Skip to content

Verifying a release

Since 0.9.0, everything a release publishes is signed or attested by the repository’s release workflow (.github/workflows/release.yml), with Sigstore keyless signing. There is no long-lived signing key to obtain, protect or rotate: the signing identity is the GitHub Actions workflow itself, recorded in a short-lived certificate and in the public Sigstore transparency log. Verifying means checking that the artifact was built by that workflow, from a v* tag of laupernoe/dumbmonit.

Each binary on the GitHub release comes with <file>.sigstore.json (the signature bundle) and <file>.sha256, and the release carries dumbmonit-agent.intoto.jsonl, the SLSA build provenance.

Terminal window
cosign verify-blob dumbmonit-agent-linux-x86_64 \
--bundle dumbmonit-agent-linux-x86_64.sigstore.json \
--certificate-oidc-issuer https://token.actions.githubusercontent.com \
--certificate-identity-regexp '^https://github.com/laupernoe/dumbmonit/\.github/workflows/release\.yml@refs/tags/v'
# or, with the GitHub CLI (checks the provenance attestation)
gh attestation verify dumbmonit-agent-linux-x86_64 -R laupernoe/dumbmonit
# or against the provenance attached to the release
gh attestation verify dumbmonit-agent-linux-x86_64 -R laupernoe/dumbmonit \
--bundle dumbmonit-agent.intoto.jsonl

A successful run prints the workflow identity and the tag. If it fails, do not install the file, and report it.

The server and agent images carry a build provenance attestation pushed to ghcr.io, and an SPDX SBOM and full SLSA provenance attached to the image index.

Terminal window
gh attestation verify oci://ghcr.io/laupernoe/dumbmonit:0.9.0 -R laupernoe/dumbmonit
# the SBOM and the provenance recorded by the build
docker buildx imagetools inspect ghcr.io/laupernoe/dumbmonit:0.9.0 \
--format '{{ json .SBOM }}'
docker buildx imagetools inspect ghcr.io/laupernoe/dumbmonit:0.9.0 \
--format '{{ json .Provenance }}'

Pin an image by digest in your Compose file if you want what you verified to be exactly what runs.

Releases from before 0.9.0 (v0.1.0-alpha.N), and files the release workflow did not sign itself (such as provenance.json), get their <file>.sigstore.json from a separate workflow run by hand (.github/workflows/sign-releases.yml). Its signature only says that the file was on the release when that workflow ran, not that it was built from the tag: check it against that workflow’s identity, and compare the file with the .sha256 next to it.

Terminal window
cosign verify-blob dumbmonit-agent-linux-x86_64 \
--bundle dumbmonit-agent-linux-x86_64.sigstore.json \
--certificate-oidc-issuer https://token.actions.githubusercontent.com \
--certificate-identity-regexp '^https://github.com/laupernoe/dumbmonit/\.github/workflows/sign-releases\.yml@refs/heads/(main|dev)$'

These releases have no build provenance: gh attestation verify does not apply to them.

Release tags (v0.9.0, …) are annotated, not GPG-signed, and only repository administrators can create them (a ruleset reserves v*). Trust in a release rests on the signed artifacts above, whose certificate names the tag they were built from, rather than on the tag signature.