fix(housekeeping): harden readonly schema facade
This commit is contained in:
1 parent
139e8cfc3a
commit
2970dff563
3 files changed
+782
-15
No files matched your search
@@ -274,6 +274,75 @@ describe("dispatchHousekeepingCommand", () => {
|
|||||||
expect(valid).toMatchObject({ ok: true });
|
expect(valid).toMatchObject({ ok: true });
|
||||||
expect(executions).toBe(1);
|
expect(executions).toBe(1);
|
||||||
});
|
});
|
||||||
|
it("rejects public error callbacks before they can weaken dispatcher validation", async () => {
|
||||||
|
const commandId = "system.dispatch.callback-schema-mutation";
|
||||||
|
let executions = 0;
|
||||||
|
register(
|
||||||
|
baseCommand(commandId, {
|
||||||
|
input: z.object({ value: z.string().min(3) }),
|
||||||
|
execute: async (context) => {
|
||||||
|
executions += 1;
|
||||||
|
return ok(null, context.correlationId);
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
const registered = getHousekeepingCommand(commandId);
|
||||||
|
if (!registered) throw new Error("registered command missing");
|
||||||
|
|
||||||
|
let callbackCalls = 0;
|
||||||
|
let capturedInstance: unknown;
|
||||||
|
let attackError: unknown;
|
||||||
|
try {
|
||||||
|
registered.input.safeParse(
|
||||||
|
{ value: "x" },
|
||||||
|
{
|
||||||
|
error: (issue) => {
|
||||||
|
callbackCalls += 1;
|
||||||
|
capturedInstance = issue.inst;
|
||||||
|
if (issue.inst) {
|
||||||
|
const internal = issue.inst._zod as {
|
||||||
|
def?: { minimum?: number };
|
||||||
|
};
|
||||||
|
if (typeof internal.def?.minimum === "number") {
|
||||||
|
internal.def.minimum = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "forged validation error";
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
} catch (error) {
|
||||||
|
attackError = error;
|
||||||
|
}
|
||||||
|
|
||||||
|
const forged = await dispatchHousekeepingCommand(
|
||||||
|
{ commandId, input: { value: "x" } },
|
||||||
|
dependencies(),
|
||||||
|
);
|
||||||
|
const valid = await dispatchHousekeepingCommand(
|
||||||
|
{ commandId, input: { value: "valid" } },
|
||||||
|
dependencies(),
|
||||||
|
);
|
||||||
|
|
||||||
|
expect({
|
||||||
|
attackError:
|
||||||
|
attackError instanceof TypeError ? attackError.message : undefined,
|
||||||
|
callbackCalls,
|
||||||
|
capturedInstance,
|
||||||
|
forgedOk: forged.ok,
|
||||||
|
forgedCode: forged.ok ? undefined : forged.error.code,
|
||||||
|
validOk: valid.ok,
|
||||||
|
executions,
|
||||||
|
}).toEqual({
|
||||||
|
attackError: "callback-bearing schema arguments are not supported",
|
||||||
|
callbackCalls: 0,
|
||||||
|
capturedInstance: undefined,
|
||||||
|
forgedOk: false,
|
||||||
|
forgedCode: "VALIDATION",
|
||||||
|
validOk: true,
|
||||||
|
executions: 1,
|
||||||
|
});
|
||||||
|
});
|
||||||
it("rejects a missing required reason before the command can execute", async () => {
|
it("rejects a missing required reason before the command can execute", async () => {
|
||||||
let executed = false;
|
let executed = false;
|
||||||
const audit = auditRecorder();
|
const audit = auditRecorder();
|
||||||
|
|||||||
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
Reference in new issue
Block a user