From 7c6ce3d27147feca3daaa8b1e7b46b3d231596da Mon Sep 17 00:00:00 2001 From: Frenchie Date: Thu, 18 Sep 2025 11:30:13 +1000 Subject: [PATCH 1/4] test --- .github/workflows/release.yml | 89 +++++++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) create mode 100644 .github/workflows/release.yml diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 00000000..57f6514d --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,89 @@ +name: release + +on: + push: + tags: + - "v*" + +# Minimal permissions required by this workflow +permissions: + contents: write # create releases and upload assets + id-token: write # needed for keyless provenance/attestations + attestations: write # record build provenance in the repo's Attestations + +concurrency: + group: release-${{ github.ref }} + cancel-in-progress: false + +jobs: + release: + if: startsWith(github.ref, 'refs/tags/') + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 # needed to access and verify tags + + # TODO(frenchi): Verify tag is signed (GPG/SSH) + # - name: Verify tag is signed (GPG/SSH) + # env: + # GH_TOKEN: ${{ github.token }} + # TAG: ${{ github.ref_name }} + # REPO: ${{ github.repository }} + # run: | + # set -euo pipefail + # obj_type="$(gh api repos/${REPO}/git/ref/tags/${TAG} --jq '.object.type')" + # obj_sha="$(gh api repos/${REPO}/git/ref/tags/${TAG} --jq '.object.sha')" + # echo "Tag ${TAG} type=${obj_type} sha=${obj_sha}" + # if [ "${obj_type}" = "tag" ]; then + # verified="$(gh api repos/${REPO}/git/tags/${obj_sha} --jq '.verification.verified')" + # reason="$(gh api repos/${REPO}/git/tags/${obj_sha} --jq '.verification.reason')" + # else + # verified="$(gh api repos/${REPO}/git/commits/${obj_sha} --jq '.verification.verified')" + # reason="$(gh api repos/${REPO}/git/commits/${obj_sha} --jq '.verification.reason')" + # fi + # echo "verification.verified=${verified} reason=${reason}" + # if [ "${verified}" != "true" ]; then + # echo "Tag ${TAG} is not signed/verified. Aborting release." >&2 + # exit 1 + # fi + + - name: Set up Go + uses: actions/setup-go@v5 + with: + go-version: "^1.23" + + - name: Download Go modules (for SBOM resolution) + run: go mod download + + - name: Generate SBOM (SPDX) + uses: anchore/sbom-action@v0 + with: + path: . + format: spdx-json + output-file: sbom.spdx.json + upload-artifact: true + + - name: Generate SLSA build provenance + uses: actions/attest-build-provenance@v1 + with: + subject-path: sbom.spdx.json + + - name: Create GitHub Release and upload SBOMs + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + set -euo pipefail + TAG="${{ github.ref_name }}" + TITLE="Release ${TAG}" + gh release create "${TAG}" \ + --title "${TITLE}" \ + --generate-notes \ + sbom.spdx.json + + - name: Post-release summary + run: | + echo "Release ${{ github.ref_name }} created with SBOMs and provenance attestations." + echo "Environment approvals (if configured) gated this job." From 4dacd675b66ecbac6da232f35024940552c33746 Mon Sep 17 00:00:00 2001 From: Frenchie Date: Thu, 18 Sep 2025 11:31:09 +1000 Subject: [PATCH 2/4] test release From a1b7114611e2285f2dec7bf9ca720ca74a478386 Mon Sep 17 00:00:00 2001 From: Frenchie Date: Thu, 18 Sep 2025 12:35:31 +1000 Subject: [PATCH 3/4] more work --- .github/workflows/release.yml | 43 ++++++++++++++++++++++++++++++----- 1 file changed, 37 insertions(+), 6 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 57f6514d..77ba7080 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -17,16 +17,27 @@ concurrency: jobs: release: + environment: release if: startsWith(github.ref, 'refs/tags/') - runs-on: ubuntu-latest + runs-on: ubuntu-latest steps: + - name: Check actor access + # Defence in depth: also require multiple approvals from: + # Settings -> Environments -> release -> Deployment protection rules -> Required reviewers + # + if: ${{ !contains( fromJson('["frenchi"]'), github.actor ) }} + # !contains( fromJson('["findleyr", "jba",...]'), github.actor ) }} + run: exit 1 + - name: Checkout uses: actions/checkout@v4 with: fetch-depth: 0 # needed to access and verify tags # TODO(frenchi): Verify tag is signed (GPG/SSH) + # Possible simpler alternative: repo rulesets + # - name: Verify tag is signed (GPG/SSH) # env: # GH_TOKEN: ${{ github.token }} @@ -58,18 +69,38 @@ jobs: - name: Download Go modules (for SBOM resolution) run: go mod download - - name: Generate SBOM (SPDX) + # Optional: sigstore/cosign. required for keyless signing at the cost of a (relatively common) dependency on cosign. + - name: Install Cosign + uses: sigstore/cosign-installer@d7543c93d881b35a8faa02e8e3605f69b7a1ce62 #v3.10.0 + + # Optional: anchore/syft. generate SBOMs, at the cost of a (relatively common) dependency on anchore/sbom-action + - name: Generate SBOM uses: anchore/sbom-action@v0 with: path: . - format: spdx-json - output-file: sbom.spdx.json + format: github-json + output-file: sbom.json upload-artifact: true + # Zero dep alternative for SBOMs: + # + # Without anchore/sbom-action, we could use actions/go-dependency-submission@v2 to submit + # to the dependency graph and then curl the github API to download the SBOM: + # + # curl -L \ + # -H "Accept: application/vnd.github+json" \ + # -H "Authorization: Bearer " \ + # -H "X-GitHub-Api-Version: 2022-11-28" \ + # https://api.github.com/repos/OWNER/REPO/dependency-graph/sboms/SHA + # + # from: https://docs.github.com/en/rest/dependency-graph/sboms?apiVersion=2022-11-28#export-a-software-bill-of-materials-sbom-for-a-repository - name: Generate SLSA build provenance uses: actions/attest-build-provenance@v1 with: - subject-path: sbom.spdx.json + subject-path: sbom.json + - name: Sign SBOM with Cosign + run: | + cosign sign --key cosign.key sbom.json - name: Create GitHub Release and upload SBOMs env: @@ -81,7 +112,7 @@ jobs: gh release create "${TAG}" \ --title "${TITLE}" \ --generate-notes \ - sbom.spdx.json + sbom.json - name: Post-release summary run: | From acffb0571423213099325418ed3dfb51f0a180cb Mon Sep 17 00:00:00 2001 From: Frenchie Date: Thu, 18 Sep 2025 12:44:01 +1000 Subject: [PATCH 4/4] test --- .github/workflows/release.yml | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 77ba7080..ad664071 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -70,9 +70,8 @@ jobs: run: go mod download # Optional: sigstore/cosign. required for keyless signing at the cost of a (relatively common) dependency on cosign. - - name: Install Cosign - uses: sigstore/cosign-installer@d7543c93d881b35a8faa02e8e3605f69b7a1ce62 #v3.10.0 - + # - name: Install Cosign + # uses: sigstore/cosign-installer@d7543c93d881b35a8faa02e8e3605f69b7a1ce62 #v3.10.0 # Optional: anchore/syft. generate SBOMs, at the cost of a (relatively common) dependency on anchore/sbom-action - name: Generate SBOM uses: anchore/sbom-action@v0 @@ -98,10 +97,6 @@ jobs: uses: actions/attest-build-provenance@v1 with: subject-path: sbom.json - - name: Sign SBOM with Cosign - run: | - cosign sign --key cosign.key sbom.json - - name: Create GitHub Release and upload SBOMs env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}