From 2a67cf3182cf468e5427b9e8fb86942d3895e92a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Enrique=20Lo=CC=81pez=20Man=CC=83as?= Date: Wed, 26 Aug 2026 23:24:39 +0700 Subject: [PATCH 1/2] fix(ci): post coverage comments for fork PRs via workflow_run report.yml previously tried to comment on the PR with a secret token in the same job that pull_request triggers for fork PRs, which GitHub always runs without secrets. That made the coverage step fail outright on every external contribution even when the build and tests passed. Split the work: report.yml now only builds and uploads the jacoco XML reports plus PR metadata as an artifact, no secrets needed. A new report-comment.yml, triggered by workflow_run, downloads that artifact and posts the comment. workflow_run jobs always run in the base repo's context with full secrets, regardless of what triggered the run they react to, so this works the same way for fork and internal PRs. --- .github/workflows/report-comment.yml | 66 ++++++++++++++++++++++++++++ .github/workflows/report.yml | 40 ++++++++++------- 2 files changed, 89 insertions(+), 17 deletions(-) create mode 100644 .github/workflows/report-comment.yml diff --git a/.github/workflows/report-comment.yml b/.github/workflows/report-comment.yml new file mode 100644 index 000000000..d4112e1c6 --- /dev/null +++ b/.github/workflows/report-comment.yml @@ -0,0 +1,66 @@ +# Copyright 2026 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Posts the JaCoCo coverage report as a PR comment, using the coverage XML built by +# "Report tests results" (report.yml). Split into its own workflow triggered by workflow_run +# so it always runs in the base repo's context with access to secrets/write permissions, even +# when report.yml itself was triggered by a pull_request from a fork (which never gets secrets). +name: Report coverage comment + +on: + workflow_run: + workflows: ['Report tests results'] + types: [completed] + +jobs: + comment: + runs-on: ubuntu-latest + if: github.event.workflow_run.event == 'pull_request' && github.event.workflow_run.conclusion == 'success' + permissions: + pull-requests: write + actions: read + steps: + - name: Download coverage artifacts + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 + with: + name: jacoco-reports + run-id: ${{ github.event.workflow_run.id }} + github-token: ${{ secrets.GITHUB_TOKEN }} + + - name: Read PR info + id: pr + run: | + echo "number=$(cat pr-info/pr-number.txt)" >> "$GITHUB_OUTPUT" + echo "head_sha=$(cat pr-info/head-sha.txt)" >> "$GITHUB_OUTPUT" + echo "base_sha=$(cat pr-info/base-sha.txt)" >> "$GITHUB_OUTPUT" + + - name: Jacoco Report to PR + id: jacoco + uses: madrapps/jacoco-report@e51ce1f46f7f8b5331593f935e59cbaf44b84920 # v1.8.0 + with: + paths: | + ${{ github.workspace }}/library/build/jacoco/jacoco.xml, + ${{ github.workspace }}/clustering/build/jacoco/jacoco.xml, + ${{ github.workspace }}/data/build/jacoco/jacoco.xml, + ${{ github.workspace }}/heatmaps/build/jacoco/jacoco.xml, + ${{ github.workspace }}/ui/build/jacoco/jacoco.xml + token: ${{ secrets.SYNCED_GITHUB_TOKEN_REPO }} + pr-number: ${{ steps.pr.outputs.number }} + head-sha: ${{ steps.pr.outputs.head_sha }} + base-sha: ${{ steps.pr.outputs.base_sha }} + min-coverage-overall: 26 + min-coverage-changed-files: 60 + title: Code Coverage + debug-mode: false + update-comment: true diff --git a/.github/workflows/report.yml b/.github/workflows/report.yml index c6cb60bfd..c934160e9 100644 --- a/.github/workflows/report.yml +++ b/.github/workflows/report.yml @@ -26,8 +26,6 @@ on: jobs: test: runs-on: ubuntu-latest - permissions: - pull-requests: write steps: # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it - name: Checkout Repo @@ -48,19 +46,27 @@ jobs: - name: Build modules run: ./gradlew build jacocoTestDebugUnitTestReport --stacktrace - - name: Jacoco Report to PR - id: jacoco - uses: madrapps/jacoco-report@e51ce1f46f7f8b5331593f935e59cbaf44b84920 # v1.8.0 + # Coverage reports are handed off to report-comment.yml (triggered via workflow_run) so the + # PR comment step runs with the base repo's permissions/secrets, which aren't available here + # when this workflow is triggered by a pull_request from a fork. + - name: Save PR info + if: github.event_name == 'pull_request' + run: | + mkdir -p pr-info + echo "${{ github.event.pull_request.number }}" > pr-info/pr-number.txt + echo "${{ github.event.pull_request.head.sha }}" > pr-info/head-sha.txt + echo "${{ github.event.pull_request.base.sha }}" > pr-info/base-sha.txt + + - name: Upload coverage artifacts + if: github.event_name == 'pull_request' + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: - paths: | - ${{ github.workspace }}/library/build/jacoco/jacoco.xml, - ${{ github.workspace }}/clustering/build/jacoco/jacoco.xml, - ${{ github.workspace }}/data/build/jacoco/jacoco.xml, - ${{ github.workspace }}/heatmaps/build/jacoco/jacoco.xml, - ${{ github.workspace }}/ui/build/jacoco/jacoco.xml - token: ${{ secrets.SYNCED_GITHUB_TOKEN_REPO }} - min-coverage-overall: 26 - min-coverage-changed-files: 60 - title: Code Coverage - debug-mode: false - update-comment: true + name: jacoco-reports + retention-days: 1 + path: | + pr-info/ + library/build/jacoco/jacoco.xml + clustering/build/jacoco/jacoco.xml + data/build/jacoco/jacoco.xml + heatmaps/build/jacoco/jacoco.xml + ui/build/jacoco/jacoco.xml From 3da3452a9df4b121fed181cb96b8b2796313ec1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Enrique=20Lo=CC=81pez=20Man=CC=83as?= Date: Wed, 26 Aug 2026 23:54:21 +0700 Subject: [PATCH 2/2] fix(ci): stop failing external PRs on missing coverage token The earlier workflow_run split to post coverage comments for fork PRs tripped the repo's mandatory zizmor security scan, which blocks any use of the workflow_run trigger regardless of how it is used. Revert to a single job. Fork PRs still cannot get a coverage comment, since secrets.SYNCED_GITHUB_TOKEN_REPO is never available to a pull_request run triggered by a fork, but continue-on-error on that step stops it from failing the whole check. The build and test steps above it remain the real pass/fail signal. --- .github/workflows/report-comment.yml | 66 ---------------------------- .github/workflows/report.yml | 45 ++++++++++--------- 2 files changed, 22 insertions(+), 89 deletions(-) delete mode 100644 .github/workflows/report-comment.yml diff --git a/.github/workflows/report-comment.yml b/.github/workflows/report-comment.yml deleted file mode 100644 index d4112e1c6..000000000 --- a/.github/workflows/report-comment.yml +++ /dev/null @@ -1,66 +0,0 @@ -# Copyright 2026 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Posts the JaCoCo coverage report as a PR comment, using the coverage XML built by -# "Report tests results" (report.yml). Split into its own workflow triggered by workflow_run -# so it always runs in the base repo's context with access to secrets/write permissions, even -# when report.yml itself was triggered by a pull_request from a fork (which never gets secrets). -name: Report coverage comment - -on: - workflow_run: - workflows: ['Report tests results'] - types: [completed] - -jobs: - comment: - runs-on: ubuntu-latest - if: github.event.workflow_run.event == 'pull_request' && github.event.workflow_run.conclusion == 'success' - permissions: - pull-requests: write - actions: read - steps: - - name: Download coverage artifacts - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 - with: - name: jacoco-reports - run-id: ${{ github.event.workflow_run.id }} - github-token: ${{ secrets.GITHUB_TOKEN }} - - - name: Read PR info - id: pr - run: | - echo "number=$(cat pr-info/pr-number.txt)" >> "$GITHUB_OUTPUT" - echo "head_sha=$(cat pr-info/head-sha.txt)" >> "$GITHUB_OUTPUT" - echo "base_sha=$(cat pr-info/base-sha.txt)" >> "$GITHUB_OUTPUT" - - - name: Jacoco Report to PR - id: jacoco - uses: madrapps/jacoco-report@e51ce1f46f7f8b5331593f935e59cbaf44b84920 # v1.8.0 - with: - paths: | - ${{ github.workspace }}/library/build/jacoco/jacoco.xml, - ${{ github.workspace }}/clustering/build/jacoco/jacoco.xml, - ${{ github.workspace }}/data/build/jacoco/jacoco.xml, - ${{ github.workspace }}/heatmaps/build/jacoco/jacoco.xml, - ${{ github.workspace }}/ui/build/jacoco/jacoco.xml - token: ${{ secrets.SYNCED_GITHUB_TOKEN_REPO }} - pr-number: ${{ steps.pr.outputs.number }} - head-sha: ${{ steps.pr.outputs.head_sha }} - base-sha: ${{ steps.pr.outputs.base_sha }} - min-coverage-overall: 26 - min-coverage-changed-files: 60 - title: Code Coverage - debug-mode: false - update-comment: true diff --git a/.github/workflows/report.yml b/.github/workflows/report.yml index c934160e9..ba021a91b 100644 --- a/.github/workflows/report.yml +++ b/.github/workflows/report.yml @@ -26,6 +26,8 @@ on: jobs: test: runs-on: ubuntu-latest + permissions: + pull-requests: write steps: # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it - name: Checkout Repo @@ -46,27 +48,24 @@ jobs: - name: Build modules run: ./gradlew build jacocoTestDebugUnitTestReport --stacktrace - # Coverage reports are handed off to report-comment.yml (triggered via workflow_run) so the - # PR comment step runs with the base repo's permissions/secrets, which aren't available here - # when this workflow is triggered by a pull_request from a fork. - - name: Save PR info - if: github.event_name == 'pull_request' - run: | - mkdir -p pr-info - echo "${{ github.event.pull_request.number }}" > pr-info/pr-number.txt - echo "${{ github.event.pull_request.head.sha }}" > pr-info/head-sha.txt - echo "${{ github.event.pull_request.base.sha }}" > pr-info/base-sha.txt - - - name: Upload coverage artifacts - if: github.event_name == 'pull_request' - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + # PRs from forks don't get repo secrets on the pull_request trigger, so + # secrets.SYNCED_GITHUB_TOKEN_REPO is empty and this step always fails for external + # contributions. continue-on-error keeps that from failing the whole job/check: the + # build and tests above are still the real signal, this is just a best-effort comment. + - name: Jacoco Report to PR + id: jacoco + continue-on-error: true + uses: madrapps/jacoco-report@e51ce1f46f7f8b5331593f935e59cbaf44b84920 # v1.8.0 with: - name: jacoco-reports - retention-days: 1 - path: | - pr-info/ - library/build/jacoco/jacoco.xml - clustering/build/jacoco/jacoco.xml - data/build/jacoco/jacoco.xml - heatmaps/build/jacoco/jacoco.xml - ui/build/jacoco/jacoco.xml + paths: | + ${{ github.workspace }}/library/build/jacoco/jacoco.xml, + ${{ github.workspace }}/clustering/build/jacoco/jacoco.xml, + ${{ github.workspace }}/data/build/jacoco/jacoco.xml, + ${{ github.workspace }}/heatmaps/build/jacoco/jacoco.xml, + ${{ github.workspace }}/ui/build/jacoco/jacoco.xml + token: ${{ secrets.SYNCED_GITHUB_TOKEN_REPO }} + min-coverage-overall: 26 + min-coverage-changed-files: 60 + title: Code Coverage + debug-mode: false + update-comment: true