Skip to content

consumer-claude-code: mention-only triggers (propagated from template) - #75

Closed
assisted-by-ai wants to merge 6 commits into
masterfrom
ai-claude-review-mention-only
Closed

consumer-claude-code: mention-only triggers (propagated from template)#75
assisted-by-ai wants to merge 6 commits into
masterfrom
ai-claude-review-mention-only

Conversation

@assisted-by-ai

@assisted-by-ai assisted-by-ai commented Jul 28, 2026

Copy link
Copy Markdown

Byte-identical propagation of consumer-claude-code.yml from developer-meta-files/consumer-templates, paired with org-ai-assisted/developer-meta-files#165.

pull_request and workflow_dispatch resolve to claude-code-action's agent mode, whose trigger condition is a non-empty prompt input. This workflow passes no prompt, so those events could only spin up a runner and exit without calling the model:

Auto-detected mode: agent for event: pull_request
Context prompt: NO PROMPT
Trigger result: false
No trigger found, skipping remaining steps

The result was a green "Claude Code Review" check on every PR that had reviewed nothing. Triggers are now comment-only, which is the only path that ever reached the model.

Merge order does not matter: the reusable's job-level if: no longer accepts pull_request, so once #165 lands these repos stop producing misleading green checks either way. This PR removes the pointless runs entirely.

Generated with assistance from Claude Code.

Summary by CodeRabbit

  • Chores
    • Updated automated workflow triggers to run only for newly created issue comments and pull request review comments.
    • Simplified automation’s detection to trigger when the comment contains the designated assistant mention.
    • Refreshed workflow documentation to match the new trigger behavior.
  • Bug Fixes
    • Improved validation diagnostics for rejected inputs, including clearer, sanitized multi-line reporting.
    • Strengthened randomness to ensure the requested entropy size is reliably produced.
  • Tests
    • Updated unit-test approach and adjusted linting behavior; re-enabled a previously skipped validation test.

Byte-identical cp from developer-meta-files/consumer-templates.

pull_request and workflow_dispatch resolve to claude-code-action's
agent mode, whose trigger is a non-empty 'prompt' input that this
workflow does not pass, so those events could only spin up a runner
and exit without calling the model - a green "Claude Code Review"
check that reviewed nothing.

Co-Authored-By: Claude <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jul 28, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The Claude workflow now runs only for created comment events and filters for @claude. String helpers update file reading, numeric parsing, locale-sensitive validation, sanitized diagnostics, randomness checks, and related test behavior.

Changes

Workflow and string helper behavior

Layer / File(s) Summary
Comment trigger and job filtering
.github/workflows/consumer-claude-code.yml
The workflow listens only for created issue and pull request review comments, filters execution to comments containing @claude, and retains existing permissions, concurrency, reusable workflow, and OAuth token forwarding.
Input reading and locale validation
usr/libexec/helper-scripts/strings.bsh
File reads preserve unterminated final lines, integer bounds use explicit decimal parsing, and validation uses byte-consistent locale handling and filename length checks.
Diagnostic and input rejection behavior
usr/libexec/helper-scripts/strings.bsh
Validation diagnostics now sanitize rejected content and cap byte details; multiline checks explicitly reject carriage returns, with error-trap output using printf.
Randomness enforcement and test coverage
usr/libexec/helper-scripts/strings.bsh
Random generation detects short reads, displaytime assertions use run_display_test, shellcheck execution is conditional, and a Unicode rejection test is enabled.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Suggested reviewers: adrelanos

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: narrowing the workflow to comment-based mention-only triggers.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch ai-claude-review-mention-only

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

claude added 5 commits July 29, 2026 05:26
check_is_not_empty_and_only_one_line echoed the value it had just
rejected straight to the terminal with printf. Callers reach that branch
holding exactly the input they could not vouch for -- an api reply, a
config field, a filename -- so the value may carry ANSI escapes or a
U+202E right-to-left override and spoof what the operator reads about why
it was rejected. A validator whose failure path is itself an injection
vector undoes the reason it was called.

