Files
reverse-engineering-anything/src/process/capture/ProcessScenarioRuntimeValidation.test.ts
T
morlutoandCursor Agent b4db35f092 fix: bind identity and coverage to the producing rule (#1513)
* fix: bind identity and coverage to the producing rule

Logical paths, container families, examined bytes, path-segment conventions, destination collisions, file-id leases, Mach-O CPU selection, and firmware cleanup now follow the observation that owns each rule.

* fix: fail unmatched Mach-O slices and keep firmware roots independent

A fat target whose architecture lipo did not list now stops before slice tools run. Chained fixups still count unread LC_DYLD_INFO rebase bytes, and a firmware cleanup failure no longer blocks the next workspace.

* test: cover path identity and runtime families at the projection boundary

NFC joins and segment conventions are now asserted by the path resolver, the Apple projection, and a real APK inventory instead of helper unit tests.

* test: expect unread dyld rebase bytes in the Apple dispatch fixture

The legacy LC_DYLD_INFO fixture keeps a rebase range this reader does not decode, so the public CLI and MCP check now requires that partial coverage beside the bind opcodes.

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
2026-10-10 17:14:47 +08:00

74 lines
2.3 KiB
TypeScript

import {
chmod,
mkdir,
mkdtemp,
rm,
symlink,
writeFile,
} from "node:fs/promises";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { expect, it } from "vitest";
import {
resolveExecutable,
resolveProcessScenarioRuntimePaths,
} from "./ProcessScenarioRuntimeValidation.js";
import { parseProcessScenario } from "../../domain/process/processScenario.js";
it("preserves the caller-selected executable symlink for process invocation", async () => {
const root = await mkdtemp(join(tmpdir(), "rea-process-executable-alias-"));
try {
const alias = join(root, "chosen-node");
await symlink(process.execPath, alias);
await expect(resolveExecutable(alias, root, "")).resolves.toBe(alias);
} finally {
await rm(root, { recursive: true, force: true });
}
});
it("resolves a Windows executable through the canonical PATH spelling", async () => {
const root = await mkdtemp(join(tmpdir(), "rea-process-path-"));
try {
const selected = join(root, "selected");
const ambient = join(root, "ambient");
await mkdir(selected);
await mkdir(ambient);
await writeFile(join(selected, "tool.exe"), "");
await chmod(join(selected, "tool.exe"), 0o644);
const scenario = parseProcessScenario({
executable: "tool.exe",
working_directory: root,
environment: { Path: selected },
});
const candidate = join(selected, "tool.exe");
try {
const resolved = await resolveProcessScenarioRuntimePaths(
scenario,
{ PATH: ambient },
"win32",
);
expect(resolved.executable).toBe(candidate);
} catch (cause: unknown) {
const message = cause instanceof Error ? cause.message : String(cause);
expect(message).toContain(candidate);
expect(message).not.toContain(ambient);
}
} finally {
await rm(root, { recursive: true, force: true });
}
});
it("retains the selected missing working directory and OS reason", async () => {
const selected = join(tmpdir(), "rea-process-missing-cwd-unique");
const scenario = parseProcessScenario({
executable: process.execPath,
working_directory: selected,
});
await expect(resolveProcessScenarioRuntimePaths(scenario)).rejects.toThrow(
`working directory could not be resolved: ${selected} (ENOENT)`,
);
});