/** * 文件路径安全单测(Metis 安全红线:穿越/.git/分隔符/深度)。 */ import { describe, expect, it } from "vitest"; import { validateFilePath, FILE_PATH_MAX_DEPTH, FILE_PATH_MAX_LENGTH } from "../../src/database/filelib/fileService.js"; import { FileLibError } from "../../src/database/filelib/model.js"; describe("validateFilePath · 路径安全", () => { it("正常相对路径通过(含 CJK 与多级)", () => { expect(validateFilePath("a.md")).toBe("a.md"); expect(validateFilePath("docs/讲义/第一课.md")).toBe("docs/讲义/第一课.md"); expect(validateFilePath("a/b/c/d.txt")).toBe("a/b/c/d.txt"); }); it("拒绝穿越:.. 段、绝对路径", () => { expect(() => validateFilePath("../x")).toThrowError(FileLibError); expect(() => validateFilePath("a/../../x")).toThrowError(FileLibError); expect(() => validateFilePath("/etc/passwd")).toThrowError(FileLibError); }); it("拒绝 .git 段与点段", () => { expect(() => validateFilePath(".git")).toThrowError(FileLibError); expect(() => validateFilePath("a/.git/config")).toThrowError(FileLibError); expect(() => validateFilePath("./a.md")).toThrowError(FileLibError); }); it("拒绝反斜杠、控制字符、空段(双斜杠/尾斜杠)", () => { expect(() => validateFilePath("a\\b.md")).toThrowError(FileLibError); expect(() => validateFilePath("a\nb.md")).toThrowError(FileLibError); expect(() => validateFilePath("a//b.md")).toThrowError(FileLibError); expect(() => validateFilePath("a/b/")).toThrowError(FileLibError); }); it("拒绝空路径、超长、超深", () => { expect(() => validateFilePath("")).toThrowError(FileLibError); expect(() => validateFilePath("a".repeat(FILE_PATH_MAX_LENGTH + 1))).toThrowError(FileLibError); expect(() => validateFilePath(Array(FILE_PATH_MAX_DEPTH + 1).fill("d").join("/"))).toThrowError(FileLibError); expect(validateFilePath(Array(FILE_PATH_MAX_DEPTH).fill("d").join("/"))).toContain("d/"); }); });