feat: add per-session agent sandbox

This commit is contained in:
Peter Steinberger
2026-01-03 21:35:44 +01:00
parent 7bad9f3fbd
commit 3b075dff8a
20 changed files with 1134 additions and 36 deletions

View File

@@ -210,7 +210,7 @@ export function createAgentEventHandler({
const jobState =
evt.stream === "job" && typeof evt.data?.state === "string"
? (evt.data.state as "done" | "error" | string)
? evt.data.state
: null;
if (sessionKey) {

View File

@@ -10,6 +10,19 @@ import {
testState,
} from "./test-helpers.js";
const decodeWsData = (data: unknown): string => {
if (typeof data === "string") return data;
if (Buffer.isBuffer(data)) return data.toString("utf-8");
if (Array.isArray(data)) return Buffer.concat(data).toString("utf-8");
if (data instanceof ArrayBuffer) return Buffer.from(data).toString("utf-8");
if (ArrayBuffer.isView(data)) {
return Buffer.from(data.buffer, data.byteOffset, data.byteLength).toString(
"utf-8",
);
}
return "";
};
installGatewayTestHooks();
describe("gateway server cron", () => {
@@ -253,7 +266,7 @@ describe("gateway server cron", () => {
}>((resolve) => {
const timeout = setTimeout(() => resolve(null as never), 8000);
ws.on("message", (data) => {
const obj = JSON.parse(String(data));
const obj = JSON.parse(decodeWsData(data));
if (
obj.type === "event" &&
obj.event === "cron" &&

View File

@@ -20,6 +20,19 @@ import {
testState,
} from "./test-helpers.js";
const decodeWsData = (data: unknown): string => {
if (typeof data === "string") return data;
if (Buffer.isBuffer(data)) return data.toString("utf-8");
if (Array.isArray(data)) return Buffer.concat(data).toString("utf-8");
if (data instanceof ArrayBuffer) return Buffer.from(data).toString("utf-8");
if (ArrayBuffer.isView(data)) {
return Buffer.from(data.buffer, data.byteOffset, data.byteLength).toString(
"utf-8",
);
}
return "";
};
installGatewayTestHooks();
describe("gateway server node/bridge", () => {
@@ -37,7 +50,7 @@ describe("gateway server node/bridge", () => {
payload?: unknown;
}>((resolve) => {
ws.on("message", (data) => {
const obj = JSON.parse(String(data)) as {
const obj = JSON.parse(decodeWsData(data)) as {
type?: string;
event?: string;
payload?: unknown;
@@ -83,7 +96,7 @@ describe("gateway server node/bridge", () => {
payload?: unknown;
}>((resolve) => {
ws.on("message", (data) => {
const obj = JSON.parse(String(data)) as {
const obj = JSON.parse(decodeWsData(data)) as {
type?: string;
event?: string;
payload?: unknown;
@@ -805,7 +818,7 @@ describe("gateway server node/bridge", () => {
payload?: unknown;
}>((resolve) => {
ws.on("message", (data) => {
const obj = JSON.parse(String(data));
const obj = JSON.parse(decodeWsData(data));
if (isVoiceFinalChatEvent(obj)) {
resolve(obj as never);
}

View File

@@ -6,6 +6,8 @@ import {
startServerWithClient,
} from "./test-helpers.js";
const loadConfigHelpers = async () => await import("../config/config.js");
installGatewayTestHooks();
describe("gateway server providers", () => {
@@ -63,9 +65,8 @@ describe("gateway server providers", () => {
test("telegram.logout clears bot token from config", async () => {
const prevToken = process.env.TELEGRAM_BOT_TOKEN;
delete process.env.TELEGRAM_BOT_TOKEN;
const { readConfigFileSnapshot, writeConfigFile } = await import(
"../config/config.js"
);
const { readConfigFileSnapshot, writeConfigFile } =
await loadConfigHelpers();
await writeConfigFile({
telegram: {
botToken: "123:abc",

View File

@@ -322,6 +322,7 @@ export function installGatewayTestHooks() {
testState.allowFrom = undefined;
testIsNixMode.value = false;
cronIsolatedRun.mockClear();
agentCommand.mockClear();
drainSystemEvents();
resetAgentRunContextForTest();
const mod = await import("./server.js");