diff --git a/pkg/validation/policy/validate.go b/pkg/validation/policy/validate.go index 15d1d9d5b8..c74327092c 100644 --- a/pkg/validation/policy/validate.go +++ b/pkg/validation/policy/validate.go @@ -639,6 +639,17 @@ func validateMatchKindHelper(rule kyvernov1.Rule) error { return fmt.Errorf("at least one element must be specified in a kind block, the kind attribute is mandatory when working with the resources element") } +// isMapStringString goes through a map to verify values are string +func isMapStringString(m map[string]interface{}) bool { + // range over labels + for _, val := range m { + if val == nil || reflect.TypeOf(val).String() != "string" { + return false + } + } + return true +} + // isLabelAndAnnotationsString :- Validate if labels and annotations contains only string values func isLabelAndAnnotationsString(rule kyvernov1.Rule) bool { checkLabelAnnotation := func(metaKey map[string]interface{}) bool { @@ -646,21 +657,15 @@ func isLabelAndAnnotationsString(rule kyvernov1.Rule) bool { if mk == "labels" { labelKey, ok := metaKey[mk].(map[string]interface{}) if ok { - // range over labels - for _, val := range labelKey { - if reflect.TypeOf(val).String() != "string" { - return false - } + if !isMapStringString(labelKey) { + return false } } } else if mk == "annotations" { annotationKey, ok := metaKey[mk].(map[string]interface{}) if ok { - // range over annotations - for _, val := range annotationKey { - if reflect.TypeOf(val).String() != "string" { - return false - } + if !isMapStringString(annotationKey) { + return false } } } diff --git a/pkg/validation/policy/validate_test.go b/pkg/validation/policy/validate_test.go index 65991a5664..aa288c81d8 100644 --- a/pkg/validation/policy/validate_test.go +++ b/pkg/validation/policy/validate_test.go @@ -3295,3 +3295,60 @@ func Test_ImmutableGenerateFields(t *testing.T) { assert.Assert(t, (err != nil) == test.expectedErr, test.name, err) } } + +func Test_isMapStringString(t *testing.T) { + type args struct { + m map[string]interface{} + } + tests := []struct { + name string + args args + want bool + }{{ + name: "nil", + args: args{ + m: nil, + }, + want: true, + }, { + name: "empty", + args: args{ + m: map[string]interface{}{}, + }, + want: true, + }, { + name: "string values", + args: args{ + m: map[string]interface{}{ + "a": "b", + "c": "d", + }, + }, + want: true, + }, { + name: "int value", + args: args{ + m: map[string]interface{}{ + "a": "b", + "c": 123, + }, + }, + want: false, + }, { + name: "nil value", + args: args{ + m: map[string]interface{}{ + "a": "b", + "c": nil, + }, + }, + want: false, + }} + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := isMapStringString(tt.args.m); got != tt.want { + t.Errorf("checkLabelAnnotation() = %v, want %v", got, tt.want) + } + }) + } +}