diff --git a/.github/workflows/sdk-regression.yml b/.github/workflows/sdk-regression.yml index 35f60b754..ad78d7ce9 100644 --- a/.github/workflows/sdk-regression.yml +++ b/.github/workflows/sdk-regression.yml @@ -21,13 +21,16 @@ jobs: regression: name: regression runs-on: ubuntu-latest - # Least-privilege: read code/PR data and write commit statuses only. Note an - # author-permission guard below (check-access) already restricts triggering - # to write/admin collaborators (CWE-284 / PER-8610). + # Least-privilege GITHUB_TOKEN: read code/PR data, write commit statuses, and + # read this run's Actions job metadata (for the job log URL) only. Triggering + # is further gated by the author-permission check (check-access) below, which + # restricts it to write/admin collaborators. The powerful cross-repo dispatch + # PAT is NOT granted here; it is injected only into the single trigger step. permissions: contents: read pull-requests: read statuses: write + actions: read # Run when either: # - a maintainer comments RUN_REGRESSION on a PR, or # - the workflow is dispatched manually (CLI branch + optional per-SDK refs). @@ -140,17 +143,22 @@ jobs: # failure must never gate the regression itself. continue-on-error: true with: - github_token: ${{ secrets.WORKFLOW_DISPATCH_ACTIONS_TOKEN }} + # Third-party action: only reads this run's job metadata on percy/cli, + # so the built-in GITHUB_TOKEN (actions: read) is sufficient. The + # cross-repo dispatch PAT is deliberately not exposed to it. + github_token: ${{ github.token }} job_name: "regression (${{ matrix.repo }})" # The fan-out matrix is >30 jobs (currently 35); the action defaults to # per_page=30, so jobs on page 2 resolve to null and exit 1. Cover the # whole matrix (GitHub jobs API max page size is 100). per_page: 100 - name: Output Current Job Log URL - run: echo ${{ steps.jobs.outputs.html_url }} + run: echo ${{ steps.job-url.outputs.html_url }} - uses: actions/github-script@f891eff65186019cbb3f7190c4590bc0a1b76fbc # v4.1.0 with: - github-token: ${{ secrets.WORKFLOW_DISPATCH_ACTIONS_TOKEN }} + # Writes a commit status on percy/cli itself (job-level statuses: write), + # so the built-in GITHUB_TOKEN is used instead of the cross-repo PAT. + github-token: ${{ github.token }} script: | const { owner, repo } = context.repo; const sha = '${{ steps.pr.outputs.head_sha }}' @@ -201,6 +209,9 @@ jobs: with: owner: percy repo: ${{ steps.split.outputs._0 }} + # Only step that strictly needs the cross-repo dispatch PAT: it triggers + # test.yml in a *different* percy repo, which the built-in GITHUB_TOKEN + # cannot do. Injection is scoped to this step alone. github_token: ${{ secrets.WORKFLOW_DISPATCH_ACTIONS_TOKEN }} # Most SDKs expose `test.yml`; a few use a differently-named workflow # that carries the @percy/cli inject step: @@ -214,7 +225,9 @@ jobs: - name: Update Status uses: actions/github-script@f891eff65186019cbb3f7190c4590bc0a1b76fbc # v4.1.0 with: - github-token: ${{ secrets.WORKFLOW_DISPATCH_ACTIONS_TOKEN }} + # Writes a commit status on percy/cli itself (job-level statuses: write), + # so the built-in GITHUB_TOKEN is used instead of the cross-repo PAT. + github-token: ${{ github.token }} script: | const { owner, repo } = context.repo; const sha = '${{ steps.pr.outputs.head_sha }}'