elastic / kibana

Your window into the Elastic Stack
https://www.elastic.co/products/kibana
Other
19.51k stars 8.07k forks source link

[Security Solution] Support local circular OpenAPI references by code generation #186066

Closed maximpn closed 2 weeks ago

maximpn commented 1 month ago

Epic: https://github.com/elastic/security-team/issues/9723 (internal)

Summary

kbn-openapi-generator package generates Zod schemas and related TS types from OpenAPI specification. It fails to handle recursive schemas. Code generation finished successfully but TS can't infer a proper type. See a related Zod documentation section.

We need to add support for recursive OpenAPI schemas.

Details

OpenAPI specification allows to use references to decompose and simplify schema declarations. References can also be used to declare a recursive schema with arbitrary recursive chain length.

An example recursive schema looks like

openapi: 3.0.0
info:
  title: Recursive schemas example
  version: 'not applicable'
paths: {}
components:
  x-codegen-enabled: true
  schemas:
    SchemaA:
      type: object
      properties:
        recursiveFieldB:
          $ref: '#/components/schemas/SchemaB'

    SchemaB:
      type: object
      properties:
        recursiveFieldA:
          $ref: '#/components/schemas/SchemaA'

The generated output has SchemaA and SchemaB types inferred as any

image image

Ideas to fix

As per Zod documentation section the problem can be resolved by explicitly declaring TS type and specifying it via z.ZodType<>. Additionally z.lazy() helps to resolve SchemaB is used before its declaration issue. So the following TS file is valid and doesn't cause any issues

import { z } from 'zod';

export interface SchemaA {
  recursiveFieldB?: SchemaB;
}
export const SchemaA: z.ZodType<SchemaA> = z.object({
  recursiveFieldB: z.lazy(() => SchemaB.optional()),
});

export type SchemaB = z.infer<typeof SchemaB>;
export const SchemaB = z.object({
  recursiveFieldA: SchemaA.optional(),
});
elasticmachine commented 1 month ago

Pinging @elastic/security-detections-response (Team:Detections and Resp)

elasticmachine commented 1 month ago

Pinging @elastic/security-solution (Team: SecuritySolution)

elasticmachine commented 1 month ago

Pinging @elastic/security-detection-rule-management (Team:Detection Rule Management)

maximpn commented 1 month ago

https://github.com/elastic/kibana/pull/186221 addresses local circular references. In general case we'll need support non local references as well.

maximpn commented 2 weeks ago

The task was implemented in https://github.com/elastic/kibana/pull/186221 and https://github.com/elastic/kibana/pull/187061.