From 6b28e414bdd9b6a919c06bfaafda8740b215da48 Mon Sep 17 00:00:00 2001 From: Dave Shanley Date: Wed, 4 Jan 2023 06:43:32 -0500 Subject: [PATCH] fix: Index incorrectly handling file references on the local file system. This was reported in https://github.com/daveshanley/vacuum/issues/225, it's a continuation of the issue found in https://github.com/pb33f/libopenapi/issues/37. This fix allows the full import of the file (not just a path/component) to be imported. Signed-off-by: Dave Shanley --- README.md | 3 ++- index/spec_index.go | 26 ++++++++++++++++++++------ index/spec_index_test.go | 34 ++++++++++++++++++++++++++++++++++ 3 files changed, 56 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 11cc978..fe49b4a 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,10 @@

- libopenapi + libopenapi

# libopenapi - enterprise grade OpenAPI tools for golang. + ![Pipeline](https://github.com/pb33f/libopenapi/workflows/Build/badge.svg) [![GoReportCard](https://goreportcard.com/badge/github.com/pb33f/libopenapi)](https://goreportcard.com/report/github.com/pb33f/libopenapi) [![codecov](https://codecov.io/gh/pb33f/libopenapi/branch/main/graph/badge.svg?)](https://codecov.io/gh/pb33f/libopenapi) diff --git a/index/spec_index.go b/index/spec_index.go index a2dcf4a..341f19c 100644 --- a/index/spec_index.go +++ b/index/spec_index.go @@ -1,4 +1,4 @@ -// Copyright 2022 Dave Shanley / Quobix +// Copyright 2022-2033 Dave Shanley / Quobix // SPDX-License-Identifier: MIT // Package index contains an OpenAPI indexer that will very quickly scan through an OpenAPI specification (all versions) @@ -1647,6 +1647,19 @@ func (index *SpecIndex) FindComponent(componentId string, parent *yaml.Node) *Re if len(uri) == 2 { return index.performExternalLookup(uri, componentId, fileLookup, parent) } + if len(uri) == 1 { + // if there is no reference, second segment is empty / has no name + // this means there is no component to look-up and the entire file should be pulled in. + // to stop all the other code from breaking (that is expecting a component), let's just post-pend + // a hash to the end of the componentId and ensure the uri slice is as expected. + // described in https://github.com/pb33f/libopenapi/issues/37 + // + // ^^ this same issue was re-reported in file based lookups in vacuum. + // more info here: https://github.com/daveshanley/vacuum/issues/225 + componentId = fmt.Sprintf("%s#", componentId) + uri = append(uri, "") + return index.performExternalLookup(uri, componentId, fileLookup, parent) + } } return nil } @@ -2080,10 +2093,6 @@ func (index *SpecIndex) lookupFileReference(ref string) (*yaml.Node, *yaml.Node, // split string to remove file reference uri := strings.Split(ref, "#") - if len(uri) != 2 { - return nil, nil, fmt.Errorf("unable to determine filename for file reference: '%s'", ref) - } - file := strings.ReplaceAll(uri[0], "file:", "") var parsedRemoteDocument *yaml.Node @@ -2106,7 +2115,12 @@ func (index *SpecIndex) lookupFileReference(ref string) (*yaml.Node, *yaml.Node, } // lookup item from reference by using a path query. - query := fmt.Sprintf("$%s", strings.ReplaceAll(uri[1], "/", ".")) + var query string + if len(uri) >= 2 { + query = fmt.Sprintf("$%s", strings.ReplaceAll(uri[1], "/", ".")) + } else { + query = "$" + } // remove any URL encoding query = strings.Replace(query, "~1", "./", 1) diff --git a/index/spec_index_test.go b/index/spec_index_test.go index 71646d8..cc9703d 100644 --- a/index/spec_index_test.go +++ b/index/spec_index_test.go @@ -555,6 +555,40 @@ func TestSpecIndex_lookupRemoteReference_NoComponent(t *testing.T) { assert.Nil(t, b) } +// Discovered in issue https://github.com/daveshanley/vacuum/issues/225 +func TestSpecIndex_lookupFileReference_NoComponent(t *testing.T) { + + index := new(SpecIndex) + _ = ioutil.WriteFile("coffee-time.yaml", []byte("time: for coffee"), 0o664) + defer os.Remove("coffee-time.yaml") + + index.seenRemoteSources = make(map[string]*yaml.Node) + a, b, err := index.lookupFileReference("coffee-time.yaml") + assert.NoError(t, err) + assert.NotNil(t, a) + assert.NotNil(t, b) +} + +func TestSpecIndex_CheckIndexDiscoversNoComponentLocalFileReference(t *testing.T) { + + _ = ioutil.WriteFile("coffee-time.yaml", []byte("name: time for coffee"), 0o664) + defer os.Remove("coffee-time.yaml") + + yml := `openapi: 3.0.3 +paths: + /cakes: + post: + parameters: + - $ref: 'coffee-time.yaml'` + + var rootNode yaml.Node + yaml.Unmarshal([]byte(yml), &rootNode) + + index := NewSpecIndex(&rootNode) + + assert.NotNil(t, index.GetAllParametersFromOperations()["/cakes"]["post"]["coffee-time.yaml"].Node) +} + func TestSpecIndex_lookupRemoteReference_SeenSourceSimulation_BadJSON(t *testing.T) { index := new(SpecIndex) index.seenRemoteSources = make(map[string]*yaml.Node)