diff --git a/cmd/cosign/cli/dockerfile/verify.go b/cmd/cosign/cli/dockerfile/verify.go index ec8baa1a159..799ac27ac54 100644 --- a/cmd/cosign/cli/dockerfile/verify.go +++ b/cmd/cosign/cli/dockerfile/verify.go @@ -25,6 +25,7 @@ import ( "strings" "github.com/sigstore/cosign/v2/cmd/cosign/cli/verify" + "github.com/sigstore/cosign/v2/internal/ui" ) // VerifyCommand verifies a signature on a supplied container image @@ -46,7 +47,7 @@ func (c *VerifyDockerfileCommand) Exec(ctx context.Context, args []string) error } defer dockerfile.Close() - images, err := getImagesFromDockerfile(dockerfile) + images, err := getImagesFromDockerfile(ctx, dockerfile) if err != nil { return fmt.Errorf("failed extracting images from Dockerfile: %w", err) } @@ -61,7 +62,7 @@ func (c *VerifyDockerfileCommand) Exec(ctx context.Context, args []string) error return c.VerifyCommand.Exec(ctx, images) } -func getImagesFromDockerfile(dockerfile io.Reader) ([]string, error) { +func getImagesFromDockerfile(ctx context.Context, dockerfile io.Reader) ([]string, error) { var images []string fileScanner := bufio.NewScanner(dockerfile) for fileScanner.Scan() { @@ -69,7 +70,7 @@ func getImagesFromDockerfile(dockerfile io.Reader) ([]string, error) { if strings.HasPrefix(strings.ToUpper(line), "FROM") { switch image := getImageFromLine(line); image { case "scratch": - fmt.Fprintln(os.Stderr, "- scratch image ignored") + ui.Infof(ctx, "- scratch image ignored") default: images = append(images, image) } diff --git a/cmd/cosign/cli/dockerfile/verify_test.go b/cmd/cosign/cli/dockerfile/verify_test.go index 2751a266020..8adf2cc6a54 100644 --- a/cmd/cosign/cli/dockerfile/verify_test.go +++ b/cmd/cosign/cli/dockerfile/verify_test.go @@ -14,6 +14,7 @@ package dockerfile import ( + "context" "os" "reflect" "strings" @@ -93,7 +94,8 @@ func TestGetImagesFromDockerfile(t *testing.T) { os.Setenv(k, v) defer os.Unsetenv(k) } - got, err := getImagesFromDockerfile(strings.NewReader(tc.fileContents)) + ctx := context.Background() + got, err := getImagesFromDockerfile(ctx, strings.NewReader(tc.fileContents)) if err != nil { t.Fatalf("getImagesFromDockerfile returned error: %v", err) } diff --git a/cmd/cosign/cli/download/attestation.go b/cmd/cosign/cli/download/attestation.go index b39c8a1b0a2..46a4d67cc30 100644 --- a/cmd/cosign/cli/download/attestation.go +++ b/cmd/cosign/cli/download/attestation.go @@ -22,7 +22,6 @@ import ( "github.com/google/go-containerregistry/pkg/name" "github.com/sigstore/cosign/v2/cmd/cosign/cli/options" - "github.com/sigstore/cosign/v2/internal/ui" "github.com/sigstore/cosign/v2/pkg/cosign" ) @@ -31,10 +30,6 @@ func AttestationCmd(ctx context.Context, regOpts options.RegistryOptions, attOpt if err != nil { return err } - if _, ok := ref.(name.Digest); !ok { - msg := fmt.Sprintf(ui.TagReferenceMessage, imageRef) - ui.Warnf(ctx, msg) - } ociremoteOpts, err := regOpts.ClientOpts(ctx) if err != nil { return err diff --git a/cmd/cosign/cli/fulcio/fulcioverifier/fulcioverifier.go b/cmd/cosign/cli/fulcio/fulcioverifier/fulcioverifier.go index 146bff483a4..8646bb298bd 100644 --- a/cmd/cosign/cli/fulcio/fulcioverifier/fulcioverifier.go +++ b/cmd/cosign/cli/fulcio/fulcioverifier/fulcioverifier.go @@ -18,10 +18,10 @@ package fulcioverifier import ( "context" "fmt" - "os" "github.com/sigstore/cosign/v2/cmd/cosign/cli/fulcio" "github.com/sigstore/cosign/v2/cmd/cosign/cli/options" + "github.com/sigstore/cosign/v2/internal/ui" "github.com/sigstore/cosign/v2/pkg/cosign" "github.com/sigstore/sigstore/pkg/signature" ) @@ -42,7 +42,7 @@ func NewSigner(ctx context.Context, ko options.KeyOpts, signer signature.SignerV if err := cosign.VerifySCT(ctx, fs.Cert, fs.Chain, fs.SCT, pubKeys); err != nil { return nil, fmt.Errorf("verifying SCT: %w", err) } - fmt.Fprintln(os.Stderr, "Successfully verified SCT...") + ui.Infof(ctx, "Successfully verified SCT...") return fs, nil } diff --git a/cmd/cosign/cli/publickey/public_key.go b/cmd/cosign/cli/publickey/public_key.go index 1f50c21f27a..36158587912 100644 --- a/cmd/cosign/cli/publickey/public_key.go +++ b/cmd/cosign/cli/publickey/public_key.go @@ -19,8 +19,8 @@ import ( "context" "fmt" "io" - "os" + "github.com/sigstore/cosign/v2/internal/ui" "github.com/sigstore/cosign/v2/pkg/cosign" "github.com/sigstore/cosign/v2/pkg/cosign/pivkey" "github.com/sigstore/cosign/v2/pkg/cosign/pkcs11key" @@ -75,7 +75,7 @@ func GetPublicKey(ctx context.Context, opts Pkopts, writer NamedWriter, pf cosig return err } if writer.Name != "" { - fmt.Fprintln(os.Stderr, "Public key written to ", writer.Name) + ui.Infof(ctx, "Public key written to %s", writer.Name) } return nil } diff --git a/cmd/cosign/cli/sign/sign_blob.go b/cmd/cosign/cli/sign/sign_blob.go index 231d808d6aa..8226ebf6a72 100644 --- a/cmd/cosign/cli/sign/sign_blob.go +++ b/cmd/cosign/cli/sign/sign_blob.go @@ -26,6 +26,7 @@ import ( "github.com/sigstore/cosign/v2/internal/pkg/cosign/tsa" "github.com/sigstore/cosign/v2/internal/pkg/cosign/tsa/client" + "github.com/sigstore/cosign/v2/internal/ui" cbundle "github.com/sigstore/cosign/v2/pkg/cosign/bundle" "github.com/sigstore/cosign/v2/cmd/cosign/cli/options" @@ -41,10 +42,13 @@ func SignBlobCmd(ro *options.RootOptions, ko options.KeyOpts, payloadPath string var payload internal.HashReader var err error + ctx, cancel := context.WithTimeout(context.Background(), ro.Timeout) + defer cancel() + if payloadPath == "-" { payload = internal.NewHashReader(os.Stdin, sha256.New()) } else { - fmt.Fprintln(os.Stderr, "Using payload from:", payloadPath) + ui.Infof(ctx, "Using payload from: %s", payloadPath) f, err := os.Open(filepath.Clean(payloadPath)) if err != nil { return nil, err @@ -55,9 +59,6 @@ func SignBlobCmd(ro *options.RootOptions, ko options.KeyOpts, payloadPath string return nil, err } - ctx, cancel := context.WithTimeout(context.Background(), ro.Timeout) - defer cancel() - sv, err := SignerFromKeyOpts(ctx, "", "", ko) if err != nil { return nil, err @@ -95,7 +96,7 @@ func SignBlobCmd(ro *options.RootOptions, ko options.KeyOpts, payloadPath string if err := os.WriteFile(ko.RFC3161TimestampPath, ts, 0600); err != nil { return nil, fmt.Errorf("create RFC3161 timestamp file: %w", err) } - fmt.Fprintf(os.Stderr, "RFC3161 timestamp written to file %s\n", ko.RFC3161TimestampPath) + ui.Infof(ctx, "RFC3161 timestamp written to file %s\n", ko.RFC3161TimestampPath) } shouldUpload, err := ShouldUploadToTlog(ctx, ko, nil, tlogUpload) if err != nil { @@ -114,7 +115,7 @@ func SignBlobCmd(ro *options.RootOptions, ko options.KeyOpts, payloadPath string if err != nil { return nil, err } - fmt.Fprintln(os.Stderr, "tlog entry created with index:", *entry.LogIndex) + ui.Infof(ctx, "tlog entry created with index: %d", *entry.LogIndex) signedPayload.Bundle = cbundle.EntryToBundle(entry) } @@ -135,7 +136,7 @@ func SignBlobCmd(ro *options.RootOptions, ko options.KeyOpts, payloadPath string if err := os.WriteFile(ko.BundlePath, contents, 0600); err != nil { return nil, fmt.Errorf("create bundle file: %w", err) } - fmt.Printf("Bundle wrote in the file %s\n", ko.BundlePath) + ui.Infof(ctx, "Wrote bundle to file %s", ko.BundlePath) } if outputSignature != "" { @@ -146,8 +147,7 @@ func SignBlobCmd(ro *options.RootOptions, ko options.KeyOpts, payloadPath string if err := os.WriteFile(outputSignature, bts, 0600); err != nil { return nil, fmt.Errorf("create signature file: %w", err) } - - fmt.Printf("Signature wrote in the file %s\n", outputSignature) + ui.Infof(ctx, "Wrote signature to file %s", outputSignature) } else { if b64 { sig = []byte(base64.StdEncoding.EncodeToString(sig)) @@ -171,7 +171,7 @@ func SignBlobCmd(ro *options.RootOptions, ko options.KeyOpts, payloadPath string if err := os.WriteFile(outputCertificate, bts, 0600); err != nil { return nil, fmt.Errorf("create certificate file: %w", err) } - fmt.Printf("Certificate wrote in the file %s\n", outputCertificate) + ui.Infof(ctx, "Wrote certificate to file %s", outputCertificate) } } diff --git a/cmd/cosign/cli/verify.go b/cmd/cosign/cli/verify.go index 28d6d2e0e98..bb005f664d5 100644 --- a/cmd/cosign/cli/verify.go +++ b/cmd/cosign/cli/verify.go @@ -17,7 +17,6 @@ package cli import ( "fmt" - "os" "github.com/google/go-containerregistry/pkg/name" @@ -25,6 +24,7 @@ import ( "github.com/sigstore/cosign/v2/cmd/cosign/cli/options" "github.com/sigstore/cosign/v2/cmd/cosign/cli/verify" + "github.com/sigstore/cosign/v2/internal/ui" ) func Verify() *cobra.Command { @@ -125,11 +125,13 @@ against the transparency log.`, v.NameOptions = append(v.NameOptions, name.Insecure) } + ctx := cmd.Context() + if o.CommonVerifyOptions.IgnoreTlog { - fmt.Fprintln(os.Stderr, "**Warning** Skipping tlog verification is an insecure practice that lacks of transparency and auditability verification for the signature.") + ui.Warnf(ctx, "Skipping tlog verification is an insecure practice that lacks of transparency and auditability verification for the signature.") } - return v.Exec(cmd.Context(), args) + return v.Exec(ctx, args) }, } diff --git a/cmd/cosign/cli/verify/verify.go b/cmd/cosign/cli/verify/verify.go index 73de8b4aba7..b2b981a13cc 100644 --- a/cmd/cosign/cli/verify/verify.go +++ b/cmd/cosign/cli/verify/verify.go @@ -35,6 +35,7 @@ import ( "github.com/sigstore/cosign/v2/cmd/cosign/cli/sign" cosignError "github.com/sigstore/cosign/v2/cmd/cosign/errors" "github.com/sigstore/cosign/v2/internal/pkg/cosign/tsa" + "github.com/sigstore/cosign/v2/internal/ui" "github.com/sigstore/cosign/v2/pkg/blob" "github.com/sigstore/cosign/v2/pkg/cosign" "github.com/sigstore/cosign/v2/pkg/cosign/pivkey" @@ -264,8 +265,8 @@ func (c *VerifyCommand) Exec(ctx context.Context, images []string) (err error) { if err != nil { return err } - PrintVerificationHeader(img, co, bundleVerified, fulcioVerified) - PrintVerification(img, verified, c.Output) + PrintVerificationHeader(ctx, img, co, bundleVerified, fulcioVerified) + PrintVerification(ctx, img, verified, c.Output) } else { ref, err := name.ParseReference(img, c.NameOptions...) if err != nil { @@ -281,66 +282,66 @@ func (c *VerifyCommand) Exec(ctx context.Context, images []string) (err error) { return cosignError.WrapError(err) } - PrintVerificationHeader(ref.Name(), co, bundleVerified, fulcioVerified) - PrintVerification(ref.Name(), verified, c.Output) + PrintVerificationHeader(ctx, ref.Name(), co, bundleVerified, fulcioVerified) + PrintVerification(ctx, ref.Name(), verified, c.Output) } } return nil } -func PrintVerificationHeader(imgRef string, co *cosign.CheckOpts, bundleVerified, fulcioVerified bool) { - fmt.Fprintf(os.Stderr, "\nVerification for %s --\n", imgRef) - fmt.Fprintln(os.Stderr, "The following checks were performed on each of these signatures:") +func PrintVerificationHeader(ctx context.Context, imgRef string, co *cosign.CheckOpts, bundleVerified, fulcioVerified bool) { + ui.Infof(ctx, "\nVerification for %s --", imgRef) + ui.Infof(ctx, "The following checks were performed on each of these signatures:") if co.ClaimVerifier != nil { if co.Annotations != nil { - fmt.Fprintln(os.Stderr, " - The specified annotations were verified.") + ui.Infof(ctx, " - The specified annotations were verified.") } - fmt.Fprintln(os.Stderr, " - The cosign claims were validated") + ui.Infof(ctx, " - The cosign claims were validated") } if bundleVerified { - fmt.Fprintln(os.Stderr, " - Existence of the claims in the transparency log was verified offline") + ui.Infof(ctx, " - Existence of the claims in the transparency log was verified offline") } else if co.RekorClient != nil { - fmt.Fprintln(os.Stderr, " - The claims were present in the transparency log") - fmt.Fprintln(os.Stderr, " - The signatures were integrated into the transparency log when the certificate was valid") + ui.Infof(ctx, " - The claims were present in the transparency log") + ui.Infof(ctx, " - The signatures were integrated into the transparency log when the certificate was valid") } if co.SigVerifier != nil { - fmt.Fprintln(os.Stderr, " - The signatures were verified against the specified public key") + ui.Infof(ctx, " - The signatures were verified against the specified public key") } if fulcioVerified { - fmt.Fprintln(os.Stderr, " - The code-signing certificate was verified using trusted certificate authority certificates") + ui.Infof(ctx, " - The code-signing certificate was verified using trusted certificate authority certificates") } } // PrintVerification logs details about the verification to stdout -func PrintVerification(imgRef string, verified []oci.Signature, output string) { +func PrintVerification(ctx context.Context, imgRef string, verified []oci.Signature, output string) { switch output { case "text": for _, sig := range verified { if cert, err := sig.Cert(); err == nil && cert != nil { ce := cosign.CertExtensions{Cert: cert} - fmt.Fprintln(os.Stderr, "Certificate subject: ", sigs.CertSubject(cert)) + ui.Infof(ctx, "Certificate subject: %s", sigs.CertSubject(cert)) if issuerURL := ce.GetIssuer(); issuerURL != "" { - fmt.Fprintln(os.Stderr, "Certificate issuer URL: ", issuerURL) + ui.Infof(ctx, "Certificate issuer URL: %s", issuerURL) } if githubWorkflowTrigger := ce.GetCertExtensionGithubWorkflowTrigger(); githubWorkflowTrigger != "" { - fmt.Fprintln(os.Stderr, "GitHub Workflow Trigger:", githubWorkflowTrigger) + ui.Infof(ctx, "GitHub Workflow Trigger: %s", githubWorkflowTrigger) } if githubWorkflowSha := ce.GetExtensionGithubWorkflowSha(); githubWorkflowSha != "" { - fmt.Fprintln(os.Stderr, "GitHub Workflow SHA:", githubWorkflowSha) + ui.Infof(ctx, "GitHub Workflow SHA: %s", githubWorkflowSha) } if githubWorkflowName := ce.GetCertExtensionGithubWorkflowName(); githubWorkflowName != "" { - fmt.Fprintln(os.Stderr, "GitHub Workflow Name:", githubWorkflowName) + ui.Infof(ctx, "GitHub Workflow Name: %s", githubWorkflowName) } if githubWorkflowRepository := ce.GetCertExtensionGithubWorkflowRepository(); githubWorkflowRepository != "" { - fmt.Fprintln(os.Stderr, "GitHub Workflow Trigger", githubWorkflowRepository) + ui.Infof(ctx, "GitHub Workflow Repository: %s", githubWorkflowRepository) } if githubWorkflowRef := ce.GetCertExtensionGithubWorkflowRef(); githubWorkflowRef != "" { - fmt.Fprintln(os.Stderr, "GitHub Workflow Ref:", githubWorkflowRef) + ui.Infof(ctx, "GitHub Workflow Ref: %s", githubWorkflowRef) } } diff --git a/cmd/cosign/cli/verify/verify_attestation.go b/cmd/cosign/cli/verify/verify_attestation.go index 2ee3b501941..e5c7f7239a0 100644 --- a/cmd/cosign/cli/verify/verify_attestation.go +++ b/cmd/cosign/cli/verify/verify_attestation.go @@ -29,6 +29,7 @@ import ( "github.com/sigstore/cosign/v2/cmd/cosign/cli/options" "github.com/sigstore/cosign/v2/cmd/cosign/cli/rekor" "github.com/sigstore/cosign/v2/internal/pkg/cosign/tsa" + "github.com/sigstore/cosign/v2/internal/ui" "github.com/sigstore/cosign/v2/pkg/cosign" "github.com/sigstore/cosign/v2/pkg/cosign/cue" "github.com/sigstore/cosign/v2/pkg/cosign/pivkey" @@ -286,7 +287,7 @@ func (c *VerifyAttestationCommand) Exec(ctx context.Context, images []string) (e } if len(cuePolicies) > 0 { - fmt.Fprintf(os.Stderr, "will be validating against CUE policies: %v\n", cuePolicies) + ui.Infof(ctx, "will be validating against CUE policies: %v", cuePolicies) cueValidationErr := cue.ValidateJSON(payload, cuePolicies) if cueValidationErr != nil { validationErrors = append(validationErrors, cueValidationErr) @@ -295,7 +296,7 @@ func (c *VerifyAttestationCommand) Exec(ctx context.Context, images []string) (e } if len(regoPolicies) > 0 { - fmt.Fprintf(os.Stderr, "will be validating against Rego policies: %v\n", regoPolicies) + ui.Infof(ctx, "will be validating against Rego policies: %v", regoPolicies) regoValidationErrs := rego.ValidateJSON(payload, regoPolicies) if len(regoValidationErrs) > 0 { validationErrors = append(validationErrors, regoValidationErrs...) @@ -307,9 +308,9 @@ func (c *VerifyAttestationCommand) Exec(ctx context.Context, images []string) (e } if len(validationErrors) > 0 { - fmt.Fprintf(os.Stderr, "There are %d number of errors occurred during the validation:\n", len(validationErrors)) + ui.Infof(ctx, "There are %d number of errors occurred during the validation:\n", len(validationErrors)) for _, v := range validationErrors { - _, _ = fmt.Fprintf(os.Stderr, "- %v\n", v) + ui.Infof(ctx, "- %v", v) } return fmt.Errorf("%d validation errors occurred", len(validationErrors)) } @@ -319,9 +320,9 @@ func (c *VerifyAttestationCommand) Exec(ctx context.Context, images []string) (e } // TODO: add CUE validation report to `PrintVerificationHeader`. - PrintVerificationHeader(imageRef, co, bundleVerified, fulcioVerified) + PrintVerificationHeader(ctx, imageRef, co, bundleVerified, fulcioVerified) // The attestations are always JSON, so use the raw "text" mode for outputting them instead of conversion - PrintVerification(imageRef, checked, "text") + PrintVerification(ctx, imageRef, checked, "text") } return nil diff --git a/cmd/cosign/cli/verify/verify_blob.go b/cmd/cosign/cli/verify/verify_blob.go index 678eed398e7..5532f8255d4 100644 --- a/cmd/cosign/cli/verify/verify_blob.go +++ b/cmd/cosign/cli/verify/verify_blob.go @@ -31,6 +31,7 @@ import ( "github.com/sigstore/cosign/v2/cmd/cosign/cli/options" "github.com/sigstore/cosign/v2/cmd/cosign/cli/rekor" "github.com/sigstore/cosign/v2/internal/pkg/cosign/tsa" + "github.com/sigstore/cosign/v2/internal/ui" "github.com/sigstore/cosign/v2/pkg/blob" "github.com/sigstore/cosign/v2/pkg/cosign" "github.com/sigstore/cosign/v2/pkg/cosign/bundle" @@ -299,7 +300,7 @@ func (c *VerifyBlobCmd) Exec(ctx context.Context, blobRef string) error { return err } - fmt.Fprintln(os.Stderr, "Verified OK") + ui.Infof(ctx, "Verified OK") return nil } diff --git a/cmd/cosign/cli/verify/verify_test.go b/cmd/cosign/cli/verify/verify_test.go index 4081c35b58f..81288e7cff1 100644 --- a/cmd/cosign/cli/verify/verify_test.go +++ b/cmd/cosign/cli/verify/verify_test.go @@ -35,6 +35,7 @@ import ( "github.com/google/go-containerregistry/pkg/name" "github.com/sigstore/cosign/v2/cmd/cosign/cli/options" + "github.com/sigstore/cosign/v2/internal/ui" "github.com/sigstore/cosign/v2/pkg/oci" "github.com/sigstore/cosign/v2/pkg/oci/static" "github.com/sigstore/cosign/v2/test" @@ -112,7 +113,7 @@ func TestPrintVerification(t *testing.T) { base64.StdEncoding.EncodeToString(signature), static.WithCertChain(pemLeaf, appendSlices([][]byte{pemSub, pemRoot}))) - captureOutput := func(imgRef string, sigs []oci.Signature, output string, f func(string, []oci.Signature, string)) string { + captureOutput := func(f func()) string { reader, writer, err := os.Pipe() if err != nil { panic(err) @@ -137,12 +138,17 @@ func TestPrintVerification(t *testing.T) { out <- buf.String() }() wg.Wait() - f(imgRef, sigs, output) + f() writer.Close() return <-out } + _ = captureOutput - out := captureOutput("", []oci.Signature{ociSig}, "json", PrintVerification) + out := captureOutput(func() { + ui.RunWithTestCtx(func(ctx context.Context, write ui.WriteFunc) { + PrintVerification(ctx, "", []oci.Signature{ociSig}, "json") + }) + }) prettyPrint := func(b []byte) ([]byte, error) { var out bytes.Buffer err := json.Indent(&out, b, "", " ") diff --git a/pkg/sget/sget.go b/pkg/sget/sget.go index 4663db3d70a..10dfcc0e4bd 100644 --- a/pkg/sget/sget.go +++ b/pkg/sget/sget.go @@ -119,8 +119,8 @@ func (sg *SecureGet) Do(ctx context.Context) error { if err != nil { return err } - verify.PrintVerificationHeader(sg.ImageRef, co, bundleVerified, fulcioVerified) - verify.PrintVerification(sg.ImageRef, sp, "text") + verify.PrintVerificationHeader(ctx, sg.ImageRef, co, bundleVerified, fulcioVerified) + verify.PrintVerification(ctx, sg.ImageRef, sp, "text") } // TODO(mattmoor): Depending on what this is, use the higher-level stuff.