docs: define v0.1 product and architecture contract
This commit is contained in:
parent
57597e7d6d
commit
c4fb0c6a01
12 changed files with 2130 additions and 64 deletions
38
AGENTS.md
Normal file
38
AGENTS.md
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
# AGENTS.md
|
||||
|
||||
## Read first
|
||||
|
||||
- Read `PRD.md`, `CONTEXT.md`, and applicable ADRs before changing behavior.
|
||||
- Keep the Rust harness synchronous and the Ghidra worker
|
||||
capability-sandboxed.
|
||||
- Treat JSON schemas, error codes, ordering, and exit statuses as public API.
|
||||
|
||||
## Change rules
|
||||
|
||||
- Add a regression test for every bug fix.
|
||||
- Never change golden files or schemas implicitly.
|
||||
- Keep the Rust operation registry, Java dispatch, schemas, and goldens in
|
||||
exact parity.
|
||||
- Preserve strict stdout/stderr framing.
|
||||
- Preserve the worker's no-network and no-default-data-egress boundary.
|
||||
- Do not add `unsafe`, an async runtime, database, daemon, or dependency
|
||||
without an accepted design change.
|
||||
- Do not weaken bounds, validation, sandboxing, or atomic store behavior.
|
||||
|
||||
## Required checks
|
||||
|
||||
- `cargo fmt --check`
|
||||
- `cargo clippy --all-targets --all-features -- -D warnings`
|
||||
- `cargo test --all-targets`
|
||||
- `cargo deny check`
|
||||
- `nix flake check`
|
||||
|
||||
## Source control
|
||||
|
||||
- Use Jujutsu for normal local change management.
|
||||
- Use `jj status`, `jj diff`, `jj log`, `jj describe`, and `jj new`.
|
||||
- Push Forgejo bookmarks through `jj git push`.
|
||||
- Keep changes focused and preserve unrelated user work.
|
||||
- Use direct Git commands only for interop or recovery that Jujutsu cannot
|
||||
perform.
|
||||
- Never run `git clean -xdf`; it can delete colocated `.jj/` metadata.
|
||||
68
CONTEXT.md
68
CONTEXT.md
|
|
@ -12,32 +12,88 @@ names or locations.
|
|||
_Avoid_: Binary, file, target
|
||||
|
||||
**Analysis Profile**:
|
||||
The declared analysis inputs other than the Sample, including the Ghidra
|
||||
version, analyzer configuration, language selection, and tool protocol version.
|
||||
The canonical analysis inputs other than the Sample, including Ghidra and Java
|
||||
versions, Target Specification, fully resolved loader and analyzer options,
|
||||
analysis-adapter version, and maximum CPU count.
|
||||
_Avoid_: Configuration, settings
|
||||
|
||||
**Target Specification**:
|
||||
The loader, executable format, processor language, and compiler specification
|
||||
used by Ghidra to interpret a Sample.
|
||||
_Avoid_: Architecture, target
|
||||
|
||||
**Analysis**:
|
||||
The reusable body of facts Ghidra derives from one Sample under one Analysis
|
||||
Profile.
|
||||
_Avoid_: Project, database, workspace
|
||||
|
||||
**Quarantined Analysis**:
|
||||
Analysis data that failed integrity validation and is retained for diagnosis
|
||||
but can never satisfy a Query.
|
||||
_Avoid_: Analysis, cache miss
|
||||
|
||||
**Query**:
|
||||
A read-only question evaluated against an Analysis. A Query cannot change the
|
||||
Sample or Analysis.
|
||||
_Avoid_: Command, job, operation
|
||||
|
||||
**Function**:
|
||||
A Ghidra-discovered unit of executable behavior identified within an Analysis
|
||||
by its entry Address.
|
||||
_Avoid_: Symbol, method
|
||||
|
||||
**Function Selector**:
|
||||
An unambiguous reference used to choose a function by address or resolved
|
||||
symbol name.
|
||||
_Avoid_: Function name, function ID
|
||||
|
||||
**Call Edge**:
|
||||
A directed relationship from a caller Function through a callsite Address to
|
||||
a resolved or unresolved callee, produced by a future targeted Query.
|
||||
_Avoid_: Call, dependency
|
||||
|
||||
**Reference**:
|
||||
A Ghidra-derived relationship from one Address to another Address or external
|
||||
symbol, produced by a future targeted Query.
|
||||
_Avoid_: Pointer, cross-reference result
|
||||
|
||||
**Address**:
|
||||
A location within an Analysis identified by an explicit Ghidra address space
|
||||
and an offset whose width is defined by that space.
|
||||
_Avoid_: Integer, offset, pointer
|
||||
|
||||
**Artifact**:
|
||||
A durable, schema-versioned representation of a Query result tied to its
|
||||
Analysis.
|
||||
_Avoid_: Output, report, result file
|
||||
|
||||
**Analysis Store**:
|
||||
The tool-owned collection of reusable Analyses and Artifacts. It is disposable
|
||||
and never contains the authoritative Sample.
|
||||
_Avoid_: Project directory, cache directory, workspace
|
||||
**Diagnostic Log**:
|
||||
A tool-owned record of execution diagnostics that may explain an Analysis or
|
||||
Query failure but is not part of the Query result.
|
||||
_Avoid_: Artifact, output
|
||||
|
||||
**Invocation**:
|
||||
One synchronous attempt by the Rust harness to run a bounded Ghidra/Java
|
||||
operation and validate its response.
|
||||
_Avoid_: Job, session, worker
|
||||
|
||||
**Worker Sandbox**:
|
||||
The capability-limited environment containing only the untrusted Ghidra/JVM
|
||||
child for one Invocation; the trusted Rust harness remains outside it.
|
||||
_Avoid_: Analysis Store, containerized CLI
|
||||
|
||||
**Cleanup Transaction**:
|
||||
Tool-owned staged data that has been removed from active store visibility and
|
||||
is awaiting complete deletion or a recoverable retry.
|
||||
_Avoid_: Analysis, quarantine
|
||||
|
||||
**Target Verification**:
|
||||
The declared relationship between a Target Specification and the project's
|
||||
integration-test matrix: either verified or unverified.
|
||||
_Avoid_: Ghidra confidence, supported Sample
|
||||
|
||||
**Analysis Store**:
|
||||
The tool-owned collection of reusable Analyses, Quarantined Analyses, Artifacts,
|
||||
and Diagnostic Logs. It is disposable and never contains the authoritative
|
||||
Sample.
|
||||
_Avoid_: Project directory, cache directory, workspace
|
||||
|
|
|
|||
201
LICENSE
Normal file
201
LICENSE
Normal file
|
|
@ -0,0 +1,201 @@
|
|||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
21
README.md
21
README.md
|
|
@ -1,6 +1,7 @@
|
|||
# ghidra-cli
|
||||
|
||||
A small, dependable command-line interface for read-only Ghidra analysis.
|
||||
The repository is named `ghidra-cli`; the installed executable is `ghidr`.
|
||||
|
||||
The project is currently in its design phase. Its first objective is to make
|
||||
common reverse-engineering questions easy to ask without exposing Ghidra
|
||||
|
|
@ -9,14 +10,15 @@ project management, JVM lifecycle, or scripting details to the user.
|
|||
Proposed usage:
|
||||
|
||||
```console
|
||||
ghidra-cli doctor
|
||||
ghidra-cli inspect ./sample
|
||||
ghidra-cli functions ./sample
|
||||
ghidra-cli decompile ./sample main
|
||||
ghidr doctor
|
||||
ghidr inspect ./sample
|
||||
ghidr functions ./sample
|
||||
ghidr decompile ./sample --name main
|
||||
```
|
||||
|
||||
Each command will identify the sample by its content, reuse compatible cached
|
||||
analysis, and produce human-readable or versioned JSON output.
|
||||
analysis, and produce versioned JSON by default. Human-readable presentation is
|
||||
available explicitly through `--format human`.
|
||||
|
||||
## Documents
|
||||
|
||||
|
|
@ -24,6 +26,10 @@ analysis, and produce human-readable or versioned JSON output.
|
|||
scope.
|
||||
- [CONTEXT.md](./CONTEXT.md) defines the domain language used throughout the
|
||||
project.
|
||||
- [docs/adr/](./docs/adr/) records durable architectural decisions.
|
||||
- [docs/research/](./docs/research/) records cited prior-art investigations,
|
||||
including the Ghidra MCP comparison that informed protocol safeguards and
|
||||
the post-version-0.1 roadmap.
|
||||
|
||||
## Status
|
||||
|
||||
|
|
@ -32,5 +38,8 @@ begins after the initial requirements and interface are reviewed.
|
|||
|
||||
## License
|
||||
|
||||
No license has been selected yet. Until one is added, all rights are reserved.
|
||||
Licensed under the [Apache License 2.0](./LICENSE).
|
||||
|
||||
Development may use AI assistance. Maintainers remain responsible for reviewing
|
||||
the resulting design and code, verifying provenance, testing behavior, and
|
||||
ensuring dependency-license compatibility.
|
||||
|
|
|
|||
16
docs/adr/0001-version-the-json-contract.md
Normal file
16
docs/adr/0001-version-the-json-contract.md
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
---
|
||||
status: accepted
|
||||
---
|
||||
|
||||
# Version the JSON contract by compatibility boundary
|
||||
|
||||
Automation agents are the primary interface consumers, so success and error
|
||||
shapes must remain predictable across upgrades. The project publishes reviewed
|
||||
JSON Schema files under `schemas/v1/`: optional fields may be added within v1
|
||||
and consumers must ignore unknown fields, while removing a field or changing
|
||||
its type or meaning requires a new major schema version. The CLI initially
|
||||
emits only its current schema rather than carrying multiple encoders; golden
|
||||
fixtures and schema validation gate every success and error change. JSON mode
|
||||
also preserves strict stream framing: a success is the only stdout document, a
|
||||
failure is the only stderr document, and progress or diagnostic logs never
|
||||
share either stream.
|
||||
11
docs/adr/0002-keep-exit-statuses-coarse.md
Normal file
11
docs/adr/0002-keep-exit-statuses-coarse.md
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
---
|
||||
status: accepted
|
||||
---
|
||||
|
||||
# Keep exit statuses coarse
|
||||
|
||||
Shell callers need broad control-flow signals, while automation agents need
|
||||
precise diagnoses. The CLI therefore reserves exit statuses for success,
|
||||
invalid invocation, runtime failure, timeout, and interruption; the versioned
|
||||
JSON `error.code` carries the detailed failure taxonomy. This avoids maintaining
|
||||
two overlapping error classifications that could drift apart.
|
||||
13
docs/adr/0003-default-to-json-everywhere.md
Normal file
13
docs/adr/0003-default-to-json-everywhere.md
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
---
|
||||
status: accepted
|
||||
---
|
||||
|
||||
# Default to JSON everywhere
|
||||
|
||||
Automation agents are the primary consumers, so the shortest invocation must
|
||||
produce the stable machine interface. The CLI defaults to JSON regardless of
|
||||
whether stdout is a terminal or pipe; human-readable presentation requires
|
||||
`--format human`. Avoiding TTY-dependent format selection ensures that the same
|
||||
command has the same framing and semantics in every execution environment.
|
||||
JSON mode never emits interactive prompts; required confirmation is represented
|
||||
as a structured error and satisfied by an explicit flag.
|
||||
11
docs/adr/0004-never-reuse-partial-analysis.md
Normal file
11
docs/adr/0004-never-reuse-partial-analysis.md
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
---
|
||||
status: accepted
|
||||
---
|
||||
|
||||
# Never reuse a partial Analysis
|
||||
|
||||
Ghidra preserves analyzer results completed before its analysis timeout, but
|
||||
automation consumers cannot safely infer which facts are missing. New Analyses
|
||||
are therefore built in staging and promoted atomically only after full success;
|
||||
a timeout, interruption, or analysis failure preserves the Diagnostic Log,
|
||||
removes the partial staging project, and leaves no reusable Analysis.
|
||||
13
docs/adr/0005-analyze-a-staged-sample-snapshot.md
Normal file
13
docs/adr/0005-analyze-a-staged-sample-snapshot.md
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
---
|
||||
status: accepted
|
||||
---
|
||||
|
||||
# Analyze a staged Sample snapshot
|
||||
|
||||
Passing the caller's path to Ghidra after hashing creates a race in which the
|
||||
bytes analyzed may differ from the recorded Sample identity. The CLI instead
|
||||
copies the input through a read-only handle into private staging while hashing,
|
||||
verifies that source metadata did not change during the copy, and gives only
|
||||
that snapshot to Ghidra. The extra temporary I/O and disk use buy reproducible
|
||||
identity, isolate Java from the caller's path, and allow the snapshot to be
|
||||
removed after either success or failure.
|
||||
14
docs/adr/0006-sandbox-the-ghidra-worker.md
Normal file
14
docs/adr/0006-sandbox-the-ghidra-worker.md
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
---
|
||||
status: accepted
|
||||
---
|
||||
|
||||
# Sandbox the Ghidra worker
|
||||
|
||||
Ghidra parses adversarial Samples through a large Java analysis engine, while
|
||||
the Rust harness must manage trusted locks, store data, and atomic promotion.
|
||||
The harness therefore remains outside a narrow sandbox containing only the
|
||||
Ghidra/JVM worker and its invocation capabilities. Bubblewrap is the default
|
||||
Linux backend, with explicit external-harness and disabled modes for
|
||||
environments that cannot nest it. This limits a compromised worker's access
|
||||
without turning the CLI into a daemon or allowing arbitrary sandbox-runner
|
||||
commands.
|
||||
425
docs/research/ghidra-mcp-comparison.md
Normal file
425
docs/research/ghidra-mcp-comparison.md
Normal file
|
|
@ -0,0 +1,425 @@
|
|||
# Ghidra MCP comparison for `ghidra-cli`
|
||||
|
||||
Status: reviewed and adopted into the PRD, 2026-07-28
|
||||
|
||||
## Scope and source snapshots
|
||||
|
||||
This note compares the accepted `ghidra-cli` version 0.1 design with two
|
||||
primary-source repositories:
|
||||
|
||||
- LaurieWired/GhidraMCP at commit
|
||||
[`27f316f80139e2d5dec882519a1bdf4aa46ac04c`](https://github.com/LaurieWired/GhidraMCP/tree/27f316f80139e2d5dec882519a1bdf4aa46ac04c),
|
||||
tagged `1.4`.
|
||||
- bethington/ghidra-mcp at commit
|
||||
[`8cd2078e10b9ba28b188cb84ce5b9051a904b995`](https://github.com/bethington/ghidra-mcp/tree/8cd2078e10b9ba28b188cb84ce5b9051a904b995),
|
||||
tagged `v6.0.0`.
|
||||
|
||||
The comparison uses repository source, manifests, CI, licenses, changelogs,
|
||||
and the repositories' own issue reports. It does not treat README marketing
|
||||
claims as independently verified performance evidence.
|
||||
|
||||
## Executive conclusion
|
||||
|
||||
Do not change the version 0.1 architecture or widen its command surface because
|
||||
of these MCP implementations. The accepted synchronous Rust harness, private
|
||||
file protocol, one Sample per command, immutable Analysis, strict JSON, and
|
||||
sandboxed short-lived Ghidra worker directly avoid the largest sources of
|
||||
complexity visible in both repositories.
|
||||
|
||||
The repositories nevertheless validate several useful mechanisms:
|
||||
|
||||
- Relationship queries are the most valuable next capability for an agent.
|
||||
Prioritize `strings`, `xrefs`, and direct `calls` after version 0.1, followed
|
||||
by targeted disassembly and detailed single-Function inspection.
|
||||
- A large agent surface needs categories and capability discovery. Do not build
|
||||
that for four commands, but preserve command metadata so a future MCP adapter
|
||||
can expose a small, generated catalog without hand-written duplication.
|
||||
- Every process/protocol boundary needs independent size validation and
|
||||
parity tests. Add a small explicit ceiling for internal `request.json`, and
|
||||
test that Rust operation types, Java dispatch, and published schemas contain
|
||||
exactly the same operations.
|
||||
- Explicit target selection is essential. Keep requiring the Sample and exact
|
||||
Function Selector on every Query; never introduce a mutable “current
|
||||
program” fallback.
|
||||
- An eventual MCP integration should be a thin, separate adapter that invokes
|
||||
`ghidr` and forwards its schemas. It should not add an embedded HTTP server,
|
||||
persistent Ghidra session, or a second result contract to the core.
|
||||
|
||||
The principal rejection is breadth. One examined project exposes 272 catalog
|
||||
entries, including mutations, arbitrary scripts, project lifecycle, emulation,
|
||||
and debugging; its own users subsequently requested filtering because the
|
||||
surface was too large for agents ([issue #267](https://github.com/bethington/ghidra-mcp/issues/267))
|
||||
and raised broader maintainability and provenance concerns
|
||||
([issue #307](https://github.com/bethington/ghidra-mcp/issues/307)). The current
|
||||
`ghidra-cli` narrow vertical slice is a feature, not a gap.
|
||||
|
||||
## LaurieWired/GhidraMCP
|
||||
|
||||
### Architecture and state
|
||||
|
||||
The original project is a three-hop interactive topology:
|
||||
|
||||
```text
|
||||
MCP client -> Python FastMCP bridge -> HTTP -> plugin in a running Ghidra GUI
|
||||
```
|
||||
|
||||
The Python process speaks MCP over stdio by default and can expose SSE; every
|
||||
tool then makes an HTTP request to a configured Ghidra URL
|
||||
([bridge initialization and transports](https://github.com/LaurieWired/GhidraMCP/blob/27f316f80139e2d5dec882519a1bdf4aa46ac04c/bridge_mcp_ghidra.py#L15-L24),
|
||||
[CLI transport selection](https://github.com/LaurieWired/GhidraMCP/blob/27f316f80139e2d5dec882519a1bdf4aa46ac04c/bridge_mcp_ghidra.py#L290-L334)).
|
||||
The Java extension embeds `com.sun.net.httpserver.HttpServer` in Ghidra and
|
||||
operates on the GUI's `ProgramManager.getCurrentProgram()`
|
||||
([server construction](https://github.com/LaurieWired/GhidraMCP/blob/27f316f80139e2d5dec882519a1bdf4aa46ac04c/src/main/java/com/lauriewired/GhidraMCPPlugin.java#L95-L114),
|
||||
[current Program resolution](https://github.com/LaurieWired/GhidraMCP/blob/27f316f80139e2d5dec882519a1bdf4aa46ac04c/src/main/java/com/lauriewired/GhidraMCPPlugin.java#L1627-L1629)).
|
||||
Installation therefore requires installing and enabling a GUI extension and
|
||||
opening Ghidra, in addition to Python and the MCP SDK
|
||||
([installation prerequisites and workflow](https://github.com/LaurieWired/GhidraMCP/blob/27f316f80139e2d5dec882519a1bdf4aa46ac04c/README.md#L30-L79)).
|
||||
|
||||
This is session-oriented rather than content-oriented. The Sample is not an
|
||||
argument to a tool call; the implicit target is whichever Program is current
|
||||
in the GUI. Cursor-dependent tools expose the current address and Function,
|
||||
further coupling automation to interactive state
|
||||
([current-selection tool wrappers](https://github.com/LaurieWired/GhidraMCP/blob/27f316f80139e2d5dec882519a1bdf4aa46ac04c/bridge_mcp_ghidra.py#L150-L176)).
|
||||
|
||||
### Tool surface and mutation
|
||||
|
||||
The snapshot has 27 Python `@mcp.tool` declarations mapped to 27 Java HTTP
|
||||
contexts. Read tools cover Functions, classes/namespaces, segments, imports,
|
||||
exports, data, strings, disassembly, and cross-references. Write tools rename
|
||||
Functions, data, and variables; change prototypes and local types; and add
|
||||
comments
|
||||
([Python tool declarations](https://github.com/LaurieWired/GhidraMCP/blob/27f316f80139e2d5dec882519a1bdf4aa46ac04c/bridge_mcp_ghidra.py#L60-L288),
|
||||
[HTTP context registration](https://github.com/LaurieWired/GhidraMCP/blob/27f316f80139e2d5dec882519a1bdf4aa46ac04c/src/main/java/com/lauriewired/GhidraMCPPlugin.java#L109-L342)).
|
||||
Writes run Ghidra transactions on the Swing event thread, so this is not a
|
||||
read-only analysis layer
|
||||
([rename transaction](https://github.com/LaurieWired/GhidraMCP/blob/27f316f80139e2d5dec882519a1bdf4aa46ac04c/src/main/java/com/lauriewired/GhidraMCPPlugin.java#L512-L540)).
|
||||
|
||||
### Result contract and bounds
|
||||
|
||||
The outer MCP parameter schemas are inferred from Python type annotations, but
|
||||
the inner HTTP protocol is mostly newline-delimited text. `safe_get` splits
|
||||
text into lines, while failures are returned as strings in the same value
|
||||
channel rather than typed MCP errors
|
||||
([GET behavior](https://github.com/LaurieWired/GhidraMCP/blob/27f316f80139e2d5dec882519a1bdf4aa46ac04c/bridge_mcp_ghidra.py#L26-L43),
|
||||
[POST behavior](https://github.com/LaurieWired/GhidraMCP/blob/27f316f80139e2d5dec882519a1bdf4aa46ac04c/bridge_mcp_ghidra.py#L45-L58)).
|
||||
The Java server always responds with HTTP 200 and `text/plain`, including
|
||||
application errors
|
||||
([response writer](https://github.com/LaurieWired/GhidraMCP/blob/27f316f80139e2d5dec882519a1bdf4aa46ac04c/src/main/java/com/lauriewired/GhidraMCPPlugin.java#L1632-L1638)).
|
||||
|
||||
Many lists have `offset` and `limit`, normally defaulting to 0 and 100, but
|
||||
there is no `total`, `returned`, or `has_more` metadata. Some duplicate tools
|
||||
are unpaginated, such as `list_functions`
|
||||
([list wrapper](https://github.com/LaurieWired/GhidraMCP/blob/27f316f80139e2d5dec882519a1bdf4aa46ac04c/bridge_mcp_ghidra.py#L171-L176)).
|
||||
Pagination accepts negative and arbitrarily large values without a public
|
||||
validation contract
|
||||
([pagination implementation](https://github.com/LaurieWired/GhidraMCP/blob/27f316f80139e2d5dec882519a1bdf4aa46ac04c/src/main/java/com/lauriewired/GhidraMCPPlugin.java#L1582-L1606)).
|
||||
There is no whole-response byte bound or spill mechanism.
|
||||
|
||||
Function selection is ambiguous by construction: name selection returns the
|
||||
first exact basename encountered, and address selection accepts an interior
|
||||
address by resolving the containing Function
|
||||
([name selection](https://github.com/LaurieWired/GhidraMCP/blob/27f316f80139e2d5dec882519a1bdf4aa46ac04c/src/main/java/com/lauriewired/GhidraMCPPlugin.java#L493-L509),
|
||||
[interior-address fallback](https://github.com/LaurieWired/GhidraMCP/blob/27f316f80139e2d5dec882519a1bdf4aa46ac04c/src/main/java/com/lauriewired/GhidraMCPPlugin.java#L782-L805)).
|
||||
These are precisely the ambiguities the accepted `ghidra-cli` selector
|
||||
contract should continue rejecting.
|
||||
|
||||
The timeout layers are inconsistent. The Python bridge times every HTTP call
|
||||
out after five seconds, while Java decompilation can run for 30 or 60 seconds
|
||||
([bridge timeouts](https://github.com/LaurieWired/GhidraMCP/blob/27f316f80139e2d5dec882519a1bdf4aa46ac04c/bridge_mcp_ghidra.py#L35-L51),
|
||||
[decompiler timeout](https://github.com/LaurieWired/GhidraMCP/blob/27f316f80139e2d5dec882519a1bdf4aa46ac04c/src/main/java/com/lauriewired/GhidraMCPPlugin.java#L1202-L1217)).
|
||||
An MCP caller can therefore receive a timeout while Ghidra continues working.
|
||||
This validates `ghidra-cli`'s single derived child watchdog and process-group
|
||||
termination design.
|
||||
|
||||
### Security, tests, and dependencies
|
||||
|
||||
`new InetSocketAddress(port)` binds the embedded server without an explicit
|
||||
loopback address, and the request path shown has neither authentication nor a
|
||||
body-size cap
|
||||
([server bind](https://github.com/LaurieWired/GhidraMCP/blob/27f316f80139e2d5dec882519a1bdf4aa46ac04c/src/main/java/com/lauriewired/GhidraMCPPlugin.java#L95-L108),
|
||||
[unbounded form read](https://github.com/LaurieWired/GhidraMCP/blob/27f316f80139e2d5dec882519a1bdf4aa46ac04c/src/main/java/com/lauriewired/GhidraMCPPlugin.java#L1559-L1579)).
|
||||
The Ghidra process and plugin are unsandboxed and inherit the GUI user's
|
||||
filesystem and network access.
|
||||
|
||||
Runtime dependencies are Python 3.10+, `mcp`, and `requests`; the Java build
|
||||
uses Maven plus manually copied Ghidra JARs
|
||||
([Python requirements](https://github.com/LaurieWired/GhidraMCP/blob/27f316f80139e2d5dec882519a1bdf4aa46ac04c/bridge_mcp_ghidra.py#L1-L6),
|
||||
[system-scoped Ghidra JARs](https://github.com/LaurieWired/GhidraMCP/blob/27f316f80139e2d5dec882519a1bdf4aa46ac04c/pom.xml#L12-L87)).
|
||||
The only committed Java test is the Maven-template `assertTrue(true)` smoke
|
||||
test, so no endpoint, schema, timeout, security, or real-Ghidra regression is
|
||||
covered
|
||||
([test source](https://github.com/LaurieWired/GhidraMCP/blob/27f316f80139e2d5dec882519a1bdf4aa46ac04c/src/test/java/com/lauriewired/AppTest.java#L1-L35)).
|
||||
|
||||
## bethington/ghidra-mcp
|
||||
|
||||
### Architecture and state
|
||||
|
||||
This repository identifies itself as a substantial derivative of the Laurie
|
||||
project, not an independent implementation
|
||||
([NOTICE](https://github.com/bethington/ghidra-mcp/blob/8cd2078e10b9ba28b188cb84ce5b9051a904b995/NOTICE#L1-L10)).
|
||||
It retains the bridge topology but expands it:
|
||||
|
||||
```text
|
||||
MCP client -> Python MCP bridge -> UDS or HTTP -> Ghidra GUI plugin
|
||||
-> headless Java server
|
||||
-> optional debugger service
|
||||
```
|
||||
|
||||
The bridge supports stdio, Streamable HTTP, and deprecated SSE
|
||||
([bridge CLI](https://github.com/bethington/ghidra-mcp/blob/8cd2078e10b9ba28b188cb84ce5b9051a904b995/python/bridge_mcp_ghidra/cli.py#L102-L143)),
|
||||
while repository documentation describes separate GUI and headless Java
|
||||
servers and a Python protocol-conversion process
|
||||
([architecture](https://github.com/bethington/ghidra-mcp/blob/8cd2078e10b9ba28b188cb84ce5b9051a904b995/README.md#L977-L995)).
|
||||
|
||||
The bridge discovers server instances, remembers a connected project and
|
||||
transport, dynamically registers tools, and attempts reconnection after Ghidra
|
||||
restarts
|
||||
([shared mutable state](https://github.com/bethington/ghidra-mcp/blob/8cd2078e10b9ba28b188cb84ce5b9051a904b995/python/bridge_mcp_ghidra/state.py#L14-L35),
|
||||
[reconnection](https://github.com/bethington/ghidra-mcp/blob/8cd2078e10b9ba28b188cb84ce5b9051a904b995/python/bridge_mcp_ghidra/dispatch.py#L67-L128)).
|
||||
The cost is visible in the project's own issue history. Concurrent sub-agent
|
||||
calls caused intermittent bridge shutdown and forced a serialization lock
|
||||
([issue #91](https://github.com/bethington/ghidra-mcp/issues/91),
|
||||
[current lock](https://github.com/bethington/ghidra-mcp/blob/8cd2078e10b9ba28b188cb84ce5b9051a904b995/python/bridge_mcp_ghidra/state.py#L18-L25)).
|
||||
On macOS, a GUI/agent environment mismatch in `$TMPDIR` prevented Unix-socket
|
||||
discovery until the implementation learned to scan multiple candidate
|
||||
locations ([issue #170](https://github.com/bethington/ghidra-mcp/issues/170),
|
||||
[current discovery rationale](https://github.com/bethington/ghidra-mcp/blob/8cd2078e10b9ba28b188cb84ce5b9051a904b995/python/bridge_mcp_ghidra/discovery.py#L20-L40)).
|
||||
|
||||
These are real solutions for a persistent multi-instance service, but they are
|
||||
states `ghidra-cli` intentionally does not have.
|
||||
|
||||
### Tool surface, discovery, and mutation
|
||||
|
||||
The committed endpoint catalog declares 272 tools across 15 categories
|
||||
([catalog](https://github.com/bethington/ghidra-mcp/blob/8cd2078e10b9ba28b188cb84ce5b9051a904b995/tests/endpoints.json)).
|
||||
The surface includes read-only listing, Functions, cross-references, call
|
||||
graphs, strings, data flow, and memory inspection, but also symbol/type/comment
|
||||
mutation, project deletion and version control, arbitrary Java script
|
||||
execution, P-code emulation, and live debugging
|
||||
([feature inventory](https://github.com/bethington/ghidra-mcp/blob/8cd2078e10b9ba28b188cb84ce5b9051a904b995/README.md#L69-L95),
|
||||
[API categories](https://github.com/bethington/ghidra-mcp/blob/8cd2078e10b9ba28b188cb84ce5b9051a904b995/README.md#L624-L740)).
|
||||
|
||||
Its most reusable mechanism is annotation-driven registration. Java service
|
||||
methods carry tool/parameter annotations; one scanner creates deterministic
|
||||
HTTP endpoint definitions and a machine-readable input schema
|
||||
([scanner contract and sorting](https://github.com/bethington/ghidra-mcp/blob/8cd2078e10b9ba28b188cb84ce5b9051a904b995/src/main/java/com/xebyte/core/AnnotationScanner.java#L13-L87),
|
||||
[descriptor construction](https://github.com/bethington/ghidra-mcp/blob/8cd2078e10b9ba28b188cb84ce5b9051a904b995/src/main/java/com/xebyte/core/AnnotationScanner.java#L94-L118)).
|
||||
The Python bridge fetches that schema and generates callable MCP signatures at
|
||||
runtime
|
||||
([dynamic handler construction](https://github.com/bethington/ghidra-mcp/blob/8cd2078e10b9ba28b188cb84ce5b9051a904b995/python/bridge_mcp_ghidra/registry.py#L22-L146),
|
||||
[schema fetch](https://github.com/bethington/ghidra-mcp/blob/8cd2078e10b9ba28b188cb84ce5b9051a904b995/python/bridge_mcp_ghidra/registry.py#L302-L318)).
|
||||
|
||||
The current bridge can load categories lazily and exposes `search_tools`,
|
||||
`list_tool_groups`, and load/unload/check helpers
|
||||
([agent discovery workflow](https://github.com/bethington/ghidra-mcp/blob/8cd2078e10b9ba28b188cb84ce5b9051a904b995/README.md#L377-L393)).
|
||||
This directly addresses tool overload, but it also introduces another mutable
|
||||
session dimension and depends on clients honoring `tools/list_changed`.
|
||||
|
||||
### Result contract and bounds
|
||||
|
||||
The Java response type is an improvement over the original but remains a
|
||||
union of structured success, simple `{ "error": "message" }`, and raw text
|
||||
passthrough
|
||||
([sealed `Response`](https://github.com/bethington/ghidra-mcp/blob/8cd2078e10b9ba28b188cb84ce5b9051a904b995/src/main/java/com/xebyte/core/Response.java#L3-L43)).
|
||||
Consequently, some endpoints return JSON while many paginated endpoints still
|
||||
return newline-delimited text, and the dynamically generated MCP handlers all
|
||||
declare `str` results
|
||||
([text pagination](https://github.com/bethington/ghidra-mcp/blob/8cd2078e10b9ba28b188cb84ce5b9051a904b995/src/main/java/com/xebyte/core/ServiceUtils.java#L232-L244),
|
||||
[generated return annotation](https://github.com/bethington/ghidra-mcp/blob/8cd2078e10b9ba28b188cb84ce5b9051a904b995/python/bridge_mcp_ghidra/registry.py#L111-L145)).
|
||||
The live tool schema describes inputs, not stable versioned output schemas or
|
||||
typed error codes
|
||||
([schema translation](https://github.com/bethington/ghidra-mcp/blob/8cd2078e10b9ba28b188cb84ce5b9051a904b995/python/bridge_mcp_ghidra/schema.py#L54-L99)).
|
||||
|
||||
Request hardening is much stronger: version 6.0 applies a 64 MiB body ceiling
|
||||
and bounds actual reads rather than trusting `Content-Length`
|
||||
([request ceiling](https://github.com/bethington/ghidra-mcp/blob/8cd2078e10b9ba28b188cb84ce5b9051a904b995/src/main/java/com/xebyte/core/SecurityConfig.java#L51-L75),
|
||||
[HTTP enforcement](https://github.com/bethington/ghidra-mcp/blob/8cd2078e10b9ba28b188cb84ce5b9051a904b995/src/main/java/com/xebyte/GhidraMCPPlugin.java#L2253-L2263)).
|
||||
Response bounding remains endpoint-specific rather than a universal contract.
|
||||
For example, the whole-program call graph accepts `limit=0` as unlimited and
|
||||
can emit text, DOT, Mermaid, adjacency, or address-edge JSON
|
||||
([call-graph parameters and implementation](https://github.com/bethington/ghidra-mcp/blob/8cd2078e10b9ba28b188cb84ce5b9051a904b995/src/main/java/com/xebyte/core/XrefCallGraphService.java#L782-L877)).
|
||||
`ghidra-cli`'s one schema, disclosed collection bounds, and universal serialized
|
||||
byte cap are materially stronger for an automation agent.
|
||||
|
||||
The bridge coordinates endpoint-specific HTTP timeouts and retries GET calls;
|
||||
write calls deliberately avoid blind retry because completion is ambiguous
|
||||
after a connection loss
|
||||
([timeout catalog](https://github.com/bethington/ghidra-mcp/blob/8cd2078e10b9ba28b188cb84ce5b9051a904b995/python/bridge_mcp_ghidra/config.py#L7-L35),
|
||||
[retry policies](https://github.com/bethington/ghidra-mcp/blob/8cd2078e10b9ba28b188cb84ce5b9051a904b995/python/bridge_mcp_ghidra/dispatch.py#L131-L195)).
|
||||
Notably, the bridge's `decompile_function` timeout is 45 seconds while the
|
||||
Java endpoint defaults to 60 seconds
|
||||
([bridge value](https://github.com/bethington/ghidra-mcp/blob/8cd2078e10b9ba28b188cb84ce5b9051a904b995/python/bridge_mcp_ghidra/config.py#L21-L34),
|
||||
[Java value](https://github.com/bethington/ghidra-mcp/blob/8cd2078e10b9ba28b188cb84ce5b9051a904b995/src/main/java/com/xebyte/core/FunctionService.java#L149-L186)).
|
||||
This is further evidence that one owning harness should derive and enforce the
|
||||
complete child lifetime.
|
||||
|
||||
The project learned an important target-selection lesson. Calls default to a
|
||||
mutable active Program; strict explicit Program selectors exist only behind an
|
||||
environment variable because compatibility retained the fallback
|
||||
([strict-mode rationale](https://github.com/bethington/ghidra-mcp/blob/8cd2078e10b9ba28b188cb84ce5b9051a904b995/README.md#L350-L375),
|
||||
[bridge enforcement](https://github.com/bethington/ghidra-mcp/blob/8cd2078e10b9ba28b188cb84ce5b9051a904b995/python/bridge_mcp_ghidra/registry.py#L26-L87)).
|
||||
`ghidra-cli` should keep Sample selection mandatory from its first release and
|
||||
never acquire this compatibility burden.
|
||||
|
||||
### Security, tests, and dependencies
|
||||
|
||||
Current security controls include loopback defaults, refusal of a non-loopback
|
||||
bind without bearer authentication, anti-CSRF/DNS-rebinding checks, script
|
||||
execution disabled by default, filesystem-root containment, request-body
|
||||
caps, and generic uncaught-error responses
|
||||
([security configuration](https://github.com/bethington/ghidra-mcp/blob/8cd2078e10b9ba28b188cb84ce5b9051a904b995/README.md#L440-L493),
|
||||
[safe handler](https://github.com/bethington/ghidra-mcp/blob/8cd2078e10b9ba28b188cb84ce5b9051a904b995/src/main/java/com/xebyte/GhidraMCPPlugin.java#L2210-L2279)).
|
||||
The change history states that these were hardening changes after earlier
|
||||
unauthenticated, ungated, or insufficiently bounded behavior
|
||||
([v6.0.0 security history](https://github.com/bethington/ghidra-mcp/blob/8cd2078e10b9ba28b188cb84ce5b9051a904b995/CHANGELOG.md#L7-L73)).
|
||||
|
||||
These controls are valuable for a network service, but they do not isolate
|
||||
Ghidra from the user's account. `ghidra-cli` should retain the stronger design
|
||||
of no listener plus a capability-limited worker sandbox. If it ever adds an
|
||||
MCP adapter, stdio should remain the default and network transport should be a
|
||||
separately threat-modeled feature.
|
||||
|
||||
The shipped bridge requires Python 3.10+ and the `mcp` package; tests and
|
||||
unshipped subsystems add many optional dependencies
|
||||
([package manifest](https://github.com/bethington/ghidra-mcp/blob/8cd2078e10b9ba28b188cb84ce5b9051a904b995/pyproject.toml#L1-L24),
|
||||
[dependency groups](https://github.com/bethington/ghidra-mcp/blob/8cd2078e10b9ba28b188cb84ce5b9051a904b995/pyproject.toml#L53-L101)).
|
||||
The repository has a materially stronger regression practice than the original:
|
||||
Java offline tests and coverage, a Python version matrix, Windows-specific
|
||||
tests, performance regressions, and Pester setup tests are gating; formatting
|
||||
and lint jobs are currently advisory
|
||||
([CI gates](https://github.com/bethington/ghidra-mcp/blob/8cd2078e10b9ba28b188cb84ce5b9051a904b995/.github/workflows/tests.yml#L16-L181),
|
||||
[quality jobs](https://github.com/bethington/ghidra-mcp/blob/8cd2078e10b9ba28b188cb84ce5b9051a904b995/.github/workflows/tests.yml#L288-L358)).
|
||||
Its annotation/schema/catalog parity approach is worth borrowing; its broad
|
||||
multi-subsystem matrix is not needed for version 0.1.
|
||||
|
||||
## Recommendations for `ghidra-cli`
|
||||
|
||||
### Adopt now
|
||||
|
||||
1. **Keep one source of truth for operations.** Define every internal operation
|
||||
once with its request type, response type, public command kind, and schema
|
||||
name. Generate or mechanically verify the Rust schema set and Java dispatch
|
||||
set against it. The bethington annotation scanner demonstrates the value of
|
||||
preventing hand-maintained endpoint/schema drift, while `ghidra-cli` can do
|
||||
this without runtime reflection or dynamic registration.
|
||||
|
||||
2. **Cap both sides of the private protocol.** The accepted 256 MiB response
|
||||
ceiling is good. Add a much smaller fixed serialized `request.json` ceiling,
|
||||
suggested at 1 MiB, enforced by Rust before launch and Java before parse.
|
||||
Requests contain metadata and tool-owned paths, not Sample bytes, so a
|
||||
larger allowance has no known use. This is a protocol-hardening detail, not
|
||||
a public CLI flag.
|
||||
|
||||
3. **Add protocol/catalog parity regressions.** A fixture should fail if a Rust
|
||||
operation lacks Java handling, if Java accepts an unpublished operation, or
|
||||
if a public schema/golden is missing. Keep the already accepted real-Ghidra
|
||||
ELF and PE integration tests and strict lint/format gates.
|
||||
|
||||
4. **Retain mandatory targets and stable identifiers.** Every Query keeps an
|
||||
explicit Sample; Function operations keep exact entry Address or exact name
|
||||
selection with ambiguity errors. Do not add GUI cursor, active Program, or
|
||||
implicit containing-Function behavior.
|
||||
|
||||
5. **Preserve extension metadata without exposing it yet.** Command/domain
|
||||
definitions may carry a stable category and one-sentence agent description.
|
||||
This costs little and lets a later MCP adapter generate a discoverable
|
||||
surface, but version 0.1 needs no `search-tools`, runtime group loading, or
|
||||
config file.
|
||||
|
||||
### Defer in priority order
|
||||
|
||||
1. **`strings` Query.** Return a bounded, stably ordered list with exact Address,
|
||||
byte length, decoded representation with explicit encoding, and referring
|
||||
Addresses or a separate bounded reference link. Avoid case-folded server-side
|
||||
substring filters initially; agents can use `jq`, and raw Sample-derived
|
||||
strings may be non-UTF-8 or extremely large.
|
||||
|
||||
2. **`xrefs` Query.** Model each Reference structurally: source Address,
|
||||
destination Address or external target, Ghidra reference type, operand index,
|
||||
and containing source Function entry when present. Direction should be an
|
||||
explicit enum. Never emit prose such as `From ... in ... [READ]`.
|
||||
|
||||
3. **Direct `calls` Query.** Start with flat Call Edges containing caller entry,
|
||||
callsite, and resolved or unresolved callee. Support pagination and stable
|
||||
ordering. Do not begin with recursive whole-program graphs, DOT/Mermaid
|
||||
renderers, graph algorithms, or `limit=0` unlimited output; agents can build
|
||||
graphs from bounded edge pages.
|
||||
|
||||
4. **Targeted `disassemble` and `function` detail Queries.** These are more
|
||||
useful than widening every `functions` item. A detailed Function result can
|
||||
later carry signature, parameters, locals, body ranges, thunk resolution,
|
||||
and alternate symbols without making discovery pages expensive.
|
||||
|
||||
5. **Batch Query execution.** Multiple decompilations in one Ghidra process may
|
||||
eventually reduce startup cost, but only add it after measurements. It needs
|
||||
explicit per-item success/error objects, deterministic order, aggregate
|
||||
byte bounds, cancellation semantics, and no hidden parallelism.
|
||||
|
||||
6. **Thin MCP adapter.** After schemas and CLI behavior stabilize, a separate
|
||||
package can expose one MCP tool per stable `ghidr` Query, invoke the CLI over
|
||||
stdio/process execution, and forward its JSON unchanged. If the surface later
|
||||
grows, generated categories and a capability-search tool become appropriate.
|
||||
The adapter should not call Ghidra directly or own Analysis Store policy.
|
||||
|
||||
7. **Interactive/mutating analysis.** Renames, types, comments, scripts,
|
||||
debugging, and shared-project workflows solve a different problem. If ever
|
||||
pursued, put them behind a separate explicit write-capability model and a
|
||||
separate domain contract; do not weaken immutable Analysis semantics.
|
||||
|
||||
### Explicitly reject for version 0.1
|
||||
|
||||
- Embedded HTTP, TCP, UDS, SSE, Streamable HTTP, discovery scans, reconnect
|
||||
logic, persistent daemons, and background JVMs.
|
||||
- Mutable current-Program/current-Address/current-Function session state.
|
||||
- Any automatic first match for duplicate Function names or interior addresses.
|
||||
- Raw text success/error unions, HTTP-status tunneling, untyped addresses, and
|
||||
prose records that agents must parse.
|
||||
- Hidden retry escalation. A caller may explicitly retry a failed read-only
|
||||
Query; `ghidr` must not multiply time budgets behind the contract.
|
||||
- Arbitrary Java/Python scripts, mutation, project management, debugger control,
|
||||
emulation, binary export, and Ghidra Server administration.
|
||||
- Whole-program graph renderers and custom search/query languages. Emit bounded
|
||||
facts; let `jq` and downstream tools transform them.
|
||||
- Runtime tool-group loading for the initial four-command surface.
|
||||
- A database or global mutable index merely to support discovery or MCP state.
|
||||
|
||||
## Licensing and provenance
|
||||
|
||||
Both repositories use Apache-2.0
|
||||
([LaurieWired license](https://github.com/LaurieWired/GhidraMCP/blob/27f316f80139e2d5dec882519a1bdf4aa46ac04c/LICENSE),
|
||||
[bethington package license](https://github.com/bethington/ghidra-mcp/blob/8cd2078e10b9ba28b188cb84ce5b9051a904b995/pyproject.toml#L1-L9)).
|
||||
The bethington repository explicitly retains attribution to LaurieWired for
|
||||
portions that remain
|
||||
([NOTICE](https://github.com/bethington/ghidra-mcp/blob/8cd2078e10b9ba28b188cb84ce5b9051a904b995/NOTICE#L1-L10)).
|
||||
|
||||
Concepts, public Ghidra API usage patterns, and independently designed schemas
|
||||
may be studied without making `ghidra-cli` a derivative. If any source or close
|
||||
adaptation is copied, Apache-2.0 requires preserving applicable copyright,
|
||||
license, change, and NOTICE obligations. The cleanest course is to keep the
|
||||
implementation independent, cite these projects as prior art in research and
|
||||
design notes, and record provenance for any deliberately reused code before it
|
||||
enters a commit.
|
||||
|
||||
The open maintainability issue also alleges that some contributor changes were
|
||||
recommitted in ways that obscured authorship. This report does not adjudicate
|
||||
that allegation, but it reinforces the accepted `ghidra-cli` rule: AI assistance
|
||||
does not replace review, attribution, or a traceable change history
|
||||
([issue #307](https://github.com/bethington/ghidra-mcp/issues/307)).
|
||||
|
||||
## Decision impact
|
||||
|
||||
No accepted version 0.1 product decision should be removed. The research adds
|
||||
three concrete implementation-time checks and a clearer post-0.1 order:
|
||||
|
||||
- internal request-size ceiling;
|
||||
- operation/Java/schema parity test;
|
||||
- relationship-query order: `strings`, `xrefs`, direct `calls`, then targeted
|
||||
disassembly and Function detail.
|
||||
|
||||
Everything else belongs either in a future thin MCP adapter or in a separately
|
||||
designed interactive/mutating product.
|
||||
|
||||
The PRD now records the request ceiling, operation/dispatch/schema parity,
|
||||
no-default-egress regression coverage, ordered relationship Queries, bounded
|
||||
batch prerequisites, and thin-adapter MCP boundary. These adoptions do not add
|
||||
a public version 0.1 command or widen the Java adapter's authority.
|
||||
Loading…
Add table
Add a link
Reference in a new issue