@oneuptime/common 13.0.4 → 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 (673) 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/Monitor/MonitorCriteriaEvaluatorPerSeriesFanout.test.ts +55 -2
  160. package/Tests/Server/Utils/SecurityEvent/Connectors/AwsSecurityHub/AwsSecurityHubClient.test.ts +1240 -0
  161. package/Tests/Server/Utils/SecurityEvent/Connectors/AwsSecurityHub/AwsSecurityHubConnector.test.ts +1853 -0
  162. package/Tests/Server/Utils/SecurityEvent/Connectors/ConnectorPlatformHealth.test.ts +1129 -0
  163. package/Tests/Server/Utils/SecurityEvent/Connectors/CrowdStrikeFalcon/CrowdStrikeFalconClient.test.ts +1066 -0
  164. package/Tests/Server/Utils/SecurityEvent/Connectors/CrowdStrikeFalcon/CrowdStrikeFalconConnector.test.ts +1568 -0
  165. package/Tests/Server/Utils/SecurityEvent/Connectors/ElasticSecurity/ElasticSecurityClient.test.ts +930 -0
  166. package/Tests/Server/Utils/SecurityEvent/Connectors/ElasticSecurity/ElasticSecurityConnector.test.ts +1409 -0
  167. package/Tests/Server/Utils/SecurityEvent/Connectors/MicrosoftDefenderXdr/MicrosoftDefenderXdrClient.test.ts +763 -0
  168. package/Tests/Server/Utils/SecurityEvent/Connectors/MicrosoftDefenderXdr/MicrosoftDefenderXdrConnector.test.ts +1296 -0
  169. package/Tests/Server/Utils/SecurityEvent/Connectors/MicrosoftSentinel/MicrosoftSentinelClient.test.ts +1102 -0
  170. package/Tests/Server/Utils/SecurityEvent/Connectors/MicrosoftSentinel/MicrosoftSentinelConnector.test.ts +1174 -0
  171. package/Tests/Server/Utils/SecurityEvent/Connectors/Okta/OktaClient.test.ts +1032 -0
  172. package/Tests/Server/Utils/SecurityEvent/Connectors/Okta/OktaConnector.test.ts +1558 -0
  173. package/Tests/Server/Utils/SecurityEvent/Connectors/SecurityEventConnectionPoller.test.ts +3041 -0
  174. package/Tests/Server/Utils/SecurityEvent/Connectors/SecurityEventConnectionRunExecutor.test.ts +1168 -0
  175. package/Tests/Server/Utils/SecurityEvent/Connectors/SecurityEventConnectionTester.test.ts +906 -0
  176. package/Tests/Server/Utils/SecurityEvent/Connectors/Splunk/SplunkClient.test.ts +1068 -0
  177. package/Tests/Server/Utils/SecurityEvent/Connectors/Splunk/SplunkConnector.test.ts +1004 -0
  178. package/Tests/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsConnectionTester.test.ts +784 -0
  179. package/Tests/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsRunExecutor.test.ts +113 -1
  180. package/Tests/Server/Utils/SecurityEvent/GoogleSecOpsClient.test.ts +5 -1
  181. package/Tests/Server/Utils/SecurityEvent/GoogleSecOpsDiagnostics.test.ts +93 -13
  182. package/Tests/Server/Utils/SecurityEvent/GoogleSecOpsHttpIntegration.test.ts +23 -1
  183. package/Tests/Server/Utils/SecurityEvent/GoogleSecOpsPoller.test.ts +25 -3
  184. package/Tests/Server/Utils/SecurityEvent/GoogleSecOpsPollerFailureTaxonomy.test.ts +22 -8
  185. package/Tests/Server/Utils/SecurityEvent/GoogleSecOpsPollerHardening.test.ts +82 -16
  186. package/Tests/Server/Utils/SecurityEvent/GoogleSecOpsSearchDetections.test.ts +730 -0
  187. package/Tests/Server/Utils/SecurityEvent/GoogleSecOpsThreePassPoller.test.ts +1577 -0
  188. package/Tests/Server/Utils/SessionReplay/SessionReplayOriginAllowlist.test.ts +41 -0
  189. package/Tests/Server/Utils/SessionReplay/SessionReplayReadServiceQueries.test.ts +1453 -18
  190. package/Tests/Server/Utils/Telemetry/KubernetesResourceAttributes.test.ts +162 -0
  191. package/Tests/Server/Utils/Telemetry/ResourceEntityFilter.test.ts +460 -13
  192. package/Tests/Server/Utils/Telemetry/ResourceFacetPlanner.test.ts +678 -0
  193. package/Tests/Server/Utils/Telemetry/ResourceFacetResolver.test.ts +348 -2
  194. package/Tests/Server/Utils/Telemetry/ServiceDependencyDiscovery.test.ts +525 -0
  195. package/Tests/Server/Utils/Telemetry/TraceContextPropagation.test.ts +420 -0
  196. package/Tests/Types/Rum/SessionReplayApiContracts.test.ts +73 -0
  197. package/Tests/Types/Rum/SessionReplayTransportContracts.test.ts +95 -0
  198. package/Tests/Types/SecurityEvent/Connectors/ConnectorDiagnostics.test.ts +82 -0
  199. package/Tests/Types/SecurityEvent/Connectors/SecurityEventConnectorCatalog.test.ts +314 -0
  200. package/Tests/Types/Telemetry/ExceptionSpanScope.test.ts +89 -0
  201. package/Tests/Types/Telemetry/ResourceEntityFacet.test.ts +96 -0
  202. package/Tests/Types/Telemetry/ResourceFacetCatalog.test.ts +304 -0
  203. package/Tests/UI/Components/ActiveFilterChipsLockedFilters.test.tsx +357 -0
  204. package/Tests/UI/Components/Card.test.tsx +312 -1
  205. package/Tests/UI/Components/CardModelDetailHeaderLayout.test.tsx +253 -0
  206. package/Tests/UI/Components/CardModelDetailRefresher.test.tsx +342 -0
  207. package/Tests/UI/Components/Checkbox.test.tsx +79 -0
  208. package/Tests/UI/Components/CopyTextButton.test.tsx +142 -0
  209. package/Tests/UI/Components/DetailCompactStyle.test.tsx +621 -0
  210. package/Tests/UI/Components/ErrorBoundary.test.tsx +60 -0
  211. package/Tests/UI/Components/FacetSections.test.tsx +581 -0
  212. package/Tests/UI/Components/FacetSidebarControls.test.tsx +812 -0
  213. package/Tests/UI/Components/FacetVisibility.test.ts +429 -0
  214. package/Tests/UI/Components/LockedFilterActions.test.tsx +396 -0
  215. package/Tests/UI/Components/LockedFilterChip.test.tsx +651 -0
  216. package/Tests/UI/Components/LogsEntityNames.test.ts +1769 -0
  217. package/Tests/UI/Components/LogsEntityNamesComponents.test.tsx +696 -0
  218. package/Tests/UI/Components/LogsFacetSidebarHiddenFacets.test.tsx +600 -0
  219. package/Tests/UI/Components/LogsViewerEntityNames.test.tsx +713 -0
  220. package/Tests/UI/Components/MarkdownInlineReferences.test.tsx +2079 -0
  221. package/Tests/UI/Components/MemberRoleAssignment.test.tsx +446 -0
  222. package/Tests/UI/Components/ModelDetailRefetch.test.tsx +397 -0
  223. package/Tests/UI/Components/ModelListRefetch.test.tsx +233 -0
  224. package/Tests/UI/Components/ModelPageModelChange.test.tsx +409 -0
  225. package/Tests/UI/Components/PaginationIntegration.test.tsx +25 -0
  226. package/Tests/UI/Components/ResourceFacetConfigs.test.ts +172 -0
  227. package/Tests/UI/Components/SavedViewsSidebarIntegration.test.tsx +32 -14
  228. package/Tests/UI/Components/TableSortAndMobileColumns.test.tsx +44 -1
  229. package/Tests/UI/Components/TelemetryActiveFilterChipsLockedFilters.test.tsx +304 -0
  230. package/Tests/UI/Components/TelemetryFacetSidebarHiddenFacets.test.tsx +718 -0
  231. package/Tests/UI/Monitor/EvaluationLogList.test.tsx +303 -0
  232. package/Tests/UI/Monitor/MonitorSummarySnapshotRender.test.tsx +55 -1
  233. package/Tests/UI/Rum/FidelityNotices.test.ts +22 -0
  234. package/Tests/UI/Rum/RecordingHealthCard.test.tsx +120 -136
  235. package/Tests/UI/Rum/RecordingHealthDashboard.test.tsx +988 -0
  236. package/Tests/UI/Rum/ReplayCard.test.tsx +32 -0
  237. package/Tests/UI/Rum/ReplayCorrelationPanel.test.tsx +709 -12
  238. package/Tests/UI/Rum/ReplayHeader.test.tsx +50 -1
  239. package/Tests/UI/Rum/ReplayPinControl.test.tsx +67 -10
  240. package/Tests/UI/Rum/ReplayPlayerChrome.test.tsx +41 -12
  241. package/Tests/UI/Rum/ReplayStage.test.tsx +663 -1
  242. package/Tests/UI/Rum/ReplayStageOverlays.test.tsx +173 -0
  243. package/Tests/UI/Rum/ReplayUi.test.tsx +189 -2
  244. package/Tests/UI/Rum/ReplayUserSessionsMenu.test.tsx +91 -0
  245. package/Tests/UI/Rum/SessionReplayEmptyState.test.tsx +1 -1
  246. package/Tests/UI/Rum/SessionReplaySettingsPolicyLoading.test.tsx +585 -0
  247. package/Tests/UI/Rum/SessionReplayTable.test.tsx +844 -51
  248. package/Tests/UI/Rum/SessionReplayUsersTable.test.tsx +29 -1
  249. package/Tests/UI/Telemetry/TelemetryDetailPanel.test.tsx +288 -0
  250. package/Tests/UI/Utils/Breadcrumb/fixtures/RealBreadcrumbTrails.ts +31 -1
  251. package/Tests/UI/Utils/Breadcrumb/fixtures/RealRoutePatterns.ts +6 -0
  252. package/Tests/UI/Utils/Clipboard.test.ts +154 -0
  253. package/Tests/UI/Utils/Navigation.test.ts +24 -0
  254. package/Tests/UI/Utils/Telemetry/TelemetryEntityNames.test.ts +2205 -0
  255. package/Tests/UI/Utils/Telemetry/UseTelemetryEntityNames.test.tsx +844 -0
  256. package/Tests/Utils/AI/InvestigationReport.test.ts +2430 -0
  257. package/Tests/Utils/APIOutgoingRequestTracer.test.ts +137 -0
  258. package/Tests/Utils/Rum/SessionReplayHealthDiagnosis.test.ts +40 -0
  259. package/Tests/Utils/Rum/SessionReplayRecordingEnded.test.ts +619 -0
  260. package/Tests/Utils/SecurityEvent/Connectors/AwsSecurityHubNormalizer.test.ts +631 -0
  261. package/Tests/Utils/SecurityEvent/Connectors/CrowdStrikeFalconNormalizer.test.ts +479 -0
  262. package/Tests/Utils/SecurityEvent/Connectors/ElasticSecurityNormalizer.test.ts +507 -0
  263. package/Tests/Utils/SecurityEvent/Connectors/MicrosoftDefenderXdrNormalizer.test.ts +686 -0
  264. package/Tests/Utils/SecurityEvent/Connectors/MicrosoftSentinelNormalizer.test.ts +474 -0
  265. package/Tests/Utils/SecurityEvent/Connectors/OktaNormalizer.test.ts +736 -0
  266. package/Tests/Utils/SecurityEvent/Connectors/SplunkNormalizer.test.ts +407 -0
  267. package/Tests/Utils/SecurityEvent/GoogleSecOpsAlertNormalizer.test.ts +129 -0
  268. package/Tests/Utils/Telemetry/CrossSignalScope.test.ts +57 -1
  269. package/Tests/Utils/Telemetry/EntityRelationship.test.ts +36 -0
  270. package/Tests/Utils/Telemetry/LockedFilterSearch.test.ts +600 -0
  271. package/Tests/Utils/Telemetry/NetworkHost.test.ts +48 -0
  272. package/Tests/Utils/Telemetry/OriginAllowList.test.ts +154 -0
  273. package/Tests/Utils/Traces/CriticalPath.test.ts +25 -0
  274. package/Types/AI/AIChatTypes.ts +8 -0
  275. package/Types/AI/InvestigationEvidence.ts +96 -0
  276. package/Types/Monitor/MonitorEvaluationSummary.ts +5 -0
  277. package/Types/Permission.ts +2 -2
  278. package/Types/Rum/SessionReplay.ts +109 -0
  279. package/Types/Rum/SessionReplayApi.ts +31 -0
  280. package/Types/SecurityEvent/Connectors/ConnectorDiagnostics.ts +111 -0
  281. package/Types/SecurityEvent/Connectors/SecurityEventConnectionDiagnostics.ts +87 -0
  282. package/Types/SecurityEvent/Connectors/SecurityEventConnectorCatalog.ts +492 -0
  283. package/Types/SecurityEvent/Connectors/SecurityEventConnectorProvider.ts +41 -0
  284. package/Types/SecurityEvent/GoogleSecOpsDiagnostics.ts +56 -1
  285. package/Types/SecurityEvent/GoogleSecOpsRegion.ts +34 -0
  286. package/Types/Telemetry/EntityType.ts +14 -0
  287. package/Types/Telemetry/ExceptionSpanScope.ts +83 -0
  288. package/Types/Telemetry/LockedFilterDetail.ts +46 -0
  289. package/Types/Telemetry/ResourceEntityFacet.ts +17 -10
  290. package/Types/Telemetry/ResourceFacetCatalog.ts +171 -0
  291. package/UI/Components/Card/Card.tsx +118 -83
  292. package/UI/Components/Checkbox/Checkbox.tsx +8 -5
  293. package/UI/Components/CopyTextButton/CopyTextButton.tsx +7 -1
  294. package/UI/Components/CustomFields/CustomFieldsDetail.tsx +4 -1
  295. package/UI/Components/Detail/Detail.tsx +137 -22
  296. package/UI/Components/ErrorBoundary.tsx +38 -0
  297. package/UI/Components/LogsViewer/LogsEntityNames.ts +912 -0
  298. package/UI/Components/LogsViewer/LogsViewer.tsx +156 -77
  299. package/UI/Components/LogsViewer/components/ActiveFilterChips.tsx +28 -11
  300. package/UI/Components/LogsViewer/components/FacetSection.tsx +66 -79
  301. package/UI/Components/LogsViewer/components/FacetValueRow.tsx +17 -2
  302. package/UI/Components/LogsViewer/components/LogDetailsPanel.tsx +45 -5
  303. package/UI/Components/LogsViewer/components/LogsAnalyticsView.tsx +100 -19
  304. package/UI/Components/LogsViewer/components/LogsFacetSidebar.tsx +156 -39
  305. package/UI/Components/LogsViewer/components/LogsTable.tsx +30 -8
  306. package/UI/Components/LogsViewer/types.ts +6 -0
  307. package/UI/Components/Markdown.tsx/InlineReferences.tsx +628 -0
  308. package/UI/Components/Markdown.tsx/MarkdownViewer.tsx +385 -312
  309. package/UI/Components/MemberRoleAssignment/MemberRoleAssignment.tsx +50 -22
  310. package/UI/Components/ModelDetail/CardModelDetail.tsx +15 -0
  311. package/UI/Components/ModelDetail/ModelDetail.tsx +64 -19
  312. package/UI/Components/ModelList/ModelList.tsx +33 -8
  313. package/UI/Components/Page/ModelPage.tsx +119 -54
  314. package/UI/Components/Table/Table.tsx +8 -0
  315. package/UI/Components/Table/TableRow.tsx +13 -5
  316. package/UI/Components/TelemetryViewer/FacetVisibility.ts +229 -0
  317. package/UI/Components/TelemetryViewer/ResourceFacetConfigs.ts +46 -0
  318. package/UI/Components/TelemetryViewer/TelemetryViewer.tsx +11 -0
  319. package/UI/Components/TelemetryViewer/components/FacetSearchInput.tsx +79 -0
  320. package/UI/Components/TelemetryViewer/components/FacetSectionHeader.tsx +69 -0
  321. package/UI/Components/TelemetryViewer/components/FacetShowMoreButton.tsx +36 -0
  322. package/UI/Components/TelemetryViewer/components/HiddenFacetsFooter.tsx +88 -0
  323. package/UI/Components/TelemetryViewer/components/LockedFilterActions.tsx +205 -0
  324. package/UI/Components/TelemetryViewer/components/LockedFilterChip.tsx +496 -0
  325. package/UI/Components/TelemetryViewer/components/TelemetryActiveFilterChips.tsx +30 -10
  326. package/UI/Components/TelemetryViewer/components/TelemetryDetailPanel.tsx +203 -10
  327. package/UI/Components/TelemetryViewer/components/TelemetryFacetSection.tsx +60 -73
  328. package/UI/Components/TelemetryViewer/components/TelemetryFacetSidebar.tsx +94 -7
  329. package/UI/Components/TelemetryViewer/components/TelemetryFacetValueRow.tsx +17 -2
  330. package/UI/Components/TelemetryViewer/types.ts +19 -0
  331. package/UI/Components/TelemetryViewer/useFacetSearchExemptions.ts +158 -0
  332. package/UI/Components/TelemetryViewer/useFacetSectionSearch.ts +102 -0
  333. package/UI/Utils/Clipboard.ts +68 -2
  334. package/UI/Utils/Navigation.ts +17 -2
  335. package/UI/Utils/Telemetry/TelemetryEntityNames.ts +620 -0
  336. package/UI/Utils/Telemetry/UseTelemetryEntityNames.ts +151 -0
  337. package/Utils/AI/InvestigationReport.ts +1789 -0
  338. package/Utils/API.ts +90 -1
  339. package/Utils/Rum/SessionReplayHealth.ts +11 -0
  340. package/Utils/Rum/SessionReplayRecordingEnded.ts +134 -0
  341. package/Utils/SecurityEvent/Connectors/AwsSecurityHubNormalizer.ts +427 -0
  342. package/Utils/SecurityEvent/Connectors/CrowdStrikeFalconNormalizer.ts +197 -0
  343. package/Utils/SecurityEvent/Connectors/ElasticSecurityNormalizer.ts +464 -0
  344. package/Utils/SecurityEvent/Connectors/MicrosoftDefenderXdrNormalizer.ts +567 -0
  345. package/Utils/SecurityEvent/Connectors/MicrosoftSentinelNormalizer.ts +299 -0
  346. package/Utils/SecurityEvent/Connectors/OktaNormalizer.ts +467 -0
  347. package/Utils/SecurityEvent/Connectors/SplunkNormalizer.ts +439 -0
  348. package/Utils/SecurityEvent/GoogleSecOpsAlertNormalizer.ts +124 -12
  349. package/Utils/Telemetry/CrossSignalScope.ts +22 -8
  350. package/Utils/Telemetry/EntityRelationship.ts +8 -0
  351. package/Utils/Telemetry/LockedFilterSearch.ts +412 -0
  352. package/Utils/Telemetry/NetworkHost.ts +43 -0
  353. package/Utils/Telemetry/OriginAllowList.ts +139 -4
  354. package/Utils/Traces/CriticalPath.ts +10 -4
  355. package/build/dist/Models/DatabaseModels/Index.js +4 -0
  356. package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
  357. package/build/dist/Models/DatabaseModels/RumApplication.js +1 -1
  358. package/build/dist/Models/DatabaseModels/RumApplication.js.map +1 -1
  359. package/build/dist/Models/DatabaseModels/SecurityEventConnection.js +490 -0
  360. package/build/dist/Models/DatabaseModels/SecurityEventConnection.js.map +1 -0
  361. package/build/dist/Models/DatabaseModels/SecurityEventConnectionRun.js +287 -0
  362. package/build/dist/Models/DatabaseModels/SecurityEventConnectionRun.js.map +1 -0
  363. package/build/dist/Models/DatabaseModels/TelemetryIngestionKey.js +2 -2
  364. package/build/dist/Models/DatabaseModels/TelemetryIngestionKey.js.map +1 -1
  365. package/build/dist/Server/API/AIInvestigationAPI.js +336 -27
  366. package/build/dist/Server/API/AIInvestigationAPI.js.map +1 -1
  367. package/build/dist/Server/API/GoogleSecOpsConnectionAPI.js +182 -7
  368. package/build/dist/Server/API/GoogleSecOpsConnectionAPI.js.map +1 -1
  369. package/build/dist/Server/API/SecurityEventConnectionAPI.js +171 -0
  370. package/build/dist/Server/API/SecurityEventConnectionAPI.js.map +1 -0
  371. package/build/dist/Server/API/TelemetryAPI.js +248 -170
  372. package/build/dist/Server/API/TelemetryAPI.js.map +1 -1
  373. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1792700000000-AddSecurityEventConnections.js +40 -0
  374. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1792700000000-AddSecurityEventConnections.js.map +1 -0
  375. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +2 -0
  376. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  377. package/build/dist/Server/Middleware/TelemetryIngest.js +57 -4
  378. package/build/dist/Server/Middleware/TelemetryIngest.js.map +1 -1
  379. package/build/dist/Server/Services/ExceptionAggregationService.js +7 -16
  380. package/build/dist/Server/Services/ExceptionAggregationService.js.map +1 -1
  381. package/build/dist/Server/Services/GoogleSecOpsConnectionService.js +8 -0
  382. package/build/dist/Server/Services/GoogleSecOpsConnectionService.js.map +1 -1
  383. package/build/dist/Server/Services/Index.js +4 -0
  384. package/build/dist/Server/Services/Index.js.map +1 -1
  385. package/build/dist/Server/Services/InventoryItemService.js +22 -0
  386. package/build/dist/Server/Services/InventoryItemService.js.map +1 -1
  387. package/build/dist/Server/Services/LogAggregationService.js +8 -17
  388. package/build/dist/Server/Services/LogAggregationService.js.map +1 -1
  389. package/build/dist/Server/Services/MetricAggregationService.js +4 -14
  390. package/build/dist/Server/Services/MetricAggregationService.js.map +1 -1
  391. package/build/dist/Server/Services/SecurityEventConnectionRunService.js +9 -0
  392. package/build/dist/Server/Services/SecurityEventConnectionRunService.js.map +1 -0
  393. package/build/dist/Server/Services/SecurityEventConnectionService.js +356 -0
  394. package/build/dist/Server/Services/SecurityEventConnectionService.js.map +1 -0
  395. package/build/dist/Server/Services/TraceAggregationService.js +51 -25
  396. package/build/dist/Server/Services/TraceAggregationService.js.map +1 -1
  397. package/build/dist/Server/Types/AnalyticsDatabase/ModelPermission.js +9 -0
  398. package/build/dist/Server/Types/AnalyticsDatabase/ModelPermission.js.map +1 -1
  399. package/build/dist/Server/Utils/AI/Chat/ObservabilityAssistant.js +3 -0
  400. package/build/dist/Server/Utils/AI/Chat/ObservabilityAssistant.js.map +1 -1
  401. package/build/dist/Server/Utils/AI/SRE/AIInvestigationEngine.js +14 -7
  402. package/build/dist/Server/Utils/AI/SRE/AIInvestigationEngine.js.map +1 -1
  403. package/build/dist/Server/Utils/AI/SRE/InvestigationEvidence.js +468 -0
  404. package/build/dist/Server/Utils/AI/SRE/InvestigationEvidence.js.map +1 -0
  405. package/build/dist/Server/Utils/AI/SRE/InvestigationReferences.js +230 -0
  406. package/build/dist/Server/Utils/AI/SRE/InvestigationReferences.js.map +1 -0
  407. package/build/dist/Server/Utils/AI/Toolbox/Index.js +32 -0
  408. package/build/dist/Server/Utils/AI/Toolbox/Index.js.map +1 -1
  409. package/build/dist/Server/Utils/AI/Toolbox/TimelineTools.js +6 -2
  410. package/build/dist/Server/Utils/AI/Toolbox/TimelineTools.js.map +1 -1
  411. package/build/dist/Server/Utils/AnalyticsDatabase/StatementGenerator.js +59 -0
  412. package/build/dist/Server/Utils/AnalyticsDatabase/StatementGenerator.js.map +1 -1
  413. package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js +5 -3
  414. package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js.map +1 -1
  415. package/build/dist/Server/Utils/SecurityEvent/Connectors/AwsSecurityHub/AwsSecurityHubClient.js +752 -0
  416. package/build/dist/Server/Utils/SecurityEvent/Connectors/AwsSecurityHub/AwsSecurityHubClient.js.map +1 -0
  417. package/build/dist/Server/Utils/SecurityEvent/Connectors/AwsSecurityHub/AwsSecurityHubConnector.js +493 -0
  418. package/build/dist/Server/Utils/SecurityEvent/Connectors/AwsSecurityHub/AwsSecurityHubConnector.js.map +1 -0
  419. package/build/dist/Server/Utils/SecurityEvent/Connectors/ConnectorPlatformHealth.js +352 -0
  420. package/build/dist/Server/Utils/SecurityEvent/Connectors/ConnectorPlatformHealth.js.map +1 -0
  421. package/build/dist/Server/Utils/SecurityEvent/Connectors/CrowdStrikeFalcon/CrowdStrikeFalconClient.js +405 -0
  422. package/build/dist/Server/Utils/SecurityEvent/Connectors/CrowdStrikeFalcon/CrowdStrikeFalconClient.js.map +1 -0
  423. package/build/dist/Server/Utils/SecurityEvent/Connectors/CrowdStrikeFalcon/CrowdStrikeFalconConnector.js +466 -0
  424. package/build/dist/Server/Utils/SecurityEvent/Connectors/CrowdStrikeFalcon/CrowdStrikeFalconConnector.js.map +1 -0
  425. package/build/dist/Server/Utils/SecurityEvent/Connectors/ElasticSecurity/ElasticSecurityClient.js +344 -0
  426. package/build/dist/Server/Utils/SecurityEvent/Connectors/ElasticSecurity/ElasticSecurityClient.js.map +1 -0
  427. package/build/dist/Server/Utils/SecurityEvent/Connectors/ElasticSecurity/ElasticSecurityConnector.js +511 -0
  428. package/build/dist/Server/Utils/SecurityEvent/Connectors/ElasticSecurity/ElasticSecurityConnector.js.map +1 -0
  429. package/build/dist/Server/Utils/SecurityEvent/Connectors/MicrosoftDefenderXdr/MicrosoftDefenderXdrClient.js +406 -0
  430. package/build/dist/Server/Utils/SecurityEvent/Connectors/MicrosoftDefenderXdr/MicrosoftDefenderXdrClient.js.map +1 -0
  431. package/build/dist/Server/Utils/SecurityEvent/Connectors/MicrosoftDefenderXdr/MicrosoftDefenderXdrConnector.js +336 -0
  432. package/build/dist/Server/Utils/SecurityEvent/Connectors/MicrosoftDefenderXdr/MicrosoftDefenderXdrConnector.js.map +1 -0
  433. package/build/dist/Server/Utils/SecurityEvent/Connectors/MicrosoftSentinel/MicrosoftSentinelClient.js +474 -0
  434. package/build/dist/Server/Utils/SecurityEvent/Connectors/MicrosoftSentinel/MicrosoftSentinelClient.js.map +1 -0
  435. package/build/dist/Server/Utils/SecurityEvent/Connectors/MicrosoftSentinel/MicrosoftSentinelConnector.js +417 -0
  436. package/build/dist/Server/Utils/SecurityEvent/Connectors/MicrosoftSentinel/MicrosoftSentinelConnector.js.map +1 -0
  437. package/build/dist/Server/Utils/SecurityEvent/Connectors/Okta/OktaClient.js +314 -0
  438. package/build/dist/Server/Utils/SecurityEvent/Connectors/Okta/OktaClient.js.map +1 -0
  439. package/build/dist/Server/Utils/SecurityEvent/Connectors/Okta/OktaConnector.js +494 -0
  440. package/build/dist/Server/Utils/SecurityEvent/Connectors/Okta/OktaConnector.js.map +1 -0
  441. package/build/dist/Server/Utils/SecurityEvent/Connectors/SecurityEventConnectionPoller.js +719 -0
  442. package/build/dist/Server/Utils/SecurityEvent/Connectors/SecurityEventConnectionPoller.js.map +1 -0
  443. package/build/dist/Server/Utils/SecurityEvent/Connectors/SecurityEventConnectionRunExecutor.js +404 -0
  444. package/build/dist/Server/Utils/SecurityEvent/Connectors/SecurityEventConnectionRunExecutor.js.map +1 -0
  445. package/build/dist/Server/Utils/SecurityEvent/Connectors/SecurityEventConnectionTester.js +209 -0
  446. package/build/dist/Server/Utils/SecurityEvent/Connectors/SecurityEventConnectionTester.js.map +1 -0
  447. package/build/dist/Server/Utils/SecurityEvent/Connectors/SecurityEventConnectorRegistry.js +40 -0
  448. package/build/dist/Server/Utils/SecurityEvent/Connectors/SecurityEventConnectorRegistry.js.map +1 -0
  449. package/build/dist/Server/Utils/SecurityEvent/Connectors/Splunk/SplunkClient.js +494 -0
  450. package/build/dist/Server/Utils/SecurityEvent/Connectors/Splunk/SplunkClient.js.map +1 -0
  451. package/build/dist/Server/Utils/SecurityEvent/Connectors/Splunk/SplunkConnector.js +379 -0
  452. package/build/dist/Server/Utils/SecurityEvent/Connectors/Splunk/SplunkConnector.js.map +1 -0
  453. package/build/dist/Server/Utils/SecurityEvent/Connectors/Types.js +27 -0
  454. package/build/dist/Server/Utils/SecurityEvent/Connectors/Types.js.map +1 -0
  455. package/build/dist/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsClient.js +234 -61
  456. package/build/dist/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsClient.js.map +1 -1
  457. package/build/dist/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsConnectionTester.js +537 -0
  458. package/build/dist/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsConnectionTester.js.map +1 -0
  459. package/build/dist/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsPoller.js +572 -115
  460. package/build/dist/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsPoller.js.map +1 -1
  461. package/build/dist/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsRunExecutor.js +35 -1
  462. package/build/dist/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsRunExecutor.js.map +1 -1
  463. package/build/dist/Server/Utils/SecurityEvent/SecurityEventDedupe.js +52 -0
  464. package/build/dist/Server/Utils/SecurityEvent/SecurityEventDedupe.js.map +1 -0
  465. package/build/dist/Server/Utils/SessionReplay/SessionReplayReadService.js +521 -32
  466. package/build/dist/Server/Utils/SessionReplay/SessionReplayReadService.js.map +1 -1
  467. package/build/dist/Server/Utils/StartServer.js +10 -0
  468. package/build/dist/Server/Utils/StartServer.js.map +1 -1
  469. package/build/dist/Server/Utils/Telemetry/EntityRegistry.js +8 -0
  470. package/build/dist/Server/Utils/Telemetry/EntityRegistry.js.map +1 -1
  471. package/build/dist/Server/Utils/Telemetry/KubernetesResourceAttributes.js +80 -0
  472. package/build/dist/Server/Utils/Telemetry/KubernetesResourceAttributes.js.map +1 -0
  473. package/build/dist/Server/Utils/Telemetry/ResourceEntityFilter.js +122 -67
  474. package/build/dist/Server/Utils/Telemetry/ResourceEntityFilter.js.map +1 -1
  475. package/build/dist/Server/Utils/Telemetry/ResourceFacetPlanner.js +146 -0
  476. package/build/dist/Server/Utils/Telemetry/ResourceFacetPlanner.js.map +1 -0
  477. package/build/dist/Server/Utils/Telemetry/ResourceFacetResolver.js +174 -248
  478. package/build/dist/Server/Utils/Telemetry/ResourceFacetResolver.js.map +1 -1
  479. package/build/dist/Server/Utils/Telemetry/ServiceDependencyDiscovery.js +492 -0
  480. package/build/dist/Server/Utils/Telemetry/ServiceDependencyDiscovery.js.map +1 -0
  481. package/build/dist/Server/Utils/Telemetry/TraceContextPropagation.js +259 -0
  482. package/build/dist/Server/Utils/Telemetry/TraceContextPropagation.js.map +1 -0
  483. package/build/dist/Server/Utils/Telemetry.js +11 -5
  484. package/build/dist/Server/Utils/Telemetry.js.map +1 -1
  485. package/build/dist/Types/AI/InvestigationEvidence.js +2 -0
  486. package/build/dist/Types/AI/InvestigationEvidence.js.map +1 -0
  487. package/build/dist/Types/Permission.js +2 -2
  488. package/build/dist/Types/Permission.js.map +1 -1
  489. package/build/dist/Types/Rum/SessionReplay.js +95 -0
  490. package/build/dist/Types/Rum/SessionReplay.js.map +1 -1
  491. package/build/dist/Types/Rum/SessionReplayApi.js.map +1 -1
  492. package/build/dist/Types/SecurityEvent/Connectors/ConnectorDiagnostics.js +18 -0
  493. package/build/dist/Types/SecurityEvent/Connectors/ConnectorDiagnostics.js.map +1 -0
  494. package/build/dist/Types/SecurityEvent/Connectors/SecurityEventConnectionDiagnostics.js +2 -0
  495. package/build/dist/Types/SecurityEvent/Connectors/SecurityEventConnectionDiagnostics.js.map +1 -0
  496. package/build/dist/Types/SecurityEvent/Connectors/SecurityEventConnectorCatalog.js +374 -0
  497. package/build/dist/Types/SecurityEvent/Connectors/SecurityEventConnectorCatalog.js.map +1 -0
  498. package/build/dist/Types/SecurityEvent/Connectors/SecurityEventConnectorProvider.js +35 -0
  499. package/build/dist/Types/SecurityEvent/Connectors/SecurityEventConnectorProvider.js.map +1 -0
  500. package/build/dist/Types/SecurityEvent/GoogleSecOpsRegion.js +35 -0
  501. package/build/dist/Types/SecurityEvent/GoogleSecOpsRegion.js.map +1 -0
  502. package/build/dist/Types/Telemetry/EntityType.js +14 -0
  503. package/build/dist/Types/Telemetry/EntityType.js.map +1 -1
  504. package/build/dist/Types/Telemetry/ExceptionSpanScope.js +59 -0
  505. package/build/dist/Types/Telemetry/ExceptionSpanScope.js.map +1 -0
  506. package/build/dist/Types/Telemetry/LockedFilterDetail.js +16 -0
  507. package/build/dist/Types/Telemetry/LockedFilterDetail.js.map +1 -0
  508. package/build/dist/Types/Telemetry/ResourceEntityFacet.js +16 -10
  509. package/build/dist/Types/Telemetry/ResourceEntityFacet.js.map +1 -1
  510. package/build/dist/Types/Telemetry/ResourceFacetCatalog.js +119 -0
  511. package/build/dist/Types/Telemetry/ResourceFacetCatalog.js.map +1 -0
  512. package/build/dist/UI/Components/Card/Card.js +34 -17
  513. package/build/dist/UI/Components/Card/Card.js.map +1 -1
  514. package/build/dist/UI/Components/Checkbox/Checkbox.js +6 -4
  515. package/build/dist/UI/Components/Checkbox/Checkbox.js.map +1 -1
  516. package/build/dist/UI/Components/CopyTextButton/CopyTextButton.js +5 -1
  517. package/build/dist/UI/Components/CopyTextButton/CopyTextButton.js.map +1 -1
  518. package/build/dist/UI/Components/CustomFields/CustomFieldsDetail.js +1 -1
  519. package/build/dist/UI/Components/CustomFields/CustomFieldsDetail.js.map +1 -1
  520. package/build/dist/UI/Components/Detail/Detail.js +63 -13
  521. package/build/dist/UI/Components/Detail/Detail.js.map +1 -1
  522. package/build/dist/UI/Components/ErrorBoundary.js +34 -0
  523. package/build/dist/UI/Components/ErrorBoundary.js.map +1 -1
  524. package/build/dist/UI/Components/LogsViewer/LogsEntityNames.js +535 -0
  525. package/build/dist/UI/Components/LogsViewer/LogsEntityNames.js.map +1 -0
  526. package/build/dist/UI/Components/LogsViewer/LogsViewer.js +117 -57
  527. package/build/dist/UI/Components/LogsViewer/LogsViewer.js.map +1 -1
  528. package/build/dist/UI/Components/LogsViewer/components/ActiveFilterChips.js +5 -7
  529. package/build/dist/UI/Components/LogsViewer/components/ActiveFilterChips.js.map +1 -1
  530. package/build/dist/UI/Components/LogsViewer/components/FacetSection.js +31 -44
  531. package/build/dist/UI/Components/LogsViewer/components/FacetSection.js.map +1 -1
  532. package/build/dist/UI/Components/LogsViewer/components/FacetValueRow.js +17 -3
  533. package/build/dist/UI/Components/LogsViewer/components/FacetValueRow.js.map +1 -1
  534. package/build/dist/UI/Components/LogsViewer/components/LogDetailsPanel.js +19 -3
  535. package/build/dist/UI/Components/LogsViewer/components/LogDetailsPanel.js.map +1 -1
  536. package/build/dist/UI/Components/LogsViewer/components/LogsAnalyticsView.js +64 -18
  537. package/build/dist/UI/Components/LogsViewer/components/LogsAnalyticsView.js.map +1 -1
  538. package/build/dist/UI/Components/LogsViewer/components/LogsFacetSidebar.js +100 -41
  539. package/build/dist/UI/Components/LogsViewer/components/LogsFacetSidebar.js.map +1 -1
  540. package/build/dist/UI/Components/LogsViewer/components/LogsTable.js +13 -5
  541. package/build/dist/UI/Components/LogsViewer/components/LogsTable.js.map +1 -1
  542. package/build/dist/UI/Components/LogsViewer/types.js.map +1 -1
  543. package/build/dist/UI/Components/Markdown.tsx/InlineReferences.js +403 -0
  544. package/build/dist/UI/Components/Markdown.tsx/InlineReferences.js.map +1 -0
  545. package/build/dist/UI/Components/Markdown.tsx/MarkdownViewer.js +197 -179
  546. package/build/dist/UI/Components/Markdown.tsx/MarkdownViewer.js.map +1 -1
  547. package/build/dist/UI/Components/MemberRoleAssignment/MemberRoleAssignment.js +30 -21
  548. package/build/dist/UI/Components/MemberRoleAssignment/MemberRoleAssignment.js.map +1 -1
  549. package/build/dist/UI/Components/ModelDetail/CardModelDetail.js +12 -0
  550. package/build/dist/UI/Components/ModelDetail/CardModelDetail.js.map +1 -1
  551. package/build/dist/UI/Components/ModelDetail/ModelDetail.js +46 -12
  552. package/build/dist/UI/Components/ModelDetail/ModelDetail.js.map +1 -1
  553. package/build/dist/UI/Components/ModelList/ModelList.js +26 -7
  554. package/build/dist/UI/Components/ModelList/ModelList.js.map +1 -1
  555. package/build/dist/UI/Components/Page/ModelPage.js +62 -34
  556. package/build/dist/UI/Components/Page/ModelPage.js.map +1 -1
  557. package/build/dist/UI/Components/Table/Table.js +3 -1
  558. package/build/dist/UI/Components/Table/Table.js.map +1 -1
  559. package/build/dist/UI/Components/Table/TableRow.js +8 -1
  560. package/build/dist/UI/Components/Table/TableRow.js.map +1 -1
  561. package/build/dist/UI/Components/TelemetryViewer/FacetVisibility.js +111 -0
  562. package/build/dist/UI/Components/TelemetryViewer/FacetVisibility.js.map +1 -0
  563. package/build/dist/UI/Components/TelemetryViewer/ResourceFacetConfigs.js +22 -0
  564. package/build/dist/UI/Components/TelemetryViewer/ResourceFacetConfigs.js.map +1 -0
  565. package/build/dist/UI/Components/TelemetryViewer/TelemetryViewer.js +1 -1
  566. package/build/dist/UI/Components/TelemetryViewer/TelemetryViewer.js.map +1 -1
  567. package/build/dist/UI/Components/TelemetryViewer/components/FacetSearchInput.js +36 -0
  568. package/build/dist/UI/Components/TelemetryViewer/components/FacetSearchInput.js.map +1 -0
  569. package/build/dist/UI/Components/TelemetryViewer/components/FacetSectionHeader.js +21 -0
  570. package/build/dist/UI/Components/TelemetryViewer/components/FacetSectionHeader.js.map +1 -0
  571. package/build/dist/UI/Components/TelemetryViewer/components/FacetShowMoreButton.js +14 -0
  572. package/build/dist/UI/Components/TelemetryViewer/components/FacetShowMoreButton.js.map +1 -0
  573. package/build/dist/UI/Components/TelemetryViewer/components/HiddenFacetsFooter.js +27 -0
  574. package/build/dist/UI/Components/TelemetryViewer/components/HiddenFacetsFooter.js.map +1 -0
  575. package/build/dist/UI/Components/TelemetryViewer/components/LockedFilterActions.js +88 -0
  576. package/build/dist/UI/Components/TelemetryViewer/components/LockedFilterActions.js.map +1 -0
  577. package/build/dist/UI/Components/TelemetryViewer/components/LockedFilterChip.js +228 -0
  578. package/build/dist/UI/Components/TelemetryViewer/components/LockedFilterChip.js.map +1 -0
  579. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryActiveFilterChips.js +6 -6
  580. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryActiveFilterChips.js.map +1 -1
  581. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryDetailPanel.js +111 -12
  582. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryDetailPanel.js.map +1 -1
  583. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryFacetSection.js +27 -40
  584. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryFacetSection.js.map +1 -1
  585. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryFacetSidebar.js +70 -10
  586. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryFacetSidebar.js.map +1 -1
  587. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryFacetValueRow.js +17 -3
  588. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryFacetValueRow.js.map +1 -1
  589. package/build/dist/UI/Components/TelemetryViewer/types.js +0 -4
  590. package/build/dist/UI/Components/TelemetryViewer/types.js.map +1 -1
  591. package/build/dist/UI/Components/TelemetryViewer/useFacetSearchExemptions.js +70 -0
  592. package/build/dist/UI/Components/TelemetryViewer/useFacetSearchExemptions.js.map +1 -0
  593. package/build/dist/UI/Components/TelemetryViewer/useFacetSectionSearch.js +52 -0
  594. package/build/dist/UI/Components/TelemetryViewer/useFacetSectionSearch.js.map +1 -0
  595. package/build/dist/UI/Utils/Clipboard.js +59 -2
  596. package/build/dist/UI/Utils/Clipboard.js.map +1 -1
  597. package/build/dist/UI/Utils/Navigation.js +11 -2
  598. package/build/dist/UI/Utils/Navigation.js.map +1 -1
  599. package/build/dist/UI/Utils/Telemetry/TelemetryEntityNames.js +471 -0
  600. package/build/dist/UI/Utils/Telemetry/TelemetryEntityNames.js.map +1 -0
  601. package/build/dist/UI/Utils/Telemetry/UseTelemetryEntityNames.js +113 -0
  602. package/build/dist/UI/Utils/Telemetry/UseTelemetryEntityNames.js.map +1 -0
  603. package/build/dist/Utils/AI/InvestigationReport.js +1241 -0
  604. package/build/dist/Utils/AI/InvestigationReport.js.map +1 -0
  605. package/build/dist/Utils/API.js +25 -0
  606. package/build/dist/Utils/API.js.map +1 -1
  607. package/build/dist/Utils/Rum/SessionReplayHealth.js +10 -0
  608. package/build/dist/Utils/Rum/SessionReplayHealth.js.map +1 -1
  609. package/build/dist/Utils/Rum/SessionReplayRecordingEnded.js +54 -0
  610. package/build/dist/Utils/Rum/SessionReplayRecordingEnded.js.map +1 -0
  611. package/build/dist/Utils/SecurityEvent/Connectors/AwsSecurityHubNormalizer.js +311 -0
  612. package/build/dist/Utils/SecurityEvent/Connectors/AwsSecurityHubNormalizer.js.map +1 -0
  613. package/build/dist/Utils/SecurityEvent/Connectors/CrowdStrikeFalconNormalizer.js +150 -0
  614. package/build/dist/Utils/SecurityEvent/Connectors/CrowdStrikeFalconNormalizer.js.map +1 -0
  615. package/build/dist/Utils/SecurityEvent/Connectors/ElasticSecurityNormalizer.js +328 -0
  616. package/build/dist/Utils/SecurityEvent/Connectors/ElasticSecurityNormalizer.js.map +1 -0
  617. package/build/dist/Utils/SecurityEvent/Connectors/MicrosoftDefenderXdrNormalizer.js +405 -0
  618. package/build/dist/Utils/SecurityEvent/Connectors/MicrosoftDefenderXdrNormalizer.js.map +1 -0
  619. package/build/dist/Utils/SecurityEvent/Connectors/MicrosoftSentinelNormalizer.js +212 -0
  620. package/build/dist/Utils/SecurityEvent/Connectors/MicrosoftSentinelNormalizer.js.map +1 -0
  621. package/build/dist/Utils/SecurityEvent/Connectors/OktaNormalizer.js +351 -0
  622. package/build/dist/Utils/SecurityEvent/Connectors/OktaNormalizer.js.map +1 -0
  623. package/build/dist/Utils/SecurityEvent/Connectors/SplunkNormalizer.js +348 -0
  624. package/build/dist/Utils/SecurityEvent/Connectors/SplunkNormalizer.js.map +1 -0
  625. package/build/dist/Utils/SecurityEvent/GoogleSecOpsAlertNormalizer.js +103 -10
  626. package/build/dist/Utils/SecurityEvent/GoogleSecOpsAlertNormalizer.js.map +1 -1
  627. package/build/dist/Utils/Telemetry/CrossSignalScope.js +16 -5
  628. package/build/dist/Utils/Telemetry/CrossSignalScope.js.map +1 -1
  629. package/build/dist/Utils/Telemetry/EntityRelationship.js +7 -0
  630. package/build/dist/Utils/Telemetry/EntityRelationship.js.map +1 -1
  631. package/build/dist/Utils/Telemetry/LockedFilterSearch.js +277 -0
  632. package/build/dist/Utils/Telemetry/LockedFilterSearch.js.map +1 -0
  633. package/build/dist/Utils/Telemetry/NetworkHost.js +39 -0
  634. package/build/dist/Utils/Telemetry/NetworkHost.js.map +1 -0
  635. package/build/dist/Utils/Telemetry/OriginAllowList.js +105 -4
  636. package/build/dist/Utils/Telemetry/OriginAllowList.js.map +1 -1
  637. package/build/dist/Utils/Traces/CriticalPath.js +9 -4
  638. package/build/dist/Utils/Traces/CriticalPath.js.map +1 -1
  639. package/package.json +1 -1
  640. package/Tests/UI/Rum/RecordingHealthStrip.test.tsx +0 -600
  641. package/UI/Components/GanttChart/Bar/BarLabel.tsx +0 -17
  642. package/UI/Components/GanttChart/Bar/Index.tsx +0 -149
  643. package/UI/Components/GanttChart/ChartContainer.tsx +0 -50
  644. package/UI/Components/GanttChart/Index.tsx +0 -90
  645. package/UI/Components/GanttChart/Row/Index.tsx +0 -22
  646. package/UI/Components/GanttChart/Row/Row.tsx +0 -231
  647. package/UI/Components/GanttChart/Row/RowLabel.tsx +0 -30
  648. package/UI/Components/GanttChart/Rows.tsx +0 -59
  649. package/UI/Components/GanttChart/Timeline/Index.tsx +0 -46
  650. package/UI/Components/GanttChart/Timeline/TimelineInterval.tsx +0 -33
  651. package/UI/Components/GanttChart/Timeline/TimelineIntervalMarks.tsx +0 -43
  652. package/build/dist/UI/Components/GanttChart/Bar/BarLabel.js +0 -8
  653. package/build/dist/UI/Components/GanttChart/Bar/BarLabel.js.map +0 -1
  654. package/build/dist/UI/Components/GanttChart/Bar/Index.js +0 -77
  655. package/build/dist/UI/Components/GanttChart/Bar/Index.js.map +0 -1
  656. package/build/dist/UI/Components/GanttChart/ChartContainer.js +0 -33
  657. package/build/dist/UI/Components/GanttChart/ChartContainer.js.map +0 -1
  658. package/build/dist/UI/Components/GanttChart/Index.js +0 -39
  659. package/build/dist/UI/Components/GanttChart/Index.js.map +0 -1
  660. package/build/dist/UI/Components/GanttChart/Row/Index.js +0 -7
  661. package/build/dist/UI/Components/GanttChart/Row/Index.js.map +0 -1
  662. package/build/dist/UI/Components/GanttChart/Row/Row.js +0 -106
  663. package/build/dist/UI/Components/GanttChart/Row/Row.js.map +0 -1
  664. package/build/dist/UI/Components/GanttChart/Row/RowLabel.js +0 -10
  665. package/build/dist/UI/Components/GanttChart/Row/RowLabel.js.map +0 -1
  666. package/build/dist/UI/Components/GanttChart/Rows.js +0 -19
  667. package/build/dist/UI/Components/GanttChart/Rows.js.map +0 -1
  668. package/build/dist/UI/Components/GanttChart/Timeline/Index.js +0 -16
  669. package/build/dist/UI/Components/GanttChart/Timeline/Index.js.map +0 -1
  670. package/build/dist/UI/Components/GanttChart/Timeline/TimelineInterval.js +0 -13
  671. package/build/dist/UI/Components/GanttChart/Timeline/TimelineInterval.js.map +0 -1
  672. package/build/dist/UI/Components/GanttChart/Timeline/TimelineIntervalMarks.js +0 -13
  673. package/build/dist/UI/Components/GanttChart/Timeline/TimelineIntervalMarks.js.map +0 -1
