Merge pull request #135763 from darshansreenivas/admissionregistratio_k8s_io_ValidationAction

feat: wire admissionregistration group for declarative validation and +k8s:required to ValidatingAdmissionPolicyBindingSpec.ValidationActions
This commit is contained in:
Kubernetes Prow Robot
2026-01-27 03:23:53 +05:30
committed by GitHub
15 changed files with 110 additions and 11 deletions

View File

@@ -534,7 +534,8 @@
}
},
"required": [
"policyName"
"policyName",
"validationActions"
],
"type": "object"
},

View File

@@ -668,7 +668,8 @@
}
},
"required": [
"policyName"
"policyName",
"validationActions"
],
"type": "object"
},

View File

@@ -55,6 +55,9 @@ func TestVersionedValidationByFuzzing(t *testing.T) {
{Group: "autoscaling", Version: "v1beta1"},
{Group: "autoscaling", Version: "v1beta2"},
{Group: "autoscaling", Version: "v2"},
{Group: "admissionregistration.k8s.io", Version: "v1"},
{Group: "admissionregistration.k8s.io", Version: "v1beta1"},
{Group: "admissionregistration.k8s.io", Version: "v1alpha1"},
{Group: "discovery.k8s.io", Version: "v1"},
{Group: "discovery.k8s.io", Version: "v1beta1"},
{Group: "admissionregistration.k8s.io", Version: "v1"},

View File

@@ -99,6 +99,27 @@ func Validate_ValidatingAdmissionPolicyBindingSpec(ctx context.Context, op opera
// field admissionregistrationv1.ValidatingAdmissionPolicyBindingSpec.ParamRef has no validation
// field admissionregistrationv1.ValidatingAdmissionPolicyBindingSpec.MatchResources has no validation
// field admissionregistrationv1.ValidatingAdmissionPolicyBindingSpec.ValidationActions has no validation
// field admissionregistrationv1.ValidatingAdmissionPolicyBindingSpec.ValidationActions
errs = append(errs,
func(fldPath *field.Path, obj, oldObj []admissionregistrationv1.ValidationAction, oldValueCorrelated bool) (errs field.ErrorList) {
// don't revalidate unchanged data
if oldValueCorrelated && op.Type == operation.Update && equality.Semantic.DeepEqual(obj, oldObj) {
return nil
}
// call field-attached validations
earlyReturn := false
if e := validate.RequiredSlice(ctx, op, fldPath, obj, oldObj); len(e) != 0 {
errs = append(errs, e...)
earlyReturn = true
}
if earlyReturn {
return // do not proceed
}
return
}(fldPath.Child("validationActions"), obj.ValidationActions, safe.Field(oldObj, func(oldObj *admissionregistrationv1.ValidatingAdmissionPolicyBindingSpec) []admissionregistrationv1.ValidationAction {
return oldObj.ValidationActions
}), oldObj != nil)...)
return errs
}

View File

@@ -99,6 +99,27 @@ func Validate_ValidatingAdmissionPolicyBindingSpec(ctx context.Context, op opera
// field admissionregistrationv1alpha1.ValidatingAdmissionPolicyBindingSpec.ParamRef has no validation
// field admissionregistrationv1alpha1.ValidatingAdmissionPolicyBindingSpec.MatchResources has no validation
// field admissionregistrationv1alpha1.ValidatingAdmissionPolicyBindingSpec.ValidationActions has no validation
// field admissionregistrationv1alpha1.ValidatingAdmissionPolicyBindingSpec.ValidationActions
errs = append(errs,
func(fldPath *field.Path, obj, oldObj []admissionregistrationv1alpha1.ValidationAction, oldValueCorrelated bool) (errs field.ErrorList) {
// don't revalidate unchanged data
if oldValueCorrelated && op.Type == operation.Update && equality.Semantic.DeepEqual(obj, oldObj) {
return nil
}
// call field-attached validations
earlyReturn := false
if e := validate.RequiredSlice(ctx, op, fldPath, obj, oldObj); len(e) != 0 {
errs = append(errs, e...)
earlyReturn = true
}
if earlyReturn {
return // do not proceed
}
return
}(fldPath.Child("validationActions"), obj.ValidationActions, safe.Field(oldObj, func(oldObj *admissionregistrationv1alpha1.ValidatingAdmissionPolicyBindingSpec) []admissionregistrationv1alpha1.ValidationAction {
return oldObj.ValidationActions
}), oldObj != nil)...)
return errs
}

View File

@@ -99,6 +99,27 @@ func Validate_ValidatingAdmissionPolicyBindingSpec(ctx context.Context, op opera
// field admissionregistrationv1beta1.ValidatingAdmissionPolicyBindingSpec.ParamRef has no validation
// field admissionregistrationv1beta1.ValidatingAdmissionPolicyBindingSpec.MatchResources has no validation
// field admissionregistrationv1beta1.ValidatingAdmissionPolicyBindingSpec.ValidationActions has no validation
// field admissionregistrationv1beta1.ValidatingAdmissionPolicyBindingSpec.ValidationActions
errs = append(errs,
func(fldPath *field.Path, obj, oldObj []admissionregistrationv1beta1.ValidationAction, oldValueCorrelated bool) (errs field.ErrorList) {
// don't revalidate unchanged data
if oldValueCorrelated && op.Type == operation.Update && equality.Semantic.DeepEqual(obj, oldObj) {
return nil
}
// call field-attached validations
earlyReturn := false
if e := validate.RequiredSlice(ctx, op, fldPath, obj, oldObj); len(e) != 0 {
errs = append(errs, e...)
earlyReturn = true
}
if earlyReturn {
return // do not proceed
}
return
}(fldPath.Child("validationActions"), obj.ValidationActions, safe.Field(oldObj, func(oldObj *admissionregistrationv1beta1.ValidatingAdmissionPolicyBindingSpec) []admissionregistrationv1beta1.ValidationAction {
return oldObj.ValidationActions
}), oldObj != nil)...)
return errs
}

View File

@@ -939,7 +939,7 @@ func validateValidationActions(va []admissionregistration.ValidationAction, fldP
allErrors = append(allErrors, field.Invalid(fldPath, va, "must not contain both Deny and Warn (repeating the same validation failure information in the API response and headers serves no purpose)"))
}
if len(actions) == 0 {
allErrors = append(allErrors, field.Required(fldPath, "at least one validation action is required"))
allErrors = append(allErrors, field.Required(fldPath, "at least one validation action is required")).MarkCoveredByDeclarative()
}
return allErrors
}

