diff --git a/internal/topology/variables/clusterclass_variable_validation.go b/internal/topology/variables/clusterclass_variable_validation.go index f3013f191e03..0bb849c27b8f 100644 --- a/internal/topology/variables/clusterclass_variable_validation.go +++ b/internal/topology/variables/clusterclass_variable_validation.go @@ -149,6 +149,7 @@ func validateRootSchema(schema *clusterv1.JSONSchemaProps, fldPath *field.Path) }); err != nil { return append(allErrs, field.Invalid(fldPath, "", fmt.Sprintf("failed to build validator: %v", err))) } + allErrs = append(allErrs, validateSchema(apiExtensionsSchema, fldPath)...) return allErrs } @@ -158,13 +159,11 @@ func validateSchema(schema *apiextensions.JSONSchemaProps, fldPath *field.Path) // Validate that type is one of the validVariableTypes. switch { case len(schema.Type) == 0: - return field.ErrorList{field.Required(fldPath.Child("type"), "openAPIV3Schema.type cannot be empty")} + return field.ErrorList{field.Required(fldPath.Child("type"), "type cannot be empty")} case !validVariableTypes.Has(schema.Type): return field.ErrorList{field.NotSupported(fldPath.Child("type"), schema.Type, validVariableTypes.List())} } - // validate enums and example here. - // If the structural schema is valid, ensure a schema validator can be constructed. validator, _, err := validation.NewSchemaValidator(&apiextensions.CustomResourceValidation{ OpenAPIV3Schema: schema, diff --git a/internal/topology/variables/clusterclass_variable_validation_test.go b/internal/topology/variables/clusterclass_variable_validation_test.go index 4c42e4f7c4b0..6da1308abc62 100644 --- a/internal/topology/variables/clusterclass_variable_validation_test.go +++ b/internal/topology/variables/clusterclass_variable_validation_test.go @@ -495,6 +495,33 @@ func Test_ValidateClusterClassVariable(t *testing.T) { }, wantErr: true, }, + { + name: "fail if variable is an object with a top level default value invalidated by the given schema", + clusterClassVariable: &clusterv1.ClusterClassVariable{ + Name: "var", + Schema: clusterv1.VariableSchema{ + OpenAPIV3Schema: clusterv1.JSONSchemaProps{ + Type: "object", + Default: &apiextensionsv1.JSON{ + Raw: []byte(`{"spec":{"replicas": -100}}`), + }, + Properties: map[string]clusterv1.JSONSchemaProps{ + "spec": { + Type: "object", + Properties: map[string]clusterv1.JSONSchemaProps{ + "replicas": { + Type: "integer", + //Default: &apiextensionsv1.JSON{Raw: []byte(`-100`)}, + Minimum: pointer.Int64(1), + }, + }, + }, + }, + }, + }, + }, + wantErr: true, + }, { name: "pass on variable with an example that is invalid by the given schema", clusterClassVariable: &clusterv1.ClusterClassVariable{ diff --git a/internal/topology/variables/schema.go b/internal/topology/variables/schema.go index 48287d6fc148..36145dad0cc0 100644 --- a/internal/topology/variables/schema.go +++ b/internal/topology/variables/schema.go @@ -122,7 +122,7 @@ func convertToAPIExtensionsJSONSchemaProps(schema *clusterv1.JSONSchemaProps, fl apiExtensionsSchema, err := convertToAPIExtensionsJSONSchemaProps(&p, fldPath.Child("properties").Key(propertyName)) if err != nil { allErrs = append(allErrs, field.Invalid(fldPath.Child("properties").Key(propertyName), "", - fmt.Sprintf("failed to convert schema of property: %v", err))) + fmt.Sprintf("failed to convert schema: %v", err))) } else { props.Properties[propertyName] = *apiExtensionsSchema } @@ -133,7 +133,7 @@ func convertToAPIExtensionsJSONSchemaProps(schema *clusterv1.JSONSchemaProps, fl apiExtensionsSchema, err := convertToAPIExtensionsJSONSchemaProps(schema.Items, fldPath.Child("items")) if err != nil { allErrs = append(allErrs, field.Invalid(fldPath.Child("items"), "", - fmt.Sprintf("failed to convert schema of items: %v", err))) + fmt.Sprintf("failed to convert schema: %v", err))) } else { props.Items = &apiextensions.JSONSchemaPropsOrArray{ Schema: apiExtensionsSchema,