@oneuptime/common 14.0.9 → 14.0.11

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 (1146) hide show
  1. package/Models/DatabaseModels/AIConversation.ts +127 -1
  2. package/Models/DatabaseModels/AutoRemediationSuggestion.ts +60 -0
  3. package/Models/DatabaseModels/CephCluster.ts +225 -0
  4. package/Models/DatabaseModels/CloudResource.ts +12 -0
  5. package/Models/DatabaseModels/DatabaseServer.ts +225 -0
  6. package/Models/DatabaseModels/DockerHost.ts +225 -0
  7. package/Models/DatabaseModels/DockerSwarmCluster.ts +225 -0
  8. package/Models/DatabaseModels/GlobalConfig.ts +1 -1
  9. package/Models/DatabaseModels/GlobalOidc.ts +0 -4
  10. package/Models/DatabaseModels/GlobalOidcProject.ts +0 -4
  11. package/Models/DatabaseModels/GlobalSso.ts +0 -4
  12. package/Models/DatabaseModels/GlobalSsoProject.ts +0 -4
  13. package/Models/DatabaseModels/Host.ts +225 -0
  14. package/Models/DatabaseModels/IncidentForm.ts +594 -0
  15. package/Models/DatabaseModels/IncidentFormSubmission.ts +283 -0
  16. package/Models/DatabaseModels/IncidentTemplate.ts +59 -0
  17. package/Models/DatabaseModels/Index.ts +16 -0
  18. package/Models/DatabaseModels/IoTFleet.ts +12 -0
  19. package/Models/DatabaseModels/KubernetesCluster.ts +12 -0
  20. package/Models/DatabaseModels/MessageQueue.ts +1102 -0
  21. package/Models/DatabaseModels/MessageQueueLabelRule.ts +553 -0
  22. package/Models/DatabaseModels/MessageQueueOwnerRule.ts +633 -0
  23. package/Models/DatabaseModels/MessageQueueOwnerTeam.ts +491 -0
  24. package/Models/DatabaseModels/MessageQueueOwnerUser.ts +490 -0
  25. package/Models/DatabaseModels/PodmanHost.ts +225 -0
  26. package/Models/DatabaseModels/Project.ts +59 -0
  27. package/Models/DatabaseModels/ProjectOidc.ts +0 -4
  28. package/Models/DatabaseModels/ProjectSso.ts +0 -4
  29. package/Models/DatabaseModels/ProxmoxCluster.ts +225 -0
  30. package/Models/DatabaseModels/ResourceAiAgent.ts +419 -0
  31. package/Models/DatabaseModels/RumApplication.ts +12 -0
  32. package/Models/DatabaseModels/RunnerJob.ts +144 -0
  33. package/Models/DatabaseModels/ServerlessFunction.ts +12 -0
  34. package/Models/DatabaseModels/Service.ts +12 -0
  35. package/Models/DatabaseModels/StatusPageOidc.ts +0 -4
  36. package/Models/DatabaseModels/StatusPageSso.ts +0 -4
  37. package/Models/DatabaseModels/TeamComplianceSetting.ts +47 -2
  38. package/Models/DatabaseModels/VMwareVCenter.ts +225 -0
  39. package/Server/API/AIChatAPI.ts +13 -114
  40. package/Server/API/AIInvestigationAPI.ts +3 -3
  41. package/Server/API/AIInvestigationConversationAPI.ts +266 -0
  42. package/Server/API/AutoRemediationAPI.ts +392 -1
  43. package/Server/API/IncidentFormAPI.ts +376 -0
  44. package/Server/API/ProjectOIDC.ts +16 -25
  45. package/Server/API/ProjectSSO.ts +16 -24
  46. package/Server/API/ResourceAiAccessAPI.ts +1669 -0
  47. package/Server/API/StatusPageAPI.ts +42 -77
  48. package/Server/Enterprise/EnterpriseEdition.ts +93 -28
  49. package/Server/Enterprise/EnterpriseFeature.ts +25 -3
  50. package/Server/Enterprise/EnterpriseLicenseSnapshot.ts +1 -1
  51. package/Server/Enterprise/EnterpriseServerModule.ts +4 -1
  52. package/Server/EnvironmentConfig.ts +1 -1
  53. package/Server/Infrastructure/Postgres/SchemaMigrations/1796300000000-AddResourceAiAgents.ts +423 -0
  54. package/Server/Infrastructure/Postgres/SchemaMigrations/1796400000000-AddIncidentForms.ts +129 -0
  55. package/Server/Infrastructure/Postgres/SchemaMigrations/1796500000000-AddTeamComplianceRuleNotificationChannels.ts +52 -0
  56. package/Server/Infrastructure/Postgres/SchemaMigrations/1796600000000-AddAIInvestigationConversationAndTimeLimits.ts +75 -0
  57. package/Server/Infrastructure/Postgres/SchemaMigrations/1796700000000-AddMessageQueueTables.ts +477 -0
  58. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +10 -0
  59. package/Server/Infrastructure/Semaphore.ts +22 -0
  60. package/Server/Middleware/IncidentFormRateLimit.ts +847 -0
  61. package/Server/Middleware/TelemetryIngest.ts +15 -5
  62. package/Server/Middleware/UserAuthorization.ts +16 -38
  63. package/Server/Services/AIService.ts +10 -13
  64. package/Server/Services/AnalyticsDatabaseService.ts +45 -1
  65. package/Server/Services/AutoRemediationRuleEngineService.ts +940 -112
  66. package/Server/Services/CephClusterService.ts +109 -1
  67. package/Server/Services/DatabaseServerService.ts +116 -1
  68. package/Server/Services/DockerHostService.ts +109 -1
  69. package/Server/Services/DockerSwarmClusterService.ts +113 -1
  70. package/Server/Services/HostService.ts +126 -4
  71. package/Server/Services/IncidentCustomFieldService.ts +112 -2
  72. package/Server/Services/IncidentEpisodeMemberService.ts +24 -4
  73. package/Server/Services/IncidentEpisodeService.ts +10 -1
  74. package/Server/Services/IncidentFormService.ts +1566 -0
  75. package/Server/Services/IncidentFormSubmissionService.ts +97 -0
  76. package/Server/Services/IncidentGroupingEngineService.ts +45 -8
  77. package/Server/Services/IncidentService.ts +123 -5
  78. package/Server/Services/IncidentTemplateService.ts +22 -0
  79. package/Server/Services/Index.ts +14 -0
  80. package/Server/Services/MessageQueueLabelRuleEngineService.ts +321 -0
  81. package/Server/Services/MessageQueueLabelRuleService.ts +14 -0
  82. package/Server/Services/MessageQueueOwnerRuleEngineService.ts +412 -0
  83. package/Server/Services/MessageQueueOwnerRuleService.ts +14 -0
  84. package/Server/Services/MessageQueueOwnerTeamService.ts +62 -0
  85. package/Server/Services/MessageQueueOwnerUserService.ts +62 -0
  86. package/Server/Services/MessageQueueService.ts +1463 -0
  87. package/Server/Services/MetricRecordingRuleService.ts +47 -0
  88. package/Server/Services/OpenTelemetryIngestService.ts +37 -4
  89. package/Server/Services/PodmanHostService.ts +109 -1
  90. package/Server/Services/ProjectService.ts +0 -59
  91. package/Server/Services/ProxmoxClusterService.ts +110 -1
  92. package/Server/Services/ResourceAiAccessService.ts +1439 -0
  93. package/Server/Services/ResourceAiAgentJobService.ts +202 -0
  94. package/Server/Services/ResourceAiAgentService.ts +2432 -0
  95. package/Server/Services/RunnerJobService.ts +611 -4
  96. package/Server/Services/StatusPagePrivateUserService.ts +1 -4
  97. package/Server/Services/StatusPageService.ts +1 -51
  98. package/Server/Services/TeamComplianceSettingService.ts +163 -42
  99. package/Server/Services/TelemetryUsageBillingService.ts +28 -0
  100. package/Server/Services/TraceRecordingRuleService.ts +33 -0
  101. package/Server/Services/UserNotificationRuleService.ts +8 -1
  102. package/Server/Services/VMwareVCenterService.ts +110 -1
  103. package/Server/Services/WorkspaceNotificationSummaryService.ts +12 -3
  104. package/Server/Types/Database/Permissions/CreatePermission.ts +17 -3
  105. package/Server/Types/Database/Permissions/EditionPermission.ts +140 -38
  106. package/Server/Types/Database/Permissions/OwnerTableRegistry.ts +16 -0
  107. package/Server/Types/Database/Permissions/TablePermission.ts +3 -3
  108. package/Server/Types/Database/Permissions/UpdatePermission.ts +20 -6
  109. package/Server/Utils/AI/Chat/AgentContextCompactor.ts +200 -0
  110. package/Server/Utils/AI/Chat/ChatAgentRunner.ts +307 -48
  111. package/Server/Utils/AI/Chat/ChatRunCancellation.ts +156 -0
  112. package/Server/Utils/AI/Chat/ObservabilityAssistant.ts +78 -18
  113. package/Server/Utils/AI/Chat/ObservabilityChatPrompt.ts +1 -1
  114. package/Server/Utils/AI/Chat/ToolOutputPager.ts +322 -0
  115. package/Server/Utils/AI/ClusterAccess/KubectlInvestigationToolkit.ts +88 -30
  116. package/Server/Utils/AI/ClusterAccess/KubectlJobRunner.ts +13 -1
  117. package/Server/Utils/AI/CodeFix/CodeFixReadiness.ts +0 -32
  118. package/Server/Utils/AI/CodeFix/FixRunBudget.ts +27 -25
  119. package/Server/Utils/AI/Remediation/RemediationCommandTools.ts +1442 -34
  120. package/Server/Utils/AI/Remediation/RemediationExecutionRunner.ts +968 -34
  121. package/Server/Utils/AI/Remediation/RemediationPlanRunner.ts +25 -1
  122. package/Server/Utils/AI/ResourceAccess/InfrastructureInvestigationToolkit.ts +622 -0
  123. package/Server/Utils/AI/ResourceAccess/ResourceAccessContext.ts +271 -0
  124. package/Server/Utils/AI/ResourceAccess/ResourceAccessToolNames.ts +45 -0
  125. package/Server/Utils/AI/ResourceAccess/ResourceAiAccessSettings.ts +964 -0
  126. package/Server/Utils/AI/ResourceAccess/ResourceAiDeleteCleanup.ts +333 -0
  127. package/Server/Utils/AI/ResourceAccess/ResourceCommandJobRunner.ts +882 -0
  128. package/Server/Utils/AI/SRE/AIInvestigationEngine.ts +125 -12
  129. package/Server/Utils/AI/SRE/AlertInvestigationRunner.ts +99 -15
  130. package/Server/Utils/AI/SRE/IncidentInvestigationRunner.ts +99 -15
  131. package/Server/Utils/AI/SRE/InvestigationQueue.ts +16 -19
  132. package/Server/Utils/AI/SRE/InvestigationThread.ts +646 -0
  133. package/Server/Utils/AI/SRE/InvestigationThreadService.ts +715 -0
  134. package/Server/Utils/AI/Toolbox/Serializer.ts +10 -3
  135. package/Server/Utils/AutoRemediation/CommandPlanExecutor.ts +396 -13
  136. package/Server/Utils/AutoRemediation/RemediationVerifier.ts +35 -2
  137. package/Server/Utils/Database/ProjectScopedReferenceValidator.ts +9 -1
  138. package/Server/Utils/EditionEnforcement.ts +19 -202
  139. package/Server/Utils/LLM/LLMService.ts +259 -63
  140. package/Server/Utils/RelaxedScimTeamLocksReport.ts +245 -0
  141. package/Server/Utils/Rules/RuleRun/RuleRunRegistry.ts +25 -0
  142. package/Server/Utils/SameOriginRequest.ts +203 -0
  143. package/Server/Utils/SessionReplay/SessionReplayBudgetMetrics.ts +920 -0
  144. package/Server/Utils/SessionReplay/SessionReplayUsage.ts +84 -6
  145. package/Server/Utils/TeamMember/ProjectLeaveResourceCleanup.ts +2 -0
  146. package/Server/Utils/Telemetry/EntityRegistry.ts +4 -1
  147. package/Server/Utils/Telemetry/MessageQueueDiscovery.ts +1402 -0
  148. package/Server/Utils/Telemetry/ResourceEntityFilter.ts +4 -1
  149. package/Server/Utils/VendorAssets.ts +3 -3
  150. package/Server/Utils/Workspace/MicrosoftTeams/Actions/Alert.ts +35 -15
  151. package/Server/Utils/Workspace/MicrosoftTeams/Actions/AlertEpisode.ts +33 -15
  152. package/Server/Utils/Workspace/MicrosoftTeams/Actions/Auth.ts +21 -1
  153. package/Server/Utils/Workspace/MicrosoftTeams/Actions/Incident.ts +301 -225
  154. package/Server/Utils/Workspace/MicrosoftTeams/Actions/IncidentEpisode.ts +38 -16
  155. package/Server/Utils/Workspace/MicrosoftTeams/Actions/ScheduledMaintenance.ts +389 -175
  156. package/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.ts +376 -144
  157. package/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsActivityDeduplicator.ts +163 -0
  158. package/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsCardChoices.ts +396 -0
  159. package/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsCreateCommands.ts +418 -0
  160. package/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsMessageSize.ts +152 -0
  161. package/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsReplies.ts +251 -0
  162. package/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsTimezone.ts +214 -0
  163. package/Tests/App/Accounts/IncidentFormPage.test.tsx +2036 -0
  164. package/Tests/App/Accounts/IncidentFormServerMessages.test.ts +119 -0
  165. package/Tests/App/Accounts/IncidentFormUtils.test.ts +1157 -0
  166. package/Tests/App/Accounts/LoginPasskey.test.tsx +6 -4
  167. package/Tests/App/Accounts/LoginSso.test.tsx +724 -0
  168. package/Tests/App/AdminDashboard/AdminAuthenticationRequireSso.test.tsx +338 -0
  169. package/Tests/App/AdminDashboard/AdminAuthenticationSsoCardLocales.test.tsx +331 -0
  170. package/Tests/App/AdminDashboard/AdminEnterprisePluginPage.test.tsx +47 -33
  171. package/Tests/App/AdminDashboard/GlobalSsoOidcPages.test.tsx +1021 -0
  172. package/Tests/App/Dashboard/AffectedResourcesDisplay.test.tsx +876 -78
  173. package/Tests/App/Dashboard/AffectedResourcesSlo.test.tsx +20 -3
  174. package/Tests/App/Dashboard/CephProxmoxVMwareDocumentationCards.test.tsx +359 -0
  175. package/Tests/App/Dashboard/CephSetupGuide.test.ts +961 -0
  176. package/Tests/App/Dashboard/CloudDocumentationCard.test.tsx +381 -95
  177. package/Tests/App/Dashboard/CloudSetupGuide.test.ts +1463 -0
  178. package/Tests/App/Dashboard/ClusterAccessNotice.test.tsx +267 -12
  179. package/Tests/App/Dashboard/ContainerSetupGuideCards.test.tsx +345 -0
  180. package/Tests/App/Dashboard/CoreListEmptyStates.test.tsx +501 -0
  181. package/Tests/App/Dashboard/DashboardLazyPages.test.tsx +0 -1
  182. package/Tests/App/Dashboard/DatabaseDocumentationCard.test.tsx +400 -0
  183. package/Tests/App/Dashboard/DatabaseDocumentationMarkdown.test.ts +23 -6
  184. package/Tests/App/Dashboard/DatabaseSetupGuide.test.ts +1869 -0
  185. package/Tests/App/Dashboard/DatabaseTelemetryScope.test.ts +44 -0
  186. package/Tests/App/Dashboard/DatabaseTelemetryTabs.test.tsx +50 -9
  187. package/Tests/App/Dashboard/DockerSetupGuide.test.ts +899 -0
  188. package/Tests/App/Dashboard/DockerSwarmSetupGuide.test.ts +964 -0
  189. package/Tests/App/Dashboard/EnterpriseFeatureUpgrade.test.tsx +141 -7
  190. package/Tests/App/Dashboard/EnterprisePluginPage.test.tsx +52 -39
  191. package/Tests/App/Dashboard/EventOverviewPages.test.tsx +7 -1
  192. package/Tests/App/Dashboard/GettingStartedTaskRoutes.test.tsx +331 -0
  193. package/Tests/App/Dashboard/HomeOverviewStatsFirstRun.test.tsx +925 -0
  194. package/Tests/App/Dashboard/HostDocumentationCard.test.tsx +225 -0
  195. package/Tests/App/Dashboard/HostSetupGuide.test.ts +1183 -0
  196. package/Tests/App/Dashboard/IdentityEnterpriseShells.test.tsx +69 -45
  197. package/Tests/App/Dashboard/IncidentCreateTemplateCustomFieldSettings.test.tsx +745 -0
  198. package/Tests/App/Dashboard/IncidentCreateTemplateOwners.test.tsx +414 -0
  199. package/Tests/App/Dashboard/IncidentCustomFieldCreateSettingsForm.test.ts +1042 -0
  200. package/Tests/App/Dashboard/IncidentCustomFieldSettingsCard.test.tsx +1816 -0
  201. package/Tests/App/Dashboard/IncidentFormPlan.test.ts +89 -0
  202. package/Tests/App/Dashboard/IncidentFormShareLinkCard.test.tsx +846 -0
  203. package/Tests/App/Dashboard/IncidentFormsPages.test.tsx +1324 -0
  204. package/Tests/App/Dashboard/IncidentTemplateCustomFieldSettings.test.tsx +630 -0
  205. package/Tests/App/Dashboard/IncidentsSideMenu.test.tsx +13 -0
  206. package/Tests/App/Dashboard/IncomingEmailMonitorLinkVerifyHint.test.tsx +104 -0
  207. package/Tests/App/Dashboard/InvestigationConversation.test.tsx +1107 -0
  208. package/Tests/App/Dashboard/InvestigationConversationData.test.ts +546 -0
  209. package/Tests/App/Dashboard/InvestigationEvidenceList.test.tsx +170 -5
  210. package/Tests/App/Dashboard/InvestigationInfrastructureTools.test.tsx +506 -0
  211. package/Tests/App/Dashboard/InvestigationNotStarted.test.tsx +207 -2
  212. package/Tests/App/Dashboard/InvestigationPanel.test.tsx +729 -34
  213. package/Tests/App/Dashboard/InvestigationPanelStatus.test.tsx +9 -21
  214. package/Tests/App/Dashboard/InvestigationReportView.test.tsx +274 -37
  215. package/Tests/App/Dashboard/InvestigationStatusBadge.test.tsx +130 -0
  216. package/Tests/App/Dashboard/IoTDocumentationCard.test.tsx +218 -0
  217. package/Tests/App/Dashboard/IoTSetupGuide.test.ts +1124 -0
  218. package/Tests/App/Dashboard/KubernetesClusterAiAccessSettings.test.ts +20 -6
  219. package/Tests/App/Dashboard/KubernetesClusterAiDocumentationMarkdown.test.ts +107 -83
  220. package/Tests/App/Dashboard/KubernetesSetupGuide.test.ts +787 -0
  221. package/Tests/App/Dashboard/MessageQueueBreadcrumbs.test.tsx +228 -0
  222. package/Tests/App/Dashboard/MessageQueueBrokerHealth.test.tsx +1538 -0
  223. package/Tests/App/Dashboard/MessageQueueBrokerHealthMetricChart.test.tsx +969 -0
  224. package/Tests/App/Dashboard/MessageQueueBrokerHealthReads.test.ts +889 -0
  225. package/Tests/App/Dashboard/MessageQueueBrokerMetricsReach.test.ts +236 -0
  226. package/Tests/App/Dashboard/MessageQueueDocumentationCard.test.tsx +479 -0
  227. package/Tests/App/Dashboard/MessageQueueListPages.test.tsx +1232 -0
  228. package/Tests/App/Dashboard/MessageQueueMetricDescriptions.test.ts +244 -0
  229. package/Tests/App/Dashboard/MessageQueueMonitorLink.test.ts +952 -0
  230. package/Tests/App/Dashboard/MessageQueueMonitorLinkMonitorCreate.test.tsx +859 -0
  231. package/Tests/App/Dashboard/MessageQueueOverview.test.tsx +1773 -0
  232. package/Tests/App/Dashboard/MessageQueueOverviewPresentation.test.ts +196 -0
  233. package/Tests/App/Dashboard/MessageQueuePresentation.test.ts +799 -0
  234. package/Tests/App/Dashboard/MessageQueueProducersConsumers.test.tsx +680 -0
  235. package/Tests/App/Dashboard/MessageQueueRoutes.test.tsx +383 -0
  236. package/Tests/App/Dashboard/MessageQueueRulePages.test.tsx +278 -0
  237. package/Tests/App/Dashboard/MessageQueueSetupGuide.test.ts +2778 -0
  238. package/Tests/App/Dashboard/MessageQueueSideMenus.test.tsx +273 -0
  239. package/Tests/App/Dashboard/MessageQueueSpanPopulations.test.ts +930 -0
  240. package/Tests/App/Dashboard/MessageQueueSpanStore.ts +351 -0
  241. package/Tests/App/Dashboard/MessageQueueTelemetryScope.test.ts +375 -0
  242. package/Tests/App/Dashboard/MessageQueueTelemetryScopeTabs.test.tsx +668 -0
  243. package/Tests/App/Dashboard/MessageQueueViewPages.test.tsx +685 -0
  244. package/Tests/App/Dashboard/MonitorAndHomeNotOperationalMenus.test.tsx +342 -0
  245. package/Tests/App/Dashboard/MonitorCreateFirstRunDefaults.test.tsx +623 -0
  246. package/Tests/App/Dashboard/MonitorCreateFromMonitorBackedDevice.test.tsx +442 -0
  247. package/Tests/App/Dashboard/MonitorLogsPageViewSummary.test.tsx +814 -0
  248. package/Tests/App/Dashboard/MonitorSetupCardBodies.test.tsx +246 -0
  249. package/Tests/App/Dashboard/NavigationSearchKeywords.test.tsx +8 -0
  250. package/Tests/App/Dashboard/OnboardingSsoEmptyState.test.tsx +27 -12
  251. package/Tests/App/Dashboard/PlanGatedPage.test.tsx +292 -0
  252. package/Tests/App/Dashboard/PodmanSetupGuide.test.ts +948 -0
  253. package/Tests/App/Dashboard/ProductOrientation.test.tsx +5 -4
  254. package/Tests/App/Dashboard/ProductSettingsSectionCollapsed.test.tsx +266 -0
  255. package/Tests/App/Dashboard/ProxmoxSetupGuide.test.ts +1318 -0
  256. package/Tests/App/Dashboard/RemediationSuggestionCardDescription.test.tsx +209 -0
  257. package/Tests/App/Dashboard/RemediationSuggestionCardResource.test.tsx +317 -0
  258. package/Tests/App/Dashboard/ResourceAiAccessSettingsUtil.test.ts +921 -0
  259. package/Tests/App/Dashboard/ResourceAiAgentAttentionServerParity.test.ts +555 -0
  260. package/Tests/App/Dashboard/ResourceAiAgentInstall.test.ts +860 -0
  261. package/Tests/App/Dashboard/ResourceAiAgentPage.test.tsx +2010 -0
  262. package/Tests/App/Dashboard/ResourceAiAgentStatus.test.ts +1455 -0
  263. package/Tests/App/Dashboard/ResourceAiInsightsPage.test.tsx +931 -0
  264. package/Tests/App/Dashboard/ResourceAiNavigation.test.tsx +575 -0
  265. package/Tests/App/Dashboard/ResourceArchiveSettings.test.tsx +16 -0
  266. package/Tests/App/Dashboard/ResourceConnectionGuideCard.test.tsx +444 -0
  267. package/Tests/App/Dashboard/ResourceConnectionGuideOverviewsInfra.test.tsx +798 -0
  268. package/Tests/App/Dashboard/ResourceConnectionGuideOverviewsPlatforms.test.tsx +717 -0
  269. package/Tests/App/Dashboard/ResourceConnectionGuides.test.ts +981 -0
  270. package/Tests/App/Dashboard/ResourceConnectionState.test.ts +132 -0
  271. package/Tests/App/Dashboard/RumDocumentationCard.test.tsx +293 -0
  272. package/Tests/App/Dashboard/RumSessionReplayRetentionSettings.test.tsx +467 -0
  273. package/Tests/App/Dashboard/RumSetupGuide.test.ts +758 -0
  274. package/Tests/App/Dashboard/RunbookStepTypeMaps.test.ts +38 -7
  275. package/Tests/App/Dashboard/ScheduledMaintenanceOverviewPage.test.tsx +25 -0
  276. package/Tests/App/Dashboard/ServerlessDocumentationCard.test.tsx +254 -0
  277. package/Tests/App/Dashboard/ServerlessSetupGuide.test.ts +1074 -0
  278. package/Tests/App/Dashboard/SetupGuide.test.ts +246 -0
  279. package/Tests/App/Dashboard/SetupGuideCard.test.tsx +756 -0
  280. package/Tests/App/Dashboard/SloListSideMenu.test.tsx +120 -0
  281. package/Tests/App/Dashboard/SsoPages.test.tsx +833 -0
  282. package/Tests/App/Dashboard/TelemetryDocumentation.test.tsx +253 -0
  283. package/Tests/App/Dashboard/TelemetryRetentionShells.test.tsx +730 -0
  284. package/Tests/App/Dashboard/VMwareSetupGuide.test.ts +1033 -0
  285. package/Tests/App/StatusPage/StatusPageSsoEmptyState.test.tsx +87 -7
  286. package/Tests/Models/DatabaseModels/DatabaseServerModels.test.ts +61 -10
  287. package/Tests/Models/DatabaseModels/IncidentFormModel.test.ts +1250 -0
  288. package/Tests/Models/DatabaseModels/MessageQueueModels.test.ts +1983 -0
  289. package/Tests/Models/DatabaseModels/ResourceAiAccessColumns.test.ts +738 -0
  290. package/Tests/Models/DatabaseModels/ResourceAiAgentModel.test.ts +842 -0
  291. package/Tests/Models/DatabaseModels/StaticRuleCriteriaInheritance.test.ts +4 -2
  292. package/Tests/Models/DatabaseModels/TeamComplianceSettingModel.test.ts +190 -14
  293. package/Tests/Models/IncidentTemplateCustomFieldSettingsColumn.test.ts +291 -0
  294. package/Tests/Server/API/AIInvestigationConversationAPI.test.ts +412 -0
  295. package/Tests/Server/API/AutoRemediationApproveResourceRound.test.ts +835 -0
  296. package/Tests/Server/API/GlobalConfigLicense.test.ts +38 -9
  297. package/Tests/Server/API/IncidentFormAPI.test.ts +942 -0
  298. package/Tests/Server/API/IncidentFormPublicRoutes.test.ts +1653 -0
  299. package/Tests/Server/API/KubernetesClusterAiAccessAPI.test.ts +2 -1
  300. package/Tests/Server/API/ResourceAiAccessAPI.test.ts +2730 -0
  301. package/Tests/Server/API/{SsoProviderListingsEdition.test.ts → SsoProviderListings.test.ts} +164 -110
  302. package/Tests/Server/Enterprise/EnterpriseEdition.test.ts +76 -54
  303. package/Tests/Server/Enterprise/EnterpriseFeatureActive.test.ts +125 -42
  304. package/Tests/Server/Enterprise/EnterpriseLicenseSnapshot.test.ts +36 -10
  305. package/Tests/Server/Enterprise/EnterpriseModelFeatureMap.test.ts +51 -9
  306. package/Tests/Server/Enterprise/FakeEnterpriseModule.ts +13 -8
  307. package/Tests/Server/Enterprise/SsoInCommunityEdition.test.ts +540 -0
  308. package/Tests/Server/Infrastructure/Postgres/AddConfigurableRuleCriteriaMigration.test.ts +3 -0
  309. package/Tests/Server/Infrastructure/Postgres/AddDatabaseServerTablesMigration.test.ts +60 -0
  310. package/Tests/Server/Infrastructure/Postgres/AddIncidentFormsMigration.test.ts +438 -0
  311. package/Tests/Server/Infrastructure/Postgres/AddResourceAiAgentsMigration.test.ts +659 -0
  312. package/Tests/Server/Infrastructure/Postgres/AddTeamComplianceRuleNotificationChannelsMigration.test.ts +255 -0
  313. package/Tests/Server/Infrastructure/Postgres/MessageQueueTablesMigration.test.ts +637 -0
  314. package/Tests/Server/Infrastructure/SemaphoreMutex.test.ts +31 -0
  315. package/Tests/Server/Middleware/IncidentFormRateLimit.test.ts +1630 -0
  316. package/Tests/Server/Middleware/TelemetryIngestBrowserKey.test.ts +63 -5
  317. package/Tests/Server/Middleware/TelemetryIngestKubernetesAgentRunnerPinnedKey.test.ts +103 -5
  318. package/Tests/Server/Middleware/TelemetryIngestKubernetesAgentRunnerRateLimit.test.ts +19 -1
  319. package/Tests/Server/Middleware/UserAuthorization.test.ts +16 -17
  320. package/Tests/Server/Middleware/UserAuthorizationSsoEnforcement.test.ts +544 -0
  321. package/Tests/Server/Services/AIServiceDailyBudget.test.ts +37 -8
  322. package/Tests/Server/Services/AutoRemediationResourceRuleEngine.test.ts +1279 -0
  323. package/Tests/Server/Services/DatabaseServerService.test.ts +55 -0
  324. package/Tests/Server/Services/GroupTelemetryUsageExcludeNames.test.ts +299 -0
  325. package/Tests/Server/Services/HostServiceFindOrCreateMemo.test.ts +44 -0
  326. package/Tests/Server/Services/IncidentCreatedFeedTitle.test.ts +212 -0
  327. package/Tests/Server/Services/IncidentCustomFieldDeleteFormQuestions.test.ts +297 -0
  328. package/Tests/Server/Services/IncidentFormOwnersCreatedNotification.test.ts +497 -0
  329. package/Tests/Server/Services/IncidentFormPostgres.test.ts +958 -0
  330. package/Tests/Server/Services/IncidentFormPublicForm.test.ts +1260 -0
  331. package/Tests/Server/Services/IncidentFormPublicSubmission.test.ts +2520 -0
  332. package/Tests/Server/Services/IncidentFormRegistration.test.ts +159 -0
  333. package/Tests/Server/Services/IncidentFormService.test.ts +663 -0
  334. package/Tests/Server/Services/IncidentFormSubmissionService.test.ts +430 -0
  335. package/Tests/Server/Services/IncidentFormSubmissionTemplateBranch.test.ts +473 -0
  336. package/Tests/Server/Services/IncidentGroupingTemplateSubstitution.test.ts +81 -0
  337. package/Tests/Server/Services/IncidentTemplateCustomFieldSettings.test.ts +262 -0
  338. package/Tests/Server/Services/IncidentTemplateOwnersOnDeclare.test.ts +566 -0
  339. package/Tests/Server/Services/IncidentTitleMarkdownSinks.test.ts +640 -0
  340. package/Tests/Server/Services/LlmLogServiceTokenAggregateParams.test.ts +3 -3
  341. package/Tests/Server/Services/MessageQueueOwnerServices.test.ts +440 -0
  342. package/Tests/Server/Services/MessageQueueRegistries.test.ts +577 -0
  343. package/Tests/Server/Services/MessageQueueRuleEngines.test.ts +900 -0
  344. package/Tests/Server/Services/MessageQueueService.test.ts +2210 -0
  345. package/Tests/Server/Services/MessageQueueSqlPostgres.test.ts +1271 -0
  346. package/Tests/Server/Services/MonitorProbeServiceIntervalScheduling.test.ts +45 -6
  347. package/Tests/Server/Services/OpenTelemetryResourceRetentionMemo.test.ts +28 -1
  348. package/Tests/Server/Services/OpenTelemetryRetentionOverrideEdition.test.ts +474 -0
  349. package/Tests/Server/Services/OpenTelemetryServiceResolutionCache.test.ts +21 -0
  350. package/Tests/Server/Services/OwnerRowUniqueness.test.ts +3 -0
  351. package/Tests/Server/Services/ProjectServiceAuditLogLicense.test.ts +0 -1
  352. package/Tests/Server/Services/RecordingRuleReservedMetricName.test.ts +171 -0
  353. package/Tests/Server/Services/ResourceAiAccessChangeAuthorization.test.ts +256 -0
  354. package/Tests/Server/Services/ResourceAiAccessService.test.ts +1373 -0
  355. package/Tests/Server/Services/ResourceAiAgentJobService.test.ts +375 -0
  356. package/Tests/Server/Services/ResourceAiAgentServiceHelpers.test.ts +1114 -0
  357. package/Tests/Server/Services/ResourceAiAgentServiceLifecycle.test.ts +1050 -0
  358. package/Tests/Server/Services/ResourceAiAgentServiceRegister.test.ts +2251 -0
  359. package/Tests/Server/Services/ResourceAiSettingsCreate.test.ts +373 -0
  360. package/Tests/Server/Services/ResourceAiSettingsPermission.test.ts +1042 -0
  361. package/Tests/Server/Services/ResourceServiceDeleteCleansUpAi.test.ts +319 -0
  362. package/Tests/Server/Services/RuleRun/LabelRuleEnginesGroupBRun.test.ts +56 -6
  363. package/Tests/Server/Services/RuleRun/OwnerRuleEnginesGroupBRun.test.ts +30 -1
  364. package/Tests/Server/Services/RunnerJobEnqueueKubectl.test.ts +105 -0
  365. package/Tests/Server/Services/RunnerJobEnqueueResourceCommand.test.ts +986 -0
  366. package/Tests/Server/Services/RunnerJobResourceCommandLane.test.ts +211 -0
  367. package/Tests/Server/Services/RunnerJobResourceCommandTimeoutAndRedaction.test.ts +352 -0
  368. package/Tests/Server/Services/SsoRequirementReads.test.ts +454 -0
  369. package/Tests/Server/Services/SsoRequirementWrites.test.ts +529 -0
  370. package/Tests/Server/Services/StaticRuleCriteriaRuntimeCoverage.test.ts +3 -3
  371. package/Tests/Server/Services/StatusPagePrivateUserInvitationPolicy.test.ts +107 -89
  372. package/Tests/Server/Services/TeamComplianceSettingPostgres.test.ts +1068 -176
  373. package/Tests/Server/Services/TeamComplianceSettingService.test.ts +1962 -200
  374. package/Tests/Server/Services/TelemetryUsageBillingSloExclusion.test.ts +218 -0
  375. package/Tests/Server/TestingUtils/Services/FakeRunnerJobCount.ts +145 -0
  376. package/Tests/Server/Types/Database/Permissions/EditionPermission.test.ts +654 -297
  377. package/Tests/Server/Types/Database/Permissions/RetentionOverrideColumns.test.ts +784 -0
  378. package/Tests/Server/Types/Database/Permissions/SsoScalePlanGate.test.ts +418 -0
  379. package/Tests/Server/Utils/AI/AIAlertGating.test.ts +0 -1
  380. package/Tests/Server/Utils/AI/AIInvestigationEngineRunLimits.test.ts +136 -0
  381. package/Tests/Server/Utils/AI/AIInvestigationQueue.test.ts +15 -14
  382. package/Tests/Server/Utils/AI/AgentContextCompactor.test.ts +351 -0
  383. package/Tests/Server/Utils/AI/ChatAgentRunnerSharedThread.test.ts +842 -0
  384. package/Tests/Server/Utils/AI/ChatRunCancellation.test.ts +195 -0
  385. package/Tests/Server/Utils/AI/CodeFixReadiness.test.ts +10 -57
  386. package/Tests/Server/Utils/AI/FixRunBudget.test.ts +20 -24
  387. package/Tests/Server/Utils/AI/Insights/InvestigationQueueInsightSubject.test.ts +7 -30
  388. package/Tests/Server/Utils/AI/InvestigationClusterAccessWiring.test.ts +225 -29
  389. package/Tests/Server/Utils/AI/InvestigationInfrastructureAccessWiring.test.ts +694 -0
  390. package/Tests/Server/Utils/AI/InvestigationInfrastructureReport.test.ts +721 -0
  391. package/Tests/Server/Utils/AI/InvestigationThread.test.ts +580 -0
  392. package/Tests/Server/Utils/AI/InvestigationThreadService.test.ts +801 -0
  393. package/Tests/Server/Utils/AI/KubectlInvestigationToolkit.test.ts +525 -43
  394. package/Tests/Server/Utils/AI/KubectlJobRunner.test.ts +4 -2
  395. package/Tests/Server/Utils/AI/LLMServiceUnreachableProvider.test.ts +435 -0
  396. package/Tests/Server/Utils/AI/ObservabilityAssistantLimits.test.ts +462 -0
  397. package/Tests/Server/Utils/AI/RemediationCommandTools.test.ts +94 -1
  398. package/Tests/Server/Utils/AI/RemediationCommandToolsResource.test.ts +1530 -0
  399. package/Tests/Server/Utils/AI/RemediationExecutionRunner.test.ts +14 -25
  400. package/Tests/Server/Utils/AI/RemediationExecutionRunnerResourceMode.test.ts +1251 -0
  401. package/Tests/Server/Utils/AI/RemediationPlanRunner.test.ts +117 -0
  402. package/Tests/Server/Utils/AI/RemediationResourceCopyParity.test.ts +463 -0
  403. package/Tests/Server/Utils/AI/ResourceAccess/InfrastructureInvestigationToolkit.test.ts +1004 -0
  404. package/Tests/Server/Utils/AI/ResourceAccess/ResourceAccessContext.test.ts +266 -0
  405. package/Tests/Server/Utils/AI/ResourceAccess/ResourceAiAccessSettings.test.ts +1220 -0
  406. package/Tests/Server/Utils/AI/ResourceAccess/ResourceAiDeleteCleanup.test.ts +569 -0
  407. package/Tests/Server/Utils/AI/ResourceAccess/ResourceCommandJobRunner.test.ts +834 -0
  408. package/Tests/Server/Utils/AI/ToolOutputPager.test.ts +382 -0
  409. package/Tests/Server/Utils/AI/ToolResultSerializer.test.ts +23 -4
  410. package/Tests/Server/Utils/AI/Toolbox/LogTools.test.ts +25 -6
  411. package/Tests/Server/Utils/AI/Toolbox/Serializer.test.ts +14 -3
  412. package/Tests/Server/Utils/AutoRemediation/CommandPlanExecutorResource.test.ts +717 -0
  413. package/Tests/Server/Utils/AutoRemediation/RemediationVerifierResourceFollowUp.test.ts +338 -0
  414. package/Tests/Server/Utils/EditionEnforcement.test.ts +107 -147
  415. package/Tests/Server/Utils/Monitor/Criteria/SessionReplayBudgetTemplateCriteria.test.ts +422 -0
  416. package/Tests/Server/Utils/{CommunityEditionSsoReport.test.ts → RelaxedScimTeamLocksReport.test.ts} +212 -208
  417. package/Tests/Server/Utils/SameOriginRequest.test.ts +372 -0
  418. package/Tests/Server/Utils/SessionReplay/SessionReplayBudgetMetrics.test.ts +1647 -0
  419. package/Tests/Server/Utils/SessionReplay/SessionReplayUsage.test.ts +143 -1
  420. package/Tests/Server/Utils/Telemetry/EntityRegistry.test.ts +20 -0
  421. package/Tests/Server/Utils/Telemetry/MessageQueueDiscovery.test.ts +2590 -0
  422. package/Tests/Server/Utils/Telemetry/MessageQueueSpanQueryTwin.ts +246 -0
  423. package/Tests/Server/Utils/Telemetry/TelemetryEntity.test.ts +23 -0
  424. package/Tests/Server/Utils/Telemetry/TelemetryIngestionKeyGuard.test.ts +33 -3
  425. package/Tests/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsAccountNotLinked.test.ts +1093 -0
  426. package/Tests/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsActivityDeduplicator.test.ts +1049 -0
  427. package/Tests/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsCardChoices.test.ts +1676 -0
  428. package/Tests/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsCreateCards.test.ts +2884 -0
  429. package/Tests/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsCreateCommands.test.ts +2490 -0
  430. package/Tests/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsCreateSubmit.test.ts +2293 -0
  431. package/Tests/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsCreateSubmitServerTimezone.test.ts +386 -0
  432. package/Tests/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsMessageSize.test.ts +1477 -0
  433. package/Tests/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsReplies.test.ts +1967 -0
  434. package/Tests/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsStripHtmlTags.test.ts +92 -0
  435. package/Tests/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsSubmittedFormRemoval.test.ts +1819 -0
  436. package/Tests/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsTimezone.test.ts +1033 -0
  437. package/Tests/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsTimezoneServerZone.test.ts +610 -0
  438. package/Tests/Server/Utils/Workspace/MicrosoftTeamsBotMessageHandling.test.ts +2610 -0
  439. package/Tests/Server/Utils/Workspace/MicrosoftTeamsCreateCommandsEndToEnd.test.ts +4672 -0
  440. package/Tests/Server/Utils/Workspace/WorkspaceCreateProjectReferences.test.ts +190 -65
  441. package/Tests/Types/AI/AIAgentRunLimits.test.ts +255 -0
  442. package/Tests/Types/AutoRemediation/AiRemediationCommandPlan.test.ts +10 -4
  443. package/Tests/Types/AutoRemediation/AiRemediationCommandPlanResourceCommand.test.ts +305 -0
  444. package/Tests/Types/Code/JsonSyntax.test.ts +1300 -0
  445. package/Tests/Types/CustomField/CustomFieldCreateSettings.test.ts +1113 -0
  446. package/Tests/Types/CustomField/CustomFieldMappingCatalog.test.ts +91 -0
  447. package/Tests/Types/CustomField/CustomFieldValueValidator.test.ts +30 -0
  448. package/Tests/Types/Incident/IncidentFormIpAllowlist.test.ts +227 -0
  449. package/Tests/Types/Incident/IncidentFormPublic.test.ts +1916 -0
  450. package/Tests/Types/MessageQueue/MessageQueueEntityKey.test.ts +916 -0
  451. package/Tests/Types/MessageQueue/MessageQueueIdentity.test.ts +567 -0
  452. package/Tests/Types/MessageQueue/MessageQueueManualIdentity.test.ts +686 -0
  453. package/Tests/Types/MessageQueue/MessageQueueMetricCatalog.test.ts +1726 -0
  454. package/Tests/Types/MessageQueue/MessageQueueMetricResolution.test.ts +1758 -0
  455. package/Tests/Types/MessageQueue/MessagingInstrumentationFixtures.test.ts +4686 -0
  456. package/Tests/Types/MessageQueue/MessagingSystem.test.ts +840 -0
  457. package/Tests/Types/MessageQueue/MessagingTelemetryFixtures.ts +3287 -0
  458. package/Tests/Types/MessageQueue/MessagingTelemetryResolver.test.ts +2966 -0
  459. package/Tests/Types/Monitor/MessageQueueAlertTemplates.test.ts +5401 -0
  460. package/Tests/Types/Monitor/MetricEngineFold.ts +154 -0
  461. package/Tests/Types/Monitor/Recommendation/MonitorRecommendationCatalog.test.ts +277 -13
  462. package/Tests/Types/Monitor/Recommendation/MonitorRecommendationUtil.test.ts +113 -0
  463. package/Tests/Types/Monitor/RumAlertTemplates.test.ts +773 -2
  464. package/Tests/Types/ResourceAiAgent/AiResourceType.test.ts +419 -0
  465. package/Tests/Types/ResourceAiAgent/ResourceAiAccess.test.ts +519 -0
  466. package/Tests/Types/Runbook/RunbookStepType.test.ts +147 -8
  467. package/Tests/Types/Team/ComplianceRule.test.ts +588 -37
  468. package/Tests/Types/Team/TeamComplianceStatus.test.ts +64 -11
  469. package/Tests/Types/XML.test.ts +51 -0
  470. package/Tests/UI/Components/CodeEditor/CodeEditor.test.tsx +2362 -0
  471. package/Tests/UI/Components/CodeEditor/CodeEditorCommands.test.ts +810 -0
  472. package/Tests/UI/Components/CodeEditor/CodeEditorHighlight.test.ts +338 -0
  473. package/Tests/UI/Components/CodeEditor/CodeEditorLanguages.test.ts +222 -0
  474. package/Tests/UI/Components/CodeEditor/CodeEditorStyles.test.ts +807 -0
  475. package/Tests/UI/Components/CodeEditor/NoMonaco.test.ts +245 -0
  476. package/Tests/UI/Components/CodeEditor/YamlEditor.test.tsx +729 -0
  477. package/Tests/UI/Components/CopyTextButton.test.tsx +76 -0
  478. package/Tests/UI/Components/EditionLabelLapseCopy.ts +51 -14
  479. package/Tests/UI/Components/EditionLabelLicenseStatus.test.tsx +131 -23
  480. package/Tests/UI/Components/ErrorMessageAction.test.tsx +142 -0
  481. package/Tests/UI/Components/FacetSidebarInScope.test.tsx +459 -0
  482. package/Tests/UI/Components/FacetValuesInScope.test.ts +270 -0
  483. package/Tests/UI/Components/Forms/FormFieldCodeEditors.test.tsx +294 -0
  484. package/Tests/UI/Components/Forms/FormFieldMarkdown.test.tsx +126 -0
  485. package/Tests/UI/Components/Forms/FormFieldYaml.test.tsx +22 -75
  486. package/Tests/UI/Components/Forms/ModelFormOnBeforeCreateMiscData.test.tsx +254 -0
  487. package/Tests/UI/Components/Icon.test.tsx +32 -0
  488. package/Tests/UI/Components/Input.test.tsx +31 -0
  489. package/Tests/UI/Components/LockedFilterChipScope.test.tsx +501 -0
  490. package/Tests/UI/Components/MarkdownConverters.test.ts +253 -1
  491. package/Tests/UI/Components/MarkdownEditor.test.tsx +2785 -2
  492. package/Tests/UI/Components/MarkdownEditorHistory.test.ts +243 -0
  493. package/Tests/UI/Components/MarkdownListEditing.test.ts +1118 -0
  494. package/Tests/UI/Components/MarkdownPaste.test.ts +1180 -0
  495. package/Tests/UI/Components/MarkdownViewerCopy.test.tsx +466 -0
  496. package/Tests/UI/Components/MarkdownVisualEditing.test.ts +1089 -0
  497. package/Tests/UI/Components/ModelTable/BaseModelTableEmptyStateAction.test.tsx +623 -0
  498. package/Tests/UI/Components/ResetObjectID.test.tsx +282 -0
  499. package/Tests/UI/Components/RuleCriteria/RuleCriteriaModelTable.test.tsx +3 -3
  500. package/Tests/UI/Components/Table/EmptyTableMessage.test.ts +439 -0
  501. package/Tests/UI/Components/Table/TableEmptyState.test.tsx +352 -0
  502. package/Tests/UI/Components/TableRowMobileTitles.test.tsx +78 -0
  503. package/Tests/UI/Components/TextArea.test.tsx +19 -0
  504. package/Tests/UI/Components/Workflow/ModelColumnEditor.render.test.tsx +12 -29
  505. package/Tests/UI/Components/fixtures/MarkdownPasteFixtures.ts +460 -0
  506. package/Tests/UI/EsbuildConfig.test.ts +115 -39
  507. package/Tests/UI/EsbuildEnterpriseAlias.test.ts +4 -4
  508. package/Tests/UI/Monitor/MonitorLogSummaryRender.test.tsx +377 -0
  509. package/Tests/UI/Rum/RecordingHealthDashboard.test.tsx +769 -1
  510. package/Tests/UI/Utils/Breadcrumb/fixtures/RealBreadcrumbTrails.ts +81 -1
  511. package/Tests/UI/Utils/Breadcrumb/fixtures/RealRoutePatterns.ts +17 -0
  512. package/Tests/Utils/AiRemediation/Resource/CephCommandPolicy.test.ts +1653 -0
  513. package/Tests/Utils/AiRemediation/Resource/CephOutputRedaction.test.ts +204 -0
  514. package/Tests/Utils/AiRemediation/Resource/DatabaseCommandPolicy.test.ts +1077 -0
  515. package/Tests/Utils/AiRemediation/Resource/DatabaseDiagnosticCatalog.test.ts +558 -0
  516. package/Tests/Utils/AiRemediation/Resource/DatabaseQueryRedactor.test.ts +834 -0
  517. package/Tests/Utils/AiRemediation/Resource/DockerCliGrammar.test.ts +747 -0
  518. package/Tests/Utils/AiRemediation/Resource/DockerEngineCommandPolicy.test.ts +1259 -0
  519. package/Tests/Utils/AiRemediation/Resource/DockerOutputRedaction.test.ts +386 -0
  520. package/Tests/Utils/AiRemediation/Resource/DockerSwarmCommandPolicy.test.ts +782 -0
  521. package/Tests/Utils/AiRemediation/Resource/GovcCommandPolicy.test.ts +2259 -0
  522. package/Tests/Utils/AiRemediation/Resource/HostCommandPolicy.test.ts +2019 -0
  523. package/Tests/Utils/AiRemediation/Resource/ProxmoxCommandPolicy.test.ts +2497 -0
  524. package/Tests/Utils/AiRemediation/Resource/ResourceCommandPolicy.test.ts +1305 -0
  525. package/Tests/Utils/AiRemediation/Resource/ResourceCommandPolicyCore.test.ts +585 -0
  526. package/Tests/Utils/AiRemediation/Resource/ResourceOutputRedactor.test.ts +334 -0
  527. package/Tests/Utils/AiRemediation/Resource/ResourceOutputRedactorCopyParity.test.ts +98 -0
  528. package/Tests/Utils/AiRemediation/Resource/ResourcePolicyImportClosure.test.ts +391 -0
  529. package/Tests/Utils/AiRemediation/ResourceAiAgentPolicyCopyParity.test.ts +497 -0
  530. package/Tests/Utils/LabelRuleImportExport.test.ts +5 -0
  531. package/Tests/Utils/Markdown/DashboardMarkdownRenderer.ts +81 -0
  532. package/Tests/Utils/Markdown/UntrustedMarkdown.test.ts +1339 -0
  533. package/Tests/Utils/Monitor/MonitorLogSummaryUtil.test.ts +862 -0
  534. package/Tests/Utils/SessionReplay/SessionReplayBudgetMetricType.test.ts +383 -0
  535. package/Types/AI/AIAgentRunLimits.ts +146 -0
  536. package/Types/AI/ResourceAiAccessApi.ts +140 -0
  537. package/Types/AI/ResourceAiAccessPermissions.ts +126 -0
  538. package/Types/AutoRemediation/AiRemediationCommandPlan.ts +183 -2
  539. package/Types/Code/CodeType.ts +2 -0
  540. package/Types/Code/JsonSyntax.ts +923 -0
  541. package/Types/CustomField/CustomFieldCreateSettings.ts +549 -0
  542. package/Types/CustomField/CustomFieldMappingCatalog.ts +77 -0
  543. package/Types/CustomField/CustomFieldValueValidator.ts +10 -7
  544. package/Types/EnterpriseLicense/EnterpriseLicensePeriods.ts +1 -1
  545. package/Types/Icon/IconProp.ts +2 -0
  546. package/Types/Incident/IncidentFormIpAllowlist.ts +206 -0
  547. package/Types/Incident/IncidentFormPublic.ts +1145 -0
  548. package/Types/Kubernetes/KubernetesClusterAiAccess.ts +10 -3
  549. package/Types/MessageQueue/MessageQueueIdentity.ts +256 -0
  550. package/Types/MessageQueue/MessageQueueManualIdentity.ts +325 -0
  551. package/Types/MessageQueue/MessageQueueMetricCatalog.ts +1357 -0
  552. package/Types/MessageQueue/MessagingSystem.ts +518 -0
  553. package/Types/MessageQueue/MessagingTelemetryResolver.ts +2311 -0
  554. package/Types/Monitor/MessageQueueAlertTemplates.ts +2128 -0
  555. package/Types/Monitor/Recommendation/MonitorRecommendationCatalog.ts +55 -22
  556. package/Types/Monitor/Recommendation/MonitorRecommendationTypes.ts +35 -3
  557. package/Types/Monitor/RumAlertTemplates.ts +351 -4
  558. package/Types/Permission.ts +310 -0
  559. package/Types/ResourceAiAgent/AiResourceType.ts +310 -0
  560. package/Types/ResourceAiAgent/ResourceAiAccess.ts +580 -0
  561. package/Types/Rules/RuleCriteriaFieldRegistry.ts +12 -0
  562. package/Types/Rules/RuleRun.ts +4 -0
  563. package/Types/Rum/SessionReplayBudgetMetricType.ts +47 -0
  564. package/Types/Runbook/RunbookStepType.ts +29 -0
  565. package/Types/Team/ComplianceNotificationChannel.ts +4 -3
  566. package/Types/Team/ComplianceRule.ts +71 -18
  567. package/Types/Team/ComplianceRuleType.ts +2 -2
  568. package/Types/Team/TeamComplianceStatus.ts +6 -2
  569. package/Types/Telemetry/EntityType.ts +16 -0
  570. package/Types/Telemetry/LockedFilterDetail.ts +22 -0
  571. package/Types/Telemetry/TelemetryIngestSurface.ts +14 -2
  572. package/Types/XML.ts +26 -0
  573. package/UI/Components/CodeEditor/CodeEditor.css +379 -0
  574. package/UI/Components/CodeEditor/CodeEditor.tsx +1128 -294
  575. package/UI/Components/CodeEditor/CodeEditorCommands.ts +774 -0
  576. package/UI/Components/CodeEditor/CodeEditorHighlight.ts +106 -0
  577. package/UI/Components/CodeEditor/CodeEditorLanguages.ts +164 -0
  578. package/UI/Components/CodeEditor/YamlEditor.tsx +28 -326
  579. package/UI/Components/CopyTextButton/CopyTextButton.tsx +5 -1
  580. package/UI/Components/CustomFields/CustomFieldModelFormFields.tsx +6 -25
  581. package/UI/Components/EditionLabel/EditionLabel.tsx +14 -13
  582. package/UI/Components/ErrorMessage/ErrorMessage.tsx +11 -1
  583. package/UI/Components/Forms/Fields/FormField.tsx +8 -0
  584. package/UI/Components/Forms/Types/Field.ts +8 -0
  585. package/UI/Components/Icon/Icon.tsx +18 -0
  586. package/UI/Components/Input/Input.tsx +11 -4
  587. package/UI/Components/LogsViewer/LogsViewer.tsx +4 -0
  588. package/UI/Components/LogsViewer/components/LogsFacetSidebar.tsx +21 -3
  589. package/UI/Components/Markdown.tsx/MarkdownConverters.ts +0 -0
  590. package/UI/Components/Markdown.tsx/MarkdownEditor.tsx +877 -79
  591. package/UI/Components/Markdown.tsx/MarkdownEditorHistory.ts +284 -0
  592. package/UI/Components/Markdown.tsx/MarkdownListEditing.ts +1362 -0
  593. package/UI/Components/Markdown.tsx/MarkdownPaste.ts +1326 -0
  594. package/UI/Components/Markdown.tsx/MarkdownViewer.tsx +106 -10
  595. package/UI/Components/Markdown.tsx/MarkdownVisualEditing.ts +1032 -0
  596. package/UI/Components/ModelTable/BaseModelTable.tsx +85 -7
  597. package/UI/Components/ResetObjectID/ResetObjectID.tsx +35 -9
  598. package/UI/Components/Table/EmptyTableMessage.ts +81 -0
  599. package/UI/Components/Table/Table.tsx +50 -21
  600. package/UI/Components/Table/TableRow.tsx +9 -1
  601. package/UI/Components/TelemetryViewer/FacetVisibility.ts +97 -2
  602. package/UI/Components/TelemetryViewer/TelemetryViewer.tsx +13 -0
  603. package/UI/Components/TelemetryViewer/components/LockedFilterChip.tsx +214 -7
  604. package/UI/Components/TelemetryViewer/components/TelemetryFacetSidebar.tsx +21 -3
  605. package/UI/Components/TextArea/TextArea.tsx +9 -2
  606. package/UI/Components/Workflow/ModelFieldPicker.tsx +10 -12
  607. package/UI/Styles/Theme.css +8 -0
  608. package/UI/esbuild-config.js +2 -32
  609. package/Utils/AI/InvestigationReport.ts +121 -15
  610. package/Utils/AiRemediation/Resource/CephCommandPolicy.ts +1936 -0
  611. package/Utils/AiRemediation/Resource/DatabaseCommandPolicy.ts +166 -0
  612. package/Utils/AiRemediation/Resource/DatabaseDiagnosticCatalog.ts +1532 -0
  613. package/Utils/AiRemediation/Resource/DatabaseQueryRedactor.ts +1394 -0
  614. package/Utils/AiRemediation/Resource/DockerCliGrammar.ts +1839 -0
  615. package/Utils/AiRemediation/Resource/DockerEngineCommandPolicy.ts +490 -0
  616. package/Utils/AiRemediation/Resource/DockerSwarmCommandPolicy.ts +687 -0
  617. package/Utils/AiRemediation/Resource/GovcCommandPolicy.ts +2096 -0
  618. package/Utils/AiRemediation/Resource/HostCommandPolicy.ts +2982 -0
  619. package/Utils/AiRemediation/Resource/ProxmoxCommandPolicy.ts +1679 -0
  620. package/Utils/AiRemediation/Resource/ResourceCommandPolicy.ts +851 -0
  621. package/Utils/AiRemediation/Resource/ResourceCommandPolicyCore.ts +593 -0
  622. package/Utils/AiRemediation/Resource/ResourceOutputRedactor.ts +2812 -0
  623. package/Utils/LabelRuleImportExport.ts +2 -0
  624. package/Utils/Markdown/UntrustedMarkdown.ts +1513 -0
  625. package/Utils/Monitor/IncomingEmailMonitorRequestUtil.ts +41 -0
  626. package/Utils/Monitor/MonitorLogSummaryUtil.ts +212 -0
  627. package/Utils/SessionReplay/SessionReplayBudgetMetricType.ts +184 -0
  628. package/Utils/Telemetry/EntityKey.ts +48 -0
  629. package/build/dist/Models/DatabaseModels/AIConversation.js +125 -1
  630. package/build/dist/Models/DatabaseModels/AIConversation.js.map +1 -1
  631. package/build/dist/Models/DatabaseModels/AutoRemediationSuggestion.js +62 -0
  632. package/build/dist/Models/DatabaseModels/AutoRemediationSuggestion.js.map +1 -1
  633. package/build/dist/Models/DatabaseModels/CephCluster.js +231 -0
  634. package/build/dist/Models/DatabaseModels/CephCluster.js.map +1 -1
  635. package/build/dist/Models/DatabaseModels/CloudResource.js +12 -0
  636. package/build/dist/Models/DatabaseModels/CloudResource.js.map +1 -1
  637. package/build/dist/Models/DatabaseModels/DatabaseServer.js +231 -0
  638. package/build/dist/Models/DatabaseModels/DatabaseServer.js.map +1 -1
  639. package/build/dist/Models/DatabaseModels/DockerHost.js +231 -0
  640. package/build/dist/Models/DatabaseModels/DockerHost.js.map +1 -1
  641. package/build/dist/Models/DatabaseModels/DockerSwarmCluster.js +231 -0
  642. package/build/dist/Models/DatabaseModels/DockerSwarmCluster.js.map +1 -1
  643. package/build/dist/Models/DatabaseModels/GlobalConfig.js +1 -1
  644. package/build/dist/Models/DatabaseModels/GlobalConfig.js.map +1 -1
  645. package/build/dist/Models/DatabaseModels/GlobalOidc.js +0 -4
  646. package/build/dist/Models/DatabaseModels/GlobalOidc.js.map +1 -1
  647. package/build/dist/Models/DatabaseModels/GlobalOidcProject.js +0 -4
  648. package/build/dist/Models/DatabaseModels/GlobalOidcProject.js.map +1 -1
  649. package/build/dist/Models/DatabaseModels/GlobalSso.js +0 -4
  650. package/build/dist/Models/DatabaseModels/GlobalSso.js.map +1 -1
  651. package/build/dist/Models/DatabaseModels/GlobalSsoProject.js +0 -4
  652. package/build/dist/Models/DatabaseModels/GlobalSsoProject.js.map +1 -1
  653. package/build/dist/Models/DatabaseModels/Host.js +231 -0
  654. package/build/dist/Models/DatabaseModels/Host.js.map +1 -1
  655. package/build/dist/Models/DatabaseModels/IncidentForm.js +605 -0
  656. package/build/dist/Models/DatabaseModels/IncidentForm.js.map +1 -0
  657. package/build/dist/Models/DatabaseModels/IncidentFormSubmission.js +299 -0
  658. package/build/dist/Models/DatabaseModels/IncidentFormSubmission.js.map +1 -0
  659. package/build/dist/Models/DatabaseModels/IncidentTemplate.js +60 -0
  660. package/build/dist/Models/DatabaseModels/IncidentTemplate.js.map +1 -1
  661. package/build/dist/Models/DatabaseModels/Index.js +16 -0
  662. package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
  663. package/build/dist/Models/DatabaseModels/IoTFleet.js +12 -0
  664. package/build/dist/Models/DatabaseModels/IoTFleet.js.map +1 -1
  665. package/build/dist/Models/DatabaseModels/KubernetesCluster.js +12 -0
  666. package/build/dist/Models/DatabaseModels/KubernetesCluster.js.map +1 -1
  667. package/build/dist/Models/DatabaseModels/MessageQueue.js +1106 -0
  668. package/build/dist/Models/DatabaseModels/MessageQueue.js.map +1 -0
  669. package/build/dist/Models/DatabaseModels/MessageQueueLabelRule.js +562 -0
  670. package/build/dist/Models/DatabaseModels/MessageQueueLabelRule.js.map +1 -0
  671. package/build/dist/Models/DatabaseModels/MessageQueueOwnerRule.js +643 -0
  672. package/build/dist/Models/DatabaseModels/MessageQueueOwnerRule.js.map +1 -0
  673. package/build/dist/Models/DatabaseModels/MessageQueueOwnerTeam.js +506 -0
  674. package/build/dist/Models/DatabaseModels/MessageQueueOwnerTeam.js.map +1 -0
  675. package/build/dist/Models/DatabaseModels/MessageQueueOwnerUser.js +505 -0
  676. package/build/dist/Models/DatabaseModels/MessageQueueOwnerUser.js.map +1 -0
  677. package/build/dist/Models/DatabaseModels/PodmanHost.js +231 -0
  678. package/build/dist/Models/DatabaseModels/PodmanHost.js.map +1 -1
  679. package/build/dist/Models/DatabaseModels/Project.js +61 -0
  680. package/build/dist/Models/DatabaseModels/Project.js.map +1 -1
  681. package/build/dist/Models/DatabaseModels/ProjectOidc.js +0 -4
  682. package/build/dist/Models/DatabaseModels/ProjectOidc.js.map +1 -1
  683. package/build/dist/Models/DatabaseModels/ProjectSso.js +0 -4
  684. package/build/dist/Models/DatabaseModels/ProjectSso.js.map +1 -1
  685. package/build/dist/Models/DatabaseModels/ProxmoxCluster.js +231 -0
  686. package/build/dist/Models/DatabaseModels/ProxmoxCluster.js.map +1 -1
  687. package/build/dist/Models/DatabaseModels/ResourceAiAgent.js +439 -0
  688. package/build/dist/Models/DatabaseModels/ResourceAiAgent.js.map +1 -0
  689. package/build/dist/Models/DatabaseModels/RumApplication.js +12 -0
  690. package/build/dist/Models/DatabaseModels/RumApplication.js.map +1 -1
  691. package/build/dist/Models/DatabaseModels/RunnerJob.js +145 -0
  692. package/build/dist/Models/DatabaseModels/RunnerJob.js.map +1 -1
  693. package/build/dist/Models/DatabaseModels/ServerlessFunction.js +12 -0
  694. package/build/dist/Models/DatabaseModels/ServerlessFunction.js.map +1 -1
  695. package/build/dist/Models/DatabaseModels/Service.js +12 -0
  696. package/build/dist/Models/DatabaseModels/Service.js.map +1 -1
  697. package/build/dist/Models/DatabaseModels/StatusPageOidc.js +0 -4
  698. package/build/dist/Models/DatabaseModels/StatusPageOidc.js.map +1 -1
  699. package/build/dist/Models/DatabaseModels/StatusPageSso.js +0 -4
  700. package/build/dist/Models/DatabaseModels/StatusPageSso.js.map +1 -1
  701. package/build/dist/Models/DatabaseModels/TeamComplianceSetting.js +49 -3
  702. package/build/dist/Models/DatabaseModels/TeamComplianceSetting.js.map +1 -1
  703. package/build/dist/Models/DatabaseModels/VMwareVCenter.js +231 -0
  704. package/build/dist/Models/DatabaseModels/VMwareVCenter.js.map +1 -1
  705. package/build/dist/Server/API/AIChatAPI.js +9 -103
  706. package/build/dist/Server/API/AIChatAPI.js.map +1 -1
  707. package/build/dist/Server/API/AIInvestigationAPI.js +3 -3
  708. package/build/dist/Server/API/AIInvestigationAPI.js.map +1 -1
  709. package/build/dist/Server/API/AIInvestigationConversationAPI.js +162 -0
  710. package/build/dist/Server/API/AIInvestigationConversationAPI.js.map +1 -0
  711. package/build/dist/Server/API/AutoRemediationAPI.js +231 -1
  712. package/build/dist/Server/API/AutoRemediationAPI.js.map +1 -1
  713. package/build/dist/Server/API/IncidentFormAPI.js +245 -0
  714. package/build/dist/Server/API/IncidentFormAPI.js.map +1 -0
  715. package/build/dist/Server/API/ProjectOIDC.js +16 -24
  716. package/build/dist/Server/API/ProjectOIDC.js.map +1 -1
  717. package/build/dist/Server/API/ProjectSSO.js +16 -24
  718. package/build/dist/Server/API/ProjectSSO.js.map +1 -1
  719. package/build/dist/Server/API/ResourceAiAccessAPI.js +1119 -0
  720. package/build/dist/Server/API/ResourceAiAccessAPI.js.map +1 -0
  721. package/build/dist/Server/API/StatusPageAPI.js +42 -75
  722. package/build/dist/Server/API/StatusPageAPI.js.map +1 -1
  723. package/build/dist/Server/Enterprise/EnterpriseEdition.js +79 -25
  724. package/build/dist/Server/Enterprise/EnterpriseEdition.js.map +1 -1
  725. package/build/dist/Server/Enterprise/EnterpriseFeature.js +24 -3
  726. package/build/dist/Server/Enterprise/EnterpriseFeature.js.map +1 -1
  727. package/build/dist/Server/Enterprise/EnterpriseLicenseSnapshot.js +1 -1
  728. package/build/dist/Server/Enterprise/EnterpriseServerModule.js.map +1 -1
  729. package/build/dist/Server/EnvironmentConfig.js +1 -1
  730. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1796300000000-AddResourceAiAgents.js +168 -0
  731. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1796300000000-AddResourceAiAgents.js.map +1 -0
  732. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1796400000000-AddIncidentForms.js +63 -0
  733. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1796400000000-AddIncidentForms.js.map +1 -0
  734. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1796500000000-AddTeamComplianceRuleNotificationChannels.js +41 -0
  735. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1796500000000-AddTeamComplianceRuleNotificationChannels.js.map +1 -0
  736. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1796600000000-AddAIInvestigationConversationAndTimeLimits.js +40 -0
  737. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1796600000000-AddAIInvestigationConversationAndTimeLimits.js.map +1 -0
  738. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1796700000000-AddMessageQueueTables.js +183 -0
  739. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1796700000000-AddMessageQueueTables.js.map +1 -0
  740. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +10 -0
  741. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  742. package/build/dist/Server/Infrastructure/Semaphore.js +6 -0
  743. package/build/dist/Server/Infrastructure/Semaphore.js.map +1 -1
  744. package/build/dist/Server/Middleware/IncidentFormRateLimit.js +559 -0
  745. package/build/dist/Server/Middleware/IncidentFormRateLimit.js.map +1 -0
  746. package/build/dist/Server/Middleware/TelemetryIngest.js +12 -5
  747. package/build/dist/Server/Middleware/TelemetryIngest.js.map +1 -1
  748. package/build/dist/Server/Middleware/UserAuthorization.js +11 -30
  749. package/build/dist/Server/Middleware/UserAuthorization.js.map +1 -1
  750. package/build/dist/Server/Services/AIService.js +10 -13
  751. package/build/dist/Server/Services/AIService.js.map +1 -1
  752. package/build/dist/Server/Services/AnalyticsDatabaseService.js +26 -1
  753. package/build/dist/Server/Services/AnalyticsDatabaseService.js.map +1 -1
  754. package/build/dist/Server/Services/AutoRemediationRuleEngineService.js +601 -3
  755. package/build/dist/Server/Services/AutoRemediationRuleEngineService.js.map +1 -1
  756. package/build/dist/Server/Services/CephClusterService.js +104 -0
  757. package/build/dist/Server/Services/CephClusterService.js.map +1 -1
  758. package/build/dist/Server/Services/DatabaseServerService.js +99 -0
  759. package/build/dist/Server/Services/DatabaseServerService.js.map +1 -1
  760. package/build/dist/Server/Services/DockerHostService.js +104 -0
  761. package/build/dist/Server/Services/DockerHostService.js.map +1 -1
  762. package/build/dist/Server/Services/DockerSwarmClusterService.js +104 -0
  763. package/build/dist/Server/Services/DockerSwarmClusterService.js.map +1 -1
  764. package/build/dist/Server/Services/HostService.js +114 -2
  765. package/build/dist/Server/Services/HostService.js.map +1 -1
  766. package/build/dist/Server/Services/IncidentCustomFieldService.js +83 -0
  767. package/build/dist/Server/Services/IncidentCustomFieldService.js.map +1 -1
  768. package/build/dist/Server/Services/IncidentEpisodeMemberService.js +8 -4
  769. package/build/dist/Server/Services/IncidentEpisodeMemberService.js.map +1 -1
  770. package/build/dist/Server/Services/IncidentEpisodeService.js +10 -1
  771. package/build/dist/Server/Services/IncidentEpisodeService.js.map +1 -1
  772. package/build/dist/Server/Services/IncidentFormService.js +1202 -0
  773. package/build/dist/Server/Services/IncidentFormService.js.map +1 -0
  774. package/build/dist/Server/Services/IncidentFormSubmissionService.js +91 -0
  775. package/build/dist/Server/Services/IncidentFormSubmissionService.js.map +1 -0
  776. package/build/dist/Server/Services/IncidentGroupingEngineService.js +20 -8
  777. package/build/dist/Server/Services/IncidentGroupingEngineService.js.map +1 -1
  778. package/build/dist/Server/Services/IncidentService.js +106 -4
  779. package/build/dist/Server/Services/IncidentService.js.map +1 -1
  780. package/build/dist/Server/Services/IncidentTemplateService.js +18 -0
  781. package/build/dist/Server/Services/IncidentTemplateService.js.map +1 -1
  782. package/build/dist/Server/Services/Index.js +14 -0
  783. package/build/dist/Server/Services/Index.js.map +1 -1
  784. package/build/dist/Server/Services/MessageQueueLabelRuleEngineService.js +262 -0
  785. package/build/dist/Server/Services/MessageQueueLabelRuleEngineService.js.map +1 -0
  786. package/build/dist/Server/Services/MessageQueueLabelRuleService.js +13 -0
  787. package/build/dist/Server/Services/MessageQueueLabelRuleService.js.map +1 -0
  788. package/build/dist/Server/Services/MessageQueueOwnerRuleEngineService.js +334 -0
  789. package/build/dist/Server/Services/MessageQueueOwnerRuleEngineService.js.map +1 -0
  790. package/build/dist/Server/Services/MessageQueueOwnerRuleService.js +13 -0
  791. package/build/dist/Server/Services/MessageQueueOwnerRuleService.js.map +1 -0
  792. package/build/dist/Server/Services/MessageQueueOwnerTeamService.js +62 -0
  793. package/build/dist/Server/Services/MessageQueueOwnerTeamService.js.map +1 -0
  794. package/build/dist/Server/Services/MessageQueueOwnerUserService.js +62 -0
  795. package/build/dist/Server/Services/MessageQueueOwnerUserService.js.map +1 -0
  796. package/build/dist/Server/Services/MessageQueueService.js +1140 -0
  797. package/build/dist/Server/Services/MessageQueueService.js.map +1 -0
  798. package/build/dist/Server/Services/MetricRecordingRuleService.js +46 -0
  799. package/build/dist/Server/Services/MetricRecordingRuleService.js.map +1 -1
  800. package/build/dist/Server/Services/OpenTelemetryIngestService.js +25 -4
  801. package/build/dist/Server/Services/OpenTelemetryIngestService.js.map +1 -1
  802. package/build/dist/Server/Services/PodmanHostService.js +104 -0
  803. package/build/dist/Server/Services/PodmanHostService.js.map +1 -1
  804. package/build/dist/Server/Services/ProjectService.js +0 -54
  805. package/build/dist/Server/Services/ProjectService.js.map +1 -1
  806. package/build/dist/Server/Services/ProxmoxClusterService.js +104 -0
  807. package/build/dist/Server/Services/ProxmoxClusterService.js.map +1 -1
  808. package/build/dist/Server/Services/ResourceAiAccessService.js +1028 -0
  809. package/build/dist/Server/Services/ResourceAiAccessService.js.map +1 -0
  810. package/build/dist/Server/Services/ResourceAiAgentJobService.js +173 -0
  811. package/build/dist/Server/Services/ResourceAiAgentJobService.js.map +1 -0
  812. package/build/dist/Server/Services/ResourceAiAgentService.js +1687 -0
  813. package/build/dist/Server/Services/ResourceAiAgentService.js.map +1 -0
  814. package/build/dist/Server/Services/RunnerJobService.js +344 -5
  815. package/build/dist/Server/Services/RunnerJobService.js.map +1 -1
  816. package/build/dist/Server/Services/StatusPagePrivateUserService.js +1 -4
  817. package/build/dist/Server/Services/StatusPagePrivateUserService.js.map +1 -1
  818. package/build/dist/Server/Services/StatusPageService.js +0 -46
  819. package/build/dist/Server/Services/StatusPageService.js.map +1 -1
  820. package/build/dist/Server/Services/TeamComplianceSettingService.js +120 -31
  821. package/build/dist/Server/Services/TeamComplianceSettingService.js.map +1 -1
  822. package/build/dist/Server/Services/TelemetryUsageBillingService.js +26 -0
  823. package/build/dist/Server/Services/TelemetryUsageBillingService.js.map +1 -1
  824. package/build/dist/Server/Services/TraceRecordingRuleService.js +37 -0
  825. package/build/dist/Server/Services/TraceRecordingRuleService.js.map +1 -1
  826. package/build/dist/Server/Services/UserNotificationRuleService.js +8 -1
  827. package/build/dist/Server/Services/UserNotificationRuleService.js.map +1 -1
  828. package/build/dist/Server/Services/VMwareVCenterService.js +104 -0
  829. package/build/dist/Server/Services/VMwareVCenterService.js.map +1 -1
  830. package/build/dist/Server/Services/WorkspaceNotificationSummaryService.js +12 -3
  831. package/build/dist/Server/Services/WorkspaceNotificationSummaryService.js.map +1 -1
  832. package/build/dist/Server/Types/Database/Permissions/CreatePermission.js +6 -3
  833. package/build/dist/Server/Types/Database/Permissions/CreatePermission.js.map +1 -1
  834. package/build/dist/Server/Types/Database/Permissions/EditionPermission.js +109 -37
  835. package/build/dist/Server/Types/Database/Permissions/EditionPermission.js.map +1 -1
  836. package/build/dist/Server/Types/Database/Permissions/OwnerTableRegistry.js +16 -0
  837. package/build/dist/Server/Types/Database/Permissions/OwnerTableRegistry.js.map +1 -1
  838. package/build/dist/Server/Types/Database/Permissions/TablePermission.js +3 -3
  839. package/build/dist/Server/Types/Database/Permissions/UpdatePermission.js +9 -6
  840. package/build/dist/Server/Types/Database/Permissions/UpdatePermission.js.map +1 -1
  841. package/build/dist/Server/Utils/AI/Chat/AgentContextCompactor.js +128 -0
  842. package/build/dist/Server/Utils/AI/Chat/AgentContextCompactor.js.map +1 -0
  843. package/build/dist/Server/Utils/AI/Chat/ChatAgentRunner.js +192 -50
  844. package/build/dist/Server/Utils/AI/Chat/ChatAgentRunner.js.map +1 -1
  845. package/build/dist/Server/Utils/AI/Chat/ChatRunCancellation.js +133 -0
  846. package/build/dist/Server/Utils/AI/Chat/ChatRunCancellation.js.map +1 -0
  847. package/build/dist/Server/Utils/AI/Chat/ObservabilityAssistant.js +53 -13
  848. package/build/dist/Server/Utils/AI/Chat/ObservabilityAssistant.js.map +1 -1
  849. package/build/dist/Server/Utils/AI/Chat/ObservabilityChatPrompt.js +1 -1
  850. package/build/dist/Server/Utils/AI/Chat/ToolOutputPager.js +206 -0
  851. package/build/dist/Server/Utils/AI/Chat/ToolOutputPager.js.map +1 -0
  852. package/build/dist/Server/Utils/AI/ClusterAccess/KubectlInvestigationToolkit.js +53 -26
  853. package/build/dist/Server/Utils/AI/ClusterAccess/KubectlInvestigationToolkit.js.map +1 -1
  854. package/build/dist/Server/Utils/AI/ClusterAccess/KubectlJobRunner.js +4 -2
  855. package/build/dist/Server/Utils/AI/ClusterAccess/KubectlJobRunner.js.map +1 -1
  856. package/build/dist/Server/Utils/AI/CodeFix/CodeFixReadiness.js +1 -29
  857. package/build/dist/Server/Utils/AI/CodeFix/CodeFixReadiness.js.map +1 -1
  858. package/build/dist/Server/Utils/AI/CodeFix/FixRunBudget.js +24 -24
  859. package/build/dist/Server/Utils/AI/CodeFix/FixRunBudget.js.map +1 -1
  860. package/build/dist/Server/Utils/AI/Remediation/RemediationCommandTools.js +1036 -32
  861. package/build/dist/Server/Utils/AI/Remediation/RemediationCommandTools.js.map +1 -1
  862. package/build/dist/Server/Utils/AI/Remediation/RemediationExecutionRunner.js +661 -41
  863. package/build/dist/Server/Utils/AI/Remediation/RemediationExecutionRunner.js.map +1 -1
  864. package/build/dist/Server/Utils/AI/Remediation/RemediationPlanRunner.js +21 -1
  865. package/build/dist/Server/Utils/AI/Remediation/RemediationPlanRunner.js.map +1 -1
  866. package/build/dist/Server/Utils/AI/ResourceAccess/InfrastructureInvestigationToolkit.js +354 -0
  867. package/build/dist/Server/Utils/AI/ResourceAccess/InfrastructureInvestigationToolkit.js.map +1 -0
  868. package/build/dist/Server/Utils/AI/ResourceAccess/ResourceAccessContext.js +160 -0
  869. package/build/dist/Server/Utils/AI/ResourceAccess/ResourceAccessContext.js.map +1 -0
  870. package/build/dist/Server/Utils/AI/ResourceAccess/ResourceAccessToolNames.js +33 -0
  871. package/build/dist/Server/Utils/AI/ResourceAccess/ResourceAccessToolNames.js.map +1 -0
  872. package/build/dist/Server/Utils/AI/ResourceAccess/ResourceAiAccessSettings.js +640 -0
  873. package/build/dist/Server/Utils/AI/ResourceAccess/ResourceAiAccessSettings.js.map +1 -0
  874. package/build/dist/Server/Utils/AI/ResourceAccess/ResourceAiDeleteCleanup.js +226 -0
  875. package/build/dist/Server/Utils/AI/ResourceAccess/ResourceAiDeleteCleanup.js.map +1 -0
  876. package/build/dist/Server/Utils/AI/ResourceAccess/ResourceCommandJobRunner.js +602 -0
  877. package/build/dist/Server/Utils/AI/ResourceAccess/ResourceCommandJobRunner.js.map +1 -0
  878. package/build/dist/Server/Utils/AI/SRE/AIInvestigationEngine.js +90 -14
  879. package/build/dist/Server/Utils/AI/SRE/AIInvestigationEngine.js.map +1 -1
  880. package/build/dist/Server/Utils/AI/SRE/AlertInvestigationRunner.js +73 -10
  881. package/build/dist/Server/Utils/AI/SRE/AlertInvestigationRunner.js.map +1 -1
  882. package/build/dist/Server/Utils/AI/SRE/IncidentInvestigationRunner.js +73 -10
  883. package/build/dist/Server/Utils/AI/SRE/IncidentInvestigationRunner.js.map +1 -1
  884. package/build/dist/Server/Utils/AI/SRE/InvestigationQueue.js +15 -18
  885. package/build/dist/Server/Utils/AI/SRE/InvestigationQueue.js.map +1 -1
  886. package/build/dist/Server/Utils/AI/SRE/InvestigationThread.js +412 -0
  887. package/build/dist/Server/Utils/AI/SRE/InvestigationThread.js.map +1 -0
  888. package/build/dist/Server/Utils/AI/SRE/InvestigationThreadService.js +495 -0
  889. package/build/dist/Server/Utils/AI/SRE/InvestigationThreadService.js.map +1 -0
  890. package/build/dist/Server/Utils/AI/Toolbox/Serializer.js +10 -3
  891. package/build/dist/Server/Utils/AI/Toolbox/Serializer.js.map +1 -1
  892. package/build/dist/Server/Utils/AutoRemediation/CommandPlanExecutor.js +290 -13
  893. package/build/dist/Server/Utils/AutoRemediation/CommandPlanExecutor.js.map +1 -1
  894. package/build/dist/Server/Utils/AutoRemediation/RemediationVerifier.js +29 -1
  895. package/build/dist/Server/Utils/AutoRemediation/RemediationVerifier.js.map +1 -1
  896. package/build/dist/Server/Utils/Database/ProjectScopedReferenceValidator.js +9 -1
  897. package/build/dist/Server/Utils/Database/ProjectScopedReferenceValidator.js.map +1 -1
  898. package/build/dist/Server/Utils/EditionEnforcement.js +20 -158
  899. package/build/dist/Server/Utils/EditionEnforcement.js.map +1 -1
  900. package/build/dist/Server/Utils/LLM/LLMService.js +193 -54
  901. package/build/dist/Server/Utils/LLM/LLMService.js.map +1 -1
  902. package/build/dist/Server/Utils/RelaxedScimTeamLocksReport.js +160 -0
  903. package/build/dist/Server/Utils/RelaxedScimTeamLocksReport.js.map +1 -0
  904. package/build/dist/Server/Utils/Rules/RuleRun/RuleRunRegistry.js +25 -0
  905. package/build/dist/Server/Utils/Rules/RuleRun/RuleRunRegistry.js.map +1 -1
  906. package/build/dist/Server/Utils/SameOriginRequest.js +151 -0
  907. package/build/dist/Server/Utils/SameOriginRequest.js.map +1 -0
  908. package/build/dist/Server/Utils/SessionReplay/SessionReplayBudgetMetrics.js +627 -0
  909. package/build/dist/Server/Utils/SessionReplay/SessionReplayBudgetMetrics.js.map +1 -0
  910. package/build/dist/Server/Utils/SessionReplay/SessionReplayUsage.js +60 -5
  911. package/build/dist/Server/Utils/SessionReplay/SessionReplayUsage.js.map +1 -1
  912. package/build/dist/Server/Utils/TeamMember/ProjectLeaveResourceCleanup.js +2 -0
  913. package/build/dist/Server/Utils/TeamMember/ProjectLeaveResourceCleanup.js.map +1 -1
  914. package/build/dist/Server/Utils/Telemetry/EntityRegistry.js +4 -1
  915. package/build/dist/Server/Utils/Telemetry/EntityRegistry.js.map +1 -1
  916. package/build/dist/Server/Utils/Telemetry/MessageQueueDiscovery.js +1015 -0
  917. package/build/dist/Server/Utils/Telemetry/MessageQueueDiscovery.js.map +1 -0
  918. package/build/dist/Server/Utils/Telemetry/ResourceEntityFilter.js +4 -1
  919. package/build/dist/Server/Utils/Telemetry/ResourceEntityFilter.js.map +1 -1
  920. package/build/dist/Server/Utils/VendorAssets.js +3 -3
  921. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/Alert.js +19 -15
  922. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/Alert.js.map +1 -1
  923. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/AlertEpisode.js +19 -15
  924. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/AlertEpisode.js.map +1 -1
  925. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/Auth.js +17 -1
  926. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/Auth.js.map +1 -1
  927. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/Incident.js +186 -210
  928. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/Incident.js.map +1 -1
  929. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/IncidentEpisode.js +22 -16
  930. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/IncidentEpisode.js.map +1 -1
  931. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/ScheduledMaintenance.js +233 -167
  932. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/ScheduledMaintenance.js.map +1 -1
  933. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js +273 -111
  934. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js.map +1 -1
  935. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsActivityDeduplicator.js +129 -0
  936. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsActivityDeduplicator.js.map +1 -0
  937. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsCardChoices.js +266 -0
  938. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsCardChoices.js.map +1 -0
  939. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsCreateCommands.js +258 -0
  940. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsCreateCommands.js.map +1 -0
  941. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsMessageSize.js +104 -0
  942. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsMessageSize.js.map +1 -0
  943. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsReplies.js +183 -0
  944. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsReplies.js.map +1 -0
  945. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsTimezone.js +123 -0
  946. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsTimezone.js.map +1 -0
  947. package/build/dist/Types/AI/AIAgentRunLimits.js +91 -0
  948. package/build/dist/Types/AI/AIAgentRunLimits.js.map +1 -0
  949. package/build/dist/Types/AI/ResourceAiAccessApi.js +30 -0
  950. package/build/dist/Types/AI/ResourceAiAccessApi.js.map +1 -0
  951. package/build/dist/Types/AI/ResourceAiAccessPermissions.js +98 -0
  952. package/build/dist/Types/AI/ResourceAiAccessPermissions.js.map +1 -0
  953. package/build/dist/Types/AutoRemediation/AiRemediationCommandPlan.js +116 -29
  954. package/build/dist/Types/AutoRemediation/AiRemediationCommandPlan.js.map +1 -1
  955. package/build/dist/Types/Code/CodeType.js +2 -0
  956. package/build/dist/Types/Code/CodeType.js.map +1 -1
  957. package/build/dist/Types/Code/JsonSyntax.js +604 -0
  958. package/build/dist/Types/Code/JsonSyntax.js.map +1 -0
  959. package/build/dist/Types/CustomField/CustomFieldCreateSettings.js +310 -0
  960. package/build/dist/Types/CustomField/CustomFieldCreateSettings.js.map +1 -0
  961. package/build/dist/Types/CustomField/CustomFieldMappingCatalog.js +38 -0
  962. package/build/dist/Types/CustomField/CustomFieldMappingCatalog.js.map +1 -1
  963. package/build/dist/Types/CustomField/CustomFieldValueValidator.js +10 -7
  964. package/build/dist/Types/CustomField/CustomFieldValueValidator.js.map +1 -1
  965. package/build/dist/Types/EnterpriseLicense/EnterpriseLicensePeriods.js +1 -1
  966. package/build/dist/Types/Icon/IconProp.js +2 -0
  967. package/build/dist/Types/Icon/IconProp.js.map +1 -1
  968. package/build/dist/Types/Incident/IncidentFormIpAllowlist.js +119 -0
  969. package/build/dist/Types/Incident/IncidentFormIpAllowlist.js.map +1 -0
  970. package/build/dist/Types/Incident/IncidentFormPublic.js +678 -0
  971. package/build/dist/Types/Incident/IncidentFormPublic.js.map +1 -0
  972. package/build/dist/Types/Kubernetes/KubernetesClusterAiAccess.js +10 -3
  973. package/build/dist/Types/Kubernetes/KubernetesClusterAiAccess.js.map +1 -1
  974. package/build/dist/Types/MessageQueue/MessageQueueIdentity.js +184 -0
  975. package/build/dist/Types/MessageQueue/MessageQueueIdentity.js.map +1 -0
  976. package/build/dist/Types/MessageQueue/MessageQueueManualIdentity.js +190 -0
  977. package/build/dist/Types/MessageQueue/MessageQueueManualIdentity.js.map +1 -0
  978. package/build/dist/Types/MessageQueue/MessageQueueMetricCatalog.js +1057 -0
  979. package/build/dist/Types/MessageQueue/MessageQueueMetricCatalog.js.map +1 -0
  980. package/build/dist/Types/MessageQueue/MessagingSystem.js +394 -0
  981. package/build/dist/Types/MessageQueue/MessagingSystem.js.map +1 -0
  982. package/build/dist/Types/MessageQueue/MessagingTelemetryResolver.js +1768 -0
  983. package/build/dist/Types/MessageQueue/MessagingTelemetryResolver.js.map +1 -0
  984. package/build/dist/Types/Monitor/MessageQueueAlertTemplates.js +1207 -0
  985. package/build/dist/Types/Monitor/MessageQueueAlertTemplates.js.map +1 -0
  986. package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationCatalog.js +47 -21
  987. package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationCatalog.js.map +1 -1
  988. package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationTypes.js +5 -0
  989. package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationTypes.js.map +1 -1
  990. package/build/dist/Types/Monitor/RumAlertTemplates.js +199 -3
  991. package/build/dist/Types/Monitor/RumAlertTemplates.js.map +1 -1
  992. package/build/dist/Types/Permission.js +274 -0
  993. package/build/dist/Types/Permission.js.map +1 -1
  994. package/build/dist/Types/ResourceAiAgent/AiResourceType.js +242 -0
  995. package/build/dist/Types/ResourceAiAgent/AiResourceType.js.map +1 -0
  996. package/build/dist/Types/ResourceAiAgent/ResourceAiAccess.js +281 -0
  997. package/build/dist/Types/ResourceAiAgent/ResourceAiAccess.js.map +1 -0
  998. package/build/dist/Types/Rules/RuleCriteriaFieldRegistry.js +12 -0
  999. package/build/dist/Types/Rules/RuleCriteriaFieldRegistry.js.map +1 -1
  1000. package/build/dist/Types/Rules/RuleRun.js +4 -0
  1001. package/build/dist/Types/Rules/RuleRun.js.map +1 -1
  1002. package/build/dist/Types/Rum/SessionReplayBudgetMetricType.js +45 -0
  1003. package/build/dist/Types/Rum/SessionReplayBudgetMetricType.js.map +1 -0
  1004. package/build/dist/Types/Runbook/RunbookStepType.js +27 -0
  1005. package/build/dist/Types/Runbook/RunbookStepType.js.map +1 -1
  1006. package/build/dist/Types/Team/ComplianceNotificationChannel.js +4 -3
  1007. package/build/dist/Types/Team/ComplianceNotificationChannel.js.map +1 -1
  1008. package/build/dist/Types/Team/ComplianceRule.js +48 -14
  1009. package/build/dist/Types/Team/ComplianceRule.js.map +1 -1
  1010. package/build/dist/Types/Team/ComplianceRuleType.js +2 -2
  1011. package/build/dist/Types/Telemetry/EntityType.js +16 -0
  1012. package/build/dist/Types/Telemetry/EntityType.js.map +1 -1
  1013. package/build/dist/Types/Telemetry/TelemetryIngestSurface.js +13 -2
  1014. package/build/dist/Types/Telemetry/TelemetryIngestSurface.js.map +1 -1
  1015. package/build/dist/Types/XML.js +23 -0
  1016. package/build/dist/Types/XML.js.map +1 -1
  1017. package/build/dist/UI/Components/CodeEditor/CodeEditor.js +641 -266
  1018. package/build/dist/UI/Components/CodeEditor/CodeEditor.js.map +1 -1
  1019. package/build/dist/UI/Components/CodeEditor/CodeEditorCommands.js +464 -0
  1020. package/build/dist/UI/Components/CodeEditor/CodeEditorCommands.js.map +1 -0
  1021. package/build/dist/UI/Components/CodeEditor/CodeEditorHighlight.js +69 -0
  1022. package/build/dist/UI/Components/CodeEditor/CodeEditorHighlight.js.map +1 -0
  1023. package/build/dist/UI/Components/CodeEditor/CodeEditorLanguages.js +108 -0
  1024. package/build/dist/UI/Components/CodeEditor/CodeEditorLanguages.js.map +1 -0
  1025. package/build/dist/UI/Components/CodeEditor/YamlEditor.js +14 -186
  1026. package/build/dist/UI/Components/CodeEditor/YamlEditor.js.map +1 -1
  1027. package/build/dist/UI/Components/CopyTextButton/CopyTextButton.js +5 -1
  1028. package/build/dist/UI/Components/CopyTextButton/CopyTextButton.js.map +1 -1
  1029. package/build/dist/UI/Components/CustomFields/CustomFieldModelFormFields.js +5 -14
  1030. package/build/dist/UI/Components/CustomFields/CustomFieldModelFormFields.js.map +1 -1
  1031. package/build/dist/UI/Components/EditionLabel/EditionLabel.js +14 -13
  1032. package/build/dist/UI/Components/EditionLabel/EditionLabel.js.map +1 -1
  1033. package/build/dist/UI/Components/ErrorMessage/ErrorMessage.js +1 -1
  1034. package/build/dist/UI/Components/ErrorMessage/ErrorMessage.js.map +1 -1
  1035. package/build/dist/UI/Components/Forms/Fields/FormField.js +8 -3
  1036. package/build/dist/UI/Components/Forms/Fields/FormField.js.map +1 -1
  1037. package/build/dist/UI/Components/Icon/Icon.js +8 -0
  1038. package/build/dist/UI/Components/Icon/Icon.js.map +1 -1
  1039. package/build/dist/UI/Components/Input/Input.js +11 -3
  1040. package/build/dist/UI/Components/Input/Input.js.map +1 -1
  1041. package/build/dist/UI/Components/LogsViewer/LogsViewer.js +2 -1
  1042. package/build/dist/UI/Components/LogsViewer/LogsViewer.js.map +1 -1
  1043. package/build/dist/UI/Components/LogsViewer/components/LogsFacetSidebar.js +14 -4
  1044. package/build/dist/UI/Components/LogsViewer/components/LogsFacetSidebar.js.map +1 -1
  1045. package/build/dist/UI/Components/Markdown.tsx/MarkdownConverters.js +0 -0
  1046. package/build/dist/UI/Components/Markdown.tsx/MarkdownConverters.js.map +1 -1
  1047. package/build/dist/UI/Components/Markdown.tsx/MarkdownEditor.js +710 -65
  1048. package/build/dist/UI/Components/Markdown.tsx/MarkdownEditor.js.map +1 -1
  1049. package/build/dist/UI/Components/Markdown.tsx/MarkdownEditorHistory.js +238 -0
  1050. package/build/dist/UI/Components/Markdown.tsx/MarkdownEditorHistory.js.map +1 -0
  1051. package/build/dist/UI/Components/Markdown.tsx/MarkdownListEditing.js +1028 -0
  1052. package/build/dist/UI/Components/Markdown.tsx/MarkdownListEditing.js.map +1 -0
  1053. package/build/dist/UI/Components/Markdown.tsx/MarkdownPaste.js +1088 -0
  1054. package/build/dist/UI/Components/Markdown.tsx/MarkdownPaste.js.map +1 -0
  1055. package/build/dist/UI/Components/Markdown.tsx/MarkdownViewer.js +70 -10
  1056. package/build/dist/UI/Components/Markdown.tsx/MarkdownViewer.js.map +1 -1
  1057. package/build/dist/UI/Components/Markdown.tsx/MarkdownVisualEditing.js +887 -0
  1058. package/build/dist/UI/Components/Markdown.tsx/MarkdownVisualEditing.js.map +1 -0
  1059. package/build/dist/UI/Components/ModelTable/BaseModelTable.js +57 -6
  1060. package/build/dist/UI/Components/ModelTable/BaseModelTable.js.map +1 -1
  1061. package/build/dist/UI/Components/ResetObjectID/ResetObjectID.js +7 -5
  1062. package/build/dist/UI/Components/ResetObjectID/ResetObjectID.js.map +1 -1
  1063. package/build/dist/UI/Components/Table/EmptyTableMessage.js +51 -0
  1064. package/build/dist/UI/Components/Table/EmptyTableMessage.js.map +1 -0
  1065. package/build/dist/UI/Components/Table/Table.js +30 -11
  1066. package/build/dist/UI/Components/Table/Table.js.map +1 -1
  1067. package/build/dist/UI/Components/Table/TableRow.js +9 -2
  1068. package/build/dist/UI/Components/Table/TableRow.js.map +1 -1
  1069. package/build/dist/UI/Components/TelemetryViewer/FacetVisibility.js +63 -1
  1070. package/build/dist/UI/Components/TelemetryViewer/FacetVisibility.js.map +1 -1
  1071. package/build/dist/UI/Components/TelemetryViewer/TelemetryViewer.js +4 -2
  1072. package/build/dist/UI/Components/TelemetryViewer/TelemetryViewer.js.map +1 -1
  1073. package/build/dist/UI/Components/TelemetryViewer/components/LockedFilterChip.js +91 -10
  1074. package/build/dist/UI/Components/TelemetryViewer/components/LockedFilterChip.js.map +1 -1
  1075. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryFacetSidebar.js +14 -4
  1076. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryFacetSidebar.js.map +1 -1
  1077. package/build/dist/UI/Components/TextArea/TextArea.js +9 -3
  1078. package/build/dist/UI/Components/TextArea/TextArea.js.map +1 -1
  1079. package/build/dist/UI/Components/Workflow/ModelFieldPicker.js +1 -2
  1080. package/build/dist/UI/Components/Workflow/ModelFieldPicker.js.map +1 -1
  1081. package/build/dist/Utils/AI/InvestigationReport.js +71 -11
  1082. package/build/dist/Utils/AI/InvestigationReport.js.map +1 -1
  1083. package/build/dist/Utils/AiRemediation/Resource/CephCommandPolicy.js +1462 -0
  1084. package/build/dist/Utils/AiRemediation/Resource/CephCommandPolicy.js.map +1 -0
  1085. package/build/dist/Utils/AiRemediation/Resource/DatabaseCommandPolicy.js +122 -0
  1086. package/build/dist/Utils/AiRemediation/Resource/DatabaseCommandPolicy.js.map +1 -0
  1087. package/build/dist/Utils/AiRemediation/Resource/DatabaseDiagnosticCatalog.js +1139 -0
  1088. package/build/dist/Utils/AiRemediation/Resource/DatabaseDiagnosticCatalog.js.map +1 -0
  1089. package/build/dist/Utils/AiRemediation/Resource/DatabaseQueryRedactor.js +1060 -0
  1090. package/build/dist/Utils/AiRemediation/Resource/DatabaseQueryRedactor.js.map +1 -0
  1091. package/build/dist/Utils/AiRemediation/Resource/DockerCliGrammar.js +1301 -0
  1092. package/build/dist/Utils/AiRemediation/Resource/DockerCliGrammar.js.map +1 -0
  1093. package/build/dist/Utils/AiRemediation/Resource/DockerEngineCommandPolicy.js +370 -0
  1094. package/build/dist/Utils/AiRemediation/Resource/DockerEngineCommandPolicy.js.map +1 -0
  1095. package/build/dist/Utils/AiRemediation/Resource/DockerSwarmCommandPolicy.js +498 -0
  1096. package/build/dist/Utils/AiRemediation/Resource/DockerSwarmCommandPolicy.js.map +1 -0
  1097. package/build/dist/Utils/AiRemediation/Resource/GovcCommandPolicy.js +1565 -0
  1098. package/build/dist/Utils/AiRemediation/Resource/GovcCommandPolicy.js.map +1 -0
  1099. package/build/dist/Utils/AiRemediation/Resource/HostCommandPolicy.js +2206 -0
  1100. package/build/dist/Utils/AiRemediation/Resource/HostCommandPolicy.js.map +1 -0
  1101. package/build/dist/Utils/AiRemediation/Resource/ProxmoxCommandPolicy.js +1129 -0
  1102. package/build/dist/Utils/AiRemediation/Resource/ProxmoxCommandPolicy.js.map +1 -0
  1103. package/build/dist/Utils/AiRemediation/Resource/ResourceCommandPolicy.js +565 -0
  1104. package/build/dist/Utils/AiRemediation/Resource/ResourceCommandPolicy.js.map +1 -0
  1105. package/build/dist/Utils/AiRemediation/Resource/ResourceCommandPolicyCore.js +408 -0
  1106. package/build/dist/Utils/AiRemediation/Resource/ResourceCommandPolicyCore.js.map +1 -0
  1107. package/build/dist/Utils/AiRemediation/Resource/ResourceOutputRedactor.js +1910 -0
  1108. package/build/dist/Utils/AiRemediation/Resource/ResourceOutputRedactor.js.map +1 -0
  1109. package/build/dist/Utils/LabelRuleImportExport.js +2 -0
  1110. package/build/dist/Utils/LabelRuleImportExport.js.map +1 -1
  1111. package/build/dist/Utils/Markdown/UntrustedMarkdown.js +988 -0
  1112. package/build/dist/Utils/Markdown/UntrustedMarkdown.js.map +1 -0
  1113. package/build/dist/Utils/Monitor/IncomingEmailMonitorRequestUtil.js +34 -0
  1114. package/build/dist/Utils/Monitor/IncomingEmailMonitorRequestUtil.js.map +1 -0
  1115. package/build/dist/Utils/Monitor/MonitorLogSummaryUtil.js +148 -0
  1116. package/build/dist/Utils/Monitor/MonitorLogSummaryUtil.js.map +1 -0
  1117. package/build/dist/Utils/SessionReplay/SessionReplayBudgetMetricType.js +160 -0
  1118. package/build/dist/Utils/SessionReplay/SessionReplayBudgetMetricType.js.map +1 -0
  1119. package/build/dist/Utils/Telemetry/EntityKey.js +36 -0
  1120. package/build/dist/Utils/Telemetry/EntityKey.js.map +1 -1
  1121. package/package.json +1 -3
  1122. package/Server/Utils/CommunityEditionSsoReport.ts +0 -361
  1123. package/Tests/App/Accounts/LoginSsoEdition.test.tsx +0 -616
  1124. package/Tests/App/AdminDashboard/AdminAuthenticationSsoEdition.test.tsx +0 -217
  1125. package/Tests/App/AdminDashboard/GlobalSSOEnterpriseShells.test.tsx +0 -271
  1126. package/Tests/App/Dashboard/CloudDocumentationMarkdown.test.ts +0 -215
  1127. package/Tests/App/Dashboard/TelemetryResourceRetentionSettings.test.tsx +0 -784
  1128. package/Tests/Server/Middleware/UserAuthorizationEditionEnforcement.test.ts +0 -518
  1129. package/Tests/Server/Services/SsoRequirementReadMasking.test.ts +0 -419
  1130. package/Tests/Server/Services/SsoRequirementWriteGuard.test.ts +0 -769
  1131. package/Tests/UI/Components/CodeEditor.test.tsx +0 -638
  1132. package/Tests/UI/Components/MonacoLoader.test.ts +0 -67
  1133. package/Tests/UI/Components/MonacoRuntime.test.ts +0 -121
  1134. package/Tests/UI/Components/Telemetry/TelemetryRetentionConfigForm.test.tsx +0 -329
  1135. package/Tests/UI/Components/YamlEditor.test.tsx +0 -847
  1136. package/UI/Components/CodeEditor/MonacoLoader.ts +0 -36
  1137. package/UI/Components/Telemetry/TelemetryRetentionConfigForm.tsx +0 -319
  1138. package/UI/Components/Telemetry/TelemetryRetentionConfigSummary.tsx +0 -223
  1139. package/build/dist/Server/Utils/CommunityEditionSsoReport.js +0 -223
  1140. package/build/dist/Server/Utils/CommunityEditionSsoReport.js.map +0 -1
  1141. package/build/dist/UI/Components/CodeEditor/MonacoLoader.js +0 -34
  1142. package/build/dist/UI/Components/CodeEditor/MonacoLoader.js.map +0 -1
  1143. package/build/dist/UI/Components/Telemetry/TelemetryRetentionConfigForm.js +0 -171
  1144. package/build/dist/UI/Components/Telemetry/TelemetryRetentionConfigForm.js.map +0 -1
  1145. package/build/dist/UI/Components/Telemetry/TelemetryRetentionConfigSummary.js +0 -119
  1146. package/build/dist/UI/Components/Telemetry/TelemetryRetentionConfigSummary.js.map +0 -1
@@ -11,7 +11,10 @@ import TeamComplianceSettingService, {
11
11
  DeletedSeverity,
12
12
  DUPLICATE_COMPLIANCE_RULE_MESSAGE,
13
13
  SEVERITIES_DELETED_ENABLE_MESSAGE,
14
+ StoredChannelColumns,
15
+ TeamComplianceSettingService as TeamComplianceSettingRules,
14
16
  } from "../../../Server/Services/TeamComplianceSettingService";
17
+ import { AddTeamComplianceRuleNotificationChannels1796500000000 } from "../../../Server/Infrastructure/Postgres/SchemaMigrations/1796500000000-AddTeamComplianceRuleNotificationChannels";
15
18
  import UpdateBy from "../../../Server/Types/Database/UpdateBy";
16
19
  import DatabaseCommonInteractionProps from "../../../Types/BaseDatabase/DatabaseCommonInteractionProps";
17
20
  import NotAuthorizedException from "../../../Types/Exception/NotAuthorizedException";
@@ -22,18 +25,22 @@ import Permission, {
22
25
  UserTenantAccessPermission,
23
26
  } from "../../../Types/Permission";
24
27
  import ComplianceNotificationChannel from "../../../Types/Team/ComplianceNotificationChannel";
25
- import { ComplianceSeverityKind } from "../../../Types/Team/ComplianceRule";
28
+ import ComplianceRule, {
29
+ ComplianceSeverityKind,
30
+ } from "../../../Types/Team/ComplianceRule";
26
31
  import ComplianceRuleType from "../../../Types/Team/ComplianceRuleType";
