From 4bf994c736822f66f8ade24f0bf2e0ceb0a00e7f Mon Sep 17 00:00:00 2001 From: "Dr. Stefan Schimanski" Date: Mon, 10 Jun 2019 16:32:24 +0200 Subject: [PATCH] apiextensions: forbid x-kubernetes-embedded-resource inside of resource meta fields --- .../apiextensions/validation/validation.go | 8 ++- .../validation/validation_test.go | 65 +++++++++++++++++++ 2 files changed, 72 insertions(+), 1 deletion(-) diff --git a/staging/src/k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/validation/validation.go b/staging/src/k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/validation/validation.go index d9ea00b6f4b..92442f89d0c 100644 --- a/staging/src/k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/validation/validation.go +++ b/staging/src/k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/validation/validation.go @@ -640,6 +640,8 @@ func ValidateCustomResourceDefinitionValidation(customResourceValidation *apiext return allErrs } +var metaFields = sets.NewString("metadata", "apiVersion", "kind") + // ValidateCustomResourceDefinitionOpenAPISchema statically validates func ValidateCustomResourceDefinitionOpenAPISchema(schema *apiextensions.JSONSchemaProps, fldPath *field.Path, ssv specStandardValidator, isRoot bool) field.ErrorList { allErrs := field.ErrorList{} @@ -682,7 +684,7 @@ func ValidateCustomResourceDefinitionOpenAPISchema(schema *apiextensions.JSONSch if len(schema.Properties) != 0 { for property, jsonSchema := range schema.Properties { subSsv := ssv - if (isRoot || schema.XEmbeddedResource) && property == "metadata" { + if (isRoot || schema.XEmbeddedResource) && metaFields.Has(property) { // we recurse into the schema that applies to ObjectMeta. subSsv = ssv.withInsideResourceMeta() if isRoot { @@ -846,6 +848,10 @@ func (v *specStandardValidatorV3) validate(schema *apiextensions.JSONSchemaProps allErrs = append(allErrs, field.Forbidden(fldPath.Child("items"), "items must be a schema object and not an array")) } + if v.isInsideResourceMeta && schema.XEmbeddedResource { + allErrs = append(allErrs, field.Forbidden(fldPath.Child("x-kubernetes-embedded-resource"), "must not be used inside of resource meta")) + } + return allErrs } diff --git a/staging/src/k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/validation/validation_test.go b/staging/src/k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/validation/validation_test.go index 8808b04c1ec..fbccf9875cf 100644 --- a/staging/src/k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/validation/validation_test.go +++ b/staging/src/k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/validation/validation_test.go @@ -1567,6 +1567,71 @@ func TestValidateCustomResourceDefinition(t *testing.T) { required("spec", "validation", "openAPIV3Schema", "type"), }, }, + { + name: "x-kubernetes-embedded-resource inside resource meta", + resource: &apiextensions.CustomResourceDefinition{ + ObjectMeta: metav1.ObjectMeta{Name: "plural.group.com"}, + Spec: apiextensions.CustomResourceDefinitionSpec{ + Group: "group.com", + Version: "version", + Versions: singleVersionList, + Scope: apiextensions.NamespaceScoped, + Names: apiextensions.CustomResourceDefinitionNames{ + Plural: "plural", + Singular: "singular", + Kind: "Plural", + ListKind: "PluralList", + }, + Validation: &apiextensions.CustomResourceValidation{ + OpenAPIV3Schema: &apiextensions.JSONSchemaProps{ + Type: "object", + Properties: map[string]apiextensions.JSONSchemaProps{ + "embedded": { + Type: "object", + XEmbeddedResource: true, + Properties: map[string]apiextensions.JSONSchemaProps{ + "metadata": { + Type: "object", + XEmbeddedResource: true, + XPreserveUnknownFields: pointer.BoolPtr(true), + }, + "apiVersion": { + Type: "string", + Properties: map[string]apiextensions.JSONSchemaProps{ + "foo": { + Type: "object", + XEmbeddedResource: true, + XPreserveUnknownFields: pointer.BoolPtr(true), + }, + }, + }, + "kind": { + Type: "string", + Properties: map[string]apiextensions.JSONSchemaProps{ + "foo": { + Type: "object", + XEmbeddedResource: true, + XPreserveUnknownFields: pointer.BoolPtr(true), + }, + }, + }, + }, + }, + }, + }, + }, + PreserveUnknownFields: pointer.BoolPtr(true), + }, + Status: apiextensions.CustomResourceDefinitionStatus{ + StoredVersions: []string{"version"}, + }, + }, + errors: []validationMatch{ + forbidden("spec", "validation", "openAPIV3Schema", "properties[embedded]", "properties[metadata]", "x-kubernetes-embedded-resource"), + forbidden("spec", "validation", "openAPIV3Schema", "properties[embedded]", "properties[apiVersion]", "properties[foo]", "x-kubernetes-embedded-resource"), + forbidden("spec", "validation", "openAPIV3Schema", "properties[embedded]", "properties[kind]", "properties[foo]", "x-kubernetes-embedded-resource"), + }, + }, { name: "defaults with enabled feature gate, unstructural schema", resource: &apiextensions.CustomResourceDefinition{