1
0
Fork 0
mirror of https://github.com/kyverno/kyverno.git synced 2024-12-14 11:57:48 +00:00

feat: use pointer in rule (exclude field) (#11050)

Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com>
This commit is contained in:
Charles-Edouard Brétéché 2024-09-10 13:14:49 +02:00 committed by GitHub
parent 9934c0e61a
commit b5e1c97913
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
20 changed files with 219 additions and 178 deletions

View file

@ -46,6 +46,9 @@ func (m *MatchResources) GetKinds() []string {
// Validate implements programmatic validation
func (m *MatchResources) Validate(path *field.Path, namespaced bool, clusterResources sets.Set[string]) (errs field.ErrorList) {
if m == nil {
return errs
}
if len(m.Any) > 0 && len(m.All) > 0 {
errs = append(errs, field.Invalid(path, m, "Can't specify any and all together"))
}

View file

@ -65,7 +65,7 @@ type Rule struct {
// criteria can include resource information (e.g. kind, name, namespace, labels)
// and admission review request information like the name or role.
// +optional
ExcludeResources MatchResources `json:"exclude,omitempty"`
ExcludeResources *MatchResources `json:"exclude,omitempty"`
// ImageExtractors defines a mapping from kinds to ImageExtractorConfigs.
// This config is only valid for verifyImages rules.
@ -252,6 +252,9 @@ func (r *Rule) ValidateRuleType(path *field.Path) (errs field.ErrorList) {
// ValidateMatchExcludeConflict checks if the resultant of match and exclude block is not an empty set
func (r *Rule) ValidateMatchExcludeConflict(path *field.Path) (errs field.ErrorList) {
if r.ExcludeResources == nil {
return errs
}
if len(r.ExcludeResources.All) > 0 || len(r.MatchResources.All) > 0 {
return errs
}
@ -266,7 +269,7 @@ func (r *Rule) ValidateMatchExcludeConflict(path *field.Path) (errs field.ErrorL
}
return errs
}
if datautils.DeepEqual(r.ExcludeResources, MatchResources{}) {
if datautils.DeepEqual(*r.ExcludeResources, MatchResources{}) {
return errs
}
excludeRoles := sets.New(r.ExcludeResources.Roles...)

View file

@ -1396,7 +1396,11 @@ func (in *Rule) DeepCopyInto(out *Rule) {
}
}
in.MatchResources.DeepCopyInto(&out.MatchResources)
in.ExcludeResources.DeepCopyInto(&out.ExcludeResources)
if in.ExcludeResources != nil {
in, out := &in.ExcludeResources, &out.ExcludeResources
*out = new(MatchResources)
(*in).DeepCopyInto(*out)
}
if in.ImageExtractors != nil {
in, out := &in.ImageExtractors, &out.ImageExtractors
*out = make(ImageExtractorConfigs, len(*in))

View file

@ -41,6 +41,9 @@ func (m *MatchResources) GetKinds() []string {
// ValidateNoUserInfo verifies that no user info is used
func (m *MatchResources) ValidateNoUserInfo(path *field.Path) (errs field.ErrorList) {
if m == nil {
return errs
}
anyPath := path.Child("any")
for i, filter := range m.Any {
errs = append(errs, filter.UserInfo.ValidateNoUserInfo(anyPath.Index(i))...)
@ -54,6 +57,9 @@ func (m *MatchResources) ValidateNoUserInfo(path *field.Path) (errs field.ErrorL
// ValidateResourceWithNoUserInfo implements programmatic validation and verifies that no user info is used
func (m *MatchResources) ValidateResourceWithNoUserInfo(path *field.Path, namespaced bool, clusterResources sets.Set[string]) (errs field.ErrorList) {
if m == nil {
return errs
}
if len(m.Any) > 0 && len(m.All) > 0 {
errs = append(errs, field.Invalid(path, m, "Can't specify any and all together"))
}
@ -72,6 +78,9 @@ func (m *MatchResources) ValidateResourceWithNoUserInfo(path *field.Path, namesp
// Validate implements programmatic validation
func (m *MatchResources) Validate(path *field.Path, namespaced bool, clusterResources sets.Set[string]) (errs field.ErrorList) {
if m == nil {
return errs
}
if len(m.Any) > 0 && len(m.All) > 0 {
errs = append(errs, field.Invalid(path, m, "Can't specify any and all together"))
}

View file

@ -32,7 +32,7 @@ type Rule struct {
// criteria can include resource information (e.g. kind, name, namespace, labels)
// and admission review request information like the name or role.
// +optional
ExcludeResources MatchResources `json:"exclude,omitempty"`
ExcludeResources *MatchResources `json:"exclude,omitempty"`
// ImageExtractors defines a mapping from kinds to ImageExtractorConfigs.
// This config is only valid for verifyImages rules.
@ -160,6 +160,9 @@ func (r *Rule) ValidateRuleType(path *field.Path) (errs field.ErrorList) {
// ValidateMatchExcludeConflict checks if the resultant of match and exclude block is not an empty set
func (r *Rule) ValidateMatchExcludeConflict(path *field.Path) (errs field.ErrorList) {
if r.ExcludeResources == nil {
return errs
}
if len(r.ExcludeResources.All) > 0 || len(r.MatchResources.All) > 0 {
return errs
}

View file

@ -712,7 +712,11 @@ func (in *Rule) DeepCopyInto(out *Rule) {
}
}
in.MatchResources.DeepCopyInto(&out.MatchResources)
in.ExcludeResources.DeepCopyInto(&out.ExcludeResources)
if in.ExcludeResources != nil {
in, out := &in.ExcludeResources, &out.ExcludeResources
*out = new(MatchResources)
(*in).DeepCopyInto(*out)
}
if in.ImageExtractors != nil {
in, out := &in.ImageExtractors, &out.ImageExtractors
*out = make(v1.ImageExtractorConfigs, len(*in))

View file

@ -98,13 +98,15 @@ func GetKindsFromPolicy(out io.Writer, policy kyvernov1.PolicyInterface, subreso
}
knownkinds.Insert(k)
}
for _, kind := range rule.ExcludeResources.ResourceDescription.Kinds {
k, err := getKind(kind, subresources, dClient)
if err != nil {
fmt.Fprintf(out, "Error: %s", err.Error())
continue
if rule.ExcludeResources != nil {
for _, kind := range rule.ExcludeResources.ResourceDescription.Kinds {
k, err := getKind(kind, subresources, dClient)
if err != nil {
fmt.Fprintf(out, "Error: %s", err.Error())
continue
}
knownkinds.Insert(k)
}
knownkinds.Insert(k)
}
}
return knownkinds

View file

@ -77,8 +77,8 @@ func CanAutoGen(spec *kyvernov1.Spec) (applyAutoGen bool, controllers sets.Set[s
return false, sets.New("none")
}
}
match, exclude := rule.MatchResources, rule.ExcludeResources
if !checkAutogenSupport(&needed, match.ResourceDescription, exclude.ResourceDescription) {
match := rule.MatchResources
if !checkAutogenSupport(&needed, match.ResourceDescription) {
debug.Info("skip generating rule on pod controllers: Name / Selector in resource description may not be applicable.", "rule", rule.Name)
return false, sets.New[string]()
}
@ -94,16 +94,22 @@ func CanAutoGen(spec *kyvernov1.Spec) (applyAutoGen bool, controllers sets.Set[s
return false, sets.New[string]()
}
}
for _, value := range exclude.Any {
if !checkAutogenSupport(&needed, value.ResourceDescription) {
debug.Info("skip generating rule on pod controllers: Name / Selector in exclude any block is not applicable.", "rule", rule.Name)
if exclude := rule.ExcludeResources; exclude != nil {
if !checkAutogenSupport(&needed, exclude.ResourceDescription) {
debug.Info("skip generating rule on pod controllers: Name / Selector in resource description may not be applicable.", "rule", rule.Name)
return false, sets.New[string]()
}
}
for _, value := range exclude.All {
if !checkAutogenSupport(&needed, value.ResourceDescription) {
debug.Info("skip generating rule on pod controllers: Name / Selector in exclud all block is not applicable.", "rule", rule.Name)
return false, sets.New[string]()
for _, value := range exclude.Any {
if !checkAutogenSupport(&needed, value.ResourceDescription) {
debug.Info("skip generating rule on pod controllers: Name / Selector in exclude any block is not applicable.", "rule", rule.Name)
return false, sets.New[string]()
}
}
for _, value := range exclude.All {
if !checkAutogenSupport(&needed, value.ResourceDescription) {
debug.Info("skip generating rule on pod controllers: Name / Selector in exclud all block is not applicable.", "rule", rule.Name)
return false, sets.New[string]()
}
}
}
}
@ -210,7 +216,7 @@ func convertRule(rule kyvernoRule, kind string) (*kyvernov1.Rule, error) {
out.MatchResources = *rule.MatchResources
}
if rule.ExcludeResources != nil {
out.ExcludeResources = *rule.ExcludeResources
out.ExcludeResources = rule.ExcludeResources
}
if rule.Context != nil {
out.Context = *rule.Context

View file

@ -42,7 +42,7 @@ func createRule(rule *kyvernov1.Rule) *kyvernoRule {
if !datautils.DeepEqual(rule.MatchResources, kyvernov1.MatchResources{}) {
jsonFriendlyStruct.MatchResources = rule.MatchResources.DeepCopy()
}
if !datautils.DeepEqual(rule.ExcludeResources, kyvernov1.MatchResources{}) {
if rule.ExcludeResources != nil && !datautils.DeepEqual(*rule.ExcludeResources, kyvernov1.MatchResources{}) {
jsonFriendlyStruct.ExcludeResources = rule.ExcludeResources.DeepCopy()
}
if !datautils.DeepEqual(rule.Mutation, kyvernov1.Mutation{}) {
@ -84,13 +84,15 @@ func generateRule(name string, rule *kyvernov1.Rule, tplKey, shift string, kinds
} else {
rule.MatchResources.Kinds = kinds
}
if len(rule.ExcludeResources.Any) > 0 {
rule.ExcludeResources.Any = grf(rule.ExcludeResources.Any, kinds)
} else if len(rule.ExcludeResources.All) > 0 {
rule.ExcludeResources.All = grf(rule.ExcludeResources.All, kinds)
} else {
if len(rule.ExcludeResources.Kinds) != 0 {
rule.ExcludeResources.Kinds = kinds
if rule.ExcludeResources != nil {
if len(rule.ExcludeResources.Any) > 0 {
rule.ExcludeResources.Any = grf(rule.ExcludeResources.Any, kinds)
} else if len(rule.ExcludeResources.All) > 0 {
rule.ExcludeResources.All = grf(rule.ExcludeResources.All, kinds)
} else {
if len(rule.ExcludeResources.Kinds) != 0 {
rule.ExcludeResources.Kinds = kinds
}
}
}
if target := rule.Mutation.GetPatchStrategicMerge(); target != nil {
@ -255,8 +257,12 @@ func generateRuleForControllers(rule *kyvernov1.Rule, controllers string) *kyver
return nil
}
debug.Info("processing rule", "rulename", rule.Name)
match, exclude := rule.MatchResources, rule.ExcludeResources
matchKinds, excludeKinds := match.GetKinds(), exclude.GetKinds()
match := rule.MatchResources
matchKinds := match.GetKinds()
var excludeKinds []string
if exclude := rule.ExcludeResources; exclude != nil {
excludeKinds = exclude.GetKinds()
}
if !kubeutils.ContainsKind(matchKinds, "Pod") || (len(excludeKinds) != 0 && !kubeutils.ContainsKind(excludeKinds, "Pod")) {
return nil
}

View file

@ -144,7 +144,7 @@ func TestAddOperationsForValidatingWebhookConf(t *testing.T) {
Kinds: []string{"ConfigMap"},
},
},
ExcludeResources: kyverno.MatchResources{
ExcludeResources: &kyverno.MatchResources{
ResourceDescription: kyverno.ResourceDescription{
Operations: []kyverno.AdmissionOperation{"DELETE", "CONNECT", "CREATE"},
},
@ -263,7 +263,7 @@ func TestAddOperationsForMutatingtingWebhookConf(t *testing.T) {
Kinds: []string{"Secret"},
},
},
ExcludeResources: kyverno.MatchResources{
ExcludeResources: &kyverno.MatchResources{
ResourceDescription: kyverno.ResourceDescription{
Operations: []kyverno.AdmissionOperation{"UPDATE"},
},

View file

@ -263,16 +263,18 @@ func computeOperationsForValidatingWebhookConf(r kyvernov1.Rule, operationStatus
operationStatusMap[webhookConnect] = true
operationStatusMap[webhookDelete] = true
}
if r.ExcludeResources.ResourceDescription.Operations != nil {
for _, o := range r.ExcludeResources.ResourceDescription.Operations {
operationStatusMap[string(o)] = false
if r.ExcludeResources != nil {
if r.ExcludeResources.ResourceDescription.Operations != nil {
for _, o := range r.ExcludeResources.ResourceDescription.Operations {
operationStatusMap[string(o)] = false
}
}
if len(r.ExcludeResources.Any) != 0 {
_, operationStatusMap = scanResourceFilterForExclude(r.ExcludeResources.Any, operationStatusMap)
}
if len(r.ExcludeResources.All) != 0 {
_, operationStatusMap = scanResourceFilterForExclude(r.ExcludeResources.All, operationStatusMap)
}
}
if len(r.ExcludeResources.Any) != 0 {
_, operationStatusMap = scanResourceFilterForExclude(r.ExcludeResources.Any, operationStatusMap)
}
if len(r.ExcludeResources.All) != 0 {
_, operationStatusMap = scanResourceFilterForExclude(r.ExcludeResources.All, operationStatusMap)
}
return operationStatusMap
}
@ -307,16 +309,18 @@ func computeOperationsForMutatingWebhookConf(r kyvernov1.Rule, operationStatusMa
operationStatusMap[webhookCreate] = true
operationStatusMap[webhookUpdate] = true
}
if r.ExcludeResources.ResourceDescription.Operations != nil {
for _, o := range r.ExcludeResources.ResourceDescription.Operations {
operationStatusMap[string(o)] = false
if r.ExcludeResources != nil {
if r.ExcludeResources.ResourceDescription.Operations != nil {
for _, o := range r.ExcludeResources.ResourceDescription.Operations {
operationStatusMap[string(o)] = false
}
}
if len(r.ExcludeResources.Any) != 0 {
_, operationStatusMap = scanResourceFilterForExclude(r.ExcludeResources.Any, operationStatusMap)
}
if len(r.ExcludeResources.All) != 0 {
_, operationStatusMap = scanResourceFilterForExclude(r.ExcludeResources.All, operationStatusMap)
}
}
if len(r.ExcludeResources.Any) != 0 {
_, operationStatusMap = scanResourceFilterForExclude(r.ExcludeResources.Any, operationStatusMap)
}
if len(r.ExcludeResources.All) != 0 {
_, operationStatusMap = scanResourceFilterForExclude(r.ExcludeResources.All, operationStatusMap)
}
}
return operationStatusMap
@ -375,17 +379,19 @@ func computeResourcesOfRule(r kyvernov1.Rule) []string {
if len(r.MatchResources.All) != 0 {
resources = scanResourceFilterForResources(r.MatchResources.Any)
}
if len(r.ExcludeResources.Any) != 0 {
resources = scanResourceFilterForResources(r.MatchResources.Any)
}
if len(r.ExcludeResources.All) != 0 {
resources = scanResourceFilterForResources(r.MatchResources.Any)
}
if r.MatchResources.ResourceDescription.Kinds != nil {
resources = append(resources, r.MatchResources.ResourceDescription.Kinds...)
}
if r.ExcludeResources.ResourceDescription.Kinds != nil {
resources = append(resources, r.ExcludeResources.ResourceDescription.Kinds...)
if r.ExcludeResources != nil {
if len(r.ExcludeResources.Any) != 0 {
resources = scanResourceFilterForResources(r.MatchResources.Any)
}
if len(r.ExcludeResources.All) != 0 {
resources = scanResourceFilterForResources(r.MatchResources.Any)
}
if r.ExcludeResources.ResourceDescription.Kinds != nil {
resources = append(resources, r.ExcludeResources.ResourceDescription.Kinds...)
}
}
return resources
}

View file

@ -241,14 +241,14 @@ func TestComputeOperationsForMutatingWebhookConf(t *testing.T) {
PatchesJSON6902: "add",
},
MatchResources: kyvernov1.MatchResources{},
ExcludeResources: kyvernov1.MatchResources{},
ExcludeResources: &kyvernov1.MatchResources{},
},
{
Mutation: kyvernov1.Mutation{
PatchesJSON6902: "add",
},
MatchResources: kyvernov1.MatchResources{},
ExcludeResources: kyvernov1.MatchResources{},
ExcludeResources: &kyvernov1.MatchResources{},
},
},
expectedResult: map[string]bool{
@ -264,7 +264,7 @@ func TestComputeOperationsForMutatingWebhookConf(t *testing.T) {
PatchesJSON6902: "add",
},
MatchResources: kyvernov1.MatchResources{},
ExcludeResources: kyvernov1.MatchResources{
ExcludeResources: &kyvernov1.MatchResources{
ResourceDescription: kyvernov1.ResourceDescription{
Operations: []kyvernov1.AdmissionOperation{webhookCreate},
},
@ -317,7 +317,7 @@ func TestComputeOperationsForValidatingWebhookConf(t *testing.T) {
rules: []kyvernov1.Rule{
{
MatchResources: kyvernov1.MatchResources{},
ExcludeResources: kyvernov1.MatchResources{},
ExcludeResources: &kyvernov1.MatchResources{},
},
},
expectedResult: map[string]bool{
@ -336,7 +336,7 @@ func TestComputeOperationsForValidatingWebhookConf(t *testing.T) {
Operations: []kyvernov1.AdmissionOperation{webhookCreate, webhookUpdate},
},
},
ExcludeResources: kyvernov1.MatchResources{
ExcludeResources: &kyvernov1.MatchResources{
ResourceDescription: kyvernov1.ResourceDescription{
Operations: []kyvernov1.AdmissionOperation{webhookDelete},
},

View file

@ -25,21 +25,22 @@ func matchResource(resource unstructured.Unstructured, rule kyvernov1.Rule) bool
return false
}
}
if rule.ExcludeResources.All != nil || rule.ExcludeResources.Any != nil {
excluded := match.CheckMatchesResources(
resource,
kyvernov2beta1.MatchResources{
Any: rule.ExcludeResources.Any,
All: rule.ExcludeResources.All,
},
make(map[string]string),
kyvernov2.RequestInfo{},
resource.GroupVersionKind(),
"",
)
if excluded == nil {
return false
if rule.ExcludeResources != nil {
if rule.ExcludeResources.All != nil || rule.ExcludeResources.Any != nil {
excluded := match.CheckMatchesResources(
resource,
kyvernov2beta1.MatchResources{
Any: rule.ExcludeResources.Any,
All: rule.ExcludeResources.All,
},
make(map[string]string),
kyvernov2.RequestInfo{},
resource.GroupVersionKind(),
"",
)
if excluded == nil {
return false
}
}
}
return true

View file

@ -209,7 +209,7 @@ func MatchesResourceDescription(
}
// check exlude conditions only if match succeeds
if len(reasonsForFailure) == 0 {
if len(reasonsForFailure) == 0 && rule.ExcludeResources != nil {
if len(rule.ExcludeResources.Any) > 0 {
// exclude the object if ANY of the criteria match
for _, rer := range rule.ExcludeResources.Any {

View file

@ -1963,7 +1963,7 @@ func TestResourceDescriptionMatch_ExcludeDefaultGroups(t *testing.T) {
},
},
}},
ExcludeResources: v1.MatchResources{},
ExcludeResources: &v1.MatchResources{},
}
// this is the request info that was also passed with the mocked pod
@ -1996,7 +1996,7 @@ func TestResourceDescriptionMatch_ExcludeDefaultGroups(t *testing.T) {
},
},
}},
ExcludeResources: v1.MatchResources{Any: v1.ResourceFilters{}},
ExcludeResources: &v1.MatchResources{Any: v1.ResourceFilters{}},
}
// Second test: confirm that matching this rule does not create any errors (and raise if err != nil)
@ -2005,7 +2005,7 @@ func TestResourceDescriptionMatch_ExcludeDefaultGroups(t *testing.T) {
}
// Now we extend the previous rule to have an Exclude part. Making it 'not-empty' should make the exclude-code run.
rule2.ExcludeResources = v1.MatchResources{Any: v1.ResourceFilters{
rule2.ExcludeResources = &v1.MatchResources{Any: v1.ResourceFilters{
v1.ResourceFilter{
ResourceDescription: v1.ResourceDescription{
Kinds: []string{"Pod"},
@ -2461,7 +2461,7 @@ func TestResourceDescriptionExclude_Label_Expression_Match(t *testing.T) {
rule := v1.Rule{
MatchResources: v1.MatchResources{ResourceDescription: resourceDescription},
ExcludeResources: v1.MatchResources{ResourceDescription: resourceDescriptionExclude},
ExcludeResources: &v1.MatchResources{ResourceDescription: resourceDescriptionExclude},
}
if err := MatchesResourceDescription(*resource, rule, v2.RequestInfo{}, nil, "", resource.GroupVersionKind(), "", "CREATE"); err == nil {

View file

@ -179,7 +179,7 @@ func createRule(f *fuzz.ConsumeFuzzer) (*kyvernov1.Rule, error) {
if err != nil {
return rule, err
}
rule.ExcludeResources = *er
rule.ExcludeResources = er
}
setRawAnyAllConditions, err := f.GetBool()

View file

@ -57,21 +57,22 @@ func BuildValidatingAdmissionPolicy(
}
// convert the exclude block
exclude := rule.ExcludeResources
if !exclude.ResourceDescription.IsEmpty() {
if err := translateResource(discoveryClient, &matchResources, &excludeRules, exclude.ResourceDescription, false); err != nil {
return err
if exclude := rule.ExcludeResources; exclude != nil {
if !exclude.ResourceDescription.IsEmpty() {
if err := translateResource(discoveryClient, &matchResources, &excludeRules, exclude.ResourceDescription, false); err != nil {
return err
}
}
}
if exclude.Any != nil {
if err := translateResourceFilters(discoveryClient, &matchResources, &excludeRules, exclude.Any, false); err != nil {
return err
if exclude.Any != nil {
if err := translateResourceFilters(discoveryClient, &matchResources, &excludeRules, exclude.Any, false); err != nil {
return err
}
}
}
if exclude.All != nil {
if err := translateResourceFilters(discoveryClient, &matchResources, &excludeRules, exclude.All, false); err != nil {
return err
if exclude.All != nil {
if err := translateResourceFilters(discoveryClient, &matchResources, &excludeRules, exclude.All, false); err != nil {
return err
}
}
}

View file

@ -72,25 +72,16 @@ func checkPolicy(spec *kyvernov1.Spec) (bool, string) {
}
// check the matched/excluded resources of the CEL rule.
match, exclude := rule.MatchResources, rule.ExcludeResources
match := rule.MatchResources
if ok, msg := checkUserInfo(match.UserInfo); !ok {
return false, msg
}
if ok, msg := checkUserInfo(exclude.UserInfo); !ok {
return false, msg
}
if ok, msg := checkResources(match.ResourceDescription, true); !ok {
return false, msg
}
if ok, msg := checkResources(exclude.ResourceDescription, false); !ok {
return false, msg
}
if ok, msg := checkResourceFilter(match.Any, true); !ok {
return false, msg
}
if len(match.All) > 1 {
msg = "skip generating ValidatingAdmissionPolicy: multiple 'all' in the match block is not applicable."
return false, msg
@ -98,17 +89,24 @@ func checkPolicy(spec *kyvernov1.Spec) (bool, string) {
if ok, msg := checkResourceFilter(match.All, true); !ok {
return false, msg
}
if ok, msg := checkResourceFilter(exclude.Any, false); !ok {
return false, msg
}
if len(exclude.All) > 1 {
msg = "skip generating ValidatingAdmissionPolicy: multiple 'all' in the exclude block is not applicable."
return false, msg
}
if ok, msg := checkResourceFilter(exclude.All, false); !ok {
return false, msg
if rule.ExcludeResources != nil {
exclude := rule.ExcludeResources
if ok, msg := checkUserInfo(exclude.UserInfo); !ok {
return false, msg
}
if ok, msg := checkResources(exclude.ResourceDescription, false); !ok {
return false, msg
}
if ok, msg := checkResourceFilter(exclude.Any, false); !ok {
return false, msg
}
if len(exclude.All) > 1 {
msg = "skip generating ValidatingAdmissionPolicy: multiple 'all' in the exclude block is not applicable."
return false, msg
}
if ok, msg := checkResourceFilter(exclude.All, false); !ok {
return false, msg
}
}
return true, msg

View file

@ -43,11 +43,6 @@ func hasUserMatchExclude(idx int, rule *kyvernov1.Rule) error {
if path := userInfoDefined(rule.MatchResources.UserInfo); path != "" {
return fmt.Errorf("invalid variable used at path: spec/rules[%d]/match/%s", idx, path)
}
if path := userInfoDefined(rule.ExcludeResources.UserInfo); path != "" {
return fmt.Errorf("invalid variable used at path: spec/rules[%d]/exclude/%s", idx, path)
}
if len(rule.MatchResources.Any) > 0 {
for i, value := range rule.MatchResources.Any {
if path := userInfoDefined(value.UserInfo); path != "" {
@ -55,7 +50,6 @@ func hasUserMatchExclude(idx int, rule *kyvernov1.Rule) error {
}
}
}
if len(rule.MatchResources.All) > 0 {
for i, value := range rule.MatchResources.All {
if path := userInfoDefined(value.UserInfo); path != "" {
@ -63,23 +57,25 @@ func hasUserMatchExclude(idx int, rule *kyvernov1.Rule) error {
}
}
}
if len(rule.ExcludeResources.All) > 0 {
for i, value := range rule.ExcludeResources.All {
if path := userInfoDefined(value.UserInfo); path != "" {
return fmt.Errorf("invalid variable used at path: spec/rules[%d]/exclude/all[%d]/%s", idx, i, path)
if rule.ExcludeResources != nil {
if path := userInfoDefined(rule.ExcludeResources.UserInfo); path != "" {
return fmt.Errorf("invalid variable used at path: spec/rules[%d]/exclude/%s", idx, path)
}
if len(rule.ExcludeResources.All) > 0 {
for i, value := range rule.ExcludeResources.All {
if path := userInfoDefined(value.UserInfo); path != "" {
return fmt.Errorf("invalid variable used at path: spec/rules[%d]/exclude/all[%d]/%s", idx, i, path)
}
}
}
if len(rule.ExcludeResources.Any) > 0 {
for i, value := range rule.ExcludeResources.Any {
if path := userInfoDefined(value.UserInfo); path != "" {
return fmt.Errorf("invalid variable used at path: spec/rules[%d]/exclude/any[%d]/%s", idx, i, path)
}
}
}
}
if len(rule.ExcludeResources.Any) > 0 {
for i, value := range rule.ExcludeResources.Any {
if path := userInfoDefined(value.UserInfo); path != "" {
return fmt.Errorf("invalid variable used at path: spec/rules[%d]/exclude/any[%d]/%s", idx, i, path)
}
}
}
return nil
}

View file

@ -236,7 +236,6 @@ func Validate(policy, oldPolicy kyvernov1.PolicyInterface, client dclient.Interf
for i, rule := range rules {
match := rule.MatchResources
exclude := rule.ExcludeResources
for j, value := range match.Any {
if err := validateKinds(value.ResourceDescription.Kinds, rule, mock, background, client); err != nil {
return warnings, fmt.Errorf("path: spec.rules[%d].match.any[%d].kinds: %v", i, j, err)
@ -247,23 +246,23 @@ func Validate(policy, oldPolicy kyvernov1.PolicyInterface, client dclient.Interf
return warnings, fmt.Errorf("path: spec.rules[%d].match.all[%d].kinds: %v", i, j, err)
}
}
for j, value := range exclude.Any {
if err := validateKinds(value.ResourceDescription.Kinds, rule, mock, background, client); err != nil {
return warnings, fmt.Errorf("path: spec.rules[%d].exclude.any[%d].kinds: %v", i, j, err)
}
}
for j, value := range exclude.All {
if err := validateKinds(value.ResourceDescription.Kinds, rule, mock, background, client); err != nil {
return warnings, fmt.Errorf("path: spec.rules[%d].exclude.all[%d].kinds: %v", i, j, err)
}
}
if err := validateKinds(rule.MatchResources.Kinds, rule, mock, background, client); err != nil {
return warnings, fmt.Errorf("path: spec.rules[%d].match.kinds: %v", i, err)
}
if err := validateKinds(rule.ExcludeResources.Kinds, rule, mock, background, client); err != nil {
return warnings, fmt.Errorf("path: spec.rules[%d].exclude.kinds: %v", i, err)
if exclude := rule.ExcludeResources; exclude != nil {
for j, value := range exclude.Any {
if err := validateKinds(value.ResourceDescription.Kinds, rule, mock, background, client); err != nil {
return warnings, fmt.Errorf("path: spec.rules[%d].exclude.any[%d].kinds: %v", i, j, err)
}
}
for j, value := range exclude.All {
if err := validateKinds(value.ResourceDescription.Kinds, rule, mock, background, client); err != nil {
return warnings, fmt.Errorf("path: spec.rules[%d].exclude.all[%d].kinds: %v", i, j, err)
}
}
if err := validateKinds(exclude.Kinds, rule, mock, background, client); err != nil {
return warnings, fmt.Errorf("path: spec.rules[%d].exclude.kinds: %v", i, err)
}
}
}
@ -377,12 +376,13 @@ func Validate(policy, oldPolicy kyvernov1.PolicyInterface, client dclient.Interf
}
match := rule.MatchResources
exclude := rule.ExcludeResources
matchKinds := match.GetKinds()
excludeKinds := exclude.GetKinds()
allKinds := make([]string, 0, len(matchKinds)+len(excludeKinds))
var allKinds []string
allKinds = append(allKinds, matchKinds...)
allKinds = append(allKinds, excludeKinds...)
if exclude := rule.ExcludeResources; exclude != nil {
excludeKinds := exclude.GetKinds()
allKinds = append(allKinds, excludeKinds...)
}
if rule.HasValidate() {
validationElem := rule.Validation.DeepCopy()
if validationElem.Deny != nil {
@ -691,17 +691,16 @@ func jsonPatchPathHasVariables(patch string) error {
return nil
}
func objectHasVariables(object interface{}) error {
var err error
objectJSON, err := json.Marshal(object)
if err != nil {
return err
func objectHasVariables(object any) error {
if object != nil {
objectJSON, err := json.Marshal(object)
if err != nil {
return err
}
if len(regexVariables.FindAllStringSubmatch(string(objectJSON), -1)) > 0 {
return fmt.Errorf("invalid variables")
}
}
if len(regexVariables.FindAllStringSubmatch(string(objectJSON), -1)) > 0 {
return fmt.Errorf("invalid variables")
}
return nil
}
@ -963,22 +962,22 @@ func ruleOnlyDealsWithResourceMetaData(rule kyvernov1.Rule) bool {
func validateResources(path *field.Path, rule kyvernov1.Rule) (string, error) {
// validate userInfo in match and exclude
if errs := rule.ExcludeResources.UserInfo.Validate(path.Child("exclude")); len(errs) != 0 {
return "exclude", errs.ToAggregate()
if exclude := rule.ExcludeResources; exclude != nil {
if errs := exclude.UserInfo.Validate(path.Child("exclude")); len(errs) != 0 {
return "exclude", errs.ToAggregate()
}
if (len(exclude.Any) > 0 || len(exclude.All) > 0) && !datautils.DeepEqual(exclude.ResourceDescription, kyvernov1.ResourceDescription{}) {
return "exclude.", fmt.Errorf("can't specify any/all together with exclude resources")
}
if len(exclude.Any) > 0 && len(exclude.All) > 0 {
return "match.", fmt.Errorf("can't specify any and all together")
}
}
if (len(rule.MatchResources.Any) > 0 || len(rule.MatchResources.All) > 0) && !datautils.DeepEqual(rule.MatchResources.ResourceDescription, kyvernov1.ResourceDescription{}) {
return "match.", fmt.Errorf("can't specify any/all together with match resources")
}
if (len(rule.ExcludeResources.Any) > 0 || len(rule.ExcludeResources.All) > 0) && !datautils.DeepEqual(rule.ExcludeResources.ResourceDescription, kyvernov1.ResourceDescription{}) {
return "exclude.", fmt.Errorf("can't specify any/all together with exclude resources")
}
if len(rule.ExcludeResources.Any) > 0 && len(rule.ExcludeResources.All) > 0 {
return "match.", fmt.Errorf("can't specify any and all together")
}
if len(rule.MatchResources.Any) > 0 {
for _, rmr := range rule.MatchResources.Any {
// matched resources