Skip to content

Run the review as a status check rather than a comment - #943

Closed
kwsantiago wants to merge 1 commit into
mainfrom
ci-review-gate
Closed

Run the review as a status check rather than a comment#943
kwsantiago wants to merge 1 commit into
mainfrom
ci-review-gate

Conversation

@kwsantiago

@kwsantiago kwsantiago commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Summary

The review step is the one that has been catching things, and nothing requires it. Merging needs seven status checks to pass and no review at all, so the loop is: write, CI passes, merge. This adds the review as a check so that step cannot be skipped.

The argument for gating on it rather than leaving it advisory is that CI has repeatedly gone green on defective changes in this repository. A clamp that made audit-registry corruption permanent and invisible, a latch that froze registry maintenance for the lifetime of the process, a lookup fix that resurrected deleted values, and a storage migration that erased a share after a write that reported success while storing nothing. Every one of those passed the full suite. Every one was caught by reading the diff. That asymmetry is what the check encodes.

The review returns a structured verdict rather than prose, and a following step fails the job on it. It fails closed: an empty or unparseable result is treated as a failure, because a gate that opens when it cannot evaluate is not a gate.

Severity is deliberately narrow. It blocks on four things: data that can be destroyed or made unreachable, a failure that resolves to the more permissive outcome, a test that asserts broken behavior is correct or that passes whether or not the code under test runs, and key material reaching any egress. Everything else is a note. A reviewer that blocks on everything gets turned off, and then nothing is reviewed at all.

Two conventions carried over from the existing guard workflow. The action is pinned by commit rather than the v1 tag, since a mutable tag on a job that gates merges is its own supply-chain hole. And there is no paths: filter, because a path-filtered job can never be a required check: a pull request touching none of the filtered globs reports nothing and blocks forever.

Test plan

The workflow parses. It cannot pass until an ANTHROPIC_API_KEY secret exists on the repository, so the run on this pull request is expected to fail on the missing secret, which is the fail-closed path working. Sequence to finish enabling it: add the secret, confirm a green run here, then add the check to branch protection. Adding it to protection before the secret exists would block every pull request.

Worth stating plainly since it is a recurring cost: this runs a model over the diff on every pull request, so it adds per-PR spend. Fork pull requests will not run it at all, because secrets are unavailable to them.

Summary by CodeRabbit

  • Chores
    • Added automated security-focused review checks for pull requests targeting the main branch.
    • Reviews now require a valid result and report blocking findings directly in the pull request checks.
    • Successful reviews complete with a passing status, while missing or invalid results fail validation.

@coderabbitai

coderabbitai Bot commented Aug 4, 2026

Copy link
Copy Markdown

Review Change Stack

Walkthrough

Changes

Claude review automation

Layer / File(s) Summary
Workflow trigger and Claude invocation
.github/workflows/claude-review.yml
The workflow runs on pull requests targeting main. It checks out full history and invokes a commit-pinned Claude action with the configured API secret.
Review prompt and verdict enforcement
.github/workflows/claude-review.yml
The prompt defines security-focused blocker criteria and a structured verdict. Result handling rejects invalid output, emits blocker annotations, and fails for block verdicts.

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

Sequence Diagram(s)

sequenceDiagram
  participant PullRequest
  participant GitHubActions
  participant ClaudeAction
  participant StatusCheck
  PullRequest->>GitHubActions: Trigger review for pull request targeting main
  GitHubActions->>ClaudeAction: Send repository history and security review prompt
  ClaudeAction-->>GitHubActions: Return structured pass or block result
  GitHubActions->>StatusCheck: Validate result and emit annotations
  StatusCheck-->>PullRequest: Pass or fail the review check
Loading

Poem

A rabbit reviews beneath the moon,
Claude checks each change in tune.
“Pass” hops forward, “block” stays near,
Clear errors make the verdict clear.
The workflow guards the code with cheer.

🚥 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 describes the main change from a comment-based review to a status check.
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 💡 1
🛠️ Fix failing CI checks 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch ci-review-gate

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.

@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.

Actionable comments posted: 1

🤖 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.

Inline comments:
In @.github/workflows/claude-review.yml:
- Around line 90-105: Update the verdict validation in the workflow block after
the `.blockers` output so only a complete, consistent result is accepted: allow
pass only with zero blockers and block only with one or more blockers, while
rejecting unknown or missing verdicts and contradictory blocker counts. Preserve
the existing blocker logging and fail the job with the current error behavior
for invalid results or blockers.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: b5beee40-fcbc-4474-9f37-440600e7d214

