From abb6cb177d5287f7b682bd4140a20ed0c36a37f1 Mon Sep 17 00:00:00 2001 From: BaaRai <130491490+BaaRai@users.noreply.github.com> Date: Fri, 13 Nov 2026 23:17:19 +0100 Subject: [PATCH] release: add build provenance attestation, CycloneDX SBOM and a dry-run trigger - release job: attest dist/*.zip with actions/attest-build-provenance (id-token: write, attestations: write; contents stays write for the Release). - SBOM: syft scans the bin-linux-amd64 binary (embedded Go modules), plus web/package-lock.json and go.mod/go.sum; artex-.cdx.json is checked for pkg:golang and pkg:npm entries and attached next to SHA256SUMS. - workflow_dispatch dry run: builds, SBOM, attestations and workflow artifacts; the Release step and the docker job only run on push. - README: Verifying a release section. --- .github/workflows/release.yml | 44 ++++++++++++++++++++++++++++++++++- README.md | 9 +++++++ 2 files changed, 52 insertions(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 3a47d9e..6fd8ce5 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -2,6 +2,9 @@ name: release on: push: tags: ["v*"] + # Dry run: builds, SBOM, attestations and workflow artifacts only. The GitHub + # Release and the image push are gated on github.event_name == 'push'. + workflow_dispatch: permissions: contents: write # required to create the Release @@ -81,6 +84,10 @@ jobs: release: needs: binaries runs-on: ubuntu-latest + permissions: + contents: write # create the Release (softprops/action-gh-release) + id-token: write # Sigstore signing of the provenance attestation + attestations: write # store the attestation on the repository steps: - uses: actions/checkout@v4 # CHANGELOG.md and the extractor script - uses: actions/download-artifact@v4 @@ -91,6 +98,39 @@ jobs: - name: Generate checksums working-directory: dist run: sha256sum *.zip > SHA256SUMS + # SBOM of what ships: the Go modules embedded in the linux/amd64 binary, plus + # the frontend lockfile and the Go module files. + - uses: actions/download-artifact@v4 + with: + name: bin-linux-amd64 + path: ${{ runner.temp }}/sbom-src/bin + - uses: anchore/sbom-action/download-syft@66cbf4bc1f1c0d2edc94016e65bc221b6bb0ad6c # v0.24.3 + id: syft + with: + syft-version: v1.54.0 + - name: Generate CycloneDX SBOM + env: + SYFT: ${{ steps.syft.outputs.cmd }} + SRC: ${{ runner.temp }}/sbom-src + TAG: ${{ github.ref_name }} + run: | + mkdir -p "$SRC/web" + cp go.mod go.sum "$SRC/" + cp web/package-lock.json "$SRC/web/" + sbom="dist/artex-${TAG}.cdx.json" + "$SYFT" scan "dir:$SRC" --source-name artex --source-version "$TAG" -o "cyclonedx-json=$sbom" + grep -q '"pkg:golang/' "$sbom" || { echo "::error::SBOM has no pkg:golang entries"; exit 1; } + grep -q '"pkg:npm/' "$sbom" || { echo "::error::SBOM has no pkg:npm entries"; exit 1; } + echo "SBOM_PATH=$sbom" >> "$GITHUB_ENV" + - uses: actions/attest-build-provenance@4d101475d8b20a2381f78447822ac1eab6504dd8 # v4.2.2 + with: + subject-path: dist/*.zip + - uses: actions/upload-artifact@v4 + with: + name: release-metadata + path: | + dist/SHA256SUMS + ${{ env.SBOM_PATH }} - name: Release body from CHANGELOG.md env: TAG: ${{ github.ref_name }} @@ -103,10 +143,12 @@ jobs: echo "Release $TAG. See CHANGELOG.md for the list of changes in this release." > "$RUNNER_TEMP/release-body.md" fi - uses: softprops/action-gh-release@v2 + if: github.event_name == 'push' with: files: | dist/*.zip dist/SHA256SUMS + ${{ env.SBOM_PATH }} generate_release_notes: false body_path: ${{ runner.temp }}/release-body.md @@ -118,7 +160,7 @@ jobs: # and provide DOCKERHUB_USERNAME / DOCKERHUB_TOKEN secrets plus DOCKERHUB_IMAGE). docker: needs: binaries - if: ${{ vars.DOCKERHUB_ENABLED == 'true' }} + if: ${{ vars.DOCKERHUB_ENABLED == 'true' && github.event_name == 'push' }} runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 # fetch the Dockerfile and skills/ diff --git a/README.md b/README.md index db1a724..ad6a18b 100644 --- a/README.md +++ b/README.md @@ -134,6 +134,15 @@ cp config.example.json config.json # fill in the database connection > Please start with `start.sh` / `start.bat` instead of running `./artex` directly. It is a daemon script: if the process crashes, it restarts it after a backoff. > To keep it running in the background: `nohup ./start.sh >artex.log 2>&1 &`. +#### Verifying a release + +Each release attaches `SHA256SUMS` and a CycloneDX SBOM, `artex-.cdx.json` (Go modules embedded in the linux/amd64 binary, the frontend `package-lock.json`, and `go.mod`/`go.sum`), next to the zips. The zips also carry a GitHub build provenance attestation. Releases published before this was added have neither the SBOM nor the attestation. + +```bash +sha256sum -c SHA256SUMS # add --ignore-missing if you downloaded only some zips +gh attestation verify --repo BaaRai/ARTEX # provenance: built by this repository's release workflow +``` + ### Option 4: build the single binary from source ```bash