diff --git a/.github/workflows/binding-release-candidate.yml b/.github/workflows/binding-release-candidate.yml index 6a2d87d86..3e1a9ce4e 100644 --- a/.github/workflows/binding-release-candidate.yml +++ b/.github/workflows/binding-release-candidate.yml @@ -22,7 +22,7 @@ jobs: outputs: evidence_sha: ${{ steps.source.outputs.evidence_sha }} steps: - - uses: actions/checkout@v7 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: ref: main fetch-depth: 1 @@ -57,7 +57,7 @@ jobs: CARGO_TARGET_DIR: ${{ github.workspace }}/target EVIDENCE_SHA: ${{ needs.validate_source.outputs.evidence_sha }} steps: - - uses: actions/checkout@v7 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: ref: ${{ needs.validate_source.outputs.evidence_sha }} @@ -67,22 +67,21 @@ jobs: [[ "$EVIDENCE_SHA" =~ ^[0-9a-f]{40}$ ]] test "$(git rev-parse HEAD)" = "$EVIDENCE_SHA" - - uses: actions/setup-python@v7 + - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 with: python-version: "3.13" - - uses: astral-sh/setup-uv@v9.0.0 - + - uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v9.0.0 - name: Mount shared Linux Cargo build disk if: matrix.sticky_target == 'true' - uses: useblacksmith/stickydisk@v1 + uses: useblacksmith/stickydisk@35ba2e331a80056a42af053ee54968511de2b7c7 # v1.5.0 with: # Python Ubuntu and Linux Node targets share compatible release products. key: ${{ github.repository }}-binding-rc-linux-rust-1.96.0-${{ hashFiles('Cargo.lock') }}-release-target-v1 path: target - name: Cache Cargo registry - uses: actions/cache@v6 + uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: path: | ~/.cargo/registry @@ -90,7 +89,7 @@ jobs: key: ${{ runner.os }}-cargo-registry-v1-${{ hashFiles('Cargo.lock') }} - name: Build native abi3 wheel - uses: PyO3/maturin-action@v1 + uses: PyO3/maturin-action@e83996d129638aa358a18fbd1dfb82f0b0fb5d3b # v1.51.0 with: command: build args: --release --manifest-path crates/graphforge-bindings-py/Cargo.toml --out dist @@ -194,7 +193,7 @@ jobs: cp "$PYTHON_RC_EVIDENCE_DIR/${{ matrix.target }}.json" binding-rc-reports/ - name: Save Python report for aggregate job - uses: actions/upload-artifact@v7 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: binding-rc-report-${{ github.run_id }}-${{ matrix.target }} path: binding-rc-reports/${{ matrix.target }}.json @@ -202,7 +201,7 @@ jobs: retention-days: 1 - name: Save tested wheel for release-candidate assembly - uses: actions/upload-artifact@v7 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: binding-rc-wheel-${{ github.run_id }}-${{ matrix.target }} path: dist/*.whl @@ -260,7 +259,7 @@ jobs: CARGO_TARGET_DIR: ${{ github.workspace }}/target EVIDENCE_SHA: ${{ needs.validate_source.outputs.evidence_sha }} steps: - - uses: actions/checkout@v7 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: ref: ${{ needs.validate_source.outputs.evidence_sha }} @@ -270,28 +269,27 @@ jobs: [[ "$EVIDENCE_SHA" =~ ^[0-9a-f]{40}$ ]] test "$(git rev-parse HEAD)" = "$EVIDENCE_SHA" - - uses: actions/setup-node@v7 + - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: node-version: "20" architecture: ${{ matrix.node_arch }} - - uses: pnpm/action-setup@v4 - - - uses: dtolnay/rust-toolchain@master + - uses: pnpm/action-setup@b906affcce14559ad1aafd4ab0e942779e9f58b1 # v4.3.0 + - uses: dtolnay/rust-toolchain@6c977a6ca4077a0ceb28ffbe03f59d46e9ac8772 # master as of 2026-08-05 with: toolchain: "1.96.0" targets: ${{ matrix.target }} - name: Mount shared Linux Cargo build disk if: matrix.sticky_target == 'true' - uses: useblacksmith/stickydisk@v1 + uses: useblacksmith/stickydisk@35ba2e331a80056a42af053ee54968511de2b7c7 # v1.5.0 with: # Python Ubuntu and Linux Node targets share compatible release products. key: ${{ github.repository }}-binding-rc-linux-rust-1.96.0-${{ hashFiles('Cargo.lock') }}-release-target-v1 path: target - name: Cache Cargo registry - uses: actions/cache@v6 + uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: path: | ~/.cargo/registry @@ -395,7 +393,7 @@ jobs: cp "crates/graphforge-bindings-node/${{ matrix.report_target }}.json" binding-rc-reports/ - name: Save Node report for aggregate job - uses: actions/upload-artifact@v7 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: binding-rc-report-${{ github.run_id }}-${{ matrix.report_target }} path: binding-rc-reports/${{ matrix.report_target }}.json @@ -403,7 +401,7 @@ jobs: retention-days: 1 - name: Save tested addon for release-candidate assembly - uses: actions/upload-artifact@v7 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: binding-rc-addon-${{ github.run_id }}-${{ matrix.target }} path: crates/graphforge-bindings-node/*.node @@ -419,12 +417,12 @@ jobs: actions: read contents: read steps: - - uses: actions/checkout@v7 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: ref: ${{ needs.validate_source.outputs.evidence_sha }} - name: Download exact-run target reports - uses: actions/download-artifact@v8 + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: pattern: binding-rc-report-${{ github.run_id }}-* path: binding-rc-reports @@ -439,7 +437,7 @@ jobs: --output binding-rc-aggregate/report.json - name: Retain aggregate publication evidence - uses: actions/upload-artifact@v7 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: M1-Binding-Release-Candidate-${{ needs.validate_source.outputs.evidence_sha }} path: binding-rc-aggregate/report.json @@ -456,7 +454,7 @@ jobs: CARGO_INCREMENTAL: 0 CARGO_TARGET_DIR: ${{ github.workspace }}/target steps: - - uses: actions/checkout@v7 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: ref: ${{ needs.validate_source.outputs.evidence_sha }} @@ -485,30 +483,28 @@ jobs: esac printf 'RELEASE_VERSION=%s\n' "$release_version" >> "$GITHUB_ENV" - - uses: actions/setup-python@v7 + - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 with: python-version: "3.13" - - uses: astral-sh/setup-uv@v9.0.0 - - - uses: actions/setup-node@v7 + - uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v9.0.0 + - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: node-version: "22" - - uses: pnpm/action-setup@v4 - - - uses: dtolnay/rust-toolchain@master + - uses: pnpm/action-setup@b906affcce14559ad1aafd4ab0e942779e9f58b1 # v4.3.0 + - uses: dtolnay/rust-toolchain@6c977a6ca4077a0ceb28ffbe03f59d46e9ac8772 # master as of 2026-08-05 with: toolchain: "1.96.0" - name: Mount release assembly Cargo build disk - uses: useblacksmith/stickydisk@v1 + uses: useblacksmith/stickydisk@35ba2e331a80056a42af053ee54968511de2b7c7 # v1.5.0 with: key: ${{ github.repository }}-release_candidate-rust-1.96.0-${{ hashFiles('Cargo.lock') }}-release-target-v1 path: target - name: Cache Cargo registry - uses: actions/cache@v6 + uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: path: | ~/.cargo/registry @@ -516,14 +512,14 @@ jobs: key: ${{ runner.os }}-cargo-registry-v1-${{ hashFiles('Cargo.lock') }} - name: Download exact-run tested wheels - uses: actions/download-artifact@v8 + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: pattern: binding-rc-wheel-${{ github.run_id }}-* path: candidate/release-artifacts/python merge-multiple: true - name: Download exact-run tested Node addons - uses: actions/download-artifact@v8 + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: pattern: binding-rc-addon-${{ github.run_id }}-* path: candidate/release-artifacts/node-addons @@ -661,7 +657,7 @@ jobs: --version "$RELEASE_VERSION" - name: Retain the candidate manifest for publication - uses: actions/upload-artifact@v7 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: M1-Release-Candidate-manifest-${{ needs.validate_source.outputs.evidence_sha }} path: candidate/v${{ env.RELEASE_VERSION }}-artifacts.json @@ -669,7 +665,7 @@ jobs: retention-days: 30 - name: Retain the Python candidate partition - uses: actions/upload-artifact@v7 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: M1-Release-Candidate-python-${{ needs.validate_source.outputs.evidence_sha }} path: candidate/release-artifacts/python/ @@ -677,7 +673,7 @@ jobs: retention-days: 30 - name: Retain the npm candidate partition - uses: actions/upload-artifact@v7 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: M1-Release-Candidate-npm-${{ needs.validate_source.outputs.evidence_sha }} path: candidate/release-artifacts/npm/ @@ -685,7 +681,7 @@ jobs: retention-days: 30 - name: Retain the crates candidate partition - uses: actions/upload-artifact@v7 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: M1-Release-Candidate-crates-${{ needs.validate_source.outputs.evidence_sha }} path: candidate/release-artifacts/crates/ @@ -693,7 +689,7 @@ jobs: retention-days: 30 - name: Retain the evidence candidate partition - uses: actions/upload-artifact@v7 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: M1-Release-Candidate-evidence-${{ needs.validate_source.outputs.evidence_sha }} # upload-artifact does not expand bash brace globs; list both dirs. diff --git a/.github/workflows/checkpoint-recovery-gate.yml b/.github/workflows/checkpoint-recovery-gate.yml index 684ed0dc5..7fb5b949f 100644 --- a/.github/workflows/checkpoint-recovery-gate.yml +++ b/.github/workflows/checkpoint-recovery-gate.yml @@ -18,8 +18,8 @@ jobs: CARGO_INCREMENTAL: 0 CARGO_PROFILE_TEST_DEBUG: 0 steps: - - uses: actions/checkout@v7 - - uses: dtolnay/rust-toolchain@master + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + - uses: dtolnay/rust-toolchain@6c977a6ca4077a0ceb28ffbe03f59d46e9ac8772 # master as of 2026-08-05 with: toolchain: "1.96.0" - name: Validate frozen acceptance ledger @@ -56,7 +56,7 @@ jobs: ) PY - name: Save Rust evidence for aggregate job - uses: actions/cache/save@v6 + uses: actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: path: checkpoint-fragments/ key: checkpoint-transfer-${{ github.run_id }}-rust @@ -69,14 +69,14 @@ jobs: CARGO_INCREMENTAL: 0 CARGO_PROFILE_DEV_DEBUG: 0 steps: - - uses: actions/checkout@v7 - - uses: dtolnay/rust-toolchain@master + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + - uses: dtolnay/rust-toolchain@6c977a6ca4077a0ceb28ffbe03f59d46e9ac8772 # master as of 2026-08-05 with: toolchain: "1.96.0" - - uses: astral-sh/setup-uv@v9.0.0 + - uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v9.0.0 with: enable-cache: true - - uses: actions/setup-python@v7 + - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 with: python-version: "3.13" - name: Build and prove isolated same-SHA wheel @@ -100,7 +100,7 @@ jobs: ) PY - name: Save Python evidence for aggregate job - uses: actions/cache/save@v6 + uses: actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: path: checkpoint-fragments/ key: checkpoint-transfer-${{ github.run_id }}-python @@ -113,14 +113,14 @@ jobs: CARGO_INCREMENTAL: 0 CARGO_PROFILE_DEV_DEBUG: 0 steps: - - uses: actions/checkout@v7 - - uses: dtolnay/rust-toolchain@master + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + - uses: dtolnay/rust-toolchain@6c977a6ca4077a0ceb28ffbe03f59d46e9ac8772 # master as of 2026-08-05 with: toolchain: "1.96.0" - - uses: actions/setup-node@v7 + - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: node-version: "20" - - uses: pnpm/action-setup@v4 + - uses: pnpm/action-setup@b906affcce14559ad1aafd4ab0e942779e9f58b1 # v4.3.0 - name: Build and prove same-SHA Node package run: | pnpm install --frozen-lockfile @@ -142,7 +142,7 @@ jobs: ) PY - name: Save Node evidence for aggregate job - uses: actions/cache/save@v6 + uses: actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: path: checkpoint-fragments/ key: checkpoint-transfer-${{ github.run_id }}-node @@ -153,18 +153,18 @@ jobs: needs: [rust, python, node] runs-on: blacksmith-4vcpu-ubuntu-2404 steps: - - uses: actions/checkout@v7 - - uses: actions/cache/restore@v6 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + - uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: path: checkpoint-fragments key: checkpoint-transfer-${{ github.run_id }}-rust fail-on-cache-miss: true - - uses: actions/cache/restore@v6 + - uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: path: checkpoint-fragments key: checkpoint-transfer-${{ github.run_id }}-python fail-on-cache-miss: true - - uses: actions/cache/restore@v6 + - uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: path: checkpoint-fragments key: checkpoint-transfer-${{ github.run_id }}-node diff --git a/.github/workflows/clean-env-verify.yml b/.github/workflows/clean-env-verify.yml index f6a6b818f..5042a77dd 100644 --- a/.github/workflows/clean-env-verify.yml +++ b/.github/workflows/clean-env-verify.yml @@ -34,17 +34,16 @@ jobs: runs-on: blacksmith-4vcpu-ubuntu-2404 timeout-minutes: 45 steps: - - uses: actions/checkout@v7 - - - uses: actions/setup-python@v7 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 with: python-version: "3.13" - - uses: actions/setup-node@v7 + - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: node-version: "20" - - uses: dtolnay/rust-toolchain@master + - uses: dtolnay/rust-toolchain@6c977a6ca4077a0ceb28ffbe03f59d46e9ac8772 # master as of 2026-08-05 with: toolchain: "1.96.0" diff --git a/.github/workflows/concurrency-stress-gate.yml b/.github/workflows/concurrency-stress-gate.yml index 6a9032322..02a26aeba 100644 --- a/.github/workflows/concurrency-stress-gate.yml +++ b/.github/workflows/concurrency-stress-gate.yml @@ -30,17 +30,16 @@ jobs: GF_STRESS_SEED: "2417" GF_STRESS_ITERATIONS: ${{ github.event.inputs.iterations || '24' }} steps: - - uses: actions/checkout@v7 - - - uses: dtolnay/rust-toolchain@master + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + - uses: dtolnay/rust-toolchain@6c977a6ca4077a0ceb28ffbe03f59d46e9ac8772 # master as of 2026-08-05 with: toolchain: "1.96.0" - - uses: astral-sh/setup-uv@v9.0.0 + - uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v9.0.0 with: enable-cache: true - - uses: actions/setup-python@v7 + - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 with: python-version: "3.13" diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 22663a3d0..a5f364ac9 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -36,17 +36,17 @@ jobs: runs-on: blacksmith-4vcpu-ubuntu-2404 steps: - name: Checkout - uses: actions/checkout@v7 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: fetch-depth: 0 - name: Install pnpm - uses: pnpm/action-setup@v4 + uses: pnpm/action-setup@b906affcce14559ad1aafd4ab0e942779e9f58b1 # v4.3.0 with: version: 10.26.2 - name: Set up Node - uses: actions/setup-node@v7 + uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: node-version: '22' cache: pnpm @@ -59,7 +59,7 @@ jobs: - name: Upload Pages artifact if: github.event_name != 'pull_request' - uses: actions/upload-pages-artifact@v5 + uses: actions/upload-pages-artifact@fc324d3547104276b827a68afc52ff2a11cc49c9 # v5.0.0 with: path: docs-site/dist/ @@ -76,4 +76,4 @@ jobs: steps: - name: Deploy to GitHub Pages id: deployment - uses: actions/deploy-pages@v5 + uses: actions/deploy-pages@cd2ce8fcbc39b97be8ca5fce6e763baed58fa128 # v5.0.0 \ No newline at end of file diff --git a/.github/workflows/fuzz.yml b/.github/workflows/fuzz.yml index 897fd5d07..7dc26bfff 100644 --- a/.github/workflows/fuzz.yml +++ b/.github/workflows/fuzz.yml @@ -23,10 +23,9 @@ jobs: RUSTUP_TOOLCHAIN: nightly steps: - name: Checkout code - uses: actions/checkout@v7 - + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Install Rust nightly - uses: dtolnay/rust-toolchain@nightly + uses: dtolnay/rust-toolchain@7c8d7d138f5c09cef361f8214cf96882cd029cdb # nightly as of 2026-08-05 with: components: clippy, rustfmt # Pin glibc: the prebuilt cargo-fuzz binary is musl-static, whose libc @@ -34,13 +33,13 @@ jobs: targets: x86_64-unknown-linux-gnu - name: Mount fuzz build disk - uses: useblacksmith/stickydisk@v1 + uses: useblacksmith/stickydisk@35ba2e331a80056a42af053ee54968511de2b7c7 # v1.5.0 with: key: ${{ github.repository }}-daily-fuzz-${{ hashFiles('fuzz/Cargo.toml', '**/Cargo.lock') }}-target-v1 path: fuzz/target - name: Cache Cargo registry - uses: actions/cache@v6 + uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: path: | ~/.cargo/registry @@ -50,7 +49,7 @@ jobs: ${{ runner.os }}-fuzz- - name: Install cargo-fuzz - uses: taiki-e/install-action@v2 + uses: taiki-e/install-action@6c6fd71fe4fb72c3697d269963d0e15df8adedad # v2.85.10 with: tool: cargo-fuzz diff --git a/.github/workflows/m1-release-certification.yml b/.github/workflows/m1-release-certification.yml index a060ae772..b62c9287e 100644 --- a/.github/workflows/m1-release-certification.yml +++ b/.github/workflows/m1-release-certification.yml @@ -33,7 +33,7 @@ jobs: outputs: evidence_sha: ${{ steps.source.outputs.evidence_sha }} steps: - - uses: actions/checkout@v7 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: ref: main fetch-depth: 1 @@ -104,7 +104,7 @@ jobs: CARGO_TARGET_DIR: ${{ github.workspace }}/target EVIDENCE_SHA: ${{ needs.validate_source.outputs.evidence_sha }} steps: - - uses: actions/checkout@v7 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: ref: ${{ needs.validate_source.outputs.evidence_sha }} - name: Verify immutable checkout @@ -112,21 +112,21 @@ jobs: run: | [[ "$EVIDENCE_SHA" =~ ^[0-9a-f]{40}$ ]] test "$(git rev-parse HEAD)" = "$EVIDENCE_SHA" - - uses: actions/setup-python@v7 + - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 with: python-version: "3.13" - - uses: astral-sh/setup-uv@v9.0.0 - - uses: actions/setup-node@v7 + - uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v9.0.0 + - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: node-version: "20" - - uses: pnpm/action-setup@v4 - - uses: dtolnay/rust-toolchain@master + - uses: pnpm/action-setup@b906affcce14559ad1aafd4ab0e942779e9f58b1 # v4.3.0 + - uses: dtolnay/rust-toolchain@6c977a6ca4077a0ceb28ffbe03f59d46e9ac8772 # master as of 2026-08-05 with: toolchain: "1.96.0" # Keep maturin + cargo + napi on one sticky volume so dense L/XL case # workspaces are not competing with a second root-disk Cargo tree (#2765). - name: Mount Cargo build disk - uses: useblacksmith/stickydisk@v1 + uses: useblacksmith/stickydisk@35ba2e331a80056a42af053ee54968511de2b7c7 # v1.5.0 with: # Per-certification workspace; cleanup_load_disk deletes it after load. key: ${{ github.repository }}-m1-release-load-${{ inputs.commit_sha }}-target-v3 @@ -134,7 +134,7 @@ jobs: - name: Install workspace dependencies run: pnpm install - name: Build one exact-SHA Python wheel - uses: PyO3/maturin-action@v1 + uses: PyO3/maturin-action@e83996d129638aa358a18fbd1dfb82f0b0fb5d3b # v1.51.0 with: command: build args: --release --manifest-path crates/graphforge-bindings-py/Cargo.toml --out dist @@ -200,7 +200,7 @@ jobs: python scripts/ci/release-load-matrix.py run \ --sha "$EVIDENCE_SHA" --work "$GF_LOAD_WORK" --output "$GF_LOAD_OUTPUT" - name: Retain load report for aggregate job - uses: actions/upload-artifact@v7 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: M1-Release-Load-${{ github.run_id }} path: m1-release-load-evidence @@ -214,7 +214,7 @@ jobs: runs-on: blacksmith-4vcpu-ubuntu-2404 steps: - name: Delete M1 certification build disk - uses: useblacksmith/stickydisk-delete@v1 + uses: useblacksmith/stickydisk-delete@b41313d28b8647d72114c9ba3c96bb04061562b6 # v1 with: delete-key: ${{ github.repository }}-m1-release-load-${{ inputs.commit_sha }}-target-v3 @@ -224,7 +224,7 @@ jobs: needs: [validate_source, load, cleanup_load_disk] runs-on: blacksmith-4vcpu-ubuntu-2404 steps: - - uses: actions/checkout@v7 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: ref: ${{ needs.validate_source.outputs.evidence_sha }} - name: Revalidate current main and component artifacts @@ -247,7 +247,7 @@ jobs: --expected-sha "$EXPECTED_SHA" \ --output evidence/component-validation-final/report.json - name: Download exact-run Rust evidence - uses: actions/download-artifact@v8 + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: name: M1-Rust-Non-Cypher-${{ needs.validate_source.outputs.evidence_sha }} path: non-cypher-evidence @@ -255,7 +255,7 @@ jobs: repository: ${{ github.repository }} run-id: ${{ inputs.rust_run_id }} - name: Download exact-run binding evidence - uses: actions/download-artifact@v8 + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: name: M1-Binding-Release-Candidate-${{ needs.validate_source.outputs.evidence_sha }} path: binding-rc-aggregate @@ -263,7 +263,7 @@ jobs: repository: ${{ github.repository }} run-id: ${{ inputs.binding_rc_run_id }} - name: Download exact-run load evidence - uses: actions/download-artifact@v8 + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 if: needs.load.result == 'success' with: name: M1-Release-Load-${{ github.run_id }} diff --git a/.github/workflows/m20-contract-gate.yml b/.github/workflows/m20-contract-gate.yml index 947b492e3..c4ec34f10 100644 --- a/.github/workflows/m20-contract-gate.yml +++ b/.github/workflows/m20-contract-gate.yml @@ -15,15 +15,15 @@ jobs: CARGO_INCREMENTAL: 0 CARGO_PROFILE_TEST_DEBUG: 0 steps: - - uses: actions/checkout@v7 - - uses: dtolnay/rust-toolchain@master + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + - uses: dtolnay/rust-toolchain@6c977a6ca4077a0ceb28ffbe03f59d46e9ac8772 # master as of 2026-08-05 with: toolchain: "1.96.0" - name: Execute Rust matrix group run: python3 scripts/ci/m20-contract-gate.py run-group --group rust --output gate-fragments - name: Save Rust evidence for report job if: always() - uses: actions/cache/save@v6 + uses: actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: path: gate-fragments/ key: m20-transfer-${{ github.run_id }}-rust @@ -33,18 +33,18 @@ jobs: runs-on: blacksmith-4vcpu-ubuntu-2404 timeout-minutes: 30 steps: - - uses: actions/checkout@v7 - - uses: astral-sh/setup-uv@v9.0.0 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + - uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v9.0.0 with: enable-cache: true - - uses: actions/setup-python@v7 + - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 with: python-version: "3.13" - name: Execute Python matrix group run: python3 scripts/ci/m20-contract-gate.py run-group --group python --output gate-fragments - name: Save Python evidence for report job if: always() - uses: actions/cache/save@v6 + uses: actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: path: gate-fragments/ key: m20-transfer-${{ github.run_id }}-python @@ -57,19 +57,19 @@ jobs: CARGO_INCREMENTAL: 0 CARGO_PROFILE_DEV_DEBUG: 0 steps: - - uses: actions/checkout@v7 - - uses: actions/setup-node@v7 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: node-version: "20" - - uses: pnpm/action-setup@v4 - - uses: dtolnay/rust-toolchain@master + - uses: pnpm/action-setup@b906affcce14559ad1aafd4ab0e942779e9f58b1 # v4.3.0 + - uses: dtolnay/rust-toolchain@6c977a6ca4077a0ceb28ffbe03f59d46e9ac8772 # master as of 2026-08-05 with: toolchain: "1.96.0" - name: Execute Node matrix group run: python3 scripts/ci/m20-contract-gate.py run-group --group node --output gate-fragments - name: Save Node evidence for report job if: always() - uses: actions/cache/save@v6 + uses: actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: path: gate-fragments/ key: m20-transfer-${{ github.run_id }}-node @@ -80,18 +80,18 @@ jobs: needs: [rust, python, node] runs-on: blacksmith-4vcpu-ubuntu-2404 steps: - - uses: actions/checkout@v7 - - uses: actions/cache/restore@v6 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + - uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: path: gate-fragments key: m20-transfer-${{ github.run_id }}-rust fail-on-cache-miss: true - - uses: actions/cache/restore@v6 + - uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: path: gate-fragments key: m20-transfer-${{ github.run_id }}-python fail-on-cache-miss: true - - uses: actions/cache/restore@v6 + - uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: path: gate-fragments key: m20-transfer-${{ github.run_id }}-node diff --git a/.github/workflows/m21-contract-gate.yml b/.github/workflows/m21-contract-gate.yml index 5dd1691c9..db5832211 100644 --- a/.github/workflows/m21-contract-gate.yml +++ b/.github/workflows/m21-contract-gate.yml @@ -15,15 +15,15 @@ jobs: CARGO_INCREMENTAL: 0 CARGO_PROFILE_TEST_DEBUG: 0 steps: - - uses: actions/checkout@v7 - - uses: dtolnay/rust-toolchain@master + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + - uses: dtolnay/rust-toolchain@6c977a6ca4077a0ceb28ffbe03f59d46e9ac8772 # master as of 2026-08-05 with: toolchain: "1.96.0" - name: Execute Rust matrix group run: python3 scripts/ci/m21-contract-gate.py run-group --group rust --output gate-fragments - name: Save Rust evidence for report job if: always() - uses: actions/cache/save@v6 + uses: actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: path: gate-fragments/ key: m21-transfer-${{ github.run_id }}-rust @@ -33,18 +33,18 @@ jobs: runs-on: blacksmith-4vcpu-ubuntu-2404 timeout-minutes: 35 steps: - - uses: actions/checkout@v7 - - uses: astral-sh/setup-uv@v9.0.0 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + - uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v9.0.0 with: enable-cache: true - - uses: actions/setup-python@v7 + - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 with: python-version: "3.13" - name: Execute Python matrix group run: python3 scripts/ci/m21-contract-gate.py run-group --group python --output gate-fragments - name: Save Python evidence for report job if: always() - uses: actions/cache/save@v6 + uses: actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: path: gate-fragments/ key: m21-transfer-${{ github.run_id }}-python @@ -57,19 +57,19 @@ jobs: CARGO_INCREMENTAL: 0 CARGO_PROFILE_DEV_DEBUG: 0 steps: - - uses: actions/checkout@v7 - - uses: actions/setup-node@v7 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: node-version: "20" - - uses: pnpm/action-setup@v4 - - uses: dtolnay/rust-toolchain@master + - uses: pnpm/action-setup@b906affcce14559ad1aafd4ab0e942779e9f58b1 # v4.3.0 + - uses: dtolnay/rust-toolchain@6c977a6ca4077a0ceb28ffbe03f59d46e9ac8772 # master as of 2026-08-05 with: toolchain: "1.96.0" - name: Execute Node matrix group run: python3 scripts/ci/m21-contract-gate.py run-group --group node --output gate-fragments - name: Save Node evidence for report job if: always() - uses: actions/cache/save@v6 + uses: actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: path: gate-fragments/ key: m21-transfer-${{ github.run_id }}-node @@ -80,18 +80,18 @@ jobs: needs: [rust, python, node] runs-on: blacksmith-4vcpu-ubuntu-2404 steps: - - uses: actions/checkout@v7 - - uses: actions/cache/restore@v6 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + - uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: path: gate-fragments key: m21-transfer-${{ github.run_id }}-rust fail-on-cache-miss: true - - uses: actions/cache/restore@v6 + - uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: path: gate-fragments key: m21-transfer-${{ github.run_id }}-python fail-on-cache-miss: true - - uses: actions/cache/restore@v6 + - uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: path: gate-fragments key: m21-transfer-${{ github.run_id }}-node diff --git a/.github/workflows/non-cypher-surface-gate.yml b/.github/workflows/non-cypher-surface-gate.yml index 03690a462..3794d5ac3 100644 --- a/.github/workflows/non-cypher-surface-gate.yml +++ b/.github/workflows/non-cypher-surface-gate.yml @@ -18,11 +18,11 @@ jobs: env: EVIDENCE_SHA: ${{ github.sha }} steps: - - uses: actions/checkout@v7 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: ref: ${{ env.EVIDENCE_SHA }} - - uses: dtolnay/rust-toolchain@master + - uses: dtolnay/rust-toolchain@6c977a6ca4077a0ceb28ffbe03f59d46e9ac8772 # master as of 2026-08-05 with: toolchain: stable @@ -142,7 +142,7 @@ jobs: PY - name: Retain Rust report for M1 certification - uses: actions/upload-artifact@v7 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: M1-Rust-Non-Cypher-${{ env.EVIDENCE_SHA }} path: non-cypher-evidence/ diff --git a/.github/workflows/pr-labeler.yml b/.github/workflows/pr-labeler.yml index 4c8676fc0..b3430a03d 100644 --- a/.github/workflows/pr-labeler.yml +++ b/.github/workflows/pr-labeler.yml @@ -18,7 +18,7 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v7 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: fetch-depth: 0 diff --git a/.github/workflows/publish-track.yml b/.github/workflows/publish-track.yml index d5a28a5be..d593ca7cb 100644 --- a/.github/workflows/publish-track.yml +++ b/.github/workflows/publish-track.yml @@ -41,7 +41,7 @@ jobs: release_sha: ${{ steps.source.outputs.release_sha }} release_version: ${{ steps.source.outputs.release_version }} steps: - - uses: actions/checkout@v7 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: ref: main fetch-depth: 1 @@ -119,11 +119,11 @@ jobs: actions: read contents: read steps: - - uses: actions/checkout@v7 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: ref: ${{ needs.resolve_source.outputs.release_sha }} - name: Download candidate manifest - uses: actions/download-artifact@v8 + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: name: M1-Release-Candidate-manifest-${{ needs.resolve_source.outputs.release_sha }} path: candidate @@ -131,7 +131,7 @@ jobs: github-token: ${{ github.token }} repository: ${{ github.repository }} - name: Download Python partition - uses: actions/download-artifact@v8 + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: name: M1-Release-Candidate-python-${{ needs.resolve_source.outputs.release_sha }} path: candidate/release-artifacts/python @@ -139,7 +139,7 @@ jobs: github-token: ${{ github.token }} repository: ${{ github.repository }} - name: Download npm partition - uses: actions/download-artifact@v8 + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: name: M1-Release-Candidate-npm-${{ needs.resolve_source.outputs.release_sha }} path: candidate/release-artifacts/npm @@ -147,7 +147,7 @@ jobs: github-token: ${{ github.token }} repository: ${{ github.repository }} - name: Download crates partition - uses: actions/download-artifact@v8 + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: name: M1-Release-Candidate-crates-${{ needs.resolve_source.outputs.release_sha }} path: candidate/release-artifacts/crates @@ -155,7 +155,7 @@ jobs: github-token: ${{ github.token }} repository: ${{ github.repository }} - name: Download evidence partition - uses: actions/download-artifact@v8 + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: name: M1-Release-Candidate-evidence-${{ needs.resolve_source.outputs.release_sha }} path: candidate/release-artifacts @@ -209,7 +209,7 @@ jobs: actions: read contents: write steps: - - uses: actions/checkout@v7 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: ref: main fetch-depth: 0 diff --git a/.github/workflows/publish.yaml b/.github/workflows/publish.yaml index a94029065..04fff63ec 100644 --- a/.github/workflows/publish.yaml +++ b/.github/workflows/publish.yaml @@ -32,7 +32,7 @@ jobs: manifest_name: ${{ steps.source.outputs.manifest_name }} release_tag: ${{ steps.source.outputs.release_tag }} steps: - - uses: actions/checkout@v7 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: ref: ${{ github.event_name == 'release' && github.event.release.tag_name || inputs.release_tag }} fetch-depth: 0 @@ -95,7 +95,7 @@ jobs: printf 'run_id=%s\n' "$run_id" >> "$GITHUB_OUTPUT" - name: Download candidate manifest - uses: actions/download-artifact@v8 + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: name: M1-Release-Candidate-manifest-${{ steps.source.outputs.release_sha }} path: candidate @@ -104,7 +104,7 @@ jobs: repository: ${{ github.repository }} - name: Download Python partition - uses: actions/download-artifact@v8 + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: name: M1-Release-Candidate-python-${{ steps.source.outputs.release_sha }} path: candidate/release-artifacts/python @@ -113,7 +113,7 @@ jobs: repository: ${{ github.repository }} - name: Download npm partition - uses: actions/download-artifact@v8 + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: name: M1-Release-Candidate-npm-${{ steps.source.outputs.release_sha }} path: candidate/release-artifacts/npm @@ -122,7 +122,7 @@ jobs: repository: ${{ github.repository }} - name: Download crates partition - uses: actions/download-artifact@v8 + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: name: M1-Release-Candidate-crates-${{ steps.source.outputs.release_sha }} path: candidate/release-artifacts/crates @@ -131,7 +131,7 @@ jobs: repository: ${{ github.repository }} - name: Download evidence partition - uses: actions/download-artifact@v8 + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: name: M1-Release-Candidate-evidence-${{ steps.source.outputs.release_sha }} path: candidate/release-artifacts @@ -211,10 +211,10 @@ jobs: contents: write id-token: write steps: - - uses: actions/checkout@v7 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: ref: ${{ needs.candidate-preflight.outputs.release_sha }} - - uses: astral-sh/setup-uv@v9.0.0 + - uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v9.0.0 - name: Download manifest and Python partition env: GH_TOKEN: ${{ github.token }} @@ -286,10 +286,10 @@ jobs: contents: write id-token: write steps: - - uses: actions/checkout@v7 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: ref: ${{ needs.candidate-preflight.outputs.release_sha }} - - uses: actions/setup-node@v7 + - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: node-version: "24" registry-url: https://registry.npmjs.org @@ -363,10 +363,10 @@ jobs: contents: write id-token: write steps: - - uses: actions/checkout@v7 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: ref: ${{ needs.candidate-preflight.outputs.release_sha }} - - uses: actions/setup-node@v7 + - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: node-version: "24" registry-url: https://registry.npmjs.org @@ -437,10 +437,10 @@ jobs: contents: write id-token: write steps: - - uses: actions/checkout@v7 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: ref: ${{ needs.candidate-preflight.outputs.release_sha }} - - uses: actions/setup-node@v7 + - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: node-version: "24" registry-url: https://registry.npmjs.org @@ -483,10 +483,10 @@ jobs: contents: write id-token: write steps: - - uses: actions/checkout@v7 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: ref: ${{ needs.candidate-preflight.outputs.release_sha }} - - uses: actions/setup-node@v7 + - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: node-version: "24" registry-url: https://registry.npmjs.org @@ -531,7 +531,7 @@ jobs: contents: write id-token: write steps: - - uses: actions/checkout@v7 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: ref: ${{ needs.candidate-preflight.outputs.release_sha }} - name: Use main-branch crates publisher for recovery @@ -555,7 +555,7 @@ jobs: git show refs/remotes/origin/main:scripts/ci/release_registry.py \ > "$RUNNER_TEMP/release_registry.py" install -m 0755 "$RUNNER_TEMP/release_registry.py" scripts/ci/release_registry.py - - uses: dtolnay/rust-toolchain@master + - uses: dtolnay/rust-toolchain@6c977a6ca4077a0ceb28ffbe03f59d46e9ac8772 # master as of 2026-08-05 with: toolchain: "1.96.0" - name: Download manifest and crates partition @@ -629,7 +629,7 @@ jobs: actions: read contents: read steps: - - uses: actions/checkout@v7 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: ref: ${{ needs.candidate-preflight.outputs.release_sha || github.sha }} - name: Download retained manifest when available @@ -679,7 +679,7 @@ jobs: jq '{complete, nodes: (.nodes | length), summary, jobs}' reconciliation/summary.json >> "$GITHUB_STEP_SUMMARY" - name: Retain reconciliation summary if: always() - uses: actions/upload-artifact@v7 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: M1-Release-Reconciliation-${{ github.run_id }} path: reconciliation/summary.json diff --git a/.github/workflows/release-credential-preflight.yml b/.github/workflows/release-credential-preflight.yml index a16485360..f25c55e33 100644 --- a/.github/workflows/release-credential-preflight.yml +++ b/.github/workflows/release-credential-preflight.yml @@ -16,7 +16,7 @@ jobs: name: Verify npm trusted-publishing contract runs-on: blacksmith-4vcpu-ubuntu-2404 steps: - - uses: actions/checkout@v7 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: ref: main fetch-depth: 1 diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index c4fcb4b62..b6fdf0658 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -27,7 +27,7 @@ jobs: bazel: ${{ steps.filter.outputs.bazel }} steps: - name: Checkout code - uses: actions/checkout@v7 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: fetch-depth: 0 @@ -51,7 +51,7 @@ jobs: needs: changes steps: - name: Checkout code - uses: actions/checkout@v7 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: fetch-depth: 0 @@ -129,14 +129,14 @@ jobs: python3 scripts/ci/api-bdd-policy.py --check-issues python3 scripts/ci/test-api-bdd-policy.py - - uses: actions/setup-node@v7 + - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 if: >- steps.policy-suites.outputs.release == 'true' || steps.policy-suites.outputs.cli_publish == 'true' with: node-version: "20" - - uses: pnpm/action-setup@v4 + - uses: pnpm/action-setup@b906affcce14559ad1aafd4ab0e942779e9f58b1 # v4.3.0 if: >- steps.policy-suites.outputs.release == 'true' || steps.policy-suites.outputs.cli_publish == 'true' @@ -202,12 +202,12 @@ jobs: run: python3 scripts/license_check.py --report license-compliance-report.json - name: Install Rust toolchain - uses: dtolnay/rust-toolchain@master + uses: dtolnay/rust-toolchain@6c977a6ca4077a0ceb28ffbe03f59d46e9ac8772 # master as of 2026-08-05 with: toolchain: "1.96.0" - name: Cache Cargo registry - uses: actions/cache@v6 + uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: path: | ~/.cargo/registry @@ -215,7 +215,7 @@ jobs: key: ${{ runner.os }}-cargo-registry-v1-${{ hashFiles('Cargo.lock') }} - name: Install cargo-deny and cargo-about - uses: taiki-e/install-action@v2 + uses: taiki-e/install-action@6c6fd71fe4fb72c3697d269963d0e15df8adedad # v2.85.10 with: tool: cargo-deny@0.20.2,cargo-about@0.9.1 @@ -235,15 +235,14 @@ jobs: if: needs.changes.outputs.python == 'true' steps: - name: Checkout code - uses: actions/checkout@v7 - + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Install uv - uses: astral-sh/setup-uv@v9.0.0 + uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v9.0.0 with: enable-cache: true - name: Set up Python - uses: actions/setup-python@v7 + uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 with: python-version: "3.13" @@ -271,13 +270,11 @@ jobs: if: needs.changes.outputs.gherkin == 'true' steps: - name: Checkout code - uses: actions/checkout@v7 - + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Install pnpm - uses: pnpm/action-setup@v4 - + uses: pnpm/action-setup@b906affcce14559ad1aafd4ab0e942779e9f58b1 # v4.3.0 - name: Set up Node - uses: actions/setup-node@v7 + uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: node-version: "20" cache: pnpm @@ -311,13 +308,11 @@ jobs: if: needs.changes.outputs.agent_skills == 'true' steps: - name: Checkout code - uses: actions/checkout@v7 - + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Install pnpm - uses: pnpm/action-setup@v4 - + uses: pnpm/action-setup@b906affcce14559ad1aafd4ab0e942779e9f58b1 # v4.3.0 - name: Set up Node - uses: actions/setup-node@v7 + uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: node-version: "20" cache: pnpm @@ -339,10 +334,9 @@ jobs: if: needs.changes.outputs.pulumi == 'true' steps: - name: Checkout code - uses: actions/checkout@v7 - + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Set up Node - uses: actions/setup-node@v7 + uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: node-version: "20" cache: npm @@ -356,12 +350,12 @@ jobs: npm run format:check - name: Install uv - uses: astral-sh/setup-uv@v9.0.0 + uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v9.0.0 with: enable-cache: true - name: Set up Python - uses: actions/setup-python@v7 + uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 with: python-version: "3.13" @@ -374,7 +368,7 @@ jobs: uv run ruff format --check . - name: Install Pulumi CLI - uses: pulumi/actions@v7 + uses: pulumi/actions@8e5e406f4007fca908480587cb9893c07090f58d # v7.0.0 with: pulumi-version: 3.254.0 @@ -388,10 +382,9 @@ jobs: if: needs.changes.outputs.terraform == 'true' steps: - name: Checkout code - uses: actions/checkout@v7 - + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Set up Go - uses: actions/setup-go@v7 + uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0 with: go-version: "1.25.x" cache-dependency-path: iac/terraform/provider/go.sum @@ -405,7 +398,7 @@ jobs: go vet ./... - name: Set up Terraform - uses: hashicorp/setup-terraform@v4 + uses: hashicorp/setup-terraform@dfe3c3f87815947d99a8997f908cb6525fc44e9e # v4.0.1 with: terraform_version: "1.11.4" terraform_wrapper: false @@ -426,17 +419,16 @@ jobs: timeout-minutes: 30 steps: - name: Checkout code - uses: actions/checkout@v7 - + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Install Rust toolchain - uses: dtolnay/rust-toolchain@master + uses: dtolnay/rust-toolchain@6c977a6ca4077a0ceb28ffbe03f59d46e9ac8772 # master as of 2026-08-05 with: toolchain: "1.96.0" components: clippy, rustfmt # No Cargo sticky disk after #4 cutover; fmt/clippy remain Cargo diagnostics. - name: Cache Cargo registry - uses: actions/cache@v6 + uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: path: | ~/.cargo/registry @@ -459,23 +451,21 @@ jobs: timeout-minutes: 30 steps: - name: Checkout code - uses: actions/checkout@v7 - + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Install uv - uses: astral-sh/setup-uv@v9.0.0 + uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v9.0.0 with: enable-cache: true - name: Set up Python - uses: actions/setup-python@v7 + uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 with: python-version: "3.13" - name: Install pnpm for cross-package publication tests - uses: pnpm/action-setup@v4 - + uses: pnpm/action-setup@b906affcce14559ad1aafd4ab0e942779e9f58b1 # v4.3.0 - name: Set up Node for cross-package publication tests - uses: actions/setup-node@v7 + uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: node-version: "20" @@ -485,7 +475,7 @@ jobs: # PR binding assembly still uses maturin for acceptance suites; sticky # Cargo target/ disks are retired after #4 (Binding RC retains sticky). - name: Cache Cargo build - uses: actions/cache@v6 + uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: path: | ~/.cargo/registry @@ -532,7 +522,7 @@ jobs: - name: Restore SNAP ego-Facebook fixture id: snap-fixture - uses: actions/cache@v6 + uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: path: ~/.graphforge/datasets/snap-ego-facebook.txt.gz key: ${{ runner.os }}-snap-ego-facebook-v1 @@ -591,7 +581,7 @@ jobs: --output dist/python-binding-parity-evidence.json - name: Upload same-SHA wheel for concurrency matrix - uses: actions/upload-artifact@v7 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: pr-python-wheel-${{ github.sha }} path: dist/*.whl @@ -611,27 +601,25 @@ jobs: CARGO_PROFILE_DEV_DEBUG: 0 steps: - name: Checkout code - uses: actions/checkout@v7 - + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Install pnpm - uses: pnpm/action-setup@v4 - + uses: pnpm/action-setup@b906affcce14559ad1aafd4ab0e942779e9f58b1 # v4.3.0 - name: Set up Node - uses: actions/setup-node@v7 + uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: node-version: "20" cache: pnpm cache-dependency-path: pnpm-lock.yaml - name: Install Rust toolchain - uses: dtolnay/rust-toolchain@master + uses: dtolnay/rust-toolchain@6c977a6ca4077a0ceb28ffbe03f59d46e9ac8772 # master as of 2026-08-05 with: toolchain: "1.96.0" # PR binding assembly still uses napi for acceptance suites; sticky # Cargo target/ disks are retired after #4 (Binding RC retains sticky). - name: Cache Cargo build - uses: actions/cache@v6 + uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: path: | ~/.cargo/registry @@ -684,7 +672,7 @@ jobs: --output crates/graphforge-bindings-node/node-binding-parity-evidence.json - name: Upload same-SHA addon for concurrency matrix - uses: actions/upload-artifact@v7 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: pr-node-addon-${{ github.sha }} path: | @@ -711,41 +699,39 @@ jobs: CARGO_PROFILE_DEV_DEBUG: 0 steps: - name: Checkout code - uses: actions/checkout@v7 - + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Install Rust toolchain - uses: dtolnay/rust-toolchain@master + uses: dtolnay/rust-toolchain@6c977a6ca4077a0ceb28ffbe03f59d46e9ac8772 # master as of 2026-08-05 with: toolchain: "1.96.0" - name: Install uv - uses: astral-sh/setup-uv@v9.0.0 + uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v9.0.0 with: enable-cache: true - name: Set up Python - uses: actions/setup-python@v7 + uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 with: python-version: "3.13" - name: Install pnpm - uses: pnpm/action-setup@v4 - + uses: pnpm/action-setup@b906affcce14559ad1aafd4ab0e942779e9f58b1 # v4.3.0 - name: Set up Node - uses: actions/setup-node@v7 + uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: node-version: "20" cache: pnpm cache-dependency-path: pnpm-lock.yaml - name: Download same-SHA Python wheel - uses: actions/download-artifact@v8 + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: name: pr-python-wheel-${{ github.sha }} path: dist - name: Download same-SHA Node addon - uses: actions/download-artifact@v8 + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: name: pr-node-addon-${{ github.sha }} path: crates/graphforge-bindings-node @@ -781,15 +767,14 @@ jobs: CARGO_PROFILE_TEST_DEBUG: 0 steps: - name: Checkout code - uses: actions/checkout@v7 - + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Install Rust toolchain - uses: dtolnay/rust-toolchain@master + uses: dtolnay/rust-toolchain@6c977a6ca4077a0ceb28ffbe03f59d46e9ac8772 # master as of 2026-08-05 with: toolchain: "1.96.0" - name: Cache Cargo registry - uses: actions/cache@v6 + uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: path: | ~/.cargo/registry @@ -813,14 +798,21 @@ jobs: timeout-minutes: 120 steps: - name: Checkout code - uses: actions/checkout@v7 - + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Install Bazelisk run: | - sudo curl -fsSL \ - "https://github.com/bazelbuild/bazelisk/releases/download/v1.26.0/bazelisk-linux-amd64" \ - -o /usr/local/bin/bazelisk - sudo chmod +x /usr/local/bin/bazelisk + version=1.26.0 + # SHA-256 of bazelisk-linux-amd64 from + # https://github.com/bazelbuild/bazelisk/releases/tag/v1.26.0 + # Computed locally: curl -fsSL … | shasum -a 256 + checksum=6539c12842ad76966f3d493e8f80d67caa84ec4a000e220d5459833c967c12bc + tmp=$(mktemp) + curl -fsSL \ + "https://github.com/bazelbuild/bazelisk/releases/download/v${version}/bazelisk-linux-amd64" \ + -o "$tmp" + printf '%s %s\n' "$checksum" "$tmp" | shasum -a 256 --check + sudo install -m 0755 "$tmp" /usr/local/bin/bazelisk + rm -f "$tmp" sudo ln -sf /usr/local/bin/bazelisk /usr/local/bin/bazel bazelisk version @@ -990,7 +982,7 @@ jobs: - name: Upload Cargo/Bazel parity evidence if: always() - uses: actions/upload-artifact@v7 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: cargo-bazel-parity-evidence-${{ github.run_id }} path: dist/cargo-bazel-parity-evidence.json @@ -999,7 +991,7 @@ jobs: - name: Upload Bazel cache/perf observation (#5) if: always() - uses: actions/upload-artifact@v7 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: bazel-cache-perf-evidence-${{ github.run_id }} path: | @@ -1032,8 +1024,7 @@ jobs: - bazel-bootstrap steps: - name: Checkout gate implementation - uses: actions/checkout@v7 - + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Require every applicable gate run: >- scripts/ci/require-gates.sh diff --git a/.github/workflows/visualization-limits-stress.yml b/.github/workflows/visualization-limits-stress.yml index 8541e1c1b..df9aa99f3 100644 --- a/.github/workflows/visualization-limits-stress.yml +++ b/.github/workflows/visualization-limits-stress.yml @@ -32,21 +32,20 @@ jobs: CARGO_INCREMENTAL: 0 CARGO_PROFILE_TEST_DEBUG: 0 steps: - - uses: actions/checkout@v7 - - - uses: dtolnay/rust-toolchain@master + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + - uses: dtolnay/rust-toolchain@6c977a6ca4077a0ceb28ffbe03f59d46e9ac8772 # master as of 2026-08-05 with: toolchain: "1.96.0" - - uses: astral-sh/setup-uv@v9.0.0 + - uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v9.0.0 with: enable-cache: true - - uses: actions/setup-python@v7 + - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 with: python-version: "3.13" - - uses: actions/setup-node@v7 + - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: node-version: "22" @@ -99,7 +98,7 @@ jobs: cp examples/visualization/stress/size_ladder.json examples/visualization/stress/results/ - name: Upload evidence artifact - uses: actions/upload-artifact@v7 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: visualization-limits-stress-${{ github.sha }} path: examples/visualization/stress/results/ diff --git a/scripts/ci/test-binding-release-candidate.py b/scripts/ci/test-binding-release-candidate.py index 89b0cca30..7306e5fbc 100644 --- a/scripts/ci/test-binding-release-candidate.py +++ b/scripts/ci/test-binding-release-candidate.py @@ -105,14 +105,23 @@ def required_section(text: str, start: str, end: str) -> str: def assert_active_lines(section: str, *expected: str) -> None: - """Require exact, non-commented workflow lines.""" + """Require exact, non-commented workflow lines. + + Expectations ending in ``@`` match any SHA-pinned ``uses: …@ # tag`` line + with that prefix (Dependabot-style action pins). + """ active = { line.strip() for line in section.splitlines() if line.strip() and not line.lstrip().startswith("#") } for line in expected: - assert line in active, f"missing active workflow line: {line}" + if line.endswith("@"): + assert any(entry.startswith(line) for entry in active), ( + f"missing active workflow line prefix: {line}" + ) + else: + assert line in active, f"missing active workflow line: {line}" def workflow_step(section: str, marker: str) -> str: @@ -132,14 +141,14 @@ def validate_python_evidence_policy(workflow_text: str) -> None: native_step = "Clean-install and execute native contract" write_step = "Write target evidence" stage_step = "Stage Python report for aggregate job" - transfer_step = "uses: actions/upload-artifact@v7" + transfer_step = "uses: actions/upload-artifact@" assert workflow_text.count(prepare_step) == 1 python_job = required_section(workflow_text, " python:\n", " node:\n") assert ( python_job.count("PYTHON_RC_EVIDENCE_DIR: ${{ runner.temp }}/graphforge-python-rc-evidence") == 4 ) - _, maturin_found, post_maturin = python_job.partition("uses: PyO3/maturin-action@v1") + _, maturin_found, post_maturin = python_job.partition("uses: PyO3/maturin-action@") assert maturin_found, "missing maturin build marker" assert ( post_maturin.index(prepare_step) @@ -234,10 +243,10 @@ def validate_windows_node_cold_start_policy(workflow_text: str) -> None: ) assert_active_lines(node_job, "timeout-minutes: ${{ matrix.timeout_minutes || 60 }}") - assert node_job.count("actions/cache@v6") == 1 - assert "actions/cache/restore@v6" not in node_job - assert "actions/cache/save@v6" not in node_job - assert node_job.count("actions/upload-artifact@v7") == 2 + assert node_job.count("actions/cache@") == 1 + assert "actions/cache/restore@" not in node_job + assert "actions/cache/save@" not in node_job + assert node_job.count("actions/upload-artifact@") == 2 assert_active_lines( node_job, "name: binding-rc-report-${{ github.run_id }}-${{ matrix.report_target }}", @@ -254,7 +263,7 @@ def validate_windows_node_cold_start_policy(workflow_text: str) -> None: ) assert "path: target" not in workflow_step(node_job, "name: Cache Cargo registry") assert "key: ${{ runner.os }}-cargo-registry-v1-${{ hashFiles('Cargo.lock') }}" in node_job - assert node_job.index("uses: dtolnay/rust-toolchain@master") < node_job.index( + assert node_job.index("uses: dtolnay/rust-toolchain@") < node_job.index( "Build declared publish target" ) @@ -282,7 +291,7 @@ def validate_windows_node_cold_start_policy(workflow_text: str) -> None: ) assert_active_lines( aggregate, - "uses: actions/download-artifact@v8", + "uses: actions/download-artifact@", "pattern: binding-rc-report-${{ github.run_id }}-*", "path: binding-rc-reports", "merge-multiple: true", @@ -385,7 +394,7 @@ def main() -> None: "duplicate Windows matrix entry", ) install_marker = " - name: Install workspace dependencies" - for cache_action in ("actions/cache/restore@v6", "actions/cache/save@v6"): + for cache_action in ("actions/cache/restore@", "actions/cache/save@"): injected = ( " - name: Unapproved Windows cache transfer\n" f" uses: {cache_action}\n" @@ -455,7 +464,7 @@ def main() -> None: prepare_marker = "Prepare writable Python RC evidence directory" native_marker = "Clean-install and execute native contract" write_marker = "Write target evidence" - transfer_marker = "uses: actions/upload-artifact@v7" + transfer_marker = "uses: actions/upload-artifact@" for marker, active_line in ( ( prepare_marker, @@ -506,11 +515,11 @@ def main() -> None: for marker in ( " python:\n", " node:\n", - "uses: PyO3/maturin-action@v1", + "uses: PyO3/maturin-action@", "Prepare writable Python RC evidence directory", "Clean-install and execute native contract", "Write target evidence", - "uses: actions/upload-artifact@v7", + "uses: actions/upload-artifact@", ): rejected_python_evidence_policy(rc_workflow_text.replace(marker, "", 1)) wrapper_step = "Prepare Rust compiler wrapper for native contracts" @@ -524,7 +533,7 @@ def main() -> None: < rc_workflow_text.index(target_step) < rc_workflow_text.index(native_step) ) - post_maturin_python = rc_workflow_text.split("uses: PyO3/maturin-action@v1", 1)[1].split( + post_maturin_python = rc_workflow_text.split("uses: PyO3/maturin-action@", 1)[1].split( " node:", 1 )[0] assert "CARGO_TARGET_DIR: ${{ github.workspace }}/target" in rc_workflow_text @@ -551,7 +560,7 @@ def main() -> None: assert "cargo test --release -p graphforge-storage" not in python_job assert "project_generation::tests::" not in python_job assert "Clean-install and execute native contract" in python_job - assert "uses: PyO3/maturin-action@v1" in python_job + assert "uses: PyO3/maturin-action@" in python_job test_workflow_text = (ROOT / ".github/workflows/test.yml").read_text() windows_locks_job = required_section( test_workflow_text, @@ -581,8 +590,8 @@ def main() -> None: assert "architecture: ${{ matrix.node_arch }}" in rc_workflow_text assert 'test "$(node -p \'process.arch\')" = "$EXPECTED_NODE_ARCH"' in rc_workflow_text assert "scripts/ci/prepare-rustc-wrapper.py" in rc_workflow_text - assert rc_workflow_text.count("uses: useblacksmith/stickydisk@v1") == 3 - assert rc_workflow_text.count("uses: actions/cache@v6") == 3 + assert rc_workflow_text.count("uses: useblacksmith/stickydisk@") == 3 + assert rc_workflow_text.count("uses: actions/cache@") == 3 shared_linux_key = ( "${{ github.repository }}-binding-rc-linux-rust-1.96.0-" "${{ hashFiles('Cargo.lock') }}-release-target-v1" diff --git a/scripts/ci/test-cargo-bazel-parity-check.py b/scripts/ci/test-cargo-bazel-parity-check.py index 44e22c582..d3ac4c59e 100644 --- a/scripts/ci/test-cargo-bazel-parity-check.py +++ b/scripts/ci/test-cargo-bazel-parity-check.py @@ -101,7 +101,7 @@ def main() -> None: real_run = mod.run - def fake_run(cmd, cwd=None): # noqa: ANN001 + def fake_run(cmd, cwd=None): if len(cmd) >= 3 and cmd[0] == "bazelisk" and cmd[1] == "query": # Empty suite → orphan label is missing. return subprocess.CompletedProcess(cmd, 0, stdout="", stderr="") diff --git a/scripts/ci/test-ci-storage-policy.py b/scripts/ci/test-ci-storage-policy.py index 269e692d6..37e47283e 100644 --- a/scripts/ci/test-ci-storage-policy.py +++ b/scripts/ci/test-ci-storage-policy.py @@ -35,8 +35,31 @@ from collections import Counter from pathlib import Path +import re ROOT = Path(__file__).resolve().parents[2] + +_SHA_RE = re.compile(r"^[0-9a-f]{40}$", re.IGNORECASE) + + +def uses_approved(uses: str | None, action: str, *tags: str) -> bool: + """Accept ``action@tag`` or Dependabot-style ``action@ # tag`` pins.""" + if uses is None: + return False + for tag in tags: + if uses == f"{action}@{tag}": + return True + prefix = f"{action}@" + if not uses.startswith(prefix) or "#" not in uses: + return False + ref, _, comment = uses.partition("#") + sha = ref[len(prefix) :].strip() + note = comment.strip().split()[0] if comment.strip() else "" + if not _SHA_RE.match(sha): + return False + return any(note == tag or note.startswith(f"{tag}.") for tag in tags) + + WORKFLOWS = ROOT / ".github" / "workflows" EXPECTED_ARTIFACT_UPLOADS = Counter( { @@ -206,7 +229,9 @@ def artifact_contracts(text: str) -> tuple[list[str], list[str]]: downloaded: list[str] = [] for step in action_steps(text, "actions/upload-artifact@"): uses = field(step, "uses") - assert uses == "actions/upload-artifact@v7", f"unapproved artifact action: {uses}" + assert uses_approved(uses, "actions/upload-artifact", "v7"), ( + f"unapproved artifact action: {uses}" + ) name = field(step, "name") assert name is not None, "artifact upload has no exact name" assert field(step, "if-no-files-found") == "error", ( @@ -251,7 +276,9 @@ def artifact_contracts(text: str) -> tuple[list[str], list[str]]: uploaded.append(name) for step in action_steps(text, "actions/download-artifact@"): uses = field(step, "uses") - assert uses == "actions/download-artifact@v8", f"unapproved artifact action: {uses}" + assert uses_approved(uses, "actions/download-artifact", "v8"), ( + f"unapproved artifact action: {uses}" + ) pattern = field(step, "pattern") name = field(step, "name") selector = pattern if pattern is not None else name @@ -334,12 +361,12 @@ def cache_contracts(text: str) -> tuple[list[str], list[str]]: uses = field(step, "uses") if uses is None or not uses.startswith("actions/cache/"): continue - assert uses in {"actions/cache/save@v6", "actions/cache/restore@v6"}, ( - f"unapproved cache transfer action: {uses}" - ) + assert uses_approved(uses, "actions/cache/save", "v6") or uses_approved( + uses, "actions/cache/restore", "v6" + ), f"unapproved cache transfer action: {uses}" key = field(step, "key") assert key is not None, f"{uses} step has no exact key" - if uses == "actions/cache/save@v6": + if uses_approved(uses, "actions/cache/save", "v6"): saved.append(key) else: assert field(step, "fail-on-cache-miss") == "true", f"restore is not fail-closed: {key}" @@ -350,8 +377,8 @@ def cache_contracts(text: str) -> tuple[list[str], list[str]]: def dependency_contracts(text: str) -> list[str]: keys: list[str] = [] for step in action_steps(text, "actions/cache@"): - assert field(step, "uses") == "actions/cache@v6", ( - "dependency cache must use actions/cache@v6" + assert uses_approved(field(step, "uses"), "actions/cache", "v6"), ( + "dependency cache must use actions/cache@v6 (tag or SHA pin)" ) key = field(step, "key") assert key is not None, "dependency cache has no exact key" @@ -371,11 +398,11 @@ def sticky_contracts(text: str) -> tuple[list[str], list[str]]: deleted: list[str] = [] for step in action_steps(text, "useblacksmith/stickydisk"): uses = field(step, "uses") - if uses == "useblacksmith/stickydisk@v1": + if uses_approved(uses, "useblacksmith/stickydisk", "v1"): key = field(step, "key") assert key is not None, "sticky disk has no exact key" mounted.append(key) - elif uses == "useblacksmith/stickydisk-delete@v1": + elif uses_approved(uses, "useblacksmith/stickydisk-delete", "v1"): key = field(step, "delete-key") assert key is not None, "sticky disk deletion has no exact key" deleted.append(key) @@ -386,7 +413,9 @@ def sticky_contracts(text: str) -> tuple[list[str], list[str]]: def validate_maturin_storage(text: str) -> None: for step in action_steps(text, "PyO3/maturin-action@"): - assert field(step, "uses") == "PyO3/maturin-action@v1", "unapproved Maturin action" + assert uses_approved(field(step, "uses"), "PyO3/maturin-action", "v1"), ( + "unapproved Maturin action" + ) sccache = field(step, "sccache") assert sccache is None or sccache.lower() == "false", ( "Maturin-action sccache:true uses the GitHub-integrated backend; " diff --git a/scripts/ci/test-m1-release-certification.py b/scripts/ci/test-m1-release-certification.py index 7cb33e961..99c2dbcb9 100644 --- a/scripts/ci/test-m1-release-certification.py +++ b/scripts/ci/test-m1-release-certification.py @@ -118,12 +118,12 @@ def test_workflow_is_manual_exact_main_and_validates_before_building(self) -> No load_job = jobs[load:aggregate] self.assertIn("needs: validate_source", load_job) self.assertIn("release-load-matrix.py run", load_job) - self.assertIn("useblacksmith/stickydisk@v1", load_job) + self.assertIn("useblacksmith/stickydisk@", load_job) self.assertIn( "${{ github.repository }}-m1-release-load-${{ inputs.commit_sha }}-target-v3", load_job, ) - self.assertIn("useblacksmith/stickydisk-delete@v1", load_job) + self.assertIn("useblacksmith/stickydisk-delete@", load_job) self.assertIn("needs: load", load_job) self.assertIn("CARGO_TARGET_DIR: ${{ github.workspace }}/target", load_job) self.assertIn("Reclaim sticky-disk ownership after maturin", load_job) @@ -154,8 +154,8 @@ def test_workflow_is_manual_exact_main_and_validates_before_building(self) -> No self.assertLess(rust_build, node_build) final_job = jobs[aggregate:] self.assertIn("Revalidate current main and component artifacts", final_job) - self.assertNotIn("actions/cache/restore@v6", final_job) - self.assertEqual(final_job.count("actions/download-artifact@v8"), 3) + self.assertNotIn("actions/cache/restore@", final_job) + self.assertEqual(final_job.count("actions/download-artifact@"), 3) self.assertIn("run-id: ${{ inputs.rust_run_id }}", final_job) self.assertIn("run-id: ${{ inputs.binding_rc_run_id }}", final_job) diff --git a/scripts/ci/test-publish-track.py b/scripts/ci/test-publish-track.py index 993406aab..82d4d840a 100644 --- a/scripts/ci/test-publish-track.py +++ b/scripts/ci/test-publish-track.py @@ -43,7 +43,7 @@ def section(text: str, start: str, end: str) -> str: assert "candidate_state=incomplete" in locate validate = section(workflow, " validate_candidate:\n", " dispatch_binding_rc:\n") -assert "actions/download-artifact@v8" in validate +assert "actions/download-artifact@" in validate for group in ("manifest", "python", "npm", "crates", "evidence"): assert ( f"M1-Release-Candidate-{group}-${{{{ needs.resolve_source.outputs.release_sha }}}}"