From ae07d151704bac5f0129985cedb92546d2d5411e Mon Sep 17 00:00:00 2001 From: morluto <76467478+morluto@users.noreply.github.com> Date: Sat, 17 Oct 2026 03:34:11 +0800 Subject: [PATCH] fix(ghidra): explain keg-only JDK admission remediation Explain how to select an existing Homebrew JDK with JAVA_HOME when macOS Java discovery cannot find a keg-only installation. Preserve caller-selected runtime inputs and the Ghidra installation's declared Java bounds. Document the installation paths and retain a regression showing only the requested Java command is probed; no automatic JDK discovery or installation added. Validation: 4 focused files, 122 passed; npm run check and docs:check passed. Public CLI prerequisite fixtures ran on macOS; Homebrew keg-only guidance is source/fixture verified against the primary formula documentation, not a fresh Homebrew installation or a Windows runtime test. Refs #4556 --- docs/installation.md | 10 ++++++++++ src/ghidra/GhidraInstallation.test.ts | 28 +++++++++++++++++++++++++++ src/ghidra/GhidraInstallation.ts | 7 +++++-- 3 files changed, 43 insertions(+), 2 deletions(-) diff --git a/docs/installation.md b/docs/installation.md index f8a996120d..2893dc75ec 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -833,6 +833,16 @@ rea doctor --json rea setup ``` +On macOS, [Homebrew OpenJDK is keg-only](https://formulae.brew.sh/formula/openjdk) +and may be unavailable to the system `java` wrapper. Set `JAVA_HOME` to the +selected formula's `libexec/openjdk.jdk/Contents/Home`, for example +`/opt/homebrew/opt/openjdk/libexec/openjdk.jdk/Contents/Home` or +`/usr/local/opt/openjdk/libexec/openjdk.jdk/Contents/Home`. Use a JDK inside the +Java version bounds declared by your Ghidra installation; REA does not select +another installed JDK automatically. Doctor distinguishes an absent Java +command from a command that runs and fails, and retains bounded probe output +and any parsed properties when the selected runtime cannot be admitted. + On Windows, configure the existing installation in PowerShell: ```powershell diff --git a/src/ghidra/GhidraInstallation.test.ts b/src/ghidra/GhidraInstallation.test.ts index f0cb38ec85..fffa5d6e56 100644 --- a/src/ghidra/GhidraInstallation.test.ts +++ b/src/ghidra/GhidraInstallation.test.ts @@ -1382,3 +1382,31 @@ describe("Ghidra Java probe os.arch extraction", () => { } }); }); + +it("explains the macOS keg-only JDK case without probing an unselected installation", () => { + const probed: string[] = []; + const inspection = inspectGhidraInstallation( + { + environment: {}, + installDir: INSTALL, + platform: "darwin", + architecture: "arm64", + }, + host({ + probeJava: (command) => { + probed.push(command); + return missingJavaProbe; + }, + }), + ); + expect(probed).toEqual(["java"]); + expect(inspection.checks.find(({ name }) => name === "java")).toMatchObject({ + status: "failed", + code: "runtime_missing", + remediation: expect.stringContaining("Homebrew OpenJDK can be keg-only"), + }); + const java = inspection.checks.find(({ name }) => name === "java"); + expect(java?.status === "failed" ? java.remediation : "").toContain( + "/opt/homebrew/opt/openjdk/libexec/openjdk.jdk/Contents/Home", + ); +}); diff --git a/src/ghidra/GhidraInstallation.ts b/src/ghidra/GhidraInstallation.ts index 3e0f570338..4437dbe2a1 100644 --- a/src/ghidra/GhidraInstallation.ts +++ b/src/ghidra/GhidraInstallation.ts @@ -534,6 +534,7 @@ const installationChecks = ({ coordinates.javaCommand, javaHome, coordinates.properties, + platform, coordinates.javaProbeFailure, ), ]; @@ -823,6 +824,7 @@ const javaCheck = ( command: string, configuredHome: string | undefined, properties: GhidraApplicationProperties | undefined, + platform: NodeJS.Platform, failure: GhidraJavaProbeFailure | undefined, ): GhidraInstallationCheck => { const requirement = ghidraJavaRequirement(properties); @@ -861,7 +863,7 @@ const javaCheck = ( ? "unsupported_version" : "version_unresolved", detail, - remediation: javaRemediation(requirement, configuredHome, range), + remediation: javaRemediation(requirement, configuredHome, range, platform), }); }; @@ -869,11 +871,12 @@ const javaRemediation = ( requirement: GhidraJavaRequirement, configuredHome: string | undefined, range: string, + platform: NodeJS.Platform, ): string => { if (requirement.unresolved !== null) return `The Ghidra installation's Java bounds could not be read (${requirement.unresolved}). Install a 64-bit full JDK inside the declared application.java.min and application.java.max.`; return configuredHome === undefined - ? `Install ${range}, or set JAVA_HOME before starting REA.` + ? `Select ${range} on PATH, or set JAVA_HOME to its installation root before starting REA.${platform === "darwin" ? " Homebrew OpenJDK can be keg-only: set JAVA_HOME to the selected formula's libexec/openjdk.jdk/Contents/Home (for example /opt/homebrew/opt/openjdk/libexec/openjdk.jdk/Contents/Home or /usr/local/opt/openjdk/libexec/openjdk.jdk/Contents/Home). The installed JDK must satisfy the declared Ghidra Java bounds." : ""}` : `Update JAVA_HOME to the root of ${range} installation.`; };