Skip to content

Commit

Permalink
flatten-allof fix circular additionalProperties overflow (#529)
Browse files Browse the repository at this point in the history
  • Loading branch information
tcdsv committed Apr 24, 2024
1 parent 6336a56 commit aa8fcea
Show file tree
Hide file tree
Showing 5 changed files with 98 additions and 1 deletion.
4 changes: 3 additions & 1 deletion flatten/allof/merge_allof.go
Original file line number Diff line number Diff line change
Expand Up @@ -580,7 +580,9 @@ func resolveNonFalseAdditionalProps(state *state, schema *openapi3.Schema, colle
}

var schemaRef *openapi3.SchemaRef
if len(additionalSchemas) > 0 {
if len(additionalSchemas) == 1 {
schemaRef = additionalSchemas[0]
} else if len(additionalSchemas) > 1 {
result := openapi3.NewSchemaRef("", openapi3.NewSchema())
err := flattenSchemas(state, result, additionalSchemas)
if err != nil {
Expand Down
45 changes: 45 additions & 0 deletions flatten/allof/merge_allof_spec_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,48 @@ func Test_MergeSpecInvalid(t *testing.T) {
_, err := load.NewSpecInfo(openapi3.NewLoader(), load.NewSource("../../data/allof/invalid.yaml"), load.WithFlattenAllOf())
require.EqualError(t, err, "failed to flatten allOf in \"../../data/allof/invalid.yaml\": unable to resolve Type conflict: all Type values must be identical")
}

func TestMergeSpec_CircularAdditionalPropsWithoutAllOf(t *testing.T) {
spec, err := load.NewSpecInfo(openapi3.NewLoader(), load.NewSource("testdata/circular_additional_props1.yaml"), load.WithFlattenAllOf())
require.NoError(t, err)

merged := spec.Spec
require.Equal(t, "object", merged.Components.Schemas["BaseSchema"].Value.Properties["prop1"].Value.Type)
require.NotNil(t, merged.Components.Schemas["BaseSchema"].Value.Properties["prop1"].Value.AdditionalProperties.Schema)
require.NotNil(t, merged.Components.Schemas["BaseSchema"].Value.Properties["prop1"].Value.AdditionalProperties.Schema.Value)

baseSchema := merged.Components.Schemas["BaseSchema"].Value
referencedAdditionalPropSchema := merged.Components.Schemas["BaseSchema"].Value.Properties["prop1"].Value.AdditionalProperties.Schema.Value
require.Equal(t, baseSchema, referencedAdditionalPropSchema)
}

func TestMergeSpec_MergeCircularAdditionalPropsWithAllOf(t *testing.T) {
spec, err := load.NewSpecInfo(openapi3.NewLoader(), load.NewSource("testdata/circular_additional_props2.yaml"), load.WithFlattenAllOf())
require.NoError(t, err)

merged := spec.Spec
require.Nil(t, merged.Components.Schemas["BaseSchema"].Value.AllOf)
require.Equal(t, "string", merged.Components.Schemas["BaseSchema"].Value.Properties["fixedProperty"].Value.Type)
require.Equal(t, "object", merged.Components.Schemas["BaseSchema"].Value.Properties["prop1"].Value.Type)
require.NotNil(t, merged.Components.Schemas["BaseSchema"].Value.Properties["prop1"].Value.AdditionalProperties.Schema)
require.NotNil(t, merged.Components.Schemas["BaseSchema"].Value.Properties["prop1"].Value.AdditionalProperties.Schema.Value)

baseSchema := merged.Components.Schemas["BaseSchema"].Value
referencedAdditionalPropSchema := merged.Components.Schemas["BaseSchema"].Value.Properties["prop1"].Value.AdditionalProperties.Schema.Value
require.Equal(t, baseSchema, referencedAdditionalPropSchema)
}

func TestMergeSpec_MergeCircularAdditionalPropsNestedWithinAllOf(t *testing.T) {
spec, err := load.NewSpecInfo(openapi3.NewLoader(), load.NewSource("testdata/circular_additional_props3.yaml"), load.WithFlattenAllOf())
require.NoError(t, err)

merged := spec.Spec
require.Nil(t, merged.Components.Schemas["BaseSchema"].Value.AllOf)
require.Equal(t, "object", merged.Components.Schemas["BaseSchema"].Value.Properties["prop1"].Value.Type)
require.NotNil(t, merged.Components.Schemas["BaseSchema"].Value.Properties["prop1"].Value.AdditionalProperties.Schema)
require.NotNil(t, merged.Components.Schemas["BaseSchema"].Value.Properties["prop1"].Value.AdditionalProperties.Schema.Value)

baseSchemaReferencedAdditionalPropSchema := merged.Components.Schemas["BaseSchema"].Value.Properties["prop1"].Value.AdditionalProperties.Schema.Value
NestedSelfReferentialSchema := merged.Components.Schemas["NestedSelfReferentialSchema"].Value
require.Equal(t, baseSchemaReferencedAdditionalPropSchema, NestedSelfReferentialSchema)
}
14 changes: 14 additions & 0 deletions flatten/allof/testdata/circular_additional_props1.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
openapi: 3.0.0
info:
title: Circular AdditionalProperties
version: 1.0.0
paths: {}
components:
schemas:
BaseSchema:
type: object
properties:
prop1:
type: object
additionalProperties:
$ref: '#/components/schemas/BaseSchema'
19 changes: 19 additions & 0 deletions flatten/allof/testdata/circular_additional_props2.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
openapi: 3.0.0
info:
title: Circular AdditionalProperties
version: 1.0.0
paths: {}
components:
schemas:
BaseSchema:
type: object
allOf:
- type: object
properties:
fixedProperty:
type: string
properties:
prop1:
type: object
additionalProperties:
$ref: '#/components/schemas/BaseSchema'
17 changes: 17 additions & 0 deletions flatten/allof/testdata/circular_additional_props3.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
openapi: 3.0.0
info:
title: Self-Referential allOf Schema API
version: 1.0.0
paths: {}
components:
schemas:
BaseSchema:
allOf:
- $ref: '#/components/schemas/NestedSelfReferentialSchema'
NestedSelfReferentialSchema:
type: object
properties:
prop1:
type: object
additionalProperties:
$ref: '#/components/schemas/NestedSelfReferentialSchema'

0 comments on commit aa8fcea

Please sign in to comment.