@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
@@ -0,0 +1,303 @@
1
+ import {
2
+ afterEach,
3
+ beforeEach,
4
+ describe,
5
+ expect,
6
+ jest,
7
+ test,
8
+ } from "@jest/globals";
9
+ import EnterpriseEdition from "../../../Server/Enterprise/EnterpriseEdition";
10
+ import EnterpriseFeature from "../../../Server/Enterprise/EnterpriseFeature";
11
+ import EditionEnforcement from "../../../Server/Utils/EditionEnforcement";
12
+ import logger from "../../../Server/Utils/Logger";
13
+ import DatabaseCommonInteractionProps from "../../../Types/BaseDatabase/DatabaseCommonInteractionProps";
14
+ import ObjectID from "../../../Types/ObjectID";
15
+ import FakeEnterpriseModule, {
16
+ createEditionStateCases,
17
+ createLicenseSnapshot,
18
+ createLicenseSnapshotWithStatus,
19
+ EditionStateCase,
20
+ installFakeEnterpriseModule,
21
+ uninstallEnterpriseModule,
22
+ } from "../Enterprise/FakeEnterpriseModule";
23
+ import { setTestBillingEnabled } from "../Enterprise/TestBillingFlag";
24
+ import { getJestSpyOn } from "../../Spy";
25
+
26
+ type SpyInstance = ReturnType<typeof getJestSpyOn>;
27
+
28
+ /*
29
+ * EditionEnforcement answers "is this identity control live here?" for the
30
+ * core enforcement sites (UserAuthorization, status page sign-in, SCIM team
31
+ * locks, provider listings, read masking).
32
+ *
33
+ * The rule: the answer follows the RUNTIME state of the feature behind it
34
+ * (EnterpriseEdition.isFeatureActive) - SSO for the SSO requirements, routes
35
+ * and listings, SCIM for the team locks. So the controls are live on the
36
+ * Enterprise Edition while the license covers the feature (or billing is on),
37
+ * and relaxed on the Community Edition AND on an Enterprise install whose
38
+ * license has lapsed - there the SSO routes refuse and nobody could satisfy a
39
+ * requirement. An unknown license state and any error answer "enforce".
40
+ *
41
+ * Billing and the edition are pinned in every test (CI's config.env sets
42
+ * BILLING_ENABLED=true).
43
+ */
44
+ jest.mock("../../../Server/EnvironmentConfig", () => {
45
+ const billingFlag: typeof import("../Enterprise/TestBillingFlag") =
46
+ jest.requireActual(
47
+ "../Enterprise/TestBillingFlag",
48
+ ) as typeof import("../Enterprise/TestBillingFlag");
49
+
50
+ return billingFlag.withLiveBillingFlag(
51
+ jest.requireActual("../../../Server/EnvironmentConfig") as Record<
52
+ string,
53
+ unknown
54
+ >,
55
+ );
56
+ });
57
+
58
+ const userProps: DatabaseCommonInteractionProps = {
59
+ userId: new ObjectID("22222222-2222-4222-8222-222222222222"),
60
+ tenantId: new ObjectID("11111111-1111-4111-8111-111111111111"),
61
+ };
62
+
63
+ const EDITION_CASES: Array<EditionStateCase> = createEditionStateCases();
64
+
65
+ describe("EditionEnforcement", () => {
66
+ beforeEach(() => {
67
+ setTestBillingEnabled(false);
68
+ uninstallEnterpriseModule();
69
+ getJestSpyOn(logger, "warn").mockImplementation((): void => {
70
+ return undefined;
71
+ });
72
+ getJestSpyOn(logger, "info").mockImplementation((): void => {
73
+ return undefined;
74
+ });
75
+ });
76
+
77
+ afterEach(() => {
78
+ uninstallEnterpriseModule();
79
+ setTestBillingEnabled(false);
80
+ jest.restoreAllMocks();
81
+ });
82
+
83
+ describe("the answers follow the runtime state of SSO and SCIM", () => {
84
+ test("the matrix has lapsed Enterprise states, not just the two editions", () => {
85
+ expect(
86
+ EDITION_CASES.filter((editionCase: EditionStateCase): boolean => {
87
+ return editionCase.isLoaded && !editionCase.isActive;
88
+ }).length,
89
+ ).toBeGreaterThanOrEqual(4);
90
+ });
91
+
92
+ test.each(
93
+ EDITION_CASES.map(
94
+ (editionCase: EditionStateCase): [string, EditionStateCase] => {
95
+ return [editionCase.label, editionCase];
96
+ },
97
+ ),
98
+ )("%s", (_label: string, editionCase: EditionStateCase) => {
99
+ editionCase.apply();
100
+
101
+ expect(EditionEnforcement.isSsoEnforced()).toBe(editionCase.isActive);
102
+ expect(EditionEnforcement.isSsoRequired(true)).toBe(editionCase.isActive);
103
+ expect(EditionEnforcement.areScimTeamLocksEnforced()).toBe(
104
+ editionCase.isActive,
105
+ );
106
+ expect(EditionEnforcement.areSsoRoutesServed()).toBe(
107
+ editionCase.isActive,
108
+ );
109
+ expect(EditionEnforcement.shouldMaskSsoRequirementOnRead(userProps)).toBe(
110
+ !editionCase.isActive,
111
+ );
112
+ });
113
+ });
114
+
115
+ describe("SSO and SCIM are decided separately", () => {
116
+ test("a license without SCIM relaxes the SCIM team locks only", () => {
117
+ installFakeEnterpriseModule({
118
+ snapshot: createLicenseSnapshot({
119
+ features: [EnterpriseFeature.SSO, EnterpriseFeature.AuditLogs],
120
+ }),
121
+ });
122
+
123
+ expect(EditionEnforcement.isSsoEnforced()).toBe(true);
124
+ expect(EditionEnforcement.areSsoRoutesServed()).toBe(true);
125
+ expect(EditionEnforcement.areScimTeamLocksEnforced()).toBe(false);
126
+ });
127
+
128
+ test("a license without SSO relaxes the SSO requirements only", () => {
129
+ installFakeEnterpriseModule({
130
+ snapshot: createLicenseSnapshot({
131
+ features: [EnterpriseFeature.SCIM],
132
+ }),
133
+ });
134
+
135
+ expect(EditionEnforcement.isSsoEnforced()).toBe(false);
136
+ expect(EditionEnforcement.isSsoRequired(true)).toBe(false);
137
+ expect(EditionEnforcement.areSsoRoutesServed()).toBe(false);
138
+ expect(EditionEnforcement.shouldMaskSsoRequirementOnRead(userProps)).toBe(
139
+ true,
140
+ );
141
+ expect(EditionEnforcement.areScimTeamLocksEnforced()).toBe(true);
142
+ });
143
+ });
144
+
145
+ describe("a license change applies at once, without a restart", () => {
146
+ test("lapse relaxes, renewal enforces again, lapse relaxes again", () => {
147
+ const fake: FakeEnterpriseModule = installFakeEnterpriseModule();
148
+
149
+ expect(EditionEnforcement.isSsoRequired(true)).toBe(true);
150
+ expect(EditionEnforcement.areScimTeamLocksEnforced()).toBe(true);
151
+
152
+ fake.setSnapshot(createLicenseSnapshotWithStatus("expired"));
153
+ expect(EditionEnforcement.isSsoRequired(true)).toBe(false);
154
+ expect(EditionEnforcement.areScimTeamLocksEnforced()).toBe(false);
155
+ expect(EditionEnforcement.areSsoRoutesServed()).toBe(false);
156
+
157
+ fake.setSnapshot(createLicenseSnapshotWithStatus("valid"));
158
+ expect(EditionEnforcement.isSsoRequired(true)).toBe(true);
159
+ expect(EditionEnforcement.areScimTeamLocksEnforced()).toBe(true);
160
+ expect(EditionEnforcement.areSsoRoutesServed()).toBe(true);
161
+
162
+ fake.setSnapshot(createLicenseSnapshotWithStatus("missing"));
163
+ expect(EditionEnforcement.isSsoRequired(true)).toBe(false);
164
+ });
165
+ });
166
+
167
+ describe("isSsoRequired", () => {
168
+ test.each([false, undefined, null])(
169
+ "a requirement that is not configured (%p) is never required",
170
+ (configured: boolean | undefined | null) => {
171
+ installFakeEnterpriseModule();
172
+ expect(EditionEnforcement.isSsoRequired(configured)).toBe(false);
173
+
174
+ uninstallEnterpriseModule();
175
+ expect(EditionEnforcement.isSsoRequired(configured)).toBe(false);
176
+ },
177
+ );
178
+
179
+ test("a configured requirement is relaxed on the Enterprise Edition once the license lapsed", () => {
180
+ installFakeEnterpriseModule({
181
+ snapshot: createLicenseSnapshotWithStatus("expired"),
182
+ });
183
+
184
+ expect(EditionEnforcement.isSsoRequired(true)).toBe(false);
185
+ });
186
+
187
+ test("a configured requirement is still required during the grace period", () => {
188
+ installFakeEnterpriseModule({
189
+ snapshot: createLicenseSnapshotWithStatus("grace"),
190
+ });
191
+
192
+ expect(EditionEnforcement.isSsoRequired(true)).toBe(true);
193
+ });
194
+
195
+ test("a configured requirement is relaxed on the Community Edition", () => {
196
+ expect(EditionEnforcement.isSsoRequired(true)).toBe(false);
197
+ });
198
+ });
199
+
200
+ describe("errors answer 'enforce' (fail secure)", () => {
201
+ let loggerError: SpyInstance;
202
+
203
+ beforeEach(() => {
204
+ loggerError = getJestSpyOn(logger, "error").mockImplementation(
205
+ (): void => {
206
+ return undefined;
207
+ },
208
+ );
209
+ getJestSpyOn(EnterpriseEdition, "isFeatureActive").mockImplementation(
210
+ (): boolean => {
211
+ throw new Error("facade exploded");
212
+ },
213
+ );
214
+ });
215
+
216
+ test("an error while deciding SSO enforcement enforces SSO and logs it", () => {
217
+ expect(EditionEnforcement.isSsoEnforced()).toBe(true);
218
+ expect(EditionEnforcement.isSsoRequired(true)).toBe(true);
219
+ expect(EditionEnforcement.shouldMaskSsoRequirementOnRead(userProps)).toBe(
220
+ false,
221
+ );
222
+ expect(loggerError).toHaveBeenCalled();
223
+ });
224
+
225
+ test("an error while deciding whether the SSO routes are served serves them", () => {
226
+ expect(EditionEnforcement.areSsoRoutesServed()).toBe(true);
227
+ expect(loggerError).toHaveBeenCalled();
228
+ });
229
+
230
+ test("an error while deciding the SCIM team locks applies them", () => {
231
+ expect(EditionEnforcement.areScimTeamLocksEnforced()).toBe(true);
232
+ expect(loggerError).toHaveBeenCalled();
233
+ });
234
+ });
235
+
236
+ describe("shouldMaskSsoRequirementOnRead", () => {
237
+ test("internal root reads are never masked, in any state", () => {
238
+ expect(
239
+ EditionEnforcement.shouldMaskSsoRequirementOnRead({ isRoot: true }),
240
+ ).toBe(false);
241
+
242
+ installFakeEnterpriseModule({
243
+ snapshot: createLicenseSnapshotWithStatus("expired"),
244
+ });
245
+
246
+ expect(
247
+ EditionEnforcement.shouldMaskSsoRequirementOnRead({ isRoot: true }),
248
+ ).toBe(false);
249
+
250
+ installFakeEnterpriseModule();
251
+
252
+ expect(
253
+ EditionEnforcement.shouldMaskSsoRequirementOnRead({ isRoot: true }),
254
+ ).toBe(false);
255
+ });
256
+
257
+ test("missing props are treated as an internal read", () => {
258
+ expect(EditionEnforcement.shouldMaskSsoRequirementOnRead(undefined)).toBe(
259
+ false,
260
+ );
261
+ expect(EditionEnforcement.shouldMaskSsoRequirementOnRead(null)).toBe(
262
+ false,
263
+ );
264
+ });
265
+
266
+ test("master admin and user reads are masked while SSO is not active only", () => {
267
+ const masterAdmin: DatabaseCommonInteractionProps = {
268
+ userId: userProps.userId!,
269
+ isMasterAdmin: true,
270
+ };
271
+
272
+ // Community Edition.
273
+ expect(
274
+ EditionEnforcement.shouldMaskSsoRequirementOnRead(masterAdmin),
275
+ ).toBe(true);
276
+ expect(EditionEnforcement.shouldMaskSsoRequirementOnRead(userProps)).toBe(
277
+ true,
278
+ );
279
+
280
+ // Enterprise Edition, lapsed license.
281
+ const fake: FakeEnterpriseModule = installFakeEnterpriseModule({
282
+ snapshot: createLicenseSnapshotWithStatus("invalid"),
283
+ });
284
+
285
+ expect(
286
+ EditionEnforcement.shouldMaskSsoRequirementOnRead(masterAdmin),
287
+ ).toBe(true);
288
+ expect(EditionEnforcement.shouldMaskSsoRequirementOnRead(userProps)).toBe(
289
+ true,
290
+ );
291
+
292
+ // Enterprise Edition, license renewed.
293
+ fake.setSnapshot(createLicenseSnapshotWithStatus("valid"));
294
+
295
+ expect(
296
+ EditionEnforcement.shouldMaskSsoRequirementOnRead(masterAdmin),
297
+ ).toBe(false);
298
+ expect(EditionEnforcement.shouldMaskSsoRequirementOnRead(userProps)).toBe(
299
+ false,
300
+ );
301
+ });
302
+ });
303
+ });
@@ -1,4 +1,6 @@
1
1
  import { afterEach, describe, expect, test, jest } from "@jest/globals";
