import { afterEach, describe, expect, it } from "bun:test"; import { mkdir, rm } from "node:fs/promises"; import { resolve } from "node:path"; import { config } from "../../src/config.js"; import { resolveConversationWorkspace, setSandboxOwnership, } from "../../src/runtime/conversationWorkspace.js"; import { executeSandboxCommand, probeLandlockSandbox, } from "../../src/sandbox/landlockSandbox.js"; const createdPaths: string[] = []; afterEach(async () => { await Promise.all( createdPaths.splice(0).map((path) => rm(path, { force: true, recursive: true })), ); }); const createWorkspace = async (name: string = crypto.randomUUID()) => { const importRoot = resolve(config.RESULT_REF_IMPORT_DIR); await mkdir(importRoot, { recursive: true }); const workspace = resolve(importRoot, `conversation-sandbox-${name}`); await mkdir(workspace, { mode: 0o700 }); await setSandboxOwnership(workspace); createdPaths.push(workspace); return workspace; }; describe("Landlock sandbox", () => { it("requires Landlock ABI 4 and seccomp", async () => { const probe = await probeLandlockSandbox(); expect(probe.landlockAbi).toBeGreaterThanOrEqual(4); expect(probe.seccomp).toBe(true); }); it("allows local Python analysis while denying filesystem escape, secrets, and network", async () => { const workspace = await createWorkspace("primary"); const sibling = await createWorkspace("sibling"); await resolveConversationWorkspace(workspace, config.RESULT_REF_IMPORT_DIR); const allowed = await executeSandboxCommand( workspace, 'python3 -c "import json; open(\'result.json\', \'w\').write(json.__name__)" && cat result.json', 10, ); expect(allowed).toMatchObject({ exitCode: 0, stdout: "json" }); const escaped = await executeSandboxCommand( workspace, `cat ${resolve("package.json")}`, 10, ); expect(escaped.exitCode).not.toBe(0); expect(escaped.stderr).toContain("Permission denied"); const siblingRead = await executeSandboxCommand( workspace, `ls ${sibling}`, 10, ); expect(siblingRead.exitCode).not.toBe(0); const originalApiKey = process.env.DEEPSEEK_API_KEY; process.env.DEEPSEEK_API_KEY = "must-not-leak"; try { const environment = await executeSandboxCommand( workspace, 'test -z "$DEEPSEEK_API_KEY"', 10, ); expect(environment.exitCode).toBe(0); } finally { if (originalApiKey === undefined) { delete process.env.DEEPSEEK_API_KEY; } else { process.env.DEEPSEEK_API_KEY = originalApiKey; } } for (const socketType of ["SOCK_STREAM", "SOCK_DGRAM"]) { const network = await executeSandboxCommand( workspace, `python3 -c "import socket; socket.socket(socket.AF_INET, socket.${socketType})"`, 10, ); expect(network.exitCode).not.toBe(0); expect(network.stderr).toContain("Operation not permitted"); } }); });