rea-agents 2.0.0 → 2.2.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.
Files changed (273) hide show
  1. package/README.md +103 -38
  2. package/bridge/ghidra/ReaGhidraBridge.java +96 -11
  3. package/dist/application/AndroidApplicationService.js +17 -0
  4. package/dist/application/AppleApplicationService.js +17 -0
  5. package/dist/application/ArtifactExtraction.js +1 -1
  6. package/dist/application/ArtifactInventory/classify.js +42 -0
  7. package/dist/application/ArtifactInventory/hash.js +43 -0
  8. package/dist/application/ArtifactInventory/reader.js +41 -0
  9. package/dist/application/ArtifactInventory/scanCanonical.js +155 -0
  10. package/dist/application/ArtifactInventory/scanReader.js +124 -0
  11. package/dist/application/ArtifactInventory/types.js +10 -0
  12. package/dist/application/ArtifactInventory.js +9 -351
  13. package/dist/application/AuthorizedArtifactInventory.js +2 -2
  14. package/dist/application/BinarySession.js +47 -270
  15. package/dist/application/BinarySessionExecution.js +28 -0
  16. package/dist/application/BinarySessionOpen.js +39 -0
  17. package/dist/application/BinarySessionRecords.js +149 -0
  18. package/dist/application/BinarySessionStatus.js +75 -0
  19. package/dist/application/CapabilityInventory.js +24 -2
  20. package/dist/application/ClientRegistrationStatus.js +11 -4
  21. package/dist/application/CrossVersionInventory.js +8 -2
  22. package/dist/application/CrossVersionInvestigation.js +1 -23
  23. package/dist/application/CrossVersionInvestigationCollections.js +23 -0
  24. package/dist/application/DirectAnalysis.js +47 -44
  25. package/dist/application/Doctor.js +156 -238
  26. package/dist/application/DoctorDiagnostics.js +180 -0
  27. package/dist/application/ElectronBoundaryAnalysis.js +23 -7
  28. package/dist/application/ElectronBoundaryGraphWindows.js +32 -8
  29. package/dist/application/EnhancedToolPagination.js +22 -0
  30. package/dist/application/EnhancedToolTypes.js +4 -0
  31. package/dist/application/EnhancedTools.js +20 -37
  32. package/dist/application/InstrumentedJavaScriptReplayHost.js +36 -0
  33. package/dist/application/InventoryProjectionEvidence.js +41 -0
  34. package/dist/application/InvestigationProviders.js +12 -0
  35. package/dist/application/InvestigationWorkspaceStore.js +24 -10
  36. package/dist/application/JavaScriptArtifactAnalysis.js +45 -6
  37. package/dist/application/JavaScriptArtifactFiles.js +6 -2
  38. package/dist/application/JavaScriptArtifactGraphBuilder.js +23 -1
  39. package/dist/application/JavaScriptArtifactGraphBundlers.js +225 -0
  40. package/dist/application/JavaScriptArtifactGraphContext.js +37 -36
  41. package/dist/application/JavaScriptArtifactGraphDocuments.js +27 -4
  42. package/dist/application/JavaScriptArtifactGraphFindings.js +54 -8
  43. package/dist/application/JavaScriptArtifactGraphStructure.js +29 -101
  44. package/dist/application/JavaScriptArtifactPathResolution.js +269 -0
  45. package/dist/application/JavaScriptArtifactReconstruction.js +1 -1
  46. package/dist/application/JavaScriptJsonModules.js +39 -0
  47. package/dist/application/JavaScriptModuleRelationships.js +262 -0
  48. package/dist/application/JavaScriptReplayPermission.js +16 -0
  49. package/dist/application/JavaScriptReplayService.js +182 -156
  50. package/dist/application/LinuxHopper.js +10 -0
  51. package/dist/application/MacHopper.js +22 -11
  52. package/dist/application/NodeRuntimeCharacterizationService.js +196 -0
  53. package/dist/application/PermissionAuthority.js +106 -63
  54. package/dist/application/ProcessCaptureCapability.js +1 -1
  55. package/dist/application/ProcessCapturePermission.js +13 -0
  56. package/dist/application/ProcessCli.js +2 -12
  57. package/dist/application/ProcessHarness.js +1 -1
  58. package/dist/application/ProcessPairedExperiment.js +72 -0
  59. package/dist/application/ProjectPermissionStore.js +48 -9
  60. package/dist/application/RealHopperAssertions.js +76 -0
  61. package/dist/application/ReconstructionCoverageService.js +69 -0
  62. package/dist/application/ReconstructionCoverageWorkspaceStore.js +31 -0
  63. package/dist/application/RuntimeExecutableDiagnostics.js +172 -0
  64. package/dist/application/Setup.js +148 -260
  65. package/dist/application/SetupClientConfiguration.js +224 -0
  66. package/dist/application/SetupClients.js +24 -2
  67. package/dist/application/SetupPlan.js +124 -12
  68. package/dist/application/SetupSkill.js +54 -36
  69. package/dist/application/SupportedClients.js +1 -0
  70. package/dist/application/Uninstall.js +12 -3
  71. package/dist/application/Upgrade.js +16 -1
  72. package/dist/application/WindowsCapabilities.js +86 -0
  73. package/dist/artifacts/AsarArtifactReader.js +11 -0
  74. package/dist/browser/BrowserProcessStartup.js +88 -0
  75. package/dist/browser/CdpCaptureDocuments.js +12 -8
  76. package/dist/browser/CdpCaptureEventBodyShapes.js +75 -0
  77. package/dist/browser/CdpCaptureEventHandlers.js +336 -0
  78. package/dist/browser/CdpCaptureEventHelpers.js +71 -0
  79. package/dist/browser/CdpCaptureEventState.js +1 -0
  80. package/dist/browser/CdpCaptureEventTypes.js +1 -0
  81. package/dist/browser/CdpCaptureEvents.js +29 -496
  82. package/dist/browser/CdpObservationSession.js +51 -8
  83. package/dist/browser/CdpPageCapture.js +12 -133
  84. package/dist/browser/CdpPageCaptureScripts.js +97 -0
  85. package/dist/browser/CdpPageCaptureWorkers.js +46 -0
  86. package/dist/browser/CdpWebMcpDiscovery.js +38 -14
  87. package/dist/browser/PngVisualDiff.js +9 -2
  88. package/dist/catalogIdentity.js +4 -0
  89. package/dist/cli/artifactCommands.js +82 -0
  90. package/dist/cli/coreAnalysisCommands.js +232 -0
  91. package/dist/cli/managedCommands.js +397 -0
  92. package/dist/cli/managedProjectGraphCommand.js +24 -0
  93. package/dist/cli/options.js +9 -0
  94. package/dist/cli/setupCommands.js +113 -0
  95. package/dist/cli/types.js +1 -0
  96. package/dist/cli/utilityCommands.js +122 -0
  97. package/dist/cli.js +10 -768
  98. package/dist/cliApplicationCommands.js +118 -4
  99. package/dist/cliBrowserAdvancedCommands.js +73 -16
  100. package/dist/cliBrowserCommands.js +39 -115
  101. package/dist/cliCommandNames.js +4 -0
  102. package/dist/cliElectronCommands.js +33 -62
  103. package/dist/cliEvidenceCommands.js +13 -2
  104. package/dist/cliInvestigationCommands.js +53 -10
  105. package/dist/cliObservationOptions.js +137 -0
  106. package/dist/cliPolicyCommands.js +80 -46
  107. package/dist/cliSetup.js +306 -0
  108. package/dist/config/environment.js +107 -0
  109. package/dist/config/parseConfig.js +228 -0
  110. package/dist/config/parsers.js +68 -0
  111. package/dist/config/permissions.js +30 -0
  112. package/dist/config/types.js +1 -0
  113. package/dist/config.js +1 -375
  114. package/dist/contracts/applicationToolContracts.js +134 -0
  115. package/dist/contracts/electronToolContracts.js +51 -3
  116. package/dist/contracts/managedToolContracts.js +8 -3
  117. package/dist/contracts/managedWorkflowToolContracts.js +3 -3
  118. package/dist/contracts/providerSelection.js +2 -0
  119. package/dist/contracts/sessionStatusContract.js +26 -0
  120. package/dist/contracts/toolContractTypes.js +12 -1
  121. package/dist/contracts/toolContracts.js +5 -12
  122. package/dist/contracts/toolEffects.js +14 -0
  123. package/dist/contracts/toolOutputSchemaGroups.js +274 -0
  124. package/dist/contracts/toolOutputSchemaPrimitives.js +328 -0
  125. package/dist/contracts/toolOutputSchemas.js +2 -550
  126. package/dist/domain/analysisErrorPresentation.js +234 -0
  127. package/dist/domain/analysisErrorProjection.js +284 -0
  128. package/dist/domain/androidApplication.js +206 -0
  129. package/dist/domain/appleApplication.js +221 -0
  130. package/dist/domain/artifactComparison.js +34 -15
  131. package/dist/domain/binaryTarget.js +87 -37
  132. package/dist/domain/boundedCartesianProjection.js +15 -0
  133. package/dist/domain/browserObservation.js +1 -285
  134. package/dist/domain/browserObservationSchemas.js +286 -0
  135. package/dist/domain/electronStaticAnalysisBrowser.js +14 -2
  136. package/dist/domain/errors.js +4 -486
  137. package/dist/domain/functionComparison.js +4 -165
  138. package/dist/domain/functionComparisonDimensions.js +164 -0
  139. package/dist/domain/javascriptApplicationVersionItems.js +18 -6
  140. package/dist/domain/javascriptApplicationVersionKeys.js +8 -8
  141. package/dist/domain/javascriptExportInstrumentation.js +97 -0
  142. package/dist/domain/javascriptFeatureTraversal.js +19 -7
  143. package/dist/domain/javascriptRuntimeStaticCandidates.js +3 -1
  144. package/dist/domain/javascriptSemanticAnalysis.js +386 -0
  145. package/dist/domain/javascriptSemanticIr.js +30 -0
  146. package/dist/domain/javascriptSemanticProjection.js +366 -0
  147. package/dist/domain/javascriptSemanticState.js +40 -0
  148. package/dist/domain/javascriptSemanticTraversal.js +22 -0
  149. package/dist/domain/javascriptSemanticValues.js +352 -0
  150. package/dist/domain/javascriptStaticAnalysis.js +5 -221
  151. package/dist/domain/javascriptStaticAnalysisBundler.js +209 -0
  152. package/dist/domain/javascriptStaticAnalysisCalls.js +180 -0
  153. package/dist/domain/javascriptStaticAnalysisHelpers.js +71 -2
  154. package/dist/domain/knownPageCoverage.js +21 -0
  155. package/dist/domain/managedApplicationGraph.js +14 -364
  156. package/dist/domain/managedApplicationGraphCoverage.js +170 -0
  157. package/dist/domain/managedApplicationGraphNodeCoverage.js +6 -0
  158. package/dist/domain/managedApplicationGraphNodes.js +336 -0
  159. package/dist/domain/managedArtifact.js +16 -8
  160. package/dist/domain/managedMemberComparison.js +37 -391
  161. package/dist/domain/managedMemberComparisonCoverage.js +72 -0
  162. package/dist/domain/managedMemberComparisonMatch.js +356 -0
  163. package/dist/domain/managedNativeVerification.js +27 -389
  164. package/dist/domain/managedNativeVerificationMatch.js +272 -0
  165. package/dist/domain/managedNativeVerificationSchemas.js +141 -0
  166. package/dist/domain/managedReconstruction.js +82 -69
  167. package/dist/domain/managedRuntimeCorrelation.js +12 -3
  168. package/dist/domain/nodeRuntimeCharacterization.js +66 -0
  169. package/dist/domain/permissionPolicy.js +2 -0
  170. package/dist/domain/processComparison.js +19 -0
  171. package/dist/domain/processPairedExperiment.js +128 -0
  172. package/dist/domain/reconstructionCoverage.js +387 -0
  173. package/dist/domain/reconstructionCoverageEvaluation.js +212 -0
  174. package/dist/domain/reconstructionVerificationSchemas.js +8 -0
  175. package/dist/domain/replayMachine.js +316 -0
  176. package/dist/domain/replayMachineRuntime.js +215 -0
  177. package/dist/domain/runtimeCharacterization.js +85 -0
  178. package/dist/domain/runtimeIdentification.js +210 -0
  179. package/dist/domain/webBundleAnalyzer.js +3 -409
  180. package/dist/domain/webBundleAnalyzerAst.js +77 -0
  181. package/dist/domain/webBundleAnalyzerInspection.js +307 -0
  182. package/dist/domain/webBundleAnalyzerResult.js +120 -0
  183. package/dist/dotnet/ManagedArtifactInspector.js +50 -29
  184. package/dist/dotnet/ManagedMemberInspector.js +51 -785
  185. package/dist/dotnet/ManagedMemberInspectorCore.js +297 -0
  186. package/dist/dotnet/ManagedMemberInstructionDecoder.js +427 -0
  187. package/dist/dotnet/ManagedMemberRows.js +120 -0
  188. package/dist/dotnet/ManagedMetadataInventory.js +42 -306
  189. package/dist/dotnet/ManagedMetadataInventoryRows.js +292 -0
  190. package/dist/dotnet/ManagedMetadataLayout.js +48 -111
  191. package/dist/dotnet/ManagedMetadataRowSizes.js +54 -0
  192. package/dist/dotnet/ManagedMethodBodyReader.js +143 -0
  193. package/dist/dotnet/ManagedNativeBoundaryHelpers.js +311 -0
  194. package/dist/dotnet/ManagedNativeBoundaryInspector.js +102 -350
  195. package/dist/dotnet/ManagedPeReader.js +59 -28
  196. package/dist/evaluation/CodexAgentEval.js +132 -0
  197. package/dist/generatedPackageMetadata.js +2 -2
  198. package/dist/ghidra/GhidraClient.js +76 -91
  199. package/dist/ghidra/GhidraClientStartup.js +29 -0
  200. package/dist/ghidra/GhidraClientWire.js +34 -0
  201. package/dist/ghidra/GhidraDefaults.js +1 -1
  202. package/dist/ghidra/GhidraDiagnostics.js +6 -1
  203. package/dist/ghidra/GhidraInstallation.js +20 -15
  204. package/dist/ghidra/GhidraLauncher.js +93 -29
  205. package/dist/ghidra/GhidraProvider.js +61 -161
  206. package/dist/ghidra/GhidraProviderCapabilities.js +173 -0
  207. package/dist/ghidra/GhidraSessionValues.js +2 -0
  208. package/dist/ghidra/GhidraSocketConnection.js +44 -7
  209. package/dist/ghidra/GhidraTargetSnapshot.js +30 -0
  210. package/dist/ghidra/GhidraTransport.js +71 -0
  211. package/dist/identity.js +4 -2
  212. package/dist/main/messages.js +5 -0
  213. package/dist/main/reload.js +49 -0
  214. package/dist/main/shutdown.js +25 -0
  215. package/dist/main/startup.js +14 -0
  216. package/dist/main/state.js +26 -0
  217. package/dist/main/transport.js +61 -0
  218. package/dist/main/types.js +1 -0
  219. package/dist/main.js +35 -146
  220. package/dist/process/PrivateRuntimeRoot.js +3 -2
  221. package/dist/process/ProcessOwnership.js +35 -0
  222. package/dist/process/ProviderProcess.js +2 -0
  223. package/dist/replay/JavaScriptReplayWorker.js +64 -50
  224. package/dist/replay/LinuxJavaScriptReplayRunner.js +173 -390
  225. package/dist/replay/LinuxJavaScriptReplaySandbox.js +140 -0
  226. package/dist/replay/ReplayOutcome.js +95 -0
  227. package/dist/replay/ReplayProcessLifecycle.js +71 -0
  228. package/dist/server/ProcessCaptureElicitation.js +157 -0
  229. package/dist/server/createServer.js +124 -56
  230. package/dist/server/javascriptApplicationResult.js +85 -0
  231. package/dist/server/registerApplicationTools/characterization.js +57 -0
  232. package/dist/server/registerApplicationTools/compareVersions.js +34 -0
  233. package/dist/server/registerApplicationTools/controlledReplay.js +38 -0
  234. package/dist/server/registerApplicationTools/coverage.js +84 -0
  235. package/dist/server/registerApplicationTools/helpers.js +42 -0
  236. package/dist/server/registerApplicationTools/traceFeature.js +26 -0
  237. package/dist/server/registerApplicationTools/types.js +1 -0
  238. package/dist/server/registerApplicationTools.js +10 -112
  239. package/dist/server/registerBrowserTools.js +59 -83
  240. package/dist/server/registerElectronTools.js +48 -49
  241. package/dist/server/registerEnhancedTools.js +34 -42
  242. package/dist/server/registerEvidenceResources.js +56 -0
  243. package/dist/server/registerInvestigationTools/helpers.js +74 -0
  244. package/dist/server/registerInvestigationTools/types.js +1 -0
  245. package/dist/server/registerInvestigationTools.js +83 -116
  246. package/dist/server/registerJavaScriptApplicationGraphResource.js +69 -0
  247. package/dist/server/registerManagedTools.js +18 -1
  248. package/dist/server/registerManagedWorkflowTools/compareManagedMembers.js +65 -0
  249. package/dist/server/registerManagedWorkflowTools/contract.js +8 -0
  250. package/dist/server/registerManagedWorkflowTools/evidence.js +43 -0
  251. package/dist/server/registerManagedWorkflowTools/importManagedReconstruction.js +39 -0
  252. package/dist/server/registerManagedWorkflowTools/planManagedRuntimeCorrelation.js +39 -0
  253. package/dist/server/registerManagedWorkflowTools/projectManagedApplicationGraph.js +52 -0
  254. package/dist/server/registerManagedWorkflowTools/types.js +1 -0
  255. package/dist/server/registerManagedWorkflowTools/verifyManagedNativeBoundaries.js +75 -0
  256. package/dist/server/registerManagedWorkflowTools.js +10 -274
  257. package/dist/server/registerOfficialTools.js +73 -59
  258. package/dist/server/registerSessionRecordTools.js +137 -0
  259. package/dist/server/registerSessionStatusTool.js +97 -26
  260. package/dist/server/registerSessionTools.js +60 -164
  261. package/dist/server/sessionAvailabilityPolicy.js +10 -0
  262. package/dist/server/toolRegistrationOptions.js +101 -3
  263. package/dist/server/toolResult.js +15 -4
  264. package/package.json +11 -11
  265. package/skills/reverse-engineer-anything/SKILL.md +76 -0
  266. package/skills/reverse-engineer-anything/references/controlled-replay.md +12 -0
  267. package/skills/reverse-engineer-anything/references/evidence-workflows.md +33 -0
  268. package/skills/reverse-engineer-anything/references/javascript-applications.md +25 -0
  269. package/skills/reverse-engineer-anything/references/native-and-artifacts.md +36 -0
  270. package/skills/reverse-engineer-anything/references/runtime-observation.md +24 -0
  271. package/scripts/prepare-node-pty.mjs +0 -35
  272. package/scripts/rebuild-native.mjs +0 -22
  273. package/skills/rea-analysis/SKILL.md +0 -222
@@ -1,7 +1,5 @@
1
- import { parse } from "@babel/parser";
2
- import * as t from "@babel/types";
3
- import { sanitizeBrowserUrl } from "./browserObservation.js";
4
- import { webBundleAnalysisSchema, } from "./webBundleAnalysis.js";
1
+ import { analyzeScript, emptyAccumulator, isIncludedScript, } from "./webBundleAnalyzerInspection.js";
2
+ import { buildWebBundleAnalysis } from "./webBundleAnalyzerResult.js";
5
3
  /** Analyze captured, explicitly approved JavaScript source without execution. */
6
4
  export const analyzeCapturedWebBundle = (inspection, input, sourceMaps = {
7
5
  status: "not_requested",
@@ -15,409 +13,5 @@ export const analyzeCapturedWebBundle = (inspection, input, sourceMaps = {
15
13
  const sourceScripts = inspection.scripts.items.filter(isIncludedScript);
16
14
  for (const script of sourceScripts)
17
15
  analyzeScript(script, input, accumulator);
18
- const unavailable = inspection.scripts.items
19
- .filter((script) => !script.source.included)
20
- .map(({ script_key }) => script_key);
21
- const sourceMapIncomplete = sourceMaps.status === "partial" || sourceMaps.status === "unavailable";
22
- const partial = accumulator.parseFailures > 0 ||
23
- unavailable.length > 0 ||
24
- sourceMapIncomplete;
25
- const truncated = accumulator.astLimitReached ||
26
- accumulator.droppedFindings > 0 ||
27
- sourceMaps.status === "truncated";
28
- return webBundleAnalysisSchema.parse({
29
- schema_version: 1,
30
- capture: {
31
- target_url: inspection.target.url,
32
- scripts_observed: inspection.scripts.total,
33
- scripts_analyzed: sourceScripts.length,
34
- source_artifacts: sourceScripts.map((script) => {
35
- if (!script.source.included)
36
- throw new TypeError("Filtered source changed");
37
- const { text: _text, ...artifact } = script.source.artifact;
38
- return { ...artifact, text_available: true };
39
- }),
40
- },
41
- observations: {
42
- chunks: {
43
- nodes: sourceScripts.map((script) => {
44
- if (!script.source.included)
45
- throw new TypeError("Filtered source changed");
46
- return {
47
- script_key: script.script_key,
48
- url: script.url,
49
- artifact_sha256: script.source.artifact.sha256,
50
- bytes: script.source.artifact.bytes,
51
- };
52
- }),
53
- edges: accumulator.edges,
54
- },
55
- routes: accumulator.routes,
56
- endpoints: accumulator.endpoints,
57
- webmcp_declarations: accumulator.webMcp,
58
- source_maps: sourceMaps,
59
- },
60
- inferences: accumulator.inferences,
61
- unknowns: [
62
- ...(unavailable.length === 0
63
- ? []
64
- : [
65
- {
66
- dimension: "script_source",
67
- reason: "Source artifact was not captured within approved limits",
68
- affected_script_keys: unavailable,
69
- },
70
- ]),
71
- ...(accumulator.parseFailures === 0
72
- ? []
73
- : [
74
- {
75
- dimension: "javascript_ast",
76
- reason: "One or more source artifacts could not be parsed",
77
- affected_script_keys: sourceScripts.map(({ script_key }) => script_key),
78
- },
79
- ]),
80
- ...(sourceMaps.status === "not_requested" ||
81
- sourceMaps.status === "included"
82
- ? []
83
- : [
84
- {
85
- dimension: "source_maps",
86
- reason: sourceMaps.status === "truncated"
87
- ? "Source-map evidence was truncated by approved limits"
88
- : "One or more requested source maps were unavailable or incomplete",
89
- affected_script_keys: [
90
- ...new Set([
91
- ...sourceMaps.items
92
- .filter(({ status }) => status !== "included")
93
- .map(({ script_key }) => script_key),
94
- ...sourceMaps.dropped_script_keys,
95
- ]),
96
- ].sort(),
97
- },
98
- ]),
99
- ],
100
- completeness: {
101
- status: truncated
102
- ? "truncated"
103
- : partial
104
- ? "partial"
105
- : "complete_within_limits",
106
- parsed_scripts: accumulator.parsedScripts,
107
- parse_failures: accumulator.parseFailures,
108
- visited_ast_nodes: accumulator.visitedNodes,
109
- dropped_findings: accumulator.droppedFindings,
110
- },
111
- limitations: [
112
- "Static bundle findings are observations or bounded inferences; REA does not execute captured JavaScript.",
113
- "String-built routes and endpoints, encrypted configuration, and server-side behavior may remain unknown.",
114
- "Page-declared WebMCP metadata is untrusted and is never registered or invoked as an REA tool.",
115
- ],
116
- });
16
+ return buildWebBundleAnalysis(inspection, sourceScripts, sourceMaps, accumulator);
117
17
  };
118
- const analyzeScript = (script, input, accumulator) => {
119
- let file;
120
- try {
121
- file = parse(script.source.artifact.text, {
122
- sourceType: "unambiguous",
123
- errorRecovery: true,
124
- plugins: ["jsx", "typescript"],
125
- });
126
- }
127
- catch {
128
- accumulator.parseFailures += 1;
129
- return;
130
- }
131
- accumulator.parsedScripts += 1;
132
- detectVendorFingerprints(script, accumulator, input.analysis_limits.max_findings);
133
- t.traverseFast(file, (node) => {
134
- accumulator.visitedNodes += 1;
135
- if (accumulator.visitedNodes > input.analysis_limits.max_ast_nodes) {
136
- accumulator.astLimitReached = true;
137
- return t.traverseFast.stop;
138
- }
139
- inspectNode(script, node, accumulator, input.analysis_limits.max_findings);
140
- return undefined;
141
- });
142
- };
143
- const inspectNode = (script, node, accumulator, maximumFindings) => {
144
- if ((t.isImportDeclaration(node) || t.isExportAllDeclaration(node)) &&
145
- node.source !== undefined)
146
- addEdge(script, node.source.value, "static_import", node, accumulator, maximumFindings);
147
- else if (t.isExportNamedDeclaration(node) && node.source != null)
148
- addEdge(script, node.source.value, "static_import", node, accumulator, maximumFindings);
149
- else if (t.isImportExpression(node) && t.isStringLiteral(node.source))
150
- addEdge(script, node.source.value, "dynamic_import", node, accumulator, maximumFindings);
151
- if (t.isObjectProperty(node))
152
- inspectRouteProperty(script, node, accumulator, maximumFindings);
153
- if (t.isCallExpression(node) || t.isNewExpression(node))
154
- inspectCall(script, node, accumulator, maximumFindings);
155
- };
156
- const inspectCall = (script, node, accumulator, maximumFindings) => {
157
- const name = calleeName(node.callee);
158
- const first = stringArgument(node.arguments[0]);
159
- if ((name === "require" || name.endsWith(".require")) && first !== undefined)
160
- addEdge(script, first, "require", node, accumulator, maximumFindings);
161
- if ((name === "importScripts" || name.endsWith(".importScripts")) &&
162
- first !== undefined)
163
- addEdge(script, first, "worker_import", node, accumulator, maximumFindings);
164
- if (routeCallNames.some((candidate) => name === candidate || name.endsWith(`.${candidate}`))) {
165
- if (first !== undefined)
166
- addFinding(accumulator.routes, script, first, `call:${name}`, node, accumulator, maximumFindings);
167
- addRouteFrameworkInference(script, name, node, accumulator, maximumFindings);
168
- }
169
- const endpoint = endpointArgument(name, node.arguments);
170
- if (endpoint !== undefined)
171
- addFinding(accumulator.endpoints, script, endpoint, `call:${name}`, node, accumulator, maximumFindings);
172
- if (name.endsWith("modelContext.registerTool") ||
173
- name === "modelContext.registerTool")
174
- addWebMcpDeclaration(script, node, accumulator, maximumFindings);
175
- };
176
- const inspectRouteProperty = (script, node, accumulator, maximumFindings) => {
177
- const key = propertyName(node.key);
178
- if ((key === "path" || key === "route") && t.isStringLiteral(node.value))
179
- addFinding(accumulator.routes, script, node.value.value, `property:${key}`, node, accumulator, maximumFindings);
180
- };
181
- const addEdge = (script, specifier, kind, node, accumulator, maximumFindings) => {
182
- const bounded = specifier.slice(0, 4_096);
183
- const key = `edge\0${script.script_key}\0${kind}\0${bounded}`;
184
- addBounded(accumulator, key, maximumFindings, () => accumulator.edges.push({
185
- from_script_key: script.script_key,
186
- kind,
187
- specifier: bounded,
188
- resolved_url: resolveSpecifier(bounded, script.url),
189
- location: location(script.script_key, node),
190
- }));
191
- };
192
- const addFinding = (collection, script, rawValue, mechanism, node, accumulator, maximumFindings) => {
193
- const value = sanitizeCandidate(rawValue);
194
- const key = `finding\0${mechanism}\0${script.script_key}\0${value}`;
195
- addBounded(accumulator, key, maximumFindings, () => collection.push({
196
- value,
197
- mechanism,
198
- location: location(script.script_key, node),
199
- }));
200
- };
201
- const addWebMcpDeclaration = (script, node, accumulator, maximumFindings) => {
202
- const declaration = node.arguments[0];
203
- if (!t.isObjectExpression(declaration))
204
- return;
205
- const name = objectString(declaration, "name");
206
- const description = objectString(declaration, "description");
207
- const schema = objectValue(declaration, "inputSchema") ??
208
- objectValue(declaration, "input_schema");
209
- const declaredProperties = t.isObjectExpression(schema)
210
- ? objectValue(schema, "properties")
211
- : undefined;
212
- const propertyObject = t.isObjectExpression(declaredProperties)
213
- ? declaredProperties
214
- : schema;
215
- const schemaPropertyNames = t.isObjectExpression(propertyObject)
216
- ? propertyObject.properties.flatMap((property) => t.isObjectProperty(property)
217
- ? [propertyName(property.key)].filter(Boolean)
218
- : [])
219
- : [];
220
- const key = `webmcp\0${script.script_key}\0${name ?? ""}\0${schemaPropertyNames.join("\0")}`;
221
- addBounded(accumulator, key, maximumFindings, () => accumulator.webMcp.push({
222
- name: name?.slice(0, 256) ?? null,
223
- description: description?.slice(0, 2_048) ?? null,
224
- schema_property_names: [...new Set(schemaPropertyNames)]
225
- .sort()
226
- .slice(0, 256),
227
- trust: "page-declared-untrusted",
228
- location: location(script.script_key, node),
229
- }));
230
- };
231
- const detectVendorFingerprints = (script, accumulator, maximumFindings) => {
232
- const text = script.source.artifact.text;
233
- for (const detector of vendorDetectors) {
234
- if (!detector.patterns.some((pattern) => text.includes(pattern)))
235
- continue;
236
- const key = `vendor\0${script.script_key}\0${detector.value}`;
237
- addBounded(accumulator, key, maximumFindings, () => accumulator.inferences.push({
238
- kind: detector.kind,
239
- value: detector.value,
240
- confidence: detector.confidence,
241
- basis: [basis(script, detector.detector)],
242
- }));
243
- }
244
- };
245
- const addRouteFrameworkInference = (script, name, node, accumulator, maximumFindings) => {
246
- const value = name.endsWith("useRoutes") || name.endsWith("createBrowserRouter")
247
- ? "React Router-compatible route API"
248
- : "Generic route registration API";
249
- const key = `route-framework\0${script.script_key}\0${value}`;
250
- addBounded(accumulator, key, maximumFindings, () => accumulator.inferences.push({
251
- kind: "route_framework",
252
- value,
253
- confidence: "medium",
254
- basis: [{ ...basis(script, `call:${name}`), ...locationFields(node) }],
255
- }));
256
- };
257
- const addBounded = (accumulator, key, maximum, add) => {
258
- if (accumulator.seen.has(key))
259
- return;
260
- const findings = accumulator.edges.length +
261
- accumulator.routes.length +
262
- accumulator.endpoints.length +
263
- accumulator.webMcp.length +
264
- accumulator.inferences.length;
265
- if (findings >= maximum) {
266
- accumulator.droppedFindings += 1;
267
- return;
268
- }
269
- accumulator.seen.add(key);
270
- add();
271
- };
272
- const endpointArgument = (name, args) => {
273
- if (name === "fetch" || name.endsWith(".fetch") || name === "WebSocket")
274
- return stringArgument(args[0]);
275
- if (name.endsWith(".open") && stringArgument(args[1]) !== undefined)
276
- return stringArgument(args[1]);
277
- if (["get", "post", "put", "patch", "delete", "request"].some((method) => name === method || name.endsWith(`.${method}`)))
278
- return stringArgument(args[0]);
279
- return undefined;
280
- };
281
- const calleeName = (callee) => {
282
- if (t.isIdentifier(callee))
283
- return callee.name;
284
- if (t.isImport(callee))
285
- return "import";
286
- if (t.isMemberExpression(callee) || t.isOptionalMemberExpression(callee)) {
287
- const object = t.isExpression(callee.object)
288
- ? calleeName(callee.object)
289
- : "";
290
- const property = propertyName(callee.property);
291
- return object === "" ? property : `${object}.${property}`;
292
- }
293
- return "";
294
- };
295
- const stringArgument = (value) => (t.isStringLiteral(value) ? value.value : undefined);
296
- const propertyName = (value) => {
297
- if (t.isIdentifier(value))
298
- return value.name;
299
- if (t.isStringLiteral(value))
300
- return value.value;
301
- return "";
302
- };
303
- const objectValue = (object, name) => {
304
- for (const property of object.properties)
305
- if (t.isObjectProperty(property) && propertyName(property.key) === name)
306
- return property.value;
307
- return undefined;
308
- };
309
- const objectString = (object, name) => {
310
- const value = objectValue(object, name);
311
- return t.isStringLiteral(value) ? value.value : undefined;
312
- };
313
- const resolveSpecifier = (specifier, base) => {
314
- try {
315
- const resolved = new URL(specifier, base);
316
- if (resolved.protocol !== "http:" && resolved.protocol !== "https:")
317
- return null;
318
- return sanitizeBrowserUrl(resolved.href).url;
319
- }
320
- catch {
321
- return null;
322
- }
323
- };
324
- const sanitizeCandidate = (value) => {
325
- const bounded = value.slice(0, 4_096);
326
- try {
327
- const parsed = new URL(bounded, "https://rea.invalid");
328
- const sanitized = sanitizeBrowserUrl(parsed.href).url;
329
- return parsed.origin === "https://rea.invalid"
330
- ? sanitized.replace("https://rea.invalid", "")
331
- : sanitized;
332
- }
333
- catch {
334
- return bounded.split("#", 1)[0]?.split("?", 1)[0] ?? "";
335
- }
336
- };
337
- const location = (scriptKey, node) => ({
338
- script_key: scriptKey,
339
- ...locationFields(node),
340
- });
341
- const locationFields = (node) => ({
342
- line: node.loc?.start.line ?? null,
343
- column: node.loc?.start.column ?? null,
344
- });
345
- const basis = (script, detector) => ({
346
- script_key: script.script_key,
347
- artifact_sha256: script.source.artifact.sha256,
348
- line: null,
349
- column: null,
350
- detector,
351
- });
352
- const emptyAccumulator = () => ({
353
- edges: [],
354
- routes: [],
355
- endpoints: [],
356
- webMcp: [],
357
- inferences: [],
358
- seen: new Set(),
359
- visitedNodes: 0,
360
- parsedScripts: 0,
361
- parseFailures: 0,
362
- droppedFindings: 0,
363
- astLimitReached: false,
364
- });
365
- const isIncludedScript = (script) => script.source.included;
366
- const routeCallNames = [
367
- "route",
368
- "addRoute",
369
- "useRoutes",
370
- "createBrowserRouter",
371
- "createHashRouter",
372
- ];
373
- const vendorDetectors = [
374
- {
375
- value: "webpack",
376
- detector: "webpack-runtime",
377
- patterns: ["__webpack_require__"],
378
- confidence: "high",
379
- kind: "bundle_runtime",
380
- },
381
- {
382
- value: "Vite",
383
- detector: "vite-runtime",
384
- patterns: ["__vite__", "import.meta.hot"],
385
- confidence: "medium",
386
- kind: "bundle_runtime",
387
- },
388
- {
389
- value: "React",
390
- detector: "react-runtime",
391
- patterns: ["__REACT_DEVTOOLS_GLOBAL_HOOK__", "React.createElement"],
392
- confidence: "medium",
393
- kind: "vendor_fingerprint",
394
- },
395
- {
396
- value: "Vue",
397
- detector: "vue-runtime",
398
- patterns: ["__VUE__", "createApp("],
399
- confidence: "medium",
400
- kind: "vendor_fingerprint",
401
- },
402
- {
403
- value: "Next.js",
404
- detector: "next-runtime",
405
- patterns: ["__NEXT_DATA__", "/_next/"],
406
- confidence: "high",
407
- kind: "vendor_fingerprint",
408
- },
409
- {
410
- value: "Angular",
411
- detector: "angular-runtime",
412
- patterns: ["ɵɵdefineComponent"],
413
- confidence: "high",
414
- kind: "vendor_fingerprint",
415
- },
416
- {
417
- value: "Svelte",
418
- detector: "svelte-runtime",
419
- patterns: ["svelte/internal"],
420
- confidence: "medium",
421
- kind: "vendor_fingerprint",
422
- },
423
- ];
@@ -0,0 +1,77 @@
1
+ import * as t from "@babel/types";
2
+ import { sanitizeBrowserUrl } from "./browserObservation.js";
3
+ /** Name of a call/new callee from its AST node. */
4
+ export const calleeName = (callee) => {
5
+ if (t.isIdentifier(callee))
6
+ return callee.name;
7
+ if (t.isImport(callee))
8
+ return "import";
9
+ if (t.isMemberExpression(callee) || t.isOptionalMemberExpression(callee)) {
10
+ const object = t.isExpression(callee.object)
11
+ ? calleeName(callee.object)
12
+ : "";
13
+ const property = propertyName(callee.property);
14
+ return object === "" ? property : `${object}.${property}`;
15
+ }
16
+ return "";
17
+ };
18
+ export const stringArgument = (value) => (t.isStringLiteral(value) ? value.value : undefined);
19
+ export const propertyName = (value) => {
20
+ if (t.isIdentifier(value))
21
+ return value.name;
22
+ if (t.isStringLiteral(value))
23
+ return value.value;
24
+ return "";
25
+ };
26
+ export const objectValue = (object, name) => {
27
+ for (const property of object.properties)
28
+ if (t.isObjectProperty(property) && propertyName(property.key) === name)
29
+ return property.value;
30
+ return undefined;
31
+ };
32
+ export const objectString = (object, name) => {
33
+ const value = objectValue(object, name);
34
+ return t.isStringLiteral(value) ? value.value : undefined;
35
+ };
36
+ export const resolveSpecifier = (specifier, base) => {
37
+ try {
38
+ const resolved = new URL(specifier, base);
39
+ if (resolved.protocol !== "http:" && resolved.protocol !== "https:")
40
+ return null;
41
+ return sanitizeBrowserUrl(resolved.href).url;
42
+ }
43
+ catch {
44
+ return null;
45
+ }
46
+ };
47
+ export const sanitizeCandidate = (value) => {
48
+ const bounded = value.slice(0, 4_096);
49
+ try {
50
+ const parsed = new URL(bounded, "https://rea.invalid");
51
+ const sanitized = sanitizeBrowserUrl(parsed.href).url;
52
+ return parsed.origin === "https://rea.invalid"
53
+ ? sanitized.replace("https://rea.invalid", "")
54
+ : sanitized;
55
+ }
56
+ catch {
57
+ return bounded.split("#", 1)[0]?.split("?", 1)[0] ?? "";
58
+ }
59
+ };
60
+ export const location = (scriptKey, node) => ({
61
+ script_key: scriptKey,
62
+ ...locationFields(node),
63
+ });
64
+ export const locationFields = (node) => ({
65
+ line: node.loc?.start.line ?? null,
66
+ column: node.loc?.start.column ?? null,
67
+ });
68
+ /** Pick the endpoint argument for common network-call patterns. */
69
+ export const endpointArgument = (name, args) => {
70
+ if (name === "fetch" || name.endsWith(".fetch") || name === "WebSocket")
71
+ return stringArgument(args[0]);
72
+ if (name.endsWith(".open") && stringArgument(args[1]) !== undefined)
73
+ return stringArgument(args[1]);
74
+ if (["get", "post", "put", "patch", "delete", "request"].some((method) => name === method || name.endsWith(`.${method}`)))
75
+ return stringArgument(args[0]);
76
+ return undefined;
77
+ };