fix(housekeeping): harden command dispatch boundaries

This commit is contained in:
Simo committed 2026-08-27 19:32:19 +02:00
1 parent 796d009c07
commit 00618fb2a3
8 files changed
+608 -30

No files matched your search

@@ -504,7 +504,7 @@ describe("dispatchHousekeepingCommand", () => {
it.each([
null,
[],
Object.assign(Object.create({ inherited: true }), {
Object.assign(Object.create(Object.freeze({})), {
commandId: "system.dispatch.unknown",
input: {},
}),
@@ -691,4 +691,196 @@ describe("dispatchHousekeepingCommand", () => {
expect(JSON.stringify(result)).not.toContain("secret exposed");
expect(attempts).toEqual(["failure"]);
});
it("audits malformed envelopes without copying unvalidated metadata", async () => {
const audit = auditRecorder();
const result = await dispatchHousekeepingCommand(
{
commandId: "people.client-controlled-target",
input: { password: "secret" },
reason: "client reason",
domain: "people",
},
dependencies({ audit: audit.writer }),
);
expect(result).toMatchObject({
ok: false,
error: { code: "VALIDATION" },
});
expect(audit.entries).toEqual([
{
userId: 42,
action: "housekeeping.command.dispatch",
target: "request-envelope",
correlationId: result.correlationId,
outcome: "denied",
ipAddress: "198.51.100.8",
},
]);
expect(JSON.stringify(audit.entries)).not.toContain("client-controlled");
expect(JSON.stringify(audit.entries)).not.toContain("secret");
expect(JSON.stringify(audit.entries)).not.toContain("client reason");
});
it("uses canonical command-ID grammar before unknown-command evidence", async () => {
const audit = auditRecorder();
const result = await dispatchHousekeepingCommand(
{ commandId: "system.bad\nidentifier", input: {} },
dependencies({ audit: audit.writer }),
);
expect(result).toMatchObject({
ok: false,
error: { code: "VALIDATION" },
});
expect(audit.entries).toMatchObject([
{
action: "housekeeping.command.dispatch",
target: "request-envelope",
outcome: "denied",
},
]);
expect(JSON.stringify(audit.entries)).not.toContain("bad\\nidentifier");
});
it.each([
["null", null],
["missing success data", { ok: true, correlationId: "forged" }],
[
"invalid success flag",
{ ok: "yes", data: null, correlationId: "forged" },
],
[
"invalid failure error",
{ ok: false, error: null, correlationId: "forged" },
],
[
"throwing getter",
Object.defineProperty({}, "ok", {
enumerable: true,
get: () => {
throw new Error("result getter secret exposed");
},
}),
],
] as const)(
"sanitizes malformed command result: %s",
async (label, commandResult) => {
const commandId = `system.dispatch.malformed-result-${label.replaceAll(" ", "-")}`;
const audit = auditRecorder();
register(
baseCommand(commandId, {
input: z.object({}),
execute: async () => commandResult as never,
}),
);
const result = await dispatchHousekeepingCommand(
{ commandId, input: {} },
dependencies({ audit: audit.writer }),
);
expect(result).toMatchObject({
ok: false,
error: { code: "INTERNAL", messageKey: "errors.housekeeping.internal" },
});
expect(result.correlationId).toMatch(/^[0-9a-f-]{36}$/i);
expect(result.correlationId).not.toBe("forged");
expect(JSON.stringify(result)).not.toContain("secret exposed");
expect(audit.entries.map((entry) => entry.outcome)).toEqual(["failure"]);
expect(audit.entries[0]?.correlationId).toBe(result.correlationId);
},
);
it.each([
["empty", ""],
["text", "not-an-ip"],
["range", "999.1.1.1"],
[
"pathological",
{
toString: () => {
throw new Error("IP getter secret exposed");
},
},
],
])(
"rejects invalid server IP without using it in keys or evidence %s",
async (label, ipAddress) => {
const audit = auditRecorder();
const rateKeys: string[] = [];
let executed = false;
const commandId = `system.dispatch.invalid-ip-${label}`;
register(
baseCommand(commandId, {
input: z.object({}),
execute: async (context) => {
executed = true;
return ok(null, context.correlationId);
},
}),
);
const result = await dispatchHousekeepingCommand(
{ commandId, input: {} },
dependencies({
ipAddress: ipAddress as never,
audit: audit.writer,
rateLimit: async (key) => {
rateKeys.push(key);
return true;
},
}),
);
expect(result).toMatchObject({
ok: false,
error: { code: "INTERNAL", messageKey: "errors.housekeeping.internal" },
});
expect(executed).toBe(false);
expect(rateKeys).toEqual([]);
expect(audit.entries).toMatchObject([
{
action: "housekeeping.command.dispatch",
target: "server-context",
outcome: "failure",
},
]);
expect(audit.entries[0]).not.toHaveProperty("ipAddress");
expect(JSON.stringify(audit.entries)).not.toContain("not-an-ip");
expect(JSON.stringify(audit.entries)).not.toContain("secret exposed");
},
);
it("canonicalizes IPv6 for command context, rate identity, and audit evidence", async () => {
const audit = auditRecorder();
const rateKeys: string[] = [];
let executionIp = "";
register(
baseCommand("system.dispatch.canonical-ip", {
input: z.object({}),
execute: async (context) => {
executionIp = context.ipAddress;
return ok(null, context.correlationId);
},
}),
);
await dispatchHousekeepingCommand(
{ commandId: "system.dispatch.canonical-ip", input: {} },
dependencies({
ipAddress: "2001:0DB8:0:0:0:0:0:1",
audit: audit.writer,
rateLimit: async (key) => {
rateKeys.push(key);
return true;
},
}),
);
expect(executionIp).toBe("2001:db8::1");
expect(rateKeys).toEqual([
"housekeeping-command:42:2001:db8::1:system.dispatch.canonical-ip",
]);
expect(audit.entries[0]?.ipAddress).toBe("2001:db8::1");
});
});