@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,319 @@
1
+ import { mockRouter } from "./Helpers";
2
+ import CommonAPI from "../../../Server/API/CommonAPI";
3
+ import MonitorTemplateAPI from "../../../Server/API/MonitorTemplateAPI";
4
+ import UserMiddleware from "../../../Server/Middleware/UserAuthorization";
5
+ import MonitorTemplateService from "../../../Server/Services/MonitorTemplateService";
6
+ import {
7
+ ExpressRequest,
8
+ ExpressResponse,
9
+ NextFunction,
10
+ } from "../../../Server/Utils/Express";
11
+ import Response from "../../../Server/Utils/Response";
12
+ import DatabaseCommonInteractionProps from "../../../Types/BaseDatabase/DatabaseCommonInteractionProps";
13
+ import Dictionary from "../../../Types/Dictionary";
14
+ import BadDataException from "../../../Types/Exception/BadDataException";
15
+ import ExceptionCode from "../../../Types/Exception/ExceptionCode";
16
+ import NotAuthenticatedException from "../../../Types/Exception/NotAuthenticatedException";
17
+ import NotAuthorizedException from "../../../Types/Exception/NotAuthorizedException";
18
+ import ObjectID from "../../../Types/ObjectID";
19
+ import UserType from "../../../Types/UserType";
20
+
21
+ jest.mock("../../../Server/Utils/Express", () => {
22
+ return {
23
+ getRouter: () => {
24
+ return mockRouter;
25
+ },
26
+ };
27
+ });
28
+
29
+ jest.mock("../../../Server/Utils/Response", () => {
30
+ return {
31
+ sendJsonObjectResponse: jest.fn(),
32
+ sendEntityArrayResponse: jest.fn(),
33
+ sendEntityResponse: jest.fn(),
34
+ sendEmptySuccessResponse: jest.fn(),
35
+ sendErrorResponse: jest.fn(),
36
+ };
37
+ });
38
+
39
+ /*
40
+ * The monitor-template actions (sync to all linked monitors, sync to one,
41
+ * link, unlink) sit on the template's own page, where an editor may leave a
42
+ * tab open long past the access-token lifetime. The access-token cookie
43
+ * expires with the JWT inside it, so the next click arrives with no
44
+ * credentials; getUserMiddleware passes it on as Public with the page's
45
+ * tenantid header, and the service's own permission check used to answer
46
+ * "You do not have permissions to ..." (422). The browser client refreshes
47
+ * the session and replays only on a 401, so the editor saw an error instead.
48
+ *
49
+ * Each route goes through CommonAPI.assertTenantScoped, which now asks for
50
+ * credentials first. The routes are automatable, so a project API key - a
51
+ * credential with no user - is still admitted to the service, whose
52
+ * permission check decides what the key may do.
53
+ */
54
+
55
+ const PROJECT_ID: ObjectID = new ObjectID(
56
+ "11111111-1111-4111-8111-111111111111",
57
+ );
58
+ const TEMPLATE_ID: ObjectID = new ObjectID(
59
+ "22222222-2222-4222-8222-222222222222",
60
+ );
61
+ const MONITOR_ID: ObjectID = new ObjectID(
62
+ "33333333-3333-4333-8333-333333333333",
63
+ );
64
+
65
+ type ServiceMethod =
66
+ | "syncLinkedMonitors"
67
+ | "syncToMonitor"
68
+ | "linkMonitor"
69
+ | "unlinkMonitor";
70
+
71
+ type TemplateRoute = {
72
+ uri: string;
73
+ params: Dictionary<string>;
74
+ serviceMethod: ServiceMethod;
75
+ };
76
+
77
+ const TEMPLATE_ROUTES: Array<TemplateRoute> = [
78
+ {
79
+ uri: "/monitor-template/:monitorTemplateId/sync-to-linked-monitors",
80
+ params: { monitorTemplateId: TEMPLATE_ID.toString() },
81
+ serviceMethod: "syncLinkedMonitors",
82
+ },
83
+ {
84
+ uri: "/monitor-template/:monitorTemplateId/sync-to-monitor/:monitorId",
85
+ params: {
86
+ monitorTemplateId: TEMPLATE_ID.toString(),
87
+ monitorId: MONITOR_ID.toString(),
88
+ },
89
+ serviceMethod: "syncToMonitor",
90
+ },
91
+ {
92
+ uri: "/monitor-template/:monitorTemplateId/link-monitor/:monitorId",
93
+ params: {
94
+ monitorTemplateId: TEMPLATE_ID.toString(),
95
+ monitorId: MONITOR_ID.toString(),
96
+ },
97
+ serviceMethod: "linkMonitor",
98
+ },
99
+ {
100
+ uri: "/monitor-template/:monitorTemplateId/unlink-monitor/:monitorId",
101
+ params: {
102
+ monitorTemplateId: TEMPLATE_ID.toString(),
103
+ monitorId: MONITOR_ID.toString(),
104
+ },
105
+ serviceMethod: "unlinkMonitor",
106
+ },
107
+ ];
108
+
109
+ function withProps(props: DatabaseCommonInteractionProps): void {
110
+ jest
111
+ .spyOn(CommonAPI, "getDatabaseCommonInteractionProps")
112
+ .mockResolvedValue(props);
113
+ }
114
+
115
+ type RouteCall = {
116
+ thrown: unknown;
117
+ nextCallCount: number;
118
+ };
119
+
120
+ async function callRoute(route: TemplateRoute): Promise<RouteCall> {
121
+ const req: ExpressRequest = {
122
+ params: route.params,
123
+ query: {},
124
+ body: {},
125
+ headers: {},
126
+ } as unknown as ExpressRequest;
127
+
128
+ const next: jest.Mock = jest.fn();
129
+
130
+ await mockRouter
131
+ .match("post", route.uri)
132
+ .handlerFunction(
133
+ req,
134
+ {} as ExpressResponse,
135
+ next as unknown as NextFunction,
136
+ );
137
+
138
+ return {
139
+ thrown: next.mock.calls[0] ? next.mock.calls[0][0] : undefined,
140
+ nextCallCount: next.mock.calls.length,
141
+ };
142
+ }
143
+
144
+ let serviceSpies: Record<ServiceMethod, jest.SpyInstance>;
145
+
146
+ beforeAll(() => {
147
+ new MonitorTemplateAPI();
148
+ });
149
+
150
+ beforeEach(() => {
151
+ jest.restoreAllMocks();
152
+ jest.clearAllMocks();
153
+
154
+ serviceSpies = {
155
+ syncLinkedMonitors: jest
156
+ .spyOn(MonitorTemplateService, "syncLinkedMonitors")
157
+ .mockResolvedValue({} as never),
158
+ syncToMonitor: jest
159
+ .spyOn(MonitorTemplateService, "syncToMonitor")
160
+ .mockResolvedValue(undefined as never),
161
+ linkMonitor: jest
162
+ .spyOn(MonitorTemplateService, "linkMonitor")
163
+ .mockResolvedValue(undefined as never),
164
+ unlinkMonitor: jest
165
+ .spyOn(MonitorTemplateService, "unlinkMonitor")
166
+ .mockResolvedValue(undefined as never),
167
+ };
168
+ });
169
+
170
+ afterEach(() => {
171
+ jest.restoreAllMocks();
172
+ });
173
+
174
+ function expectNothingChanged(): void {
175
+ for (const method of Object.keys(serviceSpies) as Array<ServiceMethod>) {
176
+ expect({ [method]: serviceSpies[method].mock.calls.length }).toEqual({
177
+ [method]: 0,
178
+ });
179
+ }
180
+
181
+ expect(Response.sendJsonObjectResponse).not.toHaveBeenCalled();
182
+ expect(Response.sendEmptySuccessResponse).not.toHaveBeenCalled();
183
+ }
184
+
185
+ function expectAuthenticationRequired(call: RouteCall): void {
186
+ expect(call.nextCallCount).toBe(1);
187
+ expect(call.thrown).toBeInstanceOf(NotAuthenticatedException);
188
+ expect(call.thrown).not.toBeInstanceOf(NotAuthorizedException);
189
+ expect(call.thrown).not.toBeInstanceOf(BadDataException);
190
+ expect((call.thrown as NotAuthenticatedException).code).toBe(
191
+ ExceptionCode.NotAuthenticatedException,
192
+ );
193
+ expect((call.thrown as NotAuthenticatedException).message).toBe(
194
+ CommonAPI.AUTHENTICATION_REQUIRED_MESSAGE,
195
+ );
196
+ }
197
+
198
+ describe("the table covers every custom monitor-template action", () => {
199
+ test("every POST /monitor-template/:monitorTemplateId/* route is in the table", () => {
200
+ const registered: Array<string> = mockRouter.routes
201
+ .filter((route: { method: string; uri: string }) => {
202
+ return (
203
+ route.method === "POST" &&
204
+ route.uri.startsWith("/monitor-template/:monitorTemplateId/")
205
+ );
206
+ })
207
+ .map((route: { uri: string }) => {
208
+ return route.uri;
209
+ })
210
+ .sort();
211
+
212
+ const covered: Array<string> = TEMPLATE_ROUTES.map(
213
+ (route: TemplateRoute) => {
214
+ return route.uri;
215
+ },
216
+ ).sort();
217
+
218
+ expect(registered).toEqual(covered);
219
+ });
220
+ });
221
+
222
+ describe.each(TEMPLATE_ROUTES)(
223
+ "POST $uri with an expired session",
224
+ (route: TemplateRoute) => {
225
+ test("is mounted behind getUserMiddleware only, so the handler is the gate", () => {
226
+ expect(mockRouter.match("post", route.uri).middlewares).toEqual([
227
+ UserMiddleware.getUserMiddleware,
228
+ ]);
229
+ });
230
+
231
+ test("answers a caller with no credentials (only a tenantid header) with 401 and changes nothing", async () => {
232
+ withProps({ tenantId: PROJECT_ID, userType: UserType.Public });
233
+
234
+ const call: RouteCall = await callRoute(route);
235
+
236
+ expectAuthenticationRequired(call);
237
+ expectNothingChanged();
238
+ });
239
+
240
+ test("answers a caller with no credentials and no tenantid header with 401, not the missing-project 400", async () => {
241
+ withProps({ userType: UserType.Public });
242
+
243
+ const call: RouteCall = await callRoute(route);
244
+
245
+ expectAuthenticationRequired(call);
246
+ expectNothingChanged();
247
+ });
248
+
249
+ test("answers a caller getUserMiddleware left unclassified with 401", async () => {
250
+ withProps({ tenantId: PROJECT_ID });
251
+
252
+ const call: RouteCall = await callRoute(route);
253
+
254
+ expectAuthenticationRequired(call);
255
+ expectNothingChanged();
256
+ });
257
+
258
+ test("admits a project API key to the service, which applies the key's own permissions", async () => {
259
+ const props: DatabaseCommonInteractionProps = {
260
+ tenantId: PROJECT_ID,
261
+ userType: UserType.API,
262
+ };
263
+ withProps(props);
264
+
265
+ const call: RouteCall = await callRoute(route);
266
+
267
+ expect(call.nextCallCount).toBe(0);
268
+ expect(serviceSpies[route.serviceMethod]).toHaveBeenCalledTimes(1);
269
+ expect(serviceSpies[route.serviceMethod]).toHaveBeenCalledWith(
270
+ expect.objectContaining({ props: props }),
271
+ );
272
+ });
273
+
274
+ test("a project API key without a tenant is scoped out with 400, not treated as anonymous", async () => {
275
+ withProps({ userType: UserType.API });
276
+
277
+ const call: RouteCall = await callRoute(route);
278
+
279
+ expect(call.thrown).toBeInstanceOf(BadDataException);
280
+ expect(call.thrown).not.toBeInstanceOf(NotAuthenticatedException);
281
+ expectNothingChanged();
282
+ });
283
+
284
+ test("admits a signed-in user as before", async () => {
285
+ withProps({
286
+ tenantId: PROJECT_ID,
287
+ userType: UserType.User,
288
+ userId: ObjectID.generate(),
289
+ });
290
+
291
+ const call: RouteCall = await callRoute(route);
292
+
293
+ expect(call.nextCallCount).toBe(0);
294
+ expect(serviceSpies[route.serviceMethod]).toHaveBeenCalledTimes(1);
295
+ });
296
+
297
+ /*
298
+ * An authenticated caller the service refuses keeps that refusal: the
299
+ * 401 is only for a caller with no credentials at all.
300
+ */
301
+ test("a signed-in user the service refuses still gets the service's 422", async () => {
302
+ withProps({
303
+ tenantId: PROJECT_ID,
304
+ userType: UserType.User,
305
+ userId: ObjectID.generate(),
306
+ });
307
+ serviceSpies[route.serviceMethod].mockRejectedValue(
308
+ new NotAuthorizedException("You do not have permission to do this."),
309
+ );
310
+
311
+ const call: RouteCall = await callRoute(route);
312
+
313
+ expect(call.thrown).toBeInstanceOf(NotAuthorizedException);
314
+ expect((call.thrown as NotAuthorizedException).code).toBe(
315
+ ExceptionCode.NotAuthorizedException,
316
+ );
317
+ });
318
+ },
319
+ );
@@ -0,0 +1,336 @@
1
+ import { mockRouter } from "./Helpers";
2
+ import CommonAPI from "../../../Server/API/CommonAPI";
3
+ import OnCallDutyPolicyAPI from "../../../Server/API/OnCallDutyPolicyAPI";
4
+ import UserMiddleware from "../../../Server/Middleware/UserAuthorization";
5
+ import OnCallDutyPolicyService from "../../../Server/Services/OnCallDutyPolicyService";
6
+ import {
7
+ ExpressRequest,
8
+ ExpressResponse,
9
+ NextFunction,
10
+ } from "../../../Server/Utils/Express";
11
+ import Response from "../../../Server/Utils/Response";
12
+ import DatabaseCommonInteractionProps from "../../../Types/BaseDatabase/DatabaseCommonInteractionProps";
13
+ import Dictionary from "../../../Types/Dictionary";
14
+ import BadDataException from "../../../Types/Exception/BadDataException";
15
+ import ExceptionCode from "../../../Types/Exception/ExceptionCode";
16
+ import NotAuthenticatedException from "../../../Types/Exception/NotAuthenticatedException";
17
+ import NotAuthorizedException from "../../../Types/Exception/NotAuthorizedException";
18
+ import { JSONObject } from "../../../Types/JSON";
19
+ import ObjectID from "../../../Types/ObjectID";
20
+ import Permission, {
21
+ UserPermission,
22
+ UserTenantAccessPermission,
23
+ } from "../../../Types/Permission";
24
+ import UserType from "../../../Types/UserType";
25
+
26
+ jest.mock("../../../Server/Utils/Express", () => {
27
+ return {
28
+ getRouter: () => {
29
+ return mockRouter;
30
+ },
31
+ };
32
+ });
33
+
34
+ jest.mock("../../../Server/Utils/Response", () => {
35
+ return {
36
+ sendJsonObjectResponse: jest.fn(),
37
+ sendEntityArrayResponse: jest.fn(),
38
+ sendEntityResponse: jest.fn(),
39
+ sendEmptySuccessResponse: jest.fn(),
40
+ sendErrorResponse: jest.fn(),
41
+ };
42
+ });
43
+
44
+ /*
45
+ * GET /on-call-duty-policy/current-on-duty-escalation-policies backs the
46
+ * "you are on call" indicator in the dashboard header, so every dashboard
47
+ * page polls it. That makes it the request most likely to be the FIRST to
48
+ * arrive after the access-token cookie has expired together with its JWT:
49
+ * the browser stops sending the cookie, getUserMiddleware passes the request
50
+ * on as Public with only the page's tenantid header, and this handler used to
51
+ * answer "Invalid userId." (400). The browser client refreshes the session
52
+ * and replays only on a 401, so that 400 left the header broken and the
53
+ * session unrefreshed.
54
+ *
55
+ * It now checks for credentials first: no credentials at all is 401. Callers
56
+ * that ARE authenticated keep exactly the answers they had - including a
57
+ * project API key, which has no user to be on call and still gets
58
+ * "Invalid userId." (a 401 would only send its client to refresh a session it
59
+ * does not have).
60
+ */
61
+
62
+ const ROUTE: string =
63
+ "/on-call-duty-policy/current-on-duty-escalation-policies";
64
+
65
+ const PROJECT_ID: ObjectID = new ObjectID(
66
+ "11111111-1111-4111-8111-111111111111",
67
+ );
68
+ const USER_ID: ObjectID = new ObjectID("22222222-2222-4222-8222-222222222222");
69
+
70
+ function tenantPermissions(
71
+ permissions: Array<Permission>,
72
+ ): Dictionary<UserTenantAccessPermission> {
73
+ const dictionary: Dictionary<UserTenantAccessPermission> = {};
74
+
75
+ dictionary[PROJECT_ID.toString()] = {
76
+ _type: "UserTenantAccessPermission",
77
+ projectId: PROJECT_ID,
78
+ permissions: permissions.map((permission: Permission) => {
79
+ return {
80
+ _type: "UserPermission",
81
+ permission: permission,
82
+ labelIds: [],
83
+ isBlockPermission: false,
84
+ } as UserPermission;
85
+ }),
86
+ isBlockPermission: false,
87
+ } as UserTenantAccessPermission;
88
+
89
+ return dictionary;
90
+ }
91
+
92
+ function withProps(props: DatabaseCommonInteractionProps): void {
93
+ jest
94
+ .spyOn(CommonAPI, "getDatabaseCommonInteractionProps")
95
+ .mockResolvedValue(props);
96
+ }
97
+
98
+ type RouteCall = {
99
+ thrown: unknown;
100
+ nextCallCount: number;
101
+ };
102
+
103
+ async function callRoute(): Promise<RouteCall> {
104
+ const req: ExpressRequest = {
105
+ params: {},
106
+ query: {},
107
+ body: {},
108
+ headers: {},
109
+ } as unknown as ExpressRequest;
110
+
111
+ const next: jest.Mock = jest.fn();
112
+
113
+ await mockRouter
114
+ .match("get", ROUTE)
115
+ .handlerFunction(
116
+ req,
117
+ {} as ExpressResponse,
118
+ next as unknown as NextFunction,
119
+ );
120
+
121
+ return {
122
+ thrown: next.mock.calls[0] ? next.mock.calls[0][0] : undefined,
123
+ nextCallCount: next.mock.calls.length,
124
+ };
125
+ }
126
+
127
+ // The error this handler sent itself (it answers bad input without next()).
128
+ function sentError(): unknown {
129
+ const sendError: jest.Mock =
130
+ Response.sendErrorResponse as unknown as jest.Mock;
131
+
132
+ expect(sendError).toHaveBeenCalledTimes(1);
133
+
134
+ return sendError.mock.calls[0]![2];
135
+ }
136
+
137
+ function expectAuthenticationRequired(call: RouteCall): void {
138
+ expect(call.nextCallCount).toBe(1);
139
+ expect(call.thrown).toBeInstanceOf(NotAuthenticatedException);
140
+ expect(call.thrown).not.toBeInstanceOf(NotAuthorizedException);
141
+ expect(call.thrown).not.toBeInstanceOf(BadDataException);
142
+ expect((call.thrown as NotAuthenticatedException).code).toBe(
143
+ ExceptionCode.NotAuthenticatedException,
144
+ );
145
+ expect((call.thrown as NotAuthenticatedException).message).toBe(
146
+ CommonAPI.AUTHENTICATION_REQUIRED_MESSAGE,
147
+ );
148
+ }
149
+
150
+ let onCallLookup: jest.SpyInstance;
151
+
152
+ beforeAll(() => {
153
+ new OnCallDutyPolicyAPI();
154
+ });
155
+
156
+ beforeEach(() => {
157
+ jest.restoreAllMocks();
158
+ jest.clearAllMocks();
159
+
160
+ onCallLookup = jest
161
+ .spyOn(OnCallDutyPolicyService, "getOnCallPoliciesWhereUserIsOnCallDuty")
162
+ .mockResolvedValue({
163
+ escalationRulesByUser: [],
164
+ escalationRulesByTeam: [],
165
+ escalationRulesBySchedule: [],
166
+ });
167
+ });
168
+
169
+ afterEach(() => {
170
+ jest.restoreAllMocks();
171
+ });
172
+
173
+ function expectNoLookupAndNoResponse(): void {
174
+ expect(onCallLookup).not.toHaveBeenCalled();
175
+ expect(Response.sendJsonObjectResponse).not.toHaveBeenCalled();
176
+ }
177
+
178
+ describe(`GET ${ROUTE} - wiring`, () => {
179
+ /*
180
+ * getUserMiddleware is a context loader, not a gate; the handler is what
181
+ * has to tell an anonymous caller to authenticate.
182
+ */
183
+ test("is mounted behind getUserMiddleware only", () => {
184
+ expect(mockRouter.match("get", ROUTE).middlewares).toEqual([
185
+ UserMiddleware.getUserMiddleware,
186
+ ]);
187
+ });
188
+ });
189
+
190
+ describe(`GET ${ROUTE} - an expired session`, () => {
191
+ test("a caller with no credentials but the page's tenantid header gets 401, not 'Invalid userId.'", async () => {
192
+ withProps({
193
+ tenantId: PROJECT_ID,
194
+ userType: UserType.Public,
195
+ userId: undefined,
196
+ });
197
+
198
+ const call: RouteCall = await callRoute();
199
+
200
+ expectAuthenticationRequired(call);
201
+ expect(Response.sendErrorResponse).not.toHaveBeenCalled();
202
+ expectNoLookupAndNoResponse();
203
+ });
204
+
205
+ test("a caller with no credentials and no tenantid header gets 401, not 'Invalid projectId.'", async () => {
206
+ withProps({ userType: UserType.Public });
207
+
208
+ const call: RouteCall = await callRoute();
209
+
210
+ expectAuthenticationRequired(call);
211
+ expect(Response.sendErrorResponse).not.toHaveBeenCalled();
212
+ expectNoLookupAndNoResponse();
213
+ });
214
+
215
+ test("a caller getUserMiddleware left unclassified is anonymous too", async () => {
216
+ withProps({ tenantId: PROJECT_ID });
217
+
218
+ const call: RouteCall = await callRoute();
219
+
220
+ expectAuthenticationRequired(call);
221
+ expectNoLookupAndNoResponse();
222
+ });
223
+
224
+ /*
225
+ * Tenant grants on a request with no user, no key and no master-admin
226
+ * session prove nothing about who sent it.
227
+ */
228
+ test("stray tenant permissions do not make an anonymous caller authenticated", async () => {
229
+ withProps({
230
+ tenantId: PROJECT_ID,
231
+ userType: UserType.Public,
232
+ userTenantAccessPermission: tenantPermissions([Permission.ProjectOwner]),
233
+ });
234
+
235
+ const call: RouteCall = await callRoute();
236
+
237
+ expectAuthenticationRequired(call);
238
+ expectNoLookupAndNoResponse();
239
+ });
240
+
241
+ /*
242
+ * isMasterAdmin is derived from a master-admin SESSION; the flag alone,
243
+ * without a user or that session, is not a credential.
244
+ */
245
+ test("an isMasterAdmin flag without a user or a master-admin session is not a credential", async () => {
246
+ withProps({ tenantId: PROJECT_ID, isMasterAdmin: true });
247
+
248
+ const call: RouteCall = await callRoute();
249
+
250
+ expectAuthenticationRequired(call);
251
+ expectNoLookupAndNoResponse();
252
+ });
253
+ });
254
+
255
+ describe(`GET ${ROUTE} - authenticated callers keep their answers`, () => {
256
+ /*
257
+ * A key has no user to be on call. It is authenticated, so it keeps the
258
+ * 400 it always got rather than a 401 that would send it to refresh a
259
+ * session it never had.
260
+ */
261
+ test("a project API key with no user still gets 400 'Invalid userId.'", async () => {
262
+ withProps({
263
+ tenantId: PROJECT_ID,
264
+ userType: UserType.API,
265
+ userId: undefined,
266
+ userTenantAccessPermission: tenantPermissions([Permission.ProjectOwner]),
267
+ });
268
+
269
+ const call: RouteCall = await callRoute();
270
+
271
+ expect(call.nextCallCount).toBe(0);
272
+
273
+ const error: unknown = sentError();
274
+ expect(error).toBeInstanceOf(BadDataException);
275
+ expect(error).not.toBeInstanceOf(NotAuthenticatedException);
276
+ expect((error as BadDataException).code).toBe(
277
+ ExceptionCode.BadDataException,
278
+ );
279
+ expect((error as BadDataException).message).toBe("Invalid userId.");
280
+ expectNoLookupAndNoResponse();
281
+ });
282
+
283
+ test("a master-admin session is a credential: with no user it gets 'Invalid userId.', not 401", async () => {
284
+ withProps({
285
+ tenantId: PROJECT_ID,
286
+ userType: UserType.MasterAdmin,
287
+ isMasterAdmin: true,
288
+ userId: undefined,
289
+ });
290
+
291
+ const call: RouteCall = await callRoute();
292
+
293
+ expect(call.nextCallCount).toBe(0);
294
+ expect((sentError() as BadDataException).message).toBe("Invalid userId.");
295
+ expectNoLookupAndNoResponse();
296
+ });
297
+
298
+ test("a signed-in user with no tenantid header still gets 400 'Invalid projectId.'", async () => {
299
+ withProps({ userType: UserType.User, userId: USER_ID });
300
+
301
+ const call: RouteCall = await callRoute();
302
+
303
+ expect(call.nextCallCount).toBe(0);
304
+ expect((sentError() as BadDataException).message).toBe(
305
+ "Invalid projectId.",
306
+ );
307
+ expectNoLookupAndNoResponse();
308
+ });
309
+
310
+ test("a signed-in user gets their on-call escalation policies for the project", async () => {
311
+ withProps({
312
+ tenantId: PROJECT_ID,
313
+ userType: UserType.User,
314
+ userId: USER_ID,
315
+ userTenantAccessPermission: tenantPermissions([Permission.ProjectMember]),
316
+ });
317
+
318
+ const call: RouteCall = await callRoute();
319
+
320
+ expect(call.nextCallCount).toBe(0);
321
+ expect(Response.sendErrorResponse).not.toHaveBeenCalled();
322
+ expect(onCallLookup).toHaveBeenCalledWith({
323
+ projectId: PROJECT_ID,
324
+ userId: USER_ID,
325
+ });
326
+
327
+ const sendJson: jest.Mock =
328
+ Response.sendJsonObjectResponse as unknown as jest.Mock;
329
+ expect(sendJson).toHaveBeenCalledTimes(1);
330
+ expect(sendJson.mock.calls[0]![2] as JSONObject).toEqual({
331
+ escalationRulesByUser: [],
332
+ escalationRulesByTeam: [],
333
+ escalationRulesBySchedule: [],
334
+ });
335
+ });
336
+ });