rea-agents 2.3.0 → 2.5.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 +80 -18
- package/bridge/ghidra/ReaGhidraBridge.java +48 -1
- package/bridge/hopper_bridge.py +259 -24
- package/dist/application/AnalysisClientCleanup.js +14 -0
- package/dist/application/ApplicationWorkflowEvidenceResolver.js +31 -13
- package/dist/application/ArtifactExtraction.js +5 -1
- package/dist/application/ArtifactGraphConstruction.js +3 -15
- package/dist/application/ArtifactInventory/classify.js +5 -1
- package/dist/application/ArtifactInventory/reader.js +2 -0
- package/dist/application/BinarySession.js +15 -4
- package/dist/application/BinarySessionStatus.js +32 -1
- package/dist/application/BrowserEvidence.js +14 -0
- package/dist/application/BrowserScenarioCapturePort.js +1 -0
- package/dist/application/BrowserScenarioCaptureService.js +53 -0
- package/dist/application/BrowserScenarioEvidence.js +40 -0
- package/dist/application/CallPathTracing.js +160 -0
- package/dist/application/CapabilityInventory.js +79 -15
- package/dist/application/CompositeProvider.js +10 -1
- package/dist/application/DirectAnalysis.js +7 -2
- package/dist/application/EnhancedLiteralTracing.js +118 -0
- package/dist/application/EnhancedTools.js +35 -121
- package/dist/application/JavaScriptApplicationWorkflowEvidence.js +13 -0
- package/dist/application/JavaScriptApplicationWorkflowService.js +27 -1
- package/dist/application/JavaScriptRuntimeObservationEvidence.js +34 -0
- package/dist/application/JavaScriptRuntimeObservationPort.js +1 -0
- package/dist/application/JavaScriptRuntimeObservationService.js +46 -0
- package/dist/application/JavaScriptSemanticGraphAsyncProjection.js +147 -0
- package/dist/application/JavaScriptSemanticGraphBuilder.js +34 -6
- package/dist/application/JavaScriptSemanticGraphChildProcessProjection.js +156 -0
- package/dist/application/JavaScriptSemanticGraphConstruction.js +2 -2
- package/dist/application/JavaScriptSemanticGraphDataProjection.js +203 -0
- package/dist/application/JavaScriptSemanticGraphFingerprintProjection.js +25 -0
- package/dist/application/JavaScriptSemanticGraphFlowProjection.js +129 -8
- package/dist/application/JavaScriptSemanticGraphObjectProjection.js +81 -0
- package/dist/application/JavaScriptSemanticGraphProjection.js +14 -7
- package/dist/application/JavaScriptSemanticGraphResourceProjection.js +59 -0
- package/dist/application/JavaScriptSemanticGraphValueProjection.js +77 -0
- package/dist/application/ProcessCaptureEnvironment.js +26 -0
- package/dist/application/ProcessCaptureLifecycle.js +1 -0
- package/dist/application/ProcessCheckpoints.js +5 -0
- package/dist/application/ProcessHarness.js +45 -34
- package/dist/application/ProcessNormalization.js +6 -0
- package/dist/application/ProcessReactiveCoordinator.js +10 -3
- package/dist/application/ProcessReactiveEffects.js +15 -1
- package/dist/application/ProcessReactiveHarness.js +100 -0
- package/dist/application/ProcessReactiveObservations.js +101 -16
- package/dist/application/ProjectPermissionStore.js +1 -0
- package/dist/application/ReconstructionObligationAuthority.js +72 -0
- package/dist/application/ReconstructionObligationCandidates.js +265 -0
- package/dist/application/ReconstructionObligationLedgerDiagnostics.js +47 -0
- package/dist/application/ReconstructionObligationLedgerEvaluation.js +263 -0
- package/dist/application/ReconstructionObligationLedgerProjection.js +86 -0
- package/dist/application/ReconstructionObligationLedgerService.js +72 -0
- package/dist/application/ReconstructionObligationOriginalCases.js +33 -0
- package/dist/application/ReconstructionObligationPolicies.js +132 -0
- package/dist/application/ReconstructionReadinessService.js +48 -0
- package/dist/artifacts/ArtifactProvider.js +87 -22
- package/dist/browser/BrowserScenarioSecrets.js +53 -0
- package/dist/browser/BrowserScenarioSessionPort.js +1 -0
- package/dist/browser/CdpBrowserProvider.js +2 -2
- package/dist/browser/CdpCaptureDocuments.js +57 -0
- package/dist/browser/CdpCaptureStorage.js +71 -29
- package/dist/browser/CdpCaptureStorageFingerprints.js +328 -0
- package/dist/browser/CdpEndpoint.js +8 -6
- package/dist/browser/CdpPageCapture.js +2 -0
- package/dist/browser/JavaScriptRuntimeScope.js +38 -0
- package/dist/browser/PlaywrightBrowserScenarioProvider.js +253 -0
- package/dist/browser/PlaywrightExecutionBoundary.js +42 -0
- package/dist/browser/PlaywrightScenarioActions.js +62 -0
- package/dist/browser/PlaywrightScenarioArtifacts.js +238 -0
- package/dist/browser/PlaywrightScenarioBrowser.js +144 -0
- package/dist/browser/PlaywrightScenarioEvents.js +301 -0
- package/dist/browser/PlaywrightScenarioSession.js +300 -0
- package/dist/browser/V8InspectorCaptureProjection.js +110 -0
- package/dist/browser/V8InspectorEndpoint.js +72 -0
- package/dist/browser/V8InspectorProvider.js +267 -0
- package/dist/catalogIdentity.js +8 -0
- package/dist/cli/artifactCommands.js +39 -0
- package/dist/cli/coreAnalysisCommands.js +37 -0
- package/dist/cli.js +4 -0
- package/dist/cliApplicationCommands.js +30 -2
- package/dist/cliBrowserAdvancedCommands.js +17 -5
- package/dist/cliBrowserCommands.js +1 -0
- package/dist/cliBrowserScenarioCommands.js +43 -0
- package/dist/cliCommandNames.js +8 -0
- package/dist/cliJavaScriptRuntimeCommands.js +164 -0
- package/dist/cliObservationOptions.js +4 -0
- package/dist/cliPolicyCommands.js +1 -0
- package/dist/config/environment.js +12 -0
- package/dist/config/parseConfig.js +88 -17
- package/dist/contracts/analysisSearchContract.js +14 -0
- package/dist/contracts/applicationToolContracts.js +86 -2
- package/dist/contracts/applicationWorkflowInputContracts.js +18 -0
- package/dist/contracts/artifactToolContracts.js +22 -0
- package/dist/contracts/browserProviderToolContracts.js +7 -0
- package/dist/contracts/browserScenarioToolContracts.js +81 -0
- package/dist/contracts/browserToolContracts.js +88 -98
- package/dist/contracts/enhancedInputs.js +25 -6
- package/dist/contracts/functionInstructionContract.js +8 -0
- package/dist/contracts/hopperMemoryContracts.js +22 -0
- package/dist/contracts/javascriptApplicationWorkflowExamples.js +42 -0
- package/dist/contracts/javascriptRuntimeObservationToolContracts.js +58 -0
- package/dist/contracts/reconstructionReadinessExample.js +436 -0
- package/dist/contracts/toolContractExamples.js +5 -0
- package/dist/contracts/toolContractTypes.js +1 -0
- package/dist/contracts/toolContracts.js +13 -21
- package/dist/contracts/toolEffects.js +21 -0
- package/dist/contracts/toolOutputSchemaGroups.js +70 -20
- package/dist/contracts/toolOutputSchemaPrimitives.js +40 -0
- package/dist/domain/analysisErrorProjection.js +8 -0
- package/dist/domain/analysisSnapshot.js +2 -0
- package/dist/domain/artifactGraph.js +2 -0
- package/dist/domain/artifactInspection.js +347 -0
- package/dist/domain/binaryTarget.js +3 -6
- package/dist/domain/browserCaptureComparison.js +82 -0
- package/dist/domain/browserObservation.js +8 -1
- package/dist/domain/browserObservationErrors.js +1 -0
- package/dist/domain/browserObservationSchemas.js +26 -0
- package/dist/domain/browserScenario.js +165 -0
- package/dist/domain/browserScenarioCapture.js +57 -0
- package/dist/domain/browserScenarioCaptureValues.js +204 -0
- package/dist/domain/browserScenarioDiff.js +324 -0
- package/dist/domain/browserScenarioDiffValues.js +157 -0
- package/dist/domain/browserScenarioNormalization.js +45 -0
- package/dist/domain/browserScenarioValues.js +372 -0
- package/dist/domain/evidence.js +2 -0
- package/dist/domain/hopperValues.js +10 -0
- package/dist/domain/javascriptRuntimeObservation.js +170 -0
- package/dist/domain/javascriptRuntimeReconciliationParsing.js +120 -2
- package/dist/domain/javascriptRuntimeReconciliationResult.js +3 -3
- package/dist/domain/javascriptRuntimeReconciliationRuntime.js +2 -2
- package/dist/domain/javascriptRuntimeReconciliationSchemas.js +1 -1
- package/dist/domain/javascriptSemanticAnalysis.js +5 -4
- package/dist/domain/javascriptSemanticAsyncEffects.js +253 -0
- package/dist/domain/javascriptSemanticChildProcesses.js +237 -0
- package/dist/domain/javascriptSemanticDataEffectHelpers.js +125 -0
- package/dist/domain/javascriptSemanticDataEffects.js +284 -0
- package/dist/domain/javascriptSemanticDerivedAnalysis.js +41 -0
- package/dist/domain/javascriptSemanticFingerprints.js +174 -0
- package/dist/domain/javascriptSemanticIr.js +21 -1
- package/dist/domain/javascriptSemanticObjects.js +115 -0
- package/dist/domain/javascriptSemanticPromises.js +290 -0
- package/dist/domain/javascriptSemanticResources.js +136 -0
- package/dist/domain/javascriptStaticAnalysis.js +4 -3
- package/dist/domain/javascriptStaticAnalysisBundler.js +38 -0
- package/dist/domain/javascriptStaticAnalysisCalls.js +23 -1
- package/dist/domain/javascriptStaticAnalysisHelpers.js +8 -0
- package/dist/domain/processCapture.js +71 -1
- package/dist/domain/processCaptureReactiveValidation.js +175 -0
- package/dist/domain/processCaptureValidation.js +2 -0
- package/dist/domain/processObservation.js +15 -6
- package/dist/domain/processReactiveRuntime.js +21 -10
- package/dist/domain/processReactiveScenario.js +1 -0
- package/dist/domain/processReactiveTransition.js +17 -10
- package/dist/domain/processScenario.js +21 -0
- package/dist/domain/providerCleanupError.js +11 -0
- package/dist/domain/reconstructionObligationLedgerSchemas.js +278 -0
- package/dist/domain/reconstructionReadiness.js +121 -0
- package/dist/domain/reconstructionReadinessFindingHelpers.js +17 -0
- package/dist/domain/reconstructionReadinessIntegrityFindings.js +118 -0
- package/dist/domain/reconstructionReadinessJourneyFindings.js +193 -0
- package/dist/domain/reconstructionReadinessSchemas.js +240 -0
- package/dist/domain/sourceToBundleComparison.js +335 -0
- package/dist/domain/sourceToBundleComparisonSchemas.js +133 -0
- package/dist/domain/sourceToBundleSignals.js +202 -0
- package/dist/domain/webCaptureDiff.js +141 -27
- package/dist/domain/webScreenshot.js +1 -1
- package/dist/domain/zipPackageFormat.js +20 -0
- package/dist/generatedPackageMetadata.js +1 -1
- package/dist/ghidra/GhidraDefaults.js +1 -1
- package/dist/ghidra/GhidraFunctionValues.js +13 -1
- package/dist/ghidra/GhidraProviderCapabilities.js +7 -0
- package/dist/hopper/HopperCleanup.js +158 -0
- package/dist/hopper/HopperClient.js +69 -99
- package/dist/hopper/HopperProvider.js +20 -1
- package/dist/hopper/HopperRequestQueue.js +187 -0
- package/dist/hopper/HopperResponseStream.js +46 -0
- package/dist/hopper/protocol.js +1 -0
- package/dist/main/transport.js +24 -24
- package/dist/main.js +6 -0
- package/dist/mcpDoctor.js +25 -2
- package/dist/native/NativeMacOSProvider.js +1 -0
- package/dist/process/ProcessCommandIdentity.js +19 -0
- package/dist/process/ProcessOwnership.js +11 -8
- package/dist/server/DynamicToolAvailability.js +70 -0
- package/dist/server/createServer.js +46 -1
- package/dist/server/lifecycleProgress.js +10 -0
- package/dist/server/permissionFailure.js +12 -0
- package/dist/server/registerApplicationTools/compareSourceToBundle.js +35 -0
- package/dist/server/registerApplicationTools/helpers.js +11 -7
- package/dist/server/registerApplicationTools/obligationLedger.js +27 -0
- package/dist/server/registerApplicationTools/readiness.js +55 -0
- package/dist/server/registerApplicationTools.js +6 -0
- package/dist/server/registerArtifactTools.js +9 -1
- package/dist/server/registerBrowserScenarioTool.js +25 -0
- package/dist/server/registerBrowserTools.js +2 -2
- package/dist/server/registerCloseLifecycleTool.js +57 -0
- package/dist/server/registerEnhancedTools.js +16 -5
- package/dist/server/registerEvidenceResources.js +4 -0
- package/dist/server/registerEvidenceTools.js +9 -2
- package/dist/server/registerJavaScriptRuntimeObservationTools.js +37 -0
- package/dist/server/registerReconstructionObligationLedgerResource.js +39 -0
- package/dist/server/registerReconstructionReadinessResource.js +39 -0
- package/dist/server/registerSessionStatusTool.js +11 -8
- package/dist/server/registerSessionTools.js +11 -57
- package/dist/server/sessionAvailabilityPolicy.js +10 -8
- package/package.json +12 -6
- package/skills/reverse-engineer-anything/SKILL.md +4 -3
- package/skills/reverse-engineer-anything/references/native-and-artifacts.md +2 -2
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { createAnalysisExecution, } from "../application/AnalysisProvider.js";
|
|
2
2
|
import { inventoryArtifact } from "../application/ArtifactInventory.js";
|
|
3
3
|
import { extractArtifact } from "../application/ArtifactExtraction.js";
|
|
4
|
-
import { ARTIFACT_TOOL_CONTRACTS, artifactInventoryInputSchema, artifactExtractionInputSchema, } from "../contracts/artifactToolContracts.js";
|
|
4
|
+
import { ARTIFACT_TOOL_CONTRACTS, artifactInspectionInputSchema, artifactInventoryInputSchema, artifactExtractionInputSchema, } from "../contracts/artifactToolContracts.js";
|
|
5
5
|
import { AnalysisCapabilityUnavailableError, ArtifactOperationError, } from "../domain/errors.js";
|
|
6
6
|
import { err, ok } from "../domain/result.js";
|
|
7
7
|
import { ArtifactReaderFailure, } from "./ArtifactReader.js";
|
|
8
8
|
import { ARTIFACT_GRAPH_PROVIDER } from "../application/InvestigationProviders.js";
|
|
9
|
+
import { createEvidence } from "../domain/evidence.js";
|
|
10
|
+
import { createArtifactInspection } from "../domain/artifactInspection.js";
|
|
9
11
|
const IDENTITY = Object.freeze(ARTIFACT_GRAPH_PROVIDER);
|
|
10
12
|
/** Read-only inventory and exclusively owned extraction provider. */
|
|
11
13
|
export class ArtifactProvider {
|
|
@@ -22,7 +24,9 @@ export class ArtifactProvider {
|
|
|
22
24
|
outputContractVersion: 1,
|
|
23
25
|
available: true,
|
|
24
26
|
reason: null,
|
|
25
|
-
pagination: "
|
|
27
|
+
pagination: contract.name === "inspect_artifact"
|
|
28
|
+
? "none"
|
|
29
|
+
: "offset",
|
|
26
30
|
exhaustive: false,
|
|
27
31
|
effects: Object.freeze({
|
|
28
32
|
mutatesArtifact: false,
|
|
@@ -68,6 +72,10 @@ class ArtifactClient {
|
|
|
68
72
|
if (!isArtifactOperation(operation))
|
|
69
73
|
return err(new AnalysisCapabilityUnavailableError(IDENTITY.id, operation, "Operation is not implemented by artifact graph provider."));
|
|
70
74
|
try {
|
|
75
|
+
if (operation === "inspect_artifact") {
|
|
76
|
+
const inspected = await this.inspectArtifact(parameters, options);
|
|
77
|
+
return inspected;
|
|
78
|
+
}
|
|
71
79
|
if (operation === "extract_artifact") {
|
|
72
80
|
const parsed = artifactExtractionInputSchema.parse(parameters);
|
|
73
81
|
const result = await extractArtifact({
|
|
@@ -90,26 +98,7 @@ class ArtifactClient {
|
|
|
90
98
|
}));
|
|
91
99
|
}
|
|
92
100
|
const parsed = artifactInventoryInputSchema.parse(parameters);
|
|
93
|
-
const result = await
|
|
94
|
-
nodeOffset: parsed.node_offset,
|
|
95
|
-
nodeLimit: parsed.node_limit,
|
|
96
|
-
occurrenceOffset: parsed.occurrence_offset,
|
|
97
|
-
occurrenceLimit: parsed.occurrence_limit,
|
|
98
|
-
edgeOffset: parsed.edge_offset,
|
|
99
|
-
edgeLimit: parsed.edge_limit,
|
|
100
|
-
}, {
|
|
101
|
-
...(options?.signal === undefined ? {} : { signal: options.signal }),
|
|
102
|
-
nativeMount: {
|
|
103
|
-
nativeMountApproved: parsed.native_mount_approved === true,
|
|
104
|
-
nativeMountEnabled: this.nativeMountEnabled,
|
|
105
|
-
},
|
|
106
|
-
integrity: {
|
|
107
|
-
mode: parsed.integrity_policy,
|
|
108
|
-
approved: parsed.integrity_continue_approved === true,
|
|
109
|
-
enabled: this.integrityContinueEnabled,
|
|
110
|
-
maxMismatches: parsed.max_integrity_mismatches,
|
|
111
|
-
},
|
|
112
|
-
});
|
|
101
|
+
const result = await this.inventory(parsed, options);
|
|
113
102
|
return ok(createAnalysisExecution(result, IDENTITY, {
|
|
114
103
|
rawResult: null,
|
|
115
104
|
limitations: result.limitations,
|
|
@@ -127,6 +116,82 @@ class ArtifactClient {
|
|
|
127
116
|
close() {
|
|
128
117
|
return Promise.resolve();
|
|
129
118
|
}
|
|
119
|
+
async inspectArtifact(parameters, options) {
|
|
120
|
+
const parsed = artifactInspectionInputSchema.parse(parameters);
|
|
121
|
+
const inventoryParameters = artifactInventoryInputSchema.parse({
|
|
122
|
+
node_offset: 0,
|
|
123
|
+
node_limit: parsed.max_observations,
|
|
124
|
+
occurrence_offset: 0,
|
|
125
|
+
occurrence_limit: parsed.max_observations,
|
|
126
|
+
edge_offset: 0,
|
|
127
|
+
edge_limit: parsed.max_relationships,
|
|
128
|
+
native_mount_approved: parsed.native_mount_approved,
|
|
129
|
+
integrity_policy: parsed.integrity_policy,
|
|
130
|
+
integrity_continue_approved: parsed.integrity_continue_approved,
|
|
131
|
+
max_integrity_mismatches: parsed.max_integrity_mismatches,
|
|
132
|
+
max_entries: parsed.max_entries,
|
|
133
|
+
max_total_bytes: parsed.max_total_bytes,
|
|
134
|
+
max_entry_bytes: parsed.max_entry_bytes,
|
|
135
|
+
max_compression_ratio: parsed.max_compression_ratio,
|
|
136
|
+
max_depth: parsed.max_depth,
|
|
137
|
+
max_path_bytes: parsed.max_path_bytes,
|
|
138
|
+
});
|
|
139
|
+
await options?.progress?.report({
|
|
140
|
+
phase: "inspect_artifact.inventory",
|
|
141
|
+
completed: 0,
|
|
142
|
+
total: 1,
|
|
143
|
+
message: "inventory substep started",
|
|
144
|
+
});
|
|
145
|
+
const inventory = await this.inventory(inventoryParameters, options);
|
|
146
|
+
const subject = subjectFor(this.target.sourcePath ?? this.target.path, inventory.manifest);
|
|
147
|
+
const locations = inventory.occurrences.items.map(({ logical_path: path }) => ({
|
|
148
|
+
kind: "artifact-path",
|
|
149
|
+
path,
|
|
150
|
+
}));
|
|
151
|
+
const inventoryEvidence = createEvidence(subject, IDENTITY, {
|
|
152
|
+
operation: "inventory_artifact",
|
|
153
|
+
parameters: inventoryParameters,
|
|
154
|
+
result: inventory,
|
|
155
|
+
rawResult: null,
|
|
156
|
+
limitations: inventory.limitations,
|
|
157
|
+
locations,
|
|
158
|
+
});
|
|
159
|
+
const result = createArtifactInspection(inventoryEvidence, parsed);
|
|
160
|
+
await options?.progress?.report({
|
|
161
|
+
phase: "inspect_artifact.inventory",
|
|
162
|
+
completed: 1,
|
|
163
|
+
total: 1,
|
|
164
|
+
message: "inventory substep completed",
|
|
165
|
+
});
|
|
166
|
+
return ok(createAnalysisExecution(result, IDENTITY, {
|
|
167
|
+
rawResult: null,
|
|
168
|
+
limitations: result.limitations,
|
|
169
|
+
subject,
|
|
170
|
+
locations,
|
|
171
|
+
}));
|
|
172
|
+
}
|
|
173
|
+
inventory(parsed, options) {
|
|
174
|
+
return inventoryArtifact(this.target.sourcePath ?? this.target.path, limitsFrom(parsed), {
|
|
175
|
+
nodeOffset: parsed.node_offset,
|
|
176
|
+
nodeLimit: parsed.node_limit,
|
|
177
|
+
occurrenceOffset: parsed.occurrence_offset,
|
|
178
|
+
occurrenceLimit: parsed.occurrence_limit,
|
|
179
|
+
edgeOffset: parsed.edge_offset,
|
|
180
|
+
edgeLimit: parsed.edge_limit,
|
|
181
|
+
}, {
|
|
182
|
+
...(options?.signal === undefined ? {} : { signal: options.signal }),
|
|
183
|
+
nativeMount: {
|
|
184
|
+
nativeMountApproved: parsed.native_mount_approved === true,
|
|
185
|
+
nativeMountEnabled: this.nativeMountEnabled,
|
|
186
|
+
},
|
|
187
|
+
integrity: {
|
|
188
|
+
mode: parsed.integrity_policy,
|
|
189
|
+
approved: parsed.integrity_continue_approved === true,
|
|
190
|
+
enabled: this.integrityContinueEnabled,
|
|
191
|
+
maxMismatches: parsed.max_integrity_mismatches,
|
|
192
|
+
},
|
|
193
|
+
});
|
|
194
|
+
}
|
|
130
195
|
}
|
|
131
196
|
const limitsFrom = (input) => ({
|
|
132
197
|
maxEntries: input.max_entries,
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
const REDACTION_PREFIX = "[REDACTED:";
|
|
3
|
+
/** Resolved secret values kept only for one in-memory scenario session. */
|
|
4
|
+
export class BrowserScenarioSecrets {
|
|
5
|
+
values;
|
|
6
|
+
constructor(values) {
|
|
7
|
+
this.values = values;
|
|
8
|
+
}
|
|
9
|
+
static resolve(scenario, environment) {
|
|
10
|
+
const values = new Map();
|
|
11
|
+
for (const declaration of scenario.secrets) {
|
|
12
|
+
const value = environment[declaration.environment_variable];
|
|
13
|
+
if (value === undefined)
|
|
14
|
+
return undefined;
|
|
15
|
+
values.set(declaration.secret_id, value);
|
|
16
|
+
}
|
|
17
|
+
return new BrowserScenarioSecrets(values);
|
|
18
|
+
}
|
|
19
|
+
value(source) {
|
|
20
|
+
if (source.source === "literal")
|
|
21
|
+
return source.value;
|
|
22
|
+
const value = this.values.get(source.secret_id);
|
|
23
|
+
if (value === undefined)
|
|
24
|
+
throw new Error("Validated browser secret was not resolved");
|
|
25
|
+
return value;
|
|
26
|
+
}
|
|
27
|
+
url(destination) {
|
|
28
|
+
const url = new URL(destination.url);
|
|
29
|
+
for (const { name, value } of destination.query)
|
|
30
|
+
url.searchParams.append(name, this.value(value));
|
|
31
|
+
return url.href;
|
|
32
|
+
}
|
|
33
|
+
redact(value) {
|
|
34
|
+
let output = value;
|
|
35
|
+
const replacements = [...this.values].sort(([leftId, left], [rightId, right]) => right.length - left.length ||
|
|
36
|
+
(leftId < rightId ? -1 : leftId > rightId ? 1 : 0));
|
|
37
|
+
for (const [id, secret] of replacements)
|
|
38
|
+
if (secret !== "")
|
|
39
|
+
output = output.replaceAll(secret, `${REDACTION_PREFIX}${id}]`);
|
|
40
|
+
return output;
|
|
41
|
+
}
|
|
42
|
+
fingerprint(value) {
|
|
43
|
+
for (const secret of this.values.values())
|
|
44
|
+
if (secret !== "" && value.includes(secret))
|
|
45
|
+
return { value_state: "redacted-secret", value_sha256: null };
|
|
46
|
+
return {
|
|
47
|
+
value_state: "hashed",
|
|
48
|
+
value_sha256: createHash("sha256")
|
|
49
|
+
.update(this.redact(value))
|
|
50
|
+
.digest("hex"),
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -3,7 +3,7 @@ import { analyzeCapturedWebBundle } from "../domain/webBundleAnalyzer.js";
|
|
|
3
3
|
import { webBundleAnalysisSchema, } from "../domain/webBundleAnalysis.js";
|
|
4
4
|
import { webObservationSessionSchema, } from "../domain/browserSession.js";
|
|
5
5
|
import { webMcpDiscoverySchema, } from "../domain/webMcpDiscovery.js";
|
|
6
|
-
import {
|
|
6
|
+
import { browserCaptureComparisonSchema, compareBrowserCaptures, } from "../domain/browserCaptureComparison.js";
|
|
7
7
|
import { webScreenshotDiffSchema, webScreenshotSchema, } from "../domain/webScreenshot.js";
|
|
8
8
|
import { AnalysisError, BrowserObservationError, ProviderAdapterError, } from "../domain/errors.js";
|
|
9
9
|
import { err, ok } from "../domain/result.js";
|
|
@@ -136,7 +136,7 @@ export class CdpBrowserProvider {
|
|
|
136
136
|
}
|
|
137
137
|
async compareCaptures(input) {
|
|
138
138
|
try {
|
|
139
|
-
return ok(
|
|
139
|
+
return ok(browserCaptureComparisonSchema.parse(compareBrowserCaptures(input)));
|
|
140
140
|
}
|
|
141
141
|
catch (cause) {
|
|
142
142
|
return err(providerError(cause, "compare_web_captures"));
|
|
@@ -156,6 +156,10 @@ export const captureDom = (result, allowedOrigins, input, completeness) => {
|
|
|
156
156
|
};
|
|
157
157
|
export const captureAccessibility = (results, maximum, options) => {
|
|
158
158
|
const all = results.flatMap((result) => recordsValue(requiredRecord(result).nodes));
|
|
159
|
+
const nodeIds = new Set(all.flatMap((node) => {
|
|
160
|
+
const nodeId = stringValue(node.nodeId);
|
|
161
|
+
return nodeId === undefined ? [] : [nodeId];
|
|
162
|
+
}));
|
|
159
163
|
let retainedBytes = 0;
|
|
160
164
|
let excludedFields = 0;
|
|
161
165
|
let truncatedFields = 0;
|
|
@@ -187,6 +191,7 @@ export const captureAccessibility = (results, maximum, options) => {
|
|
|
187
191
|
name: captureText(node.name),
|
|
188
192
|
description: captureText(node.description),
|
|
189
193
|
ignored: node.ignored === true,
|
|
194
|
+
states: accessibilityStates(node.properties),
|
|
190
195
|
};
|
|
191
196
|
});
|
|
192
197
|
for (const node of all.slice(maximum)) {
|
|
@@ -201,6 +206,11 @@ export const captureAccessibility = (results, maximum, options) => {
|
|
|
201
206
|
return {
|
|
202
207
|
total: all.length,
|
|
203
208
|
nodes,
|
|
209
|
+
treeIncomplete: all.some((node) => Array.isArray(node.childIds) &&
|
|
210
|
+
node.childIds.some((childId) => {
|
|
211
|
+
const id = stringValue(childId);
|
|
212
|
+
return id !== undefined && !nodeIds.has(id);
|
|
213
|
+
})),
|
|
204
214
|
textCapture: {
|
|
205
215
|
status: options.unavailable
|
|
206
216
|
? "unavailable"
|
|
@@ -215,6 +225,53 @@ export const captureAccessibility = (results, maximum, options) => {
|
|
|
215
225
|
},
|
|
216
226
|
};
|
|
217
227
|
};
|
|
228
|
+
const ACCESSIBILITY_STATE_NAMES = new Set([
|
|
229
|
+
"atomic",
|
|
230
|
+
"autocomplete",
|
|
231
|
+
"busy",
|
|
232
|
+
"checked",
|
|
233
|
+
"disabled",
|
|
234
|
+
"editable",
|
|
235
|
+
"expanded",
|
|
236
|
+
"focusable",
|
|
237
|
+
"focused",
|
|
238
|
+
"hasPopup",
|
|
239
|
+
"hidden",
|
|
240
|
+
"invalid",
|
|
241
|
+
"level",
|
|
242
|
+
"live",
|
|
243
|
+
"modal",
|
|
244
|
+
"multiline",
|
|
245
|
+
"multiselectable",
|
|
246
|
+
"orientation",
|
|
247
|
+
"pressed",
|
|
248
|
+
"readonly",
|
|
249
|
+
"required",
|
|
250
|
+
"selected",
|
|
251
|
+
"valuemax",
|
|
252
|
+
"valuemin",
|
|
253
|
+
]);
|
|
254
|
+
const accessibilityStates = (value) => {
|
|
255
|
+
const states = new Map();
|
|
256
|
+
for (const property of recordsValue(value)) {
|
|
257
|
+
const name = stringValue(property.name);
|
|
258
|
+
if (name === undefined || !ACCESSIBILITY_STATE_NAMES.has(name))
|
|
259
|
+
continue;
|
|
260
|
+
const raw = recordValue(property.value)?.value;
|
|
261
|
+
const state = typeof raw === "boolean"
|
|
262
|
+
? raw
|
|
263
|
+
: typeof raw === "number"
|
|
264
|
+
? numberValue(raw)
|
|
265
|
+
: typeof raw === "string"
|
|
266
|
+
? raw.slice(0, 256)
|
|
267
|
+
: undefined;
|
|
268
|
+
if (state !== undefined)
|
|
269
|
+
states.set(name, state);
|
|
270
|
+
}
|
|
271
|
+
return [...states]
|
|
272
|
+
.sort(([left], [right]) => left.localeCompare(right))
|
|
273
|
+
.map(([name, state]) => ({ name, value: state }));
|
|
274
|
+
};
|
|
218
275
|
const axText = (value) => boundedText(recordValue(value)?.value, 1_024);
|
|
219
276
|
const indexedString = (strings, index) => {
|
|
220
277
|
const integer = numberValue(index);
|
|
@@ -1,53 +1,95 @@
|
|
|
1
1
|
import { CdpConnection } from "./CdpConnection.js";
|
|
2
2
|
import { optionalCdpCommand } from "./CdpOptionalCommand.js";
|
|
3
|
+
import { captureStorageFingerprints, } from "./CdpCaptureStorageFingerprints.js";
|
|
3
4
|
import { numberValue, recordValue, recordsValue, stringValue, } from "./CdpCaptureValues.js";
|
|
4
5
|
/** Capture redacted, bounded storage metadata for one authorized origin. */
|
|
5
6
|
export const captureStorage = async (context, origin, limitations) => {
|
|
6
7
|
const quota = recordValue(await optionalCdpCommand(context, "Storage.getUsageAndQuota", { origin }, limitations));
|
|
7
8
|
const local = context.input.include_storage_keys
|
|
8
|
-
? await
|
|
9
|
-
:
|
|
9
|
+
? await storageItems(context, origin, true, limitations)
|
|
10
|
+
: emptyStorageItems;
|
|
10
11
|
const session = context.input.include_storage_keys
|
|
11
|
-
? await
|
|
12
|
-
:
|
|
13
|
-
const
|
|
14
|
-
?
|
|
15
|
-
:
|
|
16
|
-
const
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
12
|
+
? await storageItems(context, origin, false, limitations)
|
|
13
|
+
: emptyStorageItems;
|
|
14
|
+
const indexedRaw = context.input.include_storage_keys
|
|
15
|
+
? await optionalCdpCommand(context, "IndexedDB.requestDatabaseNames", { securityOrigin: origin }, limitations)
|
|
16
|
+
: undefined;
|
|
17
|
+
const indexedValues = recordValue(indexedRaw)?.databaseNames;
|
|
18
|
+
const indexed = stringArray(indexedValues);
|
|
19
|
+
const cacheRaw = context.input.include_storage_keys
|
|
20
|
+
? await optionalCdpCommand(context, "CacheStorage.requestCacheNames", { securityOrigin: origin }, limitations)
|
|
21
|
+
: undefined;
|
|
22
|
+
const cacheValues = recordsValue(recordValue(cacheRaw)?.caches);
|
|
23
|
+
const caches = capturedCaches(cacheValues);
|
|
22
24
|
const maximum = context.input.limits.max_storage_keys;
|
|
25
|
+
const fingerprints = context.input.include_storage_fingerprints
|
|
26
|
+
? await captureStorageFingerprints({
|
|
27
|
+
context,
|
|
28
|
+
origin,
|
|
29
|
+
local,
|
|
30
|
+
session,
|
|
31
|
+
indexedDbNames: indexed.slice(0, maximum),
|
|
32
|
+
caches: caches.slice(0, maximum),
|
|
33
|
+
limitations,
|
|
34
|
+
})
|
|
35
|
+
: { items: [], complete: false, truncated: false };
|
|
36
|
+
const truncated = [local.items, session.items, indexed, caches].some((items) => items.length > maximum) || fingerprints.truncated;
|
|
37
|
+
const structuredStorageComplete = indexedRaw !== undefined &&
|
|
38
|
+
Array.isArray(indexedValues) &&
|
|
39
|
+
indexed.length === indexedValues.length &&
|
|
40
|
+
cacheRaw !== undefined &&
|
|
41
|
+
caches.length === cacheValues.length;
|
|
23
42
|
return {
|
|
24
43
|
value: {
|
|
25
44
|
origin,
|
|
26
45
|
usage_bytes: numberValue(quota?.usage) ?? null,
|
|
27
46
|
quota_bytes: numberValue(quota?.quota) ?? null,
|
|
28
|
-
local_storage_keys: local.
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
47
|
+
local_storage_keys: local.items
|
|
48
|
+
.map(({ key }) => key.slice(0, 1_024))
|
|
49
|
+
.slice(0, maximum),
|
|
50
|
+
session_storage_keys: session.items
|
|
51
|
+
.map(({ key }) => key.slice(0, 1_024))
|
|
52
|
+
.slice(0, maximum),
|
|
53
|
+
indexed_db_names: indexed
|
|
54
|
+
.map((name) => name.slice(0, 1_024))
|
|
55
|
+
.slice(0, maximum),
|
|
56
|
+
cache_names: caches
|
|
57
|
+
.map(({ name }) => name.slice(0, 1_024))
|
|
58
|
+
.slice(0, maximum),
|
|
59
|
+
content_fingerprints: [...fingerprints.items],
|
|
60
|
+
fingerprint_algorithm: "sha256",
|
|
61
|
+
fingerprints_complete: fingerprints.complete && structuredStorageComplete && !truncated,
|
|
32
62
|
values_redacted: true,
|
|
33
63
|
},
|
|
34
|
-
truncated
|
|
64
|
+
truncated,
|
|
35
65
|
};
|
|
36
66
|
};
|
|
37
|
-
const
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
67
|
+
const emptyStorageItems = {
|
|
68
|
+
items: [],
|
|
69
|
+
complete: false,
|
|
70
|
+
};
|
|
71
|
+
const capturedCaches = (values) => values.flatMap((cache) => {
|
|
72
|
+
const name = stringValue(cache.cacheName);
|
|
73
|
+
const id = stringValue(cache.cacheId);
|
|
74
|
+
return name === undefined || id === undefined ? [] : [{ name, id }];
|
|
75
|
+
});
|
|
76
|
+
const storageItems = async (context, origin, isLocalStorage, limitations) => {
|
|
77
|
+
const raw = await optionalCdpCommand(context, "DOMStorage.getDOMStorageItems", { storageId: { securityOrigin: origin, isLocalStorage } }, limitations);
|
|
78
|
+
const entries = recordValue(raw)?.entries;
|
|
79
|
+
if (raw === undefined || !Array.isArray(entries))
|
|
80
|
+
return { items: [], complete: false };
|
|
81
|
+
const items = entries.flatMap((entry) => {
|
|
82
|
+
if (!Array.isArray(entry))
|
|
83
|
+
return [];
|
|
84
|
+
const key = stringValue(entry[0]);
|
|
85
|
+
const value = stringValue(entry[1]);
|
|
86
|
+
return key === undefined || value === undefined ? [] : [{ key, value }];
|
|
87
|
+
});
|
|
88
|
+
return { items, complete: items.length === entries.length };
|
|
47
89
|
};
|
|
48
90
|
const stringArray = (value) => Array.isArray(value)
|
|
49
91
|
? value.flatMap((item) => {
|
|
50
92
|
const text = stringValue(item);
|
|
51
|
-
return text === undefined ? [] : [text
|
|
93
|
+
return text === undefined ? [] : [text];
|
|
52
94
|
})
|
|
53
95
|
: [];
|