View File

@@ -2554,7 +2554,7 @@ func schema_k8sio_api_admissionregistration_v1_ValidatingAdmissionPolicyBindingS
},
},
},
Required: []string{"policyName"},
Required: []string{"policyName", "validationActions"},
},
},
Dependencies: []string{
@@ -4149,7 +4149,7 @@ func schema_k8sio_api_admissionregistration_v1alpha1_ValidatingAdmissionPolicyBi
},
},
},
Required: []string{"policyName"},
Required: []string{"policyName", "validationActions"},
},
},
Dependencies: []string{
@@ -5751,7 +5751,7 @@ func schema_k8sio_api_admissionregistration_v1beta1_ValidatingAdmissionPolicyBin
},
},
},
Required: []string{"policyName"},
Required: []string{"policyName", "validationActions"},
},
},
Dependencies: []string{

View File

@@ -51,12 +51,18 @@ func testDeclarativeValidate(t *testing.T, apiVersion string) {
"valid": {
input: mkValidBinding(),
},
"invalid policyName": {
"spec.policyName is required": {
input: mkValidBinding(tweakPolicyName("")),
expectedErrs: field.ErrorList{
field.Required(field.NewPath("spec", "policyName"), ""),
},
},
"spec.validationActions is required": {
input: mkValidBinding(tweakValidateActions([]admissionregistration.ValidationAction{})),
expectedErrs: field.ErrorList{
field.Required(field.NewPath("spec", "validationActions"), ""),
},
},
// TODO: Add more test cases
}
for k, tc := range testCases {
@@ -84,13 +90,20 @@ func testDeclarativeValidateUpdate(t *testing.T, apiVersion string) {
oldObj: mkValidBinding(),
updateObj: mkValidBinding(),
},
"invalid update name": {
"update with empty spec.policyName": {
oldObj: mkValidBinding(func(obj *admissionregistration.ValidatingAdmissionPolicyBinding) { obj.ResourceVersion = "1" }),
updateObj: mkValidBinding(tweakPolicyName("")),
expectedErrs: field.ErrorList{
field.Required(field.NewPath("spec", "policyName"), ""),
},
},
"update with empty spec.validationActions": {
oldObj: mkValidBinding(),
updateObj: mkValidBinding(tweakValidateActions([]admissionregistration.ValidationAction{})),
expectedErrs: field.ErrorList{
field.Required(field.NewPath("spec", "validationActions"), ""),
},
},
// TODO: Add more test cases
}
for k, tc := range testCases {
@@ -131,3 +144,9 @@ func tweakPolicyName(policyName string) func(obj *admissionregistration.Validati
obj.Spec.PolicyName = policyName
}
}
func tweakValidateActions(actions []admissionregistration.ValidationAction) func(*admissionregistration.ValidatingAdmissionPolicyBinding) {
return func(obj *admissionregistration.ValidatingAdmissionPolicyBinding) {
obj.Spec.ValidationActions = actions
}
}

View File

@@ -682,6 +682,8 @@ message ValidatingAdmissionPolicyBindingSpec {
//
// Required.
// +listType=set
// +required
// +k8s:required
repeated string validationActions = 4;
}

View File

@@ -533,6 +533,8 @@ type ValidatingAdmissionPolicyBindingSpec struct {
//
// Required.
// +listType=set
// +required
// +k8s:required
ValidationActions []ValidationAction `json:"validationActions,omitempty" protobuf:"bytes,4,rep,name=validationActions"`
}

View File

@@ -705,6 +705,8 @@ message ValidatingAdmissionPolicyBindingSpec {
//
// Required.
// +listType=set
// +required
// +k8s:required
repeated string validationActions = 4;
}

View File

@@ -473,6 +473,8 @@ type ValidatingAdmissionPolicyBindingSpec struct {
//
// Required.
// +listType=set
// +required
// +k8s:required
ValidationActions []ValidationAction `json:"validationActions,omitempty" protobuf:"bytes,4,rep,name=validationActions"`
}

View File

@@ -931,6 +931,8 @@ message ValidatingAdmissionPolicyBindingSpec {
//
// Required.
// +listType=set
// +required
// +k8s:required
repeated string validationActions = 4;
}

View File

@@ -486,6 +486,8 @@ type ValidatingAdmissionPolicyBindingSpec struct {
//
// Required.
// +listType=set
// +required
// +k8s:required
ValidationActions []ValidationAction `json:"validationActions,omitempty" protobuf:"bytes,4,rep,name=validationActions"`
}