@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
@@ -2,8 +2,9 @@ import { afterEach, beforeEach, describe, expect, test } from "@jest/globals";
2
2
  import ObjectID from "../../../Types/ObjectID";
3
3
 
4
4
  /*
5
- * AuditLogService caches each project's audit settings (enabled, retention,
6
- * system events, plan) for a minute. Nothing ever invalidated that cache, so
5
+ * The audit-log recorder (Enterprise Edition, behind core's AuditLogService)
6
+ * caches each project's audit settings (enabled, retention, system events,
7
+ * plan) for a minute. Nothing ever invalidated that cache, so
7
8
  * for up to a minute after an admin turned audit logging on, the process that
8
9
  * saved the setting went on recording nothing - exactly when someone is
9
10
  * watching the empty audit page to check that it works. ProjectService now
@@ -34,10 +35,14 @@ jest.mock(
34
35
 
35
36
  import AuditLogService from "../../../Server/Services/AuditLogService";
36
37
  import ProjectService from "../../../Server/Services/ProjectService";
37
- import Monitor from "../../../Models/DatabaseModels/Monitor";
38
38
  import Project from "../../../Models/DatabaseModels/Project";
39
39
  import { PlanType } from "../../../Types/Billing/SubscriptionPlan";
40
- import UserType from "../../../Types/UserType";
40
+ import {
41
+ createAuditLogRecorderSpy,
42
+ installFakeEnterpriseModule,
43
+ MockedAuditLogRecorder,
44
+ uninstallEnterpriseModule,
45
+ } from "../Enterprise/FakeEnterpriseModule";
41
46
 
42
47
  type HookCallable = {
43
48
  onUpdateSuccess: (
@@ -65,9 +70,11 @@ const updateProject: UpdateProjectFunction = async (
65
70
 
66
71
  beforeEach(() => {
67
72
  jest.clearAllMocks();
73
+ uninstallEnterpriseModule();
68
74
  });
69
75
 
70
76
  afterEach(() => {
77
+ uninstallEnterpriseModule();
71
78
  jest.restoreAllMocks();
72
79
  });
73
80
 
@@ -135,42 +142,31 @@ describe("ProjectService invalidates the audit log settings cache", () => {
135
142
  expect(invalidate).toHaveBeenCalledTimes(1);
136
143
  });
137
144
 
138
- test("the next audit write in this process reads the new setting", async () => {
145
+ /*
146
+ * The cache itself lives in the Enterprise audit-log recorder (ee/), so
147
+ * "the next write reads the new setting" is pinned there, end to end
148
+ * (ee/Tests/Server/AuditLog/AuditLogSettingsInvalidation.test.ts). What
149
+ * core owns is that the invalidation reaches whichever recorder is
150
+ * registered, and is harmless when none is.
151
+ */
152
+ test("the invalidation reaches the Enterprise audit-log recorder", async () => {
153
+ const recorder: MockedAuditLogRecorder = createAuditLogRecorderSpy();
154
+ installFakeEnterpriseModule({ auditLogRecorder: recorder });
155
+
139
156
  const projectId: ObjectID = ObjectID.generate();
140
- const project: Project = new Project();
141
- project._id = projectId.toString();
142
- project.enableAuditLogs = true;
143
-
144
- const findProject: jest.SpyInstance = jest
145
- .spyOn(ProjectService, "findOneById")
146
- .mockResolvedValue(project as never);
147
- jest.spyOn(AuditLogService, "create").mockResolvedValue(undefined as never);
148
-
149
- const monitor: Monitor = new Monitor();
150
- monitor._id = ObjectID.generate().toString();
151
- monitor.name = "Checkout API";
152
-
153
- type RecordFunction = () => Promise<void>;
154
-
155
- const recordMonitorCreate: RecordFunction = async (): Promise<void> => {
156
- await AuditLogService.recordCreate({
157
- model: new Monitor(),
158
- createdItem: monitor,
159
- // An API-key actor needs no user lookup.
160
- props: { tenantId: projectId, userType: UserType.API },
161
- });
162
- };
163
157
 
164
- await recordMonitorCreate();
165
- await recordMonitorCreate();
158
+ await updateProject({ enableAuditLogs: false }, [projectId]);
166
159
 
167
- // Cached: the second write did not read the project again.
168
- expect(findProject).toHaveBeenCalledTimes(1);
160
+ expect(recorder.invalidateProjectSettings).toHaveBeenCalledTimes(1);
161
+ expect(recorder.invalidateProjectSettings).toHaveBeenCalledWith(projectId);
162
+ });
169
163
 
