Aller au contenu

Verify a release

Ce contenu n’est pas encore disponible dans votre langue.

Every release ships with SLSA Build L3 provenance, cosign-signed CycloneDX SBOMs, a signed multi-arch container image, bit-reproducible binaries and bit-reproducible Linux packages built from them (ADR-0011). None of these claims asks for your trust: each one is verifiable, and this page shows how. Replace v1.0.0 with the release you are checking.

Tools: slsa-verifier v2.7.1 or later, and cosign 3.x. The independent rebuild needs neither — only Git and Go.

1. Independent rebuild — the air-gapped guarantee

Section titled “1. Independent rebuild — the air-gapped guarantee”

Binaries and Linux packages are bit-reproducible: the same tag rebuilds to the same SHA-256. A consumer with no access to Sigstore or GitHub infrastructure — an air-gapped review workstation included — verifies a release by rebuilding it and comparing digests. tools/release-build.sh is the exact code path the release pipeline runs (CGO disabled, -trimpath, -buildvcs=false, SOURCE_DATE_EPOCH from the commit, toolchain forced to the go.mod version), and tools/package-build.sh likewise for the packages (nfpm at the NFPM_VERSION pinned in .github/workflows/release.yml):

Terminal window
git clone https://github.com/tobby-fetch/tobby-fetch && cd tobby-fetch
git checkout v1.0.0
epoch=$(git log -1 --format=%ct)
SOURCE_DATE_EPOCH=$epoch sh tools/release-build.sh \
"v1.0.0" "$(git rev-parse HEAD)" \
"$(date -u -d "@$epoch" +%Y-%m-%dT%H:%M:%SZ)" dist
# optional — also reproduces the .deb/.rpm/.apk packages
go install github.com/goreleaser/nfpm/v2/cmd/nfpm@<NFPM_VERSION>
SOURCE_DATE_EPOCH=$epoch sh tools/package-build.sh "v1.0.0" dist dist
# compare against the SHA256SUMS file attached to the release
# (--ignore-missing: skip the package lines if you skipped nfpm)
(cd dist && sha256sum --ignore-missing -c /path/to/SHA256SUMS)

Expected output: one OK line per artifact. Any mismatch means the published binary was not produced from the tagged source. The release pipeline enforces this property on itself: a second, independent build job must reproduce the first build’s digests before a release can be published.

Download the binary and tobby.intoto.jsonl from the release page, then:

Terminal window
slsa-verifier verify-artifact tobby-linux-amd64 \
--provenance-path tobby.intoto.jsonl \
--source-uri github.com/tobby-fetch/tobby-fetch \
--source-tag v1.0.0

Expected output ends with PASSED: SLSA verification passed. This proves the binary was built by the isolated slsa-github-generator trusted builder, from this repository, at that exact tag — a compromised repository workflow could not have forged it.

3. Linux packages: provenance, then offline install

Section titled “3. Linux packages: provenance, then offline install”

The .deb, .rpm and .apk packages wrap the exact tobby-linux-<arch> release binary (installed to /usr/bin/tobby, no install scripts), are listed in SHA256SUMS, and are subjects of the same provenance. Verify a package exactly like a binary:

Terminal window
slsa-verifier verify-artifact tobby_1.0.0_linux_amd64.deb \
--provenance-path tobby.intoto.jsonl \
--source-uri github.com/tobby-fetch/tobby-fetch \
--source-tag v1.0.0

Then install with no repository and no network access:

Terminal window
dpkg -i tobby_1.0.0_linux_amd64.deb # Debian/Ubuntu
rpm -i tobby_1.0.0_linux_amd64.rpm # RHEL/SUSE/Fedora
apk add --allow-untrusted tobby_1.0.0_linux_amd64.apk # Alpine

The packages deliberately carry no package-manager signature: there is no distribution repository or maintainer keyring to anchor one, and a key published next to the artifacts it signs would add no security. Trust comes from the provenance or checksum verification above, performed before installation — --allow-untrusted on apk states exactly that, and the rpm is unsigned for the same reason.

4. Container image: signature and provenance

Section titled “4. Container image: signature and provenance”

The release notes state the image digest. Always verify — and deploy — by digest, not by tag:

Terminal window
# signature — signed by the release workflow's OIDC identity
cosign verify ghcr.io/tobby-fetch/tobby-fetch@sha256:... \
--certificate-oidc-issuer https://token.actions.githubusercontent.com \
--certificate-identity-regexp '^https://github.com/tobby-fetch/tobby-fetch/'
# SLSA provenance — generated by the trusted container builder
slsa-verifier verify-image ghcr.io/tobby-fetch/tobby-fetch@sha256:... \
--source-uri github.com/tobby-fetch/tobby-fetch \
--source-tag v1.0.0

The rolling latest tag is refreshed by a weekly rebuild against current Wolfi packages, behind a Trivy gate that publishes nothing on a failed scan. That digest is cosign-signed with the same identity but carries no SLSA provenance — only immutable vX.Y.Z digests do. Audited deployments should pin a release digest.

Each binary has a CycloneDX SBOM (.cdx.json) signed keyless via Sigstore; the signature ships as a self-contained .bundle file next to it:

Terminal window
cosign verify-blob \
--new-bundle-format \
--bundle tobby-linux-amd64.cdx.json.bundle \
--certificate-oidc-issuer https://token.actions.githubusercontent.com \
--certificate-identity-regexp '^https://github.com/tobby-fetch/tobby-fetch/' \
tobby-linux-amd64.cdx.json

Expected output: Verified OK. The image’s own SBOMs are generated natively by apko at build time (SPDX) and attached to the release. Once verified, the SBOMs ingest into any CycloneDX/SPDX consumer — a dependency tracker, or a scanner run directly against the document.

Release gates keep known critical and high findings out of every release (Trivy on the image, govulncheck with symbol-level reachability on the code). ADR-0011’s standing policy for the remainder: a scanner finding that does not apply to Tobby is answered with a published OpenVEX statement attached to the release — never a silent ignore rule. Concretely: when any finding is waived, the release assets include tobby.openvex.json with a keyless signature in tobby.openvex.json.bundle, verifiable with the same cosign verify-blob command as the SBOMs; feed the document to your scanner alongside the SBOM. No release carries the document today, because no finding has been waived — its absence is itself verifiable information: the gates passed with zero exclusions (the mechanics are in .vex/README.md).

Next: tests and proofs shows the gates every commit passes before it can become a release at all.