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" );
});
});
Messung V0.5 in Prozent C=100 H=100 G=100
¤ Dauer der Verarbeitung: 0.10 Sekunden
(vorverarbeitet am 2026-06-09)
¤
*© Formatika GbR, Deutschland