Skip to content

Add sandbox-git-write guard hook#10

Open
technicalpickles wants to merge 1 commit into
mainfrom
sandbox-git-write-guard
Open

Add sandbox-git-write guard hook#10
technicalpickles wants to merge 1 commit into
mainfrom
sandbox-git-write-guard

Conversation

@technicalpickles
Copy link
Copy Markdown
Owner

Summary

  • Adds bin/claude-sandbox-guard, a PreToolUse/Bash hook that denies sandboxed git-write and srb commands and tells Claude to retry with dangerouslyDisableSandbox=true. Both reliably fail under the sandbox (git writes hit .git/worktrees/.../index.lock and the blocked .claude/.vscode/.gitmodules paths in pt worktrees; sorbet wants its mdb/rubocop cache) and are safe to run unsandboxed. Read-only git stays sandboxed, so the common path is untouched.
  • Teaches claudeconfig.sh to concatenate hooks.<event> arrays across base + active role instead of deep-merging them. The old merge replaced same-event arrays, so a base-level PreToolUse hook got silently dropped whenever the active role also defined PreToolUse (work.jsonc does).
  • Targets came from real data, not a guess: a structural pass over 26k Bash calls in the session corpus showed git-writes and srb as the clear "always retry unsandboxed" patterns. /tmp writes were deliberately left out, since the fix there is $TMPDIR, not loosening the sandbox.

Test plan

npm test (lint + bats). The bats suite covers hand-written edge cases (env prefixes, git -C, compound chains, read-form list commands, already-unsandboxed calls, non-Bash tools) plus a sweep over 90 real commands pulled from the corpus.

Activating it

Dormant until claudeconfig.sh regenerates ~/.claude/settings.json. Heads up first: the live settings has bowerbird/rtk/plannotator hooks that aren't tracked in any role, so a regen drops them. Pre-existing drift, worth sorting out separately.

A PreToolUse/Bash hook (bin/claude-sandbox-guard) that denies sandboxed
git-write and srb commands up front, telling Claude to retry with
dangerouslyDisableSandbox=true instead of eating a cryptic EPERM and
retrying. Both classes reliably fail under the command sandbox and are
safe to run unsandboxed:

- git writes hit .git/worktrees/.../index.lock and the hardcoded blocked
  paths (.claude/, .vscode/, .gitmodules) inside pt worktrees
- sorbet (srb) wants to write its mdb / rubocop cache

Read-only git (log/show/diff/status, worktree/stash/submodule list) is
left sandboxed, so the common path is untouched.

claudeconfig.sh now concatenates hooks.<event> arrays across base +
active role. The previous deep merge replaced same-event arrays, which
would silently drop a base-level PreToolUse hook whenever the active
role also defined PreToolUse (work.jsonc does).

Behaviour is locked down by a bats suite (test/): hand-written edge
cases (env prefixes, git -C, compound chains, read-form list commands,
already-unsandboxed calls) plus a data-driven sweep over 90 real
commands pulled from the session corpus.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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