diff --git a/cmd/cosign/cli/flags.go b/cmd/cosign/cli/flags.go index acec64c79bc..e1c8395968d 100644 --- a/cmd/cosign/cli/flags.go +++ b/cmd/cosign/cli/flags.go @@ -15,7 +15,10 @@ package cli -import "reflect" +import ( + "reflect" + "strings" +) // oneOf ensures that only one of the supplied interfaces is set to a non-zero value. func oneOf(args ...interface{}) bool { @@ -32,3 +35,16 @@ func nOf(args ...interface{}) int { } return n } + +type StringSlice struct { + slice []string +} + +func (ss *StringSlice) Set(s string) error { + ss.slice = append(ss.slice, s) + return nil +} + +func (ss *StringSlice) String() string { + return strings.Join(ss.slice, ",") +} diff --git a/cmd/cosign/cli/verify.go b/cmd/cosign/cli/verify.go index b88a01eca48..b41e89c8acf 100644 --- a/cmd/cosign/cli/verify.go +++ b/cmd/cosign/cli/verify.go @@ -20,6 +20,7 @@ import ( "encoding/json" "flag" "fmt" + "io/ioutil" "os" "github.com/google/go-containerregistry/pkg/name" @@ -42,6 +43,7 @@ type VerifyCommand struct { Output string RekorURL string Annotations *map[string]interface{} + Files StringSlice } func applyVerifyFlags(cmd *VerifyCommand, flagset *flag.FlagSet) { @@ -53,6 +55,8 @@ func applyVerifyFlags(cmd *VerifyCommand, flagset *flag.FlagSet) { flagset.BoolVar(&cmd.CheckClaims, "check-claims", true, "whether to check the claims found") flagset.StringVar(&cmd.Output, "output", "json", "output the signing image information. Default JSON.") + flagset.Var(&cmd.Files, "f", "files to validate (kubernetes manifests or Dockerfiles)") + // parse annotations flagset.Var(&annotations, "a", "extra key=value pairs to sign") cmd.Annotations = &annotations.annotations @@ -103,7 +107,7 @@ EXAMPLES // Exec runs the verification command func (c *VerifyCommand) Exec(ctx context.Context, args []string) (err error) { - if len(args) == 0 { + if len(args) == 0 && len(c.Files.slice) == 0 { return flag.ErrHelp } @@ -145,7 +149,26 @@ func (c *VerifyCommand) Exec(ctx context.Context, args []string) (err error) { } co.SigVerifier = pubKey - for _, imageRef := range args { + allImgs := []string{} + allImgs = append(allImgs, args...) + + for _, f := range c.Files.slice { + err := isExtensionAllowed(f) + if err != nil { + return errors.Wrap(err, "check if extension is valid") + } + manifest, err := ioutil.ReadFile(f) + if err != nil { + return fmt.Errorf("could not read manifest: %v", err) + } + imgs, err := getImagesFromYamlManifest(string(manifest)) + if err != nil { + return err + } + allImgs = append(allImgs, imgs...) + } + + for _, imageRef := range allImgs { ref, err := name.ParseReference(imageRef) if err != nil { return err diff --git a/cmd/cosign/cli/verify_manifest.go b/cmd/cosign/cli/verify_manifest.go index 99949d82214..de03169495d 100644 --- a/cmd/cosign/cli/verify_manifest.go +++ b/cmd/cosign/cli/verify_manifest.go @@ -89,6 +89,7 @@ EXAMPLES // Exec runs the verification command func (c *VerifyManifestCommand) Exec(ctx context.Context, args []string) error { + fmt.Fprintln(os.Stderr, "This command is deprecated and will be removed in the next release. Please use `cosign verify -f ` instead.") if len(args) != 1 { return flag.ErrHelp } diff --git a/test/e2e_test.sh b/test/e2e_test.sh index 935b144e557..46b1a147b30 100755 --- a/test/e2e_test.sh +++ b/test/e2e_test.sh @@ -60,6 +60,7 @@ if (test_image="ubuntu" ./cosign verify-dockerfile -key ${DISTROLESS_PUB_KEY} ./ # Test `cosign verify-manifest` ./cosign verify-manifest -key ${DISTROLESS_PUB_KEY} ./test/testdata/signed_manifest.yaml if (./cosign verify-manifest -key ${DISTROLESS_PUB_KEY} ./test/testdata/unsigned_manifest.yaml); then false; fi +./cosign verify -key ${DISTROLESS_PUB_KEY} -f ./test/testdata/signed_manifest.yaml # Run the built container to make sure it doesn't crash make ko-local