fix(cli): route app bundles with trailing separators to native analysis (#3511)

This commit is contained in:
Wade authored and GitHub committed 2026-10-15 15:55:44 +09:00
1 parent c61a24b8c5
commit d94ef22d70
2 files changed
+54 -1

No files matched your search

+2 -1
View File
@@ -235,7 +235,8 @@ const routesToJavaScriptAnalysis = async (
const isJavaScriptApplicationPath = async (path: string): Promise<boolean> => {
const lower = path.toLowerCase();
if (lower.endsWith(".asar")) return true;
if (lower.endsWith(".app")) return false;
// `A.app/` and `A.app/.` name the same bundle as `A.app`.
if (lower.replace(/(?:\/\.?)+$/u, "").endsWith(".app")) return false;
try {
return (await stat(path)).isDirectory();
} catch (cause: unknown) {
@@ -0,0 +1,52 @@
import { mkdir, writeFile } from "node:fs/promises";
import { join } from "node:path";
import { describe, expect } from "vitest";
import { thinMach } from "../../../src/domain/binaryTarget.fixture.js";
import { createTestTempDirectory } from "../../fixtures/temporaryDirectory.js";
import { cliTest } from "../../support/cli/cliFixture.js";
// An unknown standing provider stops native analysis before any engine runs.
const environment = {
REA_LOG_LEVEL: "silent",
REA_ANALYSIS_PROVIDER: "missing-provider",
} as const;
const fixtureApp = async () => {
const directory = await createTestTempDirectory("rea-analyze-app-path-");
const contents = join(directory, "Sample.app", "Contents");
await mkdir(join(contents, "MacOS"), { recursive: true });
await writeFile(
join(contents, "MacOS/Sample"),
thinMach(0xfeedfacf, 0x100000c),
);
await writeFile(
join(contents, "Info.plist"),
"<plist><dict><key>CFBundleExecutable</key><string>Sample</string></dict></plist>",
);
return directory;
};
describe("analyze app bundle path spellings", () => {
cliTest.for(["Sample.app", "Sample.app/", "Sample.app/.", "Sample.app//"])(
"routes %s to native provider selection",
async (path, { cli }) => {
const cwd = await fixtureApp();
const result = await cli.run({
arguments: ["analyze", path, "--json"],
cwd,
environment,
});
expect(result.exitCode).toBe(1);
expect(result.json).toMatchObject({
code: "capability_unavailable",
details: {
operation: "open_binary",
selection_reason: "unknown_provider",
requested_provider_id: "missing-provider",
},
});
},
);
});