@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
@@ -7,13 +7,9 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
7
7
  var __metadata = (this && this.__metadata) || function (k, v) {
8
8
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
9
9
  };
10
- import TableColumnType from "../../../../Types/AnalyticsDatabase/TableColumnType";
11
- import { SQL } from "../../AnalyticsDatabase/Statement";
12
- import { getClickhouseClusterName, getClickhouseDatabaseName, getStorageTableName, } from "../../AnalyticsDatabase/ClusterConfig";
13
- import { getQuerySettings } from "../../AnalyticsDatabase/QuerySettingsHelper";
14
10
  import BadDataException from "../../../../Types/Exception/BadDataException";
15
11
  import { contentHashEventUid, parseEventTime, readString, readValue, } from "../../../../Utils/SecurityEvent/NormalizerHelpers";
16
- import Semaphore from "../../../Infrastructure/Semaphore";
12
+ import Semaphore, { SemaphoreLockTimeoutError, } from "../../../Infrastructure/Semaphore";
17
13
  import GoogleSecOpsConnection from "../../../../Models/DatabaseModels/GoogleSecOpsConnection";
18
14
  import LIMIT_MAX from "../../../../Types/Database/LimitMax";
19
15
  import OneUptimeDate from "../../../../Types/Date";
@@ -26,18 +22,60 @@ import logger from "../../Logger";
26
22
  import { redactLogString } from "../../LogRedaction";
27
23
  import CaptureSpan from "../../Telemetry/CaptureSpan";
28
24
  import ConnectorErrorMessage from "../ConnectorErrorMessage";
25
+ import SecurityEventDedupe from "../SecurityEventDedupe";
29
26
  import { buildSecurityEventDbRow } from "../SecurityEventRow";
30
27
  import ThreatIntelEnricher from "../ThreatIntel/ThreatIntelEnricher";
31
28
  import GoogleSecOpsClient from "./GoogleSecOpsClient";
32
29
  const SECOPS_SERVICE_NAME = "Google SecOps";
33
- const DEFAULT_LOOKBACK_IN_MINUTES = 15;
34
- const MAX_LOOKBACK_IN_MINUTES = 24 * 60;
30
+ const SECOPS_VENDOR_NAME = "Google";
31
+ /*
32
+ * The first poll of a new connection reads a full day of CREATED detections.
33
+ * Fifteen minutes used to be the default, and on a tenant whose rules run
34
+ * hourly or daily it reliably returned nothing, which read as "the
35
+ * connector is broken" on the very first look.
36
+ */
37
+ const DEFAULT_LOOKBACK_IN_MINUTES = 24 * 60;
38
+ /*
39
+ * Adaptive catch-up. A scheduled poll reads at most MAX_CHUNK_MINUTES of
40
+ * created time past its cursor. A poll that cannot read its window in one
41
+ * run halves the next chunk and a complete poll doubles it back, because
42
+ * re-reading an identical window that never fits pinned the cursor forever
43
+ * and nothing new was ever imported. The chunk is measured from the cursor,
44
+ * not from the overlapped window start: a chunk no longer than the overlap
45
+ * would otherwise end at or before the cursor and never move it.
46
+ */
47
+ const MAX_CHUNK_MINUTES = 24 * 60;
48
+ const MIN_CHUNK_MINUTES = 1;
35
49
  const WINDOW_OVERLAP_IN_MINUTES = 1;
36
- const MAX_FETCH_REQUESTS = 12;
37
- const MAX_FETCH_DURATION_MS = 2 * 60 * 1000;
50
+ /*
51
+ * Separate request budgets per kind of read. The two created-time search
52
+ * passes are the authoritative read of rule detections and share one page
53
+ * budget; the alerts view splits truncated windows and gets its own, so a
54
+ * burst that the alerts view has to split can no longer starve the searches
55
+ * (or the other way round).
56
+ */
57
+ const MAX_SEARCH_PAGES_PER_POLL = 20;
58
+ const MAX_ALERTS_VIEW_REQUESTS_PER_POLL = 16;
59
+ // The worker job times out at ten minutes; normalizing and importing follow.
60
+ const MAX_FETCH_DURATION_MS = 4 * 60 * 1000;
38
61
  const MAX_ALERTS_PER_REQUEST = 1000;
62
+ const MAX_SEARCH_PAGE_SIZE = 1000;
39
63
  const MAX_DIAGNOSTIC_SAMPLES = 25;
40
64
  const MAX_RANGE_MS = 7 * 24 * 60 * 60 * 1000;
65
+ const DEFAULT_POLL_INTERVAL_IN_MINUTES = 5;
66
+ /*
67
+ * A detection created within one poll interval plus this grace of its
68
+ * detection time would still have been caught by a detection-time cursor;
69
+ * anything later is exactly the record the old basis lost.
70
+ */
71
+ const CREATION_LAG_GRACE_IN_MINUTES = 1;
72
+ /*
73
+ * Curated (Google-authored) rule detections are optional: tenants without
74
+ * that entitlement answer 403 (and some 400/404) on the curated route. Those
75
+ * statuses degrade the pass to a warning; 401, 429, 5xx, timeouts and parse
76
+ * failures still fail the run like any other pass.
77
+ */
78
+ const CURATED_OPTIONAL_STATUSES = [400, 403, 404];
41
79
  export const GOOGLE_SECOPS_SOURCE_LOCK_NAMESPACE = "GoogleSecOpsSource";
