Skip to content

Commit a48a92c

Browse files
cici37ballista01
andauthored
Allowing direct CEL reserved keyword usage in CRD (kubernetes#126188)
* automatically escape reserved keywords for direct usage * Add reserved keyword support in a ratcheting way, add tests. --------- Co-authored-by: Wenxue Zhao <[email protected]>
1 parent fa4b8f3 commit a48a92c

File tree

7 files changed

+446
-57
lines changed

7 files changed

+446
-57
lines changed

staging/src/k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/validation/validation_test.go

Lines changed: 300 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9013,7 +9013,7 @@ func TestValidateCustomResourceDefinitionValidation(t *testing.T) {
90139013
},
90149014
},
90159015
{
9016-
name: "valid x-kubernetes-validations for escaping",
9016+
name: "invalid x-kubernetes-validations for escaping (keywords are invalid field names before v1.30)",
90179017
input: apiextensions.CustomResourceValidation{
90189018
OpenAPIV3Schema: &apiextensions.JSONSchemaProps{
90199019
Type: "object",
@@ -9024,12 +9024,75 @@ func TestValidateCustomResourceDefinitionValidation(t *testing.T) {
90249024
{
90259025
Rule: "self.__namespace__ > 0",
90269026
},
9027+
{
9028+
Rule: "self.if > 0",
9029+
},
9030+
{
9031+
Rule: "self.namespace > 0",
9032+
},
9033+
{
9034+
Rule: "self.as > 0",
9035+
},
9036+
{
9037+
Rule: "self.break > 0",
9038+
},
9039+
{
9040+
Rule: "self.const > 0",
9041+
},
9042+
{
9043+
Rule: "self.continue > 0",
9044+
},
9045+
{
9046+
Rule: "self.else > 0",
9047+
},
9048+
{
9049+
Rule: "self.for > 0",
9050+
},
9051+
{
9052+
Rule: "self.function > 0",
9053+
},
9054+
{
9055+
Rule: "self.import > 0",
9056+
},
9057+
{
9058+
Rule: "self.let > 0",
9059+
},
9060+
{
9061+
Rule: "self.loop > 0",
9062+
},
9063+
{
9064+
Rule: "self.package > 0",
9065+
},
9066+
{
9067+
Rule: "self.return > 0",
9068+
},
9069+
{
9070+
Rule: "self.var > 0",
9071+
},
9072+
{
9073+
Rule: "self.void > 0",
9074+
},
9075+
{
9076+
Rule: "self.while > 0",
9077+
},
90279078
{
90289079
Rule: "self.self > 0",
90299080
},
90309081
{
90319082
Rule: "self.int > 0",
90329083
},
9084+
{
9085+
Rule: "self.true > 0",
9086+
},
9087+
{
9088+
Rule: "self.false > 0",
9089+
},
9090+
{
9091+
Rule: "self.null > 0",
9092+
},
9093+
{
9094+
Rule: "self.in > 0",
9095+
},
90339096
},
90349097
Properties: map[string]apiextensions.JSONSchemaProps{
90359098
"if": {
@@ -9038,33 +9101,181 @@ func TestValidateCustomResourceDefinitionValidation(t *testing.T) {
90389101
"namespace": {
90399102
Type: "integer",
90409103
},
9104+
"as": {
9105+
Type: "integer",
9106+
},
9107+
"break": {
9108+
Type: "integer",
9109+
},
9110+
"const": {
9111+
Type: "integer",
9112+
},
9113+
"continue": {
9114+
Type: "integer",
9115+
},
9116+
"else": {
9117+
Type: "integer",
9118+
},
9119+
"for": {
9120+
Type: "integer",
9121+
},
9122+
"function": {
9123+
Type: "integer",
9124+
},
9125+
"import": {
9126+
Type: "integer",
9127+
},
9128+
"let": {
9129+
Type: "integer",
9130+
},
9131+
"loop": {
9132+
Type: "integer",
9133+
},
9134+
"package": {
9135+
Type: "integer",
9136+
},
9137+
"return": {
9138+
Type: "integer",
9139+
},
9140+
"var": {
9141+
Type: "integer",
9142+
},
9143+
"void": {
9144+
Type: "integer",
9145+
},
9146+
"while": {
9147+
Type: "integer",
9148+
},
90419149
"self": {
90429150
Type: "integer",
90439151
},
90449152
"int": {
90459153
Type: "integer",
90469154
},
9155+
"true": {
9156+
Type: "integer",
9157+
},
9158+
"false": {
9159+
Type: "integer",
9160+
},
9161+
"null": {
9162+
Type: "integer",
9163+
},
9164+
"in": {
9165+
Type: "integer",
9166+
},
90479167
},
90489168
},
90499169
},
90509170
opts: validationOptions{
90519171
requireStructuralSchema: true,
9172+
celEnvironmentSet: environment.MustBaseEnvSet(version.MajorMinor(1, 30), true),
9173+
},
9174+
expectedErrors: []validationMatch{
9175+
invalid("spec.validation.openAPIV3Schema.x-kubernetes-validations[2].rule"),
9176+
invalid("spec.validation.openAPIV3Schema.x-kubernetes-validations[3].rule"),
9177+
invalid("spec.validation.openAPIV3Schema.x-kubernetes-validations[4].rule"),
9178+
invalid("spec.validation.openAPIV3Schema.x-kubernetes-validations[5].rule"),
9179+
invalid("spec.validation.openAPIV3Schema.x-kubernetes-validations[6].rule"),
9180+
invalid("spec.validation.openAPIV3Schema.x-kubernetes-validations[7].rule"),
9181+
invalid("spec.validation.openAPIV3Schema.x-kubernetes-validations[8].rule"),
9182+
invalid("spec.validation.openAPIV3Schema.x-kubernetes-validations[9].rule"),
9183+
invalid("spec.validation.openAPIV3Schema.x-kubernetes-validations[10].rule"),
9184+
invalid("spec.validation.openAPIV3Schema.x-kubernetes-validations[11].rule"),
9185+
invalid("spec.validation.openAPIV3Schema.x-kubernetes-validations[12].rule"),
9186+
invalid("spec.validation.openAPIV3Schema.x-kubernetes-validations[13].rule"),
9187+
invalid("spec.validation.openAPIV3Schema.x-kubernetes-validations[14].rule"),
9188+
invalid("spec.validation.openAPIV3Schema.x-kubernetes-validations[15].rule"),
9189+
invalid("spec.validation.openAPIV3Schema.x-kubernetes-validations[16].rule"),
9190+
invalid("spec.validation.openAPIV3Schema.x-kubernetes-validations[17].rule"),
9191+
invalid("spec.validation.openAPIV3Schema.x-kubernetes-validations[18].rule"),
9192+
invalid("spec.validation.openAPIV3Schema.x-kubernetes-validations[21].rule"),
9193+
invalid("spec.validation.openAPIV3Schema.x-kubernetes-validations[22].rule"),
9194+
invalid("spec.validation.openAPIV3Schema.x-kubernetes-validations[23].rule"),
9195+
invalid("spec.validation.openAPIV3Schema.x-kubernetes-validations[24].rule"),
90529196
},
90539197
},
90549198
{
9055-
name: "invalid x-kubernetes-validations for escaping",
9199+
name: "valid x-kubernetes-validations for escaping",
90569200
input: apiextensions.CustomResourceValidation{
90579201
OpenAPIV3Schema: &apiextensions.JSONSchemaProps{
90589202
Type: "object",
90599203
XValidations: apiextensions.ValidationRules{
9204+
{
9205+
Rule: "self.__if__ > 0",
9206+
},
9207+
{
9208+
Rule: "self.__namespace__ > 0",
9209+
},
90609210
{
90619211
Rule: "self.if > 0",
90629212
},
90639213
{
90649214
Rule: "self.namespace > 0",
90659215
},
90669216
{
9067-
Rule: "self.unknownProp > 0",
9217+
Rule: "self.as > 0",
9218+
},
9219+
{
9220+
Rule: "self.break > 0",
9221+
},
9222+
{
9223+
Rule: "self.const > 0",
9224+
},
9225+
{
9226+
Rule: "self.continue > 0",
9227+
},
9228+
{
9229+
Rule: "self.else > 0",
9230+
},
9231+
{
9232+
Rule: "self.for > 0",
9233+
},
9234+
{
9235+
Rule: "self.function > 0",
9236+
},
9237+
{
9238+
Rule: "self.import > 0",
9239+
},
9240+
{
9241+
Rule: "self.let > 0",
9242+
},
9243+
{
9244+
Rule: "self.loop > 0",
9245+
},
9246+
{
9247+
Rule: "self.package > 0",
9248+
},
9249+
{
9250+
Rule: "self.return > 0",
9251+
},
9252+
{
9253+
Rule: "self.var > 0",
9254+
},
9255+
{
9256+
Rule: "self.void > 0",
9257+
},
9258+
{
9259+
Rule: "self.while > 0",
9260+
},
9261+
{
9262+
Rule: "self.self > 0",
9263+
},
9264+
{
9265+
Rule: "self.int > 0",
9266+
},
9267+
// reserved keywords `true`, `false`, `null` and `in` are not supported
9268+
{
9269+
Rule: "self.true > 0",
9270+
},
9271+
{
9272+
Rule: "self.false > 0",
9273+
},
9274+
{
9275+
Rule: "self.null > 0",
9276+
},
9277+
{
9278+
Rule: "self.in > 0",
90689279
},
90699280
},
90709281
Properties: map[string]apiextensions.JSONSchemaProps{
@@ -9074,13 +9285,97 @@ func TestValidateCustomResourceDefinitionValidation(t *testing.T) {
90749285
"namespace": {
90759286
Type: "integer",
90769287
},
9288+
"as": {
9289+
Type: "integer",
9290+
},
9291+
"break": {
9292+
Type: "integer",
9293+
},
9294+
"const": {
9295+
Type: "integer",
9296+
},
9297+
"continue": {
9298+
Type: "integer",
9299+
},
9300+
"else": {
9301+
Type: "integer",
9302+
},
9303+
"for": {
9304+
Type: "integer",
9305+
},
9306+
"function": {
9307+
Type: "integer",
9308+
},
9309+
"import": {
9310+
Type: "integer",
9311+
},
9312+
"let": {
9313+
Type: "integer",
9314+
},
9315+
"loop": {
9316+
Type: "integer",
9317+
},
9318+
"package": {
9319+
Type: "integer",
9320+
},
9321+
"return": {
9322+
Type: "integer",
9323+
},
9324+
"var": {
9325+
Type: "integer",
9326+
},
9327+
"void": {
9328+
Type: "integer",
9329+
},
9330+
"while": {
9331+
Type: "integer",
9332+
},
9333+
"self": {
9334+
Type: "integer",
9335+
},
9336+
"int": {
9337+
Type: "integer",
9338+
},
9339+
"true": {
9340+
Type: "integer",
9341+
},
9342+
"false": {
9343+
Type: "integer",
9344+
},
9345+
"null": {
9346+
Type: "integer",
9347+
},
9348+
"in": {
9349+
Type: "integer",
9350+
},
9351+
},
9352+
},
9353+
},
9354+
opts: validationOptions{
9355+
requireStructuralSchema: true,
9356+
celEnvironmentSet: environment.MustBaseEnvSet(version.MajorMinor(1, 31), true),
9357+
},
9358+
expectedErrors: []validationMatch{
9359+
invalid("spec.validation.openAPIV3Schema.x-kubernetes-validations[21].rule"),
9360+
invalid("spec.validation.openAPIV3Schema.x-kubernetes-validations[22].rule"),
9361+
invalid("spec.validation.openAPIV3Schema.x-kubernetes-validations[23].rule"),
9362+
invalid("spec.validation.openAPIV3Schema.x-kubernetes-validations[24].rule"),
9363+
},
9364+
},
9365+
{
9366+
name: "invalid x-kubernetes-validations for unknown property",
9367+
input: apiextensions.CustomResourceValidation{
9368+
OpenAPIV3Schema: &apiextensions.JSONSchemaProps{
9369+
Type: "object",
9370+
XValidations: apiextensions.ValidationRules{
9371+
{
9372+
Rule: "self.unknownProp > 0",
9373+
},
90779374
},
90789375
},
90799376
},
90809377
expectedErrors: []validationMatch{
90819378
invalid("spec.validation.openAPIV3Schema.x-kubernetes-validations[0].rule"),
9082-
invalid("spec.validation.openAPIV3Schema.x-kubernetes-validations[1].rule"),
9083-
invalid("spec.validation.openAPIV3Schema.x-kubernetes-validations[2].rule"),
90849379
},
90859380
opts: validationOptions{
90869381
requireStructuralSchema: true,

0 commit comments

Comments
 (0)