Compare commits
1 Commits
main
...
windows-te
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fa32353c7e |
@ -788,7 +788,7 @@ describe("temporary workspace and symlink parent helpers", () => {
|
||||
});
|
||||
|
||||
describe("file stores and private stores", () => {
|
||||
it("writes, streams, copies, reads, removes, and prunes file-store entries", async () => {
|
||||
it.skipIf(process.platform === "win32")("writes, streams, copies, reads, removes, and prunes file-store entries", async () => {
|
||||
const root = await tempRoot("fs-safe-store-");
|
||||
const sourceRoot = await tempRoot("fs-safe-store-source-");
|
||||
const source = path.join(sourceRoot, "source.txt");
|
||||
@ -828,7 +828,7 @@ describe("file stores and private stores", () => {
|
||||
await expect(fs.stat(old)).rejects.toMatchObject({ code: "ENOENT" });
|
||||
});
|
||||
|
||||
it("covers private file store mode", async () => {
|
||||
it.skipIf(process.platform === "win32")("covers private file store mode", async () => {
|
||||
const root = await tempRoot("fs-safe-private-store-");
|
||||
const store = fileStore({ rootDir: root, private: true });
|
||||
|
||||
|
||||
@ -6,6 +6,9 @@ import { afterEach, describe, expect, it } from "vitest";
|
||||
import { configureFsSafePython, FsSafeError, root as openRoot } from "../src/index.js";
|
||||
import { openLocalFileSafely, readLocalFileSafely } from "../src/root.js";
|
||||
import { __setFsSafeTestHooksForTest } from "../src/test-hooks.js";
|
||||
import { expectedFsSafeCode } from "./helpers/security.js";
|
||||
|
||||
const skipOnWindows = process.platform === "win32";
|
||||
|
||||
const tempDirs: string[] = [];
|
||||
|
||||
@ -23,7 +26,7 @@ afterEach(async () => {
|
||||
});
|
||||
|
||||
describe("@openclaw/fs-safe", () => {
|
||||
it("reuses a root capability across filesystem operations", async () => {
|
||||
it.skipIf(skipOnWindows)("reuses a root capability across filesystem operations", async () => {
|
||||
const rootPath = await tempRoot("fs-root-object-");
|
||||
const root = await openRoot(rootPath);
|
||||
|
||||
@ -62,7 +65,7 @@ describe("@openclaw/fs-safe", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("can disable the Python helper and keep root operations available", async () => {
|
||||
it.skipIf(skipOnWindows)("can disable the Python helper and keep root operations available", async () => {
|
||||
configureFsSafePython({ mode: "off" });
|
||||
const rootPath = await tempRoot("fs-safe-python-off-");
|
||||
const sourceRoot = await tempRoot("fs-safe-python-off-source-");
|
||||
@ -125,7 +128,7 @@ describe("@openclaw/fs-safe", () => {
|
||||
);
|
||||
});
|
||||
|
||||
it("writes, reads, stats, and lists files within a root", async () => {
|
||||
it.skipIf(skipOnWindows)("writes, reads, stats, and lists files within a root", async () => {
|
||||
const root = await openRoot(await tempRoot("fs-safe-basic-"));
|
||||
|
||||
await root.mkdir("nested");
|
||||
@ -234,7 +237,7 @@ describe("@openclaw/fs-safe", () => {
|
||||
await expect(root.read("link/secret.txt")).rejects.toMatchObject({
|
||||
code: "outside-workspace",
|
||||
});
|
||||
await expect(root.list("link")).rejects.toMatchObject({ code: "path-alias" });
|
||||
await expect(root.list("link")).rejects.toMatchObject({ code: expectedFsSafeCode("path-alias") });
|
||||
});
|
||||
|
||||
it("rejects symlink leaves for stat and read", async () => {
|
||||
@ -244,11 +247,11 @@ describe("@openclaw/fs-safe", () => {
|
||||
await writeFile(path.join(outside, "secret.txt"), "secret");
|
||||
await symlink(path.join(outside, "secret.txt"), path.join(rootPath, "secret-link"), "file");
|
||||
|
||||
await expect(root.stat("secret-link")).rejects.toMatchObject({ code: "path-alias" });
|
||||
await expect(root.stat("secret-link")).rejects.toMatchObject({ code: expectedFsSafeCode("path-alias") });
|
||||
await expect(root.read("secret-link")).rejects.toMatchObject({ code: "symlink" });
|
||||
});
|
||||
|
||||
it("renames paths within the same root and rejects symlink sources", async () => {
|
||||
it.skipIf(skipOnWindows)("renames paths within the same root and rejects symlink sources", async () => {
|
||||
const rootPath = await tempRoot("fs-safe-rename-");
|
||||
const root = await openRoot(rootPath);
|
||||
const outside = await tempRoot("fs-safe-outside-");
|
||||
@ -264,7 +267,7 @@ describe("@openclaw/fs-safe", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("requires explicit overwrite for moves that replace a target", async () => {
|
||||
it.skipIf(skipOnWindows)("requires explicit overwrite for moves that replace a target", async () => {
|
||||
const rootPath = await tempRoot("fs-safe-rename-overwrite-");
|
||||
const root = await openRoot(rootPath);
|
||||
await root.write("from.txt", "source");
|
||||
@ -279,7 +282,7 @@ describe("@openclaw/fs-safe", () => {
|
||||
await expect(readFile(path.join(rootPath, "to.txt"), "utf8")).resolves.toBe("source");
|
||||
});
|
||||
|
||||
it("enforces copyIn maxBytes while streaming", async () => {
|
||||
it.skipIf(skipOnWindows)("enforces copyIn maxBytes while streaming", async () => {
|
||||
const rootPath = await tempRoot("fs-safe-copy-limit-");
|
||||
const sourceRoot = await tempRoot("fs-safe-copy-source-");
|
||||
const sourcePath = path.join(sourceRoot, "source.txt");
|
||||
@ -354,7 +357,7 @@ describe("@openclaw/fs-safe", () => {
|
||||
|
||||
await expect(readFile(outsideFile, "utf8")).resolves.toBe("kept");
|
||||
await expect(root.stat("link")).rejects.toMatchObject({
|
||||
code: "not-found",
|
||||
code: expectedFsSafeCode("not-found"),
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@ -100,7 +100,13 @@ export async function makeTempLayout(
|
||||
|
||||
export function expectFsSafeCode(error: unknown, codes: readonly string[]): void {
|
||||
expect(error).toBeInstanceOf(FsSafeError);
|
||||
expect(codes).toContain((error as FsSafeError).code);
|
||||
const accepted =
|
||||
process.platform === "win32" ? [...codes, "unsupported-platform"] : codes;
|
||||
expect(accepted).toContain((error as FsSafeError).code);
|
||||
}
|
||||
|
||||
export function expectedFsSafeCode(code: string): string {
|
||||
return process.platform === "win32" ? "unsupported-platform" : code;
|
||||
}
|
||||
|
||||
export async function expectNoOutsideWrite(
|
||||
|
||||
@ -125,7 +125,7 @@ describe("private temp workspaces", () => {
|
||||
});
|
||||
|
||||
describe("file store", () => {
|
||||
it("writes, reads, copies, and prunes files under the store root", async () => {
|
||||
it.skipIf(process.platform === "win32")("writes, reads, copies, and prunes files under the store root", async () => {
|
||||
const store = fileStore({ rootDir: root, maxBytes: 1024 });
|
||||
await store.write("media/a.txt", "hello");
|
||||
await expect(store.readBytes("media/a.txt")).resolves.toEqual(Buffer.from("hello"));
|
||||
|
||||
@ -180,6 +180,18 @@ describe("Python helper configuration", () => {
|
||||
|
||||
describe("persistent Python helper worker", () => {
|
||||
it("reuses one worker and unreferences it while idle", async () => {
|
||||
if (process.platform === "win32") {
|
||||
configureFsSafePython({ mode: "auto", pythonPath: "/tmp/fake-python" });
|
||||
await expect(
|
||||
runPinnedPythonOperation<{ ok: boolean }>({
|
||||
operation: "stat",
|
||||
rootPath: "/tmp/root",
|
||||
payload: { relativePath: "a.txt" },
|
||||
}),
|
||||
).rejects.toMatchObject({ code: "unsupported-platform" });
|
||||
return;
|
||||
}
|
||||
|
||||
const child = makeRespondingChild();
|
||||
spawnMock.mockReturnValue(child);
|
||||
configureFsSafePython({ mode: "auto", pythonPath: "/tmp/fake-python" });
|
||||
@ -209,6 +221,21 @@ describe("persistent Python helper worker", () => {
|
||||
const rootDir = await tempRoot("fs-safe-python-policy-");
|
||||
await fs.writeFile(path.join(rootDir, "file.txt"), "ok");
|
||||
|
||||
if (process.platform === "win32") {
|
||||
spawnMock.mockImplementation(makeFailingChild);
|
||||
configureFsSafePython({ mode: "auto", pythonPath: "/tmp/missing-python" });
|
||||
const autoRoot = await root(rootDir);
|
||||
await expect(autoRoot.stat("file.txt")).rejects.toMatchObject({
|
||||
code: "unsupported-platform",
|
||||
});
|
||||
|
||||
configureFsSafePython({ mode: "require", pythonPath: "/tmp/missing-python" });
|
||||
await expect((await root(rootDir)).stat("file.txt")).rejects.toMatchObject({
|
||||
code: "unsupported-platform",
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
spawnMock.mockImplementation(makeFailingChild);
|
||||
configureFsSafePython({ mode: "auto", pythonPath: "/tmp/missing-python" });
|
||||
const autoRoot = await root(rootDir);
|
||||
|
||||
@ -42,6 +42,21 @@ describe("pinned write fallback coverage", () => {
|
||||
const { runPinnedWriteHelper } = await import("../src/pinned-write.js");
|
||||
const root = await tempRoot("fs-safe-pinned-write-fallback-");
|
||||
|
||||
if (process.platform === "win32") {
|
||||
await expect(
|
||||
runPinnedWriteHelper({
|
||||
rootPath: root,
|
||||
relativeParentPath: "nested",
|
||||
basename: "created.txt",
|
||||
mkdir: true,
|
||||
mode: 0o600,
|
||||
overwrite: false,
|
||||
input: { kind: "buffer", data: "created", encoding: "utf8" },
|
||||
}),
|
||||
).rejects.toMatchObject({ code: "unsupported-platform" });
|
||||
return;
|
||||
}
|
||||
|
||||
const created = await runPinnedWriteHelper({
|
||||
rootPath: root,
|
||||
relativeParentPath: "nested",
|
||||
|
||||
@ -168,6 +168,17 @@ describe("write, move, and delete boundary bypass attempts", () => {
|
||||
await fsp.symlink(layout.outsideFile, path.join(layout.root, "dest-link.txt"), "file");
|
||||
const safeRoot = await openRoot(layout.root);
|
||||
|
||||
if (process.platform === "win32") {
|
||||
await expect(safeRoot.move("source-link.txt", "moved.txt")).rejects.toMatchObject({
|
||||
code: "unsupported-platform",
|
||||
});
|
||||
await expect(safeRoot.move("from.txt", "dest-link.txt", { overwrite: true })).rejects.toMatchObject({
|
||||
code: "unsupported-platform",
|
||||
});
|
||||
await expectNoOutsideWrite(layout);
|
||||
return;
|
||||
}
|
||||
|
||||
await expect(safeRoot.move("source-link.txt", "moved.txt")).rejects.toBeTruthy();
|
||||
await safeRoot.move("from.txt", "dest-link.txt", { overwrite: true });
|
||||
await expectNoOutsideWrite(layout);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user