Remove the Bash(git *) blanket allow and add destructive-git deny rules - #208
Merged
Conversation
Replaces the catch-all "Bash(git *)" with an enumerated allowlist of safe read-only subcommands plus the routine writes the daily workflow needs (add, push, pull, fetch, checkout -b, switch, restore --staged, stash push/pop/apply, worktree add). Everything else falls through to the default ask (config writes, merge, rebase, reset, cherry-pick, revert, apply, am, rm, mv, branch -D, tag -d, worktree prune/move, inline -c key=val, and any unknown subcommand) — including the four arbitrary-code-execution vectors the issue flagged: git config core.pager / core.editor / core.sshCommand / core.hooksPath. Closes the deny gaps identified in #187: git push --delete, git push --mirror, the colon-prefix branch-delete refspec, and single-file git checkout -- <file>. Prunes the git ask claw-backs that became redundant once "Bash(git *)" was gone (merge, rebase, commit --amend, reset, clean, stash drop/ clear, branch -D, config, worktree prune/move/lock/unlock). They now default to ask via the same fallthrough that catches every other non-allowed subcommand. Closes #187. Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
…allowlist-187 Resolve claude/settings.json conflicts: - deny: union of this branch push --delete/--mirror/colon-refspec and checkout -- denies with main force-with-lease denies - ask: apply this branch removal of the git claw-back entries (they fall through to default ask), keep main gh api patterns, and do not restore gh issue edit which main removed in #311 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RGD2NDthkx859WNGeDKKBN
3 tasks
ikuwow
added a commit
that referenced
this pull request
Jul 20, 2026
Move Bash(git merge *) from the ask list to the allow list. The ask rule forced a prompt on every merge even though the blanket Bash(git *) allow matched (ask rules take precedence over allow), which blocked subagents from resolving PR branch conflicts: a background permission prompt gives the user no context about which branch is being merged into. The explicit allow entry is redundant with Bash(git *) today, but becomes load-bearing once #208 replaces the blanket with an explicit allowlist: without it, merges would fall through to the auto-mode classifier (occasional transient-error denials) or a manual-mode prompt. git merge is local-only and recoverable: committed state stays reachable via the merge commit parents, uncommitted work aborts the merge instead of being overwritten, and nothing touches the remote until a separate push. Claude-Session: https://claude.ai/code/session_01RGD2NDthkx859WNGeDKKBN Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
…allowlist-187 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0156RhYyZmXJn2YdA1rHZztf
…allowlist-187 # Conflicts: # claude/settings.json
defaultMode "auto" auto-approves read-only Bash commands and honors ask rules with a guaranteed prompt, so the enumerated read-only git allowlist added earlier in this branch is redundant. Drop the allowlist, keep the core of #187: remove the Bash(git *) blanket allow (closes the git-config ACE vectors at the rule layer) and add the deny entries for destructive push refspecs and single-file checkout discards. Main's ask claw-backs stay untouched — under auto mode they are the guarantee of a prompt for destructive git commands. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014Vi9VXxJvaXAHgYRoyrJsQ
ikuwow
marked this pull request as ready for review
July 27, 2026 07:06
7 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Issue: #187 (the issue recommended an enumerated allowlist; this PR lands a smaller shape than that recommendation — see Background)
Why
Bash(git *)auto-approved every git subcommand at the rule layer, including the ACE vectors the issue lists (git config core.pager/core.editor/core.sshCommand/core.hooksPathwrites,git apply/amagainst untrusted patches) and any unknown or future subcommand. Rule-layer allow matches skip every downstream safety check, so the blanket entry has to go regardless of permission mode.What
Bash(git *)frompermissions.allow. Nothing replaces it.denyentries closing the destructive-push and single-file-discard gaps from the issue:git push --delete/git push * --delete/git push --mirror/git push * --mirror/ the colon-prefix branch-delete refspec (git push * :*), plusgit checkout -- */git checkout * -- *.git rebase *,git reset *,git clean *,git branch -D *,git config *, etc.) stay and keep forcing prompts.Background: why no allowlist
This settings file runs with
permissions.defaultMode: "auto". Per the official docs (code.claude.com/docs permissions / permission-modes pages, checked 2026-07-27):git status,git log, ...) are auto-approved in every mode, so enumerating them inallowis redundantgit add(working-directory file writes) andgit pushto the working repository are auto-approved under auto mode (push since v2.1.211)So under auto mode, deny + ask lists are the two levers that matter; an enumerated read-only allowlist adds 60+ lines of maintenance surface with no behavioral effect. An earlier revision of this branch carried that allowlist; it was dropped in the final commit.
Note: this PR makes destructive git subcommands (
reset,clean,rebase, ...) flow to the ask claw-backs or the auto-mode classifier instead of being rule-approved by the blanket allow. Occasional new prompts for unusual git writes are the intended behavior change. If a specific safe command turns out to prompt annoyingly often, add a narrow allow entry for it rather than restoring the blanket.Verification
jq . claude/settings.jsonvalidatesgit diff main -- claude/settings.jsonis exactly 1 removed allow line + 7 added deny linesjq ... | sort | uniq -dempty)git checkout origin/main -- claude/settings.jsonwas blocked by this branch's ownBash(git checkout * -- *)deny entry (worked around viagit show), confirming the pattern matches as intendedgit config core.pager <x>and other config writes prompt;git push origin :branch/git checkout -- fileare denied; routine status/log/diff/add/push flow without new prompts