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, ) => { 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 }; }; it("requires a durable summary destination before acquiring a managed session", async () => { const factories = recordingFactories(); const result = await runProviderAnalysis( factories.dependencies, "/fixture/missing.dll", "inspect_managed_members", {}, undefined, undefined, { detail: "summary" }, ); expect(result).toMatchObject({ code: "invalid_request", details: { operation: "inspect_managed_members", issues: [{ path: ["evidence_bundle"], reason: "missing_argument" }], }, }); expect(factories.sessions).toEqual([]); }); it.each([ "inspect_macho", "inventory_artifact", "inspect_managed_artifact", ] as const)( "rejects delivery options for %s before selecting a provider", async (tool) => { const factories = recordingFactories(); const invocation = [ factories.dependencies, "/fixture/missing", tool, {}, undefined, undefined, { detail: "summary", evidenceBundlePath: "/fixture/bundle.json" }, ] as const; // @ts-expect-error JavaScript callers can bypass managed-members-only delivery. const result = await runProviderAnalysis(...invocation); expect(result).toMatchObject({ code: "invalid_request", details: { operation: tool, issues: [{ path: ["delivery"], reason: "invalid_value" }], }, }); expect(factories.sessions).toEqual([]); }, ); 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 }); });