Skip to content

Commit

Permalink
feat(validation): add error messages for Helm release name validation
Browse files Browse the repository at this point in the history
Added error messages for detecting empty or invalid Helm release names that do not conform to DNS-1035 label standards.

feat(validation): implement Helm release name validation

Added a new function 'ValidateReleaseName' to ensure that Helm release names conform to DNS-1035 label standards. Integrated this validation into the 'ZarfChart' struct's 'Validate' method to check release names and fallback mechanisms.

test(validation): add unit tests for Helm release name validation

Added tests to cover various scenarios, including valid release names, invalid names with periods, fallback to chart names, and missing names.

Signed-off-by: jamestexas <[email protected]>
  • Loading branch information
jamestexas committed Jul 30, 2024
1 parent 05fdaef commit a008841
Show file tree
Hide file tree
Showing 3 changed files with 100 additions and 2 deletions.
2 changes: 2 additions & 0 deletions src/config/lang/english.go
Original file line number Diff line number Diff line change
Expand Up @@ -651,6 +651,8 @@ const (
PkgValidateErrManifestNameLength = "manifest %q exceed the maximum length of %d characters"
PkgValidateErrManifestNameNotUnique = "manifest name %q is not unique"
PkgValidateErrPkgConstantPattern = "provided value for constant %q does not match pattern %q"
PkgValidateErrChartReleaseNameEmpty = "release name empty, unable to fallback to chart name"
PkgValidateErrChartReleaseNameInvalid = "invalid release name '%s': a DNS-1035 label must consist of lower case alphanumeric characters or '-', start with an alphabetic character, and end with an alphanumeric character"
PkgValidateErrVariable = "invalid package variable: %w"
PkgValidateErrYOLONoArch = "cluster architecture not allowed in YOLO"
PkgValidateErrYOLONoDistro = "cluster distros not allowed in YOLO"
Expand Down
30 changes: 29 additions & 1 deletion src/types/validate.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ package types
import (
"errors"
"fmt"
"log"
"path/filepath"
"regexp"

Expand All @@ -25,7 +26,8 @@ var (
IsLowercaseNumberHyphenNoStartHyphen = regexp.MustCompile(`^[a-z0-9][a-z0-9\-]*$`).MatchString
// Define allowed OS, an empty string means it is allowed on all operating systems
// same as enums on ZarfComponentOnlyTarget
supportedOS = []string{"linux", "darwin", "windows", ""}
supportedOS = []string{"linux", "darwin", "windows", ""}
dns1035LabelRegex = regexp.MustCompile(`^[a-z]([-a-z0-9]*[a-z0-9])?$`)
)

// SupportedOS returns the supported operating systems.
Expand Down Expand Up @@ -252,6 +254,19 @@ func (action ZarfComponentAction) Validate() error {
return err
}

// ValidateReleaseName validates against DNS 1035 kubernetes label spec
// https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#rfc-1035-label-names
// https://github.com/zarf-dev/zarf/issues/2776
func ValidateReleaseName(releaseName string) error {
if releaseName == "" {
return fmt.Errorf(lang.PkgValidateErrChartReleaseNameEmpty)
}
if !dns1035LabelRegex.MatchString(releaseName) {
return fmt.Errorf(lang.PkgValidateErrChartReleaseNameInvalid, releaseName)
}
return nil
}

// Validate runs all validation checks on a chart.
func (chart ZarfChart) Validate() error {
var err error
Expand All @@ -277,6 +292,19 @@ func (chart ZarfChart) Validate() error {
err = errors.Join(err, fmt.Errorf(lang.PkgValidateErrChartVersion, chart.Name))
}

// Validate releaseName if provided, else fallback to chart.Name
// This also ensures that the release name is a valid Helm release name
// Lastly this same fallback mechanism happens in src/internal/packager/helm/chart.go:InstallOrUpgradeChart
releaseName := chart.ReleaseName
if releaseName == "" {
releaseName = chart.Name
}
// Use Helm's ValidateReleaseName function for release name validation
if nameErr := ValidateReleaseName(releaseName); nameErr != nil {
log.Printf("Error validating ZarfChart ReleaseName: %s", releaseName)
err = errors.Join(err, nameErr)
}

return err
}

Expand Down
70 changes: 69 additions & 1 deletion src/types/validate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,54 @@ func TestValidateManifest(t *testing.T) {
}
}

func TestValidateReleaseName(t *testing.T) {
tests := []struct {
name string
releaseName string
expectedErrs []string
}{
{
name: "valid releaseName with hyphens",
releaseName: "valid-release-hyphenated",
expectedErrs: nil,
},
{
name: "valid releaseName with numbers",
releaseName: "valid-0470",
expectedErrs: nil,
},
{
name: "invalid releaseName with periods",
releaseName: "namedwithperiods-a.b.c",
expectedErrs: []string{
fmt.Sprintf(lang.PkgValidateErrChartReleaseNameInvalid, "namedwithperiods-a.b.c"),
},
},
{
name: "empty releaseName",
releaseName: "",
expectedErrs: []string{
fmt.Sprintf(lang.PkgValidateErrChartReleaseNameEmpty),
},
},
}

for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
err := ValidateReleaseName(tt.releaseName)
if tt.expectedErrs == nil {
require.NoError(t, err)
} else {
require.Error(t, err)
errs := strings.Split(err.Error(), "\n")
require.ElementsMatch(t, tt.expectedErrs, errs)
}
})
}
}

func TestValidateChart(t *testing.T) {
t.Parallel()
longName := strings.Repeat("a", ZarfMaxChartNameLength+1)
Expand All @@ -196,7 +244,7 @@ func TestValidateChart(t *testing.T) {
}{
{
name: "valid",
chart: ZarfChart{Name: "chart1", Namespace: "whatever", URL: "http://whatever", Version: "v1.0.0"},
chart: ZarfChart{Name: "chart1", Namespace: "whatever", URL: "http://whatever", Version: "v1.0.0", ReleaseName: "this-is-valid"},
expectedErrs: nil,
},
{
Expand All @@ -222,6 +270,26 @@ func TestValidateChart(t *testing.T) {
fmt.Sprintf(lang.PkgValidateErrChartURLOrPath, "invalid"),
},
},
// Various release name tests
{
name: "invalid releaseName",
chart: ZarfChart{ReleaseName: "namedwithperiods-0.47.0", Name: "releaseName", Namespace: "whatever", URL: "http://whatever", Version: "v1.0.0"},
expectedErrs: []string{
fmt.Sprintf(lang.PkgValidateErrChartReleaseNameInvalid, "namedwithperiods-0.47.0"),
},
},
{
name: "missing releaseName fallsback to name",
chart: ZarfChart{Name: "chart3", Namespace: "namespace", URL: "http://whatever", Version: "v1.0.0"},
expectedErrs: nil,
},
{
name: "missing name and releaseName",
chart: ZarfChart{Namespace: "namespace", URL: "http://whatever", Version: "v1.0.0"},
expectedErrs: []string{
fmt.Sprintf(lang.PkgValidateErrChartReleaseNameEmpty),
},
},
}
for _, tt := range tests {
tt := tt
Expand Down

0 comments on commit a008841

Please sign in to comment.