104 lines
3.4 KiB
Go
104 lines
3.4 KiB
Go
package verify
|
|
|
|
import (
|
|
"fmt"
|
|
"path/filepath"
|
|
"strings"
|
|
|
|
"github.com/cli/cli/v2/internal/gh"
|
|
"github.com/cli/cli/v2/internal/ghinstance"
|
|
"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
|
|
SignerDigest string
|
|
SignerRepo string
|
|
SignerWorkflow string
|
|
SourceDigest string
|
|
SourceRef string
|
|
APIClient api.Client
|
|
Logger *io.Handler
|
|
OCIClient oci.Client
|
|
SigstoreVerifier verification.SigstoreVerifier
|
|
exporter cmdutil.Exporter
|
|
Hostname string
|
|
// Tenant is only set when tenancy is used
|
|
Tenant string
|
|
}
|
|
|
|
// Clean cleans the file path option values
|
|
func (opts *Options) Clean() {
|
|
if opts.BundlePath != "" {
|
|
opts.BundlePath = filepath.Clean(opts.BundlePath)
|
|
}
|
|
}
|
|
|
|
// FetchAttestationsFromGitHubAPI returns true if the command should fetch attestations from the GitHub API
|
|
// It checks that a bundle path is not provided and that the "use bundle from registry" flag is not set
|
|
func (opts *Options) FetchAttestationsFromGitHubAPI() bool {
|
|
return opts.BundlePath == "" && !opts.UseBundleFromRegistry
|
|
}
|
|
|
|
// 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 <OWNER>/<REPO>
|
|
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 <OWNER>/<REPO>
|
|
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")
|
|
}
|
|
|
|
// Verify provided hostname
|
|
if opts.Hostname != "" {
|
|
if err := ghinstance.HostnameValidator(opts.Hostname); err != nil {
|
|
return fmt.Errorf("error parsing hostname: %w", err)
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func isProvidedRepoValid(repo string) bool {
|
|
// we expect a provided repository argument be in the format <OWNER>/<REPO>
|
|
splitRepo := strings.Split(repo, "/")
|
|
return len(splitRepo) == 2
|
|
}
|