Files
reverse-engineering-anything/src/native/NativeMachoVtoolRefusal.test.ts
T
morlutoandCursor Agent c0c3902207 fix(native): preserve Mach-O target selection in macOS tools (#7831)
* fix(native): preserve Mach-O target selection in macOS tools

* fix(native): retain exact Mach-O slice signature coverage

* fix(native): admit x86_64 LIB64 signature selectors

* test(native): match signature checks to actual slices

* fix(native): recognize vtool refusals on private Mach-O aliases

Match vtool's container refusal to the operand the command received so a
parenthesized universal path keeps completed facts and the refusal
limitation. Expect codesign -a only when the target format is universal.

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
2026-10-30 00:03:23 +08:00

113 lines
3.6 KiB
TypeScript

import { expect, it } from "vitest";
import { AnalysisOutputError } from "../domain/analysisErrorCore.js";
import { err, ok } from "../domain/result.js";
import {
NativeFixtureRunner,
nativeMachoTarget,
} from "../../tests/fixtures/nativeCommands.js";
import {
inspectNativeMacho,
VTOOL_CONTAINER_REFUSAL_LIMITATION,
} from "./NativeMachoInspection.js";
import {
inspectionReader,
unreadEncryption,
} from "./NativeMachoInspection.fixture.js";
const inspect = async (options: {
readonly diagnostic: string;
readonly format?: "fat" | "thin";
readonly stdout?: string;
readonly signal?: string | null;
}) => {
const path = "/fixture/universal";
const runner = new NativeFixtureRunner(
options.format === "thin"
? { lipo: `Non-fat file: ${path} is architecture: arm64\n` }
: {},
);
return inspectNativeMacho({
readCommandNames: inspectionReader(),
readEncryption: unreadEncryption,
target: nativeMachoTarget(path),
run: async (tool, args, _signal, acceptNonZeroIf) => {
const result = await runner.run(tool, args);
if (!result.ok || tool !== "vtool") return result;
const refused = {
...result.value,
stdout: options.stdout ?? "",
stdoutBytes: Buffer.byteLength(options.stdout ?? ""),
stderr: options.diagnostic,
stderrBytes: Buffer.byteLength(options.diagnostic),
exitCode: 1,
signal: options.signal ?? null,
};
return acceptNonZeroIf?.(refused)
? ok(refused)
: err(new AnalysisOutputError("inspect_macho", "vtool failed"));
},
invocation: (value) => ({
tool: value.tool,
command: [value.executable, ...value.arguments],
tool_version: value.toolVersion,
version_reason: value.versionReason,
executable_sha256: value.executableSha256,
exit: { code: value.exitCode, signal: value.signal },
stdout_bytes: value.stdoutBytes,
stderr_bytes: value.stderrBytes,
}),
});
};
const refusal = "/usr/bin/vtool error: /fixture/universal file is not mach-o\n";
it("retains required facts and failed vtool provenance for its universal-container refusal", async () => {
const result = await inspect({ diagnostic: refusal });
if (!result.ok) throw result.error;
expect(result.value.limitations).toContain(
VTOOL_CONTAINER_REFUSAL_LIMITATION,
);
expect(result.value.result).toMatchObject({
format: "mach-o-universal",
selected_architecture: { name: "arm64" },
build_metadata: {
items: [{ platform: "MACOS", minimum_os: "13.0", sdk: "14.2" }],
},
dependencies: {
items: [{ path: "/usr/lib/libSystem.B.dylib", kind: "LC_LOAD_DYLIB" }],
},
imports: {
items: expect.arrayContaining([
expect.objectContaining({ name: "__Block_copy" }),
]),
},
exports: {
items: expect.arrayContaining([
expect.objectContaining({ name: "_main" }),
]),
},
uuid: "01234567-89AB-CDEF-0123-456789ABCDEF",
provenance: expect.arrayContaining([
expect.objectContaining({
tool: "vtool",
exit: { code: 1, signal: null },
}),
]),
});
});
it.each([
{ diagnostic: refusal, format: "thin" as const },
{ diagnostic: `${refusal}another error\n` },
{ diagnostic: "/usr/bin/vtool error: /other file is not mach-o\n" },
{ diagnostic: refusal, stdout: "unexpected output" },
{ diagnostic: refusal, signal: "SIGTERM" },
])("does not suppress other vtool failures: $diagnostic", async (options) => {
const result = await inspect(options);
expect(result).toMatchObject({
ok: false,
error: { reason: "vtool failed" },
});
});