Repository navigation
fix(global-settings): deny an unauthorized git push in every form, before any prompt (v2.7.2) - #806
Merged
Conversation
…fore any prompt (v2.7.2) The push check ran after the git -C, gh, curl and docker ask guards. An ask exits the hook, so `git -C repo commit -m x && git push` (or the same after `gh pr create`, `curl -X POST`, `docker compose up`) prompted once for the first part and, on approval, ran the push without the phrase. git's global options before the subcommand were not recognised at all: `git -c k=v push`, `git --no-pager push` and `git --work-tree <path> push` passed with no deny and no prompt. The push guard now sits before every ask, next to the production guard, and matches `git` followed by any of its global options (-C/-c <value>, --git-dir/--work-tree/--namespace/... <value>, --flag[=value], -p/-P) and then `push`. With the phrase, the rest of the command is still asked about. data_free_cmd strips -m/--body values on `git <global options> commit|tag|notes` lines too, so a message that mentions git push after `git -C <path> commit` is not denied as a push. Tests: 26 fixtures for the forms above plus 9 transcript-backed checks (phrase given → still asks for the chained part; no phrase → denied). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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.
Problem
block-write-commands.shshould hard-deny everygit pushunless the last typed message has an authorization phrase. Two gaps let a push through without the phrase:git -C,gh,curlanddockerask guards. Anaskexits the hook, so a push chained after one of them was never checked. The user saw a prompt about the first part, and approving it also ran the push:git -C repo commit -m x && git pushgit -C repo add . && git -C repo push origin maingh pr create … && git push,gh api -X POST … ; git pushcurl -X POST … && git push,docker compose up -d; git push\bgit\s+push\bdoes not match when an option sits betweengitandpush. These passed with no deny and no prompt from the hook:git -c k=v pushgit --no-pager push,git -P pushgit --work-tree /x pushgit -C "/a b" push(this one was asked, not denied)Fix
The push guard now sits before every
ask, next to the production guard (same reasoning as v2.6.0).It matches
git, then any of git's global options, thenpush. The global options it knows:-C/-c <value>;--git-dir/--work-tree/--namespace/--config-env/--super-prefix/--attr-source <value>;--flag[=value];-p/-P.Values may be quoted. Other long options take no separate value, so
git --no-pager log --author pushis not mistaken for a push.With the phrase, the rest of the command still reaches its own guard. For example,
git -C r commit … && git pushstill asks about the commit.data_free_cmdnow also strips-m/--body/… values ongit <global options> commit|tag|noteslines. Otherwise moving the guard up would hard-denygit -C r commit -m "explain git push". That command is now asked about, as before.VERSION2.7.1 → 2.7.2. The README has a new section, and the guard table indocs/claude/global-claude-settings.mdis updated.Tests
tests/test-block-write-commands.shgains 26 fixtures and 9 transcript-backed checks:git -c …/--no-pagerpushes are allowed;-C-commit messages that mention push, a directory namedpush, and--author pushare not denied.test-block-write-commands.shmaintest-block-config-tool-writes.shtest-block-polling.shtest-check-settings-version.shShellCheck did not run locally (not installed); CI runs it.
Not in this PR
Several other hard denies still sit after ask guards, so the same chaining reaches them only after a prompt:
date -s--legacy-peer-depslnto~/.claude/Fixing that generally (an
askthat records its reason and lets later hard denies run, emitting the ask at the end) is a separate change.🤖 Generated with Claude Code