Skip to content

fix(pr-review): author_association check is blind to private org membership — self-PRs get blocked as external #253

@cbeaulieu-gt

Description

@cbeaulieu-gt

Symptom

A maintainer's own PR is rejected by pr-review with the message:

Automated review is restricted to repository members. A maintainer can trigger a review by commenting @claude review this PR.

…even though the maintainer is an admin / MEMBER of the repository.

Concrete reproducer: glitchwerks/mom-bot#20. PR opener: cbeaulieu-gt (admin, role_name=admin, MEMBER per gh api repos/glitchwerks/mom-bot/pulls/20). Two claude-pr-review runs (25602531075 and 25602562131), both posted the "restricted" message and skipped review. Workflow log:

AUTHOR_ASSOCIATION: CONTRIBUTOR

Root cause

pr-review/action.yml step Check author association (lines 139–155) gates the review on:

AUTHOR_ASSOCIATION: ${{ github.event.pull_request.author_association }}

GitHub's pull_request event payload does not disclose private org membership. When the user's org membership is set to private (default for personal-org / single-operator setups), the runtime value of author_association is CONTRIBUTOR, not MEMBER — even when the user is an org admin. Documented quirk; not a regression. References:

Same trap applies to pull_request_target (which pr-review is triggered by).

Why it surfaces now

This is a pre-existing bug, not a regression from #250 / PR #252. v2 is currently at e92a334 (pre-#250 merge). Surfaced today because mom-bot's PR #20 was the first run watched closely after the #250 work sensitized us to pr-review behavior.

Fix options

  1. Fallback API check. When author_association is not OWNER/MEMBER/COLLABORATOR, call gh api repos/$OWNER/$REPO/collaborators/$ACTOR (returns 204 if collaborator, 404 otherwise). This needs Read:Members only, available with github.token for repo-scoped collaborator queries. Cleanest fix — handles both public and private membership.
  2. authorized_users allowlist input on pr-review/action.yml. Mirror the pattern that check-auth/ already provides. Caller workflow passes authorized_users: cbeaulieu-gt and the gate accepts it as the highest-priority signal. Lower complexity but requires every consumer to maintain the list.
  3. Refactor pr-review to delegate to check-auth/. It already has authorized_users + association fallback semantics. Cleanest from an architectural standpoint (removes duplication of auth logic across actions). Larger diff.

Recommended: (1) + (2). Implement the API fallback as the primary fix (zero-config for common cases), keep authorized_users available as an explicit override for orgs where the API check is blocked or where a non-collaborator should be allowlisted (e.g. a CI-only bot account).

Acceptance

  • pr-review/action.yml auth step does not block a PR by an actual collaborator/admin whose org membership is private.
  • PRs by genuine non-members are still blocked (the "restricted" message is correct in that case).
  • Optional authorized_users input on pr-review/action.yml provides explicit override.
  • Verified on glitchwerks/mom-bot (or this repo) by floating v2 against a feature branch and re-running on a real PR — the verification rule from skills/github-actions/SKILL.md § 13 applies (a self-referencing dogfood will execute the OLD @v2 code, not the branch code).

🤖 Generated by Claude Code on behalf of @cbeaulieu-gt

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingci

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions