From f381690d134e65c7381a537be8e6c7129994c78b Mon Sep 17 00:00:00 2001 From: Brandon Cook Date: Wed, 17 Jun 2026 11:39:12 +1000 Subject: [PATCH] ci: SHA-pin actions, scope permissions, add Dependabot Harden the GitHub Actions supply chain without changing any CI logic: - Pin every action reference in .github/workflows/* to a full commit SHA with a trailing `# vX.Y.Z` version comment (checkout v4.3.1, setup-go v5.6.0, setup-tinygo v2.0.1, setup-node v4.4.0, goreleaser-action v6.4.0, changesets/action v1.9.0, dtolnay/rust-toolchain @stable head). SHAs were resolved via the GitHub API for the tag each workflow used. - Add a least-privilege top-level `permissions: { contents: read }` block to ci.yml and govulncheck.yml (release.yml and release-cli.yml already scope their own; their privileged steps use the KIT_RELEASE_TOKEN PAT, so no job needs GITHUB_TOKEN widened). - Add .github/dependabot.yml covering the gomod and github-actions ecosystems (weekly), so the SHA pins are kept current automatically. - TinyGo stays pinned at 0.41.1. binaryen's apt install is left at the runner's candidate (documented inline): a literal apt version pin hard-fails whenever ubuntu-latest's candidate moves. Verified: actionlint clean on all four workflows. Co-Authored-By: Claude Opus 4.8 --- .github/dependabot.yml | 16 +++++++++++++ .github/workflows/ci.yml | 37 ++++++++++++++++++++----------- .github/workflows/govulncheck.yml | 7 ++++-- .github/workflows/release-cli.yml | 6 ++--- .github/workflows/release.yml | 6 ++--- 5 files changed, 51 insertions(+), 21 deletions(-) create mode 100644 .github/dependabot.yml diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..41ae3dd --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,16 @@ +version: 2 +updates: + # Go module dependencies (go.mod / go.sum). + - package-ecosystem: "gomod" + directory: "/" + schedule: + interval: "weekly" + open-pull-requests-limit: 5 + + # GitHub Actions are SHA-pinned in .github/workflows/*; Dependabot bumps the + # pin (and the trailing `# vX.Y.Z` comment) when a new release lands. + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" + open-pull-requests-limit: 5 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d28f7e3..c75d5d1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -8,12 +8,15 @@ on: # Nightly (07:00 UTC): keep the slow release-profile artifact path honest. - cron: "0 7 * * *" +permissions: + contents: read + jobs: test: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 - - uses: actions/setup-go@v5 + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 + - uses: actions/setup-go@40f1582b2485089dde7abd97c1529aa768e1baff # v5.6.0 with: { go-version-file: go.mod } - run: go build ./... - run: go vet ./... @@ -47,12 +50,16 @@ jobs: wasm: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 with: { path: kit } - - uses: actions/setup-go@v5 + - uses: actions/setup-go@40f1582b2485089dde7abd97c1529aa768e1baff # v5.6.0 with: { go-version-file: kit/go.mod } - - uses: acifani/setup-tinygo@v2 + - uses: acifani/setup-tinygo@db56321a62b9a67922bb9ac8f9d085e218807bb3 # v2.0.1 with: { tinygo-version: "0.41.1" } + # binaryen is intentionally left at the runner's apt candidate: pinning a + # literal apt version (binaryen=) hard-fails the install whenever the + # ubuntu-latest image ships a different candidate. TinyGo (the artifact + # toolchain that actually shapes the wasm) is the pinned input above. - run: sudo apt-get update && sudo apt-get install -y binaryen - name: build shellcade-kit from this PR's source run: | @@ -84,11 +91,11 @@ jobs: wasm-rust: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 with: { path: kit } - - uses: dtolnay/rust-toolchain@stable + - uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable with: { targets: wasm32-wasip1 } - - uses: actions/setup-go@v5 + - uses: actions/setup-go@40f1582b2485089dde7abd97c1529aa768e1baff # v5.6.0 with: { go-version-file: kit/go.mod } - name: build shellcade-kit from this PR's source run: | @@ -117,8 +124,8 @@ jobs: rust: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 - - uses: dtolnay/rust-toolchain@stable + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 + - uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable with: { targets: wasm32-wasip1 } - name: crate version == kit version (lockstep) run: | @@ -144,12 +151,16 @@ jobs: if: github.event_name == 'schedule' || startsWith(github.ref, 'refs/tags/') runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 with: { path: kit } - - uses: actions/setup-go@v5 + - uses: actions/setup-go@40f1582b2485089dde7abd97c1529aa768e1baff # v5.6.0 with: { go-version-file: kit/go.mod } - - uses: acifani/setup-tinygo@v2 + - uses: acifani/setup-tinygo@db56321a62b9a67922bb9ac8f9d085e218807bb3 # v2.0.1 with: { tinygo-version: "0.41.1" } + # binaryen is intentionally left at the runner's apt candidate: pinning a + # literal apt version (binaryen=) hard-fails the install whenever the + # ubuntu-latest image ships a different candidate. TinyGo (the artifact + # toolchain that actually shapes the wasm) is the pinned input above. - run: sudo apt-get update && sudo apt-get install -y binaryen - name: build shellcade-kit from this PR's source run: | diff --git a/.github/workflows/govulncheck.yml b/.github/workflows/govulncheck.yml index 658b4f0..6d80249 100644 --- a/.github/workflows/govulncheck.yml +++ b/.github/workflows/govulncheck.yml @@ -9,12 +9,15 @@ on: # that actually catches them. - cron: "30 7 * * *" +permissions: + contents: read + jobs: govulncheck: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 - - uses: actions/setup-go@v5 + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 + - uses: actions/setup-go@40f1582b2485089dde7abd97c1529aa768e1baff # v5.6.0 with: { go-version-file: go.mod } # Deliberately unpinned: vuln scanning wants the current tool and the # current database, unlike the reproducible build toolchain above. diff --git a/.github/workflows/release-cli.yml b/.github/workflows/release-cli.yml index 6edc4d3..6000961 100644 --- a/.github/workflows/release-cli.yml +++ b/.github/workflows/release-cli.yml @@ -22,13 +22,13 @@ jobs: goreleaser: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 with: fetch-depth: 0 ref: ${{ github.event.inputs.tag || github.ref_name }} - - uses: actions/setup-go@v5 + - uses: actions/setup-go@40f1582b2485089dde7abd97c1529aa768e1baff # v5.6.0 with: { go-version-file: go.mod } - - uses: goreleaser/goreleaser-action@v6 + - uses: goreleaser/goreleaser-action@e435ccd777264be153ace6237001ef4d979d3a7a # v6.4.0 with: distribution: goreleaser version: "~> v2" diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 405b0ed..bdc4053 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -13,7 +13,7 @@ jobs: release: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 # The tag push in scripts/tag-release.sh must use a PAT, not the # default GITHUB_TOKEN: GitHub does NOT fire workflow triggers for tags # pushed with GITHUB_TOKEN, so the downstream GoReleaser/Homebrew/notify @@ -22,13 +22,13 @@ jobs: with: fetch-depth: 0 token: ${{ secrets.KIT_RELEASE_TOKEN }} - - uses: actions/setup-node@v4 + - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 with: { node-version: 22 } - run: npm ci # With pending changesets: opens/updates the "Version Packages" PR. # With none (the PR just merged): runs the publish script, which pushes # the vX.Y.Z tag — and the tag triggers the GoReleaser workflow. - - uses: changesets/action@v1 + - uses: changesets/action@a45c4d594aa4e2c509dc14a9f2b3b67ba3780d0d # v1.9.0 with: version: npm run version # changeset version + sync rust/Cargo.toml (lockstep) publish: npm run release