@oneuptime/common 12.0.33 → 12.0.34

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 (652) hide show
  1. package/Models/AnalyticsModels/RumSession.ts +117 -1
  2. package/Models/AnalyticsModels/RumSessionChunk.ts +13 -0
  3. package/Models/DatabaseModels/AlertCustomField.ts +77 -3
  4. package/Models/DatabaseModels/ApiKeyPermission.ts +3 -27
  5. package/Models/DatabaseModels/IncidentCustomField.ts +77 -3
  6. package/Models/DatabaseModels/InventoryItemCustomField.ts +77 -3
  7. package/Models/DatabaseModels/MonitorCustomField.ts +77 -3
  8. package/Models/DatabaseModels/OnCallDutyPolicyCustomField.ts +77 -3
  9. package/Models/DatabaseModels/RumApplication.ts +6 -6
  10. package/Models/DatabaseModels/ScheduledMaintenanceCustomField.ts +77 -3
  11. package/Models/DatabaseModels/StatusPageCustomField.ts +77 -3
  12. package/Models/DatabaseModels/TeamCustomField.ts +77 -3
  13. package/Models/DatabaseModels/TeamMember.ts +0 -9
  14. package/Models/DatabaseModels/TeamMemberCustomField.ts +77 -3
  15. package/Models/DatabaseModels/TeamPermission.ts +3 -24
  16. package/Models/DatabaseModels/TelemetryIngestionKey.ts +260 -0
  17. package/Models/DatabaseModels/UserTelegram.ts +0 -4
  18. package/Scripts/benchmark-fanin-capacity.js +181 -0
  19. package/Server/API/TelemetryAPI.ts +1284 -164
  20. package/Server/API/UserNotificationSettingAPI.ts +55 -0
  21. package/Server/API/UserTelegramAPI.ts +48 -4
  22. package/Server/EnvironmentConfig.ts +35 -2
  23. package/Server/Infrastructure/Postgres/SchemaMigrations/1791300000000-AddTelemetryIngestionKeyType.ts +91 -0
  24. package/Server/Infrastructure/Postgres/SchemaMigrations/1791400000000-SessionReplayRecordEverySessionByDefault.ts +67 -0
  25. package/Server/Infrastructure/Postgres/SchemaMigrations/1791500000000-WidenCustomFieldDropdownOptions.ts +139 -0
  26. package/Server/Infrastructure/Postgres/SchemaMigrations/1791600000000-AddCustomFieldValueMapping.ts +121 -0
  27. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +8 -0
  28. package/Server/Infrastructure/QueueWorker.ts +20 -14
  29. package/Server/Infrastructure/Semaphore.ts +2 -0
  30. package/Server/Middleware/TelemetryIngest.ts +453 -7
  31. package/Server/Services/AccessTokenService.ts +1 -0
  32. package/Server/Services/AlertCustomFieldService.ts +98 -0
  33. package/Server/Services/AlertService.ts +37 -0
  34. package/Server/Services/ApiKeyPermissionService.ts +461 -29
  35. package/Server/Services/CustomFieldMappingService.ts +879 -0
  36. package/Server/Services/GlobalConfigService.ts +194 -0
  37. package/Server/Services/IncidentCustomFieldService.ts +98 -0
  38. package/Server/Services/IncidentService.ts +35 -0
  39. package/Server/Services/MetricService.ts +194 -0
  40. package/Server/Services/MonitorService.ts +32 -0
  41. package/Server/Services/NetworkDeviceAutoImportRuleEngineService.ts +78 -25
  42. package/Server/Services/ProjectService.ts +22 -0
  43. package/Server/Services/RoutineEmailSettingsService.ts +73 -0
  44. package/Server/Services/RumSessionReplayViewService.ts +104 -24
  45. package/Server/Services/ScheduledMaintenanceCustomFieldService.ts +98 -0
  46. package/Server/Services/ScheduledMaintenanceService.ts +32 -0
  47. package/Server/Services/TeamMemberService.ts +78 -0
  48. package/Server/Services/TeamPermissionService.ts +235 -3
  49. package/Server/Services/TelemetryIngestionKeyService.ts +722 -19
  50. package/Server/Services/UserNotificationSettingService.ts +34 -6
  51. package/Server/Services/UserTelegramService.ts +326 -5
  52. package/Server/Types/Database/QueryHelper.ts +2 -0
  53. package/Server/Utils/APIKey/AccessPermission.ts +5 -2
  54. package/Server/Utils/CustomField/CustomFieldDefinitionMappingHooks.ts +54 -0
  55. package/Server/Utils/CustomField/CustomFieldMappingRegistry.ts +415 -0
  56. package/Server/Utils/CustomField/CustomFieldMappingValidator.ts +335 -0
  57. package/Server/Utils/DataSource/EgressGuard.ts +177 -8
  58. package/Server/Utils/EmailRollup/EmailRollupConstants.ts +38 -5
  59. package/Server/Utils/EmailRollup/EmailRollupFlushRunner.ts +57 -4
  60. package/Server/Utils/FrontendEnvironment.ts +40 -0
  61. package/Server/Utils/LogRedaction.ts +20 -0
  62. package/Server/Utils/Logger.ts +11 -0
  63. package/Server/Utils/Monitor/Criteria/CompareCriteria.ts +338 -77
  64. package/Server/Utils/Monitor/Criteria/IncomingRequestCriteria.ts +30 -4
  65. package/Server/Utils/Monitor/MonitorAlert.ts +29 -6
  66. package/Server/Utils/Monitor/MonitorCriteriaEvaluator.ts +110 -15
  67. package/Server/Utils/Monitor/MonitorIncident.ts +22 -6
  68. package/Server/Utils/Monitor/MonitorTemplateUtil.ts +29 -0
  69. package/Server/Utils/Monitor/SeriesContextEnricher.ts +304 -0
  70. package/Server/Utils/SSRFProtection.ts +217 -10
  71. package/Server/Utils/SessionReplay/SessionReplayGateCache.ts +239 -138
  72. package/Server/Utils/SessionReplay/SessionReplayHealthCounters.ts +305 -0
  73. package/Server/Utils/SessionReplay/SessionReplayReadService.ts +1430 -289
  74. package/Server/Utils/StartServer.ts +2 -17
  75. package/Server/Utils/TelegramVerificationToken.ts +185 -0
  76. package/Server/Utils/Telemetry/PinServiceName.ts +197 -0
  77. package/Server/Utils/Telemetry/TelemetryFanInWriter.ts +38 -16
  78. package/Server/Utils/Telemetry/TelemetryIngestionKeyGuard.ts +92 -0
  79. package/Server/Utils/Telemetry/TelemetryIngestionKeyRateLimiter.ts +217 -0
  80. package/Server/Utils/VM/VMAPI.ts +1 -0
  81. package/Server/Utils/VM/VMRunner.ts +975 -95
  82. package/Tests/App/AdminDashboard/AdminHeaderSmallScreens.test.tsx +202 -0
  83. package/Tests/App/Dashboard/DashboardHeaderSmallScreens.test.tsx +404 -0
  84. package/Tests/App/Dashboard/DiscoveryScanWizardValidation.test.tsx +468 -0
  85. package/Tests/App/Dashboard/NotificationEmailPreferences.test.tsx +399 -0
  86. package/Tests/App/StatusPage/StatusPageLastUpdated.test.tsx +263 -0
  87. package/Tests/App/StatusPage/StatusPageOverviewLiveAndSearch.test.tsx +753 -0
  88. package/Tests/App/StatusPage/StatusPageResourceSearchBox.test.tsx +224 -0
  89. package/Tests/Models/AnalyticsModels/RumSessionReplayColumns.test.ts +262 -0
  90. package/Tests/Models/CustomFieldMappingColumns.test.ts +166 -0
  91. package/Tests/Models/DatabaseModels/SessionReplayModels.test.ts +20 -6
  92. package/Tests/ResponsiveVisibility.test.ts +115 -0
  93. package/Tests/ResponsiveVisibility.ts +183 -0
  94. package/Tests/Server/API/SessionReplayAPI.test.ts +1940 -216
  95. package/Tests/Server/API/UserNotificationSettingAPI.test.ts +186 -0
  96. package/Tests/Server/API/UserTelegramAPISecurity.test.ts +231 -0
  97. package/Tests/Server/EnvironmentConfigFrontendSecurity.test.ts +234 -0
  98. package/Tests/Server/Infrastructure/Postgres/CustomFieldValueMappingMigration.test.ts +202 -0
  99. package/Tests/Server/Infrastructure/Postgres/InventoryItemArchiveMigration.test.ts +41 -0
  100. package/Tests/Server/Infrastructure/Postgres/SessionReplayRecordEverySessionByDefaultMigration.test.ts +169 -0
  101. package/Tests/Server/Infrastructure/QueueWorkerTimeout.test.ts +210 -0
  102. package/Tests/Server/Infrastructure/TelemetryExporterDeploymentConfig.test.ts +130 -0
  103. package/Tests/Server/Middleware/ProjectAuthorizationApiKeyMiddleware.test.ts +4 -1
  104. package/Tests/Server/Middleware/TelemetryIngestBrowserKey.test.ts +1163 -0
  105. package/Tests/Server/Middleware/TelemetryIngestTokenLog.test.ts +5 -3
  106. package/Tests/Server/Services/AddTelemetryIngestionKeyTypeMigration.test.ts +555 -0
  107. package/Tests/Server/Services/ApiKeyPermissionSecurity.test.ts +678 -0
  108. package/Tests/Server/Services/ApiKeyPermissionService.test.ts +276 -28
  109. package/Tests/Server/Services/CustomFieldDropdownOptionsColumnWidth.test.ts +431 -0
  110. package/Tests/Server/Services/CustomFieldMappingService.test.ts +850 -0
  111. package/Tests/Server/Services/DiscoveryScanClaimHookFreeSafety.test.ts +32 -0
  112. package/Tests/Server/Services/GlobalConfigService.test.ts +414 -1
  113. package/Tests/Server/Services/MetricRawEntityKeyPrune.test.ts +592 -0
  114. package/Tests/Server/Services/NetworkDeviceAutoImportRuleEngineService.test.ts +226 -1
  115. package/Tests/Server/Services/RoutineEmailSettingsPostgres.test.ts +329 -0
  116. package/Tests/Server/Services/RumSessionReplayViewService.test.ts +267 -0
  117. package/Tests/Server/Services/TeamMemberAutoAcceptInvitation.test.ts +9 -0
  118. package/Tests/Server/Services/TeamMemberInviteRegistrationToken.test.ts +9 -0
  119. package/Tests/Server/Services/TeamPrivilegeEscalation.test.ts +834 -0
  120. package/Tests/Server/Services/TelemetryIngestionKeyPolicyResolution.test.ts +814 -0
  121. package/Tests/Server/Services/TelemetryIngestionKeyValidation.test.ts +998 -0
  122. package/Tests/Server/Services/UserNotificationSettingRollupRouting.test.ts +141 -0
  123. package/Tests/Server/Services/UserNotificationSettingWorkspaceChannels.test.ts +18 -10
  124. package/Tests/Server/Services/UserTelegramVerificationSecurity.test.ts +688 -0
  125. package/Tests/Server/Utils/AI/SRE/Insights/FixRouting.test.ts +497 -0
  126. package/Tests/Server/Utils/AI/Toolbox/Serializer.test.ts +383 -0
  127. package/Tests/Server/Utils/APIKey/AccessPermission.test.ts +7 -3
  128. package/Tests/Server/Utils/AnalyticsDatabase/ClusterConfig.test.ts +315 -0
  129. package/Tests/Server/Utils/CustomField/CustomFieldMappingValidator.test.ts +437 -0
  130. package/Tests/Server/Utils/DataSource/EgressGuard.test.ts +300 -11
  131. package/Tests/Server/Utils/EmailRollup/EmailRollupBurstWindow.test.ts +83 -0
  132. package/Tests/Server/Utils/EmailRollup/EmailRollupFlushRunnerBehaviour.test.ts +1 -1
  133. package/Tests/Server/Utils/EmailRollup/EmailRollupFlushRunnerPreferences.test.ts +362 -0
  134. package/Tests/Server/Utils/EmailRollup/EmailRollupTestHarness.ts +77 -1
  135. package/Tests/Server/Utils/FrontendEnvironment.test.ts +190 -0
  136. package/Tests/Server/Utils/LogRedaction.test.ts +26 -0
  137. package/Tests/Server/Utils/LoggerCredentialLeak.test.ts +23 -9
  138. package/Tests/Server/Utils/Monitor/Criteria/CompareCriteriaAggregation.test.ts +584 -0
  139. package/Tests/Server/Utils/Monitor/Criteria/IncomingRequestHeaderCriteria.test.ts +236 -0
  140. package/Tests/Server/Utils/Monitor/MonitorCriteriaEvaluator.test.ts +437 -0
  141. package/Tests/Server/Utils/Monitor/MonitorTemplateUtilSeriesContext.test.ts +176 -0
  142. package/Tests/Server/Utils/Monitor/SeriesContextEnricher.test.ts +356 -0
  143. package/Tests/Server/Utils/SSRFProtectionCloudServiceAddresses.test.ts +595 -0
  144. package/Tests/Server/Utils/SessionReplay/SessionReplayGateCachePolicy.test.ts +198 -1
  145. package/Tests/Server/Utils/SessionReplay/SessionReplayHealthCounters.test.ts +453 -0
  146. package/Tests/Server/Utils/SessionReplay/SessionReplayReadServiceQueries.test.ts +1378 -0
  147. package/Tests/Server/Utils/SessionReplayOriginAllowListRefactor.test.ts +420 -0
  148. package/Tests/Server/Utils/TelegramVerificationToken.test.ts +253 -0
  149. package/Tests/Server/Utils/Telemetry/PinServiceName.test.ts +666 -0
  150. package/Tests/Server/Utils/Telemetry/TelemetryFanInWriterCapacity.test.ts +458 -0
  151. package/Tests/Server/Utils/Telemetry/TelemetryIngestionKeyGuard.test.ts +424 -0
  152. package/Tests/Server/Utils/Telemetry/TelemetryIngestionKeyRateLimiter.test.ts +528 -0
  153. package/Tests/Server/Utils/TelemetryExporterEnvironment.test.ts +56 -0
  154. package/Tests/Server/Utils/VM/VMRunnerHostBridgeLatency.test.ts +74 -0
  155. package/Tests/Server/Utils/VM/VMRunnerPrivateNetworkWiring.test.ts +100 -7
  156. package/Tests/Server/Utils/VM/VMRunnerSsrf.test.ts +1176 -6
  157. package/Tests/Types/CustomField/CustomFieldMappingCatalog.test.ts +220 -0
  158. package/Tests/Types/CustomField/CustomFieldValueMapping.test.ts +348 -0
  159. package/Tests/Types/JSONFunctions.test.ts +260 -0
  160. package/Tests/Types/Monitor/CephAlertTemplates.test.ts +422 -53
  161. package/Tests/Types/Monitor/DockerAlertTemplates.test.ts +495 -15
  162. package/Tests/Types/Monitor/DockerSwarmAlertTemplates.test.ts +191 -45
  163. package/Tests/Types/Monitor/HostAlertTemplates.test.ts +370 -42
  164. package/Tests/Types/Monitor/IotAlertTemplates.test.ts +375 -20
  165. package/Tests/Types/Monitor/KubernetesAlertTemplates.test.ts +636 -42
  166. package/Tests/Types/Monitor/KubernetesMetricCatalog.test.ts +189 -0
  167. package/Tests/Types/Monitor/KubernetesTemplateGroupByKeys.test.ts +95 -14
  168. package/Tests/Types/Monitor/PodmanAlertTemplates.test.ts +190 -21
  169. package/Tests/Types/Monitor/ProxmoxAlertTemplates.test.ts +352 -22
  170. package/Tests/Types/Monitor/Recommendation/MonitorRecommendationAlertDebuggability.test.ts +363 -0
  171. package/Tests/Types/Monitor/Recommendation/MonitorRecommendationNotificationMode.test.ts +93 -18
  172. package/Tests/Types/Monitor/Recommendation/MonitorRecommendationSeverityMapper.test.ts +259 -0
  173. package/Tests/Types/Monitor/Recommendation/RecommendationCriteriaBuilder.test.ts +476 -0
  174. package/Tests/Types/Monitor/RumAlertTemplates.test.ts +136 -0
  175. package/Tests/Types/Monitor/SeriesContext/SeriesDebugHints.test.ts +661 -0
  176. package/Tests/Types/Monitor/SeriesContext/SeriesLabelDisplay.test.ts +507 -0
  177. package/Tests/Types/Monitor/ServiceAlertTemplates.test.ts +270 -0
  178. package/Tests/Types/Monitor/TemplateGroupByKeys.test.ts +38 -10
  179. package/Tests/Types/Monitor/Utils/RecommendationCriteriaAssertions.ts +102 -0
  180. package/Tests/Types/NotificationSetting/RoutineEmailEvents.test.ts +47 -0
  181. package/Tests/Types/Rum/SessionReplayApiContracts.test.ts +608 -0
  182. package/Tests/Types/Rum/SessionReplayCustomEvents.test.ts +434 -0
  183. package/Tests/Types/WebsiteRequest.test.ts +285 -3
  184. package/Tests/UI/Components/Charts/ChartBucketIdentity.test.ts +16 -3
  185. package/Tests/UI/Components/Charts/ChartTrailingBucketGap.test.ts +691 -0
  186. package/Tests/UI/Components/ComponentsModal.test.tsx +12 -4
  187. package/Tests/UI/Components/ComponentsModalUsability.test.tsx +518 -0
  188. package/Tests/UI/Components/CustomFields/CustomFieldsDetailMapping.test.tsx +324 -0
  189. package/Tests/UI/Components/CustomFields/MapFromCustomFieldInput.test.tsx +176 -0
  190. package/Tests/UI/Components/Graphs/DayUptimeGraph.test.tsx +484 -0
  191. package/Tests/UI/Components/HeaderRightRail.test.tsx +157 -0
  192. package/Tests/UI/Components/IconDropdownItem.test.tsx +102 -0
  193. package/Tests/UI/Components/JSONTablePrototypePollution.test.tsx +117 -0
  194. package/Tests/UI/Components/KeyboardShortcutsModal.test.tsx +214 -0
  195. package/Tests/UI/Components/ModelTable/ModelTableWrapContent.test.tsx +561 -0
  196. package/Tests/UI/Components/MonitorGraphs/UptimeBarDayModal.test.tsx +302 -0
  197. package/Tests/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.test.ts +28 -12
  198. package/Tests/UI/Components/ShortcutDialogGuard.test.tsx +74 -0
  199. package/Tests/UI/Components/StatusPage/ResourceGroupSectionAutoExpand.test.tsx +248 -0
  200. package/Tests/UI/Components/TableCellWrapping.test.tsx +625 -0
  201. package/Tests/UI/Components/TableLoadingStates.test.tsx +205 -0
  202. package/Tests/UI/Components/Workflow/NodePlacement.test.ts +148 -0
  203. package/Tests/UI/Components/Workflow/Workflow.test.tsx +981 -0
  204. package/Tests/UI/ConfigBrowserTelemetry.test.ts +70 -0
  205. package/Tests/UI/Rum/ChunkLoader.test.ts +1036 -2
  206. package/Tests/UI/Rum/FidelityNotices.test.ts +187 -0
  207. package/Tests/UI/Rum/InactivityMap.test.ts +341 -0
  208. package/Tests/UI/Rum/PrivacySummaryCard.test.tsx +259 -0
  209. package/Tests/UI/Rum/RecordingHealthCard.test.tsx +855 -0
  210. package/Tests/UI/Rum/RecordingHealthStrip.test.tsx +594 -0
  211. package/Tests/UI/Rum/ReplayCard.test.tsx +451 -0
  212. package/Tests/UI/Rum/ReplayCorrelationPanel.test.tsx +536 -0
  213. package/Tests/UI/Rum/ReplayEngine.test.ts +2503 -0
  214. package/Tests/UI/Rum/ReplayEngineTypes.test.ts +171 -0
  215. package/Tests/UI/Rum/ReplayHeader.test.tsx +711 -0
  216. package/Tests/UI/Rum/ReplayLink.test.tsx +119 -0
  217. package/Tests/UI/Rum/ReplayPinControl.test.tsx +408 -0
  218. package/Tests/UI/Rum/ReplayPlaybackIntent.test.ts +152 -0
  219. package/Tests/UI/Rum/ReplayRail.test.tsx +1296 -0
  220. package/Tests/UI/Rum/ReplayRailDetail.test.tsx +900 -0
  221. package/Tests/UI/Rum/ReplayScrubber.test.tsx +763 -147
  222. package/Tests/UI/Rum/ReplaySignalTypes.test.ts +189 -0
  223. package/Tests/UI/Rum/ReplaySignals.test.ts +1579 -0
  224. package/Tests/UI/Rum/ReplayStage.test.tsx +396 -473
  225. package/Tests/UI/Rum/ReplayStageOverlays.test.tsx +918 -0
  226. package/Tests/UI/Rum/ReplayTimeline.test.tsx +696 -0
  227. package/Tests/UI/Rum/SessionReplayEmptyState.test.tsx +499 -0
  228. package/Tests/UI/Rum/SessionReplaySearchBar.test.tsx +346 -0
  229. package/Tests/UI/Rum/SessionReplaySetupGuide.test.tsx +545 -0
  230. package/Tests/UI/Rum/SessionReplayTable.test.tsx +991 -0
  231. package/Tests/UI/Rum/TargetedCapturePanel.test.tsx +254 -0
  232. package/Tests/UI/Telemetry/BrowserExporterIsolation.test.ts +71 -0
  233. package/Tests/UI/Utils/GlobalKeyboardShortcut.test.ts +344 -0
  234. package/Tests/Utils/API.test.ts +308 -0
  235. package/Tests/Utils/HTTPResponseBodyReader.test.ts +323 -0
  236. package/Tests/Utils/NetworkDiscovery/DiscoveryScanStatus.test.ts +117 -0
  237. package/Tests/Utils/Rum/ChunkMath.test.ts +83 -0
  238. package/Tests/Utils/Rum/SessionReplayHealthDiagnosis.test.ts +993 -0
  239. package/Tests/Utils/Rum/SessionReplayStringMap.test.ts +245 -0
  240. package/Tests/Utils/StatusPage/ResourceSearch.test.ts +631 -0
  241. package/Tests/Utils/Telemetry/OriginAllowList.test.ts +633 -0
  242. package/Tests/Utils/Uptime/DayUptimeGraphUtil.test.ts +461 -0
  243. package/Tests/Utils/ValueFormatter.test.ts +148 -0
  244. package/Types/CustomField/CustomFieldMappingCatalog.ts +161 -0
  245. package/Types/CustomField/CustomFieldMappingSourceResource.ts +19 -0
  246. package/Types/CustomField/CustomFieldValueMapping.ts +288 -0
  247. package/Types/Icon/IconProp.ts +1 -0
  248. package/Types/JSONFunctions.ts +189 -43
  249. package/Types/Monitor/CephAlertTemplates.ts +157 -195
  250. package/Types/Monitor/DockerAlertTemplates.ts +338 -128
  251. package/Types/Monitor/DockerSwarmAlertTemplates.ts +95 -112
  252. package/Types/Monitor/HostAlertTemplates.ts +302 -130
  253. package/Types/Monitor/IotAlertTemplates.ts +112 -104
  254. package/Types/Monitor/KubernetesAlertTemplates.ts +415 -224
  255. package/Types/Monitor/KubernetesMetricCatalog.ts +23 -19
  256. package/Types/Monitor/PodmanAlertTemplates.ts +116 -163
  257. package/Types/Monitor/ProxmoxAlertTemplates.ts +217 -99
  258. package/Types/Monitor/Recommendation/MonitorRecommendationSeverityMapper.ts +98 -6
  259. package/Types/Monitor/Recommendation/MonitorRecommendationUtil.ts +44 -7
  260. package/Types/Monitor/Recommendation/RecommendationCriteriaBuilder.ts +383 -0
  261. package/Types/Monitor/RumAlertTemplates.ts +46 -7
  262. package/Types/Monitor/SeriesContext/SeriesDebugHints.ts +596 -0
  263. package/Types/Monitor/SeriesContext/SeriesLabelDisplay.ts +554 -0
  264. package/Types/Monitor/ServiceAlertTemplates.ts +98 -11
  265. package/Types/Monitor/UptimeHistoryLabels.ts +56 -0
  266. package/Types/NotificationSetting/RoutineEmailEvents.ts +30 -0
  267. package/Types/Rum/SessionReplay.ts +209 -0
  268. package/Types/Rum/SessionReplayApi.ts +722 -0
  269. package/Types/Rum/SessionReplayCaptureTrigger.ts +21 -12
  270. package/Types/Rum/SessionReplayConsentMode.ts +11 -7
  271. package/Types/Rum/SessionReplayCustomEvents.ts +549 -0
  272. package/Types/Rum/SessionReplayHealth.ts +238 -0
  273. package/Types/Telemetry/TelemetryIngestSurface.ts +95 -0
  274. package/Types/Telemetry/TelemetryIngestionKeyPolicy.ts +75 -0
  275. package/Types/Telemetry/TelemetryIngestionKeyType.ts +29 -0
  276. package/Types/WebsiteRequest.ts +85 -3
  277. package/UI/Components/Charts/Area/AreaChart.tsx +13 -2
  278. package/UI/Components/Charts/Bar/BarChart.tsx +6 -2
  279. package/UI/Components/Charts/Line/LineChart.tsx +13 -2
  280. package/UI/Components/Charts/Types/XAxis/XAxis.ts +29 -0
  281. package/UI/Components/Charts/Utils/DataPoint.ts +22 -3
  282. package/UI/Components/Charts/Utils/TimeAnnotation.ts +76 -9
  283. package/UI/Components/Charts/Utils/XAxis.ts +217 -0
  284. package/UI/Components/CustomFields/CustomFieldsDetail.tsx +143 -25
  285. package/UI/Components/CustomFields/MapFromCustomFieldInput.tsx +216 -0
  286. package/UI/Components/Graphs/DayUptimeGraph.tsx +173 -8
  287. package/UI/Components/Graphs/UptimeBarTooltip.tsx +22 -278
  288. package/UI/Components/Graphs/UptimeDaySummary.tsx +327 -0
  289. package/UI/Components/Header/Header.tsx +25 -9
  290. package/UI/Components/Header/IconDropdown/IconDropdownItem.tsx +10 -1
  291. package/UI/Components/Header/IconDropdown/IconDropdownMenu.tsx +6 -1
  292. package/UI/Components/Header/ProjectPicker/ProjectPicker.tsx +6 -1
  293. package/UI/Components/HeaderAlert/NotificationBell/NotificationBellDropdown.tsx +6 -1
  294. package/UI/Components/Icon/Icon.tsx +11 -0
  295. package/UI/Components/JSONTable/JSONTable.tsx +2 -2
  296. package/UI/Components/KeyboardShortcut/KeyboardShortcutsModal.tsx +125 -0
  297. package/UI/Components/KeyboardShortcut/Screenshots/README.md +19 -0
  298. package/UI/Components/KeyboardShortcut/Screenshots/keyboard-shortcuts-command-palette.png +0 -0
  299. package/UI/Components/KeyboardShortcut/Screenshots/keyboard-shortcuts-dialog-dark.png +0 -0
  300. package/UI/Components/KeyboardShortcut/Screenshots/keyboard-shortcuts-dialog.png +0 -0
  301. package/UI/Components/KeyboardShortcut/Screenshots/keyboard-shortcuts-help-menu.png +0 -0
  302. package/UI/Components/KeyboardShortcut/Screenshots/keyboard-shortcuts-narrow.png +0 -0
  303. package/UI/Components/ModelTable/Column.ts +15 -0
  304. package/UI/Components/Monitor/SeriesDebugCommandsViewer.tsx +64 -0
  305. package/UI/Components/Monitor/SeriesLabelsViewer.tsx +93 -0
  306. package/UI/Components/MonitorGraphs/Uptime.tsx +14 -2
  307. package/UI/Components/MonitorGraphs/UptimeBarDayModal.tsx +63 -10
  308. package/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.ts +44 -0
  309. package/UI/Components/StatusPage/ResourceGroupSection.tsx +40 -0
  310. package/UI/Components/Table/CellClassName.ts +81 -0
  311. package/UI/Components/Table/TableRow.tsx +20 -14
  312. package/UI/Components/Table/TableSkeletonRows.tsx +9 -9
  313. package/UI/Components/Table/Types/Column.ts +36 -0
  314. package/UI/Components/Tooltip/Tooltip.tsx +11 -1
  315. package/UI/Components/Workflow/ComponentsModal.tsx +60 -39
  316. package/UI/Components/Workflow/NodePlacement.ts +57 -0
  317. package/UI/Components/Workflow/Workflow.tsx +47 -18
  318. package/UI/Config.ts +15 -33
  319. package/UI/Utils/GlobalKeyboardShortcut.ts +208 -0
  320. package/UI/Utils/Telemetry/BrowserTelemetryConfig.ts +28 -0
  321. package/UI/Utils/Telemetry/Telemetry.ts +10 -8
  322. package/Utils/API.ts +129 -3
  323. package/Utils/HTTPResponseBodyReader.ts +221 -0
  324. package/Utils/NetworkDiscovery/DiscoveryScanStatus.ts +77 -0
  325. package/Utils/Rum/ChunkMath.ts +106 -0
  326. package/Utils/Rum/SessionReplayHealth.ts +732 -0
  327. package/Utils/Rum/SessionReplayStringMap.ts +226 -0
  328. package/Utils/Schema/ModelSchema.ts +1 -0
  329. package/Utils/StatusPage/ResourceSearch.ts +290 -0
  330. package/Utils/Telemetry/OriginAllowList.ts +355 -0
  331. package/Utils/Uptime/DayUptimeGraphUtil.ts +205 -0
  332. package/Utils/ValueFormatter.ts +35 -1
  333. package/build/dist/Models/AnalyticsModels/RumSession.js +102 -19
  334. package/build/dist/Models/AnalyticsModels/RumSession.js.map +1 -1
  335. package/build/dist/Models/AnalyticsModels/RumSessionChunk.js +11 -9
  336. package/build/dist/Models/AnalyticsModels/RumSessionChunk.js.map +1 -1
  337. package/build/dist/Models/DatabaseModels/AlertCustomField.js +79 -3
  338. package/build/dist/Models/DatabaseModels/AlertCustomField.js.map +1 -1
  339. package/build/dist/Models/DatabaseModels/ApiKeyPermission.js +3 -27
  340. package/build/dist/Models/DatabaseModels/ApiKeyPermission.js.map +1 -1
  341. package/build/dist/Models/DatabaseModels/IncidentCustomField.js +79 -3
  342. package/build/dist/Models/DatabaseModels/IncidentCustomField.js.map +1 -1
  343. package/build/dist/Models/DatabaseModels/InventoryItemCustomField.js +79 -3
  344. package/build/dist/Models/DatabaseModels/InventoryItemCustomField.js.map +1 -1
  345. package/build/dist/Models/DatabaseModels/MonitorCustomField.js +79 -3
  346. package/build/dist/Models/DatabaseModels/MonitorCustomField.js.map +1 -1
  347. package/build/dist/Models/DatabaseModels/OnCallDutyPolicyCustomField.js +79 -3
  348. package/build/dist/Models/DatabaseModels/OnCallDutyPolicyCustomField.js.map +1 -1
  349. package/build/dist/Models/DatabaseModels/RumApplication.js +6 -6
  350. package/build/dist/Models/DatabaseModels/RumApplication.js.map +1 -1
  351. package/build/dist/Models/DatabaseModels/ScheduledMaintenanceCustomField.js +79 -3
  352. package/build/dist/Models/DatabaseModels/ScheduledMaintenanceCustomField.js.map +1 -1
  353. package/build/dist/Models/DatabaseModels/StatusPageCustomField.js +79 -3
  354. package/build/dist/Models/DatabaseModels/StatusPageCustomField.js.map +1 -1
  355. package/build/dist/Models/DatabaseModels/TeamCustomField.js +79 -3
  356. package/build/dist/Models/DatabaseModels/TeamCustomField.js.map +1 -1
  357. package/build/dist/Models/DatabaseModels/TeamMember.js +0 -9
  358. package/build/dist/Models/DatabaseModels/TeamMember.js.map +1 -1
  359. package/build/dist/Models/DatabaseModels/TeamMemberCustomField.js +79 -3
  360. package/build/dist/Models/DatabaseModels/TeamMemberCustomField.js.map +1 -1
  361. package/build/dist/Models/DatabaseModels/TeamPermission.js +3 -24
  362. package/build/dist/Models/DatabaseModels/TeamPermission.js.map +1 -1
  363. package/build/dist/Models/DatabaseModels/TelemetryIngestionKey.js +267 -0
  364. package/build/dist/Models/DatabaseModels/TelemetryIngestionKey.js.map +1 -1
  365. package/build/dist/Models/DatabaseModels/UserTelegram.js +0 -4
  366. package/build/dist/Models/DatabaseModels/UserTelegram.js.map +1 -1
  367. package/build/dist/Server/API/TelemetryAPI.js +769 -109
  368. package/build/dist/Server/API/TelemetryAPI.js.map +1 -1
  369. package/build/dist/Server/API/UserNotificationSettingAPI.js +35 -0
  370. package/build/dist/Server/API/UserNotificationSettingAPI.js.map +1 -0
  371. package/build/dist/Server/API/UserTelegramAPI.js +28 -6
  372. package/build/dist/Server/API/UserTelegramAPI.js.map +1 -1
  373. package/build/dist/Server/EnvironmentConfig.js +29 -2
  374. package/build/dist/Server/EnvironmentConfig.js.map +1 -1
  375. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1791300000000-AddTelemetryIngestionKeyType.js +60 -0
  376. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1791300000000-AddTelemetryIngestionKeyType.js.map +1 -0
  377. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1791400000000-SessionReplayRecordEverySessionByDefault.js +53 -0
  378. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1791400000000-SessionReplayRecordEverySessionByDefault.js.map +1 -0
  379. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1791500000000-WidenCustomFieldDropdownOptions.js +82 -0
  380. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1791500000000-WidenCustomFieldDropdownOptions.js.map +1 -0
  381. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1791600000000-AddCustomFieldValueMapping.js +46 -0
  382. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1791600000000-AddCustomFieldValueMapping.js.map +1 -0
  383. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +8 -0
  384. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  385. package/build/dist/Server/Infrastructure/QueueWorker.js +19 -7
  386. package/build/dist/Server/Infrastructure/QueueWorker.js.map +1 -1
  387. package/build/dist/Server/Infrastructure/Semaphore.js +1 -0
  388. package/build/dist/Server/Infrastructure/Semaphore.js.map +1 -1
  389. package/build/dist/Server/Middleware/TelemetryIngest.js +315 -8
  390. package/build/dist/Server/Middleware/TelemetryIngest.js.map +1 -1
  391. package/build/dist/Server/Services/AccessTokenService.js +1 -0
  392. package/build/dist/Server/Services/AccessTokenService.js.map +1 -1
  393. package/build/dist/Server/Services/AlertCustomFieldService.js +93 -0
  394. package/build/dist/Server/Services/AlertCustomFieldService.js.map +1 -1
  395. package/build/dist/Server/Services/AlertService.js +34 -0
  396. package/build/dist/Server/Services/AlertService.js.map +1 -1
  397. package/build/dist/Server/Services/ApiKeyPermissionService.js +331 -28
  398. package/build/dist/Server/Services/ApiKeyPermissionService.js.map +1 -1
  399. package/build/dist/Server/Services/CustomFieldMappingService.js +614 -0
  400. package/build/dist/Server/Services/CustomFieldMappingService.js.map +1 -0
  401. package/build/dist/Server/Services/GlobalConfigService.js +133 -0
  402. package/build/dist/Server/Services/GlobalConfigService.js.map +1 -1
  403. package/build/dist/Server/Services/IncidentCustomFieldService.js +93 -0
  404. package/build/dist/Server/Services/IncidentCustomFieldService.js.map +1 -1
  405. package/build/dist/Server/Services/IncidentService.js +32 -0
  406. package/build/dist/Server/Services/IncidentService.js.map +1 -1
  407. package/build/dist/Server/Services/MetricService.js +163 -0
  408. package/build/dist/Server/Services/MetricService.js.map +1 -1
  409. package/build/dist/Server/Services/MonitorService.js +29 -0
  410. package/build/dist/Server/Services/MonitorService.js.map +1 -1
  411. package/build/dist/Server/Services/NetworkDeviceAutoImportRuleEngineService.js +79 -27
  412. package/build/dist/Server/Services/NetworkDeviceAutoImportRuleEngineService.js.map +1 -1
  413. package/build/dist/Server/Services/ProjectService.js +22 -0
  414. package/build/dist/Server/Services/ProjectService.js.map +1 -1
  415. package/build/dist/Server/Services/RoutineEmailSettingsService.js +69 -0
  416. package/build/dist/Server/Services/RoutineEmailSettingsService.js.map +1 -0
  417. package/build/dist/Server/Services/RumSessionReplayViewService.js +86 -24
  418. package/build/dist/Server/Services/RumSessionReplayViewService.js.map +1 -1
  419. package/build/dist/Server/Services/ScheduledMaintenanceCustomFieldService.js +93 -0
  420. package/build/dist/Server/Services/ScheduledMaintenanceCustomFieldService.js.map +1 -1
  421. package/build/dist/Server/Services/ScheduledMaintenanceService.js +29 -0
  422. package/build/dist/Server/Services/ScheduledMaintenanceService.js.map +1 -1
  423. package/build/dist/Server/Services/TeamMemberService.js +62 -2
  424. package/build/dist/Server/Services/TeamMemberService.js.map +1 -1
  425. package/build/dist/Server/Services/TeamPermissionService.js +166 -3
  426. package/build/dist/Server/Services/TeamPermissionService.js.map +1 -1
  427. package/build/dist/Server/Services/TelemetryIngestionKeyService.js +562 -18
  428. package/build/dist/Server/Services/TelemetryIngestionKeyService.js.map +1 -1
  429. package/build/dist/Server/Services/UserNotificationSettingService.js +26 -6
  430. package/build/dist/Server/Services/UserNotificationSettingService.js.map +1 -1
  431. package/build/dist/Server/Services/UserTelegramService.js +257 -4
  432. package/build/dist/Server/Services/UserTelegramService.js.map +1 -1
  433. package/build/dist/Server/Types/Database/QueryHelper.js.map +1 -1
  434. package/build/dist/Server/Utils/APIKey/AccessPermission.js +2 -2
  435. package/build/dist/Server/Utils/APIKey/AccessPermission.js.map +1 -1
  436. package/build/dist/Server/Utils/CustomField/CustomFieldDefinitionMappingHooks.js +27 -0
  437. package/build/dist/Server/Utils/CustomField/CustomFieldDefinitionMappingHooks.js.map +1 -0
  438. package/build/dist/Server/Utils/CustomField/CustomFieldMappingRegistry.js +226 -0
  439. package/build/dist/Server/Utils/CustomField/CustomFieldMappingRegistry.js.map +1 -0
  440. package/build/dist/Server/Utils/CustomField/CustomFieldMappingValidator.js +189 -0
  441. package/build/dist/Server/Utils/CustomField/CustomFieldMappingValidator.js.map +1 -0
  442. package/build/dist/Server/Utils/DataSource/EgressGuard.js +121 -7
  443. package/build/dist/Server/Utils/DataSource/EgressGuard.js.map +1 -1
  444. package/build/dist/Server/Utils/EmailRollup/EmailRollupConstants.js +38 -5
  445. package/build/dist/Server/Utils/EmailRollup/EmailRollupConstants.js.map +1 -1
  446. package/build/dist/Server/Utils/EmailRollup/EmailRollupFlushRunner.js +44 -2
  447. package/build/dist/Server/Utils/EmailRollup/EmailRollupFlushRunner.js.map +1 -1
  448. package/build/dist/Server/Utils/FrontendEnvironment.js +33 -0
  449. package/build/dist/Server/Utils/FrontendEnvironment.js.map +1 -0
  450. package/build/dist/Server/Utils/LogRedaction.js +20 -0
  451. package/build/dist/Server/Utils/LogRedaction.js.map +1 -1
  452. package/build/dist/Server/Utils/Logger.js +10 -0
  453. package/build/dist/Server/Utils/Logger.js.map +1 -1
  454. package/build/dist/Server/Utils/Monitor/Criteria/CompareCriteria.js +287 -68
  455. package/build/dist/Server/Utils/Monitor/Criteria/CompareCriteria.js.map +1 -1
  456. package/build/dist/Server/Utils/Monitor/Criteria/IncomingRequestCriteria.js +20 -4
  457. package/build/dist/Server/Utils/Monitor/Criteria/IncomingRequestCriteria.js.map +1 -1
  458. package/build/dist/Server/Utils/Monitor/MonitorAlert.js +29 -6
  459. package/build/dist/Server/Utils/Monitor/MonitorAlert.js.map +1 -1
  460. package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js +88 -13
  461. package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js.map +1 -1
  462. package/build/dist/Server/Utils/Monitor/MonitorIncident.js +22 -6
  463. package/build/dist/Server/Utils/Monitor/MonitorIncident.js.map +1 -1
  464. package/build/dist/Server/Utils/Monitor/MonitorTemplateUtil.js +22 -0
  465. package/build/dist/Server/Utils/Monitor/MonitorTemplateUtil.js.map +1 -1
  466. package/build/dist/Server/Utils/Monitor/SeriesContextEnricher.js +237 -0
  467. package/build/dist/Server/Utils/Monitor/SeriesContextEnricher.js.map +1 -0
  468. package/build/dist/Server/Utils/SSRFProtection.js +136 -9
  469. package/build/dist/Server/Utils/SSRFProtection.js.map +1 -1
  470. package/build/dist/Server/Utils/SessionReplay/SessionReplayGateCache.js +174 -89
  471. package/build/dist/Server/Utils/SessionReplay/SessionReplayGateCache.js.map +1 -1
  472. package/build/dist/Server/Utils/SessionReplay/SessionReplayHealthCounters.js +223 -0
  473. package/build/dist/Server/Utils/SessionReplay/SessionReplayHealthCounters.js.map +1 -0
  474. package/build/dist/Server/Utils/SessionReplay/SessionReplayReadService.js +945 -164
  475. package/build/dist/Server/Utils/SessionReplay/SessionReplayReadService.js.map +1 -1
  476. package/build/dist/Server/Utils/StartServer.js +3 -14
  477. package/build/dist/Server/Utils/StartServer.js.map +1 -1
  478. package/build/dist/Server/Utils/TelegramVerificationToken.js +129 -0
  479. package/build/dist/Server/Utils/TelegramVerificationToken.js.map +1 -0
  480. package/build/dist/Server/Utils/Telemetry/PinServiceName.js +163 -0
  481. package/build/dist/Server/Utils/Telemetry/PinServiceName.js.map +1 -0
  482. package/build/dist/Server/Utils/Telemetry/TelemetryFanInWriter.js +28 -15
  483. package/build/dist/Server/Utils/Telemetry/TelemetryFanInWriter.js.map +1 -1
  484. package/build/dist/Server/Utils/Telemetry/TelemetryIngestionKeyGuard.js +64 -0
  485. package/build/dist/Server/Utils/Telemetry/TelemetryIngestionKeyGuard.js.map +1 -0
  486. package/build/dist/Server/Utils/Telemetry/TelemetryIngestionKeyRateLimiter.js +171 -0
  487. package/build/dist/Server/Utils/Telemetry/TelemetryIngestionKeyRateLimiter.js.map +1 -0
  488. package/build/dist/Server/Utils/VM/VMAPI.js.map +1 -1
  489. package/build/dist/Server/Utils/VM/VMRunner.js +780 -69
  490. package/build/dist/Server/Utils/VM/VMRunner.js.map +1 -1
  491. package/build/dist/Types/CustomField/CustomFieldMappingCatalog.js +60 -0
  492. package/build/dist/Types/CustomField/CustomFieldMappingCatalog.js.map +1 -0
  493. package/build/dist/Types/CustomField/CustomFieldMappingSourceResource.js +20 -0
  494. package/build/dist/Types/CustomField/CustomFieldMappingSourceResource.js.map +1 -0
  495. package/build/dist/Types/CustomField/CustomFieldValueMapping.js +141 -0
  496. package/build/dist/Types/CustomField/CustomFieldValueMapping.js.map +1 -0
  497. package/build/dist/Types/Icon/IconProp.js +1 -0
  498. package/build/dist/Types/Icon/IconProp.js.map +1 -1
  499. package/build/dist/Types/JSONFunctions.js +118 -37
  500. package/build/dist/Types/JSONFunctions.js.map +1 -1
  501. package/build/dist/Types/Monitor/CephAlertTemplates.js +130 -171
  502. package/build/dist/Types/Monitor/CephAlertTemplates.js.map +1 -1
  503. package/build/dist/Types/Monitor/DockerAlertTemplates.js +286 -121
  504. package/build/dist/Types/Monitor/DockerAlertTemplates.js.map +1 -1
  505. package/build/dist/Types/Monitor/DockerSwarmAlertTemplates.js +84 -105
  506. package/build/dist/Types/Monitor/DockerSwarmAlertTemplates.js.map +1 -1
  507. package/build/dist/Types/Monitor/HostAlertTemplates.js +250 -122
  508. package/build/dist/Types/Monitor/HostAlertTemplates.js.map +1 -1
  509. package/build/dist/Types/Monitor/IotAlertTemplates.js +81 -81
  510. package/build/dist/Types/Monitor/IotAlertTemplates.js.map +1 -1
  511. package/build/dist/Types/Monitor/KubernetesAlertTemplates.js +375 -215
  512. package/build/dist/Types/Monitor/KubernetesAlertTemplates.js.map +1 -1
  513. package/build/dist/Types/Monitor/KubernetesMetricCatalog.js +19 -19
  514. package/build/dist/Types/Monitor/KubernetesMetricCatalog.js.map +1 -1
  515. package/build/dist/Types/Monitor/PodmanAlertTemplates.js +104 -153
  516. package/build/dist/Types/Monitor/PodmanAlertTemplates.js.map +1 -1
  517. package/build/dist/Types/Monitor/ProxmoxAlertTemplates.js +156 -91
  518. package/build/dist/Types/Monitor/ProxmoxAlertTemplates.js.map +1 -1
  519. package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationSeverityMapper.js +67 -6
  520. package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationSeverityMapper.js.map +1 -1
  521. package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationUtil.js +38 -7
  522. package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationUtil.js.map +1 -1
  523. package/build/dist/Types/Monitor/Recommendation/RecommendationCriteriaBuilder.js +261 -0
  524. package/build/dist/Types/Monitor/Recommendation/RecommendationCriteriaBuilder.js.map +1 -0
  525. package/build/dist/Types/Monitor/RumAlertTemplates.js +46 -7
  526. package/build/dist/Types/Monitor/RumAlertTemplates.js.map +1 -1
  527. package/build/dist/Types/Monitor/SeriesContext/SeriesDebugHints.js +422 -0
  528. package/build/dist/Types/Monitor/SeriesContext/SeriesDebugHints.js.map +1 -0
  529. package/build/dist/Types/Monitor/SeriesContext/SeriesLabelDisplay.js +441 -0
  530. package/build/dist/Types/Monitor/SeriesContext/SeriesLabelDisplay.js.map +1 -0
  531. package/build/dist/Types/Monitor/ServiceAlertTemplates.js +79 -15
  532. package/build/dist/Types/Monitor/ServiceAlertTemplates.js.map +1 -1
  533. package/build/dist/Types/Monitor/UptimeHistoryLabels.js +17 -0
  534. package/build/dist/Types/Monitor/UptimeHistoryLabels.js.map +1 -0
  535. package/build/dist/Types/NotificationSetting/RoutineEmailEvents.js +29 -0
  536. package/build/dist/Types/NotificationSetting/RoutineEmailEvents.js.map +1 -0
  537. package/build/dist/Types/Rum/SessionReplay.js +117 -0
  538. package/build/dist/Types/Rum/SessionReplay.js.map +1 -1
  539. package/build/dist/Types/Rum/SessionReplayApi.js +181 -0
  540. package/build/dist/Types/Rum/SessionReplayApi.js.map +1 -0
  541. package/build/dist/Types/Rum/SessionReplayCaptureTrigger.js +21 -12
  542. package/build/dist/Types/Rum/SessionReplayCaptureTrigger.js.map +1 -1
  543. package/build/dist/Types/Rum/SessionReplayConsentMode.js +11 -7
  544. package/build/dist/Types/Rum/SessionReplayConsentMode.js.map +1 -1
  545. package/build/dist/Types/Rum/SessionReplayCustomEvents.js +172 -0
  546. package/build/dist/Types/Rum/SessionReplayCustomEvents.js.map +1 -0
  547. package/build/dist/Types/Rum/SessionReplayHealth.js +37 -0
  548. package/build/dist/Types/Rum/SessionReplayHealth.js.map +1 -0
  549. package/build/dist/Types/Telemetry/TelemetryIngestSurface.js +85 -0
  550. package/build/dist/Types/Telemetry/TelemetryIngestSurface.js.map +1 -0
  551. package/build/dist/Types/Telemetry/TelemetryIngestionKeyPolicy.js +15 -0
  552. package/build/dist/Types/Telemetry/TelemetryIngestionKeyPolicy.js.map +1 -0
  553. package/build/dist/Types/Telemetry/TelemetryIngestionKeyType.js +30 -0
  554. package/build/dist/Types/Telemetry/TelemetryIngestionKeyType.js.map +1 -0
  555. package/build/dist/Types/WebsiteRequest.js +55 -3
  556. package/build/dist/Types/WebsiteRequest.js.map +1 -1
  557. package/build/dist/UI/Components/Charts/Area/AreaChart.js +13 -2
  558. package/build/dist/UI/Components/Charts/Area/AreaChart.js.map +1 -1
  559. package/build/dist/UI/Components/Charts/Bar/BarChart.js +6 -2
  560. package/build/dist/UI/Components/Charts/Bar/BarChart.js.map +1 -1
  561. package/build/dist/UI/Components/Charts/Line/LineChart.js +13 -2
  562. package/build/dist/UI/Components/Charts/Line/LineChart.js.map +1 -1
  563. package/build/dist/UI/Components/Charts/Types/XAxis/XAxis.js.map +1 -1
  564. package/build/dist/UI/Components/Charts/Utils/DataPoint.js +15 -3
  565. package/build/dist/UI/Components/Charts/Utils/DataPoint.js.map +1 -1
  566. package/build/dist/UI/Components/Charts/Utils/TimeAnnotation.js +40 -9
  567. package/build/dist/UI/Components/Charts/Utils/TimeAnnotation.js.map +1 -1
  568. package/build/dist/UI/Components/Charts/Utils/XAxis.js +186 -0
  569. package/build/dist/UI/Components/Charts/Utils/XAxis.js.map +1 -1
  570. package/build/dist/UI/Components/CustomFields/CustomFieldsDetail.js +80 -6
  571. package/build/dist/UI/Components/CustomFields/CustomFieldsDetail.js.map +1 -1
  572. package/build/dist/UI/Components/CustomFields/MapFromCustomFieldInput.js +118 -0
  573. package/build/dist/UI/Components/CustomFields/MapFromCustomFieldInput.js.map +1 -0
  574. package/build/dist/UI/Components/Graphs/DayUptimeGraph.js +112 -7
  575. package/build/dist/UI/Components/Graphs/DayUptimeGraph.js.map +1 -1
  576. package/build/dist/UI/Components/Graphs/UptimeBarTooltip.js +5 -162
  577. package/build/dist/UI/Components/Graphs/UptimeBarTooltip.js.map +1 -1
  578. package/build/dist/UI/Components/Graphs/UptimeDaySummary.js +181 -0
  579. package/build/dist/UI/Components/Graphs/UptimeDaySummary.js.map +1 -0
  580. package/build/dist/UI/Components/Header/Header.js +2 -3
  581. package/build/dist/UI/Components/Header/Header.js.map +1 -1
  582. package/build/dist/UI/Components/Header/IconDropdown/IconDropdownItem.js +2 -1
  583. package/build/dist/UI/Components/Header/IconDropdown/IconDropdownItem.js.map +1 -1
  584. package/build/dist/UI/Components/Header/IconDropdown/IconDropdownMenu.js +7 -1
  585. package/build/dist/UI/Components/Header/IconDropdown/IconDropdownMenu.js.map +1 -1
  586. package/build/dist/UI/Components/Header/ProjectPicker/ProjectPicker.js +7 -1
  587. package/build/dist/UI/Components/Header/ProjectPicker/ProjectPicker.js.map +1 -1
  588. package/build/dist/UI/Components/HeaderAlert/NotificationBell/NotificationBellDropdown.js +7 -1
  589. package/build/dist/UI/Components/HeaderAlert/NotificationBell/NotificationBellDropdown.js.map +1 -1
  590. package/build/dist/UI/Components/Icon/Icon.js +5 -0
  591. package/build/dist/UI/Components/Icon/Icon.js.map +1 -1
  592. package/build/dist/UI/Components/JSONTable/JSONTable.js +2 -2
  593. package/build/dist/UI/Components/JSONTable/JSONTable.js.map +1 -1
  594. package/build/dist/UI/Components/KeyboardShortcut/KeyboardShortcutsModal.js +35 -0
  595. package/build/dist/UI/Components/KeyboardShortcut/KeyboardShortcutsModal.js.map +1 -0
  596. package/build/dist/UI/Components/Monitor/SeriesDebugCommandsViewer.js +34 -0
  597. package/build/dist/UI/Components/Monitor/SeriesDebugCommandsViewer.js.map +1 -0
  598. package/build/dist/UI/Components/Monitor/SeriesLabelsViewer.js +49 -0
  599. package/build/dist/UI/Components/Monitor/SeriesLabelsViewer.js.map +1 -0
  600. package/build/dist/UI/Components/MonitorGraphs/Uptime.js +1 -1
  601. package/build/dist/UI/Components/MonitorGraphs/Uptime.js.map +1 -1
  602. package/build/dist/UI/Components/MonitorGraphs/UptimeBarDayModal.js +32 -6
  603. package/build/dist/UI/Components/MonitorGraphs/UptimeBarDayModal.js.map +1 -1
  604. package/build/dist/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.js +38 -0
  605. package/build/dist/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.js.map +1 -1
  606. package/build/dist/UI/Components/StatusPage/ResourceGroupSection.js +22 -1
  607. package/build/dist/UI/Components/StatusPage/ResourceGroupSection.js.map +1 -1
  608. package/build/dist/UI/Components/Table/CellClassName.js +55 -0
  609. package/build/dist/UI/Components/Table/CellClassName.js.map +1 -0
  610. package/build/dist/UI/Components/Table/TableRow.js +16 -13
  611. package/build/dist/UI/Components/Table/TableRow.js.map +1 -1
  612. package/build/dist/UI/Components/Table/TableSkeletonRows.js +9 -8
  613. package/build/dist/UI/Components/Table/TableSkeletonRows.js.map +1 -1
  614. package/build/dist/UI/Components/Tooltip/Tooltip.js +25 -1
  615. package/build/dist/UI/Components/Tooltip/Tooltip.js.map +1 -1
  616. package/build/dist/UI/Components/Workflow/ComponentsModal.js +47 -30
  617. package/build/dist/UI/Components/Workflow/ComponentsModal.js.map +1 -1
  618. package/build/dist/UI/Components/Workflow/NodePlacement.js +37 -0
  619. package/build/dist/UI/Components/Workflow/NodePlacement.js.map +1 -0
  620. package/build/dist/UI/Components/Workflow/Workflow.js +35 -18
  621. package/build/dist/UI/Components/Workflow/Workflow.js.map +1 -1
  622. package/build/dist/UI/Config.js +10 -20
  623. package/build/dist/UI/Config.js.map +1 -1
  624. package/build/dist/UI/Utils/GlobalKeyboardShortcut.js +138 -0
  625. package/build/dist/UI/Utils/GlobalKeyboardShortcut.js.map +1 -0
  626. package/build/dist/UI/Utils/Telemetry/BrowserTelemetryConfig.js +14 -0
  627. package/build/dist/UI/Utils/Telemetry/BrowserTelemetryConfig.js.map +1 -0
  628. package/build/dist/UI/Utils/Telemetry/Telemetry.js +7 -5
  629. package/build/dist/UI/Utils/Telemetry/Telemetry.js.map +1 -1
  630. package/build/dist/Utils/API.js +67 -5
  631. package/build/dist/Utils/API.js.map +1 -1
  632. package/build/dist/Utils/HTTPResponseBodyReader.js +157 -0
  633. package/build/dist/Utils/HTTPResponseBodyReader.js.map +1 -0
  634. package/build/dist/Utils/NetworkDiscovery/DiscoveryScanStatus.js +69 -0
  635. package/build/dist/Utils/NetworkDiscovery/DiscoveryScanStatus.js.map +1 -0
  636. package/build/dist/Utils/Rum/ChunkMath.js +76 -0
  637. package/build/dist/Utils/Rum/ChunkMath.js.map +1 -1
  638. package/build/dist/Utils/Rum/SessionReplayHealth.js +534 -0
  639. package/build/dist/Utils/Rum/SessionReplayHealth.js.map +1 -0
  640. package/build/dist/Utils/Rum/SessionReplayStringMap.js +165 -0
  641. package/build/dist/Utils/Rum/SessionReplayStringMap.js.map +1 -0
  642. package/build/dist/Utils/Schema/ModelSchema.js +1 -0
  643. package/build/dist/Utils/Schema/ModelSchema.js.map +1 -1
  644. package/build/dist/Utils/StatusPage/ResourceSearch.js +200 -0
  645. package/build/dist/Utils/StatusPage/ResourceSearch.js.map +1 -0
  646. package/build/dist/Utils/Telemetry/OriginAllowList.js +299 -0
  647. package/build/dist/Utils/Telemetry/OriginAllowList.js.map +1 -0
  648. package/build/dist/Utils/Uptime/DayUptimeGraphUtil.js +147 -0
  649. package/build/dist/Utils/Uptime/DayUptimeGraphUtil.js.map +1 -0
  650. package/build/dist/Utils/ValueFormatter.js +32 -1
  651. package/build/dist/Utils/ValueFormatter.js.map +1 -1
  652. package/package.json +1 -1
