@oneuptime/common 13.0.8 → 14.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (514) hide show
  1. package/Models/AnalyticsModels/AuditLog.ts +23 -15
  2. package/Models/DatabaseModels/GlobalConfig.ts +24 -0
  3. package/Models/DatabaseModels/Index.ts +4 -0
  4. package/Models/DatabaseModels/Monitor.ts +3 -2
  5. package/Models/DatabaseModels/MonitorTemplate.ts +2 -1
  6. package/Models/DatabaseModels/ServiceLevelObjectiveFeed.ts +2 -0
  7. package/Models/DatabaseModels/ServiceLevelObjectiveLabelRule.ts +522 -0
  8. package/Models/DatabaseModels/ServiceLevelObjectiveMonitorRule.ts +38 -4
  9. package/Models/DatabaseModels/ServiceLevelObjectiveOwnerRule.ts +603 -0
  10. package/Scripts/generate-service-worker.js +65 -4
  11. package/Server/API/BaseAPI.ts +26 -5
  12. package/Server/API/GlobalConfigAPI.ts +228 -462
  13. package/Server/API/ProjectOIDC.ts +25 -16
  14. package/Server/API/ProjectSSO.ts +24 -16
  15. package/Server/API/StatusPageAPI.ts +100 -42
  16. package/Server/API/TeamMemberAPI.ts +10 -1
  17. package/Server/Enterprise/EnterpriseEdition.ts +649 -0
  18. package/Server/Enterprise/EnterpriseFeature.ts +48 -0
  19. package/Server/Enterprise/EnterpriseLicenseSnapshot.ts +192 -0
  20. package/Server/Enterprise/EnterpriseServerModule.ts +233 -0
  21. package/Server/EnvironmentConfig.ts +147 -2
  22. package/Server/Infrastructure/Postgres/SchemaMigrations/1793900000000-AddEnterpriseEditionFirstSeenAt.ts +25 -0
  23. package/Server/Infrastructure/Postgres/SchemaMigrations/1794100000000-AddSloLabelAndOwnerRules.ts +248 -0
  24. package/Server/Infrastructure/Postgres/SchemaMigrations/1794200000000-AddSloMonitorRuleMonitorType.ts +19 -0
  25. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +6 -0
  26. package/Server/Middleware/UserAuthorization.ts +38 -16
  27. package/Server/Services/AuditLogService.ts +84 -1079
  28. package/Server/Services/DatabaseService.ts +10 -0
  29. package/Server/Services/EnterpriseLicenseService.ts +38 -0
  30. package/Server/Services/GlobalConfigService.ts +80 -1
  31. package/Server/Services/Index.ts +4 -0
  32. package/Server/Services/MonitorProbeService.ts +116 -20
  33. package/Server/Services/MonitorService.ts +59 -6
  34. package/Server/Services/MonitorStatusTimelineService.ts +284 -0
  35. package/Server/Services/MonitorTemplateService.ts +26 -0
  36. package/Server/Services/ProjectService.ts +284 -0
  37. package/Server/Services/RumSessionPinService.ts +25 -6
  38. package/Server/Services/ServiceLevelObjectiveLabelRuleEngineService.ts +385 -0
  39. package/Server/Services/ServiceLevelObjectiveLabelRuleService.ts +51 -0
  40. package/Server/Services/ServiceLevelObjectiveMonitorRuleEngineService.ts +92 -16
  41. package/Server/Services/ServiceLevelObjectiveMonitorRuleService.ts +36 -1
  42. package/Server/Services/ServiceLevelObjectiveOwnerRuleEngineService.ts +521 -0
  43. package/Server/Services/ServiceLevelObjectiveOwnerRuleService.ts +51 -0
  44. package/Server/Services/ServiceLevelObjectiveService.ts +28 -0
  45. package/Server/Services/StatusPagePrivateUserService.ts +7 -3
  46. package/Server/Services/StatusPageService.ts +78 -1
  47. package/Server/Services/TeamMemberService.ts +11 -0
  48. package/Server/Services/TeamService.ts +10 -0
  49. package/Server/Services/UserService.ts +10 -17
  50. package/Server/Types/Database/Permissions/CreatePermission.ts +15 -0
  51. package/Server/Types/Database/Permissions/EditionPermission.ts +208 -18
  52. package/Server/Types/Database/Permissions/TablePermission.ts +10 -3
  53. package/Server/Types/Database/Permissions/UpdatePermission.ts +29 -0
  54. package/Server/Types/Markdown.ts +41 -0
  55. package/Server/Types/Workflow/Components/Telegram/SendMessageToChat.ts +27 -1
  56. package/Server/Utils/AI/Toolbox/SloTools.ts +1 -0
  57. package/Server/Utils/CommunityEditionSsoReport.ts +361 -0
  58. package/Server/Utils/EditionEnforcement.ts +233 -0
  59. package/Server/Utils/FrontendEnvironment.ts +41 -2
  60. package/Server/Utils/InstanceHealth/RedisHealth.ts +12 -277
  61. package/Server/Utils/Monitor/AffectedResourceList.ts +148 -0
  62. package/Server/Utils/Monitor/Criteria/CompareCriteria.ts +1 -1
  63. package/Server/Utils/Monitor/Criteria/EvaluateOverTime.ts +10 -1
  64. package/Server/Utils/Monitor/Criteria/MetricMonitorCriteria.ts +1 -1
  65. package/Server/Utils/Monitor/MonitorCriteriaEvaluator.ts +720 -465
  66. package/Server/Utils/Monitor/MonitoringIntervalValidator.ts +116 -0
  67. package/Server/Utils/Monitor/RootCauseList.ts +139 -0
  68. package/Server/Utils/Rules/RuleRun/RuleRunRegistry.ts +28 -0
  69. package/Server/Utils/Slo/SloRulePatternValidator.ts +42 -0
  70. package/Server/Utils/Workspace/Slack/Slack.ts +423 -10
  71. package/Tests/App/Accounts/LoginPasskey.test.tsx +18 -0
  72. package/Tests/App/Accounts/LoginSsoEdition.test.tsx +616 -0
  73. package/Tests/App/AdminDashboard/AdminAuthenticationSsoEdition.test.tsx +217 -0
  74. package/Tests/App/AdminDashboard/AdminEnterprisePluginPage.test.tsx +357 -0
  75. package/Tests/App/AdminDashboard/EnterpriseLicensesShell.test.tsx +214 -0
  76. package/Tests/App/AdminDashboard/GlobalSSOEnterpriseShells.test.tsx +271 -0
  77. package/Tests/App/AdminDashboard/HealthShells.test.tsx +659 -0
  78. package/Tests/App/Dashboard/AuditLogsAndComplianceShells.test.tsx +572 -0
  79. package/Tests/App/Dashboard/EnterpriseFeatureUpgrade.test.tsx +547 -0
  80. package/Tests/App/Dashboard/EnterprisePluginPage.test.tsx +667 -0
  81. package/Tests/App/Dashboard/FeedFilterSortIntegration.test.tsx +1632 -0
  82. package/Tests/App/Dashboard/FeedOptionsLocales.test.ts +250 -0
  83. package/Tests/App/Dashboard/FeedOrdering.test.ts +279 -9
  84. package/Tests/App/Dashboard/IdentityEnterpriseShells.test.tsx +319 -0
  85. package/Tests/App/Dashboard/InvestigationFeedRefresh.test.tsx +60 -1
  86. package/Tests/App/Dashboard/InvestigationPanel.test.tsx +594 -3
  87. package/Tests/App/Dashboard/OnboardingSsoEmptyState.test.tsx +185 -0
  88. package/Tests/App/Dashboard/ProductOrientation.test.tsx +646 -0
  89. package/Tests/App/Dashboard/ResourceFeed.test.tsx +612 -2
  90. package/Tests/App/Dashboard/ResourceFeedPageWiring.test.ts +30 -0
  91. package/Tests/App/Dashboard/ResourceFeedPagesFilterSort.test.tsx +1202 -0
  92. package/Tests/App/Dashboard/ScheduledMaintenanceFeedRefresh.test.tsx +52 -1
  93. package/Tests/App/Dashboard/SecurityEventConnectionDiagnostics.test.tsx +45 -9
  94. package/Tests/App/Dashboard/SecurityEventDetailPanel.test.tsx +399 -0
  95. package/Tests/App/Dashboard/SecurityEventListRow.test.tsx +214 -0
  96. package/Tests/App/Dashboard/SecurityEventsEmptyState.test.tsx +1 -83
  97. package/Tests/App/Dashboard/SecurityEventsNavTabs.test.tsx +248 -0
  98. package/Tests/App/Dashboard/SecurityEventsViewer.test.tsx +1203 -0
  99. package/Tests/App/Dashboard/SloFeed.test.tsx +106 -1
  100. package/Tests/App/Dashboard/SloMonitorRuleCriteria.test.tsx +566 -0
  101. package/Tests/App/Dashboard/SloNavigationWiring.test.tsx +6 -4
  102. package/Tests/App/Dashboard/SloNoticeBanner.test.tsx +186 -0
  103. package/Tests/App/Dashboard/SloOverviewKpiStrip.test.tsx +388 -44
  104. package/Tests/App/Dashboard/SloOverviewLayout.test.tsx +613 -0
  105. package/Tests/App/Dashboard/UserEmailCallSites.test.tsx +11 -91
  106. package/Tests/App/StatusPage/StatusPageSsoEmptyState.test.tsx +319 -0
  107. package/Tests/Helpers/RefreshAwareApiScan.ts +757 -0
  108. package/Tests/Helpers/TenantScopedRequestScan.ts +515 -0
  109. package/Tests/Models/DatabaseModels/ResourceFeedModels.test.ts +0 -8
  110. package/Tests/Models/DatabaseModels/SloLabelAndOwnerRuleModels.test.ts +404 -0
  111. package/Tests/Models/DatabaseModels/SloOverhaulModels.test.ts +17 -1
  112. package/Tests/Models/DatabaseModels/StaticRuleCriteriaInheritance.test.ts +4 -2
  113. package/Tests/Scripts/GenerateServiceWorker.test.ts +931 -0
  114. package/Tests/Server/API/BaseAPICreateItemDoesNotMutateModel.test.ts +130 -0
  115. package/Tests/Server/API/GlobalConfigLicense.test.ts +742 -497
  116. package/Tests/Server/API/OnCallReadinessAPI.test.ts +35 -909
  117. package/Tests/Server/API/SsoProviderListingsEdition.test.ts +432 -0
  118. package/Tests/Server/API/TeamMemberLeaveScimLockEdition.test.ts +252 -0
  119. package/Tests/Server/Enterprise/EnterpriseEdition.test.ts +824 -0
  120. package/Tests/Server/Enterprise/EnterpriseFeatureActive.test.ts +643 -0
  121. package/Tests/Server/Enterprise/EnterpriseLicenseSnapshot.test.ts +294 -0
  122. package/Tests/Server/Enterprise/EnterpriseModelFeatureMap.test.ts +93 -0
  123. package/Tests/Server/Enterprise/EnterpriseOnlyModulesLiveInEe.test.ts +582 -0
  124. package/Tests/Server/Enterprise/EnterpriseServerModule.test.ts +247 -0
  125. package/Tests/Server/Enterprise/FakeEnterpriseModule.ts +502 -0
  126. package/Tests/Server/Enterprise/TestBillingFlag.ts +70 -0
  127. package/Tests/Server/EnvironmentConfigEnterpriseEdition.test.ts +314 -0
  128. package/Tests/Server/Infrastructure/ContainerBootConfiguration.test.ts +289 -0
  129. package/Tests/Server/Infrastructure/E2EClickHouseFixtureAccess.test.ts +5 -1
  130. package/Tests/Server/Infrastructure/Postgres/AddConfigurableRuleCriteriaMigration.test.ts +3 -0
  131. package/Tests/Server/Infrastructure/Postgres/AddSloLabelAndOwnerRulesMigration.test.ts +407 -0
  132. package/Tests/Server/Infrastructure/Postgres/AddSloMonitorRuleMonitorTypeMigration.test.ts +171 -0
  133. package/Tests/Server/Infrastructure/Postgres/SloProductOverhaulMigration.test.ts +88 -4
  134. package/Tests/Server/Middleware/UserAuthorization.test.ts +37 -2
  135. package/Tests/Server/Middleware/UserAuthorizationEditionEnforcement.test.ts +516 -0
  136. package/Tests/Server/Services/AuditLogService.test.ts +460 -990
  137. package/Tests/Server/Services/CreateAndReadResponsesKeepIds.test.ts +263 -0
  138. package/Tests/Server/Services/DatabaseServiceRuleCriteriaValidation.test.ts +104 -0
  139. package/Tests/Server/Services/EnterpriseLicenseServiceKeyGeneration.test.ts +151 -0
  140. package/Tests/Server/Services/GlobalConfigServiceLicenseColumns.test.ts +357 -0
  141. package/Tests/Server/Services/MonitorDestinationInfoIPv6.test.ts +101 -0
  142. package/Tests/Server/Services/MonitorProbeServiceIntervalScheduling.test.ts +333 -0
  143. package/Tests/Server/Services/MonitorStatusTimelineDailyAggregates.test.ts +303 -0
  144. package/Tests/Server/Services/ProjectServiceAuditLogLicense.test.ts +701 -0
  145. package/Tests/Server/Services/ProjectServiceAuditLogSettingsCache.test.ts +31 -35
  146. package/Tests/Server/Services/RuleRun/LabelRuleEnginesGroupBRun.test.ts +48 -1
  147. package/Tests/Server/Services/RuleRun/OwnerRuleEnginesGroupBRun.test.ts +30 -0
  148. package/Tests/Server/Services/ScimPushGroupsTeamLocksEdition.test.ts +431 -0
  149. package/Tests/Server/Services/ServiceLevelObjectiveLabelAndOwnerRuleEngines.test.ts +1170 -0
  150. package/Tests/Server/Services/ServiceLevelObjectiveLabelAndOwnerRuleServices.test.ts +172 -0
  151. package/Tests/Server/Services/ServiceLevelObjectiveMonitorRuleEngineService.test.ts +323 -0
  152. package/Tests/Server/Services/ServiceLevelObjectiveMonitorRuleService.test.ts +115 -0
  153. package/Tests/Server/Services/ServiceLevelObjectiveMonitorRuleTriggers.test.ts +21 -2
  154. package/Tests/Server/Services/ServiceLevelObjectiveMonitorTypePostgres.test.ts +480 -0
  155. package/Tests/Server/Services/ServiceLevelObjectiveService.test.ts +162 -0
  156. package/Tests/Server/Services/SsoRequirementReadMasking.test.ts +419 -0
  157. package/Tests/Server/Services/SsoRequirementWriteGuard.test.ts +769 -0
  158. package/Tests/Server/Services/StaticRuleCriteriaRuntimeCoverage.test.ts +45 -6
  159. package/Tests/Server/Services/StatusPagePrivateUserInvitationPolicy.test.ts +94 -0
  160. package/Tests/Server/Services/UserAuthenticationService.test.ts +35 -0
  161. package/Tests/Server/Services/UserServiceSeatLimit.test.ts +94 -56
  162. package/Tests/Server/Types/Database/FeedEventTypeFilterQuery.test.ts +745 -0
  163. package/Tests/Server/Types/Database/Permissions/EditionPermission.test.ts +1823 -0
  164. package/Tests/Server/Types/Markdown.test.ts +183 -1
  165. package/Tests/Server/Types/Workflow/Components/ApiComponentSsrf.test.ts +49 -0
  166. package/Tests/Server/Types/Workflow/Components/TelegramSendMessageToChat.test.ts +331 -0
  167. package/Tests/Server/Utils/AI/SloTools.test.ts +10 -0
  168. package/Tests/Server/Utils/CommunityEditionSsoReport.test.ts +565 -0
  169. package/Tests/Server/Utils/EditionEnforcement.test.ts +303 -0
  170. package/Tests/Server/Utils/FrontendEnvironment.test.ts +367 -0
  171. package/Tests/Server/Utils/InstanceHealth/RedisHealth.test.ts +38 -418
  172. package/Tests/Server/Utils/Monitor/AffectedResourceList.test.ts +518 -0
  173. package/Tests/Server/Utils/Monitor/Criteria/EvaluateOverTime.test.ts +24 -4
  174. package/Tests/Server/Utils/Monitor/Criteria/MetricMonitorCriteriaAnomalyUnits.test.ts +1 -1
  175. package/Tests/Server/Utils/Monitor/MonitorCriteriaEvaluator.test.ts +1339 -96
  176. package/Tests/Server/Utils/Monitor/MonitorCriteriaEvaluatorBreachingSamples.test.ts +1101 -0
  177. package/Tests/Server/Utils/Monitor/MonitorCriteriaEvaluatorMetricUnits.test.ts +106 -80
  178. package/Tests/Server/Utils/Monitor/MonitoringIntervalValidator.test.ts +188 -0
  179. package/Tests/Server/Utils/Monitor/RootCauseList.test.ts +252 -0
  180. package/Tests/Server/Utils/Rules/RuleRun/RuleRunPermission.test.ts +154 -0
  181. package/Tests/Server/Utils/SSRFProtection.test.ts +111 -0
  182. package/Tests/Server/Utils/Slo/SloRulePatternValidator.test.ts +67 -0
  183. package/Tests/Server/Utils/VM/VMRunnerSsrf.test.ts +213 -0
  184. package/Tests/Server/Utils/Workspace/Slack/SlackMarkdownSectionSplit.test.ts +1209 -0
  185. package/Tests/Types/API/HostnameFromAuthority.test.ts +20 -10
  186. package/Tests/Types/API/HostnameIPv6.test.ts +149 -0
  187. package/Tests/Types/API/Route.test.ts +56 -0
  188. package/Tests/Types/API/URLSchemeLikePath.test.ts +304 -0
  189. package/Tests/Types/Database/CanonicalModelInstance.test.ts +190 -0
  190. package/Tests/UI/Components/EditionLabelLapseCopy.ts +104 -0
  191. package/Tests/UI/Components/EditionLabelLicenseManagerWiring.test.tsx +254 -0
  192. package/Tests/UI/Components/EditionLabelLicenseRefresh.test.tsx +84 -178
  193. package/Tests/UI/Components/EditionLabelLicenseStatus.test.tsx +1586 -0
  194. package/Tests/UI/Components/EditionLabelLicenseWritesGuard.test.tsx +157 -0
  195. package/Tests/UI/Components/FeedOptions.test.ts +1404 -0
  196. package/Tests/UI/Components/FeedOptionsButton.test.tsx +2603 -0
  197. package/Tests/UI/Components/Graphs/DayUptimeGraph.test.tsx +49 -2
  198. package/Tests/UI/Components/Icon.test.tsx +26 -0
  199. package/Tests/UI/Components/MarkdownConverters.test.ts +684 -0
  200. package/Tests/UI/Components/ModelListEmptyState.test.tsx +289 -0
  201. package/Tests/UI/Components/RuleCriteria/RuleCriteriaModelTable.test.tsx +3 -3
  202. package/Tests/UI/Components/TelemetryViewer/TelemetryViewerEmptyContent.test.tsx +131 -0
  203. package/Tests/UI/Components/useFeedItemsViewKey.test.tsx +1017 -0
  204. package/Tests/UI/Components/useFeedOptions.test.tsx +1107 -0
  205. package/Tests/UI/EsbuildEnterpriseAlias.test.ts +1127 -0
  206. package/Tests/Utils/HostAddressUtil.test.ts +138 -0
  207. package/Tests/Utils/LabelRuleImportExport.test.ts +102 -0
  208. package/Tests/Utils/Monitor/MonitorDestinationUtil.test.ts +313 -0
  209. package/Tests/Utils/Monitor/MonitoringIntervalUtil.test.ts +304 -0
  210. package/Tests/Utils/Slo/SloDuration.test.ts +115 -24
  211. package/Tests/Utils/Slo/SloHealth.test.ts +93 -10
  212. package/Tests/Utils/Slo/SloMonitorRuleCriteria.test.ts +109 -0
  213. package/Tests/Utils/Slo/SloOverviewText.test.ts +64 -0
  214. package/Tests/Utils/StatusPage/UptimeDailyAggregateUtil.test.ts +248 -0
  215. package/Types/API/Hostname.ts +63 -16
  216. package/Types/API/Route.ts +19 -2
  217. package/Types/API/URL.ts +26 -2
  218. package/Types/Database/AccessControl/ColumnAccessControl.ts +19 -7
  219. package/Types/Database/AccessControl/ColumnBillingAccessControl.ts +19 -7
  220. package/Types/Database/AccessControl/OwnerOnlyColumn.ts +15 -6
  221. package/Types/Database/CanonicalModelInstance.ts +102 -0
  222. package/Types/Database/TableColumn.ts +20 -6
  223. package/Types/EnterpriseLicense/EnterpriseLicensePeriods.ts +29 -0
  224. package/Types/IP/IPv6.ts +6 -1
  225. package/Types/Monitor/MetricMonitor/MetricCriteriaContext.ts +6 -5
  226. package/Types/Monitor/MetricMonitor/MetricMonitorResponse.ts +9 -0
  227. package/Types/Monitor/MonitorStep.ts +6 -1
  228. package/Types/Monitor/ProxmoxAlertTemplates.ts +1 -1
  229. package/Types/Permission.ts +90 -0
  230. package/Types/Rules/RuleCriteriaFieldRegistry.ts +11 -0
  231. package/Types/Rules/RuleRun.ts +4 -0
  232. package/Types/StatusPage/UptimeDailyAggregate.ts +110 -0
  233. package/UI/Components/EditionLabel/EditionLabel.tsx +796 -1195
  234. package/UI/Components/EditionLabel/LicenseManager.ts +119 -0
  235. package/UI/Components/Feed/FeedOptions.ts +427 -0
  236. package/UI/Components/Feed/FeedOptionsButton.tsx +692 -0
  237. package/UI/Components/Feed/useFeedItems.ts +28 -9
  238. package/UI/Components/Feed/useFeedOptions.ts +225 -0
  239. package/UI/Components/Graphs/DayUptimeGraph.tsx +123 -15
  240. package/UI/Components/Icon/Icon.tsx +1 -1
  241. package/UI/Components/Markdown.tsx/MarkdownConverters.ts +0 -0
  242. package/UI/Components/ModelList/ModelList.tsx +11 -1
  243. package/UI/Components/MonitorGraphs/Uptime.tsx +69 -0
  244. package/UI/Components/TelemetryViewer/TelemetryViewer.tsx +28 -12
  245. package/UI/esbuild-enterprise.js +263 -0
  246. package/Utils/EnterpriseLicense/EnterpriseLicenseUsage.ts +7 -2
  247. package/Utils/HostAddressUtil.ts +94 -0
  248. package/Utils/LabelRuleImportExport.ts +27 -9
  249. package/Utils/Monitor/MetricValueFormatter.ts +2 -2
  250. package/Utils/Monitor/MonitorDestinationUtil.ts +157 -0
  251. package/Utils/Monitor/MonitoringIntervalUtil.ts +436 -0
  252. package/Utils/Rules/MonitorTypeRuleCriteria.ts +31 -0
  253. package/Utils/Slo/SloDuration.ts +22 -6
  254. package/Utils/Slo/SloHealth.ts +8 -7
  255. package/Utils/Slo/SloMonitorRuleCriteria.ts +33 -1
  256. package/Utils/Slo/SloOverviewText.ts +33 -0
  257. package/Utils/Slo/SloProjection.ts +4 -3
  258. package/Utils/StatusPage/UptimeDailyAggregateUtil.ts +192 -0
  259. package/build/dist/Models/AnalyticsModels/AuditLog.js +23 -15
  260. package/build/dist/Models/AnalyticsModels/AuditLog.js.map +1 -1
  261. package/build/dist/Models/DatabaseModels/GlobalConfig.js +25 -0
  262. package/build/dist/Models/DatabaseModels/GlobalConfig.js.map +1 -1
  263. package/build/dist/Models/DatabaseModels/Index.js +4 -0
  264. package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
  265. package/build/dist/Models/DatabaseModels/Monitor.js +2 -2
  266. package/build/dist/Models/DatabaseModels/Monitor.js.map +1 -1
  267. package/build/dist/Models/DatabaseModels/MonitorTemplate.js +2 -1
  268. package/build/dist/Models/DatabaseModels/MonitorTemplate.js.map +1 -1
  269. package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveFeed.js +2 -0
  270. package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveFeed.js.map +1 -1
  271. package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveLabelRule.js +530 -0
  272. package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveLabelRule.js.map +1 -0
  273. package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveMonitorRule.js +39 -4
  274. package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveMonitorRule.js.map +1 -1
  275. package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveOwnerRule.js +612 -0
  276. package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveOwnerRule.js.map +1 -0
  277. package/build/dist/Server/API/BaseAPI.js +26 -5
  278. package/build/dist/Server/API/BaseAPI.js.map +1 -1
  279. package/build/dist/Server/API/GlobalConfigAPI.js +148 -344
  280. package/build/dist/Server/API/GlobalConfigAPI.js.map +1 -1
  281. package/build/dist/Server/API/ProjectOIDC.js +24 -16
  282. package/build/dist/Server/API/ProjectOIDC.js.map +1 -1
  283. package/build/dist/Server/API/ProjectSSO.js +24 -16
  284. package/build/dist/Server/API/ProjectSSO.js.map +1 -1
  285. package/build/dist/Server/API/StatusPageAPI.js +93 -43
  286. package/build/dist/Server/API/StatusPageAPI.js.map +1 -1
  287. package/build/dist/Server/API/TeamMemberAPI.js +8 -1
  288. package/build/dist/Server/API/TeamMemberAPI.js.map +1 -1
  289. package/build/dist/Server/Enterprise/EnterpriseEdition.js +466 -0
  290. package/build/dist/Server/Enterprise/EnterpriseEdition.js.map +1 -0
  291. package/build/dist/Server/Enterprise/EnterpriseFeature.js +39 -0
  292. package/build/dist/Server/Enterprise/EnterpriseFeature.js.map +1 -0
  293. package/build/dist/Server/Enterprise/EnterpriseLicenseSnapshot.js +70 -0
  294. package/build/dist/Server/Enterprise/EnterpriseLicenseSnapshot.js.map +1 -0
  295. package/build/dist/Server/Enterprise/EnterpriseServerModule.js +84 -0
  296. package/build/dist/Server/Enterprise/EnterpriseServerModule.js.map +1 -0
  297. package/build/dist/Server/EnvironmentConfig.js +84 -2
  298. package/build/dist/Server/EnvironmentConfig.js.map +1 -1
  299. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1793900000000-AddEnterpriseEditionFirstSeenAt.js +18 -0
  300. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1793900000000-AddEnterpriseEditionFirstSeenAt.js.map +1 -0
  301. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1794100000000-AddSloLabelAndOwnerRules.js +93 -0
  302. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1794100000000-AddSloLabelAndOwnerRules.js.map +1 -0
  303. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1794200000000-AddSloMonitorRuleMonitorType.js +12 -0
  304. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1794200000000-AddSloMonitorRuleMonitorType.js.map +1 -0
  305. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +6 -0
  306. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  307. package/build/dist/Server/Middleware/UserAuthorization.js +30 -11
  308. package/build/dist/Server/Middleware/UserAuthorization.js.map +1 -1
  309. package/build/dist/Server/Services/AuditLogService.js +71 -740
  310. package/build/dist/Server/Services/AuditLogService.js.map +1 -1
  311. package/build/dist/Server/Services/DatabaseService.js +7 -0
  312. package/build/dist/Server/Services/DatabaseService.js.map +1 -1
  313. package/build/dist/Server/Services/EnterpriseLicenseService.js +34 -0
  314. package/build/dist/Server/Services/EnterpriseLicenseService.js.map +1 -1
  315. package/build/dist/Server/Services/GlobalConfigService.js +63 -0
  316. package/build/dist/Server/Services/GlobalConfigService.js.map +1 -1
  317. package/build/dist/Server/Services/Index.js +4 -0
  318. package/build/dist/Server/Services/Index.js.map +1 -1
  319. package/build/dist/Server/Services/MonitorProbeService.js +90 -17
  320. package/build/dist/Server/Services/MonitorProbeService.js.map +1 -1
  321. package/build/dist/Server/Services/MonitorService.js +48 -6
  322. package/build/dist/Server/Services/MonitorService.js.map +1 -1
  323. package/build/dist/Server/Services/MonitorStatusTimelineService.js +242 -0
  324. package/build/dist/Server/Services/MonitorStatusTimelineService.js.map +1 -1
  325. package/build/dist/Server/Services/MonitorTemplateService.js +16 -0
  326. package/build/dist/Server/Services/MonitorTemplateService.js.map +1 -1
  327. package/build/dist/Server/Services/ProjectService.js +214 -0
  328. package/build/dist/Server/Services/ProjectService.js.map +1 -1
  329. package/build/dist/Server/Services/RumSessionPinService.js +24 -6
  330. package/build/dist/Server/Services/RumSessionPinService.js.map +1 -1
  331. package/build/dist/Server/Services/ServiceLevelObjectiveLabelRuleEngineService.js +295 -0
  332. package/build/dist/Server/Services/ServiceLevelObjectiveLabelRuleEngineService.js.map +1 -0
  333. package/build/dist/Server/Services/ServiceLevelObjectiveLabelRuleService.js +56 -0
  334. package/build/dist/Server/Services/ServiceLevelObjectiveLabelRuleService.js.map +1 -0
  335. package/build/dist/Server/Services/ServiceLevelObjectiveMonitorRuleEngineService.js +59 -14
  336. package/build/dist/Server/Services/ServiceLevelObjectiveMonitorRuleEngineService.js.map +1 -1
  337. package/build/dist/Server/Services/ServiceLevelObjectiveMonitorRuleService.js +22 -1
  338. package/build/dist/Server/Services/ServiceLevelObjectiveMonitorRuleService.js.map +1 -1
  339. package/build/dist/Server/Services/ServiceLevelObjectiveOwnerRuleEngineService.js +400 -0
  340. package/build/dist/Server/Services/ServiceLevelObjectiveOwnerRuleEngineService.js.map +1 -0
  341. package/build/dist/Server/Services/ServiceLevelObjectiveOwnerRuleService.js +56 -0
  342. package/build/dist/Server/Services/ServiceLevelObjectiveOwnerRuleService.js.map +1 -0
  343. package/build/dist/Server/Services/ServiceLevelObjectiveService.js +21 -0
  344. package/build/dist/Server/Services/ServiceLevelObjectiveService.js.map +1 -1
  345. package/build/dist/Server/Services/StatusPagePrivateUserService.js +7 -3
  346. package/build/dist/Server/Services/StatusPagePrivateUserService.js.map +1 -1
  347. package/build/dist/Server/Services/StatusPageService.js +71 -0
  348. package/build/dist/Server/Services/StatusPageService.js.map +1 -1
  349. package/build/dist/Server/Services/TeamMemberService.js +10 -0
  350. package/build/dist/Server/Services/TeamMemberService.js.map +1 -1
  351. package/build/dist/Server/Services/TeamService.js +9 -0
  352. package/build/dist/Server/Services/TeamService.js.map +1 -1
  353. package/build/dist/Server/Services/UserService.js +10 -16
  354. package/build/dist/Server/Services/UserService.js.map +1 -1
  355. package/build/dist/Server/Types/Database/Permissions/CreatePermission.js +10 -0
  356. package/build/dist/Server/Types/Database/Permissions/CreatePermission.js.map +1 -1
  357. package/build/dist/Server/Types/Database/Permissions/EditionPermission.js +154 -14
  358. package/build/dist/Server/Types/Database/Permissions/EditionPermission.js.map +1 -1
  359. package/build/dist/Server/Types/Database/Permissions/TablePermission.js +10 -3
  360. package/build/dist/Server/Types/Database/Permissions/TablePermission.js.map +1 -1
  361. package/build/dist/Server/Types/Database/Permissions/UpdatePermission.js +17 -0
  362. package/build/dist/Server/Types/Database/Permissions/UpdatePermission.js.map +1 -1
  363. package/build/dist/Server/Types/Markdown.js +31 -0
  364. package/build/dist/Server/Types/Markdown.js.map +1 -1
  365. package/build/dist/Server/Types/Workflow/Components/Telegram/SendMessageToChat.js +20 -1
  366. package/build/dist/Server/Types/Workflow/Components/Telegram/SendMessageToChat.js.map +1 -1
  367. package/build/dist/Server/Utils/AI/Toolbox/SloTools.js +1 -0
  368. package/build/dist/Server/Utils/AI/Toolbox/SloTools.js.map +1 -1
  369. package/build/dist/Server/Utils/CommunityEditionSsoReport.js +223 -0
  370. package/build/dist/Server/Utils/CommunityEditionSsoReport.js.map +1 -0
  371. package/build/dist/Server/Utils/EditionEnforcement.js +187 -0
  372. package/build/dist/Server/Utils/EditionEnforcement.js.map +1 -0
  373. package/build/dist/Server/Utils/FrontendEnvironment.js +31 -2
  374. package/build/dist/Server/Utils/FrontendEnvironment.js.map +1 -1
  375. package/build/dist/Server/Utils/InstanceHealth/RedisHealth.js +6 -193
  376. package/build/dist/Server/Utils/InstanceHealth/RedisHealth.js.map +1 -1
  377. package/build/dist/Server/Utils/Monitor/AffectedResourceList.js +67 -0
  378. package/build/dist/Server/Utils/Monitor/AffectedResourceList.js.map +1 -0
  379. package/build/dist/Server/Utils/Monitor/Criteria/CompareCriteria.js +1 -1
  380. package/build/dist/Server/Utils/Monitor/Criteria/EvaluateOverTime.js +8 -1
  381. package/build/dist/Server/Utils/Monitor/Criteria/EvaluateOverTime.js.map +1 -1
  382. package/build/dist/Server/Utils/Monitor/Criteria/MetricMonitorCriteria.js +1 -1
  383. package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js +585 -367
  384. package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js.map +1 -1
  385. package/build/dist/Server/Utils/Monitor/MonitoringIntervalValidator.js +88 -0
  386. package/build/dist/Server/Utils/Monitor/MonitoringIntervalValidator.js.map +1 -0
  387. package/build/dist/Server/Utils/Monitor/RootCauseList.js +101 -0
  388. package/build/dist/Server/Utils/Monitor/RootCauseList.js.map +1 -0
  389. package/build/dist/Server/Utils/Rules/RuleRun/RuleRunRegistry.js +28 -0
  390. package/build/dist/Server/Utils/Rules/RuleRun/RuleRunRegistry.js.map +1 -1
  391. package/build/dist/Server/Utils/Slo/SloRulePatternValidator.js +28 -0
  392. package/build/dist/Server/Utils/Slo/SloRulePatternValidator.js.map +1 -0
  393. package/build/dist/Server/Utils/Workspace/Slack/Slack.js +331 -11
  394. package/build/dist/Server/Utils/Workspace/Slack/Slack.js.map +1 -1
  395. package/build/dist/Types/API/Hostname.js +59 -11
  396. package/build/dist/Types/API/Hostname.js.map +1 -1
  397. package/build/dist/Types/API/Route.js +18 -2
  398. package/build/dist/Types/API/Route.js.map +1 -1
  399. package/build/dist/Types/API/URL.js +23 -2
  400. package/build/dist/Types/API/URL.js.map +1 -1
  401. package/build/dist/Types/Database/AccessControl/ColumnAccessControl.js +19 -7
  402. package/build/dist/Types/Database/AccessControl/ColumnAccessControl.js.map +1 -1
  403. package/build/dist/Types/Database/AccessControl/ColumnBillingAccessControl.js +19 -7
  404. package/build/dist/Types/Database/AccessControl/ColumnBillingAccessControl.js.map +1 -1
  405. package/build/dist/Types/Database/AccessControl/OwnerOnlyColumn.js +13 -6
  406. package/build/dist/Types/Database/AccessControl/OwnerOnlyColumn.js.map +1 -1
  407. package/build/dist/Types/Database/CanonicalModelInstance.js +88 -0
  408. package/build/dist/Types/Database/CanonicalModelInstance.js.map +1 -0
  409. package/build/dist/Types/Database/TableColumn.js +19 -6
  410. package/build/dist/Types/Database/TableColumn.js.map +1 -1
  411. package/build/dist/Types/EnterpriseLicense/EnterpriseLicensePeriods.js +28 -0
  412. package/build/dist/Types/EnterpriseLicense/EnterpriseLicensePeriods.js.map +1 -0
  413. package/build/dist/Types/IP/IPv6.js +6 -1
  414. package/build/dist/Types/IP/IPv6.js.map +1 -1
  415. package/build/dist/Types/Monitor/MonitorStep.js +5 -0
  416. package/build/dist/Types/Monitor/MonitorStep.js.map +1 -1
  417. package/build/dist/Types/Monitor/ProxmoxAlertTemplates.js +1 -1
  418. package/build/dist/Types/Permission.js +84 -0
  419. package/build/dist/Types/Permission.js.map +1 -1
  420. package/build/dist/Types/Rules/RuleCriteriaFieldRegistry.js +11 -0
  421. package/build/dist/Types/Rules/RuleCriteriaFieldRegistry.js.map +1 -1
  422. package/build/dist/Types/Rules/RuleRun.js +4 -0
  423. package/build/dist/Types/Rules/RuleRun.js.map +1 -1
  424. package/build/dist/Types/StatusPage/UptimeDailyAggregate.js +32 -0
  425. package/build/dist/Types/StatusPage/UptimeDailyAggregate.js.map +1 -0
  426. package/build/dist/UI/Components/EditionLabel/EditionLabel.js +414 -585
  427. package/build/dist/UI/Components/EditionLabel/EditionLabel.js.map +1 -1
  428. package/build/dist/UI/Components/EditionLabel/LicenseManager.js +2 -0
  429. package/build/dist/UI/Components/EditionLabel/LicenseManager.js.map +1 -0
  430. package/build/dist/UI/Components/Feed/FeedOptions.js +235 -0
  431. package/build/dist/UI/Components/Feed/FeedOptions.js.map +1 -0
  432. package/build/dist/UI/Components/Feed/FeedOptionsButton.js +346 -0
  433. package/build/dist/UI/Components/Feed/FeedOptionsButton.js.map +1 -0
  434. package/build/dist/UI/Components/Feed/useFeedItems.js +17 -7
  435. package/build/dist/UI/Components/Feed/useFeedItems.js.map +1 -1
  436. package/build/dist/UI/Components/Feed/useFeedOptions.js +130 -0
  437. package/build/dist/UI/Components/Feed/useFeedOptions.js.map +1 -0
  438. package/build/dist/UI/Components/Graphs/DayUptimeGraph.js +90 -17
  439. package/build/dist/UI/Components/Graphs/DayUptimeGraph.js.map +1 -1
  440. package/build/dist/UI/Components/Icon/Icon.js +1 -1
  441. package/build/dist/UI/Components/Icon/Icon.js.map +1 -1
  442. package/build/dist/UI/Components/Markdown.tsx/MarkdownConverters.js +0 -0
  443. package/build/dist/UI/Components/Markdown.tsx/MarkdownConverters.js.map +1 -1
  444. package/build/dist/UI/Components/ModelList/ModelList.js +4 -1
  445. package/build/dist/UI/Components/ModelList/ModelList.js.map +1 -1
  446. package/build/dist/UI/Components/MonitorGraphs/Uptime.js +42 -1
  447. package/build/dist/UI/Components/MonitorGraphs/Uptime.js.map +1 -1
  448. package/build/dist/UI/Components/TelemetryViewer/TelemetryViewer.js +2 -2
  449. package/build/dist/UI/Components/TelemetryViewer/TelemetryViewer.js.map +1 -1
  450. package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseUsage.js +6 -2
  451. package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseUsage.js.map +1 -1
  452. package/build/dist/Utils/HostAddressUtil.js +80 -0
  453. package/build/dist/Utils/HostAddressUtil.js.map +1 -0
  454. package/build/dist/Utils/LabelRuleImportExport.js +22 -6
  455. package/build/dist/Utils/LabelRuleImportExport.js.map +1 -1
  456. package/build/dist/Utils/Monitor/MetricValueFormatter.js +2 -2
  457. package/build/dist/Utils/Monitor/MonitorDestinationUtil.js +127 -0
  458. package/build/dist/Utils/Monitor/MonitorDestinationUtil.js.map +1 -0
  459. package/build/dist/Utils/Monitor/MonitoringIntervalUtil.js +374 -0
  460. package/build/dist/Utils/Monitor/MonitoringIntervalUtil.js.map +1 -0
  461. package/build/dist/Utils/Rules/MonitorTypeRuleCriteria.js +18 -0
  462. package/build/dist/Utils/Rules/MonitorTypeRuleCriteria.js.map +1 -0
  463. package/build/dist/Utils/Slo/SloDuration.js +13 -5
  464. package/build/dist/Utils/Slo/SloDuration.js.map +1 -1
  465. package/build/dist/Utils/Slo/SloHealth.js +8 -7
  466. package/build/dist/Utils/Slo/SloHealth.js.map +1 -1
  467. package/build/dist/Utils/Slo/SloMonitorRuleCriteria.js +16 -1
  468. package/build/dist/Utils/Slo/SloMonitorRuleCriteria.js.map +1 -1
  469. package/build/dist/Utils/Slo/SloOverviewText.js +16 -0
  470. package/build/dist/Utils/Slo/SloOverviewText.js.map +1 -1
  471. package/build/dist/Utils/Slo/SloProjection.js.map +1 -1
  472. package/build/dist/Utils/StatusPage/UptimeDailyAggregateUtil.js +148 -0
  473. package/build/dist/Utils/StatusPage/UptimeDailyAggregateUtil.js.map +1 -0
  474. package/jest.config.json +3 -1
  475. package/package.json +1 -1
  476. package/test-setup.sh +103 -34
  477. package/tsconfig.json +13 -0
  478. package/Server/API/EnterpriseLicenseAPI.ts +0 -925
  479. package/Server/API/TeamComplianceAPI.ts +0 -158
  480. package/Server/Middleware/SCIMAuthorization.ts +0 -141
  481. package/Server/Services/TeamComplianceService.ts +0 -733
  482. package/Server/Utils/EnterpriseLicense/EnterpriseLicenseSeatUtil.ts +0 -186
  483. package/Server/Utils/InstanceHealth/PostgresHealth.ts +0 -286
  484. package/Tests/App/AdminDashboard/EnterpriseLicenseInstanceActivity.test.tsx +0 -451
  485. package/Tests/App/Dashboard/AuditLogsTable.test.tsx +0 -598
  486. package/Tests/App/Dashboard/SecurityEventsExplorer.test.tsx +0 -761
  487. package/Tests/App/Dashboard/SecurityEventsSideMenu.test.tsx +0 -247
  488. package/Tests/App/Dashboard/SecurityEventsTableColumns.test.tsx +0 -382
  489. package/Tests/App/Dashboard/SecurityEventsVolumeChart.test.tsx +0 -321
  490. package/Tests/Server/API/EnterpriseLicenseReportUserCount.test.ts +0 -1851
  491. package/Tests/Server/Middleware/SCIMAuthorization.test.ts +0 -525
  492. package/Tests/Server/Services/TeamComplianceServiceBehaviour.test.ts +0 -1845
  493. package/Tests/Server/Utils/EnterpriseLicense/EnterpriseLicenseSeatUtil.test.ts +0 -495
  494. package/Tests/Server/Utils/InstanceHealth/PostgresHealth.test.ts +0 -337
  495. package/Tests/Utils/EnterpriseLicenseSeats.test.ts +0 -576
  496. package/Tests/Utils/EnterpriseLicenseSync.test.ts +0 -568
  497. package/Utils/EnterpriseLicense/EnterpriseLicenseSeats.ts +0 -287
  498. package/Utils/EnterpriseLicense/EnterpriseLicenseSync.ts +0 -244
  499. package/build/dist/Server/API/EnterpriseLicenseAPI.js +0 -646
  500. package/build/dist/Server/API/EnterpriseLicenseAPI.js.map +0 -1
  501. package/build/dist/Server/API/TeamComplianceAPI.js +0 -111
  502. package/build/dist/Server/API/TeamComplianceAPI.js.map +0 -1
  503. package/build/dist/Server/Middleware/SCIMAuthorization.js +0 -124
  504. package/build/dist/Server/Middleware/SCIMAuthorization.js.map +0 -1
  505. package/build/dist/Server/Services/TeamComplianceService.js +0 -537
  506. package/build/dist/Server/Services/TeamComplianceService.js.map +0 -1
  507. package/build/dist/Server/Utils/EnterpriseLicense/EnterpriseLicenseSeatUtil.js +0 -145
  508. package/build/dist/Server/Utils/EnterpriseLicense/EnterpriseLicenseSeatUtil.js.map +0 -1
  509. package/build/dist/Server/Utils/InstanceHealth/PostgresHealth.js +0 -194
  510. package/build/dist/Server/Utils/InstanceHealth/PostgresHealth.js.map +0 -1
  511. package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseSeats.js +0 -168
  512. package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseSeats.js.map +0 -1
  513. package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseSync.js +0 -174
  514. package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseSync.js.map +0 -1
