Skip to content

Commit e21b55c

Browse files
committed
Add EscapingExamples
Adds a set of example which demonstrate the effects of escaping when generating validation rules. Specifically: * `` vs "" for rule quoting * "" vs r'' in CEL expressions These tests justify the following general recommendations to avoid complex escaping: * Always prefer `` for validation rules * Always prefer r'' for strings in CEL expressions
1 parent ebe535b commit e21b55c

File tree

12 files changed

+641
-1
lines changed

12 files changed

+641
-1
lines changed

example/v1/tests/stableconfigtypes.example.openshift.io/AAA_ungated.yaml

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,144 @@ tests:
183183
requiredMember: foo
184184
immutableField: foo
185185
expectedError: "Invalid value: \"object\": requiredMember is required when type is RequiredMember, and forbidden otherwise"
186+
187+
# Escaping test fields - validating Pattern vs CEL escaping behavior
188+
- name: Should accept valid value for escapingTestPattern (Pattern marker)
189+
initial: |
190+
apiVersion: example.openshift.io/v1
191+
kind: StableConfigType
192+
spec:
193+
immutableField: foo
194+
escapingExamples:
195+
escapingTestPattern: "a123"
196+
expected: |
197+
apiVersion: example.openshift.io/v1
198+
kind: StableConfigType
199+
spec:
200+
immutableField: foo
201+
nonZeroDefault: 8
202+
escapingExamples:
203+
escapingTestPattern: "a123"
204+
205+
- name: Should reject invalid value for escapingTestPattern (Pattern marker)
206+
initial: |
207+
apiVersion: example.openshift.io/v1
208+
kind: StableConfigType
209+
spec:
210+
immutableField: foo
211+
escapingExamples:
212+
escapingTestPattern: "A123"
213+
expectedError: "should match"
214+
215+
- name: Should accept valid value for escapingTestPatternQuoted (Pattern marker with quoted string)
216+
initial: |
217+
apiVersion: example.openshift.io/v1
218+
kind: StableConfigType
219+
spec:
220+
immutableField: foo
221+
escapingExamples:
222+
escapingTestPatternQuoted: "b456"
223+
expected: |
224+
apiVersion: example.openshift.io/v1
225+
kind: StableConfigType
226+
spec:
227+
immutableField: foo
228+
nonZeroDefault: 8
229+
escapingExamples:
230+
escapingTestPatternQuoted: "b456"
231+
232+
- name: Should reject invalid value for escapingTestPatternQuoted (Pattern marker with quoted string)
233+
initial: |
234+
apiVersion: example.openshift.io/v1
235+
kind: StableConfigType
236+
spec:
237+
immutableField: foo
238+
escapingExamples:
239+
escapingTestPatternQuoted: "B456"
240+
expectedError: "should match"
241+
242+
- name: Should accept valid value for escapingTestCELQuoted (CEL with quoted string)
243+
initial: |
244+
apiVersion: example.openshift.io/v1
245+
kind: StableConfigType
246+
spec:
247+
immutableField: foo
248+
escapingExamples:
249+
escapingTestCELQuoted: "z99"
250+
expected: |
251+
apiVersion: example.openshift.io/v1
252+
kind: StableConfigType
253+
spec:
254+
immutableField: foo
255+
nonZeroDefault: 8
256+
escapingExamples:
257+
escapingTestCELQuoted: "z99"
258+
259+
- name: Should reject invalid value for escapingTestCELQuoted (CEL with quoted string)
260+
initial: |
261+
apiVersion: example.openshift.io/v1
262+
kind: StableConfigType
263+
spec:
264+
immutableField: foo
265+
escapingExamples:
266+
escapingTestCELQuoted: "123"
267+
expectedError: "must match pattern with quoted string escaping"
268+
269+
- name: Should accept valid value for escapingTestCELRaw (CEL with raw string)
270+
initial: |
271+
apiVersion: example.openshift.io/v1
272+
kind: StableConfigType
273+
spec:
274+
immutableField: foo
275+
escapingExamples:
276+
escapingTestCELRaw: "b456"
277+
expected: |
278+
apiVersion: example.openshift.io/v1
279+
kind: StableConfigType
280+
spec:
281+
immutableField: foo
282+
nonZeroDefault: 8
283+
escapingExamples:
284+
escapingTestCELRaw: "b456"
285+
286+
- name: Should reject invalid value for escapingTestCELRaw (CEL with raw string)
287+
initial: |
288+
apiVersion: example.openshift.io/v1
289+
kind: StableConfigType
290+
spec:
291+
immutableField: foo
292+
escapingExamples:
293+
escapingTestCELRaw: "B456"
294+
expectedError: "must match pattern with raw string escaping"
295+
296+
# Tests for CEL raw string prefix (r'...')
297+
- name: Should accept valid value for escapingTestCELRawPrefix (CEL raw string with r prefix)
298+
initial: |
299+
apiVersion: example.openshift.io/v1
300+
kind: StableConfigType
301+
spec:
302+
immutableField: foo
303+
escapingExamples:
304+
escapingTestCELRawPrefix: "c789"
305+
expected: |
306+
apiVersion: example.openshift.io/v1
307+
kind: StableConfigType
308+
spec:
309+
immutableField: foo
310+
nonZeroDefault: 8
311+
escapingExamples:
312+
escapingTestCELRawPrefix: "c789"
313+
314+
- name: Should reject invalid value for escapingTestCELRawPrefix (CEL raw string with r prefix)
315+
initial: |
316+
apiVersion: example.openshift.io/v1
317+
kind: StableConfigType
318+
spec:
319+
immutableField: foo
320+
escapingExamples:
321+
escapingTestCELRawPrefix: "C789"
322+
expectedError: "must match pattern with CEL raw string"
323+
186324
onUpdate:
187325
- name: Should not allow changing an immutable field
188326
initial: |

