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
This commit is contained in:
morluto authored and GitHub committed 2026-11-10 05:11:20 -05:00
1 parent 55b6d2ca20
commit cb4e5cfbff
515 files changed
+21066 -3637

No files matched your search

+55 -51
View File
@@ -1,13 +1,15 @@
import { readFile, writeFile } from "node:fs/promises";
import { z } from "zod";
import { readStableArtifact } from "../../artifacts/readStableArtifact.js";
import { WEB_NETWORK_CAPTURE_LIMITS } from "../../domain/webNetworkCapture.js";
import { webNetworkCaptureBudgetsSchema } from "../../domain/webNetworkCapture.js";
import { captureBudgets, withCaptureBudgets } from "./CaptureBudgets.js";
import { CaptureFormatError } from "./CaptureFormatError.js";
const requestSchema = z.strictObject({
snapshot_path: z.string(),
reply_path: z.string(),
sensitive_values: z.array(z.string().min(1)),
budgets: webNetworkCaptureBudgetsSchema,
});
/** Parse untrusted captures in an owned heap and return one complete bounded reply. */
@@ -16,56 +18,58 @@ const main = async (): Promise<void> => {
const request = requestSchema.parse(
JSON.parse(await readFile(process.argv[2] ?? "", "utf8")),
);
let reply: unknown;
try {
let value;
if (format !== "saz") {
const { decodeCaptureText } = await import("./CaptureJson.js");
const decoder =
format === "har"
? (await import("./HarCapture.js")).decodeHarCapture
: (await import("./QlogCapture.js")).decodeQlogCapture;
const snapshot = await readStableArtifact(
request.snapshot_path,
WEB_NETWORK_CAPTURE_LIMITS.inputBytes,
);
value = decoder(
decodeCaptureText(snapshot.bytes, format === "har" ? "HAR" : "qlog"),
request.sensitive_values,
);
} else {
const { decodeSazCapture } = await import("./SazCapture.js");
value = await decodeSazCapture(
request.snapshot_path,
request.sensitive_values,
);
await withCaptureBudgets(request.budgets, async () => {
let reply: unknown;
try {
let value;
if (format !== "saz") {
const { decodeCaptureText } = await import("./CaptureJson.js");
const decoder =
format === "har"
? (await import("./HarCapture.js")).decodeHarCapture
: (await import("./QlogCapture.js")).decodeQlogCapture;
const snapshot = await readStableArtifact(
request.snapshot_path,
captureBudgets().inputBytes,
);
value = decoder(
decodeCaptureText(snapshot.bytes, format === "har" ? "HAR" : "qlog"),
request.sensitive_values,
);
} else {
const { decodeSazCapture } = await import("./SazCapture.js");
value = await decodeSazCapture(
request.snapshot_path,
request.sensitive_values,
);
}
reply = { ok: true, value };
} catch (cause: unknown) {
reply =
cause instanceof CaptureFormatError
? {
ok: false,
reason: cause.reason,
message: cause.message,
pointer: cause.pointer,
}
: {
ok: false,
reason: "decoder",
message: `Capture decoder failed unexpectedly (${cause instanceof Error ? cause.name : "unknown exception"}).`,
pointer: "",
};
}
reply = { ok: true, value };
} catch (cause: unknown) {
reply =
cause instanceof CaptureFormatError
? {
ok: false,
reason: cause.reason,
message: cause.message,
pointer: cause.pointer,
}
: {
ok: false,
reason: "decoder",
message: `Capture decoder failed unexpectedly (${cause instanceof Error ? cause.name : "unknown exception"}).`,
pointer: "",
};
}
let text = JSON.stringify(reply);
if (Buffer.byteLength(text) > WEB_NETWORK_CAPTURE_LIMITS.outputBytes)
text = JSON.stringify({
ok: false,
reason: "limit",
message:
"Capture reply exceeds the complete-evidence output budget. This release has no runtime override.",
pointer: "",
});
await writeFile(request.reply_path, text, { flag: "wx", mode: 0o600 });
let text = JSON.stringify(reply);
if (Buffer.byteLength(text) > captureBudgets().outputBytes)
text = JSON.stringify({
ok: false,
reason: "limit",
message:
"Capture reply exceeds max_reply_bytes; raise that per-call allowance and retry after cleanup.",
pointer: "",
});
await writeFile(request.reply_path, text, { flag: "wx", mode: 0o600 });
});
};
await main();