Files
rea/tests/acceptance/applications/appleLaunchdPlists.test.ts
T
morluto 5d6029ea62 fix(apple): derive launchd domains from owning directories
Use the matched Contents/Library/LaunchAgents or LaunchDaemons suffix to
select a plist's domain. Remove the independent scan of every ancestor.
Keep regular-file, application-root, sidecar and suffix admission rules.

Adapt @bnkaiteam's proposal and ZIP boundary regression from PR #3504,
adding public CLI/stdio MCP controls for nested bundles, case variants,
misleading ancestors and excluded paths.

Validation: 53 focused checks, build, check:fast and docs:check pass.
Two new controls fail before the fix. 12 completed actual built CLI cost
controls preserve the ordinary reply and projection ID byte for byte.
No heavy profiling, target or real deep-provider execution; npm release
and whole-agent costs remain unverified.

Fixes #3353
2026-10-17 20:10:12 +08:00

94 lines
3.4 KiB
TypeScript

import { writeFile } from "node:fs/promises";
import { join } from "node:path";
import { TextReader, Uint8ArrayWriter, ZipWriter } from "@zip.js/zip.js";
import { expect } from "vitest";
import { appleApplicationProjectionResultSchema } from "../../../src/domain/apple/appleApplication.js";
import { compareUnicodeCodePoints } from "../../../src/domain/unicodeCodePointOrder.js";
import { parseEvidence } from "../../../src/domain/evidence.js";
import { connectLocalToolsMcp } from "../../fixtures/localToolsMcp.js";
import { createTestTempDirectory } from "../../fixtures/temporaryDirectory.js";
import { cliTest } from "../../support/cli/cliFixture.js";
cliTest(
"Apple launchd domains follow their owning directory through CLI and MCP",
async ({ cli }) => {
const root = await createTestTempDirectory("rea-apple-launchd-cli-");
const environment = { HOME: root, USERPROFILE: root };
const expected = [
[
"LaunchDaemons/Sample.app/Contents/Library/LaunchAgents/agent.plist",
"agent",
],
[
"LaunchDaemons/Sample.app/Contents/Resources/LaunchDaemons/Nested.app/Contents/Library/LaunchAgents/nested.plist",
"agent",
],
[
"LaunchAgents/Other.app/Contents/Library/LaunchDaemons/daemon.plist",
"daemon",
],
[
"launchdaemons/Case.app/contents/library/launchagents/mixed.plist",
"agent",
],
] as const;
const writer = new ZipWriter(new Uint8ArrayWriter());
for (const [path] of expected)
await writer.add(path, new TextReader("<plist/>"));
for (const path of [
"LaunchDaemons/Sample.app/Contents/Library/LaunchAgents/nested/ignored.plist",
"LaunchDaemons/Sample.app/Contents/Library/LaunchAgents/not-a-plist",
"Contents/Library/LaunchAgents/unrooted.plist",
"__MACOSX/Sample.app/Contents/Library/LaunchAgents/sidecar.plist",
])
await writer.add(path, new TextReader("<plist/>"));
await writer.add(
"LaunchDaemons/Sample.app/Contents/Library/LaunchAgents/directory.plist/",
undefined,
{ directory: true },
);
const path = join(root, "Launchd.zip");
await writeFile(path, await writer.close());
const inspected = await cli.run({
arguments: ["inspect-artifact", path, "--json"],
environment,
});
expect(inspected.exitCode, inspected.stderr).toBe(0);
const source = parseEvidence(inspected.json);
const input = { inventory_evidence: [source] };
const projected = await cli.run({
arguments: [
"project-apple-application-graph",
JSON.stringify(input),
"--json",
],
environment,
});
expect(projected.exitCode, projected.stderr).toBe(0);
const evidence = parseEvidence(projected.json);
const result = appleApplicationProjectionResultSchema.parse(
evidence.normalized_result,
);
expect(
result.components.launchd_plists.map(({ path, domain }) => [
path,
domain,
]),
).toEqual(
[...expected].sort(([left], [right]) =>
compareUnicodeCodePoints(left, right),
),
);
expect(result.coverage).toEqual({
status: "complete-within-inventory",
inventory_complete: true,
});
const { call } = await connectLocalToolsMcp(environment);
const mcp = await call("project_apple_application_graph", input);
expect(mcp.isError).not.toBe(true);
expect(parseEvidence(mcp.structuredContent)).toEqual(evidence);
},
);