evOo-local/packages/adapters/src/artifacts.test.ts
cynarAI 6c7eed7580 Initial clean evOo-local from f00577b
Fresh history cut from cynarAI/evoo antigravity-handoff/project-timeline
(Voice First + project timeline). Brand docs/titles as evOo; keep @rakazo/*
packages as tech debt. Excludes node_modules, caches, secrets, voice blobs.
2026-09-20 17:15:16 +02:00

46 lines
1.6 KiB
TypeScript

import { mkdtemp, rm, stat, symlink, writeFile } from "node:fs/promises";
import { tmpdir } from "node:os";
import path from "node:path";
import { afterEach, describe, expect, it } from "vitest";
import { LocalArtifactStore } from "./artifacts.js";
const dirs: string[] = [];
const context = { spaceId: "space-1" } as never;
afterEach(async () => {
await Promise.all(dirs.splice(0).map((dir) => rm(dir, { recursive: true, force: true })));
});
describe("LocalArtifactStore", () => {
it("creates artifact files with owner-only permissions", async () => {
const root = await mkdtemp(path.join(tmpdir(), "rakazo-artifacts-"));
dirs.push(root);
const store = new LocalArtifactStore(root);
const stored = await store.put(
{ name: "private.txt", mimeType: "text/plain", bytes: new TextEncoder().encode("private") },
context,
);
const info = await stat(path.join(root, "artifacts", "space-1", stored.id));
expect(info.mode & 0o777).toBe(0o600);
});
it("does not follow a replacement symlink when reading an artifact", async () => {
const root = await mkdtemp(path.join(tmpdir(), "rakazo-artifacts-"));
dirs.push(root);
const store = new LocalArtifactStore(root);
const stored = await store.put(
{ name: "private.txt", mimeType: "text/plain", bytes: new TextEncoder().encode("private") },
context,
);
const file = path.join(root, "artifacts", "space-1", stored.id);
const target = path.join(root, "outside.txt");
await writeFile(target, "outside");
await rm(file);
await symlink(target, file);
await expect(store.get(stored.id, context)).rejects.toThrow();
});
});