From e35bec9474bce60bd19a3671c1d4a558f7b46ae1 Mon Sep 17 00:00:00 2001 From: Meredith Lancaster Date: Mon, 4 Mar 2024 14:22:24 -0700 Subject: [PATCH] add verify-tuf-root cmd Signed-off-by: Meredith Lancaster --- pkg/cmd/attestation/attestation.go | 2 + .../verifytufroot/verify-tuf-root.go | 73 +++++++++++++++++++ 2 files changed, 75 insertions(+) create mode 100644 pkg/cmd/attestation/verifytufroot/verify-tuf-root.go diff --git a/pkg/cmd/attestation/attestation.go b/pkg/cmd/attestation/attestation.go index e9a2c8268..4df7b4a89 100644 --- a/pkg/cmd/attestation/attestation.go +++ b/pkg/cmd/attestation/attestation.go @@ -3,6 +3,7 @@ package attestation import ( "github.com/cli/cli/v2/pkg/cmd/attestation/download" "github.com/cli/cli/v2/pkg/cmd/attestation/inspect" + "github.com/cli/cli/v2/pkg/cmd/attestation/verifytufroot" "github.com/cli/cli/v2/pkg/cmd/attestation/verify" "github.com/cli/cli/v2/pkg/cmdutil" @@ -30,6 +31,7 @@ func NewCmdAttestation(f *cmdutil.Factory) *cobra.Command { root.AddCommand(download.NewDownloadCmd(f)) root.AddCommand(inspect.NewInspectCmd(f)) root.AddCommand(verify.NewVerifyCmd(f)) + root.AddCommand(verifytufroot.NewVerifyTUFRootCmd(f)) return root } diff --git a/pkg/cmd/attestation/verifytufroot/verify-tuf-root.go b/pkg/cmd/attestation/verifytufroot/verify-tuf-root.go new file mode 100644 index 000000000..bb6f1c484 --- /dev/null +++ b/pkg/cmd/attestation/verifytufroot/verify-tuf-root.go @@ -0,0 +1,73 @@ +package verifytufroot + +import ( + "fmt" + "os" + + "github.com/cli/cli/v2/pkg/cmdutil" + "github.com/cli/cli/v2/pkg/cmd/attestation/logger" + "github.com/cli/cli/v2/pkg/cmd/attestation/verification" + + "github.com/MakeNowJust/heredoc" + "github.com/sigstore/sigstore-go/pkg/tuf" + "github.com/spf13/cobra" +) + +func NewVerifyTUFRootCmd(f *cmdutil.Factory) *cobra.Command { + var mirror string + var root string + var cmd = cobra.Command{ + Use: "verify-tuf-root --mirror --root ", + Args: cobra.ExactArgs(0), + Short: "Verify the TUF repository from a provided TUF root", + Long: heredoc.Docf(` + Verify a TUF repository from a local TUF root. + + The command requires you provide the %[1]s--mirror%[1]s flag, which should be the URL + of the TUF repository mirror. + + The command also requires you provide the %[1]s--root%[1]s flag, which should be the + path to the TUF root file. + `, "`"), + Example: heredoc.Doc(` + # Verify the TUF repository from a provided TUF root + gh attestation tuf-root-verify --mirror https://tuf-repo.github.com --root /path/to/1.root.json + `), + Run: func(cmd *cobra.Command, args []string) { + logger := logger.NewDefaultLogger() + if err := verifyTUFRoot(mirror, root); err != nil { + fmt.Sprintln(logger.IO.Out, logger.ColorScheme.Redf("Failed to verify the TUF repository: %s", err)) + os.Exit(1) + } + fmt.Sprintln(logger.IO.Out, logger.ColorScheme.Green("Successfully verified the TUF repository")) + }, + } + + cmd.Flags().StringVarP(&mirror, "mirror", "m", "", "URL to the TUF repository mirror") + cmd.MarkFlagRequired("mirror") //nolint:errcheck + cmd.Flags().StringVarP(&root, "root", "r", "", "Path to the TUF root file on disk") + cmd.MarkFlagRequired("root") //nolint:errcheck + + return &cmd +} + +func verifyTUFRoot(mirror, root string) error { + rb, err := os.ReadFile(root) + if err != nil { + return fmt.Errorf("failed to read root file %s: %w", root, err) + } + opts, err := verification.GitHubTUFOptions() + if err != nil { + return err + } + opts.Root = rb + opts.RepositoryBaseURL = mirror + // The purpose is the verify the TUF root and repository, make + // sure there is no caching enabled + opts.CacheValidity = 0 + if _, err = tuf.New(opts); err != nil { + return fmt.Errorf("failed to create TUF client: %w", err) + } + + return nil +}