Extend --skip-schema-validation for lint command

When --skip-schema-validation is enabled, the lint command will now skip
JSON schema validation for values.yaml files, allowing charts with schema
validation errors to pass linting when the flag is used.

This addresses the gap where --skip-schema-validation only applied to
templates but not to values files, providing complete schema validation
bypass when needed.

Fixes: #13413

Signed-off-by: Suleiman Dibirov <idsulik@gmail.com>
Signed-off-by: Benoit Tigeot <benoit.tigeot@lifen.fr>
pull/31275/head
Benoit Tigeot 1 week ago
parent e2cbc5c0c9
commit 072e2a689a
No known key found for this signature in database
GPG Key ID: 8E6D4FC8AEBDA62C

@ -57,7 +57,7 @@ func RunAll(baseDir string, values map[string]interface{}, namespace string, opt
}
rules.Chartfile(&result)
rules.ValuesWithOverrides(&result, values)
rules.ValuesWithOverrides(&result, values, lo.SkipSchemaValidation)
rules.TemplatesWithSkipSchemaValidation(&result, values, namespace, lo.KubeVersion, lo.SkipSchemaValidation)
rules.Dependencies(&result)
rules.Crds(&result)

@ -32,7 +32,7 @@ import (
// they are only tested for well-formedness.
//
// If additional values are supplied, they are coalesced into the values in values.yaml.
func ValuesWithOverrides(linter *support.Linter, valueOverrides map[string]interface{}) {
func ValuesWithOverrides(linter *support.Linter, valueOverrides map[string]interface{}, skipSchemaValidation bool) {
file := "values.yaml"
vf := filepath.Join(linter.ChartDir, file)
fileExists := linter.RunLinterRule(support.InfoSev, file, validateValuesFileExistence(vf))
@ -41,7 +41,7 @@ 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, skipSchemaValidation))
}
func validateValuesFileExistence(valuesPath string) error {
@ -52,7 +52,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 := common.ReadValuesFile(valuesPath)
if err != nil {
return fmt.Errorf("unable to parse YAML: %w", err)
@ -75,5 +75,10 @@ func validateValuesFile(valuesPath string, overrides map[string]interface{}) err
if err != nil {
return err
}
return util.ValidateAgainstSingleSchema(coalescedValues, schema)
if !skipSchemaValidation {
return util.ValidateAgainstSingleSchema(coalescedValues, schema)
}
return nil
}

@ -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(), "- at '/username': got number, want string")
}
func TestValidateValuesFileSchemaFailureButWithSkipSchemaValidation(t *testing.T) {
// 1234 is an int, not a string. This should fail normally but pass with skipSchemaValidation.
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 == "":

@ -57,7 +57,7 @@ func RunAll(baseDir string, values map[string]interface{}, namespace string, opt
}
rules.Chartfile(&result)
rules.ValuesWithOverrides(&result, values)
rules.ValuesWithOverrides(&result, values, lo.SkipSchemaValidation)
rules.TemplatesWithSkipSchemaValidation(&result, values, namespace, lo.KubeVersion, lo.SkipSchemaValidation)
rules.Dependencies(&result)
rules.Crds(&result)

@ -32,7 +32,7 @@ import (
// they are only tested for well-formedness.
//
// If additional values are supplied, they are coalesced into the values in values.yaml.
func ValuesWithOverrides(linter *support.Linter, valueOverrides map[string]interface{}) {
func ValuesWithOverrides(linter *support.Linter, valueOverrides map[string]interface{}, skipSchemaValidation bool) {
file := "values.yaml"
vf := filepath.Join(linter.ChartDir, file)
fileExists := linter.RunLinterRule(support.InfoSev, file, validateValuesFileExistence(vf))
@ -41,7 +41,7 @@ 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, skipSchemaValidation))
}
func validateValuesFileExistence(valuesPath string) error {
@ -52,7 +52,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 := common.ReadValuesFile(valuesPath)
if err != nil {
return fmt.Errorf("unable to parse YAML: %w", err)
@ -75,5 +75,10 @@ func validateValuesFile(valuesPath string, overrides map[string]interface{}) err
if err != nil {
return err
}
return util.ValidateAgainstSingleSchema(coalescedValues, schema)
if !skipSchemaValidation {
return util.ValidateAgainstSingleSchema(coalescedValues, schema)
}
return nil
}

@ -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(), "- at '/username': got number, want string")
}
func TestValidateValuesFileSchemaFailureButWithSkipSchemaValidation(t *testing.T) {
// 1234 is an int, not a string. This should fail normally but pass with skipSchemaValidation.
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 == "":

Loading…
Cancel
Save