88 "fmt"
99 "io"
1010 "io/fs"
11+ "maps"
1112 "os"
1213 "path/filepath"
1314 "runtime"
@@ -19,6 +20,7 @@ import (
1920 "github.com/sirupsen/logrus"
2021 "go.podman.io/image/v5/internal/imagedestination/impl"
2122 "go.podman.io/image/v5/internal/imagedestination/stubs"
23+ "go.podman.io/image/v5/internal/iolimits"
2224 "go.podman.io/image/v5/internal/private"
2325 "go.podman.io/image/v5/internal/putblobdigest"
2426 "go.podman.io/image/v5/internal/signature"
@@ -336,7 +338,7 @@ func (d *ociImageDestination) PutSignaturesWithFormat(ctx context.Context, signa
336338 instanceDigest = & d .manifestDigest
337339 }
338340
339- sigstoreSignatures := []signature.Sigstore {}
341+ var sigstoreSignatures []signature.Sigstore
340342 for _ , sig := range signatures {
341343 if sigstoreSig , ok := sig .(signature.Sigstore ); ok {
342344 sigstoreSignatures = append (sigstoreSignatures , sigstoreSig )
@@ -356,11 +358,28 @@ func (d *ociImageDestination) PutSignaturesWithFormat(ctx context.Context, signa
356358func (d * ociImageDestination ) putSignaturesToSigstoreAttachment (ctx context.Context , signatures []signature.Sigstore , manifestDigest digest.Digest ) error {
357359 var signConfig imgspecv1.Image // Most fields empty by default
358360
359- signManifest := manifest .OCI1FromComponents (imgspecv1.Descriptor {
360- MediaType : imgspecv1 .MediaTypeImageConfig ,
361- Digest : "" , // We will fill this in later.
362- Size : 0 ,
363- }, nil )
361+ signManifest , err := d .ref .getSigstoreAttachmentManifest (manifestDigest , & d .index , d .sharedBlobDir )
362+ if err != nil {
363+ return err
364+ }
365+ if signManifest == nil {
366+ signManifest = manifest .OCI1FromComponents (imgspecv1.Descriptor {
367+ MediaType : imgspecv1 .MediaTypeImageConfig ,
368+ Digest : "" , // We will fill this in later.
369+ Size : 0 ,
370+ }, nil )
371+ signConfig .RootFS .Type = "layers"
372+ } else {
373+ logrus .Debugf ("Fetching sigstore attachment config %s" , signManifest .Config .Digest .String ())
374+ configBlob , err := d .ref .getOCIDescriptorContents (signManifest .Config , iolimits .MaxConfigBodySize , d .sharedBlobDir )
375+ if err != nil {
376+ return err
377+ }
378+ if err := json .Unmarshal (configBlob , & signConfig ); err != nil {
379+ return fmt .Errorf ("parsing sigstore attachment config %s in %s: %w" , signManifest .Config .Digest .String (),
380+ d .ref .StringWithinTransport (), err )
381+ }
382+ }
364383
365384 desc , err := d .getDescriptor (& manifestDigest )
366385 if err != nil {
@@ -375,7 +394,14 @@ func (d *ociImageDestination) putSignaturesToSigstoreAttachment(ctx context.Cont
375394 payloadBlob := sig .UntrustedPayload ()
376395 annotations := sig .UntrustedAnnotations ()
377396
378- sigDesc , err := d .putBlobBytesAsOCI (ctx , payloadBlob , mimeType , private.PutBlobOptions {
397+ // Skip if the signature is already on the registry.
398+ if slices .ContainsFunc (signManifest .Layers , func (layer imgspecv1.Descriptor ) bool {
399+ return layerMatchesSigstoreSignature (layer , mimeType , payloadBlob , annotations )
400+ }) {
401+ continue
402+ }
403+
404+ signDesc , err := d .putBlobBytesAsOCI (ctx , payloadBlob , mimeType , private.PutBlobOptions {
379405 Cache : none .NoCache ,
380406 IsConfig : false ,
381407 EmptyLayer : false ,
@@ -384,10 +410,10 @@ func (d *ociImageDestination) putSignaturesToSigstoreAttachment(ctx context.Cont
384410 if err != nil {
385411 return err
386412 }
387- sigDesc .Annotations = annotations
388- signManifest .Layers = append (signManifest .Layers , sigDesc )
389- signConfig .RootFS .DiffIDs = append (signConfig .RootFS .DiffIDs , sigDesc .Digest )
390- logrus .Debugf ("Adding new signature, digest %s" , sigDesc .Digest .String ())
413+ signDesc .Annotations = annotations
414+ signManifest .Layers = append (signManifest .Layers , signDesc )
415+ signConfig .RootFS .DiffIDs = append (signConfig .RootFS .DiffIDs , signDesc .Digest )
416+ logrus .Debugf ("Adding new signature, digest %s" , signDesc .Digest .String ())
391417 }
392418
393419 configBlob , err := json .Marshal (signConfig )
@@ -557,3 +583,18 @@ func indexExists(ref ociReference) bool {
557583 }
558584 return true
559585}
586+
587+ func layerMatchesSigstoreSignature (layer imgspecv1.Descriptor , mimeType string ,
588+ payloadBlob []byte , annotations map [string ]string ) bool {
589+ if layer .MediaType != mimeType ||
590+ layer .Size != int64 (len (payloadBlob )) ||
591+ // This is not quite correct, we should use the layer’s digest algorithm.
592+ // But right now we don’t want to deal with corner cases like bad digest formats
593+ // or unavailable algorithms; in the worst case we end up with duplicate signature
594+ // entries.
595+ layer .Digest .String () != digest .FromBytes (payloadBlob ).String () ||
596+ ! maps .Equal (layer .Annotations , annotations ) {
597+ return false
598+ }
599+ return true
600+ }
0 commit comments