mirror of
https://github.com/morluto/rea.git
synced 2026-11-13 05:01:45 -10:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8773ff231a | ||
|
|
a56139eec3 | ||
|
|
825c37b2f0 | ||
|
|
4ca8ff52ab | ||
|
|
65911d3f6d | ||
|
|
fe93175a72 | ||
|
|
0a723689fa |
No files matched your search
@@ -2,607 +2,123 @@
|
||||
name: reverse-engineer-anything
|
||||
description: Reverse engineer native, managed, Electron/JavaScript, packaged, firmware, and browser targets with REA, and build agent environments (AgentEnv bundles) of web applications from a live instance or a capture, and of Linux desktop apps with a task from a request. Use shipped-artifact or requested runtime evidence to explain features, compare versions, decompile code, or guide a reconstruction. Skip REA for ordinary source-repository architecture analysis.
|
||||
metadata:
|
||||
version: "62"
|
||||
version: "64"
|
||||
---
|
||||
|
||||
# REA
|
||||
|
||||
Use REA when a claim depends on a shipped binary or package, decompilation,
|
||||
requested runtime evidence, or comparison with
|
||||
behavior not established by available source. For ordinary analysis of a
|
||||
complete source repository, use normal repository tools and do not run REA
|
||||
Use REA when a claim depends on a shipped artifact, decompilation, requested
|
||||
runtime evidence, or behavior not established by available source. For ordinary
|
||||
analysis of a complete source repository, use normal repository tools and do not run REA
|
||||
readiness or provider commands.
|
||||
|
||||
## Select the target and authority
|
||||
|
||||
Use the target selected for this task. If the user says only "my app", ask which
|
||||
app before searching artifacts. Resolve a named app to one clear installed
|
||||
artifact; ask when ambiguous. Unrelated reports and nearby fixtures do not select
|
||||
it. Never substitute an example or broaden the selected target or runtime actions.
|
||||
|
||||
Distinguish observations, derivations, inferences, and unknowns. Cite Evidence
|
||||
IDs and preserve source identity, coverage, limitations and partial facts.
|
||||
Static code, strings and declarations do not establish observed execution.
|
||||
Within the requested investigation, call available analysis tools directly;
|
||||
REA requires no permission grants or per-call approval flags. The client may
|
||||
independently require approval; preserve its actual access requirements.
|
||||
|
||||
## Connect only when needed
|
||||
|
||||
Installing this skill supplies instructions; it does not register the REA MCP
|
||||
server, install analysis engines, or add tools to an already-running agent.
|
||||
The exception is a Claude Code, Codex, or Cursor Marketplace plugin install:
|
||||
the plugin bundles this skill and registers its own `rea` server, outside the
|
||||
state that `rea setup` and `rea doctor` manage.
|
||||
If REA tools are available and registration is not known stale, proceed directly.
|
||||
Use the connected server's actual tool list and schemas: repository-main guidance
|
||||
may describe features absent from an older release. Keep complete inline Evidence
|
||||
when retained references are not advertised. Skill installation alone adds no
|
||||
MCP server or engines; a Claude Code, Codex or Cursor Marketplace plugin bundles its own server.
|
||||
|
||||
If REA tools are available and their registration is not known to be stale,
|
||||
proceed directly to the target. Do not run diagnostics or setup before every
|
||||
investigation. Use the connected server's actual tool list and input schemas;
|
||||
a skill installed from repository main may describe capabilities absent from
|
||||
an older npm release. Keep complete inline Evidence when that server does not
|
||||
advertise retained references.
|
||||
For absent tools, blocked calls, unavailable providers, host timeouts or startup
|
||||
failures, read [connection and recovery](references/connection-and-recovery.md)
|
||||
before repair. Diagnose the observed blocker, continue useful supported work,
|
||||
and resume the original task after repair. Do not repeat unchanged failed calls.
|
||||
A host timeout without a REA result does not establish cancellation or cleanup.
|
||||
Retry a dropped connection once only if safe to repeat or known not started;
|
||||
if it may have changed the target, or fails again, ask for a client restart.
|
||||
Retry failed connection startup once; do not retry the same unchanged failure.
|
||||
|
||||
If tools are absent, a call is blocked by the client, or a required provider is
|
||||
unavailable, read [connection and recovery](references/connection-and-recovery.md).
|
||||
Diagnose the observed blocker, continue useful supported work, and resume the
|
||||
original task after repair. Client approval, shell PATH, registration and engine
|
||||
availability have different remedies; avoid repeating setup for all of them.
|
||||
If the host times out without a REA result, do not repeat the unchanged call or
|
||||
assume work stopped. Read the recovery guide's deadline distinction before retrying.
|
||||
If the MCP connection drops, retry that call once only when it is safe to
|
||||
repeat or known not to have started. If it may already have changed the
|
||||
target, or it fails again, tell the user and ask them to restart the MCP
|
||||
client. If REA could not start its connection, retry once, then tell the user
|
||||
and ask them to restart the MCP client. Do not retry a startup failure that
|
||||
returns the same unchanged result. For plugin installs, follow
|
||||
[plugin recovery](references/connection-and-recovery.md#rea-installed-as-a-client-plugin).
|
||||
For setup-owned registrations, run `rea doctor` when REA could not start
|
||||
or tools stay missing after that restart. For `cleanup_incomplete`, a retryable
|
||||
capacity limit, or `configuration_invalid`, follow the recovery guide's ladder
|
||||
before asking for a restart. Read that guide before a second repair attempt.
|
||||
|
||||
Choose the installation owner before repairing registration. Plugin installs use
|
||||
[plugin recovery](references/connection-and-recovery.md#rea-installed-as-a-client-plugin);
|
||||
only setup-owned registrations use the guide's
|
||||
[registration repair plan](references/connection-and-recovery.md#repair-registration-when-needed).
|
||||
Choose the registration owner: plugin recovery differs from setup-owned repair.
|
||||
A plugin-only doctor result of `missing` does not call for `rea setup`.
|
||||
Setup-owned repair starts with a read-only plan showing paths, backups and skill
|
||||
replacement before authorized writes. Do not install unrelated software to repair
|
||||
registration. REA setup never installs/upgrades Node, npm, Homebrew, Java,
|
||||
Ghidra, IDA, JADX, Kuna, Binwalk or Unblob.
|
||||
For an unsupported client, use manual stdio with an existing absolute runtime
|
||||
and entry script, or the CLI fallback in the recovery guide.
|
||||
|
||||
REA setup never installs or upgrades Node.js, npm, Homebrew, Java, Ghidra, IDA,
|
||||
JADX, Kuna, Binwalk, or Unblob. Use existing prerequisites; do not install unrelated
|
||||
software to repair MCP registration. For an unsupported client, use manual stdio
|
||||
registration with an existing installation’s absolute runtime and entry script, or continue through the CLI.
|
||||
## Route before analysis
|
||||
|
||||
A concrete CLI fallback for an operator-supplied JavaScript tree or ASAR is:
|
||||
Read the matching guide before its workflow; read only the relevant sections.
|
||||
Target-free tools take their explicit paths/endpoints without `open_binary`.
|
||||
Active-target native/archive tools require it. Archive members and executable
|
||||
code are different questions; follow the selected artifact's application layer.
|
||||
|
||||
```bash
|
||||
npx -y rea-agents@latest analyze-javascript-application /absolute/path/to/app --json
|
||||
```
|
||||
| Supplied target or question | Guide and first operation |
|
||||
| ------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| Native executable/library, Ghidra/IDA/Kuna, managed PE/CLI or NativeAOT | [Native and managed](references/native-and-artifacts.md): `open_binary`; managed CLI metadata: `inspect_managed_artifact`. Read provider/lifecycle sections before reuse or edits. |
|
||||
| Headerless/raw firmware, Cortex-M, ESP app/bootloader or whole-flash dump, HEX/S-record/UF2/DfuSe | [Firmware and raw images](references/firmware-and-raw-images.md): check loader support first; raw: explicit `open_binary` format/mapping; ESP/container: `open_binary` then `inspect_artifact`; region scan/extraction: advertised firmware tools. |
|
||||
| Archive/package inventory or extraction, PyInstaller, Bun/Deno executable, Godot PCK, UnityFS or wxapkg | [Packages and archives](references/packages-and-archives.md): `open_binary`, then `inspect_artifact`; read extraction/mount limits before materializing. |
|
||||
| ASAR/extracted JavaScript or Electron tree, feature trace or version comparison | [JavaScript applications](references/javascript-applications.md): `analyze_javascript_application`. |
|
||||
| APK code, manifest, classes, methods or incoming references | [Android applications](references/android-applications.md): `inspect_android_package`; signing/inventory use their separate routes. |
|
||||
| PE/ELF/Mach-O tables or hardening, Go/Rust/IL2CPP/GPU/model metadata, Windows shortcuts, kernel config, pyc/BEAM, SQLite, WASM, EVM, APK signing or recorded crash | [Offline format inspectors](references/format-inspectors.md): select the named target-free inspector in that format's section. |
|
||||
| Shipped application exposure for a local app, install directory, ASAR or executable | [Offline format inspectors](references/format-inspectors.md#release-exposure): `audit_release_exposure`; preserve unknown/unassessed checks and marker-only credential findings. |
|
||||
| Apple plist, Interface Builder, asset catalog or keyed archive resources; unknown desktop installation directory | [Resource and directory inspection](references/native-and-artifacts.md#apple-app-resources): `open_bundle_resources` or `inspect_desktop_application`; no executable/provider required for resource sessions. |
|
||||
| Native execution, live calls, instrumentation, process effects; browser/Electron runtime or agent-performed actions | [Runtime observation](references/runtime-observation.md): select the observation and declared lifecycle first. Already-open page: `list_browser_targets`; Electron: `list_electron_targets`; agent actions: `capture_browser_scenario`. |
|
||||
| Recorded HAR/SAZ/mitmproxy/qlog, packet capture, protocol-field discovery or logic/signal recording | [Recorded captures](references/recorded-captures.md): `inspect_web_network_capture`, packet/signal inspection or decoder discovery as appropriate; no live acquisition or recorded-URL fetch. |
|
||||
| Web AgentEnv bundle from a live instance or capture; task for an exported desktop environment | [Environments](references/environments.md), including its desktop-task section: read before recording/export; `capture_browser_scenario` then `export_environment_bundle` for a live web bundle. |
|
||||
| Linux desktop application environment built from a user request | [Desktop builds](references/desktop-build.md): drive the selected app on a build computer, then export and witness. |
|
||||
| Retained Evidence paging/composition, comparisons, unknowns or a broader investigation | [Evidence workflows](references/evidence-workflows.md): use existing source IDs and the smallest view that answers the question. |
|
||||
|
||||
No MCP registration or native engine is required. Read the returned Evidence,
|
||||
graph, limitations, and unknowns with the same care as an MCP result; the CLI
|
||||
returns the Evidence record directly. This fallback does not establish that
|
||||
MCP is configured. Native CLI tasks still require their selected engine.
|
||||
Prefer an existing `rea` CLI. When none is installed and REA package acquisition
|
||||
is within the authorized scope, use `npx -y rea-agents@latest` in its place from a
|
||||
trusted directory outside the target project, with absolute target paths. Managed
|
||||
setup binds the current installation directly; retain its runtime and package
|
||||
cache entry, or restore that installation before repairing its registration.
|
||||
For setup-owned registration, configuration repair starts with a read-only setup plan; show paths, backups and
|
||||
skill replacement before applying authorized changes. Preserve existing approval
|
||||
and target-execution boundaries.
|
||||
|
||||
## Route the target first
|
||||
|
||||
Choose the first tool from the target the user supplied. Use `open_binary` for
|
||||
active-target native or archive workflows; target-free tools take their own
|
||||
explicit path or endpoint and do not need it.
|
||||
|
||||
- ASAR or extracted JavaScript/Electron tree:
|
||||
`analyze_javascript_application`.
|
||||
- Archive/package member inventory (ZIP/APK/IPA/MSIX/AppX, DMG, or a PyInstaller
|
||||
executable): `open_binary` with the supplied local path; use `inspect_artifact`
|
||||
when its graph and findings help answer the question. A PyInstaller CArchive
|
||||
is the application layer; the bootloader is only the native prefix. Start with
|
||||
`detail: "summary"` for large inventories, then use retained inventory views
|
||||
for selected member fields/pages. A complete small inventory can cost less
|
||||
than extra calls and schemas. Runtime options are metadata, not files.
|
||||
Compact delivery still inventories and hashes members. See the
|
||||
[Python packaged applications guide](https://github.com/morluto/rea/blob/main/docs/python-packaged-applications.md).
|
||||
- Bun `--compile` executable: `open_binary`, then `inspect_artifact`; the Bun
|
||||
module graph is the application layer. Extract stored modules and analyze the
|
||||
JavaScript. See [Bun standalone executables](https://github.com/morluto/rea/blob/main/docs/bun-standalone.md).
|
||||
- Deno `deno compile` executable: `open_binary`, then `inspect_artifact`; the
|
||||
embedded virtual filesystem is the application layer. Extract stored files and
|
||||
analyze compatible JavaScript. Environment-file values and CA certificate bytes
|
||||
are retained in local Evidence with their counts and byte lengths. The npm
|
||||
snapshot length is reported and not decoded, and the executable is not run. See
|
||||
[Deno compile executables](https://github.com/morluto/rea/blob/main/docs/deno-standalone.md).
|
||||
- Apple app plist, Interface Builder, asset catalog, or keyed archive resources:
|
||||
`open_bundle_resources`, then the selected resource tool. This does not
|
||||
require `CFBundleExecutable` or a deep provider. Resource sessions have no
|
||||
executable digest or binary snapshot; use `open_binary` for native code.
|
||||
- Android APK code, classes, methods, or incoming references:
|
||||
`inspect_android_package`, then focused Android tools when advertised.
|
||||
Archive member inventory still uses the archive route above.
|
||||
- Managed PE/CLI assembly: `inspect_managed_artifact`.
|
||||
- Firmware image: `inspect_firmware_regions` when advertised. Use
|
||||
`extract_firmware` when extraction is requested, with a caller-selected new
|
||||
absolute output directory. These tools use caller-supplied Binwalk/Unblob on
|
||||
Linux; see the [firmware guide](https://github.com/morluto/rea/blob/main/docs/guides/firmware/firmware-analysis.md).
|
||||
- ESP32-family app or bootloader image (`0xE9` magic): `inspect_artifact`
|
||||
without a provider; see the ESP section of `references/native-and-artifacts.md`.
|
||||
- .NET NativeAOT PE/ELF: native Ghidra analysis. Native code can yield pseudocode;
|
||||
consult the NativeAOT workflow in `references/native-and-artifacts.md` for
|
||||
optional metadata recovery and its supported host/layout boundary.
|
||||
- Native program behavior, live calls, instrumentation, or command-run effects:
|
||||
choose the matching [native runtime workflow](references/runtime-observation.md#native-runtime-questions).
|
||||
`open_binary` and `trace_native_values` establish static facts; they do not
|
||||
observe execution. Runtime tools have distinct launch, attach, mutation and
|
||||
cleanup effects, and do not require a preliminary static session unless their
|
||||
own contract says so.
|
||||
- User-owned browser page already open: `list_browser_targets`.
|
||||
- Passive traffic capture of a SPA: the default scope is the page's own origin,
|
||||
and data APIs usually live on another origin. Discover API origins from
|
||||
absolute URLs in loaded bundles or script text via JavaScript analysis tools
|
||||
(another passive capture without those origins still scopes to the page
|
||||
origin, and `completeness.excluded` counts lack URLs). Pass both the page
|
||||
origin and those API origins in `allowed_origins` — the list replaces the
|
||||
default scope — and read `completeness.excluded` before reporting that an
|
||||
API is absent. For long captures with body shapes, use
|
||||
`export_evidence_bundle` instead of expecting an inline result.
|
||||
- Browser action the agent must perform (click, type, navigate):
|
||||
`capture_browser_scenario` with declared actions. See
|
||||
[runtime observation](references/runtime-observation.md) for connect/launch
|
||||
and the focused follow-up browser tools.
|
||||
- Agent environment (AgentEnv bundle) of a web application: read
|
||||
[environments](references/environments.md) before recording; it records with
|
||||
`capture_browser_scenario` and writes the bundle with `export_environment_bundle`.
|
||||
- Task for a desktop application's exported environment, from a
|
||||
`capture-desktop-application` folder: read
|
||||
[desktop application tasks](references/environments.md#tasks-for-a-desktop-application-environment).
|
||||
- Environment of a Linux desktop app with a task, from a request such as
|
||||
"build me an Inkscape environment where the agent changes a poster's
|
||||
headline": read [desktop builds](references/desktop-build.md). You drive the
|
||||
app on a build computer from `start_build_computer`, then export and witness.
|
||||
- Fiddler Everywhere traffic or a native `.saz` capture: read the
|
||||
[Fiddler workflow](references/runtime-observation.md#fiddler-everywhere-traffic-debugging).
|
||||
Inspect saved SAZ with `inspect_web_network_capture` and `format: "saz"`;
|
||||
connect Everywhere's separate MCP server for live traffic.
|
||||
- Retained HAR/SAZ/native mitmproxy/aioquic qlog capture: `inspect_web_network_capture`. Select
|
||||
original record ordinals when useful; inspect producer fields and byte/number
|
||||
sidecars without fetching recorded URLs or claiming live attribution. HAR/SAZ/qlog
|
||||
old-generation heap is `REA_CAPTURE_DECODER_OLD_GENERATION_MIB` (default 192 MiB,
|
||||
floor 8, maximum 16384), set where REA starts. Host memory and `NODE_OPTIONS` do not
|
||||
raise it. See
|
||||
[historical captures](https://github.com/morluto/rea/blob/main/docs/guides/web/web-network-captures.md) for the exact upstream
|
||||
profile and credential exclusions. Qlog support starts with aioquic 1.5.0
|
||||
JSON 0.3; stream coverage and endpoint loss declarations do not recover bodies
|
||||
or establish network loss. Prefer detail summary, then kind qlog trace/stream
|
||||
pages; select one trace, stream ID and direction for contribution/range pages.
|
||||
Facts retain all-recorded-events-before-selection scope. Other qlog layouts
|
||||
and PCAP correlation are unsupported.
|
||||
- User-owned Electron runtime already open: `list_electron_targets`. Before an electron-main Inspector attempt, check packaged fuses with `inspect_electron_fuses`; disabled `EnableNodeCliInspectArguments` means the app ignores `--inspect`.
|
||||
- Shipped application exposure for a local `.app`, install directory, ASAR, or executable: `audit_release_exposure` / `rea audit-release-exposure`. Each check has a stable id, a status, and fixed remediation. Unknown and unassessed checks stay in the report. This does not establish that an application is secure. Credential-marker hits report the rule id and location only. See [release exposure](https://github.com/morluto/rea/blob/main/docs/release-exposure.md).
|
||||
- Packet-field discovery: `inspect_packet_fields` searches installed protocols
|
||||
and field names/types before choosing fields for `inspect_packet_capture`.
|
||||
Query/page the relevant records; registrations do not establish observed traffic.
|
||||
- Recorded packet captures: `inspect_packet_capture` with selected TShark fields,
|
||||
display filters and decode-as rules. Requires Linux, util-linux prlimit and
|
||||
TShark 4.x on an absolute `PATH` entry or via the optional absolute
|
||||
`REA_TSHARK_COMMAND` override; see
|
||||
[capture guide](https://github.com/morluto/rea/blob/main/docs/guides/data/packet-captures.md).
|
||||
Packet limits count input packets before filtering. Output defaults to 50 matching
|
||||
frames; use `match_offset` / `match_limit` for later pages, or explicit null
|
||||
limit for complete matching output. Preserve the source digest across pages.
|
||||
This does not perform live capture.
|
||||
For address/DNS/SNI/protocol summaries use `inspect_pcap_capture` with MCP
|
||||
detail summary, then retained kind pcap pages. Requires Wireshark 4.x tshark
|
||||
and capinfos, with Linux prlimit or Windows Job Objects; see
|
||||
[packet summaries](https://github.com/morluto/rea/blob/main/docs/guides/data/pcap-analysis.md).
|
||||
Select an exact DNS question for address pages; page exhaustion does not prove
|
||||
network completeness. This reads recordings and does not acquire traffic.
|
||||
- Decoder discovery: `inspect_signal_decoders` searches installed decoder IDs
|
||||
or selected decoder help, including channels and options. Query and page the
|
||||
relevant details before choosing settings; this does not scan hardware.
|
||||
- Recorded logic/signal traces: `decode_signal_recording` with explicit decoder,
|
||||
channel and protocol settings. On Linux with util-linux prlimit, supply sigrok-cli 0.7.2 through
|
||||
`REA_SIGROK_COMMAND`; see [recording guide](https://github.com/morluto/rea/blob/main/docs/guides/signals/signal-recordings.md).
|
||||
Output defaults to 50 literal lines; select annotation classes and page with
|
||||
`line_offset` / `line_limit`, or explicit null for all remaining output.
|
||||
Window counts are display lines, not annotations or samples. Preserve source digests across pages.
|
||||
This reads existing files; it does not acquire hardware signals.
|
||||
- Explicit local WebAssembly artifact: `inspect_wasm_artifact`. Supply WABT 1.0.42
|
||||
through `REA_WABT_BIN_DIRECTORY`; retain exact byte/tool identity and decoded WAT.
|
||||
Select JavaScript glue and candidate paths explicitly and preserve URL/path
|
||||
ambiguity. No implicit fetch or target execution; WAT is not original source.
|
||||
See the [WASM guide](https://github.com/morluto/rea/blob/main/docs/guides/wasm/wasm-artifacts.md).
|
||||
- Explicit local Android APK (or ZIP/AAB) signing: `inspect_apk_signature`.
|
||||
Prefer its summary or selected signer/digest/lineage page; retain complete
|
||||
Evidence and use `inspect_analysis_view` kind `apk-signature` for follow-ups.
|
||||
Reports which schemes are present (v1 JAR, v2, v3, v3.1), each signer's
|
||||
certificate SHA-256 fingerprint (v1 included, from its PKCS#7 block), v3 key-rotation lineage, source stamp, and
|
||||
whether each signed digest still matches the bytes (self-consistency). This
|
||||
is identity and integrity, not a trust or authenticity verdict.
|
||||
See the [APK signature guide](https://github.com/morluto/rea/blob/main/docs/apk-signature.md).
|
||||
- Explicit local EVM bytecode carrier: `inspect_evm_interface` with caller-selected
|
||||
`raw` or `hex` encoding. The owned worker deadline is `timeout_ms` (default
|
||||
30000 ms, range 1..2147483647, next call). Select byte, address-space and CPU
|
||||
allowances separately through `producer_limits`; tighter inherited OS limits
|
||||
remain enforced, and the 256 MiB worker heap is independent. Preserve
|
||||
carrier/decoded digests and treat selectors,
|
||||
argument strings and mutability as inferred candidates; this performs no chain
|
||||
lookup or target execution. For the complete inferred interface without hex or
|
||||
duplicate stdout, discover support and select `detail: "summary"`; complete
|
||||
Evidence stays retained under its original identity. Use the returned
|
||||
`parent_evidence_id` for exact function or `bytecode_hex`/stdout/stderr pages.
|
||||
Candidate coverage does not establish interface completeness. See the
|
||||
[EVM bytecode guide](https://github.com/morluto/rea/blob/main/docs/guides/evm/evm-bytecode.md).
|
||||
- Embedded Go compiler, module, build-setting metadata, or static `(ptr, len)`
|
||||
string literals: `inspect_go_binary` with the explicit local file (pass
|
||||
`include_string_literals: true` and optional `max_string_literals` for bounded
|
||||
inferred static string-header recovery, and page retained rows with
|
||||
`inspect_analysis_view` kind `go` collection `string_literals`). This built-in
|
||||
target-free inspection requires no Go installation or disassembler. Preserve
|
||||
raw module bytes and source ranges; absent metadata does not prove a binary is
|
||||
not Go, static string recovery excludes compiler-inlined stack or immediate
|
||||
strings, and unparsed text records remain explicit. See the
|
||||
[Go binary guide](https://github.com/morluto/rea/blob/main/docs/guides/native/go-binaries.md).
|
||||
- Embedded CUDA/HIP code objects: `inspect_gpu_code_objects`; inventory targets
|
||||
first, then decode selected payloads and query retained GPU Evidence.
|
||||
- Bundled GGUF or safetensors model declarations: `inspect_model_artifact`
|
||||
with the explicit local file. Default header hashing leaves full-file identity
|
||||
unknown; `hash: "full"` additionally reads all weights for SHA-256. MCP returns
|
||||
retained summaries; optional `view` selects one page in the initial call. Use
|
||||
`inspect_analysis_view` kind `model-artifact` for
|
||||
batched metadata keys, tensor names or type totals, selected fields and pages.
|
||||
Preserve header-scoped indices and array preview omissions; do not infer model
|
||||
behavior from declared architecture or tensor types. See the
|
||||
[model file guide](https://github.com/morluto/rea/blob/main/docs/model-artifacts.md).
|
||||
- Unity IL2CPP names, member owners and string literals from `global-metadata.dat`:
|
||||
`inspect_il2cpp_metadata` with the explicit local file; MCP defaults to compact
|
||||
counts. Query sections, images, types, methods, fields, properties, events,
|
||||
parameters or string_literals through `inspect_analysis_view`
|
||||
with the returned `parent_evidence_id`, using exact filters, batch indices and
|
||||
selected fields. Parameters accept `method_indices`, avoiding a scan of all
|
||||
parameter pages. Missing collections in historical Evidence remain unknown.
|
||||
Versions 24, 27, 29, 31 and 39; no Unity, IL2CPP
|
||||
binary or disassembler is run. Unrecognized magic (possibly encrypted) and
|
||||
other versions are unsupported. Optional matching `binary_path` enables static native addresses and type references; query `method_addresses` with indices or addresses/states, preserving every shared-body method and both artifact identities. Without a linked binary native counts remain unknown. Byte-pattern fallback is inferred; no runtime behavior or same-build pairing is proved. See the
|
||||
[IL2CPP metadata guide](https://github.com/morluto/rea/blob/main/docs/il2cpp-metadata.md).
|
||||
- Embedded cargo-auditable Rust dependency metadata: `inspect_rust_binary`
|
||||
with the explicit local ELF, PE, or thin Mach-O file. This built-in
|
||||
target-free inspection requires no Rust installation or disassembler. Preserve
|
||||
package order, dependency indices, and the section file range. A missing
|
||||
`.dep-v0` section is null metadata, not proof the binary has no dependencies.
|
||||
A rustc commit hash is an inference from a read-only `/rustc/<40-hex>/` path.
|
||||
For selected crates, use `view: {collection: "packages", names: [...],
|
||||
fields: ["name", "version", "source"]}` on the first call; explicitly include
|
||||
`dependencies` for direct index references. Use `detail: "summary"` for counts
|
||||
and ranges, or retained `inspect_analysis_view` Rust package/edge pages for
|
||||
subsequent filters. Keep the complete parent Evidence accessible; CLI compact
|
||||
delivery requires `--evidence_output`.
|
||||
See the
|
||||
[Rust binary guide](https://github.com/morluto/rea/blob/main/docs/rust-binaries.md).
|
||||
- PE Authenticode certificate table: `inspect_pe_certificates` with the explicit
|
||||
local PE32/PE32+ file. This built-in target-free inspection requires no
|
||||
Windows SDK. Preserve WIN_CERTIFICATE ranges, types, payload SHA-256, and
|
||||
PKCS#7 signer/X.509 identity fields, including `subject_key_identifier_hex`
|
||||
when the signer uses that form. A missing security directory is observed
|
||||
absence of that table, not proof the image is unsigned in every catalog sense.
|
||||
Signatures are not verified. See the
|
||||
[PE certificate guide](https://github.com/morluto/rea/blob/main/docs/pe-certificates.md).
|
||||
- PE import and delay-load tables: `inspect_pe_imports` with the explicit
|
||||
local PE32/PE32+ file. This built-in target-free inspection requires no
|
||||
Windows SDK. Preserve DLL names, named and ordinal functions, ILT/IAT RVAs,
|
||||
delay-load descriptors, and the pefile import hash of the standard import
|
||||
table. A missing import directory is observed absence of that table, not
|
||||
proof the image never imported APIs through another table. Bound snapshots
|
||||
and loaded IAT contents remain unobserved. See the
|
||||
[PE import guide](https://github.com/morluto/rea/blob/main/docs/pe-imports.md).
|
||||
- Windows Shell Link shortcuts: `inspect_windows_shortcut` with the explicit
|
||||
local `.lnk` file. This built-in target-free inspection requires no Windows
|
||||
SDK or COM. Preserve header flags and FILETIMEs, IDList items, LinkInfo
|
||||
volume and network names, StringData arguments and icon location, ExtraData
|
||||
signatures, and Tracker droid facts labelled derived. Unknown IDList items
|
||||
and ExtraData signatures stay raw with SHA-256. The target path is not
|
||||
resolved or executed. See the
|
||||
[Windows shortcut guide](https://github.com/morluto/rea/blob/main/docs/guides/native/windows-shortcut.md).
|
||||
- PE TLS callbacks and load configuration: `inspect_pe_load_config` with the
|
||||
explicit local PE32/PE32+ file. This built-in target-free inspection requires
|
||||
no Windows SDK. Preserve callback VAs as strings with their RVA, file offset
|
||||
and section, and the size-covered security cookie, SafeSEH, CFG,
|
||||
EH-continuation and XFG fields. Guard-flag mitigation claims are inferred
|
||||
linker declarations, not proof of enforcement. A missing directory is observed
|
||||
absence of that declaration. See the
|
||||
[PE load configuration guide](https://github.com/morluto/rea/blob/main/docs/pe-load-config.md).
|
||||
- ELF, PE, and Mach-O hardening: `inspect_binary_hardening` with the explicit
|
||||
local file. This built-in target-free inspection requires no pwntools or other
|
||||
host tool. One image per Mach-O slice. Each property is `enabled`, `disabled`,
|
||||
`partial`, `unknown`, or `not_applicable`, with the header field or import
|
||||
behind it. A missing stack-protector or fortify import is `unknown`, not
|
||||
proof the protection was omitted. Authenticode and Mach-O code signatures
|
||||
report presence, not validity. Hardened runtime stays unknown and names
|
||||
`inspect_signature`. The image is not executed. See the
|
||||
[binary hardening guide](https://github.com/morluto/rea/blob/main/docs/binary-hardening.md).
|
||||
- ELF note tables: `inspect_elf_notes` with the explicit local ELF32/ELF64
|
||||
file. This built-in target-free inspection requires no disassembler. Preserve
|
||||
PT_NOTE and SHT_NOTE ranges, owners, types, descriptor SHA-256, and GNU
|
||||
build-id or ABI-tag fields. A missing table is observed absence of those
|
||||
declarations, not proof the image never carried notes. See the
|
||||
[ELF notes guide](https://github.com/morluto/rea/blob/main/docs/elf-notes.md).
|
||||
- Code that runs before `main` or at exit in ELF or Mach-O:
|
||||
`inspect_native_initializers` with the explicit local file (and
|
||||
`architecture` for a universal Mach-O). This built-in inspection requires no
|
||||
disassembler. Preserve slot and target addresses, the `resolution` of each
|
||||
entry, and its limitations. An `unresolved` slot is not a zero pointer, and a
|
||||
missing table is not proof that no constructor exists. See the
|
||||
[initializer guide](https://github.com/morluto/rea/blob/main/docs/guides/native/native-initializers.md).
|
||||
|
||||
- ELF unwind function ranges: `inspect_elf_unwind_ranges` with the explicit
|
||||
local ELF32/ELF64 file. This built-in target-free inspection requires no
|
||||
disassembler. Preserve FDE start, end, size, containing section, exact
|
||||
symbol name, CIE index, LSDA, and personality. Page with `offset` and
|
||||
`limit`. A missing `.eh_frame` is observed absence of that declaration,
|
||||
not proof the image has no functions. `.debug_frame` is reported present
|
||||
or absent and is not decoded. CFA instructions are counted and not
|
||||
evaluated. See the
|
||||
[ELF unwind ranges guide](https://github.com/morluto/rea/blob/main/docs/guides/native/elf-unwind-ranges.md).
|
||||
- Apple `.ips` crash reports: `inspect_apple_ips` with the explicit local
|
||||
file. This built-in target-free inspection requires no Xcode, atos, or
|
||||
pwntools. Preserve first-line metadata, `bug_type` as a string, process and
|
||||
exception facts, lossless integer registers, usedImages UUIDs, and
|
||||
documented classification matches. Only `bug_type` `"309"` yields a crash
|
||||
body; other types, including `"288"` stackshots, return no crash result.
|
||||
Select an optional `join_path` for UUID-and-architecture matching to one
|
||||
local Mach-O or dSYM; preserve slice identity and unjoined reasons. Joined
|
||||
static addresses do not resolve function names or dSYM symbols. See the
|
||||
[Apple IPS guide](https://github.com/morluto/rea/blob/main/docs/apple-ips.md).
|
||||
- Linux kernel module metadata: `inspect_kernel_module` with the explicit local
|
||||
ELF32/ELF64 relocatable file. This built-in target-free inspection requires
|
||||
no Linux host or `modinfo`. Preserve `.modinfo` key order and duplicate keys,
|
||||
`__versions` CRC hex, section file ranges, and the appended signature
|
||||
trailer's PKCS#7 SHA-256. A missing section is observed absence when section
|
||||
names are known, not proof the module never carried that metadata.
|
||||
`struct module` is not decoded. The signature is not validated. gzip, xz, and
|
||||
zstd containers are unsupported; decompress into a separate file with an
|
||||
external codec utility, then inspect the decompressed `ET_REL` image. See the
|
||||
[kernel module guide](https://github.com/morluto/rea/blob/main/docs/kernel-modules.md).
|
||||
- Linux kernel version and build config (`CONFIG_*` options such as
|
||||
`CONFIG_SECURITY_SELINUX`): `inspect_kernel_build_config` with the explicit
|
||||
local `vmlinux`, raw `Image`, x86 `bzImage`, or `configs.ko`. This built-in
|
||||
target-free inspection requires no Linux host or `extract-ikconfig`. Preserve
|
||||
the banner version, config SHA-256, option count, and value kinds; use `name`
|
||||
for one option. An `IKCFG_ST` string is a config only with a valid gzip member
|
||||
and `IKCFG_ED`. An absent config may mean the kernel was built without
|
||||
`CONFIG_IKCONFIG`. Non-gzip payloads are unsupported; decompress externally,
|
||||
then inspect the result. See the
|
||||
[kernel build config guide](https://github.com/morluto/rea/blob/main/docs/guides/native/kernel-build-config.md).
|
||||
- CPython 3.7–3.13 `.pyc` header, nested marshal code objects and bytecode
|
||||
identity: `inspect_python_pyc` with the explicit local file. This built-in
|
||||
target-free inspection requires no Python installation. Preserve magic,
|
||||
PEP 552 hash or mtime/size, nested names, and bytecode SHA-256. Bytecode is
|
||||
not decompiled, and a decoded header does not prove the matching `.py` is
|
||||
present. See the
|
||||
[CPython pyc guide](https://github.com/morluto/rea/blob/main/docs/python-pyc.md).
|
||||
- Erlang BEAM IFF container: `inspect_erlang_beam` with the explicit local
|
||||
`.beam` file. This built-in target-free inspection requires no Erlang
|
||||
installation. Preserve chunk names, atom order, export/import/lambda tables,
|
||||
and the Code header. For selected facts, prefer `detail: "summary"` plus a
|
||||
`beam` view (collection, names/indices, fields and paging), retaining the full
|
||||
Evidence. CLI summary requires `--evidence_output`. Missing table counts stay
|
||||
null; decoded empty tables count zero. Bytecode is not executed. See the
|
||||
[Erlang BEAM guide](https://github.com/morluto/rea/blob/main/docs/erlang-beam.md).
|
||||
|
||||
- Explicit local SQLite database snapshot: `inspect_sqlite_database`. Inspect
|
||||
with Node.js 24.x >=24.15 or 26+ providing native SQLite limits. Read schema
|
||||
first (compact inventory by default), or select an exact ordinary table
|
||||
and `columns` when rows are needed. Defaults are selected-table schema and
|
||||
20 rows; request `schema_scope: "database"` for the complete stored schema. Preserve both database and existing sibling WAL identity; row samples
|
||||
report truncation and have unspecified order. Use a quiescent snapshot rather
|
||||
than assuming a live database/WAL pair was copied atomically. See the
|
||||
[SQLite guide](https://github.com/morluto/rea/blob/main/docs/guides/data/sqlite-databases.md).
|
||||
- Explicit Linux ELF file for offline layout, symbols, relocations or static
|
||||
mitigation evidence: `inspect_binary_layout`. This target-free operation uses
|
||||
caller-supplied pwntools without opening a disassembler database. Preserve its
|
||||
raw locations and inference/coverage limits; see the
|
||||
[offline binary guide](https://github.com/morluto/rea/blob/main/docs/guides/native/binary-diagnostics.md).
|
||||
- Supplied Linux x86-64 ELF core: `inspect_recorded_crash`. Read every recorded
|
||||
thread, raw note and source-bound register without opening a live target.
|
||||
Historical PIDs do not select live processes. Request `include_debugger_context`
|
||||
only when core-only mapping candidates help; see the
|
||||
[recorded crash guide](https://github.com/morluto/rea/blob/main/docs/guides/native/recorded-crashes.md).
|
||||
- PE resource type/name/language trees and static icon group references:
|
||||
`inspect_pe_resources` with an explicit path. This portable operation requires
|
||||
no active target or engine; opaque payloads retain file ranges and SHA-256.
|
||||
- PE export directories and ELF dynamic-symbol exports: `inspect_native_exports`
|
||||
with an explicit path; portable, no active target or engine.
|
||||
- Native executable, library, or analysis database: `open_binary`, then
|
||||
use focused analysis tools directly; call `binary_overview` when metadata or
|
||||
inventory context is useful and available from the selected provider.
|
||||
|
||||
For an existing IDA MCP configuration, use `open_binary` with the original
|
||||
input binary and `provider_id: "ida"`; do not pass an `.idb` or `.i64` database.
|
||||
The legacy attached profile binds the already-open GUI input by SHA-256 and
|
||||
leaves its database open. The modern headless profile creates and closes an
|
||||
owned private database without saving. Installation and registration reuse
|
||||
[mrexodia/ida-pro-mcp](https://github.com/mrexodia/ida-pro-mcp); see the
|
||||
[IDA provider guide](https://github.com/morluto/rea/blob/main/docs/providers/ida-provider.md).
|
||||
For migration to the separate native IDA MCP plugin, follow the guide's
|
||||
[legacy attached migration](https://github.com/morluto/rea/blob/main/docs/providers/ida-provider.md#migrate-a-legacy-attached-registration).
|
||||
Replace the upstream registration explicitly; modern mrexodia tools are not the
|
||||
native profile. Native attachment preserves the database but does not provide
|
||||
direct callers; check session availability and the guide's verification limits.
|
||||
Proceed directly to `analyze_function`, pseudocode, or function/string searches
|
||||
after opening; IDA does not supply `binary_overview`. Consult session availability
|
||||
when composing broader workflows. Modern direct callers and unsupported dossier
|
||||
facets remain unknown; live IDA results are not replayed from snapshots.
|
||||
|
||||
With `REA_KUNA_COMMAND` configured, `provider_id: "kuna"` answers procedure
|
||||
lists, lookups, pseudocode, assembly and `analyze_function` from Kuna's cached
|
||||
whole-program export. Callers/callees use a separate body-free graph shared by
|
||||
the session; `xrefs` returns exact-address incoming sites and filters forwarding
|
||||
aliases. These queries and inventory lookups do not trigger a C export. Indirect
|
||||
targets remain unknown and can make relationship coverage partial. Reference
|
||||
caches expire on close; a fresh CLI process repeats the native reference walk.
|
||||
Typed references, CFG, raw-memory tools and annotations remain unsupported. A cold first
|
||||
answer can come from a single-function run (its limitations say so); assembly
|
||||
waits for the export. For pseudocode and assembly, `raw_result.source` names the
|
||||
cached `.c`/`.asm` file and byte span, which you may search directly instead of
|
||||
calling per function. See the
|
||||
[Kuna provider guide](https://github.com/morluto/rea/blob/main/docs/kuna-provider.md).
|
||||
|
||||
If the user says only "my app" without a name, path, or target already selected
|
||||
for this task, ask which app before searching for artifacts. Paths in unrelated
|
||||
saved reports and nearby test fixtures do not select the user's target. Resolve
|
||||
an actual human-readable app name to one clear installed artifact when possible;
|
||||
ask when matches are ambiguous. Never choose an example app on the user's behalf.
|
||||
|
||||
In a target-free session, use `open_binary` to bind any archive/package or
|
||||
native target whose analysis tool operates on the active target. Do not call an
|
||||
unadvertised tool; inspect `binary_session` with `{}` and its
|
||||
`result.tool_availability` for availability reasons and remediation. Expand each
|
||||
group's `names` into entries, inheriting the inventory-level client requirements
|
||||
unless the group overrides them. The grouped name union is the complete tool
|
||||
inventory; use `tools/list` for canonical tool schemas. The default summary keeps
|
||||
each provider candidate's availability and target-support status, code and
|
||||
reason; `omitted_fields` lists what it leaves out. Request `{"detail": "complete"}`
|
||||
only when you need an unavailable candidate's remediation, provider
|
||||
diagnostics, candidate capability sets, or tool surface, effect and annotation
|
||||
flags; in those closed flag vocabularies, listed
|
||||
flags are true and omitted known flags are false. Provider candidate facts
|
||||
describe possible providers, while top-level session capabilities describe the
|
||||
current route and `analysis_provider_binding` names the selected provider. Do
|
||||
not treat those scopes as interchangeable.
|
||||
|
||||
For editable Ghidra analysis that must survive a later agent process, select
|
||||
the [owned Program checkpoint workflow](references/native-and-artifacts.md#continue-editable-ghidra-analysis-across-processes)
|
||||
before making metadata edits. It is separate from Evidence/Unknown persistence.
|
||||
|
||||
For a Ghidra startup timeout on a large native target, follow
|
||||
[deadline recovery](references/native-and-artifacts.md#ghidra-startup-deadline-recovery)
|
||||
before abandoning deep analysis or repeating the same cold import. The default
|
||||
330 seconds can be changed for new startup attempts through
|
||||
`update_analysis_settings` using `ghidra.startup_timeout_ms`. Changing the
|
||||
server's launch environment instead requires a new REA process.
|
||||
If a needed tool is unadvertised, inspect `binary_session {}` and
|
||||
`result.tool_availability` for availability reasons/remediation; never call an
|
||||
unadvertised tool. Expand group `names`, inheriting inventory client requirements
|
||||
unless overridden. Their union is the complete in-scope inventory; `tools/list`
|
||||
owns canonical schemas. The default summary keeps provider candidate status,
|
||||
code and reason; `omitted_fields` names exclusions. Request `detail: "complete"`
|
||||
only for remediation/diagnostics, candidate capabilities or tool effect flags.
|
||||
Candidate facts describe possible providers; top-level capabilities and
|
||||
`analysis_provider_binding` describe the current route. Keep those scopes distinct.
|
||||
|
||||
## Work summary-first
|
||||
|
||||
Start with the default result and use its inline Evidence and graph context.
|
||||
For a JavaScript application or ELF layout whose size is unknown or large,
|
||||
call `analyze_javascript_application` or `inspect_binary_layout` with
|
||||
`"detail": "summary"`, then inspect the retained `parent_evidence_id` with
|
||||
`inspect_analysis_view`. Over MCP, `analyze_function` is summary-first without
|
||||
a flag: its default reply is the summary, and the complete dossier stays
|
||||
retained under `parent_evidence_id` for facet paging. Pass that ID as a
|
||||
`retained-evidence` reference to `compare_functions`, or inside
|
||||
`match_native_functions` `left_observations`/`right_observations` or
|
||||
`build_call_path.functions`; request `"detail": "complete"` only when the
|
||||
dossier must travel inline.
|
||||
Use the same exact-reference form in other advertised logical Evidence inputs,
|
||||
including optional sources, arrays and nested sources across domains. Each
|
||||
source can independently be inline or retained; preserve its source identity,
|
||||
coverage, partial facts and unknowns. A summary or inspection page has its own
|
||||
Evidence ID: use `normalized_result.parent_evidence_id` when the consumer needs
|
||||
the complete source. For portable CLI follow-ups, commands advertising
|
||||
`--evidence-bundle` resolve references from that selected exported bundle.
|
||||
See [Evidence composition](references/evidence-workflows.md) for scope and
|
||||
recovery; file selectors are supported only where explicitly advertised.
|
||||
Page module identities and select the returned `node_id` before requesting an
|
||||
item; a single file path can represent several graph roles. Do not repeat an
|
||||
identical analysis or rejected call without a changed input or resolved blocker.
|
||||
Recheck session state when a lifecycle change makes that status useful.
|
||||
Make a focused follow-up only when the
|
||||
returned result leaves a specific question unanswered.
|
||||
Start with inline Evidence and graph context. For unknown/large JavaScript or ELF
|
||||
layout, select advertised `detail: "summary"`; MCP `analyze_function` already
|
||||
defaults to a summary. Small complete results can cost less than extra pages.
|
||||
Make a focused follow-up only for a specific unanswered question. Reuse matching
|
||||
session state and Evidence instead of repeating analysis; recheck state when a
|
||||
lifecycle change makes it useful.
|
||||
|
||||
If MCP reports `resource_constraint` with `details.resource: "transport"`, call
|
||||
`inspect_analysis_view` with its reported same-session Evidence reference for a
|
||||
summary, one section/module, or a stable page. Use `trace_application_feature`
|
||||
once a seed is known, or call `export_evidence_bundle` to write the complete
|
||||
session to a selected path. The analysis remains complete in the ledger; avoid
|
||||
repeating it merely to request the same oversized response. Complete CLI JSON
|
||||
output also streams without a single MCP frame.
|
||||
Complete source Evidence stays accessible through advertised retained references.
|
||||
A summary/page has its own Evidence ID; use `normalized_result.parent_evidence_id`
|
||||
when a consumer needs the complete source. Pass `{kind: "retained-evidence",
|
||||
evidence_id}` in inputs advertising that form; do not resend complete records.
|
||||
Sources may independently be inline or retained. Read the Evidence guide for
|
||||
exact filters, bundle-based CLI reuse, comparison roles and missing-source recovery.
|
||||
|
||||
When the retained parent ID is unknown, use `get_evidence_bundle` with
|
||||
`detail: "summary"` and exact filters for operation, target SHA-256,
|
||||
analysis-profile digest or canonical procedure address. Select its returned
|
||||
Evidence ID for the next view instead of requesting the complete bundle. When
|
||||
that record has no supported view (for example an annotation), read it with
|
||||
`detail: "records"` and an `evidence_id` filter; `missing_evidence_links`
|
||||
names linked sources this session does not retain.
|
||||
`retention: "complete-record"` means the whole record is stored; native
|
||||
value-flow truncation and unknown metadata remain separate. For an exported
|
||||
portable bundle, use `rea inspect-evidence-bundle` with JSON containing `path`,
|
||||
`detail: "summary"` and the same `filters`. Reading that file still requires
|
||||
validating its full contents within the local memory budget.
|
||||
For REA transport refusal or client-truncated output, inspect a smaller retained
|
||||
view or export complete Evidence. Do not parse a preview as canonical JSON or
|
||||
repeat the producer. Never invent an Evidence ID; if unknown, find it with
|
||||
`get_evidence_bundle` summary filters. Retention is bounded and session-local;
|
||||
it does not establish automatic persistence or complete source coverage.
|
||||
|
||||
A client can also truncate a successful tool result without a REA transport
|
||||
error. Treat that preview as incomplete; use the retained parent ID for smaller
|
||||
views or export when the full record is needed. Do not parse the preview as
|
||||
canonical JSON or repeat the producer. For JavaScript, read the
|
||||
[module-view and trace recipes](references/javascript-applications.md) before
|
||||
drilling into a large graph; a broad bidirectional trace can expand unrelated
|
||||
containment relationships even after summary analysis.
|
||||
|
||||
Every conclusion must distinguish observations, inferences, and unknowns. Cite
|
||||
Evidence IDs, preserve limitations and incomplete coverage, and never imply
|
||||
that static analysis observed execution. Runtime requests execute the declared
|
||||
target and lifecycle; do not broaden the target or action beyond those fields.
|
||||
|
||||
Within the user's requested investigation, call available analysis tools
|
||||
directly. REA does not require permission grants or per-call approval flags.
|
||||
The agent client can independently require approval. Follow the declared request
|
||||
scope and the host's actual access requirements; use the recovery guide for an
|
||||
observed client-policy rejection.
|
||||
|
||||
## Plan broader investigations
|
||||
|
||||
For requests that span multiple features or subsystems, use a staged workflow:
|
||||
|
||||
1. Turn the request into a checklist of questions and the evidence each answer
|
||||
needs. Resolve target identity and constraints from the conversation and
|
||||
workspace before asking for information again.
|
||||
2. Inspect the current REA session, artifact identity, saved analysis database,
|
||||
bookmarks, and prior evidence. Reuse matching state; do not open duplicate
|
||||
sessions or repeat identical analysis.
|
||||
3. Start with the smallest useful overview or inventory. Follow each question
|
||||
from its entry point through relevant data and state changes to its result.
|
||||
Batch related operations around a specific hypothesis, then expand only when
|
||||
the returned evidence leaves a concrete gap.
|
||||
4. Inspect relevant packaged resources and configuration alongside code when
|
||||
they affect the question. Use format-aware inventory and parsers; do not
|
||||
infer behavior from filenames, strings, or layout alone.
|
||||
5. Corroborate a conclusion with the evidence type it requires. Use runtime
|
||||
observation only when static evidence cannot answer the question and the
|
||||
required host runtime and OS access are available. For JavaScript behavior,
|
||||
run probes against the actual app through the available browser, Electron,
|
||||
or process capture workflow.
|
||||
6. Decompose work into independent questions. When parallel workers are
|
||||
available and the questions do not depend on one another, assign distinct
|
||||
scopes, point workers to existing evidence, and ask them to return sources,
|
||||
conclusions, and unresolved gaps. Otherwise, work sequentially.
|
||||
7. Keep a concise finding ledger linking each conclusion to Evidence IDs,
|
||||
confidence/evidence type, search boundary, and remaining unknowns. Update
|
||||
the shared index or investigation report so later passes can reuse results.
|
||||
|
||||
Before finishing, revisit the original checklist. Mark each question as
|
||||
answered, partially answered, or unresolved based on its evidence; keep
|
||||
bounded negative searches bounded, and do not describe a broad investigation
|
||||
as complete while required questions remain open.
|
||||
|
||||
## Read only the relevant guide
|
||||
|
||||
- Native binaries, managed assemblies, archives, and extraction:
|
||||
[references/native-and-artifacts.md](references/native-and-artifacts.md)
|
||||
- ASARs, extracted JavaScript, feature tracing, and version comparison:
|
||||
[references/javascript-applications.md](references/javascript-applications.md)
|
||||
- Android APK declarations, classes, methods, and static references:
|
||||
[references/android-applications.md](references/android-applications.md)
|
||||
- Native instrumentation, debugger and process capture; browser/Electron
|
||||
observation; static/runtime comparison:
|
||||
[references/runtime-observation.md](references/runtime-observation.md)
|
||||
- Evidence paging, comparisons, residual unknowns, and verification:
|
||||
[references/evidence-workflows.md](references/evidence-workflows.md)
|
||||
- Agent environments (AgentEnv bundles) of a web application, recorded from
|
||||
a live instance or a HAR:
|
||||
[references/environments.md](references/environments.md)
|
||||
- Tasks for a desktop application's exported environment:
|
||||
[references/environments.md](references/environments.md#tasks-for-a-desktop-application-environment)
|
||||
- A desktop app environment from a request, built and witnessed on build
|
||||
computers: [references/desktop-build.md](references/desktop-build.md)
|
||||
For broad investigations, read the Evidence guide's staged workflow. Track the
|
||||
questions, source boundaries and unresolved gaps; do not claim completion while
|
||||
required questions remain open. Inspect packaged resources alongside code when
|
||||
relevant, and use runtime evidence only within the requested scope.
|
||||
|
||||
## Finish the task
|
||||
|
||||
Explain findings in plain language and tie them to returned evidence. When the
|
||||
user asks to build something, use normal coding tools and separate observed
|
||||
behavior from design choices. Close an opened native session with
|
||||
`close_binary` when its engine is no longer needed. Evidence references and Unknown
|
||||
history remain in memory on the same MCP connection. End the investigation with
|
||||
`reset_investigation`; supply `save_path` to checkpoint the complete bundle before
|
||||
clearing. Import the saved bundle to restore original references and Unknown
|
||||
history in a new process. Retention is bounded and is not automatic persistence.
|
||||
Explain findings in plain language and tie them to returned Evidence. For builds,
|
||||
use normal coding tools and separate observed behavior from design choices.
|
||||
Close an opened native/resource session with `close_binary` when no longer needed.
|
||||
Evidence references and Unknown history remain on the same MCP connection.
|
||||
End with `reset_investigation`; use `save_path` to checkpoint the complete bundle
|
||||
before clearing. Import that bundle, including its source closure, to restore
|
||||
original references and Unknown history in a new process. Editable Ghidra Program
|
||||
checkpoints are separate; read that workflow before edits needing persistence.
|
||||
@@ -1,11 +1,23 @@
|
||||
# Connection and task recovery
|
||||
|
||||
Read only the sections needed for the selected task.
|
||||
|
||||
- [Choose the remedy from the observed failure](#choose-the-remedy-from-the-observed-failure)
|
||||
- [Distinguish client and server deadlines](#distinguish-client-and-server-deadlines)
|
||||
- [Recovery ladder](#recovery-ladder)
|
||||
- [REA installed as a client plugin](#rea-installed-as-a-client-plugin)
|
||||
- [Repair registration when needed](#repair-registration-when-needed)
|
||||
- [Codex tool approval is separate from REA readiness](#codex-tool-approval-is-separate-from-rea-readiness)
|
||||
- [Repair an editable REA limit](#repair-an-editable-rea-limit)
|
||||
- [Continue through an installed CLI](#continue-through-an-installed-cli)
|
||||
|
||||
Read this guide only for an observed connection, command, approval or provider
|
||||
blocker. Keep the user's target and question in view. Explain what prevented the
|
||||
operation and the next useful step; after repair, continue the investigation.
|
||||
|
||||
Commands below use an installed `rea`. If none is available, use the package
|
||||
invocation in `SKILL.md` when acquiring REA is authorized. Follow the connected
|
||||
invocation under [Continue through an installed CLI](#continue-through-an-installed-cli)
|
||||
when acquiring REA is authorized. Follow the connected
|
||||
server's schemas and the installed CLI's help rather than assuming repository
|
||||
main and an older release expose the same arguments. Tool-name prefixes belong
|
||||
to the client: find the canonical REA operation in its actual tool listing and
|
||||
@@ -222,6 +234,25 @@ not edit host deadlines, response buffers, registrations or fixed limits.
|
||||
|
||||
## Continue through an installed CLI
|
||||
|
||||
A concrete CLI fallback for an operator-supplied JavaScript tree or ASAR is:
|
||||
|
||||
```bash
|
||||
npx -y rea-agents@latest analyze-javascript-application /absolute/path/to/app --json
|
||||
```
|
||||
|
||||
No MCP registration or native engine is required. Read the returned Evidence,
|
||||
graph, limitations, and unknowns with the same care as an MCP result; the CLI
|
||||
returns the Evidence record directly. This fallback does not establish that
|
||||
MCP is configured. Native CLI tasks still require their selected engine.
|
||||
Prefer an existing `rea` CLI. When none is installed and REA package acquisition
|
||||
is within the authorized scope, use `npx -y rea-agents@latest` in its place from a
|
||||
trusted directory outside the target project, with absolute target paths. Managed
|
||||
setup binds the current installation directly; retain its runtime and package
|
||||
cache entry, or restore that installation before repairing its registration.
|
||||
For setup-owned registration, configuration repair starts with a read-only setup plan; show paths, backups and
|
||||
skill replacement before applying authorized changes. Preserve existing approval
|
||||
and target-execution boundaries.
|
||||
|
||||
Check the command environment only if the launcher fails:
|
||||
|
||||
```bash
|
||||
|
||||
@@ -1,5 +1,13 @@
|
||||
# Agent environments from a live application
|
||||
|
||||
Read only the sections needed for the selected task.
|
||||
|
||||
- [Before recording](#before-recording)
|
||||
- [Record a session an environment can learn writes from](#record-a-session-an-environment-can-learn-writes-from)
|
||||
- [Check coverage](#check-coverage)
|
||||
- [Export and hand off](#export-and-hand-off)
|
||||
- [Tasks for a desktop application environment](#tasks-for-a-desktop-application-environment)
|
||||
|
||||
Use this when the user asks for an agent environment (an AgentEnv bundle) of a
|
||||
web application: a folder `agent-env` deploys, whose MCP tools answer from what
|
||||
one recording of the application observed and serve the writes that recording
|
||||
|
||||
@@ -1,7 +1,25 @@
|
||||
# Evidence, comparison, and verification workflows
|
||||
|
||||
Evidence-producing tools return the complete Evidence record directly in MCP
|
||||
`structuredContent` and CLI JSON. Read `normalized_result` for operation data,
|
||||
Read only the sections needed for the selected task.
|
||||
|
||||
- [Read and compose source Evidence](#read-and-compose-source-evidence)
|
||||
- [Inventory and decompilation views](#inventory-and-decompilation-views)
|
||||
- [Unknowns and comparisons](#unknowns-and-comparisons)
|
||||
- [Process captures and environment views](#process-captures-and-environment-views)
|
||||
- [Native export table pages](#native-export-table-pages)
|
||||
- [Recover oversized delivery and find retained Evidence](#recover-oversized-delivery-and-find-retained-evidence)
|
||||
- [Plan broader investigations](#plan-broader-investigations)
|
||||
|
||||
## Read and compose source Evidence
|
||||
|
||||
Evidence-producing MCP tools return Evidence directly in `structuredContent`.
|
||||
CLI complete JSON returns Evidence directly. CLI summary delivery through
|
||||
`--evidence_output` returns `{summary, evidence_bundle}`: `summary` is the view's
|
||||
Evidence, and `evidence_bundle` is the export receipt with its path and byte count.
|
||||
Read `summary.normalized_result.parent_evidence_id` for the complete source ID;
|
||||
pass the receipt's path to `--evidence-bundle` on a later supported CLI command.
|
||||
Advertised summary delivery retains the complete source separately;
|
||||
complete inline delivery is available where the connected contract says so. Read `normalized_result` for operation data,
|
||||
and cite `evidence_id` when another tool or your explanation needs a stable
|
||||
reference. Preserve authority, limitations, coverage, and residual unknowns. If a result
|
||||
is incomplete or paginated, continue only when the remaining data matters to
|
||||
@@ -49,6 +67,8 @@ An input bundle grants no implicit file lookup: `evidence-file` and historical
|
||||
graph file selectors are accepted only by contracts advertising them. See the
|
||||
[CLI reuse guide](https://github.com/morluto/rea/blob/main/docs/getting-started/cli.md#import-export-and-compare-evidence).
|
||||
|
||||
## Inventory and decompilation views
|
||||
|
||||
Completed `inspect_artifact` inventory also supports a summary and
|
||||
`view: {kind: "inventory", collection: "occurrences", logical_paths: ["package.json", "main.js"]}`.
|
||||
Omit `logical_paths` to page all available occurrences; `[]` selects none.
|
||||
@@ -81,6 +101,8 @@ exact `where.indices`, `addresses`, `procedure_addresses` or `statuses`. Add
|
||||
`collection: "pseudocode"` with one row's `index` to page a large body. Batch
|
||||
limitations aggregate every item, so do not attribute them to one successful row.
|
||||
|
||||
## Unknowns and comparisons
|
||||
|
||||
Use `record_unknown` to track unresolved questions in the user's investigation
|
||||
and name the authority or environment still required. Supply supporting and
|
||||
contradicting evidence IDs. It updates the session registry directly.
|
||||
@@ -111,6 +133,8 @@ or absence:
|
||||
- `verify_reconstruction` evaluates a finite typed specification. A pass covers
|
||||
only declared comparable claims, not global equivalence.
|
||||
|
||||
## Process captures and environment views
|
||||
|
||||
Process captures are opt-in behavioral evidence, not a security sandbox. V3
|
||||
captures cannot be upgraded to V4; rerun the original scenario. Distinguish root
|
||||
exit from descendant settlement and require freshness when the task needs it.
|
||||
@@ -164,6 +188,8 @@ catalog and state size checks. `rea environment-build <capture.har> <dir>`
|
||||
inspects, projects and exports in one step and prints the same coverage, or
|
||||
`null` when the bundle serves replay.
|
||||
|
||||
## Native export table pages
|
||||
|
||||
For a PE/ELF export question, `inspect_native_exports` accepts `detail: "summary"`
|
||||
and retains the complete table. Query `inspect_analysis_view` with
|
||||
`view: {kind: "native-exports", collection: "exports", names: ["selected_name"],
|
||||
@@ -174,3 +200,69 @@ coverage describes selected retained rows; `summary.coverage` or `exports.covera
|
||||
still describes the source table, so an empty partial page does not prove absence.
|
||||
CLI `inspect-native-exports --detail summary --evidence_output PATH` saves the
|
||||
complete bundle for later `inspect-analysis-view --evidence-bundle PATH` requests.
|
||||
|
||||
## Recover oversized delivery and find retained Evidence
|
||||
|
||||
If MCP reports `resource_constraint` with `details.resource: "transport"`, call
|
||||
`inspect_analysis_view` with its reported same-session Evidence reference for a
|
||||
summary, one section/module, or a stable page. Use `trace_application_feature`
|
||||
once a seed is known, or call `export_evidence_bundle` to write the complete
|
||||
session to a selected path. The analysis remains complete in the ledger; avoid
|
||||
repeating it merely to request the same oversized response. Complete CLI JSON
|
||||
output also streams without a single MCP frame.
|
||||
|
||||
When the retained parent ID is unknown, use `get_evidence_bundle` with
|
||||
`detail: "summary"` and exact filters for operation, target SHA-256,
|
||||
analysis-profile digest or canonical procedure address. Select its returned
|
||||
Evidence ID for the next view instead of requesting the complete bundle. When
|
||||
that record has no supported view (for example an annotation), read it with
|
||||
`detail: "records"` and an `evidence_id` filter; `missing_evidence_links`
|
||||
names linked sources this session does not retain.
|
||||
`retention: "complete-record"` means the whole record is stored; native
|
||||
value-flow truncation and unknown metadata remain separate. For an exported
|
||||
portable bundle, use `rea inspect-evidence-bundle` with JSON containing `path`,
|
||||
`detail: "summary"` and the same `filters`. Reading that file still requires
|
||||
validating its full contents within the local memory budget.
|
||||
|
||||
A client can also truncate a successful tool result without a REA transport
|
||||
error. Treat that preview as incomplete; use the retained parent ID for smaller
|
||||
views or export when the full record is needed. Do not parse the preview as
|
||||
canonical JSON or repeat the producer. For JavaScript, read the
|
||||
[module-view and trace recipes](javascript-applications.md) before
|
||||
drilling into a large graph; a broad bidirectional trace can expand unrelated
|
||||
containment relationships even after summary analysis.
|
||||
|
||||
## Plan broader investigations
|
||||
|
||||
For requests that span multiple features or subsystems, use a staged workflow:
|
||||
|
||||
1. Turn the request into a checklist of questions and the evidence each answer
|
||||
needs. Resolve target identity and constraints from the conversation and
|
||||
workspace before asking for information again.
|
||||
2. Inspect the current REA session, artifact identity, saved analysis database,
|
||||
bookmarks, and prior evidence. Reuse matching state; do not open duplicate
|
||||
sessions or repeat identical analysis.
|
||||
3. Start with the smallest useful overview or inventory. Follow each question
|
||||
from its entry point through relevant data and state changes to its result.
|
||||
Batch related operations around a specific hypothesis, then expand only when
|
||||
the returned evidence leaves a concrete gap.
|
||||
4. Inspect relevant packaged resources and configuration alongside code when
|
||||
they affect the question. Use format-aware inventory and parsers; do not
|
||||
infer behavior from filenames, strings, or layout alone.
|
||||
5. Corroborate a conclusion with the evidence type it requires. Use runtime
|
||||
observation only when static evidence cannot answer the question and the
|
||||
required host runtime and OS access are available. For JavaScript behavior,
|
||||
run probes against the actual app through the available browser, Electron,
|
||||
or process capture workflow.
|
||||
6. Decompose work into independent questions. When parallel workers are
|
||||
available and the questions do not depend on one another, assign distinct
|
||||
scopes, point workers to existing evidence, and ask them to return sources,
|
||||
conclusions, and unresolved gaps. Otherwise, work sequentially.
|
||||
7. Keep a concise finding ledger linking each conclusion to Evidence IDs,
|
||||
confidence/evidence type, search boundary, and remaining unknowns. Update
|
||||
the shared index or investigation report so later passes can reuse results.
|
||||
|
||||
Before finishing, revisit the original checklist. Mark each question as
|
||||
answered, partially answered, or unresolved based on its evidence; keep
|
||||
bounded negative searches bounded, and do not describe a broad investigation
|
||||
as complete while required questions remain open.
|
||||
@@ -0,0 +1,76 @@
|
||||
# Firmware and raw images
|
||||
|
||||
## Firmware regions and extraction
|
||||
|
||||
Use `inspect_firmware_regions` when advertised. Use `extract_firmware` when
|
||||
extraction is requested, with a caller-selected new absolute output directory.
|
||||
These tools use caller-supplied Binwalk/Unblob on Linux; see the
|
||||
[firmware guide](https://github.com/morluto/rea/blob/main/docs/guides/firmware/firmware-analysis.md).
|
||||
|
||||
## Headerless raw images and firmware containers
|
||||
|
||||
For other headerless images (embedded firmware without ELF/Mach-O/PE/MZ
|
||||
headers), open with `format: "raw-binary"`, `architecture` (`x86`, `x86_64`,
|
||||
`arm`, `arm64`, `6502`, or `m68k`), and `entry_point` (`0x` hex). File offset 0 is mapped at
|
||||
that address. Hopper and IDA refuse this interpretation; Ghidra uses
|
||||
`BinaryLoader` with a generic language: big-endian for `m68k`, little-endian
|
||||
otherwise. Big-endian ARM, Thumb-only, and Cortex-M variants are unsupported.
|
||||
`6502` selects NMOS 6502; the entry and complete file mapping must fit within
|
||||
`0x0000..0xffff`. 65C02, 65816, cartridge containers, bank switching, and mapper
|
||||
semantics are unsupported. `m68k` requires an even entry and decodes the 68040
|
||||
superset of the 68000 family; Amiga/Atari containers and vector-table entry
|
||||
discovery are unsupported. Windows Ghidra P0 admits raw images only for `6502`. See [raw binary guide](https://github.com/morluto/rea/blob/main/docs/providers/raw-binary.md).
|
||||
|
||||
Intel HEX, S-record, UF2 and DfuSe files are containers, not raw images:
|
||||
`inspect_artifact` lists address regions (UF2 per familyID, DfuSe per element
|
||||
with its alternate setting), and `extract_artifact` writes each region. Open an
|
||||
extracted region as `raw-binary` with its start address as `entry_point`. UF2
|
||||
numbering gaps leave coverage unknown; a DfuSe suffix CRC mismatch follows
|
||||
`integrity_policy`. See [UF2 and DfuSe](https://github.com/morluto/rea/blob/main/docs/uf2-dfuse.md).
|
||||
|
||||
## ESP images
|
||||
|
||||
For an ESP32-family app or bootloader image, `open_binary` then
|
||||
`inspect_artifact` with `detail: "summary"`. `root_format_metadata` holds the
|
||||
observed `header` and `descriptor` (its `kind` is the app or bootloader role)
|
||||
and the derived `chip`, `checksum`, `appended_sha256` and
|
||||
`undescribed_trailing` ranges. Segment rows (`segment-NN.bin`) carry
|
||||
`load_addr`, `classification` (`mapped`, `loaded`, `not-loaded` or `unknown`,
|
||||
per ESP-IDF `should_map`/`should_load`; RAM ranges are not checked) and
|
||||
`source_location`; select them with `inspect_analysis_view` and
|
||||
`logical_paths`. Signature blocks are `unverified`; `public_key_sha256`
|
||||
matches eFuse key digests.
|
||||
|
||||
Unknown `source_coverage` means truncation or undescribed trailing bytes, such
|
||||
as the flash segments of a `--ram-only-header` image; do not infer absence
|
||||
from it. Erased flash is described. Integrity mismatches are facts, not
|
||||
refusals. ESP8266 images are refused, and flash-encrypted images are not
|
||||
recognized. Segments are not disassembled, and RISC-V or Xtensa segments
|
||||
cannot be opened as raw-binary. See
|
||||
[ESP images](https://github.com/morluto/rea/blob/main/docs/esp-image.md).
|
||||
|
||||
## ESP flash images
|
||||
|
||||
A whole-flash dump opens as `esp-flash-image`. `root_format_metadata` holds
|
||||
`partition_table` (its `method`: `default`, `caller` or a derived
|
||||
`scan`), `bootloader` and `apps` ESP image facts, the `otadata` records,
|
||||
`partitions_outside_dump` and `boot_selection`. Every table has a
|
||||
`boot_selection`: its `basis` names the bootloader's branch (`no-otadata`
|
||||
without otadata, `none` when the bootloader rejects the table, `unknown`
|
||||
when a record is missing), and it lists its `assumptions`;
|
||||
`running_partition` is always `unknown`. Each image names its entry
|
||||
`path`. With `detail: "summary"` the root kind is `esp-flash-image-summary`
|
||||
and each image is a compact `summary` (chip, entry point, segment count,
|
||||
classified load ranges, signature block count, descriptor identity,
|
||||
integrity); complete detail keeps every segment. Partition rows
|
||||
(`partitions/<label>.bin`) carry the declared `type`, `subtype`, names,
|
||||
`flash_address`, `size` and flags; `encrypted` is a storage flag, not
|
||||
proof of ciphertext. `written_offset`/`written_end` bound the bytes that
|
||||
are not erased: an app slot whose facts say `erased` can still hold an older
|
||||
image, and a limitation says so. For a dump read from another flash address, call
|
||||
`open_binary` with `format: "esp-flash-image"` and `flash_offset`; an
|
||||
`esp-image` whose `flash_dump` is set names that offset in a next probe; a
|
||||
relocated table can be named with `partition_table_offset`. No table found
|
||||
means unknown, often flash encryption. Extraction writes `nvs_keys` as
|
||||
ordinary data. See
|
||||
[ESP flash images](https://github.com/morluto/rea/blob/main/docs/esp-flash-image.md).
|
||||
@@ -0,0 +1,449 @@
|
||||
# Offline format and metadata inspection
|
||||
|
||||
Read only the sections needed for the selected task.
|
||||
|
||||
- [Release exposure](#release-exposure)
|
||||
- [Go build metadata](#go-build-metadata)
|
||||
- [Model files](#model-files)
|
||||
- [IL2CPP metadata](#il2cpp-metadata)
|
||||
- [Rust dependency metadata](#rust-dependency-metadata)
|
||||
- [PE Authenticode certificate tables](#pe-authenticode-certificate-tables)
|
||||
- [PE import and delay-load tables](#pe-import-and-delay-load-tables)
|
||||
- [Windows Shell Link shortcuts](#windows-shell-link-shortcuts)
|
||||
- [PE TLS callbacks and load configuration](#pe-tls-callbacks-and-load-configuration)
|
||||
- [Binary hardening](#binary-hardening)
|
||||
- [ELF note tables](#elf-note-tables)
|
||||
- [ELF and Mach-O initializer functions](#elf-and-mach-o-initializer-functions)
|
||||
- [ELF unwind function ranges](#elf-unwind-function-ranges)
|
||||
- [Apple IPS crash reports](#apple-ips-crash-reports)
|
||||
- [Linux kernel modules](#linux-kernel-modules)
|
||||
- [Linux kernel build config](#linux-kernel-build-config)
|
||||
- [CPython pyc files](#cpython-pyc-files)
|
||||
- [Erlang BEAM files](#erlang-beam-files)
|
||||
- [SQLite snapshots](#sqlite-snapshots)
|
||||
- [Recorded Linux crashes](#recorded-linux-crashes)
|
||||
- [Offline ELF layout](#offline-elf-layout)
|
||||
- [Offline WASM](#offline-wasm)
|
||||
- [Offline APK signatures](#offline-apk-signatures)
|
||||
- [Offline PE resource inventory](#offline-pe-resource-inventory)
|
||||
- [Offline PE and ELF export tables](#offline-pe-and-elf-export-tables)
|
||||
- [EVM bytecode](#evm-bytecode)
|
||||
- [Embedded GPU code objects](#embedded-gpu-code-objects)
|
||||
|
||||
## Release exposure
|
||||
|
||||
Use `audit_release_exposure` (`rea audit-release-exposure PATH`) when the question is what static analysis of a shipped `.app`, install directory, ASAR, or executable recovers. Each check has a stable id, a status, the observation behind it, and fixed remediation. Unknown and unassessed checks stay in the report. The report does not establish that the application is secure.
|
||||
|
||||
`text.credential_markers` reports a rule id and location only. Matched bytes, previews, lengths, and hashes of matched bytes are omitted.
|
||||
|
||||
`native.hardening`, `macho.hardened_runtime`, and `android.manifest` are not assessed here. Their next probes are `inspect_binary_hardening`, `inspect_signature`, and `inspect_android_package`.
|
||||
|
||||
See [release exposure](https://github.com/morluto/rea/blob/main/docs/release-exposure.md).
|
||||
|
||||
## Go build metadata
|
||||
|
||||
Use `inspect_go_binary` for an explicit local ELF, PE or Mach-O (universal
|
||||
files need `architecture`) when the
|
||||
question concerns the embedded compiler version, module/dependency versions,
|
||||
local replacements, build settings, or static Go string literals packed without
|
||||
NUL terminators. Pass `include_string_literals: true`
|
||||
(`--include-string-literals`, optional `max_string_literals` /
|
||||
`--max-string-literals`) to recover bounded inferred word-aligned `(ptr, len)`
|
||||
UTF-8 string slices from read-only data and page them through `go`
|
||||
`string_literals` views. No `open_binary`, Go installation or
|
||||
target execution is required. The CLI equivalent is `inspect-go-binary PATH`.
|
||||
Preserve artifact SHA-256, original file ranges, framed module bytes and every
|
||||
unparsed module-text line. A missing record is an unknown, not proof of a
|
||||
non-Go binary; observed metadata does not authenticate its claims, and static
|
||||
`(ptr, len)` string recovery excludes compiler-inlined stack/immediate strings
|
||||
without proving runtime reachability. Function,
|
||||
source and type recovery remain a separate native-analysis question.
|
||||
|
||||
See the [Go binary guide](https://github.com/morluto/rea/blob/main/docs/guides/native/go-binaries.md).
|
||||
|
||||
## Model files
|
||||
|
||||
Optional `view` selects one page in the initial call. Batch metadata keys or
|
||||
tensor names and select only needed fields; do not infer model behavior from
|
||||
declared architecture or tensor types.
|
||||
|
||||
Use `inspect_model_artifact` (`inspect-model-artifact PATH`) for local GGUF v2/v3
|
||||
and safetensors declarations without a model runtime. Header-only mode does not
|
||||
read weights or establish full-file identity. `hash: "full"` explicitly streams
|
||||
all bytes. Retained `model-artifact` views page `metadata`, `tensors` and derived
|
||||
`types`, with exact batch filters and selected fields. Arrays retain typed counts
|
||||
and eight-element previews; omitted values, unknown types and runtime behavior
|
||||
stay explicit. See [model files](https://github.com/morluto/rea/blob/main/docs/model-artifacts.md).
|
||||
|
||||
## IL2CPP metadata
|
||||
|
||||
Use `inspect_il2cpp_metadata` for an explicit local Unity `global-metadata.dat`
|
||||
(versions 24, 27, 29, 31 and 39) when the question concerns assembly images,
|
||||
names, member owners, string literals, namespaces or index ranges. No `open_binary`, Unity installation or target
|
||||
execution is required. The CLI equivalent is `inspect-il2cpp-metadata PATH`.
|
||||
MCP defaults to counts with complete retained Evidence. Query `sections`,
|
||||
`images`, `types`, `methods`, `fields`, `properties`, `events`, `parameters` or
|
||||
`string_literals` through `inspect_analysis_view`; use exact names,
|
||||
batch indices and selected fields. Row indices are scoped by artifact SHA-256
|
||||
and collection; page offsets count filtered matches. Parameters support batch
|
||||
`method_indices` to read one method's parameters directly. Historical reports
|
||||
without member collections retain unknown counts rather than empty inventories. Preserve
|
||||
artifact SHA-256 and index widths. Unrecognized magic may mean encryption and
|
||||
is unsupported, not decrypted.
|
||||
|
||||
Optional matching `binary_path` enables static native addresses and type
|
||||
references. Query `method_addresses` with indices or addresses/states, preserving
|
||||
every shared-body method and both artifact identities. Without a linked binary,
|
||||
native counts remain unknown. Byte-pattern fallback is inferred; no runtime
|
||||
behavior or same-build pairing is proved.
|
||||
See [IL2CPP metadata](https://github.com/morluto/rea/blob/main/docs/il2cpp-metadata.md).
|
||||
|
||||
## Rust dependency metadata
|
||||
|
||||
For selected crates, use `view: {collection: "packages", names: [...],
|
||||
fields: ["name", "version", "source"]}` on the first call. Include `dependencies`
|
||||
explicitly for direct index references. Select `detail: "summary"` for counts and
|
||||
ranges; retained Rust package/edge views support later filters. Keep complete
|
||||
parent Evidence accessible; CLI compact delivery requires `--evidence_output`.
|
||||
|
||||
Use `inspect_rust_binary` for an explicit local ELF, PE, or Mach-O (universal
|
||||
files need `architecture`) when
|
||||
the question concerns the cargo-auditable crate list embedded in `.dep-v0`
|
||||
(Mach-O: `__DATA,.dep-v0`). No `open_binary`, Rust installation, or target
|
||||
execution is required. The CLI equivalent is `inspect-rust-binary PATH`.
|
||||
Preserve artifact SHA-256, package order, dependency indices, and the section
|
||||
file range. A missing section is null metadata, not proof the binary has no
|
||||
dependencies. An omitted package kind stays null. A rustc commit hash is
|
||||
inferred from a read-only `/rustc/<40-hex>/` path and does not by itself
|
||||
identify the compiler. See [Rust binaries](https://github.com/morluto/rea/blob/main/docs/rust-binaries.md).
|
||||
|
||||
## PE Authenticode certificate tables
|
||||
|
||||
Use `inspect_pe_certificates` for an explicit local PE32/PE32+ image when the
|
||||
question concerns the Authenticode certificate table, WIN_CERTIFICATE types, or
|
||||
embedded PKCS#7 signer and X.509 identity fields. No `open_binary`, Windows SDK,
|
||||
or target execution is required. The CLI equivalent is
|
||||
`inspect-pe-certificates PATH`. Preserve artifact SHA-256, table file ranges,
|
||||
payload hashes, original validity-time spellings, and
|
||||
`subject_key_identifier_hex` when the signer uses that form. A missing
|
||||
`IMAGE_DIRECTORY_ENTRY_SECURITY` directory is observed absence of that table,
|
||||
not proof the image is unsigned in every catalog or overlay sense. Signatures,
|
||||
chains, timestamps, and Authenticode digest coverage remain unobserved. See
|
||||
[PE Authenticode certificate tables](https://github.com/morluto/rea/blob/main/docs/pe-certificates.md).
|
||||
|
||||
## PE import and delay-load tables
|
||||
|
||||
Use `inspect_pe_imports` for an explicit local PE32/PE32+ image when the
|
||||
question concerns imported DLL and function names, ordinals, delay-load
|
||||
descriptors, or the pefile import hash. No `open_binary`, Windows SDK, or
|
||||
target execution is required. The CLI equivalent is `inspect-pe-imports PATH`.
|
||||
Preserve artifact SHA-256, directory file ranges, original DLL spellings, and
|
||||
ILT/IAT RVAs. A missing `IMAGE_DIRECTORY_ENTRY_IMPORT` directory is observed
|
||||
absence of that table, not proof the image never imported APIs through another
|
||||
table or overlay. Bound snapshots, loaded IAT contents, and export-forward
|
||||
resolution remain unobserved. See
|
||||
[PE import and delay-load tables](https://github.com/morluto/rea/blob/main/docs/pe-imports.md).
|
||||
|
||||
## Windows Shell Link shortcuts
|
||||
|
||||
Use `inspect_windows_shortcut` for an explicit local `.lnk` file when the
|
||||
question concerns the recorded target path, arguments, working directory, icon
|
||||
location, volume serial, network share names, ExtraData blocks, or Tracker
|
||||
droid identifiers. No `open_binary`, Windows SDK, COM, or target execution is
|
||||
required. The CLI equivalent is `inspect-windows-shortcut PATH`. Preserve
|
||||
artifact SHA-256, FILETIME raw decimals, IDList type bytes, and ExtraData
|
||||
signatures. Unknown IDList items and ExtraData signatures remain raw with
|
||||
SHA-256; they are not guessed. Version-1 UUID MAC and timestamp values are
|
||||
labelled derived. A missing optional section is observed absence of that
|
||||
structure. See
|
||||
[Windows Shell Link shortcuts](https://github.com/morluto/rea/blob/main/docs/guides/native/windows-shortcut.md).
|
||||
|
||||
## PE TLS callbacks and load configuration
|
||||
|
||||
Preserve each callback's RVA, file offset and section alongside its VA and the
|
||||
size-covered declaration fields. A missing directory is observed absence of
|
||||
that declaration.
|
||||
|
||||
Use `inspect_pe_load_config` for an explicit local PE32/PE32+ image when the
|
||||
question concerns code that runs before the entry point through TLS callbacks,
|
||||
or the security cookie, SafeSEH, CFG, EH-continuation and XFG declarations in
|
||||
the load configuration. No `open_binary`, Windows SDK, or target execution is
|
||||
required. The CLI equivalent is `inspect-pe-load-config PATH`. Preserve artifact
|
||||
SHA-256, directory and callback-array file ranges, and callback VAs as
|
||||
hexadecimal strings. Fields outside the declared `Size` are `null`. Guard-flag
|
||||
mitigations carry `evidence_kind: "inferred"`; enforcement remains unobserved.
|
||||
See
|
||||
[PE TLS callbacks and load configuration](https://github.com/morluto/rea/blob/main/docs/pe-load-config.md).
|
||||
|
||||
## Binary hardening
|
||||
|
||||
Each property reports `enabled`, `disabled`, `partial`, `unknown`, or
|
||||
`not_applicable`, with the header field or import behind it.
|
||||
|
||||
Use `inspect_binary_hardening` for an explicit local ELF, PE, or Mach-O file
|
||||
when the question concerns PIE or ASLR, NX, RELRO, stack-protector or FORTIFY
|
||||
signs, control-flow flags, or stripped state. No `open_binary`, pwntools, or
|
||||
target execution is required. The CLI equivalent is
|
||||
`inspect-binary-hardening PATH`. Universal Mach-O files return one image per
|
||||
slice. A missing import is `unknown`, not proof the protection was omitted.
|
||||
Authenticode and Mach-O code-signature rows report presence, not validity.
|
||||
`hardened_runtime` stays unknown and names `inspect_signature`. See
|
||||
[binary hardening](https://github.com/morluto/rea/blob/main/docs/binary-hardening.md).
|
||||
|
||||
## ELF note tables
|
||||
|
||||
Retain each note's owner, type, descriptor SHA-256, and PT_NOTE/SHT_NOTE ranges.
|
||||
|
||||
Use `inspect_elf_notes` for an explicit local ELF32/ELF64 image when the
|
||||
question concerns PT_NOTE/SHT_NOTE owners, GNU build-id, or GNU ABI-tag
|
||||
fields. No `open_binary` or target execution is required. The CLI equivalent
|
||||
is `inspect-elf-notes PATH`. Preserve artifact SHA-256, table file ranges,
|
||||
descriptor hashes, and original owner spellings. A missing table is observed
|
||||
absence of those declarations, not proof the image never carried notes in
|
||||
another container. See
|
||||
[ELF note tables](https://github.com/morluto/rea/blob/main/docs/elf-notes.md).
|
||||
|
||||
## ELF and Mach-O initializer functions
|
||||
|
||||
Use `inspect_native_initializers` for an explicit local ELF or Mach-O image
|
||||
when the question is which functions run before `main` or at exit: ELF
|
||||
`DT_PREINIT_ARRAY`, `DT_INIT`, `DT_INIT_ARRAY`, `DT_FINI`, `DT_FINI_ARRAY` and
|
||||
legacy `.ctors`/`.dtors`, or Mach-O `__mod_init_func`, `__init_offsets` and
|
||||
`__mod_term_func`. Pass `architecture` for a universal Mach-O. The CLI
|
||||
equivalent is `inspect-native-initializers PATH`. PIE slots are resolved
|
||||
through RELATIVE, RELR and section relocations, and Mach-O slots through
|
||||
chained fixups. Keep each entry's `resolution`: `unresolved` means the value was
|
||||
not established, and `unresolved_import` names an external symbol. Page with
|
||||
`offset` and `limit`. See
|
||||
[ELF and Mach-O initializer functions](https://github.com/morluto/rea/blob/main/docs/guides/native/native-initializers.md).
|
||||
|
||||
## ELF unwind function ranges
|
||||
|
||||
Use `inspect_elf_unwind_ranges` for an explicit local ELF32/ELF64 image when
|
||||
the question concerns function starts and lengths that survive `strip`, which
|
||||
functions have an LSDA, or which ranges have no exact symbol. No
|
||||
`open_binary` or target execution is required. The CLI equivalent is
|
||||
`inspect-elf-unwind-ranges PATH`. Preserve artifact SHA-256, FDE start and
|
||||
end, containing section, exact symbol name, CIE index, LSDA, and personality.
|
||||
Page later ranges with `offset` and `limit`. A missing `.eh_frame` is
|
||||
observed absence of that declaration and of `PT_GNU_EH_FRAME`, not proof the
|
||||
image has no functions. Header disagreement is a limitation and does not drop
|
||||
decoded ranges. `.debug_frame` is reported present or absent and is not
|
||||
decoded. CFA instructions are counted and not evaluated. Indirect EH pointers
|
||||
are not dereferenced. See
|
||||
[ELF unwind function ranges](https://github.com/morluto/rea/blob/main/docs/guides/native/elf-unwind-ranges.md).
|
||||
|
||||
## Apple IPS crash reports
|
||||
|
||||
Use `inspect_apple_ips` for an explicit local Apple `.ips` file when the
|
||||
question concerns crash metadata, exception and termination facts, threads,
|
||||
usedImages, lossless registers, or documented crash classes. No `open_binary`,
|
||||
Xcode, atos, or target execution is required. The CLI equivalent is
|
||||
`inspect-apple-ips PATH`. Preserve artifact SHA-256, `bug_type` as a string,
|
||||
uppercase image UUIDs, and integer literals that exceed IEEE-754 range. Only
|
||||
`bug_type` `"309"` yields a crash body; other DiagnosticReports types return
|
||||
no crash result. Select `join_path` for one local Mach-O or dSYM to match
|
||||
report images to slices by UUID and architecture. Preserve the selected
|
||||
artifact identity, slice facts and unjoined reasons; a joined static address
|
||||
does not resolve function names or dSYM symbols. See
|
||||
[Apple IPS crash reports](https://github.com/morluto/rea/blob/main/docs/apple-ips.md).
|
||||
|
||||
## Linux kernel modules
|
||||
|
||||
Use `inspect_kernel_module` for an explicit local ELF32/ELF64 relocatable
|
||||
object when the question concerns `.modinfo` license, vermagic, alias,
|
||||
depends, or parm strings, the `__versions` symbol CRCs, or an appended module
|
||||
signature trailer. No `open_binary`, Linux host, or `modinfo` program is
|
||||
required. The CLI equivalent is `inspect-kernel-module PATH`. Preserve
|
||||
artifact SHA-256, key order, duplicate keys, CRC hex, and section file ranges.
|
||||
A missing section is observed absence when section names are known, not proof
|
||||
the module never carried that metadata. `.gnu.linkonce.this_module` is reported
|
||||
as present or absent; `struct module` stays unknown because its layout changes
|
||||
with the kernel version. `__ksymtab` records are not decoded. The PKCS#7 range
|
||||
and its SHA-256 are observed; certificate, signer, and digest coverage remain
|
||||
unvalidated. An absent trailer is not proof the module is unsigned in another
|
||||
container. gzip, xz, and zstd whole-file containers are unsupported and name
|
||||
`external_decompression` as the next probe: use an external codec utility to
|
||||
decompress into a separate file, then call `inspect_kernel_module` on that file. See
|
||||
[Linux kernel modules](https://github.com/morluto/rea/blob/main/docs/kernel-modules.md).
|
||||
|
||||
## Linux kernel build config
|
||||
|
||||
Use `inspect_kernel_build_config` for an explicit local kernel image (`vmlinux`
|
||||
ELF, raw arm64 `Image`, x86 `bzImage`/`zImage`, or `configs.ko`) when the
|
||||
question is which kernel version it is or how it was configured. No
|
||||
`open_binary`, Linux host, or `extract-ikconfig` is required. The CLI
|
||||
equivalent is `inspect-kernel-build-config PATH`; pass `name` for one exact
|
||||
`CONFIG_*` option and `offset`/`limit` to page the rest. Preserve the banner
|
||||
version, builder, and compiler, the config SHA-256 and option count, and each
|
||||
entry's value kind (`y`, `m`, `string`, `number`, `not_set`). A config is
|
||||
accepted only when `IKCFG_ST` is immediately followed by a valid gzip member
|
||||
and `IKCFG_ED`, so an ordinary `IKCFG_ST` string is not a config. Offsets with
|
||||
`space: "inflated_payload"` are positions in an inflated bzImage payload, not
|
||||
file offsets. An absent config describes only the searched bytes; the kernel
|
||||
may have been built without `CONFIG_IKCONFIG` or with it as a module. Truncated
|
||||
payloads are incomplete, not absent. A framed blob that does not decode, has a
|
||||
bad CRC, or holds non-config text is `malformed`, not absent. xz, lz4, lzma, zstd, bzip2, and lzo
|
||||
payloads are unsupported and name `external_decompression`: decompress with an
|
||||
external utility, then call `inspect_kernel_build_config` on the result. See
|
||||
[Linux kernel build config](https://github.com/morluto/rea/blob/main/docs/guides/native/kernel-build-config.md).
|
||||
|
||||
## CPython pyc files
|
||||
|
||||
Use `inspect_python_pyc` for an explicit local CPython 3.7–3.13 `.pyc` when the
|
||||
question concerns the header magic, PEP 552 source hash or timestamp, nested
|
||||
code-object names, or bytecode identity. No `open_binary`, Python installation,
|
||||
or target execution is required. The CLI equivalent is `inspect-python-pyc PATH`.
|
||||
Preserve artifact SHA-256, the 16-byte header fields, nested code names, and
|
||||
bytecode SHA-256. Bytecode is not decompiled. A decoded header does not prove
|
||||
the matching `.py` is present. See [CPython pyc inspection](https://github.com/morluto/rea/blob/main/docs/python-pyc.md).
|
||||
|
||||
## Erlang BEAM files
|
||||
|
||||
Use `inspect_erlang_beam` for an explicit local `FOR1`/`BEAM` file when the
|
||||
question concerns IFF chunks, atom names, exports, imports, lambdas, or the
|
||||
Code header. No `open_binary`, Erlang installation, or bytecode execution is
|
||||
required. The CLI equivalent is `inspect-erlang-beam PATH`. Preserve artifact
|
||||
SHA-256, chunk file ranges, 1-based atom indices, and original atom spellings.
|
||||
Missing optional tables stay null. For a few facts, use `detail: "summary"` with
|
||||
a `beam` view selecting a collection, exact names/indices and fields; read later
|
||||
pages from `parent_evidence_id` or the complete Evidence bundle. Same-name
|
||||
exports retain every arity and original atom index. CLI summary delivery requires
|
||||
`--evidence_output`. Null table counts remain distinct from decoded empty tables. See
|
||||
[Erlang BEAM files](https://github.com/morluto/rea/blob/main/docs/erlang-beam.md).
|
||||
|
||||
## SQLite snapshots
|
||||
|
||||
Use `inspect_sqlite_database` with an explicit local database snapshot for its
|
||||
schema and optional rows from one exact ordinary table. It requires Node.js
|
||||
24.x >=24.15 or 26+ with the native `DatabaseSync.limits` API. It also consumes the
|
||||
existing sibling `-wal`; retain both original digests when citing its result.
|
||||
Default output is a compact inventory; a selected table expands only its own
|
||||
schema and samples 20 rows. Select `columns` to avoid irrelevant or large cells,
|
||||
and request `schema_scope: "database"` only for complete schema details.
|
||||
Choose `row_limit` when a finite sample is useful and keep truncation and
|
||||
unspecified row order explicit. Virtual tables, shadow tables and views are
|
||||
schema facts, not row-read targets. REA inspects private copies and leaves
|
||||
the source files untouched; obtain a coherent quiescent database/WAL snapshot
|
||||
before inspection. See [SQLite snapshots](https://github.com/morluto/rea/blob/main/docs/guides/data/sqlite-databases.md).
|
||||
|
||||
## Recorded Linux crashes
|
||||
|
||||
Use `inspect_recorded_crash` with an explicit Linux x86-64 ELF core path to
|
||||
inspect historical thread registers, signals, raw notes and original file
|
||||
ranges. It is independent of the active disassembler target. Source-bound
|
||||
register values and note bytes are observations; missing notes, signal-thread
|
||||
association and current executable/library identity remain unknown. PIDs are
|
||||
historical metadata and never authorize live attach or control.
|
||||
|
||||
The optional `include_debugger_context` facet adds mapping candidates through
|
||||
caller-supplied GDB/pwndbg in an owned core-only session. Display names do not
|
||||
establish current file identity; zero reported flags leave permissions unknown.
|
||||
Requested unavailable context fails with setup guidance. See
|
||||
[recorded crashes](https://github.com/morluto/rea/blob/main/docs/guides/native/recorded-crashes.md)
|
||||
for exact upstream profiles, bounds and verification coverage.
|
||||
|
||||
## Offline ELF layout
|
||||
|
||||
Use `inspect_binary_layout` with an explicit local ELF path for file-backed
|
||||
sections, symbols, relocations, linkage names, and static mitigation inferences
|
||||
without opening a disassembler target. When that complete record is already
|
||||
retained, call `inspect_analysis_view` for a summary, mitigations or linkage
|
||||
facet, one section or symbol, or a stable page. Do not re-run the decoder to
|
||||
read a single object.
|
||||
|
||||
## Offline WASM
|
||||
|
||||
Supply WABT 1.0.42 through `REA_WABT_BIN_DIRECTORY`. Select JavaScript glue and
|
||||
candidate paths explicitly, preserving URL/path ambiguity and exact byte/tool
|
||||
identity; no implicit fetch is performed.
|
||||
|
||||
Use `inspect_wasm_artifact` with caller-supplied WABT for selected local bytes.
|
||||
For counts, validation and WAT identity, select `detail: "summary"` on the first
|
||||
MCP call. The complete original Evidence stays retained; use
|
||||
`normalized_result.parent_evidence_id` for exact exports or text pages. Omitted
|
||||
or complete detail keeps the existing complete result.
|
||||
For a completed result, use `inspect_analysis_view` with its reported retained
|
||||
reference for a summary or `view: {kind: "wasm", facet: "exports", offset: 0, limit: 32}`.
|
||||
Facets also include sections, imports, candidates, glue, WAT, headers, details
|
||||
and tool profile. Text offsets count UTF-16 code units; follow `next_offset`.
|
||||
The complete source remains retained after an oversized MCP reply. No target
|
||||
execution or network acquisition is implied, and WAT is decoded representation.
|
||||
|
||||
For exact core-module import/export differences, use `compare_wasm_interfaces`
|
||||
with two complete inspection Evidence records (or current-session retained
|
||||
references) and explicit scope. Preserve unknown types/duplicate names; static
|
||||
interface equality is not runtime compatibility. CLI accepts complete inline
|
||||
Evidence in `rea compare-wasm-interfaces input.json --json`, or exact references
|
||||
with `--evidence-bundle /absolute/path/evidence.json`. Use the complete parent
|
||||
ID when the inspection returned a summary.
|
||||
|
||||
See the [WASM guide](https://github.com/morluto/rea/blob/main/docs/guides/wasm/wasm-artifacts.md).
|
||||
|
||||
## Offline APK signatures
|
||||
|
||||
Use `inspect_apk_signature` for a selected local APK/ZIP/AAB. Default MCP summaries
|
||||
retain complete Evidence. Select `view.collection: signers/digests/lineage`,
|
||||
with scheme or ID batches, fields and paging; use `inspect_analysis_view` kind
|
||||
`apk-signature` for retained reads after deletion. IDs retain artifact/scheme
|
||||
scope and signer links; `fields: []` keeps identity links. Empty pages preserve
|
||||
partial decoding reasons and unknown authenticity. CLI compact delivery needs
|
||||
`--evidence_output` to preserve the complete parent.
|
||||
It reads the APK
|
||||
Signing Block (v2/v3/v3.1) and v1 `META-INF` signing without executing anything,
|
||||
and reports each signer's certificate facts (for v1, the certificate the PKCS#7
|
||||
block's SignerInfo names), the declared v3 rotation lineage,
|
||||
the declared source-stamp certificate and, for SHA-256/SHA-512 digests, whether
|
||||
the declared content digest matches the current bytes. That match is not a
|
||||
signature verification: anyone who changes the bytes can recompute the digest.
|
||||
`posture` summarises v1-only signing (which cannot tell a v1-only APK from one
|
||||
whose v2/v3 block was removed), observed signer agreement across schemes,
|
||||
whether the v1 signer equals the block-scheme signer (`false` is notable),
|
||||
whether every differing signer appears in a declared (unverified) rotation
|
||||
lineage, and the strongest scheme.
|
||||
It never claims authenticity: no signature or lineage is cryptographically
|
||||
verified.
|
||||
|
||||
See the [APK signature guide](https://github.com/morluto/rea/blob/main/docs/apk-signature.md).
|
||||
|
||||
## Offline PE resource inventory
|
||||
|
||||
Use `inspect_pe_resources` with an absolute `path`, or
|
||||
`rea inspect-pe-resources ./selected.exe --json`, for portable PE32/PE32+
|
||||
resource inspection without opening a native target. Preserve returned Evidence:
|
||||
type/name/language IDs and UTF-16 names, original directory/data/payload ranges,
|
||||
code pages, payload hashes and static icon-group references. Same-language icon
|
||||
resolution is explicit; missing references and size mismatch remain visible.
|
||||
Other payloads are opaque, and this operation does not decode images or simulate
|
||||
Windows resource loading. Consult the budgets and supported tree profile in
|
||||
[offline binary diagnostics](https://github.com/morluto/rea/blob/main/docs/guides/native/binary-diagnostics.md).
|
||||
|
||||
## Offline PE and ELF export tables
|
||||
|
||||
Use `inspect_native_exports` with an absolute `path`, or
|
||||
`rea inspect-native-exports ./libexample.so --json`, to read a PE export
|
||||
directory or ELF dynamic symbol table on any host without opening a native
|
||||
target. Ordinal-only, forwarded and hidden-version exports stay distinct;
|
||||
partial or unsupported coverage means the inventory is incomplete, not that
|
||||
exports are absent. Use `inspect_macho` for Mach-O. See
|
||||
[offline binary diagnostics](https://github.com/morluto/rea/blob/main/docs/guides/native/binary-diagnostics.md).
|
||||
|
||||
## EVM bytecode
|
||||
|
||||
Explicit local EVM bytecode carrier: `inspect_evm_interface` with caller-selected
|
||||
`raw` or `hex` encoding. The owned worker deadline is `timeout_ms` (default
|
||||
30000 ms, range 1..2147483647, next call). Select byte, address-space and CPU
|
||||
allowances separately through `producer_limits`; tighter inherited OS limits
|
||||
remain enforced, and the 256 MiB worker heap is independent. Preserve carrier/decoded digests and treat selectors,
|
||||
argument strings and mutability as inferred candidates; this performs no chain
|
||||
lookup or target execution. For the complete inferred interface without hex or
|
||||
duplicate stdout, discover support and select `detail: "summary"`; complete
|
||||
Evidence stays retained under its original identity. Use the returned
|
||||
`parent_evidence_id` for exact function or `bytecode_hex`/stdout/stderr pages.
|
||||
Candidate coverage does not establish interface completeness. See the
|
||||
[EVM bytecode guide](https://github.com/morluto/rea/blob/main/docs/guides/evm/evm-bytecode.md).
|
||||
|
||||
## Embedded GPU code objects
|
||||
|
||||
Embedded CUDA/HIP code objects: `inspect_gpu_code_objects`; inventory targets
|
||||
first, then decode selected payloads and query retained GPU Evidence.
|
||||
@@ -1,5 +1,13 @@
|
||||
# JavaScript and Electron application artifacts
|
||||
|
||||
Read only the sections needed for the selected task.
|
||||
|
||||
- [Inventory route candidates without returning the application graph](#inventory-route-candidates-without-returning-the-application-graph)
|
||||
- [Read a module without repeating analysis](#read-a-module-without-repeating-analysis)
|
||||
- [Trace only the remaining question](#trace-only-the-remaining-question)
|
||||
- [Recover an oversized display](#recover-an-oversized-display)
|
||||
- [Reusing application Evidence](#reusing-application-evidence)
|
||||
|
||||
For captured or bundled JavaScript that needs readable source recovery, use
|
||||
`recover_javascript_sources` with an absolute `path` and absent
|
||||
`output_directory`. Supply related runtime/shared/lazy files in
|
||||
@@ -90,6 +98,9 @@ Endpoint candidates remain inferences rather than confirmed network behavior.
|
||||
## Read a module without repeating analysis
|
||||
|
||||
Use the actual returned parent ID, on the same connection, as `source.evidence_id`.
|
||||
For CLI summary exports, take that ID from
|
||||
`summary.normalized_result.parent_evidence_id` and pass `--evidence-bundle` with
|
||||
the exported bundle's path to each later `inspect-analysis-view` invocation.
|
||||
The following IDs are placeholders to replace with returned values. When the
|
||||
module's node ID is not already known, page identities before selecting an item.
|
||||
Pages return only node IDs, paths and roles; choose a useful page size and follow
|
||||
|
||||
@@ -1,4 +1,23 @@
|
||||
# Native, managed, and packaged artifacts
|
||||
# Native and managed analysis
|
||||
|
||||
<a id="native-managed-and-packaged-artifacts"></a>
|
||||
|
||||
Read only the sections needed for the selected task.
|
||||
|
||||
- [Other artifact guides](#other-artifact-guides)
|
||||
- [Apple app resources](#apple-app-resources)
|
||||
- [Desktop installation directories](#desktop-installation-directories)
|
||||
- [Native targets](#native-targets)
|
||||
- [Continue editable Ghidra analysis across processes](#continue-editable-ghidra-analysis-across-processes)
|
||||
- [Reuse caller-selected Ghidra analysis](#reuse-caller-selected-ghidra-analysis)
|
||||
- [Ghidra startup deadline recovery](#ghidra-startup-deadline-recovery)
|
||||
- [Bridge request ceiling](#bridge-request-ceiling)
|
||||
- [Selected native facts and call graphs](#selected-native-facts-and-call-graphs)
|
||||
- [Static memory and original file bytes](#static-memory-and-original-file-bytes)
|
||||
- [DOS MZ with Ghidra](#dos-mz-with-ghidra)
|
||||
- [Managed PE/CLI](#managed-pe-cli-guide)
|
||||
- [DOS COM loader interpretation](#dos-com-loader-interpretation)
|
||||
- [Function annotations in Ghidra](#function-annotations-in-ghidra)
|
||||
|
||||
For release comparisons on one MCP connection, retain `list_procedures` Evidence
|
||||
from each target and reuse its exact IDs after target switches or `close_binary`.
|
||||
@@ -62,342 +81,39 @@ runtime presence. For compact CLI output, use
|
||||
`inspect-desktop-application PATH --detail summary --evidence_output BUNDLE`.
|
||||
See [desktop installations](https://github.com/morluto/rea/blob/main/docs/desktop-applications.md).
|
||||
|
||||
## Release exposure
|
||||
|
||||
Use `audit_release_exposure` (`rea audit-release-exposure PATH`) when the question is what static analysis of a shipped `.app`, install directory, ASAR, or executable recovers. Each check has a stable id, a status, the observation behind it, and fixed remediation. Unknown and unassessed checks stay in the report. The report does not establish that the application is secure.
|
||||
|
||||
`text.credential_markers` reports a rule id and location only. Matched bytes, previews, lengths, and hashes of matched bytes are omitted.
|
||||
|
||||
`native.hardening`, `macho.hardened_runtime`, and `android.manifest` are not assessed here. Their next probes are `inspect_binary_hardening`, `inspect_signature`, and `inspect_android_package`.
|
||||
|
||||
See [release exposure](https://github.com/morluto/rea/blob/main/docs/release-exposure.md).
|
||||
|
||||
## Go build metadata
|
||||
|
||||
Use `inspect_go_binary` for an explicit local ELF, PE or Mach-O (universal
|
||||
files need `architecture`) when the
|
||||
question concerns the embedded compiler version, module/dependency versions,
|
||||
local replacements, build settings, or static Go string literals packed without
|
||||
NUL terminators. Pass `include_string_literals: true`
|
||||
(`--include-string-literals`, optional `max_string_literals` /
|
||||
`--max-string-literals`) to recover bounded inferred word-aligned `(ptr, len)`
|
||||
UTF-8 string slices from read-only data and page them through `go`
|
||||
`string_literals` views. No `open_binary`, Go installation or
|
||||
target execution is required. The CLI equivalent is `inspect-go-binary PATH`.
|
||||
Preserve artifact SHA-256, original file ranges, framed module bytes and every
|
||||
unparsed module-text line. A missing record is an unknown, not proof of a
|
||||
non-Go binary; observed metadata does not authenticate its claims, and static
|
||||
`(ptr, len)` string recovery excludes compiler-inlined stack/immediate strings
|
||||
without proving runtime reachability. Function,
|
||||
source and type recovery remain a separate native-analysis question.
|
||||
|
||||
## Model files
|
||||
|
||||
Use `inspect_model_artifact` (`inspect-model-artifact PATH`) for local GGUF v2/v3
|
||||
and safetensors declarations without a model runtime. Header-only mode does not
|
||||
read weights or establish full-file identity. `hash: "full"` explicitly streams
|
||||
all bytes. Retained `model-artifact` views page `metadata`, `tensors` and derived
|
||||
`types`, with exact batch filters and selected fields. Arrays retain typed counts
|
||||
and eight-element previews; omitted values, unknown types and runtime behavior
|
||||
stay explicit. See [model files](https://github.com/morluto/rea/blob/main/docs/model-artifacts.md).
|
||||
|
||||
## IL2CPP metadata
|
||||
|
||||
Use `inspect_il2cpp_metadata` for an explicit local Unity `global-metadata.dat`
|
||||
(versions 24, 27, 29, 31 and 39) when the question concerns assembly images,
|
||||
names, member owners, string literals, namespaces or index ranges. No `open_binary`, Unity installation or target
|
||||
execution is required. The CLI equivalent is `inspect-il2cpp-metadata PATH`.
|
||||
MCP defaults to counts with complete retained Evidence. Query `sections`,
|
||||
`images`, `types`, `methods`, `fields`, `properties`, `events`, `parameters` or
|
||||
`string_literals` through `inspect_analysis_view`; use exact names,
|
||||
batch indices and selected fields. Row indices are scoped by artifact SHA-256
|
||||
and collection; page offsets count filtered matches. Parameters support batch
|
||||
`method_indices` to read one method's parameters directly. Historical reports
|
||||
without member collections retain unknown counts rather than empty inventories. Preserve
|
||||
artifact SHA-256 and index widths. Unrecognized magic may mean encryption and
|
||||
is unsupported, not decrypted. Linking names to `GameAssembly` or
|
||||
`UnityFramework` code addresses remains a separate native-analysis question.
|
||||
See [IL2CPP metadata](https://github.com/morluto/rea/blob/main/docs/il2cpp-metadata.md).
|
||||
|
||||
## Rust dependency metadata
|
||||
|
||||
Use `inspect_rust_binary` for an explicit local ELF, PE, or Mach-O (universal
|
||||
files need `architecture`) when
|
||||
the question concerns the cargo-auditable crate list embedded in `.dep-v0`
|
||||
(Mach-O: `__DATA,.dep-v0`). No `open_binary`, Rust installation, or target
|
||||
execution is required. The CLI equivalent is `inspect-rust-binary PATH`.
|
||||
Preserve artifact SHA-256, package order, dependency indices, and the section
|
||||
file range. A missing section is null metadata, not proof the binary has no
|
||||
dependencies. An omitted package kind stays null. A rustc commit hash is
|
||||
inferred from a read-only `/rustc/<40-hex>/` path and does not by itself
|
||||
identify the compiler. See [Rust binaries](https://github.com/morluto/rea/blob/main/docs/rust-binaries.md).
|
||||
|
||||
## PE Authenticode certificate tables
|
||||
|
||||
Use `inspect_pe_certificates` for an explicit local PE32/PE32+ image when the
|
||||
question concerns the Authenticode certificate table, WIN_CERTIFICATE types, or
|
||||
embedded PKCS#7 signer and X.509 identity fields. No `open_binary`, Windows SDK,
|
||||
or target execution is required. The CLI equivalent is
|
||||
`inspect-pe-certificates PATH`. Preserve artifact SHA-256, table file ranges,
|
||||
payload hashes, original validity-time spellings, and
|
||||
`subject_key_identifier_hex` when the signer uses that form. A missing
|
||||
`IMAGE_DIRECTORY_ENTRY_SECURITY` directory is observed absence of that table,
|
||||
not proof the image is unsigned in every catalog or overlay sense. Signatures,
|
||||
chains, timestamps, and Authenticode digest coverage remain unobserved. See
|
||||
[PE Authenticode certificate tables](https://github.com/morluto/rea/blob/main/docs/pe-certificates.md).
|
||||
|
||||
## PE import and delay-load tables
|
||||
|
||||
Use `inspect_pe_imports` for an explicit local PE32/PE32+ image when the
|
||||
question concerns imported DLL and function names, ordinals, delay-load
|
||||
descriptors, or the pefile import hash. No `open_binary`, Windows SDK, or
|
||||
target execution is required. The CLI equivalent is `inspect-pe-imports PATH`.
|
||||
Preserve artifact SHA-256, directory file ranges, original DLL spellings, and
|
||||
ILT/IAT RVAs. A missing `IMAGE_DIRECTORY_ENTRY_IMPORT` directory is observed
|
||||
absence of that table, not proof the image never imported APIs through another
|
||||
table or overlay. Bound snapshots, loaded IAT contents, and export-forward
|
||||
resolution remain unobserved. See
|
||||
[PE import and delay-load tables](https://github.com/morluto/rea/blob/main/docs/pe-imports.md).
|
||||
|
||||
## Windows Shell Link shortcuts
|
||||
|
||||
Use `inspect_windows_shortcut` for an explicit local `.lnk` file when the
|
||||
question concerns the recorded target path, arguments, working directory, icon
|
||||
location, volume serial, network share names, ExtraData blocks, or Tracker
|
||||
droid identifiers. No `open_binary`, Windows SDK, COM, or target execution is
|
||||
required. The CLI equivalent is `inspect-windows-shortcut PATH`. Preserve
|
||||
artifact SHA-256, FILETIME raw decimals, IDList type bytes, and ExtraData
|
||||
signatures. Unknown IDList items and ExtraData signatures remain raw with
|
||||
SHA-256; they are not guessed. Version-1 UUID MAC and timestamp values are
|
||||
labelled derived. A missing optional section is observed absence of that
|
||||
structure. See
|
||||
[Windows Shell Link shortcuts](https://github.com/morluto/rea/blob/main/docs/guides/native/windows-shortcut.md).
|
||||
|
||||
## PE TLS callbacks and load configuration
|
||||
|
||||
Use `inspect_pe_load_config` for an explicit local PE32/PE32+ image when the
|
||||
question concerns code that runs before the entry point through TLS callbacks,
|
||||
or the security cookie, SafeSEH, CFG, EH-continuation and XFG declarations in
|
||||
the load configuration. No `open_binary`, Windows SDK, or target execution is
|
||||
required. The CLI equivalent is `inspect-pe-load-config PATH`. Preserve artifact
|
||||
SHA-256, directory and callback-array file ranges, and callback VAs as
|
||||
hexadecimal strings. Fields outside the declared `Size` are `null`. Guard-flag
|
||||
mitigations carry `evidence_kind: "inferred"`; enforcement remains unobserved.
|
||||
See
|
||||
[PE TLS callbacks and load configuration](https://github.com/morluto/rea/blob/main/docs/pe-load-config.md).
|
||||
|
||||
## Binary hardening
|
||||
|
||||
Use `inspect_binary_hardening` for an explicit local ELF, PE, or Mach-O file
|
||||
when the question concerns PIE or ASLR, NX, RELRO, stack-protector or FORTIFY
|
||||
signs, control-flow flags, or stripped state. No `open_binary`, pwntools, or
|
||||
target execution is required. The CLI equivalent is
|
||||
`inspect-binary-hardening PATH`. Universal Mach-O files return one image per
|
||||
slice. A missing import is `unknown`, not proof the protection was omitted.
|
||||
Authenticode and Mach-O code-signature rows report presence, not validity.
|
||||
`hardened_runtime` stays unknown and names `inspect_signature`. See
|
||||
[binary hardening](https://github.com/morluto/rea/blob/main/docs/binary-hardening.md).
|
||||
|
||||
## ELF note tables
|
||||
|
||||
Use `inspect_elf_notes` for an explicit local ELF32/ELF64 image when the
|
||||
question concerns PT_NOTE/SHT_NOTE owners, GNU build-id, or GNU ABI-tag
|
||||
fields. No `open_binary` or target execution is required. The CLI equivalent
|
||||
is `inspect-elf-notes PATH`. Preserve artifact SHA-256, table file ranges,
|
||||
descriptor hashes, and original owner spellings. A missing table is observed
|
||||
absence of those declarations, not proof the image never carried notes in
|
||||
another container. See
|
||||
[ELF note tables](https://github.com/morluto/rea/blob/main/docs/elf-notes.md).
|
||||
|
||||
## ELF and Mach-O initializer functions
|
||||
|
||||
Use `inspect_native_initializers` for an explicit local ELF or Mach-O image
|
||||
when the question is which functions run before `main` or at exit: ELF
|
||||
`DT_PREINIT_ARRAY`, `DT_INIT`, `DT_INIT_ARRAY`, `DT_FINI`, `DT_FINI_ARRAY` and
|
||||
legacy `.ctors`/`.dtors`, or Mach-O `__mod_init_func`, `__init_offsets` and
|
||||
`__mod_term_func`. Pass `architecture` for a universal Mach-O. The CLI
|
||||
equivalent is `inspect-native-initializers PATH`. PIE slots are resolved
|
||||
through RELATIVE, RELR and section relocations, and Mach-O slots through
|
||||
chained fixups. Keep each entry's `resolution`: `unresolved` means the value was
|
||||
not established, and `unresolved_import` names an external symbol. Page with
|
||||
`offset` and `limit`. See
|
||||
[ELF and Mach-O initializer functions](https://github.com/morluto/rea/blob/main/docs/guides/native/native-initializers.md).
|
||||
|
||||
## ELF unwind function ranges
|
||||
|
||||
Use `inspect_elf_unwind_ranges` for an explicit local ELF32/ELF64 image when
|
||||
the question concerns function starts and lengths that survive `strip`, which
|
||||
functions have an LSDA, or which ranges have no exact symbol. No
|
||||
`open_binary` or target execution is required. The CLI equivalent is
|
||||
`inspect-elf-unwind-ranges PATH`. Preserve artifact SHA-256, FDE start and
|
||||
end, containing section, exact symbol name, CIE index, LSDA, and personality.
|
||||
Page later ranges with `offset` and `limit`. A missing `.eh_frame` is
|
||||
observed absence of that declaration and of `PT_GNU_EH_FRAME`, not proof the
|
||||
image has no functions. Header disagreement is a limitation and does not drop
|
||||
decoded ranges. `.debug_frame` is reported present or absent and is not
|
||||
decoded. CFA instructions are counted and not evaluated. Indirect EH pointers
|
||||
are not dereferenced. See
|
||||
[ELF unwind function ranges](https://github.com/morluto/rea/blob/main/docs/guides/native/elf-unwind-ranges.md).
|
||||
|
||||
## Apple IPS crash reports
|
||||
|
||||
Use `inspect_apple_ips` for an explicit local Apple `.ips` file when the
|
||||
question concerns crash metadata, exception and termination facts, threads,
|
||||
usedImages, lossless registers, or documented crash classes. No `open_binary`,
|
||||
Xcode, atos, or target execution is required. The CLI equivalent is
|
||||
`inspect-apple-ips PATH`. Preserve artifact SHA-256, `bug_type` as a string,
|
||||
uppercase image UUIDs, and integer literals that exceed IEEE-754 range. Only
|
||||
`bug_type` `"309"` yields a crash body; other DiagnosticReports types return
|
||||
no crash result. Select `join_path` for one local Mach-O or dSYM to match
|
||||
report images to slices by UUID and architecture. Preserve the selected
|
||||
artifact identity, slice facts and unjoined reasons; a joined static address
|
||||
does not resolve function names or dSYM symbols. See
|
||||
[Apple IPS crash reports](https://github.com/morluto/rea/blob/main/docs/apple-ips.md).
|
||||
|
||||
## Linux kernel modules
|
||||
|
||||
Use `inspect_kernel_module` for an explicit local ELF32/ELF64 relocatable
|
||||
object when the question concerns `.modinfo` license, vermagic, alias,
|
||||
depends, or parm strings, the `__versions` symbol CRCs, or an appended module
|
||||
signature trailer. No `open_binary`, Linux host, or `modinfo` program is
|
||||
required. The CLI equivalent is `inspect-kernel-module PATH`. Preserve
|
||||
artifact SHA-256, key order, duplicate keys, CRC hex, and section file ranges.
|
||||
A missing section is observed absence when section names are known, not proof
|
||||
the module never carried that metadata. `.gnu.linkonce.this_module` is reported
|
||||
as present or absent; `struct module` stays unknown because its layout changes
|
||||
with the kernel version. `__ksymtab` records are not decoded. The PKCS#7 range
|
||||
and its SHA-256 are observed; certificate, signer, and digest coverage remain
|
||||
unvalidated. An absent trailer is not proof the module is unsigned in another
|
||||
container. gzip, xz, and zstd whole-file containers are unsupported and name
|
||||
`external_decompression` as the next probe: use an external codec utility to
|
||||
decompress into a separate file, then call `inspect_kernel_module` on that file. See
|
||||
[Linux kernel modules](https://github.com/morluto/rea/blob/main/docs/kernel-modules.md).
|
||||
|
||||
## Linux kernel build config
|
||||
|
||||
Use `inspect_kernel_build_config` for an explicit local kernel image (`vmlinux`
|
||||
ELF, raw arm64 `Image`, x86 `bzImage`/`zImage`, or `configs.ko`) when the
|
||||
question is which kernel version it is or how it was configured. No
|
||||
`open_binary`, Linux host, or `extract-ikconfig` is required. The CLI
|
||||
equivalent is `inspect-kernel-build-config PATH`; pass `name` for one exact
|
||||
`CONFIG_*` option and `offset`/`limit` to page the rest. Preserve the banner
|
||||
version, builder, and compiler, the config SHA-256 and option count, and each
|
||||
entry's value kind (`y`, `m`, `string`, `number`, `not_set`). A config is
|
||||
accepted only when `IKCFG_ST` is immediately followed by a valid gzip member
|
||||
and `IKCFG_ED`, so an ordinary `IKCFG_ST` string is not a config. Offsets with
|
||||
`space: "inflated_payload"` are positions in an inflated bzImage payload, not
|
||||
file offsets. An absent config describes only the searched bytes; the kernel
|
||||
may have been built without `CONFIG_IKCONFIG` or with it as a module. Truncated
|
||||
payloads are incomplete, not absent. A framed blob that does not decode, has a
|
||||
bad CRC, or holds non-config text is `malformed`, not absent. xz, lz4, lzma, zstd, bzip2, and lzo
|
||||
payloads are unsupported and name `external_decompression`: decompress with an
|
||||
external utility, then call `inspect_kernel_build_config` on the result. See
|
||||
[Linux kernel build config](https://github.com/morluto/rea/blob/main/docs/guides/native/kernel-build-config.md).
|
||||
|
||||
## CPython pyc files
|
||||
|
||||
Use `inspect_python_pyc` for an explicit local CPython 3.7–3.13 `.pyc` when the
|
||||
question concerns the header magic, PEP 552 source hash or timestamp, nested
|
||||
code-object names, or bytecode identity. No `open_binary`, Python installation,
|
||||
or target execution is required. The CLI equivalent is `inspect-python-pyc PATH`.
|
||||
Preserve artifact SHA-256, the 16-byte header fields, nested code names, and
|
||||
bytecode SHA-256. Bytecode is not decompiled. A decoded header does not prove
|
||||
the matching `.py` is present. See [CPython pyc inspection](https://github.com/morluto/rea/blob/main/docs/python-pyc.md).
|
||||
|
||||
## Erlang BEAM files
|
||||
|
||||
Use `inspect_erlang_beam` for an explicit local `FOR1`/`BEAM` file when the
|
||||
question concerns IFF chunks, atom names, exports, imports, lambdas, or the
|
||||
Code header. No `open_binary`, Erlang installation, or bytecode execution is
|
||||
required. The CLI equivalent is `inspect-erlang-beam PATH`. Preserve artifact
|
||||
SHA-256, chunk file ranges, 1-based atom indices, and original atom spellings.
|
||||
Missing optional tables stay null. For a few facts, use `detail: "summary"` with
|
||||
a `beam` view selecting a collection, exact names/indices and fields; read later
|
||||
pages from `parent_evidence_id` or the complete Evidence bundle. Same-name
|
||||
exports retain every arity and original atom index. CLI summary delivery requires
|
||||
`--evidence_output`. Null table counts remain distinct from decoded empty tables. See
|
||||
[Erlang BEAM files](https://github.com/morluto/rea/blob/main/docs/erlang-beam.md).
|
||||
|
||||
## SQLite snapshots
|
||||
|
||||
Use `inspect_sqlite_database` with an explicit local database snapshot for its
|
||||
schema and optional rows from one exact ordinary table. It requires Node.js
|
||||
24.x >=24.15 or 26+ with the native `DatabaseSync.limits` API. It also consumes the
|
||||
existing sibling `-wal`; retain both original digests when citing its result.
|
||||
Default output is a compact inventory; a selected table expands only its own
|
||||
schema and samples 20 rows. Select `columns` to avoid irrelevant or large cells,
|
||||
and request `schema_scope: "database"` only for complete schema details.
|
||||
Choose `row_limit` when a finite sample is useful and keep truncation and
|
||||
unspecified row order explicit. Virtual tables, shadow tables and views are
|
||||
schema facts, not row-read targets. REA inspects private copies and leaves
|
||||
the source files untouched; obtain a coherent quiescent database/WAL snapshot
|
||||
before inspection. See [SQLite snapshots](https://github.com/morluto/rea/blob/main/docs/guides/data/sqlite-databases.md).
|
||||
|
||||
## Recorded Linux crashes
|
||||
|
||||
Use `inspect_recorded_crash` with an explicit Linux x86-64 ELF core path to
|
||||
inspect historical thread registers, signals, raw notes and original file
|
||||
ranges. It is independent of the active disassembler target. Source-bound
|
||||
register values and note bytes are observations; missing notes, signal-thread
|
||||
association and current executable/library identity remain unknown. PIDs are
|
||||
historical metadata and never authorize live attach or control.
|
||||
|
||||
The optional `include_debugger_context` facet adds mapping candidates through
|
||||
caller-supplied GDB/pwndbg in an owned core-only session. Display names do not
|
||||
establish current file identity; zero reported flags leave permissions unknown.
|
||||
Requested unavailable context fails with setup guidance. See
|
||||
[recorded crashes](https://github.com/morluto/rea/blob/main/docs/guides/native/recorded-crashes.md)
|
||||
for exact upstream profiles, bounds and verification coverage.
|
||||
|
||||
## Offline ELF layout
|
||||
|
||||
Use `inspect_binary_layout` with an explicit local ELF path for file-backed
|
||||
sections, symbols, relocations, linkage names, and static mitigation inferences
|
||||
without opening a disassembler target. When that complete record is already
|
||||
retained, call `inspect_analysis_view` for a summary, mitigations or linkage
|
||||
facet, one section or symbol, or a stable page. Do not re-run the decoder to
|
||||
read a single object.
|
||||
|
||||
## Offline WASM
|
||||
|
||||
Use `inspect_wasm_artifact` with caller-supplied WABT for selected local bytes.
|
||||
For counts, validation and WAT identity, select `detail: "summary"` on the first
|
||||
MCP call. The complete original Evidence stays retained; use
|
||||
`normalized_result.parent_evidence_id` for exact exports or text pages. Omitted
|
||||
or complete detail keeps the existing complete result.
|
||||
For a completed result, use `inspect_analysis_view` with its reported retained
|
||||
reference for a summary or `view: {kind: "wasm", facet: "exports", offset: 0, limit: 32}`.
|
||||
Facets also include sections, imports, candidates, glue, WAT, headers, details
|
||||
and tool profile. Text offsets count UTF-16 code units; follow `next_offset`.
|
||||
The complete source remains retained after an oversized MCP reply. No target
|
||||
execution or network acquisition is implied, and WAT is decoded representation.
|
||||
|
||||
## Offline APK signatures
|
||||
|
||||
Use `inspect_apk_signature` for a selected local APK/ZIP/AAB. Default MCP summaries
|
||||
retain complete Evidence. Select `view.collection: signers/digests/lineage`,
|
||||
with scheme or ID batches, fields and paging; use `inspect_analysis_view` kind
|
||||
`apk-signature` for retained reads after deletion. IDs retain artifact/scheme
|
||||
scope and signer links; `fields: []` keeps identity links. Empty pages preserve
|
||||
partial decoding reasons and unknown authenticity. CLI compact delivery needs
|
||||
`--evidence_output` to preserve the complete parent.
|
||||
It reads the APK
|
||||
Signing Block (v2/v3/v3.1) and v1 `META-INF` signing without executing anything,
|
||||
and reports each signer's certificate facts (for v1, the certificate the PKCS#7
|
||||
block's SignerInfo names), the declared v3 rotation lineage,
|
||||
the declared source-stamp certificate and, for SHA-256/SHA-512 digests, whether
|
||||
the declared content digest matches the current bytes. That match is not a
|
||||
signature verification: anyone who changes the bytes can recompute the digest.
|
||||
`posture` summarises v1-only signing (which cannot tell a v1-only APK from one
|
||||
whose v2/v3 block was removed), observed signer agreement across schemes,
|
||||
whether the v1 signer equals the block-scheme signer (`false` is notable),
|
||||
whether every differing signer appears in a declared (unverified) rotation
|
||||
lineage, and the strongest scheme.
|
||||
It never claims authenticity: no signature or lineage is cryptographically
|
||||
verified.
|
||||
|
||||
## Native targets
|
||||
|
||||
For an existing IDA MCP configuration, use `open_binary` with the original
|
||||
input binary and `provider_id: "ida"`; do not pass an `.idb` or `.i64` database.
|
||||
The legacy attached profile binds the already-open GUI input by SHA-256 and
|
||||
leaves its database open. The modern headless profile creates and closes an
|
||||
owned private database without saving. Installation and registration reuse
|
||||
[mrexodia/ida-pro-mcp](https://github.com/mrexodia/ida-pro-mcp); see the
|
||||
[IDA provider guide](https://github.com/morluto/rea/blob/main/docs/providers/ida-provider.md).
|
||||
For migration to the separate native IDA MCP plugin, follow the guide's
|
||||
[legacy attached migration](https://github.com/morluto/rea/blob/main/docs/providers/ida-provider.md#migrate-a-legacy-attached-registration).
|
||||
Replace the upstream registration explicitly; modern mrexodia tools are not the
|
||||
native profile. Native attachment preserves the database but does not provide
|
||||
direct callers; check session availability and the guide's verification limits.
|
||||
Proceed directly to `analyze_function`, pseudocode, or function/string searches
|
||||
after opening; IDA does not supply `binary_overview`. Consult session availability
|
||||
when composing broader workflows. Modern direct callers and unsupported dossier
|
||||
facets remain unknown; live IDA results are not replayed from snapshots.
|
||||
|
||||
With `REA_KUNA_COMMAND` configured, `provider_id: "kuna"` answers procedure
|
||||
lists, lookups, pseudocode, assembly and `analyze_function` from Kuna's cached
|
||||
whole-program export. Callers/callees use a separate body-free graph shared by
|
||||
the session; `xrefs` returns exact-address incoming sites and filters forwarding
|
||||
aliases. These queries and inventory lookups do not trigger a C export. Indirect
|
||||
targets remain unknown and can make relationship coverage partial. Reference
|
||||
caches expire on close; a fresh CLI process repeats the native reference walk.
|
||||
Typed references, CFG, raw-memory tools and annotations remain unsupported. A cold first
|
||||
answer can come from a single-function run (its limitations say so); assembly
|
||||
waits for the export. For pseudocode and assembly, `raw_result.source` names the
|
||||
cached `.c`/`.asm` file and byte span, which you may search directly instead of
|
||||
calling per function. See the
|
||||
[Kuna provider guide](https://github.com/morluto/rea/blob/main/docs/kuna-provider.md).
|
||||
|
||||
After `open_binary`, use focused search, procedure, or function tools directly.
|
||||
Use `binary_overview` when target metadata or inventory context helps answer the
|
||||
question. Prefer literal search, names, decompilation, callers, callees, and
|
||||
@@ -632,6 +348,8 @@ that a class is a root class or has no ivars.
|
||||
|
||||
## Managed PE/CLI
|
||||
|
||||
<a id="managed-pe-cli-guide"></a>
|
||||
|
||||
Start with `inspect_managed_artifact`. REA's canonical managed inspection is
|
||||
execution-free: do not claim it loaded, reflected, executed, or resolved the
|
||||
assembly. Keep managed/native boundaries and unavailable reconstruction facts
|
||||
@@ -690,81 +408,17 @@ and distinguish derived metadata from Ghidra database observations. Recovered
|
||||
types and native pseudocode are not original C# source. Windows Ghidra P0 has
|
||||
no database mutation authority.
|
||||
|
||||
## Packages and extraction
|
||||
For headerless firmware and address-bearing containers, read
|
||||
[raw images](firmware-and-raw-images.md#headerless-raw-images-and-firmware-containers).
|
||||
|
||||
Use `inspect_artifact` for application bundles, archives, ZIP/APK/IPA/MSIX/AppX,
|
||||
ASAR, or DMG inputs when the artifact graph and findings help answer the
|
||||
question. It returns the complete artifact graph inline. Cite graph manifest
|
||||
IDs when using them.
|
||||
|
||||
For an IPA or a macOS `.app`, ZIP, or DMG, pass the inventory Evidence to
|
||||
`project_apple_application_graph`. It reports application roots and nested
|
||||
bundles by path convention: app extensions, XPC services, frameworks, login
|
||||
items, system and driver extensions, and plug-ins. It also lists privileged
|
||||
helpers, launchd plists, symlinks, and each bundle's `info_plist_path` and
|
||||
executable candidates. Roles are path conventions, not parsed plists; read the
|
||||
listed plists with `inspect_plist`.
|
||||
|
||||
After `open_binary` on a `.app` or Mach-O, use `trace_dylib_resolution` to see
|
||||
which file each `@rpath`, `@loader_path` and `@executable_path` load reaches for
|
||||
every executable in the bundle. It also lists missing or weak loads and earlier
|
||||
`@rpath` candidates that are absent. Narrow large bundles with `roots` or
|
||||
`architecture`. System paths stay undetermined because the dyld shared cache
|
||||
provides them.
|
||||
|
||||
Use `extract_artifact` when materialized files from a supported format are needed.
|
||||
It extracts the active target and accepts optional `integrity_policy`; see the [MCP contracts](https://github.com/morluto/rea/blob/main/docs/reference/mcp-contracts.md).
|
||||
It materializes all regular files into a fresh temporary directory chosen by
|
||||
REA. Symlinks and encrypted entries are inventory facts, not extractable files.
|
||||
The result reports the materialized directory; callers do not choose the
|
||||
destination. No separate permission grant is needed.
|
||||
|
||||
For classic iNES cartridges, `open_binary` recognizes the byte signature without
|
||||
an executable architecture. `inspect_artifact` retains header facts and each
|
||||
PRG/CHR file unit's offset, length and SHA-256; its nested inventory's
|
||||
`ines.reconstruction` verifies the actual ordered region bytes against the
|
||||
whole-file digest. Extraction includes the original header, optional trainer
|
||||
and uninterpreted trailing bytes. These file units are not mapper/CPU bank
|
||||
maps. NES 2.0, UNIF, dirty legacy headers and truncated payloads are explicitly
|
||||
refused. No emulator or 6502 analysis is performed. See the
|
||||
[iNES guide](https://github.com/morluto/rea/blob/main/docs/ines-containers.md).
|
||||
|
||||
Native DMG traversal automatically uses a read-only mount on supported macOS
|
||||
hosts, with an owned temporary mount directory and cleanup. It needs no approval
|
||||
flag. Unsupported hosts or mount failures remain explicit limitations; do not
|
||||
claim child inventory when only root identity is available. DMG extraction is
|
||||
unavailable through `extract_artifact`. To access DMG files on macOS, create a
|
||||
read-only mount with your own tools, select files from that mount for analysis,
|
||||
and detach the mount you created when finished. REA's inspection mount is
|
||||
temporary, not a retained export of the image's contents.
|
||||
## DOS COM loader interpretation
|
||||
|
||||
For headerless DOS COM, explicitly open with `format: "dos-com"` (CLI
|
||||
`--target-format dos-com`). Inspect the load image before trusting function
|
||||
analysis: the entry is `0x10100`, file offset zero, with imposed real-mode segment
|
||||
context. PSP/stack/device state remains unmodeled. See [DOS guide](https://github.com/morluto/rea/blob/main/docs/providers/ghidra-dos.md).
|
||||
|
||||
Use `inspect_byte_entropy` to triage high- and low-entropy ranges before extraction.
|
||||
|
||||
For other headerless images (embedded firmware without ELF/Mach-O/PE/MZ
|
||||
headers), open with `format: "raw-binary"`, `architecture` (`x86`, `x86_64`,
|
||||
`arm`, `arm64`, `6502`, or `m68k`), and `entry_point` (`0x` hex). File offset 0 is mapped at
|
||||
that address. Hopper and IDA refuse this interpretation; Ghidra uses
|
||||
`BinaryLoader` with a generic language: big-endian for `m68k`, little-endian
|
||||
otherwise. Big-endian ARM, Thumb-only, and Cortex-M variants are unsupported.
|
||||
`6502` selects NMOS 6502; the entry and complete file mapping must fit within
|
||||
`0x0000..0xffff`. 65C02, 65816, cartridge containers, bank switching, and mapper
|
||||
semantics are unsupported. `m68k` requires an even entry and decodes the 68040
|
||||
superset of the 68000 family; Amiga/Atari containers and vector-table entry
|
||||
discovery are unsupported. Windows Ghidra P0 admits raw images only for `6502`. See [raw binary guide](https://github.com/morluto/rea/blob/main/docs/providers/raw-binary.md).
|
||||
|
||||
Intel HEX, S-record, UF2 and DfuSe files are containers, not raw images:
|
||||
`inspect_artifact` lists address regions (UF2 per familyID, DfuSe per element
|
||||
with its alternate setting), and `extract_artifact` writes each region. Open an
|
||||
extracted region as `raw-binary` with its start address as `entry_point`. UF2
|
||||
numbering gaps leave coverage unknown; a DfuSe suffix CRC mismatch follows
|
||||
`integrity_policy`. See [UF2 and DfuSe](https://github.com/morluto/rea/blob/main/docs/uf2-dfuse.md).
|
||||
|
||||
### Function annotations in Ghidra
|
||||
## Function annotations in Ghidra
|
||||
|
||||
Fresh-import sessions admit annotations; existing-project reuse is read-only.
|
||||
Use `annotate_native_function` for one function name and/or entry comments, with at least one explicit change. Review its annotation readback and refreshed dossier inline. Changes are atomic; empty comments clear them, omitted fields preserve them. Later MCP calls observe edits. Normal close saves them when owned Program checkpoint mode is enabled; ephemeral mode discards them. CLI `annotate-native-function` follows the same setting when closing after its updated result. Select the [checkpoint workflow](#continue-editable-ghidra-analysis-across-processes) before edits that must survive a later process. Original executable bytes are unchanged; edits invalidate immutable snapshots. Windows P0 does not admit database mutations. For naming only, `set_address_name` / `set_addresses_names` also work with Ghidra: they name function entries or data addresses (primary labels) and return compact per-address success booleans instead of a dossier. Ghidra rejects batch addresses that request the same name or a name another selected address holds; `raw_result.failures` gives each failure's reason.
|
||||
@@ -784,160 +438,39 @@ architecture, provider-owned mapping and selected-image commitments. Equal
|
||||
numeric addresses alone cannot establish correspondence; inspect retained
|
||||
source Evidence and coverage when the match remains ambiguous.
|
||||
|
||||
## Offline PE resource inventory
|
||||
## Other artifact guides
|
||||
|
||||
Use `inspect_pe_resources` with an absolute `path`, or
|
||||
`rea inspect-pe-resources ./selected.exe --json`, for portable PE32/PE32+
|
||||
resource inspection without opening a native target. Preserve returned Evidence:
|
||||
type/name/language IDs and UTF-16 names, original directory/data/payload ranges,
|
||||
code pages, payload hashes and static icon-group references. Same-language icon
|
||||
resolution is explicit; missing references and size mismatch remain visible.
|
||||
Other payloads are opaque, and this operation does not decode images or simulate
|
||||
Windows resource loading. Consult the budgets and supported tree profile in
|
||||
[offline binary diagnostics](https://github.com/morluto/rea/blob/main/docs/guides/native/binary-diagnostics.md).
|
||||
Read the owning page for offline formats, containers or firmware. These explicit
|
||||
anchors preserve older links without creating duplicate searchable sections.
|
||||
|
||||
## Offline PE and ELF export tables
|
||||
|
||||
Use `inspect_native_exports` with an absolute `path`, or
|
||||
`rea inspect-native-exports ./libexample.so --json`, to read a PE export
|
||||
directory or ELF dynamic symbol table on any host without opening a native
|
||||
target. Ordinal-only, forwarded and hidden-version exports stay distinct;
|
||||
partial or unsupported coverage means the inventory is incomplete, not that
|
||||
exports are absent. Use `inspect_macho` for Mach-O. See
|
||||
[offline binary diagnostics](https://github.com/morluto/rea/blob/main/docs/guides/native/binary-diagnostics.md).
|
||||
|
||||
For exact core-module import/export differences, use `compare_wasm_interfaces`
|
||||
with two complete inspection Evidence records (or current-session retained
|
||||
references) and explicit scope. Preserve unknown types/duplicate names; static
|
||||
interface equality is not runtime compatibility. CLI accepts complete inline
|
||||
Evidence in `rea compare-wasm-interfaces input.json --json`, or exact references
|
||||
with `--evidence-bundle /absolute/path/evidence.json`. Use the complete parent
|
||||
ID when the inspection returned a summary.
|
||||
|
||||
## Godot PCK
|
||||
|
||||
For a standalone PCK, `open_binary` then `inspect_artifact` with
|
||||
`detail: "summary"` retains the complete static inventory. Use the returned
|
||||
`parent_evidence_id` with `inspect_analysis_view` inventory occurrences filtered
|
||||
by exact `logical_paths` or `occurrence_ids`, and join `artifact_id` to nodes
|
||||
filtered by `artifact_ids`. Select only needed fields; identity links remain.
|
||||
Prefer `inspect-artifact --detail summary --evidence_output PATH` for CLI tasks;
|
||||
the same CLI discovers embedded packs via their EOF trailer without opening a
|
||||
native analysis provider. Normal native opening remains unchanged.
|
||||
|
||||
Distinguish declared MD5 from observed SHA-256 and graph/page completeness from
|
||||
`source_coverage`. Encrypted directories and sparse bundles have unknown entry
|
||||
coverage; encrypted members have unknown content identity. An empty filtered
|
||||
page cannot prove absence in unknown coverage. Retained views are historical,
|
||||
not fresh filesystem checks. No decryption, Godot resource decoding, GDScript
|
||||
decompilation or target execution is provided. See
|
||||
[Godot PCK](https://github.com/morluto/rea/blob/main/docs/godot-pck.md).
|
||||
|
||||
UnityFS AssetBundle containers (`.bundle`, `.ab`, YooAsset packages and other
|
||||
byte-identified files) list `CAB-*` SerializedFiles and `.resS` members with
|
||||
header and node facts; none/LZ4/LZ4HC member blocks stream on demand. Bundles
|
||||
declaring asset-bundle encryption keep header facts with unknown directory
|
||||
coverage; LZMA member bytes retain named occurrences with unavailable hashes.
|
||||
Virtual member offsets are not physical carrier locations. Format 6–8 readers
|
||||
cache one decoded block and support retained filtered/paged views. No
|
||||
decryption or SerializedFile object decoding is provided. See
|
||||
[UnityFS](https://github.com/morluto/rea/blob/main/docs/unityfs.md).
|
||||
|
||||
WeChat mini-program packages (`.wxapkg` files with `0xBE`/`0xED` marks) list
|
||||
members with declared names and absolute carrier offsets; member bytes are
|
||||
stored verbatim. `V1MMWX` PC-client packages report `encrypted` directory
|
||||
status with unknown coverage and are refused on extraction; no decryption is
|
||||
attempted. See
|
||||
[wxapkg](https://github.com/morluto/rea/blob/main/docs/wxapkg.md).
|
||||
|
||||
U-Boot legacy uImages use the same inspection/extraction workflows. Prefer a
|
||||
retained summary and selected inventory views for header facts or component
|
||||
IDs. Header addresses/CPU/OS are declarations; payloads remain as stored.
|
||||
Multi-file components retain their aligned physical ranges; the full payload
|
||||
is also materialized. Unknown name text retains its original 32 bytes. See
|
||||
[U-Boot uImage](https://github.com/morluto/rea/blob/main/docs/uimage.md).
|
||||
|
||||
## ESP images
|
||||
|
||||
For an ESP32-family app or bootloader image, `open_binary` then
|
||||
`inspect_artifact` with `detail: "summary"`. `root_format_metadata` holds the
|
||||
observed `header` and `descriptor` (its `kind` is the app or bootloader role)
|
||||
and the derived `chip`, `checksum`, `appended_sha256` and
|
||||
`undescribed_trailing` ranges. Segment rows (`segment-NN.bin`) carry
|
||||
`load_addr`, `classification` (`mapped`, `loaded`, `not-loaded` or `unknown`,
|
||||
per ESP-IDF `should_map`/`should_load`; RAM ranges are not checked) and
|
||||
`source_location`; select them with `inspect_analysis_view` and
|
||||
`logical_paths`. Signature blocks are `unverified`; `public_key_sha256`
|
||||
matches eFuse key digests.
|
||||
|
||||
Unknown `source_coverage` means truncation or undescribed trailing bytes, such
|
||||
as the flash segments of a `--ram-only-header` image; do not infer absence
|
||||
from it. Erased flash is described. Integrity mismatches are facts, not
|
||||
refusals. ESP8266 images are refused, and flash-encrypted images are not
|
||||
recognized. Segments are not disassembled, and RISC-V or Xtensa segments
|
||||
cannot be opened as raw-binary. See
|
||||
[ESP images](https://github.com/morluto/rea/blob/main/docs/esp-image.md).
|
||||
|
||||
## ESP flash images
|
||||
|
||||
A whole-flash dump opens as `esp-flash-image`. `root_format_metadata` holds
|
||||
`partition_table` (its `method`: `default`, `caller` or a derived
|
||||
`scan`), `bootloader` and `apps` ESP image facts, the `otadata` records,
|
||||
`partitions_outside_dump` and `boot_selection`. Every table has a
|
||||
`boot_selection`: its `basis` names the bootloader's branch (`no-otadata`
|
||||
without otadata, `none` when the bootloader rejects the table, `unknown`
|
||||
when a record is missing), and it lists its `assumptions`;
|
||||
`running_partition` is always `unknown`. Each image names its entry
|
||||
`path`. With `detail: "summary"` the root kind is `esp-flash-image-summary`
|
||||
and each image is a compact `summary` (chip, entry point, segment count,
|
||||
classified load ranges, signature block count, descriptor identity,
|
||||
integrity); complete detail keeps every segment. Partition rows
|
||||
(`partitions/<label>.bin`) carry the declared `type`, `subtype`, names,
|
||||
`flash_address`, `size` and flags; `encrypted` is a storage flag, not
|
||||
proof of ciphertext. `written_offset`/`written_end` bound the bytes that
|
||||
are not erased: an app slot whose facts say `erased` can still hold an older
|
||||
image, and a limitation says so. For a dump read from another flash address, call
|
||||
`open_binary` with `format: "esp-flash-image"` and `flash_offset`; an
|
||||
`esp-image` whose `flash_dump` is set names that offset in a next probe; a
|
||||
relocated table can be named with `partition_table_offset`. No table found
|
||||
means unknown, often flash encryption. Extraction writes `nvs_keys` as
|
||||
ordinary data. See
|
||||
[ESP flash images](https://github.com/morluto/rea/blob/main/docs/esp-flash-image.md).
|
||||
|
||||
## Bun standalone executables
|
||||
|
||||
A `bun build --compile` executable stores its module graph in Mach-O
|
||||
`__BUN,__bun`, a PE or ELF `.bun` section, or an appended trailer.
|
||||
`open_binary` then `inspect_artifact` reports root format `bun-standalone` with
|
||||
the carrier, structural layout, module count, entry point, raw flags and
|
||||
compile exec-argv; each module keeps its `/$bunfs/...` source name, loader,
|
||||
encoding, sizes and SHA-256, with sourcemap, bytecode and module-info regions as
|
||||
separate children. Use summary root metadata `entry_point_logical_path` as the
|
||||
exact inventory `logical_paths` selector, then read the selected content node by
|
||||
its artifact ID; the reader owns virtual-name normalization and indexed fallback. `extract-artifact` writes stored contents through the safe
|
||||
output tree; route extracted JavaScript to `analyze_javascript_application`.
|
||||
Layout labels describe record shapes, not a detected compiler version; unknown
|
||||
or ambiguous layouts are unsupported. Bytecode is retained, not decoded, and the
|
||||
executable is never run. See
|
||||
[Bun standalone executables](https://github.com/morluto/rea/blob/main/docs/bun-standalone.md).
|
||||
|
||||
## Deno compile executables
|
||||
|
||||
A `deno compile` executable stores its application in a Mach-O `__SUI,d3n0l4nd`
|
||||
section, an Intel Mach-O `<~sui-data~>` trailer, an ELF `SUI` note of type
|
||||
`0x53554901`, or a PE `RT_RCDATA` resource named `D3N0L4ND`.
|
||||
`open_binary` then `inspect_artifact` reports root format `deno-standalone`
|
||||
with the carrier, entry point, recorded options, and one occurrence per virtual
|
||||
file, including size and SHA-256. Transpiled output, CJS export analysis, and
|
||||
source maps are separate occurrences with the file's `index` and their own
|
||||
`role`. They normally use a `.deno-*` suffix on the file path and move to an
|
||||
indexed path on a collision, so use the reported `logical_path`. Symlink targets
|
||||
stay recorded path parts. A virtual filesystem that cannot be listed leaves
|
||||
coverage unknown.
|
||||
Environment-file values and CA certificate bytes are retained in local Evidence
|
||||
with their counts and byte lengths. The npm snapshot length is reported and not
|
||||
decoded. `extract-artifact` writes
|
||||
stored files through the safe output tree; route extracted JavaScript to
|
||||
`analyze_javascript_application`. Other layouts are unsupported, and the
|
||||
executable is never run. See
|
||||
[Deno compile executables](https://github.com/morluto/rea/blob/main/docs/deno-standalone.md).
|
||||
- <a id="go-build-metadata"></a>[Go build metadata](format-inspectors.md#go-build-metadata)
|
||||
- <a id="model-files"></a>[Model files](format-inspectors.md#model-files)
|
||||
- <a id="il2cpp-metadata"></a>[IL2CPP metadata](format-inspectors.md#il2cpp-metadata)
|
||||
- <a id="rust-dependency-metadata"></a>[Rust dependency metadata](format-inspectors.md#rust-dependency-metadata)
|
||||
- <a id="pe-authenticode-certificate-tables"></a>[PE Authenticode certificate tables](format-inspectors.md#pe-authenticode-certificate-tables)
|
||||
- <a id="pe-import-and-delay-load-tables"></a>[PE import and delay-load tables](format-inspectors.md#pe-import-and-delay-load-tables)
|
||||
- <a id="pe-tls-callbacks-and-load-configuration"></a>[PE TLS callbacks and load configuration](format-inspectors.md#pe-tls-callbacks-and-load-configuration)
|
||||
- <a id="binary-hardening"></a>[Binary hardening](format-inspectors.md#binary-hardening)
|
||||
- <a id="elf-note-tables"></a>[ELF note tables](format-inspectors.md#elf-note-tables)
|
||||
- <a id="apple-ips-crash-reports"></a>[Apple IPS crash reports](format-inspectors.md#apple-ips-crash-reports)
|
||||
- <a id="linux-kernel-modules"></a>[Linux kernel modules](format-inspectors.md#linux-kernel-modules)
|
||||
- <a id="cpython-pyc-files"></a>[CPython pyc files](format-inspectors.md#cpython-pyc-files)
|
||||
- <a id="erlang-beam-files"></a>[Erlang BEAM files](format-inspectors.md#erlang-beam-files)
|
||||
- <a id="sqlite-snapshots"></a>[SQLite snapshots](format-inspectors.md#sqlite-snapshots)
|
||||
- <a id="recorded-linux-crashes"></a>[Recorded Linux crashes](format-inspectors.md#recorded-linux-crashes)
|
||||
- <a id="offline-elf-layout"></a>[Offline ELF layout](format-inspectors.md#offline-elf-layout)
|
||||
- <a id="offline-wasm"></a>[Offline WASM](format-inspectors.md#offline-wasm)
|
||||
- <a id="offline-apk-signatures"></a>[Offline APK signatures](format-inspectors.md#offline-apk-signatures)
|
||||
- <a id="packages-and-extraction"></a>[Packages and extraction](packages-and-archives.md#packages-and-extraction)
|
||||
- <a id="offline-pe-resource-inventory"></a>[Offline PE resource inventory](format-inspectors.md#offline-pe-resource-inventory)
|
||||
- <a id="offline-pe-and-elf-export-tables"></a>[Offline PE and ELF export tables](format-inspectors.md#offline-pe-and-elf-export-tables)
|
||||
- <a id="godot-pck"></a>[Godot PCK](packages-and-archives.md#godot-pck)
|
||||
- <a id="esp-images"></a>[ESP images](firmware-and-raw-images.md#esp-images)
|
||||
- <a id="esp-flash-images"></a>[ESP flash images](firmware-and-raw-images.md#esp-flash-images)
|
||||
- <a id="bun-standalone-executables"></a>[Bun standalone executables](packages-and-archives.md#bun-standalone-executables)
|
||||
- <a id="release-exposure"></a>[Release exposure](format-inspectors.md#release-exposure)
|
||||
- <a id="windows-shell-link-shortcuts"></a>[Windows Shell Link shortcuts](format-inspectors.md#windows-shell-link-shortcuts)
|
||||
- <a id="elf-and-mach-o-initializer-functions"></a>[ELF and Mach-O initializer functions](format-inspectors.md#elf-and-mach-o-initializer-functions)
|
||||
- <a id="elf-unwind-function-ranges"></a>[ELF unwind function ranges](format-inspectors.md#elf-unwind-function-ranges)
|
||||
- <a id="linux-kernel-build-config"></a>[Linux kernel build config](format-inspectors.md#linux-kernel-build-config)
|
||||
- <a id="deno-compile-executables"></a>[Deno compile executables](packages-and-archives.md#deno-compile-executables)
|
||||
@@ -0,0 +1,146 @@
|
||||
# Packages and archives
|
||||
|
||||
Read only the sections needed for the selected task.
|
||||
|
||||
- [Packages and extraction](#packages-and-extraction)
|
||||
- [Godot PCK](#godot-pck)
|
||||
- [Bun standalone executables](#bun-standalone-executables)
|
||||
- [Deno compile executables](#deno-compile-executables)
|
||||
|
||||
## Packages and extraction
|
||||
|
||||
For PyInstaller executables, the CArchive is the application layer; the native
|
||||
bootloader is only its prefix. Prefer summary delivery for large inventories,
|
||||
then retained inventory views with selected member fields/pages. Runtime options
|
||||
are metadata, not files. Compact delivery still inventories and hashes members.
|
||||
A small complete inventory can cost less than extra calls and schemas. See the
|
||||
[Python packaged applications guide](https://github.com/morluto/rea/blob/main/docs/python-packaged-applications.md).
|
||||
|
||||
Use `inspect_artifact` for application bundles, archives, ZIP/APK/IPA/MSIX/AppX,
|
||||
ASAR, or DMG inputs when the artifact graph and findings help answer the
|
||||
question. It returns the complete artifact graph inline. Cite graph manifest
|
||||
IDs when using them.
|
||||
|
||||
For an IPA or a macOS `.app`, ZIP, or DMG, pass the inventory Evidence to
|
||||
`project_apple_application_graph`. It reports application roots and nested
|
||||
bundles by path convention: app extensions, XPC services, frameworks, login
|
||||
items, system and driver extensions, and plug-ins. It also lists privileged
|
||||
helpers, launchd plists, symlinks, and each bundle's `info_plist_path` and
|
||||
executable candidates. Roles are path conventions, not parsed plists; read the
|
||||
listed plists with `inspect_plist`.
|
||||
|
||||
After `open_binary` on a `.app` or Mach-O, use `trace_dylib_resolution` to see
|
||||
which file each `@rpath`, `@loader_path` and `@executable_path` load reaches for
|
||||
every executable in the bundle. It also lists missing or weak loads and earlier
|
||||
`@rpath` candidates that are absent. Narrow large bundles with `roots` or
|
||||
`architecture`. System paths stay undetermined because the dyld shared cache
|
||||
provides them.
|
||||
|
||||
Use `extract_artifact` when materialized files from a supported format are needed.
|
||||
It extracts the active target and accepts optional `integrity_policy`; see the [MCP contracts](https://github.com/morluto/rea/blob/main/docs/reference/mcp-contracts.md).
|
||||
It materializes all regular files into a fresh temporary directory chosen by
|
||||
REA. Symlinks and encrypted entries are inventory facts, not extractable files.
|
||||
The result reports the materialized directory; callers do not choose the
|
||||
destination. No separate permission grant is needed.
|
||||
|
||||
For classic iNES cartridges, `open_binary` recognizes the byte signature without
|
||||
an executable architecture. `inspect_artifact` retains header facts and each
|
||||
PRG/CHR file unit's offset, length and SHA-256; its nested inventory's
|
||||
`ines.reconstruction` verifies the actual ordered region bytes against the
|
||||
whole-file digest. Extraction includes the original header, optional trainer
|
||||
and uninterpreted trailing bytes. These file units are not mapper/CPU bank
|
||||
maps. NES 2.0, UNIF, dirty legacy headers and truncated payloads are explicitly
|
||||
refused. No emulator or 6502 analysis is performed. See the
|
||||
[iNES guide](https://github.com/morluto/rea/blob/main/docs/ines-containers.md).
|
||||
|
||||
Native DMG traversal automatically uses a read-only mount on supported macOS
|
||||
hosts, with an owned temporary mount directory and cleanup. It needs no approval
|
||||
flag. Unsupported hosts or mount failures remain explicit limitations; do not
|
||||
claim child inventory when only root identity is available. DMG extraction is
|
||||
unavailable through `extract_artifact`. To access DMG files on macOS, create a
|
||||
read-only mount with your own tools, select files from that mount for analysis,
|
||||
and detach the mount you created when finished. REA's inspection mount is
|
||||
temporary, not a retained export of the image's contents.
|
||||
|
||||
Use `inspect_byte_entropy` to triage high- and low-entropy ranges before extraction.
|
||||
|
||||
## Godot PCK
|
||||
|
||||
For a standalone PCK, `open_binary` then `inspect_artifact` with
|
||||
`detail: "summary"` retains the complete static inventory. Use the returned
|
||||
`parent_evidence_id` with `inspect_analysis_view` inventory occurrences filtered
|
||||
by exact `logical_paths` or `occurrence_ids`, and join `artifact_id` to nodes
|
||||
filtered by `artifact_ids`. Select only needed fields; identity links remain.
|
||||
Prefer `inspect-artifact --detail summary --evidence_output PATH` for CLI tasks;
|
||||
the same CLI discovers embedded packs via their EOF trailer without opening a
|
||||
native analysis provider. Normal native opening remains unchanged.
|
||||
|
||||
Distinguish declared MD5 from observed SHA-256 and graph/page completeness from
|
||||
`source_coverage`. Encrypted directories and sparse bundles have unknown entry
|
||||
coverage; encrypted members have unknown content identity. An empty filtered
|
||||
page cannot prove absence in unknown coverage. Retained views are historical,
|
||||
not fresh filesystem checks. No decryption, Godot resource decoding, GDScript
|
||||
decompilation or target execution is provided. See
|
||||
[Godot PCK](https://github.com/morluto/rea/blob/main/docs/godot-pck.md).
|
||||
|
||||
UnityFS AssetBundle containers (`.bundle`, `.ab`, YooAsset packages and other
|
||||
byte-identified files) list `CAB-*` SerializedFiles and `.resS` members with
|
||||
header and node facts; none/LZ4/LZ4HC member blocks stream on demand. Bundles
|
||||
declaring asset-bundle encryption keep header facts with unknown directory
|
||||
coverage; LZMA member bytes retain named occurrences with unavailable hashes.
|
||||
Virtual member offsets are not physical carrier locations. Format 6–8 readers
|
||||
cache one decoded block and support retained filtered/paged views. No
|
||||
decryption or SerializedFile object decoding is provided. See
|
||||
[UnityFS](https://github.com/morluto/rea/blob/main/docs/unityfs.md).
|
||||
|
||||
WeChat mini-program packages (`.wxapkg` files with `0xBE`/`0xED` marks) list
|
||||
members with declared names and absolute carrier offsets; member bytes are
|
||||
stored verbatim. `V1MMWX` PC-client packages report `encrypted` directory
|
||||
status with unknown coverage and are refused on extraction; no decryption is
|
||||
attempted. See
|
||||
[wxapkg](https://github.com/morluto/rea/blob/main/docs/wxapkg.md).
|
||||
|
||||
U-Boot legacy uImages use the same inspection/extraction workflows. Prefer a
|
||||
retained summary and selected inventory views for header facts or component
|
||||
IDs. Header addresses/CPU/OS are declarations; payloads remain as stored.
|
||||
Multi-file components retain their aligned physical ranges; the full payload
|
||||
is also materialized. Unknown name text retains its original 32 bytes. See
|
||||
[U-Boot uImage](https://github.com/morluto/rea/blob/main/docs/uimage.md).
|
||||
|
||||
## Bun standalone executables
|
||||
|
||||
A `bun build --compile` executable stores its module graph in Mach-O
|
||||
`__BUN,__bun`, a PE or ELF `.bun` section, or an appended trailer.
|
||||
`open_binary` then `inspect_artifact` reports root format `bun-standalone` with
|
||||
the carrier, structural layout, module count, entry point, raw flags and
|
||||
compile exec-argv; each module keeps its `/$bunfs/...` source name, loader,
|
||||
encoding, sizes and SHA-256, with sourcemap, bytecode and module-info regions as
|
||||
separate children. Use summary root metadata `entry_point_logical_path` as the
|
||||
exact inventory `logical_paths` selector, then read the selected content node by
|
||||
its artifact ID; the reader owns virtual-name normalization and indexed fallback. `extract-artifact` writes stored contents through the safe
|
||||
output tree; route extracted JavaScript to `analyze_javascript_application`.
|
||||
Layout labels describe record shapes, not a detected compiler version; unknown
|
||||
or ambiguous layouts are unsupported. Bytecode is retained, not decoded, and the
|
||||
executable is never run. See
|
||||
[Bun standalone executables](https://github.com/morluto/rea/blob/main/docs/bun-standalone.md).
|
||||
|
||||
## Deno compile executables
|
||||
|
||||
A `deno compile` executable stores its application in a Mach-O `__SUI,d3n0l4nd`
|
||||
section, an Intel Mach-O `<~sui-data~>` trailer, an ELF `SUI` note of type
|
||||
`0x53554901`, or a PE `RT_RCDATA` resource named `D3N0L4ND`.
|
||||
`open_binary` then `inspect_artifact` reports root format `deno-standalone`
|
||||
with the carrier, entry point, recorded options, and one occurrence per virtual
|
||||
file, including size and SHA-256. Transpiled output, CJS export analysis, and
|
||||
source maps are separate occurrences with the file's `index` and their own
|
||||
`role`. They normally use a `.deno-*` suffix on the file path and move to an
|
||||
indexed path on a collision, so use the reported `logical_path`. Symlink targets
|
||||
stay recorded path parts. A virtual filesystem that cannot be listed leaves
|
||||
coverage unknown.
|
||||
Environment-file values and CA certificate bytes are retained in local Evidence
|
||||
with their counts and byte lengths. The npm snapshot length is reported and not
|
||||
decoded. `extract-artifact` writes
|
||||
stored files through the safe output tree; route extracted JavaScript to
|
||||
`analyze_javascript_application`. Other layouts are unsupported, and the
|
||||
executable is never run. See
|
||||
[Deno compile executables](https://github.com/morluto/rea/blob/main/docs/deno-standalone.md).
|
||||
@@ -0,0 +1,58 @@
|
||||
# Recorded captures and decoder discovery
|
||||
|
||||
## Historical web captures
|
||||
|
||||
Retained HAR/SAZ/native mitmproxy/aioquic qlog capture: `inspect_web_network_capture`. Select
|
||||
original record ordinals when useful; inspect producer fields and byte/number
|
||||
sidecars without fetching recorded URLs or claiming live attribution. For a decoder heap refusal, follow the reported `capture.decoder_old_generation_mib`
|
||||
setting and bounds with `update_analysis_settings` (default 192 MiB, floor 8,
|
||||
maximum 16384); the launch seed
|
||||
`REA_CAPTURE_DECODER_OLD_GENERATION_MIB` affects future REA processes. Host memory
|
||||
and `NODE_OPTIONS` do not raise that decoder allowance. See
|
||||
[historical captures](https://github.com/morluto/rea/blob/main/docs/guides/web/web-network-captures.md) for the exact upstream
|
||||
profile and credential exclusions. Qlog support starts with aioquic 1.5.0
|
||||
JSON 0.3; stream coverage and endpoint loss declarations do not recover bodies
|
||||
or establish network loss. Prefer detail summary, then kind qlog trace/stream
|
||||
pages; select one trace, stream ID and direction for contribution/range pages.
|
||||
Facts retain all-recorded-events-before-selection scope. Other qlog layouts
|
||||
and PCAP correlation are unsupported.
|
||||
|
||||
## Packet fields and packet captures
|
||||
|
||||
Packet-field discovery: `inspect_packet_fields` searches installed protocols
|
||||
and field names/types before choosing fields for `inspect_packet_capture`.
|
||||
Query/page the relevant records; registrations do not establish observed traffic.
|
||||
|
||||
## Packet capture inspection
|
||||
|
||||
Recorded packet captures: `inspect_packet_capture` with selected TShark fields,
|
||||
display filters and decode-as rules. Requires Linux, util-linux prlimit and
|
||||
TShark 4.x on an absolute `PATH` entry or via the optional absolute
|
||||
`REA_TSHARK_COMMAND` override; see
|
||||
[capture guide](https://github.com/morluto/rea/blob/main/docs/guides/data/packet-captures.md).
|
||||
Packet limits count input packets before filtering. Output defaults to 50 matching
|
||||
frames; use `match_offset` / `match_limit` for later pages, or explicit null
|
||||
limit for complete matching output. Preserve the source digest across pages.
|
||||
This does not perform live capture.
|
||||
For address/DNS/SNI/protocol summaries use `inspect_pcap_capture` with MCP
|
||||
detail summary, then retained kind pcap pages. Requires Wireshark 4.x tshark
|
||||
and capinfos, with Linux prlimit or Windows Job Objects; see
|
||||
[packet summaries](https://github.com/morluto/rea/blob/main/docs/guides/data/pcap-analysis.md).
|
||||
Select an exact DNS question for address pages; page exhaustion does not prove
|
||||
network completeness. This reads recordings and does not acquire traffic.
|
||||
|
||||
## Signal decoder discovery
|
||||
|
||||
Decoder discovery: `inspect_signal_decoders` searches installed decoder IDs
|
||||
or selected decoder help, including channels and options. Query and page the
|
||||
relevant details before choosing settings; this does not scan hardware.
|
||||
|
||||
## Recorded logic and signals
|
||||
|
||||
Recorded logic/signal traces: `decode_signal_recording` with explicit decoder,
|
||||
channel and protocol settings. On Linux with util-linux prlimit, supply sigrok-cli 0.7.2 through
|
||||
`REA_SIGROK_COMMAND`; see [recording guide](https://github.com/morluto/rea/blob/main/docs/guides/signals/signal-recordings.md).
|
||||
Output defaults to 50 literal lines; select annotation classes and page with
|
||||
`line_offset` / `line_limit`, or explicit null for all remaining output.
|
||||
Window counts are display lines, not annotations or samples. Preserve source digests across pages.
|
||||
This reads existing files; it does not acquire hardware signals.
|
||||
@@ -1,5 +1,12 @@
|
||||
# Runtime observation
|
||||
|
||||
Read only the sections needed for the selected task.
|
||||
|
||||
- [Native runtime questions](#native-runtime-questions)
|
||||
- [Browser and Electron](#browser-and-electron)
|
||||
- [Who performs the action](#who-performs-the-action)
|
||||
- [Fiddler Everywhere traffic debugging](#fiddler-everywhere-traffic-debugging)
|
||||
|
||||
## Native runtime questions
|
||||
|
||||
Start from the requested observation. State the selected target, input, expected
|
||||
@@ -54,6 +61,18 @@ and [native calls/UI](https://github.com/morluto/rea/blob/main/docs/guides/nativ
|
||||
|
||||
## Browser and Electron
|
||||
|
||||
Passive traffic capture of a SPA: the default scope is the page's own origin,
|
||||
and data APIs usually live on another origin. Discover API origins from
|
||||
absolute URLs in loaded bundles or script text via JavaScript analysis tools
|
||||
(another passive capture without those origins still scopes to the page
|
||||
origin, and `completeness.excluded` counts lack URLs). Pass both the page
|
||||
origin and those API origins in `allowed_origins` — the list replaces the
|
||||
default scope — and read `completeness.excluded` before reporting that an
|
||||
API is absent. For long captures with body shapes, use
|
||||
`export_evidence_bundle` instead of expecting an inline result.
|
||||
|
||||
User-owned Electron runtime already open: `list_electron_targets`. Before an electron-main Inspector attempt, check packaged fuses with `inspect_electron_fuses`; disabled `EnableNodeCliInspectArguments` means the app ignores `--inspect`.
|
||||
|
||||
Supply the existing browser or Electron instance's literal-port loopback CDP
|
||||
endpoint in the request. No separate permission configuration or per-call
|
||||
approval flag is needed. Browser discovery lists eligible HTTP(S) pages;
|
||||
|
||||
@@ -2,607 +2,123 @@
|
||||
name: reverse-engineer-anything
|
||||
description: Reverse engineer native, managed, Electron/JavaScript, packaged, firmware, and browser targets with REA, and build agent environments (AgentEnv bundles) of web applications from a live instance or a capture, and of Linux desktop apps with a task from a request. Use shipped-artifact or requested runtime evidence to explain features, compare versions, decompile code, or guide a reconstruction. Skip REA for ordinary source-repository architecture analysis.
|
||||
metadata:
|
||||
version: "62"
|
||||
version: "64"
|
||||
---
|
||||
|
||||
# REA
|
||||
|
||||
Use REA when a claim depends on a shipped binary or package, decompilation,
|
||||
requested runtime evidence, or comparison with
|
||||
behavior not established by available source. For ordinary analysis of a
|
||||
complete source repository, use normal repository tools and do not run REA
|
||||
Use REA when a claim depends on a shipped artifact, decompilation, requested
|
||||
runtime evidence, or behavior not established by available source. For ordinary
|
||||
analysis of a complete source repository, use normal repository tools and do not run REA
|
||||
readiness or provider commands.
|
||||
|
||||
## Select the target and authority
|
||||
|
||||
Use the target selected for this task. If the user says only "my app", ask which
|
||||
app before searching artifacts. Resolve a named app to one clear installed
|
||||
artifact; ask when ambiguous. Unrelated reports and nearby fixtures do not select
|
||||
it. Never substitute an example or broaden the selected target or runtime actions.
|
||||
|
||||
Distinguish observations, derivations, inferences, and unknowns. Cite Evidence
|
||||
IDs and preserve source identity, coverage, limitations and partial facts.
|
||||
Static code, strings and declarations do not establish observed execution.
|
||||
Within the requested investigation, call available analysis tools directly;
|
||||
REA requires no permission grants or per-call approval flags. The client may
|
||||
independently require approval; preserve its actual access requirements.
|
||||
|
||||
## Connect only when needed
|
||||
|
||||
Installing this skill supplies instructions; it does not register the REA MCP
|
||||
server, install analysis engines, or add tools to an already-running agent.
|
||||
The exception is a Claude Code, Codex, or Cursor Marketplace plugin install:
|
||||
the plugin bundles this skill and registers its own `rea` server, outside the
|
||||
state that `rea setup` and `rea doctor` manage.
|
||||
If REA tools are available and registration is not known stale, proceed directly.
|
||||
Use the connected server's actual tool list and schemas: repository-main guidance
|
||||
may describe features absent from an older release. Keep complete inline Evidence
|
||||
when retained references are not advertised. Skill installation alone adds no
|
||||
MCP server or engines; a Claude Code, Codex or Cursor Marketplace plugin bundles its own server.
|
||||
|
||||
If REA tools are available and their registration is not known to be stale,
|
||||
proceed directly to the target. Do not run diagnostics or setup before every
|
||||
investigation. Use the connected server's actual tool list and input schemas;
|
||||
a skill installed from repository main may describe capabilities absent from
|
||||
an older npm release. Keep complete inline Evidence when that server does not
|
||||
advertise retained references.
|
||||
For absent tools, blocked calls, unavailable providers, host timeouts or startup
|
||||
failures, read [connection and recovery](references/connection-and-recovery.md)
|
||||
before repair. Diagnose the observed blocker, continue useful supported work,
|
||||
and resume the original task after repair. Do not repeat unchanged failed calls.
|
||||
A host timeout without a REA result does not establish cancellation or cleanup.
|
||||
Retry a dropped connection once only if safe to repeat or known not started;
|
||||
if it may have changed the target, or fails again, ask for a client restart.
|
||||
Retry failed connection startup once; do not retry the same unchanged failure.
|
||||
|
||||
If tools are absent, a call is blocked by the client, or a required provider is
|
||||
unavailable, read [connection and recovery](references/connection-and-recovery.md).
|
||||
Diagnose the observed blocker, continue useful supported work, and resume the
|
||||
original task after repair. Client approval, shell PATH, registration and engine
|
||||
availability have different remedies; avoid repeating setup for all of them.
|
||||
If the host times out without a REA result, do not repeat the unchanged call or
|
||||
assume work stopped. Read the recovery guide's deadline distinction before retrying.
|
||||
If the MCP connection drops, retry that call once only when it is safe to
|
||||
repeat or known not to have started. If it may already have changed the
|
||||
target, or it fails again, tell the user and ask them to restart the MCP
|
||||
client. If REA could not start its connection, retry once, then tell the user
|
||||
and ask them to restart the MCP client. Do not retry a startup failure that
|
||||
returns the same unchanged result. For plugin installs, follow
|
||||
[plugin recovery](references/connection-and-recovery.md#rea-installed-as-a-client-plugin).
|
||||
For setup-owned registrations, run `rea doctor` when REA could not start
|
||||
or tools stay missing after that restart. For `cleanup_incomplete`, a retryable
|
||||
capacity limit, or `configuration_invalid`, follow the recovery guide's ladder
|
||||
before asking for a restart. Read that guide before a second repair attempt.
|
||||
|
||||
Choose the installation owner before repairing registration. Plugin installs use
|
||||
[plugin recovery](references/connection-and-recovery.md#rea-installed-as-a-client-plugin);
|
||||
only setup-owned registrations use the guide's
|
||||
[registration repair plan](references/connection-and-recovery.md#repair-registration-when-needed).
|
||||
Choose the registration owner: plugin recovery differs from setup-owned repair.
|
||||
A plugin-only doctor result of `missing` does not call for `rea setup`.
|
||||
Setup-owned repair starts with a read-only plan showing paths, backups and skill
|
||||
replacement before authorized writes. Do not install unrelated software to repair
|
||||
registration. REA setup never installs/upgrades Node, npm, Homebrew, Java,
|
||||
Ghidra, IDA, JADX, Kuna, Binwalk or Unblob.
|
||||
For an unsupported client, use manual stdio with an existing absolute runtime
|
||||
and entry script, or the CLI fallback in the recovery guide.
|
||||
|
||||
REA setup never installs or upgrades Node.js, npm, Homebrew, Java, Ghidra, IDA,
|
||||
JADX, Kuna, Binwalk, or Unblob. Use existing prerequisites; do not install unrelated
|
||||
software to repair MCP registration. For an unsupported client, use manual stdio
|
||||
registration with an existing installation’s absolute runtime and entry script, or continue through the CLI.
|
||||
## Route before analysis
|
||||
|
||||
A concrete CLI fallback for an operator-supplied JavaScript tree or ASAR is:
|
||||
Read the matching guide before its workflow; read only the relevant sections.
|
||||
Target-free tools take their explicit paths/endpoints without `open_binary`.
|
||||
Active-target native/archive tools require it. Archive members and executable
|
||||
code are different questions; follow the selected artifact's application layer.
|
||||
|
||||
```bash
|
||||
npx -y rea-agents@latest analyze-javascript-application /absolute/path/to/app --json
|
||||
```
|
||||
| Supplied target or question | Guide and first operation |
|
||||
| ------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| Native executable/library, Ghidra/IDA/Kuna, managed PE/CLI or NativeAOT | [Native and managed](references/native-and-artifacts.md): `open_binary`; managed CLI metadata: `inspect_managed_artifact`. Read provider/lifecycle sections before reuse or edits. |
|
||||
| Headerless/raw firmware, Cortex-M, ESP app/bootloader or whole-flash dump, HEX/S-record/UF2/DfuSe | [Firmware and raw images](references/firmware-and-raw-images.md): check loader support first; raw: explicit `open_binary` format/mapping; ESP/container: `open_binary` then `inspect_artifact`; region scan/extraction: advertised firmware tools. |
|
||||
| Archive/package inventory or extraction, PyInstaller, Bun/Deno executable, Godot PCK, UnityFS or wxapkg | [Packages and archives](references/packages-and-archives.md): `open_binary`, then `inspect_artifact`; read extraction/mount limits before materializing. |
|
||||
| ASAR/extracted JavaScript or Electron tree, feature trace or version comparison | [JavaScript applications](references/javascript-applications.md): `analyze_javascript_application`. |
|
||||
| APK code, manifest, classes, methods or incoming references | [Android applications](references/android-applications.md): `inspect_android_package`; signing/inventory use their separate routes. |
|
||||
| PE/ELF/Mach-O tables or hardening, Go/Rust/IL2CPP/GPU/model metadata, Windows shortcuts, kernel config, pyc/BEAM, SQLite, WASM, EVM, APK signing or recorded crash | [Offline format inspectors](references/format-inspectors.md): select the named target-free inspector in that format's section. |
|
||||
| Shipped application exposure for a local app, install directory, ASAR or executable | [Offline format inspectors](references/format-inspectors.md#release-exposure): `audit_release_exposure`; preserve unknown/unassessed checks and marker-only credential findings. |
|
||||
| Apple plist, Interface Builder, asset catalog or keyed archive resources; unknown desktop installation directory | [Resource and directory inspection](references/native-and-artifacts.md#apple-app-resources): `open_bundle_resources` or `inspect_desktop_application`; no executable/provider required for resource sessions. |
|
||||
| Native execution, live calls, instrumentation, process effects; browser/Electron runtime or agent-performed actions | [Runtime observation](references/runtime-observation.md): select the observation and declared lifecycle first. Already-open page: `list_browser_targets`; Electron: `list_electron_targets`; agent actions: `capture_browser_scenario`. |
|
||||
| Recorded HAR/SAZ/mitmproxy/qlog, packet capture, protocol-field discovery or logic/signal recording | [Recorded captures](references/recorded-captures.md): `inspect_web_network_capture`, packet/signal inspection or decoder discovery as appropriate; no live acquisition or recorded-URL fetch. |
|
||||
| Web AgentEnv bundle from a live instance or capture; task for an exported desktop environment | [Environments](references/environments.md), including its desktop-task section: read before recording/export; `capture_browser_scenario` then `export_environment_bundle` for a live web bundle. |
|
||||
| Linux desktop application environment built from a user request | [Desktop builds](references/desktop-build.md): drive the selected app on a build computer, then export and witness. |
|
||||
| Retained Evidence paging/composition, comparisons, unknowns or a broader investigation | [Evidence workflows](references/evidence-workflows.md): use existing source IDs and the smallest view that answers the question. |
|
||||
|
||||
No MCP registration or native engine is required. Read the returned Evidence,
|
||||
graph, limitations, and unknowns with the same care as an MCP result; the CLI
|
||||
returns the Evidence record directly. This fallback does not establish that
|
||||
MCP is configured. Native CLI tasks still require their selected engine.
|
||||
Prefer an existing `rea` CLI. When none is installed and REA package acquisition
|
||||
is within the authorized scope, use `npx -y rea-agents@latest` in its place from a
|
||||
trusted directory outside the target project, with absolute target paths. Managed
|
||||
setup binds the current installation directly; retain its runtime and package
|
||||
cache entry, or restore that installation before repairing its registration.
|
||||
For setup-owned registration, configuration repair starts with a read-only setup plan; show paths, backups and
|
||||
skill replacement before applying authorized changes. Preserve existing approval
|
||||
and target-execution boundaries.
|
||||
|
||||
## Route the target first
|
||||
|
||||
Choose the first tool from the target the user supplied. Use `open_binary` for
|
||||
active-target native or archive workflows; target-free tools take their own
|
||||
explicit path or endpoint and do not need it.
|
||||
|
||||
- ASAR or extracted JavaScript/Electron tree:
|
||||
`analyze_javascript_application`.
|
||||
- Archive/package member inventory (ZIP/APK/IPA/MSIX/AppX, DMG, or a PyInstaller
|
||||
executable): `open_binary` with the supplied local path; use `inspect_artifact`
|
||||
when its graph and findings help answer the question. A PyInstaller CArchive
|
||||
is the application layer; the bootloader is only the native prefix. Start with
|
||||
`detail: "summary"` for large inventories, then use retained inventory views
|
||||
for selected member fields/pages. A complete small inventory can cost less
|
||||
than extra calls and schemas. Runtime options are metadata, not files.
|
||||
Compact delivery still inventories and hashes members. See the
|
||||
[Python packaged applications guide](https://github.com/morluto/rea/blob/main/docs/python-packaged-applications.md).
|
||||
- Bun `--compile` executable: `open_binary`, then `inspect_artifact`; the Bun
|
||||
module graph is the application layer. Extract stored modules and analyze the
|
||||
JavaScript. See [Bun standalone executables](https://github.com/morluto/rea/blob/main/docs/bun-standalone.md).
|
||||
- Deno `deno compile` executable: `open_binary`, then `inspect_artifact`; the
|
||||
embedded virtual filesystem is the application layer. Extract stored files and
|
||||
analyze compatible JavaScript. Environment-file values and CA certificate bytes
|
||||
are retained in local Evidence with their counts and byte lengths. The npm
|
||||
snapshot length is reported and not decoded, and the executable is not run. See
|
||||
[Deno compile executables](https://github.com/morluto/rea/blob/main/docs/deno-standalone.md).
|
||||
- Apple app plist, Interface Builder, asset catalog, or keyed archive resources:
|
||||
`open_bundle_resources`, then the selected resource tool. This does not
|
||||
require `CFBundleExecutable` or a deep provider. Resource sessions have no
|
||||
executable digest or binary snapshot; use `open_binary` for native code.
|
||||
- Android APK code, classes, methods, or incoming references:
|
||||
`inspect_android_package`, then focused Android tools when advertised.
|
||||
Archive member inventory still uses the archive route above.
|
||||
- Managed PE/CLI assembly: `inspect_managed_artifact`.
|
||||
- Firmware image: `inspect_firmware_regions` when advertised. Use
|
||||
`extract_firmware` when extraction is requested, with a caller-selected new
|
||||
absolute output directory. These tools use caller-supplied Binwalk/Unblob on
|
||||
Linux; see the [firmware guide](https://github.com/morluto/rea/blob/main/docs/guides/firmware/firmware-analysis.md).
|
||||
- ESP32-family app or bootloader image (`0xE9` magic): `inspect_artifact`
|
||||
without a provider; see the ESP section of `references/native-and-artifacts.md`.
|
||||
- .NET NativeAOT PE/ELF: native Ghidra analysis. Native code can yield pseudocode;
|
||||
consult the NativeAOT workflow in `references/native-and-artifacts.md` for
|
||||
optional metadata recovery and its supported host/layout boundary.
|
||||
- Native program behavior, live calls, instrumentation, or command-run effects:
|
||||
choose the matching [native runtime workflow](references/runtime-observation.md#native-runtime-questions).
|
||||
`open_binary` and `trace_native_values` establish static facts; they do not
|
||||
observe execution. Runtime tools have distinct launch, attach, mutation and
|
||||
cleanup effects, and do not require a preliminary static session unless their
|
||||
own contract says so.
|
||||
- User-owned browser page already open: `list_browser_targets`.
|
||||
- Passive traffic capture of a SPA: the default scope is the page's own origin,
|
||||
and data APIs usually live on another origin. Discover API origins from
|
||||
absolute URLs in loaded bundles or script text via JavaScript analysis tools
|
||||
(another passive capture without those origins still scopes to the page
|
||||
origin, and `completeness.excluded` counts lack URLs). Pass both the page
|
||||
origin and those API origins in `allowed_origins` — the list replaces the
|
||||
default scope — and read `completeness.excluded` before reporting that an
|
||||
API is absent. For long captures with body shapes, use
|
||||
`export_evidence_bundle` instead of expecting an inline result.
|
||||
- Browser action the agent must perform (click, type, navigate):
|
||||
`capture_browser_scenario` with declared actions. See
|
||||
[runtime observation](references/runtime-observation.md) for connect/launch
|
||||
and the focused follow-up browser tools.
|
||||
- Agent environment (AgentEnv bundle) of a web application: read
|
||||
[environments](references/environments.md) before recording; it records with
|
||||
`capture_browser_scenario` and writes the bundle with `export_environment_bundle`.
|
||||
- Task for a desktop application's exported environment, from a
|
||||
`capture-desktop-application` folder: read
|
||||
[desktop application tasks](references/environments.md#tasks-for-a-desktop-application-environment).
|
||||
- Environment of a Linux desktop app with a task, from a request such as
|
||||
"build me an Inkscape environment where the agent changes a poster's
|
||||
headline": read [desktop builds](references/desktop-build.md). You drive the
|
||||
app on a build computer from `start_build_computer`, then export and witness.
|
||||
- Fiddler Everywhere traffic or a native `.saz` capture: read the
|
||||
[Fiddler workflow](references/runtime-observation.md#fiddler-everywhere-traffic-debugging).
|
||||
Inspect saved SAZ with `inspect_web_network_capture` and `format: "saz"`;
|
||||
connect Everywhere's separate MCP server for live traffic.
|
||||
- Retained HAR/SAZ/native mitmproxy/aioquic qlog capture: `inspect_web_network_capture`. Select
|
||||
original record ordinals when useful; inspect producer fields and byte/number
|
||||
sidecars without fetching recorded URLs or claiming live attribution. HAR/SAZ/qlog
|
||||
old-generation heap is `REA_CAPTURE_DECODER_OLD_GENERATION_MIB` (default 192 MiB,
|
||||
floor 8, maximum 16384), set where REA starts. Host memory and `NODE_OPTIONS` do not
|
||||
raise it. See
|
||||
[historical captures](https://github.com/morluto/rea/blob/main/docs/guides/web/web-network-captures.md) for the exact upstream
|
||||
profile and credential exclusions. Qlog support starts with aioquic 1.5.0
|
||||
JSON 0.3; stream coverage and endpoint loss declarations do not recover bodies
|
||||
or establish network loss. Prefer detail summary, then kind qlog trace/stream
|
||||
pages; select one trace, stream ID and direction for contribution/range pages.
|
||||
Facts retain all-recorded-events-before-selection scope. Other qlog layouts
|
||||
and PCAP correlation are unsupported.
|
||||
- User-owned Electron runtime already open: `list_electron_targets`. Before an electron-main Inspector attempt, check packaged fuses with `inspect_electron_fuses`; disabled `EnableNodeCliInspectArguments` means the app ignores `--inspect`.
|
||||
- Shipped application exposure for a local `.app`, install directory, ASAR, or executable: `audit_release_exposure` / `rea audit-release-exposure`. Each check has a stable id, a status, and fixed remediation. Unknown and unassessed checks stay in the report. This does not establish that an application is secure. Credential-marker hits report the rule id and location only. See [release exposure](https://github.com/morluto/rea/blob/main/docs/release-exposure.md).
|
||||
- Packet-field discovery: `inspect_packet_fields` searches installed protocols
|
||||
and field names/types before choosing fields for `inspect_packet_capture`.
|
||||
Query/page the relevant records; registrations do not establish observed traffic.
|
||||
- Recorded packet captures: `inspect_packet_capture` with selected TShark fields,
|
||||
display filters and decode-as rules. Requires Linux, util-linux prlimit and
|
||||
TShark 4.x on an absolute `PATH` entry or via the optional absolute
|
||||
`REA_TSHARK_COMMAND` override; see
|
||||
[capture guide](https://github.com/morluto/rea/blob/main/docs/guides/data/packet-captures.md).
|
||||
Packet limits count input packets before filtering. Output defaults to 50 matching
|
||||
frames; use `match_offset` / `match_limit` for later pages, or explicit null
|
||||
limit for complete matching output. Preserve the source digest across pages.
|
||||
This does not perform live capture.
|
||||
For address/DNS/SNI/protocol summaries use `inspect_pcap_capture` with MCP
|
||||
detail summary, then retained kind pcap pages. Requires Wireshark 4.x tshark
|
||||
and capinfos, with Linux prlimit or Windows Job Objects; see
|
||||
[packet summaries](https://github.com/morluto/rea/blob/main/docs/guides/data/pcap-analysis.md).
|
||||
Select an exact DNS question for address pages; page exhaustion does not prove
|
||||
network completeness. This reads recordings and does not acquire traffic.
|
||||
- Decoder discovery: `inspect_signal_decoders` searches installed decoder IDs
|
||||
or selected decoder help, including channels and options. Query and page the
|
||||
relevant details before choosing settings; this does not scan hardware.
|
||||
- Recorded logic/signal traces: `decode_signal_recording` with explicit decoder,
|
||||
channel and protocol settings. On Linux with util-linux prlimit, supply sigrok-cli 0.7.2 through
|
||||
`REA_SIGROK_COMMAND`; see [recording guide](https://github.com/morluto/rea/blob/main/docs/guides/signals/signal-recordings.md).
|
||||
Output defaults to 50 literal lines; select annotation classes and page with
|
||||
`line_offset` / `line_limit`, or explicit null for all remaining output.
|
||||
Window counts are display lines, not annotations or samples. Preserve source digests across pages.
|
||||
This reads existing files; it does not acquire hardware signals.
|
||||
- Explicit local WebAssembly artifact: `inspect_wasm_artifact`. Supply WABT 1.0.42
|
||||
through `REA_WABT_BIN_DIRECTORY`; retain exact byte/tool identity and decoded WAT.
|
||||
Select JavaScript glue and candidate paths explicitly and preserve URL/path
|
||||
ambiguity. No implicit fetch or target execution; WAT is not original source.
|
||||
See the [WASM guide](https://github.com/morluto/rea/blob/main/docs/guides/wasm/wasm-artifacts.md).
|
||||
- Explicit local Android APK (or ZIP/AAB) signing: `inspect_apk_signature`.
|
||||
Prefer its summary or selected signer/digest/lineage page; retain complete
|
||||
Evidence and use `inspect_analysis_view` kind `apk-signature` for follow-ups.
|
||||
Reports which schemes are present (v1 JAR, v2, v3, v3.1), each signer's
|
||||
certificate SHA-256 fingerprint (v1 included, from its PKCS#7 block), v3 key-rotation lineage, source stamp, and
|
||||
whether each signed digest still matches the bytes (self-consistency). This
|
||||
is identity and integrity, not a trust or authenticity verdict.
|
||||
See the [APK signature guide](https://github.com/morluto/rea/blob/main/docs/apk-signature.md).
|
||||
- Explicit local EVM bytecode carrier: `inspect_evm_interface` with caller-selected
|
||||
`raw` or `hex` encoding. The owned worker deadline is `timeout_ms` (default
|
||||
30000 ms, range 1..2147483647, next call). Select byte, address-space and CPU
|
||||
allowances separately through `producer_limits`; tighter inherited OS limits
|
||||
remain enforced, and the 256 MiB worker heap is independent. Preserve
|
||||
carrier/decoded digests and treat selectors,
|
||||
argument strings and mutability as inferred candidates; this performs no chain
|
||||
lookup or target execution. For the complete inferred interface without hex or
|
||||
duplicate stdout, discover support and select `detail: "summary"`; complete
|
||||
Evidence stays retained under its original identity. Use the returned
|
||||
`parent_evidence_id` for exact function or `bytecode_hex`/stdout/stderr pages.
|
||||
Candidate coverage does not establish interface completeness. See the
|
||||
[EVM bytecode guide](https://github.com/morluto/rea/blob/main/docs/guides/evm/evm-bytecode.md).
|
||||
- Embedded Go compiler, module, build-setting metadata, or static `(ptr, len)`
|
||||
string literals: `inspect_go_binary` with the explicit local file (pass
|
||||
`include_string_literals: true` and optional `max_string_literals` for bounded
|
||||
inferred static string-header recovery, and page retained rows with
|
||||
`inspect_analysis_view` kind `go` collection `string_literals`). This built-in
|
||||
target-free inspection requires no Go installation or disassembler. Preserve
|
||||
raw module bytes and source ranges; absent metadata does not prove a binary is
|
||||
not Go, static string recovery excludes compiler-inlined stack or immediate
|
||||
strings, and unparsed text records remain explicit. See the
|
||||
[Go binary guide](https://github.com/morluto/rea/blob/main/docs/guides/native/go-binaries.md).
|
||||
- Embedded CUDA/HIP code objects: `inspect_gpu_code_objects`; inventory targets
|
||||
first, then decode selected payloads and query retained GPU Evidence.
|
||||
- Bundled GGUF or safetensors model declarations: `inspect_model_artifact`
|
||||
with the explicit local file. Default header hashing leaves full-file identity
|
||||
unknown; `hash: "full"` additionally reads all weights for SHA-256. MCP returns
|
||||
retained summaries; optional `view` selects one page in the initial call. Use
|
||||
`inspect_analysis_view` kind `model-artifact` for
|
||||
batched metadata keys, tensor names or type totals, selected fields and pages.
|
||||
Preserve header-scoped indices and array preview omissions; do not infer model
|
||||
behavior from declared architecture or tensor types. See the
|
||||
[model file guide](https://github.com/morluto/rea/blob/main/docs/model-artifacts.md).
|
||||
- Unity IL2CPP names, member owners and string literals from `global-metadata.dat`:
|
||||
`inspect_il2cpp_metadata` with the explicit local file; MCP defaults to compact
|
||||
counts. Query sections, images, types, methods, fields, properties, events,
|
||||
parameters or string_literals through `inspect_analysis_view`
|
||||
with the returned `parent_evidence_id`, using exact filters, batch indices and
|
||||
selected fields. Parameters accept `method_indices`, avoiding a scan of all
|
||||
parameter pages. Missing collections in historical Evidence remain unknown.
|
||||
Versions 24, 27, 29, 31 and 39; no Unity, IL2CPP
|
||||
binary or disassembler is run. Unrecognized magic (possibly encrypted) and
|
||||
other versions are unsupported. Optional matching `binary_path` enables static native addresses and type references; query `method_addresses` with indices or addresses/states, preserving every shared-body method and both artifact identities. Without a linked binary native counts remain unknown. Byte-pattern fallback is inferred; no runtime behavior or same-build pairing is proved. See the
|
||||
[IL2CPP metadata guide](https://github.com/morluto/rea/blob/main/docs/il2cpp-metadata.md).
|
||||
- Embedded cargo-auditable Rust dependency metadata: `inspect_rust_binary`
|
||||
with the explicit local ELF, PE, or thin Mach-O file. This built-in
|
||||
target-free inspection requires no Rust installation or disassembler. Preserve
|
||||
package order, dependency indices, and the section file range. A missing
|
||||
`.dep-v0` section is null metadata, not proof the binary has no dependencies.
|
||||
A rustc commit hash is an inference from a read-only `/rustc/<40-hex>/` path.
|
||||
For selected crates, use `view: {collection: "packages", names: [...],
|
||||
fields: ["name", "version", "source"]}` on the first call; explicitly include
|
||||
`dependencies` for direct index references. Use `detail: "summary"` for counts
|
||||
and ranges, or retained `inspect_analysis_view` Rust package/edge pages for
|
||||
subsequent filters. Keep the complete parent Evidence accessible; CLI compact
|
||||
delivery requires `--evidence_output`.
|
||||
See the
|
||||
[Rust binary guide](https://github.com/morluto/rea/blob/main/docs/rust-binaries.md).
|
||||
- PE Authenticode certificate table: `inspect_pe_certificates` with the explicit
|
||||
local PE32/PE32+ file. This built-in target-free inspection requires no
|
||||
Windows SDK. Preserve WIN_CERTIFICATE ranges, types, payload SHA-256, and
|
||||
PKCS#7 signer/X.509 identity fields, including `subject_key_identifier_hex`
|
||||
when the signer uses that form. A missing security directory is observed
|
||||
absence of that table, not proof the image is unsigned in every catalog sense.
|
||||
Signatures are not verified. See the
|
||||
[PE certificate guide](https://github.com/morluto/rea/blob/main/docs/pe-certificates.md).
|
||||
- PE import and delay-load tables: `inspect_pe_imports` with the explicit
|
||||
local PE32/PE32+ file. This built-in target-free inspection requires no
|
||||
Windows SDK. Preserve DLL names, named and ordinal functions, ILT/IAT RVAs,
|
||||
delay-load descriptors, and the pefile import hash of the standard import
|
||||
table. A missing import directory is observed absence of that table, not
|
||||
proof the image never imported APIs through another table. Bound snapshots
|
||||
and loaded IAT contents remain unobserved. See the
|
||||
[PE import guide](https://github.com/morluto/rea/blob/main/docs/pe-imports.md).
|
||||
- Windows Shell Link shortcuts: `inspect_windows_shortcut` with the explicit
|
||||
local `.lnk` file. This built-in target-free inspection requires no Windows
|
||||
SDK or COM. Preserve header flags and FILETIMEs, IDList items, LinkInfo
|
||||
volume and network names, StringData arguments and icon location, ExtraData
|
||||
signatures, and Tracker droid facts labelled derived. Unknown IDList items
|
||||
and ExtraData signatures stay raw with SHA-256. The target path is not
|
||||
resolved or executed. See the
|
||||
[Windows shortcut guide](https://github.com/morluto/rea/blob/main/docs/guides/native/windows-shortcut.md).
|
||||
- PE TLS callbacks and load configuration: `inspect_pe_load_config` with the
|
||||
explicit local PE32/PE32+ file. This built-in target-free inspection requires
|
||||
no Windows SDK. Preserve callback VAs as strings with their RVA, file offset
|
||||
and section, and the size-covered security cookie, SafeSEH, CFG,
|
||||
EH-continuation and XFG fields. Guard-flag mitigation claims are inferred
|
||||
linker declarations, not proof of enforcement. A missing directory is observed
|
||||
absence of that declaration. See the
|
||||
[PE load configuration guide](https://github.com/morluto/rea/blob/main/docs/pe-load-config.md).
|
||||
- ELF, PE, and Mach-O hardening: `inspect_binary_hardening` with the explicit
|
||||
local file. This built-in target-free inspection requires no pwntools or other
|
||||
host tool. One image per Mach-O slice. Each property is `enabled`, `disabled`,
|
||||
`partial`, `unknown`, or `not_applicable`, with the header field or import
|
||||
behind it. A missing stack-protector or fortify import is `unknown`, not
|
||||
proof the protection was omitted. Authenticode and Mach-O code signatures
|
||||
report presence, not validity. Hardened runtime stays unknown and names
|
||||
`inspect_signature`. The image is not executed. See the
|
||||
[binary hardening guide](https://github.com/morluto/rea/blob/main/docs/binary-hardening.md).
|
||||
- ELF note tables: `inspect_elf_notes` with the explicit local ELF32/ELF64
|
||||
file. This built-in target-free inspection requires no disassembler. Preserve
|
||||
PT_NOTE and SHT_NOTE ranges, owners, types, descriptor SHA-256, and GNU
|
||||
build-id or ABI-tag fields. A missing table is observed absence of those
|
||||
declarations, not proof the image never carried notes. See the
|
||||
[ELF notes guide](https://github.com/morluto/rea/blob/main/docs/elf-notes.md).
|
||||
- Code that runs before `main` or at exit in ELF or Mach-O:
|
||||
`inspect_native_initializers` with the explicit local file (and
|
||||
`architecture` for a universal Mach-O). This built-in inspection requires no
|
||||
disassembler. Preserve slot and target addresses, the `resolution` of each
|
||||
entry, and its limitations. An `unresolved` slot is not a zero pointer, and a
|
||||
missing table is not proof that no constructor exists. See the
|
||||
[initializer guide](https://github.com/morluto/rea/blob/main/docs/guides/native/native-initializers.md).
|
||||
|
||||
- ELF unwind function ranges: `inspect_elf_unwind_ranges` with the explicit
|
||||
local ELF32/ELF64 file. This built-in target-free inspection requires no
|
||||
disassembler. Preserve FDE start, end, size, containing section, exact
|
||||
symbol name, CIE index, LSDA, and personality. Page with `offset` and
|
||||
`limit`. A missing `.eh_frame` is observed absence of that declaration,
|
||||
not proof the image has no functions. `.debug_frame` is reported present
|
||||
or absent and is not decoded. CFA instructions are counted and not
|
||||
evaluated. See the
|
||||
[ELF unwind ranges guide](https://github.com/morluto/rea/blob/main/docs/guides/native/elf-unwind-ranges.md).
|
||||
- Apple `.ips` crash reports: `inspect_apple_ips` with the explicit local
|
||||
file. This built-in target-free inspection requires no Xcode, atos, or
|
||||
pwntools. Preserve first-line metadata, `bug_type` as a string, process and
|
||||
exception facts, lossless integer registers, usedImages UUIDs, and
|
||||
documented classification matches. Only `bug_type` `"309"` yields a crash
|
||||
body; other types, including `"288"` stackshots, return no crash result.
|
||||
Select an optional `join_path` for UUID-and-architecture matching to one
|
||||
local Mach-O or dSYM; preserve slice identity and unjoined reasons. Joined
|
||||
static addresses do not resolve function names or dSYM symbols. See the
|
||||
[Apple IPS guide](https://github.com/morluto/rea/blob/main/docs/apple-ips.md).
|
||||
- Linux kernel module metadata: `inspect_kernel_module` with the explicit local
|
||||
ELF32/ELF64 relocatable file. This built-in target-free inspection requires
|
||||
no Linux host or `modinfo`. Preserve `.modinfo` key order and duplicate keys,
|
||||
`__versions` CRC hex, section file ranges, and the appended signature
|
||||
trailer's PKCS#7 SHA-256. A missing section is observed absence when section
|
||||
names are known, not proof the module never carried that metadata.
|
||||
`struct module` is not decoded. The signature is not validated. gzip, xz, and
|
||||
zstd containers are unsupported; decompress into a separate file with an
|
||||
external codec utility, then inspect the decompressed `ET_REL` image. See the
|
||||
[kernel module guide](https://github.com/morluto/rea/blob/main/docs/kernel-modules.md).
|
||||
- Linux kernel version and build config (`CONFIG_*` options such as
|
||||
`CONFIG_SECURITY_SELINUX`): `inspect_kernel_build_config` with the explicit
|
||||
local `vmlinux`, raw `Image`, x86 `bzImage`, or `configs.ko`. This built-in
|
||||
target-free inspection requires no Linux host or `extract-ikconfig`. Preserve
|
||||
the banner version, config SHA-256, option count, and value kinds; use `name`
|
||||
for one option. An `IKCFG_ST` string is a config only with a valid gzip member
|
||||
and `IKCFG_ED`. An absent config may mean the kernel was built without
|
||||
`CONFIG_IKCONFIG`. Non-gzip payloads are unsupported; decompress externally,
|
||||
then inspect the result. See the
|
||||
[kernel build config guide](https://github.com/morluto/rea/blob/main/docs/guides/native/kernel-build-config.md).
|
||||
- CPython 3.7–3.13 `.pyc` header, nested marshal code objects and bytecode
|
||||
identity: `inspect_python_pyc` with the explicit local file. This built-in
|
||||
target-free inspection requires no Python installation. Preserve magic,
|
||||
PEP 552 hash or mtime/size, nested names, and bytecode SHA-256. Bytecode is
|
||||
not decompiled, and a decoded header does not prove the matching `.py` is
|
||||
present. See the
|
||||
[CPython pyc guide](https://github.com/morluto/rea/blob/main/docs/python-pyc.md).
|
||||
- Erlang BEAM IFF container: `inspect_erlang_beam` with the explicit local
|
||||
`.beam` file. This built-in target-free inspection requires no Erlang
|
||||
installation. Preserve chunk names, atom order, export/import/lambda tables,
|
||||
and the Code header. For selected facts, prefer `detail: "summary"` plus a
|
||||
`beam` view (collection, names/indices, fields and paging), retaining the full
|
||||
Evidence. CLI summary requires `--evidence_output`. Missing table counts stay
|
||||
null; decoded empty tables count zero. Bytecode is not executed. See the
|
||||
[Erlang BEAM guide](https://github.com/morluto/rea/blob/main/docs/erlang-beam.md).
|
||||
|
||||
- Explicit local SQLite database snapshot: `inspect_sqlite_database`. Inspect
|
||||
with Node.js 24.x >=24.15 or 26+ providing native SQLite limits. Read schema
|
||||
first (compact inventory by default), or select an exact ordinary table
|
||||
and `columns` when rows are needed. Defaults are selected-table schema and
|
||||
20 rows; request `schema_scope: "database"` for the complete stored schema. Preserve both database and existing sibling WAL identity; row samples
|
||||
report truncation and have unspecified order. Use a quiescent snapshot rather
|
||||
than assuming a live database/WAL pair was copied atomically. See the
|
||||
[SQLite guide](https://github.com/morluto/rea/blob/main/docs/guides/data/sqlite-databases.md).
|
||||
- Explicit Linux ELF file for offline layout, symbols, relocations or static
|
||||
mitigation evidence: `inspect_binary_layout`. This target-free operation uses
|
||||
caller-supplied pwntools without opening a disassembler database. Preserve its
|
||||
raw locations and inference/coverage limits; see the
|
||||
[offline binary guide](https://github.com/morluto/rea/blob/main/docs/guides/native/binary-diagnostics.md).
|
||||
- Supplied Linux x86-64 ELF core: `inspect_recorded_crash`. Read every recorded
|
||||
thread, raw note and source-bound register without opening a live target.
|
||||
Historical PIDs do not select live processes. Request `include_debugger_context`
|
||||
only when core-only mapping candidates help; see the
|
||||
[recorded crash guide](https://github.com/morluto/rea/blob/main/docs/guides/native/recorded-crashes.md).
|
||||
- PE resource type/name/language trees and static icon group references:
|
||||
`inspect_pe_resources` with an explicit path. This portable operation requires
|
||||
no active target or engine; opaque payloads retain file ranges and SHA-256.
|
||||
- PE export directories and ELF dynamic-symbol exports: `inspect_native_exports`
|
||||
with an explicit path; portable, no active target or engine.
|
||||
- Native executable, library, or analysis database: `open_binary`, then
|
||||
use focused analysis tools directly; call `binary_overview` when metadata or
|
||||
inventory context is useful and available from the selected provider.
|
||||
|
||||
For an existing IDA MCP configuration, use `open_binary` with the original
|
||||
input binary and `provider_id: "ida"`; do not pass an `.idb` or `.i64` database.
|
||||
The legacy attached profile binds the already-open GUI input by SHA-256 and
|
||||
leaves its database open. The modern headless profile creates and closes an
|
||||
owned private database without saving. Installation and registration reuse
|
||||
[mrexodia/ida-pro-mcp](https://github.com/mrexodia/ida-pro-mcp); see the
|
||||
[IDA provider guide](https://github.com/morluto/rea/blob/main/docs/providers/ida-provider.md).
|
||||
For migration to the separate native IDA MCP plugin, follow the guide's
|
||||
[legacy attached migration](https://github.com/morluto/rea/blob/main/docs/providers/ida-provider.md#migrate-a-legacy-attached-registration).
|
||||
Replace the upstream registration explicitly; modern mrexodia tools are not the
|
||||
native profile. Native attachment preserves the database but does not provide
|
||||
direct callers; check session availability and the guide's verification limits.
|
||||
Proceed directly to `analyze_function`, pseudocode, or function/string searches
|
||||
after opening; IDA does not supply `binary_overview`. Consult session availability
|
||||
when composing broader workflows. Modern direct callers and unsupported dossier
|
||||
facets remain unknown; live IDA results are not replayed from snapshots.
|
||||
|
||||
With `REA_KUNA_COMMAND` configured, `provider_id: "kuna"` answers procedure
|
||||
lists, lookups, pseudocode, assembly and `analyze_function` from Kuna's cached
|
||||
whole-program export. Callers/callees use a separate body-free graph shared by
|
||||
the session; `xrefs` returns exact-address incoming sites and filters forwarding
|
||||
aliases. These queries and inventory lookups do not trigger a C export. Indirect
|
||||
targets remain unknown and can make relationship coverage partial. Reference
|
||||
caches expire on close; a fresh CLI process repeats the native reference walk.
|
||||
Typed references, CFG, raw-memory tools and annotations remain unsupported. A cold first
|
||||
answer can come from a single-function run (its limitations say so); assembly
|
||||
waits for the export. For pseudocode and assembly, `raw_result.source` names the
|
||||
cached `.c`/`.asm` file and byte span, which you may search directly instead of
|
||||
calling per function. See the
|
||||
[Kuna provider guide](https://github.com/morluto/rea/blob/main/docs/kuna-provider.md).
|
||||
|
||||
If the user says only "my app" without a name, path, or target already selected
|
||||
for this task, ask which app before searching for artifacts. Paths in unrelated
|
||||
saved reports and nearby test fixtures do not select the user's target. Resolve
|
||||
an actual human-readable app name to one clear installed artifact when possible;
|
||||
ask when matches are ambiguous. Never choose an example app on the user's behalf.
|
||||
|
||||
In a target-free session, use `open_binary` to bind any archive/package or
|
||||
native target whose analysis tool operates on the active target. Do not call an
|
||||
unadvertised tool; inspect `binary_session` with `{}` and its
|
||||
`result.tool_availability` for availability reasons and remediation. Expand each
|
||||
group's `names` into entries, inheriting the inventory-level client requirements
|
||||
unless the group overrides them. The grouped name union is the complete tool
|
||||
inventory; use `tools/list` for canonical tool schemas. The default summary keeps
|
||||
each provider candidate's availability and target-support status, code and
|
||||
reason; `omitted_fields` lists what it leaves out. Request `{"detail": "complete"}`
|
||||
only when you need an unavailable candidate's remediation, provider
|
||||
diagnostics, candidate capability sets, or tool surface, effect and annotation
|
||||
flags; in those closed flag vocabularies, listed
|
||||
flags are true and omitted known flags are false. Provider candidate facts
|
||||
describe possible providers, while top-level session capabilities describe the
|
||||
current route and `analysis_provider_binding` names the selected provider. Do
|
||||
not treat those scopes as interchangeable.
|
||||
|
||||
For editable Ghidra analysis that must survive a later agent process, select
|
||||
the [owned Program checkpoint workflow](references/native-and-artifacts.md#continue-editable-ghidra-analysis-across-processes)
|
||||
before making metadata edits. It is separate from Evidence/Unknown persistence.
|
||||
|
||||
For a Ghidra startup timeout on a large native target, follow
|
||||
[deadline recovery](references/native-and-artifacts.md#ghidra-startup-deadline-recovery)
|
||||
before abandoning deep analysis or repeating the same cold import. The default
|
||||
330 seconds can be changed for new startup attempts through
|
||||
`update_analysis_settings` using `ghidra.startup_timeout_ms`. Changing the
|
||||
server's launch environment instead requires a new REA process.
|
||||
If a needed tool is unadvertised, inspect `binary_session {}` and
|
||||
`result.tool_availability` for availability reasons/remediation; never call an
|
||||
unadvertised tool. Expand group `names`, inheriting inventory client requirements
|
||||
unless overridden. Their union is the complete in-scope inventory; `tools/list`
|
||||
owns canonical schemas. The default summary keeps provider candidate status,
|
||||
code and reason; `omitted_fields` names exclusions. Request `detail: "complete"`
|
||||
only for remediation/diagnostics, candidate capabilities or tool effect flags.
|
||||
Candidate facts describe possible providers; top-level capabilities and
|
||||
`analysis_provider_binding` describe the current route. Keep those scopes distinct.
|
||||
|
||||
## Work summary-first
|
||||
|
||||
Start with the default result and use its inline Evidence and graph context.
|
||||
For a JavaScript application or ELF layout whose size is unknown or large,
|
||||
call `analyze_javascript_application` or `inspect_binary_layout` with
|
||||
`"detail": "summary"`, then inspect the retained `parent_evidence_id` with
|
||||
`inspect_analysis_view`. Over MCP, `analyze_function` is summary-first without
|
||||
a flag: its default reply is the summary, and the complete dossier stays
|
||||
retained under `parent_evidence_id` for facet paging. Pass that ID as a
|
||||
`retained-evidence` reference to `compare_functions`, or inside
|
||||
`match_native_functions` `left_observations`/`right_observations` or
|
||||
`build_call_path.functions`; request `"detail": "complete"` only when the
|
||||
dossier must travel inline.
|
||||
Use the same exact-reference form in other advertised logical Evidence inputs,
|
||||
including optional sources, arrays and nested sources across domains. Each
|
||||
source can independently be inline or retained; preserve its source identity,
|
||||
coverage, partial facts and unknowns. A summary or inspection page has its own
|
||||
Evidence ID: use `normalized_result.parent_evidence_id` when the consumer needs
|
||||
the complete source. For portable CLI follow-ups, commands advertising
|
||||
`--evidence-bundle` resolve references from that selected exported bundle.
|
||||
See [Evidence composition](references/evidence-workflows.md) for scope and
|
||||
recovery; file selectors are supported only where explicitly advertised.
|
||||
Page module identities and select the returned `node_id` before requesting an
|
||||
item; a single file path can represent several graph roles. Do not repeat an
|
||||
identical analysis or rejected call without a changed input or resolved blocker.
|
||||
Recheck session state when a lifecycle change makes that status useful.
|
||||
Make a focused follow-up only when the
|
||||
returned result leaves a specific question unanswered.
|
||||
Start with inline Evidence and graph context. For unknown/large JavaScript or ELF
|
||||
layout, select advertised `detail: "summary"`; MCP `analyze_function` already
|
||||
defaults to a summary. Small complete results can cost less than extra pages.
|
||||
Make a focused follow-up only for a specific unanswered question. Reuse matching
|
||||
session state and Evidence instead of repeating analysis; recheck state when a
|
||||
lifecycle change makes it useful.
|
||||
|
||||
If MCP reports `resource_constraint` with `details.resource: "transport"`, call
|
||||
`inspect_analysis_view` with its reported same-session Evidence reference for a
|
||||
summary, one section/module, or a stable page. Use `trace_application_feature`
|
||||
once a seed is known, or call `export_evidence_bundle` to write the complete
|
||||
session to a selected path. The analysis remains complete in the ledger; avoid
|
||||
repeating it merely to request the same oversized response. Complete CLI JSON
|
||||
output also streams without a single MCP frame.
|
||||
Complete source Evidence stays accessible through advertised retained references.
|
||||
A summary/page has its own Evidence ID; use `normalized_result.parent_evidence_id`
|
||||
when a consumer needs the complete source. Pass `{kind: "retained-evidence",
|
||||
evidence_id}` in inputs advertising that form; do not resend complete records.
|
||||
Sources may independently be inline or retained. Read the Evidence guide for
|
||||
exact filters, bundle-based CLI reuse, comparison roles and missing-source recovery.
|
||||
|
||||
When the retained parent ID is unknown, use `get_evidence_bundle` with
|
||||
`detail: "summary"` and exact filters for operation, target SHA-256,
|
||||
analysis-profile digest or canonical procedure address. Select its returned
|
||||
Evidence ID for the next view instead of requesting the complete bundle. When
|
||||
that record has no supported view (for example an annotation), read it with
|
||||
`detail: "records"` and an `evidence_id` filter; `missing_evidence_links`
|
||||
names linked sources this session does not retain.
|
||||
`retention: "complete-record"` means the whole record is stored; native
|
||||
value-flow truncation and unknown metadata remain separate. For an exported
|
||||
portable bundle, use `rea inspect-evidence-bundle` with JSON containing `path`,
|
||||
`detail: "summary"` and the same `filters`. Reading that file still requires
|
||||
validating its full contents within the local memory budget.
|
||||
For REA transport refusal or client-truncated output, inspect a smaller retained
|
||||
view or export complete Evidence. Do not parse a preview as canonical JSON or
|
||||
repeat the producer. Never invent an Evidence ID; if unknown, find it with
|
||||
`get_evidence_bundle` summary filters. Retention is bounded and session-local;
|
||||
it does not establish automatic persistence or complete source coverage.
|
||||
|
||||
A client can also truncate a successful tool result without a REA transport
|
||||
error. Treat that preview as incomplete; use the retained parent ID for smaller
|
||||
views or export when the full record is needed. Do not parse the preview as
|
||||
canonical JSON or repeat the producer. For JavaScript, read the
|
||||
[module-view and trace recipes](references/javascript-applications.md) before
|
||||
drilling into a large graph; a broad bidirectional trace can expand unrelated
|
||||
containment relationships even after summary analysis.
|
||||
|
||||
Every conclusion must distinguish observations, inferences, and unknowns. Cite
|
||||
Evidence IDs, preserve limitations and incomplete coverage, and never imply
|
||||
that static analysis observed execution. Runtime requests execute the declared
|
||||
target and lifecycle; do not broaden the target or action beyond those fields.
|
||||
|
||||
Within the user's requested investigation, call available analysis tools
|
||||
directly. REA does not require permission grants or per-call approval flags.
|
||||
The agent client can independently require approval. Follow the declared request
|
||||
scope and the host's actual access requirements; use the recovery guide for an
|
||||
observed client-policy rejection.
|
||||
|
||||
## Plan broader investigations
|
||||
|
||||
For requests that span multiple features or subsystems, use a staged workflow:
|
||||
|
||||
1. Turn the request into a checklist of questions and the evidence each answer
|
||||
needs. Resolve target identity and constraints from the conversation and
|
||||
workspace before asking for information again.
|
||||
2. Inspect the current REA session, artifact identity, saved analysis database,
|
||||
bookmarks, and prior evidence. Reuse matching state; do not open duplicate
|
||||
sessions or repeat identical analysis.
|
||||
3. Start with the smallest useful overview or inventory. Follow each question
|
||||
from its entry point through relevant data and state changes to its result.
|
||||
Batch related operations around a specific hypothesis, then expand only when
|
||||
the returned evidence leaves a concrete gap.
|
||||
4. Inspect relevant packaged resources and configuration alongside code when
|
||||
they affect the question. Use format-aware inventory and parsers; do not
|
||||
infer behavior from filenames, strings, or layout alone.
|
||||
5. Corroborate a conclusion with the evidence type it requires. Use runtime
|
||||
observation only when static evidence cannot answer the question and the
|
||||
required host runtime and OS access are available. For JavaScript behavior,
|
||||
run probes against the actual app through the available browser, Electron,
|
||||
or process capture workflow.
|
||||
6. Decompose work into independent questions. When parallel workers are
|
||||
available and the questions do not depend on one another, assign distinct
|
||||
scopes, point workers to existing evidence, and ask them to return sources,
|
||||
conclusions, and unresolved gaps. Otherwise, work sequentially.
|
||||
7. Keep a concise finding ledger linking each conclusion to Evidence IDs,
|
||||
confidence/evidence type, search boundary, and remaining unknowns. Update
|
||||
the shared index or investigation report so later passes can reuse results.
|
||||
|
||||
Before finishing, revisit the original checklist. Mark each question as
|
||||
answered, partially answered, or unresolved based on its evidence; keep
|
||||
bounded negative searches bounded, and do not describe a broad investigation
|
||||
as complete while required questions remain open.
|
||||
|
||||
## Read only the relevant guide
|
||||
|
||||
- Native binaries, managed assemblies, archives, and extraction:
|
||||
[references/native-and-artifacts.md](references/native-and-artifacts.md)
|
||||
- ASARs, extracted JavaScript, feature tracing, and version comparison:
|
||||
[references/javascript-applications.md](references/javascript-applications.md)
|
||||
- Android APK declarations, classes, methods, and static references:
|
||||
[references/android-applications.md](references/android-applications.md)
|
||||
- Native instrumentation, debugger and process capture; browser/Electron
|
||||
observation; static/runtime comparison:
|
||||
[references/runtime-observation.md](references/runtime-observation.md)
|
||||
- Evidence paging, comparisons, residual unknowns, and verification:
|
||||
[references/evidence-workflows.md](references/evidence-workflows.md)
|
||||
- Agent environments (AgentEnv bundles) of a web application, recorded from
|
||||
a live instance or a HAR:
|
||||
[references/environments.md](references/environments.md)
|
||||
- Tasks for a desktop application's exported environment:
|
||||
[references/environments.md](references/environments.md#tasks-for-a-desktop-application-environment)
|
||||
- A desktop app environment from a request, built and witnessed on build
|
||||
computers: [references/desktop-build.md](references/desktop-build.md)
|
||||
For broad investigations, read the Evidence guide's staged workflow. Track the
|
||||
questions, source boundaries and unresolved gaps; do not claim completion while
|
||||
required questions remain open. Inspect packaged resources alongside code when
|
||||
relevant, and use runtime evidence only within the requested scope.
|
||||
|
||||
## Finish the task
|
||||
|
||||
Explain findings in plain language and tie them to returned evidence. When the
|
||||
user asks to build something, use normal coding tools and separate observed
|
||||
behavior from design choices. Close an opened native session with
|
||||
`close_binary` when its engine is no longer needed. Evidence references and Unknown
|
||||
history remain in memory on the same MCP connection. End the investigation with
|
||||
`reset_investigation`; supply `save_path` to checkpoint the complete bundle before
|
||||
clearing. Import the saved bundle to restore original references and Unknown
|
||||
history in a new process. Retention is bounded and is not automatic persistence.
|
||||
Explain findings in plain language and tie them to returned Evidence. For builds,
|
||||
use normal coding tools and separate observed behavior from design choices.
|
||||
Close an opened native/resource session with `close_binary` when no longer needed.
|
||||
Evidence references and Unknown history remain on the same MCP connection.
|
||||
End with `reset_investigation`; use `save_path` to checkpoint the complete bundle
|
||||
before clearing. Import that bundle, including its source closure, to restore
|
||||
original references and Unknown history in a new process. Editable Ghidra Program
|
||||
checkpoints are separate; read that workflow before edits needing persistence.
|
||||
+32
-1
@@ -1,11 +1,23 @@
|
||||
# Connection and task recovery
|
||||
|
||||
Read only the sections needed for the selected task.
|
||||
|
||||
- [Choose the remedy from the observed failure](#choose-the-remedy-from-the-observed-failure)
|
||||
- [Distinguish client and server deadlines](#distinguish-client-and-server-deadlines)
|
||||
- [Recovery ladder](#recovery-ladder)
|
||||
- [REA installed as a client plugin](#rea-installed-as-a-client-plugin)
|
||||
- [Repair registration when needed](#repair-registration-when-needed)
|
||||
- [Codex tool approval is separate from REA readiness](#codex-tool-approval-is-separate-from-rea-readiness)
|
||||
- [Repair an editable REA limit](#repair-an-editable-rea-limit)
|
||||
- [Continue through an installed CLI](#continue-through-an-installed-cli)
|
||||
|
||||
Read this guide only for an observed connection, command, approval or provider
|
||||
blocker. Keep the user's target and question in view. Explain what prevented the
|
||||
operation and the next useful step; after repair, continue the investigation.
|
||||
|
||||
Commands below use an installed `rea`. If none is available, use the package
|
||||
invocation in `SKILL.md` when acquiring REA is authorized. Follow the connected
|
||||
invocation under [Continue through an installed CLI](#continue-through-an-installed-cli)
|
||||
when acquiring REA is authorized. Follow the connected
|
||||
server's schemas and the installed CLI's help rather than assuming repository
|
||||
main and an older release expose the same arguments. Tool-name prefixes belong
|
||||
to the client: find the canonical REA operation in its actual tool listing and
|
||||
@@ -222,6 +234,25 @@ not edit host deadlines, response buffers, registrations or fixed limits.
|
||||
|
||||
## Continue through an installed CLI
|
||||
|
||||
A concrete CLI fallback for an operator-supplied JavaScript tree or ASAR is:
|
||||
|
||||
```bash
|
||||
npx -y rea-agents@latest analyze-javascript-application /absolute/path/to/app --json
|
||||
```
|
||||
|
||||
No MCP registration or native engine is required. Read the returned Evidence,
|
||||
graph, limitations, and unknowns with the same care as an MCP result; the CLI
|
||||
returns the Evidence record directly. This fallback does not establish that
|
||||
MCP is configured. Native CLI tasks still require their selected engine.
|
||||
Prefer an existing `rea` CLI. When none is installed and REA package acquisition
|
||||
is within the authorized scope, use `npx -y rea-agents@latest` in its place from a
|
||||
trusted directory outside the target project, with absolute target paths. Managed
|
||||
setup binds the current installation directly; retain its runtime and package
|
||||
cache entry, or restore that installation before repairing its registration.
|
||||
For setup-owned registration, configuration repair starts with a read-only setup plan; show paths, backups and
|
||||
skill replacement before applying authorized changes. Preserve existing approval
|
||||
and target-execution boundaries.
|
||||
|
||||
Check the command environment only if the launcher fails:
|
||||
|
||||
```bash
|
||||
|
||||
@@ -1,5 +1,13 @@
|
||||
# Agent environments from a live application
|
||||
|
||||
Read only the sections needed for the selected task.
|
||||
|
||||
- [Before recording](#before-recording)
|
||||
- [Record a session an environment can learn writes from](#record-a-session-an-environment-can-learn-writes-from)
|
||||
- [Check coverage](#check-coverage)
|
||||
- [Export and hand off](#export-and-hand-off)
|
||||
- [Tasks for a desktop application environment](#tasks-for-a-desktop-application-environment)
|
||||
|
||||
Use this when the user asks for an agent environment (an AgentEnv bundle) of a
|
||||
web application: a folder `agent-env` deploys, whose MCP tools answer from what
|
||||
one recording of the application observed and serve the writes that recording
|
||||
|
||||
@@ -1,7 +1,25 @@
|
||||
# Evidence, comparison, and verification workflows
|
||||
|
||||
Evidence-producing tools return the complete Evidence record directly in MCP
|
||||
`structuredContent` and CLI JSON. Read `normalized_result` for operation data,
|
||||
Read only the sections needed for the selected task.
|
||||
|
||||
- [Read and compose source Evidence](#read-and-compose-source-evidence)
|
||||
- [Inventory and decompilation views](#inventory-and-decompilation-views)
|
||||
- [Unknowns and comparisons](#unknowns-and-comparisons)
|
||||
- [Process captures and environment views](#process-captures-and-environment-views)
|
||||
- [Native export table pages](#native-export-table-pages)
|
||||
- [Recover oversized delivery and find retained Evidence](#recover-oversized-delivery-and-find-retained-evidence)
|
||||
- [Plan broader investigations](#plan-broader-investigations)
|
||||
|
||||
## Read and compose source Evidence
|
||||
|
||||
Evidence-producing MCP tools return Evidence directly in `structuredContent`.
|
||||
CLI complete JSON returns Evidence directly. CLI summary delivery through
|
||||
`--evidence_output` returns `{summary, evidence_bundle}`: `summary` is the view's
|
||||
Evidence, and `evidence_bundle` is the export receipt with its path and byte count.
|
||||
Read `summary.normalized_result.parent_evidence_id` for the complete source ID;
|
||||
pass the receipt's path to `--evidence-bundle` on a later supported CLI command.
|
||||
Advertised summary delivery retains the complete source separately;
|
||||
complete inline delivery is available where the connected contract says so. Read `normalized_result` for operation data,
|
||||
and cite `evidence_id` when another tool or your explanation needs a stable
|
||||
reference. Preserve authority, limitations, coverage, and residual unknowns. If a result
|
||||
is incomplete or paginated, continue only when the remaining data matters to
|
||||
@@ -49,6 +67,8 @@ An input bundle grants no implicit file lookup: `evidence-file` and historical
|
||||
graph file selectors are accepted only by contracts advertising them. See the
|
||||
[CLI reuse guide](https://github.com/morluto/rea/blob/main/docs/getting-started/cli.md#import-export-and-compare-evidence).
|
||||
|
||||
## Inventory and decompilation views
|
||||
|
||||
Completed `inspect_artifact` inventory also supports a summary and
|
||||
`view: {kind: "inventory", collection: "occurrences", logical_paths: ["package.json", "main.js"]}`.
|
||||
Omit `logical_paths` to page all available occurrences; `[]` selects none.
|
||||
@@ -81,6 +101,8 @@ exact `where.indices`, `addresses`, `procedure_addresses` or `statuses`. Add
|
||||
`collection: "pseudocode"` with one row's `index` to page a large body. Batch
|
||||
limitations aggregate every item, so do not attribute them to one successful row.
|
||||
|
||||
## Unknowns and comparisons
|
||||
|
||||
Use `record_unknown` to track unresolved questions in the user's investigation
|
||||
and name the authority or environment still required. Supply supporting and
|
||||
contradicting evidence IDs. It updates the session registry directly.
|
||||
@@ -111,6 +133,8 @@ or absence:
|
||||
- `verify_reconstruction` evaluates a finite typed specification. A pass covers
|
||||
only declared comparable claims, not global equivalence.
|
||||
|
||||
## Process captures and environment views
|
||||
|
||||
Process captures are opt-in behavioral evidence, not a security sandbox. V3
|
||||
captures cannot be upgraded to V4; rerun the original scenario. Distinguish root
|
||||
exit from descendant settlement and require freshness when the task needs it.
|
||||
@@ -164,6 +188,8 @@ catalog and state size checks. `rea environment-build <capture.har> <dir>`
|
||||
inspects, projects and exports in one step and prints the same coverage, or
|
||||
`null` when the bundle serves replay.
|
||||
|
||||
## Native export table pages
|
||||
|
||||
For a PE/ELF export question, `inspect_native_exports` accepts `detail: "summary"`
|
||||
and retains the complete table. Query `inspect_analysis_view` with
|
||||
`view: {kind: "native-exports", collection: "exports", names: ["selected_name"],
|
||||
@@ -174,3 +200,69 @@ coverage describes selected retained rows; `summary.coverage` or `exports.covera
|
||||
still describes the source table, so an empty partial page does not prove absence.
|
||||
CLI `inspect-native-exports --detail summary --evidence_output PATH` saves the
|
||||
complete bundle for later `inspect-analysis-view --evidence-bundle PATH` requests.
|
||||
|
||||
## Recover oversized delivery and find retained Evidence
|
||||
|
||||
If MCP reports `resource_constraint` with `details.resource: "transport"`, call
|
||||
`inspect_analysis_view` with its reported same-session Evidence reference for a
|
||||
summary, one section/module, or a stable page. Use `trace_application_feature`
|
||||
once a seed is known, or call `export_evidence_bundle` to write the complete
|
||||
session to a selected path. The analysis remains complete in the ledger; avoid
|
||||
repeating it merely to request the same oversized response. Complete CLI JSON
|
||||
output also streams without a single MCP frame.
|
||||
|
||||
When the retained parent ID is unknown, use `get_evidence_bundle` with
|
||||
`detail: "summary"` and exact filters for operation, target SHA-256,
|
||||
analysis-profile digest or canonical procedure address. Select its returned
|
||||
Evidence ID for the next view instead of requesting the complete bundle. When
|
||||
that record has no supported view (for example an annotation), read it with
|
||||
`detail: "records"` and an `evidence_id` filter; `missing_evidence_links`
|
||||
names linked sources this session does not retain.
|
||||
`retention: "complete-record"` means the whole record is stored; native
|
||||
value-flow truncation and unknown metadata remain separate. For an exported
|
||||
portable bundle, use `rea inspect-evidence-bundle` with JSON containing `path`,
|
||||
`detail: "summary"` and the same `filters`. Reading that file still requires
|
||||
validating its full contents within the local memory budget.
|
||||
|
||||
A client can also truncate a successful tool result without a REA transport
|
||||
error. Treat that preview as incomplete; use the retained parent ID for smaller
|
||||
views or export when the full record is needed. Do not parse the preview as
|
||||
canonical JSON or repeat the producer. For JavaScript, read the
|
||||
[module-view and trace recipes](javascript-applications.md) before
|
||||
drilling into a large graph; a broad bidirectional trace can expand unrelated
|
||||
containment relationships even after summary analysis.
|
||||
|
||||
## Plan broader investigations
|
||||
|
||||
For requests that span multiple features or subsystems, use a staged workflow:
|
||||
|
||||
1. Turn the request into a checklist of questions and the evidence each answer
|
||||
needs. Resolve target identity and constraints from the conversation and
|
||||
workspace before asking for information again.
|
||||
2. Inspect the current REA session, artifact identity, saved analysis database,
|
||||
bookmarks, and prior evidence. Reuse matching state; do not open duplicate
|
||||
sessions or repeat identical analysis.
|
||||
3. Start with the smallest useful overview or inventory. Follow each question
|
||||
from its entry point through relevant data and state changes to its result.
|
||||
Batch related operations around a specific hypothesis, then expand only when
|
||||
the returned evidence leaves a concrete gap.
|
||||
4. Inspect relevant packaged resources and configuration alongside code when
|
||||
they affect the question. Use format-aware inventory and parsers; do not
|
||||
infer behavior from filenames, strings, or layout alone.
|
||||
5. Corroborate a conclusion with the evidence type it requires. Use runtime
|
||||
observation only when static evidence cannot answer the question and the
|
||||
required host runtime and OS access are available. For JavaScript behavior,
|
||||
run probes against the actual app through the available browser, Electron,
|
||||
or process capture workflow.
|
||||
6. Decompose work into independent questions. When parallel workers are
|
||||
available and the questions do not depend on one another, assign distinct
|
||||
scopes, point workers to existing evidence, and ask them to return sources,
|
||||
conclusions, and unresolved gaps. Otherwise, work sequentially.
|
||||
7. Keep a concise finding ledger linking each conclusion to Evidence IDs,
|
||||
confidence/evidence type, search boundary, and remaining unknowns. Update
|
||||
the shared index or investigation report so later passes can reuse results.
|
||||
|
||||
Before finishing, revisit the original checklist. Mark each question as
|
||||
answered, partially answered, or unresolved based on its evidence; keep
|
||||
bounded negative searches bounded, and do not describe a broad investigation
|
||||
as complete while required questions remain open.
|
||||
@@ -0,0 +1,76 @@
|
||||
# Firmware and raw images
|
||||
|
||||
## Firmware regions and extraction
|
||||
|
||||
Use `inspect_firmware_regions` when advertised. Use `extract_firmware` when
|
||||
extraction is requested, with a caller-selected new absolute output directory.
|
||||
These tools use caller-supplied Binwalk/Unblob on Linux; see the
|
||||
[firmware guide](https://github.com/morluto/rea/blob/main/docs/guides/firmware/firmware-analysis.md).
|
||||
|
||||
## Headerless raw images and firmware containers
|
||||
|
||||
For other headerless images (embedded firmware without ELF/Mach-O/PE/MZ
|
||||
headers), open with `format: "raw-binary"`, `architecture` (`x86`, `x86_64`,
|
||||
`arm`, `arm64`, `6502`, or `m68k`), and `entry_point` (`0x` hex). File offset 0 is mapped at
|
||||
that address. Hopper and IDA refuse this interpretation; Ghidra uses
|
||||
`BinaryLoader` with a generic language: big-endian for `m68k`, little-endian
|
||||
otherwise. Big-endian ARM, Thumb-only, and Cortex-M variants are unsupported.
|
||||
`6502` selects NMOS 6502; the entry and complete file mapping must fit within
|
||||
`0x0000..0xffff`. 65C02, 65816, cartridge containers, bank switching, and mapper
|
||||
semantics are unsupported. `m68k` requires an even entry and decodes the 68040
|
||||
superset of the 68000 family; Amiga/Atari containers and vector-table entry
|
||||
discovery are unsupported. Windows Ghidra P0 admits raw images only for `6502`. See [raw binary guide](https://github.com/morluto/rea/blob/main/docs/providers/raw-binary.md).
|
||||
|
||||
Intel HEX, S-record, UF2 and DfuSe files are containers, not raw images:
|
||||
`inspect_artifact` lists address regions (UF2 per familyID, DfuSe per element
|
||||
with its alternate setting), and `extract_artifact` writes each region. Open an
|
||||
extracted region as `raw-binary` with its start address as `entry_point`. UF2
|
||||
numbering gaps leave coverage unknown; a DfuSe suffix CRC mismatch follows
|
||||
`integrity_policy`. See [UF2 and DfuSe](https://github.com/morluto/rea/blob/main/docs/uf2-dfuse.md).
|
||||
|
||||
## ESP images
|
||||
|
||||
For an ESP32-family app or bootloader image, `open_binary` then
|
||||
`inspect_artifact` with `detail: "summary"`. `root_format_metadata` holds the
|
||||
observed `header` and `descriptor` (its `kind` is the app or bootloader role)
|
||||
and the derived `chip`, `checksum`, `appended_sha256` and
|
||||
`undescribed_trailing` ranges. Segment rows (`segment-NN.bin`) carry
|
||||
`load_addr`, `classification` (`mapped`, `loaded`, `not-loaded` or `unknown`,
|
||||
per ESP-IDF `should_map`/`should_load`; RAM ranges are not checked) and
|
||||
`source_location`; select them with `inspect_analysis_view` and
|
||||
`logical_paths`. Signature blocks are `unverified`; `public_key_sha256`
|
||||
matches eFuse key digests.
|
||||
|
||||
Unknown `source_coverage` means truncation or undescribed trailing bytes, such
|
||||
as the flash segments of a `--ram-only-header` image; do not infer absence
|
||||
from it. Erased flash is described. Integrity mismatches are facts, not
|
||||
refusals. ESP8266 images are refused, and flash-encrypted images are not
|
||||
recognized. Segments are not disassembled, and RISC-V or Xtensa segments
|
||||
cannot be opened as raw-binary. See
|
||||
[ESP images](https://github.com/morluto/rea/blob/main/docs/esp-image.md).
|
||||
|
||||
## ESP flash images
|
||||
|
||||
A whole-flash dump opens as `esp-flash-image`. `root_format_metadata` holds
|
||||
`partition_table` (its `method`: `default`, `caller` or a derived
|
||||
`scan`), `bootloader` and `apps` ESP image facts, the `otadata` records,
|
||||
`partitions_outside_dump` and `boot_selection`. Every table has a
|
||||
`boot_selection`: its `basis` names the bootloader's branch (`no-otadata`
|
||||
without otadata, `none` when the bootloader rejects the table, `unknown`
|
||||
when a record is missing), and it lists its `assumptions`;
|
||||
`running_partition` is always `unknown`. Each image names its entry
|
||||
`path`. With `detail: "summary"` the root kind is `esp-flash-image-summary`
|
||||
and each image is a compact `summary` (chip, entry point, segment count,
|
||||
classified load ranges, signature block count, descriptor identity,
|
||||
integrity); complete detail keeps every segment. Partition rows
|
||||
(`partitions/<label>.bin`) carry the declared `type`, `subtype`, names,
|
||||
`flash_address`, `size` and flags; `encrypted` is a storage flag, not
|
||||
proof of ciphertext. `written_offset`/`written_end` bound the bytes that
|
||||
are not erased: an app slot whose facts say `erased` can still hold an older
|
||||
image, and a limitation says so. For a dump read from another flash address, call
|
||||
`open_binary` with `format: "esp-flash-image"` and `flash_offset`; an
|
||||
`esp-image` whose `flash_dump` is set names that offset in a next probe; a
|
||||
relocated table can be named with `partition_table_offset`. No table found
|
||||
means unknown, often flash encryption. Extraction writes `nvs_keys` as
|
||||
ordinary data. See
|
||||
[ESP flash images](https://github.com/morluto/rea/blob/main/docs/esp-flash-image.md).
|
||||
@@ -0,0 +1,449 @@
|
||||
# Offline format and metadata inspection
|
||||
|
||||
Read only the sections needed for the selected task.
|
||||
|
||||
- [Release exposure](#release-exposure)
|
||||
- [Go build metadata](#go-build-metadata)
|
||||
- [Model files](#model-files)
|
||||
- [IL2CPP metadata](#il2cpp-metadata)
|
||||
- [Rust dependency metadata](#rust-dependency-metadata)
|
||||
- [PE Authenticode certificate tables](#pe-authenticode-certificate-tables)
|
||||
- [PE import and delay-load tables](#pe-import-and-delay-load-tables)
|
||||
- [Windows Shell Link shortcuts](#windows-shell-link-shortcuts)
|
||||
- [PE TLS callbacks and load configuration](#pe-tls-callbacks-and-load-configuration)
|
||||
- [Binary hardening](#binary-hardening)
|
||||
- [ELF note tables](#elf-note-tables)
|
||||
- [ELF and Mach-O initializer functions](#elf-and-mach-o-initializer-functions)
|
||||
- [ELF unwind function ranges](#elf-unwind-function-ranges)
|
||||
- [Apple IPS crash reports](#apple-ips-crash-reports)
|
||||
- [Linux kernel modules](#linux-kernel-modules)
|
||||
- [Linux kernel build config](#linux-kernel-build-config)
|
||||
- [CPython pyc files](#cpython-pyc-files)
|
||||
- [Erlang BEAM files](#erlang-beam-files)
|
||||
- [SQLite snapshots](#sqlite-snapshots)
|
||||
- [Recorded Linux crashes](#recorded-linux-crashes)
|
||||
- [Offline ELF layout](#offline-elf-layout)
|
||||
- [Offline WASM](#offline-wasm)
|
||||
- [Offline APK signatures](#offline-apk-signatures)
|
||||
- [Offline PE resource inventory](#offline-pe-resource-inventory)
|
||||
- [Offline PE and ELF export tables](#offline-pe-and-elf-export-tables)
|
||||
- [EVM bytecode](#evm-bytecode)
|
||||
- [Embedded GPU code objects](#embedded-gpu-code-objects)
|
||||
|
||||
## Release exposure
|
||||
|
||||
Use `audit_release_exposure` (`rea audit-release-exposure PATH`) when the question is what static analysis of a shipped `.app`, install directory, ASAR, or executable recovers. Each check has a stable id, a status, the observation behind it, and fixed remediation. Unknown and unassessed checks stay in the report. The report does not establish that the application is secure.
|
||||
|
||||
`text.credential_markers` reports a rule id and location only. Matched bytes, previews, lengths, and hashes of matched bytes are omitted.
|
||||
|
||||
`native.hardening`, `macho.hardened_runtime`, and `android.manifest` are not assessed here. Their next probes are `inspect_binary_hardening`, `inspect_signature`, and `inspect_android_package`.
|
||||
|
||||
See [release exposure](https://github.com/morluto/rea/blob/main/docs/release-exposure.md).
|
||||
|
||||
## Go build metadata
|
||||
|
||||
Use `inspect_go_binary` for an explicit local ELF, PE or Mach-O (universal
|
||||
files need `architecture`) when the
|
||||
question concerns the embedded compiler version, module/dependency versions,
|
||||
local replacements, build settings, or static Go string literals packed without
|
||||
NUL terminators. Pass `include_string_literals: true`
|
||||
(`--include-string-literals`, optional `max_string_literals` /
|
||||
`--max-string-literals`) to recover bounded inferred word-aligned `(ptr, len)`
|
||||
UTF-8 string slices from read-only data and page them through `go`
|
||||
`string_literals` views. No `open_binary`, Go installation or
|
||||
target execution is required. The CLI equivalent is `inspect-go-binary PATH`.
|
||||
Preserve artifact SHA-256, original file ranges, framed module bytes and every
|
||||
unparsed module-text line. A missing record is an unknown, not proof of a
|
||||
non-Go binary; observed metadata does not authenticate its claims, and static
|
||||
`(ptr, len)` string recovery excludes compiler-inlined stack/immediate strings
|
||||
without proving runtime reachability. Function,
|
||||
source and type recovery remain a separate native-analysis question.
|
||||
|
||||
See the [Go binary guide](https://github.com/morluto/rea/blob/main/docs/guides/native/go-binaries.md).
|
||||
|
||||
## Model files
|
||||
|
||||
Optional `view` selects one page in the initial call. Batch metadata keys or
|
||||
tensor names and select only needed fields; do not infer model behavior from
|
||||
declared architecture or tensor types.
|
||||
|
||||
Use `inspect_model_artifact` (`inspect-model-artifact PATH`) for local GGUF v2/v3
|
||||
and safetensors declarations without a model runtime. Header-only mode does not
|
||||
read weights or establish full-file identity. `hash: "full"` explicitly streams
|
||||
all bytes. Retained `model-artifact` views page `metadata`, `tensors` and derived
|
||||
`types`, with exact batch filters and selected fields. Arrays retain typed counts
|
||||
and eight-element previews; omitted values, unknown types and runtime behavior
|
||||
stay explicit. See [model files](https://github.com/morluto/rea/blob/main/docs/model-artifacts.md).
|
||||
|
||||
## IL2CPP metadata
|
||||
|
||||
Use `inspect_il2cpp_metadata` for an explicit local Unity `global-metadata.dat`
|
||||
(versions 24, 27, 29, 31 and 39) when the question concerns assembly images,
|
||||
names, member owners, string literals, namespaces or index ranges. No `open_binary`, Unity installation or target
|
||||
execution is required. The CLI equivalent is `inspect-il2cpp-metadata PATH`.
|
||||
MCP defaults to counts with complete retained Evidence. Query `sections`,
|
||||
`images`, `types`, `methods`, `fields`, `properties`, `events`, `parameters` or
|
||||
`string_literals` through `inspect_analysis_view`; use exact names,
|
||||
batch indices and selected fields. Row indices are scoped by artifact SHA-256
|
||||
and collection; page offsets count filtered matches. Parameters support batch
|
||||
`method_indices` to read one method's parameters directly. Historical reports
|
||||
without member collections retain unknown counts rather than empty inventories. Preserve
|
||||
artifact SHA-256 and index widths. Unrecognized magic may mean encryption and
|
||||
is unsupported, not decrypted.
|
||||
|
||||
Optional matching `binary_path` enables static native addresses and type
|
||||
references. Query `method_addresses` with indices or addresses/states, preserving
|
||||
every shared-body method and both artifact identities. Without a linked binary,
|
||||
native counts remain unknown. Byte-pattern fallback is inferred; no runtime
|
||||
behavior or same-build pairing is proved.
|
||||
See [IL2CPP metadata](https://github.com/morluto/rea/blob/main/docs/il2cpp-metadata.md).
|
||||
|
||||
## Rust dependency metadata
|
||||
|
||||
For selected crates, use `view: {collection: "packages", names: [...],
|
||||
fields: ["name", "version", "source"]}` on the first call. Include `dependencies`
|
||||
explicitly for direct index references. Select `detail: "summary"` for counts and
|
||||
ranges; retained Rust package/edge views support later filters. Keep complete
|
||||
parent Evidence accessible; CLI compact delivery requires `--evidence_output`.
|
||||
|
||||
Use `inspect_rust_binary` for an explicit local ELF, PE, or Mach-O (universal
|
||||
files need `architecture`) when
|
||||
the question concerns the cargo-auditable crate list embedded in `.dep-v0`
|
||||
(Mach-O: `__DATA,.dep-v0`). No `open_binary`, Rust installation, or target
|
||||
execution is required. The CLI equivalent is `inspect-rust-binary PATH`.
|
||||
Preserve artifact SHA-256, package order, dependency indices, and the section
|
||||
file range. A missing section is null metadata, not proof the binary has no
|
||||
dependencies. An omitted package kind stays null. A rustc commit hash is
|
||||
inferred from a read-only `/rustc/<40-hex>/` path and does not by itself
|
||||
identify the compiler. See [Rust binaries](https://github.com/morluto/rea/blob/main/docs/rust-binaries.md).
|
||||
|
||||
## PE Authenticode certificate tables
|
||||
|
||||
Use `inspect_pe_certificates` for an explicit local PE32/PE32+ image when the
|
||||
question concerns the Authenticode certificate table, WIN_CERTIFICATE types, or
|
||||
embedded PKCS#7 signer and X.509 identity fields. No `open_binary`, Windows SDK,
|
||||
or target execution is required. The CLI equivalent is
|
||||
`inspect-pe-certificates PATH`. Preserve artifact SHA-256, table file ranges,
|
||||
payload hashes, original validity-time spellings, and
|
||||
`subject_key_identifier_hex` when the signer uses that form. A missing
|
||||
`IMAGE_DIRECTORY_ENTRY_SECURITY` directory is observed absence of that table,
|
||||
not proof the image is unsigned in every catalog or overlay sense. Signatures,
|
||||
chains, timestamps, and Authenticode digest coverage remain unobserved. See
|
||||
[PE Authenticode certificate tables](https://github.com/morluto/rea/blob/main/docs/pe-certificates.md).
|
||||
|
||||
## PE import and delay-load tables
|
||||
|
||||
Use `inspect_pe_imports` for an explicit local PE32/PE32+ image when the
|
||||
question concerns imported DLL and function names, ordinals, delay-load
|
||||
descriptors, or the pefile import hash. No `open_binary`, Windows SDK, or
|
||||
target execution is required. The CLI equivalent is `inspect-pe-imports PATH`.
|
||||
Preserve artifact SHA-256, directory file ranges, original DLL spellings, and
|
||||
ILT/IAT RVAs. A missing `IMAGE_DIRECTORY_ENTRY_IMPORT` directory is observed
|
||||
absence of that table, not proof the image never imported APIs through another
|
||||
table or overlay. Bound snapshots, loaded IAT contents, and export-forward
|
||||
resolution remain unobserved. See
|
||||
[PE import and delay-load tables](https://github.com/morluto/rea/blob/main/docs/pe-imports.md).
|
||||
|
||||
## Windows Shell Link shortcuts
|
||||
|
||||
Use `inspect_windows_shortcut` for an explicit local `.lnk` file when the
|
||||
question concerns the recorded target path, arguments, working directory, icon
|
||||
location, volume serial, network share names, ExtraData blocks, or Tracker
|
||||
droid identifiers. No `open_binary`, Windows SDK, COM, or target execution is
|
||||
required. The CLI equivalent is `inspect-windows-shortcut PATH`. Preserve
|
||||
artifact SHA-256, FILETIME raw decimals, IDList type bytes, and ExtraData
|
||||
signatures. Unknown IDList items and ExtraData signatures remain raw with
|
||||
SHA-256; they are not guessed. Version-1 UUID MAC and timestamp values are
|
||||
labelled derived. A missing optional section is observed absence of that
|
||||
structure. See
|
||||
[Windows Shell Link shortcuts](https://github.com/morluto/rea/blob/main/docs/guides/native/windows-shortcut.md).
|
||||
|
||||
## PE TLS callbacks and load configuration
|
||||
|
||||
Preserve each callback's RVA, file offset and section alongside its VA and the
|
||||
size-covered declaration fields. A missing directory is observed absence of
|
||||
that declaration.
|
||||
|
||||
Use `inspect_pe_load_config` for an explicit local PE32/PE32+ image when the
|
||||
question concerns code that runs before the entry point through TLS callbacks,
|
||||
or the security cookie, SafeSEH, CFG, EH-continuation and XFG declarations in
|
||||
the load configuration. No `open_binary`, Windows SDK, or target execution is
|
||||
required. The CLI equivalent is `inspect-pe-load-config PATH`. Preserve artifact
|
||||
SHA-256, directory and callback-array file ranges, and callback VAs as
|
||||
hexadecimal strings. Fields outside the declared `Size` are `null`. Guard-flag
|
||||
mitigations carry `evidence_kind: "inferred"`; enforcement remains unobserved.
|
||||
See
|
||||
[PE TLS callbacks and load configuration](https://github.com/morluto/rea/blob/main/docs/pe-load-config.md).
|
||||
|
||||
## Binary hardening
|
||||
|
||||
Each property reports `enabled`, `disabled`, `partial`, `unknown`, or
|
||||
`not_applicable`, with the header field or import behind it.
|
||||
|
||||
Use `inspect_binary_hardening` for an explicit local ELF, PE, or Mach-O file
|
||||
when the question concerns PIE or ASLR, NX, RELRO, stack-protector or FORTIFY
|
||||
signs, control-flow flags, or stripped state. No `open_binary`, pwntools, or
|
||||
target execution is required. The CLI equivalent is
|
||||
`inspect-binary-hardening PATH`. Universal Mach-O files return one image per
|
||||
slice. A missing import is `unknown`, not proof the protection was omitted.
|
||||
Authenticode and Mach-O code-signature rows report presence, not validity.
|
||||
`hardened_runtime` stays unknown and names `inspect_signature`. See
|
||||
[binary hardening](https://github.com/morluto/rea/blob/main/docs/binary-hardening.md).
|
||||
|
||||
## ELF note tables
|
||||
|
||||
Retain each note's owner, type, descriptor SHA-256, and PT_NOTE/SHT_NOTE ranges.
|
||||
|
||||
Use `inspect_elf_notes` for an explicit local ELF32/ELF64 image when the
|
||||
question concerns PT_NOTE/SHT_NOTE owners, GNU build-id, or GNU ABI-tag
|
||||
fields. No `open_binary` or target execution is required. The CLI equivalent
|
||||
is `inspect-elf-notes PATH`. Preserve artifact SHA-256, table file ranges,
|
||||
descriptor hashes, and original owner spellings. A missing table is observed
|
||||
absence of those declarations, not proof the image never carried notes in
|
||||
another container. See
|
||||
[ELF note tables](https://github.com/morluto/rea/blob/main/docs/elf-notes.md).
|
||||
|
||||
## ELF and Mach-O initializer functions
|
||||
|
||||
Use `inspect_native_initializers` for an explicit local ELF or Mach-O image
|
||||
when the question is which functions run before `main` or at exit: ELF
|
||||
`DT_PREINIT_ARRAY`, `DT_INIT`, `DT_INIT_ARRAY`, `DT_FINI`, `DT_FINI_ARRAY` and
|
||||
legacy `.ctors`/`.dtors`, or Mach-O `__mod_init_func`, `__init_offsets` and
|
||||
`__mod_term_func`. Pass `architecture` for a universal Mach-O. The CLI
|
||||
equivalent is `inspect-native-initializers PATH`. PIE slots are resolved
|
||||
through RELATIVE, RELR and section relocations, and Mach-O slots through
|
||||
chained fixups. Keep each entry's `resolution`: `unresolved` means the value was
|
||||
not established, and `unresolved_import` names an external symbol. Page with
|
||||
`offset` and `limit`. See
|
||||
[ELF and Mach-O initializer functions](https://github.com/morluto/rea/blob/main/docs/guides/native/native-initializers.md).
|
||||
|
||||
## ELF unwind function ranges
|
||||
|
||||
Use `inspect_elf_unwind_ranges` for an explicit local ELF32/ELF64 image when
|
||||
the question concerns function starts and lengths that survive `strip`, which
|
||||
functions have an LSDA, or which ranges have no exact symbol. No
|
||||
`open_binary` or target execution is required. The CLI equivalent is
|
||||
`inspect-elf-unwind-ranges PATH`. Preserve artifact SHA-256, FDE start and
|
||||
end, containing section, exact symbol name, CIE index, LSDA, and personality.
|
||||
Page later ranges with `offset` and `limit`. A missing `.eh_frame` is
|
||||
observed absence of that declaration and of `PT_GNU_EH_FRAME`, not proof the
|
||||
image has no functions. Header disagreement is a limitation and does not drop
|
||||
decoded ranges. `.debug_frame` is reported present or absent and is not
|
||||
decoded. CFA instructions are counted and not evaluated. Indirect EH pointers
|
||||
are not dereferenced. See
|
||||
[ELF unwind function ranges](https://github.com/morluto/rea/blob/main/docs/guides/native/elf-unwind-ranges.md).
|
||||
|
||||
## Apple IPS crash reports
|
||||
|
||||
Use `inspect_apple_ips` for an explicit local Apple `.ips` file when the
|
||||
question concerns crash metadata, exception and termination facts, threads,
|
||||
usedImages, lossless registers, or documented crash classes. No `open_binary`,
|
||||
Xcode, atos, or target execution is required. The CLI equivalent is
|
||||
`inspect-apple-ips PATH`. Preserve artifact SHA-256, `bug_type` as a string,
|
||||
uppercase image UUIDs, and integer literals that exceed IEEE-754 range. Only
|
||||
`bug_type` `"309"` yields a crash body; other DiagnosticReports types return
|
||||
no crash result. Select `join_path` for one local Mach-O or dSYM to match
|
||||
report images to slices by UUID and architecture. Preserve the selected
|
||||
artifact identity, slice facts and unjoined reasons; a joined static address
|
||||
does not resolve function names or dSYM symbols. See
|
||||
[Apple IPS crash reports](https://github.com/morluto/rea/blob/main/docs/apple-ips.md).
|
||||
|
||||
## Linux kernel modules
|
||||
|
||||
Use `inspect_kernel_module` for an explicit local ELF32/ELF64 relocatable
|
||||
object when the question concerns `.modinfo` license, vermagic, alias,
|
||||
depends, or parm strings, the `__versions` symbol CRCs, or an appended module
|
||||
signature trailer. No `open_binary`, Linux host, or `modinfo` program is
|
||||
required. The CLI equivalent is `inspect-kernel-module PATH`. Preserve
|
||||
artifact SHA-256, key order, duplicate keys, CRC hex, and section file ranges.
|
||||
A missing section is observed absence when section names are known, not proof
|
||||
the module never carried that metadata. `.gnu.linkonce.this_module` is reported
|
||||
as present or absent; `struct module` stays unknown because its layout changes
|
||||
with the kernel version. `__ksymtab` records are not decoded. The PKCS#7 range
|
||||
and its SHA-256 are observed; certificate, signer, and digest coverage remain
|
||||
unvalidated. An absent trailer is not proof the module is unsigned in another
|
||||
container. gzip, xz, and zstd whole-file containers are unsupported and name
|
||||
`external_decompression` as the next probe: use an external codec utility to
|
||||
decompress into a separate file, then call `inspect_kernel_module` on that file. See
|
||||
[Linux kernel modules](https://github.com/morluto/rea/blob/main/docs/kernel-modules.md).
|
||||
|
||||
## Linux kernel build config
|
||||
|
||||
Use `inspect_kernel_build_config` for an explicit local kernel image (`vmlinux`
|
||||
ELF, raw arm64 `Image`, x86 `bzImage`/`zImage`, or `configs.ko`) when the
|
||||
question is which kernel version it is or how it was configured. No
|
||||
`open_binary`, Linux host, or `extract-ikconfig` is required. The CLI
|
||||
equivalent is `inspect-kernel-build-config PATH`; pass `name` for one exact
|
||||
`CONFIG_*` option and `offset`/`limit` to page the rest. Preserve the banner
|
||||
version, builder, and compiler, the config SHA-256 and option count, and each
|
||||
entry's value kind (`y`, `m`, `string`, `number`, `not_set`). A config is
|
||||
accepted only when `IKCFG_ST` is immediately followed by a valid gzip member
|
||||
and `IKCFG_ED`, so an ordinary `IKCFG_ST` string is not a config. Offsets with
|
||||
`space: "inflated_payload"` are positions in an inflated bzImage payload, not
|
||||
file offsets. An absent config describes only the searched bytes; the kernel
|
||||
may have been built without `CONFIG_IKCONFIG` or with it as a module. Truncated
|
||||
payloads are incomplete, not absent. A framed blob that does not decode, has a
|
||||
bad CRC, or holds non-config text is `malformed`, not absent. xz, lz4, lzma, zstd, bzip2, and lzo
|
||||
payloads are unsupported and name `external_decompression`: decompress with an
|
||||
external utility, then call `inspect_kernel_build_config` on the result. See
|
||||
[Linux kernel build config](https://github.com/morluto/rea/blob/main/docs/guides/native/kernel-build-config.md).
|
||||
|
||||
## CPython pyc files
|
||||
|
||||
Use `inspect_python_pyc` for an explicit local CPython 3.7–3.13 `.pyc` when the
|
||||
question concerns the header magic, PEP 552 source hash or timestamp, nested
|
||||
code-object names, or bytecode identity. No `open_binary`, Python installation,
|
||||
or target execution is required. The CLI equivalent is `inspect-python-pyc PATH`.
|
||||
Preserve artifact SHA-256, the 16-byte header fields, nested code names, and
|
||||
bytecode SHA-256. Bytecode is not decompiled. A decoded header does not prove
|
||||
the matching `.py` is present. See [CPython pyc inspection](https://github.com/morluto/rea/blob/main/docs/python-pyc.md).
|
||||
|
||||
## Erlang BEAM files
|
||||
|
||||
Use `inspect_erlang_beam` for an explicit local `FOR1`/`BEAM` file when the
|
||||
question concerns IFF chunks, atom names, exports, imports, lambdas, or the
|
||||
Code header. No `open_binary`, Erlang installation, or bytecode execution is
|
||||
required. The CLI equivalent is `inspect-erlang-beam PATH`. Preserve artifact
|
||||
SHA-256, chunk file ranges, 1-based atom indices, and original atom spellings.
|
||||
Missing optional tables stay null. For a few facts, use `detail: "summary"` with
|
||||
a `beam` view selecting a collection, exact names/indices and fields; read later
|
||||
pages from `parent_evidence_id` or the complete Evidence bundle. Same-name
|
||||
exports retain every arity and original atom index. CLI summary delivery requires
|
||||
`--evidence_output`. Null table counts remain distinct from decoded empty tables. See
|
||||
[Erlang BEAM files](https://github.com/morluto/rea/blob/main/docs/erlang-beam.md).
|
||||
|
||||
## SQLite snapshots
|
||||
|
||||
Use `inspect_sqlite_database` with an explicit local database snapshot for its
|
||||
schema and optional rows from one exact ordinary table. It requires Node.js
|
||||
24.x >=24.15 or 26+ with the native `DatabaseSync.limits` API. It also consumes the
|
||||
existing sibling `-wal`; retain both original digests when citing its result.
|
||||
Default output is a compact inventory; a selected table expands only its own
|
||||
schema and samples 20 rows. Select `columns` to avoid irrelevant or large cells,
|
||||
and request `schema_scope: "database"` only for complete schema details.
|
||||
Choose `row_limit` when a finite sample is useful and keep truncation and
|
||||
unspecified row order explicit. Virtual tables, shadow tables and views are
|
||||
schema facts, not row-read targets. REA inspects private copies and leaves
|
||||
the source files untouched; obtain a coherent quiescent database/WAL snapshot
|
||||
before inspection. See [SQLite snapshots](https://github.com/morluto/rea/blob/main/docs/guides/data/sqlite-databases.md).
|
||||
|
||||
## Recorded Linux crashes
|
||||
|
||||
Use `inspect_recorded_crash` with an explicit Linux x86-64 ELF core path to
|
||||
inspect historical thread registers, signals, raw notes and original file
|
||||
ranges. It is independent of the active disassembler target. Source-bound
|
||||
register values and note bytes are observations; missing notes, signal-thread
|
||||
association and current executable/library identity remain unknown. PIDs are
|
||||
historical metadata and never authorize live attach or control.
|
||||
|
||||
The optional `include_debugger_context` facet adds mapping candidates through
|
||||
caller-supplied GDB/pwndbg in an owned core-only session. Display names do not
|
||||
establish current file identity; zero reported flags leave permissions unknown.
|
||||
Requested unavailable context fails with setup guidance. See
|
||||
[recorded crashes](https://github.com/morluto/rea/blob/main/docs/guides/native/recorded-crashes.md)
|
||||
for exact upstream profiles, bounds and verification coverage.
|
||||
|
||||
## Offline ELF layout
|
||||
|
||||
Use `inspect_binary_layout` with an explicit local ELF path for file-backed
|
||||
sections, symbols, relocations, linkage names, and static mitigation inferences
|
||||
without opening a disassembler target. When that complete record is already
|
||||
retained, call `inspect_analysis_view` for a summary, mitigations or linkage
|
||||
facet, one section or symbol, or a stable page. Do not re-run the decoder to
|
||||
read a single object.
|
||||
|
||||
## Offline WASM
|
||||
|
||||
Supply WABT 1.0.42 through `REA_WABT_BIN_DIRECTORY`. Select JavaScript glue and
|
||||
candidate paths explicitly, preserving URL/path ambiguity and exact byte/tool
|
||||
identity; no implicit fetch is performed.
|
||||
|
||||
Use `inspect_wasm_artifact` with caller-supplied WABT for selected local bytes.
|
||||
For counts, validation and WAT identity, select `detail: "summary"` on the first
|
||||
MCP call. The complete original Evidence stays retained; use
|
||||
`normalized_result.parent_evidence_id` for exact exports or text pages. Omitted
|
||||
or complete detail keeps the existing complete result.
|
||||
For a completed result, use `inspect_analysis_view` with its reported retained
|
||||
reference for a summary or `view: {kind: "wasm", facet: "exports", offset: 0, limit: 32}`.
|
||||
Facets also include sections, imports, candidates, glue, WAT, headers, details
|
||||
and tool profile. Text offsets count UTF-16 code units; follow `next_offset`.
|
||||
The complete source remains retained after an oversized MCP reply. No target
|
||||
execution or network acquisition is implied, and WAT is decoded representation.
|
||||
|
||||
For exact core-module import/export differences, use `compare_wasm_interfaces`
|
||||
with two complete inspection Evidence records (or current-session retained
|
||||
references) and explicit scope. Preserve unknown types/duplicate names; static
|
||||
interface equality is not runtime compatibility. CLI accepts complete inline
|
||||
Evidence in `rea compare-wasm-interfaces input.json --json`, or exact references
|
||||
with `--evidence-bundle /absolute/path/evidence.json`. Use the complete parent
|
||||
ID when the inspection returned a summary.
|
||||
|
||||
See the [WASM guide](https://github.com/morluto/rea/blob/main/docs/guides/wasm/wasm-artifacts.md).
|
||||
|
||||
## Offline APK signatures
|
||||
|
||||
Use `inspect_apk_signature` for a selected local APK/ZIP/AAB. Default MCP summaries
|
||||
retain complete Evidence. Select `view.collection: signers/digests/lineage`,
|
||||
with scheme or ID batches, fields and paging; use `inspect_analysis_view` kind
|
||||
`apk-signature` for retained reads after deletion. IDs retain artifact/scheme
|
||||
scope and signer links; `fields: []` keeps identity links. Empty pages preserve
|
||||
partial decoding reasons and unknown authenticity. CLI compact delivery needs
|
||||
`--evidence_output` to preserve the complete parent.
|
||||
It reads the APK
|
||||
Signing Block (v2/v3/v3.1) and v1 `META-INF` signing without executing anything,
|
||||
and reports each signer's certificate facts (for v1, the certificate the PKCS#7
|
||||
block's SignerInfo names), the declared v3 rotation lineage,
|
||||
the declared source-stamp certificate and, for SHA-256/SHA-512 digests, whether
|
||||
the declared content digest matches the current bytes. That match is not a
|
||||
signature verification: anyone who changes the bytes can recompute the digest.
|
||||
`posture` summarises v1-only signing (which cannot tell a v1-only APK from one
|
||||
whose v2/v3 block was removed), observed signer agreement across schemes,
|
||||
whether the v1 signer equals the block-scheme signer (`false` is notable),
|
||||
whether every differing signer appears in a declared (unverified) rotation
|
||||
lineage, and the strongest scheme.
|
||||
It never claims authenticity: no signature or lineage is cryptographically
|
||||
verified.
|
||||
|
||||
See the [APK signature guide](https://github.com/morluto/rea/blob/main/docs/apk-signature.md).
|
||||
|
||||
## Offline PE resource inventory
|
||||
|
||||
Use `inspect_pe_resources` with an absolute `path`, or
|
||||
`rea inspect-pe-resources ./selected.exe --json`, for portable PE32/PE32+
|
||||
resource inspection without opening a native target. Preserve returned Evidence:
|
||||
type/name/language IDs and UTF-16 names, original directory/data/payload ranges,
|
||||
code pages, payload hashes and static icon-group references. Same-language icon
|
||||
resolution is explicit; missing references and size mismatch remain visible.
|
||||
Other payloads are opaque, and this operation does not decode images or simulate
|
||||
Windows resource loading. Consult the budgets and supported tree profile in
|
||||
[offline binary diagnostics](https://github.com/morluto/rea/blob/main/docs/guides/native/binary-diagnostics.md).
|
||||
|
||||
## Offline PE and ELF export tables
|
||||
|
||||
Use `inspect_native_exports` with an absolute `path`, or
|
||||
`rea inspect-native-exports ./libexample.so --json`, to read a PE export
|
||||
directory or ELF dynamic symbol table on any host without opening a native
|
||||
target. Ordinal-only, forwarded and hidden-version exports stay distinct;
|
||||
partial or unsupported coverage means the inventory is incomplete, not that
|
||||
exports are absent. Use `inspect_macho` for Mach-O. See
|
||||
[offline binary diagnostics](https://github.com/morluto/rea/blob/main/docs/guides/native/binary-diagnostics.md).
|
||||
|
||||
## EVM bytecode
|
||||
|
||||
Explicit local EVM bytecode carrier: `inspect_evm_interface` with caller-selected
|
||||
`raw` or `hex` encoding. The owned worker deadline is `timeout_ms` (default
|
||||
30000 ms, range 1..2147483647, next call). Select byte, address-space and CPU
|
||||
allowances separately through `producer_limits`; tighter inherited OS limits
|
||||
remain enforced, and the 256 MiB worker heap is independent. Preserve carrier/decoded digests and treat selectors,
|
||||
argument strings and mutability as inferred candidates; this performs no chain
|
||||
lookup or target execution. For the complete inferred interface without hex or
|
||||
duplicate stdout, discover support and select `detail: "summary"`; complete
|
||||
Evidence stays retained under its original identity. Use the returned
|
||||
`parent_evidence_id` for exact function or `bytecode_hex`/stdout/stderr pages.
|
||||
Candidate coverage does not establish interface completeness. See the
|
||||
[EVM bytecode guide](https://github.com/morluto/rea/blob/main/docs/guides/evm/evm-bytecode.md).
|
||||
|
||||
## Embedded GPU code objects
|
||||
|
||||
Embedded CUDA/HIP code objects: `inspect_gpu_code_objects`; inventory targets
|
||||
first, then decode selected payloads and query retained GPU Evidence.
|
||||
@@ -1,5 +1,13 @@
|
||||
# JavaScript and Electron application artifacts
|
||||
|
||||
Read only the sections needed for the selected task.
|
||||
|
||||
- [Inventory route candidates without returning the application graph](#inventory-route-candidates-without-returning-the-application-graph)
|
||||
- [Read a module without repeating analysis](#read-a-module-without-repeating-analysis)
|
||||
- [Trace only the remaining question](#trace-only-the-remaining-question)
|
||||
- [Recover an oversized display](#recover-an-oversized-display)
|
||||
- [Reusing application Evidence](#reusing-application-evidence)
|
||||
|
||||
For captured or bundled JavaScript that needs readable source recovery, use
|
||||
`recover_javascript_sources` with an absolute `path` and absent
|
||||
`output_directory`. Supply related runtime/shared/lazy files in
|
||||
@@ -90,6 +98,9 @@ Endpoint candidates remain inferences rather than confirmed network behavior.
|
||||
## Read a module without repeating analysis
|
||||
|
||||
Use the actual returned parent ID, on the same connection, as `source.evidence_id`.
|
||||
For CLI summary exports, take that ID from
|
||||
`summary.normalized_result.parent_evidence_id` and pass `--evidence-bundle` with
|
||||
the exported bundle's path to each later `inspect-analysis-view` invocation.
|
||||
The following IDs are placeholders to replace with returned values. When the
|
||||
module's node ID is not already known, page identities before selecting an item.
|
||||
Pages return only node IDs, paths and roles; choose a useful page size and follow
|
||||
|
||||
+91
-558
@@ -1,4 +1,23 @@
|
||||
# Native, managed, and packaged artifacts
|
||||
# Native and managed analysis
|
||||
|
||||
<a id="native-managed-and-packaged-artifacts"></a>
|
||||
|
||||
Read only the sections needed for the selected task.
|
||||
|
||||
- [Other artifact guides](#other-artifact-guides)
|
||||
- [Apple app resources](#apple-app-resources)
|
||||
- [Desktop installation directories](#desktop-installation-directories)
|
||||
- [Native targets](#native-targets)
|
||||
- [Continue editable Ghidra analysis across processes](#continue-editable-ghidra-analysis-across-processes)
|
||||
- [Reuse caller-selected Ghidra analysis](#reuse-caller-selected-ghidra-analysis)
|
||||
- [Ghidra startup deadline recovery](#ghidra-startup-deadline-recovery)
|
||||
- [Bridge request ceiling](#bridge-request-ceiling)
|
||||
- [Selected native facts and call graphs](#selected-native-facts-and-call-graphs)
|
||||
- [Static memory and original file bytes](#static-memory-and-original-file-bytes)
|
||||
- [DOS MZ with Ghidra](#dos-mz-with-ghidra)
|
||||
- [Managed PE/CLI](#managed-pe-cli-guide)
|
||||
- [DOS COM loader interpretation](#dos-com-loader-interpretation)
|
||||
- [Function annotations in Ghidra](#function-annotations-in-ghidra)
|
||||
|
||||
For release comparisons on one MCP connection, retain `list_procedures` Evidence
|
||||
from each target and reuse its exact IDs after target switches or `close_binary`.
|
||||
@@ -62,342 +81,39 @@ runtime presence. For compact CLI output, use
|
||||
`inspect-desktop-application PATH --detail summary --evidence_output BUNDLE`.
|
||||
See [desktop installations](https://github.com/morluto/rea/blob/main/docs/desktop-applications.md).
|
||||
|
||||
## Release exposure
|
||||
|
||||
Use `audit_release_exposure` (`rea audit-release-exposure PATH`) when the question is what static analysis of a shipped `.app`, install directory, ASAR, or executable recovers. Each check has a stable id, a status, the observation behind it, and fixed remediation. Unknown and unassessed checks stay in the report. The report does not establish that the application is secure.
|
||||
|
||||
`text.credential_markers` reports a rule id and location only. Matched bytes, previews, lengths, and hashes of matched bytes are omitted.
|
||||
|
||||
`native.hardening`, `macho.hardened_runtime`, and `android.manifest` are not assessed here. Their next probes are `inspect_binary_hardening`, `inspect_signature`, and `inspect_android_package`.
|
||||
|
||||
See [release exposure](https://github.com/morluto/rea/blob/main/docs/release-exposure.md).
|
||||
|
||||
## Go build metadata
|
||||
|
||||
Use `inspect_go_binary` for an explicit local ELF, PE or Mach-O (universal
|
||||
files need `architecture`) when the
|
||||
question concerns the embedded compiler version, module/dependency versions,
|
||||
local replacements, build settings, or static Go string literals packed without
|
||||
NUL terminators. Pass `include_string_literals: true`
|
||||
(`--include-string-literals`, optional `max_string_literals` /
|
||||
`--max-string-literals`) to recover bounded inferred word-aligned `(ptr, len)`
|
||||
UTF-8 string slices from read-only data and page them through `go`
|
||||
`string_literals` views. No `open_binary`, Go installation or
|
||||
target execution is required. The CLI equivalent is `inspect-go-binary PATH`.
|
||||
Preserve artifact SHA-256, original file ranges, framed module bytes and every
|
||||
unparsed module-text line. A missing record is an unknown, not proof of a
|
||||
non-Go binary; observed metadata does not authenticate its claims, and static
|
||||
`(ptr, len)` string recovery excludes compiler-inlined stack/immediate strings
|
||||
without proving runtime reachability. Function,
|
||||
source and type recovery remain a separate native-analysis question.
|
||||
|
||||
## Model files
|
||||
|
||||
Use `inspect_model_artifact` (`inspect-model-artifact PATH`) for local GGUF v2/v3
|
||||
and safetensors declarations without a model runtime. Header-only mode does not
|
||||
read weights or establish full-file identity. `hash: "full"` explicitly streams
|
||||
all bytes. Retained `model-artifact` views page `metadata`, `tensors` and derived
|
||||
`types`, with exact batch filters and selected fields. Arrays retain typed counts
|
||||
and eight-element previews; omitted values, unknown types and runtime behavior
|
||||
stay explicit. See [model files](https://github.com/morluto/rea/blob/main/docs/model-artifacts.md).
|
||||
|
||||
## IL2CPP metadata
|
||||
|
||||
Use `inspect_il2cpp_metadata` for an explicit local Unity `global-metadata.dat`
|
||||
(versions 24, 27, 29, 31 and 39) when the question concerns assembly images,
|
||||
names, member owners, string literals, namespaces or index ranges. No `open_binary`, Unity installation or target
|
||||
execution is required. The CLI equivalent is `inspect-il2cpp-metadata PATH`.
|
||||
MCP defaults to counts with complete retained Evidence. Query `sections`,
|
||||
`images`, `types`, `methods`, `fields`, `properties`, `events`, `parameters` or
|
||||
`string_literals` through `inspect_analysis_view`; use exact names,
|
||||
batch indices and selected fields. Row indices are scoped by artifact SHA-256
|
||||
and collection; page offsets count filtered matches. Parameters support batch
|
||||
`method_indices` to read one method's parameters directly. Historical reports
|
||||
without member collections retain unknown counts rather than empty inventories. Preserve
|
||||
artifact SHA-256 and index widths. Unrecognized magic may mean encryption and
|
||||
is unsupported, not decrypted. Linking names to `GameAssembly` or
|
||||
`UnityFramework` code addresses remains a separate native-analysis question.
|
||||
See [IL2CPP metadata](https://github.com/morluto/rea/blob/main/docs/il2cpp-metadata.md).
|
||||
|
||||
## Rust dependency metadata
|
||||
|
||||
Use `inspect_rust_binary` for an explicit local ELF, PE, or Mach-O (universal
|
||||
files need `architecture`) when
|
||||
the question concerns the cargo-auditable crate list embedded in `.dep-v0`
|
||||
(Mach-O: `__DATA,.dep-v0`). No `open_binary`, Rust installation, or target
|
||||
execution is required. The CLI equivalent is `inspect-rust-binary PATH`.
|
||||
Preserve artifact SHA-256, package order, dependency indices, and the section
|
||||
file range. A missing section is null metadata, not proof the binary has no
|
||||
dependencies. An omitted package kind stays null. A rustc commit hash is
|
||||
inferred from a read-only `/rustc/<40-hex>/` path and does not by itself
|
||||
identify the compiler. See [Rust binaries](https://github.com/morluto/rea/blob/main/docs/rust-binaries.md).
|
||||
|
||||
## PE Authenticode certificate tables
|
||||
|
||||
Use `inspect_pe_certificates` for an explicit local PE32/PE32+ image when the
|
||||
question concerns the Authenticode certificate table, WIN_CERTIFICATE types, or
|
||||
embedded PKCS#7 signer and X.509 identity fields. No `open_binary`, Windows SDK,
|
||||
or target execution is required. The CLI equivalent is
|
||||
`inspect-pe-certificates PATH`. Preserve artifact SHA-256, table file ranges,
|
||||
payload hashes, original validity-time spellings, and
|
||||
`subject_key_identifier_hex` when the signer uses that form. A missing
|
||||
`IMAGE_DIRECTORY_ENTRY_SECURITY` directory is observed absence of that table,
|
||||
not proof the image is unsigned in every catalog or overlay sense. Signatures,
|
||||
chains, timestamps, and Authenticode digest coverage remain unobserved. See
|
||||
[PE Authenticode certificate tables](https://github.com/morluto/rea/blob/main/docs/pe-certificates.md).
|
||||
|
||||
## PE import and delay-load tables
|
||||
|
||||
Use `inspect_pe_imports` for an explicit local PE32/PE32+ image when the
|
||||
question concerns imported DLL and function names, ordinals, delay-load
|
||||
descriptors, or the pefile import hash. No `open_binary`, Windows SDK, or
|
||||
target execution is required. The CLI equivalent is `inspect-pe-imports PATH`.
|
||||
Preserve artifact SHA-256, directory file ranges, original DLL spellings, and
|
||||
ILT/IAT RVAs. A missing `IMAGE_DIRECTORY_ENTRY_IMPORT` directory is observed
|
||||
absence of that table, not proof the image never imported APIs through another
|
||||
table or overlay. Bound snapshots, loaded IAT contents, and export-forward
|
||||
resolution remain unobserved. See
|
||||
[PE import and delay-load tables](https://github.com/morluto/rea/blob/main/docs/pe-imports.md).
|
||||
|
||||
## Windows Shell Link shortcuts
|
||||
|
||||
Use `inspect_windows_shortcut` for an explicit local `.lnk` file when the
|
||||
question concerns the recorded target path, arguments, working directory, icon
|
||||
location, volume serial, network share names, ExtraData blocks, or Tracker
|
||||
droid identifiers. No `open_binary`, Windows SDK, COM, or target execution is
|
||||
required. The CLI equivalent is `inspect-windows-shortcut PATH`. Preserve
|
||||
artifact SHA-256, FILETIME raw decimals, IDList type bytes, and ExtraData
|
||||
signatures. Unknown IDList items and ExtraData signatures remain raw with
|
||||
SHA-256; they are not guessed. Version-1 UUID MAC and timestamp values are
|
||||
labelled derived. A missing optional section is observed absence of that
|
||||
structure. See
|
||||
[Windows Shell Link shortcuts](https://github.com/morluto/rea/blob/main/docs/guides/native/windows-shortcut.md).
|
||||
|
||||
## PE TLS callbacks and load configuration
|
||||
|
||||
Use `inspect_pe_load_config` for an explicit local PE32/PE32+ image when the
|
||||
question concerns code that runs before the entry point through TLS callbacks,
|
||||
or the security cookie, SafeSEH, CFG, EH-continuation and XFG declarations in
|
||||
the load configuration. No `open_binary`, Windows SDK, or target execution is
|
||||
required. The CLI equivalent is `inspect-pe-load-config PATH`. Preserve artifact
|
||||
SHA-256, directory and callback-array file ranges, and callback VAs as
|
||||
hexadecimal strings. Fields outside the declared `Size` are `null`. Guard-flag
|
||||
mitigations carry `evidence_kind: "inferred"`; enforcement remains unobserved.
|
||||
See
|
||||
[PE TLS callbacks and load configuration](https://github.com/morluto/rea/blob/main/docs/pe-load-config.md).
|
||||
|
||||
## Binary hardening
|
||||
|
||||
Use `inspect_binary_hardening` for an explicit local ELF, PE, or Mach-O file
|
||||
when the question concerns PIE or ASLR, NX, RELRO, stack-protector or FORTIFY
|
||||
signs, control-flow flags, or stripped state. No `open_binary`, pwntools, or
|
||||
target execution is required. The CLI equivalent is
|
||||
`inspect-binary-hardening PATH`. Universal Mach-O files return one image per
|
||||
slice. A missing import is `unknown`, not proof the protection was omitted.
|
||||
Authenticode and Mach-O code-signature rows report presence, not validity.
|
||||
`hardened_runtime` stays unknown and names `inspect_signature`. See
|
||||
[binary hardening](https://github.com/morluto/rea/blob/main/docs/binary-hardening.md).
|
||||
|
||||
## ELF note tables
|
||||
|
||||
Use `inspect_elf_notes` for an explicit local ELF32/ELF64 image when the
|
||||
question concerns PT_NOTE/SHT_NOTE owners, GNU build-id, or GNU ABI-tag
|
||||
fields. No `open_binary` or target execution is required. The CLI equivalent
|
||||
is `inspect-elf-notes PATH`. Preserve artifact SHA-256, table file ranges,
|
||||
descriptor hashes, and original owner spellings. A missing table is observed
|
||||
absence of those declarations, not proof the image never carried notes in
|
||||
another container. See
|
||||
[ELF note tables](https://github.com/morluto/rea/blob/main/docs/elf-notes.md).
|
||||
|
||||
## ELF and Mach-O initializer functions
|
||||
|
||||
Use `inspect_native_initializers` for an explicit local ELF or Mach-O image
|
||||
when the question is which functions run before `main` or at exit: ELF
|
||||
`DT_PREINIT_ARRAY`, `DT_INIT`, `DT_INIT_ARRAY`, `DT_FINI`, `DT_FINI_ARRAY` and
|
||||
legacy `.ctors`/`.dtors`, or Mach-O `__mod_init_func`, `__init_offsets` and
|
||||
`__mod_term_func`. Pass `architecture` for a universal Mach-O. The CLI
|
||||
equivalent is `inspect-native-initializers PATH`. PIE slots are resolved
|
||||
through RELATIVE, RELR and section relocations, and Mach-O slots through
|
||||
chained fixups. Keep each entry's `resolution`: `unresolved` means the value was
|
||||
not established, and `unresolved_import` names an external symbol. Page with
|
||||
`offset` and `limit`. See
|
||||
[ELF and Mach-O initializer functions](https://github.com/morluto/rea/blob/main/docs/guides/native/native-initializers.md).
|
||||
|
||||
## ELF unwind function ranges
|
||||
|
||||
Use `inspect_elf_unwind_ranges` for an explicit local ELF32/ELF64 image when
|
||||
the question concerns function starts and lengths that survive `strip`, which
|
||||
functions have an LSDA, or which ranges have no exact symbol. No
|
||||
`open_binary` or target execution is required. The CLI equivalent is
|
||||
`inspect-elf-unwind-ranges PATH`. Preserve artifact SHA-256, FDE start and
|
||||
end, containing section, exact symbol name, CIE index, LSDA, and personality.
|
||||
Page later ranges with `offset` and `limit`. A missing `.eh_frame` is
|
||||
observed absence of that declaration and of `PT_GNU_EH_FRAME`, not proof the
|
||||
image has no functions. Header disagreement is a limitation and does not drop
|
||||
decoded ranges. `.debug_frame` is reported present or absent and is not
|
||||
decoded. CFA instructions are counted and not evaluated. Indirect EH pointers
|
||||
are not dereferenced. See
|
||||
[ELF unwind function ranges](https://github.com/morluto/rea/blob/main/docs/guides/native/elf-unwind-ranges.md).
|
||||
|
||||
## Apple IPS crash reports
|
||||
|
||||
Use `inspect_apple_ips` for an explicit local Apple `.ips` file when the
|
||||
question concerns crash metadata, exception and termination facts, threads,
|
||||
usedImages, lossless registers, or documented crash classes. No `open_binary`,
|
||||
Xcode, atos, or target execution is required. The CLI equivalent is
|
||||
`inspect-apple-ips PATH`. Preserve artifact SHA-256, `bug_type` as a string,
|
||||
uppercase image UUIDs, and integer literals that exceed IEEE-754 range. Only
|
||||
`bug_type` `"309"` yields a crash body; other DiagnosticReports types return
|
||||
no crash result. Select `join_path` for one local Mach-O or dSYM to match
|
||||
report images to slices by UUID and architecture. Preserve the selected
|
||||
artifact identity, slice facts and unjoined reasons; a joined static address
|
||||
does not resolve function names or dSYM symbols. See
|
||||
[Apple IPS crash reports](https://github.com/morluto/rea/blob/main/docs/apple-ips.md).
|
||||
|
||||
## Linux kernel modules
|
||||
|
||||
Use `inspect_kernel_module` for an explicit local ELF32/ELF64 relocatable
|
||||
object when the question concerns `.modinfo` license, vermagic, alias,
|
||||
depends, or parm strings, the `__versions` symbol CRCs, or an appended module
|
||||
signature trailer. No `open_binary`, Linux host, or `modinfo` program is
|
||||
required. The CLI equivalent is `inspect-kernel-module PATH`. Preserve
|
||||
artifact SHA-256, key order, duplicate keys, CRC hex, and section file ranges.
|
||||
A missing section is observed absence when section names are known, not proof
|
||||
the module never carried that metadata. `.gnu.linkonce.this_module` is reported
|
||||
as present or absent; `struct module` stays unknown because its layout changes
|
||||
with the kernel version. `__ksymtab` records are not decoded. The PKCS#7 range
|
||||
and its SHA-256 are observed; certificate, signer, and digest coverage remain
|
||||
unvalidated. An absent trailer is not proof the module is unsigned in another
|
||||
container. gzip, xz, and zstd whole-file containers are unsupported and name
|
||||
`external_decompression` as the next probe: use an external codec utility to
|
||||
decompress into a separate file, then call `inspect_kernel_module` on that file. See
|
||||
[Linux kernel modules](https://github.com/morluto/rea/blob/main/docs/kernel-modules.md).
|
||||
|
||||
## Linux kernel build config
|
||||
|
||||
Use `inspect_kernel_build_config` for an explicit local kernel image (`vmlinux`
|
||||
ELF, raw arm64 `Image`, x86 `bzImage`/`zImage`, or `configs.ko`) when the
|
||||
question is which kernel version it is or how it was configured. No
|
||||
`open_binary`, Linux host, or `extract-ikconfig` is required. The CLI
|
||||
equivalent is `inspect-kernel-build-config PATH`; pass `name` for one exact
|
||||
`CONFIG_*` option and `offset`/`limit` to page the rest. Preserve the banner
|
||||
version, builder, and compiler, the config SHA-256 and option count, and each
|
||||
entry's value kind (`y`, `m`, `string`, `number`, `not_set`). A config is
|
||||
accepted only when `IKCFG_ST` is immediately followed by a valid gzip member
|
||||
and `IKCFG_ED`, so an ordinary `IKCFG_ST` string is not a config. Offsets with
|
||||
`space: "inflated_payload"` are positions in an inflated bzImage payload, not
|
||||
file offsets. An absent config describes only the searched bytes; the kernel
|
||||
may have been built without `CONFIG_IKCONFIG` or with it as a module. Truncated
|
||||
payloads are incomplete, not absent. A framed blob that does not decode, has a
|
||||
bad CRC, or holds non-config text is `malformed`, not absent. xz, lz4, lzma, zstd, bzip2, and lzo
|
||||
payloads are unsupported and name `external_decompression`: decompress with an
|
||||
external utility, then call `inspect_kernel_build_config` on the result. See
|
||||
[Linux kernel build config](https://github.com/morluto/rea/blob/main/docs/guides/native/kernel-build-config.md).
|
||||
|
||||
## CPython pyc files
|
||||
|
||||
Use `inspect_python_pyc` for an explicit local CPython 3.7–3.13 `.pyc` when the
|
||||
question concerns the header magic, PEP 552 source hash or timestamp, nested
|
||||
code-object names, or bytecode identity. No `open_binary`, Python installation,
|
||||
or target execution is required. The CLI equivalent is `inspect-python-pyc PATH`.
|
||||
Preserve artifact SHA-256, the 16-byte header fields, nested code names, and
|
||||
bytecode SHA-256. Bytecode is not decompiled. A decoded header does not prove
|
||||
the matching `.py` is present. See [CPython pyc inspection](https://github.com/morluto/rea/blob/main/docs/python-pyc.md).
|
||||
|
||||
## Erlang BEAM files
|
||||
|
||||
Use `inspect_erlang_beam` for an explicit local `FOR1`/`BEAM` file when the
|
||||
question concerns IFF chunks, atom names, exports, imports, lambdas, or the
|
||||
Code header. No `open_binary`, Erlang installation, or bytecode execution is
|
||||
required. The CLI equivalent is `inspect-erlang-beam PATH`. Preserve artifact
|
||||
SHA-256, chunk file ranges, 1-based atom indices, and original atom spellings.
|
||||
Missing optional tables stay null. For a few facts, use `detail: "summary"` with
|
||||
a `beam` view selecting a collection, exact names/indices and fields; read later
|
||||
pages from `parent_evidence_id` or the complete Evidence bundle. Same-name
|
||||
exports retain every arity and original atom index. CLI summary delivery requires
|
||||
`--evidence_output`. Null table counts remain distinct from decoded empty tables. See
|
||||
[Erlang BEAM files](https://github.com/morluto/rea/blob/main/docs/erlang-beam.md).
|
||||
|
||||
## SQLite snapshots
|
||||
|
||||
Use `inspect_sqlite_database` with an explicit local database snapshot for its
|
||||
schema and optional rows from one exact ordinary table. It requires Node.js
|
||||
24.x >=24.15 or 26+ with the native `DatabaseSync.limits` API. It also consumes the
|
||||
existing sibling `-wal`; retain both original digests when citing its result.
|
||||
Default output is a compact inventory; a selected table expands only its own
|
||||
schema and samples 20 rows. Select `columns` to avoid irrelevant or large cells,
|
||||
and request `schema_scope: "database"` only for complete schema details.
|
||||
Choose `row_limit` when a finite sample is useful and keep truncation and
|
||||
unspecified row order explicit. Virtual tables, shadow tables and views are
|
||||
schema facts, not row-read targets. REA inspects private copies and leaves
|
||||
the source files untouched; obtain a coherent quiescent database/WAL snapshot
|
||||
before inspection. See [SQLite snapshots](https://github.com/morluto/rea/blob/main/docs/guides/data/sqlite-databases.md).
|
||||
|
||||
## Recorded Linux crashes
|
||||
|
||||
Use `inspect_recorded_crash` with an explicit Linux x86-64 ELF core path to
|
||||
inspect historical thread registers, signals, raw notes and original file
|
||||
ranges. It is independent of the active disassembler target. Source-bound
|
||||
register values and note bytes are observations; missing notes, signal-thread
|
||||
association and current executable/library identity remain unknown. PIDs are
|
||||
historical metadata and never authorize live attach or control.
|
||||
|
||||
The optional `include_debugger_context` facet adds mapping candidates through
|
||||
caller-supplied GDB/pwndbg in an owned core-only session. Display names do not
|
||||
establish current file identity; zero reported flags leave permissions unknown.
|
||||
Requested unavailable context fails with setup guidance. See
|
||||
[recorded crashes](https://github.com/morluto/rea/blob/main/docs/guides/native/recorded-crashes.md)
|
||||
for exact upstream profiles, bounds and verification coverage.
|
||||
|
||||
## Offline ELF layout
|
||||
|
||||
Use `inspect_binary_layout` with an explicit local ELF path for file-backed
|
||||
sections, symbols, relocations, linkage names, and static mitigation inferences
|
||||
without opening a disassembler target. When that complete record is already
|
||||
retained, call `inspect_analysis_view` for a summary, mitigations or linkage
|
||||
facet, one section or symbol, or a stable page. Do not re-run the decoder to
|
||||
read a single object.
|
||||
|
||||
## Offline WASM
|
||||
|
||||
Use `inspect_wasm_artifact` with caller-supplied WABT for selected local bytes.
|
||||
For counts, validation and WAT identity, select `detail: "summary"` on the first
|
||||
MCP call. The complete original Evidence stays retained; use
|
||||
`normalized_result.parent_evidence_id` for exact exports or text pages. Omitted
|
||||
or complete detail keeps the existing complete result.
|
||||
For a completed result, use `inspect_analysis_view` with its reported retained
|
||||
reference for a summary or `view: {kind: "wasm", facet: "exports", offset: 0, limit: 32}`.
|
||||
Facets also include sections, imports, candidates, glue, WAT, headers, details
|
||||
and tool profile. Text offsets count UTF-16 code units; follow `next_offset`.
|
||||
The complete source remains retained after an oversized MCP reply. No target
|
||||
execution or network acquisition is implied, and WAT is decoded representation.
|
||||
|
||||
## Offline APK signatures
|
||||
|
||||
Use `inspect_apk_signature` for a selected local APK/ZIP/AAB. Default MCP summaries
|
||||
retain complete Evidence. Select `view.collection: signers/digests/lineage`,
|
||||
with scheme or ID batches, fields and paging; use `inspect_analysis_view` kind
|
||||
`apk-signature` for retained reads after deletion. IDs retain artifact/scheme
|
||||
scope and signer links; `fields: []` keeps identity links. Empty pages preserve
|
||||
partial decoding reasons and unknown authenticity. CLI compact delivery needs
|
||||
`--evidence_output` to preserve the complete parent.
|
||||
It reads the APK
|
||||
Signing Block (v2/v3/v3.1) and v1 `META-INF` signing without executing anything,
|
||||
and reports each signer's certificate facts (for v1, the certificate the PKCS#7
|
||||
block's SignerInfo names), the declared v3 rotation lineage,
|
||||
the declared source-stamp certificate and, for SHA-256/SHA-512 digests, whether
|
||||
the declared content digest matches the current bytes. That match is not a
|
||||
signature verification: anyone who changes the bytes can recompute the digest.
|
||||
`posture` summarises v1-only signing (which cannot tell a v1-only APK from one
|
||||
whose v2/v3 block was removed), observed signer agreement across schemes,
|
||||
whether the v1 signer equals the block-scheme signer (`false` is notable),
|
||||
whether every differing signer appears in a declared (unverified) rotation
|
||||
lineage, and the strongest scheme.
|
||||
It never claims authenticity: no signature or lineage is cryptographically
|
||||
verified.
|
||||
|
||||
## Native targets
|
||||
|
||||
For an existing IDA MCP configuration, use `open_binary` with the original
|
||||
input binary and `provider_id: "ida"`; do not pass an `.idb` or `.i64` database.
|
||||
The legacy attached profile binds the already-open GUI input by SHA-256 and
|
||||
leaves its database open. The modern headless profile creates and closes an
|
||||
owned private database without saving. Installation and registration reuse
|
||||
[mrexodia/ida-pro-mcp](https://github.com/mrexodia/ida-pro-mcp); see the
|
||||
[IDA provider guide](https://github.com/morluto/rea/blob/main/docs/providers/ida-provider.md).
|
||||
For migration to the separate native IDA MCP plugin, follow the guide's
|
||||
[legacy attached migration](https://github.com/morluto/rea/blob/main/docs/providers/ida-provider.md#migrate-a-legacy-attached-registration).
|
||||
Replace the upstream registration explicitly; modern mrexodia tools are not the
|
||||
native profile. Native attachment preserves the database but does not provide
|
||||
direct callers; check session availability and the guide's verification limits.
|
||||
Proceed directly to `analyze_function`, pseudocode, or function/string searches
|
||||
after opening; IDA does not supply `binary_overview`. Consult session availability
|
||||
when composing broader workflows. Modern direct callers and unsupported dossier
|
||||
facets remain unknown; live IDA results are not replayed from snapshots.
|
||||
|
||||
With `REA_KUNA_COMMAND` configured, `provider_id: "kuna"` answers procedure
|
||||
lists, lookups, pseudocode, assembly and `analyze_function` from Kuna's cached
|
||||
whole-program export. Callers/callees use a separate body-free graph shared by
|
||||
the session; `xrefs` returns exact-address incoming sites and filters forwarding
|
||||
aliases. These queries and inventory lookups do not trigger a C export. Indirect
|
||||
targets remain unknown and can make relationship coverage partial. Reference
|
||||
caches expire on close; a fresh CLI process repeats the native reference walk.
|
||||
Typed references, CFG, raw-memory tools and annotations remain unsupported. A cold first
|
||||
answer can come from a single-function run (its limitations say so); assembly
|
||||
waits for the export. For pseudocode and assembly, `raw_result.source` names the
|
||||
cached `.c`/`.asm` file and byte span, which you may search directly instead of
|
||||
calling per function. See the
|
||||
[Kuna provider guide](https://github.com/morluto/rea/blob/main/docs/kuna-provider.md).
|
||||
|
||||
After `open_binary`, use focused search, procedure, or function tools directly.
|
||||
Use `binary_overview` when target metadata or inventory context helps answer the
|
||||
question. Prefer literal search, names, decompilation, callers, callees, and
|
||||
@@ -632,6 +348,8 @@ that a class is a root class or has no ivars.
|
||||
|
||||
## Managed PE/CLI
|
||||
|
||||
<a id="managed-pe-cli-guide"></a>
|
||||
|
||||
Start with `inspect_managed_artifact`. REA's canonical managed inspection is
|
||||
execution-free: do not claim it loaded, reflected, executed, or resolved the
|
||||
assembly. Keep managed/native boundaries and unavailable reconstruction facts
|
||||
@@ -690,81 +408,17 @@ and distinguish derived metadata from Ghidra database observations. Recovered
|
||||
types and native pseudocode are not original C# source. Windows Ghidra P0 has
|
||||
no database mutation authority.
|
||||
|
||||
## Packages and extraction
|
||||
For headerless firmware and address-bearing containers, read
|
||||
[raw images](firmware-and-raw-images.md#headerless-raw-images-and-firmware-containers).
|
||||
|
||||
Use `inspect_artifact` for application bundles, archives, ZIP/APK/IPA/MSIX/AppX,
|
||||
ASAR, or DMG inputs when the artifact graph and findings help answer the
|
||||
question. It returns the complete artifact graph inline. Cite graph manifest
|
||||
IDs when using them.
|
||||
|
||||
For an IPA or a macOS `.app`, ZIP, or DMG, pass the inventory Evidence to
|
||||
`project_apple_application_graph`. It reports application roots and nested
|
||||
bundles by path convention: app extensions, XPC services, frameworks, login
|
||||
items, system and driver extensions, and plug-ins. It also lists privileged
|
||||
helpers, launchd plists, symlinks, and each bundle's `info_plist_path` and
|
||||
executable candidates. Roles are path conventions, not parsed plists; read the
|
||||
listed plists with `inspect_plist`.
|
||||
|
||||
After `open_binary` on a `.app` or Mach-O, use `trace_dylib_resolution` to see
|
||||
which file each `@rpath`, `@loader_path` and `@executable_path` load reaches for
|
||||
every executable in the bundle. It also lists missing or weak loads and earlier
|
||||
`@rpath` candidates that are absent. Narrow large bundles with `roots` or
|
||||
`architecture`. System paths stay undetermined because the dyld shared cache
|
||||
provides them.
|
||||
|
||||
Use `extract_artifact` when materialized files from a supported format are needed.
|
||||
It extracts the active target and accepts optional `integrity_policy`; see the [MCP contracts](https://github.com/morluto/rea/blob/main/docs/reference/mcp-contracts.md).
|
||||
It materializes all regular files into a fresh temporary directory chosen by
|
||||
REA. Symlinks and encrypted entries are inventory facts, not extractable files.
|
||||
The result reports the materialized directory; callers do not choose the
|
||||
destination. No separate permission grant is needed.
|
||||
|
||||
For classic iNES cartridges, `open_binary` recognizes the byte signature without
|
||||
an executable architecture. `inspect_artifact` retains header facts and each
|
||||
PRG/CHR file unit's offset, length and SHA-256; its nested inventory's
|
||||
`ines.reconstruction` verifies the actual ordered region bytes against the
|
||||
whole-file digest. Extraction includes the original header, optional trainer
|
||||
and uninterpreted trailing bytes. These file units are not mapper/CPU bank
|
||||
maps. NES 2.0, UNIF, dirty legacy headers and truncated payloads are explicitly
|
||||
refused. No emulator or 6502 analysis is performed. See the
|
||||
[iNES guide](https://github.com/morluto/rea/blob/main/docs/ines-containers.md).
|
||||
|
||||
Native DMG traversal automatically uses a read-only mount on supported macOS
|
||||
hosts, with an owned temporary mount directory and cleanup. It needs no approval
|
||||
flag. Unsupported hosts or mount failures remain explicit limitations; do not
|
||||
claim child inventory when only root identity is available. DMG extraction is
|
||||
unavailable through `extract_artifact`. To access DMG files on macOS, create a
|
||||
read-only mount with your own tools, select files from that mount for analysis,
|
||||
and detach the mount you created when finished. REA's inspection mount is
|
||||
temporary, not a retained export of the image's contents.
|
||||
## DOS COM loader interpretation
|
||||
|
||||
For headerless DOS COM, explicitly open with `format: "dos-com"` (CLI
|
||||
`--target-format dos-com`). Inspect the load image before trusting function
|
||||
analysis: the entry is `0x10100`, file offset zero, with imposed real-mode segment
|
||||
context. PSP/stack/device state remains unmodeled. See [DOS guide](https://github.com/morluto/rea/blob/main/docs/providers/ghidra-dos.md).
|
||||
|
||||
Use `inspect_byte_entropy` to triage high- and low-entropy ranges before extraction.
|
||||
|
||||
For other headerless images (embedded firmware without ELF/Mach-O/PE/MZ
|
||||
headers), open with `format: "raw-binary"`, `architecture` (`x86`, `x86_64`,
|
||||
`arm`, `arm64`, `6502`, or `m68k`), and `entry_point` (`0x` hex). File offset 0 is mapped at
|
||||
that address. Hopper and IDA refuse this interpretation; Ghidra uses
|
||||
`BinaryLoader` with a generic language: big-endian for `m68k`, little-endian
|
||||
otherwise. Big-endian ARM, Thumb-only, and Cortex-M variants are unsupported.
|
||||
`6502` selects NMOS 6502; the entry and complete file mapping must fit within
|
||||
`0x0000..0xffff`. 65C02, 65816, cartridge containers, bank switching, and mapper
|
||||
semantics are unsupported. `m68k` requires an even entry and decodes the 68040
|
||||
superset of the 68000 family; Amiga/Atari containers and vector-table entry
|
||||
discovery are unsupported. Windows Ghidra P0 admits raw images only for `6502`. See [raw binary guide](https://github.com/morluto/rea/blob/main/docs/providers/raw-binary.md).
|
||||
|
||||
Intel HEX, S-record, UF2 and DfuSe files are containers, not raw images:
|
||||
`inspect_artifact` lists address regions (UF2 per familyID, DfuSe per element
|
||||
with its alternate setting), and `extract_artifact` writes each region. Open an
|
||||
extracted region as `raw-binary` with its start address as `entry_point`. UF2
|
||||
numbering gaps leave coverage unknown; a DfuSe suffix CRC mismatch follows
|
||||
`integrity_policy`. See [UF2 and DfuSe](https://github.com/morluto/rea/blob/main/docs/uf2-dfuse.md).
|
||||
|
||||
### Function annotations in Ghidra
|
||||
## Function annotations in Ghidra
|
||||
|
||||
Fresh-import sessions admit annotations; existing-project reuse is read-only.
|
||||
Use `annotate_native_function` for one function name and/or entry comments, with at least one explicit change. Review its annotation readback and refreshed dossier inline. Changes are atomic; empty comments clear them, omitted fields preserve them. Later MCP calls observe edits. Normal close saves them when owned Program checkpoint mode is enabled; ephemeral mode discards them. CLI `annotate-native-function` follows the same setting when closing after its updated result. Select the [checkpoint workflow](#continue-editable-ghidra-analysis-across-processes) before edits that must survive a later process. Original executable bytes are unchanged; edits invalidate immutable snapshots. Windows P0 does not admit database mutations. For naming only, `set_address_name` / `set_addresses_names` also work with Ghidra: they name function entries or data addresses (primary labels) and return compact per-address success booleans instead of a dossier. Ghidra rejects batch addresses that request the same name or a name another selected address holds; `raw_result.failures` gives each failure's reason.
|
||||
@@ -784,160 +438,39 @@ architecture, provider-owned mapping and selected-image commitments. Equal
|
||||
numeric addresses alone cannot establish correspondence; inspect retained
|
||||
source Evidence and coverage when the match remains ambiguous.
|
||||
|
||||
## Offline PE resource inventory
|
||||
## Other artifact guides
|
||||
|
||||
Use `inspect_pe_resources` with an absolute `path`, or
|
||||
`rea inspect-pe-resources ./selected.exe --json`, for portable PE32/PE32+
|
||||
resource inspection without opening a native target. Preserve returned Evidence:
|
||||
type/name/language IDs and UTF-16 names, original directory/data/payload ranges,
|
||||
code pages, payload hashes and static icon-group references. Same-language icon
|
||||
resolution is explicit; missing references and size mismatch remain visible.
|
||||
Other payloads are opaque, and this operation does not decode images or simulate
|
||||
Windows resource loading. Consult the budgets and supported tree profile in
|
||||
[offline binary diagnostics](https://github.com/morluto/rea/blob/main/docs/guides/native/binary-diagnostics.md).
|
||||
Read the owning page for offline formats, containers or firmware. These explicit
|
||||
anchors preserve older links without creating duplicate searchable sections.
|
||||
|
||||
## Offline PE and ELF export tables
|
||||
|
||||
Use `inspect_native_exports` with an absolute `path`, or
|
||||
`rea inspect-native-exports ./libexample.so --json`, to read a PE export
|
||||
directory or ELF dynamic symbol table on any host without opening a native
|
||||
target. Ordinal-only, forwarded and hidden-version exports stay distinct;
|
||||
partial or unsupported coverage means the inventory is incomplete, not that
|
||||
exports are absent. Use `inspect_macho` for Mach-O. See
|
||||
[offline binary diagnostics](https://github.com/morluto/rea/blob/main/docs/guides/native/binary-diagnostics.md).
|
||||
|
||||
For exact core-module import/export differences, use `compare_wasm_interfaces`
|
||||
with two complete inspection Evidence records (or current-session retained
|
||||
references) and explicit scope. Preserve unknown types/duplicate names; static
|
||||
interface equality is not runtime compatibility. CLI accepts complete inline
|
||||
Evidence in `rea compare-wasm-interfaces input.json --json`, or exact references
|
||||
with `--evidence-bundle /absolute/path/evidence.json`. Use the complete parent
|
||||
ID when the inspection returned a summary.
|
||||
|
||||
## Godot PCK
|
||||
|
||||
For a standalone PCK, `open_binary` then `inspect_artifact` with
|
||||
`detail: "summary"` retains the complete static inventory. Use the returned
|
||||
`parent_evidence_id` with `inspect_analysis_view` inventory occurrences filtered
|
||||
by exact `logical_paths` or `occurrence_ids`, and join `artifact_id` to nodes
|
||||
filtered by `artifact_ids`. Select only needed fields; identity links remain.
|
||||
Prefer `inspect-artifact --detail summary --evidence_output PATH` for CLI tasks;
|
||||
the same CLI discovers embedded packs via their EOF trailer without opening a
|
||||
native analysis provider. Normal native opening remains unchanged.
|
||||
|
||||
Distinguish declared MD5 from observed SHA-256 and graph/page completeness from
|
||||
`source_coverage`. Encrypted directories and sparse bundles have unknown entry
|
||||
coverage; encrypted members have unknown content identity. An empty filtered
|
||||
page cannot prove absence in unknown coverage. Retained views are historical,
|
||||
not fresh filesystem checks. No decryption, Godot resource decoding, GDScript
|
||||
decompilation or target execution is provided. See
|
||||
[Godot PCK](https://github.com/morluto/rea/blob/main/docs/godot-pck.md).
|
||||
|
||||
UnityFS AssetBundle containers (`.bundle`, `.ab`, YooAsset packages and other
|
||||
byte-identified files) list `CAB-*` SerializedFiles and `.resS` members with
|
||||
header and node facts; none/LZ4/LZ4HC member blocks stream on demand. Bundles
|
||||
declaring asset-bundle encryption keep header facts with unknown directory
|
||||
coverage; LZMA member bytes retain named occurrences with unavailable hashes.
|
||||
Virtual member offsets are not physical carrier locations. Format 6–8 readers
|
||||
cache one decoded block and support retained filtered/paged views. No
|
||||
decryption or SerializedFile object decoding is provided. See
|
||||
[UnityFS](https://github.com/morluto/rea/blob/main/docs/unityfs.md).
|
||||
|
||||
WeChat mini-program packages (`.wxapkg` files with `0xBE`/`0xED` marks) list
|
||||
members with declared names and absolute carrier offsets; member bytes are
|
||||
stored verbatim. `V1MMWX` PC-client packages report `encrypted` directory
|
||||
status with unknown coverage and are refused on extraction; no decryption is
|
||||
attempted. See
|
||||
[wxapkg](https://github.com/morluto/rea/blob/main/docs/wxapkg.md).
|
||||
|
||||
U-Boot legacy uImages use the same inspection/extraction workflows. Prefer a
|
||||
retained summary and selected inventory views for header facts or component
|
||||
IDs. Header addresses/CPU/OS are declarations; payloads remain as stored.
|
||||
Multi-file components retain their aligned physical ranges; the full payload
|
||||
is also materialized. Unknown name text retains its original 32 bytes. See
|
||||
[U-Boot uImage](https://github.com/morluto/rea/blob/main/docs/uimage.md).
|
||||
|
||||
## ESP images
|
||||
|
||||
For an ESP32-family app or bootloader image, `open_binary` then
|
||||
`inspect_artifact` with `detail: "summary"`. `root_format_metadata` holds the
|
||||
observed `header` and `descriptor` (its `kind` is the app or bootloader role)
|
||||
and the derived `chip`, `checksum`, `appended_sha256` and
|
||||
`undescribed_trailing` ranges. Segment rows (`segment-NN.bin`) carry
|
||||
`load_addr`, `classification` (`mapped`, `loaded`, `not-loaded` or `unknown`,
|
||||
per ESP-IDF `should_map`/`should_load`; RAM ranges are not checked) and
|
||||
`source_location`; select them with `inspect_analysis_view` and
|
||||
`logical_paths`. Signature blocks are `unverified`; `public_key_sha256`
|
||||
matches eFuse key digests.
|
||||
|
||||
Unknown `source_coverage` means truncation or undescribed trailing bytes, such
|
||||
as the flash segments of a `--ram-only-header` image; do not infer absence
|
||||
from it. Erased flash is described. Integrity mismatches are facts, not
|
||||
refusals. ESP8266 images are refused, and flash-encrypted images are not
|
||||
recognized. Segments are not disassembled, and RISC-V or Xtensa segments
|
||||
cannot be opened as raw-binary. See
|
||||
[ESP images](https://github.com/morluto/rea/blob/main/docs/esp-image.md).
|
||||
|
||||
## ESP flash images
|
||||
|
||||
A whole-flash dump opens as `esp-flash-image`. `root_format_metadata` holds
|
||||
`partition_table` (its `method`: `default`, `caller` or a derived
|
||||
`scan`), `bootloader` and `apps` ESP image facts, the `otadata` records,
|
||||
`partitions_outside_dump` and `boot_selection`. Every table has a
|
||||
`boot_selection`: its `basis` names the bootloader's branch (`no-otadata`
|
||||
without otadata, `none` when the bootloader rejects the table, `unknown`
|
||||
when a record is missing), and it lists its `assumptions`;
|
||||
`running_partition` is always `unknown`. Each image names its entry
|
||||
`path`. With `detail: "summary"` the root kind is `esp-flash-image-summary`
|
||||
and each image is a compact `summary` (chip, entry point, segment count,
|
||||
classified load ranges, signature block count, descriptor identity,
|
||||
integrity); complete detail keeps every segment. Partition rows
|
||||
(`partitions/<label>.bin`) carry the declared `type`, `subtype`, names,
|
||||
`flash_address`, `size` and flags; `encrypted` is a storage flag, not
|
||||
proof of ciphertext. `written_offset`/`written_end` bound the bytes that
|
||||
are not erased: an app slot whose facts say `erased` can still hold an older
|
||||
image, and a limitation says so. For a dump read from another flash address, call
|
||||
`open_binary` with `format: "esp-flash-image"` and `flash_offset`; an
|
||||
`esp-image` whose `flash_dump` is set names that offset in a next probe; a
|
||||
relocated table can be named with `partition_table_offset`. No table found
|
||||
means unknown, often flash encryption. Extraction writes `nvs_keys` as
|
||||
ordinary data. See
|
||||
[ESP flash images](https://github.com/morluto/rea/blob/main/docs/esp-flash-image.md).
|
||||
|
||||
## Bun standalone executables
|
||||
|
||||
A `bun build --compile` executable stores its module graph in Mach-O
|
||||
`__BUN,__bun`, a PE or ELF `.bun` section, or an appended trailer.
|
||||
`open_binary` then `inspect_artifact` reports root format `bun-standalone` with
|
||||
the carrier, structural layout, module count, entry point, raw flags and
|
||||
compile exec-argv; each module keeps its `/$bunfs/...` source name, loader,
|
||||
encoding, sizes and SHA-256, with sourcemap, bytecode and module-info regions as
|
||||
separate children. Use summary root metadata `entry_point_logical_path` as the
|
||||
exact inventory `logical_paths` selector, then read the selected content node by
|
||||
its artifact ID; the reader owns virtual-name normalization and indexed fallback. `extract-artifact` writes stored contents through the safe
|
||||
output tree; route extracted JavaScript to `analyze_javascript_application`.
|
||||
Layout labels describe record shapes, not a detected compiler version; unknown
|
||||
or ambiguous layouts are unsupported. Bytecode is retained, not decoded, and the
|
||||
executable is never run. See
|
||||
[Bun standalone executables](https://github.com/morluto/rea/blob/main/docs/bun-standalone.md).
|
||||
|
||||
## Deno compile executables
|
||||
|
||||
A `deno compile` executable stores its application in a Mach-O `__SUI,d3n0l4nd`
|
||||
section, an Intel Mach-O `<~sui-data~>` trailer, an ELF `SUI` note of type
|
||||
`0x53554901`, or a PE `RT_RCDATA` resource named `D3N0L4ND`.
|
||||
`open_binary` then `inspect_artifact` reports root format `deno-standalone`
|
||||
with the carrier, entry point, recorded options, and one occurrence per virtual
|
||||
file, including size and SHA-256. Transpiled output, CJS export analysis, and
|
||||
source maps are separate occurrences with the file's `index` and their own
|
||||
`role`. They normally use a `.deno-*` suffix on the file path and move to an
|
||||
indexed path on a collision, so use the reported `logical_path`. Symlink targets
|
||||
stay recorded path parts. A virtual filesystem that cannot be listed leaves
|
||||
coverage unknown.
|
||||
Environment-file values and CA certificate bytes are retained in local Evidence
|
||||
with their counts and byte lengths. The npm snapshot length is reported and not
|
||||
decoded. `extract-artifact` writes
|
||||
stored files through the safe output tree; route extracted JavaScript to
|
||||
`analyze_javascript_application`. Other layouts are unsupported, and the
|
||||
executable is never run. See
|
||||
[Deno compile executables](https://github.com/morluto/rea/blob/main/docs/deno-standalone.md).
|
||||
- <a id="go-build-metadata"></a>[Go build metadata](format-inspectors.md#go-build-metadata)
|
||||
- <a id="model-files"></a>[Model files](format-inspectors.md#model-files)
|
||||
- <a id="il2cpp-metadata"></a>[IL2CPP metadata](format-inspectors.md#il2cpp-metadata)
|
||||
- <a id="rust-dependency-metadata"></a>[Rust dependency metadata](format-inspectors.md#rust-dependency-metadata)
|
||||
- <a id="pe-authenticode-certificate-tables"></a>[PE Authenticode certificate tables](format-inspectors.md#pe-authenticode-certificate-tables)
|
||||
- <a id="pe-import-and-delay-load-tables"></a>[PE import and delay-load tables](format-inspectors.md#pe-import-and-delay-load-tables)
|
||||
- <a id="pe-tls-callbacks-and-load-configuration"></a>[PE TLS callbacks and load configuration](format-inspectors.md#pe-tls-callbacks-and-load-configuration)
|
||||
- <a id="binary-hardening"></a>[Binary hardening](format-inspectors.md#binary-hardening)
|
||||
- <a id="elf-note-tables"></a>[ELF note tables](format-inspectors.md#elf-note-tables)
|
||||
- <a id="apple-ips-crash-reports"></a>[Apple IPS crash reports](format-inspectors.md#apple-ips-crash-reports)
|
||||
- <a id="linux-kernel-modules"></a>[Linux kernel modules](format-inspectors.md#linux-kernel-modules)
|
||||
- <a id="cpython-pyc-files"></a>[CPython pyc files](format-inspectors.md#cpython-pyc-files)
|
||||
- <a id="erlang-beam-files"></a>[Erlang BEAM files](format-inspectors.md#erlang-beam-files)
|
||||
- <a id="sqlite-snapshots"></a>[SQLite snapshots](format-inspectors.md#sqlite-snapshots)
|
||||
- <a id="recorded-linux-crashes"></a>[Recorded Linux crashes](format-inspectors.md#recorded-linux-crashes)
|
||||
- <a id="offline-elf-layout"></a>[Offline ELF layout](format-inspectors.md#offline-elf-layout)
|
||||
- <a id="offline-wasm"></a>[Offline WASM](format-inspectors.md#offline-wasm)
|
||||
- <a id="offline-apk-signatures"></a>[Offline APK signatures](format-inspectors.md#offline-apk-signatures)
|
||||
- <a id="packages-and-extraction"></a>[Packages and extraction](packages-and-archives.md#packages-and-extraction)
|
||||
- <a id="offline-pe-resource-inventory"></a>[Offline PE resource inventory](format-inspectors.md#offline-pe-resource-inventory)
|
||||
- <a id="offline-pe-and-elf-export-tables"></a>[Offline PE and ELF export tables](format-inspectors.md#offline-pe-and-elf-export-tables)
|
||||
- <a id="godot-pck"></a>[Godot PCK](packages-and-archives.md#godot-pck)
|
||||
- <a id="esp-images"></a>[ESP images](firmware-and-raw-images.md#esp-images)
|
||||
- <a id="esp-flash-images"></a>[ESP flash images](firmware-and-raw-images.md#esp-flash-images)
|
||||
- <a id="bun-standalone-executables"></a>[Bun standalone executables](packages-and-archives.md#bun-standalone-executables)
|
||||
- <a id="release-exposure"></a>[Release exposure](format-inspectors.md#release-exposure)
|
||||
- <a id="windows-shell-link-shortcuts"></a>[Windows Shell Link shortcuts](format-inspectors.md#windows-shell-link-shortcuts)
|
||||
- <a id="elf-and-mach-o-initializer-functions"></a>[ELF and Mach-O initializer functions](format-inspectors.md#elf-and-mach-o-initializer-functions)
|
||||
- <a id="elf-unwind-function-ranges"></a>[ELF unwind function ranges](format-inspectors.md#elf-unwind-function-ranges)
|
||||
- <a id="linux-kernel-build-config"></a>[Linux kernel build config](format-inspectors.md#linux-kernel-build-config)
|
||||
- <a id="deno-compile-executables"></a>[Deno compile executables](packages-and-archives.md#deno-compile-executables)
|
||||
@@ -0,0 +1,146 @@
|
||||
# Packages and archives
|
||||
|
||||
Read only the sections needed for the selected task.
|
||||
|
||||
- [Packages and extraction](#packages-and-extraction)
|
||||
- [Godot PCK](#godot-pck)
|
||||
- [Bun standalone executables](#bun-standalone-executables)
|
||||
- [Deno compile executables](#deno-compile-executables)
|
||||
|
||||
## Packages and extraction
|
||||
|
||||
For PyInstaller executables, the CArchive is the application layer; the native
|
||||
bootloader is only its prefix. Prefer summary delivery for large inventories,
|
||||
then retained inventory views with selected member fields/pages. Runtime options
|
||||
are metadata, not files. Compact delivery still inventories and hashes members.
|
||||
A small complete inventory can cost less than extra calls and schemas. See the
|
||||
[Python packaged applications guide](https://github.com/morluto/rea/blob/main/docs/python-packaged-applications.md).
|
||||
|
||||
Use `inspect_artifact` for application bundles, archives, ZIP/APK/IPA/MSIX/AppX,
|
||||
ASAR, or DMG inputs when the artifact graph and findings help answer the
|
||||
question. It returns the complete artifact graph inline. Cite graph manifest
|
||||
IDs when using them.
|
||||
|
||||
For an IPA or a macOS `.app`, ZIP, or DMG, pass the inventory Evidence to
|
||||
`project_apple_application_graph`. It reports application roots and nested
|
||||
bundles by path convention: app extensions, XPC services, frameworks, login
|
||||
items, system and driver extensions, and plug-ins. It also lists privileged
|
||||
helpers, launchd plists, symlinks, and each bundle's `info_plist_path` and
|
||||
executable candidates. Roles are path conventions, not parsed plists; read the
|
||||
listed plists with `inspect_plist`.
|
||||
|
||||
After `open_binary` on a `.app` or Mach-O, use `trace_dylib_resolution` to see
|
||||
which file each `@rpath`, `@loader_path` and `@executable_path` load reaches for
|
||||
every executable in the bundle. It also lists missing or weak loads and earlier
|
||||
`@rpath` candidates that are absent. Narrow large bundles with `roots` or
|
||||
`architecture`. System paths stay undetermined because the dyld shared cache
|
||||
provides them.
|
||||
|
||||
Use `extract_artifact` when materialized files from a supported format are needed.
|
||||
It extracts the active target and accepts optional `integrity_policy`; see the [MCP contracts](https://github.com/morluto/rea/blob/main/docs/reference/mcp-contracts.md).
|
||||
It materializes all regular files into a fresh temporary directory chosen by
|
||||
REA. Symlinks and encrypted entries are inventory facts, not extractable files.
|
||||
The result reports the materialized directory; callers do not choose the
|
||||
destination. No separate permission grant is needed.
|
||||
|
||||
For classic iNES cartridges, `open_binary` recognizes the byte signature without
|
||||
an executable architecture. `inspect_artifact` retains header facts and each
|
||||
PRG/CHR file unit's offset, length and SHA-256; its nested inventory's
|
||||
`ines.reconstruction` verifies the actual ordered region bytes against the
|
||||
whole-file digest. Extraction includes the original header, optional trainer
|
||||
and uninterpreted trailing bytes. These file units are not mapper/CPU bank
|
||||
maps. NES 2.0, UNIF, dirty legacy headers and truncated payloads are explicitly
|
||||
refused. No emulator or 6502 analysis is performed. See the
|
||||
[iNES guide](https://github.com/morluto/rea/blob/main/docs/ines-containers.md).
|
||||
|
||||
Native DMG traversal automatically uses a read-only mount on supported macOS
|
||||
hosts, with an owned temporary mount directory and cleanup. It needs no approval
|
||||
flag. Unsupported hosts or mount failures remain explicit limitations; do not
|
||||
claim child inventory when only root identity is available. DMG extraction is
|
||||
unavailable through `extract_artifact`. To access DMG files on macOS, create a
|
||||
read-only mount with your own tools, select files from that mount for analysis,
|
||||
and detach the mount you created when finished. REA's inspection mount is
|
||||
temporary, not a retained export of the image's contents.
|
||||
|
||||
Use `inspect_byte_entropy` to triage high- and low-entropy ranges before extraction.
|
||||
|
||||
## Godot PCK
|
||||
|
||||
For a standalone PCK, `open_binary` then `inspect_artifact` with
|
||||
`detail: "summary"` retains the complete static inventory. Use the returned
|
||||
`parent_evidence_id` with `inspect_analysis_view` inventory occurrences filtered
|
||||
by exact `logical_paths` or `occurrence_ids`, and join `artifact_id` to nodes
|
||||
filtered by `artifact_ids`. Select only needed fields; identity links remain.
|
||||
Prefer `inspect-artifact --detail summary --evidence_output PATH` for CLI tasks;
|
||||
the same CLI discovers embedded packs via their EOF trailer without opening a
|
||||
native analysis provider. Normal native opening remains unchanged.
|
||||
|
||||
Distinguish declared MD5 from observed SHA-256 and graph/page completeness from
|
||||
`source_coverage`. Encrypted directories and sparse bundles have unknown entry
|
||||
coverage; encrypted members have unknown content identity. An empty filtered
|
||||
page cannot prove absence in unknown coverage. Retained views are historical,
|
||||
not fresh filesystem checks. No decryption, Godot resource decoding, GDScript
|
||||
decompilation or target execution is provided. See
|
||||
[Godot PCK](https://github.com/morluto/rea/blob/main/docs/godot-pck.md).
|
||||
|
||||
UnityFS AssetBundle containers (`.bundle`, `.ab`, YooAsset packages and other
|
||||
byte-identified files) list `CAB-*` SerializedFiles and `.resS` members with
|
||||
header and node facts; none/LZ4/LZ4HC member blocks stream on demand. Bundles
|
||||
declaring asset-bundle encryption keep header facts with unknown directory
|
||||
coverage; LZMA member bytes retain named occurrences with unavailable hashes.
|
||||
Virtual member offsets are not physical carrier locations. Format 6–8 readers
|
||||
cache one decoded block and support retained filtered/paged views. No
|
||||
decryption or SerializedFile object decoding is provided. See
|
||||
[UnityFS](https://github.com/morluto/rea/blob/main/docs/unityfs.md).
|
||||
|
||||
WeChat mini-program packages (`.wxapkg` files with `0xBE`/`0xED` marks) list
|
||||
members with declared names and absolute carrier offsets; member bytes are
|
||||
stored verbatim. `V1MMWX` PC-client packages report `encrypted` directory
|
||||
status with unknown coverage and are refused on extraction; no decryption is
|
||||
attempted. See
|
||||
[wxapkg](https://github.com/morluto/rea/blob/main/docs/wxapkg.md).
|
||||
|
||||
U-Boot legacy uImages use the same inspection/extraction workflows. Prefer a
|
||||
retained summary and selected inventory views for header facts or component
|
||||
IDs. Header addresses/CPU/OS are declarations; payloads remain as stored.
|
||||
Multi-file components retain their aligned physical ranges; the full payload
|
||||
is also materialized. Unknown name text retains its original 32 bytes. See
|
||||
[U-Boot uImage](https://github.com/morluto/rea/blob/main/docs/uimage.md).
|
||||
|
||||
## Bun standalone executables
|
||||
|
||||
A `bun build --compile` executable stores its module graph in Mach-O
|
||||
`__BUN,__bun`, a PE or ELF `.bun` section, or an appended trailer.
|
||||
`open_binary` then `inspect_artifact` reports root format `bun-standalone` with
|
||||
the carrier, structural layout, module count, entry point, raw flags and
|
||||
compile exec-argv; each module keeps its `/$bunfs/...` source name, loader,
|
||||
encoding, sizes and SHA-256, with sourcemap, bytecode and module-info regions as
|
||||
separate children. Use summary root metadata `entry_point_logical_path` as the
|
||||
exact inventory `logical_paths` selector, then read the selected content node by
|
||||
its artifact ID; the reader owns virtual-name normalization and indexed fallback. `extract-artifact` writes stored contents through the safe
|
||||
output tree; route extracted JavaScript to `analyze_javascript_application`.
|
||||
Layout labels describe record shapes, not a detected compiler version; unknown
|
||||
or ambiguous layouts are unsupported. Bytecode is retained, not decoded, and the
|
||||
executable is never run. See
|
||||
[Bun standalone executables](https://github.com/morluto/rea/blob/main/docs/bun-standalone.md).
|
||||
|
||||
## Deno compile executables
|
||||
|
||||
A `deno compile` executable stores its application in a Mach-O `__SUI,d3n0l4nd`
|
||||
section, an Intel Mach-O `<~sui-data~>` trailer, an ELF `SUI` note of type
|
||||
`0x53554901`, or a PE `RT_RCDATA` resource named `D3N0L4ND`.
|
||||
`open_binary` then `inspect_artifact` reports root format `deno-standalone`
|
||||
with the carrier, entry point, recorded options, and one occurrence per virtual
|
||||
file, including size and SHA-256. Transpiled output, CJS export analysis, and
|
||||
source maps are separate occurrences with the file's `index` and their own
|
||||
`role`. They normally use a `.deno-*` suffix on the file path and move to an
|
||||
indexed path on a collision, so use the reported `logical_path`. Symlink targets
|
||||
stay recorded path parts. A virtual filesystem that cannot be listed leaves
|
||||
coverage unknown.
|
||||
Environment-file values and CA certificate bytes are retained in local Evidence
|
||||
with their counts and byte lengths. The npm snapshot length is reported and not
|
||||
decoded. `extract-artifact` writes
|
||||
stored files through the safe output tree; route extracted JavaScript to
|
||||
`analyze_javascript_application`. Other layouts are unsupported, and the
|
||||
executable is never run. See
|
||||
[Deno compile executables](https://github.com/morluto/rea/blob/main/docs/deno-standalone.md).
|
||||
@@ -0,0 +1,58 @@
|
||||
# Recorded captures and decoder discovery
|
||||
|
||||
## Historical web captures
|
||||
|
||||
Retained HAR/SAZ/native mitmproxy/aioquic qlog capture: `inspect_web_network_capture`. Select
|
||||
original record ordinals when useful; inspect producer fields and byte/number
|
||||
sidecars without fetching recorded URLs or claiming live attribution. For a decoder heap refusal, follow the reported `capture.decoder_old_generation_mib`
|
||||
setting and bounds with `update_analysis_settings` (default 192 MiB, floor 8,
|
||||
maximum 16384); the launch seed
|
||||
`REA_CAPTURE_DECODER_OLD_GENERATION_MIB` affects future REA processes. Host memory
|
||||
and `NODE_OPTIONS` do not raise that decoder allowance. See
|
||||
[historical captures](https://github.com/morluto/rea/blob/main/docs/guides/web/web-network-captures.md) for the exact upstream
|
||||
profile and credential exclusions. Qlog support starts with aioquic 1.5.0
|
||||
JSON 0.3; stream coverage and endpoint loss declarations do not recover bodies
|
||||
or establish network loss. Prefer detail summary, then kind qlog trace/stream
|
||||
pages; select one trace, stream ID and direction for contribution/range pages.
|
||||
Facts retain all-recorded-events-before-selection scope. Other qlog layouts
|
||||
and PCAP correlation are unsupported.
|
||||
|
||||
## Packet fields and packet captures
|
||||
|
||||
Packet-field discovery: `inspect_packet_fields` searches installed protocols
|
||||
and field names/types before choosing fields for `inspect_packet_capture`.
|
||||
Query/page the relevant records; registrations do not establish observed traffic.
|
||||
|
||||
## Packet capture inspection
|
||||
|
||||
Recorded packet captures: `inspect_packet_capture` with selected TShark fields,
|
||||
display filters and decode-as rules. Requires Linux, util-linux prlimit and
|
||||
TShark 4.x on an absolute `PATH` entry or via the optional absolute
|
||||
`REA_TSHARK_COMMAND` override; see
|
||||
[capture guide](https://github.com/morluto/rea/blob/main/docs/guides/data/packet-captures.md).
|
||||
Packet limits count input packets before filtering. Output defaults to 50 matching
|
||||
frames; use `match_offset` / `match_limit` for later pages, or explicit null
|
||||
limit for complete matching output. Preserve the source digest across pages.
|
||||
This does not perform live capture.
|
||||
For address/DNS/SNI/protocol summaries use `inspect_pcap_capture` with MCP
|
||||
detail summary, then retained kind pcap pages. Requires Wireshark 4.x tshark
|
||||
and capinfos, with Linux prlimit or Windows Job Objects; see
|
||||
[packet summaries](https://github.com/morluto/rea/blob/main/docs/guides/data/pcap-analysis.md).
|
||||
Select an exact DNS question for address pages; page exhaustion does not prove
|
||||
network completeness. This reads recordings and does not acquire traffic.
|
||||
|
||||
## Signal decoder discovery
|
||||
|
||||
Decoder discovery: `inspect_signal_decoders` searches installed decoder IDs
|
||||
or selected decoder help, including channels and options. Query and page the
|
||||
relevant details before choosing settings; this does not scan hardware.
|
||||
|
||||
## Recorded logic and signals
|
||||
|
||||
Recorded logic/signal traces: `decode_signal_recording` with explicit decoder,
|
||||
channel and protocol settings. On Linux with util-linux prlimit, supply sigrok-cli 0.7.2 through
|
||||
`REA_SIGROK_COMMAND`; see [recording guide](https://github.com/morluto/rea/blob/main/docs/guides/signals/signal-recordings.md).
|
||||
Output defaults to 50 literal lines; select annotation classes and page with
|
||||
`line_offset` / `line_limit`, or explicit null for all remaining output.
|
||||
Window counts are display lines, not annotations or samples. Preserve source digests across pages.
|
||||
This reads existing files; it does not acquire hardware signals.
|
||||
@@ -1,5 +1,12 @@
|
||||
# Runtime observation
|
||||
|
||||
Read only the sections needed for the selected task.
|
||||
|
||||
- [Native runtime questions](#native-runtime-questions)
|
||||
- [Browser and Electron](#browser-and-electron)
|
||||
- [Who performs the action](#who-performs-the-action)
|
||||
- [Fiddler Everywhere traffic debugging](#fiddler-everywhere-traffic-debugging)
|
||||
|
||||
## Native runtime questions
|
||||
|
||||
Start from the requested observation. State the selected target, input, expected
|
||||
@@ -54,6 +61,18 @@ and [native calls/UI](https://github.com/morluto/rea/blob/main/docs/guides/nativ
|
||||
|
||||
## Browser and Electron
|
||||
|
||||
Passive traffic capture of a SPA: the default scope is the page's own origin,
|
||||
and data APIs usually live on another origin. Discover API origins from
|
||||
absolute URLs in loaded bundles or script text via JavaScript analysis tools
|
||||
(another passive capture without those origins still scopes to the page
|
||||
origin, and `completeness.excluded` counts lack URLs). Pass both the page
|
||||
origin and those API origins in `allowed_origins` — the list replaces the
|
||||
default scope — and read `completeness.excluded` before reporting that an
|
||||
API is absent. For long captures with body shapes, use
|
||||
`export_evidence_bundle` instead of expecting an inline result.
|
||||
|
||||
User-owned Electron runtime already open: `list_electron_targets`. Before an electron-main Inspector attempt, check packaged fuses with `inspect_electron_fuses`; disabled `EnableNodeCliInspectArguments` means the app ignores `--inspect`.
|
||||
|
||||
Supply the existing browser or Electron instance's literal-port loopback CDP
|
||||
endpoint in the request. No separate permission configuration or per-call
|
||||
approval flag is needed. Browser discovery lists eligible HTTP(S) pages;
|
||||
|
||||
@@ -464,9 +464,7 @@ class ReaJadxBridge {
|
||||
if (element.getTagName().equals("uses-sdk")) {
|
||||
minSdk = element.getAttributeNS(android, "minSdkVersion");
|
||||
targetSdk = element.getAttributeNS(android, "targetSdkVersion");
|
||||
} else if (element.getTagName().equals("uses-permission")
|
||||
|| element.getTagName().equals("uses-permission-sdk-23")
|
||||
|| element.getTagName().equals("uses-permission-sdk-m")) {
|
||||
} else if (element.getTagName().equals("uses-permission")) {
|
||||
String permission = element.getAttributeNS(android, "name");
|
||||
if (!permission.isEmpty()) permissions.add(permission);
|
||||
}
|
||||
|
||||
@@ -958,6 +958,15 @@ class _BridgeServer(threading.Thread):
|
||||
proof.update(fragment.encode("utf-8"))
|
||||
return proof.hexdigest()
|
||||
|
||||
def _encode_authenticated_response(
|
||||
self, value: dict[str, Any], client_nonce: str, server_nonce: str
|
||||
) -> bytes | None:
|
||||
"""Return one exact frame. The socket path writes the same pieces."""
|
||||
proof = self._authenticated_proof(value, client_nonce, server_nonce)
|
||||
if proof is None:
|
||||
return None
|
||||
return b"".join(self._iter_authenticated_frame(value, proof))
|
||||
|
||||
def _iter_authenticated_frame(self, value: dict[str, Any], proof: str):
|
||||
yield _AUTHENTICATED_PREFIX
|
||||
for fragment in _response_fragments(value):
|
||||
|
||||
@@ -154,6 +154,13 @@ class HopperApiFacade:
|
||||
)
|
||||
|
||||
|
||||
def _configure_hopper_api(document_provider):
|
||||
"""Inject Hopper's document provider or a standalone test facade."""
|
||||
global _hopper_api, _rea_session_document
|
||||
_hopper_api = HopperApiFacade(document_provider)
|
||||
_rea_session_document = None
|
||||
|
||||
|
||||
def _api():
|
||||
"""Resolve Hopper globals lazily so importing this module needs no Hopper."""
|
||||
global _hopper_api
|
||||
|
||||
@@ -215,10 +215,7 @@ Resolution follows dyld:
|
||||
image that loaded it, up to the process root.
|
||||
- Dependencies load dependents-first in load-command order, and each image
|
||||
loads once per process. A later @rpath request whose install name matches an
|
||||
already loaded image reuses it. Loading an image and expanding its dependencies
|
||||
are separate: an already loaded sibling can first be expanded through another
|
||||
dependency, inheriting that traversal's rpath stack. Cycles do not expand an
|
||||
image twice, and lazy edges do not establish a launch-time traversal chain.
|
||||
already loaded image reuses it.
|
||||
- Symlinks such as `Versions/Current` are followed inside the analyzed root.
|
||||
An escape through `..` or an absolute link is `escapes-target`.
|
||||
- Dyld path components are POSIX names. On Windows hosts, link text uses `\`
|
||||
@@ -255,12 +252,8 @@ one of:
|
||||
|
||||
A `conditional` image is still traced, because it is an in-root candidate
|
||||
that may load. Every edge below it has `loader_conditional: true`, and a
|
||||
request that reuses it by install name is `conditional` too. A definitely loaded
|
||||
image can also first expand through a conditional chain: its dependency edges
|
||||
then have `loader_conditional: true`, while later reuse of the image retains its
|
||||
definite first-load result.
|
||||
|
||||
An in-root dylib with no platform load command remains unknown unless the root is an executable
|
||||
request that reuses it by install name is `conditional` too. An in-root dylib
|
||||
with no platform load command remains unknown unless the root is an executable
|
||||
with observed macOS platform and the candidate's CPU type is x86_64, i386, or arm64. In that macOS context,
|
||||
[Apple's dyld](https://github.com/apple-oss-distributions/dyld/blob/fd8d0c4d52320ebf64db34f3cb280310d905c5ae/mach_o/UnsafeHeader.cpp#L1137-L1145) supplies an implicit macOS platform to legacy dylibs on those CPU
|
||||
types. The candidate records `platform_basis: "macos-dyld-implicit"`; the
|
||||
|
||||
@@ -222,7 +222,7 @@ cannot answer, such as an address without one exact file offset, omits this
|
||||
hint; follow its `remediation.action`. `recovery.kind=inspect_timeout_state` names
|
||||
the operation and the REA server/provider deadline. Inspect partial Evidence
|
||||
and reported cleanup state, then follow the returned remediation. Change a
|
||||
request field or REA\_\* setting only when the returned remediation explicitly
|
||||
request field or REA_* setting only when the returned remediation explicitly
|
||||
recommends that change. Restart REA when that text says the value is read at
|
||||
startup. A mention that a control does not raise the deadline is not a
|
||||
recommendation to change it. When it names no setting, reduce supported work;
|
||||
@@ -1065,17 +1065,6 @@ from an older request does not override a newer outcome. Request deadlines and
|
||||
cancellations neither mark nor clear availability. A new provider client starts
|
||||
without these outcomes.
|
||||
|
||||
A `provider_missing` group may also list `alternatives`: advertised tools the
|
||||
current provider makes available for part of that operation's question. When
|
||||
the provider does not declare `next_address` or `prev_address`, they list
|
||||
whichever of `inspect_native_instruction`, `read_function_instructions` and
|
||||
`procedure_assembly` qualify. These answer instruction-level questions only:
|
||||
none navigates arbitrary analyzed objects such as data or addresses outside a
|
||||
procedure, and neither listing order nor address plus length proves executed
|
||||
control flow. Calling the missing operation returns `capability_unavailable`
|
||||
with the same tools in `details.alternatives` and a remediation stating each
|
||||
one's scope. Without a qualifying alternative, both keep their generic advice.
|
||||
|
||||
Standalone command operations (such as `inspect_with_objdump` and
|
||||
`execute_rizin_command`) similarly reflect observed executable launch failures:
|
||||
an unprobed executable is reported available; once a launch failure is observed,
|
||||
@@ -1922,10 +1911,13 @@ support for omitted historical values.
|
||||
known and differ. If only one value is known, storage comparison is unknown;
|
||||
when both are omitted, storage is not compared.
|
||||
|
||||
`compare_artifacts` also compares the declarations in the `format_metadata` of <!-- BEGIN:compare-artifacts:compared-format-metadata-kinds -->UnityFS members (`unityfs-entry`), PyInstaller entries
|
||||
<!-- BEGIN:compare-artifacts:compared-format-metadata-kinds -->
|
||||
|
||||
`compare_artifacts` also compares the declarations in the `format_metadata`
|
||||
of UnityFS members (`unityfs-entry`), PyInstaller entries
|
||||
(`pyinstaller-entry`), Node SEA members (`node-sea-entry`),
|
||||
ESP image segments (`esp-image-segment`), DfuSe elements (`dfuse-element`),
|
||||
ESP flash partitions (`esp-flash-partition`) and FIT images (`fit-image`)<!-- END:compare-artifacts:compared-format-metadata-kinds -->;
|
||||
ESP flash partitions (`esp-flash-partition`) and FIT images (`fit-image`);
|
||||
each format's guide names the compared fields. A changed declaration is a
|
||||
metadata change, including when content is unavailable. A declaration that
|
||||
only one side records, or that the other side records as another kind, is
|
||||
@@ -1936,6 +1928,8 @@ container or from caller options that identify the target, or repeat
|
||||
occurrence fields, except Godot PCK source paths, which
|
||||
[Godot PCK archives](../godot-pck.md) explains.
|
||||
|
||||
<!-- END:compare-artifacts:compared-format-metadata-kinds -->
|
||||
|
||||
Every occurrence records `entry_kind`, `executable` and `encrypted`. A
|
||||
different entry kind or `encrypted` value is a `metadata` difference, and a
|
||||
different `executable` value is an `executable` difference. Occurrence and node
|
||||
|
||||
@@ -10,8 +10,8 @@
|
||||
4. Verifier: `appTaskPython.ts` renders `READER_RUNNER`, `READERS`,
|
||||
`_reader_views` and `evaluate_with_readers` only for a task with readers,
|
||||
so a task without renders as before.
|
||||
5. Application: `readerViewsOfBytes` in `DesktopTaskReaders.ts`;
|
||||
`runReaderHere` in `src/desktop/TaskReaderProcess.ts`;
|
||||
5. Application: `readTaskReaderViews` and `readerViewsOfBytes` in
|
||||
`DesktopTaskReaders.ts`; `runReaderHere` in `src/desktop/TaskReaderProcess.ts`;
|
||||
the witness runs readers through `AgentEnvComputer.exec`; the export runs
|
||||
them on `shippedSeedBytes` and the end's retained content.
|
||||
6. Docs: the tasks reference, the witness page, the build skill's recipes for
|
||||
|
||||
@@ -5,8 +5,7 @@ import { fileURLToPath, pathToFileURL } from "node:url";
|
||||
|
||||
/**
|
||||
* Reduce filesystem resolution during CLI and MCP startup. Keep dependencies
|
||||
* external and original compiled worker entrypoints. Dynamic imports can split
|
||||
* into lazy chunks unless the same module is also statically reachable.
|
||||
* external, dynamic imports lazy, and original compiled worker entrypoints.
|
||||
*/
|
||||
export const bundleRuntime = async (root) => {
|
||||
const compiledRoot = resolve(root, "dist");
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { execFile } from "node:child_process";
|
||||
import { mkdir, writeFile } from "node:fs/promises";
|
||||
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
||||
import { dirname, join, resolve } from "node:path";
|
||||
import { promisify } from "node:util";
|
||||
import { fileURLToPath } from "node:url";
|
||||
|
||||
@@ -19,11 +19,6 @@ if (
|
||||
const child = spawn(
|
||||
process.execPath,
|
||||
[
|
||||
// Reuse the development runner's POSIX process-group owner. Windows
|
||||
// source tests must remain usable without the built native Job Object.
|
||||
...(process.platform === "win32"
|
||||
? []
|
||||
: [resolve("scripts/run-exclusive.mjs"), "--unlocked", process.execPath]),
|
||||
resolve("node_modules/vitest/vitest.mjs"),
|
||||
"run",
|
||||
...projects.flatMap(({ name }) => ["--project", name]),
|
||||
|
||||
@@ -37,22 +37,21 @@ const generated = addSkillManifestToolCount(
|
||||
FULL_CATALOG_IDENTITY.counts.mcp_tools,
|
||||
);
|
||||
if (!generated.ok) throw generated.error;
|
||||
const source = generated.value.replaceAll(latestSpecifier, pinnedSpecifier);
|
||||
const paths = await filePaths(sourceRoot);
|
||||
// Rebuild this owned output directory so removed references cannot survive a build.
|
||||
if (!check) await rm(outputRoot, { recursive: true, force: true });
|
||||
for (const relativePath of paths) {
|
||||
const path = join(outputRoot, relativePath);
|
||||
if (!check) await mkdir(dirname(path), { recursive: true });
|
||||
const content =
|
||||
relativePath === "SKILL.md"
|
||||
? generated.value
|
||||
: await readFile(join(sourceRoot, relativePath), "utf8");
|
||||
await ensureGeneratedFile({
|
||||
path,
|
||||
source:
|
||||
relativePath === "SKILL.md"
|
||||
? source
|
||||
: (await readFile(join(sourceRoot, relativePath), "utf8")).replaceAll(
|
||||
"\r\n",
|
||||
"\n",
|
||||
),
|
||||
source: content
|
||||
.replaceAll("\r\n", "\n")
|
||||
.replaceAll(latestSpecifier, pinnedSpecifier),
|
||||
check,
|
||||
generateCommand: "npm run docs:generate",
|
||||
});
|
||||
|
||||
@@ -2,17 +2,6 @@ import type {
|
||||
Client,
|
||||
CallToolRequestOptions,
|
||||
} from "@modelcontextprotocol/client";
|
||||
import type { VerifierCommands } from "./verify-commands.mjs";
|
||||
|
||||
/** Keep the opened target and its owned stdio server alive through verification. */
|
||||
export function withArtifactMcp(
|
||||
target: string,
|
||||
verify: (client: Client) => Promise<void>,
|
||||
options?: {
|
||||
readonly commands?: VerifierCommands;
|
||||
readonly signal?: AbortSignal;
|
||||
},
|
||||
): Promise<void>;
|
||||
|
||||
/** Call with the server's advertised schema; callers cannot replace it. */
|
||||
export function artifactMcpCall(
|
||||
|
||||
@@ -15,7 +15,6 @@ export function parseDevelopmentTestRequest(
|
||||
export function developmentTestPlan(
|
||||
request: DevelopmentTestRequest,
|
||||
baseCommit?: string,
|
||||
resolvedPaths?: readonly string[],
|
||||
): {
|
||||
readonly needsBuild: boolean;
|
||||
readonly artifactTasks: readonly string[];
|
||||
|
||||
@@ -58,11 +58,7 @@ const artifactConsumers = {
|
||||
};
|
||||
|
||||
/** Plan source feedback or explicit tests with their runtime/artifact prerequisites. */
|
||||
export const developmentTestPlan = (
|
||||
request,
|
||||
baseCommit,
|
||||
resolvedPaths = request.paths,
|
||||
) => {
|
||||
export const developmentTestPlan = (request, baseCommit) => {
|
||||
const explicit = request.paths.length > 0;
|
||||
if (
|
||||
request.mode === "changed" &&
|
||||
@@ -74,12 +70,12 @@ export const developmentTestPlan = (
|
||||
? []
|
||||
: SOURCE_TEST_PROJECTS.map(({ name }) => name);
|
||||
return {
|
||||
needsBuild: resolvedPaths.some(
|
||||
needsBuild: request.paths.some(
|
||||
(path) => projectForTest(path).group === "built",
|
||||
),
|
||||
artifactTasks: Object.entries(artifactConsumers).flatMap(
|
||||
([task, consumers]) =>
|
||||
resolvedPaths.some((path) => consumers.includes(path)) ? [task] : [],
|
||||
request.paths.some((path) => consumers.includes(path)) ? [task] : [],
|
||||
),
|
||||
vitestArguments: [
|
||||
"run",
|
||||
|
||||
@@ -10,6 +10,7 @@ import { access, readFile, readdir, stat } from "node:fs/promises";
|
||||
import { dirname, join } from "node:path";
|
||||
import { setTimeout as delay } from "node:timers/promises";
|
||||
import { promisify } from "node:util";
|
||||
import { GHIDRA_ANNOTATIONS_RETAINED } from "../../dist/ghidra/GhidraProviderClient.js";
|
||||
import Ajv from "ajv/dist/2020.js";
|
||||
import addFormats from "ajv-formats";
|
||||
import { OFFICIAL_TOOL_CONTRACTS } from "../../dist/contracts/officialToolContracts.js";
|
||||
@@ -570,11 +571,7 @@ export async function verifyGhidraBoundaries(
|
||||
// The producer reason describes the failure; continuing-session guidance
|
||||
// is projected separately and the following live calls verify it.
|
||||
assert.match(regexError.details.reason, /stack while matching pattern/u);
|
||||
assert.ok(
|
||||
regexError.message.includes(
|
||||
"The active analysis session and annotations remain available.",
|
||||
),
|
||||
);
|
||||
assert.ok(regexError.message.includes(GHIDRA_ANNOTATIONS_RETAINED));
|
||||
rejectedCalls++;
|
||||
const nestedPattern = "(".repeat(12000) + "a" + ")".repeat(12000);
|
||||
const compileFailure = await client.callTool(
|
||||
|
||||
@@ -2,7 +2,10 @@ import { randomUUID } from "node:crypto";
|
||||
|
||||
import type { RetainedResourceScope } from "../../src/application/AnalysisProvider.js";
|
||||
import { AnalysisCleanupLease } from "../../src/artifacts/AnalysisCleanupLease.js";
|
||||
import { ArtifactResourceScope } from "../../src/artifacts/ArtifactResourceScope.js";
|
||||
import {
|
||||
ArtifactResourceScope,
|
||||
type ArtifactResourceOwner,
|
||||
} from "../../src/artifacts/ArtifactResourceScope.js";
|
||||
import {
|
||||
prepareOwnedCommand,
|
||||
runOwnedCommand,
|
||||
@@ -58,7 +61,6 @@ export interface VerifierCommands {
|
||||
arguments_: readonly string[],
|
||||
options?: VerifierCommandOptions,
|
||||
): Promise<VerifierCommandOutput>;
|
||||
/** Retain a live resource until close, independently of ordinary command execution. */
|
||||
adopt(owner: VerifierCleanupOwner, resource: string): void;
|
||||
readonly cleanupResources: readonly string[];
|
||||
close(): Promise<void>;
|
||||
@@ -150,17 +152,13 @@ const commandLimits = (options: VerifierCommandOptions) => {
|
||||
};
|
||||
};
|
||||
|
||||
type AdoptedVerifierOwner = {
|
||||
readonly kind: "lease";
|
||||
readonly resource: string;
|
||||
readonly lease: AnalysisCleanupLease;
|
||||
};
|
||||
|
||||
class VerifierCommandOwner implements VerifierCommands {
|
||||
readonly #resources = new ArtifactResourceScope();
|
||||
readonly #controller = new AbortController();
|
||||
readonly #adopted = new WeakMap<VerifierCleanupOwner, AdoptedVerifierOwner>();
|
||||
readonly #liveAdopted = new Set<AdoptedVerifierOwner>();
|
||||
readonly #adopted = new WeakMap<
|
||||
VerifierCleanupOwner,
|
||||
ArtifactResourceOwner
|
||||
>();
|
||||
readonly #resourceOwner: RetainedResourceScope;
|
||||
#closed = false;
|
||||
#released = false;
|
||||
@@ -172,21 +170,13 @@ class VerifierCommandOwner implements VerifierCommands {
|
||||
) => Promise<SpawnedOwnedProviderProcess>,
|
||||
) {
|
||||
this.#resourceOwner = {
|
||||
retain: (owner, resource) =>
|
||||
this.#resources.retain(this.#adoptedOwner(owner, resource)),
|
||||
retain: (owner, resource) => this.adopt(owner, resource),
|
||||
run: (work) => this.#resources.run(work),
|
||||
};
|
||||
}
|
||||
|
||||
get cleanupResources(): readonly string[] {
|
||||
return [
|
||||
...new Set([
|
||||
...this.#resources.cleanupResources,
|
||||
...[...this.#liveAdopted].flatMap(({ lease, resource }) =>
|
||||
lease.released ? [] : (lease.cleanupResources ?? [resource]),
|
||||
),
|
||||
]),
|
||||
];
|
||||
return this.#resources.cleanupResources;
|
||||
}
|
||||
|
||||
exec(
|
||||
@@ -243,15 +233,6 @@ class VerifierCommandOwner implements VerifierCommands {
|
||||
}
|
||||
|
||||
adopt(owner: VerifierCleanupOwner, resource: string): void {
|
||||
const retained = this.#adoptedOwner(owner, resource);
|
||||
if (this.#closed) this.#resources.retain(retained);
|
||||
else this.#liveAdopted.add(retained);
|
||||
}
|
||||
|
||||
#adoptedOwner(
|
||||
owner: VerifierCleanupOwner,
|
||||
resource: string,
|
||||
): AdoptedVerifierOwner {
|
||||
if (this.#released)
|
||||
throw new Error("Verifier command resource release has completed");
|
||||
let retained = this.#adopted.get(owner);
|
||||
@@ -263,18 +244,15 @@ class VerifierCommandOwner implements VerifierCommands {
|
||||
};
|
||||
this.#adopted.set(owner, retained);
|
||||
}
|
||||
return retained;
|
||||
// An admitted command can transfer a late preparation/cleanup capability
|
||||
// while close is joining it. Acquisition must precede this scope's release.
|
||||
this.#resources.retain(retained);
|
||||
}
|
||||
|
||||
close(): Promise<void> {
|
||||
this.#closed = true;
|
||||
this.#controller.abort(new Error("Verifier command owner closed"));
|
||||
if (this.#closing !== undefined) return this.#closing;
|
||||
// Live adoption owns a lifetime, not a failed cleanup. Only closure moves
|
||||
// these leases into the retry scope; command failures enter it immediately.
|
||||
// Late transfers during admitted work still join that same close below.
|
||||
for (const owner of this.#liveAdopted) this.#resources.retain(owner);
|
||||
this.#liveAdopted.clear();
|
||||
let attempt: Promise<void>;
|
||||
attempt = this.#resources
|
||||
.close()
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
import { spawn } from "node:child_process";
|
||||
import { realpath, stat } from "node:fs/promises";
|
||||
import { relative, resolve, sep } from "node:path";
|
||||
import { stat } from "node:fs/promises";
|
||||
import { resolve } from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
|
||||
import {
|
||||
developmentTestPlan,
|
||||
parseDevelopmentTestRequest,
|
||||
} from "./lib/development-tests.mjs";
|
||||
import { projectForTest } from "./lib/test-projects.mjs";
|
||||
|
||||
let child;
|
||||
let forceTimer;
|
||||
@@ -30,22 +29,9 @@ for (const signal of Object.keys(signalExitCodes))
|
||||
try {
|
||||
const [mode, ...arguments_] = process.argv.slice(2);
|
||||
const request = parseDevelopmentTestRequest(mode, arguments_);
|
||||
const resolvedPaths = [];
|
||||
const repository = await realpath(".");
|
||||
for (const path of request.paths) {
|
||||
if (!(await stat(path)).isFile())
|
||||
throw new Error(`Test path is not a file: ${path}`);
|
||||
// Ownership follows the filesystem's canonical spelling. Execution keeps
|
||||
// the caller path so exact discovery still rejects excluded symlink aliases.
|
||||
const resolvedPath = relative(repository, await realpath(path))
|
||||
.split(sep)
|
||||
.join("/");
|
||||
if (
|
||||
request.mode !== "focused" &&
|
||||
projectForTest(resolvedPath).group !== "source"
|
||||
)
|
||||
throw new Error(`Use test:focused for built test projects: ${path}`);
|
||||
resolvedPaths.push(resolvedPath);
|
||||
}
|
||||
let baseCommit;
|
||||
if (request.mode === "changed") {
|
||||
@@ -56,7 +42,7 @@ try {
|
||||
);
|
||||
baseCommit = base.output.trim();
|
||||
}
|
||||
const plan = developmentTestPlan(request, baseCommit, resolvedPaths);
|
||||
const plan = developmentTestPlan(request, baseCommit);
|
||||
if (request.dryRun) {
|
||||
console.log(JSON.stringify({ ...request, baseCommit, ...plan }, null, 2));
|
||||
} else {
|
||||
|
||||
@@ -1,23 +1,22 @@
|
||||
#!/usr/bin/env node
|
||||
import assert from "node:assert/strict";
|
||||
import { isUtf8 } from "node:buffer";
|
||||
import { execFile } from "node:child_process";
|
||||
import { createHash } from "node:crypto";
|
||||
import { lstat, mkdir, readFile, writeFile } from "node:fs/promises";
|
||||
import { isAbsolute, join } from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import { promisify } from "node:util";
|
||||
import { Client } from "@modelcontextprotocol/client";
|
||||
import { StdioClientTransport } from "@modelcontextprotocol/client/stdio";
|
||||
import { parseEvidence } from "../dist/domain/evidence.js";
|
||||
import { goBinarySchema } from "../dist/domain/go/goBinary.js";
|
||||
import { PrivateRuntimeRoot } from "../dist/process/PrivateRuntimeRoot.js";
|
||||
import { AnalysisCleanupLease } from "../dist/artifacts/AnalysisCleanupLease.js";
|
||||
import { artifactMcpCall } from "./lib/artifact-e2e.mjs";
|
||||
import { requireMcpOutput } from "./lib/mcp-verifier-results.mjs";
|
||||
import { createVerifierRun, completeVerifierRun } from "./lib/verifier-run.mjs";
|
||||
import { createVerifierCommands } from "./lib/verify-commands.mjs";
|
||||
import { createOwnedMcpStdioTransport } from "./lib/owned-mcp-stdio.mjs";
|
||||
import { closeVerifierResources } from "./lib/verifier-cleanup.mjs";
|
||||
|
||||
const commands = await createVerifierCommands();
|
||||
const execute = promisify(execFile);
|
||||
const compiler = process.env.REA_VERIFY_GO_COMMAND ?? "go";
|
||||
if (process.env.REA_VERIFY_GO_COMMAND !== undefined && !isAbsolute(compiler))
|
||||
throw new Error(
|
||||
@@ -52,16 +51,13 @@ const goEnvironment = {
|
||||
// Go's own verifier seam isolates telemetry; no global configuration is changed.
|
||||
TEST_TELEMETRY_DIR: join(root.path, "telemetry"),
|
||||
};
|
||||
let client;
|
||||
let transport;
|
||||
const cleanup = new AnalysisCleanupLease(async () => {
|
||||
await closeVerifierResources([
|
||||
() => client?.close(),
|
||||
() => transport?.close(),
|
||||
() => commands.close(),
|
||||
]);
|
||||
await root.close();
|
||||
}, [root.path]);
|
||||
const client = new Client({ name: "go-binary-verifier", version: "1" });
|
||||
const transport = new StdioClientTransport({
|
||||
command: process.execPath,
|
||||
args: [entrypoint, "mcp"],
|
||||
env: environment,
|
||||
stderr: "pipe",
|
||||
});
|
||||
const targets = [
|
||||
["linux", "amd64", "elf", 64, "little"],
|
||||
["linux", "386", "elf", 32, "little"],
|
||||
@@ -77,19 +73,10 @@ const verified = [];
|
||||
const omittedCoverage = [];
|
||||
const failures = [];
|
||||
try {
|
||||
client = new Client({ name: "go-binary-verifier", version: "1" });
|
||||
transport = await createOwnedMcpStdioTransport({
|
||||
command: process.execPath,
|
||||
arguments: [entrypoint, "mcp"],
|
||||
hostEnvironment: environment,
|
||||
cwd: process.cwd(),
|
||||
expectedCommand: null,
|
||||
sweepTokenOwnedProcesses: true,
|
||||
});
|
||||
await prepareFixture();
|
||||
try {
|
||||
compilerVersion = (
|
||||
await commands.exec(compiler, ["version"], {
|
||||
await execute(compiler, ["version"], {
|
||||
cwd: root.path,
|
||||
env: goEnvironment,
|
||||
timeout: 10_000,
|
||||
@@ -198,7 +185,7 @@ try {
|
||||
const path = join(root.path, "linux-amd64-byte-strings");
|
||||
const expected = JSON.parse(
|
||||
(
|
||||
await commands.exec(oracle, ["--build-byte-fixture", compiler, path], {
|
||||
await execute(oracle, ["--build-byte-fixture", compiler, path], {
|
||||
cwd: sourceRoot,
|
||||
env: { ...goEnvironment, GOOS: "linux", GOARCH: "amd64" },
|
||||
timeout: 120_000,
|
||||
@@ -211,16 +198,21 @@ try {
|
||||
} catch (cause) {
|
||||
failures.push(cause);
|
||||
} finally {
|
||||
try {
|
||||
await cleanup.release();
|
||||
} catch (cause) {
|
||||
failures.push(cause);
|
||||
for (const close of [
|
||||
() => client.close(),
|
||||
() => transport.close(),
|
||||
() => root.close(),
|
||||
]) {
|
||||
try {
|
||||
await close();
|
||||
} catch (cause) {
|
||||
failures.push(cause);
|
||||
}
|
||||
}
|
||||
}
|
||||
const verifier = await completeVerifierRun(run);
|
||||
try {
|
||||
if (cleanup.released)
|
||||
await assert.rejects(lstat(root.path), { code: "ENOENT" });
|
||||
await assert.rejects(lstat(root.path), { code: "ENOENT" });
|
||||
if (verifier.process_lineage.status === "verified")
|
||||
assert.deepEqual(verifier.process_lineage.descendants, []);
|
||||
} catch (cause) {
|
||||
@@ -234,21 +226,15 @@ if (failures.length > 0) {
|
||||
compiler: compilerVersion,
|
||||
verified,
|
||||
omitted_coverage: omittedCoverage,
|
||||
retained_root: cleanup.released ? null : root.path,
|
||||
verifier,
|
||||
},
|
||||
null,
|
||||
2,
|
||||
),
|
||||
);
|
||||
throw Object.assign(
|
||||
new AggregateError(
|
||||
failures,
|
||||
cleanup.released
|
||||
? "Real Go metadata verification failed; cleanup failures are retained."
|
||||
: `Real Go metadata verification failed; cleanup is incomplete at ${root.path}.`,
|
||||
),
|
||||
{ cleanupLeases: cleanup.released ? [] : [cleanup] },
|
||||
throw new AggregateError(
|
||||
failures,
|
||||
"Real Go metadata verification failed; cleanup failures are retained.",
|
||||
);
|
||||
}
|
||||
console.log(
|
||||
@@ -270,7 +256,7 @@ console.log(
|
||||
);
|
||||
|
||||
async function go(args, overrides = {}) {
|
||||
return commands.exec(compiler, args, {
|
||||
return execute(compiler, args, {
|
||||
cwd: sourceRoot,
|
||||
env: { ...goEnvironment, ...overrides },
|
||||
timeout: 120_000,
|
||||
@@ -370,7 +356,7 @@ async function inspect(mode, path, includeStringLiterals = false) {
|
||||
...(includeStringLiterals ? ["--include-string-literals"] : []),
|
||||
"--json",
|
||||
];
|
||||
const { stdout } = await commands.exec(process.execPath, args, {
|
||||
const { stdout } = await execute(process.execPath, args, {
|
||||
env: environment,
|
||||
timeout: 30_000,
|
||||
maxBuffer: 16 * 1024 * 1024,
|
||||
@@ -438,7 +424,7 @@ async function verify(
|
||||
byteExpected ??
|
||||
JSON.parse(
|
||||
(
|
||||
await commands.exec(oracle, [oraclePath], {
|
||||
await execute(oracle, [oraclePath], {
|
||||
timeout: 10_000,
|
||||
maxBuffer: 1024 * 1024,
|
||||
})
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { deepStrictEqual } from "node:assert";
|
||||
import {
|
||||
lstat,
|
||||
mkdir,
|
||||
@@ -12,6 +13,7 @@ import { dirname, isAbsolute, join } from "node:path";
|
||||
import { parse as parseToml } from "smol-toml";
|
||||
|
||||
import { TOOL_CONTRACTS } from "../dist/contracts/toolContracts.js";
|
||||
import { PRODUCT_IDENTITY } from "../dist/identity.js";
|
||||
import { pathExists } from "./lib/verify-package-core.mjs";
|
||||
import { parse as parseJsonc } from "jsonc-parser";
|
||||
import { skillReferenceIssues } from "./lib/docs-facts.mjs";
|
||||
|
||||
@@ -99,7 +99,8 @@ async function verifyPublishedUpdate({
|
||||
environment,
|
||||
);
|
||||
|
||||
await commands.execNpm(
|
||||
await commands.exec(
|
||||
"npm",
|
||||
[
|
||||
"install",
|
||||
"--global",
|
||||
@@ -117,7 +118,7 @@ async function verifyPublishedUpdate({
|
||||
);
|
||||
|
||||
const npmRoot = (
|
||||
await commands.execNpm(["root", "--global"], {
|
||||
await commands.exec("npm", ["root", "--global"], {
|
||||
cwd: canaryRoot,
|
||||
env: environment,
|
||||
timeout: 30000,
|
||||
@@ -185,7 +186,8 @@ if (result.status === "failed") process.exitCode = 1;
|
||||
}
|
||||
|
||||
async function findPreviousPublishedVersion(targetVersion, cwd, environment) {
|
||||
const { stdout } = await commands.execNpm(
|
||||
const { stdout } = await commands.exec(
|
||||
"npm",
|
||||
["view", "rea-agents", "versions", "--json"],
|
||||
{ cwd, env: environment, timeout: 30000, maxBuffer: 16 * 1024 * 1024 },
|
||||
);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#!/usr/bin/env node
|
||||
import assert from "node:assert/strict";
|
||||
import { execFile } from "node:child_process";
|
||||
import { createHash } from "node:crypto";
|
||||
import { readFile, mkdtemp, mkdir, rm } from "node:fs/promises";
|
||||
import { tmpdir } from "node:os";
|
||||
import { join } from "node:path";
|
||||
@@ -12,6 +13,7 @@ import { parseBinaryTarget } from "../dist/application/BinaryTargetResolver.js";
|
||||
import { ArtifactResourceScope } from "../dist/artifacts/ArtifactResourceScope.js";
|
||||
import { readGhidraLanguageCatalog } from "../dist/ghidra/GhidraLanguageCatalog.js";
|
||||
import { parseEvidence } from "../dist/domain/evidence.js";
|
||||
import { parseAnalysisSnapshot } from "../dist/domain/analysisSnapshot.js";
|
||||
import { functionDossierSchema } from "../dist/domain/native/functionDossier.js";
|
||||
import { inspectVerifierGhidraInstallation } from "./lib/ghidra-installation-inspection.mjs";
|
||||
import { buildGameCubeDolFixture } from "../tests/conformance/ghidra/dol-fixture.mjs";
|
||||
@@ -94,6 +96,8 @@ async function languageInstalled(languageId) {
|
||||
}
|
||||
}
|
||||
|
||||
const sha256 = (bytes) => createHash("sha256").update(bytes).digest("hex");
|
||||
|
||||
/** One MCP session plus CLI check. `languageOverride` is set only for the Gekko pass. */
|
||||
async function runPass({ fixture, languageOverride, label, layout }) {
|
||||
const env = { ...baseEnv };
|
||||
|
||||
@@ -151,7 +151,7 @@ export async function verifyAndroidFailureRecovery({
|
||||
failure_code: "runtime_unavailable",
|
||||
},
|
||||
availabilityReason: "provider_unavailable",
|
||||
availabilityRemediation: /selected Java launcher/u,
|
||||
availabilityRemediation: /selected Java runtime/u,
|
||||
message: /selected Java runtime/u,
|
||||
remediation: /selected launcher/u,
|
||||
});
|
||||
@@ -194,7 +194,12 @@ export async function verifyAndroidFailureRecovery({
|
||||
repository,
|
||||
available: false,
|
||||
unavailableReason: scenario.availabilityReason ?? "provider_missing",
|
||||
remediation: scenario.availabilityRemediation ?? scenario.remediation,
|
||||
remediation:
|
||||
scenario.availabilityRemediation ??
|
||||
new RegExp(
|
||||
scenario.observation.replace(/[.*+?^${}()|[\]\\]/gu, "\\$&"),
|
||||
"u",
|
||||
),
|
||||
});
|
||||
console.log(`PASS CLI applicable recovery: ${scenario.label}`);
|
||||
}
|
||||
|
||||
@@ -94,36 +94,29 @@ const stringBindings = (sourceFile, symbols, unresolved) => {
|
||||
ts.forEachChild(node, collect);
|
||||
};
|
||||
collect(sourceFile);
|
||||
const potential = (node, matchesCandidate) => {
|
||||
const potential = (node) => {
|
||||
const expression = unwrapExpression(node);
|
||||
if (exactLimit(literalText(expression)) !== undefined) return true;
|
||||
if (ts.isIdentifier(expression)) return matchesCandidate(expression);
|
||||
if (ts.isIdentifier(expression)) return candidates.has(expression.text);
|
||||
if (ts.isPropertyAccessExpression(expression))
|
||||
return (
|
||||
exactLimit(expression.name.text) !== undefined ||
|
||||
potential(expression.expression, matchesCandidate)
|
||||
potential(expression.expression)
|
||||
);
|
||||
if (ts.isElementAccessExpression(expression))
|
||||
return (
|
||||
expression.argumentExpression !== undefined &&
|
||||
potential(expression.argumentExpression, matchesCandidate)
|
||||
potential(expression.argumentExpression)
|
||||
);
|
||||
if (ts.isObjectLiteralExpression(expression))
|
||||
return expression.properties.some(
|
||||
(property) =>
|
||||
ts.isPropertyAssignment(property) &&
|
||||
potential(property.initializer, matchesCandidate),
|
||||
ts.isPropertyAssignment(property) && potential(property.initializer),
|
||||
);
|
||||
if (ts.isConditionalExpression(expression))
|
||||
return (
|
||||
potential(expression.whenTrue, matchesCandidate) ||
|
||||
potential(expression.whenFalse, matchesCandidate)
|
||||
);
|
||||
return potential(expression.whenTrue) || potential(expression.whenFalse);
|
||||
if (ts.isBinaryExpression(expression))
|
||||
return (
|
||||
potential(expression.left, matchesCandidate) ||
|
||||
potential(expression.right, matchesCandidate)
|
||||
);
|
||||
return potential(expression.left) || potential(expression.right);
|
||||
return false;
|
||||
};
|
||||
let changed = true;
|
||||
@@ -132,34 +125,13 @@ const stringBindings = (sourceFile, symbols, unresolved) => {
|
||||
for (const declaration of declarations) {
|
||||
if (
|
||||
!candidates.has(declaration.name.text) &&
|
||||
potential(declaration.initializer, (identifier) =>
|
||||
candidates.has(identifier.text),
|
||||
)
|
||||
potential(declaration.initializer)
|
||||
) {
|
||||
candidates.add(declaration.name.text);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Names narrow the search cheaply, but only the lexical declaration can
|
||||
// establish that a particular use is an alias of a limit.
|
||||
const lexicalCandidates = new Set();
|
||||
changed = true;
|
||||
while (changed) {
|
||||
changed = false;
|
||||
for (const declaration of declarations) {
|
||||
if (
|
||||
candidates.has(declaration.name.text) &&
|
||||
!lexicalCandidates.has(declaration) &&
|
||||
potential(declaration.initializer, (identifier) =>
|
||||
lexicalCandidates.has(symbols(identifier)?.valueDeclaration),
|
||||
)
|
||||
) {
|
||||
lexicalCandidates.add(declaration);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
const unknown = (node, reason) => {
|
||||
const path = sourceFile.fileName;
|
||||
const offset = node.getStart();
|
||||
@@ -180,12 +152,11 @@ const stringBindings = (sourceFile, symbols, unresolved) => {
|
||||
declaration === undefined ||
|
||||
!ts.isVariableDeclaration(declaration) ||
|
||||
!ts.isVariableDeclarationList(declaration.parent) ||
|
||||
declaration.initializer === undefined ||
|
||||
!lexicalCandidates.has(declaration)
|
||||
declaration.initializer === undefined
|
||||
)
|
||||
return undefined;
|
||||
if ((declaration.parent.flags & ts.NodeFlags.Const) === 0) {
|
||||
unknown(declaration.name, "mutable setting-key or value alias");
|
||||
unknown(identifier, "mutable setting-key or value alias");
|
||||
return undefined;
|
||||
}
|
||||
if (declaration.pos >= identifier.pos) {
|
||||
@@ -919,7 +890,7 @@ if (direct) {
|
||||
const entries = parseNumericLimitRegistry(registry);
|
||||
const listed = new Map();
|
||||
for (const entry of entries) {
|
||||
const { name, read, reason } = entry;
|
||||
const { name, policy, read, reason } = entry;
|
||||
if (listed.has(name)) failures.push(`${name} is listed twice`);
|
||||
listed.set(name, entry);
|
||||
if (reason.trim().length < 40)
|
||||
|
||||
@@ -20,7 +20,6 @@ it.each([
|
||||
source:
|
||||
'process.stdout.write("partial-雪"); process.stderr.write("waiting\\n"); setInterval(() => {}, 1000)',
|
||||
code: "provider_timeout",
|
||||
timeoutMs: 500,
|
||||
stdout: "partial-雪",
|
||||
stderr: "waiting\n",
|
||||
},
|
||||
@@ -29,7 +28,6 @@ it.each([
|
||||
source:
|
||||
'process.stdout.write("partial-雪"); process.stderr.write("adb: error: device offline\\n"); process.exitCode = 1',
|
||||
code: "unsupported_target",
|
||||
expectedPath: "caller-device",
|
||||
stdout: "partial-雪",
|
||||
stderr: "adb: error: device offline\n",
|
||||
},
|
||||
@@ -38,7 +36,6 @@ it.each([
|
||||
source:
|
||||
'process.stdout.write("partial-雪"); process.stderr.write("adb: error: cannot stat \'/host/token file\': Permission denied\\n"); process.exitCode = 1',
|
||||
code: "unsupported_target",
|
||||
expectedPath: "/host/token file",
|
||||
stdout: "partial-雪",
|
||||
stderr: "adb: error: cannot stat '/host/token file': Permission denied\n",
|
||||
},
|
||||
@@ -57,7 +54,7 @@ it.each([
|
||||
},
|
||||
["-e", testCase.source],
|
||||
{
|
||||
timeoutMs: testCase.timeoutMs ?? 5_000,
|
||||
timeoutMs: testCase.name === "timeout" ? 500 : 5_000,
|
||||
maxOutputBytes: testCase.maxOutputBytes ?? 1024,
|
||||
},
|
||||
undefined,
|
||||
@@ -78,34 +75,12 @@ it.each([
|
||||
},
|
||||
});
|
||||
if (testCase.code === "unsupported_target")
|
||||
expect(projected.details?.path).toBe(testCase.expectedPath);
|
||||
if (testCase.code === "provider_timeout") {
|
||||
expect(projected.details?.timeout_ms).toBe(testCase.timeoutMs);
|
||||
expect(projected.details?.limit).toBeUndefined();
|
||||
}
|
||||
expect(projected.details?.path).toBe(
|
||||
testCase.name === "local path refusal"
|
||||
? "/host/token file"
|
||||
: "caller-device",
|
||||
);
|
||||
expect(JSON.stringify(projected)).not.toContain(
|
||||
"ambient-value-must-not-be-persisted",
|
||||
);
|
||||
});
|
||||
|
||||
it.each([true, false])(
|
||||
"projects a truncated adb capture as retryable only for volatile output (%s)",
|
||||
async (volatileOutput) => {
|
||||
const result = await runAdbCapture(
|
||||
volatileOutput ? "read_adb_logcat" : "install_adb_package",
|
||||
{ device: "device" },
|
||||
{ binary: process.execPath, pathSource: "environment", environment: {} },
|
||||
["-e", 'process.stdout.write("X".repeat(4096))'],
|
||||
{ timeoutMs: 5_000, maxOutputBytes: 1024, volatileOutput },
|
||||
undefined,
|
||||
);
|
||||
if (result.ok) throw new Error("Expected a capture allowance refusal");
|
||||
const projected = projectAnalysisError(result.error);
|
||||
expect(projected.retryable).toBe(volatileOutput);
|
||||
expect(projected).toMatchObject({
|
||||
code: "resource_constraint",
|
||||
details: { reported_limits: { max_output_bytes: 1024 } },
|
||||
});
|
||||
expect(projected.details?.limit).toBeUndefined();
|
||||
},
|
||||
);
|
||||
@@ -1,4 +1,5 @@
|
||||
import { expect, it, vi } from "vitest";
|
||||
import { projectAnalysisError } from "../domain/analysisErrorProjection.js";
|
||||
import {
|
||||
ExecFileOutputCancelledError,
|
||||
execFileBytes,
|
||||
@@ -211,6 +212,65 @@ it("does not infer cancellation from a foreign ABORT_ERR code", async () => {
|
||||
});
|
||||
});
|
||||
|
||||
it.each([true, false])(
|
||||
"projects a truncated adb capture as retryable only for volatile output (%s)",
|
||||
async (volatileOutput) => {
|
||||
vi.mocked(execFileBytes).mockRejectedValueOnce(
|
||||
Object.assign(new Error("too much"), {
|
||||
code: 1,
|
||||
stdout: "",
|
||||
stderr: "",
|
||||
signal: null,
|
||||
killed: false,
|
||||
outputTruncated: true,
|
||||
}),
|
||||
);
|
||||
const result = await runAdbCapture(
|
||||
volatileOutput ? "read_adb_logcat" : "install_adb_package",
|
||||
{ device: "device" },
|
||||
{ binary: "/host/adb", pathSource: "environment", environment: {} },
|
||||
volatileOutput ? ["logcat", "-d"] : ["install", "app.apk"],
|
||||
{ timeoutMs: 100, maxOutputBytes: 1024, volatileOutput },
|
||||
undefined,
|
||||
);
|
||||
if (result.ok) throw new Error("Expected a capture allowance refusal");
|
||||
const projected = projectAnalysisError(result.error);
|
||||
expect(projected.retryable).toBe(volatileOutput);
|
||||
expect(projected).toMatchObject({
|
||||
code: "resource_constraint",
|
||||
details: { reported_limits: { max_output_bytes: 1024 } },
|
||||
});
|
||||
expect(projected.details?.limit).toBeUndefined();
|
||||
},
|
||||
);
|
||||
|
||||
it("reports the effective fixed adb deadline", async () => {
|
||||
vi.mocked(execFileBytes).mockRejectedValueOnce(
|
||||
Object.assign(new Error("deadline"), {
|
||||
code: "ETIMEDOUT",
|
||||
stdout: "",
|
||||
stderr: "",
|
||||
signal: null,
|
||||
killed: true,
|
||||
}),
|
||||
);
|
||||
const result = await runAdbCapture(
|
||||
"pull_adb_file",
|
||||
{ device: "device" },
|
||||
{ binary: "/host/adb", pathSource: "environment", environment: {} },
|
||||
["pull", "/remote"],
|
||||
{ timeoutMs: 600_000, maxOutputBytes: 1024 },
|
||||
undefined,
|
||||
);
|
||||
if (result.ok) throw new Error("Expected an adb deadline");
|
||||
const projected = projectAnalysisError(result.error);
|
||||
expect(projected).toMatchObject({
|
||||
code: "provider_timeout",
|
||||
details: { timeout_ms: 600_000 },
|
||||
});
|
||||
expect(projected.details?.limit).toBeUndefined();
|
||||
});
|
||||
|
||||
it("keeps a physical failure even when the later abort reason is that same error", async () => {
|
||||
const controller = new AbortController();
|
||||
const failure = new Error("physical command failure");
|
||||
|
||||
@@ -84,7 +84,6 @@ import {
|
||||
import { RegularFileOperationCancelled } from "../filesystem/RegularFile.js";
|
||||
import { OwnedFileHandle } from "../filesystem/OwnedFileHandle.js";
|
||||
import { createEvidence } from "../domain/evidence.js";
|
||||
import { createAnalysisExecutionEvidence } from "../domain/analysisObservation.js";
|
||||
import {
|
||||
PrivateRuntimeRoot,
|
||||
type PrivateRuntimeRootOptions,
|
||||
@@ -994,12 +993,15 @@ export class AdbProvider {
|
||||
const partialObservation =
|
||||
execution === undefined
|
||||
? undefined
|
||||
: createAnalysisExecutionEvidence(
|
||||
: createEvidence(execution.subject ?? undefined, execution.provider, {
|
||||
operation,
|
||||
parameters,
|
||||
execution,
|
||||
"observed",
|
||||
);
|
||||
result: execution.result,
|
||||
rawResult: execution.rawResult,
|
||||
limitations: execution.limitations,
|
||||
locations: execution.locations,
|
||||
confidence: "observed",
|
||||
});
|
||||
return new ProviderCleanupError(
|
||||
ADB_PROVIDER_IDENTITY.id,
|
||||
resources,
|
||||
|
||||
@@ -47,32 +47,19 @@ it("reports the fixed adb version-probe deadline", async () => {
|
||||
});
|
||||
|
||||
it("reports the fixed adb version-output cap", async () => {
|
||||
let selected: string = selection.binary;
|
||||
if (process.platform === "win32") {
|
||||
vi.mocked(execFileOutput).mockRejectedValueOnce(
|
||||
Object.assign(new Error("too much"), {
|
||||
code: "ERR_CHILD_PROCESS_STDIO_MAXBUFFER",
|
||||
stdout: "",
|
||||
stderr: "",
|
||||
signal: null,
|
||||
killed: false,
|
||||
outputTruncated: true,
|
||||
}),
|
||||
);
|
||||
} else {
|
||||
const root = await mkdtemp(join(tmpdir(), "rea-adb-version-cap-"));
|
||||
onTestFinished(() => rm(root, { recursive: true, force: true }));
|
||||
selected = join(root, "adb");
|
||||
await writeFile(
|
||||
selected,
|
||||
`#!${process.execPath}\nprocess.stdout.write("x".repeat(100_000));\n`,
|
||||
{ mode: 0o755 },
|
||||
);
|
||||
}
|
||||
const failure = await inspectAdbClient({
|
||||
...selection,
|
||||
binary: selected,
|
||||
}).catch((cause: unknown) => cause);
|
||||
vi.mocked(execFileOutput).mockRejectedValueOnce(
|
||||
Object.assign(new Error("too much"), {
|
||||
code: "ERR_CHILD_PROCESS_STDIO_MAXBUFFER",
|
||||
stdout: "",
|
||||
stderr: "",
|
||||
signal: null,
|
||||
killed: false,
|
||||
outputTruncated: true,
|
||||
}),
|
||||
);
|
||||
const failure = await inspectAdbClient(selection).catch(
|
||||
(cause: unknown) => cause,
|
||||
);
|
||||
const projected = projectAnalysisError(
|
||||
failure as Parameters<typeof projectAnalysisError>[0],
|
||||
);
|
||||
@@ -87,28 +74,25 @@ it("reports the fixed adb version-output cap", async () => {
|
||||
expect(projected.details?.limit).toBeUndefined();
|
||||
});
|
||||
|
||||
it.skipIf(process.platform !== "win32")(
|
||||
"classifies an EACCES execute refusal on Windows",
|
||||
async () => {
|
||||
vi.mocked(execFileOutput).mockRejectedValueOnce(
|
||||
Object.assign(new Error("denied"), {
|
||||
code: "EACCES",
|
||||
spawnFailed: true,
|
||||
stdout: "",
|
||||
stderr: "",
|
||||
signal: null,
|
||||
killed: false,
|
||||
}),
|
||||
);
|
||||
await expect(inspectAdbClient(selection)).rejects.toMatchObject({
|
||||
code: "binary_not_executable",
|
||||
diagnostics: {
|
||||
selected_binary: selection.binary,
|
||||
filesystem_error: "EACCES",
|
||||
},
|
||||
});
|
||||
},
|
||||
);
|
||||
it("distinguishes execute denial from missing or unreadable version output", async () => {
|
||||
vi.mocked(execFileOutput).mockRejectedValueOnce(
|
||||
Object.assign(new Error("denied"), {
|
||||
code: "EACCES",
|
||||
spawnFailed: true,
|
||||
stdout: "",
|
||||
stderr: "",
|
||||
signal: null,
|
||||
killed: false,
|
||||
}),
|
||||
);
|
||||
await expect(inspectAdbClient(selection)).rejects.toMatchObject({
|
||||
code: "binary_not_executable",
|
||||
diagnostics: {
|
||||
selected_binary: selection.binary,
|
||||
filesystem_error: "EACCES",
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it("names an EPERM execute refusal separately from missing permission", async () => {
|
||||
vi.mocked(execFileOutput).mockRejectedValueOnce(
|
||||
|
||||
@@ -58,7 +58,7 @@ export const androidSnapshotCopy = (
|
||||
: undefined;
|
||||
|
||||
/** Adopt a snapshot descriptor whose close rejected, keyed by its exact path. */
|
||||
type AndroidSnapshotCloseRetention = (
|
||||
export type AndroidSnapshotCloseRetention = (
|
||||
path: string,
|
||||
owner: OwnedFileHandle,
|
||||
) => void;
|
||||
@@ -69,8 +69,8 @@ export const snapshotAndroidTarget = async (
|
||||
sha256: string,
|
||||
root: string,
|
||||
operation: AndroidOperation,
|
||||
signal: AbortSignal | undefined,
|
||||
retainFailedClose: AndroidSnapshotCloseRetention,
|
||||
signal?: AbortSignal,
|
||||
retainFailedClose?: AndroidSnapshotCloseRetention,
|
||||
): Promise<string> => {
|
||||
const snapshot = join(root, "target.apk");
|
||||
try {
|
||||
@@ -105,8 +105,8 @@ export const snapshotAndroidEngine = async (
|
||||
sha256: string,
|
||||
root: string,
|
||||
operation: AndroidOperation,
|
||||
signal: AbortSignal | undefined,
|
||||
retainFailedClose: AndroidSnapshotCloseRetention,
|
||||
signal?: AbortSignal,
|
||||
retainFailedClose?: AndroidSnapshotCloseRetention,
|
||||
): Promise<{ path: string; sha256: string }> => {
|
||||
const path = join(root, "engine.jar");
|
||||
try {
|
||||
@@ -159,14 +159,17 @@ const copyAndroidSnapshot = async (
|
||||
snapshotPath: string,
|
||||
expectedSha256: string,
|
||||
signal: AbortSignal | undefined,
|
||||
retainFailedClose: AndroidSnapshotCloseRetention,
|
||||
retainFailedClose: AndroidSnapshotCloseRetention | undefined,
|
||||
): Promise<AndroidSnapshotCopy> => {
|
||||
assertRegularFileActive(signal);
|
||||
let removeSnapshot = false;
|
||||
const retain = (path: string) => ({
|
||||
retainFailedClose: (owner: OwnedFileHandle) =>
|
||||
retainFailedClose(path, owner),
|
||||
});
|
||||
const retain = (path: string) =>
|
||||
retainFailedClose === undefined
|
||||
? {}
|
||||
: {
|
||||
retainFailedClose: (owner: OwnedFileHandle) =>
|
||||
retainFailedClose(path, owner),
|
||||
};
|
||||
try {
|
||||
// Close each descriptor through its owner. A rejected close keeps the
|
||||
// copy outcome and stays retained until that owner is retried; the
|
||||
@@ -284,7 +287,7 @@ const openSnapshotSource = async (
|
||||
path: string,
|
||||
signal: AbortSignal | undefined,
|
||||
retention: {
|
||||
readonly retainFailedClose: (owner: OwnedFileHandle) => void;
|
||||
readonly retainFailedClose?: (owner: OwnedFileHandle) => void;
|
||||
},
|
||||
): Promise<StableRegularFileDescriptor> => {
|
||||
try {
|
||||
@@ -302,9 +305,10 @@ const openSnapshotSource = async (
|
||||
};
|
||||
|
||||
const retainAdmissionOwner = (
|
||||
retain: (owner: OwnedFileHandle) => void,
|
||||
retain: ((owner: OwnedFileHandle) => void) | undefined,
|
||||
owner: OwnedFileHandle,
|
||||
): RegularFileCleanupFailure["retention"] => {
|
||||
if (retain === undefined) return { kind: "not_requested" };
|
||||
try {
|
||||
retain(owner);
|
||||
return { kind: "callback_returned" };
|
||||
|
||||
@@ -313,10 +313,10 @@ export class JadxProvider implements AndroidAnalysisPort {
|
||||
: AbortSignal.any([signal, this.#shutdown.signal]),
|
||||
});
|
||||
this.#inspections.add(pending);
|
||||
const remove = (): void => {
|
||||
this.#inspections.delete(pending);
|
||||
};
|
||||
void pending.then(remove, remove);
|
||||
void pending.then(
|
||||
() => this.#inspections.delete(pending),
|
||||
() => this.#inspections.delete(pending),
|
||||
);
|
||||
return pending;
|
||||
}
|
||||
|
||||
|
||||
@@ -415,11 +415,11 @@ export class ApkSignatureProvider implements ApkSignaturePort {
|
||||
const { v1, decoded: v1Decoded, duplicates } = v1Read.value;
|
||||
|
||||
const v2 = decodeScheme(block.value, APK_BLOCK_ID.signatureV2, "v2");
|
||||
if (!v2.ok) return v2;
|
||||
if (!v2.ok) return err(v2.error);
|
||||
const v3 = decodeScheme(block.value, APK_BLOCK_ID.signatureV3, "v3");
|
||||
if (!v3.ok) return v3;
|
||||
if (!v3.ok) return err(v3.error);
|
||||
const v31 = decodeScheme(block.value, APK_BLOCK_ID.signatureV31, "v3.1");
|
||||
if (!v31.ok) return v31;
|
||||
if (!v31.ok) return err(v31.error);
|
||||
|
||||
// Account for representation expansion before allocating the report.
|
||||
const projected = projectedOutputBytes(
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import * as commandOwner from "../process/OwnedCommand.js";
|
||||
import { failedInspectionDescriptor } from "../../tests/fixtures/processInspectionCleanup.js";
|
||||
import { awaitAcknowledgement } from "../../tests/fixtures/lifecycleAcknowledgement.js";
|
||||
import {
|
||||
AnalysisError,
|
||||
primaryAnalysisError,
|
||||
@@ -487,7 +486,6 @@ it("cancels a pending filesystem lookup and owns its eventual rejection", async
|
||||
const pendingStat = new Promise((_resolve, reject) => {
|
||||
rejectLookup = reject;
|
||||
});
|
||||
void pendingStat.catch(() => undefined);
|
||||
const observed = new Promise<void>((resolve) => {
|
||||
started = resolve;
|
||||
});
|
||||
@@ -504,20 +502,14 @@ it("cancels a pending filesystem lookup and owns its eventual rejection", async
|
||||
"win32",
|
||||
controller.signal,
|
||||
);
|
||||
try {
|
||||
await awaitAcknowledgement(observed, pending, "apktool filesystem lookup");
|
||||
controller.abort();
|
||||
await expect(pending).rejects.toMatchObject({
|
||||
_tag: "AnalysisCancelledError",
|
||||
});
|
||||
rejectLookup(new Error("filesystem completed after cancellation"));
|
||||
await Promise.resolve();
|
||||
expect(lookup.stat).toHaveBeenCalledTimes(1);
|
||||
} finally {
|
||||
controller.abort();
|
||||
rejectLookup(new Error("fixture cleanup"));
|
||||
await pending.catch(() => undefined);
|
||||
}
|
||||
await observed;
|
||||
controller.abort();
|
||||
await expect(pending).rejects.toMatchObject({
|
||||
_tag: "AnalysisCancelledError",
|
||||
});
|
||||
rejectLookup(new Error("filesystem completed after cancellation"));
|
||||
await Promise.resolve();
|
||||
expect(lookup.stat).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it("bounds the entire pending PATH lookup by the selection deadline", async () => {
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { describe, expect, it, onTestFinished } from "vitest";
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { createDeferred } from "../../tests/fixtures/binarySession.js";
|
||||
import { awaitAcknowledgement } from "../../tests/fixtures/lifecycleAcknowledgement.js";
|
||||
|
||||
import {
|
||||
getNavigationContext,
|
||||
@@ -501,16 +500,7 @@ it("waits for late facet cleanup after cancellation and retains its owner", asyn
|
||||
settled = true;
|
||||
return result;
|
||||
});
|
||||
onTestFinished(async () => {
|
||||
controller.abort();
|
||||
late.resolve(err(failure));
|
||||
try {
|
||||
await pending;
|
||||
} finally {
|
||||
await lease.release();
|
||||
}
|
||||
});
|
||||
await awaitAcknowledgement(started.promise, pending, "facet execution");
|
||||
await started.promise;
|
||||
controller.abort();
|
||||
await Promise.resolve();
|
||||
expect(settled).toBe(false);
|
||||
@@ -540,12 +530,7 @@ it("reports cancellation after a late successful facet that ignored its signal",
|
||||
{ address: "0x401000", document: "fixture" },
|
||||
controller.signal,
|
||||
);
|
||||
onTestFinished(async () => {
|
||||
controller.abort();
|
||||
late.resolve(ok(createAnalysisExecution("finished", provider)));
|
||||
await pending;
|
||||
});
|
||||
await awaitAcknowledgement(started.promise, pending, "facet execution");
|
||||
await started.promise;
|
||||
controller.abort();
|
||||
late.resolve(ok(createAnalysisExecution("finished", provider)));
|
||||
const result = await pending;
|
||||
@@ -601,11 +586,7 @@ it("preserves a provider's cancellation for the same signal", async () => {
|
||||
{ address: "0x401000", document: "fixture" },
|
||||
controller.signal,
|
||||
);
|
||||
onTestFinished(async () => {
|
||||
controller.abort(reason);
|
||||
await pending;
|
||||
});
|
||||
await awaitAcknowledgement(started.promise, pending, "provider execution");
|
||||
await started.promise;
|
||||
controller.abort(reason);
|
||||
const result = await pending;
|
||||
if (result.ok) throw new Error("expected cancellation");
|
||||
|
||||
@@ -53,11 +53,6 @@ export interface ExecutionOptions {
|
||||
* supplied it.
|
||||
*/
|
||||
readonly selectorOrigin?: "provider";
|
||||
/**
|
||||
* Whether the caller's catalog advertises an operation; refusal recovery
|
||||
* names only advertised operations. Absent means every operation is.
|
||||
*/
|
||||
readonly isOperationAdvertised?: (operation: AnalysisOperation) => boolean;
|
||||
}
|
||||
|
||||
/** Closed operations accepted by provider-backed analysis sessions. */
|
||||
|
||||
@@ -6,6 +6,7 @@ import {
|
||||
resolveWindowsChangeTimeSettle,
|
||||
} from "../config/windowsChangeTimeSettle.js";
|
||||
import { pwntoolsInputBytes } from "../native/pwntools/PwntoolsInputLimit.js";
|
||||
import { resolveBridgeMaxRequestBytes } from "../config/bridgeMaxRequestBytes.js";
|
||||
import { resolveCaptureDecoderHeap } from "../config/captureDecoderHeap.js";
|
||||
import { resolveRegexMatchingDeadline } from "../config/regexMatchingDeadline.js";
|
||||
import { resolveRegexWorkerHeapRequest } from "../config/regexWorkerHeapRequest.js";
|
||||
@@ -365,6 +366,7 @@ it("reads an accepted override before an invalid launch seed", () => {
|
||||
{
|
||||
revision: 1,
|
||||
overrides: {
|
||||
"bridge.max_request_bytes": 8192,
|
||||
"capture.decoder_old_generation_mib": 64,
|
||||
"regex.matching_deadline_ms": 250,
|
||||
"regex.worker_heap_request_mib": 128,
|
||||
@@ -373,6 +375,9 @@ it("reads an accepted override before an invalid launch seed", () => {
|
||||
},
|
||||
},
|
||||
() => ({
|
||||
bridge: resolveBridgeMaxRequestBytes({
|
||||
REA_BRIDGE_MAX_REQUEST_BYTES: "nope",
|
||||
}),
|
||||
capture: resolveCaptureDecoderHeap({
|
||||
REA_CAPTURE_DECODER_OLD_GENERATION_MIB: "0",
|
||||
}),
|
||||
@@ -388,6 +393,10 @@ it("reads an accepted override before an invalid launch seed", () => {
|
||||
}),
|
||||
}),
|
||||
);
|
||||
expect(resolved.bridge).toMatchObject({
|
||||
maximumBytes: 8192,
|
||||
source: "runtime",
|
||||
});
|
||||
expect(resolved.capture).toMatchObject({
|
||||
oldGenerationMiB: 64,
|
||||
source: "runtime",
|
||||
|
||||
@@ -4,7 +4,7 @@ import { join } from "node:path";
|
||||
import { expect, it } from "vitest";
|
||||
|
||||
import { createTestTempDirectory } from "../../tests/fixtures/temporaryDirectory.js";
|
||||
import { resolveAppleBundleExecutable } from "./AppBundleExecutable.js";
|
||||
import { resolveAppBundleExecutable } from "./AppBundleExecutable.js";
|
||||
|
||||
it.each([
|
||||
["no comment", ""],
|
||||
@@ -22,7 +22,7 @@ it.each([
|
||||
await writeFile(infoPlist, source);
|
||||
await writeFile(executable, "fixture - never executed");
|
||||
|
||||
expect(await resolveAppleBundleExecutable(bundle)).toEqual({
|
||||
expect(await resolveAppBundleExecutable(bundle)).toEqual({
|
||||
ok: true,
|
||||
value: { executable, infoPlist },
|
||||
});
|
||||
|
||||
@@ -6,7 +6,7 @@ import { describe, expect, it } from "vitest";
|
||||
|
||||
import { createTestTempDirectory } from "../../tests/fixtures/temporaryDirectory.js";
|
||||
import { binaryPlistObjectTable } from "../../tests/fixtures/binaryPlistObjectTable.js";
|
||||
import { resolveAppleBundleExecutable } from "./AppBundleExecutable.js";
|
||||
import { resolveAppBundleExecutable } from "./AppBundleExecutable.js";
|
||||
|
||||
const binaryPlistExecutableWithThreeByteUid = (): Buffer => {
|
||||
const ascii = (value: string): Buffer => {
|
||||
@@ -53,7 +53,7 @@ it.each([
|
||||
);
|
||||
await writeFile(executable, "inert fixture; never executed");
|
||||
|
||||
const result = await resolveAppleBundleExecutable(bundle);
|
||||
const result = await resolveAppBundleExecutable(bundle);
|
||||
expect(result).toEqual({
|
||||
ok: true,
|
||||
value: { executable, infoPlist: plistPath },
|
||||
@@ -71,7 +71,7 @@ describe("app bundle Info.plist magic", () => {
|
||||
await writeFile(plistPath, binaryPlistExecutableWithThreeByteUid());
|
||||
await writeFile(executable, "inert fixture; never executed");
|
||||
|
||||
expect(await resolveAppleBundleExecutable(bundle)).toEqual({
|
||||
expect(await resolveAppBundleExecutable(bundle)).toEqual({
|
||||
ok: true,
|
||||
value: { executable, infoPlist: plistPath },
|
||||
});
|
||||
@@ -86,13 +86,17 @@ describe("app bundle Info.plist magic", () => {
|
||||
const plist = Buffer.from("bplist00");
|
||||
plist[0] = (plist[0] ?? 0) | 0x80;
|
||||
await writeFile(plistPath, plist);
|
||||
const result = await resolveAppleBundleExecutable(bundle);
|
||||
expect(result).toMatchObject({
|
||||
ok: false,
|
||||
error: {
|
||||
cause: { name: "XmlPlistTextDecodeError", reason: "invalid-bytes" },
|
||||
let decoded = false;
|
||||
const result = await resolveAppBundleExecutable(bundle, {
|
||||
readFile: async () => plist,
|
||||
realpath: async (path) => path,
|
||||
decodeBinaryPlist: async () => {
|
||||
decoded = true;
|
||||
return "Fixture";
|
||||
},
|
||||
});
|
||||
expect(decoded).toBe(false);
|
||||
expect(result.ok).toBe(false);
|
||||
} finally {
|
||||
await rm(root, { recursive: true, force: true });
|
||||
}
|
||||
@@ -114,7 +118,7 @@ describe("app bundle program directory containment", () => {
|
||||
await writeFile(join(bundle, "Contents", "Info.plist"), plist);
|
||||
let childResolved = false;
|
||||
|
||||
const result = await resolveAppleBundleExecutable(bundle, {
|
||||
const result = await resolveAppBundleExecutable(bundle, {
|
||||
readFile: async () => Buffer.from(plist),
|
||||
realpath: async (path) => {
|
||||
if (path === bundle) return canonicalBundle;
|
||||
|
||||
@@ -88,9 +88,10 @@ export interface ResolvedAppBundleResourceRoot {
|
||||
}
|
||||
|
||||
/** Filesystem operations used by the resolver, injectable for boundary tests. */
|
||||
interface AppBundleFileSystem {
|
||||
export interface AppBundleFileSystem {
|
||||
readonly readFile: (path: string) => Promise<Buffer>;
|
||||
readonly realpath: (path: string) => Promise<string>;
|
||||
readonly decodeBinaryPlist?: (path: string) => Promise<string>;
|
||||
}
|
||||
|
||||
const defaultFileSystem: AppBundleFileSystem = { readFile, realpath };
|
||||
@@ -101,7 +102,7 @@ const defaultFileSystem: AppBundleFileSystem = { readFile, realpath };
|
||||
* a wrapper whose `Wrapper` directory holds the iOS bundle; that bundle is
|
||||
* found by listing `Wrapper`, never by following the `WrappedBundle` link.
|
||||
*/
|
||||
const resolveAppBundleExecutable = async (
|
||||
export const resolveAppBundleExecutable = async (
|
||||
path: string,
|
||||
fileSystem: AppBundleFileSystem = defaultFileSystem,
|
||||
): Promise<Result<ResolvedAppBundle, BinaryTargetError>> => {
|
||||
@@ -395,6 +396,15 @@ const codeDescription = (cause: unknown): string => {
|
||||
: "";
|
||||
};
|
||||
|
||||
const isSystemErrorCode = (cause: unknown): boolean => {
|
||||
const code = errorCode(cause);
|
||||
return (
|
||||
typeof code === "string" &&
|
||||
/^[A-Z][A-Z0-9_]+$/u.test(code) &&
|
||||
!code.startsWith("ERR_")
|
||||
);
|
||||
};
|
||||
|
||||
const isPermissionDenied = (cause: unknown): boolean =>
|
||||
errorCode(cause) === "EACCES" || errorCode(cause) === "EPERM";
|
||||
|
||||
@@ -451,12 +461,20 @@ const resolveLayoutExecutable = async (
|
||||
|
||||
let name: string;
|
||||
try {
|
||||
name = executableName(decodeInfoPlistValue(plist));
|
||||
name =
|
||||
hasBinaryPlistSignature(plist) &&
|
||||
fileSystem.decodeBinaryPlist !== undefined
|
||||
? await fileSystem.decodeBinaryPlist(plistPath)
|
||||
: executableName(decodeInfoPlistValue(plist));
|
||||
} catch (cause: unknown) {
|
||||
return err(
|
||||
new BinaryTargetError(
|
||||
plistPath,
|
||||
`${noun} Info.plist is malformed, unsupported, or lacks CFBundleExecutable: ${plistPath}${cause instanceof Error ? ` (${cause.message})` : ""}`,
|
||||
isPermissionDenied(cause)
|
||||
? `permission denied decoding ${noun} Info.plist ${plistPath}${codeDescription(cause)}`
|
||||
: isSystemErrorCode(cause)
|
||||
? `could not decode ${noun} Info.plist ${plistPath}${codeDescription(cause)}`
|
||||
: `${noun} Info.plist is malformed, unsupported, or lacks CFBundleExecutable: ${plistPath}${cause instanceof Error ? ` (${cause.message})` : ""}`,
|
||||
{
|
||||
cause,
|
||||
// A bundle without code, such as a resource bundle, declares no
|
||||
|
||||
@@ -3,7 +3,7 @@ import { join } from "node:path";
|
||||
|
||||
import { describe, expect, it } from "vitest";
|
||||
|
||||
import { resolveAppleBundleExecutable } from "./AppBundleExecutable.js";
|
||||
import { resolveAppBundleExecutable } from "./AppBundleExecutable.js";
|
||||
import { createTestTempDirectory } from "../../tests/fixtures/temporaryDirectory.js";
|
||||
|
||||
describe("OpenStep Info.plist nesting during app target resolution", () => {
|
||||
@@ -20,7 +20,7 @@ describe("OpenStep Info.plist nesting during app target resolution", () => {
|
||||
`{ CFBundleExecutable = App; payload = ${"(".repeat(depth)}x${")".repeat(depth)}; }`,
|
||||
);
|
||||
|
||||
const result = await resolveAppleBundleExecutable(app);
|
||||
const result = await resolveAppBundleExecutable(app);
|
||||
|
||||
if (depth === 127) {
|
||||
expect(result).toMatchObject({
|
||||
@@ -52,7 +52,7 @@ describe("OpenStep Info.plist nesting during app target resolution", () => {
|
||||
`{ CFBundleExecutable = App; }${"(".repeat(3000)}x${")".repeat(3000)}`,
|
||||
);
|
||||
|
||||
expect(await resolveAppleBundleExecutable(app)).toMatchObject({
|
||||
expect(await resolveAppBundleExecutable(app)).toMatchObject({
|
||||
ok: true,
|
||||
value: { executable: join(programs, "App") },
|
||||
});
|
||||
|
||||
@@ -208,7 +208,7 @@ export const parseBinaryTarget = async (
|
||||
throwIfTargetResolutionCancelled(signal);
|
||||
const resolved = await resolveAppBundle(canonical);
|
||||
throwIfTargetResolutionCancelled(signal);
|
||||
if (!resolved.ok) return resolved;
|
||||
if (!resolved.ok) return err(resolved.error);
|
||||
const { executable: path, infoPlist } = resolved.value;
|
||||
const bundle =
|
||||
infoPlist === undefined ? {} : { bundleInfoPlist: infoPlist };
|
||||
@@ -747,8 +747,8 @@ const throwIfTargetResolutionCancelled = (signal?: AbortSignal): void => {
|
||||
const detectArtifactFormat = async (
|
||||
path: string,
|
||||
source: StableRegularFileDescriptor,
|
||||
signal: AbortSignal | undefined,
|
||||
sourcePath: string,
|
||||
signal?: AbortSignal,
|
||||
sourcePath = path,
|
||||
): Promise<
|
||||
| Exclude<
|
||||
BinaryTarget["format"],
|
||||
|
||||
@@ -56,7 +56,6 @@ import {
|
||||
type AnalysisCleanupRetry,
|
||||
} from "../domain/analysisErrorRecovery.js";
|
||||
import { isBundleResourceOperation } from "./binary/BundleResourceSession.js";
|
||||
import { offeredOperationAlternatives } from "./OperationAlternatives.js";
|
||||
|
||||
const FRIDA_OPERATION_NAMES: ReadonlySet<string> = new Set(
|
||||
FRIDA_TOOL_CONTRACTS.map(({ name }) => name),
|
||||
@@ -127,8 +126,6 @@ export type AvailabilityPolicy = {
|
||||
type AvailabilityFacts = {
|
||||
readonly defaultModeAvailable?: boolean;
|
||||
readonly modes?: readonly ToolAvailabilityMode[];
|
||||
/** Advertised operations the current provider offers for part of the question. */
|
||||
readonly alternatives?: readonly AnalysisOperation[];
|
||||
};
|
||||
type Availability = AvailabilityFacts &
|
||||
(
|
||||
@@ -165,7 +162,6 @@ type AvailabilityContext = {
|
||||
readonly targetFormat: string | undefined;
|
||||
readonly descriptors: ReadonlyMap<string, ProviderDescriptor>;
|
||||
readonly policy: AvailabilityPolicy;
|
||||
readonly isToolAdvertised: (name: string) => boolean;
|
||||
};
|
||||
|
||||
type EnhancedContractName = Extract<
|
||||
@@ -326,15 +322,10 @@ const ADDRESS_CONTEXT_EFFECT_COMPOSITION: ModeComposition = {
|
||||
],
|
||||
};
|
||||
|
||||
/**
|
||||
* Build stable per-operation availability for the caller's advertised tools.
|
||||
* Each tool's availability still derives from the complete provider facts;
|
||||
* advertisement narrows only the reported tools and the alternatives named.
|
||||
*/
|
||||
/** Build stable per-operation availability for discovery and tool visibility. */
|
||||
export const buildCapabilityInventory = (
|
||||
sessionStatus: JsonValue,
|
||||
policy: AvailabilityPolicy,
|
||||
isToolAdvertised: (name: string) => boolean = () => true,
|
||||
): readonly ToolAvailability[] => {
|
||||
const status = statusSchema.parse(sessionStatus);
|
||||
const descriptors = new Map<string, ProviderDescriptor>(
|
||||
@@ -354,7 +345,6 @@ export const buildCapabilityInventory = (
|
||||
targetFormat: status.format,
|
||||
descriptors,
|
||||
policy,
|
||||
isToolAdvertised,
|
||||
});
|
||||
const effects = composedEffects(
|
||||
contract.name,
|
||||
@@ -408,13 +398,8 @@ export const buildCapabilityInventory = (
|
||||
available: false,
|
||||
reason: availability.reason,
|
||||
remediation: availability.remediation,
|
||||
...(availability.alternatives === undefined
|
||||
? {}
|
||||
: { alternatives: [...availability.alternatives] }),
|
||||
};
|
||||
})
|
||||
.filter(({ name }) => isToolAdvertised(name))
|
||||
.sort((left, right) => compareUnicodeCodePoints(left.name, right.name));
|
||||
}).sort((left, right) => compareUnicodeCodePoints(left.name, right.name));
|
||||
};
|
||||
|
||||
type ClientRequirements = ToolAvailability["client_requirements"];
|
||||
@@ -460,9 +445,6 @@ export function compactToolAvailability(
|
||||
? {}
|
||||
: { default_mode_available: entry.default_mode_available }),
|
||||
...(entry.modes === undefined ? {} : { modes: [...entry.modes] }),
|
||||
...(entry.available || entry.alternatives === undefined
|
||||
? {}
|
||||
: { alternatives: [...entry.alternatives] }),
|
||||
...(JSON.stringify(entry.client_requirements) ===
|
||||
JSON.stringify(clientRequirements)
|
||||
? {}
|
||||
@@ -977,7 +959,6 @@ const providerAvailability = ({
|
||||
kind,
|
||||
name,
|
||||
policy,
|
||||
isToolAdvertised,
|
||||
}: AvailabilityContext): Availability => {
|
||||
if (kind === "enhanced") return composedAvailability(name, descriptors);
|
||||
const launchFailure =
|
||||
@@ -995,20 +976,12 @@ const providerAvailability = ({
|
||||
kind === "native-provider")
|
||||
)
|
||||
return { reason: "available", remediation: null };
|
||||
if (descriptor === undefined) {
|
||||
const offered = offeredOperationAlternatives(
|
||||
name,
|
||||
(alternative) =>
|
||||
descriptors.get(alternative)?.available === true &&
|
||||
isToolAdvertised(alternative),
|
||||
);
|
||||
if (descriptor === undefined)
|
||||
return {
|
||||
reason: "provider_missing",
|
||||
remediation:
|
||||
"Install or configure a provider that declares this operation.",
|
||||
...(offered === undefined ? {} : { alternatives: offered.operations }),
|
||||
};
|
||||
}
|
||||
return descriptor.available
|
||||
? { reason: "available", remediation: null }
|
||||
: {
|
||||
|
||||
@@ -93,12 +93,7 @@ it("joins concurrent shutdowns and seals ownership before asynchronous cleanup s
|
||||
try {
|
||||
await awaitAcknowledgement(entered, first, "capability cleanup");
|
||||
second = scope.close();
|
||||
let secondSettled = false;
|
||||
void second.then(() => {
|
||||
secondSettled = true;
|
||||
});
|
||||
await Promise.resolve();
|
||||
expect(secondSettled).toBe(false);
|
||||
expect(second).toBe(first);
|
||||
expect(close).toHaveBeenCalledTimes(1);
|
||||
expect(() => scope.own("later-owner", {}, async () => undefined)).toThrow(
|
||||
"after host shutdown",
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
import { CLAUDE_DESKTOP_PACKAGE_FAMILY } from "../../tests/fixtures/claudeDesktop.js";
|
||||
import { basename, dirname, join, sep } from "node:path";
|
||||
|
||||
import { describe, expect, it } from "vitest";
|
||||
|
||||
import {
|
||||
CLAUDE_DESKTOP_PACKAGE_FAMILY,
|
||||
resolveWindowsClaudeDesktopLocation,
|
||||
type ClaudeDesktopLocationFileSystem,
|
||||
} from "./ClaudeDesktopConfigLocation.js";
|
||||
import {
|
||||
packagePrivateLauncherBlocker,
|
||||
packagePrivateStorageFamily,
|
||||
redirectedWriteBlocker,
|
||||
type MsixPackageView,
|
||||
windowsAppDataRoots,
|
||||
@@ -641,19 +642,15 @@ describe("package-private REA launchers", () => {
|
||||
"rea.mjs",
|
||||
);
|
||||
|
||||
it("blocks private cache paths without treating other package paths as private", () => {
|
||||
const identity = (path: string) => path;
|
||||
it("names the package that privately stores a path", () => {
|
||||
expect(packagePrivateStorageFamily(stored, packages)).toBe(
|
||||
CLAUDE_DESKTOP_PACKAGE_FAMILY,
|
||||
);
|
||||
expect(packagePrivateStorageFamily(launcher, packages)).toBeUndefined();
|
||||
expect(
|
||||
packagePrivateLauncherBlocker([stored], packages, identity),
|
||||
).toContain(CLAUDE_DESKTOP_PACKAGE_FAMILY);
|
||||
expect(
|
||||
packagePrivateLauncherBlocker([launcher], packages, identity),
|
||||
).toBeUndefined();
|
||||
expect(
|
||||
packagePrivateLauncherBlocker(
|
||||
[join(packages, CLAUDE_DESKTOP_PACKAGE_FAMILY, "LocalState", "x")],
|
||||
packagePrivateStorageFamily(
|
||||
join(packages, CLAUDE_DESKTOP_PACKAGE_FAMILY, "LocalState", "x"),
|
||||
packages,
|
||||
identity,
|
||||
),
|
||||
).toBeUndefined();
|
||||
});
|
||||
|
||||
@@ -29,7 +29,7 @@ const PROBES_PER_DIRECTORY = 2;
|
||||
* publisher ID Windows derives from `CN="Anthropic, PBC", O="Anthropic, PBC",
|
||||
* L=San Francisco, S=California, C=US, …`.
|
||||
*/
|
||||
const CLAUDE_DESKTOP_PACKAGE_FAMILY = "Claude_pzs8sxrjxfjjc";
|
||||
export const CLAUDE_DESKTOP_PACKAGE_FAMILY = "Claude_pzs8sxrjxfjjc";
|
||||
|
||||
/** Observed Claude package names plus Windows' 13-character publisher ID. */
|
||||
const CLAUDE_PACKAGE_FAMILY =
|
||||
|
||||
@@ -23,14 +23,14 @@ export interface ClientConfigurationSource extends ClientConfigurationDocument {
|
||||
const invalidEnvironment = (
|
||||
path: string,
|
||||
error: ConfigurationError,
|
||||
overrides: Readonly<Record<string, string>> | undefined,
|
||||
platform: NodeJS.Platform,
|
||||
overrides: Readonly<Record<string, string>> = {},
|
||||
platform: NodeJS.Platform = process.platform,
|
||||
): ClientConfigurationFileError => {
|
||||
const constraints = error.settings
|
||||
.map(({ setting, constraint }) => `${setting}: ${constraint}`)
|
||||
.join("; ");
|
||||
const overrideNames = new Set(
|
||||
Object.keys(overrides ?? {}).map((name) =>
|
||||
Object.keys(overrides).map((name) =>
|
||||
platform === "win32" ? name.toUpperCase() : name,
|
||||
),
|
||||
);
|
||||
|
||||
@@ -1,9 +1,15 @@
|
||||
import { validateRegistrationEnvironment } from "./RegistrationEnvironmentValidation.js";
|
||||
import { clientRegistrationSource } from "./ClientRegistrationSource.js";
|
||||
import type { SetupClient } from "./SupportedClients.js";
|
||||
|
||||
import { launchAnalysisSetting } from "../config/analysisSettings.js";
|
||||
import type { Environment } from "../config/environment.js";
|
||||
import {
|
||||
inspectAnalysisSettingSeeds,
|
||||
launchAnalysisSetting,
|
||||
} from "../config/analysisSettings.js";
|
||||
import {
|
||||
parseEnvironment,
|
||||
parseEnvironmentValues,
|
||||
type Environment,
|
||||
} from "../config/environment.js";
|
||||
import {
|
||||
DEFAULT_GHIDRA_STARTUP_TIMEOUT_MS,
|
||||
DEFAULT_HOPPER_STARTUP_TIMEOUT_MS,
|
||||
@@ -308,24 +314,34 @@ export const clientRegistrationEnvironmentDetailsWithBudget = async (
|
||||
const validatedDetails = (
|
||||
environment: Readonly<Record<string, string>>,
|
||||
validation: "fragment" | "effective",
|
||||
platform: NodeJS.Platform,
|
||||
expressionSettings: ReadonlySet<string>,
|
||||
platform: NodeJS.Platform = process.platform,
|
||||
expressionSettings: ReadonlySet<string> = new Set(),
|
||||
): Result<ClientRegistrationEnvironmentDetails, ConfigurationError> => {
|
||||
const validated = validateRegistrationEnvironment(
|
||||
environment,
|
||||
expressionSettings,
|
||||
validation,
|
||||
platform,
|
||||
const runtimeEnvironment = snapshotEnvironment(environment, platform);
|
||||
const unresolved = new Set(
|
||||
Object.keys(
|
||||
snapshotEnvironment(
|
||||
Object.fromEntries([...expressionSettings].map((name) => [name, ""])),
|
||||
platform,
|
||||
),
|
||||
),
|
||||
);
|
||||
return validated.ok
|
||||
? ok(
|
||||
environmentDetails(
|
||||
environment,
|
||||
validated.value.configuration,
|
||||
validated.value.unresolvedSettings,
|
||||
),
|
||||
)
|
||||
: validated;
|
||||
const validated =
|
||||
validation === "fragment"
|
||||
? parseEnvironmentValues(runtimeEnvironment, unresolved)
|
||||
: parseEnvironment(runtimeEnvironment, unresolved);
|
||||
if (!validated.ok) return validated;
|
||||
const seedIssues = inspectAnalysisSettingSeeds(
|
||||
runtimeEnvironment,
|
||||
unresolved,
|
||||
);
|
||||
if (seedIssues.length > 0)
|
||||
return err(
|
||||
new ConfigurationError("Invalid REA environment configuration", {
|
||||
settings: seedIssues,
|
||||
}),
|
||||
);
|
||||
return ok(environmentDetails(environment, validated.value, unresolved));
|
||||
};
|
||||
|
||||
const admittedTimeout = (
|
||||
@@ -381,7 +397,7 @@ const registrationTimeoutInputs = (
|
||||
const environmentDetails = (
|
||||
environment: Readonly<Record<string, string>>,
|
||||
configuration: Environment,
|
||||
unresolvedSettings: ReadonlySet<string>,
|
||||
unresolvedSettings: ReadonlySet<string> = new Set(),
|
||||
): ClientRegistrationEnvironmentDetails => ({
|
||||
values: Object.fromEntries(
|
||||
Object.entries(environment).sort(([left], [right]) =>
|
||||
|
||||
@@ -649,7 +649,7 @@ const packageVersionRemediation = (
|
||||
const unavailableStatus = (
|
||||
client: SetupClient,
|
||||
state: "missing" | "invalid",
|
||||
configPath: string,
|
||||
configPath: string = client.configPath,
|
||||
): ClientRegistrationStatus => ({
|
||||
client: client.name,
|
||||
config_path: configPath,
|
||||
|
||||
@@ -67,7 +67,10 @@ import type { AnalysisProfileCommitment } from "../domain/analysisProfile.js";
|
||||
import { profilelessNativeDispatchProfile } from "./binary/ProfilelessNativeWorkflowSnapshot.js";
|
||||
import { err, ok, type Result } from "../domain/result.js";
|
||||
import type { AnalysisSnapshot } from "../domain/analysisSnapshot.js";
|
||||
import type { AnalysisExecution } from "./AnalysisProvider.js";
|
||||
import type {
|
||||
AnalysisExecution,
|
||||
ProviderIdentity,
|
||||
} from "./AnalysisProvider.js";
|
||||
import { createAnalysisExecutionEvidence } from "../domain/analysisObservation.js";
|
||||
import { REA_WORKFLOW_PROVIDER } from "../domain/investigationProviders.js";
|
||||
import { workflowAnalysisProfile } from "./WorkflowAnalysisProfile.js";
|
||||
@@ -293,7 +296,7 @@ export const runProviderAnalysis = async (
|
||||
delivery.detail,
|
||||
operationSignal,
|
||||
);
|
||||
return result.ok ? result : err(cliError(result.error, path));
|
||||
return result.ok ? ok(result.value) : err(cliError(result.error, path));
|
||||
}
|
||||
const admitted = admitOneShotOperation(tool, arguments_, operationSignal);
|
||||
if (!admitted.ok) return err(cliError(admitted.error, path));
|
||||
@@ -442,14 +445,14 @@ const runAnalysis = async (
|
||||
let isDirectory = false;
|
||||
if (BUNDLE_RESOURCE_OPERATIONS.has(tool)) {
|
||||
const inspected = await inspectBundleResourceInput(path);
|
||||
if (!inspected.ok) return inspected;
|
||||
if (!inspected.ok) return err(inspected.error);
|
||||
isDirectory = inspected.value;
|
||||
}
|
||||
if (BUNDLE_RESOURCE_OPERATIONS.has(tool) && isDirectory) {
|
||||
const opened = await session.openBundleResources(path, { signal });
|
||||
if (!opened.ok) return opened;
|
||||
if (!opened.ok) return err(opened.error);
|
||||
const execution = await session.execute(tool, arguments_, { signal });
|
||||
if (!execution.ok) return execution;
|
||||
if (!execution.ok) return err(execution.error);
|
||||
return ok(
|
||||
withEvidenceCallerInputPath(
|
||||
createAnalysisExecutionEvidence(
|
||||
@@ -469,7 +472,7 @@ const runAnalysis = async (
|
||||
signal,
|
||||
...targetSelection(options),
|
||||
});
|
||||
if (!prepared.ok) return prepared;
|
||||
if (!prepared.ok) return err(prepared.error);
|
||||
const { snapshot } = prepared.value;
|
||||
let resolvedTarget: ResolvedSessionOpen | undefined;
|
||||
if (snapshot !== undefined && prepared.value.target !== undefined) {
|
||||
@@ -481,7 +484,7 @@ const runAnalysis = async (
|
||||
? {}
|
||||
: { providerId: options.providerId }),
|
||||
});
|
||||
if (!preview.ok) return preview;
|
||||
if (!preview.ok) return err(preview.error);
|
||||
resolvedTarget = preview.value;
|
||||
const route = preview.value.route;
|
||||
const bindingProfile =
|
||||
@@ -545,7 +548,7 @@ const runAnalysis = async (
|
||||
resolvedTarget === undefined
|
||||
? await session.open(path, openOptions)
|
||||
: await session.openResolvedTarget(resolvedTarget, openOptions);
|
||||
if (!opened.ok) return opened;
|
||||
if (!opened.ok) return err(opened.error);
|
||||
const evidenceProfile = analysisProfileForEvidence(session, tool);
|
||||
const executed = await executeAnalysisTool({
|
||||
session,
|
||||
|
||||
@@ -1,11 +1,18 @@
|
||||
import { validateRegistrationEnvironment } from "./RegistrationEnvironmentValidation.js";
|
||||
import { inspectAnalysisSettingSeeds } from "../config/analysisSettings.js";
|
||||
import { isMap, isSeq, type Node, type YAMLMap } from "yaml";
|
||||
import type { Environment } from "../config/environment.js";
|
||||
import {
|
||||
parseEnvironment,
|
||||
parseEnvironmentValues,
|
||||
type Environment,
|
||||
} from "../config/environment.js";
|
||||
import { ConfigurationError } from "../domain/configurationErrors.js";
|
||||
import { err, ok, type Result } from "../domain/result.js";
|
||||
import type { ClientConfigurationDocument } from "./ClientConfigurationDocument.js";
|
||||
import { CordisExpression, DshCordisYaml } from "./DshCordisYaml.js";
|
||||
import { mergeEnvironmentOverrides } from "../process/snapshotEnvironment.js";
|
||||
import {
|
||||
mergeEnvironmentOverrides,
|
||||
snapshotEnvironment,
|
||||
} from "../process/snapshotEnvironment.js";
|
||||
|
||||
export const DSH_ENTRY_ID = "rea-mcp";
|
||||
export const DSH_CLIENT_PACKAGE = "@deepseek-ai/dsh-mcp-client";
|
||||
@@ -248,15 +255,35 @@ export class DshCordisDocument {
|
||||
);
|
||||
literals[key] = value;
|
||||
}
|
||||
const validated = validateRegistrationEnvironment(
|
||||
literals,
|
||||
unresolvedSettings,
|
||||
validation,
|
||||
platform,
|
||||
const runtimeEnvironment = snapshotEnvironment(literals, platform);
|
||||
const unresolved = new Set(
|
||||
Object.keys(
|
||||
snapshotEnvironment(
|
||||
Object.fromEntries([...unresolvedSettings].map((key) => [key, ""])),
|
||||
platform,
|
||||
),
|
||||
),
|
||||
);
|
||||
return validated.ok
|
||||
? ok({ values: literals, ...validated.value })
|
||||
: validated;
|
||||
const validated =
|
||||
validation === "fragment"
|
||||
? parseEnvironmentValues(runtimeEnvironment, unresolved)
|
||||
: parseEnvironment(runtimeEnvironment, unresolved);
|
||||
if (!validated.ok) return validated;
|
||||
const seedIssues = inspectAnalysisSettingSeeds(
|
||||
runtimeEnvironment,
|
||||
unresolved,
|
||||
);
|
||||
if (seedIssues.length > 0)
|
||||
return err(
|
||||
new ConfigurationError("Invalid REA environment configuration", {
|
||||
settings: seedIssues,
|
||||
}),
|
||||
);
|
||||
return ok({
|
||||
values: literals,
|
||||
configuration: validated.value,
|
||||
unresolvedSettings: unresolved,
|
||||
});
|
||||
}
|
||||
|
||||
desired(
|
||||
|
||||
@@ -307,7 +307,9 @@ const projectWrite = (
|
||||
bundle: EvidenceBundle,
|
||||
written: Result<PublishedEvidenceFile, AnalysisError>,
|
||||
): Result<JsonValue, AnalysisError> =>
|
||||
written.ok ? ok(evidenceBundleExportReceipt(bundle, written.value)) : written;
|
||||
written.ok
|
||||
? ok(evidenceBundleExportReceipt(bundle, written.value))
|
||||
: err(written.error);
|
||||
|
||||
/** Standalone bundle discovery shares the same read owner as import and comparison. */
|
||||
export const inspectEvidenceBundleCommand = async (
|
||||
|
||||
@@ -31,11 +31,16 @@ import {
|
||||
import { readJsonFile, writeTextParts } from "./JsonFiles.js";
|
||||
import type { ArtifactResourceScope } from "../artifacts/ArtifactResourceScope.js";
|
||||
|
||||
type EvidenceBundleFileFailure =
|
||||
type EvidenceReadFailure =
|
||||
| EvidenceFileError
|
||||
| EvidenceIntegrityError
|
||||
| AnalysisResourceConstraintError
|
||||
| AnalysisCancelledError;
|
||||
type EvidenceWriteFailure =
|
||||
| EvidenceFileError
|
||||
| EvidenceIntegrityError
|
||||
| AnalysisCancelledError
|
||||
| AnalysisResourceConstraintError;
|
||||
|
||||
/** Project a published bundle with record and residual-unknown revision counts. */
|
||||
export const evidenceBundleExportReceipt = (
|
||||
@@ -54,7 +59,7 @@ export const readEvidenceBundle = (
|
||||
signal?: AbortSignal,
|
||||
resources?: ArtifactResourceScope,
|
||||
operation = "import_evidence_bundle",
|
||||
): Promise<Result<EvidenceBundle, EvidenceBundleFileFailure>> =>
|
||||
): Promise<Result<EvidenceBundle, EvidenceReadFailure>> =>
|
||||
readBundle(path, false, signal, resources, operation);
|
||||
|
||||
/** Read an authenticated immutable snapshot for a subsequent session import. */
|
||||
@@ -63,7 +68,7 @@ export const readImmutableEvidenceBundle = (
|
||||
signal?: AbortSignal,
|
||||
resources?: ArtifactResourceScope,
|
||||
operation = "import_evidence_bundle",
|
||||
): Promise<Result<EvidenceBundle, EvidenceBundleFileFailure>> =>
|
||||
): Promise<Result<EvidenceBundle, EvidenceReadFailure>> =>
|
||||
readBundle(path, true, signal, resources, operation);
|
||||
|
||||
/** Join both comparison reads and preserve cleanup owned by either failed input. */
|
||||
@@ -104,7 +109,7 @@ const readBundle = async (
|
||||
signal?: AbortSignal,
|
||||
resources?: ArtifactResourceScope,
|
||||
operation = "import_evidence_bundle",
|
||||
): Promise<Result<EvidenceBundle, EvidenceBundleFileFailure>> => {
|
||||
): Promise<Result<EvidenceBundle, EvidenceReadFailure>> => {
|
||||
if (signal?.aborted)
|
||||
return err(
|
||||
new AnalysisCancelledError(operation, {
|
||||
@@ -130,7 +135,7 @@ export const authenticateEvidenceBundleValue = (
|
||||
value: unknown,
|
||||
path: string,
|
||||
options: { readonly operation: string; readonly immutable?: boolean },
|
||||
): Result<EvidenceBundle, EvidenceBundleFileFailure> => {
|
||||
): Result<EvidenceBundle, EvidenceReadFailure> => {
|
||||
const { operation } = options;
|
||||
const headroom = requireAuthenticationHeadroom(value, {
|
||||
operation,
|
||||
@@ -221,7 +226,7 @@ export const writeEvidenceBundle = async (
|
||||
): Promise<
|
||||
Result<
|
||||
{ readonly path: string; readonly bytes: number },
|
||||
EvidenceBundleFileFailure
|
||||
EvidenceWriteFailure
|
||||
>
|
||||
> => {
|
||||
if (signal?.aborted === true)
|
||||
|
||||
@@ -4,6 +4,7 @@ import { parseDocument } from "yaml";
|
||||
import { ConfigurationError } from "../domain/configurationErrors.js";
|
||||
import {
|
||||
editGooseConfigurationYaml,
|
||||
GooseConfigurationYamlError,
|
||||
parseGooseConfigurationYaml,
|
||||
stringifyGooseConfigurationYaml,
|
||||
} from "./GooseConfigurationYaml.js";
|
||||
@@ -110,15 +111,11 @@ describe("Goose YAML 1.2 source facts", () => {
|
||||
} catch (cause: unknown) {
|
||||
failure = cause;
|
||||
}
|
||||
expect(failure).toBeInstanceOf(ConfigurationError);
|
||||
expect(failure).toBeInstanceOf(GooseConfigurationYamlError);
|
||||
expect(failure).toMatchObject({ kind: "shadowed_member", path });
|
||||
expect(failure).toHaveProperty(
|
||||
"message",
|
||||
`Goose YAML contains a duplicate mapping member at ${path.join(".")}`,
|
||||
);
|
||||
expect(() =>
|
||||
editGooseConfigurationYaml(source, ["extensions", "rea"], extension),
|
||||
).toThrow(`duplicate mapping member at ${path.join(".")}`);
|
||||
).toThrow(GooseConfigurationYamlError);
|
||||
},
|
||||
);
|
||||
|
||||
|
||||
@@ -143,7 +143,7 @@ const gooseYamlOptions = {
|
||||
} as const;
|
||||
|
||||
/** A duplicate YAML member cannot establish one selected configuration value. */
|
||||
class GooseConfigurationYamlError extends ConfigurationError {
|
||||
export class GooseConfigurationYamlError extends ConfigurationError {
|
||||
readonly kind = "shadowed_member";
|
||||
constructor(
|
||||
readonly path: readonly string[],
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { expect, it } from "vitest";
|
||||
import { ArtifactResourceScope } from "../artifacts/ArtifactResourceScope.js";
|
||||
import { RegularFileCleanupFailure } from "../filesystem/OwnedRegularFile.js";
|
||||
import { ArtifactReaderFailure } from "../artifacts/ArtifactReader.js";
|
||||
import { MANAGED_SKILL_FILES } from "./SetupSkill.js";
|
||||
import { searchGuidanceOutputSchema } from "../contracts/guidanceContracts.js";
|
||||
import { RetainedRegularFileCleanupFailure } from "./RegularFileRead.js";
|
||||
|
||||
@@ -49,13 +49,13 @@ export type HopperRequestFailure = HopperDownloadFailure & {
|
||||
export const HOPPER_DOWNLOAD_BYTES = 100_000_000;
|
||||
|
||||
/** Longest wait for the response or its next bytes before a download stalls. */
|
||||
const HOPPER_DOWNLOAD_STALL_MS = 30_000;
|
||||
export const HOPPER_DOWNLOAD_STALL_MS = 30_000;
|
||||
|
||||
/**
|
||||
* Overall bound for one download. A slow connection that keeps delivering
|
||||
* bytes is bounded here rather than by a deadline sized for fast networks.
|
||||
*/
|
||||
const HOPPER_DOWNLOAD_TIMEOUT_MS = 15 * 60_000;
|
||||
export const HOPPER_DOWNLOAD_TIMEOUT_MS = 15 * 60_000;
|
||||
|
||||
/** Small release feed and key requests must not use the package bounds. */
|
||||
export const HOPPER_METADATA_TIMEOUT_MS = 10_000;
|
||||
|
||||
@@ -4,8 +4,9 @@ import { join } from "node:path";
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
|
||||
import {
|
||||
formatCommandForDisplay,
|
||||
installLinuxHopper,
|
||||
linuxHopperInstallDisclosure,
|
||||
linuxPackageManagerCommands,
|
||||
linuxSharedLibrariesAvailable,
|
||||
parseLinuxDistribution,
|
||||
supportsReaHost,
|
||||
@@ -30,6 +31,19 @@ import * as nativeCommands from "../process/ExecFileOutput.js";
|
||||
import * as pythonRuntime from "./LinuxHopperPython.js";
|
||||
import { createTestTempDirectory } from "../../tests/fixtures/temporaryDirectory.js";
|
||||
|
||||
describe("Linux package-manager command display", () => {
|
||||
it("preserves argument boundaries for paths with spaces and quotes", () => {
|
||||
expect(
|
||||
formatCommandForDisplay("pkexec", [
|
||||
"pacman",
|
||||
"-U",
|
||||
"/tmp/rea test/hopper.arch",
|
||||
"apostrophe'path",
|
||||
]),
|
||||
).toBe('pkexec pacman -U "/tmp/rea test/hopper.arch" "apostrophe\'path"');
|
||||
});
|
||||
});
|
||||
|
||||
class RecordingLinuxHost implements LinuxHopperInstallHost {
|
||||
distributionValue: LinuxDistribution | undefined = {
|
||||
id: "ubuntu",
|
||||
@@ -249,34 +263,47 @@ describe("Linux Hopper installation", () => {
|
||||
] as const)(
|
||||
"selects the %s native package manager and dependencies",
|
||||
(family, executable, packages) => {
|
||||
const root = linuxHopperInstallDisclosure(family, true).commands;
|
||||
const nonRoot = linuxHopperInstallDisclosure(family, false).commands;
|
||||
expect(root.some((command) => command.startsWith(`${executable} `))).toBe(
|
||||
true,
|
||||
);
|
||||
for (const dependency of packages)
|
||||
expect(
|
||||
root.some((command) => command.split(" ").includes(dependency)),
|
||||
).toBe(true);
|
||||
expect(
|
||||
nonRoot.some(
|
||||
(command) =>
|
||||
command.startsWith(`pkexec ${executable} `) &&
|
||||
command.includes(`"<verified-hopper.${family}>"`),
|
||||
),
|
||||
).toBe(true);
|
||||
linuxPackageManagerCommands(family, "/tmp/Hopper package", true),
|
||||
).toContainEqual(
|
||||
expect.objectContaining({
|
||||
executable,
|
||||
args: expect.arrayContaining([...packages]),
|
||||
}),
|
||||
);
|
||||
expect(
|
||||
linuxPackageManagerCommands(family, "/tmp/Hopper package", false),
|
||||
).toContainEqual(
|
||||
expect.objectContaining({
|
||||
executable: "pkexec",
|
||||
args: expect.arrayContaining([executable, "/tmp/Hopper package"]),
|
||||
}),
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
it.each([true, false])(
|
||||
"keeps installed apt dependencies at their versions while Hopper may upgrade (root: %s)",
|
||||
(isRoot) => {
|
||||
const prefix = isRoot ? "" : "pkexec ";
|
||||
const prefix = isRoot ? [] : ["pkexec"];
|
||||
expect(
|
||||
linuxHopperInstallDisclosure("deb", isRoot).commands.slice(0, 2),
|
||||
linuxPackageManagerCommands("deb", "/tmp/Hopper package", isRoot).map(
|
||||
({ executable, args }) => [executable, ...args],
|
||||
),
|
||||
).toEqual([
|
||||
`${prefix}apt-get install -y --no-upgrade xvfb xauth python3 libx11-6 libxtst6`,
|
||||
`${prefix}apt-get install -y "<verified-hopper.deb>"`,
|
||||
[
|
||||
...prefix,
|
||||
"apt-get",
|
||||
"install",
|
||||
"-y",
|
||||
"--no-upgrade",
|
||||
"xvfb",
|
||||
"xauth",
|
||||
"python3",
|
||||
"libx11-6",
|
||||
"libxtst6",
|
||||
],
|
||||
[...prefix, "apt-get", "install", "-y", "/tmp/Hopper package"],
|
||||
]);
|
||||
},
|
||||
);
|
||||
|
||||
@@ -511,7 +511,7 @@ export const installLinuxHopper = async (
|
||||
};
|
||||
|
||||
/** Canonical launcher path for a legacy user-local Linux Hopper installation. */
|
||||
const linuxHopperLauncherPath = (home: string): string =>
|
||||
export const linuxHopperLauncherPath = (home: string): string =>
|
||||
appendCallerPath(home, ".local/share/rea/hopper/bin/Hopper", "linux");
|
||||
|
||||
/** REA's managed Linux install path, preferred when no explicit launcher is set. */
|
||||
@@ -796,7 +796,7 @@ const runPackageManagerCommand = async (
|
||||
};
|
||||
|
||||
/** Preserve argument boundaries in a command shown to the user. */
|
||||
const formatCommandForDisplay = (
|
||||
export const formatCommandForDisplay = (
|
||||
executable: string,
|
||||
args: readonly string[],
|
||||
): string =>
|
||||
@@ -807,7 +807,7 @@ const formatCommandForDisplay = (
|
||||
.join(" ");
|
||||
|
||||
/** Select the native package manager and authorization boundary without shell evaluation. */
|
||||
const linuxPackageManagerCommands = (
|
||||
export const linuxPackageManagerCommands = (
|
||||
family: LinuxPackageFamily,
|
||||
archive: string,
|
||||
isRoot: boolean,
|
||||
|
||||
@@ -6,11 +6,16 @@ import { err, ok } from "../domain/result.js";
|
||||
import * as pythonRuntime from "./LinuxHopperPython.js";
|
||||
import {
|
||||
linuxHopperInstallDisclosure,
|
||||
linuxPackageManagerCommands,
|
||||
systemLinuxHopperInstallHost,
|
||||
} from "./LinuxHopper.js";
|
||||
|
||||
/** Package transactions that install Hopper before any runtime library repair. */
|
||||
const debCommands = 2;
|
||||
const debCommands = linuxPackageManagerCommands(
|
||||
"deb",
|
||||
"/tmp/verified-hopper.deb",
|
||||
false,
|
||||
).length;
|
||||
|
||||
const missingPython = {
|
||||
interpreter: "/usr/bin/python3",
|
||||
@@ -36,34 +41,6 @@ const commandSuccess = {
|
||||
};
|
||||
|
||||
describe("Linux Hopper package runtime", () => {
|
||||
it("preserves package path boundaries in the reported failed command", async () => {
|
||||
const directory = await createTestTempDirectory("rea-hopper-command-");
|
||||
const host = systemLinuxHopperInstallHost(
|
||||
{ XDG_CACHE_HOME: directory },
|
||||
async () => undefined,
|
||||
);
|
||||
const archive = "/tmp/rea test/hopper's package.rpm";
|
||||
const command = vi
|
||||
.spyOn(boundedCommands, "execFileBoundedOutput")
|
||||
.mockResolvedValue({
|
||||
exitCode: 1,
|
||||
stdout: "",
|
||||
stderr: "fixture failure",
|
||||
outputTruncated: false,
|
||||
});
|
||||
try {
|
||||
const result = await host.installPackage("rpm", archive);
|
||||
expect(command.mock.calls[0]?.[1]).toContain(archive);
|
||||
expect(result).toMatchObject({
|
||||
status: "failed",
|
||||
failure: { command: expect.stringContaining(`"${archive}"`) },
|
||||
});
|
||||
} finally {
|
||||
command.mockRestore();
|
||||
await host.close?.();
|
||||
}
|
||||
});
|
||||
|
||||
it.each([
|
||||
{
|
||||
name: "installs and verifies the matching future Python library",
|
||||
|
||||
@@ -11,7 +11,7 @@ import {
|
||||
import { tmpdir } from "node:os";
|
||||
import { join, posix, relative } from "node:path";
|
||||
import { installMacHopperBundle } from "./MacHopper.js";
|
||||
import { linuxHopperLauncherCandidates } from "./LinuxHopper.js";
|
||||
import { linuxHopperLauncherPath } from "./LinuxHopper.js";
|
||||
import { homeDirectoryFromEnvironment } from "../config/homeDirectory.js";
|
||||
import { describe, expect, it } from "vitest";
|
||||
|
||||
@@ -19,17 +19,34 @@ import {
|
||||
localMacHopperRenamedLauncherCandidates,
|
||||
macHopperCanonicalLauncherCandidates,
|
||||
macHopperUserApplicationPath,
|
||||
macHopperRenamedLauncherCandidates,
|
||||
readMacHopperRenamedLauncherCandidates,
|
||||
} from "./MacHopperPaths.js";
|
||||
|
||||
describe("macOS Hopper launcher paths", () => {
|
||||
const home = "/fixture/home";
|
||||
|
||||
it("keeps canonical system and user candidates in order", () => {
|
||||
it("keeps canonical system and user candidates ahead of renamed bundles", () => {
|
||||
expect(macHopperCanonicalLauncherCandidates(home)).toEqual([
|
||||
"/Applications/Hopper Disassembler.app/Contents/MacOS/hopper",
|
||||
"/fixture/home/Applications/Hopper Disassembler.app/Contents/MacOS/hopper",
|
||||
]);
|
||||
expect(
|
||||
macHopperRenamedLauncherCandidates(
|
||||
home,
|
||||
new Map([
|
||||
[
|
||||
"/Applications",
|
||||
["Hopper z.app", "Hopper a.app", "Hopper Disassembler.app"],
|
||||
],
|
||||
["/fixture/home/Applications", ["Hopper User.app"]],
|
||||
]),
|
||||
),
|
||||
).toEqual([
|
||||
"/Applications/Hopper a.app/Contents/MacOS/hopper",
|
||||
"/Applications/Hopper z.app/Contents/MacOS/hopper",
|
||||
"/fixture/home/Applications/Hopper User.app/Contents/MacOS/hopper",
|
||||
]);
|
||||
});
|
||||
|
||||
it.skipIf(process.platform === "win32")(
|
||||
@@ -67,7 +84,7 @@ describe("macOS Hopper launcher paths", () => {
|
||||
expect(macHopperCanonicalLauncherCandidates(home)[1]).toBe(
|
||||
`${home}/Applications/Hopper Disassembler.app/Contents/MacOS/hopper`,
|
||||
);
|
||||
expect(linuxHopperLauncherCandidates(home)[1]).toBe(
|
||||
expect(linuxHopperLauncherPath(home)).toBe(
|
||||
`${home}/.local/share/rea/hopper/bin/Hopper`,
|
||||
);
|
||||
const source = join(temporary, "source.app");
|
||||
@@ -137,17 +154,13 @@ describe("macOS Hopper launcher paths", () => {
|
||||
recursive: true,
|
||||
});
|
||||
await mkdir(join(applications, "Hopper Disassembler.app"));
|
||||
await mkdir(join(applications, "Hopper Alpha.app"));
|
||||
await mkdir(join(applications, "Hopper Zeta.app"));
|
||||
await writeFile(join(applications, "Hopper File.app"), "");
|
||||
const runtime = [...localMacHopperRenamedLauncherCandidates(home)];
|
||||
expect(runtime.filter((path) => path.startsWith(home))).toEqual([
|
||||
posix.join(home, "Applications/Hopper Alpha.app/Contents/MacOS/hopper"),
|
||||
posix.join(
|
||||
home,
|
||||
"Applications/Hopper Preview.app/Contents/MacOS/hopper",
|
||||
),
|
||||
posix.join(home, "Applications/Hopper Zeta.app/Contents/MacOS/hopper"),
|
||||
]);
|
||||
expect(await readMacHopperRenamedLauncherCandidates(home)).toEqual(
|
||||
runtime,
|
||||
|
||||
@@ -43,7 +43,7 @@ export const macHopperCanonicalLauncherCandidates = (
|
||||
];
|
||||
|
||||
/** Build deterministic candidates from the discovered app bundle names. */
|
||||
const macHopperRenamedLauncherCandidates = (
|
||||
export const macHopperRenamedLauncherCandidates = (
|
||||
homeDirectory: string,
|
||||
bundleNamesByRoot: ReadonlyMap<string, readonly string[]>,
|
||||
): readonly string[] =>
|
||||
|
||||
@@ -12,7 +12,6 @@ import { join, sep } from "node:path";
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
|
||||
import { createTestTempDirectory } from "../../tests/fixtures/temporaryDirectory.js";
|
||||
import { awaitAcknowledgement } from "../../tests/fixtures/lifecycleAcknowledgement.js";
|
||||
import { ok } from "../domain/result.js";
|
||||
import { ArtifactResourceScope } from "../artifacts/ArtifactResourceScope.js";
|
||||
let resources: ArtifactResourceScope;
|
||||
@@ -613,22 +612,17 @@ describe("Registration cancellation and sibling outcomes", () => {
|
||||
entered();
|
||||
await blocked;
|
||||
});
|
||||
try {
|
||||
await awaitAcknowledgement(admitted, first, "registration transaction");
|
||||
const controller = new AbortController();
|
||||
const queued = register(path, launcher, controller.signal);
|
||||
controller.abort("queued cancellation");
|
||||
unblock();
|
||||
await first;
|
||||
expect(await queued).toMatchObject({
|
||||
ok: false,
|
||||
error: { _tag: "AnalysisCancelledError" },
|
||||
});
|
||||
expect(await readFile(path, "utf8")).toBe("{}");
|
||||
} finally {
|
||||
unblock();
|
||||
await first;
|
||||
}
|
||||
await admitted;
|
||||
const controller = new AbortController();
|
||||
const queued = register(path, launcher, controller.signal);
|
||||
controller.abort("queued cancellation");
|
||||
unblock();
|
||||
await first;
|
||||
expect(await queued).toMatchObject({
|
||||
ok: false,
|
||||
error: { _tag: "AnalysisCancelledError" },
|
||||
});
|
||||
expect(await readFile(path, "utf8")).toBe("{}");
|
||||
});
|
||||
|
||||
it("keeps successful siblings after ordinary failures and marks work not started after cancellation", async () => {
|
||||
|
||||
@@ -5,28 +5,7 @@ import { z } from "zod";
|
||||
|
||||
import { createTestTempDirectory } from "../../tests/fixtures/temporaryDirectory.js";
|
||||
import { createTestProcessRegistry } from "../../tests/support/process/processFixture.js";
|
||||
import { resolveMcpRegistrationClients } from "./McpRegistrationCatalog.js";
|
||||
import { ArtifactResourceScope } from "../artifacts/ArtifactResourceScope.js";
|
||||
|
||||
const selectAgent = async (agent: string) => {
|
||||
const root = await createTestTempDirectory("rea-mcp-alias-");
|
||||
const resources = new ArtifactResourceScope();
|
||||
try {
|
||||
return await resolveMcpRegistrationClients(
|
||||
{
|
||||
agents: [agent],
|
||||
global: true,
|
||||
cwd: root,
|
||||
home: root,
|
||||
platform: process.platform,
|
||||
environment: {},
|
||||
},
|
||||
resources,
|
||||
);
|
||||
} finally {
|
||||
await resources.close();
|
||||
}
|
||||
};
|
||||
import { resolveMcpRegistrationClientId } from "./McpRegistrationCatalog.js";
|
||||
|
||||
it.each([
|
||||
["cline-vscode", "cline"],
|
||||
@@ -44,22 +23,15 @@ it.each([
|
||||
["kiro", "kiro-cli"],
|
||||
["mastra", "mastracode"],
|
||||
["pi-agent", "pi"],
|
||||
])("resolves registration alias %s as %s", async (alias, expected) => {
|
||||
const result = await selectAgent(alias.toUpperCase());
|
||||
if (!result.ok) throw result.error;
|
||||
expect(result.value.map(({ id }) => id)).toEqual([expected]);
|
||||
])("retains helper alias %s as %s", (alias, expected) => {
|
||||
expect(resolveMcpRegistrationClientId(alias.toUpperCase())).toBe(expected);
|
||||
});
|
||||
|
||||
it.each(["__proto__", "constructor", "unknown-client"])(
|
||||
"rejects unknown registration identity %s",
|
||||
async (agent) => {
|
||||
const result = await selectAgent(agent);
|
||||
expect(result).toMatchObject({
|
||||
ok: false,
|
||||
error: { _tag: "ConfigurationError" },
|
||||
});
|
||||
},
|
||||
);
|
||||
it("does not treat prototype names or unknown strings as client identities", () => {
|
||||
expect(resolveMcpRegistrationClientId("__proto__")).toBeUndefined();
|
||||
expect(resolveMcpRegistrationClientId("constructor")).toBeUndefined();
|
||||
expect(resolveMcpRegistrationClientId("unknown-client")).toBeUndefined();
|
||||
});
|
||||
|
||||
const clientSchema = z.object({
|
||||
id: z.string(),
|
||||
|
||||
@@ -356,7 +356,7 @@ const ALIASES = {
|
||||
const isClientId = (value: string): value is McpRegistrationClientId =>
|
||||
Object.hasOwn(MCP_REGISTRATION_CLIENTS, value);
|
||||
|
||||
const resolveMcpRegistrationClientId = (
|
||||
export const resolveMcpRegistrationClientId = (
|
||||
input: string,
|
||||
): McpRegistrationClientId | undefined => {
|
||||
const lower = input.toLowerCase();
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { readElfAttributeUleb } from "../domain/elfAttributeUleb.js";
|
||||
import type { MipsGnuAttributes } from "../domain/binaryTargetTypes.js";
|
||||
import { err, ok, type Result } from "../domain/result.js";
|
||||
|
||||
@@ -23,6 +22,21 @@ export const parseMipsGnuAttributes = (
|
||||
|
||||
const readU32 = (offset: number): number =>
|
||||
littleEndian ? bytes.readUInt32LE(offset) : bytes.readUInt32BE(offset);
|
||||
const readUleb = (
|
||||
offset: number,
|
||||
end: number,
|
||||
): { readonly value: number; readonly next: number } | undefined => {
|
||||
let value = 0;
|
||||
for (let index = 0; index < 5 && offset + index < end; index += 1) {
|
||||
const byte = bytes[offset + index]!;
|
||||
value += (byte & 0x7f) * 2 ** (7 * index);
|
||||
if ((byte & 0x80) === 0)
|
||||
return value <= 0xffffffff
|
||||
? { value, next: offset + index + 1 }
|
||||
: undefined;
|
||||
}
|
||||
return undefined;
|
||||
};
|
||||
|
||||
let fpAbi: number | null = null;
|
||||
let msa: number | null = null;
|
||||
@@ -51,7 +65,7 @@ export const parseMipsGnuAttributes = (
|
||||
let cursor = vendorEnd + 1;
|
||||
while (cursor < end) {
|
||||
const scopeStart = cursor;
|
||||
const scope = readElfAttributeUleb(bytes, cursor, end);
|
||||
const scope = readUleb(cursor, end);
|
||||
if (scope === undefined)
|
||||
return err("malformed MIPS GNU attribute scope tag");
|
||||
if (scope.value !== TAG_FILE)
|
||||
@@ -71,7 +85,7 @@ export const parseMipsGnuAttributes = (
|
||||
const scopeEnd = scopeStart + scopeLength;
|
||||
cursor = scope.next + 4;
|
||||
while (cursor < scopeEnd) {
|
||||
const tag = readElfAttributeUleb(bytes, cursor, scopeEnd);
|
||||
const tag = readUleb(cursor, scopeEnd);
|
||||
if (tag === undefined) return err("malformed MIPS GNU attribute tag");
|
||||
if (
|
||||
tag.value !== TAG_GNU_MIPS_ABI_FP &&
|
||||
@@ -80,7 +94,7 @@ export const parseMipsGnuAttributes = (
|
||||
return err(
|
||||
`MIPS ELF declares GNU attribute tag ${tag.value}, which REA does not inspect`,
|
||||
);
|
||||
const value = readElfAttributeUleb(bytes, tag.next, scopeEnd);
|
||||
const value = readUleb(tag.next, scopeEnd);
|
||||
if (value === undefined)
|
||||
return err("malformed MIPS GNU attribute value");
|
||||
if (tag.value === TAG_GNU_MIPS_ABI_FP) {
|
||||
|
||||
@@ -54,7 +54,7 @@ const pathWithin = (path: string, root: string): boolean => {
|
||||
* processes see those files at virtual AppData locations; other processes do
|
||||
* not, and Windows removes them with the package.
|
||||
*/
|
||||
const packagePrivateStorageFamily = (
|
||||
export const packagePrivateStorageFamily = (
|
||||
canonicalPath: string,
|
||||
packagesDirectory: string,
|
||||
): string | undefined => {
|
||||
|
||||
@@ -1,84 +0,0 @@
|
||||
import type { AnalysisOperation } from "./AnalysisProvider.js";
|
||||
|
||||
/** One operation that observes part of what a missing operation answers. */
|
||||
interface OperationAlternative {
|
||||
readonly operation: AnalysisOperation;
|
||||
/** What it returns, as a noun phrase. */
|
||||
readonly observes: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Follow-ups for one question shape that an undeclared operation would have
|
||||
* answered. They are conditional rather than substitutes: `limitation`
|
||||
* states what none of them establishes.
|
||||
*/
|
||||
interface OperationAlternativeRelation {
|
||||
readonly question: string;
|
||||
readonly alternatives: readonly OperationAlternative[];
|
||||
readonly limitation: string;
|
||||
}
|
||||
|
||||
const INSTRUCTION_OBSERVATIONS: OperationAlternativeRelation = {
|
||||
question: "instruction-level questions",
|
||||
alternatives: [
|
||||
{
|
||||
operation: "inspect_native_instruction",
|
||||
observes:
|
||||
"the decoded instruction or data at one exact address, with its length and static flow",
|
||||
},
|
||||
{
|
||||
operation: "read_function_instructions",
|
||||
observes: "one analyzed procedure's instruction listing in address order",
|
||||
},
|
||||
{
|
||||
operation: "procedure_assembly",
|
||||
observes: "one analyzed procedure's assembly text",
|
||||
},
|
||||
],
|
||||
limitation:
|
||||
"None navigates arbitrary analyzed objects such as data or addresses outside a procedure, and neither listing order nor address plus length proves executed control flow.",
|
||||
};
|
||||
|
||||
/** Operations absent from this relation keep their consumer's generic advice. */
|
||||
const OPERATION_ALTERNATIVES: ReadonlyMap<
|
||||
string,
|
||||
OperationAlternativeRelation
|
||||
> = new Map<AnalysisOperation, OperationAlternativeRelation>([
|
||||
["next_address", INSTRUCTION_OBSERVATIONS],
|
||||
["prev_address", INSTRUCTION_OBSERVATIONS],
|
||||
]);
|
||||
|
||||
/** Declared alternatives the caller can run now, in declaration order. */
|
||||
export interface OfferedOperationAlternatives {
|
||||
readonly operations: readonly AnalysisOperation[];
|
||||
/** Each offer's scope, what none establishes, and the provider choice. */
|
||||
readonly remediation: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Select the declared alternatives for an operation the current provider does
|
||||
* not declare. `isOffered` holds only for operations that provider makes
|
||||
* available and the caller advertises. Undefined means none qualifies.
|
||||
*/
|
||||
export const offeredOperationAlternatives = (
|
||||
operation: string,
|
||||
isOffered: (alternative: AnalysisOperation) => boolean,
|
||||
): OfferedOperationAlternatives | undefined => {
|
||||
const relation = OPERATION_ALTERNATIVES.get(operation);
|
||||
if (relation === undefined) return undefined;
|
||||
const offered = relation.alternatives.filter((alternative) =>
|
||||
isOffered(alternative.operation),
|
||||
);
|
||||
if (offered.length === 0) return undefined;
|
||||
const described = offered.map(
|
||||
({ operation: alternative, observes }) => `${alternative} (${observes})`,
|
||||
);
|
||||
const listed =
|
||||
described.length === 1
|
||||
? described[0]
|
||||
: `${described.slice(0, -1).join(", ")} and ${described.at(-1)}`;
|
||||
return {
|
||||
operations: offered.map((alternative) => alternative.operation),
|
||||
remediation: `For ${relation.question}, the current provider offers ${listed}. ${relation.limitation} Running ${operation} itself requires a provider that declares it.`,
|
||||
};
|
||||
};
|
||||
@@ -34,7 +34,7 @@ export interface ParsedReferenceSourceEntries {
|
||||
}
|
||||
|
||||
/** Preserve the observed reader failure and add entry-specific recovery guidance. */
|
||||
const projectReferenceSourceEntryFailure = (
|
||||
export const projectReferenceSourceEntryFailure = (
|
||||
entry: Extract<ReferenceSourceEntry, { status: "failed" }>,
|
||||
): string => `${entry.message} ${entryRecoveryGuidance(entry)}`;
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
|
||||
import {
|
||||
projectReferenceSourceImportError,
|
||||
referenceSourceImportAnalysisError,
|
||||
type ReferenceSourceImportError,
|
||||
} from "./ReferenceSourceImportTypes.js";
|
||||
@@ -19,13 +20,11 @@ describe("reference-source import error projection", () => {
|
||||
parse: "execution_failure",
|
||||
} as const;
|
||||
for (const [code, category] of Object.entries(expectedCategories)) {
|
||||
const projected = projectAnalysisError(
|
||||
referenceSourceImportAnalysisError({
|
||||
tag: "reference-source-import",
|
||||
code: code as ReferenceSourceImportError["code"],
|
||||
message: "EIO while reading /selected/source/src/main.ts",
|
||||
}),
|
||||
);
|
||||
const projected = projectReferenceSourceImportError({
|
||||
tag: "reference-source-import",
|
||||
code: code as ReferenceSourceImportError["code"],
|
||||
message: "EIO while reading /selected/source/src/main.ts",
|
||||
});
|
||||
expect(analysisErrorProjectionSchema.safeParse(projected).success).toBe(
|
||||
true,
|
||||
);
|
||||
|
||||
@@ -5,6 +5,10 @@ import {
|
||||
AnalysisOutputError,
|
||||
} from "../domain/analysisErrorCore.js";
|
||||
import { analysisErrorWithCancellation } from "../domain/analysisErrorCancellation.js";
|
||||
import {
|
||||
projectAnalysisError,
|
||||
type AnalysisErrorProjection,
|
||||
} from "../domain/analysisErrorProjection.js";
|
||||
import type {
|
||||
AnalysisError,
|
||||
AnalysisErrorOptions,
|
||||
@@ -121,6 +125,12 @@ export const referenceSourceImportAnalysisError = (
|
||||
);
|
||||
};
|
||||
|
||||
/** Canonical CLI/MCP projection, retaining source facts under diagnostic details. */
|
||||
export const projectReferenceSourceImportError = (
|
||||
error: ReferenceSourceImportError,
|
||||
): AnalysisErrorProjection =>
|
||||
projectAnalysisError(referenceSourceImportAnalysisError(error));
|
||||
|
||||
/** Import a caller-selected local source tree as historical reference. */
|
||||
export interface ReferenceSourceImportOptions {
|
||||
readonly root: string;
|
||||
|
||||
@@ -1,49 +0,0 @@
|
||||
import { inspectAnalysisSettingSeeds } from "../config/analysisSettings.js";
|
||||
import {
|
||||
parseEnvironment,
|
||||
parseEnvironmentValues,
|
||||
type Environment,
|
||||
} from "../config/environment.js";
|
||||
import { ConfigurationError } from "../domain/configurationErrors.js";
|
||||
import { err, ok, type Result } from "../domain/result.js";
|
||||
import { snapshotEnvironment } from "../process/snapshotEnvironment.js";
|
||||
|
||||
/** Validate literal registration settings while retaining expression-owned unknowns. */
|
||||
export const validateRegistrationEnvironment = (
|
||||
values: Readonly<Record<string, string>>,
|
||||
expressionSettings: ReadonlySet<string>,
|
||||
validation: "fragment" | "effective",
|
||||
platform: NodeJS.Platform,
|
||||
): Result<
|
||||
{
|
||||
readonly configuration: Environment;
|
||||
readonly unresolvedSettings: ReadonlySet<string>;
|
||||
},
|
||||
ConfigurationError
|
||||
> => {
|
||||
const runtimeEnvironment = snapshotEnvironment(values, platform);
|
||||
const unresolvedSettings = new Set(
|
||||
Object.keys(
|
||||
snapshotEnvironment(
|
||||
Object.fromEntries([...expressionSettings].map((name) => [name, ""])),
|
||||
platform,
|
||||
),
|
||||
),
|
||||
);
|
||||
const validated =
|
||||
validation === "fragment"
|
||||
? parseEnvironmentValues(runtimeEnvironment, unresolvedSettings)
|
||||
: parseEnvironment(runtimeEnvironment, unresolvedSettings);
|
||||
if (!validated.ok) return validated;
|
||||
const seedIssues = inspectAnalysisSettingSeeds(
|
||||
runtimeEnvironment,
|
||||
unresolvedSettings,
|
||||
);
|
||||
if (seedIssues.length > 0)
|
||||
return err(
|
||||
new ConfigurationError("Invalid REA environment configuration", {
|
||||
settings: seedIssues,
|
||||
}),
|
||||
);
|
||||
return ok({ configuration: validated.value, unresolvedSettings });
|
||||
};
|
||||
@@ -23,6 +23,7 @@ import { PRODUCT_IDENTITY, SDK_IDENTITY } from "../identity.js";
|
||||
import { DEFAULT_CATALOG_IDENTITY } from "../catalogIdentity.js";
|
||||
import type { ClientRegistrationStatus } from "./ClientRegistrationStatus.js";
|
||||
import { currentClientRegistrationCommand } from "./ClientRegistrationIdentity.js";
|
||||
import { CURRENT_ENTRYPOINT_PATH } from "../process/CurrentEntrypointPath.js";
|
||||
|
||||
/** Recording setup host for service-level planning and recovery tests. */
|
||||
export class FakeSetupHost implements SetupHost {
|
||||
|
||||
@@ -101,16 +101,9 @@ it("starts child finalization synchronously and shares concurrent closes", async
|
||||
]);
|
||||
const first = owner.close();
|
||||
expect(calls).toBe(1);
|
||||
const second = owner.close();
|
||||
let secondSettled = false;
|
||||
void second.then(() => {
|
||||
secondSettled = true;
|
||||
});
|
||||
await Promise.resolve();
|
||||
expect(secondSettled).toBe(false);
|
||||
expect(owner.close()).toBe(first);
|
||||
complete?.();
|
||||
expect(await first).toBeUndefined();
|
||||
expect(await second).toBeUndefined();
|
||||
expect(await owner.close()).toBeUndefined();
|
||||
expect(calls).toBe(1);
|
||||
});
|
||||
|
||||
@@ -34,6 +34,10 @@ export const MANAGED_SKILL_FILES = [
|
||||
"references/runtime-observation.md",
|
||||
"references/evidence-workflows.md",
|
||||
"references/environments.md",
|
||||
"references/firmware-and-raw-images.md",
|
||||
"references/packages-and-archives.md",
|
||||
"references/format-inspectors.md",
|
||||
"references/recorded-captures.md",
|
||||
"references/desktop-build.md",
|
||||
] as const;
|
||||
|
||||
@@ -420,8 +424,8 @@ export const validateCanonicalSkillDirectories = async (
|
||||
const canonicalSkillFiles = async (
|
||||
home: string,
|
||||
clientIds: readonly string[],
|
||||
environment: Readonly<NodeJS.ProcessEnv>,
|
||||
platform: NodeJS.Platform,
|
||||
environment: Readonly<NodeJS.ProcessEnv> = {},
|
||||
platform: NodeJS.Platform = process.platform,
|
||||
resources?: ArtifactResourceScope,
|
||||
): Promise<readonly CanonicalSkillFile[]> => {
|
||||
const destinations = skillDestinations(
|
||||
|
||||
@@ -872,7 +872,7 @@ const readClientConfiguration = async (
|
||||
client: UninstallClient,
|
||||
fileSystem: UninstallFileSystem,
|
||||
resources: ArtifactResourceScope,
|
||||
ownershipEstablished: boolean,
|
||||
ownershipEstablished = false,
|
||||
): Promise<ClientConfigurationRead> => {
|
||||
const applicabilityUnverified =
|
||||
client.applicability === "unverified" && !ownershipEstablished;
|
||||
|
||||
@@ -18,7 +18,7 @@ import { UpdateCommandProgress } from "./UpdateCommandProgress.js";
|
||||
import type { UpdateOutput } from "./Update.js";
|
||||
import { withoutPackageRunnerIdentity } from "./ClientRegistrationIdentity.js";
|
||||
|
||||
const UPDATE_COMMAND_OUTPUT_BYTES = 4 * 1024 * 1024;
|
||||
export const UPDATE_COMMAND_OUTPUT_BYTES = 4 * 1024 * 1024;
|
||||
const UPDATE_PROBE_TIMEOUT_MS = 10_000;
|
||||
|
||||
/** The runner owns whether the process started; callers need not infer it from text. */
|
||||
|
||||
@@ -144,7 +144,7 @@ const INVALID_NPM_RELEASE_METADATA =
|
||||
"Invalid npm release metadata: expected a version string or a single-element version array.";
|
||||
|
||||
/** bun info arguments for dist-tags.latest; Bun resolves its configured registry. */
|
||||
const BUN_LATEST_VERSION_COMMAND: readonly string[] = [
|
||||
export const BUN_LATEST_VERSION_COMMAND: readonly string[] = [
|
||||
"bun",
|
||||
"info",
|
||||
PRODUCT_IDENTITY.packageName,
|
||||
@@ -173,7 +173,7 @@ const npmLatestVersionCommand = (
|
||||
*/
|
||||
const parseNpmLatestVersion = (metadata: string): Result<string, string> => {
|
||||
const decoded = safeParseJson(metadata);
|
||||
if (!decoded.ok) return decoded;
|
||||
if (!decoded.ok) return err(decoded.error);
|
||||
const version = readNpmLatestVersion(decoded.value);
|
||||
return version === undefined
|
||||
? err(INVALID_NPM_RELEASE_METADATA)
|
||||
|
||||
@@ -217,7 +217,7 @@ export const executeComposedWorkflow = async (
|
||||
};
|
||||
|
||||
/** Scope of the exact-address reference lookups composed by trace_feature. */
|
||||
const TRACE_FEATURE_REFERENCE_LIMITATION =
|
||||
export const TRACE_FEATURE_REFERENCE_LIMITATION =
|
||||
"Reference queries cover only each matched start address, not interior bytes of strings and procedures. Empty references and truncated: false do not establish complete reference coverage.";
|
||||
|
||||
/** Build the shared Evidence record for a successful composed binary workflow. */
|
||||
|
||||
@@ -17,7 +17,7 @@ import {
|
||||
AnalysisCapabilityUnavailableError,
|
||||
} from "../../domain/analysisErrorCore.js";
|
||||
import { analysisInputErrorFromIssues } from "../../domain/inputIssueProjection.js";
|
||||
import { validateAnalysisViewSubject } from "../../domain/analysisView/analysisViewParent.js";
|
||||
import { EvidenceIntegrityError } from "../../domain/evidenceErrors.js";
|
||||
import { safeParseEvidence } from "../../domain/evidenceValidation.js";
|
||||
import {
|
||||
createEvidence,
|
||||
@@ -249,11 +249,15 @@ const projectResolvedAnalysisView = (
|
||||
},
|
||||
});
|
||||
if (!projected.ok) return projected;
|
||||
const identity = validateAnalysisViewSubject(
|
||||
parent.subject,
|
||||
projected.value.artifact?.sha256,
|
||||
);
|
||||
if (!identity.ok) return identity;
|
||||
if (
|
||||
parent.subject !== null &&
|
||||
parent.subject.digest.sha256 !== projected.value.artifact?.sha256
|
||||
)
|
||||
return err(
|
||||
new EvidenceIntegrityError(
|
||||
`Parent subject SHA-256 ${parent.subject.digest.sha256} differs from analysis artifact SHA-256 ${projected.value.artifact?.sha256 ?? "unknown"}.`,
|
||||
),
|
||||
);
|
||||
return ok(createAnalysisViewEvidence(input, presentation, projected.value));
|
||||
};
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ import {
|
||||
inspectAnalysisView,
|
||||
projectRetainedAnalysis,
|
||||
} from "./AnalysisViewService.js";
|
||||
import { analysisViewRequestSchema } from "../../domain/analysisView/analysisViewRequest.js";
|
||||
import { analysisViewRequestSchema } from "../../domain/analysisView/analysisView.js";
|
||||
import type { Evidence } from "../../domain/evidence.js";
|
||||
|
||||
const trace = async (
|
||||
|
||||
@@ -31,6 +31,7 @@ import type {
|
||||
} from "../AnalysisProvider.js";
|
||||
import {
|
||||
AnalysisSnapshotCache,
|
||||
SNAPSHOT_CACHE_ENTRY_CEILING,
|
||||
isSnapshotCacheable,
|
||||
isSourceEvidenceRetainable,
|
||||
} from "./AnalysisSnapshotCache.js";
|
||||
@@ -594,7 +595,7 @@ describe("analysis snapshot cache capacity", () => {
|
||||
parameters: { query: "existing" },
|
||||
execution,
|
||||
};
|
||||
for (let index = 0; index < 9_999; index += 1)
|
||||
for (let index = 0; index < SNAPSHOT_CACHE_ENTRY_CEILING - 1; index += 1)
|
||||
cache.recordWorkflow({
|
||||
...workflowInput,
|
||||
parameters: { query: String(index) },
|
||||
@@ -619,7 +620,9 @@ describe("analysis snapshot cache capacity", () => {
|
||||
});
|
||||
cache.recordWorkflow(workflowInput);
|
||||
expect(cache.entries()).toHaveLength(1);
|
||||
expect(cache.workflowEntries()).toHaveLength(9_999);
|
||||
expect(cache.workflowEntries()).toHaveLength(
|
||||
SNAPSHOT_CACHE_ENTRY_CEILING - 1,
|
||||
);
|
||||
|
||||
cache.record({
|
||||
...directInput,
|
||||
@@ -666,7 +669,9 @@ describe("analysis snapshot cache capacity", () => {
|
||||
),
|
||||
"a capacity-refused workflow binding is not counted",
|
||||
).toBe(0);
|
||||
expect(cache.workflowEntries()).toHaveLength(9_999);
|
||||
expect(cache.workflowEntries()).toHaveLength(
|
||||
SNAPSHOT_CACHE_ENTRY_CEILING - 1,
|
||||
);
|
||||
|
||||
const otherTarget = { ...target, sha256: "b".repeat(64) };
|
||||
cache.recordWorkflow({
|
||||
|
||||
Loaded 100 of 1027 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user