rea-agents 2.5.0 → 3.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 +20 -12
- package/bridge/ghidra/ReaGhidraBridge.java +477 -4
- package/bridge/hopper_bridge.py +54 -4
- package/dist/application/AnalysisContextQueries.js +142 -0
- package/dist/application/AnalysisSnapshotCache.js +4 -2
- package/dist/application/ApplicationWorkflowEvidenceResolver.js +19 -11
- package/dist/application/ArtifactInventory/policy.js +17 -0
- package/dist/application/ArtifactInventory/reader.js +1 -4
- package/dist/application/ArtifactInventory/scanCanonical.js +0 -3
- package/dist/application/ArtifactInventory/scanReader.js +7 -7
- package/dist/application/ArtifactInventory/types.js +1 -5
- package/dist/application/BinarySession.js +19 -20
- package/dist/application/BinarySessionComposition.js +21 -0
- package/dist/application/BinarySessionRecords.js +106 -10
- package/dist/application/BinarySessionStatus.js +11 -5
- package/dist/application/BrowserEvidence.js +3 -5
- package/dist/application/CapabilityClientRequirements.js +26 -0
- package/dist/application/CapabilityInventory.js +140 -55
- package/dist/application/ClientRegistrationStatus.js +4 -1
- package/dist/application/CrossVersionInventory.js +7 -6
- package/dist/application/DirectAnalysis.js +6 -2
- package/dist/application/ElectronActiveEvidence.js +55 -0
- package/dist/application/ElectronActiveObservationPort.js +1 -0
- package/dist/application/ElectronActiveObservationService.js +81 -0
- package/dist/application/EnhancedTools.js +49 -17
- package/dist/application/EvidenceBundleCommands.js +5 -1
- package/dist/application/EvidenceLedger.js +53 -17
- package/dist/application/JavaScriptArtifactAnalysis.js +13 -4
- package/dist/application/JavaScriptReplayPermission.js +1 -1
- package/dist/application/JavaScriptReplayService.js +23 -15
- package/dist/application/LazyAnalysisProvider.js +77 -0
- package/dist/application/LoopbackReplay.js +1 -1
- package/dist/application/ManagedRuntimeCorrelationService.js +9 -5
- package/dist/application/NativeApiInspection.js +80 -0
- package/dist/application/NodeRuntimeCharacterizationService.js +8 -9
- package/dist/application/ProcessCaptureLifecycle.js +5 -0
- package/dist/application/ProcessCli.js +2 -1
- package/dist/application/ProcessHarness.js +8 -3
- package/dist/application/ProcessNormalization.js +2 -1
- package/dist/application/ProjectPermissionStore.js +1 -0
- package/dist/application/ReferenceSourceImport.js +2 -2
- package/dist/application/SessionProviderRouter.js +6 -6
- package/dist/application/SetupClientConfiguration.js +10 -3
- package/dist/application/WindowsCapabilities.js +5 -4
- package/dist/application/runtime.js +26 -9
- package/dist/artifacts/ArtifactProvider.js +8 -10
- package/dist/artifacts/SafeOutputTree.js +7 -8
- package/dist/browser/CdpCaptureStorageFingerprints.js +10 -7
- package/dist/browser/CdpElectronInspection.js +3 -1
- package/dist/browser/JavaScriptRuntimeScope.js +5 -0
- package/dist/browser/PlaywrightBrowserScenarioProvider.js +8 -2
- package/dist/browser/PlaywrightElectronActiveActions.js +324 -0
- package/dist/browser/PlaywrightElectronActiveProvider.js +294 -0
- package/dist/browser/PlaywrightScenarioBrowser.js +4 -4
- package/dist/browser/PlaywrightScenarioSession.js +4 -4
- package/dist/browser/SensitiveTextCapture.js +1 -1
- package/dist/browser/V8InspectorCaptureProjection.js +1 -0
- package/dist/browser/V8InspectorProvider.js +3 -3
- package/dist/catalogIdentity.js +15 -9
- package/dist/cli/artifactCommands.js +5 -3
- package/dist/cli/coreAnalysisCommands.js +41 -0
- package/dist/cli/managedCommands.js +1 -1
- package/dist/cliApplicationCommands.js +2 -2
- package/dist/cliBrowserAdvancedCommands.js +11 -5
- package/dist/cliBrowserCommands.js +14 -7
- package/dist/cliCommandNames.js +2 -0
- package/dist/cliElectronCommands.js +46 -4
- package/dist/cliJavaScriptRuntimeCommands.js +14 -6
- package/dist/cliObservationOptions.js +4 -0
- package/dist/cliPolicyCommands.js +1 -0
- package/dist/config/browserScenario.js +77 -0
- package/dist/config/electronAutomation.js +35 -0
- package/dist/config/environment.js +6 -0
- package/dist/config/javascriptReplay.js +41 -0
- package/dist/config/managedRuntime.js +25 -0
- package/dist/config/parseConfig.js +56 -200
- package/dist/config/parsers.js +10 -1
- package/dist/config/passiveObservation.js +157 -0
- package/dist/config/processCapture.js +47 -0
- package/dist/contracts/applicationToolContracts.js +2 -5
- package/dist/contracts/applicationWorkflowInputContracts.js +86 -96
- package/dist/contracts/artifactToolContracts.js +35 -37
- package/dist/contracts/browserToolContracts.js +2 -2
- package/dist/contracts/electronToolContracts.js +30 -1
- package/dist/contracts/enhancedInputs.js +21 -27
- package/dist/contracts/functionWorkflowToolContracts.js +29 -0
- package/dist/contracts/managedToolContracts.js +4 -9
- package/dist/contracts/managedWorkflowExamples.js +12 -9
- package/dist/contracts/managedWorkflowToolContracts.js +30 -27
- package/dist/contracts/nativeToolContracts.js +2 -3
- package/dist/contracts/promptContracts.js +14 -15
- package/dist/contracts/sessionToolSchemas.js +61 -0
- package/dist/contracts/toolContractExamples.js +4 -0
- package/dist/contracts/toolContractHelpers.js +23 -0
- package/dist/contracts/toolContracts.js +12 -67
- package/dist/contracts/toolEffects.js +19 -0
- package/dist/contracts/toolOutputSchemaGroups.js +66 -11
- package/dist/contracts/toolOutputSchemaPrimitives.js +76 -26
- package/dist/contracts/toolSchemaMetadata.js +128 -0
- package/dist/doctorRuntime.js +1 -1
- package/dist/domain/analysisErrorPresentation.js +8 -2
- package/dist/domain/analysisErrorProjection.js +1 -0
- package/dist/domain/androidApplication.js +2 -0
- package/dist/domain/appleApplication.js +2 -0
- package/dist/domain/binaryTarget.js +7 -5
- package/dist/domain/binaryTargetTypes.js +1 -0
- package/dist/domain/browserCaptureComparison.js +21 -69
- package/dist/domain/browserObservation.js +22 -9
- package/dist/domain/bytecodeProvider.js +177 -0
- package/dist/domain/callPath.js +3 -2
- package/dist/domain/conformancePackage.js +169 -0
- package/dist/domain/conformanceReplay.js +104 -0
- package/dist/domain/conformanceTrustGate.js +328 -0
- package/dist/domain/customProtocolCapture.js +137 -0
- package/dist/domain/electronActiveObservation.js +277 -0
- package/dist/domain/electronObservation.js +15 -11
- package/dist/domain/electronStaticAnalysisValues.js +4 -1
- package/dist/domain/eventProcessTree.js +217 -0
- package/dist/domain/evidenceBundle.js +47 -0
- package/dist/domain/functionComparisonNormalization.js +15 -8
- package/dist/domain/functionDossierEvidence.js +9 -4
- package/dist/domain/hopperStartupFailure.js +1 -1
- package/dist/domain/hopperValues.js +68 -68
- package/dist/domain/inputIssueProjection.js +11 -2
- package/dist/domain/investigationWorkspace.js +16 -15
- package/dist/domain/javascriptExportShapeComparisonSchemas.js +2 -2
- package/dist/domain/javascriptReplay.js +79 -63
- package/dist/domain/javascriptRuntimeObservation.js +1 -0
- package/dist/domain/javascriptRuntimeReconciliationActive.js +89 -0
- package/dist/domain/javascriptRuntimeReconciliationGraph.js +11 -10
- package/dist/domain/javascriptRuntimeReconciliationMatching.js +57 -49
- package/dist/domain/javascriptRuntimeReconciliationParsing.js +5 -1
- package/dist/domain/javascriptRuntimeReconciliationResult.js +21 -14
- package/dist/domain/javascriptRuntimeReconciliationSchemas.js +1 -1
- package/dist/domain/javascriptSemanticAnalysis.js +8 -12
- package/dist/domain/javascriptSourceParser.js +15 -0
- package/dist/domain/javascriptStaticAnalysis.js +8 -12
- package/dist/domain/knownPageCoverage.js +15 -7
- package/dist/domain/mobileApplicationInvestigation.js +159 -0
- package/dist/domain/nativeApiBoundary.js +138 -0
- package/dist/domain/nodeRuntimeCharacterization.js +14 -13
- package/dist/domain/objcSwiftMetadata.js +150 -0
- package/dist/domain/packageAnalysis.js +123 -0
- package/dist/domain/peInspection.js +196 -0
- package/dist/domain/processCaptureReactiveValidation.js +8 -3
- package/dist/domain/processCaptureValidation.js +7 -3
- package/dist/domain/processComparison.js +12 -7
- package/dist/domain/processObservation.js +5 -6
- package/dist/domain/processReactiveMatching.js +14 -7
- package/dist/domain/processReactiveTransition.js +9 -3
- package/dist/domain/processScenario.js +6 -3
- package/dist/domain/processTraceComparison.js +3 -2
- package/dist/domain/protocolCapture.js +245 -0
- package/dist/domain/reconstructionReadinessSchemas.js +30 -2
- package/dist/domain/referenceSourceImportParsing.js +2 -2
- package/dist/domain/replayMachineRuntime.js +5 -3
- package/dist/domain/sourceToBundleComparison.js +2 -2
- package/dist/domain/sourceToBundleComparisonSchemas.js +8 -8
- package/dist/domain/sourceToBundleSignals.js +7 -1
- package/dist/domain/staticRuntimeCorrelation.js +7 -5
- package/dist/domain/webBundleAnalysis.js +14 -14
- package/dist/domain/webCaptureDiff.js +15 -12
- package/dist/dotnet/ManagedNativeBoundaryInspector.js +2 -3
- package/dist/dotnet/ManagedStaticProvider.js +34 -5
- package/dist/generatedMcpToolCatalog.js +37 -0
- package/dist/generatedPackageMetadata.js +4 -4
- package/dist/ghidra/GhidraClient.js +1 -1
- package/dist/ghidra/GhidraClientStartup.js +1 -1
- package/dist/ghidra/GhidraDefaults.js +1 -1
- package/dist/ghidra/GhidraFunctionValues.js +44 -16
- package/dist/ghidra/GhidraInventoryValues.js +57 -47
- package/dist/ghidra/GhidraProvider.js +18 -10
- package/dist/ghidra/GhidraProviderCapabilities.js +45 -39
- package/dist/ghidra/GhidraSocketConnection.js +1 -1
- package/dist/ghidra/protocol.js +19 -42
- package/dist/hopper/BridgeLauncher.js +3 -1
- package/dist/hopper/HopperAnalysisProfile.js +2 -4
- package/dist/hopper/HopperCleanup.js +5 -6
- package/dist/hopper/HopperClient.js +27 -3
- package/dist/hopper/HopperProvider.js +42 -44
- package/dist/hopper/HopperRequestQueue.js +32 -4
- package/dist/hopper/HopperResponseStream.js +2 -2
- package/dist/hopper/LinuxPrivateDisplayProbe.js +16 -10
- package/dist/hopper/protocol.js +63 -21
- package/dist/main/reload.js +1 -6
- package/dist/main/state.js +0 -14
- package/dist/main/transport.js +31 -41
- package/dist/main.js +17 -13
- package/dist/mcpDoctor.js +4 -26
- package/dist/mcpStartupPolicy.js +14 -0
- package/dist/process/PrivateRuntimeRoot.js +17 -0
- package/dist/process/ProcessOwnership.js +64 -128
- package/dist/process/ProcessOwnershipIdentity.js +13 -0
- package/dist/process/ProcessOwnershipObservation.js +88 -0
- package/dist/process/ProcessOwnershipProcessTree.js +22 -0
- package/dist/process/ProviderDeadline.js +8 -12
- package/dist/process/WindowsAuthority.js +32 -0
- package/dist/reference/ReferenceSourceReader.js +3 -3
- package/dist/reference/ReferenceSourceReaderEntries.js +2 -2
- package/dist/replay/JavaScriptReplayWorker.js +95 -11
- package/dist/replay/JavaScriptReplayWorkerTypes.js +1 -0
- package/dist/replay/LinuxJavaScriptReplayRunner.js +10 -15
- package/dist/replay/ReplayOutcome.js +26 -15
- package/dist/replay/ReplayWorkerProtocol.js +34 -29
- package/dist/server/createServer.js +101 -144
- package/dist/server/mcpClientMetadata.js +32 -0
- package/dist/server/registerApplicationTools/characterization.js +6 -13
- package/dist/server/registerApplicationTools/compareExportShapes.js +2 -7
- package/dist/server/registerApplicationTools/compareSourceToBundle.js +2 -7
- package/dist/server/registerApplicationTools/compareVersions.js +3 -8
- package/dist/server/registerApplicationTools/controlledReplay.js +6 -11
- package/dist/server/registerApplicationTools/coverage.js +13 -19
- package/dist/server/registerApplicationTools/obligationLedger.js +1 -6
- package/dist/server/registerApplicationTools/readiness.js +1 -6
- package/dist/server/registerApplicationTools/traceFeature.js +3 -8
- package/dist/server/registerApplicationTools/traceSemantics.js +1 -6
- package/dist/server/registerArtifactComparisonTool.js +12 -16
- package/dist/server/registerBrowserScenarioTool.js +1 -6
- package/dist/server/registerBrowserTools.js +37 -79
- package/dist/server/registerBundleComparisonTool.js +10 -14
- package/dist/server/registerCloseLifecycleTool.js +6 -14
- package/dist/server/registerElectronTools.js +30 -47
- package/dist/server/registerEnhancedTools.js +124 -122
- package/dist/server/registerEvidenceResources.js +50 -101
- package/dist/server/registerEvidenceTools.js +5 -9
- package/dist/server/registerFunctionComparisonTool.js +11 -15
- package/dist/server/registerInvestigationTools.js +42 -59
- package/dist/server/registerJavaScriptApplicationGraphResource.js +0 -4
- package/dist/server/registerJavaScriptRuntimeObservationTools.js +13 -27
- package/dist/server/registerManagedWorkflowTools/compareManagedMembers.js +4 -9
- package/dist/server/registerManagedWorkflowTools/contract.js +2 -3
- package/dist/server/registerManagedWorkflowTools/importManagedReconstruction.js +3 -8
- package/dist/server/registerManagedWorkflowTools/planManagedRuntimeCorrelation.js +3 -8
- package/dist/server/registerManagedWorkflowTools/projectManagedApplicationGraph.js +8 -13
- package/dist/server/registerManagedWorkflowTools/verifyManagedNativeBoundaries.js +4 -9
- package/dist/server/registerOfficialTools.js +8 -9
- package/dist/server/registerProcessComparisonTool.js +19 -24
- package/dist/server/registerReconstructionObligationLedgerResource.js +0 -7
- package/dist/server/registerReconstructionReadinessResource.js +0 -7
- package/dist/server/registerReplayMachineTool.js +4 -10
- package/dist/server/registerSessionRecordTools.js +146 -47
- package/dist/server/registerSessionStatusTool.js +14 -29
- package/dist/server/registerSessionTools.js +45 -41
- package/dist/server/sessionAvailabilityPolicy.js +2 -1
- package/dist/server/sessionToolPolicies.js +1 -5
- package/dist/server/toolRegistrationOptions.js +4 -177
- package/dist/server/toolResult.js +14 -18
- package/package.json +35 -16
- package/scripts/electron-active-hook-boundaries.cjs +394 -0
- package/scripts/electron-active-hook.cjs +501 -0
- package/skills/reverse-engineer-anything/SKILL.md +10 -3
- package/dist/server/DynamicToolAvailability.js +0 -70
- package/dist/server/toolInputValidation.js +0 -77
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { realpath } from "node:fs/promises";
|
|
2
|
+
import { digestJson } from "./JavaScriptReplayPlanning.js";
|
|
3
|
+
import { AnalysisCapabilityUnavailableError, AnalysisInputError, AnalysisProtocolError, PermissionRequiredError, } from "../domain/errors.js";
|
|
4
|
+
import { isPathContained } from "../domain/permissionPolicy.js";
|
|
5
|
+
import { err } from "../domain/result.js";
|
|
6
|
+
import { createElectronActiveEvidence } from "./ElectronActiveEvidence.js";
|
|
7
|
+
const OPERATION = "capture_electron_scenario";
|
|
8
|
+
const PROVIDER_ID = "rea-playwright-electron-active";
|
|
9
|
+
const canonicalizeInput = async (input) => {
|
|
10
|
+
try {
|
|
11
|
+
const [executablePath, applicationPath, applicationRoot] = await Promise.all([
|
|
12
|
+
realpath(input.executable_path),
|
|
13
|
+
realpath(input.application_path),
|
|
14
|
+
realpath(input.application_root),
|
|
15
|
+
]);
|
|
16
|
+
if (!isPathContained(applicationRoot, applicationPath))
|
|
17
|
+
return err(new AnalysisInputError(OPERATION, undefined, [
|
|
18
|
+
{
|
|
19
|
+
path: ["application_path"],
|
|
20
|
+
reason: "invalid_value",
|
|
21
|
+
message: "application_path must remain beneath application_root after symlink resolution",
|
|
22
|
+
},
|
|
23
|
+
]));
|
|
24
|
+
return {
|
|
25
|
+
ok: true,
|
|
26
|
+
value: {
|
|
27
|
+
...input,
|
|
28
|
+
executable_path: executablePath,
|
|
29
|
+
application_path: applicationPath,
|
|
30
|
+
application_root: applicationRoot,
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
catch (cause) {
|
|
35
|
+
return err(new AnalysisInputError(OPERATION, { cause }, [
|
|
36
|
+
{
|
|
37
|
+
path: ["application_path"],
|
|
38
|
+
reason: "invalid_format",
|
|
39
|
+
message: "Electron executable, application, and root must resolve to existing paths",
|
|
40
|
+
},
|
|
41
|
+
]));
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
const authorize = async (authority, input) => {
|
|
45
|
+
const canonical = await canonicalizeInput(input);
|
|
46
|
+
if (!canonical.ok)
|
|
47
|
+
return canonical;
|
|
48
|
+
if (authority === undefined)
|
|
49
|
+
return err(new AnalysisCapabilityUnavailableError(PROVIDER_ID, OPERATION, "active Electron observation permission policy is not configured"));
|
|
50
|
+
const authorized = await authority.authorize({
|
|
51
|
+
capability: "electron_automate",
|
|
52
|
+
roots: [canonical.value.application_root],
|
|
53
|
+
executables: [canonical.value.executable_path],
|
|
54
|
+
environment_names: [],
|
|
55
|
+
network: "external",
|
|
56
|
+
mount: false,
|
|
57
|
+
operation_identity: `${OPERATION}:${digestJson(canonical.value)}`,
|
|
58
|
+
}, "write");
|
|
59
|
+
if (!authorized.ok)
|
|
60
|
+
return err(authorized.error instanceof PermissionRequiredError
|
|
61
|
+
? authorized.error
|
|
62
|
+
: new AnalysisProtocolError(authorized.error.message, {
|
|
63
|
+
cause: authorized.error,
|
|
64
|
+
}));
|
|
65
|
+
return canonical;
|
|
66
|
+
};
|
|
67
|
+
/** Authorize and execute one bounded, provider-owned Electron experiment. */
|
|
68
|
+
export const captureElectronScenario = async (provider, authority, input, options = {}) => {
|
|
69
|
+
const authorized = await authorize(authority, input);
|
|
70
|
+
if (!authorized.ok)
|
|
71
|
+
return authorized;
|
|
72
|
+
if (provider === undefined)
|
|
73
|
+
return err(new AnalysisCapabilityUnavailableError(PROVIDER_ID, OPERATION, "active Electron observation provider is not configured"));
|
|
74
|
+
const captured = await provider.capture(authorized.value, options);
|
|
75
|
+
return captured.ok
|
|
76
|
+
? {
|
|
77
|
+
ok: true,
|
|
78
|
+
value: createElectronActiveEvidence(authorized.value, captured.value, provider.identity()),
|
|
79
|
+
}
|
|
80
|
+
: captured;
|
|
81
|
+
};
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import { enhancedInputSchemas } from "../contracts/enhancedInputs.js";
|
|
2
2
|
import { AnalysisCancelledError, AnalysisOutputError, projectAnalysisError, } from "../domain/errors.js";
|
|
3
|
-
import { addressDistance, parseDocuments, parseFunctionDossier, parseListCount, parseRelatedAddresses, parseSegments, } from "../domain/hopperValues.js";
|
|
3
|
+
import { addressDistance, functionDossierSchema, parseDocuments, parseFunctionDossier, parseListCount, parseRelatedAddresses, parseSegments, } from "../domain/hopperValues.js";
|
|
4
4
|
import { err, ok } from "../domain/result.js";
|
|
5
5
|
import { categorizeSwiftTypes, discoverObjcClasses, discoverObjcProtocols, discoverSwiftClasses, } from "../domain/symbolAnalysis.js";
|
|
6
|
+
import { jsonValueSchema } from "../domain/jsonValue.js";
|
|
6
7
|
import { invalidEnhancedInput, } from "./EnhancedToolTypes.js";
|
|
7
8
|
import { readAllAddressed } from "./EnhancedToolPagination.js";
|
|
8
9
|
import { traceCallPath } from "./CallPathTracing.js";
|
|
9
10
|
import { traceLiteralFeature } from "./EnhancedLiteralTracing.js";
|
|
11
|
+
import { projectNativeApiInspection } from "./NativeApiInspection.js";
|
|
10
12
|
/**
|
|
11
13
|
* Composes direct provider operations into bounded reverse-engineering tools.
|
|
12
14
|
* Direct callers use `execute`; adapters that own validation use
|
|
@@ -23,6 +25,8 @@ export class EnhancedTools {
|
|
|
23
25
|
name === "find_code_for_string" ||
|
|
24
26
|
name === "trace_call_path")
|
|
25
27
|
return this.#executeTracing(name, input, signal);
|
|
28
|
+
if (name === "analyze_function" || name === "inspect_native_api")
|
|
29
|
+
return this.#executeFunctionAnalysis(name, input, signal);
|
|
26
30
|
switch (name) {
|
|
27
31
|
case "swift_classes": {
|
|
28
32
|
const parsed = enhancedInputSchemas.swift_classes.safeParse(input);
|
|
@@ -64,12 +68,6 @@ export class EnhancedTools {
|
|
|
64
68
|
? this.executeValidated({ name, input: parsed.data }, signal)
|
|
65
69
|
: invalidEnhancedInput(name, parsed.error);
|
|
66
70
|
}
|
|
67
|
-
case "analyze_function": {
|
|
68
|
-
const parsed = enhancedInputSchemas.analyze_function.safeParse(input);
|
|
69
|
-
return parsed.success
|
|
70
|
-
? this.executeValidated({ name, input: parsed.data }, signal)
|
|
71
|
-
: invalidEnhancedInput(name, parsed.error);
|
|
72
|
-
}
|
|
73
71
|
}
|
|
74
72
|
}
|
|
75
73
|
/** Dispatch input already parsed by a trusted adapter boundary. */
|
|
@@ -93,6 +91,8 @@ export class EnhancedTools {
|
|
|
93
91
|
return this.#binaryOverview(call.input, signal);
|
|
94
92
|
case "analyze_function":
|
|
95
93
|
return this.#analyzeFunction(call.input, signal);
|
|
94
|
+
case "inspect_native_api":
|
|
95
|
+
return this.#inspectNativeApi(call.input, signal);
|
|
96
96
|
case "trace_feature":
|
|
97
97
|
return traceLiteralFeature((name, arguments_, operationSignal) => this.#call(name, arguments_, operationSignal), call.input, "feature", signal);
|
|
98
98
|
case "find_code_for_string":
|
|
@@ -102,23 +102,55 @@ export class EnhancedTools {
|
|
|
102
102
|
}
|
|
103
103
|
}
|
|
104
104
|
#executeTracing(name, input, signal) {
|
|
105
|
-
|
|
105
|
+
if (name === "trace_call_path") {
|
|
106
|
+
const parsed = enhancedInputSchemas.trace_call_path.safeParse(input);
|
|
107
|
+
if (!parsed.success)
|
|
108
|
+
return invalidEnhancedInput(name, parsed.error);
|
|
109
|
+
return this.executeValidated({ name, input: parsed.data }, signal);
|
|
110
|
+
}
|
|
111
|
+
if (name === "trace_feature") {
|
|
112
|
+
const parsed = enhancedInputSchemas.trace_feature.safeParse(input);
|
|
113
|
+
if (!parsed.success)
|
|
114
|
+
return invalidEnhancedInput(name, parsed.error);
|
|
115
|
+
return this.executeValidated({ name, input: parsed.data }, signal);
|
|
116
|
+
}
|
|
117
|
+
const parsed = enhancedInputSchemas.find_code_for_string.safeParse(input);
|
|
106
118
|
if (!parsed.success)
|
|
107
119
|
return invalidEnhancedInput(name, parsed.error);
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
input:
|
|
116
|
-
}
|
|
120
|
+
return this.executeValidated({ name, input: parsed.data }, signal);
|
|
121
|
+
}
|
|
122
|
+
#executeFunctionAnalysis(name, input, signal) {
|
|
123
|
+
if (name === "analyze_function") {
|
|
124
|
+
const parsed = enhancedInputSchemas.analyze_function.safeParse(input);
|
|
125
|
+
if (!parsed.success)
|
|
126
|
+
return invalidEnhancedInput(name, parsed.error);
|
|
127
|
+
return this.executeValidated({ name, input: parsed.data }, signal);
|
|
128
|
+
}
|
|
129
|
+
const parsed = enhancedInputSchemas.inspect_native_api.safeParse(input);
|
|
130
|
+
if (!parsed.success)
|
|
131
|
+
return invalidEnhancedInput(name, parsed.error);
|
|
132
|
+
return this.executeValidated({ name, input: parsed.data }, signal);
|
|
117
133
|
}
|
|
118
134
|
async #analyzeFunction(input, signal) {
|
|
119
135
|
const result = await this.#call("analyze_function", input, signal);
|
|
120
136
|
return result.ok ? parseFunctionDossier(result.value) : result;
|
|
121
137
|
}
|
|
138
|
+
async #inspectNativeApi(input, signal) {
|
|
139
|
+
const analysisInput = enhancedInputSchemas.analyze_function.parse({
|
|
140
|
+
procedure: input.procedure,
|
|
141
|
+
include_assembly: true,
|
|
142
|
+
max_pseudocode_chars: input.max_pseudocode_chars,
|
|
143
|
+
max_instructions: input.max_instructions,
|
|
144
|
+
});
|
|
145
|
+
const result = await this.#call("analyze_function", analysisInput, signal);
|
|
146
|
+
if (!result.ok)
|
|
147
|
+
return result;
|
|
148
|
+
const parsed = parseFunctionDossier(result.value);
|
|
149
|
+
if (!parsed.ok)
|
|
150
|
+
return parsed;
|
|
151
|
+
const dossier = functionDossierSchema.parse(parsed.value);
|
|
152
|
+
return ok(jsonValueSchema.parse(projectNativeApiInspection(dossier)));
|
|
153
|
+
}
|
|
122
154
|
async #swiftClasses(pattern, signal) {
|
|
123
155
|
const procedures = await this.#allAddressed("list_procedures", signal);
|
|
124
156
|
return procedures.ok
|
|
@@ -12,7 +12,11 @@ export const importEvidenceBundleCommand = async (path, policy) => {
|
|
|
12
12
|
const ledger = createLedger();
|
|
13
13
|
const imported = ledger.import(loaded.value);
|
|
14
14
|
return imported.ok
|
|
15
|
-
? ok({
|
|
15
|
+
? ok({
|
|
16
|
+
imported: imported.value.recordsAdded,
|
|
17
|
+
unknowns_added: imported.value.unknownsAdded,
|
|
18
|
+
total: ledger.export().records.length,
|
|
19
|
+
})
|
|
16
20
|
: imported;
|
|
17
21
|
};
|
|
18
22
|
/** Validate a source bundle and atomically export canonical bytes. */
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import canonicalize from "canonicalize";
|
|
2
|
-
import { createEvidenceBundle, parseEvidenceBundle, } from "../domain/evidenceBundle.js";
|
|
2
|
+
import { createEvidenceBundle, parseEvidenceBundle, validateResidualUnknownAddition, } from "../domain/evidenceBundle.js";
|
|
3
3
|
import { EvidenceIntegrityError, EvidenceLimitError, UnknownRegistryError, } from "../domain/errors.js";
|
|
4
4
|
import { parseEvidence } from "../domain/evidence.js";
|
|
5
5
|
import { createResidualUnknown, updateResidualUnknown, } from "../domain/residualUnknown.js";
|
|
@@ -63,6 +63,7 @@ export class EvidenceLedger {
|
|
|
63
63
|
pending.set(evidence.evidence_id, evidence);
|
|
64
64
|
}
|
|
65
65
|
const pendingUnknowns = new Map(this.#unknownRevisions);
|
|
66
|
+
let unknownsAdded = 0;
|
|
66
67
|
for (const unknown of bundle.unknowns) {
|
|
67
68
|
const key = unknownRevisionKey(unknown);
|
|
68
69
|
const existing = pendingUnknowns.get(key);
|
|
@@ -70,6 +71,8 @@ export class EvidenceLedger {
|
|
|
70
71
|
existing.revision_digest !== unknown.revision_digest)
|
|
71
72
|
return err(new EvidenceIntegrityError("Conflicting unknown revision"));
|
|
72
73
|
pendingUnknowns.set(key, unknown);
|
|
74
|
+
if (existing === undefined)
|
|
75
|
+
unknownsAdded += 1;
|
|
73
76
|
}
|
|
74
77
|
const checked = this.#validateCandidate(pending, pendingUnknowns);
|
|
75
78
|
if (!checked.ok) {
|
|
@@ -81,7 +84,11 @@ export class EvidenceLedger {
|
|
|
81
84
|
}
|
|
82
85
|
const added = pending.size - this.#records.size;
|
|
83
86
|
this.#commit(pending, pendingUnknowns, checked.value);
|
|
84
|
-
return ok(
|
|
87
|
+
return ok({
|
|
88
|
+
recordsAdded: added,
|
|
89
|
+
unknownsAdded,
|
|
90
|
+
changed: added > 0 || unknownsAdded > 0,
|
|
91
|
+
});
|
|
85
92
|
}
|
|
86
93
|
/** Export records in deterministic, semantically irrelevant ID order. */
|
|
87
94
|
export() {
|
|
@@ -142,26 +149,19 @@ export class EvidenceLedger {
|
|
|
142
149
|
catch (cause) {
|
|
143
150
|
return err(new UnknownRegistryError("invalid-transition", { cause }));
|
|
144
151
|
}
|
|
145
|
-
const pendingRecords = new Map(this.#records);
|
|
146
|
-
pendingRecords.set(evidence.evidence_id, evidence);
|
|
147
152
|
const existingUnknown = this.#unknownHeads.get(unknown.unknown_id);
|
|
148
153
|
if (existingUnknown !== undefined) {
|
|
149
154
|
if (existingUnknown.revision !== 1 ||
|
|
150
155
|
existingUnknown.revision_digest !== unknown.revision_digest)
|
|
151
156
|
return err(new UnknownRegistryError("already-exists"));
|
|
152
|
-
const checked = this.#
|
|
157
|
+
const checked = this.#appendIncremental([evidence]);
|
|
153
158
|
if (!checked.ok)
|
|
154
159
|
return checked;
|
|
155
|
-
this.#commit(pendingRecords, this.#unknownRevisions, checked.value);
|
|
156
160
|
return ok(null);
|
|
157
161
|
}
|
|
158
|
-
|
|
159
|
-
const pendingUnknowns = new Map(this.#unknownRevisions);
|
|
160
|
-
pendingUnknowns.set(unknownRevisionKey(unknown), unknown);
|
|
161
|
-
const checked = this.#validateCandidate(pendingRecords, pendingUnknowns);
|
|
162
|
+
const checked = this.#appendIncremental([evidence, mutation], unknown);
|
|
162
163
|
if (!checked.ok)
|
|
163
164
|
return checked;
|
|
164
|
-
this.#commit(pendingRecords, pendingUnknowns, checked.value);
|
|
165
165
|
return ok(structuredClone(unknown));
|
|
166
166
|
}
|
|
167
167
|
/** Apply one approved full-state update using optimistic revision matching. */
|
|
@@ -218,16 +218,52 @@ export class EvidenceLedger {
|
|
|
218
218
|
cause,
|
|
219
219
|
}));
|
|
220
220
|
}
|
|
221
|
-
const
|
|
222
|
-
pendingRecords.set(mutationEvidence.evidence_id, mutationEvidence);
|
|
223
|
-
const pendingUnknowns = new Map(this.#unknownRevisions);
|
|
224
|
-
pendingUnknowns.set(unknownRevisionKey(unknown), unknown);
|
|
225
|
-
const checked = this.#validateCandidate(pendingRecords, pendingUnknowns);
|
|
221
|
+
const checked = this.#appendIncremental([mutationEvidence], unknown);
|
|
226
222
|
if (!checked.ok)
|
|
227
223
|
return checked;
|
|
228
|
-
this.#commit(pendingRecords, pendingUnknowns, checked.value);
|
|
229
224
|
return ok(structuredClone(unknown));
|
|
230
225
|
}
|
|
226
|
+
#appendIncremental(records, unknown) {
|
|
227
|
+
const additions = new Map();
|
|
228
|
+
let addedBytes = 0;
|
|
229
|
+
for (const evidence of records) {
|
|
230
|
+
const existing = additions.get(evidence.evidence_id) ??
|
|
231
|
+
this.#records.get(evidence.evidence_id);
|
|
232
|
+
if (existing !== undefined) {
|
|
233
|
+
if (!recordsAgree(existing, evidence))
|
|
234
|
+
return err(new EvidenceIntegrityError("Conflicting evidence record"));
|
|
235
|
+
continue;
|
|
236
|
+
}
|
|
237
|
+
additions.set(evidence.evidence_id, evidence);
|
|
238
|
+
addedBytes += serializedBytes(evidence);
|
|
239
|
+
}
|
|
240
|
+
const unknownKey = unknown === undefined ? undefined : unknownRevisionKey(unknown);
|
|
241
|
+
if (unknownKey !== undefined && this.#unknownRevisions.has(unknownKey))
|
|
242
|
+
return err(new UnknownRegistryError("integrity"));
|
|
243
|
+
const unknownBytes = unknown === undefined ? 0 : serializedBytes(unknown);
|
|
244
|
+
if (this.#exceedsRecordLimit(this.#records.size + additions.size, this.#unknownRevisions.size + (unknown === undefined ? 0 : 1)))
|
|
245
|
+
return err(new EvidenceLimitError("records", this.limits.maxRecords));
|
|
246
|
+
if (this.#bytes + addedBytes + unknownBytes > this.limits.maxBytes)
|
|
247
|
+
return err(new EvidenceLimitError("bytes", this.limits.maxBytes));
|
|
248
|
+
if (unknown !== undefined)
|
|
249
|
+
try {
|
|
250
|
+
validateResidualUnknownAddition(unknown, {
|
|
251
|
+
get: (id) => additions.get(id) ?? this.#records.get(id),
|
|
252
|
+
has: (id) => additions.has(id) || this.#records.has(id),
|
|
253
|
+
}, this.#unknownHeads);
|
|
254
|
+
}
|
|
255
|
+
catch (cause) {
|
|
256
|
+
return err(new UnknownRegistryError("integrity", { cause }));
|
|
257
|
+
}
|
|
258
|
+
for (const [id, evidence] of additions)
|
|
259
|
+
this.#records.set(id, evidence);
|
|
260
|
+
if (unknown !== undefined && unknownKey !== undefined) {
|
|
261
|
+
this.#unknownRevisions.set(unknownKey, unknown);
|
|
262
|
+
this.#unknownHeads.set(unknown.unknown_id, unknown);
|
|
263
|
+
}
|
|
264
|
+
this.#bytes += addedBytes + unknownBytes;
|
|
265
|
+
return ok(undefined);
|
|
266
|
+
}
|
|
231
267
|
#validateCandidate(records, unknowns) {
|
|
232
268
|
if (this.#exceedsRecordLimit(records.size, unknowns.size))
|
|
233
269
|
return err(new EvidenceLimitError("records", this.limits.maxRecords));
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { analyzeParsedJavaScriptStaticSource } from "../domain/javascriptStaticAnalysis.js";
|
|
3
|
+
import { analyzeParsedJavaScriptSemantics } from "../domain/javascriptSemanticAnalysis.js";
|
|
4
4
|
import { DEFAULT_JAVASCRIPT_SEMANTIC_LIMITS, } from "../domain/javascriptSemanticIr.js";
|
|
5
|
+
import { parseJavaScriptSource } from "../domain/javascriptSourceParser.js";
|
|
6
|
+
import { failedJavaScriptStaticAnalysis } from "../domain/javascriptStaticAnalysisHelpers.js";
|
|
5
7
|
import { analyzeJavaScriptJsonModule } from "./JavaScriptJsonModules.js";
|
|
6
8
|
/** Analyze selected text files under one shared AST, finding, module, and time budget. */
|
|
7
9
|
export const analyzeJavaScriptArtifactFiles = (fileSet, input, now) => {
|
|
@@ -70,7 +72,14 @@ const analyzeArtifactFile = (file, context) => {
|
|
|
70
72
|
state.truncatedScopes += 1;
|
|
71
73
|
return;
|
|
72
74
|
}
|
|
73
|
-
const
|
|
75
|
+
const parsed = parseJavaScriptSource(file.text.value);
|
|
76
|
+
if (parsed === null) {
|
|
77
|
+
const analysis = failedJavaScriptStaticAnalysis();
|
|
78
|
+
state.files.push({ file, javascript: analysis, semantic: null });
|
|
79
|
+
state.parseFailures += 1;
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
const analysis = analyzeParsedJavaScriptStaticSource(file.text.value, parsed, {
|
|
74
83
|
maxAstNodes: remainingNodes,
|
|
75
84
|
maxFindings: remainingFindings,
|
|
76
85
|
maxModules: remainingModules,
|
|
@@ -88,7 +97,7 @@ const analyzeArtifactFile = (file, context) => {
|
|
|
88
97
|
maxModuleLinks: semanticFindingBudget,
|
|
89
98
|
};
|
|
90
99
|
const semantics = analysis.parse_status === "complete" || analysis.parse_status === "partial"
|
|
91
|
-
?
|
|
100
|
+
? analyzeParsedJavaScriptSemantics(parsed, semanticLimits)
|
|
92
101
|
: null;
|
|
93
102
|
state.files.push({
|
|
94
103
|
file,
|
|
@@ -12,5 +12,5 @@ export const replayPermissionRequest = (input, policy) => ({
|
|
|
12
12
|
environment_names: [],
|
|
13
13
|
network: "none",
|
|
14
14
|
mount: true,
|
|
15
|
-
operation_identity: `run_controlled_replay:${input.
|
|
15
|
+
operation_identity: `run_controlled_replay:${input.mode === "plan" ? "plan" : input.plan_digest}`,
|
|
16
16
|
});
|
|
@@ -19,10 +19,10 @@ export const runControlledReplay = async (dependencies, rawInput, options = {})
|
|
|
19
19
|
};
|
|
20
20
|
/** Plan or execute replay input already parsed by a trusted adapter. */
|
|
21
21
|
export const runControlledReplayValidated = async (dependencies, input, options = {}) => {
|
|
22
|
-
const authorized = await authorizeReplay(dependencies, input, options.signal);
|
|
22
|
+
const authorized = await authorizeReplay(dependencies, dependencies.policy(), input, options.signal);
|
|
23
23
|
if (!authorized.ok)
|
|
24
24
|
return authorized;
|
|
25
|
-
const prepared = await prepareValidatedReplay(dependencies, input, options.signal);
|
|
25
|
+
const prepared = await prepareValidatedReplay(dependencies, authorized.value, input, options.signal);
|
|
26
26
|
if (!prepared.ok)
|
|
27
27
|
return prepared;
|
|
28
28
|
if (isAborted(options.signal))
|
|
@@ -35,11 +35,17 @@ export const runControlledReplayValidated = async (dependencies, input, options
|
|
|
35
35
|
evidence: null,
|
|
36
36
|
}));
|
|
37
37
|
if (input.plan_digest !== prepared.value.publicPlan.plan_digest)
|
|
38
|
-
return err(new ReplayPlanStaleError(input.plan_digest
|
|
38
|
+
return err(new ReplayPlanStaleError(input.plan_digest, prepared.value.publicPlan.plan_digest));
|
|
39
39
|
const exportContext = await authorizeReproducerExport(dependencies.authority, input, prepared.value);
|
|
40
40
|
if (!exportContext.ok)
|
|
41
41
|
return exportContext;
|
|
42
|
-
const executed = await executeValidatedReplay(
|
|
42
|
+
const executed = await executeValidatedReplay({
|
|
43
|
+
runner: dependencies.runner,
|
|
44
|
+
policy: authorized.value,
|
|
45
|
+
prepared: prepared.value,
|
|
46
|
+
exportContext: exportContext.value,
|
|
47
|
+
options,
|
|
48
|
+
});
|
|
43
49
|
if (!executed.ok)
|
|
44
50
|
return executed;
|
|
45
51
|
try {
|
|
@@ -51,14 +57,14 @@ export const runControlledReplayValidated = async (dependencies, input, options
|
|
|
51
57
|
: "Controlled replay could not establish or clean up its sandbox", { cause }));
|
|
52
58
|
}
|
|
53
59
|
};
|
|
54
|
-
const authorizeReplay = async (dependencies, input, signal) => {
|
|
55
|
-
if (
|
|
60
|
+
const authorizeReplay = async (dependencies, policy, input, signal) => {
|
|
61
|
+
if (policy.status === "disabled")
|
|
56
62
|
return err(new AnalysisCapabilityUnavailableError("rea-javascript-replay", OPERATION, "controlled replay is disabled; configure exact roots and executables before enabling it"));
|
|
57
63
|
if (dependencies.authority === undefined)
|
|
58
64
|
return err(new AnalysisCapabilityUnavailableError("rea-javascript-replay", OPERATION, "JavaScript replay permission policy is not configured"));
|
|
59
65
|
if (isAborted(signal))
|
|
60
66
|
return err(new AnalysisCancelledError(OPERATION));
|
|
61
|
-
const request = replayPermissionRequest(input,
|
|
67
|
+
const request = replayPermissionRequest(input, policy);
|
|
62
68
|
const authorized = input.mode === "plan"
|
|
63
69
|
? await dependencies.authority.explain(request, "read")
|
|
64
70
|
: await dependencies.authority.authorize(request, "read");
|
|
@@ -68,13 +74,13 @@ const authorizeReplay = async (dependencies, input, signal) => {
|
|
|
68
74
|
: new AnalysisProtocolError(authorized.error.message, {
|
|
69
75
|
cause: authorized.error,
|
|
70
76
|
}));
|
|
71
|
-
return ok(
|
|
77
|
+
return ok(policy);
|
|
72
78
|
};
|
|
73
|
-
const prepareValidatedReplay = async (dependencies, input, signal) => {
|
|
79
|
+
const prepareValidatedReplay = async (dependencies, policy, input, signal) => {
|
|
74
80
|
if (isAborted(signal))
|
|
75
81
|
return err(new AnalysisCancelledError(OPERATION));
|
|
76
82
|
try {
|
|
77
|
-
return ok(await prepareReplayPlan(input,
|
|
83
|
+
return ok(await prepareReplayPlan(input, policy, dependencies.host));
|
|
78
84
|
}
|
|
79
85
|
catch (cause) {
|
|
80
86
|
return err(new AnalysisCapabilityUnavailableError("rea-javascript-replay", OPERATION, cause instanceof Error ? cause.message : "replay planning failed"));
|
|
@@ -83,8 +89,6 @@ const prepareValidatedReplay = async (dependencies, input, signal) => {
|
|
|
83
89
|
const authorizeReproducerExport = async (authority, input, prepared) => {
|
|
84
90
|
if (input.reproducer_export === undefined)
|
|
85
91
|
return ok(undefined);
|
|
86
|
-
if (input.reproducer_export.approved !== true)
|
|
87
|
-
return err(new AnalysisInputError(`${OPERATION}:reproducer_export`));
|
|
88
92
|
if (authority === undefined)
|
|
89
93
|
return err(new AnalysisCapabilityUnavailableError("rea-javascript-replay", OPERATION, "JavaScript replay permission policy is not configured"));
|
|
90
94
|
const exportAuthorized = await authority.authorize({
|
|
@@ -112,7 +116,8 @@ const authorizeReproducerExport = async (authority, input, prepared) => {
|
|
|
112
116
|
includeSources: input.reproducer_export.include_sources === true,
|
|
113
117
|
});
|
|
114
118
|
};
|
|
115
|
-
const executeValidatedReplay = async (
|
|
119
|
+
const executeValidatedReplay = async (context) => {
|
|
120
|
+
const { runner, policy, prepared, exportContext, options } = context;
|
|
116
121
|
await options.progress?.report({
|
|
117
122
|
phase: OPERATION,
|
|
118
123
|
completed: 0,
|
|
@@ -122,7 +127,7 @@ const executeValidatedReplay = async (dependencies, prepared, exportContext, opt
|
|
|
122
127
|
if (isAborted(options.signal))
|
|
123
128
|
return err(new AnalysisCancelledError(OPERATION));
|
|
124
129
|
try {
|
|
125
|
-
let executed = replayExecutionResultSchema.parse(await
|
|
130
|
+
let executed = replayExecutionResultSchema.parse(await runner.execute(prepared, policy, options.signal));
|
|
126
131
|
await options.progress?.report({
|
|
127
132
|
phase: OPERATION,
|
|
128
133
|
completed: 1,
|
|
@@ -289,4 +294,7 @@ const createReplayEvidence = (prepared, executed, side, outcomes) => {
|
|
|
289
294
|
})),
|
|
290
295
|
});
|
|
291
296
|
};
|
|
292
|
-
const asJson = (value) =>
|
|
297
|
+
const asJson = (value) => {
|
|
298
|
+
const serialized = JSON.parse(JSON.stringify(controlledReplayOutputSchema.parse(value)));
|
|
299
|
+
return jsonValueSchema.parse(serialized);
|
|
300
|
+
};
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Preserve synchronous provider discovery while loading implementation modules
|
|
3
|
+
* only when a target-bound client first executes.
|
|
4
|
+
*/
|
|
5
|
+
export class LazyAnalysisProvider {
|
|
6
|
+
#providerIdentity;
|
|
7
|
+
#capabilityDescriptors;
|
|
8
|
+
#loadProvider;
|
|
9
|
+
#provider;
|
|
10
|
+
constructor(options) {
|
|
11
|
+
this.#providerIdentity = options.identity;
|
|
12
|
+
this.#capabilityDescriptors = options.capabilities;
|
|
13
|
+
this.#loadProvider = options.load;
|
|
14
|
+
}
|
|
15
|
+
/** Return generated provider identity without loading its implementation. */
|
|
16
|
+
identity() {
|
|
17
|
+
return this.#providerIdentity;
|
|
18
|
+
}
|
|
19
|
+
/** Return generated capability metadata without loading its implementation. */
|
|
20
|
+
capabilities() {
|
|
21
|
+
return this.#capabilityDescriptors;
|
|
22
|
+
}
|
|
23
|
+
/** Create a client whose implementation is loaded on first execution. */
|
|
24
|
+
createClient(target, profile, context) {
|
|
25
|
+
return new LazyAnalysisClient(async () => {
|
|
26
|
+
const provider = await this.#load();
|
|
27
|
+
return provider.createClient(target, profile, context);
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
async #load() {
|
|
31
|
+
this.#provider ??= this.#loadProvider().catch((cause) => {
|
|
32
|
+
this.#provider = undefined;
|
|
33
|
+
throw cause;
|
|
34
|
+
});
|
|
35
|
+
return this.#provider;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
class LazyAnalysisClient {
|
|
39
|
+
#loadClient;
|
|
40
|
+
#client;
|
|
41
|
+
#loading;
|
|
42
|
+
#closed = false;
|
|
43
|
+
constructor(loadClient) {
|
|
44
|
+
this.#loadClient = loadClient;
|
|
45
|
+
}
|
|
46
|
+
execute = async (operation, parameters, options) => {
|
|
47
|
+
const client = await this.#load();
|
|
48
|
+
return client.execute(operation, parameters, options);
|
|
49
|
+
};
|
|
50
|
+
runtimeLineageSnapshots() {
|
|
51
|
+
return this.#client?.runtimeLineageSnapshots?.() ?? [];
|
|
52
|
+
}
|
|
53
|
+
requestActivitySnapshots() {
|
|
54
|
+
return this.#client?.requestActivitySnapshots?.() ?? [];
|
|
55
|
+
}
|
|
56
|
+
async close() {
|
|
57
|
+
this.#closed = true;
|
|
58
|
+
if (this.#loading === undefined)
|
|
59
|
+
return;
|
|
60
|
+
const client = await this.#loading;
|
|
61
|
+
await client.close();
|
|
62
|
+
}
|
|
63
|
+
async #load() {
|
|
64
|
+
if (this.#closed)
|
|
65
|
+
throw new Error("Lazy analysis client is closed");
|
|
66
|
+
this.#loading ??= this.#loadClient()
|
|
67
|
+
.then((client) => {
|
|
68
|
+
this.#client = client;
|
|
69
|
+
return client;
|
|
70
|
+
})
|
|
71
|
+
.catch((cause) => {
|
|
72
|
+
this.#loading = undefined;
|
|
73
|
+
throw cause;
|
|
74
|
+
});
|
|
75
|
+
return this.#loading;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
@@ -374,11 +374,11 @@ export const startLoopbackReplay = async (scenario, recordEvent = () => undefine
|
|
|
374
374
|
async close() {
|
|
375
375
|
closePromise ??= (async () => {
|
|
376
376
|
recorder.stopMachineAdmission();
|
|
377
|
+
await recorder.drainMachine();
|
|
377
378
|
for (const client of websocket.clients)
|
|
378
379
|
client.terminate();
|
|
379
380
|
await new Promise((resolveClose) => websocket.close(() => resolveClose()));
|
|
380
381
|
await closeReplayServer(server);
|
|
381
|
-
await recorder.drainMachine();
|
|
382
382
|
})();
|
|
383
383
|
await closePromise;
|
|
384
384
|
},
|
|
@@ -6,6 +6,10 @@ import { err, ok } from "../domain/result.js";
|
|
|
6
6
|
import { MANAGED_WORKFLOW_PROVIDER } from "./InvestigationProviders.js";
|
|
7
7
|
import { digestJson } from "./JavaScriptReplayPlanning.js";
|
|
8
8
|
const OPERATION = "plan_managed_runtime_correlation";
|
|
9
|
+
/** A managed-runtime policy that grants no runtime-correlation authority. */
|
|
10
|
+
export const MANAGED_RUNTIME_DISABLED = {
|
|
11
|
+
status: "disabled",
|
|
12
|
+
};
|
|
9
13
|
/** Create a separately authorized, non-executing managed runtime plan Evidence. */
|
|
10
14
|
export const planManagedRuntimeCorrelationEvidence = async (dependencies, rawInput) => {
|
|
11
15
|
const parsed = managedRuntimeCorrelationInputSchema.safeParse(rawInput);
|
|
@@ -15,12 +19,12 @@ export const planManagedRuntimeCorrelationEvidence = async (dependencies, rawInp
|
|
|
15
19
|
};
|
|
16
20
|
/** Plan runtime correlation from input parsed by a trusted adapter. */
|
|
17
21
|
export const planManagedRuntimeCorrelationEvidenceValidated = async (dependencies, input) => {
|
|
18
|
-
|
|
22
|
+
const policy = dependencies.policy();
|
|
23
|
+
if (policy.status === "disabled")
|
|
19
24
|
return err(new AnalysisCapabilityUnavailableError(MANAGED_WORKFLOW_PROVIDER.id, OPERATION, "managed runtime correlation is disabled; configure exact roots and runtime executable before enabling it"));
|
|
20
25
|
if (dependencies.authority === undefined)
|
|
21
26
|
return err(new AnalysisCapabilityUnavailableError(MANAGED_WORKFLOW_PROVIDER.id, OPERATION, "managed runtime permission policy is not configured"));
|
|
22
|
-
let staticEvidence;
|
|
23
|
-
let artifactPath;
|
|
27
|
+
let staticEvidence, artifactPath;
|
|
24
28
|
try {
|
|
25
29
|
staticEvidence = parseEvidence(input.static_members);
|
|
26
30
|
artifactPath = artifactPathFor(staticEvidence);
|
|
@@ -31,7 +35,7 @@ export const planManagedRuntimeCorrelationEvidenceValidated = async (dependencie
|
|
|
31
35
|
const authorized = await dependencies.authority.explain({
|
|
32
36
|
capability: "managed_runtime",
|
|
33
37
|
roots: [artifactPath],
|
|
34
|
-
executables: [
|
|
38
|
+
executables: [policy.executablePath],
|
|
35
39
|
environment_names: [],
|
|
36
40
|
network: "none",
|
|
37
41
|
mount: false,
|
|
@@ -44,7 +48,7 @@ export const planManagedRuntimeCorrelationEvidenceValidated = async (dependencie
|
|
|
44
48
|
cause: authorized.error,
|
|
45
49
|
}));
|
|
46
50
|
try {
|
|
47
|
-
const result = planManagedRuntimeCorrelation(input,
|
|
51
|
+
const result = planManagedRuntimeCorrelation(input, policy.executablePath, authorized.value.grant_id);
|
|
48
52
|
return ok(createEvidence({
|
|
49
53
|
path: result.static_observation.artifact_path,
|
|
50
54
|
sha256: result.static_observation.artifact_sha256,
|