mirror of
https://github.com/morluto/rea.git
synced 2026-10-23 14:22:30 -05:00
* fix(native): recover macOS command deadlines Promote native_command_timeout_ms (default 60000), native_ui_deadline_ms (default 180000), and pwntools_timeout_ms (default 30000) as validated per-call settings. Keep cpuSeconds, byte allowances, LLDB grace, and plist probes fixed, and say those caps have no runtime override. Co-authored-by: morluto <morluto@users.noreply.github.com> * fix(native): report the deadline that actually expired Pass the selected native command timeout through xcrun resolution, thread the pwntools deadline into pwndbg failures, and state the selected UI deadline apart from the fixed wait-step cap. SIGXFSZ and EFBIG recovery names the file-size allowance. Co-authored-by: morluto <morluto@users.noreply.github.com> * fix(native): honor the selected deadline on helper stages The UI helper compile and capture subprocesses used fixed 60s and 30s exec timeouts, so a longer native_ui_deadline_ms still failed as a generic provider error. Preparation timeouts reported the 60000 ms default instead of the selected native_command_timeout_ms. Memory resource-constraint recovery names memory again, and the Darwin plist CLI expectation matches the byte-counted input allowance. Co-authored-by: morluto <morluto@users.noreply.github.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: morluto <morluto@users.noreply.github.com>
167 lines
5.3 KiB
TypeScript
167 lines
5.3 KiB
TypeScript
import { createHash } from "node:crypto";
|
|
import { readFile } from "node:fs/promises";
|
|
import type { BinaryTarget } from "../../src/domain/binaryTargetTypes.js";
|
|
import type { InspectSignature } from "../../src/domain/native/nativeInspection.js";
|
|
import { ok } from "../../src/domain/result.js";
|
|
import type {
|
|
NativeCommandCapture,
|
|
NativeCommandOptions,
|
|
NativeCommandRunner,
|
|
} from "../../src/native/CommandRunner.js";
|
|
|
|
/** Replay captured native command outputs through the production runner seam. */
|
|
export class NativeFixtureRunner implements NativeCommandRunner {
|
|
constructor(
|
|
private readonly overrides: Readonly<Record<string, string>> = {},
|
|
private readonly exitCode = 0,
|
|
) {}
|
|
|
|
async run(
|
|
tool: string,
|
|
arguments_: readonly string[],
|
|
_options?: NativeCommandOptions,
|
|
) {
|
|
const output =
|
|
this.overrides[`${tool}:${arguments_[0] ?? ""}`] ??
|
|
this.overrides[tool] ??
|
|
(await outputFor(tool, arguments_));
|
|
return ok({
|
|
...capture(tool, arguments_, output),
|
|
exitCode: this.exitCode,
|
|
});
|
|
}
|
|
}
|
|
|
|
const outputFor = async (
|
|
tool: string,
|
|
arguments_: readonly string[],
|
|
): Promise<string> => {
|
|
if (tool === "lipo") return nativeFixture("lipo-fat.txt");
|
|
if (tool === "otool") return nativeFixture("otool-load.txt");
|
|
if (tool === "nm") return "_main\n_$s4Test3fooyyF\n";
|
|
if (tool === "dyld_info")
|
|
return nativeFixture(
|
|
arguments_[0] === "-imports" ? "dyld-imports.txt" : "dyld-exports.txt",
|
|
);
|
|
if (tool === "dwarfdump")
|
|
return `UUID: 01234567-89AB-CDEF-0123-456789ABCDEF (arm64) ${arguments_.at(-1)}\n`;
|
|
if (tool === "file")
|
|
return arguments_.at(-1)?.endsWith(".plist") === true
|
|
? "XML 1.0 document text\n"
|
|
: "Mach-O 64-bit executable arm64\n";
|
|
if (tool === "vtool") return "Load command 3 LC_BUILD_VERSION\n";
|
|
if (tool === "swift-demangle") return nativeFixture("demangle.txt");
|
|
if (tool === "plutil") return nativeFixture("plist.json");
|
|
if (tool === "codesign") {
|
|
if (arguments_.includes("--entitlements"))
|
|
return nativeFixture("entitlements.xml");
|
|
if (arguments_.includes("-r-"))
|
|
return "designated => identifier com.example.fixture\n";
|
|
return nativeFixture("codesign.txt");
|
|
}
|
|
throw new Error(`Unexpected fixture tool ${tool}`);
|
|
};
|
|
|
|
/**
|
|
* codesign prints display diagnostics to stderr and requirements or
|
|
* entitlements to stdout.
|
|
*/
|
|
const fixtureStreams = (
|
|
tool: string,
|
|
arguments_: readonly string[],
|
|
output: string,
|
|
) => {
|
|
const stderr =
|
|
tool === "codesign" &&
|
|
!arguments_.includes("-r-") &&
|
|
!arguments_.includes("--entitlements");
|
|
return {
|
|
stdout: stderr ? "" : output,
|
|
stderr: stderr ? output : "",
|
|
stdoutBytes: Buffer.byteLength(stderr ? "" : output),
|
|
stderrBytes: Buffer.byteLength(stderr ? output : ""),
|
|
};
|
|
};
|
|
|
|
const capture = (
|
|
tool: string,
|
|
arguments_: readonly string[],
|
|
output: string,
|
|
): NativeCommandCapture => ({
|
|
tool,
|
|
executable: `/usr/bin/${tool}`,
|
|
executableSha256: "a".repeat(64),
|
|
toolVersion: null,
|
|
versionReason: "fixture",
|
|
arguments: [...arguments_],
|
|
...fixtureStreams(tool, arguments_, output),
|
|
exitCode: 0,
|
|
signal: null,
|
|
});
|
|
|
|
/** Build the Mach-O target identity used by native boundary fixtures. */
|
|
export const nativeMachoTarget = (
|
|
path: string,
|
|
sourcePath?: string,
|
|
): BinaryTarget & {
|
|
readonly kind: "executable";
|
|
readonly format: "mach-o";
|
|
} => ({
|
|
path,
|
|
...(sourcePath === undefined ? {} : { sourcePath }),
|
|
sha256: "0".repeat(64),
|
|
kind: "executable",
|
|
format: "mach-o",
|
|
architecture: "arm64",
|
|
availableArchitectures: ["x86_64", "arm64"],
|
|
});
|
|
|
|
/** Register the actual bytes of a filesystem-backed native test target. */
|
|
export const nativeMachoTargetForFile = async (
|
|
path: string,
|
|
sourcePath?: string,
|
|
): Promise<ReturnType<typeof nativeMachoTarget>> => ({
|
|
...nativeMachoTarget(path, sourcePath),
|
|
sha256: createHash("sha256")
|
|
.update(await readFile(path))
|
|
.digest("hex"),
|
|
});
|
|
|
|
/** Load one captured native tool output. */
|
|
export const nativeFixture = (name: string): Promise<string> =>
|
|
readFile(new URL(`./native-macos/${name}`, import.meta.url), "utf8");
|
|
|
|
/** Add consistent Mach command-count metadata to a command-only test capture. */
|
|
export const withOtoolMachHeader = (output: string): string => {
|
|
const count = [...output.matchAll(/^Load command (\d+)$/gmu)].length;
|
|
const sizes = [...output.matchAll(/^\s*cmdsize\s+(\d+)\s*$/gmu)].map(
|
|
([, size]) => Number(size),
|
|
);
|
|
if (sizes.length !== count)
|
|
throw new TypeError("command-only fixture must provide every cmdsize");
|
|
const bytes = sizes.reduce((sum, size) => sum + size, 0);
|
|
return [
|
|
"Mach header",
|
|
" magic cputype cpusubtype caps filetype ncmds sizeofcmds flags",
|
|
` 0xfeedfacf 16777228 0 0x00 2 ${count} ${bytes} 0x00000000`,
|
|
output,
|
|
].join("\n");
|
|
};
|
|
|
|
/** Parsed signature facts for lifecycle controls that do not invoke native tools. */
|
|
export const signatureInspectionFixture = (): InspectSignature => ({
|
|
signed: true,
|
|
identifier: "rea.lifecycle-fixture",
|
|
team_identifier: null,
|
|
format: "Mach-O thin (arm64)",
|
|
cdhashes: ["0123456789abcdef"],
|
|
hash_algorithms: ["sha256"],
|
|
authorities: [],
|
|
designated_requirement: null,
|
|
entitlements: null,
|
|
timestamp: null,
|
|
hardened_runtime: null,
|
|
provenance: [],
|
|
limitations: ["Controlled parsed facts; no native signing tool invoked."],
|
|
});
|