Skip to content

Commit 85a3d83

Browse files
authored
fix(ci): fetch author_association via REST API instead of webhook payload (#444)
The webhook payload field context.payload.pull_request.author_association is unreliable under pull_request_target events — it was absent or not populated, causing the previous fix (#442) to still fail. Switch to fetching author_association via pulls.get REST API, which only needs pull-requests permission (already granted) and reliably returns MEMBER for org members regardless of membership visibility. Also removes the redundant orgs.checkMembershipForUser and repos.checkCollaborator fallbacks, which suffered from the same GITHUB_TOKEN permission limitation that started this bug. Co-authored-by: John Myers <[email protected]>
1 parent 240d0ee commit 85a3d83

File tree

1 file changed

+13
-35
lines changed

1 file changed

+13
-35
lines changed

.github/workflows/vouch-check.yml

Lines changed: 13 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -19,56 +19,34 @@ jobs:
1919
script: |
2020
const author = context.payload.pull_request.user.login;
2121
const authorType = context.payload.pull_request.user.type;
22-
const authorAssociation = context.payload.pull_request.author_association;
2322
2423
// Skip bots (dependabot, renovate, github-actions, etc.).
2524
if (authorType === 'Bot') {
2625
console.log(`${author} is a bot. Skipping vouch check.`);
2726
return;
2827
}
2928
30-
// Check author_association from the webhook payload. This is set by
31-
// GitHub itself and doesn't require extra token permissions, so it
32-
// works reliably for org members even when their membership is private.
29+
// Fetch author_association via the REST API. The webhook payload
30+
// field (context.payload.pull_request.author_association) is
31+
// unreliable under pull_request_target — it can be absent or stale.
32+
// The pulls.get endpoint only needs pull-requests permission, which
33+
// we already have, and reliably returns MEMBER for org members even
34+
// when their membership is private.
3335
const trustedAssociations = ['MEMBER', 'OWNER', 'COLLABORATOR'];
34-
if (trustedAssociations.includes(authorAssociation)) {
35-
console.log(`${author} has author_association=${authorAssociation}. Skipping vouch check.`);
36-
return;
37-
}
38-
39-
// Fallback: explicit API checks in case author_association is unexpected.
40-
41-
// Check org membership — members bypass the vouch gate.
4236
try {
43-
const { status } = await github.rest.orgs.checkMembershipForUser({
44-
org: context.repo.owner,
45-
username: author,
46-
});
47-
if (status === 204 || status === 302) {
48-
console.log(`${author} is an org member (API). Skipping vouch check.`);
49-
return;
50-
}
51-
} catch (e) {
52-
if (e.status !== 404) {
53-
console.log(`Org membership check error: ${e.message}`);
54-
}
55-
}
56-
57-
// Check collaborator status — direct collaborators bypass.
58-
try {
59-
const { status } = await github.rest.repos.checkCollaborator({
37+
const { data: pr } = await github.rest.pulls.get({
6038
owner: context.repo.owner,
6139
repo: context.repo.repo,
62-
username: author,
40+
pull_number: context.payload.pull_request.number,
6341
});
64-
if (status === 204) {
65-
console.log(`${author} is a collaborator (API). Skipping vouch check.`);
42+
const association = pr.author_association;
43+
console.log(`${author}: author_association=${association}`);
44+
if (trustedAssociations.includes(association)) {
45+
console.log(`${author} has author_association=${association}. Skipping vouch check.`);
6646
return;
6747
}
6848
} catch (e) {
69-
if (e.status !== 404) {
70-
console.log(`Collaborator check error: ${e.message}`);
71-
}
49+
console.log(`Failed to fetch PR author_association: ${e.message}`);
7250
}
7351
7452
// Check the VOUCHED.td file on the dedicated "vouched" branch.

0 commit comments

Comments
 (0)