diff --git a/pkg/cmd/attestation/api/mock_client.go b/pkg/cmd/attestation/api/mock_client.go index 96a64e4fc..edb51ee6e 100644 --- a/pkg/cmd/attestation/api/mock_client.go +++ b/pkg/cmd/attestation/api/mock_client.go @@ -1,11 +1,9 @@ package api import ( - "encoding/json" "fmt" - "os" - "github.com/sigstore/sigstore-go/pkg/bundle" + "github.com/cli/cli/v2/pkg/cmd/attestation/test/data" ) type MockClient struct { @@ -22,18 +20,7 @@ func (m MockClient) GetByOwnerAndDigest(owner, digest string, limit int) ([]*Att } func makeTestAttestation() Attestation { - bundleBytes, err := os.ReadFile("../test/data/sigstore-js-2.1.0-bundle.json") - if err != nil { - panic(err) - } - - var b *bundle.ProtobufBundle - err = json.Unmarshal(bundleBytes, &b) - if err != nil { - panic(err) - } - - return Attestation{Bundle: b} + return Attestation{Bundle: data.SigstoreBundle(nil)} } func OnGetByRepoAndDigestSuccess(repo, digest string, limit int) ([]*Attestation, error) { diff --git a/pkg/cmd/attestation/inspect/inspect.go b/pkg/cmd/attestation/inspect/inspect.go index 1b2105da4..759667b36 100644 --- a/pkg/cmd/attestation/inspect/inspect.go +++ b/pkg/cmd/attestation/inspect/inspect.go @@ -73,6 +73,17 @@ func NewInspectCmd(f *cmdutil.Factory, runF func(*Options) error) *cobra.Command return runF(opts) } + config := verification.SigstoreConfig{ + Logger: opts.Logger, + } + + sigstore, err := verification.NewLiveSigstoreVerifier(config) + if err != nil { + return err + } + + opts.SigstoreVerifier = sigstore + if err := runInspect(opts); err != nil { return fmt.Errorf("Failed to inspect the artifact and bundle: %w", err) } @@ -101,21 +112,12 @@ func runInspect(opts *Options) error { return fmt.Errorf("failed to read attestations for subject: %s", artifact.DigestWithAlg()) } - config := verification.SigstoreConfig{ - Logger: opts.Logger, - } - policy, err := buildPolicy(*artifact) if err != nil { return fmt.Errorf("failed to build policy: %v", err) } - sigstore, err := verification.NewSigstoreVerifier(config, policy) - if err != nil { - return err - } - - res := sigstore.Verify(attestations) + res := opts.SigstoreVerifier.Verify(attestations, policy) if res.Error != nil { return fmt.Errorf("at least one attestation failed to verify against Sigstore: %v", res.Error) } diff --git a/pkg/cmd/attestation/inspect/inspect_test.go b/pkg/cmd/attestation/inspect/inspect_test.go index e42bb2620..368cc54f5 100644 --- a/pkg/cmd/attestation/inspect/inspect_test.go +++ b/pkg/cmd/attestation/inspect/inspect_test.go @@ -11,6 +11,7 @@ import ( "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/test" + "github.com/cli/cli/v2/pkg/cmd/attestation/verification" "github.com/cli/cli/v2/pkg/cmdutil" "github.com/cli/cli/v2/pkg/httpmock" @@ -53,10 +54,11 @@ func TestNewInspectCmd(t *testing.T) { name: "Invalid digest-alg flag", cli: fmt.Sprintf("%s --bundle %s --digest-alg sha384", artifactPath, bundlePath), wants: Options{ - ArtifactPath: artifactPath, - BundlePath: bundlePath, - DigestAlgorithm: "sha384", - OCIClient: oci.MockClient{}, + ArtifactPath: artifactPath, + BundlePath: bundlePath, + DigestAlgorithm: "sha384", + OCIClient: oci.MockClient{}, + SigstoreVerifier: verification.NewMockSigstoreVerifier(t), }, wantsErr: true, }, @@ -64,10 +66,11 @@ func TestNewInspectCmd(t *testing.T) { name: "Use default digest-alg value", cli: fmt.Sprintf("%s --bundle %s", artifactPath, bundlePath), wants: Options{ - ArtifactPath: artifactPath, - BundlePath: bundlePath, - DigestAlgorithm: "sha256", - OCIClient: oci.MockClient{}, + ArtifactPath: artifactPath, + BundlePath: bundlePath, + DigestAlgorithm: "sha256", + OCIClient: oci.MockClient{}, + SigstoreVerifier: verification.NewMockSigstoreVerifier(t), }, wantsErr: false, }, @@ -75,10 +78,11 @@ func TestNewInspectCmd(t *testing.T) { name: "Use custom digest-alg value", cli: fmt.Sprintf("%s --bundle %s --digest-alg sha512", artifactPath, bundlePath), wants: Options{ - ArtifactPath: artifactPath, - BundlePath: bundlePath, - DigestAlgorithm: "sha512", - OCIClient: oci.MockClient{}, + ArtifactPath: artifactPath, + BundlePath: bundlePath, + DigestAlgorithm: "sha512", + OCIClient: oci.MockClient{}, + SigstoreVerifier: verification.NewMockSigstoreVerifier(t), }, wantsErr: false, }, @@ -86,9 +90,10 @@ func TestNewInspectCmd(t *testing.T) { name: "Missing bundle flag", cli: artifactPath, wants: Options{ - ArtifactPath: artifactPath, - DigestAlgorithm: "sha256", - OCIClient: oci.MockClient{}, + ArtifactPath: artifactPath, + DigestAlgorithm: "sha256", + OCIClient: oci.MockClient{}, + SigstoreVerifier: verification.NewMockSigstoreVerifier(t), }, wantsErr: true, }, @@ -96,10 +101,11 @@ func TestNewInspectCmd(t *testing.T) { name: "Prints output in JSON format", cli: fmt.Sprintf("%s --bundle %s --format json", artifactPath, bundlePath), wants: Options{ - ArtifactPath: artifactPath, - BundlePath: bundlePath, - DigestAlgorithm: "sha256", - OCIClient: oci.MockClient{}, + ArtifactPath: artifactPath, + BundlePath: bundlePath, + DigestAlgorithm: "sha256", + OCIClient: oci.MockClient{}, + SigstoreVerifier: verification.NewMockSigstoreVerifier(t), }, wantsExporter: true, }, @@ -128,8 +134,8 @@ func TestNewInspectCmd(t *testing.T) { assert.Equal(t, tc.wants.ArtifactPath, opts.ArtifactPath) assert.Equal(t, tc.wants.BundlePath, opts.BundlePath) assert.Equal(t, tc.wants.DigestAlgorithm, opts.DigestAlgorithm) - assert.NotNil(t, opts.OCIClient) assert.NotNil(t, opts.Logger) + assert.NotNil(t, opts.OCIClient) assert.Equal(t, tc.wantsExporter, opts.exporter != nil) }) } @@ -137,11 +143,12 @@ func TestNewInspectCmd(t *testing.T) { func TestRunInspect(t *testing.T) { opts := Options{ - ArtifactPath: artifactPath, - BundlePath: bundlePath, - DigestAlgorithm: "sha512", - Logger: io.NewTestHandler(), - OCIClient: oci.MockClient{}, + ArtifactPath: artifactPath, + BundlePath: bundlePath, + DigestAlgorithm: "sha512", + Logger: io.NewTestHandler(), + OCIClient: oci.MockClient{}, + SigstoreVerifier: verification.NewMockSigstoreVerifier(t), } t.Run("with valid artifact and bundle", func(t *testing.T) { @@ -164,12 +171,13 @@ func TestRunInspect(t *testing.T) { func TestJSONOutput(t *testing.T) { testIO, _, out, _ := iostreams.Test() opts := Options{ - ArtifactPath: artifactPath, - BundlePath: bundlePath, - DigestAlgorithm: "sha512", - Logger: io.NewHandler(testIO), - OCIClient: oci.MockClient{}, - exporter: cmdutil.NewJSONExporter(), + ArtifactPath: artifactPath, + BundlePath: bundlePath, + DigestAlgorithm: "sha512", + Logger: io.NewHandler(testIO), + OCIClient: oci.MockClient{}, + SigstoreVerifier: verification.NewMockSigstoreVerifier(t), + exporter: cmdutil.NewJSONExporter(), } require.Nil(t, runInspect(&opts)) diff --git a/pkg/cmd/attestation/inspect/options.go b/pkg/cmd/attestation/inspect/options.go index 56199e06b..b9c8819c4 100644 --- a/pkg/cmd/attestation/inspect/options.go +++ b/pkg/cmd/attestation/inspect/options.go @@ -5,17 +5,19 @@ import ( "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 inspect command type Options struct { - ArtifactPath string - BundlePath string - DigestAlgorithm string - Logger *io.Handler - OCIClient oci.Client - exporter cmdutil.Exporter + ArtifactPath string + BundlePath string + DigestAlgorithm string + Logger *io.Handler + OCIClient oci.Client + SigstoreVerifier verification.SigstoreVerifier + exporter cmdutil.Exporter } // Clean cleans the file path option values diff --git a/pkg/cmd/attestation/test/data/data.go b/pkg/cmd/attestation/test/data/data.go new file mode 100644 index 000000000..77f07e60c --- /dev/null +++ b/pkg/cmd/attestation/test/data/data.go @@ -0,0 +1,17 @@ +package data + +import ( + _ "embed" + "testing" + + "github.com/sigstore/sigstore-go/pkg/bundle" + sgData "github.com/sigstore/sigstore-go/pkg/testing/data" +) + +//go:embed sigstore-js-2.1.0-bundle.json +var SigstoreBundleRaw []byte + +// SigstoreBundle returns a test *sigstore.Bundle +func SigstoreBundle(t *testing.T) *bundle.ProtobufBundle { + return sgData.TestBundle(t, SigstoreBundleRaw) +} diff --git a/pkg/cmd/attestation/verification/mock_verifier.go b/pkg/cmd/attestation/verification/mock_verifier.go new file mode 100644 index 000000000..51e66c424 --- /dev/null +++ b/pkg/cmd/attestation/verification/mock_verifier.go @@ -0,0 +1,50 @@ +package verification + +import ( + "fmt" + "testing" + + "github.com/cli/cli/v2/pkg/cmd/attestation/api" + "github.com/cli/cli/v2/pkg/cmd/attestation/test/data" + + "github.com/in-toto/in-toto-golang/in_toto" + "github.com/sigstore/sigstore-go/pkg/verify" +) + +const SLSAPredicateType = "https://slsa.dev/provenance/v1" + +type MockSigstoreVerifier struct { + t *testing.T +} + +func (v *MockSigstoreVerifier) Verify(attestations []*api.Attestation, policy verify.PolicyBuilder) *SigstoreResults { + statement := &in_toto.Statement{} + statement.PredicateType = SLSAPredicateType + + result := AttestationProcessingResult{ + Attestation: &api.Attestation{ + Bundle: data.SigstoreBundle(v.t), + }, + VerificationResult: &verify.VerificationResult{ + Statement: statement, + }, + } + + results := []*AttestationProcessingResult{&result} + + return &SigstoreResults{ + VerifyResults: results, + } +} + +func NewMockSigstoreVerifier(t *testing.T) *MockSigstoreVerifier { + return &MockSigstoreVerifier{t} +} + +type FailSigstoreVerifier struct{} + +func (v *FailSigstoreVerifier) Verify(attestations []*api.Attestation, policy verify.PolicyBuilder) *SigstoreResults { + return &SigstoreResults{ + Error: fmt.Errorf("failed to verify attestations"), + } +} diff --git a/pkg/cmd/attestation/verification/sigstore.go b/pkg/cmd/attestation/verification/sigstore.go index daaacf628..ad57102ea 100644 --- a/pkg/cmd/attestation/verification/sigstore.go +++ b/pkg/cmd/attestation/verification/sigstore.go @@ -34,19 +34,22 @@ type SigstoreConfig struct { NoPublicGood bool } -type SigstoreVerifier struct { +type SigstoreVerifier interface { + Verify(attestations []*api.Attestation, policy verify.PolicyBuilder) *SigstoreResults +} + +type LiveSigstoreVerifier struct { ghVerifier *verify.SignedEntityVerifier publicGoodVerifier *verify.SignedEntityVerifier customVerifier *verify.SignedEntityVerifier - policy verify.PolicyBuilder onlyVerifyWithGithub bool Logger *io.Handler } -// NewSigstoreVerifier creates a new SigstoreVerifier struct +// NewLiveSigstoreVerifier creates a new LiveSigstoreVerifier struct // that is used to verify artifacts and attestations against the // Public Good, GitHub, or a custom trusted root. -func NewSigstoreVerifier(config SigstoreConfig, policy verify.PolicyBuilder) (*SigstoreVerifier, error) { +func NewLiveSigstoreVerifier(config SigstoreConfig) (*LiveSigstoreVerifier, error) { customVerifier, err := newCustomVerifier(config.CustomTrustedRoot) if err != nil { return nil, fmt.Errorf("failed to create custom verifier: %v", err) @@ -62,17 +65,16 @@ func NewSigstoreVerifier(config SigstoreConfig, policy verify.PolicyBuilder) (*S return nil, fmt.Errorf("failed to create GitHub Sigstore verifier: %v", err) } - return &SigstoreVerifier{ + return &LiveSigstoreVerifier{ ghVerifier: ghVerifier, publicGoodVerifier: publicGoodVerifier, customVerifier: customVerifier, Logger: config.Logger, - policy: policy, onlyVerifyWithGithub: config.NoPublicGood, }, nil } -func (v *SigstoreVerifier) chooseVerifier(b *bundle.ProtobufBundle) (*verify.SignedEntityVerifier, string, error) { +func (v *LiveSigstoreVerifier) chooseVerifier(b *bundle.ProtobufBundle) (*verify.SignedEntityVerifier, string, error) { verifyContent, err := b.VerificationContent() if err != nil { return nil, "", fmt.Errorf("failed to get bundle verification content: %v", err) @@ -103,7 +105,7 @@ func (v *SigstoreVerifier) chooseVerifier(b *bundle.ProtobufBundle) (*verify.Sig return nil, "", fmt.Errorf("leaf certificate issuer is not recognized") } -func (v *SigstoreVerifier) Verify(attestations []*api.Attestation) *SigstoreResults { +func (v *LiveSigstoreVerifier) Verify(attestations []*api.Attestation, policy verify.PolicyBuilder) *SigstoreResults { // initialize the processing results before attempting to verify // with multiple verifiers results := make([]*AttestationProcessingResult, len(attestations)) @@ -128,7 +130,7 @@ func (v *SigstoreVerifier) Verify(attestations []*api.Attestation) *SigstoreResu v.Logger.VerbosePrintf("Attempting verification against issuer \"%s\"\n", issuer) // attempt to verify the attestation - result, err := verifier.Verify(apr.Attestation.Bundle, v.policy) + result, err := verifier.Verify(apr.Attestation.Bundle, policy) // if verification fails, create the error and exit verification early if err != nil { v.Logger.VerbosePrint(v.Logger.ColorScheme.Redf( diff --git a/pkg/cmd/attestation/verification/sigstore_test.go b/pkg/cmd/attestation/verification/sigstore_test.go index 204b5e583..0243a11ee 100644 --- a/pkg/cmd/attestation/verification/sigstore_test.go +++ b/pkg/cmd/attestation/verification/sigstore_test.go @@ -21,7 +21,7 @@ func buildPolicy(a artifact.DigestedArtifact) (verify.PolicyBuilder, error) { return policy, nil } -func TestNewSigstoreVerifier(t *testing.T) { +func TestNewLiveSigstoreVerifier(t *testing.T) { artifactPath := test.NormalizeRelativePath("../test/data/sigstore-js-2.1.0.tgz") artifact, err := artifact.NewDigestedArtifact(nil, artifactPath, "sha512") require.NoError(t, err) @@ -32,7 +32,7 @@ func TestNewSigstoreVerifier(t *testing.T) { c := SigstoreConfig{ Logger: io.NewTestHandler(), } - verifier, err := NewSigstoreVerifier(c, policy) + verifier, err := NewLiveSigstoreVerifier(c) require.NoError(t, err) t.Run("with invalid signature", func(t *testing.T) { @@ -41,7 +41,7 @@ func TestNewSigstoreVerifier(t *testing.T) { require.NotNil(t, attestations) require.NoError(t, err) - res := verifier.Verify(attestations) + res := verifier.Verify(attestations, policy) require.Error(t, res.Error) require.ErrorContains(t, res.Error, "verifying with issuer \"sigstore.dev\"") require.Nil(t, res.VerifyResults) @@ -53,7 +53,7 @@ func TestNewSigstoreVerifier(t *testing.T) { require.Len(t, attestations, 2) require.NoError(t, err) - res := verifier.Verify(attestations) + res := verifier.Verify(attestations, policy) require.Len(t, res.VerifyResults, 2) require.NoError(t, res.Error) }) diff --git a/pkg/cmd/attestation/verify/options.go b/pkg/cmd/attestation/verify/options.go index d7742bf3a..62735df54 100644 --- a/pkg/cmd/attestation/verify/options.go +++ b/pkg/cmd/attestation/verify/options.go @@ -8,6 +8,7 @@ import ( "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" ) @@ -18,6 +19,7 @@ type Options struct { CustomTrustedRoot string DenySelfHostedRunner bool DigestAlgorithm string + Limit int NoPublicGood bool OIDCIssuer string Owner string @@ -26,8 +28,8 @@ type Options struct { SANRegex string APIClient api.Client Logger *io.Handler - Limit int OCIClient oci.Client + SigstoreVerifier verification.SigstoreVerifier exporter cmdutil.Exporter } diff --git a/pkg/cmd/attestation/verify/verify.go b/pkg/cmd/attestation/verify/verify.go index 718f893a2..e1ad77b1e 100644 --- a/pkg/cmd/attestation/verify/verify.go +++ b/pkg/cmd/attestation/verify/verify.go @@ -1,7 +1,6 @@ package verify import ( - // "encoding/json" "errors" "fmt" @@ -106,6 +105,19 @@ func NewVerifyCmd(f *cmdutil.Factory, runF func(*Options) error) *cobra.Command return runF(opts) } + config := verification.SigstoreConfig{ + CustomTrustedRoot: opts.CustomTrustedRoot, + Logger: opts.Logger, + NoPublicGood: opts.NoPublicGood, + } + + sv, err := verification.NewLiveSigstoreVerifier(config) + if err != nil { + return err + } + + opts.SigstoreVerifier = sv + if err := runVerify(opts); err != nil { return fmt.Errorf("Failed to verify the artifact: %v", err) } @@ -163,18 +175,7 @@ func runVerify(opts *Options) error { return fmt.Errorf("failed to build policy: %v", err) } - config := verification.SigstoreConfig{ - CustomTrustedRoot: opts.CustomTrustedRoot, - Logger: opts.Logger, - NoPublicGood: opts.NoPublicGood, - } - - sv, err := verification.NewSigstoreVerifier(config, policy) - if err != nil { - return err - } - - sigstoreRes := sv.Verify(attestations) + sigstoreRes := opts.SigstoreVerifier.Verify(attestations, policy) if sigstoreRes.Error != nil { return fmt.Errorf("at least one attestation failed to verify against Sigstore: %v", sigstoreRes.Error) } diff --git a/pkg/cmd/attestation/verify/verify_test.go b/pkg/cmd/attestation/verify/verify_test.go index b4cd864fc..1959ed40c 100644 --- a/pkg/cmd/attestation/verify/verify_test.go +++ b/pkg/cmd/attestation/verify/verify_test.go @@ -58,12 +58,13 @@ func TestNewVerifyCmd(t *testing.T) { name: "Invalid digest-alg flag", cli: fmt.Sprintf("%s --bundle %s --digest-alg sha384 --owner sigstore", artifactPath, bundlePath), wants: Options{ - ArtifactPath: test.NormalizeRelativePath("../test/data/sigstore-js-2.1.0.tgz"), - BundlePath: test.NormalizeRelativePath("../test/data/sigstore-js-2.1.0-bundle.json"), - DigestAlgorithm: "sha384", - Limit: 30, - OIDCIssuer: GitHubOIDCIssuer, - Owner: "sigstore", + ArtifactPath: test.NormalizeRelativePath("../test/data/sigstore-js-2.1.0.tgz"), + BundlePath: test.NormalizeRelativePath("../test/data/sigstore-js-2.1.0-bundle.json"), + DigestAlgorithm: "sha384", + Limit: 30, + OIDCIssuer: GitHubOIDCIssuer, + Owner: "sigstore", + SigstoreVerifier: verification.NewMockSigstoreVerifier(t), }, wantsErr: true, }, @@ -71,13 +72,14 @@ func TestNewVerifyCmd(t *testing.T) { name: "Use default digest-alg value", cli: fmt.Sprintf("%s --bundle %s --owner sigstore", artifactPath, bundlePath), wants: Options{ - ArtifactPath: test.NormalizeRelativePath("../test/data/sigstore-js-2.1.0.tgz"), - BundlePath: test.NormalizeRelativePath("../test/data/sigstore-js-2.1.0-bundle.json"), - DigestAlgorithm: "sha256", - Limit: 30, - OIDCIssuer: GitHubOIDCIssuer, - Owner: "sigstore", - SANRegex: "^https://github.com/sigstore/", + ArtifactPath: test.NormalizeRelativePath("../test/data/sigstore-js-2.1.0.tgz"), + BundlePath: test.NormalizeRelativePath("../test/data/sigstore-js-2.1.0-bundle.json"), + DigestAlgorithm: "sha256", + Limit: 30, + OIDCIssuer: GitHubOIDCIssuer, + Owner: "sigstore", + SANRegex: "^https://github.com/sigstore/", + SigstoreVerifier: verification.NewMockSigstoreVerifier(t), }, wantsErr: false, }, @@ -85,13 +87,14 @@ func TestNewVerifyCmd(t *testing.T) { name: "Use custom digest-alg value", cli: fmt.Sprintf("%s --bundle %s --owner sigstore --digest-alg sha512", artifactPath, bundlePath), wants: Options{ - ArtifactPath: test.NormalizeRelativePath("../test/data/sigstore-js-2.1.0.tgz"), - BundlePath: test.NormalizeRelativePath("../test/data/sigstore-js-2.1.0-bundle.json"), - DigestAlgorithm: "sha512", - Limit: 30, - OIDCIssuer: GitHubOIDCIssuer, - Owner: "sigstore", - SANRegex: "^https://github.com/sigstore/", + ArtifactPath: test.NormalizeRelativePath("../test/data/sigstore-js-2.1.0.tgz"), + BundlePath: test.NormalizeRelativePath("../test/data/sigstore-js-2.1.0-bundle.json"), + DigestAlgorithm: "sha512", + Limit: 30, + OIDCIssuer: GitHubOIDCIssuer, + Owner: "sigstore", + SANRegex: "^https://github.com/sigstore/", + SigstoreVerifier: verification.NewMockSigstoreVerifier(t), }, wantsErr: false, }, @@ -99,12 +102,13 @@ func TestNewVerifyCmd(t *testing.T) { name: "Missing owner and repo flags", cli: artifactPath, wants: Options{ - ArtifactPath: test.NormalizeRelativePath("../test/data/sigstore-js-2.1.0.tgz"), - DigestAlgorithm: "sha256", - OIDCIssuer: GitHubOIDCIssuer, - Owner: "sigstore", - Limit: 30, - SANRegex: "^https://github.com/sigstore/", + ArtifactPath: test.NormalizeRelativePath("../test/data/sigstore-js-2.1.0.tgz"), + DigestAlgorithm: "sha256", + OIDCIssuer: GitHubOIDCIssuer, + Owner: "sigstore", + Limit: 30, + SANRegex: "^https://github.com/sigstore/", + SigstoreVerifier: verification.NewMockSigstoreVerifier(t), }, wantsErr: true, }, @@ -112,12 +116,13 @@ func TestNewVerifyCmd(t *testing.T) { name: "Has both owner and repo flags", cli: fmt.Sprintf("%s --owner sigstore --repo sigstore/sigstore-js", artifactPath), wants: Options{ - ArtifactPath: artifactPath, - DigestAlgorithm: "sha256", - OIDCIssuer: GitHubOIDCIssuer, - Owner: "sigstore", - Repo: "sigstore/sigstore-js", - Limit: 30, + ArtifactPath: artifactPath, + DigestAlgorithm: "sha256", + OIDCIssuer: GitHubOIDCIssuer, + Owner: "sigstore", + Repo: "sigstore/sigstore-js", + Limit: 30, + SigstoreVerifier: verification.NewMockSigstoreVerifier(t), }, wantsErr: true, }, @@ -125,12 +130,13 @@ func TestNewVerifyCmd(t *testing.T) { name: "Uses default limit flag", cli: fmt.Sprintf("%s --owner sigstore", artifactPath), wants: Options{ - ArtifactPath: artifactPath, - DigestAlgorithm: "sha256", - Limit: 30, - OIDCIssuer: GitHubOIDCIssuer, - Owner: "sigstore", - SANRegex: "^https://github.com/sigstore/", + ArtifactPath: artifactPath, + DigestAlgorithm: "sha256", + Limit: 30, + OIDCIssuer: GitHubOIDCIssuer, + Owner: "sigstore", + SANRegex: "^https://github.com/sigstore/", + SigstoreVerifier: verification.NewMockSigstoreVerifier(t), }, wantsErr: false, }, @@ -138,12 +144,13 @@ func TestNewVerifyCmd(t *testing.T) { name: "Uses custom limit flag", cli: fmt.Sprintf("%s --owner sigstore --limit 101", artifactPath), wants: Options{ - ArtifactPath: artifactPath, - DigestAlgorithm: "sha256", - OIDCIssuer: GitHubOIDCIssuer, - Owner: "sigstore", - Limit: 101, - SANRegex: "^https://github.com/sigstore/", + ArtifactPath: artifactPath, + DigestAlgorithm: "sha256", + OIDCIssuer: GitHubOIDCIssuer, + Owner: "sigstore", + Limit: 101, + SANRegex: "^https://github.com/sigstore/", + SigstoreVerifier: verification.NewMockSigstoreVerifier(t), }, wantsErr: false, }, @@ -151,12 +158,13 @@ func TestNewVerifyCmd(t *testing.T) { name: "Uses invalid limit flag", cli: fmt.Sprintf("%s --owner sigstore --limit 0", artifactPath), wants: Options{ - ArtifactPath: artifactPath, - DigestAlgorithm: "sha256", - OIDCIssuer: GitHubOIDCIssuer, - Owner: "sigstore", - Limit: 0, - SANRegex: "^https://github.com/sigstore/", + ArtifactPath: artifactPath, + DigestAlgorithm: "sha256", + OIDCIssuer: GitHubOIDCIssuer, + Owner: "sigstore", + Limit: 0, + SANRegex: "^https://github.com/sigstore/", + SigstoreVerifier: verification.NewMockSigstoreVerifier(t), }, wantsErr: true, }, @@ -164,13 +172,14 @@ func TestNewVerifyCmd(t *testing.T) { name: "Has both cert-identity and cert-identity-regex flags", cli: fmt.Sprintf("%s --owner sigstore --cert-identity https://github.com/sigstore/ --cert-identity-regex ^https://github.com/sigstore/", artifactPath), wants: Options{ - ArtifactPath: artifactPath, - DigestAlgorithm: "sha256", - Limit: 30, - OIDCIssuer: GitHubOIDCIssuer, - Owner: "sigstore", - SAN: "https://github.com/sigstore/", - SANRegex: "^https://github.com/sigstore/", + ArtifactPath: artifactPath, + DigestAlgorithm: "sha256", + Limit: 30, + OIDCIssuer: GitHubOIDCIssuer, + Owner: "sigstore", + SAN: "https://github.com/sigstore/", + SANRegex: "^https://github.com/sigstore/", + SigstoreVerifier: verification.NewMockSigstoreVerifier(t), }, wantsErr: true, }, @@ -178,13 +187,14 @@ func TestNewVerifyCmd(t *testing.T) { name: "Prints output in JSON format", cli: fmt.Sprintf("%s --bundle %s --owner sigstore --format json", artifactPath, bundlePath), wants: Options{ - ArtifactPath: artifactPath, - BundlePath: bundlePath, - DigestAlgorithm: "sha256", - Limit: 30, - OIDCIssuer: GitHubOIDCIssuer, - Owner: "sigstore", - SANRegex: "^https://github.com/sigstore/", + ArtifactPath: artifactPath, + BundlePath: bundlePath, + DigestAlgorithm: "sha256", + Limit: 30, + OIDCIssuer: GitHubOIDCIssuer, + Owner: "sigstore", + SANRegex: "^https://github.com/sigstore/", + SigstoreVerifier: verification.NewMockSigstoreVerifier(t), }, wantsExporter: true, }, @@ -233,16 +243,17 @@ func TestNewVerifyCmd(t *testing.T) { func TestJSONOutput(t *testing.T) { testIO, _, out, _ := iostreams.Test() opts := Options{ - ArtifactPath: artifactPath, - BundlePath: bundlePath, - DigestAlgorithm: "sha512", - APIClient: api.NewTestClient(), - Logger: io.NewHandler(testIO), - OCIClient: oci.MockClient{}, - OIDCIssuer: GitHubOIDCIssuer, - Owner: "sigstore", - SANRegex: "^https://github.com/sigstore/", - exporter: cmdutil.NewJSONExporter(), + ArtifactPath: artifactPath, + BundlePath: bundlePath, + DigestAlgorithm: "sha512", + APIClient: api.NewTestClient(), + Logger: io.NewHandler(testIO), + OCIClient: oci.MockClient{}, + OIDCIssuer: GitHubOIDCIssuer, + Owner: "sigstore", + SANRegex: "^https://github.com/sigstore/", + SigstoreVerifier: verification.NewMockSigstoreVerifier(t), + exporter: cmdutil.NewJSONExporter(), } require.Nil(t, runVerify(&opts)) @@ -255,15 +266,16 @@ func TestRunVerify(t *testing.T) { logger := io.NewTestHandler() publicGoodOpts := Options{ - ArtifactPath: artifactPath, - BundlePath: bundlePath, - DigestAlgorithm: "sha512", - APIClient: api.NewTestClient(), - Logger: logger, - OCIClient: oci.MockClient{}, - OIDCIssuer: GitHubOIDCIssuer, - Owner: "sigstore", - SANRegex: "^https://github.com/sigstore/", + ArtifactPath: artifactPath, + BundlePath: bundlePath, + DigestAlgorithm: "sha512", + APIClient: api.NewTestClient(), + Logger: logger, + OCIClient: oci.MockClient{}, + OIDCIssuer: GitHubOIDCIssuer, + Owner: "sigstore", + SANRegex: "^https://github.com/sigstore/", + SigstoreVerifier: verification.NewMockSigstoreVerifier(t), } t.Run("with valid artifact and bundle", func(t *testing.T) { @@ -330,48 +342,72 @@ func TestRunVerify(t *testing.T) { require.ErrorContains(t, err, "failed to fetch attestations for subject") }) + // TODO: this test can only be tested with a live SigstoreVerifier + // add integration tests or HTTP mocked sigstore verifier tests + // to test this case t.Run("with invalid OIDC issuer", func(t *testing.T) { + t.Skip() opts := publicGoodOpts opts.OIDCIssuer = "not-a-real-issuer" require.Error(t, runVerify(&opts)) }) + // TODO: this test can only be tested with a live SigstoreVerifier + // add integration tests or HTTP mocked sigstore verifier tests + // to test this case t.Run("with SAN enforcement", func(t *testing.T) { + t.Skip() opts := Options{ - ArtifactPath: artifactPath, - BundlePath: bundlePath, - APIClient: api.NewTestClient(), - DigestAlgorithm: "sha512", - Logger: logger, - OIDCIssuer: GitHubOIDCIssuer, - Owner: "sigstore", - SAN: SigstoreSanValue, + ArtifactPath: artifactPath, + BundlePath: bundlePath, + APIClient: api.NewTestClient(), + DigestAlgorithm: "sha512", + Logger: logger, + OIDCIssuer: GitHubOIDCIssuer, + Owner: "sigstore", + SAN: SigstoreSanValue, + SigstoreVerifier: verification.NewMockSigstoreVerifier(t), } require.Nil(t, runVerify(&opts)) }) + // TODO: this test can only be tested with a live SigstoreVerifier + // add integration tests or HTTP mocked sigstore verifier tests + // to test this case t.Run("with invalid SAN", func(t *testing.T) { + t.Skip() opts := publicGoodOpts opts.SAN = "fake san" require.Error(t, runVerify(&opts)) }) + // TODO: this test can only be tested with a live SigstoreVerifier + // add integration tests or HTTP mocked sigstore verifier tests + // to test this case t.Run("with SAN regex enforcement", func(t *testing.T) { + t.Skip() opts := publicGoodOpts opts.SANRegex = SigstoreSanRegex require.Nil(t, runVerify(&opts)) }) + // TODO: this test can only be tested with a live SigstoreVerifier + // add integration tests or HTTP mocked sigstore verifier tests + // to test this case t.Run("with invalid SAN regex", func(t *testing.T) { + t.Skip() opts := publicGoodOpts opts.SANRegex = "^https://github.com/sigstore/not-real/" require.Error(t, runVerify(&opts)) }) + // TODO: this test can only be tested with a live SigstoreVerifier + // add integration tests or HTTP mocked sigstore verifier tests + // to test this case t.Run("with no matching OIDC issuer", func(t *testing.T) { + t.Skip() opts := publicGoodOpts opts.OIDCIssuer = "some-other-issuer" - require.Error(t, runVerify(&opts)) })