Skip to content

fix(sandbox): resolve git worktree .git indirection for bwrap commits - #454

Merged
getappz merged 2 commits into
masterfrom
task/90
Aug 12, 2026
Merged

fix(sandbox): resolve git worktree .git indirection for bwrap commits#454
getappz merged 2 commits into
masterfrom
task/90

Conversation

@getappz

@getappz getappz commented Aug 11, 2026

Copy link
Copy Markdown
Owner

The diff is correct and complete. My edits are on disk but I cannot git add/git commit from inside this sandboxed worktree — every attempt fails with the exact index.lock/read-only error this task describes, since the running daemon predates my source fix. Per the task's own note, this is expected: the daemon's outside-the-sandbox auto-commit safety net (the same one that rescued item #89) is the mechanism meant to land this.

Summary

Root cause confirmed and fixed in crates/agentflare-jobs/src/sandbox/bwrap/mod.rs. build_bwrap_args_with_home only ever bound cwd/.git, correct for a plain clone but wrong for a git worktree checkout, where cwd/.git is a gitfile pointing at the real metadata (HEAD, index, index.lock, logs) under the main repo's .git.

Fix:

  • Detect via symlink_metadata whether cwd/.git is a file (worktree gitfile) vs. a directory (plain repo), preserving the existing read-only-bind behavior for plain repos.
  • For a worktree gitfile, added resolve_worktree_common_dir: parses the gitdir: line, then follows that admin dir's commondir file (git's own documented mechanism, not an assumed ../.. offset) to the main repo's real .git directory.
  • Bind that resolved directory read-write (--bind, not --ro-bind) — it's the shared object/ref store and the actual place index.lock needs to be created.

Tests added: worktree_gitfile_resolves_main_git_dir_and_binds_it_read_write (builds a tempdir shaped like a real worktree, asserts the resolved main .git dir gets --bind) and plain_repo_git_dir_is_still_bound_read_only (regression guard for the unchanged directory case). All 10 tests in the module pass; cargo clippy is clean.

I hit the exact bug I was fixing when trying to git commit/git add from inside this sandboxed worktree — the running daemon binary predates my source change, so index.lock creation failed with "Read-only file system," and the vent escalation call failed identically, matching the incident description precisely. The fix is on disk but not committed by me — leaving it for the daemon's outside-the-sandbox auto-commit safety net, as anticipated by the task.

Summary by CodeRabbit

  • Bug Fixes
    • Improved Git protection for repositories that use worktrees.
    • Worktree administrative directories are now correctly identified and protected according to the configured Git write-access setting.
    • Unresolvable Git paths are safely skipped, while standard repository behavior remains unchanged.

@coderabbitai

coderabbitai Bot commented Aug 11, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Bubblewrap Git protection now resolves worktree .git files to the main repository’s shared Git directory. It applies read-only or read-write binding based on git_writable and preserves plain-repository behavior.

Changes

Git worktree protection

Layer / File(s) Summary
Resolve worktree Git directories
crates/agentflare-jobs/src/sandbox/bwrap/mod.rs
Helpers parse gitdir and commondir metadata, resolve relative and absolute paths, and canonicalize the shared Git directory.
Bind Git directories and validate behavior
crates/agentflare-jobs/src/sandbox/bwrap/mod.rs
Sandbox setup applies git_writable to worktree Git bindings and keeps ordinary repositories read-only by default. Tests cover both cases.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
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.
Title check ✅ Passed The title clearly and concisely describes the main change: resolving Git worktree .git indirection for bwrap commits.
Description check ✅ Passed The description explains the root cause, fix, tests, and compatibility behavior, but does not fully use the template checklist.
✨ 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 task/90

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

@getappz

getappz commented Aug 11, 2026

Copy link
Copy Markdown
Owner Author

Closing as a duplicate — the real fix (item #88) already merged as #452. This PR was auto-generated from item #90, which was cancelled as a duplicate of #88 before this got pushed; the daemon's auto-commit/push safety net ran anyway on the orphaned worktree after cancellation.

@getappz getappz closed this Aug 11, 2026
@getappz getappz reopened this Aug 12, 2026
shiva added 2 commits August 12, 2026 13:20
cwd/.git in a git worktree checkout is a gitfile pointing outside cwd,
not a real directory -- resolve it via the admin dir's commondir file
and bind the real common dir read-write when git_writable is true.
Integrates with #452's git_writable parameter (Supervisor::spawn
passes false, run_headless passes true).

Agentflare-Branch: task/90
Agentflare-Item: 90
shiva
fmt
Agentflare-Agent: claude-code
Agentflare-Branch: task/90
Agentflare-Item: 90

@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: 1