This was the only such site in the file. check_is_alpha_numeric already
reports through stecho on the same class of failure, so this is a
consistency fix as much as a security one; line 175 interpolates with %q
and is fine.

Verified at byte level rather than by eye, since the sandbox transport
sanitises its own output and hides the difference: with printf the stderr
contained a literal 0x1B, with stecho it is '_'. Exit status, the
accepted single-line case and the empty-value rejection are unchanged.

Co-Authored-By: Claude <noreply@anthropic.com>
The gate greps WHOLE changed files, so touching this file exposed three
pre-existing findings. All three are now green.

R-010 wanted a strict-mode preamble. It is a SOURCED library: setting
'set -o errexit' here would silently impose it on every caller's shell,
and the file's own header already documents that the caller owns that
choice. Waived with 'style-ok: no-strict' and the reason recorded, rather
than adding options a library has no business setting.

R-034: echo -> printf in the error trap.

R-042 flagged the trailing newline in random_alpha_numeric as a
decorative blank-line separator. It is not -- 'head --bytes' emits no
trailing newline, so that printf terminated the value. The two obvious
rewrites are both dead ends: R-030/R-031 requires the newline be spelled
printf '%s\n' "", which is exactly what R-042 rejects, and printf '\n' ""
is a shellcheck SC2182 error. Capturing the bytes and printing value and
terminator in one statement sidesteps the knot and reads better.
Behaviour verified unchanged for n=1/8/43: length, alphanumeric content,
trailing newline, and the non-numeric rejection.

Co-Authored-By: Claude <noreply@anthropic.com>
stecho is the wrong tool for echoing back a value that failed validation.
It passes SGR escape sequences through -- verified on this host, TERM
independent: given 'A\033[31mB\033[2J' it strips the clear-screen but
keeps the colour code, because stdisplay defaults sgr to
get_sgr_support(). SGR alone still spoofs, e.g. foreground matched to
background to hide text in the very message explaining the rejection. It
also imposes no length limit: a 5000-byte value produced 5001 bytes of
output.

sanitize-string escapes every ESC unconditionally and takes a maximum
length. All three sites that echo a rejected value now use it, capped at
200 characters: check_is_not_empty_and_only_one_line,
check_is_alpha_numeric and validate_safe_filename. The remaining stecho
call reports "empty!" and interpolates no value.

Verified: no ESC byte reaches stderr from any of the three, a 5000-byte
multi-line value reports in 297 bytes, and valid inputs are still
accepted.

Co-Authored-By: Claude <noreply@anthropic.com>
read_integer_file's bounds checks fail open on leading-zero input. The
value is validated as a string with ^[0-9]+$ and then compared inside
((...)), which reads a leading zero as octal. With file contents '08' and
bounds 0..7 both comparisons abort with "value too great for base", each
'if' is therefore false, and the function returns 0 and emits 08 -- above
the upper bound it was asked to enforce. '010' with bounds 9..100 is
rejected although the caller means decimal 10. Reproduced, then fixed by
forcing base 10 on both operands.

validate_safe_filename dumped the rejected value to stdout, raw and
uncapped, immediately above the sanitized stderr message -- so the
sanitizing was moot. Confirmed on this host: a filename containing U+202E
put the raw override bytes on stdout. It is also the wrong stream for a
library, corrupting any caller that captures stdout, and od amplifies its
input several-fold, defeating the length cap. The %q line is gone (%q runs
under the caller's locale and passes multibyte sequences through, which is
exactly why string_quote_safe exists) and the hex dump now goes to stderr,
capped.

random_alpha_numeric returned whatever it got. A failed read left the
value empty and the function still exited 0, handing a caller an empty
string where it asked for a secret. Length is now checked.

Verified: 08/010/5 bound cases, stdout empty and stderr sanitized for a
U+202E filename, and a 43-character result.

Co-Authored-By: Claude <noreply@anthropic.com>
string_bsh_tests began with 'shellcheck "$0"'. Sourced -- which is how
this library is used -- $0 is the CALLER, so it linted whatever invoked
the library, or died when that was not a file, and the ERR trap aborted
the function before a single assertion. Measured: 0 tests executed.
Linting BASH_SOURCE[0] instead, and skipping when shellcheck is absent,
brings the suite to 28 passed / 0 failed.

