@oneuptime/common 13.0.3 → 13.0.5

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 (687) hide show
  1. package/Models/DatabaseModels/Index.ts +4 -0
  2. package/Models/DatabaseModels/RumApplication.ts +1 -1
  3. package/Models/DatabaseModels/SecurityEventConnection.ts +457 -0
  4. package/Models/DatabaseModels/SecurityEventConnectionRun.ts +263 -0
  5. package/Models/DatabaseModels/TelemetryIngestionKey.ts +2 -2
  6. package/Server/API/AIInvestigationAPI.ts +484 -24
  7. package/Server/API/GoogleSecOpsConnectionAPI.ts +249 -8
  8. package/Server/API/SecurityEventConnectionAPI.ts +250 -0
  9. package/Server/API/TelemetryAPI.ts +402 -265
  10. package/Server/Infrastructure/Postgres/SchemaMigrations/1792700000000-AddSecurityEventConnections.ts +99 -0
  11. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +2 -0
  12. package/Server/Middleware/TelemetryIngest.ts +101 -6
  13. package/Server/Services/ExceptionAggregationService.ts +7 -16
  14. package/Server/Services/GoogleSecOpsConnectionService.ts +15 -0
  15. package/Server/Services/Index.ts +4 -0
  16. package/Server/Services/InventoryItemService.ts +28 -0
  17. package/Server/Services/LogAggregationService.ts +17 -23
  18. package/Server/Services/MetricAggregationService.ts +4 -14
  19. package/Server/Services/SecurityEventConnectionRunService.ts +10 -0
  20. package/Server/Services/SecurityEventConnectionService.ts +538 -0
  21. package/Server/Services/TraceAggregationService.ts +77 -28
  22. package/Server/Types/AnalyticsDatabase/ModelPermission.ts +9 -0
  23. package/Server/Utils/AI/Chat/ObservabilityAssistant.ts +13 -1
  24. package/Server/Utils/AI/SRE/AIInvestigationEngine.ts +15 -1
  25. package/Server/Utils/AI/SRE/InvestigationEvidence.ts +658 -0
  26. package/Server/Utils/AI/SRE/InvestigationReferences.ts +324 -0
  27. package/Server/Utils/AI/Toolbox/Index.ts +38 -0
  28. package/Server/Utils/AI/Toolbox/TimelineTools.ts +9 -2
  29. package/Server/Utils/AnalyticsDatabase/StatementGenerator.ts +80 -0
  30. package/Server/Utils/Monitor/MonitorCriteriaEvaluator.ts +5 -3
  31. package/Server/Utils/SecurityEvent/Connectors/AwsSecurityHub/AwsSecurityHubClient.ts +1108 -0
  32. package/Server/Utils/SecurityEvent/Connectors/AwsSecurityHub/AwsSecurityHubConnector.ts +732 -0
  33. package/Server/Utils/SecurityEvent/Connectors/ConnectorPlatformHealth.ts +495 -0
  34. package/Server/Utils/SecurityEvent/Connectors/CrowdStrikeFalcon/CrowdStrikeFalconClient.ts +689 -0
  35. package/Server/Utils/SecurityEvent/Connectors/CrowdStrikeFalcon/CrowdStrikeFalconConnector.ts +767 -0
  36. package/Server/Utils/SecurityEvent/Connectors/ElasticSecurity/ElasticSecurityClient.ts +571 -0
  37. package/Server/Utils/SecurityEvent/Connectors/ElasticSecurity/ElasticSecurityConnector.ts +827 -0
  38. package/Server/Utils/SecurityEvent/Connectors/MicrosoftDefenderXdr/MicrosoftDefenderXdrClient.ts +610 -0
  39. package/Server/Utils/SecurityEvent/Connectors/MicrosoftDefenderXdr/MicrosoftDefenderXdrConnector.ts +549 -0
  40. package/Server/Utils/SecurityEvent/Connectors/MicrosoftSentinel/MicrosoftSentinelClient.ts +830 -0
  41. package/Server/Utils/SecurityEvent/Connectors/MicrosoftSentinel/MicrosoftSentinelConnector.ts +684 -0
  42. package/Server/Utils/SecurityEvent/Connectors/Okta/OktaClient.ts +487 -0
  43. package/Server/Utils/SecurityEvent/Connectors/Okta/OktaConnector.ts +778 -0
  44. package/Server/Utils/SecurityEvent/Connectors/SecurityEventConnectionPoller.ts +1002 -0
  45. package/Server/Utils/SecurityEvent/Connectors/SecurityEventConnectionRunExecutor.ts +556 -0
  46. package/Server/Utils/SecurityEvent/Connectors/SecurityEventConnectionTester.ts +275 -0
  47. package/Server/Utils/SecurityEvent/Connectors/SecurityEventConnectorRegistry.ts +53 -0
  48. package/Server/Utils/SecurityEvent/Connectors/Splunk/SplunkClient.ts +709 -0
  49. package/Server/Utils/SecurityEvent/Connectors/Splunk/SplunkConnector.ts +596 -0
  50. package/Server/Utils/SecurityEvent/Connectors/Types.ts +191 -0
  51. package/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsClient.ts +353 -65
  52. package/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsConnectionTester.ts +777 -0
  53. package/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsPoller.ts +747 -148
  54. package/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsRunExecutor.ts +48 -2
  55. package/Server/Utils/SecurityEvent/SecurityEventDedupe.ts +81 -0
  56. package/Server/Utils/SessionReplay/SessionReplayReadService.ts +741 -40
  57. package/Server/Utils/StartServer.ts +10 -0
  58. package/Server/Utils/Telemetry/EntityRegistry.ts +8 -0
  59. package/Server/Utils/Telemetry/KubernetesResourceAttributes.ts +108 -0
  60. package/Server/Utils/Telemetry/ResourceEntityFilter.ts +174 -93
  61. package/Server/Utils/Telemetry/ResourceFacetPlanner.ts +251 -0
  62. package/Server/Utils/Telemetry/ResourceFacetResolver.ts +248 -413
  63. package/Server/Utils/Telemetry/ServiceDependencyDiscovery.ts +668 -0
  64. package/Server/Utils/Telemetry/TraceContextPropagation.ts +348 -0
  65. package/Server/Utils/Telemetry.ts +18 -0
  66. package/Tests/App/Dashboard/AIInvestigationHeaderStatus.test.tsx +413 -0
  67. package/Tests/App/Dashboard/AIRootCauseFeedItem.test.tsx +285 -0
  68. package/Tests/App/Dashboard/AffectedResourcesDisplay.test.tsx +242 -0
  69. package/Tests/App/Dashboard/AlertEpisodeViewFields.test.tsx +601 -15
  70. package/Tests/App/Dashboard/ChangeAlertStateAIHeader.test.tsx +835 -0
  71. package/Tests/App/Dashboard/CloudResourceTelemetryScope.test.ts +41 -0
  72. package/Tests/App/Dashboard/ConnectionTestModal.test.tsx +604 -0
  73. package/Tests/App/Dashboard/ConnectorTestReportView.test.tsx +738 -0
  74. package/Tests/App/Dashboard/DashboardLazyPages.test.tsx +153 -6
  75. package/Tests/App/Dashboard/EntityDetailPanel.test.tsx +165 -0
  76. package/Tests/App/Dashboard/EpisodeChangeState.test.tsx +1069 -0
  77. package/Tests/App/Dashboard/EpisodeMembersCard.test.tsx +772 -0
  78. package/Tests/App/Dashboard/EventOverviewPages.test.tsx +2354 -0
  79. package/Tests/App/Dashboard/EventOverviewSkeleton.test.tsx +210 -0
  80. package/Tests/App/Dashboard/EventStatBar.test.tsx +392 -0
  81. package/Tests/App/Dashboard/EventStatusPanel.test.tsx +247 -0
  82. package/Tests/App/Dashboard/ExceptionAIAssistance.test.tsx +606 -0
  83. package/Tests/App/Dashboard/ExceptionBreadcrumbTimeline.test.tsx +273 -0
  84. package/Tests/App/Dashboard/ExceptionDetailSideMenu.test.tsx +176 -0
  85. package/Tests/App/Dashboard/ExceptionOverviewCards.test.tsx +366 -0
  86. package/Tests/App/Dashboard/ExceptionSignalPages.test.tsx +371 -0
  87. package/Tests/App/Dashboard/ExceptionStackFrameViewer.test.tsx +440 -0
  88. package/Tests/App/Dashboard/ExceptionSummary.test.tsx +381 -0
  89. package/Tests/App/Dashboard/ExceptionTriage.test.tsx +306 -0
  90. package/Tests/App/Dashboard/ExceptionsResourceFacets.test.tsx +604 -0
  91. package/Tests/App/Dashboard/ExceptionsViewerEntityChips.test.tsx +706 -0
  92. package/Tests/App/Dashboard/FeedOrdering.test.ts +32 -0
  93. package/Tests/App/Dashboard/GoogleSecOpsConnectionForm.test.tsx +838 -0
  94. package/Tests/App/Dashboard/GoogleSecOpsConnectionsErrors.test.tsx +18 -0
  95. package/Tests/App/Dashboard/GoogleSecOpsDiagnostics.test.tsx +297 -20
  96. package/Tests/App/Dashboard/IncidentEpisodeViewFields.test.tsx +618 -13
  97. package/Tests/App/Dashboard/InfrastructureExplorer.test.tsx +254 -207
  98. package/Tests/App/Dashboard/InfrastructureGraph.test.tsx +303 -135
  99. package/Tests/App/Dashboard/InvestigationEvidenceList.test.tsx +1251 -0
  100. package/Tests/App/Dashboard/InvestigationFeedRefresh.test.tsx +303 -0
  101. package/Tests/App/Dashboard/InvestigationPanel.test.tsx +876 -8
  102. package/Tests/App/Dashboard/InvestigationPanelStatus.test.tsx +35 -0
  103. package/Tests/App/Dashboard/InvestigationReferenceLink.test.tsx +177 -0
  104. package/Tests/App/Dashboard/InvestigationReportView.test.tsx +1295 -0
  105. package/Tests/App/Dashboard/KubernetesImageReferenceView.test.tsx +114 -0
  106. package/Tests/App/Dashboard/KubernetesLogsTabChips.test.tsx +285 -0
  107. package/Tests/App/Dashboard/LogsEntityChipNames.test.tsx +316 -0
  108. package/Tests/App/Dashboard/LogsResourceFacetChips.test.tsx +361 -0
  109. package/Tests/App/Dashboard/ProfileTableEntityNames.test.tsx +432 -0
  110. package/Tests/App/Dashboard/ProfileViewEntityName.test.tsx +250 -0
  111. package/Tests/App/Dashboard/ResourceArchiveSettings.test.tsx +10 -0
  112. package/Tests/App/Dashboard/ResourceLogsTabsBareLayout.test.tsx +700 -0
  113. package/Tests/App/Dashboard/ResourcePageEntityNameProps.test.tsx +803 -0
  114. package/Tests/App/Dashboard/RumSessionReplaySideMenu.test.tsx +11 -1
  115. package/Tests/App/Dashboard/ScheduledMaintenanceChangeState.test.tsx +1026 -0
  116. package/Tests/App/Dashboard/ScheduledMaintenanceFeedRefresh.test.tsx +436 -0
  117. package/Tests/App/Dashboard/ScheduledMaintenanceOverviewPage.test.tsx +1195 -0
  118. package/Tests/App/Dashboard/SecurityEventConnectionFormModal.test.tsx +1022 -0
  119. package/Tests/App/Dashboard/SecurityEventConnectionsTable.test.tsx +905 -0
  120. package/Tests/App/Dashboard/SecurityEventsSideMenu.test.tsx +247 -0
  121. package/Tests/App/Dashboard/ServiceMapGraph.test.tsx +375 -274
  122. package/Tests/App/Dashboard/SessionReplayAuditTable.test.tsx +410 -0
  123. package/Tests/App/Dashboard/TelemetryResourceRetentionSettings.test.tsx +774 -0
  124. package/Tests/App/Dashboard/TopErrorsPanelResourceNames.test.tsx +316 -0
  125. package/Tests/App/Dashboard/TopologyDataLoading.test.tsx +30 -0
  126. package/Tests/App/Dashboard/TopologyPageNavigation.test.tsx +88 -24
  127. package/Tests/App/Dashboard/TraceExplorer.test.tsx +1590 -0
  128. package/Tests/App/Dashboard/TraceWaterfall.test.tsx +488 -0
  129. package/Tests/App/Dashboard/TracesAnalyticsSeriesLabels.test.tsx +367 -0
  130. package/Tests/App/Dashboard/TracesEntityNames.test.tsx +585 -0
  131. package/Tests/App/Dashboard/TracesResourceFacets.test.tsx +613 -0
  132. package/Tests/App/Dashboard/UseServiceNames.test.tsx +359 -0
  133. package/Tests/Models/DatabaseModels/DomainRoleTierCoverage.test.ts +7 -0
  134. package/Tests/Models/InventoryItemNaming.test.ts +132 -16
  135. package/Tests/Models/SecurityDomainAccessControl.test.ts +61 -17
  136. package/Tests/Server/API/AIInvestigationAPI.test.ts +611 -2
  137. package/Tests/Server/API/AIInvestigationEvidenceAPI.test.ts +1098 -0
  138. package/Tests/Server/API/GoogleSecOpsConnectionAPI.test.ts +409 -0
  139. package/Tests/Server/API/SecurityEventConnectionAPI.test.ts +856 -0
  140. package/Tests/Server/API/SessionReplayAPI.test.ts +528 -1
  141. package/Tests/Server/API/TelemetryFacetsAPI.test.ts +810 -0
  142. package/Tests/Server/Infrastructure/E2EClickHouseFixtureAccess.test.ts +240 -0
  143. package/Tests/Server/Middleware/TelemetryIngestBrowserKey.test.ts +229 -0
  144. package/Tests/Server/Services/InventoryItemDisplayName.test.ts +66 -0
  145. package/Tests/Server/Services/OpenTelemetryResourceRetentionMemo.test.ts +28 -1
  146. package/Tests/Server/Services/SecurityEventConnectionService.test.ts +1233 -0
  147. package/Tests/Server/Services/TelemetryIngestionKeyValidation.test.ts +53 -0
  148. package/Tests/Server/Services/TelemetryResourceFacetCounting.test.ts +218 -0
  149. package/Tests/Server/Services/TelemetryResourceFacetFilters.test.ts +155 -1
  150. package/Tests/Server/Services/TraceAggregationExceptionScope.test.ts +142 -0
  151. package/Tests/Server/Services/TraceAnalyticsResourceDisplayNames.test.ts +85 -24
  152. package/Tests/Server/Types/Database/Permissions/SecurityRoleAccess.test.ts +33 -0
  153. package/Tests/Server/Utils/AI/InvestigationEvidence.test.ts +1395 -0
  154. package/Tests/Server/Utils/AI/InvestigationReferences.test.ts +616 -0
  155. package/Tests/Server/Utils/AI/TimelineTools.test.ts +119 -0
  156. package/Tests/Server/Utils/AI/Toolbox/AIToolbox.test.ts +151 -0
  157. package/Tests/Server/Utils/AnalyticsDatabase/StatementGenerator.test.ts +65 -0
  158. package/Tests/Server/Utils/AnalyticsDatabase/StatementGeneratorExceptionScope.test.ts +224 -0
  159. package/Tests/Server/Utils/LoggerCore.test.ts +597 -0
  160. package/Tests/Server/Utils/Monitor/MonitorCriteriaEvaluatorPerSeriesFanout.test.ts +55 -2
  161. package/Tests/Server/Utils/Monitor/MonitorTemplateUtil.test.ts +1109 -0
  162. package/Tests/Server/Utils/SecurityEvent/Connectors/AwsSecurityHub/AwsSecurityHubClient.test.ts +1240 -0
  163. package/Tests/Server/Utils/SecurityEvent/Connectors/AwsSecurityHub/AwsSecurityHubConnector.test.ts +1853 -0
  164. package/Tests/Server/Utils/SecurityEvent/Connectors/ConnectorPlatformHealth.test.ts +1129 -0
  165. package/Tests/Server/Utils/SecurityEvent/Connectors/CrowdStrikeFalcon/CrowdStrikeFalconClient.test.ts +1066 -0
  166. package/Tests/Server/Utils/SecurityEvent/Connectors/CrowdStrikeFalcon/CrowdStrikeFalconConnector.test.ts +1568 -0
  167. package/Tests/Server/Utils/SecurityEvent/Connectors/ElasticSecurity/ElasticSecurityClient.test.ts +930 -0
  168. package/Tests/Server/Utils/SecurityEvent/Connectors/ElasticSecurity/ElasticSecurityConnector.test.ts +1409 -0
  169. package/Tests/Server/Utils/SecurityEvent/Connectors/MicrosoftDefenderXdr/MicrosoftDefenderXdrClient.test.ts +763 -0
  170. package/Tests/Server/Utils/SecurityEvent/Connectors/MicrosoftDefenderXdr/MicrosoftDefenderXdrConnector.test.ts +1296 -0
  171. package/Tests/Server/Utils/SecurityEvent/Connectors/MicrosoftSentinel/MicrosoftSentinelClient.test.ts +1102 -0
  172. package/Tests/Server/Utils/SecurityEvent/Connectors/MicrosoftSentinel/MicrosoftSentinelConnector.test.ts +1174 -0
  173. package/Tests/Server/Utils/SecurityEvent/Connectors/Okta/OktaClient.test.ts +1032 -0
  174. package/Tests/Server/Utils/SecurityEvent/Connectors/Okta/OktaConnector.test.ts +1558 -0
  175. package/Tests/Server/Utils/SecurityEvent/Connectors/SecurityEventConnectionPoller.test.ts +3041 -0
  176. package/Tests/Server/Utils/SecurityEvent/Connectors/SecurityEventConnectionRunExecutor.test.ts +1168 -0
  177. package/Tests/Server/Utils/SecurityEvent/Connectors/SecurityEventConnectionTester.test.ts +906 -0
  178. package/Tests/Server/Utils/SecurityEvent/Connectors/Splunk/SplunkClient.test.ts +1068 -0
  179. package/Tests/Server/Utils/SecurityEvent/Connectors/Splunk/SplunkConnector.test.ts +1004 -0
  180. package/Tests/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsConnectionTester.test.ts +784 -0
  181. package/Tests/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsRunExecutor.test.ts +113 -1
  182. package/Tests/Server/Utils/SecurityEvent/GoogleSecOpsClient.test.ts +5 -1
  183. package/Tests/Server/Utils/SecurityEvent/GoogleSecOpsDiagnostics.test.ts +93 -13
  184. package/Tests/Server/Utils/SecurityEvent/GoogleSecOpsHttpIntegration.test.ts +23 -1
  185. package/Tests/Server/Utils/SecurityEvent/GoogleSecOpsPoller.test.ts +25 -3
  186. package/Tests/Server/Utils/SecurityEvent/GoogleSecOpsPollerFailureTaxonomy.test.ts +22 -8
  187. package/Tests/Server/Utils/SecurityEvent/GoogleSecOpsPollerHardening.test.ts +82 -16
  188. package/Tests/Server/Utils/SecurityEvent/GoogleSecOpsSearchDetections.test.ts +730 -0
  189. package/Tests/Server/Utils/SecurityEvent/GoogleSecOpsThreePassPoller.test.ts +1577 -0
  190. package/Tests/Server/Utils/SessionReplay/SessionReplayOriginAllowlist.test.ts +41 -0
  191. package/Tests/Server/Utils/SessionReplay/SessionReplayReadServiceQueries.test.ts +1453 -18
  192. package/Tests/Server/Utils/Telemetry/EntityRegistry.test.ts +711 -0
  193. package/Tests/Server/Utils/Telemetry/KubernetesResourceAttributes.test.ts +162 -0
  194. package/Tests/Server/Utils/Telemetry/ResourceEntityFilter.test.ts +460 -13
  195. package/Tests/Server/Utils/Telemetry/ResourceFacetPlanner.test.ts +678 -0
  196. package/Tests/Server/Utils/Telemetry/ResourceFacetResolver.test.ts +868 -0
  197. package/Tests/Server/Utils/Telemetry/ServiceDependencyDiscovery.test.ts +525 -0
  198. package/Tests/Server/Utils/Telemetry/TraceContextPropagation.test.ts +420 -0
  199. package/Tests/Types/OnCallDutyPolicy/LayerUtilCorePaths.test.ts +1014 -0
  200. package/Tests/Types/OnCallDutyPolicy/LayerUtilExhaustiveRotation.test.ts +9 -6
  201. package/Tests/Types/Rules/RuleCriteriaFieldRegistry.test.ts +276 -0
  202. package/Tests/Types/Rum/SessionReplayApiContracts.test.ts +73 -0
  203. package/Tests/Types/Rum/SessionReplayTransportContracts.test.ts +95 -0
  204. package/Tests/Types/SecurityEvent/Connectors/ConnectorDiagnostics.test.ts +82 -0
  205. package/Tests/Types/SecurityEvent/Connectors/SecurityEventConnectorCatalog.test.ts +314 -0
  206. package/Tests/Types/Telemetry/ExceptionSpanScope.test.ts +89 -0
  207. package/Tests/Types/Telemetry/LlmConventions.test.ts +495 -0
  208. package/Tests/Types/Telemetry/ResourceEntityFacet.test.ts +96 -0
  209. package/Tests/Types/Telemetry/ResourceFacetCatalog.test.ts +304 -0
  210. package/Tests/UI/Components/ActiveFilterChipsLockedFilters.test.tsx +357 -0
  211. package/Tests/UI/Components/Card.test.tsx +312 -1
  212. package/Tests/UI/Components/CardModelDetailHeaderLayout.test.tsx +253 -0
  213. package/Tests/UI/Components/CardModelDetailRefresher.test.tsx +342 -0
  214. package/Tests/UI/Components/Checkbox.test.tsx +79 -0
  215. package/Tests/UI/Components/CopyTextButton.test.tsx +142 -0
  216. package/Tests/UI/Components/DetailCompactStyle.test.tsx +621 -0
  217. package/Tests/UI/Components/ErrorBoundary.test.tsx +60 -0
  218. package/Tests/UI/Components/FacetSections.test.tsx +581 -0
  219. package/Tests/UI/Components/FacetSidebarControls.test.tsx +812 -0
  220. package/Tests/UI/Components/FacetVisibility.test.ts +429 -0
  221. package/Tests/UI/Components/LockedFilterActions.test.tsx +396 -0
  222. package/Tests/UI/Components/LockedFilterChip.test.tsx +651 -0
  223. package/Tests/UI/Components/LogsEntityNames.test.ts +1769 -0
  224. package/Tests/UI/Components/LogsEntityNamesComponents.test.tsx +696 -0
  225. package/Tests/UI/Components/LogsFacetSidebarHiddenFacets.test.tsx +600 -0
  226. package/Tests/UI/Components/LogsViewerEntityNames.test.tsx +713 -0
  227. package/Tests/UI/Components/MarkdownInlineReferences.test.tsx +2079 -0
  228. package/Tests/UI/Components/MemberRoleAssignment.test.tsx +446 -0
  229. package/Tests/UI/Components/ModelDetailRefetch.test.tsx +397 -0
  230. package/Tests/UI/Components/ModelListRefetch.test.tsx +233 -0
  231. package/Tests/UI/Components/ModelPageModelChange.test.tsx +409 -0
  232. package/Tests/UI/Components/PaginationIntegration.test.tsx +25 -0
  233. package/Tests/UI/Components/ResourceFacetConfigs.test.ts +172 -0
  234. package/Tests/UI/Components/SavedViewsSidebarIntegration.test.tsx +32 -14
  235. package/Tests/UI/Components/TableSortAndMobileColumns.test.tsx +44 -1
  236. package/Tests/UI/Components/TelemetryActiveFilterChipsLockedFilters.test.tsx +304 -0
  237. package/Tests/UI/Components/TelemetryFacetSidebarHiddenFacets.test.tsx +718 -0
  238. package/Tests/UI/Monitor/EvaluationLogList.test.tsx +303 -0
  239. package/Tests/UI/Monitor/MonitorSummarySnapshotRender.test.tsx +55 -1
  240. package/Tests/UI/Rum/FidelityNotices.test.ts +22 -0
  241. package/Tests/UI/Rum/RecordingHealthCard.test.tsx +120 -136
  242. package/Tests/UI/Rum/RecordingHealthDashboard.test.tsx +988 -0
  243. package/Tests/UI/Rum/ReplayCard.test.tsx +32 -0
  244. package/Tests/UI/Rum/ReplayCorrelationPanel.test.tsx +709 -12
  245. package/Tests/UI/Rum/ReplayHeader.test.tsx +50 -1
  246. package/Tests/UI/Rum/ReplayPinControl.test.tsx +67 -10
  247. package/Tests/UI/Rum/ReplayPlayerChrome.test.tsx +41 -12
  248. package/Tests/UI/Rum/ReplayStage.test.tsx +663 -1
  249. package/Tests/UI/Rum/ReplayStageOverlays.test.tsx +173 -0
  250. package/Tests/UI/Rum/ReplayUi.test.tsx +189 -2
  251. package/Tests/UI/Rum/ReplayUserSessionsMenu.test.tsx +91 -0
  252. package/Tests/UI/Rum/SessionReplayEmptyState.test.tsx +1 -1
  253. package/Tests/UI/Rum/SessionReplaySettingsPolicyLoading.test.tsx +585 -0
  254. package/Tests/UI/Rum/SessionReplayTable.test.tsx +844 -51
  255. package/Tests/UI/Rum/SessionReplayUsersTable.test.tsx +29 -1
  256. package/Tests/UI/Telemetry/TelemetryDetailPanel.test.tsx +288 -0
  257. package/Tests/UI/Utils/Breadcrumb/fixtures/RealBreadcrumbTrails.ts +31 -1
  258. package/Tests/UI/Utils/Breadcrumb/fixtures/RealRoutePatterns.ts +6 -0
  259. package/Tests/UI/Utils/Clipboard.test.ts +154 -0
  260. package/Tests/UI/Utils/Navigation.test.ts +24 -0
  261. package/Tests/UI/Utils/Telemetry/TelemetryEntityNames.test.ts +2205 -0
  262. package/Tests/UI/Utils/Telemetry/UseTelemetryEntityNames.test.tsx +844 -0
  263. package/Tests/Utils/AI/InvestigationReport.test.ts +2430 -0
  264. package/Tests/Utils/APIOutgoingRequestTracer.test.ts +137 -0
  265. package/Tests/Utils/Rum/SessionReplayHealth.test.ts +884 -0
  266. package/Tests/Utils/Rum/SessionReplayHealthDiagnosis.test.ts +40 -0
  267. package/Tests/Utils/Rum/SessionReplayRecordingEnded.test.ts +619 -0
  268. package/Tests/Utils/SecurityEvent/Connectors/AwsSecurityHubNormalizer.test.ts +631 -0
  269. package/Tests/Utils/SecurityEvent/Connectors/CrowdStrikeFalconNormalizer.test.ts +479 -0
  270. package/Tests/Utils/SecurityEvent/Connectors/ElasticSecurityNormalizer.test.ts +507 -0
  271. package/Tests/Utils/SecurityEvent/Connectors/MicrosoftDefenderXdrNormalizer.test.ts +686 -0
  272. package/Tests/Utils/SecurityEvent/Connectors/MicrosoftSentinelNormalizer.test.ts +474 -0
  273. package/Tests/Utils/SecurityEvent/Connectors/OktaNormalizer.test.ts +736 -0
  274. package/Tests/Utils/SecurityEvent/Connectors/SplunkNormalizer.test.ts +407 -0
  275. package/Tests/Utils/SecurityEvent/GoogleSecOpsAlertNormalizer.test.ts +129 -0
  276. package/Tests/Utils/Telemetry/CrossSignalScope.test.ts +57 -1
  277. package/Tests/Utils/Telemetry/EntityRelationship.test.ts +36 -0
  278. package/Tests/Utils/Telemetry/LockedFilterSearch.test.ts +600 -0
  279. package/Tests/Utils/Telemetry/NetworkHost.test.ts +48 -0
  280. package/Tests/Utils/Telemetry/OriginAllowList.test.ts +154 -0
  281. package/Tests/Utils/Traces/CriticalPath.test.ts +25 -0
  282. package/Types/AI/AIChatTypes.ts +8 -0
  283. package/Types/AI/InvestigationEvidence.ts +96 -0
  284. package/Types/Monitor/MonitorEvaluationSummary.ts +5 -0
  285. package/Types/OnCallDutyPolicy/Layer.ts +12 -0
  286. package/Types/Permission.ts +2 -2
  287. package/Types/Rules/RuleCriteriaFieldRegistry.ts +12 -0
  288. package/Types/Rum/SessionReplay.ts +109 -0
  289. package/Types/Rum/SessionReplayApi.ts +31 -0
  290. package/Types/SecurityEvent/Connectors/ConnectorDiagnostics.ts +111 -0
  291. package/Types/SecurityEvent/Connectors/SecurityEventConnectionDiagnostics.ts +87 -0
  292. package/Types/SecurityEvent/Connectors/SecurityEventConnectorCatalog.ts +492 -0
  293. package/Types/SecurityEvent/Connectors/SecurityEventConnectorProvider.ts +41 -0
  294. package/Types/SecurityEvent/GoogleSecOpsDiagnostics.ts +56 -1
  295. package/Types/SecurityEvent/GoogleSecOpsRegion.ts +34 -0
  296. package/Types/Telemetry/EntityType.ts +14 -0
  297. package/Types/Telemetry/ExceptionSpanScope.ts +83 -0
  298. package/Types/Telemetry/LockedFilterDetail.ts +46 -0
  299. package/Types/Telemetry/ResourceEntityFacet.ts +17 -10
  300. package/Types/Telemetry/ResourceFacetCatalog.ts +171 -0
  301. package/UI/Components/Card/Card.tsx +118 -83
  302. package/UI/Components/Checkbox/Checkbox.tsx +8 -5
  303. package/UI/Components/CopyTextButton/CopyTextButton.tsx +7 -1
  304. package/UI/Components/CustomFields/CustomFieldsDetail.tsx +4 -1
  305. package/UI/Components/Detail/Detail.tsx +137 -22
  306. package/UI/Components/ErrorBoundary.tsx +38 -0
  307. package/UI/Components/LogsViewer/LogsEntityNames.ts +912 -0
  308. package/UI/Components/LogsViewer/LogsViewer.tsx +156 -77
  309. package/UI/Components/LogsViewer/components/ActiveFilterChips.tsx +28 -11
  310. package/UI/Components/LogsViewer/components/FacetSection.tsx +66 -79
  311. package/UI/Components/LogsViewer/components/FacetValueRow.tsx +17 -2
  312. package/UI/Components/LogsViewer/components/LogDetailsPanel.tsx +45 -5
  313. package/UI/Components/LogsViewer/components/LogsAnalyticsView.tsx +100 -19
  314. package/UI/Components/LogsViewer/components/LogsFacetSidebar.tsx +156 -39
  315. package/UI/Components/LogsViewer/components/LogsTable.tsx +30 -8
  316. package/UI/Components/LogsViewer/types.ts +6 -0
  317. package/UI/Components/Markdown.tsx/InlineReferences.tsx +628 -0
  318. package/UI/Components/Markdown.tsx/MarkdownViewer.tsx +385 -312
  319. package/UI/Components/MemberRoleAssignment/MemberRoleAssignment.tsx +50 -22
  320. package/UI/Components/ModelDetail/CardModelDetail.tsx +15 -0
  321. package/UI/Components/ModelDetail/ModelDetail.tsx +64 -19
  322. package/UI/Components/ModelList/ModelList.tsx +33 -8
  323. package/UI/Components/Page/ModelPage.tsx +119 -54
  324. package/UI/Components/Table/Table.tsx +8 -0
  325. package/UI/Components/Table/TableRow.tsx +13 -5
  326. package/UI/Components/TelemetryViewer/FacetVisibility.ts +229 -0
  327. package/UI/Components/TelemetryViewer/ResourceFacetConfigs.ts +46 -0
  328. package/UI/Components/TelemetryViewer/TelemetryViewer.tsx +11 -0
  329. package/UI/Components/TelemetryViewer/components/FacetSearchInput.tsx +79 -0
  330. package/UI/Components/TelemetryViewer/components/FacetSectionHeader.tsx +69 -0
  331. package/UI/Components/TelemetryViewer/components/FacetShowMoreButton.tsx +36 -0
  332. package/UI/Components/TelemetryViewer/components/HiddenFacetsFooter.tsx +88 -0
  333. package/UI/Components/TelemetryViewer/components/LockedFilterActions.tsx +205 -0
  334. package/UI/Components/TelemetryViewer/components/LockedFilterChip.tsx +496 -0
  335. package/UI/Components/TelemetryViewer/components/TelemetryActiveFilterChips.tsx +30 -10
  336. package/UI/Components/TelemetryViewer/components/TelemetryDetailPanel.tsx +203 -10
  337. package/UI/Components/TelemetryViewer/components/TelemetryFacetSection.tsx +60 -73
  338. package/UI/Components/TelemetryViewer/components/TelemetryFacetSidebar.tsx +94 -7
  339. package/UI/Components/TelemetryViewer/components/TelemetryFacetValueRow.tsx +17 -2
  340. package/UI/Components/TelemetryViewer/types.ts +19 -0
  341. package/UI/Components/TelemetryViewer/useFacetSearchExemptions.ts +158 -0
  342. package/UI/Components/TelemetryViewer/useFacetSectionSearch.ts +102 -0
  343. package/UI/Utils/Clipboard.ts +68 -2
  344. package/UI/Utils/Navigation.ts +17 -2
  345. package/UI/Utils/Telemetry/TelemetryEntityNames.ts +620 -0
  346. package/UI/Utils/Telemetry/UseTelemetryEntityNames.ts +151 -0
  347. package/Utils/AI/InvestigationReport.ts +1789 -0
  348. package/Utils/API.ts +90 -1
  349. package/Utils/Rum/SessionReplayHealth.ts +11 -0
  350. package/Utils/Rum/SessionReplayRecordingEnded.ts +134 -0
  351. package/Utils/SecurityEvent/Connectors/AwsSecurityHubNormalizer.ts +427 -0
  352. package/Utils/SecurityEvent/Connectors/CrowdStrikeFalconNormalizer.ts +197 -0
  353. package/Utils/SecurityEvent/Connectors/ElasticSecurityNormalizer.ts +464 -0
  354. package/Utils/SecurityEvent/Connectors/MicrosoftDefenderXdrNormalizer.ts +567 -0
  355. package/Utils/SecurityEvent/Connectors/MicrosoftSentinelNormalizer.ts +299 -0
  356. package/Utils/SecurityEvent/Connectors/OktaNormalizer.ts +467 -0
  357. package/Utils/SecurityEvent/Connectors/SplunkNormalizer.ts +439 -0
  358. package/Utils/SecurityEvent/GoogleSecOpsAlertNormalizer.ts +124 -12
  359. package/Utils/Telemetry/CrossSignalScope.ts +22 -8
  360. package/Utils/Telemetry/EntityRelationship.ts +8 -0
  361. package/Utils/Telemetry/LockedFilterSearch.ts +412 -0
  362. package/Utils/Telemetry/NetworkHost.ts +43 -0
  363. package/Utils/Telemetry/OriginAllowList.ts +139 -4
  364. package/Utils/Traces/CriticalPath.ts +10 -4
  365. package/build/dist/Models/DatabaseModels/Index.js +4 -0
  366. package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
  367. package/build/dist/Models/DatabaseModels/RumApplication.js +1 -1
  368. package/build/dist/Models/DatabaseModels/RumApplication.js.map +1 -1
  369. package/build/dist/Models/DatabaseModels/SecurityEventConnection.js +490 -0
  370. package/build/dist/Models/DatabaseModels/SecurityEventConnection.js.map +1 -0
  371. package/build/dist/Models/DatabaseModels/SecurityEventConnectionRun.js +287 -0
  372. package/build/dist/Models/DatabaseModels/SecurityEventConnectionRun.js.map +1 -0
  373. package/build/dist/Models/DatabaseModels/TelemetryIngestionKey.js +2 -2
  374. package/build/dist/Models/DatabaseModels/TelemetryIngestionKey.js.map +1 -1
  375. package/build/dist/Server/API/AIInvestigationAPI.js +336 -27
  376. package/build/dist/Server/API/AIInvestigationAPI.js.map +1 -1
  377. package/build/dist/Server/API/GoogleSecOpsConnectionAPI.js +182 -7
  378. package/build/dist/Server/API/GoogleSecOpsConnectionAPI.js.map +1 -1
  379. package/build/dist/Server/API/SecurityEventConnectionAPI.js +171 -0
  380. package/build/dist/Server/API/SecurityEventConnectionAPI.js.map +1 -0
  381. package/build/dist/Server/API/TelemetryAPI.js +248 -170
  382. package/build/dist/Server/API/TelemetryAPI.js.map +1 -1
  383. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1792700000000-AddSecurityEventConnections.js +40 -0
  384. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1792700000000-AddSecurityEventConnections.js.map +1 -0
  385. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +2 -0
  386. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  387. package/build/dist/Server/Middleware/TelemetryIngest.js +57 -4
  388. package/build/dist/Server/Middleware/TelemetryIngest.js.map +1 -1
  389. package/build/dist/Server/Services/ExceptionAggregationService.js +7 -16
  390. package/build/dist/Server/Services/ExceptionAggregationService.js.map +1 -1
  391. package/build/dist/Server/Services/GoogleSecOpsConnectionService.js +8 -0
  392. package/build/dist/Server/Services/GoogleSecOpsConnectionService.js.map +1 -1
  393. package/build/dist/Server/Services/Index.js +4 -0
  394. package/build/dist/Server/Services/Index.js.map +1 -1
  395. package/build/dist/Server/Services/InventoryItemService.js +22 -0
  396. package/build/dist/Server/Services/InventoryItemService.js.map +1 -1
  397. package/build/dist/Server/Services/LogAggregationService.js +8 -17
  398. package/build/dist/Server/Services/LogAggregationService.js.map +1 -1
  399. package/build/dist/Server/Services/MetricAggregationService.js +4 -14
  400. package/build/dist/Server/Services/MetricAggregationService.js.map +1 -1
  401. package/build/dist/Server/Services/SecurityEventConnectionRunService.js +9 -0
  402. package/build/dist/Server/Services/SecurityEventConnectionRunService.js.map +1 -0
  403. package/build/dist/Server/Services/SecurityEventConnectionService.js +356 -0
  404. package/build/dist/Server/Services/SecurityEventConnectionService.js.map +1 -0
  405. package/build/dist/Server/Services/TraceAggregationService.js +51 -25
  406. package/build/dist/Server/Services/TraceAggregationService.js.map +1 -1
  407. package/build/dist/Server/Types/AnalyticsDatabase/ModelPermission.js +9 -0
  408. package/build/dist/Server/Types/AnalyticsDatabase/ModelPermission.js.map +1 -1
  409. package/build/dist/Server/Utils/AI/Chat/ObservabilityAssistant.js +3 -0
  410. package/build/dist/Server/Utils/AI/Chat/ObservabilityAssistant.js.map +1 -1
  411. package/build/dist/Server/Utils/AI/SRE/AIInvestigationEngine.js +14 -7
  412. package/build/dist/Server/Utils/AI/SRE/AIInvestigationEngine.js.map +1 -1
  413. package/build/dist/Server/Utils/AI/SRE/InvestigationEvidence.js +468 -0
  414. package/build/dist/Server/Utils/AI/SRE/InvestigationEvidence.js.map +1 -0
  415. package/build/dist/Server/Utils/AI/SRE/InvestigationReferences.js +230 -0
  416. package/build/dist/Server/Utils/AI/SRE/InvestigationReferences.js.map +1 -0
  417. package/build/dist/Server/Utils/AI/Toolbox/Index.js +32 -0
  418. package/build/dist/Server/Utils/AI/Toolbox/Index.js.map +1 -1
  419. package/build/dist/Server/Utils/AI/Toolbox/TimelineTools.js +6 -2
  420. package/build/dist/Server/Utils/AI/Toolbox/TimelineTools.js.map +1 -1
  421. package/build/dist/Server/Utils/AnalyticsDatabase/StatementGenerator.js +59 -0
  422. package/build/dist/Server/Utils/AnalyticsDatabase/StatementGenerator.js.map +1 -1
  423. package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js +5 -3
  424. package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js.map +1 -1
  425. package/build/dist/Server/Utils/SecurityEvent/Connectors/AwsSecurityHub/AwsSecurityHubClient.js +752 -0
  426. package/build/dist/Server/Utils/SecurityEvent/Connectors/AwsSecurityHub/AwsSecurityHubClient.js.map +1 -0
  427. package/build/dist/Server/Utils/SecurityEvent/Connectors/AwsSecurityHub/AwsSecurityHubConnector.js +493 -0
  428. package/build/dist/Server/Utils/SecurityEvent/Connectors/AwsSecurityHub/AwsSecurityHubConnector.js.map +1 -0
  429. package/build/dist/Server/Utils/SecurityEvent/Connectors/ConnectorPlatformHealth.js +352 -0
  430. package/build/dist/Server/Utils/SecurityEvent/Connectors/ConnectorPlatformHealth.js.map +1 -0
  431. package/build/dist/Server/Utils/SecurityEvent/Connectors/CrowdStrikeFalcon/CrowdStrikeFalconClient.js +405 -0
  432. package/build/dist/Server/Utils/SecurityEvent/Connectors/CrowdStrikeFalcon/CrowdStrikeFalconClient.js.map +1 -0
  433. package/build/dist/Server/Utils/SecurityEvent/Connectors/CrowdStrikeFalcon/CrowdStrikeFalconConnector.js +466 -0
  434. package/build/dist/Server/Utils/SecurityEvent/Connectors/CrowdStrikeFalcon/CrowdStrikeFalconConnector.js.map +1 -0
  435. package/build/dist/Server/Utils/SecurityEvent/Connectors/ElasticSecurity/ElasticSecurityClient.js +344 -0
  436. package/build/dist/Server/Utils/SecurityEvent/Connectors/ElasticSecurity/ElasticSecurityClient.js.map +1 -0
  437. package/build/dist/Server/Utils/SecurityEvent/Connectors/ElasticSecurity/ElasticSecurityConnector.js +511 -0
  438. package/build/dist/Server/Utils/SecurityEvent/Connectors/ElasticSecurity/ElasticSecurityConnector.js.map +1 -0
  439. package/build/dist/Server/Utils/SecurityEvent/Connectors/MicrosoftDefenderXdr/MicrosoftDefenderXdrClient.js +406 -0
  440. package/build/dist/Server/Utils/SecurityEvent/Connectors/MicrosoftDefenderXdr/MicrosoftDefenderXdrClient.js.map +1 -0
  441. package/build/dist/Server/Utils/SecurityEvent/Connectors/MicrosoftDefenderXdr/MicrosoftDefenderXdrConnector.js +336 -0
  442. package/build/dist/Server/Utils/SecurityEvent/Connectors/MicrosoftDefenderXdr/MicrosoftDefenderXdrConnector.js.map +1 -0
  443. package/build/dist/Server/Utils/SecurityEvent/Connectors/MicrosoftSentinel/MicrosoftSentinelClient.js +474 -0
  444. package/build/dist/Server/Utils/SecurityEvent/Connectors/MicrosoftSentinel/MicrosoftSentinelClient.js.map +1 -0
  445. package/build/dist/Server/Utils/SecurityEvent/Connectors/MicrosoftSentinel/MicrosoftSentinelConnector.js +417 -0
  446. package/build/dist/Server/Utils/SecurityEvent/Connectors/MicrosoftSentinel/MicrosoftSentinelConnector.js.map +1 -0
  447. package/build/dist/Server/Utils/SecurityEvent/Connectors/Okta/OktaClient.js +314 -0
  448. package/build/dist/Server/Utils/SecurityEvent/Connectors/Okta/OktaClient.js.map +1 -0
  449. package/build/dist/Server/Utils/SecurityEvent/Connectors/Okta/OktaConnector.js +494 -0
  450. package/build/dist/Server/Utils/SecurityEvent/Connectors/Okta/OktaConnector.js.map +1 -0
  451. package/build/dist/Server/Utils/SecurityEvent/Connectors/SecurityEventConnectionPoller.js +719 -0
  452. package/build/dist/Server/Utils/SecurityEvent/Connectors/SecurityEventConnectionPoller.js.map +1 -0
  453. package/build/dist/Server/Utils/SecurityEvent/Connectors/SecurityEventConnectionRunExecutor.js +404 -0
  454. package/build/dist/Server/Utils/SecurityEvent/Connectors/SecurityEventConnectionRunExecutor.js.map +1 -0
  455. package/build/dist/Server/Utils/SecurityEvent/Connectors/SecurityEventConnectionTester.js +209 -0
  456. package/build/dist/Server/Utils/SecurityEvent/Connectors/SecurityEventConnectionTester.js.map +1 -0
  457. package/build/dist/Server/Utils/SecurityEvent/Connectors/SecurityEventConnectorRegistry.js +40 -0
  458. package/build/dist/Server/Utils/SecurityEvent/Connectors/SecurityEventConnectorRegistry.js.map +1 -0
  459. package/build/dist/Server/Utils/SecurityEvent/Connectors/Splunk/SplunkClient.js +494 -0
  460. package/build/dist/Server/Utils/SecurityEvent/Connectors/Splunk/SplunkClient.js.map +1 -0
  461. package/build/dist/Server/Utils/SecurityEvent/Connectors/Splunk/SplunkConnector.js +379 -0
  462. package/build/dist/Server/Utils/SecurityEvent/Connectors/Splunk/SplunkConnector.js.map +1 -0
  463. package/build/dist/Server/Utils/SecurityEvent/Connectors/Types.js +27 -0
  464. package/build/dist/Server/Utils/SecurityEvent/Connectors/Types.js.map +1 -0
  465. package/build/dist/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsClient.js +234 -61
  466. package/build/dist/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsClient.js.map +1 -1
  467. package/build/dist/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsConnectionTester.js +537 -0
  468. package/build/dist/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsConnectionTester.js.map +1 -0
  469. package/build/dist/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsPoller.js +572 -115
  470. package/build/dist/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsPoller.js.map +1 -1
  471. package/build/dist/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsRunExecutor.js +35 -1
  472. package/build/dist/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsRunExecutor.js.map +1 -1
  473. package/build/dist/Server/Utils/SecurityEvent/SecurityEventDedupe.js +52 -0
  474. package/build/dist/Server/Utils/SecurityEvent/SecurityEventDedupe.js.map +1 -0
  475. package/build/dist/Server/Utils/SessionReplay/SessionReplayReadService.js +521 -32
  476. package/build/dist/Server/Utils/SessionReplay/SessionReplayReadService.js.map +1 -1
  477. package/build/dist/Server/Utils/StartServer.js +10 -0
  478. package/build/dist/Server/Utils/StartServer.js.map +1 -1
  479. package/build/dist/Server/Utils/Telemetry/EntityRegistry.js +8 -0
  480. package/build/dist/Server/Utils/Telemetry/EntityRegistry.js.map +1 -1
  481. package/build/dist/Server/Utils/Telemetry/KubernetesResourceAttributes.js +80 -0
  482. package/build/dist/Server/Utils/Telemetry/KubernetesResourceAttributes.js.map +1 -0
  483. package/build/dist/Server/Utils/Telemetry/ResourceEntityFilter.js +122 -67
  484. package/build/dist/Server/Utils/Telemetry/ResourceEntityFilter.js.map +1 -1
  485. package/build/dist/Server/Utils/Telemetry/ResourceFacetPlanner.js +146 -0
  486. package/build/dist/Server/Utils/Telemetry/ResourceFacetPlanner.js.map +1 -0
  487. package/build/dist/Server/Utils/Telemetry/ResourceFacetResolver.js +174 -248
  488. package/build/dist/Server/Utils/Telemetry/ResourceFacetResolver.js.map +1 -1
  489. package/build/dist/Server/Utils/Telemetry/ServiceDependencyDiscovery.js +492 -0
  490. package/build/dist/Server/Utils/Telemetry/ServiceDependencyDiscovery.js.map +1 -0
  491. package/build/dist/Server/Utils/Telemetry/TraceContextPropagation.js +259 -0
  492. package/build/dist/Server/Utils/Telemetry/TraceContextPropagation.js.map +1 -0
  493. package/build/dist/Server/Utils/Telemetry.js +11 -5
  494. package/build/dist/Server/Utils/Telemetry.js.map +1 -1
  495. package/build/dist/Types/AI/InvestigationEvidence.js +2 -0
  496. package/build/dist/Types/AI/InvestigationEvidence.js.map +1 -0
  497. package/build/dist/Types/OnCallDutyPolicy/Layer.js +11 -0
  498. package/build/dist/Types/OnCallDutyPolicy/Layer.js.map +1 -1
  499. package/build/dist/Types/Permission.js +2 -2
  500. package/build/dist/Types/Permission.js.map +1 -1
  501. package/build/dist/Types/Rules/RuleCriteriaFieldRegistry.js +9 -0
  502. package/build/dist/Types/Rules/RuleCriteriaFieldRegistry.js.map +1 -1
  503. package/build/dist/Types/Rum/SessionReplay.js +95 -0
  504. package/build/dist/Types/Rum/SessionReplay.js.map +1 -1
  505. package/build/dist/Types/Rum/SessionReplayApi.js.map +1 -1
  506. package/build/dist/Types/SecurityEvent/Connectors/ConnectorDiagnostics.js +18 -0
  507. package/build/dist/Types/SecurityEvent/Connectors/ConnectorDiagnostics.js.map +1 -0
  508. package/build/dist/Types/SecurityEvent/Connectors/SecurityEventConnectionDiagnostics.js +2 -0
  509. package/build/dist/Types/SecurityEvent/Connectors/SecurityEventConnectionDiagnostics.js.map +1 -0
  510. package/build/dist/Types/SecurityEvent/Connectors/SecurityEventConnectorCatalog.js +374 -0
  511. package/build/dist/Types/SecurityEvent/Connectors/SecurityEventConnectorCatalog.js.map +1 -0
  512. package/build/dist/Types/SecurityEvent/Connectors/SecurityEventConnectorProvider.js +35 -0
  513. package/build/dist/Types/SecurityEvent/Connectors/SecurityEventConnectorProvider.js.map +1 -0
  514. package/build/dist/Types/SecurityEvent/GoogleSecOpsRegion.js +35 -0
  515. package/build/dist/Types/SecurityEvent/GoogleSecOpsRegion.js.map +1 -0
  516. package/build/dist/Types/Telemetry/EntityType.js +14 -0
  517. package/build/dist/Types/Telemetry/EntityType.js.map +1 -1
  518. package/build/dist/Types/Telemetry/ExceptionSpanScope.js +59 -0
  519. package/build/dist/Types/Telemetry/ExceptionSpanScope.js.map +1 -0
  520. package/build/dist/Types/Telemetry/LockedFilterDetail.js +16 -0
  521. package/build/dist/Types/Telemetry/LockedFilterDetail.js.map +1 -0
  522. package/build/dist/Types/Telemetry/ResourceEntityFacet.js +16 -10
  523. package/build/dist/Types/Telemetry/ResourceEntityFacet.js.map +1 -1
  524. package/build/dist/Types/Telemetry/ResourceFacetCatalog.js +119 -0
  525. package/build/dist/Types/Telemetry/ResourceFacetCatalog.js.map +1 -0
  526. package/build/dist/UI/Components/Card/Card.js +34 -17
  527. package/build/dist/UI/Components/Card/Card.js.map +1 -1
  528. package/build/dist/UI/Components/Checkbox/Checkbox.js +6 -4
  529. package/build/dist/UI/Components/Checkbox/Checkbox.js.map +1 -1
  530. package/build/dist/UI/Components/CopyTextButton/CopyTextButton.js +5 -1
  531. package/build/dist/UI/Components/CopyTextButton/CopyTextButton.js.map +1 -1
  532. package/build/dist/UI/Components/CustomFields/CustomFieldsDetail.js +1 -1
  533. package/build/dist/UI/Components/CustomFields/CustomFieldsDetail.js.map +1 -1
  534. package/build/dist/UI/Components/Detail/Detail.js +63 -13
  535. package/build/dist/UI/Components/Detail/Detail.js.map +1 -1
  536. package/build/dist/UI/Components/ErrorBoundary.js +34 -0
  537. package/build/dist/UI/Components/ErrorBoundary.js.map +1 -1
  538. package/build/dist/UI/Components/LogsViewer/LogsEntityNames.js +535 -0
  539. package/build/dist/UI/Components/LogsViewer/LogsEntityNames.js.map +1 -0
  540. package/build/dist/UI/Components/LogsViewer/LogsViewer.js +117 -57
  541. package/build/dist/UI/Components/LogsViewer/LogsViewer.js.map +1 -1
  542. package/build/dist/UI/Components/LogsViewer/components/ActiveFilterChips.js +5 -7
  543. package/build/dist/UI/Components/LogsViewer/components/ActiveFilterChips.js.map +1 -1
  544. package/build/dist/UI/Components/LogsViewer/components/FacetSection.js +31 -44
  545. package/build/dist/UI/Components/LogsViewer/components/FacetSection.js.map +1 -1
  546. package/build/dist/UI/Components/LogsViewer/components/FacetValueRow.js +17 -3
  547. package/build/dist/UI/Components/LogsViewer/components/FacetValueRow.js.map +1 -1
  548. package/build/dist/UI/Components/LogsViewer/components/LogDetailsPanel.js +19 -3
  549. package/build/dist/UI/Components/LogsViewer/components/LogDetailsPanel.js.map +1 -1
  550. package/build/dist/UI/Components/LogsViewer/components/LogsAnalyticsView.js +64 -18
  551. package/build/dist/UI/Components/LogsViewer/components/LogsAnalyticsView.js.map +1 -1
  552. package/build/dist/UI/Components/LogsViewer/components/LogsFacetSidebar.js +100 -41
  553. package/build/dist/UI/Components/LogsViewer/components/LogsFacetSidebar.js.map +1 -1
  554. package/build/dist/UI/Components/LogsViewer/components/LogsTable.js +13 -5
  555. package/build/dist/UI/Components/LogsViewer/components/LogsTable.js.map +1 -1
  556. package/build/dist/UI/Components/LogsViewer/types.js.map +1 -1
  557. package/build/dist/UI/Components/Markdown.tsx/InlineReferences.js +403 -0
  558. package/build/dist/UI/Components/Markdown.tsx/InlineReferences.js.map +1 -0
  559. package/build/dist/UI/Components/Markdown.tsx/MarkdownViewer.js +197 -179
  560. package/build/dist/UI/Components/Markdown.tsx/MarkdownViewer.js.map +1 -1
  561. package/build/dist/UI/Components/MemberRoleAssignment/MemberRoleAssignment.js +30 -21
  562. package/build/dist/UI/Components/MemberRoleAssignment/MemberRoleAssignment.js.map +1 -1
  563. package/build/dist/UI/Components/ModelDetail/CardModelDetail.js +12 -0
  564. package/build/dist/UI/Components/ModelDetail/CardModelDetail.js.map +1 -1
  565. package/build/dist/UI/Components/ModelDetail/ModelDetail.js +46 -12
  566. package/build/dist/UI/Components/ModelDetail/ModelDetail.js.map +1 -1
  567. package/build/dist/UI/Components/ModelList/ModelList.js +26 -7
  568. package/build/dist/UI/Components/ModelList/ModelList.js.map +1 -1
  569. package/build/dist/UI/Components/Page/ModelPage.js +62 -34
  570. package/build/dist/UI/Components/Page/ModelPage.js.map +1 -1
  571. package/build/dist/UI/Components/Table/Table.js +3 -1
  572. package/build/dist/UI/Components/Table/Table.js.map +1 -1
  573. package/build/dist/UI/Components/Table/TableRow.js +8 -1
  574. package/build/dist/UI/Components/Table/TableRow.js.map +1 -1
  575. package/build/dist/UI/Components/TelemetryViewer/FacetVisibility.js +111 -0
  576. package/build/dist/UI/Components/TelemetryViewer/FacetVisibility.js.map +1 -0
  577. package/build/dist/UI/Components/TelemetryViewer/ResourceFacetConfigs.js +22 -0
  578. package/build/dist/UI/Components/TelemetryViewer/ResourceFacetConfigs.js.map +1 -0
  579. package/build/dist/UI/Components/TelemetryViewer/TelemetryViewer.js +1 -1
  580. package/build/dist/UI/Components/TelemetryViewer/TelemetryViewer.js.map +1 -1
  581. package/build/dist/UI/Components/TelemetryViewer/components/FacetSearchInput.js +36 -0
  582. package/build/dist/UI/Components/TelemetryViewer/components/FacetSearchInput.js.map +1 -0
  583. package/build/dist/UI/Components/TelemetryViewer/components/FacetSectionHeader.js +21 -0
  584. package/build/dist/UI/Components/TelemetryViewer/components/FacetSectionHeader.js.map +1 -0
  585. package/build/dist/UI/Components/TelemetryViewer/components/FacetShowMoreButton.js +14 -0
  586. package/build/dist/UI/Components/TelemetryViewer/components/FacetShowMoreButton.js.map +1 -0
  587. package/build/dist/UI/Components/TelemetryViewer/components/HiddenFacetsFooter.js +27 -0
  588. package/build/dist/UI/Components/TelemetryViewer/components/HiddenFacetsFooter.js.map +1 -0
  589. package/build/dist/UI/Components/TelemetryViewer/components/LockedFilterActions.js +88 -0
  590. package/build/dist/UI/Components/TelemetryViewer/components/LockedFilterActions.js.map +1 -0
  591. package/build/dist/UI/Components/TelemetryViewer/components/LockedFilterChip.js +228 -0
  592. package/build/dist/UI/Components/TelemetryViewer/components/LockedFilterChip.js.map +1 -0
  593. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryActiveFilterChips.js +6 -6
  594. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryActiveFilterChips.js.map +1 -1
  595. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryDetailPanel.js +111 -12
  596. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryDetailPanel.js.map +1 -1
  597. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryFacetSection.js +27 -40
  598. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryFacetSection.js.map +1 -1
  599. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryFacetSidebar.js +70 -10
  600. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryFacetSidebar.js.map +1 -1
  601. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryFacetValueRow.js +17 -3
  602. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryFacetValueRow.js.map +1 -1
  603. package/build/dist/UI/Components/TelemetryViewer/types.js +0 -4
  604. package/build/dist/UI/Components/TelemetryViewer/types.js.map +1 -1
  605. package/build/dist/UI/Components/TelemetryViewer/useFacetSearchExemptions.js +70 -0
  606. package/build/dist/UI/Components/TelemetryViewer/useFacetSearchExemptions.js.map +1 -0
  607. package/build/dist/UI/Components/TelemetryViewer/useFacetSectionSearch.js +52 -0
  608. package/build/dist/UI/Components/TelemetryViewer/useFacetSectionSearch.js.map +1 -0
  609. package/build/dist/UI/Utils/Clipboard.js +59 -2
  610. package/build/dist/UI/Utils/Clipboard.js.map +1 -1
  611. package/build/dist/UI/Utils/Navigation.js +11 -2
  612. package/build/dist/UI/Utils/Navigation.js.map +1 -1
  613. package/build/dist/UI/Utils/Telemetry/TelemetryEntityNames.js +471 -0
  614. package/build/dist/UI/Utils/Telemetry/TelemetryEntityNames.js.map +1 -0
  615. package/build/dist/UI/Utils/Telemetry/UseTelemetryEntityNames.js +113 -0
  616. package/build/dist/UI/Utils/Telemetry/UseTelemetryEntityNames.js.map +1 -0
  617. package/build/dist/Utils/AI/InvestigationReport.js +1241 -0
  618. package/build/dist/Utils/AI/InvestigationReport.js.map +1 -0
  619. package/build/dist/Utils/API.js +25 -0
  620. package/build/dist/Utils/API.js.map +1 -1
  621. package/build/dist/Utils/Rum/SessionReplayHealth.js +10 -0
  622. package/build/dist/Utils/Rum/SessionReplayHealth.js.map +1 -1
  623. package/build/dist/Utils/Rum/SessionReplayRecordingEnded.js +54 -0
  624. package/build/dist/Utils/Rum/SessionReplayRecordingEnded.js.map +1 -0
  625. package/build/dist/Utils/SecurityEvent/Connectors/AwsSecurityHubNormalizer.js +311 -0
  626. package/build/dist/Utils/SecurityEvent/Connectors/AwsSecurityHubNormalizer.js.map +1 -0
  627. package/build/dist/Utils/SecurityEvent/Connectors/CrowdStrikeFalconNormalizer.js +150 -0
  628. package/build/dist/Utils/SecurityEvent/Connectors/CrowdStrikeFalconNormalizer.js.map +1 -0
  629. package/build/dist/Utils/SecurityEvent/Connectors/ElasticSecurityNormalizer.js +328 -0
  630. package/build/dist/Utils/SecurityEvent/Connectors/ElasticSecurityNormalizer.js.map +1 -0
  631. package/build/dist/Utils/SecurityEvent/Connectors/MicrosoftDefenderXdrNormalizer.js +405 -0
  632. package/build/dist/Utils/SecurityEvent/Connectors/MicrosoftDefenderXdrNormalizer.js.map +1 -0
  633. package/build/dist/Utils/SecurityEvent/Connectors/MicrosoftSentinelNormalizer.js +212 -0
  634. package/build/dist/Utils/SecurityEvent/Connectors/MicrosoftSentinelNormalizer.js.map +1 -0
  635. package/build/dist/Utils/SecurityEvent/Connectors/OktaNormalizer.js +351 -0
  636. package/build/dist/Utils/SecurityEvent/Connectors/OktaNormalizer.js.map +1 -0
  637. package/build/dist/Utils/SecurityEvent/Connectors/SplunkNormalizer.js +348 -0
  638. package/build/dist/Utils/SecurityEvent/Connectors/SplunkNormalizer.js.map +1 -0
  639. package/build/dist/Utils/SecurityEvent/GoogleSecOpsAlertNormalizer.js +103 -10
  640. package/build/dist/Utils/SecurityEvent/GoogleSecOpsAlertNormalizer.js.map +1 -1
  641. package/build/dist/Utils/Telemetry/CrossSignalScope.js +16 -5
  642. package/build/dist/Utils/Telemetry/CrossSignalScope.js.map +1 -1
  643. package/build/dist/Utils/Telemetry/EntityRelationship.js +7 -0
  644. package/build/dist/Utils/Telemetry/EntityRelationship.js.map +1 -1
  645. package/build/dist/Utils/Telemetry/LockedFilterSearch.js +277 -0
  646. package/build/dist/Utils/Telemetry/LockedFilterSearch.js.map +1 -0
  647. package/build/dist/Utils/Telemetry/NetworkHost.js +39 -0
  648. package/build/dist/Utils/Telemetry/NetworkHost.js.map +1 -0
  649. package/build/dist/Utils/Telemetry/OriginAllowList.js +105 -4
  650. package/build/dist/Utils/Telemetry/OriginAllowList.js.map +1 -1
  651. package/build/dist/Utils/Traces/CriticalPath.js +9 -4
  652. package/build/dist/Utils/Traces/CriticalPath.js.map +1 -1
  653. package/package.json +1 -1
  654. package/Tests/UI/Rum/RecordingHealthStrip.test.tsx +0 -600
  655. package/UI/Components/GanttChart/Bar/BarLabel.tsx +0 -17
  656. package/UI/Components/GanttChart/Bar/Index.tsx +0 -149
  657. package/UI/Components/GanttChart/ChartContainer.tsx +0 -50
  658. package/UI/Components/GanttChart/Index.tsx +0 -90
  659. package/UI/Components/GanttChart/Row/Index.tsx +0 -22
  660. package/UI/Components/GanttChart/Row/Row.tsx +0 -231
  661. package/UI/Components/GanttChart/Row/RowLabel.tsx +0 -30
  662. package/UI/Components/GanttChart/Rows.tsx +0 -59
  663. package/UI/Components/GanttChart/Timeline/Index.tsx +0 -46
  664. package/UI/Components/GanttChart/Timeline/TimelineInterval.tsx +0 -33
  665. package/UI/Components/GanttChart/Timeline/TimelineIntervalMarks.tsx +0 -43
  666. package/build/dist/UI/Components/GanttChart/Bar/BarLabel.js +0 -8
  667. package/build/dist/UI/Components/GanttChart/Bar/BarLabel.js.map +0 -1
  668. package/build/dist/UI/Components/GanttChart/Bar/Index.js +0 -77
  669. package/build/dist/UI/Components/GanttChart/Bar/Index.js.map +0 -1
  670. package/build/dist/UI/Components/GanttChart/ChartContainer.js +0 -33
  671. package/build/dist/UI/Components/GanttChart/ChartContainer.js.map +0 -1
  672. package/build/dist/UI/Components/GanttChart/Index.js +0 -39
  673. package/build/dist/UI/Components/GanttChart/Index.js.map +0 -1
  674. package/build/dist/UI/Components/GanttChart/Row/Index.js +0 -7
  675. package/build/dist/UI/Components/GanttChart/Row/Index.js.map +0 -1
  676. package/build/dist/UI/Components/GanttChart/Row/Row.js +0 -106
  677. package/build/dist/UI/Components/GanttChart/Row/Row.js.map +0 -1
  678. package/build/dist/UI/Components/GanttChart/Row/RowLabel.js +0 -10
  679. package/build/dist/UI/Components/GanttChart/Row/RowLabel.js.map +0 -1
  680. package/build/dist/UI/Components/GanttChart/Rows.js +0 -19
  681. package/build/dist/UI/Components/GanttChart/Rows.js.map +0 -1
  682. package/build/dist/UI/Components/GanttChart/Timeline/Index.js +0 -16
  683. package/build/dist/UI/Components/GanttChart/Timeline/Index.js.map +0 -1
  684. package/build/dist/UI/Components/GanttChart/Timeline/TimelineInterval.js +0 -13
  685. package/build/dist/UI/Components/GanttChart/Timeline/TimelineInterval.js.map +0 -1
  686. package/build/dist/UI/Components/GanttChart/Timeline/TimelineIntervalMarks.js +0 -13
  687. package/build/dist/UI/Components/GanttChart/Timeline/TimelineIntervalMarks.js.map +0 -1
