Skip to content

Add post-patch-validation plugin #440

Add post-patch-validation plugin

Add post-patch-validation plugin #440

Workflow file for this run

# Automated review on pull requests.
#
# An organization-level ANTHROPIC_API_KEY is visible to this repository, so this
# workflow is LIVE the moment it merges — it will start reviewing PRs immediately.
# (It is not listed by `gh secret list` at the repo level, which is what made this
# easy to get wrong.)
#
# Every review step is still gated on the key being present, so if the org secret is
# ever removed these jobs go quiet rather than red. A review workflow that fails on
# every PR for want of a credential teaches people to ignore red checks.
#
# One tier, deliberately. This was two — a cheap pass on every push and an xhigh
# adversarial pass behind a `deep-review` label — and the split did not survive
# contact: the label was never created, so the deep tier skipped 9 times and ran
# zero, while every real review came from the cheap tier. Rather than wire up a
# label to remember to apply, the default is now the strong review.
#
# Fork PRs get NO automated review. A `pull_request_target` variant was written and
# then deleted: it checked out the fork tree and ran this repo's review script from
# it, so the script itself — and any CLAUDE.md or .claude/hooks beside it — was
# fork-authored and executed with the org API key in the environment. The SHA pin
# and the tool allowlist did not touch that path. Doing it safely means checking
# out base into the workspace and the fork commit into a subdirectory, running
# everything from base; that is a deliberate piece of work, not a footnote to this
# change.
name: Claude Review
on:
pull_request:
# ready_for_review is load-bearing: the job skips drafts, so without it a
# draft-then-ready PR gets no event and no review at all.
types: [opened, synchronize, reopened, ready_for_review]
# Granted per job rather than here. A workflow-level write grant applies to every job
# including ones that never need it, which zizmor flags as excessive-permissions.
permissions: {}
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number }}
cancel-in-progress: true
jobs:
review:
name: Claude review
# Skips drafts, bots, and forks. Forks are excluded because under `pull_request`
# they get a read-only token and could not post a comment anyway, and the
# privileged alternative is unsafe (above).
if: >-
github.event.pull_request.draft == false &&
github.event.pull_request.user.type != 'Bot' &&
github.event.pull_request.head.repo.fork == false
runs-on: ubuntu-latest
# xhigh on a large diff needs room. The old cheap tier ran in 20.
timeout-minutes: 30
permissions:
# read: check out the diff under review.
contents: read
# write: post the review as a PR comment. This is the whole point of the job —
# a run that cannot comment produces a green check and no review, which reads
# as "reviewed and clean".
pull-requests: write
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
# Needs history to diff against origin/main. At depth 1 the diff comes back
# empty, which is indistinguishable from "nothing to find".
fetch-depth: 0
persist-credentials: false
# The key is reduced to a boolean here so that no later step needs it in scope
# merely to test for it. `secrets` is not available in a step-level `if:`, so
# gating on presence otherwise means putting the secret in that step's `env:` —
# which for the install step below would run npm lifecycle scripts, from an
# unpinned version nobody chose, beside an org-wide credential.
- name: Check for API key
id: key
env:
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
run: |
if [ -n "$ANTHROPIC_API_KEY" ]; then
echo "present=true" >>"$GITHUB_OUTPUT"
else
echo "present=false" >>"$GITHUB_OUTPUT"
echo "ANTHROPIC_API_KEY is not visible here; skipping the review." >&2
fi
# Deliberately unpinned: the reviewer should get CLI fixes and features as they
# ship. The trade is that a bad release can change review behaviour with no
# commit here, so `claude_review.sh` logs the resolved version and model on every
# run — that is what makes a surprising review attributable afterwards. The model
# itself IS pinned, in that script; it is the larger lever on review quality.
# Note this step holds no secret, which is what makes @latest acceptable here.
- name: Install Claude Code CLI # zizmor: ignore[adhoc-packages]
if: steps.key.outputs.present == 'true'
run: |
npm install --global --prefix "$RUNNER_TEMP/claude-cli" \
"@anthropic-ai/claude-code@latest"
- name: Review
if: steps.key.outputs.present == 'true'
env:
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
PR_NUMBER: ${{ github.event.pull_request.number }}
REPO: ${{ github.repository }}
run: |
export PATH="$RUNNER_TEMP/claude-cli/bin:$PATH"
.github/scripts/claude_review.sh