example/v1/types_stable.go

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,12 @@ type StableConfigTypeSpec struct {
100100
// subnetsWithExclusions demonstrates how to validate a list of subnets with exclusions
101101
// +optional
102102
SubnetsWithExclusions SubnetsWithExclusions `json:"subnetsWithExclusions,omitempty"`
103+
104+
// escapingExamples demonstrates regex escaping requirements across different validation contexts.
105+
// This field provides comprehensive examples of how to properly escape regex patterns
106+
// depending on whether you're using Pattern markers or CEL expressions with various string types.
107+
// +optional
108+
EscapingExamples EscapingExamples `json:"escapingExamples,omitempty"`
103109
}
104110

105111
// SetValue defines the types allowed in string set type
@@ -208,6 +214,47 @@ type SubnetsWithExclusions struct {
208214
// +kubebuilder:validation:MaxLength:=43
209215
type CIDR string
210216

217+
// EscapingExamples demonstrates regex escaping requirements across different validation contexts.
218+
// Each field validates the same pattern (lowercase letter + digits) but uses different
219+
// string literal types, requiring different escaping.
220+
type EscapingExamples struct {
221+
// escapingTestPattern demonstrates use of the Pattern marker with raw string literal (backticks).
222+
// Must match format: lowercase letter followed by one or more digits (e.g., "a123", "z99").
223+
// Pattern uses raw string literal (backticks), so single backslash.
224+
// +kubebuilder:validation:Pattern=`^[a-z]\d+$`
225+
// +optional
226+
EscapingTestPattern *string `json:"escapingTestPattern,omitempty"`
227+
228+
// escapingTestPatternQuoted demonstrates use of the Pattern marker with Go quoted string.
229+
// Must match format: lowercase letter followed by one or more digits (e.g., "b456", "c789").
230+
// Quoted strings interpret escape sequences, requiring double backslash for regex metacharacters.
231+
// +kubebuilder:validation:Pattern="^[a-z]\\d+$"
232+
// +optional
233+
EscapingTestPatternQuoted *string `json:"escapingTestPatternQuoted,omitempty"`
234+
235+
// escapingTestCELQuoted demonstrates use of CEL .matches() with Go quoted string.
236+
// Must match format: lowercase letter followed by one or more digits (e.g., "a123", "z99").
237+
// Quoted strings require double backslash for regex metacharacters.
238+
// +kubebuilder:validation:XValidation:rule="self.matches('^[a-z]\\\\d+$')",message="must match pattern with quoted string escaping"
239+
// +optional
240+
EscapingTestCELQuoted *string `json:"escapingTestCELQuoted,omitempty"`
241+
242+
// escapingTestCELRaw demonstrates use of CEL .matches() with raw string literal (backticks).
243+
// Must match format: lowercase letter followed by one or more digits (e.g., "a123", "z99").
244+
// Raw string literals (backticks) preserve backslashes literally, same as Pattern.
245+
// +kubebuilder:validation:XValidation:rule=`self.matches('^[a-z]\\d+$')`,message="must match pattern with raw string escaping"
246+
// +optional
247+
EscapingTestCELRaw *string `json:"escapingTestCELRaw,omitempty"`
248+
249+
// escapingTestCELRawPrefix demonstrates use of CEL .matches() with raw
250+
// string literal (backticks) + CEL raw string (r prefix).
251+
// Must match format: lowercase letter followed by one or more digits (e.g., "a123", "z99").
252+
// Tests whether CEL's r'...' raw string syntax reduces backslash requirements.
253+
// +kubebuilder:validation:XValidation:rule=`self.matches(r'^[a-z]\d+$')`,message="must match pattern with CEL raw string"
254+
// +optional
255+
EscapingTestCELRawPrefix *string `json:"escapingTestCELRawPrefix,omitempty"`
256+
}
257+
211258
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
212259
// +openshift:compatibility-gen:level=1
213260

example/v1/zz_generated.crd-manifests/0000_50_my-operator_01_stableconfigtypes-CustomNoUpgrade.crd.yaml

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,55 @@ spec:
7979
description: coolNewField is a field that is for tech preview only. On
8080
normal clusters this shouldn't be present
8181
type: string
82+
escapingExamples:
83+
description: |-
84+
escapingExamples demonstrates regex escaping requirements across different validation contexts.
85+
This field provides comprehensive examples of how to properly escape regex patterns
86+
depending on whether you're using Pattern markers or CEL expressions with various string types.
87+
properties:
88+
escapingTestCELQuoted:
89+
description: |-
90+
escapingTestCELQuoted demonstrates use of CEL .matches() with Go quoted string.
91+
Must match format: lowercase letter followed by one or more digits (e.g., "a123", "z99").
92+
Quoted strings require double backslash for regex metacharacters.
93+
type: string
94+
x-kubernetes-validations:
95+
- message: must match pattern with quoted string escaping
96+
rule: self.matches('^[a-z]\\d+$')
97+
escapingTestCELRaw:
98+
description: |-
99+
escapingTestCELRaw demonstrates use of CEL .matches() with raw string literal (backticks).
100+
Must match format: lowercase letter followed by one or more digits (e.g., "a123", "z99").
101+
Raw string literals (backticks) preserve backslashes literally, same as Pattern.
102+
type: string
103+
x-kubernetes-validations:
104+
- message: must match pattern with raw string escaping
105+
rule: self.matches('^[a-z]\\d+$')
106+
escapingTestCELRawPrefix:
107+
description: |-
108+
escapingTestCELRawPrefix demonstrates use of CEL .matches() with raw
109+
string literal (backticks) + CEL raw string (r prefix).
110+
Must match format: lowercase letter followed by one or more digits (e.g., "a123", "z99").
111+
Tests whether CEL's r'...' raw string syntax reduces backslash requirements.
112+
type: string
113+
x-kubernetes-validations:
114+
- message: must match pattern with CEL raw string
115+
rule: self.matches(r'^[a-z]\d+$')
116+
escapingTestPattern:
117+
description: |-
118+
escapingTestPattern demonstrates use of the Pattern marker with raw string literal (backticks).
119+
Must match format: lowercase letter followed by one or more digits (e.g., "a123", "z99").
120+
Pattern uses raw string literal (backticks), so single backslash.
121+
pattern: ^[a-z]\d+$
122+
type: string
123+
escapingTestPatternQuoted:
124+
description: |-
125+
escapingTestPatternQuoted demonstrates use of the Pattern marker with Go quoted string.
126+
Must match format: lowercase letter followed by one or more digits (e.g., "b456", "c789").
127+
Quoted strings interpret escape sequences, requiring double backslash for regex metacharacters.
128+
pattern: ^[a-z]\d+$
129+
type: string
130+
type: object
82131
evolvingCollection:
83132
description: |-
84133
evolvingCollection demonstrates how to have a collection where the maximum number of items varies on cluster type.

example/v1/zz_generated.crd-manifests/0000_50_my-operator_01_stableconfigtypes-Default.crd.yaml

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,55 @@ spec:
7575
- message: optionalMember is forbidden when type is not OptionalMember
7676
rule: 'has(self.type) && self.type == ''OptionalMember'' ? true
7777
: !has(self.optionalMember)'
78+
escapingExamples:
79+
description: |-
80+
escapingExamples demonstrates regex escaping requirements across different validation contexts.
81+
This field provides comprehensive examples of how to properly escape regex patterns
82+
depending on whether you're using Pattern markers or CEL expressions with various string types.
83+
properties:
84+
escapingTestCELQuoted:
85+
description: |-
86+
escapingTestCELQuoted demonstrates use of CEL .matches() with Go quoted string.
87+
Must match format: lowercase letter followed by one or more digits (e.g., "a123", "z99").
88+
Quoted strings require double backslash for regex metacharacters.
89+
type: string
90+
x-kubernetes-validations:
91+
- message: must match pattern with quoted string escaping
92+
rule: self.matches('^[a-z]\\d+$')
93+
escapingTestCELRaw:
94+
description: |-
95+
escapingTestCELRaw demonstrates use of CEL .matches() with raw string literal (backticks).
96+
Must match format: lowercase letter followed by one or more digits (e.g., "a123", "z99").
97+
Raw string literals (backticks) preserve backslashes literally, same as Pattern.
98+
type: string
99+
x-kubernetes-validations:
100+
- message: must match pattern with raw string escaping
101+
rule: self.matches('^[a-z]\\d+$')
102+
escapingTestCELRawPrefix:
103+
description: |-
104+
escapingTestCELRawPrefix demonstrates use of CEL .matches() with raw
105+
string literal (backticks) + CEL raw string (r prefix).
106+
Must match format: lowercase letter followed by one or more digits (e.g., "a123", "z99").
107+
Tests whether CEL's r'...' raw string syntax reduces backslash requirements.
108+
type: string
109+
x-kubernetes-validations:
110+
- message: must match pattern with CEL raw string
111+
rule: self.matches(r'^[a-z]\d+$')
112+
escapingTestPattern:
113+
description: |-
114+
escapingTestPattern demonstrates use of the Pattern marker with raw string literal (backticks).
115+
Must match format: lowercase letter followed by one or more digits (e.g., "a123", "z99").
116+
Pattern uses raw string literal (backticks), so single backslash.
117+
pattern: ^[a-z]\d+$
118+
type: string
119+
escapingTestPatternQuoted:
120+
description: |-
121+
escapingTestPatternQuoted demonstrates use of the Pattern marker with Go quoted string.
122+
Must match format: lowercase letter followed by one or more digits (e.g., "b456", "c789").
123+
Quoted strings interpret escape sequences, requiring double backslash for regex metacharacters.
124+
pattern: ^[a-z]\d+$
125+
type: string
126+
type: object
78127
evolvingCollection:
79128
description: |-
80129
evolvingCollection demonstrates how to have a collection where the maximum number of items varies on cluster type.

example/v1/zz_generated.crd-manifests/0000_50_my-operator_01_stableconfigtypes-DevPreviewNoUpgrade.crd.yaml

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,55 @@ spec:
7979
description: coolNewField is a field that is for tech preview only. On
8080
normal clusters this shouldn't be present
8181
type: string
82+
escapingExamples:
83+
description: |-
84+
escapingExamples demonstrates regex escaping requirements across different validation contexts.
85+
This field provides comprehensive examples of how to properly escape regex patterns
86+
depending on whether you're using Pattern markers or CEL expressions with various string types.
87+
properties:
88+
escapingTestCELQuoted:
89+
description: |-
90+
escapingTestCELQuoted demonstrates use of CEL .matches() with Go quoted string.
91+
Must match format: lowercase letter followed by one or more digits (e.g., "a123", "z99").
92+
Quoted strings require double backslash for regex metacharacters.
93+
type: string
94+
x-kubernetes-validations:
95+
- message: must match pattern with quoted string escaping
96+
rule: self.matches('^[a-z]\\d+$')
97+
escapingTestCELRaw:
98+
description: |-
99+
escapingTestCELRaw demonstrates use of CEL .matches() with raw string literal (backticks).
100+
Must match format: lowercase letter followed by one or more digits (e.g., "a123", "z99").
101+
Raw string literals (backticks) preserve backslashes literally, same as Pattern.
102+
type: string
103+
x-kubernetes-validations:
104+
- message: must match pattern with raw string escaping
105+
rule: self.matches('^[a-z]\\d+$')
106+
escapingTestCELRawPrefix:
107+
description: |-
108+
escapingTestCELRawPrefix demonstrates use of CEL .matches() with raw
109+
string literal (backticks) + CEL raw string (r prefix).
110+
Must match format: lowercase letter followed by one or more digits (e.g., "a123", "z99").
111+
Tests whether CEL's r'...' raw string syntax reduces backslash requirements.
112+
type: string
113+
x-kubernetes-validations:
114+
- message: must match pattern with CEL raw string
115+
rule: self.matches(r'^[a-z]\d+$')
116+
escapingTestPattern:
117+
description: |-
118+
escapingTestPattern demonstrates use of the Pattern marker with raw string literal (backticks).
119+
Must match format: lowercase letter followed by one or more digits (e.g., "a123", "z99").
120+
Pattern uses raw string literal (backticks), so single backslash.
121+
pattern: ^[a-z]\d+$
122+
type: string
123+
escapingTestPatternQuoted:
124+
description: |-
125+
escapingTestPatternQuoted demonstrates use of the Pattern marker with Go quoted string.
126+
Must match format: lowercase letter followed by one or more digits (e.g., "b456", "c789").
127+
Quoted strings interpret escape sequences, requiring double backslash for regex metacharacters.
128+
pattern: ^[a-z]\d+$
129+
type: string
130+
type: object
82131
evolvingCollection:
83132
description: |-
84133
evolvingCollection demonstrates how to have a collection where the maximum number of items varies on cluster type.

0 commit comments

Comments
 (0)