Files
reverse-engineering-anything/scripts/verify/analysis/source-location-delivery/task.mjs
T
morluto cb4e5cfbff feat(analysis): make resource budgets recoverable across CLI and MCP (#9706)
* refactor(analysis): centralize resource budgets and recovery facts

* feat(analysis): expose ASAR and Ghidra runtime admission controls

* feat(artifacts): expose reader admission and preserve limited recognition

* feat(javascript): expose recoverable semantic precision budgets

* feat(web): add recoverable source-map budgets and compact retained views

* feat(web): make historical capture decoding budgets recoverable

* fix(desktop): enforce selected view policies across capture and export

* feat(runtime): make Frida and LLDB retention budgets selectable

* feat(native): expose diagnostic budgets and preserve exhaustion causes

* feat(managed): expose recoverable snapshot and representation budgets

* feat(metadata): make Go and Rust inspection budgets recoverable

* feat(wasm): expose representation and producer admissions

* feat(evm): expose per-call worker resource budgets

* feat(android): make resource and string-pool omissions recoverable

* feat(producers): expose command and recorded-capture budgets

* docs(analysis): record recovery contracts and integrated validation

* fix(docs): link calibration oracle from published verification pages

* fix(docs): restore desktop task anchors and receipt links

* test(analysis): align fixtures with selectable budget contracts

* fix(analysis): remove source-location projector dependency cycle

* test(analysis): refresh budget recovery and verifier regressions

* test(analysis): preserve format and publication recovery expectations

* test(windows): align conformance with owned runtime admission

* fix(desktop): preserve selected alias kinds in exported state

* test(analysis): align provider fixtures with recoverable budgets

* test(desktop): validate emitted alias metadata structurally

* fix(ghidra): classify bounded Windows endpoint refusals

* test(cli): assert selectable artifact admission recovery

* fix(cli): preserve capture provenance in environment builds
2026-11-10 05:11:20 -05:00

427 lines
13 KiB
JavaScript

import { spawn } from "node:child_process";
import { readFile, writeFile } from "node:fs/promises";
import { createHash } from "node:crypto";
import assert from "node:assert/strict";
import { isAbsolute, join, relative, resolve, sep } from "node:path";
// Acquire artifactDir with docs/verification/source-map-budgets-2026-11-09/acquire.py.
// This driver runs the public compiled stdio workflow; no target application is executed.
const [rootArgument, configText, ...extra] = process.argv.slice(2);
assert(
rootArgument && configText && extra.length === 0,
"Usage: node task.mjs REPO_ROOT CONFIG_JSON",
);
const root = resolve(rootArgument);
const config = JSON.parse(configText);
assert(
config && typeof config === "object" && !Array.isArray(config),
"CONFIG_JSON must be an object",
);
const allowed = new Set([
"artifactDir",
"select",
"detail",
"resultPath",
"exportPath",
"maxResponseBytes",
]);
assert(
Object.keys(config).every((key) => allowed.has(key)),
"Unknown task configuration field",
);
assert(
typeof config.artifactDir === "string" && isAbsolute(config.artifactDir),
"artifactDir must be an absolute acquired-artifact directory",
);
assert(
typeof config.select === "string" &&
config.select.length > 0 &&
config.select.length <= 256,
"select must be a nonempty artifact filename selector, at most 256 characters",
);
assert(
config.detail === "complete" || config.detail === "summary",
"detail must be complete or summary",
);
for (const key of ["resultPath", "exportPath"]) {
assert(
config[key] === undefined ||
(typeof config[key] === "string" && isAbsolute(config[key])),
`${key} must be an absolute path when selected`,
);
}
const MAX_LINE_BYTES = 32 * 1024 * 1024;
const RPC_TIMEOUT_MS = 45000;
assert(
config.maxResponseBytes === undefined ||
(Number.isSafeInteger(config.maxResponseBytes) &&
config.maxResponseBytes >= 10 * 1024 * 1024 &&
config.maxResponseBytes <= MAX_LINE_BYTES),
"maxResponseBytes must fit the driver receive guard: integer 10..32 MiB",
);
const sources = JSON.parse(
await readFile(join(config.artifactDir, "artifacts.json"), "utf8"),
);
assert(
Array.isArray(sources),
"artifacts.json must be the retained artifact list",
);
const selected = sources.filter(
(source) =>
typeof source.path === "string" && source.path.includes(config.select),
);
assert.equal(
selected.length,
1,
"select must identify exactly one pinned artifact",
);
const source = selected[0];
assert(
source.generated_script,
"Selected point task requires an acquired generated script and analyst manifest",
);
const localFile = (path) => {
assert(
typeof path === "string" && !isAbsolute(path),
"Artifact manifest paths must be relative",
);
const resolved = resolve(config.artifactDir, path);
assert(
!relative(config.artifactDir, resolved).startsWith(".." + sep) &&
resolved !== resolve(config.artifactDir, ".."),
"Artifact path must stay within artifactDir",
);
return resolved;
};
const mapPath = localFile(source.path);
const bytes = await readFile(mapPath);
assert.equal(bytes.length, source.bytes);
assert.equal(createHash("sha256").update(bytes).digest("hex"), source.sha256);
const artifact = JSON.parse(bytes.toString("utf8"));
const manifestPath = localFile(source.generated_script.path + ".manifest.json");
const child = spawn(process.execPath, [join(root, "scripts/rea.mjs"), "mcp"], {
cwd: root,
env: {
...process.env,
REA_LOG_LEVEL: "silent",
REA_MCP_TOOL_CATALOG_PROFILE: "full",
REA_MCP_INPUT_SCHEMA_PROFILE: "compact",
REA_MCP_OUTPUT_SCHEMA_PROFILE: "full",
...(config.maxResponseBytes === undefined
? {}
: { REA_MCP_MAX_RESPONSE_BYTES: String(config.maxResponseBytes) }),
HOPPER_LAUNCHER_PATH: "/rea-unconfigured-deep-provider/hopper",
GHIDRA_INSTALL_DIR: process.execPath,
},
stdio: ["pipe", "pipe", "pipe"],
});
let buffer = "",
sequence = 0,
stderr = "";
const pending = new Map(),
calls = [];
const failPending = (error) => {
for (const request of pending.values()) request.reject(error);
pending.clear();
};
child.stdout.setEncoding("utf8");
child.stderr.setEncoding("utf8");
child.stderr.on("data", (chunk) => {
stderr = (stderr + chunk).slice(-8192);
});
child.once("error", failPending);
child.once("exit", (code, signal) =>
failPending(
new Error(
`MCP server exited (${String(code)}, ${String(signal)}): ${stderr}`,
),
),
);
child.stdin.on("error", failPending);
child.stdout.on("data", (chunk) => {
try {
buffer += chunk;
assert(
Buffer.byteLength(buffer) < MAX_LINE_BYTES,
"32 MiB RPC line guard exceeded",
);
let end;
while ((end = buffer.indexOf("\n")) >= 0) {
const line = buffer.slice(0, end);
buffer = buffer.slice(end + 1);
if (!line) continue;
const payload = JSON.parse(line),
request = pending.get(payload.id);
if (request) {
pending.delete(payload.id);
request.resolve({ payload, wireBytes: Buffer.byteLength(line) + 1 });
}
}
} catch (error) {
failPending(error);
}
});
const rpc = async (method, params = {}) => {
const request = { jsonrpc: "2.0", id: ++sequence, method, params },
start = performance.now();
const waiting = new Promise((resolveReply, rejectReply) => {
const timer = setTimeout(() => {
pending.delete(request.id);
rejectReply(new Error(`RPC timeout ${method}: ${stderr}`));
}, RPC_TIMEOUT_MS);
pending.set(request.id, {
resolve: (value) => {
clearTimeout(timer);
resolveReply(value);
},
reject: (error) => {
clearTimeout(timer);
rejectReply(error);
},
});
});
child.stdin.write(JSON.stringify(request) + "\n");
const { payload, wireBytes } = await waiting;
assert(!payload.error, JSON.stringify(payload.error));
calls.push({
request,
reply: payload,
wire_bytes: wireBytes,
elapsed_ms: performance.now() - start,
});
return payload.result;
};
const errorOf = (r) =>
r.isError
? JSON.parse(r.content.find((c) => c.type === "text").text).error
: undefined;
const contentOf = (r) => {
assert(!r.isError, JSON.stringify(errorOf(r)));
return r.structuredContent;
};
try {
await rpc("initialize", {
protocolVersion: "2025-03-26",
capabilities: {},
clientInfo: { name: "source-location-completed-task", version: "1" },
});
const initialized = { jsonrpc: "2.0", method: "notifications/initialized" };
child.stdin.write(JSON.stringify(initialized) + "\n");
calls.push({
request: initialized,
reply: null,
wire_bytes: 0,
elapsed_ms: 0,
});
const catalog = await rpc("tools/list");
const definition = catalog.tools.find(
(t) => t.name === "trace_web_source_location",
);
assert(definition);
const args = {
manifest_path: manifestPath,
script_index: 0,
source_map: { path: mapPath, url: source.url },
generated_position: source.point,
...(config.detail === "summary" ? { detail: "summary" } : {}),
};
const initial = await rpc("tools/call", {
name: "trace_web_source_location",
arguments: args,
});
const error = errorOf(initial);
let evidenceId,
report,
metadata = [],
coverage;
if (error) {
assert.equal(error.code, "resource_constraint");
const limits = error.details.reported_limits;
evidenceId = limits.evidence_id;
assert(evidenceId);
const continuation = limits.continuation;
assert(continuation, "new source-location continuation required");
const first = contentOf(
await rpc("tools/call", {
name: continuation.name,
arguments: continuation.arguments,
}),
).normalized_result;
report = first.source_location;
metadata = [...first.items];
coverage = first.coverage;
} else {
const evidence = contentOf(initial),
result = evidence.normalized_result;
if (config.detail === "summary") {
evidenceId = result.parent_evidence_id;
report = result.summary;
metadata = [...report.matches];
coverage = result.coverage;
} else {
assert.equal(
createHash("sha256")
.update(evidence.raw_result.source_map_text)
.digest("hex"),
source.sha256,
"Complete initial MCP response must preserve exact raw map bytes",
);
evidenceId = evidence.evidence_id;
report = result;
metadata = [...report.matches];
coverage = { exhausted: true };
}
}
const reference = { kind: "retained-evidence", evidence_id: evidenceId };
while (!coverage.exhausted) {
const page = contentOf(
await rpc("tools/call", {
name: "inspect_analysis_view",
arguments: {
source: reference,
view: {
kind: "source-location",
collection: "matches",
offset: coverage.next_offset,
limit: 64,
},
},
}),
).normalized_result;
metadata.push(...page.items);
coverage = page.coverage;
}
assert.equal(report.source_map.sha256, source.sha256);
assert.equal(metadata.length, source.expected_matches.length);
const answer = [];
for (let index = 0; index < metadata.length; index++) {
const match = metadata[index],
expected = source.expected_matches[index];
assert.equal(
match.state,
expected.generated_only ? "generated-only" : "mapped",
);
if (match.state === "generated-only") {
answer.push(match);
continue;
}
assert.equal(match.source_index, expected.source_index);
assert.equal(match.reported_source, expected.source);
assert.equal(match.original_position.line, expected.original_line);
assert.equal(match.original_position.column, expected.original_column);
assert.equal(match.content.utf8_sha256, expected.content_sha256);
const full = artifact.sourcesContent[expected.source_index],
point = match.original_position.offset;
assert(point !== null);
let offset = Math.max(0, point - 256);
if (
offset > 0 &&
full.charCodeAt(offset) >= 0xdc00 &&
full.charCodeAt(offset) <= 0xdfff
)
offset--;
let snippet;
if ("text" in match.content) {
assert.equal(
createHash("sha256").update(match.content.text).digest("hex"),
expected.content_sha256,
);
let end = Math.min(full.length, offset + 512);
if (
end < full.length &&
full.charCodeAt(end - 1) >= 0xd800 &&
full.charCodeAt(end - 1) <= 0xdbff
)
end--;
snippet = match.content.text.slice(offset, end);
} else {
const text = contentOf(
await rpc("tools/call", {
name: "inspect_analysis_view",
arguments: {
source: reference,
view: {
kind: "source-location",
collection: "source-text",
match_index: match.match_index,
offset,
limit: 512,
},
},
}),
).normalized_result;
assert.equal(text.match.content.utf8_sha256, expected.content_sha256);
snippet = text.item.text;
}
assert.equal(snippet, full.slice(offset, offset + snippet.length));
assert(offset <= point && offset + snippet.length >= point);
const { text: _text, ...identity } = match.content;
answer.push({
...match,
match_index: index,
content: {
...identity,
code_units: full.length,
snippet: {
offset_utf16: offset,
length_utf16: snippet.length,
text: snippet,
},
},
});
}
let exported = false;
if (config.exportPath) {
const result = await rpc("tools/call", {
name: "export_evidence_bundle",
arguments: { path: config.exportPath },
});
assert(!result.isError);
const bundle = JSON.parse(await readFile(config.exportPath, "utf8"));
const parent = bundle.records.find((r) => r.evidence_id === evidenceId);
assert(parent);
assert.equal(
createHash("sha256")
.update(parent.raw_result.source_map_text)
.digest("hex"),
source.sha256,
);
exported = true;
}
const result = {
config,
evidence_id: evidenceId,
source_map_sha256: source.sha256,
lookup: report.lookup,
matches: answer,
export_verified: exported,
calls: calls.map((c) => ({
method: c.request.method,
tool: c.request.params?.name,
wire_bytes: c.wire_bytes,
elapsed_ms: c.elapsed_ms,
isError: c.reply?.result?.isError ?? false,
})),
};
if (config.resultPath)
await writeFile(
config.resultPath,
JSON.stringify({ config, definition, calls, answer: result }),
{ flag: "wx" },
);
console.log(JSON.stringify(result));
} finally {
child.stdin.end();
if (child.exitCode === null && child.signalCode === null)
await new Promise((resolve, reject) => {
const timer = setTimeout(() => {
child.kill("SIGTERM");
reject(Error("MCP close timeout"));
}, 5000);
child.once("exit", () => {
clearTimeout(timer);
resolve();
});
});
}