| 31 | type tufClientInstantiator func(o *tuf.Options) (*tuf.Client, error) |
| 32 | |
| 33 | func NewTrustedRootCmd(f *cmdutil.Factory, runF func(*Options) error) *cobra.Command { |
| 34 | opts := &Options{} |
| 35 | trustedRootCmd := cobra.Command{ |
| 36 | Use: "trusted-root [--tuf-url <url> --tuf-root <file-path>] [--verify-only]", |
| 37 | Args: cobra.ExactArgs(0), |
| 38 | Short: "Output trusted_root.jsonl contents, likely for offline verification", |
| 39 | Long: heredoc.Docf(` |
| 40 | Output contents for a trusted_root.jsonl file, likely for offline verification. |
| 41 | |
| 42 | When using %[1]sgh attestation verify%[1]s, if your machine is on the internet, |
| 43 | this will happen automatically. But to do offline verification, you need to |
| 44 | supply a trusted root file with %[1]s--custom-trusted-root%[1]s; this command |
| 45 | will help you fetch a %[1]strusted_root.jsonl%[1]s file for that purpose. |
| 46 | |
| 47 | You can call this command without any flags to get a trusted root file covering |
| 48 | the Sigstore Public Good Instance as well as GitHub's Sigstore instance. |
| 49 | |
| 50 | Otherwise you can use %[1]s--tuf-url%[1]s to specify the URL of a custom TUF |
| 51 | repository mirror, and %[1]s--tuf-root%[1]s should be the path to the |
| 52 | %[1]sroot.json%[1]s file that you securely obtained out-of-band. |
| 53 | |
| 54 | If you just want to verify the integrity of your local TUF repository, and don't |
| 55 | want the contents of a trusted_root.jsonl file, use %[1]s--verify-only%[1]s. |
| 56 | `, "`"), |
| 57 | Example: heredoc.Doc(` |
| 58 | # Get a trusted_root.jsonl for both Sigstore Public Good and GitHub's instance |
| 59 | $ gh attestation trusted-root |
| 60 | `), |
| 61 | RunE: func(cmd *cobra.Command, args []string) error { |
| 62 | if opts.Hostname == "" { |
| 63 | opts.Hostname, _ = ghauth.DefaultHost() |
| 64 | } |
| 65 | |
| 66 | if err := auth.IsHostSupported(opts.Hostname); err != nil { |
| 67 | return err |
| 68 | } |
| 69 | |
| 70 | hc, err := f.HttpClient() |
| 71 | if err != nil { |
| 72 | return err |
| 73 | } |
| 74 | |
| 75 | externalClient, err := f.ExternalHttpClient() |
| 76 | if err != nil { |
| 77 | return err |
| 78 | } |
| 79 | |
| 80 | if ghauth.IsTenancy(opts.Hostname) { |
| 81 | c, err := f.Config() |
| 82 | if err != nil { |
| 83 | return err |
| 84 | } |
| 85 | |
| 86 | if !c.Authentication().HasActiveToken(opts.Hostname) { |
| 87 | return fmt.Errorf("not authenticated with %s", opts.Hostname) |
| 88 | } |
| 89 | logger := io.NewHandler(f.IOStreams) |
| 90 | apiClient := api.NewLiveClient(hc, externalClient, opts.Hostname, logger) |