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
This commit is contained in:
Luong NGUYEN
2026-04-06 21:48:55 +02:00
parent 107153d5d7
commit 34259caf7c
4 changed files with 28 additions and 10 deletions
+3 -2
View File
@@ -2,8 +2,9 @@
# Auto-format code before writing # Auto-format code before writing
# Hook: PreToolUse:Write # Hook: PreToolUse:Write
# #
# Reads the target file path from stdin JSON and runs the appropriate formatter. # Reads the target file path from stdin JSON and runs the appropriate formatter
# Outputs updatedInput to pass the formatted content back. # 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) # Compatible with: macOS, Linux, Windows (Git Bash)
+3
View File
@@ -10,6 +10,9 @@
INPUT=$(cat) INPUT=$(cat)
# Extract the bash command from tool_input # 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) COMMAND=$(echo "$INPUT" | sed -n 's/.*"command"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' | head -1)
if [ -z "$COMMAND" ]; then if [ -z "$COMMAND" ]; then
+17 -6
View File
@@ -28,25 +28,31 @@ ISSUES=""
# Check for hardcoded passwords # Check for hardcoded passwords
# Handles both JSON format ("password": "value") and code format (password = 'value') # 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 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 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 fi
# Check for hardcoded API keys # Check for hardcoded API keys
if grep -qiE '"(api[_-]?key|apikey|access[_-]?token)"[[:space:]]*:[[:space:]]*"[^"]+"' "$FILE_PATH" 2>/dev/null; then 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 fi
# Check for private keys # Check for private keys
if grep -q "BEGIN.*PRIVATE KEY" "$FILE_PATH" 2>/dev/null; then 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 fi
# Check for AWS keys # Check for AWS keys
if grep -qE "AKIA[0-9A-Z]{16}" "$FILE_PATH" 2>/dev/null; then 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 fi
# Scan with semgrep if available # Scan with semgrep if available
@@ -60,8 +66,13 @@ if command -v trufflehog &> /dev/null; then
fi fi
# If issues found, output as additionalContext (non-blocking warning) # If issues found, output as additionalContext (non-blocking warning)
# Use hookSpecificOutput format required by Claude Code PostToolUse protocol
if [ -n "$ISSUES" ]; then 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 fi
exit 0 exit 0
+5 -2
View File
@@ -10,8 +10,11 @@
INPUT=$(cat) INPUT=$(cat)
# Extract the prompt text from JSON input # Extract the prompt text from JSON input
# Claude Code sends: {"session_id": "...", "prompt": "user's message here"} # Claude Code sends UserPromptSubmit with field "user_prompt" (falls back to "prompt")
PROMPT=$(echo "$INPUT" | sed -n 's/.*"prompt"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' | head -1) 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 if [ -z "$PROMPT" ]; then
exit 0 exit 0