2
+ import fs from "fs";
3
+ import path from "path";
2
4
  import type {
3
5
  ExpressRequest,
4
6
  ExpressResponse,
@@ -6,6 +8,9 @@ import type {
6
8
 
7
9
  const MANAGED_KEYS: Array<string> = [
8
10
  "HOST",
11
+ "IS_ENTERPRISE_EDITION",
12
+ "ONEUPTIME_EDITION",
13
+ "ENTERPRISE_EDITION_REQUESTED_BUT_NOT_LOADED",
9
14
  "PUBLIC_TEST_SETTING",
10
15
  "OPENTELEMETRY_EXPORTER_OTLP_ENDPOINT",
11
16
  "OPENTELEMETRY_EXPORTER_OTLP_HEADERS",
@@ -22,9 +27,15 @@ interface BrowserWindow {
22
27
  };
23
28
  }
24
29
 
30
+ interface RenderOptions {
31
+ // Register a fake enterprise module before serializing (the EE image).
32
+ enterpriseLoaded?: boolean;
33
+ }
34
+
25
35
  async function render(
26
36
  overrides: Record<string, string | undefined>,
27
37
  initialWindow: BrowserWindow = {},
38
+ options: RenderOptions = {},
28
39
  ): Promise<{ script: string; window: BrowserWindow }> {
29
40
  for (const key of MANAGED_KEYS) {
30
41
  delete process.env[key];
@@ -42,6 +53,20 @@ async function render(
42
53
  const { getFrontendEnvironmentScript } = await import(
43
54
  "../../../Server/Utils/FrontendEnvironment"
44
55
  );
56
+
57
+ /*
58
+ * Imported from the same fresh module registry as the serializer, so the
59
+ * fake is registered on the very EnterpriseEdition instance it reads.
60
+ */
61
+ const enterpriseKit: typeof import("../Enterprise/FakeEnterpriseModule") =
62
+ await import("../Enterprise/FakeEnterpriseModule");
63
+
64
+ if (options.enterpriseLoaded) {
65
+ enterpriseKit.installFakeEnterpriseModule();
66
+ } else {
67
+ enterpriseKit.uninstallEnterpriseModule();
68
+ }
69
+
45
70
  const script: string = getFrontendEnvironmentScript();
46
71
 
47
72
  new Function("window", script)(initialWindow);
@@ -188,3 +213,345 @@ describe("frontend environment script serialization", () => {
188
213
  expect(end).toHaveBeenCalledTimes(1);
189
214
  });
190
215
  });
216
+
217
+ describe("frontend environment edition flags", () => {
218
+ interface EditionCase {
219
+ rawValue: string | undefined;
220
+ enterpriseLoaded: boolean;
221
+ effective: string;
222
+ requestedButNotLoaded: string;
223
+ }
224
+
225
+ test.each([
226
+ {
227
+ rawValue: undefined,
228
+ enterpriseLoaded: false,
229
+ effective: "false",
230
+ requestedButNotLoaded: "false",
231
+ },
232
+ {
233
+ rawValue: "false",
234
+ enterpriseLoaded: false,
235
+ effective: "false",
236
+ requestedButNotLoaded: "false",
237
+ },
238
+ {
239
+ rawValue: "true",
240
+ enterpriseLoaded: false,
241
+ effective: "false",
242
+ requestedButNotLoaded: "true",
243
+ },
244
+ {
245
+ rawValue: "true",
246
+ enterpriseLoaded: true,
247
+ effective: "true",
248
+ requestedButNotLoaded: "false",
249
+ },
250
+ {
251
+ rawValue: undefined,
252
+ enterpriseLoaded: true,
253
+ effective: "true",
254
+ requestedButNotLoaded: "false",
255
+ },
256
+ {
257
+ rawValue: "false",
258
+ enterpriseLoaded: true,
259
+ effective: "true",
260
+ requestedButNotLoaded: "false",
261
+ },
262
+ ] as Array<EditionCase>)(
263
+ "IS_ENTERPRISE_EDITION=$rawValue with ee loaded=$enterpriseLoaded serializes the effective edition $effective",
264
+ async (editionCase: EditionCase) => {
265
+ const result: Awaited<ReturnType<typeof render>> = await render(
266
+ { IS_ENTERPRISE_EDITION: editionCase.rawValue },
267
+ {},
268
+ { enterpriseLoaded: editionCase.enterpriseLoaded },
269
+ );
270
+
271
+ expect(result.window.process?.env?.["IS_ENTERPRISE_EDITION"]).toBe(
272
+ editionCase.effective,
273
+ );
274
+ expect(
275
+ result.window.process?.env?.[
276
+ "ENTERPRISE_EDITION_REQUESTED_BUT_NOT_LOADED"
277
+ ],
278
+ ).toBe(editionCase.requestedButNotLoaded);
279
+ },
280
+ );
281
+
282
+ test("a client-supplied ENTERPRISE_EDITION_REQUESTED_BUT_NOT_LOADED cannot leak through", async () => {
283
+ const result: Awaited<ReturnType<typeof render>> = await render(
284
+ {
285
+ ENTERPRISE_EDITION_REQUESTED_BUT_NOT_LOADED: "true",
286
+ PUBLIC_TEST_SETTING: "kept",
287
+ },
288
+ {},
289
+ { enterpriseLoaded: true },
290
+ );
291
+
292
+ expect(
293
+ result.window.process?.env?.[
294
+ "ENTERPRISE_EDITION_REQUESTED_BUT_NOT_LOADED"
295
+ ],
296
+ ).toBe("false");
297
+ expect(result.window.process?.env?.["PUBLIC_TEST_SETTING"]).toBe("kept");
298
+ });
299
+
300
+ /*
301
+ * "Requested" is EnvironmentConfig's isEnterpriseEditionRequested, the
302
+ * definition the App's boot guard uses too: an explicit
303
+ * ONEUPTIME_EDITION=community withdraws the request. The Enterprise image
304
+ * bakes IS_ENTERPRISE_EDITION=true, so without that exception an operator
305
+ * running it as the Community Edition on purpose (the documented way) would
306
+ * be told "this is the Community image, switch images".
307
+ */
308
+ interface RequestCase {
309
+ label: string;
310
+ isEnterpriseEdition: string | undefined;
311
+ edition: string | undefined;
312
+ enterpriseLoaded: boolean;
313
+ requestedButNotLoaded: string;
314
+ }
315
+
316
+ test.each([
317
+ {
318
+ label: "the Enterprise image run with ONEUPTIME_EDITION=community",
319
+ isEnterpriseEdition: "true",
320
+ edition: "community",
321
+ enterpriseLoaded: false,
322
+ requestedButNotLoaded: "false",
323
+ },
324
+ {
325
+ label: "ONEUPTIME_EDITION=community in any case and spacing",
326
+ isEnterpriseEdition: "true",
327
+ edition: " Community \n",
328
+ enterpriseLoaded: false,
329
+ requestedButNotLoaded: "false",
330
+ },
331
+ {
332
+ label: "the Community image with a leftover IS_ENTERPRISE_EDITION=true",
333
+ isEnterpriseEdition: "true",
334
+ edition: undefined,
335
+ enterpriseLoaded: false,
336
+ requestedButNotLoaded: "true",
337
+ },
338
+ {
339
+ label:
340
+ "IS_ENTERPRISE_EDITION=true with an explicit ONEUPTIME_EDITION=auto",
341
+ isEnterpriseEdition: "true",
342
+ edition: "auto",
343
+ enterpriseLoaded: false,
344
+ requestedButNotLoaded: "true",
345
+ },
346
+ {
347
+ label: "IS_ENTERPRISE_EDITION=true with a blank ONEUPTIME_EDITION (auto)",
348
+ isEnterpriseEdition: "true",
349
+ edition: " ",
350
+ enterpriseLoaded: false,
351
+ requestedButNotLoaded: "true",
352
+ },
353
+ {
354
+ label: "ONEUPTIME_EDITION=enterprise whose module did not load",
355
+ isEnterpriseEdition: "true",
356
+ edition: "enterprise",
357
+ enterpriseLoaded: false,
358
+ requestedButNotLoaded: "true",
359
+ },
360
+ {
361
+ label: "an unrecognised ONEUPTIME_EDITION does not withdraw the request",
362
+ isEnterpriseEdition: "true",
363
+ edition: "comunity",
364
+ enterpriseLoaded: false,
365
+ requestedButNotLoaded: "true",
366
+ },
367
+ {
368
+ label: "IS_ENTERPRISE_EDITION=TRUE is not a request (exactly true only)",
369
+ isEnterpriseEdition: "TRUE",
370
+ edition: undefined,
371
+ enterpriseLoaded: false,
372
+ requestedButNotLoaded: "false",
373
+ },
374
+ {
375
+ label: "the Enterprise image with ee loaded",
376
+ isEnterpriseEdition: "true",
377
+ edition: "enterprise",
378
+ enterpriseLoaded: true,
379
+ requestedButNotLoaded: "false",
380
+ },
381
+ {
382
+ label: "ONEUPTIME_EDITION=community without IS_ENTERPRISE_EDITION",
383
+ isEnterpriseEdition: undefined,
384
+ edition: "community",
385
+ enterpriseLoaded: false,
386
+ requestedButNotLoaded: "false",
387
+ },
388
+ ] as Array<RequestCase>)(
389
+ "$label: requested but not loaded = $requestedButNotLoaded",
390
+ async (requestCase: RequestCase) => {
391
+ const result: Awaited<ReturnType<typeof render>> = await render(
392
+ {
393
+ IS_ENTERPRISE_EDITION: requestCase.isEnterpriseEdition,
394
+ ONEUPTIME_EDITION: requestCase.edition,
395
+ },
396
+ {},
397
+ { enterpriseLoaded: requestCase.enterpriseLoaded },
398
+ );
399
+
400
+ expect(
401
+ result.window.process?.env?.[
402
+ "ENTERPRISE_EDITION_REQUESTED_BUT_NOT_LOADED"
403
+ ],
404
+ ).toBe(requestCase.requestedButNotLoaded);
405
+ expect(result.window.process?.env?.["IS_ENTERPRISE_EDITION"]).toBe(
406
+ requestCase.enterpriseLoaded ? "true" : "false",
407
+ );
408
+ },
409
+ );
410
+
411
+ test("the request is read on every call, not frozen at import", async () => {
412
+ await render({ IS_ENTERPRISE_EDITION: "true" });
413
+
414
+ const { getFrontendEnvironmentVariables } = await import(
415
+ "../../../Server/Utils/FrontendEnvironment"
416
+ );
417
+
418
+ expect(
419
+ getFrontendEnvironmentVariables()[
420
+ "ENTERPRISE_EDITION_REQUESTED_BUT_NOT_LOADED"
421
+ ],
422
+ ).toBe("true");
423
+
424
+ process.env["ONEUPTIME_EDITION"] = "community";
425
+
426
+ expect(
427
+ getFrontendEnvironmentVariables()[
428
+ "ENTERPRISE_EDITION_REQUESTED_BUT_NOT_LOADED"
429
+ ],
430
+ ).toBe("false");
431
+ });
432
+
433
+ test("uses EnvironmentConfig's shared definition, not a copy of it", () => {
434
+ const source: string = fs
435
+ .readFileSync(
436
+ path.join(__dirname, "../../../Server/Utils/FrontendEnvironment.ts"),
437
+ "utf8",
438
+ )
439
+ .replace(/\/\*[\s\S]*?\*\//g, "")
440
+ .replace(/(^|[^:])\/\/[^\n]*/g, "$1");
441
+
442
+ expect(source).toMatch(
443
+ /isEnterpriseEditionRequested\(\s*process\.env,?\s*\)/,
444
+ );
445
+ expect(source).not.toMatch(/IS_ENTERPRISE_EDITION"\]\s*===/);
446
+ expect(source).not.toContain("ONEUPTIME_EDITION");
447
+ });
448
+
449
+ test("the effective flags are the only edition values in the script", async () => {
450
+ const result: Awaited<ReturnType<typeof render>> = await render(
451
+ { IS_ENTERPRISE_EDITION: "true" },
452
+ {},
453
+ { enterpriseLoaded: false },
454
+ );
455
+
456
+ expect(result.script.match(/IS_ENTERPRISE_EDITION/g)?.length).toBe(1);
457
+ expect(result.script).toContain('"IS_ENTERPRISE_EDITION":"false"');
458
+ });
459
+ });
460
+
461
+ /*
462
+ * The shared definition itself (EnvironmentConfig), which the App's boot guard
463
+ * (packages/App/Utils/EnterpriseLoader.ts) also uses as its default.
464
+ */
465
+ describe("isEnterpriseEditionRequested", () => {
466
+ type EnvironmentConfigModule =
467
+ typeof import("../../../Server/EnvironmentConfig");
468
+
469
+ const loadConfig: (
470
+ overrides: Record<string, string | undefined>,
471
+ ) => Promise<EnvironmentConfigModule> = async (
472
+ overrides: Record<string, string | undefined>,
473
+ ): Promise<EnvironmentConfigModule> => {
474
+ for (const key of MANAGED_KEYS) {
475
+ delete process.env[key];
476
+ }
477
+
478
+ for (const [key, value] of Object.entries(overrides)) {
479
+ if (typeof value === "undefined") {
480
+ delete process.env[key];
481
+ } else {
482
+ process.env[key] = value;
483
+ }
484
+ }
485
+
486
+ jest.resetModules();
487
+
488
+ return await import("../../../Server/EnvironmentConfig");
489
+ };
490
+
491
+ interface DefinitionCase {
492
+ isEnterpriseEdition: string | undefined;
493
+ edition: string | undefined;
494
+ requested: boolean;
495
+ }
496
+
497
+ test.each([
498
+ { isEnterpriseEdition: "true", edition: undefined, requested: true },
499
+ { isEnterpriseEdition: "true", edition: "", requested: true },
500
+ { isEnterpriseEdition: "true", edition: "auto", requested: true },
501
+ { isEnterpriseEdition: "true", edition: "enterprise", requested: true },
502
+ { isEnterpriseEdition: "true", edition: "not-an-edition", requested: true },
503
+ { isEnterpriseEdition: "true", edition: "community", requested: false },
504
+ { isEnterpriseEdition: "true", edition: " COMMUNITY ", requested: false },
505
+ { isEnterpriseEdition: "false", edition: undefined, requested: false },
506
+ { isEnterpriseEdition: "false", edition: "enterprise", requested: false },
507
+ { isEnterpriseEdition: undefined, edition: undefined, requested: false },
508
+ { isEnterpriseEdition: "", edition: "auto", requested: false },
509
+ { isEnterpriseEdition: "TRUE", edition: undefined, requested: false },
510
+ { isEnterpriseEdition: " true", edition: undefined, requested: false },
511
+ { isEnterpriseEdition: "1", edition: undefined, requested: false },
512
+ ] as Array<DefinitionCase>)(
513
+ "IS_ENTERPRISE_EDITION=$isEnterpriseEdition, ONEUPTIME_EDITION=$edition -> $requested",
514
+ async (definitionCase: DefinitionCase) => {
515
+ const config: EnvironmentConfigModule = await loadConfig({
516
+ IS_ENTERPRISE_EDITION: definitionCase.isEnterpriseEdition,
517
+ ONEUPTIME_EDITION: definitionCase.edition,
518
+ });
519
+
520
+ expect(
521
+ config.isEnterpriseEditionRequested({
522
+ IS_ENTERPRISE_EDITION: definitionCase.isEnterpriseEdition,
523
+ ONEUPTIME_EDITION: definitionCase.edition,
524
+ }),
525
+ ).toBe(definitionCase.requested);
526
+ // The constant the loader defaults to is the same rule over process.env.
527
+ expect(config.IsEnterpriseEditionRequested).toBe(
528
+ definitionCase.requested,
529
+ );
530
+ },
531
+ );
532
+
533
+ test("reads only the environment it is given", async () => {
534
+ const config: EnvironmentConfigModule = await loadConfig({
535
+ IS_ENTERPRISE_EDITION: "true",
536
+ });
537
+
538
+ expect(config.IsEnterpriseEditionRequested).toBe(true);
539
+ expect(config.isEnterpriseEditionRequested({})).toBe(false);
540
+ expect(
541
+ config.isEnterpriseEditionRequested({
542
+ IS_ENTERPRISE_EDITION: "true",
543
+ ONEUPTIME_EDITION: "community",
544
+ }),
545
+ ).toBe(false);
546
+ });
547
+
548
+ test("leaves the raw IsEnterpriseEdition flag meaning what it always meant", async () => {
549
+ const config: EnvironmentConfigModule = await loadConfig({
550
+ IS_ENTERPRISE_EDITION: "true",
551
+ ONEUPTIME_EDITION: "community",
552
+ });
553
+
554
+ expect(config.IsEnterpriseEdition).toBe(true);
555
+ expect(config.IsEnterpriseEditionRequested).toBe(false);
556
+ });
557
+ });