test: add OpenClaw bypass parity coverage

Co-authored-by: jesse-merhi <79823012+jesse-merhi@users.noreply.github.com>
This commit is contained in:
Jesse Merhi 2026-05-06 03:51:46 +10:00 committed by GitHub
parent f457c69c27
commit 83c10323a8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 613 additions and 0 deletions

36
.github/workflows/ci.yml vendored Normal file
View File

@ -0,0 +1,36 @@
name: ci
on:
pull_request:
push:
branches:
- main
workflow_dispatch:
permissions:
contents: read
jobs:
check:
name: Node 22 check
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- name: Check out
uses: actions/checkout@v4
- name: Set up Node
uses: actions/setup-node@v4
with:
node-version: "22"
- name: Enable pnpm
run: |
corepack enable
corepack prepare pnpm@10.33.2 --activate
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Check
run: pnpm check

View File

@ -0,0 +1,316 @@
import fs from "node:fs";
import fsp from "node:fs/promises";
import os from "node:os";
import path from "node:path";
import { afterEach, describe, expect, it } from "vitest";
import {
FsSafeError,
openPinnedFileSync,
openRootFile,
openRootFileSync,
pathScope,
resolveAbsolutePathForRead,
root as openRoot,
} from "../src/index.js";
type TempLayout = {
outside: string;
outsideFile: string;
root: string;
};
const tempDirs: string[] = [];
const TRAVERSAL_PAYLOADS = [
"../secret.txt",
"../../secret.txt",
"nested/../../secret.txt",
"nested/../../../secret.txt",
"./../secret.txt",
"nested/..//../secret.txt",
"nested/%2e%2e/secret.txt",
"%2e%2e/secret.txt",
"%2e%2e%2fsecret.txt",
"..%2fsecret.txt",
"%252e%252e%252fsecret.txt",
"..%00/secret.txt",
"..\\secret.txt",
"nested\\..\\..\\secret.txt",
"C:\\Windows\\win.ini",
"\\\\server\\share\\secret.txt",
] as const;
const LIST_TRAVERSAL_PAYLOADS = [
"..",
"../",
"../../",
"nested/../..",
"nested/../../outside",
"%2e%2e",
"%2e%2e%2f",
"..\\",
"C:\\Windows",
"\\\\server\\share",
] as const;
async function makeTempLayout(prefix: string): Promise<TempLayout> {
const root = await fsp.mkdtemp(path.join(os.tmpdir(), `${prefix}-root-`));
const outside = await fsp.mkdtemp(path.join(os.tmpdir(), `${prefix}-outside-`));
tempDirs.push(root, outside);
const outsideFile = path.join(outside, "secret.txt");
await fsp.writeFile(outsideFile, "outside secret");
return { outside, outsideFile, root };
}
async function closeIfOpen(value: unknown): Promise<void> {
if (typeof value === "object" && value !== null && "handle" in value) {
const handle = (value as { handle?: { close(): Promise<void> } }).handle;
if (handle) {
await handle.close();
}
}
}
function expectFsSafeCode(error: unknown, codes: readonly string[]): void {
expect(error).toBeInstanceOf(FsSafeError);
expect(codes).toContain((error as FsSafeError).code);
}
afterEach(async () => {
await Promise.all(tempDirs.splice(0).map((dir) => fsp.rm(dir, { force: true, recursive: true })));
});
describe("OpenClaw read bypass parity", () => {
it("rejects a payload corpus of traversal, encoded, NUL, Windows, and UNC read attempts", async () => {
const layout = await makeTempLayout("fs-safe-read-payloads");
await fsp.mkdir(path.join(layout.root, "nested"), { recursive: true });
await fsp.writeFile(path.join(layout.root, "nested", "safe.txt"), "safe");
const safeRoot = await openRoot(layout.root);
for (const payload of TRAVERSAL_PAYLOADS) {
await expect(safeRoot.read(payload), `read(${payload})`).rejects.toBeTruthy();
await expect(safeRoot.open(payload), `open(${payload})`).rejects.toBeTruthy();
await expect(safeRoot.stat(payload), `stat(${payload})`).rejects.toBeTruthy();
}
});
it("rejects a payload corpus of traversal, encoded, Windows, and UNC directory listing attempts", async () => {
const layout = await makeTempLayout("fs-safe-list-payloads");
await fsp.mkdir(path.join(layout.root, "nested"), { recursive: true });
await fsp.writeFile(path.join(layout.root, "nested", "safe.txt"), "safe");
const safeRoot = await openRoot(layout.root);
for (const payload of LIST_TRAVERSAL_PAYLOADS) {
await expect(safeRoot.list(payload), `list(${payload})`).rejects.toBeTruthy();
}
});
it("rejects traversal across root read, open, stat, list, and path scope APIs", async () => {
const layout = await makeTempLayout("fs-safe-read-traversal");
const safeRoot = await openRoot(layout.root);
const scope = pathScope(layout.root, { label: "test root" });
await expect(safeRoot.read("../secret.txt")).rejects.toSatisfy((error: unknown) => {
expectFsSafeCode(error, ["outside-workspace", "invalid-path", "path-alias"]);
return true;
});
await expect(safeRoot.open("../secret.txt")).rejects.toSatisfy((error: unknown) => {
expectFsSafeCode(error, ["outside-workspace", "invalid-path", "path-alias"]);
return true;
});
await expect(safeRoot.stat("../secret.txt")).rejects.toSatisfy((error: unknown) => {
expectFsSafeCode(error, ["outside-workspace", "invalid-path", "path-alias"]);
return true;
});
await expect(safeRoot.list(".." as string)).rejects.toSatisfy((error: unknown) => {
expectFsSafeCode(error, ["outside-workspace", "invalid-path", "path-alias"]);
return true;
});
await expect(scope.files(["../secret.txt"])).resolves.toMatchObject({ ok: false });
});
it("rejects symlink parents across root read/open/stat/list APIs", async () => {
const layout = await makeTempLayout("fs-safe-read-symlink-parent");
await fsp.symlink(layout.outside, path.join(layout.root, "link"), "dir");
const safeRoot = await openRoot(layout.root);
await expect(safeRoot.read("link/secret.txt")).rejects.toSatisfy((error: unknown) => {
expectFsSafeCode(error, ["outside-workspace", "path-alias", "symlink"]);
return true;
});
await expect(safeRoot.open("link/secret.txt")).rejects.toSatisfy((error: unknown) => {
expectFsSafeCode(error, ["outside-workspace", "path-alias", "symlink"]);
return true;
});
await expect(safeRoot.stat("link/secret.txt")).rejects.toSatisfy((error: unknown) => {
expectFsSafeCode(error, ["outside-workspace", "path-alias", "symlink"]);
return true;
});
await expect(safeRoot.list("link")).rejects.toSatisfy((error: unknown) => {
expectFsSafeCode(error, ["outside-workspace", "path-alias", "symlink"]);
return true;
});
});
it("rejects final symlink leaves for root read/open/stat and direct root-file APIs", async () => {
const layout = await makeTempLayout("fs-safe-read-symlink-leaf");
const linkPath = path.join(layout.root, "secret-link.txt");
await fsp.symlink(layout.outsideFile, linkPath, "file");
const safeRoot = await openRoot(layout.root);
await expect(safeRoot.read("secret-link.txt")).rejects.toSatisfy((error: unknown) => {
expectFsSafeCode(error, ["outside-workspace", "path-alias", "symlink"]);
return true;
});
await expect(safeRoot.open("secret-link.txt")).rejects.toSatisfy((error: unknown) => {
expectFsSafeCode(error, ["outside-workspace", "path-alias", "symlink"]);
return true;
});
await expect(safeRoot.stat("secret-link.txt")).rejects.toSatisfy((error: unknown) => {
expectFsSafeCode(error, ["outside-workspace", "path-alias", "symlink"]);
return true;
});
const rootRealPath = await fsp.realpath(layout.root);
const syncOpened = openRootFileSync({
absolutePath: linkPath,
boundaryLabel: "root",
rootPath: layout.root,
rootRealPath,
});
expect(syncOpened.ok).toBe(false);
if (syncOpened.ok) {
fs.closeSync(syncOpened.fd);
}
const asyncOpened = await openRootFile({
absolutePath: linkPath,
boundaryLabel: "root",
rootPath: layout.root,
rootRealPath,
});
expect(asyncOpened.ok).toBe(false);
if (asyncOpened.ok) {
await asyncOpened.handle.close();
}
const pinnedOpened = openPinnedFileSync({ filePath: linkPath, rejectPathSymlink: true });
expect(pinnedOpened.ok).toBe(false);
if (pinnedOpened.ok) {
fs.closeSync(pinnedOpened.fd);
}
});
it("rejects absolute outside files across root read, open, stat, and direct root-file APIs", async () => {
const layout = await makeTempLayout("fs-safe-absolute-outside");
const safeRoot = await openRoot(layout.root);
const rootRealPath = await fsp.realpath(layout.root);
await expect(safeRoot.read(layout.outsideFile)).rejects.toSatisfy((error: unknown) => {
expectFsSafeCode(error, ["outside-workspace", "path-alias", "invalid-path"]);
return true;
});
await expect(safeRoot.open(layout.outsideFile)).rejects.toSatisfy((error: unknown) => {
expectFsSafeCode(error, ["outside-workspace", "path-alias", "invalid-path"]);
return true;
});
await expect(safeRoot.stat(layout.outsideFile)).rejects.toSatisfy((error: unknown) => {
expectFsSafeCode(error, ["outside-workspace", "path-alias", "invalid-path"]);
return true;
});
const syncOpened = openRootFileSync({
absolutePath: layout.outsideFile,
boundaryLabel: "root",
rootPath: layout.root,
rootRealPath,
});
expect(syncOpened.ok).toBe(false);
if (syncOpened.ok) {
fs.closeSync(syncOpened.fd);
}
const asyncOpened = await openRootFile({
absolutePath: layout.outsideFile,
boundaryLabel: "root",
rootPath: layout.root,
rootRealPath,
});
expect(asyncOpened.ok).toBe(false);
if (asyncOpened.ok) {
await asyncOpened.handle.close();
}
});
it("rejects hardlinked read targets when hardlink rejection is enabled", async () => {
const layout = await makeTempLayout("fs-safe-read-hardlink");
const source = path.join(layout.root, "source.txt");
const hardlink = path.join(layout.root, "hardlink.txt");
await fsp.writeFile(source, "shared");
await fsp.link(source, hardlink);
const safeRoot = await openRoot(layout.root, { hardlinks: "reject" });
await expect(safeRoot.read("hardlink.txt")).rejects.toSatisfy((error: unknown) => {
expectFsSafeCode(error, ["hardlink", "invalid-path"]);
return true;
});
await expect(safeRoot.open("hardlink.txt")).rejects.toSatisfy((error: unknown) => {
expectFsSafeCode(error, ["hardlink", "invalid-path"]);
return true;
});
});
it("rejects absolute read paths that traverse symlinks by default", async () => {
const layout = await makeTempLayout("fs-safe-absolute-read");
const linkPath = path.join(layout.root, "absolute-link.txt");
await fsp.symlink(layout.outsideFile, linkPath, "file");
await expect(resolveAbsolutePathForRead(linkPath)).rejects.toMatchObject({ code: "symlink" });
const outsideFileReal = await fsp.realpath(layout.outsideFile);
await expect(resolveAbsolutePathForRead(linkPath, { symlinks: "follow" })).resolves.toMatchObject({
canonicalPath: outsideFileReal,
});
});
it("keeps encoded traversal payloads literal instead of URL-decoding into an escape", async () => {
const layout = await makeTempLayout("fs-safe-encoded-literal");
await fsp.writeFile(path.join(layout.root, "%2e%2e%2fsecret.txt"), "literal");
const safeRoot = await openRoot(layout.root);
await expect(safeRoot.readText("%2e%2e%2fsecret.txt")).resolves.toBe("literal");
await expect(safeRoot.read("%2e%2e/secret.txt")).rejects.toBeTruthy();
});
it("rejects pathScope payload batches when any member escapes", async () => {
const layout = await makeTempLayout("fs-safe-pathscope-payloads");
const scope = pathScope(layout.root, { label: "test root" });
for (const payload of TRAVERSAL_PAYLOADS) {
await expect(scope.files(["safe.txt", payload]), `pathScope.files(${payload})`).resolves.toMatchObject({
ok: false,
});
}
});
it("does not return outside bytes when root read APIs reject unsafe paths", async () => {
const layout = await makeTempLayout("fs-safe-read-no-leak");
await fsp.symlink(layout.outside, path.join(layout.root, "link"), "dir");
const safeRoot = await openRoot(layout.root);
for (const attempt of [
() => safeRoot.read("../outside/secret.txt"),
() => safeRoot.read("link/secret.txt"),
() => safeRoot.open("link/secret.txt"),
]) {
let opened: unknown;
try {
opened = await attempt();
await closeIfOpen(opened);
throw new Error("unsafe read unexpectedly succeeded");
} catch (error) {
await closeIfOpen(opened);
expect(error).not.toMatchObject({ message: "unsafe read unexpectedly succeeded" });
}
}
});
});

