Skip to content

Commit e9140e7

Browse files
ondrejmirtesclaude
andcommitted
Post issue-bot PR comment from a workflow_run workflow
The "Issue bot" workflow runs on the pull_request event, whose GITHUB_TOKEN is read-only and secret-less for PRs from forks — so its comment-posting step got a 403 "Resource not accessible by integration" on fork PRs. Move all PR-comment posting into a new issue-bot-pr-comment.yml triggered by workflow_run, which runs in the base-repo context with a writable token and secrets, so it can comment on fork PRs too. It only consumes the pr-comment artifact (body + exit-code marker) produced by the analysis run; it never checks out or runs PR code, and it resolves the PR number from the trusted head SHA (workflow_run.pull_requests is empty for forks). Posting uses PHPSTAN_BOT_TOKEN so the comment comes from the bot account. issue-bot.yml no longer needs pull-requests: write; the pr-comment-init and pr-comment-finalize jobs are removed and the exit code now travels in the artifact as a marker file. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent a7d4f61 commit e9140e7

2 files changed

Lines changed: 105 additions & 83 deletions

File tree

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
# https://help.github.com/en/categories/automating-your-workflow-with-github-actions
2+
3+
# Posts the issue-bot result as a PR comment.
4+
#
5+
# The "Issue bot" workflow runs on the `pull_request` event, whose GITHUB_TOKEN is
6+
# read-only (and has no secrets) for PRs from forks — so it cannot comment there.
7+
# This workflow runs on `workflow_run`, which executes in the base-repo context with
8+
# access to secrets and a writable token, so it can comment on fork PRs too. It only
9+
# consumes the artifact produced by the analysis run; it never checks out or runs PR code.
10+
#
11+
# Posting uses PHPSTAN_BOT_TOKEN so the comment comes from the bot account.
12+
13+
name: "Issue bot PR comment"
14+
15+
on:
16+
workflow_run: # zizmor: ignore[dangerous-triggers]
17+
workflows: ["Issue bot"]
18+
types:
19+
- completed
20+
21+
permissions: {}
22+
23+
concurrency:
24+
group: issue-bot-pr-comment-${{ github.event.workflow_run.head_repository.full_name }}-${{ github.event.workflow_run.head_branch }}
25+
cancel-in-progress: false
26+
27+
jobs:
28+
comment:
29+
name: "Post/update PR comment"
30+
if: github.event.workflow_run.event == 'pull_request' && github.event.workflow_run.conclusion == 'success'
31+
runs-on: "ubuntu-latest"
32+
permissions:
33+
actions: read # download the pr-comment artifact from the triggering run
34+
35+
steps:
36+
- name: Harden the runner (Audit all outbound calls)
37+
uses: step-security/harden-runner@5ef0c079ce82195b2a36a210272d6b661572d83e # v2.14.2
38+
with:
39+
egress-policy: audit
40+
41+
- name: "Download PR comment artifact"
42+
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
43+
with:
44+
name: pr-comment
45+
run-id: ${{ github.event.workflow_run.id }}
46+
github-token: ${{ secrets.GITHUB_TOKEN }}
47+
48+
- name: "Resolve PR number"
49+
id: pr
50+
uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7.1.0
51+
with:
52+
github-token: ${{ secrets.PHPSTAN_BOT_TOKEN }}
53+
script: |
54+
// Resolve the PR from the triggering run's head SHA. workflow_run.pull_requests
55+
// is empty for fork PRs, and the SHA is GitHub-provided (not artifact-controlled),
56+
// so this is the trustworthy way to find which PR to comment on.
57+
const { data: prs } = await github.rest.repos.listPullRequestsAssociatedWithCommit({
58+
owner: context.repo.owner,
59+
repo: context.repo.repo,
60+
commit_sha: context.payload.workflow_run.head_sha,
61+
});
62+
const pr = prs.find(p => p.state === 'open') ?? prs[0];
63+
if (pr === undefined) {
64+
core.info('No pull request associated with this commit; nothing to comment on.');
65+
return;
66+
}
67+
core.setOutput('number', pr.number);
68+
69+
- name: "Find existing comment"
70+
if: steps.pr.outputs.number != ''
71+
id: find-comment
72+
uses: peter-evans/find-comment@3eae4d37986fb5a8592848f6a574fdf654e61f9e # v3.1.0
73+
with:
74+
token: ${{ secrets.PHPSTAN_BOT_TOKEN }}
75+
issue-number: ${{ steps.pr.outputs.number }}
76+
body-includes: "<!-- phpstan-issue-bot -->"
77+
78+
# Changes detected: create the comment if missing, otherwise update it.
79+
- name: "Post/update comment (changes)"
80+
if: steps.pr.outputs.number != '' && hashFiles('pr-comment-exit-2') != ''
81+
uses: peter-evans/create-or-update-comment@71345be0265236311c031f5c7866368bd1eff043 # v4.0.0
82+
with:
83+
token: ${{ secrets.PHPSTAN_BOT_TOKEN }}
84+
comment-id: ${{ steps.find-comment.outputs.comment-id }}
85+
issue-number: ${{ steps.pr.outputs.number }}
86+
edit-mode: replace
87+
body-path: pr-comment.md
88+
89+
# No changes: only update an already-existing comment, never create a new one.
90+
- name: "Update comment (no changes, only if exists)"
91+
if: steps.pr.outputs.number != '' && hashFiles('pr-comment-exit-0') != '' && steps.find-comment.outputs.comment-id != ''
92+
uses: peter-evans/create-or-update-comment@71345be0265236311c031f5c7866368bd1eff043 # v4.0.0
93+
with:
94+
token: ${{ secrets.PHPSTAN_BOT_TOKEN }}
95+
comment-id: ${{ steps.find-comment.outputs.comment-id }}
96+
edit-mode: replace
97+
body-path: pr-comment.md

