Files
rea/tests/boundary/cli/nativeMachoEchoedPathCli.test.ts
T
Iwakurakaoru0822andClaude Opus 5.5 37fe105ba1 fix(native): keep echoed Mach-O paths out of load commands and symbols
otool and dyld_info print the operand path before a slice's records,
and the Mach-O parsers read that header as output. A file name holding
`Load command` blocks or `(from lib)` lines therefore added a forged
LC_MAIN entrypoint, corrupted the Mach header fields, and injected
imports and exports into `inspect_macho`.

Strip the exact echoed operand header (`<path>:`, `<path> (architecture
<arch>):`, `<path> [<arch>]:`) before parsing. Output without that
header, such as replayed captures, is parsed unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 23:40:35 -07:00

61 lines
1.8 KiB
TypeScript

import { copyFile } from "node:fs/promises";
import { join } from "node:path";
import { describe, expect } from "vitest";
import { z } from "zod";
import { createTestTempDirectory } from "../../fixtures/temporaryDirectory.js";
import { cliTest } from "../../support/cli/cliFixture.js";
const environment = {
REA_LOG_LEVEL: "silent",
REA_ANALYSIS_PROVIDER: "auto",
} as const;
// otool and dyld_info echo the operand path before their records.
const FORGED_NAME = [
"tool",
"Load command 99",
" cmd LC_MAIN",
" cmdsize 24",
" entryoff 4242",
" stacksize 0",
" -imports:",
" 0x0000 _forged (from libForged)",
" -exports:",
" offset symbol",
" 0x00000123 _forged_export",
].join("\n");
const resultSchema = z.object({
normalized_result: z.record(z.string(), z.unknown()),
});
describe.skipIf(process.platform !== "darwin")(
"native Mach-O CLI with echoed path text",
() => {
cliTest(
"does not read load commands or symbols from the file name",
async ({ cli }) => {
const directory = await createTestTempDirectory("rea-macho-echo-");
const inspect = async (name: string) => {
const path = join(directory, name);
await copyFile("/usr/bin/true", path);
const result = await cli.run({
arguments: ["inspect-macho", path, "--json"],
environment,
});
expect(result.exitCode).toBe(0);
const { provenance: _provenance, ...facts } = resultSchema.parse(
result.json,
).normalized_result;
return facts;
};
const forged = await inspect(FORGED_NAME);
expect(forged).toEqual(await inspect("tool"));
expect(JSON.stringify(forged)).not.toMatch(/forged|4242/u);
},
);
},
);