rea-agents 3.0.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 +14 -16
- package/dist/application/AnalysisContextQueries.js +21 -9
- 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 +14 -16
- package/dist/application/BinarySessionRecords.js +31 -5
- 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 +134 -63
- package/dist/application/CrossVersionInventory.js +7 -6
- 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 +22 -20
- package/dist/application/EvidenceBundleCommands.js +5 -1
- package/dist/application/EvidenceLedger.js +8 -1
- package/dist/application/JavaScriptReplayPermission.js +1 -1
- package/dist/application/JavaScriptReplayService.js +23 -15
- package/dist/application/ManagedRuntimeCorrelationService.js +9 -5
- 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/SetupClientConfiguration.js +6 -1
- package/dist/application/WindowsCapabilities.js +5 -4
- 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/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 +12 -6
- 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 +1 -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 +27 -34
- package/dist/contracts/browserToolContracts.js +2 -2
- package/dist/contracts/electronToolContracts.js +30 -1
- package/dist/contracts/enhancedInputs.js +13 -29
- package/dist/contracts/functionWorkflowToolContracts.js +2 -3
- 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/sessionToolSchemas.js +61 -0
- package/dist/contracts/toolContractExamples.js +1 -0
- package/dist/contracts/toolContractHelpers.js +23 -0
- package/dist/contracts/toolContracts.js +5 -77
- package/dist/contracts/toolEffects.js +15 -0
- package/dist/contracts/toolOutputSchemaGroups.js +17 -2
- package/dist/contracts/toolOutputSchemaPrimitives.js +76 -26
- package/dist/contracts/toolSchemaMetadata.js +128 -0
- package/dist/doctorRuntime.js +1 -1
- 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 +33 -35
- package/dist/domain/callPath.js +3 -2
- package/dist/domain/conformanceReplay.js +3 -3
- package/dist/domain/conformanceTrustGate.js +151 -16
- package/dist/domain/customProtocolCapture.js +3 -3
- 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 +82 -79
- package/dist/domain/functionComparisonNormalization.js +15 -8
- package/dist/domain/functionDossierEvidence.js +9 -4
- package/dist/domain/hopperValues.js +68 -71
- package/dist/domain/inputIssueProjection.js +4 -1
- 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/knownPageCoverage.js +15 -7
- package/dist/domain/nativeApiBoundary.js +15 -7
- package/dist/domain/nodeRuntimeCharacterization.js +14 -13
- 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 +8 -6
- 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/generatedMcpToolCatalog.js +1 -1
- package/dist/generatedPackageMetadata.js +1 -1
- package/dist/ghidra/GhidraClient.js +1 -1
- package/dist/ghidra/GhidraClientStartup.js +1 -1
- package/dist/ghidra/GhidraFunctionValues.js +17 -15
- package/dist/ghidra/GhidraInventoryValues.js +57 -47
- package/dist/ghidra/GhidraProvider.js +18 -10
- package/dist/ghidra/GhidraProviderCapabilities.js +5 -1
- 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 +1 -1
- package/dist/hopper/HopperProvider.js +0 -14
- package/dist/hopper/LinuxPrivateDisplayProbe.js +16 -10
- package/dist/main/reload.js +1 -6
- package/dist/main/state.js +0 -14
- package/dist/main/transport.js +30 -37
- package/dist/main.js +17 -15
- package/dist/mcpDoctor.js +2 -24
- 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 +158 -94
- 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 +114 -122
- package/dist/server/registerEvidenceTools.js +5 -9
- package/dist/server/registerFunctionComparisonTool.js +11 -15
- package/dist/server/registerInvestigationTools.js +41 -57
- 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/registerReplayMachineTool.js +4 -10
- package/dist/server/registerSessionRecordTools.js +69 -40
- package/dist/server/registerSessionStatusTool.js +13 -28
- package/dist/server/registerSessionTools.js +36 -52
- package/dist/server/sessionAvailabilityPolicy.js +2 -1
- package/dist/server/sessionToolPolicies.js +1 -5
- package/dist/server/toolRegistrationOptions.js +4 -192
- package/dist/server/toolResult.js +2 -18
- package/package.json +22 -14
- package/scripts/electron-active-hook-boundaries.cjs +394 -0
- package/scripts/electron-active-hook.cjs +501 -0
- package/scripts/rea.mjs +1 -11
- package/skills/reverse-engineer-anything/SKILL.md +2 -2
- package/dist/server/DynamicToolAvailability.js +0 -70
- package/dist/server/LazyToolCatalog.js +0 -134
- package/dist/server/hydrateServerTools.js +0 -191
- package/dist/server/toolInputValidation.js +0 -77
- package/scripts/package-runner-bootstrap.mjs +0 -72
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
import { realpath } from "node:fs/promises";
|
|
2
|
+
import { randomUUID } from "node:crypto";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
4
|
+
import { _electron as electron } from "playwright-core";
|
|
5
|
+
import { electronActiveObservationResultSchema, } from "../domain/electronActiveObservation.js";
|
|
6
|
+
import { AnalysisError, BrowserObservationError, ProviderAdapterError, } from "../domain/errors.js";
|
|
7
|
+
import { isPathContained } from "../domain/permissionPolicy.js";
|
|
8
|
+
import { err, ok } from "../domain/result.js";
|
|
9
|
+
import { cleanupOwnedProcessGroup, cleanupWindowsProcessTree, observeOwnedProcessLineage, selectCapturedProcessGroupIds, verifyNoTokenOwnedProcesses, } from "../process/ProcessOwnership.js";
|
|
10
|
+
import { runElectronActions, readApplicationState, runWithExecutionLimits, } from "./PlaywrightElectronActiveActions.js";
|
|
11
|
+
const OPERATION = "capture_electron_scenario";
|
|
12
|
+
/** Public identity for provider-owned Electron runtime experiments. */
|
|
13
|
+
export const PLAYWRIGHT_ELECTRON_ACTIVE_PROVIDER_IDENTITY = Object.freeze({
|
|
14
|
+
id: "rea-playwright-electron-active",
|
|
15
|
+
name: "REA Playwright active Electron observation provider",
|
|
16
|
+
version: "1",
|
|
17
|
+
});
|
|
18
|
+
const hookPath = fileURLToPath(new URL("../../scripts/electron-active-hook.cjs", import.meta.url));
|
|
19
|
+
const observableEventFamilies = [
|
|
20
|
+
"app-lifecycle",
|
|
21
|
+
"window-lifecycle",
|
|
22
|
+
"web-contents-lifecycle",
|
|
23
|
+
"navigation",
|
|
24
|
+
"shell-attempt",
|
|
25
|
+
"process-lifecycle",
|
|
26
|
+
"permission",
|
|
27
|
+
"popup-attempt",
|
|
28
|
+
"download",
|
|
29
|
+
"protocol",
|
|
30
|
+
"preload",
|
|
31
|
+
"preload-configuration",
|
|
32
|
+
"renderer-ipc",
|
|
33
|
+
"native-addon",
|
|
34
|
+
"updater",
|
|
35
|
+
"error",
|
|
36
|
+
"ipc",
|
|
37
|
+
];
|
|
38
|
+
const ipcEventKinds = new Set([
|
|
39
|
+
"main-handler-invocation",
|
|
40
|
+
"main-event-invocation",
|
|
41
|
+
"utility-process-fork",
|
|
42
|
+
"utility-process-message",
|
|
43
|
+
"ipc-main-to-renderer",
|
|
44
|
+
"ipc-utility-to-main",
|
|
45
|
+
"ipc-renderer-send",
|
|
46
|
+
"ipc-renderer-invoke",
|
|
47
|
+
"ipc-renderer-post-message",
|
|
48
|
+
]);
|
|
49
|
+
const createCoverage = (hookSnapshot) => {
|
|
50
|
+
const observedEventFamilies = [
|
|
51
|
+
...new Set(hookSnapshot.events.map(({ kind, process_type }) => {
|
|
52
|
+
if (kind === "preload" && process_type === "main")
|
|
53
|
+
return "preload-configuration";
|
|
54
|
+
if (kind.startsWith("ipc-renderer") && process_type !== "renderer")
|
|
55
|
+
return "ipc";
|
|
56
|
+
return ipcEventKinds.has(kind) ? "ipc" : kind;
|
|
57
|
+
})),
|
|
58
|
+
].sort();
|
|
59
|
+
const unavailableEventFamilies = new Set(observableEventFamilies.filter((family) => !observedEventFamilies.includes(family)));
|
|
60
|
+
const observedRoles = [
|
|
61
|
+
...new Set(hookSnapshot.events.flatMap(({ process_type, kind }) => [
|
|
62
|
+
...(process_type === null ? [] : [process_type]),
|
|
63
|
+
...(kind === "window-lifecycle" ? ["window"] : []),
|
|
64
|
+
...(kind === "web-contents-lifecycle" || kind === "navigation"
|
|
65
|
+
? ["web_contents"]
|
|
66
|
+
: []),
|
|
67
|
+
...(kind === "preload" && process_type === "preload"
|
|
68
|
+
? ["preload"]
|
|
69
|
+
: []),
|
|
70
|
+
...(kind.startsWith("ipc-renderer") && process_type === "renderer"
|
|
71
|
+
? ["renderer"]
|
|
72
|
+
: []),
|
|
73
|
+
])),
|
|
74
|
+
].sort();
|
|
75
|
+
const rendererContextObserved = hookSnapshot.events.some(({ process_type }) => process_type === "renderer" || process_type === "preload");
|
|
76
|
+
if (!rendererContextObserved) {
|
|
77
|
+
unavailableEventFamilies.add("preload");
|
|
78
|
+
unavailableEventFamilies.add("renderer-ipc");
|
|
79
|
+
}
|
|
80
|
+
return {
|
|
81
|
+
status: hookSnapshot.hook_error
|
|
82
|
+
? "hook_conflict"
|
|
83
|
+
: hookSnapshot.truncated
|
|
84
|
+
? "capture_truncated"
|
|
85
|
+
: "partial_attach",
|
|
86
|
+
observed_event_families: observedEventFamilies,
|
|
87
|
+
unavailable_event_families: [...unavailableEventFamilies].sort(),
|
|
88
|
+
observed_roles: observedRoles,
|
|
89
|
+
pre_capture_activity: "unavailable",
|
|
90
|
+
};
|
|
91
|
+
};
|
|
92
|
+
/** Launch an owned Electron application through the official Playwright API. */
|
|
93
|
+
export class PlaywrightElectronActiveProvider {
|
|
94
|
+
identity() {
|
|
95
|
+
return PLAYWRIGHT_ELECTRON_ACTIVE_PROVIDER_IDENTITY;
|
|
96
|
+
}
|
|
97
|
+
async capture(input, options = {}) {
|
|
98
|
+
let application;
|
|
99
|
+
let ownership;
|
|
100
|
+
let lineage;
|
|
101
|
+
let outcome;
|
|
102
|
+
const runId = randomUUID();
|
|
103
|
+
try {
|
|
104
|
+
if (options.signal?.aborted === true)
|
|
105
|
+
throw new BrowserObservationError(OPERATION, "cancelled");
|
|
106
|
+
const deadline = Date.now() + input.limits.max_duration_ms;
|
|
107
|
+
const paths = await canonicalPaths(input);
|
|
108
|
+
application = await electron.launch({
|
|
109
|
+
executablePath: paths.executable,
|
|
110
|
+
cwd: paths.root,
|
|
111
|
+
env: safeElectronEnvironment(input.limits.max_ipc_events, input.limits.max_runtime_events, runId),
|
|
112
|
+
args: ["-r", hookPath, paths.application, ...input.args],
|
|
113
|
+
timeout: Math.max(1, deadline - Date.now()),
|
|
114
|
+
});
|
|
115
|
+
const leaderPid = application.process().pid;
|
|
116
|
+
if (typeof leaderPid !== "number" ||
|
|
117
|
+
!Number.isSafeInteger(leaderPid) ||
|
|
118
|
+
leaderPid <= 0)
|
|
119
|
+
throw new BrowserObservationError(OPERATION, "process_ownership_unavailable");
|
|
120
|
+
ownership = {
|
|
121
|
+
runId,
|
|
122
|
+
leaderPid,
|
|
123
|
+
processGroupId: leaderPid,
|
|
124
|
+
expectedParentPid: process.pid,
|
|
125
|
+
expectedCommand: paths.executable,
|
|
126
|
+
sweepTokenOwnedProcesses: true,
|
|
127
|
+
};
|
|
128
|
+
const actions = await runElectronActions(application, input, options, deadline);
|
|
129
|
+
const state = await runWithExecutionLimits(readApplicationState(application, input.limits.max_windows), options.signal, deadline);
|
|
130
|
+
outcome = ok(createResult(paths, input, actions, state));
|
|
131
|
+
}
|
|
132
|
+
catch (cause) {
|
|
133
|
+
outcome = err(providerError(cause));
|
|
134
|
+
}
|
|
135
|
+
if (application !== undefined) {
|
|
136
|
+
if (ownership !== undefined)
|
|
137
|
+
lineage = await observeOwnedProcessLineage(ownership);
|
|
138
|
+
let closeError;
|
|
139
|
+
try {
|
|
140
|
+
await runWithExecutionLimits(application.close(), undefined, Date.now() + 5_000);
|
|
141
|
+
}
|
|
142
|
+
catch (cause) {
|
|
143
|
+
closeError = cause;
|
|
144
|
+
}
|
|
145
|
+
const cleanup = ownership === undefined
|
|
146
|
+
? {
|
|
147
|
+
cleaned: false,
|
|
148
|
+
reason: "owned Electron process identity was unavailable",
|
|
149
|
+
}
|
|
150
|
+
: await cleanupElectronProcesses(ownership, lineage);
|
|
151
|
+
if (!cleanup.cleaned)
|
|
152
|
+
return err(providerError(new BrowserObservationError(OPERATION, "cleanup_failed", {
|
|
153
|
+
cause: new Error(cleanup.reason),
|
|
154
|
+
})));
|
|
155
|
+
if (closeError !== undefined)
|
|
156
|
+
return err(providerError(closeError));
|
|
157
|
+
}
|
|
158
|
+
return outcome;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
const cleanupElectronProcesses = async (ownership, lineage) => {
|
|
162
|
+
if (process.platform === "win32") {
|
|
163
|
+
const root = await cleanupWindowsProcessTree(ownership.leaderPid);
|
|
164
|
+
if (!root.cleaned)
|
|
165
|
+
return root;
|
|
166
|
+
if (lineage?.status !== "verified")
|
|
167
|
+
return {
|
|
168
|
+
cleaned: false,
|
|
169
|
+
reason: "owned Electron lineage was unavailable; helper cleanup was not proven",
|
|
170
|
+
};
|
|
171
|
+
for (const descendant of lineage.lineage.descendants) {
|
|
172
|
+
const result = await cleanupWindowsProcessTree(descendant.pid);
|
|
173
|
+
if (!result.cleaned)
|
|
174
|
+
return result;
|
|
175
|
+
}
|
|
176
|
+
return root;
|
|
177
|
+
}
|
|
178
|
+
if (lineage?.status !== "verified") {
|
|
179
|
+
const root = await cleanupOwnedProcessGroup(ownership);
|
|
180
|
+
return root.cleaned
|
|
181
|
+
? {
|
|
182
|
+
cleaned: false,
|
|
183
|
+
reason: "owned Electron lineage was unavailable; helper cleanup was not proven",
|
|
184
|
+
}
|
|
185
|
+
: root;
|
|
186
|
+
}
|
|
187
|
+
const groupIds = selectCapturedProcessGroupIds(ownership.leaderPid, lineage.lineage.descendants.map(({ pid, processGroupId }) => ({
|
|
188
|
+
pid,
|
|
189
|
+
process_group_id: processGroupId,
|
|
190
|
+
})));
|
|
191
|
+
let signaled = false;
|
|
192
|
+
for (const processGroupId of groupIds) {
|
|
193
|
+
const cleanupOwnership = processGroupId === ownership.processGroupId
|
|
194
|
+
? { ...ownership, leaderPid: processGroupId, processGroupId }
|
|
195
|
+
: {
|
|
196
|
+
runId: ownership.runId,
|
|
197
|
+
leaderPid: processGroupId,
|
|
198
|
+
processGroupId,
|
|
199
|
+
};
|
|
200
|
+
const result = await cleanupOwnedProcessGroup(cleanupOwnership);
|
|
201
|
+
if (!result.cleaned)
|
|
202
|
+
return result;
|
|
203
|
+
signaled ||= result.signaled;
|
|
204
|
+
}
|
|
205
|
+
const remaining = await verifyNoTokenOwnedProcesses(ownership.runId);
|
|
206
|
+
if (!remaining.cleaned)
|
|
207
|
+
return remaining;
|
|
208
|
+
return { cleaned: true, signaled };
|
|
209
|
+
};
|
|
210
|
+
const createResult = (paths, input, actions, state) => {
|
|
211
|
+
const { hookSnapshot } = state;
|
|
212
|
+
const ipcEvents = hookSnapshot.events.filter(({ kind }) => ipcEventKinds.has(kind));
|
|
213
|
+
return electronActiveObservationResultSchema.parse({
|
|
214
|
+
schema_version: 1,
|
|
215
|
+
application: {
|
|
216
|
+
executable_path: paths.executable,
|
|
217
|
+
application_path: paths.application,
|
|
218
|
+
electron_version: state.electronVersion,
|
|
219
|
+
process_ownership: "provider-owned",
|
|
220
|
+
cleanup: "terminated-owned-process",
|
|
221
|
+
},
|
|
222
|
+
actions,
|
|
223
|
+
windows: state.windows.slice(0, input.limits.max_windows),
|
|
224
|
+
windows_truncated: state.windowsTruncated,
|
|
225
|
+
processes: {
|
|
226
|
+
items: state.metrics.slice(0, input.limits.max_processes),
|
|
227
|
+
truncated: state.metrics.length > input.limits.max_processes,
|
|
228
|
+
},
|
|
229
|
+
ipc: {
|
|
230
|
+
events: ipcEvents.slice(0, input.limits.max_ipc_events),
|
|
231
|
+
observed: hookSnapshot.observed_ipc,
|
|
232
|
+
retained: Math.min(ipcEvents.length, input.limits.max_ipc_events),
|
|
233
|
+
truncated: hookSnapshot.truncated ||
|
|
234
|
+
ipcEvents.length > input.limits.max_ipc_events,
|
|
235
|
+
},
|
|
236
|
+
timeline: {
|
|
237
|
+
events: hookSnapshot.events.slice(0, input.limits.max_runtime_events),
|
|
238
|
+
observed: hookSnapshot.observed,
|
|
239
|
+
retained: Math.min(hookSnapshot.events.length, input.limits.max_runtime_events),
|
|
240
|
+
truncated: hookSnapshot.truncated ||
|
|
241
|
+
hookSnapshot.events.length > input.limits.max_runtime_events,
|
|
242
|
+
},
|
|
243
|
+
coverage: createCoverage(hookSnapshot),
|
|
244
|
+
limitations: [
|
|
245
|
+
"IPC payloads are represented only by bounded value shapes; values are never retained, channels are capped at 1,024 characters, and argument-shape arrays at 32 entries.",
|
|
246
|
+
"IPC direction and sender/receiver identifiers are observed only where Electron exposes them at the hooked boundary.",
|
|
247
|
+
"The runtime timeline records bounded lifecycle, navigation, shell, permission, popup, download, protocol, preload, native-addon, process, and IPC events; activity before hook installation is unavailable.",
|
|
248
|
+
"The preload and renderer process contexts are not instrumented by the main-process -r hook; preload configuration and contextBridge API-shape events are main-boundary observations, not proof of renderer-side execution.",
|
|
249
|
+
"Process metrics are an Electron API snapshot and do not prove hostile-local-user isolation.",
|
|
250
|
+
"External shell opens, external navigation, permission grants, downloads, popup windows, updater relaunches, and OS integration are blocked and recorded by the active hook; other application filesystem and network behavior is not sandboxed by this provider.",
|
|
251
|
+
...(state.windowsTruncated
|
|
252
|
+
? ["Windows beyond max_windows were not retained."]
|
|
253
|
+
: []),
|
|
254
|
+
...(hookSnapshot.hook_error
|
|
255
|
+
? ["The active IPC hook could not be installed."]
|
|
256
|
+
: []),
|
|
257
|
+
],
|
|
258
|
+
});
|
|
259
|
+
};
|
|
260
|
+
const canonicalPaths = async (input) => {
|
|
261
|
+
const [executable, application, root] = await Promise.all([
|
|
262
|
+
realpath(input.executable_path),
|
|
263
|
+
realpath(input.application_path),
|
|
264
|
+
realpath(input.application_root),
|
|
265
|
+
]);
|
|
266
|
+
if (!isPathContained(root, application))
|
|
267
|
+
throw new BrowserObservationError(OPERATION, "target_not_allowed");
|
|
268
|
+
return { executable, application, root };
|
|
269
|
+
};
|
|
270
|
+
const safeElectronEnvironment = (maxIpcEvents, maxRuntimeEvents, runId) => Object.fromEntries([
|
|
271
|
+
...[
|
|
272
|
+
"HOME",
|
|
273
|
+
"LANG",
|
|
274
|
+
"PATH",
|
|
275
|
+
"TMP",
|
|
276
|
+
"TMPDIR",
|
|
277
|
+
"USER",
|
|
278
|
+
"DISPLAY",
|
|
279
|
+
"WAYLAND_DISPLAY",
|
|
280
|
+
]
|
|
281
|
+
.map((name) => [name, process.env[name]])
|
|
282
|
+
.filter((entry) => entry[1] !== undefined),
|
|
283
|
+
["REA_ELECTRON_ACTIVE_MAX_IPC_EVENTS", String(maxIpcEvents)],
|
|
284
|
+
[
|
|
285
|
+
"REA_ELECTRON_ACTIVE_MAX_RUNTIME_EVENTS",
|
|
286
|
+
String(maxRuntimeEvents),
|
|
287
|
+
],
|
|
288
|
+
["REA_PROCESS_RUN_ID", runId],
|
|
289
|
+
]);
|
|
290
|
+
const providerError = (cause) => cause instanceof AnalysisError
|
|
291
|
+
? cause
|
|
292
|
+
: new ProviderAdapterError(PLAYWRIGHT_ELECTRON_ACTIVE_PROVIDER_IDENTITY.id, OPERATION, {
|
|
293
|
+
cause,
|
|
294
|
+
});
|
|
@@ -89,9 +89,9 @@ export const openPlaywrightScenarioBrowser = async (scenario, environment, maxim
|
|
|
89
89
|
await configureAttachedEnvironment(target.context, target.page, scenario);
|
|
90
90
|
return { ...target, browser, profilePath: undefined };
|
|
91
91
|
}
|
|
92
|
-
catch (
|
|
92
|
+
catch (cause) {
|
|
93
93
|
await browser.close();
|
|
94
|
-
throw
|
|
94
|
+
throw cause;
|
|
95
95
|
}
|
|
96
96
|
}
|
|
97
97
|
const profilePath = await mkdtemp(join(tmpdir(), "rea-browser-scenario-"));
|
|
@@ -125,9 +125,9 @@ export const openPlaywrightScenarioBrowser = async (scenario, environment, maxim
|
|
|
125
125
|
const page = context.pages()[0] ?? (await context.newPage());
|
|
126
126
|
return { context, page, browser, profilePath };
|
|
127
127
|
}
|
|
128
|
-
catch (
|
|
128
|
+
catch (cause) {
|
|
129
129
|
await rm(profilePath, { recursive: true, force: true, maxRetries: 3 });
|
|
130
|
-
throw
|
|
130
|
+
throw cause;
|
|
131
131
|
}
|
|
132
132
|
};
|
|
133
133
|
export const closePlaywrightScenarioBrowser = async ({ context, browser, profilePath, }) => {
|
|
@@ -201,11 +201,11 @@ export class PlaywrightScenarioSession {
|
|
|
201
201
|
try {
|
|
202
202
|
opened = await withPlaywrightExecutionBoundary(() => opening, remaining(), options.signal);
|
|
203
203
|
}
|
|
204
|
-
catch (
|
|
204
|
+
catch (cause) {
|
|
205
205
|
void opening
|
|
206
206
|
.then((lateOpened) => closePlaywrightScenarioBrowser(lateOpened))
|
|
207
207
|
.catch(() => undefined);
|
|
208
|
-
throw
|
|
208
|
+
throw cause;
|
|
209
209
|
}
|
|
210
210
|
try {
|
|
211
211
|
await withPlaywrightExecutionBoundary(() => initializePage(opened.context, opened.page, scenario, secrets), remaining(), options.signal);
|
|
@@ -224,9 +224,9 @@ export class PlaywrightScenarioSession {
|
|
|
224
224
|
}), remaining(), options.signal);
|
|
225
225
|
return session;
|
|
226
226
|
}
|
|
227
|
-
catch (
|
|
227
|
+
catch (cause) {
|
|
228
228
|
await closePlaywrightScenarioBrowser(opened);
|
|
229
|
-
throw
|
|
229
|
+
throw cause;
|
|
230
230
|
}
|
|
231
231
|
}
|
|
232
232
|
currentUrl() {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const SECRET_ASSIGNMENT = /\b(authorization|api[_-]?key|access[_-]?token|refresh[_-]?token|password|passwd|secret|cookie|session)\b\s*[:=]\s*(?:Bearer\s+[A-Za-z0-9._~+/=-]+|"[^"]*"|'[^']*'|[^\s,;]+)/giu;
|
|
1
|
+
const SECRET_ASSIGNMENT = /\b(authorization|api[_-]?key|access[_-]?token|refresh[_-]?token|token|password|passwd|secret|cookie|session)\b\s*[:=]\s*(?:Bearer\s+[A-Za-z0-9._~+/=-]+|"[^"]*"|'[^']*'|[^\s,;]+)/giu;
|
|
2
2
|
const BEARER = /\bBearer\s+[A-Za-z0-9._~+/=-]+/giu;
|
|
3
3
|
const JWT = /\beyJ[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\b/gu;
|
|
4
4
|
/** Redact credential-shaped substrings before approved console text is retained. */
|
|
@@ -11,6 +11,7 @@ export const describeInspectorTargetLimitations = () => [
|
|
|
11
11
|
"REA attaches to an already-running exact target and never launches, resumes, evaluates, pauses, or mutates it.",
|
|
12
12
|
"Only Runtime.enable and Debugger.enable are sent; source text, object values, EventEmitter activity, and Electron IPC are not inspected.",
|
|
13
13
|
"Target IDs and locations are authorized, but the Inspector protocol does not authenticate an operating-system process ID or Electron role.",
|
|
14
|
+
"Some Electron main targets report only file://; for those targets, the first approved file root is recorded as a scope fallback and script locations are authorized independently.",
|
|
14
15
|
"No runtime graph depth is traversed because passive Inspector events do not establish require/import caller edges.",
|
|
15
16
|
];
|
|
16
17
|
/** Canonically authorize, deduplicate, and sort one bounded raw capture. */
|
|
@@ -3,7 +3,7 @@ import { AnalysisError, BrowserObservationError, ProviderAdapterError, } from ".
|
|
|
3
3
|
import { err, ok } from "../domain/result.js";
|
|
4
4
|
import { boundedText, numberValue, recordValue, stringValue, delayWithCancellation, } from "./CdpCaptureValues.js";
|
|
5
5
|
import { CdpConnection } from "./CdpConnection.js";
|
|
6
|
-
import {
|
|
6
|
+
import { authorizeRuntimeTargetLocation, canonicalRuntimeRoots, } from "./JavaScriptRuntimeScope.js";
|
|
7
7
|
import { createInspectorExclusionCounts, describeInspectorTargetLimitations, finalizeInspectorCapture, } from "./V8InspectorCaptureProjection.js";
|
|
8
8
|
import { discoverV8Inspector, } from "./V8InspectorEndpoint.js";
|
|
9
9
|
/** Public identity committed by passive V8 Inspector observations. */
|
|
@@ -24,7 +24,7 @@ export class V8InspectorProvider {
|
|
|
24
24
|
const allowed = [];
|
|
25
25
|
const excluded = createInspectorExclusionCounts();
|
|
26
26
|
for (const target of discovery.targets) {
|
|
27
|
-
const decision = await
|
|
27
|
+
const decision = await authorizeRuntimeTargetLocation(target.url, target.type, roots, input.allowed_origins);
|
|
28
28
|
if (!decision.allowed) {
|
|
29
29
|
excluded[decision.reason] += 1;
|
|
30
30
|
continue;
|
|
@@ -104,7 +104,7 @@ const authorizedTarget = async (targets, input, roots) => {
|
|
|
104
104
|
const target = targets.find(({ id }) => id === input.target_id);
|
|
105
105
|
if (target === undefined)
|
|
106
106
|
throw new BrowserObservationError("observe_javascript_runtime", "target_not_found");
|
|
107
|
-
const decision = await
|
|
107
|
+
const decision = await authorizeRuntimeTargetLocation(target.url, target.type, roots, input.allowed_origins);
|
|
108
108
|
if (target.attached ||
|
|
109
109
|
!decision.allowed ||
|
|
110
110
|
decision.location.kind === "builtin")
|
package/dist/catalogIdentity.js
CHANGED
|
@@ -12,12 +12,18 @@ const toolCatalog = TOOL_CONTRACTS.map((contract) => ({
|
|
|
12
12
|
description: contract.description,
|
|
13
13
|
effects: { ...contract.effects },
|
|
14
14
|
annotations: contract.annotations,
|
|
15
|
-
input_schema:
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
}
|
|
15
|
+
input_schema: {
|
|
16
|
+
type: "object",
|
|
17
|
+
...z.toJSONSchema(contract.inputSchema, {
|
|
18
|
+
unrepresentable: "any",
|
|
19
|
+
}),
|
|
20
|
+
},
|
|
21
|
+
output_schema: {
|
|
22
|
+
type: "object",
|
|
23
|
+
...z.toJSONSchema(contract.outputSchema, {
|
|
24
|
+
unrepresentable: "any",
|
|
25
|
+
}),
|
|
26
|
+
},
|
|
21
27
|
})).sort((left, right) => left.name.localeCompare(right.name));
|
|
22
28
|
const promptCatalog = PROMPT_CONTRACTS.map((contract) => ({
|
|
23
29
|
name: contract.name,
|
|
@@ -388,7 +388,7 @@ const registerPlanManagedRuntimeCorrelation = (cli, logger) => {
|
|
|
388
388
|
if (!authority.ok)
|
|
389
389
|
return projectAnalysisError(authority.error);
|
|
390
390
|
const result = await planManagedRuntimeCorrelationEvidence({
|
|
391
|
-
policy: config.value.managedRuntimePolicy,
|
|
391
|
+
policy: () => config.value.managedRuntimePolicy,
|
|
392
392
|
authority: authority.value,
|
|
393
393
|
}, input.value);
|
|
394
394
|
return result.ok ? result.value : projectAnalysisError(result.error);
|
|
@@ -75,7 +75,7 @@ export const registerApplicationCommands = (cli, logger) => {
|
|
|
75
75
|
if (!authority.ok)
|
|
76
76
|
return projectAnalysisError(authority.error);
|
|
77
77
|
const result = await runControlledReplay({
|
|
78
|
-
policy: config.value.javascriptReplayPolicy,
|
|
78
|
+
policy: () => config.value.javascriptReplayPolicy,
|
|
79
79
|
host: new SystemJavaScriptReplayHost(),
|
|
80
80
|
runner: new LinuxJavaScriptReplayRunner(),
|
|
81
81
|
authority: authority.value,
|
|
@@ -193,7 +193,7 @@ const configuredAuthority = async () => {
|
|
|
193
193
|
: { ok: false, error: projectAnalysisError(configured.error) };
|
|
194
194
|
};
|
|
195
195
|
const replayDependencies = (config, authority) => ({
|
|
196
|
-
policy: config.javascriptReplayPolicy,
|
|
196
|
+
policy: () => config.javascriptReplayPolicy,
|
|
197
197
|
host: new SystemJavaScriptReplayHost(),
|
|
198
198
|
runner: new LinuxJavaScriptReplayRunner(),
|
|
199
199
|
authority,
|
|
@@ -4,7 +4,7 @@ import { loadConfiguredPermissionAuthority } from "./application/PermissionConfi
|
|
|
4
4
|
import { CdpBrowserProvider } from "./browser/CdpBrowserProvider.js";
|
|
5
5
|
import { logCliCommand } from "./cliLogging.js";
|
|
6
6
|
import { parseConfig } from "./config.js";
|
|
7
|
-
import { AnalysisInputError, projectAnalysisError } from "./domain/errors.js";
|
|
7
|
+
import { AnalysisCapabilityUnavailableError, AnalysisInputError, projectAnalysisError, } from "./domain/errors.js";
|
|
8
8
|
import { browserCaptureComparisonInputSchema } from "./domain/browserCaptureComparison.js";
|
|
9
9
|
import { discoverWebMcpToolsInputSchema } from "./domain/webMcpDiscovery.js";
|
|
10
10
|
import { captureWebScreenshotInputSchema, compareWebScreenshotsInputSchema, } from "./domain/webScreenshot.js";
|
|
@@ -69,7 +69,7 @@ const registerWebMcp = (cli, logger) => {
|
|
|
69
69
|
.describe("Maximum nesting depth in one declared tool schema"),
|
|
70
70
|
}),
|
|
71
71
|
run: ({ args, options }) => logCliCommand(logger, "discover-webmcp-tools", async () => {
|
|
72
|
-
const context = await browserContext();
|
|
72
|
+
const context = await browserContext("discover_webmcp_tools");
|
|
73
73
|
if (!context.ok)
|
|
74
74
|
return context.error;
|
|
75
75
|
const parsed = discoverWebMcpToolsInputSchema.safeParse({
|
|
@@ -155,7 +155,7 @@ const registerScreenshot = (cli, logger) => {
|
|
|
155
155
|
.describe("Maximum captured PNG size"),
|
|
156
156
|
}),
|
|
157
157
|
run: ({ args, options }) => logCliCommand(logger, "capture-web-screenshot", async () => {
|
|
158
|
-
const context = await browserContext();
|
|
158
|
+
const context = await browserContext("capture_web_screenshot");
|
|
159
159
|
if (!context.ok)
|
|
160
160
|
return context.error;
|
|
161
161
|
const parsed = captureWebScreenshotInputSchema.safeParse({
|
|
@@ -210,10 +210,16 @@ const registerScreenshotDiff = (cli, logger) => {
|
|
|
210
210
|
}),
|
|
211
211
|
});
|
|
212
212
|
};
|
|
213
|
-
const browserContext = async () => {
|
|
213
|
+
const browserContext = async (operation) => {
|
|
214
214
|
const config = parseConfig(process.env);
|
|
215
215
|
if (!config.ok)
|
|
216
216
|
return { ok: false, error: cliError(config.error) };
|
|
217
|
+
const policy = config.value.browserObservationPolicy;
|
|
218
|
+
if (policy.status === "disabled")
|
|
219
|
+
return {
|
|
220
|
+
ok: false,
|
|
221
|
+
error: cliError(new AnalysisCapabilityUnavailableError("rea-cdp-browser", operation, "browser observation is disabled; configure exact endpoints and origins before enabling it")),
|
|
222
|
+
};
|
|
217
223
|
const authority = await loadConfiguredPermissionAuthority(config.value);
|
|
218
224
|
if (!authority.ok)
|
|
219
225
|
return { ok: false, error: cliError(authority.error) };
|
|
@@ -221,7 +227,7 @@ const browserContext = async () => {
|
|
|
221
227
|
ok: true,
|
|
222
228
|
authority: authority.value,
|
|
223
229
|
provider: new CdpBrowserProvider(),
|
|
224
|
-
allowedBrowserOrigins:
|
|
230
|
+
allowedBrowserOrigins: policy.allowedOrigins,
|
|
225
231
|
};
|
|
226
232
|
};
|
|
227
233
|
const parseJson = (value) => {
|
|
@@ -7,7 +7,7 @@ import { parseConfig } from "./config.js";
|
|
|
7
7
|
import { inspectWebPageInputSchema, listBrowserTargetsInputSchema, } from "./domain/browserObservation.js";
|
|
8
8
|
import { analyzeWebBundleInputSchema } from "./domain/webBundleAnalysis.js";
|
|
9
9
|
import { observeWebSessionInputSchema } from "./domain/browserSession.js";
|
|
10
|
-
import { AnalysisInputError, projectAnalysisError } from "./domain/errors.js";
|
|
10
|
+
import { AnalysisCapabilityUnavailableError, AnalysisInputError, projectAnalysisError, } from "./domain/errors.js";
|
|
11
11
|
import { CLI_COMMANDS } from "./cliCommandNames.js";
|
|
12
12
|
import { browserPageInspectionOptions } from "./cliObservationOptions.js";
|
|
13
13
|
const browserScopeOptions = {
|
|
@@ -49,7 +49,7 @@ const registerTargetList = (cli, logger) => {
|
|
|
49
49
|
limit: boundedCount("browser targets to return", 200, 100),
|
|
50
50
|
}),
|
|
51
51
|
run: ({ args, options }) => logCliCommand(logger, "list-browser-targets", async () => {
|
|
52
|
-
const context = await browserContext();
|
|
52
|
+
const context = await browserContext("list_browser_targets");
|
|
53
53
|
if (!context.ok)
|
|
54
54
|
return context.error;
|
|
55
55
|
const parsed = listBrowserTargetsInputSchema.safeParse({
|
|
@@ -75,7 +75,7 @@ const registerPageInspection = (cli, logger) => {
|
|
|
75
75
|
}),
|
|
76
76
|
options: browserPageInspectionOptions,
|
|
77
77
|
run: ({ args, options }) => logCliCommand(logger, "inspect-web-page", async () => {
|
|
78
|
-
const context = await browserContext();
|
|
78
|
+
const context = await browserContext("inspect_web_page");
|
|
79
79
|
if (!context.ok)
|
|
80
80
|
return context.error;
|
|
81
81
|
const parsed = inspectWebPageInputSchema.safeParse({
|
|
@@ -92,6 +92,7 @@ const registerPageInspection = (cli, logger) => {
|
|
|
92
92
|
include_websocket_shapes: options.includeWebsocketShapes,
|
|
93
93
|
websocket_shape_approved: options.websocketShapeApproved,
|
|
94
94
|
include_script_sources: options.includeScriptSources,
|
|
95
|
+
source_capture_approved: options.sourceCaptureApproved,
|
|
95
96
|
include_storage_keys: options.includeStorageKeys,
|
|
96
97
|
include_storage_fingerprints: options.includeStorageFingerprints,
|
|
97
98
|
limits: {
|
|
@@ -157,7 +158,7 @@ const registerBundleAnalysis = (cli, logger) => {
|
|
|
157
158
|
maxOriginalSources: boundedCount("original source files", 20_000, 2_000),
|
|
158
159
|
}),
|
|
159
160
|
run: ({ args, options }) => logCliCommand(logger, "analyze-web-bundle", async () => {
|
|
160
|
-
const context = await browserContext();
|
|
161
|
+
const context = await browserContext("analyze_web_bundle");
|
|
161
162
|
if (!context.ok)
|
|
162
163
|
return context.error;
|
|
163
164
|
const parsed = analyzeWebBundleInputSchema.safeParse({
|
|
@@ -200,7 +201,7 @@ const registerObservationSession = (cli, logger) => {
|
|
|
200
201
|
maxTimelineEvents: boundedCount("timeline events", 20_000, 2_000),
|
|
201
202
|
}),
|
|
202
203
|
run: ({ args, options }) => logCliCommand(logger, "observe-web-session", async () => {
|
|
203
|
-
const context = await browserContext();
|
|
204
|
+
const context = await browserContext("observe_web_session");
|
|
204
205
|
if (!context.ok)
|
|
205
206
|
return context.error;
|
|
206
207
|
const parsed = observeWebSessionInputSchema.safeParse({
|
|
@@ -218,10 +219,16 @@ const registerObservationSession = (cli, logger) => {
|
|
|
218
219
|
}),
|
|
219
220
|
});
|
|
220
221
|
};
|
|
221
|
-
const browserContext = async () => {
|
|
222
|
+
const browserContext = async (operation) => {
|
|
222
223
|
const config = parseConfig(process.env);
|
|
223
224
|
if (!config.ok)
|
|
224
225
|
return { ok: false, error: cliError(config.error) };
|
|
226
|
+
const policy = config.value.browserObservationPolicy;
|
|
227
|
+
if (policy.status === "disabled")
|
|
228
|
+
return {
|
|
229
|
+
ok: false,
|
|
230
|
+
error: cliError(new AnalysisCapabilityUnavailableError("rea-cdp-browser", operation, "browser observation is disabled; configure exact endpoints and origins before enabling it")),
|
|
231
|
+
};
|
|
225
232
|
const authority = await loadConfiguredPermissionAuthority(config.value);
|
|
226
233
|
if (!authority.ok)
|
|
227
234
|
return { ok: false, error: cliError(authority.error) };
|
|
@@ -229,7 +236,7 @@ const browserContext = async () => {
|
|
|
229
236
|
ok: true,
|
|
230
237
|
authority: authority.value,
|
|
231
238
|
provider: new CdpBrowserProvider(),
|
|
232
|
-
allowedBrowserOrigins:
|
|
239
|
+
allowedBrowserOrigins: policy.allowedOrigins,
|
|
233
240
|
};
|
|
234
241
|
};
|
|
235
242
|
const cliError = (error) => ({
|
package/dist/cliCommandNames.js
CHANGED
|
@@ -50,6 +50,7 @@ export const CLI_COMMANDS = Object.freeze({
|
|
|
50
50
|
captureBrowserScenario: "capture-browser-scenario",
|
|
51
51
|
listElectronTargets: "list-electron-targets",
|
|
52
52
|
inspectElectronPage: "inspect-electron-page",
|
|
53
|
+
captureElectronScenario: "capture-electron-scenario",
|
|
53
54
|
listJavaScriptRuntimeTargets: "list-javascript-runtime-targets",
|
|
54
55
|
observeJavaScriptRuntime: "observe-javascript-runtime",
|
|
55
56
|
analyzeJavaScriptApplication: "analyze-javascript-application",
|