@oneuptime/common 14.0.10 → 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 (837) hide show
  1. package/Models/DatabaseModels/AIConversation.ts +127 -1
  2. package/Models/DatabaseModels/CephCluster.ts +12 -0
  3. package/Models/DatabaseModels/CloudResource.ts +12 -0
  4. package/Models/DatabaseModels/DatabaseServer.ts +12 -0
  5. package/Models/DatabaseModels/DockerHost.ts +12 -0
  6. package/Models/DatabaseModels/DockerSwarmCluster.ts +12 -0
  7. package/Models/DatabaseModels/GlobalOidc.ts +0 -4
  8. package/Models/DatabaseModels/GlobalOidcProject.ts +0 -4
  9. package/Models/DatabaseModels/GlobalSso.ts +0 -4
  10. package/Models/DatabaseModels/GlobalSsoProject.ts +0 -4
  11. package/Models/DatabaseModels/Host.ts +12 -0
  12. package/Models/DatabaseModels/IncidentForm.ts +594 -0
  13. package/Models/DatabaseModels/IncidentFormSubmission.ts +283 -0
  14. package/Models/DatabaseModels/IncidentTemplate.ts +59 -0
  15. package/Models/DatabaseModels/Index.ts +14 -0
  16. package/Models/DatabaseModels/IoTFleet.ts +12 -0
  17. package/Models/DatabaseModels/KubernetesCluster.ts +12 -0
  18. package/Models/DatabaseModels/MessageQueue.ts +1102 -0
  19. package/Models/DatabaseModels/MessageQueueLabelRule.ts +553 -0
  20. package/Models/DatabaseModels/MessageQueueOwnerRule.ts +633 -0
  21. package/Models/DatabaseModels/MessageQueueOwnerTeam.ts +491 -0
  22. package/Models/DatabaseModels/MessageQueueOwnerUser.ts +490 -0
  23. package/Models/DatabaseModels/PodmanHost.ts +12 -0
  24. package/Models/DatabaseModels/Project.ts +59 -0
  25. package/Models/DatabaseModels/ProjectOidc.ts +0 -4
  26. package/Models/DatabaseModels/ProjectSso.ts +0 -4
  27. package/Models/DatabaseModels/ProxmoxCluster.ts +12 -0
  28. package/Models/DatabaseModels/RumApplication.ts +12 -0
  29. package/Models/DatabaseModels/ServerlessFunction.ts +12 -0
  30. package/Models/DatabaseModels/Service.ts +12 -0
  31. package/Models/DatabaseModels/StatusPageOidc.ts +0 -4
  32. package/Models/DatabaseModels/StatusPageSso.ts +0 -4
  33. package/Models/DatabaseModels/TeamComplianceSetting.ts +47 -2
  34. package/Models/DatabaseModels/VMwareVCenter.ts +12 -0
  35. package/Server/API/AIChatAPI.ts +13 -114
  36. package/Server/API/AIInvestigationAPI.ts +3 -3
  37. package/Server/API/AIInvestigationConversationAPI.ts +266 -0
  38. package/Server/API/IncidentFormAPI.ts +376 -0
  39. package/Server/API/ProjectOIDC.ts +16 -25
  40. package/Server/API/ProjectSSO.ts +16 -24
  41. package/Server/API/StatusPageAPI.ts +42 -77
  42. package/Server/Enterprise/EnterpriseEdition.ts +93 -28
  43. package/Server/Enterprise/EnterpriseFeature.ts +25 -3
  44. package/Server/Enterprise/EnterpriseLicenseSnapshot.ts +1 -1
  45. package/Server/Enterprise/EnterpriseServerModule.ts +4 -1
  46. package/Server/EnvironmentConfig.ts +1 -1
  47. package/Server/Infrastructure/Postgres/SchemaMigrations/1796400000000-AddIncidentForms.ts +129 -0
  48. package/Server/Infrastructure/Postgres/SchemaMigrations/1796500000000-AddTeamComplianceRuleNotificationChannels.ts +52 -0
  49. package/Server/Infrastructure/Postgres/SchemaMigrations/1796600000000-AddAIInvestigationConversationAndTimeLimits.ts +75 -0
  50. package/Server/Infrastructure/Postgres/SchemaMigrations/1796700000000-AddMessageQueueTables.ts +477 -0
  51. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +8 -0
  52. package/Server/Middleware/IncidentFormRateLimit.ts +847 -0
  53. package/Server/Middleware/UserAuthorization.ts +16 -38
  54. package/Server/Services/AIService.ts +10 -13
  55. package/Server/Services/IncidentCustomFieldService.ts +112 -2
  56. package/Server/Services/IncidentEpisodeMemberService.ts +24 -4
  57. package/Server/Services/IncidentEpisodeService.ts +10 -1
  58. package/Server/Services/IncidentFormService.ts +1566 -0
  59. package/Server/Services/IncidentFormSubmissionService.ts +97 -0
  60. package/Server/Services/IncidentGroupingEngineService.ts +45 -8
  61. package/Server/Services/IncidentService.ts +123 -5
  62. package/Server/Services/IncidentTemplateService.ts +22 -0
  63. package/Server/Services/Index.ts +14 -0
  64. package/Server/Services/MessageQueueLabelRuleEngineService.ts +321 -0
  65. package/Server/Services/MessageQueueLabelRuleService.ts +14 -0
  66. package/Server/Services/MessageQueueOwnerRuleEngineService.ts +412 -0
  67. package/Server/Services/MessageQueueOwnerRuleService.ts +14 -0
  68. package/Server/Services/MessageQueueOwnerTeamService.ts +62 -0
  69. package/Server/Services/MessageQueueOwnerUserService.ts +62 -0
  70. package/Server/Services/MessageQueueService.ts +1463 -0
  71. package/Server/Services/OpenTelemetryIngestService.ts +37 -4
  72. package/Server/Services/ProjectService.ts +0 -59
  73. package/Server/Services/StatusPagePrivateUserService.ts +1 -4
  74. package/Server/Services/StatusPageService.ts +1 -51
  75. package/Server/Services/TeamComplianceSettingService.ts +163 -42
  76. package/Server/Services/UserNotificationRuleService.ts +8 -1
  77. package/Server/Services/WorkspaceNotificationSummaryService.ts +12 -3
  78. package/Server/Types/Database/Permissions/CreatePermission.ts +17 -3
  79. package/Server/Types/Database/Permissions/EditionPermission.ts +140 -38
  80. package/Server/Types/Database/Permissions/OwnerTableRegistry.ts +16 -0
  81. package/Server/Types/Database/Permissions/TablePermission.ts +3 -3
  82. package/Server/Types/Database/Permissions/UpdatePermission.ts +20 -6
  83. package/Server/Utils/AI/Chat/AgentContextCompactor.ts +200 -0
  84. package/Server/Utils/AI/Chat/ChatAgentRunner.ts +307 -48
  85. package/Server/Utils/AI/Chat/ChatRunCancellation.ts +156 -0
  86. package/Server/Utils/AI/Chat/ObservabilityAssistant.ts +78 -18
  87. package/Server/Utils/AI/Chat/ObservabilityChatPrompt.ts +1 -1
  88. package/Server/Utils/AI/Chat/ToolOutputPager.ts +322 -0
  89. package/Server/Utils/AI/ClusterAccess/KubectlInvestigationToolkit.ts +88 -30
  90. package/Server/Utils/AI/ClusterAccess/KubectlJobRunner.ts +13 -1
  91. package/Server/Utils/AI/CodeFix/CodeFixReadiness.ts +0 -32
  92. package/Server/Utils/AI/CodeFix/FixRunBudget.ts +27 -25
  93. package/Server/Utils/AI/Remediation/RemediationCommandTools.ts +7 -1
  94. package/Server/Utils/AI/Remediation/RemediationExecutionRunner.ts +34 -14
  95. package/Server/Utils/AI/ResourceAccess/InfrastructureInvestigationToolkit.ts +69 -24
  96. package/Server/Utils/AI/ResourceAccess/ResourceCommandJobRunner.ts +9 -0
  97. package/Server/Utils/AI/SRE/AIInvestigationEngine.ts +53 -10
  98. package/Server/Utils/AI/SRE/AlertInvestigationRunner.ts +27 -10
  99. package/Server/Utils/AI/SRE/IncidentInvestigationRunner.ts +27 -10
  100. package/Server/Utils/AI/SRE/InvestigationQueue.ts +16 -19
  101. package/Server/Utils/AI/SRE/InvestigationThread.ts +646 -0
  102. package/Server/Utils/AI/SRE/InvestigationThreadService.ts +715 -0
  103. package/Server/Utils/AI/Toolbox/Serializer.ts +10 -3
  104. package/Server/Utils/EditionEnforcement.ts +19 -202
  105. package/Server/Utils/LLM/LLMService.ts +259 -63
  106. package/Server/Utils/RelaxedScimTeamLocksReport.ts +245 -0
  107. package/Server/Utils/Rules/RuleRun/RuleRunRegistry.ts +25 -0
  108. package/Server/Utils/SameOriginRequest.ts +203 -0
  109. package/Server/Utils/TeamMember/ProjectLeaveResourceCleanup.ts +2 -0
  110. package/Server/Utils/Telemetry/EntityRegistry.ts +4 -1
  111. package/Server/Utils/Telemetry/MessageQueueDiscovery.ts +1402 -0
  112. package/Server/Utils/Telemetry/ResourceEntityFilter.ts +4 -1
  113. package/Server/Utils/VendorAssets.ts +3 -3
  114. package/Server/Utils/Workspace/MicrosoftTeams/Actions/Incident.ts +3 -1
  115. package/Server/Utils/Workspace/MicrosoftTeams/Actions/IncidentEpisode.ts +3 -1
  116. package/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.ts +10 -1
  117. package/Tests/App/Accounts/IncidentFormPage.test.tsx +2036 -0
  118. package/Tests/App/Accounts/IncidentFormServerMessages.test.ts +119 -0
  119. package/Tests/App/Accounts/IncidentFormUtils.test.ts +1157 -0
  120. package/Tests/App/Accounts/LoginPasskey.test.tsx +6 -4
  121. package/Tests/App/Accounts/LoginSso.test.tsx +724 -0
  122. package/Tests/App/AdminDashboard/AdminAuthenticationRequireSso.test.tsx +338 -0
  123. package/Tests/App/AdminDashboard/AdminAuthenticationSsoCardLocales.test.tsx +331 -0
  124. package/Tests/App/AdminDashboard/AdminEnterprisePluginPage.test.tsx +47 -33
  125. package/Tests/App/AdminDashboard/GlobalSsoOidcPages.test.tsx +1021 -0
  126. package/Tests/App/Dashboard/AffectedResourcesDisplay.test.tsx +876 -78
  127. package/Tests/App/Dashboard/AffectedResourcesSlo.test.tsx +20 -3
  128. package/Tests/App/Dashboard/CephProxmoxVMwareDocumentationCards.test.tsx +359 -0
  129. package/Tests/App/Dashboard/CephSetupGuide.test.ts +961 -0
  130. package/Tests/App/Dashboard/CloudDocumentationCard.test.tsx +381 -95
  131. package/Tests/App/Dashboard/CloudSetupGuide.test.ts +1463 -0
  132. package/Tests/App/Dashboard/ClusterAccessNotice.test.tsx +174 -12
  133. package/Tests/App/Dashboard/ContainerSetupGuideCards.test.tsx +345 -0
  134. package/Tests/App/Dashboard/CoreListEmptyStates.test.tsx +501 -0
  135. package/Tests/App/Dashboard/DashboardLazyPages.test.tsx +0 -1
  136. package/Tests/App/Dashboard/DatabaseDocumentationCard.test.tsx +400 -0
  137. package/Tests/App/Dashboard/DatabaseDocumentationMarkdown.test.ts +5 -0
  138. package/Tests/App/Dashboard/DatabaseSetupGuide.test.ts +1869 -0
  139. package/Tests/App/Dashboard/DatabaseTelemetryScope.test.ts +44 -0
  140. package/Tests/App/Dashboard/DatabaseTelemetryTabs.test.tsx +50 -9
  141. package/Tests/App/Dashboard/DockerSetupGuide.test.ts +899 -0
  142. package/Tests/App/Dashboard/DockerSwarmSetupGuide.test.ts +964 -0
  143. package/Tests/App/Dashboard/EnterpriseFeatureUpgrade.test.tsx +141 -7
  144. package/Tests/App/Dashboard/EnterprisePluginPage.test.tsx +52 -39
  145. package/Tests/App/Dashboard/EventOverviewPages.test.tsx +7 -1
  146. package/Tests/App/Dashboard/GettingStartedTaskRoutes.test.tsx +331 -0
  147. package/Tests/App/Dashboard/HomeOverviewStatsFirstRun.test.tsx +925 -0
  148. package/Tests/App/Dashboard/HostDocumentationCard.test.tsx +225 -0
  149. package/Tests/App/Dashboard/HostSetupGuide.test.ts +1183 -0
  150. package/Tests/App/Dashboard/IdentityEnterpriseShells.test.tsx +69 -45
  151. package/Tests/App/Dashboard/IncidentCreateTemplateCustomFieldSettings.test.tsx +745 -0
  152. package/Tests/App/Dashboard/IncidentCreateTemplateOwners.test.tsx +414 -0
  153. package/Tests/App/Dashboard/IncidentCustomFieldCreateSettingsForm.test.ts +1042 -0
  154. package/Tests/App/Dashboard/IncidentCustomFieldSettingsCard.test.tsx +1816 -0
  155. package/Tests/App/Dashboard/IncidentFormPlan.test.ts +89 -0
  156. package/Tests/App/Dashboard/IncidentFormShareLinkCard.test.tsx +846 -0
  157. package/Tests/App/Dashboard/IncidentFormsPages.test.tsx +1324 -0
  158. package/Tests/App/Dashboard/IncidentTemplateCustomFieldSettings.test.tsx +630 -0
  159. package/Tests/App/Dashboard/IncidentsSideMenu.test.tsx +13 -0
  160. package/Tests/App/Dashboard/IncomingEmailMonitorLinkVerifyHint.test.tsx +104 -0
  161. package/Tests/App/Dashboard/InvestigationConversation.test.tsx +1107 -0
  162. package/Tests/App/Dashboard/InvestigationConversationData.test.ts +546 -0
  163. package/Tests/App/Dashboard/InvestigationEvidenceList.test.tsx +170 -5
  164. package/Tests/App/Dashboard/InvestigationNotStarted.test.tsx +207 -2
  165. package/Tests/App/Dashboard/InvestigationPanel.test.tsx +729 -34
  166. package/Tests/App/Dashboard/InvestigationPanelStatus.test.tsx +9 -21
  167. package/Tests/App/Dashboard/InvestigationReportView.test.tsx +274 -37
  168. package/Tests/App/Dashboard/InvestigationStatusBadge.test.tsx +130 -0
  169. package/Tests/App/Dashboard/IoTDocumentationCard.test.tsx +218 -0
  170. package/Tests/App/Dashboard/IoTSetupGuide.test.ts +1124 -0
  171. package/Tests/App/Dashboard/KubernetesClusterAiAccessSettings.test.ts +20 -6
  172. package/Tests/App/Dashboard/KubernetesClusterAiDocumentationMarkdown.test.ts +107 -83
  173. package/Tests/App/Dashboard/KubernetesSetupGuide.test.ts +787 -0
  174. package/Tests/App/Dashboard/MessageQueueBreadcrumbs.test.tsx +228 -0
  175. package/Tests/App/Dashboard/MessageQueueBrokerHealth.test.tsx +1538 -0
  176. package/Tests/App/Dashboard/MessageQueueBrokerHealthMetricChart.test.tsx +969 -0
  177. package/Tests/App/Dashboard/MessageQueueBrokerHealthReads.test.ts +889 -0
  178. package/Tests/App/Dashboard/MessageQueueBrokerMetricsReach.test.ts +236 -0
  179. package/Tests/App/Dashboard/MessageQueueDocumentationCard.test.tsx +479 -0
  180. package/Tests/App/Dashboard/MessageQueueListPages.test.tsx +1232 -0
  181. package/Tests/App/Dashboard/MessageQueueMetricDescriptions.test.ts +244 -0
  182. package/Tests/App/Dashboard/MessageQueueMonitorLink.test.ts +952 -0
  183. package/Tests/App/Dashboard/MessageQueueMonitorLinkMonitorCreate.test.tsx +859 -0
  184. package/Tests/App/Dashboard/MessageQueueOverview.test.tsx +1773 -0
  185. package/Tests/App/Dashboard/MessageQueueOverviewPresentation.test.ts +196 -0
  186. package/Tests/App/Dashboard/MessageQueuePresentation.test.ts +799 -0
  187. package/Tests/App/Dashboard/MessageQueueProducersConsumers.test.tsx +680 -0
  188. package/Tests/App/Dashboard/MessageQueueRoutes.test.tsx +383 -0
  189. package/Tests/App/Dashboard/MessageQueueRulePages.test.tsx +278 -0
  190. package/Tests/App/Dashboard/MessageQueueSetupGuide.test.ts +2778 -0
  191. package/Tests/App/Dashboard/MessageQueueSideMenus.test.tsx +273 -0
  192. package/Tests/App/Dashboard/MessageQueueSpanPopulations.test.ts +930 -0
  193. package/Tests/App/Dashboard/MessageQueueSpanStore.ts +351 -0
  194. package/Tests/App/Dashboard/MessageQueueTelemetryScope.test.ts +375 -0
  195. package/Tests/App/Dashboard/MessageQueueTelemetryScopeTabs.test.tsx +668 -0
  196. package/Tests/App/Dashboard/MessageQueueViewPages.test.tsx +685 -0
  197. package/Tests/App/Dashboard/MonitorAndHomeNotOperationalMenus.test.tsx +342 -0
  198. package/Tests/App/Dashboard/MonitorCreateFirstRunDefaults.test.tsx +623 -0
  199. package/Tests/App/Dashboard/MonitorCreateFromMonitorBackedDevice.test.tsx +442 -0
  200. package/Tests/App/Dashboard/MonitorLogsPageViewSummary.test.tsx +814 -0
  201. package/Tests/App/Dashboard/MonitorSetupCardBodies.test.tsx +246 -0
  202. package/Tests/App/Dashboard/NavigationSearchKeywords.test.tsx +8 -0
  203. package/Tests/App/Dashboard/OnboardingSsoEmptyState.test.tsx +27 -12
  204. package/Tests/App/Dashboard/PlanGatedPage.test.tsx +292 -0
  205. package/Tests/App/Dashboard/PodmanSetupGuide.test.ts +948 -0
  206. package/Tests/App/Dashboard/ProductOrientation.test.tsx +5 -4
  207. package/Tests/App/Dashboard/ProductSettingsSectionCollapsed.test.tsx +266 -0
  208. package/Tests/App/Dashboard/ProxmoxSetupGuide.test.ts +1318 -0
  209. package/Tests/App/Dashboard/ResourceAiAgentAttentionServerParity.test.ts +555 -0
  210. package/Tests/App/Dashboard/ResourceAiAgentPage.test.tsx +298 -9
  211. package/Tests/App/Dashboard/ResourceAiAgentStatus.test.ts +453 -0
  212. package/Tests/App/Dashboard/ResourceArchiveSettings.test.tsx +16 -0
  213. package/Tests/App/Dashboard/ResourceConnectionGuideCard.test.tsx +444 -0
  214. package/Tests/App/Dashboard/ResourceConnectionGuideOverviewsInfra.test.tsx +798 -0
  215. package/Tests/App/Dashboard/ResourceConnectionGuideOverviewsPlatforms.test.tsx +717 -0
  216. package/Tests/App/Dashboard/ResourceConnectionGuides.test.ts +981 -0
  217. package/Tests/App/Dashboard/ResourceConnectionState.test.ts +132 -0
  218. package/Tests/App/Dashboard/RumDocumentationCard.test.tsx +293 -0
  219. package/Tests/App/Dashboard/RumSessionReplayRetentionSettings.test.tsx +467 -0
  220. package/Tests/App/Dashboard/RumSetupGuide.test.ts +758 -0
  221. package/Tests/App/Dashboard/ScheduledMaintenanceOverviewPage.test.tsx +25 -0
  222. package/Tests/App/Dashboard/ServerlessDocumentationCard.test.tsx +254 -0
  223. package/Tests/App/Dashboard/ServerlessSetupGuide.test.ts +1074 -0
  224. package/Tests/App/Dashboard/SetupGuide.test.ts +246 -0
  225. package/Tests/App/Dashboard/SetupGuideCard.test.tsx +756 -0
  226. package/Tests/App/Dashboard/SloListSideMenu.test.tsx +120 -0
  227. package/Tests/App/Dashboard/SsoPages.test.tsx +833 -0
  228. package/Tests/App/Dashboard/TelemetryDocumentation.test.tsx +253 -0
  229. package/Tests/App/Dashboard/TelemetryRetentionShells.test.tsx +730 -0
  230. package/Tests/App/Dashboard/VMwareSetupGuide.test.ts +1033 -0
  231. package/Tests/App/StatusPage/StatusPageSsoEmptyState.test.tsx +87 -7
  232. package/Tests/Models/DatabaseModels/DatabaseServerModels.test.ts +28 -9
  233. package/Tests/Models/DatabaseModels/IncidentFormModel.test.ts +1250 -0
  234. package/Tests/Models/DatabaseModels/MessageQueueModels.test.ts +1983 -0
  235. package/Tests/Models/DatabaseModels/StaticRuleCriteriaInheritance.test.ts +4 -2
  236. package/Tests/Models/DatabaseModels/TeamComplianceSettingModel.test.ts +190 -14
  237. package/Tests/Models/IncidentTemplateCustomFieldSettingsColumn.test.ts +291 -0
  238. package/Tests/Server/API/AIInvestigationConversationAPI.test.ts +412 -0
  239. package/Tests/Server/API/GlobalConfigLicense.test.ts +38 -9
  240. package/Tests/Server/API/IncidentFormAPI.test.ts +942 -0
  241. package/Tests/Server/API/IncidentFormPublicRoutes.test.ts +1653 -0
  242. package/Tests/Server/API/KubernetesClusterAiAccessAPI.test.ts +2 -1
  243. package/Tests/Server/API/{SsoProviderListingsEdition.test.ts → SsoProviderListings.test.ts} +164 -110
  244. package/Tests/Server/Enterprise/EnterpriseEdition.test.ts +76 -54
  245. package/Tests/Server/Enterprise/EnterpriseFeatureActive.test.ts +125 -42
  246. package/Tests/Server/Enterprise/EnterpriseLicenseSnapshot.test.ts +36 -10
  247. package/Tests/Server/Enterprise/EnterpriseModelFeatureMap.test.ts +51 -9
  248. package/Tests/Server/Enterprise/FakeEnterpriseModule.ts +13 -8
  249. package/Tests/Server/Enterprise/SsoInCommunityEdition.test.ts +540 -0
  250. package/Tests/Server/Infrastructure/Postgres/AddConfigurableRuleCriteriaMigration.test.ts +3 -0
  251. package/Tests/Server/Infrastructure/Postgres/AddIncidentFormsMigration.test.ts +438 -0
  252. package/Tests/Server/Infrastructure/Postgres/AddTeamComplianceRuleNotificationChannelsMigration.test.ts +255 -0
  253. package/Tests/Server/Infrastructure/Postgres/MessageQueueTablesMigration.test.ts +637 -0
  254. package/Tests/Server/Middleware/IncidentFormRateLimit.test.ts +1630 -0
  255. package/Tests/Server/Middleware/UserAuthorization.test.ts +16 -17
  256. package/Tests/Server/Middleware/UserAuthorizationSsoEnforcement.test.ts +544 -0
  257. package/Tests/Server/Services/AIServiceDailyBudget.test.ts +37 -8
  258. package/Tests/Server/Services/IncidentCreatedFeedTitle.test.ts +212 -0
  259. package/Tests/Server/Services/IncidentCustomFieldDeleteFormQuestions.test.ts +297 -0
  260. package/Tests/Server/Services/IncidentFormOwnersCreatedNotification.test.ts +497 -0
  261. package/Tests/Server/Services/IncidentFormPostgres.test.ts +958 -0
  262. package/Tests/Server/Services/IncidentFormPublicForm.test.ts +1260 -0
  263. package/Tests/Server/Services/IncidentFormPublicSubmission.test.ts +2520 -0
  264. package/Tests/Server/Services/IncidentFormRegistration.test.ts +159 -0
  265. package/Tests/Server/Services/IncidentFormService.test.ts +663 -0
  266. package/Tests/Server/Services/IncidentFormSubmissionService.test.ts +430 -0
  267. package/Tests/Server/Services/IncidentFormSubmissionTemplateBranch.test.ts +473 -0
  268. package/Tests/Server/Services/IncidentGroupingTemplateSubstitution.test.ts +81 -0
  269. package/Tests/Server/Services/IncidentTemplateCustomFieldSettings.test.ts +262 -0
  270. package/Tests/Server/Services/IncidentTemplateOwnersOnDeclare.test.ts +566 -0
  271. package/Tests/Server/Services/IncidentTitleMarkdownSinks.test.ts +640 -0
  272. package/Tests/Server/Services/LlmLogServiceTokenAggregateParams.test.ts +3 -3
  273. package/Tests/Server/Services/MessageQueueOwnerServices.test.ts +440 -0
  274. package/Tests/Server/Services/MessageQueueRegistries.test.ts +577 -0
  275. package/Tests/Server/Services/MessageQueueRuleEngines.test.ts +900 -0
  276. package/Tests/Server/Services/MessageQueueService.test.ts +2210 -0
  277. package/Tests/Server/Services/MessageQueueSqlPostgres.test.ts +1271 -0
  278. package/Tests/Server/Services/OpenTelemetryResourceRetentionMemo.test.ts +28 -1
  279. package/Tests/Server/Services/OpenTelemetryRetentionOverrideEdition.test.ts +474 -0
  280. package/Tests/Server/Services/OpenTelemetryServiceResolutionCache.test.ts +21 -0
  281. package/Tests/Server/Services/OwnerRowUniqueness.test.ts +3 -0
  282. package/Tests/Server/Services/ProjectServiceAuditLogLicense.test.ts +0 -1
  283. package/Tests/Server/Services/RuleRun/LabelRuleEnginesGroupBRun.test.ts +56 -6
  284. package/Tests/Server/Services/RuleRun/OwnerRuleEnginesGroupBRun.test.ts +30 -1
  285. package/Tests/Server/Services/SsoRequirementReads.test.ts +454 -0
  286. package/Tests/Server/Services/SsoRequirementWrites.test.ts +529 -0
  287. package/Tests/Server/Services/StaticRuleCriteriaRuntimeCoverage.test.ts +3 -3
  288. package/Tests/Server/Services/StatusPagePrivateUserInvitationPolicy.test.ts +107 -89
  289. package/Tests/Server/Services/TeamComplianceSettingPostgres.test.ts +1068 -176
  290. package/Tests/Server/Services/TeamComplianceSettingService.test.ts +1962 -200
  291. package/Tests/Server/Types/Database/Permissions/EditionPermission.test.ts +654 -297
  292. package/Tests/Server/Types/Database/Permissions/RetentionOverrideColumns.test.ts +784 -0
  293. package/Tests/Server/Types/Database/Permissions/SsoScalePlanGate.test.ts +418 -0
  294. package/Tests/Server/Utils/AI/AIAlertGating.test.ts +0 -1
  295. package/Tests/Server/Utils/AI/AIInvestigationEngineRunLimits.test.ts +136 -0
  296. package/Tests/Server/Utils/AI/AIInvestigationQueue.test.ts +15 -14
  297. package/Tests/Server/Utils/AI/AgentContextCompactor.test.ts +351 -0
  298. package/Tests/Server/Utils/AI/ChatAgentRunnerSharedThread.test.ts +842 -0
  299. package/Tests/Server/Utils/AI/ChatRunCancellation.test.ts +195 -0
  300. package/Tests/Server/Utils/AI/CodeFixReadiness.test.ts +10 -57
  301. package/Tests/Server/Utils/AI/FixRunBudget.test.ts +20 -24
  302. package/Tests/Server/Utils/AI/Insights/InvestigationQueueInsightSubject.test.ts +7 -30
  303. package/Tests/Server/Utils/AI/InvestigationClusterAccessWiring.test.ts +225 -29
  304. package/Tests/Server/Utils/AI/InvestigationInfrastructureAccessWiring.test.ts +266 -25
  305. package/Tests/Server/Utils/AI/InvestigationThread.test.ts +580 -0
  306. package/Tests/Server/Utils/AI/InvestigationThreadService.test.ts +801 -0
  307. package/Tests/Server/Utils/AI/KubectlInvestigationToolkit.test.ts +525 -43
  308. package/Tests/Server/Utils/AI/KubectlJobRunner.test.ts +4 -2
  309. package/Tests/Server/Utils/AI/LLMServiceUnreachableProvider.test.ts +435 -0
  310. package/Tests/Server/Utils/AI/ObservabilityAssistantLimits.test.ts +462 -0
  311. package/Tests/Server/Utils/AI/RemediationExecutionRunner.test.ts +14 -25
  312. package/Tests/Server/Utils/AI/RemediationExecutionRunnerResourceMode.test.ts +2 -0
  313. package/Tests/Server/Utils/AI/ResourceAccess/InfrastructureInvestigationToolkit.test.ts +297 -15
  314. package/Tests/Server/Utils/AI/ResourceAccess/ResourceCommandJobRunner.test.ts +10 -6
  315. package/Tests/Server/Utils/AI/ToolOutputPager.test.ts +382 -0
  316. package/Tests/Server/Utils/AI/ToolResultSerializer.test.ts +23 -4
  317. package/Tests/Server/Utils/AI/Toolbox/LogTools.test.ts +25 -6
  318. package/Tests/Server/Utils/AI/Toolbox/Serializer.test.ts +14 -3
  319. package/Tests/Server/Utils/EditionEnforcement.test.ts +107 -147
  320. package/Tests/Server/Utils/{CommunityEditionSsoReport.test.ts → RelaxedScimTeamLocksReport.test.ts} +212 -208
  321. package/Tests/Server/Utils/SameOriginRequest.test.ts +372 -0
  322. package/Tests/Server/Utils/Telemetry/EntityRegistry.test.ts +20 -0
  323. package/Tests/Server/Utils/Telemetry/MessageQueueDiscovery.test.ts +2590 -0
  324. package/Tests/Server/Utils/Telemetry/MessageQueueSpanQueryTwin.ts +246 -0
  325. package/Tests/Server/Utils/Telemetry/TelemetryEntity.test.ts +23 -0
  326. package/Tests/Types/AI/AIAgentRunLimits.test.ts +255 -0
  327. package/Tests/Types/Code/JsonSyntax.test.ts +1300 -0
  328. package/Tests/Types/CustomField/CustomFieldCreateSettings.test.ts +1113 -0
  329. package/Tests/Types/CustomField/CustomFieldMappingCatalog.test.ts +91 -0
  330. package/Tests/Types/CustomField/CustomFieldValueValidator.test.ts +30 -0
  331. package/Tests/Types/Incident/IncidentFormIpAllowlist.test.ts +227 -0
  332. package/Tests/Types/Incident/IncidentFormPublic.test.ts +1916 -0
  333. package/Tests/Types/MessageQueue/MessageQueueEntityKey.test.ts +916 -0
  334. package/Tests/Types/MessageQueue/MessageQueueIdentity.test.ts +567 -0
  335. package/Tests/Types/MessageQueue/MessageQueueManualIdentity.test.ts +686 -0
  336. package/Tests/Types/MessageQueue/MessageQueueMetricCatalog.test.ts +1726 -0
  337. package/Tests/Types/MessageQueue/MessageQueueMetricResolution.test.ts +1758 -0
  338. package/Tests/Types/MessageQueue/MessagingInstrumentationFixtures.test.ts +4686 -0
  339. package/Tests/Types/MessageQueue/MessagingSystem.test.ts +840 -0
  340. package/Tests/Types/MessageQueue/MessagingTelemetryFixtures.ts +3287 -0
  341. package/Tests/Types/MessageQueue/MessagingTelemetryResolver.test.ts +2966 -0
  342. package/Tests/Types/Monitor/MessageQueueAlertTemplates.test.ts +5401 -0
  343. package/Tests/Types/Monitor/MetricEngineFold.ts +154 -0
  344. package/Tests/Types/ResourceAiAgent/ResourceAiAccess.test.ts +5 -3
  345. package/Tests/Types/Team/ComplianceRule.test.ts +588 -37
  346. package/Tests/Types/Team/TeamComplianceStatus.test.ts +64 -11
  347. package/Tests/Types/XML.test.ts +51 -0
  348. package/Tests/UI/Components/CodeEditor/CodeEditor.test.tsx +2362 -0
  349. package/Tests/UI/Components/CodeEditor/CodeEditorCommands.test.ts +810 -0
  350. package/Tests/UI/Components/CodeEditor/CodeEditorHighlight.test.ts +338 -0
  351. package/Tests/UI/Components/CodeEditor/CodeEditorLanguages.test.ts +222 -0
  352. package/Tests/UI/Components/CodeEditor/CodeEditorStyles.test.ts +807 -0
  353. package/Tests/UI/Components/CodeEditor/NoMonaco.test.ts +245 -0
  354. package/Tests/UI/Components/CodeEditor/YamlEditor.test.tsx +729 -0
  355. package/Tests/UI/Components/CopyTextButton.test.tsx +76 -0
  356. package/Tests/UI/Components/EditionLabelLapseCopy.ts +51 -14
  357. package/Tests/UI/Components/EditionLabelLicenseStatus.test.tsx +131 -23
  358. package/Tests/UI/Components/ErrorMessageAction.test.tsx +142 -0
  359. package/Tests/UI/Components/FacetSidebarInScope.test.tsx +459 -0
  360. package/Tests/UI/Components/FacetValuesInScope.test.ts +270 -0
  361. package/Tests/UI/Components/Forms/FormFieldCodeEditors.test.tsx +294 -0
  362. package/Tests/UI/Components/Forms/FormFieldMarkdown.test.tsx +126 -0
  363. package/Tests/UI/Components/Forms/FormFieldYaml.test.tsx +22 -75
  364. package/Tests/UI/Components/Forms/ModelFormOnBeforeCreateMiscData.test.tsx +254 -0
  365. package/Tests/UI/Components/Icon.test.tsx +32 -0
  366. package/Tests/UI/Components/Input.test.tsx +31 -0
  367. package/Tests/UI/Components/LockedFilterChipScope.test.tsx +501 -0
  368. package/Tests/UI/Components/MarkdownConverters.test.ts +253 -1
  369. package/Tests/UI/Components/MarkdownEditor.test.tsx +2785 -2
  370. package/Tests/UI/Components/MarkdownEditorHistory.test.ts +243 -0
  371. package/Tests/UI/Components/MarkdownListEditing.test.ts +1118 -0
  372. package/Tests/UI/Components/MarkdownPaste.test.ts +1180 -0
  373. package/Tests/UI/Components/MarkdownViewerCopy.test.tsx +466 -0
  374. package/Tests/UI/Components/MarkdownVisualEditing.test.ts +1089 -0
  375. package/Tests/UI/Components/ModelTable/BaseModelTableEmptyStateAction.test.tsx +623 -0
  376. package/Tests/UI/Components/ResetObjectID.test.tsx +282 -0
  377. package/Tests/UI/Components/RuleCriteria/RuleCriteriaModelTable.test.tsx +3 -3
  378. package/Tests/UI/Components/Table/EmptyTableMessage.test.ts +439 -0
  379. package/Tests/UI/Components/Table/TableEmptyState.test.tsx +352 -0
  380. package/Tests/UI/Components/TableRowMobileTitles.test.tsx +78 -0
  381. package/Tests/UI/Components/TextArea.test.tsx +19 -0
  382. package/Tests/UI/Components/Workflow/ModelColumnEditor.render.test.tsx +12 -29
  383. package/Tests/UI/Components/fixtures/MarkdownPasteFixtures.ts +460 -0
  384. package/Tests/UI/EsbuildConfig.test.ts +115 -39
  385. package/Tests/UI/EsbuildEnterpriseAlias.test.ts +4 -4
  386. package/Tests/UI/Monitor/MonitorLogSummaryRender.test.tsx +377 -0
  387. package/Tests/UI/Utils/Breadcrumb/fixtures/RealBreadcrumbTrails.ts +81 -1
  388. package/Tests/UI/Utils/Breadcrumb/fixtures/RealRoutePatterns.ts +17 -0
  389. package/Tests/Utils/LabelRuleImportExport.test.ts +5 -0
  390. package/Tests/Utils/Markdown/DashboardMarkdownRenderer.ts +81 -0
  391. package/Tests/Utils/Markdown/UntrustedMarkdown.test.ts +1339 -0
  392. package/Tests/Utils/Monitor/MonitorLogSummaryUtil.test.ts +862 -0
  393. package/Types/AI/AIAgentRunLimits.ts +146 -0
  394. package/Types/Code/CodeType.ts +2 -0
  395. package/Types/Code/JsonSyntax.ts +923 -0
  396. package/Types/CustomField/CustomFieldCreateSettings.ts +549 -0
  397. package/Types/CustomField/CustomFieldMappingCatalog.ts +77 -0
  398. package/Types/CustomField/CustomFieldValueValidator.ts +10 -7
  399. package/Types/EnterpriseLicense/EnterpriseLicensePeriods.ts +1 -1
  400. package/Types/Icon/IconProp.ts +2 -0
  401. package/Types/Incident/IncidentFormIpAllowlist.ts +206 -0
  402. package/Types/Incident/IncidentFormPublic.ts +1145 -0
  403. package/Types/Kubernetes/KubernetesClusterAiAccess.ts +10 -3
  404. package/Types/MessageQueue/MessageQueueIdentity.ts +256 -0
  405. package/Types/MessageQueue/MessageQueueManualIdentity.ts +325 -0
  406. package/Types/MessageQueue/MessageQueueMetricCatalog.ts +1357 -0
  407. package/Types/MessageQueue/MessagingSystem.ts +518 -0
  408. package/Types/MessageQueue/MessagingTelemetryResolver.ts +2311 -0
  409. package/Types/Monitor/MessageQueueAlertTemplates.ts +2128 -0
  410. package/Types/Permission.ts +310 -0
  411. package/Types/ResourceAiAgent/ResourceAiAccess.ts +10 -4
  412. package/Types/Rules/RuleCriteriaFieldRegistry.ts +12 -0
  413. package/Types/Rules/RuleRun.ts +4 -0
  414. package/Types/Team/ComplianceNotificationChannel.ts +4 -3
  415. package/Types/Team/ComplianceRule.ts +71 -18
  416. package/Types/Team/ComplianceRuleType.ts +2 -2
  417. package/Types/Team/TeamComplianceStatus.ts +6 -2
  418. package/Types/Telemetry/EntityType.ts +16 -0
  419. package/Types/Telemetry/LockedFilterDetail.ts +22 -0
  420. package/Types/XML.ts +26 -0
  421. package/UI/Components/CodeEditor/CodeEditor.css +379 -0
  422. package/UI/Components/CodeEditor/CodeEditor.tsx +1128 -294
  423. package/UI/Components/CodeEditor/CodeEditorCommands.ts +774 -0
  424. package/UI/Components/CodeEditor/CodeEditorHighlight.ts +106 -0
  425. package/UI/Components/CodeEditor/CodeEditorLanguages.ts +164 -0
  426. package/UI/Components/CodeEditor/YamlEditor.tsx +28 -326
  427. package/UI/Components/CopyTextButton/CopyTextButton.tsx +5 -1
  428. package/UI/Components/CustomFields/CustomFieldModelFormFields.tsx +6 -25
  429. package/UI/Components/EditionLabel/EditionLabel.tsx +14 -13
  430. package/UI/Components/ErrorMessage/ErrorMessage.tsx +11 -1
  431. package/UI/Components/Forms/Fields/FormField.tsx +8 -0
  432. package/UI/Components/Forms/Types/Field.ts +8 -0
  433. package/UI/Components/Icon/Icon.tsx +18 -0
  434. package/UI/Components/Input/Input.tsx +11 -4
  435. package/UI/Components/LogsViewer/LogsViewer.tsx +4 -0
  436. package/UI/Components/LogsViewer/components/LogsFacetSidebar.tsx +21 -3
  437. package/UI/Components/Markdown.tsx/MarkdownConverters.ts +0 -0
  438. package/UI/Components/Markdown.tsx/MarkdownEditor.tsx +877 -79
  439. package/UI/Components/Markdown.tsx/MarkdownEditorHistory.ts +284 -0
  440. package/UI/Components/Markdown.tsx/MarkdownListEditing.ts +1362 -0
  441. package/UI/Components/Markdown.tsx/MarkdownPaste.ts +1326 -0
  442. package/UI/Components/Markdown.tsx/MarkdownViewer.tsx +106 -10
  443. package/UI/Components/Markdown.tsx/MarkdownVisualEditing.ts +1032 -0
  444. package/UI/Components/ModelTable/BaseModelTable.tsx +85 -7
  445. package/UI/Components/ResetObjectID/ResetObjectID.tsx +35 -9
  446. package/UI/Components/Table/EmptyTableMessage.ts +81 -0
  447. package/UI/Components/Table/Table.tsx +50 -21
  448. package/UI/Components/Table/TableRow.tsx +9 -1
  449. package/UI/Components/TelemetryViewer/FacetVisibility.ts +97 -2
  450. package/UI/Components/TelemetryViewer/TelemetryViewer.tsx +13 -0
  451. package/UI/Components/TelemetryViewer/components/LockedFilterChip.tsx +214 -7
  452. package/UI/Components/TelemetryViewer/components/TelemetryFacetSidebar.tsx +21 -3
  453. package/UI/Components/TextArea/TextArea.tsx +9 -2
  454. package/UI/Components/Workflow/ModelFieldPicker.tsx +10 -12
  455. package/UI/Styles/Theme.css +8 -0
  456. package/UI/esbuild-config.js +2 -32
  457. package/Utils/LabelRuleImportExport.ts +2 -0
  458. package/Utils/Markdown/UntrustedMarkdown.ts +1513 -0
  459. package/Utils/Monitor/IncomingEmailMonitorRequestUtil.ts +41 -0
  460. package/Utils/Monitor/MonitorLogSummaryUtil.ts +212 -0
  461. package/Utils/Telemetry/EntityKey.ts +48 -0
  462. package/build/dist/Models/DatabaseModels/AIConversation.js +125 -1
  463. package/build/dist/Models/DatabaseModels/AIConversation.js.map +1 -1
  464. package/build/dist/Models/DatabaseModels/CephCluster.js +12 -0
  465. package/build/dist/Models/DatabaseModels/CephCluster.js.map +1 -1
  466. package/build/dist/Models/DatabaseModels/CloudResource.js +12 -0
  467. package/build/dist/Models/DatabaseModels/CloudResource.js.map +1 -1
  468. package/build/dist/Models/DatabaseModels/DatabaseServer.js +12 -0
  469. package/build/dist/Models/DatabaseModels/DatabaseServer.js.map +1 -1
  470. package/build/dist/Models/DatabaseModels/DockerHost.js +12 -0
  471. package/build/dist/Models/DatabaseModels/DockerHost.js.map +1 -1
  472. package/build/dist/Models/DatabaseModels/DockerSwarmCluster.js +12 -0
  473. package/build/dist/Models/DatabaseModels/DockerSwarmCluster.js.map +1 -1
  474. package/build/dist/Models/DatabaseModels/GlobalOidc.js +0 -4
  475. package/build/dist/Models/DatabaseModels/GlobalOidc.js.map +1 -1
  476. package/build/dist/Models/DatabaseModels/GlobalOidcProject.js +0 -4
  477. package/build/dist/Models/DatabaseModels/GlobalOidcProject.js.map +1 -1
  478. package/build/dist/Models/DatabaseModels/GlobalSso.js +0 -4
  479. package/build/dist/Models/DatabaseModels/GlobalSso.js.map +1 -1
  480. package/build/dist/Models/DatabaseModels/GlobalSsoProject.js +0 -4
  481. package/build/dist/Models/DatabaseModels/GlobalSsoProject.js.map +1 -1
  482. package/build/dist/Models/DatabaseModels/Host.js +12 -0
  483. package/build/dist/Models/DatabaseModels/Host.js.map +1 -1
  484. package/build/dist/Models/DatabaseModels/IncidentForm.js +605 -0
  485. package/build/dist/Models/DatabaseModels/IncidentForm.js.map +1 -0
  486. package/build/dist/Models/DatabaseModels/IncidentFormSubmission.js +299 -0
  487. package/build/dist/Models/DatabaseModels/IncidentFormSubmission.js.map +1 -0
  488. package/build/dist/Models/DatabaseModels/IncidentTemplate.js +60 -0
  489. package/build/dist/Models/DatabaseModels/IncidentTemplate.js.map +1 -1
  490. package/build/dist/Models/DatabaseModels/Index.js +14 -0
  491. package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
  492. package/build/dist/Models/DatabaseModels/IoTFleet.js +12 -0
  493. package/build/dist/Models/DatabaseModels/IoTFleet.js.map +1 -1
  494. package/build/dist/Models/DatabaseModels/KubernetesCluster.js +12 -0
  495. package/build/dist/Models/DatabaseModels/KubernetesCluster.js.map +1 -1
  496. package/build/dist/Models/DatabaseModels/MessageQueue.js +1106 -0
  497. package/build/dist/Models/DatabaseModels/MessageQueue.js.map +1 -0
  498. package/build/dist/Models/DatabaseModels/MessageQueueLabelRule.js +562 -0
  499. package/build/dist/Models/DatabaseModels/MessageQueueLabelRule.js.map +1 -0
  500. package/build/dist/Models/DatabaseModels/MessageQueueOwnerRule.js +643 -0
  501. package/build/dist/Models/DatabaseModels/MessageQueueOwnerRule.js.map +1 -0
  502. package/build/dist/Models/DatabaseModels/MessageQueueOwnerTeam.js +506 -0
  503. package/build/dist/Models/DatabaseModels/MessageQueueOwnerTeam.js.map +1 -0
  504. package/build/dist/Models/DatabaseModels/MessageQueueOwnerUser.js +505 -0
  505. package/build/dist/Models/DatabaseModels/MessageQueueOwnerUser.js.map +1 -0
  506. package/build/dist/Models/DatabaseModels/PodmanHost.js +12 -0
  507. package/build/dist/Models/DatabaseModels/PodmanHost.js.map +1 -1
  508. package/build/dist/Models/DatabaseModels/Project.js +61 -0
  509. package/build/dist/Models/DatabaseModels/Project.js.map +1 -1
  510. package/build/dist/Models/DatabaseModels/ProjectOidc.js +0 -4
  511. package/build/dist/Models/DatabaseModels/ProjectOidc.js.map +1 -1
  512. package/build/dist/Models/DatabaseModels/ProjectSso.js +0 -4
  513. package/build/dist/Models/DatabaseModels/ProjectSso.js.map +1 -1
  514. package/build/dist/Models/DatabaseModels/ProxmoxCluster.js +12 -0
  515. package/build/dist/Models/DatabaseModels/ProxmoxCluster.js.map +1 -1
  516. package/build/dist/Models/DatabaseModels/RumApplication.js +12 -0
  517. package/build/dist/Models/DatabaseModels/RumApplication.js.map +1 -1
  518. package/build/dist/Models/DatabaseModels/ServerlessFunction.js +12 -0
  519. package/build/dist/Models/DatabaseModels/ServerlessFunction.js.map +1 -1
  520. package/build/dist/Models/DatabaseModels/Service.js +12 -0
  521. package/build/dist/Models/DatabaseModels/Service.js.map +1 -1
  522. package/build/dist/Models/DatabaseModels/StatusPageOidc.js +0 -4
  523. package/build/dist/Models/DatabaseModels/StatusPageOidc.js.map +1 -1
  524. package/build/dist/Models/DatabaseModels/StatusPageSso.js +0 -4
  525. package/build/dist/Models/DatabaseModels/StatusPageSso.js.map +1 -1
  526. package/build/dist/Models/DatabaseModels/TeamComplianceSetting.js +49 -3
  527. package/build/dist/Models/DatabaseModels/TeamComplianceSetting.js.map +1 -1
  528. package/build/dist/Models/DatabaseModels/VMwareVCenter.js +12 -0
  529. package/build/dist/Models/DatabaseModels/VMwareVCenter.js.map +1 -1
  530. package/build/dist/Server/API/AIChatAPI.js +9 -103
  531. package/build/dist/Server/API/AIChatAPI.js.map +1 -1
  532. package/build/dist/Server/API/AIInvestigationAPI.js +3 -3
  533. package/build/dist/Server/API/AIInvestigationAPI.js.map +1 -1
  534. package/build/dist/Server/API/AIInvestigationConversationAPI.js +162 -0
  535. package/build/dist/Server/API/AIInvestigationConversationAPI.js.map +1 -0
  536. package/build/dist/Server/API/IncidentFormAPI.js +245 -0
  537. package/build/dist/Server/API/IncidentFormAPI.js.map +1 -0
  538. package/build/dist/Server/API/ProjectOIDC.js +16 -24
  539. package/build/dist/Server/API/ProjectOIDC.js.map +1 -1
  540. package/build/dist/Server/API/ProjectSSO.js +16 -24
  541. package/build/dist/Server/API/ProjectSSO.js.map +1 -1
  542. package/build/dist/Server/API/StatusPageAPI.js +42 -75
  543. package/build/dist/Server/API/StatusPageAPI.js.map +1 -1
  544. package/build/dist/Server/Enterprise/EnterpriseEdition.js +79 -25
  545. package/build/dist/Server/Enterprise/EnterpriseEdition.js.map +1 -1
  546. package/build/dist/Server/Enterprise/EnterpriseFeature.js +24 -3
  547. package/build/dist/Server/Enterprise/EnterpriseFeature.js.map +1 -1
  548. package/build/dist/Server/Enterprise/EnterpriseLicenseSnapshot.js +1 -1
  549. package/build/dist/Server/Enterprise/EnterpriseServerModule.js.map +1 -1
  550. package/build/dist/Server/EnvironmentConfig.js +1 -1
  551. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1796400000000-AddIncidentForms.js +63 -0
  552. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1796400000000-AddIncidentForms.js.map +1 -0
  553. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1796500000000-AddTeamComplianceRuleNotificationChannels.js +41 -0
  554. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1796500000000-AddTeamComplianceRuleNotificationChannels.js.map +1 -0
  555. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1796600000000-AddAIInvestigationConversationAndTimeLimits.js +40 -0
  556. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1796600000000-AddAIInvestigationConversationAndTimeLimits.js.map +1 -0
  557. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1796700000000-AddMessageQueueTables.js +183 -0
  558. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1796700000000-AddMessageQueueTables.js.map +1 -0
  559. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +8 -0
  560. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  561. package/build/dist/Server/Middleware/IncidentFormRateLimit.js +559 -0
  562. package/build/dist/Server/Middleware/IncidentFormRateLimit.js.map +1 -0
  563. package/build/dist/Server/Middleware/UserAuthorization.js +11 -30
  564. package/build/dist/Server/Middleware/UserAuthorization.js.map +1 -1
  565. package/build/dist/Server/Services/AIService.js +10 -13
  566. package/build/dist/Server/Services/AIService.js.map +1 -1
  567. package/build/dist/Server/Services/IncidentCustomFieldService.js +83 -0
  568. package/build/dist/Server/Services/IncidentCustomFieldService.js.map +1 -1
  569. package/build/dist/Server/Services/IncidentEpisodeMemberService.js +8 -4
  570. package/build/dist/Server/Services/IncidentEpisodeMemberService.js.map +1 -1
  571. package/build/dist/Server/Services/IncidentEpisodeService.js +10 -1
  572. package/build/dist/Server/Services/IncidentEpisodeService.js.map +1 -1
  573. package/build/dist/Server/Services/IncidentFormService.js +1202 -0
  574. package/build/dist/Server/Services/IncidentFormService.js.map +1 -0
  575. package/build/dist/Server/Services/IncidentFormSubmissionService.js +91 -0
  576. package/build/dist/Server/Services/IncidentFormSubmissionService.js.map +1 -0
  577. package/build/dist/Server/Services/IncidentGroupingEngineService.js +20 -8
  578. package/build/dist/Server/Services/IncidentGroupingEngineService.js.map +1 -1
  579. package/build/dist/Server/Services/IncidentService.js +106 -4
  580. package/build/dist/Server/Services/IncidentService.js.map +1 -1
  581. package/build/dist/Server/Services/IncidentTemplateService.js +18 -0
  582. package/build/dist/Server/Services/IncidentTemplateService.js.map +1 -1
  583. package/build/dist/Server/Services/Index.js +14 -0
  584. package/build/dist/Server/Services/Index.js.map +1 -1
  585. package/build/dist/Server/Services/MessageQueueLabelRuleEngineService.js +262 -0
  586. package/build/dist/Server/Services/MessageQueueLabelRuleEngineService.js.map +1 -0
  587. package/build/dist/Server/Services/MessageQueueLabelRuleService.js +13 -0
  588. package/build/dist/Server/Services/MessageQueueLabelRuleService.js.map +1 -0
  589. package/build/dist/Server/Services/MessageQueueOwnerRuleEngineService.js +334 -0
  590. package/build/dist/Server/Services/MessageQueueOwnerRuleEngineService.js.map +1 -0
  591. package/build/dist/Server/Services/MessageQueueOwnerRuleService.js +13 -0
  592. package/build/dist/Server/Services/MessageQueueOwnerRuleService.js.map +1 -0
  593. package/build/dist/Server/Services/MessageQueueOwnerTeamService.js +62 -0
  594. package/build/dist/Server/Services/MessageQueueOwnerTeamService.js.map +1 -0
  595. package/build/dist/Server/Services/MessageQueueOwnerUserService.js +62 -0
  596. package/build/dist/Server/Services/MessageQueueOwnerUserService.js.map +1 -0
  597. package/build/dist/Server/Services/MessageQueueService.js +1140 -0
  598. package/build/dist/Server/Services/MessageQueueService.js.map +1 -0
  599. package/build/dist/Server/Services/OpenTelemetryIngestService.js +25 -4
  600. package/build/dist/Server/Services/OpenTelemetryIngestService.js.map +1 -1
  601. package/build/dist/Server/Services/ProjectService.js +0 -54
  602. package/build/dist/Server/Services/ProjectService.js.map +1 -1
  603. package/build/dist/Server/Services/StatusPagePrivateUserService.js +1 -4
  604. package/build/dist/Server/Services/StatusPagePrivateUserService.js.map +1 -1
  605. package/build/dist/Server/Services/StatusPageService.js +0 -46
  606. package/build/dist/Server/Services/StatusPageService.js.map +1 -1
  607. package/build/dist/Server/Services/TeamComplianceSettingService.js +120 -31
  608. package/build/dist/Server/Services/TeamComplianceSettingService.js.map +1 -1
  609. package/build/dist/Server/Services/UserNotificationRuleService.js +8 -1
  610. package/build/dist/Server/Services/UserNotificationRuleService.js.map +1 -1
  611. package/build/dist/Server/Services/WorkspaceNotificationSummaryService.js +12 -3
  612. package/build/dist/Server/Services/WorkspaceNotificationSummaryService.js.map +1 -1
  613. package/build/dist/Server/Types/Database/Permissions/CreatePermission.js +6 -3
  614. package/build/dist/Server/Types/Database/Permissions/CreatePermission.js.map +1 -1
  615. package/build/dist/Server/Types/Database/Permissions/EditionPermission.js +109 -37
  616. package/build/dist/Server/Types/Database/Permissions/EditionPermission.js.map +1 -1
  617. package/build/dist/Server/Types/Database/Permissions/OwnerTableRegistry.js +16 -0
  618. package/build/dist/Server/Types/Database/Permissions/OwnerTableRegistry.js.map +1 -1
  619. package/build/dist/Server/Types/Database/Permissions/TablePermission.js +3 -3
  620. package/build/dist/Server/Types/Database/Permissions/UpdatePermission.js +9 -6
  621. package/build/dist/Server/Types/Database/Permissions/UpdatePermission.js.map +1 -1
  622. package/build/dist/Server/Utils/AI/Chat/AgentContextCompactor.js +128 -0
  623. package/build/dist/Server/Utils/AI/Chat/AgentContextCompactor.js.map +1 -0
  624. package/build/dist/Server/Utils/AI/Chat/ChatAgentRunner.js +192 -50
  625. package/build/dist/Server/Utils/AI/Chat/ChatAgentRunner.js.map +1 -1
  626. package/build/dist/Server/Utils/AI/Chat/ChatRunCancellation.js +133 -0
  627. package/build/dist/Server/Utils/AI/Chat/ChatRunCancellation.js.map +1 -0
  628. package/build/dist/Server/Utils/AI/Chat/ObservabilityAssistant.js +53 -13
  629. package/build/dist/Server/Utils/AI/Chat/ObservabilityAssistant.js.map +1 -1
  630. package/build/dist/Server/Utils/AI/Chat/ObservabilityChatPrompt.js +1 -1
  631. package/build/dist/Server/Utils/AI/Chat/ToolOutputPager.js +206 -0
  632. package/build/dist/Server/Utils/AI/Chat/ToolOutputPager.js.map +1 -0
  633. package/build/dist/Server/Utils/AI/ClusterAccess/KubectlInvestigationToolkit.js +53 -26
  634. package/build/dist/Server/Utils/AI/ClusterAccess/KubectlInvestigationToolkit.js.map +1 -1
  635. package/build/dist/Server/Utils/AI/ClusterAccess/KubectlJobRunner.js +4 -2
  636. package/build/dist/Server/Utils/AI/ClusterAccess/KubectlJobRunner.js.map +1 -1
  637. package/build/dist/Server/Utils/AI/CodeFix/CodeFixReadiness.js +1 -29
  638. package/build/dist/Server/Utils/AI/CodeFix/CodeFixReadiness.js.map +1 -1
  639. package/build/dist/Server/Utils/AI/CodeFix/FixRunBudget.js +24 -24
  640. package/build/dist/Server/Utils/AI/CodeFix/FixRunBudget.js.map +1 -1
  641. package/build/dist/Server/Utils/AI/Remediation/RemediationCommandTools.js +7 -2
  642. package/build/dist/Server/Utils/AI/Remediation/RemediationCommandTools.js.map +1 -1
  643. package/build/dist/Server/Utils/AI/Remediation/RemediationExecutionRunner.js +29 -14
  644. package/build/dist/Server/Utils/AI/Remediation/RemediationExecutionRunner.js.map +1 -1
  645. package/build/dist/Server/Utils/AI/ResourceAccess/InfrastructureInvestigationToolkit.js +38 -14
  646. package/build/dist/Server/Utils/AI/ResourceAccess/InfrastructureInvestigationToolkit.js.map +1 -1
  647. package/build/dist/Server/Utils/AI/ResourceAccess/ResourceCommandJobRunner.js +2 -0
  648. package/build/dist/Server/Utils/AI/ResourceAccess/ResourceCommandJobRunner.js.map +1 -1
  649. package/build/dist/Server/Utils/AI/SRE/AIInvestigationEngine.js +40 -10
  650. package/build/dist/Server/Utils/AI/SRE/AIInvestigationEngine.js.map +1 -1
  651. package/build/dist/Server/Utils/AI/SRE/AlertInvestigationRunner.js +19 -7
  652. package/build/dist/Server/Utils/AI/SRE/AlertInvestigationRunner.js.map +1 -1
  653. package/build/dist/Server/Utils/AI/SRE/IncidentInvestigationRunner.js +19 -7
  654. package/build/dist/Server/Utils/AI/SRE/IncidentInvestigationRunner.js.map +1 -1
  655. package/build/dist/Server/Utils/AI/SRE/InvestigationQueue.js +15 -18
  656. package/build/dist/Server/Utils/AI/SRE/InvestigationQueue.js.map +1 -1
  657. package/build/dist/Server/Utils/AI/SRE/InvestigationThread.js +412 -0
  658. package/build/dist/Server/Utils/AI/SRE/InvestigationThread.js.map +1 -0
  659. package/build/dist/Server/Utils/AI/SRE/InvestigationThreadService.js +495 -0
  660. package/build/dist/Server/Utils/AI/SRE/InvestigationThreadService.js.map +1 -0
  661. package/build/dist/Server/Utils/AI/Toolbox/Serializer.js +10 -3
  662. package/build/dist/Server/Utils/AI/Toolbox/Serializer.js.map +1 -1
  663. package/build/dist/Server/Utils/EditionEnforcement.js +20 -158
  664. package/build/dist/Server/Utils/EditionEnforcement.js.map +1 -1
  665. package/build/dist/Server/Utils/LLM/LLMService.js +193 -54
  666. package/build/dist/Server/Utils/LLM/LLMService.js.map +1 -1
  667. package/build/dist/Server/Utils/RelaxedScimTeamLocksReport.js +160 -0
  668. package/build/dist/Server/Utils/RelaxedScimTeamLocksReport.js.map +1 -0
  669. package/build/dist/Server/Utils/Rules/RuleRun/RuleRunRegistry.js +25 -0
  670. package/build/dist/Server/Utils/Rules/RuleRun/RuleRunRegistry.js.map +1 -1
  671. package/build/dist/Server/Utils/SameOriginRequest.js +151 -0
  672. package/build/dist/Server/Utils/SameOriginRequest.js.map +1 -0
  673. package/build/dist/Server/Utils/TeamMember/ProjectLeaveResourceCleanup.js +2 -0
  674. package/build/dist/Server/Utils/TeamMember/ProjectLeaveResourceCleanup.js.map +1 -1
  675. package/build/dist/Server/Utils/Telemetry/EntityRegistry.js +4 -1
  676. package/build/dist/Server/Utils/Telemetry/EntityRegistry.js.map +1 -1
  677. package/build/dist/Server/Utils/Telemetry/MessageQueueDiscovery.js +1015 -0
  678. package/build/dist/Server/Utils/Telemetry/MessageQueueDiscovery.js.map +1 -0
  679. package/build/dist/Server/Utils/Telemetry/ResourceEntityFilter.js +4 -1
  680. package/build/dist/Server/Utils/Telemetry/ResourceEntityFilter.js.map +1 -1
  681. package/build/dist/Server/Utils/VendorAssets.js +3 -3
  682. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/Incident.js +3 -1
  683. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/Incident.js.map +1 -1
  684. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/IncidentEpisode.js +3 -1
  685. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/IncidentEpisode.js.map +1 -1
  686. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js +10 -1
  687. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js.map +1 -1
  688. package/build/dist/Types/AI/AIAgentRunLimits.js +91 -0
  689. package/build/dist/Types/AI/AIAgentRunLimits.js.map +1 -0
  690. package/build/dist/Types/Code/CodeType.js +2 -0
  691. package/build/dist/Types/Code/CodeType.js.map +1 -1
  692. package/build/dist/Types/Code/JsonSyntax.js +604 -0
  693. package/build/dist/Types/Code/JsonSyntax.js.map +1 -0
  694. package/build/dist/Types/CustomField/CustomFieldCreateSettings.js +310 -0
  695. package/build/dist/Types/CustomField/CustomFieldCreateSettings.js.map +1 -0
  696. package/build/dist/Types/CustomField/CustomFieldMappingCatalog.js +38 -0
  697. package/build/dist/Types/CustomField/CustomFieldMappingCatalog.js.map +1 -1
  698. package/build/dist/Types/CustomField/CustomFieldValueValidator.js +10 -7
  699. package/build/dist/Types/CustomField/CustomFieldValueValidator.js.map +1 -1
  700. package/build/dist/Types/EnterpriseLicense/EnterpriseLicensePeriods.js +1 -1
  701. package/build/dist/Types/Icon/IconProp.js +2 -0
  702. package/build/dist/Types/Icon/IconProp.js.map +1 -1
  703. package/build/dist/Types/Incident/IncidentFormIpAllowlist.js +119 -0
  704. package/build/dist/Types/Incident/IncidentFormIpAllowlist.js.map +1 -0
  705. package/build/dist/Types/Incident/IncidentFormPublic.js +678 -0
  706. package/build/dist/Types/Incident/IncidentFormPublic.js.map +1 -0
  707. package/build/dist/Types/Kubernetes/KubernetesClusterAiAccess.js +10 -3
  708. package/build/dist/Types/Kubernetes/KubernetesClusterAiAccess.js.map +1 -1
  709. package/build/dist/Types/MessageQueue/MessageQueueIdentity.js +184 -0
  710. package/build/dist/Types/MessageQueue/MessageQueueIdentity.js.map +1 -0
  711. package/build/dist/Types/MessageQueue/MessageQueueManualIdentity.js +190 -0
  712. package/build/dist/Types/MessageQueue/MessageQueueManualIdentity.js.map +1 -0
  713. package/build/dist/Types/MessageQueue/MessageQueueMetricCatalog.js +1057 -0
  714. package/build/dist/Types/MessageQueue/MessageQueueMetricCatalog.js.map +1 -0
  715. package/build/dist/Types/MessageQueue/MessagingSystem.js +394 -0
  716. package/build/dist/Types/MessageQueue/MessagingSystem.js.map +1 -0
  717. package/build/dist/Types/MessageQueue/MessagingTelemetryResolver.js +1768 -0
  718. package/build/dist/Types/MessageQueue/MessagingTelemetryResolver.js.map +1 -0
  719. package/build/dist/Types/Monitor/MessageQueueAlertTemplates.js +1207 -0
  720. package/build/dist/Types/Monitor/MessageQueueAlertTemplates.js.map +1 -0
  721. package/build/dist/Types/Permission.js +274 -0
  722. package/build/dist/Types/Permission.js.map +1 -1
  723. package/build/dist/Types/ResourceAiAgent/ResourceAiAccess.js +10 -4
  724. package/build/dist/Types/ResourceAiAgent/ResourceAiAccess.js.map +1 -1
  725. package/build/dist/Types/Rules/RuleCriteriaFieldRegistry.js +12 -0
  726. package/build/dist/Types/Rules/RuleCriteriaFieldRegistry.js.map +1 -1
  727. package/build/dist/Types/Rules/RuleRun.js +4 -0
  728. package/build/dist/Types/Rules/RuleRun.js.map +1 -1
  729. package/build/dist/Types/Team/ComplianceNotificationChannel.js +4 -3
  730. package/build/dist/Types/Team/ComplianceNotificationChannel.js.map +1 -1
  731. package/build/dist/Types/Team/ComplianceRule.js +48 -14
  732. package/build/dist/Types/Team/ComplianceRule.js.map +1 -1
  733. package/build/dist/Types/Team/ComplianceRuleType.js +2 -2
  734. package/build/dist/Types/Telemetry/EntityType.js +16 -0
  735. package/build/dist/Types/Telemetry/EntityType.js.map +1 -1
  736. package/build/dist/Types/XML.js +23 -0
  737. package/build/dist/Types/XML.js.map +1 -1
  738. package/build/dist/UI/Components/CodeEditor/CodeEditor.js +641 -266
  739. package/build/dist/UI/Components/CodeEditor/CodeEditor.js.map +1 -1
  740. package/build/dist/UI/Components/CodeEditor/CodeEditorCommands.js +464 -0
  741. package/build/dist/UI/Components/CodeEditor/CodeEditorCommands.js.map +1 -0
  742. package/build/dist/UI/Components/CodeEditor/CodeEditorHighlight.js +69 -0
  743. package/build/dist/UI/Components/CodeEditor/CodeEditorHighlight.js.map +1 -0
  744. package/build/dist/UI/Components/CodeEditor/CodeEditorLanguages.js +108 -0
  745. package/build/dist/UI/Components/CodeEditor/CodeEditorLanguages.js.map +1 -0
  746. package/build/dist/UI/Components/CodeEditor/YamlEditor.js +14 -186
  747. package/build/dist/UI/Components/CodeEditor/YamlEditor.js.map +1 -1
  748. package/build/dist/UI/Components/CopyTextButton/CopyTextButton.js +5 -1
  749. package/build/dist/UI/Components/CopyTextButton/CopyTextButton.js.map +1 -1
  750. package/build/dist/UI/Components/CustomFields/CustomFieldModelFormFields.js +5 -14
  751. package/build/dist/UI/Components/CustomFields/CustomFieldModelFormFields.js.map +1 -1
  752. package/build/dist/UI/Components/EditionLabel/EditionLabel.js +14 -13
  753. package/build/dist/UI/Components/EditionLabel/EditionLabel.js.map +1 -1
  754. package/build/dist/UI/Components/ErrorMessage/ErrorMessage.js +1 -1
  755. package/build/dist/UI/Components/ErrorMessage/ErrorMessage.js.map +1 -1
  756. package/build/dist/UI/Components/Forms/Fields/FormField.js +8 -3
  757. package/build/dist/UI/Components/Forms/Fields/FormField.js.map +1 -1
  758. package/build/dist/UI/Components/Icon/Icon.js +8 -0
  759. package/build/dist/UI/Components/Icon/Icon.js.map +1 -1
  760. package/build/dist/UI/Components/Input/Input.js +11 -3
  761. package/build/dist/UI/Components/Input/Input.js.map +1 -1
  762. package/build/dist/UI/Components/LogsViewer/LogsViewer.js +2 -1
  763. package/build/dist/UI/Components/LogsViewer/LogsViewer.js.map +1 -1
  764. package/build/dist/UI/Components/LogsViewer/components/LogsFacetSidebar.js +14 -4
  765. package/build/dist/UI/Components/LogsViewer/components/LogsFacetSidebar.js.map +1 -1
  766. package/build/dist/UI/Components/Markdown.tsx/MarkdownConverters.js +0 -0
  767. package/build/dist/UI/Components/Markdown.tsx/MarkdownConverters.js.map +1 -1
  768. package/build/dist/UI/Components/Markdown.tsx/MarkdownEditor.js +710 -65
  769. package/build/dist/UI/Components/Markdown.tsx/MarkdownEditor.js.map +1 -1
  770. package/build/dist/UI/Components/Markdown.tsx/MarkdownEditorHistory.js +238 -0
  771. package/build/dist/UI/Components/Markdown.tsx/MarkdownEditorHistory.js.map +1 -0
  772. package/build/dist/UI/Components/Markdown.tsx/MarkdownListEditing.js +1028 -0
  773. package/build/dist/UI/Components/Markdown.tsx/MarkdownListEditing.js.map +1 -0
  774. package/build/dist/UI/Components/Markdown.tsx/MarkdownPaste.js +1088 -0
  775. package/build/dist/UI/Components/Markdown.tsx/MarkdownPaste.js.map +1 -0
  776. package/build/dist/UI/Components/Markdown.tsx/MarkdownViewer.js +70 -10
  777. package/build/dist/UI/Components/Markdown.tsx/MarkdownViewer.js.map +1 -1
  778. package/build/dist/UI/Components/Markdown.tsx/MarkdownVisualEditing.js +887 -0
  779. package/build/dist/UI/Components/Markdown.tsx/MarkdownVisualEditing.js.map +1 -0
  780. package/build/dist/UI/Components/ModelTable/BaseModelTable.js +57 -6
  781. package/build/dist/UI/Components/ModelTable/BaseModelTable.js.map +1 -1
  782. package/build/dist/UI/Components/ResetObjectID/ResetObjectID.js +7 -5
  783. package/build/dist/UI/Components/ResetObjectID/ResetObjectID.js.map +1 -1
  784. package/build/dist/UI/Components/Table/EmptyTableMessage.js +51 -0
  785. package/build/dist/UI/Components/Table/EmptyTableMessage.js.map +1 -0
  786. package/build/dist/UI/Components/Table/Table.js +30 -11
  787. package/build/dist/UI/Components/Table/Table.js.map +1 -1
  788. package/build/dist/UI/Components/Table/TableRow.js +9 -2
  789. package/build/dist/UI/Components/Table/TableRow.js.map +1 -1
  790. package/build/dist/UI/Components/TelemetryViewer/FacetVisibility.js +63 -1
  791. package/build/dist/UI/Components/TelemetryViewer/FacetVisibility.js.map +1 -1
  792. package/build/dist/UI/Components/TelemetryViewer/TelemetryViewer.js +4 -2
  793. package/build/dist/UI/Components/TelemetryViewer/TelemetryViewer.js.map +1 -1
  794. package/build/dist/UI/Components/TelemetryViewer/components/LockedFilterChip.js +91 -10
  795. package/build/dist/UI/Components/TelemetryViewer/components/LockedFilterChip.js.map +1 -1
  796. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryFacetSidebar.js +14 -4
  797. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryFacetSidebar.js.map +1 -1
  798. package/build/dist/UI/Components/TextArea/TextArea.js +9 -3
  799. package/build/dist/UI/Components/TextArea/TextArea.js.map +1 -1
  800. package/build/dist/UI/Components/Workflow/ModelFieldPicker.js +1 -2
  801. package/build/dist/UI/Components/Workflow/ModelFieldPicker.js.map +1 -1
  802. package/build/dist/Utils/LabelRuleImportExport.js +2 -0
  803. package/build/dist/Utils/LabelRuleImportExport.js.map +1 -1
  804. package/build/dist/Utils/Markdown/UntrustedMarkdown.js +988 -0
  805. package/build/dist/Utils/Markdown/UntrustedMarkdown.js.map +1 -0
  806. package/build/dist/Utils/Monitor/IncomingEmailMonitorRequestUtil.js +34 -0
  807. package/build/dist/Utils/Monitor/IncomingEmailMonitorRequestUtil.js.map +1 -0
  808. package/build/dist/Utils/Monitor/MonitorLogSummaryUtil.js +148 -0
  809. package/build/dist/Utils/Monitor/MonitorLogSummaryUtil.js.map +1 -0
  810. package/build/dist/Utils/Telemetry/EntityKey.js +36 -0
  811. package/build/dist/Utils/Telemetry/EntityKey.js.map +1 -1
  812. package/package.json +1 -3
  813. package/Server/Utils/CommunityEditionSsoReport.ts +0 -361
  814. package/Tests/App/Accounts/LoginSsoEdition.test.tsx +0 -616
  815. package/Tests/App/AdminDashboard/AdminAuthenticationSsoEdition.test.tsx +0 -217
  816. package/Tests/App/AdminDashboard/GlobalSSOEnterpriseShells.test.tsx +0 -271
  817. package/Tests/App/Dashboard/CloudDocumentationMarkdown.test.ts +0 -215
  818. package/Tests/App/Dashboard/TelemetryResourceRetentionSettings.test.tsx +0 -784
  819. package/Tests/Server/Middleware/UserAuthorizationEditionEnforcement.test.ts +0 -518
  820. package/Tests/Server/Services/SsoRequirementReadMasking.test.ts +0 -419
  821. package/Tests/Server/Services/SsoRequirementWriteGuard.test.ts +0 -769
  822. package/Tests/UI/Components/CodeEditor.test.tsx +0 -638
  823. package/Tests/UI/Components/MonacoLoader.test.ts +0 -67
  824. package/Tests/UI/Components/MonacoRuntime.test.ts +0 -121
  825. package/Tests/UI/Components/Telemetry/TelemetryRetentionConfigForm.test.tsx +0 -329
  826. package/Tests/UI/Components/YamlEditor.test.tsx +0 -847
  827. package/UI/Components/CodeEditor/MonacoLoader.ts +0 -36
  828. package/UI/Components/Telemetry/TelemetryRetentionConfigForm.tsx +0 -319
  829. package/UI/Components/Telemetry/TelemetryRetentionConfigSummary.tsx +0 -223
  830. package/build/dist/Server/Utils/CommunityEditionSsoReport.js +0 -223
  831. package/build/dist/Server/Utils/CommunityEditionSsoReport.js.map +0 -1
  832. package/build/dist/UI/Components/CodeEditor/MonacoLoader.js +0 -34
  833. package/build/dist/UI/Components/CodeEditor/MonacoLoader.js.map +0 -1
  834. package/build/dist/UI/Components/Telemetry/TelemetryRetentionConfigForm.js +0 -171
  835. package/build/dist/UI/Components/Telemetry/TelemetryRetentionConfigForm.js.map +0 -1
  836. package/build/dist/UI/Components/Telemetry/TelemetryRetentionConfigSummary.js +0 -119
  837. package/build/dist/UI/Components/Telemetry/TelemetryRetentionConfigSummary.js.map +0 -1