@@ -1,6 +1,31 @@
1
1
  import VMRunner from "../../../../Server/Utils/VM/VMRunner";
2
2
  import ReturnResult from "../../../../Types/IsolatedVM/ReturnResult";
3
- import { describe, expect, jest, test } from "@jest/globals";
3
+ import {
4
+ afterAll,
5
+ afterEach,
6
+ beforeAll,
7
+ beforeEach,
8
+ describe,
9
+ expect,
10
+ jest,
11
+ test,
12
+ } from "@jest/globals";
13
+ import axios from "axios";
14
+ import dns from "dns";
15
+ import http from "http";
16
+ import https from "https";
17
+ import { AddressInfo } from "net";
18
+ import { gzipSync } from "zlib";
19
+
20
+ /*
21
+ * Common's jsdom resolver selects Axios's browser bundle. VMRunner is a
22
+ * server-only utility, so use Axios's Node bundle here; otherwise forcing the
23
+ * `http` adapter below only finds a browser-build placeholder and the stream
24
+ * and socket tests never reach production transport code.
25
+ */
26
+ jest.mock("axios", () => {
27
+ return jest.requireActual("axios/dist/node/axios.cjs");
28
+ });
4
29
 
5
30
  /*
6
31
  * GHSA-v5xh-rw9h-77fv fixed the API workflow components, but the Custom
@@ -18,10 +43,95 @@ import { describe, expect, jest, test } from "@jest/globals";
18
43
 
19
44
  jest.setTimeout(60000);
20
45
 
21
- async function runInSandbox(code: string): Promise<ReturnResult> {
46
+ interface SandboxPrivateNetworkOptions {
47
+ allowPrivateNetworkRequests?: boolean | undefined;
48
+ privateNetworkAccessIsAllowed?: boolean | undefined;
49
+ }
50
+
51
+ interface RunningLoopbackServer {
52
+ port: number;
53
+ requestCount: () => number;
54
+ close: () => Promise<void>;
55
+ }
56
+
57
+ type LoopbackRequestHandler = (
58
+ request: http.IncomingMessage,
59
+ response: http.ServerResponse,
60
+ ) => void;
61
+
62
+ type ValidationLookupSpy = jest.SpiedFunction<
63
+ (
64
+ hostname: string,
65
+ options: { all: true },
66
+ ) => Promise<Array<{ address: string; family: number }>>
67
+ >;
68
+
69
+ interface SocketLookupSpy {
70
+ mockImplementation: (
71
+ implementation: (...args: Array<unknown>) => void,
72
+ ) => unknown;
73
+ }
74
+
75
+ async function startLoopbackServer(
76
+ handler: LoopbackRequestHandler = (
77
+ _request: http.IncomingMessage,
78
+ response: http.ServerResponse,
79
+ ): void => {
80
+ response.end("loopback sentinel");
81
+ },
82
+ ): Promise<RunningLoopbackServer> {
83
+ let receivedRequests: number = 0;
84
+ const server: http.Server = http.createServer(
85
+ (request: http.IncomingMessage, response: http.ServerResponse): void => {
86
+ receivedRequests += 1;
87
+ handler(request, response);
88
+ },
89
+ );
90
+
91
+ await new Promise<void>(
92
+ (resolve: () => void, reject: (error: Error) => void): void => {
93
+ const onError: (error: Error) => void = (error: Error): void => {
94
+ reject(error);
95
+ };
96
+ server.once("error", onError);
97
+ server.listen(0, "127.0.0.1", (): void => {
98
+ server.off("error", onError);
99
+ resolve();
100
+ });
101
+ },
102
+ );
103
+
104
+ const address: AddressInfo = server.address() as AddressInfo;
105
+
106
+ return {
107
+ port: address.port,
108
+ requestCount: (): number => {
109
+ return receivedRequests;
110
+ },
111
+ close: async (): Promise<void> => {
112
+ await new Promise<void>(
113
+ (resolve: () => void, reject: (error: Error) => void): void => {
114
+ server.close((error?: Error): void => {
115
+ if (error) {
116
+ reject(error);
117
+ return;
118
+ }
119
+ resolve();
120
+ });
121
+ server.closeAllConnections();
122
+ },
123
+ );
124
+ },
125
+ };
126
+ }
127
+
128
+ async function runInSandbox(
129
+ code: string,
130
+ privateNetworkOptions: SandboxPrivateNetworkOptions = {},
131
+ ): Promise<ReturnResult> {
22
132
  return VMRunner.runCodeInSandbox({
23
133
  code,
24
- options: { timeout: 15000 },
134
+ options: { timeout: 15000, ...privateNetworkOptions },
25
135
  });
26
136
  }
27
137
 
@@ -30,9 +140,15 @@ async function runInSandbox(code: string): Promise<ReturnResult> {
30
140
  * rejects or the returned result carries the message - accept both, and assert
31
141
  * on the SSRF wording so a mere "connection refused" cannot pass for a block.
32
142
  */