42
80
  class RecordedPollFailure extends Error {
43
81
  }
@@ -58,6 +96,8 @@ export default class GoogleSecOpsPoller {
58
96
  pollIntervalInMinutes: true,
59
97
  lastPolledAt: true,
60
98
  cursor: true,
99
+ // Carries nextChunkMinutes, the length of the next catch-up chunk.
100
+ lastPollResult: true,
61
101
  includeNonAlertingDetections: true,
62
102
  },
63
103
  skip: 0,
@@ -138,13 +178,29 @@ export default class GoogleSecOpsPoller {
138
178
  if (options.type === "test" || options.type === "preview") {
139
179
  return this.executeUnlocked(connection, options, clientOverride);
140
180
  }
141
- const mutex = await Semaphore.lock({
142
- namespace: GOOGLE_SECOPS_SOURCE_LOCK_NAMESPACE,
143
- key: connection.projectId.toString(),
144
- lockTimeout: 30000,
145
- acquireTimeout: 10000,
146
- retryInterval: 100,
147
- });
181
+ let mutex;
182
+ try {
183
+ mutex = await Semaphore.lock({
184
+ namespace: GOOGLE_SECOPS_SOURCE_LOCK_NAMESPACE,
185
+ key: connection.projectId.toString(),
186
+ lockTimeout: 30000,
187
+ acquireTimeout: 10000,
188
+ retryInterval: 100,
189
+ });
190
+ }
191
+ catch (error) {
192
+ /*
193
+ * The library's timeout message names Redis keys and reads like an
194
+ * infrastructure fault. It is the expected steady state when a long
195
+ * import holds the source lock, so it is reworded for the person
196
+ * reading run history, and left as a BadDataException so the run
197
+ * executor records it without retrying.
198
+ */
199
+ if (error instanceof SemaphoreLockTimeoutError) {
200
+ throw new BadDataException("Another poll or import for this source is still running in this project. This run was skipped; polling continues on the next scheduled tick.");
201
+ }
202
+ throw error;
203
+ }
148
204
  try {
149
205
  /*
150
206
  * An injected client also injects the connection snapshot for tests.
@@ -162,6 +218,12 @@ export default class GoogleSecOpsPoller {
162
218
  instanceResourceName: true,
163
219
  serviceAccountJson: true,
164
220
  cursor: true,
221
+ /*
222
+ * Reloaded with the cursor: the previous poll's result decides
223
+ * this poll's chunk and whether it resumes past a forced advance.
224
+ */
225
+ lastPollResult: true,
226
+ pollIntervalInMinutes: true,
165
227
  includeNonAlertingDetections: true,
166
228
  },
167
229
  props: { isRoot: true },
@@ -206,31 +268,125 @@ export default class GoogleSecOpsPoller {
206
268
  endTime.getTime() - startTime.getTime() > MAX_RANGE_MS) {
207
269
  throw new BadDataException("Select a valid past time range of at most seven days.");
208
270
  }
271
+ return { startTime, endTime, warnings, hasUsableCursor };
272
+ }
273
+ if (options.type !== "poll") {
274
+ return { startTime, endTime, warnings, hasUsableCursor };
209
275
  }