27
32
  import UserType from "../../../Types/UserType";
28
- import { DataSource, Logger } from "typeorm";
33
+ import { DataSource, Logger, QueryRunner } from "typeorm";
29
34
 
30
35
  /*
31
- * Team compliance rules scoped by severity and channel
32
- * (TeamComplianceSetting.notificationChannel / incidentSeverities /
36
+ * Team compliance rules scoped by severity and channels
37
+ * (TeamComplianceSetting.notificationChannels - with notificationChannel,
38
+ * the older single column kept in step with it - incidentSeverities and
33
39
  * alertSeverities) against a migrated Postgres.
34
40
  *
35
41
  * Opt in with RUN_POSTGRES_TEAM_COMPLIANCE_TESTS=true against a database the
36
- * registered migrations (1796000000000-AddTeamComplianceRuleScope included)
42
+ * registered migrations (1796000000000-AddTeamComplianceRuleScope and
43
+ * 1796500000000-AddTeamComplianceRuleNotificationChannels included)
37
44
  * have been applied to, e.g. from packages/Common:
38
45
  *
39
46
  * RUN_POSTGRES_TEAM_COMPLIANCE_TESTS=true \
@@ -122,6 +129,12 @@ type SeverityList = Array<
122
129
 
123
130
  interface RuleInput {
124
131
  ruleType: ComplianceRuleType;
132
+ // What the Dashboard's rule form sends.
133
+ notificationChannels?:
134
+ | Array<ComplianceNotificationChannel>
135
+ | null
136
+ | undefined;
137
+ // What a client from before the list sends instead.
125
138
  notificationChannel?: ComplianceNotificationChannel | null | undefined;
126
139
  incidentSeverities?: SeverityList | undefined;
127
140
  alertSeverities?: SeverityList | undefined;
@@ -130,10 +143,14 @@ interface RuleInput {
130
143
  projectId?: ObjectID | undefined;
131
144
  }
132
145
 
133
- // A rule row as Postgres stores it, with its join rows.
146
+ /*
147
+ * A rule row as Postgres stores it, with its join rows. `notificationChannels`
148
+ * is what the row checks, read off its two channel columns the way the
149
+ * service reads them (getStoredChannels).
150
+ */
134
151
  interface StoredRule {
135
152
  ruleType: string;
136
- notificationChannel: string | null;
153
+ notificationChannels: Array<string>;
137
154
  enabled: boolean;
138
155
  incidentSeverityIds: Array<string>;
139
156
  alertSeverityIds: Array<string>;
@@ -485,6 +502,10 @@ describePostgres(
485
502
  unknown
486
503
  >;
487
504
 
505
+ if (input.notificationChannels !== undefined) {
506
+ raw["notificationChannels"] = input.notificationChannels;
507
+ }
508
+
488
509
  if (input.notificationChannel !== undefined) {
489
510
  raw["notificationChannel"] = input.notificationChannel;
490
511
  }
@@ -544,9 +565,27 @@ describePostgres(
544
565
  });
545
566
  }