📥 Commits

Reviewing files that changed from the base of the PR and between 9954bbd and 3e6edcd.

📒 Files selected for processing (1)
  • .github/workflows/claude-review.yml

Comment on lines +90 to +105
if [ -z "${RESULT}" ] || ! printf '%s' "${RESULT}" | jq -e . >/dev/null 2>&1; then
echo "::error::The review produced no parseable verdict. Failing closed."
exit 1
fi

printf '%s' "${RESULT}" | jq -r '.summary'

printf '%s' "${RESULT}" | jq -r '
.blockers[]? |
"::error file=\(.file)\(if .line then ",line=\(.line)" else "" end)::\(.finding) — \(.failure)"
'

if [ "$(printf '%s' "${RESULT}" | jq -r '.verdict')" = "block" ]; then
echo "::error::Review found blockers. Fix them, or state why each is wrong."
exit 1
fi

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Reject contradictory verdicts before passing the check.

Line 102 only fails when .verdict equals "block". The declared schema permits "verdict":"pass" with non-empty blockers. Lines 97-100 emit those blockers, but the job exits successfully. A review can therefore report a concrete blocker while the required status check passes.

Validate the verdict and blocker count together. Reject unknown or incomplete verdict objects.

Proposed fix
           if [ -z "${RESULT}" ] || ! printf '%s' "${RESULT}" | jq -e . >/dev/null 2>&1; then
             echo "::error::The review produced no parseable verdict. Failing closed."
             exit 1
           fi
 
+          if ! printf '%s' "${RESULT}" | jq -e '
+            (.verdict == "pass" or .verdict == "block") and
+            (.blockers | type == "array") and
+            (.verdict == "block" or (.blockers | length == 0))
+          ' >/dev/null; then
+            echo "::error::The review produced an invalid verdict. Failing closed."
+            exit 1
+          fi
+
           printf '%s' "${RESULT}" | jq -r '.summary'
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if [ -z "${RESULT}" ] || ! printf '%s' "${RESULT}" | jq -e . >/dev/null 2>&1; then
echo "::error::The review produced no parseable verdict. Failing closed."
exit 1
fi
printf '%s' "${RESULT}" | jq -r '.summary'
printf '%s' "${RESULT}" | jq -r '
.blockers[]? |
"::error file=\(.file)\(if .line then ",line=\(.line)" else "" end)::\(.finding) — \(.failure)"
'
if [ "$(printf '%s' "${RESULT}" | jq -r '.verdict')" = "block" ]; then
echo "::error::Review found blockers. Fix them, or state why each is wrong."
exit 1
fi
if [ -z "${RESULT}" ] || ! printf '%s' "${RESULT}" | jq -e . >/dev/null 2>&1; then
echo "::error::The review produced no parseable verdict. Failing closed."
exit 1
fi
if ! printf '%s' "${RESULT}" | jq -e '
(.verdict == "pass" or .verdict == "block") and
(.blockers | type == "array") and
(.verdict == "block" or (.blockers | length == 0))
' >/dev/null; then
echo "::error::The review produced an invalid verdict. Failing closed."
exit 1
fi
printf '%s' "${RESULT}" | jq -r '.summary'
printf '%s' "${RESULT}" | jq -r '
.blockers[]? |
"::error file=\(.file)\(if .line then ",line=\(.line)" else "" end)::\(.finding) — \(.failure)"
'
if [ "$(printf '%s' "${RESULT}" | jq -r '.verdict')" = "block" ]; then
echo "::error::Review found blockers. Fix them, or state why each is wrong."
exit 1
fi
🤖 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 @.github/workflows/claude-review.yml around lines 90 - 105, Update the
verdict validation in the workflow block after the `.blockers` output so only a
complete, consistent result is accepted: allow pass only with zero blockers and
block only with one or more blockers, while rejecting unknown or missing
verdicts and contradictory blocker counts. Preserve the existing blocker logging
and fail the job with the current error behavior for invalid results or
blockers.

@kwsantiago

Copy link
Copy Markdown
Contributor Author

Closing: not adding an API key to this repository. The review stays advisory rather than gating.

@kwsantiago kwsantiago closed this Aug 4, 2026
@kwsantiago
kwsantiago deleted the ci-review-gate branch August 4, 2026 20:26
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.

1 participant