From 05e5313ab80925cbab62c13fde85bfeed631ef13 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 20 May 2026 03:23:55 +0000 Subject: [PATCH] fix: sanitize defaultInherit values and dedupe applied templates Agent-Logs-Url: https://github.com/helmfile/helmfile/sessions/85a8e815-3701-4b48-a28d-6bb2d50a3b40 Co-authored-by: yxxhero <11087727+yxxhero@users.noreply.github.com> --- pkg/state/state.go | 34 +++++++++++++++++++++++++------ pkg/state/state_exec_tmpl.go | 9 ++++++++ pkg/state/state_exec_tmpl_test.go | 21 +++++++++++++++++++ 3 files changed, 58 insertions(+), 6 deletions(-) diff --git a/pkg/state/state.go b/pkg/state/state.go index 2eafa151..181f36f2 100644 --- a/pkg/state/state.go +++ b/pkg/state/state.go @@ -522,19 +522,41 @@ func (r *Inherits) UnmarshalYAML(unmarshal func(any) error) error { type DefaultInherits []string func (r *DefaultInherits) UnmarshalYAML(unmarshal func(any) error) error { - var single string - if err := unmarshal(&single); err == nil { - *r = []string{single} + var list []string + if err := unmarshal(&list); err == nil { + *r = normalizeDefaultInherits(list) return nil } - var list []string - if err := unmarshal(&list); err != nil { + + var single string + if err := unmarshal(&single); err != nil { return err } - *r = list + *r = normalizeDefaultInherits([]string{single}) return nil } +func normalizeDefaultInherits(in []string) []string { + if len(in) == 0 { + return nil + } + + out := make([]string, 0, len(in)) + for _, name := range in { + name = strings.TrimSpace(name) + if name == "" { + continue + } + out = append(out, name) + } + + if len(out) == 0 { + return nil + } + + return out +} + // ChartPathOrName returns ChartPath if it is non-empty, and returns Chart otherwise. // This is useful to redirect helm commands like `helm template`, `helm dependency update`, `helm diff`, and `helm upgrade --install` to // our modified version of the chart, in case the user configured Helmfile to do modify the chart before being passed to Helm. diff --git a/pkg/state/state_exec_tmpl.go b/pkg/state/state_exec_tmpl.go index b838e964..9e77912b 100644 --- a/pkg/state/state_exec_tmpl.go +++ b/pkg/state/state_exec_tmpl.go @@ -237,13 +237,22 @@ func (st *HelmState) applyDefaultInherit(releaseInherit Inherits) Inherits { existing := make(map[string]bool, len(releaseInherit)) for _, inh := range releaseInherit { + if inh.Template == "" { + continue + } existing[inh.Template] = true } result := make(Inherits, 0, len(st.DefaultInherit)+len(releaseInherit)) for _, name := range st.DefaultInherit { + name = strings.TrimSpace(name) + if name == "" { + continue + } + if !existing[name] { result = append(result, Inherit{Template: name}) + existing[name] = true } } result = append(result, releaseInherit...) diff --git a/pkg/state/state_exec_tmpl_test.go b/pkg/state/state_exec_tmpl_test.go index 7da374bd..d66a1bb7 100644 --- a/pkg/state/state_exec_tmpl_test.go +++ b/pkg/state/state_exec_tmpl_test.go @@ -334,6 +334,12 @@ func TestApplyDefaultInherit(t *testing.T) { releaseInherit: nil, want: Inherits{{Template: "default"}}, }, + { + name: "default inherit deduplicates and skips empty values", + defaultInherit: DefaultInherits{"default", " ", "default", "ops"}, + releaseInherit: Inherits{{Template: "foo"}}, + want: Inherits{{Template: "default"}, {Template: "ops"}, {Template: "foo"}}, + }, } for i := range tests { @@ -437,6 +443,21 @@ func TestDefaultInherits_UnmarshalYAML(t *testing.T) { input: `["a", "b"]`, want: DefaultInherits{"a", "b"}, }, + { + name: "null value", + input: `null`, + want: nil, + }, + { + name: "empty string value", + input: `""`, + want: nil, + }, + { + name: "list trims and drops empty names", + input: `[" a ", "", " ", "b"]`, + want: DefaultInherits{"a", "b"}, + }, } for _, tt := range tests {