Skip claude-review on fork PRs instead of failing - #2300
Merged
Merged
Conversation
GitHub clamps pull_request runs whose head is a fork: the id-token: write this workflow declares is silently dropped and the secret store is withheld (Secret source: None, claude_code_oauth_token: ""). The action then dies on "Could not fetch an OIDC token. Did you remember to add `id-token: write` to your workflow permissions?" — an error that accuses the workflow file for a permission it already declares, sending anyone debugging from the message alone to edit correct code. Approving the run does not restore secrets, and GITHUB_TOKEN is read-only on fork PRs, so the `gh pr comment` the job is asked to make could not post either. Guard the job on head.repo.full_name == github.repository so it reports skipped — which is what actually happens — rather than a red X no contributor can clear. Dependabot branches live in this repository, so they pass the guard and the OIDC exchange works unchanged. Observed on run 33611167884 (PR #2296); dependabot control is run 33788653880.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
claude-reviewfails on every fork-based PR, and the error message points at the wrong thing.Observed on #2296 (run 33611167884):
.github/workflows/claude-code-review.ymldoes declareid-token: write. GitHub dropped it, because the head repo is a fork. The effective grant on that run:No
IdToken, everything read-only, no secrets. Anyone debugging from the error text alone will go edit a file that is already correct.Three independent blockers, any one fatal
id-token: writedowngraded → no OIDCACTIONS_ID_TOKEN_REQUEST_URLmissing; 3 retries, all failSecret source: None,"claude_code_oauth_token": ""GITHUB_TOKENread-onlygh pr commentcould not post regardlessTwo things people assume will fix it, which don't:
run_attempt: 2, triggering_actor: JSv4— already maintainer-approved — and still showsSecret source: None. Approval lets an untrusted workflow start; it does not hand it credentials.OIDC token successfully obtained→Exchanging OIDC token for app token...→App token successfully obtained→Using GITHUB_TOKEN from OIDC. The secret is fine.Across the last 40 runs of this workflow, every non-fork branch succeeds and the only two non-successes are the only two fork PRs (#2296
failure, andfix/local-session-restorationstill sitting ataction_required).Change
One line on the job, plus a comment recording why:
The job now reports skipped on fork PRs — which is accurate, it genuinely cannot run — instead of a red X the contributor has no way to clear and no fault in. Dependabot is unaffected: its branches live in this repository, so the guard passes and the OIDC exchange works exactly as before.
The commented-out "Optional: Filter by PR author" scaffolding it replaces is removed rather than left alongside.
Why not
pull_request_targetThat's the obvious fix and it's a trap, so the comment in the workflow says so explicitly.
pull_request_targetruns in base-repo context with full secrets, OIDC and a write-capable token — and reviewing a PR means checking out the untrusted head. On afrontend/PR a singleyarn installis postinstall RCE against the org'sCLAUDE_CODE_OAUTH_TOKEN.Even without code execution, the diff is attacker-controlled input the model reads. The action's own docs say it (
allowed_non_write_users): "Processing untrusted content exposes the workflow to prompt injection... best-effort scrub... reduces but does not eliminate." The narrowclaude_argsallowlist (ghsubcommands only) is what holds the line today;pull_request_targetwould pair injected text with a write-capable token.To review a fork PR on demand, comment
@claudeon it —.github/workflows/claude.ymlfires onissue_comment, which runs in base context with secrets intact, and the action gates on the commenter's write permission, so maintainers can invoke it and contributors can't.Scope
Only
claude-code-review.yml.CODECOV_TOKENis the other non-default secret in.github/workflows/, used bybackend.yml,frontend.yml,codecov-notify.ymland the threefrontend-e2e-*.ymlfiles; those are untouched here and worth a separate look if fork PRs turn out to trip them too.Verification
pre-commit run --files .github/workflows/claude-code-review.yml changelog.d/claude-review-fork-skip.fixed.md→ all hooks pass (check yaml,validate changelog fragments).yaml.safe_loadon the workflow parses; the guard lands onjobs.claude-review.ifandpermissionsis unchanged.claude-reviewran (34009576994) withSecret source: Actions,OIDC token successfully obtained,Exchanging OIDC token for app token— i.e. theif:evaluated true and the job reached the authenticated path. The negative case can only be exercised by an actual fork PR; fix(frontend): stabilize label-set workflows #2296 will exercise it on its next sync after this merges.One thing this run surfaced that is not fixed here
That job reports pass without having reviewed anything:
claude-code-actionrefuses to run when the PR modifies the workflow that invokes it — sensible, since a PR could otherwise rewrite the review prompt — but it exits success, not skipped. So every PR touching.github/workflows/gets a greenclaude-reviewwith no review behind it, and nothing in the check name says so. Pre-existing upstream behavior, orthogonal to this change, and worth its own issue rather than scope creep here.