🤖 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 `@crates/agentflare-jobs/src/sandbox/bwrap/mod.rs`:
- Around line 119-123: The sandbox argument construction must protect the
worktree gitfile in read-only mode. In the branch handling
resolve_worktree_common_dir, when git_writable is false, add a later read-only
bind for cwd/.git so it overrides the writable cwd bind; also add a regression
test for a worktree asserting the generated arguments include this --ro-bind.
🪄 Autofix

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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: da58d0dd-671a-4405-963a-dd641721a902

📥 Commits

Reviewing files that changed from the base of the PR and between 5c96bb5 and 68b040d.

📒 Files selected for processing (1)
  • crates/agentflare-jobs/src/sandbox/bwrap/mod.rs

Comment on lines +119 to +123
if let Some(common_dir) = resolve_worktree_common_dir(cwd, &git_dir) {
let common_str = path_to_string(&common_dir);
bwrap_args.push(if git_writable { "--bind" } else { "--ro-bind" }.to_string());
bwrap_args.push(common_str.clone());
bwrap_args.push(common_str);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -e
printf '%s\n' '--- target file outline ---'
ast-grep outline crates/agentflare-jobs/src/sandbox/bwrap/mod.rs || true
printf '%s\n' '--- target implementation ---'
sed -n '80,145p' crates/agentflare-jobs/src/sandbox/bwrap/mod.rs
sed -n '340,435p' crates/agentflare-jobs/src/sandbox/bwrap/mod.rs
printf '%s\n' '--- related symbols and tests ---'
rg -n -C 3 'resolve_worktree_common_dir|git_file|git_writable|ro-bind|worktree' crates/agentflare-jobs

Repository: getappz/agentflare

Length of output: 30596


🏁 Script executed:

#!/bin/bash
set -e
printf '%s\n' '--- remaining implementation and tests ---'
sed -n '145,205p' crates/agentflare-jobs/src/sandbox/bwrap/mod.rs
sed -n '278,420p' crates/agentflare-jobs/src/sandbox/bwrap/mod.rs
printf '%s\n' '--- local bubblewrap availability and help ---'
if command -v bwrap >/dev/null 2>&1; then
  command -v bwrap
  bwrap --help 2>&1 | sed -n '1,140p'
else
  echo 'bwrap not installed'
fi
printf '%s\n' '--- repository documentation references ---'
rg -n -i -C 2 'bubblewrap|bwrap|ro-bind|bind mount' README.md crates .github 2>/dev/null || true

Repository: getappz/agentflare

Length of output: 33931


🌐 Web query:

Bubblewrap bwrap man page --ro-bind file bind mount ordering later mount over earlier bind

💡 Result:

In bubblewrap (bwrap), filesystem-related options—including --bind, --ro-bind, and others—are applied strictly in the order they are provided as arguments [1][2][3]. If you specify multiple mount operations that overlap or nest, the later operations are performed on top of earlier ones [4][5]. This means: 1. Shadowing: If a later bind mount targets a directory (or a subdirectory) that was already mounted by an earlier command, the later mount will cover or "shadow" the previous one at that location [4][6]. 2. Positional Dependency: Because operations are sequential, the state of the filesystem at any given point is determined by all preceding mount operations [5]. If you mount a specific path, and then subsequently mount something onto a subdirectory of that path, the second mount will correctly appear inside the first [4]. Conversely, if you mount a "larger" filesystem over a "smaller" one (e.g., mounting / over a previously mounted /proc), the new mount will hide the previous one [5]. There is no automatic reordering or intelligent resolution of conflicting mount points; bubblewrap acts exactly as instructed, and it is the responsibility of the caller to provide the options in an order that achieves the desired final filesystem structure [5]. Top results: [4] containers/bubblewrap#612 [1] https://manpages.ubuntu.com/manpages/jammy/man1/bwrap.1.html [5] containers/bubblewrap#741 [3] https://man.archlinux.org/man/bwrap.1

Citations:


Protect the worktree gitfile when git_writable is false.

The writable cwd bind exposes cwd/.git, while this branch re-binds only the resolved common Git directory. Add a later --ro-bind for cwd/.git and a regression test that asserts this bind for a worktree.

🤖 Prompt for 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.

In `@crates/agentflare-jobs/src/sandbox/bwrap/mod.rs` around lines 119 - 123, The
sandbox argument construction must protect the worktree gitfile in read-only
mode. In the branch handling resolve_worktree_common_dir, when git_writable is
false, add a later read-only bind for cwd/.git so it overrides the writable cwd
bind; also add a regression test for a worktree asserting the generated
arguments include this --ro-bind.

@getappz getappz changed the title bwrap sandbox breaks git commit inside a worktree job (doesn't resolve the .git worktree indirection) fix(sandbox): resolve git worktree .git indirection for bwrap commits Aug 12, 2026
@getappz
getappz merged commit a6e3a10 into master Aug 12, 2026
17 of 18 checks passed
@getappz
getappz deleted the task/90 branch August 12, 2026 08:13
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