@@ -42,6 +42,7 @@ import (
4242 "github.com/sigstore/cosign/pkg/cosign/pivkey"
4343 cremote "github.com/sigstore/cosign/pkg/cosign/remote"
4444 "github.com/sigstore/cosign/pkg/oci"
45+ ociempty "github.com/sigstore/cosign/pkg/oci/empty"
4546 "github.com/sigstore/cosign/pkg/oci/mutate"
4647 ociremote "github.com/sigstore/cosign/pkg/oci/remote"
4748 "github.com/sigstore/cosign/pkg/oci/static"
@@ -168,6 +169,18 @@ func SignCmd(ctx context.Context, ko KeyOpts, regOpts options.RegistryOptions, a
168169 return fmt .Errorf ("unable to resolve attachment %s for image %s" , attachment , inputImg )
169170 }
170171
172+ if digest , ok := ref .(name.Digest ); ok && ! recursive {
173+ se , err := ociempty .SignedImage (ref )
174+ if err != nil {
175+ return err
176+ }
177+ err = signDigest (ctx , digest , staticPayload , ko , regOpts , annotations , upload , force , dd , sv , se )
178+ if err != nil {
179+ return err
180+ }
181+ continue
182+ }
183+
171184 se , err := ociremote .SignedEntity (ref , opts ... )
172185 if err != nil {
173186 return err
@@ -181,74 +194,85 @@ func SignCmd(ctx context.Context, ko KeyOpts, regOpts options.RegistryOptions, a
181194 }
182195 digest := ref .Context ().Digest (d .String ())
183196
184- // The payload can be specified via a flag to skip generation.
185- payload := staticPayload
186- if len (payload ) == 0 {
187- payload , err = (& sigPayload.Cosign {
188- Image : digest ,
189- Annotations : annotations ,
190- }).MarshalJSON ()
191- if err != nil {
192- return errors .Wrap (err , "payload" )
193- }
194- }
195-
196- signature , err := sv .SignMessage (bytes .NewReader (payload ), signatureoptions .WithContext (ctx ))
197+ err = signDigest (ctx , digest , staticPayload , ko , regOpts , annotations , upload , force , dd , sv , se )
197198 if err != nil {
198- return errors .Wrap (err , "signing" )
199- }
200- b64sig := base64 .StdEncoding .EncodeToString (signature )
201-
202- if ! upload {
203- fmt .Println (b64sig )
204- return ErrDone
199+ return err
205200 }
201+ return ErrDone
202+ }); err != nil {
203+ return err
204+ }
205+ }
206206
207- opts := []static.Option {}
208- if sv .Cert != nil {
209- opts = append (opts , static .WithCertChain (sv .Cert , sv .Chain ))
210- }
207+ return nil
208+ }
211209
212- // Check whether we should be uploading to the transparency log
213- if uploadTLog , err := ShouldUploadToTlog (digest , force , ko .RekorURL ); err != nil {
214- return err
215- } else if uploadTLog {
216- bundle , err := UploadToTlog (ctx , sv , ko .RekorURL , func (r * client.Rekor , b []byte ) (* models.LogEntryAnon , error ) {
217- return cosign .TLogUpload (r , signature , payload , b )
218- })
219- if err != nil {
220- return err
221- }
222- opts = append (opts , static .WithBundle (bundle ))
223- }
210+ func signDigest (ctx context.Context , digest name.Digest , payload []byte , ko KeyOpts ,
211+ regOpts options.RegistryOptions , annotations map [string ]interface {}, upload bool , force bool ,
212+ dd mutate.DupeDetector , sv * CertSignVerifier , se oci.SignedEntity ) error {
213+ var err error
214+ // The payload can be passed to skip generation.
215+ if len (payload ) == 0 {
216+ payload , err = (& sigPayload.Cosign {
217+ Image : digest ,
218+ Annotations : annotations ,
219+ }).MarshalJSON ()
220+ if err != nil {
221+ return errors .Wrap (err , "payload" )
222+ }
223+ }
224224
225- // Create the new signature for this entity.
226- sig , err := static . NewSignature ( payload , b64sig , opts ... )
227- if err != nil {
228- return err
229- }
225+ signature , err := sv . SignMessage ( bytes . NewReader ( payload ), signatureoptions . WithContext ( ctx ))
226+ if err != nil {
227+ return errors . Wrap ( err , "signing" )
228+ }
229+ b64sig := base64 . StdEncoding . EncodeToString ( signature )
230230
231- // Attach the signature to the entity.
232- newSE , err := mutate .AttachSignatureToEntity (se , sig , mutate .WithDupeDetector (dd ))
233- if err != nil {
234- return err
235- }
231+ if ! upload {
232+ fmt .Println (b64sig )
233+ return nil
234+ }
236235
237- walkOpts , err := regOpts . ClientOpts ( ctx )
238- if err != nil {
239- return errors . Wrap ( err , "constructing client options" )
240- }
236+ opts := []static. Option {}
237+ if sv . Cert != nil {
238+ opts = append ( opts , static . WithCertChain ( sv . Cert , sv . Chain ) )
239+ }
241240
242- // Publish the signatures associated with this entity
243- if err := ociremote .WriteSignatures (digest .Repository , newSE , walkOpts ... ); err != nil {
244- return err
245- }
246- return ErrDone
247- }); err != nil {
241+ // Check whether we should be uploading to the transparency log
242+ if uploadTLog , err := ShouldUploadToTlog (digest , force , ko .RekorURL ); err != nil {
243+ return err
244+ } else if uploadTLog {
245+ bundle , err := UploadToTlog (ctx , sv , ko .RekorURL , func (r * client.Rekor , b []byte ) (* models.LogEntryAnon , error ) {
246+ return cosign .TLogUpload (r , signature , payload , b )
247+ })
248+ if err != nil {
248249 return err
249250 }
251+ opts = append (opts , static .WithBundle (bundle ))
250252 }
251253
254+ // Create the new signature for this entity.
255+ sig , err := static .NewSignature (payload , b64sig , opts ... )
256+ if err != nil {
257+ return err
258+ }
259+
260+ // Attach the signature to the entity.
261+ newSE , err := mutate .AttachSignatureToEntity (se , sig , mutate .WithDupeDetector (dd ))
262+ if err != nil {
263+ return err
264+ }
265+
266+ // Publish the signatures associated with this entity
267+ walkOpts , err := regOpts .ClientOpts (ctx )
268+ if err != nil {
269+ return errors .Wrap (err , "constructing client options" )
270+ }
271+
272+ // Publish the signatures associated with this entity
273+ if err := ociremote .WriteSignatures (digest .Repository , newSE , walkOpts ... ); err != nil {
274+ return err
275+ }
252276 return nil
253277}
254278
0 commit comments