.github/workflows/issue-bot.yml

Lines changed: 8 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -25,39 +25,6 @@ permissions:
2525
contents: read
2626

2727
jobs:
28-
pr-comment-init:
29-
name: "Init PR comment (if exists)"
30-
if: github.event_name == 'pull_request'
31-
runs-on: "ubuntu-latest"
32-
permissions:
33-
pull-requests: write
34-
35-
steps:
36-
- name: Harden the runner (Audit all outbound calls)
37-
uses: step-security/harden-runner@5ef0c079ce82195b2a36a210272d6b661572d83e # v2.14.2
38-
with:
39-
egress-policy: audit
40-
41-
- name: "Find existing PR comment"
42-
id: find-comment
43-
uses: peter-evans/find-comment@3eae4d37986fb5a8592848f6a574fdf654e61f9e # v3.1.0
44-
with:
45-
issue-number: ${{ github.event.pull_request.number }}
46-
body-includes: "<!-- phpstan-issue-bot -->"
47-
48-
- name: "Mark comment as running"
49-
if: steps.find-comment.outputs.comment-id != ''
50-
uses: peter-evans/create-or-update-comment@71345be0265236311c031f5c7866368bd1eff043 # v4.0.0
51-
with:
52-
comment-id: ${{ steps.find-comment.outputs.comment-id }}
53-
edit-mode: replace
54-
body: |
55-
<!-- phpstan-issue-bot -->
56-
57-
:hourglass_flowing_sand: A new issue bot run is in progress: [view job](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}).
58-
59-
This comment will be updated with the latest results when the run completes.
60-
6128
download:
6229
name: "Download data"
6330

@@ -197,9 +164,6 @@ jobs:
197164

198165
runs-on: "ubuntu-latest"
199166

200-
outputs:
201-
pr-evaluate-exit-code: ${{ steps.evaluate-pr.outputs.exit_code }}
202-
203167
steps:
204168
- name: Harden the runner (Audit all outbound calls)
205169
uses: step-security/harden-runner@5ef0c079ce82195b2a36a210272d6b661572d83e # v2.14.2
@@ -240,7 +204,6 @@ jobs:
240204
run: "ls -lA issue-bot/tmp"
241205

242206
- name: "Evaluate results - pull request"
243-
id: evaluate-pr
244207
working-directory: "issue-bot"
245208
if: github.event_name == 'pull_request'
246209
env:
@@ -265,13 +228,16 @@ jobs:
265228
fi
266229
} > tmp/pr-comment.md
267230
268-
echo "exit_code=$exit_code" >> "$GITHUB_OUTPUT"
231+
# Exit-code marker carried to the issue-bot-pr-comment workflow inside the pr-comment artifact.
232+
case "$exit_code" in
233+
0|2) touch "tmp/pr-comment-exit-$exit_code" ;;
234+
esac
269235
270236
if [[ "$exit_code" == "2" ]]; then
271237
echo "::notice file=.github/workflows/issue-bot.yml,line=3 ::Issue bot detected open issues which are affected by this pull request - see $job_url"
272238
fi
273239
274-
# Always exit 0 for the PR pathway so the pr-comment-finalize job still receives outputs/artifacts.
240+
# Always exit 0 for the PR pathway; the comment itself is posted by the issue-bot-pr-comment workflow.
275241
exit 0
276242
277243
- name: "Upload step summary"
@@ -286,7 +252,9 @@ jobs:
286252
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
287253
with:
288254
name: pr-comment
289-
path: issue-bot/tmp/pr-comment.md
255+
path: |
256+
issue-bot/tmp/pr-comment.md
257+
issue-bot/tmp/pr-comment-exit-*
290258
291259
- name: "Evaluate results - push"
292260
working-directory: "issue-bot"
@@ -306,46 +274,3 @@ jobs:
306274
fi
307275
308276
exit $exit_code
309-
310-
pr-comment-finalize:
311-
name: "Post/update PR comment"
312-
needs: evaluate
313-
if: github.event_name == 'pull_request' && needs.evaluate.result == 'success'
314-
runs-on: "ubuntu-latest"
315-
permissions:
316-
pull-requests: write
317-
318-
steps:
319-
- name: Harden the runner (Audit all outbound calls)
320-
uses: step-security/harden-runner@5ef0c079ce82195b2a36a210272d6b661572d83e # v2.14.2
321-
with:
322-
egress-policy: audit
323-
324-
- name: "Download PR comment body"
325-
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
326-
with:
327-
name: pr-comment
328-
329-
- name: "Find PR comment"
330-
id: find-comment
331-
uses: peter-evans/find-comment@3eae4d37986fb5a8592848f6a574fdf654e61f9e # v3.1.0
332-
with:
333-
issue-number: ${{ github.event.pull_request.number }}
334-
body-includes: "<!-- phpstan-issue-bot -->"
335-
336-
- name: "Post/update PR comment (changes)"
337-
if: needs.evaluate.outputs.pr-evaluate-exit-code == '2'
338-
uses: peter-evans/create-or-update-comment@71345be0265236311c031f5c7866368bd1eff043 # v4.0.0
339-
with:
340-
comment-id: ${{ steps.find-comment.outputs.comment-id }}
341-
issue-number: ${{ github.event.pull_request.number }}
342-
edit-mode: replace
343-
body-path: pr-comment.md
344-
345-
- name: "Update PR comment (no changes, only if exists)"
346-
if: needs.evaluate.outputs.pr-evaluate-exit-code == '0' && steps.find-comment.outputs.comment-id != ''
347-
uses: peter-evans/create-or-update-comment@71345be0265236311c031f5c7866368bd1eff043 # v4.0.0
348-
with:
349-
comment-id: ${{ steps.find-comment.outputs.comment-id }}
350-
edit-mode: replace
351-
body-path: pr-comment.md

0 commit comments

Comments
 (0)