fix(android): validate explicit Java runtime (#742)

This commit is contained in:
Kaoru0822
2026-10-06 22:25:54 +08:00
committed by GitHub
parent 3f6d6dc756
commit 739039092f
2 changed files with 61 additions and 7 deletions
+17 -7
View File
@@ -30,21 +30,31 @@ export const resolveJadxConfiguration = async (
throw unavailable(
"Set REA_JADX_MCP_JAR to the absolute path of a caller-supplied jadx-headless-mcp 0.7.1 JAR. REA does not download or install it.",
);
const java =
environment.JAVA_HOME === undefined
? "java"
: join(environment.JAVA_HOME, "bin", "java");
try {
await access(jar, constants.R_OK);
if (!(await stat(jar)).isFile())
throw unavailable(`REA_JADX_MCP_JAR is not a regular file: ${jar}`);
return {
jar: await realpath(jar),
java:
environment.JAVA_HOME === undefined
? "java"
: join(environment.JAVA_HOME, "bin", "java"),
};
} catch (cause) {
if (cause instanceof AnalysisCapabilityUnavailableError) throw cause;
throw unavailable(
`Cannot read REA_JADX_MCP_JAR ${jar}: ${cause instanceof Error ? cause.message : String(cause)}`,
);
}
if (environment.JAVA_HOME !== undefined) {
try {
await access(java, constants.R_OK | constants.X_OK);
if (!(await stat(java)).isFile())
throw unavailable(`JAVA_HOME java is not a regular file: ${java}`);
} catch (cause) {
if (cause instanceof AnalysisCapabilityUnavailableError) throw cause;
throw unavailable(
`Cannot execute JAVA_HOME java ${java}: ${cause instanceof Error ? cause.message : String(cause)}`,
);
}
}
return { jar: await realpath(jar), java };
};
@@ -0,0 +1,44 @@
import { chmod, mkdir, realpath, writeFile } from "node:fs/promises";
import { join } from "node:path";
import { expect, it as test } from "vitest";
import { resolveJadxConfiguration } from "../../../src/android/JadxConfiguration.js";
import { createTestTempDirectory } from "../../fixtures/temporaryDirectory.js";
const it = test.skipIf(process.platform === "win32");
it("rejects an explicit JAVA_HOME without an executable java binary", async () => {
const root = await createTestTempDirectory("rea-jadx-config-");
const jar = join(root, "jadx-headless-mcp.jar");
const javaHome = join(root, "missing-jdk");
await writeFile(jar, "fixture jar");
await expect(
resolveJadxConfiguration(
{ REA_JADX_MCP_JAR: jar, JAVA_HOME: javaHome },
"inspect_android_package",
),
).rejects.toMatchObject({
_tag: "AnalysisCapabilityUnavailableError",
reason: expect.stringContaining(join(javaHome, "bin", "java")),
});
});
it("accepts a verified explicit java binary and canonicalizes the JAR", async () => {
const root = await createTestTempDirectory("rea-jadx-config-");
const jar = join(root, "jadx-headless-mcp.jar");
const javaHome = join(root, "jdk");
const java = join(javaHome, "bin", "java");
await mkdir(join(javaHome, "bin"), { recursive: true });
await writeFile(jar, "fixture jar");
await writeFile(java, "#!/bin/sh\n");
await chmod(java, 0o700);
await expect(
resolveJadxConfiguration(
{ REA_JADX_MCP_JAR: jar, JAVA_HOME: javaHome },
"inspect_android_package",
),
).resolves.toEqual({ jar: await realpath(jar), java });
});