From 1363e55bcf4fb24df00c583e49f3c9476b123e3a Mon Sep 17 00:00:00 2001 From: Luke Cichocki <999622+luke-cf@users.noreply.github.com> Date: Wed, 27 May 2026 11:45:51 +0200 Subject: [PATCH] fix(ci): guard-prod uses author_association instead of org members API MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previous implementation called gh api orgs//members/ with the workflow's GITHUB_TOKEN. The token authenticates as github-actions[bot] which is NOT an org member, so the API returns 404 for members whose membership is private - the script read that as "external contributor" and closed the PR. Symptom: PR main → prod opened by an admin/maintainer was auto-closed with the "PRs to prod are restricted to org members" comment. push:prod events were unaffected because guard-prod only runs on pull_request_target. Fix: use github.event.pull_request.author_association which GitHub already computes server-side per event. Values OWNER, MEMBER, COLLABORATOR allow the PR; anything else (CONTRIBUTOR / FIRST_TIME_CONTRIBUTOR / NONE) closes it. No extra API call, no token scope dependency, no private-membership false negatives. --- .github/workflows/guard-prod.yml | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/.github/workflows/guard-prod.yml b/.github/workflows/guard-prod.yml index 53a03cb..1fa4089 100644 --- a/.github/workflows/guard-prod.yml +++ b/.github/workflows/guard-prod.yml @@ -15,18 +15,24 @@ jobs: check: runs-on: ubuntu-latest steps: - - name: Check org membership + - name: Check author association env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + AUTHOR: ${{ github.event.pull_request.user.login }} + ASSOCIATION: ${{ github.event.pull_request.author_association }} + PR: ${{ github.event.pull_request.number }} + # GitHub computes author_association on the event itself - no extra API call, + # no auth-as-bot edge cases. OWNER/MEMBER/COLLABORATOR all imply trusted. + # Anyone else (CONTRIBUTOR, FIRST_TIME_CONTRIBUTOR, NONE) gets the PR closed. run: | - AUTHOR="${{ github.event.pull_request.user.login }}" - STATUS=$(gh api orgs/CodeFormers-it/members/$AUTHOR --silent -i 2>&1 | head -1 | grep -o '[0-9]\{3\}') - - if [ "$STATUS" != "204" ]; then - gh pr close ${{ github.event.pull_request.number }} \ - --repo ${{ github.repository }} \ - --comment "PRs to \`prod\` are restricted to org members. Please open your PR against \`main\` instead." - echo "Closed PR #${{ github.event.pull_request.number }} from external contributor $AUTHOR" - else - echo "$AUTHOR is an org member — PR allowed" - fi + case "$ASSOCIATION" in + OWNER|MEMBER|COLLABORATOR) + echo "$AUTHOR association=$ASSOCIATION - PR allowed" + ;; + *) + gh pr close "$PR" \ + --repo "${{ github.repository }}" \ + --comment "PRs to \`prod\` are restricted to org members. Please open your PR against \`main\` instead." + echo "Closed PR #$PR from $AUTHOR (association=$ASSOCIATION)" + ;; + esac