Skip to content

Commit

Permalink
feat: add --only flag in cosign copy to copy sign, att & sbom (#3247
Browse files Browse the repository at this point in the history
)

* feat: add only flag to copy sign, att & sbom

Signed-off-by: Vishal Choudhary <[email protected]>

* fix: sigOnly was not used

Signed-off-by: Vishal Choudhary <[email protected]>

* feat: added reviewed changes

Signed-off-by: Vishal Choudhary <[email protected]>

* nit: spelling fix

Signed-off-by: Vishal Choudhary <[email protected]>

---------

Signed-off-by: Vishal Choudhary <[email protected]>
  • Loading branch information
vishal-chdhry authored Oct 17, 2023
1 parent c75d1e3 commit 022fa26
Show file tree
Hide file tree
Showing 5 changed files with 47 additions and 19 deletions.
7 changes: 5 additions & 2 deletions cmd/cosign/cli/copy.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,10 @@ func Copy() *cobra.Command {
cosign copy example.com/src:latest example.com/dest:latest
# copy the signatures only
cosign copy --sig-only example.com/src example.com/dest
cosign copy --only=sign example.com/src example.com/dest
# copy the signatures, attestations, sbom only
cosign copy --only=sign,att,sbom example.com/src example.com/dest
# overwrite destination image and signatures
cosign copy -f example.com/src example.com/dest
Expand All @@ -45,7 +48,7 @@ func Copy() *cobra.Command {
Args: cobra.ExactArgs(2),
PersistentPreRun: options.BindViper,
RunE: func(cmd *cobra.Command, args []string) error {
return copy.CopyCmd(cmd.Context(), o.Registry, args[0], args[1], o.SignatureOnly, o.Force, o.Platform)
return copy.CopyCmd(cmd.Context(), o.Registry, args[0], args[1], o.SignatureOnly, o.Force, o.CopyOnly, o.Platform)
},
}

Expand Down
41 changes: 29 additions & 12 deletions cmd/cosign/cli/copy/copy.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
"net/http"
"os"
"runtime"
"strings"

"github.com/google/go-containerregistry/pkg/name"
v1 "github.com/google/go-containerregistry/pkg/v1"
Expand All @@ -32,11 +33,12 @@ import (
ociremote "github.com/sigstore/cosign/v2/pkg/oci/remote"
"github.com/sigstore/cosign/v2/pkg/oci/walk"
"golang.org/x/sync/errgroup"
"k8s.io/apimachinery/pkg/util/sets"
)

// CopyCmd implements the logic to copy the supplied container image and signatures.
// nolint
func CopyCmd(ctx context.Context, regOpts options.RegistryOptions, srcImg, dstImg string, sigOnly, force bool, platform string) error {
func CopyCmd(ctx context.Context, regOpts options.RegistryOptions, srcImg, dstImg string, sigOnly, force bool, copyOnly, platform string) error {
no := regOpts.NameOptions()
srcRef, err := name.ParseReference(srcImg, no...)
if err != nil {
Expand Down Expand Up @@ -77,6 +79,7 @@ func CopyCmd(ctx context.Context, regOpts options.RegistryOptions, srcImg, dstIm
return err
}

tags := parseOnlyOpt(copyOnly, sigOnly)
if err := walk.SignedEntity(gctx, root, func(ctx context.Context, se oci.SignedEntity) error {
// Both of the SignedEntity types implement Digest()
h, err := se.Digest()
Expand All @@ -99,15 +102,7 @@ func CopyCmd(ctx context.Context, regOpts options.RegistryOptions, srcImg, dstIm
return nil
}

if err := copyTag(ociremote.SignatureTag); err != nil {
return err
}

if sigOnly {
return nil
}

for _, tm := range []tagMap{ociremote.AttestationTag, ociremote.SBOMTag} {
for _, tm := range tags {
if err := copyTag(tm); err != nil {
return err
}
Expand All @@ -130,8 +125,8 @@ func CopyCmd(ctx context.Context, regOpts options.RegistryOptions, srcImg, dstIm
return err
}

// If we're only copying sigs, we have nothing left to do.
if sigOnly {
// If we're only copying sig/att/sbom, we have nothing left to do.
if len(tags) > 0 {
return nil
}

Expand Down Expand Up @@ -178,3 +173,25 @@ func remoteCopy(ctx context.Context, pusher *remote.Pusher, src, dest name.Refer
fmt.Fprintf(os.Stderr, "Copying %s to %s...\n", src, dest)
return pusher.Push(ctx, dest, got)
}

func parseOnlyOpt(str string, sigOnly bool) []tagMap {
var tags []tagMap
items := strings.Split(str, ",")
tagSet := sets.New(items...)

if sigOnly {
fmt.Fprintf(os.Stderr, "--sig-only is deprecated, use --only=sign instead")
tagSet.Insert("sign")
}

if tagSet.Has("sign") {
tags = append(tags, ociremote.SignatureTag)
}
if tagSet.Has("sbom") {
tags = append(tags, ociremote.SBOMTag)
}
if tagSet.Has("att") {
tags = append(tags, ociremote.AttestationTag)
}
return tags
}
4 changes: 2 additions & 2 deletions cmd/cosign/cli/copy/copy_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ func TestCopyAttachmentTagPrefix(t *testing.T) {

err := CopyCmd(ctx, options.RegistryOptions{
RefOpts: refOpts,
}, srcImg, destImg, false, true, "")
}, srcImg, destImg, false, true, "", "")
if err == nil {
t.Fatal("failed to copy with attachment-tag-prefix")
}
Expand All @@ -45,7 +45,7 @@ func TestCopyPlatformOpt(t *testing.T) {
srcImg := "alpine"
destImg := "test-alpine"

err := CopyCmd(ctx, options.RegistryOptions{}, srcImg, destImg, false, true, "linux/amd64")
err := CopyCmd(ctx, options.RegistryOptions{}, srcImg, destImg, false, true, "", "linux/amd64")
if err == nil {
t.Fatal("failed to copy with platform")
}
Expand Down
6 changes: 5 additions & 1 deletion cmd/cosign/cli/options/copy.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (

// CopyOptions is the top level wrapper for the copy command.
type CopyOptions struct {
CopyOnly string
SignatureOnly bool
Force bool
Platform string
Expand All @@ -33,8 +34,11 @@ var _ Interface = (*CopyOptions)(nil)
func (o *CopyOptions) AddFlags(cmd *cobra.Command) {
o.Registry.AddFlags(cmd)

cmd.Flags().StringVar(&o.CopyOnly, "only", "",
"custom string array to only copy specific items, this flag is comma delimited. ex: --only=sbom,sign,att")

cmd.Flags().BoolVar(&o.SignatureOnly, "sig-only", false,
"only copy the image signature")
"[DEPRECATED] only copy the image signature")

cmd.Flags().BoolVarP(&o.Force, "force", "f", false,
"overwrite destination image(s), if necessary")
Expand Down
8 changes: 6 additions & 2 deletions doc/cosign_copy.md

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

0 comments on commit 022fa26

Please sign in to comment.