From e5fd204c33e90a7e8f5a0ee70242f1296a5ec7af Mon Sep 17 00:00:00 2001 From: Max Smythe Date: Wed, 15 Mar 2023 17:23:15 -0700 Subject: [PATCH] Custom match criteria (#116350) * Add custom match conditions for CEL admission This PR is based off of, and dependent on the following PR: https://github.com/kubernetes/kubernetes/pull/116261 Signed-off-by: Max Smythe * run `make update` Signed-off-by: Max Smythe * Fix unit tests Signed-off-by: Max Smythe * Fix unit tests Signed-off-by: Max Smythe * Update compatibility test data Signed-off-by: Max Smythe * Revert "Update compatibility test data" This reverts commit 312ba7f9e74e0ec4a7ac1f07bf575479c608af28. * Allow params during validation; make match conditions optional Signed-off-by: Max Smythe * Add conditional ignoring of matcher CEL expression validation on update Signed-off-by: Max Smythe * Run codegen Signed-off-by: Max Smythe * Add more validation tests Signed-off-by: Max Smythe * Short-circuit CEL matcher when no matchers specified Signed-off-by: Max Smythe * Run codegen Signed-off-by: Max Smythe * Address review comments Signed-off-by: Max Smythe --------- Signed-off-by: Max Smythe --- api/openapi-spec/swagger.json | 30 ++ ...registration.k8s.io__v1alpha1_openapi.json | 37 ++ pkg/apis/admissionregistration/types.go | 18 + .../v1alpha1/zz_generated.conversion.go | 34 ++ .../validation/validation.go | 42 +- .../validation/validation_test.go | 321 ++++++++++++ .../zz_generated.deepcopy.go | 5 + pkg/generated/openapi/zz_generated.openapi.go | 56 ++- .../v1alpha1/generated.pb.go | 462 ++++++++++++++---- .../v1alpha1/generated.proto | 50 ++ .../admissionregistration/v1alpha1/types.go | 24 + .../v1alpha1/types_swagger_doc_generated.go | 1 + .../v1alpha1/zz_generated.deepcopy.go | 21 + ...io.v1alpha1.ValidatingAdmissionPolicy.json | 6 + ...s.io.v1alpha1.ValidatingAdmissionPolicy.pb | Bin 1080 -> 1110 bytes ...io.v1alpha1.ValidatingAdmissionPolicy.yaml | 3 + .../admission_test.go | 6 +- .../controller_reconcile.go | 16 +- .../validatingadmissionpolicy/validator.go | 25 +- .../validator_test.go | 53 +- .../v1alpha1/matchcondition.go | 48 ++ .../v1alpha1/validatingadmissionpolicyspec.go | 14 + .../applyconfigurations/internal/internal.go | 19 + .../client-go/applyconfigurations/utils.go | 2 + 24 files changed, 1173 insertions(+), 120 deletions(-) create mode 100644 staging/src/k8s.io/client-go/applyconfigurations/admissionregistration/v1alpha1/matchcondition.go diff --git a/api/openapi-spec/swagger.json b/api/openapi-spec/swagger.json index b94fc8308ee..4007eca9cb4 100644 --- a/api/openapi-spec/swagger.json +++ b/api/openapi-spec/swagger.json @@ -428,6 +428,23 @@ ], "type": "object" }, + "io.k8s.api.admissionregistration.v1alpha1.MatchCondition": { + "properties": { + "expression": { + "description": "Expression represents the expression which will be evaluated by CEL. Must evaluate to bool. CEL expressions have access to the contents of the AdmissionRequest and Authorizer, organized into CEL variables:\n\n'object' - The object from the incoming request. The value is null for DELETE requests. 'oldObject' - The existing object. The value is null for CREATE requests. 'request' - Attributes of the admission request(/pkg/apis/admission/types.go#AdmissionRequest). 'authorizer' - A CEL Authorizer. May be used to perform authorization checks for the principal (user or service account) of the request.\n See https://pkg.go.dev/k8s.io/apiserver/pkg/cel/library#Authz\n'authorizer.requestResource' - A CEL ResourceCheck constructed from the 'authorizer' and configured with the\n request resource.\nDocumentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/\n\nRequired.", + "type": "string" + }, + "name": { + "description": "Name is an identifier for this match condition, used for strategic merging of MatchConditions, as well as providing an identifier for logging purposes. A good name should be descriptive of the associated expression. Name must be a qualified name consisting of alphanumeric characters, '-', '_' or '.', and must start and end with an alphanumeric character (e.g. 'MyName', or 'my.name', or '123-abc', regex used for validation is '([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9]') with an optional DNS subdomain prefix and '/' (e.g. 'example.com/MyName')\n\nRequired.", + "type": "string" + } + }, + "required": [ + "name", + "expression" + ], + "type": "object" + }, "io.k8s.api.admissionregistration.v1alpha1.MatchResources": { "description": "MatchResources decides whether to run the admission control policy on an object based on whether it meets the match criteria. The exclude rules take precedence over include rules (if a resource matches both, it is excluded)", "properties": { @@ -725,6 +742,19 @@ "description": "failurePolicy defines how to handle failures for the admission policy. Failures can occur from CEL expression parse errors, type check errors, runtime errors and invalid or mis-configured policy definitions or bindings.\n\nA policy is invalid if spec.paramKind refers to a non-existent Kind. A binding is invalid if spec.paramRef.name refers to a non-existent resource.\n\nfailurePolicy does not define how validations that evaluate to false are handled.\n\nWhen failurePolicy is set to Fail, ValidatingAdmissionPolicyBinding validationActions define how failures are enforced.\n\nAllowed values are Ignore or Fail. Defaults to Fail.", "type": "string" }, + "matchConditions": { + "description": "MatchConditions is a list of conditions that must be met for a request to be validated. Match conditions filter requests that have already been matched by the rules, namespaceSelector, and objectSelector. An empty list of matchConditions matches all requests. There are a maximum of 64 match conditions allowed.\n\nIf a parameter object is provided, it can be accessed via the `params` handle in the same manner as validation expressions.\n\nThe exact matching logic is (in order):\n 1. If ANY matchCondition evaluates to FALSE, the policy is skipped.\n 2. If ALL matchConditions evaluate to TRUE, the policy is evaluated.\n 3. If any matchCondition evaluates to an error (but none are FALSE):\n - If failurePolicy=Fail, reject the request\n - If failurePolicy=Ignore, the policy is skipped", + "items": { + "$ref": "#/definitions/io.k8s.api.admissionregistration.v1alpha1.MatchCondition" + }, + "type": "array", + "x-kubernetes-list-map-keys": [ + "name" + ], + "x-kubernetes-list-type": "map", + "x-kubernetes-patch-merge-key": "name", + "x-kubernetes-patch-strategy": "merge" + }, "matchConstraints": { "$ref": "#/definitions/io.k8s.api.admissionregistration.v1alpha1.MatchResources", "description": "MatchConstraints specifies what resources this policy is designed to validate. The AdmissionPolicy cares about a request if it matches _all_ Constraints. However, in order to prevent clusters from being put into an unstable state that cannot be recovered from via the API ValidatingAdmissionPolicy cannot match ValidatingAdmissionPolicy and ValidatingAdmissionPolicyBinding. Required." diff --git a/api/openapi-spec/v3/apis__admissionregistration.k8s.io__v1alpha1_openapi.json b/api/openapi-spec/v3/apis__admissionregistration.k8s.io__v1alpha1_openapi.json index 9d743fe78f9..5a27f22f555 100644 --- a/api/openapi-spec/v3/apis__admissionregistration.k8s.io__v1alpha1_openapi.json +++ b/api/openapi-spec/v3/apis__admissionregistration.k8s.io__v1alpha1_openapi.json @@ -41,6 +41,25 @@ ], "type": "object" }, + "io.k8s.api.admissionregistration.v1alpha1.MatchCondition": { + "properties": { + "expression": { + "default": "", + "description": "Expression represents the expression which will be evaluated by CEL. Must evaluate to bool. CEL expressions have access to the contents of the AdmissionRequest and Authorizer, organized into CEL variables:\n\n'object' - The object from the incoming request. The value is null for DELETE requests. 'oldObject' - The existing object. The value is null for CREATE requests. 'request' - Attributes of the admission request(/pkg/apis/admission/types.go#AdmissionRequest). 'authorizer' - A CEL Authorizer. May be used to perform authorization checks for the principal (user or service account) of the request.\n See https://pkg.go.dev/k8s.io/apiserver/pkg/cel/library#Authz\n'authorizer.requestResource' - A CEL ResourceCheck constructed from the 'authorizer' and configured with the\n request resource.\nDocumentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/\n\nRequired.", + "type": "string" + }, + "name": { + "default": "", + "description": "Name is an identifier for this match condition, used for strategic merging of MatchConditions, as well as providing an identifier for logging purposes. A good name should be descriptive of the associated expression. Name must be a qualified name consisting of alphanumeric characters, '-', '_' or '.', and must start and end with an alphanumeric character (e.g. 'MyName', or 'my.name', or '123-abc', regex used for validation is '([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9]') with an optional DNS subdomain prefix and '/' (e.g. 'example.com/MyName')\n\nRequired.", + "type": "string" + } + }, + "required": [ + "name", + "expression" + ], + "type": "object" + }, "io.k8s.api.admissionregistration.v1alpha1.MatchResources": { "description": "MatchResources decides whether to run the admission control policy on an object based on whether it meets the match criteria. The exclude rules take precedence over include rules (if a resource matches both, it is excluded)", "properties": { @@ -425,6 +444,24 @@ "description": "failurePolicy defines how to handle failures for the admission policy. Failures can occur from CEL expression parse errors, type check errors, runtime errors and invalid or mis-configured policy definitions or bindings.\n\nA policy is invalid if spec.paramKind refers to a non-existent Kind. A binding is invalid if spec.paramRef.name refers to a non-existent resource.\n\nfailurePolicy does not define how validations that evaluate to false are handled.\n\nWhen failurePolicy is set to Fail, ValidatingAdmissionPolicyBinding validationActions define how failures are enforced.\n\nAllowed values are Ignore or Fail. Defaults to Fail.", "type": "string" }, + "matchConditions": { + "description": "MatchConditions is a list of conditions that must be met for a request to be validated. Match conditions filter requests that have already been matched by the rules, namespaceSelector, and objectSelector. An empty list of matchConditions matches all requests. There are a maximum of 64 match conditions allowed.\n\nIf a parameter object is provided, it can be accessed via the `params` handle in the same manner as validation expressions.\n\nThe exact matching logic is (in order):\n 1. If ANY matchCondition evaluates to FALSE, the policy is skipped.\n 2. If ALL matchConditions evaluate to TRUE, the policy is evaluated.\n 3. If any matchCondition evaluates to an error (but none are FALSE):\n - If failurePolicy=Fail, reject the request\n - If failurePolicy=Ignore, the policy is skipped", + "items": { + "allOf": [ + { + "$ref": "#/components/schemas/io.k8s.api.admissionregistration.v1alpha1.MatchCondition" + } + ], + "default": {} + }, + "type": "array", + "x-kubernetes-list-map-keys": [ + "name" + ], + "x-kubernetes-list-type": "map", + "x-kubernetes-patch-merge-key": "name", + "x-kubernetes-patch-strategy": "merge" + }, "matchConstraints": { "allOf": [ { diff --git a/pkg/apis/admissionregistration/types.go b/pkg/apis/admissionregistration/types.go index da2194a026d..a6a4bf85640 100644 --- a/pkg/apis/admissionregistration/types.go +++ b/pkg/apis/admissionregistration/types.go @@ -206,6 +206,24 @@ type ValidatingAdmissionPolicySpec struct { // +optional Validations []Validation + // MatchConditions is a list of conditions that must be met for a request to be validated. + // Match conditions filter requests that have already been matched by the rules, + // namespaceSelector, and objectSelector. An empty list of matchConditions matches all requests. + // There are a maximum of 64 match conditions allowed. + // + // If a parameter object is provided, it can be accessed via the `params` handle in the same + // manner as validation expressions. + // + // The exact matching logic is (in order): + // 1. If ANY matchCondition evaluates to FALSE, the policy is skipped. + // 2. If ALL matchConditions evaluate to TRUE, the policy is evaluated. + // 3. If any matchCondition evaluates to an error (but none are FALSE): + // - If failurePolicy=Fail, reject the request + // - If failurePolicy=Ignore, the policy is skipped + // + // +optional + MatchConditions []MatchCondition + // failurePolicy defines how to handle failures for the admission policy. Failures can // occur from CEL expression parse errors, type check errors, runtime errors and invalid // or mis-configured policy definitions or bindings. diff --git a/pkg/apis/admissionregistration/v1alpha1/zz_generated.conversion.go b/pkg/apis/admissionregistration/v1alpha1/zz_generated.conversion.go index c90b03ac40d..4e415bf000f 100644 --- a/pkg/apis/admissionregistration/v1alpha1/zz_generated.conversion.go +++ b/pkg/apis/admissionregistration/v1alpha1/zz_generated.conversion.go @@ -59,6 +59,16 @@ func RegisterConversions(s *runtime.Scheme) error { }); err != nil { return err } + if err := s.AddGeneratedConversionFunc((*v1alpha1.MatchCondition)(nil), (*admissionregistration.MatchCondition)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1alpha1_MatchCondition_To_admissionregistration_MatchCondition(a.(*v1alpha1.MatchCondition), b.(*admissionregistration.MatchCondition), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*admissionregistration.MatchCondition)(nil), (*v1alpha1.MatchCondition)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_admissionregistration_MatchCondition_To_v1alpha1_MatchCondition(a.(*admissionregistration.MatchCondition), b.(*v1alpha1.MatchCondition), scope) + }); err != nil { + return err + } if err := s.AddGeneratedConversionFunc((*v1alpha1.MatchResources)(nil), (*admissionregistration.MatchResources)(nil), func(a, b interface{}, scope conversion.Scope) error { return Convert_v1alpha1_MatchResources_To_admissionregistration_MatchResources(a.(*v1alpha1.MatchResources), b.(*admissionregistration.MatchResources), scope) }); err != nil { @@ -236,6 +246,28 @@ func Convert_admissionregistration_ExpressionWarning_To_v1alpha1_ExpressionWarni return autoConvert_admissionregistration_ExpressionWarning_To_v1alpha1_ExpressionWarning(in, out, s) } +func autoConvert_v1alpha1_MatchCondition_To_admissionregistration_MatchCondition(in *v1alpha1.MatchCondition, out *admissionregistration.MatchCondition, s conversion.Scope) error { + out.Name = in.Name + out.Expression = in.Expression + return nil +} + +// Convert_v1alpha1_MatchCondition_To_admissionregistration_MatchCondition is an autogenerated conversion function. +func Convert_v1alpha1_MatchCondition_To_admissionregistration_MatchCondition(in *v1alpha1.MatchCondition, out *admissionregistration.MatchCondition, s conversion.Scope) error { + return autoConvert_v1alpha1_MatchCondition_To_admissionregistration_MatchCondition(in, out, s) +} + +func autoConvert_admissionregistration_MatchCondition_To_v1alpha1_MatchCondition(in *admissionregistration.MatchCondition, out *v1alpha1.MatchCondition, s conversion.Scope) error { + out.Name = in.Name + out.Expression = in.Expression + return nil +} + +// Convert_admissionregistration_MatchCondition_To_v1alpha1_MatchCondition is an autogenerated conversion function. +func Convert_admissionregistration_MatchCondition_To_v1alpha1_MatchCondition(in *admissionregistration.MatchCondition, out *v1alpha1.MatchCondition, s conversion.Scope) error { + return autoConvert_admissionregistration_MatchCondition_To_v1alpha1_MatchCondition(in, out, s) +} + func autoConvert_v1alpha1_MatchResources_To_admissionregistration_MatchResources(in *v1alpha1.MatchResources, out *admissionregistration.MatchResources, s conversion.Scope) error { out.NamespaceSelector = (*v1.LabelSelector)(unsafe.Pointer(in.NamespaceSelector)) out.ObjectSelector = (*v1.LabelSelector)(unsafe.Pointer(in.ObjectSelector)) @@ -592,6 +624,7 @@ func autoConvert_v1alpha1_ValidatingAdmissionPolicySpec_To_admissionregistration out.Validations = *(*[]admissionregistration.Validation)(unsafe.Pointer(&in.Validations)) out.FailurePolicy = (*admissionregistration.FailurePolicyType)(unsafe.Pointer(in.FailurePolicy)) out.AuditAnnotations = *(*[]admissionregistration.AuditAnnotation)(unsafe.Pointer(&in.AuditAnnotations)) + out.MatchConditions = *(*[]admissionregistration.MatchCondition)(unsafe.Pointer(&in.MatchConditions)) return nil } @@ -612,6 +645,7 @@ func autoConvert_admissionregistration_ValidatingAdmissionPolicySpec_To_v1alpha1 out.MatchConstraints = nil } out.Validations = *(*[]v1alpha1.Validation)(unsafe.Pointer(&in.Validations)) + out.MatchConditions = *(*[]v1alpha1.MatchCondition)(unsafe.Pointer(&in.MatchConditions)) out.FailurePolicy = (*v1alpha1.FailurePolicyType)(unsafe.Pointer(in.FailurePolicy)) out.AuditAnnotations = *(*[]v1alpha1.AuditAnnotation)(unsafe.Pointer(&in.AuditAnnotations)) return nil diff --git a/pkg/apis/admissionregistration/validation/validation.go b/pkg/apis/admissionregistration/validation/validation.go index 204ed745b91..69483cf1eed 100644 --- a/pkg/apis/admissionregistration/validation/validation.go +++ b/pkg/apis/admissionregistration/validation/validation.go @@ -213,6 +213,7 @@ func validateAdmissionReviewVersions(versions []string, requireRecognizedAdmissi func ValidateValidatingWebhookConfiguration(e *admissionregistration.ValidatingWebhookConfiguration) field.ErrorList { return validateValidatingWebhookConfiguration(e, validationOptions{ ignoreMatchConditions: false, + allowParamsInMatchConditions: false, requireNoSideEffects: true, requireRecognizedAdmissionReviewVersion: true, requireUniqueWebhookNames: true, @@ -241,6 +242,7 @@ func validateValidatingWebhookConfiguration(e *admissionregistration.ValidatingW func ValidateMutatingWebhookConfiguration(e *admissionregistration.MutatingWebhookConfiguration) field.ErrorList { return validateMutatingWebhookConfiguration(e, validationOptions{ ignoreMatchConditions: false, + allowParamsInMatchConditions: false, requireNoSideEffects: true, requireRecognizedAdmissionReviewVersion: true, requireUniqueWebhookNames: true, @@ -250,6 +252,7 @@ func ValidateMutatingWebhookConfiguration(e *admissionregistration.MutatingWebho type validationOptions struct { ignoreMatchConditions bool + allowParamsInMatchConditions bool requireNoSideEffects bool requireRecognizedAdmissionReviewVersion bool requireUniqueWebhookNames bool @@ -324,7 +327,7 @@ func validateValidatingWebhook(hook *admissionregistration.ValidatingWebhook, op } if !opts.ignoreMatchConditions { - allErrors = append(allErrors, validateMatchConditions(hook.MatchConditions, fldPath.Child("matchConditions"))...) + allErrors = append(allErrors, validateMatchConditions(hook.MatchConditions, opts, fldPath.Child("matchConditions"))...) } return allErrors @@ -382,7 +385,7 @@ func validateMutatingWebhook(hook *admissionregistration.MutatingWebhook, opts v } if !opts.ignoreMatchConditions { - allErrors = append(allErrors, validateMatchConditions(hook.MatchConditions, fldPath.Child("matchConditions"))...) + allErrors = append(allErrors, validateMatchConditions(hook.MatchConditions, opts, fldPath.Child("matchConditions"))...) } return allErrors @@ -520,6 +523,17 @@ func ignoreValidatingWebhookMatchConditions(new, old []admissionregistration.Val return true } +// ignoreValidatingAdmissionPolicyMatchConditions returns true if there have been no updates that could invalidate previously-valid match conditions +func ignoreValidatingAdmissionPolicyMatchConditions(new, old *admissionregistration.ValidatingAdmissionPolicy) bool { + if !reflect.DeepEqual(new.Spec.ParamKind, old.Spec.ParamKind) { + return false + } + if !reflect.DeepEqual(new.Spec.MatchConditions, old.Spec.MatchConditions) { + return false + } + return true +} + // mutatingHasUniqueWebhookNames returns true if all webhooks have unique names func mutatingHasUniqueWebhookNames(webhooks []admissionregistration.MutatingWebhook) bool { names := sets.NewString() @@ -610,6 +624,7 @@ func mutatingWebhookHasInvalidLabelValueInSelector(webhooks []admissionregistrat func ValidateValidatingWebhookConfigurationUpdate(newC, oldC *admissionregistration.ValidatingWebhookConfiguration) field.ErrorList { return validateValidatingWebhookConfiguration(newC, validationOptions{ ignoreMatchConditions: ignoreValidatingWebhookMatchConditions(newC.Webhooks, oldC.Webhooks), + allowParamsInMatchConditions: false, requireNoSideEffects: validatingHasNoSideEffects(oldC.Webhooks), requireRecognizedAdmissionReviewVersion: validatingHasAcceptedAdmissionReviewVersions(oldC.Webhooks), requireUniqueWebhookNames: validatingHasUniqueWebhookNames(oldC.Webhooks), @@ -621,6 +636,7 @@ func ValidateValidatingWebhookConfigurationUpdate(newC, oldC *admissionregistrat func ValidateMutatingWebhookConfigurationUpdate(newC, oldC *admissionregistration.MutatingWebhookConfiguration) field.ErrorList { return validateMutatingWebhookConfiguration(newC, validationOptions{ ignoreMatchConditions: ignoreMutatingWebhookMatchConditions(newC.Webhooks, oldC.Webhooks), + allowParamsInMatchConditions: false, requireNoSideEffects: mutatingHasNoSideEffects(oldC.Webhooks), requireRecognizedAdmissionReviewVersion: mutatingHasAcceptedAdmissionReviewVersions(oldC.Webhooks), requireUniqueWebhookNames: mutatingHasUniqueWebhookNames(oldC.Webhooks), @@ -638,16 +654,16 @@ const ( // ValidateValidatingAdmissionPolicy validates a ValidatingAdmissionPolicy before creation. func ValidateValidatingAdmissionPolicy(p *admissionregistration.ValidatingAdmissionPolicy) field.ErrorList { - return validateValidatingAdmissionPolicy(p) + return validateValidatingAdmissionPolicy(p, validationOptions{ignoreMatchConditions: false}) } -func validateValidatingAdmissionPolicy(p *admissionregistration.ValidatingAdmissionPolicy) field.ErrorList { +func validateValidatingAdmissionPolicy(p *admissionregistration.ValidatingAdmissionPolicy, opts validationOptions) field.ErrorList { allErrors := genericvalidation.ValidateObjectMeta(&p.ObjectMeta, false, genericvalidation.NameIsDNSSubdomain, field.NewPath("metadata")) - allErrors = append(allErrors, validateValidatingAdmissionPolicySpec(p.ObjectMeta, &p.Spec, field.NewPath("spec"))...) + allErrors = append(allErrors, validateValidatingAdmissionPolicySpec(p.ObjectMeta, &p.Spec, opts, field.NewPath("spec"))...) return allErrors } -func validateValidatingAdmissionPolicySpec(meta metav1.ObjectMeta, spec *admissionregistration.ValidatingAdmissionPolicySpec, fldPath *field.Path) field.ErrorList { +func validateValidatingAdmissionPolicySpec(meta metav1.ObjectMeta, spec *admissionregistration.ValidatingAdmissionPolicySpec, opts validationOptions, fldPath *field.Path) field.ErrorList { var allErrors field.ErrorList if spec.FailurePolicy == nil { allErrors = append(allErrors, field.Required(fldPath.Child("failurePolicy"), "")) @@ -655,6 +671,7 @@ func validateValidatingAdmissionPolicySpec(meta metav1.ObjectMeta, spec *admissi allErrors = append(allErrors, field.NotSupported(fldPath.Child("failurePolicy"), *spec.FailurePolicy, supportedFailurePolicies.List())) } if spec.ParamKind != nil { + opts.allowParamsInMatchConditions = true allErrors = append(allErrors, validateParamKind(*spec.ParamKind, fldPath.Child("paramKind"))...) } if spec.MatchConstraints == nil { @@ -666,6 +683,9 @@ func validateValidatingAdmissionPolicySpec(meta metav1.ObjectMeta, spec *admissi allErrors = append(allErrors, field.Required(fldPath.Child("matchConstraints", "resourceRules"), "")) } } + if !opts.ignoreMatchConditions { + allErrors = append(allErrors, validateMatchConditions(spec.MatchConditions, opts, fldPath.Child("matchConditions"))...) + } if len(spec.Validations) == 0 && len(spec.AuditAnnotations) == 0 { allErrors = append(allErrors, field.Required(fldPath.Child("validations"), "validations or auditAnnotations must contain at least one item")) allErrors = append(allErrors, field.Required(fldPath.Child("auditAnnotations"), "validations or auditAnnotations must contain at least one item")) @@ -822,14 +842,14 @@ func validateNamedRuleWithOperations(n *admissionregistration.NamedRuleWithOpera return allErrors } -func validateMatchConditions(m []admissionregistration.MatchCondition, fldPath *field.Path) field.ErrorList { +func validateMatchConditions(m []admissionregistration.MatchCondition, opts validationOptions, fldPath *field.Path) field.ErrorList { var allErrors field.ErrorList conditionNames := sets.NewString() if len(m) > 64 { allErrors = append(allErrors, field.TooMany(fldPath, len(m), 64)) } for i, matchCondition := range m { - allErrors = append(allErrors, validateMatchCondition(&matchCondition, fldPath.Index(i))...) + allErrors = append(allErrors, validateMatchCondition(&matchCondition, opts, fldPath.Index(i))...) if len(matchCondition.Name) > 0 { if conditionNames.Has(matchCondition.Name) { allErrors = append(allErrors, field.Duplicate(fldPath.Index(i).Child("name"), matchCondition.Name)) @@ -841,14 +861,14 @@ func validateMatchConditions(m []admissionregistration.MatchCondition, fldPath * return allErrors } -func validateMatchCondition(v *admissionregistration.MatchCondition, fldPath *field.Path) field.ErrorList { +func validateMatchCondition(v *admissionregistration.MatchCondition, opts validationOptions, fldPath *field.Path) field.ErrorList { var allErrors field.ErrorList trimmedExpression := strings.TrimSpace(v.Expression) if len(trimmedExpression) == 0 { allErrors = append(allErrors, field.Required(fldPath.Child("expression"), "")) } else { allErrors = append(allErrors, validateCELExpression(trimmedExpression, plugincel.OptionalVariableDeclarations{ - HasParams: false, + HasParams: opts.allowParamsInMatchConditions, HasAuthorizer: true, }, fldPath.Child("expression"))...) } @@ -995,7 +1015,7 @@ func validateParamRef(pr *admissionregistration.ParamRef, fldPath *field.Path) f // ValidateValidatingAdmissionPolicyUpdate validates update of validating admission policy func ValidateValidatingAdmissionPolicyUpdate(newC, oldC *admissionregistration.ValidatingAdmissionPolicy) field.ErrorList { - return validateValidatingAdmissionPolicy(newC) + return validateValidatingAdmissionPolicy(newC, validationOptions{ignoreMatchConditions: ignoreValidatingAdmissionPolicyMatchConditions(newC, oldC)}) } // ValidateValidatingAdmissionPolicyStatusUpdate validates update of status of validating admission policy diff --git a/pkg/apis/admissionregistration/validation/validation_test.go b/pkg/apis/admissionregistration/validation/validation_test.go index 7f1ee76a54d..25b6eecf44c 100644 --- a/pkg/apis/admissionregistration/validation/validation_test.go +++ b/pkg/apis/admissionregistration/validation/validation_test.go @@ -3150,6 +3150,131 @@ func TestValidateValidatingAdmissionPolicy(t *testing.T) { }, expectedError: `spec.auditAnnotations[0].valueExpression: Invalid value: "object.x in [1, 2, ": compilation failed: ERROR: :1:19: Syntax error: missing ']' at '`, }, + { + name: "single match condition must have a name", + config: &admissionregistration.ValidatingAdmissionPolicy{ + ObjectMeta: metav1.ObjectMeta{ + Name: "config", + }, + Spec: admissionregistration.ValidatingAdmissionPolicySpec{ + MatchConditions: []admissionregistration.MatchCondition{ + { + Expression: "true", + }, + }, + Validations: []admissionregistration.Validation{ + { + Expression: "object.x < 100", + }, + }, + }, + }, + expectedError: `spec.matchConditions[0].name: Required value`, + }, + { + name: "match condition with parameters allowed", + config: &admissionregistration.ValidatingAdmissionPolicy{ + ObjectMeta: metav1.ObjectMeta{ + Name: "config", + }, + Spec: admissionregistration.ValidatingAdmissionPolicySpec{ + ParamKind: &admissionregistration.ParamKind{ + Kind: "Foo", + APIVersion: "foobar/v1alpha1", + }, + MatchConstraints: &admissionregistration.MatchResources{ + ResourceRules: []admissionregistration.NamedRuleWithOperations{ + { + RuleWithOperations: admissionregistration.RuleWithOperations{ + Operations: []admissionregistration.OperationType{"*"}, + Rule: admissionregistration.Rule{ + APIGroups: []string{"a"}, + APIVersions: []string{"a"}, + Resources: []string{"a"}, + }, + }, + }, + }, + NamespaceSelector: &metav1.LabelSelector{ + MatchLabels: map[string]string{"a": "b"}, + }, + ObjectSelector: &metav1.LabelSelector{ + MatchLabels: map[string]string{"a": "b"}, + }, + MatchPolicy: func() *admissionregistration.MatchPolicyType { + r := admissionregistration.MatchPolicyType("Exact") + return &r + }(), + }, + FailurePolicy: func() *admissionregistration.FailurePolicyType { + r := admissionregistration.FailurePolicyType("Fail") + return &r + }(), + MatchConditions: []admissionregistration.MatchCondition{ + { + Name: "hasParams", + Expression: `params.foo == "okay"`, + }, + }, + Validations: []admissionregistration.Validation{ + { + Expression: "object.x < 100", + }, + }, + }, + }, + expectedError: "", + }, + { + name: "match condition with parameters not allowed if no param kind", + config: &admissionregistration.ValidatingAdmissionPolicy{ + ObjectMeta: metav1.ObjectMeta{ + Name: "config", + }, + Spec: admissionregistration.ValidatingAdmissionPolicySpec{ + MatchConstraints: &admissionregistration.MatchResources{ + ResourceRules: []admissionregistration.NamedRuleWithOperations{ + { + RuleWithOperations: admissionregistration.RuleWithOperations{ + Operations: []admissionregistration.OperationType{"*"}, + Rule: admissionregistration.Rule{ + APIGroups: []string{"a"}, + APIVersions: []string{"a"}, + Resources: []string{"a"}, + }, + }, + }, + }, + NamespaceSelector: &metav1.LabelSelector{ + MatchLabels: map[string]string{"a": "b"}, + }, + ObjectSelector: &metav1.LabelSelector{ + MatchLabels: map[string]string{"a": "b"}, + }, + MatchPolicy: func() *admissionregistration.MatchPolicyType { + r := admissionregistration.MatchPolicyType("Exact") + return &r + }(), + }, + FailurePolicy: func() *admissionregistration.FailurePolicyType { + r := admissionregistration.FailurePolicyType("Fail") + return &r + }(), + MatchConditions: []admissionregistration.MatchCondition{ + { + Name: "hasParams", + Expression: `params.foo == "okay"`, + }, + }, + Validations: []admissionregistration.Validation{ + { + Expression: "object.x < 100", + }, + }, + }, + }, + expectedError: `undeclared reference to 'params'`, + }, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { @@ -3293,6 +3418,202 @@ func TestValidateValidatingAdmissionPolicyUpdate(t *testing.T) { Spec: admissionregistration.ValidatingAdmissionPolicySpec{}, }, }, + { + name: "match conditions re-checked if paramKind changes", + oldconfig: &admissionregistration.ValidatingAdmissionPolicy{ + ObjectMeta: metav1.ObjectMeta{ + Name: "config", + }, + Spec: admissionregistration.ValidatingAdmissionPolicySpec{ + ParamKind: &admissionregistration.ParamKind{ + Kind: "Foo", + APIVersion: "foobar/v1alpha1", + }, + MatchConstraints: &admissionregistration.MatchResources{ + ResourceRules: []admissionregistration.NamedRuleWithOperations{ + { + RuleWithOperations: admissionregistration.RuleWithOperations{ + Operations: []admissionregistration.OperationType{"*"}, + Rule: admissionregistration.Rule{ + APIGroups: []string{"a"}, + APIVersions: []string{"a"}, + Resources: []string{"a"}, + }, + }, + }, + }, + NamespaceSelector: &metav1.LabelSelector{ + MatchLabels: map[string]string{"a": "b"}, + }, + ObjectSelector: &metav1.LabelSelector{ + MatchLabels: map[string]string{"a": "b"}, + }, + MatchPolicy: func() *admissionregistration.MatchPolicyType { + r := admissionregistration.MatchPolicyType("Exact") + return &r + }(), + }, + FailurePolicy: func() *admissionregistration.FailurePolicyType { + r := admissionregistration.FailurePolicyType("Fail") + return &r + }(), + MatchConditions: []admissionregistration.MatchCondition{ + { + Name: "hasParams", + Expression: `params.foo == "okay"`, + }, + }, + Validations: []admissionregistration.Validation{ + { + Expression: "object.x < 100", + }, + }, + }, + }, + config: &admissionregistration.ValidatingAdmissionPolicy{ + ObjectMeta: metav1.ObjectMeta{ + Name: "config", + }, + Spec: admissionregistration.ValidatingAdmissionPolicySpec{ + MatchConstraints: &admissionregistration.MatchResources{ + ResourceRules: []admissionregistration.NamedRuleWithOperations{ + { + RuleWithOperations: admissionregistration.RuleWithOperations{ + Operations: []admissionregistration.OperationType{"*"}, + Rule: admissionregistration.Rule{ + APIGroups: []string{"a"}, + APIVersions: []string{"a"}, + Resources: []string{"a"}, + }, + }, + }, + }, + NamespaceSelector: &metav1.LabelSelector{ + MatchLabels: map[string]string{"a": "b"}, + }, + ObjectSelector: &metav1.LabelSelector{ + MatchLabels: map[string]string{"a": "b"}, + }, + MatchPolicy: func() *admissionregistration.MatchPolicyType { + r := admissionregistration.MatchPolicyType("Exact") + return &r + }(), + }, + FailurePolicy: func() *admissionregistration.FailurePolicyType { + r := admissionregistration.FailurePolicyType("Fail") + return &r + }(), + MatchConditions: []admissionregistration.MatchCondition{ + { + Name: "hasParams", + Expression: `params.foo == "okay"`, + }, + }, + Validations: []admissionregistration.Validation{ + { + Expression: "object.x < 100", + }, + }, + }, + }, + expectedError: `undeclared reference to 'params'`, + }, + { + name: "match conditions not re-checked if no change to paramKind or matchConditions", + oldconfig: &admissionregistration.ValidatingAdmissionPolicy{ + ObjectMeta: metav1.ObjectMeta{ + Name: "config", + }, + Spec: admissionregistration.ValidatingAdmissionPolicySpec{ + MatchConstraints: &admissionregistration.MatchResources{ + ResourceRules: []admissionregistration.NamedRuleWithOperations{ + { + RuleWithOperations: admissionregistration.RuleWithOperations{ + Operations: []admissionregistration.OperationType{"*"}, + Rule: admissionregistration.Rule{ + APIGroups: []string{"a"}, + APIVersions: []string{"a"}, + Resources: []string{"a"}, + }, + }, + }, + }, + NamespaceSelector: &metav1.LabelSelector{ + MatchLabels: map[string]string{"a": "b"}, + }, + ObjectSelector: &metav1.LabelSelector{ + MatchLabels: map[string]string{"a": "b"}, + }, + MatchPolicy: func() *admissionregistration.MatchPolicyType { + r := admissionregistration.MatchPolicyType("Exact") + return &r + }(), + }, + FailurePolicy: func() *admissionregistration.FailurePolicyType { + r := admissionregistration.FailurePolicyType("Fail") + return &r + }(), + MatchConditions: []admissionregistration.MatchCondition{ + { + Name: "hasParams", + Expression: `params.foo == "okay"`, + }, + }, + Validations: []admissionregistration.Validation{ + { + Expression: "object.x < 100", + }, + }, + }, + }, + config: &admissionregistration.ValidatingAdmissionPolicy{ + ObjectMeta: metav1.ObjectMeta{ + Name: "config", + }, + Spec: admissionregistration.ValidatingAdmissionPolicySpec{ + MatchConstraints: &admissionregistration.MatchResources{ + ResourceRules: []admissionregistration.NamedRuleWithOperations{ + { + RuleWithOperations: admissionregistration.RuleWithOperations{ + Operations: []admissionregistration.OperationType{"*"}, + Rule: admissionregistration.Rule{ + APIGroups: []string{"a"}, + APIVersions: []string{"a"}, + Resources: []string{"a"}, + }, + }, + }, + }, + NamespaceSelector: &metav1.LabelSelector{ + MatchLabels: map[string]string{"a": "b"}, + }, + ObjectSelector: &metav1.LabelSelector{ + MatchLabels: map[string]string{"a": "b"}, + }, + MatchPolicy: func() *admissionregistration.MatchPolicyType { + r := admissionregistration.MatchPolicyType("Exact") + return &r + }(), + }, + FailurePolicy: func() *admissionregistration.FailurePolicyType { + r := admissionregistration.FailurePolicyType("Ignore") + return &r + }(), + MatchConditions: []admissionregistration.MatchCondition{ + { + Name: "hasParams", + Expression: `params.foo == "okay"`, + }, + }, + Validations: []admissionregistration.Validation{ + { + Expression: "object.x < 50", + }, + }, + }, + }, + expectedError: "", + }, // TODO: CustomAuditAnnotations: string valueExpression with {oldObject} is allowed } for _, test := range tests { diff --git a/pkg/apis/admissionregistration/zz_generated.deepcopy.go b/pkg/apis/admissionregistration/zz_generated.deepcopy.go index 5c2250b4d1f..179ec47171a 100644 --- a/pkg/apis/admissionregistration/zz_generated.deepcopy.go +++ b/pkg/apis/admissionregistration/zz_generated.deepcopy.go @@ -580,6 +580,11 @@ func (in *ValidatingAdmissionPolicySpec) DeepCopyInto(out *ValidatingAdmissionPo (*in)[i].DeepCopyInto(&(*out)[i]) } } + if in.MatchConditions != nil { + in, out := &in.MatchConditions, &out.MatchConditions + *out = make([]MatchCondition, len(*in)) + copy(*out, *in) + } if in.FailurePolicy != nil { in, out := &in.FailurePolicy, &out.FailurePolicy *out = new(FailurePolicyType) diff --git a/pkg/generated/openapi/zz_generated.openapi.go b/pkg/generated/openapi/zz_generated.openapi.go index 48bf8ee50df..b13b88c4854 100644 --- a/pkg/generated/openapi/zz_generated.openapi.go +++ b/pkg/generated/openapi/zz_generated.openapi.go @@ -48,6 +48,7 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA "k8s.io/api/admissionregistration/v1.WebhookClientConfig": schema_k8sio_api_admissionregistration_v1_WebhookClientConfig(ref), "k8s.io/api/admissionregistration/v1alpha1.AuditAnnotation": schema_k8sio_api_admissionregistration_v1alpha1_AuditAnnotation(ref), "k8s.io/api/admissionregistration/v1alpha1.ExpressionWarning": schema_k8sio_api_admissionregistration_v1alpha1_ExpressionWarning(ref), + "k8s.io/api/admissionregistration/v1alpha1.MatchCondition": schema_k8sio_api_admissionregistration_v1alpha1_MatchCondition(ref), "k8s.io/api/admissionregistration/v1alpha1.MatchResources": schema_k8sio_api_admissionregistration_v1alpha1_MatchResources(ref), "k8s.io/api/admissionregistration/v1alpha1.NamedRuleWithOperations": schema_k8sio_api_admissionregistration_v1alpha1_NamedRuleWithOperations(ref), "k8s.io/api/admissionregistration/v1alpha1.ParamKind": schema_k8sio_api_admissionregistration_v1alpha1_ParamKind(ref), @@ -2008,6 +2009,35 @@ func schema_k8sio_api_admissionregistration_v1alpha1_ExpressionWarning(ref commo } } +func schema_k8sio_api_admissionregistration_v1alpha1_MatchCondition(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "name": { + SchemaProps: spec.SchemaProps{ + Description: "Name is an identifier for this match condition, used for strategic merging of MatchConditions, as well as providing an identifier for logging purposes. A good name should be descriptive of the associated expression. Name must be a qualified name consisting of alphanumeric characters, '-', '_' or '.', and must start and end with an alphanumeric character (e.g. 'MyName', or 'my.name', or '123-abc', regex used for validation is '([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9]') with an optional DNS subdomain prefix and '/' (e.g. 'example.com/MyName')\n\nRequired.", + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + "expression": { + SchemaProps: spec.SchemaProps{ + Description: "Expression represents the expression which will be evaluated by CEL. Must evaluate to bool. CEL expressions have access to the contents of the AdmissionRequest and Authorizer, organized into CEL variables:\n\n'object' - The object from the incoming request. The value is null for DELETE requests. 'oldObject' - The existing object. The value is null for CREATE requests. 'request' - Attributes of the admission request(/pkg/apis/admission/types.go#AdmissionRequest). 'authorizer' - A CEL Authorizer. May be used to perform authorization checks for the principal (user or service account) of the request.\n See https://pkg.go.dev/k8s.io/apiserver/pkg/cel/library#Authz\n'authorizer.requestResource' - A CEL ResourceCheck constructed from the 'authorizer' and configured with the\n request resource.\nDocumentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/\n\nRequired.", + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, + Required: []string{"name", "expression"}, + }, + }, + } +} + func schema_k8sio_api_admissionregistration_v1alpha1_MatchResources(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ @@ -2621,11 +2651,35 @@ func schema_k8sio_api_admissionregistration_v1alpha1_ValidatingAdmissionPolicySp }, }, }, + "matchConditions": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-map-keys": []interface{}{ + "name", + }, + "x-kubernetes-list-type": "map", + "x-kubernetes-patch-merge-key": "name", + "x-kubernetes-patch-strategy": "merge", + }, + }, + SchemaProps: spec.SchemaProps{ + Description: "MatchConditions is a list of conditions that must be met for a request to be validated. Match conditions filter requests that have already been matched by the rules, namespaceSelector, and objectSelector. An empty list of matchConditions matches all requests. There are a maximum of 64 match conditions allowed.\n\nIf a parameter object is provided, it can be accessed via the `params` handle in the same manner as validation expressions.\n\nThe exact matching logic is (in order):\n 1. If ANY matchCondition evaluates to FALSE, the policy is skipped.\n 2. If ALL matchConditions evaluate to TRUE, the policy is evaluated.\n 3. If any matchCondition evaluates to an error (but none are FALSE):\n - If failurePolicy=Fail, reject the request\n - If failurePolicy=Ignore, the policy is skipped", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("k8s.io/api/admissionregistration/v1alpha1.MatchCondition"), + }, + }, + }, + }, + }, }, }, }, Dependencies: []string{ - "k8s.io/api/admissionregistration/v1alpha1.AuditAnnotation", "k8s.io/api/admissionregistration/v1alpha1.MatchResources", "k8s.io/api/admissionregistration/v1alpha1.ParamKind", "k8s.io/api/admissionregistration/v1alpha1.Validation"}, + "k8s.io/api/admissionregistration/v1alpha1.AuditAnnotation", "k8s.io/api/admissionregistration/v1alpha1.MatchCondition", "k8s.io/api/admissionregistration/v1alpha1.MatchResources", "k8s.io/api/admissionregistration/v1alpha1.ParamKind", "k8s.io/api/admissionregistration/v1alpha1.Validation"}, } } diff --git a/staging/src/k8s.io/api/admissionregistration/v1alpha1/generated.pb.go b/staging/src/k8s.io/api/admissionregistration/v1alpha1/generated.pb.go index 5f37a6416f4..7465350263b 100644 --- a/staging/src/k8s.io/api/admissionregistration/v1alpha1/generated.pb.go +++ b/staging/src/k8s.io/api/admissionregistration/v1alpha1/generated.pb.go @@ -101,10 +101,38 @@ func (m *ExpressionWarning) XXX_DiscardUnknown() { var xxx_messageInfo_ExpressionWarning proto.InternalMessageInfo +func (m *MatchCondition) Reset() { *m = MatchCondition{} } +func (*MatchCondition) ProtoMessage() {} +func (*MatchCondition) Descriptor() ([]byte, []int) { + return fileDescriptor_c3be8d256e3ae3cf, []int{2} +} +func (m *MatchCondition) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MatchCondition) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil +} +func (m *MatchCondition) XXX_Merge(src proto.Message) { + xxx_messageInfo_MatchCondition.Merge(m, src) +} +func (m *MatchCondition) XXX_Size() int { + return m.Size() +} +func (m *MatchCondition) XXX_DiscardUnknown() { + xxx_messageInfo_MatchCondition.DiscardUnknown(m) +} + +var xxx_messageInfo_MatchCondition proto.InternalMessageInfo + func (m *MatchResources) Reset() { *m = MatchResources{} } func (*MatchResources) ProtoMessage() {} func (*MatchResources) Descriptor() ([]byte, []int) { - return fileDescriptor_c3be8d256e3ae3cf, []int{2} + return fileDescriptor_c3be8d256e3ae3cf, []int{3} } func (m *MatchResources) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -132,7 +160,7 @@ var xxx_messageInfo_MatchResources proto.InternalMessageInfo func (m *NamedRuleWithOperations) Reset() { *m = NamedRuleWithOperations{} } func (*NamedRuleWithOperations) ProtoMessage() {} func (*NamedRuleWithOperations) Descriptor() ([]byte, []int) { - return fileDescriptor_c3be8d256e3ae3cf, []int{3} + return fileDescriptor_c3be8d256e3ae3cf, []int{4} } func (m *NamedRuleWithOperations) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -160,7 +188,7 @@ var xxx_messageInfo_NamedRuleWithOperations proto.InternalMessageInfo func (m *ParamKind) Reset() { *m = ParamKind{} } func (*ParamKind) ProtoMessage() {} func (*ParamKind) Descriptor() ([]byte, []int) { - return fileDescriptor_c3be8d256e3ae3cf, []int{4} + return fileDescriptor_c3be8d256e3ae3cf, []int{5} } func (m *ParamKind) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -188,7 +216,7 @@ var xxx_messageInfo_ParamKind proto.InternalMessageInfo func (m *ParamRef) Reset() { *m = ParamRef{} } func (*ParamRef) ProtoMessage() {} func (*ParamRef) Descriptor() ([]byte, []int) { - return fileDescriptor_c3be8d256e3ae3cf, []int{5} + return fileDescriptor_c3be8d256e3ae3cf, []int{6} } func (m *ParamRef) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -216,7 +244,7 @@ var xxx_messageInfo_ParamRef proto.InternalMessageInfo func (m *TypeChecking) Reset() { *m = TypeChecking{} } func (*TypeChecking) ProtoMessage() {} func (*TypeChecking) Descriptor() ([]byte, []int) { - return fileDescriptor_c3be8d256e3ae3cf, []int{6} + return fileDescriptor_c3be8d256e3ae3cf, []int{7} } func (m *TypeChecking) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -244,7 +272,7 @@ var xxx_messageInfo_TypeChecking proto.InternalMessageInfo func (m *ValidatingAdmissionPolicy) Reset() { *m = ValidatingAdmissionPolicy{} } func (*ValidatingAdmissionPolicy) ProtoMessage() {} func (*ValidatingAdmissionPolicy) Descriptor() ([]byte, []int) { - return fileDescriptor_c3be8d256e3ae3cf, []int{7} + return fileDescriptor_c3be8d256e3ae3cf, []int{8} } func (m *ValidatingAdmissionPolicy) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -272,7 +300,7 @@ var xxx_messageInfo_ValidatingAdmissionPolicy proto.InternalMessageInfo func (m *ValidatingAdmissionPolicyBinding) Reset() { *m = ValidatingAdmissionPolicyBinding{} } func (*ValidatingAdmissionPolicyBinding) ProtoMessage() {} func (*ValidatingAdmissionPolicyBinding) Descriptor() ([]byte, []int) { - return fileDescriptor_c3be8d256e3ae3cf, []int{8} + return fileDescriptor_c3be8d256e3ae3cf, []int{9} } func (m *ValidatingAdmissionPolicyBinding) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -300,7 +328,7 @@ var xxx_messageInfo_ValidatingAdmissionPolicyBinding proto.InternalMessageInfo func (m *ValidatingAdmissionPolicyBindingList) Reset() { *m = ValidatingAdmissionPolicyBindingList{} } func (*ValidatingAdmissionPolicyBindingList) ProtoMessage() {} func (*ValidatingAdmissionPolicyBindingList) Descriptor() ([]byte, []int) { - return fileDescriptor_c3be8d256e3ae3cf, []int{9} + return fileDescriptor_c3be8d256e3ae3cf, []int{10} } func (m *ValidatingAdmissionPolicyBindingList) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -328,7 +356,7 @@ var xxx_messageInfo_ValidatingAdmissionPolicyBindingList proto.InternalMessageIn func (m *ValidatingAdmissionPolicyBindingSpec) Reset() { *m = ValidatingAdmissionPolicyBindingSpec{} } func (*ValidatingAdmissionPolicyBindingSpec) ProtoMessage() {} func (*ValidatingAdmissionPolicyBindingSpec) Descriptor() ([]byte, []int) { - return fileDescriptor_c3be8d256e3ae3cf, []int{10} + return fileDescriptor_c3be8d256e3ae3cf, []int{11} } func (m *ValidatingAdmissionPolicyBindingSpec) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -356,7 +384,7 @@ var xxx_messageInfo_ValidatingAdmissionPolicyBindingSpec proto.InternalMessageIn func (m *ValidatingAdmissionPolicyList) Reset() { *m = ValidatingAdmissionPolicyList{} } func (*ValidatingAdmissionPolicyList) ProtoMessage() {} func (*ValidatingAdmissionPolicyList) Descriptor() ([]byte, []int) { - return fileDescriptor_c3be8d256e3ae3cf, []int{11} + return fileDescriptor_c3be8d256e3ae3cf, []int{12} } func (m *ValidatingAdmissionPolicyList) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -384,7 +412,7 @@ var xxx_messageInfo_ValidatingAdmissionPolicyList proto.InternalMessageInfo func (m *ValidatingAdmissionPolicySpec) Reset() { *m = ValidatingAdmissionPolicySpec{} } func (*ValidatingAdmissionPolicySpec) ProtoMessage() {} func (*ValidatingAdmissionPolicySpec) Descriptor() ([]byte, []int) { - return fileDescriptor_c3be8d256e3ae3cf, []int{12} + return fileDescriptor_c3be8d256e3ae3cf, []int{13} } func (m *ValidatingAdmissionPolicySpec) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -412,7 +440,7 @@ var xxx_messageInfo_ValidatingAdmissionPolicySpec proto.InternalMessageInfo func (m *ValidatingAdmissionPolicyStatus) Reset() { *m = ValidatingAdmissionPolicyStatus{} } func (*ValidatingAdmissionPolicyStatus) ProtoMessage() {} func (*ValidatingAdmissionPolicyStatus) Descriptor() ([]byte, []int) { - return fileDescriptor_c3be8d256e3ae3cf, []int{13} + return fileDescriptor_c3be8d256e3ae3cf, []int{14} } func (m *ValidatingAdmissionPolicyStatus) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -440,7 +468,7 @@ var xxx_messageInfo_ValidatingAdmissionPolicyStatus proto.InternalMessageInfo func (m *Validation) Reset() { *m = Validation{} } func (*Validation) ProtoMessage() {} func (*Validation) Descriptor() ([]byte, []int) { - return fileDescriptor_c3be8d256e3ae3cf, []int{14} + return fileDescriptor_c3be8d256e3ae3cf, []int{15} } func (m *Validation) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -468,6 +496,7 @@ var xxx_messageInfo_Validation proto.InternalMessageInfo func init() { proto.RegisterType((*AuditAnnotation)(nil), "k8s.io.api.admissionregistration.v1alpha1.AuditAnnotation") proto.RegisterType((*ExpressionWarning)(nil), "k8s.io.api.admissionregistration.v1alpha1.ExpressionWarning") + proto.RegisterType((*MatchCondition)(nil), "k8s.io.api.admissionregistration.v1alpha1.MatchCondition") proto.RegisterType((*MatchResources)(nil), "k8s.io.api.admissionregistration.v1alpha1.MatchResources") proto.RegisterType((*NamedRuleWithOperations)(nil), "k8s.io.api.admissionregistration.v1alpha1.NamedRuleWithOperations") proto.RegisterType((*ParamKind)(nil), "k8s.io.api.admissionregistration.v1alpha1.ParamKind") @@ -488,93 +517,95 @@ func init() { } var fileDescriptor_c3be8d256e3ae3cf = []byte{ - // 1367 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x58, 0x4b, 0x6f, 0x5b, 0xc5, - 0x17, 0xcf, 0x8d, 0xdd, 0x36, 0x39, 0xce, 0xcb, 0xf3, 0x6f, 0x55, 0x37, 0xfa, 0xd7, 0x8e, 0xae, - 0x2a, 0xd4, 0x48, 0x70, 0x4d, 0xd2, 0x42, 0x01, 0x21, 0xa1, 0xdc, 0xbe, 0xe8, 0x23, 0x4d, 0x34, - 0x45, 0x89, 0x84, 0xa8, 0xc4, 0xe4, 0xde, 0x89, 0x3d, 0xb5, 0xef, 0x83, 0x3b, 0xd7, 0xa1, 0x11, - 0x0b, 0x2a, 0xb1, 0x81, 0x1d, 0x0b, 0x36, 0x7c, 0x19, 0x24, 0x76, 0x5d, 0x76, 0x59, 0x16, 0x58, - 0xd4, 0x6c, 0xf8, 0x04, 0x20, 0x65, 0x03, 0x9a, 0xb9, 0x73, 0x9f, 0x76, 0x88, 0x53, 0x02, 0x3b, - 0xdf, 0xf3, 0xf8, 0xfd, 0xe6, 0x9c, 0x39, 0x73, 0xe6, 0x8c, 0x01, 0x77, 0xde, 0xe1, 0x06, 0xf3, - 0x9a, 0x9d, 0xde, 0x0e, 0x0d, 0x5c, 0x1a, 0x52, 0xde, 0xdc, 0xa3, 0xae, 0xed, 0x05, 0x4d, 0xa5, - 0x20, 0x3e, 0x6b, 0x12, 0xdb, 0x61, 0x9c, 0x33, 0xcf, 0x0d, 0x68, 0x8b, 0xf1, 0x30, 0x20, 0x21, - 0xf3, 0xdc, 0xe6, 0xde, 0x0a, 0xe9, 0xfa, 0x6d, 0xb2, 0xd2, 0x6c, 0x51, 0x97, 0x06, 0x24, 0xa4, - 0xb6, 0xe1, 0x07, 0x5e, 0xe8, 0xa1, 0xe5, 0xc8, 0xd5, 0x20, 0x3e, 0x33, 0x46, 0xba, 0x1a, 0xb1, - 0xeb, 0xe2, 0x1b, 0x2d, 0x16, 0xb6, 0x7b, 0x3b, 0x86, 0xe5, 0x39, 0xcd, 0x96, 0xd7, 0xf2, 0x9a, - 0x12, 0x61, 0xa7, 0xb7, 0x2b, 0xbf, 0xe4, 0x87, 0xfc, 0x15, 0x21, 0x2f, 0x5e, 0x19, 0x63, 0x51, - 0xc5, 0xe5, 0x2c, 0x5e, 0x4d, 0x9d, 0x1c, 0x62, 0xb5, 0x99, 0x4b, 0x83, 0xfd, 0xa6, 0xdf, 0x69, - 0x09, 0x01, 0x6f, 0x3a, 0x34, 0x24, 0xa3, 0xbc, 0x9a, 0x87, 0x79, 0x05, 0x3d, 0x37, 0x64, 0x0e, - 0x1d, 0x72, 0x78, 0xfb, 0x28, 0x07, 0x6e, 0xb5, 0xa9, 0x43, 0x8a, 0x7e, 0x3a, 0x87, 0xf9, 0xb5, - 0x9e, 0xcd, 0xc2, 0x35, 0xd7, 0xf5, 0x42, 0x19, 0x04, 0xba, 0x08, 0xa5, 0x0e, 0xdd, 0xaf, 0x69, - 0x4b, 0xda, 0xe5, 0x69, 0xb3, 0xf2, 0xac, 0xdf, 0x98, 0x18, 0xf4, 0x1b, 0xa5, 0x7b, 0x74, 0x1f, - 0x0b, 0x39, 0x5a, 0x83, 0xf9, 0x3d, 0xd2, 0xed, 0xd1, 0x9b, 0x4f, 0xfc, 0x80, 0xca, 0x14, 0xd4, - 0x26, 0xa5, 0xe9, 0x79, 0x65, 0x3a, 0xbf, 0x95, 0x57, 0xe3, 0xa2, 0xbd, 0xde, 0x85, 0x6a, 0xfa, - 0xb5, 0x4d, 0x02, 0x97, 0xb9, 0x2d, 0xf4, 0x3a, 0x4c, 0xed, 0x32, 0xda, 0xb5, 0x31, 0xdd, 0x55, - 0x80, 0x0b, 0x0a, 0x70, 0xea, 0x96, 0x92, 0xe3, 0xc4, 0x02, 0x2d, 0xc3, 0x99, 0xcf, 0x23, 0xc7, - 0x5a, 0x49, 0x1a, 0xcf, 0x2b, 0xe3, 0x33, 0x0a, 0x0f, 0xc7, 0x7a, 0xfd, 0xa7, 0x32, 0xcc, 0xad, - 0x93, 0xd0, 0x6a, 0x63, 0xca, 0xbd, 0x5e, 0x60, 0x51, 0x8e, 0x9e, 0x40, 0xd5, 0x25, 0x0e, 0xe5, - 0x3e, 0xb1, 0xe8, 0x43, 0xda, 0xa5, 0x56, 0xe8, 0x05, 0x32, 0xe0, 0xca, 0xea, 0x15, 0x23, 0xad, - 0x9f, 0x24, 0x93, 0x86, 0xdf, 0x69, 0x09, 0x01, 0x37, 0xc4, 0x86, 0x19, 0x7b, 0x2b, 0xc6, 0x7d, - 0xb2, 0x43, 0xbb, 0xb1, 0xab, 0x79, 0x6e, 0xd0, 0x6f, 0x54, 0x1f, 0x14, 0x11, 0xf1, 0x30, 0x09, - 0xf2, 0x60, 0xce, 0xdb, 0x79, 0x4c, 0xad, 0x30, 0xa1, 0x9d, 0x7c, 0x75, 0x5a, 0x34, 0xe8, 0x37, - 0xe6, 0x36, 0x72, 0x70, 0xb8, 0x00, 0x8f, 0xbe, 0x84, 0xd9, 0x40, 0xc5, 0x8d, 0x7b, 0x5d, 0xca, - 0x6b, 0xa5, 0xa5, 0xd2, 0xe5, 0xca, 0xaa, 0x69, 0x8c, 0x7d, 0x4c, 0x0c, 0x11, 0x98, 0x2d, 0x9c, - 0xb7, 0x59, 0xd8, 0xde, 0xf0, 0x69, 0xa4, 0xe7, 0xe6, 0x39, 0x95, 0xf2, 0x59, 0x9c, 0x25, 0xc0, - 0x79, 0x3e, 0xf4, 0x9d, 0x06, 0x67, 0xe9, 0x13, 0xab, 0xdb, 0xb3, 0x69, 0xce, 0xae, 0x56, 0x3e, - 0xb1, 0x85, 0xfc, 0x5f, 0x2d, 0xe4, 0xec, 0xcd, 0x11, 0x3c, 0x78, 0x24, 0x3b, 0xba, 0x01, 0x15, - 0x47, 0x14, 0xc5, 0xa6, 0xd7, 0x65, 0xd6, 0x7e, 0xed, 0x8c, 0x2c, 0x22, 0x7d, 0xd0, 0x6f, 0x54, - 0xd6, 0x53, 0xf1, 0x41, 0xbf, 0x31, 0x9f, 0xf9, 0xfc, 0x68, 0xdf, 0xa7, 0x38, 0xeb, 0xa6, 0xbf, - 0xd0, 0xe0, 0xfc, 0x21, 0xab, 0x42, 0xd7, 0xd2, 0xcc, 0xcb, 0xd2, 0xa8, 0x69, 0x4b, 0xa5, 0xcb, - 0xd3, 0x66, 0x35, 0x9b, 0x31, 0xa9, 0xc0, 0x79, 0x3b, 0xf4, 0x95, 0x06, 0x28, 0x18, 0xc2, 0x53, - 0x85, 0x72, 0x6d, 0x9c, 0x7c, 0x19, 0x23, 0x92, 0xb4, 0xa8, 0x92, 0x84, 0x86, 0x75, 0x78, 0x04, - 0x9d, 0x4e, 0x60, 0x7a, 0x93, 0x04, 0xc4, 0xb9, 0xc7, 0x5c, 0x1b, 0xad, 0x02, 0x10, 0x9f, 0x6d, - 0xd1, 0x40, 0x9e, 0xf7, 0xa8, 0x35, 0x20, 0x05, 0x08, 0x6b, 0x9b, 0x77, 0x94, 0x06, 0x67, 0xac, - 0xd0, 0x12, 0x94, 0x3b, 0xcc, 0xb5, 0xd5, 0x61, 0x9e, 0x51, 0xd6, 0x65, 0x81, 0x87, 0xa5, 0x46, - 0x7f, 0x04, 0x53, 0x92, 0x42, 0x1c, 0xe8, 0x25, 0x28, 0x8b, 0xd3, 0xa2, 0xb0, 0x13, 0x6b, 0x91, - 0x11, 0x2c, 0x35, 0xa8, 0x09, 0xd3, 0xc9, 0x79, 0x52, 0xa0, 0x55, 0x65, 0x36, 0x9d, 0x9c, 0x3d, - 0x9c, 0xda, 0xe8, 0xdf, 0x6b, 0x30, 0x23, 0xb6, 0xec, 0x7a, 0x9b, 0x5a, 0x1d, 0xd1, 0x62, 0xbe, - 0xd6, 0x00, 0xd1, 0x62, 0xe3, 0x89, 0xf6, 0xa5, 0xb2, 0xfa, 0xfe, 0x31, 0x0a, 0x71, 0xa8, 0x7b, - 0xa5, 0xd9, 0x1d, 0x52, 0x71, 0x3c, 0x82, 0x53, 0xff, 0x79, 0x12, 0x2e, 0x6c, 0x91, 0x2e, 0xb3, - 0x49, 0xc8, 0xdc, 0xd6, 0x5a, 0x4c, 0x17, 0x95, 0x15, 0xfa, 0x14, 0xa6, 0xc4, 0x89, 0xb7, 0x49, - 0x48, 0x54, 0x5b, 0x7a, 0x73, 0xbc, 0xfe, 0x10, 0x35, 0x83, 0x75, 0x1a, 0x92, 0x74, 0x7b, 0x52, - 0x19, 0x4e, 0x50, 0xd1, 0x63, 0x28, 0x73, 0x9f, 0x5a, 0xaa, 0xa8, 0x3e, 0x3c, 0x46, 0xec, 0x87, - 0xae, 0xfa, 0xa1, 0x4f, 0xad, 0x74, 0xe3, 0xc4, 0x17, 0x96, 0x1c, 0x28, 0x80, 0xd3, 0x3c, 0x24, - 0x61, 0x8f, 0xcb, 0x56, 0x5d, 0x59, 0xbd, 0x7b, 0x22, 0x6c, 0x12, 0xd1, 0x9c, 0x53, 0x7c, 0xa7, - 0xa3, 0x6f, 0xac, 0x98, 0xf4, 0x3f, 0x34, 0x58, 0x3a, 0xd4, 0xd7, 0x64, 0xae, 0x2d, 0xea, 0xe1, - 0xdf, 0x4f, 0xf3, 0x67, 0xb9, 0x34, 0x6f, 0x9c, 0x44, 0xe0, 0x6a, 0xf1, 0x87, 0x65, 0x5b, 0xff, - 0x5d, 0x83, 0x4b, 0x47, 0x39, 0xdf, 0x67, 0x3c, 0x44, 0x9f, 0x0c, 0x45, 0x6f, 0x8c, 0x79, 0x09, - 0x31, 0x1e, 0xc5, 0x9e, 0x5c, 0xd0, 0xb1, 0x24, 0x13, 0xb9, 0x0f, 0xa7, 0x58, 0x48, 0x1d, 0xd1, - 0xb6, 0xc4, 0xe9, 0xba, 0x77, 0x82, 0xa1, 0x9b, 0xb3, 0x8a, 0xf7, 0xd4, 0x1d, 0xc1, 0x80, 0x23, - 0x22, 0xfd, 0x9b, 0xd2, 0xd1, 0x81, 0x8b, 0x3c, 0x89, 0x66, 0xe6, 0x4b, 0xe1, 0x83, 0xb4, 0xe1, - 0x24, 0xdb, 0xb8, 0x99, 0x68, 0x70, 0xc6, 0x0a, 0x3d, 0x82, 0x29, 0x5f, 0xb5, 0xaa, 0x11, 0x37, - 0xf6, 0x51, 0x11, 0xc5, 0x5d, 0xce, 0x9c, 0x11, 0xd9, 0x8a, 0xbf, 0x70, 0x02, 0x89, 0x7a, 0x30, - 0xe7, 0xe4, 0x46, 0x14, 0x75, 0x54, 0xde, 0x3d, 0x06, 0x49, 0x7e, 0xc6, 0x89, 0x86, 0x83, 0xbc, - 0x0c, 0x17, 0x48, 0xd0, 0x36, 0x54, 0xf7, 0x54, 0xc6, 0x3c, 0x77, 0xcd, 0x8a, 0xee, 0x99, 0xb2, - 0xbc, 0xa6, 0x96, 0xc5, 0x48, 0xb3, 0x55, 0x54, 0x1e, 0xf4, 0x1b, 0x0b, 0x45, 0x21, 0x1e, 0xc6, - 0xd0, 0x7f, 0xd3, 0xe0, 0xe2, 0xa1, 0x7b, 0xf1, 0x1f, 0x54, 0x1f, 0xcb, 0x57, 0xdf, 0x8d, 0x13, - 0xa9, 0xbe, 0xd1, 0x65, 0xf7, 0x43, 0xf9, 0x6f, 0x42, 0x95, 0xf5, 0x46, 0x60, 0xda, 0x8f, 0x6f, - 0x52, 0x15, 0xeb, 0xd5, 0xe3, 0x16, 0x8f, 0xf0, 0x35, 0x67, 0xc5, 0x55, 0x97, 0x7c, 0xe2, 0x14, - 0x15, 0x7d, 0x01, 0x0b, 0x72, 0x6b, 0xaf, 0x7b, 0xae, 0x00, 0x60, 0x6e, 0x18, 0xcf, 0x0b, 0xff, - 0xa0, 0x82, 0xce, 0x0e, 0xfa, 0x8d, 0x85, 0xf5, 0x02, 0x2c, 0x1e, 0x22, 0x42, 0x5d, 0xa8, 0xa4, - 0x15, 0x10, 0x0f, 0x98, 0x6f, 0xbd, 0x42, 0xca, 0x3d, 0xd7, 0xfc, 0x9f, 0xca, 0x71, 0x25, 0x95, - 0x71, 0x9c, 0x85, 0x47, 0xf7, 0x61, 0x76, 0x97, 0xb0, 0x6e, 0x2f, 0xa0, 0x6a, 0x74, 0x2b, 0xcb, - 0x03, 0xfc, 0x9a, 0x18, 0xab, 0x6e, 0x65, 0x15, 0x07, 0xfd, 0x46, 0x35, 0x27, 0x90, 0xe3, 0x5b, - 0xde, 0x19, 0x3d, 0xd5, 0x60, 0x81, 0xe4, 0x1f, 0x40, 0xbc, 0x76, 0x4a, 0x46, 0xf0, 0xde, 0x31, - 0x22, 0x28, 0xbc, 0xa1, 0xcc, 0x9a, 0x0a, 0x63, 0xa1, 0xa0, 0xe0, 0x78, 0x88, 0x4d, 0xff, 0x71, - 0x12, 0x1a, 0x47, 0x5c, 0x73, 0xe8, 0x2e, 0x20, 0x6f, 0x87, 0xd3, 0x60, 0x8f, 0xda, 0xb7, 0xa3, - 0x17, 0x5c, 0x3c, 0x87, 0x95, 0xd2, 0xd1, 0x63, 0x63, 0xc8, 0x02, 0x8f, 0xf0, 0x42, 0x0e, 0xcc, - 0x84, 0x99, 0xa9, 0xe8, 0x38, 0x73, 0xa5, 0x8a, 0x36, 0x3b, 0x54, 0x99, 0x0b, 0x83, 0x7e, 0x23, - 0x37, 0x66, 0xe1, 0x1c, 0x3c, 0xb2, 0x00, 0x2c, 0xcf, 0xb5, 0x59, 0xb6, 0x38, 0x9a, 0xe3, 0x1d, - 0xf5, 0xeb, 0xb1, 0x5f, 0xda, 0x9e, 0x13, 0x11, 0xc7, 0x19, 0x58, 0xfd, 0x4f, 0x0d, 0x20, 0xad, - 0x18, 0x74, 0x09, 0x20, 0xf3, 0x3c, 0x8d, 0x3a, 0x7c, 0x59, 0x40, 0xe0, 0x8c, 0x5c, 0xbc, 0x21, - 0x1d, 0xca, 0x39, 0x69, 0xc5, 0xe3, 0x64, 0xf2, 0x86, 0x5c, 0x8f, 0xc4, 0x38, 0xd6, 0xa3, 0x6d, - 0x38, 0x1d, 0x50, 0xc2, 0x3d, 0x57, 0xbd, 0x36, 0x3f, 0x10, 0x23, 0x07, 0x96, 0x92, 0x83, 0x7e, - 0x63, 0x65, 0x9c, 0x37, 0xbe, 0xa1, 0x26, 0x14, 0xe9, 0x84, 0x15, 0x1c, 0xba, 0x0d, 0x55, 0xc5, - 0x91, 0x59, 0x70, 0x54, 0xd1, 0x17, 0xd4, 0x6a, 0xaa, 0xeb, 0x45, 0x03, 0x3c, 0xec, 0x63, 0x6e, - 0x3c, 0x7b, 0x59, 0x9f, 0x78, 0xfe, 0xb2, 0x3e, 0xf1, 0xe2, 0x65, 0x7d, 0xe2, 0xe9, 0xa0, 0xae, - 0x3d, 0x1b, 0xd4, 0xb5, 0xe7, 0x83, 0xba, 0xf6, 0x62, 0x50, 0xd7, 0x7e, 0x19, 0xd4, 0xb5, 0x6f, - 0x7f, 0xad, 0x4f, 0x7c, 0xbc, 0x3c, 0xf6, 0xff, 0x2a, 0x7f, 0x05, 0x00, 0x00, 0xff, 0xff, 0xc3, - 0xd9, 0x66, 0xdd, 0x9c, 0x11, 0x00, 0x00, + // 1407 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x58, 0xcb, 0x6f, 0x1b, 0x45, + 0x18, 0xcf, 0xc6, 0x4e, 0x9a, 0x8c, 0xf3, 0xb0, 0x87, 0x56, 0x75, 0x23, 0x6a, 0x47, 0xab, 0x0a, + 0x35, 0x12, 0xec, 0x92, 0xb4, 0x50, 0x40, 0x48, 0x28, 0xdb, 0x17, 0x7d, 0xa4, 0x89, 0xa6, 0x28, + 0x91, 0x10, 0x95, 0x98, 0xec, 0x4e, 0xec, 0xa9, 0xbd, 0x0f, 0x76, 0xd6, 0xa1, 0x11, 0x48, 0x54, + 0xe2, 0x02, 0x37, 0x0e, 0x5c, 0xf8, 0x5f, 0xb8, 0x70, 0xeb, 0xb1, 0xc7, 0x72, 0xc0, 0x22, 0xe6, + 0xc2, 0x5f, 0x00, 0x52, 0x2e, 0xa0, 0x99, 0x9d, 0x7d, 0x3b, 0xc4, 0x2e, 0x81, 0x9b, 0xf7, 0x7b, + 0xfc, 0x7e, 0xf3, 0x7d, 0xf3, 0x7d, 0x33, 0xdf, 0x18, 0xa0, 0xce, 0x3b, 0x4c, 0xa3, 0xae, 0xde, + 0xe9, 0xed, 0x12, 0xdf, 0x21, 0x01, 0x61, 0xfa, 0x3e, 0x71, 0x2c, 0xd7, 0xd7, 0xa5, 0x02, 0x7b, + 0x54, 0xc7, 0x96, 0x4d, 0x19, 0xa3, 0xae, 0xe3, 0x93, 0x16, 0x65, 0x81, 0x8f, 0x03, 0xea, 0x3a, + 0xfa, 0xfe, 0x2a, 0xee, 0x7a, 0x6d, 0xbc, 0xaa, 0xb7, 0x88, 0x43, 0x7c, 0x1c, 0x10, 0x4b, 0xf3, + 0x7c, 0x37, 0x70, 0xe1, 0x4a, 0xe8, 0xaa, 0x61, 0x8f, 0x6a, 0x43, 0x5d, 0xb5, 0xc8, 0x75, 0xe9, + 0x8d, 0x16, 0x0d, 0xda, 0xbd, 0x5d, 0xcd, 0x74, 0x6d, 0xbd, 0xe5, 0xb6, 0x5c, 0x5d, 0x20, 0xec, + 0xf6, 0xf6, 0xc4, 0x97, 0xf8, 0x10, 0xbf, 0x42, 0xe4, 0xa5, 0x2b, 0x23, 0x2c, 0x2a, 0xbf, 0x9c, + 0xa5, 0xab, 0x89, 0x93, 0x8d, 0xcd, 0x36, 0x75, 0x88, 0x7f, 0xa0, 0x7b, 0x9d, 0x16, 0x17, 0x30, + 0xdd, 0x26, 0x01, 0x1e, 0xe6, 0xa5, 0x1f, 0xe7, 0xe5, 0xf7, 0x9c, 0x80, 0xda, 0xa4, 0xe0, 0xf0, + 0xf6, 0x49, 0x0e, 0xcc, 0x6c, 0x13, 0x1b, 0xe7, 0xfd, 0x54, 0x06, 0x16, 0xd7, 0x7b, 0x16, 0x0d, + 0xd6, 0x1d, 0xc7, 0x0d, 0x44, 0x10, 0xf0, 0x22, 0x28, 0x75, 0xc8, 0x41, 0x5d, 0x59, 0x56, 0x2e, + 0xcf, 0x1a, 0x95, 0x67, 0xfd, 0xe6, 0xc4, 0xa0, 0xdf, 0x2c, 0xdd, 0x23, 0x07, 0x88, 0xcb, 0xe1, + 0x3a, 0x58, 0xdc, 0xc7, 0xdd, 0x1e, 0xb9, 0xf9, 0xc4, 0xf3, 0x89, 0x48, 0x41, 0x7d, 0x52, 0x98, + 0x9e, 0x97, 0xa6, 0x8b, 0xdb, 0x59, 0x35, 0xca, 0xdb, 0xab, 0x5d, 0x50, 0x4b, 0xbe, 0x76, 0xb0, + 0xef, 0x50, 0xa7, 0x05, 0x5f, 0x07, 0x33, 0x7b, 0x94, 0x74, 0x2d, 0x44, 0xf6, 0x24, 0x60, 0x55, + 0x02, 0xce, 0xdc, 0x92, 0x72, 0x14, 0x5b, 0xc0, 0x15, 0x70, 0xe6, 0xf3, 0xd0, 0xb1, 0x5e, 0x12, + 0xc6, 0x8b, 0xd2, 0xf8, 0x8c, 0xc4, 0x43, 0x91, 0x5e, 0xdd, 0x03, 0x0b, 0x1b, 0x38, 0x30, 0xdb, + 0xd7, 0x5d, 0xc7, 0xa2, 0x22, 0xc2, 0x65, 0x50, 0x76, 0xb0, 0x4d, 0x64, 0x88, 0x73, 0xd2, 0xb3, + 0xfc, 0x00, 0xdb, 0x04, 0x09, 0x0d, 0x5c, 0x03, 0x80, 0xe4, 0xe3, 0x83, 0xd2, 0x0e, 0xa4, 0x42, + 0x4b, 0x59, 0xa9, 0x3f, 0x97, 0x25, 0x11, 0x22, 0xcc, 0xed, 0xf9, 0x26, 0x61, 0xf0, 0x09, 0xa8, + 0x71, 0x38, 0xe6, 0x61, 0x93, 0x3c, 0x24, 0x5d, 0x62, 0x06, 0xae, 0x2f, 0x58, 0x2b, 0x6b, 0x57, + 0xb4, 0xa4, 0x4e, 0xe3, 0x1d, 0xd3, 0xbc, 0x4e, 0x8b, 0x0b, 0x98, 0xc6, 0x0b, 0x43, 0xdb, 0x5f, + 0xd5, 0xee, 0xe3, 0x5d, 0xd2, 0x8d, 0x5c, 0x8d, 0x73, 0x83, 0x7e, 0xb3, 0xf6, 0x20, 0x8f, 0x88, + 0x8a, 0x24, 0xd0, 0x05, 0x0b, 0xee, 0xee, 0x63, 0x62, 0x06, 0x31, 0xed, 0xe4, 0xcb, 0xd3, 0xc2, + 0x41, 0xbf, 0xb9, 0xb0, 0x99, 0x81, 0x43, 0x39, 0x78, 0xf8, 0x15, 0x98, 0xf7, 0x65, 0xdc, 0xa8, + 0xd7, 0x25, 0xac, 0x5e, 0x5a, 0x2e, 0x5d, 0xae, 0xac, 0x19, 0xda, 0xc8, 0xed, 0xa8, 0xf1, 0xc0, + 0x2c, 0xee, 0xbc, 0x43, 0x83, 0xf6, 0xa6, 0x47, 0x42, 0x3d, 0x33, 0xce, 0xc9, 0xc4, 0xcf, 0xa3, + 0x34, 0x01, 0xca, 0xf2, 0xc1, 0xef, 0x15, 0x70, 0x96, 0x3c, 0x31, 0xbb, 0x3d, 0x8b, 0x64, 0xec, + 0xea, 0xe5, 0x53, 0x5b, 0xc8, 0xab, 0x72, 0x21, 0x67, 0x6f, 0x0e, 0xe1, 0x41, 0x43, 0xd9, 0xe1, + 0x0d, 0x50, 0xb1, 0x79, 0x51, 0x6c, 0xb9, 0x5d, 0x6a, 0x1e, 0xd4, 0xcf, 0x88, 0x52, 0x52, 0x07, + 0xfd, 0x66, 0x65, 0x23, 0x11, 0x1f, 0xf5, 0x9b, 0x8b, 0xa9, 0xcf, 0x8f, 0x0e, 0x3c, 0x82, 0xd2, + 0x6e, 0xea, 0x0b, 0x05, 0x9c, 0x3f, 0x66, 0x55, 0xf0, 0x5a, 0x92, 0x79, 0x51, 0x1a, 0x75, 0x65, + 0xb9, 0x74, 0x79, 0xd6, 0xa8, 0xa5, 0x33, 0x26, 0x14, 0x28, 0x6b, 0x07, 0xbf, 0x56, 0x00, 0xf4, + 0x0b, 0x78, 0xb2, 0x50, 0xae, 0x8d, 0x92, 0x2f, 0x6d, 0x48, 0x92, 0x96, 0x64, 0x92, 0x60, 0x51, + 0x87, 0x86, 0xd0, 0xa9, 0x18, 0xcc, 0x6e, 0x61, 0x1f, 0xdb, 0xf7, 0xa8, 0x63, 0xf1, 0xbe, 0xc3, + 0x1e, 0xdd, 0x26, 0xbe, 0xe8, 0x3b, 0x25, 0xdb, 0x77, 0xeb, 0x5b, 0x77, 0xa4, 0x06, 0xa5, 0xac, + 0x78, 0x37, 0x77, 0xa8, 0x63, 0xc9, 0x2e, 0x8d, 0xbb, 0x99, 0xe3, 0x21, 0xa1, 0x51, 0x1f, 0x81, + 0x19, 0x41, 0xc1, 0x0f, 0x8e, 0x93, 0x7b, 0x5f, 0x07, 0xb3, 0x71, 0x3f, 0x49, 0xd0, 0x9a, 0x34, + 0x9b, 0x8d, 0x7b, 0x0f, 0x25, 0x36, 0xea, 0x0f, 0x0a, 0x98, 0xe3, 0x5b, 0x76, 0xbd, 0x4d, 0xcc, + 0x0e, 0x3f, 0xca, 0xbe, 0x51, 0x00, 0x24, 0xf9, 0x03, 0x2e, 0xdc, 0x97, 0xca, 0xda, 0xfb, 0x63, + 0x14, 0x62, 0xe1, 0x94, 0x4c, 0xb2, 0x5b, 0x50, 0x31, 0x34, 0x84, 0x53, 0xfd, 0x65, 0x12, 0x5c, + 0xd8, 0xc6, 0x5d, 0x6a, 0xe1, 0x80, 0x3a, 0xad, 0xf5, 0x88, 0x2e, 0x2c, 0x2b, 0xf8, 0x29, 0x98, + 0xe1, 0x1d, 0x6f, 0xe1, 0x00, 0xcb, 0x63, 0xe9, 0xcd, 0xd1, 0xce, 0x87, 0xf0, 0x30, 0xd8, 0x20, + 0x01, 0x4e, 0xb6, 0x27, 0x91, 0xa1, 0x18, 0x15, 0x3e, 0x06, 0x65, 0xe6, 0x11, 0x53, 0x16, 0xd5, + 0x87, 0x63, 0xc4, 0x7e, 0xec, 0xaa, 0x1f, 0x7a, 0xc4, 0x4c, 0x36, 0x8e, 0x7f, 0x21, 0xc1, 0x01, + 0x7d, 0x30, 0xcd, 0x02, 0x1c, 0xf4, 0x98, 0xb8, 0x12, 0x2a, 0x6b, 0x77, 0x4f, 0x85, 0x4d, 0x20, + 0x1a, 0x0b, 0x92, 0x6f, 0x3a, 0xfc, 0x46, 0x92, 0x49, 0xfd, 0x53, 0x01, 0xcb, 0xc7, 0xfa, 0x1a, + 0xd4, 0xb1, 0x78, 0x3d, 0xfc, 0xf7, 0x69, 0xfe, 0x2c, 0x93, 0xe6, 0xcd, 0xd3, 0x08, 0x5c, 0x2e, + 0xfe, 0xb8, 0x6c, 0xab, 0x7f, 0x28, 0xe0, 0xd2, 0x49, 0xce, 0xf7, 0x29, 0x0b, 0xe0, 0x27, 0x85, + 0xe8, 0xb5, 0x11, 0x2f, 0x21, 0xca, 0xc2, 0xd8, 0xe3, 0x41, 0x20, 0x92, 0xa4, 0x22, 0xf7, 0xc0, + 0x14, 0x0d, 0x88, 0xcd, 0x8f, 0x2d, 0xde, 0x5d, 0xf7, 0x4e, 0x31, 0x74, 0x63, 0x5e, 0xf2, 0x4e, + 0xdd, 0xe1, 0x0c, 0x28, 0x24, 0x52, 0xbf, 0x2d, 0x9d, 0x1c, 0x38, 0xcf, 0x13, 0x3f, 0xcc, 0x3c, + 0x21, 0x7c, 0x90, 0x1c, 0x38, 0xf1, 0x36, 0x6e, 0xc5, 0x1a, 0x94, 0xb2, 0x82, 0x8f, 0xc0, 0x8c, + 0x27, 0x8f, 0xaa, 0x21, 0x37, 0xf6, 0x49, 0x11, 0x45, 0xa7, 0x9c, 0x31, 0xc7, 0xb3, 0x15, 0x7d, + 0xa1, 0x18, 0x12, 0xf6, 0xc0, 0x82, 0x9d, 0x19, 0x51, 0x64, 0xab, 0xbc, 0x3b, 0x06, 0x49, 0x76, + 0xc6, 0x09, 0x87, 0x83, 0xac, 0x0c, 0xe5, 0x48, 0xe0, 0x0e, 0xa8, 0xed, 0xcb, 0x8c, 0xb9, 0xce, + 0xba, 0x19, 0xde, 0x33, 0x65, 0x71, 0x4d, 0xad, 0xf0, 0x91, 0x66, 0x3b, 0xaf, 0x3c, 0xea, 0x37, + 0xab, 0x79, 0x21, 0x2a, 0x62, 0xa8, 0xbf, 0x2b, 0xe0, 0xe2, 0xb1, 0x7b, 0xf1, 0x3f, 0x54, 0x1f, + 0xcd, 0x56, 0xdf, 0x8d, 0x53, 0xa9, 0xbe, 0xe1, 0x65, 0xf7, 0xe3, 0xd4, 0x3f, 0x84, 0x2a, 0xea, + 0x0d, 0x83, 0x59, 0x2f, 0xba, 0x49, 0x65, 0xac, 0x57, 0xc7, 0x2d, 0x1e, 0xee, 0x6b, 0xcc, 0xf3, + 0xab, 0x2e, 0xfe, 0x44, 0x09, 0x2a, 0xfc, 0x02, 0x54, 0x6d, 0x39, 0x4b, 0x73, 0x00, 0xea, 0x04, + 0xd1, 0xbc, 0xf0, 0x2f, 0x2a, 0xe8, 0xec, 0xa0, 0xdf, 0xac, 0x6e, 0xe4, 0x60, 0x51, 0x81, 0x08, + 0x76, 0x41, 0x25, 0xa9, 0x80, 0x68, 0xc0, 0x7c, 0xeb, 0x25, 0x52, 0xee, 0x3a, 0xc6, 0x2b, 0x32, + 0xc7, 0x95, 0x44, 0xc6, 0x50, 0x1a, 0x1e, 0xde, 0x07, 0xf3, 0x7b, 0x98, 0x76, 0x7b, 0x3e, 0x91, + 0xa3, 0x5b, 0x59, 0x34, 0xf0, 0x6b, 0x7c, 0xac, 0xba, 0x95, 0x56, 0x1c, 0xf5, 0x9b, 0xb5, 0x8c, + 0x40, 0x8c, 0x6f, 0x59, 0x67, 0xf8, 0x54, 0x01, 0x55, 0x9c, 0x7d, 0x68, 0xb1, 0xfa, 0x94, 0x88, + 0xe0, 0xbd, 0x31, 0x22, 0xc8, 0xbd, 0xd5, 0x8c, 0xba, 0x0c, 0xa3, 0x9a, 0x53, 0x30, 0x54, 0x60, + 0x83, 0x5f, 0x82, 0x45, 0x3b, 0xf3, 0x0e, 0x62, 0xf5, 0x69, 0xb1, 0x80, 0xb1, 0xb7, 0x2e, 0x46, + 0x48, 0xde, 0x7c, 0x59, 0x39, 0x43, 0x79, 0x2a, 0xf5, 0xa7, 0x49, 0xd0, 0x3c, 0xe1, 0x92, 0x85, + 0x77, 0x01, 0x74, 0x77, 0x19, 0xf1, 0xf7, 0x89, 0x75, 0x3b, 0x7c, 0xa7, 0x46, 0x53, 0x60, 0x29, + 0x19, 0x7c, 0x36, 0x0b, 0x16, 0x68, 0x88, 0x17, 0xb4, 0xc1, 0x5c, 0x90, 0x9a, 0xc9, 0xc6, 0x99, + 0x6a, 0x65, 0xa8, 0xe9, 0x91, 0xce, 0xa8, 0x0e, 0xfa, 0xcd, 0xcc, 0x90, 0x87, 0x32, 0xf0, 0xd0, + 0x04, 0xc0, 0x4c, 0xf2, 0x1a, 0x96, 0xa6, 0x3e, 0xda, 0x41, 0x93, 0x64, 0x33, 0xbe, 0x1c, 0x52, + 0x89, 0x4c, 0xc1, 0xaa, 0x7f, 0x29, 0x00, 0x24, 0xf5, 0x0a, 0x2f, 0x81, 0xd4, 0x53, 0x54, 0xde, + 0x2f, 0x65, 0x0e, 0x81, 0x52, 0x72, 0xfe, 0x52, 0xb6, 0x09, 0x63, 0xb8, 0x15, 0x0d, 0xb3, 0xf1, + 0x4b, 0x79, 0x23, 0x14, 0xa3, 0x48, 0x0f, 0x77, 0xc0, 0xb4, 0x4f, 0x30, 0x73, 0x1d, 0xf9, 0xa6, + 0xfe, 0x80, 0x0f, 0x3c, 0x48, 0x48, 0x8e, 0xfa, 0xcd, 0xd5, 0x51, 0xfe, 0xc9, 0xd0, 0xe4, 0x7c, + 0x24, 0x9c, 0x90, 0x84, 0x83, 0xb7, 0x41, 0x4d, 0x72, 0xa4, 0x16, 0x1c, 0xf6, 0xd3, 0x05, 0xb9, + 0x9a, 0xda, 0x46, 0xde, 0x00, 0x15, 0x7d, 0x8c, 0xcd, 0x67, 0x87, 0x8d, 0x89, 0xe7, 0x87, 0x8d, + 0x89, 0x17, 0x87, 0x8d, 0x89, 0xa7, 0x83, 0x86, 0xf2, 0x6c, 0xd0, 0x50, 0x9e, 0x0f, 0x1a, 0xca, + 0x8b, 0x41, 0x43, 0xf9, 0x75, 0xd0, 0x50, 0xbe, 0xfb, 0xad, 0x31, 0xf1, 0xf1, 0xca, 0xc8, 0xff, + 0x1e, 0xfd, 0x1d, 0x00, 0x00, 0xff, 0xff, 0x08, 0xaf, 0xaa, 0x52, 0x82, 0x12, 0x00, 0x00, } func (m *AuditAnnotation) Marshal() (dAtA []byte, err error) { @@ -643,6 +674,39 @@ func (m *ExpressionWarning) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } +func (m *MatchCondition) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MatchCondition) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MatchCondition) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + i -= len(m.Expression) + copy(dAtA[i:], m.Expression) + i = encodeVarintGenerated(dAtA, i, uint64(len(m.Expression))) + i-- + dAtA[i] = 0x12 + i -= len(m.Name) + copy(dAtA[i:], m.Name) + i = encodeVarintGenerated(dAtA, i, uint64(len(m.Name))) + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + func (m *MatchResources) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -1141,6 +1205,20 @@ func (m *ValidatingAdmissionPolicySpec) MarshalToSizedBuffer(dAtA []byte) (int, _ = i var l int _ = l + if len(m.MatchConditions) > 0 { + for iNdEx := len(m.MatchConditions) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.MatchConditions[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenerated(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x32 + } + } if len(m.AuditAnnotations) > 0 { for iNdEx := len(m.AuditAnnotations) - 1; iNdEx >= 0; iNdEx-- { { @@ -1337,6 +1415,19 @@ func (m *ExpressionWarning) Size() (n int) { return n } +func (m *MatchCondition) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Name) + n += 1 + l + sovGenerated(uint64(l)) + l = len(m.Expression) + n += 1 + l + sovGenerated(uint64(l)) + return n +} + func (m *MatchResources) Size() (n int) { if m == nil { return 0 @@ -1545,6 +1636,12 @@ func (m *ValidatingAdmissionPolicySpec) Size() (n int) { n += 1 + l + sovGenerated(uint64(l)) } } + if len(m.MatchConditions) > 0 { + for _, e := range m.MatchConditions { + l = e.Size() + n += 1 + l + sovGenerated(uint64(l)) + } + } return n } @@ -1615,6 +1712,17 @@ func (this *ExpressionWarning) String() string { }, "") return s } +func (this *MatchCondition) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&MatchCondition{`, + `Name:` + fmt.Sprintf("%v", this.Name) + `,`, + `Expression:` + fmt.Sprintf("%v", this.Expression) + `,`, + `}`, + }, "") + return s +} func (this *MatchResources) String() string { if this == nil { return "nil" @@ -1769,12 +1877,18 @@ func (this *ValidatingAdmissionPolicySpec) String() string { repeatedStringForAuditAnnotations += strings.Replace(strings.Replace(f.String(), "AuditAnnotation", "AuditAnnotation", 1), `&`, ``, 1) + "," } repeatedStringForAuditAnnotations += "}" + repeatedStringForMatchConditions := "[]MatchCondition{" + for _, f := range this.MatchConditions { + repeatedStringForMatchConditions += strings.Replace(strings.Replace(f.String(), "MatchCondition", "MatchCondition", 1), `&`, ``, 1) + "," + } + repeatedStringForMatchConditions += "}" s := strings.Join([]string{`&ValidatingAdmissionPolicySpec{`, `ParamKind:` + strings.Replace(this.ParamKind.String(), "ParamKind", "ParamKind", 1) + `,`, `MatchConstraints:` + strings.Replace(this.MatchConstraints.String(), "MatchResources", "MatchResources", 1) + `,`, `Validations:` + repeatedStringForValidations + `,`, `FailurePolicy:` + valueToStringGenerated(this.FailurePolicy) + `,`, `AuditAnnotations:` + repeatedStringForAuditAnnotations + `,`, + `MatchConditions:` + repeatedStringForMatchConditions + `,`, `}`, }, "") return s @@ -2045,6 +2159,120 @@ func (m *ExpressionWarning) Unmarshal(dAtA []byte) error { } return nil } +func (m *MatchCondition) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MatchCondition: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MatchCondition: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Name = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Expression", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Expression = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGenerated(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func (m *MatchResources) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 @@ -3582,6 +3810,40 @@ func (m *ValidatingAdmissionPolicySpec) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field MatchConditions", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.MatchConditions = append(m.MatchConditions, MatchCondition{}) + if err := m.MatchConditions[len(m.MatchConditions)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipGenerated(dAtA[iNdEx:]) diff --git a/staging/src/k8s.io/api/admissionregistration/v1alpha1/generated.proto b/staging/src/k8s.io/api/admissionregistration/v1alpha1/generated.proto index 6348472d65f..c718c5464df 100644 --- a/staging/src/k8s.io/api/admissionregistration/v1alpha1/generated.proto +++ b/staging/src/k8s.io/api/admissionregistration/v1alpha1/generated.proto @@ -79,6 +79,34 @@ message ExpressionWarning { optional string warning = 3; } +message MatchCondition { + // Name is an identifier for this match condition, used for strategic merging of MatchConditions, + // as well as providing an identifier for logging purposes. A good name should be descriptive of + // the associated expression. + // Name must be a qualified name consisting of alphanumeric characters, '-', '_' or '.', and + // must start and end with an alphanumeric character (e.g. 'MyName', or 'my.name', or + // '123-abc', regex used for validation is '([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9]') with an + // optional DNS subdomain prefix and '/' (e.g. 'example.com/MyName') + // + // Required. + optional string name = 1; + + // Expression represents the expression which will be evaluated by CEL. Must evaluate to bool. + // CEL expressions have access to the contents of the AdmissionRequest and Authorizer, organized into CEL variables: + // + // 'object' - The object from the incoming request. The value is null for DELETE requests. + // 'oldObject' - The existing object. The value is null for CREATE requests. + // 'request' - Attributes of the admission request(/pkg/apis/admission/types.go#AdmissionRequest). + // 'authorizer' - A CEL Authorizer. May be used to perform authorization checks for the principal (user or service account) of the request. + // See https://pkg.go.dev/k8s.io/apiserver/pkg/cel/library#Authz + // 'authorizer.requestResource' - A CEL ResourceCheck constructed from the 'authorizer' and configured with the + // request resource. + // Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/ + // + // Required. + optional string expression = 2; +} + // MatchResources decides whether to run the admission control policy on an object based // on whether it meets the match criteria. // The exclude rules take precedence over include rules (if a resource matches both, it is excluded) @@ -380,6 +408,28 @@ message ValidatingAdmissionPolicySpec { // +listType=atomic // +optional repeated AuditAnnotation auditAnnotations = 5; + + // MatchConditions is a list of conditions that must be met for a request to be validated. + // Match conditions filter requests that have already been matched by the rules, + // namespaceSelector, and objectSelector. An empty list of matchConditions matches all requests. + // There are a maximum of 64 match conditions allowed. + // + // If a parameter object is provided, it can be accessed via the `params` handle in the same + // manner as validation expressions. + // + // The exact matching logic is (in order): + // 1. If ANY matchCondition evaluates to FALSE, the policy is skipped. + // 2. If ALL matchConditions evaluate to TRUE, the policy is evaluated. + // 3. If any matchCondition evaluates to an error (but none are FALSE): + // - If failurePolicy=Fail, reject the request + // - If failurePolicy=Ignore, the policy is skipped + // + // +patchMergeKey=name + // +patchStrategy=merge + // +listType=map + // +listMapKey=name + // +optional + repeated MatchCondition matchConditions = 6; } // ValidatingAdmissionPolicyStatus represents the status of a ValidatingAdmissionPolicy. diff --git a/staging/src/k8s.io/api/admissionregistration/v1alpha1/types.go b/staging/src/k8s.io/api/admissionregistration/v1alpha1/types.go index ec7a1301783..2bbb55a47da 100644 --- a/staging/src/k8s.io/api/admissionregistration/v1alpha1/types.go +++ b/staging/src/k8s.io/api/admissionregistration/v1alpha1/types.go @@ -179,8 +179,32 @@ type ValidatingAdmissionPolicySpec struct { // +listType=atomic // +optional AuditAnnotations []AuditAnnotation `json:"auditAnnotations,omitempty" protobuf:"bytes,5,rep,name=auditAnnotations"` + + // MatchConditions is a list of conditions that must be met for a request to be validated. + // Match conditions filter requests that have already been matched by the rules, + // namespaceSelector, and objectSelector. An empty list of matchConditions matches all requests. + // There are a maximum of 64 match conditions allowed. + // + // If a parameter object is provided, it can be accessed via the `params` handle in the same + // manner as validation expressions. + // + // The exact matching logic is (in order): + // 1. If ANY matchCondition evaluates to FALSE, the policy is skipped. + // 2. If ALL matchConditions evaluate to TRUE, the policy is evaluated. + // 3. If any matchCondition evaluates to an error (but none are FALSE): + // - If failurePolicy=Fail, reject the request + // - If failurePolicy=Ignore, the policy is skipped + // + // +patchMergeKey=name + // +patchStrategy=merge + // +listType=map + // +listMapKey=name + // +optional + MatchConditions []MatchCondition `json:"matchConditions,omitempty" patchStrategy:"merge" patchMergeKey:"name" protobuf:"bytes,6,rep,name=matchConditions"` } +type MatchCondition v1.MatchCondition + // ParamKind is a tuple of Group Kind and Version. // +structType=atomic type ParamKind struct { diff --git a/staging/src/k8s.io/api/admissionregistration/v1alpha1/types_swagger_doc_generated.go b/staging/src/k8s.io/api/admissionregistration/v1alpha1/types_swagger_doc_generated.go index 5117fb9b18e..b3cac1821ba 100644 --- a/staging/src/k8s.io/api/admissionregistration/v1alpha1/types_swagger_doc_generated.go +++ b/staging/src/k8s.io/api/admissionregistration/v1alpha1/types_swagger_doc_generated.go @@ -158,6 +158,7 @@ var map_ValidatingAdmissionPolicySpec = map[string]string{ "validations": "Validations contain CEL expressions which is used to apply the validation. Validations and AuditAnnotations may not both be empty; a minimum of one Validations or AuditAnnotations is required.", "failurePolicy": "failurePolicy defines how to handle failures for the admission policy. Failures can occur from CEL expression parse errors, type check errors, runtime errors and invalid or mis-configured policy definitions or bindings.\n\nA policy is invalid if spec.paramKind refers to a non-existent Kind. A binding is invalid if spec.paramRef.name refers to a non-existent resource.\n\nfailurePolicy does not define how validations that evaluate to false are handled.\n\nWhen failurePolicy is set to Fail, ValidatingAdmissionPolicyBinding validationActions define how failures are enforced.\n\nAllowed values are Ignore or Fail. Defaults to Fail.", "auditAnnotations": "auditAnnotations contains CEL expressions which are used to produce audit annotations for the audit event of the API request. validations and auditAnnotations may not both be empty; a least one of validations or auditAnnotations is required.", + "matchConditions": "MatchConditions is a list of conditions that must be met for a request to be validated. Match conditions filter requests that have already been matched by the rules, namespaceSelector, and objectSelector. An empty list of matchConditions matches all requests. There are a maximum of 64 match conditions allowed.\n\nIf a parameter object is provided, it can be accessed via the `params` handle in the same manner as validation expressions.\n\nThe exact matching logic is (in order):\n 1. If ANY matchCondition evaluates to FALSE, the policy is skipped.\n 2. If ALL matchConditions evaluate to TRUE, the policy is evaluated.\n 3. If any matchCondition evaluates to an error (but none are FALSE):\n - If failurePolicy=Fail, reject the request\n - If failurePolicy=Ignore, the policy is skipped", } func (ValidatingAdmissionPolicySpec) SwaggerDoc() map[string]string { diff --git a/staging/src/k8s.io/api/admissionregistration/v1alpha1/zz_generated.deepcopy.go b/staging/src/k8s.io/api/admissionregistration/v1alpha1/zz_generated.deepcopy.go index 65842ed2469..8e4abfd0877 100644 --- a/staging/src/k8s.io/api/admissionregistration/v1alpha1/zz_generated.deepcopy.go +++ b/staging/src/k8s.io/api/admissionregistration/v1alpha1/zz_generated.deepcopy.go @@ -58,6 +58,22 @@ func (in *ExpressionWarning) DeepCopy() *ExpressionWarning { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *MatchCondition) DeepCopyInto(out *MatchCondition) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MatchCondition. +func (in *MatchCondition) DeepCopy() *MatchCondition { + if in == nil { + return nil + } + out := new(MatchCondition) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *MatchResources) DeepCopyInto(out *MatchResources) { *out = *in @@ -360,6 +376,11 @@ func (in *ValidatingAdmissionPolicySpec) DeepCopyInto(out *ValidatingAdmissionPo *out = make([]AuditAnnotation, len(*in)) copy(*out, *in) } + if in.MatchConditions != nil { + in, out := &in.MatchConditions, &out.MatchConditions + *out = make([]MatchCondition, len(*in)) + copy(*out, *in) + } return } diff --git a/staging/src/k8s.io/api/testdata/HEAD/admissionregistration.k8s.io.v1alpha1.ValidatingAdmissionPolicy.json b/staging/src/k8s.io/api/testdata/HEAD/admissionregistration.k8s.io.v1alpha1.ValidatingAdmissionPolicy.json index 7b673ce921c..e7139fc9544 100644 --- a/staging/src/k8s.io/api/testdata/HEAD/admissionregistration.k8s.io.v1alpha1.ValidatingAdmissionPolicy.json +++ b/staging/src/k8s.io/api/testdata/HEAD/admissionregistration.k8s.io.v1alpha1.ValidatingAdmissionPolicy.json @@ -133,6 +133,12 @@ "key": "keyValue", "valueExpression": "valueExpressionValue" } + ], + "matchConditions": [ + { + "name": "nameValue", + "expression": "expressionValue" + } ] }, "status": { diff --git a/staging/src/k8s.io/api/testdata/HEAD/admissionregistration.k8s.io.v1alpha1.ValidatingAdmissionPolicy.pb b/staging/src/k8s.io/api/testdata/HEAD/admissionregistration.k8s.io.v1alpha1.ValidatingAdmissionPolicy.pb index ba3b1f53d8d778f5a4bc4e04313c611dace96a35..2fd9006f3025ce47e7efd91b2a60c924d56037ba 100644 GIT binary patch delta 41 xcmdnNagAewCsRAeM(-3x#@(AYFv>9r7|C#P<|XE)h9%~drV8<=PCmd~0RR*S4GjPQ delta 24 gcmcb{v4dlRC(}#zjovAYjB__{V3cE;{DwIT0CDCB*#H0l diff --git a/staging/src/k8s.io/api/testdata/HEAD/admissionregistration.k8s.io.v1alpha1.ValidatingAdmissionPolicy.yaml b/staging/src/k8s.io/api/testdata/HEAD/admissionregistration.k8s.io.v1alpha1.ValidatingAdmissionPolicy.yaml index 11373c659d1..62ef12d9010 100644 --- a/staging/src/k8s.io/api/testdata/HEAD/admissionregistration.k8s.io.v1alpha1.ValidatingAdmissionPolicy.yaml +++ b/staging/src/k8s.io/api/testdata/HEAD/admissionregistration.k8s.io.v1alpha1.ValidatingAdmissionPolicy.yaml @@ -37,6 +37,9 @@ spec: - key: keyValue valueExpression: valueExpressionValue failurePolicy: failurePolicyValue + matchConditions: + - expression: expressionValue + name: nameValue matchConstraints: excludeResourceRules: - apiGroups: diff --git a/staging/src/k8s.io/apiserver/pkg/admission/plugin/validatingadmissionpolicy/admission_test.go b/staging/src/k8s.io/apiserver/pkg/admission/plugin/validatingadmissionpolicy/admission_test.go index 6b364436fb9..7ed56b12b65 100644 --- a/staging/src/k8s.io/apiserver/pkg/admission/plugin/validatingadmissionpolicy/admission_test.go +++ b/staging/src/k8s.io/apiserver/pkg/admission/plugin/validatingadmissionpolicy/admission_test.go @@ -28,8 +28,6 @@ import ( celgo "github.com/google/cel-go/cel" "github.com/stretchr/testify/require" - "k8s.io/klog/v2" - admissionv1 "k8s.io/api/admission/v1" admissionRegistrationv1 "k8s.io/api/admissionregistration/v1" "k8s.io/api/admissionregistration/v1alpha1" @@ -47,6 +45,7 @@ import ( "k8s.io/apiserver/pkg/admission/initializer" "k8s.io/apiserver/pkg/admission/plugin/cel" "k8s.io/apiserver/pkg/admission/plugin/validatingadmissionpolicy/internal/generic" + "k8s.io/apiserver/pkg/admission/plugin/webhook/matchconditions" auditinternal "k8s.io/apiserver/pkg/apis/audit" "k8s.io/apiserver/pkg/authorization/authorizer" "k8s.io/apiserver/pkg/features" @@ -57,6 +56,7 @@ import ( clienttesting "k8s.io/client-go/testing" "k8s.io/client-go/tools/cache" "k8s.io/component-base/featuregate" + "k8s.io/klog/v2" ) var ( @@ -418,7 +418,7 @@ func setupTestCommon(t *testing.T, compiler cel.FilterCompiler, matcher Matcher, // Override compiler used by controller for tests controller = handler.evaluator.(*celAdmissionController) controller.policyController.filterCompiler = compiler - controller.policyController.newValidator = func(validationFilter, auditAnnotationFilter, messageFilter cel.Filter, fail *admissionRegistrationv1.FailurePolicyType, authorizer authorizer.Authorizer) Validator { + controller.policyController.newValidator = func(validationFilter cel.Filter, celMatcher matchconditions.Matcher, auditAnnotationFilter, messageFilter cel.Filter, fail *admissionRegistrationv1.FailurePolicyType, authorizer authorizer.Authorizer) Validator { f := validationFilter.(*fakeFilter) v := validatorMap[f.keyId] v.validationFilter = f diff --git a/staging/src/k8s.io/apiserver/pkg/admission/plugin/validatingadmissionpolicy/controller_reconcile.go b/staging/src/k8s.io/apiserver/pkg/admission/plugin/validatingadmissionpolicy/controller_reconcile.go index 4d2671c0829..296ac416aa2 100644 --- a/staging/src/k8s.io/apiserver/pkg/admission/plugin/validatingadmissionpolicy/controller_reconcile.go +++ b/staging/src/k8s.io/apiserver/pkg/admission/plugin/validatingadmissionpolicy/controller_reconcile.go @@ -35,6 +35,7 @@ import ( celmetrics "k8s.io/apiserver/pkg/admission/cel" "k8s.io/apiserver/pkg/admission/plugin/cel" "k8s.io/apiserver/pkg/admission/plugin/validatingadmissionpolicy/internal/generic" + "k8s.io/apiserver/pkg/admission/plugin/webhook/matchconditions" celconfig "k8s.io/apiserver/pkg/apis/cel" "k8s.io/apiserver/pkg/authorization/authorizer" "k8s.io/client-go/dynamic" @@ -99,7 +100,7 @@ type policyController struct { authz authorizer.Authorizer } -type newValidator func(validationFilter cel.Filter, auditAnnotationFilter cel.Filter, messageFilter cel.Filter, failurePolicy *v1.FailurePolicyType, authorizer authorizer.Authorizer) Validator +type newValidator func(validationFilter cel.Filter, celMatcher matchconditions.Matcher, auditAnnotationFilter, messageFilter cel.Filter, failurePolicy *v1.FailurePolicyType, authorizer authorizer.Authorizer) Validator func newPolicyController( restMapper meta.RESTMapper, @@ -503,11 +504,22 @@ func (c *policyController) latestPolicyData() []policyData { } optionalVars := cel.OptionalVariableDeclarations{HasParams: hasParam, HasAuthorizer: true} expressionOptionalVars := cel.OptionalVariableDeclarations{HasParams: hasParam, HasAuthorizer: false} + failurePolicy := convertv1alpha1FailurePolicyTypeTov1FailurePolicyType(definitionInfo.lastReconciledValue.Spec.FailurePolicy) + var matcher matchconditions.Matcher = nil + matchConditions := definitionInfo.lastReconciledValue.Spec.MatchConditions + if len(matchConditions) > 0 { + matchExpressionAccessors := make([]cel.ExpressionAccessor, len(matchConditions)) + for i := range matchConditions { + matchExpressionAccessors[i] = (*matchconditions.MatchCondition)(&matchConditions[i]) + } + matcher = matchconditions.NewMatcher(c.filterCompiler.Compile(matchExpressionAccessors, optionalVars, celconfig.PerCallLimit), c.authz, failurePolicy, "validatingadmissionpolicy", definitionInfo.lastReconciledValue.Name) + } bindingInfo.validator = c.newValidator( c.filterCompiler.Compile(convertv1alpha1Validations(definitionInfo.lastReconciledValue.Spec.Validations), optionalVars, celconfig.PerCallLimit), + matcher, c.filterCompiler.Compile(convertv1alpha1AuditAnnotations(definitionInfo.lastReconciledValue.Spec.AuditAnnotations), optionalVars, celconfig.PerCallLimit), c.filterCompiler.Compile(convertV1Alpha1MessageExpressions(definitionInfo.lastReconciledValue.Spec.Validations), expressionOptionalVars, celconfig.PerCallLimit), - convertv1alpha1FailurePolicyTypeTov1FailurePolicyType(definitionInfo.lastReconciledValue.Spec.FailurePolicy), + failurePolicy, c.authz, ) } diff --git a/staging/src/k8s.io/apiserver/pkg/admission/plugin/validatingadmissionpolicy/validator.go b/staging/src/k8s.io/apiserver/pkg/admission/plugin/validatingadmissionpolicy/validator.go index 0b19158a123..448750c9199 100644 --- a/staging/src/k8s.io/apiserver/pkg/admission/plugin/validatingadmissionpolicy/validator.go +++ b/staging/src/k8s.io/apiserver/pkg/admission/plugin/validatingadmissionpolicy/validator.go @@ -28,6 +28,7 @@ import ( "k8s.io/apimachinery/pkg/runtime" "k8s.io/apiserver/pkg/admission" "k8s.io/apiserver/pkg/admission/plugin/cel" + "k8s.io/apiserver/pkg/admission/plugin/webhook/matchconditions" celconfig "k8s.io/apiserver/pkg/apis/cel" "k8s.io/apiserver/pkg/authorization/authorizer" apiservercel "k8s.io/apiserver/pkg/cel" @@ -36,6 +37,7 @@ import ( // validator implements the Validator interface type validator struct { + celMatcher matchconditions.Matcher validationFilter cel.Filter auditAnnotationFilter cel.Filter messageFilter cel.Filter @@ -43,8 +45,9 @@ type validator struct { authorizer authorizer.Authorizer } -func NewValidator(validationFilter, auditAnnotationFilter, messageFilter cel.Filter, failPolicy *v1.FailurePolicyType, authorizer authorizer.Authorizer) Validator { +func NewValidator(validationFilter cel.Filter, celMatcher matchconditions.Matcher, auditAnnotationFilter, messageFilter cel.Filter, failPolicy *v1.FailurePolicyType, authorizer authorizer.Authorizer) Validator { return &validator{ + celMatcher: celMatcher, validationFilter: validationFilter, auditAnnotationFilter: auditAnnotationFilter, messageFilter: messageFilter, @@ -77,6 +80,26 @@ func (v *validator) Validate(ctx context.Context, versionedAttr *admission.Versi f = *v.failPolicy } + if v.celMatcher != nil { + matchResults := v.celMatcher.Match(ctx, versionedAttr, versionedParams) + if matchResults.Error != nil { + return ValidateResult{ + Decisions: []PolicyDecision{ + { + Action: policyDecisionActionForError(f), + Evaluation: EvalError, + Message: matchResults.Error.Error(), + }, + }, + } + } + + // if preconditions are not met, then do not return any validations + if !matchResults.Matches { + return ValidateResult{} + } + } + optionalVars := cel.OptionalVariableBindings{VersionedParams: versionedParams, Authorizer: v.authorizer} expressionOptionalVars := cel.OptionalVariableBindings{VersionedParams: versionedParams} admissionRequest := cel.CreateAdmissionRequest(versionedAttr.Attributes) diff --git a/staging/src/k8s.io/apiserver/pkg/admission/plugin/validatingadmissionpolicy/validator_test.go b/staging/src/k8s.io/apiserver/pkg/admission/plugin/validatingadmissionpolicy/validator_test.go index 33e1796f8b0..9d5101ec7f1 100644 --- a/staging/src/k8s.io/apiserver/pkg/admission/plugin/validatingadmissionpolicy/validator_test.go +++ b/staging/src/k8s.io/apiserver/pkg/admission/plugin/validatingadmissionpolicy/validator_test.go @@ -23,16 +23,17 @@ import ( "strings" "testing" - "github.com/stretchr/testify/require" - celtypes "github.com/google/cel-go/common/types" + "github.com/stretchr/testify/require" admissionv1 "k8s.io/api/admission/v1" v1 "k8s.io/api/admissionregistration/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apiserver/pkg/admission" "k8s.io/apiserver/pkg/admission/plugin/cel" + "k8s.io/apiserver/pkg/admission/plugin/webhook/matchconditions" celconfig "k8s.io/apiserver/pkg/apis/cel" apiservercel "k8s.io/apiserver/pkg/cel" ) @@ -61,6 +62,17 @@ func (f *fakeCelFilter) CompilationErrors() []error { return []error{} } +var _ matchconditions.Matcher = &fakeCELMatcher{} + +type fakeCELMatcher struct { + error error + matches bool +} + +func (f *fakeCELMatcher) Match(ctx context.Context, versionedAttr *admission.VersionedAttributes, versionedParams runtime.Object) matchconditions.MatchResult { + return matchconditions.MatchResult{Matches: f.matches, FailedConditionName: "placeholder", Error: f.error} +} + func TestValidate(t *testing.T) { ignore := v1.Ignore fail := v1.Fail @@ -74,6 +86,7 @@ func TestValidate(t *testing.T) { cases := []struct { name string failPolicy *v1.FailurePolicyType + matcher matchconditions.Matcher evaluations []cel.EvaluationResult messageEvaluations []cel.EvaluationResult auditEvaluations []cel.EvaluationResult @@ -819,11 +832,46 @@ func TestValidate(t *testing.T) { }, costBudget: 1, // shared between expression and messageExpression, needs 1 + 1 = 2 in total }, + { + name: "no match surpresses failure", + matcher: &fakeCELMatcher{matches: false}, + evaluations: []cel.EvaluationResult{ + { + Error: errors.New("expected"), + ExpressionAccessor: &ValidationCondition{}, + }, + }, + policyDecision: []PolicyDecision{}, + failPolicy: &fail, + }, + { + name: "match error => presumed match", + matcher: &fakeCELMatcher{matches: true, error: fmt.Errorf("test error")}, + evaluations: []cel.EvaluationResult{ + { + Error: errors.New("expected"), + ExpressionAccessor: &ValidationCondition{}, + }, + }, + policyDecision: []PolicyDecision{ + { + Action: ActionDeny, + }, + }, + failPolicy: &fail, + }, } for _, tc := range cases { t.Run(tc.name, func(t *testing.T) { + var matcher matchconditions.Matcher + if tc.matcher == nil { + matcher = &fakeCELMatcher{matches: true} + } else { + matcher = tc.matcher + } v := validator{ failPolicy: tc.failPolicy, + celMatcher: matcher, validationFilter: &fakeCelFilter{ evaluations: tc.evaluations, throwError: tc.throwError, @@ -884,6 +932,7 @@ func TestContextCanceled(t *testing.T) { f := fc.Compile([]cel.ExpressionAccessor{&ValidationCondition{Expression: "[1,2,3,4,5,6,7,8,9,10].map(x, [1,2,3,4,5,6,7,8,9,10].map(y, x*y)) == []"}}, cel.OptionalVariableDeclarations{HasParams: false, HasAuthorizer: false}, celconfig.PerCallLimit) v := validator{ failPolicy: &fail, + celMatcher: &fakeCELMatcher{matches: true}, validationFilter: f, messageFilter: f, auditAnnotationFilter: &fakeCelFilter{ diff --git a/staging/src/k8s.io/client-go/applyconfigurations/admissionregistration/v1alpha1/matchcondition.go b/staging/src/k8s.io/client-go/applyconfigurations/admissionregistration/v1alpha1/matchcondition.go new file mode 100644 index 00000000000..186c750f96e --- /dev/null +++ b/staging/src/k8s.io/client-go/applyconfigurations/admissionregistration/v1alpha1/matchcondition.go @@ -0,0 +1,48 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v1alpha1 + +// MatchConditionApplyConfiguration represents an declarative configuration of the MatchCondition type for use +// with apply. +type MatchConditionApplyConfiguration struct { + Name *string `json:"name,omitempty"` + Expression *string `json:"expression,omitempty"` +} + +// MatchConditionApplyConfiguration constructs an declarative configuration of the MatchCondition type for use with +// apply. +func MatchCondition() *MatchConditionApplyConfiguration { + return &MatchConditionApplyConfiguration{} +} + +// WithName sets the Name field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Name field is set to the value of the last call. +func (b *MatchConditionApplyConfiguration) WithName(value string) *MatchConditionApplyConfiguration { + b.Name = &value + return b +} + +// WithExpression sets the Expression field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Expression field is set to the value of the last call. +func (b *MatchConditionApplyConfiguration) WithExpression(value string) *MatchConditionApplyConfiguration { + b.Expression = &value + return b +} diff --git a/staging/src/k8s.io/client-go/applyconfigurations/admissionregistration/v1alpha1/validatingadmissionpolicyspec.go b/staging/src/k8s.io/client-go/applyconfigurations/admissionregistration/v1alpha1/validatingadmissionpolicyspec.go index a0763b518cd..f674b5b1ec2 100644 --- a/staging/src/k8s.io/client-go/applyconfigurations/admissionregistration/v1alpha1/validatingadmissionpolicyspec.go +++ b/staging/src/k8s.io/client-go/applyconfigurations/admissionregistration/v1alpha1/validatingadmissionpolicyspec.go @@ -30,6 +30,7 @@ type ValidatingAdmissionPolicySpecApplyConfiguration struct { Validations []ValidationApplyConfiguration `json:"validations,omitempty"` FailurePolicy *admissionregistrationv1alpha1.FailurePolicyType `json:"failurePolicy,omitempty"` AuditAnnotations []AuditAnnotationApplyConfiguration `json:"auditAnnotations,omitempty"` + MatchConditions []MatchConditionApplyConfiguration `json:"matchConditions,omitempty"` } // ValidatingAdmissionPolicySpecApplyConfiguration constructs an declarative configuration of the ValidatingAdmissionPolicySpec type for use with @@ -87,3 +88,16 @@ func (b *ValidatingAdmissionPolicySpecApplyConfiguration) WithAuditAnnotations(v } return b } + +// WithMatchConditions adds the given value to the MatchConditions field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, values provided by each call will be appended to the MatchConditions field. +func (b *ValidatingAdmissionPolicySpecApplyConfiguration) WithMatchConditions(values ...*MatchConditionApplyConfiguration) *ValidatingAdmissionPolicySpecApplyConfiguration { + for i := range values { + if values[i] == nil { + panic("nil value passed to WithMatchConditions") + } + b.MatchConditions = append(b.MatchConditions, *values[i]) + } + return b +} diff --git a/staging/src/k8s.io/client-go/applyconfigurations/internal/internal.go b/staging/src/k8s.io/client-go/applyconfigurations/internal/internal.go index e490be8123e..df8f5ebba5c 100644 --- a/staging/src/k8s.io/client-go/applyconfigurations/internal/internal.go +++ b/staging/src/k8s.io/client-go/applyconfigurations/internal/internal.go @@ -274,6 +274,17 @@ var schemaYAML = typed.YAMLObject(`types: type: scalar: string default: "" +- name: io.k8s.api.admissionregistration.v1alpha1.MatchCondition + map: + fields: + - name: expression + type: + scalar: string + default: "" + - name: name + type: + scalar: string + default: "" - name: io.k8s.api.admissionregistration.v1alpha1.MatchResources map: fields: @@ -433,6 +444,14 @@ var schemaYAML = typed.YAMLObject(`types: - name: failurePolicy type: scalar: string + - name: matchConditions + type: + list: + elementType: + namedType: io.k8s.api.admissionregistration.v1alpha1.MatchCondition + elementRelationship: associative + keys: + - name - name: matchConstraints type: namedType: io.k8s.api.admissionregistration.v1alpha1.MatchResources diff --git a/staging/src/k8s.io/client-go/applyconfigurations/utils.go b/staging/src/k8s.io/client-go/applyconfigurations/utils.go index c9becae24c7..1d4cee853bb 100644 --- a/staging/src/k8s.io/client-go/applyconfigurations/utils.go +++ b/staging/src/k8s.io/client-go/applyconfigurations/utils.go @@ -145,6 +145,8 @@ func ForKind(kind schema.GroupVersionKind) interface{} { return &admissionregistrationv1alpha1.AuditAnnotationApplyConfiguration{} case v1alpha1.SchemeGroupVersion.WithKind("ExpressionWarning"): return &admissionregistrationv1alpha1.ExpressionWarningApplyConfiguration{} + case v1alpha1.SchemeGroupVersion.WithKind("MatchCondition"): + return &admissionregistrationv1alpha1.MatchConditionApplyConfiguration{} case v1alpha1.SchemeGroupVersion.WithKind("MatchResources"): return &admissionregistrationv1alpha1.MatchResourcesApplyConfiguration{} case v1alpha1.SchemeGroupVersion.WithKind("NamedRuleWithOperations"):