diff --git a/.github/workflows/api-compat.yml b/.github/workflows/api-compat.yml index 6fcbdfe8d1..5c270e0efa 100644 --- a/.github/workflows/api-compat.yml +++ b/.github/workflows/api-compat.yml @@ -49,8 +49,15 @@ jobs: # bound that protects against a hung go install or git fetch. timeout-minutes: 10 steps: + # Left persisting credentials deliberately. This job cannot push — it has + # contents: read — so the exposure is limited, and it runs + # `git fetch origin refs/tags/...` below. That fetch succeeds + # unauthenticated only because this repository is public; dropping the + # credential would make it depend on that staying true. This job is also + # the repository's only required status check, so breaking it blocks + # every pull request. Not worth it to clear one low-severity finding. - name: Checkout PR HEAD - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6 + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6 # zizmor: ignore[artipacked] - name: Set up Go uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6 diff --git a/.github/workflows/claude.yml b/.github/workflows/claude.yml index 2a89ca1885..d339838bdc 100644 --- a/.github/workflows/claude.yml +++ b/.github/workflows/claude.yml @@ -54,8 +54,13 @@ jobs: id-token: write actions: read # Required for Claude to read CI results on PRs steps: + # Unlike every other checkout in this repository, this one keeps its + # credentials on purpose. The job holds contents: write precisely so + # Claude can push commits to a pull request, and that push uses the + # credential actions/checkout leaves in .git/config. Setting + # persist-credentials: false here would break the action. - name: Checkout repository - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6 + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6 # zizmor: ignore[artipacked] with: fetch-depth: 1 diff --git a/.github/workflows/pr-size-label-apply.yml b/.github/workflows/pr-size-label-apply.yml index 5c94faa490..71f8f531db 100644 --- a/.github/workflows/pr-size-label-apply.yml +++ b/.github/workflows/pr-size-label-apply.yml @@ -1,7 +1,17 @@ name: PR Size Labeler - Apply on: - workflow_run: + # The `workflow_run` trigger is what makes this workflow privileged, and it + # cannot be removed — applying a label needs write access that the calculate + # workflow, running on `pull_request`, deliberately does not have. + # + # What made that dangerous was trusting the artifact: the pull request number + # and the label were both read out of it, and the artifact is produced by a + # workflow the pull request author controls, forks included. Neither is now. + # The number is derived from this workflow's own event and the label must + # match a fixed list of five values, so nothing crossing the boundary can + # decide which pull request is acted on or what is applied to it. + workflow_run: # zizmor: ignore[dangerous-triggers] workflows: ["PR Size Labeler - Calculate"] types: [completed] diff --git a/.github/workflows/release-notes.yml b/.github/workflows/release-notes.yml index 185c03fc57..82ec459ddb 100644 --- a/.github/workflows/release-notes.yml +++ b/.github/workflows/release-notes.yml @@ -24,7 +24,14 @@ name: Generate Release Notes on: - workflow_run: + # `workflow_run` is required here, not incidental: claude-code-action rejects + # the `release` event outright (see the note above), and this needs to run + # after the tag workflow completes. + # + # The risk this audit flags is a privileged workflow checking out an + # event-supplied ref. This one deliberately does not — it checks out the + # default branch, for the reasons set out on the checkout step below. + workflow_run: # zizmor: ignore[dangerous-triggers] workflows: ["Create Release Tag"] types: [completed] workflow_dispatch: