ci: gate claude.yml on author_association to skip unauthorized invokes#1270
Conversation
Previously the workflow's `if:` only checked the event type and the presence of `@claude` in the body. The job would start for any commenter and only later fail when the action attempted privileged operations on behalf of a user without write access. That produced noisy red runs and wasted runner minutes for what is effectively an authorization rejection. Add an `author_association` check (OWNER, MEMBER, or COLLABORATOR) to each of the four trigger branches (issue_comment, pull_request_review_comment, pull_request_review, issues), so the job is short-circuited at workflow evaluation time and never starts for unauthorized invokers. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
@claude review |
|
Claude finished @cliffhall's task in 57s —— View job Code Review
Overall: This is a well-reasoned, correct change. The approach — checking What's good
Minor observations1. For the This is arguably acceptable (and the 2. Style: The three-way OR for each event branch could be replaced with a single contains(fromJSON('["OWNER", "MEMBER", "COLLABORATOR"]'), github.event.comment.author_association)This reduces duplication across four trigger branches and makes the allowed-roles list easier to update in one place. Not a blocker, just a readability suggestion. Fix this → 3. No test for If the SummaryThe change is correct and achieves its goal cleanly. The two minor notes (edge case on
|
|
Thanks for the review. Responding to the three notes: 1. Good catch, and I think the conservative behavior is actually what we want here. For I'd leave this branch as-is, but happy to revisit if anyone hits a real workflow they want to enable. 2. Agreed this is cleaner — single source of truth for the allowed-roles list, and four fewer repeated contains(fromJSON('["OWNER", "MEMBER", "COLLABORATOR"]'), github.event.comment.author_association)(or the equivalent field per event). Holding off until there's a 👍 on point 1 so I'm not churning the diff. 3. Yep — fail-closed is the right default for an auth gate, even if accidental. No change needed. |
Per review feedback on PR #1270: replace the three-way `==` OR chain in each of the four trigger branches with a single contains(fromJSON(...)) check against a shared list. Same semantics, less duplication, and the allowed-roles list is now defined once per branch instead of three times. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Summary
Tighten the trigger conditions for
.github/workflows/claude.ymlso the job is skipped at workflow evaluation time when the invoking user does not have write access, rather than starting and later failing when the action tries to perform privileged operations.Background
We observed a case where someone left an
@claudecomment on a PR and the workflow started running, then errored out partway through because the commenter didn't have the repo permissions Claude needs to act on their behalf. That's the intended security posture (only trusted users should be able to drive Claude in this repo), but the failure mode wasn't great:Change
Add an
author_associationcheck to each of the four trigger branches (issue_comment,pull_request_review_comment,pull_request_review,issues). The job'sif:now requires the author to beOWNER,MEMBER, orCOLLABORATORin addition to the existing event-type and@claudebody checks.author_associationis supplied by GitHub on the event payload itself, so this check happens during workflow evaluation — before a runner is allocated. Comments from users without write access become silent no-ops instead of failed runs.This doesn't change who is allowed to drive Claude (the action itself already enforces this); it just moves the rejection earlier in the pipeline and makes it quiet.
Test plan
@claude ...from an account with write access on an issue or PR — workflow runs as before.@claude ...from an account without write access — workflow is skipped (no run appears in Actions), instead of starting and failing.issue_comment,pull_request_review_comment,pull_request_review,issues) behave consistently.🤖 Generated with Claude Code