Skip to content

Commit

Permalink
feat: add output flag for signCmd (#1066)
Browse files Browse the repository at this point in the history
* feat: add output flag for signCmd

Fixes #1059

Signed-off-by: Furkan <[email protected]>
Co-authored-off-by: Batuhan <[email protected]>

* docs: regenerate doc gen

Signed-off-by: Batuhan Apaydın <[email protected]>

Co-authored-by: Batuhan Apaydın <[email protected]>
  • Loading branch information
Dentrax and developer-guy authored Nov 18, 2021
1 parent d673477 commit 943e824
Show file tree
Hide file tree
Showing 6 changed files with 37 additions and 17 deletions.
4 changes: 4 additions & 0 deletions cmd/cosign/cli/options/sign.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ type SignOptions struct {
Key string
Cert string
Upload bool
Output string
PayloadPath string
Force bool
Recursive bool
Expand Down Expand Up @@ -57,6 +58,9 @@ func (o *SignOptions) AddFlags(cmd *cobra.Command) {
cmd.Flags().BoolVar(&o.Upload, "upload", true,
"whether to upload the signature")

cmd.Flags().StringVar(&o.Output, "output", "",
"write the signature to FILE")

cmd.Flags().StringVar(&o.PayloadPath, "payload", "",
"path to a payload file to use rather than generating one")

Expand Down
2 changes: 1 addition & 1 deletion cmd/cosign/cli/sign.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ func Sign() *cobra.Command {
if err != nil {
return err
}
if err := sign.SignCmd(cmd.Context(), ko, o.Registry, annotationsMap.Annotations, args, o.Cert, o.Upload, o.PayloadPath, o.Force, o.Recursive, o.Attachment); err != nil {
if err := sign.SignCmd(cmd.Context(), ko, o.Registry, annotationsMap.Annotations, args, o.Cert, o.Upload, o.Output, o.PayloadPath, o.Force, o.Recursive, o.Attachment); err != nil {
if o.Attachment == "" {
return errors.Wrapf(err, "signing %v", args)
}
Expand Down
23 changes: 19 additions & 4 deletions cmd/cosign/cli/sign/sign.go
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ func GetAttachedImageRef(ref name.Reference, attachment string, opts ...ociremot

// nolint
func SignCmd(ctx context.Context, ko KeyOpts, regOpts options.RegistryOptions, annotations map[string]interface{},
imgs []string, certPath string, upload bool, payloadPath string, force bool, recursive bool, attachment string) error {
imgs []string, certPath string, upload bool, output string, payloadPath string, force bool, recursive bool, attachment string) error {
if options.EnableExperimental() {
if options.NOf(ko.KeyRef, ko.Sk) > 1 {
return &options.KeyParseError{}
Expand Down Expand Up @@ -177,7 +177,7 @@ func SignCmd(ctx context.Context, ko KeyOpts, regOpts options.RegistryOptions, a
if err != nil {
return errors.Wrap(err, "accessing image")
}
err = signDigest(ctx, digest, staticPayload, ko, regOpts, annotations, upload, force, dd, sv, se)
err = signDigest(ctx, digest, staticPayload, ko, regOpts, annotations, upload, output, force, dd, sv, se)
if err != nil {
return errors.Wrap(err, "signing digest")
}
Expand All @@ -197,7 +197,7 @@ func SignCmd(ctx context.Context, ko KeyOpts, regOpts options.RegistryOptions, a
}
digest := ref.Context().Digest(d.String())

err = signDigest(ctx, digest, staticPayload, ko, regOpts, annotations, upload, force, dd, sv, se)
err = signDigest(ctx, digest, staticPayload, ko, regOpts, annotations, upload, output, force, dd, sv, se)
if err != nil {
return errors.Wrap(err, "signing digest")
}
Expand All @@ -211,7 +211,7 @@ func SignCmd(ctx context.Context, ko KeyOpts, regOpts options.RegistryOptions, a
}

func signDigest(ctx context.Context, digest name.Digest, payload []byte, ko KeyOpts,
regOpts options.RegistryOptions, annotations map[string]interface{}, upload bool, force bool,
regOpts options.RegistryOptions, annotations map[string]interface{}, upload bool, output string, force bool,
dd mutate.DupeDetector, sv *CertSignVerifier, se oci.SignedEntity) error {
var err error
// The payload can be passed to skip generation.
Expand All @@ -236,6 +236,21 @@ func signDigest(ctx context.Context, digest name.Digest, payload []byte, ko KeyO
return nil
}

if output != "" {
f, err := os.Create(output)
if err != nil {
return errors.Wrap(err, "create signature file")
}
defer f.Close()
_, err = f.Write([]byte(b64sig))

if err != nil {
return errors.Wrap(err, "write signature to file")
}

fmt.Fprintf(os.Stderr, "Signature wrote to the file %s\n", f.Name())
}

opts := []static.Option{}
if sv.Cert != nil {
opts = append(opts, static.WithCertChain(sv.Cert, sv.Chain))
Expand Down
2 changes: 1 addition & 1 deletion cmd/cosign/cli/sign/sign_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ func TestSignCmdLocalKeyAndSk(t *testing.T) {
Sk: true,
},
} {
err := SignCmd(ctx, ko, options.RegistryOptions{}, nil, nil, "", false, "", false, false, "")
err := SignCmd(ctx, ko, options.RegistryOptions{}, nil, nil, "", false, "", "", false, false, "")
if (errors.Is(err, &options.KeyParseError{}) == false) {
t.Fatal("expected KeyParseError")
}
Expand Down
1 change: 1 addition & 0 deletions doc/cosign_sign.md

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

22 changes: 11 additions & 11 deletions test/e2e_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ func TestSignVerify(t *testing.T) {

// Now sign the image
ko := sign.KeyOpts{KeyRef: privKeyPath, PassFunc: passFunc}
must(sign.SignCmd(ctx, ko, options.RegistryOptions{}, nil, []string{imgName}, "", true, "", false, false, ""), t)
must(sign.SignCmd(ctx, ko, options.RegistryOptions{}, nil, []string{imgName}, "", true, "", "", false, false, ""), t)

// Now verify and download should work!
must(verify(pubKeyPath, imgName, true, nil, ""), t)
Expand All @@ -117,7 +117,7 @@ func TestSignVerify(t *testing.T) {

// Sign the image with an annotation
annotations := map[string]interface{}{"foo": "bar"}
must(sign.SignCmd(ctx, ko, options.RegistryOptions{}, annotations, []string{imgName}, "", true, "", false, false, ""), t)
must(sign.SignCmd(ctx, ko, options.RegistryOptions{}, annotations, []string{imgName}, "", true, "", "", false, false, ""), t)

// It should match this time.
must(verify(pubKeyPath, imgName, true, map[string]interface{}{"foo": "bar"}, ""), t)
Expand All @@ -141,7 +141,7 @@ func TestSignVerifyClean(t *testing.T) {

// Now sign the image
ko := sign.KeyOpts{KeyRef: privKeyPath, PassFunc: passFunc}
must(sign.SignCmd(ctx, ko, options.RegistryOptions{}, nil, []string{imgName}, "", true, "", false, false, ""), t)
must(sign.SignCmd(ctx, ko, options.RegistryOptions{}, nil, []string{imgName}, "", true, "", "", false, false, ""), t)

// Now verify and download should work!
must(verify(pubKeyPath, imgName, true, nil, ""), t)
Expand Down Expand Up @@ -233,7 +233,7 @@ func TestBundle(t *testing.T) {
}

// Sign the image
must(sign.SignCmd(ctx, ko, options.RegistryOptions{}, nil, []string{imgName}, "", true, "", false, false, ""), t)
must(sign.SignCmd(ctx, ko, options.RegistryOptions{}, nil, []string{imgName}, "", true, "", "", false, false, ""), t)
// Make sure verify works
must(verify(pubKeyPath, imgName, true, nil, ""), t)

Expand Down Expand Up @@ -263,14 +263,14 @@ func TestDuplicateSign(t *testing.T) {

// Now sign the image
ko := sign.KeyOpts{KeyRef: privKeyPath, PassFunc: passFunc}
must(sign.SignCmd(ctx, ko, options.RegistryOptions{}, nil, []string{imgName}, "", true, "", false, false, ""), t)
must(sign.SignCmd(ctx, ko, options.RegistryOptions{}, nil, []string{imgName}, "", true, "", "", false, false, ""), t)

// Now verify and download should work!
must(verify(pubKeyPath, imgName, true, nil, ""), t)
must(download.SignatureCmd(ctx, options.RegistryOptions{}, imgName), t)

// Signing again should work just fine...
must(sign.SignCmd(ctx, ko, options.RegistryOptions{}, nil, []string{imgName}, "", true, "", false, false, ""), t)
must(sign.SignCmd(ctx, ko, options.RegistryOptions{}, nil, []string{imgName}, "", true, "", "", false, false, ""), t)

se, err := ociremote.SignedEntity(ref, ociremote.WithRemoteOptions(registryClientOpts(ctx)...))
must(err, t)
Expand Down Expand Up @@ -362,14 +362,14 @@ func TestMultipleSignatures(t *testing.T) {

// Now sign the image with one key
ko := sign.KeyOpts{KeyRef: priv1, PassFunc: passFunc}
must(sign.SignCmd(ctx, ko, options.RegistryOptions{}, nil, []string{imgName}, "", true, "", false, false, ""), t)
must(sign.SignCmd(ctx, ko, options.RegistryOptions{}, nil, []string{imgName}, "", true, "", "", false, false, ""), t)
// Now verify should work with that one, but not the other
must(verify(pub1, imgName, true, nil, ""), t)
mustErr(verify(pub2, imgName, true, nil, ""), t)

// Now sign with the other key too
ko.KeyRef = priv2
must(sign.SignCmd(ctx, ko, options.RegistryOptions{}, nil, []string{imgName}, "", true, "", false, false, ""), t)
must(sign.SignCmd(ctx, ko, options.RegistryOptions{}, nil, []string{imgName}, "", true, "", "", false, false, ""), t)

// Now verify should work with both
must(verify(pub1, imgName, true, nil, ""), t)
Expand Down Expand Up @@ -657,7 +657,7 @@ func TestAttachSBOM(t *testing.T) {

// Now sign the sbom with one key
ko1 := sign.KeyOpts{KeyRef: privKeyPath1, PassFunc: passFunc}
must(sign.SignCmd(ctx, ko1, options.RegistryOptions{}, nil, []string{imgName}, "", true, "", false, false, "sbom"), t)
must(sign.SignCmd(ctx, ko1, options.RegistryOptions{}, nil, []string{imgName}, "", true, "", "", false, false, "sbom"), t)

// Now verify should work with that one, but not the other
must(verify(pubKeyPath1, imgName, true, nil, "sbom"), t)
Expand Down Expand Up @@ -695,7 +695,7 @@ func TestTlog(t *testing.T) {
PassFunc: passFunc,
RekorURL: rekorURL,
}
must(sign.SignCmd(ctx, ko, options.RegistryOptions{}, nil, []string{imgName}, "", true, "", false, false, ""), t)
must(sign.SignCmd(ctx, ko, options.RegistryOptions{}, nil, []string{imgName}, "", true, "", "", false, false, ""), t)

// Now verify should work!
must(verify(pubKeyPath, imgName, true, nil, ""), t)
Expand All @@ -707,7 +707,7 @@ func TestTlog(t *testing.T) {
mustErr(verify(pubKeyPath, imgName, true, nil, ""), t)

// Sign again with the tlog env var on
must(sign.SignCmd(ctx, ko, options.RegistryOptions{}, nil, []string{imgName}, "", true, "", false, false, ""), t)
must(sign.SignCmd(ctx, ko, options.RegistryOptions{}, nil, []string{imgName}, "", true, "", "", false, false, ""), t)
// And now verify works!
must(verify(pubKeyPath, imgName, true, nil, ""), t)
}
Expand Down

0 comments on commit 943e824

Please sign in to comment.