1313# limitations under the License.
1414
1515# This workflow posts coverage comments on PRs after the main workflow completes.
16- # Using workflow_run gives us write permissions even for fork PRs .
16+ # Uses workflow_run with guarded checkout to avoid executing untrusted code .
1717# See: https://securitylab.github.com/resources/github-actions-preventing-pwn-requests/
1818
1919name : Post PR Comment
2626
2727permissions :
2828 actions : read # Required to download artifacts from other workflow runs
29- contents : read # Required to checkout repository for go.mod and changed-files
3029 pull-requests : write
3130
3231jobs :
3332 post-coverage-comment :
3433 name : Post Coverage Comment
3534 runs-on : ubuntu-latest
3635 # Run for PRs regardless of conclusion - coverage might exist even if other steps failed
37- if : github.event.workflow_run.event == 'pull_request'
36+ if : github.event.workflow_run.event == 'pull_request' && github.event.workflow_run.head_repository.fork == false
37+ permissions :
38+ actions : read
39+ pull-requests : write
3840 steps :
3941 - name : Checkout for go.mod version
4042 uses : actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
5860 with :
5961 name : coverage-pr
6062 path : /tmp/pr-coverage
61- github-token : ${{ secrets.GITHUB_TOKEN }}
63+ github-token : ${{ github.token }}
6264 run-id : ${{ github.event.workflow_run.id }}
6365
6466 - name : Download Coverage Metadata
@@ -68,14 +70,14 @@ jobs:
6870 with :
6971 name : coverage-comment-data
7072 path : /tmp/coverage-comment-data
71- github-token : ${{ secrets.GITHUB_TOKEN }}
73+ github-token : ${{ github.token }}
7274 run-id : ${{ github.event.workflow_run.id }}
7375
7476 - name : Download Baseline Coverage
7577 id : download-baseline
7678 if : steps.download-pr.outcome == 'success'
7779 env :
78- GH_TOKEN : ${{ secrets.GITHUB_TOKEN }}
80+ GH_TOKEN : ${{ github.token }}
7981 run : |
8082 set -e
8183 mkdir -p /tmp/baseline-coverage
@@ -111,25 +113,41 @@ jobs:
111113 echo "mode: set" > /tmp/baseline-coverage/coverage.out
112114 fi
113115
114- - name : Checkout for changed-files action
115- if : steps.download-pr.outcome == 'success'
116- uses : actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
117- with :
118- ref : ${{ github.event.workflow_run.head_sha }}
119- fetch-depth : 0
120-
121116 - name : Get Changed Files
122117 id : changed-files
123118 if : steps.download-pr.outcome == 'success'
124- uses : tj-actions/changed-files@aa08304bd477b800d468db44fe10f6c61f7f7b11 # v46.0.5
125- with :
126- write_output_files : true
127- json : true
128- files : " **.go"
129- files_ignore : |
130- vendor/**
131- **_test.go
132- output_dir : .github/outputs
119+ shell : bash
120+ env :
121+ GH_TOKEN : ${{ github.token }}
122+ run : |
123+ set -euo pipefail
124+ mkdir -p .github/outputs
125+
126+ PR_URL="${{ github.event.workflow_run.pull_requests[0].url }}"
127+ if [[ -z "$PR_URL" || "$PR_URL" == "null" ]]; then
128+ echo "No PR URL found in workflow_run payload. Skipping changed files." >&2
129+ echo "any_changed=false" >> "$GITHUB_OUTPUT"
130+ exit 0
131+ fi
132+
133+ FILES_JSON=$(curl -sS \
134+ -H "Authorization: Bearer $GH_TOKEN" \
135+ -H "Accept: application/vnd.github+json" \
136+ "$PR_URL/files?per_page=300")
137+
138+ echo "$FILES_JSON" | jq -c '
139+ [.[] |
140+ select(.filename | endswith(".go")) |
141+ select(.filename | test("^vendor/") | not) |
142+ select(.filename | test("_test\\.go$") | not) |
143+ .filename
144+ ]' > .github/outputs/all_modified_files.json
145+
146+ if [[ "$(cat .github/outputs/all_modified_files.json)" == "[]" ]]; then
147+ echo "any_changed=false" >> "$GITHUB_OUTPUT"
148+ else
149+ echo "any_changed=true" >> "$GITHUB_OUTPUT"
150+ fi
133151
134152 - name : Generate Coverage Delta Report
135153 id : delta
0 commit comments