Files
PaperClipAI/server/src/__tests__/work-folder-agent-import.test.ts
T
DottaandPaperclip 23407236b4 Preserve sandbox work through provider launches and failed saves
Resume retained ephemeral leases, pin managed-agent imports against link replacement, carry scoped home settings through native provider boundaries, and keep file transfer arguments below Linux limits. Restrict acceptance exclusions to the engines explicitly deferred by the user.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-09-07 13:22:36 -05:00

35 lines
2.7 KiB
TypeScript

import fs from "node:fs/promises";
import os from "node:os";
import path from "node:path";
import { afterEach, expect, it } from "vitest";
import { managedAgentFiles } from "../services/work-folder-agent-import.js";
const roots: string[] = [];
afterEach(async () => { for (const root of roots.splice(0)) await fs.rm(root, { recursive: true, force: true }); });
async function fixture() { const root = await fs.realpath(await fs.mkdtemp(path.join(os.tmpdir(), "agent-import-"))); roots.push(root); return root; }
async function collect(root: string) { const results: Array<{ path: string; executable: boolean; text: string }> = [];
for await (const entry of managedAgentFiles(root)) { const chunks: Buffer[] = [];
if (entry.body) for await (const chunk of entry.body) chunks.push(Buffer.from(chunk));
results.push({ path: entry.path, executable: entry.executable, text: Buffer.concat(chunks).toString() });
} return results; }
it("imports nested empty and executable files while excluding credential homes", async () => {
const root = await fixture(); await fs.mkdir(path.join(root, "notes")); await fs.writeFile(path.join(root, "notes/run.sh"), "", { mode: 0o700 });
await fs.mkdir(path.join(root, ".codex")); await fs.writeFile(path.join(root, ".codex/auth.json"), "private");
expect(await collect(root)).toEqual([{ path: "notes", executable: false, text: "" }, { path: "notes/run.sh", executable: true, text: "" }]);
expect(await collect(path.join(root, "absent"))).toEqual([]);
});
it("rejects symlink and hard-link imports", async () => {
const root = await fixture(); const other = await fixture(); await fs.writeFile(path.join(other, "private"), "private");
await fs.symlink(path.join(other, "private"), path.join(root, "linked")); await expect(collect(root)).rejects.toThrow();
await fs.unlink(path.join(root, "linked")); await fs.link(path.join(other, "private"), path.join(root, "linked"));
await expect(collect(root)).rejects.toThrow("hard links");
});
it.skipIf(process.platform !== "linux")("keeps an admitted parent pinned when replaced by a symlink", async () => {
const root = await fixture(); const other = await fixture(); await fs.mkdir(path.join(root, "notes"));
await fs.writeFile(path.join(root, "notes/file"), "original"); await fs.writeFile(path.join(other, "file"), "private");
const iterator = managedAgentFiles(root); expect((await iterator.next()).value?.path).toBe("notes");
await fs.rename(path.join(root, "notes"), path.join(root, "moved")); await fs.symlink(other, path.join(root, "notes"));
const file = (await iterator.next()).value!; const chunks: Buffer[] = [];
for await (const chunk of file.body!) chunks.push(Buffer.from(chunk));
expect(Buffer.concat(chunks).toString()).toBe("original"); await iterator.return(undefined);
});