Skip to content

chore: INFRA-312 unblock the Security + compliance CI gate (npm audit endpoint) - #222

Closed
MP2EZ wants to merge 1 commit into
developmentfrom
chore/INFRA-312-fix-npm-audit-ci-gate
Closed

chore: INFRA-312 unblock the Security + compliance CI gate (npm audit endpoint)#222
MP2EZ wants to merge 1 commit into
developmentfrom
chore/INFRA-312-fix-npm-audit-ci-gate

Conversation

@MP2EZ

@MP2EZ MP2EZ commented Jul 26, 2026

Copy link
Copy Markdown
Owner

Closes INFRA-312. This PR is self-validating β€” if its own Security + compliance check goes green, the fix works.

Symptom

Every PR in the repo started failing Security + compliance with no app-code change. development was green at 2026-07-26T01:06Z (#220); it broke within hours. Discovered on #221 (INFRA-306), which passes 8 of 9 gates.

audit-ci reported only:

code undefined:
Exiting...

That is audit-ci failing to classify an error β€” not a CVE finding. A real advisory always names its GHSA.

Root cause

Asking npm directly:

npm notice This endpoint is being retired. Use the bulk advisory endpoint instead.
npm warn audit 400 Bad Request - POST .../-/npm/v1/security/audits/quick
{ statusCode: 400, error: 'Bad Request',
  message: 'Invalid package tree, run  npm install  to rebuild your package-lock.json' }
npm tree endpoint result
10.9.3 20 pkgs quick βœ… passes (finds a real CVE)
10.9.3 Being's 1,185 quick ❌ 400 Invalid package tree
11.18.0 20 pkgs bulk βœ… passes

The job pins NODE_VERSION: 20 β†’ npm 10 β†’ the legacy quick endpoint, which is mid-retirement and no longer accepts a tree this size. npm 11 uses security/advisories/bulk.

Two hypotheses tested and disproved

Recorded so nobody re-walks them:

  • Not the private-registry dep. Removing @mp2ez/being-design-system β€” the only non-registry.npmjs.org entry, from GitHub Packages β€” still 400s.
  • Not a stale lockfile. npm install leaves package-lock.json byte-identical, so npm's own "rebuild your package-lock.json" hint is a red herring. The lockfile is structurally clean: 0 entries missing a version, 0 link:true, 0 non-numeric versions.

Fix

Pin npm@11 for that one step. Scoped deliberately rather than bumping NODE_VERSION, which would change the toolchain for all 12 jobs to fix a single endpoint call. Removable once NODE_VERSION reaches Node 24+ (ships npm β‰₯11).

The gate must still be able to fail

The allowlist in .audit-ci.json is untouched β€” every previously allowlisted GHSA stays allowlisted. This restores real scanning rather than silencing it, which matters: a gate that passes because it quietly stopped auditing is the same failure class INFRA-306 just cleaned up (a Math.random() fps metric) and MAINT-307 before it. Verified npm 11 still reports real advisories (it flagged a high-severity lodash CVE on the control tree). If this PR's check goes green, confirm on a follow-up that a deliberately vulnerable dep still trips it.

Also

.audit-ci.json gains a diagnostic note: a bare code undefined: means ask npm directly, it is never a CVE report. That message cost a full investigation to decode.

Unblocks #221 and every other PR.

πŸ€– Generated with Claude Code

… endpoint)

The gate broke repo-wide with no app-code change, failing every PR including
INFRA-306's otherwise-green #221.

audit-ci reported only `code undefined:`, which is it failing to classify an
error rather than a CVE finding. Asking npm directly gives the real cause:

  npm notice This endpoint is being retired. Use the bulk advisory endpoint instead.
  npm warn audit 400 Bad Request - POST .../-/npm/v1/security/audits/quick
  { statusCode: 400, message: 'Invalid package tree, run npm install to rebuild
    your package-lock.json' }

Diagnosis matrix (npm 10.9.3 vs 11.18.0):
  npm 10 + 20-package tree   -> quick endpoint -> PASSES (finds a real CVE)
  npm 10 + Being's 1,185     -> quick endpoint -> 400 Invalid package tree
  npm 11 + 20-package tree   -> bulk  endpoint -> PASSES
So npm 10's legacy quick endpoint, mid-retirement, no longer accepts a tree this
size. npm 11 uses security/advisories/bulk instead.

Two hypotheses tested and DISPROVED, recorded so nobody re-walks them:
  - Not the private-registry dep. Removing @mp2ez/being-design-system (the only
    non-registry.npmjs.org entry, from GitHub Packages) still 400s.
  - Not a stale lockfile. npm install leaves package-lock.json byte-identical, so
    npm's own "rebuild your package-lock.json" hint is a red herring. The lockfile
    is structurally clean: 0 entries missing a version, 0 link:true, 0 non-numeric
    versions.

Fix: pin npm@11 for that one step. Scoped deliberately rather than bumping
NODE_VERSION, which would change the toolchain for all 12 jobs to fix one endpoint
call. Removable once NODE_VERSION reaches Node 24+ (ships npm >=11).

The allowlist is untouched β€” every previously allowlisted GHSA stays allowlisted.
This restores real scanning rather than silencing it.

Also records a diagnostic note in .audit-ci.json: a bare `code undefined:` means
ask npm directly, it is never a CVE report.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@MP2EZ

MP2EZ commented Jul 26, 2026

Copy link
Copy Markdown
Owner Author

Closing β€” the npm@11 theory is disproved. CI confirmed npm 11.18.0 was active for the audit step and audit-ci failed identically with code undefined:, so the legacy quick-endpoint hypothesis was aimed at the wrong target.

Superseded by a fresh attempt on INFRA-312 that starts from a CI debug step capturing raw npm audit --json output β€” the one piece of evidence this investigation never obtained. Full eight-hypothesis evidence ledger is recorded on the INFRA-312 Notion item so nothing here is lost.

The .audit-ci.json diagnostic note from this branch ("a bare code undefined: means ask npm directly, it is never a CVE report") will be re-added alongside the actual fix.

@MP2EZ MP2EZ closed this Jul 26, 2026
@MP2EZ
MP2EZ deleted the chore/INFRA-312-fix-npm-audit-ci-gate branch July 26, 2026 10:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant