From 72b4735adf4e032426c27b9b18dfa7407b8f70be Mon Sep 17 00:00:00 2001 From: Suleiman Dibirov Date: Wed, 30 Oct 2024 18:14:23 +0200 Subject: [PATCH] fix(lint): Extend --skip-schema-validation for lint command Signed-off-by: Suleiman Dibirov --- pkg/lint/lint.go | 1 + pkg/lint/rules/values.go | 31 ++++++++++++++++++++++++++++--- pkg/lint/rules/values_test.go | 24 +++++++++++++++++++----- 3 files changed, 48 insertions(+), 8 deletions(-) diff --git a/pkg/lint/lint.go b/pkg/lint/lint.go index 70a49ee90..fa7271f7d 100644 --- a/pkg/lint/lint.go +++ b/pkg/lint/lint.go @@ -57,6 +57,7 @@ func RunAll(baseDir string, values map[string]interface{}, namespace string, opt } rules.Chartfile(&result) + rules.ValuesWithOverridesWithSkipSchemaValidation(&result, values, lo.SkipSchemaValidation) rules.ValuesWithOverrides(&result, values) rules.TemplatesWithSkipSchemaValidation(&result, values, namespace, lo.KubeVersion, lo.SkipSchemaValidation) rules.Dependencies(&result) diff --git a/pkg/lint/rules/values.go b/pkg/lint/rules/values.go index 82278522d..268ac798a 100644 --- a/pkg/lint/rules/values.go +++ b/pkg/lint/rules/values.go @@ -41,7 +41,25 @@ func ValuesWithOverrides(linter *support.Linter, valueOverrides map[string]inter return } - linter.RunLinterRule(support.ErrorSev, file, validateValuesFile(vf, valueOverrides)) + linter.RunLinterRule(support.ErrorSev, file, validateValuesFile(vf, valueOverrides, false)) +} + +// ValuesWithOverridesWithSkipSchemaValidation tests the values.yaml file. +// +// If a schema is present in the chart, values are tested against that. Otherwise, +// they are only tested for well-formedness. +// +// If additional values are supplied, they are coalesced into the values in values.yaml. +func ValuesWithOverridesWithSkipSchemaValidation(linter *support.Linter, values map[string]interface{}, skipSchemaValidation bool) { + file := "values.yaml" + vf := filepath.Join(linter.ChartDir, file) + fileExists := linter.RunLinterRule(support.InfoSev, file, validateValuesFileExistence(vf)) + + if !fileExists { + return + } + + linter.RunLinterRule(support.ErrorSev, file, validateValuesFile(vf, values, skipSchemaValidation)) } func validateValuesFileExistence(valuesPath string) error { @@ -52,7 +70,7 @@ func validateValuesFileExistence(valuesPath string) error { return nil } -func validateValuesFile(valuesPath string, overrides map[string]interface{}) error { +func validateValuesFile(valuesPath string, overrides map[string]interface{}, skipSchemaValidation bool) error { values, err := chartutil.ReadValuesFile(valuesPath) if err != nil { return errors.Wrap(err, "unable to parse YAML") @@ -75,5 +93,12 @@ func validateValuesFile(valuesPath string, overrides map[string]interface{}) err if err != nil { return err } - return chartutil.ValidateAgainstSingleSchema(coalescedValues, schema) + + if !skipSchemaValidation { + res := chartutil.ValidateAgainstSingleSchema(coalescedValues, schema) + + return res + } + + return nil } diff --git a/pkg/lint/rules/values_test.go b/pkg/lint/rules/values_test.go index 8a2556a60..41bd3c34b 100644 --- a/pkg/lint/rules/values_test.go +++ b/pkg/lint/rules/values_test.go @@ -67,7 +67,7 @@ func TestValidateValuesFileWellFormed(t *testing.T) { ` tmpdir := ensure.TempFile(t, "values.yaml", []byte(badYaml)) valfile := filepath.Join(tmpdir, "values.yaml") - if err := validateValuesFile(valfile, map[string]interface{}{}); err == nil { + if err := validateValuesFile(valfile, map[string]interface{}{}, false); err == nil { t.Fatal("expected values file to fail parsing") } } @@ -78,7 +78,7 @@ func TestValidateValuesFileSchema(t *testing.T) { createTestingSchema(t, tmpdir) valfile := filepath.Join(tmpdir, "values.yaml") - if err := validateValuesFile(valfile, map[string]interface{}{}); err != nil { + if err := validateValuesFile(valfile, map[string]interface{}{}, false); err != nil { t.Fatalf("Failed validation with %s", err) } } @@ -91,7 +91,7 @@ func TestValidateValuesFileSchemaFailure(t *testing.T) { valfile := filepath.Join(tmpdir, "values.yaml") - err := validateValuesFile(valfile, map[string]interface{}{}) + err := validateValuesFile(valfile, map[string]interface{}{}, false) if err == nil { t.Fatal("expected values file to fail parsing") } @@ -99,6 +99,20 @@ func TestValidateValuesFileSchemaFailure(t *testing.T) { assert.Contains(t, err.Error(), "Expected: string, given: integer", "integer should be caught by schema") } +func TestValidateValuesFileSchemaFailureButWithSkipSchemaValidation(t *testing.T) { + // 1234 is an int, not a string. This should fail. + yaml := "username: 1234\npassword: swordfish" + tmpdir := ensure.TempFile(t, "values.yaml", []byte(yaml)) + createTestingSchema(t, tmpdir) + + valfile := filepath.Join(tmpdir, "values.yaml") + + err := validateValuesFile(valfile, map[string]interface{}{}, true) + if err != nil { + t.Fatal("expected values file to pass parsing because of skipSchemaValidation") + } +} + func TestValidateValuesFileSchemaOverrides(t *testing.T) { yaml := "username: admin" overrides := map[string]interface{}{ @@ -108,7 +122,7 @@ func TestValidateValuesFileSchemaOverrides(t *testing.T) { createTestingSchema(t, tmpdir) valfile := filepath.Join(tmpdir, "values.yaml") - if err := validateValuesFile(valfile, overrides); err != nil { + if err := validateValuesFile(valfile, overrides, false); err != nil { t.Fatalf("Failed validation with %s", err) } } @@ -145,7 +159,7 @@ func TestValidateValuesFile(t *testing.T) { valfile := filepath.Join(tmpdir, "values.yaml") - err := validateValuesFile(valfile, tt.overrides) + err := validateValuesFile(valfile, tt.overrides, false) switch { case err != nil && tt.errorMessage == "":