887 lines
29 KiB
TypeScript
887 lines
29 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
|
import { z } from "zod";
|
|
import { anyCapability, ok } from "../contracts";
|
|
import {
|
|
getHousekeepingCommand,
|
|
type HousekeepingCommand,
|
|
registerHousekeepingCommand,
|
|
sealHousekeepingCommandRegistry,
|
|
UnsupportedHousekeepingCommandSchemaError,
|
|
} from "./registry";
|
|
|
|
function command(
|
|
id: string,
|
|
owner: "people" | "system" = "people",
|
|
): HousekeepingCommand<{ id: number }, { id: number }> {
|
|
return {
|
|
id,
|
|
owner,
|
|
risk: "safe",
|
|
capability: anyCapability("admin.users.view"),
|
|
input: z.object({ id: z.number().int().positive() }),
|
|
requiresReason: false,
|
|
rateLimit: { attempts: 4, windowMs: 30_000 },
|
|
execute: async (context, input) => ok(input, context.correlationId),
|
|
};
|
|
}
|
|
|
|
type DescriptorReader = (
|
|
target: object,
|
|
property: PropertyKey,
|
|
) => PropertyDescriptor | undefined;
|
|
|
|
const descriptorReaders = [
|
|
[
|
|
"Object.getOwnPropertyDescriptor",
|
|
"object-descriptor",
|
|
Object.getOwnPropertyDescriptor,
|
|
],
|
|
[
|
|
"Object.getOwnPropertyDescriptors",
|
|
"object-descriptors",
|
|
(target: object, property: PropertyKey) =>
|
|
Reflect.get(Object.getOwnPropertyDescriptors(target), property) as
|
|
| PropertyDescriptor
|
|
| undefined,
|
|
],
|
|
[
|
|
"Reflect.getOwnPropertyDescriptor",
|
|
"reflect-descriptor",
|
|
Reflect.getOwnPropertyDescriptor,
|
|
],
|
|
] as const satisfies readonly (readonly [string, string, DescriptorReader])[];
|
|
|
|
function readDescriptorValue(
|
|
target: object,
|
|
property: PropertyKey,
|
|
readDescriptor: DescriptorReader,
|
|
): unknown {
|
|
const descriptor = readDescriptor(target, property);
|
|
if (!descriptor) throw new Error(`missing descriptor: ${String(property)}`);
|
|
if ("value" in descriptor) return descriptor.value;
|
|
if (descriptor.get) return Reflect.apply(descriptor.get, target, []);
|
|
return undefined;
|
|
}
|
|
|
|
function attemptMutation(mutate: () => void): void {
|
|
try {
|
|
mutate();
|
|
} catch {
|
|
// Readonly public views may reject the mutation directly.
|
|
}
|
|
}
|
|
|
|
function mutationWasRejected(mutate: () => void): boolean {
|
|
try {
|
|
mutate();
|
|
return false;
|
|
} catch {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
const unsafeSchemaCallbackMessage =
|
|
"callback-bearing schema arguments are not supported";
|
|
|
|
const callbackOptionMethodNames = [
|
|
"parse",
|
|
"safeParse",
|
|
"parseAsync",
|
|
"safeParseAsync",
|
|
"spa",
|
|
"encode",
|
|
"decode",
|
|
"encodeAsync",
|
|
"decodeAsync",
|
|
"safeEncode",
|
|
"safeDecode",
|
|
"safeEncodeAsync",
|
|
"safeDecodeAsync",
|
|
] as const;
|
|
|
|
function attemptMinimumMutation(instance: unknown): void {
|
|
if (typeof instance !== "object" || instance === null) return;
|
|
const internal = Reflect.get(instance, "_zod") as
|
|
| { def?: { minimum?: number } }
|
|
| undefined;
|
|
if (typeof internal?.def?.minimum !== "number") return;
|
|
attemptMutation(() => {
|
|
if (internal.def) internal.def.minimum = 0;
|
|
});
|
|
}
|
|
|
|
describe("housekeeping command registry", () => {
|
|
it("returns the validated snapshot registered under its global ID", () => {
|
|
const registered = command("people.registry.lookup");
|
|
|
|
registerHousekeepingCommand(registered);
|
|
|
|
expect(getHousekeepingCommand(registered.id)).toMatchObject({
|
|
id: "people.registry.lookup",
|
|
owner: "people",
|
|
risk: "safe",
|
|
requiresReason: false,
|
|
rateLimit: { attempts: 4, windowMs: 30_000 },
|
|
});
|
|
expect(getHousekeepingCommand(registered.id)).not.toBe(registered);
|
|
});
|
|
|
|
it("rejects a duplicate global command ID before it can shadow its owner", () => {
|
|
registerHousekeepingCommand(command("people.registry.duplicate"));
|
|
|
|
expect(() =>
|
|
registerHousekeepingCommand(command("people.registry.duplicate")),
|
|
).toThrow("duplicate command id: people.registry.duplicate");
|
|
});
|
|
|
|
it("rejects a command whose namespace disagrees with its declared owner", () => {
|
|
expect(() =>
|
|
registerHousekeepingCommand(
|
|
command("people.registry.owner-mismatch", "system"),
|
|
),
|
|
).toThrow("command owner mismatch: people.registry.owner-mismatch");
|
|
});
|
|
it("stores a frozen snapshot that resists mutation through the original definition", () => {
|
|
const original = command("people.registry.immutable");
|
|
const callerOwnedInput = original.input;
|
|
registerHousekeepingCommand(original);
|
|
const registered = getHousekeepingCommand(original.id);
|
|
if (!registered) throw new Error("registered command missing");
|
|
|
|
const registeredInput = registered.input;
|
|
const registeredExecute = registered.execute;
|
|
(original as { risk: "safe" | "sensitive" }).risk = "sensitive";
|
|
(original as { owner: "people" | "system" }).owner = "system";
|
|
(original as { input: z.ZodType<{ id: number }> }).input = z.object({
|
|
id: z.literal(999),
|
|
});
|
|
(original.capability.slugs as string[]).push("admin.settings.edit");
|
|
(original.rateLimit as { attempts: number }).attempts = 999;
|
|
(
|
|
original as {
|
|
execute: HousekeepingCommand<{ id: number }, { id: number }>["execute"];
|
|
}
|
|
).execute = async (context) => ok({ id: 999 }, context.correlationId);
|
|
|
|
expect(registered).toMatchObject({
|
|
risk: "safe",
|
|
owner: "people",
|
|
capability: { slugs: ["admin.users.view"] },
|
|
rateLimit: { attempts: 4, windowMs: 30_000 },
|
|
});
|
|
expect(registered.input).toBe(registeredInput);
|
|
expect(registered.input).not.toBe(callerOwnedInput);
|
|
expect(Object.isFrozen(callerOwnedInput)).toBe(false);
|
|
expect(registered.execute).toBe(registeredExecute);
|
|
expect(Object.isFrozen(registered)).toBe(true);
|
|
expect(Object.isFrozen(registered.input)).toBe(true);
|
|
expect(Object.isFrozen(registered.capability)).toBe(true);
|
|
expect(Object.isFrozen(registered.capability.slugs)).toBe(true);
|
|
expect(Object.isFrozen(registered.rateLimit)).toBe(true);
|
|
});
|
|
|
|
it.each([
|
|
["risk", { risk: "dangerous" }],
|
|
["requiresReason", { requiresReason: "yes" }],
|
|
[
|
|
"capability mode",
|
|
{ capability: { mode: "none", slugs: ["admin.users.view"] } },
|
|
],
|
|
["empty capability", { capability: { mode: "any", slugs: [] } }],
|
|
[
|
|
"unknown capability",
|
|
{ capability: { mode: "any", slugs: ["forged.permission"] } },
|
|
],
|
|
["execute", { execute: null }],
|
|
[
|
|
"Zod schema",
|
|
{ input: { safeParse: () => ({ success: true, data: {} }) } },
|
|
],
|
|
["normalized ID", { id: " people.registry.invalid-id " }],
|
|
] as const)("rejects an invalid %s definition", (label, override) => {
|
|
const invalid = {
|
|
...command(
|
|
`people.registry.invalid-${label.toLowerCase().replaceAll(" ", "-")}`,
|
|
),
|
|
...override,
|
|
} as unknown as HousekeepingCommand<{ id: number }, { id: number }>;
|
|
|
|
expect(() => registerHousekeepingCommand(invalid)).toThrow();
|
|
});
|
|
|
|
it("keeps registered validation unchanged after original shape and child mutation", () => {
|
|
const child = z.string().min(3);
|
|
const input = z.object({ value: child, guard: child });
|
|
registerHousekeepingCommand({
|
|
...command("people.registry.deep-validation"),
|
|
input,
|
|
execute: async (context, value) =>
|
|
ok({ id: value.value.length }, context.correlationId),
|
|
} as HousekeepingCommand<{ value: string; guard: string }, { id: number }>);
|
|
const registered = getHousekeepingCommand(
|
|
"people.registry.deep-validation",
|
|
);
|
|
if (!registered) throw new Error("registered command missing");
|
|
|
|
(input.def as { shape: { value: z.ZodType } }).shape.value = z.number();
|
|
const minCheck = (child.def as { checks: unknown[] }).checks[0] as {
|
|
_zod: { def: { minimum: number } };
|
|
};
|
|
minCheck._zod.def.minimum = 0;
|
|
|
|
expect(input.safeParse({ value: 4, guard: "a" }).success).toBe(true);
|
|
expect(
|
|
registered.input.safeParse({ value: "abcd", guard: "ab" }).success,
|
|
).toBe(false);
|
|
expect(
|
|
registered.input.safeParse({ value: "abcd", guard: "abcd" }).success,
|
|
).toBe(true);
|
|
expect(
|
|
registered.input.safeParse({ value: 4, guard: "abcd" }).success,
|
|
).toBe(false);
|
|
});
|
|
it("snapshots caller-owned lazy targets across supported container schemas", () => {
|
|
let lazyChild: z.ZodType = z.string().min(2);
|
|
let defaultValue = "registered-default";
|
|
const input = z.object({
|
|
choice: z.union([z.lazy(() => lazyChild), z.number().int()]),
|
|
optional: z.lazy(() => lazyChild).optional(),
|
|
defaulted: z.string().default(() => defaultValue),
|
|
list: z.array(z.lazy(() => lazyChild)),
|
|
lookup: z.record(
|
|
z.string(),
|
|
z.lazy(() => lazyChild),
|
|
),
|
|
});
|
|
registerHousekeepingCommand({
|
|
...command("people.registry.lazy-containers"),
|
|
input,
|
|
execute: async (context) => ok({ id: 1 }, context.correlationId),
|
|
} as HousekeepingCommand<z.output<typeof input>, { id: number }>);
|
|
const registered = getHousekeepingCommand(
|
|
"people.registry.lazy-containers",
|
|
);
|
|
if (!registered) throw new Error("registered command missing");
|
|
|
|
lazyChild = z.boolean();
|
|
defaultValue = "caller-mutated-default";
|
|
|
|
const parsed = registered.input.safeParse({
|
|
choice: "ok",
|
|
list: ["one"],
|
|
lookup: { key: "two" },
|
|
});
|
|
expect(parsed).toMatchObject({
|
|
success: true,
|
|
data: { defaulted: "registered-default" },
|
|
});
|
|
expect(
|
|
registered.input.safeParse({
|
|
choice: true,
|
|
optional: true,
|
|
list: [true],
|
|
lookup: { key: true },
|
|
}).success,
|
|
).toBe(false);
|
|
});
|
|
|
|
it("snapshots recursive lazy back-edges with cycle safety", () => {
|
|
type TreeNode = { name: string; children: TreeNode[] };
|
|
let nameSchema: z.ZodType = z.string().min(2);
|
|
let recursiveSchema: z.ZodType<TreeNode>;
|
|
recursiveSchema = z.object({
|
|
name: z.lazy(() => nameSchema),
|
|
children: z.array(z.lazy(() => recursiveSchema)),
|
|
}) as z.ZodType<TreeNode>;
|
|
registerHousekeepingCommand({
|
|
...command("people.registry.recursive-lazy"),
|
|
input: recursiveSchema,
|
|
execute: async (context) => ok({ id: 1 }, context.correlationId),
|
|
} as HousekeepingCommand<TreeNode, { id: number }>);
|
|
const registered = getHousekeepingCommand("people.registry.recursive-lazy");
|
|
if (!registered) throw new Error("registered command missing");
|
|
|
|
nameSchema = z.number();
|
|
recursiveSchema = z.object({
|
|
name: z.number(),
|
|
children: z.array(z.unknown()),
|
|
}) as unknown as z.ZodType<TreeNode>;
|
|
|
|
expect(
|
|
registered.input.safeParse({
|
|
name: "root",
|
|
children: [{ name: "leaf", children: [] }],
|
|
}).success,
|
|
).toBe(true);
|
|
expect(
|
|
registered.input.safeParse({
|
|
name: "root",
|
|
children: [{ name: 7, children: [] }],
|
|
}).success,
|
|
).toBe(false);
|
|
});
|
|
|
|
it.each([
|
|
["refine", "custom", z.string().refine((value) => value === "allowed")],
|
|
["super-refine", "custom", z.string().superRefine(() => undefined)],
|
|
[
|
|
"preprocess",
|
|
"transform",
|
|
z.preprocess((value) => String(value), z.string()),
|
|
],
|
|
["transform", "transform", z.string().transform((value) => value.length)],
|
|
["async-refine", "custom", z.string().refine(async () => true)],
|
|
] as const)(
|
|
"rejects unsupported executable validation schema %s",
|
|
(suffix, schemaKind, input) => {
|
|
const id = `people.registry.unsupported-${suffix}`;
|
|
let thrown: unknown;
|
|
try {
|
|
registerHousekeepingCommand({
|
|
...command(id),
|
|
input,
|
|
execute: async (context) => ok({ id: 1 }, context.correlationId),
|
|
} as HousekeepingCommand<unknown, { id: number }>);
|
|
} catch (error) {
|
|
thrown = error;
|
|
}
|
|
|
|
expect(thrown).toBeInstanceOf(UnsupportedHousekeepingCommandSchemaError);
|
|
expect(thrown).toMatchObject({
|
|
name: "UnsupportedHousekeepingCommandSchemaError",
|
|
code: "UNSUPPORTED_COMMAND_INPUT_SCHEMA",
|
|
commandId: id,
|
|
schemaKind,
|
|
});
|
|
expect(getHousekeepingCommand(id)).toBeUndefined();
|
|
},
|
|
);
|
|
|
|
it("rejects a lazy edge that cannot be resolved at registration", () => {
|
|
const id = "people.registry.unresolvable-lazy";
|
|
let thrown: unknown;
|
|
try {
|
|
registerHousekeepingCommand({
|
|
...command(id),
|
|
input: z.lazy(() => {
|
|
throw new Error("caller lazy secret");
|
|
}),
|
|
execute: async (context) => ok({ id: 1 }, context.correlationId),
|
|
} as HousekeepingCommand<unknown, { id: number }>);
|
|
} catch (error) {
|
|
thrown = error;
|
|
}
|
|
|
|
expect(thrown).toBeInstanceOf(UnsupportedHousekeepingCommandSchemaError);
|
|
expect(thrown).toMatchObject({
|
|
name: "UnsupportedHousekeepingCommandSchemaError",
|
|
code: "UNSUPPORTED_COMMAND_INPUT_SCHEMA",
|
|
commandId: id,
|
|
schemaKind: "lazy",
|
|
});
|
|
expect(String(thrown)).not.toContain("caller lazy secret");
|
|
});
|
|
it.each(descriptorReaders)(
|
|
"keeps private validation unchanged after nested mutation through %s",
|
|
(_api, suffix, readDescriptor) => {
|
|
const input = z.object({ value: z.string().min(3) });
|
|
const id = `people.registry.${suffix}`;
|
|
registerHousekeepingCommand({
|
|
...command(id),
|
|
input,
|
|
execute: async (context) => ok({ id: 1 }, context.correlationId),
|
|
} as HousekeepingCommand<z.output<typeof input>, { id: number }>);
|
|
const registered = getHousekeepingCommand(id);
|
|
if (!registered) throw new Error("registered command missing");
|
|
|
|
const definition = readDescriptorValue(
|
|
registered.input,
|
|
"def",
|
|
readDescriptor,
|
|
) as object;
|
|
const shape = readDescriptorValue(
|
|
definition,
|
|
"shape",
|
|
readDescriptor,
|
|
) as { value: z.ZodType };
|
|
const child = shape.value;
|
|
const childDefinition = readDescriptorValue(
|
|
child,
|
|
"def",
|
|
readDescriptor,
|
|
) as object;
|
|
const checks = readDescriptorValue(
|
|
childDefinition,
|
|
"checks",
|
|
readDescriptor,
|
|
) as readonly object[];
|
|
const internal = readDescriptorValue(
|
|
checks[0] as object,
|
|
"_zod",
|
|
readDescriptor,
|
|
) as object;
|
|
const checkDefinition = readDescriptorValue(
|
|
internal,
|
|
"def",
|
|
readDescriptor,
|
|
) as { minimum: number };
|
|
|
|
attemptMutation(() => {
|
|
shape.value = z.number();
|
|
});
|
|
attemptMutation(() => {
|
|
checkDefinition.minimum = 0;
|
|
});
|
|
|
|
expect(registered.input.safeParse({ value: "ab" }).success).toBe(false);
|
|
expect(registered.input.safeParse({ value: "abcd" }).success).toBe(true);
|
|
expect(registered.input.safeParse({ value: 7 }).success).toBe(false);
|
|
},
|
|
);
|
|
|
|
it("keeps own-key and symbol iteration detached from private checks", () => {
|
|
const input = z.object({ value: z.string().min(3) });
|
|
const id = "people.registry.symbol-iteration";
|
|
registerHousekeepingCommand({
|
|
...command(id),
|
|
input,
|
|
execute: async (context) => ok({ id: 1 }, context.correlationId),
|
|
} as HousekeepingCommand<z.output<typeof input>, { id: number }>);
|
|
const registered = getHousekeepingCommand(id);
|
|
if (!registered) throw new Error("registered command missing");
|
|
|
|
const publicInput = registered.input as z.ZodObject<{
|
|
value: z.ZodString;
|
|
}>;
|
|
const shape = publicInput.shape;
|
|
expect(Reflect.ownKeys(publicInput.def)).toContain("shape");
|
|
expect(Object.keys(shape)).toEqual(["value"]);
|
|
const child = Object.entries(shape)[0]?.[1];
|
|
if (!child) throw new Error("public child schema missing");
|
|
const checks = child.def.checks ?? [];
|
|
const spreadChecks = [...checks];
|
|
const iterator = checks[Symbol.iterator]();
|
|
const iteratedCheck = iterator.next().value;
|
|
if (!iteratedCheck) throw new Error("public check missing");
|
|
expect(spreadChecks[0]).toBe(iteratedCheck);
|
|
|
|
attemptMutation(() => {
|
|
(
|
|
iteratedCheck as unknown as {
|
|
_zod: { def: { minimum: number } };
|
|
}
|
|
)._zod.def.minimum = 0;
|
|
});
|
|
|
|
expect(registered.input.safeParse({ value: "ab" }).success).toBe(false);
|
|
expect(registered.input.safeParse({ value: "abcd" }).success).toBe(true);
|
|
});
|
|
|
|
it("keeps prototype methods operational without passing the private schema to callbacks", async () => {
|
|
const input = z.object({ value: z.string().min(3) });
|
|
const id = "people.registry.prototype-methods";
|
|
registerHousekeepingCommand({
|
|
...command(id),
|
|
input,
|
|
execute: async (context) => ok({ id: 1 }, context.correlationId),
|
|
} as HousekeepingCommand<z.output<typeof input>, { id: number }>);
|
|
const registered = getHousekeepingCommand(id);
|
|
if (!registered) throw new Error("registered command missing");
|
|
const publicInput = registered.input as z.ZodObject<{
|
|
value: z.ZodString;
|
|
}>;
|
|
|
|
const publicPrototype = Object.getPrototypeOf(publicInput);
|
|
expect(publicPrototype).toBe(Reflect.getPrototypeOf(publicInput));
|
|
const prototypeMutation = Symbol("prototype-mutation");
|
|
Object.defineProperty(publicPrototype, prototypeMutation, {
|
|
configurable: true,
|
|
value(this: z.ZodObject<{ value: z.ZodString }>): unknown {
|
|
attemptMutation(() => {
|
|
this.def.shape.value = z.number() as never;
|
|
});
|
|
return this.def;
|
|
},
|
|
});
|
|
try {
|
|
(
|
|
publicInput as typeof publicInput & {
|
|
[prototypeMutation](): unknown;
|
|
}
|
|
)[prototypeMutation]();
|
|
} finally {
|
|
Reflect.deleteProperty(publicPrototype, prototypeMutation);
|
|
}
|
|
expect(publicInput.safeParse({ value: "abcd" }).success).toBe(true);
|
|
expect(publicInput.safeParse({ value: 7 }).success).toBe(false);
|
|
|
|
let appliedSchema: z.ZodType | undefined;
|
|
const applied = publicInput.apply((schema) => {
|
|
appliedSchema = schema;
|
|
return schema;
|
|
});
|
|
expect(appliedSchema).toBe(publicInput);
|
|
expect(applied).toBe(publicInput);
|
|
|
|
let externallyRegistered: z.ZodType | undefined;
|
|
const externalRegistry = {
|
|
add(schema: z.ZodType): void {
|
|
externallyRegistered = schema;
|
|
},
|
|
};
|
|
expect(
|
|
publicInput.register(externalRegistry as never, undefined as never),
|
|
).toBe(publicInput);
|
|
expect(externallyRegistered).toBe(publicInput);
|
|
|
|
const partial = publicInput.partial();
|
|
const picked = publicInput.pick({ value: true });
|
|
expect(partial.safeParse({}).success).toBe(true);
|
|
expect(picked.safeParse({ value: "abcd" }).success).toBe(true);
|
|
expect((await publicInput.safeParseAsync({ value: "ab" })).success).toBe(
|
|
false,
|
|
);
|
|
expect((await publicInput.safeParseAsync({ value: "abcd" })).success).toBe(
|
|
true,
|
|
);
|
|
});
|
|
it.each(callbackOptionMethodNames)(
|
|
"rejects callback-bearing %s options before private issue nodes are exposed",
|
|
async (methodName) => {
|
|
const input = z.object({ value: z.string().min(3) });
|
|
const id = `people.registry.callback-${methodName.toLowerCase()}`;
|
|
registerHousekeepingCommand({
|
|
...command(id),
|
|
input,
|
|
execute: async (context) => ok({ id: 1 }, context.correlationId),
|
|
} as HousekeepingCommand<z.output<typeof input>, { id: number }>);
|
|
const registered = getHousekeepingCommand(id);
|
|
if (!registered) throw new Error("registered command missing");
|
|
|
|
let callbackCalls = 0;
|
|
let capturedInstance: unknown;
|
|
const errorCallback = (issue: unknown): string => {
|
|
callbackCalls += 1;
|
|
capturedInstance = Reflect.get(issue as object, "inst");
|
|
attemptMinimumMutation(capturedInstance);
|
|
return "forged validation error";
|
|
};
|
|
const method = Reflect.get(registered.input, methodName);
|
|
if (typeof method !== "function") {
|
|
throw new Error(`public schema method missing: ${methodName}`);
|
|
}
|
|
const attack = Promise.resolve().then(() =>
|
|
Reflect.apply(method, registered.input, [
|
|
{ value: "x" },
|
|
{ error: errorCallback },
|
|
]),
|
|
);
|
|
|
|
await expect(attack).rejects.toThrow(unsafeSchemaCallbackMessage);
|
|
expect(callbackCalls).toBe(0);
|
|
expect(capturedInstance).toBeUndefined();
|
|
expect(registered.input.safeParse({ value: "x" }).success).toBe(false);
|
|
expect(registered.input.safeParse({ value: "valid" }).success).toBe(true);
|
|
},
|
|
);
|
|
|
|
it("rejects JSON-schema overrides before private schema or check nodes are exposed", () => {
|
|
const input = z.object({ value: z.string().min(3) });
|
|
const id = "people.registry.callback-json-schema";
|
|
registerHousekeepingCommand({
|
|
...command(id),
|
|
input,
|
|
execute: async (context) => ok({ id: 1 }, context.correlationId),
|
|
} as HousekeepingCommand<z.output<typeof input>, { id: number }>);
|
|
const registered = getHousekeepingCommand(id);
|
|
if (!registered) throw new Error("registered command missing");
|
|
|
|
let callbackCalls = 0;
|
|
let capturedSchema: unknown;
|
|
let attackError: unknown;
|
|
try {
|
|
registered.input.toJSONSchema({
|
|
override: ({ zodSchema }) => {
|
|
callbackCalls += 1;
|
|
capturedSchema = zodSchema;
|
|
const checks = (zodSchema._zod.def as { checks?: unknown[] }).checks;
|
|
if (checks?.[0]) attemptMinimumMutation(checks[0]);
|
|
},
|
|
});
|
|
} catch (error) {
|
|
attackError = error;
|
|
}
|
|
|
|
expect({
|
|
attackError:
|
|
attackError instanceof TypeError ? attackError.message : undefined,
|
|
callbackCalls,
|
|
capturedSchema,
|
|
shortValueAccepted: registered.input.safeParse({ value: "x" }).success,
|
|
validValueAccepted: registered.input.safeParse({ value: "valid" })
|
|
.success,
|
|
}).toEqual({
|
|
attackError: unsafeSchemaCallbackMessage,
|
|
callbackCalls: 0,
|
|
capturedSchema: undefined,
|
|
shortValueAccepted: false,
|
|
validValueAccepted: true,
|
|
});
|
|
});
|
|
|
|
it("rejects an error callback concealed behind an option Proxy", () => {
|
|
const input = z.object({ value: z.string().min(3) });
|
|
const id = "people.registry.callback-proxy-options";
|
|
registerHousekeepingCommand({
|
|
...command(id),
|
|
input,
|
|
execute: async (context) => ok({ id: 1 }, context.correlationId),
|
|
} as HousekeepingCommand<z.output<typeof input>, { id: number }>);
|
|
const registered = getHousekeepingCommand(id);
|
|
if (!registered) throw new Error("registered command missing");
|
|
|
|
let callbackCalls = 0;
|
|
let capturedInstance: unknown;
|
|
const errorCallback = (issue: unknown): string => {
|
|
callbackCalls += 1;
|
|
capturedInstance = Reflect.get(issue as object, "inst");
|
|
attemptMinimumMutation(capturedInstance);
|
|
return "forged validation error";
|
|
};
|
|
const concealedOptions = new Proxy(
|
|
{},
|
|
{
|
|
get: (_target, property) =>
|
|
property === "error" ? errorCallback : undefined,
|
|
getOwnPropertyDescriptor: () => undefined,
|
|
ownKeys: () => [],
|
|
},
|
|
);
|
|
let attackError: unknown;
|
|
try {
|
|
registered.input.safeParse({ value: "x" }, concealedOptions as never);
|
|
} catch (error) {
|
|
attackError = error;
|
|
}
|
|
|
|
expect({
|
|
attackError:
|
|
attackError instanceof TypeError ? attackError.message : undefined,
|
|
callbackCalls,
|
|
capturedInstance,
|
|
shortValueAccepted: registered.input.safeParse({ value: "x" }).success,
|
|
validValueAccepted: registered.input.safeParse({ value: "valid" })
|
|
.success,
|
|
}).toEqual({
|
|
attackError: unsafeSchemaCallbackMessage,
|
|
callbackCalls: 0,
|
|
capturedInstance: undefined,
|
|
shortValueAccepted: false,
|
|
validValueAccepted: true,
|
|
});
|
|
});
|
|
|
|
it("keeps callback-free sync and async parsing available", async () => {
|
|
const input = z.object({ value: z.string().min(3) });
|
|
const id = "people.registry.callback-free-parse";
|
|
registerHousekeepingCommand({
|
|
...command(id),
|
|
input,
|
|
execute: async (context) => ok({ id: 1 }, context.correlationId),
|
|
} as HousekeepingCommand<z.output<typeof input>, { id: number }>);
|
|
const registered = getHousekeepingCommand(id);
|
|
if (!registered) throw new Error("registered command missing");
|
|
|
|
expect(
|
|
registered.input.parse({ value: "valid" }, { jitless: true }),
|
|
).toEqual({ value: "valid" });
|
|
expect(
|
|
registered.input.safeParse({ value: "valid" }, { reportInput: true }),
|
|
).toMatchObject({ success: true, data: { value: "valid" } });
|
|
await expect(
|
|
registered.input.parseAsync({ value: "valid" }, { jitless: true }),
|
|
).resolves.toEqual({ value: "valid" });
|
|
await expect(
|
|
registered.input.safeParseAsync({ value: "x" }, { reportInput: true }),
|
|
).resolves.toMatchObject({ success: false });
|
|
});
|
|
|
|
it("exposes detached Map, Set, and Date values as behaviorally readonly views", () => {
|
|
const sourceMap = new Map<string, { count: number }>([
|
|
["registered", { count: 1 }],
|
|
]);
|
|
const sourceSet = new Set(["registered"]);
|
|
const sourceDate = new Date("2026-08-26T12:34:56.000Z");
|
|
const input = z.object({ value: z.string() });
|
|
Object.assign(input.def, {
|
|
exposedMap: sourceMap,
|
|
exposedSet: sourceSet,
|
|
exposedDate: sourceDate,
|
|
});
|
|
const id = "people.registry.readonly-builtins";
|
|
registerHousekeepingCommand({
|
|
...command(id),
|
|
input,
|
|
execute: async (context) => ok({ id: 1 }, context.correlationId),
|
|
} as HousekeepingCommand<z.output<typeof input>, { id: number }>);
|
|
const registered = getHousekeepingCommand(id);
|
|
if (!registered) throw new Error("registered command missing");
|
|
const publicDefinition = registered.input
|
|
.def as typeof registered.input.def & {
|
|
exposedMap: ReadonlyMap<string, { count: number }>;
|
|
exposedSet: ReadonlySet<string>;
|
|
exposedDate: Date;
|
|
};
|
|
const publicMap = publicDefinition.exposedMap;
|
|
const publicSet = publicDefinition.exposedSet;
|
|
const publicDate = publicDefinition.exposedDate;
|
|
|
|
sourceMap.set("caller-late", { count: 2 });
|
|
sourceSet.add("caller-late");
|
|
sourceDate.setTime(0);
|
|
const mapForEachReceivers: unknown[] = [];
|
|
const mapEntries: Array<[string, number]> = [];
|
|
publicMap.forEach((value, key, collection) => {
|
|
mapEntries.push([key, value.count]);
|
|
mapForEachReceivers.push(collection);
|
|
});
|
|
const setForEachReceivers: unknown[] = [];
|
|
const setEntries: string[] = [];
|
|
publicSet.forEach((value, duplicate, collection) => {
|
|
expect(duplicate).toBe(value);
|
|
setEntries.push(value);
|
|
setForEachReceivers.push(collection);
|
|
});
|
|
const dateIsoBefore = publicDate.toISOString();
|
|
|
|
const mapEscape = Symbol("map-escape");
|
|
const setEscape = Symbol("set-escape");
|
|
const dateEscape = Symbol("date-escape");
|
|
Object.defineProperty(Map.prototype, mapEscape, {
|
|
configurable: true,
|
|
value(this: Map<unknown, unknown>): Map<unknown, unknown> {
|
|
return this;
|
|
},
|
|
});
|
|
Object.defineProperty(Set.prototype, setEscape, {
|
|
configurable: true,
|
|
value(this: Set<unknown>): Set<unknown> {
|
|
return this;
|
|
},
|
|
});
|
|
Object.defineProperty(Date.prototype, dateEscape, {
|
|
configurable: true,
|
|
value(this: Date): Date {
|
|
return this;
|
|
},
|
|
});
|
|
let escapedMap: unknown;
|
|
let escapedSet: unknown;
|
|
let escapedDate: unknown;
|
|
try {
|
|
const mapMethod = Reflect.get(publicMap, mapEscape);
|
|
const setMethod = Reflect.get(publicSet, setEscape);
|
|
const dateMethod = Reflect.get(publicDate, dateEscape);
|
|
if (
|
|
typeof mapMethod !== "function" ||
|
|
typeof setMethod !== "function" ||
|
|
typeof dateMethod !== "function"
|
|
) {
|
|
throw new Error("dynamic builtin method missing");
|
|
}
|
|
escapedMap = Reflect.apply(mapMethod, publicMap, []);
|
|
escapedSet = Reflect.apply(setMethod, publicSet, []);
|
|
escapedDate = Reflect.apply(dateMethod, publicDate, []);
|
|
} finally {
|
|
Reflect.deleteProperty(Map.prototype, mapEscape);
|
|
Reflect.deleteProperty(Set.prototype, setEscape);
|
|
Reflect.deleteProperty(Date.prototype, dateEscape);
|
|
}
|
|
const escapeMutationResults = [
|
|
mutationWasRejected(() =>
|
|
(escapedMap as Map<string, { count: number }>).set("escaped-forged", {
|
|
count: 11,
|
|
}),
|
|
),
|
|
mutationWasRejected(() =>
|
|
(escapedSet as Set<string>).add("escaped-forged"),
|
|
),
|
|
mutationWasRejected(() => (escapedDate as Date).setTime(0)),
|
|
];
|
|
|
|
const mapMutationResults = [
|
|
mutationWasRejected(() =>
|
|
(publicMap as Map<string, { count: number }>).set("forged", {
|
|
count: 9,
|
|
}),
|
|
),
|
|
mutationWasRejected(() =>
|
|
(publicMap as Map<string, { count: number }>).delete("registered"),
|
|
),
|
|
mutationWasRejected(() =>
|
|
(publicMap as Map<string, { count: number }>).clear(),
|
|
),
|
|
mutationWasRejected(() =>
|
|
Map.prototype.set.call(
|
|
publicMap as Map<string, { count: number }>,
|
|
"prototype-forged",
|
|
{ count: 10 },
|
|
),
|
|
),
|
|
];
|
|
const setMutationResults = [
|
|
mutationWasRejected(() => (publicSet as Set<string>).add("forged")),
|
|
mutationWasRejected(() =>
|
|
(publicSet as Set<string>).delete("registered"),
|
|
),
|
|
mutationWasRejected(() => (publicSet as Set<string>).clear()),
|
|
mutationWasRejected(() =>
|
|
Set.prototype.add.call(publicSet as Set<string>, "prototype-forged"),
|
|
),
|
|
];
|
|
const dateMutationResults = Object.getOwnPropertyNames(Date.prototype)
|
|
.filter((property) => property.startsWith("set"))
|
|
.map((property) =>
|
|
mutationWasRejected(() => {
|
|
const method = Reflect.get(publicDate, property);
|
|
if (typeof method !== "function") {
|
|
throw new TypeError(`date mutator unavailable: ${property}`);
|
|
}
|
|
Reflect.apply(method, publicDate, [0]);
|
|
}),
|
|
);
|
|
dateMutationResults.push(
|
|
mutationWasRejected(() => Date.prototype.setTime.call(publicDate, 0)),
|
|
);
|
|
let dateIsoAfter: string | undefined;
|
|
try {
|
|
dateIsoAfter = publicDate.toISOString();
|
|
} catch {
|
|
dateIsoAfter = undefined;
|
|
}
|
|
|
|
expect(dateMutationResults.length).toBeGreaterThan(1);
|
|
expect(dateMutationResults.every(Boolean)).toBe(true);
|
|
expect(escapeMutationResults).toEqual([true, true, true]);
|
|
expect(mapEntries).toEqual([["registered", 1]]);
|
|
expect(mapForEachReceivers).toHaveLength(1);
|
|
expect(mapForEachReceivers[0]).toBe(publicMap);
|
|
expect(mapMutationResults).toEqual([true, true, true, true]);
|
|
expect([...publicMap.entries()]).toEqual([["registered", { count: 1 }]]);
|
|
expect(setEntries).toEqual(["registered"]);
|
|
expect(setForEachReceivers).toHaveLength(1);
|
|
expect(setForEachReceivers[0]).toBe(publicSet);
|
|
expect(setMutationResults).toEqual([true, true, true, true]);
|
|
expect([...publicSet]).toEqual(["registered"]);
|
|
expect(dateIsoBefore).toBe("2026-08-26T12:34:56.000Z");
|
|
expect(dateIsoAfter).toBe("2026-08-26T12:34:56.000Z");
|
|
});
|
|
it("seals the global registry after deterministic bootstrap", () => {
|
|
sealHousekeepingCommandRegistry();
|
|
|
|
expect(() =>
|
|
registerHousekeepingCommand(command("people.registry.after-seal")),
|
|
).toThrow("command registry is sealed");
|
|
});
|
|
});
|