Repository navigation
fix(storage): sign OCI images as cosign/sign/v1 in-toto statements in sigstore-bundle mode - #2096
Conversation
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #2096 +/- ##
==========================================
+ Coverage 79.60% 80.11% +0.50%
==========================================
Files 58 59 +1
Lines 3384 3349 -35
==========================================
- Hits 2694 2683 -11
+ Misses 688 664 -24
Partials 2 2
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
a79123f to
705ed87
Compare
705ed87 to
5bc9572
Compare
|
@tektoncd/chains-collaborators - Request your detailed review and feedback on this PR. Thank you. |
|
Detailed manual test notes: |
There was a problem hiding this comment.
🟡 Changes recommended
The documentation still claims the setting has no effect with non-OCI artifact backends, but enabling OCI image signing with sigstore-bundle now rejects such configurations.
1 open issue
What changed in this PR
Fixes #2036 by routing OCI image signatures in sigstore-bundle mode through Chains’ existing DSSE attestation path, producing cosign/sign/v1 statements instead of unverifiable SimpleSigning bundles.
Changes:
- Adds an encoding-dependent image-signature format while preserving legacy
dssebehavior. - Rejects non-OCI storage backends for enabled OCI image signing in bundle mode and documents the restriction.
- Adds cryptographic verification, regression, and cosign v3 end-to-end tests; the end-to-end tests remain unrun.
| File | Description |
|---|---|
test/oci_sigstore_bundle_e2e_test.go |
Adds cosign v3 verification scenarios with transparency on and off. |
test/clients.go |
Adds ClusterIP-based registry addressing for bundle tests. |
pkg/config/config.go |
Validates OCI image storage backends in bundle mode. |
pkg/config/config_test.go |
Tests backend restrictions and disabled-signing exceptions. |
pkg/chains/storage/oci/simple.go |
Removes invalid bundle creation and rejects bundle-mode requests. |
pkg/chains/storage/oci/simple_test.go |
Tests legacy signature tags and bundle-mode rejection. |
pkg/chains/storage/oci/cosignsign_bundle_test.go |
Adds bundle verification, tampering, and Rekor-entry checks. |
pkg/chains/signing_test.go |
Tests payload selection, DSSE wrapping, and Rekor format routing. |
pkg/chains/formats/format.go |
Classifies the new payload as an in-toto attestation. |
pkg/chains/formats/cosignsign/cosignsign.go |
Implements the cosign/sign/v1 statement formatter. |
pkg/chains/formats/cosignsign/cosignsign_test.go |
Tests statement content and formatter behavior. |
pkg/chains/formats/all/all.go |
Registers the new formatter. |
pkg/artifacts/signable.go |
Selects the image payload format by encoding mode. |
pkg/artifacts/signable_test.go |
Tests encoding-dependent payload selection. |
go.mod |
Promotes sigstore-go to a direct dependency. |
docs/oci-encoding-format.md |
Explains corrected bundle contents, restrictions, and verification. |
docs/config.md |
Documents payload selection and backend restrictions. |
config/100-deployment.yaml |
Updates configuration comments with the backend restriction. |
Review effort: Balanced
| > `sigstore-bundle` requires `artifacts.oci.storage` to be `oci` only. If it | ||
| > includes another backend (for example `grafeas`, `docdb`, `gcs`, `pubsub` or | ||
| > `archivista`), Chains rejects the configuration when it loads it. Those | ||
| > backends expect a SimpleSigning payload for OCI images, while `sigstore-bundle` | ||
| > mode signs a `cosign/sign/v1` Statement. |
…en lancé) ; contrôle de fin de J7 atteint, preuves rejouées sous Cilium (kata-essais, kata-exemption, construction-construire, construction-provenance), J7 laissé « en cours » jusqu'aux deux décisions du propriétaire ; état des 8 tests (mécanisme sous Cilium, trace, déjà mesuré, à faire en J8 ; test 7 : attestation de l'ancienne construire-image sur 3a7ca1b1 et ordre des attestations) ; forme proposée (preuves.sh, une étape par test, prédiction, témoin positif, trace archivée) ; décisions préalables avec recommandations : canal (c) des internalParameters et ses trous ; test 6 sous Cilium (vecteur : variante signée de construire-image pour le seul test, le code du dépôt n'atteignant que le RUN en --network=none du Dockerfile de la plateforme ; témoin par destination, seule construction-sans-sortie sélectionnant des pods de builds ; trace Hubble capturée pendant le test, tampon de 4 095 flux relu dans l'agent ; compte par tentative) ; mesure du droit update de poc-build (accord requis ; contrôle de la décision 4 : détection après coup) ; dsse gardé (tektoncd/chains#2096 ouverte au 30/10/2026, dernière release v0.29.9 ; contrôle exécutions/enveloppes à écrire) ; réserve du banc C à mesurer (journal prévu) ; budget : aucun suivi en pw, chrono.tsv couvre deux jours calendaires ; doc 03
infernus01
left a comment
There was a problem hiding this comment.
Thanks for the PR @anithapriyanatarajan. I did a thorough testing and found payloadType is "application/vnd.in-toto+json" and cosign verification also works:
[{"critical":{"identity":{"docker-reference":"10.96.202.200:5000/final-test@sha256:4741f679c26d8f59e42c3fad6768efc7855b006d283c7cfd35a7271be455f1d4"},"image":{"dock
er-manifest-digest":"sha256:4741f679c26d8f59e42c3fad6768efc7855b006d283c7cfd35a7271be455f1d4"},"type":"https://sigstore.dev/cosign/sign/v1"},"optional":{}}]
Verification for 10.96.202.200:5000/final-test@sha256:4741f679c26d8f59e42c3fad6768efc7855b006d283c7cfd35a7271be455f1d4 --
The following checks were performed on each of these signatures:
- The cosign claims were validated
- Existence of the claims in the transparency log was verified offline
- The signatures were verified against the specified public key
/lgtm
In sigstore-bundle mode the image signature was a simplesigning payload signed over its raw bytes, wrapped in a DSSE envelope and logged to Rekor as a hashedrekord entry. A DSSE bundle needs an in-toto payload, a signature over the DSSE PAE and a dsse Rekor entry, so no verifier accepted it. `cosign verify` hid this whenever the SLSA attestation bundle was also present, because it succeeds if any bundle verifies. The encoding mode now decides the image-signature payload. dsse is unchanged. sigstore-bundle uses a new internal cosign-sign/v1 payload: an in-toto Statement with the image as subject, predicateType https://sigstore.dev/cosign/sign/v1 and an empty predicate, as `cosign sign` v3 produces. It goes through the existing wrapped DSSE signer, a dsse Rekor entry and AttestationStorer, so no new bundle writer is needed. The broken SimpleStorer bundle path is removed. sigstore-bundle now requires artifacts.oci.storage to be "oci" only; the config is rejected at load time otherwise, because the other backends expect a simplesigning payload for OCI images. Tests verify the stored bundle with sigstore-go and add e2e cases that run cosign v3 against the registry. The e2e registry is addressed by its ClusterIP so go-containerregistry uses plain HTTP for the referrer manifest write. Fixes tektoncd#2036 Signed-off-by: Anitha Natarajan <anataraj@redhat.com> Assisted-by: Claude Sonnet 5.5 (via GitHub Copilot)
5bc9572 to
14c39e4
Compare
|
/retest |
1 similar comment
|
/retest |
|
[APPROVALNOTIFIER] This PR is APPROVED This pull-request has been approved by: infernus01 The full list of commands accepted by this bot can be found here. The pull request process is described here DetailsNeeds approval from an approver in each of these files:
Approvers can indicate their approval by writing |

Changes
Fixes #2036
Root cause
With
storage.oci.encoding-format: sigstore-bundle, Chains v0.29.0-v0.29.x wroteimage signatures that no verifier accepts. The bundle was a DSSE envelope around
a simplesigning payload signed over its raw bytes, and
rekor.gologged it asa hashedrekord entry. A DSSE bundle needs an in-toto payload, a signature over
the DSSE PAE and a
dsse/intotoRekor entry, so verification fails(
rekor v1 entry is not a dsse_v001 or intoto_v002 entry). Attestations were notaffected.
cosign verifyhid the failure whenever the SLSA attestation bundle wasalso stored, because it passes if any bundle verifies.
Fix
The encoding mode decides the image-signature payload. There is no new config key.
dsse: unchanged (simplesigning, raw-byte signature,hashedrekord,.sigtag).sigstore-bundle: new internal payloadcosign-sign/v1, the same shape ascosign signv3. It is an in-toto v1 Statement with the image repository andsha256digest as subject,predicateType: https://sigstore.dev/cosign/sign/v1and
predicate: {}.It reuses the existing attestation path: wrapped DSSE signer, a
dsseRekorentry, and
AttestationStorer/WriteAttestationNewBundleFormat. The brokenSimpleStorerbundle path is removed, andSimpleStorernow returns an error insigstore-bundlemode.artifacts.oci.formatis not used for payload selection inthat mode.
Decision pending maintainer confirmation
sigstore-bundlenow requiresartifacts.oci.storageto beocionly. The configis rejected at load time otherwise (error references #2036), because grafeas, docdb,
gcs, pubsub and archivista expect a simplesigning payload for OCI images. Please
confirm this is the behavior you want.
cosign-sign/v1is also inIntotoAttestationSet; the Grafeas backend is not changed and relies on thisconfig check.
Tests
OCIArtifact.PayloadFormatin both modes, config validation(
ociaccepted;oci,grafeasand others rejected;dsseunaffected), andObjectSignerpayload format / wrapping / Rekor format per encoding.pkg/chains/storage/oci/cosignsign_bundle_test.go):signs with the real wrapped DSSE signer, stores to an in-memory registry with
referrers support, and verifies the referrer's bundle with sigstore-go
(
WithArtifactDigest+WithKey). It also asserts thedsseEnvelopecontent,payload type and referrer annotations, and that a tampered payload or a wrong
digest fails. With a Rekor entry,
tlogEntries[0].kindVersion.kind == "dsse".dssemode still writes a.sigtag with a simplesigning layer.test/oci_sigstore_bundle_e2e_test.go): cosign v3verify(andverify-attestation --type slsaprovenance) for signature only andsignature + attestation, with transparency on and off. It asserts a
cosign/sign/v1entry is present in the output, since exit code 0 alone can besatisfied by the attestation.
e2e notes
referrerManifest.targetRefdropsname.Insecure, so thereferrer manifest write to a plain-HTTP registry reached by a DNS name uses HTTPS.
The e2e registry is therefore addressed by its Service ClusterIP; go-containerregistry
treats private IPs as HTTP. This is a test-only workaround. Production use with a
plain-HTTP registry by DNS name is still affected.
(
ghcr.io/sigstore/cosign/cosign:v3.1.4-dev) and its shell path are unverified.The verify step uses the public key from the signing secret rather than
k8s://tekton-chains/signing-secrets.sigstore-gois now a direct dependency ingo.mod(already vendored, no vendor diff).Sample bundle written by the unit test
cosign download signaturestyle output for an image signature insigstore-bundlemode:{"mediaType":"application/vnd.dev.sigstore.bundle.v0.3+json", "verificationMaterial":{"publicKey":{"hint":"ICAGuSNlLNbuhnueYznCFLTHYzGgjGfTuTMBIogfxVk="}}, "dsseEnvelope":{"payload":"eyJfdHlwZSI6Imh0dHBzOi8vaW4tdG90by5pby9TdGF0ZW1lbnQvdjEiLCAic3ViamVjdCI6W3sibmFtZSI6IjEyNy4wLjAuMTozNjEwNy90ZXN0L2Nvc2lnbi1zaWduLWltZyIsICJkaWdlc3QiOnsic2hhMjU2IjoiNjEzNTQ5YjlhOGNmNzY5MDNkMmJiYTNiNjIxMjBkZjg0NmI4ZGRjODgzZDM0MTA2NjQyN2NmYjczMDE1MTZiNSJ9fV0sICJwcmVkaWNhdGVUeXBlIjoiaHR0cHM6Ly9zaWdzdG9yZS5kZXYvY29zaWduL3NpZ24vdjEiLCAicHJlZGljYXRlIjp7fX0=", "payloadType":"application/vnd.in-toto+json", "signatures":[{"sig":"MEUCIE2vGJ4xeqnxLVV5hBcyu6FBT2O5Y07frWRs7gG2hEpRAiEA6P17QCUZ5rT3TAE1r2+w7n+hFezKejoL2La9uqdrknU="}]}}The decoded payload is:
{"_type":"https://in-toto.io/Statement/v1","subject":[{"name":"127.0.0.1:36107/test/cosign-sign-img","digest":{"sha256":"613549b9a8cf76903d2bba3b62120df846b8ddc883d341066427cfb7301516b5"}}],"predicateType":"https://sigstore.dev/cosign/sign/v1","predicate":{}}Out of scope
KMS no-verification-material guard,
insecureNameOpts, MicroshiftassignSCC(salvaged from #2044), Rekor v2 / TSA support, upstream cosign changes.
Submitter Checklist
As the author of this PR, please check off the items in this checklist:
functionality, content, code)
Release Notes