Skip to content

openapi: a percent-encoded $dynamicRef fragment does not match its $dynamicAnchor #233

Description

@OmarAlJarrah

A $dynamicRef fragment is URI text, so #my%2Danchor names the anchor my-anchor. The
anchor index compares the raw fragment against declared $dynamicAnchor names instead, so a
spec-correct escape matches nothing: the reference is reported irreducible and kept verbatim
under Unmodeled rather than expanded to the type it names.

Reproduction

openapi: 3.1.0
info: {title: t, version: "1"}
paths: {}
components:
  schemas:
    A:
      type: object
      properties:
        x: {$dynamicRef: "#my%2Danchor"}
    B: {$dynamicAnchor: my-anchor, type: string}

Emitted:

openapi/degraded-construct: $dynamicRef was not expanded because no $dynamicAnchor
"my%2Danchor" is declared in this document; it is kept verbatim under Unmodeled

Spelling the same reference #my-anchor expands it to t/openapi/components/schemas/B.

Root cause

dynamicFragment (compilers/openapi/internal/schema/schema.go) cuts the leading # and
returns the remainder as the anchor name, never percent-decoding it. soleAnchorSite then looks
that raw text up in the $dynamicAnchor index, which is keyed by the names as declared.

Why this is separate from #40

#40 covers $ref pointers, where the fix is to read the fragment the way the library that
actually resolves the reference reads it — disagreeing with the resolver is what made it a bug.
Nothing external resolves $dynamicRef: this compiler owns the anchor index and the match, so
what the decoding should be is a decision about our own behavior rather than one taken by
matching a dependency. Worth settling on its own terms, including whether $anchor names should
be decoded on the declaration side too.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions