feat: vendor permission system source

This commit is contained in:
云服务部-叶林立
2026-08-19 14:35:19 +08:00
parent 198584daf8
commit 410c50a3e5
809 changed files with 157793 additions and 139 deletions
@@ -0,0 +1,120 @@
import { beforeEach, describe, expect, test, vi } from "vitest";
const realpathSync = vi.hoisted(() => vi.fn<(path: string) => string>());
vi.mock("node:fs", () => ({
realpathSync,
default: { realpathSync },
}));
import { canonicalizePath } from "#src/path/canonicalize-path";
import { posixPathFlavor, win32PathFlavor } from "#src/path/path-flavor";
function enoent(p: string): NodeJS.ErrnoException {
return Object.assign(new Error(`ENOENT: no such file or directory '${p}'`), {
code: "ENOENT",
});
}
describe("canonicalizePath", () => {
beforeEach(() => {
realpathSync.mockReset();
});
test("returns empty string for empty input", () => {
expect(canonicalizePath("", posixPathFlavor)).toBe("");
});
test("returns realpathSync result when path exists", () => {
realpathSync.mockReturnValueOnce("/real/projects/app");
expect(canonicalizePath("/projects/link", posixPathFlavor)).toBe(
"/real/projects/app",
);
});
test("re-appends a non-existent leaf to the canonical parent", () => {
realpathSync
.mockImplementationOnce(() => {
throw enoent("/projects/app/new-file.ts");
})
.mockReturnValueOnce("/canonical/app");
expect(canonicalizePath("/projects/app/new-file.ts", posixPathFlavor)).toBe(
"/canonical/app/new-file.ts",
);
});
test("walks up multiple levels for a deeply non-existent path", () => {
realpathSync
.mockImplementationOnce(() => {
throw enoent("/projects/app/src/new-file.ts");
})
.mockImplementationOnce(() => {
throw enoent("/projects/app/src");
})
.mockImplementationOnce(() => {
throw enoent("/projects/app");
})
.mockReturnValueOnce("/canonical/projects");
expect(
canonicalizePath("/projects/app/src/new-file.ts", posixPathFlavor),
).toBe("/canonical/projects/app/src/new-file.ts");
});
test("returns input unchanged when walk reaches filesystem root (all ENOENT)", () => {
realpathSync.mockImplementation(() => {
throw enoent("");
});
expect(canonicalizePath("/nonexistent/path/file.ts", posixPathFlavor)).toBe(
"/nonexistent/path/file.ts",
);
});
test("returns input unchanged on ELOOP (symlink loop)", () => {
realpathSync.mockImplementation(() => {
throw Object.assign(new Error("ELOOP"), { code: "ELOOP" });
});
expect(canonicalizePath("/some/looping/path", posixPathFlavor)).toBe(
"/some/looping/path",
);
});
test("returns input unchanged on EACCES (permission denied)", () => {
realpathSync.mockImplementation(() => {
throw Object.assign(new Error("EACCES"), { code: "EACCES" });
});
expect(canonicalizePath("/restricted/path", posixPathFlavor)).toBe(
"/restricted/path",
);
});
test("handles ENOTDIR by walking up (like ENOENT)", () => {
realpathSync
.mockImplementationOnce(() => {
throw Object.assign(new Error("ENOTDIR"), { code: "ENOTDIR" });
})
.mockReturnValueOnce("/real/parent");
expect(canonicalizePath("/real/parent/not-a-dir", posixPathFlavor)).toBe(
"/real/parent/not-a-dir",
);
});
// ── injected platform flavor (win32-separator splitting) ──────────────
test("win32: splits and rejoins on the backslash separator", () => {
realpathSync
.mockImplementationOnce(() => {
throw enoent("C:\\projects\\link\\file.ts");
})
.mockReturnValueOnce("C:\\real\\app");
expect(
canonicalizePath("C:\\projects\\link\\file.ts", win32PathFlavor),
).toBe("C:\\real\\app\\file.ts");
});
test("win32: resolves an existing path via realpathSync", () => {
realpathSync.mockReturnValueOnce("C:\\real\\app");
expect(canonicalizePath("C:\\projects\\link", win32PathFlavor)).toBe(
"C:\\real\\app",
);
});
});
@@ -0,0 +1,117 @@
import { describe, expect, test, vi } from "vitest";
// Mock node:fs so the discriminator test can assert realpathSync is untouched.
const realpathSync = vi.hoisted(() =>
vi.fn<(path: string) => string>((p) => p),
);
vi.mock("node:fs", () => ({
realpathSync,
default: { realpathSync },
}));
import { isPathOutsideWorkingDirectory } from "#src/path/path-containment";
import { posixPathFlavor } from "#src/path/path-flavor";
describe("isPathOutsideWorkingDirectory", () => {
// Pure geometry over already-canonical operands: the caller (PathNormalizer)
// prepares the canonical path and cwd; this predicate never canonicalizes.
const canonicalCwd = "/projects/my-app";
test("does not canonicalize its operands (no filesystem access)", () => {
realpathSync.mockClear();
isPathOutsideWorkingDirectory(
"/projects/my-app/src",
canonicalCwd,
posixPathFlavor,
);
expect(realpathSync).not.toHaveBeenCalled();
});
test("returns false when path is inside cwd", () => {
expect(
isPathOutsideWorkingDirectory(
"/projects/my-app/src",
canonicalCwd,
posixPathFlavor,
),
).toBe(false);
});
test("returns false when path equals cwd", () => {
expect(
isPathOutsideWorkingDirectory(
"/projects/my-app",
canonicalCwd,
posixPathFlavor,
),
).toBe(false);
});
test("returns true when path is outside cwd", () => {
expect(
isPathOutsideWorkingDirectory(
"/etc/passwd",
canonicalCwd,
posixPathFlavor,
),
).toBe(true);
});
test("returns false for an empty canonical path", () => {
expect(
isPathOutsideWorkingDirectory("", canonicalCwd, posixPathFlavor),
).toBe(false);
});
test("returns false for an empty canonical cwd", () => {
expect(
isPathOutsideWorkingDirectory("/etc/passwd", "", posixPathFlavor),
).toBe(false);
});
test("returns false for /dev/null (safe system path)", () => {
expect(
isPathOutsideWorkingDirectory("/dev/null", canonicalCwd, posixPathFlavor),
).toBe(false);
});
test("returns false for /dev/stdin (safe system path)", () => {
expect(
isPathOutsideWorkingDirectory(
"/dev/stdin",
canonicalCwd,
posixPathFlavor,
),
).toBe(false);
});
test("returns false for /dev/stdout (safe system path)", () => {
expect(
isPathOutsideWorkingDirectory(
"/dev/stdout",
canonicalCwd,
posixPathFlavor,
),
).toBe(false);
});
test("returns false for /dev/stderr (safe system path)", () => {
expect(
isPathOutsideWorkingDirectory(
"/dev/stderr",
canonicalCwd,
posixPathFlavor,
),
).toBe(false);
});
test("returns true for /dev/null/subdir (not a safe path)", () => {
expect(
isPathOutsideWorkingDirectory(
"/dev/null/subdir",
canonicalCwd,
posixPathFlavor,
),
).toBe(true);
});
});
@@ -0,0 +1,151 @@
import { posix as posixPath, win32 as winPath } from "node:path";
import { describe, expect, it } from "vitest";
import {
pathFlavorForPlatform,
posixPathFlavor,
win32PathFlavor,
} from "#src/path/path-flavor";
describe("win32PathFlavor", () => {
it("exposes the win32 path implementation", () => {
expect(win32PathFlavor.impl).toBe(winPath);
});
it("carries the win32 case/separator match options", () => {
expect(win32PathFlavor.matchOptions).toEqual({
caseInsensitive: true,
windowsSeparators: true,
});
});
it("folds to lower case", () => {
expect(win32PathFlavor.fold("C:\\Foo\\Bar")).toBe("c:\\foo\\bar");
});
it("resolves, normalizes, and folds a comparable value against a base", () => {
expect(win32PathFlavor.comparable("Foo/Bar", "C:\\base")).toBe(
"c:\\base\\foo\\bar",
);
});
it("decides containment with win32 (case-folding) geometry", () => {
expect(win32PathFlavor.isWithin("C:\\base\\sub", "C:\\base")).toBe(true);
expect(win32PathFlavor.isWithin("C:\\base", "C:\\base")).toBe(true);
expect(win32PathFlavor.isWithin("C:\\other", "C:\\base")).toBe(false);
});
it("folds case for a case-different descendant", () => {
expect(
win32PathFlavor.isWithin(
"c:\\users\\foo\\dir\\sub\\x.md",
"C:\\Users\\Foo\\dir",
),
).toBe(true);
});
it("folds case when path equals directory in a different case", () => {
expect(
win32PathFlavor.isWithin(
"c:\\users\\foo\\dir\\sub",
"C:\\USERS\\foo\\DIR",
),
).toBe(true);
});
it("rejects a win32 sibling directory", () => {
expect(
win32PathFlavor.isWithin("C:\\Users\\Foo\\other", "C:\\Users\\Foo\\dir"),
).toBe(false);
});
it("recognizes either separator as a path separator", () => {
expect(win32PathFlavor.hasPathSeparator("dir/file")).toBe(true);
expect(win32PathFlavor.hasPathSeparator("dir\\file")).toBe(true);
expect(win32PathFlavor.hasPathSeparator("plain")).toBe(false);
});
it("classifies bash tokens with MSYS semantics", () => {
expect(win32PathFlavor.bashTokenShape("/dev/null")).toEqual({
kind: "device",
});
expect(win32PathFlavor.bashTokenShape("/c/Users/x")).toEqual({
kind: "drive-mount",
windowsPath: "C:\\Users\\x",
});
expect(win32PathFlavor.bashTokenShape("/tmp/x")).toEqual({
kind: "posix-absolute",
});
expect(win32PathFlavor.bashTokenShape("relative/x")).toEqual({
kind: "plain",
});
});
});
describe("posixPathFlavor", () => {
it("exposes the posix path implementation", () => {
expect(posixPathFlavor.impl).toBe(posixPath);
});
it("carries no win32 match options", () => {
expect(posixPathFlavor.matchOptions).toBeUndefined();
});
it("does not fold case", () => {
expect(posixPathFlavor.fold("/Foo/Bar")).toBe("/Foo/Bar");
});
it("resolves and normalizes a comparable value without folding", () => {
expect(posixPathFlavor.comparable("Foo/Bar", "/base")).toBe(
"/base/Foo/Bar",
);
});
it("decides containment with posix geometry", () => {
expect(posixPathFlavor.isWithin("/base/sub", "/base")).toBe(true);
expect(posixPathFlavor.isWithin("/base", "/base")).toBe(true);
expect(posixPathFlavor.isWithin("/a/b/c/d/e", "/a/b")).toBe(true);
expect(posixPathFlavor.isWithin("/other", "/base")).toBe(false);
});
it("rejects a sibling directory sharing a name prefix", () => {
expect(posixPathFlavor.isWithin("/a/bc", "/a/b")).toBe(false);
});
it("stays case-sensitive", () => {
expect(posixPathFlavor.isWithin("/a/B/c", "/a/b")).toBe(false);
});
it("returns false for empty operands", () => {
expect(posixPathFlavor.isWithin("", "/a/b")).toBe(false);
expect(posixPathFlavor.isWithin("/a/b", "")).toBe(false);
});
it("recognizes only the forward slash as a path separator", () => {
expect(posixPathFlavor.hasPathSeparator("dir/file")).toBe(true);
expect(posixPathFlavor.hasPathSeparator("dir\\file")).toBe(false);
expect(posixPathFlavor.hasPathSeparator("plain")).toBe(false);
});
it("treats every bash token as an ordinary path", () => {
expect(posixPathFlavor.bashTokenShape("/dev/null")).toEqual({
kind: "plain",
});
expect(posixPathFlavor.bashTokenShape("/c/Users/x")).toEqual({
kind: "plain",
});
expect(posixPathFlavor.bashTokenShape("/tmp/x")).toEqual({ kind: "plain" });
});
});
describe("pathFlavorForPlatform", () => {
it("selects the win32 flavor for win32", () => {
expect(pathFlavorForPlatform("win32")).toBe(win32PathFlavor);
});
it("selects the posix flavor for every other platform", () => {
expect(pathFlavorForPlatform("linux")).toBe(posixPathFlavor);
expect(pathFlavorForPlatform("darwin")).toBe(posixPathFlavor);
});
});
@@ -0,0 +1,439 @@
import { homedir } from "node:os";
import { join } from "node:path";
import { beforeEach, describe, expect, test, vi } from "vitest";
// Hoisted stub so the vi.mock factory can reference it.
const { mockSpawnSync } = vi.hoisted(() => ({
mockSpawnSync: vi.fn(),
}));
// Mock node:child_process so tests that exercise the subprocess fallback path
// don't actually invoke npm. Default: subprocess fails (non-zero exit), so
// tests focused on the walk-up strategy continue to expect null.
vi.mock("node:child_process", () => ({
spawnSync: mockSpawnSync,
default: { spawnSync: mockSpawnSync },
}));
import { discoverGlobalNodeModulesRoot } from "#src/node-modules-discovery";
import { posixPathFlavor, win32PathFlavor } from "#src/path/path-flavor";
import { isPiInfrastructureRead } from "#src/path/pi-infrastructure-read";
// ── discoverGlobalNodeModulesRoot ──────────────────────────────────────────
describe("discoverGlobalNodeModulesRoot", () => {
beforeEach(() => {
// Default: subprocess fails, so walk-up-focused tests see null for URLs
// with no node_modules ancestor.
mockSpawnSync.mockReset();
mockSpawnSync.mockReturnValue({ status: 1, stdout: "" });
});
test("returns the node_modules dir when the file is inside one", () => {
const url =
"file:///opt/homebrew/lib/node_modules/pi-permission-system/dist/external-directory.js";
expect(discoverGlobalNodeModulesRoot(url)).toBe(
"/opt/homebrew/lib/node_modules",
);
});
test("returns node_modules for a deeply nested file", () => {
const url =
"file:///home/user/.nvm/versions/node/v20/lib/node_modules/pi-permission-system/src/external-directory.js";
expect(discoverGlobalNodeModulesRoot(url)).toBe(
"/home/user/.nvm/versions/node/v20/lib/node_modules",
);
});
test("returns node_modules for a bun global install path", () => {
const url =
"file:///home/user/.bun/install/global/node_modules/pi-permission-system/dist/external-directory.js";
expect(discoverGlobalNodeModulesRoot(url)).toBe(
"/home/user/.bun/install/global/node_modules",
);
});
test("returns the innermost (closest-to-file) node_modules ancestor", () => {
// The walk-up algorithm stops at the first node_modules dir it encounters,
// which is the innermost one when the file is inside a nested install.
// In practice this never happens for a real global install — the extension
// is always directly at <global_root>/node_modules/pi-permission-system/…
const url =
"file:///opt/lib/node_modules/some-pkg/node_modules/pi-permission-system/dist/index.js";
expect(discoverGlobalNodeModulesRoot(url)).toBe(
"/opt/lib/node_modules/some-pkg/node_modules",
);
});
test("returns null when the file is not inside any node_modules directory", () => {
const url =
"file:///home/user/development/pi-permission-system/dist/external-directory.js";
expect(discoverGlobalNodeModulesRoot(url)).toBeNull();
});
test("returns null for a root-level file", () => {
const url = "file:///external-directory.js";
expect(discoverGlobalNodeModulesRoot(url)).toBeNull();
});
test("returns null for an invalid URL", () => {
expect(discoverGlobalNodeModulesRoot("not-a-url")).toBeNull();
});
test("works with the real import.meta.url of this extension (smoke test)", () => {
// The extension IS installed inside a node_modules tree when running in CI
// or global install. In a local dev checkout the result may be null — that's
// the documented graceful-degradation path.
const result = discoverGlobalNodeModulesRoot();
expect(result === null || result.endsWith("node_modules")).toBe(true);
});
test("the discovered path includes the pi-permission-system package directory", () => {
const url =
"file:///opt/homebrew/lib/node_modules/pi-permission-system/dist/external-directory.js";
const root = discoverGlobalNodeModulesRoot(url);
expect(root).not.toBeNull();
expect(join(root!, "pi-permission-system")).toBe(
"/opt/homebrew/lib/node_modules/pi-permission-system",
);
});
});
// ── isPiInfrastructureRead ─────────────────────────────────────────────────
const INFRA_DIRS = [
"/home/user/.pi/agent",
"/home/user/.pi/agent/git",
"/opt/homebrew/lib/node_modules",
];
const CWD = "/home/user/project";
describe("isPiInfrastructureRead", () => {
// ── read tools allowed for infra paths ──────────────────────────────────
test("allows 'read' tool for a file inside agentDir", () => {
expect(
isPiInfrastructureRead(
"read",
"/home/user/.pi/agent/extensions/pi-permission-system/config.json",
INFRA_DIRS,
CWD,
posixPathFlavor,
),
).toBe(true);
});
test("allows 'find' tool for a path inside node_modules infra dir", () => {
expect(
isPiInfrastructureRead(
"find",
"/opt/homebrew/lib/node_modules/pi-ask-user/skills",
INFRA_DIRS,
CWD,
posixPathFlavor,
),
).toBe(true);
});
test("allows 'grep' tool for a path inside agentDir/git", () => {
expect(
isPiInfrastructureRead(
"grep",
"/home/user/.pi/agent/git/some-package/README.md",
INFRA_DIRS,
CWD,
posixPathFlavor,
),
).toBe(true);
});
test("allows 'ls' tool for a path inside node_modules infra dir", () => {
expect(
isPiInfrastructureRead(
"ls",
"/opt/homebrew/lib/node_modules/pi-permission-system",
INFRA_DIRS,
CWD,
posixPathFlavor,
),
).toBe(true);
});
// ── write tools never allowed even for infra paths ───────────────────────
test("blocks 'write' tool for a file inside agentDir", () => {
expect(
isPiInfrastructureRead(
"write",
"/home/user/.pi/agent/extensions/pi-permission-system/config.json",
INFRA_DIRS,
CWD,
posixPathFlavor,
),
).toBe(false);
});
test("blocks 'edit' tool for a file inside node_modules", () => {
expect(
isPiInfrastructureRead(
"edit",
"/opt/homebrew/lib/node_modules/pi-ask-user/skills/ask-user/SKILL.md",
INFRA_DIRS,
CWD,
posixPathFlavor,
),
).toBe(false);
});
test("blocks 'bash' tool regardless of path", () => {
expect(
isPiInfrastructureRead(
"bash",
"/opt/homebrew/lib/node_modules/pi-ask-user/SKILL.md",
INFRA_DIRS,
CWD,
posixPathFlavor,
),
).toBe(false);
});
// ── non-infra paths not allowed ──────────────────────────────────────────
test("does not allow 'read' for a path outside all infra dirs", () => {
expect(
isPiInfrastructureRead(
"read",
"/etc/passwd",
INFRA_DIRS,
CWD,
posixPathFlavor,
),
).toBe(false);
});
test("does not allow 'read' for a path only partially matching an infra dir prefix", () => {
// /home/user/.pi/agent-other should not match /home/user/.pi/agent
expect(
isPiInfrastructureRead(
"read",
"/home/user/.pi/agent-other/config.json",
INFRA_DIRS,
CWD,
posixPathFlavor,
),
).toBe(false);
});
// ── project-local Pi packages (.pi/npm, .pi/git) ─────────────────────────
test("allows 'read' for a path inside project-local .pi/npm/", () => {
expect(
isPiInfrastructureRead(
"read",
`${CWD}/.pi/npm/node_modules/some-skill/SKILL.md`,
INFRA_DIRS,
CWD,
posixPathFlavor,
),
).toBe(true);
});
test("allows 'read' for a path inside project-local .pi/git/", () => {
expect(
isPiInfrastructureRead(
"read",
`${CWD}/.pi/git/github.com/org/skill-repo/SKILL.md`,
INFRA_DIRS,
CWD,
posixPathFlavor,
),
).toBe(true);
});
test("blocks 'write' for a path inside project-local .pi/npm/", () => {
expect(
isPiInfrastructureRead(
"write",
`${CWD}/.pi/npm/node_modules/some-skill/SKILL.md`,
INFRA_DIRS,
CWD,
posixPathFlavor,
),
).toBe(false);
});
// ── empty / edge cases ───────────────────────────────────────────────────
test("returns false when infrastructureDirs is empty and path is not project-local", () => {
expect(
isPiInfrastructureRead("read", "/etc/passwd", [], CWD, posixPathFlavor),
).toBe(false);
});
test("returns false when infrastructureDirs is empty but path IS project-local .pi/npm", () => {
// Project-local paths are checked separately from the dirs array.
expect(
isPiInfrastructureRead(
"read",
`${CWD}/.pi/npm/node_modules/x/SKILL.md`,
[],
CWD,
posixPathFlavor,
),
).toBe(true);
});
});
// ── isPiInfrastructureRead — glob patterns ─────────────────────────────────
describe("isPiInfrastructureRead with glob patterns", () => {
test("glob entry matches a versioned nested path", () => {
expect(
isPiInfrastructureRead(
"read",
"/opt/homebrew/Cellar/pi-coding-agent/0.74.0/libexec/lib/node_modules/@earendil-works/pi-coding-agent/SKILL.md",
["/opt/homebrew/*/@earendil-works/pi-coding-agent/*"],
CWD,
posixPathFlavor,
),
).toBe(true);
});
test("** behaves the same as * (matches across path separators)", () => {
expect(
isPiInfrastructureRead(
"read",
"/opt/homebrew/Cellar/pi-coding-agent/0.74.0/libexec/lib/node_modules/@earendil-works/pi-coding-agent/SKILL.md",
["/opt/homebrew/**/@earendil-works/pi-coding-agent/**"],
CWD,
posixPathFlavor,
),
).toBe(true);
});
test("glob entry does not match an unrelated path", () => {
expect(
isPiInfrastructureRead(
"read",
"/etc/passwd",
["/opt/homebrew/*/@earendil-works/pi-coding-agent/*"],
CWD,
posixPathFlavor,
),
).toBe(false);
});
test("? matches exactly one character", () => {
expect(
isPiInfrastructureRead(
"read",
"/opt/homebrew/X/file.md",
["/opt/homebrew/?/file.md"],
CWD,
posixPathFlavor,
),
).toBe(true);
});
test("? does not match multiple characters", () => {
expect(
isPiInfrastructureRead(
"read",
"/opt/homebrew/abc/file.md",
["/opt/homebrew/?/file.md"],
CWD,
posixPathFlavor,
),
).toBe(false);
});
test("mixed array of plain dirs and glob patterns — both branches work", () => {
const dirs = [
"/home/user/.pi/agent",
"/opt/homebrew/*/@earendil-works/pi-coding-agent/*",
];
expect(
isPiInfrastructureRead(
"read",
"/home/user/.pi/agent/config.json",
dirs,
CWD,
posixPathFlavor,
),
).toBe(true);
expect(
isPiInfrastructureRead(
"read",
"/opt/homebrew/Cellar/pi-coding-agent/0.74.0/libexec/lib/node_modules/@earendil-works/pi-coding-agent/SKILL.md",
dirs,
CWD,
posixPathFlavor,
),
).toBe(true);
});
test("plain entry with ~ prefix matches after home expansion", () => {
const home = homedir();
expect(
isPiInfrastructureRead(
"read",
`${home}/.pi/agent/config.json`,
["~/.pi/agent"],
CWD,
posixPathFlavor,
),
).toBe(true);
});
test("write tool with a glob-matching path is still rejected", () => {
expect(
isPiInfrastructureRead(
"write",
"/opt/homebrew/Cellar/pi-coding-agent/0.74.0/libexec/lib/node_modules/@earendil-works/pi-coding-agent/SKILL.md",
["/opt/homebrew/**/@earendil-works/pi-coding-agent/**"],
CWD,
posixPathFlavor,
),
).toBe(false);
});
});
// ── isPiInfrastructureRead — win32 case-insensitive matching ───────────────
describe("isPiInfrastructureRead on win32", () => {
test("plain infra dir matches a case-different path", () => {
expect(
isPiInfrastructureRead(
"read",
"c:\\users\\foo\\.pi\\agent\\config.json",
["C:\\Users\\Foo\\.pi\\agent"],
"C:\\proj",
win32PathFlavor,
),
).toBe(true);
});
test("glob infra dir matches case-insensitively", () => {
expect(
isPiInfrastructureRead(
"read",
"c:\\users\\foo\\npm\\node_modules\\@earendil-works\\pi-coding-agent\\skill.md",
["C:\\Users\\Foo\\**\\pi-coding-agent\\**"],
"C:\\proj",
win32PathFlavor,
),
).toBe(true);
});
test("rejects a path outside every infra dir", () => {
expect(
isPiInfrastructureRead(
"read",
"c:\\windows\\system32\\drivers\\etc\\hosts",
["C:\\Users\\Foo\\.pi\\agent"],
"C:\\proj",
win32PathFlavor,
),
).toBe(false);
});
});