Skip to content

openapi: $id resource-boundary walk skips empty pointer segments #302

Description

@OmarAlJarrah

declaresResourceIDAbove (compilers/openapi/internal/schema/schema.go) walks a
pointer from the document root looking for a $id above the position it names, and
skips every empty segment on the way:

for seg := range strings.SplitSeq(pointer, "/") {
	...
	if seg != "" { // every pointer starts with the empty segment
		cur = nodeview.Deref(view.ChildByToken(cur, ids.UnescapeSegment(seg)))
	}
}

Only the leading empty segment is an artifact of the split. Every later one is a
real RFC 6901 reference token naming the key "", so a pointer that ends in one
stops the walk at the parent and the position's own $id is never read.

A component schema named "" is addressed at /components/schemas/, which is
exactly that shape. Probed directly against the lowerer:

const src = `openapi: 3.1.0
info: {title: t, version: '1'}
paths: {}
components:
  schemas:
    "":
      $id: https://example.com/empty
      type: object
`
l, _ := loweredFor(t, src)
declaresResourceIDAbove(l.ctx, "/components/schemas/") // => false, want true

Consequence is a missed resource boundary rather than a hang: dynamicChainVerdict
lets a $dynamicRef expansion cross into a schema resource it should have degraded
at, which the function's own comment calls the worse of the two directions to err in
("a missed one mints a reference the IR cannot express").

Found while fixing the same laundering in nodeview.PointerPath, whose consequence
was a deadlock and is fixed separately. The two sites need different fixes: this walk
reads $id before descending, so its first iteration must still skip the leading
empty segment while every later one becomes a real ChildByToken step.

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