rea-agents 1.7.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +38 -31
- package/dist/application/CapabilityInventory.js +18 -0
- package/dist/application/CrossVersionInvestigation.js +10 -6
- package/dist/application/Doctor.js +56 -6
- package/dist/application/ElectronBoundaryAnalysis.js +96 -0
- package/dist/application/ElectronBoundaryGraph.js +9 -0
- package/dist/application/ElectronBoundaryGraphContext.js +62 -0
- package/dist/application/ElectronBoundaryGraphIpc.js +242 -0
- package/dist/application/ElectronBoundaryGraphNative.js +86 -0
- package/dist/application/ElectronBoundaryGraphWindows.js +199 -0
- package/dist/application/EnhancedTools.js +38 -13
- package/dist/application/InvestigationProviders.js +30 -0
- package/dist/application/JavaScriptApplicationEvidence.js +26 -0
- package/dist/application/JavaScriptApplicationEvidenceGraph.js +89 -0
- package/dist/application/JavaScriptApplicationService.js +74 -0
- package/dist/application/JavaScriptApplicationWorkflowEvidence.js +29 -0
- package/dist/application/JavaScriptApplicationWorkflowService.js +90 -0
- package/dist/application/JavaScriptArtifactAnalysis.js +7 -1
- package/dist/application/JavaScriptArtifactGraphBuilder.js +59 -16
- package/dist/application/JavaScriptArtifactGraphEvidence.js +24 -14
- package/dist/application/JavaScriptArtifactReconstruction.js +3 -0
- package/dist/application/JavaScriptArtifactReconstructionInput.js +2 -83
- package/dist/application/JavaScriptReplayPlanning.js +201 -0
- package/dist/application/JavaScriptReplayService.js +266 -0
- package/dist/application/JavaScriptRuntimeReconciliationEvidence.js +25 -0
- package/dist/application/JavaScriptRuntimeReconciliationService.js +27 -0
- package/dist/application/ManagedApplicationGraphService.js +55 -0
- package/dist/application/ManagedMemberComparisonService.js +122 -0
- package/dist/application/ManagedNativeVerificationService.js +39 -0
- package/dist/application/ManagedReconstructionService.js +58 -0
- package/dist/application/ManagedRuntimeCorrelationService.js +103 -0
- package/dist/application/PermissionAuthority.js +1 -1
- package/dist/application/ProcessSampling.js +15 -11
- package/dist/application/ProjectPermissionStore.js +1 -0
- package/dist/application/runtime.js +2 -0
- package/dist/browser/CdpCaptureEvents.js +49 -0
- package/dist/browser/CdpElectronInspection.js +106 -162
- package/dist/browser/CdpElectronProvider.js +5 -1
- package/dist/browser/CdpElectronScriptEvents.js +69 -0
- package/dist/browser/CdpElectronScripts.js +94 -0
- package/dist/browser/CdpElectronWorkers.js +56 -0
- package/dist/browser/CdpPageCapture.js +8 -4
- package/dist/catalogIdentity.js +4 -1
- package/dist/cli.js +388 -0
- package/dist/cliApplicationCommands.js +62 -0
- package/dist/cliCommandNames.js +13 -0
- package/dist/cliElectronCommands.js +103 -1
- package/dist/cliJsonInput.js +54 -0
- package/dist/config.js +83 -0
- package/dist/contracts/applicationToolContracts.js +91 -0
- package/dist/contracts/artifactToolContracts.js +5 -9
- package/dist/contracts/browserToolContracts.js +14 -62
- package/dist/contracts/electronToolContracts.js +45 -19
- package/dist/contracts/errorSchemas.js +1 -0
- package/dist/contracts/investigationExamples.js +0 -6
- package/dist/contracts/javascriptApplicationWorkflowExamples.js +46 -0
- package/dist/contracts/javascriptRuntimeReconciliationExample.js +208 -0
- package/dist/contracts/managedToolContracts.js +153 -0
- package/dist/contracts/managedWorkflowExamples.js +346 -0
- package/dist/contracts/managedWorkflowToolContracts.js +203 -0
- package/dist/contracts/nativeToolContracts.js +2 -6
- package/dist/contracts/promptContracts.js +18 -2
- package/dist/contracts/toolContractExamples.js +10 -25
- package/dist/contracts/toolContracts.js +47 -45
- package/dist/contracts/toolEffects.js +160 -0
- package/dist/contracts/toolOutputSchemas.js +46 -31
- package/dist/doctorRuntime.js +42 -1
- package/dist/domain/artifactComparison.js +3 -4
- package/dist/domain/browserObservation.js +3 -0
- package/dist/domain/bundleComparison.js +4 -4
- package/dist/domain/electronObservation.js +13 -0
- package/dist/domain/electronStaticAnalysis.js +9 -0
- package/dist/domain/electronStaticAnalysisBrowser.js +194 -0
- package/dist/domain/electronStaticAnalysisIpc.js +171 -0
- package/dist/domain/electronStaticAnalysisNative.js +164 -0
- package/dist/domain/electronStaticAnalysisTypes.js +1 -0
- package/dist/domain/electronStaticAnalysisValues.js +103 -0
- package/dist/domain/errors.js +67 -1
- package/dist/domain/functionComparisonSchemas.js +3 -8
- package/dist/domain/inputIssueProjection.js +52 -0
- package/dist/domain/javascriptApplicationAnalysis.js +155 -0
- package/dist/domain/javascriptApplicationChangeGraph.js +231 -0
- package/dist/domain/javascriptApplicationEvidenceSchemas.js +18 -0
- package/dist/domain/javascriptApplicationGraph.js +2 -1
- package/dist/domain/javascriptApplicationGraphSchemas.js +7 -0
- package/dist/domain/javascriptApplicationVersionComparison.js +116 -0
- package/dist/domain/javascriptApplicationVersionComparisonSchemas.js +139 -0
- package/dist/domain/javascriptApplicationVersionItems.js +221 -0
- package/dist/domain/javascriptApplicationVersionKeys.js +170 -0
- package/dist/domain/javascriptFeatureSeed.js +140 -0
- package/dist/domain/javascriptFeatureTrace.js +232 -0
- package/dist/domain/javascriptFeatureTraceSchemas.js +136 -0
- package/dist/domain/javascriptFeatureTraversal.js +88 -0
- package/dist/domain/javascriptNativeHandoff.js +85 -0
- package/dist/domain/javascriptReplay.js +361 -0
- package/dist/domain/javascriptRuntimeLoadState.js +106 -0
- package/dist/domain/javascriptRuntimeReconciliation.js +42 -0
- package/dist/domain/javascriptRuntimeReconciliationGraph.js +169 -0
- package/dist/domain/javascriptRuntimeReconciliationMatching.js +247 -0
- package/dist/domain/javascriptRuntimeReconciliationParsing.js +160 -0
- package/dist/domain/javascriptRuntimeReconciliationResult.js +119 -0
- package/dist/domain/javascriptRuntimeReconciliationRuntime.js +316 -0
- package/dist/domain/javascriptRuntimeReconciliationSchemas.js +245 -0
- package/dist/domain/javascriptRuntimeStaticCandidates.js +191 -0
- package/dist/domain/javascriptStaticAnalysis.js +31 -43
- package/dist/domain/javascriptStaticAnalysisFindings.js +39 -0
- package/dist/domain/javascriptStaticAnalysisHelpers.js +10 -0
- package/dist/domain/javascriptStaticAnalysisState.js +6 -0
- package/dist/domain/managedApplicationGraph.js +556 -0
- package/dist/domain/managedArtifact.js +444 -0
- package/dist/domain/managedMemberComparison.js +565 -0
- package/dist/domain/managedNativeVerification.js +408 -0
- package/dist/domain/managedReconstruction.js +183 -0
- package/dist/domain/managedRuntimeCorrelation.js +175 -0
- package/dist/domain/reconstructionVerificationSchemas.js +1 -3
- package/dist/dotnet/ManagedArtifactInspector.js +318 -0
- package/dist/dotnet/ManagedMemberInspector.js +887 -0
- package/dist/dotnet/ManagedMetadataHeaps.js +131 -0
- package/dist/dotnet/ManagedMetadataInventory.js +368 -0
- package/dist/dotnet/ManagedMetadataLayout.js +322 -0
- package/dist/dotnet/ManagedNativeBoundaryInspector.js +391 -0
- package/dist/dotnet/ManagedPeReader.js +157 -0
- package/dist/dotnet/ManagedReaderFailure.js +10 -0
- package/dist/dotnet/ManagedStaticProvider.js +203 -0
- package/dist/generatedPackageMetadata.js +2 -2
- package/dist/ghidra/GhidraProvider.js +6 -0
- package/dist/main.js +14 -0
- package/dist/replay/JavaScriptReplayWorker.js +286 -0
- package/dist/replay/LinuxJavaScriptReplayRunner.js +434 -0
- package/dist/replay/LinuxRuntimeClosure.js +46 -0
- package/dist/replay/LinuxSeccompPolicy.js +40 -0
- package/dist/replay/ReplayWorkerProtocol.js +55 -0
- package/dist/replay/SystemJavaScriptReplayHost.js +182 -0
- package/dist/server/createServer.js +52 -0
- package/dist/server/registerApplicationTools.js +115 -0
- package/dist/server/registerArtifactComparisonTool.js +16 -9
- package/dist/server/registerBrowserTools.js +33 -8
- package/dist/server/registerBundleComparisonTool.js +17 -20
- package/dist/server/registerElectronTools.js +45 -3
- package/dist/server/registerEnhancedTools.js +58 -13
- package/dist/server/registerEvidenceTools.js +5 -1
- package/dist/server/registerFunctionComparisonTool.js +14 -7
- package/dist/server/registerInvestigationTools.js +21 -17
- package/dist/server/registerManagedTools.js +6 -0
- package/dist/server/registerManagedWorkflowTools.js +277 -0
- package/dist/server/registerOfficialTools.js +8 -8
- package/dist/server/registerProcessComparisonTool.js +25 -47
- package/dist/server/registerSessionStatusTool.js +7 -7
- package/dist/server/registerSessionTools.js +51 -86
- package/dist/server/sessionEvidence.js +14 -19
- package/dist/server/toolInputValidation.js +77 -0
- package/dist/server/toolRegistrationOptions.js +79 -2
- package/dist/server/toolResult.js +25 -17
- package/package.json +12 -4
- package/scripts/rea.mjs +1 -1
- package/skills/rea-analysis/SKILL.md +59 -3
package/README.md
CHANGED
|
@@ -10,11 +10,11 @@
|
|
|
10
10
|
|
|
11
11
|
[](https://www.npmjs.com/package/rea-agents)
|
|
12
12
|
[](https://github.com/morluto/rea/actions/workflows/ci.yml)
|
|
13
|
-
[](#tool-catalog-for-investigation)
|
|
14
14
|
[](https://nodejs.org/)
|
|
15
15
|
[](LICENSE)
|
|
16
16
|
|
|
17
|
-
[Quick start](#quick-start) · [Current status](#current-status) · [Investigation model](#the-investigation-model) · [
|
|
17
|
+
[Quick start](#quick-start) · [Current status](#current-status) · [Investigation model](#the-investigation-model) · [Tool catalog](#tool-catalog-for-investigation) · [Roadmap](#roadmap) · [How it works](#how-it-works)
|
|
18
18
|
|
|
19
19
|
<br />
|
|
20
20
|
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
|
|
31
31
|
See a feature in an app that you want in your own product? Give the app to your agent—even without its source code. With REA, the agent can investigate the feature, explain how it works, show its evidence, and build a version adapted to your stack and requirements.
|
|
32
32
|
|
|
33
|
-
REA gives agents one consistent way to investigate software. Today that includes deep native analysis and function dossiers through Hopper or bring-your-own Ghidra on Linux, reproducible Evidence v2 records, controlled process capture, passive website and Electron observation, bounded JavaScript/source-map reconstruction, and a versioned domain graph for connecting JavaScript application layers without confusing static inference with runtime observation. The longer-term toolkit extends the same agent workflow to APIs, protocols, mobile artifacts, firmware, richer runtime behavior, and differences between versions.
|
|
33
|
+
REA gives agents one consistent way to investigate software. Today that includes deep native analysis and function dossiers through Hopper or bring-your-own Ghidra on Linux, execution-free managed PE/CLI triage, reproducible Evidence v2 records, controlled process capture, passive website and Electron observation, bounded JavaScript/source-map reconstruction, and a versioned domain graph for connecting JavaScript application layers without confusing static inference with runtime observation. The longer-term toolkit extends the same agent workflow to APIs, protocols, mobile artifacts, firmware, richer runtime behavior, and differences between versions.
|
|
34
34
|
|
|
35
35
|
Reverse engineering normally makes the operator choose a tool, learn its API, move evidence between programs, and decide what to inspect next. REA gives that work to the agent through commands, skills, structured results, and repeatable investigation workflows.
|
|
36
36
|
|
|
@@ -219,15 +219,16 @@ Uninstall preserves Hopper, Node.js, evidence, captures, external evidence roots
|
|
|
219
219
|
|
|
220
220
|
### CLI or agent?
|
|
221
221
|
|
|
222
|
-
| If you want to…
|
|
223
|
-
|
|
|
224
|
-
| Ask an agent to investigate an app and build a feature
|
|
225
|
-
| Inspect or decompile one part of an app from the Terminal
|
|
226
|
-
| Validate, canonicalize, or compare Evidence v2 bundles
|
|
227
|
-
| Run or resume a persistent two-version artifact analysis
|
|
228
|
-
|
|
|
229
|
-
|
|
|
230
|
-
|
|
|
222
|
+
| If you want to… | Use |
|
|
223
|
+
| ---------------------------------------------------------------- | ------------------------------------------------------------------------- |
|
|
224
|
+
| Ask an agent to investigate an app and build a feature | Install the skill, then talk to your agent |
|
|
225
|
+
| Inspect or decompile one part of an app from the Terminal | `rea analyze` or `rea decompile` |
|
|
226
|
+
| Validate, canonicalize, or compare Evidence v2 bundles | `rea evidence-import`, `rea evidence-export`, or `rea compare` |
|
|
227
|
+
| Run or resume a persistent two-version artifact analysis | `rea investigate-versions` |
|
|
228
|
+
| Map a local JavaScript/Electron application without executing it | `rea analyze-javascript-application` |
|
|
229
|
+
| Reuse immutable analysis results without relaunching a provider | Pass `--snapshot /approved/path/analysis.json` to a deep-analysis command |
|
|
230
|
+
| Import source as historical reference | `rea import-reference-source` |
|
|
231
|
+
| Capture or compare controlled process behavior | `rea capture-process` or `rea compare-process-captures` |
|
|
231
232
|
|
|
232
233
|
Filesystem evidence commands and MCP file tools are disabled until the operator approves absolute roots:
|
|
233
234
|
|
|
@@ -238,6 +239,7 @@ rea evidence-import /absolute/path/to/evidence/bundle.json
|
|
|
238
239
|
rea evidence-export /absolute/path/to/evidence/bundle.json /absolute/path/to/evidence/canonical.json
|
|
239
240
|
rea compare /absolute/path/to/evidence/left.json /absolute/path/to/evidence/right.json
|
|
240
241
|
rea investigate-versions /absolute/path/to/releases/v1 /absolute/path/to/releases/v2 /absolute/path/to/evidence/releases.json --yes --workspace-name releases
|
|
242
|
+
rea analyze-javascript-application /absolute/path/to/releases/app.asar --approved --json
|
|
241
243
|
```
|
|
242
244
|
|
|
243
245
|
`investigate-versions` inventories both versions, checkpoints their observed
|
|
@@ -318,17 +320,19 @@ REA handles the app analysis in steps 1–5. The agent performs step 6 with its
|
|
|
318
320
|
- Analyze Swift and Objective-C metadata without manually untangling every mangled symbol.
|
|
319
321
|
- Leave names, comments, and bookmarks in Hopper so human and agent analysis reinforce each other.
|
|
320
322
|
|
|
321
|
-
##
|
|
323
|
+
## Tool catalog for investigation
|
|
322
324
|
|
|
323
|
-
| Tool family | Count | Examples
|
|
324
|
-
| ------------------------- | ----: |
|
|
325
|
-
| Native inspection | 33 | procedures, pseudocode, assembly, strings, names, segments, callers, callees, xrefs, annotations
|
|
326
|
-
| Investigation workflows | 10 | `binary_overview`, `analyze_function`, `batch_decompile`, `trace_feature`, call graphs, Swift and Objective-C discovery
|
|
327
|
-
| Native macOS utilities | 5 | Mach-O metadata, code signatures, plists, architectures, Swift demangling; Hopper-free and provenance-bearing
|
|
328
|
-
| Artifact graph | 2 | deterministic directory, ZIP/APK/IPA, and ASAR inventory; explicitly selected extraction into an absent owned tree
|
|
329
|
-
|
|
|
330
|
-
|
|
|
331
|
-
|
|
|
325
|
+
| Tool family | Count | Examples |
|
|
326
|
+
| ------------------------- | ----: | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
327
|
+
| Native inspection | 33 | procedures, pseudocode, assembly, strings, names, segments, callers, callees, xrefs, annotations |
|
|
328
|
+
| Investigation workflows | 10 | `binary_overview`, `analyze_function`, `batch_decompile`, `trace_feature`, call graphs, Swift and Objective-C discovery |
|
|
329
|
+
| Native macOS utilities | 5 | Mach-O metadata, code signatures, plists, architectures, Swift demangling; Hopper-free and provenance-bearing |
|
|
330
|
+
| Artifact graph | 2 | deterministic directory, ZIP/APK/IPA, and ASAR inventory; explicitly selected extraction into an absent owned tree |
|
|
331
|
+
| Managed PE/CLI | 8 | PE/CLI identity, metadata members, CIL hashes, P/Invoke/native-boundary declarations and verification, application-graph projection, decompiler reconstruction import, token remapping, runtime-correlation plans, and version comparison |
|
|
332
|
+
| Browser observation | 8 | exact-origin CDP capture, bundle and source-map analysis, WebMCP discovery, session timelines, capture diff, and visual evidence |
|
|
333
|
+
| Electron analysis | 4 | passive root-confined observation, bounded static application mapping, and evidence-backed static/runtime reconciliation |
|
|
334
|
+
| Application workflows | 3 | bounded cross-layer traces, unique-only version matching, and approved Linux-isolated extracted-module replay |
|
|
335
|
+
| Workspace and observation | 18 | target lifecycle, Evidence v2 bundles, process/artifact/function comparison, evidence-linked residual-unknown lifecycle |
|
|
332
336
|
|
|
333
337
|
The public interface describes what the agent is trying to learn. Providers decide how to answer. macOS utilities handle common semantic inspection without launching Hopper; Hopper handles deeper native analysis; the process harness implements controlled behavioral capture.
|
|
334
338
|
|
|
@@ -341,7 +345,10 @@ REA is already useful for native application, browser, and Electron investigatio
|
|
|
341
345
|
- Attach to a user-owned Chrome-family browser over a configured loopback CDP endpoint; capture exact-origin web structure, safe metadata, approved value-free payload shapes, bundle/source-map evidence, WebMCP declarations, user-action timelines, capture diffs, and explicitly approved screenshots without navigation or JavaScript evaluation.
|
|
342
346
|
- Inspect Electron `file://` renderer pages through a separate canonical-root permission boundary without invoking Electron APIs; script contents remain separately approved and byte bounded.
|
|
343
347
|
- Validate and canonically serialize a provider-neutral [JavaScript Application Graph v1](docs/javascript-application-graph.md) spanning packages, ASAR entries, Electron roles, JavaScript/source-map entities, browser/runtime instances, IPC, endpoints, storage, and native add-ons. This shipped domain contract performs no extraction or I/O by itself.
|
|
344
|
-
- Reconstruct bounded static package, entrypoint, Webpack/Rspack module, import, worker, endpoint, storage, source-map, and native-add-on structure from
|
|
348
|
+
- Reconstruct bounded static package, entrypoint, Webpack/Rspack module, import, worker, endpoint, storage, source-map, BrowserWindow, preload, contextBridge, IPC, utility-process, and native-add-on structure from an approved local directory or ASAR through `analyze_javascript_application` or `rea analyze-javascript-application`. The AST-only [application service](docs/javascript-artifact-reconstruction.md) never executes bootstrap code, pairs only unique exact literal IPC channels, and reports dynamic or ambiguous channels as unresolved.
|
|
349
|
+
- Reconcile that static graph with existing passive web or Electron Evidence through `reconcile_javascript_runtime` or `rea reconcile-javascript-runtime`. Exact captured bytes outrank caller-declared file/URL mappings; target, frame, script, worker, cache, and asset ambiguity stays explicit, source-map authority stays separate, and a module resident in an observed bundle is never reported as executed. See [JavaScript static/runtime reconciliation](docs/javascript-runtime-reconciliation.md).
|
|
350
|
+
- Trace a literal route, string, API, IPC channel, module, or native export through authenticated application Evidence with explicit traversal bounds, then hand exact native artifact digests and requested exports to retained Ghidra or Hopper Evidence without automatic provider switching. Compare application versions using unique-only digest, source-map, structural, and semantic tiers; duplicate, incomplete, and truncated matches stay unknown. See [cross-layer JavaScript application workflows](docs/javascript-application-workflows.md).
|
|
351
|
+
- Classify PE/CLI managed artifacts with `inspect_managed_artifact` / `rea inspect-managed-artifact`, inspect bounded metadata members, signatures, method-body CIL hashes, exception regions, call edges, and field-access anchors with `inspect_managed_members` / `rea inspect-managed-members`, inventory declared ModuleRef/ImplMap/PInvoke and non-IL method boundary indicators with `inspect_managed_native_boundaries` / `rea inspect-managed-native-boundaries`, then compare two authenticated member observations with `compare_managed_members` / `rea compare-managed-members`. `verify_managed_native_boundaries` / `rea verify-managed-native-boundaries` checks managed P/Invoke declarations against authenticated native export or function Evidence while keeping verified, inferred, contradicted, and unresolved states distinct. The comparison remaps build-local tokens using unique CIL/signature and structural method-shape tiers, never names alone. `project_managed_application_graph` / `rea project-managed-application-graph` projects authenticated managed artifact/member/native-boundary Evidence into the existing application graph for cross-layer feature tracing. `import_managed_reconstruction` / `rea import-managed-reconstruction` admits user-supplied decompiler C#/IL/pseudocode as analyst inference only after exact artifact SHA-256, MVID, signature, and normalized IL commitments match. Separately, `plan_managed_runtime_correlation` / `rea plan-managed-runtime-correlation` can admit a default-disabled, permission-gated runtime-correlation plan locked to the same build evidence. These paths never load the assembly, resolve CLR dependencies, execute target code, run a decompiler, or translate managed tokens into native addresses; native-body bridge mapping and an actual runtime executor remain future managed-code contracts.
|
|
345
352
|
- Traverse content-addressed artifact graphs without extraction; on macOS, read-only DMG traversal additionally requires `native_mount_approved: true` and `REA_ARTIFACT_NATIVE_MOUNT_ENABLED=true`. Materialize only approved occurrences into absent output roots.
|
|
346
353
|
- Build bounded function dossiers with pseudocode, assembly, CFG edges, comments, calls, references, strings, and names.
|
|
347
354
|
- Search and trace features across symbols, strings, metadata, references, and call paths.
|
|
@@ -386,24 +393,24 @@ REA is growing into a toolkit for understanding software across static artifacts
|
|
|
386
393
|
### Now
|
|
387
394
|
|
|
388
395
|
1. **Maintain truthful product metadata** — extend the shipped canonical catalog and drift checks whenever versions, tools, providers, schemas, setup clients, or CLI capabilities change.
|
|
389
|
-
2. **
|
|
390
|
-
3. **Cross-provider conformance growth** — add source-owned architectures and difficult indirect/thunk cases while preserving semantic comparison and provider-specific text boundaries.
|
|
396
|
+
2. **Cross-provider conformance growth** — add source-owned architectures and difficult indirect/thunk cases while preserving semantic comparison and provider-specific text boundaries.
|
|
391
397
|
|
|
392
398
|
### Next
|
|
393
399
|
|
|
394
|
-
1. **
|
|
395
|
-
2. **
|
|
396
|
-
3. **
|
|
400
|
+
1. **Controlled replay conformance growth** — extend the shipped Linux extracted-module sandbox with more source-owned hostile fixtures and cross-kernel conformance; browser or Electron interaction remains a different future authority.
|
|
401
|
+
2. **Broader application graph evidence** — extend authenticated cross-layer traces with additional static extractors and separately approved runtime authorities.
|
|
402
|
+
3. **Professional managed-code analysis** — extend shipped PE/CLI triage, CIL evidence, managed/native declaration inventory, source-owned conformance, and obfuscation-resistant comparisons toward verified native-provider composition under the accepted [managed-code boundary](docs/managed-code-analysis.md).
|
|
403
|
+
4. **Deterministic behavior harnesses** — extend process ownership, protocol fixtures, filesystem observation, reconnects, and cross-version behavioral comparison.
|
|
397
404
|
|
|
398
405
|
### Later
|
|
399
406
|
|
|
400
|
-
1. **Controlled interaction
|
|
407
|
+
1. **Controlled application interaction** — evaluate separately authorized full-application driving without widening passive browser, Electron, or extracted-module replay authority.
|
|
401
408
|
2. **Native runtime observation** — approval-gated LLDB, Frida, system logs, process/filesystem observers, and native API tracing.
|
|
402
409
|
3. **Additional providers and targets** — evaluate IDA/Hex-Rays, Binary Ninja, Rizin, LIEF, Windows-native providers, mobile artifacts, firmware, document formats, and other software-defined systems.
|
|
403
410
|
|
|
404
411
|
New providers must produce the same evidence and safety metadata as existing capabilities before they become part of the public workflow. Once REA has multiple optional toolchains, setup can become capability-selective; the consent rules for that future work are recorded in the [installation roadmap](docs/roadmap.md).
|
|
405
412
|
|
|
406
|
-
See the [static-analysis provider evaluation](docs/provider-evaluation.md) for the shipped Ghidra function-analysis boundary, remaining admission gates, and provider comparison matrix
|
|
413
|
+
See the [static-analysis provider evaluation](docs/provider-evaluation.md) for the shipped Ghidra function-analysis boundary, remaining admission gates, and provider comparison matrix; [ADR-0001](docs/adr/0001-provider-selection-and-analysis-profiles.md) for binding, selection, profile, snapshot, and compatibility decisions; the [controlled replay guide](docs/controlled-javascript-replay.md) plus [ADR-0002](docs/adr/0002-controlled-replay-authority-and-sandbox.md) for the shipped JavaScript replay boundary; and [ADR-0003](docs/adr/0003-managed-code-evidence-and-provider-boundary.md) for the managed-code evidence and provider design.
|
|
407
414
|
|
|
408
415
|
## Using REA with other agents
|
|
409
416
|
|
|
@@ -583,7 +590,7 @@ unpacked; REA does not silently accept the mismatched artifact.
|
|
|
583
590
|
|
|
584
591
|
## Security model
|
|
585
592
|
|
|
586
|
-
REA does not provide a hosted analysis service. Hopper and Ghidra bridge communication uses authenticated private local sockets. Dynamic capabilities are disabled by default and require both operator policy and explicit per-call approval.
|
|
593
|
+
REA does not provide a hosted analysis service. Hopper and Ghidra bridge communication uses authenticated private local sockets. Dynamic capabilities are disabled by default and require both operator policy and explicit per-call approval. Shipped providers, passive observers, and Process Capture are not security sandboxes: providers and launched targets run with the current user's permissions. Extracted JavaScript replay is a distinct Linux-only capability that fails closed unless Bubblewrap namespaces, architecture-checked seccomp, private runtime mounts, and delegated cgroup limits are available; it never inherits browser, Electron, or Process Capture authority. See [ADR-0002](docs/adr/0002-controlled-replay-authority-and-sandbox.md). Report vulnerabilities through the private process in [SECURITY.md](SECURITY.md).
|
|
587
594
|
|
|
588
595
|
## FAQ
|
|
589
596
|
|
|
@@ -44,6 +44,7 @@ export const buildCapabilityInventory = (sessionStatus, policy) => {
|
|
|
44
44
|
available: availability.reason === "available",
|
|
45
45
|
reason: availability.reason,
|
|
46
46
|
remediation: availability.remediation,
|
|
47
|
+
effects: { ...contract.effects },
|
|
47
48
|
annotations: {
|
|
48
49
|
read_only: contract.annotations.readOnlyHint ?? false,
|
|
49
50
|
destructive: contract.annotations.destructiveHint ?? false,
|
|
@@ -59,6 +60,23 @@ const availabilityFor = (name, kind, targetOpen, targetKind, descriptors, policy
|
|
|
59
60
|
reason: "policy_disabled",
|
|
60
61
|
remediation: "Enable or grant process_capture within the administrator ceiling.",
|
|
61
62
|
};
|
|
63
|
+
if (name === "run_controlled_replay" && !policy.javascriptReplayEnabled)
|
|
64
|
+
return {
|
|
65
|
+
reason: "policy_disabled",
|
|
66
|
+
remediation: "Enable javascript_replay with exact source roots and sandbox executables.",
|
|
67
|
+
};
|
|
68
|
+
if (name === "run_controlled_replay")
|
|
69
|
+
return { reason: "available", remediation: null };
|
|
70
|
+
if (name === "plan_managed_runtime_correlation" &&
|
|
71
|
+
!policy.managedRuntimeEnabled)
|
|
72
|
+
return {
|
|
73
|
+
reason: "policy_disabled",
|
|
74
|
+
remediation: "Enable managed_runtime with exact artifact roots and a runtime executable.",
|
|
75
|
+
};
|
|
76
|
+
if (name === "plan_managed_runtime_correlation")
|
|
77
|
+
return { reason: "available", remediation: null };
|
|
78
|
+
if (kind === "application")
|
|
79
|
+
return { reason: "available", remediation: null };
|
|
62
80
|
if (name === "import_evidence_bundle" && policy.evidenceFileRoots === 0)
|
|
63
81
|
return {
|
|
64
82
|
reason: "policy_disabled",
|
|
@@ -14,16 +14,20 @@ export const runCrossVersionInvestigation = async (input, policy, execution) =>
|
|
|
14
14
|
return err(new AnalysisInputError("find_changed_behavior", {
|
|
15
15
|
cause: parsed.error,
|
|
16
16
|
}));
|
|
17
|
-
|
|
17
|
+
return runCrossVersionInvestigationValidated(parsed.data, policy, execution);
|
|
18
|
+
};
|
|
19
|
+
/** Run input already parsed by a trusted adapter boundary. */
|
|
20
|
+
export const runCrossVersionInvestigationValidated = async (input, policy, execution) => {
|
|
21
|
+
const initial = await readInvestigationWorkspace(input.workspace_path, policy);
|
|
18
22
|
if (!initial.ok)
|
|
19
23
|
return initial;
|
|
20
|
-
const preflight = validateWorkspaceRequest(initial.value,
|
|
24
|
+
const preflight = validateWorkspaceRequest(initial.value, input);
|
|
21
25
|
if (!preflight.ok)
|
|
22
26
|
return preflight;
|
|
23
27
|
if (isCancelled(execution.signal))
|
|
24
28
|
return err(new AnalysisCancelledError("find_changed_behavior"));
|
|
25
|
-
if (
|
|
26
|
-
const replay = selectCompletedInvestigationReplay(initial.value,
|
|
29
|
+
if (input.replay_run_id !== undefined) {
|
|
30
|
+
const replay = selectCompletedInvestigationReplay(initial.value, input);
|
|
27
31
|
if (!replay.ok)
|
|
28
32
|
return replay;
|
|
29
33
|
return completeOutcome(replay.value.workspace, replay.value.run, true, execution.session);
|
|
@@ -39,7 +43,7 @@ export const runCrossVersionInvestigation = async (input, policy, execution) =>
|
|
|
39
43
|
total: 4,
|
|
40
44
|
message: "Scanning both version inputs",
|
|
41
45
|
});
|
|
42
|
-
const snapshots = await scanVersions(
|
|
46
|
+
const snapshots = await scanVersions(input, execution.inputRoots, execution.signal, execution.integrityContinueEnabled);
|
|
43
47
|
if (!snapshots.ok)
|
|
44
48
|
return snapshots;
|
|
45
49
|
await execution.progress?.report({
|
|
@@ -49,7 +53,7 @@ export const runCrossVersionInvestigation = async (input, policy, execution) =>
|
|
|
49
53
|
message: "Version inputs scanned",
|
|
50
54
|
});
|
|
51
55
|
return continueInvestigation({
|
|
52
|
-
input
|
|
56
|
+
input,
|
|
53
57
|
initial: initial.value,
|
|
54
58
|
snapshots: snapshots.value,
|
|
55
59
|
policy,
|
|
@@ -66,6 +66,9 @@ export const runDoctor = async (target, host = systemDoctorHost()) => {
|
|
|
66
66
|
classification: "config_drift",
|
|
67
67
|
}));
|
|
68
68
|
const providerInspections = await inspectDoctorProviders(host, checks);
|
|
69
|
+
const javascriptReplayCheck = await host.javascriptReplayCheck?.();
|
|
70
|
+
if (javascriptReplayCheck !== undefined)
|
|
71
|
+
checks.push(javascriptReplayCheck);
|
|
69
72
|
if (host.platform === "linux" && hopperPath !== undefined)
|
|
70
73
|
checks.push(check("hopper-demo-runtime", await host.linuxDemoRuntimeReady(), undefined, {
|
|
71
74
|
remediation: "Rerun rea setup to install the Xvfb, xauth, Python, X11, and XTEST packages required for Linux demo sessions.",
|
|
@@ -77,7 +80,33 @@ export const runDoctor = async (target, host = systemDoctorHost()) => {
|
|
|
77
80
|
classification: "config_drift",
|
|
78
81
|
}));
|
|
79
82
|
const installationPaths = (await host.installationPaths?.()) ?? [];
|
|
80
|
-
const
|
|
83
|
+
const observedSkillIdentity = await host.installedSkillIdentity?.();
|
|
84
|
+
const legacySkillVersion = observedSkillIdentity === undefined
|
|
85
|
+
? await host.installedSkillVersion?.()
|
|
86
|
+
: undefined;
|
|
87
|
+
const installedSkillIdentity = observedSkillIdentity ??
|
|
88
|
+
(legacySkillVersion === undefined
|
|
89
|
+
? undefined
|
|
90
|
+
: {
|
|
91
|
+
version: legacySkillVersion,
|
|
92
|
+
toolCount: null,
|
|
93
|
+
catalogDigest: null,
|
|
94
|
+
});
|
|
95
|
+
const installedSkillVersion = installedSkillIdentity?.version ?? undefined;
|
|
96
|
+
const skillAligned = installedSkillIdentity?.version === PRODUCT_IDENTITY.skillVersion &&
|
|
97
|
+
installedSkillIdentity.toolCount === CATALOG_IDENTITY.counts.mcp_tools &&
|
|
98
|
+
installedSkillIdentity.catalogDigest ===
|
|
99
|
+
CATALOG_IDENTITY.digests.combined_sha256;
|
|
100
|
+
if (!skillAligned)
|
|
101
|
+
checks.push({
|
|
102
|
+
name: "skill:identity",
|
|
103
|
+
ok: false,
|
|
104
|
+
classification: "config_drift",
|
|
105
|
+
detail: installedSkillIdentity === undefined
|
|
106
|
+
? "Installed REA skill identity is missing."
|
|
107
|
+
: "Installed REA skill identity is stale.",
|
|
108
|
+
remediation: "Run rea setup to update the installed REA skill.",
|
|
109
|
+
});
|
|
81
110
|
const registrations = (await host.clientRegistrations?.()) ?? [];
|
|
82
111
|
for (const registration of registrations)
|
|
83
112
|
if (registration.state !== "aligned")
|
|
@@ -120,13 +149,14 @@ export const runDoctor = async (target, host = systemDoctorHost()) => {
|
|
|
120
149
|
},
|
|
121
150
|
skill: {
|
|
122
151
|
installed_version: installedSkillVersion ?? null,
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
152
|
+
installed_tool_count: installedSkillIdentity?.toolCount ?? null,
|
|
153
|
+
installed_catalog_digest: installedSkillIdentity?.catalogDigest ?? null,
|
|
154
|
+
state: installedSkillIdentity === undefined
|
|
155
|
+
? "missing"
|
|
156
|
+
: skillAligned
|
|
126
157
|
? "aligned"
|
|
127
158
|
: "stale",
|
|
128
|
-
remediation:
|
|
129
|
-
installedSkillVersion === PRODUCT_IDENTITY.skillVersion
|
|
159
|
+
remediation: skillAligned
|
|
130
160
|
? null
|
|
131
161
|
: "Run rea setup to update the installed REA skill.",
|
|
132
162
|
},
|
|
@@ -220,6 +250,9 @@ export const systemDoctorHost = (options = {}) => ({
|
|
|
220
250
|
...(options.providerInspections === undefined
|
|
221
251
|
? {}
|
|
222
252
|
: { providerInspections: options.providerInspections }),
|
|
253
|
+
...(options.javascriptReplayCheck === undefined
|
|
254
|
+
? {}
|
|
255
|
+
: { javascriptReplayCheck: options.javascriptReplayCheck }),
|
|
223
256
|
async installationPaths() {
|
|
224
257
|
try {
|
|
225
258
|
const command = process.platform === "win32" ? "where" : "which";
|
|
@@ -239,6 +272,23 @@ export const systemDoctorHost = (options = {}) => ({
|
|
|
239
272
|
return undefined;
|
|
240
273
|
}
|
|
241
274
|
},
|
|
275
|
+
async installedSkillIdentity() {
|
|
276
|
+
try {
|
|
277
|
+
const content = await readFile(join(homedir(), ".agents/skills", PRODUCT_IDENTITY.skillName, "SKILL.md"), "utf8");
|
|
278
|
+
const version = /^\s{2}version:\s*"([^"]+)"\s*$/mu.exec(content)?.[1] ?? null;
|
|
279
|
+
const countText = /^\s{2}tool_count:\s*(\d+)\s*$/mu.exec(content)?.[1];
|
|
280
|
+
const catalogDigest = /^\s{2}catalog_digest:\s*"([a-f0-9]{64})"\s*$/mu.exec(content)?.[1] ??
|
|
281
|
+
null;
|
|
282
|
+
return {
|
|
283
|
+
version,
|
|
284
|
+
toolCount: countText === undefined ? null : Number.parseInt(countText, 10),
|
|
285
|
+
catalogDigest,
|
|
286
|
+
};
|
|
287
|
+
}
|
|
288
|
+
catch {
|
|
289
|
+
return undefined;
|
|
290
|
+
}
|
|
291
|
+
},
|
|
242
292
|
clientRegistrations: () => readClientRegistrationStatuses(homedir()),
|
|
243
293
|
});
|
|
244
294
|
const parseMajor = (version) => Number.parseInt(version.split(".")[0] ?? "0", 10);
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { resolveArtifactPath } from "./JavaScriptArtifactGraphContext.js";
|
|
2
|
+
/** Flatten all per-file IPC facts into deterministic application records. */
|
|
3
|
+
export const collectElectronIpcRecords = (analysis) => analysis.files
|
|
4
|
+
.flatMap(({ file, javascript }) => (javascript?.electron.ipc ?? []).map((finding) => ({
|
|
5
|
+
key: ipcRecordKey(file.path, finding),
|
|
6
|
+
file,
|
|
7
|
+
finding,
|
|
8
|
+
})))
|
|
9
|
+
.sort((left, right) => compareCodePoints(left.key, right.key));
|
|
10
|
+
/** Match only exact literal channels and retain ambiguous matches separately. */
|
|
11
|
+
export const classifyElectronIpcPairings = (records) => {
|
|
12
|
+
const handlers = records.filter(isMainHandler);
|
|
13
|
+
return records.filter(isPairableRendererTransmission).map((transmission) => {
|
|
14
|
+
const candidates = transmission.finding.channel === null
|
|
15
|
+
? []
|
|
16
|
+
: handlers.filter((handler) => handler.finding.channel === transmission.finding.channel &&
|
|
17
|
+
compatibleIpcModes(transmission.finding, handler.finding));
|
|
18
|
+
return {
|
|
19
|
+
transmission,
|
|
20
|
+
candidates,
|
|
21
|
+
status: candidates.length === 1
|
|
22
|
+
? "paired"
|
|
23
|
+
: candidates.length > 1
|
|
24
|
+
? "ambiguous"
|
|
25
|
+
: "unpaired",
|
|
26
|
+
};
|
|
27
|
+
});
|
|
28
|
+
};
|
|
29
|
+
/** Return only pairings supported by one unique literal main handler. */
|
|
30
|
+
export const unambiguousElectronIpcPairings = (records) => classifyElectronIpcPairings(records).flatMap((state) => {
|
|
31
|
+
const handler = state.candidates[0];
|
|
32
|
+
return state.status === "paired" && handler !== undefined
|
|
33
|
+
? [{ transmission: state.transmission, handler }]
|
|
34
|
+
: [];
|
|
35
|
+
});
|
|
36
|
+
/** Summarize static Electron findings without treating gaps as absence. */
|
|
37
|
+
export const summarizeElectronBoundaries = (analysis) => {
|
|
38
|
+
const files = new Map(analysis.files.map(({ file }) => [file.path, file]));
|
|
39
|
+
const javascript = analysis.files.flatMap(({ javascript: value }) => value === null ? [] : [value]);
|
|
40
|
+
const windows = javascript.flatMap(({ electron }) => electron.browser_windows);
|
|
41
|
+
const bridges = javascript.flatMap(({ electron }) => electron.context_bridge_apis);
|
|
42
|
+
const validations = javascript.flatMap(({ electron }) => electron.sender_validations);
|
|
43
|
+
const utilities = analysis.files.flatMap(({ file, javascript: value }) => (value?.electron.utility_processes ?? []).map((finding) => ({
|
|
44
|
+
file,
|
|
45
|
+
finding,
|
|
46
|
+
})));
|
|
47
|
+
const nativeBindings = analysis.files.flatMap(({ file, javascript: value }) => (value?.electron.native_addon_bindings ?? []).map((finding) => ({
|
|
48
|
+
file,
|
|
49
|
+
finding,
|
|
50
|
+
})));
|
|
51
|
+
const ipc = collectElectronIpcRecords(analysis);
|
|
52
|
+
const pairing = classifyElectronIpcPairings(ipc);
|
|
53
|
+
const literalChannels = new Set(ipc.flatMap(({ finding }) => finding.channel === null ? [] : [finding.channel]));
|
|
54
|
+
return {
|
|
55
|
+
browser_windows: windows.length,
|
|
56
|
+
explicit_web_preferences: windows.reduce((count, window) => count + window.web_preferences.length, 0),
|
|
57
|
+
preload_entrypoints: windows.filter(({ preload_path: path }) => path !== null).length,
|
|
58
|
+
context_bridge_apis: bridges.length,
|
|
59
|
+
exposed_api_members: bridges.reduce((count, bridge) => count + bridge.members.length, 0),
|
|
60
|
+
ipc: {
|
|
61
|
+
operations: ipc.length,
|
|
62
|
+
literal_channels: literalChannels.size,
|
|
63
|
+
dynamic_channel_operations: ipc.filter(({ finding }) => finding.channel === null).length,
|
|
64
|
+
renderer_transmissions: ipc.filter(isRendererTransmission).length,
|
|
65
|
+
renderer_listeners: ipc.filter(({ finding }) => finding.side === "renderer" && finding.mode === "listen").length,
|
|
66
|
+
main_handlers: ipc.filter(isMainHandler).length,
|
|
67
|
+
paired_renderer_transmissions: pairing.filter(({ status }) => status === "paired").length,
|
|
68
|
+
ambiguous_renderer_transmissions: pairing.filter(({ status }) => status === "ambiguous").length,
|
|
69
|
+
unpaired_literal_renderer_transmissions: pairing.filter(({ status, transmission }) => status === "unpaired" && transmission.finding.channel !== null).length,
|
|
70
|
+
},
|
|
71
|
+
sender_validation_observations: validations.length,
|
|
72
|
+
utility_processes: utilities.length,
|
|
73
|
+
resolved_utility_entrypoints: utilities.filter(({ file, finding }) => resolvesToFile(file, finding.module_path, files)).length,
|
|
74
|
+
native_addon_bindings: nativeBindings.length,
|
|
75
|
+
resolved_native_addon_bindings: nativeBindings.filter(({ file, finding }) => resolvesToFile(file, finding.specifier, files, "native-addon")).length,
|
|
76
|
+
};
|
|
77
|
+
};
|
|
78
|
+
const compatibleIpcModes = (transmission, handler) => transmission.mode === "invoke"
|
|
79
|
+
? handler.mode === "handle"
|
|
80
|
+
: transmission.operation === "send-to-host"
|
|
81
|
+
? false
|
|
82
|
+
: transmission.mode === "send" && handler.mode === "listen";
|
|
83
|
+
const isRendererTransmission = ({ finding }) => finding.side === "renderer" &&
|
|
84
|
+
(finding.mode === "send" || finding.mode === "invoke");
|
|
85
|
+
const isPairableRendererTransmission = (record) => isRendererTransmission(record) && record.finding.operation !== "send-to-host";
|
|
86
|
+
const isMainHandler = ({ finding }) => finding.side === "main" &&
|
|
87
|
+
(finding.mode === "listen" || finding.mode === "handle");
|
|
88
|
+
const resolvesToFile = (file, specifier, files, kind) => {
|
|
89
|
+
if (specifier === null)
|
|
90
|
+
return false;
|
|
91
|
+
const resolved = resolveArtifactPath(specifier, file.path, files);
|
|
92
|
+
return (resolved !== null &&
|
|
93
|
+
(kind === undefined || files.get(resolved)?.kind === kind));
|
|
94
|
+
};
|
|
95
|
+
const ipcRecordKey = (path, finding) => `${path}\0${String(finding.location.start.line)}:${String(finding.location.start.column)}\0${finding.side}\0${finding.operation}`;
|
|
96
|
+
const compareCodePoints = (left, right) => left < right ? -1 : left > right ? 1 : 0;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { addElectronIpcBoundaries } from "./ElectronBoundaryGraphIpc.js";
|
|
2
|
+
import { addElectronNativeBoundaries } from "./ElectronBoundaryGraphNative.js";
|
|
3
|
+
import { addElectronWindowBoundaries } from "./ElectronBoundaryGraphWindows.js";
|
|
4
|
+
/** Add every static Electron process and security-boundary fact to the JAG. */
|
|
5
|
+
export const addElectronBoundaries = (context) => {
|
|
6
|
+
addElectronWindowBoundaries(context);
|
|
7
|
+
addElectronIpcBoundaries(context);
|
|
8
|
+
addElectronNativeBoundaries(context);
|
|
9
|
+
};
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { sha256Text } from "../domain/javascriptStaticAnalysisHelpers.js";
|
|
2
|
+
import { astObservationEvidence, staticInferenceEvidence, } from "./JavaScriptArtifactGraphEvidence.js";
|
|
3
|
+
/** Resolve the file or recovered bundle module that owns one finding. */
|
|
4
|
+
export const electronFindingSourceNode = (context, file, moduleKey) => moduleKey === null
|
|
5
|
+
? (context.assetNodes.get(file.path) ?? context.fileNodes.get(file.path))
|
|
6
|
+
: context.moduleNodes.get(`${file.path}\0${moduleKey}`);
|
|
7
|
+
/** Observation-scoped identity shared safely across different artifact files. */
|
|
8
|
+
export const electronObservationIdentity = (context, scope, key) => ({
|
|
9
|
+
strategy: "observation-fingerprint",
|
|
10
|
+
stability: "observation-only",
|
|
11
|
+
observation_sha256: sha256Text(`${context.snapshot.manifest.root_sha256}\0${scope}\0${key}`),
|
|
12
|
+
scope: scope.slice(0, 4_096),
|
|
13
|
+
});
|
|
14
|
+
/** Add a direct AST syntax relationship. */
|
|
15
|
+
export const addElectronAstEdge = (context, input) => {
|
|
16
|
+
context.accumulator.addEdge({
|
|
17
|
+
source_node_id: input.source.node_id,
|
|
18
|
+
target_node_id: input.target.node_id,
|
|
19
|
+
relation: input.relation,
|
|
20
|
+
properties: input.properties,
|
|
21
|
+
evidence: astObservationEvidence({
|
|
22
|
+
sha256: input.file.sha256,
|
|
23
|
+
path: input.file.path,
|
|
24
|
+
range: input.range,
|
|
25
|
+
operation: input.operation,
|
|
26
|
+
coverage: input.coverage,
|
|
27
|
+
...(input.limitations === undefined
|
|
28
|
+
? {}
|
|
29
|
+
: { limitations: input.limitations }),
|
|
30
|
+
}),
|
|
31
|
+
});
|
|
32
|
+
};
|
|
33
|
+
/** Add an Electron relationship that static syntax suggests but cannot prove. */
|
|
34
|
+
export const addElectronInferenceEdge = (context, input) => {
|
|
35
|
+
context.accumulator.addEdge({
|
|
36
|
+
source_node_id: input.source.node_id,
|
|
37
|
+
target_node_id: input.target.node_id,
|
|
38
|
+
relation: input.relation,
|
|
39
|
+
properties: input.properties,
|
|
40
|
+
evidence: staticInferenceEvidence({
|
|
41
|
+
sha256: input.file.sha256,
|
|
42
|
+
path: input.file.path,
|
|
43
|
+
range: input.range,
|
|
44
|
+
operation: input.operation,
|
|
45
|
+
coverage: input.coverage,
|
|
46
|
+
...(input.confidence === undefined
|
|
47
|
+
? {}
|
|
48
|
+
: { confidence: input.confidence }),
|
|
49
|
+
...(input.limitations === undefined
|
|
50
|
+
? {}
|
|
51
|
+
: { limitations: input.limitations }),
|
|
52
|
+
}),
|
|
53
|
+
});
|
|
54
|
+
};
|
|
55
|
+
/** Deterministic source-range key for artifact-local graph identities. */
|
|
56
|
+
export const electronRangeKey = (range) => `${String(range.start.line)}:${String(range.start.column)}-${String(range.end.line)}:${String(range.end.column)}`;
|
|
57
|
+
/** Test exact source-range containment without assuming runtime reachability. */
|
|
58
|
+
export const electronRangeContains = (outer, inner) => comparePoint(outer.start, inner.start) <= 0 &&
|
|
59
|
+
comparePoint(outer.end, inner.end) >= 0;
|
|
60
|
+
const comparePoint = (left, right) => left.line === right.line
|
|
61
|
+
? left.column - right.column
|
|
62
|
+
: left.line - right.line;
|