mirror of
https://github.com/morluto/rea.git
synced 2026-10-12 02:19:24 +00:00
Keep FAT container format distinct from selected slice architecture through target admission, Evidence, snapshots, and CLI/MCP lifecycle results. Preserve native, Hopper, Ghidra, extraction, and dylib routing for the Mach-O family. Reject selected FAT ranges overlapping their table or too short for a Mach-O header. Replace empty-slice fixtures with in-bounds executable headers and cover thin, universal, single-slice, FAT64, and swapped containers. Validation: static and architecture checks, generated docs, targeted producer and public MCP tests. Provider routing uses controlled fixtures; no live Hopper, IDA, JADX, or Ghidra analysis was performed for this change.
82 lines
3.1 KiB
TypeScript
82 lines
3.1 KiB
TypeScript
import { parseMcpToolError } from "../../fixtures/mcpToolError.js";
|
|
import { writeFile } from "node:fs/promises";
|
|
import { join } from "node:path";
|
|
import { Client, InMemoryTransport } from "@modelcontextprotocol/client";
|
|
import { expect, it } from "vitest";
|
|
import { NativeMacOSProvider } from "../../../src/native/NativeMacOSProvider.js";
|
|
import {
|
|
machoImage,
|
|
rpathCommand,
|
|
CPU,
|
|
fatImage,
|
|
} from "../../../src/artifacts/apple/MachoImage.fixture.js";
|
|
import { createServer } from "../../../src/server/createServer.js";
|
|
import { createTestBinarySession } from "../../fixtures/binarySession.js";
|
|
import { createTestTempDirectory } from "../../fixtures/temporaryDirectory.js";
|
|
import { NativeFixtureRunner } from "../../fixtures/nativeCommands.js";
|
|
import { toolContract } from "../../../src/contracts/toolContracts.js";
|
|
|
|
it.each(["mach-o", "mach-o-universal"] as const)(
|
|
"rejects changed %s signature targets through MCP and accepts reopening the new version",
|
|
async (format) => {
|
|
const path = join(
|
|
await createTestTempDirectory("rea-signature-binding-mcp-"),
|
|
"program",
|
|
);
|
|
const image = (commands: readonly Uint8Array[] = []) =>
|
|
format === "mach-o"
|
|
? machoImage({ commands })
|
|
: fatImage(
|
|
[CPU.arm64, CPU.x86_64].map((cpu) => ({
|
|
cpu,
|
|
bytes: machoImage({ cpu, commands }),
|
|
})),
|
|
);
|
|
await writeFile(path, image());
|
|
const session = createTestBinarySession(
|
|
new NativeMacOSProvider({}, new NativeFixtureRunner(), "darwin"),
|
|
);
|
|
const server = createServer({ kind: "session", session });
|
|
const client = new Client({ name: "signature-binding-test", version: "1" });
|
|
const [clientTransport, serverTransport] =
|
|
InMemoryTransport.createLinkedPair();
|
|
try {
|
|
await server.connect(serverTransport);
|
|
await client.connect(clientTransport);
|
|
const open = () =>
|
|
client.callTool({ name: "open_binary", arguments: { path } });
|
|
const opened = await open();
|
|
expect(opened.isError).not.toBe(true);
|
|
expect(
|
|
toolContract("open_binary").outputSchema.parse(opened.structuredContent)
|
|
.result,
|
|
).toMatchObject({ format });
|
|
await writeFile(path, image([rpathCommand("new-version")]));
|
|
const changed = await client.callTool({
|
|
name: "inspect_signature",
|
|
arguments: {},
|
|
});
|
|
expect(changed.isError).toBe(true);
|
|
expect(parseMcpToolError(changed)).toMatchObject({
|
|
error: { code: "artifact_changed", details: { path } },
|
|
});
|
|
expect((await open()).isError).not.toBe(true);
|
|
const inspected = await client.callTool({
|
|
name: "inspect_signature",
|
|
arguments: {},
|
|
});
|
|
expect(
|
|
inspected.isError,
|
|
JSON.stringify(inspected.structuredContent),
|
|
).not.toBe(true);
|
|
expect(inspected.structuredContent).toMatchObject({
|
|
subject: { format },
|
|
normalized_result: { signed: true, identifier: "com.example.fixture" },
|
|
});
|
|
} finally {
|
|
await client.close();
|
|
await server.close();
|
|
}
|
|
},
|
|
);
|