@oneuptime/common 13.0.8 → 14.0.0

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 (333) hide show
  1. package/Models/AnalyticsModels/AuditLog.ts +23 -15
  2. package/Models/DatabaseModels/GlobalConfig.ts +24 -0
  3. package/Models/DatabaseModels/Monitor.ts +3 -2
  4. package/Models/DatabaseModels/MonitorTemplate.ts +2 -1
  5. package/Scripts/generate-service-worker.js +65 -4
  6. package/Server/API/BaseAPI.ts +26 -5
  7. package/Server/API/GlobalConfigAPI.ts +228 -462
  8. package/Server/API/ProjectOIDC.ts +25 -16
  9. package/Server/API/ProjectSSO.ts +24 -16
  10. package/Server/API/StatusPageAPI.ts +100 -42
  11. package/Server/API/TeamMemberAPI.ts +10 -1
  12. package/Server/Enterprise/EnterpriseEdition.ts +649 -0
  13. package/Server/Enterprise/EnterpriseFeature.ts +48 -0
  14. package/Server/Enterprise/EnterpriseLicenseSnapshot.ts +192 -0
  15. package/Server/Enterprise/EnterpriseServerModule.ts +233 -0
  16. package/Server/EnvironmentConfig.ts +147 -2
  17. package/Server/Infrastructure/Postgres/SchemaMigrations/1793900000000-AddEnterpriseEditionFirstSeenAt.ts +25 -0
  18. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +2 -0
  19. package/Server/Middleware/UserAuthorization.ts +38 -16
  20. package/Server/Services/AuditLogService.ts +84 -1079
  21. package/Server/Services/EnterpriseLicenseService.ts +38 -0
  22. package/Server/Services/GlobalConfigService.ts +80 -1
  23. package/Server/Services/MonitorProbeService.ts +116 -20
  24. package/Server/Services/MonitorService.ts +56 -4
  25. package/Server/Services/MonitorStatusTimelineService.ts +284 -0
  26. package/Server/Services/MonitorTemplateService.ts +26 -0
  27. package/Server/Services/ProjectService.ts +284 -0
  28. package/Server/Services/RumSessionPinService.ts +25 -6
  29. package/Server/Services/StatusPagePrivateUserService.ts +7 -3
  30. package/Server/Services/StatusPageService.ts +78 -1
  31. package/Server/Services/TeamMemberService.ts +11 -0
  32. package/Server/Services/TeamService.ts +10 -0
  33. package/Server/Services/UserService.ts +10 -17
  34. package/Server/Types/Database/Permissions/CreatePermission.ts +15 -0
  35. package/Server/Types/Database/Permissions/EditionPermission.ts +208 -18
  36. package/Server/Types/Database/Permissions/TablePermission.ts +10 -3
  37. package/Server/Types/Database/Permissions/UpdatePermission.ts +29 -0
  38. package/Server/Types/Markdown.ts +41 -0
  39. package/Server/Utils/CommunityEditionSsoReport.ts +361 -0
  40. package/Server/Utils/EditionEnforcement.ts +233 -0
  41. package/Server/Utils/FrontendEnvironment.ts +41 -2
  42. package/Server/Utils/InstanceHealth/RedisHealth.ts +12 -277
  43. package/Server/Utils/Monitor/AffectedResourceList.ts +190 -0
  44. package/Server/Utils/Monitor/Criteria/EvaluateOverTime.ts +10 -1
  45. package/Server/Utils/Monitor/MonitorCriteriaEvaluator.ts +543 -333
  46. package/Server/Utils/Monitor/MonitoringIntervalValidator.ts +116 -0
  47. package/Server/Utils/Workspace/Slack/Slack.ts +423 -10
  48. package/Tests/App/Accounts/LoginPasskey.test.tsx +18 -0
  49. package/Tests/App/Accounts/LoginSsoEdition.test.tsx +616 -0
  50. package/Tests/App/AdminDashboard/AdminAuthenticationSsoEdition.test.tsx +217 -0
  51. package/Tests/App/AdminDashboard/AdminEnterprisePluginPage.test.tsx +357 -0
  52. package/Tests/App/AdminDashboard/EnterpriseLicensesShell.test.tsx +214 -0
  53. package/Tests/App/AdminDashboard/GlobalSSOEnterpriseShells.test.tsx +271 -0
  54. package/Tests/App/AdminDashboard/HealthShells.test.tsx +659 -0
  55. package/Tests/App/Dashboard/AuditLogsAndComplianceShells.test.tsx +572 -0
  56. package/Tests/App/Dashboard/EnterpriseFeatureUpgrade.test.tsx +547 -0
  57. package/Tests/App/Dashboard/EnterprisePluginPage.test.tsx +667 -0
  58. package/Tests/App/Dashboard/IdentityEnterpriseShells.test.tsx +319 -0
  59. package/Tests/App/Dashboard/OnboardingSsoEmptyState.test.tsx +185 -0
  60. package/Tests/App/Dashboard/SecurityEventConnectionDiagnostics.test.tsx +45 -9
  61. package/Tests/App/Dashboard/SecurityEventDetailPanel.test.tsx +399 -0
  62. package/Tests/App/Dashboard/SecurityEventListRow.test.tsx +214 -0
  63. package/Tests/App/Dashboard/SecurityEventsEmptyState.test.tsx +1 -83
  64. package/Tests/App/Dashboard/SecurityEventsNavTabs.test.tsx +248 -0
  65. package/Tests/App/Dashboard/SecurityEventsViewer.test.tsx +1203 -0
  66. package/Tests/App/Dashboard/UserEmailCallSites.test.tsx +11 -91
  67. package/Tests/App/StatusPage/StatusPageSsoEmptyState.test.tsx +319 -0
  68. package/Tests/Helpers/RefreshAwareApiScan.ts +757 -0
  69. package/Tests/Helpers/TenantScopedRequestScan.ts +515 -0
  70. package/Tests/Scripts/GenerateServiceWorker.test.ts +931 -0
  71. package/Tests/Server/API/BaseAPICreateItemDoesNotMutateModel.test.ts +130 -0
  72. package/Tests/Server/API/GlobalConfigLicense.test.ts +742 -497
  73. package/Tests/Server/API/OnCallReadinessAPI.test.ts +35 -909
  74. package/Tests/Server/API/SsoProviderListingsEdition.test.ts +432 -0
  75. package/Tests/Server/API/TeamMemberLeaveScimLockEdition.test.ts +252 -0
  76. package/Tests/Server/Enterprise/EnterpriseEdition.test.ts +824 -0
  77. package/Tests/Server/Enterprise/EnterpriseFeatureActive.test.ts +643 -0
  78. package/Tests/Server/Enterprise/EnterpriseLicenseSnapshot.test.ts +294 -0
  79. package/Tests/Server/Enterprise/EnterpriseModelFeatureMap.test.ts +93 -0
  80. package/Tests/Server/Enterprise/EnterpriseOnlyModulesLiveInEe.test.ts +582 -0
  81. package/Tests/Server/Enterprise/EnterpriseServerModule.test.ts +247 -0
  82. package/Tests/Server/Enterprise/FakeEnterpriseModule.ts +502 -0
  83. package/Tests/Server/Enterprise/TestBillingFlag.ts +70 -0
  84. package/Tests/Server/EnvironmentConfigEnterpriseEdition.test.ts +314 -0
  85. package/Tests/Server/Infrastructure/ContainerBootConfiguration.test.ts +289 -0
  86. package/Tests/Server/Infrastructure/E2EClickHouseFixtureAccess.test.ts +5 -1
  87. package/Tests/Server/Middleware/UserAuthorization.test.ts +37 -2
  88. package/Tests/Server/Middleware/UserAuthorizationEditionEnforcement.test.ts +516 -0
  89. package/Tests/Server/Services/AuditLogService.test.ts +460 -990
  90. package/Tests/Server/Services/CreateAndReadResponsesKeepIds.test.ts +263 -0
  91. package/Tests/Server/Services/EnterpriseLicenseServiceKeyGeneration.test.ts +151 -0
  92. package/Tests/Server/Services/GlobalConfigServiceLicenseColumns.test.ts +357 -0
  93. package/Tests/Server/Services/MonitorDestinationInfoIPv6.test.ts +101 -0
  94. package/Tests/Server/Services/MonitorProbeServiceIntervalScheduling.test.ts +333 -0
  95. package/Tests/Server/Services/MonitorStatusTimelineDailyAggregates.test.ts +303 -0
  96. package/Tests/Server/Services/ProjectServiceAuditLogLicense.test.ts +701 -0
  97. package/Tests/Server/Services/ProjectServiceAuditLogSettingsCache.test.ts +31 -35
  98. package/Tests/Server/Services/ScimPushGroupsTeamLocksEdition.test.ts +431 -0
  99. package/Tests/Server/Services/SsoRequirementReadMasking.test.ts +419 -0
  100. package/Tests/Server/Services/SsoRequirementWriteGuard.test.ts +769 -0
  101. package/Tests/Server/Services/StatusPagePrivateUserInvitationPolicy.test.ts +94 -0
  102. package/Tests/Server/Services/UserAuthenticationService.test.ts +35 -0
  103. package/Tests/Server/Services/UserServiceSeatLimit.test.ts +94 -56
  104. package/Tests/Server/Types/Database/Permissions/EditionPermission.test.ts +1823 -0
  105. package/Tests/Server/Types/Markdown.test.ts +181 -0
  106. package/Tests/Server/Utils/CommunityEditionSsoReport.test.ts +565 -0
  107. package/Tests/Server/Utils/EditionEnforcement.test.ts +303 -0
  108. package/Tests/Server/Utils/FrontendEnvironment.test.ts +367 -0
  109. package/Tests/Server/Utils/InstanceHealth/RedisHealth.test.ts +38 -418
  110. package/Tests/Server/Utils/Monitor/AffectedResourceList.test.ts +518 -0
  111. package/Tests/Server/Utils/Monitor/Criteria/EvaluateOverTime.test.ts +24 -4
  112. package/Tests/Server/Utils/Monitor/MonitorCriteriaEvaluator.test.ts +934 -96
  113. package/Tests/Server/Utils/Monitor/MonitoringIntervalValidator.test.ts +188 -0
  114. package/Tests/Server/Utils/Workspace/Slack/SlackMarkdownSectionSplit.test.ts +1209 -0
  115. package/Tests/Types/API/HostnameFromAuthority.test.ts +20 -10
  116. package/Tests/Types/API/HostnameIPv6.test.ts +149 -0
  117. package/Tests/Types/Database/CanonicalModelInstance.test.ts +190 -0
  118. package/Tests/UI/Components/EditionLabelLapseCopy.ts +104 -0
  119. package/Tests/UI/Components/EditionLabelLicenseManagerWiring.test.tsx +254 -0
  120. package/Tests/UI/Components/EditionLabelLicenseRefresh.test.tsx +84 -178
  121. package/Tests/UI/Components/EditionLabelLicenseStatus.test.tsx +1586 -0
  122. package/Tests/UI/Components/EditionLabelLicenseWritesGuard.test.tsx +157 -0
  123. package/Tests/UI/Components/Graphs/DayUptimeGraph.test.tsx +49 -2
  124. package/Tests/UI/Components/MarkdownConverters.test.ts +684 -0
  125. package/Tests/UI/Components/ModelListEmptyState.test.tsx +289 -0
  126. package/Tests/UI/Components/TelemetryViewer/TelemetryViewerEmptyContent.test.tsx +131 -0
  127. package/Tests/UI/EsbuildEnterpriseAlias.test.ts +1127 -0
  128. package/Tests/Utils/HostAddressUtil.test.ts +138 -0
  129. package/Tests/Utils/Monitor/MonitorDestinationUtil.test.ts +313 -0
  130. package/Tests/Utils/Monitor/MonitoringIntervalUtil.test.ts +304 -0
  131. package/Tests/Utils/StatusPage/UptimeDailyAggregateUtil.test.ts +248 -0
  132. package/Types/API/Hostname.ts +63 -16
  133. package/Types/Database/AccessControl/ColumnAccessControl.ts +19 -7
  134. package/Types/Database/AccessControl/ColumnBillingAccessControl.ts +19 -7
  135. package/Types/Database/AccessControl/OwnerOnlyColumn.ts +15 -6
  136. package/Types/Database/CanonicalModelInstance.ts +102 -0
  137. package/Types/Database/TableColumn.ts +20 -6
  138. package/Types/EnterpriseLicense/EnterpriseLicensePeriods.ts +29 -0
  139. package/Types/IP/IPv6.ts +6 -1
  140. package/Types/Monitor/MonitorStep.ts +6 -1
  141. package/Types/Monitor/ProxmoxAlertTemplates.ts +1 -1
  142. package/Types/StatusPage/UptimeDailyAggregate.ts +110 -0
  143. package/UI/Components/EditionLabel/EditionLabel.tsx +796 -1195
  144. package/UI/Components/EditionLabel/LicenseManager.ts +119 -0
  145. package/UI/Components/Graphs/DayUptimeGraph.tsx +123 -15
  146. package/UI/Components/Markdown.tsx/MarkdownConverters.ts +0 -0
  147. package/UI/Components/ModelList/ModelList.tsx +11 -1
  148. package/UI/Components/MonitorGraphs/Uptime.tsx +69 -0
  149. package/UI/Components/TelemetryViewer/TelemetryViewer.tsx +28 -12
  150. package/UI/esbuild-enterprise.js +263 -0
  151. package/Utils/EnterpriseLicense/EnterpriseLicenseUsage.ts +7 -2
  152. package/Utils/HostAddressUtil.ts +94 -0
  153. package/Utils/Monitor/MonitorDestinationUtil.ts +157 -0
  154. package/Utils/Monitor/MonitoringIntervalUtil.ts +436 -0
  155. package/Utils/StatusPage/UptimeDailyAggregateUtil.ts +192 -0
  156. package/build/dist/Models/AnalyticsModels/AuditLog.js +23 -15
  157. package/build/dist/Models/AnalyticsModels/AuditLog.js.map +1 -1
  158. package/build/dist/Models/DatabaseModels/GlobalConfig.js +25 -0
  159. package/build/dist/Models/DatabaseModels/GlobalConfig.js.map +1 -1
  160. package/build/dist/Models/DatabaseModels/Monitor.js +2 -2
  161. package/build/dist/Models/DatabaseModels/Monitor.js.map +1 -1
  162. package/build/dist/Models/DatabaseModels/MonitorTemplate.js +2 -1
  163. package/build/dist/Models/DatabaseModels/MonitorTemplate.js.map +1 -1
  164. package/build/dist/Server/API/BaseAPI.js +26 -5
  165. package/build/dist/Server/API/BaseAPI.js.map +1 -1
  166. package/build/dist/Server/API/GlobalConfigAPI.js +148 -344
  167. package/build/dist/Server/API/GlobalConfigAPI.js.map +1 -1
  168. package/build/dist/Server/API/ProjectOIDC.js +24 -16
  169. package/build/dist/Server/API/ProjectOIDC.js.map +1 -1
  170. package/build/dist/Server/API/ProjectSSO.js +24 -16
  171. package/build/dist/Server/API/ProjectSSO.js.map +1 -1
  172. package/build/dist/Server/API/StatusPageAPI.js +93 -43
  173. package/build/dist/Server/API/StatusPageAPI.js.map +1 -1
  174. package/build/dist/Server/API/TeamMemberAPI.js +8 -1
  175. package/build/dist/Server/API/TeamMemberAPI.js.map +1 -1
  176. package/build/dist/Server/Enterprise/EnterpriseEdition.js +466 -0
  177. package/build/dist/Server/Enterprise/EnterpriseEdition.js.map +1 -0
  178. package/build/dist/Server/Enterprise/EnterpriseFeature.js +39 -0
  179. package/build/dist/Server/Enterprise/EnterpriseFeature.js.map +1 -0
  180. package/build/dist/Server/Enterprise/EnterpriseLicenseSnapshot.js +70 -0
  181. package/build/dist/Server/Enterprise/EnterpriseLicenseSnapshot.js.map +1 -0
  182. package/build/dist/Server/Enterprise/EnterpriseServerModule.js +84 -0
  183. package/build/dist/Server/Enterprise/EnterpriseServerModule.js.map +1 -0
  184. package/build/dist/Server/EnvironmentConfig.js +84 -2
  185. package/build/dist/Server/EnvironmentConfig.js.map +1 -1
  186. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1793900000000-AddEnterpriseEditionFirstSeenAt.js +18 -0
  187. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1793900000000-AddEnterpriseEditionFirstSeenAt.js.map +1 -0
  188. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +2 -0
  189. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  190. package/build/dist/Server/Middleware/UserAuthorization.js +30 -11
  191. package/build/dist/Server/Middleware/UserAuthorization.js.map +1 -1
  192. package/build/dist/Server/Services/AuditLogService.js +71 -740
  193. package/build/dist/Server/Services/AuditLogService.js.map +1 -1
  194. package/build/dist/Server/Services/EnterpriseLicenseService.js +34 -0
  195. package/build/dist/Server/Services/EnterpriseLicenseService.js.map +1 -1
  196. package/build/dist/Server/Services/GlobalConfigService.js +63 -0
  197. package/build/dist/Server/Services/GlobalConfigService.js.map +1 -1
  198. package/build/dist/Server/Services/MonitorProbeService.js +90 -17
  199. package/build/dist/Server/Services/MonitorProbeService.js.map +1 -1
  200. package/build/dist/Server/Services/MonitorService.js +45 -4
  201. package/build/dist/Server/Services/MonitorService.js.map +1 -1
  202. package/build/dist/Server/Services/MonitorStatusTimelineService.js +242 -0
  203. package/build/dist/Server/Services/MonitorStatusTimelineService.js.map +1 -1
  204. package/build/dist/Server/Services/MonitorTemplateService.js +16 -0
  205. package/build/dist/Server/Services/MonitorTemplateService.js.map +1 -1
  206. package/build/dist/Server/Services/ProjectService.js +214 -0
  207. package/build/dist/Server/Services/ProjectService.js.map +1 -1
  208. package/build/dist/Server/Services/RumSessionPinService.js +24 -6
  209. package/build/dist/Server/Services/RumSessionPinService.js.map +1 -1
  210. package/build/dist/Server/Services/StatusPagePrivateUserService.js +7 -3
  211. package/build/dist/Server/Services/StatusPagePrivateUserService.js.map +1 -1
  212. package/build/dist/Server/Services/StatusPageService.js +71 -0
  213. package/build/dist/Server/Services/StatusPageService.js.map +1 -1
  214. package/build/dist/Server/Services/TeamMemberService.js +10 -0
  215. package/build/dist/Server/Services/TeamMemberService.js.map +1 -1
  216. package/build/dist/Server/Services/TeamService.js +9 -0
  217. package/build/dist/Server/Services/TeamService.js.map +1 -1
  218. package/build/dist/Server/Services/UserService.js +10 -16
  219. package/build/dist/Server/Services/UserService.js.map +1 -1
  220. package/build/dist/Server/Types/Database/Permissions/CreatePermission.js +10 -0
  221. package/build/dist/Server/Types/Database/Permissions/CreatePermission.js.map +1 -1
  222. package/build/dist/Server/Types/Database/Permissions/EditionPermission.js +154 -14
  223. package/build/dist/Server/Types/Database/Permissions/EditionPermission.js.map +1 -1
  224. package/build/dist/Server/Types/Database/Permissions/TablePermission.js +10 -3
  225. package/build/dist/Server/Types/Database/Permissions/TablePermission.js.map +1 -1
  226. package/build/dist/Server/Types/Database/Permissions/UpdatePermission.js +17 -0
  227. package/build/dist/Server/Types/Database/Permissions/UpdatePermission.js.map +1 -1
  228. package/build/dist/Server/Types/Markdown.js +31 -0
  229. package/build/dist/Server/Types/Markdown.js.map +1 -1
  230. package/build/dist/Server/Utils/CommunityEditionSsoReport.js +223 -0
  231. package/build/dist/Server/Utils/CommunityEditionSsoReport.js.map +1 -0
  232. package/build/dist/Server/Utils/EditionEnforcement.js +187 -0
  233. package/build/dist/Server/Utils/EditionEnforcement.js.map +1 -0
  234. package/build/dist/Server/Utils/FrontendEnvironment.js +31 -2
  235. package/build/dist/Server/Utils/FrontendEnvironment.js.map +1 -1
  236. package/build/dist/Server/Utils/InstanceHealth/RedisHealth.js +6 -193
  237. package/build/dist/Server/Utils/InstanceHealth/RedisHealth.js.map +1 -1
  238. package/build/dist/Server/Utils/Monitor/AffectedResourceList.js +96 -0
  239. package/build/dist/Server/Utils/Monitor/AffectedResourceList.js.map +1 -0
  240. package/build/dist/Server/Utils/Monitor/Criteria/EvaluateOverTime.js +8 -1
  241. package/build/dist/Server/Utils/Monitor/Criteria/EvaluateOverTime.js.map +1 -1
  242. package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js +449 -261
  243. package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js.map +1 -1
  244. package/build/dist/Server/Utils/Monitor/MonitoringIntervalValidator.js +88 -0
  245. package/build/dist/Server/Utils/Monitor/MonitoringIntervalValidator.js.map +1 -0
  246. package/build/dist/Server/Utils/Workspace/Slack/Slack.js +331 -11
  247. package/build/dist/Server/Utils/Workspace/Slack/Slack.js.map +1 -1
  248. package/build/dist/Types/API/Hostname.js +59 -11
  249. package/build/dist/Types/API/Hostname.js.map +1 -1
  250. package/build/dist/Types/Database/AccessControl/ColumnAccessControl.js +19 -7
  251. package/build/dist/Types/Database/AccessControl/ColumnAccessControl.js.map +1 -1
  252. package/build/dist/Types/Database/AccessControl/ColumnBillingAccessControl.js +19 -7
  253. package/build/dist/Types/Database/AccessControl/ColumnBillingAccessControl.js.map +1 -1
  254. package/build/dist/Types/Database/AccessControl/OwnerOnlyColumn.js +13 -6
  255. package/build/dist/Types/Database/AccessControl/OwnerOnlyColumn.js.map +1 -1
  256. package/build/dist/Types/Database/CanonicalModelInstance.js +88 -0
  257. package/build/dist/Types/Database/CanonicalModelInstance.js.map +1 -0
  258. package/build/dist/Types/Database/TableColumn.js +19 -6
  259. package/build/dist/Types/Database/TableColumn.js.map +1 -1
  260. package/build/dist/Types/EnterpriseLicense/EnterpriseLicensePeriods.js +28 -0
  261. package/build/dist/Types/EnterpriseLicense/EnterpriseLicensePeriods.js.map +1 -0
  262. package/build/dist/Types/IP/IPv6.js +6 -1
  263. package/build/dist/Types/IP/IPv6.js.map +1 -1
  264. package/build/dist/Types/Monitor/MonitorStep.js +5 -0
  265. package/build/dist/Types/Monitor/MonitorStep.js.map +1 -1
  266. package/build/dist/Types/Monitor/ProxmoxAlertTemplates.js +1 -1
  267. package/build/dist/Types/StatusPage/UptimeDailyAggregate.js +32 -0
  268. package/build/dist/Types/StatusPage/UptimeDailyAggregate.js.map +1 -0
  269. package/build/dist/UI/Components/EditionLabel/EditionLabel.js +414 -585
  270. package/build/dist/UI/Components/EditionLabel/EditionLabel.js.map +1 -1
  271. package/build/dist/UI/Components/EditionLabel/LicenseManager.js +2 -0
  272. package/build/dist/UI/Components/EditionLabel/LicenseManager.js.map +1 -0
  273. package/build/dist/UI/Components/Graphs/DayUptimeGraph.js +90 -17
  274. package/build/dist/UI/Components/Graphs/DayUptimeGraph.js.map +1 -1
  275. package/build/dist/UI/Components/Markdown.tsx/MarkdownConverters.js +0 -0
  276. package/build/dist/UI/Components/Markdown.tsx/MarkdownConverters.js.map +1 -1
  277. package/build/dist/UI/Components/ModelList/ModelList.js +4 -1
  278. package/build/dist/UI/Components/ModelList/ModelList.js.map +1 -1
  279. package/build/dist/UI/Components/MonitorGraphs/Uptime.js +42 -1
  280. package/build/dist/UI/Components/MonitorGraphs/Uptime.js.map +1 -1
  281. package/build/dist/UI/Components/TelemetryViewer/TelemetryViewer.js +2 -2
  282. package/build/dist/UI/Components/TelemetryViewer/TelemetryViewer.js.map +1 -1
  283. package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseUsage.js +6 -2
  284. package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseUsage.js.map +1 -1
  285. package/build/dist/Utils/HostAddressUtil.js +80 -0
  286. package/build/dist/Utils/HostAddressUtil.js.map +1 -0
  287. package/build/dist/Utils/Monitor/MonitorDestinationUtil.js +127 -0
  288. package/build/dist/Utils/Monitor/MonitorDestinationUtil.js.map +1 -0
  289. package/build/dist/Utils/Monitor/MonitoringIntervalUtil.js +374 -0
  290. package/build/dist/Utils/Monitor/MonitoringIntervalUtil.js.map +1 -0
  291. package/build/dist/Utils/StatusPage/UptimeDailyAggregateUtil.js +148 -0
  292. package/build/dist/Utils/StatusPage/UptimeDailyAggregateUtil.js.map +1 -0
  293. package/jest.config.json +3 -1
  294. package/package.json +1 -1
  295. package/test-setup.sh +103 -34
  296. package/tsconfig.json +13 -0
  297. package/Server/API/EnterpriseLicenseAPI.ts +0 -925
  298. package/Server/API/TeamComplianceAPI.ts +0 -158
  299. package/Server/Middleware/SCIMAuthorization.ts +0 -141
  300. package/Server/Services/TeamComplianceService.ts +0 -733
  301. package/Server/Utils/EnterpriseLicense/EnterpriseLicenseSeatUtil.ts +0 -186
  302. package/Server/Utils/InstanceHealth/PostgresHealth.ts +0 -286
  303. package/Tests/App/AdminDashboard/EnterpriseLicenseInstanceActivity.test.tsx +0 -451
  304. package/Tests/App/Dashboard/AuditLogsTable.test.tsx +0 -598
  305. package/Tests/App/Dashboard/SecurityEventsExplorer.test.tsx +0 -761
  306. package/Tests/App/Dashboard/SecurityEventsSideMenu.test.tsx +0 -247
  307. package/Tests/App/Dashboard/SecurityEventsTableColumns.test.tsx +0 -382
  308. package/Tests/App/Dashboard/SecurityEventsVolumeChart.test.tsx +0 -321
  309. package/Tests/Server/API/EnterpriseLicenseReportUserCount.test.ts +0 -1851
  310. package/Tests/Server/Middleware/SCIMAuthorization.test.ts +0 -525
  311. package/Tests/Server/Services/TeamComplianceServiceBehaviour.test.ts +0 -1845
  312. package/Tests/Server/Utils/EnterpriseLicense/EnterpriseLicenseSeatUtil.test.ts +0 -495
  313. package/Tests/Server/Utils/InstanceHealth/PostgresHealth.test.ts +0 -337
  314. package/Tests/Utils/EnterpriseLicenseSeats.test.ts +0 -576
  315. package/Tests/Utils/EnterpriseLicenseSync.test.ts +0 -568
  316. package/Utils/EnterpriseLicense/EnterpriseLicenseSeats.ts +0 -287
  317. package/Utils/EnterpriseLicense/EnterpriseLicenseSync.ts +0 -244
  318. package/build/dist/Server/API/EnterpriseLicenseAPI.js +0 -646
  319. package/build/dist/Server/API/EnterpriseLicenseAPI.js.map +0 -1
  320. package/build/dist/Server/API/TeamComplianceAPI.js +0 -111
  321. package/build/dist/Server/API/TeamComplianceAPI.js.map +0 -1
  322. package/build/dist/Server/Middleware/SCIMAuthorization.js +0 -124
  323. package/build/dist/Server/Middleware/SCIMAuthorization.js.map +0 -1
  324. package/build/dist/Server/Services/TeamComplianceService.js +0 -537
  325. package/build/dist/Server/Services/TeamComplianceService.js.map +0 -1
  326. package/build/dist/Server/Utils/EnterpriseLicense/EnterpriseLicenseSeatUtil.js +0 -145
  327. package/build/dist/Server/Utils/EnterpriseLicense/EnterpriseLicenseSeatUtil.js.map +0 -1
  328. package/build/dist/Server/Utils/InstanceHealth/PostgresHealth.js +0 -194
  329. package/build/dist/Server/Utils/InstanceHealth/PostgresHealth.js.map +0 -1
  330. package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseSeats.js +0 -168
  331. package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseSeats.js.map +0 -1
  332. package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseSync.js +0 -174
  333. package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseSync.js.map +0 -1
