apiextensions: forbid x-kubernetes-embedded-resource inside of resource meta fields

This commit is contained in:
Dr. Stefan Schimanski 2019-06-10 16:32:24 +02:00
parent e2fd72ca84
commit 4bf994c736
2 changed files with 72 additions and 1 deletions

View File

@ -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
}

View File

@ -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{