mirror of
https://github.com/helm/helm.git
synced 2026-05-28 04:35:48 -04:00
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>
This commit is contained in:
parent
e2cbc5c0c9
commit
072e2a689a
6 changed files with 58 additions and 20 deletions
|
|
@ -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…
Reference in a new issue