refactor(backend-defaults): migrate internal Zod usage from v3 to v4
The auditor's severity log level mappings previously used a `zod/v3` `z.record()` schema with manual fallbacks for defaults and relied on casting into Zod error internals (`.received`, `.options`) that changed between v3 and v4. This replaces it with a `z.object()` schema using `.default()` so that Zod owns the default values and type inference, and derives the valid values and received input without reaching into undocumented error properties. This does not migrate all `zod/v3` imports in the package, as the remaining usages are tied to public API types (e.g. `AnyZodObject` from `@backstage/backend-plugin-api`). Signed-off-by: Jon Koops <jonkoops@gmail.com>
This commit is contained in:
@@ -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.
|
||||
@@ -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';
|
||||
@@ -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<typeof severityLogLevelMappingsSchema>;
|
||||
|
||||
/**
|
||||
* 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<z.infer<typeof severityLogLevelMappingsSchema>>;
|
||||
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<PropertyKey, unknown>
|
||||
).received as string;
|
||||
const validKeys = (
|
||||
res.error.issues.at(0) as unknown as Record<PropertyKey, unknown>
|
||||
).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;
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user