Skip to content

Commit 6f42531

Browse files
sudiptob2shawnh2
andauthored
chore(installation): early validate presence of tag in image and imageRepository (envoyproxy#6354)
* chore(installation): early validate presence of tag in `image` and `imageRepository` field in KubernetesContainerSpec Signed-off-by: sudipto baral <[email protected]> * chore(installation): CEL validate presence of tag in image and imageRepository Signed-off-by: sudipto baral <[email protected]> * chore(installation): add more CEL test Signed-off-by: sudipto baral <[email protected]> * chore(installation): stricter CEL rules. Signed-off-by: sudipto baral <[email protected]> --------- Signed-off-by: sudipto baral <[email protected]> Co-authored-by: sh2 <[email protected]>
1 parent 9453572 commit 6f42531

File tree

6 files changed

+158
-2
lines changed

6 files changed

+158
-2
lines changed

api/v1alpha1/shared_types.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,13 +231,15 @@ type KubernetesContainerSpec struct {
231231
// Image specifies the EnvoyProxy container image to be used including a tag, instead of the default image.
232232
// This field is mutually exclusive with ImageRepository.
233233
//
234+
// +kubebuilder:validation:XValidation:rule="self.matches('^[a-zA-Z0-9._/-]+:[a-zA-Z0-9._-]+$')",message="Image must include a tag and allowed characters only (e.g., 'repo:tag')."
234235
// +optional
235236
Image *string `json:"image,omitempty"`
236237

237238
// ImageRepository specifies the container image repository to be used without specifying a tag.
238239
// The default tag will be used.
239240
// This field is mutually exclusive with Image.
240241
//
242+
// +kubebuilder:validation:XValidation:rule="self.matches('^[a-zA-Z0-9._/-]+$')",message="ImageRepository must contain only allowed characters and must not include a tag or any colons."
241243
// +optional
242244
ImageRepository *string `json:"imageRepository,omitempty"`
243245

charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_envoyproxies.yaml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -608,12 +608,20 @@ spec:
608608
Image specifies the EnvoyProxy container image to be used including a tag, instead of the default image.
609609
This field is mutually exclusive with ImageRepository.
610610
type: string
611+
x-kubernetes-validations:
612+
- message: Image must include a tag and allowed characters
613+
only (e.g., 'repo:tag').
614+
rule: self.matches('^[a-zA-Z0-9._/-]+:[a-zA-Z0-9._-]+$')
611615
imageRepository:
612616
description: |-
613617
ImageRepository specifies the container image repository to be used without specifying a tag.
614618
The default tag will be used.
615619
This field is mutually exclusive with Image.
616620
type: string
621+
x-kubernetes-validations:
622+
- message: ImageRepository must contain only allowed
623+
characters and must not include a tag or any colons.
624+
rule: self.matches('^[a-zA-Z0-9._/-]+$')
617625
resources:
618626
description: |-
619627
Resources required by this container.
@@ -4445,12 +4453,20 @@ spec:
44454453
Image specifies the EnvoyProxy container image to be used including a tag, instead of the default image.
44464454
This field is mutually exclusive with ImageRepository.
44474455
type: string
4456+
x-kubernetes-validations:
4457+
- message: Image must include a tag and allowed characters
4458+
only (e.g., 'repo:tag').
4459+
rule: self.matches('^[a-zA-Z0-9._/-]+:[a-zA-Z0-9._-]+$')
44484460
imageRepository:
44494461
description: |-
44504462
ImageRepository specifies the container image repository to be used without specifying a tag.
44514463
The default tag will be used.
44524464
This field is mutually exclusive with Image.
44534465
type: string
4466+
x-kubernetes-validations:
4467+
- message: ImageRepository must contain only allowed
4468+
characters and must not include a tag or any colons.
4469+
rule: self.matches('^[a-zA-Z0-9._/-]+$')
44544470
resources:
44554471
description: |-
44564472
Resources required by this container.

charts/gateway-helm/crds/generated/gateway.envoyproxy.io_envoyproxies.yaml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -607,12 +607,20 @@ spec:
607607
Image specifies the EnvoyProxy container image to be used including a tag, instead of the default image.
608608
This field is mutually exclusive with ImageRepository.
609609
type: string
610+
x-kubernetes-validations:
611+
- message: Image must include a tag and allowed characters
612+
only (e.g., 'repo:tag').
613+
rule: self.matches('^[a-zA-Z0-9._/-]+:[a-zA-Z0-9._-]+$')
610614
imageRepository:
611615
description: |-
612616
ImageRepository specifies the container image repository to be used without specifying a tag.
613617
The default tag will be used.
614618
This field is mutually exclusive with Image.
615619
type: string
620+
x-kubernetes-validations:
621+
- message: ImageRepository must contain only allowed
622+
characters and must not include a tag or any colons.
623+
rule: self.matches('^[a-zA-Z0-9._/-]+$')
616624
resources:
617625
description: |-
618626
Resources required by this container.
@@ -4444,12 +4452,20 @@ spec:
44444452
Image specifies the EnvoyProxy container image to be used including a tag, instead of the default image.
44454453
This field is mutually exclusive with ImageRepository.
44464454
type: string
4455+
x-kubernetes-validations:
4456+
- message: Image must include a tag and allowed characters
4457+
only (e.g., 'repo:tag').
4458+
rule: self.matches('^[a-zA-Z0-9._/-]+:[a-zA-Z0-9._-]+$')
44474459
imageRepository:
44484460
description: |-
44494461
ImageRepository specifies the container image repository to be used without specifying a tag.
44504462
The default tag will be used.
44514463
This field is mutually exclusive with Image.
44524464
type: string
4465+
x-kubernetes-validations:
4466+
- message: ImageRepository must contain only allowed
4467+
characters and must not include a tag or any colons.
4468+
rule: self.matches('^[a-zA-Z0-9._/-]+$')
44534469
resources:
44544470
description: |-
44554471
Resources required by this container.

test/cel-validation/envoyproxy_test.go

Lines changed: 92 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1545,7 +1545,7 @@ func TestEnvoyProxyProvider(t *testing.T) {
15451545
},
15461546
},
15471547
{
1548-
desc: "valid: image set, imageRepository not set",
1548+
desc: "valid: image set with tag, imageRepository not set",
15491549
mutate: func(envoy *egv1a1.EnvoyProxy) {
15501550
envoy.Spec = egv1a1.EnvoyProxySpec{
15511551
Provider: &egv1a1.EnvoyProxyProvider{
@@ -1563,7 +1563,7 @@ func TestEnvoyProxyProvider(t *testing.T) {
15631563
wantErrors: []string{},
15641564
},
15651565
{
1566-
desc: "valid: imageRepository set, image not set",
1566+
desc: "valid: imageRepository set without tag, image not set",
15671567
mutate: func(envoy *egv1a1.EnvoyProxy) {
15681568
envoy.Spec = egv1a1.EnvoyProxySpec{
15691569
Provider: &egv1a1.EnvoyProxyProvider{
@@ -1599,6 +1599,96 @@ func TestEnvoyProxyProvider(t *testing.T) {
15991599
},
16001600
wantErrors: []string{"Either image or imageRepository can be set."},
16011601
},
1602+
{
1603+
desc: "invalid: image set without tag",
1604+
mutate: func(envoy *egv1a1.EnvoyProxy) {
1605+
envoy.Spec = egv1a1.EnvoyProxySpec{
1606+
Provider: &egv1a1.EnvoyProxyProvider{
1607+
Type: egv1a1.ProviderTypeKubernetes,
1608+
Kubernetes: &egv1a1.EnvoyProxyKubernetesProvider{
1609+
EnvoyDeployment: &egv1a1.KubernetesDeploymentSpec{
1610+
Container: &egv1a1.KubernetesContainerSpec{
1611+
Image: ptr.To("envoyproxy/envoy"),
1612+
},
1613+
},
1614+
},
1615+
},
1616+
}
1617+
},
1618+
wantErrors: []string{"Image must include a tag and allowed characters only (e.g., 'repo:tag')."},
1619+
},
1620+
{
1621+
desc: "invalid: image ends with colon",
1622+
mutate: func(envoy *egv1a1.EnvoyProxy) {
1623+
envoy.Spec = egv1a1.EnvoyProxySpec{
1624+
Provider: &egv1a1.EnvoyProxyProvider{
1625+
Type: egv1a1.ProviderTypeKubernetes,
1626+
Kubernetes: &egv1a1.EnvoyProxyKubernetesProvider{
1627+
EnvoyDeployment: &egv1a1.KubernetesDeploymentSpec{
1628+
Container: &egv1a1.KubernetesContainerSpec{
1629+
Image: ptr.To("envoyproxy/envoy:"),
1630+
},
1631+
},
1632+
},
1633+
},
1634+
}
1635+
},
1636+
wantErrors: []string{"Image must include a tag and allowed characters only (e.g., 'repo:tag')."},
1637+
},
1638+
{
1639+
desc: "invalid: image starts with colon",
1640+
mutate: func(envoy *egv1a1.EnvoyProxy) {
1641+
envoy.Spec = egv1a1.EnvoyProxySpec{
1642+
Provider: &egv1a1.EnvoyProxyProvider{
1643+
Type: egv1a1.ProviderTypeKubernetes,
1644+
Kubernetes: &egv1a1.EnvoyProxyKubernetesProvider{
1645+
EnvoyDeployment: &egv1a1.KubernetesDeploymentSpec{
1646+
Container: &egv1a1.KubernetesContainerSpec{
1647+
Image: ptr.To(":v1.25.2"),
1648+
},
1649+
},
1650+
},
1651+
},
1652+
}
1653+
},
1654+
wantErrors: []string{"Image must include a tag and allowed characters only (e.g., 'repo:tag')."},
1655+
},
1656+
{
1657+
desc: "invalid: image with multiple colons",
1658+
mutate: func(envoy *egv1a1.EnvoyProxy) {
1659+
envoy.Spec = egv1a1.EnvoyProxySpec{
1660+
Provider: &egv1a1.EnvoyProxyProvider{
1661+
Type: egv1a1.ProviderTypeKubernetes,
1662+
Kubernetes: &egv1a1.EnvoyProxyKubernetesProvider{
1663+
EnvoyDeployment: &egv1a1.KubernetesDeploymentSpec{
1664+
Container: &egv1a1.KubernetesContainerSpec{
1665+
Image: ptr.To("registry.com/envoy:v1.2.3:latest"),
1666+
},
1667+
},
1668+
},
1669+
},
1670+
}
1671+
},
1672+
wantErrors: []string{"Image must include a tag and allowed characters only (e.g., 'repo:tag')."},
1673+
},
1674+
{
1675+
desc: "invalid: imageRepository contains tag",
1676+
mutate: func(envoy *egv1a1.EnvoyProxy) {
1677+
envoy.Spec = egv1a1.EnvoyProxySpec{
1678+
Provider: &egv1a1.EnvoyProxyProvider{
1679+
Type: egv1a1.ProviderTypeKubernetes,
1680+
Kubernetes: &egv1a1.EnvoyProxyKubernetesProvider{
1681+
EnvoyDeployment: &egv1a1.KubernetesDeploymentSpec{
1682+
Container: &egv1a1.KubernetesContainerSpec{
1683+
ImageRepository: ptr.To("envoyproxy/envoy:v1.2.3"),
1684+
},
1685+
},
1686+
},
1687+
},
1688+
}
1689+
},
1690+
wantErrors: []string{"ImageRepository must contain only allowed characters and must not include a tag or any colons."},
1691+
},
16021692
}
16031693

16041694
for _, tc := range cases {

test/helm/gateway-crds-helm/all.out.yaml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24189,12 +24189,20 @@ spec:
2418924189
Image specifies the EnvoyProxy container image to be used including a tag, instead of the default image.
2419024190
This field is mutually exclusive with ImageRepository.
2419124191
type: string
24192+
x-kubernetes-validations:
24193+
- message: Image must include a tag and allowed characters
24194+
only (e.g., 'repo:tag').
24195+
rule: self.matches('^[a-zA-Z0-9._/-]+:[a-zA-Z0-9._-]+$')
2419224196
imageRepository:
2419324197
description: |-
2419424198
ImageRepository specifies the container image repository to be used without specifying a tag.
2419524199
The default tag will be used.
2419624200
This field is mutually exclusive with Image.
2419724201
type: string
24202+
x-kubernetes-validations:
24203+
- message: ImageRepository must contain only allowed
24204+
characters and must not include a tag or any colons.
24205+
rule: self.matches('^[a-zA-Z0-9._/-]+$')
2419824206
resources:
2419924207
description: |-
2420024208
Resources required by this container.
@@ -28026,12 +28034,20 @@ spec:
2802628034
Image specifies the EnvoyProxy container image to be used including a tag, instead of the default image.
2802728035
This field is mutually exclusive with ImageRepository.
2802828036
type: string
28037+
x-kubernetes-validations:
28038+
- message: Image must include a tag and allowed characters
28039+
only (e.g., 'repo:tag').
28040+
rule: self.matches('^[a-zA-Z0-9._/-]+:[a-zA-Z0-9._-]+$')
2802928041
imageRepository:
2803028042
description: |-
2803128043
ImageRepository specifies the container image repository to be used without specifying a tag.
2803228044
The default tag will be used.
2803328045
This field is mutually exclusive with Image.
2803428046
type: string
28047+
x-kubernetes-validations:
28048+
- message: ImageRepository must contain only allowed
28049+
characters and must not include a tag or any colons.
28050+
rule: self.matches('^[a-zA-Z0-9._/-]+$')
2803528051
resources:
2803628052
description: |-
2803728053
Resources required by this container.

test/helm/gateway-crds-helm/envoy-gateway-crds.out.yaml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6877,12 +6877,20 @@ spec:
68776877
Image specifies the EnvoyProxy container image to be used including a tag, instead of the default image.
68786878
This field is mutually exclusive with ImageRepository.
68796879
type: string
6880+
x-kubernetes-validations:
6881+
- message: Image must include a tag and allowed characters
6882+
only (e.g., 'repo:tag').
6883+
rule: self.matches('^[a-zA-Z0-9._/-]+:[a-zA-Z0-9._-]+$')
68806884
imageRepository:
68816885
description: |-
68826886
ImageRepository specifies the container image repository to be used without specifying a tag.
68836887
The default tag will be used.
68846888
This field is mutually exclusive with Image.
68856889
type: string
6890+
x-kubernetes-validations:
6891+
- message: ImageRepository must contain only allowed
6892+
characters and must not include a tag or any colons.
6893+
rule: self.matches('^[a-zA-Z0-9._/-]+$')
68866894
resources:
68876895
description: |-
68886896
Resources required by this container.
@@ -10714,12 +10722,20 @@ spec:
1071410722
Image specifies the EnvoyProxy container image to be used including a tag, instead of the default image.
1071510723
This field is mutually exclusive with ImageRepository.
1071610724
type: string
10725+
x-kubernetes-validations:
10726+
- message: Image must include a tag and allowed characters
10727+
only (e.g., 'repo:tag').
10728+
rule: self.matches('^[a-zA-Z0-9._/-]+:[a-zA-Z0-9._-]+$')
1071710729
imageRepository:
1071810730
description: |-
1071910731
ImageRepository specifies the container image repository to be used without specifying a tag.
1072010732
The default tag will be used.
1072110733
This field is mutually exclusive with Image.
1072210734
type: string
10735+
x-kubernetes-validations:
10736+
- message: ImageRepository must contain only allowed
10737+
characters and must not include a tag or any colons.
10738+
rule: self.matches('^[a-zA-Z0-9._/-]+$')
1072310739
resources:
1072410740
description: |-
1072510741
Resources required by this container.

0 commit comments

Comments
 (0)