@@ -183,6 +183,17 @@ func (a *ApplicationSnapshotImage) ValidateImageSignature(ctx context.Context) e
183183
184184 for _ , s := range sigs {
185185 if useBundles {
186+ // This will appears in the output under "signatures" so filter out
187+ // the sigs that are provenance attestations leaving only the sigs
188+ // that are image signatures. Note: This does seems confusing and
189+ // I'm not 100% sure we're doing the right thing here. Maybe revisit
190+ // once we have a better idea about sigstore bundles and how they're
191+ // handled by cosign itself.
192+ if ! isImageSignatureAttestation (s ) {
193+ log .Debugf ("Skipping non-image signature attestation" )
194+ continue
195+ }
196+
186197 // For bundle image signatures produced by cosign v3, the old
187198 // method of accessing the signatures doesn't work. Instead we have
188199 // to extract them from the bundle. And the bundle actually has
@@ -193,7 +204,8 @@ func (a *ApplicationSnapshotImage) ValidateImageSignature(ctx context.Context) e
193204 }
194205 a .signatures = append (a .signatures , signatures ... )
195206 } else {
196- // For older non-bundle image signatures produced by cosign v2
207+ // For older non-bundle image signatures produced by cosign v2.
208+ // Note that filtering isn't needed, since we have only image sigs here.
197209 es , err := signature .NewEntitySignature (s )
198210 if err != nil {
199211 return err
@@ -220,6 +232,11 @@ func (a *ApplicationSnapshotImage) ValidateAttestationSignature(ctx context.Cont
220232 return err
221233 }
222234
235+ // Todo:
236+ // - For the non-bundle code path we actually check the syntax.
237+ // We should do that for bundles as well probably.
238+ // - Doing an early return like thi shere seems untidy, refactor
239+ // maybe?
223240 if useBundles {
224241 return a .parseAttestationsFromBundles (layers )
225242 }
@@ -272,8 +289,19 @@ func (a *ApplicationSnapshotImage) ValidateAttestationSignature(ctx context.Cont
272289// parseAttestationsFromBundles extracts attestations from Sigstore bundles.
273290// Bundle-wrapped layers report an incorrect media type, so we unmarshal the
274291// DSSE envelope from the raw payload directly.
292+ //
293+ // Note: For v3 bundles, this function filters out image signature attestations
294+ // (https://sigstore.dev/cosign/sign/v1) since those are handled in ValidateImageSignature.
295+ // Only provenance and other attestations are added to the attestations array.
275296func (a * ApplicationSnapshotImage ) parseAttestationsFromBundles (layers []cosignOCI.Signature ) error {
276297 for _ , sig := range layers {
298+ // For v3 bundles, filter out image signature attestations - those are handled
299+ // in ValidateImageSignature. Only add provenance attestations here.
300+ if isImageSignatureAttestation (sig ) {
301+ log .Debugf ("Skipping image signature attestation - handled in ValidateImageSignature" )
302+ continue
303+ }
304+
277305 payload , err := sig .Payload ()
278306 if err != nil {
279307 log .Debugf ("Skipping bundle entry: cannot read payload: %v" , err )
@@ -296,8 +324,8 @@ func (a *ApplicationSnapshotImage) parseAttestationsFromBundles(layers []cosignO
296324 if err != nil {
297325 return fmt .Errorf ("unable to parse bundle attestation: %w" , err )
298326 }
299- t := att .PredicateType ()
300- log . Debugf ( "Found bundle attestation with predicateType: %s" , t )
327+ log . Debugf ( "Found bundle attestation with predicateType: %s" , att .PredicateType () )
328+
301329 a .attestations = append (a .attestations , att )
302330 }
303331 return nil
@@ -502,6 +530,43 @@ func (a *ApplicationSnapshotImage) WriteInputFile(ctx context.Context) (string,
502530 return inputJSONPath , inputJSON , nil
503531}
504532
533+ // extractPredicateType extracts the predicateType field from a JSON
534+ // payload lazily, i.e. without unmarshalling all the other fields
535+ func extractPredicateType (payload []byte ) (string , error ) {
536+ var attestation struct {
537+ PredicateType string `json:"predicateType"`
538+ }
539+ if err := json .Unmarshal (payload , & attestation ); err != nil {
540+ return "" , err
541+ }
542+ return attestation .PredicateType , nil
543+ }
544+
545+ // hasPredicateType checks if a JSON payload has the specified predicate type.
546+ func hasPredicateType (payload []byte , expectedType string ) bool {
547+ predicateType , err := extractPredicateType (payload )
548+ if err != nil {
549+ log .Debugf ("Cannot parse JSON payload: %v" , err )
550+ return false
551+ }
552+ return predicateType == expectedType
553+ }
554+
555+ const cosignSignPredicateType = "https://sigstore.dev/cosign/sign/v1"
556+
557+ // isImageSignatureAttestation checks if a signature from a bundle represents
558+ // an image signature attestation (vs. a provenance attestation).
559+ func isImageSignatureAttestation (sig cosignOCI.Signature ) bool {
560+ payload , err := sig .Payload ()
561+ if err != nil {
562+ log .Debugf ("Cannot read signature payload: %v" , err )
563+ return false
564+ }
565+
566+ // Image signature attestations use the cosign/sign predicate type
567+ return hasPredicateType (payload , cosignSignPredicateType )
568+ }
569+
505570// extractSignaturesFromBundle extracts signature information from a bundle
506571// image signature attestation, using the same pattern as createEntitySignatures.
507572//
0 commit comments