From 97dd8acff26588978cf008eaccfc5b5bf919e00d Mon Sep 17 00:00:00 2001 From: nk2ge5k Date: Sun, 6 Nov 2022 00:55:51 +0400 Subject: [PATCH 1/5] fix panic slice out of range error #652 Fixes panic from the issue #652, that occurs when trying to load specification from file that contains reference to the file insed of parent directory. --- openapi3/issue652_test.go | 20 ++++++++++++++++++ openapi3/loader.go | 22 +++++++++++++------- openapi3/testdata/issue652/definitions.yml | 4 ++++ openapi3/testdata/issue652/nested/schema.yml | 7 +++++++ 4 files changed, 46 insertions(+), 7 deletions(-) create mode 100644 openapi3/issue652_test.go create mode 100644 openapi3/testdata/issue652/definitions.yml create mode 100644 openapi3/testdata/issue652/nested/schema.yml diff --git a/openapi3/issue652_test.go b/openapi3/issue652_test.go new file mode 100644 index 000000000..e51985ffb --- /dev/null +++ b/openapi3/issue652_test.go @@ -0,0 +1,20 @@ +package openapi3_test + +import ( + "testing" + + "github.com/getkin/kin-openapi/openapi3" + "github.com/stretchr/testify/require" +) + +func TestIssue652(t *testing.T) { + loader := openapi3.NewLoader() + loader.IsExternalRefsAllowed = true + + // Test checks that no slice bounds out of range error occurs while loading + // from file that contains reference to file in the parent directory. + require.NotPanics(t, func() { + _, err := loader.LoadFromFile("testdata/issue652/nested/schema.yml") + require.NoError(t, err) + }) +} diff --git a/openapi3/loader.go b/openapi3/loader.go index 1ab693b0f..e428162d7 100644 --- a/openapi3/loader.go +++ b/openapi3/loader.go @@ -742,7 +742,10 @@ func (loader *Loader) resolveSchemaRef(doc *T, component *SchemaRef, documentPat return err } component.Value = resolved.Value - foundPath := loader.getResolvedRefPath(ref, &resolved, documentPath, componentPath) + foundPath, rerr := loader.getResolvedRefPath(ref, &resolved, documentPath, componentPath) + if rerr != nil { + return fmt.Errorf("failed to resolve file for reference %q: %w", ref, rerr) + } documentPath = loader.documentPathForRecursiveRef(documentPath, foundPath) } } @@ -790,23 +793,28 @@ func (loader *Loader) resolveSchemaRef(doc *T, component *SchemaRef, documentPat return nil } -func (loader *Loader) getResolvedRefPath(ref string, resolved *SchemaRef, cur, found *url.URL) string { +func (loader *Loader) getResolvedRefPath(ref string, resolved *SchemaRef, cur, found *url.URL) (string, error) { if referencedFilename := strings.Split(ref, "#")[0]; referencedFilename == "" { if cur != nil { if loader.rootDir != "" && strings.HasPrefix(cur.Path, loader.rootDir) { - return cur.Path[len(loader.rootDir)+1:] + return cur.Path[len(loader.rootDir)+1:], nil } - return path.Base(cur.Path) + return path.Base(cur.Path), nil } - return "" + return "", nil } // ref. to external file if resolved.Ref != "" { - return resolved.Ref + return resolved.Ref, nil } + + if loader.rootDir == "" { + return path.Dir(found.Path), nil + } + // found dest spec. file - return path.Dir(found.Path)[len(loader.rootDir):] + return filepath.Rel(loader.rootDir, found.Path) } func (loader *Loader) resolveSecuritySchemeRef(doc *T, component *SecuritySchemeRef, documentPath *url.URL) (err error) { diff --git a/openapi3/testdata/issue652/definitions.yml b/openapi3/testdata/issue652/definitions.yml new file mode 100644 index 000000000..98ef69254 --- /dev/null +++ b/openapi3/testdata/issue652/definitions.yml @@ -0,0 +1,4 @@ +components: + schemas: + TestSchema: + type: string diff --git a/openapi3/testdata/issue652/nested/schema.yml b/openapi3/testdata/issue652/nested/schema.yml new file mode 100644 index 000000000..66aade6a6 --- /dev/null +++ b/openapi3/testdata/issue652/nested/schema.yml @@ -0,0 +1,7 @@ +components: + schemas: + TestObject: + type: object + properties: + reference_to_parent_directory: + $ref: "../definitions.yml#/components/schemas/TestSchema" From 5c4cad4375a9c1dabe6a2badd682d264cc158a7e Mon Sep 17 00:00:00 2001 From: nk2ge5k Date: Sun, 6 Nov 2022 01:05:29 +0400 Subject: [PATCH 2/5] fix import order --- openapi3/issue652_test.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/openapi3/issue652_test.go b/openapi3/issue652_test.go index e51985ffb..88467bb6a 100644 --- a/openapi3/issue652_test.go +++ b/openapi3/issue652_test.go @@ -3,8 +3,9 @@ package openapi3_test import ( "testing" - "github.com/getkin/kin-openapi/openapi3" "github.com/stretchr/testify/require" + + "github.com/getkin/kin-openapi/openapi3" ) func TestIssue652(t *testing.T) { From 620a3b23de3c4153b7aca26a4045af58d6c9efa4 Mon Sep 17 00:00:00 2001 From: nk2ge5k Date: Sun, 6 Nov 2022 01:23:22 +0400 Subject: [PATCH 3/5] Return file path instead of directory path when root directory is empty --- openapi3/loader.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openapi3/loader.go b/openapi3/loader.go index e428162d7..21eafa2f1 100644 --- a/openapi3/loader.go +++ b/openapi3/loader.go @@ -810,7 +810,7 @@ func (loader *Loader) getResolvedRefPath(ref string, resolved *SchemaRef, cur, f } if loader.rootDir == "" { - return path.Dir(found.Path), nil + return found.Path, nil } // found dest spec. file From b457c7a21dcadc88e86c3d9fc1cb86d706e96641 Mon Sep 17 00:00:00 2001 From: nk2ge5k Date: Sun, 6 Nov 2022 01:47:04 +0400 Subject: [PATCH 4/5] Improve test for checking load result. --- openapi3/issue652_test.go | 10 +++++++++- openapi3/testdata/issue652/nested/schema.yml | 7 ++----- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/openapi3/issue652_test.go b/openapi3/issue652_test.go index 88467bb6a..f36e92005 100644 --- a/openapi3/issue652_test.go +++ b/openapi3/issue652_test.go @@ -3,6 +3,7 @@ package openapi3_test import ( "testing" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/getkin/kin-openapi/openapi3" @@ -15,7 +16,14 @@ func TestIssue652(t *testing.T) { // Test checks that no slice bounds out of range error occurs while loading // from file that contains reference to file in the parent directory. require.NotPanics(t, func() { - _, err := loader.LoadFromFile("testdata/issue652/nested/schema.yml") + const schemaName = "ReferenceToParentDirectory" + + spec, err := loader.LoadFromFile("testdata/issue652/nested/schema.yml") require.NoError(t, err) + require.Contains(t, spec.Components.Schemas, schemaName) + + schema := spec.Components.Schemas[schemaName] + assert.Equal(t, schema.Ref, "../definitions.yml#/components/schemas/TestSchema") + assert.Equal(t, schema.Value.Type, "string") }) } diff --git a/openapi3/testdata/issue652/nested/schema.yml b/openapi3/testdata/issue652/nested/schema.yml index 66aade6a6..ef321a101 100644 --- a/openapi3/testdata/issue652/nested/schema.yml +++ b/openapi3/testdata/issue652/nested/schema.yml @@ -1,7 +1,4 @@ components: schemas: - TestObject: - type: object - properties: - reference_to_parent_directory: - $ref: "../definitions.yml#/components/schemas/TestSchema" + ReferenceToParentDirectory: + $ref: "../definitions.yml#/components/schemas/TestSchema" From 0944b663b2e3f1e8c68aae277005b67bd7672d1f Mon Sep 17 00:00:00 2001 From: nk2ge5k Date: Sun, 6 Nov 2022 02:43:14 +0400 Subject: [PATCH 5/5] Fix error message --- openapi3/loader.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openapi3/loader.go b/openapi3/loader.go index 21eafa2f1..2bb9999ee 100644 --- a/openapi3/loader.go +++ b/openapi3/loader.go @@ -744,7 +744,7 @@ func (loader *Loader) resolveSchemaRef(doc *T, component *SchemaRef, documentPat component.Value = resolved.Value foundPath, rerr := loader.getResolvedRefPath(ref, &resolved, documentPath, componentPath) if rerr != nil { - return fmt.Errorf("failed to resolve file for reference %q: %w", ref, rerr) + return fmt.Errorf("failed to resolve file from reference %q: %w", ref, rerr) } documentPath = loader.documentPathForRecursiveRef(documentPath, foundPath) }