rea-agents 6.2.0 → 6.3.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 +18 -20
- package/bridge/hopper_bridge.py +2 -0
- package/dist/android/JadxProvider.js +8 -2
- package/dist/android/JadxSession.js +51 -9
- package/dist/application/BinaryTargetResolver.js +63 -17
- package/dist/application/BrowserScenarioEvidence.js +2 -2
- package/dist/application/ClientConfigurationDocument.js +28 -0
- package/dist/application/ClientRegistrationStatus.js +19 -6
- package/dist/application/DirectAnalysis.js +12 -6
- package/dist/application/DirectAnalysisCleanup.js +0 -1
- package/dist/application/DirectAnalysisStatus.js +2 -5
- package/dist/application/Doctor.js +25 -34
- package/dist/application/DoctorDiagnostics.js +1 -1
- package/dist/application/EvidenceBundleFiles.js +1 -1
- package/dist/application/InvestigationProviders.js +4 -4
- package/dist/application/JsonFiles.js +15 -15
- package/dist/application/LinuxHopper.js +2 -1
- package/dist/application/ReconstructionObligationCandidates.js +9 -2
- package/dist/application/ReconstructionObligationLedgerProjection.js +3 -1
- package/dist/application/RegularFileRead.js +17 -0
- package/dist/application/Setup.js +18 -7
- package/dist/application/SetupClientConfiguration.js +18 -7
- package/dist/application/SetupHost.js +6 -4
- package/dist/application/SetupPlan.js +19 -15
- package/dist/application/SetupSkill.js +57 -8
- package/dist/application/SupportedClients.js +43 -0
- package/dist/application/Uninstall.js +18 -2
- package/dist/application/UpdateMaintenance.js +6 -2
- package/dist/application/Utf8JsonInput.js +64 -0
- package/dist/application/WebScriptExportService.js +13 -6
- package/dist/application/android/AndroidAnalysisService.js +1 -1
- package/dist/application/binary/AnalysisSnapshotCache.js +5 -4
- package/dist/application/binary/BinarySession.js +16 -0
- package/dist/application/binary/BinarySessionOpen.js +9 -1
- package/dist/application/javascript/ElectronActiveEvidence.js +2 -2
- package/dist/application/javascript/ElectronBoundaryAnalysis.js +2 -2
- package/dist/application/javascript/ElectronBoundaryGraphNative.js +5 -1
- package/dist/application/javascript/JavaScriptApplicationEvidence.js +1 -0
- package/dist/application/javascript/JavaScriptApplicationEvidenceGraph.js +107 -46
- package/dist/application/javascript/JavaScriptApplicationService.js +1 -0
- package/dist/application/javascript/JavaScriptApplicationWorkflowService.js +59 -45
- package/dist/application/javascript/JavaScriptArtifactAnalysis.js +0 -6
- package/dist/application/javascript/JavaScriptArtifactGraphBuilder.js +8 -18
- package/dist/application/javascript/JavaScriptArtifactGraphFindings.js +34 -26
- package/dist/application/javascript/JavaScriptArtifactPathResolution.js +44 -12
- package/dist/application/javascript/JavaScriptArtifactReconstruction.js +6 -3
- package/dist/application/javascript/JavaScriptArtifactReconstructionInput.js +1 -0
- package/dist/application/javascript/JavaScriptJsonModules.js +2 -2
- package/dist/application/javascript/JavaScriptModuleRelationships.js +5 -17
- package/dist/application/javascript/JavaScriptRuntimeReconciliationService.js +11 -27
- package/dist/application/javascript/JavaScriptSemanticGraphAsyncProjection.js +2 -2
- package/dist/application/javascript/JavaScriptSemanticGraphBuilder.js +8 -6
- package/dist/application/javascript/JavaScriptSemanticGraphChildProcessProjection.js +1 -1
- package/dist/application/javascript/JavaScriptSemanticGraphConstruction.js +7 -5
- package/dist/application/javascript/JavaScriptSemanticGraphDataProjection.js +1 -1
- package/dist/application/javascript/JavaScriptSemanticGraphEvidence.js +1 -1
- package/dist/application/javascript/JavaScriptSemanticGraphFingerprintProjection.js +2 -2
- package/dist/application/javascript/JavaScriptSemanticGraphFlowProjection.js +2 -2
- package/dist/application/javascript/JavaScriptSemanticGraphObjectProjection.js +1 -1
- package/dist/application/javascript/JavaScriptSemanticGraphProjection.js +4 -4
- package/dist/application/javascript/JavaScriptSemanticGraphResourceProjection.js +1 -1
- package/dist/application/javascript/JavaScriptSemanticGraphValueProjection.js +10 -7
- package/dist/application/javascript/JavaScriptSemanticTraceService.js +15 -10
- package/dist/application/native/NativeCallRoutes.js +2 -4
- package/dist/artifacts/ArtifactProvider.js +14 -16
- package/dist/artifacts/ArtifactProviderMetadata.js +1 -4
- package/dist/artifacts/AsarArtifactReader.js +81 -17
- package/dist/artifacts/DirectoryArtifactReader.js +2 -2
- package/dist/artifacts/NativeDmgArtifactReader.js +152 -67
- package/dist/artifacts/NativeDmgOwnership.js +109 -0
- package/dist/artifacts/apple/KeyedArchiveReader.js +54 -46
- package/dist/artifacts/apple/MachoLoadCommandReader.js +36 -6
- package/dist/artifacts/extraction/ArtifactExtraction.js +29 -11
- package/dist/artifacts/inventory/ArtifactGraphConstruction.js +7 -8
- package/dist/artifacts/inventory/classify.js +33 -14
- package/dist/artifacts/inventory/hashStableRootArtifact.js +37 -0
- package/dist/artifacts/inventory/scanCanonical.js +28 -22
- package/dist/artifacts/inventory/scanReader.js +7 -11
- package/dist/artifacts/javascript/JavaScriptArtifactFiles.js +65 -27
- package/dist/browser/CdpBrowserProvider.js +4 -3
- package/dist/browser/CdpCaptureStorageFingerprints.js +3 -3
- package/dist/browser/CdpElectronInspection.js +2 -2
- package/dist/browser/CdpElectronProvider.js +4 -3
- package/dist/browser/CdpElectronScripts.js +2 -2
- package/dist/browser/CdpWebMcpDiscovery.js +16 -13
- package/dist/browser/PlaywrightBrowserScenarioProvider.js +6 -6
- package/dist/browser/PlaywrightScenarioBrowser.js +145 -42
- package/dist/browser/PlaywrightScenarioSession.js +3 -11
- package/dist/browser/WebSourceMapFetcher.js +32 -6
- package/dist/browser/assets/ScenarioScriptCapture.js +8 -12
- package/dist/cli/coreAnalysisCommands.js +2 -2
- package/dist/cli/coreBinaryCommands.js +13 -9
- package/dist/cli/electronCommands.js +9 -10
- package/dist/cli/javascriptApplicationAnalysis.js +2 -12
- package/dist/cli/jsonOutput.js +3 -2
- package/dist/cli/streamedJsonOutput.js +83 -4
- package/dist/cli/utilityCommands.js +2 -4
- package/dist/cli.js +5 -2
- package/dist/cliJsonFile.js +179 -0
- package/dist/cliJsonInput.js +47 -34
- package/dist/cliObservationOptions.js +4 -0
- package/dist/composition/auxiliaryAnalysisProviders.js +5 -4
- package/dist/composition/browserScenario.js +2 -2
- package/dist/composition/directAnalysis.js +2 -3
- package/dist/contracts/artifactComparisonExample.js +5 -5
- package/dist/contracts/errorSchemas.js +3 -1
- package/dist/contracts/functionComparisonExample.js +8 -0
- package/dist/contracts/inputSchemaPresentation.js +94 -3
- package/dist/contracts/javascript/electronToolContracts.js +2 -1
- package/dist/contracts/javascript/javascriptApplicationWorkflowExamples.js +3 -2
- package/dist/contracts/javascript/javascriptExportShapeComparisonExample.js +6 -3
- package/dist/contracts/javascript/javascriptRuntimeReconciliationExample.js +8 -7
- package/dist/contracts/managed/managedToolContracts.js +3 -2
- package/dist/contracts/mobileApplicationGraphExamples.js +5 -5
- package/dist/contracts/native/nativeToolContracts.js +1 -1
- package/dist/contracts/sessionLifecycleInputs.js +4 -3
- package/dist/contracts/sessionStatusContract.js +3 -2
- package/dist/contracts/sessionToolContracts.js +3 -2
- package/dist/contracts/sessionToolSchemas.js +3 -2
- package/dist/contracts/toolOutputSchemaGroups.js +2 -2
- package/dist/contracts/toolOutputSchemaPrimitives.js +2 -5
- package/dist/domain/analysisErrorBase.js +5 -0
- package/dist/domain/analysisErrorPresentation.js +4 -2
- package/dist/domain/analysisSnapshot.js +3 -1
- package/dist/domain/analysisView/analysisView.js +1 -3
- package/dist/domain/android/androidPartialObservation.js +36 -0
- package/dist/domain/apple/dylibResolution.js +1 -1
- package/dist/domain/artifactComparison.js +4 -4
- package/dist/domain/artifactGraph.js +1 -1
- package/dist/domain/artifactIdentity.js +8 -8
- package/dist/domain/artifactInspection.js +8 -8
- package/dist/domain/artifactInventoryEvidence.js +5 -5
- package/dist/domain/browserCompleteness.js +3 -2
- package/dist/domain/browserScenarioCaptureValues.js +2 -2
- package/dist/domain/browserScenarioNormalization.js +3 -3
- package/dist/domain/browserScenarioValues.js +3 -2
- package/dist/domain/callPath.js +8 -10
- package/dist/domain/canonicalDigest.js +7 -1
- package/dist/domain/canonicalOrdering.js +1 -13
- package/dist/domain/changedBehavior.js +2 -3
- package/dist/domain/comparisonSemantics.js +0 -5
- package/dist/domain/digests.js +0 -3
- package/dist/domain/evidence.js +10 -5
- package/dist/domain/evidenceBundle.js +51 -33
- package/dist/domain/firmware/firmwareAnalysis.js +4 -3
- package/dist/domain/functionComparison.js +2 -1
- package/dist/domain/functionComparisonNormalization.js +4 -3
- package/dist/domain/functionComparisonResults.js +2 -2
- package/dist/domain/functionDossierEvidence.js +2 -1
- package/dist/domain/hopperValues.js +11 -15
- package/dist/domain/javascript/electronActiveObservation.js +4 -3
- package/dist/domain/javascript/electronStaticAnalysisBrowser.js +2 -2
- package/dist/domain/javascript/electronStaticAnalysisIpc.js +9 -1
- package/dist/domain/javascript/electronStaticAnalysisNative.js +5 -3
- package/dist/domain/javascript/electronStaticAnalysisValues.js +8 -4
- package/dist/domain/javascript/javascriptApplicationAnalysis.js +3 -1
- package/dist/domain/javascript/javascriptApplicationChangeGraph.js +12 -8
- package/dist/domain/javascript/javascriptApplicationEvidenceSchemas.js +4 -0
- package/dist/domain/javascript/javascriptApplicationGraph.js +15 -13
- package/dist/domain/javascript/javascriptApplicationVersionComparison.js +4 -4
- package/dist/domain/javascript/javascriptApplicationVersionComparisonSchemas.js +37 -22
- package/dist/domain/javascript/javascriptApplicationVersionItems.js +45 -34
- package/dist/domain/javascript/javascriptApplicationVersionKeys.js +7 -7
- package/dist/domain/javascript/javascriptAstFingerprint.js +2 -2
- package/dist/domain/javascript/javascriptAstValues.js +22 -0
- package/dist/domain/javascript/javascriptExportShapeComparison.js +3 -2
- package/dist/domain/javascript/javascriptExportShapeComparisonSchemas.js +31 -23
- package/dist/domain/javascript/javascriptExportShapeSelection.js +2 -2
- package/dist/domain/javascript/javascriptExportShapeVariants.js +3 -2
- package/dist/domain/javascript/javascriptFeatureSeed.js +5 -3
- package/dist/domain/javascript/javascriptFeatureTrace.js +7 -6
- package/dist/domain/javascript/javascriptFeatureTraceSchemas.js +17 -9
- package/dist/domain/javascript/javascriptFeatureTraversal.js +4 -4
- package/dist/domain/javascript/javascriptNativeHandoff.js +6 -6
- package/dist/domain/javascript/javascriptRuntimeObservation.js +8 -5
- package/dist/domain/javascript/javascriptRuntimeReconciliation.js +12 -6
- package/dist/domain/javascript/javascriptRuntimeReconciliationActive.js +9 -8
- package/dist/domain/javascript/javascriptRuntimeReconciliationCaptureParsing.js +212 -0
- package/dist/domain/javascript/javascriptRuntimeReconciliationGraph.js +5 -4
- package/dist/domain/javascript/javascriptRuntimeReconciliationInputValidation.js +28 -0
- package/dist/domain/javascript/javascriptRuntimeReconciliationMatching.js +5 -5
- package/dist/domain/javascript/javascriptRuntimeReconciliationParsing.js +12 -223
- package/dist/domain/javascript/javascriptRuntimeReconciliationResult.js +2 -2
- package/dist/domain/javascript/javascriptRuntimeReconciliationRuntime.js +15 -4
- package/dist/domain/javascript/javascriptRuntimeReconciliationSchemas.js +2 -2
- package/dist/domain/javascript/javascriptRuntimeStaticCandidates.js +7 -6
- package/dist/domain/javascript/javascriptSemanticAnalysis.js +200 -8
- package/dist/domain/javascript/javascriptSemanticCallResolution.js +9 -7
- package/dist/domain/javascript/javascriptSemanticChildProcesses.js +2 -2
- package/dist/domain/javascript/javascriptSemanticCoverage.js +20 -0
- package/dist/domain/javascript/javascriptSemanticDataEffectHelpers.js +7 -9
- package/dist/domain/javascript/javascriptSemanticDataEffects.js +4 -11
- package/dist/domain/javascript/javascriptSemanticFingerprints.js +2 -2
- package/dist/domain/javascript/javascriptSemanticGraph.js +142 -35
- package/dist/domain/javascript/javascriptSemanticGraphSchemas.js +19 -1
- package/dist/domain/javascript/javascriptSemanticIr.js +0 -4
- package/dist/domain/javascript/javascriptSemanticIterationSources.js +106 -0
- package/dist/domain/javascript/javascriptSemanticMemberMutations.js +497 -113
- package/dist/domain/javascript/javascriptSemanticMutationInitializers.js +190 -0
- package/dist/domain/javascript/javascriptSemanticMutationValues.js +41 -27
- package/dist/domain/javascript/javascriptSemanticObjects.js +2 -6
- package/dist/domain/javascript/javascriptSemanticPrimitives.js +7 -2
- package/dist/domain/javascript/javascriptSemanticProjection.js +20 -14
- package/dist/domain/javascript/javascriptSemanticPromises.js +15 -21
- package/dist/domain/javascript/javascriptSemanticPropertyPaths.js +23 -0
- package/dist/domain/javascript/javascriptSemanticProvenance.js +3 -3
- package/dist/domain/javascript/javascriptSemanticQuery.js +8 -2
- package/dist/domain/javascript/javascriptSemanticQueryIdentity.js +3 -2
- package/dist/domain/javascript/javascriptSemanticQuerySchemas.js +8 -9
- package/dist/domain/javascript/javascriptSemanticRequireOrigin.js +16 -10
- package/dist/domain/javascript/javascriptSemanticReturns.js +23 -27
- package/dist/domain/javascript/javascriptSemanticTraversal.js +6 -1
- package/dist/domain/javascript/javascriptSemanticValues.js +135 -24
- package/dist/domain/javascript/javascriptSourceMapPaths.js +11 -1
- package/dist/domain/javascript/javascriptSourceParser.js +34 -9
- package/dist/domain/javascript/javascriptStaticAnalysisBundler.js +5 -6
- package/dist/domain/javascript/javascriptStaticAnalysisHelpers.js +26 -15
- package/dist/domain/javascript/sourceToBundleComparison.js +7 -5
- package/dist/domain/javascript/sourceToBundleSignals.js +7 -7
- package/dist/domain/jsonSerialization.js +109 -55
- package/dist/domain/jsonShape.js +46 -19
- package/dist/domain/localPath.js +10 -4
- package/dist/domain/managed/managedApplicationGraph.js +10 -6
- package/dist/domain/managed/managedApplicationGraphNodes.js +82 -57
- package/dist/domain/managed/managedMemberComparisonMatch.js +6 -7
- package/dist/domain/native/nativeCallObservation.js +2 -4
- package/dist/domain/native/nativeValueFlow.js +5 -11
- package/dist/domain/native/objcSwiftMetadata.js +15 -17
- package/dist/domain/process/processCapture.js +11 -10
- package/dist/domain/process/processCaptureCoverage.js +8 -5
- package/dist/domain/process/processCaptureExample.js +43 -0
- package/dist/domain/process/processCaptureValidation.js +4 -3
- package/dist/domain/process/processComparison.js +0 -23
- package/dist/domain/process/processScenario.js +3 -3
- package/dist/domain/process/processTraceEvaluation.js +4 -4
- package/dist/domain/process/processTraceSpecification.js +1 -3
- package/dist/domain/providerCleanupError.js +6 -2
- package/dist/domain/reconstructionCoverage.js +2 -1
- package/dist/domain/reconstructionUnknowns.js +4 -3
- package/dist/domain/reconstructionVerification.js +3 -2
- package/dist/domain/referenceSourceGraph.js +7 -7
- package/dist/domain/referenceSourceImportParsing.js +34 -45
- package/dist/domain/residualUnknown.js +3 -2
- package/dist/domain/staticRuntimeCorrelation.js +2 -1
- package/dist/domain/swiftSymbolClassification.js +6 -1
- package/dist/domain/symbolAnalysis.js +17 -2
- package/dist/domain/unicodeCodePointOrder.js +6 -0
- package/dist/domain/webBundleAnalyzerInspection.js +9 -1
- package/dist/domain/webCaptureDiff.js +71 -29
- package/dist/domain/webCaptureDiffSchemas.js +2 -8
- package/dist/domain/webInventory.js +3 -2
- package/dist/domain/webMcpDiscovery.js +4 -3
- package/dist/domain/webScriptExport.js +1 -1
- package/dist/dotnet/ManagedMemberInstructionDecoder.js +1 -2
- package/dist/dotnet/ManagedStaticProvider.js +10 -7
- package/dist/dotnet/ManagedStaticProviderMetadata.js +1 -4
- package/dist/filesystem/RegularFile.js +41 -0
- package/dist/generatedPackageMetadata.js +1 -1
- package/dist/ghidra/GhidraClient.js +14 -4
- package/dist/ghidra/GhidraInstallation.js +111 -10
- package/dist/ghidra/GhidraLauncher.js +43 -19
- package/dist/hopper/HopperCleanup.js +1 -1
- package/dist/ida/IdaOperationRunner.js +2 -0
- package/dist/ida/IdaSessionClient.js +4 -2
- package/dist/inspector/JavaScriptRuntimeScope.js +9 -5
- package/dist/inspector/V8InspectorCaptureProjection.js +46 -13
- package/dist/inspector/V8InspectorProvider.js +60 -8
- package/dist/main/shutdown.js +76 -32
- package/dist/main/transport.js +1 -1
- package/dist/native/AppleObjcDispatchFacets.js +3 -3
- package/dist/native/AppleObjcProperties.js +17 -7
- package/dist/native/LldbCallTracer.js +241 -75
- package/dist/native/NativeMacOSProvider.js +10 -5
- package/dist/native/NativeMacOSProviderMetadata.js +1 -2
- package/dist/process/ProcessOwnershipObservation.js +9 -13
- package/dist/process/capture/FilesystemSnapshot.js +88 -18
- package/dist/process/capture/ProcessCaptureLifecycle.js +13 -27
- package/dist/process/capture/ProcessFilesystemEffects.js +19 -4
- package/dist/process/capture/ProcessHarness.js +8 -21
- package/dist/server/analysisAdmission.js +8 -0
- package/dist/server/createServer.js +22 -23
- package/dist/server/registerApplicationTools/compareExportShapes.js +2 -1
- package/dist/server/registerApplicationTools/helpers.js +3 -2
- package/dist/server/registerArtifactTools.js +2 -2
- package/dist/server/registerCloseLifecycleTool.js +6 -4
- package/dist/server/registerEnhancedTools.js +78 -73
- package/dist/server/registerEvidenceTools.js +54 -46
- package/dist/server/registerManagedTools.js +7 -4
- package/dist/server/registerOfficialTools.js +31 -25
- package/dist/server/registerSessionTools.js +9 -3
- package/native/windows/build/manifest.json +1 -1
- package/package.json +6 -3
- package/skills/reverse-engineer-anything/SKILL.md +5 -5
- package/skills/reverse-engineer-anything/references/native-and-artifacts.md +9 -0
- package/dist/artifacts/inventory/policy.js +0 -2
- package/dist/domain/managed/managedApplicationGraphNodeCoverage.js +0 -6
- package/dist/server/registerNativeTools.js +0 -6
package/README.md
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
[](https://www.npmjs.com/package/rea-agents)
|
|
12
12
|
[](https://github.com/morluto/rea/actions/workflows/ci.yml)
|
|
13
13
|
[](docs/mcp-contracts.md#generated-catalog)
|
|
14
|
-
[](#what-you-can-analyze)
|
|
15
15
|
[](https://skills.sh/morluto/rea/reverse-engineer-anything)
|
|
16
16
|
[](LICENSE)
|
|
17
17
|
[](https://discord.gg/GkcryMnJDM)
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
|
|
29
29
|
<img src="docs/assets/rea-hopper-analysis.png" alt="REA launching its analysis bridge inside Hopper while inspecting a native binary" width="1200" />
|
|
30
30
|
|
|
31
|
-
<br />
|
|
31
|
+
<br /><br />
|
|
32
32
|
|
|
33
33
|
<table aria-label="REA community">
|
|
34
34
|
<tr>
|
|
@@ -52,7 +52,7 @@ See a feature in an app that you want in your own product? Ask your agent to inv
|
|
|
52
52
|
|
|
53
53
|
REA connects your agent to tools for inspecting native binaries, JavaScript and Electron apps, .NET assemblies, and websites. You can also use the same tools from your terminal. Analysis runs locally, and results include the evidence and limitations behind each conclusion.
|
|
54
54
|
|
|
55
|
-
Setup registers REA with your agent and installs matching workflow instructions. Native analysis can use an existing Hopper or
|
|
55
|
+
Setup registers REA with your agent and installs matching workflow instructions. Native analysis can use an existing Hopper, Ghidra, or IDA installation; setup can optionally install Hopper with approval. Static JavaScript analysis needs no native analysis engine.
|
|
56
56
|
|
|
57
57
|
> **[Visit the REA website](https://rea.tools/)** for setup instructions, illustrated guides, and real case studies.
|
|
58
58
|
|
|
@@ -156,7 +156,7 @@ Additional tools and host support depend on the target:
|
|
|
156
156
|
| JavaScript / Electron | Modules, imports, source maps, routes, IPC and native add-on relationships | Node.js and npm; [application analysis](https://rea.tools/guides/javascript/) |
|
|
157
157
|
| Websites | Page structure, scripts, network observations and requested screenshots | A Chrome-family browser; [browser analysis](https://rea.tools/guides/browser/) |
|
|
158
158
|
| Saved network captures | Requests, responses, exposed payloads and source locations | HAR; mitmdump on Linux for native mitmproxy captures; [capture guide](docs/web-network-captures.md) |
|
|
159
|
-
| .NET assemblies | Metadata, CIL instructions, declared native dependencies and build comparisons |
|
|
159
|
+
| .NET assemblies | Metadata, CIL instructions, declared native dependencies and build comparisons | None (static only); [managed-code guide](docs/managed-code-analysis.md) |
|
|
160
160
|
| Android APKs | Manifest declarations, classes, decompiled methods and references | Headless JADX and a full JDK on Linux/macOS/Windows x64; [Android guide](docs/android-analysis.md) |
|
|
161
161
|
| Firmware | Regions, extraction results and native-analysis handoffs | Binwalk / Unblob on Linux; [firmware guide](docs/firmware-analysis.md) |
|
|
162
162
|
| Packages and resources | File inventories, digests, plists, Apple bundle anatomy and extracted resources | [Artifact and JavaScript guide](docs/javascript-artifact-reconstruction.md), [Apple applications](docs/apple-application-analysis.md) |
|
|
@@ -181,6 +181,8 @@ for features added since the latest npm release.
|
|
|
181
181
|
|
|
182
182
|
## Showcases
|
|
183
183
|
|
|
184
|
+
[](https://rea.tools/showcase/)
|
|
185
|
+
|
|
184
186
|
### DX-Ball: reconstruct a sound-pan calculation
|
|
185
187
|
|
|
186
188
|
Follow a sound call into its position-to-pan helper, inspect the instructions,
|
|
@@ -243,7 +245,7 @@ ask you to choose demo mode or activate your license. See
|
|
|
243
245
|
<details>
|
|
244
246
|
<summary><strong>What does installing the skill from skills.sh do?</strong></summary>
|
|
245
247
|
|
|
246
|
-
The skill supplies investigation instructions for your agent. Use `rea setup`
|
|
248
|
+
The skill supplies investigation instructions for your agent. Use `npx rea-agents setup`
|
|
247
249
|
to register REA's MCP server and install the matching instructions, then restart
|
|
248
250
|
your agent. See [skill-only installation](docs/installation.md#skill-only-installation).
|
|
249
251
|
|
|
@@ -303,23 +305,9 @@ For exact options, prerequisites and result contracts:
|
|
|
303
305
|
|
|
304
306
|
Report vulnerabilities through [SECURITY.md](SECURITY.md).
|
|
305
307
|
|
|
306
|
-
## Contributing
|
|
307
|
-
|
|
308
|
-
We'd love your help with REA! [Open an issue](https://github.com/morluto/rea/issues) to
|
|
309
|
-
report a bug or suggest a feature, or [send a pull request](https://github.com/morluto/rea/pulls)
|
|
310
|
-
to improve the code or docs.
|
|
311
|
-
|
|
312
|
-
See [CONTRIBUTING.md](CONTRIBUTING.md) for development setup and checks,
|
|
313
|
-
[testing](docs/testing.md) for verification lanes, and the
|
|
314
|
-
[architecture map](docs/architecture.mermaid) for the project structure.
|
|
315
|
-
|
|
316
|
-
## Project links
|
|
317
|
-
|
|
318
|
-
[Website](https://rea.tools/) · [npm](https://www.npmjs.com/package/rea-agents) · [skills.sh](https://skills.sh/morluto/rea/reverse-engineer-anything) · [Issues](https://github.com/morluto/rea/issues) · [Security](SECURITY.md)
|
|
319
|
-
|
|
320
308
|
## Star history
|
|
321
309
|
|
|
322
|
-
🎉 **
|
|
310
|
+
🎉 **40,000 GitHub stars — thank you!**
|
|
323
311
|
|
|
324
312
|
Thanks to everyone using REA, reporting bugs, requesting features, testing builds, and contributing fixes.
|
|
325
313
|
|
|
@@ -337,6 +325,16 @@ REA provides tools for lawful reverse-engineering research, analysis, and recons
|
|
|
337
325
|
|
|
338
326
|
REA is an open-source software project. We have not issued or endorsed any cryptocurrency or token. Tokens using the REA name are not affiliated with the project.
|
|
339
327
|
|
|
328
|
+
## Contributing
|
|
329
|
+
|
|
330
|
+
We'd love your help with REA! [Open an issue](https://github.com/morluto/rea/issues) to
|
|
331
|
+
report a bug or suggest a feature, or [send a pull request](https://github.com/morluto/rea/pulls)
|
|
332
|
+
to improve the code or docs.
|
|
333
|
+
|
|
334
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md) for development setup and checks,
|
|
335
|
+
[testing](docs/testing.md) for verification lanes, and the
|
|
336
|
+
[architecture map](docs/architecture.mermaid) for the project structure.
|
|
337
|
+
|
|
340
338
|
## License
|
|
341
339
|
|
|
342
340
|
[MIT](LICENSE)
|
package/bridge/hopper_bridge.py
CHANGED
|
@@ -716,6 +716,8 @@ def _analyze_function(document, params):
|
|
|
716
716
|
"referenced_strings": referenced_strings,
|
|
717
717
|
"referenced_names": referenced_names,
|
|
718
718
|
"basic_blocks": blocks,
|
|
719
|
+
"native_api": None,
|
|
720
|
+
"native_value_flow": None,
|
|
719
721
|
"limitations": [
|
|
720
722
|
"Native CallReference classifications are observed where available; detailed reference flags remain unknown.",
|
|
721
723
|
"Hopper's public Python API does not expose equivalent external or thunk classification in this dossier.",
|
|
@@ -71,7 +71,7 @@ const cleanup = async (resources) => {
|
|
|
71
71
|
}
|
|
72
72
|
catch (cause) {
|
|
73
73
|
// Retain an uncertain workspace until the caller can resolve process ownership.
|
|
74
|
-
|
|
74
|
+
const error = new ProviderCleanupError("jadx", [
|
|
75
75
|
session?.transport.runId ?? "unknown",
|
|
76
76
|
...(root === undefined ? [] : [root.path]),
|
|
77
77
|
], {
|
|
@@ -80,7 +80,10 @@ const cleanup = async (resources) => {
|
|
|
80
80
|
provider_cleanup: cause instanceof ProviderCleanupError
|
|
81
81
|
? (cause.diagnostics ?? null)
|
|
82
82
|
: null,
|
|
83
|
-
}, { cause: previousError ?? cause })
|
|
83
|
+
}, { cause: previousError ?? cause });
|
|
84
|
+
if (previousError?.partialObservation !== undefined)
|
|
85
|
+
error.retainPartialObservation(previousError.partialObservation);
|
|
86
|
+
return err(error);
|
|
84
87
|
}
|
|
85
88
|
try {
|
|
86
89
|
await root?.close();
|
|
@@ -287,6 +290,9 @@ export class JadxProvider {
|
|
|
287
290
|
signal: options?.signal,
|
|
288
291
|
session,
|
|
289
292
|
});
|
|
293
|
+
const partialObservation = session?.partialObservation();
|
|
294
|
+
if (partialObservation !== undefined)
|
|
295
|
+
previousError.retainPartialObservation(partialObservation);
|
|
290
296
|
// Admission can fail before selecting an existing session for execution.
|
|
291
297
|
root ??= this.#retained?.root;
|
|
292
298
|
session ??= this.#retained?.session;
|
|
@@ -13,12 +13,28 @@ export class JadxSession {
|
|
|
13
13
|
#client = new Client({ name: "rea-android-adapter", version: "1" });
|
|
14
14
|
#loaded;
|
|
15
15
|
#connected = false;
|
|
16
|
+
#partialContext;
|
|
17
|
+
#observedCalls = [];
|
|
18
|
+
#serverName = null;
|
|
19
|
+
#serverVersion = null;
|
|
20
|
+
#engineVersion = null;
|
|
16
21
|
constructor(options, launcher) {
|
|
17
22
|
this.transport = new JadxMcpTransport(options, launcher);
|
|
18
23
|
}
|
|
19
24
|
/** Analyze one admitted immutable APK, checking producer identity and selectors. */
|
|
20
25
|
async execute(context) {
|
|
21
26
|
const { request, target, snapshot, jarHash, signal } = context;
|
|
27
|
+
this.#partialContext = {
|
|
28
|
+
operation: request.operation,
|
|
29
|
+
selectedPath: request.input.path,
|
|
30
|
+
target,
|
|
31
|
+
jarHash,
|
|
32
|
+
bridgeHash: context.bridgeHash,
|
|
33
|
+
};
|
|
34
|
+
this.#observedCalls = [];
|
|
35
|
+
this.#serverName = null;
|
|
36
|
+
this.#serverVersion = null;
|
|
37
|
+
this.#engineVersion = null;
|
|
22
38
|
const abort = () => {
|
|
23
39
|
void this.transport.close().catch(() => undefined);
|
|
24
40
|
};
|
|
@@ -26,17 +42,19 @@ export class JadxSession {
|
|
|
26
42
|
try {
|
|
27
43
|
signal.throwIfAborted();
|
|
28
44
|
this.transport.beginOperation();
|
|
29
|
-
const raw = [];
|
|
30
45
|
if (!this.#connected) {
|
|
31
46
|
await this.#client.connect(this.transport, { timeout: 30_000 });
|
|
32
47
|
this.#connected = true;
|
|
33
48
|
}
|
|
34
49
|
const server = this.#client.getServerVersion();
|
|
50
|
+
this.#serverName = server?.name ?? null;
|
|
51
|
+
this.#serverVersion = server?.version ?? null;
|
|
35
52
|
if (server?.name !== JADX_BRIDGE_IDENTITY.name ||
|
|
36
53
|
server.version !== JADX_BRIDGE_IDENTITY.version)
|
|
37
54
|
throw new AnalysisCapabilityUnavailableError("jadx", request.operation, `Expected ${JADX_BRIDGE_IDENTITY.name} ${JADX_BRIDGE_IDENTITY.version}; server reported ${server?.name ?? "unknown"} ${server?.version ?? "unknown"}.`);
|
|
38
|
-
const tools = this.#tools(request, target, signal
|
|
55
|
+
const tools = this.#tools(request, target, signal);
|
|
39
56
|
const runtime = jadxRuntimeSchema.parse(await tools.json("rea_jvm_status", {}));
|
|
57
|
+
this.#engineVersion = runtime.engine_reported_version;
|
|
40
58
|
if (runtime.engine_reported_version !== JADX_RELEASE.version)
|
|
41
59
|
throw new AnalysisCapabilityUnavailableError("jadx", request.operation, `Expected engine ${JADX_RELEASE.version}; JAR reported ${runtime.engine_reported_version}.`);
|
|
42
60
|
const loaded = this.#loaded ??
|
|
@@ -63,7 +81,7 @@ export class JadxSession {
|
|
|
63
81
|
bridge_sha256: context.bridgeHash,
|
|
64
82
|
jar_sha256: jarHash,
|
|
65
83
|
loaded,
|
|
66
|
-
calls:
|
|
84
|
+
calls: this.#observedCalls,
|
|
67
85
|
},
|
|
68
86
|
subject: target,
|
|
69
87
|
limitations: JADX_LIMITATIONS,
|
|
@@ -76,6 +94,32 @@ export class JadxSession {
|
|
|
76
94
|
signal.removeEventListener("abort", abort);
|
|
77
95
|
}
|
|
78
96
|
}
|
|
97
|
+
/** Facts and upstream replies retained if a later request step fails. */
|
|
98
|
+
partialObservation() {
|
|
99
|
+
const context = this.#partialContext;
|
|
100
|
+
if (context === undefined)
|
|
101
|
+
return undefined;
|
|
102
|
+
return {
|
|
103
|
+
provider_id: "jadx",
|
|
104
|
+
operation: context.operation,
|
|
105
|
+
target: {
|
|
106
|
+
selected_path: context.selectedPath,
|
|
107
|
+
path: context.target.path,
|
|
108
|
+
sha256: context.target.sha256,
|
|
109
|
+
format: "apk",
|
|
110
|
+
},
|
|
111
|
+
provider_facts: {
|
|
112
|
+
jar_sha256: context.jarHash,
|
|
113
|
+
bridge_sha256: context.bridgeHash,
|
|
114
|
+
bridge_name: JADX_BRIDGE_IDENTITY.name,
|
|
115
|
+
bridge_version: JADX_BRIDGE_IDENTITY.version,
|
|
116
|
+
server_name: this.#serverName,
|
|
117
|
+
server_version: this.#serverVersion,
|
|
118
|
+
engine_version: this.#engineVersion,
|
|
119
|
+
},
|
|
120
|
+
calls: this.#observedCalls,
|
|
121
|
+
};
|
|
122
|
+
}
|
|
79
123
|
/** Whether the selected Java runtime established the REA bridge protocol. */
|
|
80
124
|
initialized() {
|
|
81
125
|
return this.#connected;
|
|
@@ -89,16 +133,14 @@ export class JadxSession {
|
|
|
89
133
|
await this.transport.close();
|
|
90
134
|
}
|
|
91
135
|
}
|
|
92
|
-
#tools(request, target, signal
|
|
136
|
+
#tools(request, target, signal) {
|
|
93
137
|
const call = async (name, input) => {
|
|
94
138
|
signal.throwIfAborted();
|
|
95
139
|
const response = await this.#client.callTool({ name, arguments: input }, { timeout: 120_000, signal });
|
|
140
|
+
const observedResponse = jsonValueSchema.parse(response);
|
|
141
|
+
const call = { operation: name, input, response: observedResponse };
|
|
142
|
+
this.#observedCalls.push(call);
|
|
96
143
|
const envelope = parseJadxEnvelope(response, request.operation);
|
|
97
|
-
raw.push({
|
|
98
|
-
operation: name,
|
|
99
|
-
input,
|
|
100
|
-
response: jsonValueSchema.parse(response),
|
|
101
|
-
});
|
|
102
144
|
if (envelope.failed) {
|
|
103
145
|
if (envelope.text.startsWith("{")) {
|
|
104
146
|
const failure = jadxInputFailureSchema.safeParse(parseJadxJson(envelope.text, request.operation));
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { constants } from "node:fs";
|
|
2
2
|
import { createHash } from "node:crypto";
|
|
3
|
-
import { access,
|
|
3
|
+
import { access, lstat, realpath, stat, } from "node:fs/promises";
|
|
4
4
|
import { extname, isAbsolute, resolve } from "node:path";
|
|
5
5
|
import { BinaryTargetError } from "../domain/configurationErrors.js";
|
|
6
|
+
import { openRegularFile, sameRegularFileState, } from "../filesystem/RegularFile.js";
|
|
7
|
+
import { AnalysisCancelledError } from "../domain/analysisErrorCore.js";
|
|
6
8
|
import { err, ok } from "../domain/result.js";
|
|
7
9
|
import { resolveAppBundleExecutable, } from "./AppBundleExecutable.js";
|
|
8
10
|
import { validateDosComLength, } from "../domain/dosCom.js";
|
|
@@ -14,30 +16,41 @@ import { parseExecutableHeader, parsePeRecord, } from "../domain/binaryTarget.js
|
|
|
14
16
|
* FAT Mach-O inputs select only a host-compatible architecture so setup remains
|
|
15
17
|
* non-interactive; unsupported or ambiguous inputs are returned as typed errors.
|
|
16
18
|
*/
|
|
17
|
-
export const parseBinaryTarget = async (input,
|
|
19
|
+
export const parseBinaryTarget = async (input, options = {}) => {
|
|
20
|
+
const cwd = options.cwd ?? process.cwd();
|
|
21
|
+
const hostArchitecture = options.hostArchitecture ?? process.arch;
|
|
22
|
+
const { targetKind, formatHint, signal } = options;
|
|
18
23
|
const candidate = isAbsolute(input) ? input : resolve(cwd, input);
|
|
19
24
|
try {
|
|
25
|
+
throwIfTargetResolutionCancelled(signal);
|
|
20
26
|
await access(candidate, constants.R_OK);
|
|
27
|
+
throwIfTargetResolutionCancelled(signal);
|
|
21
28
|
const canonical = await realpath(candidate);
|
|
29
|
+
throwIfTargetResolutionCancelled(signal);
|
|
22
30
|
const resolved = await resolveAppBundle(canonical);
|
|
31
|
+
throwIfTargetResolutionCancelled(signal);
|
|
23
32
|
if (!resolved.ok)
|
|
24
33
|
return err(resolved.error);
|
|
25
34
|
const { executable: path, infoPlist } = resolved.value;
|
|
26
35
|
const bundle = infoPlist === undefined ? {} : { bundleInfoPlist: infoPlist };
|
|
27
|
-
const handle = await
|
|
36
|
+
const handle = await openRegularFile(path, {
|
|
37
|
+
symlinks: "reject",
|
|
38
|
+
signal,
|
|
39
|
+
});
|
|
28
40
|
try {
|
|
29
|
-
|
|
30
|
-
|
|
41
|
+
throwIfTargetResolutionCancelled(signal);
|
|
42
|
+
const metadata = await handle.stat();
|
|
43
|
+
throwIfTargetResolutionCancelled(signal);
|
|
31
44
|
if (formatHint === "dos-com") {
|
|
32
45
|
if (targetKind !== undefined && targetKind !== "executable")
|
|
33
46
|
return err(new BinaryTargetError(path, "DOS COM format requires an executable target kind"));
|
|
34
|
-
const length = validateDosComLength(
|
|
47
|
+
const length = validateDosComLength(metadata.size);
|
|
35
48
|
if (!length.ok)
|
|
36
49
|
return err(new BinaryTargetError(path, length.error));
|
|
37
50
|
return ok({
|
|
38
51
|
path,
|
|
39
52
|
sourcePath: canonical,
|
|
40
|
-
sha256: await sha256Handle(handle),
|
|
53
|
+
sha256: await sha256Handle(handle, path, metadata, signal),
|
|
41
54
|
kind: "executable",
|
|
42
55
|
format: "dos-com",
|
|
43
56
|
architecture: "x86",
|
|
@@ -49,29 +62,29 @@ export const parseBinaryTarget = async (input, cwd = process.cwd(), hostArchitec
|
|
|
49
62
|
return ok({
|
|
50
63
|
path,
|
|
51
64
|
sourcePath: process.platform === "win32" ? candidate : canonical,
|
|
52
|
-
sha256: await sha256Handle(handle),
|
|
65
|
+
sha256: await sha256Handle(handle, path, metadata, signal),
|
|
53
66
|
kind: "database",
|
|
54
67
|
format: "analysis-database",
|
|
55
68
|
});
|
|
56
|
-
const artifactFormat = await detectArtifactFormat(path, handle);
|
|
69
|
+
const artifactFormat = await detectArtifactFormat(path, handle, signal);
|
|
57
70
|
if (artifactFormat !== undefined) {
|
|
58
71
|
const identity = {
|
|
59
72
|
path,
|
|
60
73
|
sourcePath: process.platform === "win32" ? candidate : canonical,
|
|
61
|
-
sha256: await sha256Handle(handle),
|
|
74
|
+
sha256: await sha256Handle(handle, path, metadata, signal),
|
|
62
75
|
};
|
|
63
76
|
return isArchiveFormat(artifactFormat)
|
|
64
77
|
? ok({ ...identity, kind: "archive", format: artifactFormat })
|
|
65
78
|
: ok({ ...identity, kind: "artifact", format: artifactFormat });
|
|
66
79
|
}
|
|
67
|
-
const detected = await readExecutableMetadata(handle, hostArchitecture);
|
|
80
|
+
const detected = await readExecutableMetadata(handle, hostArchitecture, signal);
|
|
68
81
|
if (!detected.ok)
|
|
69
82
|
return err(new BinaryTargetError(path, detected.error));
|
|
70
83
|
return ok({
|
|
71
84
|
path,
|
|
72
85
|
sourcePath: process.platform === "win32" ? candidate : canonical,
|
|
73
86
|
...bundle,
|
|
74
|
-
sha256: await sha256Handle(handle),
|
|
87
|
+
sha256: await sha256Handle(handle, path, metadata, signal),
|
|
75
88
|
kind: "executable",
|
|
76
89
|
...detected.value,
|
|
77
90
|
});
|
|
@@ -81,6 +94,10 @@ export const parseBinaryTarget = async (input, cwd = process.cwd(), hostArchitec
|
|
|
81
94
|
}
|
|
82
95
|
}
|
|
83
96
|
catch (cause) {
|
|
97
|
+
if (cause instanceof AnalysisCancelledError)
|
|
98
|
+
return err(cause);
|
|
99
|
+
if (cause instanceof BinaryTargetError)
|
|
100
|
+
return err(cause);
|
|
84
101
|
if (!(cause instanceof Error))
|
|
85
102
|
throw cause;
|
|
86
103
|
const code = filesystemErrorCode(cause);
|
|
@@ -103,14 +120,24 @@ const targetFailureReason = (code, detail) => {
|
|
|
103
120
|
return `permission denied while reading target: ${detail}`;
|
|
104
121
|
case "EISDIR":
|
|
105
122
|
return `target is a directory, not a readable file: ${detail}`;
|
|
123
|
+
case "ENOTFILE":
|
|
124
|
+
return "target is not a regular file";
|
|
125
|
+
case "ELOOP":
|
|
126
|
+
return `target changed while being opened: ${detail}`;
|
|
106
127
|
default:
|
|
107
128
|
return `target could not be read (${code}): ${detail}`;
|
|
108
129
|
}
|
|
109
130
|
};
|
|
110
|
-
const
|
|
131
|
+
const throwIfTargetResolutionCancelled = (signal) => {
|
|
132
|
+
if (signal?.aborted === true)
|
|
133
|
+
throw new AnalysisCancelledError("resolve_binary_target");
|
|
134
|
+
};
|
|
135
|
+
const detectArtifactFormat = async (path, handle, signal) => {
|
|
136
|
+
throwIfTargetResolutionCancelled(signal);
|
|
111
137
|
const lower = path.toLowerCase();
|
|
112
138
|
const magic = Buffer.alloc(8);
|
|
113
139
|
const observed = await handle.read(magic, 0, magic.length, 0);
|
|
140
|
+
throwIfTargetResolutionCancelled(signal);
|
|
114
141
|
if (hasZipSignature(magic.subarray(0, observed.bytesRead))) {
|
|
115
142
|
return zipPackageFormatForPath(lower) ?? "zip";
|
|
116
143
|
}
|
|
@@ -122,10 +149,13 @@ const detectArtifactFormat = async (path, handle) => {
|
|
|
122
149
|
magic.subarray(0, 4).toString("ascii") === "xar!")
|
|
123
150
|
return "pkg";
|
|
124
151
|
if (lower.endsWith(".dmg")) {
|
|
152
|
+
throwIfTargetResolutionCancelled(signal);
|
|
125
153
|
const size = (await handle.stat()).size;
|
|
154
|
+
throwIfTargetResolutionCancelled(signal);
|
|
126
155
|
if (size >= 512) {
|
|
127
156
|
const trailer = Buffer.alloc(4);
|
|
128
157
|
const read = await handle.read(trailer, 0, trailer.length, size - 512);
|
|
158
|
+
throwIfTargetResolutionCancelled(signal);
|
|
129
159
|
if (read.bytesRead === 4 && trailer.toString("ascii") === "koly")
|
|
130
160
|
return "dmg";
|
|
131
161
|
}
|
|
@@ -142,17 +172,25 @@ const namedArtifactFormat = (lowerPath) => {
|
|
|
142
172
|
return /\.(?:m?js|cjs)$/u.test(lowerPath) ? "javascript" : undefined;
|
|
143
173
|
};
|
|
144
174
|
const isArchiveFormat = (format) => ["zip", "ipa", "apk", "msix", "appx", "asar", "dmg", "pkg"].includes(format);
|
|
145
|
-
const sha256Handle = async (handle) => {
|
|
175
|
+
const sha256Handle = async (handle, path, initial, signal) => {
|
|
146
176
|
const hash = createHash("sha256");
|
|
147
177
|
const chunk = Buffer.allocUnsafe(64 * 1024);
|
|
148
178
|
let position = 0;
|
|
149
179
|
while (true) {
|
|
180
|
+
throwIfTargetResolutionCancelled(signal);
|
|
150
181
|
const observed = await handle.read(chunk, 0, chunk.length, position);
|
|
182
|
+
throwIfTargetResolutionCancelled(signal);
|
|
151
183
|
if (observed.bytesRead === 0)
|
|
152
184
|
break;
|
|
153
185
|
hash.update(chunk.subarray(0, observed.bytesRead));
|
|
154
186
|
position += observed.bytesRead;
|
|
155
187
|
}
|
|
188
|
+
throwIfTargetResolutionCancelled(signal);
|
|
189
|
+
const [opened, currentPath] = await Promise.all([handle.stat(), lstat(path)]);
|
|
190
|
+
if (!sameRegularFileState(initial, opened) ||
|
|
191
|
+
!sameRegularFileState(initial, currentPath) ||
|
|
192
|
+
position !== initial.size)
|
|
193
|
+
throw new BinaryTargetError(path, "target changed while being read");
|
|
156
194
|
return hash.digest("hex");
|
|
157
195
|
};
|
|
158
196
|
const resolveAppBundle = async (path) => {
|
|
@@ -165,19 +203,22 @@ const resolveAppBundle = async (path) => {
|
|
|
165
203
|
}));
|
|
166
204
|
return resolveAppBundleExecutable(path);
|
|
167
205
|
};
|
|
168
|
-
const readExecutableMetadata = async (handle, hostArchitecture) => {
|
|
206
|
+
const readExecutableMetadata = async (handle, hostArchitecture, signal) => {
|
|
207
|
+
throwIfTargetResolutionCancelled(signal);
|
|
169
208
|
const prefix = Buffer.alloc(4096);
|
|
170
209
|
const prefixRead = await handle.read(prefix, 0, prefix.length, 0);
|
|
210
|
+
throwIfTargetResolutionCancelled(signal);
|
|
171
211
|
const bytes = prefix.subarray(0, prefixRead.bytesRead);
|
|
172
212
|
// Header commitments such as Mach-O load commands and FAT slices are
|
|
173
213
|
// checked against the whole file, not the probed prefix.
|
|
174
214
|
const fileSize = (await handle.stat()).size;
|
|
215
|
+
throwIfTargetResolutionCancelled(signal);
|
|
175
216
|
if (bytes.length >= 2 && bytes[0] === 0x4d && bytes[1] === 0x5a) {
|
|
176
217
|
const offset = mzWindowsHeaderOffset(bytes);
|
|
177
218
|
if (offset !== null) {
|
|
178
219
|
if (offset < 64)
|
|
179
220
|
return err("invalid Windows new-header offset in MZ image");
|
|
180
|
-
return readPeMetadata(handle, offset);
|
|
221
|
+
return readPeMetadata(handle, offset, signal);
|
|
181
222
|
}
|
|
182
223
|
// MZ relocation records may extend past the initial probe; their format
|
|
183
224
|
// bounds are at most 65535 records inside a 65535-paragraph header.
|
|
@@ -190,6 +231,7 @@ const readExecutableMetadata = async (handle, hostArchitecture) => {
|
|
|
190
231
|
tableEnd <= fileSize) {
|
|
191
232
|
const table = Buffer.alloc(tableEnd);
|
|
192
233
|
const observed = await handle.read(table, 0, table.length, 0);
|
|
234
|
+
throwIfTargetResolutionCancelled(signal);
|
|
193
235
|
return parseExecutableHeader(table.subarray(0, observed.bytesRead), hostArchitecture, fileSize);
|
|
194
236
|
}
|
|
195
237
|
return parseExecutableHeader(bytes, hostArchitecture, fileSize);
|
|
@@ -203,15 +245,18 @@ const readExecutableMetadata = async (handle, hostArchitecture) => {
|
|
|
203
245
|
if (count <= 128 && required > bytes.length) {
|
|
204
246
|
const header = Buffer.alloc(required);
|
|
205
247
|
const headerRead = await handle.read(header, 0, header.length, 0);
|
|
248
|
+
throwIfTargetResolutionCancelled(signal);
|
|
206
249
|
return parseExecutableHeader(header.subarray(0, headerRead.bytesRead), hostArchitecture, fileSize);
|
|
207
250
|
}
|
|
208
251
|
}
|
|
209
252
|
}
|
|
210
253
|
return parseExecutableHeader(bytes, hostArchitecture, fileSize);
|
|
211
254
|
};
|
|
212
|
-
const readPeMetadata = async (handle, offset) => {
|
|
255
|
+
const readPeMetadata = async (handle, offset, signal) => {
|
|
256
|
+
throwIfTargetResolutionCancelled(signal);
|
|
213
257
|
const fileHeader = Buffer.alloc(24);
|
|
214
258
|
const fileHeaderRead = await handle.read(fileHeader, 0, fileHeader.length, offset);
|
|
259
|
+
throwIfTargetResolutionCancelled(signal);
|
|
215
260
|
if (fileHeaderRead.bytesRead !== fileHeader.length)
|
|
216
261
|
return err("invalid or truncated PE header");
|
|
217
262
|
const signature = fileHeader.toString("ascii", 0, 2);
|
|
@@ -222,6 +267,7 @@ const readPeMetadata = async (handle, offset) => {
|
|
|
222
267
|
return err("invalid PE optional header size");
|
|
223
268
|
const record = Buffer.alloc(24 + optionalHeaderSize);
|
|
224
269
|
const recordRead = await handle.read(record, 0, record.length, offset);
|
|
270
|
+
throwIfTargetResolutionCancelled(signal);
|
|
225
271
|
return recordRead.bytesRead === record.length
|
|
226
272
|
? parsePeRecord(record)
|
|
227
273
|
: err("invalid or truncated PE header");
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { digestCanonicalValue } from "../domain/canonicalDigest.js";
|
|
2
2
|
import { createEvidence, } from "../domain/evidence.js";
|
|
3
3
|
import { jsonObjectSchema, jsonValueSchema } from "../domain/jsonValue.js";
|
|
4
4
|
const browserScenarioParameters = (scenario) => ({
|
|
5
5
|
...jsonObjectSchema.parse(scenario),
|
|
6
|
-
scenario_sha256:
|
|
6
|
+
scenario_sha256: digestCanonicalValue(scenario, "Browser scenario"),
|
|
7
7
|
});
|
|
8
8
|
/** Create Evidence without retaining resolved scenario secret values. */
|
|
9
9
|
export const createBrowserScenarioEvidence = (scenario, capture, provider) => createEvidence(undefined, provider, {
|
|
@@ -858,6 +858,33 @@ const tomlServerEntry = (document, serverKey) => {
|
|
|
858
858
|
/** Whether Grok Build's root disable list names `serverKey`. */
|
|
859
859
|
export const grokServerListedDisabled = (document, serverKey) => Array.isArray(document.disabled_mcp_servers) &&
|
|
860
860
|
document.disabled_mcp_servers.includes(serverKey);
|
|
861
|
+
/**
|
|
862
|
+
* OMP's user `disabledServers` denylist hides a server by name regardless of
|
|
863
|
+
* its entry, so a listed REA registration is not loaded.
|
|
864
|
+
*/
|
|
865
|
+
export const OMP_DISABLED_SERVERS_KEY = "disabledServers";
|
|
866
|
+
/** Whether OMP's root `disabledServers` denylist names `serverKey`. */
|
|
867
|
+
export const ompServerListedDisabled = (document, serverKey) => {
|
|
868
|
+
const listed = document[OMP_DISABLED_SERVERS_KEY];
|
|
869
|
+
return Array.isArray(listed) && listed.includes(serverKey);
|
|
870
|
+
};
|
|
871
|
+
/** OMP's user `enabledServers` allowlist overrides an entry's `enabled: false`. */
|
|
872
|
+
const OMP_ENABLED_SERVERS_KEY = "enabledServers";
|
|
873
|
+
/**
|
|
874
|
+
* Whether OMP's allowlist forces `serverKey` on despite its entry's
|
|
875
|
+
* `enabled: false`. The `disabledServers` denylist still wins over it.
|
|
876
|
+
*/
|
|
877
|
+
export const clientServerForcedEnabled = (parsed, serverKey) => {
|
|
878
|
+
if (parsed.dialect !== "omp")
|
|
879
|
+
return false;
|
|
880
|
+
const listed = parsed.document[OMP_ENABLED_SERVERS_KEY];
|
|
881
|
+
return Array.isArray(listed) && listed.includes(serverKey);
|
|
882
|
+
};
|
|
883
|
+
/** Whether a client's own disable list suppresses `serverKey`. */
|
|
884
|
+
export const clientServerListedDisabled = (parsed, serverKey) => (parsed.dialect === "grok" &&
|
|
885
|
+
grokServerListedDisabled(parsed.document, serverKey)) ||
|
|
886
|
+
(parsed.dialect === "omp" &&
|
|
887
|
+
ompServerListedDisabled(parsed.document, serverKey));
|
|
861
888
|
/** Keep an existing Grok document intact aside from the REA server tables. */
|
|
862
889
|
const serializeGrokConfiguration = (document, originalText) => {
|
|
863
890
|
const entry = tomlServerEntry(document, PRODUCT_IDENTITY.mcpServerKey);
|
|
@@ -1051,6 +1078,7 @@ export const clientRegistrationEntry = (format, command, environment) => {
|
|
|
1051
1078
|
: { environment: { ...environment } }),
|
|
1052
1079
|
};
|
|
1053
1080
|
case "vscode":
|
|
1081
|
+
case "omp":
|
|
1054
1082
|
return {
|
|
1055
1083
|
type: "stdio",
|
|
1056
1084
|
command: executable,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { clientServerForcedEnabled, clientServerListedDisabled, effectiveClientServer, parseClientConfiguration, } from "./ClientConfigurationDocument.js";
|
|
2
2
|
import { access, readFile } from "node:fs/promises";
|
|
3
3
|
import { resolve } from "node:path";
|
|
4
4
|
import { z } from "zod";
|
|
@@ -29,7 +29,11 @@ export const readClientRegistrationStatuses = async (home, currentCommandPath =
|
|
|
29
29
|
CODEX_HOME: options.environment.CODEX_HOME,
|
|
30
30
|
COPILOT_HOME: options.environment.COPILOT_HOME,
|
|
31
31
|
GROK_HOME: options.environment.GROK_HOME,
|
|
32
|
+
OMP_PROFILE: options.environment.OMP_PROFILE,
|
|
32
33
|
OPENCODE_CONFIG: options.environment.OPENCODE_CONFIG,
|
|
34
|
+
PI_CODING_AGENT_DIR: options.environment.PI_CODING_AGENT_DIR,
|
|
35
|
+
PI_CONFIG_DIR: options.environment.PI_CONFIG_DIR,
|
|
36
|
+
PI_PROFILE: options.environment.PI_PROFILE,
|
|
33
37
|
SAND_DATA_ROOT: options.environment.SAND_DATA_ROOT,
|
|
34
38
|
XDG_CONFIG_HOME: options.environment.XDG_CONFIG_HOME,
|
|
35
39
|
})) {
|
|
@@ -61,9 +65,8 @@ export const readClientRegistrationStatuses = async (home, currentCommandPath =
|
|
|
61
65
|
registration.command,
|
|
62
66
|
...registration.args,
|
|
63
67
|
];
|
|
64
|
-
statuses.push(configuredStatus(client.name, client.configPath, command, registrationAligned(registration, client, currentCommandPath, options.platform ?? process.platform) &&
|
|
65
|
-
!(
|
|
66
|
-
grokServerListedDisabled(parsed.document, PRODUCT_IDENTITY.mcpServerKey))
|
|
68
|
+
statuses.push(configuredStatus(client.name, client.configPath, command, registrationAligned(registration, client, currentCommandPath, options.platform ?? process.platform, clientServerForcedEnabled(parsed, PRODUCT_IDENTITY.mcpServerKey)) &&
|
|
69
|
+
!clientServerListedDisabled(parsed, PRODUCT_IDENTITY.mcpServerKey)
|
|
67
70
|
? "aligned"
|
|
68
71
|
: "stale"));
|
|
69
72
|
}
|
|
@@ -73,9 +76,10 @@ export const readClientRegistrationStatuses = async (home, currentCommandPath =
|
|
|
73
76
|
}
|
|
74
77
|
return statuses.sort((left, right) => left.client.localeCompare(right.client));
|
|
75
78
|
};
|
|
76
|
-
const registrationAligned = (registration, client, currentCommandPath, platform) => {
|
|
79
|
+
const registrationAligned = (registration, client, currentCommandPath, platform, forcedEnabled = false) => {
|
|
77
80
|
const command = [registration.command, ...registration.args];
|
|
78
|
-
if (registration.disabled === true ||
|
|
81
|
+
if (registration.disabled === true ||
|
|
82
|
+
(registration.enabled === false && !forcedEnabled))
|
|
79
83
|
return false;
|
|
80
84
|
if (!isOwnedClientRegistrationCommand(command, currentCommandPath))
|
|
81
85
|
return false;
|
|
@@ -85,6 +89,11 @@ const registrationAligned = (registration, client, currentCommandPath, platform)
|
|
|
85
89
|
return false;
|
|
86
90
|
if (client.format === "vscode" && registration.type !== "stdio")
|
|
87
91
|
return false;
|
|
92
|
+
// OMP infers stdio for a command entry without an explicit type.
|
|
93
|
+
if (client.format === "omp" &&
|
|
94
|
+
registration.type !== undefined &&
|
|
95
|
+
registration.type !== "stdio")
|
|
96
|
+
return false;
|
|
88
97
|
if (client.format === "copilot_cli" &&
|
|
89
98
|
(registration.type !== "stdio" ||
|
|
90
99
|
JSON.stringify(registration.tools) !== JSON.stringify(["*"])))
|
|
@@ -127,6 +136,10 @@ const parseRegistration = (value, client) => {
|
|
|
127
136
|
throw new TypeError("Expected an stdio registration");
|
|
128
137
|
if (client.format === "commandcode" && registration.transport !== "stdio")
|
|
129
138
|
throw new TypeError("Expected an stdio registration");
|
|
139
|
+
if (client.format === "omp" &&
|
|
140
|
+
registration.type !== undefined &&
|
|
141
|
+
registration.type !== "stdio")
|
|
142
|
+
throw new TypeError("Expected an stdio registration");
|
|
130
143
|
return registration;
|
|
131
144
|
};
|
|
132
145
|
const remediation = "Run rea setup to refresh this registration, then restart the client.";
|