Files
reverse-engineering-anything/tests/boundary/filesystem/directoryRootIdentity.test.ts
T

114 lines
4.1 KiB
TypeScript

import { mkdir, rename, symlink, writeFile } from "node:fs/promises";
import { join } from "node:path";
import { expect, it } from "vitest";
import { DirectoryArtifactReader } from "../../../src/artifacts/DirectoryArtifactReader.js";
import { DesktopApplicationReader } from "../../../src/artifacts/DesktopApplicationReader.js";
import { DesktopApplicationService } from "../../../src/application/artifacts/DesktopApplicationService.js";
import { parseEvidence } from "../../../src/domain/evidence.js";
import { desktopApplicationSchema } from "../../../src/domain/desktopApplication.js";
import { createTestTempDirectory } from "../../fixtures/temporaryDirectory.js";
it.each(["before-open", "during-inspection", "during-stream"] as const)(
"rejects replacement of the admitted physical root %s even when file identity survives",
async (stage) => {
const root = await createTestTempDirectory("rea-directory-root-identity-");
const original = join(root, "original");
await mkdir(original);
await writeFile(join(original, "sample.txt"), "original content");
const reader = new DirectoryArtifactReader(original);
const entries = [];
for await (const entry of reader.entries()) entries.push(entry);
const entry = entries[0];
if (entry === undefined) throw new Error("Expected sample file");
const replaceRoot = async () => {
const moved = join(root, "moved");
await rename(original, moved);
await symlink(
moved,
original,
process.platform === "win32" ? "junction" : "dir",
);
};
try {
if (stage === "before-open") {
await replaceRoot();
await expect(reader.open(entry)).rejects.toMatchObject({
reason: "integrity",
});
} else if (stage === "during-inspection") {
await expect(
reader.inspectFile(entry, async (file) => {
const bytes = await file.readFile();
await replaceRoot();
return bytes;
}),
).rejects.toMatchObject({ reason: "integrity" });
} else {
const stream = await reader.open(entry);
await replaceRoot();
await expect(
(async () => {
for await (const _chunk of stream) {
/* consume the admitted file */
}
})(),
).rejects.toMatchObject({ reason: "integrity" });
}
} finally {
await reader.close();
}
},
);
it("discards unverified desktop byte facts when the admitted root changes during inspection", async () => {
const root = await createTestTempDirectory("rea-desktop-root-identity-");
const original = join(root, "original");
const moved = join(root, "moved");
await mkdir(original);
await writeFile(join(original, "sample.exe"), Buffer.from("MZ"));
const service = new DesktopApplicationService(
new DesktopApplicationReader((path) => {
const reader = new DirectoryArtifactReader(path);
const inspect = reader.inspectFile.bind(reader);
reader.inspectFile = (entry, read, signal) =>
inspect(
entry,
async (file) => {
const value = await read(file);
await rename(original, moved);
await symlink(
moved,
original,
process.platform === "win32" ? "junction" : "dir",
);
return value;
},
signal,
);
return reader;
}),
);
try {
const result = await service.inspect({ path: original });
expect(result.ok).toBe(false);
if (result.ok) throw new Error("Expected root identity failure");
const report = desktopApplicationSchema.parse(
parseEvidence(result.error.partialObservation).normalized_result,
);
expect(report.root.path).toBe(original);
expect(report.files).toHaveLength(1);
expect(report.files[0]).toMatchObject({
path: "sample.exe",
read_status: "unavailable",
ranges: [],
});
expect(report.files[0]?.facts.every((fact) => fact.offset === null)).toBe(
true,
);
expect(report.coverage.status).toBe("partial");
} finally {
await service.close();
}
});