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