170
- await updateProject({ enableAuditLogs: false }, [projectId]);
171
- await recordMonitorCreate();
164
+ test("on the Community Edition there is no cache to drop, and the update still succeeds", async () => {
165
+ uninstallEnterpriseModule();
172
166
 
173
- expect(findProject).toHaveBeenCalledTimes(2);
167
+ await expect(
168
+ updateProject({ enableAuditLogs: true }, [ObjectID.generate()]),
169
+ ).resolves.toBeUndefined();
174
170
  });
175
171
 
176
172
  test("a failure to invalidate never fails the project update", async () => {
@@ -28,6 +28,10 @@ import ServiceFeedService from "../../../../Server/Services/ServiceFeedService";
28
28
  import ServiceLabelRuleEngineService from "../../../../Server/Services/ServiceLabelRuleEngineService";
29
29
  import ServiceLabelRuleService from "../../../../Server/Services/ServiceLabelRuleService";
30
30
  import ServiceService from "../../../../Server/Services/ServiceService";
31
+ import ServiceLevelObjectiveFeedService from "../../../../Server/Services/ServiceLevelObjectiveFeedService";
32
+ import ServiceLevelObjectiveLabelRuleEngineService from "../../../../Server/Services/ServiceLevelObjectiveLabelRuleEngineService";
33
+ import ServiceLevelObjectiveLabelRuleService from "../../../../Server/Services/ServiceLevelObjectiveLabelRuleService";
34
+ import ServiceLevelObjectiveService from "../../../../Server/Services/ServiceLevelObjectiveService";
31
35
  import StatusPageLabelRuleEngineService from "../../../../Server/Services/StatusPageLabelRuleEngineService";
32
36
  import StatusPageLabelRuleService from "../../../../Server/Services/StatusPageLabelRuleService";
33
37
  import StatusPageService from "../../../../Server/Services/StatusPageService";
@@ -61,6 +65,8 @@ import ServerlessFunction from "../../../../Models/DatabaseModels/ServerlessFunc
61
65
  import ServerlessFunctionLabelRule from "../../../../Models/DatabaseModels/ServerlessFunctionLabelRule";
62
66
  import Service from "../../../../Models/DatabaseModels/Service";
63
67
  import ServiceLabelRule from "../../../../Models/DatabaseModels/ServiceLabelRule";
68
+ import ServiceLevelObjective from "../../../../Models/DatabaseModels/ServiceLevelObjective";
69
+ import ServiceLevelObjectiveLabelRule from "../../../../Models/DatabaseModels/ServiceLevelObjectiveLabelRule";
64
70
  import StatusPage from "../../../../Models/DatabaseModels/StatusPage";
65
71
  import StatusPageLabelRule from "../../../../Models/DatabaseModels/StatusPageLabelRule";
66
72
  import VMwareVCenter from "../../../../Models/DatabaseModels/VMwareVCenter";
@@ -397,6 +403,47 @@ const cases: Array<LabelEngineCase> = [
397
403
  },
398
404
  feedResourceIdKey: "serviceId",
399
405
  }),
