Skip to content
Merged
7,466 changes: 7,306 additions & 160 deletions oas_docs/output/kibana.serverless.yaml

Large diffs are not rendered by default.

7,464 changes: 7,305 additions & 159 deletions oas_docs/output/kibana.yaml

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@

import { OasConverter } from '.';
import { schema } from '@kbn/config-schema';
import { z } from '@kbn/zod/v4';
import { buildRouteValidationWithZod } from '@kbn/zod-helpers/v4';

describe('OasConverter', () => {
it('converts schemas with refs', () => {
Expand Down Expand Up @@ -88,4 +90,63 @@ describe('OasConverter', () => {
required: ['foo'],
});
});

describe('unwraps Zod schemas from buildRouteValidationWithZod', () => {
it('converts query parameters from a wrapped Zod schema', () => {
const converter = new OasConverter();
const querySchema = z.object({
include_components: z.boolean().optional().describe('Return component-level details'),
page: z.number().int().optional().describe('Page number'),
});
const wrapped = buildRouteValidationWithZod(querySchema);

const result = converter.convertQuery(wrapped);
expect(result.length).toBe(2);
expect(result.map((p) => p.name).sort()).toEqual(['include_components', 'page']);
expect(result.find((p) => p.name === 'include_components')).toMatchObject({
in: 'query',
required: false,
schema: { type: 'boolean' },
description: 'Return component-level details',
});
});

it('converts path parameters from a wrapped Zod schema', () => {
const converter = new OasConverter();
const paramsSchema = z.object({
entityType: z.enum(['user', 'host']).describe('The entity type'),
});
const wrapped = buildRouteValidationWithZod(paramsSchema);

const result = converter.convertPathParameters(wrapped, {
entityType: { optional: false },
});
expect(result.length).toBe(1);
expect(result[0]).toMatchObject({
name: 'entityType',
in: 'path',
required: true,
description: 'The entity type',
});
});

it('converts body schema from a wrapped Zod schema', () => {
const converter = new OasConverter();
const bodySchema = z.object({
name: z.string().describe('Entity name'),
tags: z.array(z.string()).optional().describe('Tags'),
});
const wrapped = buildRouteValidationWithZod(bodySchema);

const result = converter.convert(wrapped);
expect(result).toMatchObject({
type: 'object',
properties: {
name: { type: 'string', description: 'Entity name' },
tags: { type: 'array', items: { type: 'string' }, description: 'Tags' },
},
required: ['name'],
});
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,17 @@ export class OasConverter {
this.#env = env;
}

/**
* Unwrap a RouteValidationFunction produced by buildRouteValidationWithZod
* so the original Zod schema is visible to the converter chain.
*/
#unwrapSchema(schema: unknown): unknown {
if (typeof schema === 'function' && '_sourceSchema' in schema && schema._sourceSchema != null) {
return schema._sourceSchema;
}
return schema;
}

#getConverter(schema: unknown) {
return this.#converters.find((c) => c.is(schema))!;
}
Expand All @@ -43,7 +54,8 @@ export class OasConverter {
}

public convert(schema: unknown) {
const { schema: oasSchema, shared } = this.#getConverter(schema)!.convert(schema, {
const unwrapped = this.#unwrapSchema(schema);
const { schema: oasSchema, shared } = this.#getConverter(unwrapped)!.convert(unwrapped, {
env: this.#env,
sharedSchemas: this.#sharedSchemas,
});
Expand All @@ -52,16 +64,18 @@ export class OasConverter {
}

public convertPathParameters(schema: unknown, pathParameters: KnownParameters) {
const { params, shared } = this.#getConverter(schema).convertPathParameters(
schema,
const unwrapped = this.#unwrapSchema(schema);
const { params, shared } = this.#getConverter(unwrapped).convertPathParameters(
unwrapped,
pathParameters
);
this.#addComponents(shared);
return params;
}

public convertQuery(schema: unknown) {
const { query, shared } = this.#getConverter(schema).convertQuery(schema);
const unwrapped = this.#unwrapSchema(schema);
const { query, shared } = this.#getConverter(unwrapped).convertQuery(unwrapped);
this.#addComponents(shared);
return query;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,14 @@ interface ZodSafeParseable<Output = any> {
export function buildRouteValidationWithZod<Output>(
schema: ZodSafeParseable<Output>
): RouteValidationFunction<Output> {
return (inputValue: unknown, validationResult: RouteValidationResultFactory) => {
const fn = (inputValue: unknown, validationResult: RouteValidationResultFactory) => {
const decoded = schema.safeParse(inputValue);

return decoded.success
? validationResult.ok(decoded.data)
: validationResult.badRequest(stringifyZodError(decoded.error as any));
};
// Expose the original Zod schema so the OAS generator can detect and convert it.
(fn as RouteValidationFunction<Output> & { _sourceSchema: unknown })._sourceSchema = schema;
return fn;
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ export const LogExtractionConfig = z.object({
.string()
.regex(/[smdh]$/)
.default(LOG_EXTRACTION_DELAY_DEFAULT),
docsLimit: z.number().int().positive().default(LOG_EXTRACTION_DOCS_LIMIT_DEFAULT),
maxLogsPerPage: z.number().int().positive().default(LOG_EXTRACTION_MAX_LOGS_PER_PAGE_DEFAULT),
docsLimit: z.number().int().min(1).default(LOG_EXTRACTION_DOCS_LIMIT_DEFAULT),
maxLogsPerPage: z.number().int().min(1).default(LOG_EXTRACTION_MAX_LOGS_PER_PAGE_DEFAULT),
Comment on lines +34 to +35
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

relates to the max comment, just to avoid a max integer doc haha

Not sure if decreasing afterwards would lead to a considered breaking change? We can set to something that we know that it's a lot for our use case. Like docsLimit 1mil and maxLogsPerPage 10mil. Those max numbers are very very high

timeout: z
.string()
.regex(/[smdh]$/)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,9 @@ import {
} from '../../../domain/errors';
import { Entity } from '../../../../common/domain/definitions/entity.gen';

const paramsSchema = z
.object({
entityType: z.enum(ALL_ENTITY_TYPES).describe('The entity type to create.'),
})
.required();
const paramsSchema = z.object({
entityType: z.enum(ALL_ENTITY_TYPES).describe('The entity type to create.'),
});

export function registerCRUDCreate(router: EntityStorePluginRouter) {
router.versioned
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ const querySchema = z
size: z.coerce
.number()
.int()
.positive()
.min(1)
.optional()
.describe('Number of entities to return in search-after mode.'),
searchAfter: z
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,9 @@ import {
} from '../../../domain/errors';
import { Entity } from '../../../../common/domain/definitions/entity.gen';

const paramsSchema = z
.object({
entityType: z.enum(ALL_ENTITY_TYPES).describe('The entity type to update.'),
})
.required();
const paramsSchema = z.object({
entityType: z.enum(ALL_ENTITY_TYPES).describe('The entity type to update.'),
});

const querySchema = z.object({
force: BooleanFromString.optional()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ const bodySchema = z.object({
indexPatterns: z.array(z.string()).min(1),
fromDateISO: z.string().datetime(),
toDateISO: z.string().datetime(),
docsLimit: z.number().int().positive().optional(),
docsLimit: z.number().int().min(1).optional(),
});

export function registerForceCcsExtractToUpdates(router: EntityStorePluginRouter) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,8 @@ export const LogExtractionUpdateParams = z.object({
.string()
.regex(/[smdh]$/)
.optional(),
docsLimit: z.number().int().positive().optional(),
maxLogsPerPage: z.number().int().positive().optional(),
docsLimit: z.number().int().min(1).optional(),
maxLogsPerPage: z.number().int().min(1).optional(),
});

export type LogExtractionBodyParams = LogExtractionInstallParams | LogExtractionUpdateParams;
Expand Down
Loading