@oneuptime/common 13.0.8 → 14.0.1

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 (514) hide show
  1. package/Models/AnalyticsModels/AuditLog.ts +23 -15
  2. package/Models/DatabaseModels/GlobalConfig.ts +24 -0
  3. package/Models/DatabaseModels/Index.ts +4 -0
  4. package/Models/DatabaseModels/Monitor.ts +3 -2
  5. package/Models/DatabaseModels/MonitorTemplate.ts +2 -1
  6. package/Models/DatabaseModels/ServiceLevelObjectiveFeed.ts +2 -0
  7. package/Models/DatabaseModels/ServiceLevelObjectiveLabelRule.ts +522 -0
  8. package/Models/DatabaseModels/ServiceLevelObjectiveMonitorRule.ts +38 -4
  9. package/Models/DatabaseModels/ServiceLevelObjectiveOwnerRule.ts +603 -0
  10. package/Scripts/generate-service-worker.js +65 -4
  11. package/Server/API/BaseAPI.ts +26 -5
  12. package/Server/API/GlobalConfigAPI.ts +228 -462
  13. package/Server/API/ProjectOIDC.ts +25 -16
  14. package/Server/API/ProjectSSO.ts +24 -16
  15. package/Server/API/StatusPageAPI.ts +100 -42
  16. package/Server/API/TeamMemberAPI.ts +10 -1
  17. package/Server/Enterprise/EnterpriseEdition.ts +649 -0
  18. package/Server/Enterprise/EnterpriseFeature.ts +48 -0
  19. package/Server/Enterprise/EnterpriseLicenseSnapshot.ts +192 -0
  20. package/Server/Enterprise/EnterpriseServerModule.ts +233 -0
  21. package/Server/EnvironmentConfig.ts +147 -2
  22. package/Server/Infrastructure/Postgres/SchemaMigrations/1793900000000-AddEnterpriseEditionFirstSeenAt.ts +25 -0
  23. package/Server/Infrastructure/Postgres/SchemaMigrations/1794100000000-AddSloLabelAndOwnerRules.ts +248 -0
  24. package/Server/Infrastructure/Postgres/SchemaMigrations/1794200000000-AddSloMonitorRuleMonitorType.ts +19 -0
  25. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +6 -0
  26. package/Server/Middleware/UserAuthorization.ts +38 -16
  27. package/Server/Services/AuditLogService.ts +84 -1079
  28. package/Server/Services/DatabaseService.ts +10 -0
  29. package/Server/Services/EnterpriseLicenseService.ts +38 -0
  30. package/Server/Services/GlobalConfigService.ts +80 -1
  31. package/Server/Services/Index.ts +4 -0
  32. package/Server/Services/MonitorProbeService.ts +116 -20
  33. package/Server/Services/MonitorService.ts +59 -6
  34. package/Server/Services/MonitorStatusTimelineService.ts +284 -0
  35. package/Server/Services/MonitorTemplateService.ts +26 -0
  36. package/Server/Services/ProjectService.ts +284 -0
  37. package/Server/Services/RumSessionPinService.ts +25 -6
  38. package/Server/Services/ServiceLevelObjectiveLabelRuleEngineService.ts +385 -0
  39. package/Server/Services/ServiceLevelObjectiveLabelRuleService.ts +51 -0
  40. package/Server/Services/ServiceLevelObjectiveMonitorRuleEngineService.ts +92 -16
  41. package/Server/Services/ServiceLevelObjectiveMonitorRuleService.ts +36 -1
  42. package/Server/Services/ServiceLevelObjectiveOwnerRuleEngineService.ts +521 -0
  43. package/Server/Services/ServiceLevelObjectiveOwnerRuleService.ts +51 -0
  44. package/Server/Services/ServiceLevelObjectiveService.ts +28 -0
  45. package/Server/Services/StatusPagePrivateUserService.ts +7 -3
  46. package/Server/Services/StatusPageService.ts +78 -1
  47. package/Server/Services/TeamMemberService.ts +11 -0
  48. package/Server/Services/TeamService.ts +10 -0
  49. package/Server/Services/UserService.ts +10 -17
  50. package/Server/Types/Database/Permissions/CreatePermission.ts +15 -0
  51. package/Server/Types/Database/Permissions/EditionPermission.ts +208 -18
  52. package/Server/Types/Database/Permissions/TablePermission.ts +10 -3
  53. package/Server/Types/Database/Permissions/UpdatePermission.ts +29 -0
  54. package/Server/Types/Markdown.ts +41 -0
  55. package/Server/Types/Workflow/Components/Telegram/SendMessageToChat.ts +27 -1
  56. package/Server/Utils/AI/Toolbox/SloTools.ts +1 -0
  57. package/Server/Utils/CommunityEditionSsoReport.ts +361 -0
  58. package/Server/Utils/EditionEnforcement.ts +233 -0
  59. package/Server/Utils/FrontendEnvironment.ts +41 -2
  60. package/Server/Utils/InstanceHealth/RedisHealth.ts +12 -277
  61. package/Server/Utils/Monitor/AffectedResourceList.ts +148 -0
  62. package/Server/Utils/Monitor/Criteria/CompareCriteria.ts +1 -1
  63. package/Server/Utils/Monitor/Criteria/EvaluateOverTime.ts +10 -1
  64. package/Server/Utils/Monitor/Criteria/MetricMonitorCriteria.ts +1 -1
  65. package/Server/Utils/Monitor/MonitorCriteriaEvaluator.ts +720 -465
  66. package/Server/Utils/Monitor/MonitoringIntervalValidator.ts +116 -0
  67. package/Server/Utils/Monitor/RootCauseList.ts +139 -0
  68. package/Server/Utils/Rules/RuleRun/RuleRunRegistry.ts +28 -0
  69. package/Server/Utils/Slo/SloRulePatternValidator.ts +42 -0
  70. package/Server/Utils/Workspace/Slack/Slack.ts +423 -10
  71. package/Tests/App/Accounts/LoginPasskey.test.tsx +18 -0
  72. package/Tests/App/Accounts/LoginSsoEdition.test.tsx +616 -0
  73. package/Tests/App/AdminDashboard/AdminAuthenticationSsoEdition.test.tsx +217 -0
  74. package/Tests/App/AdminDashboard/AdminEnterprisePluginPage.test.tsx +357 -0
  75. package/Tests/App/AdminDashboard/EnterpriseLicensesShell.test.tsx +214 -0
  76. package/Tests/App/AdminDashboard/GlobalSSOEnterpriseShells.test.tsx +271 -0
  77. package/Tests/App/AdminDashboard/HealthShells.test.tsx +659 -0
  78. package/Tests/App/Dashboard/AuditLogsAndComplianceShells.test.tsx +572 -0
  79. package/Tests/App/Dashboard/EnterpriseFeatureUpgrade.test.tsx +547 -0
  80. package/Tests/App/Dashboard/EnterprisePluginPage.test.tsx +667 -0
  81. package/Tests/App/Dashboard/FeedFilterSortIntegration.test.tsx +1632 -0
  82. package/Tests/App/Dashboard/FeedOptionsLocales.test.ts +250 -0
  83. package/Tests/App/Dashboard/FeedOrdering.test.ts +279 -9
  84. package/Tests/App/Dashboard/IdentityEnterpriseShells.test.tsx +319 -0
  85. package/Tests/App/Dashboard/InvestigationFeedRefresh.test.tsx +60 -1
  86. package/Tests/App/Dashboard/InvestigationPanel.test.tsx +594 -3
  87. package/Tests/App/Dashboard/OnboardingSsoEmptyState.test.tsx +185 -0
  88. package/Tests/App/Dashboard/ProductOrientation.test.tsx +646 -0
  89. package/Tests/App/Dashboard/ResourceFeed.test.tsx +612 -2
  90. package/Tests/App/Dashboard/ResourceFeedPageWiring.test.ts +30 -0
  91. package/Tests/App/Dashboard/ResourceFeedPagesFilterSort.test.tsx +1202 -0
  92. package/Tests/App/Dashboard/ScheduledMaintenanceFeedRefresh.test.tsx +52 -1
  93. package/Tests/App/Dashboard/SecurityEventConnectionDiagnostics.test.tsx +45 -9
  94. package/Tests/App/Dashboard/SecurityEventDetailPanel.test.tsx +399 -0
  95. package/Tests/App/Dashboard/SecurityEventListRow.test.tsx +214 -0
  96. package/Tests/App/Dashboard/SecurityEventsEmptyState.test.tsx +1 -83
  97. package/Tests/App/Dashboard/SecurityEventsNavTabs.test.tsx +248 -0
  98. package/Tests/App/Dashboard/SecurityEventsViewer.test.tsx +1203 -0
  99. package/Tests/App/Dashboard/SloFeed.test.tsx +106 -1
  100. package/Tests/App/Dashboard/SloMonitorRuleCriteria.test.tsx +566 -0
  101. package/Tests/App/Dashboard/SloNavigationWiring.test.tsx +6 -4
  102. package/Tests/App/Dashboard/SloNoticeBanner.test.tsx +186 -0
  103. package/Tests/App/Dashboard/SloOverviewKpiStrip.test.tsx +388 -44
  104. package/Tests/App/Dashboard/SloOverviewLayout.test.tsx +613 -0
  105. package/Tests/App/Dashboard/UserEmailCallSites.test.tsx +11 -91
  106. package/Tests/App/StatusPage/StatusPageSsoEmptyState.test.tsx +319 -0
  107. package/Tests/Helpers/RefreshAwareApiScan.ts +757 -0
  108. package/Tests/Helpers/TenantScopedRequestScan.ts +515 -0
  109. package/Tests/Models/DatabaseModels/ResourceFeedModels.test.ts +0 -8
  110. package/Tests/Models/DatabaseModels/SloLabelAndOwnerRuleModels.test.ts +404 -0
  111. package/Tests/Models/DatabaseModels/SloOverhaulModels.test.ts +17 -1
  112. package/Tests/Models/DatabaseModels/StaticRuleCriteriaInheritance.test.ts +4 -2
  113. package/Tests/Scripts/GenerateServiceWorker.test.ts +931 -0
  114. package/Tests/Server/API/BaseAPICreateItemDoesNotMutateModel.test.ts +130 -0
  115. package/Tests/Server/API/GlobalConfigLicense.test.ts +742 -497
  116. package/Tests/Server/API/OnCallReadinessAPI.test.ts +35 -909
  117. package/Tests/Server/API/SsoProviderListingsEdition.test.ts +432 -0
  118. package/Tests/Server/API/TeamMemberLeaveScimLockEdition.test.ts +252 -0
  119. package/Tests/Server/Enterprise/EnterpriseEdition.test.ts +824 -0
  120. package/Tests/Server/Enterprise/EnterpriseFeatureActive.test.ts +643 -0
  121. package/Tests/Server/Enterprise/EnterpriseLicenseSnapshot.test.ts +294 -0
  122. package/Tests/Server/Enterprise/EnterpriseModelFeatureMap.test.ts +93 -0
  123. package/Tests/Server/Enterprise/EnterpriseOnlyModulesLiveInEe.test.ts +582 -0
  124. package/Tests/Server/Enterprise/EnterpriseServerModule.test.ts +247 -0
  125. package/Tests/Server/Enterprise/FakeEnterpriseModule.ts +502 -0
  126. package/Tests/Server/Enterprise/TestBillingFlag.ts +70 -0
  127. package/Tests/Server/EnvironmentConfigEnterpriseEdition.test.ts +314 -0
  128. package/Tests/Server/Infrastructure/ContainerBootConfiguration.test.ts +289 -0
  129. package/Tests/Server/Infrastructure/E2EClickHouseFixtureAccess.test.ts +5 -1
  130. package/Tests/Server/Infrastructure/Postgres/AddConfigurableRuleCriteriaMigration.test.ts +3 -0
  131. package/Tests/Server/Infrastructure/Postgres/AddSloLabelAndOwnerRulesMigration.test.ts +407 -0
  132. package/Tests/Server/Infrastructure/Postgres/AddSloMonitorRuleMonitorTypeMigration.test.ts +171 -0
  133. package/Tests/Server/Infrastructure/Postgres/SloProductOverhaulMigration.test.ts +88 -4
  134. package/Tests/Server/Middleware/UserAuthorization.test.ts +37 -2
  135. package/Tests/Server/Middleware/UserAuthorizationEditionEnforcement.test.ts +516 -0
  136. package/Tests/Server/Services/AuditLogService.test.ts +460 -990
  137. package/Tests/Server/Services/CreateAndReadResponsesKeepIds.test.ts +263 -0
  138. package/Tests/Server/Services/DatabaseServiceRuleCriteriaValidation.test.ts +104 -0
  139. package/Tests/Server/Services/EnterpriseLicenseServiceKeyGeneration.test.ts +151 -0
  140. package/Tests/Server/Services/GlobalConfigServiceLicenseColumns.test.ts +357 -0
  141. package/Tests/Server/Services/MonitorDestinationInfoIPv6.test.ts +101 -0
  142. package/Tests/Server/Services/MonitorProbeServiceIntervalScheduling.test.ts +333 -0
  143. package/Tests/Server/Services/MonitorStatusTimelineDailyAggregates.test.ts +303 -0
  144. package/Tests/Server/Services/ProjectServiceAuditLogLicense.test.ts +701 -0
  145. package/Tests/Server/Services/ProjectServiceAuditLogSettingsCache.test.ts +31 -35
  146. package/Tests/Server/Services/RuleRun/LabelRuleEnginesGroupBRun.test.ts +48 -1
  147. package/Tests/Server/Services/RuleRun/OwnerRuleEnginesGroupBRun.test.ts +30 -0
  148. package/Tests/Server/Services/ScimPushGroupsTeamLocksEdition.test.ts +431 -0
  149. package/Tests/Server/Services/ServiceLevelObjectiveLabelAndOwnerRuleEngines.test.ts +1170 -0
  150. package/Tests/Server/Services/ServiceLevelObjectiveLabelAndOwnerRuleServices.test.ts +172 -0
  151. package/Tests/Server/Services/ServiceLevelObjectiveMonitorRuleEngineService.test.ts +323 -0
  152. package/Tests/Server/Services/ServiceLevelObjectiveMonitorRuleService.test.ts +115 -0
  153. package/Tests/Server/Services/ServiceLevelObjectiveMonitorRuleTriggers.test.ts +21 -2
  154. package/Tests/Server/Services/ServiceLevelObjectiveMonitorTypePostgres.test.ts +480 -0
  155. package/Tests/Server/Services/ServiceLevelObjectiveService.test.ts +162 -0
  156. package/Tests/Server/Services/SsoRequirementReadMasking.test.ts +419 -0
  157. package/Tests/Server/Services/SsoRequirementWriteGuard.test.ts +769 -0
  158. package/Tests/Server/Services/StaticRuleCriteriaRuntimeCoverage.test.ts +45 -6
  159. package/Tests/Server/Services/StatusPagePrivateUserInvitationPolicy.test.ts +94 -0
  160. package/Tests/Server/Services/UserAuthenticationService.test.ts +35 -0
  161. package/Tests/Server/Services/UserServiceSeatLimit.test.ts +94 -56
  162. package/Tests/Server/Types/Database/FeedEventTypeFilterQuery.test.ts +745 -0
  163. package/Tests/Server/Types/Database/Permissions/EditionPermission.test.ts +1823 -0
  164. package/Tests/Server/Types/Markdown.test.ts +183 -1
  165. package/Tests/Server/Types/Workflow/Components/ApiComponentSsrf.test.ts +49 -0
  166. package/Tests/Server/Types/Workflow/Components/TelegramSendMessageToChat.test.ts +331 -0
  167. package/Tests/Server/Utils/AI/SloTools.test.ts +10 -0
  168. package/Tests/Server/Utils/CommunityEditionSsoReport.test.ts +565 -0
  169. package/Tests/Server/Utils/EditionEnforcement.test.ts +303 -0
  170. package/Tests/Server/Utils/FrontendEnvironment.test.ts +367 -0
  171. package/Tests/Server/Utils/InstanceHealth/RedisHealth.test.ts +38 -418
  172. package/Tests/Server/Utils/Monitor/AffectedResourceList.test.ts +518 -0
  173. package/Tests/Server/Utils/Monitor/Criteria/EvaluateOverTime.test.ts +24 -4
  174. package/Tests/Server/Utils/Monitor/Criteria/MetricMonitorCriteriaAnomalyUnits.test.ts +1 -1
  175. package/Tests/Server/Utils/Monitor/MonitorCriteriaEvaluator.test.ts +1339 -96
  176. package/Tests/Server/Utils/Monitor/MonitorCriteriaEvaluatorBreachingSamples.test.ts +1101 -0
  177. package/Tests/Server/Utils/Monitor/MonitorCriteriaEvaluatorMetricUnits.test.ts +106 -80
  178. package/Tests/Server/Utils/Monitor/MonitoringIntervalValidator.test.ts +188 -0
  179. package/Tests/Server/Utils/Monitor/RootCauseList.test.ts +252 -0
  180. package/Tests/Server/Utils/Rules/RuleRun/RuleRunPermission.test.ts +154 -0
  181. package/Tests/Server/Utils/SSRFProtection.test.ts +111 -0
  182. package/Tests/Server/Utils/Slo/SloRulePatternValidator.test.ts +67 -0
  183. package/Tests/Server/Utils/VM/VMRunnerSsrf.test.ts +213 -0
  184. package/Tests/Server/Utils/Workspace/Slack/SlackMarkdownSectionSplit.test.ts +1209 -0
  185. package/Tests/Types/API/HostnameFromAuthority.test.ts +20 -10
  186. package/Tests/Types/API/HostnameIPv6.test.ts +149 -0
  187. package/Tests/Types/API/Route.test.ts +56 -0
  188. package/Tests/Types/API/URLSchemeLikePath.test.ts +304 -0
  189. package/Tests/Types/Database/CanonicalModelInstance.test.ts +190 -0
  190. package/Tests/UI/Components/EditionLabelLapseCopy.ts +104 -0
  191. package/Tests/UI/Components/EditionLabelLicenseManagerWiring.test.tsx +254 -0
  192. package/Tests/UI/Components/EditionLabelLicenseRefresh.test.tsx +84 -178
  193. package/Tests/UI/Components/EditionLabelLicenseStatus.test.tsx +1586 -0
  194. package/Tests/UI/Components/EditionLabelLicenseWritesGuard.test.tsx +157 -0
  195. package/Tests/UI/Components/FeedOptions.test.ts +1404 -0
  196. package/Tests/UI/Components/FeedOptionsButton.test.tsx +2603 -0
  197. package/Tests/UI/Components/Graphs/DayUptimeGraph.test.tsx +49 -2
  198. package/Tests/UI/Components/Icon.test.tsx +26 -0
  199. package/Tests/UI/Components/MarkdownConverters.test.ts +684 -0
  200. package/Tests/UI/Components/ModelListEmptyState.test.tsx +289 -0
  201. package/Tests/UI/Components/RuleCriteria/RuleCriteriaModelTable.test.tsx +3 -3
  202. package/Tests/UI/Components/TelemetryViewer/TelemetryViewerEmptyContent.test.tsx +131 -0
  203. package/Tests/UI/Components/useFeedItemsViewKey.test.tsx +1017 -0
  204. package/Tests/UI/Components/useFeedOptions.test.tsx +1107 -0
  205. package/Tests/UI/EsbuildEnterpriseAlias.test.ts +1127 -0
  206. package/Tests/Utils/HostAddressUtil.test.ts +138 -0
  207. package/Tests/Utils/LabelRuleImportExport.test.ts +102 -0
  208. package/Tests/Utils/Monitor/MonitorDestinationUtil.test.ts +313 -0
  209. package/Tests/Utils/Monitor/MonitoringIntervalUtil.test.ts +304 -0
  210. package/Tests/Utils/Slo/SloDuration.test.ts +115 -24
  211. package/Tests/Utils/Slo/SloHealth.test.ts +93 -10
  212. package/Tests/Utils/Slo/SloMonitorRuleCriteria.test.ts +109 -0
  213. package/Tests/Utils/Slo/SloOverviewText.test.ts +64 -0
  214. package/Tests/Utils/StatusPage/UptimeDailyAggregateUtil.test.ts +248 -0
  215. package/Types/API/Hostname.ts +63 -16
  216. package/Types/API/Route.ts +19 -2
  217. package/Types/API/URL.ts +26 -2
  218. package/Types/Database/AccessControl/ColumnAccessControl.ts +19 -7
  219. package/Types/Database/AccessControl/ColumnBillingAccessControl.ts +19 -7
  220. package/Types/Database/AccessControl/OwnerOnlyColumn.ts +15 -6
  221. package/Types/Database/CanonicalModelInstance.ts +102 -0
  222. package/Types/Database/TableColumn.ts +20 -6
  223. package/Types/EnterpriseLicense/EnterpriseLicensePeriods.ts +29 -0
  224. package/Types/IP/IPv6.ts +6 -1
  225. package/Types/Monitor/MetricMonitor/MetricCriteriaContext.ts +6 -5
  226. package/Types/Monitor/MetricMonitor/MetricMonitorResponse.ts +9 -0
  227. package/Types/Monitor/MonitorStep.ts +6 -1
  228. package/Types/Monitor/ProxmoxAlertTemplates.ts +1 -1
  229. package/Types/Permission.ts +90 -0
  230. package/Types/Rules/RuleCriteriaFieldRegistry.ts +11 -0
  231. package/Types/Rules/RuleRun.ts +4 -0
  232. package/Types/StatusPage/UptimeDailyAggregate.ts +110 -0
  233. package/UI/Components/EditionLabel/EditionLabel.tsx +796 -1195
  234. package/UI/Components/EditionLabel/LicenseManager.ts +119 -0
  235. package/UI/Components/Feed/FeedOptions.ts +427 -0
  236. package/UI/Components/Feed/FeedOptionsButton.tsx +692 -0
  237. package/UI/Components/Feed/useFeedItems.ts +28 -9
  238. package/UI/Components/Feed/useFeedOptions.ts +225 -0
  239. package/UI/Components/Graphs/DayUptimeGraph.tsx +123 -15
  240. package/UI/Components/Icon/Icon.tsx +1 -1
  241. package/UI/Components/Markdown.tsx/MarkdownConverters.ts +0 -0
  242. package/UI/Components/ModelList/ModelList.tsx +11 -1
  243. package/UI/Components/MonitorGraphs/Uptime.tsx +69 -0
  244. package/UI/Components/TelemetryViewer/TelemetryViewer.tsx +28 -12
  245. package/UI/esbuild-enterprise.js +263 -0
  246. package/Utils/EnterpriseLicense/EnterpriseLicenseUsage.ts +7 -2
  247. package/Utils/HostAddressUtil.ts +94 -0
  248. package/Utils/LabelRuleImportExport.ts +27 -9
  249. package/Utils/Monitor/MetricValueFormatter.ts +2 -2
  250. package/Utils/Monitor/MonitorDestinationUtil.ts +157 -0
  251. package/Utils/Monitor/MonitoringIntervalUtil.ts +436 -0
  252. package/Utils/Rules/MonitorTypeRuleCriteria.ts +31 -0
  253. package/Utils/Slo/SloDuration.ts +22 -6
  254. package/Utils/Slo/SloHealth.ts +8 -7
  255. package/Utils/Slo/SloMonitorRuleCriteria.ts +33 -1
  256. package/Utils/Slo/SloOverviewText.ts +33 -0
  257. package/Utils/Slo/SloProjection.ts +4 -3
  258. package/Utils/StatusPage/UptimeDailyAggregateUtil.ts +192 -0
  259. package/build/dist/Models/AnalyticsModels/AuditLog.js +23 -15
  260. package/build/dist/Models/AnalyticsModels/AuditLog.js.map +1 -1
  261. package/build/dist/Models/DatabaseModels/GlobalConfig.js +25 -0
  262. package/build/dist/Models/DatabaseModels/GlobalConfig.js.map +1 -1
  263. package/build/dist/Models/DatabaseModels/Index.js +4 -0
  264. package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
  265. package/build/dist/Models/DatabaseModels/Monitor.js +2 -2
  266. package/build/dist/Models/DatabaseModels/Monitor.js.map +1 -1
  267. package/build/dist/Models/DatabaseModels/MonitorTemplate.js +2 -1
  268. package/build/dist/Models/DatabaseModels/MonitorTemplate.js.map +1 -1
  269. package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveFeed.js +2 -0
  270. package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveFeed.js.map +1 -1
  271. package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveLabelRule.js +530 -0
  272. package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveLabelRule.js.map +1 -0
  273. package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveMonitorRule.js +39 -4
  274. package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveMonitorRule.js.map +1 -1
  275. package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveOwnerRule.js +612 -0
  276. package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveOwnerRule.js.map +1 -0
  277. package/build/dist/Server/API/BaseAPI.js +26 -5
  278. package/build/dist/Server/API/BaseAPI.js.map +1 -1
  279. package/build/dist/Server/API/GlobalConfigAPI.js +148 -344
  280. package/build/dist/Server/API/GlobalConfigAPI.js.map +1 -1
  281. package/build/dist/Server/API/ProjectOIDC.js +24 -16
  282. package/build/dist/Server/API/ProjectOIDC.js.map +1 -1
  283. package/build/dist/Server/API/ProjectSSO.js +24 -16
  284. package/build/dist/Server/API/ProjectSSO.js.map +1 -1
  285. package/build/dist/Server/API/StatusPageAPI.js +93 -43
  286. package/build/dist/Server/API/StatusPageAPI.js.map +1 -1
  287. package/build/dist/Server/API/TeamMemberAPI.js +8 -1
  288. package/build/dist/Server/API/TeamMemberAPI.js.map +1 -1
  289. package/build/dist/Server/Enterprise/EnterpriseEdition.js +466 -0
  290. package/build/dist/Server/Enterprise/EnterpriseEdition.js.map +1 -0
  291. package/build/dist/Server/Enterprise/EnterpriseFeature.js +39 -0
  292. package/build/dist/Server/Enterprise/EnterpriseFeature.js.map +1 -0
  293. package/build/dist/Server/Enterprise/EnterpriseLicenseSnapshot.js +70 -0
  294. package/build/dist/Server/Enterprise/EnterpriseLicenseSnapshot.js.map +1 -0
  295. package/build/dist/Server/Enterprise/EnterpriseServerModule.js +84 -0
  296. package/build/dist/Server/Enterprise/EnterpriseServerModule.js.map +1 -0
  297. package/build/dist/Server/EnvironmentConfig.js +84 -2
  298. package/build/dist/Server/EnvironmentConfig.js.map +1 -1
  299. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1793900000000-AddEnterpriseEditionFirstSeenAt.js +18 -0
  300. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1793900000000-AddEnterpriseEditionFirstSeenAt.js.map +1 -0
  301. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1794100000000-AddSloLabelAndOwnerRules.js +93 -0
  302. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1794100000000-AddSloLabelAndOwnerRules.js.map +1 -0
  303. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1794200000000-AddSloMonitorRuleMonitorType.js +12 -0
  304. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1794200000000-AddSloMonitorRuleMonitorType.js.map +1 -0
  305. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +6 -0
  306. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  307. package/build/dist/Server/Middleware/UserAuthorization.js +30 -11
  308. package/build/dist/Server/Middleware/UserAuthorization.js.map +1 -1
  309. package/build/dist/Server/Services/AuditLogService.js +71 -740
  310. package/build/dist/Server/Services/AuditLogService.js.map +1 -1
  311. package/build/dist/Server/Services/DatabaseService.js +7 -0
  312. package/build/dist/Server/Services/DatabaseService.js.map +1 -1
  313. package/build/dist/Server/Services/EnterpriseLicenseService.js +34 -0
  314. package/build/dist/Server/Services/EnterpriseLicenseService.js.map +1 -1
  315. package/build/dist/Server/Services/GlobalConfigService.js +63 -0
  316. package/build/dist/Server/Services/GlobalConfigService.js.map +1 -1
  317. package/build/dist/Server/Services/Index.js +4 -0
  318. package/build/dist/Server/Services/Index.js.map +1 -1
  319. package/build/dist/Server/Services/MonitorProbeService.js +90 -17
  320. package/build/dist/Server/Services/MonitorProbeService.js.map +1 -1
  321. package/build/dist/Server/Services/MonitorService.js +48 -6
  322. package/build/dist/Server/Services/MonitorService.js.map +1 -1
  323. package/build/dist/Server/Services/MonitorStatusTimelineService.js +242 -0
  324. package/build/dist/Server/Services/MonitorStatusTimelineService.js.map +1 -1
  325. package/build/dist/Server/Services/MonitorTemplateService.js +16 -0
  326. package/build/dist/Server/Services/MonitorTemplateService.js.map +1 -1
  327. package/build/dist/Server/Services/ProjectService.js +214 -0
  328. package/build/dist/Server/Services/ProjectService.js.map +1 -1
  329. package/build/dist/Server/Services/RumSessionPinService.js +24 -6
  330. package/build/dist/Server/Services/RumSessionPinService.js.map +1 -1
  331. package/build/dist/Server/Services/ServiceLevelObjectiveLabelRuleEngineService.js +295 -0
  332. package/build/dist/Server/Services/ServiceLevelObjectiveLabelRuleEngineService.js.map +1 -0
  333. package/build/dist/Server/Services/ServiceLevelObjectiveLabelRuleService.js +56 -0
  334. package/build/dist/Server/Services/ServiceLevelObjectiveLabelRuleService.js.map +1 -0
  335. package/build/dist/Server/Services/ServiceLevelObjectiveMonitorRuleEngineService.js +59 -14
  336. package/build/dist/Server/Services/ServiceLevelObjectiveMonitorRuleEngineService.js.map +1 -1
  337. package/build/dist/Server/Services/ServiceLevelObjectiveMonitorRuleService.js +22 -1
  338. package/build/dist/Server/Services/ServiceLevelObjectiveMonitorRuleService.js.map +1 -1
  339. package/build/dist/Server/Services/ServiceLevelObjectiveOwnerRuleEngineService.js +400 -0
  340. package/build/dist/Server/Services/ServiceLevelObjectiveOwnerRuleEngineService.js.map +1 -0
  341. package/build/dist/Server/Services/ServiceLevelObjectiveOwnerRuleService.js +56 -0
  342. package/build/dist/Server/Services/ServiceLevelObjectiveOwnerRuleService.js.map +1 -0
  343. package/build/dist/Server/Services/ServiceLevelObjectiveService.js +21 -0
  344. package/build/dist/Server/Services/ServiceLevelObjectiveService.js.map +1 -1
  345. package/build/dist/Server/Services/StatusPagePrivateUserService.js +7 -3
  346. package/build/dist/Server/Services/StatusPagePrivateUserService.js.map +1 -1
  347. package/build/dist/Server/Services/StatusPageService.js +71 -0
  348. package/build/dist/Server/Services/StatusPageService.js.map +1 -1
  349. package/build/dist/Server/Services/TeamMemberService.js +10 -0
  350. package/build/dist/Server/Services/TeamMemberService.js.map +1 -1
  351. package/build/dist/Server/Services/TeamService.js +9 -0
  352. package/build/dist/Server/Services/TeamService.js.map +1 -1
  353. package/build/dist/Server/Services/UserService.js +10 -16
  354. package/build/dist/Server/Services/UserService.js.map +1 -1
  355. package/build/dist/Server/Types/Database/Permissions/CreatePermission.js +10 -0
  356. package/build/dist/Server/Types/Database/Permissions/CreatePermission.js.map +1 -1
  357. package/build/dist/Server/Types/Database/Permissions/EditionPermission.js +154 -14
  358. package/build/dist/Server/Types/Database/Permissions/EditionPermission.js.map +1 -1
  359. package/build/dist/Server/Types/Database/Permissions/TablePermission.js +10 -3
  360. package/build/dist/Server/Types/Database/Permissions/TablePermission.js.map +1 -1
  361. package/build/dist/Server/Types/Database/Permissions/UpdatePermission.js +17 -0
  362. package/build/dist/Server/Types/Database/Permissions/UpdatePermission.js.map +1 -1
  363. package/build/dist/Server/Types/Markdown.js +31 -0
  364. package/build/dist/Server/Types/Markdown.js.map +1 -1
  365. package/build/dist/Server/Types/Workflow/Components/Telegram/SendMessageToChat.js +20 -1
  366. package/build/dist/Server/Types/Workflow/Components/Telegram/SendMessageToChat.js.map +1 -1
  367. package/build/dist/Server/Utils/AI/Toolbox/SloTools.js +1 -0
  368. package/build/dist/Server/Utils/AI/Toolbox/SloTools.js.map +1 -1
  369. package/build/dist/Server/Utils/CommunityEditionSsoReport.js +223 -0
  370. package/build/dist/Server/Utils/CommunityEditionSsoReport.js.map +1 -0
  371. package/build/dist/Server/Utils/EditionEnforcement.js +187 -0
  372. package/build/dist/Server/Utils/EditionEnforcement.js.map +1 -0
  373. package/build/dist/Server/Utils/FrontendEnvironment.js +31 -2
  374. package/build/dist/Server/Utils/FrontendEnvironment.js.map +1 -1
  375. package/build/dist/Server/Utils/InstanceHealth/RedisHealth.js +6 -193
  376. package/build/dist/Server/Utils/InstanceHealth/RedisHealth.js.map +1 -1
  377. package/build/dist/Server/Utils/Monitor/AffectedResourceList.js +67 -0
  378. package/build/dist/Server/Utils/Monitor/AffectedResourceList.js.map +1 -0
  379. package/build/dist/Server/Utils/Monitor/Criteria/CompareCriteria.js +1 -1
  380. package/build/dist/Server/Utils/Monitor/Criteria/EvaluateOverTime.js +8 -1
  381. package/build/dist/Server/Utils/Monitor/Criteria/EvaluateOverTime.js.map +1 -1
  382. package/build/dist/Server/Utils/Monitor/Criteria/MetricMonitorCriteria.js +1 -1
  383. package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js +585 -367
  384. package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js.map +1 -1
  385. package/build/dist/Server/Utils/Monitor/MonitoringIntervalValidator.js +88 -0
  386. package/build/dist/Server/Utils/Monitor/MonitoringIntervalValidator.js.map +1 -0
  387. package/build/dist/Server/Utils/Monitor/RootCauseList.js +101 -0
  388. package/build/dist/Server/Utils/Monitor/RootCauseList.js.map +1 -0
  389. package/build/dist/Server/Utils/Rules/RuleRun/RuleRunRegistry.js +28 -0
  390. package/build/dist/Server/Utils/Rules/RuleRun/RuleRunRegistry.js.map +1 -1
  391. package/build/dist/Server/Utils/Slo/SloRulePatternValidator.js +28 -0
  392. package/build/dist/Server/Utils/Slo/SloRulePatternValidator.js.map +1 -0
  393. package/build/dist/Server/Utils/Workspace/Slack/Slack.js +331 -11
  394. package/build/dist/Server/Utils/Workspace/Slack/Slack.js.map +1 -1
  395. package/build/dist/Types/API/Hostname.js +59 -11
  396. package/build/dist/Types/API/Hostname.js.map +1 -1
  397. package/build/dist/Types/API/Route.js +18 -2
  398. package/build/dist/Types/API/Route.js.map +1 -1
  399. package/build/dist/Types/API/URL.js +23 -2
  400. package/build/dist/Types/API/URL.js.map +1 -1
  401. package/build/dist/Types/Database/AccessControl/ColumnAccessControl.js +19 -7
  402. package/build/dist/Types/Database/AccessControl/ColumnAccessControl.js.map +1 -1
  403. package/build/dist/Types/Database/AccessControl/ColumnBillingAccessControl.js +19 -7
  404. package/build/dist/Types/Database/AccessControl/ColumnBillingAccessControl.js.map +1 -1
  405. package/build/dist/Types/Database/AccessControl/OwnerOnlyColumn.js +13 -6
  406. package/build/dist/Types/Database/AccessControl/OwnerOnlyColumn.js.map +1 -1
  407. package/build/dist/Types/Database/CanonicalModelInstance.js +88 -0
  408. package/build/dist/Types/Database/CanonicalModelInstance.js.map +1 -0
  409. package/build/dist/Types/Database/TableColumn.js +19 -6
  410. package/build/dist/Types/Database/TableColumn.js.map +1 -1
  411. package/build/dist/Types/EnterpriseLicense/EnterpriseLicensePeriods.js +28 -0
  412. package/build/dist/Types/EnterpriseLicense/EnterpriseLicensePeriods.js.map +1 -0
  413. package/build/dist/Types/IP/IPv6.js +6 -1
  414. package/build/dist/Types/IP/IPv6.js.map +1 -1
  415. package/build/dist/Types/Monitor/MonitorStep.js +5 -0
  416. package/build/dist/Types/Monitor/MonitorStep.js.map +1 -1
  417. package/build/dist/Types/Monitor/ProxmoxAlertTemplates.js +1 -1
  418. package/build/dist/Types/Permission.js +84 -0
  419. package/build/dist/Types/Permission.js.map +1 -1
  420. package/build/dist/Types/Rules/RuleCriteriaFieldRegistry.js +11 -0
  421. package/build/dist/Types/Rules/RuleCriteriaFieldRegistry.js.map +1 -1
  422. package/build/dist/Types/Rules/RuleRun.js +4 -0
  423. package/build/dist/Types/Rules/RuleRun.js.map +1 -1
  424. package/build/dist/Types/StatusPage/UptimeDailyAggregate.js +32 -0
  425. package/build/dist/Types/StatusPage/UptimeDailyAggregate.js.map +1 -0
  426. package/build/dist/UI/Components/EditionLabel/EditionLabel.js +414 -585
  427. package/build/dist/UI/Components/EditionLabel/EditionLabel.js.map +1 -1
  428. package/build/dist/UI/Components/EditionLabel/LicenseManager.js +2 -0
  429. package/build/dist/UI/Components/EditionLabel/LicenseManager.js.map +1 -0
  430. package/build/dist/UI/Components/Feed/FeedOptions.js +235 -0
  431. package/build/dist/UI/Components/Feed/FeedOptions.js.map +1 -0
  432. package/build/dist/UI/Components/Feed/FeedOptionsButton.js +346 -0
  433. package/build/dist/UI/Components/Feed/FeedOptionsButton.js.map +1 -0
  434. package/build/dist/UI/Components/Feed/useFeedItems.js +17 -7
  435. package/build/dist/UI/Components/Feed/useFeedItems.js.map +1 -1
  436. package/build/dist/UI/Components/Feed/useFeedOptions.js +130 -0
  437. package/build/dist/UI/Components/Feed/useFeedOptions.js.map +1 -0
  438. package/build/dist/UI/Components/Graphs/DayUptimeGraph.js +90 -17
  439. package/build/dist/UI/Components/Graphs/DayUptimeGraph.js.map +1 -1
  440. package/build/dist/UI/Components/Icon/Icon.js +1 -1
  441. package/build/dist/UI/Components/Icon/Icon.js.map +1 -1
  442. package/build/dist/UI/Components/Markdown.tsx/MarkdownConverters.js +0 -0
  443. package/build/dist/UI/Components/Markdown.tsx/MarkdownConverters.js.map +1 -1
  444. package/build/dist/UI/Components/ModelList/ModelList.js +4 -1
  445. package/build/dist/UI/Components/ModelList/ModelList.js.map +1 -1
  446. package/build/dist/UI/Components/MonitorGraphs/Uptime.js +42 -1
  447. package/build/dist/UI/Components/MonitorGraphs/Uptime.js.map +1 -1
  448. package/build/dist/UI/Components/TelemetryViewer/TelemetryViewer.js +2 -2
  449. package/build/dist/UI/Components/TelemetryViewer/TelemetryViewer.js.map +1 -1
  450. package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseUsage.js +6 -2
  451. package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseUsage.js.map +1 -1
  452. package/build/dist/Utils/HostAddressUtil.js +80 -0
  453. package/build/dist/Utils/HostAddressUtil.js.map +1 -0
  454. package/build/dist/Utils/LabelRuleImportExport.js +22 -6
  455. package/build/dist/Utils/LabelRuleImportExport.js.map +1 -1
  456. package/build/dist/Utils/Monitor/MetricValueFormatter.js +2 -2
  457. package/build/dist/Utils/Monitor/MonitorDestinationUtil.js +127 -0
  458. package/build/dist/Utils/Monitor/MonitorDestinationUtil.js.map +1 -0
  459. package/build/dist/Utils/Monitor/MonitoringIntervalUtil.js +374 -0
  460. package/build/dist/Utils/Monitor/MonitoringIntervalUtil.js.map +1 -0
  461. package/build/dist/Utils/Rules/MonitorTypeRuleCriteria.js +18 -0
  462. package/build/dist/Utils/Rules/MonitorTypeRuleCriteria.js.map +1 -0
  463. package/build/dist/Utils/Slo/SloDuration.js +13 -5
  464. package/build/dist/Utils/Slo/SloDuration.js.map +1 -1
  465. package/build/dist/Utils/Slo/SloHealth.js +8 -7
  466. package/build/dist/Utils/Slo/SloHealth.js.map +1 -1
  467. package/build/dist/Utils/Slo/SloMonitorRuleCriteria.js +16 -1
  468. package/build/dist/Utils/Slo/SloMonitorRuleCriteria.js.map +1 -1
  469. package/build/dist/Utils/Slo/SloOverviewText.js +16 -0
  470. package/build/dist/Utils/Slo/SloOverviewText.js.map +1 -1
  471. package/build/dist/Utils/Slo/SloProjection.js.map +1 -1
  472. package/build/dist/Utils/StatusPage/UptimeDailyAggregateUtil.js +148 -0
  473. package/build/dist/Utils/StatusPage/UptimeDailyAggregateUtil.js.map +1 -0
  474. package/jest.config.json +3 -1
  475. package/package.json +1 -1
  476. package/test-setup.sh +103 -34
  477. package/tsconfig.json +13 -0
  478. package/Server/API/EnterpriseLicenseAPI.ts +0 -925
  479. package/Server/API/TeamComplianceAPI.ts +0 -158
  480. package/Server/Middleware/SCIMAuthorization.ts +0 -141
  481. package/Server/Services/TeamComplianceService.ts +0 -733
  482. package/Server/Utils/EnterpriseLicense/EnterpriseLicenseSeatUtil.ts +0 -186
  483. package/Server/Utils/InstanceHealth/PostgresHealth.ts +0 -286
  484. package/Tests/App/AdminDashboard/EnterpriseLicenseInstanceActivity.test.tsx +0 -451
  485. package/Tests/App/Dashboard/AuditLogsTable.test.tsx +0 -598
  486. package/Tests/App/Dashboard/SecurityEventsExplorer.test.tsx +0 -761
  487. package/Tests/App/Dashboard/SecurityEventsSideMenu.test.tsx +0 -247
  488. package/Tests/App/Dashboard/SecurityEventsTableColumns.test.tsx +0 -382
  489. package/Tests/App/Dashboard/SecurityEventsVolumeChart.test.tsx +0 -321
  490. package/Tests/Server/API/EnterpriseLicenseReportUserCount.test.ts +0 -1851
  491. package/Tests/Server/Middleware/SCIMAuthorization.test.ts +0 -525
  492. package/Tests/Server/Services/TeamComplianceServiceBehaviour.test.ts +0 -1845
  493. package/Tests/Server/Utils/EnterpriseLicense/EnterpriseLicenseSeatUtil.test.ts +0 -495
  494. package/Tests/Server/Utils/InstanceHealth/PostgresHealth.test.ts +0 -337
  495. package/Tests/Utils/EnterpriseLicenseSeats.test.ts +0 -576
  496. package/Tests/Utils/EnterpriseLicenseSync.test.ts +0 -568
  497. package/Utils/EnterpriseLicense/EnterpriseLicenseSeats.ts +0 -287
  498. package/Utils/EnterpriseLicense/EnterpriseLicenseSync.ts +0 -244
  499. package/build/dist/Server/API/EnterpriseLicenseAPI.js +0 -646
  500. package/build/dist/Server/API/EnterpriseLicenseAPI.js.map +0 -1
  501. package/build/dist/Server/API/TeamComplianceAPI.js +0 -111
  502. package/build/dist/Server/API/TeamComplianceAPI.js.map +0 -1
  503. package/build/dist/Server/Middleware/SCIMAuthorization.js +0 -124
  504. package/build/dist/Server/Middleware/SCIMAuthorization.js.map +0 -1
  505. package/build/dist/Server/Services/TeamComplianceService.js +0 -537
  506. package/build/dist/Server/Services/TeamComplianceService.js.map +0 -1
  507. package/build/dist/Server/Utils/EnterpriseLicense/EnterpriseLicenseSeatUtil.js +0 -145
  508. package/build/dist/Server/Utils/EnterpriseLicense/EnterpriseLicenseSeatUtil.js.map +0 -1
  509. package/build/dist/Server/Utils/InstanceHealth/PostgresHealth.js +0 -194
  510. package/build/dist/Server/Utils/InstanceHealth/PostgresHealth.js.map +0 -1
  511. package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseSeats.js +0 -168
  512. package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseSeats.js.map +0 -1
  513. package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseSync.js +0 -174
  514. package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseSync.js.map +0 -1
