diff --git a/.github/workflows/audit.yml b/.github/workflows/audit.yml index 680dc11..1cced08 100644 --- a/.github/workflows/audit.yml +++ b/.github/workflows/audit.yml @@ -9,17 +9,24 @@ on: - '**/Cargo.lock' pull_request: +permissions: {} + jobs: audit: permissions: contents: read runs-on: ubuntu-latest steps: - - uses: actions/checkout@v5 - # Installs a prebuilt cargo-audit from the upstream GitHub releases. - # `actions-rs/audit-check` built it with `cargo install` instead, which - # broke once cargo-audit's dependencies outran the runner's toolchain. - - uses: taiki-e/install-action@v2 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false + # Installs a prebuilt cargo-audit from the upstream GitHub releases and + # verifies its SHA256 checksum. `actions-rs/audit-check` built it with + # `cargo install`, which broke once cargo-audit's dependencies outran the + # runner's toolchain. `fallback: none` keeps that compile path from + # silently coming back if the download ever fails. + - uses: taiki-e/install-action@5b4d68e2e660441203ab128a23676f1e4faf1532 # v2.86.3 with: tool: cargo-audit + fallback: none - run: cargo audit diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f77e08b..6515afb 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -26,7 +26,9 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout sources - uses: actions/checkout@v2 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false - name: Run cargo check run: cargo check @@ -35,7 +37,9 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout sources - uses: actions/checkout@v2 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false - name: Run cargo test with backtrace run: cargo test -- --nocapture @@ -48,7 +52,9 @@ jobs: RUSTFLAGS: '-Dwarnings' steps: - name: Checkout sources - uses: actions/checkout@v2 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false - name: Run cargo fmt run: cargo fmt --all -- --check diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 6ea7152..78ccf1a 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -56,7 +56,7 @@ jobs: env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 with: persist-credentials: false submodules: recursive @@ -66,7 +66,7 @@ jobs: shell: bash run: "curl --proto '=https' --tlsv1.2 -LsSf https://github.com/axodotdev/cargo-dist/releases/download/v0.30.3/cargo-dist-installer.sh | sh" - name: Cache dist - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 with: name: cargo-dist-cache path: ~/.cargo/bin/dist @@ -82,7 +82,7 @@ jobs: cat plan-dist-manifest.json echo "manifest=$(jq -c "." plan-dist-manifest.json)" >> "$GITHUB_OUTPUT" - name: "Upload dist-manifest.json" - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 with: name: artifacts-plan-dist-manifest path: plan-dist-manifest.json @@ -120,7 +120,7 @@ jobs: - name: enable windows longpaths run: | git config --global core.longpaths true - - uses: actions/checkout@v4 + - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 with: persist-credentials: false submodules: recursive @@ -135,7 +135,7 @@ jobs: run: ${{ matrix.install_dist.run }} # Get the dist-manifest - name: Fetch local artifacts - uses: actions/download-artifact@v4 + uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 with: pattern: artifacts-* path: target/distrib/ @@ -149,7 +149,7 @@ jobs: dist build ${{ needs.plan.outputs.tag-flag }} --print=linkage --output-format=json ${{ matrix.dist_args }} > dist-manifest.json echo "dist ran successfully" - name: Attest - uses: actions/attest-build-provenance@v2 + uses: actions/attest-build-provenance@e8998f949152b193b063cb0ec769d69d929409be with: subject-path: "target/distrib/*${{ join(matrix.targets, ', ') }}*" - id: cargo-dist @@ -166,7 +166,7 @@ jobs: cp dist-manifest.json "$BUILD_MANIFEST_NAME" - name: "Upload artifacts" - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 with: name: artifacts-build-local-${{ join(matrix.targets, '_') }} path: | @@ -183,19 +183,19 @@ jobs: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} BUILD_MANIFEST_NAME: target/distrib/global-dist-manifest.json steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 with: persist-credentials: false submodules: recursive - name: Install cached dist - uses: actions/download-artifact@v4 + uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 with: name: cargo-dist-cache path: ~/.cargo/bin/ - run: chmod +x ~/.cargo/bin/dist # Get all the local artifacts for the global tasks to use (for e.g. checksums) - name: Fetch local artifacts - uses: actions/download-artifact@v4 + uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 with: pattern: artifacts-* path: target/distrib/ @@ -213,7 +213,7 @@ jobs: cp dist-manifest.json "$BUILD_MANIFEST_NAME" - name: "Upload artifacts" - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 with: name: artifacts-build-global path: | @@ -233,19 +233,19 @@ jobs: outputs: val: ${{ steps.host.outputs.manifest }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 with: persist-credentials: false submodules: recursive - name: Install cached dist - uses: actions/download-artifact@v4 + uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 with: name: cargo-dist-cache path: ~/.cargo/bin/ - run: chmod +x ~/.cargo/bin/dist # Fetch artifacts from scratch-storage - name: Fetch artifacts - uses: actions/download-artifact@v4 + uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 with: pattern: artifacts-* path: target/distrib/ @@ -258,14 +258,14 @@ jobs: cat dist-manifest.json echo "manifest=$(jq -c "." dist-manifest.json)" >> "$GITHUB_OUTPUT" - name: "Upload dist-manifest.json" - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 with: # Overwrite the previous copy name: artifacts-dist-manifest path: dist-manifest.json # Create a GitHub Release while uploading all files to it - name: "Download GitHub Artifacts" - uses: actions/download-artifact@v4 + uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 with: pattern: artifacts-* path: artifacts @@ -298,7 +298,7 @@ jobs: env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 with: persist-credentials: false submodules: recursive diff --git a/.github/workflows/zizmor.yml b/.github/workflows/zizmor.yml new file mode 100644 index 0000000..e911917 --- /dev/null +++ b/.github/workflows/zizmor.yml @@ -0,0 +1,23 @@ +name: GitHub Actions Security Analysis + +on: + push: + branches: [main] + pull_request: + branches: ["**"] + +permissions: {} + +jobs: + zizmor: + runs-on: ubuntu-latest + permissions: + security-events: write + contents: read + actions: read + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false + - name: Run zizmor + uses: zizmorcore/zizmor-action@6fc4b006235f201fdab3722e17240ab420d580e5 # v0.6.1 diff --git a/.github/zizmor.yml b/.github/zizmor.yml new file mode 100644 index 0000000..19c0fdd --- /dev/null +++ b/.github/zizmor.yml @@ -0,0 +1,33 @@ +# Configuration for the zizmor GitHub Actions security linter. +# See https://docs.zizmor.sh/configuration/ +# +# Everything ignored below is in release.yml, which is autogenerated by dist +# (cargo-dist) from dist-workspace.toml -- see the header comment in that file. +# Editing release.yml by hand does not work: the next `dist generate` overwrites +# it. Where dist offers a knob we use it (the actions in release.yml are pinned +# to commits via [dist.github-action-commits] in dist-workspace.toml), and what +# is left below is inherent to dist's template and has no such knob. +# +# These are deliberately file-scoped rather than line-scoped, because line +# numbers shift whenever release.yml is regenerated. +rules: + excessive-permissions: + ignore: + # dist declares `contents: write` at the workflow level because the + # announce job creates the GitHub Release. Narrowing it per-job is + # dist's call, not ours. + - release.yml + template-injection: + ignore: + # dist interpolates `github.ref_name`, `needs.plan.outputs.tag*` and its + # `matrix.*` build parameters straight into run blocks. The tag-derived + # values only expand on `push:` of a tag, which requires push access, and + # expand to '' on pull_request. The matrix values come from dist's own + # plan output, not from user input. + - release.yml + unpinned-images: + ignore: + # `container: ${{ matrix.container && matrix.container.image || null }}`. + # This repo configures no custom container runners, so matrix.container is + # always null and no image is ever pulled. + - release.yml diff --git a/dist-workspace.toml b/dist-workspace.toml index a719571..138620e 100644 --- a/dist-workspace.toml +++ b/dist-workspace.toml @@ -24,3 +24,14 @@ install-path = "CARGO_HOME" install-updater = false # Link build artifacts to the process which created it github-attestations = true + +# Pin the GitHub Actions that dist generates into release.yml to exact commits +# rather than floating tags, so a compromised or retagged upstream release can't +# silently change what runs. Keep these on the same major version that dist +# 0.30.3 generates; bump the SHA and the trailing version comment together. +# Docs: https://axodotdev.github.io/cargo-dist/book/ci/customizing.html#pinned-actions-commits +[dist.github-action-commits] +"actions/checkout" = "11d5960a326750d5838078e36cf38b85af677262" # v4.4.0 +"actions/upload-artifact" = "ea165f8d65b6e75b540449e92b4886f43607fa02" # v4.6.2 +"actions/download-artifact" = "d3f86a106a0bac45b974a628896c90dbdf5c8093" # v4.3.0 +"actions/attest-build-provenance" = "e8998f949152b193b063cb0ec769d69d929409be" # v2.4.0