210
- else if (options.type === "poll" && connection.cursor) {
211
- const cursorTime = new Date(connection.cursor);
212
- if (!Number.isFinite(cursorTime.getTime())) {
213
- warnings.push("The saved cursor is unreadable; polling the default 15 minute window.");
276
+ const chunk = this.getChunkMinutes(connection);
277
+ let cursorTime = null;
278
+ if (connection.cursor) {
279
+ const parsed = new Date(connection.cursor);
280
+ if (!Number.isFinite(parsed.getTime())) {
281
+ warnings.push("The saved cursor is unreadable; polling the default 24 hour window.");
214
282
  }
215
- else if (cursorTime >= now) {
216
- warnings.push("The saved cursor is in the future; polling the default 15 minute window.");
283
+ else if (parsed >= now) {
284
+ warnings.push("The saved cursor is in the future; polling the default 24 hour window.");
217
285
  }
218
286
  else {
219
- hasUsableCursor = true;
220
- startTime = OneUptimeDate.addRemoveMinutes(cursorTime, -WINDOW_OVERLAP_IN_MINUTES);
221
- const chunkEnd = OneUptimeDate.addRemoveMinutes(startTime, MAX_LOOKBACK_IN_MINUTES);
222
- if (chunkEnd < endTime) {
223
- endTime = chunkEnd;
224
- warnings.push("Catching up from the saved cursor in 24 hour windows. Later detections will be fetched by subsequent polls.");
225
- }
287
+ cursorTime = parsed;
288
+ }
289
+ }
290
+ if (cursorTime) {
291
+ hasUsableCursor = true;
292
+ startTime = this.resumesFromForcedAdvance(connection, cursorTime)
293
+ ? cursorTime
294
+ : OneUptimeDate.addRemoveMinutes(cursorTime, -WINDOW_OVERLAP_IN_MINUTES);
295
+ const chunkEnd = OneUptimeDate.addRemoveMinutes(cursorTime, chunk);
296
+ if (chunkEnd < endTime) {
297
+ endTime = chunkEnd;
298
+ warnings.push(`Catching up from the saved cursor in ${this.describeChunk(chunk)} windows. Later detections will be fetched by subsequent polls.`);
299
+ }
300
+ }
301
+ else {
302
+ // The first window keeps its 24 hour lookback; a narrowed chunk only shortens its end.
303
+ const chunkEnd = OneUptimeDate.addRemoveMinutes(startTime, chunk);
304
+ if (chunkEnd < endTime) {
305
+ endTime = chunkEnd;
306
+ warnings.push(`Reading the first ${chunk} minutes of the 24 hour lookback. Later detections will be fetched by subsequent polls.`);
226
307
  }
227
308
  }
228
- return { startTime, endTime, warnings, hasUsableCursor };
309
+ const chunkBase = cursorTime || startTime;
310
+ return {
311
+ startTime,
312
+ endTime,
313
+ warnings,
314
+ hasUsableCursor,
315
+ chunkBase,
316
+ requestedChunkMinutes: chunk,
317
+ chunkMinutes: Math.max(MIN_CHUNK_MINUTES, Math.ceil((endTime.getTime() - chunkBase.getTime()) / 60000)),
318
+ };
319
+ }
320
+ /*
321
+ * lastPollResult.nextChunkMinutes when it is a whole number of minutes
322
+ * inside the allowed range. Anything else (no previous poll, a hand-edited
323
+ * row, a result from before adaptive catch-up) reads the full 24 hours.
324
+ */
325
+ static getChunkMinutes(connection) {
326
+ const stored = connection.lastPollResult
327
+ ? connection.lastPollResult["nextChunkMinutes"]
328
+ : undefined;
329
+ if (typeof stored === "number" &&
330
+ Number.isInteger(stored) &&
331
+ stored >= MIN_CHUNK_MINUTES &&
332
+ stored <= MAX_CHUNK_MINUTES) {
333
+ return stored;
334
+ }
335
+ return MAX_CHUNK_MINUTES;
336
+ }
337
+ /*
338
+ * True when the saved cursor is the end of a minute that a forced advance
339
+ * skipped (or a poll that already started there and did not move the
340
+ * cursor). Such a poll starts at the cursor without the overlap: the
341
+ * overlap minute is exactly the minute that could not be read, and
342
+ * re-reading it would overflow again and force a second advance over a
343
+ * minute that was never the problem.
344
+ */
345
+ static resumesFromForcedAdvance(connection, cursorTime) {
346
+ const stored = connection.lastPollResult;
347
+ if (!stored || stored["type"] !== "poll") {
348
+ return false;
349
+ }
350
+ const readTime = (key) => {
351
+ const value = stored[key];
352
+ return typeof value === "string" ? Date.parse(value) : Number.NaN;
353
+ };
354
+ return ((stored["forcedAdvance"] === true &&
355
+ readTime("windowEnd") === cursorTime.getTime()) ||
356
+ readTime("windowStart") === cursorTime.getTime());
357
+ }
358
+ static describeChunk(minutes) {
359
+ if (minutes % 60 === 0) {
360
+ const hours = minutes / 60;
361
+ return `${hours} hour`;
362
+ }
363
+ return `${minutes} minute`;
229
364
  }
230
365
  static async executeUnlocked(connection, options, clientOverride) {
231
366
  const window = this.getWindow(connection, options);
232
367
  const startedMs = Date.now();
233
- const result = Object.assign(Object.assign({ type: options.type }, (options.runId ? { runId: options.runId } : {})), { status: "running", startedAt: new Date(startedMs).toISOString(), completedAt: new Date(startedMs).toISOString(), durationMs: 0, windowStart: window.startTime.toISOString(), windowEnd: window.endTime.toISOString(), includeNonAlertingDetections: connection.includeNonAlertingDetections === true, fetchedCount: 0, ingestedCount: 0, duplicateCount: 0, rejectedCount: 0, failedCount: 0, complete: true, requestCount: 0, warnings: window.warnings, samples: [], checks: [] });
368
+ /*
369
+ * Preview and backfill take a detection-time range from the person (it
370
+ * is how the SecOps alerts view frames time), and read created time as
371
+ * well so an import of "yesterday" also carries detections created
372
+ * yesterday about older events. Polls read created time only; the
373
+ * alerts-view pass supplies detection time.
374
+ */
375
+ const isHistorical = options.type === "preview" || options.type === "backfill";
376
+ const searchBases = isHistorical
377
+ ? ["CREATED_TIME", "DETECTION_TIME"]
378
+ : ["CREATED_TIME"];
379
+ const basisLabel = isHistorical
380
+ ? "created and detection time"
381
+ : "created time";
382
+ const result = Object.assign(Object.assign(Object.assign({ type: options.type }, (options.runId ? { runId: options.runId } : {})), { status: "running", startedAt: new Date(startedMs).toISOString(), completedAt: new Date(startedMs).toISOString(), durationMs: 0, windowStart: window.startTime.toISOString(), windowEnd: window.endTime.toISOString(), includeNonAlertingDetections: connection.includeNonAlertingDetections === true, basis: isHistorical ? "detection-time" : "created-time", sourceCounts: { ruleDetections: 0, curatedDetections: 0, alertsView: 0 }, fetchedCount: 0, ingestedCount: 0, duplicateCount: 0, rejectedCount: 0, failedCount: 0, complete: true, requestCount: 0, warnings: window.warnings, samples: [], checks: [] }), (window.chunkMinutes !== undefined
383
+ ? { chunkMinutes: window.chunkMinutes }
384
+ : {}));
385
+ const budget = {
386
+ startedMs,
387
+ searchRequests: 0,
388
+ alertsViewRequests: 0,
389
+ };
234
390
  let phase = "Validate configuration";
235
391
  let phaseStartedMs = Date.now();
236
392
  try {
@@ -257,16 +413,71 @@ export default class GoogleSecOpsPoller {
257
413
  message: "Google accepted the service account credentials.",
258
414
  });
259
415
  }
260
- phase = "Read detections from the configured instance";
416
+ /*
417
+ * Three passes over one window, unioned by Collection.id. The alerts
418
+ * view alone filters on DETECTION time, and a rule that runs hourly
419
+ * creates detections whose detection time is already behind a
420
+ * forward-only cursor, so it can never be the primary read.
421
+ */
422
+ const seen = new Map();
423
+ phase = `Read rule detections by ${basisLabel}`;
261
424
  phaseStartedMs = Date.now();
262
- const alerts = await this.fetchWindows(client, window, result, startedMs);
263
- result.fetchedCount = alerts.length;
264
- result.checks.push({
425
+ const rulePass = await this.searchPass(client, window, result, budget, seen, { curated: false, bases: searchBases });
426
+ result.sourceCounts.ruleDetections = rulePass.returned;
427
+ this.recordPass({
428
+ result,
265
429
  name: phase,
266
- status: "success",
267
- durationMs: Date.now() - phaseStartedMs,
268
- message: "The configured Google SecOps instance is reachable and allows reading detections.",
430
+ startedMs: phaseStartedMs,
431
+ outcome: rulePass,
432
+ countMessage: `${rulePass.returned} rule detections returned for the window by ${basisLabel}.`,
269
433
  });
434
+ phase = `Read curated rule detections by ${basisLabel}`;
435
+ phaseStartedMs = Date.now();
436
+ try {
437
+ const curatedPass = await this.searchPass(client, window, result, budget, seen, { curated: true, bases: searchBases });
438
+ result.sourceCounts.curatedDetections = curatedPass.returned;
439
+ this.recordPass({
440
+ result,
441
+ name: phase,
442
+ startedMs: phaseStartedMs,
443
+ outcome: curatedPass,
444
+ countMessage: `${curatedPass.returned} curated rule detections returned for the window by ${basisLabel}.`,
445
+ });
446
+ }
447
+ catch (curatedError) {
448
+ /*
449
+ * Named differently from the outer catch on purpose: the guidance
450
+ * accuracy test reads executeUnlocked's first catch clause, by its
451
+ * variable name, as the run-failure path.
452
+ */
453
+ const status = GoogleSecOpsClient.readHttpStatus(curatedError);
454
+ if (status === null || !CURATED_OPTIONAL_STATUSES.includes(status)) {
455
+ throw curatedError;
456
+ }
457
+ const message = redactLogString(ConnectorErrorMessage.toMessage(curatedError));
458
+ result.warnings.push(`Curated rule detections could not be read (HTTP ${status}); this tenant may not have curated rule access. Rule detections and the alerts view were still read.`);
459
+ result.checks.push({
460
+ name: phase,
461
+ status: "warn",
462
+ durationMs: Date.now() - phaseStartedMs,
463
+ message,
464
+ });
465
+ }
466
+ phase = "Read alerts view by detection time";
467
+ phaseStartedMs = Date.now();
468
+ const alertsPass = await this.fetchWindows(client, window, result, budget, seen);
469
+ result.sourceCounts.alertsView = alertsPass.returned;
470
+ this.recordPass({
471
+ result,
472
+ name: phase,
473
+ startedMs: phaseStartedMs,
474
+ outcome: alertsPass,
475
+ countMessage: `${alertsPass.returned} alerts returned by detection time.`,
476
+ successMessage: `${alertsPass.returned} alerts returned by detection time. The configured Google SecOps instance is reachable and allows reading detections.`,
477
+ });
478
+ const alerts = Array.from(seen.values());
479
+ result.fetchedCount = alerts.length;
480
+ result.creationLag = this.measureCreationLag(alerts, connection, result);
270
481
  phase = "Normalize detections";
271
482
  phaseStartedMs = Date.now();
272
483
  const normalized = [];
@@ -287,18 +498,25 @@ export default class GoogleSecOpsPoller {
287
498
  }
288
499
  }
289
500
  if (result.rejectedCount) {
290
- result.warnings.push(`${result.rejectedCount} returned objects were discarded because they do not look like Google SecOps detections.`);
501
+ /*
502
+ * Counted and reported, never retried: an object Google returns
503
+ * that is not a Collection is permanently unrecognizable, so
504
+ * holding the cursor for it would pin the window until the 24 hour
505
+ * chunk could never reach the present.
506
+ */
507
+ result.warnings.push(`${result.rejectedCount} returned objects were discarded because they do not look like Google SecOps detections. They are counted here and do not hold the poll cursor.`);
291
508
  }
292
509
  if (result.failedCount) {
293
- result.warnings.push(`${result.failedCount} detections could not be normalized. The poll cursor is held for retry.`);
510
+ result.warnings.push(`${result.failedCount} detections could not be normalized, so this window is not fully imported.`);
294
511
  }
295
- result.complete =
296
- result.complete &&
297
- result.failedCount === 0 &&
298
- result.rejectedCount === 0;
512
+ result.complete = result.complete && result.failedCount === 0;
299
513
  result.checks.push({
300
514
  name: phase,
301
- status: result.failedCount || result.rejectedCount ? "failed" : "success",
515
+ status: result.failedCount
516
+ ? "failed"
517
+ : result.rejectedCount
518
+ ? "warn"
519
+ : "success",
302
520
  durationMs: Date.now() - phaseStartedMs,
303
521
  message: `${normalized.length} detections recognized; ${result.rejectedCount} rejected; ${result.failedCount} failed.`,
304
522
  });
@@ -330,29 +548,40 @@ export default class GoogleSecOpsPoller {
330
548
  message: result.error,
331
549
  });
332
550
  }
551
+ let decision = null;
552
+ if (options.type === "poll") {
553
+ decision = this.decideCursor(window, result);
554
+ result.nextChunkMinutes = decision.nextChunkMinutes;
555
+ if (decision.forcedAdvance) {
556
+ result.forcedAdvance = true;
557
+ }
558
+ if (decision.warning) {
559
+ /*
560
+ * A forced advance leaves a reported gap, so it leads the warnings
561
+ * (and therefore lastError); narrowing follows the reasons for it.
562
+ */
563
+ if (decision.forcedAdvance) {
564
+ result.warnings.unshift(decision.warning);
565
+ }
566
+ else {
567
+ result.warnings.push(decision.warning);
568
+ }
569
+ }
570
+ }
333
571
  result.completedAt = OneUptimeDate.getCurrentDate().toISOString();
334
572
  result.durationMs = Math.max(0, Date.now() - startedMs);
335
573
  for (const warning of result.warnings) {
336
574
  logger.warn(`GoogleSecOpsPoller: connection ${connection.id.toString()}: ${warning}`);
337
575
  }
338
576
  logger.debug(`GoogleSecOpsPoller: connection ${connection.id.toString()} fetched ${result.fetchedCount} alerts and ingested ${result.ingestedCount} security events for ${result.windowStart} to ${result.windowEnd}.`);
339
- if (options.type === "poll") {
340
- /*
341
- * A failed first poll must keep its original start. Otherwise the next
342
- * default lookback would slide past records before we ever imported them.
343
- */
344
- const cursor = result.complete
345
- ? result.windowEnd
346
- : !window.hasUsableCursor
347
- ? OneUptimeDate.addRemoveMinutes(window.startTime, WINDOW_OVERLAP_IN_MINUTES).toISOString()
348
- : undefined;
577
+ if (options.type === "poll" && decision) {
349
578
  await GoogleSecOpsConnectionService.updateOneById({
350
579
  id: connection.id,
351
580
  data: Object.assign(Object.assign(Object.assign({ lastPolledAt: new Date(result.completedAt), lastPollResult: result, lastError: (result.error ||
352
581
  (result.complete
353
582
  ? null
354
583
  : result.warnings.join(" ") ||
355
- "Poll incomplete; retrying the same window.")) }, (cursor ? { cursor } : {})), (result.complete
584
+ "Poll incomplete.")) }, (decision.cursor ? { cursor: decision.cursor } : {})), (result.complete
356
585
  ? { lastSuccessfulPollAt: new Date(result.completedAt) }
357
586
  : {})), (result.ingestedCount
358
587
  ? { lastEventIngestedAt: new Date(result.completedAt) }
@@ -369,32 +598,140 @@ export default class GoogleSecOpsPoller {
369
598
  }
370
599
  return result;
371
600
  }
372
- static async fetchWindows(client, window, result, startedMs) {
373
- const pending = [window];
374
- const seen = new Map();
601
+ /*
602
+ * Where a scheduled poll leaves its cursor and how long the next chunk is.
603
+ * Google's search endpoints return newest first, so a poll that stops
604
+ * early has no "everything before here was read" point to resume from;
605
+ * the only ways forward are a shorter window and, at one minute, moving
606
+ * past the minute and reporting it.
607
+ */
608
+ static decideCursor(window, result) {
609
+ const chunkMinutes = window.chunkMinutes || MAX_CHUNK_MINUTES;
610
+ const requestedChunkMinutes = window.requestedChunkMinutes || MAX_CHUNK_MINUTES;
611
+ /*
612
+ * A first poll that does not finish keeps its original start. Otherwise
613
+ * the next default lookback would slide past records before we ever
614
+ * imported them.
615
+ */
616
+ const heldCursor = window.hasUsableCursor
617
+ ? undefined
618
+ : OneUptimeDate.addRemoveMinutes(window.startTime, WINDOW_OVERLAP_IN_MINUTES).toISOString();
619
+ /*
620
+ * Failed and finished polls work from the requested chunk, not from the
621
+ * window read: a caught-up window is only as long as the gap to now, and
622
+ * keeping that as the next chunk would make polls after an outage or a
623
+ * failure fall behind the present for no reason.
624
+ */
625
+ if (result.status === "failed") {
626
+ // A failure says nothing about volume, so the chunk is kept as it was.
627
+ return {
628
+ cursor: heldCursor,
629
+ nextChunkMinutes: requestedChunkMinutes,
630
+ forcedAdvance: false,
631
+ };
632
+ }
633
+ if (result.complete) {
634
+ // A finished poll never shrinks the chunk; it doubles back after narrowing.
635
+ return {
636
+ cursor: result.windowEnd,
637
+ nextChunkMinutes: Math.min(MAX_CHUNK_MINUTES, Math.max(requestedChunkMinutes, chunkMinutes * 2)),
638
+ forcedAdvance: false,
639
+ };
640
+ }
641
+ if (chunkMinutes > MIN_CHUNK_MINUTES) {
642
+ const nextChunkMinutes = Math.max(MIN_CHUNK_MINUTES, Math.floor(chunkMinutes / 2));
643
+ return {
644
+ cursor: heldCursor,
645
+ nextChunkMinutes,
646
+ forcedAdvance: false,
647
+ warning: `This window holds more records than one poll can read; the next poll reads a ${nextChunkMinutes} minute window from the same starting point.`,
648
+ };
649
+ }
650
+ /*
651
+ * One minute that still cannot be read. Holding here would stall polling
652
+ * for good, so the cursor moves past the minute and the gap is reported
653
+ * loudly with the way to recover it.
654
+ */
655
+ const from = window.chunkBase || window.startTime;
656
+ return {
657
+ cursor: result.windowEnd,
658
+ nextChunkMinutes: MIN_CHUNK_MINUTES,
659
+ forcedAdvance: true,
660
+ warning: `More records were created in the one minute from ${from.toISOString()} 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.`,
661
+ };
662
+ }
663
+ /*
664
+ * One diagnostic check per read pass. A pass a budget stopped, or never
665
+ * let start, is a warning naming the budget, never a success: a green
666
+ * step that did not read its window hid which data went unread.
667
+ */
668
+ static recordPass(data) {
669
+ const outcome = data.outcome;
670
+ let status = "success";
671
+ let message = data.successMessage || data.countMessage;
672
+ if (outcome.stoppedBy === "time" && outcome.requests === 0) {
673
+ status = "warn";
674
+ message = "Not run: the poll time budget was spent.";
675
+ this.addWarning(data.result, `${data.name} was not run: the poll time budget was spent.`);
676
+ }
677
+ else if (outcome.stoppedBy) {
678
+ status = "warn";
679
+ const budgetName = outcome.stoppedBy === "time" ? "poll time budget" : "request budget";
680
+ const stop = `stopped by the ${budgetName} after ${outcome.requests} ${outcome.requests === 1 ? "request" : "requests"}`;
681
+ message =
682
+ outcome.requests === 0
683
+ ? `Not run: ${stop}. The search passes share one page budget and it was spent before this pass started.`
684
+ : `${data.countMessage} The pass was ${stop}.`;
685
+ this.addWarning(data.result, `${data.name} was ${stop}.`);
686
+ }
687
+ else if (outcome.leftUnread) {
688
+ status = "warn";
689
+ message = `${data.countMessage} Google did not return part of the window.`;
690
+ }
691
+ data.result.checks.push({
692
+ name: data.name,
693
+ status,
694
+ durationMs: Date.now() - data.startedMs,
695
+ message,
696
+ });
697
+ }
698
+ /*
699
+ * The alerts-view pass (legacyFetchAlertsView, detection time). The
700
+ * endpoint has no pagination, so a truncated window is split in half and
701
+ * both halves are re-read until they fit or the alerts-view budget runs
702
+ * out.
703
+ */
704
+ static async fetchWindows(client, window, result, budget, seen) {
705
+ const outcome = {
706
+ returned: 0,
707
+ requests: 0,
708
+ stoppedBy: null,
709
+ leftUnread: false,
710
+ };
711
+ const pending = [
712
+ { startTime: window.startTime, endTime: window.endTime },
713
+ ];
714
+ let splits = 0;
375
715
  while (pending.length > 0) {
376
- if (result.requestCount >= MAX_FETCH_REQUESTS ||
377
- Date.now() - startedMs >= MAX_FETCH_DURATION_MS) {
716
+ const stop = this.budgetStop(budget, budget.alertsViewRequests, MAX_ALERTS_VIEW_REQUESTS_PER_POLL);
717
+ if (stop) {
718
+ outcome.stoppedBy = stop;
378
719
  result.complete = false;
379
- result.warnings.push("The recovery request limit was reached. Narrow the time range; the poll cursor has not advanced.");
380
720
  break;
381
721
  }
382
722
  const current = pending.shift();
723
+ budget.alertsViewRequests++;
724
+ outcome.requests++;
383
725
  result.requestCount++;
384
- const fetched = await client.fetchDetectionAlerts(Object.assign(Object.assign({}, current), { maxAlerts: result.type === "test" ? 1 : MAX_ALERTS_PER_REQUEST, includeNonAlertingDetections: result.includeNonAlertingDetections }));
726
+ const fetched = await client.fetchDetectionAlerts({
727
+ startTime: current.startTime,
728
+ endTime: current.endTime,
729
+ maxAlerts: result.type === "test" ? 1 : MAX_ALERTS_PER_REQUEST,
730
+ includeNonAlertingDetections: result.includeNonAlertingDetections,
731
+ });
732
+ outcome.returned += fetched.alerts.length;
385
733
  for (const alert of fetched.alerts) {
386
- let key;
387
- try {
388
- key = readString(alert, "id") || contentHashEventUid(alert);
389
- }
390
- catch (_a) {
391
- /*
392
- * Keep an uninspectable object in the normalization failure count
393
- * without preventing valid detections in this response from importing.
394
- */
395
- key = `malformed:${result.requestCount}:${seen.size}`;
396
- }
397
- seen.set(key, alert);
734
+ this.collect(seen, alert, result);
398
735
  }
399
736
  result.fetchedCount = seen.size;
400
737
  const truncated = fetched.truncatedByCount ||
@@ -406,7 +743,7 @@ export default class GoogleSecOpsPoller {
406
743
  * A one-record permission probe is deliberately limited; it makes no
407
744
  * assertion about whether the full detection window can be imported.
408
745
  */
409
- result.complete = fetched.complete;
746
+ result.complete = result.complete && fetched.complete;
410
747
  if (truncated) {
411
748
  result.warnings.push("Connection test reads at most one detection. Use Preview to inspect the full time range.");
412
749
  }
@@ -418,17 +755,162 @@ export default class GoogleSecOpsPoller {
418
755
  const midpoint = Math.floor((current.startTime.getTime() + current.endTime.getTime()) / 2);
419
756
  if (truncated &&
420
757
  current.endTime.getTime() - current.startTime.getTime() > 1000) {
421
- result.warnings.push(`Google limited the response for ${current.startTime.toISOString()} to ${current.endTime.toISOString()}; retrying smaller windows.`);
758
+ splits++;
422
759
  pending.unshift({ startTime: current.startTime, endTime: new Date(midpoint) }, { startTime: new Date(midpoint), endTime: current.endTime });
423
760
  }
424
761
  else if (!fetched.complete || truncated) {
425
762
  result.complete = false;
426
- result.warnings.push(truncated
427
- ? "Google still truncated a one-second window. Some detections may be missing; the cursor has not advanced."
428
- : "Google ended the response without confirming it was complete; the cursor has not advanced.");
763
+ outcome.leftUnread = true;
764
+ this.addWarning(result, truncated
765
+ ? "Google still truncated a one-second window of the alerts view, so some alerts in it were not read."
766
+ : "Google ended an alerts view response without confirming it was complete.");
429
767
  }
430
768
  }
431
- return Array.from(seen.values());
769
+ if (splits > 0) {
770
+ // One line rather than one per split: lastError joins every warning.
771
+ result.warnings.push(`Google limited the alerts view response for ${window.startTime.toISOString()} to ${window.endTime.toISOString()}, so it was split into smaller windows ${splits} ${splits === 1 ? "time" : "times"}.`);
772
+ }
773
+ return outcome;
774
+ }
775
+ /*
776
+ * A detections-search pass (legacySearchDetections or the curated
777
+ * variant), one basis at a time, following nextPageToken under the page
778
+ * budget the two search passes share.
779
+ */
780
+ static async searchPass(client, window, result, budget, seen, options) {
781
+ const label = options.curated
782
+ ? "curated rule detections"
783
+ : "rule detections";
784
+ const outcome = {
785
+ returned: 0,
786
+ requests: 0,
787
+ stoppedBy: null,
788
+ leftUnread: false,
789
+ };
790
+ for (const listBasis of options.bases) {
791
+ let pageToken = undefined;
792
+ do {
793
+ const stop = this.budgetStop(budget, budget.searchRequests, MAX_SEARCH_PAGES_PER_POLL);
794
+ if (stop) {
795
+ outcome.stoppedBy = stop;
796
+ result.complete = false;
797
+ return outcome;
798
+ }
799
+ budget.searchRequests++;
800
+ outcome.requests++;
801
+ result.requestCount++;
802
+ const page = await client.searchDetections({
803
+ startTime: window.startTime,
804
+ endTime: window.endTime,
805
+ listBasis,
806
+ alertingOnly: !result.includeNonAlertingDetections,
807
+ pageSize: result.type === "test" ? 1 : MAX_SEARCH_PAGE_SIZE,
808
+ pageToken,
809
+ curated: options.curated,
810
+ });
811
+ outcome.returned += page.detections.length;
812
+ for (const detection of page.detections) {
813
+ this.collect(seen, detection, result);
814
+ }
815
+ result.fetchedCount = seen.size;
816
+ if (page.truncated) {
817
+ /*
818
+ * respTooLargeDetectionsTruncated: Google cut the page by byte
819
+ * size and the rest is not reachable through a page token, so the
820
+ * window is not fully read.
821
+ */
822
+ result.complete = false;
823
+ outcome.leftUnread = true;
824
+ this.addWarning(result, `Google truncated a page of ${label} by size for ${window.startTime.toISOString()} to ${window.endTime.toISOString()}, so part of the window was not read.`);
825
+ }
826
+ if (result.type === "test") {
827
+ // One record per pass is all a permission probe needs.
828
+ return outcome;
829
+ }
830
+ pageToken = page.nextPageToken || undefined;
831
+ } while (pageToken);
832
+ }
833
+ return outcome;
834
+ }
835
+ /*
836
+ * Whether a pass may make another request: each kind of read has its own
837
+ * request count, and all of them share the poll's wall-clock bound so a
838
+ * slow endpoint cannot run the worker job into its timeout.
839
+ */
840
+ static budgetStop(budget, used, limit) {
841
+ if (used >= limit) {
842
+ return "requests";
843
+ }
844
+ if (Date.now() - budget.startedMs >= MAX_FETCH_DURATION_MS) {
845
+ return "time";
846
+ }
847
+ return null;
848
+ }
849
+ // Repeated conditions (every one-second window, every page) are said once.
850
+ static addWarning(result, warning) {
851
+ if (!result.warnings.includes(warning)) {
852
+ result.warnings.push(warning);
853
+ }
854
+ }
855
+ /*
856
+ * Union by Collection.id across passes and across the alerts view's
857
+ * chunks; a record with no id falls back to a content hash, and an
858
+ * object that cannot even be inspected is kept under a positional key so
859
+ * it is counted as rejected without hiding the valid records beside it.
860
+ */
861
+ static collect(seen, record, result) {
862
+ let key;
863
+ try {
864
+ key = readString(record, "id") || contentHashEventUid(record);
865
+ }
866
+ catch (_a) {
867
+ key = `malformed:${result.requestCount}:${seen.size}`;
868
+ }
869
+ seen.set(key, record);
870
+ }
871
+ /*
872
+ * createdTime minus detectionTime over what was fetched. A lag beyond one
873
+ * poll interval is the record a detection-time cursor skips, so the
874
+ * warning names the reason polling reads created time.
875
+ */
876
+ static measureCreationLag(alerts, connection, result) {
877
+ var _a, _b;
878
+ const intervalInMinutes = Math.max(1, connection.pollIntervalInMinutes || DEFAULT_POLL_INTERVAL_IN_MINUTES);
879
+ const thresholdInMinutes = intervalInMinutes + CREATION_LAG_GRACE_IN_MINUTES;
880
+ let measured = 0;
881
+ let lateCount = 0;
882
+ let maxLagMs = 0;
883
+ for (const alert of alerts) {
884
+ let detectionTime = null;
885
+ let createdTime = null;
886
+ try {
887
+ detectionTime = parseEventTime((_a = readValue(alert, "detectionTime")) !== null && _a !== void 0 ? _a : readValue(alert, "detection_time"));
888
+ createdTime = parseEventTime((_b = readValue(alert, "createdTime")) !== null && _b !== void 0 ? _b : readValue(alert, "created_time"));
889
+ }
890
+ catch (_c) {
891
+ continue;
892
+ }
893
+ if (!detectionTime || !createdTime) {
894
+ continue;
895
+ }
896
+ measured++;
897
+ const lagMs = createdTime.getTime() - detectionTime.getTime();
898
+ if (lagMs > maxLagMs) {
899
+ maxLagMs = lagMs;
900
+ }
901
+ if (lagMs > thresholdInMinutes * 60 * 1000) {
902
+ lateCount++;
903
+ }
904
+ }
905
+ const lag = {
906
+ measured,
907
+ lateCount,
908
+ maxLagMinutes: Math.round(maxLagMs / 60000),
909
+ };
910
+ if (lateCount > 0) {
911
+ result.warnings.push(`${lateCount} of ${measured} detections were created more than ${thresholdInMinutes} minutes after their detection time (up to ${lag.maxLagMinutes} minutes). This is why the connector polls by created time: a cursor over detection time would already have moved past them.`);
912
+ }
913
+ return lag;
432
914
  }
433
915
  static sample(alert, event) {
434
916
  var _a, _b, _c, _d;
@@ -450,42 +932,17 @@ export default class GoogleSecOpsPoller {
450
932
  : {}));
451
933
  }
452
934
  /**
453
- * This is a correctness lookup, not a dashboard query: returning a partial
454
- * result on timeout or reading a lagging replica would create duplicates.
455
- * Read every replica and fail closed on an unavailable shard. The preceding
456
- * source lock plus synchronous inserts make at least one replica contain
457
- * every earlier acknowledged import before this query begins.
935
+ * Thin delegate kept as a static on this class: existing tests spy on it,
936
+ * and the query itself now lives in SecurityEventDedupe so the Google
937
+ * poller and the Security Event Connections poller cannot drift.
458
938
  */
459
939
  static async findExistingEventUids(projectId, ids) {
460
- const existing = new Set();
461
- const startedMs = Date.now();
462
- for (let offset = 0; offset < ids.length; offset += MAX_ALERTS_PER_REQUEST) {
463
- if (Date.now() - startedMs >= 2 * 60 * 1000) {
464
- throw new Error("Duplicate lookup exceeded its time limit. Retry a smaller import window.");
465
- }
466
- const statement = SQL `SELECT DISTINCT eventUid FROM clusterAllReplicas(
467
- ${{ type: TableColumnType.Text, value: getClickhouseClusterName() }},
468
- ${{ type: TableColumnType.Text, value: getClickhouseDatabaseName() }},
469
- ${{ type: TableColumnType.Text, value: getStorageTableName(SecurityEventService.model.tableName) }}
470
- ) WHERE projectId = ${{ type: TableColumnType.ObjectID, value: projectId }}
471
- AND vendorName = ${{ type: TableColumnType.Text, value: "Google" }}
472
- AND productName = ${{ type: TableColumnType.Text, value: SECOPS_SERVICE_NAME }}
473
- AND eventUid IN ${{ type: TableColumnType.ArrayText, value: ids.slice(offset, offset + MAX_ALERTS_PER_REQUEST) }}`;
474
- statement.append(getQuerySettings({
475
- maxExecutionTimeInSeconds: 30,
476
- timeoutOverflowMode: "throw",
477
- boundScanMemory: true,
478
- additionalSettings: { skip_unavailable_shards: 0 },
479
- }));
480
- const response = await SecurityEventService.executeQuery(statement);
481
- const data = await response.json();
482
- for (const row of data.data) {
483
- if (typeof row["eventUid"] === "string") {
484
- existing.add(row["eventUid"]);
485
- }
486
- }
487
- }
488
- return existing;
940
+ return SecurityEventDedupe.findExistingEventUids({
941
+ projectId,
942
+ vendorName: SECOPS_VENDOR_NAME,
943
+ productName: SECOPS_SERVICE_NAME,
944
+ ids,
945
+ });
489
946
  }
490
947
  static async ingest(connection, normalized, result) {
491
948
  if (!normalized.length) {