mirror of
https://github.com/morluto/rea.git
synced 2026-10-31 11:56:12 +00:00
Move shared function, dossier, inventory, reference and output semantics from the legacy Hopper module to native domain owners. Migrate provider, adapter, test and verifier consumers directly.
443 lines
14 KiB
TypeScript
443 lines
14 KiB
TypeScript
import { Client } from "@modelcontextprotocol/client";
|
|
import { StdioClientTransport } from "@modelcontextprotocol/client/stdio";
|
|
import { writeFile } from "node:fs/promises";
|
|
import { join, resolve } from "node:path";
|
|
import { afterAll, beforeAll, expect } from "vitest";
|
|
|
|
import { createEvidence, parseEvidence } from "../../../src/domain/evidence.js";
|
|
import { functionDossierSchema } from "../../../src/domain/native/functionDossier.js";
|
|
import {
|
|
MANAGED_APPLICATION_GRAPH_EXAMPLE,
|
|
MANAGED_NATIVE_VERIFICATION_EXAMPLE,
|
|
} from "../../../src/contracts/managed/managedWorkflowExamples.js";
|
|
import { managedMemberInspectionSchema } from "../../../src/domain/managed/managedArtifact.js";
|
|
import { managedApplicationGraphReferenceInputSchema } from "../../../src/contracts/managed/managedWorkflowToolContracts.js";
|
|
import { managedNativeVerificationResultSchema } from "../../../src/domain/managed/managedNativeVerificationSchemas.js";
|
|
import { buildManagedPeFixture } from "../../../src/dotnet/ManagedPe.fixture.js";
|
|
import { parseMcpToolError } from "../../fixtures/mcpToolError.js";
|
|
import { createTestTempDirectory } from "../../fixtures/temporaryDirectory.js";
|
|
import { cliTest } from "../../support/cli/cliFixture.js";
|
|
|
|
const client = new Client({ name: "managed-native-adapters", version: "1" });
|
|
const transport = new StdioClientTransport({
|
|
command: process.execPath,
|
|
args: [resolve("scripts/rea.mjs"), "mcp"],
|
|
cwd: process.cwd(),
|
|
env: { PATH: process.env.PATH ?? "" },
|
|
stderr: "pipe",
|
|
});
|
|
beforeAll(async () => {
|
|
await client.connect(transport);
|
|
transport.stderr?.on("data", () => undefined);
|
|
});
|
|
afterAll(async () => {
|
|
await Promise.all([client.close(), transport.close()]);
|
|
});
|
|
|
|
cliTest(
|
|
"preserves managed graph identity failures and wrong-role controls through CLI and stdio MCP",
|
|
async ({ cli }) => {
|
|
const original = MANAGED_APPLICATION_GRAPH_EXAMPLE.managed_members;
|
|
const members = managedMemberInspectionSchema.parse(
|
|
original.normalized_result,
|
|
);
|
|
const otherDigest = "b".repeat(64);
|
|
const otherMvid = "ffffffff-ffff-ffff-ffff-ffffffffffff";
|
|
for (const variant of [
|
|
"subject-sha256",
|
|
"scope-sha256",
|
|
"scope-mvid",
|
|
] as const) {
|
|
const source = createEvidence(
|
|
variant === "subject-sha256"
|
|
? { path: members.artifact.path, format: "pe", sha256: otherDigest }
|
|
: undefined,
|
|
original.provider,
|
|
{
|
|
operation: original.operation,
|
|
parameters: {},
|
|
result: {
|
|
...members,
|
|
identity_scope: {
|
|
...members.identity_scope,
|
|
...(variant === "scope-sha256"
|
|
? { requires_artifact_sha256: otherDigest }
|
|
: {}),
|
|
...(variant === "scope-mvid" ? { requires_mvid: otherMvid } : {}),
|
|
},
|
|
},
|
|
rawResult: null,
|
|
},
|
|
);
|
|
// The record authenticates and the request has the advertised shape;
|
|
// rejection must identify the contradictory identities within that record.
|
|
const input = managedApplicationGraphReferenceInputSchema.parse({
|
|
managed_members: parseEvidence(JSON.parse(JSON.stringify(source))),
|
|
});
|
|
const response = await client.callTool({
|
|
name: "project_managed_application_graph",
|
|
arguments: input,
|
|
});
|
|
const error = parseMcpToolError(response).error;
|
|
const contradiction =
|
|
variant === "subject-sha256"
|
|
? `subject SHA-256 ${otherDigest} does not match normalized artifact SHA-256 ${members.artifact.sha256}`
|
|
: variant === "scope-sha256"
|
|
? `token scope SHA-256 ${otherDigest} does not match normalized artifact SHA-256 ${members.artifact.sha256}`
|
|
: `token scope MVID ${otherMvid} does not match module MVID ${String(members.module?.mvid)}`;
|
|
expect(error).toMatchObject({
|
|
code: "evidence_integrity_mismatch",
|
|
category: "integrity_mismatch",
|
|
retryable: false,
|
|
details: {
|
|
reason: `Managed Evidence inspect_managed_members (${source.evidence_id}) ${contradiction}`,
|
|
},
|
|
});
|
|
expect(error.recovery).toBeUndefined();
|
|
expect(response.structuredContent).toBeUndefined();
|
|
const command = await cli.run({
|
|
arguments: [
|
|
"project-managed-application-graph",
|
|
JSON.stringify(input),
|
|
"--json",
|
|
],
|
|
});
|
|
expect(command.exitCode, command.stderr).toBe(1);
|
|
expect(command.json).toMatchObject(error);
|
|
expect(command.json).not.toHaveProperty("recovery");
|
|
expect(command.json).not.toHaveProperty("evidence_id");
|
|
}
|
|
|
|
const wrongRole = MANAGED_NATIVE_VERIFICATION_EXAMPLE.managed_boundaries;
|
|
const wrongInput = { managed_members: wrongRole };
|
|
const wrongResponse = await client.callTool({
|
|
name: "project_managed_application_graph",
|
|
arguments: wrongInput,
|
|
});
|
|
const wrongError = parseMcpToolError(wrongResponse).error;
|
|
expect(wrongError).toMatchObject({
|
|
code: "invalid_request",
|
|
category: "invalid_input",
|
|
recovery: {
|
|
kind: "inspect_input_contract",
|
|
operation: "project_managed_application_graph",
|
|
},
|
|
details: {
|
|
issues: [
|
|
{
|
|
path: ["managed_members"],
|
|
reason: "invalid_value",
|
|
message: `Expected rea.analysis inspect_managed_members Evidence, received ${wrongRole.predicate_type} ${wrongRole.operation}`,
|
|
},
|
|
],
|
|
},
|
|
});
|
|
const wrongCommand = await cli.run({
|
|
arguments: [
|
|
"project-managed-application-graph",
|
|
JSON.stringify(wrongInput),
|
|
"--json",
|
|
],
|
|
});
|
|
expect(wrongCommand.exitCode, wrongCommand.stderr).toBe(1);
|
|
expect(wrongCommand.json).toMatchObject(wrongError);
|
|
|
|
const control = await client.callTool({
|
|
name: "project_managed_application_graph",
|
|
arguments: MANAGED_APPLICATION_GRAPH_EXAMPLE,
|
|
});
|
|
expect(control.isError, JSON.stringify(control.content)).not.toBe(true);
|
|
const commandControl = await cli.run({
|
|
arguments: [
|
|
"project-managed-application-graph",
|
|
JSON.stringify(MANAGED_APPLICATION_GRAPH_EXAMPLE),
|
|
"--json",
|
|
],
|
|
});
|
|
expect(commandControl.exitCode, commandControl.stderr).toBe(0);
|
|
const evidence = parseEvidence(control.structuredContent);
|
|
expect(parseEvidence(commandControl.json).normalized_result).toEqual(
|
|
evidence.normalized_result,
|
|
);
|
|
expect(evidence.evidence_links).toEqual([original.evidence_id]);
|
|
},
|
|
60_000,
|
|
);
|
|
|
|
/** Authentic native Evidence whose operation the workflow cannot read symbols from. */
|
|
const signatureEvidence = () =>
|
|
createEvidence(
|
|
{
|
|
path: "/usr/bin/true",
|
|
sha256: "a".repeat(64),
|
|
format: "mach-o",
|
|
architecture: "arm64",
|
|
},
|
|
{ id: "native", name: "Native", version: "simulated" },
|
|
{
|
|
predicateType: "rea.native-signature",
|
|
operation: "inspect_signature",
|
|
parameters: {},
|
|
result: { signed: true },
|
|
limitations: ["No native provider executed."],
|
|
},
|
|
);
|
|
|
|
const platformPinvokeCases = [
|
|
{
|
|
format: "pe",
|
|
scope: "nativehelper.dll",
|
|
module: "nativehelper.dll",
|
|
status: "verified",
|
|
},
|
|
{
|
|
format: "pe",
|
|
scope: "nativehelper.dll",
|
|
module: "nativehelper.exe",
|
|
status: "contradicted",
|
|
},
|
|
{
|
|
format: "pe",
|
|
scope: "nativehelper.dll",
|
|
module: "nativehelper.node",
|
|
status: "contradicted",
|
|
},
|
|
{
|
|
format: "pe",
|
|
scope: "nativehelper",
|
|
module: "nativehelper.dll",
|
|
status: "verified",
|
|
},
|
|
{
|
|
scope: "nativedep.so.6",
|
|
module: "libnativedep.so.6",
|
|
format: "elf",
|
|
status: "verified",
|
|
},
|
|
{
|
|
scope: "nativehelper",
|
|
module: "libnativehelper.so",
|
|
format: "elf",
|
|
flags: 0x202,
|
|
symbol: "open_nativeA",
|
|
status: "unresolved",
|
|
},
|
|
{
|
|
scope: "nativehelper",
|
|
module: "libnativehelper.dylib",
|
|
format: "mach-o",
|
|
flags: 0x204,
|
|
symbol: "open_nativeW",
|
|
status: "unresolved",
|
|
},
|
|
{
|
|
scope: "nativehelper",
|
|
module: "libnativehelper.so",
|
|
format: "elf",
|
|
flags: 0x204,
|
|
symbol: "open_native",
|
|
status: "verified",
|
|
},
|
|
{
|
|
scope: "nativehelper",
|
|
module: "nativehelper.dll",
|
|
format: "pe",
|
|
flags: 0x202,
|
|
symbol: "open_nativeA",
|
|
status: "inferred",
|
|
},
|
|
] as const;
|
|
|
|
cliTest(
|
|
"preserves platform-specific P/Invoke names and module matching through CLI and MCP",
|
|
async ({ cli }) => {
|
|
const root = await createTestTempDirectory(
|
|
"rea-managed-native-module-names-",
|
|
);
|
|
const nativeProvider = {
|
|
id: "native-fixture",
|
|
name: "Synthetic native fixture",
|
|
version: "1",
|
|
};
|
|
const dossier = functionDossierSchema.parse({
|
|
procedure: {
|
|
address: "0x1000",
|
|
name: "open_native",
|
|
classification: {
|
|
external: false,
|
|
thunk: false,
|
|
thunk_target: null,
|
|
provenance: "synthetic-provider",
|
|
},
|
|
body: { available: false, reason: "Synthetic test Evidence only." },
|
|
signature: null,
|
|
locals: [],
|
|
},
|
|
pseudocode: "",
|
|
assembly: [],
|
|
comments: [],
|
|
callers: [],
|
|
callees: [],
|
|
incoming_references: [],
|
|
outgoing_references: [],
|
|
referenced_strings: [],
|
|
referenced_names: [],
|
|
basic_blocks: [],
|
|
native_api: null,
|
|
native_value_flow: null,
|
|
limitations: ["No native provider was executed."],
|
|
});
|
|
|
|
for (const [index, item] of platformPinvokeCases.entries()) {
|
|
const managedPath = join(root, `managed-${String(index)}.dll`);
|
|
await writeFile(
|
|
managedPath,
|
|
buildManagedPeFixture({
|
|
pinvoke: {
|
|
importName: "open_native",
|
|
moduleName: item.scope,
|
|
...("flags" in item ? { mappingFlags: item.flags } : {}),
|
|
},
|
|
}),
|
|
);
|
|
const inspected = await client.callTool({
|
|
name: "inspect_managed_native_boundaries",
|
|
arguments: { path: managedPath },
|
|
});
|
|
expect(inspected.isError, JSON.stringify(inspected.content)).not.toBe(
|
|
true,
|
|
);
|
|
const managed = parseEvidence(inspected.structuredContent);
|
|
const native = createEvidence(
|
|
{
|
|
path: `/synthetic/${item.module}`,
|
|
sha256: "8".repeat(64),
|
|
format: item.format ?? "pe",
|
|
},
|
|
nativeProvider,
|
|
{
|
|
operation: "analyze_function",
|
|
parameters: {},
|
|
result: {
|
|
...dossier,
|
|
procedure: {
|
|
...dossier.procedure,
|
|
name: "symbol" in item ? item.symbol : "open_native",
|
|
},
|
|
},
|
|
rawResult: null,
|
|
limitations: ["Synthetic native Evidence; no provider executed."],
|
|
},
|
|
);
|
|
const input = {
|
|
managed_boundaries: managed,
|
|
native_observations: [native],
|
|
};
|
|
const mcp = await client.callTool({
|
|
name: "verify_managed_native_boundaries",
|
|
arguments: input,
|
|
});
|
|
expect(mcp.isError, JSON.stringify(mcp.content)).not.toBe(true);
|
|
const mcpResult = managedNativeVerificationResultSchema.parse(
|
|
parseEvidence(mcp.structuredContent).normalized_result,
|
|
);
|
|
const request = join(root, `verify-${String(index)}.json`);
|
|
await writeFile(request, JSON.stringify(input));
|
|
const cliRun = await cli.run({
|
|
arguments: ["verify-managed-native-boundaries", request, "--json"],
|
|
});
|
|
expect(cliRun.exitCode, cliRun.stderr).toBe(0);
|
|
const cliResult = managedNativeVerificationResultSchema.parse(
|
|
parseEvidence(cliRun.json).normalized_result,
|
|
);
|
|
expect(mcpResult).toEqual(cliResult);
|
|
expect(mcpResult.pinvoke_imports[0]).toMatchObject({
|
|
status: item.status,
|
|
...(item.status === "contradicted" ? { basis: "module-mismatch" } : {}),
|
|
...(item.status === "unresolved"
|
|
? {
|
|
basis: "no-native-candidate",
|
|
candidates: [],
|
|
matched_native: null,
|
|
}
|
|
: {}),
|
|
});
|
|
expect(mcpResult.evidence_links).toEqual([
|
|
managed.evidence_id,
|
|
native.evidence_id,
|
|
]);
|
|
}
|
|
},
|
|
60_000,
|
|
);
|
|
|
|
cliTest(
|
|
"counts authentic unsupported native Evidence identically through MCP and CLI",
|
|
async ({ cli }) => {
|
|
const root = await createTestTempDirectory("rea-managed-native-adapters-");
|
|
const path = join(root, "fixture.dll");
|
|
await writeFile(path, buildManagedPeFixture({ pinvoke: {} }));
|
|
const inspected = await client.callTool({
|
|
name: "inspect_managed_native_boundaries",
|
|
arguments: { path },
|
|
});
|
|
expect(inspected.isError).not.toBe(true);
|
|
const managed = parseEvidence(inspected.structuredContent);
|
|
const native = signatureEvidence();
|
|
const input = {
|
|
managed_boundaries: managed,
|
|
native_observations: [native],
|
|
};
|
|
|
|
const mcp = await client.callTool({
|
|
name: "verify_managed_native_boundaries",
|
|
arguments: input,
|
|
});
|
|
expect(mcp.isError, JSON.stringify(mcp.content)).not.toBe(true);
|
|
const mcpResult = managedNativeVerificationResultSchema.parse(
|
|
parseEvidence(mcp.structuredContent).normalized_result,
|
|
);
|
|
|
|
const request = join(root, "verify.json");
|
|
await writeFile(request, JSON.stringify(input));
|
|
const cliRun = await cli.run({
|
|
arguments: ["verify-managed-native-boundaries", request, "--json"],
|
|
});
|
|
expect(cliRun.exitCode, cliRun.stderr).toBe(0);
|
|
const cliResult = managedNativeVerificationResultSchema.parse(
|
|
parseEvidence(cliRun.json).normalized_result,
|
|
);
|
|
|
|
expect(mcpResult).toEqual(cliResult);
|
|
expect(mcpResult).toMatchObject({
|
|
native_observations: {
|
|
total: 1,
|
|
accepted: 0,
|
|
unsupported: 1,
|
|
symbols: 0,
|
|
},
|
|
summary: { unresolved: 1 },
|
|
pinvoke_imports: [
|
|
expect.objectContaining({ basis: "unsupported-native-evidence" }),
|
|
],
|
|
coverage: { status: "partial" },
|
|
evidence_links: [managed.evidence_id, native.evidence_id],
|
|
});
|
|
expect(mcpResult.limitations).toContain(
|
|
"Some native Evidence operations were unsupported by this workflow.",
|
|
);
|
|
|
|
const tampered = await client.callTool({
|
|
name: "verify_managed_native_boundaries",
|
|
arguments: {
|
|
...input,
|
|
native_observations: [{ ...native, operation: "inspect_macho" }],
|
|
},
|
|
});
|
|
expect(parseMcpToolError(tampered)).toMatchObject({
|
|
error: { code: "evidence_integrity_mismatch" },
|
|
});
|
|
},
|
|
60_000,
|
|
);
|