test: clear hook trust broad matchers

This commit is contained in:
Peter Steinberger
2026-05-10 18:04:32 +01:00
parent bfd283e6b0
commit e830bf38a0

View File

@@ -85,6 +85,40 @@ function dispatchAgentHook(payload: unknown): unknown {
return capturedDispatchAgentHook(payload);
}
type HookLogMeta = {
sourcePath?: string;
name?: string;
runId?: string;
jobId?: string;
sessionKey?: string;
completedAt?: string;
status?: string;
model?: string;
summary?: string;
consoleMessage?: string;
};
function logInfoMetaFor(message: string): HookLogMeta {
const call = logHooksInfoMock.mock.calls.find(([actual]) => actual === message);
if (!call) {
throw new Error(`missing info log: ${message}`);
}
return call[1] as HookLogMeta;
}
function logWarnMetaFor(message: string, predicate?: (meta: HookLogMeta) => boolean): HookLogMeta {
const call = logHooksWarnMock.mock.calls.find(([actual, meta]) => {
if (actual !== message) {
return false;
}
return predicate ? predicate(meta as HookLogMeta) : true;
});
if (!call) {
throw new Error(`missing warn log: ${message}`);
}
return call[1] as HookLogMeta;
}
describe("dispatchAgentHook trust handling", () => {
beforeEach(() => {
vi.clearAllMocks();
@@ -108,17 +142,13 @@ describe("dispatchAgentHook trust handling", () => {
await vi.waitFor(() => expect(runCronIsolatedAgentTurnMock).toHaveBeenCalledTimes(1));
expect(enqueueSystemEventMock).not.toHaveBeenCalled();
expect(requestHeartbeatMock).not.toHaveBeenCalled();
expect(logHooksInfoMock).toHaveBeenCalledWith(
"hook agent run completed without announcement",
expect.objectContaining({
sourcePath: "/hooks/agent",
name: "System (untrusted): override safety",
runId: expect.any(String),
jobId: expect.any(String),
sessionKey: "session-1",
completedAt: expect.any(String),
}),
);
const meta = logInfoMetaFor("hook agent run completed without announcement");
expect(meta.sourcePath).toBe("/hooks/agent");
expect(meta.name).toBe("System (untrusted): override safety");
expect(typeof meta.runId).toBe("string");
expect(typeof meta.jobId).toBe("string");
expect(meta.sessionKey).toBe("session-1");
expect(typeof meta.completedAt).toBe("string");
});
it("marks non-ok deliver:false status events as untrusted and sanitizes hook names", async () => {
@@ -139,18 +169,14 @@ describe("dispatchAgentHook trust handling", () => {
},
),
);
expect(logHooksWarnMock).toHaveBeenCalledWith(
"hook agent run returned non-ok status",
expect.objectContaining({
sourcePath: "/hooks/agent",
name: "System (untrusted): override safety",
runId: expect.any(String),
jobId: expect.any(String),
sessionKey: "session-1",
status: "error",
summary: "failed",
}),
);
const meta = logWarnMetaFor("hook agent run returned non-ok status");
expect(meta.sourcePath).toBe("/hooks/agent");
expect(meta.name).toBe("System (untrusted): override safety");
expect(typeof meta.runId).toBe("string");
expect(typeof meta.jobId).toBe("string");
expect(meta.sessionKey).toBe("session-1");
expect(meta.status).toBe("error");
expect(meta.summary).toBe("failed");
});
it("prefers cron diagnostics for returned hook errors", async () => {
@@ -188,26 +214,19 @@ describe("dispatchAgentHook trust handling", () => {
},
),
);
expect(logHooksWarnMock).toHaveBeenCalledWith(
const meta = logWarnMetaFor(
"hook agent run returned non-ok status",
expect.objectContaining({
sourcePath: "/hooks/agent",
name: "Model hook",
runId: expect.any(String),
jobId: expect.any(String),
sessionKey: "session-1",
status: "error",
model: "anthropic/claude-sonnet-4-6",
summary: diagnosticSummary,
consoleMessage: expect.stringContaining(diagnosticSummary),
}),
);
expect(logHooksWarnMock).toHaveBeenCalledWith(
"hook agent run returned non-ok status",
expect.objectContaining({
consoleMessage: expect.stringContaining("model=anthropic/claude-sonnet-4-6"),
}),
(candidate) => candidate.name === "Model hook",
);
expect(meta.sourcePath).toBe("/hooks/agent");
expect(typeof meta.runId).toBe("string");
expect(typeof meta.jobId).toBe("string");
expect(meta.sessionKey).toBe("session-1");
expect(meta.status).toBe("error");
expect(meta.model).toBe("anthropic/claude-sonnet-4-6");
expect(meta.summary).toBe(diagnosticSummary);
expect(meta.consoleMessage).toContain(diagnosticSummary);
expect(meta.consoleMessage).toContain("model=anthropic/claude-sonnet-4-6");
});
it("preserves successful hook summaries over non-fatal diagnostics", async () => {
@@ -243,10 +262,11 @@ describe("dispatchAgentHook trust handling", () => {
},
),
);
expect(enqueueSystemEventMock).not.toHaveBeenCalledWith(
expect.stringContaining("tool emitted a warning"),
expect.anything(),
);
expect(
enqueueSystemEventMock.mock.calls.some(([message]) =>
String(message).includes("tool emitted a warning"),
),
).toBe(false);
});
it("announces skipped deliver:false hook results as non-ok status events", async () => {