diff --git a/internal/commands/validate.go b/internal/commands/validate.go index b9b2fdab..448ac314 100644 --- a/internal/commands/validate.go +++ b/internal/commands/validate.go @@ -2,7 +2,6 @@ package commands import ( "fmt" - "slices" "strings" "github.com/go-git/go-billy/v5" @@ -40,15 +39,7 @@ func (v Validate) Execute(args []string) error { return fmt.Errorf("failed to load kilnfiles: %w", err) } - if len(v.Options.ReleaseSourceTypeAllowList) > 0 { - for _, s := range kf.ReleaseSources { - if !slices.Contains(v.Options.ReleaseSourceTypeAllowList, s.Type) { - return fmt.Errorf("release source type not allowed: %s", s.Type) - } - } - } - - errs := cargo.Validate(kf, lock) + errs := cargo.Validate(kf, lock, cargo.ValidateResourceTypeAllowList(v.Options.ReleaseSourceTypeAllowList...)) if len(errs) > 0 { return errorList(errs) } diff --git a/internal/commands/validate_test.go b/internal/commands/validate_test.go new file mode 100644 index 00000000..d3b6dbd6 --- /dev/null +++ b/internal/commands/validate_test.go @@ -0,0 +1,66 @@ +package commands_test + +import ( + "io" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + + "github.com/go-git/go-billy/v5" + "github.com/go-git/go-billy/v5/memfs" + + "github.com/pivotal-cf/kiln/internal/commands" +) + +var _ = Describe("validate", func() { + var ( + validate commands.Validate + directory billy.Filesystem + ) + + BeforeEach(func() { + directory = memfs.New() + }) + + JustBeforeEach(func() { + validate = commands.NewValidate(directory) + }) + + When("the kilnfile has two release_sources", func() { + BeforeEach(func() { + f, err := directory.Create("Kilnfile") + Expect(err).NotTo(HaveOccurred()) + _, _ = io.WriteString(f, `--- +release_sources: + - type: "bosh.io" + - type: "github" +`) + _ = f.Close() + }) + + BeforeEach(func() { + f, err := directory.Create("Kilnfile.lock") + Expect(err).NotTo(HaveOccurred()) + _ = f.Close() + }) + + When("both types are in the allow list", func() { + It("it does fail", func() { + err := validate.Execute([]string{ + "--allow-release-source-type=bosh.io", + "--allow-release-source-type=github", + }) + Expect(err).NotTo(HaveOccurred()) + }) + }) + When("both one of the types is not in the allow list", func() { + It("it does fail", func() { + err := validate.Execute([]string{ + "--allow-release-source-type=bosh.io", + }) + Expect(err).To(MatchError(ContainSubstring("release source type not allowed: github"))) + }) + }) + }) + +}) diff --git a/pkg/cargo/validate.go b/pkg/cargo/validate.go index c3f036e0..94b2e751 100644 --- a/pkg/cargo/validate.go +++ b/pkg/cargo/validate.go @@ -7,9 +7,41 @@ import ( "github.com/Masterminds/semver/v3" ) -func Validate(spec Kilnfile, lock KilnfileLock) []error { +type ValidationOptions struct { + resourceTypeAllowList []string +} + +func ValidateResourceTypeAllowList(allowList ...string) ValidationOptions { + return ValidationOptions{}.SetValidateResourceTypeAllowList(allowList) +} + +func (o ValidationOptions) SetValidateResourceTypeAllowList(allowList []string) ValidationOptions { + o.resourceTypeAllowList = allowList + return o +} + +func mergeOptions(options []ValidationOptions) ValidationOptions { + var opt ValidationOptions + for _, o := range options { + if o.resourceTypeAllowList != nil { + opt.resourceTypeAllowList = o.resourceTypeAllowList + } + } + return opt +} + +func Validate(spec Kilnfile, lock KilnfileLock, options ...ValidationOptions) []error { + opt := mergeOptions(options) var result []error + if len(opt.resourceTypeAllowList) > 0 { + for _, s := range spec.ReleaseSources { + if !slices.Contains(opt.resourceTypeAllowList, s.Type) { + result = append(result, fmt.Errorf("release source type not allowed: %s", s.Type)) + } + } + } + for index, componentSpec := range spec.Releases { if componentSpec.Name == "" { result = append(result, fmt.Errorf("release at index %d missing name in spec", index)) diff --git a/pkg/cargo/validate_test.go b/pkg/cargo/validate_test.go index bb352136..aa23fe2a 100644 --- a/pkg/cargo/validate_test.go +++ b/pkg/cargo/validate_test.go @@ -4,6 +4,8 @@ import ( "testing" . "github.com/onsi/gomega" + + "github.com/stretchr/testify/assert" ) const ( @@ -296,3 +298,32 @@ func TestValidate_checkComponentVersionsAndConstraint(t *testing.T) { )) }) } + +func TestValidateWithOptions(t *testing.T) { + t.Run("resource type allow list", func(t *testing.T) { + t.Run("when the types are permitted", func(t *testing.T) { + kf := Kilnfile{ + ReleaseSources: []ReleaseSourceConfig{ + {Type: "farm"}, + {Type: "orchard"}, + }, + } + kl := KilnfileLock{} + errs := Validate(kf, kl, ValidateResourceTypeAllowList("orchard", "farm")) + assert.Zero(t, errs) + }) + t.Run("when one of the types is not in the allow list", func(t *testing.T) { + kf := Kilnfile{ + ReleaseSources: []ReleaseSourceConfig{ + {Type: "farm"}, + {Type: "orchard"}, + }, + } + kl := KilnfileLock{} + errs := Validate(kf, kl, ValidateResourceTypeAllowList("orchard")) + if assert.Len(t, errs, 1) { + assert.ErrorContains(t, errs[0], "release source type not allowed: farm") + } + }) + }) +}