@@ -0,0 +1,824 @@
1
+ import {
2
+ afterAll,
3
+ beforeAll,
4
+ beforeEach,
5
+ describe,
6
+ expect,
7
+ jest,
8
+ test,
9
+ } from "@jest/globals";
10
+ import fs from "fs";
11
+ import path from "path";
12
+ import EnterpriseEdition from "../../../Server/Enterprise/EnterpriseEdition";
13
+ import EnterpriseFeature, {
14
+ ALL_ENTERPRISE_FEATURES,
15
+ } from "../../../Server/Enterprise/EnterpriseFeature";
16
+ import {
17
+ EnterpriseLicenseFeatures,
18
+ EnterpriseLicenseSnapshot,
19
+ EnterpriseLicenseStatus,
20
+ SeatUsage,
21
+ } from "../../../Server/Enterprise/EnterpriseLicenseSnapshot";
22
+ import PaymentRequiredException from "../../../Types/Exception/PaymentRequiredException";
23
+ import logger from "../../../Server/Utils/Logger";
24
+ import FakeEnterpriseModule, {
25
+ createAuditLogRecorderSpy,
26
+ createLicenseSnapshot,
27
+ createLicenseSnapshotWithStatus,
28
+ installFakeEnterpriseModule,
29
+ MockedAuditLogRecorder,
30
+ uninstallEnterpriseModule,
31
+ } from "./FakeEnterpriseModule";
32
+ import { isTestBillingEnabled, setTestBillingEnabled } from "./TestBillingFlag";
33
+
34
+ /*
35
+ * Billing is pinned through the mocked EnvironmentConfig below, never read from
36
+ * the process environment: CI's config.env sets BILLING_ENABLED=true, so an
37
+ * unpinned suite would only ever test the SaaS path there.
38
+ */
39
+ jest.mock("../../../Server/EnvironmentConfig", () => {
40
+ const billingFlag: typeof import("./TestBillingFlag") = jest.requireActual(
41
+ "./TestBillingFlag",
42
+ ) as typeof import("./TestBillingFlag");
43
+
44
+ return billingFlag.withLiveBillingFlag(
45
+ jest.requireActual("../../../Server/EnvironmentConfig") as Record<
46
+ string,
47
+ unknown
48
+ >,
49
+ );
50
+ });
51
+
52
+ // Imports inside Server/EnvironmentConfig.ts or BillingConfig.ts that reach Enterprise/.
53
+ const ENTERPRISE_IMPORT_PATTERN: RegExp = /from\s+["'][^"']*Enterprise\//;
54
+ const ENTERPRISE_REQUIRE_PATTERN: RegExp = /require\(\s*["'][^"']*Enterprise\//;
55
+
56
+ const ALL_STATUSES: ReadonlyArray<EnterpriseLicenseStatus> = [
57
+ "missing",
58
+ "valid",
59
+ "grace",
60
+ "expired",
61
+ "invalid",
62
+ ];
63
+
64
+ type Entitlement = "all" | "includes" | "excludes" | "empty";
65
+
66
+ const ALL_ENTITLEMENTS: ReadonlyArray<Entitlement> = [
67
+ "all",
68
+ "includes",
69
+ "excludes",
70
+ "empty",
71
+ ];
72
+
73
+ type Mode = "sync" | "async";
74
+
75
+ const ALL_MODES: ReadonlyArray<Mode> = ["sync", "async"];
76
+
77
+ const featuresFor: (
78
+ entitlement: Entitlement,
79
+ feature: EnterpriseFeature,
80
+ ) => EnterpriseLicenseFeatures = (
81
+ entitlement: Entitlement,
82
+ feature: EnterpriseFeature,
83
+ ): EnterpriseLicenseFeatures => {
84
+ switch (entitlement) {
85
+ case "all":
86
+ return "all";
87
+ case "includes":
88
+ return [feature, EnterpriseFeature.InstanceHealth].filter(
89
+ (
90
+ value: EnterpriseFeature,
91
+ index: number,
92
+ all: Array<EnterpriseFeature>,
93
+ ): boolean => {
94
+ return all.indexOf(value) === index;
95
+ },
96
+ );
97
+ case "excludes":
98
+ return ALL_ENTERPRISE_FEATURES.filter(
99
+ (value: EnterpriseFeature): boolean => {
100
+ return value !== feature;
101
+ },
102
+ );
103
+ case "empty":
104
+ default:
105
+ return [];
106
+ }
107
+ };
108
+
109
+ const checkAvailability: (
110
+ mode: Mode,
111
+ feature: EnterpriseFeature,
112
+ ) => Promise<boolean> = async (
113
+ mode: Mode,
114
+ feature: EnterpriseFeature,
115
+ ): Promise<boolean> => {
116
+ if (mode === "sync") {
117
+ return EnterpriseEdition.isFeatureAvailableSync(feature);
118
+ }
119
+
120
+ return await EnterpriseEdition.isFeatureAvailable(feature);
121
+ };
122
+
123
+ const assertAvailability: (
124
+ mode: Mode,
125
+ feature: EnterpriseFeature,
126
+ ) => Promise<void> = async (
127
+ mode: Mode,
128
+ feature: EnterpriseFeature,
129
+ ): Promise<void> => {
130
+ if (mode === "sync") {
131
+ EnterpriseEdition.assertFeatureAvailableSync(feature);
132
+ return;
133
+ }
134
+
135
+ await EnterpriseEdition.assertFeatureAvailable(feature);
136
+ };
137
+
138
+ const captureError: (fn: () => Promise<void>) => Promise<unknown> = async (
139
+ fn: () => Promise<void>,
140
+ ): Promise<unknown> => {
141
+ try {
142
+ await fn();
143
+ } catch (err) {
144
+ return err;
145
+ }
146
+
147
+ return undefined;
148
+ };
149
+
150
+ beforeAll(() => {
151
+ jest.spyOn(logger, "warn").mockImplementation((): void => {
152
+ return undefined;
153
+ });
154
+ jest.spyOn(logger, "error").mockImplementation((): void => {
155
+ return undefined;
156
+ });
157
+ });
158
+
159
+ afterAll(() => {
160
+ jest.restoreAllMocks();
161
+ uninstallEnterpriseModule();
162
+ });
163
+
164
+ beforeEach(() => {
165
+ uninstallEnterpriseModule();
166
+ setTestBillingEnabled(false);
167
+ });
168
+
169
+ describe("EnterpriseEdition registration", () => {
170
+ test("starts on the Community Edition with nothing registered", () => {
171
+ expect(EnterpriseEdition.isLoaded()).toBe(false);
172
+ expect(EnterpriseEdition.getModule()).toBeNull();
173
+ });
174
+
175
+ test("register makes the module the loaded one", () => {
176
+ const fake: FakeEnterpriseModule = new FakeEnterpriseModule();
177
+
178
+ EnterpriseEdition.register(fake);
179
+
180
+ expect(EnterpriseEdition.isLoaded()).toBe(true);
181
+ expect(EnterpriseEdition.getModule()).toBe(fake);
182
+ });
183
+
184
+ test("a second registration throws and keeps the first module", () => {
185
+ const first: FakeEnterpriseModule = new FakeEnterpriseModule();
186
+ const second: FakeEnterpriseModule = new FakeEnterpriseModule();
187
+
188
+ EnterpriseEdition.register(first);
189
+
190
+ expect(() => {
191
+ EnterpriseEdition.register(second);
192
+ }).toThrow("already registered");
193
+ expect(EnterpriseEdition.getModule()).toBe(first);
194
+ });
195
+
196
+ test("registering the same module twice also throws", () => {
197
+ const fake: FakeEnterpriseModule = new FakeEnterpriseModule();
198
+
199
+ EnterpriseEdition.register(fake);
200
+
201
+ expect(() => {
202
+ EnterpriseEdition.register(fake);
203
+ }).toThrow("already registered");
204
+ });
205
+
206
+ test("registering nothing throws and leaves the edition unloaded", () => {
207
+ expect(() => {
208
+ EnterpriseEdition.register(
209
+ null as unknown as Parameters<typeof EnterpriseEdition.register>[0],
210
+ );
211
+ }).toThrow("needs a module");
212
+ expect(EnterpriseEdition.isLoaded()).toBe(false);
213
+ });
214
+
215
+ test("resetForTests forgets the module so a new one can be registered", () => {
216
+ const first: FakeEnterpriseModule = new FakeEnterpriseModule();
217
+ const second: FakeEnterpriseModule = new FakeEnterpriseModule();
218
+
219
+ EnterpriseEdition.register(first);
220
+ EnterpriseEdition.resetForTests();
221
+
222
+ expect(EnterpriseEdition.isLoaded()).toBe(false);
223
+ expect(EnterpriseEdition.getModule()).toBeNull();
224
+
225
+ EnterpriseEdition.register(second);
226
+ expect(EnterpriseEdition.getModule()).toBe(second);
227
+ });
228
+
229
+ test("the kit's install/uninstall helpers flip the edition", () => {
230
+ const fake: FakeEnterpriseModule = installFakeEnterpriseModule();
231
+ expect(EnterpriseEdition.getModule()).toBe(fake);
232
+
233
+ const replacement: FakeEnterpriseModule = installFakeEnterpriseModule();
234
+ expect(EnterpriseEdition.getModule()).toBe(replacement);
235
+
236
+ uninstallEnterpriseModule();
237
+ expect(EnterpriseEdition.isLoaded()).toBe(false);
238
+ });
239
+ });
240
+
241
+ /*
242
+ * The full availability matrix: billing x loaded x license status x feature
243
+ * entitlement, each checked for every feature both sync and async. The
244
+ * expectation is written as the three rules from the design, independently of
245
+ * the implementation:
246
+ * - not loaded -> never available
247
+ * - loaded, billing on -> always available (plan gates apply elsewhere)
248
+ * - loaded, billing off -> status valid or grace AND the feature is entitled
249
+ */
250
+ interface MatrixCase {
251
+ billing: boolean;
252
+ loaded: boolean;
253
+ status: EnterpriseLicenseStatus;
254
+ entitlement: Entitlement;
255
+ expected: boolean;
256
+ }
257
+
258
+ const USABLE_STATUSES: ReadonlySet<EnterpriseLicenseStatus> =
259
+ new Set<EnterpriseLicenseStatus>(["valid", "grace"]);
260
+
261
+ const ENTITLING: ReadonlySet<Entitlement> = new Set<Entitlement>([
262
+ "all",
263
+ "includes",
264
+ ]);
265
+
266
+ const matrix: Array<MatrixCase> = [];
267
+
268
+ for (const billing of [false, true]) {
269
+ for (const loaded of [false, true]) {
270
+ for (const status of ALL_STATUSES) {
271
+ for (const entitlement of ALL_ENTITLEMENTS) {
272
+ let expected: boolean = false;
273
+
274
+ if (loaded && billing) {
275
+ expected = true;
276
+ } else if (loaded) {
277
+ expected = USABLE_STATUSES.has(status) && ENTITLING.has(entitlement);
278
+ }
279
+
280
+ matrix.push({ billing, loaded, status, entitlement, expected });
281
+ }
282
+ }
283
+ }
284
+ }
285
+
286
+ describe("EnterpriseEdition feature availability matrix", () => {
287
+ test("the matrix covers every combination", () => {
288
+ expect(matrix.length).toBe(
289
+ 2 * 2 * ALL_STATUSES.length * ALL_ENTITLEMENTS.length,
290
+ );
291
+ expect(
292
+ matrix.filter((testCase: MatrixCase) => {
293
+ return testCase.expected;
294
+ }).length,
295
+ ).toBeGreaterThan(0);
296
+ expect(
297
+ matrix.filter((testCase: MatrixCase) => {
298
+ return !testCase.expected;
299
+ }).length,
300
+ ).toBeGreaterThan(0);
301
+ });
302
+
303
+ test.each(matrix)(
304
+ "billing=$billing loaded=$loaded status=$status entitlement=$entitlement -> $expected",
305
+ async (testCase: MatrixCase) => {
306
+ setTestBillingEnabled(testCase.billing);
307
+
308
+ for (const feature of ALL_ENTERPRISE_FEATURES) {
309
+ if (testCase.loaded) {
310
+ installFakeEnterpriseModule({
311
+ snapshot: createLicenseSnapshotWithStatus(testCase.status, {
312
+ features: featuresFor(testCase.entitlement, feature),
313
+ }),
314
+ });
315
+ } else {
316
+ uninstallEnterpriseModule();
317
+ }
318
+
319
+ for (const mode of ALL_MODES) {
320
+ const context: string = `${feature} ${mode}`;
321
+
322
+ expect(`${context}: ${await checkAvailability(mode, feature)}`).toBe(
323
+ `${context}: ${testCase.expected}`,
324
+ );
325
+
326
+ const error: unknown = await captureError(async () => {
327
+ await assertAvailability(mode, feature);
328
+ });
329
+
330
+ if (testCase.expected) {
331
+ expect(error).toBeUndefined();
332
+ continue;
333
+ }
334
+
335
+ expect(error).toBeInstanceOf(PaymentRequiredException);
336
+ expect(
337
+ `${context}: ${(error as PaymentRequiredException).message}`,
338
+ ).toBe(
339
+ `${context}: ${
340
+ testCase.loaded
341
+ ? EnterpriseEdition.LICENSE_REQUIRED_MESSAGE
342
+ : EnterpriseEdition.COMMUNITY_EDITION_MESSAGE
343
+ }`,
344
+ );
345
+ }
346
+ }
347
+ },
348
+ );
349
+ });
350
+
351
+ describe("EnterpriseEdition fails closed on an unknown license", () => {
352
+ test("sync: a null cached snapshot (first load not finished) is not available", () => {
353
+ installFakeEnterpriseModule({ snapshot: null });
354
+
355
+ expect(
356
+ EnterpriseEdition.isFeatureAvailableSync(EnterpriseFeature.SSO),
357
+ ).toBe(false);
358
+ expect(() => {
359
+ EnterpriseEdition.assertFeatureAvailableSync(EnterpriseFeature.SSO);
360
+ }).toThrow(EnterpriseEdition.LICENSE_REQUIRED_MESSAGE);
361
+ });
362
+
363
+ test("sync: a throwing cached-snapshot read is not available", () => {
364
+ const fake: FakeEnterpriseModule = installFakeEnterpriseModule();
365
+ fake.licensing.getCachedSnapshotError = new Error("cache exploded");
366
+
367
+ expect(
368
+ EnterpriseEdition.isFeatureAvailableSync(EnterpriseFeature.AuditLogs),
369
+ ).toBe(false);
370
+ });
371
+
372
+ test("async: a failing load with no cached snapshot is not available", async () => {
373
+ const fake: FakeEnterpriseModule = installFakeEnterpriseModule({
374
+ snapshot: null,
375
+ });
376
+ fake.licensing.getSnapshotError = new Error("database unreachable");
377
+
378
+ expect(
379
+ await EnterpriseEdition.isFeatureAvailable(EnterpriseFeature.SCIM),
380
+ ).toBe(false);
381
+ });
382
+
383
+ test("async: a failing load falls back to the last good cached snapshot", async () => {
384
+ const fake: FakeEnterpriseModule = installFakeEnterpriseModule({
385
+ snapshot: createLicenseSnapshot(),
386
+ });
387
+ fake.licensing.getSnapshotError = new Error("database unreachable");
388
+
389
+ expect(
390
+ await EnterpriseEdition.isFeatureAvailable(EnterpriseFeature.SCIM),
391
+ ).toBe(true);
392
+ });
393
+
394
+ test("async: a failing load and a throwing cache is not available", async () => {
395
+ const fake: FakeEnterpriseModule = installFakeEnterpriseModule();
396
+ fake.licensing.getSnapshotError = new Error("database unreachable");
397
+ fake.licensing.getCachedSnapshotError = new Error("cache exploded");
398
+
399
+ expect(
400
+ await EnterpriseEdition.isFeatureAvailable(
401
+ EnterpriseFeature.TeamCompliance,
402
+ ),
403
+ ).toBe(false);
404
+ expect(await EnterpriseEdition.getLicenseSnapshot()).toBeNull();
405
+ });
406
+
407
+ test("async prefers the fresh snapshot over the cached one", async () => {
408
+ installFakeEnterpriseModule({
409
+ snapshot: createLicenseSnapshotWithStatus("expired"),
410
+ asyncSnapshot: createLicenseSnapshot(),
411
+ });
412
+
413
+ expect(
414
+ EnterpriseEdition.isFeatureAvailableSync(EnterpriseFeature.SSO),
415
+ ).toBe(false);
416
+ expect(
417
+ await EnterpriseEdition.isFeatureAvailable(EnterpriseFeature.SSO),
418
+ ).toBe(true);
419
+ });
420
+
421
+ test("a snapshot with a malformed features value entitles nothing", () => {
422
+ installFakeEnterpriseModule({
423
+ snapshot: createLicenseSnapshot({
424
+ features: "everything" as unknown as EnterpriseLicenseFeatures,
425
+ }),
426
+ });
427
+
428
+ expect(
429
+ EnterpriseEdition.isFeatureAvailableSync(EnterpriseFeature.SSO),
430
+ ).toBe(false);
431
+ });
432
+
433
+ test("billing on does not need a license at all (SaaS: plan gates apply instead)", async () => {
434
+ setTestBillingEnabled(true);
435
+ const fake: FakeEnterpriseModule = installFakeEnterpriseModule({
436
+ snapshot: null,
437
+ });
438
+ fake.licensing.getSnapshotError = new Error("never asked");
439
+
440
+ expect(
441
+ EnterpriseEdition.isFeatureAvailableSync(EnterpriseFeature.SSO),
442
+ ).toBe(true);
443
+ expect(
444
+ await EnterpriseEdition.isFeatureAvailable(EnterpriseFeature.SSO),
445
+ ).toBe(true);
446
+ });
447
+ });
448
+
449
+ describe("EnterpriseEdition reads billing at call time", () => {
450
+ test("flipping the billing flag changes the answer without a reload", () => {
451
+ installFakeEnterpriseModule({
452
+ snapshot: createLicenseSnapshotWithStatus("expired"),
453
+ });
454
+
455
+ setTestBillingEnabled(false);
456
+ expect(isTestBillingEnabled()).toBe(false);
457
+ expect(
458
+ EnterpriseEdition.isFeatureAvailableSync(EnterpriseFeature.SSO),
459
+ ).toBe(false);
460
+
461
+ setTestBillingEnabled(true);
462
+ expect(
463
+ EnterpriseEdition.isFeatureAvailableSync(EnterpriseFeature.SSO),
464
+ ).toBe(true);
465
+
466
+ setTestBillingEnabled(false);
467
+ expect(
468
+ EnterpriseEdition.isFeatureAvailableSync(EnterpriseFeature.SSO),
469
+ ).toBe(false);
470
+ });
471
+
472
+ test("EnvironmentConfig never imports the enterprise facade (no import cycle)", () => {
473
+ const serverDirectory: string = path.join(__dirname, "../../../Server");
474
+
475
+ for (const fileName of ["EnvironmentConfig.ts", "BillingConfig.ts"]) {
476
+ const source: string = fs.readFileSync(
477
+ path.join(serverDirectory, fileName),
478
+ "utf8",
479
+ );
480
+
481
+ expect(source).not.toMatch(ENTERPRISE_IMPORT_PATTERN);
482
+ expect(source).not.toMatch(ENTERPRISE_REQUIRE_PATTERN);
483
+ }
484
+ });
485
+ });
486
+
487
+ describe("EnterpriseEdition unavailable messages", () => {
488
+ test("the Community Edition and the unlicensed Enterprise Edition say different things", () => {
489
+ expect(EnterpriseEdition.COMMUNITY_EDITION_MESSAGE).not.toBe(
490
+ EnterpriseEdition.LICENSE_REQUIRED_MESSAGE,
491
+ );
492
+ expect(EnterpriseEdition.COMMUNITY_EDITION_MESSAGE).toContain(
493
+ "Community Edition",
494
+ );
495
+ expect(EnterpriseEdition.COMMUNITY_EDITION_MESSAGE).toContain(
496
+ "Enterprise Edition image",
497
+ );
498
+ expect(EnterpriseEdition.LICENSE_REQUIRED_MESSAGE).toContain("license");
499
+ expect(EnterpriseEdition.LICENSE_REQUIRED_MESSAGE).not.toContain(
500
+ "Community Edition",
501
+ );
502
+ });
503
+
504
+ test("the license message points at the edition label, the only place a license is activated", () => {
505
+ /*
506
+ * The Admin Dashboard has no "Settings > License" page. Licenses are
507
+ * activated from the edition label in its header (the dialog the
508
+ * GlobalConfig license-column guard also names).
509
+ */
510
+ expect(EnterpriseEdition.LICENSE_REQUIRED_MESSAGE).toContain(
511
+ "edition label in the Admin Dashboard header",
512
+ );
513
+ expect(EnterpriseEdition.LICENSE_REQUIRED_MESSAGE).not.toMatch(
514
+ /Settings\s*(?:>|→|->)\s*License/i,
515
+ );
516
+ });
517
+
518
+ test("the license message never claims existing configuration keeps working", () => {
519
+ /*
520
+ * Every configuration write refused on a lapsed license answers with
521
+ * this message - SSO, OIDC and SCIM models, and the audit log settings -
522
+ * and for those features nothing keeps working: SSO, SCIM and audit
523
+ * logging stop (EnterpriseEdition.isFeatureActive). The configuration is
524
+ * only kept.
525
+ */
526
+ expect(EnterpriseEdition.LICENSE_REQUIRED_MESSAGE).not.toMatch(
527
+ /keeps? (?:on )?working|keeps? running|continues? to work/i,
528
+ );
529
+ expect(EnterpriseEdition.LICENSE_REQUIRED_MESSAGE).toContain(
530
+ "Enterprise configuration you already have is kept and can still be viewed or deleted",
531
+ );
532
+ });
533
+
534
+ test("the Community Edition message is used on CE even with billing on", async () => {
535
+ setTestBillingEnabled(true);
536
+
537
+ await expect(
538
+ EnterpriseEdition.assertFeatureAvailable(EnterpriseFeature.AuditLogs),
539
+ ).rejects.toThrow(EnterpriseEdition.COMMUNITY_EDITION_MESSAGE);
540
+ expect(() => {
541
+ EnterpriseEdition.assertFeatureAvailableSync(EnterpriseFeature.AuditLogs);
542
+ }).toThrow(EnterpriseEdition.COMMUNITY_EDITION_MESSAGE);
543
+ });
544
+
545
+ test.each([
546
+ "missing",
547
+ "expired",
548
+ "invalid",
549
+ ] as Array<EnterpriseLicenseStatus>)(
550
+ "an Enterprise install whose license is %s gets the license message",
551
+ async (status: EnterpriseLicenseStatus) => {
552
+ installFakeEnterpriseModule({
553
+ snapshot: createLicenseSnapshotWithStatus(status),
554
+ });
555
+
556
+ await expect(
557
+ EnterpriseEdition.assertFeatureAvailable(
558
+ EnterpriseFeature.InstanceHealth,
559
+ ),
560
+ ).rejects.toThrow(EnterpriseEdition.LICENSE_REQUIRED_MESSAGE);
561
+ },
562
+ );
563
+
564
+ test("a valid license that does not include the feature gets the license message", () => {
565
+ installFakeEnterpriseModule({
566
+ snapshot: createLicenseSnapshot({ features: [EnterpriseFeature.SSO] }),
567
+ });
568
+
569
+ expect(() => {
570
+ EnterpriseEdition.assertFeatureAvailableSync(EnterpriseFeature.SCIM);
571
+ }).toThrow(EnterpriseEdition.LICENSE_REQUIRED_MESSAGE);
572
+ expect(() => {
573
+ EnterpriseEdition.assertFeatureAvailableSync(EnterpriseFeature.SSO);
574
+ }).not.toThrow();
575
+ });
576
+
577
+ test("the thrown exception is a PaymentRequiredException (HTTP 402)", () => {
578
+ let caught: unknown = undefined;
579
+
580
+ try {
581
+ EnterpriseEdition.assertFeatureAvailableSync(EnterpriseFeature.SSO);
582
+ } catch (err) {
583
+ caught = err;
584
+ }
585
+
586
+ expect(caught).toBeInstanceOf(PaymentRequiredException);
587
+ });
588
+ });
589
+
590
+ describe("EnterpriseEdition license snapshot and seats", () => {
591
+ test("the Community Edition has no license snapshot", async () => {
592
+ expect(await EnterpriseEdition.getLicenseSnapshot()).toBeNull();
593
+ });
594
+
595
+ test("the Enterprise Edition returns the provider's snapshot", async () => {
596
+ const snapshot: EnterpriseLicenseSnapshot =
597
+ createLicenseSnapshotWithStatus("grace");
598
+ installFakeEnterpriseModule({ snapshot });
599
+
600
+ expect(await EnterpriseEdition.getLicenseSnapshot()).toBe(snapshot);
601
+ });
602
+
603
+ test("the Community Edition has no seat usage", async () => {
604
+ expect(await EnterpriseEdition.getSeatUsage()).toBeNull();
605
+ });
606
+
607
+ test("the Enterprise Edition returns the provider's seat usage", async () => {
608
+ const seatUsage: SeatUsage = {
609
+ isEnforced: true,
610
+ userLimit: 10,
611
+ seatsInUse: 4,
612
+ seatsRemaining: 6,
613
+ hasSeatForNewUser: true,
614
+ seatsUsedByOtherInstances: 0,
615
+ };
616
+ installFakeEnterpriseModule({ seatUsage });
617
+
618
+ expect(await EnterpriseEdition.getSeatUsage()).toEqual(seatUsage);
619
+ });
620
+
621
+ test("a failing seat-usage read returns null instead of throwing", async () => {
622
+ const fake: FakeEnterpriseModule = installFakeEnterpriseModule();
623
+ fake.licensing.getSeatUsage = async (): Promise<SeatUsage | null> => {
624
+ throw new Error("count failed");
625
+ };
626
+
627
+ expect(await EnterpriseEdition.getSeatUsage()).toBeNull();
628
+ });
629
+
630
+ test("the Community Edition never refuses a new user for seats", async () => {
631
+ await expect(
632
+ EnterpriseEdition.assertSeatAvailableForNewUser(),
633
+ ).resolves.toBeUndefined();
634
+ });
635
+
636
+ test("the Enterprise Edition asks the provider, and its refusal propagates", async () => {
637
+ const fake: FakeEnterpriseModule = installFakeEnterpriseModule({
638
+ seatError: new PaymentRequiredException("No seats left."),
639
+ });
640
+
641
+ await expect(
642
+ EnterpriseEdition.assertSeatAvailableForNewUser(),
643
+ ).rejects.toThrow("No seats left.");
644
+ expect(fake.licensing.seatChecks).toBe(1);
645
+ });
646
+
647
+ test("the Enterprise Edition allows the new user when the provider does", async () => {
648
+ const fake: FakeEnterpriseModule = installFakeEnterpriseModule();
649
+
650
+ await expect(
651
+ EnterpriseEdition.assertSeatAvailableForNewUser(),
652
+ ).resolves.toBeUndefined();
653
+ expect(fake.licensing.seatChecks).toBe(1);
654
+ });
655
+ });
656
+
657
+ describe("EnterpriseEdition audit log recorder", () => {
658
+ test("the Community Edition records nothing", () => {
659
+ expect(EnterpriseEdition.getAuditLogRecorder()).toBeNull();
660
+ });
661
+
662
+ test("the Enterprise Edition hands out the module's recorder", () => {
663
+ const recorder: MockedAuditLogRecorder = createAuditLogRecorderSpy();
664
+ installFakeEnterpriseModule({ auditLogRecorder: recorder });
665
+
666
+ expect(EnterpriseEdition.getAuditLogRecorder()).toBe(recorder);
667
+ });
668
+
669
+ test("the recorder is handed out whatever the license says (it decides per entry whether to record)", () => {
670
+ const recorder: MockedAuditLogRecorder = createAuditLogRecorderSpy();
671
+ installFakeEnterpriseModule({
672
+ auditLogRecorder: recorder,
673
+ snapshot: createLicenseSnapshotWithStatus("expired"),
674
+ });
675
+
676
+ /*
677
+ * Handing it out keeps invalidateProjectSettings working while the license
678
+ * is lapsed. Whether an entry is recorded is the recorder's own
679
+ * isFeatureActive(AuditLogs) check (ee/Tests/Server/AuditLog/
680
+ * AuditLogRecorder.test.ts pins that it records nothing while lapsed).
681
+ */
682
+ expect(EnterpriseEdition.getAuditLogRecorder()).toBe(recorder);
683
+ });
684
+
685
+ test("a module without a recorder yields null", () => {
686
+ installFakeEnterpriseModule({ auditLogRecorder: null });
687
+
688
+ expect(EnterpriseEdition.getAuditLogRecorder()).toBeNull();
689
+ });
690
+
691
+ test("a module whose recorder getter throws yields null", () => {
692
+ const fake: FakeEnterpriseModule = installFakeEnterpriseModule();
693
+ fake.getAuditLogRecorder = (): never => {
694
+ throw new Error("recorder failed");
695
+ };
696
+
697
+ expect(EnterpriseEdition.getAuditLogRecorder()).toBeNull();
698
+ });
699
+ });
700
+
701
+ describe("EnterpriseEdition runtime state (isFeatureActive)", () => {
702
+ /*
703
+ * The full matrix, the unknown-state rule and the lapse log live in
704
+ * EnterpriseFeatureActive.test.ts. The old shouldEnforceSso() ("enforce SSO
705
+ * whenever ee is loaded, whatever the license says") is gone on purpose:
706
+ * SSO enforcement now follows isFeatureActive(SSO), so it relaxes when the
707
+ * license lapses.
708
+ */
709
+ test("shouldEnforceSso no longer exists", () => {
710
+ expect(
711
+ (EnterpriseEdition as unknown as Record<string, unknown>)[
712
+ "shouldEnforceSso"
713
+ ],
714
+ ).toBeUndefined();
715
+ });
716
+
717
+ test.each(ALL_STATUSES)(
718
+ "billing off, %s license: SSO is active exactly when the license entitles it",
719
+ (status: EnterpriseLicenseStatus) => {
720
+ installFakeEnterpriseModule({
721
+ snapshot: createLicenseSnapshotWithStatus(status),
722
+ });
723
+
724
+ expect(EnterpriseEdition.isFeatureActive(EnterpriseFeature.SSO)).toBe(
725
+ status === "valid" || status === "grace",
726
+ );
727
+ },
728
+ );
729
+ });
730
+
731
+ describe("EnterpriseEdition model to feature map", () => {
732
+ test.each([
733
+ ["GlobalSSO", EnterpriseFeature.SSO],
734
+ ["GlobalOIDC", EnterpriseFeature.SSO],
735
+ ["GlobalSSOProject", EnterpriseFeature.SSO],
736
+ ["GlobalOIDCProject", EnterpriseFeature.SSO],
737
+ ["ProjectSSO", EnterpriseFeature.SSO],
738
+ ["ProjectOIDC", EnterpriseFeature.SSO],
739
+ ["StatusPageSSO", EnterpriseFeature.SSO],
740
+ ["StatusPageOIDC", EnterpriseFeature.SSO],
741
+ ["ProjectSCIM", EnterpriseFeature.SCIM],
742
+ ["StatusPageSCIM", EnterpriseFeature.SCIM],
743
+ ["TeamComplianceSetting", EnterpriseFeature.TeamCompliance],
744
+ ] as Array<[string, EnterpriseFeature]>)(
745
+ "table %s is gated by %s",
746
+ (tableName: string, feature: EnterpriseFeature) => {
747
+ expect(EnterpriseEdition.getFeatureForTableName(tableName)).toBe(feature);
748
+ },
749
+ );
750
+
751
+ test("maps exactly the eleven enterprise configuration tables", () => {
752
+ expect(EnterpriseEdition.getMappedTableNames().sort()).toEqual(
753
+ [
754
+ "GlobalOIDC",
755
+ "GlobalOIDCProject",
756
+ "GlobalSSO",
757
+ "GlobalSSOProject",
758
+ "ProjectOIDC",
759
+ "ProjectSCIM",
760
+ "ProjectSSO",
761
+ "StatusPageOIDC",
762
+ "StatusPageSCIM",
763
+ "StatusPageSSO",
764
+ "TeamComplianceSetting",
765
+ ].sort(),
766
+ );
767
+ });
768
+
769
+ test("unknown, empty and missing table names map to nothing", () => {
770
+ expect(EnterpriseEdition.getFeatureForTableName("Monitor")).toBeNull();
771
+ expect(EnterpriseEdition.getFeatureForTableName("")).toBeNull();
772
+ expect(EnterpriseEdition.getFeatureForTableName(null)).toBeNull();
773
+ expect(EnterpriseEdition.getFeatureForTableName(undefined)).toBeNull();
774
+ expect(EnterpriseEdition.getFeatureForTableName("globalsso")).toBeNull();
775
+ });
776
+
777
+ test("getModelFeature reads the table name off a model instance", () => {
778
+ class FakeSsoModel {
779
+ public tableName: string | null = "ProjectSSO";
780
+ }
781
+ class FakePlainModel {
782
+ public tableName: string | null = "Incident";
783
+ }
784
+ class FakeUnnamedModel {
785
+ public tableName: string | null = null;
786
+ }
787
+
788
+ type ModelTypeArgument = Parameters<
789
+ typeof EnterpriseEdition.getModelFeature
790
+ >[0];
791
+
792
+ expect(
793
+ EnterpriseEdition.getModelFeature(
794
+ FakeSsoModel as unknown as ModelTypeArgument,
795
+ ),
796
+ ).toBe(EnterpriseFeature.SSO);
797
+ expect(
798
+ EnterpriseEdition.getModelFeature(
799
+ FakePlainModel as unknown as ModelTypeArgument,
800
+ ),
801
+ ).toBeNull();
802
+ expect(
803
+ EnterpriseEdition.getModelFeature(
804
+ FakeUnnamedModel as unknown as ModelTypeArgument,
805
+ ),
806
+ ).toBeNull();
807
+ });
808
+
809
+ test("getModelFeature returns null when the model cannot be constructed", () => {
810
+ class ExplodingModel {
811
+ public constructor() {
812
+ throw new Error("boom");
813
+ }
814
+ }
815
+
816
+ expect(
817
+ EnterpriseEdition.getModelFeature(
818
+ ExplodingModel as unknown as Parameters<
819
+ typeof EnterpriseEdition.getModelFeature
820
+ >[0],
821
+ ),
822
+ ).toBeNull();
823
+ });
824
+ });