Skip to content

fix(agent): fail closed on explicit read-confine + credential-overlapping read-allow (P4-GIT-03 review follow-up)#129

Merged
Reederey87 merged 2 commits into
mainfrom
fix/agent-read-confine-failclosed
Jul 5, 2026
Merged

fix(agent): fail closed on explicit read-confine + credential-overlapping read-allow (P4-GIT-03 review follow-up)#129
Reederey87 merged 2 commits into
mainfrom
fix/agent-read-confine-failclosed

Conversation

@Reederey87

@Reederey87 Reederey87 commented Jul 5, 2026

Copy link
Copy Markdown
Owner

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.

  1. Explicit --read-confine on silently no-op'd when no OS sandbox was available. Under --sandbox auto on a host with no sandbox, resolveAgentSandbox returned 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.

  2. Skipping bwrap credential masks under read confinement was unsafe when --read-allow overlapped 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. FirstReadAllowCredentialConflict now 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.
  • Gates: gofmt, GOOS=linux build, 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

  • Bug Fixes
    • Tightened --read-confine on so it fails closed when the required OS sandbox isn’t available.
    • Added validation to reject --read-allow roots that overlap protected credential locations, preventing credential re-exposure.
    • Added safeguards to refuse unsafe confinement configuration before starting sandboxed runs.
  • Tests
    • Added cases covering sandbox-availability handling and credential-path overlap conflict detection.
  • Documentation
    • Updated agent command and platform test-plan notes to reflect the stricter confinement rules.

…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>
@Reederey87 Reederey87 enabled auto-merge (squash) July 5, 2026 21:45
@coderabbitai

coderabbitai Bot commented Jul 5, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 73250853-a810-4cc6-883d-8cf80e3f06e8

📥 Commits

Reviewing files that changed from the base of the PR and between a644460 and bb2ee6c.

📒 Files selected for processing (3)
  • internal/cli/agent.go
  • internal/platform/sandbox_read_confine.go
  • internal/platform/sandbox_read_confine_test.go
🚧 Files skipped from review as they are similar to previous changes (2)
  • internal/platform/sandbox_read_confine_test.go
  • internal/platform/sandbox_read_confine.go

📝 Walkthrough

Walkthrough

Adds fail-closed validation for --read-confine and --read-allow: explicit read-confine on now returns exitPolicy when no OS sandbox backend is available, and overlapping credential-path allow roots are rejected with exitInvalidConfig before sandbox setup. Tests and spec/work-log entries were updated.

Changes

Fail-closed read-confinement and credential-conflict validation

Layer / File(s) Summary
Credential-conflict detection helper
internal/platform/sandbox_read_confine.go, internal/platform/sandbox_read_confine_test.go
Adds credentialAnchors, pathsOverlap, and exported FirstReadAllowCredentialConflict to detect overlap between --read-allow roots and protected credential paths, with a table-driven test.
CLI fail-closed wiring in resolveAgentSandbox
internal/cli/agent.go, internal/cli/agent_sandbox_test.go
resolveAgentSandbox resolves user home and rejects overlapping --read-allow paths (exitInvalidConfig), and returns exitPolicy instead of degrading when --read-confine on is explicit but the OS sandbox backend is unavailable; adds corresponding tests.
Spec and work-log documentation
spec/13_CLI_DAEMON_API.md, spec/16_TEST_PLAN.md, spec/18_WORK_LOG.md
Documents sandbox hardening, read-confinement failure semantics, updated test-plan coverage requirements, and a work-log entry describing the dual-review fixes.

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
Loading

Possibly related PRs

  • Reederey87/DevStrap#109: Both PRs modify internal/cli/agent.go/agent_sandbox_test.go to resolve and require the real user home when building sandbox policy and anchors.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description covers the change and tests, but it misses the required Summary section and the full Safety Checklist template. Add a ## Summary section, rename ## Testing to ## Tests if needed, and complete the Safety Checklist with the required checkbox items.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: fail-closed behavior for explicit read confinement and credential-overlapping read-allow paths.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/agent-read-confine-failclosed

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

📥 Commits

Reviewing files that changed from the base of the PR and between ed615c0 and a644460.

📒 Files selected for processing (7)
  • internal/cli/agent.go
  • internal/cli/agent_sandbox_test.go
  • internal/platform/sandbox_read_confine.go
  • internal/platform/sandbox_read_confine_test.go
  • spec/13_CLI_DAEMON_API.md
  • spec/16_TEST_PLAN.md
  • spec/18_WORK_LOG.md

Comment thread internal/cli/agent.go
Comment thread internal/platform/sandbox_read_confine.go
- 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>
@Reederey87 Reederey87 merged commit ccea683 into main Jul 5, 2026
7 checks passed
@Reederey87 Reederey87 deleted the fix/agent-read-confine-failclosed branch July 5, 2026 22:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant