mirror of
https://github.com/morluto/rea.git
synced 2026-10-31 20:06:14 +00:00
* test: strengthen integration oracles and verification * test: bound lifecycle gates and strengthen workflow checks * test: verify complete paged and extracted results * test: preserve bytecode and cancellation evidence * test: strengthen retained evidence and fixture cleanup * test: require cross-projection bridge identities * test: retain fixture owners through cleanup failures * test: verify graph examples and project selectors * test: tighten provider and lifecycle regressions * test: consolidate hex coverage and bound cutter cleanup * test: bound subprocess output waits and strengthen graph checks * test: check mcp recovery and preserve cleanup owners * test: verify structured mcp argument failures * test: preserve artifact cleanup and gdb limit evidence * test: preserve evidence identities and bound provider gates * test: retain browser and comparison cleanup owners * test: bound startup and strengthen fixture oracles * test: bound lifecycle gates and verify recovered evidence * test: verify public outcomes and lifecycle ownership * test: assert precise evidence and release lifecycle gates * test: verify selected facts and bound cleanup waits * test: check retained evidence and decoded records * test: verify final reports and retain cleanup ownership * test: bound reviewed startup gates and retain cleanup * test: verify PE errors and preserve MCP cleanup * test: preserve MCP fixture cleanup ownership * test: release provider gates before late startup
117 lines
4.7 KiB
TypeScript
117 lines
4.7 KiB
TypeScript
import { createHash } from "node:crypto";
|
|
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
import { join } from "node:path";
|
|
import { expect } from "vitest";
|
|
import { thinMach } from "../../../src/domain/binaryTarget.fixture.js";
|
|
import { interfaceBuilderAnalysisSchema } from "../../../src/domain/apple/interfaceBuilderGraph.js";
|
|
import { keyedArchiveResultSchema } from "../../../src/domain/apple/keyedArchive.js";
|
|
import { inspectPlistSchema } from "../../../src/domain/native/nativeInspection.js";
|
|
import { parseEvidence } from "../../../src/domain/evidence.js";
|
|
import { createTestTempDirectory } from "../../fixtures/temporaryDirectory.js";
|
|
import { connectLocalToolsMcp } from "../../fixtures/localToolsMcp.js";
|
|
import { parseMcpToolError } from "../../fixtures/mcpToolError.js";
|
|
import { cliTest } from "../../support/cli/cliFixture.js";
|
|
|
|
cliTest.for([
|
|
"decode_interface_builder",
|
|
"inspect_keyed_archive",
|
|
...(process.platform === "darwin"
|
|
? ["inspect_asset_catalog", "inspect_plist"]
|
|
: []),
|
|
] as const)(
|
|
"binds live %s Evidence to the open executable through stdio MCP",
|
|
async (operation) => {
|
|
const root = await createTestTempDirectory("rea-bundle-resource-identity-");
|
|
const app = join(root, "Probe.app");
|
|
const contents = join(app, "Contents");
|
|
const resources = join(contents, "Resources");
|
|
await mkdir(resources, { recursive: true });
|
|
await mkdir(join(contents, "MacOS"));
|
|
const executable = join(contents, "MacOS", "Probe");
|
|
const original = thinMach(0xfeedfacf, 0x0100000c);
|
|
await writeFile(executable, original);
|
|
await writeFile(
|
|
join(contents, "Info.plist"),
|
|
"<plist><dict><key>CFBundleExecutable</key><string>Probe</string></dict></plist>",
|
|
);
|
|
const nib = await readFile(
|
|
join(process.cwd(), "tests/fixtures/interface-builder/UIKitOutlet.xml"),
|
|
"utf8",
|
|
);
|
|
const nibPath = join(resources, "Main.nib");
|
|
await writeFile(nibPath, nib);
|
|
const { call } = await connectLocalToolsMcp();
|
|
const parameters =
|
|
operation === "inspect_keyed_archive"
|
|
? { path: "Contents/Resources/Main.nib" }
|
|
: {};
|
|
expect((await call("open_binary", { path: app })).isError).not.toBe(true);
|
|
const before = await call(operation, parameters);
|
|
expect(before.isError).not.toBe(true);
|
|
const initial = parseEvidence(before.structuredContent);
|
|
expect(initial.subject?.digest.sha256).toBe(
|
|
createHash("sha256").update(original).digest("hex"),
|
|
);
|
|
|
|
const changed = Buffer.from(original);
|
|
changed[31] = 1;
|
|
await writeFile(executable, changed);
|
|
const changedNib = nib.replaceAll("UIViewController", "ChangedController");
|
|
expect(changedNib).not.toBe(nib);
|
|
await writeFile(nibPath, changedNib);
|
|
if (operation === "inspect_plist")
|
|
await writeFile(
|
|
join(contents, "Info.plist"),
|
|
"<plist><dict><key>CFBundleExecutable</key><string>Probe</string><key>Marker</key><string>ChangedController</string></dict></plist>",
|
|
);
|
|
const stale = await call(operation, parameters);
|
|
expect(parseMcpToolError(stale).error).toMatchObject({
|
|
code:
|
|
operation === "inspect_plist"
|
|
? "artifact_changed"
|
|
: "artifact_operation_failed",
|
|
category: "integrity_mismatch",
|
|
});
|
|
|
|
expect((await call("open_binary", { path: app })).isError).not.toBe(true);
|
|
const after = await call(operation, parameters);
|
|
expect(after.isError).not.toBe(true);
|
|
const refreshed = parseEvidence(after.structuredContent);
|
|
expect(refreshed.subject?.digest.sha256).toBe(
|
|
createHash("sha256").update(changed).digest("hex"),
|
|
);
|
|
const nibHash = createHash("sha256").update(changedNib).digest("hex");
|
|
if (operation === "inspect_plist")
|
|
expect(
|
|
inspectPlistSchema.parse(refreshed.normalized_result).value,
|
|
).toMatchObject({ Marker: "ChangedController" });
|
|
if (operation === "decode_interface_builder") {
|
|
const report = interfaceBuilderAnalysisSchema.parse(
|
|
refreshed.normalized_result,
|
|
);
|
|
expect(report.documents).toContainEqual(
|
|
expect.objectContaining({
|
|
relative_path: "Contents/Resources/Main.nib",
|
|
archive_sha256: nibHash,
|
|
}),
|
|
);
|
|
expect(report.graph.nodes).toContainEqual(
|
|
expect.objectContaining({
|
|
attributes: expect.objectContaining({
|
|
class_name: "ChangedController",
|
|
}),
|
|
}),
|
|
);
|
|
}
|
|
if (operation === "inspect_keyed_archive") {
|
|
const report = keyedArchiveResultSchema.parse(
|
|
refreshed.normalized_result,
|
|
);
|
|
expect(report.archive_sha256).toBe(nibHash);
|
|
expect(report.objects).toContainEqual(
|
|
expect.objectContaining({ class_name: "ChangedController" }),
|
|
);
|
|
}
|
|
},
|
|
);
|