From 34259caf7c2b3f5043508b79e32cf14a06fd3eac Mon Sep 17 00:00:00 2001 From: Luong NGUYEN Date: Mon, 6 Apr 2026 21:48:55 +0200 Subject: [PATCH] fix(hooks): apply review fixes dropped by squash merge The squash merge of PR #49 discarded two review fix commits. Re-applying: - security-scan.sh: wrap output in hookSpecificOutput (PostToolUse protocol); restore secret/token detection; fix JSON newline escaping; escape file path - validate-prompt.sh: try "user_prompt" field first, fall back to "prompt" - log-bash.sh: document sed truncation limitation for quoted commands - format-code.sh: fix misleading comment about updatedInput output --- 06-hooks/format-code.sh | 5 +++-- 06-hooks/log-bash.sh | 3 +++ 06-hooks/security-scan.sh | 23 +++++++++++++++++------ 06-hooks/validate-prompt.sh | 7 +++++-- 4 files changed, 28 insertions(+), 10 deletions(-) diff --git a/06-hooks/format-code.sh b/06-hooks/format-code.sh index e59a132..71bb7c3 100644 --- a/06-hooks/format-code.sh +++ b/06-hooks/format-code.sh @@ -2,8 +2,9 @@ # Auto-format code before writing # Hook: PreToolUse:Write # -# Reads the target file path from stdin JSON and runs the appropriate formatter. -# Outputs updatedInput to pass the formatted content back. +# Reads the target file path from stdin JSON and runs the appropriate formatter +# in-place on the existing file (if it already exists on disk). For new files, +# formatting runs after Claude writes the file via a subsequent PostToolUse hook. # # Compatible with: macOS, Linux, Windows (Git Bash) diff --git a/06-hooks/log-bash.sh b/06-hooks/log-bash.sh index a6871f6..2ca16d9 100644 --- a/06-hooks/log-bash.sh +++ b/06-hooks/log-bash.sh @@ -10,6 +10,9 @@ INPUT=$(cat) # Extract the bash command from tool_input +# Note: sed [^"]* stops at escaped quotes in JSON; for commands with double-quoted +# strings, only the portion up to the first \" will be captured — this is a known +# limitation of sed-based JSON parsing and is acceptable for logging purposes. COMMAND=$(echo "$INPUT" | sed -n 's/.*"command"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' | head -1) if [ -z "$COMMAND" ]; then diff --git a/06-hooks/security-scan.sh b/06-hooks/security-scan.sh index d2b7e45..cddc0c5 100644 --- a/06-hooks/security-scan.sh +++ b/06-hooks/security-scan.sh @@ -28,25 +28,31 @@ ISSUES="" # Check for hardcoded passwords # Handles both JSON format ("password": "value") and code format (password = 'value') +# Use \\n as separator — it is a valid JSON newline escape and passes through printf safely if grep -qiE '"password"[[:space:]]*:[[:space:]]*"[^"]+"' "$FILE_PATH" 2>/dev/null; then - ISSUES="${ISSUES}- WARNING: Potential hardcoded password detected\n" + ISSUES="${ISSUES}- WARNING: Potential hardcoded password detected\\n" elif grep -qiE '(password|passwd|pwd)\s*=\s*'"'"'[^'"'"']+'"'"'' "$FILE_PATH" 2>/dev/null; then - ISSUES="${ISSUES}- WARNING: Potential hardcoded password detected\n" + ISSUES="${ISSUES}- WARNING: Potential hardcoded password detected\\n" fi # Check for hardcoded API keys if grep -qiE '"(api[_-]?key|apikey|access[_-]?token)"[[:space:]]*:[[:space:]]*"[^"]+"' "$FILE_PATH" 2>/dev/null; then - ISSUES="${ISSUES}- WARNING: Potential hardcoded API key detected\n" + ISSUES="${ISSUES}- WARNING: Potential hardcoded API key detected\\n" +fi + +# Check for hardcoded secrets and tokens +if grep -qiE '(secret|token)\s*=\s*['"'"'"][^'"'"'"]+['"'"'"]' "$FILE_PATH" 2>/dev/null; then + ISSUES="${ISSUES}- WARNING: Potential hardcoded secret or token detected\\n" fi # Check for private keys if grep -q "BEGIN.*PRIVATE KEY" "$FILE_PATH" 2>/dev/null; then - ISSUES="${ISSUES}- WARNING: Private key detected\n" + ISSUES="${ISSUES}- WARNING: Private key detected\\n" fi # Check for AWS keys if grep -qE "AKIA[0-9A-Z]{16}" "$FILE_PATH" 2>/dev/null; then - ISSUES="${ISSUES}- WARNING: AWS access key detected\n" + ISSUES="${ISSUES}- WARNING: AWS access key detected\\n" fi # Scan with semgrep if available @@ -60,8 +66,13 @@ if command -v trufflehog &> /dev/null; then fi # If issues found, output as additionalContext (non-blocking warning) +# Use hookSpecificOutput format required by Claude Code PostToolUse protocol if [ -n "$ISSUES" ]; then - printf '{"additionalContext": "Security scan found issues in %s:\n%sPlease review and use environment variables instead."}' "$FILE_PATH" "$ISSUES" + # Escape file path for JSON (backslash and double-quote) + # ISSUES already uses \\n as separator (valid JSON escape) — only escape double-quotes + SAFE_PATH=$(printf '%s' "$FILE_PATH" | sed 's/\\/\\\\/g; s/"/\\"/g') + SAFE_ISSUES=$(printf '%s' "$ISSUES" | sed 's/"/\\"/g') + printf '{"hookSpecificOutput": {"hookEventName": "PostToolUse", "additionalContext": "Security scan found issues in %s:\\n%sPlease review and use environment variables instead."}}' "$SAFE_PATH" "$SAFE_ISSUES" fi exit 0 diff --git a/06-hooks/validate-prompt.sh b/06-hooks/validate-prompt.sh index 882f74e..b2701f3 100644 --- a/06-hooks/validate-prompt.sh +++ b/06-hooks/validate-prompt.sh @@ -10,8 +10,11 @@ INPUT=$(cat) # Extract the prompt text from JSON input -# Claude Code sends: {"session_id": "...", "prompt": "user's message here"} -PROMPT=$(echo "$INPUT" | sed -n 's/.*"prompt"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' | head -1) +# Claude Code sends UserPromptSubmit with field "user_prompt" (falls back to "prompt") +PROMPT=$(echo "$INPUT" | sed -n 's/.*"user_prompt"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' | head -1) +if [ -z "$PROMPT" ]; then + PROMPT=$(echo "$INPUT" | sed -n 's/.*"prompt"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' | head -1) +fi if [ -z "$PROMPT" ]; then exit 0