diff --git a/.github/workflows/README.md b/.github/workflows/README.md index f7e752357..476fa375f 100644 --- a/.github/workflows/README.md +++ b/.github/workflows/README.md @@ -7,6 +7,12 @@ smoke suite. Remote actions and reusable workflows must use full commit SHAs, container actions must use SHA-256 digests, and GitHub-hosted runners must use dated image labels rather than moving `-latest` aliases. +Checkout pins additionally belong to a reviewed allowlist whose current floor +includes GitHub's fail-closed fork-PR protection for privileged events. The +audit prohibits `pull_request_target` entirely and rejects checkout's +`allow-unsafe-pr-checkout` opt-out; privileged work must remain isolated from +pull-request code rather than bypassing the upstream guard. + Every `actions/checkout` step must also set `persist-credentials` explicitly. Use `false` unless a later command in the same job performs an authenticated Git write. The small number of write-path exceptions use `true` with the diff --git a/.github/workflows/backfill-release-assets.yml b/.github/workflows/backfill-release-assets.yml index 9bc471409..7078bd363 100644 --- a/.github/workflows/backfill-release-assets.yml +++ b/.github/workflows/backfill-release-assets.yml @@ -24,7 +24,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 with: persist-credentials: false diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index a15341951..20be1ff7e 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -33,7 +33,7 @@ jobs: GITLEAKS_LINUX_X64_SHA256: "551f6fc83ea457d62a0d98237cbad105af8d557003051f41f3e7ca7b3f2470eb" steps: - name: Checkout repository - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 with: persist-credentials: false fetch-depth: 0 @@ -73,7 +73,7 @@ jobs: code: ${{ steps.filter.outputs.code }} steps: - name: Checkout repository - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 with: persist-credentials: false fetch-depth: 0 @@ -114,7 +114,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 with: persist-credentials: false @@ -186,7 +186,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 with: persist-credentials: false @@ -237,7 +237,7 @@ jobs: timeout-minutes: 30 steps: - name: Checkout repository - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 with: persist-credentials: false # test_gitleaks_ignore.py resolves historical fingerprints against @@ -270,7 +270,7 @@ jobs: timeout-minutes: 30 steps: - name: Checkout repository - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 with: persist-credentials: false diff --git a/.github/workflows/build-release-candidate.yml b/.github/workflows/build-release-candidate.yml index 15ce06661..0142604cb 100644 --- a/.github/workflows/build-release-candidate.yml +++ b/.github/workflows/build-release-candidate.yml @@ -268,7 +268,7 @@ jobs: timeout-minutes: 30 steps: - name: Checkout repository - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 with: persist-credentials: false @@ -372,7 +372,7 @@ jobs: contents: read steps: - name: Checkout repository - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 with: persist-credentials: false @@ -667,7 +667,7 @@ jobs: echo "container_artifact_name=release-container-payload-${GITHUB_SHA}-${VERSION}" >> "$GITHUB_OUTPUT" - name: Checkout repository - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 with: persist-credentials: false fetch-depth: 0 diff --git a/.github/workflows/canonical-governance.yml b/.github/workflows/canonical-governance.yml index 775b0b1a1..2e29f99c6 100644 --- a/.github/workflows/canonical-governance.yml +++ b/.github/workflows/canonical-governance.yml @@ -24,7 +24,7 @@ jobs: working-directory: repos/pulse steps: - name: Checkout repository - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 with: persist-credentials: false fetch-depth: 0 diff --git a/.github/workflows/canonical-private-governance.yml b/.github/workflows/canonical-private-governance.yml index 219b19e05..571dc2a33 100644 --- a/.github/workflows/canonical-private-governance.yml +++ b/.github/workflows/canonical-private-governance.yml @@ -25,14 +25,14 @@ jobs: working-directory: repos/pulse steps: - name: Checkout repository - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 with: persist-credentials: false fetch-depth: 1 path: repos/pulse - name: Checkout pulse-pro evidence repo - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 with: repository: rcourtman/pulse-pro token: ${{ secrets.WORKFLOW_PAT }} @@ -41,7 +41,7 @@ jobs: path: repos/pulse-pro - name: Checkout pulse-enterprise evidence repo - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 with: repository: rcourtman/pulse-enterprise token: ${{ secrets.WORKFLOW_PAT }} @@ -50,7 +50,7 @@ jobs: path: repos/pulse-enterprise - name: Checkout pulse-mobile evidence repo - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 with: repository: rcourtman/pulse-mobile token: ${{ secrets.WORKFLOW_PAT }} diff --git a/.github/workflows/close-needs-retest-timeout.yml b/.github/workflows/close-needs-retest-timeout.yml index e3ac58b07..d1faa2464 100644 --- a/.github/workflows/close-needs-retest-timeout.yml +++ b/.github/workflows/close-needs-retest-timeout.yml @@ -30,7 +30,7 @@ jobs: private-key: ${{ secrets.PULSE_TRIAGE_APP_PRIVATE_KEY }} - name: Check out triage helper - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 with: persist-credentials: false sparse-checkout: | diff --git a/.github/workflows/compile-release-payload.yml b/.github/workflows/compile-release-payload.yml index e400e6fe2..e21ada520 100644 --- a/.github/workflows/compile-release-payload.yml +++ b/.github/workflows/compile-release-payload.yml @@ -38,7 +38,7 @@ jobs: test "${GITHUB_WORKFLOW_SHA}" = "${EXPECTED_SOURCE_SHA}" - name: Checkout exact release source - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 with: persist-credentials: false fetch-depth: 0 @@ -121,7 +121,7 @@ jobs: test "${GITHUB_WORKFLOW_SHA}" = "${EXPECTED_SOURCE_SHA}" - name: Checkout exact release source - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 with: persist-credentials: false fetch-depth: 0 diff --git a/.github/workflows/create-release.yml b/.github/workflows/create-release.yml index e1a840e84..8c9c8eac7 100644 --- a/.github/workflows/create-release.yml +++ b/.github/workflows/create-release.yml @@ -139,7 +139,7 @@ jobs: echo "Version: ${VERSION}, Tag: ${TAG}, Prerelease: ${IS_PRERELEASE}, Branch: ${SOURCE_BRANCH}, HistoricalBackfillOnly: ${HISTORICAL_ASSET_BACKFILL_ONLY}" - name: Checkout repository - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 with: persist-credentials: false fetch-depth: 0 @@ -281,7 +281,7 @@ jobs: steps: - name: Checkout release trust control if: ${{ github.event.inputs.draft_only != 'true' && needs.prepare.outputs.historical_asset_backfill_only != 'true' }} - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 with: persist-credentials: false @@ -345,7 +345,7 @@ jobs: timeout-minutes: 10 steps: - name: Checkout repository - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 with: persist-credentials: false @@ -380,7 +380,7 @@ jobs: timeout-minutes: 20 steps: - name: Checkout repository - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 with: persist-credentials: false @@ -419,7 +419,7 @@ jobs: timeout-minutes: 15 steps: - name: Checkout repository - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 with: persist-credentials: false @@ -456,7 +456,7 @@ jobs: FRONTEND_DIST: frontend-modern/dist steps: - name: Checkout repository - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 with: persist-credentials: false @@ -495,7 +495,7 @@ jobs: FRONTEND_DIST: frontend-modern/dist steps: - name: Checkout repository - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 with: persist-credentials: false @@ -660,7 +660,7 @@ jobs: PULSE_E2E_BOOTSTRAP_TOKEN: 0123456789abcdef0123456789abcdef0123456789abcdef steps: - name: Checkout repository - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 with: persist-credentials: false @@ -760,7 +760,7 @@ jobs: steps: - name: Checkout repository if: ${{ needs.prepare.outputs.visual_capture_count != '0' }} - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 with: persist-credentials: false fetch-depth: 0 @@ -810,7 +810,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 with: persist-credentials: true # required: authenticated git writes fetch-depth: 0 @@ -1251,7 +1251,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 with: persist-credentials: false @@ -1646,7 +1646,7 @@ jobs: secure_runtime_qualification_run_url: ${{ steps.secure_runtime_qualification.outputs.run_url }} steps: - name: Checkout release integrity control - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 with: persist-credentials: false @@ -2014,7 +2014,7 @@ jobs: timeout-minutes: 10 steps: - name: Checkout release integrity control - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 with: persist-credentials: false diff --git a/.github/workflows/eval-model-matrix.yml b/.github/workflows/eval-model-matrix.yml index 793ad5748..46e1747b7 100644 --- a/.github/workflows/eval-model-matrix.yml +++ b/.github/workflows/eval-model-matrix.yml @@ -35,7 +35,7 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 with: persist-credentials: false diff --git a/.github/workflows/helm-ci.yml b/.github/workflows/helm-ci.yml index a5313e01a..eab6852d3 100644 --- a/.github/workflows/helm-ci.yml +++ b/.github/workflows/helm-ci.yml @@ -26,7 +26,7 @@ jobs: timeout-minutes: 15 steps: - name: Checkout repository - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 with: persist-credentials: false diff --git a/.github/workflows/helm-pages.yml b/.github/workflows/helm-pages.yml index f1e9b164f..7168c8e02 100644 --- a/.github/workflows/helm-pages.yml +++ b/.github/workflows/helm-pages.yml @@ -36,7 +36,7 @@ jobs: timeout-minutes: 20 steps: - name: Checkout release verification control - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 with: persist-credentials: false @@ -171,7 +171,7 @@ jobs: helm show chart "${CHART_PATH}" - name: Check out current Pages index - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 with: ref: gh-pages path: gh-pages diff --git a/.github/workflows/install-sh-smoke.yml b/.github/workflows/install-sh-smoke.yml index 57abc1867..3fd351e6c 100644 --- a/.github/workflows/install-sh-smoke.yml +++ b/.github/workflows/install-sh-smoke.yml @@ -100,7 +100,7 @@ jobs: contents: write steps: - name: Checkout repository (for README key extraction) - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 with: persist-credentials: false diff --git a/.github/workflows/issue-version-label-sync.yml b/.github/workflows/issue-version-label-sync.yml index 576185f12..a0e558934 100644 --- a/.github/workflows/issue-version-label-sync.yml +++ b/.github/workflows/issue-version-label-sync.yml @@ -24,7 +24,7 @@ jobs: private-key: ${{ secrets.PULSE_TRIAGE_APP_PRIVATE_KEY }} - name: Check out triage helper - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 with: persist-credentials: false sparse-checkout: | diff --git a/.github/workflows/issue-version-retest-comment.yml b/.github/workflows/issue-version-retest-comment.yml index fe7ed5f58..1dc1b5f52 100644 --- a/.github/workflows/issue-version-retest-comment.yml +++ b/.github/workflows/issue-version-retest-comment.yml @@ -25,7 +25,7 @@ jobs: private-key: ${{ secrets.PULSE_TRIAGE_APP_PRIVATE_KEY }} - name: Check out triage helper - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 with: persist-credentials: false sparse-checkout: | diff --git a/.github/workflows/patrol-qualification-live.yml b/.github/workflows/patrol-qualification-live.yml index 5b9b81ab6..6f8ff89dd 100644 --- a/.github/workflows/patrol-qualification-live.yml +++ b/.github/workflows/patrol-qualification-live.yml @@ -51,7 +51,7 @@ jobs: steps: - name: Checkout pinned source - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 with: persist-credentials: false diff --git a/.github/workflows/patrol-qualification-regression.yml b/.github/workflows/patrol-qualification-regression.yml index 9bff2e0ec..aeb3b6b52 100644 --- a/.github/workflows/patrol-qualification-regression.yml +++ b/.github/workflows/patrol-qualification-regression.yml @@ -42,7 +42,7 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 with: persist-credentials: false diff --git a/.github/workflows/promote-floating-tags.yml b/.github/workflows/promote-floating-tags.yml index ff984ca60..f61fd3a03 100644 --- a/.github/workflows/promote-floating-tags.yml +++ b/.github/workflows/promote-floating-tags.yml @@ -64,7 +64,7 @@ jobs: echo "Promoting floating tags for ${TAG} (prerelease: ${PRERELEASE})" - name: Checkout repository - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 with: persist-credentials: false fetch-depth: 0 diff --git a/.github/workflows/public-docs.yml b/.github/workflows/public-docs.yml index 06efb084b..3fdc4bc0a 100644 --- a/.github/workflows/public-docs.yml +++ b/.github/workflows/public-docs.yml @@ -31,7 +31,7 @@ jobs: timeout-minutes: 10 steps: - name: Check out repository - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 with: persist-credentials: false diff --git a/.github/workflows/publish-docker.yml b/.github/workflows/publish-docker.yml index 95b95daf2..b121e1ac7 100644 --- a/.github/workflows/publish-docker.yml +++ b/.github/workflows/publish-docker.yml @@ -54,7 +54,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 with: persist-credentials: false fetch-depth: 0 @@ -244,7 +244,7 @@ jobs: control_plane_digest: ${{ steps.proof.outputs.control_plane_digest }} steps: - name: Checkout release verification control - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 with: persist-credentials: false diff --git a/.github/workflows/publish-helm-chart.yml b/.github/workflows/publish-helm-chart.yml index 5670a5b8a..2bf16513a 100644 --- a/.github/workflows/publish-helm-chart.yml +++ b/.github/workflows/publish-helm-chart.yml @@ -94,7 +94,7 @@ jobs: echo "is_prerelease=$IS_PRERELEASE" >> "$GITHUB_OUTPUT" - name: Checkout repository - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 with: persist-credentials: false fetch-depth: 0 diff --git a/.github/workflows/qualify-release-containers.yml b/.github/workflows/qualify-release-containers.yml index c06dab17d..ccd1a6b94 100644 --- a/.github/workflows/qualify-release-containers.yml +++ b/.github/workflows/qualify-release-containers.yml @@ -27,7 +27,7 @@ jobs: VERSION: ${{ inputs.version }} steps: - name: Checkout repository - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 with: # A reusable workflow inherits github.sha from its caller. Do not # accept a caller-controlled checkout ref: the caller event commit is diff --git a/.github/workflows/qualify-secure-runtime-release.yml b/.github/workflows/qualify-secure-runtime-release.yml index 29b0d4187..6c2305a72 100644 --- a/.github/workflows/qualify-secure-runtime-release.yml +++ b/.github/workflows/qualify-secure-runtime-release.yml @@ -48,7 +48,7 @@ jobs: echo "release_id=${release_id}" >> "$GITHUB_OUTPUT" - name: Checkout exact release tag - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 with: persist-credentials: false fetch-depth: 0 diff --git a/.github/workflows/recover-demo-server.yml b/.github/workflows/recover-demo-server.yml index 2f4190073..d03275eab 100644 --- a/.github/workflows/recover-demo-server.yml +++ b/.github/workflows/recover-demo-server.yml @@ -24,7 +24,7 @@ jobs: steps: - name: Checkout exact recovery implementation - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 with: persist-credentials: false fetch-depth: 0 diff --git a/.github/workflows/recover-release-activation.yml b/.github/workflows/recover-release-activation.yml index 1e97acde2..494bdf568 100644 --- a/.github/workflows/recover-release-activation.yml +++ b/.github/workflows/recover-release-activation.yml @@ -32,7 +32,7 @@ jobs: timeout-minutes: 30 steps: - name: Checkout release control - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 with: persist-credentials: false diff --git a/.github/workflows/release-convergence.yml b/.github/workflows/release-convergence.yml index 25db897b0..9ab22ee0f 100644 --- a/.github/workflows/release-convergence.yml +++ b/.github/workflows/release-convergence.yml @@ -58,7 +58,7 @@ jobs: helm_chart_digest: ${{ steps.marker.outputs.helm_chart_digest }} steps: - name: Checkout release integrity control - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 with: persist-credentials: false @@ -214,7 +214,7 @@ jobs: helm_chart_digest: ${{ needs.await_activation_commit.outputs.helm_chart_digest }} steps: - name: Checkout release control - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 with: fetch-depth: 1 persist-credentials: true # required: authenticated git writes @@ -472,7 +472,7 @@ jobs: contents: write steps: - name: Checkout release control - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 with: fetch-depth: 1 persist-credentials: true # required: authenticated git writes diff --git a/.github/workflows/release-dry-run.yml b/.github/workflows/release-dry-run.yml index 33599d712..04fd112a3 100644 --- a/.github/workflows/release-dry-run.yml +++ b/.github/workflows/release-dry-run.yml @@ -121,7 +121,7 @@ jobs: echo "[OK] Dry run executing on branch ${GITHUB_REF_NAME}" - name: Checkout repository - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 with: persist-credentials: false fetch-depth: 0 diff --git a/.github/workflows/repo-boundary-audit.yml b/.github/workflows/repo-boundary-audit.yml index 8a7f9d4a6..e5cd204c7 100644 --- a/.github/workflows/repo-boundary-audit.yml +++ b/.github/workflows/repo-boundary-audit.yml @@ -13,7 +13,7 @@ jobs: timeout-minutes: 15 steps: - name: Checkout - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 with: persist-credentials: false diff --git a/.github/workflows/security-scan.yml b/.github/workflows/security-scan.yml index 806aa6edd..06b412dd7 100644 --- a/.github/workflows/security-scan.yml +++ b/.github/workflows/security-scan.yml @@ -31,7 +31,7 @@ jobs: timeout-minutes: 60 steps: - name: Checkout release verification controls - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 with: persist-credentials: false @@ -291,7 +291,7 @@ jobs: timeout-minutes: 30 steps: - name: Checkout repository - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 with: persist-credentials: false @@ -318,7 +318,7 @@ jobs: - 'tests/integration/mock-github-server' steps: - name: Checkout repository - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 with: persist-credentials: false @@ -353,7 +353,7 @@ jobs: directory: 'tests/integration' steps: - name: Checkout repository - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 with: persist-credentials: false diff --git a/.github/workflows/signpath-test-signing.yml b/.github/workflows/signpath-test-signing.yml index 9df56439a..e2d9c599e 100644 --- a/.github/workflows/signpath-test-signing.yml +++ b/.github/workflows/signpath-test-signing.yml @@ -26,7 +26,7 @@ jobs: contents: read steps: - name: Checkout repository - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 with: persist-credentials: false diff --git a/.github/workflows/test-e2e.yml b/.github/workflows/test-e2e.yml index 0b232b6b4..f5a1b8f51 100644 --- a/.github/workflows/test-e2e.yml +++ b/.github/workflows/test-e2e.yml @@ -41,7 +41,7 @@ jobs: timeout-minutes: 10 steps: - name: Checkout code - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 with: persist-credentials: false @@ -82,7 +82,7 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 with: persist-credentials: false @@ -235,7 +235,7 @@ jobs: timeout-minutes: 30 steps: - name: Checkout code - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 with: persist-credentials: false diff --git a/.github/workflows/unified-agent-native.yml b/.github/workflows/unified-agent-native.yml index 8b04da394..f8a4e686a 100644 --- a/.github/workflows/unified-agent-native.yml +++ b/.github/workflows/unified-agent-native.yml @@ -74,7 +74,7 @@ jobs: timeout-minutes: 45 steps: - name: Checkout repository - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 with: persist-credentials: false @@ -181,7 +181,7 @@ jobs: timeout-minutes: 30 steps: - name: Checkout repository - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 with: persist-credentials: false diff --git a/.github/workflows/update-demo-server.yml b/.github/workflows/update-demo-server.yml index 13bfb673e..324b68cf5 100644 --- a/.github/workflows/update-demo-server.yml +++ b/.github/workflows/update-demo-server.yml @@ -129,7 +129,7 @@ jobs: echo "Resolved demo deployment: tag=${TAG}, target=${TARGET}, environment=${ENVIRONMENT_NAME}" - name: Checkout repository - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 with: persist-credentials: false fetch-depth: 0 @@ -275,7 +275,7 @@ jobs: echo "[OK] Stable demo mutation is bound to committed ${TAG} convergence run ${CONVERGENCE_RUN_ID}." - name: Checkout repository - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 with: persist-credentials: false fetch-depth: 0 diff --git a/.github/workflows/validate-release-assets.yml b/.github/workflows/validate-release-assets.yml index a095274ab..9630f506a 100644 --- a/.github/workflows/validate-release-assets.yml +++ b/.github/workflows/validate-release-assets.yml @@ -72,7 +72,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 with: persist-credentials: false diff --git a/docs/release-control/v6/internal/subsystems/agent-lifecycle.md b/docs/release-control/v6/internal/subsystems/agent-lifecycle.md index 9de33fe09..e321532dc 100644 --- a/docs/release-control/v6/internal/subsystems/agent-lifecycle.md +++ b/docs/release-control/v6/internal/subsystems/agent-lifecycle.md @@ -7262,3 +7262,15 @@ The node drawer may use `Node.LinkedAgentID` to label Pulse coverage, but that presentation does not combine agent lifecycle with package evidence. The polling states are pinned independently in `internal/monitoring/node_pending_updates_evidence_test.go`. + +### Native agent lifecycle proof preserves protected checkout semantics + +The native Linux and Windows agent lifecycle jobs obtain their source through +the reviewed immutable `actions/checkout` v6.1.0 pin. That baseline refuses +fork pull-request checkout on privileged events unless a workflow explicitly +opts out; Pulse prohibits that opt-out and the `pull_request_target` trigger. +A dependency refresh must update the central workflow-trust allowlist and the +native lifecycle workflow proof together, so lifecycle qualification cannot +silently execute under a weaker checkout boundary. +`scripts/check_workflow_trust.py`, `scripts/tests/test_workflow_trust.py`, and +`scripts/installtests/install_ps1_test.go` pin that relationship. diff --git a/docs/release-control/v6/internal/subsystems/deployment-installability.md b/docs/release-control/v6/internal/subsystems/deployment-installability.md index 3a7c8833d..ceeecdd60 100644 --- a/docs/release-control/v6/internal/subsystems/deployment-installability.md +++ b/docs/release-control/v6/internal/subsystems/deployment-installability.md @@ -4712,3 +4712,17 @@ The opt-in belongs only to the generated systemd service. Container and terminal output remain unprefixed, and the logger tees the unmodified record to the rotating file sink and authenticated live-log broadcaster. Installer and logging tests pin the unit directives, level mapping, and sink isolation. + +### Release automation preserves protected checkout semantics + +Every repository checkout in build, packaging, publication, qualification, +recovery, and deployment automation uses the reviewed immutable +`actions/checkout` v6.1.0 pin. That baseline refuses fork pull-request checkout +on privileged events unless a workflow explicitly opts out; Pulse prohibits +that opt-out and the `pull_request_target` trigger. Dependency refreshes must +update the central workflow-trust allowlist and its regression proof together, +so a routine pin change cannot silently remove this release-automation trust +boundary. `scripts/check_workflow_trust.py`, +`scripts/tests/test_workflow_trust.py`, and +`scripts/installtests/build_release_assets_test.go` pin the policy and the +release-workflow integration. diff --git a/scripts/check_workflow_trust.py b/scripts/check_workflow_trust.py index a59e28f7d..5bbaca599 100644 --- a/scripts/check_workflow_trust.py +++ b/scripts/check_workflow_trust.py @@ -43,6 +43,12 @@ SECRET_CONTEXT_TOKEN_RE = re.compile(r"(? list[Finding]: lines = path.read_text(encoding="utf-8").splitlines() findings = _audit_runner_job_timeouts(path, lines) + if _has_trigger(lines, "pull_request_target"): + findings.append( + Finding( + path, + 1, + "pull_request_target is prohibited; use pull_request or isolate " + "privileged work from pull-request code", + ) + ) + if _has_trigger(lines, "pull_request"): for index, line in enumerate(lines): code = line.split("#", 1)[0] @@ -326,9 +342,35 @@ def audit_workflow(path: Path) -> list[Finding]: # applying checkout-specific credential controls. if not dependency.lower().startswith(CHECKOUT_PREFIX): continue + if ref not in PROTECTED_CHECKOUT_PINS: + findings.append( + Finding( + path, + line_number, + "checkout pin is outside the reviewed privileged-event " + "protection baseline", + ) + ) + checkout_block = _checkout_block(lines, index) + unsafe_pr_settings = [ + (block_index, block_line) + for block_index, block_line in checkout_block + if re.match(r"^\s*allow-unsafe-pr-checkout\s*:", block_line) + ] + for setting_index, setting in unsafe_pr_settings: + if not re.match( + r"^\s*allow-unsafe-pr-checkout\s*:\s*false(?:\s|$)", setting + ): + findings.append( + Finding( + path, + setting_index + 1, + "checkout must not opt out of privileged-event PR protection", + ) + ) credential_settings = [ (block_index, block_line) - for block_index, block_line in _checkout_block(lines, index) + for block_index, block_line in checkout_block if re.match(r"^\s*persist-credentials\s*:", block_line) ] if len(credential_settings) != 1: diff --git a/scripts/installtests/build_release_assets_test.go b/scripts/installtests/build_release_assets_test.go index 442d125dc..aa26c1369 100644 --- a/scripts/installtests/build_release_assets_test.go +++ b/scripts/installtests/build_release_assets_test.go @@ -1337,7 +1337,7 @@ func TestBackfillReleaseWorkflowRepairsPublishedAssetsWithoutRebuilds(t *testing `workflow_dispatch:`, `contents: write`, `runs-on: ubuntu-24.04`, - `uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3`, + `uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0`, `uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0`, `SYFT_VERSION="1.42.4"`, `SYFT_ARCHIVE="syft_${SYFT_VERSION}_linux_amd64.tar.gz"`, diff --git a/scripts/installtests/install_ps1_test.go b/scripts/installtests/install_ps1_test.go index 0a89314d0..8637da04b 100644 --- a/scripts/installtests/install_ps1_test.go +++ b/scripts/installtests/install_ps1_test.go @@ -110,6 +110,7 @@ func TestNativeWindowsSelfTestDoesNotPreseedLifecycleState(t *testing.T) { workflow := string(content) required := []string{ + `uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0`, `node-version: '24'`, `$selfTestStateDir = Join-Path $env:RUNNER_TEMP 'pulse-agent-self-test'`, `$selfTestLogFile = Join-Path $selfTestStateDir 'pulse-agent.log'`, diff --git a/scripts/tests/test_workflow_trust.py b/scripts/tests/test_workflow_trust.py index 2b73fdeae..d6458917e 100644 --- a/scripts/tests/test_workflow_trust.py +++ b/scripts/tests/test_workflow_trust.py @@ -20,6 +20,7 @@ SPEC.loader.exec_module(workflow_trust) PIN = "a" * 40 DIGEST = "b" * 64 +CHECKOUT_PIN = next(iter(workflow_trust.PROTECTED_CHECKOUT_PINS)) class WorkflowTrustTest(unittest.TestCase): @@ -38,7 +39,7 @@ jobs: runs-on: ubuntu-24.04 timeout-minutes: 10 steps: - - uses: actions/checkout@{PIN} + - uses: actions/checkout@{CHECKOUT_PIN} with: persist-credentials: false - uses: owner/action/path@{PIN} # v1 @@ -161,11 +162,44 @@ steps: any("must set persist-credentials" in finding for finding in mixed_case) ) - def test_accepts_documented_authenticated_git_write(self) -> None: + def test_requires_reviewed_protected_checkout_pin(self) -> None: findings = self.audit( f"""permissions: {{}} steps: - uses: actions/checkout@{PIN} + with: + persist-credentials: false +""" + ) + self.assertTrue( + any( + "privileged-event protection baseline" in finding + for finding in findings + ) + ) + + def test_rejects_privileged_pr_trigger_and_checkout_opt_out(self) -> None: + findings = self.audit( + f"""on: + pull_request_target: +permissions: {{}} +steps: + - uses: actions/checkout@{CHECKOUT_PIN} + with: + persist-credentials: false + allow-unsafe-pr-checkout: true +""" + ) + self.assertTrue( + any("pull_request_target is prohibited" in finding for finding in findings) + ) + self.assertTrue(any("must not opt out" in finding for finding in findings)) + + def test_accepts_documented_authenticated_git_write(self) -> None: + findings = self.audit( + f"""permissions: {{}} +steps: + - uses: actions/checkout@{CHECKOUT_PIN} with: persist-credentials: true # required: authenticated git writes """