Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions examples/branch_guard.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#!/usr/bin/env python3
"""Branch protection using cchooks SDK.

Blocks push to main/master and force-push on all branches.
Install: Add to PreToolUse hooks matching "Bash" in settings.json.
"""
import re
from cchooks import create_context
from cchooks.contexts import PreToolUseContext

ctx = create_context()
if isinstance(ctx, PreToolUseContext):
cmd = ctx.tool_input.get("command", "")

if re.search(r'\bgit\s+push\b.*\b(main|master)\b', cmd, re.I):
ctx.output.block(reason="Direct push to main/master branch")

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Replace unsupported PreToolUse output.block calls

PreToolUseOutput has no block() method, so ctx.output.block(...) raises AttributeError whenever a rule matches. That turns an intended deny into a hook crash (exit code 1/non-blocking), so commands like git push origin main are not actually denied. The same pattern appears across the three new examples and should use a supported PreToolUse API such as deny(...) or exit_block(...).

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fix needed.

elif re.search(r'\bgit\s+push\s+.*--force\b', cmd, re.I):
ctx.output.block(reason="Force push overwrites remote history")
elif re.search(r'\bgit\s+push\s+.*-f\b', cmd, re.I):
ctx.output.block(reason="Force push (-f shorthand)")
31 changes: 31 additions & 0 deletions examples/destructive_guard.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#!/usr/bin/env python3
"""Destructive command guard using cchooks SDK.

Blocks rm -rf /, git reset --hard, and similar destructive commands.
Install: Add to PreToolUse hooks matching "Bash" in settings.json.

Born from: https://github.com/anthropics/claude-code/issues/36339
(User lost entire C:\Users directory to rm -rf via NTFS junctions)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Escape backslashes in destructive guard docstring

The docstring includes C:\Users as C:\Users text with a single backslash in source (C:\Users intended), and Python interprets \U as a Unicode escape starter, causing SyntaxError: truncated \UXXXXXXXX escape during parsing. Because this fails at import time, the example script cannot run at all until that path text is escaped (e.g., C:\\Users) or made raw.

Useful? React with 👍 / 👎.

"""
import re
from cchooks import create_context
from cchooks.contexts import PreToolUseContext

DANGEROUS = [
re.compile(r'\brm\s+.*-rf\s+(/|~/?\s*$|\.\./)', re.I),
re.compile(r'\bgit\s+reset\s+--hard', re.I),
re.compile(r'\bgit\s+clean\s+-[a-zA-Z]*f', re.I),
re.compile(r'\bchmod\s+(-R\s+)?777\s+/', re.I),
re.compile(r'\bfind\s+/\s+-delete', re.I),
re.compile(r'Remove-Item.*-Recurse.*-Force', re.I),
re.compile(r'--no-preserve-root', re.I),
]

ctx = create_context()
if isinstance(ctx, PreToolUseContext):
cmd = ctx.tool_input.get("command", "")
if cmd and not cmd.lstrip().startswith(("echo ", "printf ")):
for pattern in DANGEROUS:
if pattern.search(cmd):
ctx.output.block(reason=f"Destructive command: {cmd[:80]}")
break
30 changes: 30 additions & 0 deletions examples/secret_guard.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#!/usr/bin/env python3
"""Secret leak prevention using cchooks SDK.

Blocks git add .env, credential files, and git add . when .env exists.
Install: Add to PreToolUse hooks matching "Bash" in settings.json.

Born from: https://github.com/anthropics/claude-code/issues/16561
(API keys committed via git add .)
"""
import os
import re
from cchooks import create_context
from cchooks.contexts import PreToolUseContext

ctx = create_context()
if isinstance(ctx, PreToolUseContext):
cmd = ctx.tool_input.get("command", "")

# Block git add .env*
if re.search(r'\bgit\s+add\s+.*\.env\b', cmd, re.I):
ctx.output.block(reason="Adding .env file to git exposes secrets")

# Block git add of credential files
elif re.search(r'\bgit\s+add\s+.*(\.pem|\.key|id_rsa|credentials)', cmd, re.I):
ctx.output.block(reason="Adding credential file to git")

# Warn on git add . / git add -A (may include .env)
elif re.search(r'\bgit\s+add\s+(-A|--all|\.)\s*$', cmd):
if os.path.exists('.env') or os.path.exists('.env.local'):
ctx.output.block(reason="git add all with .env present — use specific files")