mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-08-19 08:40:42 +00:00
allow CEL and additionalProperties used in allof
additionalProperties makes sense to use in a NestedValueValidation, but it is currently forbidden. This change makes the treatment of additionalProperties more in line with the treatment of `items` or `properties` - so users can specify additional value validations for schemas which use `additionalProperties` structurally. This change also move XValidations so that it is allowed to be used inside an allOf in a CRD schema
This commit is contained in:
parent
0aa01be424
commit
bf7770f92f
@ -122,10 +122,10 @@ func Compile(s *schema.Structural, declType *apiservercel.DeclType, perCallLimit
|
||||
metrics.Metrics.ObserveCompilation(time.Since(t))
|
||||
}()
|
||||
|
||||
if len(s.Extensions.XValidations) == 0 {
|
||||
if len(s.XValidations) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
celRules := s.Extensions.XValidations
|
||||
celRules := s.XValidations
|
||||
|
||||
oldSelfEnvSet, optionalOldSelfEnvSet, err := prepareEnvSet(baseEnvSet, declType)
|
||||
if err != nil {
|
||||
|
@ -168,7 +168,7 @@ func TestCelCompilation(t *testing.T) {
|
||||
Generic: schema.Generic{
|
||||
Type: "integer",
|
||||
},
|
||||
Extensions: schema.Extensions{
|
||||
ValidationExtensions: schema.ValidationExtensions{
|
||||
XValidations: apiextensions.ValidationRules{
|
||||
{Rule: "self >= oldSelf.value()", OptionalOldSelf: ptr.To(true)},
|
||||
{Rule: "self >= oldSelf.orValue(1)", OptionalOldSelf: ptr.To(true)},
|
||||
@ -216,7 +216,7 @@ func TestCelCompilation(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
Extensions: schema.Extensions{
|
||||
ValidationExtensions: schema.ValidationExtensions{
|
||||
XValidations: apiextensions.ValidationRules{
|
||||
{Rule: "self.i >= oldSelf.i.value()", OptionalOldSelf: ptr.To(true)},
|
||||
{Rule: "self.s == oldSelf.s.value()", OptionalOldSelf: ptr.To(true)},
|
||||
@ -266,7 +266,7 @@ func TestCelCompilation(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
Extensions: schema.Extensions{
|
||||
ValidationExtensions: schema.ValidationExtensions{
|
||||
XValidations: apiextensions.ValidationRules{
|
||||
{
|
||||
Rule: "self.minReplicas < self.maxReplicas",
|
||||
@ -285,7 +285,7 @@ func TestCelCompilation(t *testing.T) {
|
||||
Generic: schema.Generic{
|
||||
Type: "string",
|
||||
},
|
||||
Extensions: schema.Extensions{
|
||||
ValidationExtensions: schema.ValidationExtensions{
|
||||
XValidations: apiextensions.ValidationRules{
|
||||
{
|
||||
Rule: "self.startsWith('s')",
|
||||
@ -307,7 +307,7 @@ func TestCelCompilation(t *testing.T) {
|
||||
ValueValidation: &schema.ValueValidation{
|
||||
Format: "byte",
|
||||
},
|
||||
Extensions: schema.Extensions{
|
||||
ValidationExtensions: schema.ValidationExtensions{
|
||||
XValidations: apiextensions.ValidationRules{
|
||||
{
|
||||
Rule: "string(self).endsWith('s')",
|
||||
@ -326,7 +326,7 @@ func TestCelCompilation(t *testing.T) {
|
||||
Generic: schema.Generic{
|
||||
Type: "boolean",
|
||||
},
|
||||
Extensions: schema.Extensions{
|
||||
ValidationExtensions: schema.ValidationExtensions{
|
||||
XValidations: apiextensions.ValidationRules{
|
||||
{
|
||||
Rule: "self == true",
|
||||
@ -345,7 +345,7 @@ func TestCelCompilation(t *testing.T) {
|
||||
Generic: schema.Generic{
|
||||
Type: "integer",
|
||||
},
|
||||
Extensions: schema.Extensions{
|
||||
ValidationExtensions: schema.ValidationExtensions{
|
||||
XValidations: apiextensions.ValidationRules{
|
||||
{
|
||||
Rule: "self > 0",
|
||||
@ -364,7 +364,7 @@ func TestCelCompilation(t *testing.T) {
|
||||
Generic: schema.Generic{
|
||||
Type: "number",
|
||||
},
|
||||
Extensions: schema.Extensions{
|
||||
ValidationExtensions: schema.ValidationExtensions{
|
||||
XValidations: apiextensions.ValidationRules{
|
||||
{
|
||||
Rule: "self > 1.0",
|
||||
@ -400,7 +400,7 @@ func TestCelCompilation(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
Extensions: schema.Extensions{
|
||||
ValidationExtensions: schema.ValidationExtensions{
|
||||
XValidations: apiextensions.ValidationRules{
|
||||
{
|
||||
Rule: "self.nestedObj.val == 10",
|
||||
@ -436,7 +436,7 @@ func TestCelCompilation(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
Extensions: schema.Extensions{
|
||||
ValidationExtensions: schema.ValidationExtensions{
|
||||
XValidations: apiextensions.ValidationRules{
|
||||
{
|
||||
Rule: "size(self.nestedObj[0]) == 10",
|
||||
@ -470,7 +470,7 @@ func TestCelCompilation(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
Extensions: schema.Extensions{
|
||||
ValidationExtensions: schema.ValidationExtensions{
|
||||
XValidations: apiextensions.ValidationRules{
|
||||
{
|
||||
Rule: "size(self[0][0]) == 10",
|
||||
@ -511,7 +511,7 @@ func TestCelCompilation(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
Extensions: schema.Extensions{
|
||||
ValidationExtensions: schema.ValidationExtensions{
|
||||
XValidations: apiextensions.ValidationRules{
|
||||
{
|
||||
Rule: "self[0].nestedObj.val == 10",
|
||||
@ -529,17 +529,17 @@ func TestCelCompilation(t *testing.T) {
|
||||
input: schema.Structural{
|
||||
Generic: schema.Generic{
|
||||
Type: "object",
|
||||
AdditionalProperties: &schema.StructuralOrBool{
|
||||
Bool: true,
|
||||
Structural: &schema.Structural{
|
||||
Generic: schema.Generic{
|
||||
Type: "boolean",
|
||||
Nullable: false,
|
||||
},
|
||||
},
|
||||
AdditionalProperties: &schema.StructuralOrBool{
|
||||
Bool: true,
|
||||
Structural: &schema.Structural{
|
||||
Generic: schema.Generic{
|
||||
Type: "boolean",
|
||||
Nullable: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
Extensions: schema.Extensions{
|
||||
ValidationExtensions: schema.ValidationExtensions{
|
||||
XValidations: apiextensions.ValidationRules{
|
||||
{
|
||||
Rule: "size(self) > 0",
|
||||
@ -558,7 +558,7 @@ func TestCelCompilation(t *testing.T) {
|
||||
Generic: schema.Generic{
|
||||
Type: "number",
|
||||
},
|
||||
Extensions: schema.Extensions{
|
||||
ValidationExtensions: schema.ValidationExtensions{
|
||||
XValidations: apiextensions.ValidationRules{
|
||||
{
|
||||
Rule: "size(self) == 10",
|
||||
@ -577,7 +577,7 @@ func TestCelCompilation(t *testing.T) {
|
||||
Generic: schema.Generic{
|
||||
Type: "integer",
|
||||
},
|
||||
Extensions: schema.Extensions{
|
||||
ValidationExtensions: schema.ValidationExtensions{
|
||||
XValidations: apiextensions.ValidationRules{
|
||||
{
|
||||
Rule: "size(self) == 10",
|
||||
@ -623,7 +623,7 @@ func TestCelCompilation(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
Extensions: schema.Extensions{
|
||||
ValidationExtensions: schema.ValidationExtensions{
|
||||
XValidations: apiextensions.ValidationRules{
|
||||
{
|
||||
Rule: "size(self.__namespace__[0]) == 10",
|
||||
@ -677,7 +677,7 @@ func TestCelCompilation(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
Extensions: schema.Extensions{
|
||||
ValidationExtensions: schema.ValidationExtensions{
|
||||
XValidations: apiextensions.ValidationRules{
|
||||
{
|
||||
Rule: "size(self.namespace[0]) == 10",
|
||||
@ -704,7 +704,7 @@ func TestCelCompilation(t *testing.T) {
|
||||
Generic: schema.Generic{
|
||||
Type: "integer",
|
||||
},
|
||||
Extensions: schema.Extensions{
|
||||
ValidationExtensions: schema.ValidationExtensions{
|
||||
XValidations: apiextensions.ValidationRules{
|
||||
{Rule: "self > 0"},
|
||||
{Rule: "self >= oldSelf"},
|
||||
@ -722,7 +722,7 @@ func TestCelCompilation(t *testing.T) {
|
||||
Generic: schema.Generic{
|
||||
Type: "object",
|
||||
},
|
||||
Extensions: schema.Extensions{
|
||||
ValidationExtensions: schema.ValidationExtensions{
|
||||
XValidations: apiextensions.ValidationRules{
|
||||
{Rule: " \t"},
|
||||
},
|
||||
@ -745,7 +745,7 @@ func TestCelCompilation(t *testing.T) {
|
||||
Generic: schema.Generic{
|
||||
Type: "object",
|
||||
},
|
||||
Extensions: schema.Extensions{
|
||||
ValidationExtensions: schema.ValidationExtensions{
|
||||
XValidations: apiextensions.ValidationRules{
|
||||
{Rule: "42"},
|
||||
},
|
||||
@ -761,7 +761,7 @@ func TestCelCompilation(t *testing.T) {
|
||||
Generic: schema.Generic{
|
||||
Type: "string",
|
||||
},
|
||||
Extensions: schema.Extensions{
|
||||
ValidationExtensions: schema.ValidationExtensions{
|
||||
XValidations: apiextensions.ValidationRules{
|
||||
{
|
||||
Rule: "self.startsWith('s')",
|
||||
@ -780,7 +780,7 @@ func TestCelCompilation(t *testing.T) {
|
||||
Generic: schema.Generic{
|
||||
Type: "integer",
|
||||
},
|
||||
Extensions: schema.Extensions{
|
||||
ValidationExtensions: schema.ValidationExtensions{
|
||||
XValidations: apiextensions.ValidationRules{
|
||||
{
|
||||
Rule: "self == 5",
|
||||
@ -799,7 +799,7 @@ func TestCelCompilation(t *testing.T) {
|
||||
Generic: schema.Generic{
|
||||
Type: "number",
|
||||
},
|
||||
Extensions: schema.Extensions{
|
||||
ValidationExtensions: schema.ValidationExtensions{
|
||||
XValidations: apiextensions.ValidationRules{
|
||||
{
|
||||
Rule: "self < 32.0",
|
||||
@ -818,7 +818,7 @@ func TestCelCompilation(t *testing.T) {
|
||||
Generic: schema.Generic{
|
||||
Type: "object",
|
||||
},
|
||||
Extensions: schema.Extensions{
|
||||
ValidationExtensions: schema.ValidationExtensions{
|
||||
XValidations: apiextensions.ValidationRules{
|
||||
{Rule: "fakeFunction('abc') == 'ABC'"},
|
||||
},
|
||||
@ -835,7 +835,7 @@ func TestCelCompilation(t *testing.T) {
|
||||
Generic: schema.Generic{
|
||||
Type: "object",
|
||||
},
|
||||
Extensions: schema.Extensions{
|
||||
ValidationExtensions: schema.ValidationExtensions{
|
||||
XValidations: apiextensions.ValidationRules{
|
||||
{Rule: "fakeFunction('abc') == 'ABC'"},
|
||||
},
|
||||
@ -917,7 +917,7 @@ func genArrayWithRule(arrayType, rule string) func(maxItems *int64) *schema.Stru
|
||||
ValueValidation: &schema.ValueValidation{
|
||||
MaxItems: maxItems,
|
||||
},
|
||||
Extensions: schema.Extensions{
|
||||
ValidationExtensions: schema.ValidationExtensions{
|
||||
XValidations: apiextensions.ValidationRules{
|
||||
{
|
||||
Rule: rule,
|
||||
@ -947,7 +947,7 @@ func genArrayOfArraysWithRule(arrayType, rule string) func(maxItems *int64) *sch
|
||||
ValueValidation: &schema.ValueValidation{
|
||||
MaxItems: maxItems,
|
||||
},
|
||||
Extensions: schema.Extensions{
|
||||
ValidationExtensions: schema.ValidationExtensions{
|
||||
XValidations: apiextensions.ValidationRules{
|
||||
{
|
||||
Rule: rule,
|
||||
@ -987,7 +987,7 @@ func genObjectArrayWithRule(rule string) func(maxItems *int64) *schema.Structura
|
||||
ValueValidation: &schema.ValueValidation{
|
||||
MaxItems: maxItems,
|
||||
},
|
||||
Extensions: schema.Extensions{
|
||||
ValidationExtensions: schema.ValidationExtensions{
|
||||
XValidations: apiextensions.ValidationRules{
|
||||
{
|
||||
Rule: rule,
|
||||
@ -1007,17 +1007,17 @@ func getMapArrayWithRule(mapType, rule string) func(maxItems *int64) *schema.Str
|
||||
Items: &schema.Structural{
|
||||
Generic: schema.Generic{
|
||||
Type: "object",
|
||||
AdditionalProperties: &schema.StructuralOrBool{Structural: &schema.Structural{
|
||||
Generic: schema.Generic{
|
||||
Type: mapType,
|
||||
},
|
||||
}},
|
||||
},
|
||||
AdditionalProperties: &schema.StructuralOrBool{Structural: &schema.Structural{
|
||||
Generic: schema.Generic{
|
||||
Type: mapType,
|
||||
},
|
||||
}},
|
||||
},
|
||||
ValueValidation: &schema.ValueValidation{
|
||||
MaxItems: maxItems,
|
||||
},
|
||||
Extensions: schema.Extensions{
|
||||
ValidationExtensions: schema.ValidationExtensions{
|
||||
XValidations: apiextensions.ValidationRules{
|
||||
{
|
||||
Rule: rule,
|
||||
@ -1034,22 +1034,22 @@ func genMapWithRule(mapType, rule string) func(maxProperties *int64) *schema.Str
|
||||
return &schema.Structural{
|
||||
Generic: schema.Generic{
|
||||
Type: "object",
|
||||
AdditionalProperties: &schema.StructuralOrBool{Structural: &schema.Structural{
|
||||
Generic: schema.Generic{
|
||||
Type: passedType,
|
||||
},
|
||||
ValueValidation: &schema.ValueValidation{
|
||||
Format: passedFormat,
|
||||
},
|
||||
Extensions: schema.Extensions{
|
||||
XIntOrString: xIntString,
|
||||
},
|
||||
}},
|
||||
},
|
||||
AdditionalProperties: &schema.StructuralOrBool{Structural: &schema.Structural{
|
||||
Generic: schema.Generic{
|
||||
Type: passedType,
|
||||
},
|
||||
ValueValidation: &schema.ValueValidation{
|
||||
Format: passedFormat,
|
||||
},
|
||||
Extensions: schema.Extensions{
|
||||
XIntOrString: xIntString,
|
||||
},
|
||||
}},
|
||||
ValueValidation: &schema.ValueValidation{
|
||||
MaxProperties: maxProperties,
|
||||
},
|
||||
Extensions: schema.Extensions{
|
||||
ValidationExtensions: schema.ValidationExtensions{
|
||||
XValidations: apiextensions.ValidationRules{
|
||||
{
|
||||
Rule: rule,
|
||||
@ -1069,7 +1069,7 @@ func genStringWithRule(rule string) func(maxLength *int64) *schema.Structural {
|
||||
ValueValidation: &schema.ValueValidation{
|
||||
MaxLength: maxLength,
|
||||
},
|
||||
Extensions: schema.Extensions{
|
||||
ValidationExtensions: schema.ValidationExtensions{
|
||||
XValidations: apiextensions.ValidationRules{
|
||||
{
|
||||
Rule: rule,
|
||||
@ -1098,7 +1098,7 @@ func genEnumWithRuleAndValues(rule string, values ...string) func(maxLength *int
|
||||
MaxLength: maxLength,
|
||||
Enum: enums,
|
||||
},
|
||||
Extensions: schema.Extensions{
|
||||
ValidationExtensions: schema.ValidationExtensions{
|
||||
XValidations: apiextensions.ValidationRules{
|
||||
{
|
||||
Rule: rule,
|
||||
@ -1119,7 +1119,7 @@ func genBytesWithRule(rule string) func(maxLength *int64) *schema.Structural {
|
||||
MaxLength: maxLength,
|
||||
Format: "byte",
|
||||
},
|
||||
Extensions: schema.Extensions{
|
||||
ValidationExtensions: schema.ValidationExtensions{
|
||||
XValidations: apiextensions.ValidationRules{
|
||||
{
|
||||
Rule: rule,
|
||||
@ -1135,19 +1135,19 @@ func genNestedSpecWithRule(rule string) func(maxLength *int64) *schema.Structura
|
||||
return &schema.Structural{
|
||||
Generic: schema.Generic{
|
||||
Type: "object",
|
||||
AdditionalProperties: &schema.StructuralOrBool{Structural: &schema.Structural{
|
||||
Generic: schema.Generic{
|
||||
Type: "string",
|
||||
},
|
||||
ValueValidation: &schema.ValueValidation{
|
||||
MaxLength: maxLength,
|
||||
},
|
||||
}},
|
||||
},
|
||||
AdditionalProperties: &schema.StructuralOrBool{Structural: &schema.Structural{
|
||||
Generic: schema.Generic{
|
||||
Type: "string",
|
||||
},
|
||||
ValueValidation: &schema.ValueValidation{
|
||||
MaxLength: maxLength,
|
||||
},
|
||||
}},
|
||||
ValueValidation: &schema.ValueValidation{
|
||||
MaxProperties: maxLength,
|
||||
},
|
||||
Extensions: schema.Extensions{
|
||||
ValidationExtensions: schema.ValidationExtensions{
|
||||
XValidations: apiextensions.ValidationRules{
|
||||
{
|
||||
Rule: rule,
|
||||
@ -1167,28 +1167,28 @@ func genAllMaxNestedSpecWithRootRule(rule string) func(maxLength *int64) *schema
|
||||
Items: &schema.Structural{
|
||||
Generic: schema.Generic{
|
||||
Type: "object",
|
||||
AdditionalProperties: &schema.StructuralOrBool{Structural: &schema.Structural{
|
||||
Generic: schema.Generic{
|
||||
Type: "object",
|
||||
},
|
||||
ValueValidation: &schema.ValueValidation{
|
||||
Required: []string{"required"},
|
||||
MaxProperties: maxLength,
|
||||
},
|
||||
Properties: map[string]schema.Structural{
|
||||
"required": {
|
||||
Generic: schema.Generic{
|
||||
Type: "string",
|
||||
},
|
||||
},
|
||||
"optional": {
|
||||
Generic: schema.Generic{
|
||||
Type: "string",
|
||||
},
|
||||
},
|
||||
},
|
||||
}},
|
||||
},
|
||||
AdditionalProperties: &schema.StructuralOrBool{Structural: &schema.Structural{
|
||||
Generic: schema.Generic{
|
||||
Type: "object",
|
||||
},
|
||||
ValueValidation: &schema.ValueValidation{
|
||||
Required: []string{"required"},
|
||||
MaxProperties: maxLength,
|
||||
},
|
||||
Properties: map[string]schema.Structural{
|
||||
"required": {
|
||||
Generic: schema.Generic{
|
||||
Type: "string",
|
||||
},
|
||||
},
|
||||
"optional": {
|
||||
Generic: schema.Generic{
|
||||
Type: "string",
|
||||
},
|
||||
},
|
||||
},
|
||||
}},
|
||||
ValueValidation: &schema.ValueValidation{
|
||||
MaxProperties: maxLength,
|
||||
},
|
||||
@ -1196,7 +1196,7 @@ func genAllMaxNestedSpecWithRootRule(rule string) func(maxLength *int64) *schema
|
||||
ValueValidation: &schema.ValueValidation{
|
||||
MaxItems: maxLength,
|
||||
},
|
||||
Extensions: schema.Extensions{
|
||||
ValidationExtensions: schema.ValidationExtensions{
|
||||
XValidations: apiextensions.ValidationRules{
|
||||
{
|
||||
Rule: rule,
|
||||
@ -1216,32 +1216,32 @@ func genOneMaxNestedSpecWithRootRule(rule string) func(maxLength *int64) *schema
|
||||
Items: &schema.Structural{
|
||||
Generic: schema.Generic{
|
||||
Type: "object",
|
||||
AdditionalProperties: &schema.StructuralOrBool{Structural: &schema.Structural{
|
||||
Generic: schema.Generic{
|
||||
Type: "object",
|
||||
},
|
||||
ValueValidation: &schema.ValueValidation{
|
||||
Required: []string{"required"},
|
||||
},
|
||||
Properties: map[string]schema.Structural{
|
||||
"required": {
|
||||
Generic: schema.Generic{
|
||||
Type: "string",
|
||||
},
|
||||
},
|
||||
"optional": {
|
||||
Generic: schema.Generic{
|
||||
Type: "string",
|
||||
},
|
||||
},
|
||||
},
|
||||
}},
|
||||
},
|
||||
AdditionalProperties: &schema.StructuralOrBool{Structural: &schema.Structural{
|
||||
Generic: schema.Generic{
|
||||
Type: "object",
|
||||
},
|
||||
ValueValidation: &schema.ValueValidation{
|
||||
Required: []string{"required"},
|
||||
},
|
||||
Properties: map[string]schema.Structural{
|
||||
"required": {
|
||||
Generic: schema.Generic{
|
||||
Type: "string",
|
||||
},
|
||||
},
|
||||
"optional": {
|
||||
Generic: schema.Generic{
|
||||
Type: "string",
|
||||
},
|
||||
},
|
||||
},
|
||||
}},
|
||||
ValueValidation: &schema.ValueValidation{
|
||||
MaxProperties: maxLength,
|
||||
},
|
||||
},
|
||||
Extensions: schema.Extensions{
|
||||
ValidationExtensions: schema.ValidationExtensions{
|
||||
XValidations: apiextensions.ValidationRules{
|
||||
{
|
||||
Rule: rule,
|
||||
@ -1292,12 +1292,12 @@ func genMapForMap() *schema.Structural {
|
||||
return &schema.Structural{
|
||||
Generic: schema.Generic{
|
||||
Type: "object",
|
||||
AdditionalProperties: &schema.StructuralOrBool{Structural: &schema.Structural{
|
||||
Generic: schema.Generic{
|
||||
Type: "number",
|
||||
},
|
||||
}},
|
||||
},
|
||||
AdditionalProperties: &schema.StructuralOrBool{Structural: &schema.Structural{
|
||||
Generic: schema.Generic{
|
||||
Type: "number",
|
||||
},
|
||||
}},
|
||||
}
|
||||
}
|
||||
|
||||
@ -1305,13 +1305,13 @@ func genMapWithCustomItemRule(item *schema.Structural, rule string) func(maxProp
|
||||
return func(maxProperties *int64) *schema.Structural {
|
||||
return &schema.Structural{
|
||||
Generic: schema.Generic{
|
||||
Type: "object",
|
||||
AdditionalProperties: &schema.StructuralOrBool{Structural: item},
|
||||
Type: "object",
|
||||
},
|
||||
AdditionalProperties: &schema.StructuralOrBool{Structural: item},
|
||||
ValueValidation: &schema.ValueValidation{
|
||||
MaxProperties: maxProperties,
|
||||
},
|
||||
Extensions: schema.Extensions{
|
||||
ValidationExtensions: schema.ValidationExtensions{
|
||||
XValidations: apiextensions.ValidationRules{
|
||||
{
|
||||
Rule: rule,
|
||||
|
@ -279,11 +279,18 @@ func nestedValueValidationToStructural(nvv *schema.NestedValueValidation) *Struc
|
||||
newProperties[k] = *nestedValueValidationToStructural(&v).Structural
|
||||
}
|
||||
|
||||
var newAdditionalProperties *schema.StructuralOrBool
|
||||
if nvv.AdditionalProperties != nil {
|
||||
newAdditionalProperties = &schema.StructuralOrBool{Structural: nestedValueValidationToStructural(nvv.AdditionalProperties).Structural}
|
||||
}
|
||||
|
||||
return &Structural{
|
||||
Structural: &schema.Structural{
|
||||
Items: newItems,
|
||||
Properties: newProperties,
|
||||
ValueValidation: &nvv.ValueValidation,
|
||||
Items: newItems,
|
||||
Properties: newProperties,
|
||||
AdditionalProperties: newAdditionalProperties,
|
||||
ValueValidation: &nvv.ValueValidation,
|
||||
ValidationExtensions: nvv.ValidationExtensions,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -49,9 +49,11 @@ func WithTypeAndObjectMeta(s *schema.Structural) *schema.Structural {
|
||||
return s
|
||||
}
|
||||
result := &schema.Structural{
|
||||
Generic: s.Generic,
|
||||
Extensions: s.Extensions,
|
||||
ValueValidation: s.ValueValidation,
|
||||
AdditionalProperties: s.AdditionalProperties,
|
||||
Generic: s.Generic,
|
||||
Extensions: s.Extensions,
|
||||
ValueValidation: s.ValueValidation,
|
||||
ValidationExtensions: s.ValidationExtensions,
|
||||
}
|
||||
props := make(map[string]schema.Structural, len(s.Properties))
|
||||
for k, prop := range s.Properties {
|
||||
|
@ -199,11 +199,11 @@ func testSchema() *schema.Structural {
|
||||
"flags": {
|
||||
Generic: schema.Generic{
|
||||
Type: "object",
|
||||
AdditionalProperties: &schema.StructuralOrBool{
|
||||
Structural: &schema.Structural{
|
||||
Generic: schema.Generic{
|
||||
Type: "boolean",
|
||||
},
|
||||
},
|
||||
AdditionalProperties: &schema.StructuralOrBool{
|
||||
Structural: &schema.Structural{
|
||||
Generic: schema.Generic{
|
||||
Type: "boolean",
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -317,12 +317,12 @@ func TestEstimateMaxLengthJSON(t *testing.T) {
|
||||
InputSchema: &schema.Structural{
|
||||
Generic: schema.Generic{
|
||||
Type: "object",
|
||||
AdditionalProperties: &schema.StructuralOrBool{Structural: &schema.Structural{
|
||||
Generic: schema.Generic{
|
||||
Type: "string",
|
||||
},
|
||||
}},
|
||||
},
|
||||
AdditionalProperties: &schema.StructuralOrBool{Structural: &schema.Structural{
|
||||
Generic: schema.Generic{
|
||||
Type: "string",
|
||||
},
|
||||
}},
|
||||
},
|
||||
// expected JSON is {"":"","":"",...} so our length should be (3000000 - 2) / 6
|
||||
ExpectedMaxElements: 393215,
|
||||
@ -382,12 +382,12 @@ func TestEstimateMaxLengthJSON(t *testing.T) {
|
||||
InputSchema: &schema.Structural{
|
||||
Generic: schema.Generic{
|
||||
Type: "object",
|
||||
AdditionalProperties: &schema.StructuralOrBool{Structural: &schema.Structural{
|
||||
Generic: schema.Generic{
|
||||
Type: "string",
|
||||
},
|
||||
}},
|
||||
},
|
||||
AdditionalProperties: &schema.StructuralOrBool{Structural: &schema.Structural{
|
||||
Generic: schema.Generic{
|
||||
Type: "string",
|
||||
},
|
||||
}},
|
||||
ValueValidation: &schema.ValueValidation{
|
||||
Format: "string",
|
||||
MaxProperties: maxPtr(15),
|
||||
@ -519,15 +519,15 @@ func genNestedSchema(depth int) *schema.Structural {
|
||||
generator = func(d int) schema.Structural {
|
||||
nodeTemplate := schema.Structural{
|
||||
Generic: schema.Generic{
|
||||
Type: "object",
|
||||
AdditionalProperties: &schema.StructuralOrBool{},
|
||||
Type: "object",
|
||||
},
|
||||
AdditionalProperties: &schema.StructuralOrBool{},
|
||||
}
|
||||
if d == 1 {
|
||||
return nodeTemplate
|
||||
} else {
|
||||
mapType := generator(d - 1)
|
||||
nodeTemplate.Generic.AdditionalProperties.Structural = &mapType
|
||||
nodeTemplate.AdditionalProperties.Structural = &mapType
|
||||
return nodeTemplate
|
||||
}
|
||||
}
|
||||
|
@ -2787,7 +2787,7 @@ func TestReasonAndFldPath(t *testing.T) {
|
||||
"field2": stringType,
|
||||
"field3": stringType,
|
||||
},
|
||||
Extensions: schema.Extensions{
|
||||
ValidationExtensions: schema.ValidationExtensions{
|
||||
XValidations: apiextensions.ValidationRules{
|
||||
{
|
||||
Rule: `self.field2 != "value2"`,
|
||||
@ -2852,16 +2852,16 @@ func TestValidateFieldPath(t *testing.T) {
|
||||
"foo": {
|
||||
Generic: schema.Generic{
|
||||
Type: "object",
|
||||
AdditionalProperties: &schema.StructuralOrBool{
|
||||
Structural: &schema.Structural{
|
||||
Generic: schema.Generic{
|
||||
Type: "object",
|
||||
},
|
||||
Properties: map[string]schema.Structural{
|
||||
"subAdd": {
|
||||
Generic: schema.Generic{
|
||||
Type: "number",
|
||||
},
|
||||
},
|
||||
AdditionalProperties: &schema.StructuralOrBool{
|
||||
Structural: &schema.Structural{
|
||||
Generic: schema.Generic{
|
||||
Type: "object",
|
||||
},
|
||||
Properties: map[string]schema.Structural{
|
||||
"subAdd": {
|
||||
Generic: schema.Generic{
|
||||
Type: "number",
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -4387,7 +4387,7 @@ func BenchmarkCELValidationWithAndWithoutOldSelfReference(b *testing.B) {
|
||||
ValueValidation: &schema.ValueValidation{
|
||||
Format: "date-time",
|
||||
},
|
||||
Extensions: schema.Extensions{
|
||||
ValidationExtensions: schema.ValidationExtensions{
|
||||
XValidations: []apiextensions.ValidationRule{
|
||||
{Rule: rule},
|
||||
},
|
||||
@ -4520,9 +4520,9 @@ func objectTypePtr(props map[string]schema.Structural) *schema.Structural {
|
||||
func mapType(valSchema *schema.Structural) schema.Structural {
|
||||
result := schema.Structural{
|
||||
Generic: schema.Generic{
|
||||
Type: "object",
|
||||
AdditionalProperties: &schema.StructuralOrBool{Bool: true, Structural: valSchema},
|
||||
Type: "object",
|
||||
},
|
||||
AdditionalProperties: &schema.StructuralOrBool{Bool: true, Structural: valSchema},
|
||||
}
|
||||
return result
|
||||
}
|
||||
@ -4541,7 +4541,7 @@ func intOrStringType() schema.Structural {
|
||||
}
|
||||
|
||||
func withRule(s schema.Structural, rule string) schema.Structural {
|
||||
s.Extensions.XValidations = apiextensions.ValidationRules{
|
||||
s.XValidations = apiextensions.ValidationRules{
|
||||
{
|
||||
Rule: rule,
|
||||
},
|
||||
@ -4550,7 +4550,7 @@ func withRule(s schema.Structural, rule string) schema.Structural {
|
||||
}
|
||||
|
||||
func withRuleMessageAndMessageExpression(s schema.Structural, rule, message, messageExpression string) schema.Structural {
|
||||
s.Extensions.XValidations = apiextensions.ValidationRules{
|
||||
s.XValidations = apiextensions.ValidationRules{
|
||||
{
|
||||
Rule: rule,
|
||||
Message: message,
|
||||
@ -4561,7 +4561,7 @@ func withRuleMessageAndMessageExpression(s schema.Structural, rule, message, mes
|
||||
}
|
||||
|
||||
func withReasonAndFldPath(s schema.Structural, rule, jsonPath string, reason *apiextensions.FieldValueErrorReason) schema.Structural {
|
||||
s.Extensions.XValidations = apiextensions.ValidationRules{
|
||||
s.XValidations = apiextensions.ValidationRules{
|
||||
{
|
||||
Rule: rule,
|
||||
FieldPath: jsonPath,
|
||||
@ -4572,7 +4572,7 @@ func withReasonAndFldPath(s schema.Structural, rule, jsonPath string, reason *ap
|
||||
}
|
||||
|
||||
func withRuleAndMessageExpression(s schema.Structural, rule, messageExpression string) schema.Structural {
|
||||
s.Extensions.XValidations = apiextensions.ValidationRules{
|
||||
s.XValidations = apiextensions.ValidationRules{
|
||||
{
|
||||
Rule: rule,
|
||||
MessageExpression: messageExpression,
|
||||
@ -4582,7 +4582,7 @@ func withRuleAndMessageExpression(s schema.Structural, rule, messageExpression s
|
||||
}
|
||||
|
||||
func withRulePtr(s *schema.Structural, rule string) *schema.Structural {
|
||||
s.Extensions.XValidations = apiextensions.ValidationRules{
|
||||
s.XValidations = apiextensions.ValidationRules{
|
||||
{
|
||||
Rule: rule,
|
||||
},
|
||||
|
@ -100,10 +100,10 @@ var (
|
||||
mapSchema = schema.Structural{
|
||||
Generic: schema.Generic{
|
||||
Type: "object",
|
||||
AdditionalProperties: &schema.StructuralOrBool{
|
||||
Bool: true,
|
||||
Structural: &stringSchema,
|
||||
},
|
||||
},
|
||||
AdditionalProperties: &schema.StructuralOrBool{
|
||||
Bool: true,
|
||||
Structural: &stringSchema,
|
||||
},
|
||||
}
|
||||
)
|
||||
|
@ -18,6 +18,7 @@ package schema
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions"
|
||||
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
|
||||
)
|
||||
@ -62,10 +63,16 @@ func NewStructural(s *apiextensions.JSONSchemaProps) (*Structural, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
vx, err := newValidationExtensions(s)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ss := &Structural{
|
||||
Generic: *g,
|
||||
Extensions: *x,
|
||||
ValueValidation: vv,
|
||||
Generic: *g,
|
||||
Extensions: *x,
|
||||
ValueValidation: vv,
|
||||
ValidationExtensions: *vx,
|
||||
}
|
||||
|
||||
if s.Items != nil {
|
||||
@ -91,6 +98,18 @@ func NewStructural(s *apiextensions.JSONSchemaProps) (*Structural, error) {
|
||||
}
|
||||
}
|
||||
|
||||
if s.AdditionalProperties != nil {
|
||||
if s.AdditionalProperties.Schema != nil {
|
||||
additionalPropertiesSchema, err := NewStructural(s.AdditionalProperties.Schema)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ss.AdditionalProperties = &StructuralOrBool{Structural: additionalPropertiesSchema, Bool: true}
|
||||
} else {
|
||||
ss.AdditionalProperties = &StructuralOrBool{Bool: s.AdditionalProperties.Allows}
|
||||
}
|
||||
}
|
||||
|
||||
return ss, nil
|
||||
}
|
||||
|
||||
@ -108,18 +127,6 @@ func newGenerics(s *apiextensions.JSONSchemaProps) (*Generic, error) {
|
||||
g.Default = JSON{interface{}(*s.Default)}
|
||||
}
|
||||
|
||||
if s.AdditionalProperties != nil {
|
||||
if s.AdditionalProperties.Schema != nil {
|
||||
ss, err := NewStructural(s.AdditionalProperties.Schema)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
g.AdditionalProperties = &StructuralOrBool{Structural: ss, Bool: true}
|
||||
} else {
|
||||
g.AdditionalProperties = &StructuralOrBool{Bool: s.AdditionalProperties.Allows}
|
||||
}
|
||||
}
|
||||
|
||||
return g, nil
|
||||
}
|
||||
|
||||
@ -205,10 +212,16 @@ func newNestedValueValidation(s *apiextensions.JSONSchemaProps) (*NestedValueVal
|
||||
return nil, err
|
||||
}
|
||||
|
||||
vx, err := newValidationExtensions(s)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
v := &NestedValueValidation{
|
||||
ValueValidation: *vv,
|
||||
ForbiddenGenerics: *g,
|
||||
ForbiddenExtensions: *x,
|
||||
ValueValidation: *vv,
|
||||
ValidationExtensions: *vx,
|
||||
ForbiddenGenerics: *g,
|
||||
ForbiddenExtensions: *x,
|
||||
}
|
||||
|
||||
if s.Items != nil {
|
||||
@ -232,6 +245,18 @@ func newNestedValueValidation(s *apiextensions.JSONSchemaProps) (*NestedValueVal
|
||||
v.Properties[k] = *nvv
|
||||
}
|
||||
}
|
||||
if s.AdditionalProperties != nil {
|
||||
if s.AdditionalProperties.Schema != nil {
|
||||
additionalPropertiesSchema, err := newNestedValueValidation(s.AdditionalProperties.Schema)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
v.AdditionalProperties = additionalPropertiesSchema
|
||||
} else if s.AdditionalProperties.Allows {
|
||||
v.AdditionalProperties = &NestedValueValidation{}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return v, nil
|
||||
}
|
||||
@ -248,9 +273,6 @@ func newExtensions(s *apiextensions.JSONSchemaProps) (*Extensions, error) {
|
||||
XListType: s.XListType,
|
||||
XMapType: s.XMapType,
|
||||
}
|
||||
if err := apiextensionsv1.Convert_apiextensions_ValidationRules_To_v1_ValidationRules(&s.XValidations, &ret.XValidations, nil); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if s.XPreserveUnknownFields != nil {
|
||||
if !*s.XPreserveUnknownFields {
|
||||
@ -262,6 +284,19 @@ func newExtensions(s *apiextensions.JSONSchemaProps) (*Extensions, error) {
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func newValidationExtensions(s *apiextensions.JSONSchemaProps) (*ValidationExtensions, error) {
|
||||
if s == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
ret := &ValidationExtensions{}
|
||||
if err := apiextensionsv1.Convert_apiextensions_ValidationRules_To_v1_ValidationRules(&s.XValidations, &ret.XValidations, nil); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
// validateUnsupportedFields checks that those fields rejected by validation are actually unset.
|
||||
func validateUnsupportedFields(s *apiextensions.JSONSchemaProps) error {
|
||||
if len(s.ID) > 0 {
|
||||
|
@ -99,19 +99,17 @@ func TestDefault(t *testing.T) {
|
||||
},
|
||||
},
|
||||
"additionalProperties": {
|
||||
Generic: structuralschema.Generic{
|
||||
AdditionalProperties: &structuralschema.StructuralOrBool{
|
||||
Structural: &structuralschema.Structural{
|
||||
Properties: map[string]structuralschema.Structural{
|
||||
"a": {
|
||||
Generic: structuralschema.Generic{
|
||||
Default: structuralschema.JSON{Object: "alpha"},
|
||||
},
|
||||
AdditionalProperties: &structuralschema.StructuralOrBool{
|
||||
Structural: &structuralschema.Structural{
|
||||
Properties: map[string]structuralschema.Structural{
|
||||
"a": {
|
||||
Generic: structuralschema.Generic{
|
||||
Default: structuralschema.JSON{Object: "alpha"},
|
||||
},
|
||||
"b": {
|
||||
Generic: structuralschema.Generic{
|
||||
Default: structuralschema.JSON{Object: "beta"},
|
||||
},
|
||||
},
|
||||
"b": {
|
||||
Generic: structuralschema.Generic{
|
||||
Default: structuralschema.JSON{Object: "beta"},
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -182,34 +180,28 @@ func TestDefault(t *testing.T) {
|
||||
},
|
||||
}, `{"a": "A"}`},
|
||||
{"null in nullable object with additionalProperties", `{"a": null}`, &structuralschema.Structural{
|
||||
Generic: structuralschema.Generic{
|
||||
AdditionalProperties: &structuralschema.StructuralOrBool{
|
||||
Structural: &structuralschema.Structural{
|
||||
Generic: structuralschema.Generic{
|
||||
Nullable: true,
|
||||
Default: structuralschema.JSON{Object: "A"},
|
||||
},
|
||||
AdditionalProperties: &structuralschema.StructuralOrBool{
|
||||
Structural: &structuralschema.Structural{
|
||||
Generic: structuralschema.Generic{
|
||||
Nullable: true,
|
||||
Default: structuralschema.JSON{Object: "A"},
|
||||
},
|
||||
},
|
||||
},
|
||||
}, `{"a": null}`},
|
||||
{"null in non-nullable object with additionalProperties", `{"a": null}`, &structuralschema.Structural{
|
||||
Generic: structuralschema.Generic{
|
||||
AdditionalProperties: &structuralschema.StructuralOrBool{
|
||||
Structural: &structuralschema.Structural{
|
||||
Generic: structuralschema.Generic{
|
||||
Nullable: false,
|
||||
Default: structuralschema.JSON{Object: "A"},
|
||||
},
|
||||
AdditionalProperties: &structuralschema.StructuralOrBool{
|
||||
Structural: &structuralschema.Structural{
|
||||
Generic: structuralschema.Generic{
|
||||
Nullable: false,
|
||||
Default: structuralschema.JSON{Object: "A"},
|
||||
},
|
||||
},
|
||||
},
|
||||
}, `{"a": "A"}`},
|
||||
{"null unknown field", `{"a": null}`, &structuralschema.Structural{
|
||||
Generic: structuralschema.Generic{
|
||||
AdditionalProperties: &structuralschema.StructuralOrBool{
|
||||
Bool: true,
|
||||
},
|
||||
AdditionalProperties: &structuralschema.StructuralOrBool{
|
||||
Bool: true,
|
||||
},
|
||||
}, `{"a": null}`},
|
||||
}
|
||||
|
@ -37,10 +37,16 @@ func (s *Structural) ToKubeOpenAPI() *spec.Schema {
|
||||
ret.Properties[k] = *v.ToKubeOpenAPI()
|
||||
}
|
||||
}
|
||||
if s.AdditionalProperties != nil {
|
||||
ret.AdditionalProperties = &spec.SchemaOrBool{
|
||||
Allows: s.AdditionalProperties.Bool,
|
||||
Schema: s.AdditionalProperties.Structural.ToKubeOpenAPI(),
|
||||
}
|
||||
}
|
||||
s.Generic.toKubeOpenAPI(ret)
|
||||
s.Extensions.toKubeOpenAPI(ret)
|
||||
s.ValueValidation.toKubeOpenAPI(ret)
|
||||
|
||||
s.ValidationExtensions.toKubeOpenAPI(ret)
|
||||
return ret
|
||||
}
|
||||
|
||||
@ -53,12 +59,6 @@ func (g *Generic) toKubeOpenAPI(ret *spec.Schema) {
|
||||
ret.Type = spec.StringOrArray{g.Type}
|
||||
}
|
||||
ret.Nullable = g.Nullable
|
||||
if g.AdditionalProperties != nil {
|
||||
ret.AdditionalProperties = &spec.SchemaOrBool{
|
||||
Allows: g.AdditionalProperties.Bool,
|
||||
Schema: g.AdditionalProperties.Structural.ToKubeOpenAPI(),
|
||||
}
|
||||
}
|
||||
ret.Description = g.Description
|
||||
ret.Title = g.Title
|
||||
ret.Default = g.Default.Object
|
||||
@ -87,6 +87,13 @@ func (x *Extensions) toKubeOpenAPI(ret *spec.Schema) {
|
||||
if x.XMapType != nil {
|
||||
ret.VendorExtensible.AddExtension("x-kubernetes-map-type", *x.XMapType)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *ValidationExtensions) toKubeOpenAPI(ret *spec.Schema) {
|
||||
if x == nil {
|
||||
return
|
||||
}
|
||||
|
||||
if len(x.XValidations) > 0 {
|
||||
ret.VendorExtensible.AddExtension("x-kubernetes-validations", x.XValidations)
|
||||
}
|
||||
@ -138,6 +145,7 @@ func (vv *NestedValueValidation) toKubeOpenAPI() *spec.Schema {
|
||||
ret := &spec.Schema{}
|
||||
|
||||
vv.ValueValidation.toKubeOpenAPI(ret)
|
||||
vv.ValidationExtensions.toKubeOpenAPI(ret)
|
||||
if vv.Items != nil {
|
||||
ret.Items = &spec.SchemaOrArray{Schema: vv.Items.toKubeOpenAPI()}
|
||||
}
|
||||
@ -149,6 +157,5 @@ func (vv *NestedValueValidation) toKubeOpenAPI() *spec.Schema {
|
||||
}
|
||||
vv.ForbiddenGenerics.toKubeOpenAPI(ret) // normally empty. Exception: int-or-string
|
||||
vv.ForbiddenExtensions.toKubeOpenAPI(ret) // shouldn't do anything
|
||||
|
||||
return ret
|
||||
}
|
||||
|
@ -202,18 +202,18 @@ func TestValidateListSetsAndMaps(t *testing.T) {
|
||||
schema: &schema.Structural{
|
||||
Generic: schema.Generic{
|
||||
Type: "object",
|
||||
AdditionalProperties: &schema.StructuralOrBool{
|
||||
Structural: &schema.Structural{
|
||||
},
|
||||
AdditionalProperties: &schema.StructuralOrBool{
|
||||
Structural: &schema.Structural{
|
||||
Generic: schema.Generic{
|
||||
Type: "array",
|
||||
},
|
||||
Extensions: schema.Extensions{
|
||||
XListType: strPtr("set"),
|
||||
},
|
||||
Items: &schema.Structural{
|
||||
Generic: schema.Generic{
|
||||
Type: "array",
|
||||
},
|
||||
Extensions: schema.Extensions{
|
||||
XListType: strPtr("set"),
|
||||
},
|
||||
Items: &schema.Structural{
|
||||
Generic: schema.Generic{
|
||||
Type: "string",
|
||||
},
|
||||
Type: "string",
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -387,11 +387,11 @@ func TestValidateListSetsAndMaps(t *testing.T) {
|
||||
Items: &schema.Structural{
|
||||
Generic: schema.Generic{
|
||||
Type: "object",
|
||||
AdditionalProperties: &schema.StructuralOrBool{
|
||||
Structural: &schema.Structural{
|
||||
Generic: schema.Generic{
|
||||
Type: "string",
|
||||
},
|
||||
},
|
||||
AdditionalProperties: &schema.StructuralOrBool{
|
||||
Structural: &schema.Structural{
|
||||
Generic: schema.Generic{
|
||||
Type: "string",
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -407,11 +407,11 @@ func TestValidateListSetsAndMaps(t *testing.T) {
|
||||
Items: &schema.Structural{
|
||||
Generic: schema.Generic{
|
||||
Type: "object",
|
||||
AdditionalProperties: &schema.StructuralOrBool{
|
||||
Structural: &schema.Structural{
|
||||
Generic: schema.Generic{
|
||||
Type: "string",
|
||||
},
|
||||
},
|
||||
AdditionalProperties: &schema.StructuralOrBool{
|
||||
Structural: &schema.Structural{
|
||||
Generic: schema.Generic{
|
||||
Type: "string",
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -427,12 +427,12 @@ func TestValidateListSetsAndMaps(t *testing.T) {
|
||||
Items: &schema.Structural{
|
||||
Generic: schema.Generic{
|
||||
Type: "object",
|
||||
AdditionalProperties: &schema.StructuralOrBool{
|
||||
Structural: &schema.Structural{
|
||||
Generic: schema.Generic{
|
||||
Type: "string",
|
||||
Nullable: true,
|
||||
},
|
||||
},
|
||||
AdditionalProperties: &schema.StructuralOrBool{
|
||||
Structural: &schema.Structural{
|
||||
Generic: schema.Generic{
|
||||
Type: "string",
|
||||
Nullable: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -485,11 +485,11 @@ func TestValidateListSetsAndMaps(t *testing.T) {
|
||||
Items: &schema.Structural{
|
||||
Generic: schema.Generic{
|
||||
Type: "object",
|
||||
AdditionalProperties: &schema.StructuralOrBool{
|
||||
Structural: &schema.Structural{
|
||||
Generic: schema.Generic{
|
||||
Type: "string",
|
||||
},
|
||||
},
|
||||
AdditionalProperties: &schema.StructuralOrBool{
|
||||
Structural: &schema.Structural{
|
||||
Generic: schema.Generic{
|
||||
Type: "string",
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -670,11 +670,11 @@ func TestValidateListSetsAndMaps(t *testing.T) {
|
||||
Items: &schema.Structural{
|
||||
Generic: schema.Generic{
|
||||
Type: "object",
|
||||
AdditionalProperties: &schema.StructuralOrBool{
|
||||
Structural: &schema.Structural{
|
||||
Generic: schema.Generic{
|
||||
Type: "string",
|
||||
},
|
||||
},
|
||||
AdditionalProperties: &schema.StructuralOrBool{
|
||||
Structural: &schema.Structural{
|
||||
Generic: schema.Generic{
|
||||
Type: "string",
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -691,11 +691,11 @@ func TestValidateListSetsAndMaps(t *testing.T) {
|
||||
Items: &schema.Structural{
|
||||
Generic: schema.Generic{
|
||||
Type: "object",
|
||||
AdditionalProperties: &schema.StructuralOrBool{
|
||||
Structural: &schema.Structural{
|
||||
Generic: schema.Generic{
|
||||
Type: "string",
|
||||
},
|
||||
},
|
||||
AdditionalProperties: &schema.StructuralOrBool{
|
||||
Structural: &schema.Structural{
|
||||
Generic: schema.Generic{
|
||||
Type: "string",
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -712,11 +712,11 @@ func TestValidateListSetsAndMaps(t *testing.T) {
|
||||
Items: &schema.Structural{
|
||||
Generic: schema.Generic{
|
||||
Type: "object",
|
||||
AdditionalProperties: &schema.StructuralOrBool{
|
||||
Structural: &schema.Structural{
|
||||
Generic: schema.Generic{
|
||||
Type: "string",
|
||||
},
|
||||
},
|
||||
AdditionalProperties: &schema.StructuralOrBool{
|
||||
Structural: &schema.Structural{
|
||||
Generic: schema.Generic{
|
||||
Type: "string",
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -733,12 +733,12 @@ func TestValidateListSetsAndMaps(t *testing.T) {
|
||||
Items: &schema.Structural{
|
||||
Generic: schema.Generic{
|
||||
Type: "object",
|
||||
AdditionalProperties: &schema.StructuralOrBool{
|
||||
Structural: &schema.Structural{
|
||||
Generic: schema.Generic{
|
||||
Type: "string",
|
||||
Nullable: true,
|
||||
},
|
||||
},
|
||||
AdditionalProperties: &schema.StructuralOrBool{
|
||||
Structural: &schema.Structural{
|
||||
Generic: schema.Generic{
|
||||
Type: "string",
|
||||
Nullable: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -856,12 +856,12 @@ func TestValidateListSetsAndMaps(t *testing.T) {
|
||||
Items: &schema.Structural{
|
||||
Generic: schema.Generic{
|
||||
Type: "object",
|
||||
AdditionalProperties: &schema.StructuralOrBool{
|
||||
Structural: &schema.Structural{
|
||||
Generic: schema.Generic{
|
||||
Type: "string",
|
||||
Nullable: true,
|
||||
},
|
||||
},
|
||||
AdditionalProperties: &schema.StructuralOrBool{
|
||||
Structural: &schema.Structural{
|
||||
Generic: schema.Generic{
|
||||
Type: "string",
|
||||
Nullable: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -171,11 +171,9 @@ func TestValidate(t *testing.T) {
|
||||
},
|
||||
},
|
||||
"additionalProperties": {
|
||||
Generic: structuralschema.Generic{
|
||||
AdditionalProperties: &structuralschema.StructuralOrBool{
|
||||
Structural: &structuralschema.Structural{
|
||||
Extensions: structuralschema.Extensions{XEmbeddedResource: true},
|
||||
},
|
||||
AdditionalProperties: &structuralschema.StructuralOrBool{
|
||||
Structural: &structuralschema.Structural{
|
||||
Extensions: structuralschema.Extensions{XEmbeddedResource: true},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -146,12 +146,12 @@ func TestPrune(t *testing.T) {
|
||||
Extensions: structuralschema.Extensions{XPreserveUnknownFields: true},
|
||||
Generic: structuralschema.Generic{
|
||||
Type: "object",
|
||||
AdditionalProperties: &structuralschema.StructuralOrBool{
|
||||
Structural: &structuralschema.Structural{
|
||||
Generic: structuralschema.Generic{Type: "object"},
|
||||
Properties: map[string]structuralschema.Structural{
|
||||
"specified": {Generic: structuralschema.Generic{Type: "object"}},
|
||||
},
|
||||
},
|
||||
AdditionalProperties: &structuralschema.StructuralOrBool{
|
||||
Structural: &structuralschema.Structural{
|
||||
Generic: structuralschema.Generic{Type: "object"},
|
||||
Properties: map[string]structuralschema.Structural{
|
||||
"specified": {Generic: structuralschema.Generic{Type: "object"}},
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -159,12 +159,12 @@ func TestPrune(t *testing.T) {
|
||||
"preservingAdditionalPropertiesKeyPruneValues": {
|
||||
Generic: structuralschema.Generic{
|
||||
Type: "object",
|
||||
AdditionalProperties: &structuralschema.StructuralOrBool{
|
||||
Structural: &structuralschema.Structural{
|
||||
Generic: structuralschema.Generic{Type: "object"},
|
||||
Properties: map[string]structuralschema.Structural{
|
||||
"specified": {Generic: structuralschema.Generic{Type: "object"}},
|
||||
},
|
||||
},
|
||||
AdditionalProperties: &structuralschema.StructuralOrBool{
|
||||
Structural: &structuralschema.Structural{
|
||||
Generic: structuralschema.Generic{Type: "object"},
|
||||
Properties: map[string]structuralschema.Structural{
|
||||
"specified": {Generic: structuralschema.Generic{Type: "object"}},
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -203,12 +203,10 @@ func TestPrune(t *testing.T) {
|
||||
Properties: map[string]structuralschema.Structural{
|
||||
"a": {},
|
||||
"c": {
|
||||
Generic: structuralschema.Generic{
|
||||
AdditionalProperties: &structuralschema.StructuralOrBool{
|
||||
Structural: &structuralschema.Structural{
|
||||
Generic: structuralschema.Generic{
|
||||
Type: "integer",
|
||||
},
|
||||
AdditionalProperties: &structuralschema.StructuralOrBool{
|
||||
Structural: &structuralschema.Structural{
|
||||
Generic: structuralschema.Generic{
|
||||
Type: "integer",
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -220,10 +218,8 @@ func TestPrune(t *testing.T) {
|
||||
Properties: map[string]structuralschema.Structural{
|
||||
"a": {},
|
||||
"c": {
|
||||
Generic: structuralschema.Generic{
|
||||
AdditionalProperties: &structuralschema.StructuralOrBool{
|
||||
Bool: false,
|
||||
},
|
||||
AdditionalProperties: &structuralschema.StructuralOrBool{
|
||||
Bool: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -25,11 +25,13 @@ import (
|
||||
|
||||
// Structural represents a structural schema.
|
||||
type Structural struct {
|
||||
Items *Structural
|
||||
Properties map[string]Structural
|
||||
Items *Structural
|
||||
Properties map[string]Structural
|
||||
AdditionalProperties *StructuralOrBool
|
||||
|
||||
Generic
|
||||
Extensions
|
||||
ValidationExtensions
|
||||
|
||||
ValueValidation *ValueValidation
|
||||
}
|
||||
@ -51,11 +53,10 @@ type Generic struct {
|
||||
// It can be object, array, number, integer, boolean, string.
|
||||
// It is optional only if x-kubernetes-preserve-unknown-fields
|
||||
// or x-kubernetes-int-or-string is true.
|
||||
Type string
|
||||
Title string
|
||||
Default JSON
|
||||
AdditionalProperties *StructuralOrBool
|
||||
Nullable bool
|
||||
Type string
|
||||
Title string
|
||||
Default JSON
|
||||
Nullable bool
|
||||
}
|
||||
|
||||
// +k8s:deepcopy-gen=true
|
||||
@ -128,7 +129,13 @@ type Extensions struct {
|
||||
// Atomic maps will be entirely replaced when updated.
|
||||
// +optional
|
||||
XMapType *string
|
||||
}
|
||||
|
||||
// +k8s:deepcopy-gen=true
|
||||
|
||||
// ValidationExtensions contains the Kubernetes OpenAPI v3 extensions that are
|
||||
// used for validation rather than structure.
|
||||
type ValidationExtensions struct {
|
||||
// x-kubernetes-validations describes a list of validation rules for expression validation.
|
||||
// Use the v1 struct since this gets serialized as an extension.
|
||||
XValidations apiextensionsv1.ValidationRules
|
||||
@ -166,9 +173,11 @@ type ValueValidation struct {
|
||||
// under a logical junctor, and catch all structs for generic and vendor extensions schema fields.
|
||||
type NestedValueValidation struct {
|
||||
ValueValidation
|
||||
ValidationExtensions
|
||||
|
||||
Items *NestedValueValidation
|
||||
Properties map[string]NestedValueValidation
|
||||
Items *NestedValueValidation
|
||||
Properties map[string]NestedValueValidation
|
||||
AdditionalProperties *NestedValueValidation
|
||||
|
||||
// Anything set in the following will make the scheme
|
||||
// non-structural, with the exception of these two patterns if
|
||||
|
@ -91,6 +91,16 @@ func validateStructuralInvariants(s *Structural, lvl level, fldPath *field.Path)
|
||||
for k, v := range s.Properties {
|
||||
allErrs = append(allErrs, validateStructuralInvariants(&v, fieldLevel, fldPath.Child("properties").Key(k))...)
|
||||
}
|
||||
|
||||
if s.AdditionalProperties != nil {
|
||||
if lvl == rootLevel {
|
||||
allErrs = append(allErrs, field.Forbidden(fldPath.Child("additionalProperties"), "must not be used at the root"))
|
||||
}
|
||||
if s.AdditionalProperties.Structural != nil {
|
||||
allErrs = append(allErrs, validateStructuralInvariants(s.AdditionalProperties.Structural, fieldLevel, fldPath.Child("additionalProperties"))...)
|
||||
}
|
||||
}
|
||||
|
||||
allErrs = append(allErrs, validateGeneric(&s.Generic, lvl, fldPath)...)
|
||||
allErrs = append(allErrs, validateExtensions(&s.Extensions, fldPath)...)
|
||||
|
||||
@ -207,18 +217,7 @@ func validateGeneric(g *Generic, lvl level, fldPath *field.Path) field.ErrorList
|
||||
return nil
|
||||
}
|
||||
|
||||
allErrs := field.ErrorList{}
|
||||
|
||||
if g.AdditionalProperties != nil {
|
||||
if lvl == rootLevel {
|
||||
allErrs = append(allErrs, field.Forbidden(fldPath.Child("additionalProperties"), "must not be used at the root"))
|
||||
}
|
||||
if g.AdditionalProperties.Structural != nil {
|
||||
allErrs = append(allErrs, validateStructuralInvariants(g.AdditionalProperties.Structural, fieldLevel, fldPath.Child("additionalProperties"))...)
|
||||
}
|
||||
}
|
||||
|
||||
return allErrs
|
||||
return nil
|
||||
}
|
||||
|
||||
// validateExtensions checks Kubernetes vendor extensions of a structural schema.
|
||||
@ -282,6 +281,7 @@ func validateNestedValueValidation(v *NestedValueValidation, skipAnyOf, skipAllO
|
||||
|
||||
allErrs = append(allErrs, validateValueValidation(&v.ValueValidation, skipAnyOf, skipAllOfAnyOf, lvl, fldPath)...)
|
||||
allErrs = append(allErrs, validateNestedValueValidation(v.Items, false, false, lvl, fldPath.Child("items"))...)
|
||||
allErrs = append(allErrs, validateNestedValueValidation(v.AdditionalProperties, false, false, lvl, fldPath.Child("additionalProperties"))...)
|
||||
|
||||
for k, fld := range v.Properties {
|
||||
allErrs = append(allErrs, validateNestedValueValidation(&fld, false, false, fieldLevel, fldPath.Child("properties").Key(k))...)
|
||||
@ -290,9 +290,6 @@ func validateNestedValueValidation(v *NestedValueValidation, skipAnyOf, skipAllO
|
||||
if len(v.ForbiddenGenerics.Type) > 0 {
|
||||
allErrs = append(allErrs, field.Forbidden(fldPath.Child("type"), "must be empty to be structural"))
|
||||
}
|
||||
if v.ForbiddenGenerics.AdditionalProperties != nil {
|
||||
allErrs = append(allErrs, field.Forbidden(fldPath.Child("additionalProperties"), "must be undefined to be structural"))
|
||||
}
|
||||
if v.ForbiddenGenerics.Default.Object != nil {
|
||||
allErrs = append(allErrs, field.Forbidden(fldPath.Child("default"), "must be undefined to be structural"))
|
||||
}
|
||||
@ -324,9 +321,6 @@ func validateNestedValueValidation(v *NestedValueValidation, skipAnyOf, skipAllO
|
||||
if v.ForbiddenExtensions.XMapType != nil {
|
||||
allErrs = append(allErrs, field.Forbidden(fldPath.Child("x-kubernetes-map-type"), "must be undefined to be structural"))
|
||||
}
|
||||
if len(v.ForbiddenExtensions.XValidations) > 0 {
|
||||
allErrs = append(allErrs, field.Forbidden(fldPath.Child("x-kubernetes-validations"), "must be empty to be structural"))
|
||||
}
|
||||
|
||||
// forbid reasoning about metadata because it can lead to metadata restriction we don't want
|
||||
if _, found := v.Properties["metadata"]; found {
|
||||
|
@ -50,8 +50,8 @@ func (m *Visitor) visitStructural(s *Structural) bool {
|
||||
s.Properties[k] = v
|
||||
}
|
||||
}
|
||||
if s.Generic.AdditionalProperties != nil && s.Generic.AdditionalProperties.Structural != nil {
|
||||
m.visitStructural(s.Generic.AdditionalProperties.Structural)
|
||||
if s.AdditionalProperties != nil && s.AdditionalProperties.Structural != nil {
|
||||
m.visitStructural(s.AdditionalProperties.Structural)
|
||||
}
|
||||
if s.ValueValidation != nil {
|
||||
for i := range s.ValueValidation.AllOf {
|
||||
@ -86,8 +86,8 @@ func (m *Visitor) visitNestedValueValidation(vv *NestedValueValidation) bool {
|
||||
vv.Properties[k] = v
|
||||
}
|
||||
}
|
||||
if vv.ForbiddenGenerics.AdditionalProperties != nil && vv.ForbiddenGenerics.AdditionalProperties.Structural != nil {
|
||||
m.visitStructural(vv.ForbiddenGenerics.AdditionalProperties.Structural)
|
||||
if vv.AdditionalProperties != nil {
|
||||
m.visitNestedValueValidation(vv.AdditionalProperties)
|
||||
}
|
||||
for i := range vv.ValueValidation.AllOf {
|
||||
m.visitNestedValueValidation(&vv.ValueValidation.AllOf[i])
|
||||
|
Loading…
Reference in New Issue
Block a user