[8.18] [server-route-repository] Only validate zod schema effects in dev mode (#210412) (#210794)

# Backport

This will backport the following commits from `main` to `8.18`:
- [[server-route-repository] Only validate zod schema effects in dev
mode (#210412)](https://github.com/elastic/kibana/pull/210412)

<!--- Backport version: 9.4.3 -->

### Questions ?
Please refer to the [Backport tool
documentation](https://github.com/sqren/backport)

<!--BACKPORT [{"author":{"name":"Milton
Hultgren","email":"milton.hultgren@elastic.co"},"sourceCommit":{"committedDate":"2025-02-12T11:28:10Z","message":"[server-route-repository]
Only validate zod schema effects in dev mode (#210412)\n\nIn
https://github.com/elastic/kibana/pull/208166, we added a
validation\r\nstep that verifies that all zod schemas:\r\na) Are built
with supported types, meaning types that we can analyze for\r\nif they
are applied strictly (no excess keys)\r\nb) Are built with any side
effects (refine or transform, which may\r\nimpact the type
reliability)\r\n\r\nThis doesn't impact the actual parameter validation,
but is instead an\r\nadditional check on the schemas we're using.\r\nFor
any violation found, we log a warning, this has the downside
of\r\nincreasing our total log volume and is only really needed in
development\r\nmode.\r\n\r\nHence, in this PR, we're only logging these
warnings if Kibana is\r\nrunning in dev mode, and the PR updates all
consuming plugins to pass\r\nthis context
along.","sha":"42f5b0ba170e49db54e0aef5d56e255659484365","branchLabelMapping":{"^v9.1.0$":"main","^v8.19.0$":"8.x","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["release_note:skip","v9.0.0","Team:Obs
AI
Assistant","Team:obs-ux-management","backport:version","v8.18.0","v9.1.0","v8.19.0"],"title":"[server-route-repository]
Only validate zod schemas in dev
mode","number":210412,"url":"https://github.com/elastic/kibana/pull/210412","mergeCommit":{"message":"[server-route-repository]
Only validate zod schema effects in dev mode (#210412)\n\nIn
https://github.com/elastic/kibana/pull/208166, we added a
validation\r\nstep that verifies that all zod schemas:\r\na) Are built
with supported types, meaning types that we can analyze for\r\nif they
are applied strictly (no excess keys)\r\nb) Are built with any side
effects (refine or transform, which may\r\nimpact the type
reliability)\r\n\r\nThis doesn't impact the actual parameter validation,
but is instead an\r\nadditional check on the schemas we're using.\r\nFor
any violation found, we log a warning, this has the downside
of\r\nincreasing our total log volume and is only really needed in
development\r\nmode.\r\n\r\nHence, in this PR, we're only logging these
warnings if Kibana is\r\nrunning in dev mode, and the PR updates all
consuming plugins to pass\r\nthis context
along.","sha":"42f5b0ba170e49db54e0aef5d56e255659484365"}},"sourceBranch":"main","suggestedTargetBranches":["9.0","8.18","8.x"],"targetPullRequestStates":[{"branch":"9.0","label":"v9.0.0","branchLabelMappingKey":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"state":"NOT_CREATED"},{"branch":"8.18","label":"v8.18.0","branchLabelMappingKey":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"state":"NOT_CREATED"},{"branch":"main","label":"v9.1.0","branchLabelMappingKey":"^v9.1.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/210412","number":210412,"mergeCommit":{"message":"[server-route-repository]
Only validate zod schema effects in dev mode (#210412)\n\nIn
https://github.com/elastic/kibana/pull/208166, we added a
validation\r\nstep that verifies that all zod schemas:\r\na) Are built
with supported types, meaning types that we can analyze for\r\nif they
are applied strictly (no excess keys)\r\nb) Are built with any side
effects (refine or transform, which may\r\nimpact the type
reliability)\r\n\r\nThis doesn't impact the actual parameter validation,
but is instead an\r\nadditional check on the schemas we're using.\r\nFor
any violation found, we log a warning, this has the downside
of\r\nincreasing our total log volume and is only really needed in
development\r\nmode.\r\n\r\nHence, in this PR, we're only logging these
warnings if Kibana is\r\nrunning in dev mode, and the PR updates all
consuming plugins to pass\r\nthis context
along.","sha":"42f5b0ba170e49db54e0aef5d56e255659484365"}},{"branch":"8.x","label":"v8.19.0","branchLabelMappingKey":"^v8.19.0$","isSourceBranch":false,"state":"NOT_CREATED"}]}]
BACKPORT-->

Co-authored-by: Milton Hultgren <milton.hultgren@elastic.co>
This commit is contained in:
Kibana Machine 2025-02-13 01:52:22 +11:00 committed by GitHub
parent c2d3c70ac9
commit 376d5a2bc7
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
15 changed files with 40 additions and 3 deletions

View file

@ -437,6 +437,7 @@ describe('registerRoutes', () => {
aService: mockService,
},
repository,
runDevModeChecks: true,
});
}
});

View file

@ -43,11 +43,13 @@ export function registerRoutes<TDependencies extends Record<string, any>>({
repository,
logger,
dependencies,
runDevModeChecks,
}: {
core: CoreSetup;
repository: Record<string, ServerRoute<string, RouteParamsRT | undefined, any, any, any>>;
logger: Logger;
dependencies: TDependencies;
runDevModeChecks: boolean;
}) {
const routes = Object.values(repository);
@ -62,7 +64,7 @@ export function registerRoutes<TDependencies extends Record<string, any>>({
const { method, pathname, version } = parseEndpoint(endpoint);
if (isZod(params)) {
if (runDevModeChecks && isZod(params)) {
const dangerousSchemas = assertAllParsableSchemas(params);
if (dangerousSchemas.size > 0) {
for (const { key, schema } of dangerousSchemas) {
@ -74,7 +76,7 @@ export function registerRoutes<TDependencies extends Record<string, any>>({
);
} else {
logger.warn(
`Warning for ${endpoint}: schema ${typeName} at ${key} is not inspectable and could lead to runtime exceptions, convert it to a support schema`
`Warning for ${endpoint}: schema ${typeName} at ${key} is not inspectable and could lead to runtime exceptions, convert it to a supported schema`
);
}
}

View file

@ -69,8 +69,10 @@ export class EntityManagerServerPlugin
public config: EntityManagerConfig;
public logger: Logger;
public server?: EntityManagerServerSetup;
private isDev: boolean;
constructor(context: PluginInitializerContext<EntityManagerConfig>) {
this.isDev = context.env.mode.dev;
this.config = context.config.get();
this.logger = context.logger.get();
}
@ -143,6 +145,7 @@ export class EntityManagerServerPlugin
},
core,
logger: this.logger,
runDevModeChecks: this.isDev,
});
return {};

View file

@ -44,8 +44,10 @@ export class ObservabilityAIAssistantPlugin
logger: Logger;
config: ObservabilityAIAssistantConfig;
service: ObservabilityAIAssistantService | undefined;
private isDev: boolean;
constructor(context: PluginInitializerContext<ObservabilityAIAssistantConfig>) {
this.isDev = context.env.mode.dev;
this.logger = context.logger.get();
this.config = context.config.get<ObservabilityAIAssistantConfig>();
initLangtrace();
@ -139,6 +141,7 @@ export class ObservabilityAIAssistantPlugin
plugins: withCore,
service: this.service,
},
isDev: this.isDev,
});
core.analytics.registerEventType(recallRankingEvent);

View file

@ -15,6 +15,7 @@ export function registerServerRoutes({
core,
logger,
dependencies,
isDev,
}: {
core: CoreSetup<ObservabilityAIAssistantPluginStartDependencies>;
logger: Logger;
@ -22,11 +23,13 @@ export function registerServerRoutes({
ObservabilityAIAssistantRouteHandlerResources,
keyof DefaultRouteHandlerResources
>;
isDev: boolean;
}) {
registerRoutes({
core,
logger,
repository: getGlobalObservabilityAIAssistantServerRouteRepository(),
dependencies,
runDevModeChecks: isDev,
});
}

View file

@ -29,8 +29,10 @@ export class InventoryPlugin
>
{
logger: Logger;
private isDev;
constructor(context: PluginInitializerContext<ConfigSchema>) {
this.isDev = context.env.mode.dev;
this.logger = context.logger.get();
}
setup(
@ -55,6 +57,7 @@ export class InventoryPlugin
};
}) as unknown as InventoryRouteHandlerResources['plugins'],
},
isDev: this.isDev,
});
pluginsSetup.features.registerKibanaFeature(INVENTORY_SERVER_FEATURE);

