Files
reverse-engineering-anything/tests/acceptance/artifactComparisonUnavailableMetadata.test.ts
T
morluto 62ce357f16 fix(artifacts): preserve known metadata without content hashes (#7932)
* fix(artifacts): preserve known metadata without content hashes

* fix(artifacts): keep missing relation projections unknown
2026-10-29 10:10:41 +08:00

90 lines
3.5 KiB
TypeScript

import { TextReader, Uint8ArrayWriter, ZipWriter } from "@zip.js/zip.js";
import { execFile } from "node:child_process";
import { writeFile } from "node:fs/promises";
import { join } from "node:path";
import { fileURLToPath } from "node:url";
import { promisify } from "node:util";
import { expect, it } from "vitest";
import { artifactInspectionResultSchema } from "../../src/domain/artifactInspection.js";
import { parseEvidence } from "../../src/domain/evidence.js";
import { connectLocalToolsMcp } from "../fixtures/localToolsMcp.js";
import { createTestTempDirectory } from "../fixtures/temporaryDirectory.js";
const cli = fileURLToPath(new URL("../../scripts/rea.mjs", import.meta.url));
const execute = promisify(execFile);
it("keeps observed entry differences when content identity is unknown", async () => {
const root = await createTestTempDirectory("rea-artifact-unavailable-");
const inspect = async (name: string, mode: number, content: string) => {
const writer = new ZipWriter(new Uint8ArrayWriter(), {
useWebWorkers: false,
});
await writer.add("entry", new TextReader(content), { unixMode: mode });
const path = join(root, `${name}.zip`);
await writeFile(path, Buffer.from(await writer.close()));
const result = await execute(process.execPath, [
cli,
"inspect-artifact",
path,
"--detail",
"complete",
"--json",
]);
const inspection = artifactInspectionResultSchema.parse(
parseEvidence(JSON.parse(result.stdout)).normalized_result,
);
const inventory = inspection.substeps.find(
({ operation }) => operation === "inventory_artifact",
)?.evidence;
if (inventory === undefined) throw new Error("Missing inventory Evidence");
return parseEvidence(inventory);
};
const symlink = await inspect("symlink", 0o120777, "target.txt");
const executable = await inspect("executable", 0o100755, "target\n");
const plain = await inspect("plain", 0o100644, "target\n");
const { call } = await connectLocalToolsMcp();
const compare = async (left: typeof symlink, right: typeof symlink) => {
const response = await call("compare_artifacts", { left, right });
expect(response.isError, JSON.stringify(response)).not.toBe(true);
return parseEvidence(response.structuredContent).normalized_result as {
status: string;
changes: {
logical_path: string;
classification: string;
dimensions: string[];
left_occurrence_id: string | null;
right_occurrence_id: string | null;
}[];
};
};
for (const [left, right] of [
[symlink, executable],
[executable, symlink],
] as const) {
const result = await compare(left, right);
expect(result.status).toBe("unknown");
const entry = result.changes.find(
({ logical_path }) => logical_path === "entry",
);
expect(entry?.dimensions).not.toContain("relations");
expect(entry).toMatchObject({
classification: "unknown",
dimensions: expect.arrayContaining([
"executable",
"metadata",
"availability",
]),
left_occurrence_id: expect.any(String),
right_occurrence_id: expect.any(String),
});
}
expect((await compare(symlink, symlink)).status).toBe("unknown");
expect(
(await compare(executable, plain)).changes.find(
({ logical_path }) => logical_path === "entry",
),
).toMatchObject({ classification: "changed", dimensions: ["executable"] });
expect((await compare(executable, executable)).status).toBe("unchanged");
});