Skip to content

Commit 0f7e340

Browse files
refactor(git-permission-guard): simplify to match Anthropic docs
- Fix hooks.json format: use PreToolUse event key, string matcher - Use proper JSON output with permissionDecision deny/ask (not exit 2) - Inline all rules in script (remove config/ directory) - Add early exit for non-git/gh commands (performance) - Reduce script from 311 to 139 lines - Use ${CLAUDE_PLUGIN_ROOT} per repo convention Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent ca32c8c commit 0f7e340

5 files changed

Lines changed: 169 additions & 654 deletions

File tree

git-permission-guard/README.md

Lines changed: 46 additions & 210 deletions
Original file line numberDiff line numberDiff line change
@@ -1,234 +1,70 @@
11
# Git Permission Guard
22

3-
A Claude Code plugin that provides centralized git and gh permission
4-
management via PreToolUse hooks with detailed warning messages.
5-
6-
## Overview
7-
8-
This plugin replaces scattered permission rules with a single, intelligent
9-
hook that:
10-
11-
- Parses git and gh commands to understand their intent
12-
- Applies allow/ask/deny logic based on command risk level
13-
- Provides detailed explanations for blocked commands
14-
- Handles `git -C <path>` by analyzing the actual subcommand
3+
PreToolUse hook that blocks dangerous git/gh commands with early exit
4+
optimization for non-git commands.
155

166
## Installation
177

18-
Add to your Claude Code settings:
19-
20-
```json
21-
{
22-
"plugins": [
23-
"/path/to/git-permission-guard"
24-
]
25-
}
26-
```
27-
28-
## Permission Categories
29-
30-
### DENY (Never Allowed)
31-
32-
Commands that bypass safety mechanisms are blocked with strong warnings:
33-
34-
| Pattern | Reason |
35-
| ------------------------------ | --------------------------- |
36-
| `git commit --no-verify / -n` | Bypasses pre-commit hooks |
37-
| `git merge --no-verify` | Bypasses merge hooks |
38-
| `git cherry-pick --no-verify` | Bypasses commit hooks |
39-
| `git rebase --no-verify` | Bypasses commit hooks |
40-
| `git config core.hooksPath` | Changes hook directory |
41-
| `git -c core.hooksPath=...` | Temporarily bypasses hooks |
42-
| `pre-commit uninstall` | Removes pre-commit hooks |
43-
| `rm .git/hooks/*` | Deletes hooks |
44-
| `chmod -x .git/hooks/` | Disables hooks |
45-
46-
### ASK (Require Confirmation)
47-
48-
Potentially dangerous commands are blocked with detailed warnings:
49-
50-
**Git Commands:**
51-
52-
| Command | Risk |
53-
| -------------------------- | -------------------------------------- |
54-
| `git merge` | Can create merge commits or conflicts |
55-
| `git reset` | Can lose uncommitted work permanently |
56-
| `git restore` | Can discard local changes |
57-
| `git rm` | Removes files from tree and index |
58-
| `git cherry-pick` | Rewrites commit history |
59-
| `git worktree remove` | Removes worktree directory |
60-
| `git gc` | May remove unreferenced objects |
61-
| `git prune` | Removes unreferenced objects |
62-
| `git rebase` | Rewrites commit history |
63-
| `git commit --amend` | Rewrites the last commit |
64-
| `git push --force` | Overwrites remote history |
65-
| `git push --force-w-lease` | Overwrites remote history |
66-
| `git clean` | Removes untracked files permanently |
67-
68-
**GitHub CLI Commands:**
69-
70-
| Command | Risk |
71-
| ------------------- | ------------------------------------------- |
72-
| `gh repo delete` | Permanently deletes a repository |
73-
| `gh issue close` | Closes issues (could be accidental) |
74-
| `gh pr close` | Closes pull requests (could be accidental) |
75-
| `gh pr merge` | Merges PR - ONLY when user requests |
76-
| `gh release delete` | Deletes releases permanently |
77-
78-
### ALLOW (Safe Commands)
79-
80-
All other git/gh commands pass through silently:
81-
82-
- `git status`, `git log`, `git diff`, `git add`
83-
- `git commit` (without `--no-verify`)
84-
- `git push` (without `--force`)
85-
- `git pull`, `git fetch`, `git branch`
86-
- `git checkout`, `git switch`, `git stash`
87-
- `git tag`, `git remote`, `git show`
88-
- `git blame`, `git bisect`, `git reflog`
89-
- `git worktree add`, `git worktree list`
90-
- `gh pr list`, `gh issue list`, `gh repo view`
91-
- `gh auth`, `gh api`, etc.
92-
93-
## Special Handling
94-
95-
### `git -C <path>` Commands
96-
97-
The hook intelligently handles `git -C <path>` by extracting the actual
98-
subcommand:
99-
1008
```bash
101-
git -C /some/path merge main # Triggers ASK (same as "git merge")
102-
git -C /some/path status # Passes through (safe command)
103-
git -C /path commit -n # Triggers DENY (bypasses hooks)
9+
claude plugins add jacobpevans-cc-plugins/git-permission-guard
10410
```
10511

106-
### `git -c <key=value>` Commands
12+
## How It Works
10713

108-
Configuration options are parsed to find the actual subcommand:
14+
1. **Early exit** - Non-git/gh commands exit immediately (most Bash calls)
15+
2. **DENY** - Commands bypassing safety are always blocked
16+
3. **ASK** - Dangerous commands require user confirmation
17+
4. **ALLOW** - Safe commands pass through silently
10918

110-
```bash
111-
git -c user.name="Test" commit -m "msg" # Passes through
112-
git -c core.hooksPath=/dev/null commit # Triggers DENY
113-
```
19+
## Blocked Commands (DENY)
11420

115-
## Warning Message Examples
21+
| Pattern | Reason |
22+
| ----------------------------- | -------------------------- |
23+
| `git commit --no-verify / -n` | Bypasses pre-commit hooks |
24+
| `git merge --no-verify` | Bypasses merge hooks |
25+
| `git rebase --no-verify` | Bypasses commit hooks |
26+
| `git config core.hooksPath` | Changes hook directory |
27+
| `pre-commit uninstall` | Removes pre-commit hooks |
28+
| `rm .git/hooks/*` | Deletes git hooks |
11629

117-
### DENY Message
30+
## Confirmation Required (ASK)
11831

119-
```text
120-
======================================================================
121-
BLOCKED: Prohibited Git Command
122-
======================================================================
32+
**Git:**
12333

124-
Command: git commit --no-verify
34+
- `merge` - Can create conflicts
35+
- `reset` - Can lose uncommitted work
36+
- `restore` - Can discard changes
37+
- `rm` - Removes from tree and index
38+
- `cherry-pick`, `rebase` - Rewrites history
39+
- `commit --amend` - Rewrites last commit
40+
- `push --force` - Overwrites remote
41+
- `clean` - Removes untracked files
42+
- `gc`, `prune` - May remove objects
43+
- `worktree remove` - Removes worktree
12544

126-
THIS COMMAND IS NEVER ALLOWED because it bypasses pre-commit hooks
127-
that enforce code quality and security.
45+
**GitHub CLI:**
12846

129-
WHY THIS IS BLOCKED:
130-
- Pre-commit hooks catch security vulnerabilities
131-
- Hooks enforce consistent code formatting
132-
- Bypassing hooks violates development standards
47+
- `repo delete` - Permanently deletes repo
48+
- `issue close` - Closes issues
49+
- `pr close` - Closes pull requests
50+
- `pr merge` - **ONLY when user EXPLICITLY requests**
51+
- `release delete` - Deletes releases
13352

134-
WHAT TO DO INSTEAD:
135-
- Fix the issues that pre-commit hooks identify
136-
- Run: pre-commit run --all-files
53+
## Special Handling
13754

138-
======================================================================
139-
```
55+
`git -C <path>` and `git -c <key=value>` are parsed to extract the actual
56+
subcommand. `git -C /path merge` triggers the same rules as `git merge`.
14057

141-
### ASK Message
58+
## Structure
14259

14360
```text
144-
======================================================================
145-
CAUTION: Potentially Dangerous Git Command
146-
======================================================================
147-
148-
Command: git reset --hard HEAD~1
149-
150-
RISK: Can permanently lose uncommitted work and rewrite local history
151-
152-
WHY THIS MATTERS:
153-
- Uncommitted changes may be discarded forever
154-
- Cannot be undone without reflog knowledge
155-
- May cause confusion if you forget what was lost
156-
157-
SAFER ALTERNATIVES:
158-
- git stash (saves changes temporarily)
159-
- git reset --soft (keeps changes staged)
160-
- git revert (preserves history)
161-
162-
To proceed, you must explicitly confirm this operation.
163-
======================================================================
164-
```
165-
166-
## Configuration
167-
168-
Configuration files are in the `config/` directory:
169-
170-
- `deny.json` - Patterns that are never allowed
171-
- `ask.json` - Patterns requiring confirmation
172-
173-
### Adding Custom Rules
174-
175-
**To deny a command:**
176-
177-
```json
178-
{
179-
"patterns": [
180-
{
181-
"match": "your-regex-pattern",
182-
"reason": "why this is blocked",
183-
"alternative": "what to do instead"
184-
}
185-
]
186-
}
187-
```
188-
189-
**To require confirmation:**
190-
191-
```json
192-
{
193-
"git": [
194-
{
195-
"cmd": "subcommand",
196-
"risk": "description of the risk",
197-
"safer": ["alternative 1", "alternative 2"]
198-
}
199-
]
200-
}
201-
```
202-
203-
## Exit Codes
204-
205-
| Code | Meaning | Behavior |
206-
| ---------------- | ------- | ------------------------------ |
207-
| 0 (no output) | ALLOW | Command executes normally |
208-
| 2 (with message) | BLOCK | Command is blocked with warning|
209-
210-
## Testing
211-
212-
Test the hook manually:
213-
214-
```bash
215-
# Should pass (exit 0, no output)
216-
echo '{"tool_name":"Bash","tool_input":{"command":"git status"}}' \
217-
| python3 scripts/git-permission-guard.py
218-
219-
# Should block (exit 2, deny message)
220-
echo '{"tool_name":"Bash","tool_input":{"command":"git commit -n"}}' \
221-
| python3 scripts/git-permission-guard.py
222-
223-
# Should block (exit 2, ask message)
224-
echo '{"tool_name":"Bash","tool_input":{"command":"git reset --hard"}}' \
225-
| python3 scripts/git-permission-guard.py
226-
227-
# Should pass (non-git command)
228-
echo '{"tool_name":"Bash","tool_input":{"command":"ls -la"}}' \
229-
| python3 scripts/git-permission-guard.py
61+
git-permission-guard/
62+
├── .claude-plugin/plugin.json
63+
├── hooks/hooks.json
64+
├── scripts/git-permission-guard.py
65+
└── README.md
23066
```
23167

232-
## License
68+
## Sources
23369

234-
MIT
70+
- [Claude Code Hooks Reference](https://docs.anthropic.com/en/docs/claude-code/hooks)

git-permission-guard/config/ask.json

Lines changed: 0 additions & 98 deletions
This file was deleted.

0 commit comments

Comments
 (0)