View file

@ -14,15 +14,18 @@ export function registerServerRoutes({
core,
logger,
dependencies,
isDev,
}: {
core: CoreSetup;
logger: Logger;
dependencies: Omit<InventoryRouteHandlerResources, 'request' | 'context' | 'logger' | 'params'>;
isDev: boolean;
}) {
registerRoutes({
core,
logger,
repository: getGlobalInventoryServerRouteRepository(),
dependencies,
runDevModeChecks: isDev,
});
}

View file

@ -32,8 +32,10 @@ export class InvestigateAppPlugin
{
logger: Logger;
config: InvestigateAppConfig;
private isDev;
constructor(context: PluginInitializerContext<ConfigSchema>) {
this.isDev = context.env.mode.dev;
this.logger = context.logger.get();
this.config = context.config.get<InvestigateAppConfig>();
}
@ -62,6 +64,7 @@ export class InvestigateAppPlugin
dependencies: {
plugins: routeHandlerPlugins,
},
isDev: this.isDev,
});
}

View file

@ -14,6 +14,7 @@ export function registerServerRoutes({
core,
logger,
dependencies,
isDev,
}: {
core: CoreSetup;
logger: Logger;
@ -21,11 +22,13 @@ export function registerServerRoutes({
InvestigateAppRouteHandlerResources,
'request' | 'context' | 'logger' | 'params'
>;
isDev: boolean;
}) {
registerRoutes({
core,
logger,
repository: getGlobalInvestigateAppServerRouteRepository(),
dependencies,
runDevModeChecks: isDev,
});
}

View file

@ -202,6 +202,7 @@ export class ObservabilityPlugin
},
logger: this.logger,
repository: getObservabilityServerRouteRepository(config),
isDev: this.initContext.env.mode.dev,
});
});
/**

View file

@ -18,6 +18,7 @@ interface RegisterRoutes {
repository: AbstractObservabilityServerRouteRepository;
logger: Logger;
dependencies: RegisterRoutesDependencies;
isDev: boolean;
}
export interface RegisterRoutesDependencies {
@ -33,11 +34,12 @@ export interface RegisterRoutesDependencies {
getRulesClientWithRequest: (request: KibanaRequest) => Promise<RulesClientApi>;
}
export function registerRoutes({ repository, core, logger, dependencies }: RegisterRoutes) {
export function registerRoutes({ repository, core, logger, dependencies, isDev }: RegisterRoutes) {
registerServerRoutes({
core,
dependencies: { dependencies },
logger,
repository,
runDevModeChecks: isDev,
});
}

View file

@ -94,6 +94,7 @@ export class ObservabilityOnboardingPlugin
logger: this.logger,
repository: getObservabilityOnboardingServerRouteRepository(),
dependencies,
runDevModeChecks: this.initContext.env.mode.dev,
});
plugins.customIntegrations.registerCustomIntegration({

View file

@ -48,12 +48,14 @@ export class SLOPlugin
private readonly logger: Logger;
private readonly config: SLOConfig;
private readonly isServerless: boolean;
private readonly isDev: boolean;
private sloOrphanCleanupTask?: SloOrphanSummaryCleanupTask;
constructor(private readonly initContext: PluginInitializerContext) {
this.logger = this.initContext.logger.get();
this.config = this.initContext.config.get<SLOConfig>();
this.isServerless = this.initContext.env.packageInfo.buildFlavor === 'serverless';
this.isDev = this.initContext.env.mode.dev;
}
public setup(
@ -150,6 +152,7 @@ export class SLOPlugin
logger: this.logger,
repository: getSloServerRouteRepository({ isServerless: this.isServerless }),
isServerless: this.isServerless,
isDev: this.isDev,
});
core

View file

@ -14,6 +14,7 @@ interface RegisterRoutes {
logger: Logger;
dependencies: SLORoutesDependencies;
isServerless: boolean;
isDev: boolean;
}
export function registerServerRoutes({
@ -22,6 +23,7 @@ export function registerServerRoutes({
logger,
dependencies,
isServerless,
isDev,
}: RegisterRoutes) {
core.http.registerRouteHandlerContext<SLORequestHandlerContext, 'slo'>(
'slo',
@ -37,5 +39,6 @@ export function registerServerRoutes({
dependencies,
core,
logger,
runDevModeChecks: isDev,
});
}

View file

@ -48,8 +48,10 @@ export class StreamsPlugin
public config: StreamsConfig;
public logger: Logger;
public server?: StreamsServer;
private isDev: boolean;
constructor(context: PluginInitializerContext<StreamsConfig>) {
this.isDev = context.env.mode.dev;
this.config = context.config.get();
this.logger = context.logger.get();
}
@ -91,6 +93,7 @@ export class StreamsPlugin
},
core,
logger: this.logger,
runDevModeChecks: this.isDev,
});
return {};