From b9b1209ec1395f314e2de9623ea7c540558467b1 Mon Sep 17 00:00:00 2001 From: Binbin Li Date: Tue, 11 Oct 2022 03:38:49 +0000 Subject: [PATCH 1/6] feat: use new verify workflow Signed-off-by: Binbin Li --- cmd/notation/verify.go | 164 ++++++++++-------------------------- cmd/notation/verify_test.go | 40 ++------- go.mod | 4 + go.sum | 24 ++++++ internal/ioutil/print.go | 28 ++++++ 5 files changed, 107 insertions(+), 153 deletions(-) diff --git a/cmd/notation/verify.go b/cmd/notation/verify.go index 367c02b38..3fea9e721 100644 --- a/cmd/notation/verify.go +++ b/cmd/notation/verify.go @@ -1,31 +1,23 @@ package main import ( - "context" "errors" - "fmt" "os" - "github.com/notaryproject/notation-go" - "github.com/notaryproject/notation-go/dir" - "github.com/notaryproject/notation-go/signature" + "github.com/notaryproject/notation-go/registry" + "github.com/notaryproject/notation-go/verification" "github.com/notaryproject/notation/internal/cmd" - "github.com/notaryproject/notation/internal/envelope" - "github.com/notaryproject/notation/internal/slices" - "github.com/notaryproject/notation/pkg/cache" - "github.com/notaryproject/notation/pkg/configutil" - "github.com/opencontainers/go-digest" + "github.com/notaryproject/notation/internal/ioutil" + + orasregistry "oras.land/oras-go/v2/registry" "github.com/spf13/cobra" ) type verifyOpts struct { - RemoteFlagOpts - signatures []string - certs []string - certFiles []string - pull bool - reference string + SecureFlagOpts + reference string + config string } func verifyCommand(opts *verifyOpts) *cobra.Command { @@ -33,21 +25,10 @@ func verifyCommand(opts *verifyOpts) *cobra.Command { opts = &verifyOpts{} } command := &cobra.Command{ - Use: "verify [reference]", - Short: "Verify OCI artifacts", - Long: `Verify OCI artifacts - -Prerequisite: a trusted certificate needs to be generated or added using the command "notation cert". - -Example - Verify a signature using the trusted certificate: - notation verify /: - -Example - Verify a signature associated with an OCI artifact identified by the digest: - notation verify /@ - -Example - Verify a signature using a trusted certificate in a specified path: - notation verify --cert-file /: -`, + Use: "verify [flags] ", + Short: "Verifies OCI Artifacts", + Long: `Verifies OCI Artifacts: + notation verify [--config =,...] [--username ] [--password ] `, Args: func(cmd *cobra.Command, args []string) error { if len(args) == 0 { return errors.New("missing reference") @@ -59,119 +40,60 @@ Example - Verify a signature using a trusted certificate in a specified path: return runVerify(cmd, opts) }, } - setFlagSignature(command.Flags(), &opts.signatures) - command.Flags().StringSliceVarP(&opts.certs, "cert", "c", []string{}, "certificate names for verification") - command.Flags().StringSliceVar(&opts.certFiles, cmd.PflagCertFile.Name, []string{}, "certificate files for verification") - command.Flags().BoolVar(&opts.pull, "pull", true, "pull remote signatures before verification") opts.ApplyFlags(command.Flags()) + command.Flags().StringVarP(&opts.config, "config", "c", "", "list of comma-separated {key}={value} pairs that are passed as is to the plugin") return command } func runVerify(command *cobra.Command, opts *verifyOpts) error { - // initialize - verifier, err := getVerifier(opts) + // resolve the given reference and set the digest. + ref, err := resolveReference(command, opts) if err != nil { return err } - manifestDesc, err := getManifestDescriptorFromContext(command.Context(), &opts.RemoteFlagOpts, opts.reference) + + // initialize verifier. + verifier, err := getVerifier(opts, ref) if err != nil { return err } - sigPaths := opts.signatures - if len(sigPaths) == 0 { - if !opts.Local && opts.pull { - if err := pullSignatures(command, opts.reference, &opts.SecureFlagOpts, digest.Digest(manifestDesc.Digest)); err != nil { - return err - } - } - manifestDigest := digest.Digest(manifestDesc.Digest) - sigDigests, err := cache.SignatureDigests(manifestDigest) - if err != nil { - return err - } - for _, sigDigest := range sigDigests { - sigPaths = append(sigPaths, dir.Path.CachedSignature(manifestDigest, sigDigest)) - } - } - - // core process - if err := verifySignatures(command.Context(), verifier, manifestDesc, sigPaths); err != nil { + // set up verification plugin config. + configs, err := cmd.ParseFlagPluginConfig(opts.config) + if err != nil { return err } - // write out - fmt.Println(manifestDesc.Digest) - return nil + // core verify process. + ctx := verification.WithPluginConfig(command.Context(), configs) + outcomes, err := verifier.Verify(ctx, ref.String()) + + // write out. + return ioutil.PrintVerificationResults(os.Stdout, outcomes, err, ref.Reference) } -func verifySignatures(ctx context.Context, verifier notation.Verifier, manifestDesc notation.Descriptor, sigPaths []string) error { - if len(sigPaths) == 0 { - return errors.New("verification failure: no signatures found") +func getVerifier(opts *verifyOpts, ref orasregistry.Reference) (*verification.Verifier, error) { + authClient, plainHTTP, err := getAuthClient(&opts.SecureFlagOpts, ref) + if err != nil { + return nil, err } - var lastErr error - for _, path := range sigPaths { - sig, err := os.ReadFile(path) - if err != nil { - lastErr = fmt.Errorf("verification failure: %v", err) - continue - } - // pass in nonempty annotations if needed - sigMediaType, err := envelope.SpeculateSignatureEnvelopeFormat(sig) - if err != nil { - lastErr = fmt.Errorf("verification failure: %v", err) - continue - } - opts := notation.VerifyOptions{ - SignatureMediaType: sigMediaType, - } - desc, err := verifier.Verify(ctx, sig, opts) - if err != nil { - lastErr = fmt.Errorf("verification failure: %v", err) - continue - } - - if !desc.Equal(manifestDesc) { - lastErr = fmt.Errorf("verification failure: %s", manifestDesc.Digest) - continue - } - return nil - } - return lastErr + repo := registry.NewRepositoryClient(authClient, ref, plainHTTP) + + return verification.NewVerifier(repo) } -func getVerifier(opts *verifyOpts) (notation.Verifier, error) { - certPaths, err := appendCertPathFromName(opts.certFiles, opts.certs) +func resolveReference(command *cobra.Command, opts *verifyOpts) (orasregistry.Reference, error) { + ref, err := orasregistry.ParseReference(opts.reference) if err != nil { - return nil, err - } - if len(certPaths) == 0 { - cfg, err := configutil.LoadConfigOnce() - if err != nil { - return nil, err - } - if len(cfg.VerificationCertificates.Certificates) == 0 { - return nil, errors.New("trust certificate not specified") - } - for _, ref := range cfg.VerificationCertificates.Certificates { - certPaths = append(certPaths, ref.Path) - } + return orasregistry.Reference{}, err } - return signature.NewVerifierFromFiles(certPaths) -} -func appendCertPathFromName(paths, names []string) ([]string, error) { - for _, name := range names { - cfg, err := configutil.LoadConfigOnce() - if err != nil { - return nil, err - } - idx := slices.Index(cfg.VerificationCertificates.Certificates, name) - if idx < 0 { - return nil, errors.New("verification certificate not found: " + name) - } - paths = append(paths, cfg.VerificationCertificates.Certificates[idx].Path) + manifestDesc, err := getManifestDescriptorFromReference(command.Context(), &opts.SecureFlagOpts, opts.reference) + if err != nil { + return orasregistry.Reference{}, err } - return paths, nil + + ref.Reference = manifestDesc.Digest.String() + return ref, nil } diff --git a/cmd/notation/verify_test.go b/cmd/notation/verify_test.go index 64c98f27d..ff3de9c7a 100644 --- a/cmd/notation/verify_test.go +++ b/cmd/notation/verify_test.go @@ -10,30 +10,15 @@ func TestVerifyCommand_BasicArgs(t *testing.T) { command := verifyCommand(opts) expected := &verifyOpts{ reference: "ref", - RemoteFlagOpts: RemoteFlagOpts{ - SecureFlagOpts: SecureFlagOpts{ - Username: "user", - Password: "password", - }, - CommonFlagOpts: CommonFlagOpts{ - MediaType: defaultMediaType, - }, + SecureFlagOpts: SecureFlagOpts{ + Username: "user", + Password: "password", }, - certs: []string{"cert0", "cert1"}, - certFiles: []string{"certfile0", "certfile1"}, - signatures: []string{"sig0", "sig1"}, - pull: true, } if err := command.ParseFlags([]string{ expected.reference, "--username", expected.Username, - "--password", expected.Password, - "-c", expected.certs[0], - "--cert", expected.certs[1], - "--cert-file", expected.certFiles[0], - "--cert-file", expected.certFiles[1], - "--signature", expected.signatures[0], - "-s", expected.signatures[1]}); err != nil { + "--password", expected.Password}); err != nil { t.Fatalf("Parse Flag failed: %v", err) } if err := command.Args(command, command.Flags().Args()); err != nil { @@ -49,24 +34,15 @@ func TestVerifyCommand_MoreArgs(t *testing.T) { command := verifyCommand(opts) expected := &verifyOpts{ reference: "ref", - RemoteFlagOpts: RemoteFlagOpts{ - SecureFlagOpts: SecureFlagOpts{ - PlainHTTP: true, - }, - CommonFlagOpts: CommonFlagOpts{ - MediaType: "mediaT", - }, + SecureFlagOpts: SecureFlagOpts{ + PlainHTTP: true, }, - certs: []string{}, - certFiles: []string{}, - signatures: []string{}, - pull: false, + config: "key1=val1,key2=val2", } if err := command.ParseFlags([]string{ expected.reference, "--plain-http", - "--pull=false", - "--media-type=mediaT"}); err != nil { + "--config", expected.config}); err != nil { t.Fatalf("Parse Flag failed: %v", err) } if err := command.Args(command, command.Flags().Args()); err != nil { diff --git a/go.mod b/go.mod index a25c2ff6b..235c264ff 100644 --- a/go.mod +++ b/go.mod @@ -15,13 +15,17 @@ require ( ) require ( + github.com/Azure/go-ntlmssp v0.0.0-20220621081337-cb9428e4ac1e // indirect github.com/fxamacker/cbor/v2 v2.4.0 // indirect + github.com/go-asn1-ber/asn1-ber v1.5.4 // indirect + github.com/go-ldap/ldap/v3 v3.4.4 // indirect github.com/golang-jwt/jwt/v4 v4.4.2 // indirect github.com/inconshreveable/mousetrap v1.0.0 // indirect github.com/opencontainers/distribution-spec/specs-go v0.0.0-20220620172159-4ab4752c3b86 // indirect github.com/opencontainers/image-spec v1.0.3-0.20211202183452-c5a74bcca799 // indirect github.com/oras-project/artifacts-spec v1.0.0-rc.2 // indirect github.com/x448/float16 v0.8.4 // indirect + golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d // indirect golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 // indirect golang.org/x/sys v0.0.0-20220825204002-c680a09ffe64 // indirect ) diff --git a/go.sum b/go.sum index cc7e667db..07166ac5d 100644 --- a/go.sum +++ b/go.sum @@ -1,10 +1,18 @@ +github.com/Azure/go-ntlmssp v0.0.0-20220621081337-cb9428e4ac1e h1:NeAW1fUYUEWhft7pkxDf6WoUvEZJ/uOKsvtpjLnn8MU= +github.com/Azure/go-ntlmssp v0.0.0-20220621081337-cb9428e4ac1e/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/distribution/distribution/v3 v3.0.0-20220729163034-26163d82560f h1:3NCYdjXycNd/Xn/iICZzmxkiDX1e1cjTHjbMAz+wRVk= github.com/distribution/distribution/v3 v3.0.0-20220729163034-26163d82560f/go.mod h1:28YO/VJk9/64+sTGNuYaBjWxrXTPrj0C0XmgTIOjxX4= github.com/docker/docker-credential-helpers v0.7.0 h1:xtCHsjxogADNZcdv1pKUHXryefjlVRqWqIhk/uXJp0A= github.com/docker/docker-credential-helpers v0.7.0/go.mod h1:rETQfLdHNT3foU5kuNkFR1R1V12OJRRO5lzt2D1b5X0= github.com/fxamacker/cbor/v2 v2.4.0 h1:ri0ArlOR+5XunOP8CRUowT0pSJOwhW098ZCUyskZD88= github.com/fxamacker/cbor/v2 v2.4.0/go.mod h1:TA1xS00nchWmaBnEIxPSE5oHLuJBAVvqrtAnWBwBCVo= +github.com/go-asn1-ber/asn1-ber v1.5.4 h1:vXT6d/FNDiELJnLb6hGNa309LMsrCoYFvpwHDF0+Y1A= +github.com/go-asn1-ber/asn1-ber v1.5.4/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0= +github.com/go-ldap/ldap/v3 v3.4.4 h1:qPjipEpt+qDa6SI/h1fzuGWoRUY+qqQ9sOZq67/PYUs= +github.com/go-ldap/ldap/v3 v3.4.4/go.mod h1:fe1MsuN5eJJ1FeLT/LEBVdWfNWKh459R7aXgXtJC+aI= github.com/golang-jwt/jwt/v4 v4.4.2 h1:rcc4lwaZgFMCZ5jxF9ABolDcIHdBytAFgqFPbSJQAYs= github.com/golang-jwt/jwt/v4 v4.4.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= @@ -21,20 +29,36 @@ github.com/opencontainers/image-spec v1.0.3-0.20211202183452-c5a74bcca799 h1:rc3 github.com/opencontainers/image-spec v1.0.3-0.20211202183452-c5a74bcca799/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= github.com/oras-project/artifacts-spec v1.0.0-rc.2 h1:9SMCNSxkJEHqWGDiMCuy6TXHgvjgwXGdXZZGXLKQvVE= github.com/oras-project/artifacts-spec v1.0.0-rc.2/go.mod h1:Xch2aLzSwtkhbFFN6LUzTfLtukYvMMdXJ4oZ8O7BOdc= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/spf13/cobra v1.5.0 h1:X+jTBEBqF0bHN+9cSMgmfuvv2VHJ9ezmFNf9Y/XstYU= github.com/spf13/cobra v1.5.0/go.mod h1:dWXEIy2H428czQCjInthrTRUg7yKbok+2Qi/yBIJoUM= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.7.2 h1:4jaiDzPyXQvSd7D0EjG45355tLlV3VOECpq10pLC+8s= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= github.com/veraison/go-cose v1.0.0-rc.1.0.20220824135457-9d2fab636b83 h1:g8vDfnNOPcGzg6mnlBGc0J5t5lAJkaepXqbc9qFRnFs= github.com/veraison/go-cose v1.0.0-rc.1.0.20220824135457-9d2fab636b83/go.mod h1:7ziE85vSq4ScFTg6wyoMXjucIGOf4JkFEZi/an96Ct4= github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= +golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d h1:sK3txAijHtOK88l68nt020reeT1ZdKLIYetKl95FzVY= +golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 h1:uVc8UZUe6tr40fFVnUP5Oj+veunVezqYl9z7DYw9xzw= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220825204002-c680a09ffe64 h1:UiNENfZ8gDvpiWw7IpOMQ27spWmThO1RwwdQVbJahJM= golang.org/x/sys v0.0.0-20220825204002-c680a09ffe64/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= oras.land/oras-go/v2 v2.0.0-rc.3 h1:O4GeIwJ9Ge7rbCkqa/M7DLrL55ww+ZEc+Rhc63OYitU= oras.land/oras-go/v2 v2.0.0-rc.3/go.mod h1:PrY+cCglzK/DrQoJUtxbYVbL94ZHecVS3eJR01RglpE= diff --git a/internal/ioutil/print.go b/internal/ioutil/print.go index 3e62c1c33..7156f9ed3 100644 --- a/internal/ioutil/print.go +++ b/internal/ioutil/print.go @@ -7,6 +7,7 @@ import ( "github.com/notaryproject/notation-go/config" "github.com/notaryproject/notation-go/plugin/manager" + "github.com/notaryproject/notation-go/verification" ) func newTabWriter(w io.Writer) *tabwriter.Writer { @@ -52,3 +53,30 @@ func PrintCertificateMap(w io.Writer, v []config.CertificateReference) error { } return tw.Flush() } + +func PrintVerificationResults(w io.Writer, v []*verification.SignatureVerificationOutcome, resultErr error, digest string) error { + tw := newTabWriter(w) + + if resultErr == nil { + fmt.Fprintf(tw, "%s\n", digest) + return nil + } + + fmt.Fprintf(tw, "ERROR: %s\n\n", resultErr.Error()) + printOutcomes(tw, v) + + return tw.Flush() +} + +func printOutcomes(tw *tabwriter.Writer, outcomes []*verification.SignatureVerificationOutcome) { + if len(outcomes) == 1 { + fmt.Println("1 signature failed verification, error is listed as below:") + } else { + fmt.Printf("%d signatures failed verification, errors are listed as below:\n", len(outcomes)) + } + + for _, outcome := range outcomes { + // TODO: print out the signature digest once the outcome contains it. + fmt.Printf("%s\n\n", outcome.Error.Error()) + } +} From 819281d0dd611acf7daf7ef64f6cf87eac1e9ff7 Mon Sep 17 00:00:00 2001 From: Binbin Li Date: Wed, 12 Oct 2022 05:11:55 +0000 Subject: [PATCH 2/6] refactor: refactor Signed-off-by: Binbin Li --- cmd/notation/verify.go | 27 +++++++++++++++++++++------ cmd/notation/verify_test.go | 4 ++-- 2 files changed, 23 insertions(+), 8 deletions(-) diff --git a/cmd/notation/verify.go b/cmd/notation/verify.go index 3fea9e721..59b96d9b2 100644 --- a/cmd/notation/verify.go +++ b/cmd/notation/verify.go @@ -3,21 +3,21 @@ package main import ( "errors" "os" + "strings" "github.com/notaryproject/notation-go/registry" "github.com/notaryproject/notation-go/verification" "github.com/notaryproject/notation/internal/cmd" "github.com/notaryproject/notation/internal/ioutil" - orasregistry "oras.land/oras-go/v2/registry" - "github.com/spf13/cobra" + orasregistry "oras.land/oras-go/v2/registry" ) type verifyOpts struct { SecureFlagOpts - reference string - config string + reference string + pluginConfig string } func verifyCommand(opts *verifyOpts) *cobra.Command { @@ -41,7 +41,7 @@ func verifyCommand(opts *verifyOpts) *cobra.Command { }, } opts.ApplyFlags(command.Flags()) - command.Flags().StringVarP(&opts.config, "config", "c", "", "list of comma-separated {key}={value} pairs that are passed as is to the plugin") + command.Flags().StringVarP(&opts.pluginConfig, "config", "c", "", "list of comma-separated {key}={value} pairs that are passed as is to the plugin") return command } @@ -59,7 +59,7 @@ func runVerify(command *cobra.Command, opts *verifyOpts) error { } // set up verification plugin config. - configs, err := cmd.ParseFlagPluginConfig(opts.config) + configs, err := cmd.ParseFlagPluginConfig(opts.pluginConfig) if err != nil { return err } @@ -89,6 +89,11 @@ func resolveReference(command *cobra.Command, opts *verifyOpts) (orasregistry.Re return orasregistry.Reference{}, err } + if isDigestReference(opts.reference) { + return ref, nil + } + + // Resolve tag reference to digest reference. manifestDesc, err := getManifestDescriptorFromReference(command.Context(), &opts.SecureFlagOpts, opts.reference) if err != nil { return orasregistry.Reference{}, err @@ -97,3 +102,13 @@ func resolveReference(command *cobra.Command, opts *verifyOpts) (orasregistry.Re ref.Reference = manifestDesc.Digest.String() return ref, nil } + +func isDigestReference(reference string) bool { + parts := strings.SplitN(reference, "/", 2) + if len(parts) == 1 { + return false + } + + index := strings.Index(parts[1], "@") + return index != -1 +} diff --git a/cmd/notation/verify_test.go b/cmd/notation/verify_test.go index ff3de9c7a..da87ad347 100644 --- a/cmd/notation/verify_test.go +++ b/cmd/notation/verify_test.go @@ -37,12 +37,12 @@ func TestVerifyCommand_MoreArgs(t *testing.T) { SecureFlagOpts: SecureFlagOpts{ PlainHTTP: true, }, - config: "key1=val1,key2=val2", + pluginConfig: "key1=val1,key2=val2", } if err := command.ParseFlags([]string{ expected.reference, "--plain-http", - "--config", expected.config}); err != nil { + "--config", expected.pluginConfig}); err != nil { t.Fatalf("Parse Flag failed: %v", err) } if err := command.Args(command, command.Flags().Args()); err != nil { From 2860bb2ee67ae0ff799fc829ca4d22f4125257ab Mon Sep 17 00:00:00 2001 From: Binbin Li Date: Fri, 14 Oct 2022 06:38:00 +0000 Subject: [PATCH 3/6] refactor: address pr comments Signed-off-by: Binbin Li --- cmd/notation/verify.go | 16 ++++++++-------- internal/ioutil/print.go | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/cmd/notation/verify.go b/cmd/notation/verify.go index 59b96d9b2..468814906 100644 --- a/cmd/notation/verify.go +++ b/cmd/notation/verify.go @@ -5,13 +5,13 @@ import ( "os" "strings" - "github.com/notaryproject/notation-go/registry" + notationregistry "github.com/notaryproject/notation-go/registry" "github.com/notaryproject/notation-go/verification" "github.com/notaryproject/notation/internal/cmd" "github.com/notaryproject/notation/internal/ioutil" "github.com/spf13/cobra" - orasregistry "oras.land/oras-go/v2/registry" + "oras.land/oras-go/v2/registry" ) type verifyOpts struct { @@ -72,21 +72,21 @@ func runVerify(command *cobra.Command, opts *verifyOpts) error { return ioutil.PrintVerificationResults(os.Stdout, outcomes, err, ref.Reference) } -func getVerifier(opts *verifyOpts, ref orasregistry.Reference) (*verification.Verifier, error) { +func getVerifier(opts *verifyOpts, ref registry.Reference) (*verification.Verifier, error) { authClient, plainHTTP, err := getAuthClient(&opts.SecureFlagOpts, ref) if err != nil { return nil, err } - repo := registry.NewRepositoryClient(authClient, ref, plainHTTP) + repo := notationregistry.NewRepositoryClient(authClient, ref, plainHTTP) return verification.NewVerifier(repo) } -func resolveReference(command *cobra.Command, opts *verifyOpts) (orasregistry.Reference, error) { - ref, err := orasregistry.ParseReference(opts.reference) +func resolveReference(command *cobra.Command, opts *verifyOpts) (registry.Reference, error) { + ref, err := registry.ParseReference(opts.reference) if err != nil { - return orasregistry.Reference{}, err + return registry.Reference{}, err } if isDigestReference(opts.reference) { @@ -96,7 +96,7 @@ func resolveReference(command *cobra.Command, opts *verifyOpts) (orasregistry.Re // Resolve tag reference to digest reference. manifestDesc, err := getManifestDescriptorFromReference(command.Context(), &opts.SecureFlagOpts, opts.reference) if err != nil { - return orasregistry.Reference{}, err + return registry.Reference{}, err } ref.Reference = manifestDesc.Digest.String() diff --git a/internal/ioutil/print.go b/internal/ioutil/print.go index 7156f9ed3..e610ee9e3 100644 --- a/internal/ioutil/print.go +++ b/internal/ioutil/print.go @@ -58,7 +58,7 @@ func PrintVerificationResults(w io.Writer, v []*verification.SignatureVerificati tw := newTabWriter(w) if resultErr == nil { - fmt.Fprintf(tw, "%s\n", digest) + fmt.Fprintf(tw, "Signature verification succeeded for %s\n", digest) return nil } From 6ad56081de84d5e1b3aa09d0936449e11218972c Mon Sep 17 00:00:00 2001 From: Binbin Li Date: Mon, 17 Oct 2022 05:52:58 +0000 Subject: [PATCH 4/6] refactor: refactor result format Signed-off-by: Binbin Li --- internal/ioutil/print.go | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/internal/ioutil/print.go b/internal/ioutil/print.go index e610ee9e3..83d029fc7 100644 --- a/internal/ioutil/print.go +++ b/internal/ioutil/print.go @@ -59,24 +59,18 @@ func PrintVerificationResults(w io.Writer, v []*verification.SignatureVerificati if resultErr == nil { fmt.Fprintf(tw, "Signature verification succeeded for %s\n", digest) + // TODO: print out failed validations as warnings. return nil } fmt.Fprintf(tw, "ERROR: %s\n\n", resultErr.Error()) - printOutcomes(tw, v) + printOutcomes(tw, v, digest) return tw.Flush() } -func printOutcomes(tw *tabwriter.Writer, outcomes []*verification.SignatureVerificationOutcome) { - if len(outcomes) == 1 { - fmt.Println("1 signature failed verification, error is listed as below:") - } else { - fmt.Printf("%d signatures failed verification, errors are listed as below:\n", len(outcomes)) - } +func printOutcomes(tw *tabwriter.Writer, outcomes []*verification.SignatureVerificationOutcome, digest string) { + fmt.Printf("Signature verification failed for all the %d signatures associated with digest: %s\n", len(outcomes), digest) - for _, outcome := range outcomes { - // TODO: print out the signature digest once the outcome contains it. - fmt.Printf("%s\n\n", outcome.Error.Error()) - } + // TODO: print out detailed errors in debug mode. } From 8b6693826ec8314293a9fd9727de6fba0fcd0f5a Mon Sep 17 00:00:00 2001 From: Binbin Li Date: Tue, 18 Oct 2022 03:10:52 +0000 Subject: [PATCH 5/6] refactor: refator input/output format Signed-off-by: Binbin Li --- cmd/notation/verify.go | 9 ++++++--- cmd/notation/verify_test.go | 2 +- internal/ioutil/print.go | 8 ++++++-- 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/cmd/notation/verify.go b/cmd/notation/verify.go index 468814906..2e4d83568 100644 --- a/cmd/notation/verify.go +++ b/cmd/notation/verify.go @@ -27,8 +27,11 @@ func verifyCommand(opts *verifyOpts) *cobra.Command { command := &cobra.Command{ Use: "verify [flags] ", Short: "Verifies OCI Artifacts", - Long: `Verifies OCI Artifacts: - notation verify [--config =,...] [--username ] [--password ] `, + Long: `Verifies OCI Artifacts + +Prerequisite: a trusted certificate needs to be generated or added using the command "notation cert". + +notation verify [--pluginConfig =,...] [--username ] [--password ] `, Args: func(cmd *cobra.Command, args []string) error { if len(args) == 0 { return errors.New("missing reference") @@ -41,7 +44,7 @@ func verifyCommand(opts *verifyOpts) *cobra.Command { }, } opts.ApplyFlags(command.Flags()) - command.Flags().StringVarP(&opts.pluginConfig, "config", "c", "", "list of comma-separated {key}={value} pairs that are passed as is to the plugin") + command.Flags().StringVarP(&opts.pluginConfig, "pluginConfig", "c", "", "list of comma-separated {key}={value} pairs that are passed as is to the plugin") return command } diff --git a/cmd/notation/verify_test.go b/cmd/notation/verify_test.go index da87ad347..ddf5b3be6 100644 --- a/cmd/notation/verify_test.go +++ b/cmd/notation/verify_test.go @@ -42,7 +42,7 @@ func TestVerifyCommand_MoreArgs(t *testing.T) { if err := command.ParseFlags([]string{ expected.reference, "--plain-http", - "--config", expected.pluginConfig}); err != nil { + "--pluginConfig", expected.pluginConfig}); err != nil { t.Fatalf("Parse Flag failed: %v", err) } if err := command.Args(command, command.Flags().Args()); err != nil { diff --git a/internal/ioutil/print.go b/internal/ioutil/print.go index 83d029fc7..f75147649 100644 --- a/internal/ioutil/print.go +++ b/internal/ioutil/print.go @@ -65,12 +65,16 @@ func PrintVerificationResults(w io.Writer, v []*verification.SignatureVerificati fmt.Fprintf(tw, "ERROR: %s\n\n", resultErr.Error()) printOutcomes(tw, v, digest) + tw.Flush() - return tw.Flush() + return resultErr } func printOutcomes(tw *tabwriter.Writer, outcomes []*verification.SignatureVerificationOutcome, digest string) { - fmt.Printf("Signature verification failed for all the %d signatures associated with digest: %s\n", len(outcomes), digest) + fmt.Printf("Signature verification failed for all the %d signatures associated with digest: %s\n\n", len(outcomes), digest) // TODO: print out detailed errors in debug mode. + for idx, outcome := range outcomes { + fmt.Printf("Signature #%d : %s\n", idx+1, outcome.Error.Error()) + } } From 83291271ae748d560c8094a3df19b9155b2c86e8 Mon Sep 17 00:00:00 2001 From: Binbin Li Date: Tue, 18 Oct 2022 04:44:48 +0000 Subject: [PATCH 6/6] refactor: todo to issue link Signed-off-by: Binbin Li --- cmd/notation/verify.go | 4 ++-- cmd/notation/verify_test.go | 2 +- internal/ioutil/print.go | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/cmd/notation/verify.go b/cmd/notation/verify.go index 2e4d83568..6199db2f9 100644 --- a/cmd/notation/verify.go +++ b/cmd/notation/verify.go @@ -31,7 +31,7 @@ func verifyCommand(opts *verifyOpts) *cobra.Command { Prerequisite: a trusted certificate needs to be generated or added using the command "notation cert". -notation verify [--pluginConfig =,...] [--username ] [--password ] `, +notation verify [--plugin-config =,...] [--username ] [--password ] `, Args: func(cmd *cobra.Command, args []string) error { if len(args) == 0 { return errors.New("missing reference") @@ -44,7 +44,7 @@ notation verify [--pluginConfig =,...] [--username ] [--pa }, } opts.ApplyFlags(command.Flags()) - command.Flags().StringVarP(&opts.pluginConfig, "pluginConfig", "c", "", "list of comma-separated {key}={value} pairs that are passed as is to the plugin") + command.Flags().StringVarP(&opts.pluginConfig, "plugin-config", "c", "", "list of comma-separated {key}={value} pairs that are passed as is to the plugin") return command } diff --git a/cmd/notation/verify_test.go b/cmd/notation/verify_test.go index ddf5b3be6..c3f03ee6b 100644 --- a/cmd/notation/verify_test.go +++ b/cmd/notation/verify_test.go @@ -42,7 +42,7 @@ func TestVerifyCommand_MoreArgs(t *testing.T) { if err := command.ParseFlags([]string{ expected.reference, "--plain-http", - "--pluginConfig", expected.pluginConfig}); err != nil { + "--plugin-config", expected.pluginConfig}); err != nil { t.Fatalf("Parse Flag failed: %v", err) } if err := command.Args(command, command.Flags().Args()); err != nil { diff --git a/internal/ioutil/print.go b/internal/ioutil/print.go index f75147649..9f7eca634 100644 --- a/internal/ioutil/print.go +++ b/internal/ioutil/print.go @@ -59,7 +59,7 @@ func PrintVerificationResults(w io.Writer, v []*verification.SignatureVerificati if resultErr == nil { fmt.Fprintf(tw, "Signature verification succeeded for %s\n", digest) - // TODO: print out failed validations as warnings. + // TODO[https://github.com/notaryproject/notation/issues/304]: print out failed validations as warnings. return nil } @@ -73,7 +73,7 @@ func PrintVerificationResults(w io.Writer, v []*verification.SignatureVerificati func printOutcomes(tw *tabwriter.Writer, outcomes []*verification.SignatureVerificationOutcome, digest string) { fmt.Printf("Signature verification failed for all the %d signatures associated with digest: %s\n\n", len(outcomes), digest) - // TODO: print out detailed errors in debug mode. + // TODO[https://github.com/notaryproject/notation/issues/304]: print out detailed errors in debug mode. for idx, outcome := range outcomes { fmt.Printf("Signature #%d : %s\n", idx+1, outcome.Error.Error()) }