mirror of
https://github.com/morluto/rea.git
synced 2026-11-09 17:32:36 -10:00
Compare commits
125
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6ecbcd6bc8 | ||
|
|
87c5024310 | ||
|
|
0c3ae4962b | ||
|
|
4ab6ea82ea | ||
|
|
3558b56823 | ||
|
|
19a63d21fb | ||
|
|
e568d1269c | ||
|
|
9f1d656afd | ||
|
|
6057cceb41 | ||
|
|
c581184ce4 | ||
|
|
990acda04c | ||
|
|
9886bbb5b1 | ||
|
|
0dd1ac5485 | ||
|
|
1ffa4906e6 | ||
|
|
329df8b331 | ||
|
|
0380e2756f | ||
|
|
06965362bc | ||
|
|
d53ee6d87b | ||
|
|
5399c23e46 | ||
|
|
5476a3ee17 | ||
|
|
7bdd16783d | ||
|
|
4815e82342 | ||
|
|
623bd7c40f | ||
|
|
be0f27e7c3 | ||
|
|
0a00d1291c | ||
|
|
5bd4bf9ba0 | ||
|
|
7882368d47 | ||
|
|
f1f9ce661a | ||
|
|
90e8f03466 | ||
|
|
8dfc47b107 | ||
|
|
e9b6c87c1c | ||
|
|
387bcb795d | ||
|
|
e5ddbe8909 | ||
|
|
018f19d8c8 | ||
|
|
fe2985a0b4 | ||
|
|
26d81afedd | ||
|
|
d71e35a5ae | ||
|
|
240f08d406 | ||
|
|
61ab3f0c4f | ||
|
|
fd39977c32 | ||
|
|
012861ce1d | ||
|
|
0dcd0dfc20 | ||
|
|
35f1c3517f | ||
|
|
eb8ba20c35 | ||
|
|
bdf7cc3b1e | ||
|
|
3b2522bd3b | ||
|
|
8bc01b48b4 | ||
|
|
deae5fbe6d | ||
|
|
fa0fcf35ce | ||
|
|
217b6fdcdc | ||
|
|
78343052c2 | ||
|
|
b105dae7c6 | ||
|
|
7a1d89a801 | ||
|
|
759817ccbe | ||
|
|
da3bb5aa7b | ||
|
|
ec7d09176b | ||
|
|
bf1811bdbc | ||
|
|
74201434e7 | ||
|
|
769d92025d | ||
|
|
ca1674473c | ||
|
|
22f28644fe | ||
|
|
43f06eb1e8 | ||
|
|
f21fda0fc0 | ||
|
|
7b9b6cc78b | ||
|
|
b1f473fcf8 | ||
|
|
24053f7ee2 | ||
|
|
a344650a7b | ||
|
|
9e0bc71e78 | ||
|
|
1f9bf8af0e | ||
|
|
419956f56e | ||
|
|
c5ee066022 | ||
|
|
3230f50b16 | ||
|
|
0a15246d32 | ||
|
|
9108d9a627 | ||
|
|
3c3d405c00 | ||
|
|
43d9c9d19b | ||
|
|
86059108b1 | ||
|
|
35fbec9df5 | ||
|
|
b394d50943 | ||
|
|
694edef951 | ||
|
|
d4b9a33348 | ||
|
|
b06df804d6 | ||
|
|
df2d018b30 | ||
|
|
6c1faaed75 | ||
|
|
1fcf50518e | ||
|
|
437e65d349 | ||
|
|
df5103e26d | ||
|
|
f328b49d22 | ||
|
|
70e4653feb | ||
|
|
1883578b67 | ||
|
|
97b5503f39 | ||
|
|
645735fc0f | ||
|
|
25885b05c0 | ||
|
|
2c27c2a43b | ||
|
|
ab1b9e35d0 | ||
|
|
bf271ba3fb | ||
|
|
dda2d40295 | ||
|
|
0b1a945d69 | ||
|
|
425581e838 | ||
|
|
f047624018 | ||
|
|
62a2814756 | ||
|
|
400a91b5f9 | ||
|
|
8dc2d7bec4 | ||
|
|
908d9c0726 | ||
|
|
6a24e801ea | ||
|
|
5e61ae0b0e | ||
|
|
7baed55130 | ||
|
|
512bcf5cdb | ||
|
|
31b6db72c6 | ||
|
|
3e1f70096b | ||
|
|
e8d1bbc98b | ||
|
|
e66e92904e | ||
|
|
8c64eb511f | ||
|
|
e304de99bc | ||
|
|
d307ece767 | ||
|
|
4fde832260 | ||
|
|
97fe58d3fe | ||
|
|
7c821cfea1 | ||
|
|
f46e9a8479 | ||
|
|
29768c6f53 | ||
|
|
cc13c5d095 | ||
|
|
897caa814d | ||
|
|
a874cef9af | ||
|
|
a6c10a28f4 | ||
|
|
9536ebb7ca |
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
|
||||
@@ -97,6 +97,12 @@ explicit path or endpoint and do not need it.
|
||||
- Bun `--compile` executable: `open_binary`, then `inspect_artifact`; the Bun
|
||||
module graph is the application layer. Extract stored modules and analyze the
|
||||
JavaScript. See [Bun standalone executables](https://github.com/morluto/rea/blob/main/docs/bun-standalone.md).
|
||||
- Deno `deno compile` executable: `open_binary`, then `inspect_artifact`; the
|
||||
embedded virtual filesystem is the application layer. Extract stored files and
|
||||
analyze compatible JavaScript. Environment-file values and CA certificate bytes
|
||||
are retained in local Evidence with their counts and byte lengths. The npm
|
||||
snapshot length is reported and not decoded, and the executable is not run. See
|
||||
[Deno compile executables](https://github.com/morluto/rea/blob/main/docs/deno-standalone.md).
|
||||
- Apple app plist, Interface Builder, asset catalog, or keyed archive resources:
|
||||
`open_bundle_resources`, then the selected resource tool. This does not
|
||||
require `CFBundleExecutable` or a deep provider. Resource sessions have no
|
||||
@@ -276,6 +282,14 @@ 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
|
||||
@@ -299,6 +313,23 @@ explicit path or endpoint and do not need it.
|
||||
build-id or ABI-tag fields. A missing table is observed absence of those
|
||||
declarations, not proof the image never carried notes. See the
|
||||
[ELF notes guide](https://github.com/morluto/rea/blob/main/docs/elf-notes.md).
|
||||
- Code that runs before `main` or at exit in ELF or Mach-O:
|
||||
`inspect_native_initializers` with the explicit local file (and
|
||||
`architecture` for a universal Mach-O). This built-in inspection requires no
|
||||
disassembler. Preserve slot and target addresses, the `resolution` of each
|
||||
entry, and its limitations. An `unresolved` slot is not a zero pointer, and a
|
||||
missing table is not proof that no constructor exists. See the
|
||||
[initializer guide](https://github.com/morluto/rea/blob/main/docs/guides/native/native-initializers.md).
|
||||
|
||||
- ELF unwind function ranges: `inspect_elf_unwind_ranges` with the explicit
|
||||
local ELF32/ELF64 file. This built-in target-free inspection requires no
|
||||
disassembler. Preserve FDE start, end, size, containing section, exact
|
||||
symbol name, CIE index, LSDA, and personality. Page with `offset` and
|
||||
`limit`. A missing `.eh_frame` is observed absence of that declaration,
|
||||
not proof the image has no functions. `.debug_frame` is reported present
|
||||
or absent and is not decoded. CFA instructions are counted and not
|
||||
evaluated. See the
|
||||
[ELF unwind ranges guide](https://github.com/morluto/rea/blob/main/docs/guides/native/elf-unwind-ranges.md).
|
||||
- Apple `.ips` crash reports: `inspect_apple_ips` with the explicit local
|
||||
file. This built-in target-free inspection requires no Xcode, atos, or
|
||||
pwntools. Preserve first-line metadata, `bug_type` as a string, process and
|
||||
@@ -317,6 +348,16 @@ explicit path or endpoint and do not need it.
|
||||
zstd containers are unsupported; decompress into a separate file with an
|
||||
external codec utility, then inspect the decompressed `ET_REL` image. See the
|
||||
[kernel module guide](https://github.com/morluto/rea/blob/main/docs/kernel-modules.md).
|
||||
- Linux kernel version and build config (`CONFIG_*` options such as
|
||||
`CONFIG_SECURITY_SELINUX`): `inspect_kernel_build_config` with the explicit
|
||||
local `vmlinux`, raw `Image`, x86 `bzImage`, or `configs.ko`. This built-in
|
||||
target-free inspection requires no Linux host or `extract-ikconfig`. Preserve
|
||||
the banner version, config SHA-256, option count, and value kinds; use `name`
|
||||
for one option. An `IKCFG_ST` string is a config only with a valid gzip member
|
||||
and `IKCFG_ED`. An absent config may mean the kernel was built without
|
||||
`CONFIG_IKCONFIG`. Non-gzip payloads are unsupported; decompress externally,
|
||||
then inspect the result. See the
|
||||
[kernel build config guide](https://github.com/morluto/rea/blob/main/docs/guides/native/kernel-build-config.md).
|
||||
- CPython 3.7–3.13 `.pyc` header, nested marshal code objects and bytecode
|
||||
identity: `inspect_python_pyc` with the explicit local file. This built-in
|
||||
target-free inspection requires no Python installation. Preserve magic,
|
||||
|
||||
@@ -5,14 +5,18 @@ task, such as "Build me an Inkscape environment where the agent changes a
|
||||
poster's headline and saves it". You are the building agent: you drive the
|
||||
app on a build computer through REA's MCP tools, write the task, export the
|
||||
bundle and witness it in a fresh computer. REA runs no model. The tools are
|
||||
MCP-only and need Docker, `REA_AGENT_ENV_COMMAND` and
|
||||
`REA_BUILD_COMPUTER_REA_ARCHIVE` where the REA server starts; when a start
|
||||
reports one missing, tell the person what to set and stop.
|
||||
MCP-only and need a Linux host with Docker, agentenv and REA's packed
|
||||
runtime. When a start reports one missing, tell the person to run
|
||||
`rea doctor --provider desktop_build` and apply its fixes, or
|
||||
`rea setup --client <client> --desktop-build` and restart the client, and
|
||||
stop.
|
||||
|
||||
For the whole build:
|
||||
|
||||
- Drive the app only with `act_on_build_computer`. Never script it, run
|
||||
commands in the computer or write its files another way.
|
||||
commands in the computer or write its files another way. The one command
|
||||
you write for the computer is a task's reader, which REA runs to check a
|
||||
file; it never makes the seed or the edit.
|
||||
- Ask the upfront questions once, then work on your own. Pause only when
|
||||
blocked.
|
||||
- The seed's content is synthetic. Never put real personal data in it.
|
||||
@@ -22,7 +26,8 @@ For the whole build:
|
||||
## Ask once, upfront
|
||||
|
||||
In one message, ask only what the request leaves open, and keep the list for
|
||||
the report:
|
||||
the report. Skip each question the request answers; when it answers them all,
|
||||
start without asking:
|
||||
|
||||
1. The app and the task, if either is unclear: what changes, in which
|
||||
document.
|
||||
@@ -31,39 +36,83 @@ the report:
|
||||
and with which model.
|
||||
4. If so, whether they want to review the task before those runs.
|
||||
|
||||
When you cannot ask, as in a headless `claude -p` run, do not stop: take
|
||||
these defaults for whatever the request leaves open, say which you took in
|
||||
your first message and in the report, and go on. Install from the Ubuntu
|
||||
archive, make a synthetic seed, skip the review, and make 3 solver runs
|
||||
within $4 in all, with the model the request names or else the runner's
|
||||
default.
|
||||
|
||||
## When you are blocked
|
||||
|
||||
Stop, say what you need and wait only for:
|
||||
|
||||
- a licence the app or its installer asks someone to accept: never accept it
|
||||
yourself; name it and where to read it, and go on only once the person
|
||||
says they accept it;
|
||||
- credentials: they may only be typed as handles you never see, and the
|
||||
build tools have none yet, so say the app needs a sign-in and stop. Never
|
||||
ask for a password in chat;
|
||||
- a signed-in state in the seed: ask before seeding one;
|
||||
on your own; name it and where to read it, and go on only once the person
|
||||
says they accept it. Then record their words with `record_build_consent`,
|
||||
kind `licence`, and accept it on their behalf;
|
||||
- credentials: ask the person to write each secret, and nothing else, in a
|
||||
file named after a handle you choose, such as `keepassxc-master`, in
|
||||
`~/.config/rea/build-secrets/` on this host (under `$XDG_CONFIG_HOME` when
|
||||
it is set), readable only by them (`chmod 600`), and wait until they say it
|
||||
is there; then type it with `type_secret` (see Drive the app). Never ask
|
||||
for a password or key in chat, and never read, list or print that folder;
|
||||
- a signed-in state in the seed: by default the export withholds it (see
|
||||
Sign-in and licence state). Seed it only when the person says the bundle
|
||||
may hold it: record their words with `record_build_consent`, kind
|
||||
`seed_sign_in`, and export with `seed_sign_in: true`;
|
||||
- an install this flow cannot do, below.
|
||||
|
||||
Decide everything else yourself and note it in the report.
|
||||
|
||||
## Sign-in and licence state
|
||||
|
||||
What an app writes when someone signs in or activates a licence is withheld
|
||||
from the seed: the bundle's receiver supplies their own. Mark
|
||||
`pre-sign-in` with `mark_build_checkpoint` just before the sign-in or
|
||||
activation and `post-sign-in` just after, both before `seed`: every file
|
||||
under the owned paths that changed between them is withheld, and the draft
|
||||
leaves it out. A file the app writes at first launch, such as a trial's
|
||||
licence file, changes before you can mark anything: name it in
|
||||
`export_build_environment`'s `withhold`. The export lists each withheld file
|
||||
in `withheld_files` with the environment variable a deploy reads it from and
|
||||
the handle of the secret REA keeps its bytes in; a check may not name one.
|
||||
The export refuses a seed file holding a withheld file's exact bytes, such as
|
||||
a `.bak` copy, but a backup that differs from it is not caught: trash backups
|
||||
before `seed`.
|
||||
Explicitly withhold any other files the person identifies as sensitive;
|
||||
REA does not infer secrecy from a value's shape or a file name.
|
||||
|
||||
## Choose the install
|
||||
|
||||
The computer is Ubuntu 24.04 (noble) on this host's architecture only. Use
|
||||
the first source that has the app:
|
||||
|
||||
| Source | `install` |
|
||||
| ---------------------------- | --------------------------------------------------------------------------------- |
|
||||
| Ubuntu archive | `{"kind": "archive", "package": "inkscape"}` |
|
||||
| PPA or vendor apt repository | `{"kind": "apt_repository", "package", "uri", "suite", "components", "key_file"}` |
|
||||
| `.deb` by URL | `{"kind": "package_file", "url", "sha256", "architecture", "dependencies"}` |
|
||||
| Source | `install` |
|
||||
| ---------------------------- | ------------------------------------------------------------------------------------------- |
|
||||
| Ubuntu archive | `{"kind": "archive", "package": "inkscape"}` |
|
||||
| PPA or vendor apt repository | `{"kind": "apt_repository", "package", "uri", "suite", "components", "key_file"}` |
|
||||
| `.deb` by URL | `{"kind": "package_file", "url", "sha256", "architecture", "dependencies"}` |
|
||||
| AppImage by URL | `{"kind": "appimage", "url", "sha256", "architecture", "extra_packages"}` |
|
||||
| Tarball by URL | `{"kind": "tarball", "url", "sha256", "architecture", "program", "name", "extra_packages"}` |
|
||||
|
||||
- A PPA's `uri` is `https://ppa.launchpadcontent.net/OWNER/NAME/ubuntu`,
|
||||
`suite` `noble`, `components` `["main"]`. `key_file` is the repository's
|
||||
signing key saved on this host; for a PPA, fetch it from
|
||||
keyserver.ubuntu.com by the fingerprint its Launchpad page shows.
|
||||
- For a `.deb`, ask the requester for its URL and SHA-256; do not fetch a
|
||||
vendor's download page yourself. List its `Depends` as `dependencies`:
|
||||
it installs with the network off.
|
||||
- When the app exits at launch for want of a runtime piece its package does
|
||||
not install, start a new build computer with that package in
|
||||
`extra_packages`, up to 16 archive names; the export installs them too.
|
||||
MyPaint needs
|
||||
`{"kind": "archive", "package": "mypaint", "extra_packages": ["librsvg2-common"]}`
|
||||
for its SVG icons, and Freeplane `["openjdk-17-jre"]`, since its launcher
|
||||
refuses noble's Java 21. Name one up front, too, when a package the app
|
||||
only recommends holds its content, such as QElectroTech's element library
|
||||
`qelectrotech-data`, without which no component can be placed.
|
||||
- Take the `.deb` path only when the app is not in the archive at all, not
|
||||
to add a package. Ask the requester for its URL and SHA-256; do not fetch
|
||||
a vendor's download page yourself. List its `Depends` as `dependencies`,
|
||||
with any runtime piece it lacks: it installs with the network off.
|
||||
- Flatpak, AppImage and snaps are not supported yet: say so and stop. An
|
||||
archive package that only installs a snap, such as noble's `firefox`,
|
||||
counts as a snap. A package with no build for this host's architecture
|
||||
@@ -72,6 +121,13 @@ 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
|
||||
|
||||
@@ -81,8 +137,10 @@ the first source that has the app:
|
||||
[the build-computer guide](https://github.com/morluto/rea/blob/main/docs/desktop-build-computer.md).
|
||||
- Take a `screenshot` before pointing: points are pixels of the latest
|
||||
frame. If a response is too large, ask for a `region`, or `jpeg` with a
|
||||
lower `quality`. A region crops the latest frame and becomes it: take a
|
||||
full screenshot before pointing again.
|
||||
lower `quality`. A screenshot with `region` does not capture the screen
|
||||
again; it crops the latest frame, so take a full screenshot, or a `wait`
|
||||
with `screenshot: true`, first. The crop then becomes the latest frame:
|
||||
take a full screenshot before pointing again.
|
||||
- A drawn caret does not prove keyboard focus. After using a toolbar
|
||||
control, click into the document, then type a few characters and look
|
||||
before a long text.
|
||||
@@ -95,25 +153,149 @@ the first source that has the app:
|
||||
close it while capturing; the capture ends when the app exits. When the
|
||||
app is closed at any other time, open it from Applications → Other → the
|
||||
environment's name.
|
||||
- Type a secret with `{"action": "type_secret", "secret": "<handle>"}`,
|
||||
only into a field that masks what is typed: check in a screenshot that it
|
||||
is a password field, which shows dots. A screenshot shows any field that
|
||||
shows its text, such as many licence-key boxes, so never type a secret into
|
||||
one: say the app needs a secret the build cannot type unseen, and stop.
|
||||
`type_secret` takes no `screenshot`; look with a `wait` after it. A refusal
|
||||
names the secret's file and what is wrong with it: tell the person, never
|
||||
the value.
|
||||
- Prefer shortcuts and typing to long pointer paths: `key` takes `keys`, an
|
||||
array holding one chord's keys, such as
|
||||
`{"action": "key", "keys": ["ctrl", "s"]}`, and `type` turns `\n` into
|
||||
`{"action": "key", "keys": ["Control", "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 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.
|
||||
- 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. When a GTK Save dialog ignores
|
||||
clicks or runs off the screen, type `~/Documents/<name>` in its Name field
|
||||
and press Return.
|
||||
- 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.
|
||||
- gLabels edits an object's text in Object properties → Text, not on the
|
||||
canvas.
|
||||
- In Grisbi's transaction form Return moves to the next field; only Return
|
||||
in the last field, Notes, records the transaction.
|
||||
- ghostwriter autosaves a new document as `~/Documents/untitled-1.md`: name
|
||||
it with File → Rename, not Save As; Ctrl+Shift+S does nothing, and Enter
|
||||
after a checklist item starts another `- [ ]` item.
|
||||
- KMyMoney's first launch opens the New File Setup wizard; Finish asks for a
|
||||
storage type (XML), then a Save As where typing `Documents/<name>.kmy`
|
||||
works. Its date field is a sectioned Qt editor: double-click the month and
|
||||
type each part, since Ctrl+A garbles it. A new transaction's payee comes
|
||||
prefilled and selected. Amounts are saved as reduced fractions, such as
|
||||
`-1749/20`, so compare them exactly. Untick Help → Tip of the Day → "Show
|
||||
tips on startup" before `seed`, or the tip appears at every boot.
|
||||
- QElectroTech: an element dropped from Collections follows the pointer until
|
||||
a click on the folio places it. Its title shows only the app, so it needs
|
||||
`state_paths`; its settings are in `~/.qet`.
|
||||
- Rosegarden: after a dialog its Transport window can take keyboard focus,
|
||||
so save with File → Save.
|
||||
- Pencil2D: the Tools dock is too narrow for its buttons, so use shortcuts
|
||||
(B for the brush); double-click a layer's name to rename it.
|
||||
- Umbrello: the title shows no unsaved mark, so confirm a save with a probe
|
||||
checkpoint. An Untitled document autosaves `~/autosave.xmi`: delete it
|
||||
before `seed`. Add attributes from the tree: right-click the class → New →
|
||||
Attribute.
|
||||
- Hydrogen: the computer has no audio device, so Hydrogen falls back to a
|
||||
null driver and its BPM field snaps back to 120 within about 100 ms.
|
||||
Before `seed`, set Preferences → Audio System → ALSA with device `null`
|
||||
and click "Apply and restart output", which `~/.hydrogen/hydrogen.conf`
|
||||
keeps for the seed; also set autosaves per hour to 0, and dismiss the
|
||||
development-version dialog with "Don't show again". `pulseaudio` as an
|
||||
extra package does not help.
|
||||
- Poedit cannot add entries by hand. Use File → New, pick the language and
|
||||
save to `Documents` first (Sources Paths stays locked until then), then
|
||||
Properties → Sources Paths → + → Add Files with a source such as
|
||||
`/usr/lib/python3.12/argparse.py`. It writes `fr.mo` beside the `.po`, and
|
||||
the language box's autocomplete popup takes the first OK click.
|
||||
- CherryTree: its first-run autosave "Choose Storage Type" dialog swallows
|
||||
keys, so save once early as `.ctd` and untick autosave.
|
||||
- VSCodium (its tarball, with `extra_packages: ["libnss3",
|
||||
"libasound2t64"]`) runs on outside REA's reach, so `stop_build_capture`
|
||||
fails to clean it up: after `end`, quit it with Ctrl+Q, then stop. Enter
|
||||
accepts its word suggestions, so press Escape after typing a line.
|
||||
- Glade: a new widget's id is empty until you set it, and a second save
|
||||
writes a `.glade~` backup, which shows in the draft as an unrelated
|
||||
change. A backup present at `seed` is seeded with the document, so trash
|
||||
it before `seed`. The draft names a button's `<child>` by the id
|
||||
its widget carries, `[name=child][>object@id=submit_button]`, which moving
|
||||
the button keeps; give the widget an id before `seed` so it can.
|
||||
- VYM: the title never names the map, so pass `Documents/<map>.vym` in
|
||||
`state_paths`. Its settings live in `.config/InSilmaril` and are written
|
||||
only at a clean exit. It writes `<map>.vym.lock` while a map is open, so
|
||||
close the map before `seed`. Press A only after clicking a branch on the
|
||||
canvas: keys typed in the tree editor run other shortcuts.
|
||||
- KmPlot: Create → Cartesian Plot, then edit the formula in the Function
|
||||
tab and press Return. It stores minus as U+2212 (`−`). Its file:// title
|
||||
still names the file.
|
||||
- RedNotebook keeps each month in `~/.rednotebook/data/YYYY-MM.txt`, YAML
|
||||
read as text, folded at about column 80: pick check phrases the fold keeps
|
||||
on one line.
|
||||
- Qt5 apps saving with QDom, such as KmPlot, write attributes in a random
|
||||
order in each process, so check their XML by element, never by whole line.
|
||||
- Gnumeric's desktop entry is `org.gnumeric.gnumeric`. Its Save As dialog
|
||||
runs off the 1280×800 screen: type `~/Documents/<name>` in Name and press
|
||||
Return. Rename a sheet with right-click on its tab, then Rename….
|
||||
- Parley's title shows the collection's title, so name the file in
|
||||
`state_paths`. File → New opens the new collection's Properties dialog:
|
||||
confirm it with OK, since Cancel keeps the old collection and its autosave
|
||||
lock open. A new collection starts with 15 blank entries: delete them.
|
||||
Pick languages from the dropdown; a typed name keeps the previous locale.
|
||||
While a document is open KDE keeps an autosave and its `.lock` in
|
||||
`~/.local/share/stalefiles/parley/`, and there is no File → Close: before
|
||||
`seed`, use File → New, then reopen the collection from Open Recent.
|
||||
- Sigil: pass `extra_packages: ["libqt5svg5"]`, or its SVG toolbar icons are
|
||||
blank. Its title names the book, so it needs no `state_paths`. It unpacks
|
||||
the open book into `.local/share/sigil-ebook/sigil/workspace/Sigil-XXXXXX/`
|
||||
and deletes it on exit, so never name the whole `sigil-ebook` folder: that
|
||||
seeds the stale copy.
|
||||
- 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
|
||||
file rather than starting over.
|
||||
file rather than starting over. JabRef 3.8 writes `<file>.bak` and
|
||||
`<file>.sav` beside a `.bib` it saves; in the owned folder they are seeded
|
||||
and show in the draft as noise, so trash them before `seed` if they should
|
||||
not ship.
|
||||
- Dismiss first-run dialogs, such as a welcome screen, before `seed`. A
|
||||
choice the app saves only later, such as Inkscape's "show this every
|
||||
time", may not reach the seed, so expect the dialog in the witness too.
|
||||
- Some apps write their settings late: Freeplane writes
|
||||
`~/.config/freeplane/1.7.x/auto.properties` only once Preferences is
|
||||
confirmed, and a seed without it reopens its documentation map. Before
|
||||
`seed`, open the app's preferences and confirm them, then read a probe
|
||||
checkpoint's `changed_files` to see the settings file written.
|
||||
- Before `seed`, click into the document to clear any selection the app
|
||||
would save: Gnote saves its cursor and selection with the note.
|
||||
- An app whose state folder is named after it, such as
|
||||
`~/.local/share/gnote`, or after it and its version, such as TreeLine's
|
||||
`~/.treeline-3.1`, is found without `state_paths`.
|
||||
- TreeLine: File → New opens a template window. Book List's CATEGORY makes
|
||||
AUTHOR children by default; change it under Data → Configure Data Types →
|
||||
Default Child Type. A new child opens an inline rename showing "", so
|
||||
press Escape and fill its fields in the Data Edit tab. Ctrl+A adds a child
|
||||
node even while a field has focus. Clicking a node already selected starts
|
||||
an inline rename, so Ctrl+X then cuts its text: cut a node from its
|
||||
context menu. It saves nodes sorted by their
|
||||
generated uid1, so their order changes from run to run. The draft names a
|
||||
new node by its format and a field of its `data`,
|
||||
`/nodes/[format=BOOK][>data~1Title=The Silk Roads]`, and checks its other
|
||||
fields through that, so give each new node a title no other node has.
|
||||
- After an app crashes, capture again on a fresh computer, so the seed
|
||||
carries no crash-recovery state, such as MyPaint's "Recover interrupted
|
||||
work?".
|
||||
- Give what the task changes a stable name where the app has one, such as an
|
||||
id in Inkscape's Object Properties, so a check can select it.
|
||||
- Expect apps to split text into runs: Writer's revision ids split an
|
||||
@@ -121,17 +303,46 @@ the first source that has the app:
|
||||
`P1`, and AbiWord wraps each insertion in `<c>`. Check such text whole
|
||||
with `text_equals` (see Write the task), and find the paragraph by
|
||||
something the edit keeps, such as AbiWord's `xid`.
|
||||
- Freeplane's first launch opens a documentation map: close it with Ctrl+W.
|
||||
Its Ctrl+N asks for a template.
|
||||
- MyPaint 2.0.1 crashes on brush strokes on the build computer: build its
|
||||
seed with flood fill and layer operations.
|
||||
- GnuCash's Ctrl+S on a new book opens a Save dialog with no format choice:
|
||||
use File > Save As to pick XML. Close the book (File > New File) before
|
||||
`seed`, so its `.LCK` lock is not seeded.
|
||||
|
||||
## Build the seed and the edit
|
||||
|
||||
1. `start_build_computer` with
|
||||
`{"source": {"kind": "request", "desktop_entry": ..., "install": ...}}`.
|
||||
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
|
||||
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
|
||||
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.
|
||||
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 an icon loader or a Java
|
||||
runtime: close the computer and start a new one with that package in
|
||||
`extra_packages` (see Choose the install), 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. gLabels' title
|
||||
leaves out the file's extension and Grisbi's shows the entity's name,
|
||||
so both need it.
|
||||
- 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.
|
||||
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
|
||||
@@ -141,14 +352,71 @@ 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 a window title
|
||||
named first, then those under `state_paths` and 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. Compression may be off by default: Dia's
|
||||
"Compress diagram files" is unticked, which REA reads as plain XML. 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. When the task is about the app's own binary
|
||||
format, such as GIMP's `.xcf` or Blender's `.blend`, keep it and check
|
||||
it through a reader (see Read a binary file with a reader).
|
||||
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), `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.
|
||||
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. If a declared secret was used,
|
||||
automatic drafting is withheld: write the task manually and export it.
|
||||
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`. When the app
|
||||
keeps the task's state only on screen, such as a calculator's result,
|
||||
judge the screen instead (see Judge the screen).
|
||||
- `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, or judge the screen (see Judge the screen).
|
||||
- `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. Name a record that keeps its fields as child
|
||||
elements by one of them, as Osmo's contact by
|
||||
`[name=contact][>first_name=Delphine]`, a JSON record by a field
|
||||
inside it, `[>data/Title=…]` (`~1` for the `/` inside a pointer), or
|
||||
an element by an id its child carries, `[>object@id=…]`; count records
|
||||
with `member_count`, `matching` `[name=contact]`; otherwise check an
|
||||
ancestor's text, or give the element an id in the app 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). For
|
||||
a binary file, read it with a reader (see Read a binary file with a
|
||||
reader).
|
||||
|
||||
## Write the task
|
||||
|
||||
@@ -156,20 +424,49 @@ Write `{"name", "prompt", "checks"}` from the draft and what you did.
|
||||
|
||||
- `name`: lowercase letters, digits and hyphens, not `smoke`.
|
||||
- `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." Never say how the file stores it, and never give the checks.
|
||||
starting with the app's name, naming the document as a user would and
|
||||
ending with saving it: "In Inkscape, change the poster's headline in
|
||||
Documents/poster.svg to Summer Bake Sale and save it." Name the app: the
|
||||
solving agent's own shell cannot see the computer's files, and the app's
|
||||
name sends it to the screen. 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.
|
||||
- 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` (an uncut scalar, or
|
||||
a preview cut at 600 characters) at the pointer a check names it by. Copy
|
||||
the pointer. Copy `after` into `value` only when it is an uncut scalar: a
|
||||
string without a trailing `…`, a number, or a boolean. Compact XML and a
|
||||
JSON array or object are preview strings, so a `value_equals` check needs
|
||||
the structured value from the file's view, and element text uses
|
||||
`text_equals` or `text_contains`.
|
||||
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 or id stands for, such as `category="44"`
|
||||
naming `<cat key="44" name="Groceries"/>`, or a new KMyMoney
|
||||
transaction's splits naming their account and payee; use it for the
|
||||
prompt's words. `alternatives` gives a changed value's pointer by the
|
||||
element's other names, such as a label beside an id, to pick another key
|
||||
without another export.
|
||||
Skip entries whose `note` is `by_position` (no check can use that
|
||||
pointer) or noise (`view_state`, `renumbered`, `volatile`,
|
||||
`timestamp`, `upkeep`, `layout`). `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 may suggest positional pointers; rewrite
|
||||
them. Only an element's text is read by position, as `children/0`.
|
||||
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`.
|
||||
- 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
|
||||
@@ -178,15 +475,48 @@ 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; 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/`.
|
||||
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: the draft names it by its
|
||||
label cell, `[name=table:table-row][>table:table-cell=February]`. Where no
|
||||
cell names it alone, 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.
|
||||
- For a note placed by its own `x` and `y`, such as Xournal++'s `<text>`
|
||||
on a layer, the draft checks its text on the layer with `text_contains`,
|
||||
which passes wherever the user puts it, and guards each note it kept.
|
||||
- Some apps keep text in an attribute, one element per run, such as
|
||||
Scribus's `<ITEXT CH=...>`: add `"text_attribute": "CH"` to `text_equals`
|
||||
or `text_contains` on the frame,
|
||||
`/root/children/[name=DOCUMENT]/children/[name=PAGEOBJECT][@ANNAME=Headline]`,
|
||||
to read its runs' values joined.
|
||||
- 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.
|
||||
- Where easy, add one check that the rest is untouched, such as another
|
||||
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.
|
||||
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.
|
||||
- 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
|
||||
@@ -200,6 +530,124 @@ Write `{"name", "prompt", "checks"}` from the draft and what you did.
|
||||
The kinds and pointer rules are in
|
||||
[the desktop tasks section](environments.md#pick-the-checks).
|
||||
|
||||
### Read a binary file with a reader
|
||||
|
||||
When the draft notes `unreadable_view` on a binary document, add a reader to
|
||||
the task: the app's own headless command, which REA runs in the computer on a
|
||||
private copy of the file, and whose output a check reads instead of the file.
|
||||
Write it in the app's scripting mode, print each fact on a line starting
|
||||
with `REA ` (with the space), and name the copy `{file}`:
|
||||
|
||||
- GIMP `.xcf`, layer names, as `lines`:
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "layers",
|
||||
"file": "Documents/poster.xcf",
|
||||
"argv": ["gimp-console-2.10", "-i", "-d", "-f", "-b", "-"],
|
||||
"stdin": "(let ((image (car (gimp-file-load RUN-NONINTERACTIVE \"{file}\" \"{file}\")))) (for-each (lambda (layer) (display \"\\nREA layer \") (display (car (gimp-item-get-name layer)))) (vector->list (cadr (gimp-image-get-layers image)))) (newline))\n(gimp-quit 0)\n",
|
||||
"output": "lines"
|
||||
}
|
||||
```
|
||||
|
||||
checked with `{"kind": "lines_present", "file": "Documents/poster.xcf", "reader": "layers", "lines": ["layer Summer Sale"]}`.
|
||||
Script-Fu's prompt `ts> ` starts a line, so print a newline before each
|
||||
marked line, as `\nREA` does. A text layer's text is
|
||||
`(car (gimp-text-layer-get-text layer))`.
|
||||
|
||||
- Blender `.blend`, objects with their type and location, as `json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "objects",
|
||||
"file": "Documents/scene.blend",
|
||||
"argv": [
|
||||
"blender",
|
||||
"-b",
|
||||
"--factory-startup",
|
||||
"{file}",
|
||||
"--python-expr",
|
||||
"import bpy, json; print('REA ' + json.dumps({o.name: {'type': o.type, 'location': [round(v, 4) for v in o.location]} for o in bpy.data.objects}, sort_keys=True))"
|
||||
],
|
||||
"output": "json"
|
||||
}
|
||||
```
|
||||
|
||||
checked with `{"kind": "value_equals", "file": "Documents/scene.blend", "reader": "objects", "pointer": "/Crate/location/0", "value": 2, "tolerance": 0.001}`.
|
||||
Print every value a check compares as a number or string a check can
|
||||
name, rounded where the app stores floats.
|
||||
Blender 4 shows its Quick Setup splash at every launch until its
|
||||
preferences are saved: with `.config/blender` in `state_paths`, confirm
|
||||
Quick Setup with Continue, save the preferences (Edit → Preferences, then
|
||||
Save Preferences in the menu at its bottom left), and read a probe
|
||||
checkpoint's `changed_files` for `.config/blender/4.0/config/userpref.blend`
|
||||
before `seed`, so solves start on the scene. Blender often takes the first click on a
|
||||
menu or a dialog's button only to focus it: click again.
|
||||
|
||||
- A format LibreOffice opens but REA cannot read, such as a legacy `.xls`,
|
||||
converted with `--convert-to`:
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "cells",
|
||||
"file": "Documents/budget.xls",
|
||||
"argv": [
|
||||
"sh",
|
||||
"-c",
|
||||
"soffice --headless --convert-to csv --outdir out \"$1\" >/dev/null && sed 's/^/REA /' out/*.csv",
|
||||
"sh",
|
||||
"{file}"
|
||||
],
|
||||
"output": "lines",
|
||||
"timeout_s": 120
|
||||
}
|
||||
```
|
||||
|
||||
Pass `{file}` to `sh -c` as an argument, as here, rather than inside the
|
||||
script.
|
||||
|
||||
The reader runs without the display, in a fresh home with the app's default
|
||||
settings, so use the app's headless or batch mode; set `display: true` only
|
||||
for an app that has none. It must exit 0 within `timeout_s` (60 s by
|
||||
default, at most 300) and print at most 1 MiB. Pick facts the change sets and
|
||||
the near miss gets wrong, such as a name or a number, not the app's whole
|
||||
output.
|
||||
|
||||
Give the task the reader in `readers`, and each check through it `reader`
|
||||
and the reader's `file`. `json` readers serve `value_equals`, `value_absent`
|
||||
and `member_count`; `lines` readers `lines_present`, `lines_absent` and
|
||||
`line_count`. The export runs the reader in the build computer on the seed
|
||||
and the end: when a check through it fails on the end, the refusal shows
|
||||
what the reader printed, and a reader that fails shows its error and the end
|
||||
of its stderr. Fix the reader or the check from that and export again.
|
||||
|
||||
### Judge the screen
|
||||
|
||||
Only when no file shows the change, as when the draft notes `no_change`
|
||||
because the app keeps its state on screen, write the task's checks as
|
||||
screen judges: `{"id": "shown", "kind": "screen_judge", "question": "Does the
|
||||
calculator's display show 8.568?"}`. A model, the judge, answers the question
|
||||
on a screenshot three times, and the check passes when most answers are yes.
|
||||
|
||||
- REA keeps a screenshot at each checkpoint. Mark `seed` with the screen
|
||||
showing the state before the task, where the answer is no, and `end` with
|
||||
the change showing, where it is yes: the bundle ships both as the judge's
|
||||
examples.
|
||||
- Ask about what the change makes visible, with exact values, so the near
|
||||
miss is a no: a result, a label, a selected item. Avoid what a window
|
||||
moved or a cursor blinking can change.
|
||||
- The prompt asks to leave the result showing, since the judge sees only
|
||||
the screen when the agent stops.
|
||||
- A task with screen judges holds only screen judges and no readers. The
|
||||
export refuses one when a file shows the change, and checks none of its
|
||||
questions: the witness does, running the bundle's own judge with the
|
||||
runner's model endpoint (`LITELLM_BASE_URL` and `LITELLM_API_KEY`, or
|
||||
`[model]` in `.agentenv/config.toml`) on a fresh screenshot at each stage.
|
||||
Without an endpoint the witness's check fails: say what to set and stop.
|
||||
- The judge's model is `[model.roles] judge`, else `[model] default`, else
|
||||
`anthropic/claude-sonnet-5-5`. `agent-env run --judge-model` does not
|
||||
reach it. Each grade costs about $0.02.
|
||||
|
||||
## Export
|
||||
|
||||
`export_build_environment` with `task` and `directory`, the absolute path of
|
||||
@@ -211,10 +659,36 @@ unless at least one check fails on the seed and every check passes at the
|
||||
end, and says why, such as a pointer that names nothing at the end. A
|
||||
check that the rest is untouched passes on the seed too, which is fine. On
|
||||
a refusal, fix the task and export again, into another folder if that one
|
||||
is no longer empty. Keep
|
||||
is no longer empty. A refusal naming a secret's handle means a file of the
|
||||
bundle holds that secret, most often an app's sign-in or licence state in
|
||||
the seed: do not work around it, but report it and stop. 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>#`, GnuCash's `<book>.LCK` or Grisbi's `.<file>.lock`, are
|
||||
left out of the seed and listed after "Left out of the seed". An app can
|
||||
still start fine yet refuse every save when a lock was seeded, so close the
|
||||
document before `seed` where the app lets you (apps other than LibreOffice,
|
||||
such as Rosegarden, also write `.~lock.<name>#` and autosaves beside a
|
||||
document, and closing it covers them too), and treat "file is locked"
|
||||
on a save in the witness as a seeded lock: delete it from the bundle's seed
|
||||
and witness again in a new computer. In LibreOffice, own the profile
|
||||
(`state_paths: [".config/libreoffice"]`) for a clean boot, and close the
|
||||
document before `seed`, then reopen it from Recent Documents to make the
|
||||
change: the export also leaves out the recovery list LibreOffice writes while
|
||||
a document is open, which would start the bundle into document recovery. A
|
||||
limitation naming `~/.config/dconf/user` as unread means the app's dconf
|
||||
settings, such as a first-run tip you turned off, are not seeded: capture
|
||||
again on a new build computer. The limitations also name seeded WebKit,
|
||||
Chromium or QtWebEngine 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.
|
||||
|
||||
@@ -226,17 +700,27 @@ check between stages to steer the edit: a solving agent never sees the
|
||||
checks. Give every `check_build_task` the task exactly as exported.
|
||||
|
||||
1. `start_build_computer` with
|
||||
`{"source": {"kind": "bundle", "path": "<bundle>"}}`. The app starts
|
||||
`{"source": {"kind": "bundle", "path": "<bundle>"}}`, adding
|
||||
`"settings": {"<variable>": "<handle>"}` for each of the export's
|
||||
`withheld_files`, or the deploy is refused for want of them, and agentenv
|
||||
keeps that bundle's build failed, so start from a fresh copy of it. The app starts
|
||||
with the seed's files in place and opens the seed's document when the
|
||||
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.
|
||||
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.
|
||||
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.
|
||||
@@ -262,14 +746,17 @@ Stop after three witnesses and report what still fails.
|
||||
|
||||
## Solver runs
|
||||
|
||||
Only if the requester asked for them. If they wanted to review the task
|
||||
first, show them its prompt and checks and wait for their approval. Then run
|
||||
the bundle within the budget, one run at a time, with the runner
|
||||
`REA_AGENT_ENV_COMMAND` names:
|
||||
Only if the requester asked for them, or by the headless default above. If
|
||||
they wanted to review the task first, show them its prompt and checks and
|
||||
wait for their approval. Then run the bundle within the budget, one run at a
|
||||
time, with `REA_AGENT_ENV_COMMAND`'s runner, or else `agent-env` on PATH:
|
||||
`agent-env run <bundle> --task <name> --agent claude-code --model <model>`.
|
||||
Count runs reported `passed`. A run `scored below 1` is a miss; one reported
|
||||
`failed` did not finish, so run it again if the budget allows instead of
|
||||
counting it. Never run past the budget.
|
||||
The runner needs a model endpoint in your shell: `LITELLM_BASE_URL` and
|
||||
`LITELLM_API_KEY`, or `base_url` and `api_key` under `[model]` in
|
||||
`.agentenv/config.toml`. When a run says no model endpoint is set, tell the
|
||||
person what to set and stop. Count runs reported `passed`. A run
|
||||
`scored below 1` is a miss; one reported `failed` did not finish, so run it
|
||||
again if the budget allows instead of counting it. Never run past the budget.
|
||||
|
||||
## Close and report
|
||||
|
||||
@@ -281,12 +768,15 @@ Report:
|
||||
|
||||
- the bundle path and the environment name;
|
||||
- the task's name and prompt;
|
||||
- each check, and why it proves the edit and fails the near miss;
|
||||
- each check, and why it proves the edit and fails the near miss, and each
|
||||
reader's command;
|
||||
- each witness stage with its result, the verdict, and the paths of
|
||||
`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;
|
||||
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;
|
||||
- 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,14 +308,27 @@ 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
|
||||
|
||||
Say what the user wants done, in their words and the app's terms: "Add buy
|
||||
milk to my to-do list and save it". Never say how the file stores it: no
|
||||
Say what the user wants done, in their words and the app's terms, naming the
|
||||
app: "In Mousepad, add buy milk to my to-do list and save it". A solving
|
||||
agent's own shell cannot see the computer's files; the app's name sends it to
|
||||
the screen. Never say how the file stores it: no
|
||||
paths the user would not name, line formats, XML, keys or SQL, and never the
|
||||
checks. Replace the draft's placeholder; the export refuses it.
|
||||
|
||||
@@ -346,13 +359,18 @@ 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. Give
|
||||
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
|
||||
`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
|
||||
text node: apps such as AbiWord and Writer split a paragraph into runs as they
|
||||
save, so its first text node holds only part of it; use `text_contains` for a
|
||||
value within a sentence, such as a time. The
|
||||
value within a sentence, such as a time. A binary document, such as GIMP's
|
||||
`.xcf`, has no view: give the task a `readers` entry, the app's own headless
|
||||
command printing `REA ` lines, and a check naming it in `reader`, as
|
||||
[desktop builds](desktop-build.md#read-a-binary-file-with-a-reader) shows. The
|
||||
[desktop application tasks](https://github.com/morluto/rea/blob/main/docs/desktop-application-tasks.md)
|
||||
guide has the exact rules.
|
||||
|
||||
@@ -374,5 +392,7 @@ user's to choose.
|
||||
|
||||
Tell the user the task's name, prompt and checks, and how to measure a solve
|
||||
rate: run `agent-env run DIRECTORY --task NAME --agent claude-code` with
|
||||
`--model MODEL` three times and count the runs reported `passed`. Do not run
|
||||
`--model MODEL` three times and count the runs reported `passed`. The runs
|
||||
need a model endpoint: `LITELLM_BASE_URL` and `LITELLM_API_KEY`, or
|
||||
`base_url` and `api_key` under `[model]` in `.agentenv/config.toml`. Do not run
|
||||
agents unless asked. The bundle's seed is the user's real data: keep it local.
|
||||
@@ -149,6 +149,20 @@ 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
|
||||
@@ -185,6 +199,36 @@ absence of those declarations, not proof the image never carried notes in
|
||||
another container. See
|
||||
[ELF note tables](https://github.com/morluto/rea/blob/main/docs/elf-notes.md).
|
||||
|
||||
## ELF and Mach-O initializer functions
|
||||
|
||||
Use `inspect_native_initializers` for an explicit local ELF or Mach-O image
|
||||
when the question is which functions run before `main` or at exit: ELF
|
||||
`DT_PREINIT_ARRAY`, `DT_INIT`, `DT_INIT_ARRAY`, `DT_FINI`, `DT_FINI_ARRAY` and
|
||||
legacy `.ctors`/`.dtors`, or Mach-O `__mod_init_func`, `__init_offsets` and
|
||||
`__mod_term_func`. Pass `architecture` for a universal Mach-O. The CLI
|
||||
equivalent is `inspect-native-initializers PATH`. PIE slots are resolved
|
||||
through RELATIVE, RELR and section relocations, and Mach-O slots through
|
||||
chained fixups. Keep each entry's `resolution`: `unresolved` means the value was
|
||||
not established, and `unresolved_import` names an external symbol. Page with
|
||||
`offset` and `limit`. See
|
||||
[ELF and Mach-O initializer functions](https://github.com/morluto/rea/blob/main/docs/guides/native/native-initializers.md).
|
||||
|
||||
## ELF unwind function ranges
|
||||
|
||||
Use `inspect_elf_unwind_ranges` for an explicit local ELF32/ELF64 image when
|
||||
the question concerns function starts and lengths that survive `strip`, which
|
||||
functions have an LSDA, or which ranges have no exact symbol. No
|
||||
`open_binary` or target execution is required. The CLI equivalent is
|
||||
`inspect-elf-unwind-ranges PATH`. Preserve artifact SHA-256, FDE start and
|
||||
end, containing section, exact symbol name, CIE index, LSDA, and personality.
|
||||
Page later ranges with `offset` and `limit`. A missing `.eh_frame` is
|
||||
observed absence of that declaration and of `PT_GNU_EH_FRAME`, not proof the
|
||||
image has no functions. Header disagreement is a limitation and does not drop
|
||||
decoded ranges. `.debug_frame` is reported present or absent and is not
|
||||
decoded. CFA instructions are counted and not evaluated. Indirect EH pointers
|
||||
are not dereferenced. See
|
||||
[ELF unwind function ranges](https://github.com/morluto/rea/blob/main/docs/guides/native/elf-unwind-ranges.md).
|
||||
|
||||
## Apple IPS crash reports
|
||||
|
||||
Use `inspect_apple_ips` for an explicit local Apple `.ips` file when the
|
||||
@@ -216,6 +260,27 @@ container. gzip, xz, and zstd whole-file containers are unsupported and name
|
||||
decompress into a separate file, then call `inspect_kernel_module` on that file. See
|
||||
[Linux kernel modules](https://github.com/morluto/rea/blob/main/docs/kernel-modules.md).
|
||||
|
||||
## Linux kernel build config
|
||||
|
||||
Use `inspect_kernel_build_config` for an explicit local kernel image (`vmlinux`
|
||||
ELF, raw arm64 `Image`, x86 `bzImage`/`zImage`, or `configs.ko`) when the
|
||||
question is which kernel version it is or how it was configured. No
|
||||
`open_binary`, Linux host, or `extract-ikconfig` is required. The CLI
|
||||
equivalent is `inspect-kernel-build-config PATH`; pass `name` for one exact
|
||||
`CONFIG_*` option and `offset`/`limit` to page the rest. Preserve the banner
|
||||
version, builder, and compiler, the config SHA-256 and option count, and each
|
||||
entry's value kind (`y`, `m`, `string`, `number`, `not_set`). A config is
|
||||
accepted only when `IKCFG_ST` is immediately followed by a valid gzip member
|
||||
and `IKCFG_ED`, so an ordinary `IKCFG_ST` string is not a config. Offsets with
|
||||
`space: "inflated_payload"` are positions in an inflated bzImage payload, not
|
||||
file offsets. An absent config describes only the searched bytes; the kernel
|
||||
may have been built without `CONFIG_IKCONFIG` or with it as a module. Truncated
|
||||
payloads are incomplete, not absent. A framed blob that does not decode, has a
|
||||
bad CRC, or holds non-config text is `malformed`, not absent. xz, lz4, lzma, zstd, bzip2, and lzo
|
||||
payloads are unsupported and name `external_decompression`: decompress with an
|
||||
external utility, then call `inspect_kernel_build_config` on the result. See
|
||||
[Linux kernel build config](https://github.com/morluto/rea/blob/main/docs/guides/native/kernel-build-config.md).
|
||||
|
||||
## CPython pyc files
|
||||
|
||||
Use `inspect_python_pyc` for an explicit local CPython 3.7–3.13 `.pyc` when the
|
||||
@@ -843,3 +908,24 @@ Layout labels describe record shapes, not a detected compiler version; unknown
|
||||
or ambiguous layouts are unsupported. Bytecode is retained, not decoded, and the
|
||||
executable is never run. See
|
||||
[Bun standalone executables](https://github.com/morluto/rea/blob/main/docs/bun-standalone.md).
|
||||
|
||||
## Deno compile executables
|
||||
|
||||
A `deno compile` executable stores its application in a Mach-O `__SUI,d3n0l4nd`
|
||||
section, an Intel Mach-O `<~sui-data~>` trailer, an ELF `SUI` note of type
|
||||
`0x53554901`, or a PE `RT_RCDATA` resource named `D3N0L4ND`.
|
||||
`open_binary` then `inspect_artifact` reports root format `deno-standalone`
|
||||
with the carrier, entry point, recorded options, and one occurrence per virtual
|
||||
file, including size and SHA-256. Transpiled output, CJS export analysis, and
|
||||
source maps are separate occurrences with the file's `index` and their own
|
||||
`role`. They normally use a `.deno-*` suffix on the file path and move to an
|
||||
indexed path on a collision, so use the reported `logical_path`. Symlink targets
|
||||
stay recorded path parts. A virtual filesystem that cannot be listed leaves
|
||||
coverage unknown.
|
||||
Environment-file values and CA certificate bytes are retained in local Evidence
|
||||
with their counts and byte lengths. The npm snapshot length is reported and not
|
||||
decoded. `extract-artifact` writes
|
||||
stored files through the safe output tree; route extracted JavaScript to
|
||||
`analyze_javascript_application`. Other layouts are unsupported, and the
|
||||
executable is never run. See
|
||||
[Deno compile executables](https://github.com/morluto/rea/blob/main/docs/deno-standalone.md).
|
||||
@@ -41,6 +41,12 @@ 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,6 +924,7 @@ 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,3 +95,31 @@ 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"
|
||||
@@ -1,7 +1,7 @@
|
||||
<div align="center">
|
||||
|
||||
**English** · [简体中文](docs/readme/README_zh.md) · [繁體中文](docs/readme/README_zh-TW.md) · [日本語](docs/readme/README_ja.md) · [한국어](docs/readme/README_ko.md) · [Türkçe](docs/readme/README_tr.md) · [Русский](docs/readme/README_ru.md) · [Tiếng Việt](docs/readme/README_vi.md) · [ไทย](docs/readme/README_th.md) · [Deutsch](docs/readme/README_de.md) · [Español](docs/readme/README_es.md) · [Français](docs/readme/README_fr.md) · [Українська](docs/readme/README_uk.md) · [Polski](docs/readme/README_pl.md) · [Português (Brasil)](docs/readme/README_pt-BR.md) · [العربية](docs/readme/README_ar.md) · [فارسی](docs/readme/README_fa.md) · [Bahasa Indonesia](docs/readme/README_id.md) · [Italiano](docs/readme/README_it.md)
|
||||
· [Ελληνικά](docs/readme/README_el.md) · [മലയാളം](docs/readme/README_ml.md) · [Roman Urdu](docs/readme/README_ur-Latn.md) · [Română](docs/readme/README_ro.md)
|
||||
· [Ελληνικά](docs/readme/README_el.md) · [മലയാളം](docs/readme/README_ml.md) · [Roman Urdu](docs/readme/README_ur-Latn.md) · [Română](docs/readme/README_ro.md) · [Български](docs/readme/README_bg.md)
|
||||
|
||||
# REA: Reverse Engineer Anything
|
||||
|
||||
@@ -204,6 +204,7 @@ 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) |
|
||||
@@ -230,6 +231,7 @@ Additional tools and host support depend on the target:
|
||||
| Packages and resources | File inventories, digests, plists, Apple bundle anatomy and extracted resources | [Artifact and JavaScript guide](docs/guides/javascript/javascript-artifact-reconstruction.md), [Apple applications](docs/guides/apple/apple-application-analysis.md) |
|
||||
| Process behavior | Terminal output, interactions, exit and filesystem observations, and run comparisons | Linux/macOS with a native PTY; [process capture](docs/guides/runtime/process-capture.md) |
|
||||
| PyInstaller executables | CArchive members, Python version, entry scripts and extracted bytecode | None (static only); [Python packaged applications](docs/python-packaged-applications.md) |
|
||||
| Deno compile binaries | Virtual files, entry point, recorded options, npm snapshot length | None (static only); [Deno compile executables](docs/deno-standalone.md) |
|
||||
|
||||
Static JavaScript and .NET inspection read the supplied files without running
|
||||
the application. Runtime capture runs or interacts with the selected target
|
||||
@@ -335,6 +337,12 @@ REA exports a runnable environment with a basic test to check that it starts and
|
||||
[Environment reference](docs/agent-environments.md) ·
|
||||
[Watch the demo on X](https://x.com/reatools/status/2112574822584918075?s=20)
|
||||
|
||||
### Desktop app environments
|
||||
|
||||
REA can also build an environment of a Linux desktop app, which an agent uses through screenshots, the mouse and the keyboard. From a one-line request, such as "Build me a Gnote environment where the agent adds olive oil to the shopping list note", your agent installs the app on a local build computer, writes the task, exports the environment and checks the task in a fresh computer. The machine that builds it needs Linux on amd64 or arm64, Docker and the agentenv framework version the guide pins.
|
||||
|
||||
[Set up desktop app environments](docs/desktop-build-computer.md)
|
||||
|
||||
## FAQ
|
||||
|
||||
<details>
|
||||
|
||||
+255
-12
@@ -1,7 +1,9 @@
|
||||
"""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>``; each command prints one JSON line and exits. ``start``
|
||||
``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``
|
||||
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
|
||||
@@ -91,6 +93,13 @@ 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:
|
||||
@@ -119,17 +128,49 @@ 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 {"exited": code, "progress": _tail(log), "output": _tail(os.path.join(capture, "capture.out"))}
|
||||
return _ended(capture, code)
|
||||
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))
|
||||
@@ -143,20 +184,38 @@ 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.
|
||||
reader = os.open(control, os.O_RDWR)
|
||||
process = None
|
||||
try:
|
||||
with open(os.path.join(capture, "capture.out"), "wb") as out, \
|
||||
open(os.path.join(capture, "progress.log"), "wb") as progress:
|
||||
process = subprocess.Popen(
|
||||
["sh", "-c", 'done=$1; shift; "$@"; code=$?; printf "%s" "$code" > "$done.tmp" && mv "$done.tmp" "$done"',
|
||||
"sh", os.path.join(capture, "exit"), *argv],
|
||||
cwd=os.path.expanduser("~"), env=_environment(work), stdin=reader, stdout=out, stderr=progress,
|
||||
start_new_session=True)
|
||||
try:
|
||||
with open(os.path.join(capture, "capture.out"), "wb") as out, \
|
||||
open(os.path.join(capture, "progress.log"), "wb") as progress:
|
||||
process = subprocess.Popen(
|
||||
["sh", "-c", 'done=$1; shift; "$@"; code=$?; printf "%s" "$code" > "$done.tmp" && mv "$done.tmp" "$done"',
|
||||
"sh", os.path.join(capture, "exit"), *argv],
|
||||
cwd=os.path.expanduser("~"), env=_environment(work), stdin=reader, stdout=out, stderr=progress,
|
||||
start_new_session=True)
|
||||
except Exception as cause:
|
||||
# Nothing will write exit. Record one and drop the FIFO, so stop does not wait on it.
|
||||
try:
|
||||
with open(os.path.join(capture, "exit"), "w", encoding="utf-8") as handle:
|
||||
handle.write("1")
|
||||
except OSError:
|
||||
pass
|
||||
try:
|
||||
os.unlink(control)
|
||||
except OSError:
|
||||
pass
|
||||
return _say({"error": f"the capture did not start: {cause}"})
|
||||
finally:
|
||||
os.close(reader)
|
||||
if process is None:
|
||||
return _say({"error": "the capture did not start"})
|
||||
waited = _wait(capture, 0, {"window_open"}, None, arguments.get("timeout_s", 120))
|
||||
return _say({"pid": process.pid, "apt": apt, **waited})
|
||||
|
||||
@@ -175,11 +234,13 @@ 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({"exited": code, "progress": _tail(log)})
|
||||
return _say(_ended(capture, code))
|
||||
# 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:
|
||||
@@ -229,6 +290,187 @@ def run(arguments: dict) -> int:
|
||||
"stderr": done.stderr[-TAIL_BYTES:].decode("utf-8", "replace")})
|
||||
|
||||
|
||||
# The controller is sent with python -c, so a detached supervisor needs its
|
||||
# own source. It alone holds the child process handle and signals its group.
|
||||
LONG_RUN = r'''
|
||||
import json, os, signal, subprocess, sys, threading, time
|
||||
job = sys.argv[1]
|
||||
result = {}
|
||||
child = None
|
||||
drainer = None
|
||||
stderr_tail, stderr_errors = bytearray(), []
|
||||
|
||||
def drain(stream):
|
||||
try:
|
||||
while chunk := stream.read1(65536):
|
||||
stderr_tail.extend(chunk)
|
||||
del stderr_tail[:-4096]
|
||||
except OSError as error:
|
||||
stderr_errors.append(str(error))
|
||||
finally:
|
||||
try:
|
||||
stream.close()
|
||||
except OSError as error:
|
||||
stderr_errors.append(str(error))
|
||||
|
||||
def timed_out_marker():
|
||||
try:
|
||||
open(os.path.join(job, "timed_out"), "x").close()
|
||||
except FileExistsError:
|
||||
pass
|
||||
|
||||
try:
|
||||
request = json.loads("".join(sys.argv[2:]))
|
||||
if os.path.exists(os.path.join(job, "cancel")):
|
||||
result = {"absent": True}
|
||||
else:
|
||||
with open(request["stdout"], "wb") as out:
|
||||
child = subprocess.Popen(request["argv"], cwd=request["home"], stdin=subprocess.DEVNULL,
|
||||
stdout=out, stderr=subprocess.PIPE, start_new_session=True)
|
||||
drainer = threading.Thread(target=drain, args=(child.stderr,), daemon=True)
|
||||
drainer.start()
|
||||
deadline = time.monotonic() + request["timeout_s"]
|
||||
interrupted = False
|
||||
timed_out = False
|
||||
while child.poll() is None:
|
||||
timed_out = timed_out or time.monotonic() >= deadline
|
||||
if not interrupted and (timed_out or os.path.exists(os.path.join(job, "cancel"))):
|
||||
interrupted = True
|
||||
if timed_out:
|
||||
timed_out_marker()
|
||||
try:
|
||||
os.killpg(child.pid, signal.SIGINT)
|
||||
except OSError:
|
||||
pass
|
||||
time.sleep(0.2)
|
||||
# A descendant can still hold stderr after the leader exits. Do
|
||||
# not publish completion until that stream has actually closed.
|
||||
while drainer.is_alive():
|
||||
drainer.join(0.2)
|
||||
if time.monotonic() >= deadline:
|
||||
timed_out = True
|
||||
timed_out_marker()
|
||||
result = {"exit_code": child.returncode, "stdout_bytes": os.path.getsize(request["stdout"]),
|
||||
"timed_out": timed_out, "cancelled": interrupted and not timed_out,
|
||||
"stderr": bytes(stderr_tail).decode("utf-8", "replace")}
|
||||
if stderr_errors:
|
||||
result["error"] = f"The REA command's stderr could not be read: {stderr_errors[0]}"
|
||||
except Exception as error:
|
||||
result["error"] = f"The REA command supervisor failed: {error}"
|
||||
# Keep the child handle until it exits, including when cancellation arrives
|
||||
# after an unexpected supervisor error.
|
||||
while child is not None and child.poll() is None:
|
||||
if os.path.exists(os.path.join(job, "cancel")):
|
||||
try:
|
||||
os.killpg(child.pid, signal.SIGINT)
|
||||
except OSError:
|
||||
pass
|
||||
time.sleep(0.2)
|
||||
if drainer is not None and drainer.ident is not None:
|
||||
drainer.join()
|
||||
if child is not None:
|
||||
result.setdefault("exit_code", child.returncode)
|
||||
result.setdefault("stderr", bytes(stderr_tail).decode("utf-8", "replace"))
|
||||
try:
|
||||
result.setdefault("stdout_bytes", os.path.getsize(request["stdout"]))
|
||||
except OSError:
|
||||
pass
|
||||
if child is None or child.poll() is not None:
|
||||
temporary = os.path.join(job, "result.tmp")
|
||||
with open(temporary, "w", encoding="utf-8") as out:
|
||||
json.dump(result, out)
|
||||
os.replace(temporary, os.path.join(job, "result.json"))
|
||||
'''
|
||||
|
||||
|
||||
def run_begin(arguments: dict) -> int:
|
||||
"""Start one long REA command in its own capture-owned job folder."""
|
||||
rea = shutil.which("rea")
|
||||
if rea is None:
|
||||
return _say({"error": "REA is not installed in this computer"})
|
||||
job = os.path.abspath(arguments["job"])
|
||||
os.makedirs(os.path.dirname(job), exist_ok=True)
|
||||
try:
|
||||
os.mkdir(job, 0o700)
|
||||
except FileExistsError:
|
||||
return _say({"refused": "the command job folder is already used"})
|
||||
process = None
|
||||
try:
|
||||
with open(os.path.join(job, "owner"), "x", encoding="ascii") as out:
|
||||
out.write(arguments["token"])
|
||||
for path, text in arguments.get("files", {}).items():
|
||||
os.makedirs(os.path.dirname(path), exist_ok=True)
|
||||
with open(path, "w", encoding="utf-8") as handle:
|
||||
handle.write(text)
|
||||
os.makedirs(os.path.dirname(arguments["stdout"]), exist_ok=True)
|
||||
request = json.dumps({"argv": [rea, *arguments["argv"]], "stdout": arguments["stdout"],
|
||||
"home": os.path.expanduser("~"), "timeout_s": arguments["timeout_s"]})
|
||||
chunks = [request[i:i + 60000] for i in range(0, len(request), 60000)]
|
||||
with open(os.path.join(job, "supervisor.log"), "wb") as log:
|
||||
process = subprocess.Popen([sys.executable, "-I", "-c", LONG_RUN, job, *chunks], cwd=os.path.expanduser("~"),
|
||||
env=_environment(os.path.abspath(arguments["work"])), stdin=subprocess.DEVNULL,
|
||||
stdout=log, stderr=log, start_new_session=True)
|
||||
except (OSError, ValueError) as error:
|
||||
stage = "did not start" if process is None else "started but its setup did not finish"
|
||||
result = {"error": f"The REA command supervisor {stage}: {error}"}
|
||||
if process is None:
|
||||
temporary = os.path.join(job, "result.tmp")
|
||||
with open(temporary, "w", encoding="utf-8") as out:
|
||||
json.dump(result, out)
|
||||
os.replace(temporary, os.path.join(job, "result.json"))
|
||||
return _say(result)
|
||||
return _say({"started": True})
|
||||
|
||||
|
||||
def _run_result(job: str):
|
||||
try:
|
||||
with open(os.path.join(job, "result.json"), encoding="utf-8") as source:
|
||||
return json.load(source)
|
||||
except FileNotFoundError:
|
||||
return None
|
||||
|
||||
|
||||
def _owns_run(job: str, token: str) -> bool:
|
||||
try:
|
||||
with open(os.path.join(job, "owner"), encoding="ascii") as owner:
|
||||
return owner.read() == token
|
||||
except OSError:
|
||||
return False
|
||||
|
||||
|
||||
def run_poll(arguments: dict) -> int:
|
||||
job = os.path.abspath(arguments["job"])
|
||||
if not _owns_run(job, arguments["token"]):
|
||||
return _say({"error": "the command job ownership is not confirmed"})
|
||||
deadline = time.monotonic() + arguments.get("timeout_s", 30)
|
||||
while (result := _run_result(job)) is None and time.monotonic() < deadline:
|
||||
time.sleep(POLL_S)
|
||||
if result is None:
|
||||
pending = {"pending": True, "timed_out": os.path.exists(os.path.join(job, "timed_out"))}
|
||||
progress = _tail(os.path.join(job, "supervisor.log"))
|
||||
return _say({**pending, **({"progress": progress} if progress else {})})
|
||||
return _say({"finished": True, **result})
|
||||
|
||||
|
||||
def run_cancel(arguments: dict) -> int:
|
||||
job = os.path.abspath(arguments["job"])
|
||||
os.makedirs(os.path.dirname(job), exist_ok=True)
|
||||
try:
|
||||
os.mkdir(job, 0o700)
|
||||
except FileExistsError:
|
||||
pass
|
||||
else:
|
||||
# A late begin cannot launch into a folder cancellation claimed.
|
||||
with open(os.path.join(job, "owner"), "x", encoding="ascii") as owner:
|
||||
owner.write(arguments["token"])
|
||||
return _say({"absent": True})
|
||||
if not _owns_run(job, arguments["token"]):
|
||||
return _say({"error": "the command job ownership is not confirmed"})
|
||||
with open(os.path.join(job, "cancel"), "a", encoding="utf-8"):
|
||||
pass
|
||||
return run_poll(arguments)
|
||||
|
||||
|
||||
def listing(arguments: dict) -> int:
|
||||
"""Every regular file under a folder, by its path relative to the home, with its size and SHA-256.
|
||||
|
||||
@@ -267,7 +509,8 @@ def listing(arguments: dict) -> int:
|
||||
return _say({"listing_bytes": os.path.getsize(output)})
|
||||
|
||||
|
||||
COMMANDS = {"start": start, "mark": mark, "stop": stop, "run": run, "list": listing}
|
||||
COMMANDS = {"start": start, "mark": mark, "stop": stop, "run": run, "list": listing,
|
||||
"run-begin": run_begin, "run-poll": run_poll, "run-cancel": run_cancel}
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(COMMANDS[sys.argv[1]](json.loads(sys.argv[2])))
|
||||
sys.exit(COMMANDS[sys.argv[1]](json.loads("".join(sys.argv[2:]))))
|
||||
@@ -1,12 +1,17 @@
|
||||
"""Exercise the capture controller's filesystem inventory boundary."""
|
||||
|
||||
import json
|
||||
import io
|
||||
from contextlib import redirect_stdout
|
||||
import os
|
||||
from pathlib import Path
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
import unittest
|
||||
from unittest.mock import patch
|
||||
|
||||
from bridge.agentenv import capture
|
||||
|
||||
|
||||
CONTROLLER = Path(__file__).with_name("capture.py")
|
||||
@@ -60,5 +65,168 @@ class CaptureListingTest(unittest.TestCase):
|
||||
self.assertFalse(output.exists())
|
||||
|
||||
|
||||
@unittest.skipIf(sys.platform == "win32", "desktop build computers use Linux")
|
||||
class LongRunTest(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.tmp = tempfile.TemporaryDirectory()
|
||||
self.addCleanup(self.tmp.cleanup)
|
||||
self.root = Path(self.tmp.name)
|
||||
self.bin = self.root / "bin"
|
||||
self.bin.mkdir()
|
||||
rea = self.bin / "rea"
|
||||
rea.write_text(
|
||||
f"#!{sys.executable}\n"
|
||||
"import os, signal, subprocess, sys, time\n"
|
||||
"signal.signal(signal.SIGINT, lambda *_: sys.exit(130))\n"
|
||||
"if len(sys.argv) > 1 and sys.argv[1] == 'wait':\n"
|
||||
" open(sys.argv[2], 'w').close()\n"
|
||||
" time.sleep(30)\n"
|
||||
"if len(sys.argv) > 1 and sys.argv[1] == 'ignore':\n"
|
||||
" signal.signal(signal.SIGINT, signal.SIG_IGN)\n"
|
||||
" open(sys.argv[2], 'w').close()\n"
|
||||
" while not os.path.exists(sys.argv[3]): time.sleep(0.02)\n"
|
||||
"if len(sys.argv) > 1 and sys.argv[1] == 'stderr':\n"
|
||||
" sys.stderr.write('x' * 100000 + 'TAIL')\n"
|
||||
"if len(sys.argv) > 1 and sys.argv[1] == 'hold':\n"
|
||||
" subprocess.Popen([sys.executable, '-c', 'import os,sys,time\\nwhile not os.path.exists(sys.argv[1]): time.sleep(0.02)', sys.argv[2]], stdout=subprocess.DEVNULL, stderr=sys.stderr, start_new_session=True)\n"
|
||||
" sys.exit(0)\n"
|
||||
"print(os.environ.get('AGENTENV_CONTROL_TOKEN', 'no token'))\n"
|
||||
)
|
||||
rea.chmod(0o755)
|
||||
self.environment = {**os.environ, "HOME": str(self.root), "PATH": f"{self.bin}{os.pathsep}{os.environ.get('PATH', '')}",
|
||||
"AGENTENV_CONTROL_TOKEN": "not-for-the-child"}
|
||||
self.job = self.root / "job"
|
||||
self.output = self.root / "out.json"
|
||||
|
||||
def command(self, name, **values):
|
||||
result = subprocess.run([sys.executable, str(CONTROLLER), name, json.dumps(values)],
|
||||
env=self.environment, text=True, capture_output=True, timeout=10, check=True)
|
||||
return json.loads(result.stdout)
|
||||
|
||||
def begin(self, argv, timeout=60):
|
||||
return self.command("run-begin", job=str(self.job), work=str(self.root), stdout=str(self.output),
|
||||
token="owner-token", argv=argv, files={}, timeout_s=timeout)
|
||||
|
||||
def test_runs_and_reports_its_output(self):
|
||||
self.assertEqual(self.begin([]), {"started": True})
|
||||
result = self.command("run-poll", job=str(self.job), token="owner-token", timeout_s=5)
|
||||
self.assertEqual(result["exit_code"], 0)
|
||||
self.assertEqual(self.output.read_text().strip(), "no token")
|
||||
|
||||
def test_passes_large_command_without_persisting_its_arguments(self):
|
||||
self.assertEqual(self.begin(["done", *("x" * 4000 for _ in range(20))]), {"started": True})
|
||||
result = self.command("run-poll", job=str(self.job), token="owner-token", timeout_s=5)
|
||||
self.assertEqual(result["exit_code"], 0)
|
||||
self.assertFalse((self.job / "request.json").exists())
|
||||
|
||||
def test_keeps_only_a_bounded_stderr_tail(self):
|
||||
self.assertEqual(self.begin(["stderr"]), {"started": True})
|
||||
result = self.command("run-poll", job=str(self.job), token="owner-token", timeout_s=5)
|
||||
self.assertEqual(len(result["stderr"]), 4096)
|
||||
self.assertTrue(result["stderr"].endswith("TAIL"))
|
||||
|
||||
def test_cancels_a_running_child_and_confirms_exit(self):
|
||||
ready = self.root / "ready"
|
||||
self.assertEqual(self.begin(["wait", str(ready)]), {"started": True})
|
||||
import time
|
||||
deadline = time.monotonic() + 5
|
||||
while not ready.exists() and time.monotonic() < deadline:
|
||||
time.sleep(0.02)
|
||||
self.assertTrue(ready.exists())
|
||||
result = self.command("run-cancel", job=str(self.job), token="owner-token", timeout_s=5)
|
||||
self.assertTrue(result["cancelled"])
|
||||
self.assertEqual(result["exit_code"], 130)
|
||||
|
||||
def test_cancel_before_late_start_claims_the_job(self):
|
||||
self.assertEqual(self.command("run-cancel", job=str(self.job), token="owner-token", timeout_s=1), {"absent": True})
|
||||
self.assertIn("already used", self.begin([])["refused"])
|
||||
self.assertFalse(self.output.exists())
|
||||
|
||||
def test_cancel_refuses_a_folder_without_the_matching_owner(self):
|
||||
self.job.mkdir()
|
||||
(self.job / "owner").write_text("someone-else")
|
||||
result = self.command("run-cancel", job=str(self.job), token="owner-token", timeout_s=1)
|
||||
self.assertIn("ownership is not confirmed", result["error"])
|
||||
self.assertFalse((self.job / "cancel").exists())
|
||||
|
||||
def test_reports_supervisor_output_if_completion_is_unconfirmed(self):
|
||||
self.job.mkdir()
|
||||
(self.job / "owner").write_text("owner-token")
|
||||
(self.job / "supervisor.log").write_text("supervisor failed")
|
||||
result = self.command("run-poll", job=str(self.job), token="owner-token", timeout_s=0)
|
||||
self.assertEqual(result["progress"], "supervisor failed")
|
||||
self.assertTrue(result["pending"])
|
||||
|
||||
def test_reports_a_timed_out_child_that_has_not_stopped(self):
|
||||
ready, release = self.root / "ready", self.root / "release"
|
||||
self.assertEqual(self.begin(["ignore", str(ready), str(release)], timeout=3), {"started": True})
|
||||
try:
|
||||
result = self.command("run-poll", job=str(self.job), token="owner-token", timeout_s=4)
|
||||
self.assertTrue(result["pending"])
|
||||
self.assertTrue(result["timed_out"])
|
||||
self.assertTrue(ready.exists())
|
||||
finally:
|
||||
release.touch()
|
||||
self.command("run-poll", job=str(self.job), token="owner-token", timeout_s=5)
|
||||
|
||||
def test_waits_for_an_inherited_stderr_pipe_after_the_child_exits(self):
|
||||
release = self.root / "release"
|
||||
self.assertEqual(self.begin(["hold", str(release)], timeout=3), {"started": True})
|
||||
try:
|
||||
result = self.command("run-poll", job=str(self.job), token="owner-token", timeout_s=4)
|
||||
self.assertTrue(result["pending"])
|
||||
self.assertTrue(result["timed_out"])
|
||||
finally:
|
||||
release.touch()
|
||||
result = self.command("run-poll", job=str(self.job), token="owner-token", timeout_s=5)
|
||||
self.assertTrue(result["finished"])
|
||||
|
||||
def test_failure_closing_supervisor_log_after_launch_does_not_claim_exit(self):
|
||||
ready = self.root / "ready"
|
||||
original_open = open
|
||||
original_popen = subprocess.Popen
|
||||
supervisors = []
|
||||
|
||||
class FailingClose:
|
||||
def __init__(self, file):
|
||||
self.file = file
|
||||
|
||||
def __enter__(self):
|
||||
return self.file
|
||||
|
||||
def __exit__(self, *args):
|
||||
self.file.close()
|
||||
raise OSError("log close failed")
|
||||
|
||||
def opening(path, *args, **kwargs):
|
||||
file = original_open(path, *args, **kwargs)
|
||||
return FailingClose(file) if str(path).endswith("supervisor.log") else file
|
||||
|
||||
def spawning(*args, **kwargs):
|
||||
process = original_popen(*args, **kwargs)
|
||||
supervisors.append(process)
|
||||
def cleanup():
|
||||
if process.poll() is None:
|
||||
(self.job / "cancel").touch()
|
||||
process.wait(timeout=5)
|
||||
self.addCleanup(cleanup)
|
||||
return process
|
||||
|
||||
arguments = {"job": str(self.job), "work": str(self.root), "stdout": str(self.output),
|
||||
"token": "owner-token", "argv": ["wait", str(ready)], "files": {}, "timeout_s": 60}
|
||||
with patch.dict(os.environ, self.environment, clear=True), patch("builtins.open", side_effect=opening), patch.object(capture.subprocess, "Popen", side_effect=spawning), redirect_stdout(io.StringIO()) as output:
|
||||
capture.run_begin(arguments)
|
||||
self.assertIn("started but its setup did not finish", json.loads(output.getvalue())["error"])
|
||||
import time
|
||||
deadline = time.monotonic() + 5
|
||||
while not ready.exists() and time.monotonic() < deadline:
|
||||
time.sleep(0.02)
|
||||
self.assertTrue(ready.exists())
|
||||
self.assertFalse((self.job / "result.json").exists())
|
||||
result = self.command("run-cancel", job=str(self.job), token="owner-token", timeout_s=5)
|
||||
self.assertTrue(result["cancelled"])
|
||||
supervisors[0].wait(timeout=5)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -119,9 +119,9 @@ import ghidra.program.util.VarnodeContext;
|
||||
public final class ReaGhidraBridge extends HeadlessScript {
|
||||
// At most 24 KiB after worst-case JSON escaping (six bytes per UTF-16 unit).
|
||||
private static final int PDB_ATTRIBUTE_UTF16_BUDGET = 4096;
|
||||
private static final int MAX_HIGH_PCODE_OPS = 3000;
|
||||
private static final int MAX_HIGH_PCODE_INPUTS_PER_OP = 64;
|
||||
private static final int MAX_HIGH_PCODE_DEF_USE_EDGES = 12000;
|
||||
private static final int DEFAULT_HIGH_PCODE_OPS = 3000;
|
||||
private static final int DEFAULT_HIGH_PCODE_INPUTS_PER_OP = 64;
|
||||
private static final int DEFAULT_HIGH_PCODE_DEF_USE_EDGES = 12000;
|
||||
private static final Gson GSON = new GsonBuilder().serializeNulls().create();
|
||||
private final Map<FileBytes, Boolean> targetSourceIdentity = new IdentityHashMap<>();
|
||||
private String admittedTargetSha256;
|
||||
@@ -184,6 +184,10 @@ public final class ReaGhidraBridge extends HeadlessScript {
|
||||
private String identityAdmissionFailure;
|
||||
/** Per-function native decompiler limit from the session; 0 leaves it unbounded. */
|
||||
private int decompileTimeoutSeconds;
|
||||
private Integer decompileMaxPayloadMiB;
|
||||
// DecompileProcess converts MiB to bytes using a signed-int left shift.
|
||||
private static final int MAX_DECOMPILE_PAYLOAD_MIB = Integer.MAX_VALUE >> 20;
|
||||
private ValueFlowLimits valueFlowLimits = defaultValueFlowLimits();
|
||||
// DecompileProcess converts seconds to an int millisecond timer delay.
|
||||
private static final int MAX_DECOMPILE_TIMEOUT_SECONDS = Integer.MAX_VALUE / 1000;
|
||||
private final ReaGhidraExtensions analysisExtensions = new ReaGhidraExtensions();
|
||||
@@ -426,6 +430,8 @@ public final class ReaGhidraBridge extends HeadlessScript {
|
||||
}
|
||||
decompileTimeoutSeconds = request.decompileTimeoutSeconds() == null
|
||||
? descriptor.decompileTimeoutSeconds() : request.decompileTimeoutSeconds();
|
||||
valueFlowLimits = request.valueFlowLimits();
|
||||
applyDecompilePayloadLimit(request.decompileMaxPayloadMiB());
|
||||
writeSuccess(writer, request.id, handleRequest(request, descriptor));
|
||||
}
|
||||
catch (RequestFailure failure) {
|
||||
@@ -1038,11 +1044,26 @@ public final class ReaGhidraBridge extends HeadlessScript {
|
||||
return result;
|
||||
}
|
||||
|
||||
private void initializeDecompiler() {
|
||||
private DecompileOptions decompileOptions(Integer payloadMiB) {
|
||||
DecompileOptions options = new DecompileOptions();
|
||||
options.setMaxInstructions(Integer.MAX_VALUE);
|
||||
if (payloadMiB != null) options.setMaxPayloadMBytes(payloadMiB);
|
||||
return options;
|
||||
}
|
||||
|
||||
private void applyDecompilePayloadLimit(Integer payloadMiB) {
|
||||
if (java.util.Objects.equals(decompileMaxPayloadMiB, payloadMiB)) return;
|
||||
// DecompInterface supports live setOptions: it updates the existing
|
||||
// DecompileProcess result-size bound before sending native options.
|
||||
if (!decompiler.setOptions(decompileOptions(payloadMiB)))
|
||||
throw new RequestFailure("decompile_options_failed", "Ghidra could not apply the selected native decompiler payload limit");
|
||||
decompiler.flushCache();
|
||||
decompileMaxPayloadMiB = payloadMiB;
|
||||
}
|
||||
|
||||
private void initializeDecompiler() {
|
||||
decompiler = new DecompInterface();
|
||||
decompiler.setOptions(options);
|
||||
decompiler.setOptions(decompileOptions(decompileMaxPayloadMiB));
|
||||
decompiler.toggleCCode(true);
|
||||
decompiler.toggleSyntaxTree(true);
|
||||
decompiler.toggleJumpLoads(true);
|
||||
@@ -1856,7 +1877,7 @@ public final class ReaGhidraBridge extends HeadlessScript {
|
||||
while (operations.hasNext()) {
|
||||
monitor.checkCancelled();
|
||||
PcodeOpAST operation = operations.next();
|
||||
if (selected.size() >= MAX_HIGH_PCODE_OPS) {
|
||||
if (selected.size() >= valueFlowLimits.maxOperations()) {
|
||||
omittedOperationsLowerBound = 1;
|
||||
break;
|
||||
}
|
||||
@@ -1884,6 +1905,7 @@ public final class ReaGhidraBridge extends HeadlessScript {
|
||||
JsonArray effects = new JsonArray();
|
||||
int omittedInputs = 0;
|
||||
int omittedEdges = 0;
|
||||
boolean edgeLimitReached = false;
|
||||
for (PcodeOpAST operation : selected) {
|
||||
monitor.checkCancelled();
|
||||
String operationId = operationIds.get(operation);
|
||||
@@ -1899,14 +1921,16 @@ public final class ReaGhidraBridge extends HeadlessScript {
|
||||
value.addProperty("block_membership", operation.getParent() == null ? "detached" : "member");
|
||||
JsonArray inputs = new JsonArray();
|
||||
int inputCount = operation.getNumInputs();
|
||||
int capturedInputs = Math.min(inputCount, MAX_HIGH_PCODE_INPUTS_PER_OP);
|
||||
int capturedInputs = Math.min(inputCount, valueFlowLimits.maxInputsPerOperation());
|
||||
for (int inputIndex = 0; inputIndex < capturedInputs; inputIndex += 1) {
|
||||
Varnode input = operation.getInput(inputIndex);
|
||||
inputs.add(varnodeValue(input));
|
||||
if (input instanceof VarnodeAST astInput) {
|
||||
if (astInput.getHigh() instanceof HighParam parameter) {
|
||||
if (parameterUses.size() >= MAX_HIGH_PCODE_DEF_USE_EDGES) omittedEdges++;
|
||||
else {
|
||||
if (parameterUses.size() >= valueFlowLimits.maxEdges()) {
|
||||
edgeLimitReached = true;
|
||||
omittedEdges++;
|
||||
} else {
|
||||
JsonObject use = new JsonObject();
|
||||
use.addProperty("ordinal", parameter.getSlot());
|
||||
use.addProperty("use", operationId);
|
||||
@@ -1917,7 +1941,8 @@ public final class ReaGhidraBridge extends HeadlessScript {
|
||||
PcodeOp definition = astInput.getDef();
|
||||
if (definition instanceof PcodeOpAST astDefinition) {
|
||||
String definitionId = operationIds.get(astDefinition);
|
||||
if (definitionId == null || defUse.size() >= MAX_HIGH_PCODE_DEF_USE_EDGES) {
|
||||
if (definitionId == null || defUse.size() >= valueFlowLimits.maxEdges()) {
|
||||
if (defUse.size() >= valueFlowLimits.maxEdges()) edgeLimitReached = true;
|
||||
omittedEdges += 1;
|
||||
} else {
|
||||
JsonObject edge = new JsonObject();
|
||||
@@ -1940,6 +1965,16 @@ public final class ReaGhidraBridge extends HeadlessScript {
|
||||
JsonObject result = new JsonObject();
|
||||
result.addProperty("available", true);
|
||||
result.addProperty("provenance", "ghidra-high-pcode");
|
||||
JsonObject limits = new JsonObject();
|
||||
limits.addProperty("max_operations", valueFlowLimits.maxOperations());
|
||||
limits.addProperty("max_inputs_per_operation", valueFlowLimits.maxInputsPerOperation());
|
||||
limits.addProperty("max_edges", valueFlowLimits.maxEdges());
|
||||
result.add("limits", limits);
|
||||
JsonArray limitsReached = new JsonArray();
|
||||
if (omittedOperationsLowerBound > 0) limitsReached.add("max_operations");
|
||||
if (omittedInputs > 0) limitsReached.add("max_inputs_per_operation");
|
||||
if (edgeLimitReached) limitsReached.add("max_edges");
|
||||
result.add("limits_reached", limitsReached);
|
||||
result.add("operations", operationValues);
|
||||
result.add("def_use", defUse);
|
||||
result.add("parameters", parameterValues);
|
||||
@@ -1968,15 +2003,35 @@ public final class ReaGhidraBridge extends HeadlessScript {
|
||||
"Memory read/write effects include stack and temporary memory operations; they do not identify persistent state or business meaning."
|
||||
);
|
||||
limitations.add(
|
||||
"Operation, input, and def-use limits can truncate large functions; inspect truncation, omitted lower bounds, and known omitted counts before drawing conclusions."
|
||||
"Operation, input, and def-use limits can truncate large functions; inspect the effective limits, limits_reached and omitted counts before drawing conclusions."
|
||||
);
|
||||
limitations.add(
|
||||
"Known omitted-edge counts cover links omitted from retained operations; omitted operations may contain additional uncounted links."
|
||||
);
|
||||
if (omittedOperationsLowerBound > 0)
|
||||
limitations.add(valueFlowLimitRecovery("max_operations", valueFlowLimits.maxOperations()));
|
||||
if (omittedInputs > 0)
|
||||
limitations.add(valueFlowLimitRecovery("max_inputs_per_operation", valueFlowLimits.maxInputsPerOperation()));
|
||||
if (edgeLimitReached)
|
||||
limitations.add(valueFlowLimitRecovery("max_edges", valueFlowLimits.maxEdges()));
|
||||
result.add("limitations", limitations);
|
||||
return result;
|
||||
}
|
||||
|
||||
private static String valueFlowLimitRecovery(String field, int effective) {
|
||||
String setting = "ghidra.value_flow_" + field;
|
||||
String environment = "REA_GHIDRA_VALUE_FLOW_" + field.toUpperCase(Locale.ROOT);
|
||||
String adjustment = effective < Integer.MAX_VALUE
|
||||
? "In MCP, use update_analysis_settings with setting " + setting +
|
||||
", action set and a larger integer value from 1 to " + Integer.MAX_VALUE +
|
||||
", then repeat the selected function analysis on this Program without restarting REA. " +
|
||||
"For a one-shot CLI retry, set " + environment +
|
||||
" to a larger count in the environment that starts the next rea invocation, then repeat the selected analysis; the previous invocation's Program is no longer active."
|
||||
: "The setting is at its Java integer maximum; select a smaller function for this projection.";
|
||||
return setting + " reached its effective value of " + effective + ". " + adjustment +
|
||||
" These controls do not raise the decompile deadline, bridge transport or MCP client limits.";
|
||||
}
|
||||
|
||||
private String pcodeOperationId(PcodeOpAST operation) {
|
||||
return canonicalAddress(operation.getSeqnum().getTarget()) + "#" +
|
||||
operation.getSeqnum().getTime();
|
||||
@@ -3699,12 +3754,26 @@ public final class ReaGhidraBridge extends HeadlessScript {
|
||||
if (!results.decompileCompleted()) {
|
||||
throw new RequestFailure(
|
||||
"decompile_failed",
|
||||
"Ghidra decompilation failed: " + diagnosticMessage(results.getErrorMessage())
|
||||
"Ghidra decompilation failed: " + diagnosticMessage(results.getErrorMessage()) +
|
||||
". The effective native decompiler payload allowance is " +
|
||||
decompiler.getOptions().getMaxPayloadMBytes() +
|
||||
" MiB. " + decompilePayloadRecovery()
|
||||
);
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
private String decompilePayloadRecovery() {
|
||||
int effective = decompiler.getOptions().getMaxPayloadMBytes();
|
||||
if (effective >= MAX_DECOMPILE_PAYLOAD_MIB)
|
||||
return "If the diagnostic reports payload exhaustion, the native payload allowance is already at its supported maximum; no higher value is accepted. Use analyze_function for available listing facts or explicitly select a smaller function for decompilation.";
|
||||
return "If the diagnostic reports payload exhaustion, in MCP raise ghidra.decompile_max_payload_mib with update_analysis_settings " +
|
||||
"(integer MiB from 1 to " + MAX_DECOMPILE_PAYLOAD_MIB +
|
||||
") and repeat the selected operation on this Program without restarting REA. " +
|
||||
"For a one-shot CLI retry, set REA_GHIDRA_DECOMPILE_MAX_PAYLOAD_MIB to a larger MiB value in the environment that starts the next rea invocation, then repeat the selected operation; the previous invocation's Program is no longer active. " +
|
||||
"Runtime null or an omitted launch seed restores the installed Ghidra default. This does not raise the decompile deadline, high-pcode projection budgets or MCP client limits.";
|
||||
}
|
||||
|
||||
private static String decompiledText(DecompileResults results) {
|
||||
if (results == null) {
|
||||
return null;
|
||||
@@ -3753,6 +3822,20 @@ 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");
|
||||
@@ -3771,10 +3854,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");
|
||||
@@ -3824,6 +3907,24 @@ 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());
|
||||
@@ -3858,9 +3959,11 @@ public final class ReaGhidraBridge extends HeadlessScript {
|
||||
monitor.checkCancelled();
|
||||
calls.observe(reference);
|
||||
}
|
||||
List<String> computedCallSites = new ArrayList<>();
|
||||
for (Instruction instruction : instructions) {
|
||||
boundary.observe(instruction);
|
||||
if (!instruction.getFlowType().isCall()) continue;
|
||||
FlowType flow = instruction.getFlowType();
|
||||
if (!flow.isCall()) continue;
|
||||
boolean destination = false;
|
||||
for (Reference reference : instruction.getReferencesFrom()) {
|
||||
if (!reference.getReferenceType().isCall()) continue;
|
||||
@@ -3872,9 +3975,13 @@ 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());
|
||||
returnedCallees == null ? null : calls.unrepresented, calls.unresolvedCalls(),
|
||||
List.copyOf(computedCallSites));
|
||||
}
|
||||
|
||||
private final class FunctionBoundaryLimitations {
|
||||
@@ -5118,7 +5225,28 @@ public final class ReaGhidraBridge extends HeadlessScript {
|
||||
Set<String> keys = new HashSet<>(REQUEST_KEYS);
|
||||
if (parsed.isJsonObject() && parsed.getAsJsonObject().has("decompile_timeout_seconds"))
|
||||
keys.add("decompile_timeout_seconds");
|
||||
if (parsed.isJsonObject() && parsed.getAsJsonObject().has("value_flow_limits"))
|
||||
keys.add("value_flow_limits");
|
||||
if (parsed.isJsonObject() && parsed.getAsJsonObject().has("decompile_max_payload_mib"))
|
||||
keys.add("decompile_max_payload_mib");
|
||||
JsonObject object = requireObject(parsed, keys);
|
||||
Integer payloadMiB = null;
|
||||
if (object.has("decompile_max_payload_mib") && !object.get("decompile_max_payload_mib").isJsonNull()) {
|
||||
payloadMiB = requireInteger(object, "decompile_max_payload_mib");
|
||||
if (payloadMiB < 1 || payloadMiB > MAX_DECOMPILE_PAYLOAD_MIB)
|
||||
throw new IllegalArgumentException("Invalid per-request native decompiler payload limit");
|
||||
}
|
||||
ValueFlowLimits flowLimits = defaultValueFlowLimits();
|
||||
if (object.has("value_flow_limits")) {
|
||||
JsonObject limits = requireObject(object.get("value_flow_limits"),
|
||||
Set.of("max_operations", "max_inputs_per_operation", "max_edges"));
|
||||
int operations = requireInteger(limits, "max_operations");
|
||||
int inputs = requireInteger(limits, "max_inputs_per_operation");
|
||||
int edges = requireInteger(limits, "max_edges");
|
||||
if (operations < 1 || inputs < 1 || edges < 1)
|
||||
throw new IllegalArgumentException("Invalid per-request value-flow limits");
|
||||
flowLimits = new ValueFlowLimits(operations, inputs, edges);
|
||||
}
|
||||
Integer timeout = null;
|
||||
if (object.has("decompile_timeout_seconds")) {
|
||||
JsonElement value = object.get("decompile_timeout_seconds");
|
||||
@@ -5134,7 +5262,7 @@ public final class ReaGhidraBridge extends HeadlessScript {
|
||||
if (params == null || !params.isJsonObject()) {
|
||||
throw new IllegalArgumentException("Bridge request parameters are invalid");
|
||||
}
|
||||
return new Request(id, requireString(object, "method"), params.getAsJsonObject(), timeout);
|
||||
return new Request(id, requireString(object, "method"), params.getAsJsonObject(), timeout, payloadMiB, flowLimits);
|
||||
}
|
||||
|
||||
private static JsonObject requireObject(JsonElement element, Set<String> keys) {
|
||||
@@ -5320,7 +5448,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) {}
|
||||
private record CallBoundaryObservation(List<String> limitations, Integer unrepresentedCalleeCalls, JsonArray unresolvedCalls, List<String> computedCallSites) {}
|
||||
private record SwiftStringLiteralDecode(JsonArray literals, JsonArray omissions) {}
|
||||
private record SwiftLiteralLayout(
|
||||
String representation,
|
||||
@@ -5342,7 +5470,11 @@ public final class ReaGhidraBridge extends HeadlessScript {
|
||||
int decompileTimeoutSeconds,
|
||||
boolean existingProject
|
||||
) {}
|
||||
private record Request(int id, String method, JsonObject params, Integer decompileTimeoutSeconds) {}
|
||||
private static ValueFlowLimits defaultValueFlowLimits() {
|
||||
return new ValueFlowLimits(DEFAULT_HIGH_PCODE_OPS, DEFAULT_HIGH_PCODE_INPUTS_PER_OP, DEFAULT_HIGH_PCODE_DEF_USE_EDGES);
|
||||
}
|
||||
private record ValueFlowLimits(int maxOperations, int maxInputsPerOperation, int maxEdges) {}
|
||||
private record Request(int id, String method, JsonObject params, Integer decompileTimeoutSeconds, Integer decompileMaxPayloadMiB, ValueFlowLimits valueFlowLimits) {}
|
||||
|
||||
private static final class RequestFailure extends RuntimeException {
|
||||
private final String code;
|
||||
|
||||
@@ -1399,7 +1399,8 @@ def _serve_connection(connection):
|
||||
break
|
||||
except (ConnectionError, OSError):
|
||||
# A lost client cannot confirm document closure or revoke this run.
|
||||
pass
|
||||
# Keep the listener available for the owner to confirm cleanup.
|
||||
should_stop = False
|
||||
finally:
|
||||
try:
|
||||
file.close()
|
||||
|
||||
@@ -18,7 +18,6 @@ from mitmproxy import ctx, version
|
||||
from mitmproxy.io import tnetstring
|
||||
|
||||
PROFILE = "12.2.3"
|
||||
OUTPUT_BYTES = 96 * 1024 * 1024
|
||||
CREDENTIALS = {b"authorization", b"proxy-authorization", b"cookie", b"set-cookie"}
|
||||
|
||||
|
||||
@@ -204,7 +203,7 @@ def without_userinfo(value, base_scheme=None):
|
||||
raise CaptureFailure("decoder", "Normalized URL authority could not be bound to its source.")
|
||||
|
||||
|
||||
def project_record(state, secrets):
|
||||
def project_record(state, secrets, max_depth):
|
||||
binaries, numbers, redactions = [], [], []
|
||||
byte_secrets = []
|
||||
for secret in secrets:
|
||||
@@ -251,8 +250,8 @@ def project_record(state, secrets):
|
||||
del redactions[before[2]:]
|
||||
|
||||
def visit(value, path, depth=0, credential=False, transport_url=False, base_scheme=None):
|
||||
if depth > 64:
|
||||
raise CaptureFailure("input-limit", "Native capture exceeds the 64-level evidence nesting budget.", path)
|
||||
if depth > max_depth:
|
||||
raise CaptureFailure("input-limit", f"Native capture exceeds max_nesting_depth ({max_depth} levels).", path)
|
||||
if credential:
|
||||
validate_omitted(value, path, depth)
|
||||
redactions.append({"pointer": path, "reason": "transport-credential"})
|
||||
@@ -337,12 +336,12 @@ def decode(request):
|
||||
except CaptureFailure:
|
||||
raise
|
||||
except RecursionError:
|
||||
raise CaptureFailure("input-limit", "Native parser exceeded its recursion budget at byte offset " + str(start) + ".") from None
|
||||
raise CaptureFailure("unsupported", "Native parser reached Python's recursion limit at byte offset " + str(start) + ". max_nesting_depth does not raise that upstream limit.") from None
|
||||
except (ValueError, IndexError, UnicodeError, EOFError):
|
||||
raise CaptureFailure("format", "Malformed native record at byte offset " + str(start) + ".") from None
|
||||
if not isinstance(state, dict):
|
||||
raise CaptureFailure("format", "Native flow record must be a dictionary at byte offset " + str(start) + ".")
|
||||
records.append({"ordinal": len(records), "location": {"kind": "byte-range", "offset": start, "bytes": handle.tell() - start}, **project_record(state, request["sensitive_values"]), "limitations": ["Fields are original native states without FlowReader migration. Binary fields contain exact producer bytes; reported UTF-8 strings for those fields are derived display views. Unknown flow/version extensions are retained without interpretation."]})
|
||||
records.append({"ordinal": len(records), "location": {"kind": "byte-range", "offset": start, "bytes": handle.tell() - start}, **project_record(state, request["sensitive_values"], request["budgets"]["depth"]), "limitations": ["Fields are original native states without FlowReader migration. Binary fields contain exact producer bytes; reported UTF-8 strings for those fields are derived display views. Unknown flow/version extensions are retained without interpretation."]})
|
||||
return {"decoder": {"id": "mitmproxy-native-tnetstring", "name": "REA offline native mitmproxy adapter", "version": PROFILE}, "container": {"reported": None, "numeric_literals": [], "redactions": [], "records_pointer": None}, "total_records": len(records), "records": records}
|
||||
|
||||
|
||||
@@ -350,6 +349,8 @@ def failure_reply(error):
|
||||
"""Keep producer constraints, resource exhaustion and adapter defects distinct."""
|
||||
if isinstance(error, CaptureFailure):
|
||||
return {"ok": False, "reason": error.reason, "message": str(error), "pointer": error.pointer}
|
||||
if isinstance(error, RecursionError):
|
||||
return {"ok": False, "reason": "unsupported", "message": "Native projection reached Python's recursion limit; max_nesting_depth does not raise that upstream limit.", "pointer": ""}
|
||||
if isinstance(error, MemoryError):
|
||||
return {"ok": False, "reason": "resource-limit", "message": "Native decoder exhausted its 768 MiB address-space budget.", "pointer": ""}
|
||||
return {"ok": False, "reason": "decoder", "message": "Offline native decoder failed unexpectedly: " + type(error).__name__ + ".", "pointer": ""}
|
||||
@@ -362,9 +363,13 @@ class OfflineCapture:
|
||||
def running(self):
|
||||
resource.setrlimit(resource.RLIMIT_AS, (768 * 1024 * 1024, 768 * 1024 * 1024))
|
||||
resource.setrlimit(resource.RLIMIT_CPU, (30, 30))
|
||||
resource.setrlimit(resource.RLIMIT_FSIZE, (OUTPUT_BYTES, OUTPUT_BYTES))
|
||||
resource.setrlimit(resource.RLIMIT_CORE, (0, 0))
|
||||
request = json.loads(Path(ctx.options.rea_request_path).read_text(encoding="utf-8"))
|
||||
budgets = request["budgets"]
|
||||
if any(type(budgets[key]) is not int or budgets[key] < 1 for key in ("inputBytes", "outputBytes", "depth")):
|
||||
raise ValueError("Invalid admitted capture budgets")
|
||||
output_bytes = budgets["outputBytes"]
|
||||
resource.setrlimit(resource.RLIMIT_FSIZE, (output_bytes, output_bytes))
|
||||
try:
|
||||
response = {"ok": True, "value": decode(request)}
|
||||
except Exception as error:
|
||||
@@ -374,7 +379,7 @@ class OfflineCapture:
|
||||
output = json.dumps(response, ensure_ascii=True, allow_nan=False, separators=(",", ":")).encode("ascii")
|
||||
except Exception as error:
|
||||
output = json.dumps(failure_reply(error), separators=(",", ":")).encode("ascii")
|
||||
if len(output) > OUTPUT_BYTES:
|
||||
if len(output) > output_bytes:
|
||||
output = b'{"ok":false,"reason":"limit","message":"Native reply exceeds the complete-evidence output budget.","pointer":""}'
|
||||
Path(request["reply_path"]).write_bytes(output)
|
||||
finally:
|
||||
|
||||
@@ -36,7 +36,7 @@ def location(value, scheme=None):
|
||||
state = {"response": {"headers": [[b"Location", value]]}}
|
||||
if scheme is not None:
|
||||
state["request"] = {"scheme": scheme}
|
||||
record = capture.project_record(state, [])
|
||||
record = capture.project_record(state, [], 64)
|
||||
sidecar = next(
|
||||
field for field in record["binary_fields"] if field["pointer"] == "/response/headers/0/1"
|
||||
)
|
||||
@@ -75,11 +75,11 @@ class TransportUserinfoTests(unittest.TestCase):
|
||||
def test_native_request_paths_preserve_origin_form_and_redact_absolute_form(self):
|
||||
for value in [b"/\\invoice@customer", b"//invoice@customer", b"\\\\invoice@customer"]:
|
||||
with self.subTest(value=value):
|
||||
record = capture.project_record({"request": {"path": value}}, [])
|
||||
record = capture.project_record({"request": {"path": value}}, [], 64)
|
||||
self.assertEqual(record["reported"]["request"]["path"], value.decode("ascii"))
|
||||
self.assertEqual(record["binary_fields"][0]["state"], "retained")
|
||||
self.assertEqual(record["redactions"], [])
|
||||
record = capture.project_record({"request": {"path": b"https://user:pass@host/x"}}, [])
|
||||
record = capture.project_record({"request": {"path": b"https://user:pass@host/x"}}, [], 64)
|
||||
self.assertEqual(record["reported"]["request"]["path"], "https://host/x")
|
||||
self.assertEqual(record["binary_fields"][0]["state"], "redacted")
|
||||
|
||||
@@ -110,7 +110,7 @@ class TransportUserinfoTests(unittest.TestCase):
|
||||
"request": {"scheme": b"https"},
|
||||
"response": {"headers": [[b"Location", b"https:invoice@customer"]]},
|
||||
},
|
||||
}, [])
|
||||
}, [], 64)
|
||||
self.assertEqual(record["reported"]["backup"]["response"]["headers"][0][1], "https:invoice@customer")
|
||||
self.assertEqual(record["redactions"], [])
|
||||
|
||||
|
||||
@@ -24,3 +24,16 @@ 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,9 +18,10 @@ 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) -> CFTypeRef? {
|
||||
func attribute(_ element: AXUIElement, _ key: String) -> (value: CFTypeRef?, error: Int32?) {
|
||||
var value: CFTypeRef?
|
||||
return AXUIElementCopyAttributeValue(element, key as CFString, &value) == .success ? value : nil
|
||||
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)
|
||||
}
|
||||
func childCount(_ element: AXUIElement) -> ChildCount {
|
||||
var count = 0
|
||||
@@ -34,13 +35,15 @@ func children(_ element: AXUIElement, count: Int) -> ChildBatch<AXUIElement> {
|
||||
return value as? [AXUIElement]
|
||||
}
|
||||
}
|
||||
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 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 observe(_ request: Request) async throws -> [String: Any] {
|
||||
guard let app = NSRunningApplication(processIdentifier: request.pid) else {
|
||||
@@ -84,11 +87,22 @@ 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)
|
||||
guard let axWindows = attribute(application, kAXWindowsAttribute) as? [AXUIElement] else {
|
||||
try fail("accessibility-unavailable", "Selected application does not expose accessibility windows")
|
||||
let windowsAttribute = attribute(application, kAXWindowsAttribute)
|
||||
if let error = windowsAttribute.error {
|
||||
try fail("accessibility-unavailable", "Cannot read accessibility windows: AXError \(error)")
|
||||
}
|
||||
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)) })") }
|
||||
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) })") }
|
||||
selected = matches[0]
|
||||
}
|
||||
if let action = request.action, let root = selected {
|
||||
@@ -99,13 +113,16 @@ 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,
|
||||
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") }
|
||||
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") }
|
||||
element = item
|
||||
}
|
||||
var owner: pid_t = 0
|
||||
guard AXUIElementGetPid(element, &owner) == .success && owner == request.pid else { try fail("element-owner-mismatch", "Selected element belongs to another process") }
|
||||
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") }
|
||||
let outcome: AXError
|
||||
switch action.kind {
|
||||
case "click": outcome = AXUIElementPerformAction(element, kAXPressAction as CFString)
|
||||
@@ -122,10 +139,18 @@ func observe(_ request: Request) async throws -> [String: Any] {
|
||||
if nodes.count >= request.max_nodes { truncated = true; break }
|
||||
let childCountResult = childCount(element)
|
||||
var actions: CFArray?
|
||||
AXUIElementCopyActionNames(element, &actions)
|
||||
let observedValue = captureAccessibilityValue(attribute(element, kAXValueAttribute))
|
||||
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)
|
||||
if let gap = observedValue.gap { gaps.append("\(gap) at path \(path)"); truncated = true }
|
||||
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()])
|
||||
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()])
|
||||
guard let totalChildren = childCountResult.value else {
|
||||
truncated = true
|
||||
gaps.append("AX child count unavailable at path \(path): AXError \(childCountResult.error ?? -1)")
|
||||
|
||||
@@ -25,24 +25,17 @@ ARGUMENT_REGISTERS = {
|
||||
"x86_64": ["rdi", "rsi", "rdx", "rcx", "r8", "r9"],
|
||||
"x86_64h": ["rdi", "rsi", "rdx", "rcx", "r8", "r9"],
|
||||
}
|
||||
MAX_SELECTOR_BYTES = 1024
|
||||
MAX_OTHER_STOPS = 256
|
||||
MAX_TRACE_BYTES = 8 * 1024 * 1024
|
||||
MAX_TRACE_FRAMES = 65_536
|
||||
MAX_OBSERVATION_JOURNAL_BYTES = MAX_TRACE_BYTES
|
||||
MAX_BREAKPOINT_LOCATION_BYTES = 8 * 1024 * 1024
|
||||
MAX_TARGET_OUTPUT_BYTES = 1024 * 1024
|
||||
OUTPUT_DRAIN_BYTES_PER_PASS = 1024 * 1024
|
||||
OUTPUT_EOF_WAIT_SECONDS = 1.0
|
||||
OUTPUT_READER_JOIN_SECONDS = 0.5
|
||||
LISTENER_NAME = "rea-native-call-observation"
|
||||
|
||||
|
||||
def _can_retain_trace(current_bytes, current_frames, event_bytes, event_frames):
|
||||
def _can_retain_trace(current_bytes, current_frames, event_bytes, event_frames, limits):
|
||||
"""Whether a complete event fits both aggregate trace budgets."""
|
||||
return (
|
||||
current_bytes + event_bytes <= MAX_TRACE_BYTES
|
||||
and current_frames + event_frames <= MAX_TRACE_FRAMES
|
||||
current_bytes + event_bytes <= limits["trace_bytes"]
|
||||
and current_frames + event_frames <= limits["trace_frames"]
|
||||
)
|
||||
|
||||
|
||||
@@ -71,7 +64,7 @@ def _fits_trace_budget(value, remaining_bytes):
|
||||
class _ObservationJournal:
|
||||
"""Flush a bounded JSONL prefix so observations survive tracer failure."""
|
||||
|
||||
def __init__(self, handle, max_bytes=MAX_OBSERVATION_JOURNAL_BYTES):
|
||||
def __init__(self, handle, max_bytes):
|
||||
self.handle = handle
|
||||
self.max_bytes = max_bytes
|
||||
self.bytes = 0
|
||||
@@ -371,7 +364,7 @@ def _record(context, thread, frame, index, sequence, location, remaining_bytes):
|
||||
error = lldb.SBError()
|
||||
text = process.ReadCStringFromMemory(
|
||||
values[names[1]],
|
||||
MAX_SELECTOR_BYTES,
|
||||
config["capture_limits"]["selector_bytes"],
|
||||
error,
|
||||
)
|
||||
selector = text if error.Success() and text else None
|
||||
@@ -404,10 +397,16 @@ def _record(context, thread, frame, index, sequence, location, remaining_bytes):
|
||||
_TRACE_CONTEXT = None
|
||||
|
||||
|
||||
def _resource_limit(context, limit):
|
||||
context["resource_limit"] = limit
|
||||
return "resource-limit"
|
||||
|
||||
|
||||
def _handle_breakpoint(context, frame, index):
|
||||
"""Read one hit while LLDB's breakpoint callback owns the stopped frame."""
|
||||
if not frame.IsValid() or frame.GetPC() == lldb.LLDB_INVALID_ADDRESS:
|
||||
raise RuntimeError("LLDB breakpoint callback did not supply a readable frame")
|
||||
limits = context["config"]["capture_limits"]
|
||||
thread = frame.GetThread()
|
||||
events = context["events"]
|
||||
location = _location(frame.GetPCAddress(), context["target"])
|
||||
@@ -424,49 +423,50 @@ def _handle_breakpoint(context, frame, index):
|
||||
context["retained_frames"],
|
||||
0,
|
||||
event_frame_count,
|
||||
limits,
|
||||
):
|
||||
return "resource-limit"
|
||||
return _resource_limit(context, "trace_frames")
|
||||
try:
|
||||
remaining_bytes = MAX_TRACE_BYTES - context["retained_trace_bytes"]
|
||||
remaining_bytes = limits["trace_bytes"] - context["retained_trace_bytes"]
|
||||
record = _record(
|
||||
context, thread, frame, index, len(events), location, remaining_bytes
|
||||
)
|
||||
except ValueError:
|
||||
return "resource-limit"
|
||||
return _resource_limit(context, "trace_bytes")
|
||||
if record is not None:
|
||||
if not _fits_trace_budget(record, remaining_bytes):
|
||||
return "resource-limit"
|
||||
return _resource_limit(context, "trace_bytes")
|
||||
record_bytes = len(json.dumps(record).encode("utf-8"))
|
||||
if context["retained_trace_bytes"] + record_bytes > MAX_TRACE_BYTES:
|
||||
return "resource-limit"
|
||||
if context["retained_trace_bytes"] + record_bytes > limits["trace_bytes"]:
|
||||
return _resource_limit(context, "trace_bytes")
|
||||
for depth in range(1, frame_count + 1):
|
||||
try:
|
||||
location = _location(
|
||||
thread.GetFrameAtIndex(depth).GetPCAddress(), context["target"]
|
||||
)
|
||||
except ValueError:
|
||||
return "resource-limit"
|
||||
return _resource_limit(context, "trace_bytes")
|
||||
if (
|
||||
_estimated_json_size(location) + record_bytes + 1
|
||||
> MAX_TRACE_BYTES - context["retained_trace_bytes"]
|
||||
> limits["trace_bytes"] - context["retained_trace_bytes"]
|
||||
):
|
||||
return "resource-limit"
|
||||
return _resource_limit(context, "trace_bytes")
|
||||
location_bytes = len(json.dumps(location).encode("utf-8"))
|
||||
addition = location_bytes + (1 if record["backtrace"] else 0)
|
||||
if (
|
||||
context["retained_trace_bytes"]
|
||||
+ record_bytes
|
||||
+ addition
|
||||
> MAX_TRACE_BYTES
|
||||
> limits["trace_bytes"]
|
||||
):
|
||||
return "resource-limit"
|
||||
return _resource_limit(context, "trace_bytes")
|
||||
record["backtrace"].append(location)
|
||||
record_bytes += addition
|
||||
journal = context.get("observation_journal")
|
||||
if journal is not None and not journal.append(
|
||||
{"kind": "event", "event": record}
|
||||
):
|
||||
return "resource-limit"
|
||||
return _resource_limit(context, "trace_bytes")
|
||||
events.append(record)
|
||||
context["retained_frames"] += event_frame_count
|
||||
context["retained_trace_bytes"] += record_bytes
|
||||
@@ -498,9 +498,9 @@ def _handle_stop(context, other_stops):
|
||||
if journal is not None and not journal.append(
|
||||
{"kind": "other-stop", "reason": stop_description}
|
||||
):
|
||||
return "resource-limit"
|
||||
return _resource_limit(context, "trace_bytes")
|
||||
other_stops.append(stop_description)
|
||||
if len(other_stops) >= MAX_OTHER_STOPS:
|
||||
if len(other_stops) >= context["config"]["capture_limits"]["other_stops"]:
|
||||
return "stop-limit"
|
||||
return None
|
||||
|
||||
@@ -520,7 +520,7 @@ def _breakpoint_report(target, created, config):
|
||||
continue
|
||||
count += 1
|
||||
remaining_bytes = (
|
||||
MAX_BREAKPOINT_LOCATION_BYTES - retained_location_bytes
|
||||
config["capture_limits"]["breakpoint_location_bytes"] - retained_location_bytes
|
||||
)
|
||||
if not _fits_trace_budget(location, remaining_bytes):
|
||||
locations_truncated = True
|
||||
@@ -651,7 +651,7 @@ def trace(debugger, config):
|
||||
for breakpoint in breakpoints:
|
||||
breakpoint_index[breakpoint.GetID()] = index
|
||||
listener = lldb.SBListener(LISTENER_NAME)
|
||||
output_budget = config.get("max_output_bytes", MAX_TARGET_OUTPUT_BYTES)
|
||||
output_budget = config["capture_limits"]["output_bytes"]
|
||||
stdout = _OutputPipe(
|
||||
config["stdout_path"], config["stdout_capture_path"], output_budget
|
||||
)
|
||||
@@ -671,7 +671,8 @@ def trace(debugger, config):
|
||||
observation_path = config.get("observation_path")
|
||||
if observation_path:
|
||||
observation_journal = _ObservationJournal(
|
||||
open(observation_path, "wb")
|
||||
open(observation_path, "wb"),
|
||||
config["capture_limits"]["trace_bytes"],
|
||||
)
|
||||
process = target.Launch(_launch_info(target, config, listener), error)
|
||||
process_created = process.IsValid()
|
||||
@@ -862,6 +863,7 @@ def trace(debugger, config):
|
||||
"breakpoint_locations_truncated": breakpoint_locations_truncated,
|
||||
"events": events,
|
||||
"resource_limit_reached": outcome == "resource-limit",
|
||||
"resource_limit": context.get("resource_limit"),
|
||||
"target_output": {
|
||||
"stdout_bytes": stdout.bytes,
|
||||
"stderr_bytes": stderr.bytes,
|
||||
|
||||
@@ -121,6 +121,7 @@ class NativeTraceBudgetTests(unittest.TestCase):
|
||||
result = tracer.trace(Debugger(), {
|
||||
"executable": "fixture", "architecture": "arm64", "expected_sha256": "expected",
|
||||
"breakpoints": [], "working_directory": "fixture/absent",
|
||||
"capture_limits": {"output_bytes": 1024},
|
||||
"stdout_path": "stdout", "stdout_capture_path": "stdout-capture",
|
||||
"stderr_path": "stderr", "stderr_capture_path": "stderr-capture",
|
||||
})
|
||||
@@ -320,37 +321,44 @@ class NativeTraceBudgetTests(unittest.TestCase):
|
||||
return super().flush()
|
||||
|
||||
stream = CountingStream()
|
||||
journal = tracer._ObservationJournal(stream)
|
||||
journal = tracer._ObservationJournal(stream, max_bytes=4096)
|
||||
journal.append({"kind": "event", "event": {"sequence": 0}})
|
||||
journal.append({"kind": "other-stop", "reason": "signal"})
|
||||
self.assertEqual((stream.writes, stream.flushes), (2, 2))
|
||||
self.assertEqual(journal.bytes, len(stream.getvalue()))
|
||||
|
||||
def test_aggregate_trace_budget_admits_exact_boundary_and_rejects_next_record(self):
|
||||
self.assertTrue(
|
||||
tracer._can_retain_trace(
|
||||
tracer.MAX_TRACE_BYTES - 10,
|
||||
tracer.MAX_TRACE_FRAMES - 2,
|
||||
10,
|
||||
2,
|
||||
)
|
||||
)
|
||||
self.assertFalse(
|
||||
tracer._can_retain_trace(
|
||||
tracer.MAX_TRACE_BYTES - 10,
|
||||
tracer.MAX_TRACE_FRAMES - 2,
|
||||
11,
|
||||
2,
|
||||
)
|
||||
)
|
||||
self.assertFalse(
|
||||
tracer._can_retain_trace(
|
||||
tracer.MAX_TRACE_BYTES - 10,
|
||||
tracer.MAX_TRACE_FRAMES - 2,
|
||||
10,
|
||||
3,
|
||||
)
|
||||
def test_aggregate_trace_budget_uses_the_selected_admission(self):
|
||||
limits = {"trace_bytes": 100, "trace_frames": 10}
|
||||
self.assertTrue(tracer._can_retain_trace(90, 8, 10, 2, limits))
|
||||
self.assertFalse(tracer._can_retain_trace(90, 8, 11, 2, limits))
|
||||
self.assertFalse(tracer._can_retain_trace(90, 8, 10, 3, limits))
|
||||
raised = {"trace_bytes": 101, "trace_frames": 11}
|
||||
self.assertTrue(tracer._can_retain_trace(90, 8, 11, 3, raised))
|
||||
|
||||
def test_breakpoint_reports_exact_exhausted_budget_and_accepts_more_room(self):
|
||||
frame = types.SimpleNamespace(
|
||||
IsValid=lambda: True, GetPC=lambda: 1,
|
||||
GetThread=lambda: types.SimpleNamespace(GetNumFrames=lambda: 1),
|
||||
GetPCAddress=lambda: object(),
|
||||
)
|
||||
context = {
|
||||
"target": object(), "events": [], "retained_frames": 1,
|
||||
"retained_trace_bytes": 0,
|
||||
"config": {"breakpoints": [{}], "backtrace_frames": 0, "max_events": 10,
|
||||
"capture_limits": {"trace_bytes": 4096, "trace_frames": 1}},
|
||||
}
|
||||
with patch.object(tracer, "_location", return_value={"symbol": "main"}), patch.object(
|
||||
tracer, "_wanted", return_value=True
|
||||
), patch.object(tracer, "_record", return_value={"backtrace": []}):
|
||||
self.assertEqual(tracer._handle_breakpoint(context, frame, 0), "resource-limit")
|
||||
self.assertEqual(context["resource_limit"], "trace_frames")
|
||||
context["config"]["capture_limits"] = {"trace_bytes": 8, "trace_frames": 2}
|
||||
self.assertEqual(tracer._handle_breakpoint(context, frame, 0), "resource-limit")
|
||||
self.assertEqual(context["resource_limit"], "trace_bytes")
|
||||
self.assertEqual(context["events"], [])
|
||||
context["config"]["capture_limits"]["trace_bytes"] = 4096
|
||||
self.assertIsNone(tracer._handle_breakpoint(context, frame, 0))
|
||||
self.assertEqual(context["events"], [{"backtrace": []}])
|
||||
|
||||
def test_oversized_producer_string_is_rejected_before_serialization(self):
|
||||
self.assertTrue(tracer._fits_trace_budget("method", 1024))
|
||||
@@ -459,6 +467,7 @@ class NativeTraceBudgetTests(unittest.TestCase):
|
||||
object(),
|
||||
[[Breakpoint()]],
|
||||
{
|
||||
"capture_limits": {"breakpoint_location_bytes": 4096},
|
||||
"breakpoints": [
|
||||
{
|
||||
"kind": "objc-method",
|
||||
@@ -493,7 +502,7 @@ class NativeTraceBudgetTests(unittest.TestCase):
|
||||
side_effect=lambda address, _target: {"address": address, "symbol": None},
|
||||
), patch.object(tracer, "_wanted", return_value=True):
|
||||
report, locations_truncated = tracer._breakpoint_report(
|
||||
object(), [[Breakpoint()]], {"breakpoints": [{}]}
|
||||
object(), [[Breakpoint()]], {"breakpoints": [{}], "capture_limits": {"breakpoint_location_bytes": 4096}}
|
||||
)
|
||||
|
||||
self.assertEqual(report[0]["location_count"], 65)
|
||||
@@ -574,9 +583,10 @@ class NativeTraceBudgetTests(unittest.TestCase):
|
||||
def GetLocationAtIndex(self, index):
|
||||
return Location()
|
||||
|
||||
breakpoint_count = 1000
|
||||
breakpoint_count = 30
|
||||
created = [[Breakpoint()] for _ in range(breakpoint_count)]
|
||||
config = {"breakpoints": [{"kind": "objc-method"}] * breakpoint_count}
|
||||
config = {"breakpoints": [{"kind": "objc-method"}] * breakpoint_count,
|
||||
"capture_limits": {"breakpoint_location_bytes": 512 * 1024}}
|
||||
for source_path in (None, "/tmp/" + "源🚀" * 3000 + "/calls.pas"):
|
||||
with self.subTest(source_path_present=source_path is not None):
|
||||
report, locations_truncated = tracer._breakpoint_report(
|
||||
@@ -590,13 +600,13 @@ class NativeTraceBudgetTests(unittest.TestCase):
|
||||
)
|
||||
self.assertTrue(locations_truncated)
|
||||
self.assertEqual(
|
||||
sum(row["location_count"] for row in report), 64_000
|
||||
sum(row["location_count"] for row in report), 1920
|
||||
)
|
||||
self.assertLess(
|
||||
sum(len(row["locations"]) for row in report), 64_000
|
||||
sum(len(row["locations"]) for row in report), 1920
|
||||
)
|
||||
self.assertLessEqual(
|
||||
retained_bytes, tracer.MAX_BREAKPOINT_LOCATION_BYTES
|
||||
retained_bytes, 512 * 1024
|
||||
)
|
||||
if source_path is not None:
|
||||
self.assertTrue(
|
||||
|
||||
@@ -78,14 +78,9 @@ 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();
|
||||
@@ -94,6 +89,13 @@ 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);
|
||||
|
||||
@@ -5,7 +5,6 @@ from pathlib import Path
|
||||
import resource
|
||||
import gdb
|
||||
|
||||
OUTPUT_BYTES = 64 * 1024 * 1024
|
||||
|
||||
|
||||
class ContextFailure(Exception):
|
||||
@@ -79,6 +78,7 @@ def failure_exit(request_path, status, marker):
|
||||
def main():
|
||||
request_path = os.environ["REA_CORE_CONTEXT_REQUEST"]
|
||||
request = json.loads(Path(request_path).read_text(encoding="utf-8"))
|
||||
output_bytes = request["producer_limits"]["output_bytes"]
|
||||
reserve = bytearray(1024 * 1024)
|
||||
try:
|
||||
reply = {"ok": True, "value": inspect(request)}
|
||||
@@ -94,8 +94,8 @@ def main():
|
||||
reply = {"ok": False, "reason": "decoder", "message": type(error).__name__ + ": " + str(error)}
|
||||
try:
|
||||
encoded = json.dumps(reply, ensure_ascii=True, allow_nan=False).encode("utf-8")
|
||||
if len(encoded) > OUTPUT_BYTES:
|
||||
encoded = json.dumps({"ok": False, "reason": "output-limit", "message": "Complete debugger context exceeds the 64 MiB reply budget."}).encode("utf-8")
|
||||
if len(encoded) > output_bytes:
|
||||
encoded = json.dumps({"ok": False, "reason": "output-limit", "message": "Complete debugger context exceeds producer_limits.output_bytes=" + str(output_bytes) + "."}).encode("utf-8")
|
||||
descriptor = os.open(request["reply_path"], os.O_WRONLY | os.O_CREAT | os.O_EXCL, 0o600)
|
||||
with os.fdopen(descriptor, "wb") as handle:
|
||||
handle.write(encoded)
|
||||
|
||||
@@ -14,7 +14,7 @@ BRIDGE = Path(__file__).with_name("core_context.py")
|
||||
|
||||
|
||||
class CoreContextTests(unittest.TestCase):
|
||||
def inspect(self, failure=None, connection="core", symbols=None, architecture="x86_64-little-endian", objfile="recorded-executable"):
|
||||
def inspect(self, failure=None, connection="core", symbols=None, architecture="x86_64-little-endian", objfile="recorded-executable", output_bytes=16384):
|
||||
commands, reads, queries = [], [], []
|
||||
state = {"executable": None, "symbols": None, "connection": None}
|
||||
gdb = types.ModuleType("gdb")
|
||||
@@ -63,7 +63,7 @@ class CoreContextTests(unittest.TestCase):
|
||||
plugin.write_text("")
|
||||
request = stage / "request.json"
|
||||
reply = stage / "reply.json"
|
||||
request.write_text(json.dumps({"gdbinit": str(plugin), "architecture": architecture, "snapshot_path": str(root / "object.snapshot"), "reply_path": str(reply)}))
|
||||
request.write_text(json.dumps({"gdbinit": str(plugin), "architecture": architecture, "snapshot_path": str(root / "object.snapshot"), "reply_path": str(reply), "producer_limits": {"output_bytes": output_bytes}}))
|
||||
with patch.dict(sys.modules, modules), patch.dict(os.environ, REA_CORE_CONTEXT_REQUEST=str(request)):
|
||||
runpy.run_path(str(BRIDGE))
|
||||
result = json.loads(reply.read_text())
|
||||
@@ -104,14 +104,15 @@ class CoreContextTests(unittest.TestCase):
|
||||
self.assertEqual(reads, [])
|
||||
self.assertEqual(queries, [])
|
||||
|
||||
def test_output_limit_message_separates_the_words_and_names_the_limit(self):
|
||||
result, _, reads, queries = self.inspect(objfile="m" * (64 * 1024 * 1024))
|
||||
def test_selected_output_limit_reports_recovery_and_accepts_more_headroom(self):
|
||||
result, _, reads, queries = self.inspect(objfile="m" * 2048, output_bytes=1024)
|
||||
self.assertFalse(result["ok"])
|
||||
self.assertEqual(result["reason"], "output-limit")
|
||||
self.assertNotIn("exceeds64", result["message"])
|
||||
self.assertIn("64 MiB", result["message"])
|
||||
self.assertIn("producer_limits.output_bytes=1024", result["message"])
|
||||
self.assertEqual(reads, [])
|
||||
self.assertEqual(queries, ["maps"])
|
||||
recovered, _, _, _ = self.inspect(objfile="m" * 2048, output_bytes=4096)
|
||||
self.assertTrue(recovered["ok"], recovered)
|
||||
|
||||
def test_wrong_connection_or_remaining_symbols_never_queries_mappings(self):
|
||||
for options in [{"connection": "native"}, {"symbols": "unexpected-symbols"}]:
|
||||
|
||||
@@ -5,14 +5,12 @@ from pathlib import Path
|
||||
import resource
|
||||
import sys
|
||||
|
||||
OUTPUT_BYTES = 64 * 1024 * 1024
|
||||
|
||||
def lower_resource_limits():
|
||||
def lower_resource_limits(policy):
|
||||
limits = {}
|
||||
for name, kind, maximum in (
|
||||
("address_space_bytes", resource.RLIMIT_AS, 3 * 1024**3),
|
||||
("cpu_seconds", resource.RLIMIT_CPU, 30),
|
||||
("file_size_bytes", resource.RLIMIT_FSIZE, OUTPUT_BYTES),
|
||||
("address_space_bytes", resource.RLIMIT_AS, policy["address_space_bytes"]),
|
||||
("cpu_seconds", resource.RLIMIT_CPU, policy["cpu_seconds"]),
|
||||
("file_size_bytes", resource.RLIMIT_FSIZE, policy["file_bytes"]),
|
||||
):
|
||||
soft, hard = resource.getrlimit(kind)
|
||||
finite = [maximum] + [value for value in (soft, hard) if value != resource.RLIM_INFINITY]
|
||||
@@ -25,6 +23,11 @@ def lower_resource_limits():
|
||||
|
||||
def main(request_path, inspect, failure_type, profile):
|
||||
request = json.loads(Path(request_path).read_text(encoding="utf-8"))
|
||||
policy = request["producer_limits"]
|
||||
for key in ("input_bytes", "output_bytes", "diagnostic_bytes", "address_space_bytes", "file_bytes", "cpu_seconds"):
|
||||
value = policy[key]
|
||||
if type(value) is not int or not 1 <= value <= 9007199254740991:
|
||||
raise ValueError("producer_limits." + key + " must be a positive safe integer")
|
||||
os.environ["PWNLIB_NOTERM"] = "1"
|
||||
os.environ["PWNLIB_CACHE_DIR"] = str(Path(request_path).parent / "cache")
|
||||
limits = None
|
||||
@@ -32,7 +35,7 @@ def main(request_path, inspect, failure_type, profile):
|
||||
# The outer exit-status contract also covers allocation failure during serialization.
|
||||
memory_reserve = bytearray(1024 * 1024)
|
||||
try:
|
||||
limits = lower_resource_limits()
|
||||
limits = lower_resource_limits(policy)
|
||||
descriptor = os.open(Path(request_path).parent / "limits.json", os.O_WRONLY | os.O_CREAT | os.O_EXCL, 0o600)
|
||||
with os.fdopen(descriptor, "w", encoding="utf-8") as handle:
|
||||
json.dump(limits, handle)
|
||||
@@ -51,8 +54,8 @@ def main(request_path, inspect, failure_type, profile):
|
||||
else:
|
||||
reply = {"ok": False, "reason": "decoder", "message": type(error).__name__ + ": " + str(error)}
|
||||
encoded = json.dumps(reply, ensure_ascii=True, allow_nan=False).encode("utf-8")
|
||||
if len(encoded) > OUTPUT_BYTES:
|
||||
encoded = json.dumps({"ok": False, "reason": "output-limit", "message": "Complete artifact result exceeds the 64 MiB reply budget."}).encode("utf-8")
|
||||
if len(encoded) > policy["output_bytes"]:
|
||||
encoded = json.dumps({"ok": False, "reason": "output-limit", "message": "Complete artifact result exceeds producer_limits.output_bytes=" + str(policy["output_bytes"]) + "."}).encode("utf-8")
|
||||
descriptor = os.open(request["reply_path"], os.O_WRONLY | os.O_CREAT | os.O_EXCL, 0o600)
|
||||
with os.fdopen(descriptor, "wb") as handle:
|
||||
handle.write(encoded)
|
||||
|
||||
@@ -43,11 +43,31 @@ export const documentationSections = [
|
||||
source: "guides/native/binary-diagnostics.md",
|
||||
route: "/binary-diagnostics",
|
||||
},
|
||||
{
|
||||
text: "ELF and Mach-O initializer functions",
|
||||
source: "guides/native/native-initializers.md",
|
||||
route: "/native-initializers",
|
||||
},
|
||||
{
|
||||
text: "ELF unwind function ranges",
|
||||
source: "guides/native/elf-unwind-ranges.md",
|
||||
route: "/elf-unwind-ranges",
|
||||
},
|
||||
{
|
||||
text: "Linux kernel build config",
|
||||
source: "guides/native/kernel-build-config.md",
|
||||
route: "/kernel-build-config",
|
||||
},
|
||||
{
|
||||
text: "Recorded crash evidence",
|
||||
source: "guides/native/recorded-crashes.md",
|
||||
route: "/recorded-crashes",
|
||||
},
|
||||
{
|
||||
text: "Windows Shell Link shortcuts",
|
||||
source: "guides/native/windows-shortcut.md",
|
||||
route: "/windows-shortcut",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
@@ -88,6 +108,11 @@ 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",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
@@ -398,6 +423,11 @@ export const documentationSections = [
|
||||
source: "bun-standalone.md",
|
||||
route: "/bun-standalone",
|
||||
},
|
||||
{
|
||||
text: "Deno compile executables",
|
||||
source: "deno-standalone.md",
|
||||
route: "/deno-standalone",
|
||||
},
|
||||
{
|
||||
text: "Capability composition and ownership",
|
||||
source: "capability-composition.md",
|
||||
|
||||
@@ -16,7 +16,11 @@ product pages. The VitePress documentation source is this `docs/` tree.
|
||||
- [Native binary investigation](guides/native/native-investigation.md)
|
||||
- [Go binary build metadata](guides/native/go-binaries.md)
|
||||
- [Offline binary diagnostics](guides/native/binary-diagnostics.md)
|
||||
- [ELF and Mach-O initializer functions](guides/native/native-initializers.md)
|
||||
- [ELF unwind function ranges](guides/native/elf-unwind-ranges.md)
|
||||
- [Linux kernel build config](guides/native/kernel-build-config.md)
|
||||
- [Recorded crash evidence](guides/native/recorded-crashes.md)
|
||||
- [Windows Shell Link shortcuts](guides/native/windows-shortcut.md)
|
||||
|
||||
## JavaScript and Electron
|
||||
|
||||
@@ -27,6 +31,7 @@ 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
|
||||
|
||||
@@ -106,6 +111,10 @@ product pages. The VitePress documentation source is this `docs/` tree.
|
||||
## Development and verification
|
||||
|
||||
- [Settings and recovery](design/limits-and-recovery.md)
|
||||
- [Flutter budget calibration](verification/flutter-budget-calibration.md)
|
||||
- [Source-map budget calibration](verification/source-map-budget-calibration.md)
|
||||
- [Source-location delivery qualification](verification/source-location-delivery.md)
|
||||
- [JavaScript precision calibration](verification/javascript-precision-calibration.md)
|
||||
- [MCP tool design](development/tool-design.md)
|
||||
- [Testing REA](development/testing.md)
|
||||
- [Client and agent verification](development/client-verification.md)
|
||||
@@ -143,6 +152,7 @@ the exact commit messages and references from the release they describe.
|
||||
|
||||
- [Offline API contract inventory](api-contracts.md)
|
||||
- [Bun standalone executables](bun-standalone.md)
|
||||
- [Deno compile executables](deno-standalone.md)
|
||||
- [Capability composition and ownership](capability-composition.md)
|
||||
- [.NET single-file bundles](dotnet-bundles.md)
|
||||
- [ESP flash images](esp-flash-image.md)
|
||||
|
||||
@@ -107,7 +107,10 @@ refusal names its stage: `environment-build` for the build's own checks,
|
||||
`inspect_web_network_capture` and `inspect_analysis_view` for inspection and
|
||||
projection, `environment-export` for the bundle. SIGINT cancels the build
|
||||
(`cancelled`); before the bundle stage nothing is written, and a cancellation
|
||||
during the write names the bundle it wrote. Stage progress is logged to stderr
|
||||
after publication preserves the bundle receipt. Before publication, a failed
|
||||
write attempts to remove partial output and reports cleanup failures. See
|
||||
[bundle publication and recovery](getting-started/cli.md#export-an-environment-bundle).
|
||||
Stage progress is logged to stderr
|
||||
at info level; the report is the only output on stdout:
|
||||
|
||||
```json
|
||||
@@ -209,9 +212,9 @@ warning does not establish that these bodies were checked. A browser scenario's
|
||||
saved values (`save` and `save_response`) named like credentials but not marked
|
||||
`secret: true` are recorded unredacted; `credential-named-saved-values` lists up
|
||||
to 20 of them by parameter pointer. Names do not establish sensitivity,
|
||||
so the build never refuses on them. Capture
|
||||
so the build never refuses on them.
|
||||
|
||||
Evidence also records the capture file's absolute path (`subject.local_path`,
|
||||
Capture Evidence also records the capture file's absolute path (`subject.local_path`,
|
||||
`parameters.capture_path`, `locations`, `artifact.path`), and the bundle
|
||||
carries it: build from a neutral folder when that path should not ship.
|
||||
|
||||
@@ -332,9 +335,12 @@ scenario is written and cannot use a value an earlier response returned, so an
|
||||
id must be known before the run: one the caller chooses, such as a `uid` in the
|
||||
create body, or one an earlier scenario created. When the server assigns ids,
|
||||
read the list after each create (the create's response or the list shows the
|
||||
new entity), and record updates and deletes in a second scenario that reads
|
||||
the first one's objects by id before editing them, or make them through the
|
||||
UI. The environment coverage view names each
|
||||
new entity). A second scenario can record updates and deletes using those
|
||||
known ids, but produces a separate environment: recordings are not combined.
|
||||
That scenario must include its own before/after reads and every action the
|
||||
environment should support; it does not inherit the first scenario's create
|
||||
evidence. To capture create and subsequent edits together, make them through
|
||||
the UI in one scenario. The environment coverage view names each
|
||||
write it withholds and what to record next. A scenario with write requests
|
||||
changes the application's data: record against an instance whose data may
|
||||
change.
|
||||
|
||||
+67
-4
@@ -85,9 +85,49 @@ canonical hexadecimal form), `EXC_GUARD` subtypes,
|
||||
pointer-authentication suffixes, and dyld missing-library strings. A report
|
||||
that matches none of those rules is `unclassified`.
|
||||
|
||||
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.
|
||||
## 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.
|
||||
|
||||
## Limits and failures
|
||||
|
||||
@@ -120,4 +160,27 @@ success or truncated integer facts.
|
||||
rea inspect-apple-ips /absolute/path/to/report.ips --max-integer-text-bytes 16777216 --json
|
||||
```
|
||||
|
||||
This workflow does not execute a target, launch atos, or search for dSYMs.
|
||||
`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.
|
||||
+18
-3
@@ -24,7 +24,7 @@ entry-point status, sizes and SHA-256. Sourcemaps, bytecode and module-info regi
|
||||
are separate children. Source names such as `/$bunfs/root/main.js` remain in
|
||||
metadata; extraction uses a relative path. Unsafe or non-UTF-8 names receive an
|
||||
indexed path and retain their source spelling or bytes. Virtual names deeper
|
||||
than 256 logical path parts also use an indexed path with an explicit limitation,
|
||||
than the selected `path_parts` allowance (default 256) also use an indexed path with an explicit limitation,
|
||||
preventing unbounded path-tree work while retaining the source fact. Duplicate names remain
|
||||
separate occurrences; ordinary extraction collision rules apply.
|
||||
|
||||
@@ -43,12 +43,27 @@ compatible source files; bytecode is retained as evidence, not decoded.
|
||||
Module parsing reads exact metadata ranges rather than loading stored asset
|
||||
bodies or whole pages around small pointers. A cache retains at most 256 KiB
|
||||
and 1,024 ranges for one reader preparation. Cumulative uncached metadata reads
|
||||
are limited to 256 MiB, checked before allocation or I/O. The module table,
|
||||
default to 256 MiB, checked before allocation or I/O. The module table,
|
||||
decoded strings and combined logical path tree have separate admission checks;
|
||||
at most 250,000 distinct path prefixes are admitted before inventory construction.
|
||||
by default at most 250,000 distinct path prefixes are admitted before inventory construction.
|
||||
Stored bodies are range-streamed for hashing and extraction. Header/suffix observations are reused
|
||||
only for the same admitted file state, with selected-path checks before publication.
|
||||
|
||||
Both artifact operations accept `artifact_limits.bun`. Its independent controls
|
||||
are `payload_bytes`, `module_count`, `representation_bytes`, `metadata_read_bytes`,
|
||||
`recognition_table_bytes`, `recognition_load_command_bytes`, `path_parts` and
|
||||
`path_nodes`. Failed recognition remains explicitly limited instead of proving
|
||||
absence. ELF section names are examined at their actual offsets, including names
|
||||
beyond a large section-name prefix. Select `artifact_limits.expanded_bytes` to
|
||||
change the aggregate referenced-plaintext work allowance.
|
||||
|
||||
For a reported metadata-read refusal, keep the same carrier and retry with
|
||||
`--artifact-limits '{"bun":{"metadata_read_bytes":536870912}}'` or the equivalent
|
||||
MCP `artifact_limits` object. Omitted fields keep defaults. The response names
|
||||
the effective limit and exact repair; accepted overrides are reported separately
|
||||
from caller selections. Changes apply on the next call without restarting REA.
|
||||
Summary and selected extraction do not change the producer's admission.
|
||||
|
||||
See [limits and recovery](design/limits-and-recovery.md) for admission ceilings.
|
||||
Synthetic tests cover the carriers and malformed declarations. Run
|
||||
`node scripts/verify-bun-standalone.mjs` after `npm run build:cached` for local Bun
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
# Deno compile executables
|
||||
|
||||
`inspect-artifact` inventories a `deno compile` executable. `extract-artifact` writes the embedded virtual files through the existing safe output tree. Neither operation runs the executable or the Deno runtime.
|
||||
|
||||
```sh
|
||||
rea inspect-artifact ./app --json
|
||||
rea extract-artifact ./app --json
|
||||
```
|
||||
|
||||
In MCP, open the executable with `open_binary`, then call `inspect_artifact`. Use `detail: "summary"` for a large virtual filesystem and `inspect_analysis_view` to page retained Evidence.
|
||||
|
||||
The recognized carriers are a Mach-O `__SUI` section named `d3n0l4nd`, an Intel Mach-O `<~sui-data~>` trailer, an ELF `PT_NOTE` or `SHT_NOTE` owned by `SUI` with type `0x53554901` and descriptor name `d3n0l4nd`, and a PE `RT_RCDATA` resource named `D3N0L4ND`. These are structural layouts. The metadata JSON has no Deno version field, so the compiler version stays unknown unless another record establishes it. Other layouts, including older eszip trailers, are unsupported.
|
||||
|
||||
Root metadata reports the carrier, entry point, argv, V8 flags, permission options, unstable configuration, application name, self-extracting marker, virtual-filesystem case sensitivity, and the npm snapshot byte length. The npm snapshot is not decoded. Each virtual file is one occurrence with its logical path, size, and SHA-256. Transpiled output, CJS export analysis, and source maps are separate occurrences beside that file. Each has the same `index` as the file and its own `role`. A region normally has the logical path of the file plus a `.deno-*` suffix. When that path belongs to another stored file, the region moves to an indexed path such as `deno-vfs/0.vfs-transpiled`, so read the reported `logical_path` instead of building it from the file name. They are not linked by `parent_occurrence_id`, which follows directories and expanded containers. Symlink targets stay recorded path parts and are never followed.
|
||||
|
||||
`Metadata.env_vars_from_env_file` holds values from a compile-time `--env-file`, and `ca_data` holds certificate bytes. Inventory retains the variable names and values, certificate bytes, counts, and byte lengths in local Evidence, so sharing that Evidence shares them. Extraction does not write them as files.
|
||||
|
||||
A virtual filesystem that cannot be listed reports `vfs_listing` as `unsupported` and leaves inventory and extraction coverage unknown, because its files are not examined.
|
||||
|
||||
Remote modules, redirects, and specifiers contribute counts and logical paths when their stored form is unambiguous. When it is not, they stay present with a byte length and an `unsupported` member listing. A module whose specifier is missing uses an indexed `deno-remote/<index>` path, which still exposes its stored bytes, and modules with resolved specifiers keep their paths. Colons, backslashes, and control characters in a specifier are percent-encoded in the logical path, so `http://localhost:8000/mod.ts` becomes `deno-remote/localhost%3A8000/mod.ts`. Percent escapes in a logical path use uppercase hex, and a specifier that reaches a path already taken uses an indexed path. `source_path` keeps the original specifier. A remote specifier is indexed the same way when a path component exceeds 255 UTF-8 bytes or the logical path exceeds 512 UTF-8 bytes, counting the `.deno-*` suffix of its stored regions. Unsafe, deep, or over-long virtual names use `deno-vfs/<index>` under the same rule and retain the original spelling when it fits the name allowance. A descendant does not present its own name as a complete source path when an ancestor spelling was dropped.
|
||||
|
||||
A length that overruns the section, or a closing marker that does not match, is malformed. An opening marker that is absent is unsupported. A confirmed section that cannot be parsed fails closed and does not fall through to a plain native inventory. An Intel Mach-O sentinel inside a confirmed trailer payload is data of that payload, so an Intel Deno executable stored as a virtual file does not replace the app that stores it. Trailers side by side with different bytes fail closed. A file is confirmed only by its carrier name, so an unrelated native file with malformed tables keeps its native inventory. That inventory does not establish that the file holds no Deno section.
|
||||
|
||||
See [limits and recovery](design/limits-and-recovery.md) for the named allowances. Synthetic tests cover the carriers and malformed declarations. Run `npm run verify:deno:standalone` for a local Deno compile of the host and, when the compiler can produce them, Linux, Windows, and Intel macOS targets. Deno is a fixture producer only and is not installed by REA. The produced executable is not run.
|
||||
|
||||
Layout reference: Deno `cli/lib/standalone/binary.rs` and `cli/lib/standalone/virtual_fs.rs` at 2.9.8, with libsui 0.16.4 section placement.
|
||||
@@ -172,17 +172,20 @@ checks all happen before publishing the replacement snapshot; a rejected batch
|
||||
cannot partially apply. Clients coordinating writes can supply
|
||||
`expected_revision`; without it, valid updates apply to the current state.
|
||||
|
||||
| Runtime setting | Application point |
|
||||
| ------------------------------------------------------------- | ---------------------------------------------------------------------- |
|
||||
| `asar.max_header_bytes` | Next archive operation, including full JavaScript application analysis |
|
||||
| `ghidra.startup_timeout_ms`, `hopper.startup_timeout_ms` | Next provider startup attempt |
|
||||
| `ghidra.decompile_timeout_seconds` | Next operation on the existing Ghidra Program; `null` means unbounded |
|
||||
| `jadx.operation_timeout_ms` | Next JADX operation |
|
||||
| `regex.matching_deadline_ms`, `regex.worker_heap_request_mib` | Next search / new regex worker |
|
||||
| `capture.decoder_old_generation_mib` | Next owned capture decoder |
|
||||
| `javascript.analysis_timeout_ms`, `javascript.max_heap_mb` | Next source analysis / new JavaScript worker |
|
||||
| `wasm.command_timeout_ms` | Next WABT operation |
|
||||
| `native.matching_representation_bytes` | Next `match_native_functions` request |
|
||||
| Runtime setting | Application point |
|
||||
| --------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------- |
|
||||
| `asar.max_header_bytes` | Next archive operation, including full JavaScript application analysis |
|
||||
| `asar.max_listing_bytes` | Next expanded ASAR listing, independently of packed header bytes |
|
||||
| `ghidra.startup_timeout_ms`, `hopper.startup_timeout_ms` | Next provider startup attempt |
|
||||
| `ghidra.decompile_timeout_seconds` | Next operation on the existing Ghidra Program; `null` means unbounded |
|
||||
| `ghidra.decompile_max_payload_mib` | Next native decompile; `null` preserves the selected provider's payload default |
|
||||
| `ghidra.value_flow_max_operations`, `ghidra.value_flow_max_inputs_per_operation`, `ghidra.value_flow_max_edges` | Next function value-flow projection on the existing Program |
|
||||
| `jadx.operation_timeout_ms` | Next JADX operation |
|
||||
| `regex.matching_deadline_ms`, `regex.worker_heap_request_mib` | Next search / new regex worker |
|
||||
| `capture.decoder_old_generation_mib` | Next owned capture decoder |
|
||||
| `javascript.analysis_timeout_ms`, `javascript.max_heap_mb` | Next source analysis / new JavaScript worker |
|
||||
| `wasm.command_timeout_ms` | Next WABT operation |
|
||||
| `native.matching_representation_bytes` | Next `match_native_functions` request |
|
||||
|
||||
### Precedence and lifetime
|
||||
|
||||
@@ -202,6 +205,48 @@ for an unknown or omitted value elsewhere.
|
||||
A write does not extend active work, relaunch a provider, clear retained
|
||||
cleanup, or invalidate successful Evidence.
|
||||
|
||||
Expanded ASAR listing admission defaults to 64 MiB and has its own launch seed,
|
||||
`REA_ASAR_MAX_LISTING_BYTES`. Raising `asar.max_header_bytes` alone cannot admit
|
||||
expanded paths and entries that exceed this separate budget. The listing bound
|
||||
uses exact safe-integer byte accounting; the host heap and transport constraints
|
||||
remain independent. A lower runtime value is enforced on the next listing even
|
||||
when the archive header was already examined.
|
||||
|
||||
Ghidra value-flow controls default to 3,000 operations, 64 inputs per operation,
|
||||
and 12,000 edges. They accept positive Java integer counts and use the respective
|
||||
`REA_GHIDRA_VALUE_FLOW_MAX_OPERATIONS`,
|
||||
`REA_GHIDRA_VALUE_FLOW_MAX_INPUTS_PER_OPERATION`, and
|
||||
`REA_GHIDRA_VALUE_FLOW_MAX_EDGES` launch seeds. Truncation names the exhausted
|
||||
control. Completed Evidence remains accessible, but a new function dossier is
|
||||
observed with the accepted controls instead of replaying an earlier projection.
|
||||
|
||||
The native decompiler payload control is separate from those projections and
|
||||
from decompile time. Its launch seed is
|
||||
`REA_GHIDRA_DECOMPILE_MAX_PAYLOAD_MIB`. Accepted explicit values are 1..2047 MiB:
|
||||
the supported Ghidra implementation shifts that value into a signed integer byte
|
||||
capacity. Omission or runtime `null` keeps the provider's own default; REA does
|
||||
not guess that default from a different provider version. Changing payload
|
||||
options takes effect before the next native decompile.
|
||||
|
||||
### Per-call resource policies and selection
|
||||
|
||||
An agent can also use controls declared directly by an operation. These do not
|
||||
require a runtime setter or restart. Keep omitted fields omitted in Evidence;
|
||||
report the resolved policy separately where needed. See the owning guides for
|
||||
[Apktool string pages](../guides/android/apktool-resource-analysis.md),
|
||||
[source maps](../guides/web/web-source-location.md),
|
||||
[historical captures](../guides/web/web-network-captures.md),
|
||||
[JavaScript precision](../guides/javascript/javascript-application-graph.md),
|
||||
[managed inspection](../guides/managed/managed-code-analysis.md), and
|
||||
[Frida capture](../guides/runtime/frida-instrumentation.md).
|
||||
|
||||
The same accepted policy must reach acquisition, parsing, worker requests,
|
||||
serialization, cached-result admission and generated consumers where those
|
||||
stages exist. Desktop state views and emitted AgentEnv Python share one policy;
|
||||
delivery pagination never substitutes for producer selection. Capture limits
|
||||
must be selected before an experiment: another experiment cannot recover bytes
|
||||
that were dropped from a previous live observation.
|
||||
|
||||
Overrides belong to one REA runtime, survive target close/open, and disappear
|
||||
when REA exits. Connections sharing that runtime share its overrides. No files,
|
||||
ambient environment, registrations or upstream software are edited. Overrides
|
||||
@@ -419,14 +464,107 @@ editable setting or active worker telemetry.
|
||||
|
||||
## Bun standalone module graphs
|
||||
|
||||
`MAX_BUN_MODULE_COUNT` admits at most 100,000 module records.
|
||||
`MAX_BUN_RETAINED_BYTES` admits at most 256 MiB of serialized graph payload and
|
||||
separately bounds retained entry metadata. Physical metadata read work is also
|
||||
limited to 256 MiB per preparation, including repeated uncached ranges. A
|
||||
256 KiB / 1,024-entry exact-range cache avoids full-page amplification. The
|
||||
combined logical path tree admits at most 250,000 distinct prefixes; this is
|
||||
checked before adding nodes, with shared prefixes counted once. The shared
|
||||
artifact expansion budget also bounds the sum of referenced member lengths. Refusals name the boundary.
|
||||
There is no runtime override; additional host memory or `NODE_OPTIONS` does not
|
||||
raise these ceilings. Use a smaller producer fixture or a separately reviewed
|
||||
reader for larger graphs. No partial extraction is claimed on admission failure.
|
||||
`inspect_artifact` and `extract_artifact` accept per-call `artifact_limits`.
|
||||
The `bun` group defaults to 100,000 modules, independent 256 MiB payload,
|
||||
retained-representation and physical metadata-read allowances, 256 path parts
|
||||
and 250,000 logical path nodes. Recognition separately admits a 1 MiB ELF
|
||||
section table and 16 MiB Mach-O load commands. Exhausted recognition remains
|
||||
unknown rather than proving the carrier has no Bun graph. Inventory preserves
|
||||
native-root facts or another confirmed pack and reports the exact unexamined
|
||||
alternative inline; it does not assert Bun presence. ELF section names
|
||||
are examined with exact bounded reads, including names beyond the former
|
||||
prefix window.
|
||||
|
||||
For example, keep the same complete carrier and retry a reported recognition
|
||||
limitation with `{"artifact_limits":{"bun":{"recognition_table_bytes":2097152}}}`.
|
||||
The CLI spelling is `--artifact-limits '{"bun":{"recognition_table_bytes":2097152}}'`.
|
||||
No REA restart is needed. A smaller later selection is re-admitted; previously
|
||||
parsed facts cannot bypass it. The 256 KiB / 1,024-entry exact-range cache
|
||||
avoids full-page amplification and remains an internal optimization, not an agent
|
||||
resource setting. Shared logical path prefixes count once before nodes are added.
|
||||
|
||||
## Artifact reader admission
|
||||
|
||||
The same request provides `dotnet_bundle`, `node_sea` and `godot` groups. Their
|
||||
controls apply when recognition or inventory encounters that format; supplying
|
||||
a policy does not assert the format is present. Unsupported keys are rejected.
|
||||
Each group follows one domain-owned default policy. See [.NET bundles](../dotnet-bundles.md),
|
||||
[Node SEA](../node-sea.md), [Godot PCK](../godot-pck.md) and
|
||||
[Bun standalone](../bun-standalone.md) for format semantics.
|
||||
|
||||
`artifact_limits.expanded_bytes` selects aggregate plaintext work for ZIP, Bun,
|
||||
SEA and PCK readers, including repeated readable logical occurrences. Omission
|
||||
retains each archive's encoded-size-derived default. The .NET bundle group's
|
||||
own `expanded_bytes` controls its independently enforced bundle expansion.
|
||||
|
||||
Failures preserve `details.reader_limit` with the exact parameter, effective
|
||||
value, units, supported range, required value when known, next-call scope and
|
||||
`can_increase`. When `can_increase` is true, raise that field and retry the same
|
||||
complete artifact. At the supported maximum, or when the required representation
|
||||
exceeds it, the failure is not retryable by increasing that budget; inspect the
|
||||
declared dimensions and input validity, or explicitly choose a suitable reader.
|
||||
Summary, pagination and
|
||||
selected extraction do not bypass producing admission. Intrinsic format,
|
||||
safe-integer, path validity and runtime representation constraints remain fixed.
|
||||
|
||||
Evidence parameters retain the exact selected object, including omission or
|
||||
`{}`. When an object was selected, inventory and extraction report the resolved
|
||||
`effective_limits`; summaries preserve those facts. These are accepted policies,
|
||||
not process-memory telemetry or a claim that every format reader ran. Complete
|
||||
source identities and graph manifests remain content-addressed independently
|
||||
of delivery selection. No partial extraction is claimed on admission failure.
|
||||
|
||||
## Deno compile sections
|
||||
|
||||
`MAX_DENO_METADATA_JSON_BYTES` admits at most 8 MiB of metadata JSON.
|
||||
`MAX_DENO_VFS_HEADER_JSON_BYTES` admits at most 32 MiB of virtual-filesystem
|
||||
header JSON. Specifier, redirect, and remote tables each admit at most 100,000
|
||||
records. Specifier text admits at most 8 MiB, and remote module bodies admit at
|
||||
most 256 MiB. The virtual filesystem admits at most 100,000 directory, file,
|
||||
and symlink records and at most 512 nested levels (`MAX_DENO_VFS_DEPTH`). A
|
||||
name longer than 4,096 UTF-16 code units is indexed and is not retained.
|
||||
`MAX_DENO_VFS_RETAINED_UNITS` admits at most 32 million UTF-16 code units across
|
||||
the source path built for every entry, directories included, and retained
|
||||
symlink parts. A logical path deeper than 256 parts, a name that is not a safe
|
||||
relative path, a path component longer than 255 UTF-8 bytes
|
||||
(`MAX_DENO_PATH_COMPONENT_BYTES`, POSIX `NAME_MAX`), or a logical path longer
|
||||
than 512 UTF-8 bytes (`MAX_DENO_LOGICAL_PATH_BYTES`, half of the Darwin
|
||||
`PATH_MAX`) uses an indexed path and keeps the original spelling when that
|
||||
spelling is within the name allowance. Component and path lengths include the
|
||||
`.deno-*` suffix of the stored regions a member has. A descendant has no source
|
||||
path when an ancestor spelling was not retained. Cancellation is checked before
|
||||
the virtual-filesystem walk. The walk does not yield, so it does not observe a
|
||||
cancellation that arrives while it is running; the retained allowance bounds its
|
||||
work. The combined logical path tree admits at most 250,000 distinct prefixes.
|
||||
`MAX_DENO_RETAINED_BYTES` admits at most 256 MiB of retained header and entry
|
||||
metadata. The shared artifact expansion budget also bounds the sum of referenced
|
||||
member lengths, with a 256 MiB floor.
|
||||
|
||||
Carrier location claims a file only after it confirms the carrier name: a
|
||||
Mach-O `__SUI` segment, a `SUI` ELF note descriptor named `d3n0l4nd`, a PE
|
||||
`D3N0L4ND` resource, or an Intel trailer opening with `d3n0l4nd`. Before that,
|
||||
malformed tables and exhausted search budgets leave the file with native
|
||||
inventory, and that inventory makes no claim that the file holds no Deno
|
||||
section. ELF location reads ELF and note headers, not the whole image, and does
|
||||
not hash note descriptors. An ELF larger than 512 MiB is still located when
|
||||
those headers fit. Program and section tables are read at their canonical record
|
||||
size, so the 16-bit header count bounds each read at 65,535 records. A table
|
||||
that cannot be read, or that uses extended program numbering, is skipped and
|
||||
another table can still hold the note. At most 256 notes are examined
|
||||
(`MAX_INSPECT_ELF_NOTE_ENTRIES`). A damaged table or the note ceiling is a
|
||||
refusal only when a `SUI` note was also confirmed. Intel Mach-O trailer search
|
||||
reads each scanned byte at most once and examines at most 64 `<~sui-data~>`
|
||||
sentinels (`MAX_DENO_INTEL_TRAILER_SENTINELS`). The search continues past a
|
||||
confirmed trailer, because an enclosing trailer can hold it as a stored file, so
|
||||
reaching that allowance after a confirmation is a refusal. PE location walks the resource directories to the named payload and
|
||||
does not read the image whole, so a PE of any size is located when the
|
||||
`D3N0L4ND` payload is within the 512 MiB resource reader ceiling. A larger
|
||||
payload, or a confirmed resource that cannot be resolved, is a named refusal.
|
||||
Refusals name the boundary. There is no runtime override; additional host memory
|
||||
or `NODE_OPTIONS` does not raise these ceilings. Duplicate-section verification
|
||||
rejects unequal lengths before hashing, stops at the first digest mismatch,
|
||||
and reads at most the carrier file size in aggregate
|
||||
payload bytes. Overlapping copies that exceed that allowance are refused.
|
||||
Environment-file values and CA certificate bytes are retained in local Evidence
|
||||
with their counts and byte lengths. The npm snapshot length is retained and its
|
||||
bytes are not decoded.
|
||||
@@ -47,6 +47,17 @@ 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.
|
||||
|
||||
A nested desktop file uses a dashed ID: `vendor/app.desktop` has ID
|
||||
`vendor-app`. REA checks path spellings that can encode that ID within each
|
||||
XDG root before trying the next root. Unrelated directories do not affect
|
||||
selection. If an applicable path cannot be examined or the bounded search
|
||||
cannot establish absence, capture reports an incomplete desktop-entry search
|
||||
rather than selecting a different application from a later root.
|
||||
|
||||
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
|
||||
@@ -56,6 +67,9 @@ environment, and reads commands from stdin, one per line. The application gets
|
||||
REA's environment without the `AGENTENV_*` variables an agent environment sets,
|
||||
such as its control token: an app the exported computer launches never has
|
||||
them, and an app captured inside a computer must not hold a credential to it.
|
||||
It also gets `LIBC_FATAL_STDERR_=1`, so glibc writes a fatal error, such as
|
||||
an abort's reason, to the app's stderr rather than its terminal, and an app
|
||||
that exits at launch reports it.
|
||||
|
||||
| Line | Effect |
|
||||
| ------------------------------------------- | ----------------------------------------------------------- |
|
||||
@@ -90,12 +104,20 @@ 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"}` 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.
|
||||
"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.
|
||||
|
||||
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
|
||||
@@ -107,7 +129,11 @@ remain. Interrupting the command (Ctrl-C) ends the session the same way
|
||||
without a further checkpoint; the capture is still written with end reason
|
||||
`cancelled`, and the command exits with status 130. Interrupted before the
|
||||
application is launched, the command writes no capture and removes the
|
||||
content it had retained.
|
||||
content it had retained. If cancellation arrives during publication or final
|
||||
cleanup, the already-written capture can instead retain its earlier end
|
||||
reason. Inspect `capture.json` and the error's `details.partial_observation`
|
||||
for the retained capture Evidence. Cleanup failures also report resources
|
||||
that could not be released.
|
||||
|
||||
If the capture fails for any other reason before `capture.json` is written,
|
||||
the application is closed the same way and the content already retained is
|
||||
@@ -264,8 +290,8 @@ found nowhere are listed in
|
||||
not an ELF image (a launcher script, for example), `ldconfig`, `dpkg-query` or
|
||||
`apt-cache` is missing, `dpkg-query -S` could not tell which package owns a
|
||||
library (it exits 2 rather than 1, which only says no package owns the paths
|
||||
it did not name), a library could not be read or names more than 512
|
||||
libraries, or the walk stopped after 512 libraries. A failed owner query does
|
||||
it did not name), a library could not be read or exceeds the selected dependency
|
||||
inventory budget, or the walk reached that budget. A failed owner query does
|
||||
not list the libraries it covered in `unpackaged_libraries`, since a lookup
|
||||
that could not finish is not proof that no package owns them. Completed batches
|
||||
retain their package and unowned-library facts. Paths containing package-query
|
||||
@@ -302,20 +328,29 @@ dot-folder named after the package, the executable, the desktop entry's full
|
||||
id and its last part, and the entry's name, with whether each existed at the
|
||||
start. A folder in those places whose name is one of these in another letter
|
||||
case joins them, such as GIMP's `~/.config/GIMP` for the `gimp` package; only
|
||||
the whole name is compared, so `~/.config/GIMPshop` does not. Dotfiles in the
|
||||
the whole name is compared, so `~/.config/GIMPshop` does not. A file under a
|
||||
folder the application creates during the capture beside one of them, with
|
||||
the same name in another letter case or with a version added (`-3.1` or
|
||||
`3`), as TreeLine's `~/.treeline-3.1`, is its state too. 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. A `flatpak run` launch is named after its application
|
||||
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
|
||||
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; when the first application window appeared; the
|
||||
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
|
||||
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 first
|
||||
8 KiB of the launched process's stderr; and whether cleanup was verified. Each
|
||||
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
|
||||
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.
|
||||
@@ -341,7 +376,9 @@ 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 paths every walk left out (the output folder and
|
||||
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
|
||||
`--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,
|
||||
@@ -370,7 +407,11 @@ 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`.
|
||||
`--state-path`, or `state_paths` on a build computer's `start_build_capture`,
|
||||
and a limitation names them, spelled from `~/` under the home. A lock file
|
||||
the application held open, such as Poedit's `~/poedit.lock` or Lucene's
|
||||
`write.lock`, makes no folder such a directory, since it holds nothing to
|
||||
retain.
|
||||
|
||||
**Limitations.** What the capture could not establish, such as a truncated
|
||||
walk or a missing window.
|
||||
@@ -387,3 +428,18 @@ evidence for attribution, not proof.
|
||||
|
||||
Clicks and keystrokes are not recorded. Window titles are sampled every half
|
||||
second, so short-lived titles can be missed.
|
||||
|
||||
Dependency inventory headroom is selected for each capture with
|
||||
`--library-policy '{"libraries":1024,"string_bytes":8192}'`. Unset fields retain
|
||||
their defaults: `libraries: 512` bounds both the closure walk and distinct
|
||||
DT_NEEDED offsets in each ELF image; `search_path_entries: 16` bounds distinct
|
||||
DT_RUNPATH and DT_RPATH offsets per kind; `string_bytes: 4096` includes the NUL
|
||||
terminator of each decoded string; `table_bytes: 1048576` bounds each program
|
||||
header or dynamic table. Values must be positive safe integers. A budget refusal
|
||||
names the field that needs headroom; partial package facts and unresolved
|
||||
coverage remain visible. The policy applies during this capture's admission,
|
||||
without restarting REA, and explicit selections are retained in Evidence. Raising
|
||||
content retention or a worker heap does not raise these inventory budgets.
|
||||
Choosing a new capture still launches the selected application; changing these
|
||||
read budgets does not add execution authority or recover an earlier capture's
|
||||
omitted inventory.
|
||||
@@ -15,13 +15,28 @@ agent-env run ./mousepad-bundle --dry-run
|
||||
|
||||
The export reads the capture and its [state view](desktop-application-state.md);
|
||||
it does not run the application. `--name` sets the environment name; otherwise
|
||||
it comes from the desktop entry id or the program, with an `app-` prefix when
|
||||
it comes from the desktop entry id or the program: a reverse-DNS id's last
|
||||
part (`org.xfce.mousepad` gives `mousepad`), or else the whole id without a
|
||||
trailing version (`glabels-3.0` gives `glabels`), with an `app-` prefix when
|
||||
that name would not be a portable bundle name (for example all digits). The
|
||||
output directory must be new or empty. `--task` adds a task an agent wrote for
|
||||
the capture, once REA has validated it against the capture; see
|
||||
[desktop application tasks](desktop-application-tasks.md). `--package-url`
|
||||
says where the computer downloads the package of an application installed from
|
||||
a `.deb` file; see [Applications from a .deb file](#applications-from-a-deb-file).
|
||||
`--download-install FILE` says which AppImage or tarball a build computer
|
||||
unpacked the application from; see
|
||||
[Applications from an AppImage or tarball](#applications-from-an-appimage-or-tarball).
|
||||
`--extra-package NAME`, repeatable, installs another Ubuntu 24.04 archive
|
||||
package beside the application, such as a runtime piece its package does not
|
||||
install; a [build computer](desktop-build-witness.md) passes its request's
|
||||
`extra_packages`, or a `.deb` request's `dependencies`, this way. A name that
|
||||
is not a Debian package name is refused (`extra_package`). Names the bundle
|
||||
installs anyway, the application's own package and the dependencies it names
|
||||
for a package installed from its `.deb` file, are not repeated; the rest are
|
||||
listed in the limitations and the README. A package the captured `.deb` lists
|
||||
as one alternative, such as `openjdk-17-jre | java-runtime`, is kept when apt
|
||||
installs the application by name, since apt may satisfy it with another.
|
||||
`--seed-checkpoint` names the checkpoint whose state seeds the bundle, the
|
||||
baseline by default, and `--end-checkpoint` the one a task must pass on, the
|
||||
capture's last by default; see [The seed checkpoint](#the-seed-checkpoint).
|
||||
@@ -33,8 +48,10 @@ 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
|
||||
bundle files that still hold them (`unscrubbed_files`), and written files,
|
||||
the last three by their path in the bundle. A failed export, cancellation
|
||||
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
|
||||
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
|
||||
@@ -42,17 +59,19 @@ Evidence; the bundle itself is complete.
|
||||
|
||||
## The bundle
|
||||
|
||||
| Path | Contents |
|
||||
| -------------------------------- | -------------------------------------------------------------------------------------------------- |
|
||||
| `envs/<name>/env.toml` | `type = "computer_app"`, the module and class, `computer = "ubuntu-24.04"`, `driver = "reference"` |
|
||||
| `envs/<name>/<file>.py` | The `ComputerAppEnvironment` class |
|
||||
| `envs/<name>/SKILL.md` | What the app is, its window class and where its files live |
|
||||
| `envs/<name>/seed/` | The application's files at the seed checkpoint, by home-relative path |
|
||||
| `envs/<name>/apt-keys/` | The signing key of each vendor apt repository the app installs from |
|
||||
| `envs/<name>/install-package.sh` | With `--package-url`: the run script that installs the downloaded package with dpkg |
|
||||
| `tasks/smoke.json` | A task that deploys the app |
|
||||
| `tasks/<task>.json` | With `--task`: the agent's task, its verifier in `artifacts/` and the eval in `evals/` |
|
||||
| `README.md` | What was exported, from which capture, and what to keep in mind |
|
||||
| Path | Contents |
|
||||
| --------------------------------- | -------------------------------------------------------------------------------------------------- |
|
||||
| `envs/<name>/env.toml` | `type = "computer_app"`, the module and class, `computer = "ubuntu-24.04"`, `driver = "reference"` |
|
||||
| `envs/<name>/<file>.py` | The `ComputerAppEnvironment` class |
|
||||
| `envs/<name>/SKILL.md` | What the app is, its window class and where its files live |
|
||||
| `envs/<name>/seed/` | The application's files at the seed checkpoint, by home-relative path |
|
||||
| `envs/<name>/apt-keys/` | The signing key of each vendor apt repository the app installs from |
|
||||
| `envs/<name>/install-package.sh` | With `--package-url`: the run script that installs the downloaded package with dpkg |
|
||||
| `envs/<name>/install-download.sh` | With `--download-install`: the run script that unpacks the downloaded AppImage or tarball |
|
||||
| `envs/<name>/applications/` | With a tarball's `--download-install`: the desktop entry REA wrote for its program |
|
||||
| `tasks/smoke.json` | A task that deploys the app |
|
||||
| `tasks/<task>.json` | With `--task`: the agent's task, its verifier in `artifacts/` and the eval in `evals/` |
|
||||
| `README.md` | What was exported, from which capture, and what to keep in mind |
|
||||
|
||||
The class file is `<name>_app.py` with hyphens as underscores, for example
|
||||
`mousepad_app.py`: agentenv imports it under its stem, so a plain `<name>.py`
|
||||
@@ -62,9 +81,10 @@ an `App` suffix.
|
||||
|
||||
The class declares:
|
||||
|
||||
- `Packages(apt=[...])` with the package the capture found. A vendor package
|
||||
is named `<package>/<release>`, its repository's release (the Suite apt
|
||||
reports as `a=`, or else its Codename), so apt takes it from that repository
|
||||
- `Packages(apt=[...])` with the package the capture found, then the
|
||||
`--extra-package` names. A vendor package is named `<package>/<release>`,
|
||||
its repository's release (the Suite apt reports as `a=`, or else its
|
||||
Codename), so apt takes it from that repository
|
||||
even when the Ubuntu archive offers a higher version or epoch, as noble's
|
||||
transitional `firefox` does over packages.mozilla.org's; it is named alone
|
||||
when the release names neither, or when the capture was written before
|
||||
@@ -104,7 +124,8 @@ The class declares:
|
||||
reason (a capture
|
||||
written before restrictions were recorded counts as unrestricted); when
|
||||
another usable repository lists the same version it is left out instead,
|
||||
with a limitation. The export also refuses snaps, flatpaks, AppImages, and a
|
||||
with a limitation. The export also refuses snaps, flatpaks, an AppImage or
|
||||
tarball not named with `--download-install`, and a
|
||||
package no recorded repository lists unless it was installed from a `.deb`
|
||||
file the capture recorded and `--package-url` is given, since the computer
|
||||
could not install them by name, and a capture written before credentials
|
||||
@@ -145,7 +166,8 @@ The class declares:
|
||||
README and the result's limitations say the sandbox is off.
|
||||
- `paths`: the state directories holding the application's state files and the
|
||||
folders holding its documents, nested folders collapsed. A folder beside a
|
||||
state directory whose name differs from it only in letter case is owned
|
||||
state directory whose name differs from it only in letter case, or that
|
||||
adds a version, as TreeLine's `~/.treeline-3.1` beside `~/.treeline`, is owned
|
||||
whole in the files' spelling, so a `~/.config/GIMP` profile GIMP created
|
||||
during the capture beside the candidate `~/.config/gimp` is owned as
|
||||
`.config/GIMP`, not as the folder of its first file. The home itself and
|
||||
@@ -154,9 +176,11 @@ 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 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 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.
|
||||
- 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`
|
||||
@@ -169,10 +193,76 @@ 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. 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.
|
||||
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`,
|
||||
`SingletonLock` and Lucene's index lock `write.lock` anywhere, as Poedit's
|
||||
translation memory holds, LibreOffice's document lock `.~lock.<name>#`, a
|
||||
`<file>.lck`, `.<file>.lock`, `.<file>.lck` or `<file>.<ext>.lock` beside a
|
||||
file the capture recorded in the same folder, such as GnuCash's
|
||||
`household.gnucash.LCK`, Grisbi's empty `.household.gsb.lock`, which made it
|
||||
refuse every save, and VYM's `plan.vym.lock` (a project's `Gemfile.lock`
|
||||
beside its `Gemfile` has no extension to its file, so it is seeded), and
|
||||
`*.lock` or `*.lck` directly in the home, as wxWidgets' single-instance
|
||||
`~/poedit.lock`, or directly in one of the application's state directories;
|
||||
a lone `notes.lck` or `.notes.lock` elsewhere is seeded. A lock
|
||||
never makes a path the application's own, so `~/poedit.lock` is neither owned
|
||||
nor named among the folders the bundle does not own.
|
||||
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.
|
||||
|
||||
A seed file keeps the permission bits it had at the seed when the capture saw
|
||||
it change, such as a `0600` file an app checks: the class module lists those
|
||||
other than `0644` in `SEED_MODES`, and the first boot sets them when it copies
|
||||
the seed. A file the capture never saw change has no recorded mode and is
|
||||
written `0644`.
|
||||
|
||||
Files in app state are retained regardless of a `.log` extension or `log.<n>`
|
||||
name. They can hold conversation history or database writes as well as
|
||||
diagnostics. The normal host-identity scrub applies to retained text; filenames
|
||||
alone do not identify disposable diagnostics. Locks beside these files follow
|
||||
the lock rules above.
|
||||
|
||||
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`, `Visited Links`,
|
||||
`Platform Notifications/`, and a whole `QtWebEngine/`
|
||||
profile), 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. A seeded LibreOffice profile's
|
||||
`registrymodifications.xcu` ships without its `RecoveryList` items, which
|
||||
LibreOffice writes for the documents it has open and which would start the
|
||||
bundle into document recovery instead of its window; a limitation and the
|
||||
README name the file. REA finds the items with its XML parser, as `item`
|
||||
elements whose `oor:path` is `/org.openoffice.Office.Recovery/RecoveryList`
|
||||
however the tags are spelled, and cuts exactly those elements, so text in a
|
||||
comment or CDATA and every other byte stay as captured. A registry that is
|
||||
not well-formed XML ships unchanged.
|
||||
|
||||
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
|
||||
@@ -182,7 +272,14 @@ 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.
|
||||
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`. When a dconf database changed by the
|
||||
seed checkpoint but its version there could not be read, as without
|
||||
`dconf-cli`, the export seeds no keys from it and a limitation names it with
|
||||
the read error.
|
||||
|
||||
## The seed checkpoint
|
||||
|
||||
@@ -209,6 +306,39 @@ tell the two apart, so the flag is the caller's word. `export_build_environment`
|
||||
passes it, since the building agent makes the seed in the build computer. The
|
||||
Evidence records it as `synthetic_seed`.
|
||||
|
||||
## Withheld sign-in state
|
||||
|
||||
`--withhold-from <checkpoint> --withhold-to <checkpoint>` withholds every file
|
||||
under the owned paths that changed after the first checkpoint up to the
|
||||
second, as the capture recorded its changes; `--withhold-path <file>` adds a
|
||||
home-relative file, such as one written at first launch. The draft
|
||||
(`describe-desktop-application-task`) takes the same options, leaves those
|
||||
files out and lists them as `withheld_files`; the export refuses a check that
|
||||
names one. Each withheld file present at the seed is left out of
|
||||
`envs/<name>/seed/` and becomes a secret setting:
|
||||
|
||||
- the class declares `Settings` with a `SecretStr` field per file, and
|
||||
`WITHHELD`, each field's home path;
|
||||
- `env.toml` sets each field to `env:REA_<APP>_<FILE>`, so agentenv refuses
|
||||
the deploy, naming the variable, until it is set;
|
||||
- at first boot, before keeping the initial state, the class writes each file
|
||||
from its setting, the file's bytes in base64, mode `0600`, so `data/reset`
|
||||
restores it, and `data/get` serves it neither as a part nor in the views;
|
||||
- the README names each variable, with
|
||||
`export REA_<APP>_<FILE>="$(base64 -w0 < ~/<file>)"` from the receiver's
|
||||
own signed-in copy of the app.
|
||||
|
||||
A withheld file larger than 48 KiB is refused, since its base64 must fit one
|
||||
environment variable. `--withheld-copy <folder>` copies the withheld files,
|
||||
as captured, into a new or empty folder outside the bundle. The result lists
|
||||
them as `withheld_files`, each with its `setting`, `variable` and `handle`.
|
||||
|
||||
`--consent <file>` ships the person's consents, a `consent.json` that
|
||||
`record_build_consent` records, as the bundle's own `consent.json`.
|
||||
`--seed-withheld` seeds the withheld files after all, refused unless that
|
||||
file holds a `seed_sign_in` consent; the result lists them as
|
||||
`consented_files`, and the README says they are there with consent.
|
||||
|
||||
## Host name and user
|
||||
|
||||
A seed can hold the capture host's name and the user's: Geany saved its mail
|
||||
@@ -252,6 +382,28 @@ 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 within the scrub limit ships as captured, its bytes searched.
|
||||
A document the state view did not read can still be decompressed and
|
||||
recompressed under the separate 256 MiB scrub limit; its content is searched
|
||||
even when its format cannot be scrubbed. 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
|
||||
@@ -318,6 +470,73 @@ 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`.
|
||||
|
||||
## Applications from an AppImage or tarball
|
||||
|
||||
A [build computer](desktop-build-computer.md) can install an application from
|
||||
its project's AppImage or tarball, pinned by URL and SHA-256, under
|
||||
`/opt/rea-apps/<desktop entry>`. Neither holds a Debian package, so the
|
||||
capture records the package as `unknown`, and the export takes the install
|
||||
from `--download-install`, a JSON file the build computer writes from its
|
||||
request:
|
||||
|
||||
```json
|
||||
{
|
||||
"kind": "appimage",
|
||||
"desktop_entry": "org.freecad.FreeCAD",
|
||||
"url": "https://github.com/FreeCAD/FreeCAD/releases/download/1.1.4/FreeCAD_1.1.4-Linux-aarch64-py311.AppImage",
|
||||
"sha256": "675d1a4295b2183e0e1d816a4b5557dcb63aeced4e60aaa28d6c3686f4c71dc9",
|
||||
"architecture": "arm64"
|
||||
}
|
||||
```
|
||||
|
||||
A tarball's adds `program`, its path inside the archive, and optionally
|
||||
`name`. The class then declares
|
||||
`downloads=[Download(url=..., sha256=..., to="vendor/app.AppImage", arch=...)]`
|
||||
(`vendor/app.tar` for a tarball) and `run=[RunScript(script="install-download.sh")]`,
|
||||
the same script the build computer ran, with no apt package for the app. The
|
||||
bundle does not contain the application and supports only the download's
|
||||
architecture; the URL must keep serving those bytes, and the application's
|
||||
licence is the operator's to check.
|
||||
|
||||
The export refuses the file (`download_install`) unless it names an
|
||||
`appimage` or `tarball` with an `http://` or `https://` URL and a SHA-256,
|
||||
the capture launched its `desktop_entry`, the captured program lies under its
|
||||
folder in `/opt/rea-apps`, and the capture ran on its architecture; it
|
||||
refuses `--package-url` beside it.
|
||||
|
||||
## 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
|
||||
@@ -332,13 +551,30 @@ 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 JSON file
|
||||
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
|
||||
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
|
||||
document, such as JSON Lines, stays text. Format detection follows REA's
|
||||
rules. Files larger than 64 MiB get an `error` instead of a view
|
||||
and are not read. XML is read with Python's `expat` twice: with namespace
|
||||
and are not read. The selected `file_bytes` also applies to scrubbed seed task
|
||||
views before admission, independently of how much seed data the export can
|
||||
copy. SQLite table views have a shared `sqlite_view_bytes` allowance, default
|
||||
16 MiB of compact UTF-8 JSON per table, checked before retaining each row.
|
||||
An oversized table keeps its error while other tables remain readable. Raising
|
||||
this view allowance does not raise the independent 16 MiB native SQLite
|
||||
value/record limit or REA worker reply limit; worker facts include additional
|
||||
schema and typed-cell metadata and may be refused earlier. The TypeScript
|
||||
and exported Python readers count their respective native compact JSON encodings;
|
||||
float and exponent spelling can make their exact byte thresholds differ even
|
||||
when they report equal numeric facts. The Python byte counter quotes large
|
||||
strings in bounded chunks before retention.
|
||||
Exported SQLite readers require Python 3.11 or later for the native connection limits; the
|
||||
AgentEnv compatibility workflow uses Python 3.12.
|
||||
XML is read with Python's `expat` twice: with namespace
|
||||
processing, which refuses what REA's parser refuses, such as an undeclared
|
||||
prefix, then without it, so element and attribute names keep the prefixes the
|
||||
document spells and namespace declarations stay attributes, as in REA's view;
|
||||
@@ -363,5 +599,5 @@ when a DOCTYPE names a DTD. Known differences remain:
|
||||
|
||||
Unless it was [made for the task](#a-seed-made-for-the-task), the seed is the
|
||||
user's real data. Keep the bundle local and do not publish it.
|
||||
The class was checked against agentenv-framework 0.9.1431 with
|
||||
The class was checked against agentenv-framework 0.9.1464 with
|
||||
`python -m agentenv_protocol.computer._declare` and `agent-env run --dry-run`.
|
||||
@@ -11,6 +11,65 @@ again.
|
||||
rea inspect-desktop-application-state ./mousepad-capture --format json
|
||||
```
|
||||
|
||||
Views use bounded defaults. When a view reports truncation or a byte-budget
|
||||
refusal, retry the same capture with `--view-policy` JSON overrides:
|
||||
|
||||
```bash
|
||||
rea inspect-desktop-application-state ./mousepad-capture \
|
||||
--state-path /home/ada/Documents/notes.txt \
|
||||
--view-policy '{"text_lines":10000,"file_bytes":134217728}' --format json
|
||||
```
|
||||
|
||||
`--state-path` selects an exact original captured path and can be repeated.
|
||||
Omitting it examines every captured path. Selection preserves the captured
|
||||
checkpoint and digest; it does not substitute the file's current contents.
|
||||
A path absent from the capture is an input error.
|
||||
|
||||
`--view-policy` accepts positive safe-integer overrides for `file_bytes`,
|
||||
`sqlite_tables`, `sqlite_rows`, `sqlite_view_bytes`, `text_lines`, `xml_nodes`, `xml_depth`,
|
||||
`parsed_bytes`, `json_depth`, `zip_entries`, `zip_entry_bytes`, `zip_bytes`,
|
||||
and `zip_ratio`. Unspecified controls keep the defaults described below.
|
||||
`xml_depth` admits at most 494 and `json_depth` at most 991: these bounds
|
||||
follow the fixed Evidence JSON nesting limit, including the captured-version
|
||||
and ZIP-member wrappers and XML's element/children representation. A request
|
||||
above either bound is rejected before reading the capture.
|
||||
Evidence parameters retain only the supplied `view_policy` overrides; omission
|
||||
and an explicitly empty selection remain distinct. State inspection and task
|
||||
drafts report the resolved policy separately as
|
||||
`normalized_result.effective_view_policy`. Changes apply on this call, without
|
||||
a restart. File and ZIP byte counts refer to retained file bytes or uncompressed
|
||||
ZIP member bytes, not transport size. Gzip document views share `zip_entry_bytes`
|
||||
and `zip_ratio` with ZIP entry views; `zip_bytes` bounds a ZIP archive, not a
|
||||
gzip stream. These selections also apply to the decompressed document's format
|
||||
view. `sqlite_view_bytes` instead bounds each
|
||||
projected table's compact UTF-8 JSON, including column names, primary keys,
|
||||
rows and truncation metadata; it defaults to 16 MiB. Rows are charged before
|
||||
retention. A table that exceeds this allowance keeps an actionable `error`,
|
||||
while other tables remain readable. Increase this control and retry the same
|
||||
capture for a projected-view refusal. It does not raise the SQLite worker's
|
||||
separate fixed value/record or complete-reply limits, which may refuse earlier.
|
||||
Each reader counts its native compact JSON encoding. Float spelling can differ:
|
||||
Python emits `16.0` where JavaScript emits `16`, and exponent spelling also
|
||||
varies. Identical numeric facts can therefore cross this byte threshold at
|
||||
different settings. This is not a common transport-byte guarantee.
|
||||
|
||||
The same option is available on `describe-desktop-application-task` and
|
||||
`export-desktop-application`. Export uses the accepted policy for task
|
||||
validation and emits it into the Python readers used by the environment's
|
||||
`data/get`; re-export with another policy to change those reader budgets.
|
||||
Task checks apply `file_bytes` to the actual scrubbed seed bytes, including any
|
||||
growth from replacing the capture home with `/home/user`. A seed over that
|
||||
view allowance may still be exported under the independent acquisition limit,
|
||||
but its unreadable view cannot establish a known task failure.
|
||||
The TypeScript and exported Python readers share the policy's defaults.
|
||||
These desktop capture workflows remain CLI-only.
|
||||
|
||||
Raising a view budget cannot recover content the capture never retained,
|
||||
change numeric exactness, enable encrypted or unsupported archive formats,
|
||||
or raise SQLite worker, Evidence nesting, process-memory or transport limits.
|
||||
Keep increases specific to the exhausted budget. Truncation and incomplete
|
||||
comparison coverage remain visible until the requested facts were examined.
|
||||
|
||||
The result is Evidence with operation `inspect_desktop_application_state` and
|
||||
predicate type `rea.desktop-application-state`. Its confidence is `inferred`,
|
||||
because roles come from heuristics; the views themselves are read from the
|
||||
@@ -25,7 +84,7 @@ changed later. Each path records the evidence the capture holds about it:
|
||||
| ------------------------ | ------------------------------------------------------------------------- |
|
||||
| `state_directory` | It lies in one of the application's state directories, in either spelling |
|
||||
| `opened_by_application` | An application process held it open during a sample |
|
||||
| `named_in_window_title` | An application window title spelled its name or `~/` path on its own |
|
||||
| `named_in_window_title` | An application window title spelled its name, `~/` or absolute path whole |
|
||||
| `selected_path` | It lies under a `--state-path` or absolute `--argument` of the capture |
|
||||
| `dconf_application_keys` | It is a dconf database holding groups whose path names the application |
|
||||
| `desktop_service` | It lies where desktop services and toolkits keep shared files, or caches |
|
||||
@@ -40,11 +99,26 @@ 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; `application_state` for another
|
||||
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
|
||||
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
|
||||
`today.txt - Notes`.
|
||||
`today.txt - Notes`, and never by a folder of a path the title shows: in
|
||||
CherryTree's `home-notebook.ctd - /home/user/Documents - CherryTree 1.1.2`,
|
||||
`user` names no file. A name without an extension, such as `Makefile`, must
|
||||
also stand on its own rather than end a longer path, as in
|
||||
`Makefile - Editor`. A file under `~/.cache` or `~/.config/dconf` is never
|
||||
named by a title. The capture's checkpoint acknowledgements rank files by the
|
||||
same rule.
|
||||
|
||||
Application names, which select dconf groups, come from the package, the
|
||||
executable, the desktop entry's id and `StartupWMClass`, and the window match.
|
||||
@@ -70,11 +144,21 @@ whether the file was present, the SHA-256 of its retained bytes, and a view:
|
||||
| `dconf` | The `GVariant` header | Groups whose path names the application, plus the names of the other groups |
|
||||
| `zip` | A zip local file header, `PK\x03\x04`, whatever the name | Its file entries in archive order, each with its own format and view |
|
||||
| `json` | A `.json` name or a leading `{` or `[` that parses | The parsed value, from files up to 4 MiB nested up to 500 levels |
|
||||
| `xml` | An XML name or declaration that parses | An element tree (`name`, `attributes`, `children`); text kept exactly, DTDs never read |
|
||||
| `xml` | An XML name, a declaration or a leading element that parses | An element tree (`name`, `attributes`, `children`); text kept exactly, DTDs never read |
|
||||
| `keyfile` | Only `[group]`, `key=value` and comment lines, with at least one group | Groups of `key` → string value, from files up to 4 MiB |
|
||||
| `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).
|
||||
|
||||
Text that opens with an element, such as a Freeplane map's
|
||||
`<map version="freeplane 1.7.0">` with no declaration, or with a DOCTYPE that
|
||||
has no internal subset and then an element, such as a KmPlot plot's
|
||||
`<!DOCTYPE kmpdoc>` before `<kmpdoc version="4">`, is XML when the whole text
|
||||
is well formed, whatever the file is called, a `.txt` file included;
|
||||
otherwise it stays text. The exported verifier makes the same choice.
|
||||
|
||||
A JSON value holding a number JavaScript would round, such as an integer above
|
||||
2^53, is not read rather than shown rounded.
|
||||
|
||||
@@ -193,6 +277,37 @@ 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
|
||||
|
||||
@@ -3,11 +3,12 @@
|
||||
A [desktop application export](desktop-application-export.md) can carry one
|
||||
task: a prompt for a computer-use agent and checks that grade what the agent
|
||||
left in the application's files. An agent, not REA, writes the prompt and the
|
||||
checks from the change the capture recorded. REA validates the task against
|
||||
the capture and keeps it only when its checks fail on the seed and all pass on
|
||||
the captured end state. REA runs no model and no code the agent wrote: the
|
||||
checks are declarative, and the exported verifier evaluates them the same way
|
||||
REA does.
|
||||
checks from the change the capture recorded. For file checks, REA validates
|
||||
the task against the capture and keeps it only when its checks fail on the
|
||||
seed and all pass on the captured end state. The checks are declarative;
|
||||
optional [readers](#readers) run commands to interpret files, and
|
||||
[screen judges](#screen-judges) use a model when no file shows the change.
|
||||
The exported verifier uses the same checks and reader runner as REA.
|
||||
|
||||
```sh
|
||||
rea describe-desktop-application-task ./mousepad-capture --format json > draft.json
|
||||
@@ -42,35 +43,457 @@ 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. Views appear only for the files the suggestions cover,
|
||||
with arrays past 200 items and strings past 2,000 characters cut
|
||||
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
|
||||
(`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`, `upkeep` or `layout` (see `task`). A record of
|
||||
text fields added to a list of its kind, as GnuCash's
|
||||
`<gnc:transaction>`, is listed field by field, and a field that lists
|
||||
records, as its `<trn:splits>`, record by record, so the cut never hides
|
||||
one. `refers_to` names up to
|
||||
five other elements a value equals the `key` or `id` (`xmi:id` among them)
|
||||
of, outside a view the app keeps of the document, as Umbrello's
|
||||
`listview` mirroring its model by id, with the
|
||||
`attribute` holding it, as HomeBank's `category="44"` names
|
||||
`<cat key="44" name="Groceries"/>`, or the id a child element holds, as a
|
||||
GnuCash split's `<split:account>` names the account whose `<act:id>` it
|
||||
is, shown with its name, `<gnc:account …><act:name>Groceries</act:name>…`;
|
||||
an element added whole lists those of the records of attributes it nests
|
||||
too, as a KMyMoney transaction's splits name their `<ACCOUNT>` and
|
||||
`<PAYEE>`, each once. Where several elements share that key, the one
|
||||
whose tag shares the attribute's stem, as `payee` and `<pay>`, and of
|
||||
those the one named for the attribute, as `account` an `<ACCOUNT>` before
|
||||
an `<ACCOUNTID>`. A plain number names an element only through an
|
||||
attribute so named or ending in `id`, `ref` or `key`, so a list's
|
||||
`count="5"` names no `<FIXVERSION id="5"/>`. A value that changed lists,
|
||||
in `alternatives`, its pointer naming the element by each other identifier
|
||||
or name-like attribute it holds alone among its tag's members, up to
|
||||
three, as an Inkscape text's `[@inkscape:label=Headline]` beside its
|
||||
`[@id=text12]`, for a check to name it by instead; an element its tag
|
||||
alone names inside the first one a condition names, as an EPUB chapter's
|
||||
`h1`, by its `[@id=chapter-two]`. What a check can
|
||||
name comes first, text an edit changed before the rest, so no cut drops
|
||||
the edit, 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.
|
||||
role `document`, or of the app's own state files when no document changed,
|
||||
excluding locks the export leaves out of the seed. App state files ending
|
||||
in `.log` remain eligible for checks.
|
||||
A text file gains `lines_present` for its new lines and `lines_absent` for
|
||||
lines it lost (when either is at most ten), and `line_count` for each line
|
||||
holding a letter whose count changed; JSON and key files gain
|
||||
`value_equals` and `value_absent` by pointer; SQLite tables gain rows added,
|
||||
holding a letter whose count changed; a new line holding an XML attribute
|
||||
REA recognizes as generated, such as a named epoch time or `ID_329023692`, gets a
|
||||
`line_count` of the lines `contains` its text up to that value, as
|
||||
`<node TEXT="Water filter" ID="`, at the end's number, where both views
|
||||
hold the whole file, instead of a `lines_present` another save would
|
||||
fail, or a `volatile_lines` note when no text comes before it. UUID-shaped
|
||||
text stays exact because its shape alone does not show that it was generated;
|
||||
JSON and key files gain
|
||||
`value_equals` and `value_absent` by pointer, a JSON array's records named
|
||||
by an id field each holds alone at both ends (`id`, `uid`, `uuid`, `guid`,
|
||||
`key` or a name ending in `_id` or `Id`), as `/lists/[id=chores]`,
|
||||
whatever order the app saves them in; where the app generated that id, a
|
||||
record both ends hold is named by its kind field and its first name-like
|
||||
string field (a key ending in `name`, `title`, `label` or `caption`),
|
||||
nearest first and up to three keys deep, that holds the same string at
|
||||
both ends and names it alone at each, as TreeLine's category by
|
||||
`/nodes/[format=CATEGORY][>data~1NAME=Science]`, and by its id where none
|
||||
does, as `/nodes/[uid=7584d494d9f511f1a873edd4f1920549]` once its name
|
||||
changed; and a record only one end holds is named by such a field that
|
||||
names it alone at its end and nothing at the other, as TreeLine's new book by
|
||||
`/nodes/[format=BOOK][>data~1Title=The Silk Roads]`, its other fields
|
||||
checked through that selector and the fields the selector reads not, nor
|
||||
a field holding what every like record (one of its kind) at the end holds
|
||||
there, as the empty `children` of every book; and
|
||||
by position only where nothing names a record, as a new book whose title
|
||||
another book holds, with a `by_position` note listing those checks;
|
||||
never a value that is a uid the app generates (a
|
||||
GUID, or 32 hex digits as TreeLine's uuid1), nor a check the seed already
|
||||
passes, as a new record's `format` where another record of that kind held
|
||||
its place; a removed record is checked gone by its own pointer, as
|
||||
`/lists/[id=chores]`, and only where the end holds nothing there, so a
|
||||
record only position reached, whose place another took, is left to the
|
||||
count; `member_count` checks of the
|
||||
arrays whose members were added or removed, of the members' kind where
|
||||
records share a `type`, `kind`, `format` or `category` field, as `/nodes`
|
||||
matching `[format=BOOK]`, and a count guard of the innermost array an edit
|
||||
went through, as for XML; SQLite tables gain rows added,
|
||||
changed and removed, by primary key, and their new row count. An XML file,
|
||||
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 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.
|
||||
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]`, then by a coordinate, a long
|
||||
number, a length with its unit, as `svg:height="2.629cm"`, an `xml:id`
|
||||
or `draw:id` of the form `id2` that LibreOffice numbers anew as it saves,
|
||||
so a Draw shape is named by its `draw:name`, or a token,
|
||||
such as `XPOS` or `ItemID`, or an id of random case, as Umbrello's
|
||||
`ubcgF2AWfBmHh` (`u` and twelve letters and digits), an automatic style name an app numbers as it
|
||||
saves and renumbers on reload, as LibreOffice's
|
||||
`presentation:style-name="pr1"` (`P1`, `T1`, `MT1`, `L2` on a
|
||||
`*:style-name`), so a slide's frames are named by `presentation:class`,
|
||||
or an attribute naming
|
||||
view state, such as which layer is `selected`, and last by a child
|
||||
element's text, `[>CHILD=VALUE]`, a name-like tag first, as Osmo's
|
||||
record by `[>first_name=Delphine]`, MuseScore's `<Text>` by
|
||||
`[>style=Title]`, a spreadsheet row by its label cell, or GnuCash's
|
||||
transaction by `[>trn:description=Greenleaf Market]`: text of at most 64
|
||||
characters, never a time or a token or id a program generates; then by
|
||||
an identifier a child carries, `[>CHILD@ATTR=VALUE]`, as a GtkBuilder
|
||||
`<child>` by `[>object@id=submit_button]`, never one an app generates or
|
||||
numbers anew as it saves; and then by text a child joins from elements
|
||||
of its own, as Glade's `[>packing=TrueTrue1]` from a widget's packing
|
||||
properties, which moving the widget changes. A pair
|
||||
counts every member holding both its values, whichever attributes that
|
||||
member ranks first. An element with identifiers is named by those alone;
|
||||
an id the app generates, as Freeplane's `ID_329023692`, or a GUID in
|
||||
any attribute, braced or not, as VYM's `uuid="{18eadb5d-…}"`, ranks
|
||||
last, after a child's text, so a new node is named by its `TEXT` and a
|
||||
new VYM branch by `[>heading=Sunset boat tour]`, while a member
|
||||
both versions hold pairs by such an id first, so records that keep their
|
||||
UUIDs and swap titles read as two title edits. A value that stands for
|
||||
none, as Grisbi's `Id="(null)"` on every transaction, names nothing, so a
|
||||
new transaction is named by its `Nb`. A child's text is
|
||||
counted on every sibling, one an identifier names included, so a title
|
||||
two records share names neither. The selector must name the
|
||||
member alone at both ends, with the same values; a child's text names a
|
||||
member that is in one version only when the list's length changed, so a
|
||||
row whose one cell an edit changed stays that row. 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 `Layer` to `Sun`: it is paired by its first
|
||||
other attribute naming it alone at both ends, as
|
||||
`[@src=data/sun.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. Where that attribute's values number
|
||||
the members in document order, as MyPaint 2 writes `src` as
|
||||
`data/layer-00.png`, `data/layer-01.png` and on along the stack and
|
||||
renumbers them when a layer moves, each version is named by its own
|
||||
value of the renamed identifier instead, `[@name=Sun]` and
|
||||
`[@name=Layer]`.
|
||||
- A child of the document's root that its tag alone names, and that holds
|
||||
a list (two or more elements of one tag and no text of its own) and has
|
||||
an identifier, also gets a condition that keeps it named if the app adds
|
||||
a sibling of its tag, as Dia adds an empty `Background` layer each time
|
||||
it reopens and saves a diagram: an id other than `name` both ends hold,
|
||||
as Inkscape's `[name=g][@id=layer1]`, which a new sibling would not
|
||||
share; else the text of a child both ends hold, as Dia's
|
||||
`[name=dia:layer][>dia:object=#Receive order#]`, which an empty sibling
|
||||
lacks; else its `name`, which a new one may repeat. Deeper, a member of
|
||||
a list named for its tag, as Gnumeric's `gnm:Sheet` in `gnm:Sheets`,
|
||||
holding elements and its tag alone naming it, gets an id, else a
|
||||
name-like child's text, `[name=gnm:Sheet][>gnm:Name=Budget]`, else its
|
||||
`name`. Other steps, and elements with neither, stay as they are.
|
||||
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. An
|
||||
identifier numbering the members 0..N-1 in document order at both ends,
|
||||
where members came or went, as Parley numbers its `<entry id="6">` by
|
||||
where it saves it, ranks after a child's text where a member has one, so
|
||||
a new entry is `[>translation=library]` and its kept neighbours are named
|
||||
alike; Tellico's ids, which count from 1, Tiled's and Rosegarden's,
|
||||
whose members hold no text, stay identity. An element a change added that
|
||||
holds nothing but the id of a record it added elsewhere, as Parley's
|
||||
lesson membership `<entry id="6"/>`, is `upkeep`, listed with `refers_to`
|
||||
on that record, never a check or a count.
|
||||
- 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`, unless it is a field its tag names in a
|
||||
record of two or more fields holding text, as QElectroTech's `<text>`
|
||||
beside `<info_name>` in a `<dynamic_elmt_text>`, or KmPlot's
|
||||
`<equation-0>` beside `<arg-min>`, which is checked itself rather than
|
||||
the record whose text joins its fields; one line of text the app lays
|
||||
out between line breaks, as KmPlot's formula before the next element, is
|
||||
checked, and its siblings guarded, with `normalize_whitespace: true`,
|
||||
and text whose whitespace alone changed, as a formula the app moved to
|
||||
an indented line of its own, gets no check; 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. Text an app keeps in an attribute, one element per run, as Scribus's
|
||||
`<StoryText><ITEXT CH="Spring "/><ITEXT CH="Fair"/>`, gets a `text_equals`
|
||||
with `text_attribute` on the nearest ancestor an attribute names, as
|
||||
`[name=PAGEOBJECT][@ANNAME=Headline]` with `"text_attribute": "CH"`, where
|
||||
that ancestor holds no text nodes and the attribute's holders are runs,
|
||||
none inside another and none carrying an identifier or a name-like
|
||||
attribute beside it, as Umbrello's `<ownedAttribute xmi:id="…"
|
||||
name="email" visibility="private"/>`, a record whose attributes are
|
||||
checked one by one, two or more or one holding words with a space: an
|
||||
element's own attribute, as a Freeplane node's `TEXT` beside the nodes in
|
||||
it, or a lone value, as `<Bool value="false"/>`, is checked where it is.
|
||||
The check covers that attribute and the runs holding it; another change
|
||||
in the frame, as a run's `FONT`, keeps its own check. 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`), one inside such an
|
||||
element, as Word's `<w:r>` run in its `<w:p>`, one whose elements are all
|
||||
inline formatting (`b`, `i`, `u`, `em`, `strong`, `bold`, `italic`, a
|
||||
`span`, `a`, `code`, `sub`, `sup` and the like, Gnote's `size:` and
|
||||
`link:` runs), as `<list-item><bold>olive oil</bold></list-item>`, 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, view state and values standing for none, as HomeBank's
|
||||
new `<ope>` gets its `amount`, `category` and `payee`; a value two or
|
||||
more like siblings all hold, as Grisbi's `Cu="1"`, comes after those
|
||||
that vary, as its `Pa`, `Ca`, `Dt` and `Am`. Records of attributes
|
||||
alone that it nests, as a KMyMoney `<TRANSACTION>` its `<SPLITS>` of
|
||||
`<SPLIT>`, get a `value_equals` of each attribute whose values vary among
|
||||
the like records, its own and those under its like siblings, at most
|
||||
three a record and six in all, as each split's `value` and `payee`, but
|
||||
not one every split holds alike, as `price="1/1"`, nor one each holds
|
||||
equal to an earlier one, as `shares` repeats `value`. Each record is
|
||||
named by an identifier that the app neither generates nor numbers anew
|
||||
in every record holding such a list, as KMyMoney's `S0001` in every
|
||||
transaction, else by its best ranked attribute short of a coordinate or
|
||||
an amount, as `[name=SPLIT][@account=A000001]`. 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; of those copied, an attribute naming an element the seed
|
||||
holds by an id that is no plain number, as an Umbrello attribute's
|
||||
`type` its data type, is the user's choice and keeps its check. A record added to a list that a selector names, as
|
||||
Tellico's `<entry id="4">` or Osmo's `<record>` by its first name, 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, the field its selector names it by unless it is
|
||||
the only one left, as a new VYM branch's `<heading>`, a value every
|
||||
like record holds in that field, as Osmo's `<group>None</group>`, noise,
|
||||
a field holding ids of its own, a date the app stamps in parts, and blank
|
||||
text or times; a field that lists records, as GnuCash's `<trn:splits>`,
|
||||
gets its records' fields instead, each record by its own selector. An
|
||||
attribute every like record holds alike, as GnuCash's `version`, is the
|
||||
format's and gets no check. A record only position names 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.
|
||||
- Where members of a list were added or removed, a `member_count` of the
|
||||
list's members of their tag, and of their kind where they share one
|
||||
(`type`, `kind` or `shape`, as `[name=dia:object][@type=Flowchart - Box]`),
|
||||
unless every member of the tag holds a value of its own, as Tiled's
|
||||
objects a free-form `type` (`well`, `door`, `gate`), which labels each
|
||||
rather than grouping them,
|
||||
equal to the end's number, which differs from the seed's: at most two a
|
||||
file, the shallowest lists first, after the other checks. None for a
|
||||
list of one member at both ends, as a style an app adds for a run, for
|
||||
members of an element a text check reads, which are runs of its text,
|
||||
for an element in mixed content, or for noise.
|
||||
- A decimal written as text, such as `146.83`, is suggested as a number
|
||||
with `tolerance: 0.001`, unless the seed's value, read as the evaluator
|
||||
reads a number (`10` and `1e1` included), is that close too. A
|
||||
`value_equals` that would pass on the seed's value is not suggested.
|
||||
- An element placed by its own position, holding numeric `x` and `y` as a
|
||||
like sibling does, as Xournal++ places each `<text>` note on a layer, is
|
||||
an item of its own, never a run of the others' text: one added whole
|
||||
gets a `text_contains` of its text on the element holding the items,
|
||||
which passes wherever it is placed, and that list's `member_count`.
|
||||
- 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, as VYM's
|
||||
`<select>`, the layer, frame,
|
||||
view or colour the app has current, as Pencil2D's `currentLayer`,
|
||||
scrolling, zoom, the viewport, windows, splitters, a list or tree view
|
||||
mirroring the document, as Umbrello's `listview`, 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, and a preview or thumbnail the app renders, as
|
||||
Xournal++'s `<preview>`), 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]`, or a settings path ending in how a
|
||||
panel shows (`visible`, `hidden`, `expanded`, `geometry`, `size` and the
|
||||
like), as VYM's `<setting key="/treeeditor/visible">`; an identifier the
|
||||
app numbers by position. An `Id` suffix alone does not show that an
|
||||
attribute is generated, so relationship fields such as `accountId` are
|
||||
retained; other save-generated IDs may need manual review; volatile
|
||||
values, UUIDs and epoch times, binary data encoded as base64 (a PNG's
|
||||
`iVBORw0KGgo`, or 256 or more base64 characters mixing cases and
|
||||
digits), an id counter (`uniqueid`, `nextobjectid`), a value equal to an
|
||||
id the change gave a new element where a counter or that element holds
|
||||
it, as Umbrello's `lastobject` holds the new attribute's `xmi:id`, but
|
||||
never a reference on an element both ends hold, as a KMyMoney split
|
||||
moved to a new account, 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`,
|
||||
`entered`), or written whole under such a tag, as GnuCash's
|
||||
`<trn:date-entered><ts:date>2026-11-06 08:53:08 +0000`,
|
||||
which no check ever reads, while a date a user enters in parts, as a
|
||||
birthday, is an edit like any other; an id the app assigns, an `id`
|
||||
element with `type="guid"`, as GnuCash's `<trn:id>`, and text of control
|
||||
characters, as its unset options hold; `upkeep`, a change inside an
|
||||
app's `slots`, as GnuCash's `book:slots`, which it adds to and fills on
|
||||
reopening a book, a count an app keeps of its members, an attribute
|
||||
whose key ends in `count` or an element whose tag names a count, whose
|
||||
integer changed and at each end equals how many elements of one tag it,
|
||||
or the element holding the text, holds there, the counter left out, as
|
||||
VYM's root `branchCount`, KMyMoney's `<TRANSACTIONS count="5">` or
|
||||
GnuCash's `<gnc:count-data>`, or, for a counter the change added, how
|
||||
many of one tag, more than one, it holds as children, as FreeCAD's
|
||||
`<ObjectDeps Count="2">`, while a count a user enters, as an item's
|
||||
`<count>`, is an edit, and the `loext:tab-stop-distance` attributes
|
||||
LibreOffice fills in `styles.xml` while another entry holds the edit,
|
||||
and, while a change outside them is the edit, any
|
||||
change in `styles.xml`, in a document's style containers or its master,
|
||||
handout and notes pages, or to an attribute naming an automatic style
|
||||
(`P1`, `MT1`) at both ends, as Impress after a reload wraps its master pages' fields in a new `MT1` style and
|
||||
rewrites list style `L2`, and a text showing another field that changed
|
||||
alike, its element beside a field naming that one's key, as
|
||||
QElectroTech's `<dynamic_elmt_text>` shows a component's label in its
|
||||
`<text>` beside `<info_name>label</info_name>`; and `layout`, attributes holding a list of
|
||||
numbers, as Dia's `obj_bb` `6.3225,6.15;12.5775,8.15`, or a number a
|
||||
name on its way calls layout (a position, point, box, corner, width,
|
||||
height, side or offset, as `elem_width`), that changed in an element up
|
||||
to three levels below one whose text changed, below the root's own
|
||||
children, while their own element's text did not, as Dia moves and
|
||||
resizes a box around its new text, or below an element whose tag names a
|
||||
diagram, widget, canvas or scene while the model change is elsewhere, as
|
||||
Umbrello grows a class's `classwidget` `height` when an attribute is
|
||||
added; an order's `<amount value="12"/>` beside its new description is
|
||||
content. Geometry that changed with
|
||||
no text beside it, as a CAD sketch's, is content. 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 an XML list, or a
|
||||
`value_equals` through a JSON record added whole, as TreeLine's new book's
|
||||
`data/Author` gives
|
||||
`/nodes/[format=BOOK][>data~1Title=Small Engines of Life]/data/Author`
|
||||
(its like records are those of its kind, named as both ends pair them,
|
||||
and it reads only the check's own field), a field on up to
|
||||
two like siblings, those sharing most of the attributes its selector
|
||||
names it by and its type, as a cell's `Row` or `Col` and `ValueType`,
|
||||
then the nearest first, at its seed value, which the end holds
|
||||
too, trying at most the 16 nearest, so a guard costs the same among
|
||||
thousands of siblings; for a member named as a field, by a name-like attribute alone, as
|
||||
QElectroTech's `elementInformation[@name=label]`, the like siblings of
|
||||
the nearest record out that hold that field too come first, so the other
|
||||
components' labels guard a component's label rather than its other
|
||||
fields: 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, but not one numbering the
|
||||
members in order, as MyPaint's `src`; never through a sibling only
|
||||
position pairs. A guard never selects its sibling by
|
||||
what it reads: a sibling its selector names by the attribute the guard
|
||||
checks, or by a value that is or holds the text it reads, as Glade's
|
||||
`[>object=CancelTrueTrueTrue]` for a button's `Cancel` label, is named by
|
||||
another identifier, name-like attribute or child's text it holds alone
|
||||
at both ends instead, as Tiled's objects by `[@id=2]` rather than the
|
||||
`name` the guard reads, or Glade's button by `[>packing=TrueTrue0]`, or
|
||||
else the guard reads another field, or there is none. A `text_equals` with `text_attribute`
|
||||
reads its siblings the same way. A text file gets a `lines_present` of the
|
||||
nearest two unchanged lines of its first new line's kind, list items with the same
|
||||
marker, as Zim's other `[ ]` action items, or lines the same command
|
||||
opens, as the other headings after LyX's `\begin_layout Section`, or lines
|
||||
of the same keyword or `key:` in other records, as a gettext catalogue's
|
||||
other `msgstr` lines rather than the edited entry's own `msgid`, or else
|
||||
its nearest lines with words in them; each text both ends hold once, never
|
||||
a line with no text of its own, a command such as `\end_layout`, tags
|
||||
alone such as `<fonts>` or `</node>`, or a key alone such as a RedNotebook
|
||||
day's `24:`, nor a line that repeats; an item placed by its own position
|
||||
that an edit added, a `text_contains` of each of up to four kept items'
|
||||
text, nearest first. Where members were only edited, a
|
||||
`member_count` of the innermost list holding the edited element that an
|
||||
edit goes through by a member with like siblings, a record rather than a
|
||||
field of one (a member named by a name-like attribute alone that the
|
||||
record's like siblings hold too), of the edited member's tag and kind, at
|
||||
the seed's number, as Dia's boxes in their layer, MyPaint's layers in
|
||||
their stack or Glade's buttons in their button box: no member of the kind
|
||||
added or removed; never of runs in an element a text check reads, and
|
||||
only where the end holds the same number. A guard of a coordinate comes
|
||||
after those of text. At most four a file besides the count guard, which
|
||||
sits outside that cap, so sibling guards never squeeze it out. 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; `unreadable_view` when no
|
||||
check can read it, as a document REA reads as binary;
|
||||
`volatile_lines` when a text file gained lines holding a value the app
|
||||
generates with no text before it to count them by; `generated_reference`
|
||||
when an array references a newly generated record ID that cannot be checked
|
||||
exactly across runs, with up to five affected `pointers`; and `read_as_text`
|
||||
when a text file opens like XML, with a declaration, a DOCTYPE or an
|
||||
element, but reads as text because its DOCTYPE has an internal subset or
|
||||
it is not well formed, so its checks compare lines that hold attributes in
|
||||
the order the app wrote them.
|
||||
|
||||
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. A LibreCAD
|
||||
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
|
||||
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.
|
||||
@@ -80,7 +503,7 @@ and `CIRCLE`, and only `CIRCLE` going from 5 to 9 is the user's change.
|
||||
```json
|
||||
{
|
||||
"name": "add-milk",
|
||||
"prompt": "Add buy milk to my to-do list in Mousepad and save it.",
|
||||
"prompt": "In Mousepad, add buy milk to my to-do list and save it.",
|
||||
"checks": [
|
||||
{
|
||||
"id": "milk",
|
||||
@@ -93,31 +516,35 @@ and `CIRCLE`, and only `CIRCLE` going from 5 to 9 is the user's change.
|
||||
```
|
||||
|
||||
`name` is a portable bundle name other than `smoke` (lowercase letters, digits
|
||||
and hyphens); `prompt` is what the user asks for; `checks` holds 1 to 32
|
||||
checks. Each check has a `kind`, a `file` given as a path under the home such as
|
||||
and hyphens); `prompt` is what the user asks for, naming the app, since a
|
||||
solving agent's own shell cannot see the computer's files and the app's name
|
||||
sends it to the screen; `checks` holds 1 to 32
|
||||
checks. Each file check has a `kind`, a `file` given as a path under the home such as
|
||||
`Documents/todo.txt`, and an optional `id` (`check-1`, `check-2` and so on by
|
||||
position otherwise). A check reads the typed view `data/get` returns for that
|
||||
file, in the shapes of the state view.
|
||||
|
||||
| Kind | Fields | Passes when |
|
||||
| --------------- | ------------------------------------------------------------ | ------------------------------------------------------------------------ |
|
||||
| `file_present` | | The file exists |
|
||||
| `file_absent` | | The file does not exist |
|
||||
| `lines_present` | `lines` | Every listed line is a whole line of the text view |
|
||||
| `lines_absent` | `lines` | None of the listed lines is |
|
||||
| `line_count` | `exact` or `contains`; `equals`, `at_least` or `at_most` | The number of lines equal to `exact`, or holding `contains`, compares so |
|
||||
| `value_equals` | `pointer`, `value`; optional `tolerance` | The pointer names a value equal to `value`, or within `tolerance` of it |
|
||||
| `value_absent` | `pointer` | The pointer names no value |
|
||||
| `text_equals` | `pointer`, `value`; optional `normalize_whitespace` | The XML element's [whole text](#whole-text) equals `value` |
|
||||
| `text_contains` | `pointer`, `value`; optional `normalize_whitespace` | The XML element's whole text holds `value` |
|
||||
| `row_present` | `table`, `where` | A row of the SQLite table has every column in `where` equal |
|
||||
| `row_absent` | `table`, `where` | No row does |
|
||||
| `row_count` | `table`; optional `where`; `equals`, `at_least` or `at_most` | The number of rows, or of rows matching `where`, compares so |
|
||||
| Kind | Fields | Passes when |
|
||||
| --------------- | --------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------- |
|
||||
| `file_present` | | The file exists |
|
||||
| `file_absent` | | The file does not exist |
|
||||
| `lines_present` | `lines` | Every listed line is a whole line of the text view |
|
||||
| `lines_absent` | `lines` | None of the listed lines is |
|
||||
| `line_count` | `exact` or `contains`; `equals`, `at_least` or `at_most` | The number of lines equal to `exact`, or holding `contains`, compares so |
|
||||
| `value_equals` | `pointer`, `value`; optional `tolerance` | The pointer names a value equal to `value`, or within `tolerance` of it |
|
||||
| `value_absent` | `pointer` | The pointer names no value |
|
||||
| `text_equals` | `pointer`, `value`; optional `normalize_whitespace`, `text_attribute` | The XML element's [whole text](#whole-text) equals `value` |
|
||||
| `text_contains` | `pointer`, `value`; optional `normalize_whitespace`, `text_attribute` | The XML element's whole text holds `value` |
|
||||
| `member_count` | `pointer`; optional `matching`; `equals`, `at_least` or `at_most` | The number of [members of the array](#counting-members), or of those `matching` names, compares so |
|
||||
| `row_present` | `table`, `where` | A row of the SQLite table has every column in `where` equal |
|
||||
| `row_absent` | `table`, `where` | No row does |
|
||||
| `row_count` | `table`; optional `where`; `equals`, `at_least` or `at_most` | The number of rows, or of rows matching `where`, compares so |
|
||||
|
||||
The rules both evaluators follow:
|
||||
|
||||
- An absent file reads as empty: no lines, values or rows. So `lines_absent`,
|
||||
`value_absent` and `row_absent` pass on it and a count is 0.
|
||||
`value_absent` and `row_absent` pass on it and a count of lines or rows is
|
||||
0; `member_count` fails, since its pointer names no array.
|
||||
- A file that has no view (binary, over the read limit, or unreadable) fails
|
||||
every check but `file_present` and `file_absent`. Line checks need a text
|
||||
view, row checks a SQLite view and text checks an XML view, in a file or an
|
||||
@@ -129,7 +556,9 @@ 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", …}]}`.
|
||||
`{"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.
|
||||
- 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`.
|
||||
@@ -149,15 +578,94 @@ The rules both evaluators follow:
|
||||
The export refuses, naming the check, a file outside the owned paths, a file
|
||||
spelled with a leading slash, `.` or `..`, a pointer into a file that is text
|
||||
at the seed, as the bundle ships it, or at the end checkpoint, the empty
|
||||
pointer (the whole file), a value that names the captured home, or the
|
||||
pointer (the whole file) except in `member_count`, a `matching` that is no
|
||||
selector, a value that names the captured home, or the
|
||||
capture host's name or `user@host` anywhere (which the
|
||||
[export removes from the seed](desktop-application-export.md#host-name-and-user)), a
|
||||
`tolerance` with a value that is not a number, an empty `text_contains`
|
||||
value, or one of only whitespace with `normalize_whitespace`, and a value that
|
||||
looks like a date and time, in ISO 8601 or `asctime`'s form. Other volatile
|
||||
value, or one of only whitespace with `normalize_whitespace`, an empty
|
||||
`text_attribute`, a count without exactly one of `equals`, `at_least` and
|
||||
`at_most`, and a value that looks like a date and time, in ISO 8601 or
|
||||
`asctime`'s form. Other volatile
|
||||
content, such as a
|
||||
counter the app bumps on every save, is for the author to leave out.
|
||||
|
||||
## Readers
|
||||
|
||||
For a file REA cannot interpret itself, such as an app's binary document,
|
||||
the task can define `readers`: 1 to 8 commands using the app's own reading
|
||||
capability. Each reader has a unique `id` of lowercase letters, digits and
|
||||
hyphens, a home-relative `file`, an `argv` array and `output`, either `json`
|
||||
or `lines`. Its `argv`, or optional `stdin` text, must contain `{file}`;
|
||||
the runner replaces it with the path of a private copy of that file.
|
||||
The command must be installed where the export runs and in the exported
|
||||
computer where the task will be graded.
|
||||
|
||||
The command prints its answer in lines starting with `REA `; other stdout
|
||||
is ignored. With `output: "json"`, those marked lines join into one JSON
|
||||
value for `value_equals`, `value_absent` and `member_count`. With
|
||||
`output: "lines"`, they supply the lines for `lines_present`, `lines_absent`
|
||||
and `line_count`. A check selects a reader with `"reader": "READER-ID"`
|
||||
and must give that reader's file as its `file`. Every reader must be used by
|
||||
at least one check.
|
||||
|
||||
Readers execute commands, including any code in `argv` or `stdin`; review
|
||||
them before exporting or running a task. The runner uses a private copy, a
|
||||
fresh home, no session bus or computer control token, and no display unless
|
||||
the reader requests `display: true`. This is execution isolation from the
|
||||
running app's normal profile, not a filesystem sandbox. `timeout_s` defaults
|
||||
to 60 seconds and accepts 1 to 300. A failed command, timeout, malformed
|
||||
answer or missing marked output reports a reader error; it does not establish
|
||||
that the document lacks the expected value. Correct the command or its output and retry; increase
|
||||
`timeout_s` within its accepted range when the reader needs longer.
|
||||
|
||||
Export runs readers on both retained ends, using the seed bytes as the bundle
|
||||
actually ships them. The witness and exported verifier run them in the
|
||||
computer after the app's files settle. Cleanup failures retain the reader's
|
||||
reported resources: retry the check or close the build computer to retry
|
||||
cleanup; when the command's outcome is unknown, confirm it stopped before
|
||||
removing its folder.
|
||||
|
||||
## Screen judges
|
||||
|
||||
A task whose result exists only on screen can use `screen_judge` checks:
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "show-list",
|
||||
"prompt": "In Notes, show the shopping list.",
|
||||
"checks": [
|
||||
{
|
||||
"id": "shown",
|
||||
"kind": "screen_judge",
|
||||
"question": "Does the window show the shopping list?"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
Each question must be a nonempty yes-or-no question of at most 2,000
|
||||
characters, false on the seed and true when the task is done. A screen task
|
||||
contains only screen checks and takes no readers. Export refuses it when an
|
||||
owned file's readable change could be checked instead, or when the build
|
||||
computer's seed or end screenshot is missing or exceeds 2 MiB. Capture those
|
||||
checkpoints in a build computer before exporting.
|
||||
|
||||
Export ships the two screenshots as labelled failing and passing examples;
|
||||
it does not call the judge or establish that the questions distinguish them.
|
||||
The [build witness](desktop-build-witness.md) runs the exported judge on a
|
||||
fresh screenshot at each stage. The verifier takes a screenshot after the
|
||||
solving agent stops. For each question, the judge sees both examples and
|
||||
votes three times; a majority of yes answers passes the check.
|
||||
|
||||
The judge uses `[model.roles] judge` in the runner's
|
||||
`.agentenv/config.toml`, then `[model] default`, then
|
||||
`anthropic/claude-sonnet-5-5`. Configure its endpoint with
|
||||
`LITELLM_BASE_URL` and `LITELLM_API_KEY`, or `[model] base_url` and `api_key`.
|
||||
`agent-env run --judge-model` does not reach this verifier. Without an
|
||||
endpoint, grading raises and the run fails rather than scoring the agent;
|
||||
configure the endpoint and rerun the witness or task.
|
||||
|
||||
## Pointers and selectors
|
||||
|
||||
An app that rewrites a document moves things: FreeCAD 1.0 records more
|
||||
@@ -171,9 +679,31 @@ rather than by its position:
|
||||
`[name=Object]`.
|
||||
- `[@KEY=VALUE]` names the member whose `attributes` hold `KEY="VALUE"`, as
|
||||
the XML view keeps an element's attributes.
|
||||
- `[>PATH=VALUE]` names the member that holds `VALUE` at a path of one to
|
||||
three `/`-separated steps inside it. `>` reads XML and JSON differently:
|
||||
|
||||
| Form | In an XML element | In a JSON record |
|
||||
| -------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------- |
|
||||
| `[>CHILD=VALUE]` | a child element `CHILD` whose text, every text node in it with each run of whitespace collapsed to one space and none at either end, is `VALUE` | the string field `CHILD`, compared whole |
|
||||
| `[>A/B=VALUE]`, up to `[>A/B/C=VALUE]` | a child `A` with a child `B` of that text | the string at `member.A.B`, compared whole |
|
||||
| `[>A@ATTR=VALUE]`, `[>A/B@ATTR=VALUE]` | a child `A` (or its child `B`) whose attribute `ATTR` is `VALUE` | the field named `A@ATTR`: `@` is part of a JSON key |
|
||||
|
||||
Records that keep their fields as elements are named by a child's text:
|
||||
Osmo's `<contact><first_name>Delphine</first_name>…` is
|
||||
`[name=contact][>first_name=Delphine]`. A GtkBuilder `<child>` is named by
|
||||
the id its widget carries, `[name=child][>object@id=submit_button]`, and a
|
||||
TreeLine node by a field of its `data`,
|
||||
`[format=BOOK][>data/Title=The Silk Roads]`. Any element on the way will
|
||||
do; a path with more than three steps, or an empty one, is no selector;
|
||||
and a missing step, or a value at its end that is not a string, matches
|
||||
nothing.
|
||||
|
||||
- Conditions can follow one another, `[name=Object][@name=Hole]`, and all must
|
||||
hold. They compare strings only, the selector is escaped like any pointer
|
||||
segment (`~1` for `/`), and a value cannot hold `][`.
|
||||
segment, so a path's `/` is `~1` inside a pointer,
|
||||
`/nodes/[format=BOOK][>data~1Title=The Silk Roads]`, and a `/` in a key
|
||||
cannot be a step; a value cannot hold `][`. A JSON field whose key begins
|
||||
with `@` or `>` is selected through a path, `[>@type=Book]`.
|
||||
|
||||
A selector must name exactly one member. When several match, or none does
|
||||
before the last segment, the check fails and says which selector matched what.
|
||||
@@ -187,7 +717,7 @@ FreeCAD 0.21 and 1.0 alike:
|
||||
```json
|
||||
{
|
||||
"name": "cut-hole",
|
||||
"prompt": "Cut a 10 mm hole through the middle of the plate and save it.",
|
||||
"prompt": "In FreeCAD, cut a 10 mm hole through the middle of the plate and save it.",
|
||||
"checks": [
|
||||
{
|
||||
"id": "cut",
|
||||
@@ -294,11 +824,56 @@ read the element's whole text instead:
|
||||
and trims both ends before comparing, as XPath's `normalize-space()` does,
|
||||
for an app that reflows text or a value written across lines. A no-break
|
||||
space is not whitespace there.
|
||||
- `text_attribute` reads text an app keeps in an attribute: the element's
|
||||
text is then that attribute's values on it and its descendants, joined in
|
||||
document order, and its text nodes are left out. Scribus keeps a text
|
||||
frame's text as `<StoryText><ITEXT CH="Spring "/><ITEXT CH="Fair"/></StoryText>`,
|
||||
one `ITEXT` per run of formatting, so the check below reads `Spring Fair`
|
||||
however the runs are split. The pointer must name an element; a text node
|
||||
or attribute value fails.
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "headline",
|
||||
"kind": "text_equals",
|
||||
"file": "Documents/flyer.sla",
|
||||
"pointer": "/root/children/[name=DOCUMENT]/children/[name=PAGEOBJECT][@ANNAME=Headline]",
|
||||
"value": "Spring Fair",
|
||||
"text_attribute": "CH"
|
||||
}
|
||||
```
|
||||
|
||||
## Counting members
|
||||
|
||||
`member_count` counts the members of the array its pointer names: a JSON
|
||||
array, or an XML element's `children`. `matching`, a selector of one or more
|
||||
conditions as [above](#pointers-and-selectors), `[>PATH=VALUE]` included,
|
||||
counts only the members it matches, however many; without it every member
|
||||
counts. An element's children hold its text nodes too, so give `matching`
|
||||
for XML, such as `[name=entry]`. A Tellico task that adds one book to a
|
||||
collection of 12:
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "one-more-book",
|
||||
"kind": "member_count",
|
||||
"file": "Documents/books.tc",
|
||||
"pointer": "/entries/[name=tellico.xml]/view/root/children/[name=collection]/children",
|
||||
"matching": "[name=entry]",
|
||||
"equals": 13
|
||||
}
|
||||
```
|
||||
|
||||
It takes exactly one of `equals`, `at_least` and `at_most`. The empty
|
||||
pointer `""` names the whole file, for a JSON file whose top level is an
|
||||
array. A pointer that names no array, an absent file's included, fails and
|
||||
says what it found there. Like the other counts, it is undecided on a view
|
||||
that may hold only part of the array.
|
||||
|
||||
## Validation and export
|
||||
|
||||
`rea export-desktop-application <capture> <directory> --task <task.json>`
|
||||
evaluates the checks on the capture's state view: on each file as it was at
|
||||
evaluates file checks on the capture's state view: on each file as it was at
|
||||
the seed checkpoint, which is the seed, as the bundle ships it with the
|
||||
capture host's name and user removed, and at the end checkpoint, the
|
||||
captured end state. Those are the capture's first and last checkpoints unless
|
||||
@@ -322,7 +897,10 @@ 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 raises when the app cannot be reached, so the run
|
||||
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
|
||||
fails rather than scoring the agent. The README lists the task, its prompt, its
|
||||
checks and the recipe below.
|
||||
|
||||
@@ -339,7 +917,10 @@ done
|
||||
```
|
||||
|
||||
The agent defaults to Claude Code and the model is the caller's choice (Claude
|
||||
Sonnet 5.5 is a reasonable reference). A run reported as `scored below 1`
|
||||
Sonnet 5.5 is a reasonable reference). The agent calls a model endpoint, and
|
||||
agentenv refuses the run without one: set `LITELLM_BASE_URL` and
|
||||
`LITELLM_API_KEY` where the runs start, or `base_url` and `api_key` under
|
||||
`[model]` in `.agentenv/config.toml`. A run reported as `scored below 1`
|
||||
failed the checks and counts as a miss; one reported as `failed` did not finish,
|
||||
as when the computer or the app could not be reached, and is run again rather
|
||||
than counted. Each run's instance keeps the verifier's results per check under
|
||||
|
||||
+163
-26
@@ -18,13 +18,66 @@ app, exporting its bundle and witnessing the task on such a computer are in
|
||||
skill for doing all of it from a request is
|
||||
[desktop builds](https://github.com/morluto/rea/blob/main/.agents/skills/reverse-engineer-anything/references/desktop-build.md).
|
||||
|
||||
## Set up a build host
|
||||
|
||||
On a Linux host with Node.js and Docker, from a REA
|
||||
[checkout](getting-started/installation.md#run-rea-from-a-checkout):
|
||||
|
||||
```bash
|
||||
rea setup --client claude_code --desktop-build --install-agentenv
|
||||
rea doctor --provider desktop_build --client claude_code
|
||||
```
|
||||
|
||||
Setup shows its plan and asks before it changes anything; `--dry-run` only
|
||||
prints it and `--yes` approves it. It packs REA's runtime archive into
|
||||
`~/.cache/rea/build-computer/rea-<version>.tar.xz` (under `$XDG_CACHE_HOME`
|
||||
when set, `~/Library/Caches` on macOS), and packs again once REA's version
|
||||
changes; an archive `REA_BUILD_COMPUTER_REA_ARCHIVE` already names is
|
||||
recorded instead. It records `REA_AGENT_ENV_COMMAND`, `REA_DOCKER_COMMAND` and
|
||||
`REA_BUILD_COMPUTER_REA_ARCHIVE` as absolute paths in that client's REA
|
||||
registration, keeping a value the registration already has other than an
|
||||
archive setup packed for an earlier REA version, and refreshes the skill.
|
||||
`--install-agentenv` runs `uv tool install agentenv-framework==0.9.1464`
|
||||
when `uv` is on `PATH`, and otherwise prints the command. Setup never
|
||||
installs Docker or Node.js and never runs `sudo`. Restart the client
|
||||
afterwards.
|
||||
|
||||
Doctor is read-only and checks, in order: a Linux amd64 or arm64 host,
|
||||
Node.js, procps `ps`, the Docker CLI, a Docker daemon reachable without
|
||||
`sudo`, 20 GB free where Docker keeps images, agentenv-framework 0.9.1464,
|
||||
the runtime archive of this REA version, the build settings in the
|
||||
registration or the environment, and the skill. Each failure names its fix.
|
||||
It also reports, without counting them against `healthy`, whether a model
|
||||
endpoint for solver runs is configured and which agentenv containers
|
||||
earlier builds left. Pass `--json` for the full report.
|
||||
|
||||
When a setting is unset where the server starts, REA uses `agent-env` and
|
||||
`docker` on `PATH` and the archive setup packed for this REA version. The
|
||||
rest of this page is the same setup by hand.
|
||||
|
||||
## Requirements
|
||||
|
||||
- Docker, and an agentenv-framework install whose `agent-env` program is named
|
||||
by the absolute `REA_AGENT_ENV_COMMAND`. Bundles target agentenv
|
||||
0.9.1431. REA runs its helper, `bridge/agentenv/computer.py`, with that
|
||||
runner's Python: the interpreter on the program's `#!` line, or the
|
||||
`python3` beside it in its virtual environment.
|
||||
- A Linux host on amd64 or arm64 with about 20 GB of free disk for the
|
||||
images agentenv builds and pulls. amd64 and arm64 hosts both build
|
||||
natively; a host builds only its own architecture.
|
||||
- Node.js at the version in `.nvmrc`, installed with
|
||||
[nvm](https://github.com/nvm-sh/nvm) or from
|
||||
[nodejs.org](https://nodejs.org/en/download), and REA
|
||||
[run from a checkout](getting-started/installation.md#run-rea-from-a-checkout).
|
||||
- [Docker Engine](https://docs.docker.com/engine/install/) and its
|
||||
[post-install steps](https://docs.docker.com/engine/install/linux-postinstall/):
|
||||
add yourself to the `docker` group, then log in again.
|
||||
- agentenv-framework 0.9.1464, the version bundles target. Install
|
||||
[uv](https://docs.astral.sh/uv/getting-started/installation/) first, then
|
||||
run `uv tool install agentenv-framework==0.9.1464`. Set
|
||||
`REA_AGENT_ENV_COMMAND` to the absolute path of the resulting `agent-env`
|
||||
program, normally `$HOME/.local/bin/agent-env`; `command -v agent-env`
|
||||
shows the path when its install directory is on your `PATH`. Installing it
|
||||
with pip into a virtual environment instead needs `python3.12-venv` on
|
||||
stock Ubuntu. REA runs its
|
||||
helper, `bridge/agentenv/computer.py`, with that runner's Python: the
|
||||
interpreter on the program's `#!` line, or the `python3` beside it in its
|
||||
virtual environment.
|
||||
- `REA_DOCKER_COMMAND`, the absolute path of the Docker CLI, lets REA remove a
|
||||
computer whose agentenv teardown was not confirmed. Without it, REA names the
|
||||
command to run instead.
|
||||
@@ -34,20 +87,83 @@ skill for doing all of it from a request is
|
||||
checkout, `npm run pack:build-computer-runtime -- /path/to/rea-prod.tar.xz`
|
||||
writes one: `npm pack`, its package folder as
|
||||
`rea-prod` with the lockfile, `npm ci --omit=dev --omit=optional`, then
|
||||
`rea-prod` as `.tar.xz`.
|
||||
`rea-prod` as `.tar.xz`. The archive is a copy of the checkout: pack it
|
||||
again after `git pull` and a rebuild.
|
||||
|
||||
Set these where the MCP server starts; a shell export does not reach a server
|
||||
that is already running.
|
||||
|
||||
## Claude Code
|
||||
|
||||
Without `--desktop-build`, `rea setup --client claude_code` registers REA
|
||||
without these variables. Either
|
||||
export them in the shell that starts `claude`, which starts REA's server with
|
||||
its environment:
|
||||
|
||||
```bash
|
||||
export REA_AGENT_ENV_COMMAND="$HOME/.local/bin/agent-env"
|
||||
export REA_DOCKER_COMMAND="$(command -v docker)"
|
||||
export REA_BUILD_COMPUTER_REA_ARCHIVE="$HOME/rea-runtime/rea-prod.tar.xz"
|
||||
claude
|
||||
```
|
||||
|
||||
or set them, as absolute paths, in the `env` of the `mcpServers.rea` entry
|
||||
setup wrote, such as in `~/.claude.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"mcpServers": {
|
||||
"rea": {
|
||||
"command": "/absolute/path/to/node",
|
||||
"args": ["/absolute/path/to/rea/scripts/rea.mjs", "mcp"],
|
||||
"env": {
|
||||
"REA_AGENT_ENV_COMMAND": "/home/ada/.local/bin/agent-env",
|
||||
"REA_DOCKER_COMMAND": "/usr/bin/docker",
|
||||
"REA_BUILD_COMPUTER_REA_ARCHIVE": "/home/ada/rea-runtime/rea-prod.tar.xz"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Solver runs are `agent-env run` commands the agent runs in its shell, and
|
||||
agentenv refuses them without a model endpoint: export `LITELLM_BASE_URL` and
|
||||
`LITELLM_API_KEY` in the shell that starts `claude`, whose Bash tool inherits
|
||||
them, or set `base_url` and `api_key` under `[model]` in
|
||||
`.agentenv/config.toml`.
|
||||
|
||||
Claude Code asks before each MCP tool call its permission settings do not
|
||||
allow, and a build makes dozens of `act_on_build_computer` calls. You can
|
||||
allow REA's tools in those settings' `permissions.allow` list:
|
||||
`mcp__rea__act_on_build_computer` allows that tool, and `mcp__rea` allows all
|
||||
of REA's.
|
||||
|
||||
A headless run, `claude -p`, ends when the skill asks its upfront questions,
|
||||
and refuses the tool calls its permission settings do not allow. Put the
|
||||
answers in the request: the install source when the app is not in the Ubuntu
|
||||
archive, a synthetic seed or the file to start from, whether to review the
|
||||
task before solver runs, and the solver runs' count, model and budget, or
|
||||
none:
|
||||
|
||||
```bash
|
||||
claude -p 'Build me a Gnote environment where the agent adds olive oil to the
|
||||
shopping list note. Make a synthetic note. Then make 2 solver runs with
|
||||
<model>, at most $4 in all, without a review first.'
|
||||
```
|
||||
|
||||
## Start a computer
|
||||
|
||||
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: 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.
|
||||
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. The name is the desktop entry's last part when it
|
||||
is reverse-DNS (`com.github.xournalpp.xournalpp` gives `xournalpp`), or else
|
||||
the whole entry without a trailing version (`glabels-3.0` gives `glabels`).
|
||||
|
||||
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`
|
||||
@@ -71,16 +187,28 @@ Applications menu entry can open the app.
|
||||
|
||||
| `kind` | Installs |
|
||||
| ---------------- | ---------------------------------------------------------------------------------------------------------- |
|
||||
| `archive` | `package` from the Ubuntu 24.04 archive, on amd64 and arm64 |
|
||||
| `archive` | `package` from the Ubuntu 24.04 archive, on amd64 and arm64, with its optional `extra_packages` beside it |
|
||||
| `apt_repository` | `package` from the repository at `uri` with `suite` and `components`, trusting the key file `key_file` |
|
||||
| `package_file` | The `.deb` at `url`, checked against `sha256`, for one `architecture`, after its apt `dependencies` are in |
|
||||
|
||||
Build steps run with the network off, so a `.deb`'s dependencies must be
|
||||
listed. The bundle adds REA in a build-only layer: Node.js
|
||||
listed. `extra_packages` names up to 16 more archive packages, by the same
|
||||
name rules as `package`, for a runtime piece the app needs that its package
|
||||
does not install: apt here skips Recommends, so MyPaint 2.0.1 exits at launch
|
||||
without `librsvg2-common`, GTK's SVG icon loader, and Freeplane 1.7.10 needs
|
||||
`openjdk-17-jre`, since its launcher refuses noble's default Java 21. The
|
||||
export installs them beside the app too, as it does a `.deb`'s
|
||||
`dependencies` when apt offers the `.deb`'s package; see
|
||||
[build and witness](desktop-build-witness.md).
|
||||
|
||||
The bundle adds REA in a build-only layer: Node.js
|
||||
24.22.1, downloaded per architecture and checked against its release checksum,
|
||||
and REA from `REA_BUILD_COMPUTER_REA_ARCHIVE`, both unpacked into `/opt/rea` by
|
||||
a root build step, with `node` and `rea` on `PATH`. An exported bundle carries
|
||||
none of it.
|
||||
a root build step, with `node` and `rea` on `PATH`. It also installs
|
||||
`libgtk-3-bin`, for `gtk-launch`, and `dconf-cli`, so the capture reads the
|
||||
app's settings in dconf, such as GnuCash's "Show tips at startup", and the
|
||||
seed keeps them. An exported bundle carries none of it but `dconf-cli`, which
|
||||
it installs when it loads the app's dconf keys.
|
||||
|
||||
From a bundle folder, such as one `export-desktop-application` wrote, REA
|
||||
starts that bundle's `tasks/smoke.json` as it is:
|
||||
@@ -96,6 +224,10 @@ 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
|
||||
@@ -105,9 +237,12 @@ while it is one colour throughout. The retries share 10 s, each given only
|
||||
what is left of it, and when that runs out REA returns the latest frame;
|
||||
progress notifications continue meanwhile. Given `screenshot` with a
|
||||
`region`, `format` or `quality`, REA then takes one with them, a `region`
|
||||
cropping that frame. The result holds
|
||||
cropping that frame rather than capturing the screen again. The result holds
|
||||
`computer_id`, agentenv's `sandbox_id`, the environment name or bundle folder,
|
||||
and the screenshot's frame as structured content beside its image.
|
||||
`extra_packages`, what the request named beside the app for the export to
|
||||
install too (an archive install's `extra_packages` or a `.deb`'s
|
||||
`dependencies`, empty otherwise), and the screenshot's frame as structured
|
||||
content beside its image.
|
||||
|
||||
A failed start returns the last 16 KiB of the helper's stderr, where a failing
|
||||
build prints its error, and its exit status; a cancelled one stops the helper,
|
||||
@@ -121,16 +256,16 @@ progress and waits for them before closing every computer.
|
||||
`act_on_build_computer` takes `computer_id`, an `action` and the driver's own
|
||||
arguments for `computer_<action>`, which REA passes through:
|
||||
|
||||
| `action` | Arguments |
|
||||
| ------------ | --------------------------------------------------------------- |
|
||||
| `screenshot` | `region`, `format` (`png` or `jpeg`), `quality` |
|
||||
| `click` | `x`, `y`, `button`, `count` (2 double-clicks), `modifiers` |
|
||||
| `drag` | `path` of `[x, y]` points, `button`, `duration_ms`, `modifiers` |
|
||||
| `scroll` | `direction`, `x`, `y`, `amount`, `modifiers` |
|
||||
| `type` | `text`, where `\n` presses Enter and `\t` Tab |
|
||||
| `key` | `keys`, one chord pressed in order, and `repeat` |
|
||||
| `wait` | `ms` |
|
||||
| `reset` | `screenshot` |
|
||||
| `action` | Arguments |
|
||||
| ------------ | ----------------------------------------------------------------------- |
|
||||
| `screenshot` | `region`, `format` (`png` or `jpeg`), `quality` |
|
||||
| `click` | `x`, `y`, `button`, `count` (2 double-clicks), `modifiers` |
|
||||
| `drag` | `path` of 2 to 50 `[x, y]` points, `button`, `duration_ms`, `modifiers` |
|
||||
| `scroll` | `direction`, `x`, `y`, `amount`, `modifiers` |
|
||||
| `type` | `text`, where `\n` presses Enter and `\t` Tab |
|
||||
| `key` | `keys`, one chord pressed in order, and `repeat` |
|
||||
| `wait` | `ms` |
|
||||
| `reset` | `screenshot` |
|
||||
|
||||
`reset` is not a driver tool: REA calls the app's `data/reset`, which restores
|
||||
the bundle's seed and relaunches the app, then waits until the computer's
|
||||
@@ -154,7 +289,9 @@ The result carries the driver's content unchanged, its text and images, after
|
||||
REA's own JSON: `action_index` and the driver's structured result. A refusal,
|
||||
such as a stale frame, is an error carrying the computer's message. A response
|
||||
larger than the MCP budget is refused with how to ask for a smaller image: a
|
||||
`region`, or `jpeg` with a lower `quality`. That error keeps REA's own result,
|
||||
`region`, or `jpeg` with a lower `quality`. A screenshot with `region` does not
|
||||
capture the screen again; it crops the latest frame, so take a full
|
||||
screenshot, or a `wait` with `screenshot: true`, first. That error keeps REA's own result,
|
||||
`computer_id` included, as `details.result`, since the action or start has
|
||||
happened.
|
||||
|
||||
|
||||
+137
-27
@@ -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 acknowledgement with its counts |
|
||||
| `mark_build_checkpoint` | Takes a named checkpoint and returns the capture's counts and the files that changed |
|
||||
| `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,6 +41,34 @@ 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`.
|
||||
@@ -48,37 +76,96 @@ 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 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.
|
||||
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: like siblings' fields, each line kept beside new text, and
|
||||
the count of a list whose members were only edited. 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, is `unreadable_changes`, not an empty key list);
|
||||
`unreadable_changes` when a dconf database changed but REA could not read
|
||||
it, such as without `dconf-cli` or when a present version's bytes were
|
||||
not retained, 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`, `unreadable_view`,
|
||||
`volatile_lines`, `generated_reference` or `read_as_text`.
|
||||
6. Write the task: its name, the prompt in the user's own words naming the
|
||||
app (a solving agent's own shell cannot see the computer's files, and the
|
||||
export's limitations say when a prompt names neither the app's title,
|
||||
environment nor package), and checks
|
||||
that hold after the change and not on the seed, from the suggestions,
|
||||
`values` and any `guards` worth keeping.
|
||||
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. 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
|
||||
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>#`, GnuCash's
|
||||
`<book>.LCK` or Grisbi's `.<file>.lock` beside its file, are left out of
|
||||
the seed, since a copied one can keep the app from starting or saving. The
|
||||
limitations and 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`, and app
|
||||
logs that are not locks are seeded. The limitations 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
|
||||
`.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
|
||||
through `data/get`, since a large bundle's list outgrows a command's
|
||||
output; it then brings the files back through the driver's
|
||||
`data/get` in answers of at most 8 MiB, and checks and writes each answer
|
||||
into the folder before asking for the next, so one answer at a time is
|
||||
held; a failure leaves no partial folder.
|
||||
the request's URL with `--package-url`; one apt offers installs from apt.
|
||||
Either way the request's `dependencies` reach the export as
|
||||
`--extra-package`, as an archive request's `extra_packages` do, so a
|
||||
runtime piece the agent named, such as MyPaint's `librsvg2-common`, is
|
||||
installed beside the app; the limitations and the README list them,
|
||||
except the app itself and dependencies the bundle already names for a
|
||||
`.deb` it installs from the file. REA lists the bundle's files
|
||||
with their sizes and SHA-256 in the computer, into a file beside the
|
||||
bundle that it reads through `data/get`, since a large bundle's list
|
||||
outgrows a command's output; it then brings the files back through the
|
||||
driver's `data/get` in answers of at most 8 MiB, and checks and writes
|
||||
each answer into the folder before asking for the next, so one answer at
|
||||
a time is held; a failure leaves no partial folder.
|
||||
8. `close_build_computer`.
|
||||
|
||||
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`.
|
||||
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 an app window's title has named so far
|
||||
come first, as a document saved and no longer held open is in Gnumeric, LyX
|
||||
or Tiled; then files named themselves in `state_paths`; then those the app
|
||||
holds open, those under a selected folder and those in its state
|
||||
directories; then the rest; and caches and WebKit, Chromium or QtWebEngine
|
||||
storage last, even under a selected folder such as `.config/libreoffice`
|
||||
with its icon cache, 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.
|
||||
|
||||
Each step can be asked again after its answer was lost:
|
||||
|
||||
@@ -102,7 +189,9 @@ 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.
|
||||
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.
|
||||
|
||||
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
|
||||
@@ -116,7 +205,11 @@ 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.
|
||||
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.
|
||||
Then, with the task exactly as exported:
|
||||
|
||||
| `stage` | Before it | Its checks must |
|
||||
@@ -129,13 +222,29 @@ 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. Without `stage` it only grades. The `seed` stage begins a recording
|
||||
check. Once the files settle it runs the task's
|
||||
[readers](desktop-application-tasks.md#readers) in the computer through
|
||||
`computer-exec/v1`, as the verifier does, and a check through a reader reads
|
||||
that reader's view. A task of [screen judges](desktop-application-tasks.md#screen-judges)
|
||||
reads no files: REA takes a screenshot and runs the bundle's own judge on it
|
||||
with the agentenv runner's Python and model endpoint. 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
|
||||
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
|
||||
recording under the same id, which the computer answers with the recording
|
||||
it already began. The stages come in order. The edit and the near miss each
|
||||
need an applied click, drag, scroll, type or key since the stage before, with
|
||||
need an applied click, drag, scroll, type, typed secret or key since the stage before, with
|
||||
no reset after the last of them, since a reset puts the seed back rather than
|
||||
changing the app; `after_reset` needs the reset as the last change, and a
|
||||
reset that leaves any check unlike on the seed fails the witness, its
|
||||
@@ -171,13 +280,14 @@ 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, the
|
||||
each stage's results with how many logged actions came before it and
|
||||
whether the app's files had settled (`settled`), 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`.
|
||||
`truncated_arguments`, and which stages graded files that had not settled.
|
||||
|
||||
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
|
||||
|
||||
@@ -181,7 +181,8 @@ When choosing the manual path, leave the automatic main release PR unmerged.
|
||||
Select the application commit from main, create the frozen branch, and prepare
|
||||
its own release PR using the steps below. Merging the main release PR starts
|
||||
automatic publication instead. Close the superseded main PR after the manual
|
||||
release has published and its metadata has been synchronized back to main.
|
||||
release has published, before merging the metadata synchronization PR back
|
||||
to main.
|
||||
|
||||
`release/VERSION` also sets the expected version for the workflow. Use an exact
|
||||
SemVer such as `release/6.1.0` or `release/6.1.0-rc.1`, without build metadata.
|
||||
|
||||
+16
-10
@@ -602,6 +602,12 @@ 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
|
||||
@@ -702,16 +708,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 | 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. |
|
||||
| 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. |
|
||||
|
||||
Shared process-supervision controls separate leader exit from output closure.
|
||||
Cover output during held or failed cleanup, bounded retention and drain timeout,
|
||||
|
||||
@@ -60,23 +60,11 @@ 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.
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
## Audit existing tools
|
||||
|
||||
@@ -94,14 +82,10 @@ 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 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.
|
||||
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.
|
||||
|
||||
Report working routes as well as findings. Separate a reproduced contract bug,
|
||||
an intentional limitation, a design opportunity and an unverified hypothesis;
|
||||
@@ -182,7 +166,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`.
|
||||
relationship coverage remains `unknown`. Computed candidates and unestablished incoming targets qualify directional discovery; they do not by themselves mean that recorded edges were omitted.
|
||||
- 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
|
||||
@@ -348,13 +332,15 @@ 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 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.
|
||||
- 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.
|
||||
- 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
|
||||
@@ -373,8 +359,9 @@ 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. Before returning success, check the signal after the
|
||||
last awaited finalization step.
|
||||
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.
|
||||
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,
|
||||
|
||||
+14
-1
@@ -50,7 +50,8 @@ explicitly with the managed tools to establish PE/CLI facts.
|
||||
|
||||
## Admission and containment
|
||||
|
||||
Metadata is range-read with a 64 KiB cache. Policy budgets are 16 MiB of
|
||||
Metadata is range-read with a cache of at most 64 KiB, bounded by the remaining
|
||||
selected metadata allowance. Default policy budgets are 16 MiB of
|
||||
manifest metadata, 100,000 files, 64 KiB per UTF-8 string, 512 MiB of stored or
|
||||
expanded bytes per file, 256 path parts per member, 250,000 distinct in-memory
|
||||
path-tree nodes, and 2 GiB of aggregate expanded bytes. The node budget counts
|
||||
@@ -60,6 +61,18 @@ streams 64 KiB chunks and reuses completed probe facts during extraction;
|
||||
ordinary native files without a marker incur one extra
|
||||
read pass before host hashing.
|
||||
|
||||
Both artifact tools accept `artifact_limits.dotnet_bundle` to select
|
||||
`metadata_bytes`, `entry_count`, `string_bytes`, `member_bytes`,
|
||||
`expanded_bytes`, `path_parts`, and `path_nodes` for the next operation. The
|
||||
string allowance applies to every manifest string, including the bundle ID.
|
||||
For example, retry a complete bundle whose manifest exceeds the default with
|
||||
`{"artifact_limits":{"dotnet_bundle":{"metadata_bytes":33554432}}}`.
|
||||
The CLI accepts the same selection through `--artifact-limits` JSON. Omitted
|
||||
fields preserve defaults; errors name the exact selected control, effective
|
||||
value and required minimum when known. No REA restart is needed. Summary
|
||||
delivery and paging do not change producer admission, and larger reader
|
||||
budgets do not raise MCP response or Node representation limits.
|
||||
|
||||
Extraction hashes the whole host again through the same descriptor used to read
|
||||
members and compares it with the inventory's root digest before creating an
|
||||
output directory. This adds a full-host read pass to extraction, including when
|
||||
|
||||
+17
-1
@@ -44,6 +44,22 @@ 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.
|
||||
|
||||
For Android `NT_ANDROID_TYPE_IDENT` (`.note.android.ident`, owner `Android`,
|
||||
type `1`) notes, `android.android_api` is decoded from both legacy 4-byte
|
||||
descriptors (where `ndk_version` and `ndk_build_number` remain null) and modern
|
||||
132-byte or extended NDK descriptors, which also populate `android.ndk_version`
|
||||
and `ndk_build_number` when their 64-byte slots hold NUL-padded
|
||||
printable ASCII. Truncated or non-ASCII Android descriptors degrade `android`
|
||||
to null while preserving the raw descriptor digest and preview, and other
|
||||
owners keep `android` null.
|
||||
|
||||
`PT_NOTE` and `SHT_NOTE` are examined independently. The same file range may
|
||||
appear twice when both tables declare it.
|
||||
|
||||
@@ -54,7 +70,7 @@ the image never carried notes in another container or overlay.
|
||||
|
||||
The selected file is limited to 64 MiB by default (512 MiB maximum). At most
|
||||
32 note entries are examined by default across every table. Retained note
|
||||
names, section names, GNU descriptor text, and core dump string representations share a scan budget based on
|
||||
names, section names, GNU descriptor text, core dump string representations, and Android ident strings share a scan budget based on
|
||||
the source bytes plus any decoded section-name table, capped at
|
||||
`max_file_bytes`. The raw source and decoded table must also fit together
|
||||
within that ceiling. If admission fails, the error reports the required
|
||||
|
||||
+7
-5
@@ -22,9 +22,10 @@ use the current projection identity; there is no pre-coverage FIT summary varian
|
||||
A FIT is a flattened devicetree (FDT v16 or v17) with a top-level `/images`
|
||||
node. Recognition walks the structure block within the first 4 KiB of the file
|
||||
only; the file name does not matter. A devicetree whose `/images` node begins
|
||||
after 4 KiB, a devicetree without `/images`, and any other FDT version stay on
|
||||
the plain devicetree route: `open_binary` refuses them and
|
||||
[`inspect_devicetree`](devicetree.md) still parses them. A U-Boot control DTB
|
||||
after 4 KiB or a devicetree without `/images` stays on the plain devicetree
|
||||
route: `open_binary` refuses it and [`inspect_devicetree`](devicetree.md)
|
||||
can parse it when its FDT version is 16 or 17. Other FDT versions are not
|
||||
recognized as FIT and are also unsupported by `inspect_devicetree`. A U-Boot control DTB
|
||||
that contains `/images` is treated as a FIT. The container format is `fit`.
|
||||
|
||||
Recognition is a probe. The complete devicetree parse decides, so a file whose
|
||||
@@ -124,8 +125,9 @@ Failures apply to the whole file and return no partial inventory.
|
||||
|
||||
The devicetree, including any embedded image data, must be at most 16 MiB; a
|
||||
larger `totalsize` fails as a memory limit. Store large images externally
|
||||
(`mkimage -E`): external data of any size is streamed from the file and never
|
||||
loaded into memory. A FIT may declare at most 1,024 images and 1,024
|
||||
(`mkimage -E`): external image bytes are streamed from the file within their declared
|
||||
32-bit sizes and the resource bounds below, without loading the whole image
|
||||
into memory. A FIT may declare at most 1,024 images and 1,024
|
||||
configurations, and an image at most 8 hash nodes; the devicetree parser's
|
||||
node, property and depth bounds also apply. The sum of declared image sizes
|
||||
is bounded by the shared archive expansion budget. These are fixed resource
|
||||
|
||||
+98
-65
@@ -439,6 +439,19 @@ 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
|
||||
@@ -449,6 +462,32 @@ The workflow reports note owners, types, descriptor hashes, and GNU build-id
|
||||
or ABI-tag fields when those descriptors match. A missing note table is
|
||||
observed absence of those declarations. See [ELF note tables](../elf-notes.md).
|
||||
|
||||
List ELF and Mach-O initializer and finalizer functions without executing the
|
||||
image:
|
||||
|
||||
```bash
|
||||
rea inspect-native-initializers /absolute/path/to/program --json
|
||||
```
|
||||
|
||||
The workflow reports `DT_INIT`, init/fini arrays, legacy `.ctors`/`.dtors`, and
|
||||
Mach-O `__mod_init_func`, `__init_offsets` and `__mod_term_func` entries with
|
||||
their resolved targets. Universal Mach-O files need `--architecture`. See
|
||||
[ELF and Mach-O initializer functions](../guides/native/native-initializers.md).
|
||||
|
||||
Inspect ELF unwind function ranges without executing the image:
|
||||
|
||||
```bash
|
||||
rea inspect-elf-unwind-ranges /absolute/path/to/program --json
|
||||
```
|
||||
|
||||
The workflow reports FDE start, end, and size, the containing section, an exact
|
||||
symbol name when one exists, CIE identity, LSDA, and personality. Coverage
|
||||
counts ranges that match a symbol, ranges without a symbol, and whether the
|
||||
`.eh_frame_hdr` search table agrees with the decoded FDEs. `.debug_frame` is
|
||||
reported present, absent, or incomplete and is not decoded. A missing unwind table is
|
||||
observed absence of those declarations. See
|
||||
[ELF unwind function ranges](../guides/native/elf-unwind-ranges.md).
|
||||
|
||||
Inspect an Apple `.ips` crash report without executing a target:
|
||||
|
||||
```bash
|
||||
@@ -476,6 +515,22 @@ applicable. gzip, xz, and zstd containers are unsupported and name
|
||||
utility, then inspect the decompressed file. See
|
||||
[Linux kernel modules](../kernel-modules.md).
|
||||
|
||||
Read a Linux kernel image's version banner and embedded `CONFIG_IKCONFIG`
|
||||
build config without executing it:
|
||||
|
||||
```bash
|
||||
rea inspect-kernel-build-config /absolute/path/to/vmlinux --json
|
||||
rea inspect-kernel-build-config /absolute/path/to/bzImage --name CONFIG_MODULE_SIG --json
|
||||
```
|
||||
|
||||
The workflow reports the banner version, builder, and compiler, the config
|
||||
option count, and paged `CONFIG_*` entries (`y`, `m`, strings, numbers, and
|
||||
`not_set`). An `IKCFG_ST` string counts as a config only when a valid gzip
|
||||
member follows it and `IKCFG_ED` follows that member. A gzip bzImage payload
|
||||
is inflated and searched; other payload codecs are unsupported and name
|
||||
`external_decompression` as the next probe. See
|
||||
[Linux kernel build config](../guides/native/kernel-build-config.md).
|
||||
|
||||
Inspect a CPython 3.7–3.13 `.pyc` header and nested marshal code objects (3.14 and
|
||||
3.15 headers are qualified but their marshal layout is not pinned)
|
||||
without executing bytecode or installing Python:
|
||||
@@ -596,10 +651,11 @@ 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 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
|
||||
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
|
||||
`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`.
|
||||
@@ -628,12 +684,10 @@ 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.
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
Importing an Evidence bundle refreshes retained request and subject display metadata.
|
||||
It preserves cached analysis results, including observations for other targets.
|
||||
@@ -1139,6 +1193,23 @@ 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> ...]`
|
||||
@@ -1330,62 +1401,17 @@ 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.
|
||||
`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.
|
||||
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.
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
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
|
||||
@@ -1461,3 +1487,10 @@ Bun standalone executables use the existing `inspect-artifact` and
|
||||
`extract-artifact` commands to inventory and materialize embedded source,
|
||||
sourcemaps and bytecode without running the executable. See
|
||||
[Bun standalone executables](../bun-standalone.md) for layout coverage and limits.
|
||||
|
||||
Deno compile executables use the same commands to inventory and materialize the
|
||||
embedded virtual filesystem, remote modules, and recorded options. Inventory retains
|
||||
embedded environment-file values and certificate bytes in local Evidence with their
|
||||
counts and byte lengths, and extraction does not write them as files. The npm snapshot
|
||||
length is reported and not decoded, and the executable is not run. See
|
||||
[Deno compile executables](../deno-standalone.md).
|
||||
@@ -7,6 +7,7 @@ Setup previews configuration changes and asks for approval before applying them.
|
||||
| ---------------------------------- | ------------------------------------------------------------------------------------------------------------------- |
|
||||
| Connect an agent | [Start setup](#start-setup), then [review changes](#review-setup-changes) |
|
||||
| Install a Claude Code/Codex plugin | [Agent plugins and marketplaces](#agent-plugins-and-marketplaces) |
|
||||
| Run unreleased code | [Run REA from a checkout](#run-rea-from-a-checkout) |
|
||||
| Diagnose one task | [Scoped readiness checks](#check-readiness-for-your-task) |
|
||||
| Configure an analysis engine | [Hopper](#hopper), [Ghidra](#ghidra), the [IDA guide](../providers/ida-provider.md), or [Kuna](../kuna-provider.md) |
|
||||
| Update or remove REA | [Maintenance](#diagnose-update-and-remove) |
|
||||
@@ -384,14 +385,22 @@ Select the part you want to check:
|
||||
| One analysis engine | `rea doctor --provider ghidra --json` (or `hopper`, `ida`, `jadx`, `kuna`) |
|
||||
| One agent registration | `rea doctor --client codex --json` (see [client IDs](#supported-agents)) |
|
||||
| Installed workflow instructions | `rea doctor --skill --json` |
|
||||
| Desktop app environment builds | `rea doctor --provider desktop_build --client claude_code --json` |
|
||||
|
||||
A scoped report has `scope.mode: "explicit"`. Its `scope_checks` determine
|
||||
`healthy` and the exit status. Other checks appear in `informational_checks`;
|
||||
`environment_healthy` summarizes the full audit. `--target` adds a target check,
|
||||
but the report remains audit-wide unless a scope option is also supplied.
|
||||
|
||||
Provider checks read the terminal running doctor. A client-started server may
|
||||
receive a different environment, and doctor cannot observe it. When an available
|
||||
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 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
|
||||
@@ -595,6 +604,36 @@ feature selection. The same package version string in a development checkout
|
||||
does not establish that its bytes match the npm tarball. Update a registration
|
||||
through a reviewed, scoped setup plan, then restart/reconnect the agent.
|
||||
|
||||
### Run REA from a checkout
|
||||
|
||||
To run code that is not released yet, build a checkout with the Node.js
|
||||
version in `.nvmrc`:
|
||||
|
||||
```bash
|
||||
git clone https://github.com/morluto/rea.git
|
||||
cd rea
|
||||
npm ci
|
||||
npm run build:cached
|
||||
```
|
||||
|
||||
Then run `npm link` once in the checkout to put its `rea` on your `PATH`, or,
|
||||
wherever these docs say `rea …`, run
|
||||
`node /absolute/path/to/rea/scripts/rea.mjs …`. Setup run this way registers
|
||||
the checkout's `scripts/rea.mjs` with your agents.
|
||||
|
||||
After `git pull`, run `npm ci` and `npm run build:cached` again. If the
|
||||
checkout's skill changed, refresh each installed copy before restarting its
|
||||
agent. For example, preview and review the Claude Code skill changes:
|
||||
|
||||
```bash
|
||||
rea setup --skill-client claude_code --dry-run --json
|
||||
```
|
||||
|
||||
Then apply the reviewed changes with `rea setup --skill-client claude_code --yes --json`.
|
||||
Substitute the relevant skill client; use the checkout's
|
||||
`node /absolute/path/to/rea/scripts/rea.mjs` form if `rea` is not linked. For desktop builds, also pack the [build computer's runtime
|
||||
archive](../desktop-build-computer.md#requirements) again.
|
||||
|
||||
## Skill-only installation
|
||||
|
||||
```bash
|
||||
|
||||
+2
-2
@@ -1,7 +1,7 @@
|
||||
# GameCube DOL analysis through Ghidra
|
||||
|
||||
This lane imports 32-bit big-endian PowerPC GameCube/Wii DOL images through
|
||||
Ghidra. It does not execute the image. DOL is a headerless format with no magic
|
||||
Ghidra. It does not execute the image. DOL has a section and entry-point header but no magic
|
||||
number, so REA never detects it: the caller must select it explicitly.
|
||||
|
||||
Only the cached MEM1 window `0x80000000..0x81800000` is admitted. Wii MEM2
|
||||
@@ -29,7 +29,7 @@ MCP, with the existing `open_binary` tool:
|
||||
}
|
||||
```
|
||||
|
||||
The architecture comes from the DOL header (`powerpc`). Do not pass
|
||||
Selecting the DOL format supplies the architecture (`powerpc`). Do not pass
|
||||
`architecture` with `gamecube-dol`; it is rejected. `entry_point` is optional,
|
||||
and if given it must equal the header entry.
|
||||
|
||||
|
||||
+26
-1
@@ -144,9 +144,34 @@ keys, decode Godot resources, decompile GDScript bytecode, analyze signals,
|
||||
apply patch/removal entries or execute targets.
|
||||
|
||||
Readable logical member bytes, including repeated physical ranges, share the ZIP
|
||||
archive expansion policy: at most the larger of 256 MiB or 500 times the PCK's
|
||||
archive expansion policy by default: at most the larger of 256 MiB or 500 times the PCK's
|
||||
encoded byte span. Embedded carrier bytes do not enlarge that budget. The full
|
||||
directory is checked before any member is yielded, hashed or extracted. Encrypted
|
||||
members are not read and do not consume this plaintext-work allowance. Small
|
||||
bounded aliases remain valid. This is a processing/output resource bound, separate
|
||||
from the directory metadata retention budget and format validity.
|
||||
|
||||
Directory retention defaults to 64 MiB of encoded metadata. Select
|
||||
`artifact_limits.godot.directory_bytes` to change it; path/source facts reserve
|
||||
worst-case JSON expansion before declared path bytes are read, and the reader
|
||||
then charges actual retained metadata. A preallocation `required_value` is the
|
||||
allowance needed by that admission check, not a measurement of final output size.
|
||||
Select `artifact_limits.expanded_bytes` independently to change aggregate
|
||||
plaintext work, including repeated readable logical occurrences. Both controls
|
||||
apply to inspection and extraction, before any member is yielded.
|
||||
|
||||
For example:
|
||||
|
||||
```sh
|
||||
rea inspect-artifact ./game.pck --artifact-limits '{"godot":{"directory_bytes":134217728},"expanded_bytes":1073741824}' --json
|
||||
```
|
||||
|
||||
MCP uses the same object under `artifact_limits` on `inspect_artifact` or
|
||||
`extract_artifact`. A refusal reports the exact `reader_limit` parameter,
|
||||
effective value, unit, supported range and required value when known. Raise the
|
||||
named admission and retry the same complete PCK on the next call; no REA restart
|
||||
is needed. Summary or page size does not change producer admission. Omitted
|
||||
policy selections stay omitted in Evidence parameters; a selected object records
|
||||
the accepted selection and `effective_limits`, conditional on which readers are
|
||||
encountered. Raising these policies does not admit malformed offsets, unsupported
|
||||
flags, unsafe extraction paths or unavailable encrypted contents.
|
||||
@@ -113,8 +113,8 @@ existing analysis families directly, for example
|
||||
| `push_adb_file` | **mutates device** | One local file to a device path (e.g. pushing tools into `/data/local/tmp`); checks for existing targets and refuses them without explicit overwrite (the check is not atomic); compares digests when device `sha256sum` is available |
|
||||
| `install_adb_package` | **mutates device** | Local APK via `adb install [-r]`; preserves its Success/Failure verdict, records `replace_requested`, and leaves actual replacement `null` because prior package state is not observed |
|
||||
| `uninstall_adb_package` | **mutates device** | Requests package removal for user 0 via `adb shell pm uninstall --user 0`, without data retention |
|
||||
| `start_adb_app` | **mutates device** | Resolves the package's launcher activity (`cmd package resolve-activity --brief`) and starts it (`am start -n`) |
|
||||
| `start_adb_activity` | **mutates device** | Starts an intent (`am start -a` with optional URI, component, and up to 16 typed extras); preserves the activity manager's verdict |
|
||||
| `start_adb_app` | **mutates device** | Resolves the package's launcher activity (`cmd package resolve-activity --brief`) and starts it (`am start -W -n`) |
|
||||
| `start_adb_activity` | **mutates device** | Starts an intent (`am start -W -a` with optional URI, component, and up to 16 typed extras); preserves the activity manager's verdict |
|
||||
| `stop_adb_app` | **mutates device** | Force-stops every process of a package, ending a dynamic-analysis run |
|
||||
|
||||
Screen capture validates the PNG signature, IHDR framing, dimensions, and IHDR
|
||||
@@ -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,
|
||||
each paired with byte size and SHA-256 digest. A pulled file's host name is
|
||||
with byte size and SHA-256 digest on success. 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,6 +249,10 @@ 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.
|
||||
|
||||
@@ -545,7 +545,8 @@ and each upstream request and reply collected before the failure. Failed replies
|
||||
remain available even when their payload cannot be interpreted. Cancellation
|
||||
also stops target hashing before provider admission.
|
||||
|
||||
These operations do not execute the APK or provide split APK/AAB handling,
|
||||
The JADX package, class, method and reference operations do not execute the APK
|
||||
or provide split APK/AAB handling,
|
||||
signature validation, full resource-table semantics, native-library analysis or
|
||||
Android runtime capture. An `.aab` suffix is a ZIP archive, not an APK, so
|
||||
Android tools and the application graph do not treat it as a standalone APK.
|
||||
|
||||
@@ -66,6 +66,8 @@ rea decode-android-resources /targets/Example.apk --locales de --locales pt-BR
|
||||
rea decode-android-resources /targets/Example.apk --locales de --locales pt-BR --string-tables-only
|
||||
rea decode-android-resources /targets/Example.apk --no-strings
|
||||
rea decode-android-resources /targets/Example.apk --decode-timeout-ms 900000
|
||||
rea decode-android-resources /targets/Example.apk --string-offset 2000 --string-limit 100 --string-tables-only
|
||||
rea decode-android-resources /targets/Example.apk --max-string-table-bytes 16777216 --max-total-string-table-bytes 67108864
|
||||
```
|
||||
|
||||
Equivalent MCP methods are `inspect_apktool_client` and
|
||||
@@ -87,6 +89,31 @@ responses and charges the aggregate output budget for one copy per table.
|
||||
Omitting the option preserves existing responses. `include_strings: false`
|
||||
still suppresses all string projection, including in this mode.
|
||||
|
||||
Use `string_offset` and `string_limit` (CLI `--string-offset` and
|
||||
`--string-limit`) to select a page of valid parsed entries from each requested
|
||||
table, in source order. Defaults are offset 0 and limit 2000. Explicit page or
|
||||
budget controls include `string_tables` even for a single primary table; its
|
||||
`page` gives the requested offset and limit, returned count, and `next_offset`.
|
||||
Retry that offset with the same locale and confirm `target.sha256` matches.
|
||||
Each call decodes a fresh owned snapshot; it does not retain a workspace or
|
||||
promise identity across changed APKs. A null continuation means the page reaches
|
||||
the end, while table coverage remains partial if earlier entries were omitted.
|
||||
An offset at or beyond the end returns an empty, present table with known counts.
|
||||
If the continuation equals the requested offset, no output entry fit: increase
|
||||
`max_total_strings` or use `string_tables_only` before retrying.
|
||||
|
||||
`max_total_strings` (CLI `--max-total-strings`, default 10000) bounds returned
|
||||
string copies across all tables. Raise it, request fewer locales, or use
|
||||
`string_tables_only` when aggregate output is exhausted. The legacy
|
||||
multi-table shape charges both copies of primary strings. `max_string_table_bytes`
|
||||
(CLI `--max-string-table-bytes`, default 8388608) bounds one XML source read;
|
||||
`max_total_string_table_bytes` (CLI `--max-total-string-table-bytes`, default 33554432) bounds XML reads across distinct physical tables. Locale aliases
|
||||
share the physical read and parsed page. Raise the relevant read budget to
|
||||
retry an oversized table; a larger string limit or timeout does not raise it.
|
||||
These controls take nonnegative safe-integer offsets and positive safe-integer
|
||||
budgets, apply on the next decode, and require no REA restart. Process memory
|
||||
and response transport capacity still apply.
|
||||
|
||||
## Interpret the result
|
||||
|
||||
- **An owned APK snapshot is digested and decoded.** `target.sha256` and
|
||||
@@ -117,8 +144,8 @@ still suppresses all string projection, including in this mode.
|
||||
Malformed XML and a wrong document root are whole-document projection
|
||||
failures: the result is partial, the failure reason is disclosed, and entry
|
||||
counts remain unknown. They are not counted as one unsupported string.
|
||||
The default table is bounded to 2000 entries with partial coverage when more
|
||||
exist. `locales` lists observed regular `strings.xml` tables whose exact
|
||||
The default page returns up to 2000 entries with partial coverage when more
|
||||
exist; its limitation names the next `string_offset`. `locales` lists observed regular `strings.xml` tables whose exact
|
||||
`values-<locale>` directory is selectable by the request's locale grammar.
|
||||
Locale suffixes allow up to 23 ASCII characters, derived from Apktool's
|
||||
language, script, region, and variant fields; for example,
|
||||
@@ -133,9 +160,10 @@ still suppresses all string projection, including in this mode.
|
||||
When multiple tables are requested with `locales`, `string_tables` records
|
||||
each projected table with its locale, status (`present`, `missing`,
|
||||
`oversized`, `malformed`, or `skipped`), entry counts, and coverage,
|
||||
bounded at an aggregate budget of 10,000 strings and 32 MiB XML. When `locales`
|
||||
is omitted and `string_tables_only` is not true, legacy single-table payloads are preserved
|
||||
without adding `string_tables`.
|
||||
with default aggregate budgets of 10,000 strings and 32 MiB XML. When `locales`
|
||||
is omitted, `string_tables_only` is not true and no string page or budget
|
||||
control is selected, legacy single-table payloads are preserved without adding
|
||||
`string_tables`.
|
||||
- **Smali is skipped by design** (`apktool d --no-src`): Java-source
|
||||
recovery belongs to the JADX family. Resource smali edits and rebuild are
|
||||
a follow-up lane with mutation authority.
|
||||
@@ -156,8 +184,8 @@ still suppresses all string projection, including in this mode.
|
||||
- The version probe waits 20000 ms and retains 65536 bytes. This release has
|
||||
no runtime override for that probe. `decode_timeout_ms` does not raise it.
|
||||
- Manifest reads are bounded to 512 KiB before decoding UTF-8. Strings XML
|
||||
reads are bounded to 8 MiB; larger documents are skipped with partial
|
||||
coverage and an explicit limit, rather than reported as missing.
|
||||
reads default to 8 MiB per table; larger documents are skipped with partial
|
||||
coverage and an explicit read-budget recovery, rather than reported as missing.
|
||||
- `decoded_file_count` is capped at 100,000 files; the cap is reported in
|
||||
the limitations when hit.
|
||||
- An ordinary nonzero decode exit surfaces as `unsupported_target` naming
|
||||
|
||||
@@ -217,3 +217,47 @@ The Gallery workflow and all 147 focused Flutter tests also pass on macOS Sonoma
|
||||
including the conflicting-load and note-range-limit CLI/MCP regressions. Windows
|
||||
verification runs under a non-administrator account. Verifiers use a shared
|
||||
temporary parent so each CLI/MCP process can own and release its own snapshots.
|
||||
|
||||
## Selecting and recovering string-pool observations
|
||||
|
||||
`inspect_dart_aot` accepts `pool_policy`; the CLI uses `--pool-policy` JSON:
|
||||
|
||||
```sh
|
||||
rea inspect-dart-aot app.apk --pool-policy '{"contains":"package:my_app/"}'
|
||||
rea inspect-dart-aot app.apk --pool-policy '{"uri_limit":2000,"token_limit":4000,"run_bytes":4096,"token_bytes":256}'
|
||||
```
|
||||
|
||||
A literal, case-sensitive `contains` filter runs before distinct collection,
|
||||
so an omitted URI or identifier can be selected without returning every other
|
||||
string. URI/token counts describe matching entries; `printable_run_count` counts
|
||||
complete printable runs before filtering. Unset budgets preserve the defaults:
|
||||
500 returned entries per URI category, 2000 identifier-like tokens, 1024 bytes
|
||||
per printable run, and 128 bytes per identifier. Budget values must be positive
|
||||
safe integers. Collection retains at most twice the selected category limit;
|
||||
counts remain lower bounds when that capacity is reached. A run exceeding
|
||||
`run_bytes` is omitted whole, rather than reported as a fabricated prefix.
|
||||
The result names the budget reached, and `string_pool.policy` records the
|
||||
selected filter and effective values. A larger budget or a narrower selection
|
||||
applies to the next call without a REA restart; explicit choices stay in Evidence.
|
||||
|
||||
For a larger package-URI inventory, select the category and its relevant budget:
|
||||
|
||||
```sh
|
||||
rea inspect-dart-aot app.apk --pool-policy '{"contains":"package:","uri_limit":2048}'
|
||||
```
|
||||
|
||||
The equivalent MCP input is `pool_policy: {contains: "package:", uri_limit: 2048}`.
|
||||
This recovers all bounded package-URI observations in the measured Gallery and
|
||||
LocalSend APKs. Check the result's limits and coverage for other targets; long
|
||||
runs and unsupported snapshot layouts remain separate limitations. The
|
||||
[calibration report](../../verification/flutter-budget-calibration.md)
|
||||
keeps the default at 500 because increasing every complete overview also delivers
|
||||
more strings when they are unnecessary. Use `detail: "summary"` for the MCP
|
||||
identity/count task described above.
|
||||
|
||||
These controls do not raise APK, ELF, library or response budgets, deserialize
|
||||
Dart objects, or establish typed class/function semantics. Retained
|
||||
`inspect_analysis_view` pages cover the returned selection; exhausting those
|
||||
pages does not recover facts that the producing pool scan omitted. Re-run the
|
||||
producer with the reported selection or budget change to obtain a new
|
||||
observation, checking its APK and library digests before comparing it.
|
||||
@@ -117,8 +117,8 @@ are never passed to TShark.
|
||||
Installed libraries, global configuration and plugins remain trusted, are not
|
||||
fully fingerprinted, and can influence dissection. This is not an OS sandbox.
|
||||
|
||||
Input is limited to 32 MiB before reading, each command to 30 seconds, and
|
||||
combined stdout/stderr to 4 MiB during collection. Output overflow fails instead
|
||||
Default limits are 32 MiB input before reading, 30 seconds per command, and
|
||||
4 MiB combined stdout/stderr during collection. Output overflow fails instead
|
||||
of returning truncated success. Before execution, `prlimit` enforces **1 GiB
|
||||
address space per process**, **64 MiB per file**, **30 CPU seconds** and no core
|
||||
dumps. Stricter inherited soft/hard limits are preserved; Evidence records the effective
|
||||
@@ -128,6 +128,23 @@ These are not aggregate process-memory or filesystem quotas. The selected
|
||||
limiter is trusted; its path, digest and arguments are retained in Evidence.
|
||||
No arbitrary process flags are accepted.
|
||||
|
||||
Each capture/recording operation accepts `producer_limits` with positive safe
|
||||
integer overrides: `input_bytes`, `output_bytes`, `command_timeout_ms`,
|
||||
`address_space_bytes`, `file_bytes`, and `cpu_seconds`. The wall-clock timeout
|
||||
is at most 2,147,483,647 milliseconds, matching Node timers. Omitted fields keep
|
||||
the defaults above. Discovery accepts the same controls except `input_bytes`,
|
||||
since it does not read a capture or recording. Packet field discovery defaults
|
||||
to 32 MiB output rather than 4 MiB.
|
||||
|
||||
CLI supplies this object as JSON with `--producer-limits`, for example
|
||||
`--producer-limits '{"input_bytes":67108864,"output_bytes":8388608,"cpu_seconds":60}'`.
|
||||
Values apply to the next call without restarting REA. Effective native ceilings
|
||||
still preserve any tighter inherited soft and hard limit. Errors identify the
|
||||
exhausted producer control and retain partial output and cleanup status; follow
|
||||
that repair after cleanup settles. Raising producer budgets does not raise
|
||||
separate parser representations, transport buffers or external client deadlines.
|
||||
Never truncate the selected artifact to fit an input budget.
|
||||
|
||||
## Verification
|
||||
|
||||
```sh
|
||||
@@ -182,8 +199,9 @@ proof that the field appears in a selected recording.
|
||||
|
||||
The adapter uses the documented `tshark -G fields` grammar under its existing
|
||||
private empty profile and Linux process limits. TShark 4.6.9's full glossary was
|
||||
measured at 22,303,197 bytes; discovery admits at most **32 MiB** combined command
|
||||
output (capture inspection remains at **4 MiB**). Parsing walks lines once and
|
||||
measured at 22,303,197 bytes; discovery defaults to **32 MiB** combined command
|
||||
output (capture inspection defaults to **4 MiB**); `producer_limits.output_bytes`
|
||||
can change either request budget. Parsing walks lines once and
|
||||
constructs objects only for the selected page. Returned strings are copied so
|
||||
retained pages do not retain the complete glossary string. Before constructing a selected
|
||||
record it charges six times the source UTF-8 bytes plus 512 bytes against an
|
||||
|
||||
@@ -90,9 +90,20 @@ 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. Row
|
||||
order is unspecified; a truncated sample does not prove anything about omitted
|
||||
records. View, virtual-table and shadow-table row reads are unsupported.
|
||||
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.
|
||||
|
||||
SQLite integers are decimal strings so every signed 64-bit value survives JSON
|
||||
serialization. Real values retain their numbers; `"Infinity"`, `"-Infinity"`
|
||||
|
||||
@@ -118,16 +118,25 @@ CLI keeps its existing complete result.
|
||||
|
||||
## Resource and lifecycle limits
|
||||
|
||||
Inputs are limited to 4 MiB, complete replies to 16 MiB and combined diagnostic
|
||||
output to 1 MiB. An owned worker has a 256 MiB JavaScript heap; its profile
|
||||
maxima are 3 GiB virtual address space and 30 CPU seconds, with tighter inherited
|
||||
limits retained. The worker command deadline is
|
||||
`timeout_ms` (default 30000 ms, integer 1 through 2147483647) on the next call,
|
||||
or `--timeout-ms` on `rea inspect-evm-interface`. Omission keeps 30000 ms.
|
||||
Those byte, address-space, and CPU ceilings have no runtime override, and
|
||||
`timeout_ms` does not raise them. An oversized selected carrier returns a
|
||||
non-retryable `resource_constraint` with resource `file-size` and its fixed
|
||||
input allowance in `reported_limits.maximum_input_bytes`.
|
||||
Per-call `producer_limits` selects `input_bytes`, `output_bytes`,
|
||||
`diagnostic_bytes`, `address_space_bytes`, `file_bytes` and `cpu_seconds`.
|
||||
Omission keeps 4 MiB input, 16 MiB reply/file, 1 MiB diagnostics, 3 GiB address
|
||||
space and 30 CPU seconds. Omitted `file_bytes` follows the selected
|
||||
`output_bytes`, so raising the reply allowance does not silently meet the old
|
||||
file-write allowance. Explicit file limits remain independent. These fields
|
||||
accept positive safe integers; changes apply to the next call without a REA
|
||||
restart. The CLI accepts the same exact policy as JSON, for example:
|
||||
|
||||
```sh
|
||||
rea inspect-evm-interface ./runtime.hex hex --producer-limits '{"input_bytes":8388608,"output_bytes":33554432}'
|
||||
```
|
||||
|
||||
The owned worker's 256 MiB JavaScript heap remains separate. The worker command
|
||||
deadline is `timeout_ms` (default 30000 ms, integer 1 through 2147483647), or
|
||||
`--timeout-ms` on the CLI. Raising it does not raise producer, heap or client
|
||||
limits. An oversized carrier reports non-retryable `resource_constraint` with
|
||||
`reported_limits.maximum_input_bytes` and recovery naming
|
||||
`producer_limits.input_bytes`.
|
||||
Complete-reply allowance refusals use the same non-retryable resource family,
|
||||
with `reported_limits.maximum_reply_bytes`; malformed JSON remains unreadable
|
||||
output. This refusal leaves no complete report to retrieve through another
|
||||
@@ -135,7 +144,7 @@ delivery channel. Virtual address space differs from resident memory. The worker
|
||||
soft/hard limits, reports its configured soft limits inline and leaves hard limits
|
||||
unchanged. WASM trap reservations are disabled
|
||||
so the engine can run within that virtual limit; actual memory is not equated to
|
||||
its 3 GiB allowance. Limits fail without partial success. Stable snapshots,
|
||||
the selected address-space allowance. Limits fail without partial success. Stable snapshots,
|
||||
private files and owned processes are cleaned independently of caller cancellation.
|
||||
Invalid-input, unsupported, cancellation, timeout and malformed-reply failures
|
||||
retain bounded stdout/stderr under `details.captured_output`, including whether
|
||||
|
||||
@@ -265,6 +265,9 @@ 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,6 +50,9 @@ 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
|
||||
|
||||
@@ -223,6 +226,12 @@ registrations/removals and dispatch, Node timers and cancellation handles, async
|
||||
`node:child_process` creation and ownership, configuration sources and direct
|
||||
defaults, request construction and response consumers, parse/coercion/
|
||||
validation boundaries, and built-in resource acquisition/release.
|
||||
For `fs/promises.open`, a binding receiving the Promise is distinct from one
|
||||
receiving the awaited FileHandle. Awaiting the Promise later does not replace
|
||||
the original binding, but `h = await h` can replace it with the FileHandle.
|
||||
Receiver writes can therefore retain a candidate release and its ownership
|
||||
ambiguity; a still-known Promise has no direct FileHandle release. Acquisitions
|
||||
remain retained, and unknown loader authority keeps its existing candidate tag.
|
||||
Reassignments connect retained right-hand reads to the binding or property
|
||||
write. Compound assignments also retain the previous-value input; logical
|
||||
assignments keep conditional inputs as candidates. These edges describe
|
||||
|
||||
@@ -22,7 +22,9 @@ rea analyze-javascript-application /absolute/path/to/apps/app.asar \
|
||||
|
||||
Generic `rea analyze` selects this static provider for directories and `.asar`
|
||||
paths when neither `--provider` nor `--snapshot` is supplied. The dedicated
|
||||
command and the generic route return their complete results inline. Native
|
||||
command and the generic route return complete results inline by default.
|
||||
Summary and route-view delivery export the full Evidence to `--evidence_output`
|
||||
and return a projection; see [route delivery](../../javascript-route-inventory.md). Native
|
||||
targets, single JavaScript files, `.app` bundles, and explicit deep-provider or
|
||||
snapshot requests retain the native deep-analysis route.
|
||||
|
||||
@@ -86,6 +88,11 @@ 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:
|
||||
|
||||
@@ -181,7 +188,9 @@ coverage, limitations, and `normalized_result.parent_evidence_id`. Pass that ID
|
||||
to `inspect_analysis_view` for module pages or items, or to the application
|
||||
workflows as a retained reference. The summary does not repeat or truncate the
|
||||
analysis; a server without session retention refuses summary detail with
|
||||
`capability_unavailable`. CLI output is unchanged and always complete.
|
||||
`capability_unavailable`. On the CLI, `--detail summary --evidence_output PATH`
|
||||
exports the full Evidence and returns its summary; the default remains complete
|
||||
inline delivery.
|
||||
|
||||
With a connected MCP `client` and the caller-selected absolute `inputPath`, this
|
||||
recipe analyzes once and pages module identities using the returned ID:
|
||||
@@ -323,6 +332,12 @@ 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`
|
||||
@@ -515,6 +530,25 @@ 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
|
||||
@@ -729,7 +763,7 @@ These safeguards are not caller-selectable output budgets. Source-map parsing
|
||||
reports truncation when its format or parser safety boundary is reached. The
|
||||
application graph has no aggregate node, edge, root, or observation prefix cap.
|
||||
|
||||
Semantic evaluation retains at most 256 distinct primitive candidates per
|
||||
By default, semantic evaluation retains at most 256 distinct primitive candidates per
|
||||
expression and at most 1 MiB of worst-case JSON string bytes across a normalized
|
||||
primitive value's string candidates. The byte budget estimates six JSON bytes
|
||||
per UTF-16 code unit, the expansion bound for escaped strings, and bounds both
|
||||
@@ -749,13 +783,48 @@ available for endpoint queries, tracing and comparison. Each analysis records en
|
||||
later projections: a selected healthy sibling can remain exact while whole-file
|
||||
coverage reports the encountered bound. Projection preserves limiting values
|
||||
from the shared property-slot owner. Expression
|
||||
evaluation and provenance walks stop after 256 nested levels. Union products
|
||||
evaluation and provenance walks default to 256 nested levels. Union products
|
||||
and string lengths are checked before allocating combinations or concatenated
|
||||
strings. When a boundary is reached, the value stays unknown, semantic coverage
|
||||
becomes partial, and graph evidence retains the expression location and typed
|
||||
limiting reason. The number of unresolved alternatives is unknown; it is not
|
||||
reported as an exact omission count.
|
||||
|
||||
`semantic_precision` selects per-source evaluator budgets independently of
|
||||
retained graph capacity, worker memory and deadlines. Both
|
||||
`analyze_javascript_application` and `analyze_web_bundle` accept a partial object:
|
||||
|
||||
| Field | Default | Unit |
|
||||
| ---------------------- | ------: | ------------------------------------------- |
|
||||
| `primitive_candidates` | 256 | alternatives per normalized primitive value |
|
||||
| `primitive_bytes` | 1048576 | estimated JSON bytes per primitive value |
|
||||
| `expression_depth` | 256 | nested expression/provenance levels |
|
||||
| `getter_expansions` | 512 | scheduled states per precise getter query |
|
||||
| `alias_selections` | 512 | additional precise selector states |
|
||||
| `wrapper_visits` | 1000000 | wrapper visits/substitutions per source |
|
||||
| `wrapper_depth` | 128 | active symbolic wrapper levels |
|
||||
|
||||
`primitive_bytes` charges six estimated JSON bytes per UTF-16 code unit plus
|
||||
quotes before creating concatenated strings. Ordinary ASCII can exhaust that
|
||||
conservative estimate before its actual JSON encoding reaches the selected
|
||||
byte count. The [calibration record](../../verification/javascript-precision-calibration.md)
|
||||
keeps existing defaults for its measured literal-value tasks; it does not
|
||||
establish optimal candidate, getter or alias budgets for larger applications.
|
||||
|
||||
All fields accept positive safe integers; worker memory, execution and JSON
|
||||
representation bounds remain independently enforced. Omission keeps the defaults;
|
||||
invalid values fail validation. For example, retry a finite candidate-limit
|
||||
observation with `semantic_precision: {"primitive_candidates": 512}`. The CLI
|
||||
accepts `--semantic-precision '{"primitive_candidates":512}'` or a JSON file.
|
||||
An override applies to that next analysis without restarting REA, remains in
|
||||
Evidence parameters and effective coverage, and cannot change already retained
|
||||
facts. Increasing these budgets does not raise graph retention, worker heap,
|
||||
transfer admission, or parent result memory. Cyclic or unsupported evaluations
|
||||
remain unknown. Wrapper limitations name visits and depth separately so a
|
||||
caller can change the resource actually exhausted. Finite inline literal object
|
||||
spreads use iterative syntax traversal and no longer inherit a duplicate
|
||||
semantic-depth cut.
|
||||
|
||||
Byte, entry, path, and graph-shape bounds are hard limits. The parse deadline is
|
||||
checked before and between bounded parsing and traversal phases; the synchronous
|
||||
Babel and JSON parser calls cannot be preempted mid-call, so their input byte
|
||||
|
||||
@@ -141,7 +141,7 @@ variants of one file remain separate observations. Older Evidence may omit
|
||||
|
||||
## Node and Electron roles
|
||||
|
||||
The caller declares one role: `node`, `electron-main`, `electron-preload`, or
|
||||
The caller may declare one role: `node`, `electron-main`, `electron-preload`, or
|
||||
`electron-renderer`. Node and Electron-main declarations require a protocol
|
||||
target of type `node`; preload and renderer declarations require `page`.
|
||||
Inspector does not authenticate the operating-system PID or distinguish an
|
||||
|
||||
@@ -0,0 +1,121 @@
|
||||
# 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 produces completed inspection
|
||||
Evidence; the stable-read partial observation described above is retained when available.
|
||||
|
||||
`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,13 +212,9 @@ 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. 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`.
|
||||
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).
|
||||
|
||||
Copy `normalized_result.parent_evidence_id` from the summary into the
|
||||
`source.evidence_id` field of the `managed-members` request above, then save that
|
||||
@@ -268,12 +264,30 @@ is retained in the classification evidence list.
|
||||
|
||||
### Resource admission
|
||||
|
||||
The static provider admits regular input files up to 128 MiB before retaining
|
||||
their bytes. Reads remain bounded if a file grows after admission. Metadata,
|
||||
CIL decoding, and projected inspection records have a separate conservative
|
||||
64 MiB representation budget; shared heap strings are cached, but repeated
|
||||
output occurrences still consume that budget. These are inspection resource
|
||||
policies, not PE format limits or a hard bound on total V8 heap use.
|
||||
The static provider defaults to a 128 MiB eagerly retained PE snapshot and a
|
||||
separate conservative 64 MiB budget for metadata, CIL decoding and projected
|
||||
inspection records. All three static inspection tools accept
|
||||
`max_snapshot_bytes` and `max_metadata_representation_bytes` as positive safe
|
||||
integers in bytes. CLI inspection and path comparison expose
|
||||
`--max-snapshot-bytes` and `--max-metadata-representation-bytes`. An omitted
|
||||
value keeps its default; explicit values apply to that call without a restart.
|
||||
|
||||
Snapshot refusal names its selected byte budget and tells the caller to raise
|
||||
it for the same complete file. Representation exhaustion retains partial or
|
||||
unavailable coverage and names the selected budget in its `resource-limit`
|
||||
issue; raise that budget on the next inspection, or select fewer `type_names`
|
||||
for members. For example:
|
||||
|
||||
```bash
|
||||
rea inspect-managed-members /absolute/path/Assembly.dll --max-snapshot-bytes 268435456 --max-metadata-representation-bytes 134217728
|
||||
```
|
||||
|
||||
Reads remain bounded if a file grows after admission. A cached snapshot is
|
||||
rechecked against the current call's snapshot allowance and on-disk digest.
|
||||
Shared heap strings are cached, but repeated output occurrences still consume
|
||||
the representation budget. These are per-call resource policies, not PE format
|
||||
limits or a bound on total V8 heap use. Raising one does not raise the other,
|
||||
transport limits or available host memory.
|
||||
|
||||
Path-based member comparison uses the same per-input snapshot policy and
|
||||
inspects its two selected paths sequentially, retaining each inspection rather
|
||||
@@ -330,7 +344,7 @@ original `resource-limit` coordinate. It does not return partially admitted
|
||||
member collections: empty fields, methods, references and edges are unexamined,
|
||||
not proof of absence; exported types, user strings and signature-resolution
|
||||
attestation remain null. Summary and retained pages keep this partial coverage.
|
||||
The capacity limit is unchanged. If metadata or the type inventory itself cannot
|
||||
The selected capacity applies to the metadata and member projection together. If metadata or the type inventory itself cannot
|
||||
be admitted, the result remains unavailable.
|
||||
|
||||
Use the returned `types[].full_name` values to select declaring types before
|
||||
@@ -654,7 +668,8 @@ unchanged signature. Comparison retains exact byte-based pairs for malformed
|
||||
signatures, including empty, truncated, or invalid headers, but reports them as
|
||||
unknown with a `signature-malformed` limitation when no change is observed.
|
||||
This applies to historical Evidence without signature-resolution attestation as
|
||||
well. Runtime-provided methods are counted separately in
|
||||
well. Runtime-provided methods have the Runtime code type or the InternalCall
|
||||
implementation flag, as core library FCalls do. They are counted separately in
|
||||
`native_implementations.runtime_provided`; they have no file-backed native body
|
||||
for this workflow to map and do not increase `native_body_unresolved`. Historical
|
||||
verification Evidence without this separate count leaves it unknown (`null`).
|
||||
|
||||
@@ -120,7 +120,13 @@ CLI output are unchanged.
|
||||
|
||||
Complete results have a 32 MiB input, 64 MiB reply, 1 MiB combined diagnostics
|
||||
and 30-second owned command deadline. `REA_PWNTOOLS_MAX_INPUT_BYTES` raises the
|
||||
input bound alone, up to 1 GiB; the reply and deadline bounds are unchanged. The
|
||||
launch input default alone, up to 1 GiB. Per-call `producer_limits` selects
|
||||
`input_bytes`, `output_bytes`, `diagnostic_bytes`, `address_space_bytes`,
|
||||
`file_bytes`, and `cpu_seconds`; positive safe integers apply on the next call
|
||||
without restart. `input_bytes` overrides the launch default. File admission
|
||||
follows selected `output_bytes` unless `file_bytes` is explicit. The separate
|
||||
`pwntools_timeout_ms` controls each command wall deadline. On CLI pass
|
||||
`--producer-limits '{"cpu_seconds":60,"output_bytes":134217728}'`. The
|
||||
reply budget applies to the decoder record; the CLI/MCP Evidence envelope adds
|
||||
copies and encoding overhead. The
|
||||
pinned MCP SDK defaults to a 10 MiB receive buffer. Large complete results need
|
||||
@@ -128,15 +134,16 @@ a caller-configured `StdioClientTransport({ maxBufferSize: ... })` and a matchin
|
||||
server `REA_MCP_MAX_RESPONSE_BYTES`. See [MCP delivery budgets](../../reference/mcp-contracts.md#tool-results).
|
||||
These settings affect delivery, not decoder coverage or limits. The large
|
||||
extended-index verification uses 256 MiB and an explicit five-minute request
|
||||
timeout in its separate opt-in MCP lane. REA does not silently truncate the result. Python lowers resource soft limits to at most 3 GiB virtual address space,
|
||||
30 CPU seconds and 64 MiB file output. Inherited tighter soft/hard limits are
|
||||
timeout in its separate opt-in MCP lane. REA does not silently truncate the result. Python lowers resource soft limits to the selected policy: defaults are 3 GiB
|
||||
virtual address space, 30 CPU seconds and 64 MiB file output. Inherited tighter soft/hard limits are
|
||||
retained, and the effective values are returned in the result limitations. Virtual address space is not RSS;
|
||||
Unicorn needs a large virtual map. Limits fail with no partial success, and
|
||||
owned process/root cleanup completes independently of cancellation.
|
||||
|
||||
Core files, GDB session/state/control, optional pwndbg enrichment and instruction
|
||||
inspection are separate increments tracked by #969. This increment makes no
|
||||
real support claim for those features or other operating systems/architectures.
|
||||
For core files and optional pwndbg mapping context, use the
|
||||
[recorded-crash workflow](recorded-crashes.md). The binary-layout operations
|
||||
described here do not provide debugger session state or control, or establish
|
||||
support for other operating systems/architectures.
|
||||
|
||||
Typed decoder failures retain bounded `captured_output` (stdout, stderr and an
|
||||
explicit truncation flag) alongside the original failure category and reason.
|
||||
@@ -272,6 +279,12 @@ 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.
|
||||
|
||||
|
||||
@@ -0,0 +1,177 @@
|
||||
# ELF unwind function ranges
|
||||
|
||||
`inspect_elf_unwind_ranges` / `inspect-elf-unwind-ranges` reads `.eh_frame`
|
||||
and `.eh_frame_hdr` from one selected local ELF32/ELF64 image and lists the
|
||||
function ranges those tables name. It reads the file without executing it and
|
||||
does not require a disassembler.
|
||||
|
||||
```bash
|
||||
rea inspect-elf-unwind-ranges /absolute/path/to/program --json
|
||||
```
|
||||
|
||||
The CLI resolves relative paths against the caller's working directory. MCP
|
||||
requires an absolute filesystem path and preserves that exact selection:
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "inspect_elf_unwind_ranges",
|
||||
"arguments": { "path": "/artifacts/program" }
|
||||
}
|
||||
```
|
||||
|
||||
Pass `--offset` and `--limit` (MCP `offset` and `limit`) to page the ranges.
|
||||
The default page starts at 0 and returns at most 256 ranges.
|
||||
|
||||
## Observations
|
||||
|
||||
The inline Evidence result contains the artifact path, SHA-256, and byte
|
||||
length, plus ELF class, byte order, machine, and object type.
|
||||
|
||||
`eh_frame.status` is `present`, `absent`, `incomplete`, or `unknown`. A
|
||||
present table names its source: `section` when section headers name
|
||||
`.eh_frame`, or `program` when section headers are missing and
|
||||
`PT_GNU_EH_FRAME` supplies the bytes. `location` is the file range that was
|
||||
examined. A `.eh_frame` section that is `SHT_NOBITS` or lies outside the file
|
||||
is `incomplete` with a null `location`. One that runs past the end of the
|
||||
file is `incomplete`, `location` is clamped to its in-file bytes, and the
|
||||
records in those bytes are still decoded. Only the first `.eh_frame` and
|
||||
`.eh_frame_hdr` section is decoded, and only the first `PT_GNU_EH_FRAME`
|
||||
program header. A duplicate section, or a duplicate `PT_GNU_EH_FRAME` when no
|
||||
`.eh_frame_hdr` section supplies the header, keeps `coverage.status` at
|
||||
`incomplete`.
|
||||
|
||||
`eh_frame_hdr` reports version, the three pointer encodings, the `.eh_frame`
|
||||
pointer, the declared FDE count, and how many binary-search table entries
|
||||
were decoded. A header section that is `SHT_NOBITS` or extends past the end of
|
||||
the file is `incomplete` with a null `location` and is not decoded.
|
||||
`coverage.eh_frame_hdr_agreement` is `agree` when the table has exactly one
|
||||
row per decoded FDE, the sorted starts match including repeats, and each row
|
||||
points at a distinct FDE with that start. It is `disagree` otherwise, and
|
||||
`unavailable` when the header is absent, unknown, or incomplete. Disagreement
|
||||
is a limitation. The decoded FDEs stay in the result. The search table is
|
||||
read for at most `max_ranges` rows, and for no more rows than the header bytes
|
||||
can hold. When the declared FDE count is larger than either bound, the header
|
||||
is `incomplete`, `table_entries` counts only the rows read, the comparison is
|
||||
`unavailable`, and a limitation names the cap. A declared count that does not fit
|
||||
in 32 bits is not decoded: `fde_count` is null, the header is `incomplete`,
|
||||
and the decoded FDEs stay in the result. A header whose FDE count encoding is
|
||||
`DW_EH_PE_omit` (`0xff`), as GNU ld writes when it cannot build the search
|
||||
table, is `present` with a null `fde_count`, no table rows, and comparison
|
||||
`unavailable`; it does not make coverage incomplete. A header that declares
|
||||
an FDE count but writes `DW_EH_PE_omit` as its table encoding is `present`
|
||||
with that count, no table rows, and comparison `unavailable`, and also keeps
|
||||
coverage complete. A non-zero FDE count under an indirect encoding is the
|
||||
address of a slot that is not followed, so `fde_count` is null, the header is
|
||||
`incomplete`, and the table is not read.
|
||||
|
||||
When section headers name both `.eh_frame_hdr` and `PT_GNU_EH_FRAME`, the
|
||||
section is decoded. A limitation names the segment as ignored only when it
|
||||
declares different bytes than the section. When no `.eh_frame_hdr` section is
|
||||
named, the header is read from `PT_GNU_EH_FRAME` even if a `.eh_frame`
|
||||
section is present.
|
||||
|
||||
A record whose length word is `0xffffffff` uses the 64-bit extended length
|
||||
that follows it. In `.eh_frame` the CIE ID and CIE pointer after that length
|
||||
stay 4 bytes wide.
|
||||
|
||||
`DW_EH_PE_datarel` fields in `.eh_frame_hdr` are relative to the header
|
||||
address. In `.eh_frame` they are relative to the GOT: `DT_PLTGOT` when the
|
||||
dynamic table names it, otherwise the `.got.plt` or `.got` section address.
|
||||
A limitation names the base that was used. When no GOT base is declared,
|
||||
those values are unresolved: the affected record is not reported and
|
||||
`coverage.status` is `incomplete`.
|
||||
|
||||
`debug_frame.status` is `present`, `absent`, `incomplete`, or `unknown`. It
|
||||
is `unknown` when the image has no section headers or unreadable section
|
||||
names. It is `incomplete`, with a null `location` and `coverage.status` at
|
||||
`incomplete`, when the section is `SHT_NOBITS` or its bytes are not all in
|
||||
the file. The `.eh_frame` results stay in the report. This command does not
|
||||
decode `.debug_frame`.
|
||||
|
||||
`cies` lists the CIEs that the returned page's ranges name, in index order,
|
||||
so its length never exceeds the page size. Each `cie_index` in `ranges`
|
||||
matches the `index` of one entry in `cies`. `coverage.total_cies` counts every
|
||||
decoded CIE, including CIEs no FDE on this page uses. Each CIE reports
|
||||
version 1 or 3, augmentation, code and data alignment,
|
||||
return-address register, pointer encoding, LSDA encoding, personality address
|
||||
when the augmentation carries one, signal-frame and B-key flags, and the byte
|
||||
length of the CFA program. CFA instructions are counted and not evaluated.
|
||||
A CIE whose augmentation has a letter other than `z`, `L`, `P`, `R`, `S`, or
|
||||
`B` is not decoded: the encodings of later letters cannot be trusted, so its
|
||||
FDEs are not decoded either. A limitation counts those FDEs and coverage is
|
||||
`incomplete`.
|
||||
|
||||
`ranges` is one page of FDEs. Each range has `start`, `end`, decimal `size`,
|
||||
the containing `SHF_ALLOC` section, an exact symbol name when a symbol starts
|
||||
at that address, the CIE index, LSDA, and personality. A function symbol is
|
||||
preferred, then an `STT_GNU_IFUNC` symbol, then an untyped one. An IFUNC name
|
||||
is the resolver that starts at that address, not the implementation it
|
||||
selects at run time, and a limitation says so. Symbol names, section names,
|
||||
and augmentation strings are target-derived and untrusted. Indirect EH
|
||||
pointers are not dereferenced. An FDE whose initial location is indirect names
|
||||
a pointer slot, not its function, so it is not reported as a range; a
|
||||
limitation counts those FDEs and coverage is `incomplete`. An indirect
|
||||
`eh_frame_ptr` does not locate `.eh_frame`, and the header is `incomplete`.
|
||||
A search table with an indirect encoding is not read: the header is
|
||||
`incomplete`, the comparison is `unavailable`, and the table does not bound a
|
||||
header-located `.eh_frame`.
|
||||
|
||||
An encoded pointer whose stored value is zero is a null pointer, as libgcc
|
||||
reads it: no PC-relative, text, data, or function base is added and an
|
||||
indirect pointer is not followed. A resolved address, and an FDE `end`,
|
||||
wraps at the ELF address width (32 or 64 bits), as libgcc's pointer
|
||||
arithmetic does. A zero LSDA pointer is reported as a null
|
||||
`lsda`, even when the CIE declares an LSDA encoding. An FDE whose initial
|
||||
location is zero marks a function the linker discarded. It is not reported
|
||||
as a range, `examined_records` still counts it, and a limitation counts how
|
||||
many were skipped. In a relocatable object an unrelocated initial location
|
||||
is also zero, so those FDEs are skipped too.
|
||||
|
||||
`page` reports `offset`, `limit`, `returned`, `total`, and `next_offset`.
|
||||
`next_offset` is null when the page reaches the end of the decoded list.
|
||||
`coverage` counts every decoded range, every decoded CIE, how many ranges
|
||||
match a symbol, and how many do not. `examined_records` counts CIE and FDE records visited, including
|
||||
records that could not be decoded.
|
||||
|
||||
A missing `.eh_frame` section and a missing `PT_GNU_EH_FRAME` segment are
|
||||
observed absence of those declarations. That absence is not proof the image
|
||||
has no functions. Program headers come from the shared ELF section
|
||||
directory, which rejects an image whose program-header table cannot be read,
|
||||
so a missing `PT_GNU_EH_FRAME` is always observed absence. When section
|
||||
headers are missing too, section names are unknown, so a missing header is
|
||||
`unknown` rather than `absent`.
|
||||
|
||||
A `.eh_frame` located only through the `.eh_frame_hdr` `eh_frame_ptr` has no
|
||||
section size, so it is read up to the end of its `PT_LOAD` segment. Other
|
||||
data, such as `.gcc_except_table`, can follow it there. When the search table
|
||||
was decoded, the scan stops after the last FDE the table names, as libgcc's
|
||||
`PT_GNU_EH_FRAME` lookup only binary-searches that table. Later bytes are not
|
||||
decoded and a limitation says so. Without a usable table, the scan stops at
|
||||
the first record that fails to decode, as libgcc's linear FDE search does,
|
||||
and `coverage.status` is `incomplete`. A CIE with an unrecognized
|
||||
augmentation letter, or an FDE that uses one, also stops that scan. Reaching the end of the segment with
|
||||
no terminator also keeps coverage `incomplete`, because the table's extent is
|
||||
then unknown.
|
||||
|
||||
Addresses map to file offsets through `SHF_ALLOC` sections, then `PT_LOAD`
|
||||
segments. A section without `SHF_ALLOC`, such as `.comment` or `.debug_*`,
|
||||
is not loaded, so its `sh_addr` is never used for translation and it is never
|
||||
reported as the section containing a range. A record that ends past the table, or non-zero bytes after
|
||||
the terminator, keeps `coverage.status` at `incomplete`. Relocatable objects
|
||||
stay incomplete because relocations are not applied.
|
||||
|
||||
## Limits and failures
|
||||
|
||||
The selected file is limited to 64 MiB by default (512 MiB maximum).
|
||||
`max_ranges` defaults to 8192 and caps at 65536. That ceiling applies
|
||||
separately to CIE records and to FDEs. Exceeding either budget fails without
|
||||
partial success. One page returns at most 4096 ranges. Symbol lookup stops
|
||||
after 65536 entries across `.symtab` and `.dynsym` combined. Reaching that
|
||||
cap keeps `coverage.status` at `incomplete`. Only symbols at decoded FDE
|
||||
starts are kept, and a name is decoded only for a returned range. The names
|
||||
on one page share a fixed 16 MiB text allowance; a page that exceeds it fails
|
||||
with a resource error whose recovery is a smaller `limit`, because
|
||||
`max_ranges` and `max_file_bytes` do not raise it.
|
||||
|
||||
Malformed ELF headers fail without partial success. This workflow does not
|
||||
execute the image, evaluate CFA programs, or follow indirect pointers.
|
||||
@@ -116,18 +116,22 @@ The result's limitations state this explicitly. A module-mode build with a main
|
||||
module record and no dependency records has an observed empty dependency list.
|
||||
|
||||
When `include_string_literals: true` (CLI `--include-string-literals`, optional
|
||||
`max_string_literals` / `--max-string-literals`, default `2000`, maximum `10000`)
|
||||
`max_string_literals` / `--max-string-literals`, default `2000`)
|
||||
is selected, `string_literals` reports `evidence_kind: "inferred"` alongside
|
||||
deduplicated printable UTF-8 literals referenced by word-aligned two-word
|
||||
`(ptr, len)` string headers in non-executable initialized data. Because Go packs
|
||||
read-only string data contiguously without NUL terminators, slicing by `(ptr, len)`
|
||||
recovers exact literal boundaries instead of concatenated C-string runs. Each
|
||||
target slice (`1`–`4096` bytes) must stay within a single read-only mapped
|
||||
target slice (default `1`–`4096` bytes) must stay within a single read-only mapped
|
||||
section or segment, decode as printable UTF-8 (`\t`, `\n`, `\r`, joiners
|
||||
`U+200C` / `U+200D` and printable Unicode scalar values, excluding control and
|
||||
other format characters), and fit within
|
||||
a 64 MiB header-scan budget and 512 KiB aggregate string budget
|
||||
(`truncated: true` when capped). Compiler-inlined or
|
||||
a default 64 MiB header-scan budget and 512 KiB aggregate string budget
|
||||
(`truncated: true` when capped). Select `max_string_literal_bytes`,
|
||||
`max_string_bytes`, `max_string_header_scan_bytes`, or `max_string_candidates`
|
||||
to change these independent budgets. Their CLI flags use hyphens, for example
|
||||
`--max-string-literal-bytes 16384`. `limits_reached` names exhausted controls;
|
||||
increase those controls for a new inspection of the same complete artifact. Compiler-inlined or
|
||||
stack-constructed strings without static headers, unapplied relocation addends
|
||||
and Mach-O `LC_DYLD_CHAINED_FIXUPS` pointer encodings are noted in `limitations`.
|
||||
|
||||
@@ -201,23 +205,39 @@ host permission denial, changed artifacts and cancellation retain distinct
|
||||
errors. The selected file is never modified; this inspection creates no
|
||||
temporary files, starts no subprocesses and accesses no network endpoint.
|
||||
|
||||
An input above 256 MiB returns `resource_constraint` with resource `file-size`
|
||||
and `reported_limits.maximum_input_bytes`. Select a suitable input within that
|
||||
fixed allowance; changing an output-write or transport budget does not admit it.
|
||||
The existing default resource budgets are now explicit per-call controls:
|
||||
|
||||
Resource guards bound the selected file and cumulative header searches to 256 MiB
|
||||
each, aggregate embedded string contents to 1 MiB (varint length prefixes are
|
||||
framing and do not count toward this allowance), structural table decoding to
|
||||
16 MiB and the complete normalized metadata report to 8 MiB. Inline strings must
|
||||
also fit within their actual mapped source range. Identical search spans with
|
||||
the same virtual alignment are searched once; partially overlapping spans
|
||||
consume the cumulative search budget
|
||||
and fail with a CPU resource constraint when it is exhausted. Oversized results
|
||||
fail without partial success. MCP also applies
|
||||
its [response transport budget](../../reference/mcp-contracts.md), which counts both text and
|
||||
structured content; a report within the metadata limit can still require export
|
||||
from retained Evidence. These limits are not operating-system memory or CPU
|
||||
isolation.
|
||||
| Parameter | Default | What it admits |
|
||||
| ------------------------------ | ----------- | ------------------------------------------------------------- |
|
||||
| `max_input_bytes` | 256 MiB | Complete stable input file |
|
||||
| `max_report_bytes` | 8 MiB | Complete normalized metadata representation |
|
||||
| `max_build_info_bytes` | 1 MiB | Aggregate embedded string contents, excluding length prefixes |
|
||||
| `max_header_search_bytes` | 256 MiB | Cumulative build-info search work |
|
||||
| `max_string_literals` | 2,000 | Returned inferred string rows |
|
||||
| `max_string_literal_bytes` | 4,096 bytes | Each inferred string candidate |
|
||||
| `max_string_bytes` | 512 KiB | Aggregate returned inferred text |
|
||||
| `max_string_header_scan_bytes` | 64 MiB | String-header and candidate-byte examination |
|
||||
| `max_string_candidates` | 100,000 | Distinct inferred candidates retained before projection |
|
||||
|
||||
Every value is a positive safe integer. Input and string byte maxima follow the
|
||||
runtime Buffer/string representation, with base64 expansion accounted for in
|
||||
build-info admission; schemas advertise their exact maxima. CLI options use the same names with
|
||||
hyphens, such as `--max-build-info-bytes 2097152`. Inferred-string controls
|
||||
require `include_string_literals: true`. Omitted controls keep the defaults
|
||||
and stay omitted in request Evidence. Error recovery names the exhausted
|
||||
parameter and effective bytes; increase that parameter on the next call,
|
||||
without restarting REA. The original complete artifact and its identity are
|
||||
preserved. An unchanged retry cannot increase a deterministic allowance.
|
||||
|
||||
The shared native container reader separately bounds structural table decoding
|
||||
to 16 MiB. None of these Go controls changes that boundary. Inline strings must
|
||||
also fit their actual mapped source range. Identical search spans with the same
|
||||
virtual alignment are searched once; partially overlapping spans consume the
|
||||
cumulative search budget. Oversized complete reports fail without partial
|
||||
success and without allocating the full JSON serialization. MCP's separate
|
||||
[response transport budget](../../reference/mcp-contracts.md) can still require
|
||||
export or paging of successfully retained Evidence. These controls do not
|
||||
establish operating-system memory or CPU isolation.
|
||||
|
||||
Embedded metadata is evidence of file content. It does not authenticate a
|
||||
compiler, dependency, commit or supply chain, and it does not establish runtime
|
||||
|
||||
@@ -0,0 +1,151 @@
|
||||
# Linux kernel build config
|
||||
|
||||
`inspect_kernel_build_config` / `inspect-kernel-build-config` reads the
|
||||
`Linux version` banner and the embedded `.config` from one selected local
|
||||
kernel image without executing or booting it. Accepted inputs are a `vmlinux`
|
||||
ELF, a raw arm64 `Image`, an x86 `bzImage` or `zImage` whose payload is gzip,
|
||||
and a `configs.ko` module. It does not require a Linux host,
|
||||
`extract-ikconfig`, or `/proc/config.gz`.
|
||||
|
||||
```bash
|
||||
rea inspect-kernel-build-config /absolute/path/to/vmlinux --json
|
||||
rea inspect-kernel-build-config /absolute/path/to/bzImage --name CONFIG_SECURITY_SELINUX --json
|
||||
```
|
||||
|
||||
The CLI resolves relative paths against the caller's working directory. MCP
|
||||
requires an absolute filesystem path and preserves that exact selection:
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "inspect_kernel_build_config",
|
||||
"arguments": { "path": "/artifacts/vmlinux", "name": "CONFIG_MODULE_SIG" }
|
||||
}
|
||||
```
|
||||
|
||||
## Observations
|
||||
|
||||
The inline Evidence result contains the artifact path, SHA-256, and byte
|
||||
length. `format` is `elf` when the file starts with the ELF magic and `file`
|
||||
otherwise.
|
||||
|
||||
`banner` is the first printable string that starts with `Linux version `
|
||||
followed by a version token beginning with a digit and ends at a NUL or
|
||||
newline within 512 bytes. `version` is that token. `builder` is the first
|
||||
parenthesized group (`user@host`). `compiler` is the second group up to the
|
||||
last `) #`, so nested parentheses in compiler strings are kept. The banner is
|
||||
`absent` when no such string was found in the searched bytes and `unknown`
|
||||
when the bytes were not searched.
|
||||
|
||||
`config` is `present` only when all of the following hold:
|
||||
|
||||
- `IKCFG_ST` is immediately followed by a gzip member (`1f 8b 08`).
|
||||
- The member inflates within `max_config_bytes` and its CRC-32 and ISIZE
|
||||
trailer match.
|
||||
- The member trailer ends exactly at the first `IKCFG_ED` after the gzip
|
||||
header. Inflation reads only the bytes up to that marker.
|
||||
- Every non-blank line of the inflated text is a `#` comment,
|
||||
`# CONFIG_X is not set`, or `CONFIG_X=value`, and the text is valid UTF-8
|
||||
with no control bytes other than tab, CR, and LF.
|
||||
|
||||
An `IKCFG_ST` string that is not followed by gzip magic, or whose complete
|
||||
member is not followed by `IKCFG_ED`, is skipped, so an ordinary string is never
|
||||
reported as a config. When `IKCFG_ST`, gzip magic, and a later `IKCFG_ED` frame
|
||||
a member that does not decode, a deflate stream cut off by that marker, a
|
||||
member that fails its CRC-32 or ISIZE check, or text that fails the grammar,
|
||||
the config is `malformed` with coverage
|
||||
`incomplete`, and `marker`, `gzip`, and `end_marker` locate the blob. A
|
||||
malformed blob is never reported as an absent config. A valid config later in
|
||||
the searched bytes still wins. `marker`, `gzip`, and `end_marker` give
|
||||
the three ranges. `sha256` hashes the inflated text. `option_count` counts
|
||||
every `CONFIG_*` line. `matched_count` counts the options that match the
|
||||
optional exact `name` filter, and `entries` is the `offset`/`limit` page of
|
||||
those matches in file order.
|
||||
|
||||
Each entry has a `name`, a `kind`, and a `value`:
|
||||
|
||||
| `kind` | Source line | `value` |
|
||||
| --------- | -------------------------- | ------------------------- |
|
||||
| `y`, `m` | `CONFIG_X=y`, `CONFIG_X=m` | `y` or `m` |
|
||||
| `number` | decimal or `0x` hex | the text as written |
|
||||
| `string` | `CONFIG_X="..."` | decoded text (`\"`, `\\`) |
|
||||
| `not_set` | `# CONFIG_X is not set` | `null` |
|
||||
|
||||
Banner text and configuration values are target-derived and untrusted.
|
||||
|
||||
## bzImage payloads
|
||||
|
||||
A file with `HdrS` at offset `0x202` is an x86 setup header. From boot
|
||||
protocol 2.08, `payload_offset` and `payload_length` locate the compressed
|
||||
kernel after the `(setup_sects + 1) * 512` setup code. `payload` reports the
|
||||
container, codec, file range, and inflated length. A gzip payload is inflated
|
||||
within `max_payload_bytes` and the inflated bytes are searched. Locations in
|
||||
those bytes have `space: "inflated_payload"` and are offsets in the inflated
|
||||
payload, not file offsets. Only the leading gzip member is inflated, and its
|
||||
own ISIZE trailer gives the inflated length. Kbuild appends a separate 4-byte
|
||||
size only for the non-gzip codecs. Any bytes after the gzip member inside the
|
||||
payload are not read.
|
||||
|
||||
xz, lz4, lzma, zstd, bzip2, and lzo payloads are `unsupported`. The result
|
||||
names the codec and `external_decompression` as the next probe. This is an
|
||||
external step, not a REA operation: decompress the payload with the matching
|
||||
utility into a separate file, then call `inspect_kernel_build_config` on that
|
||||
file. A file that is itself a compressed stream, including a whole-file gzip
|
||||
such as `Image.gz`, is reported as `unsupported` with its codec and is not
|
||||
inflated. Only a gzip payload inside a bzImage is inflated.
|
||||
|
||||
## Limits and failures
|
||||
|
||||
The selected file is limited to 64 MiB by default (512 MiB maximum). An IKCFG
|
||||
member may inflate to 4 MiB by default (32 MiB maximum) and a bzImage payload
|
||||
to 128 MiB by default (512 MiB maximum). At most 16384 `CONFIG_*` options are
|
||||
examined by default (65536 maximum). A page holds 256 entries by default
|
||||
(4096 maximum). Exceeding any budget fails with no partial success and names
|
||||
the option to raise. An IKCFG member past `max_config_bytes` fails that way only
|
||||
when no later candidate is accepted, so an oversized decoy cannot hide a valid
|
||||
config.
|
||||
|
||||
One search inflates at most 16 `IKCFG_ST` gzip candidates and at most four
|
||||
times `max_config_bytes` of output across them. A candidate whose stream fails
|
||||
partway through is charged its full per-candidate allowance, since its partial
|
||||
output is not measured. When that search budget runs
|
||||
out before a config is accepted, the config is `incomplete` with reason
|
||||
`config_search_exhausted` instead of failing or reporting an absent config.
|
||||
Inflation runs off the event loop. Every scan, including marker
|
||||
searches that find nothing, config text checks, validation of one long value,
|
||||
and hashing, yields to it at least once
|
||||
per MiB, so a cancellation that arrives while the image is being parsed is honored
|
||||
at the next check. One inflate call runs to its output bound once started.
|
||||
|
||||
Results that could not search or read the kernel bytes stay `incomplete`,
|
||||
`malformed`, or `unsupported` and are never
|
||||
reported as an absent config:
|
||||
|
||||
| `config.reason` | Meaning |
|
||||
| ---------------------------------- | ---------------------------------------------------------------------------- |
|
||||
| `config_gzip_invalid` | a framed `IKCFG_ST` gzip member does not decode or fails its CRC-32 or ISIZE |
|
||||
| `config_text_invalid` | a framed `IKCFG_ST` gzip member is not `.config` text |
|
||||
| `config_gzip_truncated` | an `IKCFG_ST` gzip member runs past the searched bytes |
|
||||
| `config_search_exhausted` | decoy candidates used up the config search budget |
|
||||
| `payload_truncated` | the declared bzImage payload or its gzip member ends early |
|
||||
| `payload_gzip_invalid` | the bzImage gzip payload fails to inflate or its trailer |
|
||||
| `payload_codec_unsupported` | a compressed payload or whole-file stream was not inflated |
|
||||
| `unrecognized_payload_codec` | the bzImage payload starts with no known codec magic |
|
||||
| `setup_header_payload_unavailable` | the setup header predates 2.08 or has no payload length |
|
||||
|
||||
A kernel built without `CONFIG_IKCONFIG` carries no embedded config, so an
|
||||
`absent` config describes only the bytes that were searched. A kernel built
|
||||
with `CONFIG_IKCONFIG=m` keeps the config in `configs.ko`; inspect that module
|
||||
instead of the image. This workflow does not execute the image, compare the
|
||||
config with a source tree, or evaluate Kconfig dependencies.
|
||||
|
||||
## Format references
|
||||
|
||||
The markers follow Linux v6.12's
|
||||
[`kernel/configs.c`](https://github.com/torvalds/linux/blob/v6.12/kernel/configs.c)
|
||||
and
|
||||
[`scripts/extract-ikconfig`](https://github.com/torvalds/linux/blob/v6.12/scripts/extract-ikconfig).
|
||||
The setup header fields follow the
|
||||
[x86 boot protocol](https://docs.kernel.org/arch/x86/boot.html). The banner
|
||||
format follows
|
||||
[`init/version-timestamp.c`](https://github.com/torvalds/linux/blob/v6.12/init/version-timestamp.c).
|
||||
These references establish the decoded layout, not runtime behavior.
|
||||
@@ -0,0 +1,178 @@
|
||||
# ELF and Mach-O initializer functions
|
||||
|
||||
`inspect_native_initializers` / `inspect-native-initializers` lists the
|
||||
functions that one local ELF or Mach-O image declares to run before `main` and
|
||||
at exit. It reads the file without executing it and does not need a
|
||||
disassembler provider.
|
||||
|
||||
```bash
|
||||
rea inspect-native-initializers /absolute/path/to/program --json
|
||||
rea inspect-native-initializers ./Universal.app/Contents/MacOS/App --architecture arm64 --json
|
||||
```
|
||||
|
||||
The CLI resolves relative paths against the caller's working directory. MCP
|
||||
requires an absolute filesystem path:
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "inspect_native_initializers",
|
||||
"arguments": { "path": "/artifacts/program", "offset": 0, "limit": 64 }
|
||||
}
|
||||
```
|
||||
|
||||
A universal Mach-O requires `architecture` to select one slice. ELF files and
|
||||
thin Mach-O files do not take it.
|
||||
|
||||
## Sources
|
||||
|
||||
ELF entries are listed in this order:
|
||||
|
||||
| Kind | Source |
|
||||
| --------------- | ------------------------------------------------------------------------------------- |
|
||||
| `preinit_array` | `DT_PREINIT_ARRAY` / `DT_PREINIT_ARRAYSZ`, else `.preinit_array` |
|
||||
| `init` | `DT_INIT` |
|
||||
| `init_array` | `DT_INIT_ARRAY` / `DT_INIT_ARRAYSZ`, else `SHT_INIT_ARRAY` or `.init_array*` sections |
|
||||
| `ctors` | legacy `.ctors` and `.ctors.*` sections |
|
||||
| `fini` | `DT_FINI` |
|
||||
| `fini_array` | `DT_FINI_ARRAY` / `DT_FINI_ARRAYSZ`, else `SHT_FINI_ARRAY` or `.fini_array*` sections |
|
||||
| `dtors` | legacy `.dtors` and `.dtors.*` sections |
|
||||
|
||||
Section fallback applies when the dynamic tag is absent, as in static
|
||||
executables and relocatable objects. Mach-O entries come from sections typed
|
||||
`S_MOD_INIT_FUNC_POINTERS` (`mod_init`), `S_INIT_FUNC_OFFSETS`
|
||||
(`init_offsets`) and `S_MOD_TERM_FUNC_POINTERS` (`mod_term`).
|
||||
|
||||
## Entries
|
||||
|
||||
Each `entries[]` item reports:
|
||||
|
||||
- `slot_va`, `slot_file_offset`, `slot_bytes` and `slot_section`: where the
|
||||
pointer or offset is stored. For a universal Mach-O, file offsets are
|
||||
relative to the whole file, not the slice. For `init` and `fini` the slot is
|
||||
the `DT_INIT` / `DT_FINI` value field in the dynamic section. When that field
|
||||
is outside every load segment, `slot_va` and `slot_section` are null and a
|
||||
limitation says so.
|
||||
- `value_va`, `value_file_offset` and `section`: the resolved target address,
|
||||
its file offset and its containing section. These are null when the value
|
||||
was not established. A file offset is also null when load segments map the
|
||||
address ambiguously (overlapping segments with different file offsets, or
|
||||
file and zero-fill memory), and the report is then `incomplete`.
|
||||
- `symbol`: a defined symbol whose value equals the target exactly, or the
|
||||
import name of an unresolved symbolic relocation or chained bind.
|
||||
- `resolution`: how the value was obtained.
|
||||
|
||||
| Resolution | Meaning |
|
||||
| ------------------- | -------------------------------------------------------------------- |
|
||||
| `raw` | The stored word, used when no relocation or fixup covers it |
|
||||
| `relative_addend` | An `R_*_RELATIVE` relocation addend (RELA, or the REL in-place word) |
|
||||
| `relr` | A `DT_RELR` packed relative relocation |
|
||||
| `symbol_addend` | A section relocation against a defined symbol plus its addend |
|
||||
| `chained_fixup` | A Mach-O chained-fixup rebase target |
|
||||
| `dyld_info_rebase` | A Mach-O `LC_DYLD_INFO` rebase opcode target |
|
||||
| `offset_table` | A 32-bit `__init_offsets` value added to the image base |
|
||||
| `unresolved_import` | A relocation or bind against an undefined symbol |
|
||||
| `unresolved` | A slot whose value this inspection cannot establish |
|
||||
|
||||
A bound import name over the 1024-byte name budget is reported as no name and
|
||||
makes the report `incomplete` with a counted limitation.
|
||||
|
||||
Symbol and section names are untrusted file text and carry
|
||||
`trust: "observed-untrusted"`.
|
||||
|
||||
For PIE executables and shared objects the array slots are usually zero on
|
||||
disk. A slot is reported `unresolved`, never as its stored zero, when the
|
||||
dynamic relocation tables use an encoding this inspection does not decode
|
||||
(for example Android packed relocations or an unsupported machine). Relative
|
||||
relocations are decoded for x86-64, i386, AArch64 and 32-bit ARM. A slot is
|
||||
also `unresolved` when a dynamic relocation writes only part of it, starts
|
||||
inside it, or writes it more than once with different values.
|
||||
|
||||
Section `REL` / `RELA` tables are applied to slots that no dynamic relocation
|
||||
covers. When such a table is skipped for an unexpected entry size, cannot be
|
||||
read, or lies past the record budget, every slot it could reach that has no
|
||||
relocation found is `unresolved`, and a `.ctors` slot is not dropped as a
|
||||
sentinel. A section record that writes only part of a slot, starts inside it,
|
||||
or repeats it also leaves the slot `unresolved`. In a relocatable object a
|
||||
table reaches only the section named by its `sh_info`. In a linked image, a relocation section without `SHF_ALLOC`
|
||||
(such as one kept by `--emit-relocs`) was already applied by the static
|
||||
linker, so the slot's stored word is used rather than applying the record
|
||||
again.
|
||||
|
||||
An absolute relocation against an `STT_GNU_IFUNC` symbol is `unresolved`: the
|
||||
symbol value is the resolver, and the loader stores whatever the resolver
|
||||
returns.
|
||||
|
||||
On 32-bit ARM (ELF `EM_ARM` and Mach-O `CPU_TYPE_ARM`), bit 0 of a function
|
||||
pointer selects Thumb state. `value_va` keeps the pointer as stored, while
|
||||
`value_file_offset` and `section` describe the code address with that bit
|
||||
cleared. A Mach-O symbol is matched at either address.
|
||||
|
||||
In a relocatable object (`ET_REL`) every section starts at address 0. Slot
|
||||
and value addresses are offsets inside the named section, and a limitation
|
||||
says so.
|
||||
|
||||
Mach-O pointer slots are decoded through chained fixups or `LC_DYLD_INFO`
|
||||
opcodes for linked little-endian arm64 and x86-64 images. Other linked images,
|
||||
including 32-bit ones, have no fixup decoder here: their stored word is used
|
||||
only when the image declares no `LC_DYLD_INFO` bind stream, and a pointer slot
|
||||
is `unresolved` otherwise. Legacy external relocations (`LC_DYSYMTAB`
|
||||
`nextrel`) are not decoded, so they make an otherwise raw pointer slot
|
||||
`unresolved` in any image. In an object file (`MH_OBJECT`), each section's own
|
||||
relocation entries set the slot: a pointer-width `UNSIGNED` entry against a
|
||||
defined symbol gives `symbol_addend`, one against an undefined symbol gives
|
||||
`unresolved_import`, a section-ordinal entry keeps the stored address, and any
|
||||
other entry leaves the slot `unresolved`. An `arm64_32` image that declares a
|
||||
64-bit header is rejected as malformed, since its pointers are four bytes.
|
||||
|
||||
`.ctors` and `.dtors` values `0` and `-1` are list sentinels and are omitted.
|
||||
`-1` means all ones at the image's pointer width: `0xffffffff` in ELF32 and
|
||||
`0xffffffffffffffff` in ELF64. A 64-bit slot holding `0xffffffff` is listed.
|
||||
A stored zero in an initializer array is listed, so the array length stays
|
||||
visible.
|
||||
|
||||
## Paging and limits
|
||||
|
||||
`offset` and `limit` page the ordered list (default limit 64, maximum 4096).
|
||||
`coverage.examined_entries` counts every slot read, including omitted
|
||||
sentinels, and `total_entries` (the listed entries) is set when the inventory
|
||||
is complete. At most 65536 slots are examined; beyond that, or when relocation
|
||||
coverage is unknown, `status` and `coverage.status` are `incomplete`.
|
||||
|
||||
ELF symbol names come from at most 65536 symbols across all `SHT_SYMTAB` and
|
||||
`SHT_DYNSYM` tables together, and section `REL` / `RELA` relocations from at
|
||||
most 1048576 records across all relocation sections together. Mach-O symbol
|
||||
names come from at most 65536 symbols across all `LC_SYMTAB` commands
|
||||
together; a repeated `LC_SYMTAB` over the same ranges is ignored with a
|
||||
limitation. Reaching any of these budgets makes the report `incomplete` with a
|
||||
limitation.
|
||||
|
||||
A symbol name that cannot be read, because its string table is missing or its
|
||||
offset lies outside the table, is reported as no name and makes the report
|
||||
`incomplete` with a counted limitation. Name offset 0 is the empty name.
|
||||
|
||||
The dynamic relocation tables are read in steps that yield to other work and
|
||||
observe cancellation, so a large `DT_RELR` table does not block the server.
|
||||
|
||||
`limitations` lists the standing limitations, then at most 24 distinct
|
||||
observations from the image. Reasons a crafted table can repeat per row, such
|
||||
as symbol names over the 1024-byte budget or relocation sections with an
|
||||
unexpected entry size, are reported once with a count, and observations past
|
||||
the 24-note budget are counted in one closing line. The list never exceeds 40
|
||||
lines.
|
||||
|
||||
The selected file is limited to 64 MiB by default (`max_file_bytes`, 512 MiB
|
||||
maximum). Malformed headers, multiple `PT_DYNAMIC` segments and truncated
|
||||
dynamic sections fail without partial success.
|
||||
|
||||
This inspection does not prove that a listed address runs, and file order is
|
||||
not the runtime order: `DT_FINI` is listed before `fini_array`, while the
|
||||
dynamic linker runs `fini_array` first, and `.ctors` runs in reverse order. A
|
||||
missing tag or section is observed absence of that declaration, not proof that
|
||||
no code runs before `main`.
|
||||
|
||||
Legacy Mach-O bind lookup examines at most 4096 candidate runs per query and
|
||||
at most twice the file byte count across the decoded image's queries. These
|
||||
resource allowances bound sparse, overlapping run descriptions without expanding
|
||||
them into per-address objects. Exhaustion leaves pointer applicability unresolved
|
||||
and the report incomplete. Bind-stream parsing and initializer batches yield so
|
||||
other requests and cancellation can run.
|
||||
@@ -332,6 +332,10 @@ 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
|
||||
@@ -1131,6 +1135,9 @@ 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
|
||||
@@ -1240,7 +1247,7 @@ resource, REA releases that runtime and admits the next observation.
|
||||
Cancellation observed while output and Evidence are finalized returns partial
|
||||
cancellation Evidence, even if the target has already exited.
|
||||
|
||||
- the outcome, exit status and captured stdout/stderr (1 MiB kept per stream
|
||||
- the outcome, exit status and captured stdout/stderr (1 MiB by default kept per stream
|
||||
while excess bytes are drained and counted without growing capture files).
|
||||
Each stream reports `complete`; when draining could not finish, its byte
|
||||
count is an observed lower bound and truncation is explicit;
|
||||
@@ -1253,16 +1260,32 @@ cancellation Evidence, even if the target has already exited.
|
||||
code makes coverage partial;
|
||||
- limitations.
|
||||
|
||||
The bridge limits retained event JSON to 8 MiB and caller frames to 65,536
|
||||
across the run. It checks admission before retaining another complete event;
|
||||
The bridge defaults to 8 MiB retained event JSON and 65,536 caller frames
|
||||
across the run. Select `capture_limits` before launch to adjust `trace_bytes`,
|
||||
`trace_frames`, `breakpoint_location_bytes`, `other_stops`, `selector_bytes`,
|
||||
and `output_bytes`. Defaults are respectively 8388608, 65536, 8388608, 256,
|
||||
1024, and 1048576. Byte budgets accept positive safe integers up to the smaller of the running
|
||||
Node Buffer and single-string representation ceilings; counts are positive safe
|
||||
integers. These representability ceilings do not establish available memory or
|
||||
raise complete Evidence/transport admission. Omitted fields keep their defaults. The journal shares
|
||||
`trace_bytes`; completed and partial capture readers use the selected budgets.
|
||||
For example, `"capture_limits":{"trace_bytes":16777216,"output_bytes":2097152}`
|
||||
selects 16 MiB trace/journal and 2 MiB retained output per stream. These choices
|
||||
do not extend `duration_ms`, `max_events`, the outer client deadline or MCP
|
||||
receive allowance, and require no REA restart. A larger budget applies to a new
|
||||
authorized observation; it cannot recover facts omitted from an earlier run. It checks admission before retaining another complete event;
|
||||
`resource-limit` reports which observations could not be completed without
|
||||
silently changing the requested event or frame settings.
|
||||
Resolved breakpoint locations have a separate aggregate 8 MiB metadata budget.
|
||||
Resolved breakpoint locations have a separate aggregate metadata budget,
|
||||
default 8 MiB (`capture_limits.breakpoint_location_bytes`).
|
||||
If their details exceed it, `location_count` retains the full observed match
|
||||
count, coverage is partial, and `breakpoint_locations_truncated` is true. This
|
||||
post-run metadata limit does not imply that the target was killed.
|
||||
|
||||
Accepted entries and signal stops are also flushed to a bounded 8 MiB journal.
|
||||
Accepted entries and signal stops are also flushed to the bounded trace journal.
|
||||
When event admission stops, `coverage.capture_limit` identifies `trace_bytes`
|
||||
or `trace_frames` when the bridge supplied that fact; historical reports that
|
||||
lack it retain the combined limitation without guessing the exhausted resource.
|
||||
If cancellation, timeout, capture failure, or a later bridge error prevents a
|
||||
full result, the error retains this evidence in `details.partial_observation`
|
||||
with partial coverage. Available output prefixes remain inline; their byte
|
||||
|
||||
@@ -105,8 +105,14 @@ Initial Linux x64 limits: 32 MiB input, 64 MiB decoder reply, 1 MiB diagnostics
|
||||
stage, 30 seconds owned wall deadline per stage, 3 GiB address-space soft ceiling
|
||||
and 30 seconds CPU soft ceiling. `REA_PWNTOOLS_MAX_INPUT_BYTES` raises the input
|
||||
bound alone, up to 1 GiB, and returns `provider_unavailable` when it is not a
|
||||
decimal integer in range; the reply, diagnostic and deadline bounds stay fixed, so a
|
||||
large core that outruns them still fails explicitly instead of partially. Tighter
|
||||
decimal integer in range. Per-call `producer_limits` selects input/output/diagnostic,
|
||||
file/address-space bytes and CPU seconds; positive safe integers apply on the
|
||||
next call without restart. `input_bytes` overrides the launch default, and the
|
||||
file allowance follows selected output unless `file_bytes` is explicit. Both
|
||||
Python decoder and optional core-only debugger consume the same accepted policy.
|
||||
Use CLI `--producer-limits '{"cpu_seconds":60,"output_bytes":134217728}'`.
|
||||
`pwntools_timeout_ms` is the independent per-stage wall deadline. A large core
|
||||
that still exceeds the selected complete-reply allowance fails explicitly. Tighter
|
||||
inherited soft/hard limits are retained; hard limits are not raised. Complete
|
||||
oversized results fail explicitly. These process limits do not constitute a sandbox
|
||||
for caller-supplied engine code.
|
||||
|
||||
@@ -0,0 +1,94 @@
|
||||
# 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.
|
||||
@@ -26,6 +26,6 @@ Use `get_evidence_bundle` with `detail="summary"` and `filters={"evidence_id":"P
|
||||
|
||||
Failed startup cleanup retains acquired Frida handles, including a paused spawn that has not attached, for later cleanup retries. Its remote connection stays leased until session detach and target resume complete. CLI commands await provider cleanup before returning; MCP retains these resources for cleanup when its server closes. Server shutdown stops admitting new Frida operations and waits for admitted startup, discovery, and queued work before releasing their resources. A failed cleanup remains reported and can be retried by closing the server again, rather than treating an unregistered session as fully released.
|
||||
|
||||
Frida scripts execute inside the selected target with that process's memory, filesystem, and network authority. Local device lookup waits 1000 ms. This release has no runtime override for that lookup; another REA timeout does not raise it. Remote endpoints do not use that lookup. Message capture is bounded to 16 MiB and reports truncation. Metadata, type, and text field caps, and the JSON node cap, are also fixed. Evidence names a cap when that observation actually dropped data. This release has no runtime override for those capture caps. Script source is not stored in Evidence; its selected path and SHA-256 digest are. For a file, `source_sha256` identifies the original selected bytes. Invalid UTF-8 continues to use replacement decoding; Evidence then records that limitation and `raw_result.source_representation` with the encoding, decoding mode, and `loaded_source_sha256` of the UTF-8 string passed to Frida. Valid UTF-8 files and inline scripts do not need this additional representation fact. Evidence retains non-authentication target selection such as device or endpoint, mode, program or PID, and spawn arguments. Authentication values remain excluded. Results report the observed session and messages, while unsupported platform metadata remains unknown. A request cancelled before a Frida operation starts has no provider effects. If cancellation arrives during a native Frida call, REA waits for that call to return, then closes any session it created and returns the observed session as a partial observation. A cancelled script load on an existing session releases only its new script before queued operations can run; the session and previously loaded scripts remain available. If cancellation is observed when the native call returns, partial Evidence retains the source identity and captured messages even if that call rejects, including messages emitted during awaited cleanup. The caller's cancellation reason remains primary and a native rejection is retained as a sanitized diagnostic. A failure already observed before cleanup stays primary if cancellation arrives during cleanup. The cancellation cutoff is REA's observation of native completion, rather than a claim about unobservable native event order. `script_id` is REA's load-attempt identity. When creation rejects without returning a handle, `script_cleanup: "no_handle"` means REA acquired no handle to unload; it does not prove that the engine performed no work. Once the provider commits a successful load, later request cancellation does not unload that script; use `unload_frida_script` to release it. If script cleanup fails, the script remains owned and a paused target cannot resume until the pending instrumentation is released. Queued script loads, resumes, and unloads check cancellation before dispatching native effects. Cancellation Evidence separately reports whether a target resume was observed, whether instrumentation cleanup completed, and that final target liveness remains unknown. REA does not kill the target. Remote discovery retains its observations and reports a separate cleanup error if the temporary connection cannot be removed.
|
||||
Frida scripts execute inside the selected target with that process's memory, filesystem, and network authority. Local device lookup waits 1000 ms. This release has no runtime override for that lookup; another REA timeout does not raise it. Remote endpoints do not use that lookup. Message capture defaults to 16 MiB per session, 4 KiB per type, 32 KiB per error text field, 250,000 JSON nodes and depth 64. Select `capture_limits` on `start_frida_session` or `instrument_with_frida` before observing: `session_bytes`, `message_type_bytes`, `message_text_bytes`, `json_nodes`, and `json_depth`. Omitted fields keep these defaults. The session allowance includes JSON/base64 expansion, the envelope and metadata; a budget too small for one complete event retains no event. Depth is bounded to 992 levels, reserving eight enclosing message/status/Evidence containers within REA's shared JSON representation limit. These are retention budgets, independent of target authority, observation duration and MCP/client delivery limits. The selected policy is fixed for that session and returned as `capture_limits` in observations; no REA restart is required. The CLI exposes `--capture-session-bytes`, `--capture-message-type-bytes`, `--capture-message-text-bytes`, `--capture-json-nodes`, and `--capture-json-depth`. Evidence names the effective control when that observation dropped data. Changing a budget requires choosing a new session or experiment and cannot recover already discarded live observations. Script source is not stored in Evidence; its selected path and SHA-256 digest are. For a file, `source_sha256` identifies the original selected bytes. Invalid UTF-8 continues to use replacement decoding; Evidence then records that limitation and `raw_result.source_representation` with the encoding, decoding mode, and `loaded_source_sha256` of the UTF-8 string passed to Frida. Valid UTF-8 files and inline scripts do not need this additional representation fact. Evidence retains non-authentication target selection such as device or endpoint, mode, program or PID, and spawn arguments. Authentication values remain excluded. Results report the observed session and messages, while unsupported platform metadata remains unknown. A request cancelled before a Frida operation starts has no provider effects. If cancellation arrives during a native Frida call, REA waits for that call to return, then closes any session it created and returns the observed session as a partial observation. A cancelled script load on an existing session releases only its new script before queued operations can run; the session and previously loaded scripts remain available. If cancellation is observed when the native call returns, partial Evidence retains the source identity and captured messages even if that call rejects, including messages emitted during awaited cleanup. The caller's cancellation reason remains primary and a native rejection is retained as a sanitized diagnostic. A failure already observed before cleanup stays primary if cancellation arrives during cleanup. The cancellation cutoff is REA's observation of native completion, rather than a claim about unobservable native event order. `script_id` is REA's load-attempt identity. When creation rejects without returning a handle, `script_cleanup: "no_handle"` means REA acquired no handle to unload; it does not prove that the engine performed no work. Once the provider commits a successful load, later request cancellation does not unload that script; use `unload_frida_script` to release it. If script cleanup fails, the script remains owned and a paused target cannot resume until the pending instrumentation is released. Queued script loads, resumes, and unloads check cancellation before dispatching native effects. Cancellation Evidence separately reports whether a target resume was observed, whether instrumentation cleanup completed, and that final target liveness remains unknown. REA does not kill the target. Remote discovery retains its observations and reports a separate cleanup error if the temporary connection cannot be removed.
|
||||
|
||||
The [Frida Core API](https://frida.re/docs/frida-core-api/) documents device management, sessions, and script loading; the [JavaScript API](https://frida.re/docs/javascript-api/) documents target-side instrumentation. [Luma](https://luma.frida.re/) is Frida's standalone GUI; REA does not automate or control it. `npm run verify:frida` requires a Linux host with the optional Frida binding and uses a short-lived local Node.js fixture created by the verifier. Add `-- --address HOST:PORT --pid PID` to run the separate remote attach lane against a caller-selected target. Mock tests do not establish real device/server compatibility.
|
||||
@@ -35,11 +35,13 @@ different recovery: reinstall REA for the active platform, architecture, and
|
||||
Node.js version with optional dependencies enabled. Capability diagnostics
|
||||
distinguish this from the Windows capture-adapter limitation.
|
||||
|
||||
macOS also requires Apple's Swift compiler through `xcrun` for process
|
||||
ownership inspection. REA compiles its packaged, narrow process-inspection
|
||||
helper into a private temporary directory before a capture or owned provider
|
||||
process starts; the same prerequisite applies to owned provider-process
|
||||
supervision on macOS. REA removes that directory when it exits. REA does not
|
||||
macOS also requires REA's process-inspection helper for ownership inspection.
|
||||
REA reuses a verified cached helper or compiles one with the selected Swift
|
||||
toolchain before a capture or owned provider process starts; the same
|
||||
prerequisite applies to owned provider-process supervision on macOS.
|
||||
Per-process temporary helper directories are removed on exit; the verified
|
||||
cache persists. See [helper and toolchain configuration](#scenario-and-result-details)
|
||||
for cache validation and compiler overrides. REA does not
|
||||
install Xcode, Command Line Tools, or other software. Capability checks prepare
|
||||
this helper before reporting macOS capture as available.
|
||||
|
||||
@@ -97,6 +99,18 @@ 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.
|
||||
@@ -508,8 +522,9 @@ 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 timing data and take part in
|
||||
exit comparison like `settlement.elapsed_ms`.
|
||||
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.
|
||||
|
||||
Every capture requires `truncation_details`, with separate accounting for:
|
||||
|
||||
|
||||
@@ -103,10 +103,10 @@ failure; bounded post-run integrity checks finish before honoring a late abort.
|
||||
never passed to sigrok. Caller-supplied tools and their libraries/decoder modules
|
||||
are trusted, and hashes identify bytes rather than publisher authenticity.
|
||||
|
||||
The input copy is bounded at 32 MiB before reading, each command has a 30-second
|
||||
deadline, and combined stdout/stderr is bounded at 4 MiB during collection.
|
||||
By default, the input copy is bounded at 32 MiB before reading, each command has
|
||||
a 30-second deadline, and combined stdout/stderr is bounded at 4 MiB during collection.
|
||||
Oversized output fails rather than becoming truncated success. These limits do
|
||||
not form an OS sandbox. Before execution, `prlimit` enforces **1 GiB address
|
||||
not form an OS sandbox. Before execution, `prlimit` defaults to **1 GiB address
|
||||
space per process**, **64 MiB per file**, **30 CPU seconds** and no core dumps.
|
||||
Stricter inherited soft/hard limits are preserved; Evidence records the effective
|
||||
ceilings. Both limits are set before execution, so decoder allocations and compressed
|
||||
@@ -114,6 +114,23 @@ recording expansion cannot exceed the per-process address-space cap. These are
|
||||
not aggregate process-memory or filesystem quotas. The selected limiter is
|
||||
trusted and its path, digest and arguments are retained in Evidence.
|
||||
|
||||
Each capture/recording operation accepts `producer_limits` with positive safe
|
||||
integer overrides: `input_bytes`, `output_bytes`, `command_timeout_ms`,
|
||||
`address_space_bytes`, `file_bytes`, and `cpu_seconds`. The wall-clock timeout
|
||||
is at most 2,147,483,647 milliseconds, matching Node timers. Omitted fields keep
|
||||
the defaults above. Discovery accepts the same controls except `input_bytes`,
|
||||
since it does not read a capture or recording. Packet field discovery defaults
|
||||
to 32 MiB output rather than 4 MiB.
|
||||
|
||||
CLI supplies this object as JSON with `--producer-limits`, for example
|
||||
`--producer-limits '{"input_bytes":67108864,"output_bytes":8388608,"cpu_seconds":60}'`.
|
||||
Values apply to the next call without restarting REA. Effective native ceilings
|
||||
still preserve any tighter inherited soft and hard limit. Errors identify the
|
||||
exhausted producer control and retain partial output and cleanup status; follow
|
||||
that repair after cleanup settles. Raising producer budgets does not raise
|
||||
separate parser representations, transport buffers or external client deadlines.
|
||||
Never truncate the selected artifact to fit an input budget.
|
||||
|
||||
## Verification
|
||||
|
||||
```sh
|
||||
|
||||
@@ -64,10 +64,11 @@ Equivalent MCP input:
|
||||
```
|
||||
|
||||
Each selected regular file is read through the existing stable artifact reader;
|
||||
symlinks, changing files and files over 8 MiB fail closed. An oversized input
|
||||
returns `resource_constraint` with resource `file-size` and its fixed byte
|
||||
allowance in `reported_limits.maximum_input_bytes`; retrying the unchanged file
|
||||
does not raise that allowance. WASM bytes are copied
|
||||
symlinks, changing files and files over the selected `max_input_bytes` (default
|
||||
8 MiB) fail closed. An oversized input returns `resource_constraint` with
|
||||
resource `file-size` and the effective allowance in
|
||||
`reported_limits.maximum_input_bytes`. Its recovery names `max_input_bytes`;
|
||||
raise that per-call value before retrying the same complete file. WASM bytes are copied
|
||||
into a private workspace as read-only `module.wasm`; its digest is rechecked
|
||||
before and after each tool. WABT validates with
|
||||
`wasm-validate --enable-all --ignore-custom-section-errors`, reports sections
|
||||
@@ -137,12 +138,30 @@ the equivalent MCP input is `{"path":"/artifacts/module.wasm",
|
||||
"command_timeout_ms":60000,"detail":"summary"}`. Summary delivery retains the
|
||||
complete Evidence but does not reduce WABT analysis work.
|
||||
|
||||
The 8 MiB input allowance and 32 MiB combined command-output budget remain fixed;
|
||||
increasing `command_timeout_ms`, host memory or the client deadline does not raise
|
||||
them. Do not truncate required module bytes to fit. Select another suitable
|
||||
complete artifact only if it answers the question, otherwise report the limit.
|
||||
Inspection output past the budget fails with `resource_constraint`; an oversized
|
||||
`--version` probe still reports `unreadable_output`. Both streams share the
|
||||
The default input, executable, and combined command-output allowances remain
|
||||
8 MiB, 64 MiB, and 32 MiB respectively. Select `max_input_bytes`,
|
||||
`max_tool_bytes`, or `max_output_bytes` (CLI `--max-input-bytes`,
|
||||
`--max-tool-bytes`, `--max-output-bytes`) to change one allowance for the next
|
||||
inspection. Values are positive integer bytes; the advertised schema maximum
|
||||
follows the runtime's single-string or Buffer representation ceiling. Raising a
|
||||
budget does not reserve host memory or raise another budget, the command
|
||||
deadline, or the client's receive buffer. No REA restart is required. Unset
|
||||
values preserve the defaults, and explicit values remain in Evidence parameters.
|
||||
The same effective input/tool limit is used for initial and integrity rereads.
|
||||
Before cloning and committing complete Evidence, REA accounts for the actual
|
||||
escaped JSON representation and authentication copies. A large command budget
|
||||
does not guarantee that the complete report fits the runtime's single-string
|
||||
ceiling or available heap. Those refusals name the distinct representation or
|
||||
heap constraint; increasing `max_output_bytes` cannot repair them. WABT reports
|
||||
use no redundant raw-result mirror, but exact import/export forms and derived
|
||||
interface facts can still expand beyond their source WAT size.
|
||||
|
||||
A limit failure names its effective byte value and exact per-call control.
|
||||
Raise that control, resolve incomplete cleanup, then retry the same complete
|
||||
artifact. Do not truncate required module bytes. If already at the runtime
|
||||
maximum, report the limit or explicitly select another suitable complete input.
|
||||
Output past the budget fails with `resource_constraint`, including a `--version`
|
||||
probe; no truncated output is claimed as a successful inspection. Both streams share the
|
||||
budget, so a stream that starts after the other has filled it retains nothing.
|
||||
The captured output keeps up to the first 4,096 bytes that each stream retained,
|
||||
each stream's retained byte count, and the exit code and signal. Retained text
|
||||
@@ -238,3 +257,25 @@ Glue parsing accepts Node-supported WASM source-phase imports, including
|
||||
`await import.source("./module.wasm")`. Their string literals retain the same
|
||||
coordinates and local candidate associations as ordinary import literals; these
|
||||
are static source observations, without module instantiation or execution.
|
||||
|
||||
Typed interface decoding separately charges `max_interface_bytes` (default
|
||||
32 MiB; CLI `--max-interface-bytes`). The selected allowance applies to both
|
||||
nested WAT parsing and retained typed entries, so increasing it is not blocked
|
||||
by an independent fixed nested-parser cap. A partial interface preserves the
|
||||
original WAT, admitted entries, exact exhausted allowance and retry guidance.
|
||||
Inspect the same complete module again with a larger value to recover omitted
|
||||
typed facts.
|
||||
|
||||
`compare_wasm_interfaces` accepts its own `max_interface_bytes` in the JSON
|
||||
input, also default 32 MiB. It admits selected entries and group metadata before
|
||||
building the comparison inventory. A larger comparison budget cannot upgrade
|
||||
an already partial inspection: first recover the producer Evidence, then compare
|
||||
those exact replacement records. Both allowances retain independent runtime
|
||||
serialization and heap boundaries.
|
||||
|
||||
Auxiliary `candidate_paths` and `glue_paths` each retain a default admission of
|
||||
16 paths. Set `max_artifact_paths` (CLI `--max-artifact-paths`) to admit a larger
|
||||
explicit selection. Admission happens before any provider acquisition or command,
|
||||
and errors report the selected list, requested count and required control.
|
||||
Per-file byte budgets still apply to each admitted path; increasing the path
|
||||
count does not raise those limits or reserve host memory.
|
||||
@@ -120,7 +120,7 @@ correspondence merely from their different retained registrations.
|
||||
- `compare_web_screenshots` / `rea compare-web-screenshots` performs bounded local PNG pixel comparison without OCR or external services.
|
||||
- The CLI comparison commands accept each capture, screenshot artifact or normalization policy as inline JSON or a JSON file path. Use files for screenshot artifacts and scenario captures, whose embedded PNG bytes can exceed the host's command-line length limit.
|
||||
- Every surface has equivalent CLI and MCP contracts and returns Evidence provenance.
|
||||
- MCP tools return complete results inline and include the Evidence ID. Session evidence can be exported with `export_evidence_bundle`.
|
||||
- By default, MCP tools return complete results inline and include the Evidence ID. Selected summary views retain the complete parent Evidence and return a projection. Session evidence can be exported with `export_evidence_bundle`.
|
||||
|
||||
Target discovery returns the complete in-scope target array in one result.
|
||||
|
||||
@@ -228,7 +228,7 @@ in an existing profile.
|
||||
For such a browser, pass the browser socket instead of the HTTP endpoint:
|
||||
|
||||
```bash
|
||||
rea list-browser-targets ws://127.0.0.1:9222/devtools/browser/<id>
|
||||
rea list-browser-targets "ws://127.0.0.1:9222/devtools/browser/<id>"
|
||||
```
|
||||
|
||||
Chrome writes the port and the `/devtools/browser/<id>` path to the
|
||||
@@ -635,7 +635,7 @@ rejects it as unknown; other command rejections retain their reported failure.
|
||||
|
||||
Network and console coverage starts only after REA attaches and enables the relevant CDP domains. `prior_activity_available` is always `false`; absence from these arrays is not evidence that an event never occurred. Scripts are different: scripts the page parsed before REA attached are still reported under `scripts`. A page that loaded before attach can therefore list its scripts while `network.requests` lacks the requests that fetched them. If CDP reuses a request ID without supplying redirect metadata, REA retains the predecessor observation and marks network coverage incomplete.
|
||||
|
||||
Source maps are not fetched by inspection. Bundle analysis fetches them only when `fetch_source_maps` is selected, with exact-origin redirect checks and no credentials, cookies, or referrer. Each fetch operation uses `source_map_fetch_timeout_ms` (default 30000) and a 64 MiB aggregate streamed-response budget across redirects. The byte budget has no runtime override. A fetch overrun is an item limitation, not a thrown analysis timeout. A deadline or byte-limit failure remains explicitly unavailable and makes bundle completeness partial. Source-map decoding also bounds raw resolved identities to 64 MiB and aggregate inline evidence to 32 MiB. Failed maps preserve their failure context when it fits; if another context cannot fit, collection stops with the full requested count, the returned processed count, and an explicit unknown-results limitation. Retained mappings and original sources are returned inline. See [source-location limits](web-source-location.md) for the structural decoder bounds. Original source artifacts with `.ts`, `.tsx`, `.mts`, or `.cts` suffixes carry `text/typescript`; other source names retain `text/javascript`.
|
||||
Source maps are not fetched by inspection. Bundle analysis fetches them only when `fetch_source_maps` is selected, with exact-origin redirect checks and no credentials, cookies, or referrer. Each fetch operation uses `source_map_fetch_timeout_ms` (default 30000) and a default 64 MiB aggregate streamed-response budget across redirects. Select `source_map_limits.fetch_bytes` to change byte admission for the next call. A fetch overrun is an item limitation, not a thrown analysis timeout. A deadline or byte-limit failure remains explicitly unavailable and makes bundle completeness partial. Source-map decoding defaults to 64 MiB for raw resolved identities and 32 MiB for aggregate inline evidence; `source_map_limits.fetch_bytes` and `source_map_limits.output_bytes` own those independent admissions. Failed maps preserve their failure context when it fits; if another context cannot fit, collection stops with the full requested count, the returned processed count, and an explicit unknown-results limitation. Retained mappings and original sources are returned inline. See [source-location limits](web-source-location.md) for the structural decoder bounds. Original source artifacts with `.ts`, `.tsx`, `.mts`, or `.cts` suffixes carry `text/typescript`; other source names retain `text/javascript`.
|
||||
|
||||
A fully read response that fails UTF-8, JSON, mapping, or structural validation
|
||||
retains `artifact: null`, empty original-source, module-edge, and mapping
|
||||
|
||||
@@ -359,7 +359,7 @@ A `request` step sends one HTTP request from the page with the page's own
|
||||
recorded in the step's network events like any request the application makes.
|
||||
Use it to record an application's API, including writes, when driving the UI
|
||||
for each call would be slower or less exact than calling the endpoint the UI
|
||||
calls. It is the only action that changes application state without a user
|
||||
calls. This action directly sends a caller-declared HTTP request without a user
|
||||
gesture, so run scenarios with write requests only against an instance whose
|
||||
data you may change. This scenario creates one item:
|
||||
|
||||
|
||||
@@ -357,7 +357,11 @@ 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. Failure messages, diagnostics and cleanup
|
||||
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
|
||||
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
|
||||
@@ -1110,44 +1114,21 @@ for the hint per reason.
|
||||
|
||||
## Resource and lifecycle boundaries
|
||||
|
||||
Complete evidence has a 32 MiB input, 96 MiB decoder reply and 64-level nesting
|
||||
budget. Those budgets have no runtime override. `capture_timeout_ms` does not
|
||||
raise them. Exceeding a budget returns no partial success.
|
||||
Oversized selected captures return an input error identifying `capture_path`
|
||||
and the byte budget; owned reply/output failures remain output or provider errors.
|
||||
An explicit complete-reply refusal names the 100663296-byte allowance and its
|
||||
lack of a runtime override. Record selection, paging, delivery mode and worker
|
||||
memory do not increase that allowance; a smaller producer export is a narrower
|
||||
observation, and the refusal leaves no completed capture Evidence to retrieve.
|
||||
Cancellation during reply-file finalization retains validated completed capture
|
||||
facts as partial observations. Malformed or unvalidated replies are not promoted.
|
||||
HAR, SAZ and qlog run in an owned Node old-generation heap with one V8 worker.
|
||||
`REA_CAPTURE_DECODER_OLD_GENERATION_MIB` is a decimal integer of mebibytes from
|
||||
8 to 16384. Unset uses 192, the previous constant. Invalid values fail
|
||||
configuration and name the setting; they do not fall back to 192. The setting
|
||||
seeds the launch value. In MCP, set `capture.decoder_old_generation_mib`
|
||||
through `update_analysis_settings` for decoders belonging to newly accepted
|
||||
operations, without restarting REA. Changing the launch environment still
|
||||
requires a new process. A memory failure names the effective mebibytes, known
|
||||
source, default, floor, and maximum. The decoder
|
||||
passes that value as `--max-old-space-size` and removes inherited
|
||||
`NODE_OPTIONS`, so additional host memory and `NODE_OPTIONS` do not raise the
|
||||
heap. The 8 MiB semi-space stays fixed; a smaller old generation aborts Node
|
||||
during startup instead of enforcing a limit. Mitmproxy decoding applies
|
||||
Linux limits of 768 MiB address space, 30 seconds CPU and 96 MiB file output;
|
||||
both commands use `capture_timeout_ms` (default 30000) and independently supervised
|
||||
process cleanup. Owned decoder diagnostics retain at most 1 MiB across stdout
|
||||
and stderr; the collector drops overflow as it arrives, reports the limit
|
||||
failure and verifies cleanup. Heap limits alone do not establish aggregate RSS limits.
|
||||
SAZ and qlog refuse decoding when neither a Node heap limit nor a Windows Job Object bound can be enforced. Existing HAR availability is preserved.
|
||||
When REA runs on Bun, the HAR/SAZ/qlog decoder runs on Bun, which ignores these V8 heap
|
||||
flags; its limitations and resource failures then omit the V8 heap sizes. On
|
||||
Windows, the decoder's owned Job Object instead limits its committed memory to
|
||||
the effective `REA_CAPTURE_DECODER_OLD_GENERATION_MIB` value plus a 512 MiB
|
||||
reserve for Bun itself. The default 192 MiB setting therefore yields 704 MiB.
|
||||
The limitations state that limit, and reaching it returns `resource_constraint`
|
||||
with `process_memory_limit_bytes`, whatever exit status Bun reports. Other Bun
|
||||
hosts enforce no decoder heap limit, so raising the setting does not bound them.
|
||||
Complete evidence defaults to a 32 MiB input, 96 MiB decoder reply and
|
||||
64-level nesting allowance. Set `max_input_bytes`, `max_reply_bytes` or
|
||||
`max_nesting_depth` on the next `inspect_web_network_capture` call to change
|
||||
that operation's policy; CLI equivalents are `--max-input-bytes`,
|
||||
`--max-reply-bytes` and `--max-nesting-depth`. No REA restart is required.
|
||||
Byte allowances are positive safe integers; nesting is bounded by REA's
|
||||
advertised maximum of 996 levels, derived by reserving four enclosing
|
||||
reply/Evidence levels within the 1,000-level JSON representation. Input admission also covers expanded SAZ
|
||||
members and protobuf descriptor/body reads. Reply admission covers the complete
|
||||
child reply and protobuf interpretation work. These choices do not raise the
|
||||
separately owned worker heap, CPU limits or client deadline/receive buffer.
|
||||
Record selection takes place after complete decoding, so it cannot bypass
|
||||
whole-capture admission. A refusal names the exhausted control; increase that
|
||||
control and retry the same unchanged capture after cleanup. No completed capture
|
||||
Evidence exists for a refused decode.
|
||||
|
||||
Observed decoder memory exhaustion returns `resource_constraint`, with the
|
||||
selected capture, applicable limits and retained process diagnostics. Raising
|
||||
|
||||
@@ -82,13 +82,13 @@ implement every current source-map extension.
|
||||
One owned Node subprocess decodes the map. Its private request directory is
|
||||
removed before success is returned. Only this child's inherited `NODE_OPTIONS`
|
||||
is removed; explicit V8 flags set a 192 MiB old-generation and 8 MiB semi-space
|
||||
budget, one V8 worker and `decode_timeout_ms` (default 20000). The codec heap, map budget, and reply budget have no runtime override. Reported actual V8 heap limits
|
||||
budget, one V8 worker and `decode_timeout_ms` (default 20000). These are the defaults: select `source_map_limits.codec_heap_mib` for a different heap request. Reported actual V8 heap limits
|
||||
are checked. These are heap limits, not an aggregate process RSS limit. When
|
||||
REA runs on Bun, the subprocess is Bun, which ignores these V8 flags: `runtime`
|
||||
records `id: "bun"`, the Bun version, its Node.js compatibility version and a
|
||||
null `v8_heap_limit_bytes`. On Windows, the codec's owned Job Object then
|
||||
limits its committed memory to 704 MiB, the 192 MiB budget plus a 512 MiB
|
||||
reserve for Bun itself; `process_memory_limit_bytes` records that limit, the
|
||||
limits its committed memory to the selected codec heap request plus a 512 MiB
|
||||
reserve for Bun itself (704 MiB with the default request); `process_memory_limit_bytes` records that limit, the
|
||||
limitations state it, and reaching it returns `resource_constraint` with
|
||||
`codec_process_memory_limit_bytes`. Elsewhere Bun has no enforced codec limit:
|
||||
`process_memory_limit_bytes` is null and the limitations state that no codec
|
||||
@@ -102,16 +102,143 @@ run token while process release is unconfirmed, and the directory until removal
|
||||
succeeds. A later successful retry settles every error bound to that command;
|
||||
historical failure diagnostics remain available.
|
||||
|
||||
Complete evidence is bounded by a 4 MiB map, 32 MiB codec reply and a shared
|
||||
Complete evidence defaults to an 8 MiB map, 32 MiB codec reply and a shared
|
||||
262144-record decoder budget. Generated rows, mapping segments, leaf maps,
|
||||
source and name declarations, `sourcesContent` entries and indexed sections all
|
||||
consume this budget. Generated rows and mapping segments also each have a
|
||||
262144 limit; indexed maps allow at most 64 nested section levels. Those budgets and the
|
||||
192 MiB codec heap have no runtime override. Exceeding a budget returns an explicit
|
||||
262144 limit; indexed maps default to 64 nested section levels. Select per-call
|
||||
`source_map_limits` to change these admissions. Exceeding a budget returns an explicit
|
||||
failure, without partial results. The existing 32 MiB manifest and 16 MiB selected
|
||||
script boundaries also apply. No global toolchain or browser configuration changes
|
||||
are made.
|
||||
|
||||
## Compact point delivery and retained source text
|
||||
|
||||
Summary delivery is useful for large point answers. Complete output can answer
|
||||
a small-map task with fewer calls. The
|
||||
[delivery qualification](../../verification/source-location-delivery.md)
|
||||
records measured task costs and first-use discovery tradeoffs.
|
||||
|
||||
Complete delivery remains the default and includes raw map text and embedded source
|
||||
content. Select `detail: "summary"` in MCP, or `--detail summary` with
|
||||
`--evidence_output /analysis/source-point.json` in CLI, to retain the same complete
|
||||
Evidence and return body-free point metadata. Summary includes source/map/manifest
|
||||
identity, requested and matched generated positions, original source positions,
|
||||
content digests and sizes, match count, runtime qualifications and limitations.
|
||||
MCP returns the summary Evidence directly; its `normalized_result.parent_evidence_id`
|
||||
identifies the complete parent. CLI returns `{ summary: <Evidence>, evidence_bundle:
|
||||
{ path, bytes } }`; read `summary.normalized_result.parent_evidence_id` and use the
|
||||
published bundle path for later views. The receipt byte count describes the written
|
||||
complete Evidence bundle.
|
||||
Delivery selection does not enter that parent's analysis parameters or change its ID.
|
||||
|
||||
Summary returns the first metadata page (up to 64 matches and 1 MiB), with explicit
|
||||
`coverage.total`, `coverage.next_offset` and `coverage.exhausted`. Every equal-position
|
||||
alternative remains in the parent, including duplicate reported names, distinct
|
||||
indexed-section/source indexes and generated-only segments. Page exhaustion describes
|
||||
the retained lookup alternatives; execution and deployment authenticity remain unknown.
|
||||
For another page, call `inspect_analysis_view` with the same retained parent:
|
||||
|
||||
```json
|
||||
{
|
||||
"source": {
|
||||
"kind": "retained-evidence",
|
||||
"evidence_id": "<parent_evidence_id>"
|
||||
},
|
||||
"view": {
|
||||
"kind": "source-location",
|
||||
"collection": "matches",
|
||||
"offset": 64,
|
||||
"limit": 64
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Source text is explicit. Select `collection: "source-text"`, an original
|
||||
`match_index` from the metadata page, and UTF-16 `offset`/`limit` (default 0/1024).
|
||||
For a snippet around the mapped point, use its `original_position.offset` when
|
||||
known. The result preserves content digest/size and total code units, returns only
|
||||
the selected text, and reports text-page coverage. Unretained or generated-only
|
||||
content returns `item: null` and unavailable coverage. An offset splitting a
|
||||
surrogate pair is rejected; a page never splits a complete Unicode character.
|
||||
|
||||
Both collections accept `max_bytes` (default 1048576), independently of their
|
||||
row/code-unit limit and MCP response limits. A byte refusal names the allowance
|
||||
and retained parent: select a smaller page or increase `max_bytes`, then retry
|
||||
without decoding again. A large individual identity may require a larger view
|
||||
allowance or complete export. Complete map text and diagnostics remain in the parent.
|
||||
An optional `view` can accompany `detail: "summary"` on the initial trace, returning
|
||||
that selected page immediately. `view` with complete delivery is rejected before
|
||||
artifact acquisition. Summary also refuses before acquisition when session retention
|
||||
or the CLI Evidence output is unavailable.
|
||||
|
||||
These views read retained facts even after the original map is removed. CLI can read
|
||||
the saved parent with `inspect-analysis-view` and an `evidence-file` source pointing
|
||||
to the written bundle; select its `evidence_id` when the bundle has multiple records.
|
||||
MCP can export the complete session with `export_evidence_bundle`. A complete MCP
|
||||
response that exceeds transport admission retains its parent and supplies a
|
||||
`source-location` matches continuation.
|
||||
|
||||
## Selecting budgets and recovering the same map
|
||||
|
||||
Both `trace_web_source_location` and `analyze_web_bundle` accept an optional
|
||||
`source_map_limits` object. Omitted fields retain the defaults above and stay
|
||||
omitted in Evidence parameters. An update applies on the next call without a
|
||||
REA restart. Failure text names the exact field, effective value, supported
|
||||
range and next action; increasing a deadline does not change any of these
|
||||
budgets.
|
||||
|
||||
| Field | Default | Scope |
|
||||
| ------------------ | -------- | ------------------------------------------------------------------------------------- |
|
||||
| `map_bytes` | 8388608 | Local selected map admission, enforced before reading and again by the codec |
|
||||
| `output_bytes` | 33554432 | Complete local request/reply or aggregate fetched-map representation |
|
||||
| `decoded_rows` | 262144 | Generated rows before upstream allocation |
|
||||
| `decoded_segments` | 262144 | Mapping segments before upstream allocation |
|
||||
| `decoded_records` | 262144 | Shared structural work across leaves, declarations, rows, segments and sections |
|
||||
| `section_depth` | 64 | Indexed-section nesting |
|
||||
| `codec_heap_mib` | 192 | Local codec old-generation request; process-memory enforcement remains host dependent |
|
||||
| `fetch_bytes` | 67108864 | Aggregate response bytes and, independently, resolved-identity bytes |
|
||||
|
||||
The local 8 MiB admission covers the pinned 4,284,329-byte main map and 5,529,840-byte
|
||||
DateSelect map from Actual Budget without an admission retry. This is an artifact
|
||||
compatibility allowance, not a context or latency optimization: complete Evidence
|
||||
retains raw map text, and those two measured replies estimate 1.59 and 2.23 million
|
||||
tokens. A smaller admission refuses the map; it does not compact successful
|
||||
Evidence. MCP retains complete Evidence before encoding; an oversized response
|
||||
returns its retained reference for `export_evidence_bundle`, or callers can use
|
||||
complete CLI JSON. Select opt-in compact delivery above to keep complete Evidence accessible while returning only point metadata or an explicitly selected text page.
|
||||
Browser collection keeps its separate conservative defaults; see the
|
||||
[calibration record](../../verification/source-map-budget-calibration.md).
|
||||
|
||||
Local tracing accepts all listed fields except `fetch_bytes`. Bundle fetching
|
||||
accepts all except `map_bytes` and `codec_heap_mib`: it uses its existing
|
||||
inspection process rather than launching the local codec. Unsupported fields
|
||||
are rejected rather than silently ignored. Byte fields are bounded below
|
||||
Node's single-string representation ceiling, record fields by the signed
|
||||
32-bit decoder coordinate range, section depth by the same supported count range and shared structural admission,
|
||||
and heap requests by the existing 128..16384 MiB worker envelope. These bounds
|
||||
remain independent; a larger map can require a larger encoded request budget
|
||||
and codec heap, and the outer MCP client still owns its receive buffer/deadline.
|
||||
|
||||
For example, a valid 10 MiB selected local map can be retried with:
|
||||
|
||||
```json
|
||||
{
|
||||
"source_map_limits": { "map_bytes": 16777216 }
|
||||
}
|
||||
```
|
||||
|
||||
Keep the original manifest/map/point selection in that retry. The CLI spelling
|
||||
is `--source-map-bytes 8388608`; the other local flags are
|
||||
`--source-map-output-bytes`, `--source-map-decoded-rows`,
|
||||
`--source-map-decoded-segments`, `--source-map-decoded-records`,
|
||||
`--source-map-section-depth` and `--source-map-codec-heap-mib`.
|
||||
`analyze-web-bundle` instead offers `--source-map-fetch-bytes` and the shared
|
||||
output/record/depth flags. Raising only `decoded_records` does not raise the
|
||||
independent row or segment budgets. Failed local decoding returns no partial
|
||||
point evidence; completed browser map observations retain their existing
|
||||
partial/unknown semantics. Wait for retained cleanup to settle before retrying.
|
||||
|
||||
## Verification
|
||||
|
||||
Browser bundle collection uses absolute section offsets for nested inline maps.
|
||||
@@ -130,10 +257,10 @@ its `original_sources` declaration, including repeated source URLs across indexe
|
||||
sections. Imports are deduplicated within each declaration. Older observations
|
||||
may omit the index; their edge declaration identity remains unknown.
|
||||
|
||||
Browser collection accepts up to 64 MiB of map responses per inspection and
|
||||
Browser collection defaults to 64 MiB of map responses per inspection and
|
||||
preflights indexed sections, sources, names, generated rows and mapping segments
|
||||
against a 262144-record decode budget before upstream flattening. Indexed maps
|
||||
are limited to 64 nested levels. These structural limits bound decoded object
|
||||
default to 64 nested levels. These structural limits bound decoded object
|
||||
growth while preserving large embedded `sourcesContent` strings within the
|
||||
response-byte budget. It also bounds the expanded inline evidence to 32 MiB
|
||||
across the inspection, checking resolved source identities and mapping rows
|
||||
|
||||
+1
-1
@@ -52,7 +52,7 @@ The [documentation directory](README.md) lists every guide by domain.
|
||||
| Task | Guides |
|
||||
| --------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| Identify a desktop installation | [Runtime candidates, evidence and follow-up files](desktop-applications.md) |
|
||||
| Inspect native functions, references, or types | [Native binaries](guides/native/native-investigation.md), [Go metadata](guides/native/go-binaries.md), [Rust dependencies](rust-binaries.md), [CPython pyc files](python-pyc.md), [PE certificates](pe-certificates.md), [PE imports](pe-imports.md), [PE TLS/load config](pe-load-config.md), [ELF notes](elf-notes.md), [Linux kernel modules](kernel-modules.md), [Apple IPS](apple-ips.md), [Erlang BEAM](erlang-beam.md), [offline ELF layout](guides/native/binary-diagnostics.md), [recorded crashes](guides/native/recorded-crashes.md) |
|
||||
| Inspect native functions, references, or types | [Native binaries](guides/native/native-investigation.md), [Go metadata](guides/native/go-binaries.md), [Rust dependencies](rust-binaries.md), [CPython pyc files](python-pyc.md), [PE certificates](pe-certificates.md), [PE imports](pe-imports.md), [PE TLS/load config](pe-load-config.md), [ELF notes](elf-notes.md), [initializer functions](guides/native/native-initializers.md), [ELF unwind ranges](guides/native/elf-unwind-ranges.md), [Linux kernel modules](kernel-modules.md), [Linux kernel build config](guides/native/kernel-build-config.md), [Apple IPS](apple-ips.md), [Erlang BEAM](erlang-beam.md), [offline ELF layout](guides/native/binary-diagnostics.md), [recorded crashes](guides/native/recorded-crashes.md) |
|
||||
| Select a native provider or import format | [Ghidra semantics](providers/ghidra-provider.md), [Windows](providers/windows-ghidra-p0.md), [DOS](providers/ghidra-dos.md), [raw bytes](providers/raw-binary.md), [GameCube DOL](ghidra-dol.md), [MIPS](providers/ghidra-mips.md), [RISC-V](providers/ghidra-riscv.md), [PowerPC](ghidra-ppc.md), [PSP](providers/ghidra-psp.md), [NativeAOT](providers/ghidra-nativeaot.md), [IDA](providers/ida-provider.md), [Kuna](kuna-provider.md), [JEB](providers/jeb-analysis.md) |
|
||||
| Analyze JavaScript or Electron artifacts | [Static analysis](guides/javascript/javascript-artifact-reconstruction.md), [tracing and comparisons](guides/javascript/javascript-application-workflows.md), [application graph](guides/javascript/javascript-application-graph.md), [source recovery](guides/javascript/javascript-recovery.md) |
|
||||
| Compare static JavaScript with runtime observations | [Runtime attribution](guides/javascript/javascript-runtime-observation.md), [reconciliation](guides/javascript/javascript-runtime-reconciliation.md), [Electron observation](guides/javascript/electron-observation.md), [Electron fuses](electron-fuses.md) |
|
||||
|
||||
+16
-3
@@ -83,9 +83,22 @@ that `struct module`, symbol-table records, or certificate chains were decoded.
|
||||
The selected file is limited to 64 MiB by default (512 MiB maximum). At most
|
||||
8192 `.modinfo` and `__versions` entries plus listed `__ksymtab*` sections are
|
||||
examined by default (65536 maximum); `coverage.examined_entries` counts all
|
||||
three. Exceeding that budget fails with no partial success. Keys longer
|
||||
than 256 bytes and values longer than 4096 bytes stay malformed per entry;
|
||||
the field that fits is still copied. A `__ksymtab*` section name longer than
|
||||
three. Exceeding that budget fails with no partial success. `.modinfo` keys
|
||||
retain at most 256 bytes and values at most 4096 bytes by default. A larger
|
||||
field becomes `null` and is named in the entry's `omitted_fields`; the field
|
||||
that fits is still copied. Structural `status` and `reason` remain independent:
|
||||
a terminated, nonempty `key=value` entry stays `observed` when its text is
|
||||
omitted, while overall coverage becomes `partial`. Source range and digest
|
||||
remain available.
|
||||
|
||||
Raise `max_modinfo_key_bytes` or `max_modinfo_value_bytes` on the next MCP call
|
||||
to retain the omitted text. The returned limitation names the required byte
|
||||
budget. CLI flags are `--max-modinfo-key-bytes` and `--max-modinfo-value-bytes`.
|
||||
Each accepts an integer from 1 through 536870912 bytes, matching the maximum
|
||||
input size. No restart is required; file, entry and raw-hex budgets do not
|
||||
change. These are per-call controls, not runtime settings.
|
||||
|
||||
A `__ksymtab*` section name longer than
|
||||
256 bytes keeps its range with `name: null` and `ksymtab_name_exceeds_limit`. Inline raw hex stops at 4096 bytes and
|
||||
the SHA-256 remains.
|
||||
|
||||
|
||||
@@ -24,6 +24,13 @@ 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
|
||||
|
||||
+53
-9
@@ -72,16 +72,60 @@ Carrier byte order is independent of blob byte order.
|
||||
|
||||
Malformed magic, truncation, unknown flags/extensions, invalid UTF-8, duplicate
|
||||
raw asset keys and conflicting blob declarations fail closed with named reasons.
|
||||
Zero padding after a complete blob is allowed. The blob read ceiling is 256 MiB;
|
||||
PE carriers also use the shared 512 MiB input, 65,536 directory-entry and 8 MiB
|
||||
resource-metadata ceilings. The decoder admits at most 100,000 assets whose
|
||||
names total at most 8 MiB, and 4,096 exec arguments totaling at most 1 MiB of
|
||||
text. These are fixed resource bounds, not Node format limits, checked before
|
||||
decoding names or creating records; a hit fails as a limit with no runtime
|
||||
override. Asset and argument decoding, padding scans, and inventory construction
|
||||
Zero padding after a complete blob is allowed. Producer admission defaults to
|
||||
a 256 MiB blob, 100,000 assets whose names total at most 8 MiB, and 4,096 exec
|
||||
arguments totaling at most 1 MiB of text. These are resource policies, not Node
|
||||
format limits. Select `artifact_limits.node_sea` on inspection or extraction to
|
||||
change them before decoding names or creating records. Asset and argument
|
||||
decoding, padding scans, and inventory construction
|
||||
yield in bounded batches and honor caller cancellation. Asset count and name
|
||||
budgets bound retained metadata independently of stored member body sizes. The PE
|
||||
name probe reads headers from the first 64 KiB of the carrier; a PE whose
|
||||
budgets bound retained metadata independently of stored member body sizes.
|
||||
|
||||
| `artifact_limits.node_sea` field | Default | Unit and admission |
|
||||
| -------------------------------- | --------: | ------------------------------------------------------ |
|
||||
| `blob_bytes` | 268435456 | Bytes in one blob, checked before reading and decoding |
|
||||
| `asset_count` | 100000 | Asset records |
|
||||
| `asset_name_bytes` | 8388608 | Aggregate raw UTF-8 asset-name bytes |
|
||||
| `argument_count` | 4096 | Exec-argument records |
|
||||
| `argument_bytes` | 1048576 | Aggregate raw UTF-8 exec-argument bytes |
|
||||
| `recognition_header_count` | 4096 | ELF header rows admitted for recognition |
|
||||
| `recognition_load_command_bytes` | 8388608 | Mach-O load-command bytes admitted for recognition |
|
||||
|
||||
Exhausted recognition remains unknown, not examined absence. Inventory preserves
|
||||
native-root facts or another positively recognized pack and records the exact
|
||||
recognition limit inline. If extraction cannot establish a supported pack, it
|
||||
refuses with that admission cause. Confirmed SEA blob admission still returns a
|
||||
typed resource failure. ELF note-owner matching reads only the prefix needed to distinguish
|
||||
`NODE_SEA_BLOB`; an unrelated long owner does not consume retained string space
|
||||
or conceal a later SEA note. This does not change malformed framing checks.
|
||||
|
||||
For example, retain the same active carrier and retry an argument-count refusal:
|
||||
|
||||
```json
|
||||
{ "artifact_limits": { "node_sea": { "argument_count": 8192 } } }
|
||||
```
|
||||
|
||||
The CLI spelling is:
|
||||
|
||||
```sh
|
||||
rea inspect-artifact ./application --artifact-limits '{"node_sea":{"argument_count":8192}}' --json
|
||||
```
|
||||
|
||||
Failures report `reader_limit`, including the exact parameter, effective value,
|
||||
unit, supported range and required value when known. Changes apply on the next
|
||||
call without restarting REA. Delivery summary, paging and extraction selection
|
||||
cannot bypass whole-manifest admission. Omitted selections stay omitted in
|
||||
Evidence parameters; selecting `artifact_limits` records the accepted selection
|
||||
and `effective_limits`. Those are conditional policies for encountered readers,
|
||||
not a claim that every listed format was examined. The independent aggregate
|
||||
member-work override is `artifact_limits.expanded_bytes`; omission keeps the
|
||||
encoded-size-derived work allowance. Runtime Buffer/string representation limits
|
||||
and host memory remain independent of larger selected budgets.
|
||||
|
||||
PE carriers additionally use the shared 512 MiB input, 65,536 directory-entry
|
||||
and 8 MiB resource-metadata ceilings; the Node SEA selections do not raise those
|
||||
shared PE-parser boundaries. The PE name probe reads headers from the first
|
||||
64 KiB of the carrier; a PE whose
|
||||
headers extend beyond that is left to native classification. ELF note tables
|
||||
are read for at most one note per 12 carrier bytes in total, the most that
|
||||
disjoint tables can hold, so program headers that repeat the same notes do not
|
||||
|
||||
@@ -58,7 +58,11 @@ fail without partial success. A security directory that ends in fewer than
|
||||
eight header bytes, including zeros, is a truncated `WIN_CERTIFICATE` and
|
||||
fails the same way. SignedData must contain at least one `SignerInfo`, and
|
||||
each `SignerInfo` must carry a non-empty signature value. Each embedded X.509
|
||||
certificate must include `subjectPublicKeyInfo` and `signatureValue`. Decoded
|
||||
certificate must include `subjectPublicKeyInfo` and `signatureValue`.
|
||||
Certificate issuer/subject and signer issuer names require nonempty RDN sets
|
||||
and exactly two fields (type and value) in each attribute, as defined in
|
||||
[RFC 5280](https://www.rfc-editor.org/rfc/rfc5280.html#section-4.1.2.4).
|
||||
Malformed name structures fail before their text is reported. Decoded
|
||||
certificate name text, serials, validity spellings, and subject key identifiers
|
||||
share a 64 KiB budget per PKCS#7 payload, and each payload decodes at most
|
||||
16,384 ASN.1 values. Exhausting either fixed allowance returns a nonretryable
|
||||
|
||||
@@ -96,6 +96,40 @@ and trace matches likewise retain Ghidra's external and thunk classification.
|
||||
The Ghidra analysis profile identifies this search projection, so older
|
||||
snapshots with unqualified search rows cannot replay under the new profile.
|
||||
|
||||
## Decompiler and value-flow budgets
|
||||
|
||||
Use `inspect_analysis_settings` or a result's named recovery to inspect
|
||||
`ghidra.value_flow_max_operations` (default 3000),
|
||||
`ghidra.value_flow_max_inputs_per_operation` (default 64), and
|
||||
`ghidra.value_flow_max_edges` (default 12000). Each accepts a positive Java
|
||||
integer count. `update_analysis_settings` applies changes to the next operation
|
||||
on the same Program without restarting REA. Launch seeds use the corresponding
|
||||
`REA_GHIDRA_VALUE_FLOW_MAX_OPERATIONS`,
|
||||
`REA_GHIDRA_VALUE_FLOW_MAX_INPUTS_PER_OPERATION`, and
|
||||
`REA_GHIDRA_VALUE_FLOW_MAX_EDGES` environment settings.
|
||||
For a one-shot CLI retry, set the named seed in the environment that launches
|
||||
the next `rea` invocation; the completed invocation's Program is no longer
|
||||
active. Runtime MCP changes preserve the current Program. A changed launch seed
|
||||
only affects a running MCP server after that server restarts.
|
||||
|
||||
The returned `native_value_flow.limits` and `limits_reached` distinguish accepted
|
||||
budgets from actual exhaustion. Truncation keeps omitted counts and names the
|
||||
setting to adjust. The edge budget applies independently to def-use and
|
||||
parameter-use collections. New function dossiers are reobserved rather than
|
||||
replayed from snapshots; completed Evidence remains available for historical
|
||||
inspection. Other observation caches keep their existing policy.
|
||||
|
||||
`ghidra.decompile_max_payload_mib` controls the native decompiler's response
|
||||
payload, separately from p-code projection and decompile time. Its launch seed
|
||||
is `REA_GHIDRA_DECOMPILE_MAX_PAYLOAD_MIB`; explicit values are 1..2047 MiB to
|
||||
avoid overflow in Ghidra's signed integer byte conversion. Omission or runtime
|
||||
`null` preserves the installed provider's default. Changes apply before the
|
||||
next native decompile, and native option changes clear its old cached function
|
||||
state. A failed decompile preserves the original diagnostic and reports the
|
||||
effective payload allowance; payload recovery applies only when that diagnostic
|
||||
identifies payload exhaustion. Raising these controls does not raise the MCP
|
||||
client's deadline or receive buffer.
|
||||
|
||||
## PE debug-symbol coverage
|
||||
|
||||
The post-analysis handshake reports Ghidra's PDB Program Information attributes:
|
||||
@@ -267,7 +301,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. 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. 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. |
|
||||
| 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. 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. 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 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.
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<div align="center">
|
||||
|
||||
[English](../../README.md) · [简体中文](README_zh.md) · [繁體中文](README_zh-TW.md) · [日本語](README_ja.md) · [한국어](README_ko.md) · [Türkçe](README_tr.md) · [Русский](README_ru.md) · [Tiếng Việt](README_vi.md) · [ไทย](README_th.md) · [Deutsch](README_de.md) · [Español](README_es.md) · [Français](README_fr.md) · [Українська](README_uk.md) · [Polski](README_pl.md) · [Português (Brasil)](README_pt-BR.md) · **العربية** · [فارسی](README_fa.md) · [Bahasa Indonesia](README_id.md) · [Italiano](README_it.md)
|
||||
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md) · [Roman Urdu](README_ur-Latn.md) · [Română](README_ro.md)
|
||||
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md) · [Roman Urdu](README_ur-Latn.md) · [Română](README_ro.md) · [Български](README_bg.md)
|
||||
|
||||
# REA: هندسة عكسية لأي شيء
|
||||
|
||||
@@ -84,6 +84,10 @@ npx rea-agents setup
|
||||
|
||||
يستخدم MCP مخططات إدخال مختصرة افتراضيًا. للحصول على إرشادات الحقول الكاملة وتفاصيل التحقق المتداخل، اضبط `REA_MCP_INPUT_SCHEMA_PROFILE=full` في تسجيل MCP. يحتفظ الخياران بجميع الأدوات والتحقق القياسي نفسه على الخادم؛ راجع دليل عقود MCP.
|
||||
|
||||
يسجّل الإعداد بيئة التشغيل المحددة وملف دخول REA مباشرةً. عند استخدام مشغّل حزم، احتفظ بإدخال ذاكرة التخزين المؤقت وبيئة التشغيل؛ ونفّذ تنزيل الحزمة من دليل موثوق خارج المشروع المستهدف. راجع دليل التثبيت والإعداد.
|
||||
|
||||
تُعلن مخططات الإخراج الكاملة افتراضيًا. إذا حدّ عميلك من حجم `tools/list`، فاضبط `REA_MCP_OUTPUT_SCHEMA_PROFILE=compact` أو `off` في تسجيل MCP؛ يظل التحقق والخروج المنظّم كاملين على الخادم. راجع قسم مخططات الإخراج في دليل عقود MCP.
|
||||
|
||||
### اطلب من وكيلك
|
||||
|
||||
```text
|
||||
@@ -157,6 +161,7 @@ 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) |
|
||||
@@ -172,6 +177,7 @@ npx rea-agents@latest setup
|
||||
| التقاط الحزم | نقاط النهاية وDNS وTLS SNI وتوزيع البروتوكولات وطلبات HTTP | tshark وcapinfos يوفّرهما المُستدعي؛ [دليل pcap](../guides/data/pcap-analysis.md) |
|
||||
| تجميعات .NET | البيانات الوصفية، وتعليمات CIL، واعتماديات الشيفرة الأصلية المعلنة، ومقارنات البناء | فحص ثابت؛ [دليل الشيفرة المُدارة](../guides/managed/managed-code-analysis.md) |
|
||||
| PyInstaller | CArchive, PYZ, Python bytecode | Static inspection; [Python packaged applications](../python-packaged-applications.md) |
|
||||
| Deno compile binaries | Virtual files, entry point, recorded options, npm snapshot length | Static inspection; [Deno compile executables](../deno-standalone.md) |
|
||||
| حزم Android APK | تصريحات ملف manifest، والأصناف، والدوال الناتجة عن فك الترجمة، والمراجع | JADX دون واجهة رسومية وJDK كامل على Linux/macOS/Windows x64؛ [دليل Android](../guides/android/android-analysis.md) |
|
||||
| أجهزة Android | الأجهزة والحزم والعمليات والسجلات والدامبات ولقطات الشاشة ونقل APK/الملفات | adb يوفّره المُستدعي (محاكي أو جهاز)؛ [دليل ADB](../guides/android/adb-device-analysis.md) |
|
||||
| مشاريع JEB | وحدات المشروع من المحرك وبصمات المصنّفات والكود الزائف للأنواع/الدوال | عميل JEB يبدأه المُستدعي ويقدّم MCP، ويُختار عبر REA_JEB_MCP_URL؛ [دليل JEB](../providers/jeb-analysis.md) |
|
||||
@@ -273,6 +279,12 @@ agent-env run ./my-env
|
||||
[مرجع البيئات](../agent-environments.md) ·
|
||||
[شاهد العرض على X](https://x.com/reatools/status/2112574822584918075?s=20)
|
||||
|
||||
### بيئات تطبيقات سطح المكتب
|
||||
|
||||
يستطيع REA أيضًا إنشاء بيئة لتطبيق سطح مكتب على Linux يستخدمه الوكيل عبر لقطات الشاشة والفأرة ولوحة المفاتيح. من طلب من سطر واحد، مثل "أنشئ لي بيئة Gnote يضيف فيها الوكيل زيت الزيتون إلى ملاحظة قائمة التسوق"، يثبّت وكيلك التطبيق على حاسوب بناء محلي، ويكتب المهمة، ويصدّر البيئة، ثم يتحقق من المهمة على حاسوب جديد. يحتاج الجهاز الذي يبنيها إلى Linux على amd64 أو arm64، وDocker، وإصدار إطار agentenv الذي يحدده الدليل.
|
||||
|
||||
[إعداد بيئات تطبيقات سطح المكتب](../desktop-build-computer.md)
|
||||
|
||||
## الأسئلة الشائعة
|
||||
|
||||
<details>
|
||||
|
||||
@@ -0,0 +1,523 @@
|
||||
<div align="center">
|
||||
|
||||
[English](../../README.md) · [简体中文](README_zh.md) · [繁體中文](README_zh-TW.md) · [日本語](README_ja.md) · [한국어](README_ko.md) · [Türkçe](README_tr.md) · [Русский](README_ru.md) · [Tiếng Việt](README_vi.md) · [ไทย](README_th.md) · [Deutsch](README_de.md) · [Español](README_es.md) · [Français](README_fr.md) · [Українська](README_uk.md) · [Polski](README_pl.md) · [Português (Brasil)](README_pt-BR.md) · [العربية](README_ar.md) · [فارسی](README_fa.md) · [Bahasa Indonesia](README_id.md) · [Italiano](README_it.md)
|
||||
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md) · [Roman Urdu](README_ur-Latn.md) · [Română](README_ro.md) · **Български**
|
||||
|
||||
# REA: Reverse Engineer Anything
|
||||
|
||||
### Един MCP сървър за обратно инженерство на бинарни файлове, приложения и поведение по време на изпълнение.
|
||||
|
||||
**Харесва ви функция в някое приложение? Разберете как работи, чак до ниво бинарен код.**
|
||||
|
||||
[](https://www.npmjs.com/package/rea-agents)
|
||||
[](../reference/mcp-contracts.md#generated-catalog)
|
||||
[](#current-status)
|
||||
[](https://skills.sh/morluto/rea/reverse-engineer-anything)
|
||||
[](../../LICENSE)
|
||||
[](https://discord.gg/GkcryMnJDM)
|
||||
|
||||
<a href="https://trendshift.io/repositories/82054?utm_source=repository-badge&utm_medium=badge&utm_campaign=badge-repository-82054" target="_blank" rel="noopener noreferrer"><img src="https://trendshift.io/api/badge/repositories/82054" alt="morluto%2Frea | Trendshift" width="250" height="55"/></a>
|
||||
|
||||
**[Уебсайт](https://rea.tools/) · [Ръководства](https://rea.tools/guides/) · [Примери](https://rea.tools/showcase/)**
|
||||
|
||||
<a href="https://discord.com/invite/GkcryMnJDM"><img alt="Присъединете се към общността на REA в Discord" src="https://img.shields.io/badge/Join%20us%20on%20Discord-5865F2?style=for-the-badge&logo=discord&logoColor=white" height="40"></a>
|
||||
|
||||
[Бърз старт](#бърз-старт) · [Как работи REA](#как-работи-rea) · [Какво можете да анализирате](#какво-можете-да-анализирате) · [Примери](#примери) · [Създаване на RL среди](#build-rl-environments) · [Често задавани въпроси](#често-задавани-въпроси) · [Документация](#документация)
|
||||
|
||||
<code>npx rea-agents setup</code>
|
||||
|
||||
</div>
|
||||
|
||||
> [!IMPORTANT]
|
||||
> Изтегляйте REA от [morluto/rea](https://github.com/morluto/rea),
|
||||
> [rea.tools](https://rea.tools/) или [npm пакета rea-agents](https://www.npmjs.com/package/rea-agents).
|
||||
> Следвайте връзките за инсталиране и издания от тези официални източници. Подобно
|
||||
> име на хранилище или копиран README не доказва, че дадено изтегляне е официално.
|
||||
|
||||
<div align="center">
|
||||
|
||||
<br />
|
||||
|
||||
<img src="../assets/rea-hopper-analysis.png" alt="REA стартира своя мост за анализ в Hopper, докато изследва нативен бинарен файл" width="1200" />
|
||||
|
||||
<br /><br />
|
||||
|
||||
<table aria-label="Общността на REA">
|
||||
<tr>
|
||||
<td align="center" width="360">
|
||||
<a href="https://discord.gg/GkcryMnJDM">
|
||||
<img src="../assets/discord.svg" height="42" alt="Discord" /><br />
|
||||
<strong>Присъединете се към общността за обратно инженерство</strong>
|
||||
</a><br />
|
||||
<sub>Discord · Въпроси и отговори · Покажете какво сте направили</sub>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<br />
|
||||
|
||||
</div>
|
||||
|
||||
---
|
||||
|
||||
Видели сте функция в приложение и искате същата във вашия продукт? Помолете агента си да я проучи с REA. Той може да изследва приложението без изходния му код, да обясни как работи функцията, да покаже доказателствата и да изгради подобна версия за вашия проект.
|
||||
|
||||
REA свързва агента ви с инструменти за изследване на нативни бинарни файлове, JavaScript и Electron приложения, .NET асемблита и уебсайтове. Същите инструменти можете да използвате и от терминала. Анализът се извършва локално, а резултатите включват доказателствата и ограниченията зад всеки извод.
|
||||
|
||||
Настройката регистрира REA в агента ви и инсталира съответните инструкции за работния процес. Нативният анализ може да използва вече инсталиран Hopper, Ghidra, IDA или Kuna; по желание настройката може да инсталира Hopper след ваше одобрение. Статичният анализ на JavaScript не изисква двигател за нативен анализ.
|
||||
|
||||
> **[Посетете уебсайта на REA](https://rea.tools/)** за инструкции за настройка, илюстрирани ръководства и реални казуси.
|
||||
|
||||
## Бърз старт
|
||||
|
||||
В Linux стартирането на Ghidra, JADX и инструментите за фърмуер, както и
|
||||
статичният анализ на JavaScript/Electron, изискват съвместима с procps команда
|
||||
`ps` в `PATH` на REA за проверките кой процес на кого принадлежи. Стъпките за
|
||||
отстраняване на проблема са в `docs/getting-started/installation.md`, в раздела
|
||||
„Linux owned-process prerequisite“.
|
||||
|
||||
### Настройте агента си
|
||||
|
||||
След като имате инсталирани Node.js и npm, изпълнете:
|
||||
|
||||
```bash
|
||||
npx rea-agents setup
|
||||
```
|
||||
|
||||
Изберете агентите си, прегледайте предложените промени и ги одобрете. Настройката
|
||||
добавя MCP сървъра на REA и съответните инструкции за работния процес, като прави
|
||||
резервни копия на съществуващата конфигурация. След това рестартирайте агента.
|
||||
Настройката записва директно избраната среда за изпълнение и входния скрипт на
|
||||
REA. Ако сте получили REA чрез инструмент за изпълнение на пакети (package
|
||||
runner), не изтривайте записа му в кеша. Изтегляйте пакета от доверена
|
||||
директория извън целевия проект. Подробности за инсталирането и отстраняването на
|
||||
проблеми има в ръководството за настройка по-долу.
|
||||
|
||||
Настройката поддържа Claude Code, Codex, Cursor, Gemini CLI, Grok Build и
|
||||
[други агенти](../getting-started/installation.md#supported-agents). Вижте
|
||||
[инсталиране и настройка](../getting-started/installation.md) за конфигуриране на
|
||||
доставчици на анализ, ръчна регистрация на MCP и инсталиране на плъгина за
|
||||
Claude Code/Codex.
|
||||
|
||||
По подразбиране MCP използва компактни входни схеми, за да заема по-малко от
|
||||
контекста. Задайте `REA_MCP_INPUT_SCHEMA_PROFILE=full` в MCP регистрацията си,
|
||||
когато са ви нужни пълните описания на полетата и подробностите за вложената
|
||||
валидация. И двата профила запазват пълния набор от инструменти и каноничната
|
||||
валидация на сървъра. Вижте „Compact input schema profile“ в ръководството за MCP
|
||||
договорите.
|
||||
|
||||
По подразбиране се обявяват пълните изходни схеми. Ако клиентът ви ограничава
|
||||
размера на цялата рамка `tools/list`, задайте
|
||||
`REA_MCP_OUTPUT_SCHEMA_PROFILE=compact`, за да ограничите всяка обявена изходна
|
||||
схема, или `off`, за да пропуснете изходните схеми изцяло. И двете настройки
|
||||
запазват каноничната валидация от страна на сървъра и пълните структурирани
|
||||
резултати. Вижте „Output schemas“ в ръководството за MCP договорите.
|
||||
|
||||
### Попитайте агента си
|
||||
|
||||
```text
|
||||
Разбери как работи търсенето в приложението Notes, покажи ми доказателствата и
|
||||
изгради подобна функция за моя проект.
|
||||
```
|
||||
|
||||
Заменете Notes с целевото си приложение и функцията, която искате да разберете.
|
||||
|
||||
### Използвайте терминала
|
||||
|
||||
Изследвайте директорията на разархивирано JavaScript/Electron приложение или ASAR
|
||||
архив:
|
||||
|
||||
```bash
|
||||
npx -y rea-agents@latest analyze-javascript-application /absolute/path/to/app --json
|
||||
```
|
||||
|
||||
Резултатът включва модули, импорти, границите на Electron и доказателствата за
|
||||
тях. Заменете пътя с вашата цел, например `"D:/apps/example"` в Windows.
|
||||
|
||||
За да инсталирате командата `rea` за редовна употреба:
|
||||
|
||||
```bash
|
||||
npm install --global rea-agents
|
||||
rea --help
|
||||
```
|
||||
|
||||
За нативен анализ първо конфигурирайте доставчик на анализ. Вижте
|
||||
[ръководството за CLI и Evidence](../getting-started/cli.md) за нативните
|
||||
команди, избора на доставчик, моментните снимки (snapshots) и скриптирането.
|
||||
|
||||
### Обновяване на REA
|
||||
|
||||
REA се променя бързо и новите издания често съдържат поправки на грешки.
|
||||
Поддържайте инсталацията си актуална.
|
||||
|
||||
За CLI, инсталиран с `npm install --global` или `bun add --global`:
|
||||
|
||||
```bash
|
||||
rea update
|
||||
```
|
||||
|
||||
`rea --update` е псевдоним на същия проверен процес и приема същите глобални
|
||||
флагове за изхода. Използвайте `rea update`, когато го комбинирате с други опции
|
||||
на командата.
|
||||
|
||||
Командите за обновяване запазват общо най-много 4 MiB от stdout и stderr. Твърде
|
||||
големите отговори с метаданни се отхвърлят след приключване на командата;
|
||||
подробните (verbose) инсталации продължават с ограничена диагностика. Изходът за
|
||||
напредъка, предназначен за хора, се съобразява с обратното налягане
|
||||
(backpressure) на терминала и изчаква изпратените записи да завършат.
|
||||
|
||||
Глобалните обновявания чрез Bun изискват Bun 1.2.17 или по-нова версия. При
|
||||
по-стара версия първо обновете Bun ръчно и след това изпълнете `rea update`.
|
||||
|
||||
За да опресните регистрациите в агентите и умението (skill), изпълнете командата
|
||||
за настройка, която обновяването отпечатва.
|
||||
|
||||
Ако използвате `npx`, обновете настройката на агента си с:
|
||||
|
||||
```bash
|
||||
npx rea-agents@latest setup
|
||||
```
|
||||
|
||||
Прегледайте промените от настройката и рестартирайте агента. За еднократни CLI
|
||||
команди използвайте `npx rea-agents@latest`, последвано от командата. С Bun
|
||||
използвайте `bunx rea-agents@latest` вместо `npx rea-agents@latest`.
|
||||
|
||||
## Как работи REA
|
||||
|
||||
Агентът ви извиква REA чрез MCP, за да изследва целта и да проследи съответния
|
||||
код. REA връща констатации заедно с доказателствата за тях. Агентът ги използва,
|
||||
за да задава допълнителни въпроси, да обяснява поведението или да напише и тества
|
||||
реализация. CLI командите използват същите работни процеси.
|
||||
|
||||

|
||||
|
||||
[Отворете фигурата в пълен размер](../../website/public/assets/figures/rea-investigation-flow.svg).
|
||||
|
||||
<a id="current-status"></a>
|
||||
|
||||
## Какво можете да анализирате
|
||||
|
||||
REA изисква Node.js 22.x (>=22.23.4), 24.x (>=24.22.1) или 26.12.1+, както и
|
||||
npm. Допълнителните инструменти и поддържаните операционни системи зависят от
|
||||
целта:
|
||||
|
||||
| Цел | Какво връща REA | Изисквания и ръководство |
|
||||
| ------------------------------- | ------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| Инсталирани настолни приложения | Кандидати за среда за изпълнение, поддържащи файлове, маркери на компоненти и следващи проверки | Вградена ограничена проверка на директории и заглавни части; [настолни приложения](../desktop-applications.md) |
|
||||
| Нативни бинарни файлове | Псевдокод, асемблер, низове, символи, извиквания и препратки | Hopper, Ghidra, IDA или Kuna; [нативен анализ](../guides/native/native-investigation.md) |
|
||||
| Структура на ELF (офлайн) | Секции, сегменти, оригинални символи/релокации и кандидати за статични защитни механизми | Предоставен от вас pwntools на Linux x64; [диагностика на бинарни файлове](../guides/native/binary-diagnostics.md) |
|
||||
| Go бинарни файлове | Вградена версия на компилатора, модули, замени и настройки на компилацията | Вградена статична проверка на ELF/PE/thin Mach-O; не изисква инсталиран Go |
|
||||
| GPU кодови обекти | CUDA/HIP цели, избрани параметри и ресурси на ядрата, запазен PTX текст | Вградена статична проверка на ELF/PE/fatbin/CUBIN/PTX; [GPU кодови обекти](../gpu-code-objects.md) |
|
||||
| Файлове на модели | Метаданни на GGUF / safetensors, декларации на тензори и изчислени общи стойности | Вградена проверка на заглавните части; по желание хеш на целия файл; [файлове на модели](../model-artifacts.md) |
|
||||
| IL2CPP метаданни | Образи на асемблита от Unity global-metadata.dat, имена на типове и методи и диапазони на индекси | Вградено статично декодиране на версии 24, 27, 29, 31 и 39; не изисква Unity |
|
||||
| Godot PCK | Опис и извличане на архива, оригинални данни от заглавната част и директорията и идентичност на избрано съдържание | Вградена статична поддръжка на формати 2, 3 и 4; не изисква Godot |
|
||||
| Rust бинарни файлове | Вградени от cargo-auditable имена на crate-ове, версии, източници и връзки между зависимостите | Вградена статична проверка на ELF/PE/thin Mach-O; [Rust бинарни файлове](../rust-binaries.md) |
|
||||
| PE сертификати | Записи Authenticode WIN_CERTIFICATE и полета за самоличност на подписващия от PKCS#7/X.509 | Вградена статична проверка на PE; [PE сертификати](../pe-certificates.md) |
|
||||
| PE импорти | Имена на импортирани и отложено зареждани (delay-load) DLL библиотеки, ординали, IAT RVA адреси и pefile хеш на импортите | Вградена статична проверка на PE; [PE импорти](../pe-imports.md) |
|
||||
| Windows преки пътища | Цел, аргументи, работна директория и данни от Shell Link | Вградена статична проверка на LNK; [Windows преки пътища](../guides/native/windows-shortcut.md) |
|
||||
| ELF бележки | Собственици и типове на PT_NOTE/SHT_NOTE, полета GNU build-id и ABI-tag | Вградена статична проверка на ELF; [ELF бележки](../elf-notes.md) |
|
||||
| Защита на бинарни файлове | PIE, NX, RELRO, CFG и свързаните с тях флагове в заглавните части на ELF, PE и Mach-O | Вградена статична проверка на заглавните части; [защита на бинарни файлове](../binary-hardening.md) |
|
||||
| Сривове на Apple (IPS) | Метаданни от .ips, нишки, образи, регистри и документирани класове сривове | Вградена статична проверка на JSON; [Apple IPS](../apple-ips.md) |
|
||||
| Модули на ядрото на Linux | Ключове от .modinfo, CRC стойности от __versions, наличие на this_module и подпис в края на файла | Вградена статична проверка на ELF; [модули на ядрото](../kernel-modules.md) |
|
||||
| Erlang BEAM | IFF блокове (chunks), атоми, експорти, импорти, ламбди и заглавната част Code | Вградена статична проверка на BEAM; [Erlang BEAM](../erlang-beam.md) |
|
||||
| WASM артефакти | Валидация, секции, точни WAT форми на импортите/експортите и декодиран WAT | Предоставен от вас WABT 1.0.42; `inspect_wasm_artifact` |
|
||||
| EVM байткод | Селектори на функции, отмествания в байтове, изведени аргументи и променливост (mutability) | Локален raw/hex носител на Linux x64; [ръководство за офлайн EVM](../guides/evm/evm-bytecode.md) |
|
||||
| SQLite бази данни | Таблици, колони, индекси, изгледи, тригери и избрани редове от обикновени таблици | Локална моментна снимка на базата/WAL; Node.js 24.x >=24.15 или 26+ с нативни ограничения на SQLite |
|
||||
| Записани сривове в Linux | Сурови бележки, регистри/сигнали на всяка записана нишка и по желание кандидати за съпоставяне с файлове в паметта | Предоставен от вас pwntools на Linux x64; по желание GDB/pwndbg; [записани сривове](../guides/native/recorded-crashes.md) |
|
||||
| JavaScript / Electron | Модули, импорти, source maps, маршрути, IPC и връзки с нативни добавки | Node.js и npm; Linux: съвместима с procps команда `ps`; [анализ на приложения](../guides/javascript/javascript-application-workflows.md) |
|
||||
| Уебсайтове | Структура на страниците, скриптове, мрежови наблюдения и заявени екранни снимки | Браузър от семейството на Chrome; [анализ в браузъра](../guides/web/browser-observation.md) |
|
||||
| Запазени мрежови записи | Заявки, отговори, открити полезни данни (payloads) и местоположения в изходния код | HAR или Fiddler Everywhere SAZ; mitmdump на Linux за нативен mitmproxy; [ръководство за мрежови записи](../guides/web/web-network-captures.md) |
|
||||
| .NET асемблита | Метаданни, CIL инструкции, декларирани нативни зависимости и сравнения между компилации | Няма (само статичен анализ); [ръководство за управляван код](../guides/managed/managed-code-analysis.md) |
|
||||
| Android APK файлове | Декларации в манифеста, класове, декомпилирани методи и препратки | JADX без графичен интерфейс и пълен JDK на Linux/macOS/Windows x64; [ръководство за Android](../guides/android/android-analysis.md) |
|
||||
| Подписи на APK | Подписващи v1/v2/v3/v3.1, отпечатъци на сертификати, ротация на ключове и вътрешна съгласуваност на хешовете | Няма (само статичен анализ); `inspect_apk_signature` |
|
||||
| Android устройства | Устройства, пакети, процеси, логове, дъмпове, екранни снимки и прехвърляне на APK/файлове | Предоставен от вас adb (емулатор или физическо устройство); [ръководство за ADB](../guides/android/adb-device-analysis.md) |
|
||||
| JEB проекти | Единици на проекта от двигателя на JEB, хешове на артефакти и псевдокод на типове/методи | Стартиран от вас JEB клиент, който обслужва MCP и е избран чрез REA_JEB_MCP_URL; [ръководство за JEB](../providers/jeb-analysis.md) |
|
||||
| Android ресурси | Декодиран манифест, таблици с низове, локали и данни за версията | Предоставен от вас стартер за Apktool; [ръководство за ресурси](../guides/android/apktool-resource-analysis.md) |
|
||||
| Flutter приложения | Хеш на Dart snapshot, хешове на библиотеките за всяко ABI и произход на компилацията на двигателя | Няма (статичен анализ на APK); [ръководство за Flutter](../guides/android/flutter-analysis.md) |
|
||||
| Фърмуер | Региони, резултати от извличането и предаване към нативен анализ | Binwalk / Unblob на Linux; [ръководство за фърмуер](../guides/firmware/firmware-analysis.md) |
|
||||
| Записани пакети | Избрани полета, повтарящи се стойности, филтри и правила decode-as | Linux: TShark 4.x + prlimit; [ръководство за записи](../guides/data/packet-captures.md) |
|
||||
| Обобщения на пакети | Крайни точки, DNS, TLS SNI, разпределение по протоколи и HTTP заявки | Предоставени от вас tshark и capinfos (проверено на Linux); [ръководство за pcap](../guides/data/pcap-analysis.md) |
|
||||
| Записани логически сигнали | Анотации от декодерите, диапазони от семпли и диагностика | Linux: sigrok-cli 0.7.2 + prlimit; [записи на сигнали](../guides/signals/signal-recordings.md) |
|
||||
| Пакети и ресурси | Описи на файлове, хешове, plist файлове, устройство на Apple пакети (bundles) и извлечени ресурси | [Ръководство за артефакти и JavaScript](../guides/javascript/javascript-artifact-reconstruction.md), [Apple приложения](../guides/apple/apple-application-analysis.md) |
|
||||
| Поведение на процеси | Изход в терминала, взаимодействия, наблюдения на изхода от процеса и на файловата система и сравнения между изпълнения | Linux/macOS с нативен PTY; [запис на процеси](../guides/runtime/process-capture.md) |
|
||||
| PyInstaller изпълними файлове | Членове на CArchive, версия на Python, входни скриптове и извлечен байткод | Няма (само статичен анализ); [пакетирани Python приложения](../python-packaged-applications.md) |
|
||||
| Изпълними файлове на Deno | Виртуални файлове, входна точка, опции и размер на npm снимката | Няма (само статичен анализ); [изпълними файлове на Deno](../deno-standalone.md) |
|
||||
|
||||
Статичната проверка на JavaScript и .NET чете предоставените файлове, без да
|
||||
стартира приложението. Записът по време на изпълнение стартира избраната цел или
|
||||
взаимодейства с нея с правата на вашия потребител; всяко ръководство за анализ по
|
||||
време на изпълнение описва какво точно прави.
|
||||
|
||||
За офлайн проверка на нативни бинарни файлове REA поддържа и предоставени от вас
|
||||
GNU objdump и Rizin. Вижте
|
||||
[ръководството за инструменти за обратно инженерство](../reverse-engineering-tools.md)
|
||||
за настройка на доставчиците, CLI командите и ограниченията на Evidence. REA не
|
||||
инсталира и не обновява нито един от двата доставчика.
|
||||
|
||||
<a id="choosing-a-deep-analysis-provider"></a>
|
||||
|
||||
Поддържаните нативни формати и операционни системи зависят от доставчика. Вижте
|
||||
[настройката на Hopper и Ghidra](../getting-started/installation.md#hopper),
|
||||
[ръководството за IDA](../providers/ida-provider.md) (включително незадължителен
|
||||
нативен MCP мост), [ръководството за декомпилатора Kuna](../kuna-provider.md) и
|
||||
[експерименталната поддръжка на Ghidra за Windows](../providers/windows-ghidra-p0.md).
|
||||
Ghidra поддържа и [анализ на 16-битов DOS код](../providers/ghidra-dos.md). За
|
||||
големи бинарни файлове увеличете времето за стартиране на доставчика с
|
||||
`REA_GHIDRA_STARTUP_TIMEOUT_MS` или `REA_HOPPER_STARTUP_TIMEOUT_MS`. За избора
|
||||
на доставчик вижте [ръководството за CLI](../getting-started/cli.md#choose-a-provider).
|
||||
Проверете [наличността в изданията](../getting-started/installation.md#released-package-and-main)
|
||||
за функции, добавени след последното издание в npm.
|
||||
|
||||
## Примери
|
||||
|
||||
<a href="https://rea.tools/showcase/">
|
||||
<picture>
|
||||
<source media="(prefers-color-scheme: dark)" srcset="../assets/rea-showcases-dark.svg" />
|
||||
<img alt="Илюстрации на примерите DX-Ball (звукова панорама), Notion (мост за клипборда) и TH04 (пръстен от куршуми)" src="../assets/rea-showcases.svg" />
|
||||
</picture>
|
||||
</a>
|
||||
|
||||
### DX-Ball: реконструиране на изчислението на звуковата панорама
|
||||
|
||||
Проследете извикване на звук до помощната функция, която превръща позицията в
|
||||
панорама, изследвайте инструкциите и превърнете непълния псевдокод в C.
|
||||
Реконструкцията минава 3 205 тестови случая спрямо оригиналния x86 код и
|
||||
възпроизвежда всичките 63 байта на компилираната функция.
|
||||
|
||||
[Прочетете казуса](https://rea.tools/showcase/dx-ball/) ·
|
||||
[Хранилище с реконструкцията](https://github.com/N0zoM1z0/dx-ball)
|
||||
|
||||
### Notion: проследяване на моста за клипборда в Electron
|
||||
|
||||
Открийте API-то за клипборда в renderer процеса, проследете го през preload
|
||||
скрипта и IPC до главния процес и изследвайте формата за форматирано съдържание
|
||||
в клипборда.
|
||||
|
||||
[Прочетете казуса](https://rea.tools/showcase/notion/)
|
||||
|
||||
### TH04: възстановяване на изчислението на пръстена от куршуми в DOS
|
||||
|
||||
Изследвайте 16-битовите инструкции на оригиналната игра за PC-98, възстановете
|
||||
изчисленията на фиксираните и насочените ъгли и сравнете реконструирания C++ код
|
||||
с изхода на историческия компилатор.
|
||||
|
||||
[Прочетете казуса](https://rea.tools/showcase/th04/) ·
|
||||
[Хранилище с реконструкцията](https://github.com/N0zoM1z0/th04)
|
||||
|
||||
### Създавайте RL среди с REA
|
||||
|
||||
Запишете сесия в уеб приложение, превърнете неговото API в инструменти и експортирайте среда, която AI агент може да използва. Стартирайте я с AgentEnv, след което добавете задачи и проверки за награда за RL обучение или оценка.
|
||||
|
||||
[Прочетете ръководството](https://rea.tools/guides/rl-environments/) ·
|
||||
[Гледайте видеото](https://x.com/reatools/status/2112574822584918075?s=20)
|
||||
|
||||
Ако сте използвали REA за нещо интересно, ще се радваме да го видим. Споделете
|
||||
случая си в [issue](https://github.com/morluto/rea/issues) или
|
||||
[pull request](https://github.com/morluto/rea/pulls), като включите целта,
|
||||
въпроса си, как ви помогна REA и какво открихте.
|
||||
|
||||
<a id="build-rl-environments"></a>
|
||||
|
||||
## Създаване на RL среди
|
||||
|
||||
Дайте на AI агент локална среда, в която да упражнява задачи като намиране на issue или създаване на папка, без да стартира оригиналното приложение. Използвайте я за обучение с подсилване (reinforcement learning, RL) или за да проверите колко добре агентът изпълнява задачи.
|
||||
|
||||
REA превръща записаните API заявки и отговори в инструменти, които агентът може да извиква. Средата използва записаните данни и поддържа промени само когато записът потвърждава ефекта им.
|
||||
|
||||
След като REA е настроен в агента ви, заменете примерния URL адрес и задачите с папки по-долу със свои:
|
||||
|
||||
```text
|
||||
Използвай REA, за да изградиш RL среда от тестовото ми уеб приложение на
|
||||
http://127.0.0.1:3000.
|
||||
Обхвани извеждането на списък, създаването, преименуването и изтриването на
|
||||
папки. Можеш да създаваш и премахваш тестови папки. Не променяй съществуващите
|
||||
данни.
|
||||
Запази я в папка с име my-env. Провери кои операции работят и ми кажи как да я
|
||||
стартирам.
|
||||
```
|
||||
|
||||
<details>
|
||||
<summary>Използвайте командния ред вместо това</summary>
|
||||
|
||||
Използвайте тези команди, ако вече имате файл със записаните от браузъра заявки и отговори на приложението. За да стартирате резултата, са нужни и AgentEnv, и Docker.
|
||||
|
||||
```sh
|
||||
rea environment-build ./session.har ./my-env --name my-env --json
|
||||
agent-env run ./my-env
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
REA експортира готова за стартиране среда с базов тест, който проверява дали тя стартира и отговаря. Използвайте я с вашата RL рамка, за да зададете целите на задачите, да добавите проверки за награда и да стартирате обучението.
|
||||
|
||||
[Изградете среда](https://rea.tools/guides/rl-environments/) ·
|
||||
[Справочник за средите](../agent-environments.md) ·
|
||||
[Гледайте демонстрацията в X](https://x.com/reatools/status/2112574822584918075?s=20)
|
||||
|
||||
### Среди за настолни приложения
|
||||
|
||||
REA може да създаде среда за Linux настолно приложение: агентът го управлява чрез снимки на екрана, мишка и клавиатура. От кратка заявка агентът инсталира приложението, създава задача, експортира средата и я проверява на нов компютър. За изграждането са необходими Linux на amd64 или arm64, Docker и версията на agentenv, посочена в ръководството.
|
||||
|
||||
[Настройка на среди за настолни приложения](../desktop-build-computer.md)
|
||||
|
||||
## Често задавани въпроси
|
||||
|
||||
<details>
|
||||
<summary><strong>Кои агенти могат да използват REA?</strong></summary>
|
||||
|
||||
Всеки агент, който поддържа локални MCP сървъри. Настройката конфигурира
|
||||
[поддържаните агенти](../getting-started/installation.md#supported-agents);
|
||||
другите клиенти могат да използват
|
||||
[ръчна MCP регистрация](../getting-started/installation.md#mcp-registry).
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><strong>Нужен ли ми е двигател за нативен анализ?</strong></summary>
|
||||
|
||||
Задълбоченият нативен анализ използва Hopper, Ghidra, IDA или Kuna в зависимост
|
||||
от целта и операцията. Статичната проверка на JavaScript и .NET работи без
|
||||
двигател за нативен анализ. Настройката може да инсталира Hopper след ваше
|
||||
одобрение; Ghidra, IDA и Kuna се използват от вече съществуващите ви инсталации.
|
||||
Вижте [настройката на доставчиците](../getting-started/installation.md#hopper)
|
||||
за възможностите и поддържаните от тях цели.
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><strong>Трябва ли първо да стартирам Hopper?</strong></summary>
|
||||
|
||||
REA стартира Hopper, когато дадена операция се нуждае от него. В macOS при първо
|
||||
стартиране може да се появи диалогов прозорец, който ви пита дали да изберете
|
||||
демо режим, или да активирате лиценза си. Завършете този диалог в същата
|
||||
потребителска сесия преди първата си CLI/MCP операция или задача, която ще се
|
||||
изпълнява без надзор. При нужда отворете Hopper ръчно. Вижте
|
||||
[стартиране и отстраняване на проблеми с Hopper](../getting-started/installation.md#launcher-paths-and-troubleshooting).
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><strong>Какво прави инсталирането на умението (skill) от skills.sh?</strong></summary>
|
||||
|
||||
Умението дава на агента ви инструкции как да провежда изследвания. Използвайте
|
||||
`npx rea-agents setup`, за да регистрирате MCP сървъра на REA и да инсталирате
|
||||
съответните инструкции, след което рестартирайте агента. Вижте
|
||||
[инсталиране само на умението](../getting-started/installation.md#skill-only-installation).
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><strong>Какъв код връща REA?</strong></summary>
|
||||
|
||||
Нативният анализ връща псевдокод и асемблер. Анализът на JavaScript/Electron
|
||||
възстановява модулите и връзките между тях. Агентът ви използва тези
|
||||
констатации, за да напише и тества реализация; [примерите](#примери) показват
|
||||
цялостни разработени случаи.
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><strong>Качва ли REA приложението ми някъде?</strong></summary>
|
||||
|
||||
REA анализира целите локално. Агентът ви получава резултатите от инструментите,
|
||||
а доставчикът на модела, който агентът използва, има собствена политика за
|
||||
данните.
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><strong>Какво да направя, ако попадна на грешка?</strong></summary>
|
||||
|
||||
Първо обновете; възможно е скорошно издание вече да я е поправило.
|
||||
|
||||
За CLI, инсталиран с `npm install --global` или `bun add --global`:
|
||||
|
||||
```bash
|
||||
rea update
|
||||
```
|
||||
|
||||
За настройка на агента чрез `npx`:
|
||||
|
||||
```bash
|
||||
npx rea-agents@latest setup
|
||||
```
|
||||
|
||||
Ако използвате агент, извършете
|
||||
[опресняването на настройката](#обновяване-на-rea) и го рестартирайте. Опитайте
|
||||
отново същата задача. Ако проблемът продължава,
|
||||
[отворете issue](https://github.com/morluto/rea/issues), като посочите версията
|
||||
на REA, типа на целта, стъпките за възпроизвеждане и изхода с грешката.
|
||||
|
||||
</details>
|
||||
|
||||
## Документация
|
||||
|
||||
Започнете с [практическите ръководства](https://rea.tools/guides/) на уебсайта.
|
||||
За точните опции, предварителните изисквания и договорите за резултатите:
|
||||
|
||||
- [Инсталиране и настройка](../getting-started/installation.md): регистриране на агенти, конфигуриране на доставчици, обновяване и деинсталиране.
|
||||
- [Готовност и отстраняване на проблеми](../getting-started/installation.md#check-readiness-for-your-task): диагностика на конкретен агент или двигател за анализ.
|
||||
- [CLI и Evidence](../getting-started/cli.md): команди, избор на доставчик, моментни снимки, импорт/експорт и изходни статуси.
|
||||
- [MCP договори](../reference/mcp-contracts.md) и [подсказки за агенти](../getting-started/mcp-prompts.md): резултати от инструментите, сесии и насочвани изследвания.
|
||||
- [Каталог с инструменти](../reference/mcp-contracts.md#generated-catalog): генериран списък с инструменти, доставчици и CLI команди.
|
||||
- [Пътна карта](../development/roadmap.md): планирана работа и проследяване на възможностите.
|
||||
|
||||
Съобщавайте за уязвимости чрез [SECURITY.md](../../SECURITY.md).
|
||||
|
||||
## История на звездите
|
||||
|
||||
🎉 **400 000 звезди в GitHub — благодарим ви!**
|
||||
|
||||
Благодарим на всички, които използват REA, съобщават за грешки, предлагат нови функции, тестват версии и допринасят с поправки.
|
||||
|
||||
<a href="https://www.star-history.com/?repos=morluto%2Frea&type=date">
|
||||
<picture>
|
||||
<source media="(prefers-color-scheme: dark)" srcset="https://api.star-history.com/chart?repos=morluto/rea&type=date&theme=dark&legend=top-left" />
|
||||
<source media="(prefers-color-scheme: light)" srcset="https://api.star-history.com/chart?repos=morluto/rea&type=date" />
|
||||
<img alt="История на звездите на REA в GitHub" src="https://api.star-history.com/chart?repos=morluto/rea&type=date" />
|
||||
</picture>
|
||||
</a>
|
||||
|
||||
## Отказ от отговорност
|
||||
|
||||
Вижте [DISCLAIMER.md](../../DISCLAIMER.md) за насоки за отговорна употреба.
|
||||
|
||||
Позицията на проекта относно незаконната или неразрешената употреба обхваща
|
||||
всички версии, канали за разпространение и платформи на REA; всяко копие запазва
|
||||
приложимите за него лицензи.
|
||||
|
||||
REA е предназначен за законни изследвания, обучение, оперативна съвместимост,
|
||||
съхраняване на софтуер и анализ на софтуер, който притежавате или имате
|
||||
разрешение да изследвате.
|
||||
|
||||
## Принос към проекта
|
||||
|
||||
Ще се радваме на помощта ви с REA! [Отворете issue](https://github.com/morluto/rea/issues),
|
||||
за да съобщите за грешка или да предложите функция, или
|
||||
[изпратете pull request](https://github.com/morluto/rea/pulls), за да подобрите
|
||||
кода или документацията.
|
||||
|
||||
Вижте [CONTRIBUTING.md](../../CONTRIBUTING.md) за настройка на средата за
|
||||
разработка и проверките, [тестване](../development/testing.md) за видовете
|
||||
проверки и [картата на архитектурата](../architecture/architecture.mermaid) за
|
||||
избрани слоеве и пътища на зависимостите.
|
||||
|
||||
## Лиценз
|
||||
|
||||
[MIT](../../LICENSE)
|
||||
|
||||
Кодът, написан за проекта REA, е лицензиран под MIT. Материалите от трети страни
|
||||
запазват собствените си лицензи и бележки за авторски права; вижте
|
||||
[бележките за трети страни](../../THIRD_PARTY_NOTICES.md) за списъка със
|
||||
зависимости, запазените текстове на лицензите и условията на външните
|
||||
инструменти.
|
||||
|
||||
**Трябва да сте придобили законно търговските инструменти и да имате право да ги
|
||||
използвате**, включително IDA Pro / декомпилаторите на Hex-Rays, Hopper и JEB,
|
||||
съгласно приложимите им лицензи. REA не предоставя лиценз, ключ или право на
|
||||
активиране за нито един инструмент. Пробните и демо версиите остават обект на
|
||||
условията на производителя, включително ограниченията за брой потребители,
|
||||
функции, автоматизация и споделяне на резултатите. Кракнати копия, откраднати
|
||||
ключове, неразрешено споделяне на ключове и заобикаляне на лицензионни
|
||||
ограничения не са разрешени. Тези насоки не изменят лиценза MIT или лицензите на
|
||||
трети страни.
|
||||
@@ -1,7 +1,7 @@
|
||||
<div align="center">
|
||||
|
||||
[English](../../README.md) · [简体中文](README_zh.md) · [繁體中文](README_zh-TW.md) · [日本語](README_ja.md) · [한국어](README_ko.md) · [Türkçe](README_tr.md) · [Русский](README_ru.md) · [Tiếng Việt](README_vi.md) · [ไทย](README_th.md) · **Deutsch** · [Español](README_es.md) · [Français](README_fr.md) · [Українська](README_uk.md) · [Polski](README_pl.md) · [Português (Brasil)](README_pt-BR.md) · [العربية](README_ar.md) · [فارسی](README_fa.md) · [Bahasa Indonesia](README_id.md) · [Italiano](README_it.md)
|
||||
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md) · [Roman Urdu](README_ur-Latn.md) · [Română](README_ro.md)
|
||||
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md) · [Roman Urdu](README_ur-Latn.md) · [Română](README_ro.md) · [Български](README_bg.md)
|
||||
|
||||
# REA: Alles reverse-engineeren
|
||||
|
||||
@@ -84,6 +84,10 @@ Die Einrichtung unterstützt Claude Code, Codex, Cursor, Gemini CLI, Grok Build
|
||||
|
||||
MCP verwendet standardmäßig kompakte Eingabeschemas. Für vollständige Feldhinweise und Details zur verschachtelten Validierung setze `REA_MCP_INPUT_SCHEMA_PROFILE=full` in der MCP-Registrierung. Beide Profile behalten alle Tools und dieselbe kanonische Servervalidierung; siehe MCP-Vertragsleitfaden.
|
||||
|
||||
Die Einrichtung registriert die gewählte Laufzeit und das REA-Einstiegsskript direkt. Bewahre bei einem Paket-Runner dessen Cache-Eintrag und die Laufzeit auf; lade das Paket aus einem vertrauenswürdigen Verzeichnis außerhalb des Zielprojekts. Siehe die Installationsanleitung.
|
||||
|
||||
Vollständige Ausgabeschemas werden standardmäßig angekündigt. Begrenzt dein Client `tools/list`, setze in der MCP-Registrierung `REA_MCP_OUTPUT_SCHEMA_PROFILE=compact` oder `off`. Servervalidierung und strukturierte Ergebnisse bleiben vollständig. Siehe „Output schemas“ im MCP-Vertragsleitfaden.
|
||||
|
||||
### Deinen Agenten fragen
|
||||
|
||||
```text
|
||||
@@ -157,6 +161,7 @@ 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) |
|
||||
@@ -172,6 +177,7 @@ REA benötigt Node.js 22.x (>=22.23.4), 24.x (>=24.22.1) oder 26+ (>=26.12.1) so
|
||||
| Paketerfassungen | Endpunkte, DNS, TLS SNI, Protokollverteilung und HTTP-Anfragen | Vom Aufrufer bereitgestellte tshark- und capinfos-Binaries; [pcap-Leitfaden](../guides/data/pcap-analysis.md) |
|
||||
| .NET-Assemblies | Metadaten, CIL-Anweisungen, deklarierte native Abhängigkeiten und Build-Vergleiche | Statische Untersuchung; [Leitfaden für verwalteten Code](../guides/managed/managed-code-analysis.md) |
|
||||
| PyInstaller | CArchive, PYZ, Python bytecode | Static inspection; [Python packaged applications](../python-packaged-applications.md) |
|
||||
| Deno compile binaries | Virtual files, entry point, recorded options, npm snapshot length | Static inspection; [Deno compile executables](../deno-standalone.md) |
|
||||
| Android-APKs | Manifest-Deklarationen, Klassen, dekompilierte Methoden und Verweise | JADX ohne grafische Oberfläche und ein vollständiges JDK unter Linux/macOS/Windows x64; [Android-Leitfaden](../guides/android/android-analysis.md) |
|
||||
| Android-Geräte | Geräte, Pakete, Prozesse, Logs, Dumps, Bildschirmaufnahmen sowie APK- und Dateiübertragungen | Vom Aufrufer bereitgestelltes adb (Emulator oder Gerät); [ADB-Leitfaden](../guides/android/adb-device-analysis.md) |
|
||||
| JEB-Projekte | Engine-gestützte Projekteinheiten, Artefakt-Prüfsummen und Pseudokode von Typen/Methoden | Ein vom Aufrufer gestarteter JEB-Client mit MCP, ausgewählt über REA_JEB_MCP_URL; [JEB-Leitfaden](../providers/jeb-analysis.md) |
|
||||
@@ -273,6 +279,12 @@ REA exportiert eine lauffähige Umgebung mit einem einfachen Test, der prüft, o
|
||||
[Umgebungsreferenz](../agent-environments.md) ·
|
||||
[Demo auf X ansehen](https://x.com/reatools/status/2112574822584918075?s=20)
|
||||
|
||||
### Desktop-App-Umgebungen
|
||||
|
||||
REA kann auch eine Umgebung für eine Linux-Desktop-App erstellen, die ein Agent über Screenshots, Maus und Tastatur bedient. Aus einer einzeiligen Anfrage wie „Erstelle mir eine Gnote-Umgebung, in der der Agent der Einkaufslisten-Notiz Olivenöl hinzufügt“ installiert dein Agent die App auf einem lokalen Build-Computer, schreibt die Aufgabe, exportiert die Umgebung und prüft die Aufgabe auf einem frischen Computer. Der Rechner, der sie erstellt, braucht Linux auf amd64 oder arm64, Docker und die Version des agentenv-Frameworks, die der Leitfaden festlegt.
|
||||
|
||||
[Desktop-App-Umgebungen einrichten](../desktop-build-computer.md)
|
||||
|
||||
## Häufige Fragen
|
||||
|
||||
<details>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<div align="center">
|
||||
|
||||
[English](../../README.md) · [简体中文](README_zh.md) · [繁體中文](README_zh-TW.md) · [日本語](README_ja.md) · [한국어](README_ko.md) · [Türkçe](README_tr.md) · [Русский](README_ru.md) · [Tiếng Việt](README_vi.md) · [ไทย](README_th.md) · [Deutsch](README_de.md) · [Español](README_es.md) · [Français](README_fr.md) · [Українська](README_uk.md) · [Polski](README_pl.md) · [Português (Brasil)](README_pt-BR.md) · [العربية](README_ar.md) · [فارسی](README_fa.md) · [Bahasa Indonesia](README_id.md) · [Italiano](README_it.md) · **Ελληνικά** · [മലയാളം](README_ml.md) · [Roman Urdu](README_ur-Latn.md) · [Română](README_ro.md)
|
||||
[English](../../README.md) · [简体中文](README_zh.md) · [繁體中文](README_zh-TW.md) · [日本語](README_ja.md) · [한국어](README_ko.md) · [Türkçe](README_tr.md) · [Русский](README_ru.md) · [Tiếng Việt](README_vi.md) · [ไทย](README_th.md) · [Deutsch](README_de.md) · [Español](README_es.md) · [Français](README_fr.md) · [Українська](README_uk.md) · [Polski](README_pl.md) · [Português (Brasil)](README_pt-BR.md) · [العربية](README_ar.md) · [فارسی](README_fa.md) · [Bahasa Indonesia](README_id.md) · [Italiano](README_it.md) · **Ελληνικά** · [മലയാളം](README_ml.md) · [Roman Urdu](README_ur-Latn.md) · [Română](README_ro.md) · [Български](README_bg.md)
|
||||
|
||||
# REA: Reverse Engineer Anything
|
||||
|
||||
@@ -86,6 +86,10 @@ npx rea-agents setup
|
||||
|
||||
Το MCP χρησιμοποιεί συμπαγή σχήματα εισόδου από προεπιλογή. Για πλήρεις οδηγίες πεδίων και ένθετης επικύρωσης, όρισε `REA_MCP_INPUT_SCHEMA_PROFILE=full` στην καταχώριση MCP. Και τα δύο προφίλ διατηρούν όλα τα εργαλεία και την ίδια κανονική επικύρωση διακομιστή· δες τον οδηγό συμβολαίων MCP.
|
||||
|
||||
Η εγκατάσταση καταχωρίζει απευθείας τον επιλεγμένο runtime και το αρχικό script του REA. Αν χρησιμοποιείς package runner, διατήρησε την καταχώριση cache και τον runtime· απόκτησε το πακέτο από έμπιστο κατάλογο έξω από το έργο-στόχο. Δες τον οδηγό εγκατάστασης.
|
||||
|
||||
Τα πλήρη σχήματα εξόδου ανακοινώνονται από προεπιλογή. Αν ο client περιορίζει το `tools/list`, όρισε `REA_MCP_OUTPUT_SCHEMA_PROFILE=compact` ή `off` στην καταχώριση MCP. Η επικύρωση του διακομιστή και τα δομημένα αποτελέσματα παραμένουν πλήρη. Δες το «Output schemas» στον οδηγό συμβάσεων MCP.
|
||||
|
||||
### Ζήτησε από τον agent σου
|
||||
|
||||
```text
|
||||
@@ -159,6 +163,7 @@ 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) |
|
||||
@@ -174,6 +179,7 @@ npx rea-agents@latest setup
|
||||
| Αποθηκευμένες καταγραφές δικτύου | Αιτήματα, αποκρίσεις, διαθέσιμα δεδομένα φορτίου και θέσεις στην πηγή | HAR ή SAZ του Fiddler Everywhere· mitmdump σε Linux για την εγγενή μορφή mitmproxy· [οδηγός καταγραφών](../guides/web/web-network-captures.md) |
|
||||
| Assemblies .NET | Μεταδεδομένα, εντολές CIL, δηλωμένες εξαρτήσεις από κώδικα μηχανής και συγκρίσεις builds | Καμία πρόσθετη απαίτηση (μόνο στατική ανάλυση)· [οδηγός διαχειριζόμενου κώδικα](../guides/managed/managed-code-analysis.md) |
|
||||
| PyInstaller | CArchive, PYZ, Python bytecode | Static inspection; [Python packaged applications](../python-packaged-applications.md) |
|
||||
| Deno compile binaries | Virtual files, entry point, recorded options, npm snapshot length | Static inspection; [Deno compile executables](../deno-standalone.md) |
|
||||
| APK Android | Δηλώσεις manifest, κλάσεις, απομεταγλωττισμένες μέθοδοι και αναφορές | JADX χωρίς γραφικό περιβάλλον και πλήρες JDK σε Linux/macOS/Windows x64· [οδηγός Android](../guides/android/android-analysis.md) |
|
||||
| Συσκευές Android | Συσκευές, πακέτα, διεργασίες, logs, dumps, στιγμιότυπα οθόνης και μεταφορές APK/αρχείων | adb που παρέχει ο χρήστης (εξομοιωτής ή φυσική συσκευή)· [οδηγός ADB](../guides/android/adb-device-analysis.md) |
|
||||
| Έργα JEB | Μονάδες έργου από τη μηχανή ανάλυσης, ψηφιακά αποτυπώματα αρχείων και ψευδοκώδικα τύπων/μεθόδων | Client JEB που έχει ξεκινήσει ο χρήστης και παρέχει MCP, επιλεγμένος μέσω REA_JEB_MCP_URL· [οδηγός JEB](../providers/jeb-analysis.md) |
|
||||
@@ -275,6 +281,12 @@ agent-env run ./my-env
|
||||
[Αναφορά περιβαλλόντων](../agent-environments.md) ·
|
||||
[Δείτε το demo στο X](https://x.com/reatools/status/2112574822584918075?s=20)
|
||||
|
||||
### Περιβάλλοντα εφαρμογών επιφάνειας εργασίας
|
||||
|
||||
Το REA μπορεί επίσης να δημιουργήσει περιβάλλον για μια εφαρμογή επιφάνειας εργασίας Linux, την οποία ο πράκτορας χρησιμοποιεί μέσω στιγμιότυπων οθόνης, ποντικιού και πληκτρολογίου. Από ένα αίτημα μίας γραμμής, όπως «Φτιάξε μου ένα περιβάλλον Gnote όπου ο πράκτορας προσθέτει ελαιόλαδο στη σημείωση με τη λίστα αγορών», ο πράκτοράς σας εγκαθιστά την εφαρμογή σε έναν τοπικό υπολογιστή κατασκευής, γράφει την εργασία, εξάγει το περιβάλλον και ελέγχει την εργασία σε έναν νέο υπολογιστή. Ο υπολογιστής που το κατασκευάζει χρειάζεται Linux σε amd64 ή arm64, Docker και την έκδοση του πλαισίου agentenv που ορίζει ο οδηγός.
|
||||
|
||||
[Ρύθμιση περιβαλλόντων εφαρμογών επιφάνειας εργασίας](../desktop-build-computer.md)
|
||||
|
||||
## Συχνές ερωτήσεις
|
||||
|
||||
<details>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<div align="center">
|
||||
|
||||
[English](../../README.md) · [简体中文](README_zh.md) · [繁體中文](README_zh-TW.md) · [日本語](README_ja.md) · [한국어](README_ko.md) · [Türkçe](README_tr.md) · [Русский](README_ru.md) · [Tiếng Việt](README_vi.md) · [ไทย](README_th.md) · [Deutsch](README_de.md) · **Español** · [Français](README_fr.md) · [Українська](README_uk.md) · [Polski](README_pl.md) · [Português (Brasil)](README_pt-BR.md) · [العربية](README_ar.md) · [فارسی](README_fa.md) · [Bahasa Indonesia](README_id.md) · [Italiano](README_it.md)
|
||||
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md) · [Roman Urdu](README_ur-Latn.md) · [Română](README_ro.md)
|
||||
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md) · [Roman Urdu](README_ur-Latn.md) · [Română](README_ro.md) · [Български](README_bg.md)
|
||||
|
||||
# REA: Ingeniería inversa de cualquier cosa
|
||||
|
||||
@@ -84,6 +84,10 @@ La configuración admite Claude Code, Codex, Cursor, Gemini CLI, Grok Build y [o
|
||||
|
||||
MCP usa esquemas de entrada compactos por defecto. Para ver todas las instrucciones de campos y la validación anidada, establece `REA_MCP_INPUT_SCHEMA_PROFILE=full` en el registro MCP. Ambos perfiles conservan todas las herramientas y la misma validación canónica del servidor; consulta la guía de contratos MCP.
|
||||
|
||||
La configuración registra directamente el entorno de ejecución elegido y el script de entrada de REA. Si usas un ejecutor de paquetes, conserva su entrada de caché y el entorno de ejecución; descarga el paquete desde un directorio de confianza fuera del proyecto objetivo. Consulta la guía de instalación.
|
||||
|
||||
Los esquemas de salida completos se anuncian por defecto. Si tu cliente limita `tools/list`, establece `REA_MCP_OUTPUT_SCHEMA_PROFILE=compact` o `off` en el registro MCP. La validación del servidor y los resultados estructurados siguen siendo completos. Consulta «Output schemas» en la guía de contratos MCP.
|
||||
|
||||
### Pregunta a tu agente
|
||||
|
||||
```text
|
||||
@@ -157,6 +161,7 @@ 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) |
|
||||
@@ -172,6 +177,7 @@ REA requiere Node.js 22.x (>=22.23.4), 24.x (>=24.22.1) o 26+ (>=26.12.1), adem
|
||||
| Capturas de paquetes | Endpoints, DNS, TLS SNI, distribución de protocolos y solicitudes HTTP | tshark y capinfos suministrados por el autor de la llamada; [guía pcap](../guides/data/pcap-analysis.md) |
|
||||
| Ensamblados .NET | Metadatos, instrucciones CIL, dependencias nativas declaradas y comparaciones de compilaciones | Inspección estática; [guía de código administrado](../guides/managed/managed-code-analysis.md) |
|
||||
| PyInstaller | CArchive, PYZ, Python bytecode | Static inspection; [Python packaged applications](../python-packaged-applications.md) |
|
||||
| Deno compile binaries | Virtual files, entry point, recorded options, npm snapshot length | Static inspection; [Deno compile executables](../deno-standalone.md) |
|
||||
| APK de Android | Declaraciones del manifiesto, clases, métodos descompilados y referencias | JADX sin interfaz gráfica y un JDK completo en Linux/macOS/Windows x64; [guía de Android](../guides/android/android-analysis.md) |
|
||||
| Dispositivos Android | Dispositivos, paquetes, procesos, registros, volcados, capturas de pantalla y transferencias de APK/archivos | adb suministrado por el autor de la llamada (emulador o dispositivo); [guía de ADB](../guides/android/adb-device-analysis.md) |
|
||||
| Proyectos JEB | Unidades de proyecto del motor, resúmenes de artefactos y pseudocódigo de tipos/métodos | Un cliente JEB iniciado por el autor de la llamada que sirve MCP, seleccionado con REA_JEB_MCP_URL; [guía de JEB](../providers/jeb-analysis.md) |
|
||||
@@ -273,6 +279,12 @@ REA exporta un entorno ejecutable con una prueba básica que comprueba que arran
|
||||
[Referencia de entornos](../agent-environments.md) ·
|
||||
[Ver la demo en X](https://x.com/reatools/status/2112574822584918075?s=20)
|
||||
|
||||
### Entornos de aplicaciones de escritorio
|
||||
|
||||
REA también puede crear un entorno de una aplicación de escritorio de Linux, que un agente usa mediante capturas de pantalla, el ratón y el teclado. A partir de una petición de una línea, como «Créame un entorno de Gnote en el que el agente añada aceite de oliva a la nota de la lista de la compra», tu agente instala la aplicación en un ordenador de compilación local, escribe la tarea, exporta el entorno y comprueba la tarea en un ordenador nuevo. El equipo que lo crea necesita Linux en amd64 o arm64, Docker y la versión del framework agentenv que fija la guía.
|
||||
|
||||
[Configurar entornos de aplicaciones de escritorio](../desktop-build-computer.md)
|
||||
|
||||
## Preguntas frecuentes
|
||||
|
||||
<details>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<div align="center" dir="rtl">
|
||||
|
||||
[English](../../README.md) · [简体中文](README_zh.md) · [繁體中文](README_zh-TW.md) · [日本語](README_ja.md) · [한국어](README_ko.md) · [Türkçe](README_tr.md) · [Русский](README_ru.md) · [Tiếng Việt](README_vi.md) · [ไทย](README_th.md) · [Deutsch](README_de.md) · [Español](README_es.md) · [Français](README_fr.md) · [Українська](README_uk.md) · [Polski](README_pl.md) · [Português (Brasil)](README_pt-BR.md) · [العربية](README_ar.md) · **فارسی** · [Bahasa Indonesia](README_id.md) · [Italiano](README_it.md)
|
||||
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md) · [Roman Urdu](README_ur-Latn.md) · [Română](README_ro.md)
|
||||
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md) · [Roman Urdu](README_ur-Latn.md) · [Română](README_ro.md) · [Български](README_bg.md)
|
||||
|
||||
# REA: مهندسی معکوس هر چیزی
|
||||
|
||||
@@ -76,6 +76,10 @@ npx rea-agents setup
|
||||
|
||||
MCP بهطور پیشفرض از schema ورودی فشرده استفاده میکند. برای راهنمای کامل فیلدها و اعتبارسنجی تودرتو، در ثبت MCP مقدار `REA_MCP_INPUT_SCHEMA_PROFILE=full` را تنظیم کنید. هر دو حالت همهٔ ابزارها و اعتبارسنجی استاندارد یکسان سرور را نگه میدارند؛ راهنمای قراردادهای MCP را ببینید.
|
||||
|
||||
راهاندازی، محیط اجرای انتخابشده و اسکریپت ورودی REA را مستقیماً ثبت میکند. اگر از اجراکنندهٔ بسته استفاده میکنید، ورودی حافظهٔ پنهان و محیط اجرا را حفظ کنید؛ بسته را از پوشهای قابل اعتماد خارج از پروژهٔ هدف دریافت کنید. راهنمای نصب را ببینید.
|
||||
|
||||
طرحهای خروجی کامل بهطور پیشفرض اعلام میشوند. اگر کلاینت `tools/list` را محدود میکند، در ثبت MCP مقدار `REA_MCP_OUTPUT_SCHEMA_PROFILE=compact` یا `off` را تنظیم کنید. اعتبارسنجی سرور و نتایج ساختیافته کامل میمانند. بخش «Output schemas» در راهنمای قراردادهای MCP را ببینید.
|
||||
|
||||
### از ایجنت خود بپرسید
|
||||
|
||||
```text
|
||||
@@ -149,6 +153,7 @@ 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) |
|
||||
@@ -163,6 +168,7 @@ REA به Node.js 22.x (>=22.23.4)، 24.x (>=24.22.1) یا 26+ (>=26.12.1)، به
|
||||
| دادههای ضبطشدهٔ شبکه | درخواستها، پاسخها، payloadهای آشکارشده و مکان آنها در منبع | HAR / Fiddler Everywhere SAZ؛ ابزار mitmdump در لینوکس برای ضبطهای بومی mitmproxy؛ [راهنمای ضبط شبکه](../guides/web/web-network-captures.md) |
|
||||
| اسمبلیهای .NET | فراداده، دستورالعملهای CIL، وابستگیهای بومی اعلامشده و مقایسهٔ buildها | بررسی ایستا؛ [راهنمای کد مدیریتشده](../guides/managed/managed-code-analysis.md) |
|
||||
| PyInstaller | CArchive, PYZ, Python bytecode | Static inspection; [Python packaged applications](../python-packaged-applications.md) |
|
||||
| Deno compile binaries | Virtual files, entry point, recorded options, npm snapshot length | Static inspection; [Deno compile executables](../deno-standalone.md) |
|
||||
| فایلهای APK اندروید | تعاریف Manifest، کلاسها، متدهای دیکامپایلشده و ارجاعات | JADX بدون رابط گرافیکی و JDK کامل در Linux/macOS/Windows x64؛ [راهنمای اندروید](../guides/android/android-analysis.md) |
|
||||
| دستگاههای اندروید | دستگاهها، بستهها، فرایندها، لاگها، دامپها، اسکرینشاتها و انتقال APK/فایل | adb تأمینشده توسط فراخوانکننده (شبیهساز یا دستگاه)؛ [راهنمای ADB](../guides/android/adb-device-analysis.md) |
|
||||
| پروژههای JEB | واحدهای پروژه از موتور، هشهای مصنوع و شبهکدِ نوع/متد | یک کلاینت JEB که توسط فراخوانکننده اجرا شده و MCP ارائه میدهد و با REA_JEB_MCP_URL انتخاب میشود؛ [راهنمای JEB](../providers/jeb-analysis.md) |
|
||||
@@ -265,6 +271,12 @@ REA محیطی آمادهٔ اجرا همراه با یک آزمون ساده ب
|
||||
[مرجع محیطها](../agent-environments.md) ·
|
||||
[نمایش را در X ببینید](https://x.com/reatools/status/2112574822584918075?s=20)
|
||||
|
||||
### محیطهای برنامههای دسکتاپ
|
||||
|
||||
REA میتواند برای یک برنامهٔ دسکتاپ Linux هم محیط بسازد که عامل با تصویر صفحه، ماوس و صفحهکلید از آن استفاده میکند. از یک درخواست یکخطی، مثل «یک محیط Gnote برایم بساز که در آن عامل روغن زیتون را به یادداشت فهرست خرید اضافه کند»، عامل شما برنامه را روی یک رایانهٔ ساخت محلی نصب میکند، کار را مینویسد، محیط را صادر میکند و کار را روی یک رایانهٔ تازه بررسی میکند. دستگاهی که آن را میسازد به Linux روی amd64 یا arm64، Docker و نسخهای از چارچوب agentenv که راهنما تعیین کرده نیاز دارد.
|
||||
|
||||
[راهاندازی محیطهای برنامههای دسکتاپ](../desktop-build-computer.md)
|
||||
|
||||
## پرسشهای متداول
|
||||
|
||||
<details><summary><strong>کدام ایجنتها میتوانند از REA استفاده کنند؟</strong></summary>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<div align="center">
|
||||
|
||||
[English](../../README.md) · [简体中文](README_zh.md) · [繁體中文](README_zh-TW.md) · [日本語](README_ja.md) · [한국어](README_ko.md) · [Türkçe](README_tr.md) · [Русский](README_ru.md) · [Tiếng Việt](README_vi.md) · [ไทย](README_th.md) · [Deutsch](README_de.md) · [Español](README_es.md) · **Français** · [Українська](README_uk.md) · [Polski](README_pl.md) · [Português (Brasil)](README_pt-BR.md) · [العربية](README_ar.md) · [فارسی](README_fa.md) · [Bahasa Indonesia](README_id.md) · [Italiano](README_it.md)
|
||||
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md) · [Roman Urdu](README_ur-Latn.md) · [Română](README_ro.md)
|
||||
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md) · [Roman Urdu](README_ur-Latn.md) · [Română](README_ro.md) · [Български](README_bg.md)
|
||||
|
||||
# REA : rétro-ingénierie de tout
|
||||
|
||||
@@ -84,6 +84,10 @@ Setup prend en charge Claude Code, Codex, Cursor, Gemini CLI, Grok Build et [d'a
|
||||
|
||||
MCP utilise par défaut des schémas d’entrée compacts. Pour les descriptions complètes des champs et de la validation imbriquée, définissez `REA_MCP_INPUT_SCHEMA_PROFILE=full` dans l’enregistrement MCP. Les deux profils conservent tous les outils et la même validation canonique du serveur ; voir le guide des contrats MCP.
|
||||
|
||||
La configuration enregistre directement le runtime choisi et le script d’entrée de REA. Avec un exécuteur de paquets, conservez son entrée de cache et le runtime ; récupérez le paquet depuis un répertoire de confiance hors du projet cible. Consultez le guide d’installation.
|
||||
|
||||
Les schémas de sortie complets sont annoncés par défaut. Si votre client limite `tools/list`, définissez `REA_MCP_OUTPUT_SCHEMA_PROFILE=compact` ou `off` dans l’enregistrement MCP. La validation du serveur et les résultats structurés restent complets. Consultez « Output schemas » dans le guide des contrats MCP.
|
||||
|
||||
### Interroger votre agent
|
||||
|
||||
```text
|
||||
@@ -156,6 +160,7 @@ 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) |
|
||||
@@ -172,6 +177,7 @@ REA nécessite Node.js 22.x (>=22.23.4), 24.x (>=24.22.1) ou 26+ (>=26.12.1), ai
|
||||
| Captures de paquets | Points de terminaison, DNS, TLS SNI, distribution des protocoles et requêtes HTTP | tshark et capinfos fournis par l'appelant ; [guide pcap](../guides/data/pcap-analysis.md) |
|
||||
| Assemblys .NET | Métadonnées, instructions CIL, dépendances natives déclarées et comparaisons de builds | Inspection statique ; [guide du code managé](../guides/managed/managed-code-analysis.md) |
|
||||
| PyInstaller | CArchive, PYZ, Python bytecode | Static inspection; [Python packaged applications](../python-packaged-applications.md) |
|
||||
| Deno compile binaries | Virtual files, entry point, recorded options, npm snapshot length | Static inspection; [Deno compile executables](../deno-standalone.md) |
|
||||
| APK Android | Déclarations du manifeste, classes, méthodes décompilées et références | JADX headless et un JDK complet sous Linux/macOS/Windows x64 ; [guide Android](../guides/android/android-analysis.md) |
|
||||
| Appareils Android | Appareils, paquets, processus, journaux, dumps, captures d'écran et transferts d'APK/fichiers | adb fourni par l'appelant (émulateur ou appareil) ; [guide ADB](../guides/android/adb-device-analysis.md) |
|
||||
| Projets JEB | Unités de projet fournies par le moteur, condensés d'artefacts et pseudo-code de types/méthodes | Un client JEB démarré par l'appelant servant MCP, sélectionné via REA_JEB_MCP_URL ; [guide JEB](../providers/jeb-analysis.md) |
|
||||
@@ -270,6 +276,12 @@ REA exporte un environnement exécutable avec un test de base qui vérifie qu’
|
||||
[Référence des environnements](../agent-environments.md) ·
|
||||
[Voir la démo sur X](https://x.com/reatools/status/2112574822584918075?s=20)
|
||||
|
||||
### Environnements d’applications de bureau
|
||||
|
||||
REA peut aussi créer un environnement pour une application de bureau Linux, qu’un agent utilise par captures d’écran, souris et clavier. À partir d’une demande d’une ligne, comme « Crée-moi un environnement Gnote où l’agent ajoute de l’huile d’olive à la note de liste de courses », votre agent installe l’application sur un ordinateur de construction local, rédige la tâche, exporte l’environnement et vérifie la tâche sur un ordinateur neuf. La machine qui le construit a besoin de Linux sur amd64 ou arm64, de Docker et de la version du framework agentenv fixée par le guide.
|
||||
|
||||
[Configurer les environnements d’applications de bureau](../desktop-build-computer.md)
|
||||
|
||||
## Questions fréquentes
|
||||
|
||||
<details>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<div align="center">
|
||||
|
||||
[English](../../README.md) · [简体中文](README_zh.md) · [繁體中文](README_zh-TW.md) · [日本語](README_ja.md) · [한국어](README_ko.md) · [Türkçe](README_tr.md) · [Русский](README_ru.md) · [Tiếng Việt](README_vi.md) · [ไทย](README_th.md) · [Deutsch](README_de.md) · [Español](README_es.md) · [Français](README_fr.md) · [Українська](README_uk.md) · [Polski](README_pl.md) · [Português (Brasil)](README_pt-BR.md) · [العربية](README_ar.md) · [فارسی](README_fa.md) · **Bahasa Indonesia** · [Italiano](README_it.md)
|
||||
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md) · [Roman Urdu](README_ur-Latn.md) · [Română](README_ro.md)
|
||||
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md) · [Roman Urdu](README_ur-Latn.md) · [Română](README_ro.md) · [Български](README_bg.md)
|
||||
|
||||
# REA: Rekayasa Balik Apa Pun
|
||||
|
||||
@@ -84,6 +84,10 @@ Penyiapan mendukung Claude Code, Codex, Cursor, Gemini CLI, Grok Build, dan [age
|
||||
|
||||
MCP menggunakan skema input ringkas secara default. Untuk petunjuk bidang lengkap dan validasi bertingkat, atur `REA_MCP_INPUT_SCHEMA_PROFILE=full` pada pendaftaran MCP. Kedua profil mempertahankan semua alat dan validasi server kanonis yang sama; lihat panduan kontrak MCP.
|
||||
|
||||
Setup mencatat runtime yang dipilih dan skrip masuk REA secara langsung. Jika memakai package runner, pertahankan entri cache dan runtime tersebut; unduh paket dari direktori tepercaya di luar proyek target. Lihat panduan instalasi.
|
||||
|
||||
Skema keluaran lengkap diumumkan secara default. Jika klien membatasi `tools/list`, atur `REA_MCP_OUTPUT_SCHEMA_PROFILE=compact` atau `off` dalam registrasi MCP. Validasi server dan hasil terstruktur tetap lengkap. Lihat «Output schemas» di panduan kontrak MCP.
|
||||
|
||||
### Minta agen Anda
|
||||
|
||||
```text
|
||||
@@ -159,6 +163,7 @@ 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) |
|
||||
@@ -175,6 +180,7 @@ Alat tambahan dan dukungan sistem host bergantung pada target yang dianalisis:
|
||||
| Capturan paket | Endpoint, DNS, TLS SNI, distribusi protokol, dan permintaan HTTP | tshark dan capinfos buatan pemanggil; [panduan pcap](../guides/data/pcap-analysis.md) |
|
||||
| Assembly .NET | Metadata, instruksi CIL, dependensi native yang dideklarasikan, dan perbandingan build | Tidak ada (hanya analisis statis); [panduan kode terkelola](../guides/managed/managed-code-analysis.md) |
|
||||
| PyInstaller | CArchive, PYZ, Python bytecode | Static inspection; [Python packaged applications](../python-packaged-applications.md) |
|
||||
| Deno compile binaries | Virtual files, entry point, recorded options, npm snapshot length | Static inspection; [Deno compile executables](../deno-standalone.md) |
|
||||
| APK Android | Deklarasi manifest, kelas, metode hasil dekompilasi, dan referensi | JADX mode headless dan JDK lengkap di Linux/macOS/Windows x64; [panduan Android](../guides/android/android-analysis.md) |
|
||||
| Perangkat Android | Perangkat, paket, proses, log, dump, tangkapan layar, serta transfer APK/berkas | adb buatan pemanggil (emulator atau perangkat); [panduan ADB](../guides/android/adb-device-analysis.md) |
|
||||
| Proyek JEB | Unit proyek bertenaga mesin, hash artefak, dan pseudokode tipe/metode | Klien JEB yang dijalankan pemanggil dan menyajikan MCP, dipilih dengan REA_JEB_MCP_URL; [panduan JEB](../providers/jeb-analysis.md) |
|
||||
@@ -281,6 +287,12 @@ REA mengekspor lingkungan yang dapat dijalankan dengan uji dasar untuk memeriksa
|
||||
[Referensi lingkungan](../agent-environments.md) ·
|
||||
[Tonton demo di X](https://x.com/reatools/status/2112574822584918075?s=20)
|
||||
|
||||
### Lingkungan aplikasi desktop
|
||||
|
||||
REA juga dapat membuat lingkungan untuk aplikasi desktop Linux yang digunakan agen melalui tangkapan layar, mouse, dan keyboard. Dari permintaan satu baris, seperti "Buatkan lingkungan Gnote tempat agen menambahkan minyak zaitun ke catatan daftar belanja", agen Anda memasang aplikasi di komputer build lokal, menulis tugas, mengekspor lingkungan, dan memeriksa tugas di komputer baru. Mesin yang membuatnya memerlukan Linux di amd64 atau arm64, Docker, dan versi framework agentenv yang ditetapkan panduan.
|
||||
|
||||
[Siapkan lingkungan aplikasi desktop](../desktop-build-computer.md)
|
||||
|
||||
## FAQ
|
||||
|
||||
<details>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<div align="center">
|
||||
|
||||
[English](../../README.md) · [简体中文](README_zh.md) · [繁體中文](README_zh-TW.md) · [日本語](README_ja.md) · [한국어](README_ko.md) · [Türkçe](README_tr.md) · [Русский](README_ru.md) · [Tiếng Việt](README_vi.md) · [ไทย](README_th.md) · [Deutsch](README_de.md) · [Español](README_es.md) · [Français](README_fr.md) · [Українська](README_uk.md) · [Polski](README_pl.md) · [Português (Brasil)](README_pt-BR.md) · [العربية](README_ar.md) · [فارسی](README_fa.md) · [Bahasa Indonesia](README_id.md) · **Italiano**
|
||||
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md) · [Roman Urdu](README_ur-Latn.md) · [Română](README_ro.md)
|
||||
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md) · [Roman Urdu](README_ur-Latn.md) · [Română](README_ro.md) · [Български](README_bg.md)
|
||||
|
||||
# REA: Reverse Engineer Anything
|
||||
|
||||
@@ -84,6 +84,10 @@ La configurazione supporta Claude Code, Codex, Cursor, Gemini CLI, Grok Build e
|
||||
|
||||
MCP usa schemi di input compatti per impostazione predefinita. Per tutte le indicazioni sui campi e la validazione annidata, imposta `REA_MCP_INPUT_SCHEMA_PROFILE=full` nella registrazione MCP. Entrambi i profili mantengono tutti gli strumenti e la stessa validazione canonica del server; vedi la guida ai contratti MCP.
|
||||
|
||||
La configurazione registra direttamente il runtime scelto e lo script di avvio di REA. Se usi un package runner, conserva la sua voce nella cache e il runtime; scarica il pacchetto da una directory attendibile fuori dal progetto di destinazione. Consulta la guida di installazione.
|
||||
|
||||
Gli schemi di output completi sono dichiarati per impostazione predefinita. Se il client limita `tools/list`, imposta `REA_MCP_OUTPUT_SCHEMA_PROFILE=compact` o `off` nella registrazione MCP. La validazione del server e i risultati strutturati restano completi. Consulta «Output schemas» nella guida ai contratti MCP.
|
||||
|
||||
### Chiedi al tuo agente
|
||||
|
||||
```text
|
||||
@@ -156,6 +160,7 @@ 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) |
|
||||
@@ -172,6 +177,7 @@ REA richiede Node.js 22.x (>=22.23.4), 24.x (>=24.22.1) o 26+ (>=26.12.1), oltre
|
||||
| Captured di pacchetti | Endpoint, DNS, TLS SNI, distribuzione dei protocolli e richieste HTTP | tshark e capinfos forniti dal chiamante; [guida pcap](../guides/data/pcap-analysis.md) |
|
||||
| Assembly .NET | Metadati, istruzioni CIL, dipendenze native dichiarate e confronti di build | Nessuno (solo statico); [guida managed-code](../guides/managed/managed-code-analysis.md) |
|
||||
| PyInstaller | CArchive, PYZ, Python bytecode | Static inspection; [Python packaged applications](../python-packaged-applications.md) |
|
||||
| Deno compile binaries | Virtual files, entry point, recorded options, npm snapshot length | Static inspection; [Deno compile executables](../deno-standalone.md) |
|
||||
| APK Android | Dichiarazioni manifest, classi, metodi decompilati e riferimenti | JADX headless e un JDK completo su Linux/macOS/Windows x64; [guida Android](../guides/android/android-analysis.md) |
|
||||
| Dispositivi Android | Dispositivi, pacchetti, processi, log, dump, screenshot e trasferimenti APK/file | adb fornito dal chiamante (emulatore o hardware); [guida ADB](../guides/android/adb-device-analysis.md) |
|
||||
| Progetti JEB | Unità di progetto dal motore, digest degli artifact e pseudocodice di tipi/metodi | Client JEB avviato dal chiamante via MCP, selezionato con REA_JEB_MCP_URL; [guida JEB](../providers/jeb-analysis.md) |
|
||||
@@ -270,6 +276,12 @@ REA esporta un ambiente eseguibile con un test di base che ne verifica l’avvio
|
||||
[Riferimento degli ambienti](../agent-environments.md) ·
|
||||
[Guarda la demo su X](https://x.com/reatools/status/2112574822584918075?s=20)
|
||||
|
||||
### Ambienti di app desktop
|
||||
|
||||
REA può creare anche un ambiente per un’app desktop Linux, che un agente usa tramite screenshot, mouse e tastiera. Da una richiesta di una riga, come «Creami un ambiente Gnote in cui l’agente aggiunge l’olio d’oliva alla nota della lista della spesa», il tuo agente installa l’app su un computer di build locale, scrive l’attività, esporta l’ambiente e verifica l’attività su un computer nuovo. La macchina che lo crea richiede Linux su amd64 o arm64, Docker e la versione del framework agentenv indicata dalla guida.
|
||||
|
||||
[Configurare gli ambienti di app desktop](../desktop-build-computer.md)
|
||||
|
||||
## FAQ
|
||||
|
||||
<details>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<div align="center">
|
||||
|
||||
[English](../../README.md) · [简体中文](README_zh.md) · [繁體中文](README_zh-TW.md) · **日本語** · [한국어](README_ko.md) · [Türkçe](README_tr.md) · [Русский](README_ru.md) · [Tiếng Việt](README_vi.md) · [ไทย](README_th.md) · [Deutsch](README_de.md) · [Español](README_es.md) · [Français](README_fr.md) · [Українська](README_uk.md) · [Polski](README_pl.md) · [Português (Brasil)](README_pt-BR.md) · [العربية](README_ar.md) · [فارسی](README_fa.md) · [Bahasa Indonesia](README_id.md) · [Italiano](README_it.md)
|
||||
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md) · [Roman Urdu](README_ur-Latn.md) · [Română](README_ro.md)
|
||||
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md) · [Roman Urdu](README_ur-Latn.md) · [Română](README_ro.md) · [Български](README_bg.md)
|
||||
|
||||
# REA:あらゆるものをリバースエンジニアリング
|
||||
|
||||
@@ -84,6 +84,10 @@ npx rea-agents setup
|
||||
|
||||
MCP は既定でコンパクトな入力スキーマを使用します。完全なフィールド説明と入れ子の検証情報が必要な場合は、MCP 登録に `REA_MCP_INPUT_SCHEMA_PROFILE=full` を設定してください。どちらも全ツールと同じ正規サーバー検証を維持します。詳細は MCP 契約ガイドを参照してください。
|
||||
|
||||
セットアップは選択したランタイムと REA のエントリースクリプトを直接登録します。パッケージランナーを使う場合は、そのキャッシュ項目とランタイムを残し、対象プロジェクト外の信頼できるディレクトリからパッケージを取得してください。 インストールガイドを参照してください。
|
||||
|
||||
出力スキーマはデフォルトで完全なものが公開されます。クライアントが `tools/list` を制限する場合は、MCP 登録で `REA_MCP_OUTPUT_SCHEMA_PROFILE=compact` または `off` を設定してください。サーバー側の検証と構造化結果は完全なままです。 MCP 契約ガイドの「Output schemas」を参照してください。
|
||||
|
||||
### エージェントに依頼する
|
||||
|
||||
```text
|
||||
@@ -157,6 +161,7 @@ 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) |
|
||||
@@ -172,6 +177,7 @@ REA には Node.js 22.x(>=22.23.4)、24.x(>=24.22.1)、または 26+ (>=
|
||||
| パケットキャプチャ | エンドポイント、DNS、TLS SNI、プロトコル分布、HTTPリクエスト | 呼び出し側が用意した tshark と capinfos;[pcapガイド](../guides/data/pcap-analysis.md) |
|
||||
| .NET アセンブリ | メタデータ、CIL 命令、宣言されたネイティブ依存関係、ビルドの比較 | 静的な検査;[マネージドコードのガイド](../guides/managed/managed-code-analysis.md) |
|
||||
| PyInstaller | CArchive, PYZ, Python bytecode | Static inspection; [Python packaged applications](../python-packaged-applications.md) |
|
||||
| Deno compile binaries | Virtual files, entry point, recorded options, npm snapshot length | Static inspection; [Deno compile executables](../deno-standalone.md) |
|
||||
| Android APK | マニフェストの宣言、クラス、逆コンパイルされたメソッド、参照 | Linux/macOS/Windows x64 上のヘッドレス JADX と完全な JDK;[Android ガイド](../guides/android/android-analysis.md) |
|
||||
| Android デバイス | デバイス、パッケージ、プロセス、ログ、ダンプ、スクリーンキャプチャ、APK/ファイル転送 | 呼び出し側が用意した adb(エミュレーターまたは実機);[ADB ガイド](../guides/android/adb-device-analysis.md) |
|
||||
| JEBプロジェクト | エンジンによるプロジェクトユニット、アーティファクトのダイジェスト、型/メソッドの擬似コード | 呼び出し側が起動し MCP を提供する JEB クライアント(REA_JEB_MCP_URL で選択);[JEB ガイド](../providers/jeb-analysis.md) |
|
||||
@@ -275,6 +281,12 @@ REA は実行可能な環境と、起動して応答することを確認する
|
||||
[環境リファレンス](../agent-environments.md) ·
|
||||
[X でデモを見る](https://x.com/reatools/status/2112574822584918075?s=20)
|
||||
|
||||
### デスクトップアプリの環境
|
||||
|
||||
REA は、エージェントがスクリーンショット、マウス、キーボードで操作する Linux デスクトップアプリの環境も構築できます。「エージェントが買い物リストのメモにオリーブオイルを追加する Gnote 環境を作って」のような 1 行の依頼から、エージェントがローカルのビルド用コンピューターにアプリをインストールし、タスクを書き、環境をエクスポートし、新しいコンピューターでタスクを確認します。構築するマシンには、amd64 または arm64 の Linux、Docker、ガイドが指定するバージョンの agentenv フレームワークが必要です。
|
||||
|
||||
[デスクトップアプリ環境を設定する](../desktop-build-computer.md)
|
||||
|
||||
## よくある質問
|
||||
|
||||
<details>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<div align="center">
|
||||
|
||||
[English](../../README.md) · [简体中文](README_zh.md) · [繁體中文](README_zh-TW.md) · [日本語](README_ja.md) · **한국어** · [Türkçe](README_tr.md) · [Русский](README_ru.md) · [Tiếng Việt](README_vi.md) · [ไทย](README_th.md) · [Deutsch](README_de.md) · [Español](README_es.md) · [Français](README_fr.md) · [Українська](README_uk.md) · [Polski](README_pl.md) · [Português (Brasil)](README_pt-BR.md) · [العربية](README_ar.md) · [فارسی](README_fa.md) · [Bahasa Indonesia](README_id.md) · [Italiano](README_it.md)
|
||||
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md) · [Roman Urdu](README_ur-Latn.md) · [Română](README_ro.md)
|
||||
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md) · [Roman Urdu](README_ur-Latn.md) · [Română](README_ro.md) · [Български](README_bg.md)
|
||||
|
||||
# REA: 무엇이든 리버스 엔지니어링
|
||||
|
||||
@@ -84,6 +84,10 @@ npx rea-agents setup
|
||||
|
||||
MCP는 기본적으로 간결한 입력 스키마를 사용합니다. 전체 필드 안내와 중첩 검증 정보가 필요하면 MCP 등록에서 `REA_MCP_INPUT_SCHEMA_PROFILE=full`을 설정하세요. 두 프로필 모두 전체 도구와 동일한 정규 서버 검증을 유지합니다. MCP 계약 가이드를 참고하세요.
|
||||
|
||||
설정은 선택한 런타임과 REA 진입 스크립트를 직접 등록합니다. 패키지 실행기를 사용한다면 해당 캐시 항목과 런타임을 유지하고, 대상 프로젝트 밖의 신뢰할 수 있는 디렉터리에서 패키지를 받으세요. 설치 가이드를 참고하세요.
|
||||
|
||||
기본적으로 완전한 출력 스키마가 제공됩니다. 클라이언트가 `tools/list` 크기를 제한한다면 MCP 등록에서 `REA_MCP_OUTPUT_SCHEMA_PROFILE=compact` 또는 `off`로 설정하세요. 서버 검증과 구조화된 결과는 완전하게 유지됩니다. MCP 계약 가이드의 «Output schemas»를 참고하세요.
|
||||
|
||||
### 에이전트에게 요청
|
||||
|
||||
```text
|
||||
@@ -159,6 +163,7 @@ 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) |
|
||||
@@ -185,6 +190,7 @@ REA에는 Node.js 22.x(>=22.23.4), 24.x(>=24.22.1) 또는 26+ (>=26.12.1)와 npm
|
||||
| 패키지 및 리소스 | 파일 목록, 다이제스트, plist, Apple 번들 구조, 추출한 리소스 | [아티팩트 및 JavaScript 가이드](../guides/javascript/javascript-artifact-reconstruction.md), [Apple 애플리케이션](../guides/apple/apple-application-analysis.md) |
|
||||
| 프로세스 동작 | 터미널 출력, 상호작용, 종료 및 파일 시스템 관찰 결과, 실행 비교 | 네이티브 PTY를 지원하는 Linux/macOS; [프로세스 캡처](../guides/runtime/process-capture.md) |
|
||||
| PyInstaller | CArchive, PYZ, Python bytecode | Static inspection; [Python packaged applications](../python-packaged-applications.md) |
|
||||
| Deno compile binaries | Virtual files, entry point, recorded options, npm snapshot length | Static inspection; [Deno compile executables](../deno-standalone.md) |
|
||||
| GPU 코드 객체 | CUDA/HIP 대상, 선택한 커널 매개변수와 자원, 보존된 PTX 텍스트 | 내장 정적 검사 ELF/PE/fatbin/CUBIN/PTX; [GPU](../gpu-code-objects.md) |
|
||||
| 모델 파일 | GGUF / safetensors 메타데이터, 텐서 선언과 계산한 합계 | 헤더 검사; 전체 파일 해시는 선택 사항; [GGUF / safetensors](../model-artifacts.md) |
|
||||
| IL2CPP 메타데이터 | Unity global-metadata.dat 어셈블리 이미지, 형식·메서드 이름과 인덱스 범위 | 버전 24, 27, 29, 31, 39 정적 디코딩; Unity 불필요 |
|
||||
@@ -273,6 +279,12 @@ REA는 실행 가능한 환경과 시작 및 응답 여부를 확인하는 기
|
||||
[환경 참조 문서](../agent-environments.md) ·
|
||||
[X에서 데모 보기](https://x.com/reatools/status/2112574822584918075?s=20)
|
||||
|
||||
### 데스크톱 앱 환경
|
||||
|
||||
REA는 에이전트가 스크린샷, 마우스, 키보드로 사용하는 Linux 데스크톱 앱의 환경도 만들 수 있습니다. "에이전트가 장보기 목록 메모에 올리브유를 추가하는 Gnote 환경을 만들어 줘" 같은 한 줄 요청에서 에이전트가 로컬 빌드 컴퓨터에 앱을 설치하고, 작업을 작성하고, 환경을 내보낸 뒤 새 컴퓨터에서 작업을 확인합니다. 환경을 만드는 머신에는 amd64 또는 arm64의 Linux, Docker, 가이드가 지정한 버전의 agentenv 프레임워크가 필요합니다.
|
||||
|
||||
[데스크톱 앱 환경 설정하기](../desktop-build-computer.md)
|
||||
|
||||
## 자주 묻는 질문
|
||||
|
||||
<details>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<div align="center">
|
||||
|
||||
[English](../../README.md) · [简体中文](README_zh.md) · [繁體中文](README_zh-TW.md) · [日本語](README_ja.md) · [한국어](README_ko.md) · [Türkçe](README_tr.md) · [Русский](README_ru.md) · [Tiếng Việt](README_vi.md) · [ไทย](README_th.md) · [Deutsch](README_de.md) · [Español](README_es.md) · [Français](README_fr.md) · [Українська](README_uk.md) · [Polski](README_pl.md) · [Português (Brasil)](README_pt-BR.md) · [العربية](README_ar.md) · [فارسی](README_fa.md) · [Bahasa Indonesia](README_id.md) · [Italiano](README_it.md)
|
||||
· [Ελληνικά](README_el.md) · **മലയാളം** · [Roman Urdu](README_ur-Latn.md) · [Română](README_ro.md)
|
||||
· [Ελληνικά](README_el.md) · **മലയാളം** · [Roman Urdu](README_ur-Latn.md) · [Română](README_ro.md) · [Български](README_bg.md)
|
||||
|
||||
# REA: എന്തും Reverse Engineer ചെയ്യുക
|
||||
|
||||
@@ -86,6 +86,10 @@ Claude Code, Codex, Cursor, Gemini CLI, Grok Build, കൂടാതെ [മറ
|
||||
|
||||
MCP സാധാരണയായി compact input schemas ഉപയോഗിക്കുന്നു. പൂർണ്ണ field guidance-ഉം nested validation details-ഉം വേണമെങ്കിൽ MCP registration-ൽ `REA_MCP_INPUT_SCHEMA_PROFILE=full` സജ്ജമാക്കുക. രണ്ടു profiles-ലും എല്ലാ tools-ഉം ഒരേ canonical server validation-ഉം നിലനിൽക്കും; MCP contracts guide കാണുക.
|
||||
|
||||
തിരഞ്ഞെടുത്ത runtime-ഉം REA entry script-ഉം setup നേരിട്ട് രജിസ്റ്റർ ചെയ്യുന്നു. Package runner ഉപയോഗിക്കുമ്പോൾ അതിന്റെ cache entry-യും runtime-ഉം നിലനിർത്തുക; target project-ന് പുറത്തുള്ള വിശ്വസനീയമായ ഡയറക്ടറിയിൽ നിന്ന് package നേടുക. ഇൻസ്റ്റലേഷൻ ഗൈഡ് കാണുക.
|
||||
|
||||
പൂർണ്ണ output schema-കൾ സ്ഥിരസ്ഥിതിയായി പരസ്യപ്പെടുത്തുന്നു. Client `tools/list` പരിമിതപ്പെടുത്തുന്നുവെങ്കിൽ MCP registration-ൽ `REA_MCP_OUTPUT_SCHEMA_PROFILE=compact` അല്ലെങ്കിൽ `off` സജ്ജമാക്കുക. Server validation-ഉം structured result-കളും പൂർണ്ണമായി നിലനിൽക്കും. MCP കരാർ ഗൈഡിലെ «Output schemas» കാണുക.
|
||||
|
||||
### നിങ്ങളുടെ agent-നോട് ആവശ്യപ്പെടുക
|
||||
|
||||
```text
|
||||
@@ -159,6 +163,7 @@ 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) |
|
||||
@@ -174,6 +179,7 @@ REA-യ്ക്ക് Node.js 22.x (>=22.23.4), 24.x (>=24.22.1), അല്ല
|
||||
| Saved network captures | Requests, responses, പുറത്തുകാണുന്ന payload-ുകൾ, source locations | HAR അല്ലെങ്കിൽ Fiddler Everywhere SAZ; native mitmproxy-നായി Linux-ൽ mitmdump; [capture guide](../guides/web/web-network-captures.md) |
|
||||
| .NET assemblies | Metadata, CIL instructions, പ്രഖ്യാപിച്ച native dependencies, build comparisons | ഒന്നും ആവശ്യമില്ല (static മാത്രം); [managed-code guide](../guides/managed/managed-code-analysis.md) |
|
||||
| Python packaged apps | CArchive/PYZ entries, Python version, bytecode, resources and runtime options | Static PyInstaller parsing; [Python guide](../python-packaged-applications.md) |
|
||||
| Deno compile binaries | Virtual files, entry point, recorded options, npm snapshot length | Static inspection; [Deno compile executables](../deno-standalone.md) |
|
||||
| Android APKs | Manifest declarations, classes, decompiled methods, references | Linux/macOS/Windows x64-ൽ Headless JADX-ഉം full JDK-ഉം; [Android guide](../guides/android/android-analysis.md) |
|
||||
| Android devices | Devices, packages, processes, logs, dumps, screen captures, APK/file transfers | Caller നൽകുന്ന adb (emulator അല്ലെങ്കിൽ hardware); [ADB guide](../guides/android/adb-device-analysis.md) |
|
||||
| JEB projects | Engine-backed project units, artifact digests, type/method pseudo-code | MCP സേവനം നൽകുന്ന caller ആരംഭിച്ച JEB client; REA_JEB_MCP_URL ഉപയോഗിച്ച് തിരഞ്ഞെടുക്കുക; [JEB guide](../providers/jeb-analysis.md) |
|
||||
@@ -277,6 +283,12 @@ agent-env run ./my-env
|
||||
[പരിതസ്ഥിതി റഫറൻസ്](../agent-environments.md) ·
|
||||
[X-ൽ ഡെമോ കാണുക](https://x.com/reatools/status/2112574822584918075?s=20)
|
||||
|
||||
### ഡെസ്ക്ടോപ്പ് ആപ്പ് പരിതസ്ഥിതികൾ
|
||||
|
||||
സ്ക്രീൻഷോട്ടുകൾ, മൗസ്, കീബോർഡ് എന്നിവ വഴി ഏജന്റ് ഉപയോഗിക്കുന്ന Linux ഡെസ്ക്ടോപ്പ് ആപ്പിന്റെ പരിതസ്ഥിതിയും REA-യ്ക്ക് നിർമ്മിക്കാം. "ഷോപ്പിംഗ് ലിസ്റ്റ് നോട്ടിൽ ഏജന്റ് ഒലിവ് ഓയിൽ ചേർക്കുന്ന ഒരു Gnote പരിതസ്ഥിതി നിർമ്മിക്കുക" പോലുള്ള ഒറ്റവരി അഭ്യർത്ഥനയിൽ നിന്ന്, നിങ്ങളുടെ ഏജന്റ് ഒരു പ്രാദേശിക ബിൽഡ് കമ്പ്യൂട്ടറിൽ ആപ്പ് ഇൻസ്റ്റാൾ ചെയ്യുന്നു, ടാസ്ക് എഴുതുന്നു, പരിതസ്ഥിതി എക്സ്പോർട്ട് ചെയ്യുന്നു, ഒരു പുതിയ കമ്പ്യൂട്ടറിൽ ടാസ്ക് പരിശോധിക്കുന്നു. ഇത് നിർമ്മിക്കുന്ന മെഷീന് amd64 അല്ലെങ്കിൽ arm64-ലെ Linux, Docker, ഗൈഡ് നിശ്ചയിക്കുന്ന agentenv ഫ്രെയിംവർക്ക് പതിപ്പ് എന്നിവ വേണം.
|
||||
|
||||
[ഡെസ്ക്ടോപ്പ് ആപ്പ് പരിതസ്ഥിതികൾ സജ്ജീകരിക്കുക](../desktop-build-computer.md)
|
||||
|
||||
## പതിവുചോദ്യങ്ങൾ
|
||||
|
||||
<details>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<div align="center">
|
||||
|
||||
[English](../../README.md) · [简体中文](README_zh.md) · [繁體中文](README_zh-TW.md) · [日本語](README_ja.md) · [한국어](README_ko.md) · [Türkçe](README_tr.md) · [Русский](README_ru.md) · [Tiếng Việt](README_vi.md) · [ไทย](README_th.md) · [Deutsch](README_de.md) · [Español](README_es.md) · [Français](README_fr.md) · [Українська](README_uk.md) · **Polski** · [Português (Brasil)](README_pt-BR.md) · [العربية](README_ar.md) · [فارسی](README_fa.md) · [Bahasa Indonesia](README_id.md) · [Italiano](README_it.md)
|
||||
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md) · [Roman Urdu](README_ur-Latn.md) · [Română](README_ro.md)
|
||||
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md) · [Roman Urdu](README_ur-Latn.md) · [Română](README_ro.md) · [Български](README_bg.md)
|
||||
|
||||
# REA: Reverse Engineer Anything
|
||||
|
||||
@@ -84,6 +84,10 @@ Konfigurator obsługuje Claude Code, Codex, Cursor, Gemini CLI, Grok Build i [in
|
||||
|
||||
MCP domyślnie używa zwartych schematów wejściowych. Pełne opisy pól i zagnieżdżonej walidacji włącza `REA_MCP_INPUT_SCHEMA_PROFILE=full` w rejestracji MCP. Oba profile zachowują wszystkie narzędzia i tę samą kanoniczną walidację serwera; zobacz przewodnik kontraktów MCP.
|
||||
|
||||
Konfiguracja zapisuje bezpośrednio wybrane środowisko uruchomieniowe i skrypt wejściowy REA. Przy użyciu narzędzia uruchamiającego pakiety zachowaj jego wpis w pamięci podręcznej i środowisko; pobierz pakiet z zaufanego katalogu poza projektem docelowym. Zobacz instrukcję instalacji.
|
||||
|
||||
Pełne schematy wyjściowe są udostępniane domyślnie. Jeśli klient ogranicza `tools/list`, ustaw `REA_MCP_OUTPUT_SCHEMA_PROFILE=compact` lub `off` w rejestracji MCP. Walidacja serwera i wyniki strukturalne pozostają pełne. Zobacz „Output schemas” w przewodniku po kontraktach MCP.
|
||||
|
||||
### Zapytaj agenta
|
||||
|
||||
```text
|
||||
@@ -157,6 +161,7 @@ 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) |
|
||||
@@ -172,6 +177,7 @@ REA wymaga Node.js 22.x (>=22.23.4), 24.x (>=24.22.1) lub 26+ (>=26.12.1) oraz n
|
||||
| Przechwytywanie pakietów | Punkty końcowe, DNS, TLS SNI, dystrybucja protokołów i żądania HTTP | Dostarczone przez wywołującego tshark i capinfos; [przewodnik pcap](../guides/data/pcap-analysis.md) |
|
||||
| Zestawy .NET | Metadane, instrukcje CIL, zadeklarowane zależności natywne i porównania kompilacji | Analiza statyczna; [przewodnik kodu zarządzanego](../guides/managed/managed-code-analysis.md) |
|
||||
| PyInstaller | CArchive, PYZ, Python bytecode | Static inspection; [Python packaged applications](../python-packaged-applications.md) |
|
||||
| Deno compile binaries | Virtual files, entry point, recorded options, npm snapshot length | Static inspection; [Deno compile executables](../deno-standalone.md) |
|
||||
| Pakiety APK dla Androida | Deklaracje manifestu, klasy, zdekompilowane metody i odwołania | JADX bez interfejsu graficznego i pełny JDK w systemach Linux/macOS/Windows x64; [przewodnik Androida](../guides/android/android-analysis.md) |
|
||||
| Urządzenia z Androidem | Urządzenia, pakiety, procesy, logi, zrzuty, zrzuty ekranu oraz transfery APK/plików | adb dostarczony przez wywołującego (emulator lub urządzenie); [przewodnik ADB](../guides/android/adb-device-analysis.md) |
|
||||
| Projekty JEB | Jednostki projektu obsługiwane przez silnik, skróty artefaktów i pseudokod typów/metod | Uruchomiony przez wywołującego klient JEB udostępniający MCP, wybrany przez REA_JEB_MCP_URL; [przewodnik JEB](../providers/jeb-analysis.md) |
|
||||
@@ -273,6 +279,12 @@ REA eksportuje gotowe do uruchomienia środowisko z podstawowym testem uruchamia
|
||||
[Dokumentacja środowisk](../agent-environments.md) ·
|
||||
[Obejrzyj demo w X](https://x.com/reatools/status/2112574822584918075?s=20)
|
||||
|
||||
### Środowiska aplikacji desktopowych
|
||||
|
||||
REA może też zbudować środowisko aplikacji desktopowej dla Linuksa, z której agent korzysta przez zrzuty ekranu, mysz i klawiaturę. Z jednowierszowej prośby, takiej jak „Zbuduj mi środowisko Gnote, w którym agent dodaje oliwę z oliwek do notatki z listą zakupów”, twój agent instaluje aplikację na lokalnym komputerze budującym, pisze zadanie, eksportuje środowisko i sprawdza zadanie na nowym komputerze. Maszyna, która je buduje, potrzebuje Linuksa na amd64 lub arm64, Dockera i wersji frameworka agentenv wskazanej w przewodniku.
|
||||
|
||||
[Konfiguracja środowisk aplikacji desktopowych](../desktop-build-computer.md)
|
||||
|
||||
## FAQ
|
||||
|
||||
<details>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<div align="center">
|
||||
|
||||
[English](../../README.md) · [简体中文](README_zh.md) · [繁體中文](README_zh-TW.md) · [日本語](README_ja.md) · [한국어](README_ko.md) · [Türkçe](README_tr.md) · [Русский](README_ru.md) · [Tiếng Việt](README_vi.md) · [ไทย](README_th.md) · [Deutsch](README_de.md) · [Español](README_es.md) · [Français](README_fr.md) · [Українська](README_uk.md) · [Polski](README_pl.md) · **Português (Brasil)** · [العربية](README_ar.md) · [فارسی](README_fa.md) · [Bahasa Indonesia](README_id.md) · [Italiano](README_it.md)
|
||||
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md) · [Roman Urdu](README_ur-Latn.md) · [Română](README_ro.md)
|
||||
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md) · [Roman Urdu](README_ur-Latn.md) · [Română](README_ro.md) · [Български](README_bg.md)
|
||||
|
||||
# REA: Faça engenharia reversa de qualquer coisa
|
||||
|
||||
@@ -84,6 +84,10 @@ A configuração oferece suporte ao Claude Code, Codex, Cursor, Gemini CLI, Grok
|
||||
|
||||
O MCP usa esquemas de entrada compactos por padrão. Para obter todas as orientações de campos e validação aninhada, defina `REA_MCP_INPUT_SCHEMA_PROFILE=full` no registro MCP. Ambos os perfis mantêm todas as ferramentas e a mesma validação canônica do servidor; veja o guia dos contratos MCP.
|
||||
|
||||
A configuração registra diretamente o runtime escolhido e o script de entrada do REA. Ao usar um executor de pacotes, mantenha sua entrada de cache e o runtime; obtenha o pacote em um diretório confiável fora do projeto alvo. Consulte o guia de instalação.
|
||||
|
||||
Os esquemas de saída completos são anunciados por padrão. Se o cliente limitar `tools/list`, defina `REA_MCP_OUTPUT_SCHEMA_PROFILE=compact` ou `off` no registro MCP. A validação do servidor e os resultados estruturados continuam completos. Consulte “Output schemas” no guia de contratos MCP.
|
||||
|
||||
### Peça ao seu agente
|
||||
|
||||
```text
|
||||
@@ -157,6 +161,7 @@ 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) |
|
||||
@@ -172,6 +177,7 @@ O REA requer Node.js 22.x (>=22.23.4), 24.x (>=24.22.1) ou 26+ (>=26.12.1), alé
|
||||
| Capturas de pacotes | Endpoints, DNS, TLS SNI, distribuição de protocolos e requisições HTTP | tshark e capinfos fornecidos pelo chamador; [guia pcap](../guides/data/pcap-analysis.md) |
|
||||
| Assemblies .NET | Metadados, instruções CIL, dependências nativas declaradas e comparações de builds | Inspeção estática; [guia de código gerenciado](../guides/managed/managed-code-analysis.md) |
|
||||
| PyInstaller | CArchive, PYZ, Python bytecode | Static inspection; [Python packaged applications](../python-packaged-applications.md) |
|
||||
| Deno compile binaries | Virtual files, entry point, recorded options, npm snapshot length | Static inspection; [Deno compile executables](../deno-standalone.md) |
|
||||
| APKs Android | Declarações do manifesto, classes, métodos descompilados e referências | JADX sem interface gráfica e um JDK completo no Linux/macOS/Windows x64; [guia de Android](../guides/android/android-analysis.md) |
|
||||
| Dispositivos Android | Dispositivos, pacotes, processos, logs, despejos, capturas de tela e transferências de APK/arquivos | adb fornecido pelo chamador (emulador ou aparelho); [guia de ADB](../guides/android/adb-device-analysis.md) |
|
||||
| Projetos JEB | Unidades de projeto do motor, hashes de artefatos e pseudocódigo de tipos/métodos | Um cliente JEB iniciado pelo chamador servindo MCP, selecionado com REA_JEB_MCP_URL; [guia de JEB](../providers/jeb-analysis.md) |
|
||||
@@ -273,6 +279,12 @@ O REA exporta um ambiente executável com um teste básico para verificar se ele
|
||||
[Referência de ambientes](../agent-environments.md) ·
|
||||
[Veja a demonstração no X](https://x.com/reatools/status/2112574822584918075?s=20)
|
||||
|
||||
### Ambientes de aplicativos de desktop
|
||||
|
||||
O REA também pode criar um ambiente de um aplicativo de desktop Linux, que um agente usa por capturas de tela, mouse e teclado. A partir de um pedido de uma linha, como "Crie um ambiente do Gnote em que o agente adiciona azeite à nota da lista de compras", seu agente instala o aplicativo em um computador de build local, escreve a tarefa, exporta o ambiente e verifica a tarefa em um computador novo. A máquina que o cria precisa de Linux em amd64 ou arm64, Docker e da versão do framework agentenv fixada pelo guia.
|
||||
|
||||
[Configurar ambientes de aplicativos de desktop](../desktop-build-computer.md)
|
||||
|
||||
## Perguntas frequentes
|
||||
|
||||
<details>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<div align="center">
|
||||
|
||||
[English](../../README.md) · [简体中文](README_zh.md) · [繁體中文](README_zh-TW.md) · [日本語](README_ja.md) · [한국어](README_ko.md) · [Türkçe](README_tr.md) · [Русский](README_ru.md) · [Tiếng Việt](README_vi.md) · [ไทย](README_th.md) · [Deutsch](README_de.md) · [Español](README_es.md) · [Français](README_fr.md) · [Українська](README_uk.md) · [Polski](README_pl.md) · [Português (Brasil)](README_pt-BR.md) · [العربية](README_ar.md) · [فارسی](README_fa.md) · [Bahasa Indonesia](README_id.md) · [Italiano](README_it.md)
|
||||
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md) · [Roman Urdu](README_ur-Latn.md) · **Română**
|
||||
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md) · [Roman Urdu](README_ur-Latn.md) · **Română** · [Български](README_bg.md)
|
||||
|
||||
# REA: Reverse Engineer Anything
|
||||
|
||||
@@ -99,6 +99,10 @@ validării structurilor imbricate. Ambele profiluri păstrează toate uneltele
|
||||
validarea canonică a serverului. Consultă secțiunea „Compact input schema profile”
|
||||
din ghidul contractelor MCP.
|
||||
|
||||
Configurarea înregistrează direct mediul de execuție ales și scriptul de intrare REA. Dacă folosești un executor de pachete, păstrează intrarea sa din cache și mediul de execuție; obține pachetul dintr-un director de încredere din afara proiectului țintă. Consultă ghidul de instalare.
|
||||
|
||||
Schemele complete de ieșire sunt anunțate implicit. Dacă clientul limitează `tools/list`, setează `REA_MCP_OUTPUT_SCHEMA_PROFILE=compact` sau `off` în înregistrarea MCP. Validarea serverului și rezultatele structurate rămân complete. Consultă „Output schemas” din ghidul contractelor MCP.
|
||||
|
||||
### Cere-i agentului
|
||||
|
||||
```text
|
||||
@@ -199,6 +203,7 @@ 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) |
|
||||
@@ -225,6 +230,7 @@ Uneltele suplimentare și platformele acceptate depind de ținta analizată:
|
||||
| Pachete și resurse | Inventare de fișiere, hash-uri, fișiere plist, structura pachetelor de aplicație Apple și resurse extrase | [Ghidul artefactelor și JavaScript](../guides/javascript/javascript-artifact-reconstruction.md), [aplicații Apple](../guides/apple/apple-application-analysis.md) |
|
||||
| Comportamentul proceselor | Ieșirea în terminal, interacțiuni, observații despre terminarea proceselor și sistemul de fișiere și comparații între rulări | Linux/macOS cu un PTY nativ; [capturarea proceselor](../guides/runtime/process-capture.md) |
|
||||
| Executabile PyInstaller | Membri CArchive, versiunea Python, scripturi de intrare și bytecode extras | Fără cerințe suplimentare (doar analiză statică); [aplicații Python împachetate](../python-packaged-applications.md) |
|
||||
| Deno compile binaries | Virtual files, entry point, recorded options, npm snapshot length | Static inspection; [Deno compile executables](../deno-standalone.md) |
|
||||
|
||||
Inspectarea statică JavaScript și .NET citește fișierele furnizate fără a rula
|
||||
aplicația. Capturarea în timpul execuției rulează ținta selectată sau interacționează
|
||||
@@ -333,6 +339,12 @@ REA exportă un mediu executabil cu un test de bază care verifică pornirea și
|
||||
[Referință pentru medii](../agent-environments.md) ·
|
||||
[Vezi demonstrația pe X](https://x.com/reatools/status/2112574822584918075?s=20)
|
||||
|
||||
### Medii pentru aplicații desktop
|
||||
|
||||
REA poate crea și un mediu pentru o aplicație desktop Linux, pe care un agent o folosește prin capturi de ecran, mouse și tastatură. Dintr-o cerere de un rând, precum „Creează-mi un mediu Gnote în care agentul adaugă ulei de măsline în notița cu lista de cumpărături”, agentul tău instalează aplicația pe un computer de build local, scrie sarcina, exportă mediul și verifică sarcina pe un computer nou. Mașina care îl creează are nevoie de Linux pe amd64 sau arm64, Docker și versiunea frameworkului agentenv fixată de ghid.
|
||||
|
||||
[Configurează mediile pentru aplicații desktop](../desktop-build-computer.md)
|
||||
|
||||
## Întrebări frecvente
|
||||
|
||||
<details>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<div align="center">
|
||||
|
||||
[English](../../README.md) · [简体中文](README_zh.md) · [繁體中文](README_zh-TW.md) · [日本語](README_ja.md) · [한국어](README_ko.md) · [Türkçe](README_tr.md) · **Русский** · [Tiếng Việt](README_vi.md) · [ไทย](README_th.md) · [Deutsch](README_de.md) · [Español](README_es.md) · [Français](README_fr.md) · [Українська](README_uk.md) · [Polski](README_pl.md) · [Português (Brasil)](README_pt-BR.md) · [العربية](README_ar.md) · [فارسی](README_fa.md) · [Bahasa Indonesia](README_id.md) · [Italiano](README_it.md)
|
||||
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md) · [Roman Urdu](README_ur-Latn.md) · [Română](README_ro.md)
|
||||
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md) · [Roman Urdu](README_ur-Latn.md) · [Română](README_ro.md) · [Български](README_bg.md)
|
||||
|
||||
# REA: Реверс-инжиниринг чего угодно
|
||||
|
||||
@@ -84,6 +84,10 @@ npx rea-agents setup
|
||||
|
||||
MCP по умолчанию использует компактные входные схемы. Для полного описания полей и вложенной валидации задайте `REA_MCP_INPUT_SCHEMA_PROFILE=full` в регистрации MCP. Оба профиля сохраняют все инструменты и одинаковую каноническую проверку на сервере; см. руководство по контрактам MCP.
|
||||
|
||||
Настройка напрямую регистрирует выбранную среду выполнения и входной скрипт REA. При использовании средства запуска пакетов сохраняйте его запись в кэше и среду выполнения; получайте пакет из доверенного каталога вне целевого проекта. См. руководство по установке.
|
||||
|
||||
Полные схемы вывода объявляются по умолчанию. Если клиент ограничивает `tools/list`, задайте `REA_MCP_OUTPUT_SCHEMA_PROFILE=compact` или `off` в регистрации MCP. Проверка на сервере и структурированные результаты остаются полными. См. раздел «Output schemas» в руководстве по контрактам MCP.
|
||||
|
||||
### Задайте вопрос агенту
|
||||
|
||||
```text
|
||||
@@ -159,6 +163,7 @@ 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) |
|
||||
@@ -182,6 +187,7 @@ REA требует Node.js 22.x (>=22.23.4), 24.x (>=24.22.1) или 26+ (>=26.1
|
||||
| Пакеты и ресурсы | Списки файлов, хеши, plist, структура пакетов Apple и извлечённые ресурсы | [Руководство по артефактам и JavaScript](../guides/javascript/javascript-artifact-reconstruction.md), [приложения Apple](../guides/apple/apple-application-analysis.md) |
|
||||
| Поведение процессов | Вывод терминала, взаимодействия, наблюдения за завершением и файловой системой, сравнения запусков | Linux/macOS с нативным PTY; [захват процессов](../guides/runtime/process-capture.md) |
|
||||
| PyInstaller | CArchive, PYZ, Python bytecode | Static inspection; [Python packaged applications](../python-packaged-applications.md) |
|
||||
| Deno compile binaries | Virtual files, entry point, recorded options, npm snapshot length | Static inspection; [Deno compile executables](../deno-standalone.md) |
|
||||
| Бинарные файлы Go | Встроенная версия компилятора, модули, замены и параметры сборки | Встроенный статический анализ ELF/PE/thin Mach-O; Установка Go не нужна |
|
||||
| Базы SQLite | Таблицы, столбцы, индексы, представления, триггеры и выбранные строки обычных таблиц | Локальный снимок БД/WAL; Node.js 24.x >=24.15 или 26+ с нативными ограничениями SQLite |
|
||||
| Объекты кода GPU | Цели CUDA/HIP, параметры и ресурсы выбранных ядер, сохранённый текст PTX | Встроенный статический анализ ELF/PE/fatbin/CUBIN/PTX; [GPU](../gpu-code-objects.md) |
|
||||
@@ -273,6 +279,12 @@ REA экспортирует готовое к запуску окружение
|
||||
[Справочник окружений](../agent-environments.md) ·
|
||||
[Смотреть демо в X](https://x.com/reatools/status/2112574822584918075?s=20)
|
||||
|
||||
### Окружения десктопных приложений
|
||||
|
||||
REA также может создать окружение десктопного приложения для Linux, которым агент пользуется через снимки экрана, мышь и клавиатуру. По запросу в одну строку, например «Создай окружение Gnote, где агент добавляет оливковое масло в заметку со списком покупок», ваш агент устанавливает приложение на локальный компьютер сборки, пишет задание, экспортирует окружение и проверяет задание на новом компьютере. Машине, которая его собирает, нужны Linux на amd64 или arm64, Docker и версия фреймворка agentenv, указанная в руководстве.
|
||||
|
||||
[Настройка окружений десктопных приложений](../desktop-build-computer.md)
|
||||
|
||||
## Частые вопросы
|
||||
|
||||
<details>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<div align="center">
|
||||
|
||||
[English](../../README.md) · [简体中文](README_zh.md) · [繁體中文](README_zh-TW.md) · [日本語](README_ja.md) · [한국어](README_ko.md) · [Türkçe](README_tr.md) · [Русский](README_ru.md) · [Tiếng Việt](README_vi.md) · **ไทย** · [Deutsch](README_de.md) · [Español](README_es.md) · [Français](README_fr.md) · [Українська](README_uk.md) · [Polski](README_pl.md) · [Português (Brasil)](README_pt-BR.md) · [العربية](README_ar.md) · [فارسی](README_fa.md) · [Bahasa Indonesia](README_id.md) · [Italiano](README_it.md)
|
||||
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md) · [Roman Urdu](README_ur-Latn.md) · [Română](README_ro.md)
|
||||
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md) · [Roman Urdu](README_ur-Latn.md) · [Română](README_ro.md) · [Български](README_bg.md)
|
||||
|
||||
# REA: Reverse Engineer Anything
|
||||
|
||||
@@ -84,6 +84,10 @@ npx rea-agents setup
|
||||
|
||||
MCP ใช้สคีมาอินพุตแบบกระชับโดยปริยาย หากต้องการคำอธิบายฟิลด์และการตรวจสอบแบบซ้อนทั้งหมด ให้ตั้ง `REA_MCP_INPUT_SCHEMA_PROFILE=full` ในการลงทะเบียน MCP ทั้งสองแบบคงเครื่องมือครบและใช้การตรวจสอบมาตรฐานฝั่งเซิร์ฟเวอร์เดียวกัน ดูคู่มือสัญญา MCP
|
||||
|
||||
การตั้งค่าจะลงทะเบียนรันไทม์ที่เลือกและสคริปต์เริ่มต้นของ REA โดยตรง หากใช้ตัวรันแพ็กเกจ ให้เก็บรายการแคชและรันไทม์ไว้ และรับแพ็กเกจจากไดเรกทอรีที่เชื่อถือได้นอกโปรเจกต์เป้าหมาย ดูคู่มือการติดตั้ง
|
||||
|
||||
ระบบประกาศสคีมาเอาต์พุตฉบับเต็มตามค่าเริ่มต้น หากไคลเอนต์จำกัด `tools/list` ให้ตั้ง `REA_MCP_OUTPUT_SCHEMA_PROFILE=compact` หรือ `off` ในการลงทะเบียน MCP การตรวจสอบฝั่งเซิร์ฟเวอร์และผลลัพธ์แบบมีโครงสร้างยังคงครบถ้วน ดูหัวข้อ “Output schemas” ในคู่มือสัญญา MCP
|
||||
|
||||
### ถามเอเจนต์
|
||||
|
||||
```text
|
||||
@@ -157,6 +161,7 @@ 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) |
|
||||
@@ -172,6 +177,7 @@ REA ต้องใช้ Node.js 22.x (>=22.23.4), 24.x (>=24.22.1) หรื
|
||||
| การจับแพ็กเก็ต | จุดเชื่อมต่อ, DNS, TLS SNI, การกระจายโปรโตคอล และคำขอ HTTP | tshark และ capinfos ที่ผู้เรียกจัดเตรียม; [คู่มือ pcap](../guides/data/pcap-analysis.md) |
|
||||
| แอสเซมบลี .NET | เมทาดาทา คำสั่ง CIL การพึ่งพาเนทีฟที่ประกาศไว้ และการเปรียบเทียบผลการบิลด์ | การตรวจสอบแบบสถิต; [คู่มือโค้ดแบบจัดการ](../guides/managed/managed-code-analysis.md) |
|
||||
| PyInstaller | CArchive, PYZ, Python bytecode | Static inspection; [Python packaged applications](../python-packaged-applications.md) |
|
||||
| Deno compile binaries | Virtual files, entry point, recorded options, npm snapshot length | Static inspection; [Deno compile executables](../deno-standalone.md) |
|
||||
| APK ของ Android | การประกาศใน manifest คลาส เมธอดที่ดีคอมไพล์ และการอ้างอิง | JADX แบบไม่มี GUI และ JDK แบบเต็มบน Linux/macOS/Windows x64; [คู่มือ Android](../guides/android/android-analysis.md) |
|
||||
| อุปกรณ์ Android | อุปกรณ์ แพ็กเกจ โพรเซส บันทึก ดัมพ์ ภาพหน้าจอ และการถ่ายโอน APK/ไฟล์ | adb ที่ผู้เรียกจัดเตรียม (โปรแกรมจำลองหรืออุปกรณ์จริง); [คู่มือ ADB](../guides/android/adb-device-analysis.md) |
|
||||
| โปรเจกต์ JEB | หน่วยโปรเจกต์จากเอนจิน, แฮชของอาร์ติแฟกต์ และซูโดโค้ดของไทป์/เมท็อด | ไคลเอนต์ JEB ที่ผู้เรียกเริ่มและให้บริการ MCP เลือกด้วย REA_JEB_MCP_URL; [คู่มือ JEB](../providers/jeb-analysis.md) |
|
||||
@@ -273,6 +279,12 @@ REA ส่งออกสภาพแวดล้อมที่รันได
|
||||
[เอกสารอ้างอิงสภาพแวดล้อม](../agent-environments.md) ·
|
||||
[ชมเดโมบน X](https://x.com/reatools/status/2112574822584918075?s=20)
|
||||
|
||||
### สภาพแวดล้อมของแอปเดสก์ท็อป
|
||||
|
||||
REA ยังสร้างสภาพแวดล้อมของแอปเดสก์ท็อปบน Linux ที่เอเจนต์ใช้งานผ่านภาพหน้าจอ เมาส์ และคีย์บอร์ดได้ด้วย จากคำขอเพียงบรรทัดเดียว เช่น "สร้างสภาพแวดล้อม Gnote ที่เอเจนต์เพิ่มน้ำมันมะกอกลงในโน้ตรายการซื้อของ" เอเจนต์ของคุณจะติดตั้งแอปบนคอมพิวเตอร์สำหรับบิลด์ในเครื่อง เขียนงาน ส่งออกสภาพแวดล้อม และตรวจสอบงานบนคอมพิวเตอร์เครื่องใหม่ เครื่องที่ใช้สร้างต้องมี Linux บน amd64 หรือ arm64, Docker และ agentenv framework เวอร์ชันที่คู่มือกำหนด
|
||||
|
||||
[ตั้งค่าสภาพแวดล้อมของแอปเดสก์ท็อป](../desktop-build-computer.md)
|
||||
|
||||
## คำถามที่พบบ่อย
|
||||
|
||||
<details>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<div align="center">
|
||||
|
||||
[English](../../README.md) · [简体中文](README_zh.md) · [繁體中文](README_zh-TW.md) · [日本語](README_ja.md) · [한국어](README_ko.md) · **Türkçe** · [Русский](README_ru.md) · [Tiếng Việt](README_vi.md) · [ไทย](README_th.md) · [Deutsch](README_de.md) · [Español](README_es.md) · [Français](README_fr.md) · [Українська](README_uk.md) · [Polski](README_pl.md) · [Português (Brasil)](README_pt-BR.md) · [العربية](README_ar.md) · [فارسی](README_fa.md) · [Bahasa Indonesia](README_id.md) · [Italiano](README_it.md)
|
||||
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md) · [Roman Urdu](README_ur-Latn.md) · [Română](README_ro.md)
|
||||
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md) · [Roman Urdu](README_ur-Latn.md) · [Română](README_ro.md) · [Български](README_bg.md)
|
||||
|
||||
# REA: Her şeyi tersine mühendislikle inceleyin
|
||||
|
||||
@@ -84,6 +84,10 @@ Kurulum Claude Code, Codex, Cursor, Gemini CLI, Grok Build ve [diğer ajanları]
|
||||
|
||||
MCP varsayılan olarak kompakt girdi şemaları kullanır. Tam alan açıklamaları ve iç içe doğrulama ayrıntıları için MCP kaydında `REA_MCP_INPUT_SCHEMA_PROFILE=full` ayarlayın. Her iki profil tüm araçları ve aynı kanonik sunucu doğrulamasını korur; MCP sözleşme rehberine bakın.
|
||||
|
||||
Kurulum, seçilen çalışma zamanını ve REA giriş betiğini doğrudan kaydeder. Paket çalıştırıcısı kullanıyorsanız önbellek girdisini ve çalışma zamanını koruyun; paketi hedef projenin dışında güvenilir bir dizinden edinin. Kurulum rehberine bakın.
|
||||
|
||||
Tam çıktı şemaları varsayılan olarak duyurulur. İstemciniz `tools/list` boyutunu sınırlıyorsa MCP kaydında `REA_MCP_OUTPUT_SCHEMA_PROFILE=compact` veya `off` ayarlayın. Sunucu doğrulaması ve yapılandırılmış sonuçlar tam kalır. MCP sözleşmeleri rehberindeki “Output schemas” bölümüne bakın.
|
||||
|
||||
### Ajanınıza sorun
|
||||
|
||||
```text
|
||||
@@ -157,6 +161,7 @@ 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) |
|
||||
@@ -172,6 +177,7 @@ REA; Node.js 22.x (>=22.23.4), 24.x (>=24.22.1) veya 26+ (>=26.12.1) ve npm gere
|
||||
| Kaydedilmiş ağ yakalamaları | İstekler, yanıtlar, erişilebilir yük içerikleri ve kaynak konumları | HAR veya Fiddler Everywhere SAZ; Linux'ta native mitmproxy için mitmdump; [ağ yakalama rehberi](../guides/web/web-network-captures.md) |
|
||||
| .NET derlemeleri | Meta veriler, CIL talimatları, bildirilmiş yerel bağımlılıklar ve derleme karşılaştırmaları | Statik inceleme; [yönetilen kod rehberi](../guides/managed/managed-code-analysis.md) |
|
||||
| PyInstaller | CArchive, PYZ, Python bytecode | Static inspection; [Python packaged applications](../python-packaged-applications.md) |
|
||||
| Deno compile binaries | Virtual files, entry point, recorded options, npm snapshot length | Static inspection; [Deno compile executables](../deno-standalone.md) |
|
||||
| Android APK'leri | Manifest bildirimleri, sınıflar, tersine derlenmiş metotlar ve referanslar | Linux/macOS/Windows x64 üzerinde arayüzsüz JADX ve tam bir JDK; [Android rehberi](../guides/android/android-analysis.md) |
|
||||
| Android cihazları | Cihazlar, paketler, süreçler, günlükler, dökümler, ekran görüntüleri ve APK/dosya aktarımları | Çağıranın sağladığı adb (emülatör veya cihaz); [ADB rehberi](../guides/android/adb-device-analysis.md) |
|
||||
| JEB projeleri | Motor destekli proje birimleri, artefakt özetleri ve tür/metot sözdekodu | Çağıranın başlattığı, MCP sunan bir JEB istemcisi, REA_JEB_MCP_URL ile seçilir; [JEB rehberi](../providers/jeb-analysis.md) |
|
||||
@@ -267,6 +273,12 @@ REA, çalıştırılabilir bir ortamı ve başlayıp yanıt verdiğini kontrol e
|
||||
[Ortam referansı](../agent-environments.md) ·
|
||||
[Demoyu X’te izleyin](https://x.com/reatools/status/2112574822584918075?s=20)
|
||||
|
||||
### Masaüstü uygulama ortamları
|
||||
|
||||
REA, bir ajanın ekran görüntüleri, fare ve klavye ile kullandığı bir Linux masaüstü uygulamasının ortamını da oluşturabilir. “Ajanın alışveriş listesi notuna zeytinyağı eklediği bir Gnote ortamı oluştur” gibi tek satırlık bir istekten ajanınız uygulamayı yerel bir derleme bilgisayarına kurar, görevi yazar, ortamı dışa aktarır ve görevi yeni bir bilgisayarda kontrol eder. Ortamı oluşturan makinede amd64 veya arm64 üzerinde Linux, Docker ve kılavuzun sabitlediği agentenv framework sürümü gerekir.
|
||||
|
||||
[Masaüstü uygulama ortamlarını kurun](../desktop-build-computer.md)
|
||||
|
||||
## Sık sorulan sorular
|
||||
|
||||
<details>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<div align="center">
|
||||
|
||||
[English](../../README.md) · [简体中文](README_zh.md) · [繁體中文](README_zh-TW.md) · [日本語](README_ja.md) · [한국어](README_ko.md) · [Türkçe](README_tr.md) · [Русский](README_ru.md) · [Tiếng Việt](README_vi.md) · [ไทย](README_th.md) · [Deutsch](README_de.md) · [Español](README_es.md) · [Français](README_fr.md) · **Українська** · [Polski](README_pl.md) · [Português (Brasil)](README_pt-BR.md) · [العربية](README_ar.md) · [فارسی](README_fa.md) · [Bahasa Indonesia](README_id.md) · [Italiano](README_it.md)
|
||||
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md) · [Roman Urdu](README_ur-Latn.md) · [Română](README_ro.md)
|
||||
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md) · [Roman Urdu](README_ur-Latn.md) · [Română](README_ro.md) · [Български](README_bg.md)
|
||||
|
||||
# REA: Реверс-інжиніринг будь-чого
|
||||
|
||||
@@ -84,6 +84,10 @@ npx rea-agents setup
|
||||
|
||||
MCP типово використовує компактні вхідні схеми. Для повного опису полів і вкладеної перевірки задайте `REA_MCP_INPUT_SCHEMA_PROFILE=full` у реєстрації MCP. Обидва профілі зберігають усі інструменти й однакову канонічну перевірку сервера; див. посібник контрактів MCP.
|
||||
|
||||
Налаштування безпосередньо реєструє вибране середовище виконання та стартовий скрипт REA. Якщо ви використовуєте засіб запуску пакетів, збережіть його запис у кеші та середовище виконання; отримуйте пакет із довіреного каталогу поза цільовим проєктом. Див. посібник зі встановлення.
|
||||
|
||||
Повні схеми виводу оголошуються за замовчуванням. Якщо клієнт обмежує `tools/list`, задайте `REA_MCP_OUTPUT_SCHEMA_PROFILE=compact` або `off` у реєстрації MCP. Перевірка сервера та структуровані результати залишаються повними. Див. розділ «Output schemas» у посібнику з контрактів MCP.
|
||||
|
||||
### Запитайте агента
|
||||
|
||||
```text
|
||||
@@ -157,6 +161,7 @@ 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) |
|
||||
@@ -172,6 +177,7 @@ REA потребує Node.js 22.x (>=22.23.4), 24.x (>=24.22.1) або 26+ (>=26
|
||||
| Захоплення пакетів | Кінцеві точки, DNS, TLS SNI, розподіл протоколів та HTTP-запити | Надані викликаючою стороною tshark та capinfos; [підручник pcap](../guides/data/pcap-analysis.md) |
|
||||
| Збірки .NET | Метадані, інструкції CIL, оголошені нативні залежності й порівняння збірок | Статична перевірка; [посібник керованого коду](../guides/managed/managed-code-analysis.md) |
|
||||
| PyInstaller | CArchive, PYZ, Python bytecode | Static inspection; [Python packaged applications](../python-packaged-applications.md) |
|
||||
| Deno compile binaries | Virtual files, entry point, recorded options, npm snapshot length | Static inspection; [Deno compile executables](../deno-standalone.md) |
|
||||
| Android APK | Оголошення маніфесту, класи, декомпільовані методи й посилання | JADX без графічного інтерфейсу й повний JDK у Linux/macOS/Windows x64; [посібник Android](../guides/android/android-analysis.md) |
|
||||
| Пристрої Android | Пристрої, пакети, процеси, журнали, дампи, знімки екрана та передавання APK/файлів | adb, наданий викликаючою стороною (емулятор або пристрій); [підручник ADB](../guides/android/adb-device-analysis.md) |
|
||||
| Проєкти JEB | Єдиниці проєкту від рушія, дайджести артефактів і псевдокод типів/методів | Запущений викликаною стороною клієнт JEB з MCP, обирається через REA_JEB_MCP_URL; [посібник JEB](../providers/jeb-analysis.md) |
|
||||
@@ -273,6 +279,12 @@ REA експортує готове до запуску середовище з
|
||||
[Довідник середовищ](../agent-environments.md) ·
|
||||
[Дивитися демо в X](https://x.com/reatools/status/2112574822584918075?s=20)
|
||||
|
||||
### Середовища настільних застосунків
|
||||
|
||||
REA також може створити середовище настільного застосунку для Linux, яким агент користується через знімки екрана, мишу й клавіатуру. За запитом в один рядок, як-от «Створи середовище Gnote, де агент додає оливкову олію до нотатки зі списком покупок», ваш агент встановлює застосунок на локальний комп’ютер збирання, пише завдання, експортує середовище й перевіряє завдання на новому комп’ютері. Машині, яка його збирає, потрібні Linux на amd64 або arm64, Docker і версія фреймворку agentenv, зазначена в посібнику.
|
||||
|
||||
[Налаштування середовищ настільних застосунків](../desktop-build-computer.md)
|
||||
|
||||
## Поширені запитання
|
||||
|
||||
<details>
|
||||
|
||||
Loaded 100 of 1334 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user