fix(agent): fail closed on explicit read-confine + credential-overlapping read-allow (P4-GIT-03 review follow-up)#129
Conversation
…ping read-allow (Codex review) Two fail-closed gaps found in dual review of the read-confinement slice: - An explicit `--read-confine on` degraded to an unconfined advisory run when no OS sandbox was available under `--sandbox auto` (it returned at the availability-failure branch before the read-confine refusal). An explicit knob must not silently no-op — now refuses with the policy exit class, mirroring `--sandbox require`. - Skipping bwrap credential masks under read confinement is unsafe if a `--read-allow` root overlaps a credential path (e.g. `--read-allow ~` or `~/.ssh`): bwrap would expose the credential and Landlock cannot subtract from an allowed root. `FirstReadAllowCredentialConflict` now refuses such a root pre-worktree. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (3)
🚧 Files skipped from review as they are similar to previous changes (2)
📝 WalkthroughWalkthroughAdds fail-closed validation for ChangesFail-closed read-confinement and credential-conflict validation
Estimated code review effort: 3 (Moderate) | ~25 minutes Sequence Diagram(s)sequenceDiagram
participant CLI as agent run CLI
participant Resolve as resolveAgentSandbox
participant Platform as FirstReadAllowCredentialConflict
participant Sandbox as OS Sandbox Backend
CLI->>Resolve: invoke with --read-confine, --read-allow
Resolve->>Platform: check read-allow vs credential anchors
Platform-->>Resolve: overlapping path or ""
alt overlap found
Resolve-->>CLI: exitInvalidConfig
else no overlap
Resolve->>Sandbox: check availability
alt sandbox unavailable and read-confine explicit on
Sandbox-->>Resolve: unavailable
Resolve-->>CLI: exitPolicy
else sandbox available or auto mode
Sandbox-->>Resolve: proceed
Resolve-->>CLI: sandbox config resolved
end
end
Possibly related PRs
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@internal/cli/agent.go`:
- Around line 127-139: The credential-conflict guard in agent.go is failing open
when os.UserHomeDir() returns an error, so the protected-path overlap check is
skipped instead of rejecting the config early. Update the
readConfineWant/readAllow validation near agentSandboxSpec to treat a
home-directory resolution error as a fatal invalid-config case, and only proceed
to platform.FirstReadAllowCredentialConflict when the real home path is
available. Keep the existing fail-closed behavior in this preflight check so
launch is rejected before any worktree or DB row is created.
In `@internal/platform/sandbox_read_confine.go`:
- Around line 98-106: pathsOverlap currently misses the filesystem root case
because appending filepath.Separator to "/" produces a non-matching prefix, so
update the overlap check in pathsOverlap to explicitly treat "/" as overlapping
with any absolute path before using the prefix logic. Verify the fix through the
read-confine conflict path that uses pathsOverlap, and add a "--read-allow /"
scenario to TestFirstReadAllowCredentialConflict so the root-anchor case stays
covered.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 4ffc262f-7a3c-4c9b-bdc6-9de789ce4a4b
📒 Files selected for processing (7)
internal/cli/agent.gointernal/cli/agent_sandbox_test.gointernal/platform/sandbox_read_confine.gointernal/platform/sandbox_read_confine_test.gospec/13_CLI_DAEMON_API.mdspec/16_TEST_PLAN.mdspec/18_WORK_LOG.md
- pathsOverlap now treats the filesystem root `/` as overlapping every path: `"/" + separator` is `"//"`, never a prefix of a clean absolute path, so `--read-allow /` (the ultimate footgun) was silently allowed. - The credential-conflict preflight now fails closed when os.UserHomeDir() errors instead of skipping the check (it would otherwise create a worktree/DB row before agentSandboxSpec fails on the same call). - Test: `--read-allow /` is now a covered conflict case. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
What
Follow-up to #128 (tighter read confinement). An independent Codex review flagged two fail-closed gaps that landed via auto-merge before the fixes could be folded in — this PR ships them.
Explicit
--read-confine onsilently no-op'd when no OS sandbox was available. Under--sandbox autoon a host with no sandbox,resolveAgentSandboxreturned at the availability-failure branch (advisory warning) before the read-confine refusal, so an explicit request for confinement produced an unconfined run. An explicit knob must fail closed — now refuses with the policy exit class, mirroring--sandbox require.Skipping bwrap credential masks under read confinement was unsafe when
--read-allowoverlapped a credential path (e.g.--read-allow ~or~/.ssh). bwrap would then expose the credential and Landlock (additive-allow) cannot subtract it from an allowed root.FirstReadAllowCredentialConflictnow refuses such a root before any worktree is created. (Seatbelt was already safe — its credential deny is emitted last.)Testing
TestFirstReadAllowCredentialConflict(exact/ancestor/descendant/sibling cases),TestResolveAgentSandboxReadConfineExplicitOnRefusesWhenUnavailable,TestResolveAgentSandboxReadAllowCredentialConflictRefuses.gofmt,GOOS=linuxbuild,golangci-lint(0 issues),go test ./internal/platform ./internal/cli, spec-drift — all green. spec/13 and spec/16 document the guard.🤖 Generated with Claude Code
Summary by CodeRabbit
--read-confine onso it fails closed when the required OS sandbox isn’t available.--read-allowroots that overlap protected credential locations, preventing credential re-exposure.