mirror of
https://github.com/LukeHagar/libopenapi.git
synced 2025-12-06 20:47:49 +00:00
Merge branch 'main' into ordered-libopenapi
This commit is contained in:
@@ -310,7 +310,8 @@ func (resolver *Resolver) VisitReference(ref *Reference, seen map[string]bool, j
|
|||||||
}
|
}
|
||||||
|
|
||||||
journey = append(journey, ref)
|
journey = append(journey, ref)
|
||||||
relatives := resolver.extractRelatives(ref, ref.Node, nil, seen, journey, resolve)
|
seenRelatives := make(map[int]bool)
|
||||||
|
relatives := resolver.extractRelatives(ref, ref.Node, nil, seen, journey, seenRelatives, resolve, 0)
|
||||||
|
|
||||||
seen = make(map[string]bool)
|
seen = make(map[string]bool)
|
||||||
|
|
||||||
@@ -421,19 +422,50 @@ func (resolver *Resolver) isInfiniteCircularDependency(ref *Reference, visitedDe
|
|||||||
|
|
||||||
func (resolver *Resolver) extractRelatives(ref *Reference, node, parent *yaml.Node,
|
func (resolver *Resolver) extractRelatives(ref *Reference, node, parent *yaml.Node,
|
||||||
foundRelatives map[string]bool,
|
foundRelatives map[string]bool,
|
||||||
journey []*Reference, resolve bool) []*Reference {
|
journey []*Reference, seen map[int]bool, resolve bool, depth int) []*Reference {
|
||||||
|
|
||||||
if len(journey) > 100 {
|
if len(journey) > 100 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// this is a safety check to prevent a stack overflow.
|
||||||
|
if depth > 500 {
|
||||||
|
def := "unknown"
|
||||||
|
if ref != nil {
|
||||||
|
def = ref.FullDefinition
|
||||||
|
}
|
||||||
|
if resolver.specIndex != nil && resolver.specIndex.logger != nil {
|
||||||
|
resolver.specIndex.logger.Warn("libopenapi resolver: relative depth exceeded 500 levels, "+
|
||||||
|
"check for circular references - resolving may be incomplete",
|
||||||
|
"reference", def)
|
||||||
|
}
|
||||||
|
|
||||||
|
loop := append(journey, ref)
|
||||||
|
circRef := &CircularReferenceResult{
|
||||||
|
Journey: loop,
|
||||||
|
Start: ref,
|
||||||
|
LoopIndex: depth,
|
||||||
|
LoopPoint: ref,
|
||||||
|
}
|
||||||
|
resolver.circularReferences = append(resolver.circularReferences, circRef)
|
||||||
|
resolver.resolvingErrors = append(resolver.resolvingErrors, &ResolvingError{
|
||||||
|
ErrorRef: fmt.Errorf("circular reference detected: %s", circRef.GenerateJourneyPath()),
|
||||||
|
Node: node,
|
||||||
|
Path: circRef.GenerateJourneyPath(),
|
||||||
|
})
|
||||||
|
ref.Circular = true
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
var found []*Reference
|
var found []*Reference
|
||||||
|
|
||||||
if len(node.Content) > 0 {
|
if len(node.Content) > 0 {
|
||||||
for i, n := range node.Content {
|
for i, n := range node.Content {
|
||||||
if utils.IsNodeMap(n) || utils.IsNodeArray(n) {
|
if utils.IsNodeMap(n) || utils.IsNodeArray(n) {
|
||||||
|
depth++
|
||||||
|
|
||||||
|
found = append(found, resolver.extractRelatives(ref, n, node, foundRelatives, journey, seen, resolve, depth)...)
|
||||||
|
|
||||||
found = append(found, resolver.extractRelatives(ref, n, node, foundRelatives, journey, resolve)...)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if i%2 == 0 && n.Value == "$ref" {
|
if i%2 == 0 && n.Value == "$ref" {
|
||||||
|
|||||||
@@ -1,11 +1,13 @@
|
|||||||
package index
|
package index
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/pb33f/libopenapi/datamodel"
|
"github.com/pb33f/libopenapi/datamodel"
|
||||||
"github.com/pb33f/libopenapi/utils"
|
"github.com/pb33f/libopenapi/utils"
|
||||||
"github.com/vmware-labs/yaml-jsonpath/pkg/yamlpath"
|
"github.com/vmware-labs/yaml-jsonpath/pkg/yamlpath"
|
||||||
|
"log/slog"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
@@ -432,7 +434,43 @@ func TestResolver_DeepJourney(t *testing.T) {
|
|||||||
}
|
}
|
||||||
idx := NewSpecIndexWithConfig(nil, CreateClosedAPIIndexConfig())
|
idx := NewSpecIndexWithConfig(nil, CreateClosedAPIIndexConfig())
|
||||||
resolver := NewResolver(idx)
|
resolver := NewResolver(idx)
|
||||||
assert.Nil(t, resolver.extractRelatives(nil, nil, nil, nil, journey, false))
|
assert.Nil(t, resolver.extractRelatives(nil, nil, nil, nil, journey, nil, false, 0))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestResolver_DeepDepth(t *testing.T) {
|
||||||
|
var refA, refB *yaml.Node
|
||||||
|
|
||||||
|
refA = &yaml.Node{
|
||||||
|
Value: "A",
|
||||||
|
Tag: "!!seq",
|
||||||
|
}
|
||||||
|
|
||||||
|
refB = &yaml.Node{
|
||||||
|
Value: "B",
|
||||||
|
Tag: "!!seq",
|
||||||
|
}
|
||||||
|
|
||||||
|
refA.Content = append(refA.Content, refB)
|
||||||
|
refB.Content = append(refB.Content, refA)
|
||||||
|
|
||||||
|
idx := NewSpecIndexWithConfig(nil, CreateClosedAPIIndexConfig())
|
||||||
|
resolver := NewResolver(idx)
|
||||||
|
|
||||||
|
// add a logger
|
||||||
|
var log []byte
|
||||||
|
buf := bytes.NewBuffer(log)
|
||||||
|
logger := slog.New(slog.NewTextHandler(buf, &slog.HandlerOptions{
|
||||||
|
Level: slog.LevelDebug,
|
||||||
|
}))
|
||||||
|
idx.logger = logger
|
||||||
|
|
||||||
|
ref := &Reference{
|
||||||
|
FullDefinition: "#/components/schemas/A",
|
||||||
|
}
|
||||||
|
found := resolver.extractRelatives(ref, refA, nil, nil, nil, nil, false, 0)
|
||||||
|
|
||||||
|
assert.Nil(t, found)
|
||||||
|
assert.Contains(t, buf.String(), "libopenapi resolver: relative depth exceeded 500 levels")
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestResolver_ResolveComponents_Stripe_NoRolodex(t *testing.T) {
|
func TestResolver_ResolveComponents_Stripe_NoRolodex(t *testing.T) {
|
||||||
|
|||||||
Reference in New Issue
Block a user