fix: make sandboxed sessions usable for real git workflows

Address three integration gaps found in review:

- Bind ~/.gitconfig read-only in the sandbox base layer so `git commit`
  finds user.name/email inside the jail (spec §3).
- Bind a worktree session's repo common .git dir writable: the worktree's
  real gitdir lives at <repo>/.git/worktrees/<branch>, outside the bound
  cwd, so git was broken in sandboxed worktree sessions.
- doctor now gates on sandbox.is_available() (the single source of truth
  shared with the New Session dialog) rather than a raw shutil.which, so
  it agrees with the service on non-Linux platforms (spec §6).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-11 08:16:48 -04:00
parent 7d851dcb7e
commit 5f29418186
7 changed files with 130 additions and 26 deletions
+15 -4
View File
@@ -292,7 +292,12 @@ async def test_new_session_on_dismiss_sequential_create_then_refresh():
call_order: list[str] = []
async def fake_create(
project_id, harness_name, nickname, model, worktree_branch=None, sandbox=None
project_id,
harness_name,
nickname,
model,
worktree_branch=None,
sandbox=None,
):
# Brief yield so that, if two separate workers were used, the list
# worker would be able to start and record "list" before this
@@ -1316,7 +1321,9 @@ async def test_new_session_worktree_checked_uses_typed_branch():
branch.value = "feature-x"
app.screen.query_one("#ok-btn", Button).press()
await pilot.pause()
assert results == [("claude", "My Work", None, "feature-x", None)], f"got {results}"
assert results == [("claude", "My Work", None, "feature-x", None)], (
f"got {results}"
)
@pytest.mark.asyncio
@@ -1532,7 +1539,9 @@ async def test_sandbox_switch_disabled_when_unavailable():
app = HqtApp()
async with app.run_test(size=(120, 40)) as pilot:
app.push_screen(NewSessionScreen(["claude"], is_git_repo=False, sandbox_available=False))
app.push_screen(
NewSessionScreen(["claude"], is_git_repo=False, sandbox_available=False)
)
await pilot.pause()
assert app.screen.query_one("#sandbox-switch", Switch).disabled is True
@@ -1544,6 +1553,8 @@ async def test_sandbox_switch_enabled_when_available():
app = HqtApp()
async with app.run_test(size=(120, 40)) as pilot:
app.push_screen(NewSessionScreen(["claude"], is_git_repo=False, sandbox_available=True))
app.push_screen(
NewSessionScreen(["claude"], is_git_repo=False, sandbox_available=True)
)
await pilot.pause()
assert app.screen.query_one("#sandbox-switch", Switch).disabled is False