Files
reverse-engineering-anything/scripts/lib/artifact-e2e.mjs
Kaoru0822andClaude Opus 5.5 ade11fa02d feat(apple): inspect dyld shared caches and resolve system paths
macOS 11 and later ship system libraries only inside the dyld shared
cache. trace_dylib_resolution therefore left every /usr/lib and /System
load undetermined, and REA had no way to see what a cache contains.

inspect_dyld_shared_cache (CLI inspect-dyld-shared-cache) reads a cache
file set selected by path, without an open target. Its pure TypeScript
reader parses modern and legacy dyld_cache_header layouts and reports:
- UUID, architecture, platform, OS version, Mac Catalyst alternate,
  cache type, shared region, max slide;
- every VM mapping;
- each subcache by file suffix, checked by UUID. A missing or
  mismatched subcache makes coverage partial;
- the complete image list.
For each requested install path it reads that image's load commands
through the cache mappings with the existing Mach-O reader.

trace_dylib_resolution accepts an optional shared_cache. Absolute
candidates found in a cache that serves the process's CPU family resolve
with the new outcome and status `shared-cache`. That status also takes
precedence over later in-bundle fallbacks such as a back-deployed
libswiftCore. The result names the cache UUID and OS version it used.

verify:dyld-shared-cache checks every image in the host cache (3,649 on
macOS 26.6), with dependencies and their re-export, weak, upward and
delay-init attributes, against `dyld_info -all_dyld_cache
-linked_dylibs`. It also checks CLI/MCP parity, and that each
shared-cache edge in the fixture trace is a library dyld actually loads.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 11:43:15 +00:00

74 lines
2.7 KiB
JavaScript

import assert from "node:assert/strict";
import { execFile } from "node:child_process";
import { promisify } from "node:util";
import { fileURLToPath } from "node:url";
import { Client } from "@modelcontextprotocol/client";
import { StdioClientTransport } from "@modelcontextprotocol/client/stdio";
const environment = () => ({
PATH: process.env.PATH ?? "/usr/bin:/bin",
REA_LOG_LEVEL: "silent",
REA_ANALYSIS_PROVIDER: "auto",
// Artifact workflows have no deep-provider prerequisite or GUI authority.
HOPPER_LAUNCHER_PATH: "/rea-unconfigured-deep-provider/hopper",
});
/** Execute the compiled CLI with production providers and no test adapters. */
export async function artifactCli(command, target, arguments_ = []) {
return (await artifactCliEvidence(command, target, arguments_))
.normalized_result;
}
/** Execute the compiled CLI and return its complete Evidence record. */
export async function artifactCliEvidence(command, target, arguments_ = []) {
const { stdout } = await promisify(execFile)(
process.execPath,
[
fileURLToPath(new URL("../rea.mjs", import.meta.url)),
command,
target,
...arguments_,
"--json",
],
{ env: environment(), timeout: 60000, maxBuffer: 16 * 1024 * 1024 },
);
const evidence = JSON.parse(stdout);
assert.equal(evidence.error, undefined, stdout);
assert.ok(evidence.normalized_result, "CLI omitted normalized result");
return evidence;
}
/** Run a real stdio MCP subprocess, owning and closing its transport; open `target` unless it is null. */
export async function withArtifactMcp(target, verify) {
const transport = new StdioClientTransport({
command: process.execPath,
args: [fileURLToPath(new URL("../rea.mjs", import.meta.url)), "mcp"],
env: environment(),
stderr: "pipe",
});
const client = new Client({ name: "artifact-real-e2e", version: "1" });
try {
await client.connect(transport);
// Target-free tools pass `null` and need no open session.
if (target !== null) {
const opened = await client.callTool({
name: "open_binary",
arguments: { path: target },
});
assert.notEqual(opened.isError, true, JSON.stringify(opened));
}
await verify(client);
} finally {
await client.close();
await transport.close();
}
}
/** Require a successful structured MCP tool result rather than its text rendering. */
export async function artifactMcpResult(client, name, arguments_ = {}) {
const result = await client.callTool({ name, arguments: arguments_ });
assert.notEqual(result.isError, true, JSON.stringify(result));
assert.ok(result.structuredContent?.result, "MCP omitted structured result");
return result.structuredContent.result;
}