mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-07 16:40:43 +00:00
212 lines
6.3 KiB
TypeScript
212 lines
6.3 KiB
TypeScript
import { describe, expect, it, vi } from "vitest";
|
|
import {
|
|
createReadableTextStream,
|
|
createWritableTextBuffer,
|
|
runNativeHookRelayCli,
|
|
} from "./native-hook-relay-cli.js";
|
|
|
|
describe("native hook relay CLI", () => {
|
|
it("reads Codex hook JSON from stdin and forwards it to the gateway relay", async () => {
|
|
const callGateway = vi.fn(async () => ({ stdout: "", stderr: "", exitCode: 0 }));
|
|
const stdout = createWritableTextBuffer();
|
|
const stderr = createWritableTextBuffer();
|
|
|
|
const exitCode = await runNativeHookRelayCli(
|
|
{
|
|
provider: "codex",
|
|
relayId: "relay-1",
|
|
event: "pre_tool_use",
|
|
timeout: "1234",
|
|
},
|
|
{
|
|
stdin: createReadableTextStream(
|
|
JSON.stringify({
|
|
hook_event_name: "PreToolUse",
|
|
tool_name: "Bash",
|
|
tool_input: { command: "pnpm test" },
|
|
}),
|
|
),
|
|
stdout,
|
|
stderr,
|
|
callGateway: callGateway as never,
|
|
},
|
|
);
|
|
|
|
expect(exitCode).toBe(0);
|
|
expect(stdout.text()).toBe("");
|
|
expect(stderr.text()).toBe("");
|
|
expect(callGateway).toHaveBeenCalledWith({
|
|
method: "nativeHook.invoke",
|
|
params: {
|
|
provider: "codex",
|
|
relayId: "relay-1",
|
|
event: "pre_tool_use",
|
|
rawPayload: {
|
|
hook_event_name: "PreToolUse",
|
|
tool_name: "Bash",
|
|
tool_input: { command: "pnpm test" },
|
|
},
|
|
},
|
|
timeoutMs: 1234,
|
|
scopes: ["operator.admin"],
|
|
});
|
|
});
|
|
|
|
it("renders provider-compatible stdout, stderr, and exit code from the gateway response", async () => {
|
|
const callGateway = vi.fn(async () => ({ stdout: "out", stderr: "err", exitCode: 2 }));
|
|
const stdout = createWritableTextBuffer();
|
|
const stderr = createWritableTextBuffer();
|
|
|
|
const exitCode = await runNativeHookRelayCli(
|
|
{ provider: "codex", relayId: "relay-1", event: "permission_request" },
|
|
{
|
|
stdin: createReadableTextStream("{}"),
|
|
stdout,
|
|
stderr,
|
|
callGateway: callGateway as never,
|
|
},
|
|
);
|
|
|
|
expect(exitCode).toBe(2);
|
|
expect(stdout.text()).toBe("out");
|
|
expect(stderr.text()).toBe("err");
|
|
});
|
|
|
|
it("returns a nonzero code for malformed hook input without touching the gateway", async () => {
|
|
const callGateway = vi.fn();
|
|
const stderr = createWritableTextBuffer();
|
|
|
|
const exitCode = await runNativeHookRelayCli(
|
|
{ provider: "codex", relayId: "relay-1", event: "pre_tool_use" },
|
|
{
|
|
stdin: createReadableTextStream("{nope"),
|
|
stderr,
|
|
callGateway: callGateway as never,
|
|
},
|
|
);
|
|
|
|
expect(exitCode).toBe(1);
|
|
expect(stderr.text()).toContain("failed to read native hook input");
|
|
expect(callGateway).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it("rejects oversized hook input without touching the gateway", async () => {
|
|
const callGateway = vi.fn();
|
|
const stderr = createWritableTextBuffer();
|
|
|
|
const exitCode = await runNativeHookRelayCli(
|
|
{ provider: "codex", relayId: "relay-1", event: "post_tool_use" },
|
|
{
|
|
stdin: createReadableTextStream("x".repeat(1024 * 1024 + 1)),
|
|
stderr,
|
|
callGateway: callGateway as never,
|
|
},
|
|
);
|
|
|
|
expect(exitCode).toBe(1);
|
|
expect(stderr.text()).toContain("native hook input exceeds");
|
|
expect(callGateway).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it("fails closed for PreToolUse when the gateway relay is unavailable", async () => {
|
|
const callGateway = vi.fn(async () => {
|
|
throw new Error("gateway closed");
|
|
});
|
|
const stdout = createWritableTextBuffer();
|
|
const stderr = createWritableTextBuffer();
|
|
|
|
const exitCode = await runNativeHookRelayCli(
|
|
{ provider: "codex", relayId: "relay-1", event: "pre_tool_use" },
|
|
{
|
|
stdin: createReadableTextStream("{}"),
|
|
stdout,
|
|
stderr,
|
|
callGateway: callGateway as never,
|
|
},
|
|
);
|
|
|
|
expect(exitCode).toBe(0);
|
|
expect(JSON.parse(stdout.text())).toEqual({
|
|
hookSpecificOutput: {
|
|
hookEventName: "PreToolUse",
|
|
permissionDecision: "deny",
|
|
permissionDecisionReason: "Native hook relay unavailable",
|
|
},
|
|
});
|
|
expect(stderr.text()).toContain("native hook relay unavailable");
|
|
});
|
|
|
|
it("fails closed for PermissionRequest when the gateway relay is unavailable", async () => {
|
|
const callGateway = vi.fn(async () => {
|
|
throw new Error("gateway closed");
|
|
});
|
|
const stdout = createWritableTextBuffer();
|
|
const stderr = createWritableTextBuffer();
|
|
|
|
const exitCode = await runNativeHookRelayCli(
|
|
{ provider: "codex", relayId: "relay-1", event: "permission_request" },
|
|
{
|
|
stdin: createReadableTextStream("{}"),
|
|
stdout,
|
|
stderr,
|
|
callGateway: callGateway as never,
|
|
},
|
|
);
|
|
|
|
expect(exitCode).toBe(0);
|
|
expect(JSON.parse(stdout.text())).toEqual({
|
|
hookSpecificOutput: {
|
|
hookEventName: "PermissionRequest",
|
|
decision: {
|
|
behavior: "deny",
|
|
message: "Native hook relay unavailable",
|
|
},
|
|
},
|
|
});
|
|
});
|
|
|
|
it("keeps PostToolUse unavailable handling observational", async () => {
|
|
const callGateway = vi.fn(async () => {
|
|
throw new Error("gateway closed");
|
|
});
|
|
const stdout = createWritableTextBuffer();
|
|
const stderr = createWritableTextBuffer();
|
|
|
|
const exitCode = await runNativeHookRelayCli(
|
|
{ provider: "codex", relayId: "relay-1", event: "post_tool_use" },
|
|
{
|
|
stdin: createReadableTextStream("{}"),
|
|
stdout,
|
|
stderr,
|
|
callGateway: callGateway as never,
|
|
},
|
|
);
|
|
|
|
expect(exitCode).toBe(0);
|
|
expect(stdout.text()).toBe("");
|
|
expect(stderr.text()).toContain("native hook relay unavailable");
|
|
});
|
|
|
|
it("keeps before_agent_finalize unavailable handling observational", async () => {
|
|
const callGateway = vi.fn(async () => {
|
|
throw new Error("gateway closed");
|
|
});
|
|
const stdout = createWritableTextBuffer();
|
|
const stderr = createWritableTextBuffer();
|
|
|
|
const exitCode = await runNativeHookRelayCli(
|
|
{ provider: "codex", relayId: "relay-1", event: "before_agent_finalize" },
|
|
{
|
|
stdin: createReadableTextStream("{}"),
|
|
stdout,
|
|
stderr,
|
|
callGateway: callGateway as never,
|
|
},
|
|
);
|
|
|
|
expect(exitCode).toBe(0);
|
|
expect(stdout.text()).toBe("");
|
|
expect(stderr.text()).toContain("native hook relay unavailable");
|
|
});
|
|
});
|