diff --git a/internal/chart/v3/util/dependencies.go b/internal/chart/v3/util/dependencies.go index b31f7eb96..70741cdf7 100644 --- a/internal/chart/v3/util/dependencies.go +++ b/internal/chart/v3/util/dependencies.go @@ -181,9 +181,23 @@ Loop: for _, lr := range c.Metadata.Dependencies { lr.Enabled = true } - cvals, err := util.CoalesceValues(c, v) - if err != nil { - return err + // For the top-level chart (path == ""), v is user-provided values that need + // coalescing with chart defaults before evaluating conditions and tags. + // For recursive calls (path != ""), v is the parent's fully coalesced values + // which already contains sub-chart defaults via coalesceDeps. Calling + // CoalesceValues again with the full parent values would produce spurious + // type-mismatch warnings when parent-level keys conflict with sub-chart + // defaults in type (e.g., parent has tolerations:{} and sub-chart default + // is tolerations:[]). + var cvals common.Values + if path == "" { + var err error + cvals, err = util.CoalesceValues(c, v) + if err != nil { + return err + } + } else { + cvals = v } // flag dependencies as enabled/disabled processDependencyTags(c.Metadata.Dependencies, cvals) diff --git a/internal/chart/v3/util/dependencies_test.go b/internal/chart/v3/util/dependencies_test.go index 0a0937e4a..49d44f1eb 100644 --- a/internal/chart/v3/util/dependencies_test.go +++ b/internal/chart/v3/util/dependencies_test.go @@ -15,10 +15,13 @@ limitations under the License. package util import ( + "bytes" + "log" "os" "path/filepath" "sort" "strconv" + "strings" "testing" chart "helm.sh/helm/v4/internal/chart/v3" @@ -567,3 +570,60 @@ func TestChartWithDependencyAliasedTwiceAndDoublyReferencedSubDependency(t *test } validateDependencyTree(t, c) } + +// TestProcessDependencyEnabledNoSpuriousWarnings verifies that processing a +// sub-chart that itself has a sub-chart does not produce spurious type-mismatch +// warnings when a parent-level key has a different type than the sub-chart's +// default for the same key name. The parent's top-level "tolerations:{}" should +// not be compared against the sub-chart's default "tolerations:[]". +// Regression test for https://github.com/helm/helm/issues/11251 +func TestProcessDependencyEnabledNoSpuriousWarnings(t *testing.T) { + subSub := &chart.Chart{ + Metadata: &chart.Metadata{Name: "subsubchart", Version: "1.0.0"}, + } + + sub := &chart.Chart{ + Metadata: &chart.Metadata{ + Name: "subchart", + Version: "1.0.0", + Dependencies: []*chart.Dependency{ + {Name: "subsubchart", Version: "1.0.0"}, + }, + }, + Values: map[string]any{ + // subchart defines tolerations as an array + "tolerations": []any{"entry1"}, + }, + } + sub.AddDependency(subSub) + + parent := &chart.Chart{ + Metadata: &chart.Metadata{ + Name: "parent", + Version: "1.0.0", + Dependencies: []*chart.Dependency{ + {Name: "subchart", Version: "1.0.0"}, + }, + }, + Values: map[string]any{ + // parent defines tolerations as a map at the top level + "tolerations": map[string]any{"key": "value"}, + }, + } + parent.AddDependency(sub) + + // Capture standard log output to detect spurious warnings from CoalesceValues. + var buf bytes.Buffer + oldOutput := log.Writer() + log.SetOutput(&buf) + defer log.SetOutput(oldOutput) + + if err := processDependencyEnabled(parent, parent.Values, ""); err != nil { + t.Fatalf("unexpected error: %v", err) + } + + output := buf.String() + if strings.Contains(output, "Not a table") { + t.Errorf("spurious type-mismatch warning from parent-level key leaking into sub-chart scope: %s", output) + } +} diff --git a/pkg/chart/v2/util/dependencies.go b/pkg/chart/v2/util/dependencies.go index f28a4f4b1..c1f47c230 100644 --- a/pkg/chart/v2/util/dependencies.go +++ b/pkg/chart/v2/util/dependencies.go @@ -181,9 +181,23 @@ Loop: for _, lr := range c.Metadata.Dependencies { lr.Enabled = true } - cvals, err := util.CoalesceValues(c, v) - if err != nil { - return err + // For the top-level chart (path == ""), v is user-provided values that need + // coalescing with chart defaults before evaluating conditions and tags. + // For recursive calls (path != ""), v is the parent's fully coalesced values + // which already contains sub-chart defaults via coalesceDeps. Calling + // CoalesceValues again with the full parent values would produce spurious + // type-mismatch warnings when parent-level keys conflict with sub-chart + // defaults in type (e.g., parent has tolerations:{} and sub-chart default + // is tolerations:[]). + var cvals common.Values + if path == "" { + var err error + cvals, err = util.CoalesceValues(c, v) + if err != nil { + return err + } + } else { + cvals = v } // flag dependencies as enabled/disabled processDependencyTags(c.Metadata.Dependencies, cvals) diff --git a/pkg/chart/v2/util/dependencies_test.go b/pkg/chart/v2/util/dependencies_test.go index 90a8806ec..c97babd93 100644 --- a/pkg/chart/v2/util/dependencies_test.go +++ b/pkg/chart/v2/util/dependencies_test.go @@ -15,10 +15,13 @@ limitations under the License. package util import ( + "bytes" + "log" "os" "path/filepath" "sort" "strconv" + "strings" "testing" "helm.sh/helm/v4/pkg/chart/common" @@ -567,3 +570,60 @@ func TestChartWithDependencyAliasedTwiceAndDoublyReferencedSubDependency(t *test } validateDependencyTree(t, c) } + +// TestProcessDependencyEnabledNoSpuriousWarnings verifies that processing a +// sub-chart that itself has a sub-chart does not produce spurious type-mismatch +// warnings when a parent-level key has a different type than the sub-chart's +// default for the same key name. The parent's top-level "tolerations:{}" should +// not be compared against the sub-chart's default "tolerations:[]". +// Regression test for https://github.com/helm/helm/issues/11251 +func TestProcessDependencyEnabledNoSpuriousWarnings(t *testing.T) { + subSub := &chart.Chart{ + Metadata: &chart.Metadata{Name: "subsubchart", Version: "1.0.0"}, + } + + sub := &chart.Chart{ + Metadata: &chart.Metadata{ + Name: "subchart", + Version: "1.0.0", + Dependencies: []*chart.Dependency{ + {Name: "subsubchart", Version: "1.0.0"}, + }, + }, + Values: map[string]any{ + // subchart defines tolerations as an array + "tolerations": []any{"entry1"}, + }, + } + sub.AddDependency(subSub) + + parent := &chart.Chart{ + Metadata: &chart.Metadata{ + Name: "parent", + Version: "1.0.0", + Dependencies: []*chart.Dependency{ + {Name: "subchart", Version: "1.0.0"}, + }, + }, + Values: map[string]any{ + // parent defines tolerations as a map at the top level + "tolerations": map[string]any{"key": "value"}, + }, + } + parent.AddDependency(sub) + + // Capture standard log output to detect spurious warnings from CoalesceValues. + var buf bytes.Buffer + oldOutput := log.Writer() + log.SetOutput(&buf) + defer log.SetOutput(oldOutput) + + if err := processDependencyEnabled(parent, parent.Values, ""); err != nil { + t.Fatalf("unexpected error: %v", err) + } + + output := buf.String() + if strings.Contains(output, "Not a table") { + t.Errorf("spurious type-mismatch warning from parent-level key leaking into sub-chart scope: %s", output) + } +}