Skip to content

Commit 406c361

Browse files
committed
(CAT-2609) Improve reliability and coverage of Claude safety hooks
Updates the shell hooks to more robustly detect git and rm commands by handling environment variables, absolute paths, and common wrappers like sudo or xargs. Also refactors input parsing to pipe directly into JSON parsers and adds ShellCheck directives for script maintenance.
1 parent 527bf59 commit 406c361

6 files changed

Lines changed: 13 additions & 10 deletions

File tree

.claude/hooks/_parse_input.sh

100644100755
Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,10 @@
33
# Sources into each hook with: . "$(dirname "$0")/_parse_input.sh"
44
# Exits 0 (allow) if no JSON parser is available.
55

6-
input=$(cat)
7-
86
if command -v jq >/dev/null 2>&1; then
9-
cmd=$(printf '%s' "$input" | jq -r '.tool_input.command // ""' 2>/dev/null || echo "")
7+
cmd=$(jq -r '.tool_input.command // ""' 2>/dev/null || echo "")
108
elif command -v python3 >/dev/null 2>&1; then
11-
cmd=$(printf '%s' "$input" | python3 -c "import sys,json; print(json.load(sys.stdin).get('tool_input',{}).get('command',''))" 2>/dev/null || echo "")
9+
cmd=$(python3 -c "import sys,json; print(json.load(sys.stdin).get('tool_input',{}).get('command',''))" 2>/dev/null || echo "")
1210
else
1311
exit 0
1412
fi

.claude/hooks/no-main-commits.sh

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,10 @@
22
# Project rule: never work directly on the main or master branch.
33
# Blocks: git commit when current branch is main or master.
44

5+
# shellcheck source=/dev/null
56
. "$(dirname "$0")/_parse_input.sh"
67

7-
if echo "$cmd" | grep -qE '(^|[;&|])[[:space:]]*git commit'; then
8+
if echo "$cmd" | grep -qE '(^|[;&|`(])[[:space:]]*(([[:alpha:]_][[:alnum:]_]*=[^[:space:]]*[[:space:]]+)*)([^[:space:]]*/)?git[[:space:]]+commit([[:space:]]|$|[;&|])'; then
89
branch=$(git rev-parse --abbrev-ref HEAD 2>/dev/null)
910
if [ "$branch" = "main" ] || [ "$branch" = "master" ]; then
1011
echo "{\"continue\":false,\"stopReason\":\"Project rule: never work directly on the $branch branch.\"}"

.claude/hooks/no-pr-merge.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
# Project rule: never merge a pull request.
33
# Blocks: gh pr merge
44

5+
# shellcheck source=/dev/null
56
. "$(dirname "$0")/_parse_input.sh"
67

78
if echo "$cmd" | grep -qE '(^|[;&|])[[:space:]]*gh pr merge'; then

.claude/hooks/no-push.sh

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@
22
# Project rule: never push a branch without explicit instruction.
33
# Blocks: git push
44

5+
# shellcheck source=/dev/null
56
. "$(dirname "$0")/_parse_input.sh"
67

7-
if echo "$cmd" | grep -qE '^git push'; then
8+
if echo "$cmd" | grep -qE '(^|[;&|`(])[[:space:]]*(([[:alpha:]_][[:alnum:]_]*=[^[:space:]]*[[:space:]]+)*)([^[:space:]]*/)?git[[:space:]]+push([[:space:]]|$|[;&|])'; then
89
echo '{"continue":false,"stopReason":"Project rule: never push a branch without explicit instruction."}'
910
fi

.claude/hooks/no-rm.sh

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
#!/usr/bin/env bash
22
# Project rule: never delete a file without explicit permission.
3-
# Blocks: rm as the leading command token after a shell separator.
4-
# Does not cover sudo rm, /bin/rm, or find -exec rm variants.
3+
# Blocks: rm, sudo rm, xargs rm, /bin/rm, /usr/bin/rm (and similar absolute paths).
4+
# Does not cover: find -exec rm (rm as a subprocess argument, not a shell token).
55

6+
# shellcheck source=/dev/null
67
. "$(dirname "$0")/_parse_input.sh"
78

8-
if echo "$cmd" | grep -qE '(^|[;&|])[[:space:]]*rm([[:space:]]|$)'; then
9+
if echo "$cmd" | grep -qE '(^|[;&|])[[:space:]]*(sudo[[:space:]]+|xargs[[:space:]]+)?([^[:space:]]*/)?rm([[:space:]]|$)'; then
910
echo '{"continue":false,"stopReason":"Project rule: never delete a file without explicit permission."}'
1011
fi

CLAUDE.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,8 @@ If you change template behavior, update:
9797
## Project Rules
9898

9999
- At the start of a coding session, review the repository structure and any relevant README or documentation files to understand the area you are working in.
100-
- Always read the files relevant to the task before suggesting or making a change.- Never merge a pull request.
100+
- Always read the files relevant to the task before suggesting or making a change.
101+
- Never merge a pull request.
101102
- Never work directly on the `main` or `master` branch.
102103
- Never push a branch without explicit instruction.
103104
- Never delete a file without permission — this applies even after a blanket "yes to all".

0 commit comments

Comments
 (0)