Skip to content

[OAS] Detect colliding shared schema ids during OpenAPI generation#271815

Open
tobio wants to merge 1 commit into
elastic:mainfrom
tobio:unique-component-ids
Open

[OAS] Detect colliding shared schema ids during OpenAPI generation#271815
tobio wants to merge 1 commit into
elastic:mainfrom
tobio:unique-component-ids

Conversation

@tobio
Copy link
Copy Markdown
Member

@tobio tobio commented May 29, 2026

Closes part of #271809.
Companion to #271812 (Path A).

Summary

Adds a runtime guardrail in @kbn/router-to-openapispec that fails
OAS generation loudly when two distinct schema shapes are registered
under the same shared-schema id during a single generation pass. This
is the silent-overwrite class of bug that caused the Fleet regressions
in #271809.

The OAS converter keeps a Map<id, schema> of named components so it
can emit $ref-based reuse. Today that map is last-write-wins: if two
routes register the same id with different shapes (most often through
Base.extends({...}) inheriting meta.id from its base), one shape
silently overwrites the other in the bundled spec, dropping fields. With
this PR the converter throws an OasSchemaCollisionError instead, with
a key-set diff and a concrete fix suggestion pointing back to #271809:

OAS shared schema collision for id "package_policy_status_response":
the same id was registered with two different shapes.
  properties only in the first registration: (none)
  properties only in the second registration: `output_id`, `policy_id`,
    `policy_ids`, `package`
This usually means a `Base.extends({...})` call inherited `meta.id`
from its base, or two unrelated schemas accidentally chose the same id
string. Pass `{ meta: { id: 'distinct_id' } }` as the second argument
to `extends()` to give the derived schema its own component name.
See https://github.com/elastic/kibana/issues/271809.

Re-using the same shared schema across multiple routes (the common,
intended case) stays a no-op — equality is deep, but ignores the
transient META_FIELD_X_OAS_OPTIONAL annotation that MaybeType
attaches mid-parse and removeInternalOptionalMarker strips on the
way out.

Changes

  • oas_converter/kbn_config_schema/post_process_mutations/schema_collision.ts
    (new) — OasSchemaCollisionError, describeSchemaCollision,
    and a schemasMatch deep-equality helper that ignores the
    internal optional marker.
  • oas_converter/kbn_config_schema/post_process_mutations/context.ts
    Context.addSharedSchema now compares any existing entry against
    the incoming shape via schemasMatch and dispatches on a new
    OnCollision = 'throw' | 'warn' | 'ignore' option (default
    'throw').
  • oas_converter/index.tsOasConverter accepts an
    OasConverterOptions { onCollision } second-arg, threads it through
    to the underlying Context, and applies the same check as a backstop
    in #addComponents (covers convertPathParameters /
    convertQuery, which currently create their own Context).
  • kbn_config_schema/lib.ts + type.ts — propagate onCollision
    through the converter API.
  • index.ts — re-export OasSchemaCollisionError so callers can
    catch it.
  • Tests:

Sequencing

This PR should land after #271812.
Without Path A merged first, the existing Fleet collisions (the very
ones #271809 reports) would now trip the strict throw and break the
OAS snapshot CI step. Once Path A is in, this PR locks the door behind
it: any future regression of the same shape gets caught at build time
rather than silently corrupting the bundle.

Test plan

  • node scripts/jest src/platform/packages/shared/kbn-router-to-openapispec — 252/252 pass (18 suites; +9 new tests covering the guardrail).
  • node scripts/type_check --project src/platform/packages/shared/kbn-router-to-openapispec/tsconfig.json — clean.
  • node scripts/eslint on the diff — clean.
  • OAS snapshot CI step is green once Path A ([Fleet] Restore dropped OpenAPI fields by giving extends() schemas distinct meta.id #271812) is merged into this branch's base.

Risks

Low. The throw is a build-time check on the OAS bundle pipeline; it
does not affect any runtime route handler. The new 'warn' and
'ignore' modes are escape hatches for transitional or test usage —
nothing in production sets them. The biggest exposure is the
sequencing dependency on Path A: if this lands first, the next OAS
snapshot run will fail on the existing Fleet collisions until Path A
also merges.

Release Notes

None — internal tooling change. Failures here surface during OAS
generation, not at runtime.

Made with Cursor

Throw a descriptive `OasSchemaCollisionError` from `@kbn/router-to-openapispec`
when two distinct shapes are registered under the same shared-schema id
during a single generation pass. Catches the silent component-overwrite class
of bug behind elastic#271809 (e.g.
`Base.extends({...})` inheriting `meta.id` from its base).

Companion to elastic#271812 (Path A —
short-term Fleet-side fix that removes the existing collisions).

Co-authored-by: Cursor <cursoragent@cursor.com>
@tobio tobio added release_note:skip Skip the PR/issue when compiling release notes backport:skip This PR does not require backporting labels May 29, 2026
@tobio tobio marked this pull request as ready for review May 29, 2026 02:22
@tobio tobio requested a review from a team as a code owner May 29, 2026 02:22
@kibanamachine
Copy link
Copy Markdown
Contributor

kibanamachine commented May 29, 2026

💔 Build Failed

Failed CI Steps

Metrics [docs]

Unknown metric groups

ESLint disabled line counts

id before after diff
@kbn/router-to-openapispec 2 4 +2

Total ESLint disabled count

id before after diff
@kbn/router-to-openapispec 2 4 +2

History

@tobio tobio added the Team:Core Platform Core services: plugins, logging, config, saved objects, http, ES client, i18n, etc t// label Jun 3, 2026
@infra-vault-gh-plugin-prod
Copy link
Copy Markdown

Pinging @elastic/kibana-core (Team:Core)

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

Labels

backport:skip This PR does not require backporting release_note:skip Skip the PR/issue when compiling release notes Team:Core Platform Core services: plugins, logging, config, saved objects, http, ES client, i18n, etc t//

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants