Merge pull request #1200 from morluto/fix/doctor-setup-relative-provider-paths

fix(ghidra): reject relative installation and Java paths in doctor and setup
This commit is contained in:
Kaoru0822 authored and GitHub committed 2026-10-08 21:21:04 -07:00
commit 8998438c23
2 files changed
+80 -7

No files matched your search

+45
View File
@@ -1,5 +1,6 @@
import { describe, expect, it } from "vitest";
import { projectGhidraDoctorInspection } from "./GhidraDoctor.js";
import {
ghidraJavaEnvironment,
inspectGhidraInstallation,
@@ -378,3 +379,47 @@ describe("Ghidra release line and JDK bounds", () => {
).toMatchObject({ status: "available", javaVersion: "17.0.20.1" });
});
});
describe("Ghidra configuration paths", () => {
it.each([
[{ installDir: "./ghidra" }, "GHIDRA_INSTALL_DIR must be absolute"],
[{ installDir: INSTALL, javaHome: "./jdk" }, "JAVA_HOME must be absolute"],
[
{ installDir: "ghidra", javaHome: "jdk" },
"GHIDRA_INSTALL_DIR and JAVA_HOME must be absolute",
],
])(
"rejects relative paths that REA's configuration parser rejects (%o)",
(paths, detail) => {
const result = inspectGhidraInstallation(
{ ...paths, platform: "linux", architecture: "x64" },
host(),
);
expect(result).toMatchObject({
status: "unavailable",
rejection: {
code: "not_configured",
reason: expect.stringContaining("reject relative paths"),
},
});
expect(result.checks).toContainEqual(
expect.objectContaining({ name: "configuration", detail }),
);
// Setup registers only an available inspection's environment.
expect(projectGhidraDoctorInspection(result)).toMatchObject({
available: false,
registrationEnvironment: {},
});
},
);
it("judges absolute paths by the inspected platform", () => {
const result = inspectGhidraInstallation(
{ installDir: "C:\\ghidra", platform: "win32", architecture: "x64" },
host(),
);
expect(result.checks).toContainEqual(
expect.objectContaining({ name: "configuration", status: "passed" }),
);
});
});
+35 -7
View File
@@ -306,13 +306,7 @@ const installationChecks = ({
javaHome,
host,
}: GhidraInstallationCheckContext): readonly GhidraInstallationCheck[] => [
installationCheck({
name: "configuration",
passed: coordinates.installDir !== null,
code: "not_configured",
detail: coordinates.installDir ?? "GHIDRA_INSTALL_DIR is not set",
remediation: `Set GHIDRA_INSTALL_DIR to an extracted Ghidra ${ghidraReleaseLine()} release directory.`,
}),
configurationCheck(coordinates.installDir, javaHome, platform),
installationCheck({
name: "platform",
passed: NATIVE_PLATFORMS[platform] !== undefined,
@@ -366,6 +360,40 @@ const installationChecks = ({
),
];
/**
* REA's configuration parser, and so the MCP server and analysis, accept only
* absolute paths; a relative one that happens to resolve here must not pass.
*/
const configurationCheck = (
installDir: string | null,
javaHome: string | undefined,
platform: NodeJS.Platform,
): GhidraInstallationCheck => {
const { isAbsolute } = platform === "win32" ? win32 : posix;
const relative = [
...(installDir !== null && !isAbsolute(installDir)
? ["GHIDRA_INSTALL_DIR"]
: []),
...(javaHome !== undefined && !isAbsolute(javaHome) ? ["JAVA_HOME"] : []),
];
if (installDir === null || relative.length === 0)
return installationCheck({
name: "configuration",
passed: installDir !== null,
code: "not_configured",
detail: installDir ?? "GHIDRA_INSTALL_DIR is not set",
remediation: `Set GHIDRA_INSTALL_DIR to an extracted Ghidra ${ghidraReleaseLine()} release directory.`,
});
const settings = relative.join(" and ");
return installationCheck({
name: "configuration",
passed: false,
code: "not_configured",
detail: `${settings} must be absolute`,
remediation: `Set ${settings} to ${relative.length === 1 ? "an absolute path" : "absolute paths"}. REA's analysis and MCP server reject relative paths even when they resolve from the current directory.`,
});
};
/** Project an installation probe into caller-visible, secret-free diagnostics. */
export const ghidraInstallationDiagnostics = (
inspection: GhidraInstallationInspection,