Repository navigation
fix(run-claude-cli): run each leg with the CLI install and action dirs bound read-only - #798
Conversation
…s bound read-only When the CLI install tree or _work/_actions exists, each leg now runs as bwrap --die-with-parent --dev-bind / / --ro-bind <dir> <dir> ... -- <cli>. A leg runs as the owning uid, so it could restore the write bits the mode lock removes; a read-only bind cannot be undone from inside the leg. The mode lock stays as a second layer. bwrap forwards no signal, so --die-with-parent makes a leg timeout or stdout overflow kill the CLI (SIGKILL) instead of leaving it running. Timeout and overflow are still classified from spawnSync's error code. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Hosted-runner probe at 162c9e1 passed: run 39307237666 (ubuntu-24.04, CLI 2.1.303, role automations, sandbox PR melodic-software/pr-pipeline-sandbox#173, closed unmerged).
|
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
|
Claude finished @kyle-sexton's task in 10m 3s —— View job Security review complete
Scope: Per IMPORTANT —
|
|
Claude finished @kyle-sexton's task in 6m 20s —— View job Code review complete
This repo runs a dedicated security lane ( On correctness/maintainability, One concrete test-coverage finding posted inline on I was not able to independently run No findings against the paved-paths, closing-issue, or |
|
claude-review has reviewed this pull request through 8afb95e; a later push is reviewed from there. |
|
claude-security-review has reviewed this pull request through 8afb95e; a later push is reviewed from there. |
--die-with-parent kills only the process bwrap execs, so a process a leg detached kept running after a timeout or overflow killed bwrap. --unshare-pid makes bwrap the namespace's init, and its death takes every process in the namespace with it. Tests: a detached process does not outlive a timed-out leg (fails without --unshare-pid), and under real bwrap a leg cannot restore the write bits on _work/_actions. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Security review in progress
|
|
Claude finished @kyle-sexton's task in 3m 0s —— View job Code review complete (incremental, since 162c9e1)
Scope: per this lane's charter, this is incremental — only What changed: this commit adds This is a direct, correctly-scoped fix for the two findings raised on
No new findings. I could not independently execute No closing issue is claimed (PR body still opens with |
Inside the new PID namespace /proc is still the host's procfs, so a bwrap nested in the leg (the CLI's Bash sandbox) fails with "open /proc/3/ns/ns failed". The leg goes back to the argv from 162c9e1. The _work/_actions real-bwrap test stays. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Claude finished @kyle-sexton's task in 4m 0s —— View job Code review complete
Scope: incremental — only the diff between What changed in this push
Finding posted inlineOne test-coverage finding on No findings on the I could not run |
|
Claude finished @kyle-sexton's task in 2m 9s —— View job Security review complete
Scope: per this lane's incremental-review contract, Finding: none. The only change is the new test For the record (not a new finding, since this file is out of scope and was already flagged at |

No related issue: follow-up to #797
Summary
#797 removes the write bits on the CLI install tree (
<workDir>/cli) and_work/_actionswhile the legs run. A leg runs as the uid that owns those trees, so it could put the bits back. This change bind-mounts both trees read-only for each leg, which the leg cannot undo.Fix
readOnlyPathsfinds a tree, each leg runs asbwrap --die-with-parent --dev-bind / / --ro-bind <dir> <dir> ... -- <cli> <args>(legCommandinlane.cjs). The env, cwd, stdin and stdio are the same as before, and the read-only binds come after the root bind so they take precedence. With no tree present, the CLI runs directly as before.--die-with-parent: bwrap forwards no signals, so without it a leg timeout or stdout overflow killed only bwrap and left the CLI running. A local probe showed the orphan still running 4 s later. With the flag the CLI gets SIGKILL when bwrap dies. Timeout and overflow are still classified from spawnSync'sETIMEDOUT/ENOBUFS(lane.cjs,timedOut/overflowed;classify.cjsreturnstimeoutbefore it reads any message), so classification never depends on the CLI flushing a final result.verifyIsolation, and there is no unwrapped fallback.Verification
timeout 300 node --test .github/actions/run-claude-cli/lane.test.cjs: 38 of 38 pass locally with bwrap 0.11.1.--die-with-parentand the bind order;chmodon the install tree fails withEROFSand the file is unchanged;The two real-bwrap tests skip on hosts where bwrap cannot run, such as the test-contracts job. Against the old
lane.cjs, the argv test and the EROFS test fail. With--die-with-parentremoved, the orphan test fails.--. They still exercise the mode lock on hosts without bwrap.Related
🤖 Generated with Claude Code