diff --git a/.changeset/auditor-zod-v4-refactor.md b/.changeset/auditor-zod-v4-refactor.md new file mode 100644 index 0000000000..c1ac7ce0aa --- /dev/null +++ b/.changeset/auditor-zod-v4-refactor.md @@ -0,0 +1,5 @@ +--- +'@backstage/backend-defaults': patch +--- + +Refactored auditor severity log level mappings to use `zod/v4` with schema-driven defaults and type inference. diff --git a/packages/backend-defaults/src/entrypoints/auditor/types.ts b/packages/backend-defaults/src/entrypoints/auditor/types.ts deleted file mode 100644 index 49a6de75ea..0000000000 --- a/packages/backend-defaults/src/entrypoints/auditor/types.ts +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright 2025 The Backstage Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { z } from 'zod/v3'; - -/** @internal */ -export const severityLogLevelMappingsSchema = z.record( - z.enum(['low', 'medium', 'high', 'critical']), - z.enum(['debug', 'info', 'warn', 'error']), -); - -/** @internal */ -export const CONFIG_ROOT_KEY = 'backend.auditor'; diff --git a/packages/backend-defaults/src/entrypoints/auditor/utils.ts b/packages/backend-defaults/src/entrypoints/auditor/utils.ts index bf1e1f4756..0513aa84b2 100644 --- a/packages/backend-defaults/src/entrypoints/auditor/utils.ts +++ b/packages/backend-defaults/src/entrypoints/auditor/utils.ts @@ -16,8 +16,20 @@ import type { Config } from '@backstage/config'; import { InputError } from '@backstage/errors'; -import { z } from 'zod/v3'; -import { CONFIG_ROOT_KEY, severityLogLevelMappingsSchema } from './types'; +import { z } from 'zod/v4'; + +const CONFIG_ROOT_KEY = 'backend.auditor'; + +const logLevel = z.enum(['debug', 'info', 'warn', 'error']); + +const severityLogLevelMappingsSchema = z.object({ + low: logLevel.default('debug'), + medium: logLevel.default('info'), + high: logLevel.default('info'), + critical: logLevel.default('info'), +}); + +type SeverityLogLevelMappings = z.infer; /** * Gets the `backend.auditor.severityLogLevelMappings` configuration. @@ -26,41 +38,32 @@ import { CONFIG_ROOT_KEY, severityLogLevelMappingsSchema } from './types'; * @returns The validated severity-to-log-level mappings. * @throws error - {@link @backstage/errors#InputError} if the mapping configuration is invalid. */ -export function getSeverityLogLevelMappings(config: Config) { +export function getSeverityLogLevelMappings( + config: Config, +): SeverityLogLevelMappings { const auditorConfig = config.getOptionalConfig(CONFIG_ROOT_KEY); - const severityLogLevelMappings = { - low: - auditorConfig?.getOptionalString('severityLogLevelMappings.low') ?? - 'debug', - medium: - auditorConfig?.getOptionalString('severityLogLevelMappings.medium') ?? - 'info', - high: - auditorConfig?.getOptionalString('severityLogLevelMappings.high') ?? - 'info', - critical: - auditorConfig?.getOptionalString('severityLogLevelMappings.critical') ?? - 'info', - } as Required>; + const input = { + low: auditorConfig?.getOptionalString('severityLogLevelMappings.low'), + medium: auditorConfig?.getOptionalString('severityLogLevelMappings.medium'), + high: auditorConfig?.getOptionalString('severityLogLevelMappings.high'), + critical: auditorConfig?.getOptionalString( + 'severityLogLevelMappings.critical', + ), + }; - const res = severityLogLevelMappingsSchema.safeParse( - severityLogLevelMappings, - ); - if (!res.success) { - const key = res.error.issues.at(0)?.path.at(0) as string; - const value = ( - res.error.issues.at(0) as unknown as Record - ).received as string; - const validKeys = ( - res.error.issues.at(0) as unknown as Record - ).options as string[]; + const parsed = severityLogLevelMappingsSchema.safeParse(input); + + if (!parsed.success) { + const issue = parsed.error.issues[0]; + const key = issue.path[0] as keyof typeof input; + const receivedValue = input[key]; throw new InputError( - `The configuration value for 'backend.auditor.severityLogLevelMappings.${key}' was given an invalid value: '${value}'. Expected one of the following valid values: '${validKeys.join( + `The configuration value for '${CONFIG_ROOT_KEY}.severityLogLevelMappings.${key}' was given an invalid value: '${receivedValue}'. Expected one of the following valid values: '${logLevel.options.join( ', ', )}'.`, ); } - return severityLogLevelMappings; + return parsed.data; } diff --git a/packages/backend-defaults/src/entrypoints/scheduler/lib/types.ts b/packages/backend-defaults/src/entrypoints/scheduler/lib/types.ts index c7f77e7a85..64f7d00899 100644 --- a/packages/backend-defaults/src/entrypoints/scheduler/lib/types.ts +++ b/packages/backend-defaults/src/entrypoints/scheduler/lib/types.ts @@ -17,7 +17,7 @@ import { JsonObject } from '@backstage/types'; import { CronTime } from 'cron'; import { Duration } from 'luxon'; -import { z } from 'zod/v3'; +import { z } from 'zod/v4'; function isValidOptionalDurationString(d: string | undefined): boolean { try {