@oneuptime/common 13.0.7 → 13.0.8

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 (463) hide show
  1. package/Models/DatabaseModels/OnCallDutyPolicyScheduleCalendarFeed.ts +1 -1
  2. package/Models/DatabaseModels/ProjectOnCallCalendarFeed.ts +1 -1
  3. package/Models/DatabaseModels/UserOnCallCalendarFeed.ts +1 -1
  4. package/Server/API/AIBillingAPI.ts +1 -0
  5. package/Server/API/AIInsightAPI.ts +1 -4
  6. package/Server/API/AIInvestigationAPI.ts +1 -4
  7. package/Server/API/AIReadinessAPI.ts +4 -5
  8. package/Server/API/AlertAPI.ts +1 -0
  9. package/Server/API/AutoRemediationAPI.ts +1 -4
  10. package/Server/API/BaseAPI.ts +13 -0
  11. package/Server/API/BaseAnalyticsAPI.ts +80 -9
  12. package/Server/API/BillingAPI.ts +2 -0
  13. package/Server/API/BillingInvoiceAPI.ts +1 -0
  14. package/Server/API/BillingPaymentMethodAPI.ts +2 -0
  15. package/Server/API/CodeFixRunAPI.ts +1 -3
  16. package/Server/API/CommonAPI.ts +68 -4
  17. package/Server/API/DashboardAPI.ts +12 -12
  18. package/Server/API/GlobalConfigAPI.ts +17 -0
  19. package/Server/API/IncidentAPI.ts +2 -0
  20. package/Server/API/IncidentEpisodeAPI.ts +1 -0
  21. package/Server/API/NotificationAPI.ts +1 -0
  22. package/Server/API/OnCallCalendarAPI.ts +4 -5
  23. package/Server/API/OnCallDutyPolicyAPI.ts +7 -0
  24. package/Server/API/OnCallReadinessAPI.ts +4 -1
  25. package/Server/API/OnCallScheduleTimelineAPI.ts +731 -0
  26. package/Server/API/ProjectAPI.ts +1 -0
  27. package/Server/API/ScheduledMaintenanceAPI.ts +1 -0
  28. package/Server/API/StatusPageAPI.ts +161 -32
  29. package/Server/API/TeamMemberAPI.ts +3 -0
  30. package/Server/API/UserCallAPI.ts +2 -0
  31. package/Server/API/UserEmailAPI.ts +2 -0
  32. package/Server/API/UserIncomingCallNumberAPI.ts +2 -0
  33. package/Server/API/UserMicrosoftTeamsAPI.ts +1 -0
  34. package/Server/API/UserSlackAPI.ts +1 -0
  35. package/Server/API/UserSmsAPI.ts +2 -0
  36. package/Server/API/UserTotpAuthAPI.ts +1 -0
  37. package/Server/API/UserWebAuthnAPI.ts +2 -0
  38. package/Server/API/UserWebhookAPI.ts +1 -0
  39. package/Server/API/UserWhatsAppAPI.ts +2 -0
  40. package/Server/Middleware/MasterAdminAuthorization.ts +13 -2
  41. package/Server/Middleware/UserAuthorization.ts +79 -5
  42. package/Server/Services/ApiKeyPermissionService.ts +101 -4
  43. package/Server/Services/DatabaseService.ts +245 -0
  44. package/Server/Services/DetectionRuleService.ts +5 -4
  45. package/Server/Services/OnCallDutyPolicyChildService.ts +261 -0
  46. package/Server/Services/OnCallDutyPolicyEscalationRuleScheduleService.ts +2 -2
  47. package/Server/Services/OnCallDutyPolicyEscalationRuleService.ts +2 -2
  48. package/Server/Services/OnCallDutyPolicyEscalationRuleTeamService.ts +2 -2
  49. package/Server/Services/OnCallDutyPolicyEscalationRuleUserService.ts +2 -2
  50. package/Server/Services/PayAsYouGoBillingService.ts +23 -28
  51. package/Server/Services/ProjectService.ts +18 -0
  52. package/Server/Services/RumSessionPinService.ts +274 -22
  53. package/Server/Services/TeamPermissionService.ts +120 -26
  54. package/Server/Services/ThreatIntelFeedService.ts +6 -3
  55. package/Server/Types/Database/Permissions/BasePermission.ts +9 -7
  56. package/Server/Types/Database/Permissions/Index.ts +75 -11
  57. package/Server/Types/Database/Permissions/TablePermission.ts +24 -28
  58. package/Server/Utils/AI/AIChatPrivacyFilter.ts +8 -0
  59. package/Server/Utils/AI/AIRunPrivacyFilter.ts +8 -0
  60. package/Server/Utils/MasterAdminPageAccess.ts +61 -0
  61. package/Server/Utils/Monitor/MonitorAlert.ts +3 -1
  62. package/Server/Utils/Monitor/MonitorIncident.ts +3 -1
  63. package/Server/Utils/OnCall/OnCallCalendarFeedRenderer.ts +1 -1
  64. package/Server/Utils/Realtime.ts +163 -45
  65. package/Server/Utils/SecurityEvent/DetectionRuleEvaluator.ts +11 -28
  66. package/Server/Utils/SecurityEvent/GoogleSecOpsSeverityRepair.ts +170 -0
  67. package/Server/Utils/SecurityEvent/Sigma/SigmaClickhouseCompiler.ts +1 -1
  68. package/Server/Utils/SecurityEvent/ThreatIntel/ThreatIntelFeedPoller.ts +6 -2
  69. package/Server/Utils/SecurityEvent/ThreatIntel/ThreatIntelMatcher.ts +10 -9
  70. package/Tests/App/Dashboard/AffectedResourcesPicker.test.tsx +1059 -0
  71. package/Tests/App/Dashboard/AffectedResourcesPickerEditForm.test.tsx +376 -0
  72. package/Tests/App/Dashboard/AffectedResourcesPickerHiddenTypes.test.tsx +757 -0
  73. package/Tests/App/Dashboard/AffectedResourcesSummaryStep.test.tsx +307 -0
  74. package/Tests/App/Dashboard/ArgumentsFormGroupByUnlistedAttributes.test.tsx +131 -0
  75. package/Tests/App/Dashboard/DashboardHeaderRequests.test.tsx +1 -1
  76. package/Tests/App/Dashboard/DashboardMonitorLabelVariable.test.tsx +9 -1
  77. package/Tests/App/Dashboard/DashboardVariableAllContract.test.tsx +24 -0
  78. package/Tests/App/Dashboard/DashboardVariableSelector.test.tsx +162 -8
  79. package/Tests/App/Dashboard/EntityFilterDropdownArchivedSlos.test.tsx +105 -6
  80. package/Tests/App/Dashboard/EntityFilterDropdownUnlistedSelection.test.tsx +434 -0
  81. package/Tests/App/Dashboard/EscalationRuleReadiness.test.tsx +276 -1
  82. package/Tests/App/Dashboard/OnCallCalendarFeedSideMenus.test.tsx +9 -1
  83. package/Tests/App/Dashboard/PayAsYouGoConsentGate.test.tsx +58 -42
  84. package/Tests/App/Dashboard/PayAsYouGoNotices.test.tsx +42 -5
  85. package/Tests/App/Dashboard/ResourceAuditLogsSideMenus.test.tsx +34 -23
  86. package/Tests/App/Dashboard/ScheduleTimeline.test.tsx +1580 -0
  87. package/Tests/App/Dashboard/ScheduleTimelineAPI.test.ts +280 -0
  88. package/Tests/App/Dashboard/ScheduleTimelineModel.test.ts +673 -0
  89. package/Tests/App/Dashboard/SecurityEventConnectionDiagnostics.test.tsx +95 -68
  90. package/Tests/App/Dashboard/SecurityEventsDetectionRulesPage.test.tsx +86 -3
  91. package/Tests/App/Dashboard/SecurityEventsEmptyState.test.tsx +28 -3
  92. package/Tests/App/Dashboard/SecurityEventsExplorer.test.tsx +761 -0
  93. package/Tests/App/Dashboard/SecurityEventsGuideContent.test.ts +1313 -0
  94. package/Tests/App/Dashboard/SecurityEventsHowItWorksCard.test.tsx +536 -0
  95. package/Tests/App/Dashboard/SecurityEventsNoResults.test.tsx +222 -0
  96. package/Tests/App/Dashboard/SecurityEventsThreatIntelPage.test.tsx +199 -0
  97. package/Tests/App/Dashboard/SecurityEventsVolumeChart.test.tsx +321 -0
  98. package/Tests/App/Dashboard/SloOverviewHero.test.tsx +171 -36
  99. package/Tests/App/Dashboard/SloViewSideMenu.test.tsx +215 -0
  100. package/Tests/App/Dashboard/SloViewSideMenuCounts.test.tsx +40 -3
  101. package/Tests/App/PublicDashboard/DashboardVariableSelector.test.tsx +12 -4
  102. package/Tests/App/PublicDashboard/PublicDashboardWidgetListAuth.test.tsx +623 -0
  103. package/Tests/Models/OnCallCalendarFeedModels.test.ts +23 -1
  104. package/Tests/Server/API/AIChatRouteAuthorization.test.ts +138 -5
  105. package/Tests/Server/API/AIGenerationProjectAIToggle.test.ts +187 -0
  106. package/Tests/Server/API/AIInvestigationAvailabilityAuthorization.test.ts +51 -3
  107. package/Tests/Server/API/AIInvestigationEvidenceAPI.test.ts +55 -2
  108. package/Tests/Server/API/BaseAnalyticsAPIAggregateCache.test.ts +729 -0
  109. package/Tests/Server/API/BillingPayAsYouGoStatus.test.ts +93 -7
  110. package/Tests/Server/API/BillingPaymentMethodAPI.test.ts +36 -3
  111. package/Tests/Server/API/CommonAPIAuthGuard.test.ts +1003 -24
  112. package/Tests/Server/API/DashboardPublicRateLimit.test.ts +6 -3
  113. package/Tests/Server/API/ExpiredSessionAIRoutes.test.ts +708 -0
  114. package/Tests/Server/API/ExpiredSessionCustomRoutes.test.ts +928 -0
  115. package/Tests/Server/API/ExpiredSessionMonitorTemplate.test.ts +319 -0
  116. package/Tests/Server/API/ExpiredSessionOnCallDutyPolicy.test.ts +336 -0
  117. package/Tests/Server/API/ExpiredSessionRouteGuards.test.ts +820 -0
  118. package/Tests/Server/API/GlobalConfigLicense.test.ts +140 -0
  119. package/Tests/Server/API/NotificationChannelVerificationAPI.test.ts +115 -12
  120. package/Tests/Server/API/OnCallCalendarAPI.test.ts +375 -8
  121. package/Tests/Server/API/OnCallReadinessAPI.test.ts +175 -17
  122. package/Tests/Server/API/OnCallScheduleTimelineAPI.test.ts +1513 -0
  123. package/Tests/Server/API/OnCallSetupReminderAPI.test.ts +119 -7
  124. package/Tests/Server/API/ProjectScopedCustomRouteAuth.test.ts +111 -4
  125. package/Tests/Server/API/PublicRouteInvalidAccessToken.test.ts +615 -0
  126. package/Tests/Server/API/SecurityEventAttributesAPI.test.ts +89 -2
  127. package/Tests/Server/API/SessionReplayAPI.test.ts +121 -0
  128. package/Tests/Server/API/StatusPageMasterPasswordRateLimit.test.ts +4 -2
  129. package/Tests/Server/API/StatusPagePostmortemVisibility.test.ts +441 -0
  130. package/Tests/Server/API/StatusPageTestEmailReportAuth.test.ts +664 -0
  131. package/Tests/Server/API/TeamMemberRemoveUserFromProjectAPI.test.ts +7 -0
  132. package/Tests/Server/API/UserIncomingCallNumberApi.test.ts +6 -0
  133. package/Tests/Server/API/UserNotificationSettingAPI.test.ts +65 -4
  134. package/Tests/Server/API/UserProjectsAPI.test.ts +63 -3
  135. package/Tests/Server/API/UserTotpAuthAPI.test.ts +48 -2
  136. package/Tests/Server/API/UserWebAuthnAuthenticationOptionsRoute.test.ts +11 -2
  137. package/Tests/Server/API/UserWebAuthnBackupCodeMinting.test.ts +46 -3
  138. package/Tests/Server/API/UserWebAuthnPasskeyAPI.test.ts +18 -2
  139. package/Tests/Server/API/ZZVerifyChatsAuth.test.ts +24 -7
  140. package/Tests/Server/Middleware/ExpiredSessionUserMiddleware.test.ts +563 -0
  141. package/Tests/Server/Middleware/MasterAdminAuthorization.test.ts +299 -19
  142. package/Tests/Server/Middleware/PublicRouteUserMiddleware.test.ts +453 -0
  143. package/Tests/Server/Services/AIChatPrivacyPin.test.ts +24 -0
  144. package/Tests/Server/Services/ApiKeyPermissionSecurity.test.ts +2 -0
  145. package/Tests/Server/Services/ApiKeyPermissionService.test.ts +3 -3
  146. package/Tests/Server/Services/DatabaseServiceCreateSuppliedId.test.ts +147 -0
  147. package/Tests/Server/Services/DatabaseServiceLoginBeforeHooks.test.ts +1078 -0
  148. package/Tests/Server/Services/DatabaseServiceTenantRelationGuard.test.ts +259 -0
  149. package/Tests/Server/Services/DatabaseServiceWriteOperatorValues.test.ts +147 -0
  150. package/Tests/Server/Services/MonitorPayAsYouGoBilling.test.ts +115 -1
  151. package/Tests/Server/Services/OnCallChildCreateAuthorizationPostgres.test.ts +711 -0
  152. package/Tests/Server/Services/OnCallDutyPolicyChildService.test.ts +733 -0
  153. package/Tests/Server/Services/PayAsYouGoBillingService.test.ts +190 -140
  154. package/Tests/Server/Services/PayAsYouGoStripeRateLimitBudget.test.ts +4 -9
  155. package/Tests/Server/Services/PermissionBlockDeletion.test.ts +780 -0
  156. package/Tests/Server/Services/PermissionBlockDeletionPostgres.test.ts +628 -0
  157. package/Tests/Server/Services/ProjectServiceCreateSubscriptionStarted.test.ts +77 -1
  158. package/Tests/Server/Services/RumSessionPinCreatePermission.test.ts +715 -0
  159. package/Tests/Server/Services/TeamMemberMultiTenantReadPostgres.test.ts +394 -0
  160. package/Tests/Server/Services/TeamPrivilegeEscalation.test.ts +6 -0
  161. package/Tests/Server/Services/TelemetryPayAsYouGoBilling.test.ts +131 -0
  162. package/Tests/Server/Services/UserNotificationRuleAdminGuards.test.ts +13 -2
  163. package/Tests/Server/Types/Database/Permissions/ModelPermissionAnonymousRefusal.test.ts +518 -0
  164. package/Tests/Server/Types/Database/Permissions/MultiTenantPermissions.test.ts +350 -0
  165. package/Tests/Server/Types/Database/Permissions/OnCallCalendarFeedPermissions.test.ts +282 -25
  166. package/Tests/Server/Types/Database/Permissions/TableLevelBlockPermission.test.ts +459 -0
  167. package/Tests/Server/Utils/AI/AIRunPrivacyFilter.test.ts +101 -9
  168. package/Tests/Server/Utils/AI/ChatAgentHelpers.test.ts +88 -4
  169. package/Tests/Server/Utils/AI/Toolbox/ExceptionTools.test.ts +459 -0
  170. package/Tests/Server/Utils/AI/Toolbox/LogTools.test.ts +794 -0
  171. package/Tests/Server/Utils/AI/Toolbox/RecentChangesTools.test.ts +574 -0
  172. package/Tests/Server/Utils/AI/Toolbox/SecurityEventTools.test.ts +596 -0
  173. package/Tests/Server/Utils/CaptchaRequestAndLogging.test.ts +395 -0
  174. package/Tests/Server/Utils/MasterAdminPageAccess.test.ts +251 -0
  175. package/Tests/Server/Utils/Monitor/MonitorActionTimestamps.test.ts +616 -0
  176. package/Tests/Server/Utils/Realtime.test.ts +502 -0
  177. package/Tests/Server/Utils/SecurityEvent/Connectors/GoogleSecOps/GoogleSecOpsConnectorSeverity.test.ts +216 -0
  178. package/Tests/Server/Utils/SecurityEvent/DetectionRuleEvaluator.test.ts +142 -0
  179. package/Tests/Server/Utils/SecurityEvent/GoogleSecOpsSeverityRepair.test.ts +140 -0
  180. package/Tests/Server/Utils/SecurityEvent/GoogleSecOpsSeverityRepairClickhouseIntegration.test.ts +542 -0
  181. package/Tests/Server/Utils/Telemetry/ChangeEventRow.test.ts +743 -0
  182. package/Tests/Server/Utils/Telemetry/RuntimeMetrics.test.ts +465 -0
  183. package/Tests/Server/Utils/Workspace/MicrosoftTeams/Messages/Alert.test.ts +202 -0
  184. package/Tests/Server/Utils/Workspace/MicrosoftTeams/Messages/Incident.test.ts +194 -0
  185. package/Tests/Server/Utils/Workspace/MicrosoftTeams/Messages/ScheduledMaintenance.test.ts +231 -0
  186. package/Tests/Server/Utils/Workspace/Slack/Messages/Alert.test.ts +194 -0
  187. package/Tests/Server/Utils/Workspace/Slack/Messages/AlertEpisode.test.ts +194 -0
  188. package/Tests/Server/Utils/Workspace/Slack/Messages/Incident.test.ts +194 -0
  189. package/Tests/Server/Utils/Workspace/Slack/Messages/IncidentEpisode.test.ts +194 -0
  190. package/Tests/Server/Utils/Workspace/Slack/Messages/ScheduledMaintenance.test.ts +247 -0
  191. package/Tests/Types/AI/AIInsightEvidence.test.ts +206 -0
  192. package/Tests/Types/BaseDatabase/DatabaseCommonInteractionPropsUtilAnonymous.test.ts +144 -0
  193. package/Tests/Types/Call/CallProvider.test.ts +528 -0
  194. package/Tests/Types/Kubernetes/KubernetesCostIngest.test.ts +236 -0
  195. package/Tests/Types/OnCallDutyPolicy/ScheduleTimeline.test.ts +736 -0
  196. package/Tests/Types/OnCallDutyPolicy/ScheduleTimelineLayout.test.ts +996 -0
  197. package/Tests/Types/SecurityEvent/SigmaRule.test.ts +142 -0
  198. package/Tests/Types/Workflow/Components/JSON.test.ts +182 -0
  199. package/Tests/UI/Components/BasicFormDropdownNormalization.test.tsx +116 -1
  200. package/Tests/UI/Components/Dropdown/DropdownAsyncOptions.test.tsx +81 -0
  201. package/Tests/UI/Components/EditionLabelLicenseRefresh.test.tsx +89 -1
  202. package/Tests/UI/Components/EventAttachmentList.test.tsx +174 -0
  203. package/Tests/UI/Components/Forms/BasicFormBurnRateTemplateDefaults.test.tsx +395 -0
  204. package/Tests/UI/Components/Forms/BasicFormCollapsibleSections.test.tsx +286 -0
  205. package/Tests/UI/Components/Forms/FormSummary.test.tsx +128 -0
  206. package/Tests/UI/Components/ModelTable/BaseModelTableQueryChange.test.tsx +365 -0
  207. package/Tests/UI/Components/OpenAuthenticatedUrl.test.ts +358 -0
  208. package/Tests/UI/Components/SessionAwareImage.test.tsx +496 -0
  209. package/Tests/UI/Components/TelemetryHistogramZeroBuckets.test.tsx +190 -0
  210. package/Tests/UI/Components/TooltipInteractive.test.tsx +97 -0
  211. package/Tests/UI/MicrosoftTeams/MicrosoftTeamsChatsCardInstallGuidance.test.tsx +1 -1
  212. package/Tests/UI/Monitor/EvaluationLogListTimestamps.test.tsx +367 -0
  213. package/Tests/UI/Utils/API/BaseAPIRefreshSession.test.ts +1087 -0
  214. package/Tests/UI/Utils/API/DashboardHost.ts +12 -0
  215. package/Tests/UI/Utils/API/FakeAxiosServer.ts +183 -0
  216. package/Tests/UI/Utils/Breadcrumb/fixtures/RealBreadcrumbTrails.ts +10 -0
  217. package/Tests/UI/Utils/Breadcrumb/fixtures/RealRoutePatterns.ts +2 -0
  218. package/Tests/UI/Utils/Cookie.test.ts +440 -0
  219. package/Tests/UI/Utils/ModelAPIRequestClient.test.ts +278 -0
  220. package/Tests/UI/Utils/Navigation.test.ts +33 -0
  221. package/Tests/UI/Utils/PricingPlan.test.ts +295 -0
  222. package/Tests/UI/Utils/Realtime.test.ts +759 -0
  223. package/Tests/UI/Utils/Telemetry/Telemetry.test.ts +500 -0
  224. package/Tests/Utils/APIInstanceDispatch.test.ts +311 -0
  225. package/Tests/Utils/SecurityEvent/GoogleSecOpsAlertNormalizerSeverity.test.ts +565 -0
  226. package/Types/BaseDatabase/DatabaseCommonInteractionPropsUtil.ts +40 -0
  227. package/Types/Monitor/MonitorEvaluationSummary.ts +3 -0
  228. package/Types/OnCallDutyPolicy/ScheduleTimeline.ts +507 -0
  229. package/Types/OnCallDutyPolicy/ScheduleTimelineLayout.ts +589 -0
  230. package/Types/Realtime/EventName.ts +11 -0
  231. package/Types/SecurityEvent/DetectionFindingConstants.ts +14 -0
  232. package/Types/SecurityEvent/OcsfSeverity.ts +31 -26
  233. package/Types/SecurityEvent/SigmaRule.ts +51 -0
  234. package/Types/SecurityEvent/ThreatIntelConstants.ts +18 -0
  235. package/UI/Components/AttachmentList/EventAttachmentList.tsx +30 -2
  236. package/UI/Components/Dashboard/DashboardVariableControl.tsx +12 -2
  237. package/UI/Components/Dropdown/Dropdown.tsx +6 -1
  238. package/UI/Components/EditionLabel/EditionLabel.tsx +12 -0
  239. package/UI/Components/EventItem/EventItem.tsx +12 -1
  240. package/UI/Components/Forms/BasicForm.tsx +151 -126
  241. package/UI/Components/Forms/CollapsibleFormSection.tsx +63 -0
  242. package/UI/Components/Forms/Fields/FormField.tsx +10 -4
  243. package/UI/Components/Forms/FormSummary.tsx +7 -0
  244. package/UI/Components/Forms/Types/Field.ts +10 -0
  245. package/UI/Components/Markdown.tsx/MarkdownViewer.tsx +2 -1
  246. package/UI/Components/Markdown.tsx/SessionAwareImage.tsx +122 -0
  247. package/UI/Components/ModelTable/BaseModelTable.tsx +34 -5
  248. package/UI/Components/ModelTable/TableView.tsx +1 -1
  249. package/UI/Components/TelemetryViewer/components/TelemetryHistogram.tsx +8 -1
  250. package/UI/Components/Tooltip/Tooltip.tsx +8 -1
  251. package/UI/Utils/API/API.ts +173 -12
  252. package/UI/Utils/API/RequestOptions.ts +11 -0
  253. package/UI/Utils/AnalyticsModelAPI/AnalyticsModelAPI.ts +31 -7
  254. package/UI/Utils/ModelAPI/ModelAPI.ts +30 -9
  255. package/UI/Utils/Navigation.ts +9 -0
  256. package/UI/Utils/OpenAuthenticatedUrl.ts +154 -0
  257. package/UI/Utils/Realtime.ts +176 -30
  258. package/Utils/API.ts +14 -5
  259. package/Utils/SecurityEvent/GoogleSecOpsAlertNormalizer.ts +157 -7
  260. package/Utils/SecurityEvent/Sigma/SigmaRuleParser.ts +9 -17
  261. package/Utils/Slo/SloBurnRateTemplate.ts +2 -2
  262. package/build/dist/Models/DatabaseModels/OnCallDutyPolicyScheduleCalendarFeed.js +1 -1
  263. package/build/dist/Models/DatabaseModels/OnCallDutyPolicyScheduleCalendarFeed.js.map +1 -1
  264. package/build/dist/Models/DatabaseModels/ProjectOnCallCalendarFeed.js +1 -1
  265. package/build/dist/Models/DatabaseModels/ProjectOnCallCalendarFeed.js.map +1 -1
  266. package/build/dist/Models/DatabaseModels/UserOnCallCalendarFeed.js +1 -1
  267. package/build/dist/Models/DatabaseModels/UserOnCallCalendarFeed.js.map +1 -1
  268. package/build/dist/Server/API/AIBillingAPI.js +1 -1
  269. package/build/dist/Server/API/AIBillingAPI.js.map +1 -1
  270. package/build/dist/Server/API/AIInsightAPI.js +1 -4
  271. package/build/dist/Server/API/AIInsightAPI.js.map +1 -1
  272. package/build/dist/Server/API/AIInvestigationAPI.js +1 -4
  273. package/build/dist/Server/API/AIInvestigationAPI.js.map +1 -1
  274. package/build/dist/Server/API/AIReadinessAPI.js +1 -3
  275. package/build/dist/Server/API/AIReadinessAPI.js.map +1 -1
  276. package/build/dist/Server/API/AlertAPI.js +1 -1
  277. package/build/dist/Server/API/AlertAPI.js.map +1 -1
  278. package/build/dist/Server/API/AutoRemediationAPI.js +1 -4
  279. package/build/dist/Server/API/AutoRemediationAPI.js.map +1 -1
  280. package/build/dist/Server/API/BaseAPI.js +12 -0
  281. package/build/dist/Server/API/BaseAPI.js.map +1 -1
  282. package/build/dist/Server/API/BaseAnalyticsAPI.js +55 -10
  283. package/build/dist/Server/API/BaseAnalyticsAPI.js.map +1 -1
  284. package/build/dist/Server/API/BillingAPI.js +2 -2
  285. package/build/dist/Server/API/BillingAPI.js.map +1 -1
  286. package/build/dist/Server/API/BillingInvoiceAPI.js +1 -1
  287. package/build/dist/Server/API/BillingInvoiceAPI.js.map +1 -1
  288. package/build/dist/Server/API/BillingPaymentMethodAPI.js +2 -2
  289. package/build/dist/Server/API/BillingPaymentMethodAPI.js.map +1 -1
  290. package/build/dist/Server/API/CodeFixRunAPI.js +1 -3
  291. package/build/dist/Server/API/CodeFixRunAPI.js.map +1 -1
  292. package/build/dist/Server/API/CommonAPI.js +50 -5
  293. package/build/dist/Server/API/CommonAPI.js.map +1 -1
  294. package/build/dist/Server/API/DashboardAPI.js +12 -12
  295. package/build/dist/Server/API/DashboardAPI.js.map +1 -1
  296. package/build/dist/Server/API/GlobalConfigAPI.js +12 -0
  297. package/build/dist/Server/API/GlobalConfigAPI.js.map +1 -1
  298. package/build/dist/Server/API/IncidentAPI.js +2 -2
  299. package/build/dist/Server/API/IncidentAPI.js.map +1 -1
  300. package/build/dist/Server/API/IncidentEpisodeAPI.js +1 -1
  301. package/build/dist/Server/API/IncidentEpisodeAPI.js.map +1 -1
  302. package/build/dist/Server/API/NotificationAPI.js +1 -1
  303. package/build/dist/Server/API/NotificationAPI.js.map +1 -1
  304. package/build/dist/Server/API/OnCallCalendarAPI.js +1 -4
  305. package/build/dist/Server/API/OnCallCalendarAPI.js.map +1 -1
  306. package/build/dist/Server/API/OnCallDutyPolicyAPI.js +6 -0
  307. package/build/dist/Server/API/OnCallDutyPolicyAPI.js.map +1 -1
  308. package/build/dist/Server/API/OnCallReadinessAPI.js +4 -1
  309. package/build/dist/Server/API/OnCallReadinessAPI.js.map +1 -1
  310. package/build/dist/Server/API/OnCallScheduleTimelineAPI.js +494 -0
  311. package/build/dist/Server/API/OnCallScheduleTimelineAPI.js.map +1 -0
  312. package/build/dist/Server/API/ProjectAPI.js +1 -1
  313. package/build/dist/Server/API/ProjectAPI.js.map +1 -1
  314. package/build/dist/Server/API/ScheduledMaintenanceAPI.js +1 -1
  315. package/build/dist/Server/API/ScheduledMaintenanceAPI.js.map +1 -1
  316. package/build/dist/Server/API/StatusPageAPI.js +125 -33
  317. package/build/dist/Server/API/StatusPageAPI.js.map +1 -1
  318. package/build/dist/Server/API/TeamMemberAPI.js +3 -3
  319. package/build/dist/Server/API/TeamMemberAPI.js.map +1 -1
  320. package/build/dist/Server/API/UserCallAPI.js +2 -2
  321. package/build/dist/Server/API/UserCallAPI.js.map +1 -1
  322. package/build/dist/Server/API/UserEmailAPI.js +2 -2
  323. package/build/dist/Server/API/UserEmailAPI.js.map +1 -1
  324. package/build/dist/Server/API/UserIncomingCallNumberAPI.js +2 -2
  325. package/build/dist/Server/API/UserIncomingCallNumberAPI.js.map +1 -1
  326. package/build/dist/Server/API/UserMicrosoftTeamsAPI.js +1 -1
  327. package/build/dist/Server/API/UserMicrosoftTeamsAPI.js.map +1 -1
  328. package/build/dist/Server/API/UserSlackAPI.js +1 -1
  329. package/build/dist/Server/API/UserSlackAPI.js.map +1 -1
  330. package/build/dist/Server/API/UserSmsAPI.js +2 -2
  331. package/build/dist/Server/API/UserSmsAPI.js.map +1 -1
  332. package/build/dist/Server/API/UserTotpAuthAPI.js +1 -1
  333. package/build/dist/Server/API/UserTotpAuthAPI.js.map +1 -1
  334. package/build/dist/Server/API/UserWebAuthnAPI.js +2 -2
  335. package/build/dist/Server/API/UserWebAuthnAPI.js.map +1 -1
  336. package/build/dist/Server/API/UserWebhookAPI.js +1 -1
  337. package/build/dist/Server/API/UserWebhookAPI.js.map +1 -1
  338. package/build/dist/Server/API/UserWhatsAppAPI.js +2 -2
  339. package/build/dist/Server/API/UserWhatsAppAPI.js.map +1 -1
  340. package/build/dist/Server/Middleware/MasterAdminAuthorization.js +11 -2
  341. package/build/dist/Server/Middleware/MasterAdminAuthorization.js.map +1 -1
  342. package/build/dist/Server/Middleware/UserAuthorization.js +64 -4
  343. package/build/dist/Server/Middleware/UserAuthorization.js.map +1 -1
  344. package/build/dist/Server/Services/ApiKeyPermissionService.js +80 -4
  345. package/build/dist/Server/Services/ApiKeyPermissionService.js.map +1 -1
  346. package/build/dist/Server/Services/DatabaseService.js +171 -0
  347. package/build/dist/Server/Services/DatabaseService.js.map +1 -1
  348. package/build/dist/Server/Services/DetectionRuleService.js +4 -4
  349. package/build/dist/Server/Services/DetectionRuleService.js.map +1 -1
  350. package/build/dist/Server/Services/OnCallDutyPolicyChildService.js +170 -0
  351. package/build/dist/Server/Services/OnCallDutyPolicyChildService.js.map +1 -0
  352. package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleScheduleService.js +2 -2
  353. package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleScheduleService.js.map +1 -1
  354. package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleService.js +2 -2
  355. package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleService.js.map +1 -1
  356. package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleTeamService.js +2 -2
  357. package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleTeamService.js.map +1 -1
  358. package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleUserService.js +2 -2
  359. package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleUserService.js.map +1 -1
  360. package/build/dist/Server/Services/PayAsYouGoBillingService.js +20 -27
  361. package/build/dist/Server/Services/PayAsYouGoBillingService.js.map +1 -1
  362. package/build/dist/Server/Services/ProjectService.js +17 -0
  363. package/build/dist/Server/Services/ProjectService.js.map +1 -1
  364. package/build/dist/Server/Services/RumSessionPinService.js +180 -16
  365. package/build/dist/Server/Services/RumSessionPinService.js.map +1 -1
  366. package/build/dist/Server/Services/TeamPermissionService.js +89 -27
  367. package/build/dist/Server/Services/TeamPermissionService.js.map +1 -1
  368. package/build/dist/Server/Services/ThreatIntelFeedService.js +5 -4
  369. package/build/dist/Server/Services/ThreatIntelFeedService.js.map +1 -1
  370. package/build/dist/Server/Types/Database/Permissions/BasePermission.js +9 -6
  371. package/build/dist/Server/Types/Database/Permissions/BasePermission.js.map +1 -1
  372. package/build/dist/Server/Types/Database/Permissions/Index.js +60 -6
  373. package/build/dist/Server/Types/Database/Permissions/Index.js.map +1 -1
  374. package/build/dist/Server/Types/Database/Permissions/TablePermission.js +14 -13
  375. package/build/dist/Server/Types/Database/Permissions/TablePermission.js.map +1 -1
  376. package/build/dist/Server/Utils/AI/AIChatPrivacyFilter.js +7 -0
  377. package/build/dist/Server/Utils/AI/AIChatPrivacyFilter.js.map +1 -1
  378. package/build/dist/Server/Utils/AI/AIRunPrivacyFilter.js +7 -0
  379. package/build/dist/Server/Utils/AI/AIRunPrivacyFilter.js.map +1 -1
  380. package/build/dist/Server/Utils/MasterAdminPageAccess.js +39 -0
  381. package/build/dist/Server/Utils/MasterAdminPageAccess.js.map +1 -0
  382. package/build/dist/Server/Utils/Monitor/MonitorAlert.js +3 -1
  383. package/build/dist/Server/Utils/Monitor/MonitorAlert.js.map +1 -1
  384. package/build/dist/Server/Utils/Monitor/MonitorIncident.js +3 -1
  385. package/build/dist/Server/Utils/Monitor/MonitorIncident.js.map +1 -1
  386. package/build/dist/Server/Utils/Realtime.js +126 -37
  387. package/build/dist/Server/Utils/Realtime.js.map +1 -1
  388. package/build/dist/Server/Utils/SecurityEvent/DetectionRuleEvaluator.js +7 -25
  389. package/build/dist/Server/Utils/SecurityEvent/DetectionRuleEvaluator.js.map +1 -1
  390. package/build/dist/Server/Utils/SecurityEvent/GoogleSecOpsSeverityRepair.js +127 -0
  391. package/build/dist/Server/Utils/SecurityEvent/GoogleSecOpsSeverityRepair.js.map +1 -0
  392. package/build/dist/Server/Utils/SecurityEvent/Sigma/SigmaClickhouseCompiler.js +1 -1
  393. package/build/dist/Server/Utils/SecurityEvent/Sigma/SigmaClickhouseCompiler.js.map +1 -1
  394. package/build/dist/Server/Utils/SecurityEvent/ThreatIntel/ThreatIntelFeedPoller.js +3 -2
  395. package/build/dist/Server/Utils/SecurityEvent/ThreatIntel/ThreatIntelFeedPoller.js.map +1 -1
  396. package/build/dist/Server/Utils/SecurityEvent/ThreatIntel/ThreatIntelMatcher.js +4 -8
  397. package/build/dist/Server/Utils/SecurityEvent/ThreatIntel/ThreatIntelMatcher.js.map +1 -1
  398. package/build/dist/Types/BaseDatabase/DatabaseCommonInteractionPropsUtil.js +31 -1
  399. package/build/dist/Types/BaseDatabase/DatabaseCommonInteractionPropsUtil.js.map +1 -1
  400. package/build/dist/Types/OnCallDutyPolicy/ScheduleTimeline.js +321 -0
  401. package/build/dist/Types/OnCallDutyPolicy/ScheduleTimeline.js.map +1 -0
  402. package/build/dist/Types/OnCallDutyPolicy/ScheduleTimelineLayout.js +372 -0
  403. package/build/dist/Types/OnCallDutyPolicy/ScheduleTimelineLayout.js.map +1 -0
  404. package/build/dist/Types/Realtime/EventName.js +10 -0
  405. package/build/dist/Types/Realtime/EventName.js.map +1 -1
  406. package/build/dist/Types/SecurityEvent/DetectionFindingConstants.js +11 -0
  407. package/build/dist/Types/SecurityEvent/DetectionFindingConstants.js.map +1 -1
  408. package/build/dist/Types/SecurityEvent/OcsfSeverity.js +30 -25
  409. package/build/dist/Types/SecurityEvent/OcsfSeverity.js.map +1 -1
  410. package/build/dist/Types/SecurityEvent/SigmaRule.js +47 -0
  411. package/build/dist/Types/SecurityEvent/SigmaRule.js.map +1 -1
  412. package/build/dist/Types/SecurityEvent/ThreatIntelConstants.js +14 -0
  413. package/build/dist/Types/SecurityEvent/ThreatIntelConstants.js.map +1 -1
  414. package/build/dist/UI/Components/AttachmentList/EventAttachmentList.js +9 -4
  415. package/build/dist/UI/Components/AttachmentList/EventAttachmentList.js.map +1 -1
  416. package/build/dist/UI/Components/Dashboard/DashboardVariableControl.js +10 -2
  417. package/build/dist/UI/Components/Dashboard/DashboardVariableControl.js.map +1 -1
  418. package/build/dist/UI/Components/Dropdown/Dropdown.js +5 -1
  419. package/build/dist/UI/Components/Dropdown/Dropdown.js.map +1 -1
  420. package/build/dist/UI/Components/EditionLabel/EditionLabel.js +11 -0
  421. package/build/dist/UI/Components/EditionLabel/EditionLabel.js.map +1 -1
  422. package/build/dist/UI/Components/EventItem/EventItem.js +2 -2
  423. package/build/dist/UI/Components/EventItem/EventItem.js.map +1 -1
  424. package/build/dist/UI/Components/Forms/BasicForm.js +70 -64
  425. package/build/dist/UI/Components/Forms/BasicForm.js.map +1 -1
  426. package/build/dist/UI/Components/Forms/CollapsibleFormSection.js +27 -0
  427. package/build/dist/UI/Components/Forms/CollapsibleFormSection.js.map +1 -0
  428. package/build/dist/UI/Components/Forms/Fields/FormField.js +10 -7
  429. package/build/dist/UI/Components/Forms/Fields/FormField.js.map +1 -1
  430. package/build/dist/UI/Components/Forms/FormSummary.js +7 -0
  431. package/build/dist/UI/Components/Forms/FormSummary.js.map +1 -1
  432. package/build/dist/UI/Components/Markdown.tsx/MarkdownViewer.js +2 -1
  433. package/build/dist/UI/Components/Markdown.tsx/MarkdownViewer.js.map +1 -1
  434. package/build/dist/UI/Components/Markdown.tsx/SessionAwareImage.js +84 -0
  435. package/build/dist/UI/Components/Markdown.tsx/SessionAwareImage.js.map +1 -0
  436. package/build/dist/UI/Components/ModelTable/BaseModelTable.js +14 -1
  437. package/build/dist/UI/Components/ModelTable/BaseModelTable.js.map +1 -1
  438. package/build/dist/UI/Components/ModelTable/TableView.js +1 -1
  439. package/build/dist/UI/Components/ModelTable/TableView.js.map +1 -1
  440. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryHistogram.js +8 -1
  441. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryHistogram.js.map +1 -1
  442. package/build/dist/UI/Components/Tooltip/Tooltip.js +2 -1
  443. package/build/dist/UI/Components/Tooltip/Tooltip.js.map +1 -1
  444. package/build/dist/UI/Utils/API/API.js +143 -19
  445. package/build/dist/UI/Utils/API/API.js.map +1 -1
  446. package/build/dist/UI/Utils/AnalyticsModelAPI/AnalyticsModelAPI.js +21 -7
  447. package/build/dist/UI/Utils/AnalyticsModelAPI/AnalyticsModelAPI.js.map +1 -1
  448. package/build/dist/UI/Utils/ModelAPI/ModelAPI.js +26 -9
  449. package/build/dist/UI/Utils/ModelAPI/ModelAPI.js.map +1 -1
  450. package/build/dist/UI/Utils/Navigation.js +8 -0
  451. package/build/dist/UI/Utils/Navigation.js.map +1 -1
  452. package/build/dist/UI/Utils/OpenAuthenticatedUrl.js +92 -0
  453. package/build/dist/UI/Utils/OpenAuthenticatedUrl.js.map +1 -0
  454. package/build/dist/UI/Utils/Realtime.js +120 -15
  455. package/build/dist/UI/Utils/Realtime.js.map +1 -1
  456. package/build/dist/Utils/API.js +13 -5
  457. package/build/dist/Utils/API.js.map +1 -1
  458. package/build/dist/Utils/SecurityEvent/GoogleSecOpsAlertNormalizer.js +123 -6
  459. package/build/dist/Utils/SecurityEvent/GoogleSecOpsAlertNormalizer.js.map +1 -1
  460. package/build/dist/Utils/SecurityEvent/Sigma/SigmaRuleParser.js +4 -18
  461. package/build/dist/Utils/SecurityEvent/Sigma/SigmaRuleParser.js.map +1 -1
  462. package/build/dist/Utils/Slo/SloBurnRateTemplate.js +2 -2
  463. package/package.json +1 -1
@@ -0,0 +1,623 @@
1
+ // Must stay the first import: the client's URLs are built from HOST on load.
2
+ import { DASHBOARD_ORIGIN } from "../../UI/Utils/API/DashboardHost";
3
+ import FakeAxiosServer, {
4
+ FakeTransport,
5
+ SentRequest,
6
+ settle,
7
+ } from "../../UI/Utils/API/FakeAxiosServer";
8
+ import React from "react";
9
+ import { cleanup, render, screen, waitFor } from "@testing-library/react";
10
+ import { afterEach, beforeEach, describe, expect, test } from "@jest/globals";
11
+ import axios from "axios";
12
+ import PublicDashboardAPI from "../../../../App/FeatureSet/PublicDashboard/src/Utils/API";
13
+ import { PUBLIC_DASHBOARD_API_URL } from "../../../../App/FeatureSet/PublicDashboard/src/Utils/Config";
14
+ import PublicDashboardUtil from "../../../../App/FeatureSet/PublicDashboard/src/Utils/PublicDashboard";
15
+ import PublicDashboardWidgetContext from "../../../../App/FeatureSet/PublicDashboard/src/Utils/WidgetContext";
16
+ import { DashboardBaseComponentProps } from "../../../../App/FeatureSet/Dashboard/src/Components/Dashboard/Components/DashboardBaseComponent";
17
+ import DashboardIncidentListComponentElement from "../../../../App/FeatureSet/Dashboard/src/Components/Dashboard/Components/DashboardIncidentListComponent";
18
+ import DashboardLogStreamComponentElement from "../../../../App/FeatureSet/Dashboard/src/Components/Dashboard/Components/DashboardLogStreamComponent";
19
+ import DashboardResourceList from "../../../../App/FeatureSet/Dashboard/src/Components/Dashboard/Utils/DashboardResourceList";
20
+ import {
21
+ getPublicDashboardContext,
22
+ PublicDashboardContext,
23
+ setPublicDashboardContext,
24
+ } from "../../../../App/FeatureSet/Dashboard/src/Components/Dashboard/Utils/PublicDashboardContext";
25
+ import SloWidgetData from "../../../../App/FeatureSet/Dashboard/src/Components/Dashboard/Utils/SloWidgetData";
26
+ import Log from "../../../Models/AnalyticsModels/Log";
27
+ import Incident from "../../../Models/DatabaseModels/Incident";
28
+ import HTTPErrorResponse from "../../../Types/API/HTTPErrorResponse";
29
+ import HTTPMethod from "../../../Types/API/HTTPMethod";
30
+ import HTTPResponse from "../../../Types/API/HTTPResponse";
31
+ import Route from "../../../Types/API/Route";
32
+ import URL from "../../../Types/API/URL";
33
+ import InBetween from "../../../Types/BaseDatabase/InBetween";
34
+ import DashboardComponentType from "../../../Types/Dashboard/DashboardComponentType";
35
+ import DashboardIncidentListComponent from "../../../Types/Dashboard/DashboardComponents/DashboardIncidentListComponent";
36
+ import DashboardLogStreamComponent from "../../../Types/Dashboard/DashboardComponents/DashboardLogStreamComponent";
37
+ import { JSONObject, ObjectType } from "../../../Types/JSON";
38
+ import ObjectID from "../../../Types/ObjectID";
39
+ import TimeRange from "../../../Types/Time/TimeRange";
40
+ import { SLO_WIDGET_NAME_MATCH_LIMIT } from "../../../Utils/Dashboard/SloWidgetSource";
41
+ import { IDENTITY_URL } from "../../../UI/Config";
42
+ import AnalyticsModelAPI from "../../../UI/Utils/AnalyticsModelAPI/AnalyticsModelAPI";
43
+ import ModelAPI from "../../../UI/Utils/ModelAPI/ModelAPI";
44
+ import Navigation from "../../../UI/Utils/Navigation";
45
+ import {
46
+ CURRENT_PROJECT_ID_STORAGE_KEY,
47
+ LAST_ACCESSED_PROJECT_ID_STORAGE_KEY,
48
+ } from "../../../UI/Utils/Project";
49
+ import User from "../../../UI/Utils/User";
50
+
51
+ jest.mock("axios", () => {
52
+ // Keep the real helpers (axios.isAxiosError, AxiosError) and fake only the call.
53
+ return Object.assign(jest.fn(), jest.requireActual("axios"));
54
+ });
55
+
56
+ /*
57
+ * A PUBLIC DASHBOARD WIDGET'S 401 BELONGS TO THE PUBLIC DASHBOARD.
58
+ *
59
+ * The incident/alert/monitor/host/log/... list widgets are shared with the
60
+ * authenticated dashboard and read through ModelAPI / AnalyticsModelAPI. On a
61
+ * public dashboard they are pointed at /public-dashboard-api/resource-list,
62
+ * which answers 401 when the owner unpublishes the dashboard or the
63
+ * master-password cookie lapses. Sent through the DASHBOARD client, that 401:
64
+ * - POSTed /identity/refresh-token (a failed refresh clears every cookie on
65
+ * the host, the master-password cookie included),
66
+ * - ran the dashboard's User.logout() - which, for a viewer also signed in to
67
+ * the dashboard on the same host, ended their real session once the
68
+ * successful refresh replayed into the same 401 - and
69
+ * - force-navigated to /accounts/login, not a page on a public-dashboard
70
+ * custom domain.
71
+ *
72
+ * These tests register the context the public dashboard page registers
73
+ * (PublicDashboardWidgetContext.build) and run the real widgets, the real
74
+ * ModelAPI / AnalyticsModelAPI and the real BaseAPI / Common API client. A
75
+ * scripted server stands in for axios and answers nothing but the requests
76
+ * each test expects, so a refresh or a replay fails the test. They prove the
77
+ * request goes through the public dashboard's own client: one request, no
78
+ * refresh, no dashboard logout, and the public dashboard's master-password
79
+ * page.
80
+ */
81
+
82
+ const mockedAxios: FakeTransport = axios as unknown as FakeTransport;
83
+
84
+ const DASHBOARD_ID: string = "44444444-4444-4444-8444-444444444444";
85
+
86
+ const COMPONENT_ID: ObjectID = new ObjectID(
87
+ "11111111-1111-4111-8111-111111111111",
88
+ );
89
+
90
+ // The viewer's own dashboard project, remembered by this browser.
91
+ const VIEWER_PROJECT_ID: string = "55555555-5555-4555-8555-555555555555";
92
+
93
+ const PUBLIC_API_URL: string = PUBLIC_DASHBOARD_API_URL.toString();
94
+
95
+ const RESOURCE_LIST_URL: string = `${PUBLIC_API_URL}/resource-list/${DASHBOARD_ID}`;
96
+
97
+ const REFRESH_URL: string = URL.fromString(IDENTITY_URL.toString())
98
+ .addRoute("/refresh-token")
99
+ .toString();
100
+
101
+ const MASTER_PASSWORD_ROUTE: Route = new Route("/master-password");
102
+
103
+ const NOT_AUTHENTICATED_BODY: JSONObject = {
104
+ message: "Master password required",
105
+ };
106
+
107
+ const EMPTY_LIST_BODY: JSONObject = {
108
+ data: [],
109
+ count: 0,
110
+ skip: 0,
111
+ limit: 10,
112
+ };
113
+
114
+ let server: FakeAxiosServer;
115
+
116
+ let navigateSpy: jest.SpiedFunction<typeof Navigation.navigate>;
117
+
118
+ let dashboardLogoutSpy: jest.SpiedFunction<typeof User.logout>;
119
+
120
+ type SentRequestsFunction = () => Array<string>;
121
+
122
+ const sentRequests: SentRequestsFunction = (): Array<string> => {
123
+ return server.sent.map((request: SentRequest): string => {
124
+ return `${request.method.toUpperCase()} ${request.url}`;
125
+ });
126
+ };
127
+
128
+ type ReadFunction = () => Promise<unknown>;
129
+
130
+ const readIncidentList: ReadFunction = async (): Promise<unknown> => {
131
+ return await ModelAPI.getList<Incident>({
132
+ modelType: Incident,
133
+ query: {},
134
+ limit: 10,
135
+ skip: 0,
136
+ select: { title: true },
137
+ sort: {},
138
+ requestOptions: DashboardResourceList.getRequestOptions("incident", {
139
+ componentId: COMPONENT_ID,
140
+ variables: [],
141
+ }),
142
+ });
143
+ };
144
+
145
+ const readLogList: ReadFunction = async (): Promise<unknown> => {
146
+ return await AnalyticsModelAPI.getList<Log>({
147
+ modelType: Log,
148
+ query: {},
149
+ limit: 10,
150
+ skip: 0,
151
+ select: { body: true },
152
+ sort: {},
153
+ requestOptions: DashboardResourceList.getRequestOptions("log", {
154
+ componentId: COMPONENT_ID,
155
+ variables: [],
156
+ }),
157
+ });
158
+ };
159
+
160
+ type WidgetPropsFunction = () => DashboardBaseComponentProps;
161
+
162
+ const baseWidgetProps: WidgetPropsFunction =
163
+ (): DashboardBaseComponentProps => {
164
+ return {
165
+ componentId: COMPONENT_ID,
166
+ isEditMode: false,
167
+ isSelected: false,
168
+ key: "public-widget",
169
+ onComponentUpdate: (): void => {},
170
+ totalCurrentDashboardWidthInPx: 1200,
171
+ dashboardCanvasTopInPx: 0,
172
+ dashboardCanvasLeftInPx: 0,
173
+ dashboardCanvasWidthInPx: 1200,
174
+ dashboardCanvasHeightInPx: 800,
175
+ dashboardComponentHeightInPx: 450,
176
+ dashboardComponentWidthInPx: 1200,
177
+ dashboardViewConfig: {
178
+ _type: ObjectType.DashboardViewConfig,
179
+ components: [],
180
+ heightInDashboardUnits: 60,
181
+ },
182
+ dashboardStartAndEndDate: {
183
+ range: TimeRange.CUSTOM,
184
+ startAndEndDate: new InBetween<Date>(
185
+ new Date("2026-08-10T00:00:00.000Z"),
186
+ new Date("2026-08-10T06:00:00.000Z"),
187
+ ),
188
+ },
189
+ metricTypes: [],
190
+ refreshTick: 0,
191
+ };
192
+ };
193
+
194
+ type ExpectPublicAuthRedirectFunction = (data: {
195
+ url: string;
196
+ route?: Route | undefined;
197
+ }) => void;
198
+
199
+ /*
200
+ * The whole contract, in one place: the widget's read was the only request
201
+ * (no refresh, no replay), the dashboard session was left alone, the public
202
+ * dashboard's own "logout" ran (it forgets the password was entered), and the
203
+ * viewer is sent to the public dashboard's master-password page - once.
204
+ */
205
+ const expectPublicAuthRedirect: ExpectPublicAuthRedirectFunction = (data: {
206
+ url: string;
207
+ route?: Route | undefined;
208
+ }): void => {
209
+ expect(sentRequests()).toEqual([`POST ${data.url}`]);
210
+ expect(server.requestsTo(HTTPMethod.POST, REFRESH_URL)).toEqual([]);
211
+
212
+ expect(dashboardLogoutSpy).not.toHaveBeenCalled();
213
+ expect(PublicDashboardUtil.isMasterPasswordValidated()).toBe(false);
214
+
215
+ expect(navigateSpy).toHaveBeenCalledTimes(1);
216
+ expect(navigateSpy).toHaveBeenCalledWith(
217
+ data.route || MASTER_PASSWORD_ROUTE,
218
+ { forceNavigate: true },
219
+ );
220
+ };
221
+
222
+ beforeEach(() => {
223
+ window.localStorage.clear();
224
+ window.sessionStorage.clear();
225
+ window.history.replaceState(null, "", "/");
226
+
227
+ server = new FakeAxiosServer(mockedAxios);
228
+
229
+ PublicDashboardUtil.setDashboardId(new ObjectID(DASHBOARD_ID));
230
+ PublicDashboardUtil.setRequiresMasterPassword(true);
231
+ PublicDashboardUtil.setMasterPasswordValidated(true);
232
+
233
+ navigateSpy = jest
234
+ .spyOn(Navigation, "navigate")
235
+ .mockImplementation((): void => {});
236
+
237
+ // Also keeps the real logout from wiping storage or POSTing /logout.
238
+ dashboardLogoutSpy = jest
239
+ .spyOn(User, "logout")
240
+ .mockImplementation((): void => {});
241
+
242
+ // Navigation.getCurrentRoute needs a router; the viewer is on the dashboard.
243
+ jest.spyOn(Navigation, "getCurrentRoute").mockReturnValue(new Route("/"));
244
+ });
245
+
246
+ afterEach(async () => {
247
+ cleanup();
248
+ await settle();
249
+
250
+ setPublicDashboardContext(null);
251
+ mockedAxios.mockReset();
252
+ jest.restoreAllMocks();
253
+ window.localStorage.clear();
254
+ window.sessionStorage.clear();
255
+ });
256
+
257
+ describe("public dashboard widget lists: a 401 goes to the master-password page", () => {
258
+ beforeEach(() => {
259
+ setPublicDashboardContext(
260
+ PublicDashboardWidgetContext.build(new ObjectID(DASHBOARD_ID)),
261
+ );
262
+ });
263
+
264
+ test("the real incident list widget makes no refresh, keeps the dashboard session and opens the master-password page", async () => {
265
+ server.on(
266
+ HTTPMethod.POST,
267
+ `${RESOURCE_LIST_URL}/incident?limit=10&skip=0`,
268
+ [{ status: 401, data: NOT_AUTHENTICATED_BODY }],
269
+ );
270
+
271
+ const component: DashboardIncidentListComponent = {
272
+ _type: ObjectType.DashboardComponent,
273
+ componentId: COMPONENT_ID,
274
+ componentType: DashboardComponentType.IncidentList,
275
+ topInDashboardUnits: 0,
276
+ leftInDashboardUnits: 0,
277
+ widthInDashboardUnits: 12,
278
+ heightInDashboardUnits: 5,
279
+ minWidthInDashboardUnits: 6,
280
+ minHeightInDashboardUnits: 3,
281
+ arguments: { title: "Incidents", maxRows: 10 },
282
+ };
283
+
284
+ render(
285
+ <DashboardIncidentListComponentElement
286
+ {...baseWidgetProps()}
287
+ component={component}
288
+ />,
289
+ );
290
+
291
+ // The widget shows the error in place...
292
+ await screen.findByText(/Master password required/);
293
+
294
+ // ...and the page goes to the public dashboard's password prompt.
295
+ await waitFor(() => {
296
+ expect(navigateSpy).toHaveBeenCalled();
297
+ });
298
+
299
+ expectPublicAuthRedirect({
300
+ url: `${RESOURCE_LIST_URL}/incident?limit=10&skip=0`,
301
+ });
302
+ });
303
+
304
+ test("the real log stream widget (AnalyticsModelAPI) does the same", async () => {
305
+ server.on(HTTPMethod.POST, `${RESOURCE_LIST_URL}/log?limit=10&skip=0`, [
306
+ { status: 401, data: NOT_AUTHENTICATED_BODY },
307
+ ]);
308
+
309
+ const component: DashboardLogStreamComponent = {
310
+ _type: ObjectType.DashboardComponent,
311
+ componentId: COMPONENT_ID,
312
+ componentType: DashboardComponentType.LogStream,
313
+ topInDashboardUnits: 0,
314
+ leftInDashboardUnits: 0,
315
+ widthInDashboardUnits: 12,
316
+ heightInDashboardUnits: 5,
317
+ minWidthInDashboardUnits: 6,
318
+ minHeightInDashboardUnits: 3,
319
+ arguments: { title: "Logs", maxRows: 10 },
320
+ };
321
+
322
+ render(
323
+ <DashboardLogStreamComponentElement
324
+ {...baseWidgetProps()}
325
+ component={component}
326
+ />,
327
+ );
328
+
329
+ await screen.findByText(/Master password required/);
330
+
331
+ await waitFor(() => {
332
+ expect(navigateSpy).toHaveBeenCalled();
333
+ });
334
+
335
+ expectPublicAuthRedirect({
336
+ url: `${RESOURCE_LIST_URL}/log?limit=10&skip=0`,
337
+ });
338
+ });
339
+
340
+ test("a ModelAPI list read gets its 401 back", async () => {
341
+ server.on(
342
+ HTTPMethod.POST,
343
+ `${RESOURCE_LIST_URL}/incident?limit=10&skip=0`,
344
+ [{ status: 401, data: NOT_AUTHENTICATED_BODY }],
345
+ );
346
+
347
+ await expect(readIncidentList()).rejects.toMatchObject({
348
+ statusCode: 401,
349
+ });
350
+
351
+ expectPublicAuthRedirect({
352
+ url: `${RESOURCE_LIST_URL}/incident?limit=10&skip=0`,
353
+ });
354
+ });
355
+
356
+ test("an AnalyticsModelAPI list read gets its 401 back", async () => {
357
+ server.on(HTTPMethod.POST, `${RESOURCE_LIST_URL}/log?limit=10&skip=0`, [
358
+ { status: 401, data: NOT_AUTHENTICATED_BODY },
359
+ ]);
360
+
361
+ await expect(readLogList()).rejects.toMatchObject({ statusCode: 401 });
362
+
363
+ expectPublicAuthRedirect({
364
+ url: `${RESOURCE_LIST_URL}/log?limit=10&skip=0`,
365
+ });
366
+ });
367
+
368
+ test("the SLO widget's reads (pinned and by name) do the same", async () => {
369
+ server.on(HTTPMethod.POST, `${RESOURCE_LIST_URL}/slo?limit=1&skip=0`, [
370
+ { status: 401, data: NOT_AUTHENTICATED_BODY },
371
+ ]);
372
+
373
+ await expect(
374
+ SloWidgetData.fetchSlo({
375
+ serviceLevelObjectiveId: new ObjectID(
376
+ "22222222-2222-4222-8222-222222222222",
377
+ ),
378
+ componentId: COMPONENT_ID,
379
+ }),
380
+ ).rejects.toMatchObject({ statusCode: 401 });
381
+
382
+ expectPublicAuthRedirect({
383
+ url: `${RESOURCE_LIST_URL}/slo?limit=1&skip=0`,
384
+ });
385
+
386
+ server.sent.length = 0;
387
+ navigateSpy.mockClear();
388
+
389
+ const byNameUrl: string = `${RESOURCE_LIST_URL}/slo?limit=${SLO_WIDGET_NAME_MATCH_LIMIT}&skip=0`;
390
+
391
+ server.on(HTTPMethod.POST, byNameUrl, [
392
+ { status: 401, data: NOT_AUTHENTICATED_BODY },
393
+ ]);
394
+
395
+ await expect(
396
+ SloWidgetData.fetchSlosByName({
397
+ sloName: "Checkout availability",
398
+ componentId: COMPONENT_ID,
399
+ variables: [],
400
+ }),
401
+ ).rejects.toMatchObject({ statusCode: 401 });
402
+
403
+ expectPublicAuthRedirect({ url: byNameUrl });
404
+ });
405
+
406
+ /*
407
+ * Before the fix, a viewer who was ALSO signed in to the dashboard on the
408
+ * same host had the refresh succeed, the replay 401 again, and
409
+ * User.logout() end their real dashboard session.
410
+ */
411
+ test("a viewer also signed in to the dashboard keeps their dashboard session", async () => {
412
+ server
413
+ .on(HTTPMethod.POST, `${RESOURCE_LIST_URL}/incident?limit=10&skip=0`, [
414
+ { status: 401, data: NOT_AUTHENTICATED_BODY },
415
+ ])
416
+ .on(HTTPMethod.POST, REFRESH_URL, [{ status: 200 }]);
417
+
418
+ await expect(readIncidentList()).rejects.toMatchObject({
419
+ statusCode: 401,
420
+ });
421
+
422
+ expectPublicAuthRedirect({
423
+ url: `${RESOURCE_LIST_URL}/incident?limit=10&skip=0`,
424
+ });
425
+ });
426
+
427
+ test("the preview of a protected dashboard goes to the preview's master-password page", async () => {
428
+ window.history.replaceState(
429
+ null,
430
+ "",
431
+ `/public-dashboard/${DASHBOARD_ID}/view`,
432
+ );
433
+
434
+ server.on(
435
+ HTTPMethod.POST,
436
+ `${RESOURCE_LIST_URL}/incident?limit=10&skip=0`,
437
+ [{ status: 401, data: NOT_AUTHENTICATED_BODY }],
438
+ );
439
+
440
+ await expect(readIncidentList()).rejects.toMatchObject({
441
+ statusCode: 401,
442
+ });
443
+
444
+ expectPublicAuthRedirect({
445
+ url: `${RESOURCE_LIST_URL}/incident?limit=10&skip=0`,
446
+ route: new Route(`/public-dashboard/${DASHBOARD_ID}/master-password`),
447
+ });
448
+ });
449
+
450
+ // The metric and SLO-history reads were already on the public client.
451
+ test("the page's postJSON reads never refresh either", async () => {
452
+ const url: string = `${PUBLIC_API_URL}/metrics-aggregate/${DASHBOARD_ID}`;
453
+
454
+ server.on(HTTPMethod.POST, url, [
455
+ { status: 401, data: NOT_AUTHENTICATED_BODY },
456
+ ]);
457
+
458
+ const context: PublicDashboardContext | null = getPublicDashboardContext();
459
+
460
+ if (!context) {
461
+ throw new Error("The public dashboard context should be set.");
462
+ }
463
+
464
+ const result: HTTPResponse<JSONObject> | HTTPErrorResponse =
465
+ await context.postJSON(`/metrics-aggregate/${DASHBOARD_ID}`, {});
466
+
467
+ expect(result).toBeInstanceOf(HTTPErrorResponse);
468
+ expect(result.statusCode).toBe(401);
469
+
470
+ expectPublicAuthRedirect({ url });
471
+ });
472
+
473
+ /*
474
+ * The public client sends its own, empty, tenant. The viewer's remembered
475
+ * dashboard project must not override it: a stale or foreign one turned a
476
+ * public widget read into a 405 (tenant not found) that the page treats as
477
+ * a login event, while the dashboard's own reads - sent without it - kept
478
+ * succeeding.
479
+ */
480
+ test("list reads carry the public dashboard's headers, not the viewer's dashboard project", async () => {
481
+ window.localStorage.setItem(
482
+ LAST_ACCESSED_PROJECT_ID_STORAGE_KEY,
483
+ JSON.stringify(VIEWER_PROJECT_ID),
484
+ );
485
+ window.sessionStorage.setItem(
486
+ CURRENT_PROJECT_ID_STORAGE_KEY,
487
+ JSON.stringify(VIEWER_PROJECT_ID),
488
+ );
489
+
490
+ server
491
+ .on(HTTPMethod.POST, `${RESOURCE_LIST_URL}/incident?limit=10&skip=0`, [
492
+ { status: 200, data: EMPTY_LIST_BODY },
493
+ ])
494
+ .on(HTTPMethod.POST, `${RESOURCE_LIST_URL}/log?limit=10&skip=0`, [
495
+ { status: 200, data: EMPTY_LIST_BODY },
496
+ ]);
497
+
498
+ await readIncidentList();
499
+ await readLogList();
500
+
501
+ expect(server.sent).toHaveLength(2);
502
+
503
+ for (const request of server.sent) {
504
+ expect(request.headers["dashboard-id"]).toBe(DASHBOARD_ID);
505
+ expect(request.headers["tenantid"]).toBe("");
506
+ }
507
+
508
+ expect(navigateSpy).not.toHaveBeenCalled();
509
+ });
510
+
511
+ test("the page's context routes list reads through the public dashboard's client", () => {
512
+ const context: PublicDashboardContext = PublicDashboardWidgetContext.build(
513
+ new ObjectID(DASHBOARD_ID),
514
+ );
515
+
516
+ expect(context.apiClient).toBe(PublicDashboardAPI);
517
+ expect(context.apiUrl.toString()).toBe(PUBLIC_API_URL);
518
+
519
+ expect(DashboardResourceList.getRequestOptions("incident")?.apiClient).toBe(
520
+ PublicDashboardAPI,
521
+ );
522
+ expect(
523
+ DashboardResourceList.getRequestOptions("log", {
524
+ componentId: COMPONENT_ID,
525
+ variables: [],
526
+ })?.apiClient,
527
+ ).toBe(PublicDashboardAPI);
528
+ });
529
+ });
530
+
531
+ /*
532
+ * The fix must not reach the authenticated dashboard: without a public
533
+ * context its reads still go through the dashboard client, which still
534
+ * refreshes an expired session, still logs out when that fails, and still
535
+ * scopes the read to the viewer's project.
536
+ */
537
+ describe("authenticated dashboard widget lists keep the dashboard client", () => {
538
+ const DASHBOARD_API_URL: string = `${DASHBOARD_ORIGIN}/api`;
539
+
540
+ const INCIDENT_LIST_URL: string = `${DASHBOARD_API_URL}/incident/get-list?limit=10&skip=0`;
541
+
542
+ const LOG_LIST_URL: string = `${DASHBOARD_API_URL}/logs/get-list?limit=10&skip=0`;
543
+
544
+ const readDashboardIncidentList: ReadFunction =
545
+ async (): Promise<unknown> => {
546
+ return await ModelAPI.getList<Incident>({
547
+ modelType: Incident,
548
+ query: {},
549
+ limit: 10,
550
+ skip: 0,
551
+ select: { title: true },
552
+ sort: {},
553
+ requestOptions: DashboardResourceList.getRequestOptions("incident"),
554
+ });
555
+ };
556
+
557
+ beforeEach(() => {
558
+ window.sessionStorage.setItem(
559
+ CURRENT_PROJECT_ID_STORAGE_KEY,
560
+ JSON.stringify(VIEWER_PROJECT_ID),
561
+ );
562
+ });
563
+
564
+ test("a 401 refreshes the session and replays the read, scoped to the viewer's project", async () => {
565
+ server
566
+ .on(HTTPMethod.POST, INCIDENT_LIST_URL, [
567
+ { status: 401, data: { message: "Session expired" } },
568
+ { status: 200, data: EMPTY_LIST_BODY },
569
+ ])
570
+ .on(HTTPMethod.POST, REFRESH_URL, [{ status: 200 }]);
571
+
572
+ await expect(readDashboardIncidentList()).resolves.toMatchObject({
573
+ data: [],
574
+ });
575
+
576
+ expect(sentRequests()).toEqual([
577
+ `POST ${INCIDENT_LIST_URL}`,
578
+ `POST ${REFRESH_URL}`,
579
+ `POST ${INCIDENT_LIST_URL}`,
580
+ ]);
581
+ expect(server.sent[0]!.headers["tenantid"]).toBe(VIEWER_PROJECT_ID);
582
+ expect(dashboardLogoutSpy).not.toHaveBeenCalled();
583
+ expect(navigateSpy).not.toHaveBeenCalled();
584
+ });
585
+
586
+ test("a refused refresh still logs the dashboard user out, for model and analytics reads", async () => {
587
+ server
588
+ .on(HTTPMethod.POST, INCIDENT_LIST_URL, [
589
+ { status: 401, data: { message: "Session expired" } },
590
+ ])
591
+ .on(HTTPMethod.POST, LOG_LIST_URL, [
592
+ { status: 401, data: { message: "Session expired" } },
593
+ ])
594
+ .on(HTTPMethod.POST, REFRESH_URL, [{ status: 401 }, { status: 401 }]);
595
+
596
+ await expect(readDashboardIncidentList()).rejects.toMatchObject({
597
+ statusCode: 401,
598
+ });
599
+
600
+ expect(server.requestsTo(HTTPMethod.POST, REFRESH_URL)).toHaveLength(1);
601
+ expect(dashboardLogoutSpy).toHaveBeenCalled();
602
+ expect(navigateSpy).toHaveBeenCalledWith(new Route("/accounts/login"), {
603
+ forceNavigate: true,
604
+ });
605
+
606
+ dashboardLogoutSpy.mockClear();
607
+
608
+ await expect(
609
+ AnalyticsModelAPI.getList<Log>({
610
+ modelType: Log,
611
+ query: {},
612
+ limit: 10,
613
+ skip: 0,
614
+ select: { body: true },
615
+ sort: {},
616
+ requestOptions: DashboardResourceList.getRequestOptions("log"),
617
+ }),
618
+ ).rejects.toMatchObject({ statusCode: 401 });
619
+
620
+ expect(server.requestsTo(HTTPMethod.POST, REFRESH_URL)).toHaveLength(2);
621
+ expect(dashboardLogoutSpy).toHaveBeenCalled();
622
+ });
623
+ });
@@ -142,10 +142,10 @@ const SECRET_COLUMNS: Array<string> = [
142
142
  "tokenHash",
143
143
  "token",
144
144
  "previousTokenHash",
145
- "previousTokenExpiresAt",
146
145
  ];
147
146
 
148
147
  const BOOKKEEPING_COLUMNS: Array<string> = [
148
+ "previousTokenExpiresAt",
149
149
  "tokenHint",
150
150
  "rotatedAt",
151
151
  "lastFetchedAt",
@@ -443,6 +443,28 @@ describe("On-call calendar feed token columns", () => {
443
443
  });
444
444
 
445
445
  describe("On-call calendar feed settings and bookkeeping", () => {
446
+ test.each(feedSpecs())(
447
+ "%s exposes the old link expiry as read-only status metadata",
448
+ (_name: string, spec: FeedSpec) => {
449
+ const model: BaseModel = new spec.modelType();
450
+ const metadata: TableColumnMetadata = model.getTableColumnMetadata(
451
+ "previousTokenExpiresAt",
452
+ );
453
+
454
+ expect(model.getColumnAccessControlFor("previousTokenExpiresAt")).toEqual(
455
+ {
456
+ create: [],
457
+ read: model.readRecordPermissions,
458
+ update: [],
459
+ },
460
+ );
461
+ expect(model.readRecordPermissions.length).toBeGreaterThan(0);
462
+ expect(metadata.computed).toBe(true);
463
+ expect(metadata.canReadOnRelationQuery).toBe(false);
464
+ expect(metadata.hideColumnInDocumentation).toBe(true);
465
+ },
466
+ );
467
+
446
468
  test.each(feedSpecs())(
447
469
  "%s lets its readers read and its editors update exactly the settings columns",
448
470
  (_name: string, spec: FeedSpec) => {