With it running, the rest:

- br_add_to_file dropped the final line of a file not ending in a
  newline: 'a\nb' produced only 'a<br />'. br_add, the same transform in
  memory, kept both.
- validate_safe_filename measured length in CHARACTERS against a limit
  that is 255 BYTES, so 200 multibyte letters (600 bytes) passed a check
  meant to guarantee the filesystem will accept the name.
- check_is_alpha_numeric accepted accented letters under a UTF-8 locale,
  because 'a-z' is resolved by collation. The test marked "unclear if
  this is possible" is now enabled and passes. check_valid_linux_user_-
  account_name got the same treatment: SYS_NAME_REGEX is meant
  byte-for-byte.
- its empty-value branch was unreachable -- the regex rejects "" first --
  so an empty value reported "Invalid character!". Checked before the
  regex now.
- check_is_not_empty_and_only_one_line accepted a carriage return as one
  line, though CR ends a line and rewrites it on a terminal. Also fixes
  the comment claiming the read trims whitespace; with IFS= it trims
  nothing.
- the six displaytime tests were vacuous: run_test passes a variable
  NAME, right for the name-based validators but not for a function taking
  a value, so every case was forced to T=0 and would have passed with the
  arithmetic entirely wrong. Replaced with output assertions, plus a
  non-numeric case.
- a zero-argument call read $1 before the arity check, killing the
  caller's shell under nounset instead of returning 1. Also 'stcat --'
  so a filename beginning with a dash is an operand.

Co-Authored-By: Claude <noreply@anthropic.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
usr/libexec/helper-scripts/strings.bsh (1)

194-200: 🎯 Functional Correctness | 🔵 Trivial

Hex-dump diagnostic includes a phantom trailing byte.

od -An -tx1 <<<"$value" uses a here-string, which appends a newline to $value before feeding it to od. The resulting hex dump on stderr will always show a trailing 0a that isn't actually part of the rejected value, which can mislead someone diagnosing the exact bytes that triggered rejection.

♻️ Avoid the synthetic trailing newline
-  LC_ALL=C od -An -tx1 <<<"$value" | head --bytes="$STRINGS_BSH_REPORT_MAX" >&2
+  LC_ALL=C printf '%s' "$value" | od -An -tx1 | head --bytes="$STRINGS_BSH_REPORT_MAX" >&2
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@usr/libexec/helper-scripts/strings.bsh` around lines 194 - 200, Update the
hex-dump diagnostic around the od invocation to feed the exact contents of value
without the here-string’s synthetic trailing newline, while preserving LC_ALL=C,
the byte cap, and stderr output.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@usr/libexec/helper-scripts/strings.bsh`:
- Around line 194-200: Update the hex-dump diagnostic around the od invocation
to feed the exact contents of value without the here-string’s synthetic trailing
newline, while preserving LC_ALL=C, the byte cap, and stderr output.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: a217de54-bc97-46d5-b1b4-bf66c2271ee4

📥 Commits

Reviewing files that changed from the base of the PR and between 871fc4b and 76d7c6b.

📒 Files selected for processing (1)
  • usr/libexec/helper-scripts/strings.bsh

@assisted-by-ai

Copy link
Copy Markdown
Author

Superseded by #78: this branch is merged into ai, which is now the single branch for this repo per the git skill (one branch named ai, one PR).

Two changes were made to this work while consolidating, both at the maintainer's request:

  • stecho is restored. It was replaced by printf '%s\n', which drops the escape sanitization stecho exists to provide.
  • the inline $(sanitize-string ...) in diagnostics is gone. It spawned a subshell per message and spliced the sanitized value back into a printf FORMAT string, so a % in untrusted text became a conversion spec. Diagnostics now go through the new sanitize-echo, one call, no substitution.

CodeRabbit's two findings on read_integer_file from the review of this branch are still open and carried forward.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants