11name : 🧪 Run Tests
22
33on :
4- pull_request :
4+ pull_request_target :
5+ types : [opened, synchronize, reopened]
56 push :
67 branches : [main]
8+ workflow_dispatch :
79
810concurrency :
911 group : ci-${{ github.ref }}
@@ -14,6 +16,12 @@ permissions:
1416 id-token : write # For OIDC with Codecov
1517 checks : write # For test reporting
1618
19+ env :
20+ # PR context helpers for conditional logic
21+ IS_PR : ${{ github.event_name == 'pull_request_target' }}
22+ IS_FORK : ${{ github.event_name == 'pull_request_target' && github.event.pull_request.head.repo.full_name != github.repository }}
23+ HAS_BOT_TOKEN : ${{ secrets.BOT_TOKEN != '' }}
24+
1725jobs :
1826 unit-tests :
1927 name : Unit Tests
2230 NODE_OPTIONS : " --max_old_space_size=8192"
2331
2432 steps :
33+ # Secure checkout for external PRs
2534 - uses : actions/checkout@v4
35+ with :
36+ # For PRs from forks, check out the PR head to prevent token exposure
37+ ref : ${{ github.event_name == 'pull_request_target' && github.event.pull_request.head.sha || github.ref }}
38+
2639 - uses : actions/setup-node@v4
2740 with :
2841 node-version : 22
3346 id : test
3447 run : |
3548 npx vitest run \
49+ --coverage \
3650 --reporter=github-actions \
3751 --reporter=verbose \
3852 --reporter=junit \
5165 path : test-result-unit.txt
5266
5367 - name : Upload coverage to Codecov
54- if : github.event_name == 'push' || github.event.pull_request.head.repo.full_name == github.repository
68+ if : github.event_name == 'push' || github.event_name == 'workflow_dispatch' || github. event.pull_request.head.repo.full_name == github.repository
5569 uses : codecov/codecov-action@v4
5670 with :
5771 token : ${{ secrets.CODECOV_TOKEN }}
@@ -64,20 +78,22 @@ jobs:
6478 - name : Unit Test Report
6579 id : unit-test-report
6680 uses : dorny/test-reporter@v1
67- if : always()
81+ if : always() && (env.IS_FORK != 'true' || env.HAS_BOT_TOKEN == 'true')
6882 with :
6983 name : Unit Tests
7084 path : test-results.xml
7185 reporter : java-junit
7286 fail-on-error : false
87+ token : ${{ env.IS_FORK == 'true' && secrets.BOT_TOKEN || secrets.GITHUB_TOKEN }}
88+ continue-on-error : true
7389
7490 - name : Save unit test report data
7591 if : always()
7692 run : |
77- echo "passed=${{ steps.unit-test-report.outputs.passed }}" > unit-report-data.txt
78- echo "failed=${{ steps.unit-test-report.outputs.failed }}" >> unit-report-data.txt
79- echo "skipped=${{ steps.unit-test-report.outputs.skipped }}" >> unit-report-data.txt
80- echo "time=${{ steps.unit-test-report.outputs.time }}" >> unit-report-data.txt
93+ echo "passed=${{ steps.unit-test-report.outputs.passed || '0' }}" > unit-report-data.txt
94+ echo "failed=${{ steps.unit-test-report.outputs.failed || '0' }}" >> unit-report-data.txt
95+ echo "skipped=${{ steps.unit-test-report.outputs.skipped || '0' }}" >> unit-report-data.txt
96+ echo "time=${{ steps.unit-test-report.outputs.time || '0' }}" >> unit-report-data.txt
8197
8298 - name : Upload unit test report data
8399 if : always()
@@ -104,7 +120,12 @@ jobs:
104120 NODE_OPTIONS : " --max_old_space_size=8192"
105121
106122 steps :
123+ # Secure checkout for external PRs
107124 - uses : actions/checkout@v4
125+ with :
126+ # For PRs from forks, check out the PR head to prevent naughty people finding my token
127+ ref : ${{ github.event_name == 'pull_request_target' && github.event.pull_request.head.sha || github.ref }}
128+
108129 - uses : actions/setup-node@v4
109130 with :
110131 node-version : 22
@@ -142,20 +163,22 @@ jobs:
142163 - name : API Test Report
143164 id : api-test-report
144165 uses : dorny/test-reporter@v1
145- if : always()
166+ if : always() && (env.IS_FORK != 'true' || env.HAS_BOT_TOKEN == 'true')
146167 with :
147168 name : API Contract Tests
148169 path : api-test-results.xml
149170 reporter : java-junit
150171 fail-on-error : false
172+ token : ${{ env.IS_FORK == 'true' && secrets.BOT_TOKEN || secrets.GITHUB_TOKEN }}
173+ continue-on-error : true
151174
152175 - name : Save API test report data
153176 if : always()
154177 run : |
155- echo "passed=${{ steps.api-test-report.outputs.passed }}" > api-report-data.txt
156- echo "failed=${{ steps.api-test-report.outputs.failed }}" >> api-report-data.txt
157- echo "skipped=${{ steps.api-test-report.outputs.skipped }}" >> api-report-data.txt
158- echo "time=${{ steps.api-test-report.outputs.time }}" >> api-report-data.txt
178+ echo "passed=${{ steps.api-test-report.outputs.passed || '0' }}" > api-report-data.txt
179+ echo "failed=${{ steps.api-test-report.outputs.failed || '0' }}" >> api-report-data.txt
180+ echo "skipped=${{ steps.api-test-report.outputs.skipped || '0' }}" >> api-report-data.txt
181+ echo "time=${{ steps.api-test-report.outputs.time || '0' }}" >> api-report-data.txt
159182
160183 - name : Upload API test report data
161184 if : always()
@@ -175,7 +198,12 @@ jobs:
175198 NODE_OPTIONS : " --max_old_space_size=8192"
176199
177200 steps :
201+ # Secure checkout for external PRs
178202 - uses : actions/checkout@v4
203+ with :
204+ # For PRs from forks, check out the PR head to prevent token exposure
205+ ref : ${{ github.event_name == 'pull_request_target' && github.event.pull_request.head.sha || github.ref }}
206+
179207 - uses : actions/setup-node@v4
180208 with :
181209 node-version : 22
@@ -219,20 +247,22 @@ jobs:
219247 - name : E2E Test Report
220248 id : e2e-test-report
221249 uses : dorny/test-reporter@v1
222- if : always()
250+ if : always() && (env.IS_FORK != 'true' || env.HAS_BOT_TOKEN == 'true')
223251 with :
224252 name : E2E Tests
225253 path : e2e-results.xml
226254 reporter : java-junit
227255 fail-on-error : false
256+ token : ${{ env.IS_FORK == 'true' && secrets.BOT_TOKEN || secrets.GITHUB_TOKEN }}
257+ continue-on-error : true
228258
229259 - name : Save e2e test report data
230260 if : always()
231261 run : |
232- echo "passed=${{ steps.e2e-test-report.outputs.passed }}" > e2e-report-data.txt
233- echo "failed=${{ steps.e2e-test-report.outputs.failed }}" >> e2e-report-data.txt
234- echo "skipped=${{ steps.e2e-test-report.outputs.skipped }}" >> e2e-report-data.txt
235- echo "time=${{ steps.e2e-test-report.outputs.time }}" >> e2e-report-data.txt
262+ echo "passed=${{ steps.e2e-test-report.outputs.passed || '0' }}" > e2e-report-data.txt
263+ echo "failed=${{ steps.e2e-test-report.outputs.failed || '0' }}" >> e2e-report-data.txt
264+ echo "skipped=${{ steps.e2e-test-report.outputs.skipped || '0' }}" >> e2e-report-data.txt
265+ echo "time=${{ steps.e2e-test-report.outputs.time || '0' }}" >> e2e-report-data.txt
236266
237267 - name : Upload e2e test report data
238268 if : always()
0 commit comments