Clear the Dependency Audit backlog and make the job meaningful again (#282) #283

Merged
claude-bot merged 1 commit from fix/dependency-audit into main 2026-08-06 00:45:39 +00:00
Contributor

Closes #282.

The scheduled Dependency Audit has been red on main every run since at least 2026-08-03 (runs 640, 642, 643), all three jobs failing. Genuine CVEs, not infrastructure — the job log was pulled rather than guessed at.

Five advisories, four fixed outright

Component Change Advisories Verification
Backend cryptography 48.0.1 → 50.0.0 PYSEC-2026-3552/3553/3554 836 passed, unchanged
Bot aiohttp 3.14.1 → 3.14.3 PYSEC-2026-3545/3546/3547 194 passed
Frontend 3 transitive dev bumps via npm audit fix --package-lock-only 4 × brace-expansion / fast-uri 431 passed, lint clean

cryptography is a two-major jump, so the full suite was run against it rather than trusting the version number. authlib==1.7.2 depends on it as well, so the OIDC paths are in scope, not just the AES-GCM at-rest encryption it's pinned for directly.

Those four frontend advisories were not in the CI log. It's tail-truncated and only surfaced the react-router pair. Building the wrapper below is what exposed them — five advisories total, not one.

The fifth is allowlisted, because there is no fix to apply

GHSA-qwww-vcr4-c8h2 (high) in react-router, vulnerable range 7.12.0 – 8.2.0. We're on react-router-dom@7.18.2.

  • react-router-dom has no fixed version. Its latest dist-tag is 7.18.2 and no 8.x was ever published — in v8 the package folded into react-router itself. The fix, react-router@8.3.0, is only reachable by migrating off react-router-dom entirely.
  • npm audit fix --force proposes a downgrade to 7.11.0. That is not an upgrade path.
  • It doesn't apply here. The advisory's own wording: "This only affects your application if you are using the unstable RSC APIs." This frontend is a plain Vite SPA — no React Server Components, no server-side route module rendering, no @vitejs/plugin-rsc. I fetched and read the advisory to confirm this rather than inferring it from the title.

The v8 migration is real work and deliberately out of scope here; the allowlist entry names it as the removal trigger.

The allowlist mechanism

npm audit has no native ignore, and both workarounds are bad: --audit-level=critical hides real high findings, and audit-ci/better-npm-audit adds a dependency to the thing whose job is auditing dependencies.

scripts/check_npm_audit.mjs parses npm audit --json, drops IDs in scripts/npm-audit-allowlist.json, and fails on everything else.

Case Exit
Clean, or only allowlisted findings 0
Any un-allowlisted advisory 1
Audit could not be run or parsed 2

Exit 2 is deliberate and distinct — a broken audit must never look like a clean one. All three paths were exercised.

The allowlist entry carries the reason, the review date, a recheck date, and an explicit "delete this if the frontend adopts RSC or the v8 migration lands." Adding an entry is meant to read as a security decision, not a config tweak.

Why nothing warned you — the actual root cause

renovate.json already configured vulnerabilityAlerts. But that only fires on platform-supplied advisory data (GitHub Dependabot alerts), and Forgejo doesn't provide it — so the rule has been inert on this host the whole time.

That's how Renovate came to automerge react-router-dom to 7.18.2 in b51223e, deeper into a range with an open high-severity advisory, four commits before anyone noticed. Auto-merge was doing exactly what it was told; nothing was teaching it about advisories.

osvVulnerabilityAlerts: true makes Renovate query the OSV database itself, independent of the platform.

Verification

Run with the same pip-audit==2.10.0 the workflow pins, not inferred from version numbers:

webapp/backend/requirements.txt      → No known vulnerabilities found
webapp/backend/requirements-dev.txt  → No known vulnerabilities found
bot/requirements.txt                 → No known vulnerabilities found
check_npm_audit.mjs --omit=dev       → exit 0
check_npm_audit.mjs                  → exit 0

Plus all three test suites green, as above.

Why this matters beyond the CVEs

A permanently-red scheduled job is worse than no job — it teaches you to ignore the thing that would tell you about the next real vulnerability. This gets the audit to genuinely green, with exactly one documented, dated, revocable exception.

🤖 Generated with Claude Code

Closes #282. The scheduled Dependency Audit has been red on `main` every run since at least 2026-08-03 (runs 640, 642, 643), all three jobs failing. Genuine CVEs, not infrastructure — the job log was pulled rather than guessed at. ## Five advisories, four fixed outright | Component | Change | Advisories | Verification | |---|---|---|---| | Backend | `cryptography` 48.0.1 → **50.0.0** | PYSEC-2026-3552/3553/3554 | **836 passed**, unchanged | | Bot | `aiohttp` 3.14.1 → **3.14.3** | PYSEC-2026-3545/3546/3547 | **194 passed** | | Frontend | 3 transitive dev bumps via `npm audit fix --package-lock-only` | 4 × `brace-expansion` / `fast-uri` | **431 passed**, lint clean | cryptography is a two-major jump, so the full suite was run against it rather than trusting the version number. `authlib==1.7.2` depends on it as well, so the OIDC paths are in scope, not just the AES-GCM at-rest encryption it's pinned for directly. **Those four frontend advisories were not in the CI log.** It's tail-truncated and only surfaced the react-router pair. Building the wrapper below is what exposed them — five advisories total, not one. ## The fifth is allowlisted, because there is no fix to apply `GHSA-qwww-vcr4-c8h2` (high) in `react-router`, vulnerable range `7.12.0 – 8.2.0`. We're on `react-router-dom@7.18.2`. - **`react-router-dom` has no fixed version.** Its `latest` dist-tag *is* 7.18.2 and no 8.x was ever published — in v8 the package folded into `react-router` itself. The fix, `react-router@8.3.0`, is only reachable by migrating off `react-router-dom` entirely. - `npm audit fix --force` proposes a **downgrade** to 7.11.0. That is not an upgrade path. - **It doesn't apply here.** The advisory's own wording: *"This only affects your application if you are using the unstable RSC APIs."* This frontend is a plain Vite SPA — no React Server Components, no server-side route module rendering, no `@vitejs/plugin-rsc`. I fetched and read the advisory to confirm this rather than inferring it from the title. The v8 migration is real work and deliberately out of scope here; the allowlist entry names it as the removal trigger. ## The allowlist mechanism `npm audit` has no native ignore, and both workarounds are bad: `--audit-level=critical` hides real high findings, and `audit-ci`/`better-npm-audit` adds a dependency to the thing whose job is auditing dependencies. `scripts/check_npm_audit.mjs` parses `npm audit --json`, drops IDs in `scripts/npm-audit-allowlist.json`, and fails on everything else. | Case | Exit | |---|---| | Clean, or only allowlisted findings | 0 | | Any un-allowlisted advisory | 1 | | Audit could not be run or parsed | 2 | Exit 2 is deliberate and distinct — **a broken audit must never look like a clean one.** All three paths were exercised. The allowlist entry carries the reason, the review date, a recheck date, and an explicit "delete this if the frontend adopts RSC or the v8 migration lands." Adding an entry is meant to read as a security decision, not a config tweak. ## Why nothing warned you — the actual root cause `renovate.json` already configured `vulnerabilityAlerts`. But that only fires on **platform-supplied** advisory data (GitHub Dependabot alerts), and Forgejo doesn't provide it — so the rule has been inert on this host the whole time. That's how Renovate came to automerge `react-router-dom` to 7.18.2 in `b51223e`, *deeper into a range with an open high-severity advisory*, four commits before anyone noticed. Auto-merge was doing exactly what it was told; nothing was teaching it about advisories. `osvVulnerabilityAlerts: true` makes Renovate query the OSV database itself, independent of the platform. ## Verification Run with the same `pip-audit==2.10.0` the workflow pins, not inferred from version numbers: ``` webapp/backend/requirements.txt → No known vulnerabilities found webapp/backend/requirements-dev.txt → No known vulnerabilities found bot/requirements.txt → No known vulnerabilities found check_npm_audit.mjs --omit=dev → exit 0 check_npm_audit.mjs → exit 0 ``` Plus all three test suites green, as above. ## Why this matters beyond the CVEs A permanently-red scheduled job is worse than no job — it teaches you to ignore the thing that would tell you about the next real vulnerability. This gets the audit to genuinely green, with exactly one documented, dated, revocable exception. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
fix(deps): clear the Dependency Audit backlog and make the job meaningful again (#282)
All checks were successful
CI / Bot/backend version sync (pull_request) Successful in 27s
CI / Backend lint (ruff) (pull_request) Successful in 1m48s
CI / Docker image build (pull_request) Successful in 2m5s
CI / Frontend tests, audit, and build (pull_request) Successful in 4m15s
CI / Bot tests and audit (pull_request) Successful in 4m16s
CI / Backend migration, tests, and audit (pull_request) Successful in 12m18s
668688a317
The scheduled Dependency Audit has failed on main every run since at least
2026-08-03 (runs 640, 642, 643). All three jobs were red. These were genuine
CVEs, not an infrastructure problem — the job log was pulled rather than
guessed at.

Four of the five advisories are fixed outright:

- cryptography 48.0.1 -> 50.0.0 (PYSEC-2026-3552/3553/3554). Two majors, so the
  full backend suite was run against it: 836 passed, unchanged. authlib 1.7.2
  depends on cryptography too, so the OIDC paths matter here, not just the
  AES-GCM at-rest encryption this pins it for directly.
- aiohttp 3.14.1 -> 3.14.3 (PYSEC-2026-3545/3546/3547). Bot suite: 194 passed.
- brace-expansion and fast-uri, four advisories between them, resolved by
  `npm audit fix --package-lock-only` — three transitive dev bumps, no direct
  dependency touched, nothing breaking. Frontend suite: 431 passed.

Those four were not visible in the CI log, which is tail-truncated and only
showed the react-router pair. Building the wrapper below is what surfaced them.

The fifth, GHSA-qwww-vcr4-c8h2 in react-router, has no fix available on our
line and is allowlisted instead. react-router-dom's latest is 7.18.2 and no 8.x
was ever published — in v8 the package folded into react-router itself, so the
fixed version (8.3.0) is only reachable by migrating off react-router-dom
entirely. `npm audit fix --force` proposes a *downgrade* to 7.11.0, which is
not an upgrade path. The advisory is also RSC-mode-specific — its own wording
is "This only affects your application if you are using the unstable RSC APIs"
— and this frontend is a plain Vite SPA with no React Server Components
anywhere. The advisory was fetched and read to confirm that, not inferred.

npm audit has no native ignore mechanism, and both workarounds are bad:
--audit-level=critical hides real high findings, and audit-ci/better-npm-audit
adds a dependency to the thing whose job is auditing dependencies. So
scripts/check_npm_audit.mjs parses `npm audit --json`, drops IDs listed in
scripts/npm-audit-allowlist.json, and fails on everything else. Exit 2 for "the
audit could not run" is deliberate and distinct from exit 0 — a broken audit
must never look like a clean one. The allowlist entry carries the reason, the
date, a recheck date, and an explicit instruction to delete it if the frontend
adopts RSC or the v8 migration lands.

Finally, the reason none of this was flagged. renovate.json already configured
vulnerabilityAlerts, but that only fires on platform-supplied advisory data
(GitHub Dependabot alerts). Forgejo does not provide it, so the rule has been
inert on this host — which is how Renovate came to automerge react-router-dom
to 7.18.2, deeper into a range with an open high-severity advisory, four
commits before anyone noticed. osvVulnerabilityAlerts makes Renovate query the
OSV database itself, independent of the platform.

A permanently-red scheduled job is worse than no job: it teaches you to ignore
the thing that would tell you about the next real vulnerability. Verified with
the same pip-audit==2.10.0 the workflow pins — all three requirements files now
report "No known vulnerabilities found", and both npm audit invocations exit 0.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
claude-bot deleted branch fix/dependency-audit 2026-08-06 00:45:40 +00:00
Sign in to join this conversation.
No description provided.