package verify import ( "fmt" "path/filepath" "strings" "github.com/cli/cli/v2/internal/gh" "github.com/cli/cli/v2/pkg/cmd/attestation/api" "github.com/cli/cli/v2/pkg/cmd/attestation/artifact/oci" "github.com/cli/cli/v2/pkg/cmd/attestation/io" "github.com/cli/cli/v2/pkg/cmd/attestation/verification" "github.com/cli/cli/v2/pkg/cmdutil" ) // Options captures the options for the verify command type Options struct { ArtifactPath string BundlePath string UseBundleFromRegistry bool Config func() (gh.Config, error) TrustedRoot string DenySelfHostedRunner bool DigestAlgorithm string Limit int NoPublicGood bool OIDCIssuer string Owner string PredicateType string Repo string SAN string SANRegex string SignerRepo string SignerWorkflow string APIClient api.Client Logger *io.Handler OCIClient oci.Client SigstoreVerifier verification.SigstoreVerifier exporter cmdutil.Exporter } // Clean cleans the file path option values func (opts *Options) Clean() { if opts.BundlePath != "" { opts.BundlePath = filepath.Clean(opts.BundlePath) } } func (opts *Options) SetPolicyFlags() { // check that Repo is in the expected format if provided if opts.Repo != "" { // we expect the repo argument to be in the format / splitRepo := strings.Split(opts.Repo, "/") // if Repo is provided but owner is not, set the OWNER portion of the Repo value // to Owner opts.Owner = splitRepo[0] if !isSignerIdentityProvided(opts) { opts.SANRegex = expandToGitHubURL(opts.Repo) } return } if !isSignerIdentityProvided(opts) { opts.SANRegex = expandToGitHubURL(opts.Owner) } } // AreFlagsValid checks that the provided flag combination is valid // and returns an error otherwise func (opts *Options) AreFlagsValid() error { // If provided, check that the Repo option is in the expected format / if opts.Repo != "" && !isProvidedRepoValid(opts.Repo) { return fmt.Errorf("invalid value provided for repo: %s", opts.Repo) } // If provided, check that the SignerRepo option is in the expected format / if opts.SignerRepo != "" && !isProvidedRepoValid(opts.SignerRepo) { return fmt.Errorf("invalid value provided for signer-repo: %s", opts.SignerRepo) } // Check that limit is between 1 and 1000 if opts.Limit < 1 || opts.Limit > 1000 { return fmt.Errorf("limit %d not allowed, must be between 1 and 1000", opts.Limit) } // Check that the bundle-from-oci flag is only used with OCI artifact paths if opts.UseBundleFromRegistry && !strings.HasPrefix(opts.ArtifactPath, "oci://") { return fmt.Errorf("bundle-from-oci flag can only be used with OCI artifact paths") } // Check that both the bundle-from-oci and bundle-path flags are not used together if opts.UseBundleFromRegistry && opts.BundlePath != "" { return fmt.Errorf("bundle-from-oci flag cannot be used with bundle-path flag") } return nil } // check if any of the signer identity flags have been provided func isSignerIdentityProvided(opts *Options) bool { return opts.SAN != "" || opts.SANRegex != "" || opts.SignerRepo != "" || opts.SignerWorkflow != "" } func isProvidedRepoValid(repo string) bool { // we expect a provided repository argument be in the format / splitRepo := strings.Split(repo, "/") return len(splitRepo) == 2 }