Skip to content

fix(compilers/openapi): drop a non-object security requirement - #327

Merged
OmarAlJarrah merged 1 commit into
mainfrom
fix/openapi-null-security-entry
Aug 9, 2026
Merged

fix(compilers/openapi): drop a non-object security requirement#327
OmarAlJarrah merged 1 commit into
mainfrom
fix/openapi-null-security-entry

Conversation

@OmarAlJarrah

@OmarAlJarrah OmarAlJarrah commented Aug 9, 2026

Copy link
Copy Markdown
Member

Summary

A security list entry the document does not write as an object — null, a scalar, a
sequence — was lowered to ir.AuthRequirement{}, the encoding ir-design.md §9 reserves
for a deliberately empty option: "no auth is one acceptable choice". The two spellings
produced byte-identical IR, so a malformed entry silently granted a permission the
document never wrote. Beside a real requirement, security: [{key: []}, null] compiled to
an OR-list reading as optionally authenticated; on its own, security: [null] compiled
to [{}], i.e. explicitly public.

The entry is now dropped whole, on the terms #41 established for an option naming an
undeclared scheme, and the enclosing collapse handles the sole-entry case for free: an
originally non-empty list left empty by dropping becomes nil — "inherit the enclosing
default" — rather than [], which §9 reserves for a deliberate "explicitly public"
declaration.

One guard serves both call sites of the lowering, the document-level security list and
an operation's own override. Both are tested, because a document-level fixture alone would
pass just as well on a fix wired into the service walk that an operation's override never
reaches.

Telling the two apart

null and {} both unmarshal to a requirement holding no members, so nothing about the
requirement itself separates them. The node it was read from does: the marshaller records
a root node for a value it could read as a mapping and none for anything else, so {}
carries one whether written inline or reached through an alias, and no other spelling
does. That is a fact about the library rather than about the document, so the tests
holding it compile documents rather than build requirements — including an alias to {},
which is what stops the check being rewritten as a test of the node's kind.

No new diagnostic, deliberately

The drop draws no report from the compiler. That follows the rule this package already
states for the same shape in securitySchemes: an entry written as something other than
an object already draws the loader's type-mismatch, which names both the entry
(openapi.security.1) and what was wrong with it, so a second report would send the
reader to the same position to learn less. An unresolved scheme name is reported here,
because nothing else places it — that asymmetry is the existing rule rather than a new
one. Every malformed row asserts the loader's report is present, so the drop cannot
quietly become silent if that report stops arriving.

The contrast the issue notes is left standing: the loader's report is sited at a
line:col rather than at a /security/<index> pointer like the requirement diagnostics
beside it. That is not a gap at this entry — a structured validation error is sited at
line:col by load.validationProvenance, the same shape scan.cyclicDiag uses, and this
entry's type-mismatch is one of those. So the two reports differ because they come from
different channels, not because this one was missed. Worth knowing when reading them side
by side; not something one entry could settle.

Test plan

  • go test ./compilers/openapi/internal/auth/... — three new tests:
    • document-level: six malformed spellings (null, ~, a string, a number, a sequence,
      an alias to a scalar), plus {} and an alias to {} as controls that must survive
    • operation-level: null dropped, {} kept
    • a sole non-object entry at either level collapses the list to nil
  • The tests bite: with the guard reverted all three go red, at both entry points; with the
    guard written as a node-kind check instead, the alias-to-{} control goes red.
  • Full gate green — gofmt, go vet, golangci-lint, go build, and the 100% coverage
    gate.

Closes #284

@OmarAlJarrah
OmarAlJarrah merged commit 560a564 into main Aug 9, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

openapi: a null security entry lowers to the empty-option encoding

1 participant