| tracked lockfile | walked before | advisories found | now |
|---|---|---|---|
| package-lock.json (root) | yes | 0 | walked |
| docs/site/ | yes | 0 | walked |
| src/hooks/ | yes | 1 (fixed in #3272) | walked |
| src/mcp-server/ | yes | 6 (fixed in #3272) | walked |
| orchestkit-demos/ | NO | 6 (5x brace-expansion HIGH, fast-uri HIGH) | walked |
| packages/hook-contract/examples/generic-client/ | NO | 1 (postcss) | walked |
An unaudited workspace does not report "unknown". It contributes nothing to the failure count, so the summary line prints all-green and a reader concludes the tree is clean. The gate was not wrong about what it checked; it was silent about what it did not check.
Dependabot reports per manifest, so it flagged orchestkit-demos and the
hook-contract example client independently. The gate walks a hand-written list of
directories. The two views disagreed, and the disagreement was the signal: after #3272
cleared src/mcp-server, the gate went green while Dependabot still showed
three open alerts. That mismatch is what exposed the missing entries.
$ npm update --no-audit --no-fund # in-range only, no --force orchestkit-demos added 516 packages in 39s 1123896 brace-expansion HIGH cleared 1130589 brace-expansion HIGH cleared 1130591 brace-expansion HIGH cleared 1130734 brace-expansion HIGH cleared 1130736 brace-expansion HIGH cleared 1130720 fast-uri HIGH cleared hook-contract/examples/generic-client added 151 packages in 8s 1130709 postcss moderate cleared remaining: none
Every fix already existed inside a range the manifests permitted. No manifest edits, no overrides, no allowlist entries, nothing semver-major.
The list stays hand-written (readable, intentional), but the script now
asserts that it covers every tracked lockfile:
AUDITED_DIRS=() # appended by audit_project
...
git ls-files '*package-lock.json' # source of truth
-> any lockfile whose directory was never passed to
audit_project fails the run and is named by path
Negative test, run in place:
$ (remove the orchestkit-demos line)
$ bash tests/security/test-npm-audit.sh
audit coverage gap: tracked lockfile(s) never audited
orchestkit-demos/package-lock.json
exit 1 <-- assertion fires
Restored, full run:
Total: 6 | Passed: 6 | Failed: 0
exit 0
A workspace added tomorrow with no audit_project line turns the build red
and names itself, instead of joining the silent-pass set. The assertion also caught its own
first bug: the root lockfile's dirname is ., which built
$PROJECT_ROOT/. and failed a literal comparison against
$PROJECT_ROOT, so root was falsely reported as uncovered.
| check | result |
|---|---|
| full gate, all six workspaces | Total 6 | Passed 6 | Failed 0, exit 0 |
| negative test (one entry removed) | exit 1, names the missing lockfile |
bash -n syntax check | clean |
| files changed | 2 lockfiles + the gate script |
An earlier negative test appeared to show the assertion never firing. That harness was
wrong, not the gate: it copied the script to /tmp, and
PROJECT_ROOT is derived from SCRIPT_DIR, so the copy pointed at
the wrong tree entirely. Re-run in place, it fires correctly. Recorded because a test that
silently proves nothing is the same failure class this whole PR is about.