@@ -0,0 +1,745 @@
1
+ import QueryPermission from "../../../../Server/Types/Database/Permissions/QueryPermission";
2
+ import Query from "../../../../Server/Types/Database/Query";
3
+ import QueryUtil from "../../../../Server/Types/Database/QueryUtil";
4
+ import AlertEpisodeFeed, {
5
+ AlertEpisodeFeedEventType,
6
+ } from "../../../../Models/DatabaseModels/AlertEpisodeFeed";
7
+ import AlertFeed, {
8
+ AlertFeedEventType,
9
+ } from "../../../../Models/DatabaseModels/AlertFeed";
10
+ import CephClusterFeed, {
11
+ CephClusterFeedEventType,
12
+ } from "../../../../Models/DatabaseModels/CephClusterFeed";
13
+ import CloudResourceFeed, {
14
+ CloudResourceFeedEventType,
15
+ } from "../../../../Models/DatabaseModels/CloudResourceFeed";
16
+ import BaseModel, {
17
+ DatabaseBaseModelType,
18
+ } from "../../../../Models/DatabaseModels/DatabaseBaseModel/DatabaseBaseModel";
19
+ import DockerHostFeed, {
20
+ DockerHostFeedEventType,
21
+ } from "../../../../Models/DatabaseModels/DockerHostFeed";
22
+ import DockerSwarmClusterFeed, {
23
+ DockerSwarmClusterFeedEventType,
24
+ } from "../../../../Models/DatabaseModels/DockerSwarmClusterFeed";
25
+ import HostFeed, {
26
+ HostFeedEventType,
27
+ } from "../../../../Models/DatabaseModels/HostFeed";
28
+ import IncidentEpisodeFeed, {
29
+ IncidentEpisodeFeedEventType,
30
+ } from "../../../../Models/DatabaseModels/IncidentEpisodeFeed";
31
+ import IncidentFeed, {
32
+ IncidentFeedEventType,
33
+ } from "../../../../Models/DatabaseModels/IncidentFeed";
34
+ import KubernetesClusterFeed, {
35
+ KubernetesClusterFeedEventType,
36
+ } from "../../../../Models/DatabaseModels/KubernetesClusterFeed";
37
+ import MonitorFeed, {
38
+ MonitorFeedEventType,
39
+ } from "../../../../Models/DatabaseModels/MonitorFeed";
40
+ import OnCallDutyPolicyFeed, {
41
+ OnCallDutyPolicyFeedEventType,
42
+ } from "../../../../Models/DatabaseModels/OnCallDutyPolicyFeed";
43
+ import PodmanHostFeed, {
44
+ PodmanHostFeedEventType,
45
+ } from "../../../../Models/DatabaseModels/PodmanHostFeed";
46
+ import ProxmoxClusterFeed, {
47
+ ProxmoxClusterFeedEventType,
48
+ } from "../../../../Models/DatabaseModels/ProxmoxClusterFeed";
49
+ import ScheduledMaintenanceFeed, {
50
+ ScheduledMaintenanceFeedEventType,
51
+ } from "../../../../Models/DatabaseModels/ScheduledMaintenanceFeed";
52
+ import ServiceFeed, {
53
+ ServiceFeedEventType,
54
+ } from "../../../../Models/DatabaseModels/ServiceFeed";
55
+ import ServiceLevelObjectiveFeed, {
56
+ ServiceLevelObjectiveFeedEventType,
57
+ } from "../../../../Models/DatabaseModels/ServiceLevelObjectiveFeed";
58
+ import VMwareVCenterFeed, {
59
+ VMwareVCenterFeedEventType,
60
+ } from "../../../../Models/DatabaseModels/VMwareVCenterFeed";
61
+ import { ColumnAccessControl } from "../../../../Types/BaseDatabase/AccessControl";
62
+ import DatabaseCommonInteractionProps from "../../../../Types/BaseDatabase/DatabaseCommonInteractionProps";
63
+ import Includes from "../../../../Types/BaseDatabase/Includes";
64
+ import SortOrder from "../../../../Types/BaseDatabase/SortOrder";
65
+ import { TableColumnMetadata } from "../../../../Types/Database/TableColumn";
66
+ import TableColumnType from "../../../../Types/Database/TableColumnType";
67
+ import NotAuthorizedException from "../../../../Types/Exception/NotAuthorizedException";
68
+ import { JSONObject } from "../../../../Types/JSON";
69
+ import JSONFunctions from "../../../../Types/JSONFunctions";
70
+ import ObjectID from "../../../../Types/ObjectID";
71
+ import Permission, { UserPermission } from "../../../../Types/Permission";
72
+ import {
73
+ FEED_SORT_ORDER_OPTIONS,
74
+ FeedOptions,
75
+ getFeedEventTypeQuery,
76
+ } from "../../../../UI/Components/Feed/FeedOptions";
77
+ import { FindOperator } from "typeorm";
78
+ import { describe, expect, it, test } from "@jest/globals";
79
+ import fs from "fs";
80
+ import path from "path";
81
+
82
+ /*
83
+ * The server half of the dashboard feeds' "Filter & Sort" button.
84
+ *
85
+ * Filtering and sorting are done by the API, never in the browser: a feed is
86
+ * read a window at a time, so the dashboard sends
87
+ *
88
+ * query: { <resource id column>: ObjectID,
89
+ * <event type column>: new Includes([...checked event types]) }
90
+ * sort: { postedAt: "ASC" | "DESC" }
91
+ *
92
+ * to the feed model's list endpoint. Every link of that trip fails for the
93
+ * reader and not for the developer - a 403 or an unfiltered feed looks the same
94
+ * as "no activity" until somebody ticks a box on a feed they happen to watch.
95
+ * So each link is asserted here, for every feed model, rather than for the one
96
+ * a reviewer happened to click:
97
+ *
98
+ * 1. the query and the sort survive the wire: JSONFunctions.serialize on the
99
+ * client, JSON over HTTP, JSONFunctions.deserialize in BaseAPI. An Includes
100
+ * that came back as a plain `{ _type, value }` object would reach TypeORM
101
+ * as an equality against an object and match nothing.
102
+ * 2. QueryPermission lets every reader of the feed filter on both columns - a
103
+ * WHERE clause is held to the same read standard as a SELECT.
104
+ * 3. which is only true while the event type column's read list is the
105
+ * table's read list: a reader who may open the feed but not read that
106
+ * column would see the feed and get a 403 the moment they filter it.
107
+ * 4. QueryUtil turns the Includes into a real `IN (...)` over bound
108
+ * parameters, instead of letting it through as an object.
109
+ *
110
+ * The table below is checked against the model directory, so a feed model
111
+ * added later cannot ship its Filter & Sort button without these guarantees.
112
+ */
113
+
114
+ const MODELS_DIRECTORY: string = path.resolve(
115
+ __dirname,
116
+ "..",
117
+ "..",
118
+ "..",
119
+ "..",
120
+ "Models",
121
+ "DatabaseModels",
122
+ );
123
+
124
+ /*
125
+ * What makes a model a filterable activity feed: an exported event type enum,
126
+ * which is what the checklist offers. The calendar feeds and ThreatIntelFeed
127
+ * are also named *Feed but have no such enum, and no Filter & Sort button.
128
+ */
129
+ const FEED_EVENT_TYPE_ENUM: RegExp = /export enum (\w+FeedEventType)\b/;
130
+
131
+ interface FeedModelEntry {
132
+ // The model's file name in Models/DatabaseModels, without ".ts".
133
+ file: string;
134
+ // The event type enum that file exports.
135
+ enumName: string;
136
+ modelType: DatabaseBaseModelType;
137
+ // Every value of that enum - the checklist the dashboard offers.
138
+ eventTypes: Array<string>;
139
+ // The foreign key the dashboard scopes the feed by.
140
+ resourceIdColumn: string;
141
+ // The column the event type filter is applied to.
142
+ eventTypeColumn: string;
143
+ }
144
+
145
+ /*
146
+ * The column names are the ones the dashboard sends: the feed components
147
+ * under App/FeatureSet/Dashboard/src/Components (Incident, Alert, their
148
+ * episodes, Monitor, On-Call Policy, Scheduled Maintenance) name them in their
149
+ * getList queries, and every resource feed page passes them to ResourceFeed as
150
+ * resourceIdColumn / eventTypeColumn (SloFeed through getSloResourceFeedProps).
151
+ */
152
+ const FEED_MODELS: Array<FeedModelEntry> = [
153
+ {
154
+ file: "AlertEpisodeFeed",
155
+ enumName: "AlertEpisodeFeedEventType",
156
+ modelType: AlertEpisodeFeed,
157
+ eventTypes: Object.values(AlertEpisodeFeedEventType),
158
+ resourceIdColumn: "alertEpisodeId",
159
+ eventTypeColumn: "alertEpisodeFeedEventType",
160
+ },
161
+ {
162
+ file: "AlertFeed",
163
+ enumName: "AlertFeedEventType",
164
+ modelType: AlertFeed,
165
+ eventTypes: Object.values(AlertFeedEventType),
166
+ resourceIdColumn: "alertId",
167
+ eventTypeColumn: "alertFeedEventType",
168
+ },
169
+ {
170
+ file: "CephClusterFeed",
171
+ enumName: "CephClusterFeedEventType",
172
+ modelType: CephClusterFeed,
173
+ eventTypes: Object.values(CephClusterFeedEventType),
174
+ resourceIdColumn: "cephClusterId",
175
+ eventTypeColumn: "cephClusterFeedEventType",
176
+ },
177
+ {
178
+ file: "CloudResourceFeed",
179
+ enumName: "CloudResourceFeedEventType",
180
+ modelType: CloudResourceFeed,
181
+ eventTypes: Object.values(CloudResourceFeedEventType),
182
+ resourceIdColumn: "cloudResourceId",
183
+ eventTypeColumn: "cloudResourceFeedEventType",
184
+ },
185
+ {
186
+ file: "DockerHostFeed",
187
+ enumName: "DockerHostFeedEventType",
188
+ modelType: DockerHostFeed,
189
+ eventTypes: Object.values(DockerHostFeedEventType),
190
+ resourceIdColumn: "dockerHostId",
191
+ eventTypeColumn: "dockerHostFeedEventType",
192
+ },
193
+ {
194
+ file: "DockerSwarmClusterFeed",
195
+ enumName: "DockerSwarmClusterFeedEventType",
196
+ modelType: DockerSwarmClusterFeed,
197
+ eventTypes: Object.values(DockerSwarmClusterFeedEventType),
198
+ resourceIdColumn: "dockerSwarmClusterId",
199
+ eventTypeColumn: "dockerSwarmClusterFeedEventType",
200
+ },
201
+ {
202
+ file: "HostFeed",
203
+ enumName: "HostFeedEventType",
204
+ modelType: HostFeed,
205
+ eventTypes: Object.values(HostFeedEventType),
206
+ resourceIdColumn: "hostId",
207
+ eventTypeColumn: "hostFeedEventType",
208
+ },
209
+ {
210
+ file: "IncidentEpisodeFeed",
211
+ enumName: "IncidentEpisodeFeedEventType",
212
+ modelType: IncidentEpisodeFeed,
213
+ eventTypes: Object.values(IncidentEpisodeFeedEventType),
214
+ resourceIdColumn: "incidentEpisodeId",
215
+ eventTypeColumn: "incidentEpisodeFeedEventType",
216
+ },
217
+ {
218
+ file: "IncidentFeed",
219
+ enumName: "IncidentFeedEventType",
220
+ modelType: IncidentFeed,
221
+ eventTypes: Object.values(IncidentFeedEventType),
222
+ resourceIdColumn: "incidentId",
223
+ eventTypeColumn: "incidentFeedEventType",
224
+ },
225
+ {
226
+ file: "KubernetesClusterFeed",
227
+ enumName: "KubernetesClusterFeedEventType",
228
+ modelType: KubernetesClusterFeed,
229
+ eventTypes: Object.values(KubernetesClusterFeedEventType),
230
+ resourceIdColumn: "kubernetesClusterId",
231
+ eventTypeColumn: "kubernetesClusterFeedEventType",
232
+ },
233
+ {
234
+ file: "MonitorFeed",
235
+ enumName: "MonitorFeedEventType",
236
+ modelType: MonitorFeed,
237
+ eventTypes: Object.values(MonitorFeedEventType),
238
+ resourceIdColumn: "monitorId",
239
+ eventTypeColumn: "monitorFeedEventType",
240
+ },
241
+ {
242
+ file: "OnCallDutyPolicyFeed",
243
+ enumName: "OnCallDutyPolicyFeedEventType",
244
+ modelType: OnCallDutyPolicyFeed,
245
+ eventTypes: Object.values(OnCallDutyPolicyFeedEventType),
246
+ resourceIdColumn: "onCallDutyPolicyId",
247
+ eventTypeColumn: "onCallDutyPolicyFeedEventType",
248
+ },
249
+ {
250
+ file: "PodmanHostFeed",
251
+ enumName: "PodmanHostFeedEventType",
252
+ modelType: PodmanHostFeed,
253
+ eventTypes: Object.values(PodmanHostFeedEventType),
254
+ resourceIdColumn: "podmanHostId",
255
+ eventTypeColumn: "podmanHostFeedEventType",
256
+ },
257
+ {
258
+ file: "ProxmoxClusterFeed",
259
+ enumName: "ProxmoxClusterFeedEventType",
260
+ modelType: ProxmoxClusterFeed,
261
+ eventTypes: Object.values(ProxmoxClusterFeedEventType),
262
+ resourceIdColumn: "proxmoxClusterId",
263
+ eventTypeColumn: "proxmoxClusterFeedEventType",
264
+ },
265
+ {
266
+ file: "ScheduledMaintenanceFeed",
267
+ enumName: "ScheduledMaintenanceFeedEventType",
268
+ modelType: ScheduledMaintenanceFeed,
269
+ eventTypes: Object.values(ScheduledMaintenanceFeedEventType),
270
+ resourceIdColumn: "scheduledMaintenanceId",
271
+ eventTypeColumn: "scheduledMaintenanceFeedEventType",
272
+ },
273
+ {
274
+ file: "ServiceFeed",
275
+ enumName: "ServiceFeedEventType",
276
+ modelType: ServiceFeed,
277
+ eventTypes: Object.values(ServiceFeedEventType),
278
+ resourceIdColumn: "serviceId",
279
+ eventTypeColumn: "serviceFeedEventType",
280
+ },
281
+ {
282
+ file: "ServiceLevelObjectiveFeed",
283
+ enumName: "ServiceLevelObjectiveFeedEventType",
284
+ modelType: ServiceLevelObjectiveFeed,
285
+ eventTypes: Object.values(ServiceLevelObjectiveFeedEventType),
286
+ resourceIdColumn: "serviceLevelObjectiveId",
287
+ eventTypeColumn: "serviceLevelObjectiveFeedEventType",
288
+ },
289
+ {
290
+ file: "VMwareVCenterFeed",
291
+ enumName: "VMwareVCenterFeedEventType",
292
+ modelType: VMwareVCenterFeed,
293
+ eventTypes: Object.values(VMwareVCenterFeedEventType),
294
+ resourceIdColumn: "vmwareVCenterId",
295
+ eventTypeColumn: "vmwareVCenterFeedEventType",
296
+ },
297
+ ];
298
+
299
+ // The column every feed sorts by, whichever way the reader picked.
300
+ const SORT_COLUMN: string = "postedAt";
301
+
302
+ const projectId: ObjectID = ObjectID.generate();
303
+ const userId: ObjectID = ObjectID.generate();
304
+ const resourceId: ObjectID = ObjectID.generate();
305
+
306
+ type DiscoverFeedModelsFunction = () => Array<string>;
307
+
308
+ // "<file>:<enum name>" for every model file that exports a feed event type enum.
309
+ const discoverFeedModels: DiscoverFeedModelsFunction = (): Array<string> => {
310
+ const discovered: Array<string> = [];
311
+
312
+ for (const fileName of fs.readdirSync(MODELS_DIRECTORY)) {
313
+ if (!fileName.endsWith("Feed.ts")) {
314
+ continue;
315
+ }
316
+
317
+ const source: string = fs.readFileSync(
318
+ path.join(MODELS_DIRECTORY, fileName),
319
+ "utf8",
320
+ );
321
+ const match: RegExpExecArray | null = FEED_EVENT_TYPE_ENUM.exec(source);
322
+
323
+ if (match) {
324
+ discovered.push(`${fileName.replace(/\.ts$/, "")}:${match[1]}`);
325
+ }
326
+ }
327
+
328
+ return discovered.sort();
329
+ };
330
+
331
+ type GetCheckedEventTypesFunction = (entry: FeedModelEntry) => Array<string>;
332
+
333
+ /*
334
+ * Two different event types - the first and the last the checklist offers -
335
+ * so an IN that collapsed to its first value, or a round trip that dropped one,
336
+ * shows up as a missing value rather than passing on a list of one.
337
+ */
338
+ const getCheckedEventTypes: GetCheckedEventTypesFunction = (
339
+ entry: FeedModelEntry,
340
+ ): Array<string> => {
341
+ return [entry.eventTypes[0]!, entry.eventTypes[entry.eventTypes.length - 1]!];
342
+ };
343
+
344
+ type GetClientQueryFunction = (
345
+ entry: FeedModelEntry,
346
+ eventTypes: Array<string>,
347
+ ) => JSONObject;
348
+
349
+ /*
350
+ * Built the way every dashboard feed builds it - the resource id, spread with
351
+ * getFeedEventTypeQuery - so a change to the client's filter shape is judged
352
+ * by the server-side checks below rather than by a copy of the old shape. The
353
+ * first assertion in each test pins that shape.
354
+ */
355
+ const getClientQuery: GetClientQueryFunction = (
356
+ entry: FeedModelEntry,
357
+ eventTypes: Array<string>,
358
+ ): JSONObject => {
359
+ const options: FeedOptions = {
360
+ sortOrder: SortOrder.Ascending,
361
+ eventTypes: eventTypes,
362
+ };
363
+
364
+ return {
365
+ [entry.resourceIdColumn]: resourceId,
366
+ ...(getFeedEventTypeQuery<JSONObject>(
367
+ entry.eventTypeColumn,
368
+ options,
369
+ ) as unknown as JSONObject),
370
+ } as JSONObject;
371
+ };
372
+
373
+ type OverTheWireFunction = (value: JSONObject) => JSONObject;
374
+
375
+ // ModelAPI.getList's serialize, the HTTP body, then BaseAPI.getList's deserialize.
376
+ const overTheWire: OverTheWireFunction = (value: JSONObject): JSONObject => {
377
+ const body: string = JSON.stringify(JSONFunctions.serialize(value));
378
+
379
+ return JSONFunctions.deserialize(JSON.parse(body) as JSONObject);
380
+ };
381
+
382
+ type GetServerQueryFunction = (
383
+ entry: FeedModelEntry,
384
+ eventTypes: Array<string>,
385
+ ) => JSONObject;
386
+
387
+ // The query as BaseAPI hands it to the permission layer and the service.
388
+ const getServerQuery: GetServerQueryFunction = (
389
+ entry: FeedModelEntry,
390
+ eventTypes: Array<string>,
391
+ ): JSONObject => {
392
+ return overTheWire(getClientQuery(entry, eventTypes));
393
+ };
394
+
395
+ type MakePropsFunction = (
396
+ tenantPermissions: Array<Permission>,
397
+ ) => DatabaseCommonInteractionProps;
398
+
399
+ /*
400
+ * A signed-in project member holding exactly `tenantPermissions`, with the
401
+ * global permissions AccessTokenService grants every user. Fresh per call:
402
+ * DatabaseCommonInteractionPropsUtil MUTATES the props it is handed (it pushes
403
+ * Public and CurrentUser onto the global list), so a shared object would carry
404
+ * state from one assertion to the next.
405
+ */
406
+ const makeProps: MakePropsFunction = (
407
+ tenantPermissions: Array<Permission>,
408
+ ): DatabaseCommonInteractionProps => {
409
+ return {
410
+ userId: userId,
411
+ tenantId: projectId,
412
+ userGlobalAccessPermission: {
413
+ projectIds: [projectId],
414
+ globalPermissions: [
415
+ Permission.Public,
416
+ Permission.User,
417
+ Permission.CurrentUser,
418
+ ],
419
+ _type: "UserGlobalAccessPermission",
420
+ },
421
+ userTenantAccessPermission: {
422
+ [projectId.toString()]: {
423
+ projectId: projectId,
424
+ permissions: tenantPermissions.map(
425
+ (permission: Permission): UserPermission => {
426
+ return {
427
+ permission: permission,
428
+ labelIds: [],
429
+ isBlockPermission: false,
430
+ _type: "UserPermission",
431
+ };
432
+ },
433
+ ),
434
+ _type: "UserTenantAccessPermission",
435
+ },
436
+ },
437
+ };
438
+ };
439
+
440
+ type CheckQueryFunction = (
441
+ entry: FeedModelEntry,
442
+ query: JSONObject,
443
+ props: DatabaseCommonInteractionProps,
444
+ ) => void;
445
+
446
+ const checkQuery: CheckQueryFunction = (
447
+ entry: FeedModelEntry,
448
+ query: JSONObject,
449
+ props: DatabaseCommonInteractionProps,
450
+ ): void => {
451
+ QueryPermission.checkQueryPermission<BaseModel>(
452
+ entry.modelType,
453
+ query as unknown as Query<BaseModel>,
454
+ props,
455
+ );
456
+ };
457
+
458
+ type SortedFunction = (permissions: Array<Permission>) => Array<Permission>;
459
+
460
+ // Read lists are sets; the order they are written in means nothing.
461
+ const sorted: SortedFunction = (
462
+ permissions: Array<Permission>,
463
+ ): Array<Permission> => {
464
+ return [...permissions].sort();
465
+ };
466
+
467
+ type RawOperatorParametersFunction = (
468
+ operator: FindOperator<unknown>,
469
+ ) => Record<string, unknown>;
470
+
471
+ const rawOperatorParameters: RawOperatorParametersFunction = (
472
+ operator: FindOperator<unknown>,
473
+ ): Record<string, unknown> => {
474
+ return (operator.objectLiteralParameters || {}) as Record<string, unknown>;
475
+ };
476
+
477
+ type RawOperatorSqlFunction = (
478
+ operator: FindOperator<unknown>,
479
+ alias: string,
480
+ ) => string;
481
+
482
+ const rawOperatorSql: RawOperatorSqlFunction = (
483
+ operator: FindOperator<unknown>,
484
+ alias: string,
485
+ ): string => {
486
+ const getSql: ((alias: string) => string) | undefined = operator.getSql;
487
+
488
+ if (!getSql) {
489
+ throw new Error("Expected a Raw FindOperator with a SQL generator.");
490
+ }
491
+
492
+ return getSql(alias);
493
+ };
494
+
495
+ describe("feed event type filter - the table of feed models", () => {
496
+ /*
497
+ * Without this, a new feed model gets the dashboard's Filter & Sort button
498
+ * (it only needs an enum and a column name) while nothing below checks that
499
+ * its server side can actually answer it.
500
+ */
501
+ it("covers exactly the feed models that export an event type enum", () => {
502
+ const covered: Array<string> = FEED_MODELS.map(
503
+ (entry: FeedModelEntry): string => {
504
+ return `${entry.file}:${entry.enumName}`;
505
+ },
506
+ ).sort();
507
+
508
+ expect(covered).toEqual(discoverFeedModels());
509
+ });
510
+
511
+ test.each(FEED_MODELS)(
512
+ "$file: the entry is the model its file declares, with a checklist to filter",
513
+ (entry: FeedModelEntry) => {
514
+ // A mis-paired import would test one model's columns against another's.
515
+ expect(new entry.modelType().tableName).toBe(entry.file);
516
+
517
+ // Two distinct string values to filter by - the enum is string-valued.
518
+ expect(new Set(getCheckedEventTypes(entry)).size).toBe(2);
519
+
520
+ for (const eventType of entry.eventTypes) {
521
+ expect(typeof eventType).toBe("string");
522
+ }
523
+ },
524
+ );
525
+ });
526
+
527
+ describe("feed event type filter - over the wire", () => {
528
+ test.each(FEED_MODELS)(
529
+ "$file: the query survives serialize -> JSON -> deserialize",
530
+ (entry: FeedModelEntry) => {
531
+ const eventTypes: Array<string> = getCheckedEventTypes(entry);
532
+ const clientQuery: JSONObject = getClientQuery(entry, eventTypes);
533
+
534
+ // The shape the dashboard sends.
535
+ expect(clientQuery[entry.eventTypeColumn]).toBeInstanceOf(Includes);
536
+ expect(clientQuery[entry.eventTypeColumn]).toEqual(
537
+ new Includes(eventTypes),
538
+ );
539
+
540
+ const serverQuery: JSONObject = overTheWire(clientQuery);
541
+
542
+ expect(Object.keys(serverQuery).sort()).toEqual(
543
+ [entry.resourceIdColumn, entry.eventTypeColumn].sort(),
544
+ );
545
+
546
+ /*
547
+ * A real Includes, not a `{ _type: "Includes", value }` object -
548
+ * QueryUtil dispatches on instanceof, and anything else reaches TypeORM
549
+ * as an equality against an object.
550
+ */
551
+ const includes: Includes = serverQuery[
552
+ entry.eventTypeColumn
553
+ ] as unknown as Includes;
554
+
555
+ expect(includes).toBeInstanceOf(Includes);
556
+ expect(includes.values).toEqual(eventTypes);
557
+
558
+ // ...and the feed is still scoped to its one resource.
559
+ const serverResourceId: ObjectID = serverQuery[
560
+ entry.resourceIdColumn
561
+ ] as unknown as ObjectID;
562
+
563
+ expect(serverResourceId).toBeInstanceOf(ObjectID);
564
+ expect(serverResourceId.toString()).toBe(resourceId.toString());
565
+ },
566
+ );
567
+
568
+ /*
569
+ * Every sort order the control offers, and "Oldest first" in particular:
570
+ * TypeORM's `order` takes the literal "ASC" / "DESC", so the value has to
571
+ * arrive as that string and not as anything wrapped.
572
+ */
573
+ test.each(FEED_MODELS)(
574
+ "$file: every offered sort order survives the round trip on a real Date column",
575
+ (entry: FeedModelEntry) => {
576
+ expect(
577
+ overTheWire({
578
+ [SORT_COLUMN]: SortOrder.Ascending,
579
+ })[SORT_COLUMN],
580
+ ).toBe("ASC");
581
+
582
+ for (const option of FEED_SORT_ORDER_OPTIONS) {
583
+ expect(
584
+ overTheWire({
585
+ [SORT_COLUMN]: option.value,
586
+ }),
587
+ ).toEqual({
588
+ [SORT_COLUMN]: option.value,
589
+ });
590
+ }
591
+
592
+ // ORDER BY a column the model does not have is a 500, not a no-op.
593
+ const model: BaseModel = new entry.modelType();
594
+
595
+ expect(model.getTableColumns().columns).toContain(SORT_COLUMN);
596
+ expect(model.getTableColumnMetadata(SORT_COLUMN).type).toBe(
597
+ TableColumnType.Date,
598
+ );
599
+ },
600
+ );
601
+ });
602
+
603
+ describe("feed event type filter - query permissions", () => {
604
+ test.each(FEED_MODELS)(
605
+ "$file: every reader of the feed may filter it by event type",
606
+ (entry: FeedModelEntry) => {
607
+ const readers: Array<Permission> = new entry.modelType()
608
+ .readRecordPermissions;
609
+
610
+ expect(readers.length).toBeGreaterThan(0);
611
+
612
+ const query: JSONObject = getServerQuery(
613
+ entry,
614
+ getCheckedEventTypes(entry),
615
+ );
616
+
617
+ for (const permission of readers) {
618
+ expect(() => {
619
+ return checkQuery(entry, query, makeProps([permission]));
620
+ }).not.toThrow();
621
+ }
622
+ },
623
+ );
624
+
625
+ /*
626
+ * The counterpart: the gate really evaluates the event type column, so the
627
+ * test above passes because every reader may read it rather than because
628
+ * nothing was checked. A signed-in user with no role in the project holds
629
+ * only the global permissions, none of which reads a feed.
630
+ */
631
+ test.each(FEED_MODELS)(
632
+ "$file: a caller who cannot read the feed may not filter it",
633
+ (entry: FeedModelEntry) => {
634
+ expect(() => {
635
+ return checkQuery(
636
+ entry,
637
+ overTheWire({
638
+ [entry.eventTypeColumn]: new Includes(getCheckedEventTypes(entry)),
639
+ } as unknown as JSONObject),
640
+ makeProps([]),
641
+ );
642
+ }).toThrow(NotAuthorizedException);
643
+ },
644
+ );
645
+
646
+ /*
647
+ * Why the reader loop above holds, stated where it can break. A column read
648
+ * list narrower than the table's is a reader who sees the feed and 403s on
649
+ * the first ticked box; a wider one is a column nobody extra can use.
650
+ */
651
+ test.each(FEED_MODELS)(
652
+ "$file: the event type column is a ShortText column readable by exactly the feed's readers",
653
+ (entry: FeedModelEntry) => {
654
+ const model: BaseModel = new entry.modelType();
655
+
656
+ expect(model.getTableColumns().columns).toContain(entry.eventTypeColumn);
657
+
658
+ const metadata: TableColumnMetadata = model.getTableColumnMetadata(
659
+ entry.eventTypeColumn,
660
+ );
661
+
662
+ expect(metadata.type).toBe(TableColumnType.ShortText);
663
+
664
+ const accessControl: ColumnAccessControl | null =
665
+ model.getColumnAccessControlFor(entry.eventTypeColumn);
666
+
667
+ expect(accessControl).not.toBeNull();
668
+ expect(sorted(accessControl!.read)).toEqual(
669
+ sorted(model.readRecordPermissions),
670
+ );
671
+ },
672
+ );
673
+
674
+ test.each(FEED_MODELS)(
675
+ "$file: the resource id the feed is scoped by is a real ObjectID column",
676
+ (entry: FeedModelEntry) => {
677
+ const model: BaseModel = new entry.modelType();
678
+
679
+ expect(model.getTableColumns().columns).toContain(entry.resourceIdColumn);
680
+ expect(model.getTableColumnMetadata(entry.resourceIdColumn).type).toBe(
681
+ TableColumnType.ObjectID,
682
+ );
683
+ },
684
+ );
685
+ });
686
+
687
+ describe("feed event type filter - QueryUtil.serializeQuery", () => {
688
+ test.each(FEED_MODELS)(
689
+ "$file: the Includes becomes an IN over bound parameters",
690
+ (entry: FeedModelEntry) => {
691
+ const eventTypes: Array<string> = getCheckedEventTypes(entry);
692
+
693
+ // serializeQuery rewrites the query in place, so hand it a copy.
694
+ const serialized: JSONObject = QueryUtil.serializeQuery<BaseModel>(
695
+ entry.modelType,
696
+ {
697
+ ...getServerQuery(entry, eventTypes),
698
+ } as unknown as Query<BaseModel>,
699
+ ) as unknown as JSONObject;
700
+
701
+ const operator: FindOperator<unknown> = serialized[
702
+ entry.eventTypeColumn
703
+ ] as unknown as FindOperator<unknown>;
704
+
705
+ expect(operator).toBeInstanceOf(FindOperator);
706
+ expect(operator).not.toBeInstanceOf(Includes);
707
+ expect(operator.type).toBe("raw");
708
+
709
+ /*
710
+ * One bound list parameter holding both values, and the SQL expands
711
+ * exactly that parameter inside the IN. The parameter name is random, so
712
+ * it is read back rather than assumed; the values never appear in the
713
+ * SQL text itself.
714
+ */
715
+ const parameters: Record<string, unknown> =
716
+ rawOperatorParameters(operator);
717
+ const parameterNames: Array<string> = Object.keys(parameters);
718
+
719
+ expect(parameterNames).toHaveLength(1);
720
+ expect(parameters[parameterNames[0]!]).toEqual(eventTypes);
721
+
722
+ const sql: string = rawOperatorSql(operator, "feed.eventType");
723
+
724
+ expect(sql).toContain(" IN (");
725
+ expect(sql).toContain(`feed.eventType IN (:...${parameterNames[0]})`);
726
+
727
+ for (const eventType of eventTypes) {
728
+ expect(sql).not.toContain(eventType);
729
+ }
730
+
731
+ // The resource scope beside it is still a plain equality on the id.
732
+ const scope: FindOperator<unknown> = serialized[
733
+ entry.resourceIdColumn
734
+ ] as unknown as FindOperator<unknown>;
735
+
736
+ expect(scope).toBeInstanceOf(FindOperator);
737
+ expect(Object.values(rawOperatorParameters(scope))).toEqual([
738
+ resourceId.toString(),
739
+ ]);
740
+ expect(rawOperatorSql(scope, "feed.resourceId")).toContain(
741
+ "feed.resourceId = :",
742
+ );
743
+ },
744
+ );
745
+ });