Repository navigation
Description
Problem / motivation
No release carries a signature, provenance or SBOM. OpenSSF Scorecard's Signed-Releases check scores 0 ("0 out of 5 artifacts are signed or have provenance" for v1.7.0-alpha.3, v1.6.4, v1.6.4-rc.1, v1.6.3 and v1.6.3-rc.2). CLOMonitor's signed_releases and sbom checks fail with it and hold the security section down. Together with the missing Security Insights manifest (#4757), that section scores 72.73.
Users who install from the release page download a Talos ISO, raw disk images, a kernel and initramfs, operator manifests, CRDs and cozypkg binaries. They can verify none of it. The only checksum file is cozypkg-checksums.txt, which covers cozypkg alone and is not signed.
This gap is already acknowledged in several places:
- the 2026 Q4 Scorecard target of ≥ 7.0 in ROADMAP.md;
- the "sign releases" follow-up listed in ci: harden GitHub Actions workflows for OpenSSF Scorecard (pin, permissions, zizmor gate) #3223 and never tracked;
docs/security/self-assessment.md, whose SBOM row says "Not published at this time";- the provenance-first plan in docs(security): clarify self-assessment per TAG-Security review #4352.
Proposed solution
Both release paths end in hack/upload-assets.sh, with every asset in _out/assets. The rc path is the prepare-release job in tags.yaml. The stable path is promote-rc.yaml, after it re-stamps the version-stamped assets. Before the uploads, the script would:
- Generate
cozystack-sbom.spdx.jsonwith syft, over the source tree and thecozypkgbinaries. The file name matters: CLOMonitor'ssbomcheck matches(?i)sbomin the asset names of the latest release. - Write
cozystack-checksums.txtwith the SHA-256 of every asset, the SBOM included. - Sign it keylessly with the workflow's GitHub OIDC identity:
cosign sign-blob --yes --bundle cozystack-checksums.txt.sigstore.json cozystack-checksums.txt. One signature then covers every file through the checksums. - Upload all three files with the rest.
Workflow changes: the two jobs that call make upload_assets need id-token: write, and need sigstore/cosign-installer and anchore/sbom-action/download-syft pinned by SHA for the zizmor gate. Signing inside the script also covers promotion. promote-rc.yaml downloads the rc's assets and rebuilds some of them, so the stable release has to get freshly computed checksums and a fresh signature, not the rc's copies.
Users would verify with:
cosign verify-blob cozystack-checksums.txt \
--bundle cozystack-checksums.txt.sigstore.json \
--certificate-identity-regexp '^https://github.com/cozystack/cozystack/\.github/workflows/(tags|promote-rc)\.yaml@' \
--certificate-oidc-issuer https://token.actions.githubusercontent.com
sha256sum --check --ignore-missing cozystack-checksums.txtThat procedure would go into the release docs and into project.documentation.signature-verification in security-insights.yml.
Scorecard gives 8 when every recent release carries a signature. CLOMonitor passes once that score reaches 1, so the first release that carries the bundle flips both CLOMonitor checks. A later step to Scorecard's 10 would be SLSA provenance (*.intoto.jsonl) over the same checksums file, via the slsa-github-generator generic workflow.
Scope check
- This affects a single component / package (if it spans many, consider a design proposal)
- I can describe the expected behavior concretely (if not, consider a Discussion first)
Alternatives considered
- GitHub artifact attestations (
actions/attest-build-provenance). Users can verify them withgh attestation verify, but they live outside the release assets, so Scorecard and CLOMonitor do not see them unless the bundle is also attached. They can be added alongside the bundle. - PGP-signed checksums. This needs a long-lived key, its custody and rotation. Keyless signing ties the signature to the workflow identity instead.
- Image SBOM attestations (Finish the CI image-build refactor: SBOM emission and pr-* tag retention #2937, item A2 in [Tracking] Remaining CI / build / release / E2E automation work #3278). They are complementary: they cover the container images, not the release downloads, and they do not satisfy CLOMonitor's
sbomcheck, which reads only release assets and the README.
Additional context
- Scorecard check definition: https://github.com/ossf/scorecard/blob/main/docs/checks.md#signed-releases
- Tracking: [Tracking] Remaining CI / build / release / E2E automation work #3278 (CI / build / release umbrella) and Finish the CI image-build refactor: SBOM emission and pr-* tag retention #2937 (image SBOM). Release engineering owners: Aleksei Sviridkin (@lexfrei), myasnikovdaniil.
- I can take the
hack/upload-assets.shand workflow change once the approach is agreed.
Activity
docs(security): add an OpenSSF Security Insights manifest (#4757)
feat(release): sign the release assets and attach a source SBOM
feat(release): sign the release assets and attach a source SBOM
feat(release): sign the release assets and attach a source SBOM (#4861)
themoriarti commentedon Oct 21, 2026
Status on 2026-10-21, with the pull requests that implement this issue and what is still open after them.
Landed
hack/upload-assets.shhands its asset list tohack/sign-release-assets.sh, which writescozystack-source-sbom.spdx.json(syft over the committed tree and thecozypkgbinaries),cozystack-checksums.txt(SHA-256 of every asset and the SBOM) andcozystack-checksums.txt.sigstore.json(keyless cosign, identity pinned totags.yaml@refs/tags/v*andpromote-rc.yaml@refs/heads/main), and verifies the bundle before the first upload. Both upload jobs gotid-token: write, syft 1.54.1 from its release tarball checked against a committed SHA-256, and cosign v3.1.3;docs/release.mdcarries the verify recipe. The source SBOM is namedsourceon purpose, socozystack-sbomstays free for a document of the whole release.Open, in review
SBOM=1, so BuildKit attaches an SPDX SBOM as an attestation manifest in the image's index; the stitch and the multi-arch gate read that index shape, and the scanner is pinned by digest. Aleksei Sviridkin (@lexfrei) asked for two small changes (the nightly-mirror wording and a Renovate manager for the scanner pin).hack/sign-release-images.shsigns every index the stitch repinned the tree on, keylessly, with the same identity as the checksums, skipping a digest that already verifies, and verifies each beforemake upload_assets;promote-rc.yamlchecks every signature of the rc with--verify-onlybefore it stages the stable release. The signature over an index covers the attestation manifest the index lists, so the SBOM from feat(release): attach an SBOM to every release image #4997 is covered without a signature of its own.hack/collect-image-sboms.shreads those SBOMs back intocozystack-images-sbom.tar.gz, one SPDX document per platform, andcozystack-images.txtlists the signed digests; both ride under the existing checksums signature.docs/release.mdgets a "How to verify a release" block that checks the bundle, every asset, every image signature and unpacks the SBOMs, and the SBOM row ofdocs/security/self-assessment.mdsays what a release publishes.SBOM=1also attaches a SLSA provenance statement inmode=min(build times, platform, frontend, BuildKit version, no build arguments or secrets) to the same attestation manifest, so the per-image provenance is covered by the signature from feat(release): sign the release images and attach their SBOMs #5042.Still to do
release-1.6line stays unsigned untilhack/sign-release-assets.shand, later, the two scripts of feat(release): sign the release images and attach their SBOMs #5042 are backported to it, since promotion runs the rc tree's scripts.project.documentation.signature-verificationinsecurity-insights.yml→docs/release.md#how-to-verify-a-release, once the first signed release exists (the docs(security): add an OpenSSF Security Insights manifest #4757 follow-up).cozystack-checksums.txt(*.intoto.jsonl, the slsa-github-generator generic workflow, as the issue says). feat(build): attach a provenance attestation beside the SBOM #5043's provenance is per image, in the registry; Scorecard does not read it.cozystack-packages) and thecozy-installerchart are not signed by feat(release): sign the release images and attach their SBOMs #5042: promotion republishes both under a new digest, so they need a signing step inpromote-rc.yamland in finalize, with its own verify.cozystack-sbom.spdx.jsonas one SPDX document of the whole release, the source SBOM and the image SBOMs tied by relationships, under the name this issue reserved for it. Cheap once feat(release): sign the release images and attach their SBOMs #5042's archive exists; worth doing only if someone wants one file rather than the archive.v*tag rulesets that restrict tag creation to the CI app, and a parse-time guard refusing apromote-rc.yamldispatch from a branch other thanmain: until then a hand-pushedv*tag whose tree carries an editedtags.yamlstill signs, whichdocs/release.mdsays. Both are repository settings and workflow guards, not part of the PRs above.I suggest keeping this issue open as the tracker until the first signed release is out and the CLOMonitor and Scorecard checks have moved, then closing it with that release linked and filing items 3 to 6 separately if they are still wanted. It still carries
triage/needs-triage.feat(release): sign the release assets and attach a source SBOM