406
+ labelEngineCase<ServiceLevelObjective, ServiceLevelObjectiveLabelRule>({
407
+ name: "ServiceLevelObjectiveLabelRuleEngineService",
408
+ engine: ServiceLevelObjectiveLabelRuleEngineService,
409
+ applyOnCreate: (resource: ServiceLevelObjective): Promise<void> => {
410
+ return ServiceLevelObjectiveLabelRuleEngineService.applyRulesToServiceLevelObjective(
411
+ resource,
412
+ );
413
+ },
414
+ ruleService:
415
+ ServiceLevelObjectiveLabelRuleService as unknown as RuleReadService,
416
+ resourceService: ServiceLevelObjectiveService as unknown as ResourceService,
417
+ resourceModel: ServiceLevelObjective,
418
+ textField: "name",
419
+ patternField: "serviceLevelObjectiveNamePattern",
420
+ labelMatchField: "serviceLevelObjectiveLabels",
421
+ matchesHandedResource: false,
422
+ syncsInMemoryLabels: true,
423
+ severity: null,
424
+ expectedRuleSelect: {
425
+ _id: true,
426
+ name: true,
427
+ criteria: true,
428
+ serviceLevelObjectiveLabels: { _id: true },
429
+ serviceLevelObjectiveNamePattern: true,
430
+ serviceLevelObjectiveDescriptionPattern: true,
431
+ labelsToAdd: { _id: true },
432
+ },
433
+ expectedResourceSelect: IDS_ONLY_RESOURCE_SELECT,
434
+ mockFeed: (): jest.SpyInstance => {
435
+ jest
436
+ .spyOn(ServiceLevelObjectiveService, "getSloMarkdownLink")
437
+ .mockResolvedValue(MARKDOWN_LINK);
438
+ return jest
439
+ .spyOn(
440
+ ServiceLevelObjectiveFeedService,
441
+ "createServiceLevelObjectiveFeedItem",
442
+ )
443
+ .mockResolvedValue(undefined);
444
+ },
445
+ feedResourceIdKey: "serviceLevelObjectiveId",
446
+ }),
400
447
  labelEngineCase<StatusPage, StatusPageLabelRule>({
401
448
  name: "StatusPageLabelRuleEngineService",
402
449
  engine: StatusPageLabelRuleEngineService,
@@ -797,7 +844,7 @@ describe("label rule engines (group B) - applying a rule to existing resources",
797
844
  cases.map((c: LabelEngineCase) => {
798
845
  return c.name;
799
846
  }),
800
- ).toHaveLength(11);
847
+ ).toHaveLength(12);
801
848
  });
802
849
 
803
850
  describe.each(cases)("$name", (c: LabelEngineCase) => {
@@ -43,6 +43,12 @@ import ServiceOwnerRuleService from "../../../../Server/Services/ServiceOwnerRul
43
43
  import ServiceOwnerTeamService from "../../../../Server/Services/ServiceOwnerTeamService";
44
44
  import ServiceOwnerUserService from "../../../../Server/Services/ServiceOwnerUserService";
45
45
  import ServiceService from "../../../../Server/Services/ServiceService";
46
+ import ServiceLevelObjectiveFeedService from "../../../../Server/Services/ServiceLevelObjectiveFeedService";
47
+ import ServiceLevelObjectiveOwnerRuleEngineService from "../../../../Server/Services/ServiceLevelObjectiveOwnerRuleEngineService";
48
+ import ServiceLevelObjectiveOwnerRuleService from "../../../../Server/Services/ServiceLevelObjectiveOwnerRuleService";
49
+ import ServiceLevelObjectiveOwnerTeamService from "../../../../Server/Services/ServiceLevelObjectiveOwnerTeamService";
50
+ import ServiceLevelObjectiveOwnerUserService from "../../../../Server/Services/ServiceLevelObjectiveOwnerUserService";
51
+ import ServiceLevelObjectiveService from "../../../../Server/Services/ServiceLevelObjectiveService";
46
52
  import StatusPageOwnerRuleEngineService from "../../../../Server/Services/StatusPageOwnerRuleEngineService";
47
53
  import StatusPageOwnerRuleService from "../../../../Server/Services/StatusPageOwnerRuleService";
48
54
  import StatusPageOwnerTeamService from "../../../../Server/Services/StatusPageOwnerTeamService";
@@ -78,6 +84,8 @@ import ServerlessFunctionOwnerTeam from "../../../../Models/DatabaseModels/Serve
78
84
  import ServerlessFunctionOwnerUser from "../../../../Models/DatabaseModels/ServerlessFunctionOwnerUser";
79
85
  import ServiceOwnerTeam from "../../../../Models/DatabaseModels/ServiceOwnerTeam";
80
86
  import ServiceOwnerUser from "../../../../Models/DatabaseModels/ServiceOwnerUser";
87
+ import ServiceLevelObjectiveOwnerTeam from "../../../../Models/DatabaseModels/ServiceLevelObjectiveOwnerTeam";
88
+ import ServiceLevelObjectiveOwnerUser from "../../../../Models/DatabaseModels/ServiceLevelObjectiveOwnerUser";
81
89
  import StatusPageOwnerTeam from "../../../../Models/DatabaseModels/StatusPageOwnerTeam";
82
90
  import StatusPageOwnerUser from "../../../../Models/DatabaseModels/StatusPageOwnerUser";
83
91
  import VMwareVCenterOwnerTeam from "../../../../Models/DatabaseModels/VMwareVCenterOwnerTeam";
@@ -336,6 +344,28 @@ const ENGINE_CASES: Array<EngineCase> = [
336
344
  }),
337
345
  prepare: noop,
338
346
  },
