From 8fd16b7c45f58ac09aa19643efd4c7e0dd1242ca Mon Sep 17 00:00:00 2001 From: Roger Barreto <19890735+RogerBarreto@users.noreply.github.com> Date: Wed, 15 Jul 2026 11:13:53 +0100 Subject: [PATCH 1/2] CI: resolve PR author in community team check pull_request_target events expose the author on payload.pull_request, not payload.issue. Read that field first and fall back to pulls.get so limit-community-prs no longer calls issues.get and fails with 401. --- .github/scripts/check_team_membership.js | 27 ++++++++--- .github/tests/test_check_team_membership.js | 53 ++++++++++++++++++++- 2 files changed, 71 insertions(+), 9 deletions(-) diff --git a/.github/scripts/check_team_membership.js b/.github/scripts/check_team_membership.js index ca8e75f1d13..8815f2833eb 100644 --- a/.github/scripts/check_team_membership.js +++ b/.github/scripts/check_team_membership.js @@ -12,14 +12,27 @@ * @returns {Promise<{author: string|null, isTeamMember: boolean}>} */ async function checkTeamMembership({ github, context, core, teamSlug, issueNumber }) { - let author = context.payload.issue?.user?.login; + let author = + context.payload.issue?.user?.login ?? + context.payload.pull_request?.user?.login; + if (!author) { - const { data: issue } = await github.rest.issues.get({ - owner: context.repo.owner, - repo: context.repo.repo, - issue_number: Number(issueNumber), - }); - author = issue.user?.login; + const number = Number(issueNumber); + if (context.payload.pull_request) { + const { data: pr } = await github.rest.pulls.get({ + owner: context.repo.owner, + repo: context.repo.repo, + pull_number: number, + }); + author = pr.user?.login; + } else { + const { data: issue } = await github.rest.issues.get({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: number, + }); + author = issue.user?.login; + } } if (!author) { diff --git a/.github/tests/test_check_team_membership.js b/.github/tests/test_check_team_membership.js index 6fbec9ff609..2e35135b9e7 100644 --- a/.github/tests/test_check_team_membership.js +++ b/.github/tests/test_check_team_membership.js @@ -16,7 +16,12 @@ const checkTeamMembership = require('../scripts/check_team_membership.js'); // Helpers // --------------------------------------------------------------------------- -function createMocks({ payloadIssue = undefined, apiUser = 'api-user', teamState = 'active' } = {}) { +function createMocks({ + payloadIssue = undefined, + payloadPullRequest = undefined, + apiUser = 'api-user', + teamState = 'active', +} = {}) { const core = { _infoMessages: [], _failedMessages: [], @@ -24,8 +29,16 @@ function createMocks({ payloadIssue = undefined, apiUser = 'api-user', teamState setFailed(msg) { this._failedMessages.push(msg); }, }; + const payload = {}; + if (payloadIssue !== undefined) { + payload.issue = payloadIssue; + } + if (payloadPullRequest !== undefined) { + payload.pull_request = payloadPullRequest; + } + const context = { - payload: { issue: payloadIssue }, + payload, repo: { owner: 'test-org', repo: 'test-repo' }, }; @@ -36,6 +49,11 @@ function createMocks({ payloadIssue = undefined, apiUser = 'api-user', teamState data: { user: apiUser ? { login: apiUser } : null }, }), }, + pulls: { + get: async () => ({ + data: { user: apiUser ? { login: apiUser } : null }, + }), + }, teams: { getByName: async () => ({}), getMembershipForUserInOrg: async () => ({ @@ -64,6 +82,37 @@ describe('author resolution', () => { assert.equal(result.author, 'payload-user'); }); + it('resolves author from pull_request event payload', async () => { + const { github, context, core } = createMocks({ + payloadPullRequest: { user: { login: 'pr-author' } }, + }); + let issuesGetCalled = false; + github.rest.issues.get = async () => { + issuesGetCalled = true; + return { data: { user: { login: 'api-user' } } }; + }; + + const result = await checkTeamMembership({ github, context, core, ...BASE_OPTS }); + assert.equal(result.author, 'pr-author'); + assert.equal(issuesGetCalled, false); + }); + + it('resolves author via pulls API when pull_request payload user is null', async () => { + const { github, context, core } = createMocks({ + payloadPullRequest: { user: null }, + apiUser: 'fetched-pr-author', + }); + let pullsGetCalled = false; + github.rest.pulls.get = async () => { + pullsGetCalled = true; + return { data: { user: { login: 'fetched-pr-author' } } }; + }; + + const result = await checkTeamMembership({ github, context, core, ...BASE_OPTS }); + assert.equal(result.author, 'fetched-pr-author'); + assert.equal(pullsGetCalled, true); + }); + it('resolves author via API when payload issue is absent', async () => { const { github, context, core } = createMocks({ apiUser: 'api-user' }); const result = await checkTeamMembership({ github, context, core, ...BASE_OPTS }); From a63468d1d10bb8cbbed16af52ba712f4da3045c9 Mon Sep 17 00:00:00 2001 From: Roger Barreto <19890735+RogerBarreto@users.noreply.github.com> Date: Wed, 15 Jul 2026 11:38:47 +0100 Subject: [PATCH 2/2] Docs: clarify issueNumber accepts PR numbers --- .github/scripts/check_team_membership.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/scripts/check_team_membership.js b/.github/scripts/check_team_membership.js index 8815f2833eb..46705d648ef 100644 --- a/.github/scripts/check_team_membership.js +++ b/.github/scripts/check_team_membership.js @@ -1,14 +1,14 @@ // Copyright (c) Microsoft. All rights reserved. /** - * Resolve the issue author and check their team membership. + * Resolve the issue or pull request author and check their team membership. * * @param {object} opts * @param {object} opts.github - Octokit REST client from actions/github-script * @param {object} opts.context - GitHub Actions context * @param {object} opts.core - GitHub Actions core toolkit * @param {string} opts.teamSlug - Team slug to check membership against - * @param {string|number} opts.issueNumber - Issue number to resolve author for + * @param {string|number} opts.issueNumber - Issue or pull request number to resolve author for * @returns {Promise<{author: string|null, isTeamMember: boolean}>} */ async function checkTeamMembership({ github, context, core, teamSlug, issueNumber }) {