Commit lockfiles and wire pip-audit / npm audit into CI #72
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Severity: HIGH (supply chain / reproducibility)
The problem
Neither project has a committed lockfile.
backend/pyproject.tomluses>=lower bounds only. Norequirements.txt, nouv.lock, nopoetry.lock— confirmed absent.frontend/package.jsonuses^ranges, and nopackage-lock.jsonis tracked in git —confirmed via
git ls-files.Why it matters
Builds are not reproducible: two installs a week apart produce different dependency trees. You
cannot audit what is actually deployed, or answer "am I affected by advisory X," without SSHing
to the host. A compromised or yanked upstream is picked up silently.
For an application holding irreplaceable data, this is a more durable problem than any single
CVE — and Renovate PR #1 can only be useful once lockfiles exist for it to update.
Installed versions at audit time
Read from the dev server, so accurate for that host only: Authlib 1.6.10, Pillow 12.2.0,
FastAPI 0.121.3, Starlette 0.49.4, SQLAlchemy 2.0.45, Pydantic 2.12.4, uvicorn 0.38.0,
itsdangerous 2.2.0, python-multipart 0.0.20, Vite 7.3.2, esbuild 0.27.7, React 19.2.0,
react-router-dom 7.9.6, TanStack Query 5.90.5, TypeScript 5.9.3. All recent releases.
The CVE question is unresolved
The audit's CVE section was model recall, explicitly unverified. It must be confirmed by
running the real tools. Priority order for review once output exists:
Fix
uv lockorpip-compile;npm installcommittingpackage-lock.json).pip-auditandnpm auditto CI (#13), failing on high severity.Done when
pip-auditandnpm auditrun in CI and gate the buildReferences
backend/pyproject.toml,frontend/package.jsonRelated: #13 (CI pipeline).
Lockfiles done in
8a28bbb. The audit tooling is still outstanding, so leaving this open.Committed:
frontend/package-lock.json(1796 lines)backend/requirements.txtandbackend/requirements-dev.txt, generated bypip-compilefrompyproject.tomlwith--strip-extrasCI now installs from these rather than resolving ranges, so builds are reproducible and
npm ciworks. Renovate can manage pinned versions rather than just bumping ranges in a manifest.
Note the workflow: edit
pyproject.toml, then regenerate, never editrequirements*.txtbyhand.
pip-compilewrites a header recording the command, and Renovate'spip-compilemanagerrelies on it.
Still to do for this issue:
pip-auditstep in the backend CI jobnpm auditstep in the frontend CI jobThe CVE list in the original audit was explicitly unverified model recall — treat the tool output as
authoritative over it.
Done in
709b983. Lockfiles were already committed; this closes the audit half and, importantly, actually ran the tools — the audit's CVE section was explicitly unverified recall, so the first job was finding out what is true.Real output
pip-audit: clean on bothrequirements.txtandrequirements-dev.txt. No advisories at all. So the Authlib / python-multipart concerns in the issue body were not borne out — good news, but now verified rather than assumed.npm audit: six findings, four high. Five are real and fixed by a lockfile refresh within existing semver ranges — no code changes; typecheck and build verified:react-routerviteserver.fs.denybypass on Windows alternate paths; launch-editor NTLMv2 hash disclosure via UNC handlingpostcsssourceMappingURLesbuild@babel/coresourceMappingURLarbitrary file readYour prioritisation was right about where to look — Vite/esbuild dev-server advisories matter because the dev server runs on the LAN — but the biggest one was react-router, which the original list did not flag.
The sixth needs judgement, not a bump. GHSA-qwww-vcr4-c8h2, high, CSRF bypass in React Router's RSC mode. That requires a React Router server runtime handling server actions; Circa's frontend is a static Vite build with a FastAPI backend —
BrowserRouter, declarative<Routes>, no SSR, no framework mode, no data router, no actions. Unreachable. The CSRF control here is server-side anyway (CSRFOriginMiddleware, #63). The fix exists only in react-router 8.3.0, a major thatrenovate.jsondeliberately holds for review. Filed as #132 (v0.2.0) rather than forced through — pushing a framework major under a CVE that does not apply to us is how working software breaks.The CI gate
This raised a real question: how does CI stay honest with a known-inapplicable high outstanding?
npm audithas no ignore mechanism, so the usual answers are lowering--audit-level(blinds the build to the next real finding at that severity) or|| true(blinds it to everything). Both trade the control for a green tick.frontend/scripts/audit.mjsfiltersnpm audit --jsonby advisory id againstfrontend/audit-allowlist.json, and is deliberately hostile to its own allowlist:reviewBydate fails the build — this one expires 2026-10-31 and CI will start refusing merges until someone re-decidesI tested all three failure modes by hand before committing, including the empty-allowlist case proving the gate genuinely blocks the react-router finding.
pip-auditis pinned viarequirements-dev.txtrather thanpip installed in the workflow — fetching a security tool unpinned at build time is its own supply-chain risk. Both audits run against the locked set, not the installed set, so the result describes what a deployment would actually get. I replayed both CI jobs end to end in the exact images (node:22-bookworm-slim+ python3,node:22-slim) before pushing."Done when"
pip-auditandnpm auditrun in CI and gate the buildThat last box is the only thing outstanding on this issue, and it needs you rather than me. Closing on the basis that the tooling and triage are done; reopen if you would rather it stay open until #1 lands.