build(reproducibility): pin deterministic Node and npm toolchain - #78
build(reproducibility): pin deterministic Node and npm toolchain#78seonghobae wants to merge 55 commits into
Conversation
|
Warning Review limit reached
Next review available in: 59 minutes You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (15)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
@coderabbitai review Please review the unchanged exact head |
🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
printf '%s\n' '== Exact Git identity =='
git rev-parse HEAD
git status --short
git branch --show-current
printf '%s\n' '== Commit metadata =='
git show -s --format='%H%n%P%n%s' HEAD
printf '%s\n' '== Changed paths against main merge base =='
base="$(git merge-base HEAD main)"
printf 'merge-base=%s\n' "$base"
git diff --name-status "$base"...HEAD
printf '%s\n' '== Candidate files =='
fd -t f . | rg '(^|/)(package\.json|package-lock\.json|package-manager-reproducibility\.test\.ts|package-manager-reproducibility\.md|CHANGELOG\.md)$|(^|/)\.github/workflows/.*\.(yml|yaml)$'
printf '%s\n' '== Workflow action and package-manager references =='
rg -n -C 3 -e 'actions/(checkout|setup-node)@' -e 'node-version' -e 'npm (ci|install|audit)' -e 'packageManager|devEngines|strict-allow-scripts|allowScripts' \
package.json .npmrc .github 2>/dev/null || true
printf '%s\n' '== Source outlines =='
test_file="$(fd -t f '^package-manager-reproducibility\.test\.ts$' | head -n 1 || true)"
if [ -n "$test_file" ]; then
ast-grep outline "$test_file" --items all --view expanded
fiLength of output: 22025 🏁 Script executed: #!/bin/bash
set -euo pipefail
printf '%s\n' '== package and CI policy =='
cat -n package.json
cat -n .npmrc
sed -n '1,180p' .github/workflows/ci.yml | cat -n
printf '%s\n' '== Lockfile-control implementation outline =='
ast-grep outline scripts/lockfile-change-control.mjs --items all --view expanded
printf '%s\n' '== Lockfile-control implementation =='
cat -n scripts/lockfile-change-control.mjs
printf '%s\n' '== Package-manager reproducibility fixture =='
cat -n test/package-manager-reproducibility.test.ts
printf '%s\n' '== Lockfile control test outlines =='
for f in test/lockfile-change-control*.test.ts test/workflow-readiness.test.ts; do
printf '\n-- %s --\n' "$f"
ast-grep outline "$f" --items all --view expanded
done
printf '%s\n' '== Lockfile control test assertion terms =='
rg -n -C 4 \
-e 'duplicate|race|symlink|base|sha256|canonical|allowScripts|strict-allow-scripts|resolved|integrity|schema' \
test/lockfile-change-control*.test.ts test/workflow-readiness.test.tsLength of output: 92183 🏁 Script executed: #!/bin/bash
set -euo pipefail
printf '%s\n' '== package-lock diff status =='
base="$(git merge-base HEAD main)"
git diff --stat "$base"...HEAD -- package-lock.json
git diff --exit-code "$base"...HEAD -- package-lock.json || true
printf '%s\n' '== Every workflow npm install invocation with surrounding setup =='
rg -n -U -C 16 \
'(uses: actions/setup-node@|node-version:|run: npm (ci|install)|npm ci|npm install|strict-allow-scripts|allowScripts)' \
.github/workflows --glob '*.{yml,yaml}'
printf '%s\n' '== Workflow reproducibility coverage =='
cat -n test/workflow-readiness.test.ts
rg -n -C 4 \
-e 'package-manager-reproducibility|actions/setup-node|actions/checkout|npm ci|strict-allow-scripts|lockfile' \
test --glob '*.test.ts'
printf '%s\n' '== Race-boundary tests =='
cat -n test/lockfile-change-control-race-boundaries.test.ts
printf '%s\n' '== Changed workflow diff only =='
git diff --find-renames --find-copies "$base"...HEAD -- .github/workflows/ci.ymlLength of output: 94122
I confirmed the local merge base is The changed central CI path has the requested static controls:
I found one execution-authority gap outside
The same unpinned install pattern exists in release, deployment, and scheduled scan workflows. This means the repository-wide package-manager and lifecycle-script authority claim can false-pass outside the changed central CI path. Update each root dependency-install workflow to use the immutable Node setup action, Node This is diagnostic review evidence only. It is not merge approval.
|
|
Superseded by dependency-ordered replacement #89. Fresh verification on #89 exact head |
Summary
packageManagerplus fail-closeddevEngines;actions/checkout6.0.2 andactions/setup-node6.4.0 by immutable full commit SHA, verifies exact checkout and Node/npm identities before install, and avoids deprecated Node 20 action runtimes;strict-allow-scripts=truewith exact reviewed install-script identities:esbuild@0.28.1andworkerd@1.20260625.1are explicitly allowed, whilefsevents@2.3.3is explicitly denied;postinstallcannot run under the pinned npm 11.17 strict policy, rather than relying only on configuration-string assertions;packageskey plus canonical SHA-256 digests of the exact before/after package objects;resolved/integrity, and duplicate decoded JSON object keys;Why
Issue #77 exposed that an unbound npm toolchain could regenerate a targeted
nanoidsecurity update together with unrelated lock metadata churn. Issue #79 separately requires install-time code execution to be explicitly reviewed and fail closed rather than inferred from a green dependency audit.The repository therefore treats package-manager identity, lockfile change authority, install-script authority, vulnerability audit, model/reviewer judgement, and merge authority as distinct controls.
Install-script execution proof
The existing static contract already required project
strict-allow-scripts=trueplus exact pinnedallowScriptsentries. The latest change adds a real offline npm fixture totest/package-manager-reproducibility.test.ts:postinstallthat would write a marker file if executed;npm ciwith projectstrict-allow-scripts=trueand no matchingallowScriptsentry;This is direct execution evidence for issue #79's fail-closed requirement. It does not approve any additional dependency script or weaken the project policy.
Primary npm documentation for the pinned v11 line defines
strict-allow-scripts=trueas converting an unreviewed dependency install script into a hard install error, while an explicitfalseentry remains non-executable. The repository retains the exact Node/npm identity instead of silently tracking a moving npm release.Current exact source identity
main.9adb784902cae19a150146a8fadd6a0491f67814.build/deterministic-npm-toolchain.23391f31410ad9d258b52c21c8b58d7ae2c6e82b.Current exact-head evidence
For exact head
23391f31410ad9d258b52c21c8b58d7ae2c6e82b:cirun31341608914: exact-head checkout and SHA assertion passed; Node24.19.0/ npm11.17.0identity passed; independently resolved livemainequality passed; lockfile change control passed with zero changed package nodes; strict project install succeeded for the reviewed dependency set; typecheck passed; 68 test files / 684 tests passed; the new real unreviewed-script refusal regression passed; configured production/security-control statements, branches, functions and lines are all 100%. The run then failed only at the unchanged repository-widenpm audit --audit-level=highboundary because protectedmainstill resolvesnanoid <3.3.17/ GHSA-2v37-7h3g-55p8. That root remediation remains isolated in fix(security): update transitive nanoid for CVE-2026-67213 #76; no audit waiver or duplicate lockfile patch is introduced here.reviewer-cirun31341608910: terminal success.Security Scanrun31341608937: terminal success.Queued, pending, cancelled, skipped-required, status-only, stale-head, predecessor-head, model-only, synthetic-only, or failed evidence is not treated as success or approval.
Documentation and evidence boundary
docs/doctoring/package-manager-reproducibility.mdrecords the immutable Node/npm identity, exact allow/deny lifecycle-script policy, lockfile evidence semantics, and stale-base invariant.CHANGELOG.mdrecords the package-manager, install-script, and lockfile-provenance control under## Unreleased.This PR does not modify the vulnerable
nanoidlockfile node, weakennpm audit, create a VEX/ignore exception, add self-modifying/repair workflows, add branch-patchingcontents:write, alter OpenCode/NVIDIA NIM reviewer credentials, authorize merge, or authorize release/deployment.Merge boundary
Keep this PR Draft until #76 integrates under actual live governance. Then refresh/revalidate against the protected lineage and require fresh exact-head/current-base CI, Security Scan, reviewer evidence, all applicable provenance gates, zero valid unresolved findings, and the qualifying formal review/ruleset requirements actually enforced by Noema/CWL governance. No predecessor-head evidence transfers.
Related: #77, #79, #75, #76, #27, #29