93 lines
4.7 KiB
Markdown
93 lines
4.7 KiB
Markdown
---
|
|
phase: 16-ci-dependency-audit-and-security-checks
|
|
plan: "02"
|
|
subsystem: ci-security
|
|
tags: [dependency-audit, pnpm-audit, pnpm-outdated, allowlist, tdd]
|
|
dependency_graph:
|
|
requires: []
|
|
provides: [scripts/check-audit.mjs, scripts/audit-allowlist.json, scripts/check-outdated.mjs, scripts/outdated-pins.json]
|
|
affects: [16-05-ci-security-job]
|
|
tech_stack:
|
|
added: []
|
|
patterns: [node-wrapper-script, tdd-red-green, audit-allowlist-pattern]
|
|
key_files:
|
|
created:
|
|
- scripts/check-audit.mjs
|
|
- scripts/audit-allowlist.json
|
|
- scripts/check-outdated.mjs
|
|
- scripts/outdated-pins.json
|
|
- scripts/__tests__/check-audit.test.mjs
|
|
modified: []
|
|
decisions:
|
|
- "D-04/D-05: Audit wrapper uses committed allowlist (audit-allowlist.json) with reason+reviewer+expiry per GHSA; Option B over native pnpm.auditConfig.ignoreGhsas (no accountability metadata in native approach)"
|
|
- "D-06: check-outdated.mjs always exits 0; tiered report never gates"
|
|
- "Pitfall 1 honored: pnpm audit --json with NO --audit-level flag"
|
|
- "TDD gate: test(16-02) RED commit precedes feat(16-02) GREEN commit"
|
|
metrics:
|
|
duration: 25
|
|
completed: "2026-06-13"
|
|
tasks: 3
|
|
files: 5
|
|
---
|
|
|
|
# Phase 16 Plan 02: Dependency Audit Gate + Outdated Report Summary
|
|
|
|
**One-liner:** pnpm audit blocking wrapper with committed GHSA allowlist (esbuild waiver pre-seeded) plus tiered outdated report — both as standalone Node.js scripts, TDD-verified.
|
|
|
|
## What Was Built
|
|
|
|
### Task 1 — Audit allowlist + pin reasons (chore, `0f101bd`)
|
|
|
|
- `scripts/audit-allowlist.json`: committed GHSA waiver map. Seeded with `GHSA-gv7w-rqvm-qjhr` (esbuild High advisory, transitive dev-only via drizzle-kit/vitest/vite, not in production image). Each entry carries `reason`, `reviewer`, and `expires` fields for auditability.
|
|
- `scripts/outdated-pins.json`: flat package→reason map for four intentional pins: eslint (ESLint 10 breaks eslint-plugin-react), @eslint/js (same), zod (v4 breaking API), @types/node (Node 22 LTS types).
|
|
|
|
### Task 2 — check-audit.mjs blocking wrapper, TDD (`7ac8b19` RED → `6eb5107` GREEN)
|
|
|
|
- `scripts/check-audit.mjs`: exports two pure functions (`selectBlocking`, `partitionAdvisories`) for unit testing. Main body runs only when invoked directly (import.meta.url guard). Uses `pnpm audit --json` with no `--audit-level` (Pitfall 1 honored). Exits 1 on unwaived High/Critical; exits 0 with advisory report for moderate/low.
|
|
- `scripts/__tests__/check-audit.test.mjs`: 5 cases via `node:test` + `node:assert` (no extra deps). Covers: unwaived High → blocking; waived High → not blocking; moderate/low only → not blocking; no advisories → not blocking; mixed → correct partition.
|
|
- All 5 tests green.
|
|
|
|
### Task 3 — check-outdated.mjs tiered report (`baf2e3a`)
|
|
|
|
- `scripts/check-outdated.mjs`: classifies outdated packages into four tiers (AUDIT-ADVISORY > MAJOR-BEHIND-INTENTIONAL > MAJOR-BEHIND-UNPINNED > ROUTINE-DRIFT). Cross-checks `pnpm audit --json` to surface pinned-but-vulnerable packages under AUDIT-ADVISORY. Reads `outdated-pins.json` to label intentional pins with their reason. Always `process.exit(0)` — never gates (D-06).
|
|
- Live run output: eslint/@eslint/js/zod/@types/node correctly under INTENTIONAL, @vitejs/plugin-react/jsdom/typescript under UNPINNED, hono/mysql2/@types/react under ROUTINE-DRIFT.
|
|
|
|
## Verification Results
|
|
|
|
- `node --test scripts/__tests__/check-audit.test.mjs` → 5/5 pass
|
|
- `node scripts/check-outdated.mjs` → exit 0, tiered report printed
|
|
- `node -e "require('./scripts/audit-allowlist.json')['GHSA-gv7w-rqvm-qjhr']"` → defined
|
|
- `grep "execSync" scripts/check-audit.mjs` → `pnpm audit --json` (no `--audit-level`)
|
|
- `grep -c "process.exit(0)" scripts/check-outdated.mjs` → 1
|
|
- `grep "process.exit(1)" scripts/check-outdated.mjs` → absent
|
|
|
|
## TDD Gate Compliance
|
|
|
|
| Gate | Commit | Message |
|
|
|------|--------|---------|
|
|
| RED | 7ac8b19 | test(16-02): add failing tests for check-audit.mjs filter logic |
|
|
| GREEN | 6eb5107 | feat(16-02): add check-audit.mjs blocking wrapper + unit tests |
|
|
|
|
TDD gate sequence correct: test commit precedes implementation commit.
|
|
|
|
## Deviations from Plan
|
|
|
|
None — plan executed exactly as written.
|
|
|
|
## Known Stubs
|
|
|
|
None. All scripts are fully functional with live data.
|
|
|
|
## Threat Flags
|
|
|
|
No new threat surface introduced. Files created are scripts (no network endpoints, no auth paths, no schema changes).
|
|
|
|
## Self-Check: PASSED
|
|
|
|
- `scripts/check-audit.mjs` — exists ✓
|
|
- `scripts/audit-allowlist.json` — exists ✓ (GHSA-gv7w-rqvm-qjhr present)
|
|
- `scripts/check-outdated.mjs` — exists ✓
|
|
- `scripts/outdated-pins.json` — exists ✓
|
|
- `scripts/__tests__/check-audit.test.mjs` — exists ✓
|
|
- Commits 0f101bd, 7ac8b19, 6eb5107, baf2e3a — all present in git log ✓
|