From 939fff9cb97d339ba1c5d2021c424fe73d53ca10 Mon Sep 17 00:00:00 2001 From: Benoit Tigeot Date: Sun, 7 Sep 2025 16:45:16 +0200 Subject: [PATCH] Avoid "panic: interface conversion: interface {} is nil" Closes: #31202 Signed-off-by: Benoit Tigeot --- pkg/chart/common/util/jsonschema.go | 17 ++++- pkg/chart/common/util/jsonschema_test.go | 90 ++++++++++++++++++++++++ 2 files changed, 106 insertions(+), 1 deletion(-) diff --git a/pkg/chart/common/util/jsonschema.go b/pkg/chart/common/util/jsonschema.go index acd2ca100..d14435bd8 100644 --- a/pkg/chart/common/util/jsonschema.go +++ b/pkg/chart/common/util/jsonschema.go @@ -93,7 +93,22 @@ func ValidateAgainstSchema(ch chart.Charter, values map[string]interface{}) erro if err != nil { return err } - subchartValues := values[sub.Name()].(map[string]interface{}) + + raw, exists := values[sub.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", + sub.Name(), raw, + )) + continue + } + if err := ValidateAgainstSchema(subchart, subchartValues); err != nil { sb.WriteString(err.Error()) } diff --git a/pkg/chart/common/util/jsonschema_test.go b/pkg/chart/common/util/jsonschema_test.go index b34f9d514..6fec260ab 100644 --- a/pkg/chart/common/util/jsonschema_test.go +++ b/pkg/chart/common/util/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") + } +}