Files
ehoandClaude Opus 5 adfaa32a42 ci: gate on known advisories in the .NET dependency tree (RB-14)
npm audit --omit=dev gates the shipped frontend bundle; nothing equivalent
existed for the backend, so the entire .NET dependency tree — direct and
transitive — was unscanned (BIO-016 lists it first under "Absent").

The ticket's literal wording would not have worked. `dotnet list package
--vulnerable` is a reporting command: it prints the advisory table and exits
0 regardless. Verified with a throwaway project on System.Net.Http 4.3.0 —
severity High, GHSA-7jgj-8wvc-jh57, exit code 0. A bare `- run: dotnet list
package --vulnerable` would have added a line that reads like coverage in a
compliance review and enforces nothing, which is worse than leaving the gap
visible.

scripts/dotnet-audit.sh runs the scan and matches "has the following
vulnerable packages" — the exact sentence dotnet prints per project on a hit.
One script, two callers (ci.yml and ci-local.sh), so the workflow and the
local gate cannot drift apart.

No severity threshold and no suppression list: picking either before a real
advisory forces the question would be guessing at a policy nobody needs yet.
Secret scanning, BIO-016's other named absence, stays on the checklist.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-27 16:24:16 +02:00

26 lines
1.3 KiB
Bash
Executable File

#!/usr/bin/env bash
# Fail if any NuGet package (direct or transitive) has a known advisory — the .NET half of
# `npm audit --omit=dev`, which only ever covered the frontend (RB-14/BIO-016).
#
# `dotnet list package --vulnerable` is a REPORTING command: it prints the advisory table and
# still exits 0. Verified against a deliberately vulnerable project — System.Net.Http 4.3.0,
# GHSA-7jgj-8wvc-jh57, severity High, exit code 0. So `- run: dotnet list package --vulnerable`
# on its own is a gate that enforces nothing, which is worse than no gate: it reads like
# coverage in the workflow file. Matching its output is what makes it block.
#
# Shared by .github/workflows/ci.yml and scripts/ci-local.sh so the two cannot drift.
set -euo pipefail
cd "$(dirname "$0")/.."
report=$(dotnet list backend/BigRegister.slnx package --vulnerable --include-transitive)
echo "$report"
# The exact sentence `dotnet list` prints per project when it finds something; the clean case
# prints "has no vulnerable packages given the current sources" instead.
if grep -q "has the following vulnerable packages" <<<"$report"; then
echo
echo "✖ Vulnerable NuGet packages found (table above)." >&2
echo " Transitive hits can be pinned with a direct PackageReference to a patched version." >&2
exit 1
fi