diff --git a/api/v1alpha1/backendtrafficpolicy_types.go b/api/v1alpha1/backendtrafficpolicy_types.go index 44fa5688715..65a71e90e60 100644 --- a/api/v1alpha1/backendtrafficpolicy_types.go +++ b/api/v1alpha1/backendtrafficpolicy_types.go @@ -18,7 +18,6 @@ const ( // +kubebuilder:object:root=true // +kubebuilder:resource:shortName=btp // +kubebuilder:subresource:status -// +kubebuilder:subresource:overrideStrategy // +kubebuilder:printcolumn:name="Status",type=string,JSONPath=`.status.conditions[?(@.type=="Accepted")].reason` // +kubebuilder:printcolumn:name="Age",type=date,JSONPath=`.metadata.creationTimestamp` // @@ -37,8 +36,9 @@ type BackendTrafficPolicy struct { // spec defines the desired state of BackendTrafficPolicy. type BackendTrafficPolicySpec struct { - - // +kubebuilder:validation:XValidation:rule="self.kind == 'Gateway' || self.kind == 'HTTPRoute' || self.kind == 'GRPCRoute' || self.kind == 'UDPRoute' || self.kind == 'TCPRoute' || self.kind == 'TLSRoute'", message="this policy can only have a targetRef.kind of Gateway/HTTPRoute/GRPCRoute/TCPRoute/UDPRoute/TLSRoute" + // +kubebuilder:validation:XValidation:rule="self.group == 'gateway.networking.k8s.io'", message="this policy can only have a targetRef.group of gateway.networking.k8s.io" + // +kubebuilder:validation:XValidation:rule="self.kind in ['Gateway', 'HTTPRoute', 'GRPCRoute', 'UDPRoute', 'TCPRoute', 'TLSRoute']", message="this policy can only have a targetRef.kind of Gateway/HTTPRoute/GRPCRoute/TCPRoute/UDPRoute/TLSRoute" + // +kubebuilder:validation:XValidation:rule="!has(self.sectionName)",message="this policy does not yet support the sectionName field" // // targetRef is the name of the resource this policy // is being attached to. diff --git a/api/v1alpha1/clienttrafficpolicy_types.go b/api/v1alpha1/clienttrafficpolicy_types.go index 4e8cdd29a51..43907dba96a 100644 --- a/api/v1alpha1/clienttrafficpolicy_types.go +++ b/api/v1alpha1/clienttrafficpolicy_types.go @@ -37,6 +37,10 @@ type ClientTrafficPolicy struct { // ClientTrafficPolicySpec defines the desired state of ClientTrafficPolicy. type ClientTrafficPolicySpec struct { + // +kubebuilder:validation:XValidation:rule="self.group == 'gateway.networking.k8s.io'", message="this policy can only have a targetRef.group of gateway.networking.k8s.io" + // +kubebuilder:validation:XValidation:rule="self.kind == 'Gateway'", message="this policy can only have a targetRef.kind of Gateway" + // +kubebuilder:validation:XValidation:rule="!has(self.sectionName)",message="this policy does not yet support the sectionName field" + // // TargetRef is the name of the Gateway resource this policy // is being attached to. // This Policy and the TargetRef MUST be in the same namespace diff --git a/api/v1alpha1/securitypolicy_types.go b/api/v1alpha1/securitypolicy_types.go index 7adece4cbca..21cac85398d 100644 --- a/api/v1alpha1/securitypolicy_types.go +++ b/api/v1alpha1/securitypolicy_types.go @@ -36,6 +36,10 @@ type SecurityPolicy struct { // SecurityPolicySpec defines the desired state of SecurityPolicy. type SecurityPolicySpec struct { + // +kubebuilder:validation:XValidation:rule="self.group == 'gateway.networking.k8s.io'", message="this policy can only have a targetRef.group of gateway.networking.k8s.io" + // +kubebuilder:validation:XValidation:rule="self.kind == 'Gateway'", message="this policy can only have a targetRef.kind of Gateway" + // +kubebuilder:validation:XValidation:rule="!has(self.sectionName)",message="this policy does not yet support the sectionName field" + // // TargetRef is the name of the Gateway resource this policy // is being attached to. // This Policy and the TargetRef MUST be in the same namespace diff --git a/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_backendtrafficpolicies.yaml b/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_backendtrafficpolicies.yaml index 8a8e2283ddb..be8c6c3d760 100644 --- a/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_backendtrafficpolicies.yaml +++ b/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_backendtrafficpolicies.yaml @@ -264,10 +264,13 @@ spec: - name type: object x-kubernetes-validations: + - message: this policy can only have a targetRef.group of gateway.networking.k8s.io + rule: self.group == 'gateway.networking.k8s.io' - message: this policy can only have a targetRef.kind of Gateway/HTTPRoute/GRPCRoute/TCPRoute/UDPRoute/TLSRoute - rule: self.kind == 'Gateway' || self.kind == 'HTTPRoute' || self.kind - == 'GRPCRoute' || self.kind == 'UDPRoute' || self.kind == 'TCPRoute' - || self.kind == 'TLSRoute' + rule: self.kind in ['Gateway', 'HTTPRoute', 'GRPCRoute', 'UDPRoute', + 'TCPRoute', 'TLSRoute'] + - message: this policy does not yet support the sectionName field + rule: '!has(self.sectionName)' required: - targetRef type: object diff --git a/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_clienttrafficpolicies.yaml b/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_clienttrafficpolicies.yaml index c34aba25627..7e0edba928f 100644 --- a/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_clienttrafficpolicies.yaml +++ b/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_clienttrafficpolicies.yaml @@ -93,6 +93,13 @@ spec: - kind - name type: object + x-kubernetes-validations: + - message: this policy can only have a targetRef.group of gateway.networking.k8s.io + rule: self.group == 'gateway.networking.k8s.io' + - message: this policy can only have a targetRef.kind of Gateway + rule: self.kind == 'Gateway' + - message: this policy does not yet support the sectionName field + rule: '!has(self.sectionName)' tcpKeepalive: description: TcpKeepalive settings associated with the downstream client connection. If defined, sets SO_KEEPALIVE on the listener diff --git a/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_securitypolicies.yaml b/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_securitypolicies.yaml index 2c7c91aa529..544e8dbe867 100644 --- a/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_securitypolicies.yaml +++ b/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_securitypolicies.yaml @@ -235,6 +235,13 @@ spec: - kind - name type: object + x-kubernetes-validations: + - message: this policy can only have a targetRef.group of gateway.networking.k8s.io + rule: self.group == 'gateway.networking.k8s.io' + - message: this policy can only have a targetRef.kind of Gateway + rule: self.kind == 'Gateway' + - message: this policy does not yet support the sectionName field + rule: '!has(self.sectionName)' required: - targetRef type: object diff --git a/test/cel-validation/backendtrafficpolicy_test.go b/test/cel-validation/backendtrafficpolicy_test.go new file mode 100644 index 00000000000..b49870c0dc7 --- /dev/null +++ b/test/cel-validation/backendtrafficpolicy_test.go @@ -0,0 +1,186 @@ +// Copyright Envoy Gateway Authors +// SPDX-License-Identifier: Apache-2.0 +// The full text of the Apache license is available in the LICENSE file at +// the root of the repo. + +//go:build celvalidation +// +build celvalidation + +package celvalidation + +import ( + "context" + "fmt" + "strings" + "testing" + "time" + + egv1a1 "github.com/envoyproxy/gateway/api/v1alpha1" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + gwapiv1a2 "sigs.k8s.io/gateway-api/apis/v1alpha2" +) + +func TestBackendTrafficPolicyTarget(t *testing.T) { + ctx := context.Background() + baseBTP := egv1a1.BackendTrafficPolicy{ + ObjectMeta: metav1.ObjectMeta{ + Name: "btp", + Namespace: metav1.NamespaceDefault, + }, + Spec: egv1a1.BackendTrafficPolicySpec{}, + } + + sectionName := gwapiv1a2.SectionName("foo") + + cases := []struct { + desc string + mutate func(btp *egv1a1.BackendTrafficPolicy) + mutateStatus func(btp *egv1a1.BackendTrafficPolicy) + wantErrors []string + }{ + { + desc: "valid gateway targetRef", + mutate: func(btp *egv1a1.BackendTrafficPolicy) { + btp.Spec = egv1a1.BackendTrafficPolicySpec{ + TargetRef: gwapiv1a2.PolicyTargetReferenceWithSectionName{ + PolicyTargetReference: gwapiv1a2.PolicyTargetReference{ + Group: gwapiv1a2.Group("gateway.networking.k8s.io"), + Kind: gwapiv1a2.Kind("Gateway"), + Name: gwapiv1a2.ObjectName("eg"), + }, + }, + } + }, + wantErrors: []string{}, + }, + { + desc: "valid httproute targetRef", + mutate: func(btp *egv1a1.BackendTrafficPolicy) { + btp.Spec = egv1a1.BackendTrafficPolicySpec{ + TargetRef: gwapiv1a2.PolicyTargetReferenceWithSectionName{ + PolicyTargetReference: gwapiv1a2.PolicyTargetReference{ + Group: gwapiv1a2.Group("gateway.networking.k8s.io"), + Kind: gwapiv1a2.Kind("HTTPRoute"), + Name: gwapiv1a2.ObjectName("httpbin-route"), + }, + }, + } + }, + wantErrors: []string{}, + }, + { + desc: "no targetRef", + mutate: func(btp *egv1a1.BackendTrafficPolicy) { + btp.Spec = egv1a1.BackendTrafficPolicySpec{} + }, + wantErrors: []string{ + "spec.targetRef.kind: Invalid value: \"\": spec.targetRef.kind in body should be at least 1 chars long", + "spec.targetRef.name: Invalid value: \"\": spec.targetRef.name in body should be at least 1 chars long", + "spec.targetRef: Invalid value: \"object\": this policy can only have a targetRef.group of gateway.networking.k8s.io", + "spec.targetRef: Invalid value: \"object\": this policy can only have a targetRef.kind of Gateway/HTTPRoute/GRPCRoute/TCPRoute/UDPRoute/TLSRoute", + }, + }, + { + desc: "targetRef unsupported kind", + mutate: func(btp *egv1a1.BackendTrafficPolicy) { + btp.Spec = egv1a1.BackendTrafficPolicySpec{ + TargetRef: gwapiv1a2.PolicyTargetReferenceWithSectionName{ + PolicyTargetReference: gwapiv1a2.PolicyTargetReference{ + Group: gwapiv1a2.Group("gateway.networking.k8s.io"), + Kind: gwapiv1a2.Kind("foo"), + Name: gwapiv1a2.ObjectName("eg"), + }, + }, + } + }, + wantErrors: []string{ + "spec.targetRef: Invalid value: \"object\": this policy can only have a targetRef.kind of Gateway/HTTPRoute/GRPCRoute/TCPRoute/UDPRoute/TLSRoute", + }, + }, + { + desc: "targetRef unsupported group", + mutate: func(btp *egv1a1.BackendTrafficPolicy) { + btp.Spec = egv1a1.BackendTrafficPolicySpec{ + TargetRef: gwapiv1a2.PolicyTargetReferenceWithSectionName{ + PolicyTargetReference: gwapiv1a2.PolicyTargetReference{ + Group: gwapiv1a2.Group("foo"), + Kind: gwapiv1a2.Kind("Gateway"), + Name: gwapiv1a2.ObjectName("eg"), + }, + }, + } + }, + wantErrors: []string{ + "spec.targetRef: Invalid value: \"object\": this policy can only have a targetRef.group of gateway.networking.k8s.io", + }, + }, + { + desc: "targetRef unsupported group and kind", + mutate: func(btp *egv1a1.BackendTrafficPolicy) { + btp.Spec = egv1a1.BackendTrafficPolicySpec{ + TargetRef: gwapiv1a2.PolicyTargetReferenceWithSectionName{ + PolicyTargetReference: gwapiv1a2.PolicyTargetReference{ + Group: gwapiv1a2.Group("foo"), + Kind: gwapiv1a2.Kind("bar"), + Name: gwapiv1a2.ObjectName("eg"), + }, + }, + } + }, + wantErrors: []string{ + "spec.targetRef: Invalid value: \"object\": this policy can only have a targetRef.group of gateway.networking.k8s.io", + "spec.targetRef: Invalid value: \"object\": this policy can only have a targetRef.kind of Gateway/HTTPRoute/GRPCRoute/TCPRoute/UDPRoute/TLSRoute", + }, + }, + { + desc: "sectionName disabled until supported", + mutate: func(btp *egv1a1.BackendTrafficPolicy) { + btp.Spec = egv1a1.BackendTrafficPolicySpec{ + TargetRef: gwapiv1a2.PolicyTargetReferenceWithSectionName{ + PolicyTargetReference: gwapiv1a2.PolicyTargetReference{ + Group: gwapiv1a2.Group("gateway.networking.k8s.io"), + Kind: gwapiv1a2.Kind("Gateway"), + Name: gwapiv1a2.ObjectName("eg"), + }, + SectionName: §ionName, + }, + } + }, + wantErrors: []string{ + "spec.targetRef: Invalid value: \"object\": this policy does not yet support the sectionName field", + }, + }, + } + + for _, tc := range cases { + t.Run(tc.desc, func(t *testing.T) { + btp := baseBTP.DeepCopy() + btp.Name = fmt.Sprintf("btp-%v", time.Now().UnixNano()) + + if tc.mutate != nil { + tc.mutate(btp) + } + err := c.Create(ctx, btp) + + if tc.mutateStatus != nil { + tc.mutateStatus(btp) + err = c.Status().Update(ctx, btp) + } + + if (len(tc.wantErrors) != 0) != (err != nil) { + t.Fatalf("Unexpected response while creating BackendTrafficPolicy; got err=\n%v\n;want error=%v", err, tc.wantErrors) + } + + var missingErrorStrings []string + for _, wantError := range tc.wantErrors { + if !strings.Contains(strings.ToLower(err.Error()), strings.ToLower(wantError)) { + missingErrorStrings = append(missingErrorStrings, wantError) + } + } + if len(missingErrorStrings) != 0 { + t.Errorf("Unexpected response while creating BackendTrafficPolicy; got err=\n%v\n;missing strings within error=%q", err, missingErrorStrings) + } + }) + } +} diff --git a/test/cel-validation/clienttrafficpolicy_test.go b/test/cel-validation/clienttrafficpolicy_test.go new file mode 100644 index 00000000000..b0449b78f51 --- /dev/null +++ b/test/cel-validation/clienttrafficpolicy_test.go @@ -0,0 +1,170 @@ +// Copyright Envoy Gateway Authors +// SPDX-License-Identifier: Apache-2.0 +// The full text of the Apache license is available in the LICENSE file at +// the root of the repo. + +//go:build celvalidation +// +build celvalidation + +package celvalidation + +import ( + "context" + "fmt" + "strings" + "testing" + "time" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + egv1a1 "github.com/envoyproxy/gateway/api/v1alpha1" + gwapiv1a2 "sigs.k8s.io/gateway-api/apis/v1alpha2" +) + +func TestClientTrafficPolicyTarget(t *testing.T) { + ctx := context.Background() + baseCTP := egv1a1.ClientTrafficPolicy{ + ObjectMeta: metav1.ObjectMeta{ + Name: "ctp", + Namespace: metav1.NamespaceDefault, + }, + Spec: egv1a1.ClientTrafficPolicySpec{}, + } + + sectionName := gwapiv1a2.SectionName("foo") + + cases := []struct { + desc string + mutate func(ctp *egv1a1.ClientTrafficPolicy) + mutateStatus func(ctp *egv1a1.ClientTrafficPolicy) + wantErrors []string + }{ + { + desc: "valid targetRef", + mutate: func(ctp *egv1a1.ClientTrafficPolicy) { + ctp.Spec = egv1a1.ClientTrafficPolicySpec{ + TargetRef: gwapiv1a2.PolicyTargetReferenceWithSectionName{ + PolicyTargetReference: gwapiv1a2.PolicyTargetReference{ + Group: gwapiv1a2.Group("gateway.networking.k8s.io"), + Kind: gwapiv1a2.Kind("Gateway"), + Name: gwapiv1a2.ObjectName("eg"), + }, + }, + } + }, + wantErrors: []string{}, + }, + { + desc: "no targetRef", + mutate: func(ctp *egv1a1.ClientTrafficPolicy) { + ctp.Spec = egv1a1.ClientTrafficPolicySpec{} + }, + wantErrors: []string{ + "spec.targetRef.kind: Invalid value: \"\": spec.targetRef.kind in body should be at least 1 chars long", + "spec.targetRef.name: Invalid value: \"\": spec.targetRef.name in body should be at least 1 chars long", + "spec.targetRef: Invalid value: \"object\": this policy can only have a targetRef.group of gateway.networking.k8s.io", + "spec.targetRef: Invalid value: \"object\": this policy can only have a targetRef.kind of Gateway", + }, + }, + { + desc: "targetRef unsupported kind", + mutate: func(ctp *egv1a1.ClientTrafficPolicy) { + ctp.Spec = egv1a1.ClientTrafficPolicySpec{ + TargetRef: gwapiv1a2.PolicyTargetReferenceWithSectionName{ + PolicyTargetReference: gwapiv1a2.PolicyTargetReference{ + Group: gwapiv1a2.Group("gateway.networking.k8s.io"), + Kind: gwapiv1a2.Kind("foo"), + Name: gwapiv1a2.ObjectName("eg"), + }, + }, + } + }, + wantErrors: []string{ + "spec.targetRef: Invalid value: \"object\": this policy can only have a targetRef.kind of Gateway", + }, + }, + { + desc: "targetRef unsupported group", + mutate: func(ctp *egv1a1.ClientTrafficPolicy) { + ctp.Spec = egv1a1.ClientTrafficPolicySpec{ + TargetRef: gwapiv1a2.PolicyTargetReferenceWithSectionName{ + PolicyTargetReference: gwapiv1a2.PolicyTargetReference{ + Group: gwapiv1a2.Group("foo"), + Kind: gwapiv1a2.Kind("Gateway"), + Name: gwapiv1a2.ObjectName("eg"), + }, + }, + } + }, + wantErrors: []string{ + "spec.targetRef: Invalid value: \"object\": this policy can only have a targetRef.group of gateway.networking.k8s.io", + }, + }, + { + desc: "targetRef unsupported group and kind", + mutate: func(ctp *egv1a1.ClientTrafficPolicy) { + ctp.Spec = egv1a1.ClientTrafficPolicySpec{ + TargetRef: gwapiv1a2.PolicyTargetReferenceWithSectionName{ + PolicyTargetReference: gwapiv1a2.PolicyTargetReference{ + Group: gwapiv1a2.Group("foo"), + Kind: gwapiv1a2.Kind("bar"), + Name: gwapiv1a2.ObjectName("eg"), + }, + }, + } + }, + wantErrors: []string{ + "spec.targetRef: Invalid value: \"object\": this policy can only have a targetRef.group of gateway.networking.k8s.io", + "spec.targetRef: Invalid value: \"object\": this policy can only have a targetRef.kind of Gateway", + }, + }, + { + desc: "sectionName disabled until supported", + mutate: func(ctp *egv1a1.ClientTrafficPolicy) { + ctp.Spec = egv1a1.ClientTrafficPolicySpec{ + TargetRef: gwapiv1a2.PolicyTargetReferenceWithSectionName{ + PolicyTargetReference: gwapiv1a2.PolicyTargetReference{ + Group: gwapiv1a2.Group("gateway.networking.k8s.io"), + Kind: gwapiv1a2.Kind("Gateway"), + }, + SectionName: §ionName, + }, + } + }, + wantErrors: []string{ + "spec.targetRef: Invalid value: \"object\": this policy does not yet support the sectionName field", + }, + }, + } + + for _, tc := range cases { + t.Run(tc.desc, func(t *testing.T) { + ctp := baseCTP.DeepCopy() + ctp.Name = fmt.Sprintf("ctp-%v", time.Now().UnixNano()) + + if tc.mutate != nil { + tc.mutate(ctp) + } + err := c.Create(ctx, ctp) + + if tc.mutateStatus != nil { + tc.mutateStatus(ctp) + err = c.Status().Update(ctx, ctp) + } + + if (len(tc.wantErrors) != 0) != (err != nil) { + t.Fatalf("Unexpected response while creating ClientTrafficPolicy; got err=\n%v\n;want error=%v", err, tc.wantErrors) + } + + var missingErrorStrings []string + for _, wantError := range tc.wantErrors { + if !strings.Contains(strings.ToLower(err.Error()), strings.ToLower(wantError)) { + missingErrorStrings = append(missingErrorStrings, wantError) + } + } + if len(missingErrorStrings) != 0 { + t.Errorf("Unexpected response while creating ClientTrafficPolicy; got err=\n%v\n;missing strings within error=%q", err, missingErrorStrings) + } + }) + } +} diff --git a/test/cel-validation/securitypolicy_test.go b/test/cel-validation/securitypolicy_test.go new file mode 100644 index 00000000000..7b634f2f1e5 --- /dev/null +++ b/test/cel-validation/securitypolicy_test.go @@ -0,0 +1,171 @@ +// Copyright Envoy Gateway Authors +// SPDX-License-Identifier: Apache-2.0 +// The full text of the Apache license is available in the LICENSE file at +// the root of the repo. + +//go:build celvalidation +// +build celvalidation + +package celvalidation + +import ( + "context" + "fmt" + "strings" + "testing" + "time" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + egv1a1 "github.com/envoyproxy/gateway/api/v1alpha1" + gwapiv1a2 "sigs.k8s.io/gateway-api/apis/v1alpha2" +) + +func TestSecurityPolicyTarget(t *testing.T) { + ctx := context.Background() + baseSP := egv1a1.SecurityPolicy{ + ObjectMeta: metav1.ObjectMeta{ + Name: "sp", + Namespace: metav1.NamespaceDefault, + }, + Spec: egv1a1.SecurityPolicySpec{}, + } + + sectionName := gwapiv1a2.SectionName("foo") + + cases := []struct { + desc string + mutate func(sp *egv1a1.SecurityPolicy) + mutateStatus func(sp *egv1a1.SecurityPolicy) + wantErrors []string + }{ + { + desc: "valid targetRef", + mutate: func(sp *egv1a1.SecurityPolicy) { + sp.Spec = egv1a1.SecurityPolicySpec{ + TargetRef: gwapiv1a2.PolicyTargetReferenceWithSectionName{ + PolicyTargetReference: gwapiv1a2.PolicyTargetReference{ + Group: gwapiv1a2.Group("gateway.networking.k8s.io"), + Kind: gwapiv1a2.Kind("Gateway"), + Name: gwapiv1a2.ObjectName("eg"), + }, + }, + } + }, + wantErrors: []string{}, + }, + { + desc: "no targetRef", + mutate: func(sp *egv1a1.SecurityPolicy) { + sp.Spec = egv1a1.SecurityPolicySpec{} + }, + wantErrors: []string{ + "spec.targetRef.kind: Invalid value: \"\": spec.targetRef.kind in body should be at least 1 chars long", + "spec.targetRef.name: Invalid value: \"\": spec.targetRef.name in body should be at least 1 chars long", + "spec.targetRef: Invalid value: \"object\": this policy can only have a targetRef.group of gateway.networking.k8s.io", + "spec.targetRef: Invalid value: \"object\": this policy can only have a targetRef.kind of Gateway", + }, + }, + { + desc: "targetRef unsupported kind", + mutate: func(sp *egv1a1.SecurityPolicy) { + sp.Spec = egv1a1.SecurityPolicySpec{ + TargetRef: gwapiv1a2.PolicyTargetReferenceWithSectionName{ + PolicyTargetReference: gwapiv1a2.PolicyTargetReference{ + Group: gwapiv1a2.Group("gateway.networking.k8s.io"), + Kind: gwapiv1a2.Kind("foo"), + Name: gwapiv1a2.ObjectName("eg"), + }, + }, + } + }, + wantErrors: []string{ + "spec.targetRef: Invalid value: \"object\": this policy can only have a targetRef.kind of Gateway", + }, + }, + { + desc: "targetRef unsupported group", + mutate: func(sp *egv1a1.SecurityPolicy) { + sp.Spec = egv1a1.SecurityPolicySpec{ + TargetRef: gwapiv1a2.PolicyTargetReferenceWithSectionName{ + PolicyTargetReference: gwapiv1a2.PolicyTargetReference{ + Group: gwapiv1a2.Group("foo"), + Kind: gwapiv1a2.Kind("Gateway"), + Name: gwapiv1a2.ObjectName("eg"), + }, + }, + } + }, + wantErrors: []string{ + "spec.targetRef: Invalid value: \"object\": this policy can only have a targetRef.group of gateway.networking.k8s.io", + }, + }, + { + desc: "targetRef unsupported group and kind", + mutate: func(sp *egv1a1.SecurityPolicy) { + sp.Spec = egv1a1.SecurityPolicySpec{ + TargetRef: gwapiv1a2.PolicyTargetReferenceWithSectionName{ + PolicyTargetReference: gwapiv1a2.PolicyTargetReference{ + Group: gwapiv1a2.Group("foo"), + Kind: gwapiv1a2.Kind("bar"), + Name: gwapiv1a2.ObjectName("eg"), + }, + }, + } + }, + wantErrors: []string{ + "spec.targetRef: Invalid value: \"object\": this policy can only have a targetRef.group of gateway.networking.k8s.io", + "spec.targetRef: Invalid value: \"object\": this policy can only have a targetRef.kind of Gateway", + }, + }, + { + desc: "sectionName disabled until supported", + mutate: func(sp *egv1a1.SecurityPolicy) { + sp.Spec = egv1a1.SecurityPolicySpec{ + TargetRef: gwapiv1a2.PolicyTargetReferenceWithSectionName{ + PolicyTargetReference: gwapiv1a2.PolicyTargetReference{ + Group: gwapiv1a2.Group("gateway.networking.k8s.io"), + Kind: gwapiv1a2.Kind("Gateway"), + Name: gwapiv1a2.ObjectName("eg"), + }, + SectionName: §ionName, + }, + } + }, + wantErrors: []string{ + "spec.targetRef: Invalid value: \"object\": this policy does not yet support the sectionName field", + }, + }, + } + + for _, tc := range cases { + t.Run(tc.desc, func(t *testing.T) { + sp := baseSP.DeepCopy() + sp.Name = fmt.Sprintf("sp-%v", time.Now().UnixNano()) + + if tc.mutate != nil { + tc.mutate(sp) + } + err := c.Create(ctx, sp) + + if tc.mutateStatus != nil { + tc.mutateStatus(sp) + err = c.Status().Update(ctx, sp) + } + + if (len(tc.wantErrors) != 0) != (err != nil) { + t.Fatalf("Unexpected response while creating SecurityPolicy; got err=\n%v\n;want error=%v", err, tc.wantErrors) + } + + var missingErrorStrings []string + for _, wantError := range tc.wantErrors { + if !strings.Contains(strings.ToLower(err.Error()), strings.ToLower(wantError)) { + missingErrorStrings = append(missingErrorStrings, wantError) + } + } + if len(missingErrorStrings) != 0 { + t.Errorf("Unexpected response while creating SecurityPolicy; got err=\n%v\n;missing strings within error=%q", err, missingErrorStrings) + } + }) + } +}