Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use real root filename as theoretical root yaml file #322

Merged
merged 6 commits into from
Sep 9, 2024
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions bundler/bundler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ func TestBundleDocument_DigitalOcean(t *testing.T) {
digi, _ := os.ReadFile(spec)

doc, err := libopenapi.NewDocumentWithConfiguration([]byte(digi), &datamodel.DocumentConfiguration{
SpecFilePath: spec,
BasePath: tmp + "/specification",
ExtractRefsSequentially: true,
Logger: slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{
Expand Down
3 changes: 3 additions & 0 deletions datamodel/document_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ type DocumentConfiguration struct {
// To avoid sucking in all the files, set the FileFilter to a list of specific files to be included.
BasePath string // set the Base Path for resolving relative references if the spec is exploded.

// SpecFilePath is the name of the root specification file (usually named "openapi.yaml").
SpecFilePath string

// FileFilter is a list of specific files to be included by the rolodex when looking up references. If this value
// is set, then only these specific files will be included. If this value is not set, then all files will be included.
FileFilter []string
Expand Down
1 change: 1 addition & 0 deletions datamodel/low/v3/create_document.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ func createDocument(info *datamodel.SpecInfo, config *datamodel.DocumentConfigur
idxConfig.AvoidCircularReferenceCheck = true
idxConfig.BaseURL = config.BaseURL
idxConfig.BasePath = config.BasePath
idxConfig.SpecFilePath = config.SpecFilePath
idxConfig.Logger = config.Logger
extract := config.ExtractRefsSequentially
idxConfig.ExtractRefsSequentially = extract
Expand Down
3 changes: 3 additions & 0 deletions index/index_model.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,9 @@ type SpecIndexConfig struct {
// If resolving locally, the BasePath will be the root from which relative references will be resolved from
BasePath string // set the Base Path for resolving relative references if the spec is exploded.

// SpecFilePath is the name of the root specification file (usually named "openapi.yaml").
SpecFilePath string

// In an earlier version of libopenapi (pre 0.6.0) the index would automatically resolve all references
// They could have been local, or they could have been remote. This was a problem because it meant
// There was a potential for a remote exploit if a remote reference was malicious. There aren't any known
Expand Down
35 changes: 34 additions & 1 deletion index/rolodex.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"io"
"io/fs"
"log/slog"
"maps"
"math"
"os"
"path/filepath"
Expand Down Expand Up @@ -312,7 +313,13 @@ func (r *Rolodex) IndexTheRolodex() error {
}

if len(r.localFS) > 0 || len(r.remoteFS) > 0 {
r.indexConfig.SpecAbsolutePath = filepath.Join(basePath, "root.yaml")
// For specs that are not read from a filesystem (either from remote URL or []byte), we need to
// assign a theoretical root file. Having a root file is necessary when mapping references.
rootFile := "root.yaml"
if r.indexConfig.SpecFilePath != "" {
rootFile = filepath.Base(r.indexConfig.SpecFilePath)
}
r.indexConfig.SpecAbsolutePath = filepath.Join(basePath, rootFile)
}
}

Expand Down Expand Up @@ -425,6 +432,32 @@ func (r *Rolodex) BuildIndexes() {
r.manualBuilt = true
}

// GetAllReferences returns all references found in the root and all other indices
func (r *Rolodex) GetAllReferences() map[string]*Reference {
allRefs := make(map[string]*Reference)
for _, idx := range append(r.GetIndexes(), r.GetRootIndex()) {
daveshanley marked this conversation as resolved.
Show resolved Hide resolved
if idx == nil {
continue
}
refs := idx.GetAllReferences()
maps.Copy(allRefs, refs)
}
return allRefs
}

// GetAllMappedReferences returns all mapped references found in the root and all other indices
func (r *Rolodex) GetAllMappedReferences() map[string]*Reference {
mappedRefs := make(map[string]*Reference)
for _, idx := range append(r.GetIndexes(), r.GetRootIndex()) {
if idx == nil {
continue
}
refs := idx.GetMappedReferences()
maps.Copy(mappedRefs, refs)
}
return mappedRefs
}

// Open opens a file in the rolodex, and returns a RolodexFile.
func (r *Rolodex) Open(location string) (RolodexFile, error) {

Expand Down
13 changes: 12 additions & 1 deletion index/rolodex_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ import (
func TestRolodex_NewRolodex(t *testing.T) {
c := CreateOpenAPIIndexConfig()
rolo := NewRolodex(c)
assert.Len(t, rolo.GetAllReferences(), 0)
assert.Len(t, rolo.GetAllMappedReferences(), 0)
assert.NotNil(t, rolo)
assert.NotNil(t, rolo.indexConfig)
assert.Nil(t, rolo.GetIgnoredCircularReferences())
Expand Down Expand Up @@ -1516,18 +1518,27 @@ func TestRolodex_SimpleTest_OneDoc(t *testing.T) {
}

cf := CreateOpenAPIIndexConfig()
cf.SpecFilePath = filepath.Join(baseDir, "doc1.yaml")
daveshanley marked this conversation as resolved.
Show resolved Hide resolved
cf.BasePath = baseDir
cf.IgnoreArrayCircularReferences = true
cf.IgnorePolymorphicCircularReferences = true

rolo := NewRolodex(cf)
rolo.AddLocalFS(baseDir, fileFS)

rootBytes, err := os.ReadFile(cf.SpecFilePath)
assert.NoError(t, err)
var rootNode yaml.Node
_ = yaml.Unmarshal(rootBytes, &rootNode)
rolo.SetRootNode(&rootNode)

err = rolo.IndexTheRolodex()

//assert.NotZero(t, rolo.GetIndexingDuration()) comes back as 0 on windows.
assert.Nil(t, rolo.GetRootIndex())
assert.NotNil(t, rolo.GetRootIndex())
assert.Len(t, rolo.GetIndexes(), 10)
assert.Len(t, rolo.GetAllReferences(), 7)
assert.Len(t, rolo.GetAllMappedReferences(), 7)

assert.NoError(t, err)
assert.Len(t, rolo.indexes, 10)
Expand Down
Loading