22name : " Vercel Preview"
33
44" on " :
5- pull_request :
5+ pull_request_target :
66 types :
77 - " opened"
88 - " synchronize"
@@ -21,33 +21,48 @@ jobs:
2121 deployments : " write"
2222 pull-requests : " write"
2323 steps :
24- - name : " Checkout code"
25- uses : " actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd" # v6
26-
2724 - name : " Check collaborator write access"
2825 id : " permission"
2926 uses : " actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b" # v7
3027 with :
3128 result-encoding : " string"
3229 script : |
33- const author = context.payload.pull_request.user.login;
34- try {
35- const { data } = await github.rest.repos.getCollaboratorPermissionLevel({
36- owner: context.repo.owner,
37- repo: context.repo.repo,
38- username: author,
39- });
40- const hasWrite = ['write', 'maintain', 'admin'].includes(data.permission);
41- core.info(`${author} has permission '${data.permission}' — hasWrite: ${hasWrite}`);
42- return String(hasWrite);
43- } catch (e) {
44- if (e.status === 404) {
45- core.info(`${author} is not a collaborator — hasWrite: false`);
46- return 'false';
30+ const writeLevels = ['write', 'maintain', 'admin'];
31+
32+ async function hasWrite(username) {
33+ try {
34+ const { data } = await github.rest.repos.getCollaboratorPermissionLevel({
35+ owner: context.repo.owner,
36+ repo: context.repo.repo,
37+ username,
38+ });
39+ const result = writeLevels.includes(data.permission);
40+ core.info(`${username} has permission '${data.permission}' — hasWrite: ${result}`);
41+ return result;
42+ } catch (e) {
43+ if (e.status === 404) {
44+ core.info(`${username} is not a collaborator — hasWrite: false`);
45+ return false;
46+ }
47+ throw e;
4748 }
48- throw e;
4949 }
5050
51+ const author = context.payload.pull_request.user.login;
52+ const actor = context.actor;
53+
54+ if (await hasWrite(author)) {
55+ return 'true';
56+ }
57+
58+ // On re-runs, github.actor is the person who triggered the re-run
59+ if (actor !== author && await hasWrite(actor)) {
60+ core.info(`PR author ${author} lacks write access, but actor ${actor} (re-run) has it — allowing`);
61+ return 'true';
62+ }
63+
64+ return 'false';
65+
5166 - name : " Find existing comment"
5267 uses : " peter-evans/find-comment@3eae4d37986fb5a8592848f6a574fdf654e61f9e" # v3
5368 id : " find-comment"
5671 comment-author : " github-actions[bot]"
5772 body-includes : " <!-- vercel-preview-deployment -->"
5873
74+ - name : " Checkout code"
75+ if : " steps.permission.outputs.result == 'true'"
76+ uses : " actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd" # v6
77+ with :
78+ ref : " ${{ github.event.pull_request.head.sha }}"
79+
5980 - name : " Post no-permission comment"
6081 if : " steps.permission.outputs.result == 'false'"
6182 uses : " peter-evans/create-or-update-comment@71345be0265236311c031f5c7866368bd1eff043" # v4
@@ -104,6 +125,7 @@ jobs:
104125 VERCEL_TOKEN : " ${{ secrets.VERCEL_TOKEN }}"
105126 VERCEL_ORG_ID : " ${{ secrets.VERCEL_ORG_ID }}"
106127 VERCEL_PROJECT_ID : " ${{ secrets.VERCEL_PROJECT_ID }}"
128+ HEAD_REF : " ${{ github.head_ref }}"
107129 run : |
108130 npm install --global vercel@latest
109131
@@ -112,7 +134,7 @@ jobs:
112134
113135 # Sanitize branch name for DNS: lowercase, non-alphanumeric to hyphens, collapse runs
114136 # Truncate to 46 chars so the full alias (docs-git-<branch>-authzed) stays within the 63-char DNS label limit
115- BRANCH=$(echo "${{ github.head_ref }} " \
137+ BRANCH=$(echo "$HEAD_REF " \
116138 | tr '[:upper:]' '[:lower:]' \
117139 | sed 's/[^a-z0-9]/-/g' \
118140 | sed 's/-\+/-/g' \
0 commit comments