refactor(core): dedupe infra, media, pairing, and plugin helpers

This commit is contained in:
Peter Steinberger
2026-03-02 21:31:18 +00:00
parent 91dd89313a
commit 34daed1d1e
11 changed files with 301 additions and 340 deletions

View File

@@ -24,6 +24,81 @@ afterEach(async () => {
await tempDirs.cleanup();
});
async function expectWriteOpenRaceIsBlocked(params: {
slotPath: string;
outsideDir: string;
runWrite: () => Promise<void>;
}): Promise<void> {
await withRealpathSymlinkRebindRace({
shouldFlip: (realpathInput) => realpathInput.endsWith(path.join("slot", "target.txt")),
symlinkPath: params.slotPath,
symlinkTarget: params.outsideDir,
timing: "before-realpath",
run: async () => {
await expect(params.runWrite()).rejects.toMatchObject({ code: "outside-workspace" });
},
});
}
async function expectSymlinkWriteRaceRejectsOutside(params: {
slotPath: string;
outsideDir: string;
runWrite: (relativePath: string) => Promise<void>;
}): Promise<void> {
const relativePath = path.join("slot", "target.txt");
await expectWriteOpenRaceIsBlocked({
slotPath: params.slotPath,
outsideDir: params.outsideDir,
runWrite: async () => await params.runWrite(relativePath),
});
}
async function withOutsideHardlinkAlias(params: {
aliasPath: string;
run: (outsideFile: string) => Promise<void>;
}): Promise<void> {
const outside = await tempDirs.make("openclaw-fs-safe-outside-");
const outsideFile = path.join(outside, "outside.txt");
await fs.writeFile(outsideFile, "outside");
try {
try {
await fs.link(outsideFile, params.aliasPath);
} catch (err) {
if ((err as NodeJS.ErrnoException).code === "EXDEV") {
return;
}
throw err;
}
await params.run(outsideFile);
} finally {
await fs.rm(params.aliasPath, { force: true });
await fs.rm(outsideFile, { force: true });
}
}
async function setupSymlinkWriteRaceFixture(options?: { seedInsideTarget?: boolean }): Promise<{
root: string;
outside: string;
slot: string;
outsideTarget: string;
}> {
const root = await tempDirs.make("openclaw-fs-safe-root-");
const inside = path.join(root, "inside");
const outside = await tempDirs.make("openclaw-fs-safe-outside-");
await fs.mkdir(inside, { recursive: true });
if (options?.seedInsideTarget) {
await fs.writeFile(path.join(inside, "target.txt"), "inside");
}
const outsideTarget = path.join(outside, "target.txt");
await fs.writeFile(outsideTarget, "X".repeat(4096));
const slot = path.join(root, "slot");
await createRebindableDirectoryAlias({
aliasPath: slot,
targetPath: inside,
});
return { root, outside, slot, outsideTarget };
}
describe("fs-safe", () => {
it("reads a local file safely", async () => {
const dir = await tempDirs.make("openclaw-fs-safe-");
@@ -147,29 +222,18 @@ describe("fs-safe", () => {
it.runIf(process.platform !== "win32")("blocks hardlink aliases under root", async () => {
const root = await tempDirs.make("openclaw-fs-safe-root-");
const outside = await tempDirs.make("openclaw-fs-safe-outside-");
const outsideFile = path.join(outside, "outside.txt");
const hardlinkPath = path.join(root, "link.txt");
await fs.writeFile(outsideFile, "outside");
try {
try {
await fs.link(outsideFile, hardlinkPath);
} catch (err) {
if ((err as NodeJS.ErrnoException).code === "EXDEV") {
return;
}
throw err;
}
await expect(
openFileWithinRoot({
rootDir: root,
relativePath: "link.txt",
}),
).rejects.toMatchObject({ code: "invalid-path" });
} finally {
await fs.rm(hardlinkPath, { force: true });
await fs.rm(outsideFile, { force: true });
}
await withOutsideHardlinkAlias({
aliasPath: hardlinkPath,
run: async () => {
await expect(
openFileWithinRoot({
rootDir: root,
relativePath: "link.txt",
}),
).rejects.toMatchObject({ code: "invalid-path" });
},
});
});
it("writes a file within root safely", async () => {
@@ -245,99 +309,58 @@ describe("fs-safe", () => {
it.runIf(process.platform !== "win32")("rejects writing through hardlink aliases", async () => {
const root = await tempDirs.make("openclaw-fs-safe-root-");
const outside = await tempDirs.make("openclaw-fs-safe-outside-");
const outsideFile = path.join(outside, "outside.txt");
const hardlinkPath = path.join(root, "alias.txt");
await fs.writeFile(outsideFile, "outside");
try {
try {
await fs.link(outsideFile, hardlinkPath);
} catch (err) {
if ((err as NodeJS.ErrnoException).code === "EXDEV") {
return;
}
throw err;
}
await expect(
writeFileWithinRoot({
rootDir: root,
relativePath: "alias.txt",
data: "pwned",
}),
).rejects.toMatchObject({ code: "invalid-path" });
await expect(fs.readFile(outsideFile, "utf8")).resolves.toBe("outside");
} finally {
await fs.rm(hardlinkPath, { force: true });
await fs.rm(outsideFile, { force: true });
}
});
it("does not truncate out-of-root file when symlink retarget races write open", async () => {
const root = await tempDirs.make("openclaw-fs-safe-root-");
const inside = path.join(root, "inside");
const outside = await tempDirs.make("openclaw-fs-safe-outside-");
await fs.mkdir(inside, { recursive: true });
const insideTarget = path.join(inside, "target.txt");
const outsideTarget = path.join(outside, "target.txt");
await fs.writeFile(insideTarget, "inside");
await fs.writeFile(outsideTarget, "X".repeat(4096));
const slot = path.join(root, "slot");
await createRebindableDirectoryAlias({
aliasPath: slot,
targetPath: inside,
});
await withRealpathSymlinkRebindRace({
shouldFlip: (realpathInput) => realpathInput.endsWith(path.join("slot", "target.txt")),
symlinkPath: slot,
symlinkTarget: outside,
timing: "before-realpath",
run: async () => {
await withOutsideHardlinkAlias({
aliasPath: hardlinkPath,
run: async (outsideFile) => {
await expect(
writeFileWithinRoot({
rootDir: root,
relativePath: path.join("slot", "target.txt"),
data: "new-content",
mkdir: false,
relativePath: "alias.txt",
data: "pwned",
}),
).rejects.toMatchObject({ code: "outside-workspace" });
).rejects.toMatchObject({ code: "invalid-path" });
await expect(fs.readFile(outsideFile, "utf8")).resolves.toBe("outside");
},
});
});
it("does not truncate out-of-root file when symlink retarget races write open", async () => {
const { root, outside, slot, outsideTarget } = await setupSymlinkWriteRaceFixture({
seedInsideTarget: true,
});
await expectSymlinkWriteRaceRejectsOutside({
slotPath: slot,
outsideDir: outside,
runWrite: async (relativePath) =>
await writeFileWithinRoot({
rootDir: root,
relativePath,
data: "new-content",
mkdir: false,
}),
});
await expect(fs.readFile(outsideTarget, "utf8")).resolves.toBe("X".repeat(4096));
});
it("does not clobber out-of-root file when symlink retarget races write-from-path open", async () => {
const root = await tempDirs.make("openclaw-fs-safe-root-");
const inside = path.join(root, "inside");
const outside = await tempDirs.make("openclaw-fs-safe-outside-");
const { root, outside, slot, outsideTarget } = await setupSymlinkWriteRaceFixture();
const sourceDir = await tempDirs.make("openclaw-fs-safe-source-");
const sourcePath = path.join(sourceDir, "source.txt");
await fs.writeFile(sourcePath, "new-content");
await fs.mkdir(inside, { recursive: true });
const outsideTarget = path.join(outside, "target.txt");
await fs.writeFile(outsideTarget, "X".repeat(4096));
const slot = path.join(root, "slot");
await createRebindableDirectoryAlias({
aliasPath: slot,
targetPath: inside,
});
await withRealpathSymlinkRebindRace({
shouldFlip: (realpathInput) => realpathInput.endsWith(path.join("slot", "target.txt")),
symlinkPath: slot,
symlinkTarget: outside,
timing: "before-realpath",
run: async () => {
await expect(
writeFileFromPathWithinRoot({
rootDir: root,
relativePath: path.join("slot", "target.txt"),
sourcePath,
mkdir: false,
}),
).rejects.toMatchObject({ code: "outside-workspace" });
},
await expectSymlinkWriteRaceRejectsOutside({
slotPath: slot,
outsideDir: outside,
runWrite: async (relativePath) =>
await writeFileFromPathWithinRoot({
rootDir: root,
relativePath,
sourcePath,
mkdir: false,
}),
});
await expect(fs.readFile(outsideTarget, "utf8")).resolves.toBe("X".repeat(4096));