Sandbox: the `claude` profile build is broken by an UNPINNED `@anthropic-ai/claude-code` — 2.1.237 needs its postinstall, npm's allowScripts default skips it, and the arm's smoke test fails every CI run
Repo: motir-core (packages/cli/sandbox/install-agent.sh).
Sandbox images / Sandbox profile claude (tier 1) fails on every run from 2026-08-19 ~01:08Z onward, on main and on every open pull request. It is NOT a flake — the same input fails identically each time — and it is not caused by any diff in the repository.
The evidence, two runs 27 minutes apart on an unchanged install-agent.sh
GREEN — run 32318138522, main @ a1f8aaad, 00:41Z | RED — run 32319852816, PR #2187, 01:08Z | |
|---|---|---|
| resolved version | @anthropic-ai/claude-code@2.1.236 | @anthropic-ai/claude-code@2.1.237 |
| npm's allow-scripts warning | present (postinstall skipped) | present (postinstall skipped) |
| packages installed | added 2 packages | added 1 package |
claude --version | 2.1.236 (Claude Code) | Error: claude native binary not installed. |
Same npm, same Dockerfile layer, same script. The only variable is the version latest resolved to.
Root cause
The arm installs UNPINNED:
npm_agent '@anthropic-ai/claude-code' # → npm install -g --no-fund --no-audit <pkg>
npm now declines to run a package's install scripts unless the package is named in allowScripts, and it says so as a WARNING rather than an error:
npm warn allow-scripts 1 package has install scripts not yet covered by allowScripts:
npm warn allow-scripts @anthropic-ai/claude-code@2.1.237 (postinstall: node install.cjs)
At 2.1.236 the CLI still worked without that postinstall — its platform-native binary arrived as an optional dependency, which is the second package in added 2 packages. At 2.1.237 it does not (added 1 package), so the binary is never installed and the arm's own smoke test — invariant 2, claude --version, working exactly as designed — fails the build.
Nothing in this repository changed. The failure is an unpinned third-party install resolving to a version with a different install contract.
What the fix has to decide
Three options, and the card should pick one deliberately rather than take the first that goes green:
- Allow the script:
npm install -g --allow-scripts=@anthropic-ai/claude-code …. Restores the postinstall. Note that it grants arbitrary install-time code execution to a third-party package inside the image build — which is what the npm default was changed to prevent, so this is a decision, not a formality. - Run the postinstall explicitly after the install (
node $(npm root -g)/@anthropic-ai/claude-code/install.cjs), which is what the error message itself suggests. Same trust decision, narrower blast radius, and it fails loudly if the file moves. - PIN the version. The card that created this arm (MOTIR-1506) says agents are fetched "from its official source at build time (pinned where the source allows)" — and this one is not pinned. Pinning turns an upstream publish into a deliberate bump instead of an unannounced break, but on its own it does not fix 2.1.237 and it freezes the profile at a version that will age.
These are not exclusive, and the sweep matters more than the choice. install-agent.sh has eight arms and several are unpinned npm installs (codex, opencode, kimi); whichever remedy is chosen, check whether the same failure is one upstream publish away for each of them, and say per arm why it is or is not.
Acceptance criteria
- The
claudearm installs a CLI whoseclaude --versionsucceeds, and the CI matrix jobSandbox profile claude (tier 1)is green. - The remedy chosen is stated IN the script, with the trade it makes — an
--allow-scriptsgrant is recorded as a trust decision, not left as a flag nobody can explain. - Every other npm-installed arm is checked for the same exposure and the finding recorded per arm, including the ones that need no change.
- A test or build assertion fails when an arm installs an agent it cannot execute — invariant 2 already does this and did its job here; confirm it covers every arm rather than only this one.
Context refs
- MOTIR-1506 — the arm this defect lives in, and the "pinned where the source allows" intent it states
- MOTIR-885 — the CI matrix that builds and liveness-checks every profile
packages/cli/sandbox/install-agent.sh— theclaude)arm and thenpm_agenthelper- Failing job:
https://github.com/moooon-B-V/motir-core/actions/runs/32319852816/job/96279843881 - Last green job:
https://github.com/moooon-B-V/motir-core/actions/runs/32318138522(same workflow, 27 minutes earlier)