Repository navigation
ci: use npm ci over npm install, pin npm CLI, move audit earlier - #21
Merged
Merged
Conversation
publish.yml previously ran npm install -g npm@latest (unpinned mutable tag) then npm install (ignoring the committed lockfile) in a job that holds id-token: write immediately before npm publish --provenance. A compromised transitive dependency resolved fresh at publish time would get a valid provenance attestation. Pins the npm CLI to the version the file's own comment already names (11.5.1), switches both publish.yml and ci.yml to npm ci --ignore-scripts against the audited lockfile, and adds/moves npm audit --audit-level=high to run immediately after install rather than last (or not at all, in publish.yml's case). Deliberately not doing in this branch: SHA-pinning actions/checkout, actions/setup-node, and codeql-action, or adding an environment approval gate. Both are sound hygiene but defend against GitHub/npm Inc. itself being compromised, lower urgency than the lockfile-bypass issue above for a single-maintainer repo, and the environment gate needs an actual GitHub Environment created first. Verified locally end to end: npm ci --ignore-scripts (194 packages, 0 vulnerabilities), lint, typecheck, coverage (24 tests), build, demo all pass. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The first version of this branch failed real CI: npm ci --ignore-scripts on ubuntu-latest left @esbuild/linux-x64 unresolved (vite/vitest/tsx all depend on esbuild transitively), because --ignore-scripts also disables esbuild's postinstall fallback that resolves the platform binary when npm's own optionalDependencies resolution doesn't land it. Local verification on Windows didn't catch this, esbuild resolved fine there, which is exactly why the real Linux CI run is the actual check, not a local pass. Keeping npm ci (the real fix: pins to the audited lockfile instead of re-resolving ^ ranges) and npm install -g npm@11.5.1 --ignore-scripts (installing the npm CLI binary itself has no legitimate need for scripts and isn't affected by this). Dropping --ignore-scripts only from the npm ci steps. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
8 tasks done
This was referenced Sep 13, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Branch 0 of the agent-trace-normalizer review's fix plan (highest leverage, lowest cost, ships alone and non-breaking).
publish.yml:npm install -g npm@latest->npm install -g npm@11.5.1 --ignore-scripts(the file's own comment already names 11.5.1 as the requirement)publish.ymlandci.yml:npm install->npm ci --ignore-scriptsagainst the committed, audited lockfilenpm audit --audit-level=highadded topublish.yml(was absent) and moved to run immediately after install inci.yml(was last, after everything else already passed)This job holds
id-token: writeright beforenpm publish --provenance.npm installre-resolves every^-range dependency against whatever currently satisfies it on the registry at publish time, bypassing the audited lockfile entirely.npm cipins to exactly what's committed.Deliberately deferred: SHA-pinning
actions/checkout/setup-node/codeql-action, and anenvironment: npm-publishapproval gate. Real hygiene, but defend against GitHub/npm Inc. itself being compromised rather than this repo's actual threat model, and the environment gate needs a GitHub Environment created first (repo settings, not code).Test plan
npm ci --ignore-scripts— 194 packages, 0 vulnerabilitiesnpm run lintnpm run typechecknpm run coverage— 24/24 testsnpm run buildnpm run demo🤖 Generated with Claude Code