Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 35 additions & 24 deletions cmd/notation/verify.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,11 @@ package main

import (
"errors"
"fmt"
"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"
Expand All @@ -18,18 +17,18 @@ import (
type verifyOpts struct {
SecureFlagOpts
reference string
config []string
config string
}

func verifyCommand(opts *verifyOpts) *cobra.Command {
if opts == nil {
opts = &verifyOpts{}
}
command := &cobra.Command{
Use: "verify <reference>",
Use: "verify [flags] <reference>",
Short: "Verifies OCI Artifacts",
Long: `Verifies OCI Artifacts:
notation verify [--config <key>=<value>] [--username <username>] [--password <password>] <reference>`,
notation verify [--config <key>=<value>,...] [--username <username>] [--password <password>] <reference>`,
Args: func(cmd *cobra.Command, args []string) error {
if len(args) == 0 {
return errors.New("missing reference")
Expand All @@ -42,41 +41,38 @@ func verifyCommand(opts *verifyOpts) *cobra.Command {
},
}
opts.ApplyFlags(command.Flags())
command.Flags().StringSliceVar(&opts.config, "config", nil, "verification plugin config (accepts multiple inputs)")
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
}

// initialize verifier.
verifier, err := getVerifier(opts, ref)
if err != nil {
return err
}

// set up verification plugin config.
configs := make(map[string]string)
for _, c := range opts.config {
parts := strings.Split(c, "=")
if len(parts) != 2 {
return fmt.Errorf("invalid config option: %s", c)
}
configs[parts[0]] = parts[1]
configs, err := cmd.ParseFlagPluginConfig(opts.config)
if err != nil {
return err
}
ctx := verification.WithPluginConfig(command.Context(), configs)

// core verify process.
outcomes, err := verifier.Verify(ctx, opts.reference)
ctx := verification.WithPluginConfig(command.Context(), configs)
outcomes, err := verifier.Verify(ctx, ref.String())

// write out.
return ioutil.PrintVerificationResults(os.Stdout, outcomes, err)
return ioutil.PrintVerificationResults(os.Stdout, outcomes, err, ref.Reference)
}

func getVerifier(opts *verifyOpts) (*verification.Verifier, error) {
ref, err := orasregistry.ParseReference(opts.reference)
if err != nil {
return nil, err
}

func getVerifier(opts *verifyOpts, ref orasregistry.Reference) (*verification.Verifier, error) {
authClient, plainHTTP, err := getAuthClient(&opts.SecureFlagOpts, ref)
if err != nil {
return nil, err
Expand All @@ -86,3 +82,18 @@ func getVerifier(opts *verifyOpts) (*verification.Verifier, error) {

return verification.NewVerifier(repo)
}

func resolveReference(command *cobra.Command, opts *verifyOpts) (orasregistry.Reference, error) {
ref, err := orasregistry.ParseReference(opts.reference)
if err != nil {
return orasregistry.Reference{}, err
}

manifestDesc, err := getManifestDescriptorFromReference(command.Context(), &opts.SecureFlagOpts, opts.reference)
if err != nil {
return orasregistry.Reference{}, err
}

ref.Reference = manifestDesc.Digest.String()
return ref, nil
}
5 changes: 2 additions & 3 deletions cmd/notation/verify_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,12 @@ func TestVerifyCommand_MoreArgs(t *testing.T) {
SecureFlagOpts: SecureFlagOpts{
PlainHTTP: true,
},
config: []string{"key1=val1", "key2=val2"},
config: "key1=val1,key2=val2",
}
if err := command.ParseFlags([]string{
expected.reference,
"--plain-http",
"--config", expected.config[0],
"--config", expected.config[1]}); err != nil {
"--config", expected.config}); err != nil {
t.Fatalf("Parse Flag failed: %v", err)
}
if err := command.Args(command, command.Flags().Args()); err != nil {
Expand Down
31 changes: 16 additions & 15 deletions internal/ioutil/print.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,28 +54,29 @@ func PrintCertificateMap(w io.Writer, v []config.CertificateReference) error {
return tw.Flush()
}

func PrintVerificationResults(w io.Writer, v []*verification.SignatureVerificationOutcome, resultErr error) error {
func PrintVerificationResults(w io.Writer, v []*verification.SignatureVerificationOutcome, resultErr error, digest string) error {
tw := newTabWriter(w)

overallResult := "success"
if resultErr != nil {
overallResult = "failure"
if resultErr == nil {
fmt.Fprintf(tw, "%s\n", digest)
return nil
}
fmt.Fprintf(tw, "OVERALL RESULT: %s\n", overallResult)

if resultErr != nil {
fmt.Fprintf(tw, "ERROR: %s\n", resultErr.Error())
printOutcomes(tw, v)
}
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) > 0 {
fmt.Fprintln(tw, "DETAILED ERRORS:")
for _, outcome := range outcomes {
fmt.Println(outcome.Error)
}
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())
}
}