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
|
_Avoid_: Binary, file, target
|
||||||
|
|
||||||
**Analysis Profile**:
|
**Analysis Profile**:
|
||||||
The declared analysis inputs other than the Sample, including the Ghidra
|
The canonical analysis inputs other than the Sample, including Ghidra and Java
|
||||||
version, analyzer configuration, language selection, and tool protocol version.
|
versions, Target Specification, fully resolved loader and analyzer options,
|
||||||
|
analysis-adapter version, and maximum CPU count.
|
||||||
_Avoid_: Configuration, settings
|
_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**:
|
**Analysis**:
|
||||||
The reusable body of facts Ghidra derives from one Sample under one Analysis
|
The reusable body of facts Ghidra derives from one Sample under one Analysis
|
||||||
Profile.
|
Profile.
|
||||||
_Avoid_: Project, database, workspace
|
_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**:
|
**Query**:
|
||||||
A read-only question evaluated against an Analysis. A Query cannot change the
|
A read-only question evaluated against an Analysis. A Query cannot change the
|
||||||
Sample or Analysis.
|
Sample or Analysis.
|
||||||
_Avoid_: Command, job, operation
|
_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**:
|
**Function Selector**:
|
||||||
An unambiguous reference used to choose a function by address or resolved
|
An unambiguous reference used to choose a function by address or resolved
|
||||||
symbol name.
|
symbol name.
|
||||||
_Avoid_: Function name, function ID
|
_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**:
|
**Artifact**:
|
||||||
A durable, schema-versioned representation of a Query result tied to its
|
A durable, schema-versioned representation of a Query result tied to its
|
||||||
Analysis.
|
Analysis.
|
||||||
_Avoid_: Output, report, result file
|
_Avoid_: Output, report, result file
|
||||||
|
|
||||||
**Analysis Store**:
|
**Diagnostic Log**:
|
||||||
The tool-owned collection of reusable Analyses and Artifacts. It is disposable
|
A tool-owned record of execution diagnostics that may explain an Analysis or
|
||||||
and never contains the authoritative Sample.
|
Query failure but is not part of the Query result.
|
||||||
_Avoid_: Project directory, cache directory, workspace
|
_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
|
# ghidra-cli
|
||||||
|
|
||||||
A small, dependable command-line interface for read-only Ghidra analysis.
|
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
|
The project is currently in its design phase. Its first objective is to make
|
||||||
common reverse-engineering questions easy to ask without exposing Ghidra
|
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:
|
Proposed usage:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
ghidra-cli doctor
|
ghidr doctor
|
||||||
ghidra-cli inspect ./sample
|
ghidr inspect ./sample
|
||||||
ghidra-cli functions ./sample
|
ghidr functions ./sample
|
||||||
ghidra-cli decompile ./sample main
|
ghidr decompile ./sample --name main
|
||||||
```
|
```
|
||||||
|
|
||||||
Each command will identify the sample by its content, reuse compatible cached
|
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
|
## Documents
|
||||||
|
|
||||||
|
|
@ -24,6 +26,10 @@ analysis, and produce human-readable or versioned JSON output.
|
||||||
scope.
|
scope.
|
||||||
- [CONTEXT.md](./CONTEXT.md) defines the domain language used throughout the
|
- [CONTEXT.md](./CONTEXT.md) defines the domain language used throughout the
|
||||||
project.
|
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
|
## Status
|
||||||
|
|
||||||
|
|
@ -32,5 +38,8 @@ begins after the initial requirements and interface are reviewed.
|
||||||
|
|
||||||
## License
|
## 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