diff --git a/pkg/lint/rules/template.go b/pkg/lint/rules/template.go index b36153ec6..ced47ef4e 100644 --- a/pkg/lint/rules/template.go +++ b/pkg/lint/rules/template.go @@ -160,7 +160,11 @@ func TemplatesWithSkipSchemaValidation(linter *support.Linter, values map[string if yamlStruct != nil { // NOTE: set to warnings to allow users to support out-of-date kubernetes // Refs https://github.com/helm/helm/issues/8596 - linter.RunLinterRule(support.WarningSev, fpath, validateMetadataName(yamlStruct)) + // Skip metadata name validation for List resources as they don't require meaningful names + // Refs https://github.com/helm/helm/issues/13192 + if !isListResource(yamlStruct) { + linter.RunLinterRule(support.WarningSev, fpath, validateMetadataName(yamlStruct)) + } linter.RunLinterRule(support.WarningSev, fpath, validateNoDeprecations(yamlStruct, kubeVersion)) linter.RunLinterRule(support.ErrorSev, fpath, validateMatchSelector(yamlStruct, renderedContent)) @@ -235,6 +239,12 @@ func validateYamlContent(err error) error { return nil } +// isListResource returns true if the resource is a Kubernetes List type +// (e.g. ConfigMapList, SecretList). +func isListResource(obj *k8sYamlStruct) bool { + return strings.HasSuffix(obj.Kind, "List") +} + // validateMetadataName uses the correct validation function for the object // Kind, or if not set, defaults to the standard definition of a subdomain in // DNS (RFC 1123), used by most resources. diff --git a/pkg/lint/rules/template_test.go b/pkg/lint/rules/template_test.go index 787bd6e4b..695530155 100644 --- a/pkg/lint/rules/template_test.go +++ b/pkg/lint/rules/template_test.go @@ -438,3 +438,48 @@ items: t.Fatalf("List objects keep annotations should pass. got: %s", err) } } + +func TestIsListResource(t *testing.T) { + tests := []struct { + kind string + expected bool + }{ + {"ConfigMap", false}, + {"ConfigMapList", true}, + {"Secret", false}, + {"SecretList", true}, + {"List", true}, + {"", false}, + {"SomethingListExtra", false}, + } + + for _, test := range tests { + t.Run(test.kind, func(t *testing.T) { + obj := &k8sYamlStruct{Kind: test.kind} + result := isListResource(obj) + if result != test.expected { + t.Errorf("isListResource(%q) = %v, expected %v", test.kind, result, test.expected) + } + }) + } +} + +func TestConfigMapListLinting(t *testing.T) { + linter := support.Linter{ChartDir: "./testdata/configmaplist-chart"} + Templates(&linter, values, namespace, strict) + + // The ConfigMapList should not generate any lint warnings about metadata.name + for _, msg := range linter.Messages { + if strings.Contains(msg.Err.Error(), "object name does not conform to Kubernetes naming requirements") { + t.Errorf("ConfigMapList should not generate metadata name validation errors, but got: %v", msg.Err) + } + } + + // Should have no errors or warnings + if len(linter.Messages) > 0 { + t.Errorf("Expected no lint messages for ConfigMapList, got %d messages:", len(linter.Messages)) + for i, msg := range linter.Messages { + t.Logf("Message %d: %s", i, msg) + } + } +} diff --git a/pkg/lint/rules/testdata/configmaplist-chart/Chart.yaml b/pkg/lint/rules/testdata/configmaplist-chart/Chart.yaml new file mode 100644 index 000000000..830ebea92 --- /dev/null +++ b/pkg/lint/rules/testdata/configmaplist-chart/Chart.yaml @@ -0,0 +1,6 @@ +apiVersion: v2 +name: configmaplist-chart +description: Test chart with ConfigMapList +type: application +version: "0.1.0" +appVersion: "1.0" diff --git a/pkg/lint/rules/testdata/configmaplist-chart/templates/configmap.yaml b/pkg/lint/rules/testdata/configmaplist-chart/templates/configmap.yaml new file mode 100644 index 000000000..605e363fc --- /dev/null +++ b/pkg/lint/rules/testdata/configmaplist-chart/templates/configmap.yaml @@ -0,0 +1,7 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ .Release.Name }}-single-config + namespace: {{ .Release.Namespace }} +data: + setting: "value" \ No newline at end of file diff --git a/pkg/lint/rules/testdata/configmaplist-chart/templates/configmaplist.yaml b/pkg/lint/rules/testdata/configmaplist-chart/templates/configmaplist.yaml new file mode 100644 index 000000000..2227e0a45 --- /dev/null +++ b/pkg/lint/rules/testdata/configmaplist-chart/templates/configmaplist.yaml @@ -0,0 +1,21 @@ +apiVersion: v1 +kind: ConfigMapList +metadata: + # ConfigMapList objects don't require meaningful names + # This should not trigger lint warnings +items: + - apiVersion: v1 + kind: ConfigMap + metadata: + name: {{ .Release.Name }}-database-config + namespace: {{ .Release.Namespace }} + data: + host: {{ .Values.configs.database.host }} + port: "{{ .Values.configs.database.port }}" + - apiVersion: v1 + kind: ConfigMap + metadata: + name: {{ .Release.Name }}-cache-config + namespace: {{ .Release.Namespace }} + data: + redis-url: {{ .Values.configs.cache.redis }} \ No newline at end of file diff --git a/pkg/lint/rules/testdata/configmaplist-chart/values.yaml b/pkg/lint/rules/testdata/configmaplist-chart/values.yaml new file mode 100644 index 000000000..f7e69300e --- /dev/null +++ b/pkg/lint/rules/testdata/configmaplist-chart/values.yaml @@ -0,0 +1,7 @@ +# Default values for configmaplist-chart +configs: + database: + host: localhost + port: 5432 + cache: + redis: redis://localhost:6379 \ No newline at end of file