mirror of
https://github.com/morluto/rea.git
synced 2026-11-09 03:39:49 -10:00
Compare commits
4
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4ca8ff52ab | ||
|
|
65911d3f6d | ||
|
|
fe93175a72 | ||
|
|
0a723689fa |
No files matched your search
@@ -2,7 +2,7 @@
|
||||
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: "61"
|
||||
version: "62"
|
||||
---
|
||||
|
||||
# REA
|
||||
@@ -110,7 +110,7 @@ explicit path or endpoint and do not need it.
|
||||
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`.
|
||||
without a provider; read [ESP images](references/firmware-and-raw-images.md#esp-images).
|
||||
- .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.
|
||||
@@ -276,14 +276,6 @@ explicit path or endpoint and do not need it.
|
||||
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
|
||||
@@ -539,8 +531,14 @@ as complete while required questions remain open.
|
||||
|
||||
## Read only the relevant guide
|
||||
|
||||
- Native binaries, managed assemblies, archives, and extraction:
|
||||
- Native binaries and managed assemblies:
|
||||
[references/native-and-artifacts.md](references/native-and-artifacts.md)
|
||||
- Firmware, headerless images, ESP images, and address-bearing containers:
|
||||
[references/firmware-and-raw-images.md](references/firmware-and-raw-images.md)
|
||||
- Archive inventory, extraction, Godot PCK, UnityFS, wxapkg, and Bun:
|
||||
[references/packages-and-archives.md](references/packages-and-archives.md)
|
||||
- Offline format headers, metadata, signatures, and database snapshots:
|
||||
[references/format-inspectors.md](references/format-inspectors.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:
|
||||
|
||||
@@ -72,13 +72,6 @@ the first source that has the app:
|
||||
`/usr/share/applications` without `.desktop`, such as
|
||||
`org.inkscape.Inkscape`. Add `window_class` when you know it; Inkscape's
|
||||
is `Inkscape`. AbiWord's entry is `abiword` and its class `Abiword`.
|
||||
- To find the entry, read the package's file list: its page on
|
||||
packages.ubuntu.com, or `apt-get download PKG && dpkg -c PKG_*.deb` where
|
||||
apt runs. The entry may ship in a companion `-data` or `-common` package,
|
||||
as Planner's in `planner-data`: read that package's list too. The entry's `StartupWMClass` may not be the window's real
|
||||
class, so do not take `window_class` from it: MuseScore 3's says
|
||||
`mscore3`, its window's is `MuseScore3`. The export uses the class the
|
||||
capture saw.
|
||||
|
||||
## Drive the app
|
||||
|
||||
@@ -104,25 +97,16 @@ the first source that has the app:
|
||||
environment's name.
|
||||
- Prefer shortcuts and typing to long pointer paths: `key` takes `keys`, an
|
||||
array holding one chord's keys, such as
|
||||
`{"action": "key", "keys": ["Control", "s"]}`, and `type` turns `\n` into
|
||||
`{"action": "key", "keys": ["ctrl", "s"]}`, and `type` turns `\n` into
|
||||
Enter.
|
||||
- Before `type`, check in a screenshot that a text cursor or a focused
|
||||
field is there. In apps with single-key shortcuts, such as Inkscape, text
|
||||
typed without one runs as commands.
|
||||
- Save As differs by app. Check the dialog's current folder first: most
|
||||
open in the home, so click Documents in the sidebar, but Scribus opens in
|
||||
`~/Documents` and its sidebar has no Documents entry. Type only the file
|
||||
name. A dialog taller than the 1280×800 screen hides its buttons:
|
||||
maximize it from its title bar, or confirm it with `key` Return, as when
|
||||
HomeBank's Save button is off-screen.
|
||||
- Answer the app's save questions, such as keeping the format, then check
|
||||
the saved path in the title or status bar, or the dialog's folder when
|
||||
the app shows only the name, and that it shows no unsaved mark, before
|
||||
you mark a checkpoint or check. Where the title never shows one, as in
|
||||
HomeBank, a greyed Save or Revert, or the file reopened from recent
|
||||
files, confirms the save.
|
||||
- Qt spin boxes change their value on scroll: move the pointer off them
|
||||
before you scroll.
|
||||
- Save As opens in the home: click Documents in its sidebar and type only
|
||||
the file name. Answer the app's save questions, such as keeping the
|
||||
format, then check the saved path in the title or status bar, or the
|
||||
dialog's folder when the app shows only the name, and that it shows no
|
||||
unsaved mark, before you mark a checkpoint or check.
|
||||
- What the app saved under the home before `seed`, such as a document in
|
||||
`~/Documents` or its settings, is part of the seed. A file you move to the
|
||||
Trash is left out, and the export lists it in `limitations`. Trash a stray
|
||||
@@ -142,30 +126,12 @@ the first source that has the app:
|
||||
|
||||
1. `start_build_computer` with
|
||||
`{"source": {"kind": "request", "desktop_entry": ..., "install": ...}}`.
|
||||
The first start of an app builds its image, and starts at the same time
|
||||
on this host wait for each other; either can take minutes. A failed
|
||||
start returns the build's error: fix the request, or stop when the
|
||||
The first start of an app builds its image and can take minutes. A
|
||||
failed start returns the build's error: fix the request, or stop when the
|
||||
install cannot work, and close any `computer_id` the error names.
|
||||
2. `start_build_capture`. It returns once the app's window is open. A
|
||||
`package_lists_error` may stop the capture finding the package's
|
||||
sources; the export says when that matters. When the app exits before
|
||||
its window opens, the error gives its exit code and the end of its
|
||||
stderr, which may name what it lacks, such as a Java runtime: try
|
||||
another install source, or stop as for an install this flow cannot do.
|
||||
- REA counts a file as the app's document only when the app's window
|
||||
title shows its file name or `~/` path. When the title shows something
|
||||
else, such as MuseScore's score title, pass the path you will save the
|
||||
document at in `state_paths`, relative to the home:
|
||||
`{"computer_id": ..., "state_paths": ["Documents/MuseScore3/Scores/Morning_Song.mscz"]}`.
|
||||
It need not exist yet. Add the app's settings folder when its name
|
||||
differs from the app's, such as `.config/MuseScore`, so the seed keeps
|
||||
the dismissed first-run dialogs. Do not pass the document as a launch
|
||||
argument to make REA see it: `state_paths` is the way.
|
||||
- An app whose document is a folder of pages, such as a Zim notebook
|
||||
(`Notebooks/Notes`, a `.txt` file per page), never shows a file in its
|
||||
title: pass the folder in `state_paths`. Every page in it is then a
|
||||
document, so the bundle opens none at launch and the app starts where
|
||||
it keeps its place; check the page the task changes.
|
||||
sources; the export says when that matters.
|
||||
3. Make the seed through the app and save it from the app under
|
||||
`~/Documents`: build the document in the app, or write its source where
|
||||
the app edits its format as text, then save it again from the app. Make
|
||||
@@ -175,57 +141,14 @@ the first source that has the app:
|
||||
otherwise starts on its own screen. For a starting file of the requester's,
|
||||
read it here and rebuild it in the app with synthetic data in place of
|
||||
personal data; REA cannot copy a file into the computer.
|
||||
- An app that keeps its own data and saves after every change, such as
|
||||
Osmo's contacts in `~/.local/share/osmo/contacts_records.xml`, has no
|
||||
document: that state is the seed. Build it in the app and mark `seed`
|
||||
once the app has written. To see whether it has, mark a throwaway
|
||||
checkpoint, such as `probe-1`, and read its `changed_files`: up to ten
|
||||
files that changed since the checkpoint before, those under
|
||||
`state_paths` first, then those the app held open, caches last, with
|
||||
`more_changed_files` counting the rest.
|
||||
- The app's own compressed format works when it is gzip, such as
|
||||
Gnumeric's `.gnumeric`, Dia's `.dia` or Inkscape's `.svgz`: REA reads
|
||||
the document inside, and checks point into it as into the same
|
||||
document uncompressed. A format REA reads as binary, such as one
|
||||
compressed with xz, has no view: save in a format the app offers that
|
||||
REA reads, then reopen the file once and check that a plain Ctrl+S
|
||||
keeps that format.
|
||||
4. Only once the seed is saved, `mark_build_checkpoint` with name `seed`.
|
||||
5. Make the change the task asks for, as a user would, and save it.
|
||||
6. Only once the change is saved, `mark_build_checkpoint` with name `end`.
|
||||
7. `stop_build_capture`. Read `draft.files` (each file that changed, with
|
||||
its net change and its `values`), `draft.task.checks` (suggested
|
||||
checks), `draft.guards`, `draft.notes` and `limitations`. When `draft`
|
||||
is null, read `draft_refusal` first: a missing `seed` or `end`
|
||||
checkpoint means capturing again on a new build computer, while a failed
|
||||
draft command names its own cause to fix. When `draft.files` is empty,
|
||||
`draft.notes` says why:
|
||||
- `no_change`: nothing was saved between `seed` and `end`. Capture again
|
||||
on a new build computer, and save before marking `end`.
|
||||
- `unowned_changes` with `no_document`: the app saved your document
|
||||
where REA did not count it as the app's. Its `files` list what changed,
|
||||
with their roles; the document is among them. Close the computer and
|
||||
capture again on a new one with that path in `state_paths`; the export
|
||||
refuses a check on a file outside the owned paths.
|
||||
- `uncheckable_changes`: the app saved the change in dconf, as gedit does
|
||||
its preferences, and no check reads dconf. Saving again does not help:
|
||||
choose a change the app saves in a file, and capture again on a new
|
||||
build computer.
|
||||
- `unreadable_changes`: a dconf database changed but REA could not read
|
||||
it; `error` says why. This is not evidence the app saved there: report
|
||||
the error rather than changing the task.
|
||||
|
||||
A note with a `file` says why that file's suggestions are thin:
|
||||
- `by_position`: only position names what changed; its `elements` lack
|
||||
a naming attribute. Check an ancestor's text, or give the element a
|
||||
name in the app, such as an id, and capture again.
|
||||
- `view_state_only`: every change is view state, a renumbered id or a
|
||||
time the app stamps, and its `pointers` are the checks kept. The edit
|
||||
was likely not saved: capture again and save it before `end`.
|
||||
- `long_text`: the element's text is too long to check whole; check a
|
||||
phrase in it with `text_contains`.
|
||||
- `cut_view` or `unreadable_view`: REA's view holds only part of the
|
||||
file, or none a check can read, such as a binary format (step 3).
|
||||
its net change), `draft.task.checks` (suggested checks) and
|
||||
`limitations`. When `draft` is null, read `draft_refusal` first: a
|
||||
missing `seed` or `end` checkpoint means capturing again on a new build
|
||||
computer, while a failed draft command names its own cause to fix.
|
||||
|
||||
## Write the task
|
||||
|
||||
@@ -235,37 +158,18 @@ Write `{"name", "prompt", "checks"}` from the draft and what you did.
|
||||
- `prompt`: what the requester wants, in their words and the app's terms,
|
||||
naming the document as a user would and ending with saving it: "Change the
|
||||
poster's headline in Documents/poster.svg to Summer Bake Sale and save
|
||||
it." Leave saving out for an app that saves on its own, after every change
|
||||
or a few seconds after the last one, such as Osmo or Gnote: grading waits
|
||||
until the app's files have held for 3 s, so the solving agent need not
|
||||
wait for the save. A save more than 3 s after the agent stops is still
|
||||
missed; name such an app in the report. Never say how the file stores it,
|
||||
and never give the checks.
|
||||
it." Never say how the file stores it, and never give the checks.
|
||||
- Checks are file-based: content checks that prove the edit, never only that
|
||||
a file exists or changed. Start from the suggestions; keep those that say
|
||||
what the user did and drop what follows from how the app saves.
|
||||
- Compare exact values, so a typo or a wrong number fails.
|
||||
- Read each file's `values` before writing checks: every value the change
|
||||
added, changed and removed, with `before` and `after` (a scalar, or an
|
||||
element as compact XML, cut at 600 characters) at the pointer a check
|
||||
names it by, so copy the pointer and the `after` value into a check.
|
||||
Only XML files, archives, JSON and key files have values: a text file's
|
||||
or SQLite database's `change` already lists its lines and rows.
|
||||
`refers_to` says what a number stands for, such as `category="44"`
|
||||
naming `<cat key="44" name="Groceries"/>`; use it for the prompt's words.
|
||||
Skip entries whose `note` is `by_position` (no check can use that
|
||||
pointer) or noise (`view_state`, `renumbered`, `volatile`,
|
||||
`timestamp`, `upkeep`). `values_cut` means a limit left some out.
|
||||
- Select elements by what they hold, never by position: SVG text by id,
|
||||
`/root/children/[name=g][@inkscape:label=Layer 1]/children/[name=text][@id=headline]/children/[name=tspan]/children/0`,
|
||||
or an ODF paragraph by style,
|
||||
`/entries/[name=content.xml]/view/root/children/[name=office:body]/children/[name=office:text]/children/[name=text:p][@text:style-name=Title]/children/0`.
|
||||
A selector must match exactly one element, so give the target a unique id
|
||||
or style in the seed. The draft's pointers already do this: a name-like
|
||||
attribute such as Scribus's `ANNAME` before a coordinate, and two
|
||||
attributes together where one is not enough, as a spreadsheet cell's
|
||||
`[@Col=3][@Row=2]`. Only an element's text is read by position, as
|
||||
`children/0`.
|
||||
or style in the seed. The draft may suggest positional pointers; rewrite
|
||||
them. Only an element's text is read by position, as `children/0`.
|
||||
- When an app may split an element's text into runs, check it whole:
|
||||
`text_equals` (or `text_contains` for a value inside a sentence) on the
|
||||
element compares all its text, however it is split. Add
|
||||
@@ -274,43 +178,15 @@ Write `{"name", "prompt", "checks"}` from the draft and what you did.
|
||||
`{"kind": "text_contains", "file": "Documents/memo.abw", "pointer": "/root/children/[name=section]/children/[name=p][@xid=6]", "value": "at 3:30 PM"}`.
|
||||
Point a text check at the paragraph or another element the edit keeps,
|
||||
never at a run such as AbiWord's `[name=c]`: a reopened document splits
|
||||
the text into several runs. The draft lists only what changed; an
|
||||
unchanged element is in `draft.guards` when it is a like sibling of a
|
||||
changed one, and otherwise use the app's usual numbering, such as another
|
||||
paragraph's `xid`, and let the export confirm it.
|
||||
- In an ODS spreadsheet no attribute names a row or a cell. Name the sheet
|
||||
in the seed, and check its whole text: `text_equals` on
|
||||
`/entries/[name=content.xml]/view/root/children/[name=office:body]/children/[name=office:spreadsheet]/children/[name=table:table][@table:name=Q1 Sales]`,
|
||||
or a stretch of it with `text_contains`. Cell texts join with nothing
|
||||
between, so a row reads `February23100`.
|
||||
- For a line added to free text, such as an item on a note's list, the
|
||||
draft compares the whole text with `text_equals`. This rejects longer or
|
||||
negated items, but can reject a correct edit with different ordering or
|
||||
spacing. Report that limitation when the task permits such variations.
|
||||
- Some apps keep text in an attribute, such as Scribus's `<ITEXT CH=...>`.
|
||||
`text_equals` cannot join it, so check the attribute with `value_equals`:
|
||||
`/root/children/[name=DOCUMENT]/children/[name=PAGEOBJECT][@ANNAME=Headline]/children/[name=StoryText]/children/[name=ITEXT]/attributes/CH`.
|
||||
A partial edit the app restyles splits the text into several runs and
|
||||
fails that check; list it in the report's limitations.
|
||||
- When the draft shows no values or no checks, a scratch export can expose
|
||||
`envs/<env>/seed/` only after the task has at least one valid check: it must
|
||||
pass on the captured end state and fail on the seed. Before the first
|
||||
successful export, use `act_on_build_computer` to open the saved file in an
|
||||
available GUI text editor or viewer and inspect its actual representation
|
||||
without changing it. Use the visible saved content and the task's edit to
|
||||
write a check; an export refusal can also name the end state's value, such
|
||||
as `is "44", not "1"`. If the file cannot be inspected or expressed by a
|
||||
supported check, report the limitation instead of guessing a check.
|
||||
the text into several runs. The draft lists only what changed; to name an
|
||||
unchanged element, such as another paragraph's `xid`, use the app's usual
|
||||
numbering and let the export confirm it, or read it in the exported
|
||||
bundle's `envs/<env>/seed/`.
|
||||
- Where easy, add one check that the rest is untouched, such as another
|
||||
text's value the edit must leave alone. `draft.guards` offers them at
|
||||
their seed values, which the end holds too: a field on the nearest like
|
||||
siblings, one the user sets, such as Planner's `work`, before a default
|
||||
they all share; the text an addition kept; a text file's lines beside its
|
||||
new one. Copy one or two into `checks`; they pass on the seed, which is
|
||||
fine, since the export needs only one check to fail there.
|
||||
- The draft suggests a decimal the app writes as text, such as `146.83`,
|
||||
as a number with `tolerance: 0.001`; keep the tolerance for any number
|
||||
you check that way.
|
||||
text's value the edit must leave alone. It is the one unchanged value
|
||||
worth checking; it passes on the seed too, which is fine, since the export
|
||||
needs only one check to fail there.
|
||||
- Give `value_equals` a `tolerance` for a number the app writes as text.
|
||||
- When the draft shows an XML document's changes as `lines`, REA read it
|
||||
as text, for example because its DOCTYPE declares entities. Selectors are
|
||||
impossible there, and `line_count` with `contains` only approximates a
|
||||
@@ -339,17 +215,6 @@ is no longer empty. Keep
|
||||
`seed_files`, `scrubbed_files`, `unscrubbed_files` and `limitations` for the
|
||||
report.
|
||||
|
||||
The limitations name the folders the app wrote that the bundle neither owns
|
||||
nor seeds, such as `~/.config/MuseScore`, so the app starts without them:
|
||||
expect its first-run wizard, a tour or a "restore session?" question at every
|
||||
boot. If the witness shows one, capture again on a new build computer with
|
||||
those folders in `state_paths`, and dismiss the dialogs before `seed`. Lock
|
||||
files the app holds while it runs, such as LibreOffice's `.lock` and
|
||||
`.~lock.<name>#`, are left out of the seed and listed after "Left out of the
|
||||
seed", so you need not close the document or delete them before `seed`. The
|
||||
limitations also name seeded WebKit or Chromium storage and caches; when the
|
||||
witness's boot is clean, list them in the report.
|
||||
|
||||
Keep the build computer open until the witness holds: a task fix exports
|
||||
again from it.
|
||||
|
||||
@@ -366,19 +231,12 @@ checks. Give every `check_build_task` the task exactly as exported.
|
||||
seed holds exactly one and the app takes a file. When the export's
|
||||
`limitations` say it opens no document, open it from the prompt's path,
|
||||
as a solving agent would. Take a `wait` screenshot first, since the
|
||||
desktop may not have drawn yet. When the start fails because the
|
||||
computer never got ready, and its error names lock files in the bundle's
|
||||
seed, delete them from the bundle and start again.
|
||||
desktop may not have drawn yet.
|
||||
2. `check_build_task` with `stage: "seed"` and `directory`, the absolute
|
||||
path of a new or empty folder for the record. A check must fail.
|
||||
Recording starts. Later stages take no `directory`.
|
||||
3. Do the task from the prompt with `act_on_build_computer` and save.
|
||||
`check_build_task` with `stage: "after_edit"`: every check must pass.
|
||||
Each check waits until the app's files have held for 3 s, as the
|
||||
bundle's verifier does, so an app that saves on its own needs no wait of
|
||||
yours. A result with `settled: false` means the files were still
|
||||
changing at the 15 s bound, and `read_cut: true` that a slow read was
|
||||
still running there.
|
||||
4. Make a near miss on top of it: a plausible wrong edit, such as a typo or
|
||||
a wrong number, and save. `check_build_task` with `stage: "near_miss"`:
|
||||
a check must fail.
|
||||
@@ -428,9 +286,7 @@ Report:
|
||||
`witness.json` and the recording;
|
||||
- the seed's contents: `seed_files` and what each holds;
|
||||
- `scrubbed_files` and `unscrubbed_files`; an unscrubbed file still names
|
||||
the host or user, so it needs review before sharing. `recompressed_files`
|
||||
are gzip seeds whose headers were cleared, their content unchanged: give
|
||||
their count;
|
||||
the host or user, so it needs review before sharing;
|
||||
- limitations: the capture's, the export's and anything you could not do;
|
||||
- solver runs, if any: the model, the runs and the passes;
|
||||
- the build time and the questions you asked.
|
||||
|
||||
@@ -308,20 +308,9 @@ Run `rea describe-desktop-application-task CAPTURE --format json`. Read:
|
||||
and last version, with its `role`, the `baseline` and `final` versions and
|
||||
the net `change`. Text changes list each added and removed line once, and
|
||||
`line_counts` gives lines found at both ends whose count changed.
|
||||
- `values` in each of those files: what the change added, changed and
|
||||
removed, `before` and `after`, at the pointer a check names it by, with
|
||||
`refers_to` naming the element a key such as `category="44"` stands for.
|
||||
Skip entries noted `by_position` or as noise. Only XML files, archives,
|
||||
JSON and key files have values: a text file's or database's change
|
||||
already lists its lines and rows.
|
||||
- `task`: a draft whose `checks` are suggestions from the net change of the
|
||||
documents the user worked on, or of the app's own state when no document
|
||||
changed.
|
||||
- `guards`: optional checks that the rest kept its seed values, such as a
|
||||
like sibling's field or a text file's neighbouring lines; add one or two
|
||||
to show the rest is untouched.
|
||||
- `notes`: why `files` is empty, or why a file's suggestions are thin, such
|
||||
as `by_position` when no attribute names the changed element.
|
||||
|
||||
### Write the prompt
|
||||
|
||||
@@ -357,9 +346,7 @@ document saved as a zip archive, such as FreeCAD's `.FCStd`, reads as its
|
||||
entries: point into an entry's view, and name array members by selector
|
||||
rather than position, as
|
||||
`/entries/[name=Document.xml]/view/root/children/[name=Object][@name=Hole]`,
|
||||
so the check survives an app version that writes them in another order. A
|
||||
gzip-compressed document, such as Gnumeric's `.gnumeric`, reads as the
|
||||
document inside: point into it as into the same document uncompressed. Give
|
||||
so the check survives an app version that writes them in another order. Give
|
||||
`value_equals` a `tolerance` to compare a number the app writes as text, such
|
||||
as `"5.0000000000000000"`, with a number. Check what the user wrote in a
|
||||
document with `text_equals` on its paragraph element, not `value_equals` on a
|
||||
|
||||
@@ -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,310 @@
|
||||
# Offline format and metadata inspection
|
||||
|
||||
Read the section matching the supplied artifact; other sections are optional.
|
||||
|
||||
- [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)
|
||||
- [PE TLS callbacks and load configuration](#pe-tls-callbacks-and-load-configuration)
|
||||
- [Binary hardening](#binary-hardening)
|
||||
- [ELF note tables](#elf-note-tables)
|
||||
- [Apple IPS crash reports](#apple-ips-crash-reports)
|
||||
- [Linux kernel modules](#linux-kernel-modules)
|
||||
- [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)
|
||||
|
||||
## 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).
|
||||
|
||||
## 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).
|
||||
|
||||
## 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. Opened Mach-O and dSYM UUID joins remain unobserved. 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).
|
||||
|
||||
## 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.
|
||||
|
||||
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.
|
||||
|
||||
## 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.
|
||||
|
||||
## 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).
|
||||
@@ -1,4 +1,21 @@
|
||||
# Native, managed, and packaged artifacts
|
||||
# Native and managed analysis
|
||||
|
||||
Read the section matching the supplied artifact; other sections are optional.
|
||||
|
||||
- [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-pecli)
|
||||
- [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,276 +79,6 @@ 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).
|
||||
|
||||
## 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).
|
||||
|
||||
## 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. Opened Mach-O and dSYM UUID joins remain unobserved. 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).
|
||||
|
||||
## 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
|
||||
|
||||
After `open_binary`, use focused search, procedure, or function tools directly.
|
||||
@@ -627,81 +374,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.
|
||||
@@ -721,139 +404,33 @@ 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).
|
||||
- <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)
|
||||
@@ -0,0 +1,117 @@
|
||||
# Packages and archives
|
||||
|
||||
Read the section matching the supplied artifact; other sections are optional.
|
||||
|
||||
- [Packages and extraction](#packages-and-extraction)
|
||||
- [Godot PCK](#godot-pck)
|
||||
- [Bun standalone executables](#bun-standalone-executables)
|
||||
|
||||
## Packages and extraction
|
||||
|
||||
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).
|
||||
@@ -41,12 +41,6 @@ behavior unknown. Record truncation, unmatched breakpoints, changed target
|
||||
identity and cleanup uncertainty as limitations, rather than treating no retained
|
||||
event as proof that the behavior never occurs.
|
||||
|
||||
For same-session MCP comparisons, pass each capture inline or reuse it as
|
||||
`{"kind":"retained-evidence","evidence_id":"ev_..."}`. Default comparison
|
||||
keeps capture-local timing as provenance without treating scheduler or observer
|
||||
latency as a behavior change; use an exact `trace_spec` event when timing is part
|
||||
of the analyst question.
|
||||
|
||||
Detailed contracts and prerequisites: [Frida](https://github.com/morluto/rea/blob/main/docs/guides/runtime/frida-instrumentation.md),
|
||||
[GDB/Rizin/Cutter](https://github.com/morluto/rea/blob/main/docs/reverse-engineering-tools.md),
|
||||
[process capture](https://github.com/morluto/rea/blob/main/docs/guides/runtime/process-capture.md),
|
||||
|
||||
@@ -924,7 +924,6 @@ jobs:
|
||||
tests/process-global/filesystemSnapshotFallbackCancellation.test.ts
|
||||
tests/boundary/filesystem/typescriptCompiler.test.ts
|
||||
tests/boundary/filesystem/releaseProposal.test.ts
|
||||
tests/acceptance/byteEntropyWindowsIdentity.test.ts
|
||||
tests/boundary/filesystem/binaryTarget.test.ts
|
||||
src/contracts/sessionPathInputs.test.ts
|
||||
tests/boundary/filesystem/directAnalysisSnapshotReplay.test.ts
|
||||
|
||||
@@ -95,31 +95,3 @@ jobs:
|
||||
decode cortex ARM:LE:32:Cortex mrs/4/msp bx/2/lr
|
||||
decode v8m ARM:LE:32:v8-m mrs/4/msplim bx/2/lr
|
||||
decode xtensa Xtensa:LE:32:default entry/3/a1 retw.n/2
|
||||
# A call through a writable slot keeps Ghidra's recorded target as an
|
||||
# observed callee while callee coverage stays partial; a direct call is
|
||||
# the complete control. The source-owned x86-64 bytes are never executed.
|
||||
- name: Keep computed-call targets non-exhaustive in callee coverage
|
||||
shell: bash
|
||||
run: |
|
||||
java_home_variable="JAVA_HOME_${GHIDRA_JAVA_MAJOR}_X64"
|
||||
export JAVA_HOME="${!java_home_variable}"
|
||||
probe_root="${RUNNER_TEMP}/rea-computed-call"
|
||||
mkdir -p "${probe_root}/project"
|
||||
{
|
||||
printf '\270\001\000\000\000\303\314\314' # 0x1000: mov eax, 1; ret
|
||||
printf '\270\002\000\000\000\303\314\314' # 0x1008: mov eax, 2; ret
|
||||
printf '\377\025\052\000\000\000\303\314' # 0x1010: call [rip + 0x2a]; ret
|
||||
printf '\377\320\303\314\314\314\314\314' # 0x1018: call rax; ret
|
||||
printf '\350\333\377\377\377\303\314\314' # 0x1020: call 0x1000; ret
|
||||
printf '\314%.0s' $(seq 24) # 0x1028: int3 padding
|
||||
printf '\000\020\000\000\000\000\000\000' # 0x1040: slot = 0x1000
|
||||
} > "${probe_root}/computed-call.bin"
|
||||
test "$(wc -c < "${probe_root}/computed-call.bin")" -eq 72
|
||||
timeout 180s "${GHIDRA_INSTALL_DIR}/support/analyzeHeadless" "${probe_root}/project" ComputedCall \
|
||||
-import "${probe_root}/computed-call.bin" -loader BinaryLoader -loader-baseAddr 0x1000 \
|
||||
-processor x86:LE:64:default -noanalysis -readOnly -deleteProject \
|
||||
-scriptPath "${GITHUB_WORKSPACE}/tests/conformance/ghidra;${GITHUB_WORKSPACE}/bridge/ghidra" \
|
||||
-postScript ReaComputedCallCoverageProbe.java "${GITHUB_WORKSPACE}/bridge/ghidra" \
|
||||
> "${probe_root}/output.log" 2>&1 || { cat "${probe_root}/output.log"; exit 1; }
|
||||
cat "${probe_root}/output.log"
|
||||
grep -F 'REA_COMPUTED_CALL_COVERAGE_OK slot=observed-complete-discovery-unknown register=partial direct=complete callers=discovery-unknown' "${probe_root}/output.log"
|
||||
@@ -204,7 +204,6 @@ Additional tools and host support depend on the target:
|
||||
| Rust binaries | Embedded cargo-auditable crate names, versions, sources and dependency edges | Built-in static ELF/PE/thin Mach-O inspection; [Rust binaries](docs/rust-binaries.md) |
|
||||
| PE certificates | Authenticode WIN_CERTIFICATE entries and PKCS#7 signer/X.509 identity fields | Built-in static PE inspection; [PE certificates](docs/pe-certificates.md) |
|
||||
| PE imports | Import and delay-load DLL names, ordinals, IAT RVAs and pefile import hash | Built-in static PE inspection; [PE imports](docs/pe-imports.md) |
|
||||
| Windows shortcuts | Shell Link target, arguments, working dir, ExtraData and Tracker droid facts | Built-in static LNK inspection; [Windows shortcuts](docs/guides/native/windows-shortcut.md) |
|
||||
| ELF notes | PT_NOTE/SHT_NOTE owners, types, GNU build-id and ABI-tag fields | Built-in static ELF inspection; [ELF notes](docs/elf-notes.md) |
|
||||
| Binary hardening | PIE, NX, RELRO, CFG and related header flags for ELF, PE and Mach-O | Built-in static header inspection; [binary hardening](docs/binary-hardening.md) |
|
||||
| Apple IPS crashes | .ips metadata, threads, images, registers and documented crash classes | Built-in static JSON inspection; [Apple IPS](docs/apple-ips.md) |
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
"""Run REA inside an agentenv build computer for REA on the host: capture the app, draft its task and export it.
|
||||
|
||||
REA sends this file's source through the computer's ``computer-exec/v1`` route as
|
||||
``python3 -I -c <source> <command> <JSON arguments>``. JSON that would exceed the bytes Linux
|
||||
passes as one string travels as several arguments, which this file joins before parsing. Each command prints
|
||||
one JSON line and exits. ``start``
|
||||
``python3 -I -c <source> <command> <JSON arguments>``; each command prints one JSON line and exits. ``start``
|
||||
leaves the capture running on its own: its stdin is a FIFO it holds open for reading and writing, so it never
|
||||
sees the end of its input, and ``mark`` and ``stop`` write their requests there and wait for the capture's own
|
||||
acknowledgement on its progress log. A small shell around the capture writes its exit status to a file, the
|
||||
@@ -93,13 +91,6 @@ def _exit_code(capture: str):
|
||||
return None
|
||||
|
||||
|
||||
def _ended(capture: str, code: int) -> dict:
|
||||
"""A capture that has exited: its status, the end of its progress log and its output's size, which REA reads
|
||||
whole for the Evidence or failure it ended with, whichever step was waiting on it."""
|
||||
return {"exited": code, "progress": _tail(os.path.join(capture, "progress.log")),
|
||||
"output_bytes": os.path.getsize(os.path.join(capture, "capture.out"))}
|
||||
|
||||
|
||||
def _event_line(path: str, offset: int, kinds: set, name):
|
||||
"""The first progress line after ``offset`` whose event is of one of ``kinds``, for ``name`` when given."""
|
||||
try:
|
||||
@@ -128,49 +119,17 @@ def _wait(capture: str, offset: int, kinds: set, name, timeout: float) -> dict:
|
||||
return {"line": line}
|
||||
code = _exit_code(capture)
|
||||
if code is not None:
|
||||
return _ended(capture, code)
|
||||
return {"exited": code, "progress": _tail(log), "output": _tail(os.path.join(capture, "capture.out"))}
|
||||
if time.monotonic() > deadline:
|
||||
return {"timed_out": True, "progress": _tail(log)}
|
||||
time.sleep(POLL_S)
|
||||
|
||||
|
||||
def _within(path: str, folder: str) -> bool:
|
||||
return path == folder or path.startswith(folder + os.sep)
|
||||
|
||||
|
||||
def _state_paths(values: list, work: str):
|
||||
"""Each state path as an absolute path strictly under the home and outside REA's work folder, both as named
|
||||
and with its links resolved, or the refusal of the first that is not. The capture resolves the links again
|
||||
and retains what they lead to, so a link out of the home is refused here. Each passes on as named, so the
|
||||
capture keeps what its spelling means, such as a hidden settings folder."""
|
||||
home = os.path.normpath(os.path.expanduser("~"))
|
||||
real_home, real_work = os.path.realpath(home), os.path.realpath(work)
|
||||
spellings = {home, real_home}
|
||||
paths = []
|
||||
for value in values:
|
||||
relative = value[2:] if value.startswith("~/") else value
|
||||
path = os.path.normpath(os.path.join(home, relative))
|
||||
if ".." in relative.split("/") or not any(path.startswith(spelling + os.sep) for spelling in spellings):
|
||||
return None, f"The state path {value} is not under the computer's home, {home}."
|
||||
# Every link on the way is followed, a dangling one too; a path that does not exist yet resolves
|
||||
# through its nearest existing folder.
|
||||
resolved = os.path.realpath(path)
|
||||
if not resolved.startswith(real_home + os.sep):
|
||||
return None, f"The state path {value} leads through a link to {resolved}, which is not under the computer's home, {home}."
|
||||
if _within(path, work) or _within(resolved, real_work):
|
||||
return None, f"The state path {value} is in REA's work folder {work}, which every capture leaves out."
|
||||
paths.append(path)
|
||||
return paths, None
|
||||
|
||||
|
||||
def start(arguments: dict) -> int:
|
||||
work, capture = os.path.abspath(arguments["work"]), os.path.abspath(arguments["capture"])
|
||||
rea = shutil.which("rea")
|
||||
if rea is None:
|
||||
return _say({"error": "REA is not installed in this computer; start the computer from a request, which installs it."})
|
||||
state_paths, refusal = _state_paths(arguments.get("state_paths", []), work)
|
||||
if refusal is not None:
|
||||
return _say({"refused": refusal})
|
||||
if os.path.exists(capture):
|
||||
return _say({"error": f"the capture folder {capture} is already used"})
|
||||
apt = _apt(work, arguments.get("apt_timeout_s", 600))
|
||||
@@ -184,8 +143,6 @@ def start(arguments: dict) -> int:
|
||||
"--output", os.path.join(capture, "capture"), "--exclude", work, "--json"]
|
||||
for value in arguments.get("arguments", []):
|
||||
argv += ["--argument", value]
|
||||
for path in state_paths:
|
||||
argv += ["--state-path", path]
|
||||
if arguments.get("package_file"):
|
||||
argv += ["--package-file", arguments["package_file"]]
|
||||
# Reading and writing, so the capture never reads the end of its input between requests.
|
||||
@@ -218,13 +175,11 @@ def _request(capture: str, line: str) -> bool:
|
||||
|
||||
|
||||
def mark(arguments: dict) -> int:
|
||||
"""Request a checkpoint and answer with the capture's acknowledgement line as it wrote it: the checkpoint's
|
||||
counts and up to ten of the files that changed, home-relative, with a count of the rest."""
|
||||
capture, name = os.path.abspath(arguments["capture"]), arguments["name"]
|
||||
code = _exit_code(capture)
|
||||
log = os.path.join(capture, "progress.log")
|
||||
if code is not None:
|
||||
return _say(_ended(capture, code))
|
||||
return _say({"exited": code, "progress": _tail(log)})
|
||||
# A checkpoint already taken, whose answer was lost, is answered from the capture's own log.
|
||||
taken = _event_line(log, 0, {"checkpoint"}, name)
|
||||
if taken is not None:
|
||||
@@ -315,4 +270,4 @@ def listing(arguments: dict) -> int:
|
||||
COMMANDS = {"start": start, "mark": mark, "stop": stop, "run": run, "list": listing}
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(COMMANDS[sys.argv[1]](json.loads("".join(sys.argv[2:]))))
|
||||
sys.exit(COMMANDS[sys.argv[1]](json.loads(sys.argv[2])))
|
||||
@@ -3753,20 +3753,6 @@ public final class ReaGhidraBridge extends HeadlessScript {
|
||||
private JsonObject callRelationshipCoverage(
|
||||
CallBoundaryObservation calls, Integer missingCallers) {
|
||||
JsonObject coverage = completeResolvedCallCoverage();
|
||||
JsonObject discovery = new JsonObject();
|
||||
if (missingCallers != null) {
|
||||
JsonObject callers = new JsonObject();
|
||||
callers.addProperty("status", "unknown");
|
||||
callers.addProperty("reason", "Recorded incoming references do not establish additional computed callers elsewhere in the program.");
|
||||
discovery.add("callers", callers);
|
||||
}
|
||||
if (calls != null && !calls.computedCallSites().isEmpty()) {
|
||||
JsonObject callees = new JsonObject();
|
||||
callees.addProperty("status", "unknown");
|
||||
callees.addProperty("reason", computedCallTargetLimitation(calls.computedCallSites()));
|
||||
discovery.add("callees", callees);
|
||||
}
|
||||
if (!discovery.isEmpty()) coverage.add("discovery", discovery);
|
||||
Integer omitted = calls == null ? null : calls.unrepresentedCalleeCalls();
|
||||
JsonArray directions = new JsonArray();
|
||||
if (missingCallers != null && missingCallers > 0) directions.add("callers");
|
||||
@@ -3785,10 +3771,10 @@ public final class ReaGhidraBridge extends HeadlessScript {
|
||||
}
|
||||
JsonArray limitations = new JsonArray();
|
||||
if (callerLimitation != null) limitations.add(callerLimitation);
|
||||
if (omitted != null && omitted > 0) directions.add("callees");
|
||||
if (omitted != null && omitted > 0) {
|
||||
limitations.add("Ghidra's callee inventory omits targets of " + omitted +
|
||||
" call reference(s) or decoded call(s) without destinations.");
|
||||
directions.add("callees");
|
||||
}
|
||||
if (!limitations.isEmpty()) {
|
||||
coverage.addProperty("status", "partial");
|
||||
@@ -3838,24 +3824,6 @@ public final class ReaGhidraBridge extends HeadlessScript {
|
||||
return coverage;
|
||||
}
|
||||
|
||||
/** Name a few sites inline; reference reads and call-target queries recover the rest. */
|
||||
private static final int NAMED_COMPUTED_CALL_SITES = 4;
|
||||
|
||||
/**
|
||||
* A computed call's ReferenceManager targets are static candidates: Ghidra
|
||||
* records no proof that other values cannot reach the call, so the callee
|
||||
* set stays incomplete while the recorded candidates remain observed.
|
||||
*/
|
||||
private static String computedCallTargetLimitation(List<String> sites) {
|
||||
if (sites.isEmpty()) return null;
|
||||
int named = Math.min(sites.size(), NAMED_COMPUTED_CALL_SITES);
|
||||
String listed = String.join(", ", sites.subList(0, named)) +
|
||||
(sites.size() > named ? " and " + (sites.size() - named) + " more" : "");
|
||||
return "Ghidra records call reference targets at " + sites.size() +
|
||||
" computed call site(s) (" + listed + "); these static references do not establish" +
|
||||
" every possible target, so additional callees remain unknown.";
|
||||
}
|
||||
|
||||
private boolean unrepresentedCaller(Reference reference, Set<Function> callers) {
|
||||
if (!reference.getReferenceType().isCall()) return false;
|
||||
Function caller = functionAtOrContaining(reference.getFromAddress());
|
||||
@@ -3890,11 +3858,9 @@ public final class ReaGhidraBridge extends HeadlessScript {
|
||||
monitor.checkCancelled();
|
||||
calls.observe(reference);
|
||||
}
|
||||
List<String> computedCallSites = new ArrayList<>();
|
||||
for (Instruction instruction : instructions) {
|
||||
boundary.observe(instruction);
|
||||
FlowType flow = instruction.getFlowType();
|
||||
if (!flow.isCall()) continue;
|
||||
if (!instruction.getFlowType().isCall()) continue;
|
||||
boolean destination = false;
|
||||
for (Reference reference : instruction.getReferencesFrom()) {
|
||||
if (!reference.getReferenceType().isCall()) continue;
|
||||
@@ -3906,13 +3872,9 @@ public final class ReaGhidraBridge extends HeadlessScript {
|
||||
calls.unresolved(instruction.getAddress(),
|
||||
"Instruction decoder identifies a call but ReferenceManager supplies no call destination");
|
||||
}
|
||||
// The same decoded flow classifies resolve_native_call_targets'
|
||||
// mechanism; its recorded targets are candidates, not a closed set.
|
||||
else if (flow.isComputed()) computedCallSites.add(canonicalAddress(instruction.getAddress()));
|
||||
}
|
||||
return new CallBoundaryObservation(boundary.values(),
|
||||
returnedCallees == null ? null : calls.unrepresented, calls.unresolvedCalls(),
|
||||
List.copyOf(computedCallSites));
|
||||
returnedCallees == null ? null : calls.unrepresented, calls.unresolvedCalls());
|
||||
}
|
||||
|
||||
private final class FunctionBoundaryLimitations {
|
||||
@@ -5358,7 +5320,7 @@ public final class ReaGhidraBridge extends HeadlessScript {
|
||||
}
|
||||
}
|
||||
private record FunctionAnalysisObservation(JsonObject dossier, List<String> limitations, JsonObject relationshipCoverage, boolean decompilerFailed) {}
|
||||
private record CallBoundaryObservation(List<String> limitations, Integer unrepresentedCalleeCalls, JsonArray unresolvedCalls, List<String> computedCallSites) {}
|
||||
private record CallBoundaryObservation(List<String> limitations, Integer unrepresentedCalleeCalls, JsonArray unresolvedCalls) {}
|
||||
private record SwiftStringLiteralDecode(JsonArray literals, JsonArray omissions) {}
|
||||
private record SwiftLiteralLayout(
|
||||
String representation,
|
||||
|
||||
@@ -1399,8 +1399,7 @@ def _serve_connection(connection):
|
||||
break
|
||||
except (ConnectionError, OSError):
|
||||
# A lost client cannot confirm document closure or revoke this run.
|
||||
# Keep the listener available for the owner to confirm cleanup.
|
||||
should_stop = False
|
||||
pass
|
||||
finally:
|
||||
try:
|
||||
file.close()
|
||||
|
||||
@@ -24,16 +24,3 @@ func captureAccessibilityValue(_ source: Any?) -> AccessibilityValue {
|
||||
}
|
||||
return AccessibilityValue(value: NSNull(), gap: "AXValue type \(type(of: source)) is not a supported JSON scalar")
|
||||
}
|
||||
|
||||
/** Keep an unavailable action list distinct from a successful empty list. */
|
||||
func captureActionNames(status: Int32, success: Int32, names: [String]?) -> (names: [String], error: Int32?) {
|
||||
guard status == success else { return ([], status) }
|
||||
return (names ?? [], nil)
|
||||
}
|
||||
|
||||
/** AX absence is distinct from a failed attribute read. */
|
||||
func captureAttributeValue<Value>(status: Int32, success: Int32, absent: [Int32], value: Value?) -> (value: Value?, error: Int32?) {
|
||||
if status == success { return (value, nil) }
|
||||
if absent.contains(status) { return (nil, nil) }
|
||||
return (nil, status)
|
||||
}
|
||||
@@ -18,10 +18,9 @@ struct Request: Decodable {
|
||||
struct Action: Decodable { var kind: String; var path: [Int]?; var direction: String?; var text: String? }
|
||||
struct BoundaryFailure: Error { var code: String; var message: String }
|
||||
func fail(_ code: String, _ message: String) throws -> Never { throw BoundaryFailure(code: code, message: message) }
|
||||
func attribute(_ element: AXUIElement, _ key: String) -> (value: CFTypeRef?, error: Int32?) {
|
||||
func attribute(_ element: AXUIElement, _ key: String) -> CFTypeRef? {
|
||||
var value: CFTypeRef?
|
||||
let status = AXUIElementCopyAttributeValue(element, key as CFString, &value)
|
||||
return captureAttributeValue(status: status.rawValue, success: AXError.success.rawValue, absent: [AXError.noValue.rawValue, AXError.attributeUnsupported.rawValue], value: value)
|
||||
return AXUIElementCopyAttributeValue(element, key as CFString, &value) == .success ? value : nil
|
||||
}
|
||||
func childCount(_ element: AXUIElement) -> ChildCount {
|
||||
var count = 0
|
||||
@@ -35,15 +34,13 @@ func children(_ element: AXUIElement, count: Int) -> ChildBatch<AXUIElement> {
|
||||
return value as? [AXUIElement]
|
||||
}
|
||||
}
|
||||
func windowBounds(_ element: AXUIElement) -> (bounds: CGRect?, error: Int32?) {
|
||||
let position = attribute(element, kAXPositionAttribute)
|
||||
let size = attribute(element, kAXSizeAttribute)
|
||||
if let error = position.error ?? size.error { return (nil, error) }
|
||||
guard let p = position.value, let s = size.value,
|
||||
CFGetTypeID(p) == AXValueGetTypeID(), CFGetTypeID(s) == AXValueGetTypeID() else { return (nil, nil) }
|
||||
var point = CGPoint.zero; var dimensions = CGSize.zero
|
||||
guard AXValueGetValue(p as! AXValue, .cgPoint, &point), AXValueGetValue(s as! AXValue, .cgSize, &dimensions) else { return (nil, nil) }
|
||||
return (CGRect(origin: point, size: dimensions), nil)
|
||||
func text(_ element: AXUIElement, _ key: String) -> Any { (attribute(element, key) as? String) ?? NSNull() as Any }
|
||||
func windowBounds(_ element: AXUIElement) -> CGRect? {
|
||||
guard let p = attribute(element, kAXPositionAttribute), let s = attribute(element, kAXSizeAttribute),
|
||||
CFGetTypeID(p) == AXValueGetTypeID(), CFGetTypeID(s) == AXValueGetTypeID() else { return nil }
|
||||
var point = CGPoint.zero; var size = CGSize.zero
|
||||
guard AXValueGetValue(p as! AXValue, .cgPoint, &point), AXValueGetValue(s as! AXValue, .cgSize, &size) else { return nil }
|
||||
return CGRect(origin: point, size: size)
|
||||
}
|
||||
func observe(_ request: Request) async throws -> [String: Any] {
|
||||
guard let app = NSRunningApplication(processIdentifier: request.pid) else {
|
||||
@@ -87,22 +84,11 @@ func observe(_ request: Request) async throws -> [String: Any] {
|
||||
guard AXIsProcessTrusted() else { try fail("accessibility-denied", "Grant Accessibility to the REA host in System Settings > Privacy & Security, then retry") }
|
||||
let application = AXUIElementCreateApplication(request.pid)
|
||||
AXUIElementSetMessagingTimeout(application, 2)
|
||||
let windowsAttribute = attribute(application, kAXWindowsAttribute)
|
||||
if let error = windowsAttribute.error {
|
||||
try fail("accessibility-unavailable", "Cannot read accessibility windows: AXError \(error)")
|
||||
guard let axWindows = attribute(application, kAXWindowsAttribute) as? [AXUIElement] else {
|
||||
try fail("accessibility-unavailable", "Selected application does not expose accessibility windows")
|
||||
}
|
||||
guard let axWindows = windowsAttribute.value as? [AXUIElement] else {
|
||||
try fail("accessibility-unavailable", "Accessibility windows are unavailable for the selected application")
|
||||
}
|
||||
let candidates = axWindows.map { (element: $0, observation: windowBounds($0)) }
|
||||
if let error = candidates.compactMap({ $0.observation.error }).first {
|
||||
try fail("accessibility-unavailable", "Cannot read accessibility window geometry: AXError \(error)")
|
||||
}
|
||||
guard candidates.allSatisfy({ $0.observation.bounds != nil }) else {
|
||||
try fail("accessibility-unavailable", "Accessibility window geometry is unavailable; the selected window cannot be identified")
|
||||
}
|
||||
let matches = candidates.filter { $0.observation.bounds == bounds }.map { $0.element }
|
||||
guard matches.count == 1 else { try fail("ambiguous-window", "Accessibility window geometry does not identify exactly one selected window; selected CG bounds \(bounds), AX candidates \(candidates.map { String(describing: $0.observation.bounds) })") }
|
||||
let matches = axWindows.filter { windowBounds($0) == bounds }
|
||||
guard matches.count == 1 else { try fail("ambiguous-window", "Accessibility window geometry does not identify exactly one selected window; selected CG bounds \(bounds), AX candidates \(axWindows.map { String(describing: windowBounds($0)) })") }
|
||||
selected = matches[0]
|
||||
}
|
||||
if let action = request.action, let root = selected {
|
||||
@@ -113,16 +99,13 @@ func observe(_ request: Request) async throws -> [String: Any] {
|
||||
guard let available = count.value else {
|
||||
try fail("element-count-unavailable", "Cannot validate selected accessibility path because child count failed with AXError \(count.error ?? -1)")
|
||||
}
|
||||
guard index >= 0 && index < available else { try fail("element-missing", "Selected accessibility path no longer exists") }
|
||||
let childStatus = AXUIElementCopyAttributeValues(element, kAXChildrenAttribute as CFString, index, 1, &selectedChild)
|
||||
guard childStatus == .success else { try fail("accessibility-unavailable", "Cannot read selected accessibility child: AXError \(childStatus.rawValue)") }
|
||||
guard let item = (selectedChild as? [AXUIElement])?.first else { try fail("accessibility-unavailable", "Selected accessibility child was not returned") }
|
||||
guard index >= 0 && index < available,
|
||||
AXUIElementCopyAttributeValues(element, kAXChildrenAttribute as CFString, index, 1, &selectedChild) == .success,
|
||||
let item = (selectedChild as? [AXUIElement])?.first else { try fail("element-missing", "Selected accessibility path no longer exists") }
|
||||
element = item
|
||||
}
|
||||
var owner: pid_t = 0
|
||||
let ownerStatus = AXUIElementGetPid(element, &owner)
|
||||
guard ownerStatus == .success else { try fail("accessibility-unavailable", "Cannot identify accessibility element owner: AXError \(ownerStatus.rawValue)") }
|
||||
guard owner == request.pid else { try fail("element-owner-mismatch", "Selected element belongs to another process") }
|
||||
guard AXUIElementGetPid(element, &owner) == .success && owner == request.pid else { try fail("element-owner-mismatch", "Selected element belongs to another process") }
|
||||
let outcome: AXError
|
||||
switch action.kind {
|
||||
case "click": outcome = AXUIElementPerformAction(element, kAXPressAction as CFString)
|
||||
@@ -139,18 +122,10 @@ func observe(_ request: Request) async throws -> [String: Any] {
|
||||
if nodes.count >= request.max_nodes { truncated = true; break }
|
||||
let childCountResult = childCount(element)
|
||||
var actions: CFArray?
|
||||
let actionStatus = AXUIElementCopyActionNames(element, &actions)
|
||||
let observedActions = captureActionNames(status: actionStatus.rawValue, success: AXError.success.rawValue, names: actions as? [String])
|
||||
if let error = observedActions.error { gaps.append("AX actions unavailable at path \(path): AXError \(error)"); truncated = true }
|
||||
let role = attribute(element, kAXRoleAttribute)
|
||||
let title = attribute(element, kAXTitleAttribute)
|
||||
let value = attribute(element, kAXValueAttribute)
|
||||
for (name, error) in [("role", role.error), ("title", title.error), ("value", value.error)] {
|
||||
if let error { gaps.append("AX \(name) unavailable at path \(path): AXError \(error)"); truncated = true }
|
||||
}
|
||||
let observedValue = captureAccessibilityValue(value.value)
|
||||
AXUIElementCopyActionNames(element, &actions)
|
||||
let observedValue = captureAccessibilityValue(attribute(element, kAXValueAttribute))
|
||||
if let gap = observedValue.gap { gaps.append("\(gap) at path \(path)"); truncated = true }
|
||||
nodes.append(["path": path, "role": (role.value as? String) ?? NSNull() as Any, "title": (title.value as? String) ?? NSNull() as Any, "value": observedValue.value, "actions": observedActions.names, "children_count": childCountResult.value.map { $0 as Any } ?? NSNull()])
|
||||
nodes.append(["path": path, "role": text(element, kAXRoleAttribute), "title": text(element, kAXTitleAttribute), "value": observedValue.value, "actions": actions as? [String] ?? [], "children_count": childCountResult.value.map { $0 as Any } ?? NSNull()])
|
||||
guard let totalChildren = childCountResult.value else {
|
||||
truncated = true
|
||||
gaps.append("AX child count unavailable at path \(path): AXError \(childCountResult.error ?? -1)")
|
||||
|
||||
@@ -78,9 +78,14 @@ public final class NativeAotExtension {
|
||||
new FrozenObjectAnnotator(program, manager).analyze(located.directory(), scan.getPointerLocations(), monitor, log);
|
||||
}
|
||||
monitor.checkCancelled();
|
||||
report.addProperty("method_tables", manager.getMethodTableCount());
|
||||
JsonObject coverage = auditFrozenObjects(program, scan.getPointerLocations(), monitor);
|
||||
report.add("coverage", coverage);
|
||||
if (coverage.get("frozen_objects_annotated").getAsInt() != coverage.get("frozen_object_candidates").getAsInt())
|
||||
diagnostics.add("Some frozen-object candidates lack committed instance annotations; inspect coverage counts and Ghidra diagnostics.");
|
||||
report.addProperty("status", diagnostics.isEmpty() ? "complete" : "partial");
|
||||
report.add("reason", JsonNull.INSTANCE);
|
||||
report.add("derived_memory", derivedRange.deepCopy());
|
||||
JsonArray tables = new JsonArray();
|
||||
for (var mt : manager.getMethodTables()) {
|
||||
monitor.checkCancelled();
|
||||
@@ -89,13 +94,6 @@ public final class NativeAotExtension {
|
||||
identity.addProperty("type", mt.getMTType().getPathName());
|
||||
tables.add(identity);
|
||||
}
|
||||
// Publish recovery facts only after every fallible recovery and audit step.
|
||||
// A failed transaction is rolled back, so it cannot report committed metadata.
|
||||
report.addProperty("method_tables", manager.getMethodTableCount());
|
||||
report.add("coverage", coverage);
|
||||
report.addProperty("status", diagnostics.isEmpty() ? "complete" : "partial");
|
||||
report.add("reason", JsonNull.INSTANCE);
|
||||
report.add("derived_memory", derivedRange.deepCopy());
|
||||
report.add("types", tables);
|
||||
commit = true;
|
||||
return finish(log);
|
||||
|
||||
@@ -48,11 +48,6 @@ export const documentationSections = [
|
||||
source: "guides/native/recorded-crashes.md",
|
||||
route: "/recorded-crashes",
|
||||
},
|
||||
{
|
||||
text: "Windows Shell Link shortcuts",
|
||||
source: "guides/native/windows-shortcut.md",
|
||||
route: "/windows-shortcut",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
@@ -93,11 +88,6 @@ export const documentationSections = [
|
||||
source: "guides/javascript/electron-observation.md",
|
||||
route: "/electron-observation",
|
||||
},
|
||||
{
|
||||
text: "V8 code cache inspection",
|
||||
source: "guides/javascript/v8-code-cache.md",
|
||||
route: "/v8-code-cache",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
|
||||
@@ -17,7 +17,6 @@ product pages. The VitePress documentation source is this `docs/` tree.
|
||||
- [Go binary build metadata](guides/native/go-binaries.md)
|
||||
- [Offline binary diagnostics](guides/native/binary-diagnostics.md)
|
||||
- [Recorded crash evidence](guides/native/recorded-crashes.md)
|
||||
- [Windows Shell Link shortcuts](guides/native/windows-shortcut.md)
|
||||
|
||||
## JavaScript and Electron
|
||||
|
||||
@@ -28,7 +27,6 @@ product pages. The VitePress documentation source is this `docs/` tree.
|
||||
- [Passive Node and Electron runtime observation](guides/javascript/javascript-runtime-observation.md)
|
||||
- [JavaScript static/runtime reconciliation](guides/javascript/javascript-runtime-reconciliation.md)
|
||||
- [Electron file-page observation](guides/javascript/electron-observation.md)
|
||||
- [V8 code cache inspection](guides/javascript/v8-code-cache.md)
|
||||
|
||||
## Browser and captured websites
|
||||
|
||||
|
||||
+4
-67
@@ -85,49 +85,9 @@ canonical hexadecimal form), `EXC_GUARD` subtypes,
|
||||
pointer-authentication suffixes, and dyld missing-library strings. A report
|
||||
that matches none of those rules is `unclassified`.
|
||||
|
||||
## Joining frames to the crashed Mach-O or dSYM
|
||||
|
||||
Pass `join_path` (`--join-path` in the CLI) to select one local Mach-O
|
||||
executable or dSYM. UUID bytes in the report and the artifact's `LC_UUID` load
|
||||
commands are compared in hexadecimal, so an uppercase `dwarfdump --uuid` value
|
||||
and a lowercase report `uuid` match.
|
||||
|
||||
```bash
|
||||
rea inspect-apple-ips /absolute/path/to/report.ips \
|
||||
--join-path /absolute/path/to/App.app/Contents/MacOS/App --json
|
||||
```
|
||||
|
||||
Shared-cache image sources `S` and `C` remain unjoined: UUID agreement does not
|
||||
establish that a standalone image has the cached layout.
|
||||
|
||||
For a FAT container every slice is examined. An image joins only when exactly
|
||||
one slice has that UUID **and** an architecture that agrees with the report's
|
||||
`arch`; `arm64` and `arm64e` stay distinct, and an all-zero UUID never joins. A
|
||||
UUID match with a different architecture, more than one compatible slice, or a
|
||||
slice without a readable `__TEXT` segment is reported as a rejected image with
|
||||
its reason and stays unjoined rather than being guessed.
|
||||
An unknown UUID in another slice prevents a unique join unless its architecture
|
||||
rules out a match. Missing or unrecognized architecture and unsupported CPU
|
||||
subtypes remain unknown; display-name fallbacks do not establish agreement.
|
||||
The parsed slice facts remain available even when no match can be derived.
|
||||
|
||||
`join.status` is `selected` with the artifact path, SHA-256, byte length, every
|
||||
slice's offset, arch, CPU type and subtype, UUID, and `__TEXT` vmaddr, plus
|
||||
`image_matches`, per-frame results, and join-specific limitations. A joined
|
||||
frame reports `static_address`, the slice `__TEXT` vmaddr plus the frame's
|
||||
recorded `imageOffset`, in decimal and hexadecimal. An unjoined frame reports
|
||||
a reason instead; an unknown image UUID, an absent `imageIndex` row, and a
|
||||
frame without `imageOffset` all stay unjoined rather than treated as aligned.
|
||||
|
||||
An artifact that is not a Mach-O image or FAT container reports
|
||||
`join.status: "unreadable"` with a typed reason and leaves every report fact
|
||||
intact. Symbol names printed inside the report stay recorded claims. Function
|
||||
or symbol lookup at a joined static address, and matching dSYM symbol tables,
|
||||
are not performed by this step.
|
||||
|
||||
Symbol names printed inside the report are recorded claims and are not
|
||||
verified. Linux ELF cores use the separate
|
||||
[recorded crash](guides/native/recorded-crashes.md) workflow.
|
||||
Opened Mach-O and dSYM UUID joins remain unobserved. Symbol names printed
|
||||
inside the report are recorded claims and are not verified. Linux ELF cores
|
||||
use the separate [recorded crash](guides/native/recorded-crashes.md) workflow.
|
||||
|
||||
## Limits and failures
|
||||
|
||||
@@ -160,27 +120,4 @@ success or truncated integer facts.
|
||||
rea inspect-apple-ips /absolute/path/to/report.ips --max-integer-text-bytes 16777216 --json
|
||||
```
|
||||
|
||||
`max_join_bytes` (`--max-join-bytes`) independently bounds the join artifact
|
||||
read, defaulting to 64 MiB. This workflow does not execute a target, launch
|
||||
atos, or search for dSYMs.
|
||||
|
||||
## Join admission and failures
|
||||
|
||||
The join uses the shared Mach-O container, slice, command-table and segment
|
||||
readers. Slice extents and `sizeofcmds` bound every identity observation; duplicate
|
||||
UUIDs or malformed commands cannot select the first plausible value. Unreadable
|
||||
join results retain the successfully read artifact's path, SHA-256 and byte count.
|
||||
|
||||
The integer-text allowance spans the report and join, including repeated integer
|
||||
facts and derived static addresses. Reservation precedes derived address
|
||||
expansion. If a selected join read, interpretation or allowance fails, the error
|
||||
retains the completed IPS report. Join read limits and recovery use
|
||||
`max_join_bytes`, even when the report and join paths are identical. Cancellation
|
||||
retains the caller's reason independently of those completed facts.
|
||||
|
||||
When a failure follows a completed join-file read, `partial_observation` retains
|
||||
both the decoded report and a `join_artifact` receipt with the independently
|
||||
observed path, SHA-256 and byte count. Frame rejection reasons reference
|
||||
`join.limitations`; source-sized architecture diagnostics are retained once per
|
||||
image rather than copied into every frame. Universal-image admission includes
|
||||
the shared reader's supported hidden ARM64 row and rejects overlapping slices.
|
||||
This workflow does not execute a target, launch atos, or search for dSYMs.
|
||||
@@ -47,10 +47,6 @@ computer would not have that entry. An `--executable` runs from
|
||||
the current directory, as it would from a shell, and a relative path to it is
|
||||
resolved there.
|
||||
|
||||
Desktop-entry string values retain literal trailing spaces. For example,
|
||||
`Path=/tmp/workspace ` and `Path=/tmp/workspace\s` name the same directory
|
||||
ending in a space. Use the escaped spelling to make such a suffix visible.
|
||||
|
||||
Before writing anything the command refuses to start if a window of the
|
||||
application is already open, or if the window list cannot be read. A launch
|
||||
beside a running instance can hand off to it, and that instance's unsaved
|
||||
@@ -94,20 +90,12 @@ Progress lines on stderr are JSON, `{"rea_progress": {"phase":
|
||||
"desktop_capture", "message": ...}}`. Those a driver waits on also carry an
|
||||
`event`: `{"kind": "window_open"}` once the window opens; `{"kind":
|
||||
"checkpoint", "name", "trigger", "at_ms", "entries", "changes",
|
||||
"retained_files", "retained_bytes", "changed_files", "more_changed_files"}`
|
||||
once a checkpoint has been taken, the baseline, `stop` and `exit` included,
|
||||
with the paths walked, the paths changed since the checkpoint before, the
|
||||
files retained, and up to ten of the files (not folders) that changed,
|
||||
home-relative: those under a `--state-path` or absolute `--argument` first,
|
||||
then those the application held open, then those in its state directories,
|
||||
then the rest, and last caches (a folder whose name ends in `cache`, such as
|
||||
`~/.cache`) and WebKit or Chromium storage, each by path, with a count of the
|
||||
rest. An application can rewrite dozens of cache files on a save, and KDE's
|
||||
holds its service cache open, so the saved document would otherwise fall past
|
||||
the ten;
|
||||
and `{"kind": "checkpoint_refused", "name", "reason"}` for a requested name it
|
||||
refused. A driver that sends `checkpoint <name>` waits for the event naming it
|
||||
rather than for a fixed time.
|
||||
"retained_files", "retained_bytes"}` once a checkpoint has been taken, the
|
||||
baseline, `stop` and `exit` included, with the paths walked, the paths
|
||||
changed since the checkpoint before and the files retained; and `{"kind":
|
||||
"checkpoint_refused", "name", "reason"}` for a requested name it refused. A
|
||||
driver that sends `checkpoint <name>` waits for the event naming it rather
|
||||
than for a fixed time.
|
||||
|
||||
When the session ends the capture sends SIGTERM to the launched process, its
|
||||
process group and every process that carries the run token, waits up to five
|
||||
@@ -318,22 +306,16 @@ the whole name is compared, so `~/.config/GIMPshop` does not. Dotfiles in the
|
||||
home named after the application (`.<name>rc`, or
|
||||
`.<name>` followed by `-`, `.` or `_`, for a name of three or more characters)
|
||||
that exist at the start join them, since an application may only read such a
|
||||
file during the capture. So does KDE's settings file in the config folder,
|
||||
`<name>rc` such as Tellico's `~/.config/tellicorc`, for each such name of three
|
||||
or more characters, whether or not it exists yet. A `flatpak run` launch is named after its application
|
||||
file during the capture. A `flatpak run` launch is named after its application
|
||||
id rather than the `flatpak` launcher, and adds `~/.var/app/<id>`.
|
||||
|
||||
**Session.** When it started, how long it ran and why it ended; the launched
|
||||
process's exit status; every process seen in the application's tree; every
|
||||
client window with its class pair, titles, owner pid and type, marked when it
|
||||
belongs to the application. Titles and class names decode xprop's quoted
|
||||
delimiters, newline and tab escapes, and three-digit octal byte escapes;
|
||||
unsupported escape spellings leave that string unknown rather than inventing
|
||||
text. The session also records when the first application window appeared; the
|
||||
belongs to the application; when the first application window appeared; the
|
||||
most common class pair of the application's windows, for matching its window
|
||||
later; files the application's processes held open under the walked roots; the last
|
||||
8 KiB of the launched process's stderr, where a failing app's last words are,
|
||||
with `stderr_truncated` when earlier output was dropped; and whether cleanup was verified. Each
|
||||
later; files the application's processes held open under the walked roots; the first
|
||||
8 KiB of the launched process's stderr; and whether cleanup was verified. Each
|
||||
process records whether the capture started it: the launched process, a
|
||||
process carrying the capture's run token, or a descendant of one, even when
|
||||
its environment cannot be read, as for a zombie or a sandboxed renderer.
|
||||
@@ -359,9 +341,7 @@ directory, which are named in the limitations instead; a selected path that is
|
||||
not a directory brings the `-wal` and `-journal` paths beside it, so a database
|
||||
selected on its own is captured with its logs), the state directories
|
||||
as walked (their physical spelling, which differs from the inventory's when one
|
||||
is a symlink), the selected paths (each `--state-path` and content-root
|
||||
`--argument` as named, absolute, beside the physical path walked, so a
|
||||
symlinked settings folder keeps what its name means), the paths every walk left out (the output folder and
|
||||
is a symlink), the paths every walk left out (the output folder and
|
||||
`--exclude` values), and the checkpoints in order: `baseline` before
|
||||
launch, each requested checkpoint, `stop` or `time-limit`, and `exit` after the
|
||||
application has gone. Each checkpoint records how many paths its walk saw,
|
||||
@@ -390,8 +370,7 @@ unreadable SQLite sidecar from an absent one. Captures made before this field
|
||||
was added must be made again before state inspection, task drafting or export.
|
||||
Directories the application held files open in, but whose starting content was
|
||||
not retained, are listed so a second capture can pass them with
|
||||
`--state-path`, or `state_paths` on a build computer's `start_build_capture`,
|
||||
and a limitation names them, spelled from `~/` under the home.
|
||||
`--state-path`.
|
||||
|
||||
**Limitations.** What the capture could not establish, such as a truncated
|
||||
walk or a missing window.
|
||||
|
||||
@@ -33,10 +33,8 @@ The command returns Evidence with operation `export_desktop_application` and
|
||||
predicate type `rea.desktop-application-export`, listing the environment name,
|
||||
the seed and end `checkpoints`, owned paths, seed files, the seeds it
|
||||
rewrote to remove the capture host's name and user (`scrubbed_files`), the
|
||||
gzip seeds it compressed again only to clear their headers
|
||||
(`recompressed_files`), the bundle files that still hold them
|
||||
(`unscrubbed_files`), and written files, the last four by their path in the
|
||||
bundle. A failed export, cancellation
|
||||
bundle files that still hold them (`unscrubbed_files`), and written files,
|
||||
the last three by their path in the bundle. A failed export, cancellation
|
||||
included, removes the bundle it had not yet published, so no partial copy of the
|
||||
user's data remains. If the bundle was published but its output handles could
|
||||
not be closed, the command reports a cleanup error that carries the export
|
||||
@@ -156,11 +154,9 @@ The class declares:
|
||||
Files the capture recorded under a symlinked state directory's physical
|
||||
spelling are mapped back to the innermost such directory's home spelling,
|
||||
unless that spelling is outside the captured home, as when the home itself is
|
||||
a symbolic link. When a selected link names an application state directory,
|
||||
the bundle seeds the application's state path and restores the selected
|
||||
alias at boot. Selections nested under that alias are seeded under the same
|
||||
state path. An existing incompatible alias stops setup without replacing it. When two files map to one home path, the export uses the one present
|
||||
before the capture, else the first by path, and a limitation names the other.
|
||||
a symbolic link. When two files map to one home path, the export uses the one
|
||||
present before the capture, else the first by path, and a limitation names
|
||||
the other.
|
||||
- Data hooks, because declaring any hook switches off agentenv's default data
|
||||
plane: the class seeds the home once per boot and keeps it as the initial
|
||||
state with `keep_initial`, `data/add` and `data/reset` call agentenv's `add`
|
||||
@@ -173,43 +169,10 @@ retain is not seeded: one in the state view without retained content at that
|
||||
checkpoint, or one the capture omitted (for example too large or past the
|
||||
content budget). The result lists them in `unseeded_files` and the README
|
||||
names them. When the application held files open in folders whose starting
|
||||
content the capture did not retain, a limitation names those folders, spelled
|
||||
from `~/` under the home: a file there is seeded only when the capture
|
||||
retained it, as it does one written during the capture, and the limitation
|
||||
names the seed files there or says there are none. The desktop Trash,
|
||||
`~/.local/share/Trash`, is never the application's, so a file the user moved
|
||||
there is neither owned nor seeded, even when a window title names it; a
|
||||
limitation lists the files the Trash held at the seed.
|
||||
|
||||
Files that changed during the capture outside the owned paths are neither
|
||||
owned nor seeded, so the app starts without what it saved there: MuseScore
|
||||
keeps its settings in `~/.config/MuseScore`, which its name rules miss, and
|
||||
showed its first-run wizard on every boot. A limitation and the README name
|
||||
those folders, leaving out desktop services' files, each collapsed to its
|
||||
folder in `~/.config`, `~/.local/share`, `~/.local/state` or `~/.local`, the
|
||||
hidden folder of the home it lies in, or else its own folder, up to eight and
|
||||
a count of the rest. Capture again naming them with `--state-path`, or
|
||||
`state_paths` on a build computer, to own them.
|
||||
|
||||
Lock files the app holds while it runs are left out of the seed: a copied one
|
||||
makes the app find its profile or document in use, and a LibreOffice Calc
|
||||
bundle whose seed held its profile's `.lock` showed no window at boot. They
|
||||
are `lockfile`, `lock`, `.lock`, `.parentlock`, `parent.lock` and
|
||||
`SingletonLock` anywhere, LibreOffice's document lock `.~lock.<name>#`, and
|
||||
`*.lock` or `*.lck` directly in one of the application's state directories.
|
||||
Elsewhere such a file may be a project's own, such as `Cargo.lock` or
|
||||
`yarn.lock`, which pin dependencies, and is seeded, even under a folder whose
|
||||
name starts with a dot. A file the state view makes a document, or one named
|
||||
itself by `--state-path` or an absolute `--argument`, is never left out,
|
||||
whatever its name. A limitation and the README list them, up to
|
||||
eight and a count, after "Left out of the seed". They stay under the owned
|
||||
paths, so `data/get` returns the lock the running app holds, and `data/reset`
|
||||
restores the seed without them. Other seed files the app keeps for its own
|
||||
running are seeded as captured and named, collapsed to the folder that holds
|
||||
them: WebKit or Chromium storage (such as `hsts-storage.sqlite`, `storage/`,
|
||||
`mediakeys/`, `Local Storage/`, `IndexedDB/`, `Cookies`), which may hold the
|
||||
app's own data, and caches (a folder whose name ends in `cache`); a stale one
|
||||
can change how the app starts.
|
||||
content the capture did not retain, a limitation names those folders. The
|
||||
desktop Trash, `~/.local/share/Trash`, is never the application's, so a file
|
||||
the user moved there is neither owned nor seeded, even when a window title
|
||||
names it; a limitation lists the files the Trash held at the seed.
|
||||
|
||||
The application's dconf keys at the seed, if any, are written once when the
|
||||
app first starts, also for an application that owns no files, and the class adds
|
||||
@@ -219,11 +182,7 @@ existing user database through a `file-db:` profile, then runs `dconf compile`
|
||||
on that dump and the captured keys, in that name order so the captured keys
|
||||
win, and replaces `~/.config/dconf/user`. If that fails, the server prints a
|
||||
one-line warning and the app starts without the captured keys. `data/reset` does
|
||||
not restore them. No file of the bundle holds them, so `data/get` does not
|
||||
return them and no task check reads them; a draft whose only change between
|
||||
its checkpoints is to the application's dconf keys says so with
|
||||
`uncheckable_changes`, and one whose dconf database changed but could not be
|
||||
read says so with `unreadable_changes`.
|
||||
not restore them.
|
||||
|
||||
## The seed checkpoint
|
||||
|
||||
@@ -293,26 +252,6 @@ export removes them from what the bundle ships:
|
||||
boot, as it did the captured home before. The replacements read as the
|
||||
computer's own: its user is `user`, with its home in `/home/user`, and
|
||||
`localhost` is the name every host has for itself.
|
||||
- A gzip-compressed seed, such as a Gnumeric workbook, is decompressed, up to
|
||||
256 MiB, scrubbed as the format the state view read its document as, and
|
||||
compressed again whether or not its document changed, so no file name,
|
||||
comment or time its header held ships: with no file name, comment or extra
|
||||
field, modification time 0 and the operating system unknown, so the same
|
||||
document gives the same bytes on every host. It is deflated at the fastest
|
||||
level, or stored when deflating would make it expand more than the 100 times
|
||||
a view reads, so a seed that read still reads. It is listed in
|
||||
`scrubbed_files` when its document changed, and otherwise in
|
||||
`recompressed_files`, which the README counts rather than lists, so the
|
||||
example and template files an app copies on first run do not bury the
|
||||
document scrubbed; one already in that form ships as captured. The class copies it at
|
||||
boot as it is, so the home it holds stays `/home/user`. One that does not
|
||||
decompress ships as captured, its bytes searched, and one the state view did
|
||||
not read is only searched. One whose document needs no edit but a member of
|
||||
which has an extra field, where BGZF (`.vcf.gz`, `.bam`) and dictzip
|
||||
(`.dict.dz`) files index their blocks, also ships as captured, its bytes
|
||||
searched, so its blocks stay where its index says; one whose document
|
||||
changed is still compressed again as one member, losing them, as the
|
||||
export's limitation says.
|
||||
- Binary files, SQLite databases among them, and text files over 256 MiB are
|
||||
copied as captured. Then every file the bundle ships, the class module with
|
||||
its dconf keys and the README included, is searched by a looser rule than
|
||||
@@ -379,39 +318,6 @@ declared vendor repository installs the package already; when the URL is not
|
||||
written as `http://` or `https://` or holds a user name or password; and when
|
||||
the file is built for an architecture other than `amd64`, `arm64` or `all`.
|
||||
|
||||
## Grading once the app has saved
|
||||
|
||||
A task's verifier, `artifacts/<task>-check/verify.py`, grades the app's files
|
||||
only once they have settled, because an app can save on its own timer after the
|
||||
last change. Gnote saves a note 4 s after the last key, so a read taken as
|
||||
soon as the agent stops finds the text on screen but not yet in the file. The
|
||||
verifier reads the app's `data/get` every 0.5 s. It compares each file's bytes
|
||||
between reads by their SHA-256, as `data/get` returns them, and grades once
|
||||
every file has held for 3 s. The 3 s count from when a read returned the
|
||||
current bytes, not when it began, so a slow read that brings a change late
|
||||
does not count its own run as quiet. 15 s after the first read began, the
|
||||
bound, the verifier grades the last completed read: no read starts at or
|
||||
after the bound, and a read still running then is cut. Each result records
|
||||
whether the files settled in `settled`, and whether the bound cut a read in
|
||||
`read_cut`.
|
||||
|
||||
The window has a cost and a limit:
|
||||
|
||||
- An app whose files do not change during the check, such as one that saved
|
||||
at once, is graded 3 s after the first read returns.
|
||||
- A save that lands more than 3 s after the first read returns is still
|
||||
missed. An app that saves 4 s after the last key is caught only when the
|
||||
agent stops at least a second after that key.
|
||||
- Files the app rewrites more often than every 3 s, such as a log, never
|
||||
settle, so every check waits until the bound.
|
||||
- The bound counts the reads too, so a slow `data/get` ends the check at
|
||||
15 s. Only the first read, which every grade needs, runs to its own
|
||||
timeout.
|
||||
|
||||
The bound and window are `SETTLE_BOUND_S` and `SETTLE_WINDOW_S` in the
|
||||
verifier. `check_build_task` waits the same way before it grades each
|
||||
witness stage; see [witnessing](desktop-build-witness.md#witness).
|
||||
|
||||
## Typed views
|
||||
|
||||
The views follow the [state view](desktop-application-state.md)'s formats and
|
||||
@@ -426,10 +332,7 @@ as their entries, read with Python's `zipfile` from the file in place, with
|
||||
REA's entry, size, compression ratio and archive limits and its wording for an
|
||||
entry it does not read. The module reads the central directory itself, as REA
|
||||
does, and shows `zipfile` only the records it lists, reading each entry in
|
||||
bounded chunks no further than a byte past its declared size. A gzip file is
|
||||
the view of the document inside it, with `"compression": "gzip"` beside its
|
||||
format, decompressed with Python's `zlib` within the same entry size and ratio
|
||||
limits, its members joined as REA joins them. A JSON file
|
||||
bounded chunks no further than a byte past its declared size. A JSON file
|
||||
holding a number JavaScript cannot read exactly, such as an integer above 2^53,
|
||||
or whose retained value nests more than 500 levels deep, gets an `error` instead of a view, as in
|
||||
REA. Duplicate keys keep their last value before the depth check. Text that is not one JSON
|
||||
|
||||
@@ -40,16 +40,7 @@ The role follows from the reasons, in this order: `shared_desktop` for a file
|
||||
in the desktop Trash, which the user deleted, whatever else names it;
|
||||
`application_state` for application keys in dconf, or a state directory outside shared desktop
|
||||
locations; `document` for a file named in a window title or selected by the
|
||||
caller, even if the application holds it open, except that a selected file
|
||||
under a hidden folder of the home, such as `~/.config/MuseScore`, a dotfile
|
||||
there, or a lock an application holds, such as LibreOffice's `.~lock.<name>#`
|
||||
beside a document, is `application_state`, judged by the path as the caller
|
||||
named it, so a file reached through `~/.config/MuseScore` stays the application's
|
||||
when that folder is a link to `~/settings/MuseScore`; the innermost selected
|
||||
path holding a file decides, so a score selected itself inside the link's
|
||||
target keeps its own name and is a document (a capture written before it
|
||||
recorded selected paths is judged by their physical spelling);
|
||||
`application_state` for another
|
||||
caller, even if the application holds it open; `application_state` for another
|
||||
open file outside shared locations; `shared_desktop` for other files in shared
|
||||
locations; `unrelated` otherwise. A window title names a file only when no
|
||||
other file name character adjoins the name, so `day.txt` does not match
|
||||
@@ -84,9 +75,6 @@ whether the file was present, the SHA-256 of its retained bytes, and a view:
|
||||
| `text` | Other UTF-8 text | Lines, up to 5,000 |
|
||||
| `binary` | NUL bytes or invalid UTF-8 | None |
|
||||
|
||||
A gzip file is read as the document inside it; see
|
||||
[compressed documents](#compressed-documents).
|
||||
|
||||
A JSON value holding a number JavaScript would round, such as an integer above
|
||||
2^53, is not read rather than shown rounded.
|
||||
|
||||
@@ -205,37 +193,6 @@ so an archive of hundreds of thousands of entries costs no more to read
|
||||
than one of a thousand. An archive whose central directory cannot be read has a
|
||||
`view_error` of its own.
|
||||
|
||||
## Compressed documents
|
||||
|
||||
Gnumeric's `.gnumeric`, Dia's `.dia`, Xournal++'s `.xopp`, GnuCash's default
|
||||
book and Inkscape's `.svgz` are XML compressed with gzip. A file that starts
|
||||
with gzip's magic bytes, `1f 8b 08`, whatever its name, is read as the
|
||||
document inside it: its members joined, then given a format and view by the
|
||||
rules above under the file's own name, so a pointer or check into it is
|
||||
written exactly as for the same document uncompressed, and the task draft is
|
||||
the same. The version records the compression beside the format:
|
||||
|
||||
```json
|
||||
{
|
||||
"format": "xml",
|
||||
"compression": "gzip",
|
||||
"view": {
|
||||
"root": { "name": "gnm:Workbook", "attributes": {}, "children": [] },
|
||||
"truncated": false
|
||||
},
|
||||
"view_error": null
|
||||
}
|
||||
```
|
||||
|
||||
The document is read only when it is at most 16 MiB and at most 100 times the
|
||||
file's size, an archive entry's limits, so decompressing stops there; past
|
||||
them, or when the stream is damaged or cut short, the version has `format`
|
||||
null and a `view_error`, and a check into it is undecided. A SQLite or dconf
|
||||
database inside keeps its format and has a `view_error`, an archive inside is
|
||||
read as an archive, and another gzip stream inside is binary. A gzip file
|
||||
inside an archive reads as binary. Other compression, such as xz, Zstandard
|
||||
or bzip2, is not read: such a file is binary.
|
||||
|
||||
## Kinds of change
|
||||
|
||||
Between consecutive versions a change is `created`, `deleted`, or a
|
||||
|
||||
@@ -42,31 +42,9 @@ operation `describe_desktop_application_task` and predicate type
|
||||
database is compared by its rows, since its hash leaves out the `-wal`
|
||||
file. Text changes list each line
|
||||
once and add `line_counts`, the lines found at both ends whose number of
|
||||
occurrences changed. An XML file's change names its members by the
|
||||
[selectors](#pointers-and-selectors) checks use, as an archive's already
|
||||
does, and by position only where nothing names a member or where only the
|
||||
members' order changed. Views appear only for the files the suggestions
|
||||
cover, with arrays past 200 items and strings past 2,000 characters cut
|
||||
occurrences changed. Views appear only for the files the suggestions cover,
|
||||
with arrays past 200 items and strings past 2,000 characters cut
|
||||
(`view_cut`).
|
||||
- `values`, in each of those files: the values its change added, changed and
|
||||
removed, each with the `pointer` a check names it by, its `kind` (`added`,
|
||||
`changed` or `removed`), and `before` and `after`: the scalar, an element as
|
||||
compact XML with the text the XML reader kept, spaces between runs included,
|
||||
or a JSON value as compact JSON, cut at 600 characters, and null at the end
|
||||
that lacks it. A file created or deleted lists what its one end holds,
|
||||
`added` or `removed`: an archive's entries, an XML file's root element, a
|
||||
JSON file's members or a key file's keys, each whole once. A value only
|
||||
position reaches has `note: "by_position"`, and its pointer cannot go into a
|
||||
check; noise an app writes as it saves has `view_state`, `renumbered`,
|
||||
`volatile`, `timestamp` or `upkeep` (see `task`). `refers_to` names up to
|
||||
three other elements a value equals the `key` or `id` of, with the
|
||||
`attribute` holding it, as HomeBank's `category="44"` names
|
||||
`<cat key="44" name="Groceries"/>`; where several elements share that key,
|
||||
the one whose tag shares the attribute's stem, as `payee` and `<pay>`. What a check can
|
||||
name comes first, then what only position reaches, then noise. A file lists
|
||||
at most 20 values and 8 KB, the draft 24 KB, and `values_cut` says when a
|
||||
limit left some out. Values cover XML, archives, JSON and key files; a text
|
||||
or SQLite file's change and suggestions already carry its lines and rows.
|
||||
- `task`: a draft with the name `change`, a placeholder prompt the export
|
||||
refuses, and suggested checks derived from the net change of the files with
|
||||
role `document`, or of the app's own state files when no document changed.
|
||||
@@ -78,151 +56,21 @@ operation `describe_desktop_application_task` and predicate type
|
||||
and the JSON, key file and XML views of a zip archive's entries, gain checks
|
||||
by [selectors](#pointers-and-selectors) and never through an element by
|
||||
position: in XML, first [`text_equals`](#whole-text) for each element whose
|
||||
text changed, then elements added or removed whole, then values changed,
|
||||
added and removed, an entry or a JSON value added whole through its
|
||||
members, and an empty array or object as it is.
|
||||
- A selector names a member by its tag, then by its identifiers (`name`,
|
||||
`id`, `xid`, `xml:id`), then by one other attribute, a name-like key such
|
||||
as Scribus's `ANNAME` or `inkscape:label`, a worded value or an integer of
|
||||
up to five digits first, then by two such attributes together, as
|
||||
Gnumeric's cells by `[@Col=3][@Row=2]`, and last by a coordinate, a long
|
||||
number or a token, such as `XPOS` or `ItemID`, or an attribute naming
|
||||
view state, such as which layer is `selected`. A pair counts every
|
||||
member holding both its values, whichever attributes that member ranks
|
||||
first. An element with identifiers is named by those alone. The selector
|
||||
must name the member alone at both ends, with the same values. An
|
||||
element whose one identifier changed, at its place among its tag's
|
||||
members, with every other attribute and its children alike, is that
|
||||
element renamed, as a MyPaint layer renamed from `Untitled` to `Sun`: it
|
||||
is named by its first other attribute naming it alone at both ends, as
|
||||
`[@src=data/layer-00.png]`, so the rename reads as its `name` changed,
|
||||
and the old name gets a check that it names nothing, unless its change
|
||||
is noise, as an id the app renumbered.
|
||||
An identifier the app numbers by position names nothing: where the
|
||||
members of a tag hold it as 1..N (or 0..N-1) in document order at both
|
||||
ends, members were inserted or removed, and every member another
|
||||
attribute names alone at both ends kept its number or moved it the way
|
||||
the count did, one at least, as Planner's task `id` after a task is
|
||||
inserted, members are paired by their other attributes, so an insertion
|
||||
reads as one task added. A value two members swap, or an id appended at
|
||||
the end, as Tellico's next `<entry id="4">`, leaves the ids identity.
|
||||
- The text check names the paragraph rather than a run inside it: it goes up
|
||||
from an element sitting in its parent's text, and from one named by its
|
||||
tag or position alone to the nearest ancestor named by an attribute, as
|
||||
AbiWord's `p` by its `xid`; where no attribute names one, to the nearest
|
||||
ancestor within three levels its tag names with no step by position, as
|
||||
MuseScore's `VBox` around untitled `<Text>` elements; and where only
|
||||
position reaches the element, to the ancestor above the outermost step by
|
||||
position, by an attribute of its own that names it alone where one does,
|
||||
as an ODS sheet's `table:table[@table:name=Q1 Sales]` above its rows. The
|
||||
text nodes and runs inside it get no other check, but an element holding
|
||||
no text that is added or removed there, such as an image or a line break,
|
||||
keeps its own, since the text check never reads it. A decimal that is an
|
||||
element's only text, such as a spreadsheet cell's, is checked by its
|
||||
number instead. Free text that gains a line, such as a shopping list,
|
||||
uses `text_equals` on the whole text: the current XML checks cannot
|
||||
compare an unstructured line as a whole item. This can reject a correct
|
||||
edit that puts the item elsewhere or changes spacing. A record added
|
||||
or removed whole, an element holding only elements, its fields, such as
|
||||
Tellico's `<entry>` or a record of repeated `<field>` elements, never
|
||||
makes the list holding records of its kind a check, whose text would hold
|
||||
the records the edit left alone, except a record removed whole that only
|
||||
position names, whose absence only the list's text shows. Text made of
|
||||
runs is no record: an element whose tag names a paragraph or a piece of
|
||||
text (`p`, Writer's `text:p` and `text:h`, `h1` to `h6`, `li`, `para`,
|
||||
SVG's `text` and `tspan`, a `span` or an `a`), or whose runs split a
|
||||
sentence at a space, as `Meet ` and a linked `Monday`. Nor does an
|
||||
element holding a date the app stamps in parts take a text check.
|
||||
- An element added to a list, where another element of its tag is at either
|
||||
end, gets a `value_equals` for each of its attributes, best ranked first,
|
||||
at most six, leaving out its selector's attributes, identifiers, times,
|
||||
volatile values and view state, as HomeBank's new `<ope>` gets its
|
||||
`amount`, `category` and `payee`. An element whose other attributes, two
|
||||
or more, a like sibling holds every one of, as a new Planner task copies
|
||||
its neighbour's defaults, and any other element added whole, get a check
|
||||
that it exists. A record added to a list that a selector names, as
|
||||
Tellico's `<entry id="4">`, gets a `text_equals` for each field, at most
|
||||
five, each by its selector among the record's fields, as `[name=title]`,
|
||||
leaving out a field repeating the record's identifier, a date the app
|
||||
stamps in parts, and blank text or times. A record only position names,
|
||||
such as Osmo's `<record>` of fields, also gets a `text_contains` for each
|
||||
new field of three or more characters, at most five, at the nearest
|
||||
ancestor a check can name, each absent from that ancestor's text at the
|
||||
seed.
|
||||
- A decimal written as text, such as `146.83`, is suggested as a number
|
||||
with `tolerance: 0.001`, unless the seed's value is that close too.
|
||||
- Noise leaves the suggestions when the file's change holds anything
|
||||
else, a change only position reaches included: view state, which a tag
|
||||
or attribute on the way names (the cursor, a selection, scrolling, zoom,
|
||||
the viewport, windows, splitters, Inkscape's `namedview`, view and
|
||||
configuration settings, the printer, a save's history, edit time,
|
||||
editing duration and cycles, last-saved time, the generator and
|
||||
document statistics), or the value of a name-like attribute or `key` on
|
||||
the way, when it is one token of several words, as LibreOffice's
|
||||
`config:config-item[@config:name=CursorPositionX]` inside
|
||||
`[@config:name=ooo:view-settings]`; an attribute ending in `ID` or `Id`,
|
||||
or an `rsid`, that the app renumbered, with everything else in its
|
||||
element, as Gnumeric empties a formula cell whose shared expression it
|
||||
renumbers, and an identifier the app numbers by position; volatile
|
||||
values, UUIDs and epoch times, and durations and counts under a
|
||||
document's metadata; times the app stamps, also as a date written in
|
||||
parts whose tag, or one it sits in, names when the app made, changed or
|
||||
saved something, as Tellico's `<cdate>` of `<year>`, `<month>` and
|
||||
`<day>` (`cdate`, `mdate`, `created`, `modified`, `saved`, `updated`),
|
||||
which no check ever reads, while a date a user enters in parts, as a
|
||||
birthday, is an edit like any other; and `upkeep`, the
|
||||
`loext:tab-stop-distance` attributes LibreOffice fills in `styles.xml`
|
||||
while another archive entry holds an edit. However much noise
|
||||
comes first, it never takes a check's place. When the change holds
|
||||
nothing else, the checks stay and a note flags them: up to three in a
|
||||
document, and as many as fit in the app's own state, where a view
|
||||
setting may be the task.
|
||||
- Whitespace an app lays out between elements is not checked, and values
|
||||
that look like a time the app stamps, in ISO 8601, as C's `asctime`
|
||||
writes it (`Thu Nov 5 09:20:31 2026`) or as a time of day to the
|
||||
second (`05:16:21.675302540`), are left out; noise never makes its
|
||||
ancestor's whole text a check.
|
||||
- `guards`: checks an author may add to show the edit left the rest alone,
|
||||
kept out of `task.checks`, with ids `guard-1` and on: for each suggested
|
||||
`value_equals` or `text_equals` on a member of a list, a field on up to
|
||||
two like siblings, nearest first, at its seed value, which the end holds
|
||||
too: the check's own field where like siblings hold different values in
|
||||
it, and otherwise one that varies among them, as Planner's `work` rather
|
||||
than the `type="normal"` every task shares; never through a sibling only
|
||||
position or a renumbered id pairs. A text file gets a `lines_present` of the
|
||||
unchanged list items beside its first new line with the same marker, as
|
||||
Zim's other `[ ]` action items, or else its nearest lines with words in
|
||||
them. At most four a file. They pass on the seed, which the export allows,
|
||||
since one check failing there is enough.
|
||||
- `notes`: why `files` is empty, or why a file's suggestions are thin. Each
|
||||
note has a `code` and a `message`. For a draft with no files: `no_change`
|
||||
when no file under the home changed between the two checkpoints and nor
|
||||
did the application's dconf keys; `unowned_changes` when files changed but
|
||||
none under the owned paths, with up to five of them in `files`, each with
|
||||
its home path and role (desktop services' files last), and how many more
|
||||
in `more`; `uncheckable_changes` when the application's keys in a dconf
|
||||
database changed, with the database in `files`: no check reads dconf, and
|
||||
the export only writes the keys as they were at the seed checkpoint, so
|
||||
make the task's change one the app saves in a file; `unreadable_changes`
|
||||
when a dconf database changed but REA could not read it, with the read
|
||||
failure in `error` (install `dconf-cli` or set `REA_DCONF_COMMAND` when it
|
||||
is missing), since whose keys changed is then unknown; and `no_document`
|
||||
when no file has the document role, as when no window title shows the
|
||||
file's name. A capture again with `--state-path` naming the file, or
|
||||
`state_paths` on a build computer's `start_build_capture`, makes it the
|
||||
app's. For a drafted file, named in `file`: `by_position` when
|
||||
changes reach their element only by position, the tags no attribute names
|
||||
alone in `elements`, or when only the elements' order changed;
|
||||
`view_state_only` when every change is noise, the checks kept in
|
||||
`pointers`; `long_text` when an element's text changed past the 2,000
|
||||
characters a text check compares, the elements in `pointers`; `cut_view`
|
||||
when the views hold only part of the file; and `unreadable_view` when no
|
||||
check can read it, as a document REA reads as binary.
|
||||
text changed, then an element added whole that it exists, one removed whole
|
||||
that it is absent, then values changed, added and removed, an entry or a
|
||||
JSON value added whole through its members, and an empty array or object as
|
||||
it is. The text check names the paragraph rather than a run inside it: it
|
||||
goes up from an element sitting in its parent's text, and from one named by
|
||||
its tag or position alone to the nearest ancestor named by an attribute, as
|
||||
AbiWord's `p` by its `xid`; the text nodes and runs inside it get no other
|
||||
check, but an element holding no text that is added or removed there, such
|
||||
as an image or a line break, keeps its own, since the text check never
|
||||
reads it. Whitespace an app lays out between elements is not checked, and
|
||||
values that look like a time the app stamps, in ISO 8601 or as C's
|
||||
`asctime` writes it (`Thu Nov 5 09:20:31 2026`), are left out.
|
||||
|
||||
The suggestions are a starting point. Keep the ones that say what the user
|
||||
did; drop the ones that only follow from how the app saves its file. Read
|
||||
`values` for what changed and its pointers, and `refers_to` for what a number
|
||||
stands for, before writing the prompt and any check of your own. A LibreCAD
|
||||
did; drop the ones that only follow from how the app saves its file. A LibreCAD
|
||||
capture that added four holes to a drawing rewrote it from DXF R12 to DXF 2007,
|
||||
so most of its lines changed; the draft suggests counts of `SECTION`, `ENDSEC`
|
||||
and `CIRCLE`, and only `CIRCLE` going from 5 to 9 is the user's change.
|
||||
@@ -281,9 +129,7 @@ The rules both evaluators follow:
|
||||
`{"groups": {"GROUP": {"KEY": "VALUE"}}}`, so a setting is
|
||||
`/groups/GROUP/KEY`; XML as `{"root": {"name", "attributes", "children"}}`;
|
||||
SQLite as `{"tables": {"TABLE": {"columns", "rows"}}}`; a zip archive as
|
||||
`{"entries": [{"name", "format", "view", …}]}`; a gzip file, such as a
|
||||
Gnumeric `.gnumeric`, as the document inside it, so its pointers are those
|
||||
of the same document uncompressed.
|
||||
`{"entries": [{"name", "format", "view", …}]}`.
|
||||
- With `tolerance`, a non-negative number, `value` must be a number, and the
|
||||
value found passes when it is a number, or a string that is a decimal
|
||||
numeral such as `"5.0000000000000000"`, at most `tolerance` from `value`.
|
||||
@@ -476,10 +322,7 @@ The bundle then holds, besides the app and `tasks/smoke.json`:
|
||||
|
||||
The verifier finds the app among the computer's child environments, calls its
|
||||
`data/get` under the run's grant of the computer's control token, and reads
|
||||
the `state` data part. It reads again until the app's files settle, as
|
||||
[grading once the app has saved](desktop-application-export.md#grading-once-the-app-has-saved)
|
||||
describes, and each result's `settled` says whether they did, and `read_cut`
|
||||
whether the bound cut a read still running. It raises when the app cannot be reached, so the run
|
||||
the `state` data part. It raises when the app cannot be reached, so the run
|
||||
fails rather than scoring the agent. The README lists the task, its prompt, its
|
||||
checks and the recipe below.
|
||||
|
||||
|
||||
@@ -45,11 +45,9 @@ From a request, REA renders a bundle in a private temporary folder: a computer
|
||||
app on the `ubuntu-24.04` base with the `reference` driver that installs the
|
||||
app, opens it on demand with `gtk-launch <desktop entry>` from the computer
|
||||
user's home, so its open and save dialogs start there rather than in the
|
||||
framework's folder for the app, and keeps no seed and no data hooks. The app is not open when the computer starts:
|
||||
`start_build_capture` opens it under REA's capture. When no capture is under
|
||||
way, open it from the desktop's Applications menu, where agentenv lists it
|
||||
under Other by the environment's name, such as `mousepad`; that entry launches
|
||||
it through the app's server.
|
||||
framework's folder for the app, and keeps no seed and no data hooks. The app is not open when the computer starts: agentenv lists it
|
||||
in the desktop's Applications menu under Other by the environment's name, such
|
||||
as `mousepad`, and that entry launches it through the app's server.
|
||||
|
||||
When the app is Electron, set `electron` to true. The install rewrites that
|
||||
desktop entry's command with the same policy an export uses: `--no-sandbox`
|
||||
@@ -98,10 +96,6 @@ in the folder and its files stay as they were shared.
|
||||
REA runs the deploy with `run_bundle(keep=True, emulate=False)` on the local
|
||||
sandbox provider, so only the host's own architecture is built. The first start
|
||||
of a bundle builds its image and can take minutes; later starts reuse it.
|
||||
agentenv makes a start wait while another agentenv run on this host writes its
|
||||
bundle's ids, so starts at the same time wait for each other, several minutes
|
||||
when a few run together; the progress line then says it is waiting for another
|
||||
agent-env run to finish writing this bundle's ids.
|
||||
While it waits, REA sends an MCP progress notification every five seconds with
|
||||
agentenv's latest line, so a client that resets its request timeout on
|
||||
progress keeps waiting. REA then waits until the computer's readiness checks
|
||||
|
||||
+18
-106
@@ -10,7 +10,7 @@ grades the witness with the same checks the exported verifier runs.
|
||||
| Tool | What it does |
|
||||
| -------------------------- | ------------------------------------------------------------------------------------------- |
|
||||
| `start_build_capture` | Downloads the package lists as the computer's user and launches the app under REA's capture |
|
||||
| `mark_build_checkpoint` | Takes a named checkpoint and returns the capture's counts and the files that changed |
|
||||
| `mark_build_checkpoint` | Takes a named checkpoint and returns the capture's acknowledgement with its counts |
|
||||
| `stop_build_capture` | Stops the capture and returns its checkpoints and the task draft between `seed` and `end` |
|
||||
| `export_build_environment` | Exports the bundle with the agent's task inside the computer and copies it to a folder here |
|
||||
| `check_build_task` | Grades a task against the app's live state; with a `stage`, files the check in the witness |
|
||||
@@ -41,34 +41,6 @@ See [desktop builds](https://github.com/morluto/rea/blob/main/.agents/skills/rev
|
||||
from a `.deb` file, the build layer keeps that file at
|
||||
`/opt/rea/package.deb` and the capture records it with `--package-file`. Do not open the app from
|
||||
the menu first: the capture refuses an app whose window is already open.
|
||||
When the capture ends before the window opens, REA reads its output. An app
|
||||
that exits at launch, such as one missing a runtime, is reported with its
|
||||
program, exit code, run time and the last lines of its stderr, at most 8
|
||||
lines and 800 characters of the last 8 KiB the capture keeps, and
|
||||
`details.diagnostics` keeps the capture's record of the session. A capture
|
||||
that failed, such as one refusing to start, gives its own message and
|
||||
remediation, with the whole failure in `details.diagnostics.command_failure`
|
||||
and, when its cleanup is incomplete, the run tokens and paths it left in
|
||||
`details.resources`. A checkpoint or stop that finds the capture ended
|
||||
reads its output the same way.
|
||||
|
||||
`state_paths` names files or folders in the computer's home that hold the
|
||||
app's state, relative to the home, after `~/` or absolute under it, at
|
||||
most 16; each becomes a `--state-path` of the capture, so it is retained
|
||||
from the start and its files count as the app's even before they exist.
|
||||
REA counts a file as a document only when an app window's title shows its
|
||||
name or `~/` path, so name the file the app will save when its title shows
|
||||
something else, as MuseScore's shows a score's title: a file outside
|
||||
hidden folders, other than a lock such as LibreOffice's `.~lock.<name>#`,
|
||||
becomes a document, which the bundle owns, seeds and opens
|
||||
at launch, and one under a hidden folder such as `~/.config/MuseScore` the
|
||||
app's own state, also when that folder is a link elsewhere in the home. A
|
||||
path with `..`, or naming the home itself, is refused before the computer
|
||||
is asked; the computer refuses an absolute path outside its home, one in
|
||||
`~/.rea-build`, and one a link leads out of the home or into
|
||||
`~/.rea-build`, resolving a path that does not exist yet through its
|
||||
nearest existing folder, and starts nothing.
|
||||
|
||||
3. Make the seed through the app with `act_on_build_computer`, saving it
|
||||
where the user keeps such files, such as `~/Documents`, then
|
||||
`mark_build_checkpoint` `seed`.
|
||||
@@ -76,56 +48,22 @@ See [desktop builds](https://github.com/morluto/rea/blob/main/.agents/skills/rev
|
||||
`mark_build_checkpoint` `end`.
|
||||
5. `stop_build_capture`. The app is closed and the capture finishes. The
|
||||
result lists the checkpoints with their counts, the package and the
|
||||
sources the capture found, its limitations and the draft: each file under
|
||||
the paths the export owns that changed between `seed` and `end`, with its
|
||||
net change and, for XML files, archives, JSON and key files, its `values`,
|
||||
the values the change added, changed and removed with what each was and
|
||||
became, at the pointer a check names it by; suggested checks with a
|
||||
placeholder prompt; and `guards`, optional checks that the rest kept its
|
||||
seed values. The draft's
|
||||
[task section](desktop-application-tasks.md#describe-the-change) describes
|
||||
each. `notes`, each with a `code` and a `message`, say why a draft has no
|
||||
files: `no_change` when no file under the home changed between them and
|
||||
nor did the app's dconf keys; `unowned_changes` when files changed but
|
||||
none under the owned paths, listing up to five in `files` with their
|
||||
roles, desktop files last, and counting the rest in `more`;
|
||||
`uncheckable_changes` when the app's keys in dconf were read and changed,
|
||||
listing the database in `files`, since no check reads dconf (a version
|
||||
the capture kept no copy of, as it keeps none of the database at the
|
||||
start, counts as holding none of the app's keys);
|
||||
`unreadable_changes` when a dconf database changed but REA could not read
|
||||
it, such as without `dconf-cli`, with the read `error`, so whose keys
|
||||
changed is unknown; and `no_document` when no file has the document role.
|
||||
`unowned_changes` and `no_document` point at `state_paths`. They also say,
|
||||
for a drafted `file`, why its suggestions are thin: `by_position`,
|
||||
`view_state_only`, `long_text`, `cut_view` or `unreadable_view`.
|
||||
sources the capture found, its limitations and the draft: each file that
|
||||
changed between `seed` and `end` with its net change, and suggested
|
||||
checks with a placeholder prompt.
|
||||
6. Write the task: its name, the prompt in the user's own words, and checks
|
||||
that hold after the change and not on the seed, from the suggestions,
|
||||
`values` and any `guards` worth keeping.
|
||||
that hold after the change and not on the seed.
|
||||
7. `export_build_environment` with the task and a new or empty `directory`.
|
||||
The export runs inside the computer with `--seed-checkpoint seed
|
||||
--end-checkpoint end`, so it seeds what was saved at `seed`, scrubs the
|
||||
computer's host name and user from it, and refuses a task whose checks
|
||||
all pass on the seed. It also passes `--synthetic-seed`, since the agent
|
||||
made the seed for the task, so the README does not call it the user's real
|
||||
data. When the seed holds exactly one document and the app's desktop entry
|
||||
takes files, the bundle's app opens that document at launch. A file moved
|
||||
to the desktop Trash is not seeded, and the export's limitations name what
|
||||
the Trash held at `seed`. The limitations and the README also name the
|
||||
folders where files changed during the capture that the bundle neither
|
||||
owns nor seeds, such as settings that keep a first-run wizard away, up to
|
||||
eight collapsed to their top folder, such as `~/.config/MuseScore`, and a
|
||||
count of the rest; capture again with them in `state_paths` to own them.
|
||||
Lock files the app holds while it runs, such as LibreOffice's profile
|
||||
`.lock` and its document lock `.~lock.<name>#`, are left out of the seed,
|
||||
since a copied one can keep the app from starting, and the limitations
|
||||
and the README list them after "Left out of the seed"; a project's
|
||||
`Cargo.lock` or `yarn.lock`, a document or a path in `state_paths` is
|
||||
seeded. They name seeded
|
||||
WebKit or Chromium storage and caches too, which the app keeps for its
|
||||
own running. When the application held files open in a folder whose
|
||||
starting content the capture did not retain, a limitation names the
|
||||
folder and the seed files in it. For a
|
||||
all pass on the seed. A task larger than 96 KiB as REA passes it to the
|
||||
computer is refused before anything runs. It also passes `--synthetic-seed`,
|
||||
since the agent made the seed for the task, so the README does not call it
|
||||
the user's real data. When the seed holds exactly one document and the
|
||||
app's desktop entry takes files, the bundle's app opens that document at
|
||||
launch. A file moved to the desktop Trash is not seeded, and the export's
|
||||
limitations name what the Trash held at `seed`. For a
|
||||
`.deb` app that no apt source the capture found offers, the export takes
|
||||
the request's URL with `--package-url`; one apt offers installs from apt. REA lists the bundle's files with their sizes
|
||||
and SHA-256 in the computer, into a file beside the bundle that it reads
|
||||
@@ -140,15 +78,7 @@ A checkpoint name is lowercase letters, digits, dot, dash and underscore; the
|
||||
capture's own `baseline`, `stop`, `time-limit` and `exit` are refused, and so
|
||||
is a name already taken. The acknowledgement comes from the capture after it
|
||||
has walked the home and retained what changed: `entries` walked, `changes`
|
||||
since the checkpoint before, `retained_files` and `retained_bytes`, and up to
|
||||
ten `changed_files`, home-relative, with `more_changed_files` counting the
|
||||
rest. Folders are left out; files under `state_paths` come first, then
|
||||
those the app held open, then those in its state directories, then the rest,
|
||||
and caches and WebKit or Chromium storage last, each by path, so a save's
|
||||
document leads the list. When the computer's REA is older than these lists,
|
||||
as when `REA_BUILD_COMPUTER_REA_ARCHIVE` still names an earlier build, the
|
||||
checkpoint is still taken and both are `null`: which files changed is
|
||||
unknown. Pack the current REA into the archive to get them back.
|
||||
since the checkpoint before, `retained_files` and `retained_bytes`.
|
||||
|
||||
Each step can be asked again after its answer was lost:
|
||||
|
||||
@@ -172,9 +102,7 @@ computer's control token. REA sends each command through agentenv's
|
||||
`computer-exec/v1` route with that token, which stays in REA, and reads larger
|
||||
outputs, such as the draft, the export's Evidence and the bundle's file
|
||||
list, from files under `~/.rea-build` through `data/get`, since a command's
|
||||
output is capped at 1 MiB. In a command's Evidence or failure read this way,
|
||||
as in its own output, REA replaces the token in every string, after checking
|
||||
the Evidence's digest; the bundle's files arrive as they are.
|
||||
output is capped at 1 MiB.
|
||||
|
||||
Calls on one computer run one at a time, in the order REA receives them:
|
||||
an action, a capture step, a check or a close waits until the call before
|
||||
@@ -188,11 +116,7 @@ cancels the call in progress on it and refuses the calls still waiting.
|
||||
|
||||
Start a fresh computer from the exported folder with `start_build_computer`
|
||||
and `{"kind": "bundle", "path": ...}`; agentenv boots the app with the seed,
|
||||
on the seed's document when the export opens one. When the computer never
|
||||
gets ready and the bundle's seed holds lock files, the start's error names
|
||||
them: delete them from the bundle, or export again, which leaves them out.
|
||||
A bundle records no state directories, so the error names only files by a
|
||||
profile lock's name and LibreOffice's document locks.
|
||||
on the seed's document when the export opens one.
|
||||
Then, with the task exactly as exported:
|
||||
|
||||
| `stage` | Before it | Its checks must |
|
||||
@@ -205,18 +129,7 @@ Then, with the task exactly as exported:
|
||||
`check_build_task` reads the app's `data/get`, takes the views it returns
|
||||
beside the files and evaluates each check with REA's evaluator, the one the
|
||||
export validates tasks with and the exported verifier mirrors, one result per
|
||||
check. Like the verifier, it grades only once the app's files settle, since an
|
||||
app such as Gnote saves a few seconds after the last key. It reads `data/get`
|
||||
every 0.5 s and grades once every file's bytes have held for 3 s, counted
|
||||
from the read that returned them. 15 s after the first read began, it grades
|
||||
the last completed read: no read starts then, and one still running is cut.
|
||||
It sends progress notifications while it waits. The result's `settled` says
|
||||
whether the files settled, and `read_cut` whether the bound cut a read; each
|
||||
stage in the record keeps both. Every check therefore costs at least 3 s,
|
||||
and a save that lands more than 3 s after the first read returns is still
|
||||
missed; see
|
||||
[grading once the app has saved](desktop-application-export.md#grading-once-the-app-has-saved).
|
||||
Without `stage` it only grades. The `seed` stage begins a recording
|
||||
check. Without `stage` it only grades. The `seed` stage begins a recording
|
||||
of the display under REA's own request id, one per computer; a seed check
|
||||
that fails after it, such as on a failed read of the app's state or a lost
|
||||
reply to the recording's start, can be asked again, and asks for the
|
||||
@@ -258,14 +171,13 @@ A stage whose checks do not show what it must ends the witness, and so does
|
||||
- `recording/NNNN.mp4`, the recording's segments;
|
||||
- `witness.json`, REA Evidence (`rea.desktop-build-witness`) holding the
|
||||
verdict, the stage that failed if one did, the task's name and SHA-256,
|
||||
each stage's results with how many logged actions came before it and
|
||||
whether the app's files had settled (`settled`), the
|
||||
each stage's results with how many logged actions came before it, the
|
||||
computer's [action log](desktop-build-computer.md#act) as it keeps it, each
|
||||
action with its arguments, timing and outcome, with `actions_dropped`
|
||||
counting the earliest actions it no longer keeps, and the recording's
|
||||
segments with their sizes and SHA-256. The record's limitations say when
|
||||
the log dropped actions or cut arguments, which each entry names in
|
||||
`truncated_arguments`, and which stages graded files that had not settled.
|
||||
`truncated_arguments`.
|
||||
|
||||
The stages' rules read the log's count of actions and the last applied
|
||||
action of each kind, which it keeps for the whole session, so they hold
|
||||
|
||||
+10
-16
@@ -602,12 +602,6 @@ For partial Evidence delivery, verify that same-session readback preserves
|
||||
identity and provenance without rerunning the provider. Include a no-writer
|
||||
control that keeps completed Evidence inline and preserves the original failure.
|
||||
|
||||
For a seekable file with a known extent, distinguish a provably impossible wire
|
||||
extent from an independent representation limit. Pair the malformed declaration
|
||||
with a structurally possible over-limit control. A count-only truncated fixture
|
||||
does not establish capacity behavior. This does not require decoding an opaque
|
||||
compressed payload merely to apply its declared expansion limit.
|
||||
|
||||
When producer order is unspecified, synchronize fixtures on the observed request
|
||||
or completion event. A filename, generated key, or fixed delay does not prove
|
||||
which item completed before cancellation. Preserve real producer ordering and
|
||||
@@ -708,16 +702,16 @@ the affected owners and applicable scenarios below. Include temporary snapshots
|
||||
and one-shot commands. Use public CLI/MCP workflows where practical and a
|
||||
controlled production seam for interleavings that cannot be reproduced reliably.
|
||||
|
||||
| Scenario | Assertion and control |
|
||||
| --------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| Target admitted; startup still pending | Status preserves the readiness distinction and observed startup activity; readiness requires the provider's documented proof. |
|
||||
| First handshake is late, absent, invalid, or recovered during close | Initial and recovery paths retain the same authenticated identity facts. Foreign run/token controls cannot authorize cleanup; authenticated idle/native work survives the unauthenticated listener deadline. |
|
||||
| Launch returns an error with a valid process handle | Cover already-exited and still-live owned processes. Verify observed exit separately from creation; failed termination or unavailable identity remains unresolved. |
|
||||
| Cancellation arrives after workload exit, during result reads or temporary-root removal | Before the documented commit cutoff, return typed cancellation with available partial observations and actual cleanup status. After commit, assert the owning publication outcome and receipt. The non-aborted control succeeds; existing primary/cleanup failures keep their precedence. |
|
||||
| Children have mixed health or cleanup outcomes | Missing peer health does not erase an observed failure or activity. Idle plus unknown stays unknown. Retry a failed child without closing a successful peer again, including after a close-option change. |
|
||||
| Cleanup fails after success or primary failure | Public output retains the completed observation or primary diagnostic, remaining resources, and owner recovery action. Restore the denied resource and verify the owning cleanup retry. |
|
||||
| Cleanup owners recover after an error was returned | Retain the original child and aggregate errors and project them after each owner releases. A successful peer stays released; the aggregate remains incomplete until all owners release. Preserve the first cause even when rejection is `undefined`. |
|
||||
| Target exits without an acknowledgement, or transport disappears while it stays alive | Positive owned exit proof resolves target lifetime; other resources still need cleanup. Lost transport alone does not prove exit. Verify unrelated/attached targets survive and same-connection recovery works when supported. |
|
||||
| Scenario | Assertion and control |
|
||||
| --------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| Target admitted; startup still pending | Status preserves the readiness distinction and observed startup activity; readiness requires the provider's documented proof. |
|
||||
| First handshake is late, absent, invalid, or recovered during close | Initial and recovery paths retain the same authenticated identity facts. Foreign run/token controls cannot authorize cleanup; authenticated idle/native work survives the unauthenticated listener deadline. |
|
||||
| Launch returns an error with a valid process handle | Cover already-exited and still-live owned processes. Verify observed exit separately from creation; failed termination or unavailable identity remains unresolved. |
|
||||
| Cancellation arrives after workload exit, during result reads or temporary-root removal | Return typed cancellation with available partial observations and actual cleanup status. The non-aborted control succeeds; existing primary/cleanup failures keep their precedence. |
|
||||
| Children have mixed health or cleanup outcomes | Missing peer health does not erase an observed failure or activity. Idle plus unknown stays unknown. Retry a failed child without closing a successful peer again, including after a close-option change. |
|
||||
| Cleanup fails after success or primary failure | Public output retains the completed observation or primary diagnostic, remaining resources, and owner recovery action. Restore the denied resource and verify the owning cleanup retry. |
|
||||
| Cleanup owners recover after an error was returned | Retain the original child and aggregate errors and project them after each owner releases. A successful peer stays released; the aggregate remains incomplete until all owners release. Preserve the first cause even when rejection is `undefined`. |
|
||||
| Target exits without an acknowledgement, or transport disappears while it stays alive | Positive owned exit proof resolves target lifetime; other resources still need cleanup. Lost transport alone does not prove exit. Verify unrelated/attached targets survive and same-connection recovery works when supported. |
|
||||
|
||||
Shared process-supervision controls separate leader exit from output closure.
|
||||
Cover output during held or failed cleanup, bounded retention and drain timeout,
|
||||
|
||||
@@ -60,11 +60,23 @@ or ordinary script path when available. Identify the specific gap and what a
|
||||
new or extended contract would add; upstream capability alone does not require
|
||||
a new tool or equal support from every provider.
|
||||
|
||||
Use the caller's selected target and authority. Follow
|
||||
[provider-backed workflow verification](testing.md#provider-backed-workflow-verification)
|
||||
for independent observations, boundary controls and reporting unavailable
|
||||
provider coverage. A scripted tool sequence does not establish agent selection;
|
||||
that claim requires an actual agent evaluation.
|
||||
Exercise the task through REA as a whole and compare relevant provider behavior
|
||||
with an independent artifact or format observation where possible. Use the
|
||||
caller's selected target and authority. Record the provider version, target and
|
||||
observed coverage, and distinguish an unsupported operation from an empty
|
||||
result or an untested path.
|
||||
|
||||
Include the boundary cases that could change the answer: provider labels versus
|
||||
source facts, addresses versus file locations, partial results, and a useful
|
||||
recovery after failure or session close when those apply to the task. Check that
|
||||
composed results keep each observation's identity, limitations and source
|
||||
association. Existing real-provider lanes and focused tests establish their
|
||||
selected scenarios; they do not by themselves establish a different workflow or
|
||||
provider equivalence. If a provider cannot be exercised, report that limitation
|
||||
and continue with the available evidence. Measure agent tool selection only with
|
||||
an actual agent evaluation; a scripted tool sequence does not establish it. Use
|
||||
[testing guidance](testing.md#provider-backed-workflow-verification) to select
|
||||
the cases that establish the proposed contract.
|
||||
|
||||
## Audit existing tools
|
||||
|
||||
@@ -82,10 +94,14 @@ identity, session lifetime and available alternatives. Matching text between
|
||||
two renderers does not establish that their shared advice is correct or that an
|
||||
agent selected the workflow.
|
||||
|
||||
Exercise each selected workflow before and after the tool call. Use
|
||||
[workflow verification](testing.md#provider-backed-workflow-verification) to
|
||||
check returned facts, partial outcomes, recovery and the scope of existing
|
||||
provider evidence.
|
||||
Exercise the selected public workflows, including the steps before and after a
|
||||
tool call. Check task selection, input choices, returned facts and their source,
|
||||
partial or unsupported outcomes, and applicable session and recovery behavior.
|
||||
Compare native provider output and an independent artifact observation where
|
||||
available. Inspect existing tests and real-provider lanes for the scenario they
|
||||
actually cover; a passing test does not establish a different task or host.
|
||||
Use [workflow verification](testing.md#provider-backed-workflow-verification)
|
||||
for counterexamples and lifecycle controls relevant to the audit.
|
||||
|
||||
Report working routes as well as findings. Separate a reproduced contract bug,
|
||||
an intentional limitation, a design opportunity and an unverified hypothesis;
|
||||
@@ -166,7 +182,7 @@ does not establish another instance.
|
||||
whether applicable static relationships could have been missed by discovery;
|
||||
missing discovery is unknown. Preserve paths supported by observed edges,
|
||||
and qualify negative and shortest-path claims by discovery scope. Missing
|
||||
relationship coverage remains `unknown`. Computed candidates and unestablished incoming targets qualify directional discovery; they do not by themselves mean that recorded edges were omitted.
|
||||
relationship coverage remains `unknown`.
|
||||
- Declare process, filesystem, network, UI, and mutation effects truthfully;
|
||||
enforce the requested target and lifecycle.
|
||||
- Add limits only for real format, protocol, authority, or measured resource
|
||||
@@ -332,15 +348,13 @@ stages that never ran.
|
||||
and resource release separate. A valid process handle, successful launcher,
|
||||
or selected target establishes only its own fact. Publish available identity
|
||||
and exit observations even when launch fails; retain unknown ownership.
|
||||
- Process exit does not establish output closure. The
|
||||
[shared supervisor](https://github.com/morluto/rea/blob/main/src/process/ProviderProcess.ts)
|
||||
owns diagnostic retention and bounded draining through cleanup and retries.
|
||||
Report incomplete output separately from process cleanup. After verified stop
|
||||
and bounded draining, release owned event-loop references even if output closure
|
||||
stays unconfirmed. Keep the output capture owned for retry while process cleanup
|
||||
is unresolved. Borrowed processes and streams retain their own lifetime and
|
||||
reference state; select the matching
|
||||
[supervision controls](testing.md#lifecycle-regressions) when changing this code.
|
||||
- Process exit does not establish output closure. The shared process supervisor
|
||||
retains at most 64 KiB of additional diagnostics from owned stop entry,
|
||||
including pending cleanup and retries, and drains for up to one second after
|
||||
verified stop. It marks output incomplete when closure cannot be
|
||||
observed and releases owned event-loop references without changing the proven
|
||||
process-cleanup outcome. Failed process cleanup retains capture for retry;
|
||||
borrowed processes and streams retain their own lifetime and reference state.
|
||||
- Authenticate and capture identity through the same boundary on initial and
|
||||
recovery handshakes. Bound abandoned unauthenticated listeners where the
|
||||
protocol permits it; that deadline must not expire authenticated idle sessions
|
||||
@@ -359,9 +373,8 @@ stages that never ran.
|
||||
analysis snapshot is part of `open_binary`; cancellation keeps that operation
|
||||
and the caller's reason through the shared JSON reader.
|
||||
- For cancellable observations, carry cancellation through result consumption
|
||||
and awaited cleanup. Check the signal after the last awaited finalization step
|
||||
unless the operation has passed its documented commit cutoff. Preserve the
|
||||
owning operation's committed outcome and receipt after that cutoff.
|
||||
and awaited cleanup. Before returning success, check the signal after the
|
||||
last awaited finalization step.
|
||||
Retain collected observations under typed cancellation. Preserve an existing
|
||||
primary failure and let incomplete cleanup retain its own classification.
|
||||
Preserve the caller's abort reason as the typed cancellation error's cause,
|
||||
|
||||
@@ -44,13 +44,6 @@ file memory regions and paths (`NT_FILE`), fault signal and code (`NT_SIGINFO`),
|
||||
auxiliary vectors (`NT_AUXV`) across 32-bit and 64-bit images. Other owners or unparsed
|
||||
notes keep `core` null.
|
||||
|
||||
Linux `CORE` decoding requires System V/unspecified (0) or GNU/Linux (3)
|
||||
OSABI with ABI version zero. An unspecified OSABI alone does not establish
|
||||
Linux origin. An explicitly different OSABI or ABI version leaves `core` null
|
||||
and its Linux-specific `type_name` unknown, with a limitation explaining the
|
||||
profile. Owner/type numbers, descriptor ranges and hashes, GNU-owned notes,
|
||||
and complete table-examination coverage remain available.
|
||||
|
||||
`PT_NOTE` and `SHT_NOTE` are examined independently. The same file range may
|
||||
appear twice when both tables declare it.
|
||||
|
||||
|
||||
+65
-49
@@ -439,19 +439,6 @@ descriptors, and a pefile-compatible import hash of the standard import table.
|
||||
A missing import directory is observed absence of that table. See
|
||||
[PE import and delay-load tables](../pe-imports.md).
|
||||
|
||||
Inspect a Windows Shell Link (`.lnk`) without resolving or executing the
|
||||
target:
|
||||
|
||||
```bash
|
||||
rea inspect-windows-shortcut /absolute/path/to/shortcut.lnk --json
|
||||
```
|
||||
|
||||
The workflow reports header flags and FILETIMEs, IDList items, LinkInfo volume
|
||||
and network names, StringData arguments and icon location, ExtraData blocks
|
||||
including Tracker droid facts labelled derived, and derived observations such
|
||||
as argument length and a minimized ShowCommand. See
|
||||
[Windows Shell Link shortcuts](../guides/native/windows-shortcut.md).
|
||||
|
||||
Inspect ELF PT_NOTE and SHT_NOTE tables without executing the image:
|
||||
|
||||
```bash
|
||||
@@ -609,11 +596,10 @@ be verified. See [MCP contracts](../reference/mcp-contracts.md) for session life
|
||||
[Ghidra first-query deadlines](../reference/mcp-contracts.md#ghidra-first-query-deadlines-and-recovery)
|
||||
for import, client timeouts and recovery.
|
||||
|
||||
A one-shot command attempts provider-session and runtime cleanup before reporting
|
||||
a failure. If cleanup remains incomplete, inspect the reported resources and
|
||||
follow the error's remediation. [Same-session cleanup retry](../reference/mcp-contracts.md#retained-cleanup-retry),
|
||||
reuse and `update_analysis_settings` apply to a live MCP connection.
|
||||
For one-shot commands, `details.limit` reports `scope: "rea-invocation"` and
|
||||
A one-shot command releases its provider session and REA runtime before it
|
||||
prints a failure, so it omits the same-session reuse and
|
||||
`update_analysis_settings` guidance an MCP connection receives. Its
|
||||
`details.limit` reports `scope: "rea-invocation"` and
|
||||
`applies_at: "next_invocation"`; set the named `environment` (or the per-call
|
||||
`parameter`) for a new invocation and rerun. For example, a Ghidra decompile
|
||||
deadline names `REA_GHIDRA_DECOMPILE_TIMEOUT_SECONDS`.
|
||||
@@ -642,10 +628,12 @@ an exact result when the target bytes, operation, parameters, provider and
|
||||
settings match. Mutations and cursor-dependent calls are excluded from the
|
||||
cache. Snapshot files are local and use owner-only permissions.
|
||||
|
||||
A binary CLI replay reports the current invocation's selected path while leaving
|
||||
the saved Evidence and snapshot query unchanged. See
|
||||
[caller-selected paths](../reference/mcp-contracts.md#caller-selected-paths)
|
||||
for primary and auxiliary path fields and their relation to Evidence identity.
|
||||
One-shot binary CLI Evidence reports the exact path argument in `caller_input_path`,
|
||||
including relative spelling and symlink aliases. Its subject identifies the
|
||||
inspected artifact; `caller_input_path` does not change the Evidence ID or
|
||||
snapshot query. A replay reports the current invocation's path while leaving
|
||||
the saved Evidence unchanged. Provider inspections continue to include the
|
||||
established `parameters.input_path` field.
|
||||
|
||||
Importing an Evidence bundle refreshes retained request and subject display metadata.
|
||||
It preserves cached analysis results, including observations for other targets.
|
||||
@@ -1151,23 +1139,6 @@ of the serve command's stopped document. See
|
||||
[agent environments](../agent-environments.md#export-a-bundle) for the folder
|
||||
layout and what the smoke task checks.
|
||||
|
||||
`rea environment-export` prints the written files and exits `0` on success.
|
||||
Input-pair refusals, an occupied destination, a missing package tarball, and
|
||||
invalid labels fail before writing output. Host permission failures identify
|
||||
whether reading or writing was denied and retain the affected path.
|
||||
|
||||
A failure during writing can leave a partial folder. Inspect it before removing
|
||||
it and retrying; the next attempt refuses a non-empty destination. When one
|
||||
file caused the failure, the diagnostic names that file. A folder-sync failure
|
||||
can report only its cause.
|
||||
|
||||
If `details.partial_observation.kind` is `environment-bundle-publication`, the
|
||||
bundle was already published. Its `directory` and `files` record the committed
|
||||
output, even when a later identity check or cleanup failed. Inspect that bundle
|
||||
and resolve the reported failure before using or replacing it; the receipt is
|
||||
not an instruction to delete published output. Cleanup resources remain a
|
||||
separate obligation.
|
||||
|
||||
## Compare an environment with its application
|
||||
|
||||
`rea environment-compare <manifest.json> --evidence <capture.json> --probe <probe.json> [--probe <probe.json> ...]`
|
||||
@@ -1359,17 +1330,62 @@ retains failed stages for retry; the CLI exposes no separate retry command.
|
||||
or prints the refusing stage's structured error and exits `1`, writing nothing
|
||||
when the refusal comes before the bundle is written. SIGINT cancels it with a
|
||||
`cancelled` error; a cancellation before the bundle stage writes nothing.
|
||||
A `cancelled` result does not by itself determine the exit status. Commands
|
||||
that handle SIGINT or SIGTERM assign `130` or `143` after their operation and
|
||||
cleanup settle; their structured result can be printed before that status is
|
||||
assigned. Read the process status and typed result separately.
|
||||
`rea environment-export` is one-shot: it prints the written files and exits
|
||||
`0`, or prints a structured `invalid_request` error and exits `1` for the same
|
||||
pair refusals, a non-empty or file-occupied directory, a missing package
|
||||
tarball or a name that is not a kebab-case label or is a Windows device name,
|
||||
writing nothing in each case. A file occupying the destination is reported as
|
||||
requiring a directory; identity-change diagnostics are reserved for admitted
|
||||
paths that fail later identity checks. Host permission failures identify whether
|
||||
input reading or bundle writing was denied and retain the reported path.
|
||||
A write that fails after the first file (a permission, disk-space or
|
||||
pathname-length failure on a later path) propagates as the host's failure,
|
||||
naming its cause and, when it failed on one bundle file or the package
|
||||
tarball, that file. A failure while syncing the finished folder names only its
|
||||
cause. Either way the partial folder stays in place for inspection; remove it
|
||||
before retrying, since the next attempt refuses the non-empty directory.
|
||||
|
||||
Commands with `--evidence_output` save the complete Evidence bundle before
|
||||
delivering the selected view. For committed-file receipts, retained partial
|
||||
Evidence and missing source records, see
|
||||
[Evidence publication and source recovery](../reference/mcp-contracts.md#evidence-publication-and-source-recovery).
|
||||
Other outputs have their own receipt shapes; for example,
|
||||
[environment export](#export-an-environment-bundle) reports a published directory.
|
||||
A `cancelled` result does not by itself determine the exit status; it depends on
|
||||
the command's signal handling. Commands routed through the shared
|
||||
`withCommandCancellation` handler in the CLI set status `130` for SIGINT or
|
||||
`143` for SIGTERM after their operation settles. Current source registrations
|
||||
use that handler for process capture and comparison (`capture-process`,
|
||||
`compare-process-captures`), desktop application capture and state
|
||||
(`capture-desktop-application`, `inspect-desktop-application-state`,
|
||||
`export-desktop-application`, `describe-desktop-application-task`), JavaScript application analysis (`analyze` when it
|
||||
selects the JavaScript lane, and `analyze-javascript-application`), selected
|
||||
browser, web and Electron commands (including `analyze-web-bundle`,
|
||||
`observe-web-execution`, `capture-browser-scenario` and
|
||||
`capture-electron-scenario`), and the platform and provider command families
|
||||
for Android/ADB, Apktool/JEB/Flutter, firmware, PCAP and signal analysis,
|
||||
WASM/EVM, Go/Rust and binary diagnostics, Frida instrumentation, the Cutter
|
||||
command, objdump, Rizin and GDB, and the agent environment server
|
||||
(`environment-serve`). The handler also wraps `doctor`,
|
||||
`inspect-sqlite-database`, `recover-javascript-sources`,
|
||||
`inspect-il2cpp-metadata`, and `inspect-desktop-application`. In these paths, a returned structured
|
||||
`cancelled` result can be printed before the wrapper assigns the
|
||||
signal-derived status. This describes the current source routing; it is not a
|
||||
claim that every command or provider runtime has been independently exercised.
|
||||
|
||||
Commands with `--evidence_output` select their delivered view, then publish the
|
||||
complete Evidence bundle atomically. Cancellation before publication leaves no
|
||||
new file. A publication that has committed can win a later cancellation; the
|
||||
`cancelled` result then keeps the written path and byte count under
|
||||
`details.diagnostics.evidence_bundle`. If staging cleanup stays incomplete
|
||||
after commit, the `cleanup_incomplete` error reports the same file as
|
||||
`details.published_path` and `details.bytes`.
|
||||
|
||||
When a failure retains a completed observation and no bundle committed,
|
||||
`details.source_closure` states what that observation cites. `publication` is
|
||||
`not_published`. `records` holds authentic source Evidence this invocation
|
||||
captured, within 64 KiB. `omitted` lists up to 64 other identities and
|
||||
`omitted_count` the total: `not_captured` means the invocation holds no such
|
||||
record, so nothing is shown for it or its ancestors; `not_inlined` means it was
|
||||
captured but is not in this response. `complete` is true only when every cited
|
||||
record is in `records` or embedded in the observation. If examining the closure
|
||||
itself fails, `collection_failure` names the error type and the closure state is
|
||||
unknown; the original failure is still returned. Nothing is retained after exit,
|
||||
and running the command again is a new observation.
|
||||
|
||||
When the reader of piped output closes early, as `rea ... | head` does, the
|
||||
CLI stops writing, prints no error and exits `141` (`128 + 13`, the status of a
|
||||
|
||||
@@ -390,15 +390,8 @@ A scoped report has `scope.mode: "explicit"`. Its `scope_checks` determine
|
||||
`environment_healthy` summarizes the full audit. `--target` adds a target check,
|
||||
but the report remains audit-wide unless a scope option is also supplied.
|
||||
|
||||
With one selected client, Ghidra, IDA, JADX and Kuna provider checks use the
|
||||
client's recorded environment over the terminal it inherits. If that registration
|
||||
cannot be read or a setting a provider needs cannot be resolved, its available
|
||||
value is `null` and its check is `unknown`; its configured value is also `null`
|
||||
when the configuration setting itself is unknown. Doctor does not infer
|
||||
readiness from the terminal. A missing registration still uses terminal settings
|
||||
for setup. Other checks, including Hopper, use the terminal running doctor. A
|
||||
client-started server may receive a different environment, and doctor cannot
|
||||
observe it. When an available
|
||||
Provider checks read the terminal running doctor. A client-started server may
|
||||
receive a different environment, and doctor cannot observe it. When an available
|
||||
provider relies on a setting that a registration's file does not record, or
|
||||
records with other text, doctor adds a non-blocking
|
||||
`registration_environment:<client>` check with `classification: "unknown"`. The
|
||||
|
||||
@@ -188,7 +188,7 @@ and during shutdown.
|
||||
property value remains available in `properties`.
|
||||
- **Device paths are not host paths.** `base_apk_device_path` values live on
|
||||
the device filesystem. Only pulls and captures produce host-local paths,
|
||||
with byte size and SHA-256 digest on success. A pulled file's host name is
|
||||
each paired with byte size and SHA-256 digest. A pulled file's host name is
|
||||
the device path's final POSIX segment. REA preserves the original device
|
||||
path and filename; a missing final segment or `.`/`..` is refused before
|
||||
output creation. Windows hosts follow [Windows filename rules](https://learn.microsoft.com/en-us/windows/win32/fileio/naming-a-file),
|
||||
@@ -249,10 +249,6 @@ and during shutdown.
|
||||
- Pull and capture outputs are additive: the destination must not already
|
||||
exist. Re-running a completed pull refuses the existing directory instead
|
||||
of overwriting evidence.
|
||||
- If a single-file pull fails and REA observes a regular file at the destination,
|
||||
the error includes its `local_path` with `transfer_status: "unconfirmed"`
|
||||
and `digest_status: "unknown"`. The file remains in place; the receipt does
|
||||
not establish that the transfer completed.
|
||||
- Cancellation during a package pull preserves caller-selected output. The
|
||||
error includes partial observations identifying completed artifacts and the
|
||||
interrupted local path; remaining APKs were not attempted.
|
||||
|
||||
@@ -90,20 +90,9 @@ column limit. The selected database is readable and is not reported as
|
||||
malformed; request fewer columns per call instead. `row_limit`
|
||||
requires `table`, defaults to 20 and accepts positive safe integers. Samples
|
||||
remain subject to the byte and worker resource limits below, regardless of row count. The result reports
|
||||
the selected limit, returned count and whether more rows were observed.
|
||||
|
||||
Rows are read in a stated unique order reported as `rows.order`: `rowid` for
|
||||
rowid tables, and `primary_key` for `WITHOUT ROWID` tables, reusing the
|
||||
primary-key index's own direction and declared collation. `rows.row_offset`
|
||||
reports the rows skipped before the window and `rows.next_row_offset` the offset
|
||||
to request for the following page; it is `null` once the window reaches the end.
|
||||
Pass `row_offset` (CLI `--row-offset`, requires `table`, default 0) to skip into
|
||||
a table rather than repeating earlier rows. A table that declares all of
|
||||
`rowid`, `_rowid_` and `oid` as columns and has no primary key reports
|
||||
`order: "unspecified"` and refuses a non-zero `row_offset`, because the skipped
|
||||
prefix would be arbitrary. Pages compose only while the reported database and
|
||||
WAL SHA-256 match; re-inspecting a changed snapshot restarts the sequence.
|
||||
View, virtual-table and shadow-table row reads are unsupported.
|
||||
the selected limit, returned count and whether more rows were observed. Row
|
||||
order is unspecified; a truncated sample does not prove anything about omitted
|
||||
records. View, virtual-table and shadow-table row reads are unsupported.
|
||||
|
||||
SQLite integers are decimal strings so every signed 64-bit value survives JSON
|
||||
serialization. Real values retain their numbers; `"Infinity"`, `"-Infinity"`
|
||||
|
||||
@@ -265,9 +265,6 @@ retained arrays and counters without invoking application iterators or Array
|
||||
species.
|
||||
|
||||
Listener-chain recognition distinguishes owned, unowned and unknown metadata.
|
||||
Only a directly owned wrapper establishes hook dispatch. An application's data
|
||||
link to an owned wrapper remains unknown: `.listener` can name that wrapper
|
||||
without invoking it.
|
||||
Data links may be inherited; absence is established only after completing the
|
||||
bounded prototype lookup. Exhausting either walk, encountering a getter or seeing a Proxy leaves
|
||||
ownership unknown. The hook preserves native registration without adding another
|
||||
|
||||
@@ -50,9 +50,6 @@ A path-filtered reference reports the caller-selected path while keeping its
|
||||
shared node identity. Item selection also accepts any retained path when it
|
||||
identifies one module; if several module kinds share that path, select the
|
||||
reported `node_id`. Node-ID selection uses the stable representative path.
|
||||
Exported symbol bindings reuse the `javascript-module` kind but name one export
|
||||
of their owning module, so module pages, items, and summary counts include only
|
||||
module units and an exported module never becomes an extra path candidate.
|
||||
|
||||
## Retained module facts
|
||||
|
||||
|
||||
@@ -86,11 +86,6 @@ properties and remains readable without migration.
|
||||
|
||||
## Select sources before analysis
|
||||
|
||||
Explicit `source_paths` retain the acquisition owner's requested order, including
|
||||
selected dependency files. First-party priority applies only to unscoped analysis.
|
||||
Recovered syntax or incomplete semantic examination keeps Electron coverage
|
||||
partial even when useful windows or IPC facts were retained.
|
||||
|
||||
For a question about known entry sources, supply exact artifact-relative file
|
||||
paths in `source_paths`, or repeat `--source-path` on either CLI route:
|
||||
|
||||
@@ -328,12 +323,6 @@ failure does not authorize expanding relationships that parent admission decline
|
||||
|
||||
## What is reconstructed
|
||||
|
||||
Electron `BrowserView` and `WebContentsView` expose `webContents` and accept
|
||||
`webPreferences`, including declared preloads. `BaseWindow` has neither surface
|
||||
of its own. Preload associations retain the parsed constructor's mechanism rather
|
||||
than labeling every view as a BrowserWindow. These are static associations, not
|
||||
proof that a renderer or preload executed.
|
||||
|
||||
The projector reuses the content-addressed artifact inventory and safe artifact
|
||||
readers. It retains canonical artifact-relative paths, exact byte counts,
|
||||
SHA-256 digests, inventory IDs, ASAR container identity, and `.asar.unpacked`
|
||||
@@ -526,25 +515,6 @@ If fingerprint construction reaches its structural
|
||||
bound, the fingerprint is unavailable and its status is `truncated`; a bounded
|
||||
prefix is never presented as a complete stable fingerprint.
|
||||
|
||||
## Cached-data compilation boundaries
|
||||
|
||||
The [feature specification](../../specs/javascript/v8-cached-data/spec.md) defines
|
||||
the static admission and uncertainty contract.
|
||||
|
||||
A `node:vm` compilation reports whether `cachedData` is declared, absent or
|
||||
unknown. Explicitly supplied undefined bytes are treated as absent; shadowed
|
||||
identifiers remain declarations. Source syntax alone does not establish valid cache bytes, V8 acceptance
|
||||
or execution. The summary counts declared compilations, not executions.
|
||||
|
||||
A proven synchronous filesystem read or awaited promise-based read supplies a
|
||||
cache path. The producer retains its path base: source-directory expressions
|
||||
can name inventoried artifacts, while relative literal paths depend on the
|
||||
target working directory and remain unresolved. Other supplied values retain
|
||||
their bounded source expression. Declared paths, exact-file lookup
|
||||
status, candidate paths and resolution limitations remain separate; an unresolved
|
||||
path never becomes a resolved file. Opaque inventoried cache bytes can remain
|
||||
unavailable to the JavaScript resolver even when their occurrence is known.
|
||||
|
||||
## Authority and unknowns
|
||||
|
||||
API identity is a derivation: a familiar method or property name does not
|
||||
|
||||
@@ -1,121 +0,0 @@
|
||||
# V8 code cache inspection
|
||||
|
||||
`inspect_v8_code_cache` reads one explicitly selected V8 code cache container as static
|
||||
bytes: a bytenode `.jsc`, the bytes `vm.Script.createCachedData()` writes, or a cache
|
||||
carried inside a Node single-executable application or an Electron app. It never executes
|
||||
the file, never starts a V8 runtime, never installs bytenode, and never invokes a
|
||||
decompiler.
|
||||
|
||||
```bash
|
||||
rea inspect-v8-code-cache /absolute/path/to/module.jsc --json
|
||||
rea inspect-v8-code-cache /absolute/path/to/module.jsc --minStringBytes 8 --json
|
||||
```
|
||||
|
||||
The MCP tool is `inspect_v8_code_cache` with the same inputs and the same retained
|
||||
Evidence.
|
||||
|
||||
## What is read
|
||||
|
||||
A V8 code cache is a producer-written container, not a documented file format. This reader
|
||||
admits one container shape and reports everything else as an observation, so a build it
|
||||
has never seen still yields facts instead of a false parse.
|
||||
|
||||
The 32-byte header is eight little-endian 32-bit words. Every word is reported in
|
||||
`header.fields` with its byte offset, its observed value, the role this reader believes it
|
||||
has, and how confident that role is:
|
||||
|
||||
| Offset | Role | Status |
|
||||
| -------------- | -------------- | ----------- |
|
||||
| `0x00` | magic | confirmed |
|
||||
| `0x04` | version hash | inferred |
|
||||
| `0x08` | source length | confirmed |
|
||||
| `0x0c` | flag hash | inferred |
|
||||
| `0x10` | build constant | inferred |
|
||||
| `0x14` | payload length | confirmed |
|
||||
| `0x18`, `0x1c` | reserved | unconfirmed |
|
||||
|
||||
`confirmed` means the role is demonstrated by the reader's own tests against the producer.
|
||||
`inferred` means the word's behaviour is consistent with the role but a different producer
|
||||
could plausibly differ. `unconfirmed` means the word is reported and nothing more is
|
||||
claimed.
|
||||
|
||||
Only three facts gate admission:
|
||||
|
||||
1. the header size this reader pins (32 bytes);
|
||||
2. the V8 code cache magic high half, `0xc0de`. The low half is
|
||||
`ExternalReferenceTable::kSize` and varies per V8 build, so it is reported as a build
|
||||
fingerprint and never required to match a fixed value;
|
||||
3. the declared payload length must equal the bytes that follow the header exactly.
|
||||
|
||||
`header.source_length` is the producer's recorded source length in UTF-16 code units.
|
||||
V8's serializer calls this field the source hash; on the producers measured here its value
|
||||
equals the source length exactly, including sources whose UTF-8 byte length differs, so the
|
||||
reader reports it under the name the measurement supports. Treat that name as an
|
||||
observation, not as a claim about what any other build stores there.
|
||||
`header.producer` names the producer family from the flag bits in that word. Bit 29
|
||||
marks `vm.compileFunction` (`compile_function`); bit 30 marks `vm.SourceTextModule`
|
||||
(`module`). When neither flag is present, the producer remains `unknown`:
|
||||
`vm.Script`, bytenode output and older unflagged function caches cannot be
|
||||
separated by those bits alone. The source-length mask is `0x1fffffff`, so both
|
||||
flags sit outside the reported length. This describes the admitted header
|
||||
profile rather than a version-independent V8 ABI.
|
||||
|
||||
## Failed inspection and provenance
|
||||
|
||||
After a stable read completes, format and observation-budget refusals retain a
|
||||
`file-snapshot-hash` partial observation with the selected path, exact SHA-256 and
|
||||
byte count. This proves which bytes were read; it does not claim the format was
|
||||
successfully decoded. A refusal before read completion does not invent an identity.
|
||||
Descriptor cleanup remains owned for retry if finalization fails.
|
||||
|
||||
## Embedded byte patterns
|
||||
|
||||
`embedded_strings` lists printable runs found in the payload, each with its absolute byte
|
||||
offset in the selected file and its observed byte length. `min_string_bytes` (default 4)
|
||||
sets the shortest reported run; `max_strings` caps how many may be reported, and exceeding
|
||||
it fails without partial success.
|
||||
|
||||
These are **byte-pattern observations inside serialized V8 heap data, not parsed heap
|
||||
objects**. A reported run is not proof V8 retained it as a string. A literal that is absent
|
||||
from the payload is not proof it is absent from the program: V8 may encode a string in a
|
||||
form the run scan does not surface, and a string can be produced at runtime rather than
|
||||
retained.
|
||||
|
||||
A run longer than 4096 bytes is reported with `truncated: true` and a `retained_bytes`
|
||||
prefix.
|
||||
|
||||
## Limitations
|
||||
|
||||
Every result states these, and they are part of the contract:
|
||||
|
||||
- the payload is serialized V8 heap data, not source; no logic is recovered and no
|
||||
bytecode is decompiled;
|
||||
- recovering logic needs a version-pinned V8 decompiler (View8-style) that this tool
|
||||
neither provides nor depends on;
|
||||
- header roles beyond magic, source length, and payload length are version-dependent
|
||||
observations;
|
||||
- the tool never executes the selected file and never claims recovered source.
|
||||
|
||||
## Failure behaviour
|
||||
|
||||
An unknown magic is a typed `unsupported_target` failure, because the file is not a V8
|
||||
code cache. A short header, a payload-length disagreement, or bytes past the declared
|
||||
payload is a typed `invalid_request` failure. Neither is a partial parse, and no Evidence
|
||||
is recorded for them.
|
||||
|
||||
`max_file_bytes` (default 32 MiB, ceiling 64 MiB) is the caller-selected read budget. The
|
||||
payload SHA-256 is computed over the declared payload, so two containers with the same
|
||||
payload length and content but different version hashes have different whole-file digests
|
||||
and identical payload digests.
|
||||
|
||||
## Relationship to other tools
|
||||
|
||||
- `inspect_binary_layout` reads the surrounding ELF/PE container of a single-executable
|
||||
application; it does not decode the embedded code cache.
|
||||
- A cache embedded in a Node single-executable application or an Electron app must be
|
||||
**extracted first**: this reader admits a container whose magic is at byte zero, so
|
||||
passing the surrounding ELF/PE executable here returns `unsupported_target`. Run
|
||||
`extract_artifact` on the application, then pass the extracted `.jsc` path to this tool.
|
||||
- `inspect_artifact` inventories the file without decoding V8 structures.
|
||||
- This tool is in the same family as `inspect_python_pyc`, `inspect_erlang_beam`, and
|
||||
`inspect_kernel_module`: one explicit local file, bounded parsing, no execution.
|
||||
@@ -212,9 +212,13 @@ rea inspect-managed-members /absolute/path/Assembly.dll --type Namespace.Type \
|
||||
bundle format. Its parent directory must exist, and it never replaces an
|
||||
existing path. Relative paths resolve against the command's working directory.
|
||||
The option also works with complete delivery when a saved bundle is useful.
|
||||
Summary without a destination is rejected before analysis. For partial Evidence
|
||||
and committed-file receipts after failure or cancellation, see
|
||||
[Evidence publication and source recovery](../../reference/mcp-contracts.md#evidence-publication-and-source-recovery).
|
||||
Summary without a destination is rejected before analysis. A publication failure
|
||||
returns a typed error with the completed Evidence under
|
||||
`details.partial_observation`; it does not report successful summary delivery.
|
||||
Cancellation before publication prevents the new output. Once atomic
|
||||
publication has started, it can complete despite cancellation; a cancelled
|
||||
delivery then retains the committed path and byte count under
|
||||
`details.diagnostics.evidence_bundle`.
|
||||
|
||||
Copy `normalized_result.parent_evidence_id` from the summary into the
|
||||
`source.evidence_id` field of the `managed-members` request above, then save that
|
||||
|
||||
@@ -272,12 +272,6 @@ regular files only and rejects symbolic links.
|
||||
|
||||
## Byte entropy triage
|
||||
|
||||
Entropy admission preserves the caller's spelling in `caller_input_path`. On
|
||||
Windows, the selected regular file's case-only filesystem spelling is used
|
||||
consistently in committed paths through both CLI and MCP. Symlink, junction and
|
||||
short-name aliases are not replaced with a different path. General path
|
||||
normalization remains lexical and does not probe source-discovered paths.
|
||||
|
||||
`inspect_byte_entropy` / `inspect-byte-entropy` profiles any local regular file
|
||||
without an analysis engine, execution, extraction or network access.
|
||||
|
||||
|
||||
@@ -332,10 +332,6 @@ crashed run can be recovered by the next run. Failed descriptor or staging clean
|
||||
could not be written or read, for example on a full disk, the export stops with
|
||||
an error instead of decompiling the rest. Files and records already committed
|
||||
stay, `decompile-index.json` is still written, and a later resume continues.
|
||||
If the index was published before cancellation or a later failure, the error's
|
||||
`diagnostics.published_output` retains its `output_directory` and `index_path`.
|
||||
This receipt confirms publication, not completion of every selected function.
|
||||
Failed staging cleanup retains the same receipt through cleanup retry.
|
||||
|
||||
Type inspection selects one exact database pathname or typed data address.
|
||||
Struct/union fields, enums, pointers, arrays, typedefs, size, alignment, packing
|
||||
@@ -1135,9 +1131,6 @@ original JSON scalar types. Values that JSON cannot represent faithfully,
|
||||
including unsafe integers, negative zero and non-finite numbers, remain null
|
||||
with a path-specific gap and incomplete capture coverage. Null alone does not
|
||||
establish that an accessibility value was successfully read or absent.
|
||||
Failed role, title, value or action reads add a path-specific gap and mark the
|
||||
capture truncated. An empty `actions` array with an action-read gap means the
|
||||
available actions are unknown.
|
||||
|
||||
An initial PID or window mismatch is `invalid_request` on `pid` or
|
||||
`window_id` and leaves provider availability intact. A selected window that
|
||||
|
||||
@@ -1,94 +0,0 @@
|
||||
# Windows Shell Link shortcuts
|
||||
|
||||
`inspect_windows_shortcut` / `inspect-windows-shortcut` answers whether one
|
||||
selected local file is a Windows Shell Link (`.lnk`), which target path,
|
||||
arguments, working directory, and icon location it records, which volume and
|
||||
network names `LinkInfo` stores, and which ExtraData blocks follow the
|
||||
strings. It reads the file without resolving or executing the target and does
|
||||
not require a Windows SDK, COM, or a network.
|
||||
|
||||
```bash
|
||||
rea inspect-windows-shortcut /absolute/path/to/shortcut.lnk --json
|
||||
```
|
||||
|
||||
The CLI resolves relative paths against the caller's working directory. MCP
|
||||
and the advertised input schema require an absolute filesystem path and
|
||||
preserve that exact selection:
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "inspect_windows_shortcut",
|
||||
"arguments": { "path": "/artifacts/shortcut.lnk" }
|
||||
}
|
||||
```
|
||||
|
||||
## Observations
|
||||
|
||||
The inline Evidence result contains the artifact path, SHA-256, and byte
|
||||
length. `header` is the 76-byte `ShellLinkHeader`: `LinkFlags` and
|
||||
`FileAttributes` as raw values plus documented names, creation/access/write
|
||||
FILETIMEs as a raw 64-bit decimal and ISO-8601 UTC when the timestamp is in
|
||||
range, file size, icon index, `ShowCommand` (`normal`, `maximized`, or
|
||||
`minimized`), and hotkey modifiers. Undocumented `ShowCommand` values are
|
||||
decoded as `normal`, as specified.
|
||||
|
||||
`id_list` is present when `HasLinkTargetIDList` is set. Each item keeps its
|
||||
file offset, size, and type byte. Root-folder, volume, and file-entry items
|
||||
are decoded when those layouts match documented shell-item headers, including
|
||||
the 8.3 short name on a file entry. Every other item is `raw` with a SHA-256
|
||||
of its payload. Unknown items are not guessed.
|
||||
|
||||
`link_info` reports volume drive type, serial, label, local base path, and
|
||||
common network relative link names, with Unicode variants when the header
|
||||
declares them. ANSI strings use a byte-preserving Latin1 projection; the
|
||||
original system ANSI code page is unobserved.
|
||||
|
||||
`string_data` reports name, relative path, working directory, command-line
|
||||
arguments, and icon location according to `LinkFlags`, each with encoding,
|
||||
`CountCharacters`, byte length, and the decoded value. `IsUnicode` selects
|
||||
UTF-16LE; otherwise the Latin1 projection is used.
|
||||
|
||||
`extra_data` enumerates every block: signature, size, and offset.
|
||||
`EnvironmentVariableDataBlock` and `IconEnvironmentDataBlock` expose ANSI and
|
||||
Unicode targets. `TrackerDataBlock` exposes the NetBIOS machine id and droid /
|
||||
birth-droid GUIDs. Version-1 UUID MAC and timestamp values are labelled
|
||||
`evidence_kind: "derived"`. `KnownFolderDataBlock` and `SpecialFolderDataBlock`
|
||||
keep their folder identifiers. `ConsoleFEDataBlock` keeps the code page.
|
||||
`PropertyStoreDataBlock` and unrecognized signatures stay raw with SHA-256.
|
||||
Unknown signatures are listed and are not dropped.
|
||||
|
||||
`observations` are derived only from those documented fields: whether
|
||||
arguments are present, argument character length, target extension, whether
|
||||
`ShowCommand` is minimized, and whether the icon location differs from the
|
||||
recorded target path. That comparison is `null` unless the icon and a recorded
|
||||
target are both full paths: a stored filename, relative path, or `%VAR%` form
|
||||
cannot show that two locations differ. This workflow does not emit verdicts
|
||||
about intent.
|
||||
|
||||
A missing optional section is observed absence of that structure. It is not
|
||||
proof the shortcut never carried that data in another container.
|
||||
|
||||
## Limits and failures
|
||||
|
||||
The selected file is limited to 1 MiB by default (16 MiB maximum). At most 256
|
||||
IDList items (4096 maximum) and 64 ExtraData blocks (1024 maximum) are
|
||||
examined by default. Retained string payload bytes across StringData,
|
||||
LinkInfo, and ExtraData are limited to 64 KiB by default (1 MiB maximum).
|
||||
Malformed `HeaderSize` or `LinkCLSID`, and exhausted budgets, fail without
|
||||
partial success. Truncation after a valid header, ExtraData size overruns, and
|
||||
odd Unicode lengths return partial coverage with `coverage.failing_offset`.
|
||||
A LinkInfo offset that points outside its structure is reported at the
|
||||
offset field itself, so every issue offset lies inside the file.
|
||||
Coverage is never `complete` when issues are present.
|
||||
|
||||
The selected path must be a regular file. Symbolic links are rejected.
|
||||
UNC paths and other host-prefixed device paths, such as `\\server\share\a.lnk`
|
||||
and `\\?\UNC\server\share\a.lnk`, are rejected before any filesystem call. On
|
||||
Windows, a path whose parent directory is a symbolic link or junction is
|
||||
rejected before anything follows that link. The check covers the directories
|
||||
Windows opens after removing `.` and `..`, so `C:\alias\..\real\a.lnk` is
|
||||
checked at `C:\real` only; a `\\?\` path is checked as written. A mapped
|
||||
network drive cannot be told apart from a local drive by its path and is not
|
||||
rejected.
|
||||
This workflow does not resolve, open, or execute the link target or call COM,
|
||||
and it does not contact a network for a path on a local volume.
|
||||
@@ -97,18 +97,6 @@ process observations under a shared comparison contract. It reports observed
|
||||
differences with their locations, while residual unknowns or truncated
|
||||
observations prevent a complete-equivalence claim. Matching scenario
|
||||
commitments do not reveal whether redacted sensitive inputs were equal.
|
||||
The MCP tool accepts each complete capture inline or as an exact
|
||||
`{"kind":"retained-evidence","evidence_id":"ev_..."}` reference to capture
|
||||
Evidence already retained by the current session.
|
||||
|
||||
Capture-local observer timing remains in Evidence for provenance, but scheduler
|
||||
and observation latency alone do not make behavior changed: terminal,
|
||||
interaction-dispatch, settlement/finalization, process-sample, and filesystem
|
||||
checkpoint times are excluded from the default semantic equality projection.
|
||||
To make a timing value part of the question, supply a `trace_spec` whose exact
|
||||
event includes that field. Semantic fields such as output, interaction outcome,
|
||||
exit status, finalization delivery, process identity/command, and filesystem
|
||||
contents still participate in the default comparison.
|
||||
|
||||
For scenarios where independent scheduling can change event order, the CLI
|
||||
also accepts an optional trace-specification JSON file as the third argument.
|
||||
@@ -520,9 +508,8 @@ a representability limit, not a timer limit. The nominal lifecycle budget is tha
|
||||
sum; polling, snapshotting and cleanup lie outside it. Scenario `events` keep
|
||||
being dispatched during finalization and are recorded as usual. `finalization_ms`
|
||||
of `0`, the default, keeps today's behaviour and the committed identity of every
|
||||
existing scenario. `elapsed_ms` and `sent_at_ms` are retained timing provenance
|
||||
like `settlement.elapsed_ms`. The default semantic comparison excludes these
|
||||
capture-local times; an exact trace event can assert them explicitly.
|
||||
existing scenario. `elapsed_ms` and `sent_at_ms` are timing data and take part in
|
||||
exit comparison like `settlement.elapsed_ms`.
|
||||
|
||||
Every capture requires `truncation_details`, with separate accounting for:
|
||||
|
||||
|
||||
@@ -357,11 +357,7 @@ entire property and its sidecars; a `scope: "property-name"` redaction points
|
||||
to its actual parent. No substitute property name or child pointer is invented.
|
||||
Omitted subtrees are still validated, including canonical HAR base64. Explicitly sensitive artifact
|
||||
paths are empty in Evidence and omitted from locations, while the original
|
||||
SHA-256 and size remain available unless the digest itself is explicitly excluded.
|
||||
CLI [caller-selected paths](../../reference/mcp-contracts.md#caller-selected-paths)
|
||||
are excluded independently: a sensitive capture spelling can be omitted while a
|
||||
safe `descriptor_set_path` remains, and a safe relative spelling can remain even
|
||||
when its resolved parent path is sensitive. Failure messages, diagnostics and cleanup
|
||||
SHA-256 and size remain available unless the digest itself is explicitly excluded. Failure messages, diagnostics and cleanup
|
||||
resources follow the same explicit declarations without changing error types;
|
||||
sensitive issue pointers identify a real ancestor instead of a fabricated
|
||||
coordinate. Header/cookie authentication values and known
|
||||
|
||||
@@ -24,13 +24,6 @@ This validates the embedded bundle, not the rest of the snapshot container.
|
||||
|
||||
## Configure
|
||||
|
||||
Doctor uses the selected client's effective registration environment. An
|
||||
unresolved setting that affects the probe keeps readiness unknown rather than
|
||||
falling back to the terminal account. Kuna's home-based cache fallback includes
|
||||
`USERPROFILE` when `HOME` is absent; an explicit cache root or a selected nonempty
|
||||
`HOME` makes that fallback irrelevant. These home settings are probe dependencies
|
||||
and are not persisted as ambient provider registration settings.
|
||||
|
||||
```bash
|
||||
export REA_KUNA_COMMAND=/absolute/path/to/kuna
|
||||
rea doctor --provider kuna
|
||||
|
||||
@@ -267,7 +267,7 @@ profile stages before retrying their retained descriptors.
|
||||
| Function identity | Every function result carries the entry address and Ghidra FunctionManager classification for external, thunk, and resolved thunk target. These are observations, not proof that unresolved targetless calls have been recovered. |
|
||||
| Assembly and pseudocode | Assembly is complete Ghidra Listing text; pseudocode is Ghidra decompiler output. Neither is original source, and cross-provider comparison never treats Hopper and Ghidra text as equal or unequal semantic facts. |
|
||||
| Instruction fast path | `read_function_instructions` returns every raw Listing instruction for the requested function without invoking the decompiler or whole-program name/string inventories. |
|
||||
| Calls and references | Callers/callees contain only resolved functions. Reference edges preserve exact ReferenceManager type and call/jump/data/read/write/indirect/computed/conditional/terminal/external facts. Targetless computed flow remains unknown. A computed call's recorded targets stay observed callees, but they are static candidates rather than an exhaustive set, so callee coverage is `partial` and names those call sites. Synthetic entry-point references without actionable memory sources are omitted explicitly. |
|
||||
| Calls and references | Callers/callees contain only resolved functions. Reference edges preserve exact ReferenceManager type and call/jump/data/read/write/indirect/computed/conditional/terminal/external facts. Targetless computed flow remains unknown. Synthetic entry-point references without actionable memory sources are omitted explicitly. |
|
||||
| CFG | Dossiers use `BasicBlockModel` and retain only non-call successors inside the function body. CFG topology is address-normalized for comparison; provider-specific block construction remains a declared difference. |
|
||||
| P-code value flow | Function dossiers include up to 3,000 high-p-code operations, at most 64 inputs per operation, and 12,000 def-use edges. Results identify memory reads/writes, branches, and calls by p-code opcode, and mark decompiler-dead operations. Large results report truncation, an omitted-operation lower bound, and known omitted-input/edge counts. The dossier is an intra-function graph; `trace_native_values` composes derived parameter/argument and return/output dependencies across resolved calls. It does not resolve memory aliasing, call side effects, runtime behavior, persistent state, or business meaning. |
|
||||
| Result extent | Function instruction scans and native API boundary observations remain complete. P-code flow is the explicit bounded exception; its count fields distinguish exact retained counts from lower-bound or known-omitted counts. Caller cancellation and provider failures remain distinct. |
|
||||
|
||||
@@ -233,7 +233,7 @@ admits it explicitly. Raw-binary and GameCube DOL targets are refused; open
|
||||
them with Ghidra. Admission is not verification: the real workflows under
|
||||
[Verification](#verification) cover x86_64 and arm64 only.
|
||||
|
||||
All profiles support procedure/string inventory and literal or regex search, procedure resolution, pseudocode, assembly, raw function instructions, resolved callees, incoming address references, and a function dossier. Inventories and modern pseudocode/assembly follow upstream pagination. Upstream limits on modern xrefs and callees are retained as explicit truncation limitations. In the modern headless profile, targets that are not proven x86-only use processor-neutral `callgraph` edges instead of the x86 instruction checks in upstream `callees` (mrexodia/ida-pro-mcp#549). REA requests depth zero: the pinned upstream emits the root's outgoing edges without scanning child functions, then REA batches function-name lookup for those addresses. The graph covers recognized function destinations only; imports and other non-function targets remain unknown. A server without `callgraph` returns an empty relationship list with an explicit coverage limitation. Neither `callees` nor `callgraph` reports the call sites behind its edges, so a computed call's targets are never established as exhaustive; callee coverage is therefore `partial` even for an uncapped reply, and a call path that does not reach its goal remains `unknown`. Graph and path workflows retain those limitations alongside observed edges. A failed or inconsistent graph reply remains an error. A transport-level truncated preview is rejected rather than reported as complete evidence; the error preserves upstream retrieval guidance.
|
||||
All profiles support procedure/string inventory and literal or regex search, procedure resolution, pseudocode, assembly, raw function instructions, resolved callees, incoming address references, and a function dossier. Inventories and modern pseudocode/assembly follow upstream pagination. Upstream limits on modern xrefs and callees are retained as explicit truncation limitations. In the modern headless profile, targets that are not proven x86-only use processor-neutral `callgraph` edges instead of the x86 instruction checks in upstream `callees` (mrexodia/ida-pro-mcp#549). REA requests depth zero: the pinned upstream emits the root's outgoing edges without scanning child functions, then REA batches function-name lookup for those addresses. The graph covers recognized function destinations only; imports and other non-function targets remain unknown. A server without `callgraph` returns an empty relationship list with an explicit coverage limitation. Graph and path workflows retain those limitations alongside observed edges. A failed or inconsistent graph reply remains an error. A transport-level truncated preview is rejected rather than reported as complete evidence; the error preserves upstream retrieval guidance.
|
||||
|
||||
All profiles expose `list_documents` as the single target admitted for the session. Attached mode verifies its digest against IDA metadata before returning it; headless mode binds the digest-checked private input. `inspect_address_context`, `trace_feature`, and `binary_overview` can therefore resolve that identity without upstream document-listing tools. Segment enumeration is optional: when the selected profile cannot provide it, `binary_overview` still returns document and procedure/string counts and omits `segments` and `segment_count`; omission means unobserved, not empty. The modern headless profile also supports `resolve_containing_procedure`. An address resolves through upstream `lookup_funcs` to the canonical entry of the function that contains it; the body stays unavailable like other IDA identities. When no function contains it, REA reads the database-scoped minimal `survey_binary` and reports `not_in_procedure` for an address inside one of its segments (ends are exclusive) and `outside_segments` otherwise. A missing, truncated or inconsistent survey fails the read instead of guessing a reason. `trace_feature` marks a trace truncated, with a residual unknown for that address, when upstream caps the references it returned. Attached profiles do not declare address containment resolution.
|
||||
|
||||
|
||||
@@ -157,7 +157,6 @@ npx rea-agents@latest setup
|
||||
| بنية ELF دون تشغيل | الأقسام والمقاطع والرموز ومعلومات إعادة التموضع الأصلية، وآليات الحماية المحتملة المستدلّ عليها بالفحص الثابت | pwntools يوفّره المستدعي على Linux x64؛ [تشخيص الملفات الثنائية](../guides/native/binary-diagnostics.md) |
|
||||
| PE certificates | Authenticode WIN_CERTIFICATE entries and PKCS#7 signer/X.509 identity fields | Built-in static PE inspection; [PE certificates](../pe-certificates.md) |
|
||||
| PE imports | Import and delay-load DLL names, ordinals, IAT RVAs and pefile import hash | Built-in static PE inspection; [PE imports](../pe-imports.md) |
|
||||
| Windows shortcuts | Shell Link target, arguments, working dir, ExtraData and Tracker droid facts | Built-in static LNK inspection; [Windows shortcuts](../guides/native/windows-shortcut.md) |
|
||||
| شيفرة EVM البايتية | محددات التوجيه، وإزاحات البايتات، والمعاملات المستنتجة، وقابلية تغيير الحالة | مدخل محلي يحمل بايتات خامًا أو تمثيلًا سداسيًا عشريًا على Linux x64؛ [دليل EVM دون تشغيل](../guides/evm/evm-bytecode.md) |
|
||||
| Rust binaries | Embedded cargo-auditable dependency list | [Rust binaries](../rust-binaries.md) |
|
||||
| ELF notes | PT_NOTE/SHT_NOTE owners, types, GNU build-id and ABI-tag fields | Built-in static ELF inspection; [ELF notes](../elf-notes.md) |
|
||||
|
||||
@@ -157,7 +157,6 @@ REA benötigt Node.js 22.x (>=22.23.4), 24.x (>=24.22.1) oder 26+ (>=26.12.1) so
|
||||
| Offline-ELF-Struktur | Sektionen, Segmente, ursprüngliche Symbole/Relokationen und mögliche Schutzmaßnahmen aus statischer Analyse | Vom Aufrufer bereitgestelltes pwntools unter Linux x64; [Binärdiagnostik](../guides/native/binary-diagnostics.md) |
|
||||
| PE certificates | Authenticode WIN_CERTIFICATE entries and PKCS#7 signer/X.509 identity fields | Built-in static PE inspection; [PE certificates](../pe-certificates.md) |
|
||||
| PE imports | Import and delay-load DLL names, ordinals, IAT RVAs and pefile import hash | Built-in static PE inspection; [PE imports](../pe-imports.md) |
|
||||
| Windows shortcuts | Shell Link target, arguments, working dir, ExtraData and Tracker droid facts | Built-in static LNK inspection; [Windows shortcuts](../guides/native/windows-shortcut.md) |
|
||||
| EVM-Bytecode | Dispatch-Selektoren, Byte-Offsets, abgeleitete Argumente und Veränderbarkeit des Zustands | Lokale Eingabe mit Rohbytes oder Hexdarstellung unter Linux x64; [Offline-EVM-Leitfaden](../guides/evm/evm-bytecode.md) |
|
||||
| Rust binaries | Embedded cargo-auditable dependency list | [Rust binaries](../rust-binaries.md) |
|
||||
| ELF notes | PT_NOTE/SHT_NOTE owners, types, GNU build-id and ABI-tag fields | Built-in static ELF inspection; [ELF notes](../elf-notes.md) |
|
||||
|
||||
@@ -159,7 +159,6 @@ npx rea-agents@latest setup
|
||||
| Δυαδικά αρχεία Rust | Ενσωματωμένα ονόματα, εκδόσεις, πηγές και σχέσεις εξάρτησης των crates από το cargo-auditable | Ενσωματωμένη στατική εξέταση ELF/PE/thin Mach-O· [δυαδικά αρχεία Rust](../rust-binaries.md) |
|
||||
| PE certificates | Authenticode WIN_CERTIFICATE entries and PKCS#7 signer/X.509 identity fields | Built-in static PE inspection; [PE certificates](../pe-certificates.md) |
|
||||
| PE imports | Import and delay-load DLL names, ordinals, IAT RVAs and pefile import hash | Built-in static PE inspection; [PE imports](../pe-imports.md) |
|
||||
| Windows shortcuts | Shell Link target, arguments, working dir, ExtraData and Tracker droid facts | Built-in static LNK inspection; [Windows shortcuts](../guides/native/windows-shortcut.md) |
|
||||
| ELF notes | PT_NOTE/SHT_NOTE owners, types, GNU build-id and ABI-tag fields | Built-in static ELF inspection; [ELF notes](../elf-notes.md) |
|
||||
| Binary hardening | PIE, NX, RELRO, CFG and related header flags for ELF, PE and Mach-O | Built-in static header inspection; [binary hardening](../binary-hardening.md) |
|
||||
| Apple IPS crashes | .ips metadata, threads, images, registers and crash classes | Built-in static JSON inspection; [Apple IPS](../apple-ips.md) |
|
||||
|
||||
@@ -157,7 +157,6 @@ REA requiere Node.js 22.x (>=22.23.4), 24.x (>=24.22.1) o 26+ (>=26.12.1), adem
|
||||
| Estructura ELF sin ejecutar | Secciones, segmentos, símbolos/reubicaciones originales y posibles medidas de mitigación detectadas mediante análisis estático | pwntools proporcionado por quien llama, en Linux x64; [diagnóstico de binarios](../guides/native/binary-diagnostics.md) |
|
||||
| PE certificates | Authenticode WIN_CERTIFICATE entries and PKCS#7 signer/X.509 identity fields | Built-in static PE inspection; [PE certificates](../pe-certificates.md) |
|
||||
| PE imports | Import and delay-load DLL names, ordinals, IAT RVAs and pefile import hash | Built-in static PE inspection; [PE imports](../pe-imports.md) |
|
||||
| Windows shortcuts | Shell Link target, arguments, working dir, ExtraData and Tracker droid facts | Built-in static LNK inspection; [Windows shortcuts](../guides/native/windows-shortcut.md) |
|
||||
| Bytecode EVM | Selectores de despacho, desplazamientos en bytes, argumentos inferidos y mutabilidad | Entrada local con bytes sin procesar o representación hexadecimal, en Linux x64; [guía de EVM sin ejecutar](../guides/evm/evm-bytecode.md) |
|
||||
| Rust binaries | Embedded cargo-auditable dependency list | [Rust binaries](../rust-binaries.md) |
|
||||
| ELF notes | PT_NOTE/SHT_NOTE owners, types, GNU build-id and ABI-tag fields | Built-in static ELF inspection; [ELF notes](../elf-notes.md) |
|
||||
|
||||
@@ -149,7 +149,6 @@ REA به Node.js 22.x (>=22.23.4)، 24.x (>=24.22.1) یا 26+ (>=26.12.1)، به
|
||||
| ساختار ELF آفلاین | بخشها، سگمنتها، نمادها و relocationهای اصلی و گزینههای احتمالی کاهش آسیبپذیری ایستا | pwntools تأمینشده توسط فراخواننده روی Linux x64؛ [تشخیص باینری](../guides/native/binary-diagnostics.md) |
|
||||
| PE certificates | Authenticode WIN_CERTIFICATE entries and PKCS#7 signer/X.509 identity fields | Built-in static PE inspection; [PE certificates](../pe-certificates.md) |
|
||||
| PE imports | Import and delay-load DLL names, ordinals, IAT RVAs and pefile import hash | Built-in static PE inspection; [PE imports](../pe-imports.md) |
|
||||
| Windows shortcuts | Shell Link target, arguments, working dir, ExtraData and Tracker droid facts | Built-in static LNK inspection; [Windows shortcuts](../guides/native/windows-shortcut.md) |
|
||||
| بایتکد EVM | selectorهای dispatch، offsetهای بایتی، آرگومانهای استنباطشده و قابلیت تغییر وضعیت | دادهٔ خام/hex محلی روی Linux x64؛ [راهنمای EVM آفلاین](../guides/evm/evm-bytecode.md) |
|
||||
| Rust binaries | Embedded cargo-auditable dependency list | [Rust binaries](../rust-binaries.md) |
|
||||
| ELF notes | PT_NOTE/SHT_NOTE owners, types, GNU build-id and ABI-tag fields | Built-in static ELF inspection; [ELF notes](../elf-notes.md) |
|
||||
|
||||
@@ -156,7 +156,6 @@ REA nécessite Node.js 22.x (>=22.23.4), 24.x (>=24.22.1) ou 26+ (>=26.12.1), ai
|
||||
| Structure ELF hors ligne | Sections, segments, symboles et relocations d'origine, et protections statiques candidates | pwntools fourni par l'utilisateur sous Linux x64 ; [diagnostics binaires](../guides/native/binary-diagnostics.md) |
|
||||
| PE certificates | Authenticode WIN_CERTIFICATE entries and PKCS#7 signer/X.509 identity fields | Built-in static PE inspection; [PE certificates](../pe-certificates.md) |
|
||||
| PE imports | Import and delay-load DLL names, ordinals, IAT RVAs and pefile import hash | Built-in static PE inspection; [PE imports](../pe-imports.md) |
|
||||
| Windows shortcuts | Shell Link target, arguments, working dir, ExtraData and Tracker droid facts | Built-in static LNK inspection; [Windows shortcuts](../guides/native/windows-shortcut.md) |
|
||||
| Artefact WASM | Validation, sections, formes WAT exactes d'import/export et WAT décodé | WABT 1.0.42 fourni par l'utilisateur ; `inspect_wasm_artifact` |
|
||||
| Bytecode EVM | Sélecteurs de dispatch, offsets en octets, arguments inférés et mutabilité | Fichier local brut ou hexadécimal sous Linux x64 ; [guide EVM hors ligne](../guides/evm/evm-bytecode.md) |
|
||||
| Rust binaries | Embedded cargo-auditable dependency list | [Rust binaries](../rust-binaries.md) |
|
||||
|
||||
@@ -159,7 +159,6 @@ Alat tambahan dan dukungan sistem host bergantung pada target yang dianalisis:
|
||||
| Tata letak ELF offline | Bagian, segmen, simbol/relokasi asli, dan kandidat mitigasi statis | pwntools yang disediakan pemanggil pada Linux x64; [diagnostik biner](../guides/native/binary-diagnostics.md) |
|
||||
| PE certificates | Authenticode WIN_CERTIFICATE entries and PKCS#7 signer/X.509 identity fields | Built-in static PE inspection; [PE certificates](../pe-certificates.md) |
|
||||
| PE imports | Import and delay-load DLL names, ordinals, IAT RVAs and pefile import hash | Built-in static PE inspection; [PE imports](../pe-imports.md) |
|
||||
| Windows shortcuts | Shell Link target, arguments, working dir, ExtraData and Tracker droid facts | Built-in static LNK inspection; [Windows shortcuts](../guides/native/windows-shortcut.md) |
|
||||
| Artefak WASM | Validasi, bagian, bentuk WAT import/ekspor yang tepat, dan WAT yang didekode | WABT 1.0.42 yang disediakan pemanggil; `inspect_wasm_artifact` |
|
||||
| Bytecode EVM | Selector dispatch, offset byte, argumen yang disimpulkan, dan sifat mutabilitas | Pembawa data raw/hex lokal di Linux x64; [panduan EVM offline](../guides/evm/evm-bytecode.md) |
|
||||
| Rust binaries | Embedded cargo-auditable dependency list | [Rust binaries](../rust-binaries.md) |
|
||||
|
||||
@@ -156,7 +156,6 @@ REA richiede Node.js 22.x (>=22.23.4), 24.x (>=24.22.1) o 26+ (>=26.12.1), oltre
|
||||
| Layout ELF offline | Sezioni, segmenti, simboli/relocazioni originali e candidati mitigazioni statiche | pwntools fornito dal chiamante su Linux x64; [diagnostica binaria](../guides/native/binary-diagnostics.md) |
|
||||
| PE certificates | Authenticode WIN_CERTIFICATE entries and PKCS#7 signer/X.509 identity fields | Built-in static PE inspection; [PE certificates](../pe-certificates.md) |
|
||||
| PE imports | Import and delay-load DLL names, ordinals, IAT RVAs and pefile import hash | Built-in static PE inspection; [PE imports](../pe-imports.md) |
|
||||
| Windows shortcuts | Shell Link target, arguments, working dir, ExtraData and Tracker droid facts | Built-in static LNK inspection; [Windows shortcuts](../guides/native/windows-shortcut.md) |
|
||||
| Artefatto WASM | Convalida, sezioni, forme WAT di import/export esatte e WAT decodificato | WABT 1.0.42 fornito dal chiamante; `inspect_wasm_artifact` |
|
||||
| Bytecode EVM | Selettori di dispatch, offset dei byte, argomenti inferiti e mutabilità | Carrier raw/hex locale su Linux x64; [guida EVM offline](../guides/evm/evm-bytecode.md) |
|
||||
| Rust binaries | Embedded cargo-auditable dependency list | [Rust binaries](../rust-binaries.md) |
|
||||
|
||||
@@ -157,7 +157,6 @@ REA には Node.js 22.x(>=22.23.4)、24.x(>=24.22.1)、または 26+ (>=
|
||||
| オフライン ELF レイアウト | セクション、セグメント、元のシンボル/再配置情報、静的解析によるセキュリティ対策の候補 | Linux x64 で利用者が用意する pwntools;[バイナリ診断](../guides/native/binary-diagnostics.md) |
|
||||
| PE certificates | Authenticode WIN_CERTIFICATE entries and PKCS#7 signer/X.509 identity fields | Built-in static PE inspection; [PE certificates](../pe-certificates.md) |
|
||||
| PE imports | Import and delay-load DLL names, ordinals, IAT RVAs and pefile import hash | Built-in static PE inspection; [PE imports](../pe-imports.md) |
|
||||
| Windows shortcuts | Shell Link target, arguments, working dir, ExtraData and Tracker droid facts | Built-in static LNK inspection; [Windows shortcuts](../guides/native/windows-shortcut.md) |
|
||||
| EVM バイトコード | ディスパッチセレクター、バイトオフセット、推定された引数と状態変更の可否 | Linux x64 上のローカルの生バイト/16 進数の入力ファイル;[オフライン EVM ガイド](../guides/evm/evm-bytecode.md) |
|
||||
| Rust binaries | Embedded cargo-auditable dependency list | [Rust binaries](../rust-binaries.md) |
|
||||
| ELF notes | PT_NOTE/SHT_NOTE owners, types, GNU build-id and ABI-tag fields | Built-in static ELF inspection; [ELF notes](../elf-notes.md) |
|
||||
|
||||
@@ -159,7 +159,6 @@ REA에는 Node.js 22.x(>=22.23.4), 24.x(>=24.22.1) 또는 26+ (>=26.12.1)와 npm
|
||||
| Rust 바이너리 | cargo-auditable이 내장한 크레이트 이름, 버전, 소스, 의존성 관계 | REA 내장 ELF/PE/thin Mach-O 정적 검사; [Rust 바이너리](../rust-binaries.md) |
|
||||
| PE certificates | Authenticode WIN_CERTIFICATE entries and PKCS#7 signer/X.509 identity fields | Built-in static PE inspection; [PE certificates](../pe-certificates.md) |
|
||||
| PE imports | Import and delay-load DLL names, ordinals, IAT RVAs and pefile import hash | Built-in static PE inspection; [PE imports](../pe-imports.md) |
|
||||
| Windows shortcuts | Shell Link target, arguments, working dir, ExtraData and Tracker droid facts | Built-in static LNK inspection; [Windows shortcuts](../guides/native/windows-shortcut.md) |
|
||||
| ELF notes | PT_NOTE/SHT_NOTE owners, types, GNU build-id and ABI-tag fields | Built-in static ELF inspection; [ELF notes](../elf-notes.md) |
|
||||
| Binary hardening | PIE, NX, RELRO, CFG and related header flags for ELF, PE and Mach-O | Built-in static header inspection; [binary hardening](../binary-hardening.md) |
|
||||
| Apple IPS crashes | .ips metadata, threads, images, registers and crash classes | Built-in static JSON inspection; [Apple IPS](../apple-ips.md) |
|
||||
|
||||
@@ -159,7 +159,6 @@ REA-യ്ക്ക് Node.js 22.x (>=22.23.4), 24.x (>=24.22.1), അല്ല
|
||||
| Rust binaries | ഉൾച്ചേർത്ത cargo-auditable crate പേരുകൾ, versions, sources, dependency edges | Built-in static ELF/PE/thin Mach-O പരിശോധന; [Rust binaries](../rust-binaries.md) |
|
||||
| PE certificates | Authenticode WIN_CERTIFICATE entries and PKCS#7 signer/X.509 identity fields | Built-in static PE inspection; [PE certificates](../pe-certificates.md) |
|
||||
| PE imports | Import and delay-load DLL names, ordinals, IAT RVAs and pefile import hash | Built-in static PE inspection; [PE imports](../pe-imports.md) |
|
||||
| Windows shortcuts | Shell Link target, arguments, working dir, ExtraData and Tracker droid facts | Built-in static LNK inspection; [Windows shortcuts](../guides/native/windows-shortcut.md) |
|
||||
| ELF notes | PT_NOTE/SHT_NOTE owners, types, GNU build-id and ABI-tag fields | Built-in static ELF inspection; [ELF notes](../elf-notes.md) |
|
||||
| Binary hardening | PIE, NX, RELRO, CFG and related header flags for ELF, PE and Mach-O | Built-in static header inspection; [binary hardening](../binary-hardening.md) |
|
||||
| Linux kernel modules | .modinfo keys, __versions CRCs, this_module presence, and signature trailer | Built-in static ELF inspection; [kernel modules](../kernel-modules.md) |
|
||||
|
||||
@@ -157,7 +157,6 @@ REA wymaga Node.js 22.x (>=22.23.4), 24.x (>=24.22.1) lub 26+ (>=26.12.1) oraz n
|
||||
| Układ pliku ELF w trybie offline | Sekcje, segmenty, oryginalne symbole/relokacje i potencjalne mechanizmy zabezpieczeń wskazane przez analizę statyczną | pwntools dostarczone przez użytkownika w systemie Linux x64; [diagnostyka plików binarnych](../guides/native/binary-diagnostics.md) |
|
||||
| PE certificates | Authenticode WIN_CERTIFICATE entries and PKCS#7 signer/X.509 identity fields | Built-in static PE inspection; [PE certificates](../pe-certificates.md) |
|
||||
| PE imports | Import and delay-load DLL names, ordinals, IAT RVAs and pefile import hash | Built-in static PE inspection; [PE imports](../pe-imports.md) |
|
||||
| Windows shortcuts | Shell Link target, arguments, working dir, ExtraData and Tracker droid facts | Built-in static LNK inspection; [Windows shortcuts](../guides/native/windows-shortcut.md) |
|
||||
| Kod bajtowy EVM | Selektory wywołań, przesunięcia bajtowe, wywnioskowane argumenty i mutowalność | Lokalny plik z surowymi bajtami lub zapisem szesnastkowym w systemie Linux x64; [przewodnik EVM offline](../guides/evm/evm-bytecode.md) |
|
||||
| Rust binaries | Embedded cargo-auditable dependency list | [Rust binaries](../rust-binaries.md) |
|
||||
| ELF notes | PT_NOTE/SHT_NOTE owners, types, GNU build-id and ABI-tag fields | Built-in static ELF inspection; [ELF notes](../elf-notes.md) |
|
||||
|
||||
@@ -157,7 +157,6 @@ O REA requer Node.js 22.x (>=22.23.4), 24.x (>=24.22.1) ou 26+ (>=26.12.1), alé
|
||||
| Estrutura ELF sem execução | Seções, segmentos, símbolos/relocações originais e possíveis mecanismos de mitigação identificados por análise estática | pwntools fornecido pelo chamador no Linux x64; [diagnóstico de binários](../guides/native/binary-diagnostics.md) |
|
||||
| PE certificates | Authenticode WIN_CERTIFICATE entries and PKCS#7 signer/X.509 identity fields | Built-in static PE inspection; [PE certificates](../pe-certificates.md) |
|
||||
| PE imports | Import and delay-load DLL names, ordinals, IAT RVAs and pefile import hash | Built-in static PE inspection; [PE imports](../pe-imports.md) |
|
||||
| Windows shortcuts | Shell Link target, arguments, working dir, ExtraData and Tracker droid facts | Built-in static LNK inspection; [Windows shortcuts](../guides/native/windows-shortcut.md) |
|
||||
| Bytecode EVM | Seletores de despacho, offsets de bytes, argumentos inferidos e mutabilidade | Entrada local com bytes brutos ou representação hexadecimal no Linux x64; [guia de EVM sem execução](../guides/evm/evm-bytecode.md) |
|
||||
| Rust binaries | Embedded cargo-auditable dependency list | [Rust binaries](../rust-binaries.md) |
|
||||
| ELF notes | PT_NOTE/SHT_NOTE owners, types, GNU build-id and ABI-tag fields | Built-in static ELF inspection; [ELF notes](../elf-notes.md) |
|
||||
|
||||
@@ -199,7 +199,6 @@ Uneltele suplimentare și platformele acceptate depind de ținta analizată:
|
||||
| Fișiere binare Rust | Nume, versiuni, surse și relații de dependență ale pachetelor crate încorporate prin cargo-auditable | Inspectare statică integrată a fișierelor ELF/PE/Mach-O cu o singură arhitectură; [binare Rust](../rust-binaries.md) |
|
||||
| Certificate PE | Intrări Authenticode WIN_CERTIFICATE și câmpuri de identitate ale semnatarilor PKCS#7 și certificatelor X.509 | Inspectare statică integrată a fișierelor PE; [certificate PE](../pe-certificates.md) |
|
||||
| Importuri PE | Numele DLL-urilor importate și încărcate întârziat, ordinale, RVA-uri ale IAT și hash-ul importurilor calculat de pefile | Inspectare statică integrată a fișierelor PE; [importuri PE](../pe-imports.md) |
|
||||
| Scurtături Windows | Țintă Shell Link, argumente, director de lucru, ExtraData și identificatori Tracker | Inspectare statică integrată a fișierelor LNK; [scurtături Windows](../guides/native/windows-shortcut.md) |
|
||||
| Note ELF | Proprietari și tipuri PT_NOTE/SHT_NOTE, câmpuri GNU build-id și ABI-tag | Inspectare statică integrată a fișierelor ELF; [note ELF](../elf-notes.md) |
|
||||
| Întărire binară | PIE, NX, RELRO, CFG și indicatori de antet pentru ELF, PE și Mach-O | Inspecție statică integrată a antetelor; [întărire binară](../binary-hardening.md) |
|
||||
| Rapoarte Apple IPS de eroare fatală | Metadate .ips, fire de execuție, imagini binare, registre și clase documentate de erori fatale | Inspectare statică integrată a datelor JSON; [Apple IPS](../apple-ips.md) |
|
||||
|
||||
@@ -159,7 +159,6 @@ REA требует Node.js 22.x (>=22.23.4), 24.x (>=24.22.1) или 26+ (>=26.1
|
||||
| Rust binaries | Embedded cargo-auditable dependency list | [Rust binaries](../rust-binaries.md) |
|
||||
| PE certificates | Authenticode WIN_CERTIFICATE entries and PKCS#7 signer/X.509 identity fields | Built-in static PE inspection; [PE certificates](../pe-certificates.md) |
|
||||
| PE imports | Import and delay-load DLL names, ordinals, IAT RVAs and pefile import hash | Built-in static PE inspection; [PE imports](../pe-imports.md) |
|
||||
| Windows shortcuts | Shell Link target, arguments, working dir, ExtraData and Tracker droid facts | Built-in static LNK inspection; [Windows shortcuts](../guides/native/windows-shortcut.md) |
|
||||
| ELF notes | PT_NOTE/SHT_NOTE owners, types, GNU build-id and ABI-tag fields | Built-in static ELF inspection; [ELF notes](../elf-notes.md) |
|
||||
| Binary hardening | PIE, NX, RELRO, CFG and related header flags for ELF, PE and Mach-O | Built-in static header inspection; [binary hardening](../binary-hardening.md) |
|
||||
| Linux kernel modules | .modinfo keys, __versions CRCs, this_module presence, and signature trailer | Built-in static ELF inspection; [kernel modules](../kernel-modules.md) |
|
||||
|
||||
@@ -157,7 +157,6 @@ REA ต้องใช้ Node.js 22.x (>=22.23.4), 24.x (>=24.22.1) หรื
|
||||
| โครงสร้าง ELF แบบออฟไลน์ | เซกชัน เซกเมนต์ สัญลักษณ์/รีโลเคชันต้นฉบับ และตัวเลือกกลไกป้องกันที่พบจากการวิเคราะห์แบบสถิต | pwntools ที่ผู้ใช้จัดเตรียมบน Linux x64; [การวินิจฉัยไบนารี](../guides/native/binary-diagnostics.md) |
|
||||
| PE certificates | Authenticode WIN_CERTIFICATE entries and PKCS#7 signer/X.509 identity fields | Built-in static PE inspection; [PE certificates](../pe-certificates.md) |
|
||||
| PE imports | Import and delay-load DLL names, ordinals, IAT RVAs and pefile import hash | Built-in static PE inspection; [PE imports](../pe-imports.md) |
|
||||
| Windows shortcuts | Shell Link target, arguments, working dir, ExtraData and Tracker droid facts | Built-in static LNK inspection; [Windows shortcuts](../guides/native/windows-shortcut.md) |
|
||||
| ไบต์โค้ด EVM | ตัวเลือกฟังก์ชันสำหรับการเรียก ออฟเซ็ตไบต์ อาร์กิวเมนต์และความสามารถในการเปลี่ยนสถานะที่อนุมานได้ | ไฟล์บนเครื่องที่มีไบต์ดิบหรือข้อมูลเลขฐานสิบหกบน Linux x64; [คู่มือ EVM แบบออฟไลน์](../guides/evm/evm-bytecode.md) |
|
||||
| Rust binaries | Embedded cargo-auditable dependency list | [Rust binaries](../rust-binaries.md) |
|
||||
| ELF notes | PT_NOTE/SHT_NOTE owners, types, GNU build-id and ABI-tag fields | Built-in static ELF inspection; [ELF notes](../elf-notes.md) |
|
||||
|
||||
@@ -157,7 +157,6 @@ REA; Node.js 22.x (>=22.23.4), 24.x (>=24.22.1) veya 26+ (>=26.12.1) ve npm gere
|
||||
| Rust ikili dosyaları | Gömülü cargo-auditable crate adları, sürümleri, kaynakları ve bağımlılık ilişkileri | Yerleşik statik ELF/PE/thin Mach-O incelemesi; [Rust ikili dosyaları](../rust-binaries.md) |
|
||||
| PE certificates | Authenticode WIN_CERTIFICATE entries and PKCS#7 signer/X.509 identity fields | Built-in static PE inspection; [PE certificates](../pe-certificates.md) |
|
||||
| PE imports | Import and delay-load DLL names, ordinals, IAT RVAs and pefile import hash | Built-in static PE inspection; [PE imports](../pe-imports.md) |
|
||||
| Windows shortcuts | Shell Link target, arguments, working dir, ExtraData and Tracker droid facts | Built-in static LNK inspection; [Windows shortcuts](../guides/native/windows-shortcut.md) |
|
||||
| ELF notes | PT_NOTE/SHT_NOTE owners, types, GNU build-id and ABI-tag fields | Built-in static ELF inspection; [ELF notes](../elf-notes.md) |
|
||||
| Binary hardening | PIE, NX, RELRO, CFG and related header flags for ELF, PE and Mach-O | Built-in static header inspection; [binary hardening](../binary-hardening.md) |
|
||||
| Apple IPS crashes | .ips metadata, threads, images, registers and crash classes | Built-in static JSON inspection; [Apple IPS](../apple-ips.md) |
|
||||
|
||||
@@ -157,7 +157,6 @@ REA потребує Node.js 22.x (>=22.23.4), 24.x (>=24.22.1) або 26+ (>=26
|
||||
| Структура ELF без запуску | Секції, сегменти, початкові символи/релокації та можливі захисні механізми за даними статичного аналізу | pwntools, наданий стороною, що викликає інструмент, у Linux x64; [діагностика бінарних файлів](../guides/native/binary-diagnostics.md) |
|
||||
| PE certificates | Authenticode WIN_CERTIFICATE entries and PKCS#7 signer/X.509 identity fields | Built-in static PE inspection; [PE certificates](../pe-certificates.md) |
|
||||
| PE imports | Import and delay-load DLL names, ordinals, IAT RVAs and pefile import hash | Built-in static PE inspection; [PE imports](../pe-imports.md) |
|
||||
| Windows shortcuts | Shell Link target, arguments, working dir, ExtraData and Tracker droid facts | Built-in static LNK inspection; [Windows shortcuts](../guides/native/windows-shortcut.md) |
|
||||
| Байт-код EVM | Селектори диспетчеризації, зміщення байтів, виведені припущення про аргументи та змінюваність стану | Локальні необроблені байти або шістнадцяткове представлення у Linux x64; [посібник EVM без запуску](../guides/evm/evm-bytecode.md) |
|
||||
| Rust binaries | Embedded cargo-auditable dependency list | [Rust binaries](../rust-binaries.md) |
|
||||
| ELF notes | PT_NOTE/SHT_NOTE owners, types, GNU build-id and ABI-tag fields | Built-in static ELF inspection; [ELF notes](../elf-notes.md) |
|
||||
|
||||
@@ -199,7 +199,6 @@ Mazeed tools aur host support target par depend karte hain:
|
||||
| Rust binaries | Embedded cargo-auditable crate names, versions, sources aur dependency edges | Built-in static ELF/PE/thin Mach-O inspection; [Rust binaries](../rust-binaries.md) |
|
||||
| PE certificates | Authenticode WIN_CERTIFICATE entries aur PKCS#7 signer/X.509 identity fields | Built-in static PE inspection; [PE certificates](../pe-certificates.md) |
|
||||
| PE imports | Import aur delay-load DLL names, ordinals, IAT RVAs aur pefile import hash | Built-in static PE inspection; [PE imports](../pe-imports.md) |
|
||||
| Windows shortcuts | Shell Link target, arguments, working dir, ExtraData and Tracker droid facts | Built-in static LNK inspection; [Windows shortcuts](../guides/native/windows-shortcut.md) |
|
||||
| ELF notes | PT_NOTE/SHT_NOTE owners, types, GNU build-id aur ABI-tag fields | Built-in static ELF inspection; [ELF notes](../elf-notes.md) |
|
||||
| Binary hardening | PIE, NX, RELRO, CFG and related header flags for ELF, PE and Mach-O | Built-in static header inspection; [binary hardening](../binary-hardening.md) |
|
||||
| Linux kernel modules | .modinfo keys, __versions CRCs, this_module presence, and signature trailer | Built-in static ELF inspection; [kernel modules](../kernel-modules.md) |
|
||||
|
||||
@@ -159,7 +159,6 @@ REA yêu cầu Node.js 22.x (>=22.23.4), 24.x (>=24.22.1) hoặc 26+ (>=26.12.1)
|
||||
| Rust binaries | Embedded cargo-auditable dependency list | [Rust binaries](../rust-binaries.md) |
|
||||
| PE certificates | Authenticode WIN_CERTIFICATE entries and PKCS#7 signer/X.509 identity fields | Built-in static PE inspection; [PE certificates](../pe-certificates.md) |
|
||||
| PE imports | Import and delay-load DLL names, ordinals, IAT RVAs and pefile import hash | Built-in static PE inspection; [PE imports](../pe-imports.md) |
|
||||
| Windows shortcuts | Shell Link target, arguments, working dir, ExtraData and Tracker droid facts | Built-in static LNK inspection; [Windows shortcuts](../guides/native/windows-shortcut.md) |
|
||||
| ELF notes | PT_NOTE/SHT_NOTE owners, types, GNU build-id and ABI-tag fields | Built-in static ELF inspection; [ELF notes](../elf-notes.md) |
|
||||
| Binary hardening | PIE, NX, RELRO, CFG and related header flags for ELF, PE and Mach-O | Built-in static header inspection; [binary hardening](../binary-hardening.md) |
|
||||
| Linux kernel modules | .modinfo keys, __versions CRCs, this_module presence, and signature trailer | Built-in static ELF inspection; [kernel modules](../kernel-modules.md) |
|
||||
|
||||
@@ -160,7 +160,6 @@ REA 需要 Node.js 22.x(>=22.23.4)、24.x(>=24.22.1)或 26+ (>=26.12.1)
|
||||
| Erlang BEAM | IFF chunks, atoms, exports, and tables | Built-in static BEAM inspection; [Erlang BEAM](../erlang-beam.md) |
|
||||
| PE certificates | Authenticode WIN_CERTIFICATE entries and PKCS#7 signer/X.509 identity fields | Built-in static PE inspection; [PE certificates](../pe-certificates.md) |
|
||||
| PE imports | Import and delay-load DLL names, ordinals, IAT RVAs and pefile import hash | Built-in static PE inspection; [PE imports](../pe-imports.md) |
|
||||
| Windows shortcuts | Shell Link target, arguments, working dir, ExtraData and Tracker droid facts | Built-in static LNK inspection; [Windows shortcuts](../guides/native/windows-shortcut.md) |
|
||||
| ELF notes | PT_NOTE/SHT_NOTE owners, types, GNU build-id and ABI-tag fields | Built-in static ELF inspection; [ELF notes](../elf-notes.md) |
|
||||
| Binary hardening | PIE, NX, RELRO, CFG and related header flags for ELF, PE and Mach-O | Built-in static header inspection; [binary hardening](../binary-hardening.md) |
|
||||
| Apple IPS crashes | .ips metadata, threads, images, registers and crash classes | Built-in static JSON inspection; [Apple IPS](../apple-ips.md) |
|
||||
|
||||
@@ -160,7 +160,6 @@ REA 需要 Node.js 22.x(>=22.23.4)、24.x(>=24.22.1)或 26+ (>=26.12.1)
|
||||
| Erlang BEAM | IFF chunks, atoms, exports, and tables | Built-in static BEAM inspection; [Erlang BEAM](../erlang-beam.md) |
|
||||
| PE certificates | Authenticode WIN_CERTIFICATE entries and PKCS#7 signer/X.509 identity fields | Built-in static PE inspection; [PE certificates](../pe-certificates.md) |
|
||||
| PE imports | Import and delay-load DLL names, ordinals, IAT RVAs and pefile import hash | Built-in static PE inspection; [PE imports](../pe-imports.md) |
|
||||
| Windows shortcuts | Shell Link target, arguments, working dir, ExtraData and Tracker droid facts | Built-in static LNK inspection; [Windows shortcuts](../guides/native/windows-shortcut.md) |
|
||||
| ELF notes | PT_NOTE/SHT_NOTE owners, types, GNU build-id and ABI-tag fields | Built-in static ELF inspection; [ELF notes](../elf-notes.md) |
|
||||
| Binary hardening | PIE, NX, RELRO, CFG and related header flags for ELF, PE and Mach-O | Built-in static header inspection; [binary hardening](../binary-hardening.md) |
|
||||
| Apple IPS crashes | .ips metadata, threads, images, registers and crash classes | Built-in static JSON inspection; [Apple IPS](../apple-ips.md) |
|
||||
|
||||
@@ -28,11 +28,6 @@ this effective scope. A claim verifier must commit to its own surfaces and
|
||||
their reachable dependencies, including their artifact and implemented-owner
|
||||
digests. Callers do not need to duplicate the transitive closure in the request.
|
||||
|
||||
Listed `residual_unknown_ids` select unknown identities from the Evidence bundle.
|
||||
The evaluator uses each identity's latest revision: resolved questions do not
|
||||
block the boundary, while reopened questions do. An active, unallowed question
|
||||
retains its cited supporting, contradicting and mutation Evidence in the result.
|
||||
|
||||
## Comparable verifier Evidence
|
||||
|
||||
At least one record explicitly cited by the latest verifier observation must
|
||||
|
||||
@@ -10,9 +10,6 @@ and [session discovery](#identity-and-discovery). See [transports](#transports)
|
||||
for the opt-in HTTP listener, [cancellation](#progress-and-cancellation)
|
||||
for partial-result recovery and [first-query deadlines](#ghidra-first-query-deadlines-and-recovery)
|
||||
when a cold provider exceeds the client's wait.
|
||||
The shared [caller-path](#caller-selected-paths) and
|
||||
[publication](#evidence-publication-and-source-recovery) fields also apply to CLI
|
||||
Evidence.
|
||||
|
||||
## Tool results
|
||||
|
||||
@@ -224,7 +221,7 @@ graph, while `search_scope.discovery` describes whether discovery of applicable
|
||||
direct relationships is established. A missing goal is `unknown` when either
|
||||
discovery or a relationship read is unestablished. A found path is shortest
|
||||
within the observed graph; undiscovered calls may produce a shorter path.
|
||||
`truncated` describes relationship reads, not unestablished discovery. Ghidra's recorded incoming references do not establish every computed caller; computed outgoing candidates likewise retain unknown callee discovery. IDA function-edge replies retain their observed truncation status while unclassified call targets remain unknown in discovery.
|
||||
`truncated` describes relationship reads, not unestablished discovery.
|
||||
`build_call_path` applies the same distinction to supplied function Evidence:
|
||||
its `search_scope.exhaustive` describes the supplied graph and
|
||||
`search_scope.observed_status` preserves that graph's result. Evidence without
|
||||
@@ -522,23 +519,6 @@ that buffer. It does not raise REA's reserved single-string limit, which is
|
||||
raise that Node ceiling. It does not change analysis coverage or retained
|
||||
content. Ordinary responses keep their existing complete result contract.
|
||||
|
||||
### Caller-selected paths
|
||||
|
||||
Evidence can include `caller_input_path` for the verbatim primary selection and
|
||||
`caller_input_paths` for named auxiliary selections. Each auxiliary value is a
|
||||
string or an ordered array of strings; repeated selections preserve order and
|
||||
duplicates. Consumers must accept both forms.
|
||||
|
||||
These fields record request provenance outside semantic Evidence identity.
|
||||
They do not replace the inspected identity in `subject` or prove format validity.
|
||||
One-shot binary CLI requests retain relative spelling and symlink aliases;
|
||||
provider inspections also keep the established `parameters.input_path` field.
|
||||
|
||||
Older records and workflows without a caller-path binding omit these fields.
|
||||
A workflow's explicit sensitive-value policy can exclude primary and auxiliary
|
||||
spellings independently; do not infer a missing primary from an auxiliary value.
|
||||
See [capture redaction](../guides/web/web-network-captures.md) for its policy.
|
||||
|
||||
### Input validation resource allowance
|
||||
|
||||
Both HTTP and stdio admit at most 1,024 combined array elements and object
|
||||
@@ -1376,9 +1356,11 @@ uses `cleanup_incomplete` and lists only the owned resource kinds that remain.
|
||||
Once those owners confirm cleanup, composed failures recover their original
|
||||
typed primary outcome and recovery guidance. Historical composition diagnostics
|
||||
remain in `details.cleanup_history`, separate from the primary diagnostics.
|
||||
For written Evidence and snapshot outcomes, use the
|
||||
[publication receipt](#evidence-publication-and-source-recovery) separately from
|
||||
cleanup status.
|
||||
An atomic Evidence bundle or snapshot write can publish its complete output
|
||||
before staging cleanup fails. In that case, `details.published: true`,
|
||||
`details.published_path`, and `details.bytes` retain the publication receipt.
|
||||
Use that receipt to distinguish completed publication from a write that never
|
||||
committed. Staging resources remain owned until cleanup is verified.
|
||||
Native call tracing and process capture retain available observations in
|
||||
`details.partial_observation` on failure, including when cleanup succeeds.
|
||||
The observation reports its partial coverage; cleanup details describe host
|
||||
@@ -1450,46 +1432,6 @@ through provider cleanup, including repeated delivery by package runners.
|
||||
Existing controlled-process cleanup and provider shutdown rules still apply;
|
||||
REA never kills a process it cannot prove it owns.
|
||||
|
||||
### Evidence publication and source recovery
|
||||
|
||||
An atomic Evidence bundle or snapshot write can commit before later cancellation
|
||||
or staging cleanup failure. Cancellation observed before publication leaves the
|
||||
destination unchanged; once publication has started, the owning operation can
|
||||
complete it.
|
||||
Inspect the returned receipt before retrying or replacing output:
|
||||
|
||||
| Outcome | Receipt |
|
||||
| ----------------------------------------------------------------------- | -------------------------------------------------------------------------- |
|
||||
| Evidence or snapshot publication committed, then staging cleanup failed | `details.published: true`, `details.published_path`, and `details.bytes` |
|
||||
| CLI Evidence delivery cancelled after its bundle committed | `details.diagnostics.evidence_bundle` with the written path and byte count |
|
||||
|
||||
Receipt paths can be omitted when unavailable or explicitly excluded. A missing
|
||||
path alone does not establish that publication failed.
|
||||
|
||||
A publication failure can retain completed Evidence in
|
||||
`details.partial_observation`. The receipt confirms written output, not that
|
||||
cleanup succeeded or every analysis stage completed. Staging resources remain
|
||||
owned until cleanup is verified. Other output kinds use their own contracts,
|
||||
such as [environment directory publication](../getting-started/cli.md#export-an-environment-bundle)
|
||||
and [decompile output receipts](../guides/native/native-investigation.md).
|
||||
|
||||
For a requested one-shot Evidence bundle that did not commit, the error can
|
||||
include `details.source_closure` when completed Evidence has source records or
|
||||
links, or source collection failed. `publication` is `not_published`.
|
||||
When collection yields source facts, `records` contains captured Evidence within
|
||||
64 KiB; explicit sensitivity exclusions can withhold all inline records.
|
||||
`omitted` lists up to 64 other identities, and `omitted_count` gives the total:
|
||||
|
||||
- `not_captured`: this invocation has no record to return; its ancestry remains unknown.
|
||||
- `not_inlined`: the record was captured but is outside this bounded response.
|
||||
|
||||
`complete` is true only when source inspection succeeded and every cited record
|
||||
is included or embedded in the observation. On inspection failure,
|
||||
`collection_failure` names the error type and closure stays unknown. Captured
|
||||
records can still be returned, but record and omission fields can be absent if
|
||||
collection itself failed. The original operation failure remains primary.
|
||||
The one-shot process retains nothing after exit; rerunning is a new observation.
|
||||
|
||||
## Request scope and local effects
|
||||
|
||||
Each tool request names the target and lifecycle it will use. Browser calls
|
||||
|
||||
@@ -28,49 +28,23 @@ and the recording and writes the record as Evidence.
|
||||
out of every walk. A start returns once the capture reports the window
|
||||
open; a refused or early-ended start stops the capture and reports its
|
||||
output.
|
||||
- `start_build_capture` takes `state_paths`, at most 16 files or folders in
|
||||
the home, relative to it, after `~/` or absolute, without `..` and not the
|
||||
home itself; the controller resolves each under the computer's home, both
|
||||
as named and with its links followed (a path not there yet through its
|
||||
nearest existing folder), refuses one outside it or in `~/.rea-build`
|
||||
either way before launching anything, and passes each as named to the
|
||||
capture as `--state-path`. A selected file is a document, or the app's own
|
||||
state under a hidden folder of the home as named, before links, or when it
|
||||
is a lock the app holds, such as LibreOffice's `.~lock.<name>#`.
|
||||
- Acknowledgement: `capture-desktop-application` reports, beside each progress
|
||||
message, an `event`: `window_open`; `checkpoint` with its name, trigger,
|
||||
time, entries walked, changes and retained files and bytes, and up to ten
|
||||
changed files, home-relative, those under a selected path first, then
|
||||
those the app held open, caches and browser-engine storage last, with a count
|
||||
of the rest, once it is taken, the baseline, `stop` and `exit` included;
|
||||
and `checkpoint_refused` with the reason. `mark_build_checkpoint` writes
|
||||
`checkpoint <name>` and waits for the event naming it, returning its counts
|
||||
and changed files, both `null` when the REA in the computer predates them
|
||||
and its event leaves them out. Names follow a narrow pattern, without the capture's own
|
||||
names; a name already taken is refused.
|
||||
time, entries walked, changes and retained files and bytes, once it is
|
||||
taken, the baseline, `stop` and `exit` included; and `checkpoint_refused`
|
||||
with the reason. `mark_build_checkpoint` writes `checkpoint <name>` and
|
||||
waits for the event naming it, returning its counts. Names follow a narrow
|
||||
pattern, without the capture's own names; a name already taken is refused.
|
||||
- `stop_build_capture` sends `stop`, waits for the exit status, reads the
|
||||
capture's Evidence and, when `seed` and `end` were acknowledged, runs
|
||||
`describe-desktop-application-task --seed-checkpoint seed --end-checkpoint
|
||||
end` and returns the changed files, their net change and suggested checks.
|
||||
A draft with no files carries `notes`, coded `no_change`,
|
||||
`unowned_changes` (up to five changed home paths with their roles, and a
|
||||
count of the rest), `uncheckable_changes` (dconf databases whose app keys
|
||||
were read and changed, which no check reads, a version kept without its
|
||||
bytes counting as holding none), `unreadable_changes` (dconf
|
||||
databases that changed but could not be read, with the read `error`) and
|
||||
`no_document`; a drafted file whose suggestions are thin carries one
|
||||
naming its `file`, coded `by_position`, `view_state_only`, `long_text`,
|
||||
`cut_view` or `unreadable_view`.
|
||||
- `export_build_environment` writes the agent's task under `~/.rea-build`,
|
||||
runs `export-desktop-application` with it and the same checkpoints into a
|
||||
new folder there, reports a refused task with the export's own reason,
|
||||
lists the bundle with sizes and SHA-256, fetches it through the driver's
|
||||
`data/get` in answers of at most 8 MiB, checks each file and writes the
|
||||
caller's new or empty folder through the safe output tree. The export
|
||||
leaves lock files the app holds while it runs out of the seed, but never a
|
||||
document or selected path, listing them in its limitations and README; a
|
||||
start from a bundle whose computer never gets ready names the files its
|
||||
seed holds by a profile lock's name or as a document lock.
|
||||
caller's new or empty folder through the safe output tree.
|
||||
- `check_build_task` reads the one app's `data/get` through the card's
|
||||
child URL, takes the state views beside its files and evaluates the task's
|
||||
checks with `evaluateTaskChecks`, one result per check. With `stage`, the
|
||||
|
||||
@@ -280,123 +280,6 @@ taken 18, 23 and 21 turns for $0.70, $1.55 and $0.51 ($0.92). Cache reads
|
||||
fell from 585-714K tokens to 181-225K; the cost is mostly cache writes,
|
||||
which varied from 17K to 189K tokens whatever the turns.
|
||||
|
||||
## Naming the app's state
|
||||
|
||||
Run on macOS with source tests and gates; no build computer was started.
|
||||
Each test below failed on the head before this change, with only the tests
|
||||
and their fixtures added, and passes now.
|
||||
|
||||
- `buildCaptureStatePathsMcp.test.ts`: `start_build_capture` with
|
||||
`state_paths` passes the note's path to the capture as `--state-path`, the
|
||||
draft covers it as a document with no notes, and an export with a check on
|
||||
it is accepted; without it the draft is empty with `unowned_changes`
|
||||
(the note, `unrelated`) and `no_document`, and the export's refusal names
|
||||
`state_paths`. A path through `..`, the home itself and 17 paths are
|
||||
refused by the schema, `/etc/hosts` by the computer, and none starts a
|
||||
capture. Before, `state_paths` was an unknown argument.
|
||||
- `DesktopTaskDraftNotes.test.ts`: a draft with files has no notes; one with
|
||||
no change between seed and end has only `no_change`; one whose changes lie
|
||||
outside the owned paths lists five with their roles, desktop files last,
|
||||
and counts two more, beside `no_document`.
|
||||
- `stateRoles.test.ts`: a selected file under a hidden folder of the home is
|
||||
application state, elsewhere a document.
|
||||
- `DesktopApplicationExport.test.ts`, `appExportUnowned.test.ts`: the export's
|
||||
limitations and README name folders the capture saw change outside the
|
||||
owned paths, collapsed to their top folder and without desktop caches, up
|
||||
to eight and a count, and the seeded lock file, WebKit storage and cache
|
||||
folders.
|
||||
|
||||
## Lock files, changed files and held-open folders
|
||||
|
||||
Run on macOS with source tests and gates; no build computer was started. A
|
||||
hold-out LibreOffice Calc bundle seeded `~/.config/libreoffice/4/.lock` and
|
||||
showed no window at boot; its export also said nothing in `~/Documents` was
|
||||
seeded while `seed_files` held `Documents/q1-sales.ods`. Each test below
|
||||
failed on the head before this change, with only the tests and their
|
||||
fixtures added, and passes now.
|
||||
|
||||
- `DesktopApplicationExport.test.ts`: a capture whose seed holds a profile
|
||||
`.lock` and a document lock `.~lock.today.txt#` exports without either in
|
||||
`seed_files` or the bundle, and lists both after "Left out of the seed" in
|
||||
one limitation and the README; with `~/Documents` held open, its
|
||||
limitation names `~/Documents/today.txt` as seeded from there.
|
||||
- `appExportUnowned.test.ts`: profile, browser and document locks are lock
|
||||
files, and `*.lock` or `*.lck` only in a hidden folder, so `Cargo.lock`
|
||||
and `yarn.lock` in a project are not; the capture's limitation names the
|
||||
held-open folders from `~/`, and the export's names the seed files there
|
||||
or says there are none.
|
||||
- `desktopCapture.test.ts`: a checkpoint's acknowledgement names its changed
|
||||
files home-relative, the held-open document first, then state, then the
|
||||
rest, without folders, and names ten of thirteen with three more.
|
||||
- `buildCaptureMcp.test.ts`: `mark_build_checkpoint` returns the changed
|
||||
files the capture acknowledged.
|
||||
- `buildComputerMcp.test.ts`: a bundle's start that never got ready names
|
||||
the lock files its seed holds; one without locks, or failing otherwise,
|
||||
names none.
|
||||
|
||||
The Linux-only capture test's acknowledgement now expects the changed state
|
||||
file; it is skipped on macOS and was not run.
|
||||
|
||||
## Linked state paths, dconf changes, project lock files and older checkpoint replies
|
||||
|
||||
Run on macOS with source tests and gates; no build computer was started.
|
||||
Each test below failed on the head before this change, with only the tests
|
||||
and their fixtures added, and passes now.
|
||||
|
||||
- `buildCaptureStatePathsMcp.test.ts`: the computer refuses state paths that
|
||||
a link leads out of the home, existing or not yet (through the nearest
|
||||
existing folder, or a dangling link), or into `~/.rea-build`, and starts
|
||||
nothing; a link that stays in the home is followed and the path passed to
|
||||
the capture as named. Before, the first such path started a capture.
|
||||
- `DesktopCaptureScope.test.ts`: the capture scope records each selected
|
||||
path as named beside the physical path it walks.
|
||||
- `DesktopApplicationExport.test.ts`: with `~/.config/MuseScore` selected as
|
||||
a link to `~/settings/MuseScore` beside a selected note, the bundle's
|
||||
launch opens the note. With only the capture's record of selected paths
|
||||
added, the settings file was still a document and the launch opened none.
|
||||
- `DesktopTaskDraftNotes.test.ts`: a draft whose only change between `seed`
|
||||
and `end` is to the app's keys in dconf carries `uncheckable_changes`
|
||||
naming `~/.config/dconf/user`, not `no_change`; one where only another
|
||||
group's keys changed still has `no_change`.
|
||||
- `appExportUnowned.test.ts`: `*.lock` and `*.lck` are locks only directly
|
||||
in a state directory, so `Projects/.repo/Cargo.lock` is not; and 20,000
|
||||
separate unowned folders collapse in tens of milliseconds, where comparing
|
||||
every pair took 12.9 seconds.
|
||||
- `DesktopApplicationExport.test.ts`: `Projects/.repo/Cargo.lock` and
|
||||
`.dotfiles/web/yarn.lock`, which the capture recognized as documents, and
|
||||
a lock-named file the caller selected are seeded, a `*.lock` directly in a
|
||||
state directory is left out, and the profile and document locks still are.
|
||||
- `buildCaptureMcp.test.ts`: checkpoints acknowledged without
|
||||
`changed_files` and `more_changed_files`, as the previous REA in a build
|
||||
computer does, are taken with both `null`, also when a lost reply is read
|
||||
again from the capture's log. Before, the host refused the acknowledgement
|
||||
although the checkpoint was taken.
|
||||
- `desktopCapture.test.ts`: a checkpoint's changed files name a document
|
||||
under a selected path first, though the app did not hold it open, and
|
||||
caches and browser-engine storage last, even one the app held open or in a
|
||||
state directory, so ten KDE service-cache files no longer push the saved
|
||||
document past the cut, as they did in a held-out Tellico build.
|
||||
- `DesktopApplicationExport.test.ts`: with `~/.config/MuseScore` selected as
|
||||
a link to `~/Documents` and the note inside it selected itself, the
|
||||
launch opens the note while the settings beside it stay the app's; before,
|
||||
the link's hidden name made the note application state and the launch
|
||||
opened none.
|
||||
- `DesktopTaskDraftNotes.test.ts`: a dconf database that changed but could
|
||||
not be read gives `unreadable_changes` with the reader's error, not
|
||||
`uncheckable_changes`.
|
||||
- `buildCaptureMcp.test.ts`: `stop_build_capture` on a capture whose only
|
||||
change between `seed` and `end` is a dconf database the draft cannot read
|
||||
(no `dconf` on its `PATH`) returns the `unreadable_changes` note with its
|
||||
`error`; before, the build tool dropped the field.
|
||||
- `LinuxApplicationInventory.test.ts`: the inventory lists KDE's
|
||||
`~/.config/<name>rc` before it exists, so a Tellico capture owns
|
||||
`~/.config/tellicorc`, whose absence brought back Tip of the Day at boot;
|
||||
`DesktopApplicationExport.test.ts` shows such a file, written during the
|
||||
capture, owned and seeded (that test passed before, given the inventory).
|
||||
|
||||
The capture's recording of selected paths runs only on Linux; its scope is
|
||||
tested on macOS, and the capture itself was not run.
|
||||
|
||||
## Limits of this verification
|
||||
|
||||
- The witness acts were scripted by this agent from the task's prompt; no
|
||||
|
||||
@@ -55,9 +55,7 @@ and the bundle holds neither the capture host's name nor its user's.
|
||||
path and content, escapes decoded, for the host name and `user@host`
|
||||
anywhere and the captured home as a whole path, with the replacements set
|
||||
aside. `scrubbed_files` lists the rewritten seeds and `unscrubbed_files`
|
||||
every file found, by bundle path; the README lists both. gzip seeds
|
||||
compressed again only to clear their headers, their documents unchanged,
|
||||
are in `recompressed_files` instead, which the README counts.
|
||||
every file found, by bundle path; the README lists both.
|
||||
- Tasks: checks whose values name `user@host` or the host name by that rule
|
||||
are refused, like those that name the captured home, but not for their
|
||||
field names, kind or id; and the checks that must fail on the seed are
|
||||
|
||||
@@ -68,8 +68,7 @@ folder to build the environment; this step builds nothing.
|
||||
lists candidate state directories under the XDG folders and dot-folders
|
||||
named after the package, executable, desktop entry's full id and last part,
|
||||
and name, and every folder present there whose name is one of those in
|
||||
another letter case, such as GIMP's `~/.config/GIMP`, and KDE's
|
||||
`<name>rc` in the config folder, such as `~/.config/tellicorc`; a `flatpak run`
|
||||
another letter case, such as GIMP's `~/.config/GIMP`; a `flatpak run`
|
||||
launch uses the application id (its first operand
|
||||
after options and their values) instead of the launcher's name and adds
|
||||
`~/.var/app/<id>`. An `--executable` runs from the caller's
|
||||
@@ -79,9 +78,7 @@ folder to build the environment; this step builds nothing.
|
||||
`--state-path` values and absolute arguments other than `/` or a directory
|
||||
containing the home directory, which the limitations name instead, plus the
|
||||
`-wal` and `-journal` paths beside each of those selected paths that is not
|
||||
a directory, so a database selected on its own is captured with its logs.
|
||||
Each selected path is also recorded as named, beside its physical
|
||||
spelling, so a role can follow from the name the caller gave it. The
|
||||
a directory, so a database selected on its own is captured with its logs. The
|
||||
baseline walk runs before launch and retains every file under the content
|
||||
roots; each later checkpoint reports created, modified, deleted and retyped
|
||||
paths against the previous walk and retains every changed file. A creation
|
||||
|
||||
@@ -41,11 +41,7 @@ generation reads the kinds of change.
|
||||
([XML text checks](../xml-text-checks/spec.md)); key files up to 4 MiB
|
||||
whose every line parses; zip archives by
|
||||
their local file header, as their entries with each entry's own format and
|
||||
view ([document views](../document-views/spec.md)); text; binary. A gzip
|
||||
file, told by its magic bytes, is read as the document inside, its members
|
||||
joined, within a zip entry's 16 MiB and 100-times limits, and its version
|
||||
records `compression: "gzip"` beside that document's format; past the
|
||||
limits, or damaged, it has a `view_error`.
|
||||
view ([document views](../document-views/spec.md)); text; binary.
|
||||
- Changes between versions are created, deleted, or lines, values, keys or
|
||||
rows with added, removed and changed lists (100 each, with counts); content
|
||||
for binary files and unreadable when a view is missing. Values are JSON
|
||||
@@ -61,6 +57,5 @@ generation reads the kinds of change.
|
||||
|
||||
- No export, seed selection or task generation.
|
||||
- No parsing of other binary formats (GVDB other than dconf, LevelDB, Realm,
|
||||
protobuf), or of compression other than gzip (xz, Zstandard, bzip2); they
|
||||
are listed as binary.
|
||||
protobuf); they are listed as binary.
|
||||
- No redaction: views contain the user's real data, as the capture does.
|
||||
@@ -21,14 +21,7 @@ never runs code the agent wrote.
|
||||
both ends whose count changed); and a draft task with a placeholder prompt
|
||||
and checks suggested from the net change of documents, or of application
|
||||
state when no document changed. Views are shown only for those files, cut at
|
||||
200 items and 2,000 characters. A draft with no files says why in `notes`:
|
||||
`no_change`, `unowned_changes` with up to five changed home paths and their
|
||||
roles, `uncheckable_changes` with the dconf databases whose application
|
||||
keys were read and changed, `unreadable_changes` with the dconf databases
|
||||
that changed but could not be read and the read `error`, and
|
||||
`no_document`; a drafted file whose suggestions are thin gets one naming
|
||||
its `file`: `by_position`, `view_state_only`, `long_text`, `cut_view` or
|
||||
`unreadable_view`.
|
||||
200 items and 2,000 characters.
|
||||
- The task file is JSON with a portable `name` other than `smoke`, a `prompt`
|
||||
and 1 to 32 `checks`, parsed by a zod schema in `src/domain/desktop/`. Check
|
||||
kinds: `file_present`, `file_absent`, `lines_present`, `lines_absent`,
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
# Implementation plan
|
||||
|
||||
1. Derive VM callable identity and intact option objects from existing semantic
|
||||
owners after mutation indexing; retain unresolved spreads as unknown.
|
||||
2. Retain proven cache reads and their parsed bases through the named worker
|
||||
contract. Resolve only source-directory paths against admitted inventory.
|
||||
3. Project declarations into explicit graph unknowns and compilation summaries,
|
||||
preserving source ranges, unresolved paths and execution limitations.
|
||||
4. Verify negative mutation/spread controls and public filesystem workflows;
|
||||
document runtime qualification separately from static analysis.
|
||||
@@ -1,43 +0,0 @@
|
||||
# V8 cached-data compilation boundaries
|
||||
|
||||
## Analyst question
|
||||
|
||||
Which source-visible Node VM compilation sites declare or may receive cached
|
||||
bytes, and which admitted artifact can be associated with those bytes?
|
||||
|
||||
## Scope and authority
|
||||
|
||||
Static application analysis recognizes member calls to `vm.Script` and
|
||||
`vm.compileFunction` when the shared built-in callable owner establishes their
|
||||
identity. Analysis reads admitted source and inventory only. It does not invoke
|
||||
the target, validate V8 cache bytes, establish cache acceptance, or execute code.
|
||||
Node separates compilation, cache rejection and subsequent execution; see the
|
||||
[Node VM contract](https://nodejs.org/docs/latest-v24.x/api/vm.html).
|
||||
|
||||
## Owning facts
|
||||
|
||||
- Resolve complete callable identity after shared mutation facts settle. ESM
|
||||
default/namespace imports and proven CommonJS bindings use the same owner.
|
||||
Replaced methods do not establish VM authority.
|
||||
- `cached_data_status` is `declared` for an explicit cachedData property,
|
||||
`absent` for proven omission or a proven undefined cache value, and `unknown` for unresolved options or argument
|
||||
spreads that can supply or shift the options position. Declaration does not
|
||||
prove a valid runtime value or successful cache use.
|
||||
- A proven `fs.readFileSync` or awaited `fs/promises.readFile` can identify a
|
||||
cache path. Unawaited promises and unproven readers retain bounded source
|
||||
expressions. A supplied string alone is not proof that a file was read.
|
||||
- Preserve the parsed path base through the worker boundary. Only a proven
|
||||
source-directory base permits an application inventory lookup. Relative
|
||||
literal paths depend on the unknown target working directory; source paths
|
||||
and unresolved expressions stay separate from resolved artifact identity.
|
||||
- Graph cache boundaries remain explicit unknowns with source provenance.
|
||||
Absent sites do not add cache-boundary uncertainty. Summary counts describe
|
||||
declared compilations, never observed executions.
|
||||
|
||||
## Compatibility and verification
|
||||
|
||||
Existing source declarations and inventory remain available. Optional path-base
|
||||
facts may be absent in historical analyses; omission does not prove a base.
|
||||
Public application workflows verify worker serialization, summary and graph
|
||||
projection with local files. No test that merely supplies cache-shaped bytes
|
||||
establishes real V8 acceptance or target execution.
|
||||
@@ -1,10 +0,0 @@
|
||||
# Tasks
|
||||
|
||||
- [x] Model declared, absent and unknown cached-data sites.
|
||||
- [x] Reuse built-in callable and option-object ownership.
|
||||
- [x] Retain synchronous and awaited promise read provenance and path bases.
|
||||
- [x] Carry facts through worker serialization to summary and graph consumers.
|
||||
- [x] Exercise malformed authority, argument spreads and unresolved paths.
|
||||
- [x] Verify public filesystem application workflows and document limitations.
|
||||
|
||||
Real V8 acceptance and execution remain outside this static feature's scope.
|
||||
@@ -1,38 +0,0 @@
|
||||
# Implementation plan
|
||||
|
||||
## Boundary and contract
|
||||
|
||||
Follow the existing binary-diagnostics inspectors. `parseWindowsShortcut` in
|
||||
`src/native/windows/WindowsShortcutParser.ts` owns Shell Link bytes and
|
||||
coverage; `src/domain/native/windowsShortcut.ts` owns the result schema.
|
||||
`WindowsShortcutProvider` (`rea-windows-shortcut`, built in) owns path
|
||||
validation and the stable regular-file read through `readStableArtifact` and
|
||||
`ArtifactResourceScope`. `WindowsShortcutService` owns Evidence provenance with
|
||||
`subject.format: "file"`. The CLI command and MCP tool consume that Evidence
|
||||
and add no interpretation.
|
||||
|
||||
ANSI strings use a byte-preserving Latin1 projection because the original
|
||||
system code page is not observable from the file. `IsUnicode` selects
|
||||
UTF-16LE. Missing optional sections are reported as observed absence only.
|
||||
|
||||
## Incremental work and validation
|
||||
|
||||
1. Define the contract, limits and observations; add failing parser fixtures.
|
||||
2. Implement the parser for the header, IDList, LinkInfo, StringData and
|
||||
ExtraData with budgets and partial coverage.
|
||||
3. Add the provider, service, composition, capability declaration and tool
|
||||
effects; cover cancellation, symlink rejection and finalization cleanup.
|
||||
4. Add the CLI command and MCP tool; cover acceptance and advertisement.
|
||||
5. Update the guide, CLI page, README rows and the authored skill; run focused
|
||||
tests, repository checks and the documentation route build.
|
||||
|
||||
## Effects and compatibility
|
||||
|
||||
The workflow reads one caller-selected local file. It adds no target execution,
|
||||
injection, mutation, protection recovery or network access, so no maintainer
|
||||
scope decision is required. Existing tools and `inspect_artifact` routing are
|
||||
unchanged.
|
||||
|
||||
## References
|
||||
|
||||
- https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-shllink/
|
||||
@@ -1,51 +0,0 @@
|
||||
# Windows Shell Link shortcut inspection
|
||||
|
||||
## Problem and outcome
|
||||
|
||||
REA has no Shell Link reader. An analyst holding a local `.lnk` file cannot ask
|
||||
which target, arguments, working directory, icon location, volume or network
|
||||
names, and ExtraData blocks it records without resolving the target, calling
|
||||
COM or using a Windows host. Add one static inspector that reads a selected
|
||||
local file and returns those facts as inline Evidence.
|
||||
|
||||
## Requirements
|
||||
|
||||
- Add `inspect_windows_shortcut` (MCP) and `inspect-windows-shortcut` (CLI).
|
||||
MCP requires an absolute path; the CLI resolves a relative path against the
|
||||
caller's working directory.
|
||||
- Accept only a regular file. Reject symbolic links, UNC and other
|
||||
host-prefixed device paths before any filesystem call, and on Windows a path
|
||||
whose parent is a symbolic link or junction.
|
||||
- Validate the 76-byte `ShellLinkHeader` (`HeaderSize` `0x4C` and the Shell
|
||||
Link CLSID) and decode `LinkFlags`, `FileAttributes`, FILETIMEs, file size,
|
||||
icon index, `ShowCommand` and hotkey.
|
||||
- Decode `LinkTargetIDList` items whose layouts match documented shell-item
|
||||
headers; keep every other item raw with a SHA-256 of its payload.
|
||||
- Decode `LinkInfo` volume and network names, `StringData` per `LinkFlags`, and
|
||||
enumerate every ExtraData block. Unknown signatures stay raw with SHA-256.
|
||||
Tracker version-1 MAC and timestamp values are labelled derived.
|
||||
- Emit only documented-field observations: argument presence and length,
|
||||
target extension, minimized `ShowCommand`, and whether the icon location
|
||||
differs from a recorded full target path (`null` when not comparable).
|
||||
- Bound file size, IDList items, ExtraData blocks and retained string bytes,
|
||||
with caller-adjustable limits and documented maximums. Honor cancellation.
|
||||
- Never open, resolve or execute the link target, call COM or contact a network
|
||||
for a local-volume path.
|
||||
|
||||
## Acceptance
|
||||
|
||||
Synthesized fixtures cover a hidden-window PowerShell shortcut with an icon
|
||||
mismatch, network-share `LinkInfo`, Tracker version 1, ANSI strings, truncated
|
||||
`StringData`, an unknown ExtraData signature and a wrong CLSID. Malformed
|
||||
headers and exhausted budgets fail without partial success; truncation after a
|
||||
valid header returns partial coverage with `coverage.failing_offset`, and
|
||||
coverage is never `complete` when issues are present. CLI and stdio MCP
|
||||
acceptance, MCP advertisement, filesystem symlink, budget and cancellation
|
||||
boundaries, stable-artifact consumers and native acquisition finalization are
|
||||
covered.
|
||||
|
||||
## Out of scope
|
||||
|
||||
Resolving or launching the target, COM `IShellLink` calls, Windows SDK use,
|
||||
recovering the original system ANSI code page, verdicts about intent, and
|
||||
routing `.lnk` files through `inspect_artifact`.
|
||||
@@ -1,11 +0,0 @@
|
||||
# Tasks
|
||||
|
||||
- [x] Define the single-feature scope, contract, limits and plan.
|
||||
- [x] Parse the header, IDList, LinkInfo, StringData and ExtraData with
|
||||
synthesized fixtures, budgets and partial coverage.
|
||||
- [x] Add the provider, service and Evidence provenance; verify symlink, UNC,
|
||||
budget, cancellation and finalization boundaries.
|
||||
- [x] Add the CLI command and MCP tool; verify acceptance and advertisement.
|
||||
- [x] Document the workflow in the native Windows shortcut guide.
|
||||
- [ ] Verify against real Explorer-written `.lnk` files and non-Latin1 system
|
||||
ANSI code pages.
|
||||
@@ -1,40 +0,0 @@
|
||||
# Plan
|
||||
|
||||
## Shape
|
||||
|
||||
The container format is the only thing this feature knows, so the parser owns it and
|
||||
everything else consumes its facts.
|
||||
|
||||
- `src/domain/v8/v8CodeCache.ts` holds the schema, the bit constants and the bounds, so a
|
||||
reader and a test share one definition of what a container is.
|
||||
- `src/v8/V8CodeCacheParser.ts` decodes a `Buffer` into retained strings and producer
|
||||
facts. It is given bytes only; it never opens a file.
|
||||
- `src/v8/V8CodeCacheProvider.ts` owns the observation budget, the file read and the
|
||||
remediation text. It is the boundary that turns bytes into a reported fact.
|
||||
- `src/cli/v8CodeCacheCommands.ts` and the MCP registration are thin adapters over the
|
||||
provider, so both surfaces report the same facts.
|
||||
|
||||
## Measured premises
|
||||
|
||||
Each of these was measured on Node 24.22.1 before the parser was written, because the
|
||||
container is undocumented and the layout had to be derived rather than assumed:
|
||||
|
||||
- `vm.Script.createCachedData()` writes `0x…|length` for its producer word.
|
||||
- `vm.compileFunction` sets `0x20000000`, and `vm.SourceTextModule` sets `0x40000000`.
|
||||
- The payload retains UTF-8 strings above the threshold, and the retained set grows with
|
||||
the source's literals rather than with the bytecode size.
|
||||
|
||||
## Order
|
||||
|
||||
1. Pin the format in the domain schema so later steps cannot disagree about it.
|
||||
2. Write the parser against the measured producer words.
|
||||
3. Add the provider, the budget and its remediation.
|
||||
4. Expose the CLI command, then the MCP tool, over the same provider.
|
||||
5. Document the command and the report, and link the guide from both indexes.
|
||||
|
||||
## Budget
|
||||
|
||||
The retained-string scan is the only unbounded part of the read, so it is bounded on three
|
||||
axes at once: a maximum string count, a minimum string length, and a maximum artifact size.
|
||||
The provider reports which of the three was reached and whether raising or lowering it is
|
||||
the caller's next step, so a refusal is actionable rather than a bare truncation.
|
||||
@@ -1,58 +0,0 @@
|
||||
# Inspect a V8 code cache container
|
||||
|
||||
## Outcome
|
||||
|
||||
A bytenode `.jsc`, the bytes `vm.Script.createCachedData()` writes, and a code cache
|
||||
carried inside a Node single-executable application or an Electron application are all
|
||||
opaque today: the analysis reports the containing file and nothing about the cache. An
|
||||
analyst has to install bytenode, guess a V8 version, and run the file to learn anything,
|
||||
which executes attacker-controlled code and changes the state under study.
|
||||
|
||||
`rea inspect-v8-code-cache <path> [--minStringBytes <n>]` reads one explicitly selected
|
||||
container as static bytes and reports its producer, the strings it retains above a
|
||||
threshold, and the recoverable source metadata, without executing the file, starting a
|
||||
V8 runtime, installing bytenode, or invoking a decompiler. The same facts are available
|
||||
through the `inspect_v8_code_cache` MCP tool.
|
||||
|
||||
## Requirements
|
||||
|
||||
- The reader accepts a file whose first words describe a V8 code cache header; anything
|
||||
else is refused before the payload is walked, so an unrelated file cannot be read as a
|
||||
cache by accident.
|
||||
- The producer is decided from the header's producer bits, not from the file extension:
|
||||
a module bit means `vm.SourceTextModule`, a compile-function bit means
|
||||
`vm.compileFunction`, and neither bit means `unknown`. The unflagged case is not
|
||||
`vm.Script` by inference — whether V8 marks a function cache is a build detail. A
|
||||
`vm.compileFunction` cache reads `0x20000004` for a 4-unit source on Node 24.22.1 and
|
||||
`0x00000004` on Node 22.23.4, so an unflagged word could be either producer. The
|
||||
observed word stays in `header.fields` for a caller that trusts a specific build
|
||||
fingerprint.
|
||||
- Retained strings are reported above the caller's byte threshold, with
|
||||
`--minStringBytes` bounded so a pathological threshold cannot make the read unbounded.
|
||||
- Observation is bounded by a budget that reports which bound it hit and how to raise it,
|
||||
rather than silently truncating.
|
||||
- The container's file location is reported as given, and the payload is never written
|
||||
back or repaired.
|
||||
|
||||
## Non-goals
|
||||
|
||||
- Decoding the payload back into source. The container's bytecode is version-specific and
|
||||
the tool does not attempt to reconstruct source from it.
|
||||
- Executing the container to obtain runtime facts.
|
||||
- Recognising an encrypted or compressed wrapper around a cache.
|
||||
|
||||
## Verification
|
||||
|
||||
- The `vm.Script` producer word and its retained strings come from output this suite
|
||||
generates through `vm.Script.createCachedData()`, and the `vm.compileFunction` case
|
||||
compiles through `vm.compileFunction` for the same reason.
|
||||
- The `vm.SourceTextModule` producer bit is checked by setting the measured bit on a real
|
||||
`vm.Script` cache rather than by compiling through `vm.SourceTextModule`, so that case
|
||||
covers the bit's meaning and not a cache from that producer.
|
||||
- The CLI, MCP, absolute-path and decimal-argument boundary contracts have their own
|
||||
tests.
|
||||
- The budget tests call `observationBudgetRecovery` and assert its structured facts — the
|
||||
boundary reached and which knob may move. `observationBudgetRemediation` renders that
|
||||
struct into a sentence, so it is held to the struct rather than to its wording: the
|
||||
sentence must not advise a knob the struct closed, and must mention a smaller artifact
|
||||
exactly when the struct requires one. Rewording stays free; wrong advice does not.
|
||||
@@ -1,14 +0,0 @@
|
||||
# Tasks
|
||||
|
||||
- [x] Record the outcome, requirements and non-goals.
|
||||
- [x] Measure the producer words and the retained-string layout on Node 24.22.1.
|
||||
- [x] Add the domain schema, the bit constants and the observation bounds.
|
||||
- [x] Add the parser, reading the payload by index into the integer table.
|
||||
- [x] Add the provider with the budget and its remediation.
|
||||
- [x] Add the CLI command and register the MCP tool over the same provider.
|
||||
- [x] Document the command, the report and the bounds.
|
||||
- [x] Link the guide from `docs/README.md` and the VitePress index.
|
||||
- [x] Add parser, CLI, MCP, absolute-path and decimal-argument tests.
|
||||
- [x] Hold the budget advice to the recovery struct rather than to its wording.
|
||||
- [x] Run the static, formatting, duplication, documentation and test gates.
|
||||
- [x] Address the independent review.
|
||||
+7
-7
@@ -127,13 +127,13 @@ its declaration, so the same bytes moved to another device memory are
|
||||
|
||||
Root `format_metadata` (`dfuse`) records:
|
||||
|
||||
| Field | Meaning |
|
||||
| ---------------------------------------------------- | ------------------------------------------------------------------------------------------- |
|
||||
| `image_size`, `target_count` | `DFUImageSize` and `bTargets` from the prefix |
|
||||
| `element_count`, `empty_element_count`, `data_bytes` | All elements, elements of 0 bytes (which have no entry), and element data bytes |
|
||||
| `overlapping_element_count` | Elements that overlap an earlier element in address order within the same alternate setting |
|
||||
| `device_version`, `product_id`, `vendor_id` | `bcdDevice`, `idProduct` and `idVendor` from the suffix |
|
||||
| `suffix_crc`, `computed_crc` | The stored `dwCRC`, and the same CRC computed over every byte before it |
|
||||
| Field | Meaning |
|
||||
| ---------------------------------------------------- | ------------------------------------------------------------------------------- |
|
||||
| `image_size`, `target_count` | `DFUImageSize` and `bTargets` from the prefix |
|
||||
| `element_count`, `empty_element_count`, `data_bytes` | All elements, elements of 0 bytes (which have no entry), and element data bytes |
|
||||
| `overlapping_element_count` | Elements that overlap an earlier element of the same alternate setting |
|
||||
| `device_version`, `product_id`, `vendor_id` | `bcdDevice`, `idProduct` and `idVendor` from the suffix |
|
||||
| `suffix_crc`, `computed_crc` | The stored `dwCRC`, and the same CRC computed over every byte before it |
|
||||
|
||||
Recognition already requires `bVersion` 1 and `bcdDFU` `0x011A`, so they are
|
||||
not repeated. The DFU suffix CRC is CRC-32 without the final inversion, as
|
||||
|
||||
@@ -182,9 +182,6 @@ const PATH_SCOPES = {
|
||||
// Four-host installed-package matrix and the Windows curated lane.
|
||||
package: [
|
||||
...WINDOWS_EXECUTABLE_SELECTION_INPUTS,
|
||||
// Selected-file spelling requires the real Windows identity workflow.
|
||||
"src/application/binaryDiagnostics/ByteEntropyService.ts",
|
||||
"tests/acceptance/byteEntropyWindowsIdentity.test.ts",
|
||||
// Both host compilers must be exercised when their installation, options,
|
||||
// or entrypoints change; Linux's accelerated checker cannot stand in for Go.
|
||||
"scripts/run-typescript.*",
|
||||
@@ -633,7 +630,6 @@ const PATH_SCOPES = {
|
||||
"src/ghidra/GhidraReleasePolicy.ts",
|
||||
"scripts/verify-ghidra-bridge-sources.mjs",
|
||||
"tests/conformance/ghidra/ReaArmContextProbe.java",
|
||||
"tests/conformance/ghidra/ReaComputedCallCoverageProbe.java",
|
||||
"tests/conformance/ghidra/ReaDecodeProbe.java",
|
||||
".github/workflows/ghidra-bridge-sources.yml",
|
||||
],
|
||||
|
||||
@@ -487,8 +487,10 @@ const listenerDataDescriptor = (listener) => {
|
||||
return descriptor.get === undefined ? undefined : null;
|
||||
};
|
||||
|
||||
// Only a directly owned wrapper proves dispatch through the hook. A decorator's
|
||||
// .listener metadata can name one without calling it; preserve that uncertainty.
|
||||
// A decorator that wraps once's hook wrapper and names it through `.listener`
|
||||
// already records through that wrapper. Registering the decorator as is keeps
|
||||
// native self-removal working: the once wrapper removes itself by identity, and
|
||||
// removeListener matches the decorator through its `.listener`.
|
||||
const classifyHookListenerWrapper = (listener) => {
|
||||
const visited = new SetConstructor();
|
||||
let candidate = listener;
|
||||
@@ -497,8 +499,7 @@ const classifyHookListenerWrapper = (listener) => {
|
||||
hops <= MAX_LISTENER_CHAIN_HOPS && typeof candidate === "function";
|
||||
hops += 1
|
||||
) {
|
||||
if (weakMapHas(hookListenerRemovalTargets, candidate))
|
||||
return candidate === listener ? "owned" : "unknown";
|
||||
if (weakMapHas(hookListenerRemovalTargets, candidate)) return "owned";
|
||||
if (setHas(visited, candidate)) return "unowned";
|
||||
setAdd(visited, candidate);
|
||||
const descriptor = listenerDataDescriptor(candidate);
|
||||
|
||||
@@ -19,7 +19,7 @@ export const SOURCE_TEST_PROJECTS = [
|
||||
group: "source",
|
||||
include: [
|
||||
"src/*.test.ts",
|
||||
"src/{android,apkSignature,apktool,jeb,adb,artifacts,browser,config,cutter,desktop,dotnet,electron,erlang,evm,firmware,flutter,frida,pcap,ghidra,go,gpu,hopper,ida,inspector,javascript,main,native,process,providers,python,reference,rust,server,sqlite,v8,wasm,windows}/**/*.test.ts",
|
||||
"src/{android,apkSignature,apktool,jeb,adb,artifacts,browser,config,cutter,desktop,dotnet,electron,erlang,evm,firmware,flutter,frida,pcap,ghidra,go,gpu,hopper,ida,inspector,javascript,main,native,process,providers,python,reference,rust,server,sqlite,wasm,windows}/**/*.test.ts",
|
||||
],
|
||||
},
|
||||
{
|
||||
|
||||
@@ -9,9 +9,8 @@ import { tmpdir } from "node:os";
|
||||
import { dirname, join, resolve } from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
|
||||
import { npmInvocation } from "./lib/npm-invocation.mjs";
|
||||
|
||||
const root = join(dirname(fileURLToPath(import.meta.url)), "..");
|
||||
const npm = process.platform === "win32" ? "npm.cmd" : "npm";
|
||||
|
||||
const run = (command, args, cwd) => {
|
||||
const result = spawnSync(command, args, { cwd, stdio: "inherit" });
|
||||
@@ -32,8 +31,7 @@ if (destination === undefined || !destination.endsWith(".tar.xz")) {
|
||||
const archive = resolve(destination);
|
||||
const work = await mkdtemp(join(tmpdir(), "rea-build-runtime-"));
|
||||
try {
|
||||
const pack = npmInvocation(["pack", "--pack-destination", work], process.env);
|
||||
run(pack.command, pack.arguments, root);
|
||||
run(npm, ["pack", "--pack-destination", work], root);
|
||||
const [packed] = (await readdir(work)).filter((name) =>
|
||||
name.endsWith(".tgz"),
|
||||
);
|
||||
@@ -45,11 +43,7 @@ try {
|
||||
join(root, "package-lock.json"),
|
||||
join(runtime, "package-lock.json"),
|
||||
);
|
||||
const install = npmInvocation(
|
||||
["ci", "--omit=dev", "--omit=optional"],
|
||||
process.env,
|
||||
);
|
||||
run(install.command, install.arguments, runtime);
|
||||
run(npm, ["ci", "--omit=dev", "--omit=optional"], runtime);
|
||||
run("tar", ["-cJf", archive, "-C", work, "rea-prod"], work);
|
||||
const { size } = await stat(archive);
|
||||
process.stdout.write(
|
||||
|
||||
+1
-20
@@ -2333,26 +2333,7 @@ export class AdbProvider {
|
||||
{ timeoutMs: PULL_TIMEOUT_MS, maxOutputBytes: PULL_MAX_OUTPUT_BYTES },
|
||||
signal,
|
||||
);
|
||||
if (!pulled.ok) {
|
||||
// A failed adb process can leave caller-visible bytes at the selected
|
||||
// destination. Report only an observed regular file; its transfer and
|
||||
// digest are unconfirmed, and the caller owns the output.
|
||||
const output = await lstat(localPath).catch(() => undefined);
|
||||
if (output?.isFile() === true && !output.isSymbolicLink())
|
||||
pulled.error.retainPartialObservation({
|
||||
provider_id: "adb",
|
||||
operation,
|
||||
result: {
|
||||
client,
|
||||
serial: input.serial,
|
||||
local_path: localPath,
|
||||
device_path: input.device_path,
|
||||
digest_status: "unknown",
|
||||
transfer_status: "unconfirmed",
|
||||
},
|
||||
});
|
||||
return pulled;
|
||||
}
|
||||
if (!pulled.ok) return pulled;
|
||||
try {
|
||||
const digest = await hashAdbFile(
|
||||
localPath,
|
||||
|
||||
@@ -15,16 +15,6 @@ import {
|
||||
} from "./JadxConfiguration.js";
|
||||
import { JADX_JAR_CONFIGURATION_REMEDIATION } from "./JadxRelease.js";
|
||||
|
||||
/** Client settings consulted by this readiness probe. */
|
||||
export const JADX_DOCTOR_SETTINGS = [
|
||||
"REA_JADX_MCP_JAR",
|
||||
"JAVA_HOME",
|
||||
"PATH",
|
||||
"REA_JADX_HEAP_MIB",
|
||||
"REA_JADX_ACTIVE_PROCESSOR_COUNT",
|
||||
"REA_JADX_OPERATION_TIMEOUT_MS",
|
||||
] as const;
|
||||
|
||||
/** Project the validated JADX configuration into the doctor contract. */
|
||||
export const inspectJadxProvider = async (
|
||||
environment: Readonly<Record<string, string | undefined>>,
|
||||
|
||||
@@ -37,10 +37,8 @@ export type SourceClosureOmission = {
|
||||
/** Bounded failure handoff for a completed observation whose bundle never committed. */
|
||||
export type UndeliveredSourceClosure = {
|
||||
readonly publication: "not_published";
|
||||
/** The embedded source list was read and every cited record is in `records` or the observation. */
|
||||
/** Every cited record is in `records` or embedded in the observation itself. */
|
||||
readonly complete: boolean;
|
||||
/** The embedded producer source list could not be read, so closure remains unknown. */
|
||||
readonly collection_failure?: string;
|
||||
readonly records: Evidence[];
|
||||
readonly omitted_count: number;
|
||||
readonly omitted: SourceClosureOmission[];
|
||||
@@ -104,11 +102,10 @@ const collectSourceClosure = (
|
||||
records.push(record);
|
||||
inlineBytes -= bytes;
|
||||
}
|
||||
if (closure.size === 1 && inspection.ok) return undefined;
|
||||
if (closure.size === 1) return undefined;
|
||||
return {
|
||||
publication: "not_published",
|
||||
complete: inspection.ok && omittedCount === 0,
|
||||
...(inspection.ok ? {} : { collection_failure: inspection.error.name }),
|
||||
complete: omittedCount === 0,
|
||||
records,
|
||||
omitted_count: omittedCount,
|
||||
omitted,
|
||||
|
||||
@@ -543,7 +543,6 @@ const workflowAvailabilityFor = (
|
||||
name === "inspect_python_pyc" ||
|
||||
name === "inspect_apple_ips" ||
|
||||
name === "inspect_erlang_beam" ||
|
||||
name === "inspect_v8_code_cache" ||
|
||||
name === "inspect_electron_fuses"
|
||||
)
|
||||
return { reason: "available", remediation: null };
|
||||
@@ -622,11 +621,7 @@ const workflowAvailabilityFor = (
|
||||
};
|
||||
if (name === "inspect_pe_resources" || name === "inspect_native_exports")
|
||||
return { reason: "available", remediation: null };
|
||||
if (
|
||||
name === "inspect_pe_certificates" ||
|
||||
name === "inspect_pe_imports" ||
|
||||
name === "inspect_windows_shortcut"
|
||||
)
|
||||
if (name === "inspect_pe_certificates" || name === "inspect_pe_imports")
|
||||
return { reason: "available", remediation: null };
|
||||
if (
|
||||
name === "inspect_elf_notes" ||
|
||||
|
||||
@@ -128,7 +128,6 @@ export const readClientConfigurationFiles = async (
|
||||
if (document.value !== undefined) {
|
||||
const environment = clientRegistrationEnvironment(
|
||||
document.value,
|
||||
client.name,
|
||||
path === client.configPath ? writeOverrides : undefined,
|
||||
"fragment",
|
||||
platform,
|
||||
@@ -147,7 +146,6 @@ export const readClientConfigurationFiles = async (
|
||||
}
|
||||
const environment = clientRegistrationEnvironment(
|
||||
effectiveClientConfiguration(documents, undefined, platform),
|
||||
client.name,
|
||||
writeOverrides,
|
||||
"effective",
|
||||
platform,
|
||||
|
||||
@@ -59,45 +59,15 @@ const environmentSchema = clientConfigurationRecordSchema.transform(
|
||||
},
|
||||
);
|
||||
|
||||
/**
|
||||
* Clients that expand `$VAR` and `${VAR}` in a recorded `env` value from the
|
||||
* environment the client itself runs with.
|
||||
*
|
||||
* REA does not replicate that expansion — it would have to predict a child's
|
||||
* environment — but it must not report the literal text as the value either, or
|
||||
* a consumer that searches for an inherited `PATH` searches for a literal
|
||||
* `${PATH}` entry instead.
|
||||
*/
|
||||
const VAR_EXPANDING_CLIENTS: ReadonlySet<string> = new Set(["qwen_code"]);
|
||||
|
||||
/** Recorded setting names whose value is an expression, not a literal. */
|
||||
const expressionSettings = (
|
||||
clientName: string | undefined,
|
||||
values: Readonly<Record<string, string>>,
|
||||
): ReadonlySet<string> =>
|
||||
clientName !== undefined && VAR_EXPANDING_CLIENTS.has(clientName)
|
||||
? new Set(
|
||||
Object.entries(values)
|
||||
.filter(([, value]) =>
|
||||
/\$(?:[A-Za-z_][A-Za-z0-9_]*|\{[A-Za-z_][A-Za-z0-9_]*\})/u.test(
|
||||
value,
|
||||
),
|
||||
)
|
||||
.map(([name]) => name),
|
||||
)
|
||||
: new Set();
|
||||
|
||||
/** Read explicit REA overrides without dropping peers when one value is invalid. */
|
||||
export const clientRegistrationEnvironment = (
|
||||
parsed: ClientConfigurationDocument | undefined,
|
||||
clientName: string | undefined,
|
||||
overrides: Readonly<Record<string, string>> = {},
|
||||
validation: "fragment" | "effective" = "effective",
|
||||
platform: NodeJS.Platform = process.platform,
|
||||
): Result<Readonly<Record<string, string>>, ConfigurationError> => {
|
||||
const details = clientRegistrationEnvironmentDetails(
|
||||
parsed,
|
||||
clientName,
|
||||
overrides,
|
||||
validation,
|
||||
platform,
|
||||
@@ -108,7 +78,6 @@ export const clientRegistrationEnvironment = (
|
||||
/** Retain original strings and the parser-owned timeout facts. */
|
||||
export const clientRegistrationEnvironmentDetails = (
|
||||
parsed: ClientConfigurationDocument | undefined,
|
||||
clientName: string | undefined,
|
||||
overrides: Readonly<Record<string, string>> = {},
|
||||
validation: "fragment" | "effective" = "effective",
|
||||
platform: NodeJS.Platform = process.platform,
|
||||
@@ -155,12 +124,7 @@ export const clientRegistrationEnvironmentDetails = (
|
||||
overrides,
|
||||
platform,
|
||||
);
|
||||
return validatedDetails(
|
||||
environment,
|
||||
validation,
|
||||
platform,
|
||||
expressionSettings(clientName, environment),
|
||||
);
|
||||
return validatedDetails(environment, validation, platform);
|
||||
};
|
||||
|
||||
/** Setting names a registration does not carry as the value selected here. */
|
||||
@@ -181,7 +145,6 @@ export interface RecordedProviderSettings {
|
||||
*/
|
||||
export const recordedProviderSettings = (
|
||||
parsed: ClientConfigurationDocument,
|
||||
clientName: string | undefined,
|
||||
selected: Readonly<Record<string, string>>,
|
||||
platform: NodeJS.Platform = process.platform,
|
||||
): RecordedProviderSettings | undefined => {
|
||||
@@ -189,7 +152,6 @@ export const recordedProviderSettings = (
|
||||
if (names.length === 0) return undefined;
|
||||
const details = clientRegistrationEnvironmentDetails(
|
||||
parsed,
|
||||
clientName,
|
||||
{},
|
||||
"fragment",
|
||||
platform,
|
||||
@@ -209,9 +171,7 @@ export const recordedProviderSettings = (
|
||||
),
|
||||
differing: names.filter(
|
||||
(name) =>
|
||||
expressions[name] === undefined &&
|
||||
recorded[name] !== undefined &&
|
||||
recorded[name] !== selected[name],
|
||||
recorded[name] !== undefined && recorded[name] !== selected[name],
|
||||
),
|
||||
unresolved: names.filter((name) => expressions[name] !== undefined),
|
||||
};
|
||||
@@ -226,7 +186,6 @@ export const recordedProviderSettings = (
|
||||
/** Resolve the async provider-specific budget through its retained reader owner. */
|
||||
export const clientRegistrationEnvironmentDetailsWithBudget = async (
|
||||
parsed: ClientConfigurationDocument | undefined,
|
||||
clientName: string | undefined,
|
||||
overrides: Readonly<Record<string, string>>,
|
||||
validation: "fragment" | "effective",
|
||||
resolveProviderRequestBudget: ProviderRequestBudgetResolver | undefined,
|
||||
@@ -236,7 +195,6 @@ export const clientRegistrationEnvironmentDetailsWithBudget = async (
|
||||
> => {
|
||||
const details = clientRegistrationEnvironmentDetails(
|
||||
parsed,
|
||||
clientName,
|
||||
overrides,
|
||||
validation,
|
||||
platform,
|
||||
@@ -272,23 +230,14 @@ const validatedDetails = (
|
||||
environment: Readonly<Record<string, string>>,
|
||||
validation: "fragment" | "effective",
|
||||
platform: NodeJS.Platform = process.platform,
|
||||
expressionSettings: ReadonlySet<string> = new Set(),
|
||||
): Result<ClientRegistrationEnvironmentDetails, ConfigurationError> => {
|
||||
const runtimeEnvironment = snapshotEnvironment(environment, platform);
|
||||
const unresolved = new Set(
|
||||
Object.keys(
|
||||
snapshotEnvironment(
|
||||
Object.fromEntries([...expressionSettings].map((name) => [name, ""])),
|
||||
platform,
|
||||
),
|
||||
),
|
||||
);
|
||||
const validated =
|
||||
validation === "fragment"
|
||||
? parseEnvironmentValues(runtimeEnvironment, unresolved)
|
||||
: parseEnvironment(runtimeEnvironment, unresolved);
|
||||
? parseEnvironmentValues(runtimeEnvironment)
|
||||
: parseEnvironment(runtimeEnvironment);
|
||||
if (!validated.ok) return validated;
|
||||
return ok(environmentDetails(environment, validated.value, unresolved));
|
||||
return ok(environmentDetails(environment, validated.value));
|
||||
};
|
||||
|
||||
const environmentDetails = (
|
||||
|
||||
@@ -283,7 +283,6 @@ export const readClientRegistrationInspections = async (
|
||||
compactInputSchemaByDefault(client) || client.name === "codex"
|
||||
? await clientRegistrationEnvironmentDetailsWithBudget(
|
||||
parsed,
|
||||
client.name,
|
||||
{},
|
||||
"effective",
|
||||
client.name === "kimi" || client.name === "codex"
|
||||
@@ -380,7 +379,6 @@ export const readClientRegistrationInspections = async (
|
||||
? undefined
|
||||
: recordedProviderSettings(
|
||||
parsed,
|
||||
client.name,
|
||||
options.providerSettings,
|
||||
options.platform,
|
||||
),
|
||||
|
||||
@@ -48,7 +48,7 @@ it("joins a late provider inspection and retries only its unresolved cleanup own
|
||||
return [];
|
||||
},
|
||||
});
|
||||
const inspection = host.providerInspections!([]);
|
||||
const inspection = host.providerInspections!();
|
||||
let closing: Promise<unknown> | undefined;
|
||||
await withVerifierCleanup(async () => {
|
||||
await awaitAcknowledgement(
|
||||
@@ -83,7 +83,7 @@ it("joins a late provider inspection and retries only its unresolved cleanup own
|
||||
await host.close!();
|
||||
expect(failure.cleanupIncomplete).toBe(false);
|
||||
expect(closes).toEqual({ successful: 1, refused: 2 });
|
||||
await expect(host.providerInspections!([])).rejects.toThrow(
|
||||
await expect(host.providerInspections!()).rejects.toThrow(
|
||||
"scope is closed",
|
||||
);
|
||||
}, [
|
||||
|
||||
@@ -100,10 +100,8 @@ export interface DoctorProviderCheck {
|
||||
/** Read-only provider inspection supplied by an outer composition adapter. */
|
||||
export interface DoctorProviderInspection {
|
||||
readonly id: string;
|
||||
/** Null means the selected client's setting could not be determined. */
|
||||
readonly configured: boolean | null;
|
||||
/** Null means readiness cannot be established for the selected client. */
|
||||
readonly available: boolean | null;
|
||||
readonly configured: boolean;
|
||||
readonly available: boolean;
|
||||
readonly providerVersion: string | null;
|
||||
/** Validated discoveries used as registration defaults. Setup preserves
|
||||
* caller-selected configuration separately from these readiness facts. */
|
||||
@@ -138,9 +136,7 @@ export interface DoctorHost {
|
||||
brewHopperPath(): Promise<string | undefined>;
|
||||
/** Renamed `Hopper*.app` launchers; consulted only where macOS bundles are probed. */
|
||||
manualHopperPaths(): Promise<readonly string[]>;
|
||||
providerInspections?(
|
||||
clients: readonly string[],
|
||||
): Promise<readonly DoctorProviderInspection[]>;
|
||||
providerInspections?(): Promise<readonly DoctorProviderInspection[]>;
|
||||
/** Resolve a parsed upstream request budget from the effective client environment. */
|
||||
resolveProviderRequestBudget?: ProviderRequestBudgetResolver;
|
||||
installationPaths?(): Promise<readonly string[]>;
|
||||
@@ -281,7 +277,7 @@ const inspectDoctor = async (
|
||||
checks: diagnosticChecks,
|
||||
hopperPath,
|
||||
providerInspections,
|
||||
} = await collectDoctorDiagnostics(target, host, scope.clients);
|
||||
} = await collectDoctorDiagnostics(target, host);
|
||||
const hopperAvailable =
|
||||
hopperPath !== undefined &&
|
||||
diagnosticChecks
|
||||
@@ -394,8 +390,9 @@ export const registrationEnvironmentDetail = (
|
||||
].join(" ");
|
||||
|
||||
/**
|
||||
* Report what the registration's file leaves out without gating health:
|
||||
* doctor cannot observe the environment the client actually passes on.
|
||||
* A healthy provider check describes this terminal, not the server a client
|
||||
* starts. Report what the registration's file leaves out without gating health:
|
||||
* the client may still pass the setting on, which doctor cannot observe.
|
||||
*/
|
||||
const registrationEnvironmentChecks = (
|
||||
registrations: readonly ClientRegistrationStatus[],
|
||||
@@ -624,7 +621,6 @@ export interface SystemDoctorHostOptions {
|
||||
readonly providerInspections?: (
|
||||
resourceScope: RetainedResourceScope,
|
||||
signal: AbortSignal,
|
||||
clients: readonly string[],
|
||||
) => Promise<readonly DoctorProviderInspection[]>;
|
||||
readonly resolveProviderRequestBudget?: (
|
||||
provider: Parameters<ProviderRequestBudgetResolver>[0],
|
||||
@@ -824,13 +820,9 @@ export const systemDoctorHost = (
|
||||
...(options.providerInspections === undefined
|
||||
? {}
|
||||
: {
|
||||
providerInspections: (clients) =>
|
||||
providerInspections: () =>
|
||||
resources.run(() =>
|
||||
options.providerInspections!(
|
||||
resourceScope,
|
||||
inspectionSignal,
|
||||
clients,
|
||||
),
|
||||
options.providerInspections!(resourceScope, inspectionSignal),
|
||||
),
|
||||
}),
|
||||
...(resolveProviderRequestBudget === undefined
|
||||
|
||||
@@ -22,7 +22,6 @@ export interface DoctorDiagnostics {
|
||||
export const collectDoctorDiagnostics = async (
|
||||
target: string | undefined,
|
||||
host: DoctorHost,
|
||||
clients: readonly string[] = [],
|
||||
): Promise<DoctorDiagnostics> => {
|
||||
const checks: DoctorCheck[] = [nodeCheck(host)];
|
||||
checks.push(await hostCheck(host));
|
||||
@@ -35,7 +34,7 @@ export const collectDoctorDiagnostics = async (
|
||||
const hopperVersionCheck = await optionalHopperVersionCheck(host, hopperPath);
|
||||
if (hopperVersionCheck !== undefined) checks.push(hopperVersionCheck);
|
||||
|
||||
const providerInspections = await host.providerInspections?.(clients ?? []);
|
||||
const providerInspections = await host.providerInspections?.();
|
||||
if (providerInspections !== undefined)
|
||||
checks.push(...providerInspections.flatMap(providerDoctorChecks));
|
||||
|
||||
|
||||
Loaded 100 of 541 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user