rea/tests/conformance
Lluís Ariño 85e124253a
feat(server): frame analysis-target content as untrusted data (#1908)
* feat(server): frame analysis-target content as untrusted data

Strings, decompiled code, page text, scripts, captures and logs returned
by REA originate from the analysed target, which can embed text aimed at
the agent. Nothing marked that content, so a prompt injection inside a
binary or page could steer the agent toward tools that run code.

- Server instructions now state that target-derived tool output is data,
  never instructions, and that any request in it to run, install,
  download or send something is a prompt-injection attempt to report.
- Tool contracts declare returnsTargetContent. It is on by default; only
  seven tools whose results hold REA session state or caller-supplied
  values (binary_session, close_binary, export_evidence_bundle,
  record_unknown, update_unknown, inspect_adb_client,
  inspect_apktool_client) are audited exceptions, so new tools start
  marked.
- Successful results of marked tools carry
  _meta.provenance = { untrusted_content: true, source: "analysis_target" }.
  content and structuredContent are unchanged, and the response budget
  accounts for the fixed marker bytes.

Tests cover the encoding and budget accounting, the audited exception
list against the contract catalog, and an in-memory MCP client that sees
the instructions and the marker on a marked tool but not on
binary_session.

* fix(server): mark failed target-content results as untrusted too

The untrusted provenance marker was attached only on the success branch
of ToolResultDelivery, but failures can carry target-derived text as
well: error messages, captured output, and partial observations such as
the terminal frames a failed capture_process_scenario retains in
partial_observation. A host gating later process or device actions on the
marker would have treated an adversarial error payload as trusted.

Every error path in src/server now carries the failing tool's provenance:
- toErrorToolResult and toRecordedPartialErrorToolResult take the tool's
  target-content flag explicitly, so each caller is audited by the type
  checker; toCallToolResult, toEvidenceToolResult (recording failure), the
  response-budget error that replaces an oversized success, and the
  Electron partial-evidence path pass contract.returnsTargetContent.
- Admission failures in runAdmittedToolOperation resolve the flag from the
  tool name through the new toolReturnsTargetContent, the same predicate
  the contract metadata uses; unknown names stay marked.
- The transport's oversized-error replacement keeps the original's marker
  and counts it in its budget check, matching the projected error.
- Errors the MCP SDK builds itself (input validation, thrown handlers) are
  marked in the transport for target-content tools only.

Error encoding accounts for the marker bytes exactly as success encoding
does. docs/mcp-contracts.md now states that error results carry the
marker. Tests cover marked and unmarked error results, the
capture_process_scenario partial-observation errors in-process and over
the SDK transport, the recorded partial-evidence path, the budget
replacement, the oversized-error replacement, and SDK validation errors
for a marked and a content-free tool.

* fix(contracts): mark session status, close and client probes as target content

The content-free exception set was audited against successful results
only. Now that failures carry the marker too, every exception was
re-audited against its error paths with one question: can the result
include text produced by an external process, provider or device, or
stored content REA did not author?

Removed from TARGET_CONTENT_FREE_TOOLS:
- close_binary: a failed provider cleanup (GhidraClient cleanup error via
  createGhidraDiagnostics) projects the launcher's captured stdout and
  stderr, which can contain target-derived log text.
- binary_session: capability status reports runtime unavailability as the
  provider error message (ProviderAdapterError and similar), and the
  provider candidate and Android availability diagnostics include probe
  output such as the apktool stderr excerpt.
- inspect_adb_client: the success result carries the version and
  installed path parsed from `adb version` stdout, and a failed probe
  keeps a stderr_excerpt.
- inspect_apktool_client: the success result carries the first line of
  the launcher's `--version` output, and a failed probe keeps a
  stderr_excerpt.
- update_unknown: the new revision carries forward the stored question
  and domain, which an imported evidence bundle can supply; list_unknowns
  and get_evidence_bundle already return that data marked.

The set now holds only export_evidence_bundle (path, byte and record
counts; failures are filesystem, cancellation, or a fixed integrity
message) and record_unknown (the caller's input plus REA-computed ids
and digests; registry errors project only a reason code).

The conformance test pins the reduced set and asserts each removed tool
is marked. Tests that used binary_session as the unmarked example now use
record_unknown. docs/mcp-contracts.md lists the remaining exceptions and
why the removed tools stay marked.

* fix(contracts): include target-content policy in the catalog identity

createToolCatalog() and CATALOG_IDENTITY.tools projected every
client-visible contract field except returnsTargetContent. Because the
untrusted-content framing left schemas, effects, prompts, CLI names and
the package version unchanged, a same-version MCP process started before
the update digested equal to the new server and binary_session reported
it aligned although it never emits _meta.provenance.

Project the flag as returns_target_content in both the digested tool
catalog and CATALOG_IDENTITY.tools, and export createCatalogDigests so a
boundary test proves that toggling the flag on one tool changes the
tools and combined digests.
2026-10-13 06:06:02 +09:00
..
android fix(android): preserve executable static initializer evidence (#1876) 2026-10-11 23:40:42 +08:00
c feat(ghidra): admit RISC-V ELF analysis through a pinned generic lane (#2151) 2026-10-13 00:11:35 +08:00
contracts feat(server): frame analysis-target content as untrusted data (#1908) 2026-10-13 06:06:02 +09:00
ghidra feat(ghidra): admit RISC-V ELF analysis through a pinned generic lane (#2151) 2026-10-13 00:11:35 +08:00
ida feat(ida): support optional native IDA Free MCP in attached mode (#1544) 2026-10-13 03:10:21 +08:00
inspector refactor: give Inspector its own capability directory (#869) 2026-10-07 13:53:25 +08:00
interface-builder feat(native): add investigation features (#486) 2026-09-30 00:41:05 +08:00
napi test: add source-built Hopper conformance fixtures 2026-07-12 19:32:29 +08:00
native refactor: consolidate boundary semantics and prune redundant tests 2026-10-10 05:56:01 +08:00
objc fix(hopper): preserve typed string values and verify real searches 2026-10-09 05:12:36 +08:00
providers refactor: remove forwarding exports and redundant aliases 2026-10-09 22:46:09 +08:00
psp feat(ghidra): admit bounded PSP ELF through installed Allegrex (#1599) 2026-10-11 19:47:33 +08:00
readiness feat(electron): add autonomous Electron runtime analysis (#464) 2026-08-05 19:07:46 +08:00
swift fix(ghidra): classify modern Swift manglings in swift type analysis (#1208) 2026-10-09 16:10:55 +08:00
versions test: add source-built Hopper conformance fixtures 2026-07-12 19:32:29 +08:00
README.md docs: correct drift and reorganize English guides (#2207) 2026-10-12 22:14:25 +08:00
readmeConsistency.test.ts docs: align the Indonesian README with the other translations (#1512) 2026-10-10 16:26:52 +08:00
releaseConfiguration.test.ts test: consolidate redundant assertions into boundary workflows 2026-10-09 20:26:46 +08:00

README.md

Source-built conformance fixtures

These sources are deliberately small semantic oracles for REA providers. Run npm run verify:fixtures on macOS or Linux to compile them into the ignored build/conformance/ directory, emit a hash-and-toolchain manifest, and verify their platform-native symbols and strings with local command-line tools. The portable C, version, and large-inventory fixtures build as Mach-O on macOS and ELF on Linux; Objective-C, Swift, and N-API-like fixtures remain macOS-only.

Only source files are versioned. Generated binaries, generated large-fixture source, debug information, and manifests must remain under build/.

ghidra/inventory.c is also compiled into temporary Linux ELF debug and stripped variants by npm run verify:ghidra. It fixes local functions, external puts linkage, defined strings, and writable/executable memory needed to prove the read-only Ghidra inventory contracts without committing a binary.

scripts/create-ghidra-windows-fixture.mjs separately emits a deterministic, ignored native x86-64 PE application for the controlled Windows Ghidra P0 lane. The generator and fixed SHA-256 are versioned; the .exe is never committed or executed. npm run verify:ghidra:windows uses it to verify the admitted read-only operation inventory, digest linkage, transport, and cleanup on the self-hosted real-Ghidra runner.

The C fixture fixes a known call chain and strings. The version pair fixes an added symbol, changed string, and changed call relationship. The generated large fixture contains 1,205 uniquely named functions and strings to verify that providers return complete inventories. Objective-C, Swift, and N-API-like fixtures provide metadata-oriented inputs without package or network dependencies.

readiness/ adds source-only generated JavaScript CLI and Electron fixtures for the repository's reconstruction-readiness verifier. npm run verify:readiness combines them with the compiled native fixtures, exercises CLI and MCP parity for real analysis operations, and checks the internal machine-readable report documented in docs/reconstruction-readiness.md.