81 lines
3.0 KiB
TypeScript
81 lines
3.0 KiB
TypeScript
import { mkdtempSync, rmSync } from "node:fs";
|
|
import { homedir, tmpdir } from "node:os";
|
|
import path from "node:path";
|
|
import { afterAll, describe, expect, it } from "vitest";
|
|
import {
|
|
isAllowedDesktopPath,
|
|
normalizeDesktopWorkspacePath,
|
|
resolveDesktopExecuteCwd,
|
|
resolveDesktopHostPath,
|
|
} 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("allows host-absolute and parent-relative paths on the local desktop", () => {
|
|
const outside = path.join(tmpdir(), "outside");
|
|
expect(resolveDesktopExecuteCwd(outside, home)).toBe(path.resolve(outside));
|
|
expect(resolveDesktopExecuteCwd("/etc", home)).toBe(path.resolve("/etc"));
|
|
expect(resolveDesktopExecuteCwd("../outside", home)).toBe(path.resolve(home, "../outside"));
|
|
expect(resolveDesktopHostPath(home, "~/Documents")).toBe(path.resolve(homedir(), "Documents"));
|
|
});
|
|
|
|
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");
|
|
});
|
|
});
|