diff --git a/docs/security/2026-07-22-dependency-hardening.md b/docs/security/2026-07-22-dependency-hardening.md new file mode 100644 index 0000000..72141ca --- /dev/null +++ b/docs/security/2026-07-22-dependency-hardening.md @@ -0,0 +1,49 @@ +# Dependency Hardening Baseline + +**Baseline date:** 2026-07-22 +**Branch:** `security/dependency-hardening-2026-07-22` +**Lockfile:** root `package-lock.json`, installed with `npm ci` + +## Toolchain + +- Node.js `v22.22.1` (the production Dockerfiles target Node 20 and 24) +- npm `9.2.0` +- Python `3.14.4` +- uv `0.5.9` +- Docker `29.6.1` +- Docker Compose `v5.3.1` + +The local Node version produces an expected engine warning for `@zxing/library@0.23.0`, which requires Node 24 or newer. Production and CI must use the declared Node image/version rather than this local Node 22 runtime. + +## Audit counts + +Reports were generated online and saved outside the repository. Counts are advisory snapshots, not a substitute for the CI gate. + +| Scope | Critical | High | Moderate | Low | Total | +|---|---:|---:|---:|---:|---:| +| Workspace root | 3 | 13 | 60 | 3 | 79 | +| Backend workspace | 1 | 10 | 41 | 2 | 54 | +| Parapharmacy API | 0 | 2 | 0 | 1 | 3 | +| Frontend workspace | 1 | 6 | 20 | 1 | 28 | +| Scraper workspace | 0 | 1 | 0 | 0 | 1 | + +The parapharmacy and scraper reports resolve through the root workspace lockfile. Their package-local audit invocation fails without a package-local lockfile; the workspace-scoped audit is the authoritative current result. + +## Direct dependency families selected for review + +- Backend OpenTelemetry: `@opentelemetry/auto-instrumentations-node ^0.52.0`, exporters/SDKs primarily on `^0.55.0`, resources/API families on `^1.x`. +- Backend native dependencies: `bcrypt ^5.1.1`, `sqlite3 ^5.1.6`, and `connect-sqlite3 ^0.9.16`. +- Parapharmacy: `mongoose ^8.8.0`, `puppeteer ^22.0.0`; current installed Puppeteer is `22.15.0`. +- Scraper: `puppeteer ^24.40.0`, `puppeteer-extra ^3.3.6`, and stealth plugin `^2.11.2`. +- Frontend: `vite ^5.0.8`, `vitest ^1.6.0`, `vite-plugin-pwa ^1.3.0`, and Grafana Faro/OpenTelemetry packages on the `^1.x` family. + +## Upgrade order and known risks + +1. Resolve Python dependencies and audit them independently. +2. Pin runtime images and verify lockfile-enforced Docker builds. +3. Upgrade backend OpenTelemetry as one family, then native bcrypt/SQLite packages. +4. Upgrade parapharmacy Mongoose/`fast-uri` and scraper Puppeteer separately. +5. Upgrade frontend Vite/Rollup/esbuild/Vitest without enabling Vitest UI. +6. Re-run all audits and record any residual advisory with production reachability, mitigation, owner, and expiry/review date. + +Do not run `npm audit fix --force`: the baseline reports breaking-version fixes for several families, including OpenTelemetry, SQLite, and Vite/Vitest. Each such upgrade requires its own compatibility test and commit.