Revert claude-review to the pull_request trigger - #89
Conversation
Anthropic's token-exchange endpoint rejects OIDC tokens minted for pull_request_target events, so every review run since #83 failed with "401 Unauthorized - Invalid OIDC token" before Claude started. Tracked upstream as anthropics/claude-code-action#713, still open. Also drops the untrusted head-ref checkout #83 added, which the action's own security doc warns against for pull_request_target, and restores pull-requests: read. Closes #88 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HMmB6db4xpbuqcqaQKArZb
|
Working on this --- paws off until I'm done. |
|
Both
|
| Run | Trigger | Outcome |
|---|---|---|
| 30680266785 | pull_request (this branch's workflow) |
pass, 11s |
| 30680266779 | pull_request_target (main's workflow) |
fail, 25s |
Read the logs rather than the colors --- the green one is a skip, not a review:
Skipping action due to workflow validation: Workflow validation failed.
The workflow file must exist and have identical content to the version on
the repository's default branch.
That is the documented behavior for a PR that edits the review workflow, and the action exits 0 on it.
The point is where each run stopped. The pull_request run's OIDC token was accepted and it got as far as workflow validation; the pull_request_target run, in the same repo, in the same minute, on the same secret, was rejected outright at 401 Invalid OIDC token. That is the cleanest available demonstration of the cause, since the only variable between them is the trigger event.
The red check is main's current workflow reviewing this PR. It cannot go green before merge, and it stops firing once this lands. main is unprotected, so it does not block.
No external verdict is obtainable at this head, so I have requested Copilot review and will self-review in the meantime.
There was a problem hiding this comment.
Pull request overview
Restores the Claude Code Review GitHub Actions workflow to use the pull_request trigger to address consistent OIDC→App-token exchange failures observed under pull_request_target, and tightens the workflow’s checkout and permissions accordingly.
Changes:
- Switch workflow trigger from
pull_request_targetback topull_request, with an inline comment referencing the upstream Anthropic issue. - Remove checkout of the PR head SHA to avoid checking out an untrusted ref into a secrets-bearing workspace.
- Reduce
pull-requestspermission fromwritetoread(the action posts using its own app token).
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Ready for mergeCopilot reviewed the current head ( Checks:
That last one is red by design, not oversight: it is
Not merging --- that is yours to call. |
Correction: this repo does have a fork PRThe body's "Fork PRs" section claimed none had ever been opened here. That is false --- #77 ( A second claim in #88 was wrong the same way: I described run 30663424918 as "missing The revert still stands, on a corrected argument. Nothing in the diff changes. Re-requesting review since the description Copilot reviewed no longer matches. |
|
Copilot re-reviewed at 02:52Z against the corrected description: "reviewed 1 out of 1 changed files and generated no new comments." Two clean reviews now, zero inline comments, and the diff is unchanged from the first one. Still ready; still yours to merge. |
|
Correction, post-merge: one claim in this PR was false, and #91 is fixing its consequence. I wrote that reducing I also called this diff "byte-identical to the last version that produced successful reviews." Byte-identical, yes. Producing reviews, no: So the trigger fix here was right and the permissions change rode along on an untested premise. Both facts held at once and the second was invisible, because a green check is what a silently-dropped review looks like --- the same reading failure this PR's own description warns about for the workflow-validation skip, one line lower in the same file. Fixed forward in #91 rather than by reopening this. Evidence posted there. |
pull-requests was narrowed to read in UCD-SERG#89 while fixing the OIDC failure, but that also silently disables posting reviews on same-repo PRs: the job runs and succeeds, but every write attempt is denied (confirmed via permission_denials_count in the job log) and no review ever appears. write is safe to restore here: this workflow uses the pull_request trigger (not pull_request_target), and GitHub always forces a read-only GITHUB_TOKEN for fork PRs regardless of what permissions: declares, so fork PRs stay read-only either way.
claude-code-review.yml can't work for fork PRs: pull_request events from forks never receive an OIDC token at all (GitHub never sets ACTIONS_ID_TOKEN_REQUEST_URL for them, regardless of id-token: write - confirmed on PR UCD-SERG#77, run 30686460528/job/91333167166), and switching to pull_request_target doesn't help either since Anthropic's token-exchange endpoint rejects OIDC tokens minted under that event (UCD-SERG#89, anthropics/claude-code-action#713). issue_comment is subject to neither restriction. Add a workflow, gated to OWNER/MEMBER/COLLABORATOR commenters, that a maintainer can trigger with "@claude review" on any PR - fork or not - to get the same review claude-code-review.yml gives same-repo PRs.
Closes #88.
What was broken
Every
Claude Code Reviewrun has failed since #83 merged, at the token-exchange step:Claude never got as far as reading a diff.
The most recent instance is
run 30677231096 on #76.
Why
#83 switched the trigger to
pull_request_target.Anthropic's exchange endpoint rejects OIDC tokens minted for that event.
The action's code supports it; the server side does not.
Open upstream since 2025-12-02 as
anthropics/claude-code-action#713,
whose stated workaround is to use
pull_request.Five of five
pull_request_targetruns failed this way, and nopull_requestrunever has --- the two runs immediately before the switch both succeeded.
The full before/after table is in #88.
What this changes
pull_request, with a comment naming the upstream issueso the switch does not get re-applied.
ref: ${{ github.event.pull_request.head.sha }}.The action's security doc
warns against checking an untrusted ref into the workspace root of a job
holding the base repository's secrets.
pull-requests: read.The action posts with its own app token, so the workflow token does not need write.
The result is byte-identical to the last version that produced successful reviews,
plus the comment.
Fork PRs
Corrected. This section originally said no fork PR had ever been opened against
this repo. That is false: #77
(
imelainew/ucd-serg.github.io) has been open since 2026-06-30. I readmainin thebranch column as a same-repo branch without checking
head.repo.fork.The revert is unchanged, but the reason has to be the true one.
A fork PR gets no Claude review under either configuration:
pull_request, GitHub withholds the secret and the OIDC token from a fork PRwhatever the
permissions:block says.Run 30663424918
on Add Elaine Wang profile to team page #77 logs
"claude_code_oauth_token": ""and then fails to get an OIDC token ---under an error message that wrongly blames a missing
id-token: write.pull_request_target, the exchange 401s for every PR, forks included.And a working exchange would still leave the action refusing to run for a contributor
without write access unless
allowed_non_write_usersis set, which upstream documentsas a significant security risk.
So
pull_request_targetwas not buying fork coverage at the cost of everything else.It was reviewing nothing. This revert restores reviews for the three same-repo PRs and
leaves #77 exactly where it already was, tracked as
#90.
#84 remains separate --- Copilot-authored PRs fail the same step with
User does not have write access on this repository, a non-collaborator triggeringactor on a same-repo branch.
Verification
Corrected after the first run. This section originally said a green
claude-reviewon this PR would be the fix testing itself. That is wrong, and the reason is worth stating,
since the check does go green.
Because this PR edits the review workflow, the head version no longer matches the copy on
the default branch, so the exchange endpoint returns a workflow-validation error and the
action skips, exiting 0. The green check is a skip, not a review.
What the two runs do establish is where each one stopped, which is the thing in question:
pull_requestpull_request_target401 Invalid OIDC token--- rejected outrightSame repo, same secret, same minute, one variable. The red check is
main's currentworkflow reviewing this PR; it cannot go green before merge and stops firing afterward.
mainis unprotected, so nothing is blocked.A real end-to-end review is only observable on the next PR after this one merges.