546
567
 
568
+ // The two channel columns exactly as Postgres holds them.
569
+ async function storedChannelColumns(
570
+ settingId: ObjectID,
571
+ ): Promise<StoredChannelColumns> {
572
+ const rows: Array<SqlRow> = await database.query(
573
+ `SELECT "notificationChannels", "notificationChannel", jsonb_typeof("notificationChannels") AS "listType" FROM "${schema}"."TeamComplianceSetting" WHERE "_id" = $1`,
574
+ [settingId.toString()],
575
+ );
576
+
577
+ // A list is stored as a jsonb ARRAY - never a string holding one.
578
+ expect([null, "array"]).toContain(rows[0]?.["listType"] ?? null);
579
+
580
+ return {
581
+ notificationChannels: rows[0]?.["notificationChannels"] ?? null,
582
+ notificationChannel: rows[0]?.["notificationChannel"] ?? null,
583
+ };
584
+ }
585
+
547
586
  async function stored(settingId: ObjectID): Promise<StoredRule | null> {
548
587
  const rows: Array<SqlRow> = await database.query(
549
- `SELECT "ruleType", "notificationChannel", "enabled" FROM "${schema}"."TeamComplianceSetting" WHERE "_id" = $1`,
588
+ `SELECT "ruleType", "enabled" FROM "${schema}"."TeamComplianceSetting" WHERE "_id" = $1`,
550
589
  [settingId.toString()],
551
590
  );
552
591
 
@@ -554,12 +593,29 @@ describePostgres(
554
593
  return null;
555
594
  }
556
595
 
596
+ /*
597
+ * Every row the service writes keeps its two channel columns in step:
598
+ * either neither was ever written, or the list is canonical and the
599
+ * single column holds its first channel - which an older build reading
600
+ * only that column relies on.
601
+ */
602
+ const columns: StoredChannelColumns =
603
+ await storedChannelColumns(settingId);
604
+
605
+ if (columns.notificationChannels === null) {
606
+ expect(columns.notificationChannel).toBeNull();
607
+ } else {
608
+ const list: Array<string> =
609
+ columns.notificationChannels as Array<string>;
610
+
611
+ expect(list).toEqual(ComplianceRule.normaliseChannels(list));
612
+ expect(columns.notificationChannel).toBe(list[0] ?? null);
613
+ }
614
+
557
615
  return {
558
616
  ruleType: String(rows[0]["ruleType"]),
559
- notificationChannel:
560
- rows[0]["notificationChannel"] === null
561
- ? null
562
- : String(rows[0]["notificationChannel"]),
617
+ notificationChannels:
618
+ TeamComplianceSettingRules.getStoredChannels(columns),
563
619
  enabled: rows[0]["enabled"] === true,
564
620
  incidentSeverityIds: await joinRows(INCIDENT_JOIN_TABLE, settingId),
565
621
  alertSeverityIds: await joinRows(ALERT_JOIN_TABLE, settingId),
@@ -676,6 +732,7 @@ describePostgres(
676
732
  _id: true,
677
733
  ruleType: true,
678
734
  enabled: true,
735
+ notificationChannels: true,
679
736
  notificationChannel: true,
680
737
  incidentSeverities: {
681
738
  _id: true,
@@ -792,13 +849,13 @@ describePostgres(
792
849
  test("severity ids sent as strings land as join rows, and read back with their name, colour and order", async () => {
793
850
  const id: ObjectID = await createRule({
794
851
  ruleType: ComplianceRuleType.HasIncidentOnCallRules,
795
- notificationChannel: ComplianceNotificationChannel.Call,
852
+ notificationChannels: [ComplianceNotificationChannel.Call],
796
853
  incidentSeverities: asStrings([major, critical]),
797
854
  });
798
855
 
799
856
  expect(await stored(id)).toEqual({
800
857
  ruleType: ComplianceRuleType.HasIncidentOnCallRules,
801
- notificationChannel: ComplianceNotificationChannel.Call,
858
+ notificationChannels: [ComplianceNotificationChannel.Call],
802
859
  enabled: true,
803
860
  incidentSeverityIds: ids([critical, major]),
804
861
  alertSeverityIds: [],
@@ -806,6 +863,10 @@ describePostgres(
806
863
 
807
864
  const rule: TeamComplianceSetting | null = await readRule(id);
808
865
 
866
+ // The list the edit form loads, and the column older clients read.
867
+ expect(rule?.notificationChannels).toEqual([
868
+ ComplianceNotificationChannel.Call,
869
+ ]);
809
870
  expect(rule?.notificationChannel).toBe(
810
871
  ComplianceNotificationChannel.Call,
811
872
  );
@@ -829,13 +890,13 @@ describePostgres(
829
890
  test("severity ids sent as {_id} JSON land as join rows", async () => {
830
891
  const id: ObjectID = await createRule({
831
892
  ruleType: ComplianceRuleType.HasAlertOnCallRules,
832
- notificationChannel: ComplianceNotificationChannel.Push,
893
+ notificationChannels: [ComplianceNotificationChannel.Push],
833
894
  alertSeverities: asJson([criticalAlert]),
834
895
  });
835
896
 
836
897
  expect(await stored(id)).toEqual({
837
898
  ruleType: ComplianceRuleType.HasAlertOnCallRules,
838
- notificationChannel: ComplianceNotificationChannel.Push,
899
+ notificationChannels: [ComplianceNotificationChannel.Push],
839
900
  enabled: true,
840
901
  incidentSeverityIds: [],
841
902
  alertSeverityIds: ids([criticalAlert]),
@@ -858,7 +919,7 @@ describePostgres(
858
919
  BaseModel.fromJSON<TeamComplianceSetting>(
859
920
  {
860
921
  ruleType: ComplianceRuleType.HasIncidentEpisodeOnCallRules,
861
- notificationChannel: ComplianceNotificationChannel.SMS,
922
+ notificationChannels: [ComplianceNotificationChannel.SMS],
862
923
  enabled: true,
863
924
  incidentSeverities: asJson([critical, minor]),
864
925
  },
@@ -875,7 +936,7 @@ describePostgres(
875
936
 
876
937
  expect(await stored(created.id!)).toEqual({
877
938
  ruleType: ComplianceRuleType.HasIncidentEpisodeOnCallRules,
878
- notificationChannel: ComplianceNotificationChannel.SMS,
939
+ notificationChannels: [ComplianceNotificationChannel.SMS],
879
940
  enabled: true,
880
941
  incidentSeverityIds: ids([critical, minor]),
881
942
  alertSeverityIds: [],
@@ -889,7 +950,7 @@ describePostgres(
889
950
 
890
951
  expect(await stored(id)).toEqual({
891
952
  ruleType: ComplianceRuleType.HasIncidentOnCallRules,
892
- notificationChannel: null,
953
+ notificationChannels: [],
893
954
  enabled: true,
894
955
  incidentSeverityIds: [],
895
956
  alertSeverityIds: [],
@@ -898,20 +959,21 @@ describePostgres(
898
959
  const rule: TeamComplianceSetting | null = await readRule(id);
899
960
 
900
961
  expect(rule?.incidentSeverities || []).toEqual([]);
962
+ expect(rule?.notificationChannels ?? null).toBeNull();
901
963
  expect(rule?.notificationChannel ?? null).toBeNull();
902
964
  });
903
965
 
904
966
  test("options the rule type does not use are not stored", async () => {
905
967
  const methodRule: ObjectID = await createRule({
906
968
  ruleType: ComplianceRuleType.HasNotificationCallMethod,
907
- notificationChannel: ComplianceNotificationChannel.Push,
969
+ notificationChannels: [ComplianceNotificationChannel.Push],
908
970
  incidentSeverities: asStrings([critical]),
909
971
  alertSeverities: asJson([criticalAlert]),
910
972
  });
911
973
 
912
974
  expect(await stored(methodRule)).toEqual({
913
975
  ruleType: ComplianceRuleType.HasNotificationCallMethod,
914
- notificationChannel: null,
976
+ notificationChannels: [],
915
977
  enabled: true,
916
978
  incidentSeverityIds: [],
917
979
  alertSeverityIds: [],
@@ -919,14 +981,14 @@ describePostgres(
919
981
 
920
982
  const incidentRule: ObjectID = await createRule({
921
983
  ruleType: ComplianceRuleType.HasIncidentOnCallRules,
922
- notificationChannel: ComplianceNotificationChannel.Call,
984
+ notificationChannels: [ComplianceNotificationChannel.Call],
923
985
  incidentSeverities: asStrings([critical]),
924
986
  alertSeverities: asJson([criticalAlert]),
925
987
  });
926
988
 
927
989
  expect(await stored(incidentRule)).toEqual({
928
990
  ruleType: ComplianceRuleType.HasIncidentOnCallRules,
929
- notificationChannel: ComplianceNotificationChannel.Call,
991
+ notificationChannels: [ComplianceNotificationChannel.Call],
930
992
  enabled: true,
931
993
  incidentSeverityIds: ids([critical]),
932
994
  alertSeverityIds: [],
@@ -940,7 +1002,7 @@ describePostgres(
940
1002
 
941
1003
  expect(await stored(alertRule)).toEqual({
942
1004
  ruleType: ComplianceRuleType.HasAlertEpisodeOnCallRules,
943
- notificationChannel: null,
1005
+ notificationChannels: [],
944
1006
  enabled: true,
945
1007
  incidentSeverityIds: [],
946
1008
  alertSeverityIds: ids([warningAlert]),
@@ -950,7 +1012,7 @@ describePostgres(
950
1012
  test("an exact duplicate is refused whatever the shape, order or case of its severity ids", async () => {
951
1013
  await createRule({
952
1014
  ruleType: ComplianceRuleType.HasIncidentOnCallRules,
953
- notificationChannel: ComplianceNotificationChannel.Call,
1015
+ notificationChannels: [ComplianceNotificationChannel.Call],
954
1016
  incidentSeverities: asStrings([critical, major]),
955
1017
  });
956
1018
 
@@ -968,7 +1030,7 @@ describePostgres(
968
1030
  await expect(
969
1031
  createRule({
970
1032
  ruleType: ComplianceRuleType.HasIncidentOnCallRules,
971
- notificationChannel: ComplianceNotificationChannel.Call,
1033
+ notificationChannels: [ComplianceNotificationChannel.Call],
972
1034
  incidentSeverities: incidentSeverities,
973
1035
  }),
974
1036
  ).rejects.toThrow(DUPLICATE_COMPLIANCE_RULE_MESSAGE);
@@ -985,7 +1047,7 @@ describePostgres(
985
1047
  test("an upper-case id is stored as the lower-case uuid, and the lower-case spelling is then a duplicate", async () => {
986
1048
  const id: ObjectID = await createRule({
987
1049
  ruleType: ComplianceRuleType.HasIncidentOnCallRules,
988
- notificationChannel: ComplianceNotificationChannel.WhatsApp,
1050
+ notificationChannels: [ComplianceNotificationChannel.WhatsApp],
989
1051
  incidentSeverities: [upper(minor)],
990
1052
  });
991
1053
 
@@ -994,7 +1056,7 @@ describePostgres(
994
1056
  await expect(
995
1057
  createRule({
996
1058
  ruleType: ComplianceRuleType.HasIncidentOnCallRules,
997
- notificationChannel: ComplianceNotificationChannel.WhatsApp,
1059
+ notificationChannels: [ComplianceNotificationChannel.WhatsApp],
998
1060
  incidentSeverities: asStrings([minor]),
999
1061
  }),
1000
1062
  ).rejects.toThrow(DUPLICATE_COMPLIANCE_RULE_MESSAGE);
@@ -1008,7 +1070,7 @@ describePostgres(
1008
1070
  await expect(
1009
1071
  createRule({
1010
1072
  ruleType: ComplianceRuleType.HasIncidentOnCallRules,
1011
- notificationChannel: null,
1073
+ notificationChannels: [],
1012
1074
  incidentSeverities: [],
1013
1075
  }),
1014
1076
  ).rejects.toThrow(DUPLICATE_COMPLIANCE_RULE_MESSAGE);
@@ -1021,7 +1083,7 @@ describePostgres(
1021
1083
  await expect(
1022
1084
  createRule({
1023
1085
  ruleType: ComplianceRuleType.HasNotificationCallMethod,
1024
- notificationChannel: ComplianceNotificationChannel.SMS,
1086
+ notificationChannels: [ComplianceNotificationChannel.SMS],
1025
1087
  incidentSeverities: asStrings([critical]),
1026
1088
  }),
1027
1089
  ).rejects.toThrow(DUPLICATE_COMPLIANCE_RULE_MESSAGE);
@@ -1034,7 +1096,7 @@ describePostgres(
1034
1096
 
1035
1097
  await createRule({
1036
1098
  ruleType: ComplianceRuleType.HasIncidentOnCallRules,
1037
- notificationChannel: ComplianceNotificationChannel.Call,
1099
+ notificationChannels: [ComplianceNotificationChannel.Call],
1038
1100
  incidentSeverities: asStrings(scope),
1039
1101
  });
1040
1102
 
@@ -1042,7 +1104,7 @@ describePostgres(
1042
1104
  // Push for the same severities.
1043
1105
  {
1044
1106
  ruleType: ComplianceRuleType.HasIncidentOnCallRules,
1045
- notificationChannel: ComplianceNotificationChannel.Push,
1107
+ notificationChannels: [ComplianceNotificationChannel.Push],
1046
1108
  incidentSeverities: asStrings(scope),
1047
1109
  },
1048
1110
  // Any channel for the same severities.
@@ -1053,30 +1115,30 @@ describePostgres(
1053
1115
  // Call for a subset.
1054
1116
  {
1055
1117
  ruleType: ComplianceRuleType.HasIncidentOnCallRules,
1056
- notificationChannel: ComplianceNotificationChannel.Call,
1118
+ notificationChannels: [ComplianceNotificationChannel.Call],
1057
1119
  incidentSeverities: asStrings([critical]),
1058
1120
  },
1059
1121
  // Call for a superset.
1060
1122
  {
1061
1123
  ruleType: ComplianceRuleType.HasIncidentOnCallRules,
1062
- notificationChannel: ComplianceNotificationChannel.Call,
1124
+ notificationChannels: [ComplianceNotificationChannel.Call],
1063
1125
  incidentSeverities: asStrings([critical, major, minor]),
1064
1126
  },
1065
1127
  // Call for every severity.
1066
1128
  {
1067
1129
  ruleType: ComplianceRuleType.HasIncidentOnCallRules,
1068
- notificationChannel: ComplianceNotificationChannel.Call,
1130
+ notificationChannels: [ComplianceNotificationChannel.Call],
1069
1131
  },
1070
1132
  // The episode rule type.
1071
1133
  {
1072
1134
  ruleType: ComplianceRuleType.HasIncidentEpisodeOnCallRules,
1073
- notificationChannel: ComplianceNotificationChannel.Call,
1135
+ notificationChannels: [ComplianceNotificationChannel.Call],
1074
1136
  incidentSeverities: asStrings(scope),
1075
1137
  },
1076
1138
  // The same rule on another team.
1077
1139
  {
1078
1140
  ruleType: ComplianceRuleType.HasIncidentOnCallRules,
1079
- notificationChannel: ComplianceNotificationChannel.Call,
1141
+ notificationChannels: [ComplianceNotificationChannel.Call],
1080
1142
  incidentSeverities: asStrings(scope),
1081
1143
  teamId: otherTeamId,
1082
1144
  },
@@ -1094,7 +1156,7 @@ describePostgres(
1094
1156
  {
1095
1157
  input: {
1096
1158
  ruleType: ComplianceRuleType.HasIncidentOnCallRules,
1097
- notificationChannel: ComplianceNotificationChannel.Call,
1159
+ notificationChannels: [ComplianceNotificationChannel.Call],
1098
1160
  incidentSeverities: asStrings([otherProjectCritical]),
1099
1161
  },
1100
1162
  message: FOREIGN_SEVERITY_MESSAGE,
@@ -1102,7 +1164,7 @@ describePostgres(
1102
1164
  {
1103
1165
  input: {
1104
1166
  ruleType: ComplianceRuleType.HasIncidentOnCallRules,
1105
- notificationChannel: ComplianceNotificationChannel.Call,
1167
+ notificationChannels: [ComplianceNotificationChannel.Call],
1106
1168
  incidentSeverities: asJson([critical, otherProjectCritical]),
1107
1169
  },
1108
1170
  message: FOREIGN_SEVERITY_MESSAGE,
@@ -1157,7 +1219,7 @@ describePostgres(
1157
1219
  test("a repeated severity id (in any case, on create or update) is stored once", async () => {
1158
1220
  const id: ObjectID = await createRule({
1159
1221
  ruleType: ComplianceRuleType.HasIncidentOnCallRules,
1160
- notificationChannel: ComplianceNotificationChannel.Call,
1222
+ notificationChannels: [ComplianceNotificationChannel.Call],
1161
1223
  incidentSeverities: [critical.toString(), upper(critical)],
1162
1224
  });
1163
1225
 
@@ -1198,7 +1260,7 @@ describePostgres(
1198
1260
  test("a severity list item is checked by the id the save writes: one read by its `id` cannot smuggle in another project's severity", async () => {
1199
1261
  const id: ObjectID = await createRule({
1200
1262
  ruleType: ComplianceRuleType.HasIncidentOnCallRules,
1201
- notificationChannel: ComplianceNotificationChannel.Call,
1263
+ notificationChannels: [ComplianceNotificationChannel.Call],
1202
1264
  incidentSeverities: asStrings([critical]),
1203
1265
  });
1204
1266
 
@@ -1220,7 +1282,7 @@ describePostgres(
1220
1282
  await expect(
1221
1283
  createRule({
1222
1284
  ruleType: ComplianceRuleType.HasIncidentOnCallRules,
1223
- notificationChannel: ComplianceNotificationChannel.Push,
1285
+ notificationChannels: [ComplianceNotificationChannel.Push],
1224
1286
  incidentSeverities: [item as unknown as JSONObject],
1225
1287
  }),
1226
1288
  ).rejects.toThrow(FOREIGN_SEVERITY_MESSAGE);
@@ -1238,7 +1300,7 @@ describePostgres(
1238
1300
 
1239
1301
  expect(await stored(id)).toEqual({
1240
1302
  ruleType: ComplianceRuleType.HasIncidentOnCallRules,
1241
- notificationChannel: ComplianceNotificationChannel.Call,
1303
+ notificationChannels: [ComplianceNotificationChannel.Call],
1242
1304
  enabled: true,
1243
1305
  incidentSeverityIds: ids([critical]),
1244
1306
  alertSeverityIds: [],
@@ -1261,7 +1323,7 @@ describePostgres(
1261
1323
  await expect(
1262
1324
  createRule({
1263
1325
  ruleType: ComplianceRuleType.HasIncidentOnCallRules,
1264
- notificationChannel: ComplianceNotificationChannel.Call,
1326
+ notificationChannels: [ComplianceNotificationChannel.Call],
1265
1327
  incidentSeverities: asStrings([ObjectID.generate()]),
1266
1328
  }),
1267
1329
  ).rejects.toThrow();
@@ -1284,7 +1346,7 @@ describePostgres(
1284
1346
  async function callForCriticalAndMajor(): Promise<ObjectID> {
1285
1347
  return await createRule({
1286
1348
  ruleType: ComplianceRuleType.HasIncidentOnCallRules,
1287
- notificationChannel: ComplianceNotificationChannel.Call,
1349
+ notificationChannels: [ComplianceNotificationChannel.Call],
1288
1350
  incidentSeverities: asStrings([critical, major]),
1289
1351
  });
1290
1352
  }
@@ -1310,7 +1372,7 @@ describePostgres(
1310
1372
 
1311
1373
  expect(await stored(id)).toEqual({
1312
1374
  ruleType: ComplianceRuleType.HasIncidentOnCallRules,
1313
- notificationChannel: ComplianceNotificationChannel.Call,
1375
+ notificationChannels: [ComplianceNotificationChannel.Call],
1314
1376
  enabled: false,
1315
1377
  incidentSeverityIds: ids([critical, major]),
1316
1378
  alertSeverityIds: [],
@@ -1345,7 +1407,7 @@ describePostgres(
1345
1407
 
1346
1408
  expect(await stored(id)).toEqual({
1347
1409
  ruleType: ComplianceRuleType.HasNotificationCallMethod,
1348
- notificationChannel: null,
1410
+ notificationChannels: [],
1349
1411
  enabled: true,
1350
1412
  incidentSeverityIds: [],
1351
1413
  alertSeverityIds: [],
@@ -1354,6 +1416,7 @@ describePostgres(
1354
1416
  const rule: TeamComplianceSetting | null = await readRule(id);
1355
1417
 
1356
1418
  expect(rule?.incidentSeverities || []).toEqual([]);
1419
+ expect(rule?.notificationChannels).toEqual([]);
1357
1420
  expect(rule?.notificationChannel ?? null).toBeNull();
1358
1421
  });
1359
1422
 
@@ -1367,7 +1430,7 @@ describePostgres(
1367
1430
 
1368
1431
  expect(await stored(id)).toEqual({
1369
1432
  ruleType: ComplianceRuleType.HasAlertOnCallRules,
1370
- notificationChannel: ComplianceNotificationChannel.Call,
1433
+ notificationChannels: [ComplianceNotificationChannel.Call],
1371
1434
  enabled: true,
1372
1435
  incidentSeverityIds: [],
1373
1436
  alertSeverityIds: ids([criticalAlert]),
@@ -1393,7 +1456,7 @@ describePostgres(
1393
1456
 
1394
1457
  expect(await stored(id)).toEqual({
1395
1458
  ruleType: ComplianceRuleType.HasIncidentOnCallRules,
1396
- notificationChannel: ComplianceNotificationChannel.Call,
1459
+ notificationChannels: [ComplianceNotificationChannel.Call],
1397
1460
  enabled: true,
1398
1461
  incidentSeverityIds: [],
1399
1462
  alertSeverityIds: [],
@@ -1404,20 +1467,24 @@ describePostgres(
1404
1467
  const id: ObjectID = await callForCriticalAndMajor();
1405
1468
 
1406
1469
  await updateRule(id, {
1407
- notificationChannel: ComplianceNotificationChannel.Push,
1470
+ notificationChannels: [ComplianceNotificationChannel.Push],
1408
1471
  });
1409
1472
 
1410
1473
  expect(await stored(id)).toEqual({
1411
1474
  ruleType: ComplianceRuleType.HasIncidentOnCallRules,
1412
- notificationChannel: ComplianceNotificationChannel.Push,
1475
+ notificationChannels: [ComplianceNotificationChannel.Push],
1413
1476
  enabled: true,
1414
1477
  incidentSeverityIds: ids([critical, major]),
1415
1478
  alertSeverityIds: [],
1416
1479
  });
1417
1480
 
1418
- await updateRule(id, { notificationChannel: null });
1481
+ await updateRule(id, { notificationChannels: [] });
1419
1482
 
1420
- expect((await stored(id))?.notificationChannel).toBeNull();
1483
+ expect((await stored(id))?.notificationChannels).toEqual([]);
1484
+ expect(await storedChannelColumns(id)).toEqual({
1485
+ notificationChannels: [],
1486
+ notificationChannel: null,
1487
+ });
1421
1488
  expect(await joinRows(INCIDENT_JOIN_TABLE, id)).toEqual(
1422
1489
  ids([critical, major]),
1423
1490
  );
@@ -1430,7 +1497,7 @@ describePostgres(
1430
1497
 
1431
1498
  expect(await stored(id)).toEqual({
1432
1499
  ruleType: ComplianceRuleType.HasIncidentOnCallRules,
1433
- notificationChannel: ComplianceNotificationChannel.Call,
1500
+ notificationChannels: [ComplianceNotificationChannel.Call],
1434
1501
  enabled: true,
1435
1502
  incidentSeverityIds: ids([critical, major]),
1436
1503
  alertSeverityIds: [],
@@ -1441,7 +1508,7 @@ describePostgres(
1441
1508
  const id: ObjectID = await callForCriticalAndMajor();
1442
1509
 
1443
1510
  await updateRule(id, {
1444
- notificationChannel: ComplianceNotificationChannel.Call,
1511
+ notificationChannels: [ComplianceNotificationChannel.Call],
1445
1512
  incidentSeverities: asJson([major, critical]),
1446
1513
  });
1447
1514
 
@@ -1455,7 +1522,7 @@ describePostgres(
1455
1522
 
1456
1523
  await createRule({
1457
1524
  ruleType: ComplianceRuleType.HasIncidentOnCallRules,
1458
- notificationChannel: ComplianceNotificationChannel.Call,
1525
+ notificationChannels: [ComplianceNotificationChannel.Call],
1459
1526
  incidentSeverities: asStrings([critical]),
1460
1527
  });
1461
1528
 
@@ -1475,7 +1542,7 @@ describePostgres(
1475
1542
 
1476
1543
  expect(await stored(id)).toEqual({
1477
1544
  ruleType: ComplianceRuleType.HasIncidentOnCallRules,
1478
- notificationChannel: ComplianceNotificationChannel.Call,
1545
+ notificationChannels: [ComplianceNotificationChannel.Call],
1479
1546
  enabled: true,
1480
1547
  incidentSeverityIds: ids([critical, major]),
1481
1548
  alertSeverityIds: [],
@@ -1483,141 +1550,884 @@ describePostgres(
1483
1550
  });
1484
1551
  });
1485
1552
 
1486
- describe("deleting", () => {
1487
- test("deleting a severity removes its join row and keeps the rule", async () => {
1553
+ describe("a rule on several channels", () => {
1554
+ test("stores them as one jsonb list in catalog order, with the first in the older column, and reads them back as a list", async () => {
1488
1555
  const id: ObjectID = await createRule({
1489
1556
  ruleType: ComplianceRuleType.HasIncidentOnCallRules,
1557
+ // Picked out of order, and one twice.
1558
+ notificationChannels: [
1559
+ ComplianceNotificationChannel.Push,
1560
+ ComplianceNotificationChannel.Call,
1561
+ ComplianceNotificationChannel.Push,
1562
+ ],
1563
+ incidentSeverities: asStrings([critical]),
1564
+ });
1565
+
1566
+ expect(await storedChannelColumns(id)).toEqual({
1567
+ notificationChannels: [
1568
+ ComplianceNotificationChannel.Call,
1569
+ ComplianceNotificationChannel.Push,
1570
+ ],
1490
1571
  notificationChannel: ComplianceNotificationChannel.Call,
1491
- incidentSeverities: asStrings([critical, major]),
1492
1572
  });
1493
1573
 
1494
- // What DatabaseService.deleteBy issues once a delete is permitted.
1495
- await database.query(
1496
- `DELETE FROM "${schema}"."IncidentSeverity" WHERE "_id" = $1`,
1497
- [critical.toString()],
1574
+ const rule: TeamComplianceSetting | null = await readRule(id);
1575
+
1576
+ expect(rule?.notificationChannels).toEqual([
1577
+ ComplianceNotificationChannel.Call,
1578
+ ComplianceNotificationChannel.Push,
1579
+ ]);
1580
+ expect(rule?.notificationChannel).toBe(
1581
+ ComplianceNotificationChannel.Call,
1498
1582
  );
1583
+ });
1499
1584
 
1500
- expect(await stored(id)).toEqual({
1585
+ test("duplicates compare the channels, not the order they were picked in", async () => {
1586
+ await createRule({
1501
1587
  ruleType: ComplianceRuleType.HasIncidentOnCallRules,
1502
- notificationChannel: ComplianceNotificationChannel.Call,
1503
- enabled: true,
1504
- incidentSeverityIds: ids([major]),
1505
- alertSeverityIds: [],
1588
+ notificationChannels: [
1589
+ ComplianceNotificationChannel.Call,
1590
+ ComplianceNotificationChannel.Push,
1591
+ ],
1592
+ incidentSeverities: asStrings([critical]),
1506
1593
  });
1507
1594
 
1508
- const rule: TeamComplianceSetting | null = await readRule(id);
1595
+ await expect(
1596
+ createRule({
1597
+ ruleType: ComplianceRuleType.HasIncidentOnCallRules,
1598
+ notificationChannels: [
1599
+ ComplianceNotificationChannel.Push,
1600
+ ComplianceNotificationChannel.Call,
1601
+ ComplianceNotificationChannel.Call,
1602
+ ],
1603
+ incidentSeverities: asStrings([critical]),
1604
+ }),
1605
+ ).rejects.toThrow(DUPLICATE_COMPLIANCE_RULE_MESSAGE);
1509
1606
 
1510
- expect(toReadSeverities(rule?.incidentSeverities)).toEqual([
1607
+ // Fewer channels, more channels or other severities check other things.
1608
+ for (const input of [
1511
1609
  {
1512
- id: major.toString(),
1513
- name: "Major Incident",
1514
- color: "#FFA500",
1515
- order: 2,
1610
+ notificationChannels: [ComplianceNotificationChannel.Call],
1611
+ incidentSeverities: asStrings([critical]),
1516
1612
  },
1517
- ]);
1613
+ {
1614
+ notificationChannels: [
1615
+ ComplianceNotificationChannel.SMS,
1616
+ ComplianceNotificationChannel.Push,
1617
+ ComplianceNotificationChannel.Call,
1618
+ ],
1619
+ incidentSeverities: asStrings([critical]),
1620
+ },
1621
+ {
1622
+ notificationChannels: [
1623
+ ComplianceNotificationChannel.Call,
1624
+ ComplianceNotificationChannel.Push,
1625
+ ],
1626
+ incidentSeverities: asStrings([major]),
1627
+ },
1628
+ {
1629
+ notificationChannels: [],
1630
+ incidentSeverities: asStrings([critical]),
1631
+ },
1632
+ ]) {
1633
+ await createRule({
1634
+ ruleType: ComplianceRuleType.HasIncidentOnCallRules,
1635
+ ...input,
1636
+ });
1637
+ }
1638
+
1639
+ expect(await countRules()).toBe(5);
1518
1640
  });
1519
1641
 
1520
- test("deleting an alert severity removes its join row too", async () => {
1642
+ test("an update adds, removes and clears channels, keeping both columns in step and the severities alone", async () => {
1521
1643
  const id: ObjectID = await createRule({
1522
- ruleType: ComplianceRuleType.HasAlertOnCallRules,
1523
- notificationChannel: ComplianceNotificationChannel.Push,
1524
- alertSeverities: asStrings([criticalAlert, warningAlert]),
1644
+ ruleType: ComplianceRuleType.HasIncidentOnCallRules,
1645
+ notificationChannels: [ComplianceNotificationChannel.SMS],
1646
+ incidentSeverities: asStrings([critical, major]),
1525
1647
  });
1526
1648
 
1527
- await database.query(
1528
- `DELETE FROM "${schema}"."AlertSeverity" WHERE "_id" = $1`,
1529
- [warningAlert.toString()],
1530
- );
1649
+ const steps: Array<[unknown, StoredChannelColumns]> = [
1650
+ [
1651
+ [
1652
+ ComplianceNotificationChannel.SMS,
1653
+ ComplianceNotificationChannel.Call,
1654
+ ],
1655
+ {
1656
+ notificationChannels: [
1657
+ ComplianceNotificationChannel.Call,
1658
+ ComplianceNotificationChannel.SMS,
1659
+ ],
1660
+ notificationChannel: ComplianceNotificationChannel.Call,
1661
+ },
1662
+ ],
1663
+ [
1664
+ [ComplianceNotificationChannel.Telegram],
1665
+ {
1666
+ notificationChannels: [ComplianceNotificationChannel.Telegram],
1667
+ notificationChannel: ComplianceNotificationChannel.Telegram,
1668
+ },
1669
+ ],
1670
+ // Null is "any channel", as an empty list is.
1671
+ [null, { notificationChannels: [], notificationChannel: null }],
1672
+ [
1673
+ [ComplianceNotificationChannel.Webhook],
1674
+ {
1675
+ notificationChannels: [ComplianceNotificationChannel.Webhook],
1676
+ notificationChannel: ComplianceNotificationChannel.Webhook,
1677
+ },
1678
+ ],
1679
+ [[], { notificationChannels: [], notificationChannel: null }],
1680
+ ];
1531
1681
 
1532
- expect(await joinRows(ALERT_JOIN_TABLE, id)).toEqual(
1533
- ids([criticalAlert]),
1534
- );
1682
+ for (const [sent, expected] of steps) {
1683
+ await updateRule(id, { notificationChannels: sent as JSONObject[] });
1684
+
1685
+ expect(await storedChannelColumns(id)).toEqual(expected);
1686
+ expect(await joinRows(INCIDENT_JOIN_TABLE, id)).toEqual(
1687
+ ids([critical, major]),
1688
+ );
1689
+ }
1535
1690
  });
1536
1691
 
1537
- /*
1538
- * The raw deletes above show the cascade itself. Through the severity
1539
- * services - the only way the product deletes a severity - a rule the
1540
- * cascade leaves with no severity is paused rather than left to read
1541
- * as a rule for every severity.
1542
- */
1543
- test("deleting a rule's only severity through the service pauses the rule; a rule with another severity left keeps it", async () => {
1544
- const onlyCritical: ObjectID = await createRule({
1692
+ test("re-saving a rule's own channels is no duplicate; taking a sibling's is refused and changes nothing", async () => {
1693
+ const callAndPush: ObjectID = await createRule({
1545
1694
  ruleType: ComplianceRuleType.HasIncidentOnCallRules,
1546
- notificationChannel: ComplianceNotificationChannel.Call,
1547
- incidentSeverities: asStrings([critical]),
1548
- });
1549
- const episodeOnlyCritical: ObjectID = await createRule({
1550
- ruleType: ComplianceRuleType.HasIncidentEpisodeOnCallRules,
1551
- notificationChannel: ComplianceNotificationChannel.SMS,
1695
+ notificationChannels: [
1696
+ ComplianceNotificationChannel.Call,
1697
+ ComplianceNotificationChannel.Push,
1698
+ ],
1552
1699
  incidentSeverities: asStrings([critical]),
1553
1700
  });
1554
- const criticalAndMajor: ObjectID = await createRule({
1555
- ruleType: ComplianceRuleType.HasIncidentOnCallRules,
1556
- notificationChannel: ComplianceNotificationChannel.Push,
1557
- incidentSeverities: asStrings([critical, major]),
1558
- });
1559
- const everySeverity: ObjectID = await createRule({
1701
+
1702
+ const callOnly: ObjectID = await createRule({
1560
1703
  ruleType: ComplianceRuleType.HasIncidentOnCallRules,
1561
- notificationChannel: ComplianceNotificationChannel.Email,
1562
- });
1563
- const alertRule: ObjectID = await createRule({
1564
- ruleType: ComplianceRuleType.HasAlertOnCallRules,
1565
- alertSeverities: asStrings([criticalAlert]),
1704
+ notificationChannels: [ComplianceNotificationChannel.Call],
1705
+ incidentSeverities: asStrings([critical]),
1566
1706
  });
1567
1707
 
1568
- await IncidentSeverityService.deleteOneById({
1569
- id: critical,
1570
- props: ROOT,
1708
+ await updateRule(callAndPush, {
1709
+ notificationChannels: [
1710
+ ComplianceNotificationChannel.Push,
1711
+ ComplianceNotificationChannel.Call,
1712
+ ],
1713
+ incidentSeverities: asJson([critical]),
1571
1714
  });
1572
1715
 
1573
- expect(await stored(onlyCritical)).toEqual({
1574
- ruleType: ComplianceRuleType.HasIncidentOnCallRules,
1716
+ await expect(
1717
+ updateRule(callOnly, {
1718
+ notificationChannels: [
1719
+ ComplianceNotificationChannel.Push,
1720
+ ComplianceNotificationChannel.Call,
1721
+ ],
1722
+ }),
1723
+ ).rejects.toThrow(DUPLICATE_COMPLIANCE_RULE_MESSAGE);
1724
+
1725
+ expect(await storedChannelColumns(callOnly)).toEqual({
1726
+ notificationChannels: [ComplianceNotificationChannel.Call],
1575
1727
  notificationChannel: ComplianceNotificationChannel.Call,
1576
- enabled: false,
1577
- incidentSeverityIds: [],
1578
- alertSeverityIds: [],
1579
1728
  });
1580
- expect(await storedOptions(onlyCritical)).toEqual(MARKED);
1581
- expect((await stored(episodeOnlyCritical))?.enabled).toBe(false);
1582
- expect(await storedOptions(episodeOnlyCritical)).toEqual(MARKED);
1583
- expect(await storedOptions(criticalAndMajor)).toBeNull();
1584
- expect(await storedOptions(everySeverity)).toBeNull();
1729
+ });
1585
1730
 
1586
- expect(await stored(criticalAndMajor)).toEqual({
1731
+ test("anything but a list of channels this build knows is refused, and nothing is written", async () => {
1732
+ const id: ObjectID = await createRule({
1587
1733
  ruleType: ComplianceRuleType.HasIncidentOnCallRules,
1588
- notificationChannel: ComplianceNotificationChannel.Push,
1589
- enabled: true,
1590
- incidentSeverityIds: ids([major]),
1591
- alertSeverityIds: [],
1734
+ notificationChannels: [ComplianceNotificationChannel.Call],
1735
+ incidentSeverities: asStrings([critical]),
1592
1736
  });
1593
- expect((await stored(everySeverity))?.enabled).toBe(true);
1594
- expect(await stored(alertRule)).toMatchObject({
1595
- enabled: true,
1596
- alertSeverityIds: ids([criticalAlert]),
1737
+
1738
+ const refused: Array<[unknown, string]> = [
1739
+ [
1740
+ ComplianceNotificationChannel.Push,
1741
+ "The notification channels of a compliance rule must be a list of channels.",
1742
+ ],
1743
+ [
1744
+ { channel: ComplianceNotificationChannel.Push },
1745
+ "The notification channels of a compliance rule must be a list of channels.",
1746
+ ],
1747
+ [
1748
+ [ComplianceNotificationChannel.Push, "Pager"],
1749
+ '"Pager" is not a notification channel a compliance rule can require.',
1750
+ ],
1751
+ [
1752
+ [ComplianceNotificationChannel.Push.toLowerCase()],
1753
+ '"push" is not a notification channel a compliance rule can require.',
1754
+ ],
1755
+ ];
1756
+
1757
+ for (const [sent, message] of refused) {
1758
+ await expect(
1759
+ createRule({
1760
+ ruleType: ComplianceRuleType.HasIncidentOnCallRules,
1761
+ notificationChannels:
1762
+ sent as Array<ComplianceNotificationChannel>,
1763
+ incidentSeverities: asStrings([major]),
1764
+ }),
1765
+ ).rejects.toThrow(message);
1766
+
1767
+ await expect(
1768
+ updateRule(id, { notificationChannels: sent as JSONObject }),
1769
+ ).rejects.toThrow(message);
1770
+ }
1771
+
1772
+ expect(await countRules()).toBe(1);
1773
+ expect(await storedChannelColumns(id)).toEqual({
1774
+ notificationChannels: [ComplianceNotificationChannel.Call],
1775
+ notificationChannel: ComplianceNotificationChannel.Call,
1597
1776
  });
1598
1777
  });
1599
1778
 
1600
- test("deleting an alert rule's only severity through the service pauses it too", async () => {
1601
- const onlyWarning: ObjectID = await createRule({
1602
- ruleType: ComplianceRuleType.HasAlertEpisodeOnCallRules,
1603
- notificationChannel: ComplianceNotificationChannel.Push,
1604
- alertSeverities: asStrings([warningAlert]),
1779
+ test("a method rule stores no channels, whichever column they arrive in", async () => {
1780
+ const fromList: ObjectID = await createRule({
1781
+ ruleType: ComplianceRuleType.HasNotificationSMSMethod,
1782
+ notificationChannels: [
1783
+ ComplianceNotificationChannel.Call,
1784
+ ComplianceNotificationChannel.Push,
1785
+ ],
1605
1786
  });
1606
- const incidentRule: ObjectID = await createRule({
1607
- ruleType: ComplianceRuleType.HasIncidentOnCallRules,
1608
- incidentSeverities: asStrings([critical]),
1787
+ const fromSingle: ObjectID = await createRule({
1788
+ ruleType: ComplianceRuleType.HasNotificationPushMethod,
1789
+ notificationChannel: ComplianceNotificationChannel.Call,
1609
1790
  });
1610
1791
 
1611
- await AlertSeverityService.deleteOneById({
1612
- id: warningAlert,
1613
- props: ROOT,
1792
+ for (const id of [fromList, fromSingle]) {
1793
+ expect(await storedChannelColumns(id)).toEqual({
1794
+ notificationChannels: [],
1795
+ notificationChannel: null,
1796
+ });
1797
+ }
1798
+ });
1799
+
1800
+ test("changing a multi-channel rule into a method rule clears both columns", async () => {
1801
+ const id: ObjectID = await createRule({
1802
+ ruleType: ComplianceRuleType.HasAlertOnCallRules,
1803
+ notificationChannels: [
1804
+ ComplianceNotificationChannel.Push,
1805
+ ComplianceNotificationChannel.SMS,
1806
+ ],
1807
+ alertSeverities: asStrings([criticalAlert]),
1614
1808
  });
1615
1809
 
1616
- expect(await stored(onlyWarning)).toMatchObject({
1617
- enabled: false,
1810
+ await updateRule(id, {
1811
+ ruleType: ComplianceRuleType.HasNotificationWhatsAppMethod,
1812
+ });
1813
+
1814
+ expect(await stored(id)).toEqual({
1815
+ ruleType: ComplianceRuleType.HasNotificationWhatsAppMethod,
1816
+ notificationChannels: [],
1817
+ enabled: true,
1818
+ incidentSeverityIds: [],
1618
1819
  alertSeverityIds: [],
1619
1820
  });
1620
- expect((await stored(incidentRule))?.enabled).toBe(true);
1821
+ expect(await storedChannelColumns(id)).toEqual({
1822
+ notificationChannels: [],
1823
+ notificationChannel: null,
1824
+ });
1825
+ });
1826
+ });
1827
+
1828
+ /*
1829
+ * API clients written before a rule could hold several channels, and a
1830
+ * Dashboard bundle cached from before the upgrade, send the single
1831
+ * `notificationChannel`. They must keep getting the rule they asked for -
1832
+ * a channel dropped on the floor would turn "Call for Critical" into
1833
+ * "any channel for Critical".
1834
+ */
1835
+ describe("a client that only knows notificationChannel", () => {
1836
+ test("a create that sends the single column gets exactly that channel, as a one-item list", async () => {
1837
+ const id: ObjectID = await createRule({
1838
+ ruleType: ComplianceRuleType.HasIncidentOnCallRules,
1839
+ notificationChannel: ComplianceNotificationChannel.SMS,
1840
+ incidentSeverities: asStrings([critical]),
1841
+ });
1842
+
1843
+ expect(await storedChannelColumns(id)).toEqual({
1844
+ notificationChannels: [ComplianceNotificationChannel.SMS],
1845
+ notificationChannel: ComplianceNotificationChannel.SMS,
1846
+ });
1847
+ expect((await readRule(id))?.notificationChannels).toEqual([
1848
+ ComplianceNotificationChannel.SMS,
1849
+ ]);
1850
+
1851
+ // It is the rule a list client would have made.
1852
+ await expect(
1853
+ createRule({
1854
+ ruleType: ComplianceRuleType.HasIncidentOnCallRules,
1855
+ notificationChannels: [ComplianceNotificationChannel.SMS],
1856
+ incidentSeverities: asStrings([critical]),
1857
+ }),
1858
+ ).rejects.toThrow(DUPLICATE_COMPLIANCE_RULE_MESSAGE);
1859
+ });
1860
+
1861
+ test("an update that sends the single column replaces the whole list; null clears it", async () => {
1862
+ const id: ObjectID = await createRule({
1863
+ ruleType: ComplianceRuleType.HasIncidentOnCallRules,
1864
+ notificationChannels: [
1865
+ ComplianceNotificationChannel.Call,
1866
+ ComplianceNotificationChannel.Push,
1867
+ ],
1868
+ incidentSeverities: asStrings([critical]),
1869
+ });
1870
+
1871
+ await updateRule(id, {
1872
+ notificationChannel: ComplianceNotificationChannel.WhatsApp,
1873
+ });
1874
+
1875
+ expect(await storedChannelColumns(id)).toEqual({
1876
+ notificationChannels: [ComplianceNotificationChannel.WhatsApp],
1877
+ notificationChannel: ComplianceNotificationChannel.WhatsApp,
1878
+ });
1879
+
1880
+ await updateRule(id, { notificationChannel: null });
1881
+
1882
+ expect(await storedChannelColumns(id)).toEqual({
1883
+ notificationChannels: [],
1884
+ notificationChannel: null,
1885
+ });
1886
+ expect(await joinRows(INCIDENT_JOIN_TABLE, id)).toEqual(
1887
+ ids([critical]),
1888
+ );
1889
+ });
1890
+
1891
+ test("a client that sends both is taken at its list, whatever stale single channel rides along", async () => {
1892
+ const id: ObjectID = await createRule({
1893
+ ruleType: ComplianceRuleType.HasIncidentOnCallRules,
1894
+ notificationChannels: [
1895
+ ComplianceNotificationChannel.Call,
1896
+ ComplianceNotificationChannel.Push,
1897
+ ],
1898
+ incidentSeverities: asStrings([critical]),
1899
+ });
1900
+
1901
+ // Read the rule, change the list, send both back.
1902
+ await updateRule(id, {
1903
+ notificationChannels: [ComplianceNotificationChannel.Email],
1904
+ notificationChannel: ComplianceNotificationChannel.Call,
1905
+ });
1906
+
1907
+ expect(await storedChannelColumns(id)).toEqual({
1908
+ notificationChannels: [ComplianceNotificationChannel.Email],
1909
+ notificationChannel: ComplianceNotificationChannel.Email,
1910
+ });
1911
+ });
1912
+
1913
+ test("a single channel this build does not know is refused, even beside a valid list", async () => {
1914
+ const id: ObjectID = await createRule({
1915
+ ruleType: ComplianceRuleType.HasIncidentOnCallRules,
1916
+ notificationChannels: [ComplianceNotificationChannel.Call],
1917
+ });
1918
+
1919
+ await expect(
1920
+ updateRule(id, {
1921
+ notificationChannels: [ComplianceNotificationChannel.Push],
1922
+ notificationChannel: "Pager",
1923
+ }),
1924
+ ).rejects.toThrow(
1925
+ '"Pager" is not a notification channel a compliance rule can require.',
1926
+ );
1927
+
1928
+ await expect(
1929
+ createRule({
1930
+ ruleType: ComplianceRuleType.HasIncidentOnCallRules,
1931
+ notificationChannel: "Pager" as ComplianceNotificationChannel,
1932
+ incidentSeverities: asStrings([major]),
1933
+ }),
1934
+ ).rejects.toThrow(
1935
+ '"Pager" is not a notification channel a compliance rule can require.',
1936
+ );
1937
+
1938
+ expect(await countRules()).toBe(1);
1939
+ expect(await storedChannelColumns(id)).toEqual({
1940
+ notificationChannels: [ComplianceNotificationChannel.Call],
1941
+ notificationChannel: ComplianceNotificationChannel.Call,
1942
+ });
1943
+ });
1944
+ });
1945
+
1946
+ /*
1947
+ * A replica of the previous build keeps serving while this one rolls
1948
+ * out (and runs again after a downgrade). It reads and writes only
1949
+ * notificationChannel and never touches the list - so a row it created
1950
+ * has no list, and a row it re-channelled has a list its single column
1951
+ * no longer agrees with. Either way the single column is what the admin
1952
+ * last asked for, and the duplicate check must compare against that.
1953
+ */
1954
+ describe("a row an older build wrote", () => {
1955
+ async function insertRawRule(data: {
1956
+ notificationChannels: Array<string> | null;
1957
+ notificationChannel: string | null;
1958
+ severities: Array<ObjectID>;
1959
+ }): Promise<ObjectID> {
1960
+ const id: ObjectID = ObjectID.generate();
1961
+
1962
+ await insert("TeamComplianceSetting", {
1963
+ _id: id.toString(),
1964
+ projectId: projectId.toString(),
1965
+ teamId: teamId.toString(),
1966
+ ruleType: ComplianceRuleType.HasIncidentOnCallRules,
1967
+ enabled: true,
1968
+ notificationChannel: data.notificationChannel,
1969
+ // jsonb is bound as its JSON text.
1970
+ notificationChannels:
1971
+ data.notificationChannels === null
1972
+ ? null
1973
+ : JSON.stringify(data.notificationChannels),
1974
+ version: 1,
1975
+ });
1976
+
1977
+ for (const severity of data.severities) {
1978
+ await insert(INCIDENT_JOIN_TABLE, {
1979
+ teamComplianceSettingId: id.toString(),
1980
+ incidentSeverityId: severity.toString(),
1981
+ });
1982
+ }
1983
+
1984
+ return id;
1985
+ }
1986
+
1987
+ test("a rule it created, with no list, is compared by its single column", async () => {
1988
+ const legacy: ObjectID = await insertRawRule({
1989
+ notificationChannels: null,
1990
+ notificationChannel: ComplianceNotificationChannel.Call,
1991
+ severities: [critical],
1992
+ });
1993
+
1994
+ expect(
1995
+ TeamComplianceSettingRules.getStoredChannels(
1996
+ await storedChannelColumns(legacy),
1997
+ ),
1998
+ ).toEqual([ComplianceNotificationChannel.Call]);
1999
+
2000
+ await expect(
2001
+ createRule({
2002
+ ruleType: ComplianceRuleType.HasIncidentOnCallRules,
2003
+ notificationChannels: [ComplianceNotificationChannel.Call],
2004
+ incidentSeverities: asStrings([critical]),
2005
+ }),
2006
+ ).rejects.toThrow(DUPLICATE_COMPLIANCE_RULE_MESSAGE);
2007
+
2008
+ await createRule({
2009
+ ruleType: ComplianceRuleType.HasIncidentOnCallRules,
2010
+ notificationChannels: [
2011
+ ComplianceNotificationChannel.Call,
2012
+ ComplianceNotificationChannel.Push,
2013
+ ],
2014
+ incidentSeverities: asStrings([critical]),
2015
+ });
2016
+
2017
+ expect(await countRules()).toBe(2);
2018
+ });
2019
+
2020
+ test("a rule it re-channelled - its single column no longer agreeing with the list - checks the single column", async () => {
2021
+ const id: ObjectID = await createRule({
2022
+ ruleType: ComplianceRuleType.HasIncidentOnCallRules,
2023
+ notificationChannels: [
2024
+ ComplianceNotificationChannel.Call,
2025
+ ComplianceNotificationChannel.Push,
2026
+ ],
2027
+ incidentSeverities: asStrings([critical]),
2028
+ });
2029
+
2030
+ await database.query(
2031
+ `UPDATE "${schema}"."TeamComplianceSetting" SET "notificationChannel" = 'SMS' WHERE "_id" = $1`,
2032
+ [id.toString()],
2033
+ );
2034
+
2035
+ await expect(
2036
+ createRule({
2037
+ ruleType: ComplianceRuleType.HasIncidentOnCallRules,
2038
+ notificationChannels: [ComplianceNotificationChannel.SMS],
2039
+ incidentSeverities: asStrings([critical]),
2040
+ }),
2041
+ ).rejects.toThrow(DUPLICATE_COMPLIANCE_RULE_MESSAGE);
2042
+
2043
+ // The Call-and-Push rule it replaced is no longer on the team.
2044
+ await createRule({
2045
+ ruleType: ComplianceRuleType.HasIncidentOnCallRules,
2046
+ notificationChannels: [
2047
+ ComplianceNotificationChannel.Push,
2048
+ ComplianceNotificationChannel.Call,
2049
+ ],
2050
+ incidentSeverities: asStrings([critical]),
2051
+ });
2052
+
2053
+ // Saved again by this build, the pair is back in step.
2054
+ await updateRule(id, {
2055
+ notificationChannels: [
2056
+ ComplianceNotificationChannel.SMS,
2057
+ ComplianceNotificationChannel.Email,
2058
+ ],
2059
+ });
2060
+
2061
+ expect(await storedChannelColumns(id)).toEqual({
2062
+ notificationChannels: [
2063
+ ComplianceNotificationChannel.SMS,
2064
+ ComplianceNotificationChannel.Email,
2065
+ ],
2066
+ notificationChannel: ComplianceNotificationChannel.SMS,
2067
+ });
2068
+ });
2069
+
2070
+ test("a rule it cleared to any channel no longer checks the list it had", async () => {
2071
+ const id: ObjectID = await createRule({
2072
+ ruleType: ComplianceRuleType.HasIncidentOnCallRules,
2073
+ notificationChannels: [
2074
+ ComplianceNotificationChannel.Call,
2075
+ ComplianceNotificationChannel.Push,
2076
+ ],
2077
+ incidentSeverities: asStrings([critical]),
2078
+ });
2079
+
2080
+ await database.query(
2081
+ `UPDATE "${schema}"."TeamComplianceSetting" SET "notificationChannel" = NULL WHERE "_id" = $1`,
2082
+ [id.toString()],
2083
+ );
2084
+
2085
+ await expect(
2086
+ createRule({
2087
+ ruleType: ComplianceRuleType.HasIncidentOnCallRules,
2088
+ notificationChannels: [],
2089
+ incidentSeverities: asStrings([critical]),
2090
+ }),
2091
+ ).rejects.toThrow(DUPLICATE_COMPLIANCE_RULE_MESSAGE);
2092
+ });
2093
+
2094
+ test("a rule it re-saved without changing the channel keeps every channel of its list", async () => {
2095
+ const id: ObjectID = await createRule({
2096
+ ruleType: ComplianceRuleType.HasIncidentOnCallRules,
2097
+ notificationChannels: [
2098
+ ComplianceNotificationChannel.Call,
2099
+ ComplianceNotificationChannel.Push,
2100
+ ],
2101
+ incidentSeverities: asStrings([critical]),
2102
+ });
2103
+
2104
+ // What the older form shows - and saves back - is the first channel.
2105
+ await database.query(
2106
+ `UPDATE "${schema}"."TeamComplianceSetting" SET "notificationChannel" = 'Call' WHERE "_id" = $1`,
2107
+ [id.toString()],
2108
+ );
2109
+
2110
+ await expect(
2111
+ createRule({
2112
+ ruleType: ComplianceRuleType.HasIncidentOnCallRules,
2113
+ notificationChannels: [
2114
+ ComplianceNotificationChannel.Push,
2115
+ ComplianceNotificationChannel.Call,
2116
+ ],
2117
+ incidentSeverities: asStrings([critical]),
2118
+ }),
2119
+ ).rejects.toThrow(DUPLICATE_COMPLIANCE_RULE_MESSAGE);
2120
+ });
2121
+ });
2122
+
2123
+ describe("the migration that added the list", () => {
2124
+ // up()'s statements, in order, without running them.
2125
+ async function migrationStatements(): Promise<Array<string>> {
2126
+ const statements: Array<string> = [];
2127
+
2128
+ await new AddTeamComplianceRuleNotificationChannels1796500000000().up({
2129
+ query: (statement: string): Promise<void> => {
2130
+ statements.push(statement);
2131
+ return Promise.resolve();
2132
+ },
2133
+ } as unknown as QueryRunner);
2134
+
2135
+ return statements;
2136
+ }
2137
+
2138
+ test("added it to the migrated table as nullable jsonb with no default", async () => {
2139
+ const columns: Array<SqlRow> = await database.query(
2140
+ `SELECT data_type, is_nullable, column_default
2141
+ FROM information_schema.columns
2142
+ WHERE table_schema = 'public' AND table_name = 'TeamComplianceSetting' AND column_name = 'notificationChannels'`,
2143
+ );
2144
+
2145
+ expect(columns).toEqual([
2146
+ { data_type: "jsonb", is_nullable: "YES", column_default: null },
2147
+ ]);
2148
+ });
2149
+
2150
+ test("its backfill gives every rule with a channel that channel as a list, and touches nothing else", async () => {
2151
+ const statements: Array<string> = await migrationStatements();
2152
+ const backfill: string = statements[1]!;
2153
+
2154
+ expect(backfill.startsWith('UPDATE "TeamComplianceSetting" SET')).toBe(
2155
+ true,
2156
+ );
2157
+
2158
+ /*
2159
+ * Rows as the previous build left them, one written since - and
2160
+ * rules of every kind. Run against this suite's own table, never
2161
+ * the migrated one.
2162
+ */
2163
+ const rows: Array<[string, SqlRow]> = [
2164
+ [
2165
+ "call rule",
2166
+ {
2167
+ ruleType: ComplianceRuleType.HasIncidentOnCallRules,
2168
+ notificationChannel: ComplianceNotificationChannel.Call,
2169
+ notificationChannels: null,
2170
+ },
2171
+ ],
2172
+ [
2173
+ "telegram alert episode rule",
2174
+ {
2175
+ ruleType: ComplianceRuleType.HasAlertEpisodeOnCallRules,
2176
+ notificationChannel: ComplianceNotificationChannel.Telegram,
2177
+ notificationChannels: null,
2178
+ },
2179
+ ],
2180
+ [
2181
+ "any-channel rule",
2182
+ {
2183
+ ruleType: ComplianceRuleType.HasIncidentOnCallRules,
2184
+ notificationChannel: null,
2185
+ notificationChannels: null,
2186
+ },
2187
+ ],
2188
+ [
2189
+ "method rule",
2190
+ {
2191
+ ruleType: ComplianceRuleType.HasNotificationEmailMethod,
2192
+ notificationChannel: null,
2193
+ notificationChannels: null,
2194
+ },
2195
+ ],
2196
+ [
2197
+ "rule already on a list",
2198
+ {
2199
+ ruleType: ComplianceRuleType.HasAlertOnCallRules,
2200
+ notificationChannel: ComplianceNotificationChannel.Push,
2201
+ notificationChannels: JSON.stringify([
2202
+ ComplianceNotificationChannel.Push,
2203
+ ComplianceNotificationChannel.SMS,
2204
+ ]),
2205
+ },
2206
+ ],
2207
+ ];
2208
+
2209
+ const idsByName: Map<string, ObjectID> = new Map<string, ObjectID>();
2210
+
2211
+ for (const [name, row] of rows) {
2212
+ const id: ObjectID = ObjectID.generate();
2213
+ idsByName.set(name, id);
2214
+
2215
+ await insert("TeamComplianceSetting", {
2216
+ _id: id.toString(),
2217
+ projectId: projectId.toString(),
2218
+ teamId: teamId.toString(),
2219
+ enabled: true,
2220
+ version: 1,
2221
+ ...row,
2222
+ });
2223
+ }
2224
+
2225
+ await database.query(
2226
+ backfill.replace(
2227
+ 'UPDATE "TeamComplianceSetting"',
2228
+ `UPDATE "${schema}"."TeamComplianceSetting"`,
2229
+ ),
2230
+ );
2231
+
2232
+ const after: Record<string, StoredChannelColumns> = {};
2233
+
2234
+ for (const [name] of rows) {
2235
+ after[name] = await storedChannelColumns(idsByName.get(name)!);
2236
+ }
2237
+
2238
+ expect(after).toEqual({
2239
+ "call rule": {
2240
+ notificationChannels: [ComplianceNotificationChannel.Call],
2241
+ notificationChannel: ComplianceNotificationChannel.Call,
2242
+ },
2243
+ "telegram alert episode rule": {
2244
+ notificationChannels: [ComplianceNotificationChannel.Telegram],
2245
+ notificationChannel: ComplianceNotificationChannel.Telegram,
2246
+ },
2247
+ "any-channel rule": {
2248
+ notificationChannels: null,
2249
+ notificationChannel: null,
2250
+ },
2251
+ "method rule": {
2252
+ notificationChannels: null,
2253
+ notificationChannel: null,
2254
+ },
2255
+ "rule already on a list": {
2256
+ notificationChannels: [
2257
+ ComplianceNotificationChannel.Push,
2258
+ ComplianceNotificationChannel.SMS,
2259
+ ],
2260
+ notificationChannel: ComplianceNotificationChannel.Push,
2261
+ },
2262
+ });
2263
+
2264
+ // Each checks what it checked before the migration.
2265
+ for (const [name, channels] of [
2266
+ ["call rule", [ComplianceNotificationChannel.Call]],
2267
+ [
2268
+ "telegram alert episode rule",
2269
+ [ComplianceNotificationChannel.Telegram],
2270
+ ],
2271
+ ["any-channel rule", []],
2272
+ ["method rule", []],
2273
+ ] as Array<[string, Array<ComplianceNotificationChannel>]>) {
2274
+ expect(
2275
+ (await stored(idsByName.get(name)!))?.notificationChannels,
2276
+ ).toEqual(channels);
2277
+ }
2278
+
2279
+ // Running it again changes nothing.
2280
+ await database.query(
2281
+ backfill.replace(
2282
+ 'UPDATE "TeamComplianceSetting"',
2283
+ `UPDATE "${schema}"."TeamComplianceSetting"`,
2284
+ ),
2285
+ );
2286
+
2287
+ expect(await storedChannelColumns(idsByName.get("call rule")!)).toEqual(
2288
+ {
2289
+ notificationChannels: [ComplianceNotificationChannel.Call],
2290
+ notificationChannel: ComplianceNotificationChannel.Call,
2291
+ },
2292
+ );
2293
+ });
2294
+ });
2295
+
2296
+ describe("deleting", () => {
2297
+ test("deleting a severity removes its join row and keeps the rule", async () => {
2298
+ const id: ObjectID = await createRule({
2299
+ ruleType: ComplianceRuleType.HasIncidentOnCallRules,
2300
+ notificationChannels: [ComplianceNotificationChannel.Call],
2301
+ incidentSeverities: asStrings([critical, major]),
2302
+ });
2303
+
2304
+ // What DatabaseService.deleteBy issues once a delete is permitted.
2305
+ await database.query(
2306
+ `DELETE FROM "${schema}"."IncidentSeverity" WHERE "_id" = $1`,
2307
+ [critical.toString()],
2308
+ );
2309
+
2310
+ expect(await stored(id)).toEqual({
2311
+ ruleType: ComplianceRuleType.HasIncidentOnCallRules,
2312
+ notificationChannels: [ComplianceNotificationChannel.Call],
2313
+ enabled: true,
2314
+ incidentSeverityIds: ids([major]),
2315
+ alertSeverityIds: [],
2316
+ });
2317
+
2318
+ const rule: TeamComplianceSetting | null = await readRule(id);
2319
+
2320
+ expect(toReadSeverities(rule?.incidentSeverities)).toEqual([
2321
+ {
2322
+ id: major.toString(),
2323
+ name: "Major Incident",
2324
+ color: "#FFA500",
2325
+ order: 2,
2326
+ },
2327
+ ]);
2328
+ });
2329
+
2330
+ test("deleting an alert severity removes its join row too", async () => {
2331
+ const id: ObjectID = await createRule({
2332
+ ruleType: ComplianceRuleType.HasAlertOnCallRules,
2333
+ notificationChannels: [ComplianceNotificationChannel.Push],
2334
+ alertSeverities: asStrings([criticalAlert, warningAlert]),
2335
+ });
2336
+
2337
+ await database.query(
2338
+ `DELETE FROM "${schema}"."AlertSeverity" WHERE "_id" = $1`,
2339
+ [warningAlert.toString()],
2340
+ );
2341
+
2342
+ expect(await joinRows(ALERT_JOIN_TABLE, id)).toEqual(
2343
+ ids([criticalAlert]),
2344
+ );
2345
+ });
2346
+
2347
+ /*
2348
+ * The raw deletes above show the cascade itself. Through the severity
2349
+ * services - the only way the product deletes a severity - a rule the
2350
+ * cascade leaves with no severity is paused rather than left to read
2351
+ * as a rule for every severity.
2352
+ */
2353
+ test("deleting a rule's only severity through the service pauses the rule; a rule with another severity left keeps it", async () => {
2354
+ const onlyCritical: ObjectID = await createRule({
2355
+ ruleType: ComplianceRuleType.HasIncidentOnCallRules,
2356
+ notificationChannels: [ComplianceNotificationChannel.Call],
2357
+ incidentSeverities: asStrings([critical]),
2358
+ });
2359
+ const episodeOnlyCritical: ObjectID = await createRule({
2360
+ ruleType: ComplianceRuleType.HasIncidentEpisodeOnCallRules,
2361
+ notificationChannels: [ComplianceNotificationChannel.SMS],
2362
+ incidentSeverities: asStrings([critical]),
2363
+ });
2364
+ const criticalAndMajor: ObjectID = await createRule({
2365
+ ruleType: ComplianceRuleType.HasIncidentOnCallRules,
2366
+ notificationChannels: [ComplianceNotificationChannel.Push],
2367
+ incidentSeverities: asStrings([critical, major]),
2368
+ });
2369
+ const everySeverity: ObjectID = await createRule({
2370
+ ruleType: ComplianceRuleType.HasIncidentOnCallRules,
2371
+ notificationChannels: [ComplianceNotificationChannel.Email],
2372
+ });
2373
+ const alertRule: ObjectID = await createRule({
2374
+ ruleType: ComplianceRuleType.HasAlertOnCallRules,
2375
+ alertSeverities: asStrings([criticalAlert]),
2376
+ });
2377
+
2378
+ await IncidentSeverityService.deleteOneById({
2379
+ id: critical,
2380
+ props: ROOT,
2381
+ });
2382
+
2383
+ expect(await stored(onlyCritical)).toEqual({
2384
+ ruleType: ComplianceRuleType.HasIncidentOnCallRules,
2385
+ notificationChannels: [ComplianceNotificationChannel.Call],
2386
+ enabled: false,
2387
+ incidentSeverityIds: [],
2388
+ alertSeverityIds: [],
2389
+ });
2390
+ expect(await storedOptions(onlyCritical)).toEqual(MARKED);
2391
+ expect((await stored(episodeOnlyCritical))?.enabled).toBe(false);
2392
+ expect(await storedOptions(episodeOnlyCritical)).toEqual(MARKED);
2393
+ expect(await storedOptions(criticalAndMajor)).toBeNull();
2394
+ expect(await storedOptions(everySeverity)).toBeNull();
2395
+
2396
+ expect(await stored(criticalAndMajor)).toEqual({
2397
+ ruleType: ComplianceRuleType.HasIncidentOnCallRules,
2398
+ notificationChannels: [ComplianceNotificationChannel.Push],
2399
+ enabled: true,
2400
+ incidentSeverityIds: ids([major]),
2401
+ alertSeverityIds: [],
2402
+ });
2403
+ expect((await stored(everySeverity))?.enabled).toBe(true);
2404
+ expect(await stored(alertRule)).toMatchObject({
2405
+ enabled: true,
2406
+ alertSeverityIds: ids([criticalAlert]),
2407
+ });
2408
+ });
2409
+
2410
+ test("deleting an alert rule's only severity through the service pauses it too", async () => {
2411
+ const onlyWarning: ObjectID = await createRule({
2412
+ ruleType: ComplianceRuleType.HasAlertEpisodeOnCallRules,
2413
+ notificationChannels: [ComplianceNotificationChannel.Push],
2414
+ alertSeverities: asStrings([warningAlert]),
2415
+ });
2416
+ const incidentRule: ObjectID = await createRule({
2417
+ ruleType: ComplianceRuleType.HasIncidentOnCallRules,
2418
+ incidentSeverities: asStrings([critical]),
2419
+ });
2420
+
2421
+ await AlertSeverityService.deleteOneById({
2422
+ id: warningAlert,
2423
+ props: ROOT,
2424
+ });
2425
+
2426
+ expect(await stored(onlyWarning)).toMatchObject({
2427
+ enabled: false,
2428
+ alertSeverityIds: [],
2429
+ });
2430
+ expect((await stored(incidentRule))?.enabled).toBe(true);
1621
2431
  });
1622
2432
 
1623
2433
  test.each([
@@ -1629,19 +2439,19 @@ describePostgres(
1629
2439
  const both: ObjectID = isAlert
1630
2440
  ? await createRule({
1631
2441
  ruleType: ComplianceRuleType.HasAlertOnCallRules,
1632
- notificationChannel: ComplianceNotificationChannel.Call,
2442
+ notificationChannels: [ComplianceNotificationChannel.Call],
1633
2443
  alertSeverities: asStrings([criticalAlert, warningAlert]),
1634
2444
  })
1635
2445
  : await createRule({
1636
2446
  ruleType: ComplianceRuleType.HasIncidentOnCallRules,
1637
- notificationChannel: ComplianceNotificationChannel.Call,
2447
+ notificationChannels: [ComplianceNotificationChannel.Call],
1638
2448
  incidentSeverities: asStrings([critical, major]),
1639
2449
  });
1640
2450
 
1641
2451
  // A rule with a severity neither delete touches.
1642
2452
  const keepsMinor: ObjectID = await createRule({
1643
2453
  ruleType: ComplianceRuleType.HasIncidentOnCallRules,
1644
- notificationChannel: ComplianceNotificationChannel.Push,
2454
+ notificationChannels: [ComplianceNotificationChannel.Push],
1645
2455
  incidentSeverities: asStrings([critical, minor]),
1646
2456
  });
1647
2457
 
@@ -1683,7 +2493,7 @@ describePostgres(
1683
2493
  test("a rule an admin had paused is marked too, so switching it on later cannot widen it", async () => {
1684
2494
  const paused: ObjectID = await createRule({
1685
2495
  ruleType: ComplianceRuleType.HasIncidentOnCallRules,
1686
- notificationChannel: ComplianceNotificationChannel.Call,
2496
+ notificationChannels: [ComplianceNotificationChannel.Call],
1687
2497
  incidentSeverities: asStrings([critical]),
1688
2498
  enabled: false,
1689
2499
  });
@@ -1710,11 +2520,11 @@ describePostgres(
1710
2520
  test("a rule a delete emptied duplicates nothing, cannot be switched on as it is, and is re-scoped from its edit form", async () => {
1711
2521
  const everySeverity: ObjectID = await createRule({
1712
2522
  ruleType: ComplianceRuleType.HasIncidentOnCallRules,
1713
- notificationChannel: ComplianceNotificationChannel.Call,
2523
+ notificationChannels: [ComplianceNotificationChannel.Call],
1714
2524
  });
1715
2525
  const onlyCritical: ObjectID = await createRule({
1716
2526
  ruleType: ComplianceRuleType.HasIncidentOnCallRules,
1717
- notificationChannel: ComplianceNotificationChannel.Call,
2527
+ notificationChannels: [ComplianceNotificationChannel.Call],
1718
2528
  incidentSeverities: asStrings([critical]),
1719
2529
  });
1720
2530
 
@@ -1726,7 +2536,7 @@ describePostgres(
1726
2536
  // The every-severity rule's edit form sends its whole scope.
1727
2537
  await updateRule(everySeverity, {
1728
2538
  ruleType: ComplianceRuleType.HasIncidentOnCallRules,
1729
- notificationChannel: ComplianceNotificationChannel.Call,
2539
+ notificationChannels: [ComplianceNotificationChannel.Call],
1730
2540
  incidentSeverities: [],
1731
2541
  alertSeverities: [],
1732
2542
  enabled: false,
@@ -1744,7 +2554,7 @@ describePostgres(
1744
2554
  // The emptied rule's edit form: new severities, switched back on.
1745
2555
  await updateRule(onlyCritical, {
1746
2556
  ruleType: ComplianceRuleType.HasIncidentOnCallRules,
1747
- notificationChannel: ComplianceNotificationChannel.Call,
2557
+ notificationChannels: [ComplianceNotificationChannel.Call],
1748
2558
  incidentSeverities: asJson([major]),
1749
2559
  alertSeverities: [],
1750
2560
  enabled: true,
@@ -1752,7 +2562,7 @@ describePostgres(
1752
2562
 
1753
2563
  expect(await stored(onlyCritical)).toEqual({
1754
2564
  ruleType: ComplianceRuleType.HasIncidentOnCallRules,
1755
- notificationChannel: ComplianceNotificationChannel.Call,
2565
+ notificationChannels: [ComplianceNotificationChannel.Call],
1756
2566
  enabled: true,
1757
2567
  incidentSeverityIds: ids([major]),
1758
2568
  alertSeverityIds: [],
@@ -1768,7 +2578,7 @@ describePostgres(
1768
2578
  test("re-scoping an emptied rule keeps every other option it carries", async () => {
1769
2579
  const onlyCritical: ObjectID = await createRule({
1770
2580
  ruleType: ComplianceRuleType.HasIncidentOnCallRules,
1771
- notificationChannel: ComplianceNotificationChannel.Call,
2581
+ notificationChannels: [ComplianceNotificationChannel.Call],
1772
2582
  incidentSeverities: asStrings([critical]),
1773
2583
  });
1774
2584
 
@@ -1797,7 +2607,7 @@ describePostgres(
1797
2607
  test("a delete the database refuses - the severity is still in use - pauses nothing", async () => {
1798
2608
  const onlyCritical: ObjectID = await createRule({
1799
2609
  ruleType: ComplianceRuleType.HasIncidentOnCallRules,
1800
- notificationChannel: ComplianceNotificationChannel.Call,
2610
+ notificationChannels: [ComplianceNotificationChannel.Call],
1801
2611
  incidentSeverities: asStrings([critical]),
1802
2612
  });
1803
2613
 
@@ -1829,7 +2639,7 @@ describePostgres(
1829
2639
 
1830
2640
  expect(await stored(onlyCritical)).toEqual({
1831
2641
  ruleType: ComplianceRuleType.HasIncidentOnCallRules,
1832
- notificationChannel: ComplianceNotificationChannel.Call,
2642
+ notificationChannels: [ComplianceNotificationChannel.Call],
1833
2643
  enabled: true,
1834
2644
  incidentSeverityIds: ids([critical]),
1835
2645
  alertSeverityIds: [],
@@ -1839,13 +2649,13 @@ describePostgres(
1839
2649
  test("deleting a rule through the service removes its join rows and nobody else's", async () => {
1840
2650
  const id: ObjectID = await createRule({
1841
2651
  ruleType: ComplianceRuleType.HasIncidentOnCallRules,
1842
- notificationChannel: ComplianceNotificationChannel.Call,
2652
+ notificationChannels: [ComplianceNotificationChannel.Call],
1843
2653
  incidentSeverities: asStrings([critical, major]),
1844
2654
  });
1845
2655
 
1846
2656
  const sibling: ObjectID = await createRule({
1847
2657
  ruleType: ComplianceRuleType.HasIncidentOnCallRules,
1848
- notificationChannel: ComplianceNotificationChannel.Push,
2658
+ notificationChannels: [ComplianceNotificationChannel.Push],
1849
2659
  incidentSeverities: asStrings([critical]),
1850
2660
  });
1851
2661
 
@@ -1887,7 +2697,7 @@ describePostgres(
1887
2697
  const id: ObjectID = await createRule(
1888
2698
  {
1889
2699
  ruleType: ComplianceRuleType.HasIncidentOnCallRules,
1890
- notificationChannel: ComplianceNotificationChannel.Call,
2700
+ notificationChannels: [ComplianceNotificationChannel.Call],
1891
2701
  incidentSeverities: asIncidentModels([critical]),
1892
2702
  },
1893
2703
  admin,
@@ -1895,7 +2705,7 @@ describePostgres(
1895
2705
 
1896
2706
  expect(await stored(id)).toEqual({
1897
2707
  ruleType: ComplianceRuleType.HasIncidentOnCallRules,
1898
- notificationChannel: ComplianceNotificationChannel.Call,
2708
+ notificationChannels: [ComplianceNotificationChannel.Call],
1899
2709
  enabled: true,
1900
2710
  incidentSeverityIds: ids([critical]),
1901
2711
  alertSeverityIds: [],
@@ -1926,7 +2736,7 @@ describePostgres(
1926
2736
  createRule(
1927
2737
  {
1928
2738
  ruleType: ComplianceRuleType.HasIncidentOnCallRules,
1929
- notificationChannel: ComplianceNotificationChannel.Call,
2739
+ notificationChannels: [ComplianceNotificationChannel.Call],
1930
2740
  incidentSeverities: asJson([major, critical]),
1931
2741
  },
1932
2742
  admin,
@@ -1941,7 +2751,7 @@ describePostgres(
1941
2751
 
1942
2752
  const onlyCritical: ObjectID = await createRule({
1943
2753
  ruleType: ComplianceRuleType.HasIncidentOnCallRules,
1944
- notificationChannel: ComplianceNotificationChannel.Call,
2754
+ notificationChannels: [ComplianceNotificationChannel.Call],
1945
2755
  incidentSeverities: asStrings([critical]),
1946
2756
  });
1947
2757
 
@@ -1973,7 +2783,7 @@ describePostgres(
1973
2783
  test("a caller who may not change the project's rules learns nothing about its severities or rules", async () => {
1974
2784
  await createRule({
1975
2785
  ruleType: ComplianceRuleType.HasIncidentOnCallRules,
1976
- notificationChannel: ComplianceNotificationChannel.Call,
2786
+ notificationChannels: [ComplianceNotificationChannel.Call],
1977
2787
  incidentSeverities: asStrings([critical]),
1978
2788
  });
1979
2789
 
@@ -1997,7 +2807,7 @@ describePostgres(
1997
2807
  createRule(
1998
2808
  {
1999
2809
  ruleType: ComplianceRuleType.HasIncidentOnCallRules,
2000
- notificationChannel: ComplianceNotificationChannel.Call,
2810
+ notificationChannels: [ComplianceNotificationChannel.Call],
2001
2811
  incidentSeverities: asStrings([severity]),
2002
2812
  },
2003
2813
  props,
@@ -2009,6 +2819,88 @@ describePostgres(
2009
2819
  expect(await countRules()).toBe(1);
2010
2820
  });
2011
2821
 
2822
+ /*
2823
+ * The hooks write notificationChannel beside whatever list is sent,
2824
+ * after the caller's column permissions were checked against the
2825
+ * payload - so the column they add must pass the same check the
2826
+ * update makes again once they return.
2827
+ */
2828
+ test("a team editor sets a rule's channels with the list alone, or with the older column alone", async () => {
2829
+ const editor: DatabaseCommonInteractionProps = memberProps(projectId, [
2830
+ Permission.ReadProjectTeam,
2831
+ Permission.EditProjectTeam,
2832
+ ]);
2833
+
2834
+ const id: ObjectID = await createRule(
2835
+ {
2836
+ ruleType: ComplianceRuleType.HasAlertOnCallRules,
2837
+ notificationChannels: [
2838
+ ComplianceNotificationChannel.Push,
2839
+ ComplianceNotificationChannel.SMS,
2840
+ ],
2841
+ alertSeverities: asStrings([criticalAlert]),
2842
+ },
2843
+ editor,
2844
+ );
2845
+
2846
+ expect(await storedChannelColumns(id)).toEqual({
2847
+ notificationChannels: [
2848
+ ComplianceNotificationChannel.SMS,
2849
+ ComplianceNotificationChannel.Push,
2850
+ ],
2851
+ notificationChannel: ComplianceNotificationChannel.SMS,
2852
+ });
2853
+
2854
+ await updateRule(
2855
+ id,
2856
+ { notificationChannels: [ComplianceNotificationChannel.Call] },
2857
+ editor,
2858
+ );
2859
+
2860
+ expect(await storedChannelColumns(id)).toEqual({
2861
+ notificationChannels: [ComplianceNotificationChannel.Call],
2862
+ notificationChannel: ComplianceNotificationChannel.Call,
2863
+ });
2864
+
2865
+ await updateRule(
2866
+ id,
2867
+ { notificationChannel: ComplianceNotificationChannel.Email },
2868
+ editor,
2869
+ );
2870
+
2871
+ expect(await storedChannelColumns(id)).toEqual({
2872
+ notificationChannels: [ComplianceNotificationChannel.Email],
2873
+ notificationChannel: ComplianceNotificationChannel.Email,
2874
+ });
2875
+ });
2876
+
2877
+ test("a member who may only read the project's teams changes neither channel column", async () => {
2878
+ const reader: DatabaseCommonInteractionProps = memberProps(projectId, [
2879
+ Permission.ProjectMember,
2880
+ Permission.ReadProjectTeam,
2881
+ ]);
2882
+
2883
+ const id: ObjectID = await createRule({
2884
+ ruleType: ComplianceRuleType.HasIncidentOnCallRules,
2885
+ notificationChannels: [ComplianceNotificationChannel.Call],
2886
+ incidentSeverities: asStrings([critical]),
2887
+ });
2888
+
2889
+ for (const data of [
2890
+ { notificationChannels: [ComplianceNotificationChannel.Webhook] },
2891
+ { notificationChannel: ComplianceNotificationChannel.Webhook },
2892
+ ]) {
2893
+ await expect(updateRule(id, data, reader)).rejects.toThrow(
2894
+ NotAuthorizedException,
2895
+ );
2896
+ }
2897
+
2898
+ expect(await storedChannelColumns(id)).toEqual({
2899
+ notificationChannels: [ComplianceNotificationChannel.Call],
2900
+ notificationChannel: ComplianceNotificationChannel.Call,
2901
+ });
2902
+ });
2903
+
2012
2904
  test("a team editor creates and rescopes a rule; cleared options pass the permission check", async () => {
2013
2905
  const editor: DatabaseCommonInteractionProps = memberProps(projectId, [
2014
2906
  Permission.ReadProjectTeam,
@@ -2019,7 +2911,7 @@ describePostgres(
2019
2911
  const method: ObjectID = await createRule(
2020
2912
  {
2021
2913
  ruleType: ComplianceRuleType.HasNotificationCallMethod,
2022
- notificationChannel: ComplianceNotificationChannel.SMS,
2914
+ notificationChannels: [ComplianceNotificationChannel.SMS],
2023
2915
  incidentSeverities: asStrings([critical]),
2024
2916
  },
2025
2917
  editor,
@@ -2027,7 +2919,7 @@ describePostgres(
2027
2919
 
2028
2920
  expect(await stored(method)).toEqual({
2029
2921
  ruleType: ComplianceRuleType.HasNotificationCallMethod,
2030
- notificationChannel: null,
2922
+ notificationChannels: [],
2031
2923
  enabled: true,
2032
2924
  incidentSeverityIds: [],
2033
2925
  alertSeverityIds: [],
@@ -2036,7 +2928,7 @@ describePostgres(
2036
2928
  const id: ObjectID = await createRule(
2037
2929
  {
2038
2930
  ruleType: ComplianceRuleType.HasIncidentOnCallRules,
2039
- notificationChannel: ComplianceNotificationChannel.Call,
2931
+ notificationChannels: [ComplianceNotificationChannel.Call],
2040
2932
  incidentSeverities: asIncidentModels([critical]),
2041
2933
  alertSeverities: asStrings([criticalAlert]),
2042
2934
  },
@@ -2061,7 +2953,7 @@ describePostgres(
2061
2953
 
2062
2954
  expect(await stored(id)).toEqual({
2063
2955
  ruleType: ComplianceRuleType.HasNotificationPushMethod,
2064
- notificationChannel: null,
2956
+ notificationChannels: [],
2065
2957
  enabled: true,
2066
2958
  incidentSeverityIds: [],
2067
2959
  alertSeverityIds: [],
@@ -2129,7 +3021,7 @@ describePostgres(
2129
3021
 
2130
3022
  const onlyCritical: ObjectID = await createRule({
2131
3023
  ruleType: ComplianceRuleType.HasIncidentOnCallRules,
2132
- notificationChannel: ComplianceNotificationChannel.Call,
3024
+ notificationChannels: [ComplianceNotificationChannel.Call],
2133
3025
  incidentSeverities: asStrings([critical]),
2134
3026
  });
2135
3027
 
@@ -2170,7 +3062,7 @@ describePostgres(
2170
3062
  test("cannot rescope another project's rule", async () => {
2171
3063
  const id: ObjectID = await createRule({
2172
3064
  ruleType: ComplianceRuleType.HasIncidentOnCallRules,
2173
- notificationChannel: ComplianceNotificationChannel.Call,
3065
+ notificationChannels: [ComplianceNotificationChannel.Call],
2174
3066
  incidentSeverities: asStrings([critical]),
2175
3067
  });
2176
3068
 
@@ -2204,7 +3096,7 @@ describePostgres(
2204
3096
  createRule(
2205
3097
  {
2206
3098
  ruleType: ComplianceRuleType.HasIncidentOnCallRules,
2207
- notificationChannel: ComplianceNotificationChannel.Call,
3099
+ notificationChannels: [ComplianceNotificationChannel.Call],
2208
3100
  incidentSeverities: asIncidentModels([otherProjectCritical]),
2209
3101
  projectId: otherProjectId,
2210
3102
  },
@@ -2218,7 +3110,7 @@ describePostgres(
2218
3110
  const id: ObjectID = await createRule(
2219
3111
  {
2220
3112
  ruleType: ComplianceRuleType.HasIncidentOnCallRules,
2221
- notificationChannel: ComplianceNotificationChannel.Call,
3113
+ notificationChannels: [ComplianceNotificationChannel.Call],
2222
3114
  incidentSeverities: asIncidentModels([critical]),
2223
3115
  projectId: otherProjectId,
2224
3116
  },