Skip to content

Commit

Permalink
Migrate copy and clean to cobra. Add RegistryOptions to match the sty…
Browse files Browse the repository at this point in the history
…le of other flags. Move init. Move triangulate (#806)

Signed-off-by: Scott Nichols <[email protected]>
  • Loading branch information
n3wscott authored Sep 27, 2021
1 parent a42b124 commit 874644e
Show file tree
Hide file tree
Showing 36 changed files with 365 additions and 216 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/codeql-analysis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ jobs:

# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v1
uses: github/codeql-action/initialize@v1
with:
languages: ${{ matrix.language }}
# queries: ./path/to/local/query, your-org/your-repo/queries@main
Expand Down
4 changes: 2 additions & 2 deletions cmd/cosign/cli/attach/sbom.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ func SBOM() *ffcli.Command {
flagset = flag.NewFlagSet("cosign attach sbom", flag.ExitOnError)
sbom = flagset.String("sbom", "", "path to the sbom, or {-} for stdin")
sbomType = flagset.String("type", "spdx", "type of sbom (spdx|cyclonedx), default spdx")
regOpts options.RegistryOpts
regOpts options.RegistryOptions
)
options.ApplyRegistryFlags(&regOpts, flagset)
return &ffcli.Command{
Expand All @@ -68,7 +68,7 @@ func SBOM() *ffcli.Command {
}
}

func SBOMCmd(ctx context.Context, regOpts options.RegistryOpts, sbomRef string, sbomType types.MediaType, imageRef string) error {
func SBOMCmd(ctx context.Context, regOpts options.RegistryOptions, sbomRef string, sbomType types.MediaType, imageRef string) error {
ref, err := name.ParseReference(imageRef)
if err != nil {
return err
Expand Down
4 changes: 2 additions & 2 deletions cmd/cosign/cli/attach/sig.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ func Signature() *ffcli.Command {
flagset = flag.NewFlagSet("cosign attach signature", flag.ExitOnError)
signature = flagset.String("signature", "", "the signature, path to the signature, or {-} for stdin")
payload = flagset.String("payload", "", "path to the payload covered by the signature (if using another format)")
regOpts options.RegistryOpts
regOpts options.RegistryOptions
)
options.ApplyRegistryFlags(&regOpts, flagset)
return &ffcli.Command{
Expand All @@ -56,7 +56,7 @@ func Signature() *ffcli.Command {
}
}

func SignatureCmd(ctx context.Context, regOpts options.RegistryOpts, sigRef, payloadRef, imageRef string) error {
func SignatureCmd(ctx context.Context, regOpts options.RegistryOptions, sigRef, payloadRef, imageRef string) error {
b64SigBytes, err := signatureBytes(sigRef)
if err != nil {
return err
Expand Down
2 changes: 1 addition & 1 deletion cmd/cosign/cli/attest.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ func addAttest(topLevel *cobra.Command) {
FulcioURL: o.Fulcio.URL,
}
for _, img := range args {
if err := attest.AttestCmd(cmd.Context(), ko, o.RegistryOpts, img, o.Cert, o.Upload, o.Predicate.Path, o.Force, o.Predicate.Type); err != nil {
if err := attest.AttestCmd(cmd.Context(), ko, o.Registry, img, o.Cert, o.Upload, o.Predicate.Path, o.Force, o.Predicate.Type); err != nil {
return errors.Wrapf(err, "signing %s", img)
}
}
Expand Down
4 changes: 2 additions & 2 deletions cmd/cosign/cli/attest/attest.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ func Attest() *ffcli.Command {
force = flagset.Bool("f", false, "skip warnings and confirmations")
idToken = flagset.String("identity-token", "", "[EXPERIMENTAL] identity token to use for certificate from fulcio")
predicateType = flagset.String("type", "custom", "specify predicate type (default: custom) (slsaprovenance|link|spdx)")
regOpts options.RegistryOpts
regOpts options.RegistryOptions
)
options.ApplyRegistryFlags(&regOpts, flagset)
return &ffcli.Command{
Expand Down Expand Up @@ -125,7 +125,7 @@ var predicateTypeMap = map[string]string{
}

//nolint
func AttestCmd(ctx context.Context, ko sign.KeyOpts, regOpts options.RegistryOpts, imageRef string, certPath string,
func AttestCmd(ctx context.Context, ko sign.KeyOpts, regOpts options.RegistryOptions, imageRef string, certPath string,
upload bool, predicatePath string, force bool, predicateType string) error {
// A key file or token is required unless we're in experimental mode!
if options.EnableExperimental() {
Expand Down
34 changes: 27 additions & 7 deletions cmd/cosign/cli/clean.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,39 @@ import (
"github.com/google/go-containerregistry/pkg/name"
"github.com/google/go-containerregistry/pkg/v1/remote"
"github.com/peterbourgon/ff/v3/ffcli"
"github.com/spf13/cobra"

"github.com/sigstore/cosign/cmd/cosign/cli/options"
ociremote "github.com/sigstore/cosign/pkg/oci/remote"
)

func addClean(topLevel *cobra.Command) {
o := &options.RegistryOptions{}

cmd := &cobra.Command{
Use: "clean",
Short: "Remove all signatures from an image.\ncosign clean <image uri>",
Long: "Remove all signatures from an image.",

RunE: func(cmd *cobra.Command, args []string) error {
if len(args) != 1 {
return flag.ErrHelp
}

return CleanCmd(cmd.Context(), *o, args[0])
},
}

o.AddFlags(cmd)
topLevel.AddCommand(cmd)
}

// Clean subcommand for ffcli.
// Deprecated: this will be deleted when the migration from ffcli to cobra is done.
func Clean() *ffcli.Command {
var (
flagset = flag.NewFlagSet("cosign clean", flag.ExitOnError)
regOpts options.RegistryOpts
regOpts options.RegistryOptions
)
options.ApplyRegistryFlags(&regOpts, flagset)
return &ffcli.Command{
Expand All @@ -41,16 +65,12 @@ func Clean() *ffcli.Command {
ShortHelp: "Remove all signatures from an image",
FlagSet: flagset,
Exec: func(ctx context.Context, args []string) error {
if len(args) != 1 {
return flag.ErrHelp
}

return CleanCmd(ctx, regOpts, args[0])
panic("this command is now implemented in cobra.")
},
}
}

func CleanCmd(ctx context.Context, regOpts options.RegistryOpts, imageRef string) error {
func CleanCmd(ctx context.Context, regOpts options.RegistryOptions, imageRef string) error {
ref, err := name.ParseReference(imageRef)
if err != nil {
return err
Expand Down
14 changes: 10 additions & 4 deletions cmd/cosign/cli/commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ import (
"flag"
"fmt"

"github.com/sigstore/cosign/cmd/cosign/cli/triangulate"

"os"

"github.com/google/go-containerregistry/pkg/logs"
Expand All @@ -29,9 +31,11 @@ import (

"github.com/sigstore/cosign/cmd/cosign/cli/attach"
"github.com/sigstore/cosign/cmd/cosign/cli/attest"
"github.com/sigstore/cosign/cmd/cosign/cli/copy"
"github.com/sigstore/cosign/cmd/cosign/cli/dockerfile"
"github.com/sigstore/cosign/cmd/cosign/cli/download"
"github.com/sigstore/cosign/cmd/cosign/cli/generate"
"github.com/sigstore/cosign/cmd/cosign/cli/initialize"
"github.com/sigstore/cosign/cmd/cosign/cli/manifest"
"github.com/sigstore/cosign/cmd/cosign/cli/options"
"github.com/sigstore/cosign/cmd/cosign/cli/pivcli"
Expand Down Expand Up @@ -76,11 +80,11 @@ func New() *cobra.Command {
// PIV sub-tree
pivcli.PivKey(),
// PIV sub-tree
Copy(),
copy.Copy(),
Clean(),
Triangulate(),
// Init
Init(),
triangulate.Triangulate(),
// Initialize
initialize.Initialize(),
// Version
Version()},
Exec: func(context.Context, []string) error {
Expand Down Expand Up @@ -125,6 +129,8 @@ func New() *cobra.Command {
addSignBlob(cmd)
addGenerateKeyPair(cmd)
addAttest(cmd)
addCopy(cmd)
addClean(cmd)
addVersion(cmd)

return cmd
Expand Down
109 changes: 16 additions & 93 deletions cmd/cosign/cli/copy.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
//
// Copyright 2021 The Sigstore Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
Expand All @@ -15,117 +16,39 @@
package cli

import (
"context"
"flag"
"fmt"

"github.com/google/go-containerregistry/pkg/name"
v1 "github.com/google/go-containerregistry/pkg/v1"
"github.com/google/go-containerregistry/pkg/v1/remote"
"github.com/peterbourgon/ff/v3/ffcli"
"github.com/spf13/cobra"

"github.com/sigstore/cosign/cmd/cosign/cli/copy"
"github.com/sigstore/cosign/cmd/cosign/cli/options"
ociremote "github.com/sigstore/cosign/pkg/oci/remote"
)

func Copy() *ffcli.Command {
var (
flagset = flag.NewFlagSet("cosign copy", flag.ExitOnError)
sigOnlyFlag = flagset.Bool("sig-only", false, "only copy the image signature")
forceFlag = flagset.Bool("f", false, "overwrite destination image(s), if necessary")
regOpts options.RegistryOpts
)
options.ApplyRegistryFlags(&regOpts, flagset)
return &ffcli.Command{
Name: "copy",
ShortUsage: "cosign copy <source image> <destination image>",
ShortHelp: `Copy the supplied container image and signatures.`,
LongHelp: `Copy the supplied container image and signatures.
func addCopy(topLevel *cobra.Command) {
o := &options.CopyOptions{}

EXAMPLES
cmd := &cobra.Command{
Use: "copy",
Short: "Copy the supplied container image and signatures.\ncosign copy <source image> <destination image>",
Long: "Copy the supplied container image and signatures.",
Example: `
# copy a container image and its signatures
cosign copy example.com/src:latest example.com/dest:latest
# copy the signatures only
cosign copy -sig-only example.com/src example.com/dest
# overwrite destination image and signatures
cosign copy -f example.com/src example.com/dest
`,
FlagSet: flagset,
Exec: func(ctx context.Context, args []string) error {
cosign copy -f example.com/src example.com/dest`,

RunE: func(cmd *cobra.Command, args []string) error {
if len(args) != 2 {
return flag.ErrHelp
}
return CopyCmd(ctx, regOpts, args[0], args[1], *sigOnlyFlag, *forceFlag)
return copy.CopyCmd(cmd.Context(), o.Registry, args[0], args[1], o.SignatureOnly, o.Force)
},
}
}

func CopyCmd(ctx context.Context, regOpts options.RegistryOpts, srcImg, dstImg string, sigOnly, force bool) error {
srcRef, err := name.ParseReference(srcImg)
if err != nil {
return err
}
dstRef, err := name.ParseReference(dstImg)
if err != nil {
return err
}

remoteOpts := regOpts.GetRegistryClientOpts(ctx)
sigSrcRef, err := ociremote.SignatureTag(srcRef, ociremote.WithRemoteOptions(remoteOpts...))
if err != nil {
return err
}

dstRepoRef := dstRef.Context()
sigDstRef := dstRepoRef.Tag(sigSrcRef.Identifier())
if err := copyImage(sigSrcRef, sigDstRef, force, remoteOpts...); err != nil {
return err
}

if !sigOnly {
if err := copyImage(srcRef, dstRef, force, remoteOpts...); err != nil {
return err
}
}

return nil
}

func descriptorsEqual(a, b *v1.Descriptor) bool {
if a == nil || b == nil {
return a == nil && b == nil
}
return a.Digest == b.Digest
}

func copyImage(src, dest name.Reference, overwrite bool, opts ...remote.Option) error {
got, err := remote.Get(src, opts...)
if err != nil {
return err
}

if !overwrite {
if dstDesc, err := remote.Head(dest, opts...); err == nil {
if descriptorsEqual(&got.Descriptor, dstDesc) {
return nil
}
return fmt.Errorf("image %q already exists. Use `-f` to overwrite", dest.Name())
}
}

if got.MediaType.IsIndex() {
imgIdx, err := got.ImageIndex()
if err != nil {
return err
}
return remote.WriteIndex(dest, imgIdx, opts...)
}

img, err := got.Image()
if err != nil {
return err
}
return remote.Write(dest, img, opts...)
o.AddFlags(cmd)
topLevel.AddCommand(cmd)
}
Loading

0 comments on commit 874644e

Please sign in to comment.