347
+ {
348
+ name: "SLO",
349
+ engine: ServiceLevelObjectiveOwnerRuleEngineService,
350
+ createHook: "applyRulesToServiceLevelObjective",
351
+ ruleService: ServiceLevelObjectiveOwnerRuleService,
352
+ rereadService: ServiceLevelObjectiveService,
353
+ ownerUserService: ServiceLevelObjectiveOwnerUserService,
354
+ ownerTeamService: ServiceLevelObjectiveOwnerTeamService,
355
+ ownerUserModel: ServiceLevelObjectiveOwnerUser,
356
+ ownerTeamModel: ServiceLevelObjectiveOwnerTeam,
357
+ resourceIdColumn: "serviceLevelObjectiveId",
358
+ namePatternField: "serviceLevelObjectiveNamePattern",
359
+ hasNotificationFlag: true,
360
+ addOwnersService: null,
361
+ mockFeed: feedMock({
362
+ linkService: ServiceLevelObjectiveService,
363
+ linkMethod: "getSloMarkdownLink",
364
+ feedService: ServiceLevelObjectiveFeedService,
365
+ feedMethod: "createServiceLevelObjectiveFeedItem",
366
+ }),
367
+ prepare: noop,
368
+ },
339
369
  {
340
370
  name: "status page",
341
371
  engine: StatusPageOwnerRuleEngineService,
@@ -0,0 +1,431 @@
1
+ import TeamService from "../../../Server/Services/TeamService";
2
+ import TeamMemberService from "../../../Server/Services/TeamMemberService";
3
+ import ProjectSCIMService from "../../../Server/Services/ProjectSCIMService";
4
+ import TeamPermissionService from "../../../Server/Services/TeamPermissionService";
5
+ import OnCallDutyPolicyTimeLogService from "../../../Server/Services/OnCallDutyPolicyTimeLogService";
6
+ import ProjectService from "../../../Server/Services/ProjectService";
7
+ import ModelPermission from "../../../Server/Types/Database/Permissions/Index";
8
+ import Errors from "../../../Server/Utils/Errors";
9
+ import ObjectID from "../../../Types/ObjectID";
10
+ import PositiveNumber from "../../../Types/PositiveNumber";
11
+ import Team from "../../../Models/DatabaseModels/Team";
12
+ import TeamMember from "../../../Models/DatabaseModels/TeamMember";
13
+ import FakeEnterpriseModule, {
14
+ createEditionStateCases,
15
+ createLicenseSnapshotWithStatus,
16
+ EditionStateCase,
17
+ installFakeEnterpriseModule,
18
+ uninstallEnterpriseModule,
19
+ } from "../Enterprise/FakeEnterpriseModule";
20
+ import logger from "../../../Server/Utils/Logger";
21
+ import { setTestBillingEnabled } from "../Enterprise/TestBillingFlag";
22
+ import { getJestSpyOn } from "../../Spy";
23
+ import {
24
+ afterEach,
25
+ beforeEach,
26
+ describe,
27
+ expect,
28
+ jest,
29
+ test,
30
+ } from "@jest/globals";
31
+
32
+ type SpyInstance = ReturnType<typeof getJestSpyOn>;
33
+
34
+ jest.mock("../../../Server/EnvironmentConfig", () => {
35
+ const billingFlag: typeof import("../Enterprise/TestBillingFlag") =
36
+ jest.requireActual(
37
+ "../Enterprise/TestBillingFlag",
38
+ ) as typeof import("../Enterprise/TestBillingFlag");
39
+
40
+ return billingFlag.withLiveBillingFlag(
41
+ jest.requireActual("../../../Server/EnvironmentConfig") as Record<
42
+ string,
43
+ unknown
44
+ >,
45
+ );
46
+ });
47
+
48
+ /*
49
+ * SCIM Push Groups team locks. While a project's SCIM configuration has Push
50
+ * Groups on, its identity provider owns team membership, so OneUptime refuses
51
+ * to create or delete teams, invite or remove members, and lifts the
52
+ * "at least one member" guard (the IdP may empty a team).
53
+ *
54
+ * The locks follow the RUNTIME state of SCIM
55
+ * (EnterpriseEdition.isFeatureActive(SCIM), through EditionEnforcement):
56
+ * - SCIM active (the Enterprise Edition with billing on, or with a license
57
+ * that covers SCIM - valid, grace, trial - or an unknown license state):
58
+ * locks ON, the identity provider owns the teams.
59
+ * - SCIM not active (the Community Edition, or an Enterprise install whose
60
+ * license lapsed): locks OFF. No SCIM endpoint answers the identity
61
+ * provider there, so a Push Groups setting left on would leave teams
62
+ * nobody can manage.
63
+ * A license change applies to the next write, without a restart.
64
+ *
65
+ * Billing and the edition are pinned in every test.
66
+ */
67
+
68
+ const PROJECT_ID: ObjectID = new ObjectID(
69
+ "11111111-1111-4111-8111-111111111111",
70
+ );
71
+ const TEAM_ID: ObjectID = new ObjectID("44444444-4444-4444-8444-444444444444");
72
+ const USER_ID: ObjectID = new ObjectID("22222222-2222-4222-8222-222222222222");
73
+ const INVITEE_ID: ObjectID = new ObjectID(
74
+ "55555555-5555-4555-8555-555555555555",
75
+ );
76
+
77
+ const EDITION_CASES: Array<EditionStateCase> = createEditionStateCases();
78
+
79
+ const toMatrix: (
80
+ cases: Array<EditionStateCase>,
81
+ ) => Array<[string, EditionStateCase]> = (
82
+ cases: Array<EditionStateCase>,
83
+ ): Array<[string, EditionStateCase]> => {
84
+ return cases.map(
85
+ (editionCase: EditionStateCase): [string, EditionStateCase] => {
86
+ return [editionCase.label, editionCase];
87
+ },
88
+ );
89
+ };
90
+
91
+ // Every state in which SCIM is active, so Push Groups locks the teams.
92
+ const LOCKED_MATRIX: Array<[string, EditionStateCase]> = toMatrix(
93
+ EDITION_CASES.filter((editionCase: EditionStateCase): boolean => {
94
+ return editionCase.isActive;
95
+ }),
96
+ );
97
+
98
+ // The Community Edition and every lapsed Enterprise license: not locked.
99
+ const UNLOCKED_MATRIX: Array<[string, EditionStateCase]> = toMatrix(
100
+ EDITION_CASES.filter((editionCase: EditionStateCase): boolean => {
101
+ return !editionCase.isActive;
102
+ }),
103
+ );
104
+
105
+ const userProps: () => Record<string, unknown> = (): Record<
106
+ string,
107
+ unknown
108
+ > => {
109
+ return { userId: USER_ID, tenantId: PROJECT_ID };
110
+ };
111
+
112
+ const buildTeam: () => Team = (): Team => {
113
+ const team: Team = new Team();
114
+ team._id = TEAM_ID.toString();
115
+ team.name = "Backend";
116
+ team.projectId = PROJECT_ID;
117
+ team.isTeamDeleteable = true;
118
+ return team;
119
+ };
120
+
121
+ const buildMember: (data: {
122
+ shouldHaveAtLeastOneMember: boolean;
123
+ }) => TeamMember = (data: {
124
+ shouldHaveAtLeastOneMember: boolean;
125
+ }): TeamMember => {
126
+ const member: TeamMember = new TeamMember();
127
+ member.userId = INVITEE_ID;
128
+ member.projectId = PROJECT_ID;
129
+ member.teamId = TEAM_ID;
130
+ member.hasAcceptedInvitation = true;
131
+
132
+ const team: Team = new Team();
133
+ team._id = TEAM_ID.toString();
134
+ team.shouldHaveAtLeastOneMember = data.shouldHaveAtLeastOneMember;
135
+ member.team = team;
136
+
137
+ return member;
138
+ };
139
+
140
+ let scimCount: SpyInstance;
141
+
142
+ describe("SCIM Push Groups team locks by edition", () => {
143
+ beforeEach(() => {
144
+ setTestBillingEnabled(false);
145
+ uninstallEnterpriseModule();
146
+
147
+ getJestSpyOn(logger, "warn").mockImplementation((): void => {
148
+ return undefined;
149
+ });
150
+ getJestSpyOn(logger, "info").mockImplementation((): void => {
151
+ return undefined;
152
+ });
153
+
154
+ // Push Groups is ON for the project in every test below.
155
+ scimCount = getJestSpyOn(ProjectSCIMService, "countBy").mockResolvedValue(
156
+ new PositiveNumber(1),
157
+ );
158
+ });
159
+
160
+ afterEach(() => {
161
+ uninstallEnterpriseModule();
162
+ setTestBillingEnabled(false);
163
+ jest.restoreAllMocks();
164
+ });
165
+
166
+ describe("TeamService: creating and deleting teams", () => {
167
+ const createTeam: (props: Record<string, unknown>) => Promise<unknown> = (
168
+ props: Record<string, unknown>,
169
+ ): Promise<unknown> => {
170
+ const team: Team = new Team();
171
+ team.projectId = PROJECT_ID;
172
+ team.name = "Backend";
173
+
174
+ return (TeamService as any).onBeforeCreate({
175
+ data: team,
176
+ props: props,
177
+ });
178
+ };
179
+
180
+ const deleteTeam: (props: Record<string, unknown>) => Promise<unknown> = (
181
+ props: Record<string, unknown>,
182
+ ): Promise<unknown> => {
183
+ return (TeamService as any).onBeforeDelete({
184
+ query: { _id: TEAM_ID },
185
+ props: props,
186
+ });
187
+ };
188
+
189
+ let memberDelete: SpyInstance;
190
+
191
+ beforeEach(() => {
192
+ getJestSpyOn(TeamService, "findBy").mockResolvedValue([buildTeam()]);
193
+ getJestSpyOn(
194
+ ModelPermission,
195
+ "checkDeleteQueryPermission",
196
+ ).mockImplementation(
197
+ async (_modelType: unknown, query: unknown): Promise<unknown> => {
198
+ return query;
199
+ },
200
+ );
201
+ memberDelete = getJestSpyOn(
202
+ TeamMemberService,
203
+ "deleteBy",
204
+ ).mockResolvedValue(0);
205
+ });
206
+
207
+ test.each(LOCKED_MATRIX)(
208
+ "SCIM active (%s): creating a team is locked",
209
+ async (_label: string, editionCase: EditionStateCase) => {
210
+ editionCase.apply();
211
+
212
+ await expect(createTeam(userProps())).rejects.toThrow(
213
+ "Cannot create teams while SCIM Push Groups is enabled for this project",
214
+ );
215
+ },
216
+ );
217
+
218
+ test.each(LOCKED_MATRIX)(
219
+ "SCIM active (%s): deleting a team is locked before any member is removed",
220
+ async (_label: string, editionCase: EditionStateCase) => {
221
+ editionCase.apply();
222
+
223
+ await expect(deleteTeam(userProps())).rejects.toThrow(
224
+ "Cannot delete teams while SCIM Push Groups is enabled for this project",
225
+ );
226
+ expect(memberDelete).not.toHaveBeenCalled();
227
+ },
228
+ );
229
+
230
+ test.each(UNLOCKED_MATRIX)(
231
+ "SCIM not active (%s): creating a team is not locked and SCIM is not consulted",
232
+ async (_label: string, editionCase: EditionStateCase) => {
233
+ editionCase.apply();
234
+
235
+ await expect(createTeam(userProps())).resolves.toEqual(
236
+ expect.objectContaining({ carryForward: null }),
237
+ );
238
+ expect(scimCount).not.toHaveBeenCalled();
239
+ },
240
+ );
241
+
242
+ test.each(UNLOCKED_MATRIX)(
243
+ "SCIM not active (%s): deleting a team is not locked",
244
+ async (_label: string, editionCase: EditionStateCase) => {
245
+ editionCase.apply();
246
+
247
+ await expect(deleteTeam(userProps())).resolves.toEqual(
248
+ expect.objectContaining({ carryForward: null }),
249
+ );
250
+ expect(scimCount).not.toHaveBeenCalled();
251
+ expect(memberDelete).toHaveBeenCalledTimes(1);
252
+ },
253
+ );
254
+
255
+ test("internal root writes are never locked, on either edition", async () => {
256
+ installFakeEnterpriseModule();
257
+
258
+ await expect(createTeam({ isRoot: true })).resolves.toBeDefined();
259
+ await expect(deleteTeam({ isRoot: true })).resolves.toBeDefined();
260
+ expect(scimCount).not.toHaveBeenCalled();
261
+ });
262
+
263
+ test("with Push Groups off the Enterprise Edition does not lock either", async () => {
264
+ installFakeEnterpriseModule();
265
+ scimCount.mockResolvedValue(new PositiveNumber(0));
266
+
267
+ await expect(createTeam(userProps())).resolves.toBeDefined();
268
+ await expect(deleteTeam(userProps())).resolves.toBeDefined();
269
+ expect(scimCount).toHaveBeenCalled();
270
+ });
271
+ });
272
+
273
+ describe("TeamMemberService: inviting and removing members", () => {
274
+ const inviteMember: (props: Record<string, unknown>) => Promise<unknown> = (
275
+ props: Record<string, unknown>,
276
+ ): Promise<unknown> => {
277
+ const member: TeamMember = new TeamMember();
278
+ member.projectId = PROJECT_ID;
279
+ member.teamId = TEAM_ID;
280
+ member.userId = INVITEE_ID;
281
+
282
+ return (TeamMemberService as any).onBeforeCreate({
283
+ data: member,
284
+ props: props,
285
+ });
286
+ };
287
+
288
+ const removeMember: (props: Record<string, unknown>) => Promise<unknown> = (
289
+ props: Record<string, unknown>,
290
+ ): Promise<unknown> => {
291
+ return (TeamMemberService as any).onBeforeDelete({
292
+ query: { teamId: TEAM_ID, userId: INVITEE_ID },
293
+ props: props,
294
+ });
295
+ };
296
+
297
+ let memberLookup: SpyInstance;
298
+
299
+ beforeEach(() => {
300
+ getJestSpyOn(TeamService, "findOneBy").mockResolvedValue(buildTeam());
301
+ getJestSpyOn(
302
+ TeamPermissionService,
303
+ "assertCanGrantTeamPermissions",
304
+ ).mockResolvedValue(undefined);
305
+ // "Is this user already invited?" - no.
306
+ getJestSpyOn(TeamMemberService, "findOneBy").mockResolvedValue(null);
307
+ memberLookup = getJestSpyOn(
308
+ TeamMemberService,
309
+ "findBy",
310
+ ).mockResolvedValue([buildMember({ shouldHaveAtLeastOneMember: false })]);
311
+ getJestSpyOn(
312
+ OnCallDutyPolicyTimeLogService,
313
+ "endTimeForUser",
314
+ ).mockResolvedValue(undefined);
315
+ // The billing seat check (billing on) finds no seat limit.
316
+ getJestSpyOn(ProjectService, "findOneById").mockResolvedValue(null);
317
+ });
318
+
319
+ test.each(LOCKED_MATRIX)(
320
+ "SCIM active (%s): inviting a member is locked",
321
+ async (_label: string, editionCase: EditionStateCase) => {
322
+ editionCase.apply();
323
+
324
+ await expect(inviteMember(userProps())).rejects.toThrow(
325
+ "Cannot invite team members while SCIM Push Groups is enabled for this project",
326
+ );
327
+ },
328
+ );
329
+
330
+ test.each(LOCKED_MATRIX)(
331
+ "SCIM active (%s): removing a member is locked",
332
+ async (_label: string, editionCase: EditionStateCase) => {
333
+ editionCase.apply();
334
+
335
+ await expect(removeMember(userProps())).rejects.toThrow(
336
+ "Cannot delete team members while SCIM Push Groups is enabled for this project",
337
+ );
338
+ },
339
+ );
340
+
341
+ test.each(UNLOCKED_MATRIX)(
342
+ "SCIM not active (%s): inviting a member is not locked",
343
+ async (_label: string, editionCase: EditionStateCase) => {
344
+ editionCase.apply();
345
+
346
+ await expect(inviteMember(userProps())).resolves.toEqual(
347
+ expect.objectContaining({ carryForward: null }),
348
+ );
349
+ expect(scimCount).not.toHaveBeenCalled();
350
+ },
351
+ );
352
+
353
+ test.each(UNLOCKED_MATRIX)(
354
+ "SCIM not active (%s): removing a member is not locked",
355
+ async (_label: string, editionCase: EditionStateCase) => {
356
+ editionCase.apply();
357
+
358
+ await expect(removeMember(userProps())).resolves.toEqual(
359
+ expect.objectContaining({ deleteBy: expect.anything() }),
360
+ );
361
+ expect(scimCount).not.toHaveBeenCalled();
362
+ },
363
+ );
364
+
365
+ describe("the one-member guard", () => {
366
+ beforeEach(() => {
367
+ memberLookup.mockResolvedValue([
368
+ buildMember({ shouldHaveAtLeastOneMember: true }),
369
+ ]);
370
+ // The member being removed is the team's last accepted member.
371
+ getJestSpyOn(TeamMemberService, "countBy").mockResolvedValue(
372
+ new PositiveNumber(1),
373
+ );
374
+ });
375
+
376
+ test("is lifted while SCIM is active and Push Groups owns the team (the IdP may empty it)", async () => {
377
+ installFakeEnterpriseModule({
378
+ snapshot: createLicenseSnapshotWithStatus("grace"),
379
+ });
380
+
381
+ await expect(removeMember({ isRoot: true })).resolves.toBeDefined();
382
+ });
383
+
384
+ test("applies again once the license lapsed, because no IdP manages the team any more", async () => {
385
+ installFakeEnterpriseModule({
386
+ snapshot: createLicenseSnapshotWithStatus("expired"),
387
+ });
388
+
389
+ await expect(removeMember({ isRoot: true })).rejects.toThrow(
390
+ Errors.TeamMemberService.ONE_MEMBER_REQUIRED,
391
+ );
392
+ expect(scimCount).not.toHaveBeenCalled();
393
+ });
394
+
395
+ test("applies on the Community Edition, where no IdP manages the team", async () => {
396
+ await expect(removeMember({ isRoot: true })).rejects.toThrow(
397
+ Errors.TeamMemberService.ONE_MEMBER_REQUIRED,
398
+ );
399
+ expect(scimCount).not.toHaveBeenCalled();
400
+ });
401
+ });
402
+
403
+ test("internal root invites are never locked", async () => {
404
+ installFakeEnterpriseModule();
405
+
406
+ await expect(inviteMember({ isRoot: true })).resolves.toBeDefined();
407
+ });
408
+
409
+ test("the lock follows the license at write time: relaxed while lapsed, back after renewal", async () => {
410
+ const fake: FakeEnterpriseModule = installFakeEnterpriseModule({
411
+ snapshot: createLicenseSnapshotWithStatus("valid"),
412
+ });
413
+
414
+ await expect(inviteMember(userProps())).rejects.toThrow(
415
+ "Cannot invite team members while SCIM Push Groups is enabled for this project",
416
+ );
417
+
418
+ fake.setSnapshot(createLicenseSnapshotWithStatus("missing"));
419
+
420
+ await expect(inviteMember(userProps())).resolves.toEqual(
421
+ expect.objectContaining({ carryForward: null }),
422
+ );
423
+
424
+ fake.setSnapshot(createLicenseSnapshotWithStatus("valid"));
425
+
426
+ await expect(inviteMember(userProps())).rejects.toThrow(
427
+ "Cannot invite team members while SCIM Push Groups is enabled for this project",
428
+ );
429
+ });
430
+ });
431
+ });