diff --git a/.github/actions/setup-build-environment/action.yaml b/.github/actions/setup-build-environment/action.yaml index 12f5614df3..c28030d799 100644 --- a/.github/actions/setup-build-environment/action.yaml +++ b/.github/actions/setup-build-environment/action.yaml @@ -96,7 +96,25 @@ runs: with: vcpkgJsonGlob: vcpkg.json - - name: Cache CMake build output + # Cache strategy is split by event trust level to avoid the + # pull_request_target cache-poisoning class of bug (CodeQL rule + # `actions/cache-poisoning/poisonable-step`): + # + # - Trusted events (push to dev/main, workflow_dispatch, workflow_call + # from a release pipeline): use the combined `actions/cache` which + # restores at this step and auto-saves at job-end. Cache writes only + # happen from these trusted contexts. + # - Untrusted events (pull_request_target, pull_request): use the + # restore-only sub-action. PR builds still benefit from caches + # warmed by trusted runs but cannot themselves write back, so a + # malicious PR cannot poison a cache that a later default-branch + # run would consume. + # + # Both steps use the same key / restore-keys so cache hits cross the + # trust boundary in the allowed direction (trusted-saved → untrusted-restore). + + - name: Cache CMake build output (trusted, restore + save) + if: github.event_name != 'pull_request' && github.event_name != 'pull_request_target' uses: actions/cache@v5 with: path: ${{ inputs.build-dir }} @@ -105,6 +123,16 @@ runs: ${{ runner.os }}-cmake-msvc-${{ steps.msvc_version.outputs.version }}-${{ inputs.cache-key-suffix }}-${{ github.event.inputs.cache-key-suffix || 'default' }}- ${{ runner.os }}-cmake-msvc-${{ steps.msvc_version.outputs.version }}-${{ inputs.cache-key-suffix }}- + - name: Restore CMake build cache (untrusted PR, restore-only) + if: github.event_name == 'pull_request' || github.event_name == 'pull_request_target' + uses: actions/cache/restore@v5 + with: + path: ${{ inputs.build-dir }} + key: ${{ runner.os }}-cmake-msvc-${{ steps.msvc_version.outputs.version }}-${{ inputs.cache-key-suffix }}-${{ github.event.inputs.cache-key-suffix || 'default' }}-${{ hashFiles('.gitmodules', 'extern/**', 'CMakePresets.json', 'vcpkg.json', 'vcpkg-configuration.json') }} + restore-keys: | + ${{ runner.os }}-cmake-msvc-${{ steps.msvc_version.outputs.version }}-${{ inputs.cache-key-suffix }}-${{ github.event.inputs.cache-key-suffix || 'default' }}- + ${{ runner.os }}-cmake-msvc-${{ steps.msvc_version.outputs.version }}-${{ inputs.cache-key-suffix }}- + - name: Remove stale CMake cache if configuration changed shell: pwsh run: | diff --git a/.github/workflows/maint-todo-issues.yaml b/.github/workflows/maint-todo-issues.yaml index d6b27c2d73..83a6a03271 100644 --- a/.github/workflows/maint-todo-issues.yaml +++ b/.github/workflows/maint-todo-issues.yaml @@ -10,6 +10,14 @@ on: MANUAL_BASE_REF: description: "By default, the commit entered above is compared to the one directly before it; to go back further, enter an earlier SHA here" required: false + +# Least-privilege scope: alstr/todo-to-issue-action creates issues from TODO/ +# FIXME comments it finds in the diff. `issues: write` for the create call, +# `contents: read` for the checkout step. +permissions: + contents: read + issues: write + jobs: build: runs-on: "ubuntu-latest" diff --git a/.github/workflows/nexus-upload.yaml b/.github/workflows/nexus-upload.yaml index 13641ae496..4da6b588e9 100644 --- a/.github/workflows/nexus-upload.yaml +++ b/.github/workflows/nexus-upload.yaml @@ -86,6 +86,13 @@ on: UNEX_APIKEY: required: false +# Least-privilege for the whole workflow: every job here only reads from +# GitHub (release listing via `gh api`, asset download via `gh release +# download`) and writes only to Nexus via the UNEX_* secrets. No mutation +# of repo state. +permissions: + contents: read + jobs: prepare-nexus-matrix: runs-on: ubuntu-latest diff --git a/.github/workflows/pr-wip.yaml b/.github/workflows/pr-wip.yaml index 269228969c..2da55f67fd 100644 --- a/.github/workflows/pr-wip.yaml +++ b/.github/workflows/pr-wip.yaml @@ -3,6 +3,13 @@ on: pull_request: types: [opened, synchronize, reopened, edited] +# Least-privilege scope for the wip/action: it sets a commit status on the PR +# head (statuses: write) and reads PR metadata (pull-requests: read). No other +# repo writes happen here. +permissions: + statuses: write + pull-requests: read + jobs: wip: runs-on: ubuntu-latest