@@ -162,6 +162,13 @@ func (a *ApplicationSnapshotImage) ValidateImageSignature(ctx context.Context) e
162162 var err error
163163
164164 if a .hasBundles (ctx ) {
165+ // For v3 bundles, both image signatures and attestations are stored as
166+ // "attestations" in the unified bundle format. So we use VerifyImageAttestations
167+ // to extract image signatures from the bundle, even though it seems unintuitive.
168+ // This is different from v2 where image signatures and attestations were separate.
169+ //
170+ // The certificate extraction requires different handling for bundles and
171+ // should be addressed in future work to achieve full v2 parity.
165172 opts .NewBundleFormat = true
166173 opts .ClaimVerifier = cosign .IntotoSubjectClaimVerifier
167174 sigs , _ , err = client .VerifyImageAttestations (a .reference , & opts )
@@ -175,6 +182,17 @@ func (a *ApplicationSnapshotImage) ValidateImageSignature(ctx context.Context) e
175182
176183 for _ , s := range sigs {
177184 if a .hasBundles (ctx ) {
185+ // This will appears in the output under "signatures" so filter out
186+ // the sigs that are provenance attestations leaving only the sigs
187+ // that are image signatures. Note: This does seems confusing and
188+ // I'm not 100% sure we're doing the right thing here. Maybe revisit
189+ // once we have a better idea about sigstore bundles and how they're
190+ // handled by cosign itself.
191+ if ! isImageSignatureAttestation (s ) {
192+ log .Debugf ("Skipping non-image signature attestation" )
193+ continue
194+ }
195+
178196 // For bundle image signatures produced by cosign v3, the old
179197 // method of accessing the signatures doesn't work. Instead we have
180198 // to extract them from the bundle. And the bundle actually has
@@ -185,7 +203,8 @@ func (a *ApplicationSnapshotImage) ValidateImageSignature(ctx context.Context) e
185203 }
186204 a .signatures = append (a .signatures , signatures ... )
187205 } else {
188- // For older non-bundle image signatures produced by cosign v2
206+ // For older non-bundle image signatures produced by cosign v2.
207+ // Note that filtering isn't needed, since we have only image sigs here.
189208 es , err := signature .NewEntitySignature (s )
190209 if err != nil {
191210 return err
@@ -212,6 +231,11 @@ func (a *ApplicationSnapshotImage) ValidateAttestationSignature(ctx context.Cont
212231 return err
213232 }
214233
234+ // Todo:
235+ // - For the non-bundle code path we actually check the syntax.
236+ // We should do that for bundles as well probably.
237+ // - Doing an early return like thi shere seems untidy, refactor
238+ // maybe?
215239 if useBundles {
216240 return a .parseAttestationsFromBundles (layers )
217241 }
@@ -264,8 +288,19 @@ func (a *ApplicationSnapshotImage) ValidateAttestationSignature(ctx context.Cont
264288// parseAttestationsFromBundles extracts attestations from Sigstore bundles.
265289// Bundle-wrapped layers report an incorrect media type, so we unmarshal the
266290// DSSE envelope from the raw payload directly.
291+ //
292+ // Note: For v3 bundles, this function filters out image signature attestations
293+ // (https://sigstore.dev/cosign/sign/v1) since those are handled in ValidateImageSignature.
294+ // Only provenance and other attestations are added to the attestations array.
267295func (a * ApplicationSnapshotImage ) parseAttestationsFromBundles (layers []cosignOCI.Signature ) error {
268296 for _ , sig := range layers {
297+ // For v3 bundles, filter out image signature attestations - those are handled
298+ // in ValidateImageSignature. Only add provenance attestations here.
299+ if isImageSignatureAttestation (sig ) {
300+ log .Debugf ("Skipping image signature attestation - handled in ValidateImageSignature" )
301+ continue
302+ }
303+
269304 payload , err := sig .Payload ()
270305 if err != nil {
271306 log .Debugf ("Skipping bundle entry: cannot read payload: %v" , err )
@@ -288,8 +323,8 @@ func (a *ApplicationSnapshotImage) parseAttestationsFromBundles(layers []cosignO
288323 if err != nil {
289324 return fmt .Errorf ("unable to parse bundle attestation: %w" , err )
290325 }
291- t := att .PredicateType ()
292- log . Debugf ( "Found bundle attestation with predicateType: %s" , t )
326+ log . Debugf ( "Found bundle attestation with predicateType: %s" , att .PredicateType () )
327+
293328 a .attestations = append (a .attestations , att )
294329 }
295330 return nil
@@ -494,6 +529,29 @@ func (a *ApplicationSnapshotImage) WriteInputFile(ctx context.Context) (string,
494529 return inputJSONPath , inputJSON , nil
495530}
496531
532+ // isImageSignatureAttestation checks if a signature from a bundle represents
533+ // an image signature attestation (vs. a provenance attestation).
534+ func isImageSignatureAttestation (sig cosignOCI.Signature ) bool {
535+ payload , err := sig .Payload ()
536+ if err != nil {
537+ log .Debugf ("Cannot read signature payload: %v" , err )
538+ return false
539+ }
540+
541+ att , err := attestation .ProvenanceFromBundlePayload (sig , payload )
542+ if err != nil {
543+ log .Debugf ("Cannot parse bundle attestation: %v" , err )
544+ return false
545+ }
546+
547+ predicateType := att .PredicateType ()
548+ // Image signature attestations use the cosign/sign predicate type
549+ isImageSig := predicateType == "https://sigstore.dev/cosign/sign/v1"
550+ log .Debugf ("Attestation predicateType: %s, isImageSignature: %t" , predicateType , isImageSig )
551+
552+ return isImageSig
553+ }
554+
497555// extractSignaturesFromBundle extracts signature information from a bundle
498556// image signature attestation, using the same pattern as createEntitySignatures.
499557//
0 commit comments