63 lines
1.6 KiB
TypeScript
63 lines
1.6 KiB
TypeScript
import { describe, expect, test } from "bun:test";
|
|
import { resolve } from "node:path";
|
|
import { buildEditorCommand, resolveEditorFile } from "../../src/server/editor.ts";
|
|
|
|
describe("open editor security", () => {
|
|
const projectRoot = resolve("project");
|
|
const pageFile = resolve(projectRoot, "app/pages/index.wrn");
|
|
|
|
test("resolves project files", () => {
|
|
expect(resolveEditorFile(projectRoot, "app/pages/index.wrn")).toBe(pageFile);
|
|
});
|
|
|
|
test("rejects traversal outside root", () => {
|
|
expect(() => resolveEditorFile(projectRoot, "../secret.txt")).toThrow(
|
|
"Source file is outside the configured project root.",
|
|
);
|
|
});
|
|
|
|
test("builds argument array without shell", () => {
|
|
expect(
|
|
buildEditorCommand(
|
|
{
|
|
file: "app/pages/index.wrn",
|
|
line: 8,
|
|
column: 2,
|
|
},
|
|
{
|
|
root: projectRoot,
|
|
editor: "code",
|
|
},
|
|
),
|
|
).toEqual(["code", "--goto", `${pageFile}:8:2`]);
|
|
});
|
|
|
|
test("rejects null bytes", () => {
|
|
expect(() => resolveEditorFile(projectRoot, "app/pages/index.wrn\0.txt")).toThrow(
|
|
"Invalid source file path.",
|
|
);
|
|
});
|
|
|
|
test("rejects remote URLs", () => {
|
|
expect(() => resolveEditorFile(projectRoot, "https://example.com/file.wrn")).toThrow(
|
|
"Invalid source file path.",
|
|
);
|
|
});
|
|
|
|
test("normalizes invalid line and column values", () => {
|
|
expect(
|
|
buildEditorCommand(
|
|
{
|
|
file: "app/pages/index.wrn",
|
|
line: -10,
|
|
column: 0,
|
|
},
|
|
{
|
|
root: projectRoot,
|
|
editor: "code",
|
|
},
|
|
),
|
|
).toEqual(["code", "--goto", `${pageFile}:1:1`]);
|
|
});
|
|
});
|