From 2e8e071d75b0c69151e40b4fdfdafeb607400095 Mon Sep 17 00:00:00 2001 From: Snider Date: Sat, 14 Mar 2026 11:39:23 +0000 Subject: [PATCH] fix: reduce hook false positives - Allow go mod tidy, go work sync, go get, go run (no core wrapper) - Only block sed -i on local files (allow via ssh/docker) - grep -l only blocked when piped to destructive commands - Remove sed > and awk > blocks (too aggressive) - check-debug: only flag fmt.Print* not log.Println (go-log is valid) Co-Authored-By: Virgil --- claude/code/hooks/prefer-core.sh | 37 +++++++++++------------------- claude/code/scripts/check-debug.sh | 8 +++---- 2 files changed, 18 insertions(+), 27 deletions(-) diff --git a/claude/code/hooks/prefer-core.sh b/claude/code/hooks/prefer-core.sh index 7450929..349a598 100755 --- a/claude/code/hooks/prefer-core.sh +++ b/claude/code/hooks/prefer-core.sh @@ -56,44 +56,35 @@ if echo "$command" | grep -qE 'find\s+.*-exec\s+.*(rm|mv|cp)'; then exit 0 fi -# Block ALL sed -i (in-place editing) -if echo "$command" | grep -qE 'sed\s+(-[a-zA-Z]*i|--in-place)'; then - echo '{"decision": "block", "message": "BLOCKED: sed -i (in-place edit) is never allowed. Use the Edit tool for file changes."}' +# Block sed -i on LOCAL files only (allow on remote via ssh/docker exec) +if echo "$command" | grep -qE '^sed\s+(-[a-zA-Z]*i|--in-place)'; then + echo '{"decision": "block", "message": "BLOCKED: sed -i (in-place edit) on local files. Use the Edit tool."}' exit 0 fi -# Block sed piped to file operations (but not inside heredocs) -if echo "$command" | grep -qE 'sed.*\|.*tee|sed.*>'; then - echo '{"decision": "block", "message": "BLOCKED: sed with file output is not allowed. Use the Edit tool for file changes."}' +# Block grep -l piped to destructive commands only (not head, wc, etc.) +if echo "$command" | grep -qE 'grep\s+.*-l.*\|\s*(xargs|sed|rm|mv)'; then + echo '{"decision": "block", "message": "BLOCKED: grep -l piped to destructive commands. Too risky."}' exit 0 fi -# Block grep with -l piped to xargs/rm/sed (the classic codebase nuke pattern) -if echo "$command" | grep -qE 'grep\s+.*-l.*\|'; then - echo '{"decision": "block", "message": "BLOCKED: grep -l piped to other commands is the classic codebase nuke pattern. Not allowed."}' - exit 0 -fi - -# Block perl -i, awk with file redirection (sed alternatives) -if echo "$command" | grep -qE 'perl\s+-[a-zA-Z]*i|awk.*>'; then - echo '{"decision": "block", "message": "BLOCKED: In-place file editing with perl/awk is not allowed. Use the Edit tool."}' +# Block perl -i on local files +if echo "$command" | grep -qE '^perl\s+-[a-zA-Z]*i'; then + echo '{"decision": "block", "message": "BLOCKED: In-place file editing with perl. Use the Edit tool."}' exit 0 fi # === REQUIRE CORE CLI === -# Block raw go commands (only check first line, not heredoc content) +# Suggest core CLI for common go commands, but don't block +# go work sync, go mod edit, go get, go install, go list etc. have no core wrapper case "$command" in - "go test"*|"go build"*|"go fmt"*|"go mod tidy"*|"go vet"*|"go run"*) - echo '{"decision": "block", "message": "Use `core go test`, `core build`, `core go fmt --fix`, etc. Raw go commands are not allowed."}' - exit 0 - ;; - "go "*) - # Other go commands - block - echo '{"decision": "block", "message": "Prefer `core go *` commands. If core does not have this command, ask the user."}' + "go test"*|"go build"*|"go fmt"*|"go vet"*) + echo '{"decision": "block", "message": "Use `core go test`, `core build`, `core go fmt --fix`, `core go vet`. Raw go commands bypass quality checks."}' exit 0 ;; esac +# Allow all other go commands (go mod tidy, go work sync, go get, go run, etc.) # Block raw php commands case "$command" in diff --git a/claude/code/scripts/check-debug.sh b/claude/code/scripts/check-debug.sh index 079cc0e..f7d7551 100755 --- a/claude/code/scripts/check-debug.sh +++ b/claude/code/scripts/check-debug.sh @@ -7,10 +7,10 @@ FILE_PATH=$(echo "$input" | jq -r '.tool_input.file_path // empty') if [[ -n "$FILE_PATH" && -f "$FILE_PATH" ]]; then case "$FILE_PATH" in *.go) - # Check for fmt.Println, log.Println debug statements - if grep -n "fmt\.Println\|log\.Println" "$FILE_PATH" 2>/dev/null | head -3 | grep -q .; then - echo "[Hook] WARNING: Debug prints found in $FILE_PATH" >&2 - grep -n "fmt\.Println\|log\.Println" "$FILE_PATH" 2>/dev/null | head -3 >&2 + # Check for fmt.Print* (debug prints — log.* is fine, it's proper logging) + if grep -n 'fmt\.Print\|fmt\.Fprint' "$FILE_PATH" 2>/dev/null | grep -v 'fmt\.Fprintf(w' | head -3 | grep -q .; then + echo "[Hook] WARNING: fmt.Print* found in $FILE_PATH (use log.* or go-log instead)" >&2 + grep -n 'fmt\.Print\|fmt\.Fprint' "$FILE_PATH" 2>/dev/null | grep -v 'fmt\.Fprintf(w' | head -3 >&2 fi ;; *.php)