diff --git a/pkg/chartutil/jsonschema.go b/pkg/chartutil/jsonschema.go index d712316c5..b950ae7e0 100644 --- a/pkg/chartutil/jsonschema.go +++ b/pkg/chartutil/jsonschema.go @@ -82,7 +82,20 @@ func ValidateAgainstSchema(chrt *chart.Chart, values map[string]interface{}) err } for _, subchart := range chrt.Dependencies() { - subchartValues := values[subchart.Name()].(map[string]interface{}) + raw, exists := values[subchart.Name()] + if !exists || raw == nil { + // No values provided for this subchart; nothing to validate + continue + } + + subchartValues, ok := raw.(map[string]any) + if !ok { + sb.WriteString(fmt.Sprintf( + "%s:\ninvalid type for values: expected object (map), got %T\n", + subchart.Name(), raw, + )) + continue + } if err := ValidateAgainstSchema(subchart, subchartValues); err != nil { sb.WriteString(err.Error()) } diff --git a/pkg/chartutil/jsonschema_test.go b/pkg/chartutil/jsonschema_test.go index 8084b8602..9bc1d7b70 100644 --- a/pkg/chartutil/jsonschema_test.go +++ b/pkg/chartutil/jsonschema_test.go @@ -286,3 +286,93 @@ func TestHTTPURLLoader_Load(t *testing.T) { } }) } + +// Non-regression tests for https://github.com/helm/helm/issues/31202 +// Ensure ValidateAgainstSchema does not panic when: +// - subchart key is missing +// - subchart value is nil +// - subchart value has an invalid type + +func TestValidateAgainstSchema_MissingSubchartValues_NoPanic(t *testing.T) { + subchartJSON := []byte(subchartSchema) + subchart := &chart.Chart{ + Metadata: &chart.Metadata{Name: "subchart"}, + Schema: subchartJSON, + } + chrt := &chart.Chart{ + Metadata: &chart.Metadata{Name: "chrt"}, + } + chrt.AddDependency(subchart) + + // No "subchart" key present in values + vals := map[string]any{ + "name": "John", + } + + defer func() { + if r := recover(); r != nil { + t.Fatalf("ValidateAgainstSchema panicked (missing subchart values): %v", r) + } + }() + + if err := ValidateAgainstSchema(chrt, vals); err != nil { + t.Fatalf("expected no error when subchart values are missing, got: %v", err) + } +} + +func TestValidateAgainstSchema_SubchartNil_NoPanic(t *testing.T) { + subchartJSON := []byte(subchartSchema) + subchart := &chart.Chart{ + Metadata: &chart.Metadata{Name: "subchart"}, + Schema: subchartJSON, + } + chrt := &chart.Chart{ + Metadata: &chart.Metadata{Name: "chrt"}, + } + chrt.AddDependency(subchart) + + // "subchart" key present but nil + vals := map[string]any{ + "name": "John", + "subchart": nil, + } + + defer func() { + if r := recover(); r != nil { + t.Fatalf("ValidateAgainstSchema panicked (nil subchart values): %v", r) + } + }() + + if err := ValidateAgainstSchema(chrt, vals); err != nil { + t.Fatalf("expected no error when subchart values are nil, got: %v", err) + } +} + +func TestValidateAgainstSchema_InvalidSubchartValuesType_NoPanic(t *testing.T) { + subchartJSON := []byte(subchartSchema) + subchart := &chart.Chart{ + Metadata: &chart.Metadata{Name: "subchart"}, + Schema: subchartJSON, + } + chrt := &chart.Chart{ + Metadata: &chart.Metadata{Name: "chrt"}, + } + chrt.AddDependency(subchart) + + // "subchart" is the wrong type (string instead of map) + vals := map[string]any{ + "name": "John", + "subchart": "oops", + } + + defer func() { + if r := recover(); r != nil { + t.Fatalf("ValidateAgainstSchema panicked (invalid subchart values type): %v", r) + } + }() + + // We expect a non-nil error (invalid type), but crucially no panic. + if err := ValidateAgainstSchema(chrt, vals); err == nil { + t.Fatalf("expected an error when subchart values have invalid type, got nil") + } +}