Skip to content

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

@tobio

Description

@tobio

Kibana version

OpenAPI spec digest 25fd084766fe43b01ec0db0eccde55ad80542799 (current main as of 2026-05-28).

Last known good: 16a5962f072868f5dde786a2dab91de2c23f068d (parent of the offending commit).

Summary

Commit f8da12e93c73 ("[Fleet] Add meta:{id} to fleet schemas", PR #270560) added meta: { id: ... } annotations to a number of Fleet @kbn/config-schema definitions so they would be extracted as named OpenAPI components. During that extraction, three of the resulting components silently dropped fields that the same operations had exposed in the previous spec — and which are still read by the route handlers.

This appears to be a bug in the @kbn/config-schema → OpenAPI generator when meta: { id } is combined with .extends() (or otherwise composed) schemas: certain field shapes (nullable strings via oneOf([literal(null), string()]), arrays of strings, nested objects defined on a base schema) are dropped when the schema is flattened into the named component.

Affected components and missing fields

Component Operation Missing properties
Kibana_HTTP_APIs_simplified_create_package_policy_request POST /api/fleet/package_policies (simplified anyOf branch) output_id, policy_id, policy_ids, supports_agentless
Kibana_HTTP_APIs_update_package_policy_request PUT /api/fleet/package_policies/{packagePolicyId} id
Kibana_HTTP_APIs_package_policy_status_response POST /api/fleet/package_policies/delete (response item) output_id, policy_id, policy_ids, package

For comparison, the other five Fleet schemas the same PR annotated (create_package_policy_request, package_policy_response, dry_run_package_policy, deprecation_info, package_policy_package) all extracted cleanly with their original property sets intact.

Evidence

Reproduce the diffs directly from the published specs:

PRE=16a5962f072868f5dde786a2dab91de2c23f068d
POST=f8da12e93c73
curl -sSf "https://raw.githubusercontent.com/elastic/kibana/$PRE/oas_docs/output/kibana.yaml"  -o /tmp/pre.yaml
curl -sSf "https://raw.githubusercontent.com/elastic/kibana/$POST/oas_docs/output/kibana.yaml" -o /tmp/post.yaml

1. simplified_create_package_policy_request

Pre-PR, the simplified anyOf branch of POST /api/fleet/package_policies exposed all four fields:

$ awk '/post-fleet-package-policies$/,/responses:/' /tmp/pre.yaml \
    | grep -cE '^                    (output_id|policy_id|policy_ids|supports_agentless):$'
8   # = 4 fields × 2 anyOf branches

Post-PR, the named component drops them:

$ awk '/Kibana_HTTP_APIs_simplified_create_package_policy_request:/{f=1;next}
       f && /^    Kibana_HTTP_APIs_/ {exit} f' /tmp/post.yaml \
    | grep -E '^        (output_id|policy_id|policy_ids|supports_agentless):$'
# (no output)

The TypeScript definition in x-pack/platform/plugins/shared/fleet/common/types/models/package_policy_schema.ts still defines all four (e.g. output_id: schema.maybe(schema.oneOf([schema.literal(null), schema.string()])), supports_agentless: schema.maybe(schema.nullable(schema.boolean()))).

2. update_package_policy_request

Pre-PR PUT /api/fleet/package_policies/{packagePolicyId} body had an id property:

id:
  description: Policy unique identifier.
  type: string

Post-PR Kibana_HTTP_APIs_update_package_policy_request no longer has it (the field is defined on the base typed package_policy schema that update_package_policy extends).

3. package_policy_status_response

Pre-PR POST /api/fleet/package_policies/delete response items had:

body: { … }
id: { type: string }
name: { type: string }
output_id: { nullable: true, type: string }
package: { … nested object … }
policy_id: { deprecated: true, nullable: true, type: string }
policy_ids: { items: { type: string }, type: array }
statusCode: { type: number }
success: { type: boolean }

Post-PR Kibana_HTTP_APIs_package_policy_status_response has only body, id, name, statusCode, success — dropping output_id, policy_id, policy_ids, and the entire nested package object.

Pattern

The dropped fields share characteristics:

  • nullable strings declared via schema.oneOf([schema.literal(null), schema.string()]) — e.g. output_id, policy_id
  • arrays of strings (schema.arrayOf(schema.string())) — e.g. policy_ids
  • nullable booleans via schema.nullable(schema.boolean()) — e.g. supports_agentless
  • nested objects inherited via .extends() — e.g. package on the status response, id on update_package_policy_request

…all defined on a base schema that the now-meta.id-annotated schema extends. The generator appears to lose these fields when flattening base + extension into the named component.

Impact

Downstream OpenAPI-driven clients (e.g. the Terraform provider for Elastic Stack, which generates a Go client with oapi-codegen) lose the ability to set or read these fields:

  • simplified_create_package_policy_request — most painful. Users can no longer associate an integration policy with an agent policy (policy_ids) or override the output (output_id) on create via the simplified shape. The typed shape still exposes them, but switching shape requires converting mapped (map[string]input) inputs into typed ([]input with discriminators) inputs — a non-trivial rewrite. We have already had to add a FIXME and skip a regression test (TestOutputIdHandling/toAPIModel) in the provider until upstream is fixed.
  • update_package_policy_request — minor (id is normally taken from the URL path), but the generated client no longer exposes the field, which is observable in API contracts.
  • package_policy_status_response — bulk-delete response is less informative; callers can no longer learn the agent policy / output / package associated with the deleted policy.

Expected behaviour

The three affected named components should expose the same property sets the pre-PR inline schemas did. If any of these fields are intentionally being deprecated, please:

  • Add explicit deprecated: true (or x-deprecated/x-deprecated-reason) markers,
  • Keep the non-deprecated alternatives (policy_ids, output_id, supports_agentless, package) on the simplified / status schemas,
  • And include a migration note.

If the root cause is the @kbn/config-schema → OpenAPI generator dropping fields on extends() + meta.id, then the fix is at the generator layer (and the same bug likely affects other plugins that adopt meta.id on extended schemas in the future).

Steps to reproduce

PRE=16a5962f072868f5dde786a2dab91de2c23f068d
POST=f8da12e93c73
curl -sSf "https://raw.githubusercontent.com/elastic/kibana/$PRE/oas_docs/output/kibana.yaml"  -o /tmp/pre.yaml
curl -sSf "https://raw.githubusercontent.com/elastic/kibana/$POST/oas_docs/output/kibana.yaml" -o /tmp/post.yaml

# 1. simplified body
diff \
  <(awk '/post-fleet-package-policies$/,/responses:/' /tmp/pre.yaml \
      | grep -oE '(output_id|policy_id|policy_ids|supports_agentless)' | sort -u) \
  <(awk '/Kibana_HTTP_APIs_simplified_create_package_policy_request:/{f=1;next}
         f && /^    Kibana_HTTP_APIs_/ {exit} f' /tmp/post.yaml \
      | grep -oE '(output_id|policy_id|policy_ids|supports_agentless)' | sort -u)

# 2. update body
diff \
  <(awk '/put-fleet-package-policies-packagepolicyid/,/^      responses:/' /tmp/pre.yaml \
      | grep -E '^                    id:$') \
  <(awk '/Kibana_HTTP_APIs_update_package_policy_request:/{f=1;next}
         f && /^    Kibana_HTTP_APIs_/ {exit} f' /tmp/post.yaml \
      | grep -E '^        id:$')

# 3. delete response item
diff \
  <(awk '/post-fleet-package-policies-delete/,/post-fleet-package-policies-upgrade$/' /tmp/pre.yaml \
      | grep -oE '(output_id|policy_id|policy_ids|package):' | sort -u) \
  <(awk '/Kibana_HTTP_APIs_package_policy_status_response:/{f=1;next}
         f && /^    Kibana_HTTP_APIs_/ {exit} f' /tmp/post.yaml \
      | grep -oE '(output_id|policy_id|policy_ids|package):' | sort -u)

/cc @elastic/fleet

Metadata

Metadata

Assignees

No one assigned

    Labels

    Team:CorePlatform Core services: plugins, logging, config, saved objects, http, ES client, i18n, etc t//Team:FleetTeam label for Observability Data Collection Fleet team

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions