@oneuptime/common 13.0.6 → 13.0.7

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 (589) hide show
  1. package/Models/DatabaseModels/AIAgentOwnerTeam.ts +6 -0
  2. package/Models/DatabaseModels/AIAgentOwnerUser.ts +6 -0
  3. package/Models/DatabaseModels/Alert.ts +12 -0
  4. package/Models/DatabaseModels/AlertEpisodeOwnerTeam.ts +6 -1
  5. package/Models/DatabaseModels/AlertEpisodeOwnerUser.ts +6 -1
  6. package/Models/DatabaseModels/AlertOwnerTeam.ts +6 -1
  7. package/Models/DatabaseModels/AlertOwnerUser.ts +6 -1
  8. package/Models/DatabaseModels/CephClusterOwnerTeam.ts +6 -0
  9. package/Models/DatabaseModels/CephClusterOwnerUser.ts +6 -0
  10. package/Models/DatabaseModels/CloudResourceOwnerTeam.ts +6 -0
  11. package/Models/DatabaseModels/CloudResourceOwnerUser.ts +6 -0
  12. package/Models/DatabaseModels/DashboardOwnerTeam.ts +6 -1
  13. package/Models/DatabaseModels/DashboardOwnerUser.ts +6 -1
  14. package/Models/DatabaseModels/DatabaseBaseModel/DatabaseBaseModel.ts +8 -0
  15. package/Models/DatabaseModels/DockerHostOwnerTeam.ts +6 -0
  16. package/Models/DatabaseModels/DockerHostOwnerUser.ts +6 -0
  17. package/Models/DatabaseModels/DockerSwarmClusterOwnerTeam.ts +6 -0
  18. package/Models/DatabaseModels/DockerSwarmClusterOwnerUser.ts +6 -0
  19. package/Models/DatabaseModels/HostOwnerTeam.ts +6 -0
  20. package/Models/DatabaseModels/HostOwnerUser.ts +6 -0
  21. package/Models/DatabaseModels/Incident.ts +12 -0
  22. package/Models/DatabaseModels/IncidentEpisodeOwnerTeam.ts +6 -1
  23. package/Models/DatabaseModels/IncidentEpisodeOwnerUser.ts +6 -1
  24. package/Models/DatabaseModels/IncidentOwnerTeam.ts +6 -1
  25. package/Models/DatabaseModels/IncidentOwnerUser.ts +6 -1
  26. package/Models/DatabaseModels/IncidentTemplateOwnerTeam.ts +6 -0
  27. package/Models/DatabaseModels/IncidentTemplateOwnerUser.ts +6 -0
  28. package/Models/DatabaseModels/IncomingCallPolicyOwnerTeam.ts +6 -1
  29. package/Models/DatabaseModels/IncomingCallPolicyOwnerUser.ts +6 -1
  30. package/Models/DatabaseModels/IoTFleetOwnerTeam.ts +6 -0
  31. package/Models/DatabaseModels/IoTFleetOwnerUser.ts +6 -0
  32. package/Models/DatabaseModels/KubernetesClusterOwnerTeam.ts +6 -0
  33. package/Models/DatabaseModels/KubernetesClusterOwnerUser.ts +6 -0
  34. package/Models/DatabaseModels/Monitor.ts +2 -3
  35. package/Models/DatabaseModels/MonitorGroupOwnerTeam.ts +6 -0
  36. package/Models/DatabaseModels/MonitorGroupOwnerUser.ts +6 -0
  37. package/Models/DatabaseModels/MonitorOwnerTeam.ts +6 -1
  38. package/Models/DatabaseModels/MonitorOwnerUser.ts +6 -1
  39. package/Models/DatabaseModels/MonitorTemplate.ts +2 -3
  40. package/Models/DatabaseModels/NetworkDeviceOwnerTeam.ts +6 -0
  41. package/Models/DatabaseModels/NetworkDeviceOwnerUser.ts +6 -0
  42. package/Models/DatabaseModels/OnCallDutyPolicyOwnerTeam.ts +6 -1
  43. package/Models/DatabaseModels/OnCallDutyPolicyOwnerUser.ts +6 -1
  44. package/Models/DatabaseModels/OnCallDutyPolicyScheduleOwnerTeam.ts +6 -1
  45. package/Models/DatabaseModels/OnCallDutyPolicyScheduleOwnerUser.ts +6 -1
  46. package/Models/DatabaseModels/PodmanHostOwnerTeam.ts +6 -0
  47. package/Models/DatabaseModels/PodmanHostOwnerUser.ts +6 -0
  48. package/Models/DatabaseModels/ProbeOwnerTeam.ts +6 -0
  49. package/Models/DatabaseModels/ProbeOwnerUser.ts +6 -0
  50. package/Models/DatabaseModels/ProxmoxClusterOwnerTeam.ts +6 -0
  51. package/Models/DatabaseModels/ProxmoxClusterOwnerUser.ts +6 -0
  52. package/Models/DatabaseModels/RumApplicationOwnerTeam.ts +6 -0
  53. package/Models/DatabaseModels/RumApplicationOwnerUser.ts +6 -0
  54. package/Models/DatabaseModels/RunbookOwnerTeam.ts +6 -1
  55. package/Models/DatabaseModels/RunbookOwnerUser.ts +6 -1
  56. package/Models/DatabaseModels/RunnerOwnerTeam.ts +6 -1
  57. package/Models/DatabaseModels/RunnerOwnerUser.ts +6 -1
  58. package/Models/DatabaseModels/ScheduledMaintenanceOwnerTeam.ts +6 -1
  59. package/Models/DatabaseModels/ScheduledMaintenanceOwnerUser.ts +6 -1
  60. package/Models/DatabaseModels/ScheduledMaintenanceTemplateOwnerTeam.ts +8 -0
  61. package/Models/DatabaseModels/ScheduledMaintenanceTemplateOwnerUser.ts +8 -0
  62. package/Models/DatabaseModels/ServerlessFunctionOwnerTeam.ts +6 -0
  63. package/Models/DatabaseModels/ServerlessFunctionOwnerUser.ts +6 -0
  64. package/Models/DatabaseModels/ServiceLevelObjectiveOwnerTeam.ts +6 -1
  65. package/Models/DatabaseModels/ServiceLevelObjectiveOwnerUser.ts +6 -1
  66. package/Models/DatabaseModels/ServiceOwnerTeam.ts +6 -0
  67. package/Models/DatabaseModels/ServiceOwnerUser.ts +6 -0
  68. package/Models/DatabaseModels/StatusPageOwnerTeam.ts +6 -1
  69. package/Models/DatabaseModels/StatusPageOwnerUser.ts +6 -1
  70. package/Models/DatabaseModels/VMwareVCenterOwnerTeam.ts +6 -0
  71. package/Models/DatabaseModels/VMwareVCenterOwnerUser.ts +6 -0
  72. package/Models/DatabaseModels/WorkflowOwnerTeam.ts +6 -1
  73. package/Models/DatabaseModels/WorkflowOwnerUser.ts +6 -1
  74. package/Scripts/benchmark-fanin-capacity.js +2 -2
  75. package/Server/API/AIAgentDataAPI.ts +1 -1
  76. package/Server/API/AIChatAPI.ts +6 -4
  77. package/Server/API/AIInvestigationAPI.ts +7 -0
  78. package/Server/API/StatusPageAPI.ts +13 -0
  79. package/Server/Infrastructure/Postgres/LocalMigrationGenerationDataSource.ts +1 -1
  80. package/Server/Infrastructure/Postgres/SchemaMigrations/1793500000000-MakeOwnerRowsUnique.ts +1057 -0
  81. package/Server/Infrastructure/Postgres/SchemaMigrations/1793700000000-AddAIInvestigationDecision.ts +25 -0
  82. package/Server/Infrastructure/Postgres/SchemaMigrations/1793800000000-RemoveMonitorDescriptionLengthLimit.ts +31 -0
  83. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +6 -0
  84. package/Server/Infrastructure/Postgres/SchemaMigrations/Readme.md +6 -4
  85. package/Server/Middleware/IdentityRateLimit.ts +34 -1
  86. package/Server/Middleware/PublicDashboardRateLimit.ts +169 -39
  87. package/Server/Services/AlertEpisodeService.ts +13 -34
  88. package/Server/Services/AlertGroupingEngineService.ts +7 -4
  89. package/Server/Services/AlertService.ts +13 -32
  90. package/Server/Services/CephClusterOwnerRuleEngineService.ts +18 -10
  91. package/Server/Services/CloudResourceOwnerRuleEngineService.ts +18 -10
  92. package/Server/Services/DashboardOwnerRuleEngineService.ts +18 -10
  93. package/Server/Services/DatabaseService.ts +101 -1
  94. package/Server/Services/DockerHostOwnerRuleEngineService.ts +18 -10
  95. package/Server/Services/DockerSwarmClusterOwnerRuleEngineService.ts +18 -10
  96. package/Server/Services/HostOwnerRuleEngineService.ts +18 -10
  97. package/Server/Services/IncidentEpisodeOwnerRuleEngineService.ts +6 -4
  98. package/Server/Services/IncidentEpisodeService.ts +15 -75
  99. package/Server/Services/IncidentGroupingEngineService.ts +7 -4
  100. package/Server/Services/IncidentService.ts +13 -32
  101. package/Server/Services/IncidentTemplateService.ts +13 -36
  102. package/Server/Services/IncomingCallPolicyOwnerRuleEngineService.ts +18 -10
  103. package/Server/Services/IoTFleetOwnerRuleEngineService.ts +18 -10
  104. package/Server/Services/KubernetesClusterOwnerRuleEngineService.ts +18 -10
  105. package/Server/Services/MonitorService.ts +13 -32
  106. package/Server/Services/NetworkDeviceOwnerRuleEngineService.ts +18 -10
  107. package/Server/Services/OnCallDutyPolicyOwnerRuleEngineService.ts +18 -10
  108. package/Server/Services/OnCallDutyPolicyScheduleOwnerRuleEngineService.ts +18 -10
  109. package/Server/Services/PodmanHostOwnerRuleEngineService.ts +18 -10
  110. package/Server/Services/ProxmoxClusterOwnerRuleEngineService.ts +18 -10
  111. package/Server/Services/RumApplicationOwnerRuleEngineService.ts +18 -10
  112. package/Server/Services/RunbookOwnerRuleEngineService.ts +18 -10
  113. package/Server/Services/ScheduledMaintenanceService.ts +13 -34
  114. package/Server/Services/ScheduledMaintenanceTemplateService.ts +12 -34
  115. package/Server/Services/ServerlessFunctionOwnerRuleEngineService.ts +18 -10
  116. package/Server/Services/ServiceOwnerRuleEngineService.ts +18 -10
  117. package/Server/Services/StatusPagePrivateUserService.ts +38 -29
  118. package/Server/Services/StatusPagePrivateUserSessionService.ts +49 -1
  119. package/Server/Services/StatusPageService.ts +59 -36
  120. package/Server/Services/UserSessionService.ts +6 -0
  121. package/Server/Services/VMwareVCenterOwnerRuleEngineService.ts +18 -10
  122. package/Server/Services/WorkflowOwnerRuleEngineService.ts +18 -10
  123. package/Server/Static/Brand/README.md +7 -7
  124. package/Server/Static/Vendor/README.md +7 -7
  125. package/Server/Types/Database/Permissions/OwnedScopePermission.ts +18 -9
  126. package/Server/Types/Database/Permissions/OwnerTableRegistry.ts +82 -0
  127. package/Server/Utils/AI/Chat/ChatAgentRunner.ts +21 -8
  128. package/Server/Utils/AI/Chat/ObservabilityChatPrompt.ts +41 -4
  129. package/Server/Utils/AI/CodeFix/CodeAgentWorkspaceGuard.ts +1 -1
  130. package/Server/Utils/AI/CodeFix/CodeFixAgentCompletion.ts +1 -1
  131. package/Server/Utils/AI/SRE/AIInvestigationEngine.ts +13 -5
  132. package/Server/Utils/AI/SRE/AlertInvestigationRunner.ts +53 -13
  133. package/Server/Utils/AI/SRE/IncidentInvestigationRunner.ts +51 -14
  134. package/Server/Utils/AI/SRE/InvestigationEligibility.ts +292 -0
  135. package/Server/Utils/AI/SRE/InvestigationQueue.ts +25 -0
  136. package/Server/Utils/AI/Toolbox/Index.ts +43 -13
  137. package/Server/Utils/AI/Toolbox/ResourceTools.ts +952 -0
  138. package/Server/Utils/AI/Toolbox/RumTools.ts +424 -0
  139. package/Server/Utils/AI/Toolbox/ToolTypes.ts +10 -0
  140. package/Server/Utils/AI/Toolbox/TraceTools.ts +2 -1
  141. package/Server/Utils/Database/PostgresErrorTranslator.ts +14 -0
  142. package/Server/Utils/Monitor/Criteria/CompareCriteria.ts +137 -126
  143. package/Server/Utils/Monitor/Criteria/MetricMonitorCriteria.ts +4 -1
  144. package/Server/Utils/Rules/OwnerRuleAssignment.ts +157 -6
  145. package/Server/Utils/Telemetry/TelemetryEntity.ts +205 -6
  146. package/SslCertificates/GlobalSign.crt +26 -0
  147. package/SslCertificates/Readme.md +3 -0
  148. package/Tests/App/AdminDashboard/EnterpriseLicenseInstanceActivity.test.tsx +451 -0
  149. package/Tests/App/Dashboard/AIInsightsChatPanel.test.tsx +881 -0
  150. package/Tests/App/Dashboard/AIInsightsPageContext.test.ts +458 -0
  151. package/Tests/App/Dashboard/AIInsightsResourceCitations.test.ts +124 -0
  152. package/Tests/App/Dashboard/AIInsightsResourcePageContext.test.ts +798 -0
  153. package/Tests/App/Dashboard/AskAiSuggestedPrompts.test.ts +7 -0
  154. package/Tests/App/Dashboard/DashboardChartWidgetZoom.test.tsx +104 -0
  155. package/Tests/App/Dashboard/DashboardCommandPalette.test.tsx +156 -64
  156. package/Tests/App/Dashboard/DiscoveryScanStatusMessage.test.tsx +970 -0
  157. package/Tests/App/Dashboard/DiscoveryScanWizardValidation.test.tsx +406 -12
  158. package/Tests/App/Dashboard/EmbeddedMetricEventScope.test.tsx +358 -0
  159. package/Tests/App/Dashboard/ErrorPatternEventScope.test.tsx +148 -0
  160. package/Tests/App/Dashboard/EventOverlayAdditionalResourceScope.test.ts +255 -0
  161. package/Tests/App/Dashboard/EventOverlayScope.test.ts +845 -0
  162. package/Tests/App/Dashboard/EventOverlayScopeHook.test.tsx +903 -0
  163. package/Tests/App/Dashboard/ExternalStatusPageCriteriaFilter.test.ts +3 -3
  164. package/Tests/App/Dashboard/InvestigationDrawer.test.tsx +21 -0
  165. package/Tests/App/Dashboard/InvestigationNotStarted.test.tsx +761 -0
  166. package/Tests/App/Dashboard/InvestigationPanel.test.tsx +7 -4
  167. package/Tests/App/Dashboard/InvestigationPanelStatus.test.tsx +15 -7
  168. package/Tests/App/Dashboard/MetricsViewerEventScopeNavigation.test.tsx +264 -0
  169. package/Tests/App/Dashboard/MonitorSummaryTestMonitorButton.test.tsx +342 -0
  170. package/Tests/App/Dashboard/MonitorTestForm.test.tsx +612 -0
  171. package/Tests/App/Dashboard/NavigationSearchKeywords.test.tsx +301 -0
  172. package/Tests/App/Dashboard/ServiceMapGraph.test.tsx +74 -2
  173. package/Tests/App/Dashboard/TextClampLayoutHarness.ts +224 -0
  174. package/Tests/Models/InventoryItemNaming.test.ts +54 -0
  175. package/Tests/Server/API/AIChatRouteAuthorization.test.ts +161 -0
  176. package/Tests/Server/API/AIInvestigationAPI.test.ts +14 -0
  177. package/Tests/Server/API/AIInvestigationAvailabilityAuthorization.test.ts +260 -0
  178. package/Tests/Server/API/EnterpriseLicenseReportUserCount.test.ts +133 -0
  179. package/Tests/Server/API/StatusPageMasterPasswordRateLimit.test.ts +482 -0
  180. package/Tests/Server/EnvironmentConfigOnCallCalendarFeed.test.ts +1 -1
  181. package/Tests/Server/Infrastructure/ClickhouseKeepAliveOptions.test.ts +1 -1
  182. package/Tests/Server/Infrastructure/ContainerBootConfiguration.test.ts +38 -16
  183. package/Tests/Server/Infrastructure/E2EClickHouseFixtureAccess.test.ts +106 -31
  184. package/Tests/Server/Infrastructure/ExampleDockerfiles.test.ts +46 -12
  185. package/Tests/Server/Infrastructure/Postgres/MonitorDescriptionMigration.test.ts +422 -0
  186. package/Tests/Server/Infrastructure/TelemetryExporterDeploymentConfig.test.ts +1 -1
  187. package/Tests/Server/Infrastructure/ValkeyDeploymentConfig.test.ts +25 -4
  188. package/Tests/Server/Middleware/IdentityRateLimit.test.ts +72 -0
  189. package/Tests/Server/Middleware/PublicDashboardRateLimit.test.ts +12 -12
  190. package/Tests/Server/Middleware/PublicDashboardRateLimitStatusPage.test.ts +800 -0
  191. package/Tests/Server/Services/AIInvestigationDecisionPostgres.test.ts +346 -0
  192. package/Tests/Server/Services/AddOwnersIdempotency.test.ts +471 -0
  193. package/Tests/Server/Services/DatabaseServiceAutoOwnerOnCreate.test.ts +250 -0
  194. package/Tests/Server/Services/DatabaseServiceUniqueColumnsTogether.test.ts +622 -0
  195. package/Tests/Server/Services/MonitorDescriptionValidation.test.ts +211 -0
  196. package/Tests/Server/Services/MonitorTemplateDescriptionPropagation.test.ts +269 -0
  197. package/Tests/Server/Services/OwnerRowUniqueness.test.ts +504 -0
  198. package/Tests/Server/Services/RuleRun/OwnerRuleEnginesGroupARun.test.ts +43 -0
  199. package/Tests/Server/Services/SessionRetention.test.ts +334 -0
  200. package/Tests/Server/Services/StatusPagePrivateUserInvitationPolicy.test.ts +172 -0
  201. package/Tests/Server/Services/StatusPagePrivateUserReadAccess.test.ts +178 -0
  202. package/Tests/Server/Services/StatusPagePrivateUserReadAccessPostgres.test.ts +311 -0
  203. package/Tests/Server/Services/StatusPagePrivateUserSessionService.test.ts +216 -1
  204. package/Tests/Server/Services/TeamComplianceServiceBehaviour.test.ts +1 -1
  205. package/Tests/Server/Services/UserOnCallLogNoNotificationRules.test.ts +1 -1
  206. package/Tests/Server/Types/Database/EventOverlayScopePostgres.test.ts +626 -0
  207. package/Tests/Server/Types/Database/Permissions/InfrastructureOwnershipScope.test.ts +668 -0
  208. package/Tests/Server/Types/Database/Permissions/SelectRejectionMessageContract.test.ts +1 -0
  209. package/Tests/Server/Types/Database/Permissions/UserNotificationRuleScoping.test.ts +1 -1
  210. package/Tests/Server/Utils/AI/AIIncidentGating.test.ts +16 -9
  211. package/Tests/Server/Utils/AI/ChatAgentRunner.test.ts +137 -1
  212. package/Tests/Server/Utils/AI/InvestigationEligibility.test.ts +697 -0
  213. package/Tests/Server/Utils/AI/ObservabilityChatPrompt.test.ts +105 -0
  214. package/Tests/Server/Utils/AI/RemediationHandoff.test.ts +16 -5
  215. package/Tests/Server/Utils/AI/ResourceTools.test.ts +1304 -0
  216. package/Tests/Server/Utils/AI/RumTools.test.ts +769 -0
  217. package/Tests/Server/Utils/Database/PostgresErrorTranslator.test.ts +63 -0
  218. package/Tests/Server/Utils/Monitor/Criteria/APIRequestCriteriaEvaluateOverTime.test.ts +11 -9
  219. package/Tests/Server/Utils/Monitor/Criteria/CompareCriteria.test.ts +62 -45
  220. package/Tests/Server/Utils/Monitor/Criteria/CompareCriteriaAggregation.test.ts +25 -24
  221. package/Tests/Server/Utils/Monitor/Criteria/CompareCriteriaHumanMessages.test.ts +513 -0
  222. package/Tests/Server/Utils/Monitor/Criteria/CustomCodeMonitorCriteria.test.ts +2 -2
  223. package/Tests/Server/Utils/Monitor/Criteria/DnsMonitorCriteria.test.ts +1 -1
  224. package/Tests/Server/Utils/Monitor/Criteria/ExternalStatusPageMonitorCriteria.test.ts +9 -9
  225. package/Tests/Server/Utils/Monitor/Criteria/MetricMonitorCriteria.test.ts +7 -5
  226. package/Tests/Server/Utils/Monitor/Criteria/ProfileMonitorCriteria.test.ts +2 -2
  227. package/Tests/Server/Utils/Monitor/Criteria/ServerMonitorCriteria.test.ts +4 -3
  228. package/Tests/Server/Utils/Monitor/Criteria/SnmpMonitorCriteria.test.ts +2 -2
  229. package/Tests/Server/Utils/Monitor/MonitorCriteriaEvaluatorMetricUnits.test.ts +3 -2
  230. package/Tests/Server/Utils/Monitor/MonitorCriteriaHumanMessages.test.ts +529 -0
  231. package/Tests/Server/Utils/Rules/OwnerRuleAssignment.test.ts +412 -4
  232. package/Tests/Server/Utils/SecurityEvent/Connectors/GoogleSecOps/GoogleSecOpsPollingClickhouseIntegration.test.ts +1 -1
  233. package/Tests/Server/Utils/TailwindBuildCopy.test.ts +14 -2
  234. package/Tests/Server/Utils/Telemetry/HostAssetAttributesFromOtlp.test.ts +235 -0
  235. package/Tests/Server/Utils/Telemetry/TelemetryEntity.test.ts +385 -2
  236. package/Tests/Server/Utils/VendorAssets.test.ts +17 -3
  237. package/Tests/Types/AI/AIChatPageContext.test.ts +0 -0
  238. package/Tests/Types/AI/AIResourceContext.test.ts +312 -0
  239. package/Tests/Types/Database/UniqueColumnsTogether.test.ts +100 -0
  240. package/Tests/Types/Monitor/MetricAndProfileDefaultCriteria.test.ts +4 -4
  241. package/Tests/Types/Monitor/MonitorStepRetryPersistence.test.ts +125 -0
  242. package/Tests/Types/WebsiteRequest.test.ts +44 -0
  243. package/Tests/UI/Components/Forms/MonitorDescriptionForm.test.tsx +410 -0
  244. package/Tests/UI/Components/ModelTable/BaseModelTableReadPermissions.test.tsx +439 -0
  245. package/Tests/UI/Components/NavBarMenuSearch.test.tsx +372 -0
  246. package/Tests/UI/EsbuildConfig.test.ts +1 -1
  247. package/Tests/UI/Monitor/MonitorStepRetrySettings.test.tsx +616 -0
  248. package/Tests/UI/ReactRouterSingletonBuild.test.ts +4 -2
  249. package/Tests/UI/Rum/ReplayEngine.test.ts +179 -0
  250. package/Tests/UI/Rum/ReplayHeader.test.tsx +23 -0
  251. package/Tests/UI/Rum/ReplayScrubber.test.tsx +88 -0
  252. package/Tests/UI/Rum/ReplayStageOverlays.test.tsx +83 -0
  253. package/Tests/UI/Rum/ReplayTabSwitcher.test.tsx +33 -0
  254. package/Tests/Utils/API.test.ts +96 -0
  255. package/Tests/Utils/HTTPResponseBodyReader.test.ts +188 -1
  256. package/Tests/Utils/Metrics/MetricEventScopeUrl.test.ts +101 -0
  257. package/Tests/Utils/Monitor/MonitorTestAvailabilityUtil.test.ts +256 -0
  258. package/Tests/Utils/Telemetry/HostIpAddresses.test.ts +105 -0
  259. package/Types/AI/AIChatPageContext.ts +87 -2
  260. package/Types/AI/AIChatTypes.ts +4 -0
  261. package/Types/AI/AIResourceContext.ts +198 -0
  262. package/Types/AI/InvestigationNotStartedReason.ts +30 -0
  263. package/Types/Database/UniqueColumnsTogether.ts +55 -0
  264. package/Types/Metrics/MetricQueryConfigData.ts +8 -0
  265. package/Types/Rum/WebVitals.ts +71 -0
  266. package/Types/WebsiteRequest.ts +2 -0
  267. package/UI/Components/EditionLabel/EditionLabel.tsx +7 -5
  268. package/UI/Components/KeyboardShortcut/Screenshots/README.md +1 -1
  269. package/UI/Components/ModelTable/BaseModelTable.tsx +8 -0
  270. package/UI/Components/Navbar/NavBar.tsx +2 -0
  271. package/UI/Components/Navbar/NavBarMenuModal.tsx +6 -2
  272. package/UI/esbuild-config.js +4 -4
  273. package/Utils/API.ts +10 -1
  274. package/Utils/Dashboard/HtmlWidgetDocument.ts +1 -1
  275. package/Utils/HTTPResponseBodyReader.ts +64 -8
  276. package/Utils/Metrics/MetricExplorerUrl.ts +19 -0
  277. package/Utils/Monitor/MonitorTestAvailabilityUtil.ts +92 -0
  278. package/Utils/Telemetry/HostIpAddresses.ts +46 -2
  279. package/build/dist/Models/DatabaseModels/AIAgentOwnerTeam.js +4 -1
  280. package/build/dist/Models/DatabaseModels/AIAgentOwnerTeam.js.map +1 -1
  281. package/build/dist/Models/DatabaseModels/AIAgentOwnerUser.js +4 -1
  282. package/build/dist/Models/DatabaseModels/AIAgentOwnerUser.js.map +1 -1
  283. package/build/dist/Models/DatabaseModels/Alert.js +12 -0
  284. package/build/dist/Models/DatabaseModels/Alert.js.map +1 -1
  285. package/build/dist/Models/DatabaseModels/AlertEpisodeOwnerTeam.js +3 -1
  286. package/build/dist/Models/DatabaseModels/AlertEpisodeOwnerTeam.js.map +1 -1
  287. package/build/dist/Models/DatabaseModels/AlertEpisodeOwnerUser.js +3 -1
  288. package/build/dist/Models/DatabaseModels/AlertEpisodeOwnerUser.js.map +1 -1
  289. package/build/dist/Models/DatabaseModels/AlertOwnerTeam.js +3 -1
  290. package/build/dist/Models/DatabaseModels/AlertOwnerTeam.js.map +1 -1
  291. package/build/dist/Models/DatabaseModels/AlertOwnerUser.js +3 -1
  292. package/build/dist/Models/DatabaseModels/AlertOwnerUser.js.map +1 -1
  293. package/build/dist/Models/DatabaseModels/CephClusterOwnerTeam.js +4 -1
  294. package/build/dist/Models/DatabaseModels/CephClusterOwnerTeam.js.map +1 -1
  295. package/build/dist/Models/DatabaseModels/CephClusterOwnerUser.js +4 -1
  296. package/build/dist/Models/DatabaseModels/CephClusterOwnerUser.js.map +1 -1
  297. package/build/dist/Models/DatabaseModels/CloudResourceOwnerTeam.js +4 -1
  298. package/build/dist/Models/DatabaseModels/CloudResourceOwnerTeam.js.map +1 -1
  299. package/build/dist/Models/DatabaseModels/CloudResourceOwnerUser.js +4 -1
  300. package/build/dist/Models/DatabaseModels/CloudResourceOwnerUser.js.map +1 -1
  301. package/build/dist/Models/DatabaseModels/DashboardOwnerTeam.js +3 -1
  302. package/build/dist/Models/DatabaseModels/DashboardOwnerTeam.js.map +1 -1
  303. package/build/dist/Models/DatabaseModels/DashboardOwnerUser.js +3 -1
  304. package/build/dist/Models/DatabaseModels/DashboardOwnerUser.js.map +1 -1
  305. package/build/dist/Models/DatabaseModels/DatabaseBaseModel/DatabaseBaseModel.js +3 -0
  306. package/build/dist/Models/DatabaseModels/DatabaseBaseModel/DatabaseBaseModel.js.map +1 -1
  307. package/build/dist/Models/DatabaseModels/DockerHostOwnerTeam.js +4 -1
  308. package/build/dist/Models/DatabaseModels/DockerHostOwnerTeam.js.map +1 -1
  309. package/build/dist/Models/DatabaseModels/DockerHostOwnerUser.js +4 -1
  310. package/build/dist/Models/DatabaseModels/DockerHostOwnerUser.js.map +1 -1
  311. package/build/dist/Models/DatabaseModels/DockerSwarmClusterOwnerTeam.js +4 -1
  312. package/build/dist/Models/DatabaseModels/DockerSwarmClusterOwnerTeam.js.map +1 -1
  313. package/build/dist/Models/DatabaseModels/DockerSwarmClusterOwnerUser.js +4 -1
  314. package/build/dist/Models/DatabaseModels/DockerSwarmClusterOwnerUser.js.map +1 -1
  315. package/build/dist/Models/DatabaseModels/HostOwnerTeam.js +4 -1
  316. package/build/dist/Models/DatabaseModels/HostOwnerTeam.js.map +1 -1
  317. package/build/dist/Models/DatabaseModels/HostOwnerUser.js +4 -1
  318. package/build/dist/Models/DatabaseModels/HostOwnerUser.js.map +1 -1
  319. package/build/dist/Models/DatabaseModels/Incident.js +12 -0
  320. package/build/dist/Models/DatabaseModels/Incident.js.map +1 -1
  321. package/build/dist/Models/DatabaseModels/IncidentEpisodeOwnerTeam.js +3 -1
  322. package/build/dist/Models/DatabaseModels/IncidentEpisodeOwnerTeam.js.map +1 -1
  323. package/build/dist/Models/DatabaseModels/IncidentEpisodeOwnerUser.js +3 -1
  324. package/build/dist/Models/DatabaseModels/IncidentEpisodeOwnerUser.js.map +1 -1
  325. package/build/dist/Models/DatabaseModels/IncidentOwnerTeam.js +3 -1
  326. package/build/dist/Models/DatabaseModels/IncidentOwnerTeam.js.map +1 -1
  327. package/build/dist/Models/DatabaseModels/IncidentOwnerUser.js +3 -1
  328. package/build/dist/Models/DatabaseModels/IncidentOwnerUser.js.map +1 -1
  329. package/build/dist/Models/DatabaseModels/IncidentTemplateOwnerTeam.js +4 -1
  330. package/build/dist/Models/DatabaseModels/IncidentTemplateOwnerTeam.js.map +1 -1
  331. package/build/dist/Models/DatabaseModels/IncidentTemplateOwnerUser.js +4 -1
  332. package/build/dist/Models/DatabaseModels/IncidentTemplateOwnerUser.js.map +1 -1
  333. package/build/dist/Models/DatabaseModels/IncomingCallPolicyOwnerTeam.js +3 -1
  334. package/build/dist/Models/DatabaseModels/IncomingCallPolicyOwnerTeam.js.map +1 -1
  335. package/build/dist/Models/DatabaseModels/IncomingCallPolicyOwnerUser.js +3 -1
  336. package/build/dist/Models/DatabaseModels/IncomingCallPolicyOwnerUser.js.map +1 -1
  337. package/build/dist/Models/DatabaseModels/IoTFleetOwnerTeam.js +4 -1
  338. package/build/dist/Models/DatabaseModels/IoTFleetOwnerTeam.js.map +1 -1
  339. package/build/dist/Models/DatabaseModels/IoTFleetOwnerUser.js +4 -1
  340. package/build/dist/Models/DatabaseModels/IoTFleetOwnerUser.js.map +1 -1
  341. package/build/dist/Models/DatabaseModels/KubernetesClusterOwnerTeam.js +4 -1
  342. package/build/dist/Models/DatabaseModels/KubernetesClusterOwnerTeam.js.map +1 -1
  343. package/build/dist/Models/DatabaseModels/KubernetesClusterOwnerUser.js +4 -1
  344. package/build/dist/Models/DatabaseModels/KubernetesClusterOwnerUser.js.map +1 -1
  345. package/build/dist/Models/DatabaseModels/Monitor.js +2 -3
  346. package/build/dist/Models/DatabaseModels/Monitor.js.map +1 -1
  347. package/build/dist/Models/DatabaseModels/MonitorGroupOwnerTeam.js +4 -1
  348. package/build/dist/Models/DatabaseModels/MonitorGroupOwnerTeam.js.map +1 -1
  349. package/build/dist/Models/DatabaseModels/MonitorGroupOwnerUser.js +4 -1
  350. package/build/dist/Models/DatabaseModels/MonitorGroupOwnerUser.js.map +1 -1
  351. package/build/dist/Models/DatabaseModels/MonitorOwnerTeam.js +3 -1
  352. package/build/dist/Models/DatabaseModels/MonitorOwnerTeam.js.map +1 -1
  353. package/build/dist/Models/DatabaseModels/MonitorOwnerUser.js +3 -1
  354. package/build/dist/Models/DatabaseModels/MonitorOwnerUser.js.map +1 -1
  355. package/build/dist/Models/DatabaseModels/MonitorTemplate.js +2 -3
  356. package/build/dist/Models/DatabaseModels/MonitorTemplate.js.map +1 -1
  357. package/build/dist/Models/DatabaseModels/NetworkDeviceOwnerTeam.js +4 -1
  358. package/build/dist/Models/DatabaseModels/NetworkDeviceOwnerTeam.js.map +1 -1
  359. package/build/dist/Models/DatabaseModels/NetworkDeviceOwnerUser.js +4 -1
  360. package/build/dist/Models/DatabaseModels/NetworkDeviceOwnerUser.js.map +1 -1
  361. package/build/dist/Models/DatabaseModels/OnCallDutyPolicyOwnerTeam.js +3 -1
  362. package/build/dist/Models/DatabaseModels/OnCallDutyPolicyOwnerTeam.js.map +1 -1
  363. package/build/dist/Models/DatabaseModels/OnCallDutyPolicyOwnerUser.js +3 -1
  364. package/build/dist/Models/DatabaseModels/OnCallDutyPolicyOwnerUser.js.map +1 -1
  365. package/build/dist/Models/DatabaseModels/OnCallDutyPolicyScheduleOwnerTeam.js +3 -1
  366. package/build/dist/Models/DatabaseModels/OnCallDutyPolicyScheduleOwnerTeam.js.map +1 -1
  367. package/build/dist/Models/DatabaseModels/OnCallDutyPolicyScheduleOwnerUser.js +3 -1
  368. package/build/dist/Models/DatabaseModels/OnCallDutyPolicyScheduleOwnerUser.js.map +1 -1
  369. package/build/dist/Models/DatabaseModels/PodmanHostOwnerTeam.js +4 -1
  370. package/build/dist/Models/DatabaseModels/PodmanHostOwnerTeam.js.map +1 -1
  371. package/build/dist/Models/DatabaseModels/PodmanHostOwnerUser.js +4 -1
  372. package/build/dist/Models/DatabaseModels/PodmanHostOwnerUser.js.map +1 -1
  373. package/build/dist/Models/DatabaseModels/ProbeOwnerTeam.js +4 -1
  374. package/build/dist/Models/DatabaseModels/ProbeOwnerTeam.js.map +1 -1
  375. package/build/dist/Models/DatabaseModels/ProbeOwnerUser.js +4 -1
  376. package/build/dist/Models/DatabaseModels/ProbeOwnerUser.js.map +1 -1
  377. package/build/dist/Models/DatabaseModels/ProxmoxClusterOwnerTeam.js +4 -1
  378. package/build/dist/Models/DatabaseModels/ProxmoxClusterOwnerTeam.js.map +1 -1
  379. package/build/dist/Models/DatabaseModels/ProxmoxClusterOwnerUser.js +4 -1
  380. package/build/dist/Models/DatabaseModels/ProxmoxClusterOwnerUser.js.map +1 -1
  381. package/build/dist/Models/DatabaseModels/RumApplicationOwnerTeam.js +4 -1
  382. package/build/dist/Models/DatabaseModels/RumApplicationOwnerTeam.js.map +1 -1
  383. package/build/dist/Models/DatabaseModels/RumApplicationOwnerUser.js +4 -1
  384. package/build/dist/Models/DatabaseModels/RumApplicationOwnerUser.js.map +1 -1
  385. package/build/dist/Models/DatabaseModels/RunbookOwnerTeam.js +3 -1
  386. package/build/dist/Models/DatabaseModels/RunbookOwnerTeam.js.map +1 -1
  387. package/build/dist/Models/DatabaseModels/RunbookOwnerUser.js +3 -1
  388. package/build/dist/Models/DatabaseModels/RunbookOwnerUser.js.map +1 -1
  389. package/build/dist/Models/DatabaseModels/RunnerOwnerTeam.js +3 -1
  390. package/build/dist/Models/DatabaseModels/RunnerOwnerTeam.js.map +1 -1
  391. package/build/dist/Models/DatabaseModels/RunnerOwnerUser.js +3 -1
  392. package/build/dist/Models/DatabaseModels/RunnerOwnerUser.js.map +1 -1
  393. package/build/dist/Models/DatabaseModels/ScheduledMaintenanceOwnerTeam.js +3 -1
  394. package/build/dist/Models/DatabaseModels/ScheduledMaintenanceOwnerTeam.js.map +1 -1
  395. package/build/dist/Models/DatabaseModels/ScheduledMaintenanceOwnerUser.js +3 -1
  396. package/build/dist/Models/DatabaseModels/ScheduledMaintenanceOwnerUser.js.map +1 -1
  397. package/build/dist/Models/DatabaseModels/ScheduledMaintenanceTemplateOwnerTeam.js +6 -1
  398. package/build/dist/Models/DatabaseModels/ScheduledMaintenanceTemplateOwnerTeam.js.map +1 -1
  399. package/build/dist/Models/DatabaseModels/ScheduledMaintenanceTemplateOwnerUser.js +6 -1
  400. package/build/dist/Models/DatabaseModels/ScheduledMaintenanceTemplateOwnerUser.js.map +1 -1
  401. package/build/dist/Models/DatabaseModels/ServerlessFunctionOwnerTeam.js +4 -1
  402. package/build/dist/Models/DatabaseModels/ServerlessFunctionOwnerTeam.js.map +1 -1
  403. package/build/dist/Models/DatabaseModels/ServerlessFunctionOwnerUser.js +4 -1
  404. package/build/dist/Models/DatabaseModels/ServerlessFunctionOwnerUser.js.map +1 -1
  405. package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveOwnerTeam.js +3 -1
  406. package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveOwnerTeam.js.map +1 -1
  407. package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveOwnerUser.js +3 -1
  408. package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveOwnerUser.js.map +1 -1
  409. package/build/dist/Models/DatabaseModels/ServiceOwnerTeam.js +4 -1
  410. package/build/dist/Models/DatabaseModels/ServiceOwnerTeam.js.map +1 -1
  411. package/build/dist/Models/DatabaseModels/ServiceOwnerUser.js +4 -1
  412. package/build/dist/Models/DatabaseModels/ServiceOwnerUser.js.map +1 -1
  413. package/build/dist/Models/DatabaseModels/StatusPageOwnerTeam.js +3 -1
  414. package/build/dist/Models/DatabaseModels/StatusPageOwnerTeam.js.map +1 -1
  415. package/build/dist/Models/DatabaseModels/StatusPageOwnerUser.js +3 -1
  416. package/build/dist/Models/DatabaseModels/StatusPageOwnerUser.js.map +1 -1
  417. package/build/dist/Models/DatabaseModels/VMwareVCenterOwnerTeam.js +4 -1
  418. package/build/dist/Models/DatabaseModels/VMwareVCenterOwnerTeam.js.map +1 -1
  419. package/build/dist/Models/DatabaseModels/VMwareVCenterOwnerUser.js +4 -1
  420. package/build/dist/Models/DatabaseModels/VMwareVCenterOwnerUser.js.map +1 -1
  421. package/build/dist/Models/DatabaseModels/WorkflowOwnerTeam.js +3 -1
  422. package/build/dist/Models/DatabaseModels/WorkflowOwnerTeam.js.map +1 -1
  423. package/build/dist/Models/DatabaseModels/WorkflowOwnerUser.js +3 -1
  424. package/build/dist/Models/DatabaseModels/WorkflowOwnerUser.js.map +1 -1
  425. package/build/dist/Server/API/AIAgentDataAPI.js +1 -1
  426. package/build/dist/Server/API/AIChatAPI.js +3 -1
  427. package/build/dist/Server/API/AIChatAPI.js.map +1 -1
  428. package/build/dist/Server/API/AIInvestigationAPI.js +3 -0
  429. package/build/dist/Server/API/AIInvestigationAPI.js.map +1 -1
  430. package/build/dist/Server/API/StatusPageAPI.js +9 -1
  431. package/build/dist/Server/API/StatusPageAPI.js.map +1 -1
  432. package/build/dist/Server/Infrastructure/Postgres/LocalMigrationGenerationDataSource.js +1 -1
  433. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1793500000000-MakeOwnerRowsUnique.js +602 -0
  434. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1793500000000-MakeOwnerRowsUnique.js.map +1 -0
  435. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1793700000000-AddAIInvestigationDecision.js +14 -0
  436. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1793700000000-AddAIInvestigationDecision.js.map +1 -0
  437. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1793800000000-RemoveMonitorDescriptionLengthLimit.js +20 -0
  438. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1793800000000-RemoveMonitorDescriptionLengthLimit.js.map +1 -0
  439. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +6 -0
  440. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  441. package/build/dist/Server/Middleware/IdentityRateLimit.js +22 -1
  442. package/build/dist/Server/Middleware/IdentityRateLimit.js.map +1 -1
  443. package/build/dist/Server/Middleware/PublicDashboardRateLimit.js +117 -36
  444. package/build/dist/Server/Middleware/PublicDashboardRateLimit.js.map +1 -1
  445. package/build/dist/Server/Services/AlertEpisodeService.js +13 -31
  446. package/build/dist/Server/Services/AlertEpisodeService.js.map +1 -1
  447. package/build/dist/Server/Services/AlertGroupingEngineService.js +7 -4
  448. package/build/dist/Server/Services/AlertGroupingEngineService.js.map +1 -1
  449. package/build/dist/Server/Services/AlertService.js +13 -31
  450. package/build/dist/Server/Services/AlertService.js.map +1 -1
  451. package/build/dist/Server/Services/CephClusterOwnerRuleEngineService.js +12 -8
  452. package/build/dist/Server/Services/CephClusterOwnerRuleEngineService.js.map +1 -1
  453. package/build/dist/Server/Services/CloudResourceOwnerRuleEngineService.js +12 -8
  454. package/build/dist/Server/Services/CloudResourceOwnerRuleEngineService.js.map +1 -1
  455. package/build/dist/Server/Services/DashboardOwnerRuleEngineService.js +12 -8
  456. package/build/dist/Server/Services/DashboardOwnerRuleEngineService.js.map +1 -1
  457. package/build/dist/Server/Services/DatabaseService.js +71 -1
  458. package/build/dist/Server/Services/DatabaseService.js.map +1 -1
  459. package/build/dist/Server/Services/DockerHostOwnerRuleEngineService.js +12 -8
  460. package/build/dist/Server/Services/DockerHostOwnerRuleEngineService.js.map +1 -1
  461. package/build/dist/Server/Services/DockerSwarmClusterOwnerRuleEngineService.js +12 -8
  462. package/build/dist/Server/Services/DockerSwarmClusterOwnerRuleEngineService.js.map +1 -1
  463. package/build/dist/Server/Services/HostOwnerRuleEngineService.js +12 -8
  464. package/build/dist/Server/Services/HostOwnerRuleEngineService.js.map +1 -1
  465. package/build/dist/Server/Services/IncidentEpisodeOwnerRuleEngineService.js +6 -4
  466. package/build/dist/Server/Services/IncidentEpisodeOwnerRuleEngineService.js.map +1 -1
  467. package/build/dist/Server/Services/IncidentEpisodeService.js +15 -68
  468. package/build/dist/Server/Services/IncidentEpisodeService.js.map +1 -1
  469. package/build/dist/Server/Services/IncidentGroupingEngineService.js +7 -4
  470. package/build/dist/Server/Services/IncidentGroupingEngineService.js.map +1 -1
  471. package/build/dist/Server/Services/IncidentService.js +13 -31
  472. package/build/dist/Server/Services/IncidentService.js.map +1 -1
  473. package/build/dist/Server/Services/IncidentTemplateService.js +13 -31
  474. package/build/dist/Server/Services/IncidentTemplateService.js.map +1 -1
  475. package/build/dist/Server/Services/IncomingCallPolicyOwnerRuleEngineService.js +12 -8
  476. package/build/dist/Server/Services/IncomingCallPolicyOwnerRuleEngineService.js.map +1 -1
  477. package/build/dist/Server/Services/IoTFleetOwnerRuleEngineService.js +12 -8
  478. package/build/dist/Server/Services/IoTFleetOwnerRuleEngineService.js.map +1 -1
  479. package/build/dist/Server/Services/KubernetesClusterOwnerRuleEngineService.js +12 -8
  480. package/build/dist/Server/Services/KubernetesClusterOwnerRuleEngineService.js.map +1 -1
  481. package/build/dist/Server/Services/MonitorService.js +13 -31
  482. package/build/dist/Server/Services/MonitorService.js.map +1 -1
  483. package/build/dist/Server/Services/NetworkDeviceOwnerRuleEngineService.js +12 -8
  484. package/build/dist/Server/Services/NetworkDeviceOwnerRuleEngineService.js.map +1 -1
  485. package/build/dist/Server/Services/OnCallDutyPolicyOwnerRuleEngineService.js +12 -8
  486. package/build/dist/Server/Services/OnCallDutyPolicyOwnerRuleEngineService.js.map +1 -1
  487. package/build/dist/Server/Services/OnCallDutyPolicyScheduleOwnerRuleEngineService.js +12 -8
  488. package/build/dist/Server/Services/OnCallDutyPolicyScheduleOwnerRuleEngineService.js.map +1 -1
  489. package/build/dist/Server/Services/PodmanHostOwnerRuleEngineService.js +12 -8
  490. package/build/dist/Server/Services/PodmanHostOwnerRuleEngineService.js.map +1 -1
  491. package/build/dist/Server/Services/ProxmoxClusterOwnerRuleEngineService.js +12 -8
  492. package/build/dist/Server/Services/ProxmoxClusterOwnerRuleEngineService.js.map +1 -1
  493. package/build/dist/Server/Services/RumApplicationOwnerRuleEngineService.js +12 -8
  494. package/build/dist/Server/Services/RumApplicationOwnerRuleEngineService.js.map +1 -1
  495. package/build/dist/Server/Services/RunbookOwnerRuleEngineService.js +12 -8
  496. package/build/dist/Server/Services/RunbookOwnerRuleEngineService.js.map +1 -1
  497. package/build/dist/Server/Services/ScheduledMaintenanceService.js +13 -31
  498. package/build/dist/Server/Services/ScheduledMaintenanceService.js.map +1 -1
  499. package/build/dist/Server/Services/ScheduledMaintenanceTemplateService.js +12 -29
  500. package/build/dist/Server/Services/ScheduledMaintenanceTemplateService.js.map +1 -1
  501. package/build/dist/Server/Services/ServerlessFunctionOwnerRuleEngineService.js +12 -8
  502. package/build/dist/Server/Services/ServerlessFunctionOwnerRuleEngineService.js.map +1 -1
  503. package/build/dist/Server/Services/ServiceOwnerRuleEngineService.js +12 -8
  504. package/build/dist/Server/Services/ServiceOwnerRuleEngineService.js.map +1 -1
  505. package/build/dist/Server/Services/StatusPagePrivateUserService.js +33 -25
  506. package/build/dist/Server/Services/StatusPagePrivateUserService.js.map +1 -1
  507. package/build/dist/Server/Services/StatusPagePrivateUserSessionService.js +36 -1
  508. package/build/dist/Server/Services/StatusPagePrivateUserSessionService.js.map +1 -1
  509. package/build/dist/Server/Services/StatusPageService.js +50 -35
  510. package/build/dist/Server/Services/StatusPageService.js.map +1 -1
  511. package/build/dist/Server/Services/UserSessionService.js +5 -0
  512. package/build/dist/Server/Services/UserSessionService.js.map +1 -1
  513. package/build/dist/Server/Services/VMwareVCenterOwnerRuleEngineService.js +12 -8
  514. package/build/dist/Server/Services/VMwareVCenterOwnerRuleEngineService.js.map +1 -1
  515. package/build/dist/Server/Services/WorkflowOwnerRuleEngineService.js +12 -8
  516. package/build/dist/Server/Services/WorkflowOwnerRuleEngineService.js.map +1 -1
  517. package/build/dist/Server/Types/Database/Permissions/OwnedScopePermission.js +15 -10
  518. package/build/dist/Server/Types/Database/Permissions/OwnedScopePermission.js.map +1 -1
  519. package/build/dist/Server/Types/Database/Permissions/OwnerTableRegistry.js +82 -0
  520. package/build/dist/Server/Types/Database/Permissions/OwnerTableRegistry.js.map +1 -1
  521. package/build/dist/Server/Utils/AI/Chat/ChatAgentRunner.js +12 -3
  522. package/build/dist/Server/Utils/AI/Chat/ChatAgentRunner.js.map +1 -1
  523. package/build/dist/Server/Utils/AI/Chat/ObservabilityChatPrompt.js +32 -4
  524. package/build/dist/Server/Utils/AI/Chat/ObservabilityChatPrompt.js.map +1 -1
  525. package/build/dist/Server/Utils/AI/CodeFix/CodeAgentWorkspaceGuard.js +1 -1
  526. package/build/dist/Server/Utils/AI/CodeFix/CodeFixAgentCompletion.js +1 -1
  527. package/build/dist/Server/Utils/AI/SRE/AIInvestigationEngine.js +8 -5
  528. package/build/dist/Server/Utils/AI/SRE/AIInvestigationEngine.js.map +1 -1
  529. package/build/dist/Server/Utils/AI/SRE/AlertInvestigationRunner.js +33 -13
  530. package/build/dist/Server/Utils/AI/SRE/AlertInvestigationRunner.js.map +1 -1
  531. package/build/dist/Server/Utils/AI/SRE/IncidentInvestigationRunner.js +31 -10
  532. package/build/dist/Server/Utils/AI/SRE/IncidentInvestigationRunner.js.map +1 -1
  533. package/build/dist/Server/Utils/AI/SRE/InvestigationEligibility.js +205 -0
  534. package/build/dist/Server/Utils/AI/SRE/InvestigationEligibility.js.map +1 -0
  535. package/build/dist/Server/Utils/AI/SRE/InvestigationQueue.js +13 -0
  536. package/build/dist/Server/Utils/AI/SRE/InvestigationQueue.js.map +1 -1
  537. package/build/dist/Server/Utils/AI/Toolbox/Index.js +30 -6
  538. package/build/dist/Server/Utils/AI/Toolbox/Index.js.map +1 -1
  539. package/build/dist/Server/Utils/AI/Toolbox/ResourceTools.js +721 -0
  540. package/build/dist/Server/Utils/AI/Toolbox/ResourceTools.js.map +1 -0
  541. package/build/dist/Server/Utils/AI/Toolbox/RumTools.js +330 -0
  542. package/build/dist/Server/Utils/AI/Toolbox/RumTools.js.map +1 -0
  543. package/build/dist/Server/Utils/AI/Toolbox/ToolTypes.js.map +1 -1
  544. package/build/dist/Server/Utils/AI/Toolbox/TraceTools.js +1 -1
  545. package/build/dist/Server/Utils/AI/Toolbox/TraceTools.js.map +1 -1
  546. package/build/dist/Server/Utils/Database/PostgresErrorTranslator.js +11 -0
  547. package/build/dist/Server/Utils/Database/PostgresErrorTranslator.js.map +1 -1
  548. package/build/dist/Server/Utils/Monitor/Criteria/CompareCriteria.js +106 -101
  549. package/build/dist/Server/Utils/Monitor/Criteria/CompareCriteria.js.map +1 -1
  550. package/build/dist/Server/Utils/Monitor/Criteria/MetricMonitorCriteria.js +4 -2
  551. package/build/dist/Server/Utils/Monitor/Criteria/MetricMonitorCriteria.js.map +1 -1
  552. package/build/dist/Server/Utils/Rules/OwnerRuleAssignment.js +94 -0
  553. package/build/dist/Server/Utils/Rules/OwnerRuleAssignment.js.map +1 -1
  554. package/build/dist/Server/Utils/Telemetry/TelemetryEntity.js +171 -6
  555. package/build/dist/Server/Utils/Telemetry/TelemetryEntity.js.map +1 -1
  556. package/build/dist/Types/AI/AIChatPageContext.js +68 -2
  557. package/build/dist/Types/AI/AIChatPageContext.js.map +1 -1
  558. package/build/dist/Types/AI/AIChatTypes.js +4 -0
  559. package/build/dist/Types/AI/AIChatTypes.js.map +1 -1
  560. package/build/dist/Types/AI/AIResourceContext.js +162 -0
  561. package/build/dist/Types/AI/AIResourceContext.js.map +1 -0
  562. package/build/dist/Types/AI/InvestigationNotStartedReason.js +2 -0
  563. package/build/dist/Types/AI/InvestigationNotStartedReason.js.map +1 -0
  564. package/build/dist/Types/Database/UniqueColumnsTogether.js +19 -0
  565. package/build/dist/Types/Database/UniqueColumnsTogether.js.map +1 -0
  566. package/build/dist/Types/Metrics/MetricQueryConfigData.js.map +1 -1
  567. package/build/dist/Types/Rum/WebVitals.js +64 -0
  568. package/build/dist/Types/Rum/WebVitals.js.map +1 -0
  569. package/build/dist/Types/WebsiteRequest.js +2 -0
  570. package/build/dist/Types/WebsiteRequest.js.map +1 -1
  571. package/build/dist/UI/Components/EditionLabel/EditionLabel.js +7 -5
  572. package/build/dist/UI/Components/EditionLabel/EditionLabel.js.map +1 -1
  573. package/build/dist/UI/Components/ModelTable/BaseModelTable.js +7 -0
  574. package/build/dist/UI/Components/ModelTable/BaseModelTable.js.map +1 -1
  575. package/build/dist/UI/Components/Navbar/NavBar.js.map +1 -1
  576. package/build/dist/UI/Components/Navbar/NavBarMenuModal.js +4 -2
  577. package/build/dist/UI/Components/Navbar/NavBarMenuModal.js.map +1 -1
  578. package/build/dist/Utils/API.js +8 -4
  579. package/build/dist/Utils/API.js.map +1 -1
  580. package/build/dist/Utils/HTTPResponseBodyReader.js +50 -6
  581. package/build/dist/Utils/HTTPResponseBodyReader.js.map +1 -1
  582. package/build/dist/Utils/Metrics/MetricExplorerUrl.js +14 -3
  583. package/build/dist/Utils/Metrics/MetricExplorerUrl.js.map +1 -1
  584. package/build/dist/Utils/Monitor/MonitorTestAvailabilityUtil.js +68 -0
  585. package/build/dist/Utils/Monitor/MonitorTestAvailabilityUtil.js.map +1 -0
  586. package/build/dist/Utils/Telemetry/HostIpAddresses.js +42 -3
  587. package/build/dist/Utils/Telemetry/HostIpAddresses.js.map +1 -1
  588. package/package.json +5 -5
  589. package/test-setup.sh +2 -2
