Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 36 additions & 8 deletions .github/workflows/claude-code-review-on-demand.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,21 @@ name: Claude Code Review (on demand)
# - no `contents: write`, so it cannot push commits;
# - fires ONLY on a maintainer's comment (author_association gate), so an
# outside contributor on a fork can never trigger it.
#
# The checkout MUST be the PR's own ref, never the default one. Neither
# `issue_comment` nor `pull_request_review_comment` is a PR event, so
# actions/checkout with no `ref:` lands on the DEFAULT BRANCH — the review then
# reads `main` while claiming to review the PR. Files a PR adds or renames are
# simply absent, and nothing reports red (the job still succeeds). So the PR
# number is resolved FIRST and the checkout is pinned to it. `refs/pull/N/head`
# (not `/merge`): it is the tree the author actually pushed, it matches what
# `gh pr diff` and the inline-comment line anchors refer to, and unlike `/merge`
# it still exists when the PR has conflicts — a review is exactly what you want
# on a conflicted PR. Reading a PR ref needs no more than the `contents: read`
# this job already has — the write scopes below exist for posting comments, not
# for the checkout. So do NOT "fix" a checkout problem by reaching for
# `pull_request_target` or by widening permissions: neither was ever the
# blocker, and both trade a read problem for a write capability.
on:
issue_comment:
types: [created]
Expand All @@ -38,13 +53,11 @@ jobs:
id-token: write

steps:
# Note: claude-code-action adds its own 👀 reaction to the triggering
# comment, so there's no explicit reaction step here.
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 1

# Resolved BEFORE checkout: the checkout ref depends on it. The PR number
# lives in a different payload field per event — `issue.number` on
# issue_comment, `pull_request.number` on pull_request_review_comment —
# and each is absent on the other event, so branch on `event_name` rather
# than relying on a `||` fallback over a null.
- name: Prepare review context
id: prep
run: |
Expand All @@ -60,8 +73,23 @@ jobs:
} >> "$GITHUB_OUTPUT"
fi

# `fetch-depth: 1` is enough: the prompt forbids running the project's
# build/lint/test, and every allowed tool reads the diff through `gh`
# (the API), not through local history.
- name: Checkout PR head
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
with:
ref: refs/pull/${{ steps.prep.outputs.pr }}/head
fetch-depth: 1
Comment thread
thecodedrift marked this conversation as resolved.
# Nothing here writes to git, and this checkout is contributor-authored
# PR content — leaving the token in `.git/config` would put it a step
# away from anything that later runs in this tree.
persist-credentials: false

# Note: claude-code-action adds its own 👀 reaction to the triggering
# comment, so there's no explicit reaction step here.
- name: Run Claude Code Review
uses: anthropics/claude-code-action@v1
uses: anthropics/claude-code-action@d40ddef4c030e508327d6e35a9c45f3368482c50 # v1
with:
Comment thread
thecodedrift marked this conversation as resolved.
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
# Single tracking comment (in-progress → results), updated in place.
Expand Down
Loading