mirror of
https://github.com/morluto/rea
synced 2026-10-26 14:25:49 -04:00
b5e98915c6
Remove REA permission grants, scope ceilings, approval confirmations, and inert settings. Preserve selected local evidence, accept caller-chosen commands and paths, and report actual runtime failures. Harden provider results, schema serialization, snapshot evidence binding, archive paths, source maps, native screenshots, managed EH parsing, and cancellation cleanup. Regenerate tool metadata and document direct invocation. BREAKING CHANGE: Removed permission configuration and policy commands, approval fields, filesystem scope inputs, and fixed confirmation options. Process capture inherits the host environment and accepts command names; callers must refresh tool schemas and migrate removed fields.
203 lines
6.5 KiB
TypeScript
203 lines
6.5 KiB
TypeScript
import { mkdir, symlink, writeFile } from "node:fs/promises";
|
|
import { tmpdir } from "node:os";
|
|
import { join } from "node:path";
|
|
import { describe, expect, it } from "vitest";
|
|
|
|
import { createTestTempDirectory } from "../../fixtures/temporaryDirectory.js";
|
|
|
|
import { readReferenceSource } from "../../../src/reference/ReferenceSourceReader.js";
|
|
|
|
describe("readReferenceSource entries", () => {
|
|
it("returns explicit entries in canonical code-point path order", async () => {
|
|
const root = await createTestTempDirectory("rea-reference-");
|
|
await mkdir(join(root, "nested"));
|
|
await writeFile(join(root, "z.js"), "z");
|
|
await writeFile(join(root, "a.js"), "a");
|
|
await writeFile(join(root, "nested", "b.js"), "b");
|
|
await writeFile(join(root, "\u{e000}"), "p");
|
|
await writeFile(join(root, "\u{10000}"), "a");
|
|
|
|
const result = await readReferenceSource(root);
|
|
|
|
expect(result.ok).toBe(true);
|
|
if (!result.ok) return;
|
|
expect(result.value.entries.map(({ path }) => path)).toEqual([
|
|
"a.js",
|
|
"nested",
|
|
"nested/b.js",
|
|
"z.js",
|
|
"",
|
|
"𐀀",
|
|
]);
|
|
expect(result.value.bytesRead).toBe(5);
|
|
expect(
|
|
result.value.entries.map((entry) =>
|
|
entry.status === "read" && entry.kind === "file"
|
|
? Buffer.from(entry.bytes).toString()
|
|
: entry.status === "read"
|
|
? entry.kind
|
|
: entry.code,
|
|
),
|
|
).toEqual(["a", "directory", "b", "z", "p", "a"]);
|
|
expect(result.value.limitations).toHaveLength(1);
|
|
});
|
|
|
|
it("reports physical external symlink targets without following them", async () => {
|
|
const root = await createTestTempDirectory("rea-reference-");
|
|
const outside = await createTestTempDirectory("rea-outside-");
|
|
await writeFile(join(outside, "secret"), "secret");
|
|
await writeFile(join(root, "local"), "local");
|
|
await symlink("local", join(root, "internal"));
|
|
await symlink(join(outside, "secret"), join(root, "external"));
|
|
await symlink("absent", join(root, "missing"));
|
|
|
|
const result = await readReferenceSource(root);
|
|
|
|
expect(result.ok).toBe(true);
|
|
if (!result.ok) return;
|
|
expect(result.value.entries).toEqual([
|
|
{
|
|
status: "read",
|
|
kind: "symlink",
|
|
path: "external",
|
|
target: join(outside, "secret"),
|
|
targetState: "external",
|
|
},
|
|
{
|
|
status: "read",
|
|
kind: "symlink",
|
|
path: "internal",
|
|
target: "local",
|
|
targetState: "internal",
|
|
},
|
|
{
|
|
status: "read",
|
|
kind: "file",
|
|
path: "local",
|
|
bytes: expect.any(Uint8Array),
|
|
size: 5,
|
|
},
|
|
{
|
|
status: "read",
|
|
kind: "symlink",
|
|
path: "missing",
|
|
target: "absent",
|
|
targetState: "missing",
|
|
},
|
|
]);
|
|
expect(result.value.bytesRead).toBe(5);
|
|
expect(JSON.stringify(result.value.entries)).toContain(
|
|
join(outside, "secret"),
|
|
);
|
|
});
|
|
|
|
it("reads a source file larger than the former 16 MiB ceiling", async () => {
|
|
const root = await createTestTempDirectory("rea-reference-large-");
|
|
const size = 16 * 1024 * 1024 + 1;
|
|
await writeFile(join(root, "large.bin"), Buffer.alloc(size, 0x61));
|
|
|
|
const result = await readReferenceSource(root);
|
|
|
|
expect(result.ok).toBe(true);
|
|
if (!result.ok) return;
|
|
expect(result.value.bytesRead).toBe(size);
|
|
expect(result.value.entries).toContainEqual(
|
|
expect.objectContaining({
|
|
status: "read",
|
|
kind: "file",
|
|
path: "large.bin",
|
|
size,
|
|
}),
|
|
);
|
|
});
|
|
|
|
it("traverses source directories deeper than the former depth ceiling", async () => {
|
|
const root = await createTestTempDirectory("rea-reference-deep-");
|
|
const segments = Array.from({ length: 40 }, (_, index) => `d${index}`);
|
|
const directory = join(root, ...segments);
|
|
await mkdir(directory, { recursive: true });
|
|
await writeFile(join(directory, "deep.txt"), "deep");
|
|
|
|
const result = await readReferenceSource(root);
|
|
|
|
expect(result.ok).toBe(true);
|
|
if (!result.ok) return;
|
|
const path = [...segments, "deep.txt"].join("/");
|
|
expect(result.value.entries).toContainEqual(
|
|
expect.objectContaining({ status: "read", kind: "file", path }),
|
|
);
|
|
expect(result.value.entries).toHaveLength(41);
|
|
});
|
|
});
|
|
|
|
describe("readReferenceSource failures and exclusions", () => {
|
|
it("applies exclusions to normalized paths before reading entries", async () => {
|
|
const root = await createTestTempDirectory("rea-reference-");
|
|
await mkdir(join(root, "ignored"));
|
|
await writeFile(join(root, "ignored", "secret"), "secret");
|
|
await writeFile(join(root, "kept"), "kept");
|
|
const checked: string[] = [];
|
|
|
|
const result = await readReferenceSource(root, {
|
|
shouldExclude: (path) => {
|
|
checked.push(path);
|
|
return path === "ignored";
|
|
},
|
|
});
|
|
|
|
expect(result.ok).toBe(true);
|
|
if (!result.ok) return;
|
|
expect(checked).toEqual(["ignored", "kept"]);
|
|
expect(result.value.entries.map(({ path }) => path)).toEqual(["kept"]);
|
|
});
|
|
|
|
it("sanitizes exclusion callback failures", async () => {
|
|
const root = await createTestTempDirectory("rea-reference-");
|
|
await writeFile(join(root, "file"), "value");
|
|
const result = await readReferenceSource(root, {
|
|
shouldExclude: () => {
|
|
throw new Error("private callback detail");
|
|
},
|
|
});
|
|
|
|
expect(result).toEqual({
|
|
ok: false,
|
|
error: {
|
|
tag: "reference-source-reader",
|
|
code: "io",
|
|
message: "Reference source exclusion check failed",
|
|
},
|
|
});
|
|
});
|
|
|
|
it("keeps selected-root paths in actionable filesystem errors", async () => {
|
|
const missing = join(tmpdir(), "rea-secret-root-that-does-not-exist");
|
|
const result = await readReferenceSource(missing);
|
|
|
|
expect(result.ok).toBe(false);
|
|
if (result.ok) return;
|
|
expect(result.error.message).toContain(missing);
|
|
});
|
|
|
|
it("returns typed failures for cancellation and invalid roots", async () => {
|
|
const controller = new AbortController();
|
|
controller.abort();
|
|
const cancelled = await readReferenceSource("/unused", {
|
|
signal: controller.signal,
|
|
});
|
|
expect(cancelled).toEqual({
|
|
ok: false,
|
|
error: {
|
|
tag: "reference-source-reader",
|
|
code: "cancelled",
|
|
message: "Reference source traversal cancelled",
|
|
},
|
|
});
|
|
|
|
const invalid = await readReferenceSource("/path/that/does/not/exist");
|
|
expect(invalid.ok).toBe(false);
|
|
if (invalid.ok) return;
|
|
expect(invalid.error.code).toBe("invalid-root");
|
|
});
|
|
});
|