@@ -41,6 +41,7 @@ import (
4141 "k8s.io/apiserver/pkg/cel/environment"
4242 "k8s.io/apiserver/pkg/cel/library"
4343 "k8s.io/utils/pointer"
44+ "k8s.io/utils/ptr"
4445)
4546
4647type validationMatch struct {
@@ -9650,6 +9651,157 @@ func TestValidateCustomResourceDefinitionValidation(t *testing.T) {
96509651 required ("spec.validation.openAPIV3Schema.properties[f].x-kubernetes-validations[0].messageExpression" ),
96519652 },
96529653 },
9654+ {
9655+ name : "forbid transition rule on element of list of type atomic when optionalOldSelf is set" ,
9656+ opts : validationOptions {requireStructuralSchema : true },
9657+ input : apiextensions.CustomResourceValidation {
9658+ OpenAPIV3Schema : & apiextensions.JSONSchemaProps {
9659+ Type : "object" ,
9660+ Properties : map [string ]apiextensions.JSONSchemaProps {
9661+ "value" : {
9662+ Type : "array" ,
9663+ XListType : strPtr ("atomic" ),
9664+ Items : & apiextensions.JSONSchemaPropsOrArray {
9665+ Schema : & apiextensions.JSONSchemaProps {
9666+ Type : "string" ,
9667+ MaxLength : int64ptr (10 ),
9668+ XValidations : apiextensions.ValidationRules {
9669+ {Rule : `self == oldSelf.orValue("")` , OptionalOldSelf : ptr .To (true )},
9670+ },
9671+ },
9672+ },
9673+ },
9674+ },
9675+ },
9676+ },
9677+ expectedErrors : []validationMatch {
9678+ invalid ("spec.validation.openAPIV3Schema.properties[value].items.x-kubernetes-validations[0].rule" ),
9679+ },
9680+ },
9681+ {
9682+ name : "forbid transition rule on element of list defaulting to type atomic when optionalOldSelf is set" ,
9683+ opts : validationOptions {requireStructuralSchema : true },
9684+ input : apiextensions.CustomResourceValidation {
9685+ OpenAPIV3Schema : & apiextensions.JSONSchemaProps {
9686+ Type : "object" ,
9687+ Properties : map [string ]apiextensions.JSONSchemaProps {
9688+ "value" : {
9689+ Type : "array" ,
9690+ Items : & apiextensions.JSONSchemaPropsOrArray {
9691+ Schema : & apiextensions.JSONSchemaProps {
9692+ Type : "string" ,
9693+ MaxLength : int64ptr (10 ),
9694+ XValidations : apiextensions.ValidationRules {
9695+ {Rule : `self == oldSelf.orValue("")` , OptionalOldSelf : ptr .To (true )},
9696+ },
9697+ },
9698+ },
9699+ },
9700+ },
9701+ },
9702+ },
9703+ expectedErrors : []validationMatch {
9704+ invalid ("spec.validation.openAPIV3Schema.properties[value].items.x-kubernetes-validations[0].rule" ),
9705+ },
9706+ },
9707+ {
9708+ name : "forbid transition rule on element of list of type set when optionalOldSelf is set" ,
9709+ opts : validationOptions {requireStructuralSchema : true },
9710+ input : apiextensions.CustomResourceValidation {
9711+ OpenAPIV3Schema : & apiextensions.JSONSchemaProps {
9712+ Type : "object" ,
9713+ Properties : map [string ]apiextensions.JSONSchemaProps {
9714+ "value" : {
9715+ Type : "array" ,
9716+ MaxItems : int64ptr (10 ),
9717+ XListType : strPtr ("set" ),
9718+ Items : & apiextensions.JSONSchemaPropsOrArray {
9719+ Schema : & apiextensions.JSONSchemaProps {
9720+ Type : "string" ,
9721+ MaxLength : int64ptr (10 ),
9722+ XValidations : apiextensions.ValidationRules {
9723+ {Rule : `self == oldSelf.orValue("")` , OptionalOldSelf : ptr .To (true )},
9724+ },
9725+ },
9726+ },
9727+ },
9728+ },
9729+ },
9730+ },
9731+ expectedErrors : []validationMatch {
9732+ invalid ("spec.validation.openAPIV3Schema.properties[value].items.x-kubernetes-validations[0].rule" ),
9733+ },
9734+ },
9735+ {
9736+ name : "forbid transition rule on element of map of unrecognized type when optionalOldSelf is set" ,
9737+ opts : validationOptions {requireStructuralSchema : true },
9738+ input : apiextensions.CustomResourceValidation {
9739+ OpenAPIV3Schema : & apiextensions.JSONSchemaProps {
9740+ Type : "object" ,
9741+ Properties : map [string ]apiextensions.JSONSchemaProps {
9742+ "value" : {
9743+ Type : "object" ,
9744+ XMapType : strPtr ("future" ),
9745+ Properties : map [string ]apiextensions.JSONSchemaProps {
9746+ "subfield" : {
9747+ Type : "string" ,
9748+ MaxLength : int64ptr (10 ),
9749+ XValidations : apiextensions.ValidationRules {
9750+ {Rule : `self == oldSelf.orValue("")` , OptionalOldSelf : ptr .To (true )},
9751+ },
9752+ },
9753+ },
9754+ },
9755+ },
9756+ },
9757+ },
9758+ expectedErrors : []validationMatch {
9759+ invalid ("spec.validation.openAPIV3Schema.properties[value].properties[subfield].x-kubernetes-validations[0].rule" ),
9760+ unsupported ("spec.validation.openAPIV3Schema.properties[value].x-kubernetes-map-type" ),
9761+ },
9762+ },
9763+ {
9764+ name : "forbid setting optionalOldSelf to true if oldSelf is not used" ,
9765+ opts : validationOptions {requireStructuralSchema : true },
9766+ input : apiextensions.CustomResourceValidation {
9767+ OpenAPIV3Schema : & apiextensions.JSONSchemaProps {
9768+ Type : "object" ,
9769+ Properties : map [string ]apiextensions.JSONSchemaProps {
9770+ "value" : {
9771+ Type : "string" ,
9772+ MaxLength : int64ptr (10 ),
9773+ XValidations : apiextensions.ValidationRules {
9774+ {Rule : `self == "foo"` , OptionalOldSelf : ptr .To (true )},
9775+ },
9776+ },
9777+ },
9778+ },
9779+ },
9780+ expectedErrors : []validationMatch {
9781+ invalid ("spec.validation.openAPIV3Schema.properties[value].x-kubernetes-validations[0].optionalOldSelf" ),
9782+ },
9783+ },
9784+ {
9785+ name : "forbid setting optionalOldSelf to false if oldSelf is not used" ,
9786+ opts : validationOptions {requireStructuralSchema : true },
9787+ input : apiextensions.CustomResourceValidation {
9788+ OpenAPIV3Schema : & apiextensions.JSONSchemaProps {
9789+ Type : "object" ,
9790+ Properties : map [string ]apiextensions.JSONSchemaProps {
9791+ "value" : {
9792+ Type : "string" ,
9793+ MaxLength : int64ptr (10 ),
9794+ XValidations : apiextensions.ValidationRules {
9795+ {Rule : `self == "foo"` , OptionalOldSelf : ptr .To (false )},
9796+ },
9797+ },
9798+ },
9799+ },
9800+ },
9801+ expectedErrors : []validationMatch {
9802+ invalid ("spec.validation.openAPIV3Schema.properties[value].x-kubernetes-validations[0].optionalOldSelf" ),
9803+ },
9804+ },
96539805 }
96549806 for _ , tt := range tests {
96559807 t .Run (tt .name , func (t * testing.T ) {
0 commit comments