[PR #3521] feat(reverse): add radare2 one-shot commands and analysis sessions #5800

Open
opened 2026-10-31 01:09:31 +00:00 by bsakaguchi · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/morluto/rea/pull/3521
Author: @cainiao1992
Created: 10/14/2026
Status: 🔄 Open

Base: main ← Head: feat/radare2-provider


📝 Commits (4)

  • 5fb2c47 feat(reverse): add radare2 commands, sessions, doctor detection, and radiff2 comparison
  • e1a1940 ci(reverse): verify radare2 provider against a real engine
  • 3cd3e35 docs(reverse): document the radare2 provider and relocs.apply trade-off
  • 559c4e0 fix(reverse): bind session cleanup wrappers and correct radiff2 session effects

📊 Changes

42 files changed (+4296 additions, -56 deletions)

View changed files

➕ .github/workflows/real-radare2.yml (+57 -0)
📝 README.md (+2 -2)
📝 docs/reverse-engineering-tools.md (+36 -4)
📝 package.json (+2 -1)
📝 scripts/lib/catalog-builders.mjs (+19 -0)
📝 scripts/lib/catalog-core.mjs (+4 -0)
📝 src/application/DoctorProviderIds.ts (+1 -0)
📝 src/application/reverse/ReverseEngineeringCommandPort.ts (+4 -0)
📝 src/application/reverse/ReverseEngineeringService.ts (+86 -10)
📝 src/cli/reverseEngineeringCommands.ts (+65 -0)
📝 src/cliCommandNames.ts (+2 -0)
📝 src/composition/reverseEngineering.ts (+29 -12)
➕ src/contracts/radare2SessionToolContracts.ts (+112 -0)
📝 src/contracts/reverseEngineeringToolContracts.ts (+36 -0)
📝 src/contracts/toolContractExamples.ts (+7 -0)
📝 src/contracts/toolContracts.ts (+2 -0)
📝 src/contracts/toolEffects.test.ts (+5 -0)
📝 src/contracts/toolEffects.ts (+41 -0)
📝 src/contracts/toolFamilies.ts (+2 -0)
📝 src/doctorRuntime.ts (+2 -0)

...and 22 more files

📄 Description

Summary

Adds a radare2 provider family so lightweight native binary analysis works without Ghidra or Hopper: one-shot commands, persistent r2pipe2 sessions with structured JSON replies (including decompiler-plugin errors), radiff2 artifact comparison, doctor availability checks, and a real-engine CI lane. Raw output stays authoritative; structured fields (parsed, summary, command_error, command_code, command_logs) are additive projections.

Fixes #2711

Problem and expected behavior

Today, native-binary questions require either heavyweight deep-analysis providers (Ghidra needs a JVM and a slow first analysis; Hopper/IDA are licensed) or the existing objdump/Rizin one-shot tools. Radare2 is free, native, token-efficient for agents, and its suite (r2ghidra, r2dec, radiff2, ESIL) adds free decompilation, diffing, and emulation, but REA could not drive any of it.

Expected behavior: a user installs only their own radare2 suite (default radare2/radiff2, or REA_R2_COMMAND/REA_RADIFF2_COMMAND) and gets the same admission, effects, and Evidence semantics as the Rizin tools across CLI and MCP; optionally installing r2ghidra or r2dec enables pdg/pdd decompilation through either surface.

Change and scope

  • One-shot commands: execute_radare2_command (MCP) and rea execute-radare2-command (CLI) — radare2 -N -q -e scr.color=0 -c against one artifact, raw stdout/stderr inline, SHA-256 digests, 16 MiB combined limit, unrestricted-command admission identical to execute_rizin_command.
  • Persistent analysis sessions: start_radare2_session / radare2_command / radare2_session_status / close_radare2_session — radare2 -N -q -e scr.color=0 -0, NUL-delimited frames, r2pipe2 protocol (radare2 ≥ 5.9): one JSON reply per command whose res becomes output, with command_error / command_code / command_logs preserved. radare2 reports many command failures with error:false and the reason in logs (for example r2ghidra decompiling at a function-less offset), so logs are kept rather than trusting the flag; a non-JSON frame is a protocol failure that stops the session. start accepts optional initial_commands (≤ 16, run once inside the same admission; a failing command closes the session). For aflj/izzj, a field-reduced summary projection saves tokens alongside the complete parsed. radare2_session_status also surfaces bounded recent_stderr diagnostics. Sessions are bounded (8 concurrent, 16 MiB frames/output, per-command timeouts) and admit through the external-mutation seam shared with the Rizin debug tools. REA never runs analysis automatically.
  • Artifact comparison: compare_with_radiff2 (MCP) and rea compare-with-radiff2 (CLI) — functions maps to radiff2 -Cj -A (function-level JSON diff rows), bytes maps to -A (byte-level text). Read-only with a fixed operation set and no arbitrary-command surface, so it uses the lighter admission like inspect_with_objdump; Evidence digests cover path_a only and path_b stays caller-selected without a digest binding.
  • Decompilation and emulation: pdg (r2ghidra) and pdd (r2dec) work through both surfaces when the user installs the plugin (r2pm -ci r2ghidra / r2pm -ci r2dec); missing-plugin failures surface in command_logs. ESIL emulation is available through session commands; REA adds no dedicated tool — the docs carry a verified recipe (aei/aeim/aeip/aer/aes/ar) with its limits (no syscalls, imports, or SIMD).
  • Diagnostics: rea doctor --provider radare2 checks the BYO executable and version, flagging engines below the r2pipe2 floor (one-shot commands still work there).
  • CI: .github/workflows/real-radare2.yml builds radare2 from source on ubuntu and runs verify:radare2 — real-engine one-shot and session tests that skip when no engine is installed locally.
  • Engine defaults preserved where measurements say so: radare2 leaves relocations unapplied by default; measured across macOS Mach-O and aarch64 Linux ELF targets, applying them never changed function or string discovery and bought 0.1-2% cross references for 2-5% aaa time. REA keeps the engine default and documents the per-command opt-in (e bin.relocs.apply=true; aaa; …) with the measurements, so large-ELF callers can decide.
  • Provider code lives in src/radare2/; the rizin integration is unchanged.

Deliberately excluded: the radare2 debugger (target execution), r2pm installation/management, and dedicated decompiler/emulation tool wrappers — each needs its own proposal (a plugin-backed deep toolset neighbors #3019's provider layer).

Follows the contribution scope. The admitted session/one-shot commands are unrestricted (shell, file, and network access in the REA process user's context, identical in authority to execute_rizin_command), so integration needs an explicit maintainer scope decision: requested in #2711 (the feature issue; no decision exists yet). Opened as a draft with the readiness items unchecked until that decision lands. Note compare_with_radiff2 is deliberately narrower: fixed read-only operations with no command-injection surface.

Contract and boundary impact

  • Semantic owner and earliest changed stage: src/radare2/ (new provider family) → src/domain/reverseEngineering.ts (schemas) → shared service workflow → src/contracts/ → CLI/MCP registration; scripts/lib/catalog-*.mjs and DOCTOR_PROVIDER_IDS for generated/derived inventories.
  • Contribution scope fit and linked maintainer decision: pending — requested in #2711.
  • CLI and MCP/tool-catalog contract: adds execute_radare2_command, compare_with_radiff2, start_radare2_session, radare2_command, radare2_session_status, close_radare2_session; adds rea execute-radare2-command and rea compare-with-radiff2; radare2_command carries command_error/command_code/command_logs and the summary projection; effect-audit entries mirror the Rizin tools (compare_with_radiff2 declares only launchesProcess + mutatesSession); catalog inventory extended.
  • Provider, bridge, target-format, or platform compatibility: BYO executables, rea setup untouched; sessions have no platform restriction (unlike the Rizin debug sessions); r2pipe2 requires radare2 ≥ 5.9 (doctor reports the gap).
  • Evidence, artifact, provenance, or reconstruction contract: Evidence preserves raw output, digests, launch provenance, truncation/invalid-UTF-8 flags, r2pipe2 logs, and bounded stderr; parsed/summary are delivery-only projections, never authoritative; radiff2 Evidence digests cover path_a only.
  • Target selection, authority, upstream behavior, and cleanup details: no target execution anywhere; owned processes stop through best-effort q plus verified supervised stop, retained for retry.
  • Generated metadata: scripts/lib/catalog-{core,builders}.mjs updated; docs/public/product-catalog.json is a generated ignored output (validated via npm run docs:check).

Expected effects (check known effects; use documentation-only on its own). Unchecked items do not establish absence; leave uncertainties visible.

  • Read existing files or captured data.
  • Launch or attach to a process. (radare2/radiff2 run as owned provider processes; they do not launch or attach to a target process under REA's authority — -d is deliberately excluded.)
  • Inject instrumentation or run scripts/code. (Unrestricted session/one-shot commands can run shell/plugin code.)
  • Change process memory, registers, files, or configuration. (Unrestricted commands can mutate files.)
  • Contact network services. (Unrestricted commands can access the network.)
  • Recover protected code or work around protections.
  • Documentation or usability only; no target interaction.
  • Not sure yet; investigation or maintainer guidance needed.

Evidence and regression coverage

  • Tests added or updated: injected-process session lifecycle (start, r2pipe2 reply mapping, plugin-failure logs with error:false, non-JSON frame protocol failure, timeout, multiline rejection, capacity, close retry, stderr status), JSON/summary projection units, fake-provider MCP boundary (full lifecycle, initial commands, missing executable, admission operation names), one-shot and radiff2 MCP/CLI/port/contract/effects suites, doctor inspection units, and real-engine tests (realRadare2Provider.test.ts) that skip without a local engine.

  • Base reproduction or other evidence: end-to-end runs against real radare2 6.2.4 with r2ghidra and r2dec installed verified every surface — one-shot ij; a persistent session emitting an empty startup frame and exactly one r2pipe2 JSON reply per command; initial_commands: ["aaa"] in one round trip; aflj with parsed (135 entries) and reduced summary; pdg @ main and pdd @ main returning full pseudocode; pdg @ 0x0 returning error:false with the r2ghidra warning in logs; an ESIL workflow through session commands (ar PC reading back the stepped address); compare_with_radiff2 returning 140 function-diff rows plus the CLI bytes mode.

  • User-visible CLI/MCP output: rea execute-radare2-command ./program ij and rea compare-with-radiff2 a b functions return Evidence JSON; the Radare2 section of docs/reverse-engineering-tools.md documents sessions, r2pipe2 fields (including why json:true is not used — it produces invalid frames for non-JSON commands on 6.2.4), the decompiler plugins, the ESIL recipe, the relocs.apply measurements and opt-in, and the BYO paths.

  • Remaining proof gaps: the new CI lane has not executed on a runner yet (push-then-workflow_dispatch is the first check); no real-provider run on Windows; the full npm run check:pr was not re-run on top of the rebase (macOS local gates pass; the DMG/hdiutil local failures on that base reproduce on main).

  • 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 -- tests/boundary/providers/Radare2SessionManager.test.ts tests/boundary/providers/radare2CommandOutput.test.ts tests/boundary/providers/Radare2Doctor.test.ts tests/boundary/providers/realRadare2Provider.test.ts tests/boundary/mcp/radare2CommandMcp.test.ts tests/boundary/mcp/radare2SessionMcp.test.ts tests/boundary/cli/reverseEngineeringCommands.test.ts — 38 passed
  • npm run test:local -- src/contracts/toolEffects.test.ts src/contracts/advertisedInputExamples.test.ts src/contracts/compactInputSchema.test.ts tests/composition/reverseEngineering.test.ts tests/composition/reverseEngineeringCommandPort.test.ts src/doctorRuntime.test.ts — 50 passed
  • npm run docs:check — pass (catalog regenerated via npm run artifacts:product-catalog)
  • npm run check:fast — pass
  • End-to-end against real radare2 6.2.4 + r2ghidra + r2dec (macOS arm64), via MCP stdio and CLI: all surfaces listed under Evidence above

Compatibility, safety, and release

  • Breaking changes or migration steps: none.
  • Real Hopper/Ghidra, browser, or OS coverage: not applicable; real radare2 6.2.4 + r2ghidra + r2dec end-to-end executed (macOS only). Windows real-provider runs were not performed; the new CI lane covers ubuntu.
  • Package or release metadata impact: no package changes; catalog source lists and DOCTOR_PROVIDER_IDS extended (generated artifacts stay ignored).
  • Security, privacy, process, or containment review: unrestricted session/one-shot commands run in the REA process user's context and are stated in the effects and contract descriptions; compare_with_radiff2 is read-only with a fixed operation set; no r2pm, no debugger, no protection recovery; the LGPLv3 engines stay unbundled as unlinked BYO subprocesses.

Author readiness

Human owner: @cainiao1992

  • I reviewed the final diff and relevant existing code, understand the change and its edge cases, and take responsibility for the complete PR, including AI-assisted work.
  • I checked the evidence above, confirmed it supports the current change, and recorded meaningful validation gaps.
  • I declare this PR ready for initial maintainer review.

Before merge

  • This PR addresses a concrete problem (#2711).
  • Material scope and authority questions are resolved, and any required maintainer scope decision covers the final diff. (pending — #2711)
  • The PR has one focused outcome and the title follows type(scope): outcome.
  • Related issue is linked (#2711).
  • 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/3521 **Author:** [@cainiao1992](https://github.com/cainiao1992) **Created:** 10/14/2026 **Status:** 🔄 Open **Base:** `main` ← **Head:** `feat/radare2-provider` --- ### 📝 Commits (4) - [`5fb2c47`](https://github.com/morluto/rea/commit/5fb2c472a99f4bf5d19d4dd67d336a8b71031cbd) feat(reverse): add radare2 commands, sessions, doctor detection, and radiff2 comparison - [`e1a1940`](https://github.com/morluto/rea/commit/e1a19407083ca75e82ecfd2930453fa434482bde) ci(reverse): verify radare2 provider against a real engine - [`3cd3e35`](https://github.com/morluto/rea/commit/3cd3e35a4d04cdc19f660d8b216beb14909b78a6) docs(reverse): document the radare2 provider and relocs.apply trade-off - [`559c4e0`](https://github.com/morluto/rea/commit/559c4e04509255d6544fec9221697462ccc8cc1e) fix(reverse): bind session cleanup wrappers and correct radiff2 session effects ### 📊 Changes **42 files changed** (+4296 additions, -56 deletions) <details> <summary>View changed files</summary> ➕ `.github/workflows/real-radare2.yml` (+57 -0) 📝 `README.md` (+2 -2) 📝 `docs/reverse-engineering-tools.md` (+36 -4) 📝 `package.json` (+2 -1) 📝 `scripts/lib/catalog-builders.mjs` (+19 -0) 📝 `scripts/lib/catalog-core.mjs` (+4 -0) 📝 `src/application/DoctorProviderIds.ts` (+1 -0) 📝 `src/application/reverse/ReverseEngineeringCommandPort.ts` (+4 -0) 📝 `src/application/reverse/ReverseEngineeringService.ts` (+86 -10) 📝 `src/cli/reverseEngineeringCommands.ts` (+65 -0) 📝 `src/cliCommandNames.ts` (+2 -0) 📝 `src/composition/reverseEngineering.ts` (+29 -12) ➕ `src/contracts/radare2SessionToolContracts.ts` (+112 -0) 📝 `src/contracts/reverseEngineeringToolContracts.ts` (+36 -0) 📝 `src/contracts/toolContractExamples.ts` (+7 -0) 📝 `src/contracts/toolContracts.ts` (+2 -0) 📝 `src/contracts/toolEffects.test.ts` (+5 -0) 📝 `src/contracts/toolEffects.ts` (+41 -0) 📝 `src/contracts/toolFamilies.ts` (+2 -0) 📝 `src/doctorRuntime.ts` (+2 -0) _...and 22 more files_ </details> ### 📄 Description ## Summary Adds a radare2 provider family so lightweight native binary analysis works without Ghidra or Hopper: one-shot commands, persistent r2pipe2 sessions with structured JSON replies (including decompiler-plugin errors), radiff2 artifact comparison, doctor availability checks, and a real-engine CI lane. Raw output stays authoritative; structured fields (`parsed`, `summary`, `command_error`, `command_code`, `command_logs`) are additive projections. Fixes #2711 ## Problem and expected behavior Today, native-binary questions require either heavyweight deep-analysis providers (Ghidra needs a JVM and a slow first analysis; Hopper/IDA are licensed) or the existing objdump/Rizin one-shot tools. Radare2 is free, native, token-efficient for agents, and its suite (r2ghidra, r2dec, radiff2, ESIL) adds free decompilation, diffing, and emulation, but REA could not drive any of it. Expected behavior: a user installs only their own radare2 suite (default `radare2`/`radiff2`, or `REA_R2_COMMAND`/`REA_RADIFF2_COMMAND`) and gets the same admission, effects, and Evidence semantics as the Rizin tools across CLI and MCP; optionally installing r2ghidra or r2dec enables `pdg`/`pdd` decompilation through either surface. ## Change and scope - **One-shot commands**: `execute_radare2_command` (MCP) and `rea execute-radare2-command` (CLI) — `radare2 -N -q -e scr.color=0 -c` against one artifact, raw stdout/stderr inline, SHA-256 digests, 16 MiB combined limit, unrestricted-command admission identical to `execute_rizin_command`. - **Persistent analysis sessions**: `start_radare2_session` / `radare2_command` / `radare2_session_status` / `close_radare2_session` — `radare2 -N -q -e scr.color=0 -0`, NUL-delimited frames, r2pipe2 protocol (radare2 ≥ 5.9): one JSON reply per command whose `res` becomes `output`, with `command_error` / `command_code` / `command_logs` preserved. radare2 reports many command failures with `error:false` and the reason in `logs` (for example r2ghidra decompiling at a function-less offset), so logs are kept rather than trusting the flag; a non-JSON frame is a protocol failure that stops the session. `start` accepts optional `initial_commands` (≤ 16, run once inside the same admission; a failing command closes the session). For `aflj`/`izzj`, a field-reduced `summary` projection saves tokens alongside the complete `parsed`. `radare2_session_status` also surfaces bounded `recent_stderr` diagnostics. Sessions are bounded (8 concurrent, 16 MiB frames/output, per-command timeouts) and admit through the external-mutation seam shared with the Rizin debug tools. REA never runs analysis automatically. - **Artifact comparison**: `compare_with_radiff2` (MCP) and `rea compare-with-radiff2` (CLI) — `functions` maps to `radiff2 -Cj -A` (function-level JSON diff rows), `bytes` maps to `-A` (byte-level text). Read-only with a fixed operation set and no arbitrary-command surface, so it uses the lighter admission like `inspect_with_objdump`; Evidence digests cover `path_a` only and `path_b` stays caller-selected without a digest binding. - **Decompilation and emulation**: `pdg` (r2ghidra) and `pdd` (r2dec) work through both surfaces when the user installs the plugin (`r2pm -ci r2ghidra` / `r2pm -ci r2dec`); missing-plugin failures surface in `command_logs`. ESIL emulation is available through session commands; REA adds no dedicated tool — the docs carry a verified recipe (`aei`/`aeim`/`aeip`/`aer`/`aes`/`ar`) with its limits (no syscalls, imports, or SIMD). - **Diagnostics**: `rea doctor --provider radare2` checks the BYO executable and version, flagging engines below the r2pipe2 floor (one-shot commands still work there). - **CI**: `.github/workflows/real-radare2.yml` builds radare2 from source on ubuntu and runs `verify:radare2` — real-engine one-shot and session tests that skip when no engine is installed locally. - **Engine defaults preserved where measurements say so**: radare2 leaves relocations unapplied by default; measured across macOS Mach-O and aarch64 Linux ELF targets, applying them never changed function or string discovery and bought 0.1-2% cross references for 2-5% `aaa` time. REA keeps the engine default and documents the per-command opt-in (`e bin.relocs.apply=true; aaa; …`) with the measurements, so large-ELF callers can decide. - Provider code lives in `src/radare2/`; the `rizin` integration is unchanged. Deliberately excluded: the radare2 **debugger** (target execution), **r2pm installation/management**, and dedicated decompiler/emulation tool wrappers — each needs its own proposal (a plugin-backed deep toolset neighbors #3019's provider layer). Follows the [contribution scope](https://github.com/morluto/rea/blob/main/CONTRIBUTING.md#contribution-scope). The admitted session/one-shot commands are unrestricted (shell, file, and network access in the REA process user's context, identical in authority to `execute_rizin_command`), so integration needs an explicit maintainer scope decision: **requested in #2711** (the feature issue; no decision exists yet). Opened as a draft with the readiness items unchecked until that decision lands. Note `compare_with_radiff2` is deliberately narrower: fixed read-only operations with no command-injection surface. ## Contract and boundary impact - Semantic owner and earliest changed stage: `src/radare2/` (new provider family) → `src/domain/reverseEngineering.ts` (schemas) → shared service workflow → `src/contracts/` → CLI/MCP registration; `scripts/lib/catalog-*.mjs` and `DOCTOR_PROVIDER_IDS` for generated/derived inventories. - Contribution scope fit and linked maintainer decision: **pending** — requested in #2711. - CLI and MCP/tool-catalog contract: adds `execute_radare2_command`, `compare_with_radiff2`, `start_radare2_session`, `radare2_command`, `radare2_session_status`, `close_radare2_session`; adds `rea execute-radare2-command` and `rea compare-with-radiff2`; `radare2_command` carries `command_error`/`command_code`/`command_logs` and the `summary` projection; effect-audit entries mirror the Rizin tools (`compare_with_radiff2` declares only `launchesProcess` + `mutatesSession`); catalog inventory extended. - Provider, bridge, target-format, or platform compatibility: BYO executables, `rea setup` untouched; sessions have no platform restriction (unlike the Rizin debug sessions); r2pipe2 requires radare2 ≥ 5.9 (doctor reports the gap). - Evidence, artifact, provenance, or reconstruction contract: Evidence preserves raw output, digests, launch provenance, truncation/invalid-UTF-8 flags, r2pipe2 `logs`, and bounded stderr; `parsed`/`summary` are delivery-only projections, never authoritative; radiff2 Evidence digests cover `path_a` only. - Target selection, authority, upstream behavior, and cleanup details: no target execution anywhere; owned processes stop through best-effort `q` plus verified supervised stop, retained for retry. - Generated metadata: `scripts/lib/catalog-{core,builders}.mjs` updated; `docs/public/product-catalog.json` is a generated ignored output (validated via `npm run docs:check`). Expected effects (check known effects; use documentation-only on its own). Unchecked items do not establish absence; leave uncertainties visible. - [x] Read existing files or captured data. - [ ] Launch or attach to a process. (radare2/radiff2 run as owned provider processes; they do not launch or attach to a target process under REA's authority — `-d` is deliberately excluded.) - [x] Inject instrumentation or run scripts/code. (Unrestricted session/one-shot commands can run shell/plugin code.) - [x] Change process memory, registers, files, or configuration. (Unrestricted commands can mutate files.) - [x] Contact network services. (Unrestricted commands can access the network.) - [ ] Recover protected code or work around protections. - [ ] Documentation or usability only; no target interaction. - [ ] Not sure yet; investigation or maintainer guidance needed. ## Evidence and regression coverage - Tests added or updated: injected-process session lifecycle (start, r2pipe2 reply mapping, plugin-failure logs with `error:false`, non-JSON frame protocol failure, timeout, multiline rejection, capacity, close retry, stderr status), JSON/summary projection units, fake-provider MCP boundary (full lifecycle, initial commands, missing executable, admission operation names), one-shot and radiff2 MCP/CLI/port/contract/effects suites, doctor inspection units, and real-engine tests (`realRadare2Provider.test.ts`) that skip without a local engine. - Base reproduction or other evidence: end-to-end runs against real radare2 6.2.4 with r2ghidra and r2dec installed verified every surface — one-shot `ij`; a persistent session emitting an empty startup frame and exactly one r2pipe2 JSON reply per command; `initial_commands: ["aaa"]` in one round trip; `aflj` with `parsed` (135 entries) and reduced `summary`; `pdg @ main` and `pdd @ main` returning full pseudocode; `pdg @ 0x0` returning `error:false` with the r2ghidra warning in `logs`; an ESIL workflow through session commands (`ar PC` reading back the stepped address); `compare_with_radiff2` returning 140 function-diff rows plus the CLI bytes mode. - User-visible CLI/MCP output: `rea execute-radare2-command ./program ij` and `rea compare-with-radiff2 a b functions` return Evidence JSON; the Radare2 section of `docs/reverse-engineering-tools.md` documents sessions, r2pipe2 fields (including why `json:true` is not used — it produces invalid frames for non-JSON commands on 6.2.4), the decompiler plugins, the ESIL recipe, the relocs.apply measurements and opt-in, and the BYO paths. - Remaining proof gaps: the new CI lane has not executed on a runner yet (push-then-`workflow_dispatch` is the first check); no real-provider run on Windows; the full `npm run check:pr` was not re-run on top of the rebase (macOS local gates pass; the DMG/hdiutil local failures on that base reproduce on main). - [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 -- tests/boundary/providers/Radare2SessionManager.test.ts tests/boundary/providers/radare2CommandOutput.test.ts tests/boundary/providers/Radare2Doctor.test.ts tests/boundary/providers/realRadare2Provider.test.ts tests/boundary/mcp/radare2CommandMcp.test.ts tests/boundary/mcp/radare2SessionMcp.test.ts tests/boundary/cli/reverseEngineeringCommands.test.ts` — 38 passed - `npm run test:local -- src/contracts/toolEffects.test.ts src/contracts/advertisedInputExamples.test.ts src/contracts/compactInputSchema.test.ts tests/composition/reverseEngineering.test.ts tests/composition/reverseEngineeringCommandPort.test.ts src/doctorRuntime.test.ts` — 50 passed - `npm run docs:check` — pass (catalog regenerated via `npm run artifacts:product-catalog`) - `npm run check:fast` — pass - End-to-end against real radare2 6.2.4 + r2ghidra + r2dec (macOS arm64), via MCP stdio and CLI: all surfaces listed under Evidence above ## Compatibility, safety, and release - Breaking changes or migration steps: none. - Real Hopper/Ghidra, browser, or OS coverage: not applicable; real radare2 6.2.4 + r2ghidra + r2dec end-to-end executed (macOS only). Windows real-provider runs were not performed; the new CI lane covers ubuntu. - Package or release metadata impact: no package changes; catalog source lists and `DOCTOR_PROVIDER_IDS` extended (generated artifacts stay ignored). - Security, privacy, process, or containment review: unrestricted session/one-shot commands run in the REA process user's context and are stated in the effects and contract descriptions; `compare_with_radiff2` is read-only with a fixed operation set; no r2pm, no debugger, no protection recovery; the LGPLv3 engines stay unbundled as unlinked BYO subprocesses. ## Author readiness Human owner: @cainiao1992 - [x] I reviewed the final diff and relevant existing code, understand the change and its edge cases, and take responsibility for the complete PR, including AI-assisted work. - [x] I checked the evidence above, confirmed it supports the current change, and recorded meaningful validation gaps. - [x] I declare this PR ready for initial maintainer review. ## Before merge - [x] This PR addresses a concrete problem (#2711). - [ ] Material scope and authority questions are resolved, and any required maintainer scope decision covers the final diff. *(pending — #2711)* - [x] The PR has one focused outcome and the title follows `type(scope): outcome`. - [x] Related issue is linked (#2711). - [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>
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#5800
No description provided.