From 31dcff1b1c638d519797fb771c12277759db727d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Charles-Edouard=20Br=C3=A9t=C3=A9ch=C3=A9?= <charles.edouard@nirmata.com> Date: Wed, 4 Sep 2024 21:43:12 +0200 Subject: [PATCH] feat: add global context entry openapi validation (#10998) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com> --- .../v2alpha1/global_context_entry_types.go | 15 ++------------- .../kyverno.io_globalcontextentries.yaml | 5 +++++ .../kyverno/kyverno.io_globalcontextentries.yaml | 5 +++++ config/install-latest-testing.yaml | 5 +++++ .../globalcontext/validate-crd/chainsaw-test.yaml | 4 ++-- 5 files changed, 19 insertions(+), 15 deletions(-) diff --git a/api/kyverno/v2alpha1/global_context_entry_types.go b/api/kyverno/v2alpha1/global_context_entry_types.go index 5223658ca9..fe8df1f5b7 100644 --- a/api/kyverno/v2alpha1/global_context_entry_types.go +++ b/api/kyverno/v2alpha1/global_context_entry_types.go @@ -47,23 +47,15 @@ type GlobalContextEntry struct { Status GlobalContextEntryStatus `json:"status,omitempty"` } -// GetStatus returns the globalcontextentry status -func (p *GlobalContextEntry) GetStatus() *GlobalContextEntryStatus { - return &p.Status -} - // Validate implements programmatic validation func (c *GlobalContextEntry) Validate() (errs field.ErrorList) { errs = append(errs, c.Spec.Validate(field.NewPath("spec"))...) return errs } -// IsNamespaced indicates if the policy is namespace scoped -func (c *GlobalContextEntry) IsNamespaced() bool { - return false -} - // GlobalContextEntrySpec stores policy exception spec +// +kubebuilder:oneOf:={required:{kubernetesResource}} +// +kubebuilder:oneOf:={required:{apiCall}} type GlobalContextEntrySpec struct { // Stores a list of Kubernetes resources which will be cached. // Mutually exclusive with APICall. @@ -170,14 +162,11 @@ func (e *ExternalAPICall) Validate(path *field.Path) (errs field.ErrorList) { if e.RefreshInterval.Duration == 0*time.Second { errs = append(errs, field.Required(path.Child("refreshIntervalSeconds"), "A Resource entry requires a refresh interval greater than 0 seconds")) } - if (e.Service == nil && e.URLPath == "") || (e.Service != nil && e.URLPath != "") { errs = append(errs, field.Forbidden(path.Child("service"), "An External API call should either have Service or URLPath")) } - if e.Data != nil && e.Method != "POST" { errs = append(errs, field.Forbidden(path.Child("method"), "An External API call with data should have method as POST")) } - return errs } diff --git a/charts/kyverno/charts/crds/templates/kyverno.io/kyverno.io_globalcontextentries.yaml b/charts/kyverno/charts/crds/templates/kyverno.io/kyverno.io_globalcontextentries.yaml index 11e31feb01..82bea71d98 100644 --- a/charts/kyverno/charts/crds/templates/kyverno.io/kyverno.io_globalcontextentries.yaml +++ b/charts/kyverno/charts/crds/templates/kyverno.io/kyverno.io_globalcontextentries.yaml @@ -61,6 +61,11 @@ spec: type: object spec: description: Spec declares policy exception behaviors. + oneOf: + - required: + - kubernetesResource + - required: + - apiCall properties: apiCall: description: |- diff --git a/config/crds/kyverno/kyverno.io_globalcontextentries.yaml b/config/crds/kyverno/kyverno.io_globalcontextentries.yaml index 583a156df8..e5101b9c18 100644 --- a/config/crds/kyverno/kyverno.io_globalcontextentries.yaml +++ b/config/crds/kyverno/kyverno.io_globalcontextentries.yaml @@ -55,6 +55,11 @@ spec: type: object spec: description: Spec declares policy exception behaviors. + oneOf: + - required: + - kubernetesResource + - required: + - apiCall properties: apiCall: description: |- diff --git a/config/install-latest-testing.yaml b/config/install-latest-testing.yaml index c8d13df83e..eba0d017c2 100644 --- a/config/install-latest-testing.yaml +++ b/config/install-latest-testing.yaml @@ -24802,6 +24802,11 @@ spec: type: object spec: description: Spec declares policy exception behaviors. + oneOf: + - required: + - kubernetesResource + - required: + - apiCall properties: apiCall: description: |- diff --git a/test/conformance/chainsaw/globalcontext/validate-crd/chainsaw-test.yaml b/test/conformance/chainsaw/globalcontext/validate-crd/chainsaw-test.yaml index 6b61af90c0..4bd9ae56cb 100644 --- a/test/conformance/chainsaw/globalcontext/validate-crd/chainsaw-test.yaml +++ b/test/conformance/chainsaw/globalcontext/validate-crd/chainsaw-test.yaml @@ -19,7 +19,7 @@ spec: expect: - check: ($error): |- - admission webhook "kyverno-svc.kyverno.svc" denied the request: spec.kubernetesResource: Forbidden: A global context entry should either have KubernetesResource or APICall + GlobalContextEntry.kyverno.io "ingress-2" is invalid: <nil>: Invalid value: "": "spec" must validate one and only one schema (oneOf). Found 2 valid alternatives - name: step-03 try: - apply: @@ -27,4 +27,4 @@ spec: expect: - check: ($error): |- - admission webhook "kyverno-svc.kyverno.svc" denied the request: spec.kubernetesResource: Forbidden: A global context entry should either have KubernetesResource or APICall + GlobalContextEntry.kyverno.io "ingress-3" is invalid: [<nil>: Invalid value: "": "spec" must validate one and only one schema (oneOf). Found none valid, spec.kubernetesResource: Required value]