@@ -12,8 +12,10 @@ import { describe, expect, test } from "@jest/globals";
12
12
  * consumer, which is why a monitor on a non-443 port could never connect —
13
13
  * see https://github.com/OneUptime/oneuptime/issues/3225.
14
14
  *
15
- * fromString() is NOT a substitute: it splits on the FIRST colon, which
16
- * mangles every IPv6 literal.
15
+ * fromString() used not to be a substitute: it split on the FIRST colon,
16
+ * which mangled every IPv6 literal. It now delegates IPv6 authorities here
17
+ * instead, so the two agree on addresses; they still differ on a DNS host,
18
+ * where fromString keeps its own splitting and its own userinfo handling.
17
19
  */
18
20
  describe("Hostname.fromAuthority", () => {
19
21
  describe("host and port", () => {
@@ -141,18 +143,26 @@ describe("Hostname.fromAuthority", () => {
141
143
  });
142
144
 
143
145
  describe("contrast with fromString", () => {
144
- test("fromString rejects an IPv6 literal that fromAuthority handles", () => {
146
+ test("fromString now agrees with fromAuthority on an IPv6 literal", () => {
145
147
  /*
146
- * Pinned deliberately: it documents WHY fromAuthority exists, and
147
- * guards against someone 'simplifying' one into the other.
148
+ * This case used to be pinned the other way round: fromString split on
149
+ * the FIRST colon, so "[::1]:8443" became a host of "[" and the setter
150
+ * threw. Worse, the unbracketed spelling did NOT throw -- it returned
151
+ * host "2001" / port 518 for "2001:518:2800:9::2" and a monitor was
152
+ * saved pointing at a host nobody typed.
148
153
  *
149
- * fromString splits on the FIRST colon, so "[::1]:8443" becomes a
150
- * host of "[" - which the Hostname setter rejects outright.
154
+ * fromString delegates IPv6 authorities to fromAuthority now, so the
155
+ * two agree. Kept as a contrast test so a future 'simplification' that
156
+ * reintroduces the split fails here.
151
157
  */
152
158
  expect(Hostname.fromAuthority("[::1]:8443").hostname).toBe("[::1]");
153
- expect(() => {
154
- return Hostname.fromString("[::1]:8443");
155
- }).toThrow();
159
+ expect(Hostname.fromString("[::1]:8443").hostname).toBe("[::1]");
160
+ expect(Hostname.fromString("[::1]:8443").port?.toNumber()).toBe(8443);
161
+
162
+ expect(Hostname.fromString("2001:518:2800:9::2").hostname).toBe(
163
+ "2001:518:2800:9::2",
164
+ );
165
+ expect(Hostname.fromString("2001:518:2800:9::2").port).toBeUndefined();
156
166
  });
157
167
 
158
168
  test("both agree on the simple host:port case", () => {
@@ -0,0 +1,149 @@
1
+ import Hostname from "../../../Types/API/Hostname";
2
+ import URL from "../../../Types/API/URL";
3
+ import { describe, expect, test } from "@jest/globals";
4
+ import net from "net";
5
+
6
+ /*
7
+ * Hostname's handling of IPv6 literals.
8
+ *
9
+ * fromString used to split on the FIRST colon, which is meaningless for an
10
+ * address made of colons. The damage was silent rather than loud: for the
11
+ * customer address reported below it
12
+ * returned host "2001" with port 518 — both legal — so nothing threw and the
13
+ * value the operator typed was simply gone.
14
+ */
15
+
16
+ const CUSTOMER_ADDRESS: string = "2001:518:2800:9::2";
17
+
18
+ describe("Hostname.fromString with an IPv6 literal", () => {
19
+ test("keeps the whole address instead of its first two groups", () => {
20
+ const hostname: Hostname = Hostname.fromString(CUSTOMER_ADDRESS);
21
+
22
+ expect(hostname.hostname).toBe(CUSTOMER_ADDRESS);
23
+ expect(hostname.port).toBeUndefined();
24
+ expect(hostname.toString()).toBe(CUSTOMER_ADDRESS);
25
+ });
26
+
27
+ test("specifically, it is not 2001 port 518", () => {
28
+ const hostname: Hostname = Hostname.fromString(CUSTOMER_ADDRESS);
29
+
30
+ expect(hostname.hostname).not.toBe("2001");
31
+ expect(hostname.port?.toNumber()).not.toBe(518);
32
+ });
33
+
34
+ test("trims, so a pasted address keeps working", () => {
35
+ expect(Hostname.fromString(` ${CUSTOMER_ADDRESS}\n`).hostname).toBe(
36
+ CUSTOMER_ADDRESS,
37
+ );
38
+ });
39
+
40
+ test.each([
41
+ "::1",
42
+ "::",
43
+ "2001:db8::",
44
+ "::ffff:192.0.2.1",
45
+ "2001:0db8:85a3:0000:0000:8a2e:0370:7334",
46
+ ])("survives the compressed form %s", (address: string) => {
47
+ expect(Hostname.fromString(address).hostname).toBe(address);
48
+ });
49
+
50
+ test("a bracketed literal keeps its brackets and gives up its port", () => {
51
+ const hostname: Hostname = Hostname.fromString(`[${CUSTOMER_ADDRESS}]:179`);
52
+
53
+ expect(hostname.hostname).toBe(`[${CUSTOMER_ADDRESS}]`);
54
+ expect(hostname.port?.toNumber()).toBe(179);
55
+ });
56
+
57
+ test("a value with two colons that is NOT an address is rejected rather than silently split", () => {
58
+ expect(() => {
59
+ return Hostname.fromString("example.com:80:90");
60
+ }).toThrow();
61
+ });
62
+ });
63
+
64
+ describe("Hostname.fromString — IPv4 and DNS are unchanged", () => {
65
+ test.each([
66
+ ["example.com", "example.com", undefined],
67
+ ["example.com:8443", "example.com", 8443],
68
+ ["192.0.2.1", "192.0.2.1", undefined],
69
+ ["192.0.2.1:179", "192.0.2.1", 179],
70
+ ["localhost:3000", "localhost", 3000],
71
+ ])(
72
+ "%s parses to host %s",
73
+ (value: string, expectedHost: string, expectedPort?: number) => {
74
+ const hostname: Hostname = Hostname.fromString(value);
75
+
76
+ expect(hostname.hostname).toBe(expectedHost);
77
+ expect(hostname.port?.toNumber()).toBe(expectedPort);
78
+ },
79
+ );
80
+ });
81
+
82
+ describe("Hostname.toString with a port", () => {
83
+ test("brackets an IPv6 host, because the unbracketed form is a different address", () => {
84
+ const hostname: Hostname = new Hostname(CUSTOMER_ADDRESS, 179);
85
+
86
+ expect(hostname.toString()).toBe(`[${CUSTOMER_ADDRESS}]:179`);
87
+
88
+ // What it used to produce, and why that was not merely ugly:
89
+ expect(net.isIP(`${CUSTOMER_ADDRESS}:179`)).toBe(6);
90
+ expect(hostname.toString()).not.toBe(`${CUSTOMER_ADDRESS}:179`);
91
+ });
92
+
93
+ test("the bracketed form re-parses to the same host and port", () => {
94
+ const roundTripped: Hostname = Hostname.fromString(
95
+ new Hostname(CUSTOMER_ADDRESS, 179).toString(),
96
+ );
97
+
98
+ expect(roundTripped.hostname).toBe(`[${CUSTOMER_ADDRESS}]`);
99
+ expect(roundTripped.port?.toNumber()).toBe(179);
100
+ });
101
+
102
+ test("an IPv4 or DNS host keeps the conventional spelling", () => {
103
+ expect(new Hostname("192.0.2.1", 179).toString()).toBe("192.0.2.1:179");
104
+ expect(new Hostname("example.com", 8443).toString()).toBe(
105
+ "example.com:8443",
106
+ );
107
+ });
108
+
109
+ test("without a port the host is returned exactly as held", () => {
110
+ expect(new Hostname(CUSTOMER_ADDRESS).toString()).toBe(CUSTOMER_ADDRESS);
111
+ expect(Hostname.fromAuthority("[::1]").toString()).toBe("[::1]");
112
+ });
113
+ });
114
+
115
+ describe("Hostname.isValid validates the address, not just its characters", () => {
116
+ test.each([CUSTOMER_ADDRESS, "::1", "[::1]", "[::1]:8080", "2001:db8::"])(
117
+ "accepts %s",
118
+ (value: string) => {
119
+ expect(Hostname.isValid(value)).toBe(true);
120
+ },
121
+ );
122
+
123
+ test.each([
124
+ "::::",
125
+ "2001:db8:::1",
126
+ "[not-an-address]",
127
+ "gggg::1",
128
+ "2001:db8::1::2",
129
+ ])(
130
+ "rejects %s, which the old character allowlist let through",
131
+ (value: string) => {
132
+ expect(Hostname.isValid(value)).toBe(false);
133
+ },
134
+ );
135
+ });
136
+
137
+ describe("URL.toString still emits a valid authority for an IPv6 host", () => {
138
+ test("brackets survive a round trip", () => {
139
+ expect(
140
+ URL.fromString(`https://[${CUSTOMER_ADDRESS}]/health`).toString(),
141
+ ).toBe(`https://[${CUSTOMER_ADDRESS}]/health`);
142
+ });
143
+
144
+ test("a bracketed host with a port survives a round trip", () => {
145
+ expect(
146
+ URL.fromString(`https://[${CUSTOMER_ADDRESS}]:8443/x`).toString(),
147
+ ).toBe(`https://[${CUSTOMER_ADDRESS}]:8443/x`);
148
+ });
149
+ });
@@ -0,0 +1,190 @@
1
+ import AllModelTypes from "../../../Models/DatabaseModels/Index";
2
+ import BaseModel from "../../../Models/DatabaseModels/DatabaseBaseModel/DatabaseBaseModel";
3
+ import Monitor from "../../../Models/DatabaseModels/Monitor";
4
+ import ProjectSCIM from "../../../Models/DatabaseModels/ProjectSCIM";
5
+ import StatusPage from "../../../Models/DatabaseModels/StatusPage";
6
+ import UserEmail from "../../../Models/DatabaseModels/UserEmail";
7
+ import { ColumnAccessControl } from "../../../Types/BaseDatabase/AccessControl";
8
+ import ColumnBillingAccessControl from "../../../Types/BaseDatabase/ColumnBillingAccessControl";
9
+ import { getColumnAccessControlForAllColumns } from "../../../Types/Database/AccessControl/ColumnAccessControl";
10
+ import { getColumnBillingAccessControlForAllColumns } from "../../../Types/Database/AccessControl/ColumnBillingAccessControl";
11
+ import { getOwnerOnlyColumns } from "../../../Types/Database/AccessControl/OwnerOnlyColumn";
12
+ import Dictionary from "../../../Types/Dictionary";
13
+ import { JSONObject } from "../../../Types/JSON";
14
+ import { describe, expect, test } from "@jest/globals";
15
+ import { getMetadataArgsStorage } from "typeorm";
16
+
17
+ /*
18
+ * WHY THIS FILE EXISTS - do not delete these as "obvious" assertions.
19
+ *
20
+ * Every "which columns does this model have" lookup answers the question by
21
+ * enumerating an INSTANCE's own keys, and caches the answer per CLASS, for the
22
+ * whole process. So the FIRST instance to ask used to define what the class is
23
+ * for everybody after it.
24
+ *
25
+ * BaseAPI.createItem deleted `_id` off the live model instance it handed to
26
+ * the service, and DatabaseService.create asks that instance for its columns
27
+ * (generateDefaultValues) before any permission check runs. One POST - even a
28
+ * POST that was refused - could therefore teach the process that a model has
29
+ * no `_id` column, and DatabaseBaseModel.toJSONObject serializes a row by
30
+ * iterating exactly that cached list, so every response for that model lost
31
+ * its id from then on. To any caller, on any route, including plain reads as
32
+ * root: the row still carried its real `_id` in memory and the SQL projection
33
+ * still selected it. The id was dropped on the way out, and it stayed a 200
34
+ * because `_id` is in ColumnPermissions.getExcludedColumnNames().
35
+ *
36
+ * The tests below do the mutation on purpose. No caller in the tree does it
37
+ * any more, and that is not what is being protected: the invariant is that it
38
+ * CANNOT MATTER who asks first or what they did to their own instance. Each
39
+ * test uses a different model class, because these caches are per class and
40
+ * per process - a class another test has already asked about has a warm cache
41
+ * and would pass vacuously.
42
+ */
43
+
44
+ describe("column metadata does not depend on which instance asked first", () => {
45
+ test("getTableColumns: a mutilated instance asking first cannot strip _id from the class", () => {
46
+ const mutilated: ProjectSCIM = new ProjectSCIM();
47
+
48
+ // exactly what BaseAPI.createItem used to do before calling the service
49
+ delete (mutilated as unknown as Record<string, unknown>)["_id"];
50
+ expect(Object.keys(mutilated)).not.toContain("_id");
51
+
52
+ // the mutilated instance is the FIRST to ask, on a cold cache
53
+ expect(mutilated.getTableColumns().columns).toContain("_id");
54
+
55
+ // ...and a fresh instance of the same class is unharmed
56
+ expect(new ProjectSCIM().getTableColumns().columns).toContain("_id");
57
+ });
58
+
59
+ test("getTableColumns: a row still serializes with its _id after such a create", () => {
60
+ /*
61
+ * The assertion that matches the reported symptom: POST /api/project-scim
62
+ * answered 200 with every column except "_id", and a get-list selecting
63
+ * {_id, name} came back as {name} alone.
64
+ */
65
+ const mutilated: Monitor = new Monitor();
66
+ delete (mutilated as unknown as Record<string, unknown>)["_id"];
67
+ mutilated.getTableColumns();
68
+
69
+ const row: Monitor = new Monitor();
70
+ row._id = "22222222-2222-4222-8222-222222222222";
71
+ row.name = "a monitor";
72
+
73
+ const json: JSONObject = BaseModel.toJSONObject(row, Monitor);
74
+
75
+ expect(json["_id"]).toBe("22222222-2222-4222-8222-222222222222");
76
+ expect(json["name"]).toBe("a monitor");
77
+ });
78
+
79
+ test("getColumnAccessControlForAllColumns is instance-independent", () => {
80
+ const mutilated: StatusPage = new StatusPage();
81
+ delete (mutilated as unknown as Record<string, unknown>)["name"];
82
+
83
+ const fromMutilated: Dictionary<ColumnAccessControl> =
84
+ getColumnAccessControlForAllColumns(mutilated);
85
+
86
+ expect(fromMutilated["name"]).toBeDefined();
87
+ expect(
88
+ getColumnAccessControlForAllColumns(new StatusPage())["name"],
89
+ ).toBeDefined();
90
+ });
91
+
92
+ test("getColumnBillingAccessControlForAllColumns is instance-independent", () => {
93
+ const mutilated: StatusPage = new StatusPage();
94
+ delete (mutilated as unknown as Record<string, unknown>)["customCSS"];
95
+
96
+ const fromMutilated: Dictionary<ColumnBillingAccessControl> =
97
+ getColumnBillingAccessControlForAllColumns(mutilated);
98
+
99
+ expect(fromMutilated["customCSS"]).toBeDefined();
100
+ expect(
101
+ getColumnBillingAccessControlForAllColumns(new StatusPage())["customCSS"],
102
+ ).toBeDefined();
103
+ });
104
+
105
+ test("getOwnerOnlyColumns is instance-independent", () => {
106
+ /*
107
+ * This one is a permission list, not a projection: a marked column that
108
+ * goes unreported is a column OwnerOnlyColumnPermission stops protecting.
109
+ */
110
+ const mutilated: UserEmail = new UserEmail();
111
+ delete (mutilated as unknown as Record<string, unknown>)["email"];
112
+
113
+ expect(getOwnerOnlyColumns(mutilated)).toContain("email");
114
+ expect(getOwnerOnlyColumns(new UserEmail())).toContain("email");
115
+ });
116
+
117
+ test("mutating an instance after the class has been read changes nothing either", () => {
118
+ const first: UserEmail = new UserEmail();
119
+ expect(first.getTableColumns().columns).toContain("_id");
120
+
121
+ delete (first as unknown as Record<string, unknown>)["_id"];
122
+
123
+ expect(first.getTableColumns().columns).toContain("_id");
124
+ expect(new UserEmail().getTableColumns().columns).toContain("_id");
125
+ });
126
+ });
127
+
128
+ /*
129
+ * The premise of the fix: metadata enumeration reads a freshly constructed
130
+ * instance of the caller's class, so every model must be no-arg constructible
131
+ * and must expose every column it declares on a fresh instance (the class
132
+ * bodies do that with `= undefined` initializers). If a model is ever added
133
+ * that breaks either half, it would silently lose columns everywhere -
134
+ * responses, selects, permissions - so assert it for all of them at once.
135
+ */
136
+ describe("every database model supports canonical-instance enumeration", () => {
137
+ test("all models are no-arg constructible and declare no column that a fresh instance lacks", () => {
138
+ const columnsByTarget: Map<unknown, Array<string>> = new Map();
139
+
140
+ const record: (target: unknown, propertyName: string) => void = (
141
+ target: unknown,
142
+ propertyName: string,
143
+ ): void => {
144
+ const list: Array<string> = columnsByTarget.get(target) || [];
145
+ list.push(propertyName);
146
+ columnsByTarget.set(target, list);
147
+ };
148
+
149
+ for (const column of getMetadataArgsStorage().columns) {
150
+ record(column.target, column.propertyName);
151
+ }
152
+
153
+ for (const relation of getMetadataArgsStorage().relations) {
154
+ record(relation.target, relation.propertyName);
155
+ }
156
+
157
+ const constructFailures: Array<string> = [];
158
+ const missingKeys: Array<string> = [];
159
+
160
+ for (const modelType of AllModelTypes) {
161
+ let instance: BaseModel | null = null;
162
+
163
+ try {
164
+ instance = new modelType();
165
+ } catch (err) {
166
+ constructFailures.push(`${modelType.name}: ${(err as Error).message}`);
167
+ continue;
168
+ }
169
+
170
+ const ownKeys: Set<string> = new Set(Object.keys(instance));
171
+
172
+ // inherited columns count too, so walk the constructor chain
173
+ let ctor: unknown = modelType;
174
+
175
+ while (ctor && ctor !== Function.prototype) {
176
+ for (const propertyName of columnsByTarget.get(ctor) || []) {
177
+ if (!ownKeys.has(propertyName)) {
178
+ missingKeys.push(`${modelType.name}.${propertyName}`);
179
+ }
180
+ }
181
+
182
+ ctor = Object.getPrototypeOf(ctor);
183
+ }
184
+ }
185
+
186
+ expect(constructFailures).toEqual([]);
187
+ expect(missingKeys).toEqual([]);
188
+ expect(AllModelTypes.length).toBeGreaterThan(400);
189
+ });
190
+ });
@@ -0,0 +1,104 @@
1
+ /*
2
+ * What the edition dialog must say about an Enterprise license lapse. Shared
3
+ * by the core EditionLabel suite and ee/Tests/UI/License, which renders the
4
+ * same dialog with the Enterprise license manager.
5
+ *
6
+ * When the license lapses (after the trial or the grace period), single
7
+ * sign-on (SAML and OIDC), SCIM provisioning and audit logging stop - the
8
+ * Community Edition's behaviour - and "Require SSO" stops being enforced at
9
+ * the same moment, so nobody is locked out: users sign in with their
10
+ * password. Everything resumes as soon as a license is activated. The trial
11
+ * and grace notices must say so BEFORE it happens, and the lapsed notice must
12
+ * say what is off.
13
+ *
14
+ * The dialog used to promise the opposite ("SSO, SCIM and audit logging never
15
+ * stop"), so the checks reject that copy too. Plain functions over text, with
16
+ * no jest dependency, so a test can prove each check fails on the wrong copy.
17
+ */
18
+
19
+ // Before the lapse: the trial and grace notices, after "Without a valid license (...), ".
20
+ export const LAPSE_WARNING_PHRASES: ReadonlyArray<string> = [
21
+ "single sign-on (SAML and OIDC) stops",
22
+ '"Require SSO" is no longer enforced, so users sign in with their password',
23
+ "SCIM provisioning stops",
24
+ "audit logging stops recording",
25
+ "enterprise configuration becomes read-only",
26
+ "the enterprise admin dashboards are locked",
27
+ "Everything resumes as soon as a license is activated",
28
+ "core monitoring is never affected",
29
+ ];
30
+
31
+ // After the lapse: the license-required notice (expired, missing, invalid).
32
+ export const LAPSED_STATE_PHRASES: ReadonlyArray<string> = [
33
+ "Single sign-on (SAML and OIDC) and SCIM provisioning are off",
34
+ '"Require SSO" is not enforced, so users sign in with their password',
35
+ "SCIM requests are refused",
36
+ "Audit logging is not recording",
37
+ "Enterprise configuration is read-only",
38
+ "Everything resumes, without a restart, as soon as a valid license is added",
39
+ "core monitoring is never affected",
40
+ ];
41
+
42
+ // The soft-enforcement promises the dialog made before. None may come back.
43
+ export const RETIRED_SOFT_ENFORCEMENT_COPY: ReadonlyArray<RegExp> = [
44
+ /never stop/i,
45
+ /already configured keeps working/i,
46
+ /configured stops working/i,
47
+ /keeps? working as configured/i,
48
+ /never (?:silently )?weakens?/i,
49
+ ];
50
+
51
+ // The copy the dialog shipped before the owner's decision, verbatim.
52
+ export const RETIRED_NOTICE_EXAMPLES: ReadonlyArray<string> = [
53
+ "Without a valid license (after the 14-day grace period), enterprise configuration becomes read-only and the enterprise admin dashboards are locked. Everything you already configured keeps working — SSO, SCIM and audit logging never stop — and core monitoring is never affected.",
54
+ "Without a valid license (after the 14-day trial), enterprise configuration becomes read-only and the enterprise admin dashboards are locked. Everything you already configured keeps working — SSO, SCIM and audit logging never stop — and core monitoring is never affected.",
55
+ "The Enterprise license expired and its grace period is over. Enterprise configuration is read-only and the enterprise admin dashboards are locked until a valid license is added. Everything you already configured keeps working — SSO, SCIM and audit logging never stop — and core monitoring is never affected.",
56
+ ];
57
+
58
+ type CopyCheck = (text: string | null | undefined) => Array<string>;
59
+
60
+ // Whitespace-normalized, so a check does not depend on how JSX wraps a line.
61
+ const normalize: (text: string | null | undefined) => string = (
62
+ text: string | null | undefined,
63
+ ): string => {
64
+ return (text || "").replace(/\s+/g, " ").trim();
65
+ };
66
+
67
+ const copyProblems: (
68
+ text: string | null | undefined,
69
+ requiredPhrases: ReadonlyArray<string>,
70
+ ) => Array<string> = (
71
+ text: string | null | undefined,
72
+ requiredPhrases: ReadonlyArray<string>,
73
+ ): Array<string> => {
74
+ const flat: string = normalize(text);
75
+ const problems: Array<string> = [];
76
+
77
+ for (const phrase of requiredPhrases) {
78
+ if (!flat.includes(phrase)) {
79
+ problems.push(`missing: ${phrase}`);
80
+ }
81
+ }
82
+
83
+ for (const retired of RETIRED_SOFT_ENFORCEMENT_COPY) {
84
+ if (retired.test(flat)) {
85
+ problems.push(`retired: ${retired.source}`);
86
+ }
87
+ }
88
+
89
+ return problems;
90
+ };
91
+
92
+ // What is wrong with a trial or grace notice (empty when it is right).
93
+ export const lapseWarningProblems: CopyCheck = (
94
+ text: string | null | undefined,
95
+ ): Array<string> => {
96
+ return copyProblems(text, LAPSE_WARNING_PHRASES);
97
+ };
98
+
99
+ // What is wrong with the notice shown once the license has lapsed.
100
+ export const lapsedStateProblems: CopyCheck = (
101
+ text: string | null | undefined,
102
+ ): Array<string> => {
103
+ return copyProblems(text, LAPSED_STATE_PHRASES);
104
+ };