rea-agents 1.7.0 → 2.1.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 +112 -59
- package/bridge/ghidra/ReaGhidraBridge.java +96 -11
- package/dist/application/ArtifactExtraction.js +1 -1
- package/dist/application/ArtifactInventory/classify.js +42 -0
- package/dist/application/ArtifactInventory/hash.js +43 -0
- package/dist/application/ArtifactInventory/reader.js +41 -0
- package/dist/application/ArtifactInventory/scanCanonical.js +155 -0
- package/dist/application/ArtifactInventory/scanReader.js +124 -0
- package/dist/application/ArtifactInventory/types.js +10 -0
- package/dist/application/ArtifactInventory.js +9 -351
- package/dist/application/AuthorizedArtifactInventory.js +2 -2
- package/dist/application/BinarySession.js +47 -270
- package/dist/application/BinarySessionExecution.js +28 -0
- package/dist/application/BinarySessionOpen.js +39 -0
- package/dist/application/BinarySessionRecords.js +149 -0
- package/dist/application/BinarySessionStatus.js +75 -0
- package/dist/application/CapabilityInventory.js +42 -2
- package/dist/application/ClientRegistrationStatus.js +1 -1
- package/dist/application/CrossVersionInventory.js +8 -2
- package/dist/application/CrossVersionInvestigation.js +11 -29
- package/dist/application/CrossVersionInvestigationCollections.js +23 -0
- package/dist/application/DirectAnalysis.js +47 -44
- package/dist/application/Doctor.js +165 -197
- package/dist/application/DoctorDiagnostics.js +180 -0
- package/dist/application/ElectronBoundaryAnalysis.js +112 -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 +223 -0
- package/dist/application/EnhancedToolPagination.js +22 -0
- package/dist/application/EnhancedToolTypes.js +4 -0
- package/dist/application/EnhancedTools.js +58 -50
- package/dist/application/InstrumentedJavaScriptReplayHost.js +36 -0
- package/dist/application/InvestigationProviders.js +30 -0
- package/dist/application/InvestigationWorkspaceStore.js +24 -10
- 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 +52 -7
- package/dist/application/JavaScriptArtifactFiles.js +6 -2
- package/dist/application/JavaScriptArtifactGraphBuilder.js +82 -17
- package/dist/application/JavaScriptArtifactGraphBundlers.js +225 -0
- package/dist/application/JavaScriptArtifactGraphContext.js +37 -36
- package/dist/application/JavaScriptArtifactGraphDocuments.js +27 -4
- package/dist/application/JavaScriptArtifactGraphEvidence.js +24 -14
- package/dist/application/JavaScriptArtifactGraphFindings.js +54 -8
- package/dist/application/JavaScriptArtifactGraphStructure.js +29 -101
- package/dist/application/JavaScriptArtifactPathResolution.js +269 -0
- package/dist/application/JavaScriptArtifactReconstruction.js +4 -1
- package/dist/application/JavaScriptArtifactReconstructionInput.js +2 -83
- package/dist/application/JavaScriptJsonModules.js +39 -0
- package/dist/application/JavaScriptModuleRelationships.js +262 -0
- package/dist/application/JavaScriptReplayPermission.js +16 -0
- package/dist/application/JavaScriptReplayPlanning.js +201 -0
- package/dist/application/JavaScriptReplayService.js +292 -0
- package/dist/application/JavaScriptRuntimeReconciliationEvidence.js +25 -0
- package/dist/application/JavaScriptRuntimeReconciliationService.js +27 -0
- package/dist/application/LinuxHopper.js +10 -0
- package/dist/application/MacHopper.js +22 -11
- 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/NodeRuntimeCharacterizationService.js +196 -0
- package/dist/application/PermissionAuthority.js +106 -63
- package/dist/application/ProcessCaptureCapability.js +1 -1
- package/dist/application/ProcessCapturePermission.js +13 -0
- package/dist/application/ProcessCli.js +2 -12
- package/dist/application/ProcessHarness.js +1 -1
- package/dist/application/ProcessSampling.js +15 -11
- package/dist/application/ProjectPermissionStore.js +49 -9
- package/dist/application/RealHopperAssertions.js +76 -0
- package/dist/application/ReconstructionCoverageService.js +69 -0
- package/dist/application/ReconstructionCoverageWorkspaceStore.js +31 -0
- package/dist/application/RuntimeExecutableDiagnostics.js +172 -0
- package/dist/application/Setup.js +147 -259
- package/dist/application/SetupClientConfiguration.js +220 -0
- package/dist/application/SetupClients.js +24 -2
- package/dist/application/SetupPlan.js +123 -12
- package/dist/application/SetupSkill.js +26 -12
- package/dist/application/SupportedClients.js +1 -0
- package/dist/application/Uninstall.js +6 -3
- package/dist/application/WindowsCapabilities.js +86 -0
- package/dist/application/runtime.js +2 -0
- package/dist/artifacts/AsarArtifactReader.js +11 -0
- package/dist/browser/BrowserProcessStartup.js +88 -0
- package/dist/browser/CdpCaptureDocuments.js +12 -8
- package/dist/browser/CdpCaptureEventBodyShapes.js +75 -0
- package/dist/browser/CdpCaptureEventHandlers.js +336 -0
- package/dist/browser/CdpCaptureEventHelpers.js +71 -0
- package/dist/browser/CdpCaptureEventState.js +1 -0
- package/dist/browser/CdpCaptureEventTypes.js +1 -0
- package/dist/browser/CdpCaptureEvents.js +46 -464
- 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/CdpObservationSession.js +51 -8
- package/dist/browser/CdpPageCapture.js +12 -129
- package/dist/browser/CdpPageCaptureScripts.js +97 -0
- package/dist/browser/CdpPageCaptureWorkers.js +46 -0
- package/dist/browser/CdpWebMcpDiscovery.js +38 -14
- package/dist/browser/PngVisualDiff.js +9 -2
- package/dist/catalogIdentity.js +8 -1
- package/dist/cli/artifactCommands.js +82 -0
- package/dist/cli/coreAnalysisCommands.js +232 -0
- package/dist/cli/managedCommands.js +397 -0
- package/dist/cli/managedProjectGraphCommand.js +24 -0
- package/dist/cli/options.js +9 -0
- package/dist/cli/setupCommands.js +108 -0
- package/dist/cli/types.js +1 -0
- package/dist/cli/utilityCommands.js +122 -0
- package/dist/cli.js +13 -383
- package/dist/cliApplicationCommands.js +176 -0
- package/dist/cliBrowserAdvancedCommands.js +73 -16
- package/dist/cliBrowserCommands.js +39 -115
- package/dist/cliCommandNames.js +17 -0
- package/dist/cliElectronCommands.js +100 -27
- package/dist/cliEvidenceCommands.js +13 -2
- package/dist/cliInvestigationCommands.js +53 -10
- package/dist/cliJsonInput.js +54 -0
- package/dist/cliObservationOptions.js +137 -0
- package/dist/cliPolicyCommands.js +80 -46
- package/dist/cliSetup.js +289 -0
- package/dist/config/environment.js +107 -0
- package/dist/config/parseConfig.js +228 -0
- package/dist/config/parsers.js +68 -0
- package/dist/config/permissions.js +30 -0
- package/dist/config/types.js +1 -0
- package/dist/config.js +1 -292
- package/dist/contracts/applicationToolContracts.js +225 -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/providerSelection.js +2 -0
- package/dist/contracts/toolContractExamples.js +10 -25
- package/dist/contracts/toolContracts.js +49 -47
- package/dist/contracts/toolEffects.js +174 -0
- package/dist/contracts/toolOutputSchemaGroups.js +232 -0
- package/dist/contracts/toolOutputSchemaPrimitives.js +327 -0
- package/dist/contracts/toolOutputSchemas.js +2 -535
- package/dist/doctorRuntime.js +42 -1
- package/dist/domain/analysisErrorPresentation.js +234 -0
- package/dist/domain/analysisErrorProjection.js +284 -0
- package/dist/domain/artifactComparison.js +37 -19
- package/dist/domain/binaryTarget.js +87 -37
- package/dist/domain/browserObservation.js +1 -282
- package/dist/domain/browserObservationSchemas.js +286 -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 +206 -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 +32 -448
- package/dist/domain/functionComparison.js +4 -165
- package/dist/domain/functionComparisonDimensions.js +164 -0
- 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 +233 -0
- package/dist/domain/javascriptApplicationVersionKeys.js +170 -0
- package/dist/domain/javascriptExportInstrumentation.js +97 -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 +100 -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 +193 -0
- package/dist/domain/javascriptSemanticAnalysis.js +386 -0
- package/dist/domain/javascriptSemanticIr.js +30 -0
- package/dist/domain/javascriptSemanticProjection.js +366 -0
- package/dist/domain/javascriptSemanticState.js +40 -0
- package/dist/domain/javascriptSemanticTraversal.js +22 -0
- package/dist/domain/javascriptSemanticValues.js +352 -0
- package/dist/domain/javascriptStaticAnalysis.js +26 -254
- package/dist/domain/javascriptStaticAnalysisBundler.js +209 -0
- package/dist/domain/javascriptStaticAnalysisCalls.js +180 -0
- package/dist/domain/javascriptStaticAnalysisFindings.js +39 -0
- package/dist/domain/javascriptStaticAnalysisHelpers.js +81 -2
- package/dist/domain/javascriptStaticAnalysisState.js +6 -0
- package/dist/domain/knownPageCoverage.js +21 -0
- package/dist/domain/managedApplicationGraph.js +206 -0
- package/dist/domain/managedApplicationGraphCoverage.js +170 -0
- package/dist/domain/managedApplicationGraphNodeCoverage.js +6 -0
- package/dist/domain/managedApplicationGraphNodes.js +336 -0
- package/dist/domain/managedArtifact.js +452 -0
- package/dist/domain/managedMemberComparison.js +211 -0
- package/dist/domain/managedMemberComparisonCoverage.js +72 -0
- package/dist/domain/managedMemberComparisonMatch.js +356 -0
- package/dist/domain/managedNativeVerification.js +46 -0
- package/dist/domain/managedNativeVerificationMatch.js +272 -0
- package/dist/domain/managedNativeVerificationSchemas.js +141 -0
- package/dist/domain/managedReconstruction.js +196 -0
- package/dist/domain/managedRuntimeCorrelation.js +184 -0
- package/dist/domain/nodeRuntimeCharacterization.js +66 -0
- package/dist/domain/permissionPolicy.js +2 -0
- package/dist/domain/reconstructionCoverage.js +387 -0
- package/dist/domain/reconstructionCoverageEvaluation.js +212 -0
- package/dist/domain/reconstructionVerificationSchemas.js +9 -3
- package/dist/domain/runtimeCharacterization.js +85 -0
- package/dist/domain/webBundleAnalyzer.js +3 -409
- package/dist/domain/webBundleAnalyzerAst.js +77 -0
- package/dist/domain/webBundleAnalyzerInspection.js +307 -0
- package/dist/domain/webBundleAnalyzerResult.js +120 -0
- package/dist/dotnet/ManagedArtifactInspector.js +339 -0
- package/dist/dotnet/ManagedMemberInspector.js +153 -0
- package/dist/dotnet/ManagedMemberInspectorCore.js +297 -0
- package/dist/dotnet/ManagedMemberInstructionDecoder.js +427 -0
- package/dist/dotnet/ManagedMemberRows.js +120 -0
- package/dist/dotnet/ManagedMetadataHeaps.js +131 -0
- package/dist/dotnet/ManagedMetadataInventory.js +104 -0
- package/dist/dotnet/ManagedMetadataInventoryRows.js +292 -0
- package/dist/dotnet/ManagedMetadataLayout.js +259 -0
- package/dist/dotnet/ManagedMetadataRowSizes.js +54 -0
- package/dist/dotnet/ManagedMethodBodyReader.js +143 -0
- package/dist/dotnet/ManagedNativeBoundaryHelpers.js +311 -0
- package/dist/dotnet/ManagedNativeBoundaryInspector.js +143 -0
- package/dist/dotnet/ManagedPeReader.js +188 -0
- package/dist/dotnet/ManagedReaderFailure.js +10 -0
- package/dist/dotnet/ManagedStaticProvider.js +203 -0
- package/dist/generatedPackageMetadata.js +2 -2
- package/dist/ghidra/GhidraClient.js +76 -91
- package/dist/ghidra/GhidraClientStartup.js +29 -0
- package/dist/ghidra/GhidraClientWire.js +34 -0
- package/dist/ghidra/GhidraDefaults.js +1 -1
- package/dist/ghidra/GhidraDiagnostics.js +6 -1
- package/dist/ghidra/GhidraInstallation.js +20 -15
- package/dist/ghidra/GhidraLauncher.js +93 -29
- package/dist/ghidra/GhidraProvider.js +67 -161
- package/dist/ghidra/GhidraProviderCapabilities.js +173 -0
- package/dist/ghidra/GhidraSessionValues.js +2 -0
- package/dist/ghidra/GhidraSocketConnection.js +44 -7
- package/dist/ghidra/GhidraTargetSnapshot.js +30 -0
- package/dist/ghidra/GhidraTransport.js +71 -0
- package/dist/identity.js +3 -2
- package/dist/main/messages.js +5 -0
- package/dist/main/reload.js +49 -0
- package/dist/main/shutdown.js +25 -0
- package/dist/main/startup.js +14 -0
- package/dist/main/state.js +26 -0
- package/dist/main/transport.js +61 -0
- package/dist/main/types.js +1 -0
- package/dist/main.js +35 -132
- package/dist/process/PrivateRuntimeRoot.js +3 -2
- package/dist/process/ProcessOwnership.js +35 -0
- package/dist/process/ProviderProcess.js +2 -0
- package/dist/replay/JavaScriptReplayWorker.js +300 -0
- package/dist/replay/LinuxJavaScriptReplayRunner.js +217 -0
- package/dist/replay/LinuxJavaScriptReplaySandbox.js +140 -0
- package/dist/replay/LinuxRuntimeClosure.js +46 -0
- package/dist/replay/LinuxSeccompPolicy.js +40 -0
- package/dist/replay/ReplayOutcome.js +95 -0
- package/dist/replay/ReplayProcessLifecycle.js +71 -0
- package/dist/replay/ReplayWorkerProtocol.js +55 -0
- package/dist/replay/SystemJavaScriptReplayHost.js +182 -0
- package/dist/server/ProcessCaptureElicitation.js +157 -0
- package/dist/server/createServer.js +158 -41
- package/dist/server/registerApplicationTools/characterization.js +57 -0
- package/dist/server/registerApplicationTools/compareVersions.js +34 -0
- package/dist/server/registerApplicationTools/controlledReplay.js +38 -0
- package/dist/server/registerApplicationTools/coverage.js +84 -0
- package/dist/server/registerApplicationTools/helpers.js +42 -0
- package/dist/server/registerApplicationTools/traceFeature.js +26 -0
- package/dist/server/registerApplicationTools/types.js +1 -0
- package/dist/server/registerApplicationTools.js +13 -0
- package/dist/server/registerArtifactComparisonTool.js +16 -9
- package/dist/server/registerBrowserTools.js +61 -60
- package/dist/server/registerBundleComparisonTool.js +17 -20
- package/dist/server/registerElectronTools.js +39 -12
- package/dist/server/registerEnhancedTools.js +52 -15
- package/dist/server/registerEvidenceResources.js +54 -0
- package/dist/server/registerEvidenceTools.js +5 -1
- package/dist/server/registerFunctionComparisonTool.js +14 -7
- package/dist/server/registerInvestigationTools/helpers.js +74 -0
- package/dist/server/registerInvestigationTools/types.js +1 -0
- package/dist/server/registerInvestigationTools.js +103 -132
- package/dist/server/registerManagedTools.js +6 -0
- package/dist/server/registerManagedWorkflowTools/compareManagedMembers.js +65 -0
- package/dist/server/registerManagedWorkflowTools/contract.js +8 -0
- package/dist/server/registerManagedWorkflowTools/evidence.js +43 -0
- package/dist/server/registerManagedWorkflowTools/importManagedReconstruction.js +39 -0
- package/dist/server/registerManagedWorkflowTools/planManagedRuntimeCorrelation.js +39 -0
- package/dist/server/registerManagedWorkflowTools/projectManagedApplicationGraph.js +52 -0
- package/dist/server/registerManagedWorkflowTools/types.js +1 -0
- package/dist/server/registerManagedWorkflowTools/verifyManagedNativeBoundaries.js +75 -0
- package/dist/server/registerManagedWorkflowTools.js +13 -0
- package/dist/server/registerOfficialTools.js +81 -67
- package/dist/server/registerProcessComparisonTool.js +25 -47
- package/dist/server/registerSessionRecordTools.js +137 -0
- package/dist/server/registerSessionStatusTool.js +9 -8
- package/dist/server/registerSessionTools.js +77 -216
- package/dist/server/sessionAvailabilityPolicy.js +10 -0
- package/dist/server/sessionEvidence.js +14 -19
- package/dist/server/toolInputValidation.js +77 -0
- package/dist/server/toolRegistrationOptions.js +177 -2
- package/dist/server/toolResult.js +30 -17
- package/package.json +21 -14
- package/scripts/rea.mjs +1 -1
- package/skills/{rea-analysis → reverse-engineer-anything}/SKILL.md +75 -6
- package/scripts/prepare-node-pty.mjs +0 -35
- package/scripts/rebuild-native.mjs +0 -22
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
import { ENHANCED_TOOL_CONTRACTS, OFFICIAL_TOOL_CONTRACTS, } from "../contracts/toolContracts.js";
|
|
2
|
+
import { GHIDRA_DECOMPILE_REQUEST_TIMEOUT_MS, GHIDRA_MAX_LINE_BYTES, GHIDRA_REQUEST_TIMEOUT_MS, } from "./GhidraDefaults.js";
|
|
3
|
+
import { GHIDRA_FUNCTION_OPERATIONS } from "./GhidraFunctionValues.js";
|
|
4
|
+
import { GHIDRA_INVENTORY_OPERATIONS } from "./GhidraInventoryValues.js";
|
|
5
|
+
/** Public identity committed by every Ghidra-backed observation. */
|
|
6
|
+
export const GHIDRA_PROVIDER_IDENTITY = Object.freeze({
|
|
7
|
+
id: "ghidra",
|
|
8
|
+
name: "Ghidra",
|
|
9
|
+
version: null,
|
|
10
|
+
});
|
|
11
|
+
const providerContractByName = new Map([...OFFICIAL_TOOL_CONTRACTS, ...ENHANCED_TOOL_CONTRACTS].map((contract) => [
|
|
12
|
+
contract.name,
|
|
13
|
+
contract,
|
|
14
|
+
]));
|
|
15
|
+
/** Provider-neutral read-only contracts implemented by the Ghidra adapter. */
|
|
16
|
+
export const GHIDRA_PROVIDER_TOOL_CONTRACTS = Object.freeze([...GHIDRA_INVENTORY_OPERATIONS, ...GHIDRA_FUNCTION_OPERATIONS].map((operation) => {
|
|
17
|
+
const contract = providerContractByName.get(operation);
|
|
18
|
+
if (contract === undefined)
|
|
19
|
+
throw new TypeError(`Missing provider-neutral contract for ${operation}`);
|
|
20
|
+
return contract;
|
|
21
|
+
}));
|
|
22
|
+
const PAGINATED_OPERATIONS = new Set([
|
|
23
|
+
"list_names",
|
|
24
|
+
"list_procedures",
|
|
25
|
+
"list_strings",
|
|
26
|
+
"search_procedures",
|
|
27
|
+
"search_strings",
|
|
28
|
+
"procedure_references",
|
|
29
|
+
"analyze_function",
|
|
30
|
+
]);
|
|
31
|
+
const SEARCH_OPERATIONS = new Set([
|
|
32
|
+
"search_procedures",
|
|
33
|
+
"search_strings",
|
|
34
|
+
]);
|
|
35
|
+
const DECOMPILE_OPERATIONS = new Set([
|
|
36
|
+
"procedure_pseudo_code",
|
|
37
|
+
"analyze_function",
|
|
38
|
+
]);
|
|
39
|
+
/** Health limitations shared by every Ghidra-backed capability. */
|
|
40
|
+
export const healthLimitations = Object.freeze([
|
|
41
|
+
"The session serves operations only after default Ghidra auto-analysis completes; an analysis timeout fails the open instead of exposing partial results.",
|
|
42
|
+
"The imported Program and temporary project are ephemeral, read-only to REA, and deleted on close.",
|
|
43
|
+
]);
|
|
44
|
+
/** Additional limitations applied to the experimental Windows x64 P0 boundary. */
|
|
45
|
+
export const windowsP0Limitations = Object.freeze([
|
|
46
|
+
"Windows Ghidra P0 accepts approved native x86-64 PE applications only; DLL, managed, hostile, sensitive, and mutable-path targets are unsupported.",
|
|
47
|
+
"The Windows bridge uses authenticated IPv4 loopback because Node path-based IPC does not expose Java AF_UNIX sockets; the endpoint file contains no bearer token.",
|
|
48
|
+
"Windows P0 process-tree cleanup uses bounded taskkill termination and does not claim Job Object ownership, private DACL enforcement, or reparse-point-safe path authority.",
|
|
49
|
+
]);
|
|
50
|
+
/** Limitation text for one admitted operation, including the common base. */
|
|
51
|
+
export const limitationsFor = (operation) => {
|
|
52
|
+
const common = [
|
|
53
|
+
...healthLimitations,
|
|
54
|
+
"Default-space addresses use lowercase 0x-prefixed hexadecimal; other address spaces use <percent-encoded-space>:0x<hex>.",
|
|
55
|
+
];
|
|
56
|
+
switch (operation) {
|
|
57
|
+
case "list_documents":
|
|
58
|
+
return [
|
|
59
|
+
...common,
|
|
60
|
+
"A headless Ghidra session contains exactly one imported Program, unlike Hopper's multi-document GUI session.",
|
|
61
|
+
];
|
|
62
|
+
case "list_names":
|
|
63
|
+
return [
|
|
64
|
+
...common,
|
|
65
|
+
"The symbol inventory includes memory and external symbols, including dynamic symbols, but excludes variable and no-address namespace records.",
|
|
66
|
+
];
|
|
67
|
+
case "list_procedures":
|
|
68
|
+
case "procedure_address":
|
|
69
|
+
return [
|
|
70
|
+
...common,
|
|
71
|
+
"External functions and local thunks are distinct; procedure metadata identifies both and preserves a thunk target when Ghidra resolves one.",
|
|
72
|
+
];
|
|
73
|
+
case "list_strings":
|
|
74
|
+
return [
|
|
75
|
+
...common,
|
|
76
|
+
"Only Ghidra-defined string Data is observed; charset is reported, while a non-missing terminator cannot distinguish a present terminator from a fixed or Pascal layout.",
|
|
77
|
+
"Returned values are bounded to 1,024 Unicode code points and mark value_truncated instead of silently crossing the wire budget.",
|
|
78
|
+
];
|
|
79
|
+
case "list_segments":
|
|
80
|
+
return [
|
|
81
|
+
...common,
|
|
82
|
+
"Memory-block end addresses are exclusive; permissions come from Ghidra MemoryBlock flags rather than inference from section names.",
|
|
83
|
+
];
|
|
84
|
+
case "search_procedures":
|
|
85
|
+
case "search_strings":
|
|
86
|
+
return [
|
|
87
|
+
...common,
|
|
88
|
+
"Literal search enforces 1,000,000 cumulative work units; regex mode also accepts only a conservative finite Java-regex subset with 10,000 static paths and 4,096 UTF-16 code units per candidate.",
|
|
89
|
+
];
|
|
90
|
+
case "procedure_pseudo_code":
|
|
91
|
+
return [
|
|
92
|
+
...common,
|
|
93
|
+
"Pseudocode is Ghidra decompiler output, not original source and not text-equivalent to Hopper output; each decompile has a 30-second native deadline.",
|
|
94
|
+
"External functions and functions without an analyzable body return null; other decompiler failures remain explicit.",
|
|
95
|
+
];
|
|
96
|
+
case "procedure_assembly":
|
|
97
|
+
return [
|
|
98
|
+
...common,
|
|
99
|
+
"Assembly is Ghidra Listing text and fails rather than silently truncating when the 100,000-instruction or 1 MiB wire bound is exceeded.",
|
|
100
|
+
];
|
|
101
|
+
case "procedure_callers":
|
|
102
|
+
case "procedure_callees":
|
|
103
|
+
return [
|
|
104
|
+
...common,
|
|
105
|
+
"Only resolved Ghidra call references are returned; unresolved computed or indirect calls remain unknown, while function classifications distinguish thunks and externals.",
|
|
106
|
+
];
|
|
107
|
+
case "xrefs":
|
|
108
|
+
return [
|
|
109
|
+
...common,
|
|
110
|
+
"The direct address list projects exact Ghidra references to one address but does not expose their kinds; procedure_references and analyze_function preserve available kind metadata.",
|
|
111
|
+
"Synthetic Ghidra entry-point references without actionable memory sources are omitted.",
|
|
112
|
+
];
|
|
113
|
+
case "procedure_references":
|
|
114
|
+
return [
|
|
115
|
+
...common,
|
|
116
|
+
"Reference kinds are direct Ghidra ReferenceManager observations; unresolved computed flows without a target are absent and remain unknown.",
|
|
117
|
+
"Synthetic Ghidra entry-point references without actionable memory sources are omitted.",
|
|
118
|
+
"Instruction scans stop at max_instructions; a truncated scan reports an unknown total and no false continuation.",
|
|
119
|
+
];
|
|
120
|
+
case "analyze_function":
|
|
121
|
+
return [
|
|
122
|
+
...common,
|
|
123
|
+
"The dossier combines Ghidra FunctionManager, Listing, ReferenceManager, BasicBlockModel, and decompiler observations; provider-specific pseudocode and assembly are not cross-provider text invariants.",
|
|
124
|
+
"Resolved reference metadata identifies computed, indirect, external, call, jump, and data edges; unresolved targetless flows remain unknown, and function classifications distinguish thunks and externals.",
|
|
125
|
+
"Synthetic Ghidra entry-point references without actionable memory sources are omitted.",
|
|
126
|
+
"The Java bridge serializes one function request per Program through a bounded 32-request queue and applies a 30-second native decompilation deadline.",
|
|
127
|
+
];
|
|
128
|
+
default:
|
|
129
|
+
return common;
|
|
130
|
+
}
|
|
131
|
+
};
|
|
132
|
+
/** Provider-neutral capabilities advertised by every non-Windows Ghidra session. */
|
|
133
|
+
export const CAPABILITIES = Object.freeze(GHIDRA_PROVIDER_TOOL_CONTRACTS.map((contract) => Object.freeze({
|
|
134
|
+
provider: GHIDRA_PROVIDER_IDENTITY,
|
|
135
|
+
operation: contract.name,
|
|
136
|
+
inputContractVersion: 1,
|
|
137
|
+
outputContractVersion: 1,
|
|
138
|
+
available: true,
|
|
139
|
+
reason: null,
|
|
140
|
+
pagination: PAGINATED_OPERATIONS.has(contract.name)
|
|
141
|
+
? "offset"
|
|
142
|
+
: "none",
|
|
143
|
+
exhaustive: !PAGINATED_OPERATIONS.has(contract.name),
|
|
144
|
+
effects: Object.freeze({
|
|
145
|
+
mutatesArtifact: false,
|
|
146
|
+
launchesProcess: true,
|
|
147
|
+
mayShowUi: false,
|
|
148
|
+
mayAccessNetwork: false,
|
|
149
|
+
mayWriteFilesystem: true,
|
|
150
|
+
changesPermissions: false,
|
|
151
|
+
requiresRoot: false,
|
|
152
|
+
}),
|
|
153
|
+
limits: Object.freeze({
|
|
154
|
+
maxResults: PAGINATED_OPERATIONS.has(contract.name)
|
|
155
|
+
? SEARCH_OPERATIONS.has(contract.name)
|
|
156
|
+
? 100
|
|
157
|
+
: 500
|
|
158
|
+
: null,
|
|
159
|
+
maxPayloadBytes: GHIDRA_MAX_LINE_BYTES,
|
|
160
|
+
timeoutMs: DECOMPILE_OPERATIONS.has(contract.name)
|
|
161
|
+
? GHIDRA_DECOMPILE_REQUEST_TIMEOUT_MS
|
|
162
|
+
: GHIDRA_REQUEST_TIMEOUT_MS,
|
|
163
|
+
}),
|
|
164
|
+
limitations: Object.freeze(limitationsFor(contract.name)),
|
|
165
|
+
})));
|
|
166
|
+
/** Capabilities advertised for the experimental Windows x64 P0 boundary. */
|
|
167
|
+
export const WINDOWS_P0_CAPABILITIES = Object.freeze(CAPABILITIES.map((capability) => Object.freeze({
|
|
168
|
+
...capability,
|
|
169
|
+
limitations: Object.freeze([
|
|
170
|
+
...capability.limitations,
|
|
171
|
+
...windowsP0Limitations,
|
|
172
|
+
]),
|
|
173
|
+
})));
|
|
@@ -36,6 +36,7 @@ const sessionInfoSchema = z
|
|
|
36
36
|
compiler_spec_id: z.string().min(1),
|
|
37
37
|
image_base: z.string().regex(/^0x[0-9a-f]+$/u),
|
|
38
38
|
default_address_space: z.string().min(1),
|
|
39
|
+
sha256: z.string().regex(/^[a-f0-9]{64}$/u),
|
|
39
40
|
})
|
|
40
41
|
.strict(),
|
|
41
42
|
})
|
|
@@ -47,6 +48,7 @@ export const parseGhidraSessionInfo = (value, expected) => {
|
|
|
47
48
|
parsed.data.run_id !== expected.runId ||
|
|
48
49
|
parsed.data.provider.version !== expected.providerVersion ||
|
|
49
50
|
parsed.data.profile_digest !== expected.profileDigest ||
|
|
51
|
+
parsed.data.target.sha256 !== expected.targetSha256 ||
|
|
50
52
|
new Set(parsed.data.capabilities).size !==
|
|
51
53
|
GHIDRA_SESSION_CAPABILITIES.length ||
|
|
52
54
|
GHIDRA_SESSION_CAPABILITIES.some((capability) => !parsed.data.capabilities.includes(capability)) ||
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { createConnection } from "node:net";
|
|
2
2
|
import { err, ok } from "../domain/result.js";
|
|
3
|
-
import { GhidraSessionError } from "./GhidraSessionError.js";
|
|
3
|
+
import { GhidraSessionError, } from "./GhidraSessionError.js";
|
|
4
|
+
import { observeGhidraEndpoint, } from "./GhidraTransport.js";
|
|
4
5
|
/** Attach decoded bridge listeners and return an idempotent detach callback. */
|
|
5
|
-
|
|
6
|
+
const attachGhidraSocket = (socket, handlers) => {
|
|
6
7
|
socket.setEncoding("utf8");
|
|
7
8
|
socket.on("data", handlers.data);
|
|
8
9
|
socket.on("error", handlers.error);
|
|
@@ -13,9 +14,40 @@ export const attachGhidraSocket = (socket, handlers) => {
|
|
|
13
14
|
socket.off("close", handlers.close);
|
|
14
15
|
};
|
|
15
16
|
};
|
|
16
|
-
/**
|
|
17
|
-
export const
|
|
18
|
-
|
|
17
|
+
/** Poll the endpoint and attach the first ready bridge socket. */
|
|
18
|
+
export const connectGhidraSocket = async (options) => {
|
|
19
|
+
while (options.deadline.remainingMs() > 0) {
|
|
20
|
+
if (options.deadline.signal.aborted)
|
|
21
|
+
return err(interruptionFailure(options));
|
|
22
|
+
if (options.isClosed())
|
|
23
|
+
return err(options.failure("cancelled", "Ghidra startup was closed"));
|
|
24
|
+
if (options.processExited())
|
|
25
|
+
return err(options.failure("process", "Ghidra exited before bridge startup"));
|
|
26
|
+
const observed = await observeGhidraEndpoint(options.endpoint);
|
|
27
|
+
if (!observed.ok)
|
|
28
|
+
return observed;
|
|
29
|
+
if (observed.value === null) {
|
|
30
|
+
if ((await options.deadline.wait(50)) === "aborted")
|
|
31
|
+
return err(interruptionFailure(options));
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
34
|
+
const connected = await connectGhidraSocketOnce(observed.value, options.deadline.signal);
|
|
35
|
+
if (connected.ok) {
|
|
36
|
+
const detach = attachGhidraSocket(connected.value, options.handlers);
|
|
37
|
+
return ok({ socket: connected.value, detach });
|
|
38
|
+
}
|
|
39
|
+
if ((await options.deadline.wait(50)) === "aborted")
|
|
40
|
+
return err(interruptionFailure(options));
|
|
41
|
+
}
|
|
42
|
+
return err(options.failure("timeout", "Ghidra startup deadline elapsed", undefined, {
|
|
43
|
+
timeoutMs: options.startupTimeoutMs,
|
|
44
|
+
}));
|
|
45
|
+
};
|
|
46
|
+
/** Open one abort-aware connection to an observed local Ghidra endpoint. */
|
|
47
|
+
const connectGhidraSocketOnce = (target, signal) => new Promise((resolve) => {
|
|
48
|
+
const socket = "path" in target
|
|
49
|
+
? createConnection(target.path)
|
|
50
|
+
: createConnection({ host: target.host, port: target.port });
|
|
19
51
|
const detach = () => {
|
|
20
52
|
socket.off("connect", onConnect);
|
|
21
53
|
socket.off("error", onError);
|
|
@@ -29,14 +61,14 @@ export const connectGhidraSocketOnce = (socketPath, signal) => new Promise((reso
|
|
|
29
61
|
detach();
|
|
30
62
|
socket.destroy();
|
|
31
63
|
resolve(err(new GhidraSessionError("start", "Ghidra bridge connection failed", {
|
|
32
|
-
|
|
64
|
+
endpoint: target,
|
|
33
65
|
error: cause.message,
|
|
34
66
|
})));
|
|
35
67
|
};
|
|
36
68
|
const onAbort = () => {
|
|
37
69
|
detach();
|
|
38
70
|
socket.destroy();
|
|
39
|
-
resolve(err(new GhidraSessionError("cancelled", "Ghidra bridge connection was cancelled", {
|
|
71
|
+
resolve(err(new GhidraSessionError("cancelled", "Ghidra bridge connection was cancelled", { endpoint: target })));
|
|
40
72
|
};
|
|
41
73
|
socket.once("connect", onConnect);
|
|
42
74
|
socket.once("error", onError);
|
|
@@ -44,3 +76,8 @@ export const connectGhidraSocketOnce = (socketPath, signal) => new Promise((reso
|
|
|
44
76
|
if (signal.aborted)
|
|
45
77
|
onAbort();
|
|
46
78
|
});
|
|
79
|
+
const interruptionFailure = (options) => options.deadline.cancelled
|
|
80
|
+
? options.failure("cancelled", "Ghidra startup was cancelled")
|
|
81
|
+
: options.failure("timeout", "Ghidra startup deadline elapsed", undefined, {
|
|
82
|
+
timeoutMs: options.startupTimeoutMs,
|
|
83
|
+
});
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { constants, createReadStream } from "node:fs";
|
|
3
|
+
import { chmod, copyFile, rm } from "node:fs/promises";
|
|
4
|
+
import { extname, join } from "node:path";
|
|
5
|
+
/** Copy one target and require its bytes to match the parsed target identity. */
|
|
6
|
+
export const createGhidraTargetSnapshot = async (sourcePath, runtimeRoot, expectedSha256) => {
|
|
7
|
+
if (!/^[a-f0-9]{64}$/u.test(expectedSha256))
|
|
8
|
+
throw new TypeError("Ghidra target SHA-256 commitment is invalid");
|
|
9
|
+
const suffix = safeExtension(sourcePath);
|
|
10
|
+
const snapshotPath = join(runtimeRoot, `target-${expectedSha256.slice(0, 12)}${suffix}`);
|
|
11
|
+
try {
|
|
12
|
+
await copyFile(sourcePath, snapshotPath, constants.COPYFILE_EXCL);
|
|
13
|
+
await chmod(snapshotPath, 0o600);
|
|
14
|
+
const hash = createHash("sha256");
|
|
15
|
+
for await (const chunk of createReadStream(snapshotPath))
|
|
16
|
+
hash.update(chunk);
|
|
17
|
+
const observedSha256 = hash.digest("hex");
|
|
18
|
+
if (observedSha256 !== expectedSha256)
|
|
19
|
+
throw new Error(`Ghidra target snapshot digest mismatch: expected ${expectedSha256}, observed ${observedSha256}`);
|
|
20
|
+
return { path: snapshotPath, sha256: observedSha256 };
|
|
21
|
+
}
|
|
22
|
+
catch (cause) {
|
|
23
|
+
await rm(snapshotPath, { force: true }).catch(() => undefined);
|
|
24
|
+
throw cause;
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
const safeExtension = (path) => {
|
|
28
|
+
const extension = extname(path);
|
|
29
|
+
return /^\.[A-Za-z0-9]{1,12}$/u.test(extension) ? extension : ".bin";
|
|
30
|
+
};
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { access, open } from "node:fs/promises";
|
|
2
|
+
import { err, ok } from "../domain/result.js";
|
|
3
|
+
import { GhidraSessionError } from "./GhidraSessionError.js";
|
|
4
|
+
const MAX_ENDPOINT_BYTES = 1024;
|
|
5
|
+
/** Observe a ready endpoint, returning null while its bridge is not listening. */
|
|
6
|
+
export const observeGhidraEndpoint = async (endpoint) => {
|
|
7
|
+
if (endpoint.transport === "unix-socket") {
|
|
8
|
+
try {
|
|
9
|
+
await access(endpoint.path);
|
|
10
|
+
return ok({ path: endpoint.path });
|
|
11
|
+
}
|
|
12
|
+
catch (cause) {
|
|
13
|
+
return isMissing(cause)
|
|
14
|
+
? ok(null)
|
|
15
|
+
: err(endpointFailure(endpoint, "Ghidra socket observation failed", cause));
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
let handle;
|
|
19
|
+
try {
|
|
20
|
+
handle = await open(endpoint.path, "r");
|
|
21
|
+
}
|
|
22
|
+
catch (cause) {
|
|
23
|
+
return isMissing(cause)
|
|
24
|
+
? ok(null)
|
|
25
|
+
: err(endpointFailure(endpoint, "Ghidra endpoint observation failed", cause));
|
|
26
|
+
}
|
|
27
|
+
try {
|
|
28
|
+
const bytes = Buffer.alloc(MAX_ENDPOINT_BYTES + 1);
|
|
29
|
+
const observed = await handle.read(bytes, 0, bytes.length, 0);
|
|
30
|
+
if (observed.bytesRead === 0 || observed.bytesRead > MAX_ENDPOINT_BYTES)
|
|
31
|
+
return err(endpointFailure(endpoint, "Ghidra TCP endpoint is invalid"));
|
|
32
|
+
return parseTcpEndpoint(endpoint, bytes.subarray(0, observed.bytesRead).toString("utf8"));
|
|
33
|
+
}
|
|
34
|
+
catch (cause) {
|
|
35
|
+
return err(endpointFailure(endpoint, "Ghidra endpoint read failed", cause));
|
|
36
|
+
}
|
|
37
|
+
finally {
|
|
38
|
+
await handle.close();
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
const parseTcpEndpoint = (endpoint, encoded) => {
|
|
42
|
+
try {
|
|
43
|
+
const value = JSON.parse(encoded);
|
|
44
|
+
if (typeof value !== "object" ||
|
|
45
|
+
value === null ||
|
|
46
|
+
Array.isArray(value) ||
|
|
47
|
+
!hasExactKeys(value, ["host", "port", "schema_version"]) ||
|
|
48
|
+
value.schema_version !== 1 ||
|
|
49
|
+
value.host !== "127.0.0.1" ||
|
|
50
|
+
!Number.isSafeInteger(value.port) ||
|
|
51
|
+
typeof value.port !== "number" ||
|
|
52
|
+
value.port < 1 ||
|
|
53
|
+
value.port > 65_535)
|
|
54
|
+
return err(endpointFailure(endpoint, "Ghidra TCP endpoint is invalid"));
|
|
55
|
+
return ok({ host: "127.0.0.1", port: value.port });
|
|
56
|
+
}
|
|
57
|
+
catch (cause) {
|
|
58
|
+
return err(endpointFailure(endpoint, "Ghidra TCP endpoint is invalid", cause));
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
const hasExactKeys = (value, expected) => {
|
|
62
|
+
const keys = Object.keys(value).sort((left, right) => left.localeCompare(right));
|
|
63
|
+
return (keys.length === expected.length &&
|
|
64
|
+
keys.every((key, index) => key === expected[index]));
|
|
65
|
+
};
|
|
66
|
+
const endpointFailure = (endpoint, message, cause) => new GhidraSessionError("start", message, {
|
|
67
|
+
transport: endpoint.transport,
|
|
68
|
+
endpoint_path: endpoint.path,
|
|
69
|
+
...(cause instanceof Error ? { error: cause.message } : {}),
|
|
70
|
+
}, cause instanceof Error ? { cause } : undefined);
|
|
71
|
+
const isMissing = (cause) => cause instanceof Error && "code" in cause && cause.code === "ENOENT";
|
package/dist/identity.js
CHANGED
|
@@ -6,11 +6,12 @@
|
|
|
6
6
|
export const PRODUCT_IDENTITY = {
|
|
7
7
|
displayName: "REA",
|
|
8
8
|
packageName: PACKAGE_METADATA.name,
|
|
9
|
+
packageSpecifier: `${PACKAGE_METADATA.name}@latest`,
|
|
9
10
|
packageVersion: PACKAGE_METADATA.version,
|
|
10
11
|
cliBinary: "rea",
|
|
11
|
-
mcpCommand:
|
|
12
|
+
mcpCommand: `npx -y ${PACKAGE_METADATA.name}@latest mcp`,
|
|
12
13
|
mcpServerKey: "rea",
|
|
13
|
-
skillName: "
|
|
14
|
+
skillName: "reverse-engineer-anything",
|
|
14
15
|
skillVersion: PACKAGE_METADATA.skillVersion,
|
|
15
16
|
configFileName: "rea.json",
|
|
16
17
|
};
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export const MCP_CONNECTION_LOST = "REA lost its MCP client connection. Restart REA from your MCP client.";
|
|
2
|
+
export const MCP_CONNECTION_START_FAILED = "REA could not start its MCP connection. Restart REA from your MCP client; run `rea doctor` if it fails again.";
|
|
3
|
+
export const MCP_SHUTDOWN_FAILED = "REA could not close cleanly. End the REA process before starting it again.";
|
|
4
|
+
export const MCP_PERMISSION_RELOAD_FAILED = "Reloaded permission policy failed unexpectedly";
|
|
5
|
+
export const SERVER_START_FAILED = "REA could not start. Run `rea doctor`, then restart REA from your MCP client.";
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { parseConfig } from "../config.js";
|
|
2
|
+
import { readProjectPermissionStore } from "../application/ProjectPermissionStore.js";
|
|
3
|
+
import { MCP_PERMISSION_RELOAD_FAILED } from "./messages.js";
|
|
4
|
+
export const registerConfigReload = (input) => {
|
|
5
|
+
const { dependencies, permissionAuthority, runtimeState, liveServers, serverLogger, } = input;
|
|
6
|
+
let reloadQueue = Promise.resolve();
|
|
7
|
+
return (dependencies.registerReload?.(() => {
|
|
8
|
+
const refreshed = parseConfig(dependencies.env);
|
|
9
|
+
if (!refreshed.ok) {
|
|
10
|
+
serverLogger.error("Reloaded permission policy is invalid");
|
|
11
|
+
return;
|
|
12
|
+
}
|
|
13
|
+
reloadQueue = reloadQueue
|
|
14
|
+
.then(async () => {
|
|
15
|
+
let projectGrants = [];
|
|
16
|
+
if (refreshed.value.permissionProjectRoot !== undefined &&
|
|
17
|
+
refreshed.value.permissionProjectStore !== undefined) {
|
|
18
|
+
const project = await (dependencies.readProjectPermissionStore ??
|
|
19
|
+
readProjectPermissionStore)(refreshed.value.permissionProjectStore, refreshed.value.permissionProjectRoot);
|
|
20
|
+
if (!project.ok) {
|
|
21
|
+
serverLogger.error("Reloaded project grants could not be read");
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
projectGrants = project.value?.grants ?? [];
|
|
25
|
+
}
|
|
26
|
+
const reloaded = await permissionAuthority.replaceConfiguredPolicy({
|
|
27
|
+
ceilings: refreshed.value.permissionCeilings,
|
|
28
|
+
administratorGrants: refreshed.value.administratorPermissionGrants,
|
|
29
|
+
projectGrants,
|
|
30
|
+
});
|
|
31
|
+
if (!reloaded.ok) {
|
|
32
|
+
serverLogger.error("Reloaded permission policy could not be applied");
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
runtimeState.currentConfig = refreshed.value;
|
|
36
|
+
Object.assign(runtimeState.processPolicy, refreshed.value.processExecutionPolicy);
|
|
37
|
+
Object.assign(runtimeState.evidencePolicy, refreshed.value.evidenceFilePolicy);
|
|
38
|
+
Object.assign(runtimeState.snapshotPolicy, refreshed.value.analysisSnapshotFilePolicy);
|
|
39
|
+
runtimeState.investigationRoots.splice(0, runtimeState.investigationRoots.length, ...refreshed.value.investigationInputRoots);
|
|
40
|
+
Object.assign(runtimeState.javascriptReplayPolicy, refreshed.value.javascriptReplayPolicy);
|
|
41
|
+
Object.assign(runtimeState.managedRuntimePolicy, refreshed.value.managedRuntimePolicy);
|
|
42
|
+
for (const server of liveServers)
|
|
43
|
+
server.sendToolListChanged();
|
|
44
|
+
})
|
|
45
|
+
.catch(() => {
|
|
46
|
+
serverLogger.error(MCP_PERMISSION_RELOAD_FAILED);
|
|
47
|
+
});
|
|
48
|
+
}) ?? (() => undefined));
|
|
49
|
+
};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { MCP_SHUTDOWN_FAILED } from "./messages.js";
|
|
2
|
+
export const createShutdown = (input) => {
|
|
3
|
+
const { handle, session, permissionAuthority, unregisterReload, dependencies, serverLogger, } = input;
|
|
4
|
+
let shutdownPromise;
|
|
5
|
+
let unregisterShutdown = () => undefined;
|
|
6
|
+
const shutdown = async () => {
|
|
7
|
+
shutdownPromise ??= (async () => {
|
|
8
|
+
unregisterReload();
|
|
9
|
+
unregisterShutdown();
|
|
10
|
+
await handle.close();
|
|
11
|
+
await session.close();
|
|
12
|
+
permissionAuthority.clearSessionGrants();
|
|
13
|
+
})();
|
|
14
|
+
return shutdownPromise;
|
|
15
|
+
};
|
|
16
|
+
const requestShutdown = () => {
|
|
17
|
+
shutdown().catch(() => {
|
|
18
|
+
dependencies.setExitCode(1);
|
|
19
|
+
serverLogger.error(MCP_SHUTDOWN_FAILED);
|
|
20
|
+
dependencies.writeStderr(`${MCP_SHUTDOWN_FAILED}\n`);
|
|
21
|
+
});
|
|
22
|
+
};
|
|
23
|
+
unregisterShutdown = dependencies.registerShutdown(requestShutdown);
|
|
24
|
+
return { shutdown, request: requestShutdown };
|
|
25
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { projectAnalysisError } from "../domain/errors.js";
|
|
2
|
+
export const openInitialTarget = async (session, config, serverLogger, writeStderr) => {
|
|
3
|
+
if (config.hopperTargetPath === undefined)
|
|
4
|
+
return { ok: true };
|
|
5
|
+
const opened = await session.open(config.hopperTargetPath, {
|
|
6
|
+
targetKind: config.hopperTargetKind,
|
|
7
|
+
});
|
|
8
|
+
if (opened.ok)
|
|
9
|
+
return { ok: true };
|
|
10
|
+
await session.close();
|
|
11
|
+
serverLogger.error({ errorTag: opened.error._tag }, "Initial target failed to open");
|
|
12
|
+
writeStderr(`${projectAnalysisError(opened.error).message}\n`);
|
|
13
|
+
return { ok: false, exitCode: 1 };
|
|
14
|
+
};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export const createRuntimeState = (config) => ({
|
|
2
|
+
currentConfig: config,
|
|
3
|
+
processPolicy: {
|
|
4
|
+
...config.processExecutionPolicy,
|
|
5
|
+
executableRoots: [...config.processExecutionPolicy.executableRoots],
|
|
6
|
+
workingRoots: [...config.processExecutionPolicy.workingRoots],
|
|
7
|
+
allowedEnvironment: [...config.processExecutionPolicy.allowedEnvironment],
|
|
8
|
+
},
|
|
9
|
+
evidencePolicy: {
|
|
10
|
+
...config.evidenceFilePolicy,
|
|
11
|
+
roots: [...config.evidenceFilePolicy.roots],
|
|
12
|
+
},
|
|
13
|
+
snapshotPolicy: {
|
|
14
|
+
...config.analysisSnapshotFilePolicy,
|
|
15
|
+
roots: [...config.analysisSnapshotFilePolicy.roots],
|
|
16
|
+
},
|
|
17
|
+
investigationRoots: [...config.investigationInputRoots],
|
|
18
|
+
javascriptReplayPolicy: {
|
|
19
|
+
...config.javascriptReplayPolicy,
|
|
20
|
+
roots: [...config.javascriptReplayPolicy.roots],
|
|
21
|
+
},
|
|
22
|
+
managedRuntimePolicy: {
|
|
23
|
+
...config.managedRuntimePolicy,
|
|
24
|
+
roots: [...config.managedRuntimePolicy.roots],
|
|
25
|
+
},
|
|
26
|
+
});
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { createServer } from "../server/createServer.js";
|
|
2
|
+
import { MCP_CONNECTION_LOST, MCP_CONNECTION_START_FAILED, } from "./messages.js";
|
|
3
|
+
export const startMcpTransport = async (dependencies, session, serverContext) => {
|
|
4
|
+
const liveServers = new Set();
|
|
5
|
+
const { serverLogger } = serverContext;
|
|
6
|
+
let handle;
|
|
7
|
+
try {
|
|
8
|
+
handle = dependencies.serve(() => {
|
|
9
|
+
const server = (dependencies.createServer ?? createServer)(session, session, {
|
|
10
|
+
logger: serverContext.logger,
|
|
11
|
+
processPolicy: serverContext.runtimeState.processPolicy,
|
|
12
|
+
evidenceFilePolicy: serverContext.runtimeState.evidencePolicy,
|
|
13
|
+
investigationInputRoots: serverContext.runtimeState.investigationRoots,
|
|
14
|
+
analysisSnapshotFilePolicy: serverContext.runtimeState.snapshotPolicy,
|
|
15
|
+
permissionAuthority: serverContext.permissionAuthority,
|
|
16
|
+
browserObservation: serverContext.browserObservation,
|
|
17
|
+
electronObservation: serverContext.electronObservation,
|
|
18
|
+
artifactIntegrityContinueEnabled: () => serverContext.runtimeState.currentConfig
|
|
19
|
+
.artifactIntegrityContinueEnabled,
|
|
20
|
+
javascriptReplayPolicy: serverContext.runtimeState.javascriptReplayPolicy,
|
|
21
|
+
managedRuntimePolicy: serverContext.runtimeState.managedRuntimePolicy,
|
|
22
|
+
availabilityPolicy: () => ({
|
|
23
|
+
processCaptureEnabled: serverContext.runtimeState.currentConfig.processExecutionPolicy
|
|
24
|
+
.enabled,
|
|
25
|
+
evidenceFileRoots: serverContext.runtimeState.currentConfig.evidenceFilePolicy
|
|
26
|
+
.roots.length,
|
|
27
|
+
browserObservationEnabled: serverContext.runtimeState.currentConfig
|
|
28
|
+
.browserObservationEnabled &&
|
|
29
|
+
serverContext.runtimeState.currentConfig.browserCdpEndpoints
|
|
30
|
+
.length > 0 &&
|
|
31
|
+
serverContext.runtimeState.currentConfig.browserAllowedOrigins
|
|
32
|
+
.length > 0,
|
|
33
|
+
electronObservationEnabled: serverContext.runtimeState.currentConfig
|
|
34
|
+
.electronObservationEnabled &&
|
|
35
|
+
serverContext.runtimeState.currentConfig.electronCdpEndpoints
|
|
36
|
+
.length > 0 &&
|
|
37
|
+
serverContext.runtimeState.currentConfig.electronFileRoots
|
|
38
|
+
.length > 0,
|
|
39
|
+
javascriptReplayEnabled: serverContext.runtimeState.currentConfig.javascriptReplayPolicy
|
|
40
|
+
.enabled,
|
|
41
|
+
managedRuntimeEnabled: serverContext.runtimeState.currentConfig.managedRuntimePolicy
|
|
42
|
+
.enabled,
|
|
43
|
+
}),
|
|
44
|
+
});
|
|
45
|
+
liveServers.add(server);
|
|
46
|
+
return server;
|
|
47
|
+
}, {
|
|
48
|
+
onerror: () => {
|
|
49
|
+
serverLogger.error(MCP_CONNECTION_LOST);
|
|
50
|
+
dependencies.writeStderr(`${MCP_CONNECTION_LOST}\n`);
|
|
51
|
+
},
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
await session.close();
|
|
56
|
+
serverLogger.error(MCP_CONNECTION_START_FAILED);
|
|
57
|
+
dependencies.writeStderr(`${MCP_CONNECTION_START_FAILED}\n`);
|
|
58
|
+
return { ok: false };
|
|
59
|
+
}
|
|
60
|
+
return { ok: true, handle, liveServers };
|
|
61
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|