@@ -0,0 +1,1233 @@
1
+ import SecurityEventConnection from "../../../Models/DatabaseModels/SecurityEventConnection";
2
+ import SecurityEventConnectionService, {
3
+ Service as SecurityEventConnectionServiceType,
4
+ } from "../../../Server/Services/SecurityEventConnectionService";
5
+ import CreateBy from "../../../Server/Types/Database/CreateBy";
6
+ import { OnCreate, OnUpdate } from "../../../Server/Types/Database/Hooks";
7
+ import UpdateBy from "../../../Server/Types/Database/UpdateBy";
8
+ import DataSourceEgressGuard from "../../../Server/Utils/DataSource/EgressGuard";
9
+ import SecurityEventConnectorRegistry from "../../../Server/Utils/SecurityEvent/Connectors/SecurityEventConnectorRegistry";
10
+ import {
11
+ SecurityConnectorSettings,
12
+ SecurityEventConnector,
13
+ } from "../../../Server/Utils/SecurityEvent/Connectors/Types";
14
+ import BadDataException from "../../../Types/Exception/BadDataException";
15
+ import { JSONObject } from "../../../Types/JSON";
16
+ import ObjectID from "../../../Types/ObjectID";
17
+ import SecurityEventConnectorProvider from "../../../Types/SecurityEvent/Connectors/SecurityEventConnectorProvider";
18
+ import {
19
+ ConnectorField,
20
+ SecurityEventConnectorDefinition,
21
+ getSecurityEventConnectorDefinition,
22
+ } from "../../../Types/SecurityEvent/Connectors/SecurityEventConnectorCatalog";
23
+ import { getJestSpyOn } from "../../Spy";
24
+ import {
25
+ afterEach,
26
+ beforeEach,
27
+ describe,
28
+ expect,
29
+ jest,
30
+ test,
31
+ } from "@jest/globals";
32
+
33
+ /*
34
+ * SecurityEventConnectionService validates at save time so a connection
35
+ * that stores is a connection the poller can use: a wrong key, a missing
36
+ * secret or a blocked URL surfaces to the person filling the form, not as
37
+ * a lastError on the cron an hour later. These tests drive the hooks and
38
+ * the static validators directly, the ThreatIntelFeedService discipline.
39
+ *
40
+ * The registry is mocked so validation never depends on a provider's own
41
+ * rules: what is pinned here is that the catalog rules run, that the
42
+ * provider's validateSettings is CALLED, and that tenant-chosen URLs go
43
+ * through the egress guard.
44
+ */
45
+
46
+ jest.mock(
47
+ "../../../Server/Utils/SecurityEvent/Connectors/SecurityEventConnectorRegistry",
48
+ () => {
49
+ return {
50
+ __esModule: true,
51
+ default: { getConnector: jest.fn() },
52
+ };
53
+ },
54
+ );
55
+
56
+ const PROJECT_ID: ObjectID = new ObjectID(
57
+ "11111111-1111-4111-8111-111111111111",
58
+ );
59
+ const CONNECTION_ID: ObjectID = new ObjectID(
60
+ "22222222-2222-4222-8222-222222222222",
61
+ );
62
+ const OKTA: SecurityEventConnectorDefinition =
63
+ getSecurityEventConnectorDefinition(
64
+ SecurityEventConnectorProvider.OktaSystemLog,
65
+ )!;
66
+ const SENTINEL: SecurityEventConnectorDefinition =
67
+ getSecurityEventConnectorDefinition(
68
+ SecurityEventConnectorProvider.MicrosoftSentinel,
69
+ )!;
70
+ const AWS: SecurityEventConnectorDefinition =
71
+ getSecurityEventConnectorDefinition(
72
+ SecurityEventConnectorProvider.AwsSecurityHub,
73
+ )!;
74
+ const SECRET_VALUE: string = "okta-api-token-3f2e1d";
75
+ const ROTATED_SECRET: string = "okta-api-token-rotated-9a8b";
76
+
77
+ type HookCaller = {
78
+ onBeforeCreate: (
79
+ createBy: CreateBy<SecurityEventConnection>,
80
+ ) => Promise<OnCreate<SecurityEventConnection>>;
81
+ onBeforeUpdate: (
82
+ updateBy: UpdateBy<SecurityEventConnection>,
83
+ ) => Promise<OnUpdate<SecurityEventConnection>>;
84
+ };
85
+
86
+ const service: HookCaller =
87
+ SecurityEventConnectionService as unknown as HookCaller;
88
+
89
+ /*
90
+ * A synthetic definition carrying every field type the catalog can
91
+ * express, so the number and toggle rules are exercised even though no
92
+ * shipped provider uses them yet.
93
+ */
94
+ const SYNTHETIC: SecurityEventConnectorDefinition = {
95
+ ...OKTA,
96
+ title: "Synthetic",
97
+ configFields: [
98
+ {
99
+ key: "endpoint",
100
+ title: "Endpoint",
101
+ description: "",
102
+ type: "url",
103
+ required: true,
104
+ },
105
+ {
106
+ key: "port",
107
+ title: "Port",
108
+ description: "",
109
+ type: "number",
110
+ required: false,
111
+ },
112
+ {
113
+ key: "verifyTls",
114
+ title: "Verify TLS",
115
+ description: "",
116
+ type: "toggle",
117
+ required: false,
118
+ },
119
+ {
120
+ key: "region",
121
+ title: "Region",
122
+ description: "",
123
+ type: "dropdown",
124
+ required: true,
125
+ options: [
126
+ { label: "US", value: "us" },
127
+ { label: "EU", value: "eu" },
128
+ ],
129
+ defaultValue: "us",
130
+ },
131
+ {
132
+ key: "label",
133
+ title: "Label",
134
+ description: "",
135
+ type: "text",
136
+ required: false,
137
+ },
138
+ ],
139
+ secretFields: [
140
+ {
141
+ key: "token",
142
+ title: "Token",
143
+ description: "",
144
+ type: "password",
145
+ required: true,
146
+ },
147
+ ],
148
+ };
149
+
150
+ function validateConfig(
151
+ values: JSONObject,
152
+ definition: SecurityEventConnectorDefinition = SYNTHETIC,
153
+ requireRequiredFields: boolean = true,
154
+ ): void {
155
+ SecurityEventConnectionServiceType.validateFields({
156
+ definition,
157
+ fields: definition.configFields,
158
+ values,
159
+ label: "Configuration",
160
+ requireRequiredFields,
161
+ });
162
+ }
163
+
164
+ function validConfig(overrides: JSONObject = {}): JSONObject {
165
+ return { endpoint: "https://example.com", region: "us", ...overrides };
166
+ }
167
+
168
+ let connectorValidateCalls: Array<SecurityConnectorSettings>;
169
+ let connectorValidateError: Error | undefined;
170
+
171
+ function fakeConnector(
172
+ provider: SecurityEventConnectorProvider,
173
+ ): SecurityEventConnector {
174
+ return {
175
+ provider,
176
+ validateSettings: (settings: SecurityConnectorSettings): void => {
177
+ connectorValidateCalls.push(settings);
178
+ if (connectorValidateError) {
179
+ throw connectorValidateError;
180
+ }
181
+ },
182
+ testConnection: (): Promise<never> => {
183
+ return Promise.reject(new Error("not used"));
184
+ },
185
+ fetchEvents: (): Promise<never> => {
186
+ return Promise.reject(new Error("not used"));
187
+ },
188
+ };
189
+ }
190
+
191
+ function buildConnection(
192
+ overrides: Partial<SecurityEventConnection> = {},
193
+ ): SecurityEventConnection {
194
+ const connection: SecurityEventConnection = new SecurityEventConnection();
195
+ connection.projectId = PROJECT_ID;
196
+ connection.name = "Okta";
197
+ connection.provider = SecurityEventConnectorProvider.OktaSystemLog;
198
+ connection.config = { orgUrl: "https://acme.okta.com" };
199
+ connection.secrets = JSON.stringify({ apiToken: SECRET_VALUE });
200
+ Object.assign(connection, overrides);
201
+ return connection;
202
+ }
203
+
204
+ function createBy(
205
+ connection: SecurityEventConnection,
206
+ ): CreateBy<SecurityEventConnection> {
207
+ return {
208
+ data: connection,
209
+ props: { isRoot: true },
210
+ } as CreateBy<SecurityEventConnection>;
211
+ }
212
+
213
+ function updateBy(
214
+ data: JSONObject,
215
+ query: JSONObject = { _id: CONNECTION_ID.toString() },
216
+ ): UpdateBy<SecurityEventConnection> {
217
+ return {
218
+ query,
219
+ data,
220
+ props: { isRoot: true },
221
+ } as unknown as UpdateBy<SecurityEventConnection>;
222
+ }
223
+
224
+ function storedConnection(
225
+ overrides: Partial<SecurityEventConnection> = {},
226
+ ): SecurityEventConnection {
227
+ const connection: SecurityEventConnection = new SecurityEventConnection();
228
+ connection._id = CONNECTION_ID.toString();
229
+ connection.provider = SecurityEventConnectorProvider.OktaSystemLog;
230
+ connection.config = { orgUrl: "https://acme.okta.com", filter: "" };
231
+ connection.secrets = JSON.stringify({ apiToken: SECRET_VALUE });
232
+ connection.alertingOnly = true;
233
+ Object.assign(connection, overrides);
234
+ return connection;
235
+ }
236
+
237
+ beforeEach(() => {
238
+ connectorValidateCalls = [];
239
+ connectorValidateError = undefined;
240
+ (
241
+ SecurityEventConnectorRegistry.getConnector as unknown as jest.Mock
242
+ ).mockImplementation(((provider: SecurityEventConnectorProvider) => {
243
+ return fakeConnector(provider);
244
+ }) as never);
245
+ getJestSpyOn(DataSourceEgressGuard, "assertUrlAllowed").mockResolvedValue({
246
+ url: new URL("https://acme.okta.com"),
247
+ addresses: [],
248
+ } as never);
249
+ });
250
+
251
+ afterEach(() => {
252
+ jest.restoreAllMocks();
253
+ (
254
+ SecurityEventConnectorRegistry.getConnector as unknown as jest.Mock
255
+ ).mockReset();
256
+ });
257
+
258
+ describe("SecurityEventConnectionService.parseJsonObject", () => {
259
+ test.each([undefined, null, ""])(
260
+ "%j is an empty object",
261
+ (value: unknown) => {
262
+ expect(
263
+ SecurityEventConnectionServiceType.parseJsonObject(
264
+ value,
265
+ "Configuration",
266
+ ),
267
+ ).toEqual({});
268
+ },
269
+ );
270
+
271
+ test("an object is returned as is and a JSON string is parsed", () => {
272
+ const object: JSONObject = { orgUrl: "https://acme.okta.com" };
273
+ expect(
274
+ SecurityEventConnectionServiceType.parseJsonObject(
275
+ object,
276
+ "Configuration",
277
+ ),
278
+ ).toBe(object);
279
+ expect(
280
+ SecurityEventConnectionServiceType.parseJsonObject(
281
+ JSON.stringify(object),
282
+ "Configuration",
283
+ ),
284
+ ).toEqual(object);
285
+ });
286
+
287
+ test.each(["not json", "[1,2]", "42", '"text"', 42, true, [1]])(
288
+ "%j is rejected with the field name",
289
+ (value: unknown) => {
290
+ expect(() => {
291
+ SecurityEventConnectionServiceType.parseJsonObject(
292
+ value,
293
+ "Credentials",
294
+ );
295
+ }).toThrow(BadDataException);
296
+ expect(() => {
297
+ SecurityEventConnectionServiceType.parseJsonObject(
298
+ value,
299
+ "Credentials",
300
+ );
301
+ }).toThrow("Credentials must be a JSON object.");
302
+ },
303
+ );
304
+ });
305
+
306
+ describe("SecurityEventConnectionService.validateFields", () => {
307
+ test("a valid configuration passes", () => {
308
+ expect(() => {
309
+ validateConfig(
310
+ validConfig({ port: 8089, verifyTls: true, label: "prod" }),
311
+ );
312
+ }).not.toThrow();
313
+ });
314
+
315
+ test("an unknown key is rejected rather than stored", () => {
316
+ expect(() => {
317
+ validateConfig(validConfig({ orgUrI: "typo" }));
318
+ }).toThrow(
319
+ 'Configuration contains an unknown setting "orgUrI" for Synthetic.',
320
+ );
321
+ });
322
+
323
+ test.each([{ nested: true }, [1, 2]])(
324
+ "a value that is not a string, number or boolean (%j) is rejected",
325
+ (value: unknown) => {
326
+ expect(() => {
327
+ validateConfig(validConfig({ label: value as never }));
328
+ }).toThrow(
329
+ 'Configuration setting "label" must be a string, number or boolean.',
330
+ );
331
+ },
332
+ );
333
+
334
+ test.each([undefined, null, "", " "])(
335
+ "a required field left as %j is rejected when required fields are enforced",
336
+ (value: unknown) => {
337
+ expect(() => {
338
+ validateConfig(validConfig({ endpoint: value as never }));
339
+ }).toThrow("Endpoint is required for Synthetic.");
340
+ },
341
+ );
342
+
343
+ test("required fields are not enforced when the caller says so (update merges)", () => {
344
+ expect(() => {
345
+ validateConfig({ region: "eu" }, SYNTHETIC, false);
346
+ }).not.toThrow();
347
+ });
348
+
349
+ test("an optional field left empty is fine and skips type checks", () => {
350
+ expect(() => {
351
+ validateConfig(validConfig({ port: "", verifyTls: null }));
352
+ }).not.toThrow();
353
+ });
354
+
355
+ test("a dropdown value outside its options is rejected with the allowed list", () => {
356
+ expect(() => {
357
+ validateConfig(validConfig({ region: "apac" }));
358
+ }).toThrow("Region must be one of: us, eu.");
359
+ });
360
+
361
+ test.each(["8089", 8089, 0])(
362
+ "a numeric field accepts %j",
363
+ (value: unknown) => {
364
+ expect(() => {
365
+ validateConfig(validConfig({ port: value as never }));
366
+ }).not.toThrow();
367
+ },
368
+ );
369
+
370
+ /*
371
+ * Number(true) is 1, so a boolean slips through the numeric rule today;
372
+ * only the string and non-finite cases are pinned here.
373
+ */
374
+ test.each(["eighty", "NaN", "Infinity"])(
375
+ "a numeric field rejects %j",
376
+ (value: unknown) => {
377
+ expect(() => {
378
+ validateConfig(validConfig({ port: value as never }));
379
+ }).toThrow("Port must be a number.");
380
+ },
381
+ );
382
+
383
+ test.each(["true", 1, "yes"])(
384
+ "a toggle rejects the non-boolean %j",
385
+ (value: unknown) => {
386
+ expect(() => {
387
+ validateConfig(validConfig({ verifyTls: value as never }));
388
+ }).toThrow("Verify TLS must be true or false.");
389
+ },
390
+ );
391
+
392
+ test.each(["example.com", "not a url", "/relative"])(
393
+ "a url field rejects %j",
394
+ (value: string) => {
395
+ expect(() => {
396
+ validateConfig(validConfig({ endpoint: value }));
397
+ }).toThrow("Endpoint must be an absolute https URL.");
398
+ },
399
+ );
400
+
401
+ test.each(["ftp://example.com", "file:///etc/passwd", "javascript:alert(1)"])(
402
+ "a url field rejects the non-http scheme %s",
403
+ (value: string) => {
404
+ expect(() => {
405
+ validateConfig(validConfig({ endpoint: value }));
406
+ }).toThrow("Endpoint must be an http or https URL.");
407
+ },
408
+ );
409
+
410
+ test.each([
411
+ "https://user:pass@example.com",
412
+ "https://user@example.com",
413
+ "https://:pass@example.com",
414
+ ])("a url field refuses credentials embedded in %s", (value: string) => {
415
+ expect(() => {
416
+ validateConfig(validConfig({ endpoint: value }));
417
+ }).toThrow("Endpoint must not embed credentials in the URL.");
418
+ });
419
+
420
+ test("http is accepted (the egress guard decides the host, not the scheme)", () => {
421
+ expect(() => {
422
+ validateConfig(validConfig({ endpoint: "http://splunk.internal:8089" }));
423
+ }).not.toThrow();
424
+ });
425
+
426
+ test("the real catalog rules apply: a Sentinel cloud outside the dropdown is rejected", () => {
427
+ expect(() => {
428
+ SecurityEventConnectionServiceType.validateFields({
429
+ definition: SENTINEL,
430
+ fields: SENTINEL.configFields,
431
+ values: {
432
+ tenantId: "t",
433
+ clientId: "c",
434
+ subscriptionId: "s",
435
+ resourceGroup: "rg",
436
+ workspaceName: "ws",
437
+ cloud: "china",
438
+ },
439
+ label: "Configuration",
440
+ requireRequiredFields: true,
441
+ });
442
+ }).toThrow("Cloud must be one of: public, usgov.");
443
+ });
444
+
445
+ test("secrets are validated against the secret fields with their own label", () => {
446
+ expect(() => {
447
+ SecurityEventConnectionServiceType.validateFields({
448
+ definition: OKTA,
449
+ fields: OKTA.secretFields,
450
+ values: { apiToken: SECRET_VALUE, password: "x" },
451
+ label: "Credentials",
452
+ requireRequiredFields: true,
453
+ });
454
+ }).toThrow(
455
+ `Credentials contains an unknown setting "password" for ${OKTA.title}.`,
456
+ );
457
+ });
458
+ });
459
+
460
+ describe("SecurityEventConnectionService.mergeSecrets", () => {
461
+ /*
462
+ * The one rule both a save and the /test overlay apply (review finding
463
+ * optional-secret-cannot-be-cleared): a value replaces, "" or undefined
464
+ * keeps, null removes.
465
+ */
466
+ const STORED: JSONObject = {
467
+ secretAccessKey: SECRET_VALUE,
468
+ sessionToken: "session-1",
469
+ };
470
+
471
+ test("a value replaces the stored key and untouched keys stay", () => {
472
+ expect(
473
+ SecurityEventConnectionServiceType.mergeSecrets({
474
+ definition: AWS,
475
+ stored: STORED,
476
+ provided: { secretAccessKey: ROTATED_SECRET },
477
+ }),
478
+ ).toEqual({ secretAccessKey: ROTATED_SECRET, sessionToken: "session-1" });
479
+ });
480
+
481
+ test.each(["", undefined])("%j keeps the stored value", (blank: unknown) => {
482
+ expect(
483
+ SecurityEventConnectionServiceType.mergeSecrets({
484
+ definition: AWS,
485
+ stored: STORED,
486
+ provided: { sessionToken: blank as never },
487
+ }),
488
+ ).toEqual(STORED);
489
+ });
490
+
491
+ test("null removes the stored key", () => {
492
+ const merged: JSONObject = SecurityEventConnectionServiceType.mergeSecrets({
493
+ definition: AWS,
494
+ stored: STORED,
495
+ provided: { sessionToken: null },
496
+ });
497
+
498
+ expect(merged).toEqual({ secretAccessKey: SECRET_VALUE });
499
+ expect(merged).not.toHaveProperty("sessionToken");
500
+ });
501
+
502
+ test("null for a known credential that is not stored is a harmless no-op", () => {
503
+ expect(
504
+ SecurityEventConnectionServiceType.mergeSecrets({
505
+ definition: AWS,
506
+ stored: { secretAccessKey: SECRET_VALUE },
507
+ provided: { sessionToken: null },
508
+ }),
509
+ ).toEqual({ secretAccessKey: SECRET_VALUE });
510
+ });
511
+
512
+ test("never mutates the stored object it was given", () => {
513
+ const stored: JSONObject = { ...STORED };
514
+
515
+ SecurityEventConnectionServiceType.mergeSecrets({
516
+ definition: AWS,
517
+ stored,
518
+ provided: { sessionToken: null, secretAccessKey: ROTATED_SECRET },
519
+ });
520
+
521
+ expect(stored).toEqual(STORED);
522
+ });
523
+
524
+ test("null naming a key that is neither a credential nor stored is refused as a typo", () => {
525
+ expect(() => {
526
+ SecurityEventConnectionServiceType.mergeSecrets({
527
+ definition: AWS,
528
+ stored: STORED,
529
+ provided: { sesionToken: null },
530
+ });
531
+ }).toThrow(
532
+ `Credentials contains an unknown setting "sesionToken" for ${AWS.title}.`,
533
+ );
534
+ });
535
+
536
+ test("null may remove a stored key the catalog no longer knows, so the row can be repaired", () => {
537
+ expect(
538
+ SecurityEventConnectionServiceType.mergeSecrets({
539
+ definition: OKTA,
540
+ stored: { apiToken: SECRET_VALUE, retiredKey: "old" },
541
+ provided: { retiredKey: null },
542
+ }),
543
+ ).toEqual({ apiToken: SECRET_VALUE });
544
+ });
545
+ });
546
+
547
+ describe("SecurityEventConnectionService.getDefinitionOrThrow", () => {
548
+ test.each([undefined, null, "", "google-secops", "OKTA", 42])(
549
+ "rejects %j",
550
+ (provider: unknown) => {
551
+ expect(() => {
552
+ SecurityEventConnectionServiceType.getDefinitionOrThrow(provider);
553
+ }).toThrow(
554
+ "Provider must be one of the supported security event connectors.",
555
+ );
556
+ },
557
+ );
558
+
559
+ test("returns the catalog definition for a known provider", () => {
560
+ expect(
561
+ SecurityEventConnectionServiceType.getDefinitionOrThrow("okta"),
562
+ ).toBe(OKTA);
563
+ });
564
+ });
565
+
566
+ describe("SecurityEventConnectionService.validateSettings", () => {
567
+ test("runs catalog rules, then the provider's validateSettings, then the egress guard on url fields", async () => {
568
+ const settings: SecurityConnectorSettings =
569
+ await SecurityEventConnectionServiceType.validateSettings({
570
+ provider: "okta",
571
+ config: { orgUrl: " https://acme.okta.com " },
572
+ secrets: { apiToken: SECRET_VALUE },
573
+ alertingOnly: false,
574
+ requireRequiredSecrets: true,
575
+ });
576
+
577
+ expect(settings).toEqual({
578
+ provider: SecurityEventConnectorProvider.OktaSystemLog,
579
+ config: { orgUrl: " https://acme.okta.com " },
580
+ secrets: { apiToken: SECRET_VALUE },
581
+ alertingOnly: false,
582
+ });
583
+ expect(SecurityEventConnectorRegistry.getConnector).toHaveBeenCalledWith(
584
+ SecurityEventConnectorProvider.OktaSystemLog,
585
+ );
586
+ expect(connectorValidateCalls).toEqual([settings]);
587
+ expect(DataSourceEgressGuard.assertUrlAllowed).toHaveBeenCalledTimes(1);
588
+ expect(DataSourceEgressGuard.assertUrlAllowed).toHaveBeenCalledWith(
589
+ "https://acme.okta.com",
590
+ );
591
+ });
592
+
593
+ test("providers without url fields never consult the egress guard", async () => {
594
+ await SecurityEventConnectionServiceType.validateSettings({
595
+ provider: "microsoft-sentinel",
596
+ config: {
597
+ tenantId: "t",
598
+ clientId: "c",
599
+ subscriptionId: "s",
600
+ resourceGroup: "rg",
601
+ workspaceName: "ws",
602
+ cloud: "usgov",
603
+ },
604
+ secrets: { clientSecret: "s3cret" },
605
+ alertingOnly: true,
606
+ requireRequiredSecrets: true,
607
+ });
608
+
609
+ expect(DataSourceEgressGuard.assertUrlAllowed).not.toHaveBeenCalled();
610
+ expect(connectorValidateCalls).toHaveLength(1);
611
+ });
612
+
613
+ test("an unknown provider fails before the registry or the guard are touched", async () => {
614
+ await expect(
615
+ SecurityEventConnectionServiceType.validateSettings({
616
+ provider: "google-secops",
617
+ config: {},
618
+ secrets: {},
619
+ alertingOnly: true,
620
+ requireRequiredSecrets: true,
621
+ }),
622
+ ).rejects.toThrow("Provider must be one of the supported");
623
+ expect(SecurityEventConnectorRegistry.getConnector).not.toHaveBeenCalled();
624
+ expect(DataSourceEgressGuard.assertUrlAllowed).not.toHaveBeenCalled();
625
+ });
626
+
627
+ test("a missing required secret is rejected before the provider sees anything", async () => {
628
+ await expect(
629
+ SecurityEventConnectionServiceType.validateSettings({
630
+ provider: "okta",
631
+ config: { orgUrl: "https://acme.okta.com" },
632
+ secrets: {},
633
+ alertingOnly: true,
634
+ requireRequiredSecrets: true,
635
+ }),
636
+ ).rejects.toThrow(`API token is required for ${OKTA.title}.`);
637
+ expect(connectorValidateCalls).toHaveLength(0);
638
+ });
639
+
640
+ test("required secrets may be skipped (a form test with stored secrets) but unknown ones still fail", async () => {
641
+ await expect(
642
+ SecurityEventConnectionServiceType.validateSettings({
643
+ provider: "okta",
644
+ config: { orgUrl: "https://acme.okta.com" },
645
+ secrets: {},
646
+ alertingOnly: true,
647
+ requireRequiredSecrets: false,
648
+ }),
649
+ ).resolves.toBeDefined();
650
+
651
+ await expect(
652
+ SecurityEventConnectionServiceType.validateSettings({
653
+ provider: "okta",
654
+ config: { orgUrl: "https://acme.okta.com" },
655
+ secrets: { sessionToken: "x" },
656
+ alertingOnly: true,
657
+ requireRequiredSecrets: false,
658
+ }),
659
+ ).rejects.toThrow('unknown setting "sessionToken"');
660
+ });
661
+
662
+ test("the provider's own validation error propagates untouched", async () => {
663
+ connectorValidateError = new BadDataException(
664
+ "Okta organization URL must end with .okta.com or .oktapreview.com.",
665
+ );
666
+
667
+ await expect(
668
+ SecurityEventConnectionServiceType.validateSettings({
669
+ provider: "okta",
670
+ config: { orgUrl: "https://acme.example.com" },
671
+ secrets: { apiToken: SECRET_VALUE },
672
+ alertingOnly: true,
673
+ requireRequiredSecrets: true,
674
+ }),
675
+ ).rejects.toThrow("Okta organization URL must end with");
676
+ expect(DataSourceEgressGuard.assertUrlAllowed).not.toHaveBeenCalled();
677
+ });
678
+
679
+ test("a blocked host fails validation with the guard's own message", async () => {
680
+ getJestSpyOn(DataSourceEgressGuard, "assertUrlAllowed").mockRejectedValue(
681
+ new BadDataException(
682
+ "Data source URL resolves to a private address and is not allowed.",
683
+ ) as never,
684
+ );
685
+
686
+ await expect(
687
+ SecurityEventConnectionServiceType.validateSettings({
688
+ provider: "okta",
689
+ config: { orgUrl: "https://10.0.0.5" },
690
+ secrets: { apiToken: SECRET_VALUE },
691
+ alertingOnly: true,
692
+ requireRequiredSecrets: true,
693
+ }),
694
+ ).rejects.toThrow("private address");
695
+ });
696
+ });
697
+
698
+ describe("SecurityEventConnectionService.onBeforeCreate", () => {
699
+ test("stores the config as an object, the secrets as a JSON string, and the catalog's default interval", async () => {
700
+ const connection: SecurityEventConnection = buildConnection({
701
+ config: JSON.stringify({ orgUrl: "https://acme.okta.com" }) as never,
702
+ secrets: { apiToken: SECRET_VALUE } as never,
703
+ });
704
+
705
+ const result: OnCreate<SecurityEventConnection> =
706
+ await service.onBeforeCreate(createBy(connection));
707
+
708
+ expect(result.createBy.data.config).toEqual({
709
+ orgUrl: "https://acme.okta.com",
710
+ });
711
+ expect(typeof result.createBy.data.secrets).toBe("string");
712
+ expect(JSON.parse(result.createBy.data.secrets as string)).toEqual({
713
+ apiToken: SECRET_VALUE,
714
+ });
715
+ expect(result.createBy.data.pollIntervalInMinutes).toBe(
716
+ OKTA.defaultPollIntervalInMinutes,
717
+ );
718
+ expect(connectorValidateCalls).toEqual([
719
+ {
720
+ provider: SecurityEventConnectorProvider.OktaSystemLog,
721
+ config: { orgUrl: "https://acme.okta.com" },
722
+ secrets: { apiToken: SECRET_VALUE },
723
+ alertingOnly: true,
724
+ },
725
+ ]);
726
+ expect(DataSourceEgressGuard.assertUrlAllowed).toHaveBeenCalledWith(
727
+ "https://acme.okta.com",
728
+ );
729
+ });
730
+
731
+ test("an explicit poll interval and alertingOnly=false are kept", async () => {
732
+ const result: OnCreate<SecurityEventConnection> =
733
+ await service.onBeforeCreate(
734
+ createBy(
735
+ buildConnection({ pollIntervalInMinutes: 15, alertingOnly: false }),
736
+ ),
737
+ );
738
+
739
+ expect(result.createBy.data.pollIntervalInMinutes).toBe(15);
740
+ expect(connectorValidateCalls[0]!.alertingOnly).toBe(false);
741
+ });
742
+
743
+ test.each([0, 1441, 2.5, -1, "5"])(
744
+ "rejects the poll interval %j",
745
+ async (interval: unknown) => {
746
+ await expect(
747
+ service.onBeforeCreate(
748
+ createBy(
749
+ buildConnection({ pollIntervalInMinutes: interval as never }),
750
+ ),
751
+ ),
752
+ ).rejects.toThrow(
753
+ "Poll interval must be a whole number of minutes between 1 and 1440.",
754
+ );
755
+ },
756
+ );
757
+
758
+ test.each([1, 1440])(
759
+ "accepts the boundary interval %j",
760
+ async (interval: number) => {
761
+ await expect(
762
+ service.onBeforeCreate(
763
+ createBy(buildConnection({ pollIntervalInMinutes: interval })),
764
+ ),
765
+ ).resolves.toBeDefined();
766
+ },
767
+ );
768
+
769
+ test.each(["true", 1])(
770
+ "rejects a non-boolean alertingOnly %j",
771
+ async (value: unknown) => {
772
+ await expect(
773
+ service.onBeforeCreate(
774
+ createBy(buildConnection({ alertingOnly: value as never })),
775
+ ),
776
+ ).rejects.toThrow("Alerting records only must be true or false.");
777
+ },
778
+ );
779
+
780
+ test("rejects an unsupported provider", async () => {
781
+ await expect(
782
+ service.onBeforeCreate(
783
+ createBy(
784
+ buildConnection({
785
+ provider: "google-secops" as SecurityEventConnectorProvider,
786
+ }),
787
+ ),
788
+ ),
789
+ ).rejects.toThrow("Provider must be one of the supported");
790
+ expect(connectorValidateCalls).toHaveLength(0);
791
+ });
792
+
793
+ test("requires every required secret on create", async () => {
794
+ await expect(
795
+ service.onBeforeCreate(createBy(buildConnection({ secrets: "{}" }))),
796
+ ).rejects.toThrow(`API token is required for ${OKTA.title}.`);
797
+ });
798
+
799
+ test("requires every required config field on create", async () => {
800
+ await expect(
801
+ service.onBeforeCreate(createBy(buildConnection({ config: {} }))),
802
+ ).rejects.toThrow(`Okta organization URL is required for ${OKTA.title}.`);
803
+ });
804
+
805
+ test("rejects unparseable config and secrets", async () => {
806
+ await expect(
807
+ service.onBeforeCreate(
808
+ createBy(buildConnection({ config: "nope" as never })),
809
+ ),
810
+ ).rejects.toThrow("Configuration must be a JSON object.");
811
+ await expect(
812
+ service.onBeforeCreate(createBy(buildConnection({ secrets: "nope" }))),
813
+ ).rejects.toThrow("Credentials must be a JSON object.");
814
+ });
815
+ });
816
+
817
+ describe("SecurityEventConnectionService.onBeforeUpdate", () => {
818
+ let findOneById: ReturnType<typeof getJestSpyOn>;
819
+
820
+ beforeEach(() => {
821
+ findOneById = getJestSpyOn(
822
+ SecurityEventConnectionService,
823
+ "findOneById",
824
+ ).mockResolvedValue(storedConnection() as never);
825
+ });
826
+
827
+ test("the provider of a connection cannot be changed", async () => {
828
+ await expect(
829
+ service.onBeforeUpdate(updateBy({ provider: "splunk" })),
830
+ ).rejects.toThrow("The provider of a connection cannot be changed.");
831
+ expect(findOneById).not.toHaveBeenCalled();
832
+ });
833
+
834
+ test("an update that touches neither config nor secrets is passed through without a read", async () => {
835
+ const result: OnUpdate<SecurityEventConnection> =
836
+ await service.onBeforeUpdate(
837
+ updateBy(
838
+ { name: "renamed", pollIntervalInMinutes: 10 },
839
+ {
840
+ projectId: PROJECT_ID.toString(),
841
+ },
842
+ ),
843
+ );
844
+
845
+ expect(result.updateBy.data).toEqual({
846
+ name: "renamed",
847
+ pollIntervalInMinutes: 10,
848
+ });
849
+ expect(findOneById).not.toHaveBeenCalled();
850
+ expect(connectorValidateCalls).toHaveLength(0);
851
+ });
852
+
853
+ test.each([0, 1441, 1.5])(
854
+ "still validates the poll interval %j on a plain update",
855
+ async (interval: unknown) => {
856
+ await expect(
857
+ service.onBeforeUpdate(
858
+ updateBy({ pollIntervalInMinutes: interval as never }),
859
+ ),
860
+ ).rejects.toThrow("Poll interval must be a whole number");
861
+ },
862
+ );
863
+
864
+ test("still validates alertingOnly on a plain update", async () => {
865
+ await expect(
866
+ service.onBeforeUpdate(updateBy({ alertingOnly: "yes" })),
867
+ ).rejects.toThrow("Alerting records only must be true or false.");
868
+ });
869
+
870
+ test.each<[string, JSONObject]>([
871
+ ["no _id", { projectId: PROJECT_ID.toString() }],
872
+ ["a malformed _id", { _id: "not-a-uuid" }],
873
+ ["a list of ids", { _id: [CONNECTION_ID.toString()] }],
874
+ ])(
875
+ "settings can only be updated one connection at a time (%s)",
876
+ async (_label: string, query: JSONObject) => {
877
+ await expect(
878
+ service.onBeforeUpdate(
879
+ updateBy({ secrets: { apiToken: ROTATED_SECRET } }, query),
880
+ ),
881
+ ).rejects.toThrow(
882
+ "Configuration and credentials can only be updated one connection at a time.",
883
+ );
884
+ expect(findOneById).not.toHaveBeenCalled();
885
+ },
886
+ );
887
+
888
+ test.each<[string, unknown]>([
889
+ ["a string", CONNECTION_ID.toString()],
890
+ ["an ObjectID", CONNECTION_ID],
891
+ ])(
892
+ "accepts the connection id as %s and reads the stored row as root",
893
+ async (_label: string, id: unknown) => {
894
+ await service.onBeforeUpdate(
895
+ updateBy(
896
+ { secrets: { apiToken: ROTATED_SECRET } },
897
+ { _id: id as never },
898
+ ),
899
+ );
900
+
901
+ expect(findOneById).toHaveBeenCalledWith({
902
+ id: CONNECTION_ID,
903
+ select: {
904
+ _id: true,
905
+ provider: true,
906
+ config: true,
907
+ secrets: true,
908
+ alertingOnly: true,
909
+ },
910
+ props: { isRoot: true },
911
+ });
912
+ },
913
+ );
914
+
915
+ test("a rotated secret replaces the stored one; other stored keys stay", async () => {
916
+ findOneById.mockResolvedValue(
917
+ storedConnection({
918
+ provider: SecurityEventConnectorProvider.AwsSecurityHub,
919
+ config: { region: "us-east-1", accessKeyId: "AKIA1" },
920
+ secrets: JSON.stringify({
921
+ secretAccessKey: SECRET_VALUE,
922
+ sessionToken: "session-1",
923
+ }),
924
+ }) as never,
925
+ );
926
+
927
+ const result: OnUpdate<SecurityEventConnection> =
928
+ await service.onBeforeUpdate(
929
+ updateBy({ secrets: { secretAccessKey: ROTATED_SECRET } }),
930
+ );
931
+
932
+ const stored: JSONObject = result.updateBy.data as unknown as JSONObject;
933
+ expect(typeof stored["secrets"]).toBe("string");
934
+ expect(JSON.parse(stored["secrets"] as string)).toEqual({
935
+ secretAccessKey: ROTATED_SECRET,
936
+ sessionToken: "session-1",
937
+ });
938
+ // The stored config is what gets validated when the update omits it.
939
+ expect(stored["config"]).toEqual({
940
+ region: "us-east-1",
941
+ accessKeyId: "AKIA1",
942
+ });
943
+ expect(connectorValidateCalls).toEqual([
944
+ {
945
+ provider: SecurityEventConnectorProvider.AwsSecurityHub,
946
+ config: { region: "us-east-1", accessKeyId: "AKIA1" },
947
+ secrets: { secretAccessKey: ROTATED_SECRET, sessionToken: "session-1" },
948
+ alertingOnly: true,
949
+ },
950
+ ]);
951
+ });
952
+
953
+ /*
954
+ * null used to be listed here too. It now removes the stored key (review
955
+ * finding optional-secret-cannot-be-cleared); see the tests below.
956
+ */
957
+ test.each(["", undefined])(
958
+ "a secret submitted as %j keeps the stored value (edit forms cannot echo secrets back)",
959
+ async (blank: unknown) => {
960
+ const result: OnUpdate<SecurityEventConnection> =
961
+ await service.onBeforeUpdate(
962
+ updateBy({
963
+ config: {
964
+ orgUrl: "https://acme.okta.com",
965
+ filter: 'eventType sw "user"',
966
+ },
967
+ secrets: { apiToken: blank as never },
968
+ }),
969
+ );
970
+
971
+ const stored: JSONObject = result.updateBy.data as unknown as JSONObject;
972
+ expect(JSON.parse(stored["secrets"] as string)).toEqual({
973
+ apiToken: SECRET_VALUE,
974
+ });
975
+ expect(stored["config"]).toEqual({
976
+ orgUrl: "https://acme.okta.com",
977
+ filter: 'eventType sw "user"',
978
+ });
979
+ },
980
+ );
981
+
982
+ test("a config sent as a JSON string is stored as an object and validated with the stored secrets", async () => {
983
+ const result: OnUpdate<SecurityEventConnection> =
984
+ await service.onBeforeUpdate(
985
+ updateBy({
986
+ config: JSON.stringify({ orgUrl: "https://acme.oktapreview.com" }),
987
+ }),
988
+ );
989
+
990
+ const stored: JSONObject = result.updateBy.data as unknown as JSONObject;
991
+ expect(stored["config"]).toEqual({
992
+ orgUrl: "https://acme.oktapreview.com",
993
+ });
994
+ expect(connectorValidateCalls[0]!.secrets).toEqual({
995
+ apiToken: SECRET_VALUE,
996
+ });
997
+ expect(DataSourceEgressGuard.assertUrlAllowed).toHaveBeenCalledWith(
998
+ "https://acme.oktapreview.com",
999
+ );
1000
+ });
1001
+
1002
+ test("an unknown config key on update is rejected", async () => {
1003
+ await expect(
1004
+ service.onBeforeUpdate(
1005
+ updateBy({ config: { orgUrl: "https://acme.okta.com", nope: 1 } }),
1006
+ ),
1007
+ ).rejects.toThrow('unknown setting "nope"');
1008
+ });
1009
+
1010
+ test("a provided alertingOnly is what the provider validates; otherwise the stored one", async () => {
1011
+ await service.onBeforeUpdate(
1012
+ updateBy({ alertingOnly: false, secrets: { apiToken: ROTATED_SECRET } }),
1013
+ );
1014
+ findOneById.mockResolvedValue(
1015
+ storedConnection({ alertingOnly: false }) as never,
1016
+ );
1017
+ await service.onBeforeUpdate(
1018
+ updateBy({ secrets: { apiToken: ROTATED_SECRET } }),
1019
+ );
1020
+
1021
+ expect(
1022
+ connectorValidateCalls.map((call: SecurityConnectorSettings): boolean => {
1023
+ return call.alertingOnly;
1024
+ }),
1025
+ ).toEqual([false, false]);
1026
+ });
1027
+
1028
+ test("a connection deleted between the form load and the save is refused", async () => {
1029
+ findOneById.mockResolvedValue(null as never);
1030
+
1031
+ await expect(
1032
+ service.onBeforeUpdate(
1033
+ updateBy({ secrets: { apiToken: ROTATED_SECRET } }),
1034
+ ),
1035
+ ).rejects.toThrow("The connection no longer exists.");
1036
+ });
1037
+
1038
+ test("a null optional secret removes the stored key, from what is validated and from what is stored", async () => {
1039
+ /*
1040
+ * The AWS case from review finding optional-secret-cannot-be-cleared:
1041
+ * temporary STS credentials replaced by a long-lived key. A session
1042
+ * token left stored would be sent with the new key and every call
1043
+ * would be rejected.
1044
+ */
1045
+ findOneById.mockResolvedValue(
1046
+ storedConnection({
1047
+ provider: SecurityEventConnectorProvider.AwsSecurityHub,
1048
+ config: { region: "us-east-1", accessKeyId: "ASIA1" },
1049
+ secrets: JSON.stringify({
1050
+ secretAccessKey: SECRET_VALUE,
1051
+ sessionToken: "session-1",
1052
+ }),
1053
+ }) as never,
1054
+ );
1055
+
1056
+ const result: OnUpdate<SecurityEventConnection> =
1057
+ await service.onBeforeUpdate(
1058
+ updateBy({
1059
+ config: { region: "us-east-1", accessKeyId: "AKIA2" },
1060
+ secrets: { secretAccessKey: ROTATED_SECRET, sessionToken: null },
1061
+ }),
1062
+ );
1063
+
1064
+ const stored: JSONObject = result.updateBy.data as unknown as JSONObject;
1065
+ expect(JSON.parse(stored["secrets"] as string)).toEqual({
1066
+ secretAccessKey: ROTATED_SECRET,
1067
+ });
1068
+ expect(connectorValidateCalls).toEqual([
1069
+ {
1070
+ provider: SecurityEventConnectorProvider.AwsSecurityHub,
1071
+ config: { region: "us-east-1", accessKeyId: "AKIA2" },
1072
+ secrets: { secretAccessKey: ROTATED_SECRET },
1073
+ alertingOnly: true,
1074
+ },
1075
+ ]);
1076
+ });
1077
+
1078
+ test("a null secret sent as a JSON string removes the key too, and blank siblings keep theirs", async () => {
1079
+ // The Splunk case: a revoked token cleared in favour of username and password.
1080
+ findOneById.mockResolvedValue(
1081
+ storedConnection({
1082
+ provider: SecurityEventConnectorProvider.SplunkEnterpriseSecurity,
1083
+ config: { url: "https://splunk.example.com:8089", username: "svc" },
1084
+ secrets: JSON.stringify({ apiToken: SECRET_VALUE, password: "old" }),
1085
+ }) as never,
1086
+ );
1087
+
1088
+ const result: OnUpdate<SecurityEventConnection> =
1089
+ await service.onBeforeUpdate(
1090
+ updateBy({
1091
+ secrets: JSON.stringify({ apiToken: null, password: "" }),
1092
+ }),
1093
+ );
1094
+
1095
+ const stored: JSONObject = result.updateBy.data as unknown as JSONObject;
1096
+ expect(JSON.parse(stored["secrets"] as string)).toEqual({
1097
+ password: "old",
1098
+ });
1099
+ });
1100
+
1101
+ test("clearing a required secret with null is rejected with the field title and nothing reaches the provider", async () => {
1102
+ await expect(
1103
+ service.onBeforeUpdate(updateBy({ secrets: { apiToken: null } })),
1104
+ ).rejects.toThrow(`API token is required for ${OKTA.title}.`);
1105
+ expect(connectorValidateCalls).toHaveLength(0);
1106
+ });
1107
+
1108
+ test("a null for an unknown credential key is refused instead of silently keeping the stored credential", async () => {
1109
+ await expect(
1110
+ service.onBeforeUpdate(updateBy({ secrets: { apiTokn: null } })),
1111
+ ).rejects.toThrow(
1112
+ `Credentials contains an unknown setting "apiTokn" for ${OKTA.title}.`,
1113
+ );
1114
+ expect(connectorValidateCalls).toHaveLength(0);
1115
+ });
1116
+
1117
+ test("the merged secrets must still satisfy the catalog", async () => {
1118
+ findOneById.mockResolvedValue(storedConnection({ secrets: "{}" }) as never);
1119
+
1120
+ await expect(
1121
+ service.onBeforeUpdate(updateBy({ secrets: { apiToken: "" } })),
1122
+ ).rejects.toThrow(`API token is required for ${OKTA.title}.`);
1123
+ });
1124
+ });
1125
+
1126
+ describe("SecurityEventConnectionService.getConnectorSettings", () => {
1127
+ test("parses the decrypted JSON off a fully loaded row without a read", async () => {
1128
+ const findOneById: ReturnType<typeof getJestSpyOn> = getJestSpyOn(
1129
+ SecurityEventConnectionService,
1130
+ "findOneById",
1131
+ );
1132
+
1133
+ const settings: SecurityConnectorSettings =
1134
+ await SecurityEventConnectionService.getConnectorSettings(
1135
+ storedConnection({ alertingOnly: false }),
1136
+ );
1137
+
1138
+ expect(settings).toEqual({
1139
+ provider: SecurityEventConnectorProvider.OktaSystemLog,
1140
+ config: { orgUrl: "https://acme.okta.com", filter: "" },
1141
+ secrets: { apiToken: SECRET_VALUE },
1142
+ alertingOnly: false,
1143
+ });
1144
+ expect(findOneById).not.toHaveBeenCalled();
1145
+ });
1146
+
1147
+ test("loads the row as root when the caller's copy is missing secrets, config or provider", async () => {
1148
+ const findOneById: ReturnType<typeof getJestSpyOn> = getJestSpyOn(
1149
+ SecurityEventConnectionService,
1150
+ "findOneById",
1151
+ ).mockResolvedValue(storedConnection() as never);
1152
+ const partial: SecurityEventConnection = new SecurityEventConnection();
1153
+ partial._id = CONNECTION_ID.toString();
1154
+ partial.provider = SecurityEventConnectorProvider.OktaSystemLog;
1155
+
1156
+ const settings: SecurityConnectorSettings =
1157
+ await SecurityEventConnectionService.getConnectorSettings(partial);
1158
+
1159
+ expect(findOneById).toHaveBeenCalledWith({
1160
+ id: CONNECTION_ID,
1161
+ select: {
1162
+ _id: true,
1163
+ provider: true,
1164
+ config: true,
1165
+ secrets: true,
1166
+ alertingOnly: true,
1167
+ },
1168
+ props: { isRoot: true },
1169
+ });
1170
+ expect(settings.secrets).toEqual({ apiToken: SECRET_VALUE });
1171
+ expect(settings.alertingOnly).toBe(true);
1172
+ });
1173
+
1174
+ test("a row that vanished is an error, not empty settings", async () => {
1175
+ getJestSpyOn(
1176
+ SecurityEventConnectionService,
1177
+ "findOneById",
1178
+ ).mockResolvedValue(null as never);
1179
+ const partial: SecurityEventConnection = new SecurityEventConnection();
1180
+ partial._id = CONNECTION_ID.toString();
1181
+
1182
+ await expect(
1183
+ SecurityEventConnectionService.getConnectorSettings(partial),
1184
+ ).rejects.toThrow("The connection no longer exists.");
1185
+ });
1186
+
1187
+ test("a stored provider outside the catalog is refused", async () => {
1188
+ await expect(
1189
+ SecurityEventConnectionService.getConnectorSettings(
1190
+ storedConnection({
1191
+ provider: "google-secops" as SecurityEventConnectorProvider,
1192
+ }),
1193
+ ),
1194
+ ).rejects.toThrow("Provider must be one of the supported");
1195
+ });
1196
+
1197
+ test("corrupt stored JSON is a readable error", async () => {
1198
+ await expect(
1199
+ SecurityEventConnectionService.getConnectorSettings(
1200
+ storedConnection({ secrets: "{not json" }),
1201
+ ),
1202
+ ).rejects.toThrow("Credentials must be a JSON object.");
1203
+ });
1204
+ });
1205
+
1206
+ describe("SecurityEventConnectionService - catalog coverage", () => {
1207
+ test("every shipped url field is validated for embedded credentials", () => {
1208
+ const urlFields: Array<[SecurityEventConnectorDefinition, ConnectorField]> =
1209
+ [];
1210
+
1211
+ for (const definition of [OKTA, SENTINEL]) {
1212
+ for (const field of definition.configFields) {
1213
+ if (field.type === "url") {
1214
+ urlFields.push([definition, field]);
1215
+ }
1216
+ }
1217
+ }
1218
+
1219
+ expect(urlFields.length).toBeGreaterThan(0);
1220
+
1221
+ for (const [definition, field] of urlFields) {
1222
+ expect(() => {
1223
+ SecurityEventConnectionServiceType.validateFields({
1224
+ definition,
1225
+ fields: [field],
1226
+ values: { [field.key]: "https://admin:hunter2@example.com" },
1227
+ label: "Configuration",
1228
+ requireRequiredFields: false,
1229
+ });
1230
+ }).toThrow("must not embed credentials");
1231
+ }
1232
+ });
1233
+ });