add tests for CLI commands

Signed-off-by: Meredith Lancaster <malancas@github.com>
This commit is contained in:
Meredith Lancaster 2024-03-13 07:46:57 -06:00
parent be8ce2b23a
commit 9becdc5a26
13 changed files with 519 additions and 232 deletions

View file

@ -29,9 +29,9 @@ func NewCmdAttestation(f *cmdutil.Factory) *cobra.Command {
`, "`"),
}
root.AddCommand(download.NewDownloadCmd(f))
root.AddCommand(inspect.NewInspectCmd(f))
root.AddCommand(verify.NewVerifyCmd(f))
root.AddCommand(download.NewDownloadCmd(f, nil))
root.AddCommand(inspect.NewInspectCmd(f, nil))
root.AddCommand(verify.NewVerifyCmd(f, nil))
root.AddCommand(tufrootverify.NewTUFRootVerifyCmd(f))
return root

View file

@ -17,7 +17,7 @@ import (
"github.com/spf13/cobra"
)
func NewDownloadCmd(f *cmdutil.Factory) *cobra.Command {
func NewDownloadCmd(f *cmdutil.Factory, runF func(*Options) error) *cobra.Command {
opts := &Options{}
downloadCmd := &cobra.Command{
Use: "download [<file path> | oci://<OCI image URI>]",
@ -85,6 +85,11 @@ func NewDownloadCmd(f *cmdutil.Factory) *cobra.Command {
if err := auth.IsHostSupported(); err != nil {
return err
}
if runF != nil {
return runF(opts)
}
if err := runDownload(opts); err != nil {
return fmt.Errorf("Failed to download the artifact's bundle(s): %w", err)
}

View file

@ -2,7 +2,9 @@ package download
import (
"bufio"
"bytes"
"fmt"
"net/http"
"os"
"path"
"testing"
@ -11,10 +13,164 @@ import (
"github.com/cli/cli/v2/pkg/cmd/attestation/artifact"
"github.com/cli/cli/v2/pkg/cmd/attestation/artifact/oci"
"github.com/cli/cli/v2/pkg/cmd/attestation/logging"
"github.com/cli/cli/v2/pkg/cmdutil"
"github.com/cli/cli/v2/pkg/httpmock"
"github.com/cli/cli/v2/pkg/iostreams"
"github.com/google/shlex"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestNewDownloadCmd(t *testing.T) {
testIO, _, _, _ := iostreams.Test()
f := &cmdutil.Factory{
IOStreams: testIO,
HttpClient: func() (*http.Client, error) {
reg := &httpmock.Registry{}
client := &http.Client{}
httpmock.ReplaceTripper(client, reg)
return client, nil
},
}
tempDir := t.TempDir()
testcases := []struct {
name string
cli string
wants Options
wantsErr bool
}{
{
name: "Invalid digest-alg flag",
cli: "../test/data/sigstore-js-2.1.0.tgz --owner sigstore --digest-alg sha384",
wants: Options{
ArtifactPath: "../test/data/sigstore-js-2.1.0.tgz",
APIClient: api.NewTestClient(),
OCIClient: oci.MockClient{},
DigestAlgorithm: "sha384",
Owner: "sigstore",
OutputPath: tempDir,
Limit: 30,
},
wantsErr: true,
},
{
name: "Missing digest-alg flag",
cli: "../test/data/sigstore-js-2.1.0.tgz --owner sigstore",
wants: Options{
ArtifactPath: "../test/data/sigstore-js-2.1.0.tgz",
APIClient: api.NewTestClient(),
OCIClient: oci.MockClient{},
DigestAlgorithm: "sha256",
Owner: "sigstore",
OutputPath: tempDir,
Limit: 30,
},
wantsErr: false,
},
{
name: "Missing owner and repo flags",
cli: "../test/data/sigstore-js-2.1.0.tgz",
wants: Options{
ArtifactPath: "../test/data/sigstore-js-2.1.0.tgz",
APIClient: api.NewTestClient(),
OCIClient: oci.MockClient{},
DigestAlgorithm: "sha256",
Owner: "sigstore",
OutputPath: tempDir,
Limit: 30,
},
wantsErr: true,
},
{
name: "Has both owner and repo flags",
cli: "../test/data/sigstore-js-2.1.0.tgz --owner sigstore --repo sigstore/sigstore-js",
wants: Options{
ArtifactPath: "../test/data/sigstore-js-2.1.0.tgz",
APIClient: api.NewTestClient(),
OCIClient: oci.MockClient{},
DigestAlgorithm: "sha256",
Owner: "sigstore",
OutputPath: tempDir,
Repo: "sigstore/sigstore-js",
Limit: 30,
},
wantsErr: true,
},
{
name: "Uses default limit flag",
cli: "../test/data/sigstore-js-2.1.0.tgz --owner sigstore",
wants: Options{
ArtifactPath: "../test/data/sigstore-js-2.1.0.tgz",
APIClient: api.NewTestClient(),
OCIClient: oci.MockClient{},
DigestAlgorithm: "sha256",
Owner: "sigstore",
OutputPath: tempDir,
Limit: 30,
},
wantsErr: false,
},
{
name: "Uses custom limit flag",
cli: "../test/data/sigstore-js-2.1.0.tgz --owner sigstore --limit 101",
wants: Options{
ArtifactPath: "../test/data/sigstore-js-2.1.0.tgz",
APIClient: api.NewTestClient(),
OCIClient: oci.MockClient{},
DigestAlgorithm: "sha256",
Owner: "sigstore",
OutputPath: tempDir,
Limit: 101,
},
wantsErr: false,
},
{
name: "Uses invalid limit flag",
cli: "../test/data/sigstore-js-2.1.0.tgz --owner sigstore --limit 0",
wants: Options{
ArtifactPath: "../test/data/sigstore-js-2.1.0.tgz",
APIClient: api.NewTestClient(),
OCIClient: oci.MockClient{},
DigestAlgorithm: "sha256",
Owner: "sigstore",
OutputPath: tempDir,
Limit: 0,
},
wantsErr: true,
},
}
for _, tc := range testcases {
t.Run(tc.name, func(t *testing.T) {
var opts *Options
cmd := NewDownloadCmd(f, func(o *Options) error {
opts = o
return nil
})
argv, err := shlex.Split(tc.cli)
assert.NoError(t, err)
cmd.SetArgs(argv)
cmd.SetIn(&bytes.Buffer{})
cmd.SetOut(&bytes.Buffer{})
cmd.SetErr(&bytes.Buffer{})
_, err = cmd.ExecuteC()
if tc.wantsErr {
assert.Error(t, err)
return
}
assert.NoError(t, err)
assert.Equal(t, tc.wants.DigestAlgorithm, opts.DigestAlgorithm)
assert.Equal(t, tc.wants.Limit, opts.Limit)
assert.Equal(t, tc.wants.Owner, opts.Owner)
assert.Equal(t, tc.wants.Repo, opts.Repo)
})
}
}
func TestRunDownload(t *testing.T) {
tempDir := t.TempDir()

View file

@ -4,11 +4,15 @@ import (
"fmt"
"github.com/cli/cli/v2/pkg/cmd/attestation/api"
"github.com/cli/cli/v2/pkg/cmd/attestation/artifact/digest"
"github.com/cli/cli/v2/pkg/cmd/attestation/artifact/oci"
"github.com/cli/cli/v2/pkg/cmd/attestation/logging"
)
const (
minLimit = 1
maxLimit = 1000
)
type Options struct {
APIClient api.Client
ArtifactPath string
@ -23,22 +27,9 @@ type Options struct {
}
func (opts *Options) AreFlagsValid() error {
if opts.Owner == "" {
return fmt.Errorf("owner must be provided")
}
// DigestAlgorithm must not be empty
if opts.DigestAlgorithm == "" {
return fmt.Errorf("digest-alg cannot be empty")
}
if !digest.IsValidDigestAlgorithm(opts.DigestAlgorithm) {
return fmt.Errorf("invalid digest algorithm '%s' provided in digest-alg", opts.DigestAlgorithm)
}
// 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)
if opts.Limit < minLimit || opts.Limit > maxLimit {
return fmt.Errorf("limit %d not allowed, must be between %d and %d", opts.Limit, minLimit, maxLimit)
}
return nil

View file

@ -1,53 +1,34 @@
package download
import (
"fmt"
"testing"
"github.com/stretchr/testify/require"
)
func TestAreFlagsValid(t *testing.T) {
t.Run("missing Owner", func(t *testing.T) {
tests := []struct {
name string
limit int
}{
{
name: "Limit is too low",
limit: 0,
},
{
name: "Limit is too high",
limit: 1001,
},
}
for _, tc := range tests {
opts := Options{
DigestAlgorithm: "sha512",
Limit: tc.limit,
}
err := opts.AreFlagsValid()
require.Error(t, err)
require.ErrorContains(t, err, "owner must be provided")
})
t.Run("missing DigestAlgorithm", func(t *testing.T) {
opts := Options{
Owner: "github",
}
err := opts.AreFlagsValid()
require.Error(t, err)
require.ErrorContains(t, err, "digest-alg cannot be empty")
})
t.Run("Limit is too low", func(t *testing.T) {
opts := Options{
DigestAlgorithm: "sha512",
Limit: 0,
Owner: "github",
}
err := opts.AreFlagsValid()
require.Error(t, err)
require.ErrorContains(t, err, "limit 0 not allowed, must be between 1 and 1000")
})
t.Run("Limit is too high", func(t *testing.T) {
opts := Options{
DigestAlgorithm: "sha512",
Limit: 1001,
Owner: "github",
}
err := opts.AreFlagsValid()
require.Error(t, err)
require.ErrorContains(t, err, "limit 1001 not allowed, must be between 1 and 1000")
})
expectedErrMsg := fmt.Sprintf("limit %d not allowed, must be between 1 and 1000", tc.limit)
require.ErrorContains(t, err, expectedErrMsg)
}
}

View file

@ -15,7 +15,7 @@ import (
"github.com/spf13/cobra"
)
func NewInspectCmd(f *cmdutil.Factory) *cobra.Command {
func NewInspectCmd(f *cmdutil.Factory, runF func(*Options) error) *cobra.Command {
opts := &Options{}
inspectCmd := &cobra.Command{
Use: "inspect [<file path> | oci://<OCI image URI>] --bundle <path-to-bundle>",
@ -56,11 +56,6 @@ func NewInspectCmd(f *cmdutil.Factory) *cobra.Command {
// set the artifact path
opts.ArtifactPath = args[0]
// Check that the given flag combination is valid
if err := opts.AreFlagsValid(); err != nil {
return err
}
// Clean file path options
opts.Clean()
@ -72,6 +67,11 @@ func NewInspectCmd(f *cmdutil.Factory) *cobra.Command {
if err := auth.IsHostSupported(); err != nil {
return err
}
if runF != nil {
return runF(opts)
}
if err := runInspect(opts); err != nil {
return fmt.Errorf("Failed to inspect the artifact and bundle: %w", err)
}

View file

@ -1,12 +1,20 @@
package inspect
import (
"bytes"
"net/http"
"testing"
"github.com/cli/cli/v2/pkg/cmd/attestation/artifact/oci"
"github.com/cli/cli/v2/pkg/cmd/attestation/logging"
"github.com/cli/cli/v2/pkg/cmd/attestation/test"
"github.com/cli/cli/v2/pkg/cmdutil"
"github.com/cli/cli/v2/pkg/httpmock"
"github.com/cli/cli/v2/pkg/iostreams"
"github.com/google/shlex"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
@ -20,6 +28,113 @@ var (
bundlePath = test.NormalizeRelativePath("../test/data/sigstore-js-2.1.0-bundle.json")
)
func TestNewInspectCmd(t *testing.T) {
testIO, _, _, _ := iostreams.Test()
f := &cmdutil.Factory{
IOStreams: testIO,
HttpClient: func() (*http.Client, error) {
reg := &httpmock.Registry{}
client := &http.Client{}
httpmock.ReplaceTripper(client, reg)
return client, nil
},
}
testcases := []struct {
name string
cli string
wants Options
wantsErr bool
}{
{
name: "Invalid digest-alg flag",
cli: "../test/data/sigstore-js-2.1.0.tgz --bundle ../test/data/sigstore-js-2.1.0-bundle.json --digest-alg sha384",
wants: Options{
ArtifactPath: "../test/data/sigstore-js-2.1.0.tgz",
BundlePath: "../test/data/sigstore-js-2.1.0-bundle.json",
DigestAlgorithm: "sha384",
OCIClient: oci.MockClient{},
},
wantsErr: true,
},
{
name: "Use default digest-alg value",
cli: "../test/data/sigstore-js-2.1.0.tgz --bundle ../test/data/sigstore-js-2.1.0-bundle.json",
wants: Options{
ArtifactPath: "../test/data/sigstore-js-2.1.0.tgz",
BundlePath: "../test/data/sigstore-js-2.1.0-bundle.json",
DigestAlgorithm: "sha256",
OCIClient: oci.MockClient{},
},
wantsErr: false,
},
{
name: "Use custom digest-alg value",
cli: "../test/data/sigstore-js-2.1.0.tgz --bundle ../test/data/sigstore-js-2.1.0-bundle.json --digest-alg sha512",
wants: Options{
ArtifactPath: "../test/data/sigstore-js-2.1.0.tgz",
BundlePath: "../test/data/sigstore-js-2.1.0-bundle.json",
DigestAlgorithm: "sha512",
OCIClient: oci.MockClient{},
},
wantsErr: false,
},
{
name: "Missing bundle flag",
cli: "../test/data/sigstore-js-2.1.0.tgz",
wants: Options{
ArtifactPath: "../test/data/sigstore-js-2.1.0.tgz",
DigestAlgorithm: "sha256",
OCIClient: oci.MockClient{},
},
wantsErr: true,
},
{
name: "Has both verbose and quiet flags",
cli: "../test/data/sigstore-js-2.1.0.tgz --bundle ../test/data/sigstore-js-2.1.0-bundle.json --verbose --quiet",
wants: Options{
ArtifactPath: "../test/data/sigstore-js-2.1.0.tgz",
BundlePath: "../test/data/sigstore-js-2.1.0-bundle.json",
DigestAlgorithm: "sha256",
OCIClient: oci.MockClient{},
Verbose: true,
Quiet: true,
},
wantsErr: true,
},
}
for _, tc := range testcases {
t.Run(tc.name, func(t *testing.T) {
var opts *Options
cmd := NewInspectCmd(f, func(o *Options) error {
opts = o
return nil
})
argv, err := shlex.Split(tc.cli)
assert.NoError(t, err)
cmd.SetArgs(argv)
cmd.SetIn(&bytes.Buffer{})
cmd.SetOut(&bytes.Buffer{})
cmd.SetErr(&bytes.Buffer{})
_, err = cmd.ExecuteC()
if tc.wantsErr {
assert.Error(t, err)
return
}
assert.NoError(t, err)
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.Equal(t, tc.wants.JsonResult, opts.JsonResult)
assert.Equal(t, tc.wants.Verbose, opts.Verbose)
assert.Equal(t, tc.wants.Quiet, opts.Quiet)
})
}
}
func TestRunInspect(t *testing.T) {
opts := Options{
ArtifactPath: artifactPath,

View file

@ -1,10 +1,8 @@
package inspect
import (
"fmt"
"path/filepath"
"github.com/cli/cli/v2/pkg/cmd/attestation/artifact/digest"
"github.com/cli/cli/v2/pkg/cmd/attestation/artifact/oci"
"github.com/cli/cli/v2/pkg/cmd/attestation/logging"
)
@ -25,23 +23,3 @@ type Options struct {
func (opts *Options) Clean() {
opts.BundlePath = filepath.Clean(opts.BundlePath)
}
// AreFlagsValid checks that the provided flag combination is valid
// and returns an error otherwise
func (opts *Options) AreFlagsValid() error {
// either BundlePath or Repo must be set to configure offline or online mode
if opts.BundlePath == "" {
return fmt.Errorf("bundle must be provided")
}
// DigestAlgorithm must not be empty
if opts.DigestAlgorithm == "" {
return fmt.Errorf("digest-alg cannot be empty")
}
if !digest.IsValidDigestAlgorithm(opts.DigestAlgorithm) {
return fmt.Errorf("invalid digest algorithm '%s' provided in digest-alg", opts.DigestAlgorithm)
}
return nil
}

View file

@ -1,48 +0,0 @@
package inspect
import (
"testing"
"github.com/cli/cli/v2/pkg/cmd/attestation/test"
"github.com/stretchr/testify/require"
)
func TestAreFlagsValid(t *testing.T) {
artifactPath := test.NormalizeRelativePath("../test/data/public-good/sigstore-js-2.1.0.tgz")
bundlePath := test.NormalizeRelativePath("../test/data/public-good/sigstore-js-2.1.0-bundle.json")
t.Run("missing BundlePath", func(t *testing.T) {
opts := Options{
ArtifactPath: artifactPath,
DigestAlgorithm: "sha512",
}
err := opts.AreFlagsValid()
require.Error(t, err)
require.ErrorContains(t, err, "bundle must be provided")
})
t.Run("missing DigestAlgorithm", func(t *testing.T) {
opts := Options{
ArtifactPath: artifactPath,
BundlePath: bundlePath,
}
err := opts.AreFlagsValid()
require.Error(t, err)
require.ErrorContains(t, err, "digest-alg cannot be empty")
})
t.Run("invalid DigestAlgorithm", func(t *testing.T) {
opts := Options{
ArtifactPath: artifactPath,
BundlePath: bundlePath,
DigestAlgorithm: "sha1",
}
err := opts.AreFlagsValid()
require.Error(t, err)
require.ErrorContains(t, err, "invalid digest algorithm 'sha1' provided in digest-alg")
})
}

View file

@ -6,7 +6,6 @@ import (
"strings"
"github.com/cli/cli/v2/pkg/cmd/attestation/api"
"github.com/cli/cli/v2/pkg/cmd/attestation/artifact/digest"
"github.com/cli/cli/v2/pkg/cmd/attestation/artifact/oci"
"github.com/cli/cli/v2/pkg/cmd/attestation/logging"
)
@ -63,35 +62,6 @@ func (opts *Options) SetPolicyFlags() {
// AreFlagsValid checks that the provided flag combination is valid
// and returns an error otherwise
func (opts *Options) AreFlagsValid() error {
// either BundlePath or Repo must be set to configure offline or online mode
if opts.BundlePath == "" && opts.Repo == "" && opts.Owner == "" {
return fmt.Errorf("either bundle or repo or owner must be provided")
}
// DigestAlgorithm must not be empty
if opts.DigestAlgorithm == "" {
return fmt.Errorf("digest-alg cannot be empty")
}
if !digest.IsValidDigestAlgorithm(opts.DigestAlgorithm) {
return fmt.Errorf("invalid digtest algorithm '%s' provided in digest-alg", opts.DigestAlgorithm)
}
// OIDCIssuer must not be empty
if opts.OIDCIssuer == "" {
return fmt.Errorf("cert-oidc-issuer cannot be empty")
}
// either Owner or Repo must be supplied
if opts.Owner == "" && opts.Repo == "" {
return fmt.Errorf("owner or repo must be provided")
}
// SAN or SAN regex are mutually exclusive, only one can be provided
if opts.SAN != "" && opts.SANRegex != "" {
return fmt.Errorf("cert-identity and cert-identity-regex cannot both be provided")
}
// check that Repo is in the expected format if provided
if opts.Repo != "" {
// we expect the repo argument to be in the format <OWNER>/<REPO>

View file

@ -14,60 +14,6 @@ var (
)
func TestAreFlagsValid(t *testing.T) {
t.Run("missing BundlePath, Repo, and Owner", func(t *testing.T) {
opts := Options{
ArtifactPath: publicGoodArtifactPath,
DigestAlgorithm: "sha512",
OIDCIssuer: "some issuer",
}
err := opts.AreFlagsValid()
require.Error(t, err)
require.ErrorContains(t, err, "either bundle or repo or owner must be provided")
})
t.Run("missing DigestAlgorithm", func(t *testing.T) {
opts := Options{
ArtifactPath: publicGoodArtifactPath,
BundlePath: publicGoodBundlePath,
OIDCIssuer: "some issuer",
Owner: "sigstore",
}
err := opts.AreFlagsValid()
require.Error(t, err)
require.ErrorContains(t, err, "digest-alg cannot be empty")
})
t.Run("missing Owner and Repo", func(t *testing.T) {
opts := Options{
ArtifactPath: publicGoodArtifactPath,
BundlePath: publicGoodBundlePath,
DigestAlgorithm: "sha512",
OIDCIssuer: "some issuer",
}
err := opts.AreFlagsValid()
require.Error(t, err)
require.ErrorContains(t, err, "owner or repo must be provided")
})
t.Run("has both SAN and SANRegex", func(t *testing.T) {
opts := Options{
ArtifactPath: publicGoodArtifactPath,
BundlePath: publicGoodBundlePath,
DigestAlgorithm: "sha512",
OIDCIssuer: "some issuer",
Owner: "sigstore",
SAN: "some san",
SANRegex: "^some san regex$",
}
err := opts.AreFlagsValid()
require.Error(t, err)
require.ErrorContains(t, err, "cert-identity and cert-identity-regex cannot both be provided")
})
t.Run("has invalid Repo value", func(t *testing.T) {
opts := Options{
ArtifactPath: publicGoodArtifactPath,
@ -81,19 +27,6 @@ func TestAreFlagsValid(t *testing.T) {
require.ErrorContains(t, err, "invalid value provided for repo")
})
t.Run("missing OIDCIssuer", func(t *testing.T) {
opts := Options{
ArtifactPath: publicGoodArtifactPath,
BundlePath: publicGoodBundlePath,
DigestAlgorithm: "sha512",
Owner: "sigstore",
}
err := opts.AreFlagsValid()
require.Error(t, err)
require.ErrorContains(t, err, "cert-oidc-issuer cannot be empty")
})
t.Run("invalid limit < 0", func(t *testing.T) {
opts := Options{
ArtifactPath: publicGoodArtifactPath,

View file

@ -19,7 +19,7 @@ import (
var ErrNoMatchingSLSAPredicate = fmt.Errorf("the attestation does not have the expected SLSA predicate type: %s", SLSAPredicateType)
func NewVerifyCmd(f *cmdutil.Factory) *cobra.Command {
func NewVerifyCmd(f *cmdutil.Factory, runF func(*Options) error) *cobra.Command {
opts := &Options{}
verifyCmd := &cobra.Command{
Use: "verify <artifact-path-or-url>",
@ -100,6 +100,11 @@ func NewVerifyCmd(f *cmdutil.Factory) *cobra.Command {
if err := auth.IsHostSupported(); err != nil {
return err
}
if runF != nil {
return runF(opts)
}
if err := runVerify(opts); err != nil {
return fmt.Errorf("Failed to verify the artifact: %w", err)
}

View file

@ -1,6 +1,8 @@
package verify
import (
"bytes"
"net/http"
"testing"
"github.com/cli/cli/v2/pkg/cmd/attestation/api"
@ -8,6 +10,12 @@ import (
"github.com/cli/cli/v2/pkg/cmd/attestation/logging"
"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"
"github.com/cli/cli/v2/pkg/iostreams"
"github.com/google/shlex"
"github.com/stretchr/testify/assert"
"github.com/in-toto/in-toto-golang/in_toto"
"github.com/sigstore/sigstore-go/pkg/verify"
@ -20,6 +28,199 @@ const (
SigstoreSanRegex = "^https://github.com/sigstore/sigstore-js/"
)
func TestNewVerifyCmd(t *testing.T) {
testIO, _, _, _ := iostreams.Test()
f := &cmdutil.Factory{
IOStreams: testIO,
HttpClient: func() (*http.Client, error) {
reg := &httpmock.Registry{}
client := &http.Client{}
httpmock.ReplaceTripper(client, reg)
return client, nil
},
}
testcases := []struct {
name string
cli string
wants Options
wantsErr bool
}{
{
name: "Invalid digest-alg flag",
cli: "../test/data/sigstore-js-2.1.0.tgz --bundle ../test/data/sigstore-js-2.1.0-bundle.json --digest-alg sha384 --owner sigstore",
wants: Options{
ArtifactPath: "../test/data/sigstore-js-2.1.0.tgz",
BundlePath: "../test/data/sigstore-js-2.1.0-bundle.json",
DigestAlgorithm: "sha384",
Limit: 30,
OIDCIssuer: GitHubOIDCIssuer,
Owner: "sigstore",
},
wantsErr: true,
},
{
name: "Use default digest-alg value",
cli: "../test/data/sigstore-js-2.1.0.tgz --bundle ../test/data/sigstore-js-2.1.0-bundle.json --owner sigstore",
wants: Options{
ArtifactPath: "../test/data/sigstore-js-2.1.0.tgz",
BundlePath: "../test/data/sigstore-js-2.1.0-bundle.json",
DigestAlgorithm: "sha256",
Limit: 30,
OIDCIssuer: GitHubOIDCIssuer,
Owner: "sigstore",
SANRegex: "^https://github.com/sigstore/",
},
wantsErr: false,
},
{
name: "Use custom digest-alg value",
cli: "../test/data/sigstore-js-2.1.0.tgz --bundle ../test/data/sigstore-js-2.1.0-bundle.json --digest-alg sha512 --owner sigstore",
wants: Options{
ArtifactPath: "../test/data/sigstore-js-2.1.0.tgz",
BundlePath: "../test/data/sigstore-js-2.1.0-bundle.json",
DigestAlgorithm: "sha512",
Limit: 30,
OIDCIssuer: GitHubOIDCIssuer,
Owner: "sigstore",
SANRegex: "^https://github.com/sigstore/",
},
wantsErr: false,
},
{
name: "Missing owner and repo flags",
cli: "../test/data/sigstore-js-2.1.0.tgz",
wants: Options{
ArtifactPath: "../test/data/sigstore-js-2.1.0.tgz",
DigestAlgorithm: "sha256",
OIDCIssuer: GitHubOIDCIssuer,
Owner: "sigstore",
Limit: 30,
SANRegex: "^https://github.com/sigstore/",
},
wantsErr: true,
},
{
name: "Has both owner and repo flags",
cli: "../test/data/sigstore-js-2.1.0.tgz --owner sigstore --repo sigstore/sigstore-js",
wants: Options{
ArtifactPath: "../test/data/sigstore-js-2.1.0.tgz",
DigestAlgorithm: "sha256",
OIDCIssuer: GitHubOIDCIssuer,
Owner: "sigstore",
Repo: "sigstore/sigstore-js",
Limit: 30,
},
wantsErr: true,
},
{
name: "Uses default limit flag",
cli: "../test/data/sigstore-js-2.1.0.tgz --owner sigstore",
wants: Options{
ArtifactPath: "../test/data/sigstore-js-2.1.0.tgz",
DigestAlgorithm: "sha256",
Limit: 30,
OIDCIssuer: GitHubOIDCIssuer,
Owner: "sigstore",
SANRegex: "^https://github.com/sigstore/",
},
wantsErr: false,
},
{
name: "Uses custom limit flag",
cli: "../test/data/sigstore-js-2.1.0.tgz --owner sigstore --limit 101",
wants: Options{
ArtifactPath: "../test/data/sigstore-js-2.1.0.tgz",
DigestAlgorithm: "sha256",
OIDCIssuer: GitHubOIDCIssuer,
Owner: "sigstore",
Limit: 101,
SANRegex: "^https://github.com/sigstore/",
},
wantsErr: false,
},
{
name: "Uses invalid limit flag",
cli: "../test/data/sigstore-js-2.1.0.tgz --owner sigstore --limit 0",
wants: Options{
ArtifactPath: "../test/data/sigstore-js-2.1.0.tgz",
DigestAlgorithm: "sha256",
OIDCIssuer: GitHubOIDCIssuer,
Owner: "sigstore",
Limit: 0,
SANRegex: "^https://github.com/sigstore/",
},
wantsErr: true,
},
{
name: "Has both verbose and quiet flags",
cli: "../test/data/sigstore-js-2.1.0.tgz --bundle ../test/data/sigstore-js-2.1.0-bundle.json --owner sigstore --verbose --quiet",
wants: Options{
ArtifactPath: "../test/data/sigstore-js-2.1.0.tgz",
BundlePath: "../test/data/sigstore-js-2.1.0-bundle.json",
DigestAlgorithm: "sha256",
OIDCIssuer: GitHubOIDCIssuer,
Verbose: true,
Quiet: true,
},
wantsErr: true,
},
{
name: "Has both cert-identity and cert-identity-regex flags",
cli: "../test/data/sigstore-js-2.1.0.tgz --owner sigstore --cert-identity https://github.com/sigstore/ --cert-identity-regex ^https://github.com/sigstore/",
wants: Options{
ArtifactPath: "../test/data/sigstore-js-2.1.0.tgz",
DigestAlgorithm: "sha256",
Limit: 30,
OIDCIssuer: GitHubOIDCIssuer,
Owner: "sigstore",
SAN: "https://github.com/sigstore/",
SANRegex: "^https://github.com/sigstore/",
},
wantsErr: true,
},
}
for _, tc := range testcases {
t.Run(tc.name, func(t *testing.T) {
var opts *Options
cmd := NewVerifyCmd(f, func(o *Options) error {
opts = o
return nil
})
argv, err := shlex.Split(tc.cli)
assert.NoError(t, err)
cmd.SetArgs(argv)
cmd.SetIn(&bytes.Buffer{})
cmd.SetOut(&bytes.Buffer{})
cmd.SetErr(&bytes.Buffer{})
_, err = cmd.ExecuteC()
if tc.wantsErr {
assert.Error(t, err)
return
}
assert.NoError(t, err)
assert.Equal(t, tc.wants.ArtifactPath, opts.ArtifactPath)
assert.Equal(t, tc.wants.BundlePath, opts.BundlePath)
assert.Equal(t, tc.wants.CustomTrustedRoot, opts.CustomTrustedRoot)
assert.Equal(t, tc.wants.DenySelfHostedRunner, opts.DenySelfHostedRunner)
assert.Equal(t, tc.wants.DigestAlgorithm, opts.DigestAlgorithm)
assert.Equal(t, tc.wants.JsonResult, opts.JsonResult)
assert.Equal(t, tc.wants.Limit, opts.Limit)
assert.Equal(t, tc.wants.NoPublicGood, opts.NoPublicGood)
assert.Equal(t, tc.wants.OIDCIssuer, opts.OIDCIssuer)
assert.Equal(t, tc.wants.Owner, opts.Owner)
assert.Equal(t, tc.wants.Quiet, opts.Quiet)
assert.Equal(t, tc.wants.Repo, opts.Repo)
assert.Equal(t, tc.wants.SAN, opts.SAN)
assert.Equal(t, tc.wants.SANRegex, opts.SANRegex)
assert.Equal(t, tc.wants.Verbose, opts.Verbose)
})
}
}
func TestRunVerify(t *testing.T) {
logger := logging.NewTestLogger()