diff --git a/api/v1alpha1/shared_types.go b/api/v1alpha1/shared_types.go index c108910f97..e2ce9dc55c 100644 --- a/api/v1alpha1/shared_types.go +++ b/api/v1alpha1/shared_types.go @@ -231,7 +231,7 @@ type KubernetesContainerSpec struct { // Image specifies the EnvoyProxy container image to be used including a tag, instead of the default image. // This field is mutually exclusive with ImageRepository. // - // +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')." + // +kubebuilder:validation:XValidation:rule="self.matches('^[a-zA-Z0-9._/-]+(:[a-zA-Z0-9._-]+)?(@sha256:[a-z0-9]+)?$')",message="Image must include a tag and allowed characters only (e.g., 'repo:tag')." // +optional Image *string `json:"image,omitempty"` diff --git a/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_envoyproxies.yaml b/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_envoyproxies.yaml index 004ea44c93..e5e0dcee63 100644 --- a/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_envoyproxies.yaml +++ b/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_envoyproxies.yaml @@ -614,7 +614,7 @@ spec: x-kubernetes-validations: - message: Image must include a tag and allowed characters only (e.g., 'repo:tag'). - rule: self.matches('^[a-zA-Z0-9._/-]+:[a-zA-Z0-9._-]+$') + rule: self.matches('^[a-zA-Z0-9._/-]+(:[a-zA-Z0-9._-]+)?(@sha256:[a-z0-9]+)?$') imageRepository: description: |- ImageRepository specifies the container image repository to be used without specifying a tag. @@ -4459,7 +4459,7 @@ spec: x-kubernetes-validations: - message: Image must include a tag and allowed characters only (e.g., 'repo:tag'). - rule: self.matches('^[a-zA-Z0-9._/-]+:[a-zA-Z0-9._-]+$') + rule: self.matches('^[a-zA-Z0-9._/-]+(:[a-zA-Z0-9._-]+)?(@sha256:[a-z0-9]+)?$') imageRepository: description: |- ImageRepository specifies the container image repository to be used without specifying a tag. diff --git a/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_envoyproxies.yaml b/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_envoyproxies.yaml index 7d99356073..4a8675fdba 100644 --- a/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_envoyproxies.yaml +++ b/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_envoyproxies.yaml @@ -613,7 +613,7 @@ spec: x-kubernetes-validations: - message: Image must include a tag and allowed characters only (e.g., 'repo:tag'). - rule: self.matches('^[a-zA-Z0-9._/-]+:[a-zA-Z0-9._-]+$') + rule: self.matches('^[a-zA-Z0-9._/-]+(:[a-zA-Z0-9._-]+)?(@sha256:[a-z0-9]+)?$') imageRepository: description: |- ImageRepository specifies the container image repository to be used without specifying a tag. @@ -4458,7 +4458,7 @@ spec: x-kubernetes-validations: - message: Image must include a tag and allowed characters only (e.g., 'repo:tag'). - rule: self.matches('^[a-zA-Z0-9._/-]+:[a-zA-Z0-9._-]+$') + rule: self.matches('^[a-zA-Z0-9._/-]+(:[a-zA-Z0-9._-]+)?(@sha256:[a-z0-9]+)?$') imageRepository: description: |- ImageRepository specifies the container image repository to be used without specifying a tag. diff --git a/test/cel-validation/envoyproxy_test.go b/test/cel-validation/envoyproxy_test.go index 0f7bf5d6bd..5ec5f57bd3 100644 --- a/test/cel-validation/envoyproxy_test.go +++ b/test/cel-validation/envoyproxy_test.go @@ -1616,7 +1616,7 @@ func TestEnvoyProxyProvider(t *testing.T) { wantErrors: []string{}, }, { - desc: "valid: imageRepository set without tag, image not set", + desc: "valid: image set with digest, imageRepository not set", mutate: func(envoy *egv1a1.EnvoyProxy) { envoy.Spec = egv1a1.EnvoyProxySpec{ Provider: &egv1a1.EnvoyProxyProvider{ @@ -1624,7 +1624,7 @@ func TestEnvoyProxyProvider(t *testing.T) { Kubernetes: &egv1a1.EnvoyProxyKubernetesProvider{ EnvoyDeployment: &egv1a1.KubernetesDeploymentSpec{ Container: &egv1a1.KubernetesContainerSpec{ - ImageRepository: ptr.To("envoyproxy/envoy"), + Image: ptr.To("envoyproxy/envoy:v1.2.3@sha256:da99c47f08546492d19973920dc76334c592f59ad5b732a514320d959db9fa40"), }, }, }, @@ -1634,7 +1634,7 @@ func TestEnvoyProxyProvider(t *testing.T) { wantErrors: []string{}, }, { - desc: "invalid: both image and imageRepository set", + desc: "valid: image with sha256, imageRepository not set", mutate: func(envoy *egv1a1.EnvoyProxy) { envoy.Spec = egv1a1.EnvoyProxySpec{ Provider: &egv1a1.EnvoyProxyProvider{ @@ -1642,18 +1642,17 @@ func TestEnvoyProxyProvider(t *testing.T) { Kubernetes: &egv1a1.EnvoyProxyKubernetesProvider{ EnvoyDeployment: &egv1a1.KubernetesDeploymentSpec{ Container: &egv1a1.KubernetesContainerSpec{ - Image: ptr.To("envoyproxy/envoy:v1.2.3"), - ImageRepository: ptr.To("envoyproxy/envoy"), + Image: ptr.To("envoyproxy/envoy@sha256:da99c47f08546492d19973920dc76334c592f59ad5b732a514320d959db9fa40"), }, }, }, }, } }, - wantErrors: []string{"Either image or imageRepository can be set."}, + wantErrors: []string{}, }, { - desc: "invalid: image set without tag", + desc: "valid: image set without tag", mutate: func(envoy *egv1a1.EnvoyProxy) { envoy.Spec = egv1a1.EnvoyProxySpec{ Provider: &egv1a1.EnvoyProxyProvider{ @@ -1668,7 +1667,44 @@ func TestEnvoyProxyProvider(t *testing.T) { }, } }, - wantErrors: []string{"Image must include a tag and allowed characters only (e.g., 'repo:tag')."}, + wantErrors: []string{}, + }, + { + desc: "valid: imageRepository set without tag, image not set", + mutate: func(envoy *egv1a1.EnvoyProxy) { + envoy.Spec = egv1a1.EnvoyProxySpec{ + Provider: &egv1a1.EnvoyProxyProvider{ + Type: egv1a1.ProviderTypeKubernetes, + Kubernetes: &egv1a1.EnvoyProxyKubernetesProvider{ + EnvoyDeployment: &egv1a1.KubernetesDeploymentSpec{ + Container: &egv1a1.KubernetesContainerSpec{ + ImageRepository: ptr.To("envoyproxy/envoy"), + }, + }, + }, + }, + } + }, + wantErrors: []string{}, + }, + { + desc: "invalid: both image and imageRepository set", + mutate: func(envoy *egv1a1.EnvoyProxy) { + envoy.Spec = egv1a1.EnvoyProxySpec{ + Provider: &egv1a1.EnvoyProxyProvider{ + Type: egv1a1.ProviderTypeKubernetes, + Kubernetes: &egv1a1.EnvoyProxyKubernetesProvider{ + EnvoyDeployment: &egv1a1.KubernetesDeploymentSpec{ + Container: &egv1a1.KubernetesContainerSpec{ + Image: ptr.To("envoyproxy/envoy:v1.2.3"), + ImageRepository: ptr.To("envoyproxy/envoy"), + }, + }, + }, + }, + } + }, + wantErrors: []string{"Either image or imageRepository can be set."}, }, { desc: "invalid: image ends with colon", diff --git a/test/helm/gateway-crds-helm/all.out.yaml b/test/helm/gateway-crds-helm/all.out.yaml index 968c8140ad..31bdd8db58 100644 --- a/test/helm/gateway-crds-helm/all.out.yaml +++ b/test/helm/gateway-crds-helm/all.out.yaml @@ -24547,7 +24547,7 @@ spec: x-kubernetes-validations: - message: Image must include a tag and allowed characters only (e.g., 'repo:tag'). - rule: self.matches('^[a-zA-Z0-9._/-]+:[a-zA-Z0-9._-]+$') + rule: self.matches('^[a-zA-Z0-9._/-]+(:[a-zA-Z0-9._-]+)?(@sha256:[a-z0-9]+)?$') imageRepository: description: |- ImageRepository specifies the container image repository to be used without specifying a tag. @@ -28392,7 +28392,7 @@ spec: x-kubernetes-validations: - message: Image must include a tag and allowed characters only (e.g., 'repo:tag'). - rule: self.matches('^[a-zA-Z0-9._/-]+:[a-zA-Z0-9._-]+$') + rule: self.matches('^[a-zA-Z0-9._/-]+(:[a-zA-Z0-9._-]+)?(@sha256:[a-z0-9]+)?$') imageRepository: description: |- ImageRepository specifies the container image repository to be used without specifying a tag. diff --git a/test/helm/gateway-crds-helm/envoy-gateway-crds.out.yaml b/test/helm/gateway-crds-helm/envoy-gateway-crds.out.yaml index 257f1136ad..09101b2de0 100644 --- a/test/helm/gateway-crds-helm/envoy-gateway-crds.out.yaml +++ b/test/helm/gateway-crds-helm/envoy-gateway-crds.out.yaml @@ -7235,7 +7235,7 @@ spec: x-kubernetes-validations: - message: Image must include a tag and allowed characters only (e.g., 'repo:tag'). - rule: self.matches('^[a-zA-Z0-9._/-]+:[a-zA-Z0-9._-]+$') + rule: self.matches('^[a-zA-Z0-9._/-]+(:[a-zA-Z0-9._-]+)?(@sha256:[a-z0-9]+)?$') imageRepository: description: |- ImageRepository specifies the container image repository to be used without specifying a tag. @@ -11080,7 +11080,7 @@ spec: x-kubernetes-validations: - message: Image must include a tag and allowed characters only (e.g., 'repo:tag'). - rule: self.matches('^[a-zA-Z0-9._/-]+:[a-zA-Z0-9._-]+$') + rule: self.matches('^[a-zA-Z0-9._/-]+(:[a-zA-Z0-9._-]+)?(@sha256:[a-z0-9]+)?$') imageRepository: description: |- ImageRepository specifies the container image repository to be used without specifying a tag.