Files
rea/tests/composition/directAnalysisFactories.test.ts
T

232 lines
7.7 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 { createAnalysisProfile } from "../../src/domain/analysisProfile.js";
import {
createBinarySessionTargets,
createTestBinarySession,
} from "../fixtures/binarySession.js";
const recordingFactories = (
failure?: Error,
profile?: ReturnType<typeof createAnalysisProfile>,
) => {
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));
},
}),
profile === undefined
? {}
: {
resolveAnalysisProfile: () =>
Promise.resolve(resultOk({ profile })),
},
);
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);
},
);
});
it("preserves a managed execution profile in direct analysis Evidence", async () => {
const [path] = await createBinarySessionTargets();
const profile = createAnalysisProfile(
{
id: "fixture",
name: "Fixture analysis provider",
version: "1",
},
{ fixture: true },
);
const factories = recordingFactories(undefined, profile);
const evidence = await runProviderAnalysis(
factories.dependencies,
path,
"inspect_managed_artifact",
{},
);
expect(evidence).toMatchObject({ analysis_profile: profile });
});