@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
@@ -271,6 +271,8 @@ import OnCallCalendarFeedRateLimit, {
271
271
  import OnCallDutyPolicyScheduleCalendarFeedService from "../../../Server/Services/OnCallDutyPolicyScheduleCalendarFeedService";
272
272
  import ProjectOnCallCalendarFeedService from "../../../Server/Services/ProjectOnCallCalendarFeedService";
273
273
  import UserOnCallCalendarFeedService from "../../../Server/Services/UserOnCallCalendarFeedService";
274
+ import SelectPermission from "../../../Server/Types/Database/Permissions/SelectPermission";
275
+ import Select from "../../../Server/Types/Database/Select";
274
276
  import {
275
277
  ExpressRequest,
276
278
  ExpressResponse,
@@ -294,6 +296,9 @@ import OnCallCalendarFeedUrls, {
294
296
  PROTOCOL_WARNING,
295
297
  } from "../../../Server/Utils/OnCall/OnCallCalendarFeedUrls";
296
298
  import Response from "../../../Server/Utils/Response";
299
+ import BaseModel from "../../../Models/DatabaseModels/DatabaseBaseModel/DatabaseBaseModel";
300
+ import OnCallDutyPolicyScheduleCalendarFeed from "../../../Models/DatabaseModels/OnCallDutyPolicyScheduleCalendarFeed";
301
+ import ProjectOnCallCalendarFeed from "../../../Models/DatabaseModels/ProjectOnCallCalendarFeed";
297
302
  import Protocol from "../../../Types/API/Protocol";
298
303
  import DatabaseCommonInteractionProps from "../../../Types/BaseDatabase/DatabaseCommonInteractionProps";
299
304
  import OneUptimeDate from "../../../Types/Date";
@@ -318,6 +323,7 @@ import Permission, {
318
323
  UserPermission,
319
324
  UserTenantAccessPermission,
320
325
  } from "../../../Types/Permission";
326
+ import UserType from "../../../Types/UserType";
321
327
  import {
322
328
  DASHBOARD_URL,
323
329
  at,
@@ -366,9 +372,7 @@ interface HttpResult {
366
372
  interface CapturedFindOneBy {
367
373
  query: Record<string, unknown>;
368
374
  select?: Record<string, unknown> | undefined;
369
- props?:
370
- | { isRoot?: boolean | undefined; ignoreHooks?: boolean | undefined }
371
- | undefined;
375
+ props?: DatabaseCommonInteractionProps | undefined;
372
376
  }
373
377
 
374
378
  interface CapturedUpdate {
@@ -458,11 +462,13 @@ function routeFor(method: string, uri: string): RegisteredRoute {
458
462
  function buildMemberProps(data: {
459
463
  projectId: ObjectID | undefined;
460
464
  userId: ObjectID | undefined;
465
+ permission?: Permission | undefined;
461
466
  }): DatabaseCommonInteractionProps {
462
467
  const memberPermission: UserPermission = {
463
468
  _type: "UserPermission",
464
- permission: Permission.ProjectMember,
469
+ permission: data.permission ?? Permission.ProjectMember,
465
470
  labelIds: [],
471
+ isBlockPermission: false,
466
472
  };
467
473
 
468
474
  const permissionMap: Dictionary<UserTenantAccessPermission> = {};
@@ -3386,7 +3392,13 @@ describe("GET /on-call-calendar/feed/current", () => {
3386
3392
  expect(personalFindOneBy).not.toHaveBeenCalled();
3387
3393
  });
3388
3394
 
3389
- test("an anonymous caller (no user) is refused", async () => {
3395
+ /*
3396
+ * Tightened from "any 4xx" to the exact 401. A caller with no user and no
3397
+ * key is, in practice, a dashboard tab whose access-token cookie expired;
3398
+ * the browser client refreshes the session and replays only on a 401, so
3399
+ * any other status leaves the user looking at an error on their own feed.
3400
+ */
3401
+ test("an anonymous caller (no user) is refused with 401", async () => {
3390
3402
  propsSpy.mockResolvedValue(
3391
3403
  buildMemberProps({ projectId, userId: undefined }),
3392
3404
  );
@@ -3395,7 +3407,43 @@ describe("GET /on-call-calendar/feed/current", () => {
3395
3407
  `${API_PREFIX}${FEED_CURRENT_ROUTE}`,
3396
3408
  );
3397
3409
 
3398
- expect(result.status).toBeGreaterThanOrEqual(400);
3410
+ expect(result.status).toBe(ExceptionCode.NotAuthenticatedException);
3411
+ expect(result.status).toBe(401);
3412
+ expect(json(result)["message"]).toBe(
3413
+ CommonAPI.AUTHENTICATION_REQUIRED_MESSAGE,
3414
+ );
3415
+ expect(personalFindOneBy).not.toHaveBeenCalled();
3416
+ });
3417
+
3418
+ test("an anonymous caller with no tenant header is the 401, not the missing-tenant 400", async () => {
3419
+ propsSpy.mockResolvedValue(
3420
+ buildMemberProps({ projectId: undefined, userId: undefined }),
3421
+ );
3422
+
3423
+ const result: HttpResult = await request(
3424
+ `${API_PREFIX}${FEED_CURRENT_ROUTE}`,
3425
+ );
3426
+
3427
+ expect(result.status).toBe(ExceptionCode.NotAuthenticatedException);
3428
+ expect(personalFindOneBy).not.toHaveBeenCalled();
3429
+ });
3430
+
3431
+ test("a project API key is authenticated but is nobody, so it gets 422 rather than a 401", async () => {
3432
+ /*
3433
+ * A personal feed belongs to a person. The key fails the member guard
3434
+ * (no userId) before requireUserId is reached, and the answer is the 422 -
3435
+ * a 401 would send an API client off to refresh a session it never had.
3436
+ */
3437
+ propsSpy.mockResolvedValue({
3438
+ ...buildMemberProps({ projectId, userId: undefined }),
3439
+ userType: UserType.API,
3440
+ });
3441
+
3442
+ const result: HttpResult = await request(
3443
+ `${API_PREFIX}${FEED_CURRENT_ROUTE}`,
3444
+ );
3445
+
3446
+ expect(result.status).toBe(ExceptionCode.NotAuthorizedException);
3399
3447
  expect(personalFindOneBy).not.toHaveBeenCalled();
3400
3448
  });
3401
3449
  });
@@ -3427,6 +3475,41 @@ describe("POST /on-call-calendar/feed/rotate", () => {
3427
3475
  expect(result.status).toBe(415);
3428
3476
  });
3429
3477
 
3478
+ test("an anonymous JSON POST is 401 and mints nothing", async () => {
3479
+ /*
3480
+ * The rotate button on a page left open past the access-token lifetime.
3481
+ * The 401 is what makes the dashboard refresh and replay the POST; the
3482
+ * guard runs before the lock, so nothing is minted for the refused call.
3483
+ */
3484
+ propsSpy.mockResolvedValue(
3485
+ buildMemberProps({ projectId, userId: undefined }),
3486
+ );
3487
+
3488
+ const result: HttpResult = await postJson(
3489
+ `${API_PREFIX}${FEED_ROTATE_ROUTE}`,
3490
+ );
3491
+
3492
+ expect(result.status).toBe(ExceptionCode.NotAuthenticatedException);
3493
+ expect(personalCreateForUser).not.toHaveBeenCalled();
3494
+ expect(personalRotate).not.toHaveBeenCalled();
3495
+ expect(semaphoreLock).not.toHaveBeenCalled();
3496
+ });
3497
+
3498
+ test("a project API key POST is 422 and mints nothing", async () => {
3499
+ propsSpy.mockResolvedValue({
3500
+ ...buildMemberProps({ projectId, userId: undefined }),
3501
+ userType: UserType.API,
3502
+ });
3503
+
3504
+ const result: HttpResult = await postJson(
3505
+ `${API_PREFIX}${FEED_ROTATE_ROUTE}`,
3506
+ );
3507
+
3508
+ expect(result.status).toBe(ExceptionCode.NotAuthorizedException);
3509
+ expect(personalCreateForUser).not.toHaveBeenCalled();
3510
+ expect(personalRotate).not.toHaveBeenCalled();
3511
+ });
3512
+
3430
3513
  test("first time: mints the row as root under the (project, user) lock, purges, and returns the plaintext once", async () => {
3431
3514
  const token: string = CalendarFeedToken.mint();
3432
3515
  let created: FeedRowFixture | null = null;
@@ -4232,6 +4315,237 @@ describe("project-feed session routes", () => {
4232
4315
  });
4233
4316
  });
4234
4317
 
4318
+ /*
4319
+ * Regression: these routes selected previousTokenExpiresAt as a caller even
4320
+ * though the column denied every reader. Returning fixture rows from a
4321
+ * mocked service hid the failure, including on an unpublished feed. Keep the
4322
+ * HTTP routes real and enforce the model's actual column permissions on the
4323
+ * exact select each route sends before the in-memory lookup runs.
4324
+ */
4325
+ describe.each([
4326
+ OnCallCalendarFeedKind.Schedule,
4327
+ OnCallCalendarFeedKind.Project,
4328
+ ])(
4329
+ "%s status routes with real select permissions",
4330
+ (kind: OnCallCalendarFeedKind) => {
4331
+ let scheduleId: ObjectID;
4332
+ let rows: Array<FeedRowFixture>;
4333
+ let token: string;
4334
+ let find: jest.SpyInstance;
4335
+ let findToken: jest.SpyInstance;
4336
+ let create: jest.SpyInstance;
4337
+ let update: jest.SpyInstance;
4338
+ let rotate: jest.SpyInstance;
4339
+
4340
+ function route(action: "current" | "publish" | "rotate"): string {
4341
+ const routes: Record<typeof action, string> =
4342
+ kind === OnCallCalendarFeedKind.Schedule
4343
+ ? {
4344
+ current: SCHEDULE_FEED_CURRENT_ROUTE,
4345
+ publish: SCHEDULE_FEED_PUBLISH_ROUTE,
4346
+ rotate: SCHEDULE_FEED_ROTATE_ROUTE,
4347
+ }
4348
+ : {
4349
+ current: PROJECT_FEED_CURRENT_ROUTE,
4350
+ publish: PROJECT_FEED_PUBLISH_ROUTE,
4351
+ rotate: PROJECT_FEED_ROTATE_ROUTE,
4352
+ };
4353
+
4354
+ return `${API_PREFIX}${routes[action].replace(":scheduleId", scheduleId.toString())}`;
4355
+ }
4356
+
4357
+ function addFeed(previousTokenExpiresAt?: Date): FeedRowFixture {
4358
+ const makeRow: typeof scheduleRow =
4359
+ kind === OnCallCalendarFeedKind.Schedule ? scheduleRow : projectRow;
4360
+ const row: FeedRowFixture = makeRow({
4361
+ projectId,
4362
+ onCallDutyPolicyScheduleId: scheduleId,
4363
+ tokenHash: CalendarFeedToken.hash(token),
4364
+ previousTokenExpiresAt,
4365
+ });
4366
+
4367
+ rows.push(row);
4368
+ return row;
4369
+ }
4370
+
4371
+ beforeEach(() => {
4372
+ scheduleId = ObjectID.generate();
4373
+ rows = [];
4374
+ token = CalendarFeedToken.mint();
4375
+
4376
+ const isSchedule: boolean = kind === OnCallCalendarFeedKind.Schedule;
4377
+ const modelType:
4378
+ | typeof OnCallDutyPolicyScheduleCalendarFeed
4379
+ | typeof ProjectOnCallCalendarFeed = isSchedule
4380
+ ? OnCallDutyPolicyScheduleCalendarFeed
4381
+ : ProjectOnCallCalendarFeed;
4382
+
4383
+ find = isSchedule ? scheduleFindOneBy : projectFindOneBy;
4384
+ findToken = isSchedule ? scheduleFindOneById : projectFindOneById;
4385
+ create = isSchedule ? scheduleCreate : projectCreate;
4386
+ update = isSchedule ? scheduleUpdateOneBy : projectUpdateOneBy;
4387
+ rotate = isSchedule ? scheduleRotate : projectRotate;
4388
+
4389
+ find.mockImplementation(async (args: CapturedFindOneBy) => {
4390
+ expect(args.props?.isRoot).not.toBe(true);
4391
+ SelectPermission.checkSelectPermission(
4392
+ modelType,
4393
+ args.select as Select<BaseModel>,
4394
+ args.props || {},
4395
+ );
4396
+
4397
+ return await lookupFrom(rows)(args);
4398
+ });
4399
+ findToken.mockImplementation(async (args: { id: ObjectID }) => {
4400
+ const row: FeedRowFixture | undefined = rows.find(
4401
+ (candidate: FeedRowFixture) => {
4402
+ return candidate.id.toString() === args.id.toString();
4403
+ },
4404
+ );
4405
+
4406
+ return row ? { id: row.id, token, tokenHash: row.tokenHash } : null;
4407
+ });
4408
+ });
4409
+
4410
+ test("a viewer can read an unpublished feed without a column permission error", async () => {
4411
+ propsSpy.mockResolvedValue(
4412
+ buildMemberProps({ projectId, userId, permission: Permission.Viewer }),
4413
+ );
4414
+
4415
+ const result: HttpResult = await request(route("current"));
4416
+
4417
+ expect(result.status).toBe(200);
4418
+ expect(json(result)).toEqual(buildAbsentFeedStatus(kind));
4419
+ expect(findToken).not.toHaveBeenCalled();
4420
+ });
4421
+
4422
+ test.each([undefined, at("2026-10-01T12:00:00Z")])(
4423
+ "a viewer can read the link and expiration %p without exposing token hashes",
4424
+ async (expiresAt: Date | undefined) => {
4425
+ propsSpy.mockResolvedValue(
4426
+ buildMemberProps({
4427
+ projectId,
4428
+ userId,
4429
+ permission: Permission.Viewer,
4430
+ }),
4431
+ );
4432
+ const row: FeedRowFixture = addFeed(expiresAt);
4433
+ row.previousTokenHash = CalendarFeedToken.hash(
4434
+ CalendarFeedToken.mint(),
4435
+ );
4436
+
4437
+ const result: HttpResult = await request(route("current"));
4438
+ const status: Record<string, unknown> = json(result);
4439
+
4440
+ expect(result.status).toBe(200);
4441
+ expect(status["exists"]).toBe(true);
4442
+ expect(status["needsRegeneration"]).toBe(false);
4443
+ expect(status["previousTokenExpiresAt"]).toBe(
4444
+ expiresAt?.toISOString() ?? null,
4445
+ );
4446
+ expect((status["urls"] as Record<string, string>)["https"]).toContain(
4447
+ token,
4448
+ );
4449
+ expect(result.body).not.toContain(row.tokenHash);
4450
+ expect(result.body).not.toContain(row.previousTokenHash);
4451
+ expect(status).not.toHaveProperty("token");
4452
+ expect(status).not.toHaveProperty("tokenHash");
4453
+ expect(status).not.toHaveProperty("previousTokenHash");
4454
+
4455
+ const read: CapturedFindOneBy = find.mock
4456
+ .calls[0]?.[0] as CapturedFindOneBy;
4457
+ expect(read.select?.["previousTokenExpiresAt"]).toBe(true);
4458
+ for (const secret of ["token", "tokenHash", "previousTokenHash"]) {
4459
+ expect(read.select?.[secret]).toBeUndefined();
4460
+ }
4461
+ expect(findToken.mock.invocationCallOrder[0]).toBeGreaterThan(
4462
+ find.mock.invocationCallOrder[0] as number,
4463
+ );
4464
+ },
4465
+ );
4466
+
4467
+ test("first publish passes both caller status reads and returns a null expiration", async () => {
4468
+ create.mockImplementation(async () => {
4469
+ return addFeed();
4470
+ });
4471
+
4472
+ const result: HttpResult = await postJson(route("publish"));
4473
+
4474
+ expect(result.status).toBe(200);
4475
+ expect(create).toHaveBeenCalledTimes(1);
4476
+ expect(find).toHaveBeenCalledTimes(2);
4477
+ expect(json(result)["previousTokenExpiresAt"]).toBeNull();
4478
+ expect(
4479
+ (json(result)["urls"] as Record<string, string>)["https"],
4480
+ ).toContain(token);
4481
+ });
4482
+
4483
+ test("rotation passes both caller status reads and returns the previous link's expiration", async () => {
4484
+ const row: FeedRowFixture = addFeed();
4485
+ const expiresAt: Date = at("2026-10-01T12:00:00Z");
4486
+ const newToken: string = CalendarFeedToken.mint();
4487
+
4488
+ rotate.mockImplementation(async (): Promise<CalendarFeedRotation> => {
4489
+ row.previousTokenHash = row.tokenHash;
4490
+ row.previousTokenExpiresAt = expiresAt;
4491
+ row.tokenHash = CalendarFeedToken.hash(newToken);
4492
+ row.tokenHint = newToken.slice(-4);
4493
+ row.rotatedAt = NOW;
4494
+
4495
+ return {
4496
+ token: newToken,
4497
+ tokenHash: row.tokenHash,
4498
+ tokenHint: row.tokenHint,
4499
+ rotatedAt: NOW,
4500
+ previousTokenHash: row.previousTokenHash,
4501
+ previousTokenExpiresAt: expiresAt,
4502
+ };
4503
+ });
4504
+
4505
+ const result: HttpResult = await postJson(route("rotate"));
4506
+
4507
+ expect(result.status).toBe(200);
4508
+ expect(find).toHaveBeenCalledTimes(2);
4509
+ expect(update).toHaveBeenCalledTimes(1);
4510
+ expect(rotate).toHaveBeenCalledTimes(1);
4511
+ expect(json(result)["previousTokenExpiresAt"]).toBe(
4512
+ expiresAt.toISOString(),
4513
+ );
4514
+ expect(
4515
+ (json(result)["urls"] as Record<string, string>)["https"],
4516
+ ).toContain(newToken);
4517
+ expect(findToken).not.toHaveBeenCalled();
4518
+ expect(result.body).not.toContain(token);
4519
+ });
4520
+
4521
+ test.each(["current", "publish", "rotate"] as const)(
4522
+ "%s refuses a member without shared-feed read permissions before secrets or writes",
4523
+ async (action: "current" | "publish" | "rotate") => {
4524
+ addFeed();
4525
+ propsSpy.mockResolvedValue(
4526
+ buildMemberProps({
4527
+ projectId,
4528
+ userId,
4529
+ permission: Permission.CurrentUser,
4530
+ }),
4531
+ );
4532
+
4533
+ const result: HttpResult =
4534
+ action === "current"
4535
+ ? await request(route(action))
4536
+ : await postJson(route(action));
4537
+
4538
+ expect(result.status).toBe(ExceptionCode.NotAuthorizedException);
4539
+ expect(findToken).not.toHaveBeenCalled();
4540
+ expect(create).not.toHaveBeenCalled();
4541
+ expect(update).not.toHaveBeenCalled();
4542
+ expect(rotate).not.toHaveBeenCalled();
4543
+ expect(result.body).not.toContain(token);
4544
+ },
4545
+ );
4546
+ },
4547
+ );
4548
+
4235
4549
  // -- Session route: /my-shifts --------------------------------------------------
4236
4550
 
4237
4551
  describe("GET /on-call-calendar/my-shifts", () => {
@@ -4303,12 +4617,65 @@ describe("GET /on-call-calendar/my-shifts", () => {
4303
4617
  expect(materializeSpy).not.toHaveBeenCalled();
4304
4618
  });
4305
4619
 
4306
- test("an anonymous caller is refused", async () => {
4620
+ /*
4621
+ * Was a 400 ("A logged-in user is required." as BadDataException). The
4622
+ * route's requireUserId now goes through CommonAPI.assertAuthenticatedUser,
4623
+ * which answers a caller with no credentials with 401 - the status the
4624
+ * dashboard and the mobile app both answer by refreshing the session.
4625
+ */
4626
+ test("an anonymous caller is refused with 401", async () => {
4307
4627
  propsSpy.mockResolvedValue({ tenantId: undefined, userId: undefined });
4308
4628
 
4309
4629
  const result: HttpResult = await request(`${API_PREFIX}${MY_SHIFTS_ROUTE}`);
4310
4630
 
4311
- expect(result.status).toBe(ExceptionCode.BadDataException);
4631
+ expect(result.status).toBe(ExceptionCode.NotAuthenticatedException);
4632
+ expect(result.status).toBe(401);
4633
+ expect(json(result)["message"]).toBe(
4634
+ CommonAPI.AUTHENTICATION_REQUIRED_MESSAGE,
4635
+ );
4636
+ expect(materializeSpy).not.toHaveBeenCalled();
4637
+ });
4638
+
4639
+ test("an anonymous caller with a tenant header is refused with 401 too", async () => {
4640
+ propsSpy.mockResolvedValue(
4641
+ buildMemberProps({ projectId, userId: undefined }),
4642
+ );
4643
+
4644
+ const result: HttpResult = await request(`${API_PREFIX}${MY_SHIFTS_ROUTE}`);
4645
+
4646
+ expect(result.status).toBe(ExceptionCode.NotAuthenticatedException);
4647
+ expect(materializeSpy).not.toHaveBeenCalled();
4648
+ });
4649
+
4650
+ /*
4651
+ * An API key is authenticated, so it is not a 401 - but "my shifts" needs a
4652
+ * person, so it is refused as not authorised (422) with the route's own
4653
+ * message. This used to be a BadDataException (400) with the same text.
4654
+ */
4655
+ test("a project API key without a tenant header is refused with 422 'A logged-in user is required.'", async () => {
4656
+ propsSpy.mockResolvedValue({
4657
+ tenantId: undefined,
4658
+ userId: undefined,
4659
+ userType: UserType.API,
4660
+ });
4661
+
4662
+ const result: HttpResult = await request(`${API_PREFIX}${MY_SHIFTS_ROUTE}`);
4663
+
4664
+ expect(result.status).toBe(ExceptionCode.NotAuthorizedException);
4665
+ expect(json(result)["message"]).toBe("A logged-in user is required.");
4666
+ expect(materializeSpy).not.toHaveBeenCalled();
4667
+ });
4668
+
4669
+ test("a project API key with a tenant header gets the same 422 - the user check runs first on this route", async () => {
4670
+ propsSpy.mockResolvedValue({
4671
+ ...buildMemberProps({ projectId, userId: undefined }),
4672
+ userType: UserType.API,
4673
+ });
4674
+
4675
+ const result: HttpResult = await request(`${API_PREFIX}${MY_SHIFTS_ROUTE}`);
4676
+
4677
+ expect(result.status).toBe(ExceptionCode.NotAuthorizedException);
4678
+ expect(json(result)["message"]).toBe("A logged-in user is required.");
4312
4679
  expect(materializeSpy).not.toHaveBeenCalled();
4313
4680
  });
4314
4681