import { Client, InMemoryTransport } from "@modelcontextprotocol/client"; import { createHash } from "node:crypto"; import { describe, expect, it } from "vitest"; import { copyFile, mkdir, readFile, realpath, rm } from "node:fs/promises"; import { join, resolve } from "node:path"; import { createTestTempDirectory } from "./fixtures/temporaryDirectory.js"; import { BinarySession } from "../src/application/BinarySession.js"; import { JAVASCRIPT_APPLICATION_VERSION_COMPARISON_EXAMPLE, JAVASCRIPT_FEATURE_TRACE_FULL_EVIDENCE_EXAMPLE, JAVASCRIPT_FEATURE_TRACE_EXAMPLE, JAVASCRIPT_VERSION_COMPARISON_FULL_EVIDENCE_EXAMPLE, SOURCE_TO_BUNDLE_COMPARISON_EXAMPLE, } from "../src/contracts/javascriptApplicationWorkflowExamples.js"; import { createEvidence } from "../src/domain/evidence.js"; import { createServer } from "../src/server/createServer.js"; import { observed } from "./fixtures/analysisExecution.js"; import { PermissionAuthority } from "../src/application/PermissionAuthority.js"; import { createPermissionPolicy } from "../src/domain/permissionPolicy.js"; import { controlledReplayOutputSchema } from "../src/domain/javascriptReplay.js"; import { nodeCharacterizationPreparationOutputSchema } from "../src/domain/nodeRuntimeCharacterization.js"; import { analyzeJavaScriptApplication } from "../src/application/JavaScriptApplicationService.js"; import { javascriptApplicationAnalysisResultSchema } from "../src/domain/javascriptApplicationAnalysis.js"; import { permissionAuthorityForRoot } from "./fixtures/permissionAuthority.js"; describe("application workflow MCP parity", () => { it("compares exact parser export shapes through full Evidence and session IDs", async () => { const root = await createTestTempDirectory("rea-export-shape-mcp-"); const leftRoot = join(root, "left"); const rightRoot = join(root, "right"); await Promise.all([mkdir(leftRoot), mkdir(rightRoot)]); await Promise.all([ copyFile( resolve("tests/fixtures/replay/parser.mjs"), join(leftRoot, "parser.mjs"), ), copyFile( resolve("tests/fixtures/replay/parser-v2.mjs"), join(rightRoot, "parser.mjs"), ), ]); const authority = await permissionAuthorityForRoot( root, ["investigation_input"], ["investigation_input"], ); const [left, right] = await Promise.all([ analyzeJavaScriptApplication(authority, { input_path: leftRoot, approved: true, }), analyzeJavaScriptApplication(authority, { input_path: rightRoot, approved: true, }), ]); if (!left.ok) throw left.error; if (!right.ok) throw right.error; const session = new BinarySession(() => ({ execute: () => Promise.resolve(observed(null)), close: () => Promise.resolve(), })); const server = createServer(session, session); const client = new Client({ name: "export-shape-test", version: "1" }); const [clientTransport, serverTransport] = InMemoryTransport.createLinkedPair(); const selectors = { left_module_path: "parser.mjs", left_export_name: "default", right_module_path: "parser.mjs", right_export_name: "default", }; try { await server.connect(serverTransport); await client.connect(clientTransport); const full = await client.callTool({ name: "compare_javascript_export_shapes", arguments: { left: left.value, right: right.value, ...selectors }, }); expect(full.isError).not.toBe(true); expect(full.structuredContent).toMatchObject({ result: { summary: { added: 1, removed: 0, changed: 0, unknown: 0 }, changes: [ { status: "added", path: "/depth", right: { availability: "literal", value: 1 }, }, ], }, }); expect(session.exportEvidenceBundle().records).toEqual( expect.arrayContaining([ expect.objectContaining({ operation: "compare_javascript_export_shapes", predicate_type: "rea.javascript-export-shape-comparison/v1", }), ]), ); const byId = await client.callTool({ name: "compare_javascript_export_shapes", arguments: { left_evidence_id: left.value.evidence_id, right_evidence_id: right.value.evidence_id, ...selectors, }, }); expect(byId.isError).not.toBe(true); expect(byId.structuredContent).toMatchObject({ result: { evidence_links: [left.value.evidence_id, right.value.evidence_id], changes: [expect.objectContaining({ path: "/depth" })], }, }); const analyzed = javascriptApplicationAnalysisResultSchema.parse( left.value.normalized_result, ); if (analyzed.schema_version !== 2) throw new TypeError("Expected semantic application Evidence"); const seed = analyzed.semantic_graph.relations[0]?.source_node_id; if (seed === undefined) throw new TypeError("Expected at least one semantic relation"); const semantic = await client.callTool({ name: "trace_javascript_semantics", arguments: { application: left.value, query: { seed: { kind: "semantic-node", node_id: seed }, direction: "forward-influence", include_ambiguous_dynamic_edges: true, }, }, }); expect(semantic.isError).not.toBe(true); expect(semantic.structuredContent).toMatchObject({ result: { schema_version: 1, source_evidence_id: left.value.evidence_id, source_graph_id: analyzed.semantic_graph.graph_id, summary: { retained_seed_matches: 1 }, }, }); } finally { await client.close(); await server.close(); await session.close(); await rm(root, { recursive: true, force: true }); } }); it("traces and compares authenticated graph Evidence in the session", async () => { const session = new BinarySession(() => ({ execute: () => Promise.resolve(observed(null)), close: () => Promise.resolve(), })); const server = createServer(session, session); const client = new Client({ name: "application-workflow-test", version: "1", }); const [clientTransport, serverTransport] = InMemoryTransport.createLinkedPair(); let resourceListChanges = 0; client.setNotificationHandler( "notifications/resources/list_changed", () => { resourceListChanges += 1; }, ); try { await server.connect(serverTransport); await client.connect(clientTransport); const traced = await client.callTool({ name: "trace_application_feature", arguments: JAVASCRIPT_FEATURE_TRACE_FULL_EVIDENCE_EXAMPLE, }); expect(traced.isError).not.toBe(true); expect(traced.structuredContent).toMatchObject({ result: { schema_version: 1, coverage: { status: expect.any(String) }, }, }); const compared = await client.callTool({ name: "compare_application_versions", arguments: { ...JAVASCRIPT_VERSION_COMPARISON_FULL_EVIDENCE_EXAMPLE, unknown_registry_approved: true, }, }); expect(compared.isError).not.toBe(true); expect(compared.structuredContent).toMatchObject({ result: { schema_version: 1, summary: { unknown: expect.any(Number) }, coverage: { status: expect.any(String) }, }, }); const sourceCompared = await client.callTool({ name: "compare_source_to_bundle", arguments: { reference: SOURCE_TO_BUNDLE_COMPARISON_EXAMPLE.reference, application: JAVASCRIPT_FEATURE_TRACE_FULL_EVIDENCE_EXAMPLE.application, }, }); expect(sourceCompared.isError).not.toBe(true); expect(sourceCompared.structuredContent).toMatchObject({ result: { schema_version: 1, reference: { root_sha256: SOURCE_TO_BUNDLE_COMPARISON_EXAMPLE.reference.root_sha256, }, scoring: { algorithm: "rea-source-to-bundle-signals/v1" }, }, }); expect(session.exportEvidenceBundle().records.length).toBeGreaterThan(2); await new Promise((resolve) => setImmediate(resolve)); const notificationsBeforeIdReuse = resourceListChanges; const tracedById = await client.callTool({ name: "trace_application_feature", arguments: { ...JAVASCRIPT_FEATURE_TRACE_EXAMPLE, application_evidence_id: JAVASCRIPT_FEATURE_TRACE_FULL_EVIDENCE_EXAMPLE.application .evidence_id, }, }); expect(tracedById.isError).not.toBe(true); await new Promise((resolve) => setImmediate(resolve)); expect(resourceListChanges).toBe(notificationsBeforeIdReuse); const comparedById = await client.callTool({ name: "compare_application_versions", arguments: { ...JAVASCRIPT_APPLICATION_VERSION_COMPARISON_EXAMPLE, left_evidence_id: JAVASCRIPT_VERSION_COMPARISON_FULL_EVIDENCE_EXAMPLE.left .evidence_id, right_evidence_id: JAVASCRIPT_VERSION_COMPARISON_FULL_EVIDENCE_EXAMPLE.right .evidence_id, }, }); expect(comparedById).toMatchObject({ structuredContent: { result: { evidence_links: expect.arrayContaining([ JAVASCRIPT_VERSION_COMPARISON_FULL_EVIDENCE_EXAMPLE.left .evidence_id, JAVASCRIPT_VERSION_COMPARISON_FULL_EVIDENCE_EXAMPLE.right .evidence_id, ]), }, }, }); const sourceComparedById = await client.callTool({ name: "compare_source_to_bundle", arguments: { ...SOURCE_TO_BUNDLE_COMPARISON_EXAMPLE, application_evidence_id: JAVASCRIPT_FEATURE_TRACE_FULL_EVIDENCE_EXAMPLE.application .evidence_id, }, }); expect(sourceComparedById.isError).not.toBe(true); const missing = await client.callTool({ name: "trace_application_feature", arguments: JAVASCRIPT_FEATURE_TRACE_EXAMPLE, }); expect(missing).toMatchObject({ isError: true, structuredContent: { error: { details: { reason: "missing" } }, }, }); const wrongOperation = createEvidence( undefined, { id: "fixture", name: "Fixture", version: "1" }, { operation: "inventory_artifact", parameters: {}, result: {} }, ); const wrongPredicate = createEvidence( undefined, { id: "fixture", name: "Fixture", version: "1" }, { predicateType: "fixture.application/v1", operation: "analyze_javascript_application", parameters: {}, result: {}, }, ); expect(session.recordEvidence(wrongOperation).ok).toBe(true); expect(session.recordEvidence(wrongPredicate).ok).toBe(true); for (const [record, reason] of [ [wrongOperation, "wrong_operation"], [wrongPredicate, "wrong_predicate"], ] as const) { const rejected = await client.callTool({ name: "trace_application_feature", arguments: { ...JAVASCRIPT_FEATURE_TRACE_EXAMPLE, application_evidence_id: record.evidence_id, }, }); expect(rejected).toMatchObject({ isError: true, structuredContent: { error: { details: { reason } } }, }); } const duplicateNative = await client.callTool({ name: "trace_application_feature", arguments: { ...JAVASCRIPT_FEATURE_TRACE_FULL_EVIDENCE_EXAMPLE, native_observations: [ JAVASCRIPT_FEATURE_TRACE_FULL_EVIDENCE_EXAMPLE.application, ], native_observation_evidence_ids: [ JAVASCRIPT_FEATURE_TRACE_FULL_EVIDENCE_EXAMPLE.application .evidence_id, ], }, }); expect(duplicateNative.isError).toBe(true); const spoofed = await client.callTool({ name: "trace_application_feature", arguments: { ...JAVASCRIPT_FEATURE_TRACE_FULL_EVIDENCE_EXAMPLE, application: { ...JAVASCRIPT_FEATURE_TRACE_FULL_EVIDENCE_EXAMPLE.application, provider: { id: "spoofed", name: "spoofed", version: "1" }, }, }, }); expect(spoofed.isError).toBe(true); } finally { await client.close(); await server.close(); await session.close(); } }); it("plans and executes the same controlled replay contract", async () => { const root = resolve("tests/fixtures/replay"); const policy = { enabled: true, roots: [root], nodePath: process.execPath, bubblewrapPath: process.execPath, systemdRunPath: process.execPath, systemctlPath: process.execPath, shellPath: process.execPath, }; const ceiling = { capability: "javascript_replay" as const, roots: [root], executables: [ policy.nodePath, policy.bubblewrapPath, policy.systemdRunPath, policy.systemctlPath, policy.shellPath, ], environment_names: [], network: "none" as const, mount: true, }; const authority = new PermissionAuthority( createPermissionPolicy( [ceiling], [ { ...ceiling, grant_id: "administrator:javascript_replay", lifetime: "administrator", operation_identity: null, expires_at: null, }, ], ), ); const session = new BinarySession(() => ({ execute: () => Promise.resolve(observed(null)), close: () => Promise.resolve(), })); const server = createServer(session, session, { permissionAuthority: authority, javascriptReplayPolicy: policy, javascriptReplayHost: { readSource: async (path) => ({ canonicalPath: await realpath(path), bytes: await readFile(path), }), identifyExecutable: async (path) => ({ path, version: "fixture", sha256: "1".repeat(64), }), identifyWorker: async () => ({ path: "/fixture/worker.js", version: "fixture-worker-1", sha256: "2".repeat(64), }), identifyRuntimeClosure: async (path) => [ { sourcePath: path, destinationPath: "/runtime/node", sha256: "1".repeat(64), }, ], seccompDigest: () => "3".repeat(64), probe: async () => undefined, }, javascriptReplayRunner: { execute: async (prepared) => ({ schema_version: 1, plan_digest: prepared.publicPlan.plan_digest, outcomes: [ { case_id: "heading", outcome: "return", value: { type: "heading", text: "Title" }, input_sha256: prepared.publicPlan.cases[0]?.sha256 ?? "0".repeat(64), output_sha256: "2".repeat(64), truncated: false, }, ], stderr: "", termination: "completed", cleanup: { state: "complete", residual_resources: [] }, limitations: ["fixture runner"], reproducer: null, }), }, }); const client = new Client({ name: "replay-parity-test", version: "1" }); const [clientTransport, serverTransport] = InMemoryTransport.createLinkedPair(); const input = { mode: "plan", left: { modules: [ { alias: "parser", path: resolve(root, "parser.mjs"), format: "esm", role: "module", dependencies: {}, }, ], entry_alias: "parser", entry_export: "default", }, cases: [{ case_id: "heading", arguments: ["# Title"] }], approved: false, }; try { await server.connect(serverTransport); await client.connect(clientTransport); const planned = await client.callTool({ name: "run_controlled_replay", arguments: input, }); expect(planned.isError).not.toBe(true); const digest = controlledReplayOutputSchema.parse( planned.structuredContent, ).plan?.plan_digest; expect(digest).toMatch(/^[a-f0-9]{64}$/u); const executed = await client.callTool({ name: "run_controlled_replay", arguments: { ...input, mode: "execute", approved: true, plan_digest: digest, }, }); expect(executed.isError).not.toBe(true); expect(executed.structuredContent).toMatchObject({ phase: "execute", evidence: { authority: "controlled-replay", provider: { id: "rea-javascript-replay" }, }, }); expect(session.exportEvidenceBundle().records).toEqual( expect.arrayContaining([ expect.objectContaining({ authority: "controlled-replay" }), ]), ); const factoryPath = resolve(root, "sanitizer.factory.txt"); const factoryBytes = await readFile(factoryPath); const factorySha256 = createHash("sha256") .update(factoryBytes) .digest("hex"); const characterizationInput = { preparation_approved: true, selected_alias: "bundle", expected_effect: "pure", instrumentation: { artifact_path: factoryPath, artifact_sha256: factorySha256, selection: { byte_start: 0, byte_end: factoryBytes.byteLength, selected_sha256: factorySha256, export_name: "selected", }, }, replay: { mode: "plan", left: { modules: [ { alias: "bundle", path: factoryPath, format: "commonjs-factory", role: "module", dependencies: {}, }, ], entry_alias: "bundle", entry_export: "selected", }, cases: [{ case_id: "heading", arguments: ["# Title"] }], approved: false, }, }; const characterizationPlan = await client.callTool({ name: "prepare_node_characterization", arguments: characterizationInput, }); expect(characterizationPlan.isError).not.toBe(true); const approvedPlan = nodeCharacterizationPreparationOutputSchema.parse( characterizationPlan.structuredContent, ).plan; const characterized = await client.callTool({ name: "execute_node_characterization", arguments: { execution_approved: true, approved_plan_sha256: approvedPlan.plan_sha256, preparation: characterizationInput, }, }); expect(characterized.isError).not.toBe(true); expect(characterized.structuredContent).toMatchObject({ phase: "execution", evidence: { authority: "controlled-replay", provider: { id: "rea-node-characterization" }, }, }); expect(session.exportEvidenceBundle().records).toEqual( expect.arrayContaining([ expect.objectContaining({ predicate_type: "rea.javascript-export-transformation/v1", }), expect.objectContaining({ predicate_type: "rea.runtime-characterization/v1", }), ]), ); } finally { await client.close(); await server.close(); await session.close(); } }); });