import { mkdtempSync, rmSync } from "node:fs"; import { tmpdir } from "node:os"; import path from "node:path"; import { afterAll, describe, expect, it } from "vitest"; import { isAllowedDesktopPath, normalizeDesktopWorkspacePath, resolveDesktopExecuteCwd, } from "./desktop-sandbox-paths.js"; describe("desktop sandbox path rules", () => { const home = mkdtempSync(path.join(tmpdir(), "rakazo-desktop-home-")); afterAll(() => { rmSync(home, { recursive: true, force: true }); }); it("resolves shell cwd inside the computer home", () => { expect(resolveDesktopExecuteCwd(undefined, home)).toBe(home); expect(resolveDesktopExecuteCwd(".", home)).toBe(home); expect(resolveDesktopExecuteCwd("/home/rakazo", home)).toBe(home); expect(resolveDesktopExecuteCwd("notes/result.txt", home)).toBe( path.join(home, "notes/result.txt"), ); expect(resolveDesktopExecuteCwd("/home/rakazo/notes/result.txt", home)).toBe( path.join(home, "notes/result.txt"), ); }); it("denies host-absolute shell cwd outside the computer home", () => { const outside = path.join(tmpdir(), "outside"); const cwd = resolveDesktopExecuteCwd(outside, home); expect(isAllowedDesktopPath(cwd, [home])).toBe(false); expect(isAllowedDesktopPath(resolveDesktopExecuteCwd("/etc", home), [home])).toBe(false); }); it("rejects traversal in shell cwd requests", () => { expect(() => resolveDesktopExecuteCwd("../outside", home)).toThrow(/escapes/i); expect(() => resolveDesktopExecuteCwd("/home/rakazo/../outside", home)).toThrow(/escapes/i); }); it("compares Windows roots case-insensitively without accepting siblings or other drives", () => { const roots = ["C:\\Users\\Owner\\Rakazo\\bot"]; expect( isAllowedDesktopPath("c:\\users\\owner\\rakazo\\BOT\\notes.txt", roots, path.win32), ).toBe(true); expect( isAllowedDesktopPath("C:\\Users\\Owner\\Rakazo\\bot-other\\notes.txt", roots, path.win32), ).toBe(false); expect(isAllowedDesktopPath("D:\\notes.txt", roots, path.win32)).toBe(false); }); it("handles explicitly allowed UNC roots without accepting sibling shares", () => { const roots = ["\\\\server\\share\\rakazo\\bot"]; expect( isAllowedDesktopPath("\\\\SERVER\\share\\rakazo\\BOT\\notes.txt", roots, path.win32), ).toBe(true); expect( isAllowedDesktopPath("\\\\server\\share-other\\rakazo\\bot\\notes.txt", roots, path.win32), ).toBe(false); }); it.each([ "C:\\outside.txt", "C:outside.txt", "\\\\server\\share\\outside.txt", "\\\\?\\C:\\outside.txt", "notes.txt:secret", "NUL.txt", "COM1.log", "trailing-dot.", "trailing-space ", ])("rejects ambiguous or special Windows path %s", (requested) => { expect(() => normalizeDesktopWorkspacePath(requested, "win32")).toThrow(/escapes/i); }); it("keeps ordinary portable paths and the virtual root syntax", () => { expect(normalizeDesktopWorkspacePath("/notes/result.txt", "win32")).toBe("notes/result.txt"); expect(normalizeDesktopWorkspacePath("notes/result.txt", "linux")).toBe("notes/result.txt"); }); });