@@ -0,0 +1,334 @@
1
+ import StatusPagePrivateUserSession from "../../../Models/DatabaseModels/StatusPagePrivateUserSession";
2
+ import UserSession from "../../../Models/DatabaseModels/UserSession";
3
+ import DatabaseService from "../../../Server/Services/DatabaseService";
4
+ import Services from "../../../Server/Services/Index";
5
+ import { Service as PrivateSessionService } from "../../../Server/Services/StatusPagePrivateUserSessionService";
6
+ import { Service as UserSessionService } from "../../../Server/Services/UserSessionService";
7
+ import FindBy from "../../../Server/Types/Database/FindBy";
8
+ import logger from "../../../Server/Utils/Logger";
9
+ import LIMIT_MAX from "../../../Types/Database/LimitMax";
10
+ import ObjectID from "../../../Types/ObjectID";
11
+ import { EVERY_DAY } from "../../../Utils/CronTime";
12
+ import { getJestSpyOn } from "../../Spy";
13
+ import RunCron from "../../../../App/FeatureSet/Workers/Utils/Cron";
14
+ import "../../../../App/FeatureSet/Workers/Jobs/HardDelete/HardDeleteItemsInDatabase";
15
+ import fs from "fs";
16
+ import path from "path";
17
+ import { DeleteResult, FindOperator, Repository } from "typeorm";
18
+
19
+ jest.mock("../../../../App/FeatureSet/Workers/Utils/Cron", () => {
20
+ return { __esModule: true, default: jest.fn() };
21
+ });
22
+
23
+ /*
24
+ * Run the real worker and session services, with its registry narrowed to the
25
+ * two session tables. A separate assertion checks the production registration.
26
+ */
27
+ jest.mock("../../../Server/Services/Index", () => {
28
+ return { __esModule: true, default: [] };
29
+ });
30
+
31
+ jest.mock("../../../Server/EnvironmentConfig", () => {
32
+ return {
33
+ ...jest.requireActual("../../../Server/EnvironmentConfig"),
34
+ IsBillingEnabled: false,
35
+ IsDevelopment: false,
36
+ };
37
+ });
38
+
39
+ // Small batches exercise the worker's loop without allocating 10,001 rows.
40
+ jest.mock("../../../Types/Database/LimitMax", () => {
41
+ return { __esModule: true, default: 2 };
42
+ });
43
+
44
+ type Session = StatusPagePrivateUserSession | UserSession;
45
+ type CronHandler = () => Promise<void>;
46
+
47
+ interface SessionCase {
48
+ name: string;
49
+ service: DatabaseService<Session>;
50
+ }
51
+
52
+ interface RetentionQuery {
53
+ refreshTokenExpiresAt: FindOperator<Date>;
54
+ _id?: FindOperator<Array<string>>;
55
+ }
56
+
57
+ interface RepositoryBoundary {
58
+ rows: Array<Session>;
59
+ find: jest.SpyInstance;
60
+ deleteRows: jest.Mock;
61
+ }
62
+
63
+ const NOW: Date = new Date("2026-09-17T12:00:00.000Z");
64
+ const DAY_MS: number = 24 * 60 * 60 * 1000;
65
+ const CUTOFF: Date = new Date(NOW.getTime() - 30 * DAY_MS);
66
+ const JOB_NAME: string = "HardDelete:HardDeleteOlderItemsInDatabase";
67
+
68
+ const SESSION_CASES: Array<SessionCase> = [
69
+ {
70
+ name: "StatusPagePrivateUserSession",
71
+ service: new PrivateSessionService(),
72
+ },
73
+ { name: "UserSession", service: new UserSessionService() },
74
+ ];
75
+
76
+ function sessionRow(
77
+ entry: SessionCase,
78
+ expiresAt: Date,
79
+ fields: Partial<Session> = {},
80
+ ): Session {
81
+ const row: Session = new entry.service.modelType();
82
+ row.id = ObjectID.generate();
83
+ row.refreshTokenExpiresAt = expiresAt;
84
+ row.isRevoked = false;
85
+ row.createdAt = new Date(NOW.getTime() - 365 * DAY_MS);
86
+ row.lastActiveAt = row.createdAt;
87
+ row.ipAddress = "192.0.2.10";
88
+ row.userAgent = "Test browser";
89
+ row.deviceName = "Test device";
90
+ Object.assign(row, fields);
91
+ return row;
92
+ }
93
+
94
+ function queryCutoff(query: RetentionQuery): Date {
95
+ const operator: FindOperator<Date> = query.refreshTokenExpiresAt;
96
+ expect(Object.keys(query).sort()).toEqual(
97
+ query._id ? ["_id", "refreshTokenExpiresAt"] : ["refreshTokenExpiresAt"],
98
+ );
99
+ expect(operator.getSql!("expiry")).toMatch(/^\(expiry < :\w+\)$/);
100
+ const cutoff: Date = Object.values(operator.objectLiteralParameters!)[0];
101
+ expect(cutoff).toEqual(CUTOFF);
102
+ return cutoff;
103
+ }
104
+
105
+ /*
106
+ * Only the database reads and physical DELETE are replaced. The cron callback,
107
+ * configured retention, permission scoping, batch selection, and hardDeleteBy
108
+ * run unchanged, including the expiry predicate on the final DELETE.
109
+ */
110
+ function installRepositoryBoundary(
111
+ entry: SessionCase,
112
+ initialRows: Array<Session>,
113
+ beforeDelete?: (() => void) | undefined,
114
+ ): RepositoryBoundary {
115
+ const rows: Array<Session> = [...initialRows];
116
+ const find: jest.SpyInstance = getJestSpyOn(
117
+ entry.service,
118
+ "_findBy",
119
+ ).mockImplementation(
120
+ async (
121
+ request: FindBy<Session>,
122
+ includeDeleted: boolean,
123
+ ): Promise<Array<Session>> => {
124
+ expect(includeDeleted).toBe(true);
125
+ expect(request.props.isRoot).toBe(true);
126
+ expect(request.limit).toBe(LIMIT_MAX);
127
+ expect(request.skip).toBe(0);
128
+ const cutoff: Date = queryCutoff(
129
+ request.query as unknown as RetentionQuery,
130
+ );
131
+ return rows
132
+ .filter((row: Session): boolean => {
133
+ return Boolean(
134
+ row.refreshTokenExpiresAt && row.refreshTokenExpiresAt < cutoff,
135
+ );
136
+ })
137
+ .slice(0, LIMIT_MAX);
138
+ },
139
+ );
140
+ const deleteRows: jest.Mock = jest.fn(
141
+ async (query: RetentionQuery): Promise<DeleteResult> => {
142
+ beforeDelete?.();
143
+ const cutoff: Date = queryCutoff(query);
144
+ expect(query._id?.getSql!("id")).toMatch(/^\(id IN \(:\.\.\.\w+\)\)$/);
145
+ const ids: Array<string> = Object.values(
146
+ query._id!.objectLiteralParameters!,
147
+ )[0];
148
+ let affected: number = 0;
149
+ for (let index: number = rows.length - 1; index >= 0; index--) {
150
+ const row: Session = rows[index]!;
151
+ if (
152
+ ids.includes(row.id!.toString()) &&
153
+ row.refreshTokenExpiresAt &&
154
+ row.refreshTokenExpiresAt < cutoff
155
+ ) {
156
+ rows.splice(index, 1);
157
+ affected++;
158
+ }
159
+ }
160
+ return { affected, raw: [] };
161
+ },
162
+ );
163
+ getJestSpyOn(entry.service, "getRepository").mockReturnValue({
164
+ delete: deleteRows,
165
+ } as unknown as Repository<Session>);
166
+ return { rows, find, deleteRows };
167
+ }
168
+
169
+ function jobRegistration(): [
170
+ string,
171
+ { schedule: string; runOnStartup: boolean },
172
+ CronHandler,
173
+ ] {
174
+ const registration: Array<unknown> | undefined = (
175
+ RunCron as jest.Mock
176
+ ).mock.calls.find((call: Array<unknown>): boolean => {
177
+ return call[0] === JOB_NAME;
178
+ });
179
+ expect(registration).toBeDefined();
180
+ return registration as [
181
+ string,
182
+ { schedule: string; runOnStartup: boolean },
183
+ CronHandler,
184
+ ];
185
+ }
186
+
187
+ describe("session personal data retention", () => {
188
+ beforeEach(() => {
189
+ jest.restoreAllMocks();
190
+ jest.useFakeTimers();
191
+ jest.setSystemTime(NOW);
192
+ Services.splice(0, Services.length);
193
+ });
194
+
195
+ afterEach(() => {
196
+ jest.useRealTimers();
197
+ jest.restoreAllMocks();
198
+ });
199
+
200
+ test("runs daily without requiring billing or running immediately at startup", () => {
201
+ expect(jobRegistration()[1]).toEqual({
202
+ schedule: EVERY_DAY,
203
+ runOnStartup: false,
204
+ });
205
+ });
206
+
207
+ test.each(SESSION_CASES)(
208
+ "$name is registered and retains 30 days after credential expiry",
209
+ (entry: SessionCase) => {
210
+ expect(entry.service.hardDeleteItemByColumnName).toBe(
211
+ "refreshTokenExpiresAt",
212
+ );
213
+ expect(entry.service.hardDeleteItemsOlderThanDays).toBe(30);
214
+ const registry: string = fs.readFileSync(
215
+ path.resolve(__dirname, "../../../Server/Services/Index.ts"),
216
+ "utf8",
217
+ );
218
+ expect(registry).toContain(
219
+ `import ${entry.name}Service from "./${entry.name}Service";`,
220
+ );
221
+ expect(registry).toMatch(new RegExp(`^ ${entry.name}Service,$`, "m"));
222
+ const workers: string = fs.readFileSync(
223
+ path.resolve(__dirname, "../../../../App/FeatureSet/Workers/Index.ts"),
224
+ "utf8",
225
+ );
226
+ expect(workers).toContain(
227
+ 'import "./Jobs/HardDelete/HardDeleteItemsInDatabase";',
228
+ );
229
+ },
230
+ );
231
+
232
+ test.each(SESSION_CASES)(
233
+ "$name physically deletes expired, revoked, and abandoned code sessions across batches",
234
+ async (entry: SessionCase) => {
235
+ const expired: Session = sessionRow(
236
+ entry,
237
+ new Date(CUTOFF.getTime() - 1),
238
+ );
239
+ const revoked: Session = sessionRow(
240
+ entry,
241
+ new Date(CUTOFF.getTime() - DAY_MS),
242
+ { isRevoked: true, revokedAt: new Date(NOW.getTime() - 60 * DAY_MS) },
243
+ );
244
+ const abandonedCode: Session = sessionRow(
245
+ entry,
246
+ new Date(CUTOFF.getTime() - 5 * 60 * 1000),
247
+ { additionalInfo: { oneuptimeStatusPageSessionPurpose: "login-code" } },
248
+ );
249
+ const softDeleted: Session = sessionRow(
250
+ entry,
251
+ new Date(CUTOFF.getTime() - DAY_MS),
252
+ { deletedAt: new Date(NOW.getTime() - DAY_MS) },
253
+ );
254
+ const recentExpired: Session = sessionRow(
255
+ entry,
256
+ new Date(NOW.getTime() - DAY_MS),
257
+ );
258
+ const boundary: Session = sessionRow(entry, CUTOFF);
259
+ const renewed: Session = sessionRow(
260
+ entry,
261
+ new Date(NOW.getTime() + 30 * DAY_MS),
262
+ );
263
+ const recentlyRevoked: Session = sessionRow(
264
+ entry,
265
+ new Date(NOW.getTime() + DAY_MS),
266
+ { isRevoked: true, revokedAt: NOW },
267
+ );
268
+ const retained: Array<Session> = [
269
+ recentExpired,
270
+ boundary,
271
+ renewed,
272
+ recentlyRevoked,
273
+ ];
274
+ const database: RepositoryBoundary = installRepositoryBoundary(entry, [
275
+ expired,
276
+ revoked,
277
+ abandonedCode,
278
+ softDeleted,
279
+ ...retained,
280
+ ]);
281
+ Services.push(entry.service);
282
+
283
+ await jobRegistration()[2]();
284
+
285
+ expect(database.rows).toEqual(retained);
286
+ expect(database.deleteRows).toHaveBeenCalledTimes(2);
287
+ expect(database.find).toHaveBeenCalledTimes(3);
288
+ expect(renewed.ipAddress).toBe("192.0.2.10");
289
+ },
290
+ );
291
+
292
+ test.each(SESSION_CASES)(
293
+ "$name keeps the expiry condition on the physical delete",
294
+ async (entry: SessionCase) => {
295
+ const row: Session = sessionRow(entry, new Date(CUTOFF.getTime() - 1));
296
+ const database: RepositoryBoundary = installRepositoryBoundary(
297
+ entry,
298
+ [row],
299
+ (): void => {
300
+ row.refreshTokenExpiresAt = new Date(NOW.getTime() + 30 * DAY_MS);
301
+ },
302
+ );
303
+ Services.push(entry.service);
304
+
305
+ await jobRegistration()[2]();
306
+
307
+ expect(database.rows).toEqual([row]);
308
+ expect(database.deleteRows).toHaveBeenCalledTimes(1);
309
+ },
310
+ );
311
+
312
+ test("continues purging the other session table if one table fails", async () => {
313
+ const privateSessions: SessionCase = SESSION_CASES[0]!;
314
+ const userSessions: SessionCase = SESSION_CASES[1]!;
315
+ const failure: Error = new Error("Database unavailable");
316
+ getJestSpyOn(privateSessions.service, "hardDeleteBy").mockRejectedValue(
317
+ failure,
318
+ );
319
+ const log: jest.SpyInstance = getJestSpyOn(
320
+ logger,
321
+ "error",
322
+ ).mockImplementation(() => {});
323
+ const database: RepositoryBoundary = installRepositoryBoundary(
324
+ userSessions,
325
+ [sessionRow(userSessions, new Date(CUTOFF.getTime() - 1))],
326
+ );
327
+ Services.push(privateSessions.service, userSessions.service);
328
+
329
+ await jobRegistration()[2]();
330
+
331
+ expect(log).toHaveBeenCalledWith(failure);
332
+ expect(database.rows).toEqual([]);
333
+ });
334
+ });
@@ -0,0 +1,172 @@
1
+ import StatusPage from "../../../Models/DatabaseModels/StatusPage";
2
+ import StatusPagePrivateUser from "../../../Models/DatabaseModels/StatusPagePrivateUser";
3
+ import DatabaseConfig from "../../../Server/DatabaseConfig";
4
+ import { EncryptionSecret } from "../../../Server/EnvironmentConfig";
5
+ import MailService from "../../../Server/Services/MailService";
6
+ import { Service } from "../../../Server/Services/StatusPagePrivateUserService";
7
+ import StatusPageService from "../../../Server/Services/StatusPageService";
8
+ import Hostname from "../../../Types/API/Hostname";
9
+ import Protocol from "../../../Types/API/Protocol";
10
+ import Email from "../../../Types/Email";
11
+ import EmailTemplateType from "../../../Types/Email/EmailTemplateType";
12
+ import HashedString from "../../../Types/HashedString";
13
+ import ObjectID from "../../../Types/ObjectID";
14
+ import { getJestSpyOn } from "../../Spy";
15
+ import {
16
+ afterEach,
17
+ beforeEach,
18
+ describe,
19
+ expect,
20
+ jest,
21
+ test,
22
+ } from "@jest/globals";
23
+
24
+ class TestService extends Service {
25
+ public async completeCreation(
26
+ user: StatusPagePrivateUser,
27
+ ): Promise<StatusPagePrivateUser> {
28
+ return await this.onCreateSuccess(
29
+ {
30
+ createBy: { data: user, props: { isRoot: true } },
31
+ carryForward: null,
32
+ },
33
+ user,
34
+ );
35
+ }
36
+ }
37
+
38
+ const FROZEN_NOW: Date = new Date("2026-09-17T10:00:00.000Z");
39
+ const STATUS_PAGE_URL: string = "https://status.example.com";
40
+
41
+ describe("StatusPagePrivateUserService invitation login policy", () => {
42
+ let service: TestService;
43
+ let user: StatusPagePrivateUser;
44
+ let statusPage: StatusPage;
45
+ let update: jest.SpyInstance;
46
+ let sendMail: jest.SpyInstance;
47
+ let findStatusPage: jest.SpyInstance;
48
+
49
+ beforeEach(() => {
50
+ jest.useFakeTimers();
51
+ jest.setSystemTime(FROZEN_NOW);
52
+
53
+ service = new TestService();
54
+ statusPage = new StatusPage();
55
+ statusPage.id = ObjectID.generate();
56
+ statusPage.projectId = ObjectID.generate();
57
+ statusPage.name = "Example status";
58
+ statusPage.requireSsoForLogin = false;
59
+
60
+ user = new StatusPagePrivateUser();
61
+ user.id = ObjectID.generate();
62
+ user.statusPageId = statusPage.id!;
63
+ user.projectId = statusPage.projectId!;
64
+ user.email = new Email("private-user@example.com");
65
+ user.isSsoUser = false;
66
+
67
+ update = getJestSpyOn(service, "updateOneById").mockResolvedValue(1);
68
+ sendMail = getJestSpyOn(MailService, "sendMail").mockResolvedValue(
69
+ undefined,
70
+ );
71
+ findStatusPage = getJestSpyOn(
72
+ StatusPageService,
73
+ "findOneById",
74
+ ).mockResolvedValue(statusPage);
75
+ getJestSpyOn(StatusPageService, "getStatusPageURL").mockResolvedValue(
76
+ STATUS_PAGE_URL,
77
+ );
78
+ getJestSpyOn(DatabaseConfig, "getHost").mockResolvedValue(
79
+ new Hostname("status.example.com"),
80
+ );
81
+ getJestSpyOn(DatabaseConfig, "getHttpProtocol").mockResolvedValue(
82
+ Protocol.HTTPS,
83
+ );
84
+ });
85
+
86
+ afterEach(() => {
87
+ jest.useRealTimers();
88
+ jest.restoreAllMocks();
89
+ });
90
+
91
+ test.each([false, undefined])(
92
+ "SCIM and admin-created users with isSsoUser=%s receive no password link when the page requires SSO",
93
+ async (isSsoUser: boolean | undefined) => {
94
+ if (isSsoUser === undefined) {
95
+ delete user.isSsoUser;
96
+ } else {
97
+ user.isSsoUser = isSsoUser;
98
+ }
99
+ statusPage.requireSsoForLogin = true;
100
+
101
+ await expect(service.completeCreation(user)).resolves.toBe(user);
102
+
103
+ expect(findStatusPage).toHaveBeenCalledWith(
104
+ expect.objectContaining({
105
+ id: user.statusPageId,
106
+ select: expect.objectContaining({ requireSsoForLogin: true }),
107
+ }),
108
+ );
109
+ expect(update).not.toHaveBeenCalled();
110
+ expect(sendMail).not.toHaveBeenCalled();
111
+ expect(StatusPageService.getStatusPageURL).not.toHaveBeenCalled();
112
+ },
113
+ );
114
+
115
+ test("SSO sign-ups do not create an unused password-reset credential", async () => {
116
+ user.isSsoUser = true;
117
+
118
+ await expect(service.completeCreation(user)).resolves.toBe(user);
119
+
120
+ expect(findStatusPage).not.toHaveBeenCalled();
121
+ expect(update).not.toHaveBeenCalled();
122
+ expect(sendMail).not.toHaveBeenCalled();
123
+ });
124
+
125
+ test("password-enabled pages still send a usable invitation and persist only its digest", async () => {
126
+ await expect(service.completeCreation(user)).resolves.toBe(user);
127
+
128
+ expect(sendMail).toHaveBeenCalledTimes(1);
129
+ expect(update).toHaveBeenCalledTimes(1);
130
+ const invitation: {
131
+ vars: { tokenVerifyUrl: string };
132
+ } = sendMail.mock.calls[0]![0];
133
+ const resetUrl: string = invitation.vars.tokenVerifyUrl;
134
+ expect(resetUrl).toMatch(
135
+ /^https:\/\/status\.example\.com\/reset-password\//,
136
+ );
137
+ const rawToken: string = resetUrl.split("/reset-password/")[1]!;
138
+ expect(ObjectID.isValidUUID(rawToken)).toBe(true);
139
+ const digest: string = await HashedString.hashValue(
140
+ rawToken,
141
+ EncryptionSecret,
142
+ );
143
+
144
+ expect(update).toHaveBeenCalledWith({
145
+ id: user.id,
146
+ data: {
147
+ resetPasswordToken: digest,
148
+ resetPasswordExpires: new Date("2026-09-18T10:00:00.000Z"),
149
+ },
150
+ props: { isRoot: true, ignoreHooks: true },
151
+ });
152
+ expect(digest).not.toBe(rawToken);
153
+ expect(sendMail).toHaveBeenCalledWith(
154
+ expect.objectContaining({
155
+ toEmail: user.email,
156
+ templateType: EmailTemplateType.StatusPageWelcomeEmail,
157
+ }),
158
+ expect.objectContaining({ statusPageId: statusPage.id }),
159
+ );
160
+ });
161
+
162
+ test("a missing status page cannot leave an unused reset credential", async () => {
163
+ findStatusPage.mockResolvedValue(null);
164
+
165
+ await expect(service.completeCreation(user)).rejects.toThrow(
166
+ "Status Page not found",
167
+ );
168
+
169
+ expect(update).not.toHaveBeenCalled();
170
+ expect(sendMail).not.toHaveBeenCalled();
171
+ });
172
+ });
@@ -0,0 +1,178 @@
1
+ import StatusPage from "../../../Models/DatabaseModels/StatusPage";
2
+ import StatusPagePrivateUserSession from "../../../Models/DatabaseModels/StatusPagePrivateUserSession";
3
+ import StatusPageService from "../../../Server/Services/StatusPageService";
4
+ import StatusPagePrivateUserSessionService from "../../../Server/Services/StatusPagePrivateUserSessionService";
5
+ import CookieUtil from "../../../Server/Utils/Cookie";
6
+ import { ExpressRequest } from "../../../Server/Utils/Express";
7
+ import JSONWebToken from "../../../Server/Utils/JsonWebToken";
8
+ import logger from "../../../Server/Utils/Logger";
9
+ import Email from "../../../Types/Email";
10
+ import HashedString from "../../../Types/HashedString";
11
+ import { JSONObject } from "../../../Types/JSON";
12
+ import ObjectID from "../../../Types/ObjectID";
13
+ import { MASTER_PASSWORD_COOKIE_IDENTIFIER } from "../../../Types/StatusPage/MasterPassword";
14
+ import { SelectQueryBuilder } from "typeorm";
15
+
16
+ describe("private status page access requires a live session", () => {
17
+ const statusPageId: ObjectID = ObjectID.generate();
18
+ const userId: ObjectID = ObjectID.generate();
19
+ const sessionId: ObjectID = ObjectID.generate();
20
+ let statusPage: StatusPage;
21
+ let session: StatusPagePrivateUserSession;
22
+ let getOne: jest.Mock;
23
+ let query: SelectQueryBuilder<StatusPagePrivateUserSession>;
24
+
25
+ function request(
26
+ claims: JSONObject = {},
27
+ expiresInSeconds: number = 900,
28
+ ): ExpressRequest {
29
+ const token: string = JSONWebToken.sign({
30
+ data: {
31
+ userId,
32
+ email: new Email("private-user@example.com"),
33
+ statusPageId,
34
+ sessionId,
35
+ ...claims,
36
+ },
37
+ expiresInSeconds,
38
+ });
39
+ return {
40
+ cookies: { [CookieUtil.getUserTokenKey(statusPageId)]: token },
41
+ } as ExpressRequest;
42
+ }
43
+
44
+ async function hasAccess(req: ExpressRequest = request()): Promise<boolean> {
45
+ return (await StatusPageService.hasReadAccess({ statusPageId, req }))
46
+ .hasReadAccess;
47
+ }
48
+
49
+ beforeEach(() => {
50
+ statusPage = new StatusPage();
51
+ statusPage.id = statusPageId;
52
+ statusPage.isPublicStatusPage = false;
53
+ session = new StatusPagePrivateUserSession();
54
+ session.id = sessionId;
55
+ session.additionalInfo = {};
56
+ getOne = jest.fn().mockResolvedValue(session);
57
+ query = {
58
+ select: jest.fn().mockReturnThis(),
59
+ innerJoin: jest.fn().mockReturnThis(),
60
+ where: jest.fn().mockReturnThis(),
61
+ andWhere: jest.fn().mockReturnThis(),
62
+ getOne,
63
+ } as unknown as SelectQueryBuilder<StatusPagePrivateUserSession>;
64
+ jest.spyOn(StatusPageService, "findOneById").mockResolvedValue(statusPage);
65
+ jest
66
+ .spyOn(StatusPagePrivateUserSessionService, "getQueryBuilder")
67
+ .mockReturnValue(query);
68
+ jest.spyOn(logger, "error").mockImplementation(() => {});
69
+ });
70
+
71
+ afterEach(() => {
72
+ jest.restoreAllMocks();
73
+ });
74
+
75
+ test("accepts a signed token backed by an active session", async () => {
76
+ expect(await hasAccess()).toBe(true);
77
+ expect(getOne).toHaveBeenCalledTimes(1);
78
+ expect(query.where).toHaveBeenCalledWith("session._id = :sessionId", {
79
+ sessionId: sessionId.toString(),
80
+ });
81
+ expect(query.andWhere).toHaveBeenCalledWith(
82
+ "session.statusPagePrivateUserId = :userId",
83
+ { userId: userId.toString() },
84
+ );
85
+ expect(query.andWhere).toHaveBeenCalledWith(
86
+ "session.statusPageId = :statusPageId",
87
+ { statusPageId: statusPageId.toString() },
88
+ );
89
+ });
90
+
91
+ test("rejects a signed token without a live session", async () => {
92
+ getOne.mockResolvedValue(null);
93
+ expect(await hasAccess()).toBe(false);
94
+ });
95
+
96
+ test("does not cache successful authorization after revocation or deletion", async () => {
97
+ const req: ExpressRequest = request();
98
+ expect(await hasAccess(req)).toBe(true);
99
+ getOne.mockResolvedValue(null);
100
+ expect(await hasAccess(req)).toBe(false);
101
+ expect(getOne).toHaveBeenCalledTimes(2);
102
+ });
103
+
104
+ test("rejects a login-code session even with a valid access token", async () => {
105
+ session.additionalInfo = {
106
+ oneuptimeStatusPageSessionPurpose: "login-code",
107
+ };
108
+ expect(await hasAccess()).toBe(false);
109
+ });
110
+
111
+ test.each(["sessionId", "userId", "statusPageId"])(
112
+ "rejects a token missing %s before reading sessions",
113
+ async (claim: string) => {
114
+ expect(await hasAccess(request({ [claim]: null }))).toBe(false);
115
+ expect(getOne).not.toHaveBeenCalled();
116
+ },
117
+ );
118
+
119
+ test("rejects a token for another status page before reading sessions", async () => {
120
+ expect(
121
+ await hasAccess(request({ statusPageId: ObjectID.generate() })),
122
+ ).toBe(false);
123
+ expect(getOne).not.toHaveBeenCalled();
124
+ });
125
+
126
+ test.each(["sessionId", "userId"])(
127
+ "rejects malformed %s before reading sessions",
128
+ async (claim: string) => {
129
+ expect(await hasAccess(request({ [claim]: "not-a-uuid" }))).toBe(false);
130
+ expect(getOne).not.toHaveBeenCalled();
131
+ },
132
+ );
133
+
134
+ test("rejects an expired JWT before reading sessions", async () => {
135
+ expect(await hasAccess(request({}, -1))).toBe(false);
136
+ expect(getOne).not.toHaveBeenCalled();
137
+ });
138
+
139
+ test("rejects a tampered JWT before reading sessions", async () => {
140
+ const req: ExpressRequest = request();
141
+ req.cookies[CookieUtil.getUserTokenKey(statusPageId)] += "tampered";
142
+ expect(await hasAccess(req)).toBe(false);
143
+ expect(getOne).not.toHaveBeenCalled();
144
+ });
145
+
146
+ test("fails closed if the session database lookup fails", async () => {
147
+ getOne.mockRejectedValue(new Error("Database unavailable"));
148
+ expect(await hasAccess()).toBe(false);
149
+ });
150
+
151
+ test("does not grant access to a missing status page", async () => {
152
+ jest.spyOn(StatusPageService, "findOneById").mockResolvedValue(null);
153
+ expect(await hasAccess()).toBe(false);
154
+ expect(getOne).not.toHaveBeenCalled();
155
+ });
156
+
157
+ test("does not query sessions for public pages", async () => {
158
+ statusPage.isPublicStatusPage = true;
159
+ expect(await hasAccess()).toBe(true);
160
+ expect(getOne).not.toHaveBeenCalled();
161
+ });
162
+
163
+ test("preserves independent master-password access", async () => {
164
+ statusPage.enableMasterPassword = true;
165
+ statusPage.masterPassword = new HashedString("configured");
166
+ getOne.mockResolvedValue(null);
167
+ const req: ExpressRequest = request();
168
+ req.cookies[CookieUtil.getStatusPageMasterPasswordKey(statusPageId)] =
169
+ JSONWebToken.signJsonPayload(
170
+ {
171
+ statusPageId: statusPageId.toString(),
172
+ type: MASTER_PASSWORD_COOKIE_IDENTIFIER,
173
+ },
174
+ 900,
175
+ );
176
+ expect(await hasAccess(req)).toBe(true);
177
+ });
178
+ });