55 types : [created]
66
77jobs :
8+ authorize_commenter :
9+ runs-on : ubuntu-latest
10+ permissions :
11+ contents : read
12+ pull-requests : read
13+ outputs :
14+ allowed : ${{ steps.check.outputs.allowed }}
15+ steps :
16+ - name : Check commenter write access
17+ id : check
18+ uses : actions/github-script@v7
19+ with :
20+ github-token : ${{ secrets.GITHUB_TOKEN }}
21+ script : |
22+ const actor = context.payload.comment.user.login;
23+ const repo_owner = context.payload.repository.owner.login;
24+ const repo_name = context.payload.repository.name;
25+ try {
26+ const { data: permission } = await github.rest.repos.getCollaboratorPermissionLevel({
27+ owner: repo_owner,
28+ repo: repo_name,
29+ username: actor
30+ });
31+ const allowed = ['admin', 'write'].includes(permission.permission);
32+ core.setOutput('allowed', allowed ? 'true' : 'false');
33+ } catch (e) {
34+ core.setOutput('allowed', 'false');
35+ }
36+
837 parsing_job :
38+ needs : authorize_commenter
939 runs-on : ubuntu-latest
1040 permissions :
1141 issues : write # Allow adding a reaction via the comment-pipeline
1242 pull-requests : write
1343 outputs :
1444 command : ${{ steps.parse.outputs.command }}
1545 arg : ${{ steps.parse.outputs.arguments }}
16- if : github.event.issue.pull_request
46+ if : needs.authorize_commenter.outputs.allowed == 'true' && github.event.issue.pull_request
1747 steps :
1848 - name : Parse comment
1949 id : parse
@@ -27,13 +57,13 @@ jobs:
2757 /run test-baseline
2858 github-token : ${{ secrets.GITHUB_TOKEN }}
2959
30- # This second job by definiton runs user-supplied code - you must NOT elevate its permissions to `write`
31- # Malicious code could change nuget source URL, build targets or even compiler itself to pass a GH token
32- # And use it to create branches, spam issues etc. Any write-actions happen in the second job, which does not allow
33- # user extension points (i.e. plain scripts, must NOT run scripts from within checked-out code)
60+ # This second job by definition runs user-supplied code - you must NOT elevate its permissions to `write`
3461 run-parsed-command :
3562 needs : parsing_job
3663 runs-on : ubuntu-latest
64+ permissions :
65+ contents : read
66+ pull-requests : read
3767 if : needs.parsing_job.outputs.command != ''
3868 steps :
3969
@@ -130,6 +160,19 @@ jobs:
130160 echo "run_step_outcome=$run_step_outcome" >> $GITHUB_OUTPUT
131161 echo "hasPatch=$hasPatch" >> $GITHUB_OUTPUT
132162
163+ - name : Validate patch paths
164+ if : ${{ steps.read-meta.outputs.run_step_outcome == 'success' && steps.read-meta.outputs.hasPatch == 'true' }}
165+ run : |
166+ # Forbid any .git* paths anywhere
167+ if grep -E '^(\+\+\+|---) ' repo.patch | grep -E '(^|/)\.git(/|$)|(^|/)\.git'; then
168+ echo "Patch touches .git paths; aborting"; exit 1
169+ fi
170+
171+ # Allow only top-level src/, tests/, vsintegration/ changes
172+ if grep -E '^(\+\+\+|---) ' repo.patch | grep -Ev '^(---|\+\+\+) (a|b)/(src|tests|vsintegration)/' | grep -E '^(---|\+\+\+) '; then
173+ echo "Patch touches files outside allowed directories (src/tests/vsintegration); aborting"; exit 1
174+ fi
175+
133176 - name : Apply and push patch
134177 if : ${{ steps.read-meta.outputs.run_step_outcome == 'success' && steps.read-meta.outputs.hasPatch == 'true' }}
135178 run : |
@@ -142,7 +185,6 @@ jobs:
142185 echo "Pushing to origin $branch"
143186 git push origin HEAD:"$branch"
144187
145-
146188 - name : Count stats
147189 id : stats
148190 if : ${{ steps.read-meta.outputs.run_step_outcome == 'success' && steps.read-meta.outputs.hasPatch == 'true' }}
@@ -189,8 +231,6 @@ jobs:
189231 if : always()
190232 env :
191233 GH_TOKEN : ${{ secrets.GITHUB_TOKEN }}
192- PR_NUMBER : ${{ env.PR_NUMBER }}
193234 run : |
194- # Use gh CLI to comment with multi-line markdown
195235 gh pr comment ${{ github.event.issue.number }} \
196236 --body-file pr_report.md
0 commit comments