[PR #2945] [CLOSED] fix(ghidra): tell callers to reopen after the provider exits #5507

Closed
opened 2026-10-31 01:07:11 +00:00 by bsakaguchi · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/morluto/rea/pull/2945
Author: @RishTheFish21
Created: 10/13/2026
Status: ❌ Closed

Base: main ← Head: fix/1719-reopen-after-ghidra-exit


📝 Commits (1)

  • e1e6a2c fix(ghidra): tell callers to reopen after the provider exits

📊 Changes

2 files changed (+153 additions, -0 deletions)

View changed files

📝 src/ghidra/GhidraProvider.behavior.test.ts (+102 -0)
📝 src/ghidra/GhidraProviderClient.ts (+51 -0)

📄 Description

Summary

Fixes #1719. The reopen and snapshot_path paths from the original report were already fixed by e59db2f and #2014; I verified them on real Ghidra (see Validation). The one remaining case: after the Ghidra process dies, a query without a reopen returned a generic execution_failure telling the caller to run rea doctor and that repeating would not help. Nothing is wrong with the installation, and a plain open_binary on the same target recovers.

Problem and expected behavior

Kill the Ghidra JVM after a successful query, then call list_documents without reopening:

  • Before: "Analysis could not complete. Run rea doctor and review the reported details; repeating the unchanged request is not expected to succeed."
  • After: "The Ghidra provider for this session exited before list_documents could complete. Call open_binary for the same target to start a new Ghidra session, then retry; session-only annotations from the previous provider are not retained."

Change and scope

  • projectSessionError in GhidraProviderClient.ts now receives the client's operationHealthSnapshot(). When a process/protocol failure coincides with health exited or unreachable (providerRetryAction = restart_provider), the ProviderAdapterError carries a user message pointing at open_binary. This follows the existing Hopper RESTART_OWNED_PROVIDER path.
  • The health is only consulted after this session's provider has started or answered at least once, so a Ghidra crash during startup keeps the installation guidance.
  • Bridge-reported (remote) failures and failures with unknown health are unchanged.

Not included: restarting Ghidra automatically on the next query. A silent restart would discard session annotations, so the caller reopens explicitly.

Contract and boundary impact

  • Semantic owner and earliest changed stage: Ghidra provider client error projection.
  • CLI and MCP/tool-catalog contract: none. Same code (execution_failure), category, retryable: false and details; only the message and remediation text change in this case.
  • Provider, bridge, target-format, or platform compatibility: Ghidra only, all platforms.
  • Evidence, artifact, provenance, or reconstruction contract: none.
  • Process execution, authorization, cleanup, or containment impact: none.
  • Generated metadata (docs/public/product-catalog.json), package, or installation impact: none.

Evidence and regression coverage

  • Tests added or updated: five cases in src/ghidra/GhidraProvider.behavior.test.ts: exited → reopen message; unreachable → reopen message; death before the first reply → keeps rea doctor; unknown health → unchanged; remote failure → unchanged.
  • Base reproduction or other evidence: the real-Ghidra run on main (ebaaa79ca) posted on #1719 shows the old message.
  • User-visible CLI/MCP output: see "Problem and expected behavior".
  • Remaining proof gaps: only tested on macOS arm64. The unreachable case (socket closed, process alive) is covered by the fake-client test, not reproduced with real Ghidra.

For evidence-bearing changes:

  • Observed, derived, and inferred claims remain distinguishable.
  • Artifact identity, source provenance, and failed attempts remain preserved.
  • Unsupported, incomplete, unavailable, or uncertain outcomes remain visible.

Validation performed

  • npm run test:focused -- src/ghidra/GhidraProvider.behavior.test.ts: passed
  • npm run check:fast: passed
  • npm run check: typecheck, compile and metadata passed; format:check fails on docs/readme/README_tr.md and scripts/lib/clean-linux-hopper-runtime.mjs, which this PR doesn't touch (pre-existing on main)
  • npm run lint and npm run knip: passed
  • Real Ghidra 12.1.4, JDK 21, macOS arm64, driving rea mcp over stdio and SIGKILLing the Ghidra JVM at set points:
    • open → query → query: ok (Ghidra starts on the first query)
    • kill → open_binary same target → query: ok
    • kill → query without reopen: fails with the new message (twice); a following open_binary + query: ok
    • close_binary with snapshot_path → open_binary with snapshot_path → query → second open → query: ok
    • kill → open_binary with snapshot_path → query: ok
    • no Ghidra JVMs left over at the end

Compatibility, safety, and release

  • Breaking changes or migration steps: none.
  • Real Hopper/Ghidra, browser, or OS coverage: real Ghidra on macOS arm64 only.
  • Package or release metadata impact: none.
  • Security, privacy, process, or containment review: no new process handling; the change reads health REA already records.

Review checklist

  • This PR addresses a concrete problem or an agreed enhancement.
  • The PR has one focused outcome and the title follows type(scope): outcome.
  • Related issue is linked, or the reason for not linking one is stated above.
  • Tests cover changed observable behavior and meaningful failure paths.
  • Owning docs, contracts, and generated metadata are updated where needed.
  • User-visible CLI/MCP changes include representative output.
  • I checked the final diff for secrets, unrelated cleanup, and unsupported claims.

🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/morluto/rea/pull/2945 **Author:** [@RishTheFish21](https://github.com/RishTheFish21) **Created:** 10/13/2026 **Status:** ❌ Closed **Base:** `main` ← **Head:** `fix/1719-reopen-after-ghidra-exit` --- ### 📝 Commits (1) - [`e1e6a2c`](https://github.com/morluto/rea/commit/e1e6a2c7357a029712b93aa756140f256c41c09b) fix(ghidra): tell callers to reopen after the provider exits ### 📊 Changes **2 files changed** (+153 additions, -0 deletions) <details> <summary>View changed files</summary> 📝 `src/ghidra/GhidraProvider.behavior.test.ts` (+102 -0) 📝 `src/ghidra/GhidraProviderClient.ts` (+51 -0) </details> ### 📄 Description ## Summary Fixes #1719. The reopen and `snapshot_path` paths from the original report were already fixed by `e59db2f` and #2014; I verified them on real Ghidra (see Validation). The one remaining case: after the Ghidra process dies, a query without a reopen returned a generic `execution_failure` telling the caller to run `rea doctor` and that repeating would not help. Nothing is wrong with the installation, and a plain `open_binary` on the same target recovers. ## Problem and expected behavior Kill the Ghidra JVM after a successful query, then call `list_documents` without reopening: - Before: "Analysis could not complete. Run `rea doctor` and review the reported details; repeating the unchanged request is not expected to succeed." - After: "The Ghidra provider for this session exited before list_documents could complete. Call open_binary for the same target to start a new Ghidra session, then retry; session-only annotations from the previous provider are not retained." ## Change and scope - `projectSessionError` in `GhidraProviderClient.ts` now receives the client's `operationHealthSnapshot()`. When a `process`/`protocol` failure coincides with health `exited` or `unreachable` (`providerRetryAction` = `restart_provider`), the `ProviderAdapterError` carries a user message pointing at `open_binary`. This follows the existing Hopper `RESTART_OWNED_PROVIDER` path. - The health is only consulted after this session's provider has started or answered at least once, so a Ghidra crash during startup keeps the installation guidance. - Bridge-reported (`remote`) failures and failures with unknown health are unchanged. Not included: restarting Ghidra automatically on the next query. A silent restart would discard session annotations, so the caller reopens explicitly. ## Contract and boundary impact - Semantic owner and earliest changed stage: Ghidra provider client error projection. - CLI and MCP/tool-catalog contract: none. Same code (`execution_failure`), category, `retryable: false` and details; only the message and remediation text change in this case. - Provider, bridge, target-format, or platform compatibility: Ghidra only, all platforms. - Evidence, artifact, provenance, or reconstruction contract: none. - Process execution, authorization, cleanup, or containment impact: none. - Generated metadata (`docs/public/product-catalog.json`), package, or installation impact: none. ## Evidence and regression coverage - Tests added or updated: five cases in `src/ghidra/GhidraProvider.behavior.test.ts`: exited → reopen message; unreachable → reopen message; death before the first reply → keeps `rea doctor`; unknown health → unchanged; `remote` failure → unchanged. - Base reproduction or other evidence: the real-Ghidra run on `main` (`ebaaa79ca`) posted on #1719 shows the old message. - User-visible CLI/MCP output: see "Problem and expected behavior". - Remaining proof gaps: only tested on macOS arm64. The `unreachable` case (socket closed, process alive) is covered by the fake-client test, not reproduced with real Ghidra. For evidence-bearing changes: - [x] Observed, derived, and inferred claims remain distinguishable. - [x] Artifact identity, source provenance, and failed attempts remain preserved. - [x] Unsupported, incomplete, unavailable, or uncertain outcomes remain visible. ## Validation performed - `npm run test:focused -- src/ghidra/GhidraProvider.behavior.test.ts`: passed - `npm run check:fast`: passed - `npm run check`: typecheck, compile and metadata passed; `format:check` fails on `docs/readme/README_tr.md` and `scripts/lib/clean-linux-hopper-runtime.mjs`, which this PR doesn't touch (pre-existing on `main`) - `npm run lint` and `npm run knip`: passed - Real Ghidra 12.1.4, JDK 21, macOS arm64, driving `rea mcp` over stdio and SIGKILLing the Ghidra JVM at set points: - open → query → query: ok (Ghidra starts on the first query) - kill → `open_binary` same target → query: ok - kill → query without reopen: fails with the new message (twice); a following `open_binary` + query: ok - `close_binary` with `snapshot_path` → `open_binary` with `snapshot_path` → query → second open → query: ok - kill → `open_binary` with `snapshot_path` → query: ok - no Ghidra JVMs left over at the end ## Compatibility, safety, and release - Breaking changes or migration steps: none. - Real Hopper/Ghidra, browser, or OS coverage: real Ghidra on macOS arm64 only. - Package or release metadata impact: none. - Security, privacy, process, or containment review: no new process handling; the change reads health REA already records. ## Review checklist - [x] This PR addresses a concrete problem or an agreed enhancement. - [x] The PR has one focused outcome and the title follows `type(scope): outcome`. - [x] Related issue is linked, or the reason for not linking one is stated above. - [x] Tests cover changed observable behavior and meaningful failure paths. - [x] Owning docs, contracts, and generated metadata are updated where needed. - [x] User-visible CLI/MCP changes include representative output. - [x] I checked the final diff for secrets, unrelated cleanup, and unsupported claims. --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
bsakaguchi 2026-10-31 01:07:11 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
morluto/rea#5507
No description provided.