Files
qiming/qimingcode/packages/opencode/test/sandbox/path.test.ts

53 lines
2.1 KiB
TypeScript

import { describe, expect, test } from "bun:test"
import path from "path"
import { isWithinRoot, resolveWritableRoots, isPathWritable } from "../../src/sandbox/path"
describe("sandbox.path", () => {
test("strict: session dir allowed, sibling dir denied", () => {
const session = path.resolve("/workspace/project/session-a")
const sibling = path.resolve("/workspace/project/session-b/out.txt")
const roots = resolveWritableRoots({ sandbox_mode: "strict" }, session)
expect(isPathWritable(path.join(session, "a.txt"), roots)).toBe(true)
expect(isPathWritable(sibling, roots)).toBe(false)
})
test("isWithinRoot rejects parent escape", () => {
const root = path.resolve("C:/workspace/session")
const outside = path.resolve("C:/workspace/other/file.txt")
expect(isWithinRoot(outside, root)).toBe(false)
})
test("permissive yields empty roots (no gate)", () => {
const roots = resolveWritableRoots({ sandbox_mode: "permissive" }, "/any")
expect(roots).toEqual([])
expect(isPathWritable("/anywhere", roots)).toBe(true)
})
test("strict: no system temp in writable roots", () => {
const session = path.resolve("/workspace/project/session-a")
const roots = resolveWritableRoots({ sandbox_mode: "strict" }, session)
const temp = process.env.TEMP || process.env.TMP || "/tmp"
if (temp) {
expect(isPathWritable(path.join(path.resolve(temp), "escape.txt"), roots)).toBe(false)
}
})
test("strict ignores configured writable_roots (session cwd only)", () => {
const session = path.resolve("/workspace/project/session-a")
const projectRoot = path.resolve("/workspace/project")
const sibling = path.resolve("/workspace/project/session-b/out.txt")
const roots = resolveWritableRoots(
{
sandbox_mode: "strict",
writable_roots: [projectRoot],
},
session,
)
expect(isPathWritable(path.join(session, "a.txt"), roots)).toBe(true)
expect(isPathWritable(path.join(projectRoot, "shared.txt"), roots)).toBe(false)
expect(isPathWritable(sibling, roots)).toBe(false)
})
})