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,292 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import writeFileAtomic from "write-file-atomic";
|
|
3
|
+
import { controlledReplayInputSchema, replayExecutionResultSchema, controlledReplayOutputSchema, replayEvidenceSchema, } from "../domain/javascriptReplay.js";
|
|
4
|
+
import { AnalysisCapabilityUnavailableError, AnalysisCancelledError, AnalysisInputError, AnalysisProtocolError, PermissionRequiredError, ReplayPlanStaleError, } from "../domain/errors.js";
|
|
5
|
+
import { createEvidence } from "../domain/evidence.js";
|
|
6
|
+
import { projectInputIssues } from "../domain/inputIssueProjection.js";
|
|
7
|
+
import { jsonValueSchema } from "../domain/jsonValue.js";
|
|
8
|
+
import { err, ok } from "../domain/result.js";
|
|
9
|
+
import { replayPermissionRequest } from "./JavaScriptReplayPermission.js";
|
|
10
|
+
import { digestBytes, prepareReplayPlan, } from "./JavaScriptReplayPlanning.js";
|
|
11
|
+
const OPERATION = "run_controlled_replay";
|
|
12
|
+
const isAborted = (signal) => signal?.aborted === true;
|
|
13
|
+
/** Plan or execute one content-bound extracted-module replay experiment. */
|
|
14
|
+
export const runControlledReplay = async (dependencies, rawInput, options = {}) => {
|
|
15
|
+
const parsed = controlledReplayInputSchema.safeParse(rawInput);
|
|
16
|
+
if (!parsed.success)
|
|
17
|
+
return err(new AnalysisInputError(OPERATION, { cause: parsed.error }, projectInputIssues(parsed.error.issues, rawInput)));
|
|
18
|
+
return runControlledReplayValidated(dependencies, parsed.data, options);
|
|
19
|
+
};
|
|
20
|
+
/** Plan or execute replay input already parsed by a trusted adapter. */
|
|
21
|
+
export const runControlledReplayValidated = async (dependencies, input, options = {}) => {
|
|
22
|
+
const authorized = await authorizeReplay(dependencies, input, options.signal);
|
|
23
|
+
if (!authorized.ok)
|
|
24
|
+
return authorized;
|
|
25
|
+
const prepared = await prepareValidatedReplay(dependencies, input, options.signal);
|
|
26
|
+
if (!prepared.ok)
|
|
27
|
+
return prepared;
|
|
28
|
+
if (isAborted(options.signal))
|
|
29
|
+
return err(new AnalysisCancelledError(OPERATION));
|
|
30
|
+
if (input.mode === "plan")
|
|
31
|
+
return ok(asJson({
|
|
32
|
+
phase: "plan",
|
|
33
|
+
plan: prepared.value.publicPlan,
|
|
34
|
+
source_evidence: [],
|
|
35
|
+
evidence: null,
|
|
36
|
+
}));
|
|
37
|
+
if (input.plan_digest !== prepared.value.publicPlan.plan_digest)
|
|
38
|
+
return err(new ReplayPlanStaleError(input.plan_digest ?? "", prepared.value.publicPlan.plan_digest));
|
|
39
|
+
const exportContext = await authorizeReproducerExport(dependencies.authority, input, prepared.value);
|
|
40
|
+
if (!exportContext.ok)
|
|
41
|
+
return exportContext;
|
|
42
|
+
const executed = await executeValidatedReplay(dependencies, prepared.value, exportContext.value, options);
|
|
43
|
+
if (!executed.ok)
|
|
44
|
+
return executed;
|
|
45
|
+
try {
|
|
46
|
+
return ok(buildReplayOutput(prepared.value, executed.value.executed, executed.value.sourceEvidence));
|
|
47
|
+
}
|
|
48
|
+
catch (cause) {
|
|
49
|
+
return err(new AnalysisProtocolError(cause instanceof z.ZodError
|
|
50
|
+
? "Controlled replay produced an invalid bounded result"
|
|
51
|
+
: "Controlled replay could not establish or clean up its sandbox", { cause }));
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
const authorizeReplay = async (dependencies, input, signal) => {
|
|
55
|
+
if (!dependencies.policy.enabled)
|
|
56
|
+
return err(new AnalysisCapabilityUnavailableError("rea-javascript-replay", OPERATION, "controlled replay is disabled; configure exact roots and executables before enabling it"));
|
|
57
|
+
if (dependencies.authority === undefined)
|
|
58
|
+
return err(new AnalysisCapabilityUnavailableError("rea-javascript-replay", OPERATION, "JavaScript replay permission policy is not configured"));
|
|
59
|
+
if (isAborted(signal))
|
|
60
|
+
return err(new AnalysisCancelledError(OPERATION));
|
|
61
|
+
const request = replayPermissionRequest(input, dependencies.policy);
|
|
62
|
+
const authorized = input.mode === "plan"
|
|
63
|
+
? await dependencies.authority.explain(request, "read")
|
|
64
|
+
: await dependencies.authority.authorize(request, "read");
|
|
65
|
+
if (!authorized.ok)
|
|
66
|
+
return err(authorized.error instanceof PermissionRequiredError
|
|
67
|
+
? authorized.error
|
|
68
|
+
: new AnalysisProtocolError(authorized.error.message, {
|
|
69
|
+
cause: authorized.error,
|
|
70
|
+
}));
|
|
71
|
+
return ok(true);
|
|
72
|
+
};
|
|
73
|
+
const prepareValidatedReplay = async (dependencies, input, signal) => {
|
|
74
|
+
if (isAborted(signal))
|
|
75
|
+
return err(new AnalysisCancelledError(OPERATION));
|
|
76
|
+
try {
|
|
77
|
+
return ok(await prepareReplayPlan(input, dependencies.policy, dependencies.host));
|
|
78
|
+
}
|
|
79
|
+
catch (cause) {
|
|
80
|
+
return err(new AnalysisCapabilityUnavailableError("rea-javascript-replay", OPERATION, cause instanceof Error ? cause.message : "replay planning failed"));
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
const authorizeReproducerExport = async (authority, input, prepared) => {
|
|
84
|
+
if (input.reproducer_export === undefined)
|
|
85
|
+
return ok(undefined);
|
|
86
|
+
if (input.reproducer_export.approved !== true)
|
|
87
|
+
return err(new AnalysisInputError(`${OPERATION}:reproducer_export`));
|
|
88
|
+
if (authority === undefined)
|
|
89
|
+
return err(new AnalysisCapabilityUnavailableError("rea-javascript-replay", OPERATION, "JavaScript replay permission policy is not configured"));
|
|
90
|
+
const exportAuthorized = await authority.authorize({
|
|
91
|
+
capability: "evidence_write",
|
|
92
|
+
roots: [input.reproducer_export.path],
|
|
93
|
+
executables: [],
|
|
94
|
+
environment_names: [],
|
|
95
|
+
network: "none",
|
|
96
|
+
mount: false,
|
|
97
|
+
operation_identity: `${OPERATION}:reproducer:${prepared.publicPlan.plan_digest}`,
|
|
98
|
+
}, "write");
|
|
99
|
+
if (!exportAuthorized.ok)
|
|
100
|
+
return err(exportAuthorized.error instanceof PermissionRequiredError
|
|
101
|
+
? exportAuthorized.error
|
|
102
|
+
: new AnalysisProtocolError(exportAuthorized.error.message, {
|
|
103
|
+
cause: exportAuthorized.error,
|
|
104
|
+
}));
|
|
105
|
+
const canonicalExportPath = exportAuthorized.value.request.roots[0];
|
|
106
|
+
if (canonicalExportPath !== input.reproducer_export.path)
|
|
107
|
+
return err(new AnalysisInputError(`${OPERATION}:reproducer_export:path`, {
|
|
108
|
+
cause: new TypeError(`Use the canonical reproducer path: ${canonicalExportPath ?? "unavailable"}`),
|
|
109
|
+
}));
|
|
110
|
+
return ok({
|
|
111
|
+
path: canonicalExportPath,
|
|
112
|
+
includeSources: input.reproducer_export.include_sources === true,
|
|
113
|
+
});
|
|
114
|
+
};
|
|
115
|
+
const executeValidatedReplay = async (dependencies, prepared, exportContext, options) => {
|
|
116
|
+
await options.progress?.report({
|
|
117
|
+
phase: OPERATION,
|
|
118
|
+
completed: 0,
|
|
119
|
+
total: 1,
|
|
120
|
+
message: "Admitting approved modules into the isolated replay worker",
|
|
121
|
+
});
|
|
122
|
+
if (isAborted(options.signal))
|
|
123
|
+
return err(new AnalysisCancelledError(OPERATION));
|
|
124
|
+
try {
|
|
125
|
+
let executed = replayExecutionResultSchema.parse(await dependencies.runner.execute(prepared, dependencies.policy, options.signal));
|
|
126
|
+
await options.progress?.report({
|
|
127
|
+
phase: OPERATION,
|
|
128
|
+
completed: 1,
|
|
129
|
+
total: 1,
|
|
130
|
+
message: "Controlled replay stopped and sandbox cleanup was observed",
|
|
131
|
+
terminal: true,
|
|
132
|
+
});
|
|
133
|
+
if (executed.termination === "cancelled")
|
|
134
|
+
return err(new AnalysisCancelledError(OPERATION));
|
|
135
|
+
executed = await applyReproducerExport(executed, exportContext, prepared);
|
|
136
|
+
const sourceEvidence = buildSourceEvidence(prepared, executed);
|
|
137
|
+
return ok({ executed, sourceEvidence });
|
|
138
|
+
}
|
|
139
|
+
catch (cause) {
|
|
140
|
+
return err(new AnalysisProtocolError(cause instanceof z.ZodError
|
|
141
|
+
? "Controlled replay produced an invalid bounded result"
|
|
142
|
+
: "Controlled replay could not establish or clean up its sandbox", { cause }));
|
|
143
|
+
}
|
|
144
|
+
};
|
|
145
|
+
const applyReproducerExport = async (executed, exportContext, prepared) => {
|
|
146
|
+
if (exportContext === undefined || executed.cleanup.state !== "complete")
|
|
147
|
+
return executed;
|
|
148
|
+
const manifest = {
|
|
149
|
+
schema_version: 1,
|
|
150
|
+
plan: prepared.publicPlan,
|
|
151
|
+
result: executed,
|
|
152
|
+
sources: exportContext.includeSources
|
|
153
|
+
? {
|
|
154
|
+
left: prepared.leftSources,
|
|
155
|
+
...(prepared.rightSources === undefined
|
|
156
|
+
? {}
|
|
157
|
+
: { right: prepared.rightSources }),
|
|
158
|
+
}
|
|
159
|
+
: null,
|
|
160
|
+
};
|
|
161
|
+
const encoded = Buffer.from(`${JSON.stringify(manifest, null, 2)}\n`);
|
|
162
|
+
try {
|
|
163
|
+
await writeFileAtomic(exportContext.path, encoded, {
|
|
164
|
+
mode: 0o600,
|
|
165
|
+
});
|
|
166
|
+
return replayExecutionResultSchema.parse({
|
|
167
|
+
...executed,
|
|
168
|
+
reproducer: {
|
|
169
|
+
state: "written",
|
|
170
|
+
path: exportContext.path,
|
|
171
|
+
sha256: digestBytes(encoded),
|
|
172
|
+
},
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
catch (cause) {
|
|
176
|
+
return replayExecutionResultSchema.parse({
|
|
177
|
+
...executed,
|
|
178
|
+
limitations: [
|
|
179
|
+
...executed.limitations,
|
|
180
|
+
"Replay completed, but the separately approved reproducer export failed.",
|
|
181
|
+
],
|
|
182
|
+
reproducer: {
|
|
183
|
+
state: "failed",
|
|
184
|
+
path: exportContext.path,
|
|
185
|
+
error: cause instanceof Error
|
|
186
|
+
? cause.message
|
|
187
|
+
: "unknown reproducer export failure",
|
|
188
|
+
},
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
};
|
|
192
|
+
const buildSourceEvidence = (prepared, executed) => {
|
|
193
|
+
const leftCount = prepared.publicPlan.cases.length;
|
|
194
|
+
return [
|
|
195
|
+
createReplayEvidence(prepared, executed, "left", executed.outcomes.slice(0, leftCount)),
|
|
196
|
+
...(prepared.publicPlan.right === undefined
|
|
197
|
+
? []
|
|
198
|
+
: [
|
|
199
|
+
createReplayEvidence(prepared, executed, "right", executed.outcomes.slice(leftCount)),
|
|
200
|
+
]),
|
|
201
|
+
];
|
|
202
|
+
};
|
|
203
|
+
const buildReplayOutput = (prepared, executed, sourceEvidence) => {
|
|
204
|
+
const subject = prepared.publicPlan.left.modules[0];
|
|
205
|
+
const evidence = createEvidence(subject === undefined
|
|
206
|
+
? undefined
|
|
207
|
+
: {
|
|
208
|
+
path: subject.canonical_path,
|
|
209
|
+
sha256: subject.sha256,
|
|
210
|
+
format: "javascript",
|
|
211
|
+
}, {
|
|
212
|
+
id: "rea-javascript-replay",
|
|
213
|
+
name: "REA isolated JavaScript replay",
|
|
214
|
+
version: "1",
|
|
215
|
+
}, {
|
|
216
|
+
predicateType: "javascript-controlled-replay",
|
|
217
|
+
operation: OPERATION,
|
|
218
|
+
parameters: {
|
|
219
|
+
replay_plan: jsonValueSchema.parse(JSON.parse(JSON.stringify(prepared.publicPlan))),
|
|
220
|
+
},
|
|
221
|
+
result: jsonValueSchema.parse(JSON.parse(JSON.stringify(executed))),
|
|
222
|
+
rawResult: jsonValueSchema.parse(JSON.parse(JSON.stringify({
|
|
223
|
+
cases: prepared.publicPlan.cases,
|
|
224
|
+
outcomes: executed.outcomes,
|
|
225
|
+
stderr: executed.stderr,
|
|
226
|
+
}))),
|
|
227
|
+
confidence: executed.comparison === undefined ? "observed" : "derived",
|
|
228
|
+
authority: "controlled-replay",
|
|
229
|
+
environment: {
|
|
230
|
+
id: prepared.publicPlan.plan_digest,
|
|
231
|
+
platform: process.platform,
|
|
232
|
+
architecture: process.arch,
|
|
233
|
+
isolation: "container",
|
|
234
|
+
},
|
|
235
|
+
limitations: executed.limitations,
|
|
236
|
+
locations: prepared.publicPlan.left.modules.map((module) => ({
|
|
237
|
+
kind: "artifact-path",
|
|
238
|
+
path: module.canonical_path,
|
|
239
|
+
})),
|
|
240
|
+
evidenceLinks: sourceEvidence.map(({ evidence_id: id }) => id),
|
|
241
|
+
});
|
|
242
|
+
return asJson({
|
|
243
|
+
phase: "execute",
|
|
244
|
+
plan: null,
|
|
245
|
+
source_evidence: sourceEvidence.map((item) => replayEvidenceSchema.parse(item)),
|
|
246
|
+
evidence: replayEvidenceSchema.parse(evidence),
|
|
247
|
+
});
|
|
248
|
+
};
|
|
249
|
+
const createReplayEvidence = (prepared, executed, side, outcomes) => {
|
|
250
|
+
const manifest = side === "left" ? prepared.publicPlan.left : prepared.publicPlan.right;
|
|
251
|
+
const subject = manifest?.modules[0];
|
|
252
|
+
const result = replayExecutionResultSchema.parse({
|
|
253
|
+
...executed,
|
|
254
|
+
outcomes,
|
|
255
|
+
comparison: undefined,
|
|
256
|
+
reproducer: null,
|
|
257
|
+
});
|
|
258
|
+
return createEvidence(subject === undefined
|
|
259
|
+
? undefined
|
|
260
|
+
: {
|
|
261
|
+
path: subject.canonical_path,
|
|
262
|
+
sha256: subject.sha256,
|
|
263
|
+
format: "javascript",
|
|
264
|
+
}, {
|
|
265
|
+
id: "rea-javascript-replay",
|
|
266
|
+
name: "REA isolated JavaScript replay",
|
|
267
|
+
version: "1",
|
|
268
|
+
}, {
|
|
269
|
+
predicateType: "javascript-controlled-replay-observation",
|
|
270
|
+
operation: OPERATION,
|
|
271
|
+
parameters: {
|
|
272
|
+
replay_plan: jsonValueSchema.parse(JSON.parse(JSON.stringify(prepared.publicPlan))),
|
|
273
|
+
side,
|
|
274
|
+
},
|
|
275
|
+
result: jsonValueSchema.parse(JSON.parse(JSON.stringify(result))),
|
|
276
|
+
rawResult: jsonValueSchema.parse(JSON.parse(JSON.stringify({ cases: prepared.publicPlan.cases, outcomes }))),
|
|
277
|
+
confidence: "observed",
|
|
278
|
+
authority: "controlled-replay",
|
|
279
|
+
environment: {
|
|
280
|
+
id: prepared.publicPlan.plan_digest,
|
|
281
|
+
platform: process.platform,
|
|
282
|
+
architecture: process.arch,
|
|
283
|
+
isolation: "container",
|
|
284
|
+
},
|
|
285
|
+
limitations: executed.limitations,
|
|
286
|
+
locations: (manifest?.modules ?? []).map((module) => ({
|
|
287
|
+
kind: "artifact-path",
|
|
288
|
+
path: module.canonical_path,
|
|
289
|
+
})),
|
|
290
|
+
});
|
|
291
|
+
};
|
|
292
|
+
const asJson = (value) => jsonValueSchema.parse(JSON.parse(JSON.stringify(controlledReplayOutputSchema.parse(value))));
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { createEvidence, } from "../domain/evidence.js";
|
|
2
|
+
import { jsonValueSchema } from "../domain/jsonValue.js";
|
|
3
|
+
import { JAVASCRIPT_RUNTIME_RECONCILIATION_PROVIDER } from "./InvestigationProviders.js";
|
|
4
|
+
/** Create derived Evidence v2 for one exact set of static/runtime inputs. */
|
|
5
|
+
export const createJavaScriptRuntimeReconciliationEvidence = (input, result) => createEvidence(undefined, JAVASCRIPT_RUNTIME_RECONCILIATION_PROVIDER, {
|
|
6
|
+
predicateType: "rea.javascript-runtime-reconciliation/v1",
|
|
7
|
+
operation: "reconcile_javascript_runtime",
|
|
8
|
+
parameters: parameters(input),
|
|
9
|
+
result: jsonValueSchema.parse(result),
|
|
10
|
+
rawResult: null,
|
|
11
|
+
confidence: "inferred",
|
|
12
|
+
authority: "analyst-inference",
|
|
13
|
+
environment: null,
|
|
14
|
+
limitations: result.limitations,
|
|
15
|
+
evidenceLinks: result.evidence_links,
|
|
16
|
+
});
|
|
17
|
+
const parameters = (input) => ({
|
|
18
|
+
static_layers: input.static_layers.map((layer) => ({
|
|
19
|
+
role: layer.role,
|
|
20
|
+
evidence_id: layer.analysis.evidence_id,
|
|
21
|
+
runtime_mappings: layer.runtime_mappings,
|
|
22
|
+
})),
|
|
23
|
+
runtime_evidence_ids: input.runtime_observations.map(({ evidence_id: id }) => id),
|
|
24
|
+
limits: input.limits,
|
|
25
|
+
});
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { AnalysisInputError, AnalysisProtocolError, } from "../domain/errors.js";
|
|
3
|
+
import { projectInputIssues } from "../domain/inputIssueProjection.js";
|
|
4
|
+
import { reconcileJavaScriptRuntime } from "../domain/javascriptRuntimeReconciliation.js";
|
|
5
|
+
import { reconcileJavaScriptRuntimeInputSchema } from "../domain/javascriptRuntimeReconciliationSchemas.js";
|
|
6
|
+
import { err, ok } from "../domain/result.js";
|
|
7
|
+
import { createJavaScriptRuntimeReconciliationEvidence } from "./JavaScriptRuntimeReconciliationEvidence.js";
|
|
8
|
+
const OPERATION = "reconcile_javascript_runtime";
|
|
9
|
+
/** Derive a combined JAG from verified static and passive-runtime Evidence. */
|
|
10
|
+
export const reconcileJavaScriptRuntimeEvidence = (rawInput) => {
|
|
11
|
+
const parsed = reconcileJavaScriptRuntimeInputSchema.safeParse(rawInput);
|
|
12
|
+
if (!parsed.success)
|
|
13
|
+
return err(new AnalysisInputError(OPERATION, undefined, projectInputIssues(parsed.error.issues, rawInput)));
|
|
14
|
+
return reconcileJavaScriptRuntimeEvidenceValidated(parsed.data);
|
|
15
|
+
};
|
|
16
|
+
/** Reconcile input already parsed by a trusted adapter boundary. */
|
|
17
|
+
export const reconcileJavaScriptRuntimeEvidenceValidated = (input) => {
|
|
18
|
+
try {
|
|
19
|
+
const result = reconcileJavaScriptRuntime(input);
|
|
20
|
+
return ok(createJavaScriptRuntimeReconciliationEvidence(input, result));
|
|
21
|
+
}
|
|
22
|
+
catch (cause) {
|
|
23
|
+
return err(cause instanceof z.ZodError || cause instanceof TypeError
|
|
24
|
+
? new AnalysisInputError(OPERATION)
|
|
25
|
+
: new AnalysisProtocolError("JavaScript runtime reconciliation produced an invalid result", { cause }));
|
|
26
|
+
}
|
|
27
|
+
};
|
|
@@ -26,6 +26,16 @@ const SUPPORTED_RELEASES = {
|
|
|
26
26
|
file_hash: "92d780b61cab38eda95dc4112dee4fbeb0920f46",
|
|
27
27
|
},
|
|
28
28
|
};
|
|
29
|
+
/** Describe the release and package-manager commands without downloading or writing. */
|
|
30
|
+
export const linuxHopperInstallDisclosure = (family, isRoot) => {
|
|
31
|
+
const release = SUPPORTED_RELEASES[family];
|
|
32
|
+
return {
|
|
33
|
+
downloadUrl: release.filename,
|
|
34
|
+
expectedBytes: Number(release.file_length),
|
|
35
|
+
expectedSha1: release.file_hash,
|
|
36
|
+
commands: linuxPackageManagerCommands(family, `<verified-hopper.${family}>`, isRoot).map(({ executable, args }) => `${executable} ${args.join(" ")}`),
|
|
37
|
+
};
|
|
38
|
+
};
|
|
29
39
|
/** Parse an os-release document without executing its shell syntax. */
|
|
30
40
|
export const parseLinuxDistribution = (text) => {
|
|
31
41
|
const fields = new Map();
|
|
@@ -10,6 +10,16 @@ const RELEASES_URL = "https://www.hopperapp.com/include/files-api.php?request=re
|
|
|
10
10
|
const DOWNLOAD_PREFIX = "https://www.hopperapp.com:443/downloader/public/";
|
|
11
11
|
const MAX_PACKAGE_BYTES = 100_000_000;
|
|
12
12
|
const BUNDLE_IDENTIFIER = "com.cryptic-apps.hopper-web-4";
|
|
13
|
+
/** Stable network and command effects disclosed before macOS Hopper setup. */
|
|
14
|
+
export const macHopperInstallDisclosure = {
|
|
15
|
+
networkOrigins: [RELEASES_URL, DOWNLOAD_PREFIX],
|
|
16
|
+
commands: [
|
|
17
|
+
"hdiutil attach -readonly -nobrowse -mountpoint <private-mount> <verified-hopper.dmg>",
|
|
18
|
+
"codesign --verify --deep --strict <mounted-hopper.app>",
|
|
19
|
+
"ditto <mounted-hopper.app> <user-Applications-stage>",
|
|
20
|
+
"open <installed-hopper.app>",
|
|
21
|
+
],
|
|
22
|
+
};
|
|
13
23
|
/** Download, verify, and install Hopper into the current user's Applications directory. */
|
|
14
24
|
export const installMacHopper = async (options = {}, host = systemMacHopperInstallHost()) => {
|
|
15
25
|
let temporary;
|
|
@@ -66,17 +76,7 @@ export const installMacHopper = async (options = {}, host = systemMacHopperInsta
|
|
|
66
76
|
}
|
|
67
77
|
};
|
|
68
78
|
const systemMacHopperInstallHost = () => ({
|
|
69
|
-
|
|
70
|
-
const response = await fetch(url, {
|
|
71
|
-
headers: { accept: "application/json", "user-agent": "rea-installer" },
|
|
72
|
-
signal: AbortSignal.timeout(120_000),
|
|
73
|
-
});
|
|
74
|
-
const length = Number(response.headers.get("content-length") ?? "0");
|
|
75
|
-
if (length > MAX_PACKAGE_BYTES)
|
|
76
|
-
return { ok: false, bytes: new Uint8Array() };
|
|
77
|
-
const bytes = new Uint8Array(await response.arrayBuffer());
|
|
78
|
-
return { ok: response.ok && bytes.byteLength <= MAX_PACKAGE_BYTES, bytes };
|
|
79
|
-
},
|
|
79
|
+
download: downloadPackage,
|
|
80
80
|
createTemporaryDirectory: () => mkdtemp(join(tmpdir(), "rea-hopper-mac-")),
|
|
81
81
|
createMountDirectory: (path) => mkdir(path),
|
|
82
82
|
writePackage: (path, bytes) => writeFile(path, bytes, { mode: 0o600 }),
|
|
@@ -170,6 +170,17 @@ const systemMacHopperInstallHost = () => ({
|
|
|
170
170
|
cleanup: (path) => rm(path, { recursive: true, force: true }),
|
|
171
171
|
destination: () => join(homedir(), "Applications/Hopper Disassembler.app"),
|
|
172
172
|
});
|
|
173
|
+
const downloadPackage = async (url) => {
|
|
174
|
+
const response = await fetch(url, {
|
|
175
|
+
headers: { accept: "application/json", "user-agent": "rea-installer" },
|
|
176
|
+
signal: AbortSignal.timeout(120_000),
|
|
177
|
+
});
|
|
178
|
+
const length = Number(response.headers.get("content-length") ?? "0");
|
|
179
|
+
if (length > MAX_PACKAGE_BYTES)
|
|
180
|
+
return { ok: false, bytes: new Uint8Array() };
|
|
181
|
+
const bytes = new Uint8Array(await response.arrayBuffer());
|
|
182
|
+
return { ok: response.ok && bytes.byteLength <= MAX_PACKAGE_BYTES, bytes };
|
|
183
|
+
};
|
|
173
184
|
const parseJson = (bytes) => JSON.parse(new TextDecoder().decode(bytes));
|
|
174
185
|
const integrityMatches = (bytes, release) => bytes.byteLength === Number(release.file_length) &&
|
|
175
186
|
bytes.byteLength <= MAX_PACKAGE_BYTES &&
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { AnalysisInputError, AnalysisProtocolError, } from "../domain/errors.js";
|
|
3
|
+
import { createEvidence } from "../domain/evidence.js";
|
|
4
|
+
import { jsonValueSchema } from "../domain/jsonValue.js";
|
|
5
|
+
import { managedApplicationGraphResultSchema, projectManagedApplicationGraph, projectManagedApplicationGraphInputSchema, } from "../domain/managedApplicationGraph.js";
|
|
6
|
+
import { err, ok } from "../domain/result.js";
|
|
7
|
+
import { MANAGED_WORKFLOW_PROVIDER } from "./InvestigationProviders.js";
|
|
8
|
+
const OPERATION = "project_managed_application_graph";
|
|
9
|
+
/** Project authenticated managed Evidence into a provider-neutral graph. */
|
|
10
|
+
export const projectManagedApplicationGraphEvidence = (rawInput) => {
|
|
11
|
+
const parsed = projectManagedApplicationGraphInputSchema.safeParse(rawInput);
|
|
12
|
+
if (!parsed.success)
|
|
13
|
+
return err(new AnalysisInputError(OPERATION, { cause: parsed.error }));
|
|
14
|
+
try {
|
|
15
|
+
const result = projectManagedApplicationGraph(parsed.data);
|
|
16
|
+
return ok(createManagedApplicationGraphEvidence(parsed.data, result));
|
|
17
|
+
}
|
|
18
|
+
catch (cause) {
|
|
19
|
+
return err(cause instanceof TypeError || cause instanceof z.ZodError
|
|
20
|
+
? new AnalysisInputError(OPERATION, { cause })
|
|
21
|
+
: new AnalysisProtocolError("Managed application graph projection produced an invalid result", { cause }));
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
const createManagedApplicationGraphEvidence = (input, result) => createEvidence(subjectTarget(input), MANAGED_WORKFLOW_PROVIDER, {
|
|
25
|
+
predicateType: "rea.managed-application-graph/v1",
|
|
26
|
+
operation: OPERATION,
|
|
27
|
+
parameters: {
|
|
28
|
+
managed_artifact_evidence_id: input.managed_artifact?.evidence_id ?? null,
|
|
29
|
+
managed_members_evidence_id: input.managed_members?.evidence_id ?? null,
|
|
30
|
+
managed_native_boundaries_evidence_id: input.managed_native_boundaries?.evidence_id ?? null,
|
|
31
|
+
limits: jsonValueSchema.parse(input.limits),
|
|
32
|
+
},
|
|
33
|
+
result: jsonValueSchema.parse(managedApplicationGraphResultSchema.parse(result)),
|
|
34
|
+
rawResult: null,
|
|
35
|
+
confidence: "inferred",
|
|
36
|
+
authority: "analyst-inference",
|
|
37
|
+
environment: null,
|
|
38
|
+
limitations: result.limitations,
|
|
39
|
+
evidenceLinks: result.evidence_links,
|
|
40
|
+
});
|
|
41
|
+
const subjectTarget = (input) => {
|
|
42
|
+
const subject = input.managed_artifact?.subject ??
|
|
43
|
+
input.managed_members?.subject ??
|
|
44
|
+
input.managed_native_boundaries?.subject;
|
|
45
|
+
if (subject === undefined || subject === null || subject.format !== "pe")
|
|
46
|
+
return undefined;
|
|
47
|
+
return {
|
|
48
|
+
path: subject.local_path,
|
|
49
|
+
sha256: subject.digest.sha256,
|
|
50
|
+
format: "pe",
|
|
51
|
+
...(subject.architecture === null
|
|
52
|
+
? {}
|
|
53
|
+
: { architecture: subject.architecture }),
|
|
54
|
+
};
|
|
55
|
+
};
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { readFile, stat } from "node:fs/promises";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
import { compareManagedMembers, managedMemberComparisonResultSchema, parseManagedMemberEvidence, } from "../domain/managedMemberComparison.js";
|
|
4
|
+
import { AnalysisInputError, AnalysisProtocolError, } from "../domain/errors.js";
|
|
5
|
+
import { createEvidence } from "../domain/evidence.js";
|
|
6
|
+
import { jsonValueSchema } from "../domain/jsonValue.js";
|
|
7
|
+
import { parseBinaryTarget } from "../domain/binaryTarget.js";
|
|
8
|
+
import { err, ok } from "../domain/result.js";
|
|
9
|
+
import { inspectManagedMembersBytes } from "../dotnet/ManagedMemberInspector.js";
|
|
10
|
+
import { MANAGED_STATIC_PROVIDER } from "./InvestigationProviders.js";
|
|
11
|
+
import { MANAGED_WORKFLOW_PROVIDER } from "./InvestigationProviders.js";
|
|
12
|
+
/** Compare managed members from input parsed by a trusted adapter. */
|
|
13
|
+
export const compareManagedMembersEvidenceValidated = (input) => {
|
|
14
|
+
const operation = "compare_managed_members";
|
|
15
|
+
try {
|
|
16
|
+
const left = parseManagedMemberEvidence(input.left);
|
|
17
|
+
const right = parseManagedMemberEvidence(input.right);
|
|
18
|
+
const result = compareManagedMembers({ evidenceId: left.evidenceId, result: left.result }, { evidenceId: right.evidenceId, result: right.result }, input.limits);
|
|
19
|
+
return ok(createManagedMemberComparisonEvidence(input, result));
|
|
20
|
+
}
|
|
21
|
+
catch (cause) {
|
|
22
|
+
return workflowFailure(operation, cause);
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
/** Inspect two local PE artifacts and return one derived comparison Evidence. */
|
|
26
|
+
export const compareManagedMemberPaths = async (input) => {
|
|
27
|
+
const operation = "compare_managed_members";
|
|
28
|
+
try {
|
|
29
|
+
const [leftTarget, rightTarget] = await Promise.all([
|
|
30
|
+
parseBinaryTarget(input.leftPath),
|
|
31
|
+
parseBinaryTarget(input.rightPath),
|
|
32
|
+
]);
|
|
33
|
+
if (!leftTarget.ok)
|
|
34
|
+
return err(new AnalysisInputError(operation, { cause: leftTarget.error }));
|
|
35
|
+
if (!rightTarget.ok)
|
|
36
|
+
return err(new AnalysisInputError(operation, { cause: rightTarget.error }));
|
|
37
|
+
const [leftStat, rightStat] = await Promise.all([
|
|
38
|
+
stat(leftTarget.value.path),
|
|
39
|
+
stat(rightTarget.value.path),
|
|
40
|
+
]);
|
|
41
|
+
if (leftStat.size > input.memberLimits.maxFileBytes ||
|
|
42
|
+
rightStat.size > input.memberLimits.maxFileBytes)
|
|
43
|
+
return err(new AnalysisInputError(operation, {
|
|
44
|
+
cause: new RangeError(`Managed comparison input exceeds max_file_bytes ${String(input.memberLimits.maxFileBytes)}`),
|
|
45
|
+
}));
|
|
46
|
+
const [leftBytes, rightBytes] = await Promise.all([
|
|
47
|
+
readFile(leftTarget.value.path),
|
|
48
|
+
readFile(rightTarget.value.path),
|
|
49
|
+
]);
|
|
50
|
+
const leftInspection = inspectManagedMembersBytes(leftBytes, leftTarget.value, input.memberLimits);
|
|
51
|
+
const rightInspection = inspectManagedMembersBytes(rightBytes, rightTarget.value, input.memberLimits);
|
|
52
|
+
const leftEvidence = createEvidence(leftTarget.value, MANAGED_STATIC_PROVIDER, {
|
|
53
|
+
operation: "inspect_managed_members",
|
|
54
|
+
parameters: memberLimitParameters(input.memberLimits),
|
|
55
|
+
result: jsonValueSchema.parse(leftInspection),
|
|
56
|
+
rawResult: null,
|
|
57
|
+
limitations: leftInspection.limitations,
|
|
58
|
+
locations: [{ kind: "artifact-path", path: leftTarget.value.path }],
|
|
59
|
+
});
|
|
60
|
+
const rightEvidence = createEvidence(rightTarget.value, MANAGED_STATIC_PROVIDER, {
|
|
61
|
+
operation: "inspect_managed_members",
|
|
62
|
+
parameters: memberLimitParameters(input.memberLimits),
|
|
63
|
+
result: jsonValueSchema.parse(rightInspection),
|
|
64
|
+
rawResult: null,
|
|
65
|
+
limitations: rightInspection.limitations,
|
|
66
|
+
locations: [{ kind: "artifact-path", path: rightTarget.value.path }],
|
|
67
|
+
});
|
|
68
|
+
const result = compareManagedMembers({
|
|
69
|
+
evidenceId: leftEvidence.evidence_id,
|
|
70
|
+
result: leftInspection,
|
|
71
|
+
}, {
|
|
72
|
+
evidenceId: rightEvidence.evidence_id,
|
|
73
|
+
result: rightInspection,
|
|
74
|
+
}, input.comparisonLimits);
|
|
75
|
+
return ok(createManagedMemberComparisonEvidence({
|
|
76
|
+
left: leftEvidence,
|
|
77
|
+
right: rightEvidence,
|
|
78
|
+
limits: input.comparisonLimits,
|
|
79
|
+
}, result));
|
|
80
|
+
}
|
|
81
|
+
catch (cause) {
|
|
82
|
+
return workflowFailure(operation, cause);
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
const createManagedMemberComparisonEvidence = (parameters, result) => createEvidence(undefined, MANAGED_WORKFLOW_PROVIDER, {
|
|
86
|
+
predicateType: "rea.managed-member-comparison/v1",
|
|
87
|
+
operation: "compare_managed_members",
|
|
88
|
+
parameters: {
|
|
89
|
+
left_evidence_id: parameters.left.evidence_id,
|
|
90
|
+
right_evidence_id: parameters.right.evidence_id,
|
|
91
|
+
limits: jsonValueSchema.parse(parameters.limits),
|
|
92
|
+
},
|
|
93
|
+
result: jsonValueSchema.parse(result),
|
|
94
|
+
rawResult: null,
|
|
95
|
+
confidence: "inferred",
|
|
96
|
+
authority: "analyst-inference",
|
|
97
|
+
environment: null,
|
|
98
|
+
limitations: result.limitations,
|
|
99
|
+
evidenceLinks: result.evidence_links,
|
|
100
|
+
});
|
|
101
|
+
const memberLimitParameters = (limits) => ({
|
|
102
|
+
type_offset: limits.typeOffset,
|
|
103
|
+
type_limit: limits.typeLimit,
|
|
104
|
+
method_offset: limits.methodOffset,
|
|
105
|
+
method_limit: limits.methodLimit,
|
|
106
|
+
field_offset: limits.fieldOffset,
|
|
107
|
+
field_limit: limits.fieldLimit,
|
|
108
|
+
member_ref_offset: limits.memberRefOffset,
|
|
109
|
+
member_ref_limit: limits.memberRefLimit,
|
|
110
|
+
edge_offset: limits.edgeOffset,
|
|
111
|
+
edge_limit: limits.edgeLimit,
|
|
112
|
+
instruction_anchor_limit: limits.instructionAnchorLimit,
|
|
113
|
+
max_file_bytes: limits.maxFileBytes,
|
|
114
|
+
max_metadata_bytes: limits.maxMetadataBytes,
|
|
115
|
+
max_table_rows: limits.maxTableRows,
|
|
116
|
+
max_heap_item_bytes: limits.maxHeapItemBytes,
|
|
117
|
+
max_method_body_bytes: limits.maxMethodBodyBytes,
|
|
118
|
+
max_method_instructions: limits.maxMethodInstructions,
|
|
119
|
+
});
|
|
120
|
+
const workflowFailure = (operation, cause) => err(cause instanceof z.ZodError || cause instanceof TypeError
|
|
121
|
+
? new AnalysisInputError(operation, { cause })
|
|
122
|
+
: new AnalysisProtocolError("Managed member comparison produced an invalid result", { cause }));
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { AnalysisInputError, AnalysisProtocolError, } from "../domain/errors.js";
|
|
3
|
+
import { createEvidence } from "../domain/evidence.js";
|
|
4
|
+
import { jsonValueSchema } from "../domain/jsonValue.js";
|
|
5
|
+
import { managedNativeVerificationInputSchema, verifyManagedNativeBoundaries, } from "../domain/managedNativeVerification.js";
|
|
6
|
+
import { err, ok } from "../domain/result.js";
|
|
7
|
+
import { MANAGED_WORKFLOW_PROVIDER } from "./InvestigationProviders.js";
|
|
8
|
+
const OPERATION = "verify_managed_native_boundaries";
|
|
9
|
+
/** Verify managed/native boundary declarations against native Evidence. */
|
|
10
|
+
export const verifyManagedNativeBoundariesEvidence = (rawInput) => {
|
|
11
|
+
const parsed = managedNativeVerificationInputSchema.safeParse(rawInput);
|
|
12
|
+
if (!parsed.success)
|
|
13
|
+
return err(new AnalysisInputError(OPERATION, { cause: parsed.error }));
|
|
14
|
+
try {
|
|
15
|
+
const result = verifyManagedNativeBoundaries(parsed.data);
|
|
16
|
+
return ok(createManagedNativeVerificationEvidence(parsed.data, result));
|
|
17
|
+
}
|
|
18
|
+
catch (cause) {
|
|
19
|
+
return err(cause instanceof TypeError || cause instanceof z.ZodError
|
|
20
|
+
? new AnalysisInputError(OPERATION, { cause })
|
|
21
|
+
: new AnalysisProtocolError("Managed/native verification produced an invalid result", { cause }));
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
const createManagedNativeVerificationEvidence = (input, result) => createEvidence(undefined, MANAGED_WORKFLOW_PROVIDER, {
|
|
25
|
+
predicateType: "rea.managed-native-verification/v1",
|
|
26
|
+
operation: OPERATION,
|
|
27
|
+
parameters: {
|
|
28
|
+
managed_boundaries_evidence_id: input.managed_boundaries.evidence_id,
|
|
29
|
+
native_evidence_ids: jsonValueSchema.parse(input.native_observations.map(({ evidence_id: id }) => id)),
|
|
30
|
+
limits: jsonValueSchema.parse(input.limits),
|
|
31
|
+
},
|
|
32
|
+
result: jsonValueSchema.parse(result),
|
|
33
|
+
rawResult: null,
|
|
34
|
+
confidence: "inferred",
|
|
35
|
+
authority: "analyst-inference",
|
|
36
|
+
environment: null,
|
|
37
|
+
limitations: result.limitations,
|
|
38
|
+
evidenceLinks: result.evidence_links,
|
|
39
|
+
});
|