Supply chain
What a release holds, how to verify its signatures, how to rebuild its binaries from source, and what CI checks before a tag.
On this page
A reviewer reads this page to check that a release is what the project built. Straza releases are built by a GitHub Actions job from a version tag, signed with keyless cosign under that job’s identity, and reproducible from the source tree with one make target. The question of who built a binary therefore has a checkable answer.
What a release contains
A release is a set of files on its release page and an image in the registry.
| Artifact | What it holds |
|---|---|
| One archive per platform, for Linux, Windows and macOS on amd64 and arm64 | The three static binaries strazad, strazactl and straza, both license files, NOTICE, TRADEMARKS.md, THIRD_PARTY_NOTICES.txt, the README and the standalone quickstart |
checksums.txt |
Checksums of the release files |
checksums.txt.sig and checksums.txt.pem |
The cosign signature of checksums.txt, and the certificate that signed it |
| A software bill of materials for every archive | The components of that archive, generated by syft |
The container image ghcr.io/strazahq/straza, for linux/amd64 and linux/arm64 |
Built from scratch, with the strazad and strazactl binaries, a bundle of public certificate authorities, and under /licenses/ both license files, NOTICE, THIRD_PARTY_NOTICES.txt and the license terms of the certificate bundle. It runs as an unprivileged user. |
| The image’s signature and certificate | A signature over the image’s digest, stored in the registry next to the image |
THIRD_PARTY_NOTICES.txt carries the copyright notices and license texts of every third-party component. It is generated from the Go modules the binaries link on every release platform and from what the console build bundles.
A tag first lands as a draft release, which the maintainer publishes by hand. The release workflow fails when a component carries no license text, when the committed console notices are stale, or when an archive lacks the notices, and the image is then never built. The image job pushes the image by its digest with no name, checks the notices in it and signs it, and only then gives it the version tag and latest. A pull by name therefore always gets a checked and signed image.
How you verify one
Every binary in a release is reachable from checksums.txt, and that one file is what cosign signs, so verifying takes two steps. First you verify the signature on the checksums file against the identity of the release workflow, under the issuer https://token.actions.githubusercontent.com. Then you verify your download against the checksums file. The two commands are in the Install guide.
The identity pattern pins the repository Strazahq/straza, its release workflow .github/workflows/release.yml and a version tag. It spells the organization Strazahq as GitHub writes it into the certificate, and the match is case-sensitive, so a pattern in lowercase fails. A certificate from another repository, another workflow or a branch does not match. The container image verifies with the same identity:
cosign verify ghcr.io/strazahq/straza:1.1.0 \
--certificate-identity-regexp '^https://github\.com/Strazahq/straza/\.github/workflows/release\.yml@refs/tags/v[0-9]+\.[0-9]+\.[0-9]+$' \
--certificate-oidc-issuer https://token.actions.githubusercontent.com
Every command on this page follows the release pipeline’s definition and was not run against a published release. Keyless signing records every signature in the public Rekor transparency log together with the repository identity, which is intended for an open source project and means a signature can be audited later. A key-based fallback exists for a signing outage, and it is never automated, because a long-lived private key whose compromise forges releases is worse than a delayed release.
Reproducing a release from source
make verify-release proves that a release’s bytes came from the source tree you have, with no key and no CI, so it survives any signing outage. To run it:
- Check out the release tag.
- Download the archives and
checksums.txtintodist/. - Unpack each archive into its own directory under
dist/, because the script compares the binaries themselves and reads the version from the checked-out tag. - Run
make verify-release.
The script checks checksums.txt against the artifacts on disk, then rebuilds every release binary from the current source and compares the SHA-256 of each rebuild with the shipped file. The rebuild replays the build information embedded in each shipped binary, the operating system, the architecture and the CGO setting, rather than this machine’s defaults. It refuses to compare when the toolchain differs, because a distribution-patched Go of the same version does not produce the same bytes as the upstream one.
It exits 1 on any mismatch or when dist/ holds no release binary, and 0 only when every binary reproduces bit for bit. A mismatch usually means a different toolchain, different version flags or a dirty tree, and the script names those three in order.
What runs on every pull request, and what a tag needs
Every pull request, and every push to main that changes more than the docs, runs the CI workflow in .github/workflows/ci.yml. It runs these checks:
- golangci-lint with gosec enabled.
- govulncheck over the module graph and the standard library.
go vet.- The file-length ratchet.
- The complete test suite under the race detector, without the test cache.
- A coverage floor of 75 percent.
- The end-to-end journey suite.
- The Python kit’s tests.
- A render of the Helm chart and the compose file, with an image build.
- The console build and its tests.
A release needs a tag of the form v* pushed to the repository. That tag runs the release workflow with permission to create the release, push the image and mint the OIDC token that keyless signing needs, and no other event runs it. The archive binaries are built with the Go toolchain that go.mod names, CGO off and -trimpath, with version and commit stamped in. The image binaries are built the same way inside the golang:1.26-bookworm build image, and make verify-release checks the archive binaries only. Every action the workflow uses is pinned by commit hash rather than by tag.