import { mkdtemp, mkdir, rm, writeFile } from "node:fs/promises"; import { tmpdir } from "node:os"; import { join } from "node:path"; import { build } from "plist"; import { afterEach, expect, it } from "vitest"; import { parseConfig } from "../../../src/config/parseConfig.js"; import type { DirectAnalysisDependencies } from "../../../src/application/DirectAnalysisDependencies.js"; import { runProviderAnalysis } from "../../../src/application/DirectAnalysis.js"; import { createArtifactBinarySession, createBinarySession, createManagedBinarySession, createNativeBinarySession, createNativeDispatchBinarySession, } from "../../../src/composition/binary.js"; const temporaryDirectories: string[] = []; afterEach(async () => { await Promise.all( temporaryDirectories .splice(0) .map((path) => rm(path, { recursive: true, force: true })), ); }); it("routes a CLI app resource path through the resource session and preserves null target identity", async () => { const bundlePath = await mkdtemp(join(tmpdir(), "rea-cli-resource-root-")); temporaryDirectories.push(bundlePath); await mkdir(join(bundlePath, "Resources")); await writeFile( join(bundlePath, "Info.plist"), '', ); await writeFile( join(bundlePath, "Resources", "Archive.plist"), build({ $archiver: "NSKeyedArchiver", $version: 100000, $objects: ["$null", "sample"], $top: { root: { UID: 1 } }, }), ); const dependencies: DirectAnalysisDependencies = { readConfiguration: () => parseConfig({}), createBinarySession: (config, logger) => createBinarySession(config, logger, {}), createNativeDispatchBinarySession: (config, logger) => createNativeDispatchBinarySession(config, logger, {}), createArtifactBinarySession: () => createArtifactBinarySession({}, process.platform), createNativeBinarySession: () => createNativeBinarySession({}, process.platform), createManagedBinarySession, }; const result = await runProviderAnalysis( dependencies, bundlePath, "inspect_keyed_archive", { path: "Resources/Archive.plist" }, ); expect(result).toMatchObject({ operation: "inspect_keyed_archive", subject: null, normalized_result: { target_sha256: null, resource_root: { canonical_path: bundlePath, executable_sha256: null }, }, }); }); it("reports resource capabilities from their providers on supported and unsupported hosts", async () => { const rootPath = await mkdtemp(join(tmpdir(), "rea-resource-capabilities-")); temporaryDirectories.push(rootPath); await writeFile(join(rootPath, "Info.plist"), ""); for (const [platform, expected] of [ ["darwin", { plist: true, assets: true }], ["linux", { plist: false, assets: false }], ] as const) { const session = await createArtifactBinarySession({}, platform); const opened = await session.openBundleResources(rootPath); expect(opened.ok, platform).toBe(true); const status = await session.status(); const capabilitySets = ( status as { capabilities: Array<{ groups: Array<{ operations: string[]; available: boolean }>; }>; } ).capabilities; const operationAvailability = new Map( capabilitySets.flatMap(({ groups }) => groups.flatMap(({ operations, available }) => operations.map((operation) => [operation, available] as const), ), ), ); expect(operationAvailability.get("inspect_plist"), platform).toBe( expected.plist, ); expect(operationAvailability.get("inspect_asset_catalog"), platform).toBe( expected.assets, ); expect( operationAvailability.get("decode_interface_builder"), platform, ).toBe(true); expect(operationAvailability.get("inspect_keyed_archive"), platform).toBe( true, ); await session.close(); } });