33
- async function errorFromSandbox(code: string): Promise<string> {
143
+ async function errorFromSandbox(
144
+ code: string,
145
+ privateNetworkOptions: SandboxPrivateNetworkOptions = {},
146
+ ): Promise<string> {
34
147
  try {
35
- const result: ReturnResult = await runInSandbox(code);
148
+ const result: ReturnResult = await runInSandbox(
149
+ code,
150
+ privateNetworkOptions,
151
+ );
36
152
  if (result.scriptError) {
37
153
  return result.scriptError.message;
38
154
  }
@@ -45,6 +161,64 @@ async function errorFromSandbox(code: string): Promise<string> {
45
161
  const REFUSAL: RegExp =
46
162
  /not allowed|private, loopback, or link-local|absolute http|could not be resolved/i;
47
163
 
164
+ const ALLOW_PRIVATE_NETWORK_WEBHOOKS_ENV: string =
165
+ "ALLOW_PRIVATE_NETWORK_WEBHOOKS";
166
+ const PRIVATE_NETWORK_WEBHOOK_ALLOWLIST_ENV: string =
167
+ "PRIVATE_NETWORK_WEBHOOK_ALLOWLIST";
168
+ const originalAllowPrivateNetworkWebhooks: string | undefined =
169
+ process.env[ALLOW_PRIVATE_NETWORK_WEBHOOKS_ENV];
170
+ const originalPrivateNetworkWebhookAllowlist: string | undefined =
171
+ process.env[PRIVATE_NETWORK_WEBHOOK_ALLOWLIST_ENV];
172
+ const originalAxiosAdapter: typeof axios.defaults.adapter =
173
+ axios.defaults.adapter;
174
+
175
+ beforeAll(() => {
176
+ /*
177
+ * Common's default Jest environment is jsdom, where Axios selects XHR and
178
+ * CORS blocks the loopback fixtures before VMRunner's Node transport runs.
179
+ * Production VMRunner runs in Node, so force Axios's Node adapter for this
180
+ * server-side integration suite.
181
+ */
182
+ axios.defaults.adapter = "http";
183
+ });
184
+
185
+ beforeEach(() => {
186
+ delete process.env[ALLOW_PRIVATE_NETWORK_WEBHOOKS_ENV];
187
+ delete process.env[PRIVATE_NETWORK_WEBHOOK_ALLOWLIST_ENV];
188
+ });
189
+
190
+ afterEach(() => {
191
+ jest.restoreAllMocks();
192
+ });
193
+
194
+ afterAll(() => {
195
+ if (originalAxiosAdapter === undefined) {
196
+ delete axios.defaults.adapter;
197
+ } else {
198
+ axios.defaults.adapter = originalAxiosAdapter;
199
+ }
200
+
201
+ const restore: (key: string, value: string | undefined) => void = (
202
+ key: string,
203
+ value: string | undefined,
204
+ ): void => {
205
+ if (value === undefined) {
206
+ delete process.env[key];
207
+ } else {
208
+ process.env[key] = value;
209
+ }
210
+ };
211
+
212
+ restore(
213
+ ALLOW_PRIVATE_NETWORK_WEBHOOKS_ENV,
214
+ originalAllowPrivateNetworkWebhooks,
215
+ );
216
+ restore(
217
+ PRIVATE_NETWORK_WEBHOOK_ALLOWLIST_ENV,
218
+ originalPrivateNetworkWebhookAllowlist,
219
+ );
220
+ });
221
+
48
222
  describe("VMRunner sandbox axios bridge — SSRF guard", () => {
49
223
  const internalTargets: Array<[string, string]> = [
50
224
  ["AWS metadata endpoint", "http://169.254.169.254/latest/meta-data/"],
@@ -131,7 +305,7 @@ describe("VMRunner sandbox axios bridge — SSRF guard", () => {
131
305
  /*
132
306
  * A proxy or a unix socket steers the connection somewhere the validated URL
133
307
  * never named — /var/run/docker.sock being the memorable one — so the guard
134
- * strips them rather than trusting the URL alone.
308
+ * disables or strips them rather than trusting the URL alone.
135
309
  */
136
310
  test("a proxy in the config cannot steer a public URL at an internal host", async () => {
137
311
  /*
@@ -145,6 +319,33 @@ describe("VMRunner sandbox axios bridge — SSRF guard", () => {
145
319
  expect(message).not.toMatch(/169\.254\.169\.254/);
146
320
  });
147
321
 
322
+ test("an environment proxy cannot become an unvalidated connection path", async () => {
323
+ const originalHttpProxy: string | undefined = process.env["HTTP_PROXY"];
324
+ const originalHttpsProxy: string | undefined = process.env["HTTPS_PROXY"];
325
+
326
+ process.env["HTTP_PROXY"] = "http://169.254.169.254:80";
327
+ process.env["HTTPS_PROXY"] = "http://169.254.169.254:80";
328
+
329
+ try {
330
+ const message: string = await errorFromSandbox(
331
+ `try { return await axios.get('http://8.8.8.8/', { timeout: 1 }); } catch (e) { return 'threw: ' + e.message; }`,
332
+ );
333
+ expect(message).not.toMatch(/169\.254\.169\.254/);
334
+ } finally {
335
+ if (originalHttpProxy === undefined) {
336
+ delete process.env["HTTP_PROXY"];
337
+ } else {
338
+ process.env["HTTP_PROXY"] = originalHttpProxy;
339
+ }
340
+
341
+ if (originalHttpsProxy === undefined) {
342
+ delete process.env["HTTPS_PROXY"];
343
+ } else {
344
+ process.env["HTTPS_PROXY"] = originalHttpsProxy;
345
+ }
346
+ }
347
+ });
348
+
148
349
  test("still lets an ordinary public URL past the guard", async () => {
149
350
  /*
150
351
  * 8.8.8.8 is never actually reached - the 1ms timeout sees to that. The
@@ -158,6 +359,948 @@ describe("VMRunner sandbox axios bridge — SSRF guard", () => {
158
359
  });
159
360
  });
160
361
 
362
+ describe("VMRunner sandbox axios bridge — pinned canonical dispatch", () => {
363
+ async function expectNoLoopbackRequest(
364
+ buildCode: (port: number) => string,
365
+ ): Promise<void> {
366
+ const loopbackServer: RunningLoopbackServer = await startLoopbackServer();
367
+
368
+ try {
369
+ const result: ReturnResult = await runInSandbox(
370
+ buildCode(loopbackServer.port),
371
+ );
372
+
373
+ expect(result.returnValue).not.toBe("loopback sentinel");
374
+ expect(loopbackServer.requestCount()).toBe(0);
375
+ } finally {
376
+ await loopbackServer.close();
377
+ }
378
+ }
379
+
380
+ test("pins the address from validation instead of performing a second DNS lookup", async () => {
381
+ const loopbackServer: RunningLoopbackServer = await startLoopbackServer();
382
+ const validationLookupSpy: ValidationLookupSpy = jest.spyOn(
383
+ dns.promises,
384
+ "lookup",
385
+ ) as unknown as ValidationLookupSpy;
386
+ validationLookupSpy.mockResolvedValue([{ address: "8.8.8.8", family: 4 }]);
387
+
388
+ const socketLookupSpy: SocketLookupSpy = jest.spyOn(
389
+ dns,
390
+ "lookup",
391
+ ) as unknown as SocketLookupSpy;
392
+ socketLookupSpy.mockImplementation((...args: Array<unknown>): void => {
393
+ const lookupOptions: { all?: boolean } | undefined =
394
+ args.length > 2 && typeof args[1] === "object"
395
+ ? (args[1] as { all?: boolean })
396
+ : undefined;
397
+ const callback: (
398
+ error: NodeJS.ErrnoException | null,
399
+ address: string | Array<{ address: string; family: number }>,
400
+ family?: number,
401
+ ) => void = args[args.length - 1] as (
402
+ error: NodeJS.ErrnoException | null,
403
+ address: string | Array<{ address: string; family: number }>,
404
+ family?: number,
405
+ ) => void;
406
+
407
+ queueMicrotask((): void => {
408
+ if (lookupOptions?.all) {
409
+ callback(null, [{ address: "127.0.0.1", family: 4 }]);
410
+ return;
411
+ }
412
+ callback(null, "127.0.0.1", 4);
413
+ });
414
+ });
415
+
416
+ try {
417
+ const result: ReturnResult = await runInSandbox(`
418
+ try {
419
+ const response = await axios.get(
420
+ 'http://rebind.invalid:${loopbackServer.port}/secret',
421
+ {
422
+ timeout: 100,
423
+ httpVersion: 2,
424
+ http2Options: { sessionTimeout: 10000 }
425
+ }
426
+ );
427
+ return response.data;
428
+ } catch (error) {
429
+ return 'transport failed: ' + error.message;
430
+ }
431
+ `);
432
+
433
+ expect(result.returnValue).not.toBe("loopback sentinel");
434
+ expect(validationLookupSpy).toHaveBeenCalledTimes(1);
435
+ expect(socketLookupSpy).not.toHaveBeenCalled();
436
+ expect(loopbackServer.requestCount()).toBe(0);
437
+ } finally {
438
+ await loopbackServer.close();
439
+ }
440
+ });
441
+
442
+ test("drops destination-steering fields from a serialized HTTP Agent", async () => {
443
+ await expectNoLoopbackRequest((port: number): string => {
444
+ return `
445
+ try {
446
+ const response = await axios.get(
447
+ 'http://8.8.8.8:${port}/approved',
448
+ {
449
+ timeout: 100,
450
+ httpAgent: new http.Agent({
451
+ host: '127.0.0.1',
452
+ port: ${port},
453
+ keepAlive: true
454
+ })
455
+ }
456
+ );
457
+ return response.data;
458
+ } catch (error) {
459
+ return 'transport failed: ' + error.message;
460
+ }
461
+ `;
462
+ });
463
+ });
464
+
465
+ test("preserves TLS-only servername while replacing the HTTPS agent transport", async () => {
466
+ process.env[PRIVATE_NETWORK_WEBHOOK_ALLOWLIST_ENV] = "127.0.0.1";
467
+ let observedServername: string | undefined;
468
+ jest
469
+ .spyOn(https.Agent.prototype, "createConnection")
470
+ .mockImplementation(((options: {
471
+ servername?: string | undefined;
472
+ }): never => {
473
+ observedServername = options.servername;
474
+ throw new Error("TLS connection sentinel");
475
+ }) as never);
476
+
477
+ const result: ReturnResult = await runInSandbox(
478
+ `
479
+ try {
480
+ await axios.get('https://127.0.0.1/sni', {
481
+ httpsAgent: new https.Agent({
482
+ rejectUnauthorized: false,
483
+ servername: 'tenant.internal.example'
484
+ })
485
+ });
486
+ return 'unexpected success';
487
+ } catch (error) {
488
+ return error.message;
489
+ }
490
+ `,
491
+ {
492
+ allowPrivateNetworkRequests: true,
493
+ },
494
+ );
495
+
496
+ expect(result.scriptError).toBeUndefined();
497
+ expect(result.returnValue).toMatch(/TLS connection sentinel/i);
498
+ expect(observedServername).toBe("tenant.internal.example");
499
+ });
500
+
501
+ test("an empty positional URL wins over config.url and resolves to baseURL", async () => {
502
+ process.env[PRIVATE_NETWORK_WEBHOOK_ALLOWLIST_ENV] = "127.0.0.1";
503
+ const loopbackServer: RunningLoopbackServer = await startLoopbackServer(
504
+ (request: http.IncomingMessage, response: http.ServerResponse): void => {
505
+ response.end(request.url);
506
+ },
507
+ );
508
+
509
+ try {
510
+ const result: ReturnResult = await runInSandbox(
511
+ `
512
+ const response = await axios.get('', {
513
+ url: 'http://169.254.169.254/ignored',
514
+ baseURL: 'http://127.0.0.1:${loopbackServer.port}/from-base-url'
515
+ });
516
+ return response.data;
517
+ `,
518
+ {
519
+ allowPrivateNetworkRequests: true,
520
+ },
521
+ );
522
+
523
+ expect(result.scriptError).toBeUndefined();
524
+ expect(result.returnValue).toBe("/from-base-url");
525
+ expect(loopbackServer.requestCount()).toBe(1);
526
+ } finally {
527
+ await loopbackServer.close();
528
+ }
529
+ });
530
+
531
+ test("allowAbsoluteUrls false combines baseURL with a direct-method absolute URL", async () => {
532
+ process.env[PRIVATE_NETWORK_WEBHOOK_ALLOWLIST_ENV] = "127.0.0.1";
533
+ const loopbackServer: RunningLoopbackServer = await startLoopbackServer(
534
+ (request: http.IncomingMessage, response: http.ServerResponse): void => {
535
+ response.end(request.url);
536
+ },
537
+ );
538
+
539
+ try {
540
+ const result: ReturnResult = await runInSandbox(
541
+ `
542
+ const response = await axios.get(
543
+ 'http://169.254.169.254/metadata',
544
+ {
545
+ baseURL: 'http://127.0.0.1:${loopbackServer.port}/base',
546
+ allowAbsoluteUrls: false
547
+ }
548
+ );
549
+ return response.data;
550
+ `,
551
+ {
552
+ allowPrivateNetworkRequests: true,
553
+ },
554
+ );
555
+
556
+ expect(result.scriptError).toBeUndefined();
557
+ expect(result.returnValue).toBe("/base/http://169.254.169.254/metadata");
558
+ expect(loopbackServer.requestCount()).toBe(1);
559
+ } finally {
560
+ await loopbackServer.close();
561
+ }
562
+ });
563
+
564
+ test("allowAbsoluteUrls false combines baseURL with request().url", async () => {
565
+ process.env[PRIVATE_NETWORK_WEBHOOK_ALLOWLIST_ENV] = "127.0.0.1";
566
+ const loopbackServer: RunningLoopbackServer = await startLoopbackServer(
567
+ (request: http.IncomingMessage, response: http.ServerResponse): void => {
568
+ response.end(request.url);
569
+ },
570
+ );
571
+
572
+ try {
573
+ const result: ReturnResult = await runInSandbox(
574
+ `
575
+ const response = await axios.request({
576
+ method: 'get',
577
+ url: 'http://169.254.169.254/metadata',
578
+ baseURL: 'http://127.0.0.1:${loopbackServer.port}/base',
579
+ allowAbsoluteUrls: false
580
+ });
581
+ return response.data;
582
+ `,
583
+ {
584
+ allowPrivateNetworkRequests: true,
585
+ },
586
+ );
587
+
588
+ expect(result.scriptError).toBeUndefined();
589
+ expect(result.returnValue).toBe("/base/http://169.254.169.254/metadata");
590
+ expect(loopbackServer.requestCount()).toBe(1);
591
+ } finally {
592
+ await loopbackServer.close();
593
+ }
594
+ });
595
+ });
596
+
597
+ describe("VMRunner sandbox axios bridge — private network policy", () => {
598
+ const rfc1918Request: string = `
599
+ try {
600
+ await axios.get('http://10.0.0.5/internal', { timeout: 1 });
601
+ return 'request reached transport';
602
+ } catch (error) {
603
+ return 'request failed: ' + error.message;
604
+ }
605
+ `;
606
+
607
+ const incompletePolicies: Array<[string, SandboxPrivateNetworkOptions]> = [
608
+ ["neither flag", {}],
609
+ ["eligibility only", { allowPrivateNetworkRequests: true }],
610
+ ["trusted policy only", { privateNetworkAccessIsAllowed: true }],
611
+ [
612
+ "a false trusted policy",
613
+ {
614
+ allowPrivateNetworkRequests: true,
615
+ privateNetworkAccessIsAllowed: false,
616
+ },
617
+ ],
618
+ ];
619
+
620
+ test.each(incompletePolicies)(
621
+ "refuses RFC1918 with %s",
622
+ async (
623
+ _label: string,
624
+ policy: SandboxPrivateNetworkOptions,
625
+ ): Promise<void> => {
626
+ const message: string = await errorFromSandbox(rfc1918Request, policy);
627
+
628
+ expect(message).toMatch(REFUSAL);
629
+ },
630
+ );
631
+
632
+ test("allows RFC1918 past the guard only when both flags are true", async () => {
633
+ const message: string = await errorFromSandbox(rfc1918Request, {
634
+ allowPrivateNetworkRequests: true,
635
+ privateNetworkAccessIsAllowed: true,
636
+ });
637
+
638
+ expect(message).not.toMatch(REFUSAL);
639
+ });
640
+
641
+ test("an unaware workflow caller retains webhook-config behavior", async () => {
642
+ process.env[ALLOW_PRIVATE_NETWORK_WEBHOOKS_ENV] = "true";
643
+
644
+ const message: string = await errorFromSandbox(rfc1918Request, {
645
+ allowPrivateNetworkRequests: true,
646
+ });
647
+
648
+ expect(message).not.toMatch(REFUSAL);
649
+ });
650
+
651
+ const alwaysForbiddenTargets: Array<[string, string]> = [
652
+ ["link-local metadata", "http://169.254.169.254/latest/meta-data/"],
653
+ ["Alibaba metadata", "http://100.100.100.200/latest/meta-data/"],
654
+ ["Azure WireServer", "http://168.63.129.16/machine/?comp=goalstate"],
655
+ ["Oracle Cloud metadata", "http://192.0.0.192/opc/v2/instance/"],
656
+ ["AWS IPv6 services", "http://[fd00:ec2::254]/latest/meta-data/"],
657
+ ["Google IPv6 metadata", "http://[fd20:ce::254]/computeMetadata/v1/"],
658
+ ["RFC 8215 translation", "http://[64:ff9b:1::1]/"],
659
+ ["legacy SIIT translation", "http://[0:0:0:0:ffff:0:7f00:1]/"],
660
+ ];
661
+
662
+ test.each(alwaysForbiddenTargets)(
663
+ "still refuses %s when both private-network flags are true",
664
+ async (_label: string, url: string): Promise<void> => {
665
+ const message: string = await errorFromSandbox(
666
+ `return await axios.get(${JSON.stringify(url)});`,
667
+ {
668
+ allowPrivateNetworkRequests: true,
669
+ privateNetworkAccessIsAllowed: true,
670
+ },
671
+ );
672
+
673
+ expect(message).toMatch(REFUSAL);
674
+ },
675
+ );
676
+ });
677
+
678
+ describe("VMRunner sandbox axios bridge — bounded host I/O", () => {
679
+ const allowLoopbackForWorkflow: SandboxPrivateNetworkOptions = {
680
+ allowPrivateNetworkRequests: true,
681
+ };
682
+
683
+ beforeEach(() => {
684
+ process.env[PRIVATE_NETWORK_WEBHOOK_ALLOWLIST_ENV] = "127.0.0.1";
685
+ });
686
+
687
+ test("counts decompressed response bytes and destroys an oversized gzip stream", async () => {
688
+ const expandedBody: Buffer = Buffer.alloc(10 * 1024 * 1024 + 1, "a");
689
+ const compressedBody: Buffer = gzipSync(expandedBody);
690
+ const loopbackServer: RunningLoopbackServer = await startLoopbackServer(
691
+ (_request: http.IncomingMessage, response: http.ServerResponse): void => {
692
+ response.writeHead(200, {
693
+ "content-encoding": "gzip",
694
+ "content-length": compressedBody.length,
695
+ "content-type": "text/plain",
696
+ });
697
+ response.end(compressedBody);
698
+ },
699
+ );
700
+
701
+ try {
702
+ const message: string = await errorFromSandbox(
703
+ `return await axios.get('http://127.0.0.1:${loopbackServer.port}/gzip');`,
704
+ allowLoopbackForWorkflow,
705
+ );
706
+
707
+ expect(message).toMatch(/exceeded the allowed size/i);
708
+ expect(loopbackServer.requestCount()).toBe(1);
709
+ } finally {
710
+ await loopbackServer.close();
711
+ }
712
+ });
713
+
714
+ test("shares one cumulative response-byte budget across sandbox requests", async () => {
715
+ const responseBody: Buffer = Buffer.alloc(6 * 1024 * 1024, "a");
716
+ const loopbackServer: RunningLoopbackServer = await startLoopbackServer(
717
+ (_request: http.IncomingMessage, response: http.ServerResponse): void => {
718
+ response.writeHead(200, {
719
+ "content-length": responseBody.length,
720
+ "content-type": "text/plain",
721
+ });
722
+ response.end(responseBody);
723
+ },
724
+ );
725
+
726
+ try {
727
+ const message: string = await errorFromSandbox(
728
+ `
729
+ await axios.get('http://127.0.0.1:${loopbackServer.port}/first');
730
+ return await axios.get('http://127.0.0.1:${loopbackServer.port}/second');
731
+ `,
732
+ allowLoopbackForWorkflow,
733
+ );
734
+
735
+ expect(message).toMatch(/exceeded the allowed size/i);
736
+ expect(loopbackServer.requestCount()).toBe(2);
737
+ } finally {
738
+ await loopbackServer.close();
739
+ }
740
+ });
741
+
742
+ test("rejects an oversized serialized request before host parsing or socket I/O", async () => {
743
+ const loopbackServer: RunningLoopbackServer = await startLoopbackServer();
744
+
745
+ try {
746
+ const result: ReturnResult = await runInSandbox(
747
+ `
748
+ try {
749
+ await axios.post(
750
+ 'http://127.0.0.1:${loopbackServer.port}/upload',
751
+ { payload: 'x'.repeat(10 * 1024 * 1024 + 1) }
752
+ );
753
+ return 'request sent';
754
+ } catch (error) {
755
+ return 'request refused: ' + error.message;
756
+ }
757
+ `,
758
+ allowLoopbackForWorkflow,
759
+ );
760
+
761
+ expect(result.returnValue).toMatch(/request refused:/i);
762
+ expect(result.returnValue).toMatch(
763
+ /request body exceeded|maxbodylength|larger than|max body/i,
764
+ );
765
+ expect(loopbackServer.requestCount()).toBe(0);
766
+ } finally {
767
+ await loopbackServer.close();
768
+ }
769
+ });
770
+
771
+ test("caps cumulative serialized request bytes across one sandbox execution", async () => {
772
+ const loopbackServer: RunningLoopbackServer = await startLoopbackServer(
773
+ (request: http.IncomingMessage, response: http.ServerResponse): void => {
774
+ request.resume();
775
+ request.on("end", (): void => {
776
+ response.setHeader("content-type", "application/json");
777
+ response.end('{"ok":true}');
778
+ });
779
+ },
780
+ );
781
+
782
+ try {
783
+ const result: ReturnResult = await runInSandbox(
784
+ `
785
+ const body = { payload: 'x'.repeat(6 * 1024 * 1024) };
786
+ await axios.post(
787
+ 'http://127.0.0.1:${loopbackServer.port}/first',
788
+ body
789
+ );
790
+ try {
791
+ await axios.post(
792
+ 'http://127.0.0.1:${loopbackServer.port}/second',
793
+ body
794
+ );
795
+ return 'second request sent';
796
+ } catch (error) {
797
+ return 'second request refused: ' + error.message;
798
+ }
799
+ `,
800
+ allowLoopbackForWorkflow,
801
+ );
802
+
803
+ expect(result.scriptError).toBeUndefined();
804
+ expect(result.returnValue).toMatch(/cumulative request size/i);
805
+ expect(loopbackServer.requestCount()).toBe(1);
806
+ } finally {
807
+ await loopbackServer.close();
808
+ }
809
+ });
810
+
811
+ test("returns arraybuffer data without decimal-array serialization amplification", async () => {
812
+ const binaryBody: Buffer = Buffer.from([0, 255, 1, 254]);
813
+ const loopbackServer: RunningLoopbackServer = await startLoopbackServer(
814
+ (_request: http.IncomingMessage, response: http.ServerResponse): void => {
815
+ response.writeHead(200, {
816
+ "content-length": binaryBody.length,
817
+ "content-type": "application/octet-stream",
818
+ });
819
+ response.end(binaryBody);
820
+ },
821
+ );
822
+
823
+ try {
824
+ const result: ReturnResult = await runInSandbox(
825
+ `
826
+ const response = await axios.get(
827
+ 'http://127.0.0.1:${loopbackServer.port}/binary',
828
+ { responseType: 'arraybuffer' }
829
+ );
830
+ return {
831
+ type: response.data.constructor.name,
832
+ length: response.data.length,
833
+ bytes: Array.from(response.data)
834
+ };
835
+ `,
836
+ allowLoopbackForWorkflow,
837
+ );
838
+
839
+ expect(result.scriptError).toBeUndefined();
840
+ expect(result.returnValue).toEqual({
841
+ type: "Uint8Array",
842
+ length: 4,
843
+ bytes: [0, 255, 1, 254],
844
+ });
845
+ } finally {
846
+ await loopbackServer.close();
847
+ }
848
+ });
849
+
850
+ test("caps base64 arraybuffer serialization and keeps its raw bytes charged", async () => {
851
+ const binaryBody: Buffer = Buffer.alloc(8 * 1024 * 1024, 255);
852
+ const followUpBody: Buffer = Buffer.alloc(3 * 1024 * 1024, "a");
853
+ const loopbackServer: RunningLoopbackServer = await startLoopbackServer(
854
+ (request: http.IncomingMessage, response: http.ServerResponse): void => {
855
+ const body: Buffer =
856
+ request.url === "/binary" ? binaryBody : followUpBody;
857
+ response.writeHead(200, {
858
+ "content-length": body.length,
859
+ "content-type": "application/octet-stream",
860
+ });
861
+ response.end(body);
862
+ },
863
+ );
864
+
865
+ try {
866
+ const result: ReturnResult = await runInSandbox(
867
+ `
868
+ let firstError = '';
869
+ try {
870
+ await axios.get(
871
+ 'http://127.0.0.1:${loopbackServer.port}/binary',
872
+ { responseType: 'arraybuffer' }
873
+ );
874
+ } catch (error) {
875
+ firstError = error.message;
876
+ }
877
+
878
+ try {
879
+ await axios.get(
880
+ 'http://127.0.0.1:${loopbackServer.port}/follow-up'
881
+ );
882
+ return 'follow-up unexpectedly succeeded';
883
+ } catch (error) {
884
+ return firstError + ' | ' + error.message;
885
+ }
886
+ `,
887
+ allowLoopbackForWorkflow,
888
+ );
889
+
890
+ expect(result.scriptError).toBeUndefined();
891
+ expect(result.returnValue).toMatch(
892
+ /remote response exceeded the allowed serialized size/i,
893
+ );
894
+ expect(result.returnValue).toMatch(/remote response exceeded/i);
895
+ expect(loopbackServer.requestCount()).toBe(2);
896
+ } finally {
897
+ await loopbackServer.close();
898
+ }
899
+ });
900
+
901
+ test("base64-bridges control-heavy text before decoding it in the isolate", async () => {
902
+ const controlBody: Buffer = Buffer.alloc(7 * 1024 * 1024, 0);
903
+ const loopbackServer: RunningLoopbackServer = await startLoopbackServer(
904
+ (_request: http.IncomingMessage, response: http.ServerResponse): void => {
905
+ response.writeHead(200, {
906
+ "content-length": controlBody.length,
907
+ "content-type": "text/plain",
908
+ });
909
+ response.end(controlBody);
910
+ },
911
+ );
912
+
913
+ try {
914
+ const result: ReturnResult = await runInSandbox(
915
+ `
916
+ const response = await axios.get(
917
+ 'http://127.0.0.1:${loopbackServer.port}/control-text',
918
+ { responseType: 'text' }
919
+ );
920
+ return {
921
+ length: response.data.length,
922
+ firstCodePoint: response.data.charCodeAt(0),
923
+ lastCodePoint: response.data.charCodeAt(response.data.length - 1)
924
+ };
925
+ `,
926
+ allowLoopbackForWorkflow,
927
+ );
928
+
929
+ expect(result.scriptError).toBeUndefined();
930
+ expect(result.returnValue).toEqual({
931
+ length: 7 * 1024 * 1024,
932
+ firstCodePoint: 0,
933
+ lastCodePoint: 0,
934
+ });
935
+ expect(loopbackServer.requestCount()).toBe(1);
936
+ } finally {
937
+ await loopbackServer.close();
938
+ }
939
+ });
940
+
941
+ test("preserves responseEncoding while decoding response bytes inside the isolate", async () => {
942
+ const latin1Body: Buffer = Buffer.from([0x63, 0x61, 0x66, 0xe9]);
943
+ const loopbackServer: RunningLoopbackServer = await startLoopbackServer(
944
+ (_request: http.IncomingMessage, response: http.ServerResponse): void => {
945
+ response.end(latin1Body);
946
+ },
947
+ );
948
+
949
+ try {
950
+ const result: ReturnResult = await runInSandbox(
951
+ `
952
+ const response = await axios.get(
953
+ 'http://127.0.0.1:${loopbackServer.port}/latin1',
954
+ { responseType: 'text', responseEncoding: 'latin1' }
955
+ );
956
+ return response.data;
957
+ `,
958
+ allowLoopbackForWorkflow,
959
+ );
960
+
961
+ expect(result.scriptError).toBeUndefined();
962
+ expect(result.returnValue).toBe("café");
963
+ } finally {
964
+ await loopbackServer.close();
965
+ }
966
+ });
967
+
968
+ test("strips a UTF-8 BOM before default JSON parsing and text delivery", async () => {
969
+ const bomJsonBody: Buffer = Buffer.concat([
970
+ Buffer.from([0xef, 0xbb, 0xbf]),
971
+ Buffer.from('{"ok":true}', "utf8"),
972
+ ]);
973
+ const loopbackServer: RunningLoopbackServer = await startLoopbackServer(
974
+ (_request: http.IncomingMessage, response: http.ServerResponse): void => {
975
+ response.end(bomJsonBody);
976
+ },
977
+ );
978
+
979
+ try {
980
+ const result: ReturnResult = await runInSandbox(
981
+ `
982
+ const defaultResponse = await axios.get(
983
+ 'http://127.0.0.1:${loopbackServer.port}/default'
984
+ );
985
+ const textResponse = await axios.get(
986
+ 'http://127.0.0.1:${loopbackServer.port}/text',
987
+ { responseType: 'text', responseEncoding: 'utf8' }
988
+ );
989
+ return {
990
+ defaultData: defaultResponse.data,
991
+ textData: textResponse.data,
992
+ firstTextCodePoint: textResponse.data.charCodeAt(0)
993
+ };
994
+ `,
995
+ allowLoopbackForWorkflow,
996
+ );
997
+
998
+ expect(result.scriptError).toBeUndefined();
999
+ expect(result.returnValue).toEqual({
1000
+ defaultData: { ok: true },
1001
+ textData: '{"ok":true}',
1002
+ firstTextCodePoint: 123,
1003
+ });
1004
+ } finally {
1005
+ await loopbackServer.close();
1006
+ }
1007
+ });
1008
+
1009
+ test("honors transitional forcedJSONParsing false", async () => {
1010
+ const loopbackServer: RunningLoopbackServer = await startLoopbackServer(
1011
+ (_request: http.IncomingMessage, response: http.ServerResponse): void => {
1012
+ response.end('{"ok":true}');
1013
+ },
1014
+ );
1015
+
1016
+ try {
1017
+ const result: ReturnResult = await runInSandbox(
1018
+ `
1019
+ const response = await axios.get(
1020
+ 'http://127.0.0.1:${loopbackServer.port}/forced-off',
1021
+ { transitional: { forcedJSONParsing: false } }
1022
+ );
1023
+ return {
1024
+ type: typeof response.data,
1025
+ data: response.data
1026
+ };
1027
+ `,
1028
+ allowLoopbackForWorkflow,
1029
+ );
1030
+
1031
+ expect(result.scriptError).toBeUndefined();
1032
+ expect(result.returnValue).toEqual({
1033
+ type: "string",
1034
+ data: '{"ok":true}',
1035
+ });
1036
+ } finally {
1037
+ await loopbackServer.close();
1038
+ }
1039
+ });
1040
+
1041
+ test("honors strict JSON parsing and retains Axios error response context", async () => {
1042
+ const loopbackServer: RunningLoopbackServer = await startLoopbackServer(
1043
+ (_request: http.IncomingMessage, response: http.ServerResponse): void => {
1044
+ response.writeHead(200, { "x-response-sentinel": "strict-json" });
1045
+ response.end("not-json");
1046
+ },
1047
+ );
1048
+
1049
+ try {
1050
+ const result: ReturnResult = await runInSandbox(
1051
+ `
1052
+ try {
1053
+ await axios.get(
1054
+ 'http://127.0.0.1:${loopbackServer.port}/strict-json',
1055
+ {
1056
+ responseType: 'json',
1057
+ transitional: { silentJSONParsing: false }
1058
+ }
1059
+ );
1060
+ return 'unexpected success';
1061
+ } catch (error) {
1062
+ return {
1063
+ isAxiosError: axios.isAxiosError(error),
1064
+ name: error.name,
1065
+ code: error.code,
1066
+ status: error.response.status,
1067
+ header: error.response.headers['x-response-sentinel'],
1068
+ configMethod: error.config.method,
1069
+ configUrl: error.config.url,
1070
+ sameConfigUrl:
1071
+ error.config.url === error.response.config.url,
1072
+ hasRequest: Boolean(error.request),
1073
+ hasResponseRequest: Boolean(error.response.request),
1074
+ data: error.response.data
1075
+ };
1076
+ }
1077
+ `,
1078
+ allowLoopbackForWorkflow,
1079
+ );
1080
+
1081
+ expect(result.scriptError).toBeUndefined();
1082
+ expect(result.returnValue).toMatchObject({
1083
+ isAxiosError: true,
1084
+ name: "SyntaxError",
1085
+ code: "ERR_BAD_RESPONSE",
1086
+ status: 200,
1087
+ header: "strict-json",
1088
+ configMethod: "get",
1089
+ configUrl: `http://127.0.0.1:${loopbackServer.port}/strict-json`,
1090
+ sameConfigUrl: true,
1091
+ hasRequest: true,
1092
+ hasResponseRequest: true,
1093
+ data: "not-json",
1094
+ });
1095
+ } finally {
1096
+ await loopbackServer.close();
1097
+ }
1098
+ });
1099
+
1100
+ test("preserves a stricter caller maxContentLength and wraps its stream failure", async () => {
1101
+ const loopbackServer: RunningLoopbackServer = await startLoopbackServer(
1102
+ (_request: http.IncomingMessage, response: http.ServerResponse): void => {
1103
+ response.writeHead(200, {
1104
+ "content-length": "4",
1105
+ "x-response-sentinel": "content-limit",
1106
+ });
1107
+ response.end("four");
1108
+ },
1109
+ );
1110
+
1111
+ try {
1112
+ const result: ReturnResult = await runInSandbox(
1113
+ `
1114
+ try {
1115
+ await axios.get(
1116
+ 'http://127.0.0.1:${loopbackServer.port}/content-limit',
1117
+ { maxContentLength: 3 }
1118
+ );
1119
+ return 'unexpected success';
1120
+ } catch (error) {
1121
+ return {
1122
+ message: error.message,
1123
+ isAxiosError: axios.isAxiosError(error),
1124
+ status: error.response.status,
1125
+ header: error.response.headers['x-response-sentinel'],
1126
+ configLimit: error.config.maxContentLength,
1127
+ responseConfigLimit: error.response.config.maxContentLength,
1128
+ hasRequest: Boolean(error.request),
1129
+ hasResponseRequest: Boolean(error.response.request)
1130
+ };
1131
+ }
1132
+ `,
1133
+ allowLoopbackForWorkflow,
1134
+ );
1135
+
1136
+ expect(result.scriptError).toBeUndefined();
1137
+ expect(result.returnValue).toMatchObject({
1138
+ message: expect.stringMatching(/exceeded the allowed size/i),
1139
+ isAxiosError: true,
1140
+ status: 200,
1141
+ header: "content-limit",
1142
+ configLimit: 3,
1143
+ responseConfigLimit: 3,
1144
+ hasRequest: true,
1145
+ hasResponseRequest: true,
1146
+ });
1147
+ expect(loopbackServer.requestCount()).toBe(1);
1148
+ } finally {
1149
+ await loopbackServer.close();
1150
+ }
1151
+ });
1152
+
1153
+ test("preserves a stricter caller maxBodyLength", async () => {
1154
+ const loopbackServer: RunningLoopbackServer = await startLoopbackServer();
1155
+
1156
+ try {
1157
+ const result: ReturnResult = await runInSandbox(
1158
+ `
1159
+ try {
1160
+ await axios.post(
1161
+ 'http://127.0.0.1:${loopbackServer.port}/body-limit',
1162
+ 'four',
1163
+ { maxBodyLength: 3 }
1164
+ );
1165
+ return 'unexpected success';
1166
+ } catch (error) {
1167
+ return error.message;
1168
+ }
1169
+ `,
1170
+ allowLoopbackForWorkflow,
1171
+ );
1172
+
1173
+ expect(result.scriptError).toBeUndefined();
1174
+ expect(result.returnValue).toMatch(/maxBodyLength/i);
1175
+ expect(loopbackServer.requestCount()).toBe(0);
1176
+ } finally {
1177
+ await loopbackServer.close();
1178
+ }
1179
+ });
1180
+
1181
+ test("wraps a mid-body stream failure with Axios response context", async () => {
1182
+ const loopbackServer: RunningLoopbackServer = await startLoopbackServer(
1183
+ (_request: http.IncomingMessage, response: http.ServerResponse): void => {
1184
+ response.writeHead(200, {
1185
+ "content-length": "100",
1186
+ "x-response-sentinel": "mid-body",
1187
+ });
1188
+ response.write("partial body");
1189
+ response.flushHeaders();
1190
+ setTimeout((): void => {
1191
+ response.destroy();
1192
+ }, 10);
1193
+ },
1194
+ );
1195
+
1196
+ try {
1197
+ const result: ReturnResult = await runInSandbox(
1198
+ `
1199
+ try {
1200
+ await axios.get(
1201
+ 'http://127.0.0.1:${loopbackServer.port}/mid-body'
1202
+ );
1203
+ return 'unexpected success';
1204
+ } catch (error) {
1205
+ return {
1206
+ isAxiosError: axios.isAxiosError(error),
1207
+ status: error.response.status,
1208
+ header: error.response.headers['x-response-sentinel'],
1209
+ configMethod: error.config.method,
1210
+ configUrl: error.config.url,
1211
+ sameConfigUrl:
1212
+ error.config.url === error.response.config.url,
1213
+ hasRequest: Boolean(error.request),
1214
+ hasResponseRequest: Boolean(error.response.request),
1215
+ boundedData: error.response.data
1216
+ };
1217
+ }
1218
+ `,
1219
+ allowLoopbackForWorkflow,
1220
+ );
1221
+
1222
+ expect(result.scriptError).toBeUndefined();
1223
+ expect(result.returnValue).toMatchObject({
1224
+ isAxiosError: true,
1225
+ status: 200,
1226
+ header: "mid-body",
1227
+ configMethod: "get",
1228
+ configUrl: `http://127.0.0.1:${loopbackServer.port}/mid-body`,
1229
+ sameConfigUrl: true,
1230
+ hasRequest: true,
1231
+ hasResponseRequest: true,
1232
+ boundedData: "",
1233
+ });
1234
+ expect(loopbackServer.requestCount()).toBe(1);
1235
+ } finally {
1236
+ await loopbackServer.close();
1237
+ }
1238
+ });
1239
+
1240
+ test("preserves Axios's silent invalid-JSON response behavior", async () => {
1241
+ const loopbackServer: RunningLoopbackServer = await startLoopbackServer(
1242
+ (_request: http.IncomingMessage, response: http.ServerResponse): void => {
1243
+ response.writeHead(200, { "content-type": "application/json" });
1244
+ response.end("not-json");
1245
+ },
1246
+ );
1247
+
1248
+ try {
1249
+ const result: ReturnResult = await runInSandbox(
1250
+ `
1251
+ const response = await axios.get(
1252
+ 'http://127.0.0.1:${loopbackServer.port}/invalid-json',
1253
+ { responseType: 'json' }
1254
+ );
1255
+ return response.data;
1256
+ `,
1257
+ allowLoopbackForWorkflow,
1258
+ );
1259
+
1260
+ expect(result.scriptError).toBeUndefined();
1261
+ expect(result.returnValue).toBe("not-json");
1262
+ } finally {
1263
+ await loopbackServer.close();
1264
+ }
1265
+ });
1266
+
1267
+ test("decodes and parses a bounded Axios error response inside the isolate", async () => {
1268
+ const loopbackServer: RunningLoopbackServer = await startLoopbackServer(
1269
+ (_request: http.IncomingMessage, response: http.ServerResponse): void => {
1270
+ response.writeHead(418, { "content-type": "application/json" });
1271
+ response.end('{"error":"teapot"}');
1272
+ },
1273
+ );
1274
+
1275
+ try {
1276
+ const result: ReturnResult = await runInSandbox(
1277
+ `
1278
+ try {
1279
+ await axios.get(
1280
+ 'http://127.0.0.1:${loopbackServer.port}/error'
1281
+ );
1282
+ return 'unexpected success';
1283
+ } catch (error) {
1284
+ return {
1285
+ status: error.response.status,
1286
+ data: error.response.data
1287
+ };
1288
+ }
1289
+ `,
1290
+ allowLoopbackForWorkflow,
1291
+ );
1292
+
1293
+ expect(result.scriptError).toBeUndefined();
1294
+ expect(result.returnValue).toEqual({
1295
+ status: 418,
1296
+ data: { error: "teapot" },
1297
+ });
1298
+ } finally {
1299
+ await loopbackServer.close();
1300
+ }
1301
+ });
1302
+ });
1303
+
161
1304
  /*
162
1305
  * The "is this already an absolute URL?" decision is what tells the guard
163
1306
  * whether to fold in baseURL before validating, so it has to be scheme
@@ -194,4 +1337,31 @@ describe("VMRunner sandbox axios bridge — URL absolutization", () => {
194
1337
  );
195
1338
  expect(message).not.toMatch(REFUSAL);
196
1339
  });
1340
+
1341
+ test.each([
1342
+ ["protocol-relative", "//169.254.169.254/metadata"],
1343
+ ["non-HTTP scheme", "file:///etc/passwd"],
1344
+ ])(
1345
+ "treats an Axios-absolute %s URL as absolute before rejecting its final scheme",
1346
+ async (_label: string, requestedUrl: string): Promise<void> => {
1347
+ const loopbackServer: RunningLoopbackServer = await startLoopbackServer();
1348
+
1349
+ try {
1350
+ const message: string = await errorFromSandbox(
1351
+ `return await axios.get(${JSON.stringify(requestedUrl)}, {
1352
+ baseURL: 'http://127.0.0.1:${loopbackServer.port}/must-not-run'
1353
+ });`,
1354
+ {
1355
+ allowPrivateNetworkRequests: true,
1356
+ privateNetworkAccessIsAllowed: true,
1357
+ },
1358
+ );
1359
+
1360
+ expect(message).toMatch(/absolute http or https/i);
1361
+ expect(loopbackServer.requestCount()).toBe(0);
1362
+ } finally {
1363
+ await loopbackServer.close();
1364
+ }
1365
+ },
1366
+ );
197
1367
  });