@@ -0,0 +1,1002 @@
1
+ import BadDataException from "../../../../Types/Exception/BadDataException";
2
+ import SecurityEventConnection from "../../../../Models/DatabaseModels/SecurityEventConnection";
3
+ import LIMIT_MAX from "../../../../Types/Database/LimitMax";
4
+ import OneUptimeDate from "../../../../Types/Date";
5
+ import { JSONObject } from "../../../../Types/JSON";
6
+ import ObjectID from "../../../../Types/ObjectID";
7
+ import NormalizedSecurityEvent from "../../../../Types/SecurityEvent/NormalizedSecurityEvent";
8
+ import { SecurityConnectorCheck } from "../../../../Types/SecurityEvent/Connectors/ConnectorDiagnostics";
9
+ import {
10
+ SecurityEventConnectionRunOptions,
11
+ SecurityEventConnectionRunResult,
12
+ } from "../../../../Types/SecurityEvent/Connectors/SecurityEventConnectionDiagnostics";
13
+ import {
14
+ SecurityEventConnectorDefinition,
15
+ getSecurityEventConnectorDefinition,
16
+ } from "../../../../Types/SecurityEvent/Connectors/SecurityEventConnectorCatalog";
17
+ import { resolveTelemetryRetentionInDays } from "../../../../Types/Telemetry/TelemetryRetentionConfig";
18
+ import Semaphore, {
19
+ SemaphoreLockTimeoutError,
20
+ SemaphoreMutex,
21
+ } from "../../../Infrastructure/Semaphore";
22
+ import OTelIngestService, {
23
+ TelemetryServiceMetadata,
24
+ } from "../../../Services/OpenTelemetryIngestService";
25
+ import SecurityEventConnectionService from "../../../Services/SecurityEventConnectionService";
26
+ import SecurityEventService from "../../../Services/SecurityEventService";
27
+ import logger from "../../Logger";
28
+ import { redactLogString } from "../../LogRedaction";
29
+ import CaptureSpan from "../../Telemetry/CaptureSpan";
30
+ import ConnectorErrorMessage from "../ConnectorErrorMessage";
31
+ import SecurityEventDedupe from "../SecurityEventDedupe";
32
+ import { buildSecurityEventDbRow } from "../SecurityEventRow";
33
+ import ThreatIntelEnricher from "../ThreatIntel/ThreatIntelEnricher";
34
+ import SecurityEventConnectorRegistry from "./SecurityEventConnectorRegistry";
35
+ import {
36
+ ConnectorFetchResult,
37
+ SecurityConnectorSettings,
38
+ SecurityEventConnector,
39
+ } from "./Types";
40
+
41
+ /*
42
+ * The generic pull loop behind every Security Event Connection.
43
+ *
44
+ * Window and cursor rules, in order of what they protect against:
45
+ * - the first poll looks back a full day (DEFAULT_INITIAL_LOOKBACK), so a
46
+ * new connection shows the customer their recent records immediately
47
+ * instead of an empty window they read as "broken";
48
+ * - every later poll starts the provider's cursorOverlapInMinutes before
49
+ * the saved cursor, so a record created on a window boundary, or one
50
+ * the source made readable late, is not skipped (the dedupe lookup makes
51
+ * the overlap harmless);
52
+ * - a poll reads at most one chunk PAST THE CURSOR (the overlap is extra).
53
+ * Measuring the chunk from the window start instead would let a chunk
54
+ * no longer than the overlap end at or before the cursor, so the cursor
55
+ * could never move forward again. The chunk starts at a day, so a stale
56
+ * cursor catches up in daily windows, and adapts from poll to poll
57
+ * through lastPollResult.nextChunkMinutes;
58
+ * - a window read completely moves the cursor to its end and doubles the
59
+ * chunk back towards a day;
60
+ * - a window that could not be read in one run must never pin polling
61
+ * (review finding F1: the held window was re-read forever and nothing
62
+ * newer was ever imported). A connector that reads in ascending creation
63
+ * order reports resumeAfter and the cursor moves there. Otherwise the
64
+ * cursor holds and the chunk halves; a one-minute chunk that still
65
+ * cannot be read moves the cursor past that minute with a loud lastError,
66
+ * trading a bounded, reported gap for never stalling;
67
+ * - after that forced advance, later windows never start before the
68
+ * skipped minute's end (overlapFloor) until the overlap has moved past
69
+ * it, so a long overlap cannot drag every following poll back over the
70
+ * same overflowing minute;
71
+ * - a run that fails outright holds the cursor and keeps the chunk: an
72
+ * authentication or transport failure says nothing about volume.
73
+ *
74
+ * Every poll that does not fail therefore moves the cursor forward or
75
+ * halves the chunk, so a connection moves within log2(MAX/MIN) + 1 polls.
76
+ *
77
+ * The window is on the SOURCE'S CREATION TIME, never the underlying event
78
+ * time (see Connectors/Types.ts).
79
+ */
80
+
81
+ export const DEFAULT_INITIAL_LOOKBACK_IN_MINUTES: number = 24 * 60;
82
+ // The longest stretch past the cursor one poll reads, and the first chunk.
83
+ export const MAX_CHUNK_MINUTES: number = 24 * 60;
84
+ /*
85
+ * The shortest chunk. Halving stops here: a one-minute chunk that still
86
+ * holds more records than one run can read is skipped past (forcedAdvance).
87
+ */
88
+ export const MIN_CHUNK_MINUTES: number = 1;
89
+
90
+ /*
91
+ * Transport deadlines as connectors and the shared HTTP client word them:
92
+ * "timed out after N seconds" (Sentinel, AWS Security Hub), axios's
93
+ * "timeout of Nms exceeded" (surfaced inside "... did not complete: ...")
94
+ * and a socket-level ETIMEDOUT.
95
+ */
96
+ const TIMEOUT_ERROR_PATTERN: RegExp =
97
+ /timed out|timeout of \d+ms exceeded|ETIMEDOUT/i;
98
+ /*
99
+ * Only for a catalog entry without a usable cursorOverlapInMinutes, so a
100
+ * malformed definition still re-reads the boundary instead of skipping it.
101
+ */
102
+ export const DEFAULT_CURSOR_OVERLAP_IN_MINUTES: number = 1;
103
+ export const MAX_FETCH_REQUESTS: number = 20;
104
+ export const MAX_EVENTS_PER_RUN: number = 10000;
105
+ export const MAX_DIAGNOSTIC_SAMPLES: number = 25;
106
+ export const MAX_RANGE_MS: number = 7 * 24 * 60 * 60 * 1000;
107
+ export const POLL_REQUEST_TIMEOUT_IN_MS: number = 60 * 1000;
108
+ export const SECURITY_EVENT_SOURCE_LOCK_NAMESPACE: string =
109
+ "SecurityEventConnectionSource";
110
+
111
+ const MINUTE_IN_MS: number = 60 * 1000;
112
+
113
+ export interface PollWindow {
114
+ startTime: Date;
115
+ endTime: Date;
116
+ warnings: Array<string>;
117
+ hasUsableCursor: boolean;
118
+ /*
119
+ * Scheduled polls only. progressFrom is where this poll's new ground
120
+ * starts: the saved cursor, or the window start when there is no usable
121
+ * cursor. chunkMinutes is the minutes from there to endTime, rounded up.
122
+ * overlapFloor is the forced-advance floor this window was clamped to,
123
+ * present only while it still clamps (see planPollCursor).
124
+ */
125
+ overlapInMinutes?: number | undefined;
126
+ progressFrom?: Date | undefined;
127
+ chunkMinutes?: number | undefined;
128
+ /*
129
+ * The chunk this poll was given (lastPollResult.nextChunkMinutes, or a
130
+ * full day). chunkMinutes can be much shorter on a caught-up poll, where
131
+ * the window only reaches now; growth and failure handling are based on
132
+ * this value so a healthy poll never shrinks the next one.
133
+ */
134
+ requestedChunkMinutes?: number | undefined;
135
+ overlapFloor?: Date | undefined;
136
+ }
137
+
138
+ export class RecordedConnectionPollFailure extends Error {}
139
+
140
+ export default class SecurityEventConnectionPoller {
141
+ @CaptureSpan()
142
+ public static async pollAllDueConnections(): Promise<void> {
143
+ const connections: Array<SecurityEventConnection> =
144
+ await SecurityEventConnectionService.findBy({
145
+ query: { isEnabled: true },
146
+ select: {
147
+ _id: true,
148
+ projectId: true,
149
+ name: true,
150
+ provider: true,
151
+ pollIntervalInMinutes: true,
152
+ lastPolledAt: true,
153
+ },
154
+ skip: 0,
155
+ limit: LIMIT_MAX,
156
+ props: { isRoot: true },
157
+ });
158
+
159
+ const now: Date = OneUptimeDate.getCurrentDate();
160
+
161
+ for (const connection of connections) {
162
+ const intervalInMinutes: number = Math.max(
163
+ 1,
164
+ connection.pollIntervalInMinutes || 5,
165
+ );
166
+
167
+ if (connection.lastPolledAt) {
168
+ const dueAt: Date = OneUptimeDate.addRemoveMinutes(
169
+ connection.lastPolledAt,
170
+ intervalInMinutes,
171
+ );
172
+
173
+ if (OneUptimeDate.isAfter(dueAt, now)) {
174
+ continue;
175
+ }
176
+ }
177
+
178
+ try {
179
+ const ingested: number = await this.pollConnection(connection);
180
+ logger.info(
181
+ `SecurityEventConnectionPoller: connection ${connection.id?.toString()} ingested ${ingested} security events.`,
182
+ );
183
+ } catch (error) {
184
+ logger.error(
185
+ `SecurityEventConnectionPoller: error polling connection ${connection.id?.toString()}:`,
186
+ );
187
+ logger.error(error);
188
+
189
+ if (error instanceof RecordedConnectionPollFailure) {
190
+ continue;
191
+ }
192
+
193
+ if (connection.id) {
194
+ const connectionId: ObjectID = connection.id;
195
+
196
+ await ConnectorErrorMessage.recordFailure({
197
+ label: `SecurityEventConnectionPoller: connection ${connectionId.toString()}`,
198
+ write: async (): Promise<void> => {
199
+ await SecurityEventConnectionService.updateOneById({
200
+ id: connectionId,
201
+ data: {
202
+ lastPolledAt: OneUptimeDate.getCurrentDate(),
203
+ lastError: redactLogString(
204
+ ConnectorErrorMessage.toMessage(error, { truncate: false }),
205
+ ),
206
+ },
207
+ props: { isRoot: true },
208
+ });
209
+ },
210
+ });
211
+ }
212
+ }
213
+ }
214
+ }
215
+
216
+ @CaptureSpan()
217
+ public static async pollConnection(
218
+ connection: SecurityEventConnection,
219
+ overrides?: PollerOverrides | undefined,
220
+ ): Promise<number> {
221
+ const result: SecurityEventConnectionRunResult =
222
+ await this.executeConnection(connection, { type: "poll" }, overrides);
223
+
224
+ if (result.status === "failed") {
225
+ throw new RecordedConnectionPollFailure(
226
+ result.error || "Security event connection poll failed.",
227
+ );
228
+ }
229
+
230
+ return result.ingestedCount;
231
+ }
232
+
233
+ /*
234
+ * Source-scoped serialization: ClickHouse does not deduplicate eventUid,
235
+ * so lookup-then-insert is only safe under this lock. The key is the
236
+ * project plus the provider, which is also the dedupe scope
237
+ * (vendorName/productName), so two connections to the same product in
238
+ * one project cannot race each other.
239
+ */
240
+ @CaptureSpan()
241
+ public static async executeConnection(
242
+ connection: SecurityEventConnection,
243
+ options: SecurityEventConnectionRunOptions,
244
+ overrides?: PollerOverrides | undefined,
245
+ ): Promise<SecurityEventConnectionRunResult> {
246
+ this.validateConnection(connection);
247
+
248
+ if (options.type === "test" || options.type === "preview") {
249
+ return this.executeUnlocked(connection, options, overrides);
250
+ }
251
+
252
+ let mutex: SemaphoreMutex;
253
+
254
+ try {
255
+ mutex = await Semaphore.lock({
256
+ namespace: SECURITY_EVENT_SOURCE_LOCK_NAMESPACE,
257
+ key: `${connection.projectId!.toString()}:${connection.provider}`,
258
+ lockTimeout: 30000,
259
+ acquireTimeout: 10000,
260
+ retryInterval: 100,
261
+ });
262
+ } catch (error) {
263
+ /*
264
+ * A historical import or another connection to the same product is
265
+ * still writing. That is contention, not a broken connection: say so
266
+ * in the run instead of surfacing a raw lock error, and leave the
267
+ * connection's lastError alone (executeUnlocked never ran).
268
+ */
269
+ if (error instanceof SemaphoreLockTimeoutError) {
270
+ throw new BadDataException(
271
+ "Another poll or import for this source is still running in this project. This run was skipped; polling continues on the next scheduled tick.",
272
+ );
273
+ }
274
+
275
+ throw error;
276
+ }
277
+
278
+ try {
279
+ const current: SecurityEventConnection | null = overrides
280
+ ? connection
281
+ : await SecurityEventConnectionService.findOneById({
282
+ id: connection.id!,
283
+ select: {
284
+ _id: true,
285
+ projectId: true,
286
+ name: true,
287
+ provider: true,
288
+ config: true,
289
+ secrets: true,
290
+ alertingOnly: true,
291
+ cursor: true,
292
+ /*
293
+ * nextChunkMinutes lives in the previous poll's result. Without
294
+ * it every poll would restart at a full day and a window that
295
+ * needs narrowing would never narrow.
296
+ */
297
+ lastPollResult: true,
298
+ },
299
+ props: { isRoot: true },
300
+ });
301
+
302
+ if (
303
+ !current ||
304
+ current.projectId?.toString() !== connection.projectId!.toString()
305
+ ) {
306
+ throw new BadDataException(
307
+ "Security event connection no longer exists in this project.",
308
+ );
309
+ }
310
+
311
+ return await this.executeUnlocked(current, options, overrides);
312
+ } finally {
313
+ try {
314
+ await Semaphore.release(mutex);
315
+ } catch (error) {
316
+ logger.error(
317
+ `SecurityEventConnectionPoller: could not release source lock: ${redactLogString(ConnectorErrorMessage.toMessage(error))}`,
318
+ );
319
+ }
320
+ }
321
+ }
322
+
323
+ private static validateConnection(connection: SecurityEventConnection): void {
324
+ if (!connection.id || !connection.projectId || !connection.provider) {
325
+ throw new BadDataException(
326
+ "Security event connection is missing id, projectId or provider.",
327
+ );
328
+ }
329
+ }
330
+
331
+ public static getWindow(
332
+ connection: SecurityEventConnection,
333
+ options: SecurityEventConnectionRunOptions,
334
+ now: Date = OneUptimeDate.getCurrentDate(),
335
+ ): PollWindow {
336
+ let endTime: Date = now;
337
+ let startTime: Date = OneUptimeDate.addRemoveMinutes(
338
+ now,
339
+ -DEFAULT_INITIAL_LOOKBACK_IN_MINUTES,
340
+ );
341
+ const warnings: Array<string> = [];
342
+ let hasUsableCursor: boolean = false;
343
+
344
+ if (options.type === "preview" || options.type === "backfill") {
345
+ startTime = new Date(options.startTime || "");
346
+ endTime = new Date(options.endTime || "");
347
+
348
+ if (
349
+ !Number.isFinite(startTime.getTime()) ||
350
+ !Number.isFinite(endTime.getTime()) ||
351
+ startTime >= endTime ||
352
+ endTime.getTime() > now.getTime() + 60000 ||
353
+ endTime.getTime() - startTime.getTime() > MAX_RANGE_MS
354
+ ) {
355
+ throw new BadDataException(
356
+ "Select a valid past time range of at most seven days.",
357
+ );
358
+ }
359
+ } else if (options.type === "test") {
360
+ startTime = OneUptimeDate.addRemoveMinutes(now, -24 * 60);
361
+ } else if (options.type === "poll") {
362
+ const overlapInMinutes: number = this.getCursorOverlapInMinutes(
363
+ connection.provider,
364
+ );
365
+ const chunkLimitInMinutes: number = this.getChunkLimitInMinutes(
366
+ connection.lastPollResult,
367
+ );
368
+ let progressFrom: Date = startTime;
369
+ let overlapFloor: Date | undefined = undefined;
370
+
371
+ if (connection.cursor) {
372
+ const cursorTime: Date = new Date(connection.cursor);
373
+
374
+ if (!Number.isFinite(cursorTime.getTime())) {
375
+ warnings.push(
376
+ "The saved cursor is unreadable; polling the default 24 hour window.",
377
+ );
378
+ } else if (cursorTime >= now) {
379
+ warnings.push(
380
+ "The saved cursor is in the future; polling the default 24 hour window.",
381
+ );
382
+ } else {
383
+ hasUsableCursor = true;
384
+ progressFrom = cursorTime;
385
+ startTime = OneUptimeDate.addRemoveMinutes(
386
+ cursorTime,
387
+ -overlapInMinutes,
388
+ );
389
+
390
+ /*
391
+ * After a forced advance the overlap must not reach back over the
392
+ * minute that overflowed: every such poll would overflow on the
393
+ * same records and force one more minute past, skipping up to the
394
+ * whole overlap (30 minutes for AWS Security Hub) instead of one.
395
+ * A floor later than the cursor cannot come from this poller, so
396
+ * it is ignored rather than allowed to skip ground.
397
+ */
398
+ const floor: Date | undefined = this.readOverlapFloor(
399
+ connection.lastPollResult,
400
+ );
401
+
402
+ if (floor && floor <= cursorTime && startTime < floor) {
403
+ overlapFloor = floor;
404
+ startTime = floor;
405
+ }
406
+ }
407
+ }
408
+
409
+ const chunkEnd: Date = OneUptimeDate.addRemoveMinutes(
410
+ progressFrom,
411
+ chunkLimitInMinutes,
412
+ );
413
+
414
+ if (chunkEnd < endTime) {
415
+ endTime = chunkEnd;
416
+ warnings.push(
417
+ `Catching up from ${hasUsableCursor ? "the saved cursor" : "the start of the default 24 hour window"} in ${chunkLimitInMinutes === MAX_CHUNK_MINUTES ? "24 hour" : `${chunkLimitInMinutes} minute`} windows. Later records will be fetched by subsequent polls.`,
418
+ );
419
+ }
420
+
421
+ return {
422
+ startTime,
423
+ endTime,
424
+ warnings,
425
+ hasUsableCursor,
426
+ overlapInMinutes,
427
+ progressFrom,
428
+ overlapFloor,
429
+ requestedChunkMinutes: chunkLimitInMinutes,
430
+ chunkMinutes: Math.max(
431
+ MIN_CHUNK_MINUTES,
432
+ Math.ceil(
433
+ (endTime.getTime() - progressFrom.getTime()) / MINUTE_IN_MS,
434
+ ),
435
+ ),
436
+ };
437
+ }
438
+
439
+ return { startTime, endTime, warnings, hasUsableCursor };
440
+ }
441
+
442
+ /*
443
+ * The chunk the previous poll asked for. Anything that is not an integer
444
+ * in [MIN, MAX] (no previous poll, a row written before adaptive chunks
445
+ * existed, a hand-edited value) falls back to a full day, which is the
446
+ * behaviour a connection had before chunks adapted.
447
+ */
448
+ public static getChunkLimitInMinutes(
449
+ lastPollResult: JSONObject | null | undefined,
450
+ ): number {
451
+ const stored: unknown = lastPollResult?.["nextChunkMinutes"];
452
+
453
+ if (
454
+ typeof stored === "number" &&
455
+ Number.isInteger(stored) &&
456
+ stored >= MIN_CHUNK_MINUTES &&
457
+ stored <= MAX_CHUNK_MINUTES
458
+ ) {
459
+ return stored;
460
+ }
461
+
462
+ return MAX_CHUNK_MINUTES;
463
+ }
464
+
465
+ private static readOverlapFloor(
466
+ lastPollResult: JSONObject | null | undefined,
467
+ ): Date | undefined {
468
+ const stored: unknown = lastPollResult?.["overlapFloor"];
469
+
470
+ if (typeof stored !== "string") {
471
+ return undefined;
472
+ }
473
+
474
+ const floor: Date = new Date(stored);
475
+ return Number.isFinite(floor.getTime()) ? floor : undefined;
476
+ }
477
+
478
+ public static getCursorOverlapInMinutes(
479
+ provider: string | undefined,
480
+ ): number {
481
+ const overlap: number | undefined =
482
+ getSecurityEventConnectorDefinition(provider)?.cursorOverlapInMinutes;
483
+
484
+ if (
485
+ typeof overlap === "number" &&
486
+ Number.isFinite(overlap) &&
487
+ overlap >= 0
488
+ ) {
489
+ return overlap;
490
+ }
491
+
492
+ return DEFAULT_CURSOR_OVERLAP_IN_MINUTES;
493
+ }
494
+
495
+ private static async executeUnlocked(
496
+ connection: SecurityEventConnection,
497
+ options: SecurityEventConnectionRunOptions,
498
+ overrides?: PollerOverrides | undefined,
499
+ ): Promise<SecurityEventConnectionRunResult> {
500
+ const definition: SecurityEventConnectorDefinition | undefined =
501
+ getSecurityEventConnectorDefinition(connection.provider);
502
+
503
+ if (!definition) {
504
+ throw new BadDataException(
505
+ "Security event connection has an unsupported provider.",
506
+ );
507
+ }
508
+
509
+ const window: PollWindow = this.getWindow(connection, options);
510
+ const startedMs: number = Date.now();
511
+ const result: SecurityEventConnectionRunResult = {
512
+ type: options.type,
513
+ provider: definition.provider,
514
+ ...(options.runId ? { runId: options.runId } : {}),
515
+ status: "running",
516
+ startedAt: new Date(startedMs).toISOString(),
517
+ completedAt: new Date(startedMs).toISOString(),
518
+ durationMs: 0,
519
+ windowStart: window.startTime.toISOString(),
520
+ windowEnd: window.endTime.toISOString(),
521
+ fetchedCount: 0,
522
+ ingestedCount: 0,
523
+ duplicateCount: 0,
524
+ rejectedCount: 0,
525
+ failedCount: 0,
526
+ complete: true,
527
+ requestCount: 0,
528
+ warnings: window.warnings,
529
+ samples: [],
530
+ checks: [],
531
+ };
532
+
533
+ let phase: string = "Validate configuration";
534
+ let phaseStartedMs: number = Date.now();
535
+ /*
536
+ * What the connector said about how far it got, kept outside the try so
537
+ * the cursor decision after it can use them.
538
+ */
539
+ let resumeAfter: Date | undefined = undefined;
540
+ let onlyNormalizationFailed: boolean = false;
541
+
542
+ try {
543
+ const connector: SecurityEventConnector =
544
+ overrides?.connector ||
545
+ SecurityEventConnectorRegistry.getConnector(definition.provider);
546
+ const settings: SecurityConnectorSettings =
547
+ overrides?.settings ||
548
+ (await SecurityEventConnectionService.getConnectorSettings(connection));
549
+
550
+ connector.validateSettings(settings);
551
+ result.checks.push({
552
+ key: "configuration",
553
+ name: phase,
554
+ status: "pass",
555
+ durationMs: Date.now() - phaseStartedMs,
556
+ message: `The ${definition.title} configuration and credentials are present and well formed.`,
557
+ });
558
+
559
+ if (options.type === "test") {
560
+ phase = `Check access to ${definition.title}`;
561
+ phaseStartedMs = Date.now();
562
+ const checks: Array<SecurityConnectorCheck> =
563
+ await connector.testConnection(settings, {
564
+ requestTimeoutInMs: POLL_REQUEST_TIMEOUT_IN_MS,
565
+ });
566
+ result.checks.push(...checks);
567
+
568
+ const failed: SecurityConnectorCheck | undefined = checks.find(
569
+ (check: SecurityConnectorCheck): boolean => {
570
+ return check.status === "fail";
571
+ },
572
+ );
573
+
574
+ if (failed) {
575
+ throw new BadDataException(`${failed.name}: ${failed.message}`);
576
+ }
577
+ } else {
578
+ phase = `Read ${definition.importedRecordName}s from ${definition.title}`;
579
+ phaseStartedMs = Date.now();
580
+ const fetched: ConnectorFetchResult = await connector.fetchEvents(
581
+ settings,
582
+ { startTime: window.startTime, endTime: window.endTime },
583
+ {
584
+ maxRequests: MAX_FETCH_REQUESTS,
585
+ maxEvents: MAX_EVENTS_PER_RUN,
586
+ requestTimeoutInMs: POLL_REQUEST_TIMEOUT_IN_MS,
587
+ sampleLimit: MAX_DIAGNOSTIC_SAMPLES,
588
+ },
589
+ );
590
+
591
+ result.fetchedCount = fetched.fetchedCount;
592
+ result.rejectedCount = fetched.rejectedCount;
593
+ result.failedCount = fetched.failedCount;
594
+ result.requestCount = fetched.requestCount;
595
+ result.samples = fetched.samples.slice(0, MAX_DIAGNOSTIC_SAMPLES);
596
+ result.warnings.push(...fetched.warnings);
597
+ /*
598
+ * Rejected objects are not a reason to hold the cursor: a record the
599
+ * normalizer does not recognize will not become recognizable by
600
+ * re-reading the same window, so holding would pin polling behind it
601
+ * until the window can no longer reach the present. They are counted
602
+ * and warned about instead. Normalization FAILURES make the window
603
+ * incomplete, since a transient bug deserves a retry; the adaptive
604
+ * chunk below narrows around them and finally moves past them, so a
605
+ * record that never normalizes cannot pin polling either.
606
+ */
607
+ result.complete =
608
+ result.complete && fetched.complete && fetched.failedCount === 0;
609
+ /*
610
+ * A resume point only means something when the connector itself
611
+ * stopped early; a fetch that read its whole window has nothing to
612
+ * resume from.
613
+ */
614
+ resumeAfter = fetched.complete ? undefined : fetched.resumeAfter;
615
+ onlyNormalizationFailed = fetched.complete && fetched.failedCount > 0;
616
+
617
+ if (fetched.rejectedCount) {
618
+ result.warnings.push(
619
+ `${fetched.rejectedCount} returned records were discarded because they do not look like ${definition.title} ${definition.importedRecordName}s.`,
620
+ );
621
+ }
622
+
623
+ if (fetched.failedCount) {
624
+ result.warnings.push(
625
+ `${fetched.failedCount} records could not be normalized and were not imported.`,
626
+ );
627
+ }
628
+
629
+ result.checks.push({
630
+ key: "read",
631
+ name: phase,
632
+ status: fetched.failedCount
633
+ ? "fail"
634
+ : fetched.rejectedCount
635
+ ? "warn"
636
+ : "pass",
637
+ durationMs: Date.now() - phaseStartedMs,
638
+ message: `${fetched.events.length} ${definition.importedRecordName}s recognized; ${fetched.rejectedCount} rejected; ${fetched.failedCount} failed; ${fetched.requestCount} request${fetched.requestCount === 1 ? "" : "s"}.`,
639
+ });
640
+
641
+ if (options.type === "poll" || options.type === "backfill") {
642
+ phase = "Import records";
643
+ phaseStartedMs = Date.now();
644
+ await this.ingest(connection, definition, fetched.events, result);
645
+ result.checks.push({
646
+ key: "import",
647
+ name: phase,
648
+ status: "pass",
649
+ durationMs: Date.now() - phaseStartedMs,
650
+ message: `${result.ingestedCount} imported; ${result.duplicateCount} already imported.`,
651
+ });
652
+ }
653
+ }
654
+
655
+ result.status = !result.complete
656
+ ? "partial"
657
+ : options.type === "test" || result.fetchedCount > 0
658
+ ? "success"
659
+ : "empty";
660
+ } catch (error) {
661
+ result.status = "failed";
662
+ result.complete = false;
663
+ result.error = redactLogString(
664
+ ConnectorErrorMessage.toMessage(error, { truncate: false }),
665
+ );
666
+ result.checks.push({
667
+ key: "failure",
668
+ name: phase,
669
+ status: "fail",
670
+ durationMs: Date.now() - phaseStartedMs,
671
+ message: result.error,
672
+ });
673
+ }
674
+
675
+ result.completedAt = OneUptimeDate.getCurrentDate().toISOString();
676
+ result.durationMs = Math.max(0, Date.now() - startedMs);
677
+
678
+ // Decided before logging so the chunk warnings are logged with the rest.
679
+ const cursor: string | undefined =
680
+ options.type === "poll"
681
+ ? this.planPollCursor({
682
+ window,
683
+ result,
684
+ resumeAfter,
685
+ onlyNormalizationFailed,
686
+ })
687
+ : undefined;
688
+
689
+ for (const warning of result.warnings) {
690
+ logger.warn(
691
+ `SecurityEventConnectionPoller: connection ${connection.id!.toString()}: ${warning}`,
692
+ );
693
+ }
694
+
695
+ if (options.type === "poll") {
696
+ await SecurityEventConnectionService.updateOneById({
697
+ id: connection.id!,
698
+ data: {
699
+ lastPolledAt: new Date(result.completedAt),
700
+ lastPollResult: result as never,
701
+ // A forced advance puts its warning first, so lastError leads with it.
702
+ lastError: (result.error ||
703
+ (result.complete
704
+ ? null
705
+ : result.warnings.join(" ") ||
706
+ "Poll incomplete.")) as unknown as string,
707
+ ...(cursor ? { cursor } : {}),
708
+ ...(result.complete
709
+ ? { lastSuccessfulPollAt: new Date(result.completedAt) }
710
+ : {}),
711
+ ...(result.ingestedCount
712
+ ? { lastEventIngestedAt: new Date(result.completedAt) }
713
+ : {}),
714
+ },
715
+ props: { isRoot: true },
716
+ });
717
+ } else if (options.type === "backfill" && result.ingestedCount) {
718
+ await SecurityEventConnectionService.updateOneById({
719
+ id: connection.id!,
720
+ data: { lastEventIngestedAt: new Date(result.completedAt) },
721
+ props: { isRoot: true },
722
+ });
723
+ }
724
+
725
+ return result;
726
+ }
727
+
728
+ /*
729
+ * The F1 cursor and chunk rules for one scheduled poll. Records
730
+ * chunkMinutes, nextChunkMinutes and forcedAdvance on the result, adds the
731
+ * warning that explains what the next poll does, and returns the cursor to
732
+ * write (undefined keeps the stored cursor).
733
+ *
734
+ * Invariant: a cursor written after a usable cursor is strictly later than
735
+ * it. windowEnd is later because the chunk is measured from the cursor,
736
+ * and a resume point must be later to count as progress. The only other
737
+ * write is the first-poll anchor, which replaces a missing or unusable
738
+ * cursor.
739
+ *
740
+ * overlapFloor: a forced advance sets it to its window end; any other
741
+ * poll carries the floor its window was clamped to, and drops it once the
742
+ * cursor minus the overlap no longer reaches back past it.
743
+ */
744
+ private static planPollCursor(data: {
745
+ window: PollWindow;
746
+ result: SecurityEventConnectionRunResult;
747
+ resumeAfter: Date | undefined;
748
+ onlyNormalizationFailed: boolean;
749
+ }): string | undefined {
750
+ const { window, result } = data;
751
+ const overlapInMinutes: number =
752
+ window.overlapInMinutes ?? DEFAULT_CURSOR_OVERLAP_IN_MINUTES;
753
+ const progressFrom: Date = window.progressFrom || window.startTime;
754
+ const chunkMinutes: number = window.chunkMinutes ?? MAX_CHUNK_MINUTES;
755
+ const requestedChunkMinutes: number =
756
+ window.requestedChunkMinutes ?? MAX_CHUNK_MINUTES;
757
+ /*
758
+ * The first poll has no cursor to hold. Anchoring one overlap past the
759
+ * window start makes the next poll's window start at the same instant,
760
+ * instead of restarting a day before whenever it runs.
761
+ */
762
+ const firstPollAnchor: string | undefined = window.hasUsableCursor
763
+ ? undefined
764
+ : OneUptimeDate.addRemoveMinutes(
765
+ window.startTime,
766
+ overlapInMinutes,
767
+ ).toISOString();
768
+
769
+ result.chunkMinutes = chunkMinutes;
770
+
771
+ if (window.overlapFloor) {
772
+ result.overlapFloor = window.overlapFloor.toISOString();
773
+ }
774
+
775
+ if (result.status === "failed") {
776
+ /*
777
+ * A failure is not a volume signal, so the cursor and the requested
778
+ * chunk are kept — with one exception. A request that timed out on a
779
+ * wide window usually means the window itself is too heavy (Splunk
780
+ * sorts the whole window on the search head before returning a row),
781
+ * and retrying the same window would time out forever. Halve it, as a
782
+ * poll that could not read its window would.
783
+ */
784
+ if (
785
+ chunkMinutes > MIN_CHUNK_MINUTES &&
786
+ TIMEOUT_ERROR_PATTERN.test(result.error || "")
787
+ ) {
788
+ const nextChunkMinutes: number = Math.max(
789
+ MIN_CHUNK_MINUTES,
790
+ Math.floor(chunkMinutes / 2),
791
+ );
792
+ result.nextChunkMinutes = nextChunkMinutes;
793
+ result.warnings.push(
794
+ `The source did not answer in time for this window; the next poll reads a ${nextChunkMinutes} minute window from the same starting point.`,
795
+ );
796
+ return firstPollAnchor;
797
+ }
798
+
799
+ result.nextChunkMinutes = requestedChunkMinutes;
800
+ return firstPollAnchor;
801
+ }
802
+
803
+ if (result.complete) {
804
+ // A finished poll never shrinks the chunk; after narrowing it doubles back.
805
+ result.nextChunkMinutes = Math.min(
806
+ MAX_CHUNK_MINUTES,
807
+ Math.max(requestedChunkMinutes, chunkMinutes * 2),
808
+ );
809
+ return result.windowEnd;
810
+ }
811
+
812
+ /*
813
+ * Progress means past the previous cursor, not merely past the window
814
+ * start: records inside the overlap were already read by an earlier
815
+ * poll, so resuming inside it would re-read the same records forever.
816
+ * Without a usable cursor the previous "cursor" is the first-poll anchor
817
+ * (window start plus overlap). The saved cursor is used directly rather
818
+ * than window start plus overlap, because an overlap floor moves the
819
+ * window start later and would otherwise hide real progress.
820
+ */
821
+ const previousCursorMs: number = window.hasUsableCursor
822
+ ? progressFrom.getTime()
823
+ : window.startTime.getTime() + overlapInMinutes * MINUTE_IN_MS;
824
+ const resumeAfterMs: number | undefined =
825
+ data.resumeAfter instanceof Date &&
826
+ Number.isFinite(data.resumeAfter.getTime())
827
+ ? data.resumeAfter.getTime()
828
+ : undefined;
829
+
830
+ if (
831
+ resumeAfterMs !== undefined &&
832
+ resumeAfterMs > previousCursorMs &&
833
+ resumeAfterMs <= window.endTime.getTime()
834
+ ) {
835
+ const resumeAt: string = new Date(resumeAfterMs).toISOString();
836
+ // The connector reads ascending, so the same length keeps moving.
837
+ result.nextChunkMinutes = requestedChunkMinutes;
838
+ /*
839
+ * Resume exactly where this poll stopped, without the overlap. The
840
+ * overlap exists for records delivered late while a connection is
841
+ * caught up; during a backlog it only re-reads what this poll just
842
+ * read. With a 30 minute overlap (AWS Security Hub) and more than one
843
+ * run's worth of records inside those 30 minutes, every following poll
844
+ * would re-read only duplicates, never pass the cursor, and end in a
845
+ * forced advance past records nobody read. The floor is dropped once
846
+ * the cursor has moved one overlap past it, which restores the overlap.
847
+ */
848
+ result.overlapFloor = resumeAt;
849
+ result.warnings.push(
850
+ `This poll stopped before the end of its window after reading records created up to ${resumeAt}; the next poll resumes from there.`,
851
+ );
852
+ return resumeAt;
853
+ }
854
+
855
+ if (chunkMinutes > MIN_CHUNK_MINUTES) {
856
+ const nextChunkMinutes: number = Math.max(
857
+ MIN_CHUNK_MINUTES,
858
+ Math.floor(chunkMinutes / 2),
859
+ );
860
+ result.nextChunkMinutes = nextChunkMinutes;
861
+ result.warnings.push(
862
+ data.onlyNormalizationFailed
863
+ ? `Some records in this window could not be normalized; the next poll reads a ${nextChunkMinutes} minute window from the same starting point to retry them.`
864
+ : `This window holds more records than one poll can read; the next poll reads a ${nextChunkMinutes} minute window from the same starting point.`,
865
+ );
866
+ return firstPollAnchor;
867
+ }
868
+
869
+ /*
870
+ * A one-minute chunk that still cannot be read. Narrowing further is
871
+ * impossible and holding would stall the connection for good, so move
872
+ * past this minute and say so loudly. The warning goes first so it
873
+ * also leads lastError.
874
+ */
875
+ const minuteStart: string = progressFrom.toISOString();
876
+ result.forcedAdvance = true;
877
+ result.nextChunkMinutes = MIN_CHUNK_MINUTES;
878
+ result.overlapFloor = result.windowEnd;
879
+ result.warnings.unshift(
880
+ data.onlyNormalizationFailed
881
+ ? `${result.failedCount} records created in the one minute from ${minuteStart} to ${result.windowEnd} could not be normalized. Polling moved past this minute so newer records keep arriving; use Import this time range in Diagnostics on this minute to retry them.`
882
+ : `More records were created in the one minute from ${minuteStart} to ${result.windowEnd} than one poll can read. Polling moved past this minute so newer records keep arriving; use Import this time range in Diagnostics on this minute to recover what one run can read.`,
883
+ );
884
+ return result.windowEnd;
885
+ }
886
+
887
+ private static async ingest(
888
+ connection: SecurityEventConnection,
889
+ definition: SecurityEventConnectorDefinition,
890
+ normalized: Array<NormalizedSecurityEvent>,
891
+ result: SecurityEventConnectionRunResult,
892
+ ): Promise<void> {
893
+ if (!normalized.length) {
894
+ return;
895
+ }
896
+
897
+ const seen: Set<string> = new Set();
898
+ const unique: Array<NormalizedSecurityEvent> = normalized.filter(
899
+ (event: NormalizedSecurityEvent): boolean => {
900
+ if (seen.has(event.eventUid)) {
901
+ result.duplicateCount++;
902
+ return false;
903
+ }
904
+ seen.add(event.eventUid);
905
+ return true;
906
+ },
907
+ );
908
+
909
+ const existing: Set<string> =
910
+ await SecurityEventDedupe.findExistingEventUids({
911
+ projectId: connection.projectId!,
912
+ vendorName: definition.vendorName,
913
+ productName: definition.productName,
914
+ ids: unique.map((event: NormalizedSecurityEvent): string => {
915
+ return event.eventUid;
916
+ }),
917
+ });
918
+
919
+ const fresh: Array<NormalizedSecurityEvent> = unique.filter(
920
+ (event: NormalizedSecurityEvent): boolean => {
921
+ if (existing.has(event.eventUid)) {
922
+ result.duplicateCount++;
923
+ return false;
924
+ }
925
+ return true;
926
+ },
927
+ );
928
+
929
+ if (!fresh.length) {
930
+ return;
931
+ }
932
+
933
+ const serviceMetadata: TelemetryServiceMetadata =
934
+ await OTelIngestService.telemetryServiceFromName({
935
+ serviceName: definition.productName,
936
+ projectId: connection.projectId!,
937
+ });
938
+
939
+ const retentionDays: number = resolveTelemetryRetentionInDays({
940
+ pillar: "securityEvents",
941
+ serviceConfig: serviceMetadata.serviceRetentionConfig,
942
+ serviceRetentionInDays: serviceMetadata.serviceRetentionInDays,
943
+ projectConfig: serviceMetadata.projectRetentionConfig,
944
+ projectRetentionInDays: serviceMetadata.projectRetentionInDays,
945
+ });
946
+
947
+ await ThreatIntelEnricher.enrichNormalizedEvents({
948
+ projectId: connection.projectId!,
949
+ events: fresh,
950
+ });
951
+
952
+ const rows: Array<JSONObject> = fresh.map(
953
+ (event: NormalizedSecurityEvent): JSONObject => {
954
+ event.vendorName = definition.vendorName;
955
+ event.productName = definition.productName;
956
+ event.attributes["oneuptime.security_connection.id"] =
957
+ connection.id!.toString();
958
+ event.attributes["oneuptime.security_connection.provider"] =
959
+ definition.provider;
960
+
961
+ return buildSecurityEventDbRow({
962
+ normalized: event,
963
+ projectId: connection.projectId!,
964
+ serviceMetadata,
965
+ retentionDays,
966
+ });
967
+ },
968
+ );
969
+
970
+ /*
971
+ * The source lock cannot be released before buffered writes are
972
+ * visible, so this low-volume path asks for synchronous acknowledgement
973
+ * regardless of the high-volume telemetry defaults.
974
+ */
975
+ await SecurityEventService.insertJsonRows(rows, {
976
+ clickhouseSettings: { async_insert: 0, insert_distributed_sync: 1 },
977
+ });
978
+
979
+ result.ingestedCount = rows.length;
980
+
981
+ const times: Array<string> = rows
982
+ .map((row: JSONObject): string => {
983
+ return new Date(
984
+ String(row["time"]).replace(" ", "T") + "Z",
985
+ ).toISOString();
986
+ })
987
+ .sort();
988
+
989
+ result.eventTimeStart = times[0];
990
+ result.eventTimeEnd = times[times.length - 1];
991
+ }
992
+ }
993
+
994
+ /*
995
+ * Test seam: an injected connector and settings skip the registry, the
996
+ * decrypting service read and the in-lock reload, exactly like the
997
+ * injected client in GoogleSecOpsPoller.
998
+ */
999
+ export interface PollerOverrides {
1000
+ connector?: SecurityEventConnector | undefined;
1001
+ settings?: SecurityConnectorSettings | undefined;
1002
+ }