Skip to content

[Fleet] Restore dropped OpenAPI fields by giving extends() schemas distinct meta.id#271812

Open
tobio wants to merge 1 commit into
elastic:mainfrom
tobio:fleet-api-regression
Open

[Fleet] Restore dropped OpenAPI fields by giving extends() schemas distinct meta.id#271812
tobio wants to merge 1 commit into
elastic:mainfrom
tobio:fleet-api-regression

Conversation

@tobio
Copy link
Copy Markdown
Member

@tobio tobio commented May 29, 2026

Summary

Closes #271809.

PR #270560 added meta: { id } annotations to a number of Fleet @kbn/config-schema definitions so they would be extracted as named OpenAPI components. Three of the resulting components silently dropped fields that the same operations had exposed pre-PR (and which the route handlers still read):

Component Operation Was missing
simplified_create_package_policy_request POST /api/fleet/package_policies (simplified branch), PUT /api/fleet/package_policies/{packagePolicyId} output_id, policy_id, policy_ids, supports_agentless
package_policy_status_response POST /api/fleet/package_policies/delete (response item) output_id, policy_id, policy_ids, package
update_package_policy_request PUT /api/fleet/package_policies/{packagePolicyId} id (via the simplified branch in the request body's oneOf)

Root cause

ObjectType.extends() merges options as { ...this.options, ...newOptions }, so the extended schema inherits the base's meta.id when the caller does not pass a fresh one. The OAS generator's shared-schemas registry (OasConverter.#sharedSchemas) is keyed by id and is last-write-wins across all routes in a single generation pass, so two distinct shapes sharing the same id overwrite each other in the bundled spec.

Two places in Fleet hit this:

  • DeletePackagePoliciesResponseBodySchema extends PackagePolicyStatusResponseSchema with no own meta.id. UpgradePackagePoliciesResponseBodySchema references the bare base under the same id and overwrote the extension's keys.
  • CreateAgentlessPolicyRequestSchema.body extends SimplifiedCreatePackagePolicyRequestBodySchema with no own meta.id. The agentless body strips four fields (policy_id, policy_ids, supports_agentless, output_id), and that stripped shape was being emitted under the simplified_create_package_policy_request component name.

The third item (update_package_policy_request losing id) is a downstream effect of the second: the id field always lived on SimplifiedPackagePolicyBaseSchema and was published via the simplified branch of the PUT body's oneOf. Fixing the agentless extension restores it automatically — no TS changes to the update body are needed (and the TS schema didn't actually regress: pre-PR, UpdatePackagePolicyRequestBodySchema likewise didn't declare id).

Changes

  • x-pack/platform/plugins/shared/fleet/server/types/rest_spec/package_policy.ts — give DeletePackagePoliciesResponseBodySchema's extension meta: { id: 'delete_package_policies_response_item' }.
  • x-pack/platform/plugins/shared/fleet/common/types/rest_spec/agentless_policy.ts — give CreateAgentlessPolicyRequestSchema.body's extension meta: { id: 'create_agentless_policy_request' }.
  • src/platform/packages/shared/kbn-router-to-openapispec/src/generate_oas.test.ts — add two regression tests under extends() without a fresh meta.id (issue #271809) that document the collision and verify the workaround.
  • oas_docs/output/kibana.yaml / kibana.serverless.yaml — refresh the bundled spec.

Both new components (delete_package_policies_response_item, create_agentless_policy_request) are referenced from their respective operations; the previously colliding components (simplified_create_package_policy_request, package_policy_status_response) now correctly describe their own routes.

This is the short-term Fleet-side fix from the investigation. A follow-up to add collision detection in kbn-router-to-openapispec (so the build fails loudly on future occurrences instead of silently overwriting) and/or to change @kbn/config-schema so extends() no longer inherits meta.id is tracked separately in #271809.

Verification

Reproducing the issue's diff commands against the rebundled oas_docs/output/kibana.yaml:

# 1. simplified body — was empty, now has all four
$ awk '/Kibana_HTTP_APIs_simplified_create_package_policy_request:/{f=1;next}
       f && /^    Kibana_HTTP_APIs_/ {exit} f' oas_docs/output/kibana.yaml \
  | grep -E '^        (output_id|policy_id|policy_ids|supports_agentless):'
        output_id:
        policy_id:
        policy_ids:
        supports_agentless:

# 2. delete response item — extension keys are now under their own id
$ awk '/Kibana_HTTP_APIs_delete_package_policies_response_item:/{f=1;next}
       f && /^    Kibana_HTTP_APIs_/ {exit} f' oas_docs/output/kibana.yaml \
  | grep -E '^        [a-zA-Z_]+:'
        body: ...  id: ...  name: ...  output_id: ...  package: ...
        policy_id: ...  policy_ids: ...  statusCode: ...  success: ...

Test plan

  • node scripts/jest src/platform/packages/shared/kbn-router-to-openapispec/src/generate_oas.test.ts — all 20 tests pass, including 2 new regression tests
  • node scripts/type_check --project src/platform/packages/shared/kbn-router-to-openapispec/tsconfig.json
  • node scripts/type_check --project x-pack/platform/plugins/shared/fleet/tsconfig.json
  • node scripts/eslint on all modified files
  • node scripts/capture_oas_snapshot --include-path /api/fleet ... + cd oas_docs && make api-docs — bundled spec verified to contain restored fields
  • Existing Fleet API tests still pass in CI

Risks

Low. The change only adds meta: { id: ... } arguments; runtime validation behaviour is unchanged. Two new component names appear in the OAS but no existing component name's shape changes adversely (and several have their lost fields restored). Downstream OpenAPI-driven clients (e.g. the Terraform provider for Elastic Stack) need to regenerate from the new spec, but this restores the previously published contract — they have been blocked since the offending PR landed.

Release Notes

Restored the output_id, policy_id, policy_ids, supports_agentless, and package fields on the affected Fleet OpenAPI components. The bulk-delete response and the simplified create/update package policy bodies are now documented correctly again.

Made with Cursor

…stinct meta.id (elastic#271809)

`ObjectType.extends()` inherits `meta.id` from the base when the caller does
not pass a fresh one. The OAS generator's shared schemas registry is keyed
by id and is last-write-wins across routes, so two distinct shapes sharing
an id silently overwrite one another in the bundled spec.

Two Fleet schemas hit this:

- `DeletePackagePoliciesResponseBodySchema` extends `PackagePolicyStatusResponseSchema`
  without an own id; `UpgradePackagePoliciesResponseBodySchema` references the
  bare base under the same id and overwrote the extension's keys.
- `CreateAgentlessPolicyRequestSchema.body` extends
  `SimplifiedCreatePackagePolicyRequestBodySchema` without an own id; the
  agentless body strips four fields, and that stripped shape was being
  emitted under the simplified-create component name.

Give each extension a distinct `meta.id` so the components stop colliding,
refresh the bundled spec, and add regression tests in `generate_oas.test.ts`
documenting the collision behaviour and the workaround.

Closes elastic#271809

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

💚 Build Succeeded

Metrics [docs]

✅ unchanged

@botelastic botelastic Bot added the Team:Fleet Team label for Observability Data Collection Fleet team label Jun 1, 2026
@infra-vault-gh-plugin-prod
Copy link
Copy Markdown

Pinging @elastic/fleet (Team:Fleet)

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:Fleet Team label for Observability Data Collection Fleet team

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Fleet] Named OpenAPI components from #270560 silently drop fields (output_id, policy_id, policy_ids, supports_agentless, id, package)

3 participants