check for items as well

Signed-off-by: Thiago Perrotta <thiago@perrotta.dev>
pull/31169/head
Thiago Perrotta 3 weeks ago
parent d793d56151
commit 048b12e385

@ -162,7 +162,7 @@ func TemplatesWithSkipSchemaValidation(linter *support.Linter, values map[string
// Refs https://github.com/helm/helm/issues/8596
// 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) {
if !isListResource(yamlStruct, renderedContent) {
linter.RunLinterRule(support.WarningSev, fpath, validateMetadataName(yamlStruct))
}
linter.RunLinterRule(support.WarningSev, fpath, validateNoDeprecations(yamlStruct, kubeVersion))
@ -240,9 +240,30 @@ func validateYamlContent(err error) error {
}
// 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")
// (e.g. ConfigMapList, SecretList). It checks both that the Kind ends with
// "List" and that the resource has an "items" field that is an array.
// This avoids incorrectly treating custom resources that happen to end with
// "List" but aren't actually list containers.
func isListResource(obj *k8sYamlStruct, manifest string) bool {
if !strings.HasSuffix(obj.Kind, "List") {
return false
}
// For the special case of Kind == "List", we can be sure it's a list
if obj.Kind == "List" {
return true
}
// For other kinds ending with "List", verify they have an items field
var listStruct struct {
Items []interface{} `json:"items"`
}
if err := yaml.Unmarshal([]byte(manifest), &listStruct); err != nil {
return false
}
// Check if the items field exists and is an array (even if empty)
return listStruct.Items != nil
}
// validateMetadataName uses the correct validation function for the object

@ -442,21 +442,71 @@ items:
func TestIsListResource(t *testing.T) {
tests := []struct {
kind string
manifest string
expected bool
}{
{"ConfigMap", false},
{"ConfigMapList", true},
{"Secret", false},
{"SecretList", true},
{"List", true},
{"", false},
{"SomethingListExtra", false},
{"ConfigMap", `apiVersion: v1
kind: ConfigMap
metadata:
name: test
data:
key: value`, false},
{"ConfigMapList", `apiVersion: v1
kind: ConfigMapList
items:
- apiVersion: v1
kind: ConfigMap
metadata:
name: test1
- apiVersion: v1
kind: ConfigMap
metadata:
name: test2`, true},
{"Secret", `apiVersion: v1
kind: Secret
metadata:
name: test
data:
key: value`, false},
{"SecretList", `apiVersion: v1
kind: SecretList
items:
- apiVersion: v1
kind: Secret
metadata:
name: test1
- apiVersion: v1
kind: Secret
metadata:
name: test2`, true},
{"List", `apiVersion: v1
kind: List
items:
- apiVersion: v1
kind: ConfigMap
metadata:
name: test`, true},
{"", `apiVersion: v1
kind: ""
metadata:
name: test`, false},
{"SomethingListExtra", `apiVersion: v1
kind: SomethingListExtra
metadata:
name: test`, false},
// Test case for a custom resource ending in "List" but without items field (should be false)
{"AccessList", `apiVersion: example.com/v1
kind: AccessList
metadata:
name: test
spec:
rules: []`, false},
}
for _, test := range tests {
t.Run(test.kind, func(t *testing.T) {
obj := &k8sYamlStruct{Kind: test.kind}
result := isListResource(obj)
result := isListResource(obj, test.manifest)
if result != test.expected {
t.Errorf("isListResource(%q) = %v, expected %v", test.kind, result, test.expected)
}

Loading…
Cancel
Save