@@ -0,0 +1,1983 @@
1
+ import AllModelTypes, {
2
+ getModelTypeByName,
3
+ } from "../../../Models/DatabaseModels/Index";
4
+ import BaseModel from "../../../Models/DatabaseModels/DatabaseBaseModel/DatabaseBaseModel";
5
+ import RuleBaseModel from "../../../Models/DatabaseModels/DatabaseBaseModel/RuleBaseModel";
6
+ import Label from "../../../Models/DatabaseModels/Label";
7
+ import MessageQueue, {
8
+ MESSAGE_QUEUE_DISCOVERY_SOURCES,
9
+ getMessageQueueDiscoverySourceLabel,
10
+ } from "../../../Models/DatabaseModels/MessageQueue";
11
+ import MessageQueueLabelRule from "../../../Models/DatabaseModels/MessageQueueLabelRule";
12
+ import MessageQueueOwnerRule from "../../../Models/DatabaseModels/MessageQueueOwnerRule";
13
+ import MessageQueueOwnerTeam from "../../../Models/DatabaseModels/MessageQueueOwnerTeam";
14
+ import MessageQueueOwnerUser from "../../../Models/DatabaseModels/MessageQueueOwnerUser";
15
+ import Team from "../../../Models/DatabaseModels/Team";
16
+ import User from "../../../Models/DatabaseModels/User";
17
+ import DatabaseRequestType from "../../../Server/Types/BaseDatabase/DatabaseRequestType";
18
+ import ColumnPermissions from "../../../Server/Types/Database/Permissions/ColumnPermission";
19
+ import ModelPermission from "../../../Server/Types/Database/Permissions/Index";
20
+ import { ColumnAccessControl } from "../../../Types/BaseDatabase/AccessControl";
21
+ import DatabaseCommonInteractionProps from "../../../Types/BaseDatabase/DatabaseCommonInteractionProps";
22
+ import ColumnLength from "../../../Types/Database/ColumnLength";
23
+ import { TableColumnMetadata } from "../../../Types/Database/TableColumn";
24
+ import TableColumnType from "../../../Types/Database/TableColumnType";
25
+ import { getUniqueColumnsBy } from "../../../Types/Database/UniqueColumnBy";
26
+ import { UniqueColumnsTogetherMetadata } from "../../../Types/Database/UniqueColumnsTogether";
27
+ import BadDataException from "../../../Types/Exception/BadDataException";
28
+ import IconProp from "../../../Types/Icon/IconProp";
29
+ import {
30
+ MESSAGE_QUEUE_DISPLAY_NAME_MAX_LENGTH,
31
+ MESSAGE_QUEUE_IDENTIFIER_MAX_LENGTH,
32
+ MessageQueueIdentity,
33
+ buildMessageQueueIdentifier,
34
+ parseMessageQueueIdentifier,
35
+ } from "../../../Types/MessageQueue/MessageQueueIdentity";
36
+ import { MESSAGE_QUEUE_DESTINATION_MAX_LENGTH } from "../../../Types/MessageQueue/MessagingTelemetryResolver";
37
+ import {
38
+ MESSAGING_SYSTEMS,
39
+ MessagingSystemDescriptor,
40
+ } from "../../../Types/MessageQueue/MessagingSystem";
41
+ import ObjectID from "../../../Types/ObjectID";
42
+ import Permission, {
43
+ PermissionHelper,
44
+ PermissionProps,
45
+ UserTenantAccessPermission,
46
+ } from "../../../Types/Permission";
47
+ import { describe, expect, test } from "@jest/globals";
48
+ import { getMetadataArgsStorage } from "typeorm";
49
+ import { ColumnMetadataArgs } from "typeorm/metadata-args/ColumnMetadataArgs";
50
+ import { IndexMetadataArgs } from "typeorm/metadata-args/IndexMetadataArgs";
51
+ import { JoinColumnMetadataArgs } from "typeorm/metadata-args/JoinColumnMetadataArgs";
52
+ import { JoinTableMetadataArgs } from "typeorm/metadata-args/JoinTableMetadataArgs";
53
+ import { RelationMetadataArgs } from "typeorm/metadata-args/RelationMetadataArgs";
54
+ import fs from "fs";
55
+ import path from "path";
56
+
57
+ /*
58
+ * The Queues product is persisted as five TypeORM entities: the MessageQueue
59
+ * root and the owner / rule models cloned from the Databases product.
60
+ *
61
+ * What is pinned here only fails in production:
62
+ *
63
+ * - registration in Models/Index.ts (no table, no API otherwise)
64
+ * - the table / route / display names other layers key on, and staying
65
+ * clear of the BullMQ `Queue` the workers already import
66
+ * - the identity index discovery relies on for race safety, and the two
67
+ * NAMED partial unique indexes a generated migration would otherwise
68
+ * drop
69
+ * - the column ACL contract: DatabaseService.create runs onBeforeCreate
70
+ * BEFORE the column permission check, so every column the service sets on
71
+ * a manual create must be user-creatable, and every column only discovery
72
+ * writes must be closed to users - checked here against the real
73
+ * ColumnPermission / CreatePermission code, not just the declarations
74
+ * - the rule criteria fields and the permissions
75
+ * - Postgres's 63-character identifier limit
76
+ *
77
+ * Pure metadata and in-process permission checks - no Postgres connection.
78
+ */
79
+
80
+ type ModelType = { new (): BaseModel };
81
+
82
+ const MODEL_TYPES: Array<ModelType> = AllModelTypes as Array<ModelType>;
83
+
84
+ interface QueueModelSpec {
85
+ name: string;
86
+ modelType: ModelType;
87
+ tableName: string;
88
+ crudApiPath: string;
89
+ singularName: string;
90
+ pluralName: string;
91
+ icon: IconProp;
92
+ }
93
+
94
+ const QUEUE_MODELS: Array<QueueModelSpec> = [
95
+ {
96
+ name: "MessageQueue",
97
+ modelType: MessageQueue,
98
+ tableName: "MessageQueue",
99
+ crudApiPath: "/message-queue",
100
+ singularName: "Queue",
101
+ pluralName: "Queues",
102
+ icon: IconProp.QueueList,
103
+ },
104
+ {
105
+ name: "MessageQueueOwnerTeam",
106
+ modelType: MessageQueueOwnerTeam,
107
+ tableName: "MessageQueueOwnerTeam",
108
+ crudApiPath: "/message-queue-owner-team",
109
+ singularName: "Queue Team Owner",
110
+ pluralName: "Queue Team Owners",
111
+ icon: IconProp.Cube,
112
+ },
113
+ {
114
+ name: "MessageQueueOwnerUser",
115
+ modelType: MessageQueueOwnerUser,
116
+ tableName: "MessageQueueOwnerUser",
117
+ crudApiPath: "/message-queue-owner-user",
118
+ singularName: "Queue User Owner",
119
+ pluralName: "Queue User Owners",
120
+ icon: IconProp.Cube,
121
+ },
122
+ {
123
+ name: "MessageQueueLabelRule",
124
+ modelType: MessageQueueLabelRule,
125
+ tableName: "MessageQueueLabelRule",
126
+ crudApiPath: "/message-queue-label-rule",
127
+ singularName: "Queue Label Rule",
128
+ pluralName: "Queue Label Rules",
129
+ icon: IconProp.Tag,
130
+ },
131
+ {
132
+ name: "MessageQueueOwnerRule",
133
+ modelType: MessageQueueOwnerRule,
134
+ tableName: "MessageQueueOwnerRule",
135
+ crudApiPath: "/message-queue-owner-rule",
136
+ singularName: "Queue Owner Rule",
137
+ pluralName: "Queue Owner Rules",
138
+ // Every infrastructure owner rule (Ceph, VMware, Cloud, Databases) uses User.
139
+ icon: IconProp.User,
140
+ },
141
+ ];
142
+
143
+ // Every child of MessageQueue and the relation property it reaches it by.
144
+ const MESSAGE_QUEUE_CHILDREN: Array<[ModelType, string]> = [
145
+ [MessageQueueOwnerTeam, "messageQueue"],
146
+ [MessageQueueOwnerUser, "messageQueue"],
147
+ ];
148
+
149
+ const MESSAGE_QUEUE_PERMISSIONS: Array<string> = [
150
+ "CreateMessageQueue",
151
+ "DeleteMessageQueue",
152
+ "EditMessageQueue",
153
+ "ReadMessageQueue",
154
+ "CreateMessageQueueOwnerTeam",
155
+ "DeleteMessageQueueOwnerTeam",
156
+ "EditMessageQueueOwnerTeam",
157
+ "ReadMessageQueueOwnerTeam",
158
+ "CreateMessageQueueOwnerUser",
159
+ "DeleteMessageQueueOwnerUser",
160
+ "EditMessageQueueOwnerUser",
161
+ "ReadMessageQueueOwnerUser",
162
+ "CreateMessageQueueLabelRule",
163
+ "DeleteMessageQueueLabelRule",
164
+ "EditMessageQueueLabelRule",
165
+ "ReadMessageQueueLabelRule",
166
+ "CreateMessageQueueOwnerRule",
167
+ "DeleteMessageQueueOwnerRule",
168
+ "EditMessageQueueOwnerRule",
169
+ "ReadMessageQueueOwnerRule",
170
+ ];
171
+
172
+ // The rule criteria fields the registry, the engines and the forms share.
173
+ const RULE_CRITERIA_FIELDS: Array<string> = [
174
+ "messageQueueLabels",
175
+ "messageQueueNamePattern",
176
+ "messageQueueDescriptionPattern",
177
+ "messageQueueSystemPattern",
178
+ ];
179
+
180
+ /*
181
+ * Every column MessageQueueService.onBeforeCreate may set on a manual
182
+ * (non-root) create, plus what DatabaseService itself stamps (projectId,
183
+ * createdByUserId) and what the create form may send.
184
+ */
185
+ const MESSAGE_QUEUE_USER_CREATE_COLUMNS: Array<string> = [
186
+ "project",
187
+ "projectId",
188
+ "name",
189
+ "description",
190
+ "queueIdentifier",
191
+ "messagingSystem",
192
+ "destinationName",
193
+ "brokerScope",
194
+ "discoverySource",
195
+ "labels",
196
+ "isArchived",
197
+ "createdByUser",
198
+ "createdByUserId",
199
+ ];
200
+
201
+ // Columns a person may change after creation.
202
+ const MESSAGE_QUEUE_USER_UPDATE_COLUMNS: Array<string> = [
203
+ "name",
204
+ "description",
205
+ "labels",
206
+ "isArchived",
207
+ ];
208
+
209
+ // Columns only discovery, the sighting heartbeat and the archive paths write, as root.
210
+ const MESSAGE_QUEUE_ROOT_ONLY_COLUMNS: Array<string> = [
211
+ "slug",
212
+ "brokerAddress",
213
+ "lastSeenAt",
214
+ "brokerMetricsLastSeenAt",
215
+ "autoArchivedAt",
216
+ "manuallyRestoredAt",
217
+ "automaticAssignments",
218
+ "archivedAt",
219
+ "archivedByUser",
220
+ "archivedByUserId",
221
+ "deletedByUser",
222
+ "deletedByUserId",
223
+ ];
224
+
225
+ const PERMISSION_PROPS: Array<PermissionProps> =
226
+ PermissionHelper.getAllPermissionProps();
227
+
228
+ const PERMISSION_PROPS_BY_NAME: Map<string, PermissionProps> = new Map(
229
+ PERMISSION_PROPS.map((props: PermissionProps) => {
230
+ return [props.permission.toString(), props];
231
+ }),
232
+ );
233
+
234
+ const PROJECT_ID: ObjectID = new ObjectID(
235
+ "9e1b6b0e-0000-4000-8000-00000000c7a1",
236
+ );
237
+ const USER_ID: ObjectID = new ObjectID("9e1b6b0e-0000-4000-8000-00000000c7a2");
238
+
239
+ /*
240
+ * DatabaseCommonInteractionPropsUtil.getUserPermissions only reads the tenant
241
+ * bucket when props.tenantId is set, and drops every permission whose
242
+ * isBlockPermission does not match. Getting either wrong yields an empty
243
+ * permission set, which would make every "does not throw" below pass for the
244
+ * wrong reason - hence the harness guard test further down.
245
+ */
246
+ function makeProps(
247
+ permissions: Array<Permission>,
248
+ ): DatabaseCommonInteractionProps {
249
+ const tenantPermission: UserTenantAccessPermission = {
250
+ projectId: PROJECT_ID,
251
+ _type: "UserTenantAccessPermission",
252
+ permissions: permissions.map((permission: Permission) => {
253
+ return {
254
+ _type: "UserPermission",
255
+ permission: permission,
256
+ labelIds: [],
257
+ isBlockPermission: false,
258
+ };
259
+ }),
260
+ };
261
+
262
+ return {
263
+ userId: USER_ID,
264
+ tenantId: PROJECT_ID,
265
+ userTenantAccessPermission: {
266
+ [PROJECT_ID.toString()]: tenantPermission,
267
+ },
268
+ };
269
+ }
270
+
271
+ // What a manual create posts after MessageQueueService.onBeforeCreate ran.
272
+ function manualCreateData(): MessageQueue {
273
+ const data: MessageQueue = new MessageQueue();
274
+ data.projectId = PROJECT_ID;
275
+ data.name = "orders";
276
+ data.description = "Orders from checkout to fulfilment";
277
+ data.messagingSystem = "servicebus";
278
+ data.destinationName = "orders";
279
+ data.brokerScope = "orders-prod";
280
+ data.queueIdentifier = "servicebus|orders-prod|orders";
281
+ data.discoverySource = "manual";
282
+ data.createdByUserId = USER_ID;
283
+ return data;
284
+ }
285
+
286
+ type CheckFunction = () => void;
287
+
288
+ function checkCreate(
289
+ modelType: ModelType,
290
+ data: BaseModel,
291
+ permissions: Array<Permission>,
292
+ ): CheckFunction {
293
+ return () => {
294
+ ModelPermission.checkCreatePermissions(
295
+ modelType,
296
+ data,
297
+ makeProps(permissions),
298
+ );
299
+ };
300
+ }
301
+
302
+ function checkColumns(
303
+ modelType: ModelType,
304
+ data: BaseModel,
305
+ permissions: Array<Permission>,
306
+ requestType: DatabaseRequestType,
307
+ ): CheckFunction {
308
+ return () => {
309
+ ColumnPermissions.checkDataColumnPermissions(
310
+ modelType,
311
+ data,
312
+ makeProps(permissions),
313
+ requestType,
314
+ );
315
+ };
316
+ }
317
+
318
+ function allReferencedPermissions(model: BaseModel): Array<Permission> {
319
+ const permissions: Array<Permission> = [
320
+ ...(model.createRecordPermissions || []),
321
+ ...(model.readRecordPermissions || []),
322
+ ...(model.updateRecordPermissions || []),
323
+ ...(model.deleteRecordPermissions || []),
324
+ ];
325
+
326
+ for (const column of model.getTableColumns().columns) {
327
+ const accessControl: ColumnAccessControl | undefined =
328
+ model.getColumnAccessControlFor(column) || undefined;
329
+
330
+ if (!accessControl) {
331
+ continue;
332
+ }
333
+
334
+ permissions.push(
335
+ ...(accessControl.create || []),
336
+ ...(accessControl.read || []),
337
+ ...(accessControl.update || []),
338
+ );
339
+ }
340
+
341
+ return permissions;
342
+ }
343
+
344
+ /*
345
+ * DatabaseBaseModel's own columns (_id, timestamps, version). They carry the
346
+ * table ACL by default (or none, for version) and are never written through
347
+ * the column check, so the per-column sweeps below skip them.
348
+ */
349
+ const BASE_COLUMNS: Array<string> = [
350
+ "_id",
351
+ "createdAt",
352
+ "updatedAt",
353
+ "deletedAt",
354
+ "version",
355
+ ];
356
+
357
+ function ownColumns(model: BaseModel): Array<string> {
358
+ return model.getTableColumns().columns.filter((column: string): boolean => {
359
+ return !BASE_COLUMNS.includes(column);
360
+ });
361
+ }
362
+
363
+ function columnAccess(model: BaseModel, column: string): ColumnAccessControl {
364
+ const accessControl: ColumnAccessControl | null =
365
+ model.getColumnAccessControlFor(column);
366
+
367
+ if (!accessControl) {
368
+ throw new Error(`${column} has no @ColumnAccessControl`);
369
+ }
370
+
371
+ return accessControl;
372
+ }
373
+
374
+ function columnArgs(
375
+ modelType: ModelType,
376
+ property: string,
377
+ ): ColumnMetadataArgs {
378
+ const column: ColumnMetadataArgs | undefined = (
379
+ getMetadataArgsStorage().columns as Array<ColumnMetadataArgs>
380
+ ).find((candidate: ColumnMetadataArgs) => {
381
+ return (
382
+ candidate.target === modelType && candidate.propertyName === property
383
+ );
384
+ });
385
+
386
+ if (!column) {
387
+ throw new Error(`${modelType.name}.${property} is not a registered column`);
388
+ }
389
+
390
+ return column;
391
+ }
392
+
393
+ function relationArgs(
394
+ modelType: ModelType,
395
+ property: string,
396
+ ): RelationMetadataArgs {
397
+ const relation: RelationMetadataArgs | undefined = (
398
+ getMetadataArgsStorage().relations as Array<RelationMetadataArgs>
399
+ ).find((candidate: RelationMetadataArgs) => {
400
+ return (
401
+ candidate.target === modelType && candidate.propertyName === property
402
+ );
403
+ });
404
+
405
+ if (!relation) {
406
+ throw new Error(
407
+ `${modelType.name}.${property} is not a registered relation`,
408
+ );
409
+ }
410
+
411
+ return relation;
412
+ }
413
+
414
+ function joinColumnArgs(
415
+ modelType: ModelType,
416
+ property: string,
417
+ ): JoinColumnMetadataArgs {
418
+ const joinColumn: JoinColumnMetadataArgs | undefined = (
419
+ getMetadataArgsStorage().joinColumns as Array<JoinColumnMetadataArgs>
420
+ ).find((candidate: JoinColumnMetadataArgs) => {
421
+ return (
422
+ candidate.target === modelType && candidate.propertyName === property
423
+ );
424
+ });
425
+
426
+ if (!joinColumn) {
427
+ throw new Error(`${modelType.name}.${property} has no @JoinColumn`);
428
+ }
429
+
430
+ return joinColumn;
431
+ }
432
+
433
+ function joinTableArgs(
434
+ modelType: ModelType,
435
+ property: string,
436
+ ): JoinTableMetadataArgs {
437
+ const joinTable: JoinTableMetadataArgs | undefined = (
438
+ getMetadataArgsStorage().joinTables as Array<JoinTableMetadataArgs>
439
+ ).find((candidate: JoinTableMetadataArgs) => {
440
+ return (
441
+ candidate.target === modelType && candidate.propertyName === property
442
+ );
443
+ });
444
+
445
+ if (!joinTable) {
446
+ throw new Error(`${modelType.name}.${property} has no @JoinTable`);
447
+ }
448
+
449
+ return joinTable;
450
+ }
451
+
452
+ function classIndexes(modelType: ModelType): Array<IndexMetadataArgs> {
453
+ return getMetadataArgsStorage().indices.filter(
454
+ (index: IndexMetadataArgs): boolean => {
455
+ return index.target === modelType;
456
+ },
457
+ );
458
+ }
459
+
460
+ function indexOnColumns(
461
+ modelType: ModelType,
462
+ columns: Array<string>,
463
+ ): IndexMetadataArgs | undefined {
464
+ return classIndexes(modelType).find((index: IndexMetadataArgs): boolean => {
465
+ return (
466
+ Array.isArray(index.columns) &&
467
+ index.columns.length === columns.length &&
468
+ columns.every((column: string): boolean => {
469
+ return (index.columns as Array<string>).includes(column);
470
+ })
471
+ );
472
+ });
473
+ }
474
+
475
+ function propertyIndex(
476
+ modelType: ModelType,
477
+ property: string,
478
+ ): IndexMetadataArgs | undefined {
479
+ // A property-level @Index() is recorded with [propertyName] as its columns.
480
+ return classIndexes(modelType).find((index: IndexMetadataArgs): boolean => {
481
+ return (
482
+ Array.isArray(index.columns) &&
483
+ index.columns.length === 1 &&
484
+ index.columns[0] === property &&
485
+ !index.name
486
+ );
487
+ });
488
+ }
489
+
490
+ function namedIndex(
491
+ modelType: ModelType,
492
+ name: string,
493
+ ): IndexMetadataArgs | undefined {
494
+ return classIndexes(modelType).find((index: IndexMetadataArgs): boolean => {
495
+ return index.name === name;
496
+ });
497
+ }
498
+
499
+ function modelSource(modelName: string): string {
500
+ return fs.readFileSync(
501
+ path.join(
502
+ __dirname,
503
+ "..",
504
+ "..",
505
+ "..",
506
+ "Models",
507
+ "DatabaseModels",
508
+ `${modelName}.ts`,
509
+ ),
510
+ "utf8",
511
+ );
512
+ }
513
+
514
+ /*
515
+ * The source with its comments removed. Comments may name the template a
516
+ * model was cloned from ("like DatabaseServer.databaseIdentifier"); code may
517
+ * not. A line comment must start a line or follow whitespace, so the "//" of
518
+ * a URL inside a string is left alone.
519
+ */
520
+ function codeOf(source: string): string {
521
+ return source.replace(/\/\*[\s\S]*?\*\//g, "").replace(/(^|\s)\/\/.*$/gm, "");
522
+ }
523
+
524
+ function sorted(values: Array<Permission | string>): Array<string> {
525
+ return values
526
+ .map((value: Permission | string): string => {
527
+ return value.toString();
528
+ })
529
+ .sort();
530
+ }
531
+
532
+ describe("Queues (MessageQueue) models", () => {
533
+ test("the inventory is complete", () => {
534
+ expect(QUEUE_MODELS.length).toBe(5);
535
+ expect(MESSAGE_QUEUE_PERMISSIONS.length).toBe(20);
536
+ });
537
+
538
+ describe("harness guard", () => {
539
+ /*
540
+ * Runs first on purpose. Most permission assertions below are "does not
541
+ * throw", which a props object the permission util silently ignored
542
+ * would also satisfy. A caller holding only a READ grant must be refused
543
+ * a create; if it is not, makeProps is broken, not the model.
544
+ */
545
+ test("a read-only caller is refused a manual create", () => {
546
+ expect(
547
+ checkCreate(MessageQueue, manualCreateData(), [
548
+ Permission.ReadMessageQueue,
549
+ ]),
550
+ ).toThrow();
551
+ });
552
+
553
+ test("a caller with no permissions at all is refused a column write", () => {
554
+ expect(
555
+ checkColumns(
556
+ MessageQueue,
557
+ manualCreateData(),
558
+ [],
559
+ DatabaseRequestType.Create,
560
+ ),
561
+ ).toThrow(BadDataException);
562
+ });
563
+ });
564
+
565
+ describe("registration and identity", () => {
566
+ test.each(QUEUE_MODELS)(
567
+ "$name is registered in Models/Index.ts",
568
+ (spec: QueueModelSpec) => {
569
+ /*
570
+ * Boot-time createTables() and the migration generator both iterate
571
+ * that array. A model missing from it type-checks, imports fine, and
572
+ * simply has no table in Postgres.
573
+ */
574
+ expect(MODEL_TYPES).toContain(spec.modelType);
575
+ expect(
576
+ MODEL_TYPES.filter((modelType: ModelType): boolean => {
577
+ return modelType === spec.modelType;
578
+ }),
579
+ ).toHaveLength(1);
580
+ },
581
+ );
582
+
583
+ test.each(QUEUE_MODELS)(
584
+ "$name resolves by its table name through getModelTypeByName",
585
+ (spec: QueueModelSpec) => {
586
+ // The generic API / workflow layers look models up by table name.
587
+ expect(getModelTypeByName(spec.tableName)).toBe(spec.modelType);
588
+ },
589
+ );
590
+
591
+ test.each(QUEUE_MODELS)(
592
+ "$name carries its own table, route, display names and icon",
593
+ (spec: QueueModelSpec) => {
594
+ const model: BaseModel = new spec.modelType();
595
+
596
+ expect(spec.modelType.name).toBe(spec.name);
597
+ expect(model.tableName).toBe(spec.tableName);
598
+ expect(model.getCrudApiPath()?.toString()).toBe(spec.crudApiPath);
599
+ expect(model.singularName).toBe(spec.singularName);
600
+ expect(model.pluralName).toBe(spec.pluralName);
601
+ expect(model.icon).toBe(spec.icon);
602
+ expect(model.getTenantColumn()).toBe("projectId");
603
+ expect(model.enableDocumentation).toBe(true);
604
+ expect((model.tableDescription || "").length).toBeGreaterThan(20);
605
+ },
606
+ );
607
+
608
+ test("no Queues route or table name collides with another model", () => {
609
+ const routes: Map<string, number> = new Map<string, number>();
610
+ const tables: Map<string, number> = new Map<string, number>();
611
+
612
+ for (const modelType of MODEL_TYPES) {
613
+ const model: BaseModel = new modelType();
614
+ const route: string | undefined = model.getCrudApiPath()?.toString();
615
+
616
+ if (route) {
617
+ routes.set(route, (routes.get(route) || 0) + 1);
618
+ }
619
+
620
+ if (model.tableName) {
621
+ tables.set(model.tableName, (tables.get(model.tableName) || 0) + 1);
622
+ }
623
+ }
624
+
625
+ for (const spec of QUEUE_MODELS) {
626
+ expect(routes.get(spec.crudApiPath)).toBe(1);
627
+ expect(tables.get(spec.tableName)).toBe(1);
628
+ }
629
+ });
630
+
631
+ test("does not take the name the BullMQ job queue already uses", () => {
632
+ /*
633
+ * Server/Infrastructure/Queue.ts default-exports `Queue` (BullMQ) and
634
+ * every worker imports it. No model may claim the bare name, and every
635
+ * Queues route lives under /message-queue.
636
+ */
637
+ expect(getModelTypeByName("Queue")).toBeNull();
638
+
639
+ for (const spec of QUEUE_MODELS) {
640
+ expect(spec.tableName).not.toBe("Queue");
641
+ expect(spec.crudApiPath.startsWith("/message-queue")).toBe(true);
642
+ }
643
+ });
644
+
645
+ test.each(QUEUE_MODELS)(
646
+ "$name source carries no Databases leftovers",
647
+ (spec: QueueModelSpec) => {
648
+ /*
649
+ * The models were cloned from the Databases product. A leftover
650
+ * `/database-server` route or `databaseServerId` column reads fine in
651
+ * review and silently binds the wrong table. Comments are exempt:
652
+ * pointing at the template a decision was copied from is
653
+ * documentation, not a binding.
654
+ */
655
+ const source: string = codeOf(modelSource(spec.name));
656
+
657
+ // Guards the stripping itself: the class must still be in there.
658
+ expect(source).toContain(`export default class ${spec.name}`);
659
+
660
+ for (const token of [
661
+ "DatabaseServer",
662
+ "databaseServer",
663
+ "database-server",
664
+ "dbSystem",
665
+ "databases",
666
+ "Ceph",
667
+ "ceph",
668
+ ]) {
669
+ expect({ token, found: source.includes(token) }).toEqual({
670
+ token,
671
+ found: false,
672
+ });
673
+ }
674
+ },
675
+ );
676
+ });
677
+
678
+ describe("MessageQueue", () => {
679
+ const model: MessageQueue = new MessageQueue();
680
+
681
+ test("is unique per project on queueIdentifier - named, partial, the discovery join key", () => {
682
+ /*
683
+ * Discovery find-or-creates by queueIdentifier, and worker runs race on
684
+ * the same queue; only a DB-level unique index collapses them into one
685
+ * row. Partial (live rows only) and declared by name, so the drift
686
+ * check keeps it.
687
+ */
688
+ const found: IndexMetadataArgs | undefined = namedIndex(
689
+ MessageQueue,
690
+ "IDX_message_queue_identifier",
691
+ );
692
+
693
+ expect(found).toBeDefined();
694
+ expect(found?.unique).toBe(true);
695
+ expect(found?.columns).toEqual(["projectId", "queueIdentifier"]);
696
+ expect(found?.where).toBe('"deletedAt" IS NULL');
697
+ });
698
+
699
+ test("the display name is NOT unique - two brokers may each have an 'orders'", () => {
700
+ const nameIndexes: Array<IndexMetadataArgs> = classIndexes(
701
+ MessageQueue,
702
+ ).filter((index: IndexMetadataArgs): boolean => {
703
+ return (
704
+ Array.isArray(index.columns) &&
705
+ (index.columns as Array<string>).includes("name")
706
+ );
707
+ });
708
+
709
+ expect(nameIndexes.length).toBeGreaterThan(0);
710
+
711
+ for (const index of nameIndexes) {
712
+ expect(index.unique).not.toBe(true);
713
+ }
714
+
715
+ // Nor the app-level @UniqueColumnBy check ServerlessFunction.name carries.
716
+ expect(Object.keys(getUniqueColumnsBy(new MessageQueue()))).toEqual([]);
717
+ });
718
+
719
+ test("declares IDX_message_queue_slug by name, UNIQUE and partial", () => {
720
+ /*
721
+ * TypeORM's schema builder matches database indexes to entity
722
+ * metadata by name and drops every one it cannot find, so the partial
723
+ * slug index must be declared natively and named.
724
+ */
725
+ const found: IndexMetadataArgs | undefined = namedIndex(
726
+ MessageQueue,
727
+ "IDX_message_queue_slug",
728
+ );
729
+
730
+ expect(found).toBeDefined();
731
+ expect(found?.unique).toBe(true);
732
+ expect(found?.columns).toEqual(["slug"]);
733
+ expect(found?.where).toBe('"deletedAt" IS NULL');
734
+ });
735
+
736
+ test("names exactly two indexes - the partial unique ones", () => {
737
+ const named: Array<string> = classIndexes(MessageQueue)
738
+ .map((index: IndexMetadataArgs): string => {
739
+ return index.name || "";
740
+ })
741
+ .filter((name: string): boolean => {
742
+ return name.length > 0;
743
+ })
744
+ .sort();
745
+
746
+ expect(named).toEqual([
747
+ "IDX_message_queue_identifier",
748
+ "IDX_message_queue_slug",
749
+ ]);
750
+ });
751
+
752
+ test("indexes the list-page filters: (projectId, isArchived) and (projectId, messagingSystem)", () => {
753
+ const archived: IndexMetadataArgs | undefined = indexOnColumns(
754
+ MessageQueue,
755
+ ["projectId", "isArchived"],
756
+ );
757
+ const system: IndexMetadataArgs | undefined = indexOnColumns(
758
+ MessageQueue,
759
+ ["projectId", "messagingSystem"],
760
+ );
761
+
762
+ expect(archived).toBeDefined();
763
+ expect(archived?.unique).not.toBe(true);
764
+ expect(system).toBeDefined();
765
+ expect(system?.unique).not.toBe(true);
766
+ });
767
+
768
+ test("indexes projectId, name and queueIdentifier on their own", () => {
769
+ for (const column of ["projectId", "name", "queueIdentifier"]) {
770
+ expect({
771
+ column,
772
+ indexed: Boolean(propertyIndex(MessageQueue, column)),
773
+ }).toEqual({ column, indexed: true });
774
+ }
775
+ });
776
+
777
+ test("carries every column of the SPEC schema", () => {
778
+ const columns: Array<string> = model.getTableColumns().columns;
779
+
780
+ for (const column of [
781
+ ...MESSAGE_QUEUE_USER_CREATE_COLUMNS,
782
+ ...MESSAGE_QUEUE_ROOT_ONLY_COLUMNS,
783
+ ]) {
784
+ expect({ column, present: columns.includes(column) }).toEqual({
785
+ column,
786
+ present: true,
787
+ });
788
+ }
789
+
790
+ // No retention / AI / workload / collector columns, and no consumer groups.
791
+ for (const column of [
792
+ "retainTelemetryDataForDays",
793
+ "telemetryRetentionConfig",
794
+ "isAiInvestigationEnabled",
795
+ "aiRemediationMode",
796
+ "workloadIdentifier",
797
+ "memberEntityKeys",
798
+ "otelCollectorStatus",
799
+ "collectorLastSeenAt",
800
+ "consumerGroups",
801
+ "databaseIdentifier",
802
+ "dbSystem",
803
+ ]) {
804
+ expect(columns).not.toContain(column);
805
+ }
806
+ });
807
+
808
+ test("every declared column is accounted for as user-creatable or root-only", () => {
809
+ /*
810
+ * A new column must be placed in one of the two lists above on
811
+ * purpose - which is what decides whether a manual create can set it.
812
+ */
813
+ const accounted: Set<string> = new Set([
814
+ ...MESSAGE_QUEUE_USER_CREATE_COLUMNS,
815
+ ...MESSAGE_QUEUE_ROOT_ONLY_COLUMNS,
816
+ ]);
817
+ const unaccounted: Array<string> = ownColumns(model).filter(
818
+ (column: string): boolean => {
819
+ return !accounted.has(column);
820
+ },
821
+ );
822
+
823
+ expect(unaccounted).toEqual([]);
824
+ });
825
+
826
+ test("column types and widths follow the SPEC", () => {
827
+ const expectations: Array<
828
+ [string, TableColumnType, boolean, number | undefined]
829
+ > = [
830
+ // column, type, required, varchar length
831
+ ["name", TableColumnType.ShortText, true, ColumnLength.ShortText],
832
+ ["description", TableColumnType.LongText, false, ColumnLength.LongText],
833
+ [
834
+ "queueIdentifier",
835
+ TableColumnType.LongText,
836
+ true,
837
+ ColumnLength.LongText,
838
+ ],
839
+ [
840
+ "messagingSystem",
841
+ TableColumnType.ShortText,
842
+ true,
843
+ ColumnLength.ShortText,
844
+ ],
845
+ [
846
+ "destinationName",
847
+ TableColumnType.LongText,
848
+ true,
849
+ ColumnLength.LongText,
850
+ ],
851
+ [
852
+ "brokerScope",
853
+ TableColumnType.ShortText,
854
+ false,
855
+ ColumnLength.ShortText,
856
+ ],
857
+ [
858
+ "brokerAddress",
859
+ TableColumnType.LongText,
860
+ false,
861
+ ColumnLength.LongText,
862
+ ],
863
+ [
864
+ "discoverySource",
865
+ TableColumnType.ShortText,
866
+ false,
867
+ ColumnLength.ShortText,
868
+ ],
869
+ ["lastSeenAt", TableColumnType.Date, false, undefined],
870
+ ["brokerMetricsLastSeenAt", TableColumnType.Date, false, undefined],
871
+ ["autoArchivedAt", TableColumnType.Date, false, undefined],
872
+ ["manuallyRestoredAt", TableColumnType.Date, false, undefined],
873
+ ["automaticAssignments", TableColumnType.JSON, false, undefined],
874
+ ["archivedAt", TableColumnType.Date, false, undefined],
875
+ ["createdByUserId", TableColumnType.ObjectID, false, undefined],
876
+ ];
877
+
878
+ for (const [column, type, required, length] of expectations) {
879
+ const metadata: TableColumnMetadata =
880
+ model.getTableColumnMetadata(column);
881
+ const options: ColumnMetadataArgs["options"] = columnArgs(
882
+ MessageQueue,
883
+ column,
884
+ ).options;
885
+
886
+ expect({ column, type: metadata.type }).toEqual({ column, type });
887
+ expect({ column, required: Boolean(metadata.required) }).toEqual({
888
+ column,
889
+ required,
890
+ });
891
+ expect({ column, nullable: options.nullable }).toEqual({
892
+ column,
893
+ nullable: !required,
894
+ });
895
+ expect({ column, length: options.length }).toEqual({ column, length });
896
+ }
897
+ });
898
+
899
+ test("the widths hold everything the identity module can produce", () => {
900
+ /*
901
+ * A resolved destination is at most 255 characters, a display name
902
+ * 100 and an identifier 500 - a value past its column would fail the
903
+ * insert rather than be stored.
904
+ */
905
+ expect(MESSAGE_QUEUE_DESTINATION_MAX_LENGTH).toBeLessThanOrEqual(
906
+ ColumnLength.LongText,
907
+ );
908
+ expect(MESSAGE_QUEUE_IDENTIFIER_MAX_LENGTH).toBeLessThanOrEqual(
909
+ ColumnLength.LongText,
910
+ );
911
+ expect(MESSAGE_QUEUE_DISPLAY_NAME_MAX_LENGTH).toBeLessThanOrEqual(
912
+ ColumnLength.ShortText,
913
+ );
914
+
915
+ // Every catalogued system name fits the ShortText system column.
916
+ for (const descriptor of MESSAGING_SYSTEMS) {
917
+ expect(descriptor.system.length).toBeLessThanOrEqual(
918
+ ColumnLength.ShortText,
919
+ );
920
+ }
921
+ });
922
+
923
+ test("automaticAssignments is jsonb; new rows are not archived and carry no invented defaults", () => {
924
+ expect(
925
+ columnArgs(MessageQueue, "automaticAssignments").options.type,
926
+ ).toBe("jsonb");
927
+ expect(columnArgs(MessageQueue, "isArchived").options.default).toBe(
928
+ false,
929
+ );
930
+ expect(columnArgs(MessageQueue, "isArchived").options.nullable).toBe(
931
+ false,
932
+ );
933
+ expect(model.isDefaultValueColumn("isArchived")).toBe(true);
934
+
935
+ // No DB default where "unknown" must stay NULL.
936
+ for (const column of [
937
+ "lastSeenAt",
938
+ "brokerMetricsLastSeenAt",
939
+ "autoArchivedAt",
940
+ "manuallyRestoredAt",
941
+ "automaticAssignments",
942
+ "discoverySource",
943
+ "brokerScope",
944
+ "brokerAddress",
945
+ ]) {
946
+ expect({
947
+ column,
948
+ default: columnArgs(MessageQueue, column).options.default,
949
+ }).toEqual({ column, default: undefined });
950
+ }
951
+ });
952
+
953
+ test("the identifier column documents the family-keyed form, and its example is one", () => {
954
+ const metadata: TableColumnMetadata =
955
+ model.getTableColumnMetadata("queueIdentifier");
956
+
957
+ expect(metadata.description).toContain("family");
958
+ expect(metadata.description).toContain("jms");
959
+
960
+ const example: string = String(metadata.example);
961
+ const parsed: MessageQueueIdentity | null =
962
+ parseMessageQueueIdentifier(example);
963
+
964
+ expect(parsed).not.toBeNull();
965
+ expect(buildMessageQueueIdentifier(parsed!)).toBe(example);
966
+ expect(example).toBe(
967
+ buildMessageQueueIdentifier({
968
+ system: "kafka",
969
+ brokerScope: "",
970
+ destination: "orders.created",
971
+ }),
972
+ );
973
+ });
974
+
975
+ test("the messaging system column names catalogued systems in its example", () => {
976
+ const metadata: TableColumnMetadata =
977
+ model.getTableColumnMetadata("messagingSystem");
978
+ const systems: Array<string> = MESSAGING_SYSTEMS.map(
979
+ (descriptor: MessagingSystemDescriptor): string => {
980
+ return descriptor.system;
981
+ },
982
+ );
983
+
984
+ expect(systems).toContain(String(metadata.example));
985
+ });
986
+
987
+ test("slug is computed from name and is never user-writable", () => {
988
+ expect(model.getSlugifyColumn()).toBe("name");
989
+ expect(model.getSaveSlugToColumn()).toBe("slug");
990
+ expect(model.getTableColumnMetadata("slug").computed).toBe(true);
991
+ expect(model.getTableColumnMetadata("slug").type).toBe(
992
+ TableColumnType.Slug,
993
+ );
994
+ });
995
+
996
+ test("table access control: Settings / project roles plus the granular MessageQueue permissions", () => {
997
+ const writeRoles: Array<Permission> = [
998
+ Permission.ProjectOwner,
999
+ Permission.ProjectAdmin,
1000
+ Permission.ProjectMember,
1001
+ Permission.SettingsAdmin,
1002
+ Permission.SettingsMember,
1003
+ ];
1004
+
1005
+ expect(sorted(model.getCreatePermissions())).toEqual(
1006
+ sorted([...writeRoles, Permission.CreateMessageQueue]),
1007
+ );
1008
+ expect(sorted(model.getUpdatePermissions())).toEqual(
1009
+ sorted([...writeRoles, Permission.EditMessageQueue]),
1010
+ );
1011
+ expect(sorted(model.getDeletePermissions())).toEqual(
1012
+ sorted([...writeRoles, Permission.DeleteMessageQueue]),
1013
+ );
1014
+ expect(sorted(model.getReadPermissions())).toEqual(
1015
+ sorted([
1016
+ Permission.ProjectOwner,
1017
+ Permission.ProjectAdmin,
1018
+ Permission.ProjectMember,
1019
+ Permission.Viewer,
1020
+ Permission.SettingsAdmin,
1021
+ Permission.SettingsMember,
1022
+ Permission.SettingsViewer,
1023
+ Permission.ReadMessageQueue,
1024
+ ]),
1025
+ );
1026
+ });
1027
+
1028
+ test("is label-access-controlled and not a telemetry-owning operational resource", () => {
1029
+ expect(model.accessControlColumn).toBe("labels");
1030
+ expect(model.enableWorkflowOn).toBeFalsy();
1031
+ });
1032
+
1033
+ test.each(MESSAGE_QUEUE_USER_CREATE_COLUMNS)(
1034
+ "%s is creatable by exactly the table's create roles (COLUMN ACL RULE)",
1035
+ (column: string) => {
1036
+ /*
1037
+ * DatabaseService.create runs onBeforeCreate BEFORE
1038
+ * ModelPermission.checkCreatePermissions. A column the service sets
1039
+ * during a manual create that the caller may not create turns every
1040
+ * manual create into "User is not allowed to create on <column>".
1041
+ */
1042
+ expect(sorted(columnAccess(model, column).create || [])).toEqual(
1043
+ sorted(model.getCreatePermissions()),
1044
+ );
1045
+ },
1046
+ );
1047
+
1048
+ test.each(MESSAGE_QUEUE_ROOT_ONLY_COLUMNS)(
1049
+ "%s is root-only: nobody creates or updates it through the API",
1050
+ (column: string) => {
1051
+ const accessControl: ColumnAccessControl = columnAccess(model, column);
1052
+
1053
+ expect(accessControl.create || []).toEqual([]);
1054
+ expect(accessControl.update || []).toEqual([]);
1055
+ },
1056
+ );
1057
+
1058
+ test("identity columns are creatable but never updatable", () => {
1059
+ /*
1060
+ * Re-pointing a row at another system, namespace or destination by
1061
+ * editing it would silently hand its history to another queue.
1062
+ * messagingSystem changes only by discovery's refinement, as root.
1063
+ */
1064
+ for (const column of [
1065
+ "projectId",
1066
+ "queueIdentifier",
1067
+ "messagingSystem",
1068
+ "destinationName",
1069
+ "brokerScope",
1070
+ "discoverySource",
1071
+ "createdByUserId",
1072
+ ]) {
1073
+ expect({ column, update: columnAccess(model, column).update }).toEqual({
1074
+ column,
1075
+ update: [],
1076
+ });
1077
+ }
1078
+ });
1079
+
1080
+ test.each(MESSAGE_QUEUE_USER_UPDATE_COLUMNS)(
1081
+ "%s is updatable by exactly the table's update roles",
1082
+ (column: string) => {
1083
+ expect(sorted(columnAccess(model, column).update || [])).toEqual(
1084
+ sorted(model.getUpdatePermissions()),
1085
+ );
1086
+ },
1087
+ );
1088
+
1089
+ test("no other column is user-updatable", () => {
1090
+ const updatable: Array<string> = ownColumns(model).filter(
1091
+ (column: string): boolean => {
1092
+ return (columnAccess(model, column).update || []).length > 0;
1093
+ },
1094
+ );
1095
+
1096
+ expect(updatable.sort()).toEqual(
1097
+ [...MESSAGE_QUEUE_USER_UPDATE_COLUMNS].sort(),
1098
+ );
1099
+ });
1100
+
1101
+ test("every column is readable by exactly the table's read roles", () => {
1102
+ for (const column of ownColumns(model)) {
1103
+ expect({
1104
+ column,
1105
+ read: sorted(columnAccess(model, column).read || []),
1106
+ }).toEqual({ column, read: sorted(model.getReadPermissions()) });
1107
+ }
1108
+ });
1109
+
1110
+ describe("against the real permission checks", () => {
1111
+ test.each([
1112
+ ["ProjectOwner", [Permission.ProjectOwner]],
1113
+ ["ProjectMember", [Permission.ProjectMember]],
1114
+ ["SettingsAdmin", [Permission.SettingsAdmin]],
1115
+ ["SettingsMember", [Permission.SettingsMember]],
1116
+ ["CreateMessageQueue only", [Permission.CreateMessageQueue]],
1117
+ ])(
1118
+ "a manual create as %s passes table and column checks",
1119
+ (_label: string, permissions: Array<Permission>) => {
1120
+ expect(
1121
+ checkCreate(MessageQueue, manualCreateData(), permissions),
1122
+ ).not.toThrow();
1123
+ },
1124
+ );
1125
+
1126
+ test("a manual create with labels and an archive flag passes too", () => {
1127
+ const data: MessageQueue = manualCreateData();
1128
+ const label: Label = new Label();
1129
+ label._id = ObjectID.generate().toString();
1130
+ data.labels = [label];
1131
+ data.isArchived = false;
1132
+
1133
+ expect(
1134
+ checkCreate(MessageQueue, data, [Permission.CreateMessageQueue]),
1135
+ ).not.toThrow();
1136
+ });
1137
+
1138
+ test("a Viewer or SettingsViewer may not add a queue", () => {
1139
+ for (const permission of [
1140
+ Permission.Viewer,
1141
+ Permission.SettingsViewer,
1142
+ ]) {
1143
+ expect(
1144
+ checkCreate(MessageQueue, manualCreateData(), [permission]),
1145
+ ).toThrow();
1146
+ }
1147
+ });
1148
+
1149
+ test.each(
1150
+ MESSAGE_QUEUE_ROOT_ONLY_COLUMNS.filter((column: string): boolean => {
1151
+ // slug is a Slug column, which ColumnPermission always skips.
1152
+ return column !== "slug";
1153
+ }),
1154
+ )("a non-root create carrying %s is refused", (column: string) => {
1155
+ const data: MessageQueue = manualCreateData();
1156
+ const metadata: TableColumnMetadata =
1157
+ model.getTableColumnMetadata(column);
1158
+ let value: unknown = "value";
1159
+
1160
+ if (metadata.type === TableColumnType.ObjectID) {
1161
+ value = ObjectID.generate();
1162
+ } else if (metadata.type === TableColumnType.Date) {
1163
+ value = new Date();
1164
+ } else if (metadata.type === TableColumnType.JSON) {
1165
+ value = { labelIds: [ObjectID.generate().toString()] };
1166
+ } else if (metadata.type === TableColumnType.Entity) {
1167
+ value = { _id: ObjectID.generate().toString() };
1168
+ }
1169
+
1170
+ (data as unknown as Record<string, unknown>)[column] = value;
1171
+
1172
+ expect(
1173
+ checkColumns(
1174
+ MessageQueue,
1175
+ data,
1176
+ [Permission.ProjectOwner],
1177
+ DatabaseRequestType.Create,
1178
+ ),
1179
+ ).toThrow(`User is not allowed to create on ${column} column of Queue`);
1180
+ });
1181
+
1182
+ test("an update may rename, describe and archive", () => {
1183
+ const data: MessageQueue = new MessageQueue();
1184
+ data.name = "Orders (prod)";
1185
+ data.description = "Renamed";
1186
+ data.isArchived = true;
1187
+
1188
+ expect(
1189
+ checkColumns(
1190
+ MessageQueue,
1191
+ data,
1192
+ [Permission.EditMessageQueue],
1193
+ DatabaseRequestType.Update,
1194
+ ),
1195
+ ).not.toThrow();
1196
+ });
1197
+
1198
+ test.each([
1199
+ "queueIdentifier",
1200
+ "messagingSystem",
1201
+ "destinationName",
1202
+ "brokerScope",
1203
+ "discoverySource",
1204
+ "brokerAddress",
1205
+ ])(
1206
+ "an update of %s is refused even for a project owner",
1207
+ (column: string) => {
1208
+ const data: MessageQueue = new MessageQueue();
1209
+ (data as unknown as Record<string, unknown>)[column] = "x";
1210
+
1211
+ expect(
1212
+ checkColumns(
1213
+ MessageQueue,
1214
+ data,
1215
+ [Permission.ProjectOwner],
1216
+ DatabaseRequestType.Update,
1217
+ ),
1218
+ ).toThrow(
1219
+ `User is not allowed to update on ${column} column of Queue`,
1220
+ );
1221
+ },
1222
+ );
1223
+
1224
+ test("a reader may not archive a queue", () => {
1225
+ const data: MessageQueue = new MessageQueue();
1226
+ data.isArchived = true;
1227
+
1228
+ expect(
1229
+ checkColumns(
1230
+ MessageQueue,
1231
+ data,
1232
+ [Permission.ReadMessageQueue],
1233
+ DatabaseRequestType.Update,
1234
+ ),
1235
+ ).toThrow(BadDataException);
1236
+ });
1237
+ });
1238
+
1239
+ test("labels drive access control through the MessageQueueLabel join table", () => {
1240
+ expect(model.accessControlColumn).toBe("labels");
1241
+
1242
+ const joinTable: JoinTableMetadataArgs = joinTableArgs(
1243
+ MessageQueue,
1244
+ "labels",
1245
+ );
1246
+
1247
+ expect(joinTable.name).toBe("MessageQueueLabel");
1248
+ expect(joinTable.joinColumns?.[0]?.name).toBe("messageQueueId");
1249
+ expect(joinTable.inverseJoinColumns?.[0]?.name).toBe("labelId");
1250
+ expect(model.getTableColumnMetadata("labels").modelType).toBe(Label);
1251
+ expect(relationArgs(MessageQueue, "labels").relationType).toBe(
1252
+ "many-to-many",
1253
+ );
1254
+ });
1255
+
1256
+ test("the project relation cascades; the user relations survive their user", () => {
1257
+ expect(relationArgs(MessageQueue, "project").options.onDelete).toBe(
1258
+ "CASCADE",
1259
+ );
1260
+
1261
+ for (const [property, idColumn] of [
1262
+ ["createdByUser", "createdByUserId"],
1263
+ ["archivedByUser", "archivedByUserId"],
1264
+ ["deletedByUser", "deletedByUserId"],
1265
+ ] as Array<[string, string]>) {
1266
+ expect(relationArgs(MessageQueue, property).options.onDelete).toBe(
1267
+ "SET NULL",
1268
+ );
1269
+ expect(joinColumnArgs(MessageQueue, property).name).toBe(idColumn);
1270
+ expect(model.getTableColumnMetadata(property).modelType).toBe(User);
1271
+ }
1272
+ });
1273
+
1274
+ test("the identity and liveness columns can be read through a relation query", () => {
1275
+ for (const column of [
1276
+ "projectId",
1277
+ "name",
1278
+ "description",
1279
+ "queueIdentifier",
1280
+ "messagingSystem",
1281
+ "destinationName",
1282
+ "brokerScope",
1283
+ "discoverySource",
1284
+ "lastSeenAt",
1285
+ ]) {
1286
+ expect({
1287
+ column,
1288
+ canRead: Boolean(
1289
+ model.getTableColumnMetadata(column).canReadOnRelationQuery,
1290
+ ),
1291
+ }).toEqual({ column, canRead: true });
1292
+ }
1293
+ });
1294
+
1295
+ test("the initialisers are in place - BaseModel enumerates own properties", () => {
1296
+ for (const column of ownColumns(model)) {
1297
+ expect({
1298
+ column,
1299
+ own: Object.prototype.hasOwnProperty.call(model, column),
1300
+ }).toEqual({ column, own: true });
1301
+ }
1302
+ });
1303
+ });
1304
+
1305
+ describe("discovery sources", () => {
1306
+ test("are exactly traces, broker-metrics and manual", () => {
1307
+ expect([...MESSAGE_QUEUE_DISCOVERY_SOURCES]).toEqual([
1308
+ "traces",
1309
+ "broker-metrics",
1310
+ "manual",
1311
+ ]);
1312
+ });
1313
+
1314
+ test.each([
1315
+ ["traces", "Application traces"],
1316
+ ["broker-metrics", "Broker metrics"],
1317
+ ["manual", "Added manually"],
1318
+ [" Manual ", "Added manually"],
1319
+ ["something-else", "something-else"],
1320
+ // A Map lookup: an inherited property name is shown as it is.
1321
+ ["constructor", "constructor"],
1322
+ ["", ""],
1323
+ ])("labels %p as %p", (source: string, label: string) => {
1324
+ expect(getMessageQueueDiscoverySourceLabel(source)).toBe(label);
1325
+ });
1326
+
1327
+ test("labels a non-string as nothing", () => {
1328
+ expect(getMessageQueueDiscoverySourceLabel(undefined)).toBe("");
1329
+ expect(getMessageQueueDiscoverySourceLabel(null)).toBe("");
1330
+ expect(getMessageQueueDiscoverySourceLabel(42)).toBe("");
1331
+ });
1332
+
1333
+ test("the discoverySource column documents every source", () => {
1334
+ const description: string =
1335
+ new MessageQueue().getTableColumnMetadata("discoverySource")
1336
+ .description || "";
1337
+
1338
+ for (const source of MESSAGE_QUEUE_DISCOVERY_SOURCES) {
1339
+ expect(description).toContain(source);
1340
+ }
1341
+ });
1342
+ });
1343
+
1344
+ describe("children of MessageQueue", () => {
1345
+ test.each(MESSAGE_QUEUE_CHILDREN)(
1346
+ "%p.%s cascades on queue delete and carries a required messageQueueId",
1347
+ (modelType: ModelType, property: string) => {
1348
+ const relation: RelationMetadataArgs = relationArgs(
1349
+ modelType,
1350
+ property,
1351
+ );
1352
+
1353
+ expect(relation.relationType).toBe("many-to-one");
1354
+ expect(relation.options.onDelete).toBe("CASCADE");
1355
+
1356
+ const model: BaseModel = new modelType();
1357
+
1358
+ expect(model.getTableColumns().columns).toContain("messageQueueId");
1359
+ expect(
1360
+ model.getTableColumnMetadata(property).manyToOneRelationColumn,
1361
+ ).toBe("messageQueueId");
1362
+ expect(model.getTableColumnMetadata(property).modelType).toBe(
1363
+ MessageQueue,
1364
+ );
1365
+ expect(model.getTableColumnMetadata("messageQueueId").required).toBe(
1366
+ true,
1367
+ );
1368
+ expect(columnArgs(modelType, "messageQueueId").options.nullable).toBe(
1369
+ false,
1370
+ );
1371
+ expect(joinColumnArgs(modelType, property).name).toBe("messageQueueId");
1372
+ },
1373
+ );
1374
+
1375
+ test.each([
1376
+ [
1377
+ MessageQueueOwnerTeam,
1378
+ "teamId",
1379
+ "This team is already an owner of this queue.",
1380
+ ],
1381
+ [
1382
+ MessageQueueOwnerUser,
1383
+ "userId",
1384
+ "This user is already an owner of this queue.",
1385
+ ],
1386
+ ] as Array<[ModelType, string, string]>)(
1387
+ "%p allows one row per (queue, owner, project)",
1388
+ (modelType: ModelType, ownerColumn: string, message: string) => {
1389
+ const unique: IndexMetadataArgs | undefined = indexOnColumns(
1390
+ modelType,
1391
+ ["messageQueueId", ownerColumn, "projectId"],
1392
+ );
1393
+
1394
+ expect(unique).toBeDefined();
1395
+ expect(unique?.unique).toBe(true);
1396
+
1397
+ const constraints: Array<UniqueColumnsTogetherMetadata> =
1398
+ new modelType().getUniqueColumnsTogether();
1399
+
1400
+ expect(constraints).toHaveLength(1);
1401
+ expect(constraints[0]!.columnNames).toEqual([
1402
+ "messageQueueId",
1403
+ ownerColumn,
1404
+ "projectId",
1405
+ ]);
1406
+ expect(constraints[0]!.errorMessage).toBe(message);
1407
+ },
1408
+ );
1409
+
1410
+ test.each([
1411
+ [MessageQueueOwnerTeam, "team", Team],
1412
+ [MessageQueueOwnerUser, "user", User],
1413
+ ] as Array<[ModelType, string, ModelType]>)(
1414
+ "%p's owner relation cascades and its key is required",
1415
+ (modelType: ModelType, property: string, ownerModel: ModelType) => {
1416
+ const model: BaseModel = new modelType();
1417
+
1418
+ expect(model.getTableColumnMetadata(property).modelType).toBe(
1419
+ ownerModel,
1420
+ );
1421
+ expect(relationArgs(modelType, property).options.onDelete).toBe(
1422
+ "CASCADE",
1423
+ );
1424
+ expect(model.getTableColumnMetadata(`${property}Id`).required).toBe(
1425
+ true,
1426
+ );
1427
+ expect(columnArgs(modelType, `${property}Id`).options.nullable).toBe(
1428
+ false,
1429
+ );
1430
+ },
1431
+ );
1432
+
1433
+ test("owner rows carry the isOwnerNotified flag, which only the server sets", () => {
1434
+ // Owner rule assignment stamps it (OwnerRuleAssignment.createOwner).
1435
+ for (const modelType of [
1436
+ MessageQueueOwnerTeam,
1437
+ MessageQueueOwnerUser,
1438
+ ] as Array<ModelType>) {
1439
+ const model: BaseModel = new modelType();
1440
+
1441
+ expect(model.getTableColumns().columns).toContain("isOwnerNotified");
1442
+ expect(columnAccess(model, "isOwnerNotified").create).toEqual([]);
1443
+ expect(columnArgs(modelType, "isOwnerNotified").options.default).toBe(
1444
+ false,
1445
+ );
1446
+ expect(model.enableWorkflowOn).toBeTruthy();
1447
+ }
1448
+ });
1449
+
1450
+ test.each([
1451
+ [MessageQueueOwnerTeam, "OwnerTeam"],
1452
+ [MessageQueueOwnerUser, "OwnerUser"],
1453
+ ] as Array<[ModelType, string]>)(
1454
+ "%p gates on its own %s permissions",
1455
+ (modelType: ModelType, kind: string) => {
1456
+ const model: BaseModel = new modelType();
1457
+
1458
+ expect(model.getCreatePermissions()).toContain(
1459
+ `CreateMessageQueue${kind}` as Permission,
1460
+ );
1461
+ expect(model.getReadPermissions()).toContain(
1462
+ `ReadMessageQueue${kind}` as Permission,
1463
+ );
1464
+ expect(model.getUpdatePermissions()).toContain(
1465
+ `EditMessageQueue${kind}` as Permission,
1466
+ );
1467
+ expect(model.getDeletePermissions()).toContain(
1468
+ `DeleteMessageQueue${kind}` as Permission,
1469
+ );
1470
+ },
1471
+ );
1472
+
1473
+ test.each([
1474
+ [MessageQueueOwnerTeam, [Permission.CreateMessageQueueOwnerTeam]],
1475
+ [MessageQueueOwnerUser, [Permission.CreateMessageQueueOwnerUser]],
1476
+ ] as Array<[ModelType, Array<Permission>]>)(
1477
+ "a person adding an owner row to %p passes the real create check",
1478
+ (modelType: ModelType, permissions: Array<Permission>) => {
1479
+ const data: BaseModel = new modelType();
1480
+ data.setColumnValue("projectId", PROJECT_ID);
1481
+ data.setColumnValue("messageQueueId", ObjectID.generate());
1482
+ data.setColumnValue(
1483
+ modelType === MessageQueueOwnerTeam ? "teamId" : "userId",
1484
+ ObjectID.generate(),
1485
+ );
1486
+
1487
+ expect(checkCreate(modelType, data, permissions)).not.toThrow();
1488
+ expect(
1489
+ checkCreate(modelType, data, [Permission.ReadMessageQueue]),
1490
+ ).toThrow();
1491
+ },
1492
+ );
1493
+ });
1494
+
1495
+ describe("rule models", () => {
1496
+ test.each([
1497
+ [MessageQueueLabelRule, "LabelRule"],
1498
+ [MessageQueueOwnerRule, "OwnerRule"],
1499
+ ] as Array<[ModelType, string]>)(
1500
+ "%p is a RuleBaseModel whose criteria column follows the table ACL",
1501
+ (modelType: ModelType, kind: string) => {
1502
+ const model: BaseModel = new modelType();
1503
+
1504
+ expect(model).toBeInstanceOf(RuleBaseModel);
1505
+ expect(model.getTableColumnMetadata("criteria").type).toBe(
1506
+ TableColumnType.JSON,
1507
+ );
1508
+ expect(model.getColumnAccessControlFor("criteria")).toEqual({
1509
+ create: model.getCreatePermissions(),
1510
+ read: model.getReadPermissions(),
1511
+ update: model.getUpdatePermissions(),
1512
+ });
1513
+
1514
+ // Rule tables: owners and admins write, members and viewers read.
1515
+ expect(sorted(model.getCreatePermissions())).toEqual(
1516
+ sorted([
1517
+ Permission.ProjectOwner,
1518
+ Permission.ProjectAdmin,
1519
+ `CreateMessageQueue${kind}` as Permission,
1520
+ ]),
1521
+ );
1522
+ expect(sorted(model.getReadPermissions())).toEqual(
1523
+ sorted([
1524
+ Permission.ProjectOwner,
1525
+ Permission.ProjectAdmin,
1526
+ Permission.ProjectMember,
1527
+ Permission.Viewer,
1528
+ `ReadMessageQueue${kind}` as Permission,
1529
+ ]),
1530
+ );
1531
+ expect(model.enableWorkflowOn).toBeTruthy();
1532
+ },
1533
+ );
1534
+
1535
+ test.each([
1536
+ MessageQueueLabelRule,
1537
+ MessageQueueOwnerRule,
1538
+ ] as Array<ModelType>)(
1539
+ "%p matches on exactly the four registered criteria fields",
1540
+ (modelType: ModelType) => {
1541
+ /*
1542
+ * RuleCriteriaFieldRegistry, the rule engines' legacyFields and the
1543
+ * dashboard's match-criteria step all list these four names; a
1544
+ * rename here breaks all three silently.
1545
+ */
1546
+ const model: BaseModel = new modelType();
1547
+ const columns: Array<string> = model.getTableColumns().columns;
1548
+
1549
+ const matchColumns: Array<string> = columns.filter(
1550
+ (column: string): boolean => {
1551
+ return column.startsWith("messageQueue");
1552
+ },
1553
+ );
1554
+
1555
+ expect(matchColumns.sort()).toEqual([...RULE_CRITERIA_FIELDS].sort());
1556
+
1557
+ expect(model.getTableColumnMetadata("messageQueueLabels").type).toBe(
1558
+ TableColumnType.EntityArray,
1559
+ );
1560
+ expect(
1561
+ model.getTableColumnMetadata("messageQueueLabels").modelType,
1562
+ ).toBe(Label);
1563
+
1564
+ for (const pattern of [
1565
+ "messageQueueNamePattern",
1566
+ "messageQueueDescriptionPattern",
1567
+ "messageQueueSystemPattern",
1568
+ ]) {
1569
+ expect(model.getTableColumnMetadata(pattern).type).toBe(
1570
+ TableColumnType.LongText,
1571
+ );
1572
+ expect(model.getTableColumnMetadata(pattern).required).toBeFalsy();
1573
+ expect(columnArgs(modelType, pattern).options.nullable).toBe(true);
1574
+ expect(sorted(columnAccess(model, pattern).update || [])).toEqual(
1575
+ sorted(model.getUpdatePermissions()),
1576
+ );
1577
+ }
1578
+ },
1579
+ );
1580
+
1581
+ test.each([
1582
+ [MessageQueueLabelRule, "LabelRule"],
1583
+ [MessageQueueOwnerRule, "OwnerRule"],
1584
+ ] as Array<[ModelType, string]>)(
1585
+ "%p: every criteria field is created, read and updated by exactly the table's roles",
1586
+ (modelType: ModelType, kind: string) => {
1587
+ /*
1588
+ * An empty create or read list fails nothing else loudly: the column
1589
+ * drops out of the portable label rule file
1590
+ * (ModelImportExport.getImportExportableColumnNames skips it) - an
1591
+ * exported "Kafka only" rule re-imports as one that matches every
1592
+ * queue - and the rule form's create is refused for anyone who
1593
+ * fills the field in.
1594
+ */
1595
+ const model: BaseModel = new modelType();
1596
+
1597
+ for (const column of RULE_CRITERIA_FIELDS) {
1598
+ const accessControl: ColumnAccessControl = columnAccess(
1599
+ model,
1600
+ column,
1601
+ );
1602
+
1603
+ expect({
1604
+ column,
1605
+ create: sorted(accessControl.create || []),
1606
+ read: sorted(accessControl.read || []),
1607
+ update: sorted(accessControl.update || []),
1608
+ }).toEqual({
1609
+ column,
1610
+ create: sorted(model.getCreatePermissions()),
1611
+ read: sorted(model.getReadPermissions()),
1612
+ update: sorted(model.getUpdatePermissions()),
1613
+ });
1614
+ }
1615
+
1616
+ // And through the real column check, every field set at once.
1617
+ const data: BaseModel = new modelType();
1618
+ const label: Label = new Label();
1619
+ label._id = ObjectID.generate().toString();
1620
+ data.setColumnValue("messageQueueLabels", [label]);
1621
+ data.setColumnValue("messageQueueNamePattern", "^orders\\.");
1622
+ data.setColumnValue("messageQueueDescriptionPattern", "payments");
1623
+ data.setColumnValue("messageQueueSystemPattern", "^kafka$");
1624
+
1625
+ expect(
1626
+ checkColumns(
1627
+ modelType,
1628
+ data,
1629
+ [`CreateMessageQueue${kind}` as Permission],
1630
+ DatabaseRequestType.Create,
1631
+ ),
1632
+ ).not.toThrow();
1633
+ expect(
1634
+ checkColumns(
1635
+ modelType,
1636
+ data,
1637
+ [`EditMessageQueue${kind}` as Permission],
1638
+ DatabaseRequestType.Update,
1639
+ ),
1640
+ ).not.toThrow();
1641
+ expect(
1642
+ checkColumns(
1643
+ modelType,
1644
+ data,
1645
+ [`ReadMessageQueue${kind}` as Permission],
1646
+ DatabaseRequestType.Create,
1647
+ ),
1648
+ ).toThrow(BadDataException);
1649
+ },
1650
+ );
1651
+
1652
+ test("label rule attaches labels through its own join tables", () => {
1653
+ const model: MessageQueueLabelRule = new MessageQueueLabelRule();
1654
+
1655
+ for (const column of [
1656
+ "name",
1657
+ "description",
1658
+ "isEnabled",
1659
+ "labelsToAdd",
1660
+ ]) {
1661
+ expect(model.getTableColumns().columns).toContain(column);
1662
+ }
1663
+
1664
+ const matchLabels: JoinTableMetadataArgs = joinTableArgs(
1665
+ MessageQueueLabelRule,
1666
+ "messageQueueLabels",
1667
+ );
1668
+
1669
+ expect(matchLabels.name).toBe("MessageQueueLabelRuleMessageQueueLabel");
1670
+ expect(matchLabels.joinColumns?.[0]?.name).toBe(
1671
+ "messageQueueLabelRuleId",
1672
+ );
1673
+ expect(matchLabels.inverseJoinColumns?.[0]?.name).toBe("labelId");
1674
+
1675
+ const labelsToAdd: JoinTableMetadataArgs = joinTableArgs(
1676
+ MessageQueueLabelRule,
1677
+ "labelsToAdd",
1678
+ );
1679
+
1680
+ expect(labelsToAdd.name).toBe("MessageQueueLabelRuleLabelToAdd");
1681
+ expect(labelsToAdd.joinColumns?.[0]?.name).toBe(
1682
+ "messageQueueLabelRuleId",
1683
+ );
1684
+ });
1685
+
1686
+ test("owner rule assigns users and teams through its own join tables", () => {
1687
+ const model: MessageQueueOwnerRule = new MessageQueueOwnerRule();
1688
+
1689
+ for (const column of [
1690
+ "name",
1691
+ "description",
1692
+ "isEnabled",
1693
+ "notifyOwners",
1694
+ "ownerUsers",
1695
+ "ownerTeams",
1696
+ ]) {
1697
+ expect(model.getTableColumns().columns).toContain(column);
1698
+ }
1699
+
1700
+ expect(columnArgs(MessageQueueOwnerRule, "notifyOwners").options).toEqual(
1701
+ expect.objectContaining({ nullable: false, default: true }),
1702
+ );
1703
+
1704
+ expect(
1705
+ joinTableArgs(MessageQueueOwnerRule, "messageQueueLabels").name,
1706
+ ).toBe("MessageQueueOwnerRuleMessageQueueLabel");
1707
+ expect(joinTableArgs(MessageQueueOwnerRule, "ownerUsers").name).toBe(
1708
+ "MessageQueueOwnerRuleOwnerUser",
1709
+ );
1710
+ expect(joinTableArgs(MessageQueueOwnerRule, "ownerTeams").name).toBe(
1711
+ "MessageQueueOwnerRuleOwnerTeam",
1712
+ );
1713
+
1714
+ for (const property of [
1715
+ "messageQueueLabels",
1716
+ "ownerUsers",
1717
+ "ownerTeams",
1718
+ ]) {
1719
+ expect(
1720
+ joinTableArgs(MessageQueueOwnerRule, property).joinColumns?.[0]?.name,
1721
+ ).toBe("messageQueueOwnerRuleId");
1722
+ }
1723
+ });
1724
+
1725
+ test("the patterns tell people a queue's name is its destination and how to match a broker", () => {
1726
+ for (const modelType of [
1727
+ MessageQueueLabelRule,
1728
+ MessageQueueOwnerRule,
1729
+ ] as Array<ModelType>) {
1730
+ const model: BaseModel = new modelType();
1731
+
1732
+ expect(
1733
+ model.getTableColumnMetadata("messageQueueNamePattern").description,
1734
+ ).toContain("destination");
1735
+ expect(
1736
+ model.getTableColumnMetadata("messageQueueSystemPattern").title,
1737
+ ).toBe("Messaging System Pattern");
1738
+
1739
+ const systemDescription: string =
1740
+ model.getTableColumnMetadata("messageQueueSystemPattern")
1741
+ .description || "";
1742
+
1743
+ // Both forms the engines match against are documented.
1744
+ expect(systemDescription).toContain("messaging.system");
1745
+ expect(systemDescription).toContain("Apache Kafka");
1746
+ expect(systemDescription).toContain("^kafka$");
1747
+ }
1748
+ });
1749
+
1750
+ test("deletedBy columns are hidden on rule tables, like every rule table", () => {
1751
+ for (const modelType of [
1752
+ MessageQueueLabelRule,
1753
+ MessageQueueOwnerRule,
1754
+ ] as Array<ModelType>) {
1755
+ const model: BaseModel = new modelType();
1756
+
1757
+ for (const column of ["deletedByUser", "deletedByUserId"]) {
1758
+ expect(columnAccess(model, column)).toEqual({
1759
+ create: [],
1760
+ read: [],
1761
+ update: [],
1762
+ });
1763
+ }
1764
+ }
1765
+ });
1766
+ });
1767
+
1768
+ describe("Postgres identifier limits", () => {
1769
+ /*
1770
+ * Postgres silently truncates identifiers to 63 bytes, so two long names
1771
+ * that share a prefix become the same table, and a generated migration
1772
+ * never matches its own output again.
1773
+ */
1774
+ const LIMIT: number = 63;
1775
+
1776
+ test("every table, join table, join column and named index fits", () => {
1777
+ const names: Array<string> = [];
1778
+ const targets: Array<unknown> = QUEUE_MODELS.map(
1779
+ (spec: QueueModelSpec): unknown => {
1780
+ return spec.modelType;
1781
+ },
1782
+ );
1783
+
1784
+ for (const spec of QUEUE_MODELS) {
1785
+ names.push(spec.tableName);
1786
+ }
1787
+
1788
+ for (const joinTable of getMetadataArgsStorage()
1789
+ .joinTables as Array<JoinTableMetadataArgs>) {
1790
+ if (!targets.includes(joinTable.target)) {
1791
+ continue;
1792
+ }
1793
+
1794
+ names.push(joinTable.name!);
1795
+
1796
+ for (const column of [
1797
+ ...(joinTable.joinColumns || []),
1798
+ ...(joinTable.inverseJoinColumns || []),
1799
+ ]) {
1800
+ names.push(column.name!);
1801
+ }
1802
+ }
1803
+
1804
+ for (const target of targets) {
1805
+ for (const index of classIndexes(target as ModelType)) {
1806
+ if (index.name) {
1807
+ names.push(index.name);
1808
+ }
1809
+ }
1810
+ }
1811
+
1812
+ // 5 tables, 6 join tables with 12 columns, 2 named indexes.
1813
+ expect(names.length).toBe(25);
1814
+
1815
+ const tooLong: Array<string> = names.filter((name: string): boolean => {
1816
+ return name.length > LIMIT;
1817
+ });
1818
+
1819
+ expect(tooLong).toEqual([]);
1820
+ });
1821
+
1822
+ test("every column name fits", () => {
1823
+ for (const spec of QUEUE_MODELS) {
1824
+ for (const column of new spec.modelType().getTableColumns().columns) {
1825
+ expect(column.length).toBeLessThanOrEqual(LIMIT);
1826
+ }
1827
+ }
1828
+ });
1829
+ });
1830
+
1831
+ describe("permissions", () => {
1832
+ test("all 20 permissions exist in the enum and the catalogue", () => {
1833
+ const enumValues: Set<string> = new Set(Object.values(Permission));
1834
+
1835
+ for (const name of MESSAGE_QUEUE_PERMISSIONS) {
1836
+ expect(enumValues.has(name)).toBe(true);
1837
+ expect(Permission[name as keyof typeof Permission]).toBe(name);
1838
+
1839
+ const props: PermissionProps | undefined =
1840
+ PERMISSION_PROPS_BY_NAME.get(name);
1841
+
1842
+ expect(props).toBeDefined();
1843
+ expect(props!.isAssignableToTenant).toBe(true);
1844
+ expect(props!.isRolePermission).toBe(false);
1845
+ expect(props!.group).toBe("Telemetry");
1846
+ expect(props!.title).toContain("Queue");
1847
+ expect(props!.title).not.toContain("MessageQueue");
1848
+ expect(props!.title).not.toContain("Database");
1849
+ expect(props!.description.length).toBeGreaterThan(0);
1850
+ expect(props!.description).not.toContain("Database");
1851
+ expect(props!.description.endsWith(".")).toBe(true);
1852
+
1853
+ // The lookups the permission UI and the error messages use.
1854
+ expect(PermissionHelper.getTitle(name as Permission)).toBe(
1855
+ props!.title,
1856
+ );
1857
+ expect(PermissionHelper.getDescription(name as Permission)).toBe(
1858
+ props!.description,
1859
+ );
1860
+ }
1861
+
1862
+ // No stray members - the catalogue must not sprout a 21st.
1863
+ const members: Array<string> = Array.from(enumValues).filter(
1864
+ (value: string) => {
1865
+ return value.includes("MessageQueue");
1866
+ },
1867
+ );
1868
+
1869
+ expect(members.sort()).toEqual([...MESSAGE_QUEUE_PERMISSIONS].sort());
1870
+ });
1871
+
1872
+ test("each permission appears exactly once in the props catalogue", () => {
1873
+ for (const name of MESSAGE_QUEUE_PERMISSIONS) {
1874
+ expect(
1875
+ PERMISSION_PROPS.filter((props: PermissionProps): boolean => {
1876
+ return props.permission.toString() === name;
1877
+ }),
1878
+ ).toHaveLength(1);
1879
+ }
1880
+ });
1881
+
1882
+ test("titles are unique among the catalogue", () => {
1883
+ for (const name of MESSAGE_QUEUE_PERMISSIONS) {
1884
+ const title: string = PERMISSION_PROPS_BY_NAME.get(name)!.title;
1885
+
1886
+ expect(
1887
+ PERMISSION_PROPS.filter((props: PermissionProps): boolean => {
1888
+ return props.title === title;
1889
+ }),
1890
+ ).toHaveLength(1);
1891
+ }
1892
+ });
1893
+
1894
+ test("queue Delete/Edit/Read are label-scoped access-control permissions; nothing else is", () => {
1895
+ for (const name of MESSAGE_QUEUE_PERMISSIONS) {
1896
+ const props: PermissionProps = PERMISSION_PROPS_BY_NAME.get(name)!;
1897
+ const labelScoped: boolean = [
1898
+ "DeleteMessageQueue",
1899
+ "EditMessageQueue",
1900
+ "ReadMessageQueue",
1901
+ ].includes(name);
1902
+
1903
+ expect({ name, flag: props.isAccessControlPermission }).toEqual({
1904
+ name,
1905
+ flag: labelScoped,
1906
+ });
1907
+ }
1908
+ });
1909
+
1910
+ test("there is no queue feed, so no feed permissions", () => {
1911
+ for (const name of [
1912
+ "CreateMessageQueueFeed",
1913
+ "EditMessageQueueFeed",
1914
+ "ReadMessageQueueFeed",
1915
+ ]) {
1916
+ expect(Object.values(Permission)).not.toContain(name);
1917
+ }
1918
+ });
1919
+
1920
+ test.each(QUEUE_MODELS)(
1921
+ "$name references only real, catalogued permissions",
1922
+ (spec: QueueModelSpec) => {
1923
+ const enumValues: Set<string> = new Set(Object.values(Permission));
1924
+ const model: BaseModel = new spec.modelType();
1925
+
1926
+ for (const permission of allReferencedPermissions(model)) {
1927
+ const value: string = permission.toString();
1928
+
1929
+ expect(enumValues.has(value)).toBe(true);
1930
+ expect(PERMISSION_PROPS_BY_NAME.has(value)).toBe(true);
1931
+ }
1932
+ },
1933
+ );
1934
+
1935
+ test.each(QUEUE_MODELS)(
1936
+ "$name gates on Queue permissions, never on another product's",
1937
+ (spec: QueueModelSpec) => {
1938
+ const model: BaseModel = new spec.modelType();
1939
+
1940
+ for (const permission of allReferencedPermissions(model)) {
1941
+ const value: string = permission.toString();
1942
+
1943
+ expect(value).not.toContain("DatabaseServer");
1944
+ expect(value).not.toContain("Ceph");
1945
+ expect(value).not.toContain("ServerlessFunction");
1946
+ }
1947
+ },
1948
+ );
1949
+
1950
+ test.each(QUEUE_MODELS)(
1951
+ "$name has no column that requires a permission its table does not accept on create",
1952
+ (spec: QueueModelSpec) => {
1953
+ /*
1954
+ * The PermissionCatalogueCoverage sweep, scoped: a granular holder
1955
+ * that passes the table gate must not fail on a column gate.
1956
+ */
1957
+ const model: BaseModel = new spec.modelType();
1958
+ const roles: Set<string> = new Set(
1959
+ PermissionHelper.getRolePermissionProps().map(
1960
+ (props: PermissionProps): string => {
1961
+ return props.permission.toString();
1962
+ },
1963
+ ),
1964
+ );
1965
+ const tableCreate: Set<string> = new Set(
1966
+ sorted(model.getCreatePermissions()),
1967
+ );
1968
+
1969
+ for (const column of ownColumns(model)) {
1970
+ for (const permission of columnAccess(model, column).create || []) {
1971
+ const value: string = permission.toString();
1972
+
1973
+ expect({
1974
+ column,
1975
+ value,
1976
+ ok: roles.has(value) || tableCreate.has(value),
1977
+ }).toEqual({ column, value, ok: true });
1978
+ }
1979
+ }
1980
+ },
1981
+ );
1982
+ });
1983
+ });