View File

@ -0,0 +1,261 @@
import fsp from "node:fs/promises";
import os from "node:os";
import path from "node:path";
import { afterEach, describe, expect, it } from "vitest";
import { FsSafeError, root as openRoot } from "../src/index.js";
type TempLayout = {
outside: string;
outsideFile: string;
root: string;
};
const tempDirs: string[] = [];
const ESCAPING_WRITE_PAYLOADS = [
"../pwned.txt",
"../../pwned.txt",
"nested/../../pwned.txt",
"nested/../../../pwned.txt",
"./../pwned.txt",
"nested/..//../pwned.txt",
] as const;
const LITERAL_SUSPICIOUS_WRITE_PAYLOADS = [
"nested/%2e%2e/pwned.txt",
"%2e%2e/pwned.txt",
"%2e%2e%2fpwned.txt",
"%252e%252e%252fpwned.txt",
] as const;
const POSIX_LITERAL_SUSPICIOUS_WRITE_PAYLOADS = [
"nested\\..\\..\\pwned.txt",
"C:\\Windows\\win.ini",
"\\\\server\\share\\pwned.txt",
] as const;
const SAFE_REJECTED_SUSPICIOUS_WRITE_PAYLOADS = [
"..%2fpwned.txt",
"..%00/pwned.txt",
"..\\pwned.txt",
] as const;
const ESCAPING_DIRECTORY_PAYLOADS = [
"..",
"../",
"../../",
"nested/../..",
"nested/../../outside",
] as const;
const LITERAL_SUSPICIOUS_DIRECTORY_PAYLOADS = ["%2e%2e", "%2e%2e%2f"] as const;
const SAFE_REJECTED_SUSPICIOUS_DIRECTORY_PAYLOADS = ["..\\"] as const;
const WINDOWS_REJECTED_SUSPICIOUS_DIRECTORY_PAYLOADS = [
"C:\\Windows",
"\\\\server\\share",
] as const;
async function makeTempLayout(prefix: string): Promise<TempLayout> {
const root = await fsp.mkdtemp(path.join(os.tmpdir(), `${prefix}-root-`));
const outside = await fsp.mkdtemp(path.join(os.tmpdir(), `${prefix}-outside-`));
tempDirs.push(root, outside);
const outsideFile = path.join(outside, "secret.txt");
await fsp.writeFile(outsideFile, "outside secret");
return { outside, outsideFile, root };
}
function expectFsSafeCode(error: unknown, codes: readonly string[]): void {
expect(error).toBeInstanceOf(FsSafeError);
expect(codes).toContain((error as FsSafeError).code);
}
async function expectNoOutsideWrite(layout: TempLayout, expected = "outside secret"): Promise<void> {
await expect(fsp.readFile(layout.outsideFile, "utf8")).resolves.toBe(expected);
}
afterEach(async () => {
await Promise.all(tempDirs.splice(0).map((dir) => fsp.rm(dir, { force: true, recursive: true })));
});
describe("OpenClaw write/move/delete bypass parity", () => {
it("rejects payload corpus write/create/append/openWritable attempts without touching outside files", async () => {
const layout = await makeTempLayout("fs-safe-write-payloads");
await fsp.mkdir(path.join(layout.root, "nested"), { recursive: true });
const safeRoot = await openRoot(layout.root);
for (const payload of ESCAPING_WRITE_PAYLOADS) {
await expect(safeRoot.write(payload, "pwned"), `write(${payload})`).rejects.toBeTruthy();
await expect(safeRoot.create(payload, "pwned"), `create(${payload})`).rejects.toBeTruthy();
await expect(safeRoot.append(payload, "pwned"), `append(${payload})`).rejects.toBeTruthy();
await expect(safeRoot.openWritable(payload), `openWritable(${payload})`).rejects.toBeTruthy();
}
await expectNoOutsideWrite(layout);
});
it("rejects payload corpus mkdir and remove attempts", async () => {
const layout = await makeTempLayout("fs-safe-dir-payloads");
await fsp.mkdir(path.join(layout.root, "nested"), { recursive: true });
const safeRoot = await openRoot(layout.root);
for (const payload of ESCAPING_DIRECTORY_PAYLOADS) {
await expect(safeRoot.mkdir(payload), `mkdir(${payload})`).rejects.toBeTruthy();
await expect(safeRoot.remove(payload), `remove(${payload})`).rejects.toBeTruthy();
}
await expectNoOutsideWrite(layout);
});
it("rejects absolute outside write/create/append/openWritable/copy destinations", async () => {
const layout = await makeTempLayout("fs-safe-write-absolute");
const safeRoot = await openRoot(layout.root);
const source = path.join(layout.root, "source.txt");
await fsp.writeFile(source, "source");
await expect(safeRoot.write(layout.outsideFile, "pwned")).rejects.toSatisfy((error: unknown) => {
expectFsSafeCode(error, ["outside-workspace", "path-alias", "invalid-path"]);
return true;
});
await expect(safeRoot.create(layout.outsideFile, "pwned")).rejects.toBeTruthy();
await expect(safeRoot.append(layout.outsideFile, "pwned")).rejects.toBeTruthy();
await expect(safeRoot.openWritable(layout.outsideFile)).rejects.toBeTruthy();
await expect(safeRoot.copyIn(layout.outsideFile, source)).rejects.toBeTruthy();
await expectNoOutsideWrite(layout);
});
it("rejects symlink parent write/create/append/openWritable/copy/mkdir/remove destinations", async () => {
const layout = await makeTempLayout("fs-safe-write-symlink-parent");
await fsp.symlink(layout.outside, path.join(layout.root, "link"), "dir");
const safeRoot = await openRoot(layout.root);
const source = path.join(layout.root, "source.txt");
await fsp.writeFile(source, "source");
for (const action of [
() => safeRoot.write("link/secret.txt", "pwned"),
() => safeRoot.create("link/secret.txt", "pwned"),
() => safeRoot.append("link/secret.txt", "pwned"),
() => safeRoot.openWritable("link/secret.txt"),
() => safeRoot.copyIn("link/secret.txt", source),
() => safeRoot.mkdir("link/nested"),
() => safeRoot.remove("link/secret.txt"),
]) {
await expect(action()).rejects.toBeTruthy();
}
await expectNoOutsideWrite(layout);
});
it("rejects final symlink leaf write/append/openWritable/copy targets without clobbering their target", async () => {
const layout = await makeTempLayout("fs-safe-write-symlink-leaf");
await fsp.symlink(layout.outsideFile, path.join(layout.root, "link.txt"), "file");
const source = path.join(layout.root, "source.txt");
await fsp.writeFile(source, "source");
const safeRoot = await openRoot(layout.root);
for (const action of [
() => safeRoot.write("link.txt", "pwned"),
() => safeRoot.append("link.txt", "pwned"),
() => safeRoot.openWritable("link.txt"),
() => safeRoot.copyIn("link.txt", source),
]) {
await expect(action()).rejects.toBeTruthy();
}
await expectNoOutsideWrite(layout);
});
it("rejects hardlinked write and append targets", async () => {
const layout = await makeTempLayout("fs-safe-write-hardlink");
const source = path.join(layout.root, "source.txt");
const hardlink = path.join(layout.root, "hardlink.txt");
await fsp.writeFile(source, "shared");
await fsp.link(source, hardlink);
const safeRoot = await openRoot(layout.root);
await expect(safeRoot.write("hardlink.txt", "pwned")).rejects.toSatisfy((error: unknown) => {
expectFsSafeCode(error, ["hardlink", "invalid-path", "path-alias"]);
return true;
});
await expect(safeRoot.append("hardlink.txt", "pwned")).rejects.toSatisfy((error: unknown) => {
expectFsSafeCode(error, ["hardlink", "invalid-path", "path-alias"]);
return true;
});
});
it("rejects move payloads for escaping sources and destinations", async () => {
const layout = await makeTempLayout("fs-safe-move-payloads");
await fsp.writeFile(path.join(layout.root, "from.txt"), "from");
const safeRoot = await openRoot(layout.root);
for (const payload of ESCAPING_WRITE_PAYLOADS) {
await expect(safeRoot.move(payload, "to.txt"), `move-from(${payload})`).rejects.toBeTruthy();
await expect(safeRoot.move("from.txt", payload), `move-to(${payload})`).rejects.toBeTruthy();
}
await expectNoOutsideWrite(layout);
await expect(fsp.readFile(path.join(layout.root, "from.txt"), "utf8")).resolves.toBe("from");
});
it("rejects symlink move source and destination endpoints without touching outside targets", async () => {
const layout = await makeTempLayout("fs-safe-move-symlink");
await fsp.writeFile(path.join(layout.root, "from.txt"), "from");
await fsp.symlink(layout.outsideFile, path.join(layout.root, "source-link.txt"), "file");
await fsp.symlink(layout.outsideFile, path.join(layout.root, "dest-link.txt"), "file");
const safeRoot = await openRoot(layout.root);
await expect(safeRoot.move("source-link.txt", "moved.txt")).rejects.toBeTruthy();
await safeRoot.move("from.txt", "dest-link.txt", { overwrite: true });
await expectNoOutsideWrite(layout);
await expect(fsp.readFile(path.join(layout.root, "dest-link.txt"), "utf8")).resolves.toBe("from");
});
it("rejects remove through symlink parents but removes final symlink entries without following", async () => {
const layout = await makeTempLayout("fs-safe-remove-symlink");
await fsp.symlink(layout.outside, path.join(layout.root, "parent-link"), "dir");
await fsp.symlink(layout.outsideFile, path.join(layout.root, "leaf-link.txt"), "file");
const safeRoot = await openRoot(layout.root);
await expect(safeRoot.remove("parent-link/secret.txt")).rejects.toBeTruthy();
await safeRoot.remove("leaf-link.txt");
await expect(fsp.lstat(path.join(layout.root, "leaf-link.txt"))).rejects.toMatchObject({ code: "ENOENT" });
await expectNoOutsideWrite(layout);
});
it("keeps encoded, backslash, Windows, and UNC-looking write payloads literal and inside root", async () => {
const layout = await makeTempLayout("fs-safe-write-encoded-literal");
const safeRoot = await openRoot(layout.root);
const literalWritePayloads = process.platform === "win32"
? LITERAL_SUSPICIOUS_WRITE_PAYLOADS
: [...LITERAL_SUSPICIOUS_WRITE_PAYLOADS, ...POSIX_LITERAL_SUSPICIOUS_WRITE_PAYLOADS];
for (const payload of literalWritePayloads) {
await safeRoot.write(payload, "literal");
await expect(safeRoot.readText(payload), `read literal ${payload}`).resolves.toBe("literal");
}
if (process.platform === "win32") {
for (const payload of POSIX_LITERAL_SUSPICIOUS_WRITE_PAYLOADS) {
await expect(safeRoot.write(payload, "rejected"), `write safely rejects ${payload}`).rejects.toBeTruthy();
}
}
for (const payload of SAFE_REJECTED_SUSPICIOUS_WRITE_PAYLOADS) {
await expect(safeRoot.write(payload, "rejected"), `write safely rejects ${payload}`).rejects.toBeTruthy();
}
for (const payload of SAFE_REJECTED_SUSPICIOUS_DIRECTORY_PAYLOADS) {
await expect(safeRoot.mkdir(payload), `mkdir safely rejects ${payload}`).rejects.toBeTruthy();
}
if (process.platform === "win32") {
for (const payload of WINDOWS_REJECTED_SUSPICIOUS_DIRECTORY_PAYLOADS) {
await expect(safeRoot.mkdir(payload), `mkdir safely rejects ${payload}`).rejects.toBeTruthy();
}
} else {
for (const payload of WINDOWS_REJECTED_SUSPICIOUS_DIRECTORY_PAYLOADS) {
await safeRoot.mkdir(payload);
await expect(fsp.stat(path.join(layout.root, payload)), `created literal ${payload}`).resolves.toSatisfy((stat) =>
stat.isDirectory()
);
}
}
for (const payload of LITERAL_SUSPICIOUS_DIRECTORY_PAYLOADS) {
await safeRoot.mkdir(payload);
await expect(safeRoot.list(payload), `list literal ${payload}`).resolves.toBeInstanceOf(Array);
}
await expectNoOutsideWrite(layout);
});
});