Skip to content

Commit

Permalink
feat: add release_source field validation
Browse files Browse the repository at this point in the history
Co-authored-by: Ajita Jain <jajita@vmware.com>
  • Loading branch information
crhntr and jajita committed Aug 10, 2024
1 parent 73b3d5b commit 084efc1
Show file tree
Hide file tree
Showing 2 changed files with 347 additions and 2 deletions.
63 changes: 61 additions & 2 deletions pkg/cargo/validate.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ package cargo

import (
"fmt"
"slices"

"github.com/Masterminds/semver/v3"
"slices"
"text/template/parse"
)

type ValidationOptions struct {
Expand Down Expand Up @@ -75,6 +75,7 @@ func Validate(spec Kilnfile, lock KilnfileLock, options ...ValidationOptions) []
}

result = append(result, ensureRemoteSourceExistsForEachReleaseLock(spec, lock)...)
result = append(result, ensureReleaseSourceConfiguration(spec.ReleaseSources)...)

if len(result) > 0 {
return result
Expand All @@ -83,6 +84,64 @@ func Validate(spec Kilnfile, lock KilnfileLock, options ...ValidationOptions) []
return nil
}

func ensureReleaseSourceConfiguration(sources []ReleaseSourceConfig) []error {
var errs []error
for _, source := range sources {
switch source.Type {
case BOSHReleaseTarballSourceTypeArtifactory:
if source.ArtifactoryHost == "" {
errs = append(errs, fmt.Errorf("missing required field artifactory_host"))
}
if source.Username == "" {
errs = append(errs, fmt.Errorf("missing required field username"))
}
if source.Password == "" {
errs = append(errs, fmt.Errorf("missing required field password"))
}
if source.Repo == "" {
errs = append(errs, fmt.Errorf("missing required field repo"))
}
if source.PathTemplate == "" {
errs = append(errs, fmt.Errorf("missing required field path_template"))
} else {
p := parse.New("path_template")
p.Mode |= parse.SkipFuncCheck
if _, err := p.Parse(source.PathTemplate, "", "", make(map[string]*parse.Tree)); err != nil {
errs = append(errs, fmt.Errorf("failed to parse path_template: %w", err))
}
}
if source.Bucket != "" {
errs = append(errs, fmt.Errorf("artifactory has unexpected field bucket"))
}
if source.Region != "" {
errs = append(errs, fmt.Errorf("artifactory has unexpected field region"))
}
if source.AccessKeyId != "" {
errs = append(errs, fmt.Errorf("artifactory has unexpected field access_key_id"))
}
if source.SecretAccessKey != "" {
errs = append(errs, fmt.Errorf("artifactory has unexpected field secret_access_key"))
}
if source.RoleARN != "" {
errs = append(errs, fmt.Errorf("artifactory has unexpected field role_arn"))
}
if source.Endpoint != "" {
errs = append(errs, fmt.Errorf("artifactory has unexpected field endpoint"))
}
if source.Org != "" {
errs = append(errs, fmt.Errorf("artifactory has unexpected field org"))
}
if source.GithubToken != "" {
errs = append(errs, fmt.Errorf("artifactory has unexpected field github_token"))
}
case BOSHReleaseTarballSourceTypeBOSHIO:
case BOSHReleaseTarballSourceTypeS3:
case BOSHReleaseTarballSourceTypeGithub:
}
}
return errs
}

func ensureRemoteSourceExistsForEachReleaseLock(spec Kilnfile, lock KilnfileLock) []error {
var result []error
for _, release := range lock.Releases {
Expand Down
286 changes: 286 additions & 0 deletions pkg/cargo/validate_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package cargo

import (
"github.com/stretchr/testify/require"
"testing"

. "github.com/onsi/gomega"
Expand Down Expand Up @@ -326,4 +327,289 @@ func TestValidateWithOptions(t *testing.T) {
}
})
})

t.Run("when a release_source is not configured properly", func(t *testing.T) {
for _, tt := range []struct {
Name string
Sources []ReleaseSourceConfig
Error func(t *testing.T, errs []error)
}{
{
Name: "artifactory host is empty",
Sources: []ReleaseSourceConfig{
{
Type: BOSHReleaseTarballSourceTypeArtifactory,
ID: "",
// ArtifactoryHost: "http://example.com",
Username: "bot",
Password: "beep boop",
Repo: "secret-stash",
PathTemplate: "some-path",
},
},
Error: func(t *testing.T, errs []error) {
require.Len(t, errs, 1)
assert.ErrorContains(t, errs[0], "missing required field artifactory_host")
},
},
{
Name: "artifactory password is empty",
Sources: []ReleaseSourceConfig{
{
Type: BOSHReleaseTarballSourceTypeArtifactory,
ID: "",
ArtifactoryHost: "http://example.com",
Username: "bot",
// Password: "beep boop",
Repo: "secret-stash",
PathTemplate: "some-path",
},
},
Error: func(t *testing.T, errs []error) {
require.Len(t, errs, 1)
assert.ErrorContains(t, errs[0], "missing required field password")
},
},
{
Name: "artifactory username is empty",
Sources: []ReleaseSourceConfig{
{
Type: BOSHReleaseTarballSourceTypeArtifactory,
ID: "",
ArtifactoryHost: "http://example.com",
// Username: "bot",
Password: "beep boop",
Repo: "secret-stash",
PathTemplate: "some-path",
},
},
Error: func(t *testing.T, errs []error) {
require.Len(t, errs, 1)
assert.ErrorContains(t, errs[0], "missing required field username")
},
},
{
Name: "artifactory repo is empty",
Sources: []ReleaseSourceConfig{
{
Type: BOSHReleaseTarballSourceTypeArtifactory,
ID: "",
ArtifactoryHost: "http://example.com",
Username: "bot",
Password: "beep boop",
// Repo: "secret-stash",
PathTemplate: "some-path",
},
},
Error: func(t *testing.T, errs []error) {
require.Len(t, errs, 1)
assert.ErrorContains(t, errs[0], "missing required field repo")
},
},
{
Name: "artifactory path_template is empty",
Sources: []ReleaseSourceConfig{
{
Type: BOSHReleaseTarballSourceTypeArtifactory,
ID: "",
ArtifactoryHost: "http://example.com",
Username: "bot",
Password: "beep boop",
Repo: "secret-stash",
// PathTemplate: "some-path",
},
},
Error: func(t *testing.T, errs []error) {
require.Len(t, errs, 1)
assert.ErrorContains(t, errs[0], "missing required field path_template")
},
},
{
Name: "artifactory path_template is malformed",
Sources: []ReleaseSourceConfig{
{
Type: BOSHReleaseTarballSourceTypeArtifactory,
ID: "",
ArtifactoryHost: "http://example.com",
Username: "bot",
Password: "beep boop",
Repo: "secret-stash",
PathTemplate: "{{ loosing power",
},
},
Error: func(t *testing.T, errs []error) {
require.Len(t, errs, 1)
assert.ErrorContains(t, errs[0], "failed to parse path_template:")
},
},
{
Name: "artifactory has unexpected field bucket",
Sources: []ReleaseSourceConfig{
{
Type: BOSHReleaseTarballSourceTypeArtifactory,
ID: "",
ArtifactoryHost: "http://example.com",
Username: "bot",
Password: "beep boop",
Repo: "secret-stash",
PathTemplate: "ok",

Bucket: "UNEXPECTED",
},
},
Error: func(t *testing.T, errs []error) {
require.Len(t, errs, 1)
assert.ErrorContains(t, errs[0], "unexpected field bucket")
},
},
{
Name: "artifactory has unexpected field region",
Sources: []ReleaseSourceConfig{
{
Type: BOSHReleaseTarballSourceTypeArtifactory,
ID: "",
ArtifactoryHost: "http://example.com",
Username: "bot",
Password: "beep boop",
Repo: "secret-stash",
PathTemplate: "ok",

Region: "UNEXPECTED",
},
},
Error: func(t *testing.T, errs []error) {
require.Len(t, errs, 1)
assert.ErrorContains(t, errs[0], "unexpected field region")
},
},
{
Name: "artifactory has unexpected field access_key_id",
Sources: []ReleaseSourceConfig{
{
Type: BOSHReleaseTarballSourceTypeArtifactory,
ID: "",
ArtifactoryHost: "http://example.com",
Username: "bot",
Password: "beep boop",
Repo: "secret-stash",
PathTemplate: "ok",

AccessKeyId: "UNEXPECTED",
},
},
Error: func(t *testing.T, errs []error) {
require.Len(t, errs, 1)
assert.ErrorContains(t, errs[0], "unexpected field access_key_id")
},
},
{
Name: "artifactory has unexpected field secret_access_key",
Sources: []ReleaseSourceConfig{
{
Type: BOSHReleaseTarballSourceTypeArtifactory,
ID: "",
ArtifactoryHost: "http://example.com",
Username: "bot",
Password: "beep boop",
Repo: "secret-stash",
PathTemplate: "ok",

SecretAccessKey: "UNEXPECTED",
},
},
Error: func(t *testing.T, errs []error) {
require.Len(t, errs, 1)
assert.ErrorContains(t, errs[0], "unexpected field secret_access_key")
},
},
{
Name: "artifactory has unexpected field role_arn",
Sources: []ReleaseSourceConfig{
{
Type: BOSHReleaseTarballSourceTypeArtifactory,
ID: "",
ArtifactoryHost: "http://example.com",
Username: "bot",
Password: "beep boop",
Repo: "secret-stash",
PathTemplate: "ok",

RoleARN: "UNEXPECTED",
},
},
Error: func(t *testing.T, errs []error) {
require.Len(t, errs, 1)
assert.ErrorContains(t, errs[0], "unexpected field role_arn")
},
},
{
Name: "artifactory has unexpected field endpoint",
Sources: []ReleaseSourceConfig{
{
Type: BOSHReleaseTarballSourceTypeArtifactory,
ID: "",
ArtifactoryHost: "http://example.com",
Username: "bot",
Password: "beep boop",
Repo: "secret-stash",
PathTemplate: "ok",

Endpoint: "UNEXPECTED",
},
},
Error: func(t *testing.T, errs []error) {
require.Len(t, errs, 1)
assert.ErrorContains(t, errs[0], "unexpected field endpoint")
},
},
{
Name: "artifactory has unexpected field org",
Sources: []ReleaseSourceConfig{
{
Type: BOSHReleaseTarballSourceTypeArtifactory,
ID: "",
ArtifactoryHost: "http://example.com",
Username: "bot",
Password: "beep boop",
Repo: "secret-stash",
PathTemplate: "ok",

Org: "UNEXPECTED",
},
},
Error: func(t *testing.T, errs []error) {
require.Len(t, errs, 1)
assert.ErrorContains(t, errs[0], "unexpected field org")
},
},
{
Name: "artifactory has unexpected field github_token",
Sources: []ReleaseSourceConfig{
{
Type: BOSHReleaseTarballSourceTypeArtifactory,
ID: "",
ArtifactoryHost: "http://example.com",
Username: "bot",
Password: "beep boop",
Repo: "secret-stash",
PathTemplate: "ok",

GithubToken: "UNEXPECTED",
},
},
Error: func(t *testing.T, errs []error) {
require.Len(t, errs, 1)
assert.ErrorContains(t, errs[0], "unexpected field github_token")
},
},
} {
t.Run(tt.Name, func(t *testing.T) {
k := Kilnfile{
ReleaseSources: tt.Sources,
}
errs := Validate(k, KilnfileLock{})
tt.Error(t, errs)
})
}
})
}

0 comments on commit 084efc1

Please sign in to comment.