Files
rea/tests/composition/directAnalysisFactories.test.ts
T
morluto 060587b456 fix(cli): prefer native byte inspection for automatic dispatch metadata
Allow the composed one-shot dispatch workflow to open a covered Mach-O
without selecting a deep provider. The registry still owns selector
precedence; explicit request/environment choices remain binding, while
non-Mach-O and unsupported hosts retain deep symbol fallback. Requested
snapshots keep ordinary binding and profile semantics.

Share runtime composition and target admission with the native byte reader.
Keep target parsing, resource ownership and Evidence on the original session.

Validation: 13 focused files, 192 passed and 2 skipped; npm run check passed.
The six previously blocked native property CLI controls now pass. Ten measured
CLI workflows preserved exact metadata facts; warm raw reply token medians
1344/927, elapsed .475/.547s, CPU .691/.745s, sampled family RSS351.2/359.3MiB
baseline/candidate. Baseline used explicit Ghidra workaround; true cold and
full-agent costs unmeasured. No speed/memory improvement or Windows claim.

Refs #4555
2026-10-17 03:11:32 +08:00

200 lines
6.8 KiB
TypeScript

import { parseConfig } from "../../src/config/parseConfig.js";
import { ok as resultOk } from "../../src/domain/result.js";
import { describe, expect, it } from "vitest";
import {
runDirectAnalysis,
runProviderAnalysis,
runManagedProviderExecution,
} from "../../src/application/DirectAnalysis.js";
import type { DirectAnalysisDependencies } from "../../src/application/DirectAnalysisDependencies.js";
import type { NativeToolName } from "../../src/contracts/native/nativeToolContracts.js";
import type { BinarySession } from "../../src/application/binary/BinarySession.js";
import { observed } from "../fixtures/analysisExecution.js";
import {
createBinarySessionTargets,
createTestBinarySession,
} from "../fixtures/binarySession.js";
const recordingFactories = (failure?: Error) => {
const sessions: BinarySession[] = [];
let clientsClosed = 0;
const createSession = () => {
const session = createTestBinarySession(() => ({
execute: (operation) => {
if (failure !== undefined && operation === "read_bytes")
return Promise.reject(failure);
return Promise.resolve(observed({ operation }));
},
close: () => {
clientsClosed += 1;
return Promise.resolve(resultOk(null));
},
}));
sessions.push(session);
return session;
};
const dependencies: DirectAnalysisDependencies = {
readConfiguration: () => parseConfig({}),
createBinarySession: createSession,
createArtifactBinarySession: createSession,
createNativeDispatchBinarySession: createSession,
createNativeBinarySession: createSession,
createManagedBinarySession: createSession,
};
return { dependencies, sessions, clientsClosed: () => clientsClosed };
};
describe("one-shot analysis factory boundary", () => {
it("preserves thrown failures while releasing clients and cancellation listeners", async () => {
const [path] = await createBinarySessionTargets();
const failure = new Error("fixture execution failed");
const factories = recordingFactories(failure);
const interruptListeners = process.listenerCount("SIGINT");
const terminateListeners = process.listenerCount("SIGTERM");
await expect(
runDirectAnalysis(factories.dependencies, path, "read_bytes", {}),
).rejects.toBe(failure);
expect(factories.clientsClosed()).toBe(1);
expect(process.listenerCount("SIGINT")).toBe(interruptListeners);
expect(process.listenerCount("SIGTERM")).toBe(terminateListeners);
expect(factories.sessions[0]?.activeTarget()).toBeUndefined();
});
it("does not acquire a client after cancellation before target opening", async () => {
const [path] = await createBinarySessionTargets();
const factories = recordingFactories();
const controller = new AbortController();
controller.abort();
const result = await runDirectAnalysis(
factories.dependencies,
path,
"read_bytes",
{},
{ signal: controller.signal },
);
expect(result).toMatchObject({
error: "Analysis failed",
code: "cancelled",
});
expect(factories.clientsClosed()).toBe(0);
expect(factories.sessions[0]?.activeTarget()).toBeUndefined();
});
it("keeps managed execution independent of native construction", async () => {
const [path] = await createBinarySessionTargets();
const factories = recordingFactories();
const managedDependencies = {
...factories.dependencies,
readConfiguration: () => {
throw new Error("native configuration must stay unused");
},
createBinarySession: () => {
throw new Error("native factory must stay unused");
},
};
const result = await runManagedProviderExecution(
managedDependencies,
path,
"inspect_managed_artifact",
);
expect(result).toMatchObject({
ok: true,
value: { result: { operation: "inspect_managed_artifact" } },
});
expect(factories.clientsClosed()).toBe(1);
expect(factories.sessions[0]?.activeTarget()).toBeUndefined();
});
it.each([undefined, "/fixture/committed.snapshot"])(
"selects the dispatch inspection factory only without a requested snapshot (%s)",
async (snapshotPath) => {
const factories = recordingFactories();
const expected = new Error("selected factory");
const unexpected = (): never => {
throw new Error("wrong session policy");
};
const selected = (): never => {
throw expected;
};
await expect(
runDirectAnalysis(
{
...factories.dependencies,
createBinarySession:
snapshotPath === undefined ? unexpected : selected,
createNativeDispatchBinarySession:
snapshotPath === undefined ? selected : unexpected,
},
"/fixture/target",
"inspect_native_dispatch_metadata",
{},
{ snapshotPath },
),
).rejects.toBe(expected);
expect(factories.sessions).toEqual([]);
},
);
it.each([
"inspect_macho",
"inspect_signature",
"list_architectures",
"inspect_plist",
"demangle_swift",
] satisfies readonly NativeToolName[])(
"runs %s without reading deep-engine configuration or constructing its session",
async (tool) => {
const [path] = await createBinarySessionTargets();
const factories = recordingFactories();
const unexpected = (): never => {
throw new Error("unrelated session factory must stay unused");
};
const arguments_ =
tool === "demangle_swift" ? { symbols: ["$s4Test3fooyyF"] } : {};
const result = await runProviderAnalysis(
{
...factories.dependencies,
readConfiguration: unexpected,
createBinarySession: unexpected,
createArtifactBinarySession: unexpected,
createManagedBinarySession: unexpected,
},
path,
tool,
arguments_,
);
expect(result).toMatchObject({
operation: tool,
normalized_result: { operation: tool },
});
expect(factories.clientsClosed()).toBe(1);
expect(factories.sessions[0]?.activeTarget()).toBeUndefined();
},
);
it.each([
"observe_native_ui",
"capture_native_ui_scenario",
"observe_native_calls",
] satisfies readonly NativeToolName[])(
"keeps %s on the ordinary session route",
async (tool) => {
const [path] = await createBinarySessionTargets();
const factories = recordingFactories();
const result = await runProviderAnalysis(
{
...factories.dependencies,
createNativeBinarySession: () => {
throw new Error("static inspection factory must stay unused");
},
},
path,
tool,
{},
);
expect(result).toMatchObject({ operation: tool });
expect(factories.clientsClosed()).toBe(1);
},
);
});