镜像站点 · 本页由第三方 GitHub 只读镜像提供,非 GitHub 官方站点,不接受任何登录或凭据输入。前往 github.com
Skip to content

$id fragment lookup silently returns the parent schema when resolution fails #676

Closed

Description

@CaliLuke

On libopenapi v0.41.8, a reference resolved through a registered $id can return the enclosing schema when the requested fragment does not resolve. This affects both the absolute URI and its absolute-path lookup form.

With the schema below, #/properties/A+B%20C should select the integer property. #/properties/missing and #/properties/%zz should not resolve. All three currently return the enclosing object schema instead.

This silently changes the referenced contract and can hide a misspelled or malformed reference. The documented FindComponent/ResolveRefViaSchemaId behavior is to return nil when the target cannot be resolved.

Reproduction (Go 1.27.3, github.com/pb33f/libopenapi v0.41.8, github.com/pb33f/go-yaml v0.1.1):

Save as main.go in an empty directory, then run:

go mod init example.com/schema-id-fragment
go get github.com/pb33f/libopenapi@v0.41.8 github.com/pb33f/go-yaml@v0.1.1
go run .
package main

import (
	"context"
	"fmt"
	"github.com/pb33f/go-yaml"
	"github.com/pb33f/libopenapi/index"
)

func main() {
	const source = `openapi: 3.1.1
info: {title: Example, version: '1'}
paths: {}
components:
  schemas:
    Holder:
      $id: https://example.com/holder
      type: object
      properties:
        'A+B C': {type: integer}
`
	var root yaml.Node
	if err := yaml.Unmarshal([]byte(source), &root); err != nil {
		panic(err)
	}
	idx := index.NewSpecIndex(&root)
	for _, base := range []string{"https://example.com/holder", "/holder"} {
		for _, fragment := range []string{"#/properties/A+B%20C", "#/properties/missing", "#/properties/%zz"} {
			ref := idx.FindComponent(context.Background(), base+fragment)
			kind := "<nil>"
			if ref != nil && ref.Node != nil {
				for i := 0; i+1 < len(ref.Node.Content); i += 2 {
					if ref.Node.Content[i].Value == "type" {
						kind = ref.Node.Content[i+1].Value
					}
				}
			}
			fmt.Printf("%s%s -> %s\n", base, fragment, kind)
		}
	}
}

Actual: all six calls print object. Expected: integer for the encoded property name, <nil> for the missing member and malformed escape, for both URI forms.

The $id resolver retains entry.SchemaNode when fragment navigation fails and does not URI-decode the fragment before navigation. The absolute-path lookup repeats the parent fallback. Related pointer-token corrections are in #675, but these $id resolution paths bypass that lookup boundary and need their own correction.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions