From 0963a9b50923952a5c17c07cd539241ad5baf049 Mon Sep 17 00:00:00 2001 From: Thib_C Date: Thu, 22 Oct 2026 17:31:24 +0200 Subject: [PATCH 1/4] ci: lock workflow actions and verify the lockfile on PRs Onboard every workflow to .github/workflows/actions.lock with gh actions-lock: it records each action's commit, owner and repository ids, and the actions it calls in turn. The lockfile now holds the pins, so `uses:` refs move from SHAs to the exact tags they pointed to; every locked commit equals the previous SHA pin. The new Lockfile workflow runs `gh actions-lock --verify` on pull requests and pushes to main. Co-Authored-By: Claude Opus 5.5 --- .github/workflows/actions.lock | 146 +++++++++++++++++++++++++ .github/workflows/ci.yml | 24 ++-- .github/workflows/claude-pr-checks.yml | 12 +- .github/workflows/codeql.yml | 10 +- .github/workflows/install-channels.yml | 2 +- .github/workflows/plumber-action.yml | 8 +- .github/workflows/propagate.yml | 8 +- .github/workflows/release.yml | 44 ++++---- .github/workflows/scorecard.yml | 8 +- .github/workflows/scripts-test.yml | 2 +- .github/workflows/verify-lockfile.yml | 36 ++++++ 11 files changed, 241 insertions(+), 59 deletions(-) create mode 100644 .github/workflows/actions.lock create mode 100644 .github/workflows/verify-lockfile.yml diff --git a/.github/workflows/actions.lock b/.github/workflows/actions.lock new file mode 100644 index 00000000..af1f0291 --- /dev/null +++ b/.github/workflows/actions.lock @@ -0,0 +1,146 @@ +# This file is machine-generated by `gh actions-lock`. +# Do not edit by hand; run `gh actions-lock` to update. +# Docs: https://gh.io/actions-lockfile +version: 'v0.0.3' +workflows: + '.github/workflows/ci.yml': + - 'actions/checkout@v7.0.1' + - 'actions/setup-go@v7.0.0' + - 'actions/upload-artifact@v7.0.2' + '.github/workflows/claude-pr-checks.yml': + - 'actions/checkout@v7.0.1' + - 'actions/download-artifact@v8.0.2' + - 'actions/github-script@v9.0.0' + - 'actions/upload-artifact@v7.0.2' + - 'anthropics/claude-code-action@v1.0.252' + '.github/workflows/codeql.yml': + - 'actions/checkout@v7.0.1' + - 'actions/setup-go@v7.0.0' + - 'github/codeql-action@v4.39.0' + '.github/workflows/install-channels.yml': + - 'actions/setup-go@v7.0.0' + '.github/workflows/plumber-action.yml': + - 'actions/checkout@v7.0.1' + - 'actions/setup-go@v7.0.0' + - 'actions/upload-artifact@v7.0.2' + - 'github/codeql-action@v4.39.0' + '.github/workflows/propagate.yml': + - 'actions/checkout@v7.0.1' + - 'actions/create-github-app-token@v3.3.0' + '.github/workflows/release.yml': + - 'actions/attest-build-provenance@v4.2.2' + - 'actions/checkout@v7.0.1' + - 'actions/create-github-app-token@v3.3.0' + - 'actions/download-artifact@v8.0.2' + - 'actions/setup-go@v7.0.0' + - 'actions/setup-node@v7.1.0' + - 'actions/upload-artifact@v7.0.2' + - 'docker/build-push-action@v7.4.0' + - 'docker/login-action@v4.6.0' + - 'docker/metadata-action@v6.2.0' + - 'docker/setup-buildx-action@v4.4.1' + - 'docker/setup-qemu-action@v4.4.0' + '.github/workflows/scorecard.yml': + - 'actions/checkout@v7.0.1' + - 'actions/upload-artifact@v7.0.2' + - 'github/codeql-action@v4.39.0' + - 'ossf/scorecard-action@v2.5.0' + '.github/workflows/scripts-test.yml': + - 'actions/checkout@v7.0.1' + '.github/workflows/verify-lockfile.yml': + - 'actions/checkout@v7.0.1' +dependencies: + 'actions/attest-build-provenance@v4.2.2': + ref: 'v4.2.2' + commit: 'sha1-4d101475d8b20a2381f78447822ac1eab6504dd8' + owner_id: 44036562 + repo_id: 760702757 + uses: + - 'actions/attest@508db95dd578ae2727ebd6217d5ba78e4fbda05d' + 'actions/attest@508db95dd578ae2727ebd6217d5ba78e4fbda05d': + ref: 'v4.2.1' + commit: 'sha1-508db95dd578ae2727ebd6217d5ba78e4fbda05d' + owner_id: 44036562 + repo_id: 760701061 + 'actions/checkout@v7.0.1': + ref: 'v7.0.1' + commit: 'sha1-3d3c42e5aac5ba805825da76410c181273ba90b1' + owner_id: 44036562 + repo_id: 197814629 + 'actions/create-github-app-token@v3.3.0': + ref: 'v3.3.0' + commit: 'sha1-64ab729a6294000f5aa4a4bc0b73d1f32bc45510' + owner_id: 44036562 + repo_id: 642580244 + 'actions/download-artifact@v8.0.2': + ref: 'v8.0.2' + commit: 'sha1-9000827ccba6bdab643e8b6fd33ac0654aef8333' + owner_id: 44036562 + repo_id: 192626254 + 'actions/github-script@v9.0.0': + ref: 'v9.0.0' + commit: 'sha1-3a2844b7e9c422d3c10d287c895573f7108da1b3' + owner_id: 44036562 + repo_id: 205262760 + 'actions/setup-go@v7.0.0': + ref: 'v7.0.0' + commit: 'sha1-b7ad1dad31e06c5925ef5d2fc7ad053ef454303e' + owner_id: 44036562 + repo_id: 192624594 + 'actions/setup-node@v7.1.0': + ref: 'v7.1.0' + commit: 'sha1-949feb2413d6458794dcd2491c4babbbce0c15c1' + owner_id: 44036562 + repo_id: 189476904 + 'actions/upload-artifact@v7.0.2': + ref: 'v7.0.2' + commit: 'sha1-cf430e030ddbb5b0abf93d22962f4752f3646cd9' + owner_id: 44036562 + repo_id: 192625955 + 'anthropics/claude-code-action@v1.0.252': + ref: 'v1.0.252' + commit: 'sha1-f27be6b65a4652f08a2ba3cff79114829b588967' + owner_id: 76263028 + repo_id: 986421638 + uses: + - 'oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6' + 'docker/build-push-action@v7.4.0': + ref: 'v7.4.0' + commit: 'sha1-c3c9e263c25d99ce0380d002d59b67737d91b0dc' + owner_id: 5429470 + repo_id: 241092383 + 'docker/login-action@v4.6.0': + ref: 'v4.6.0' + commit: 'sha1-dbcb813823bdd20940b903addbd779551569679f' + owner_id: 5429470 + repo_id: 287743349 + 'docker/metadata-action@v6.2.0': + ref: 'v6.2.0' + commit: 'sha1-dc802804100637a589fabce1cb79ff13a1411302' + owner_id: 5429470 + repo_id: 306769011 + 'docker/setup-buildx-action@v4.4.1': + ref: 'v4.4.1' + commit: 'sha1-f87e5991a6d7451dcb8d9637bfbc97413f497069' + owner_id: 5429470 + repo_id: 288485773 + 'docker/setup-qemu-action@v4.4.0': + ref: 'v4.4.0' + commit: 'sha1-99012661954931238ded8c8b007157a8430204e1' + owner_id: 5429470 + repo_id: 288487894 + 'github/codeql-action@v4.39.0': + ref: 'v4.39.0' + commit: 'sha1-6f2ac81f5cd81fe351a197ba0b00d91d03cd2aee' + owner_id: 9919 + repo_id: 259445878 + 'ossf/scorecard-action@v2.5.0': + ref: 'v2.5.0' + commit: 'sha1-fa7117db83c52d787ae5a89f350999701505d78e' + owner_id: 67707773 + repo_id: 421101922 + 'oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6': + ref: 'v2.2.0' + commit: 'sha1-0c5077e51419868618aeaa5fe8019c62421857d6' + owner_id: 108928776 + repo_id: 512644635 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 55671632..5e9f16e8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -26,11 +26,11 @@ jobs: # advisories); 1.26.10 matches the pinned toolchain. go-version: ['1.26.10', '1.26.0'] steps: - - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + - uses: actions/checkout@v7.0.1 with: persist-credentials: false - - uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0 + - uses: actions/setup-go@v7.0.0 with: go-version: ${{ matrix.go-version }} @@ -41,11 +41,11 @@ jobs: name: Build from committed tree runs-on: ubuntu-24.04 steps: - - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + - uses: actions/checkout@v7.0.1 with: persist-credentials: false - - uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0 + - uses: actions/setup-go@v7.0.0 with: go-version: '1.26.10' @@ -66,11 +66,11 @@ jobs: name: Test runs-on: ubuntu-24.04 steps: - - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + - uses: actions/checkout@v7.0.1 with: persist-credentials: false - - uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0 + - uses: actions/setup-go@v7.0.0 with: go-version: '1.26.10' @@ -78,7 +78,7 @@ jobs: run: go test ./... -race -timeout 30m -coverprofile=coverage.out -covermode=atomic - name: Upload coverage artifact - uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2 + uses: actions/upload-artifact@v7.0.2 with: name: coverage path: coverage.out @@ -88,11 +88,11 @@ jobs: name: Lint runs-on: ubuntu-24.04 steps: - - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + - uses: actions/checkout@v7.0.1 with: persist-credentials: false - - uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0 + - uses: actions/setup-go@v7.0.0 with: go-version: '1.26.10' @@ -143,11 +143,11 @@ jobs: name: Govulncheck runs-on: ubuntu-24.04 steps: - - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + - uses: actions/checkout@v7.0.1 with: persist-credentials: false - - uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0 + - uses: actions/setup-go@v7.0.0 with: go-version: '1.26.10' @@ -164,7 +164,7 @@ jobs: name: Container Scan runs-on: ubuntu-24.04 steps: - - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + - uses: actions/checkout@v7.0.1 with: persist-credentials: false diff --git a/.github/workflows/claude-pr-checks.yml b/.github/workflows/claude-pr-checks.yml index 662ea04e..84d1596f 100644 --- a/.github/workflows/claude-pr-checks.yml +++ b/.github/workflows/claude-pr-checks.yml @@ -60,7 +60,7 @@ jobs: prompt_file: .github/claude-prompts/new-control-check.md steps: - name: Checkout - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + uses: actions/checkout@v7.0.1 with: # Check out the PR head (not the default merge ref) so the files and # line numbers the agent sees match head.sha, which review comments @@ -84,7 +84,7 @@ jobs: # finishes without calling the structured-output tool, and a review # with zero findings reliably ends exactly that way. continue-on-error: true - uses: anthropics/claude-code-action@f27be6b65a4652f08a2ba3cff79114829b588967 # v1.0.252 + uses: anthropics/claude-code-action@v1.0.252 with: anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }} # Without this the action exchanges an OIDC token for a GitHub App @@ -222,7 +222,7 @@ jobs: - name: Upload report if: steps.review.outputs.structured_output != '' - uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2 + uses: actions/upload-artifact@v7.0.2 with: name: claude-review-${{ matrix.control }} path: ${{ runner.temp }}/report-${{ matrix.control }}.json @@ -251,7 +251,7 @@ jobs: # download-artifact — checkout's clean step would otherwise wipe the # downloaded reports/ directory. - name: Checkout - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + uses: actions/checkout@v7.0.1 with: fetch-depth: 1 persist-credentials: false @@ -262,14 +262,14 @@ jobs: # "control did not complete". - name: Download reports continue-on-error: true - uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2 + uses: actions/download-artifact@v8.0.2 with: pattern: claude-review-* merge-multiple: true path: reports - name: Post finding comments - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 + uses: actions/github-script@v9.0.0 env: # Used only for the semantic dedup pass below. This step # never handles untrusted PR content directly (the review agents do, diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index c0c082ac..bf9cab9e 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -23,16 +23,16 @@ jobs: security-events: write contents: read steps: - - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + - uses: actions/checkout@v7.0.1 with: persist-credentials: false - - uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0 + - uses: actions/setup-go@v7.0.0 with: go-version: '1.26.10' - name: Initialize CodeQL - uses: github/codeql-action/init@6f2ac81f5cd81fe351a197ba0b00d91d03cd2aee # v4.39.0 + uses: github/codeql-action/init@v4.39.0 with: languages: go # Without this, the CodeQL bundle version is resolved from @@ -42,7 +42,7 @@ jobs: tools: linked - name: Autobuild - uses: github/codeql-action/autobuild@6f2ac81f5cd81fe351a197ba0b00d91d03cd2aee # v4.39.0 + uses: github/codeql-action/autobuild@v4.39.0 - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@6f2ac81f5cd81fe351a197ba0b00d91d03cd2aee # v4.39.0 + uses: github/codeql-action/analyze@v4.39.0 diff --git a/.github/workflows/install-channels.yml b/.github/workflows/install-channels.yml index 94ddd340..2427369a 100644 --- a/.github/workflows/install-channels.yml +++ b/.github/workflows/install-channels.yml @@ -186,7 +186,7 @@ jobs: LATEST: ${{ needs.latest.outputs.version }} PLUMBER_NO_UPDATE_CHECK: "1" steps: - - uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0 + - uses: actions/setup-go@v7.0.0 with: # Same pin as ci.yml: the toolchain go.mod asks for. go-version: '1.26.10' diff --git a/.github/workflows/plumber-action.yml b/.github/workflows/plumber-action.yml index de2ba975..f4aca953 100644 --- a/.github/workflows/plumber-action.yml +++ b/.github/workflows/plumber-action.yml @@ -25,11 +25,11 @@ jobs: security-events: write id-token: write # mint the OIDC id-token for the Plumber Score push steps: - - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + - uses: actions/checkout@v7.0.1 with: persist-credentials: false - - uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0 + - uses: actions/setup-go@v7.0.0 with: go-version: '1.26.10' @@ -63,7 +63,7 @@ jobs: - name: Upload SARIF to Code Scanning if: ${{ always() && hashFiles('plumber.sarif') != '' }} - uses: github/codeql-action/upload-sarif@6f2ac81f5cd81fe351a197ba0b00d91d03cd2aee # v4.39.0 + uses: github/codeql-action/upload-sarif@v4.39.0 with: sarif_file: plumber.sarif @@ -73,7 +73,7 @@ jobs: # even when --fail-warnings fails the job. - name: Upload Plumber reports if: ${{ always() }} - uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2 + uses: actions/upload-artifact@v7.0.2 with: name: plumber-reports path: | diff --git a/.github/workflows/propagate.yml b/.github/workflows/propagate.yml index b0f47820..01f73cca 100644 --- a/.github/workflows/propagate.yml +++ b/.github/workflows/propagate.yml @@ -67,7 +67,7 @@ jobs: component_sha: ${{ steps.sync.outputs.component_sha }} steps: - name: Checkout main - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + uses: actions/checkout@v7.0.1 with: ref: main fetch-depth: 0 @@ -226,7 +226,7 @@ jobs: steps: - name: Generate website App token id: app-token - uses: actions/create-github-app-token@64ab729a6294000f5aa4a4bc0b73d1f32bc45510 # v3.3.0 + uses: actions/create-github-app-token@v3.3.0 with: client-id: ${{ secrets.RELEASE_APP_CLIENT_ID }} private-key: ${{ secrets.RELEASE_APP_PRIVATE_KEY }} @@ -234,7 +234,7 @@ jobs: repositories: getplumber.io - name: Checkout main - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + uses: actions/checkout@v7.0.1 with: ref: main fetch-depth: 0 @@ -252,7 +252,7 @@ jobs: { echo "sha=${SHA}"; echo "digest=${DIGEST}"; } >> "$GITHUB_OUTPUT" - name: Checkout website - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + uses: actions/checkout@v7.0.1 with: repository: getplumber/getplumber.io token: ${{ steps.app-token.outputs.token }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 7b49474b..cd28b46b 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -48,20 +48,20 @@ jobs: steps: - name: Generate GitHub App token id: app-token - uses: actions/create-github-app-token@64ab729a6294000f5aa4a4bc0b73d1f32bc45510 # v3.3.0 + uses: actions/create-github-app-token@v3.3.0 with: client-id: ${{ secrets.RELEASE_APP_CLIENT_ID }} private-key: ${{ secrets.RELEASE_APP_PRIVATE_KEY }} - name: Checkout - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + uses: actions/checkout@v7.0.1 with: fetch-depth: 0 persist-credentials: false token: ${{ steps.app-token.outputs.token }} - name: Setup Node.js - uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0 + uses: actions/setup-node@v7.1.0 with: node-version: '20.20.2' @@ -98,26 +98,26 @@ jobs: VERSION: ${{ needs.plan.outputs.version || '0.0.0-dryrun' }} steps: - name: Checkout - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + uses: actions/checkout@v7.0.1 with: persist-credentials: false - name: Set up QEMU - uses: docker/setup-qemu-action@99012661954931238ded8c8b007157a8430204e1 # v4.4.0 + uses: docker/setup-qemu-action@v4.4.0 with: # The action defaults to the mutable :latest tag for this # privileged image; pin it by digest. image: docker.io/tonistiigi/binfmt:qemu-v10.2.3@sha256:400a4873b838d1b89194d982c45e5fb3cda4593fbfd7e08a02e76b03b21166f0 - name: Set up Docker Buildx - uses: docker/setup-buildx-action@f87e5991a6d7451dcb8d9637bfbc97413f497069 # v4.4.1 + uses: docker/setup-buildx-action@v4.4.1 with: # The docker-container driver otherwise boots the mutable # moby/buildkit:buildx-stable-1 tag; pin it by digest. driver-opts: image=docker.io/moby/buildkit:v0.30.0@sha256:0168606be2315b7c807a03b3d8aa79beefdb31c98740cebdffdfeebf31190c9f - name: Login to Docker Hub - uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4.6.0 + uses: docker/login-action@v4.6.0 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} @@ -126,7 +126,7 @@ jobs: # image labels, from the same tag rules the docker-tags job applies. - name: Extract metadata id: meta - uses: docker/metadata-action@dc802804100637a589fabce1cb79ff13a1411302 # v6.2.0 + uses: docker/metadata-action@v6.2.0 with: images: getplumber/plumber tags: | @@ -142,7 +142,7 @@ jobs: - name: Build and push id: push - uses: docker/build-push-action@c3c9e263c25d99ce0380d002d59b67737d91b0dc # v7.4.0 + uses: docker/build-push-action@v7.4.0 with: context: . platforms: linux/amd64,linux/arm64 @@ -168,7 +168,7 @@ jobs: no-cache-filters: runtime - name: Attest Docker image - uses: actions/attest-build-provenance@4d101475d8b20a2381f78447822ac1eab6504dd8 # v4.2.2 + uses: actions/attest-build-provenance@v4.2.2 with: subject-name: docker.io/getplumber/plumber subject-digest: ${{ steps.push.outputs.digest }} @@ -187,20 +187,20 @@ jobs: steps: - name: Generate GitHub App token id: app-token - uses: actions/create-github-app-token@64ab729a6294000f5aa4a4bc0b73d1f32bc45510 # v3.3.0 + uses: actions/create-github-app-token@v3.3.0 with: client-id: ${{ secrets.RELEASE_APP_CLIENT_ID }} private-key: ${{ secrets.RELEASE_APP_PRIVATE_KEY }} - name: Checkout - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + uses: actions/checkout@v7.0.1 with: fetch-depth: 0 persist-credentials: false token: ${{ steps.app-token.outputs.token }} - name: Setup Node.js - uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0 + uses: actions/setup-node@v7.1.0 with: node-version: '20.20.2' @@ -248,21 +248,21 @@ jobs: if: needs.release.outputs.new_release_published == 'true' steps: - name: Set up Docker Buildx - uses: docker/setup-buildx-action@f87e5991a6d7451dcb8d9637bfbc97413f497069 # v4.4.1 + uses: docker/setup-buildx-action@v4.4.1 with: # The docker-container driver otherwise boots the mutable # moby/buildkit:buildx-stable-1 tag; pin it by digest. driver-opts: image=docker.io/moby/buildkit:v0.30.0@sha256:0168606be2315b7c807a03b3d8aa79beefdb31c98740cebdffdfeebf31190c9f - name: Login to Docker Hub - uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4.6.0 + uses: docker/login-action@v4.6.0 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Extract metadata id: meta - uses: docker/metadata-action@dc802804100637a589fabce1cb79ff13a1411302 # v6.2.0 + uses: docker/metadata-action@v6.2.0 with: images: getplumber/plumber tags: | @@ -318,12 +318,12 @@ jobs: goarch: amd64 steps: - name: Checkout - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + uses: actions/checkout@v7.0.1 with: persist-credentials: false - name: Setup Go - uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0 + uses: actions/setup-go@v7.0.0 with: # Must be >= the go.mod `go` directive (1.26.0, raised by # golang.org/x/crypto v0.56.0). setup-go pins GOTOOLCHAIN=local, so a @@ -347,7 +347,7 @@ jobs: go build -ldflags="-s -w -X github.com/getplumber/plumber/cmd.Version=${VERSION} -X github.com/getplumber/plumber/cmd.Commit=${COMMIT} -X github.com/getplumber/plumber/cmd.BuildDate=${BUILD_DATE}" -o "dist/${BINARY_NAME}" . - name: Upload artifact - uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2 + uses: actions/upload-artifact@v7.0.2 with: name: plumber-${{ matrix.goos }}-${{ matrix.goarch }} path: dist/ @@ -363,7 +363,7 @@ jobs: if: needs.release.outputs.new_release_published == 'true' steps: - name: Download binary artifacts - uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2 + uses: actions/download-artifact@v8.0.2 with: path: dist/ merge-multiple: true @@ -376,7 +376,7 @@ jobs: - name: Attest build provenance id: attest - uses: actions/attest-build-provenance@4d101475d8b20a2381f78447822ac1eab6504dd8 # v4.2.2 + uses: actions/attest-build-provenance@v4.2.2 with: subject-path: dist/plumber-* @@ -428,7 +428,7 @@ jobs: echo "linux_amd64=$(grep 'plumber-linux-amd64$' checksums.txt | awk '{print $1}')" >> $GITHUB_OUTPUT - name: Checkout Homebrew tap - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + uses: actions/checkout@v7.0.1 with: repository: getplumber/homebrew-plumber path: homebrew-tap diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index efb38abc..bbedde4f 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -19,7 +19,7 @@ jobs: id-token: write steps: - name: Checkout - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + uses: actions/checkout@v7.0.1 with: persist-credentials: false @@ -33,19 +33,19 @@ jobs: # workflow and OIDC claims. A solution is still to be found # (upstream digest pin, or dropping the badge for a pinned CLI). - name: Run Scorecard - uses: ossf/scorecard-action@fa7117db83c52d787ae5a89f350999701505d78e # v2.5.0 + uses: ossf/scorecard-action@v2.5.0 with: results_file: results.sarif results_format: sarif publish_results: true - name: Upload SARIF - uses: github/codeql-action/upload-sarif@6f2ac81f5cd81fe351a197ba0b00d91d03cd2aee # v4.39.0 + uses: github/codeql-action/upload-sarif@v4.39.0 with: sarif_file: results.sarif - name: Upload artifact - uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2 + uses: actions/upload-artifact@v7.0.2 with: name: scorecard-results path: results.sarif diff --git a/.github/workflows/scripts-test.yml b/.github/workflows/scripts-test.yml index 91ffc9cf..1f8166a3 100644 --- a/.github/workflows/scripts-test.yml +++ b/.github/workflows/scripts-test.yml @@ -33,7 +33,7 @@ jobs: permissions: contents: read steps: - - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + - uses: actions/checkout@v7.0.1 with: persist-credentials: false # Pass the test file explicitly — `node --test ` tries to load the diff --git a/.github/workflows/verify-lockfile.yml b/.github/workflows/verify-lockfile.yml new file mode 100644 index 00000000..0e3eba63 --- /dev/null +++ b/.github/workflows/verify-lockfile.yml @@ -0,0 +1,36 @@ +name: Lockfile + +# Fails when .github/workflows/actions.lock is out of sync with the workflows, +# or when a locked commit no longer verifies upstream (moved tag, renamed or +# replaced repository). No paths filter: this is meant to be a required check, +# and a filtered required check never reports on PRs it skips. + +on: + pull_request: + branches: [main] + push: + branches: [main] + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +permissions: {} + +jobs: + verify: + name: Lockfile + runs-on: ubuntu-24.04 + timeout-minutes: 5 + permissions: + contents: read + env: + GH_TOKEN: ${{ github.token }} + steps: + - uses: actions/checkout@v7.0.1 + with: + persist-credentials: false + - name: Install gh-actions-lock + run: gh extension install github/gh-actions-lock --pin v0.2.0 + - name: Verify the lockfile + run: gh actions-lock --verify From 12b66c0fc99cbc5242520e0e22a6033057623d46 Mon Sep 17 00:00:00 2001 From: Thib_C Date: Thu, 22 Oct 2026 17:31:24 +0200 Subject: [PATCH 2/4] docs: document the workflow lockfile and give it a code owner entry Co-Authored-By: Claude Opus 5.5 --- .github/CODEOWNERS | 5 ++++- CONTRIBUTING.md | 11 +++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index dba7c142..9037f640 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1 +1,4 @@ -* @coconux3 @thomasboni @Joseph94m @Totara-thib \ No newline at end of file +* @coconux3 @thomasboni @Joseph94m @Totara-thib + +# Lockfile changes are dependency changes: a changed commit is new code that will run. +.github/workflows/actions.lock @coconux3 @thomasboni @Joseph94m @Totara-thib diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index a30d9bc9..f308bd36 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -10,6 +10,7 @@ Thank you for your interest in contributing to Plumber! This guide will help you - [How to Contribute](#how-to-contribute) - [Reporting Issues](#reporting-issues) - [Submitting Pull Requests](#submitting-pull-requests) + - [Changing GitHub workflows](#changing-github-workflows) - [Development Setup](#development-setup) - [Prerequisites](#prerequisites) - [Building](#building) @@ -98,6 +99,16 @@ Before opening an issue, please: - Screenshots/output examples if applicable - **"Allow edits from maintainers" enabled** (checked by default on GitHub). This lets maintainers push fixes or rebases directly to your branch, which speeds up the review process. +### Changing GitHub workflows + +Every action our workflows use is locked in `.github/workflows/actions.lock`: its commit, its owner and repository ids, and the actions it calls in turn. The `Lockfile` check fails a PR whose workflows the lockfile doesn't fully cover. + +- After adding a workflow or changing any `uses:`, run `gh actions-lock` from the repository root (install it with `gh extension install github/gh-actions-lock`) and commit the updated lockfile with the workflow change. +- Never edit `actions.lock` by hand. +- Dependabot doesn't onboard a new workflow: that one needs `gh actions-lock` by hand. If a Dependabot bump PR fails the `Lockfile` check, run `gh actions-lock` on its branch. +- Optional, before committing: `gh actions-lock --verify-local --no-fix` checks coverage offline. CI runs the full `gh actions-lock --verify`. +- Review a lockfile change as a dependency change: a changed `commit` is new code that will run, and a changed `owner_id` or `repo_id` means the repository behind the name is not the one we locked. + ## Development Setup ### Prerequisites From 48d94936a99b52e6f88fb5d5c8f43e6ea9bd978f Mon Sep 17 00:00:00 2001 From: Thib_C Date: Fri, 23 Oct 2026 09:36:41 +0200 Subject: [PATCH 3/4] ci: verify the workflow lockfile with gh-actions-lock v0.3.0 The lockfile generated with v0.2.0 passes v0.3.0's stricter --verify unchanged, and a v0.3.0 fix run writes nothing new. Co-Authored-By: Claude Opus 5.5 --- .github/workflows/verify-lockfile.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/verify-lockfile.yml b/.github/workflows/verify-lockfile.yml index 0e3eba63..8c0aed61 100644 --- a/.github/workflows/verify-lockfile.yml +++ b/.github/workflows/verify-lockfile.yml @@ -31,6 +31,6 @@ jobs: with: persist-credentials: false - name: Install gh-actions-lock - run: gh extension install github/gh-actions-lock --pin v0.2.0 + run: gh extension install github/gh-actions-lock --pin v0.3.0 - name: Verify the lockfile run: gh actions-lock --verify From cc2bc253688f8a7ca1b158726e415ceaf4117080 Mon Sep 17 00:00:00 2001 From: Thib_C Date: Mon, 26 Oct 2026 10:08:27 +0100 Subject: [PATCH 4/4] ci: verify the workflow lockfile with gh-actions-lock v0.4.0 The lockfile passes v0.4.0's --verify unchanged, and a v0.4.0 fix run writes nothing new. Co-Authored-By: Claude Opus 5.5 --- .github/workflows/verify-lockfile.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/verify-lockfile.yml b/.github/workflows/verify-lockfile.yml index 8c0aed61..1b315711 100644 --- a/.github/workflows/verify-lockfile.yml +++ b/.github/workflows/verify-lockfile.yml @@ -31,6 +31,6 @@ jobs: with: persist-credentials: false - name: Install gh-actions-lock - run: gh extension install github/gh-actions-lock --pin v0.3.0 + run: gh extension install github/gh-actions-lock --pin v0.4.0 - name: Verify the lockfile run: gh actions-lock --verify