fix(hooks): collapse multi-line commands in bash audit logs#741
Conversation
📝 WalkthroughWalkthroughTwo new Changes
Estimated code review effort🎯 2 (Simple) | ⏱️ ~10 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Greptile SummaryThis PR adds two What was improved relative to previous review feedback:
Remaining concerns:
Confidence Score: 3/5
Important Files Changed
Sequence DiagramsequenceDiagram
participant CC as Claude Code
participant H1 as bash-audit-hook
participant H2 as cost-tracker-hook
participant H3 as downstream hooks
participant L1 as ~/.claude/bash-commands.log
participant L2 as ~/.claude/cost-tracker.log
CC->>H1: stdin (JSON payload)
H1->>H1: mkdir -p ~/.claude
H1->>H1: INPUT=$(cat)
H1->>H1: jq format + redact
H1->>L1: append log line (|| true)
H1->>H2: printf INPUT (stdin passthrough)
H2->>H2: mkdir -p ~/.claude
H2->>H2: INPUT=$(cat)
H2->>H2: jq format + redact
H2->>L2: append log line (|| true)
H2->>H3: printf INPUT (stdin passthrough)
H3->>CC: result
Reviews (5): Last reviewed commit: "fix: use [: ]* instead of s* for Authori..." | Re-trigger Greptile |
There was a problem hiding this comment.
🧹 Nitpick comments (1)
hooks/hooks.json (1)
52-63: Consider redacting sensitive fragments before logging raw commandsThese logs can capture secrets passed in CLI args (tokens, passwords, keys). Add lightweight redaction in jq before append (e.g., common
--token=...,password=...,AKIA...patterns).🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@hooks/hooks.json` around lines 52 - 63, Update the Bash command hooks (the "command" strings under the matcher "tool == \"Bash\"" and the earlier audit hook writing to ~/.claude/bash-commands.log and ~/.claude/cost-tracker.log) to perform lightweight redaction in the jq pipeline before appending: apply additional gsub() calls to mask common secret patterns (e.g., replace --token=..., password=..., secret=..., AKIA[0-9A-Z]{16}, and similar CLI key/secret patterns with a fixed placeholder like "<REDACTED>") and ensure you run those gsub transformations on the (.tool_input.command // "?") value (the same place you already use gsub("\\n"; " ")) so logged lines collapse newlines and have secrets redacted before writing.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@hooks/hooks.json`:
- Around line 52-63: Update the Bash command hooks (the "command" strings under
the matcher "tool == \"Bash\"" and the earlier audit hook writing to
~/.claude/bash-commands.log and ~/.claude/cost-tracker.log) to perform
lightweight redaction in the jq pipeline before appending: apply additional
gsub() calls to mask common secret patterns (e.g., replace --token=...,
password=..., secret=..., AKIA[0-9A-Z]{16}, and similar CLI key/secret patterns
with a fixed placeholder like "<REDACTED>") and ensure you run those gsub
transformations on the (.tool_input.command // "?") value (the same place you
already use gsub("\\n"; " ")) so logged lines collapse newlines and have secrets
redacted before writing.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: a68fef8f-7e17-453c-8d77-7bd9b84c00b7
📒 Files selected for processing (2)
hooks/hooks.jsonrules/hooks.md
There was a problem hiding this comment.
2 issues found across 2 files
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="hooks/hooks.json">
<violation number="1" location="hooks/hooks.json:52">
P1: New PostToolUse Bash audit hook consumes stdin without forwarding payload, which can break downstream hooks that read stdin JSON.</violation>
<violation number="2" location="hooks/hooks.json:62">
P1: New PostToolUse cost-tracker hook also drains stdin and does not emit payload for subsequent hooks.</violation>
</file>
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.
|
Nice improvement to audit log readability. Will review. 🦞 |
|
This PR has developed merge conflicts with main. Please rebase your branch to resolve. Once all conflicts are resolved and CI passes, we can proceed with review. Thanks for your contribution! |
affaan-m
left a comment
There was a problem hiding this comment.
Three issues to fix before merge:
- Merge conflicts — rebase on latest main
- Security: no secret redaction — bash commands may contain API keys/tokens in arguments. Add redaction for common patterns (
--token,-H Authorization, env var assignments) - Stdin consumption —
cat | jqconsumes stdin without forwarding to downstream PostToolUse hooks. Useteeor read+echo pattern to preserve the payload
Happy to merge once addressed.
Add gsub("\\n"; " ") to jq filters in bash audit log and cost-tracker
hooks so multi-line commands produce single-line log entries, preventing
breakage in downstream line-based parsing.
Fixes affaan-m#734
26acc01 to
6483834
Compare
Addresses review feedback: PostToolUse hooks now preserve stdin for subsequent hooks by echoing $INPUT back to stdout after processing. Changed ; to && for proper error propagation. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
1 issue found across 1 file (changes from recent commits).
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="hooks/hooks.json">
<violation number="1" location="hooks/hooks.json:151">
P2: Hook pass-through output is incorrectly conditional on successful logging, so log failures can suppress required stdout JSON.</violation>
</file>
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.
- Use semicolons instead of && so printf passthrough always runs even if jq fails - Add || true after jq to prevent non-zero exit on parse errors - Use printf '%s\n' instead of echo for safe binary passthrough - Fix Authorization pattern to handle 'Bearer <token>' with space - Add ASIA (STS temp credentials) alongside AKIA redaction - Add GitHub token patterns (ghp_, gho_, ghs_, github_pat_) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
jq's ONIG regex engine interprets s* as literal 's' zero-or-more, not \s* (whitespace). This caused 'Authorization: Bearer <token>' to only redact 'Authorization:' and leak the actual token. Using [: ]* avoids the JSON/jq double-escape issue entirely and correctly matches both 'Authorization: Bearer xyz' and 'Authorization:xyz' patterns. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
| "hooks": [ | ||
| { | ||
| "type": "command", | ||
| "command": "#!/bin/bash\nmkdir -p ~/.claude; INPUT=$(cat);\necho \"$INPUT\" | jq -r '\"[\" + (now | todate) + \"] \" + ((.tool_input.command // \"?\") | gsub(\"\n\"; \" \") | gsub(\"--token[= ][^ ]*\"; \"--token=<REDACTED>\") | gsub(\"Authorization:[: ]*[^ ]*[: ]*[^ ]*\"; \"Authorization:<REDACTED>\") | gsub(\"AKIA[A-Z0-9]{16}\"; \"<REDACTED>\") | gsub(\"ASIA[A-Z0-9]{16}\"; \"<REDACTED>\") | gsub(\"password[= ][^ ]*\"; \"password=<REDACTED>\") | gsub(\"ghp_[A-Za-z0-9_]+\"; \"<REDACTED>\") | gsub(\"gho_[A-Za-z0-9_]+\"; \"<REDACTED>\") | gsub(\"ghs_[A-Za-z0-9_]+\"; \"<REDACTED>\") | gsub(\"github_pat_[A-Za-z0-9_]+\"; \"<REDACTED>\"))' >> ~/.claude/bash-commands.log 2>/dev/null || true;\nprintf '%s\n' \"$INPUT\"" |
There was a problem hiding this comment.
Redaction pattern substring-matches environment variable names
The gsub pattern that targets credential flags has no word-boundary anchor. A command like export MY_MASTER_PASS=value would have the credential correctly stripped, but the remaining prefix (MY_MASTER_) would be left dangling in the log entry, producing a confusing/malformed line.
Narrowing the pattern to match only a leading boundary (e.g. (^|[^A-Za-z0-9_])) or restricting to explicit CLI flag syntax (--flag[= ][^ ]*) would reduce false-positive substring matches without weakening redaction coverage. The same concern applies to the cost-tracker hook on line 161.
…#741) * fix(hooks): collapse multi-line commands in bash audit logs Add gsub("\\n"; " ") to jq filters in bash audit log and cost-tracker hooks so multi-line commands produce single-line log entries, preventing breakage in downstream line-based parsing. Fixes affaan-m#734 * fix: forward stdin to downstream hooks using echo pattern Addresses review feedback: PostToolUse hooks now preserve stdin for subsequent hooks by echoing $INPUT back to stdout after processing. Changed ; to && for proper error propagation. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: make stdin passthrough unconditional and broaden secret redaction - Use semicolons instead of && so printf passthrough always runs even if jq fails - Add || true after jq to prevent non-zero exit on parse errors - Use printf '%s\n' instead of echo for safe binary passthrough - Fix Authorization pattern to handle 'Bearer <token>' with space - Add ASIA (STS temp credentials) alongside AKIA redaction - Add GitHub token patterns (ghp_, gho_, ghs_, github_pat_) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: use [: ]* instead of s* for Authorization whitespace matching jq's ONIG regex engine interprets s* as literal 's' zero-or-more, not \s* (whitespace). This caused 'Authorization: Bearer <token>' to only redact 'Authorization:' and leak the actual token. Using [: ]* avoids the JSON/jq double-escape issue entirely and correctly matches both 'Authorization: Bearer xyz' and 'Authorization:xyz' patterns. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…#741) * fix(hooks): collapse multi-line commands in bash audit logs Add gsub("\\n"; " ") to jq filters in bash audit log and cost-tracker hooks so multi-line commands produce single-line log entries, preventing breakage in downstream line-based parsing. Fixes affaan-m#734 * fix: forward stdin to downstream hooks using echo pattern Addresses review feedback: PostToolUse hooks now preserve stdin for subsequent hooks by echoing $INPUT back to stdout after processing. Changed ; to && for proper error propagation. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: make stdin passthrough unconditional and broaden secret redaction - Use semicolons instead of && so printf passthrough always runs even if jq fails - Add || true after jq to prevent non-zero exit on parse errors - Use printf '%s\n' instead of echo for safe binary passthrough - Fix Authorization pattern to handle 'Bearer <token>' with space - Add ASIA (STS temp credentials) alongside AKIA redaction - Add GitHub token patterns (ghp_, gho_, ghs_, github_pat_) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: use [: ]* instead of s* for Authorization whitespace matching jq's ONIG regex engine interprets s* as literal 's' zero-or-more, not \s* (whitespace). This caused 'Authorization: Bearer <token>' to only redact 'Authorization:' and leak the actual token. Using [: ]* avoids the JSON/jq double-escape issue entirely and correctly matches both 'Authorization: Bearer xyz' and 'Authorization:xyz' patterns. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Summary
Fixes #734
Multi-line bash commands were producing multi-line log entries, breaking downstream line-based parsing tools (dashboards, frequency analysis).
Changes
gsub("\\n"; " ")to jq filters in both bash audit log and cost tracker hooks inhooks/hooks.jsonrules/hooks.mddocumentation to list the new hooksTest plan
Summary by cubic
Collapse multi-line Bash commands into single-line audit and cost-tracker logs, preserve stdin for downstream hooks, and harden secret redaction. Fixes #734.
jq gsub("\n"; " "); keep timestamps; robust Authorization redaction using[: ]*to handleAuthorization: Bearer <token>; redactAKIA/ASIA,--token,password=, and GitHub tokens (ghp_,gho_,ghs_,github_pat_); log to~/.claude/bash-commands.logand~/.claude/cost-tracker.log.printf '%s\n' "$INPUT"; use;so passthrough runs even ifjqfails; add|| trueafterjq.Written for commit 0c00f26. Summary will update on new commits.
Summary by CodeRabbit
New Features
Documentation