rea-agents 2.0.0 → 2.2.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 +103 -38
- package/bridge/ghidra/ReaGhidraBridge.java +96 -11
- package/dist/application/AndroidApplicationService.js +17 -0
- package/dist/application/AppleApplicationService.js +17 -0
- 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 +24 -2
- package/dist/application/ClientRegistrationStatus.js +11 -4
- package/dist/application/CrossVersionInventory.js +8 -2
- package/dist/application/CrossVersionInvestigation.js +1 -23
- package/dist/application/CrossVersionInvestigationCollections.js +23 -0
- package/dist/application/DirectAnalysis.js +47 -44
- package/dist/application/Doctor.js +156 -238
- package/dist/application/DoctorDiagnostics.js +180 -0
- package/dist/application/ElectronBoundaryAnalysis.js +23 -7
- package/dist/application/ElectronBoundaryGraphWindows.js +32 -8
- package/dist/application/EnhancedToolPagination.js +22 -0
- package/dist/application/EnhancedToolTypes.js +4 -0
- package/dist/application/EnhancedTools.js +20 -37
- package/dist/application/InstrumentedJavaScriptReplayHost.js +36 -0
- package/dist/application/InventoryProjectionEvidence.js +41 -0
- package/dist/application/InvestigationProviders.js +12 -0
- package/dist/application/InvestigationWorkspaceStore.js +24 -10
- package/dist/application/JavaScriptArtifactAnalysis.js +45 -6
- package/dist/application/JavaScriptArtifactFiles.js +6 -2
- package/dist/application/JavaScriptArtifactGraphBuilder.js +23 -1
- package/dist/application/JavaScriptArtifactGraphBundlers.js +225 -0
- package/dist/application/JavaScriptArtifactGraphContext.js +37 -36
- package/dist/application/JavaScriptArtifactGraphDocuments.js +27 -4
- 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 +1 -1
- package/dist/application/JavaScriptJsonModules.js +39 -0
- package/dist/application/JavaScriptModuleRelationships.js +262 -0
- package/dist/application/JavaScriptReplayPermission.js +16 -0
- package/dist/application/JavaScriptReplayService.js +182 -156
- package/dist/application/LinuxHopper.js +10 -0
- package/dist/application/MacHopper.js +22 -11
- 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/ProcessPairedExperiment.js +72 -0
- package/dist/application/ProjectPermissionStore.js +48 -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 +148 -260
- package/dist/application/SetupClientConfiguration.js +224 -0
- package/dist/application/SetupClients.js +24 -2
- package/dist/application/SetupPlan.js +124 -12
- package/dist/application/SetupSkill.js +54 -36
- package/dist/application/SupportedClients.js +1 -0
- package/dist/application/Uninstall.js +12 -3
- package/dist/application/Upgrade.js +16 -1
- package/dist/application/WindowsCapabilities.js +86 -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 +29 -496
- package/dist/browser/CdpObservationSession.js +51 -8
- package/dist/browser/CdpPageCapture.js +12 -133
- 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 +4 -0
- 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 +113 -0
- package/dist/cli/types.js +1 -0
- package/dist/cli/utilityCommands.js +122 -0
- package/dist/cli.js +10 -768
- package/dist/cliApplicationCommands.js +118 -4
- package/dist/cliBrowserAdvancedCommands.js +73 -16
- package/dist/cliBrowserCommands.js +39 -115
- package/dist/cliCommandNames.js +4 -0
- package/dist/cliElectronCommands.js +33 -62
- package/dist/cliEvidenceCommands.js +13 -2
- package/dist/cliInvestigationCommands.js +53 -10
- package/dist/cliObservationOptions.js +137 -0
- package/dist/cliPolicyCommands.js +80 -46
- package/dist/cliSetup.js +306 -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 -375
- package/dist/contracts/applicationToolContracts.js +134 -0
- package/dist/contracts/electronToolContracts.js +51 -3
- package/dist/contracts/managedToolContracts.js +8 -3
- package/dist/contracts/managedWorkflowToolContracts.js +3 -3
- package/dist/contracts/providerSelection.js +2 -0
- package/dist/contracts/sessionStatusContract.js +26 -0
- package/dist/contracts/toolContractTypes.js +12 -1
- package/dist/contracts/toolContracts.js +5 -12
- package/dist/contracts/toolEffects.js +14 -0
- package/dist/contracts/toolOutputSchemaGroups.js +274 -0
- package/dist/contracts/toolOutputSchemaPrimitives.js +328 -0
- package/dist/contracts/toolOutputSchemas.js +2 -550
- package/dist/domain/analysisErrorPresentation.js +234 -0
- package/dist/domain/analysisErrorProjection.js +284 -0
- package/dist/domain/androidApplication.js +206 -0
- package/dist/domain/appleApplication.js +221 -0
- package/dist/domain/artifactComparison.js +34 -15
- package/dist/domain/binaryTarget.js +87 -37
- package/dist/domain/boundedCartesianProjection.js +15 -0
- package/dist/domain/browserObservation.js +1 -285
- package/dist/domain/browserObservationSchemas.js +286 -0
- package/dist/domain/electronStaticAnalysisBrowser.js +14 -2
- package/dist/domain/errors.js +4 -486
- package/dist/domain/functionComparison.js +4 -165
- package/dist/domain/functionComparisonDimensions.js +164 -0
- package/dist/domain/javascriptApplicationVersionItems.js +18 -6
- package/dist/domain/javascriptApplicationVersionKeys.js +8 -8
- package/dist/domain/javascriptExportInstrumentation.js +97 -0
- package/dist/domain/javascriptFeatureTraversal.js +19 -7
- package/dist/domain/javascriptRuntimeStaticCandidates.js +3 -1
- 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 +5 -221
- package/dist/domain/javascriptStaticAnalysisBundler.js +209 -0
- package/dist/domain/javascriptStaticAnalysisCalls.js +180 -0
- package/dist/domain/javascriptStaticAnalysisHelpers.js +71 -2
- package/dist/domain/knownPageCoverage.js +21 -0
- package/dist/domain/managedApplicationGraph.js +14 -364
- 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 +16 -8
- package/dist/domain/managedMemberComparison.js +37 -391
- package/dist/domain/managedMemberComparisonCoverage.js +72 -0
- package/dist/domain/managedMemberComparisonMatch.js +356 -0
- package/dist/domain/managedNativeVerification.js +27 -389
- package/dist/domain/managedNativeVerificationMatch.js +272 -0
- package/dist/domain/managedNativeVerificationSchemas.js +141 -0
- package/dist/domain/managedReconstruction.js +82 -69
- package/dist/domain/managedRuntimeCorrelation.js +12 -3
- package/dist/domain/nodeRuntimeCharacterization.js +66 -0
- package/dist/domain/permissionPolicy.js +2 -0
- package/dist/domain/processComparison.js +19 -0
- package/dist/domain/processPairedExperiment.js +128 -0
- package/dist/domain/reconstructionCoverage.js +387 -0
- package/dist/domain/reconstructionCoverageEvaluation.js +212 -0
- package/dist/domain/reconstructionVerificationSchemas.js +8 -0
- package/dist/domain/replayMachine.js +316 -0
- package/dist/domain/replayMachineRuntime.js +215 -0
- package/dist/domain/runtimeCharacterization.js +85 -0
- package/dist/domain/runtimeIdentification.js +210 -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 +50 -29
- package/dist/dotnet/ManagedMemberInspector.js +51 -785
- package/dist/dotnet/ManagedMemberInspectorCore.js +297 -0
- package/dist/dotnet/ManagedMemberInstructionDecoder.js +427 -0
- package/dist/dotnet/ManagedMemberRows.js +120 -0
- package/dist/dotnet/ManagedMetadataInventory.js +42 -306
- package/dist/dotnet/ManagedMetadataInventoryRows.js +292 -0
- package/dist/dotnet/ManagedMetadataLayout.js +48 -111
- 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 +102 -350
- package/dist/dotnet/ManagedPeReader.js +59 -28
- package/dist/evaluation/CodexAgentEval.js +132 -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 +61 -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 +4 -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 -146
- 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 +64 -50
- package/dist/replay/LinuxJavaScriptReplayRunner.js +173 -390
- package/dist/replay/LinuxJavaScriptReplaySandbox.js +140 -0
- package/dist/replay/ReplayOutcome.js +95 -0
- package/dist/replay/ReplayProcessLifecycle.js +71 -0
- package/dist/server/ProcessCaptureElicitation.js +157 -0
- package/dist/server/createServer.js +124 -56
- package/dist/server/javascriptApplicationResult.js +85 -0
- 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 +10 -112
- package/dist/server/registerBrowserTools.js +59 -83
- package/dist/server/registerElectronTools.js +48 -49
- package/dist/server/registerEnhancedTools.js +34 -42
- package/dist/server/registerEvidenceResources.js +56 -0
- package/dist/server/registerInvestigationTools/helpers.js +74 -0
- package/dist/server/registerInvestigationTools/types.js +1 -0
- package/dist/server/registerInvestigationTools.js +83 -116
- package/dist/server/registerJavaScriptApplicationGraphResource.js +69 -0
- package/dist/server/registerManagedTools.js +18 -1
- 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 +10 -274
- package/dist/server/registerOfficialTools.js +73 -59
- package/dist/server/registerSessionRecordTools.js +137 -0
- package/dist/server/registerSessionStatusTool.js +97 -26
- package/dist/server/registerSessionTools.js +60 -164
- package/dist/server/sessionAvailabilityPolicy.js +10 -0
- package/dist/server/toolRegistrationOptions.js +101 -3
- package/dist/server/toolResult.js +15 -4
- package/package.json +11 -11
- package/skills/reverse-engineer-anything/SKILL.md +76 -0
- package/skills/reverse-engineer-anything/references/controlled-replay.md +12 -0
- package/skills/reverse-engineer-anything/references/evidence-workflows.md +33 -0
- package/skills/reverse-engineer-anything/references/javascript-applications.md +25 -0
- package/skills/reverse-engineer-anything/references/native-and-artifacts.md +36 -0
- package/skills/reverse-engineer-anything/references/runtime-observation.md +24 -0
- package/scripts/prepare-node-pty.mjs +0 -35
- package/scripts/rebuild-native.mjs +0 -22
- package/skills/rea-analysis/SKILL.md +0 -222
|
@@ -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,13 @@
|
|
|
6
6
|
export const PRODUCT_IDENTITY = {
|
|
7
7
|
displayName: "REA",
|
|
8
8
|
packageName: PACKAGE_METADATA.name,
|
|
9
|
+
packageSpecifier: `${PACKAGE_METADATA.name}@latest`,
|
|
10
|
+
registrationPackageSpecifier: `${PACKAGE_METADATA.name}@${PACKAGE_METADATA.version}`,
|
|
9
11
|
packageVersion: PACKAGE_METADATA.version,
|
|
10
12
|
cliBinary: "rea",
|
|
11
|
-
mcpCommand:
|
|
13
|
+
mcpCommand: `npx -y ${PACKAGE_METADATA.name}@${PACKAGE_METADATA.version} mcp`,
|
|
12
14
|
mcpServerKey: "rea",
|
|
13
|
-
skillName: "
|
|
15
|
+
skillName: "reverse-engineer-anything",
|
|
14
16
|
skillVersion: PACKAGE_METADATA.skillVersion,
|
|
15
17
|
configFileName: "rea.json",
|
|
16
18
|
};
|
|
@@ -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 {};
|
package/dist/main.js
CHANGED
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { pathToFileURL } from "node:url";
|
|
3
3
|
import { realpathSync } from "node:fs";
|
|
4
|
-
import { serveStdio
|
|
4
|
+
import { serveStdio } from "@modelcontextprotocol/server/stdio";
|
|
5
5
|
import { parseConfig } from "./config.js";
|
|
6
6
|
import { createBinarySession } from "./application/runtime.js";
|
|
7
|
-
import { createServer } from "./server/createServer.js";
|
|
8
7
|
import { createLogger } from "./logger.js";
|
|
9
8
|
import { projectAnalysisError } from "./domain/errors.js";
|
|
10
|
-
import { readProjectPermissionStore } from "./application/ProjectPermissionStore.js";
|
|
11
9
|
import { loadConfiguredPermissionAuthority } from "./application/PermissionConfiguration.js";
|
|
12
10
|
import { CdpBrowserProvider } from "./browser/CdpBrowserProvider.js";
|
|
13
11
|
import { CdpElectronProvider } from "./browser/CdpElectronProvider.js";
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
12
|
+
import { SERVER_START_FAILED } from "./main/messages.js";
|
|
13
|
+
import { createRuntimeState } from "./main/state.js";
|
|
14
|
+
import { openInitialTarget } from "./main/startup.js";
|
|
15
|
+
import { startMcpTransport } from "./main/transport.js";
|
|
16
|
+
import { registerConfigReload } from "./main/reload.js";
|
|
17
|
+
import { createShutdown } from "./main/shutdown.js";
|
|
18
18
|
const runtimeDependencies = () => ({
|
|
19
19
|
env: process.env,
|
|
20
20
|
serve: serveStdio,
|
|
@@ -60,146 +60,35 @@ export const run = async (dependencies = runtimeDependencies()) => {
|
|
|
60
60
|
const session = createBinarySession(config.value, logger);
|
|
61
61
|
const browserObservation = new CdpBrowserProvider();
|
|
62
62
|
const electronObservation = new CdpElectronProvider();
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
...config.value.processExecutionPolicy,
|
|
77
|
-
executableRoots: [...config.value.processExecutionPolicy.executableRoots],
|
|
78
|
-
workingRoots: [...config.value.processExecutionPolicy.workingRoots],
|
|
79
|
-
allowedEnvironment: [
|
|
80
|
-
...config.value.processExecutionPolicy.allowedEnvironment,
|
|
81
|
-
],
|
|
82
|
-
};
|
|
83
|
-
const runtimeEvidencePolicy = {
|
|
84
|
-
...config.value.evidenceFilePolicy,
|
|
85
|
-
roots: [...config.value.evidenceFilePolicy.roots],
|
|
86
|
-
};
|
|
87
|
-
const runtimeSnapshotPolicy = {
|
|
88
|
-
...config.value.analysisSnapshotFilePolicy,
|
|
89
|
-
roots: [...config.value.analysisSnapshotFilePolicy.roots],
|
|
90
|
-
};
|
|
91
|
-
const runtimeInvestigationRoots = [...config.value.investigationInputRoots];
|
|
92
|
-
const runtimeJavascriptReplayPolicy = {
|
|
93
|
-
...config.value.javascriptReplayPolicy,
|
|
94
|
-
roots: [...config.value.javascriptReplayPolicy.roots],
|
|
95
|
-
};
|
|
96
|
-
const runtimeManagedRuntimePolicy = {
|
|
97
|
-
...config.value.managedRuntimePolicy,
|
|
98
|
-
roots: [...config.value.managedRuntimePolicy.roots],
|
|
99
|
-
};
|
|
100
|
-
const liveServers = new Set();
|
|
101
|
-
let handle;
|
|
102
|
-
try {
|
|
103
|
-
handle = dependencies.serve(() => {
|
|
104
|
-
const server = (dependencies.createServer ?? createServer)(session, session, {
|
|
105
|
-
logger,
|
|
106
|
-
processPolicy: runtimeProcessPolicy,
|
|
107
|
-
evidenceFilePolicy: runtimeEvidencePolicy,
|
|
108
|
-
investigationInputRoots: runtimeInvestigationRoots,
|
|
109
|
-
analysisSnapshotFilePolicy: runtimeSnapshotPolicy,
|
|
110
|
-
permissionAuthority: permissionAuthority.value,
|
|
111
|
-
browserObservation,
|
|
112
|
-
electronObservation,
|
|
113
|
-
artifactIntegrityContinueEnabled: () => currentConfig.artifactIntegrityContinueEnabled,
|
|
114
|
-
javascriptReplayPolicy: runtimeJavascriptReplayPolicy,
|
|
115
|
-
managedRuntimePolicy: runtimeManagedRuntimePolicy,
|
|
116
|
-
availabilityPolicy: () => ({
|
|
117
|
-
processCaptureEnabled: currentConfig.processExecutionPolicy.enabled,
|
|
118
|
-
evidenceFileRoots: currentConfig.evidenceFilePolicy.roots.length,
|
|
119
|
-
browserObservationEnabled: currentConfig.browserObservationEnabled &&
|
|
120
|
-
currentConfig.browserCdpEndpoints.length > 0 &&
|
|
121
|
-
currentConfig.browserAllowedOrigins.length > 0,
|
|
122
|
-
electronObservationEnabled: currentConfig.electronObservationEnabled &&
|
|
123
|
-
currentConfig.electronCdpEndpoints.length > 0 &&
|
|
124
|
-
currentConfig.electronFileRoots.length > 0,
|
|
125
|
-
javascriptReplayEnabled: currentConfig.javascriptReplayPolicy.enabled,
|
|
126
|
-
managedRuntimeEnabled: currentConfig.managedRuntimePolicy.enabled,
|
|
127
|
-
}),
|
|
128
|
-
});
|
|
129
|
-
liveServers.add(server);
|
|
130
|
-
return server;
|
|
131
|
-
}, {
|
|
132
|
-
onerror: () => {
|
|
133
|
-
serverLogger.error(MCP_CONNECTION_LOST);
|
|
134
|
-
dependencies.writeStderr(`${MCP_CONNECTION_LOST}\n`);
|
|
135
|
-
},
|
|
136
|
-
});
|
|
137
|
-
}
|
|
138
|
-
catch {
|
|
139
|
-
await session.close();
|
|
140
|
-
serverLogger.error(MCP_CONNECTION_START_FAILED);
|
|
141
|
-
dependencies.writeStderr(`${MCP_CONNECTION_START_FAILED}\n`);
|
|
63
|
+
const opened = await openInitialTarget(session, config.value, serverLogger, dependencies.writeStderr);
|
|
64
|
+
if (!opened.ok)
|
|
65
|
+
return opened.exitCode;
|
|
66
|
+
const runtimeState = createRuntimeState(config.value);
|
|
67
|
+
const transport = await startMcpTransport(dependencies, session, {
|
|
68
|
+
logger,
|
|
69
|
+
serverLogger,
|
|
70
|
+
browserObservation,
|
|
71
|
+
electronObservation,
|
|
72
|
+
permissionAuthority: permissionAuthority.value,
|
|
73
|
+
runtimeState,
|
|
74
|
+
});
|
|
75
|
+
if (!transport.ok)
|
|
142
76
|
return 1;
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
serverLogger.error("Reloaded project grants could not be read");
|
|
159
|
-
return;
|
|
160
|
-
}
|
|
161
|
-
projectGrants = project.value?.grants ?? [];
|
|
162
|
-
}
|
|
163
|
-
const reloaded = await permissionAuthority.value.replaceConfiguredPolicy({
|
|
164
|
-
ceilings: refreshed.value.permissionCeilings,
|
|
165
|
-
administratorGrants: refreshed.value.administratorPermissionGrants,
|
|
166
|
-
projectGrants,
|
|
167
|
-
});
|
|
168
|
-
if (!reloaded.ok) {
|
|
169
|
-
serverLogger.error("Reloaded permission policy could not be applied");
|
|
170
|
-
return;
|
|
171
|
-
}
|
|
172
|
-
currentConfig = refreshed.value;
|
|
173
|
-
Object.assign(runtimeProcessPolicy, refreshed.value.processExecutionPolicy);
|
|
174
|
-
Object.assign(runtimeEvidencePolicy, refreshed.value.evidenceFilePolicy);
|
|
175
|
-
Object.assign(runtimeSnapshotPolicy, refreshed.value.analysisSnapshotFilePolicy);
|
|
176
|
-
runtimeInvestigationRoots.splice(0, runtimeInvestigationRoots.length, ...refreshed.value.investigationInputRoots);
|
|
177
|
-
Object.assign(runtimeJavascriptReplayPolicy, refreshed.value.javascriptReplayPolicy);
|
|
178
|
-
Object.assign(runtimeManagedRuntimePolicy, refreshed.value.managedRuntimePolicy);
|
|
179
|
-
for (const server of liveServers)
|
|
180
|
-
server.sendToolListChanged();
|
|
181
|
-
});
|
|
182
|
-
}) ?? (() => undefined);
|
|
183
|
-
let shutdownPromise;
|
|
184
|
-
let unregisterShutdown = () => undefined;
|
|
185
|
-
const shutdown = () => {
|
|
186
|
-
shutdownPromise ??= (async () => {
|
|
187
|
-
unregisterReload();
|
|
188
|
-
unregisterShutdown();
|
|
189
|
-
await handle.close();
|
|
190
|
-
await session.close();
|
|
191
|
-
permissionAuthority.value.clearSessionGrants();
|
|
192
|
-
})();
|
|
193
|
-
return shutdownPromise;
|
|
194
|
-
};
|
|
195
|
-
const requestShutdown = () => {
|
|
196
|
-
shutdown().catch(() => {
|
|
197
|
-
dependencies.setExitCode(1);
|
|
198
|
-
serverLogger.error(MCP_SHUTDOWN_FAILED);
|
|
199
|
-
dependencies.writeStderr(`${MCP_SHUTDOWN_FAILED}\n`);
|
|
200
|
-
});
|
|
201
|
-
};
|
|
202
|
-
unregisterShutdown = dependencies.registerShutdown(requestShutdown);
|
|
77
|
+
const unregisterReload = registerConfigReload({
|
|
78
|
+
dependencies,
|
|
79
|
+
permissionAuthority: permissionAuthority.value,
|
|
80
|
+
runtimeState,
|
|
81
|
+
liveServers: transport.liveServers,
|
|
82
|
+
serverLogger,
|
|
83
|
+
});
|
|
84
|
+
createShutdown({
|
|
85
|
+
handle: transport.handle,
|
|
86
|
+
session,
|
|
87
|
+
permissionAuthority: permissionAuthority.value,
|
|
88
|
+
unregisterReload,
|
|
89
|
+
dependencies,
|
|
90
|
+
serverLogger,
|
|
91
|
+
});
|
|
203
92
|
return 0;
|
|
204
93
|
};
|
|
205
94
|
/** Run the executable boundary without exposing an unexpected startup cause. */
|
|
@@ -2,10 +2,11 @@ import { chmod, mkdtemp, rm } from "node:fs/promises";
|
|
|
2
2
|
import { tmpdir } from "node:os";
|
|
3
3
|
import { join } from "node:path";
|
|
4
4
|
/**
|
|
5
|
-
* Owns one mode-0700 temporary runtime root and removes it idempotently.
|
|
5
|
+
* Owns one POSIX mode-0700 temporary runtime root and removes it idempotently.
|
|
6
6
|
*
|
|
7
7
|
* Protocol adapters decide what belongs inside the directory; this primitive
|
|
8
|
-
*
|
|
8
|
+
* establishes a private filesystem boundary on POSIX and deterministic cleanup.
|
|
9
|
+
* Windows privacy requires the separately verified native DACL boundary.
|
|
9
10
|
*/
|
|
10
11
|
export class PrivateRuntimeRoot {
|
|
11
12
|
path;
|