import { assertEquals, assertRejects } from "jsr:@std/assert@1"; import { agentCommand, isRunnableProfileProcess, killProfileProcesses, readProfileFile, } from "./isolation.ts"; import type { RuntimeProfile } from "./runtime.ts"; const profile = (uid: number, home: string): RuntimeProfile => ({ index: uid - 20_000, type: "claude", model: "test", uid, gid: uid, home, tokenFile: null, }); Deno.test("zombie process entries are already quiescent", () => { const status = "State:\tZ (zombie)\nUid:\t20010\t20010\t20010\t20010\n"; assertEquals(isRunnableProfileProcess(status, 20_010), false); }); Deno.test({ name: "refuses to read a profile result symlink as root", permissions: { read: true, write: true, sys: ["uid"] }, async fn() { if (Deno.build.os === "windows") return; const root = await Deno.makeTempDir(); try { const secret = `${root}/reviewer-token`; const result = `${root}/result.md`; await Deno.writeTextFile(secret, "reviewer-secret", { mode: 0o600 }); await Deno.symlink(secret, result); await assertRejects( () => readProfileFile(profile(Deno.uid()!, root), result), Error, "regular private file", ); } finally { await Deno.remove(root, { recursive: true }); } }, }); Deno.test({ name: "a profile process can read only its own private files", permissions: { read: true, write: true, run: true, sys: ["uid"] }, async fn() { if (Deno.uid() !== 0) return; const root = await Deno.makeTempDir(); await Deno.chmod(root, 0o711); try { const homeA = `${root}/a`; const homeB = `${root}/b`; await Deno.mkdir(homeA, { mode: 0o700 }); await Deno.mkdir(homeB, { mode: 0o700 }); await Deno.chown(homeA, 20_000, 20_000); await Deno.chown(homeB, 20_001, 20_001); await Deno.writeTextFile(`${homeA}/token`, "own", { mode: 0o600 }); await Deno.chown(`${homeA}/token`, 20_000, 20_000); await Deno.writeTextFile(`${homeB}/token`, "sibling", { mode: 0o600 }); await Deno.chown(`${homeB}/token`, 20_001, 20_001); await Deno.writeTextFile(`${root}/reviewer`, "root", { mode: 0o600 }); const selected = profile(20_000, homeA); const own = await agentCommand(selected, "/bin/cat", [`${homeA}/token`], { cwd: "/", }).output(); const sibling = await agentCommand(selected, "/bin/cat", [ `${homeB}/token`, ], { cwd: "/" }).output(); const reviewer = await agentCommand(selected, "/bin/cat", [ `${root}/reviewer`, ], { cwd: "/" }).output(); assertEquals(new TextDecoder().decode(own.stdout), "own"); assertEquals(own.success, true); assertEquals(sibling.success, false); assertEquals(reviewer.success, false); } finally { await Deno.remove(root, { recursive: true }); } }, }); Deno.test({ name: "cleanup leaves no runnable daemonized process", permissions: "inherit", async fn() { if (Deno.uid() !== 0) return; const selected = profile(20_010, "/tmp"); const launched = await agentCommand(selected, "/bin/sh", [ "-c", "sleep 60 >/dev/null 2>&1 & echo $!", ], { cwd: "/" }).output(); const pid = Number(new TextDecoder().decode(launched.stdout).trim()); assertEquals(Number.isInteger(pid), true); await killProfileProcesses(selected.uid); const status = await Deno.readTextFile(`/proc/${pid}/status`).catch( (error) => { if (error instanceof Deno.errors.NotFound) return null; throw error; }, ); assertEquals( status === null || !isRunnableProfileProcess(status, selected.uid), true, ); }, }); Deno.test({ name: "the agent process cannot read its coordinator environment", permissions: { run: true, sys: ["uid"] }, async fn() { if (Deno.uid() !== 0) return; const selected = profile(20_020, "/tmp"); const result = await agentCommand(selected, "/usr/bin/cat", [ `/proc/${Deno.pid}/environ`, ], { cwd: "/", env: { PARENT_SECRET: "must-not-cross-boundary" }, clearEnv: true, stderr: "piped", }).output(); assertEquals(result.success, false); }, });