package verify import ( "testing" "github.com/cli/cli/v2/pkg/cmd/attestation/verification" "github.com/stretchr/testify/require" ) func TestNewEnforcementCriteria(t *testing.T) { artifactPath := "../test/data/sigstore-js-2.1.0.tgz" t.Run("sets SANRegex and SAN using SANRegex and SAN", func(t *testing.T) { opts := &Options{ ArtifactPath: artifactPath, Owner: "foo", Repo: "foo/bar", SAN: "https://github/foo/bar/.github/workflows/attest.yml", SANRegex: "(?i)^https://github/foo", SignerRepo: "wrong/value", SignerWorkflow: "wrong/value/.github/workflows/attest.yml", } c, err := newEnforcementCriteria(opts) require.NoError(t, err) require.Equal(t, "https://github/foo/bar/.github/workflows/attest.yml", c.SAN) require.Equal(t, "(?i)^https://github/foo", c.SANRegex) }) t.Run("sets SANRegex using SignerRepo", func(t *testing.T) { opts := &Options{ ArtifactPath: artifactPath, Owner: "wrong", Repo: "wrong/value", SignerRepo: "foo/bar", SignerWorkflow: "wrong/value/.github/workflows/attest.yml", } c, err := newEnforcementCriteria(opts) require.NoError(t, err) require.Equal(t, "(?i)^https://github.com/foo/bar/", c.SANRegex) require.Zero(t, c.SAN) }) t.Run("sets SANRegex using SignerRepo and Tenant", func(t *testing.T) { opts := &Options{ ArtifactPath: artifactPath, Owner: "wrong", Repo: "wrong/value", SignerRepo: "foo/bar", SignerWorkflow: "wrong/value/.github/workflows/attest.yml", Tenant: "baz", } c, err := newEnforcementCriteria(opts) require.NoError(t, err) require.Equal(t, "(?i)^https://baz.ghe.com/foo/bar/", c.SANRegex) require.Zero(t, c.SAN) }) t.Run("sets SANRegex using SignerWorkflow matching host regex", func(t *testing.T) { opts := &Options{ ArtifactPath: artifactPath, Owner: "wrong", Repo: "wrong/value", SignerWorkflow: "foo/bar/.github/workflows/attest.yml", Hostname: "github.com", } c, err := newEnforcementCriteria(opts) require.NoError(t, err) require.Equal(t, "^https://github.com/foo/bar/.github/workflows/attest.yml", c.SANRegex) require.Zero(t, c.SAN) }) t.Run("sets SANRegex using opts.Repo", func(t *testing.T) { opts := &Options{ ArtifactPath: artifactPath, Owner: "wrong", Repo: "foo/bar", } c, err := newEnforcementCriteria(opts) require.NoError(t, err) require.Equal(t, "(?i)^https://github.com/foo/bar/", c.SANRegex) }) t.Run("sets SANRegex using opts.Owner", func(t *testing.T) { opts := &Options{ ArtifactPath: artifactPath, Owner: "foo", } c, err := newEnforcementCriteria(opts) require.NoError(t, err) require.Equal(t, "(?i)^https://github.com/foo/", c.SANRegex) }) t.Run("sets Extensions.RunnerEnvironment to GitHubRunner value if opts.DenySelfHostedRunner is true", func(t *testing.T) { opts := &Options{ ArtifactPath: artifactPath, Owner: "foo", Repo: "foo/bar", DenySelfHostedRunner: true, } c, err := newEnforcementCriteria(opts) require.NoError(t, err) require.Equal(t, verification.GitHubRunner, c.Certificate.RunnerEnvironment) }) t.Run("sets Extensions.RunnerEnvironment to * value if opts.DenySelfHostedRunner is false", func(t *testing.T) { opts := &Options{ ArtifactPath: artifactPath, Owner: "foo", Repo: "foo/bar", DenySelfHostedRunner: false, } c, err := newEnforcementCriteria(opts) require.NoError(t, err) require.Zero(t, c.Certificate.RunnerEnvironment) }) t.Run("sets Extensions.SourceRepositoryURI using opts.Repo and opts.Tenant", func(t *testing.T) { opts := &Options{ ArtifactPath: artifactPath, Owner: "foo", Repo: "foo/bar", Tenant: "baz", } c, err := newEnforcementCriteria(opts) require.NoError(t, err) require.Equal(t, "https://baz.ghe.com/foo/bar", c.Certificate.SourceRepositoryURI) }) t.Run("sets Extensions.SourceRepositoryURI using opts.Repo", func(t *testing.T) { opts := &Options{ ArtifactPath: artifactPath, Owner: "foo", Repo: "foo/bar", } c, err := newEnforcementCriteria(opts) require.NoError(t, err) require.Equal(t, "https://github.com/foo/bar", c.Certificate.SourceRepositoryURI) }) t.Run("sets SANRegex and SAN using SANRegex and SAN, sets Extensions.SourceRepositoryURI using opts.Repo", func(t *testing.T) { opts := &Options{ ArtifactPath: artifactPath, Owner: "baz", Repo: "baz/xyz", SAN: "https://github/foo/bar/.github/workflows/attest.yml", SANRegex: "(?i)^https://github/foo", } c, err := newEnforcementCriteria(opts) require.NoError(t, err) require.Equal(t, "https://github/foo/bar/.github/workflows/attest.yml", c.SAN) require.Equal(t, "(?i)^https://github/foo", c.SANRegex) require.Equal(t, "https://github.com/baz/xyz", c.Certificate.SourceRepositoryURI) }) t.Run("sets Extensions.SourceRepositoryOwnerURI using opts.Owner and opts.Tenant", func(t *testing.T) { opts := &Options{ ArtifactPath: artifactPath, Owner: "foo", Repo: "foo/bar", Tenant: "baz", } c, err := newEnforcementCriteria(opts) require.NoError(t, err) require.Equal(t, "https://baz.ghe.com/foo", c.Certificate.SourceRepositoryOwnerURI) }) t.Run("sets Extensions.SourceRepositoryOwnerURI using opts.Owner", func(t *testing.T) { opts := &Options{ ArtifactPath: artifactPath, Owner: "foo", Repo: "foo/bar", } c, err := newEnforcementCriteria(opts) require.NoError(t, err) require.Equal(t, "https://github.com/foo", c.Certificate.SourceRepositoryOwnerURI) }) t.Run("sets OIDCIssuer using opts.Tenant", func(t *testing.T) { opts := &Options{ ArtifactPath: artifactPath, Owner: "foo", Repo: "foo/bar", Tenant: "baz", OIDCIssuer: verification.GitHubOIDCIssuer, } c, err := newEnforcementCriteria(opts) require.NoError(t, err) require.Equal(t, "https://token.actions.baz.ghe.com", c.Certificate.Issuer) }) t.Run("sets OIDCIssuer using opts.OIDCIssuer", func(t *testing.T) { opts := &Options{ ArtifactPath: artifactPath, Owner: "foo", Repo: "foo/bar", OIDCIssuer: "https://foo.com", Tenant: "baz", } c, err := newEnforcementCriteria(opts) require.NoError(t, err) require.Equal(t, "https://foo.com", c.Certificate.Issuer) }) t.Run("sets Certificate.BuildSignerDigest using opts.SignerDigest", func(t *testing.T) { opts := &Options{ ArtifactPath: artifactPath, Owner: "wrong", Repo: "wrong/value", SignerDigest: "foo", Hostname: "github.com", } c, err := newEnforcementCriteria(opts) require.NoError(t, err) require.Equal(t, "foo", c.Certificate.BuildSignerDigest) }) t.Run("sets Certificate.SourceRepositoryDigest using opts.SourceDigest", func(t *testing.T) { opts := &Options{ ArtifactPath: artifactPath, Owner: "wrong", Repo: "wrong/value", SourceDigest: "foo", Hostname: "github.com", } c, err := newEnforcementCriteria(opts) require.NoError(t, err) require.Equal(t, "foo", c.Certificate.SourceRepositoryDigest) }) t.Run("sets Certificate.SourceRepositoryRef using opts.SourceRef", func(t *testing.T) { opts := &Options{ ArtifactPath: artifactPath, Owner: "wrong", Repo: "wrong/value", SourceRef: "refs/heads/main", Hostname: "github.com", } c, err := newEnforcementCriteria(opts) require.NoError(t, err) require.Equal(t, "refs/heads/main", c.Certificate.SourceRepositoryRef) }) } func TestValidateSignerWorkflow(t *testing.T) { type testcase struct { name string providedSignerWorkflow string expectedWorkflowRegex string host string expectErr bool errContains string } testcases := []testcase{ { name: "workflow with no host specified", providedSignerWorkflow: "github/artifact-attestations-workflows/.github/workflows/attest.yml", expectErr: true, errContains: "unknown signer workflow host", }, { name: "workflow with default host", providedSignerWorkflow: "github/artifact-attestations-workflows/.github/workflows/attest.yml", expectedWorkflowRegex: "^https://github.com/github/artifact-attestations-workflows/.github/workflows/attest.yml", host: "github.com", }, { name: "workflow with workflow URL included", providedSignerWorkflow: "github.com/github/artifact-attestations-workflows/.github/workflows/attest.yml", expectedWorkflowRegex: "^https://github.com/github/artifact-attestations-workflows/.github/workflows/attest.yml", host: "github.com", }, { name: "workflow with GH_HOST set", providedSignerWorkflow: "github/artifact-attestations-workflows/.github/workflows/attest.yml", expectedWorkflowRegex: "^https://myhost.github.com/github/artifact-attestations-workflows/.github/workflows/attest.yml", host: "myhost.github.com", }, { name: "workflow with authenticated host", providedSignerWorkflow: "github/artifact-attestations-workflows/.github/workflows/attest.yml", expectedWorkflowRegex: "^https://authedhost.github.com/github/artifact-attestations-workflows/.github/workflows/attest.yml", host: "authedhost.github.com", }, } for _, tc := range testcases { // All host resolution is done verify.go:RunE workflowRegex, err := validateSignerWorkflow(tc.host, tc.providedSignerWorkflow) require.Equal(t, tc.expectedWorkflowRegex, workflowRegex) if tc.expectErr { require.Error(t, err) require.ErrorContains(t, err, tc.errContains) } else { require.NoError(t, err) require.Equal(t, tc.expectedWorkflowRegex, workflowRegex) } } }