Skip to content

Commit 0e794ff

Browse files
matoousdaveshanley
authored andcommitted
fix(functions): checkPolymorphicProperty
checkPolymorphicProperty correctly checked anyOf/oneOf/allOf but only one level deep and didn't respect `$ref`. This fixes the code to recursively descend down the schemas and respect references to ensure that all properties, even if not directly defined on the object, are found.
1 parent 3df8a76 commit 0e794ff

File tree

2 files changed

+73
-24
lines changed

2 files changed

+73
-24
lines changed

functions/openapi/schema_type.go

Lines changed: 53 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -646,35 +646,65 @@ func (st SchemaTypeCheck) validateDependentRequired(schema *v3.Schema, context *
646646
return results
647647
}
648648

649-
// checkPolymorphicProperty checks if a property is defined in anyOf, oneOf, or allOf schemas
649+
// checkPolymorphicProperty checks if a property is defined in anyOf, oneOf, or allOf schemas,
650+
// including nested compositions and referenced schemas.
650651
func (st SchemaTypeCheck) checkPolymorphicProperty(schema *v3.Schema, propertyName string) bool {
651-
// check in AnyOf schemas
652-
if schema.Value.AnyOf != nil {
653-
for _, anyOfSchema := range schema.Value.AnyOf {
654-
if anyOfSchema.Schema() != nil && anyOfSchema.Schema().Properties != nil &&
655-
anyOfSchema.Schema().Properties.GetOrZero(propertyName) != nil {
656-
return true
657-
}
658-
}
652+
if schema == nil || schema.Value == nil {
653+
return false
659654
}
660655

661-
// check in OneOf schemas
662-
if schema.Value.OneOf != nil {
663-
for _, oneOfSchema := range schema.Value.OneOf {
664-
if oneOfSchema.Schema() != nil && oneOfSchema.Schema().Properties != nil &&
665-
oneOfSchema.Schema().Properties.GetOrZero(propertyName) != nil {
666-
return true
667-
}
656+
visited := make(map[*lowBase.Schema]struct{})
657+
return st.checkSchemaPropertyRecursive(schema.Value, propertyName, visited)
658+
}
659+
660+
// checkSchemaPropertyRecursive recursively traverses down the schema looking for the existance
661+
// of a specific property. It ensures that all references are properly resolved.
662+
func (st SchemaTypeCheck) checkSchemaPropertyRecursive(schema *highBase.Schema, propertyName string, visited map[*lowBase.Schema]struct{}) bool {
663+
if schema == nil {
664+
return false
665+
}
666+
667+
if low := schema.GoLow(); low != nil {
668+
if _, seen := visited[low]; seen {
669+
return false
668670
}
671+
visited[low] = struct{}{}
669672
}
670673

671-
// check in AllOf schemas
672-
if schema.Value.AllOf != nil {
673-
for _, allOfSchema := range schema.Value.AllOf {
674-
if allOfSchema.Schema() != nil && allOfSchema.Schema().Properties != nil &&
675-
allOfSchema.Schema().Properties.GetOrZero(propertyName) != nil {
676-
return true
677-
}
674+
if schema.Properties != nil && schema.Properties.GetOrZero(propertyName) != nil {
675+
return true
676+
}
677+
678+
if st.checkSchemaProxiesForProperty(schema.AnyOf, propertyName, visited) {
679+
return true
680+
}
681+
if st.checkSchemaProxiesForProperty(schema.OneOf, propertyName, visited) {
682+
return true
683+
}
684+
if st.checkSchemaProxiesForProperty(schema.AllOf, propertyName, visited) {
685+
return true
686+
}
687+
688+
return false
689+
}
690+
691+
func (st SchemaTypeCheck) checkSchemaProxiesForProperty(
692+
proxies []*highBase.SchemaProxy,
693+
propertyName string,
694+
visited map[*lowBase.Schema]struct{},
695+
) bool {
696+
for _, proxy := range proxies {
697+
if proxy == nil {
698+
continue
699+
}
700+
701+
subSchema := proxy.Schema()
702+
if subSchema == nil {
703+
continue
704+
}
705+
706+
if st.checkSchemaPropertyRecursive(subSchema, propertyName, visited) {
707+
return true
678708
}
679709
}
680710

functions/openapi/schema_type_test.go

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3272,6 +3272,26 @@ components:
32723272
cat: '#/components/schemas/Cat'`,
32733273
expectedErrors: []struct{ message, path string }{},
32743274
},
3275+
{
3276+
name: "PropertyInAllOfNestedRef",
3277+
yaml: `openapi: 3.0.3
3278+
components:
3279+
schemas:
3280+
Pet:
3281+
allOf:
3282+
- $ref: '#/components/schemas/PetBase'
3283+
discriminator:
3284+
propertyName: petType
3285+
PetBase:
3286+
allOf:
3287+
- type: object
3288+
properties:
3289+
petType:
3290+
type: string
3291+
name:
3292+
type: string`,
3293+
expectedErrors: []struct{ message, path string }{},
3294+
},
32753295
{
32763296
name: "PropertyInOneOf",
32773297
yaml: `openapi: 3.0.3
@@ -3444,4 +3464,3 @@ components:
34443464
assert.Contains(t, res[0].Message, "minimum")
34453465
assert.Contains(t, res[0].Message, "null")
34463466
}
3447-

0 commit comments

Comments
 (0)