chore: harden .npmrc for supply-chain audit (AXE-3444)#236
Conversation
The weekly Enigma supply-chain audit (SC-12282) flagged this repo: the committed .npmrc was missing the required hardening directives. Add ignore-scripts, strict-ssl, save-exact, audit-level, engine-strict and legacy-peer-deps. access=restricted is omitted intentionally — this is a public repository, so the restricted-access directive does not apply. ignore-scripts=true blocks dependency lifecycle scripts on install, including esbuild's postinstall that downloads its native bundler binary. Rebuild esbuild explicitly in the dependencies_unix job (the only CI job that runs `npm ci`) so the cached node_modules carries the binary to build_unix. chromedriver is unaffected — CI fetches it via browser-driver-manager, not the npm install script. patch-package still applies because build_unix runs `npm run prepare` explicitly, and ignore-scripts only suppresses pre/post hooks around an explicit `npm run`, not the invoked script itself. Document the local-dev post-install steps in the developer guide. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude Code PR ReviewPR: #236 • Head: e54b78b • Reviewers: stack:code-reviewer SummaryHardens Review Table
Findings
Verdict: FAIL — sound hardening intent, but global |
The .npmrc supply-chain hardening sets ignore-scripts=true, which skips esbuild's postinstall that fetches its native bundler binary. Every path that installs deps and then builds (grunt -> esbuild) therefore broke: - GitHub Actions `build` job (test.yml) failed with "esbuild: Failed to install correctly" at the esbuild:core grunt task. - The standard-version `postbump` hook re-runs `npm ci` (wiping the binary) before `sri-update` -> `grunt build`, breaking the release / next_release pipelines (CircleCI release jobs and GitHub release.yml). - The nightly `npm install w3c/...` steps re-resolve the whole dependency tree under ignore-scripts, skipping native postinstalls. Fixes, keeping all six audit-required directives intact (access=restricted is omitted because this is a public repo): - test.yml: `npm rebuild esbuild --ignore-scripts=false` between ci and build - package.json postbump: rebuild esbuild after its inner `npm ci` - nightly jobs: `--ignore-scripts=false` on the trusted w3c installs - .npmrc: drop internal tool/ticket reference from the comment Verified: under ignore-scripts=true esbuild installs broken, and `npm rebuild esbuild --ignore-scripts=false` runs install.js and restores the working native binary. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude Code PR ReviewPR: #236 • Head: 4d32488 • Reviewers: stack:code-reviewer SummaryHardens Review Table
FindingsNo blocking issues. Non-blocking observations:
Verdict: PASS — all install→build paths correctly patched; directives kept intact per the audit mandate; only non-blocking low-severity notes remain. |
Nightly jobs used `npm install w3c/...#main --ignore-scripts=false`, which re-enabled lifecycle scripts for the whole re-resolved dependency tree and the untrusted w3c/*#main installs — defeating the ignore-scripts=true hardening. Those jobs only consume the prebuilt artifact (test:act/test:apg are mocha), so esbuild isn't needed there; drop the flag. Also remove the verbose AXE-3444 comment blocks from the CI configs per review feedback. The targeted `npm rebuild esbuild --ignore-scripts=false` steps (single trusted package) stay, matching the tech spec's sanctioned approach. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
What & why
The weekly Enigma supply-chain audit (SC-12282) flagged
browserstack/a11y-engine-axe-corewith status misconfigured (AXE-3444): the committed root.npmrcexisted but was missing every required hardening directive.This adds the six flagged directives so the next weekly audit passes.
Changes
.npmrc— the audit fixAdded the six required directives:
ignore-scripts=truestrict-ssl=truesave-exact=trueaudit-level=highengine-strict=truelegacy-peer-deps=falseaccess=restrictedis intentionally omitted — it applies to private repos only, and this repository is public. (The audit's missing-directives list did not includeaccess.)No tokens or secrets are added: this repo installs from the public npm registry and has no scoped/authenticated registry in
.npmrc..circleci/config.yml— keep the build green underignore-scriptsignore-scripts=truesuppresses dependency lifecycle scripts duringnpm ci, including esbuild'spostinstallthat downloads its native bundler binary. Without it,build_unix→npm run build(grunt → esbuild) would fail.dependencies_unixis the only job that runsnpm ciand it cachesnode_modulesfor every downstream job, so a single explicit rebuild there fixes the whole pipeline:Two things deliberately not changed:
browser-driver-manager(and thebrowser-toolsorb), so it's unaffected.build_unixrunsnpm run prepareexplicitly, andignore-scriptsonly suppresses pre/post hooks around an explicitnpm run, not the invoked script itself. Sohusky && npm run patchstill appliespatches/colorjs.io+0.4.3.patch.doc/developer-guide.md— local-dev noteDocuments the post-install steps now required locally (
npm run prepare+npm rebuild esbuild --ignore-scripts=false) before building.Reviewer note
engine-strict=truenow makesnpm cirefuse packages whose declared engines don't match the runner's Node. CI uses Node 22 (cimg/node:22.16); if a transitive dependency ever declares an incompatible range, install will fail loudly — that's the intended behavior, and any such dep is a separate fix.Test plan
dependencies_unix→build_unixis green (esbuild binary present after rebuild)🤖 Generated with Claude Code