-
Notifications
You must be signed in to change notification settings - Fork 86
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
refactor: verify display handler (#1167)
Refactor: - move the verify command output related logic to be `VerifyHandler` Example: ```sh notation verify notationreg.azurecr.io/hello-world:v1 Warning: Always verify the artifact using digest(@sha256:...) rather than a tag(:v1) because resolved digest may not point to the same signed artifact, as tags are mutable. Successfully verified signature for notationreg.azurecr.io/hello-world@sha256:d37ada95d47ad12224c205a938129df7a3e52345828b4fa27b03a98825d1e2e7 The artifact was signed with the following user metadata. KEY VALUE foo bar ``` Resolve part of #1151 --------- Signed-off-by: Junjie Gao <[email protected]>
- Loading branch information
Showing
7 changed files
with
212 additions
and
50 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,109 @@ | ||
// Copyright The Notary Project Authors. | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
// Package text provides the text output in human-readable format for metadata | ||
// information. | ||
package text | ||
|
||
import ( | ||
"fmt" | ||
"reflect" | ||
"text/tabwriter" | ||
|
||
"github.com/notaryproject/notation-go" | ||
"github.com/notaryproject/notation-go/verifier/trustpolicy" | ||
"github.com/notaryproject/notation/cmd/notation/internal/display/output" | ||
) | ||
|
||
// VerifyHandler is a handler for rendering output for verify command in | ||
// human-readable format. | ||
type VerifyHandler struct { | ||
printer *output.Printer | ||
|
||
outcome *notation.VerificationOutcome | ||
digestReference string | ||
hasWarning bool | ||
} | ||
|
||
// NewVerifyHandler creates a VerifyHandler to render verification results in | ||
// human-readable format. | ||
func NewVerifyHandler(printer *output.Printer) *VerifyHandler { | ||
return &VerifyHandler{ | ||
printer: printer, | ||
} | ||
} | ||
|
||
// OnResolvingTagReference outputs the tag reference warning. | ||
func (h *VerifyHandler) OnResolvingTagReference(reference string) { | ||
h.printer.PrintErrorf("Warning: Always verify the artifact using digest(@sha256:...) rather than a tag(:%s) because resolved digest may not point to the same signed artifact, as tags are mutable.\n", reference) | ||
h.hasWarning = true | ||
} | ||
|
||
// OnVerifySucceeded sets the successful verification result for the handler. | ||
// | ||
// outcomes must not be nil or empty. | ||
func (h *VerifyHandler) OnVerifySucceeded(outcomes []*notation.VerificationOutcome, digestReference string) { | ||
h.outcome = outcomes[0] | ||
h.digestReference = digestReference | ||
} | ||
|
||
// Render prints out the verification results in human-readable format. | ||
func (h *VerifyHandler) Render() error { | ||
// write out on success | ||
// print out warning for any failed result with logged verification action | ||
for _, result := range h.outcome.VerificationResults { | ||
if result.Error != nil { | ||
// at this point, the verification action has to be logged and | ||
// it's failed | ||
h.printer.PrintErrorf("Warning: %v was set to %q and failed with error: %v\n", result.Type, result.Action, result.Error) | ||
h.hasWarning = true | ||
} | ||
} | ||
if h.hasWarning { | ||
// print a newline to separate the warning from the final message | ||
h.printer.Println() | ||
} | ||
if reflect.DeepEqual(h.outcome.VerificationLevel, trustpolicy.LevelSkip) { | ||
h.printer.Println("Trust policy is configured to skip signature verification for", h.digestReference) | ||
} else { | ||
h.printer.Println("Successfully verified signature for", h.digestReference) | ||
h.printMetadataIfPresent(h.outcome) | ||
} | ||
return nil | ||
} | ||
|
||
func (h *VerifyHandler) printMetadataIfPresent(outcome *notation.VerificationOutcome) { | ||
// the signature envelope is parsed as part of verification. | ||
// since user metadata is only printed on successful verification, | ||
// this error can be ignored | ||
metadata, _ := outcome.UserMetadata() | ||
|
||
if len(metadata) > 0 { | ||
h.printer.Println("\nThe artifact was signed with the following user metadata.") | ||
h.printMetadataMap(metadata) | ||
} | ||
} | ||
|
||
// printMetadataMap prints out metadata given the metatdata map | ||
// | ||
// The metadata is additional information of text output. | ||
func (h *VerifyHandler) printMetadataMap(metadata map[string]string) error { | ||
tw := tabwriter.NewWriter(h.printer, 0, 0, 3, ' ', 0) | ||
fmt.Fprintln(tw, "\nKEY\tVALUE\t") | ||
|
||
for k, v := range metadata { | ||
fmt.Fprintf(tw, "%v\t%v\t\n", k, v) | ||
} | ||
|
||
return tw.Flush() | ||
} |
57 changes: 57 additions & 0 deletions
57
cmd/notation/internal/display/metadata/text/verify_test.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
// Copyright The Notary Project Authors. | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
package text | ||
|
||
import ( | ||
"bytes" | ||
"encoding/json" | ||
"testing" | ||
|
||
"github.com/notaryproject/notation-core-go/signature" | ||
"github.com/notaryproject/notation-go" | ||
"github.com/notaryproject/notation/cmd/notation/internal/display/output" | ||
"github.com/notaryproject/notation/internal/envelope" | ||
ocispec "github.com/opencontainers/image-spec/specs-go/v1" | ||
) | ||
|
||
func TestPrintMetadataIfPresent(t *testing.T) { | ||
payload := &envelope.Payload{ | ||
TargetArtifact: ocispec.Descriptor{ | ||
Annotations: map[string]string{ | ||
"foo": "bar", | ||
}, | ||
}, | ||
} | ||
payloadBytes, _ := json.Marshal(payload) | ||
|
||
outcome := ¬ation.VerificationOutcome{ | ||
EnvelopeContent: &signature.EnvelopeContent{ | ||
Payload: signature.Payload{ | ||
Content: payloadBytes, | ||
}, | ||
}, | ||
} | ||
|
||
t.Run("with metadata", func(t *testing.T) { | ||
buf := bytes.Buffer{} | ||
printer := output.NewPrinter(&buf, &buf) | ||
h := NewVerifyHandler(printer) | ||
h.printMetadataIfPresent(outcome) | ||
got := buf.String() | ||
expected := "\nThe artifact was signed with the following user metadata.\n\nKEY VALUE \nfoo bar \n" | ||
if got != expected { | ||
t.Errorf("unexpected output: %q", got) | ||
} | ||
}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters