From 40da208b3db4623c32a91fb837b50877e05c1d0e Mon Sep 17 00:00:00 2001 From: Kermit Alexander Date: Thu, 7 Jul 2022 10:08:55 +0000 Subject: [PATCH] Add runtime cost limit test. --- .../crd_validation_expressions_test.go | 69 +++++++++++++++++++ 1 file changed, 69 insertions(+) diff --git a/test/integration/apiserver/crd_validation_expressions_test.go b/test/integration/apiserver/crd_validation_expressions_test.go index 0a6c24d9724..5824f2f3a69 100644 --- a/test/integration/apiserver/crd_validation_expressions_test.go +++ b/test/integration/apiserver/crd_validation_expressions_test.go @@ -301,6 +301,36 @@ func TestCustomResourceValidators(t *testing.T) { t.Error("Unexpected error creating custom resource but metadata validation rule") } }) + t.Run("CR creation MUST fail if a x-kubernetes-validations rule exceeds the runtime cost limit", func(t *testing.T) { + structuralWithValidators := crdWithSchema(t, "RuntimeCostLimit", structuralSchemaWithCostLimit) + crd, err := fixtures.CreateNewV1CustomResourceDefinition(structuralWithValidators, apiExtensionClient, dynamicClient) + if err != nil { + t.Errorf("Unexpected error creating custom resource definition: %v", err) + } + gvr := schema.GroupVersionResource{ + Group: crd.Spec.Group, + Version: crd.Spec.Versions[0].Name, + Resource: crd.Spec.Names.Plural, + } + crClient := dynamicClient.Resource(gvr) + name1 := names.SimpleNameGenerator.GenerateName("cr-1") + cr := &unstructured.Unstructured{Object: map[string]interface{}{ + "apiVersion": gvr.Group + "/" + gvr.Version, + "kind": crd.Spec.Names.Kind, + "metadata": map[string]interface{}{ + "name": name1, + }, + "spec": map[string]interface{}{ + "list": genLargeArray(725, 20), + }, + }} + _, err = crClient.Create(context.TODO(), cr, metav1.CreateOptions{}) + if err == nil { + t.Fatal("Expected error creating custom resource") + } else if !strings.Contains(err.Error(), "call cost exceeds limit") { + t.Errorf("Expected error to contain %s but got %v", "call cost exceeds limit", err.Error()) + } + }) t.Run("Schema with valid transition rule", func(t *testing.T) { structuralWithValidators := crdWithSchema(t, "ValidTransitionRule", structuralSchemaWithValidTransitionRule) crd, err := fixtures.CreateNewV1CustomResourceDefinition(structuralWithValidators, apiExtensionClient, dynamicClient) @@ -680,6 +710,14 @@ func nonStructuralCrdWithValidations() *apiextensionsv1beta1.CustomResourceDefin } } +func genLargeArray(n, x int64) []int64 { + arr := make([]int64, n) + for i := int64(0); i < n; i++ { + arr[i] = x + } + return arr +} + func crdWithSchema(t *testing.T, kind string, schemaJson []byte) *apiextensionsv1.CustomResourceDefinition { plural := strings.ToLower(kind) + "s" var c apiextensionsv1.CustomResourceValidation @@ -1031,3 +1069,34 @@ var structuralSchemaWithDefaultMapKeyTransitionRule = []byte(` } } }`) + +var structuralSchemaWithCostLimit = []byte(` +{ + "openAPIV3Schema": { + "description": "CRD with CEL validators", + "type": "object", + "properties": { + "spec": { + "type": "object", + "properties": { + "list": { + "type": "array", + "maxItems": 725, + "items": { + "type": "integer" + }, + "x-kubernetes-validations": [ + { + "rule": "self.all(x, self.all(y, x == y))" + } + ] + } + } + }, + "status": { + "type": "object", + "properties": {} + } + } + } +}`)