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
|
@@ -1,24 +1,37 @@
|
|
|
1
1
|
import { createEvidence } from "../domain/evidence.js";
|
|
2
|
-
import { evidenceBundleForTarget } from "../domain/evidenceBundle.js";
|
|
3
|
-
import { EvidenceIntegrityError, } from "../domain/errors.js";
|
|
2
|
+
import { evidenceBundleForTarget, serializeEvidenceBundle, } from "../domain/evidenceBundle.js";
|
|
3
|
+
import { EvidenceIntegrityError, EvidenceLimitError, } from "../domain/errors.js";
|
|
4
4
|
import { parseInvestigationWorkspace, } from "../domain/investigationWorkspace.js";
|
|
5
5
|
import { parseReconstructionCoverageWorkspace, } from "../domain/reconstructionCoverage.js";
|
|
6
|
-
import { err } from "../domain/result.js";
|
|
6
|
+
import { err, ok } from "../domain/result.js";
|
|
7
7
|
import { AnalysisSnapshotCache } from "./AnalysisSnapshotCache.js";
|
|
8
8
|
import { EvidenceLedger } from "./EvidenceLedger.js";
|
|
9
9
|
import { UNKNOWN_REGISTRY_PROVIDER, unknownEvidenceLinks, unknownMutationEvidence, } from "./UnknownEvidence.js";
|
|
10
10
|
/** Owns session evidence, snapshots, workspaces, and residual unknowns. */
|
|
11
11
|
export class BinarySessionRecords {
|
|
12
|
+
static MAX_RETAINED_BUNDLES = 16;
|
|
13
|
+
static MAX_RETAINED_BUNDLE_BYTES = 64 * 1024 * 1024;
|
|
12
14
|
#evidence = new EvidenceLedger({
|
|
13
15
|
maxRecords: 10_000,
|
|
14
16
|
maxBytes: 64 * 1024 * 1024,
|
|
15
17
|
});
|
|
16
18
|
#snapshot = new AnalysisSnapshotCache();
|
|
19
|
+
#retainedBundles = new Map();
|
|
20
|
+
#retainedBundleBytes = 0;
|
|
17
21
|
#investigationWorkspaces = new Map();
|
|
18
22
|
#coverageWorkspaces = new Map();
|
|
19
23
|
#snapshotInvalidated = false;
|
|
24
|
+
#snapshotListeners = new Set();
|
|
25
|
+
/** Observe changes to the mutable current analysis snapshot resource. */
|
|
26
|
+
onAnalysisSnapshotChanged(listener) {
|
|
27
|
+
this.#snapshotListeners.add(listener);
|
|
28
|
+
return () => this.#snapshotListeners.delete(listener);
|
|
29
|
+
}
|
|
20
30
|
recordEvidence(evidence) {
|
|
21
|
-
|
|
31
|
+
const recorded = this.#evidence.record(evidence);
|
|
32
|
+
if (recorded.ok && recorded.value === "added")
|
|
33
|
+
this.#emitSnapshotChanged();
|
|
34
|
+
return recorded;
|
|
22
35
|
}
|
|
23
36
|
hasEvidence(evidenceId) {
|
|
24
37
|
return this.#evidence.has(evidenceId);
|
|
@@ -29,8 +42,52 @@ export class BinarySessionRecords {
|
|
|
29
42
|
exportEvidenceBundle() {
|
|
30
43
|
return this.#evidence.export();
|
|
31
44
|
}
|
|
45
|
+
snapshotEvidenceBundle() {
|
|
46
|
+
const bundle = this.#evidence.export();
|
|
47
|
+
const encoded = serializeEvidenceBundle(bundle);
|
|
48
|
+
const digest = createHash("sha256").update(encoded).digest("hex");
|
|
49
|
+
const existing = this.#retainedBundles.get(digest);
|
|
50
|
+
if (existing === undefined) {
|
|
51
|
+
if (this.#retainedBundles.size >= BinarySessionRecords.MAX_RETAINED_BUNDLES)
|
|
52
|
+
return err(new EvidenceLimitError("records", BinarySessionRecords.MAX_RETAINED_BUNDLES));
|
|
53
|
+
const bytes = Buffer.byteLength(encoded);
|
|
54
|
+
if (this.#retainedBundleBytes + bytes >
|
|
55
|
+
BinarySessionRecords.MAX_RETAINED_BUNDLE_BYTES)
|
|
56
|
+
return err(new EvidenceLimitError("bytes", BinarySessionRecords.MAX_RETAINED_BUNDLE_BYTES));
|
|
57
|
+
this.#retainedBundles.set(digest, encoded);
|
|
58
|
+
this.#retainedBundleBytes += bytes;
|
|
59
|
+
}
|
|
60
|
+
return ok({
|
|
61
|
+
bundleDigest: digest,
|
|
62
|
+
bundleVersion: 2,
|
|
63
|
+
bytes: Buffer.byteLength(existing ?? encoded),
|
|
64
|
+
records: bundle.records.length,
|
|
65
|
+
unknowns: bundle.unknowns.length,
|
|
66
|
+
scope: "session",
|
|
67
|
+
survivesSession: false,
|
|
68
|
+
uri: `rea://evidence-bundle/${digest}`,
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
retainedEvidenceBundle(digest) {
|
|
72
|
+
return this.#retainedBundles.get(digest);
|
|
73
|
+
}
|
|
74
|
+
/** Release one immutable bundle so bounded retention has an explicit recovery path. */
|
|
75
|
+
releaseEvidenceBundle(bundleDigest) {
|
|
76
|
+
const encoded = this.#retainedBundles.get(bundleDigest);
|
|
77
|
+
if (encoded === undefined)
|
|
78
|
+
return false;
|
|
79
|
+
this.#retainedBundles.delete(bundleDigest);
|
|
80
|
+
this.#retainedBundleBytes -= Buffer.byteLength(encoded);
|
|
81
|
+
this.#emitSnapshotChanged();
|
|
82
|
+
return true;
|
|
83
|
+
}
|
|
32
84
|
importEvidenceBundle(bundle) {
|
|
33
|
-
|
|
85
|
+
const imported = this.#evidence.import(bundle);
|
|
86
|
+
if (!imported.ok)
|
|
87
|
+
return imported;
|
|
88
|
+
if (imported.value.changed)
|
|
89
|
+
this.#emitSnapshotChanged();
|
|
90
|
+
return ok(imported.value.recordsAdded);
|
|
34
91
|
}
|
|
35
92
|
exportAnalysisSnapshot() {
|
|
36
93
|
const active = this.activeAnalysisBinding();
|
|
@@ -48,36 +105,65 @@ export class BinarySessionRecords {
|
|
|
48
105
|
const active = this.activeAnalysisBinding();
|
|
49
106
|
if (active?.profile === null)
|
|
50
107
|
return err(new EvidenceIntegrityError("Analysis snapshot profile_mismatch: the active target has no concrete analysis profile"));
|
|
51
|
-
|
|
108
|
+
const imported = this.#snapshot.import(snapshot, active === undefined
|
|
52
109
|
? undefined
|
|
53
|
-
: { target: active.target, profile: active.profile }, (bundle) =>
|
|
110
|
+
: { target: active.target, profile: active.profile }, (bundle) => {
|
|
111
|
+
const imported = this.#evidence.import(bundle);
|
|
112
|
+
return imported.ok ? ok(imported.value.recordsAdded) : imported;
|
|
113
|
+
});
|
|
114
|
+
if (imported.ok)
|
|
115
|
+
this.#emitSnapshotChanged();
|
|
116
|
+
return imported;
|
|
54
117
|
}
|
|
55
118
|
matchesSnapshot(target, profile) {
|
|
56
119
|
return this.#snapshot.matches(target, profile ?? undefined);
|
|
57
120
|
}
|
|
58
121
|
selectSnapshot(target, profile) {
|
|
59
122
|
this.#snapshot.select(target, profile);
|
|
123
|
+
this.#emitSnapshotChanged();
|
|
60
124
|
}
|
|
61
125
|
lookupSnapshot(target, profile, operation, parameters) {
|
|
62
126
|
return this.#snapshot.lookup(target, profile, operation, parameters);
|
|
63
127
|
}
|
|
64
128
|
recordSnapshot(input) {
|
|
65
129
|
this.#snapshot.record(input);
|
|
130
|
+
this.#emitSnapshotChanged();
|
|
66
131
|
}
|
|
67
132
|
invalidateSnapshot() {
|
|
68
133
|
this.#snapshot.clear();
|
|
69
134
|
this.#snapshotInvalidated = true;
|
|
135
|
+
this.#emitSnapshotChanged();
|
|
70
136
|
}
|
|
71
137
|
resetSnapshotInvalidation() {
|
|
138
|
+
if (!this.#snapshotInvalidated)
|
|
139
|
+
return;
|
|
72
140
|
this.#snapshotInvalidated = false;
|
|
141
|
+
this.#emitSnapshotChanged();
|
|
73
142
|
}
|
|
74
143
|
clearSnapshot() {
|
|
75
144
|
this.#snapshot.clear();
|
|
145
|
+
this.#emitSnapshotChanged();
|
|
76
146
|
}
|
|
77
147
|
clearSessionRecords() {
|
|
78
148
|
this.#evidence.clear();
|
|
79
149
|
this.#snapshot.clear();
|
|
80
150
|
this.#snapshotInvalidated = false;
|
|
151
|
+
this.#retainedBundles.clear();
|
|
152
|
+
this.#retainedBundleBytes = 0;
|
|
153
|
+
this.#emitSnapshotChanged();
|
|
154
|
+
}
|
|
155
|
+
#emitSnapshotChanged() {
|
|
156
|
+
for (const listener of this.#snapshotListeners) {
|
|
157
|
+
try {
|
|
158
|
+
const notification = listener();
|
|
159
|
+
if (notification !== undefined)
|
|
160
|
+
void notification.catch(() => undefined);
|
|
161
|
+
}
|
|
162
|
+
catch {
|
|
163
|
+
// External resource observers are best-effort; one callback must not
|
|
164
|
+
// make a committed evidence mutation appear to fail.
|
|
165
|
+
}
|
|
166
|
+
}
|
|
81
167
|
}
|
|
82
168
|
retainInvestigationWorkspace(workspace) {
|
|
83
169
|
const parsed = parseInvestigationWorkspace(workspace);
|
|
@@ -111,10 +197,16 @@ export class BinarySessionRecords {
|
|
|
111
197
|
}
|
|
112
198
|
recordUnknown(input) {
|
|
113
199
|
const target = this.activeAnalysisBinding()?.target;
|
|
114
|
-
|
|
200
|
+
const recorded = this.#evidence.recordUnknown(input, unknownMutationEvidence(target, input));
|
|
201
|
+
if (recorded.ok)
|
|
202
|
+
this.#emitSnapshotChanged();
|
|
203
|
+
return recorded;
|
|
115
204
|
}
|
|
116
205
|
recordEvidenceWithUnknown(evidence, input) {
|
|
117
|
-
|
|
206
|
+
const recorded = this.#evidence.recordWithUnknown(evidence, input, unknownMutationEvidence(undefined, input));
|
|
207
|
+
if (recorded.ok)
|
|
208
|
+
this.#emitSnapshotChanged();
|
|
209
|
+
return recorded;
|
|
118
210
|
}
|
|
119
211
|
updateUnknown(input) {
|
|
120
212
|
const target = this.activeAnalysisBinding()?.target;
|
|
@@ -133,7 +225,10 @@ export class BinarySessionRecords {
|
|
|
133
225
|
"Registry mutation evidence records analyst intent, not proof of the answer.",
|
|
134
226
|
],
|
|
135
227
|
});
|
|
136
|
-
|
|
228
|
+
const updated = this.#evidence.updateUnknown(input, evidence);
|
|
229
|
+
if (updated.ok)
|
|
230
|
+
this.#emitSnapshotChanged();
|
|
231
|
+
return updated;
|
|
137
232
|
}
|
|
138
233
|
listUnknowns(filters = {}) {
|
|
139
234
|
return this.#evidence.listUnknowns(filters);
|
|
@@ -147,3 +242,4 @@ const sortedWorkspaces = (workspaces) => [...workspaces]
|
|
|
147
242
|
.sort((left, right) => left.workspace_id.localeCompare(right.workspace_id) ||
|
|
148
243
|
left.revision - right.revision)
|
|
149
244
|
.map((workspace) => structuredClone(workspace));
|
|
245
|
+
import { createHash } from "node:crypto";
|
|
@@ -1,14 +1,20 @@
|
|
|
1
1
|
/** Project internal provider routing state into the caller-visible session status. */
|
|
2
|
-
export const binarySessionStatus = ({ target, route, router,
|
|
2
|
+
export const binarySessionStatus = ({ target, route, router, runtimeUnavailability, runId, runtimeLineageSnapshots, requestActivitySnapshots, }) => {
|
|
3
3
|
const configuredProvider = router.configuredIdentity();
|
|
4
4
|
const provider = providerSummary(configuredProvider);
|
|
5
5
|
const providers = router.providerIdentities(route).map(providerSummary);
|
|
6
6
|
const capabilities = [...(route.capabilities?.values() ?? [])]
|
|
7
7
|
.sort((left, right) => left.operation.localeCompare(right.operation))
|
|
8
|
-
.map((descriptor) =>
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
8
|
+
.map((descriptor) => {
|
|
9
|
+
const unavailable = runtimeUnavailability.get(descriptor.operation);
|
|
10
|
+
return unavailable === undefined
|
|
11
|
+
? descriptor
|
|
12
|
+
: {
|
|
13
|
+
...descriptor,
|
|
14
|
+
available: false,
|
|
15
|
+
reason: unavailable.reason,
|
|
16
|
+
};
|
|
17
|
+
})
|
|
12
18
|
.map(capabilityStatus);
|
|
13
19
|
const analysisProviderBinding = route.binding === null
|
|
14
20
|
? null
|
|
@@ -21,9 +21,7 @@ export const createBrowserEvidence = (operation, input, result, provider) => cre
|
|
|
21
21
|
});
|
|
22
22
|
const browserParameters = (input) => {
|
|
23
23
|
if (!("cdp_endpoint" in input)) {
|
|
24
|
-
if ("before_scenario" in input
|
|
25
|
-
input.before_scenario !== undefined &&
|
|
26
|
-
input.after_scenario !== undefined)
|
|
24
|
+
if ("before_scenario" in input)
|
|
27
25
|
return {
|
|
28
26
|
comparison_kind: "browser_scenario",
|
|
29
27
|
before_browser: input.before_scenario.browser,
|
|
@@ -89,9 +87,9 @@ const browserParameters = (input) => {
|
|
|
89
87
|
include_storage_keys: input.include_storage_keys,
|
|
90
88
|
include_storage_fingerprints: input.include_storage_fingerprints,
|
|
91
89
|
limits: input.limits,
|
|
92
|
-
|
|
90
|
+
source_capture_approved: input.source_capture_approved,
|
|
91
|
+
...(input.include_script_sources && "analysis_limits" in input
|
|
93
92
|
? {
|
|
94
|
-
source_capture_approved: input.source_capture_approved,
|
|
95
93
|
fetch_source_maps: input.fetch_source_maps,
|
|
96
94
|
source_map_fetch_approved: input.source_map_fetch_approved,
|
|
97
95
|
analysis_limits: input.analysis_limits,
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/** Empty MCP client feature declaration used when the caller supplies none. */
|
|
2
|
+
export const NO_CLIENT_FEATURES = {
|
|
3
|
+
elicitation_form: false,
|
|
4
|
+
elicitation_url: false,
|
|
5
|
+
roots: false,
|
|
6
|
+
sampling: false,
|
|
7
|
+
};
|
|
8
|
+
const CLIENT_FEATURE_REQUIREMENTS = {
|
|
9
|
+
capture_process_scenario: {
|
|
10
|
+
required: [],
|
|
11
|
+
optional: ["elicitation_form"],
|
|
12
|
+
},
|
|
13
|
+
};
|
|
14
|
+
/** Project a tool's client requirements against the negotiated feature set. */
|
|
15
|
+
export const clientRequirementsFor = (name, clientFeatures) => {
|
|
16
|
+
const requirements = CLIENT_FEATURE_REQUIREMENTS[name] ?? {
|
|
17
|
+
required: [],
|
|
18
|
+
optional: [],
|
|
19
|
+
};
|
|
20
|
+
return {
|
|
21
|
+
required: [...requirements.required],
|
|
22
|
+
optional: [...requirements.optional],
|
|
23
|
+
missing_required: requirements.required.filter((feature) => !clientFeatures[feature]),
|
|
24
|
+
missing_optional: requirements.optional.filter((feature) => !clientFeatures[feature]),
|
|
25
|
+
};
|
|
26
|
+
};
|
|
@@ -1,28 +1,13 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
import {
|
|
2
|
+
import { providerCapability, } from "../contracts/toolOutputSchemaPrimitives.js";
|
|
3
|
+
import { GENERATED_MCP_TOOL_CATALOG } from "../generatedMcpToolCatalog.js";
|
|
4
|
+
import { clientRequirementsFor, NO_CLIENT_FEATURES, } from "./CapabilityClientRequirements.js";
|
|
3
5
|
const statusSchema = z.object({
|
|
4
6
|
open: z.boolean(),
|
|
5
7
|
kind: z.enum(["executable", "database", "archive", "artifact"]).optional(),
|
|
6
8
|
format: z.string().optional(),
|
|
7
|
-
capabilities: z.array(
|
|
8
|
-
operation: z.string(),
|
|
9
|
-
available: z.boolean(),
|
|
10
|
-
reason: z.string().nullable(),
|
|
11
|
-
availability_code: z.string().nullable().optional(),
|
|
12
|
-
})),
|
|
9
|
+
capabilities: z.array(providerCapability),
|
|
13
10
|
});
|
|
14
|
-
const NO_CLIENT_FEATURES = {
|
|
15
|
-
elicitation_form: false,
|
|
16
|
-
elicitation_url: false,
|
|
17
|
-
roots: false,
|
|
18
|
-
sampling: false,
|
|
19
|
-
};
|
|
20
|
-
const CLIENT_FEATURE_REQUIREMENTS = {
|
|
21
|
-
capture_process_scenario: {
|
|
22
|
-
required: [],
|
|
23
|
-
optional: ["elicitation_form"],
|
|
24
|
-
},
|
|
25
|
-
};
|
|
26
11
|
const ENHANCED_REQUIREMENTS = {
|
|
27
12
|
swift_classes: ["list_procedures"],
|
|
28
13
|
get_objc_classes: ["list_names"],
|
|
@@ -38,6 +23,7 @@ const ENHANCED_REQUIREMENTS = {
|
|
|
38
23
|
"list_strings",
|
|
39
24
|
],
|
|
40
25
|
analyze_function: ["analyze_function"],
|
|
26
|
+
inspect_native_api: ["analyze_function"],
|
|
41
27
|
trace_feature: [
|
|
42
28
|
"list_strings",
|
|
43
29
|
"list_procedures",
|
|
@@ -45,18 +31,25 @@ const ENHANCED_REQUIREMENTS = {
|
|
|
45
31
|
"resolve_containing_procedure",
|
|
46
32
|
],
|
|
47
33
|
};
|
|
34
|
+
const NAVIGATION_CONTEXT_MODES = [
|
|
35
|
+
{
|
|
36
|
+
name: "current_selection",
|
|
37
|
+
requirements: [
|
|
38
|
+
"current_document",
|
|
39
|
+
"current_address",
|
|
40
|
+
"resolve_containing_procedure",
|
|
41
|
+
],
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
name: "explicit_document",
|
|
45
|
+
requirements: ["current_address", "resolve_containing_procedure"],
|
|
46
|
+
},
|
|
47
|
+
];
|
|
48
48
|
/** Build stable per-operation availability for discovery and tool visibility. */
|
|
49
49
|
export const buildCapabilityInventory = (sessionStatus, policy, clientFeatures = NO_CLIENT_FEATURES) => {
|
|
50
50
|
const status = statusSchema.parse(sessionStatus);
|
|
51
|
-
const descriptors = new Map(status.capabilities.map((descriptor) => [
|
|
52
|
-
|
|
53
|
-
{
|
|
54
|
-
available: descriptor.available,
|
|
55
|
-
reason: descriptor.reason,
|
|
56
|
-
availability_code: descriptor.availability_code ?? null,
|
|
57
|
-
},
|
|
58
|
-
]));
|
|
59
|
-
return TOOL_CONTRACTS.map((contract) => {
|
|
51
|
+
const descriptors = new Map(status.capabilities.map((descriptor) => [descriptor.operation, descriptor]));
|
|
52
|
+
return GENERATED_MCP_TOOL_CATALOG.map((contract) => {
|
|
60
53
|
const availability = availabilityFor({
|
|
61
54
|
name: contract.name,
|
|
62
55
|
kind: contract.kind,
|
|
@@ -67,16 +60,15 @@ export const buildCapabilityInventory = (sessionStatus, policy, clientFeatures =
|
|
|
67
60
|
});
|
|
68
61
|
const clientRequirements = clientRequirementsFor(contract.name, clientFeatures);
|
|
69
62
|
const clientBlocked = clientRequirements.missing_required.length > 0;
|
|
70
|
-
|
|
63
|
+
const facts = {
|
|
71
64
|
name: contract.name,
|
|
72
65
|
surface: contract.kind,
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
: availability.remediation,
|
|
66
|
+
...(availability.defaultModeAvailable === undefined
|
|
67
|
+
? {}
|
|
68
|
+
: { default_mode_available: availability.defaultModeAvailable }),
|
|
69
|
+
...(availability.modes === undefined
|
|
70
|
+
? {}
|
|
71
|
+
: { modes: [...availability.modes] }),
|
|
80
72
|
client_requirements: clientRequirements,
|
|
81
73
|
effects: { ...contract.effects },
|
|
82
74
|
annotations: {
|
|
@@ -86,21 +78,31 @@ export const buildCapabilityInventory = (sessionStatus, policy, clientFeatures =
|
|
|
86
78
|
open_world: contract.annotations.openWorldHint ?? true,
|
|
87
79
|
},
|
|
88
80
|
};
|
|
81
|
+
if (clientBlocked)
|
|
82
|
+
return {
|
|
83
|
+
...facts,
|
|
84
|
+
available: false,
|
|
85
|
+
reason: "client_capability_missing",
|
|
86
|
+
remediation: `Use an MCP client that supports: ${clientRequirements.missing_required.join(", ")}.`,
|
|
87
|
+
};
|
|
88
|
+
return availability.reason === "available"
|
|
89
|
+
? {
|
|
90
|
+
...facts,
|
|
91
|
+
available: true,
|
|
92
|
+
reason: availability.reason,
|
|
93
|
+
remediation: null,
|
|
94
|
+
}
|
|
95
|
+
: {
|
|
96
|
+
...facts,
|
|
97
|
+
available: false,
|
|
98
|
+
reason: availability.reason,
|
|
99
|
+
remediation: availability.remediation,
|
|
100
|
+
};
|
|
89
101
|
}).sort((left, right) => left.name.localeCompare(right.name));
|
|
90
102
|
};
|
|
91
|
-
const clientRequirementsFor = (name, clientFeatures) => {
|
|
92
|
-
const requirements = CLIENT_FEATURE_REQUIREMENTS[name] ?? {
|
|
93
|
-
required: [],
|
|
94
|
-
optional: [],
|
|
95
|
-
};
|
|
96
|
-
return {
|
|
97
|
-
required: [...requirements.required],
|
|
98
|
-
optional: [...requirements.optional],
|
|
99
|
-
missing_required: requirements.required.filter((feature) => !clientFeatures[feature]),
|
|
100
|
-
missing_optional: requirements.optional.filter((feature) => !clientFeatures[feature]),
|
|
101
|
-
};
|
|
102
|
-
};
|
|
103
103
|
const availabilityFor = (context) => {
|
|
104
|
+
if (context.name === "get_navigation_context")
|
|
105
|
+
return navigationContextAvailability(context.descriptors);
|
|
104
106
|
const javascriptApplication = javascriptApplicationAvailability(context);
|
|
105
107
|
if (javascriptApplication !== null)
|
|
106
108
|
return javascriptApplication;
|
|
@@ -155,13 +157,9 @@ const policyAvailability = ({ name, kind, policy, }) => {
|
|
|
155
157
|
reason: "policy_disabled",
|
|
156
158
|
remediation: "Configure or grant an evidence_read root.",
|
|
157
159
|
};
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
: {
|
|
162
|
-
reason: "policy_disabled",
|
|
163
|
-
remediation: "Enable Electron observation and configure a loopback CDP endpoint and canonical file roots.",
|
|
164
|
-
};
|
|
160
|
+
const electron = electronPolicyAvailability(name, kind, policy);
|
|
161
|
+
if (electron !== null)
|
|
162
|
+
return electron;
|
|
165
163
|
if (kind === "runtime-provider")
|
|
166
164
|
return policy.v8InspectorObservationEnabled === true
|
|
167
165
|
? { reason: "available", remediation: null }
|
|
@@ -173,6 +171,23 @@ const policyAvailability = ({ name, kind, policy, }) => {
|
|
|
173
171
|
return { reason: "available", remediation: null };
|
|
174
172
|
return null;
|
|
175
173
|
};
|
|
174
|
+
const electronPolicyAvailability = (name, kind, policy) => {
|
|
175
|
+
if (kind !== "electron-provider")
|
|
176
|
+
return null;
|
|
177
|
+
if (name === "capture_electron_scenario")
|
|
178
|
+
return policy.electronAutomationEnabled === true
|
|
179
|
+
? { reason: "available", remediation: null }
|
|
180
|
+
: {
|
|
181
|
+
reason: "policy_disabled",
|
|
182
|
+
remediation: "Enable active Electron automation and configure exact executable and application roots.",
|
|
183
|
+
};
|
|
184
|
+
return policy.electronObservationEnabled === true
|
|
185
|
+
? { reason: "available", remediation: null }
|
|
186
|
+
: {
|
|
187
|
+
reason: "policy_disabled",
|
|
188
|
+
remediation: "Enable Electron observation and configure a loopback CDP endpoint and canonical file roots.",
|
|
189
|
+
};
|
|
190
|
+
};
|
|
176
191
|
const browserPolicyAvailability = (name, kind, policy) => {
|
|
177
192
|
if (name === "capture_browser_scenario")
|
|
178
193
|
return policy.browserScenarioEnabled === true
|
|
@@ -240,6 +255,9 @@ const composedAvailability = (name, descriptors) => {
|
|
|
240
255
|
reason: "provider_missing",
|
|
241
256
|
remediation: "No provider composition is declared for this operation.",
|
|
242
257
|
};
|
|
258
|
+
return composedAvailabilityFor(requirements, descriptors);
|
|
259
|
+
};
|
|
260
|
+
const composedAvailabilityFor = (requirements, descriptors) => {
|
|
243
261
|
const missing = requirements.find((operation) => !descriptors.has(operation));
|
|
244
262
|
if (missing !== undefined)
|
|
245
263
|
return {
|
|
@@ -258,3 +276,70 @@ const composedAvailability = (name, descriptors) => {
|
|
|
258
276
|
};
|
|
259
277
|
return { reason: "available", remediation: null };
|
|
260
278
|
};
|
|
279
|
+
const navigationContextAvailability = (descriptors) => {
|
|
280
|
+
const modeResults = NAVIGATION_CONTEXT_MODES.map((mode) => {
|
|
281
|
+
const availability = composedAvailabilityFor(mode.requirements, descriptors);
|
|
282
|
+
if (availability.reason === "available")
|
|
283
|
+
return {
|
|
284
|
+
name: mode.name,
|
|
285
|
+
available: true,
|
|
286
|
+
reason: availability.reason,
|
|
287
|
+
missing_operations: [],
|
|
288
|
+
remediation: null,
|
|
289
|
+
};
|
|
290
|
+
return {
|
|
291
|
+
name: mode.name,
|
|
292
|
+
available: false,
|
|
293
|
+
reason: availability.reason,
|
|
294
|
+
missing_operations: mode.requirements.filter((operation) => {
|
|
295
|
+
const descriptor = descriptors.get(operation);
|
|
296
|
+
return descriptor === undefined || descriptor.available === false;
|
|
297
|
+
}),
|
|
298
|
+
remediation: availability.remediation,
|
|
299
|
+
};
|
|
300
|
+
});
|
|
301
|
+
const modes = modeResults.map((mode) => mode.available
|
|
302
|
+
? {
|
|
303
|
+
name: mode.name,
|
|
304
|
+
available: true,
|
|
305
|
+
missing_operations: [],
|
|
306
|
+
remediation: null,
|
|
307
|
+
}
|
|
308
|
+
: {
|
|
309
|
+
name: mode.name,
|
|
310
|
+
available: false,
|
|
311
|
+
missing_operations: [...mode.missing_operations],
|
|
312
|
+
remediation: mode.remediation,
|
|
313
|
+
});
|
|
314
|
+
const availableMode = modeResults.find((mode) => mode.available);
|
|
315
|
+
const failures = modeResults.flatMap((mode) => mode.available ? [] : [mode]);
|
|
316
|
+
const failure = failures.sort((left, right) => navigationFailurePriority(left.reason) -
|
|
317
|
+
navigationFailurePriority(right.reason))[0];
|
|
318
|
+
const specificFailureRemediation = failure?.reason === "provider_missing" ? undefined : failure?.remediation;
|
|
319
|
+
const facts = {
|
|
320
|
+
defaultModeAvailable: modes[0]?.available ?? false,
|
|
321
|
+
modes,
|
|
322
|
+
};
|
|
323
|
+
if (availableMode !== undefined)
|
|
324
|
+
return { ...facts, reason: "available", remediation: null };
|
|
325
|
+
return {
|
|
326
|
+
...facts,
|
|
327
|
+
reason: failure?.reason ?? "provider_missing",
|
|
328
|
+
remediation: specificFailureRemediation ??
|
|
329
|
+
`Configure a provider for one of: ${modes
|
|
330
|
+
.flatMap((mode) => mode.missing_operations)
|
|
331
|
+
.join(", ")}.`,
|
|
332
|
+
};
|
|
333
|
+
};
|
|
334
|
+
const navigationFailurePriority = (reason) => {
|
|
335
|
+
switch (reason) {
|
|
336
|
+
case "unsupported_host":
|
|
337
|
+
return 0;
|
|
338
|
+
case "provider_unavailable":
|
|
339
|
+
return 1;
|
|
340
|
+
case "provider_missing":
|
|
341
|
+
return 2;
|
|
342
|
+
default:
|
|
343
|
+
return 3;
|
|
344
|
+
}
|
|
345
|
+
};
|
|
@@ -3,6 +3,7 @@ import { resolve } from "node:path";
|
|
|
3
3
|
import { parse as parseToml } from "smol-toml";
|
|
4
4
|
import { z } from "zod";
|
|
5
5
|
import { PRODUCT_IDENTITY } from "../identity.js";
|
|
6
|
+
import { MCP_STARTUP_POLICY } from "../mcpStartupPolicy.js";
|
|
6
7
|
import { supportedClients } from "./SupportedClients.js";
|
|
7
8
|
const objectSchema = z.record(z.string(), z.unknown());
|
|
8
9
|
const registrationSchema = z
|
|
@@ -41,7 +42,9 @@ export const readClientRegistrationStatuses = async (home, currentCommandPath =
|
|
|
41
42
|
};
|
|
42
43
|
const registrationAligned = (registration, client, currentCommandPath) => {
|
|
43
44
|
const command = [registration.command, ...registration.args];
|
|
44
|
-
if (client === "codex" &&
|
|
45
|
+
if (client === "codex" &&
|
|
46
|
+
registration.startup_timeout_sec !==
|
|
47
|
+
MCP_STARTUP_POLICY.codexStartupTimeoutSeconds)
|
|
45
48
|
return false;
|
|
46
49
|
if (command.length === 4 &&
|
|
47
50
|
command[0] === "npx" &&
|
|
@@ -6,6 +6,7 @@ import { err, ok } from "../domain/result.js";
|
|
|
6
6
|
import { paginateArtifactInventory, } from "./ArtifactInventory.js";
|
|
7
7
|
import { scanAuthorizedArtifactInventory } from "./AuthorizedArtifactInventory.js";
|
|
8
8
|
import { ARTIFACT_GRAPH_PROVIDER } from "./InvestigationProviders.js";
|
|
9
|
+
import { resolveArtifactIntegrityPolicy } from "./ArtifactInventory/policy.js";
|
|
9
10
|
export const AUTOMATIC_RUN_LIMITATION = "Automatic cross-version runs compare shipped artifact structure only; they do not execute either version.";
|
|
10
11
|
/** Start both independent version scans while preserving left/right identity. */
|
|
11
12
|
export const scanVersionInventories = async (options, scanner = scanAuthorizedArtifactInventory) => {
|
|
@@ -27,12 +28,12 @@ export const scanVersions = async (input, inputRoots, signal, integrityContinueE
|
|
|
27
28
|
if (signal?.aborted === true)
|
|
28
29
|
return err(new AnalysisCancelledError("find_changed_behavior"));
|
|
29
30
|
const limits = artifactLimits(input.options);
|
|
30
|
-
const integrity =
|
|
31
|
-
mode:
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
31
|
+
const integrity = resolveArtifactIntegrityPolicy(input.integrity_policy === "fail"
|
|
32
|
+
? { mode: "fail" }
|
|
33
|
+
: {
|
|
34
|
+
mode: input.integrity_policy,
|
|
35
|
+
maxMismatches: input.max_integrity_mismatches,
|
|
36
|
+
}, integrityContinueEnabled);
|
|
36
37
|
return ok(await scanVersionInventories({
|
|
37
38
|
leftPath: input.left_path,
|
|
38
39
|
rightPath: input.right_path,
|
|
@@ -182,6 +182,7 @@ const executeAnalysisTool = async (input) => {
|
|
|
182
182
|
const { session, tool, signal, evidenceProfile } = input;
|
|
183
183
|
if (tool === "binary_overview" ||
|
|
184
184
|
tool === "analyze_function" ||
|
|
185
|
+
tool === "inspect_native_api" ||
|
|
185
186
|
tool === "trace_feature") {
|
|
186
187
|
const result = await new EnhancedTools(session).execute(tool, input.arguments, signal);
|
|
187
188
|
if (!result.ok)
|
|
@@ -247,15 +248,18 @@ const prepareSnapshot = async (options) => {
|
|
|
247
248
|
return err(new EvidenceIntegrityError("Analysis snapshot target does not match the requested binary"));
|
|
248
249
|
return ok({ snapshot: loaded.value });
|
|
249
250
|
};
|
|
250
|
-
const replayProviderFor = (session, tool) => tool
|
|
251
|
+
const replayProviderFor = (session, tool) => isWorkflowEvidenceTool(tool)
|
|
251
252
|
? REA_WORKFLOW_PROVIDER
|
|
252
253
|
: session.providerIdentity(tool);
|
|
253
254
|
const analysisProfileForEvidence = (session, tool) => {
|
|
254
|
-
if (tool
|
|
255
|
+
if (!isWorkflowEvidenceTool(tool))
|
|
255
256
|
return session.analysisProfile(tool);
|
|
256
257
|
const upstream = session.analysisProfile();
|
|
257
258
|
return upstream === undefined ? undefined : workflowAnalysisProfile(upstream);
|
|
258
259
|
};
|
|
260
|
+
const isWorkflowEvidenceTool = (tool) => tool === "binary_overview" ||
|
|
261
|
+
tool === "inspect_native_api" ||
|
|
262
|
+
tool === "trace_feature";
|
|
259
263
|
const fileExists = async (path) => {
|
|
260
264
|
try {
|
|
261
265
|
await access(path);
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { createEvidence } from "../domain/evidence.js";
|
|
2
|
+
import { jsonValueSchema } from "../domain/jsonValue.js";
|
|
3
|
+
import { digestJson } from "./JavaScriptReplayPlanning.js";
|
|
4
|
+
/** Create Evidence v2 without retaining arbitrary runtime argument values. */
|
|
5
|
+
export const createElectronActiveEvidence = (input, result, provider) => createEvidence(undefined, provider, {
|
|
6
|
+
predicateType: "rea.electron-active-scenario/v1",
|
|
7
|
+
operation: "capture_electron_scenario",
|
|
8
|
+
parameters: parameters(input),
|
|
9
|
+
result: jsonValueSchema.parse(result),
|
|
10
|
+
confidence: "observed",
|
|
11
|
+
authority: "controlled-replay",
|
|
12
|
+
environment: {
|
|
13
|
+
id: `${result.application.electron_version}@${process.platform}`,
|
|
14
|
+
platform: process.platform,
|
|
15
|
+
architecture: process.arch,
|
|
16
|
+
isolation: "none",
|
|
17
|
+
},
|
|
18
|
+
limitations: result.limitations,
|
|
19
|
+
});
|
|
20
|
+
const scenarioProjection = (input) => ({
|
|
21
|
+
approved: input.approved,
|
|
22
|
+
schema_version: input.schema_version,
|
|
23
|
+
executable_path: input.executable_path,
|
|
24
|
+
application_path: input.application_path,
|
|
25
|
+
application_root: input.application_root,
|
|
26
|
+
args: redactArguments(input.args),
|
|
27
|
+
actions: input.actions.map(({ step_id, kind }) => ({ step_id, kind })),
|
|
28
|
+
limits: input.limits,
|
|
29
|
+
});
|
|
30
|
+
const parameters = (input) => ({
|
|
31
|
+
...scenarioProjection(input),
|
|
32
|
+
scenario_sha256: digestJson(scenarioProjection(input)),
|
|
33
|
+
});
|
|
34
|
+
const redactArguments = (arguments_) => {
|
|
35
|
+
let redactNext = false;
|
|
36
|
+
return arguments_.map((argument) => {
|
|
37
|
+
if (redactNext) {
|
|
38
|
+
redactNext = false;
|
|
39
|
+
return "<redacted>";
|
|
40
|
+
}
|
|
41
|
+
if (sensitiveFlag.test(argument)) {
|
|
42
|
+
redactNext = true;
|
|
43
|
+
return argument;
|
|
44
|
+
}
|
|
45
|
+
return redactArgument(argument);
|
|
46
|
+
});
|
|
47
|
+
};
|
|
48
|
+
const sensitiveFlag = /^--?(?:password|token|secret|api[-_]?key|authorization|cookie)$/iu;
|
|
49
|
+
const redactArgument = (argument) => {
|
|
50
|
+
if (/^--?(?:password|token|secret|api[-_]?key|authorization|cookie)=/iu.test(argument))
|
|
51
|
+
return `${argument.slice(0, argument.indexOf("=") + 1)}<redacted>`;
|
|
52
|
+
return argument.length > 256
|
|
53
|
+
? `${argument.slice(0, 256)}<redacted>`
|
|
54
|
+
: argument;
|
|
55
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|