@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,715 @@
1
+ import DatabaseService from "../../../Server/Services/DatabaseService";
2
+ import RumSessionPinService from "../../../Server/Services/RumSessionPinService";
3
+ import CreateBy from "../../../Server/Types/Database/CreateBy";
4
+ import FindOneBy from "../../../Server/Types/Database/FindOneBy";
5
+ import PostgresErrorTranslator from "../../../Server/Utils/Database/PostgresErrorTranslator";
6
+ import DatabaseBaseModel from "../../../Models/DatabaseModels/DatabaseBaseModel/DatabaseBaseModel";
7
+ import Project from "../../../Models/DatabaseModels/Project";
8
+ import RumApplication from "../../../Models/DatabaseModels/RumApplication";
9
+ import RumSessionPin from "../../../Models/DatabaseModels/RumSessionPin";
10
+ import DatabaseCommonInteractionProps from "../../../Types/BaseDatabase/DatabaseCommonInteractionProps";
11
+ import BadDataException from "../../../Types/Exception/BadDataException";
12
+ import NotAuthenticatedException from "../../../Types/Exception/NotAuthenticatedException";
13
+ import NotAuthorizedException from "../../../Types/Exception/NotAuthorizedException";
14
+ import ObjectID from "../../../Types/ObjectID";
15
+ import Permission, {
16
+ UserPermission,
17
+ UserTenantAccessPermission,
18
+ } from "../../../Types/Permission";
19
+ import UserType from "../../../Types/UserType";
20
+ import { JSONObject } from "../../../Types/JSON";
21
+ import { afterEach, beforeEach, describe, expect, test } from "@jest/globals";
22
+
23
+ /*
24
+ * RumSessionPinService.create answers "already pinned" by looking the pin up
25
+ * as root and returning it, before super.create has run any permission
26
+ * check. That lookup must not be reachable by a caller who could not create
27
+ * the pin themselves, must search only the project the caller was checked
28
+ * in, and must not hand back more of the pin than the caller could read.
29
+ *
30
+ * findOneBy is stubbed to return a pin for every lookup, so a missing gate
31
+ * shows up as that pin coming back rather than as a database error.
32
+ * DatabaseService.prototype.create is stubbed so no insert is attempted.
33
+ */
34
+
35
+ const VICTIM_PROJECT_ID: ObjectID = new ObjectID(
36
+ "00000000-0000-4000-8000-00000000000a",
37
+ );
38
+ const OTHER_PROJECT_ID: ObjectID = new ObjectID(
39
+ "00000000-0000-4000-8000-00000000000b",
40
+ );
41
+ const RUM_APPLICATION_ID: ObjectID = new ObjectID(
42
+ "00000000-0000-4000-8000-000000000002",
43
+ );
44
+ const USER_ID: ObjectID = new ObjectID("00000000-0000-4000-8000-000000000003");
45
+ const PIN_ID: string = "00000000-0000-4000-8000-000000000004";
46
+ const SESSION_ID: string = "session-abc";
47
+ const STORED_REASON: string = "Customer reported checkout freezing";
48
+
49
+ type TenantPropsFunction = (data: {
50
+ tenantId: ObjectID;
51
+ permissions: Array<Permission>;
52
+ blockedPermissions?: Array<Permission> | undefined;
53
+ blockLabelIds?: Array<ObjectID> | undefined;
54
+ }) => DatabaseCommonInteractionProps;
55
+
56
+ /* The shape getUserMiddleware builds for a signed-in member of tenantId. */
57
+ const memberProps: TenantPropsFunction = (data: {
58
+ tenantId: ObjectID;
59
+ permissions: Array<Permission>;
60
+ blockedPermissions?: Array<Permission> | undefined;
61
+ blockLabelIds?: Array<ObjectID> | undefined;
62
+ }): DatabaseCommonInteractionProps => {
63
+ type ToUserPermissionFunction = (
64
+ isBlockPermission: boolean,
65
+ ) => (permission: Permission) => UserPermission;
66
+
67
+ const toUserPermission: ToUserPermissionFunction = (
68
+ isBlockPermission: boolean,
69
+ ): ((permission: Permission) => UserPermission) => {
70
+ return (permission: Permission): UserPermission => {
71
+ return {
72
+ _type: "UserPermission",
73
+ permission: permission,
74
+ labelIds: isBlockPermission ? data.blockLabelIds || [] : [],
75
+ isBlockPermission: isBlockPermission,
76
+ };
77
+ };
78
+ };
79
+
80
+ const tenantPermission: UserTenantAccessPermission = {
81
+ projectId: data.tenantId,
82
+ _type: "UserTenantAccessPermission",
83
+ permissions: [
84
+ ...data.permissions.map(toUserPermission(false)),
85
+ ...(data.blockedPermissions || []).map(toUserPermission(true)),
86
+ ],
87
+ };
88
+
89
+ return {
90
+ userId: USER_ID,
91
+ tenantId: data.tenantId,
92
+ userType: UserType.User,
93
+ userTenantAccessPermission: {
94
+ [data.tenantId.toString()]: tenantPermission,
95
+ },
96
+ };
97
+ };
98
+
99
+ /* The shape ProjectMiddleware builds for a project API key. */
100
+ const apiKeyProps: TenantPropsFunction = (data: {
101
+ tenantId: ObjectID;
102
+ permissions: Array<Permission>;
103
+ }): DatabaseCommonInteractionProps => {
104
+ const props: DatabaseCommonInteractionProps = memberProps(data);
105
+ delete props.userId;
106
+ props.userType = UserType.API;
107
+
108
+ return props;
109
+ };
110
+
111
+ function pinRequest(
112
+ props: DatabaseCommonInteractionProps,
113
+ ): CreateBy<RumSessionPin> {
114
+ const data: RumSessionPin = new RumSessionPin();
115
+ data.projectId = VICTIM_PROJECT_ID;
116
+ data.rumApplicationId = RUM_APPLICATION_ID;
117
+ data.sessionId = SESSION_ID;
118
+
119
+ return { data, props };
120
+ }
121
+
122
+ /* The model BaseAPI.createItem builds from a request body. */
123
+ function pinRequestFromBody(
124
+ body: JSONObject,
125
+ props: DatabaseCommonInteractionProps,
126
+ ): CreateBy<RumSessionPin> {
127
+ const data: RumSessionPin = DatabaseBaseModel.fromJSON<RumSessionPin>(
128
+ body,
129
+ RumSessionPin,
130
+ ) as RumSessionPin;
131
+
132
+ return { data, props };
133
+ }
134
+
135
+ function storedPin(projectId: ObjectID): RumSessionPin {
136
+ const pin: RumSessionPin = new RumSessionPin();
137
+ pin._id = PIN_ID;
138
+ pin.projectId = projectId;
139
+ pin.rumApplicationId = RUM_APPLICATION_ID;
140
+ pin.sessionId = SESSION_ID;
141
+ pin.reason = STORED_REASON;
142
+ pin.incidentId = new ObjectID("00000000-0000-4000-8000-000000000005");
143
+ pin.alertId = new ObjectID("00000000-0000-4000-8000-000000000007");
144
+ pin.pinnedByUserId = new ObjectID("00000000-0000-4000-8000-000000000006");
145
+
146
+ return pin;
147
+ }
148
+
149
+ /* The error DatabaseService.create throws when the unique index is hit. */
150
+ function translatedUniqueViolation(): unknown {
151
+ return PostgresErrorTranslator.translate({
152
+ message:
153
+ 'duplicate key value violates unique constraint "IDX_rum_session_pin_session"',
154
+ code: "23505",
155
+ table: "RumSessionPin",
156
+ detail:
157
+ 'Key ("projectId", "rumApplicationId", "sessionId")=(00000000-0000-4000-8000-00000000000a, 00000000-0000-4000-8000-000000000002, session-abc) already exists.',
158
+ });
159
+ }
160
+
161
+ type ExpectFullPinFunction = (result: RumSessionPin) => void;
162
+
163
+ const expectFullPin: ExpectFullPinFunction = (result: RumSessionPin): void => {
164
+ expect(result._id).toBe(PIN_ID);
165
+ expect(result.reason).toBe(STORED_REASON);
166
+ expect(result.incidentId).toBeDefined();
167
+ expect(result.pinnedByUserId).toBeDefined();
168
+ };
169
+
170
+ /*
171
+ * Confirms the recording is pinned without anything somebody else wrote on
172
+ * the pin - nor its id, which the update and delete endpoints take.
173
+ */
174
+ const expectAcknowledgementOnly: ExpectFullPinFunction = (
175
+ result: RumSessionPin,
176
+ ): void => {
177
+ expect(result._id).toBeUndefined();
178
+ expect(result.projectId?.toString()).toBe(VICTIM_PROJECT_ID.toString());
179
+ expect(result.rumApplicationId?.toString()).toBe(
180
+ RUM_APPLICATION_ID.toString(),
181
+ );
182
+ expect(result.sessionId).toBe(SESSION_ID);
183
+ expect(result.reason).toBeUndefined();
184
+ expect(result.incidentId).toBeUndefined();
185
+ expect(result.alertId).toBeUndefined();
186
+ expect(result.expiresAt).toBeUndefined();
187
+ expect(result.materializedAt).toBeUndefined();
188
+ expect(result.pinnedByUserId).toBeUndefined();
189
+ };
190
+
191
+ describe("RumSessionPinService.create permission gate", () => {
192
+ let findOneBySpy: jest.SpyInstance;
193
+ let insertSpy: jest.SpyInstance;
194
+
195
+ beforeEach(() => {
196
+ findOneBySpy = jest
197
+ .spyOn(RumSessionPinService, "findOneBy")
198
+ .mockImplementation(
199
+ async (findOneBy: FindOneBy<RumSessionPin>): Promise<RumSessionPin> => {
200
+ return storedPin(findOneBy.query.projectId as ObjectID);
201
+ },
202
+ );
203
+
204
+ insertSpy = jest
205
+ .spyOn(DatabaseService.prototype, "create")
206
+ .mockImplementation(async (createBy: CreateBy<any>) => {
207
+ return createBy.data;
208
+ });
209
+ });
210
+
211
+ afterEach(() => {
212
+ jest.restoreAllMocks();
213
+ });
214
+
215
+ type RefusalType =
216
+ | typeof NotAuthenticatedException
217
+ | typeof NotAuthorizedException
218
+ | typeof BadDataException;
219
+
220
+ type ExpectRefusedFunction = (
221
+ createBy: CreateBy<RumSessionPin>,
222
+ exception: RefusalType,
223
+ ) => Promise<void>;
224
+
225
+ const expectRefusedBeforeLookup: ExpectRefusedFunction = async (
226
+ createBy: CreateBy<RumSessionPin>,
227
+ exception: RefusalType,
228
+ ): Promise<void> => {
229
+ await expect(RumSessionPinService.create(createBy)).rejects.toBeInstanceOf(
230
+ exception,
231
+ );
232
+
233
+ expect(findOneBySpy).not.toHaveBeenCalled();
234
+ expect(insertSpy).not.toHaveBeenCalled();
235
+ };
236
+
237
+ describe("anonymous caller", () => {
238
+ test("is refused as unauthenticated and never sees the pin", async () => {
239
+ await expectRefusedBeforeLookup(
240
+ pinRequest({ userType: UserType.Public }),
241
+ NotAuthenticatedException,
242
+ );
243
+ });
244
+
245
+ test("naming the project in the tenantid header changes nothing", async () => {
246
+ /*
247
+ * getUserMiddleware lets public requests through and takes tenantId
248
+ * from the caller-supplied header, so an anonymous request can arrive
249
+ * already carrying the victim's tenant.
250
+ */
251
+ await expectRefusedBeforeLookup(
252
+ pinRequest({ userType: UserType.Public, tenantId: VICTIM_PROJECT_ID }),
253
+ NotAuthenticatedException,
254
+ );
255
+ });
256
+ });
257
+
258
+ describe("authenticated member of another project", () => {
259
+ test("claiming the victim project as tenant is refused", async () => {
260
+ /*
261
+ * The header names the victim project, but the caller has no grants
262
+ * there: getUserMiddleware only attaches tenant permissions the user
263
+ * actually holds.
264
+ */
265
+ const props: DatabaseCommonInteractionProps = memberProps({
266
+ tenantId: OTHER_PROJECT_ID,
267
+ permissions: [Permission.ProjectOwner],
268
+ });
269
+ props.tenantId = VICTIM_PROJECT_ID;
270
+
271
+ await expectRefusedBeforeLookup(
272
+ pinRequest(props),
273
+ NotAuthorizedException,
274
+ );
275
+ });
276
+
277
+ test("naming the victim project from their own tenant is refused", async () => {
278
+ /*
279
+ * A real owner of their own project, pointing the body's projectId at
280
+ * someone else's. Their grants belong to their own tenant only.
281
+ */
282
+ await expectRefusedBeforeLookup(
283
+ pinRequest(
284
+ memberProps({
285
+ tenantId: OTHER_PROJECT_ID,
286
+ permissions: [Permission.ProjectOwner],
287
+ }),
288
+ ),
289
+ NotAuthorizedException,
290
+ );
291
+ });
292
+
293
+ test("naming the victim project through the project relation is refused", async () => {
294
+ /*
295
+ * The relation shares the projectId column and wins over it when
296
+ * TypeORM saves, so a matching scalar alongside it proves nothing: the
297
+ * row would be written into the victim project.
298
+ */
299
+ const createBy: CreateBy<RumSessionPin> = pinRequest(
300
+ memberProps({
301
+ tenantId: OTHER_PROJECT_ID,
302
+ permissions: [Permission.ProjectOwner],
303
+ }),
304
+ );
305
+ createBy.data.projectId = OTHER_PROJECT_ID;
306
+ createBy.data.project = new Project(VICTIM_PROJECT_ID);
307
+
308
+ await expectRefusedBeforeLookup(createBy, NotAuthorizedException);
309
+ });
310
+ });
311
+
312
+ describe("member of the project without a create grant", () => {
313
+ test("read-only access is not enough to reach the existing pin", async () => {
314
+ await expectRefusedBeforeLookup(
315
+ pinRequest(
316
+ memberProps({
317
+ tenantId: VICTIM_PROJECT_ID,
318
+ permissions: [Permission.ReadRumSessionReplay],
319
+ }),
320
+ ),
321
+ NotAuthorizedException,
322
+ );
323
+ });
324
+
325
+ test("a team block on creating pins outranks the member role", async () => {
326
+ /*
327
+ * ProjectMember is on the create list, so the allow check alone would
328
+ * let this caller through; only the block list stops them.
329
+ */
330
+ await expectRefusedBeforeLookup(
331
+ pinRequest(
332
+ memberProps({
333
+ tenantId: VICTIM_PROJECT_ID,
334
+ permissions: [Permission.ProjectMember],
335
+ blockedPermissions: [Permission.CreateRumSessionReplay],
336
+ }),
337
+ ),
338
+ NotAuthorizedException,
339
+ );
340
+ });
341
+ });
342
+
343
+ describe("permitted caller", () => {
344
+ test("pinning an already-pinned recording returns the existing pin", async () => {
345
+ const result: RumSessionPin = await RumSessionPinService.create(
346
+ pinRequest(
347
+ memberProps({
348
+ tenantId: VICTIM_PROJECT_ID,
349
+ permissions: [Permission.ProjectMember],
350
+ }),
351
+ ),
352
+ );
353
+
354
+ expectFullPin(result);
355
+ /* Idempotent: nothing was inserted. */
356
+ expect(insertSpy).not.toHaveBeenCalled();
357
+ });
358
+
359
+ test("the lookup searches the tenant, not the project as the body spelled it", async () => {
360
+ /*
361
+ * The same project in upper case is accepted, and it is the tenant's
362
+ * spelling that reaches the query - which is also what shows the
363
+ * lookup is keyed on the tenant rather than on the body.
364
+ */
365
+ const createBy: CreateBy<RumSessionPin> = pinRequest(
366
+ apiKeyProps({
367
+ tenantId: VICTIM_PROJECT_ID,
368
+ permissions: [Permission.ProjectMember],
369
+ }),
370
+ );
371
+ createBy.data.projectId = new ObjectID(
372
+ VICTIM_PROJECT_ID.toString().toUpperCase(),
373
+ );
374
+
375
+ await RumSessionPinService.create(createBy);
376
+
377
+ expect(findOneBySpy).toHaveBeenCalledTimes(1);
378
+
379
+ const lookup: FindOneBy<RumSessionPin> = findOneBySpy.mock
380
+ .calls[0]![0] as FindOneBy<RumSessionPin>;
381
+
382
+ expect((lookup.query.projectId as ObjectID).toString()).toBe(
383
+ VICTIM_PROJECT_ID.toString(),
384
+ );
385
+ expect((lookup.query.rumApplicationId as ObjectID).toString()).toBe(
386
+ RUM_APPLICATION_ID.toString(),
387
+ );
388
+ expect(lookup.query.sessionId).toBe(SESSION_ID);
389
+ });
390
+
391
+ test("a new pin reaches super.create with the project relation dropped", async () => {
392
+ findOneBySpy.mockResolvedValue(null as never);
393
+
394
+ const createBy: CreateBy<RumSessionPin> = pinRequest(
395
+ memberProps({
396
+ tenantId: VICTIM_PROJECT_ID,
397
+ permissions: [Permission.ProjectMember],
398
+ }),
399
+ );
400
+ createBy.data.project = new Project(VICTIM_PROJECT_ID);
401
+
402
+ await RumSessionPinService.create(createBy);
403
+
404
+ expect(insertSpy).toHaveBeenCalledTimes(1);
405
+
406
+ const inserted: CreateBy<RumSessionPin> = insertSpy.mock
407
+ .calls[0]![0] as CreateBy<RumSessionPin>;
408
+
409
+ expect(inserted.data.project).toBeUndefined();
410
+ expect(inserted.data.projectId?.toString()).toBe(
411
+ VICTIM_PROJECT_ID.toString(),
412
+ );
413
+ });
414
+
415
+ test("a pin that appears mid-create is returned by the race recovery", async () => {
416
+ findOneBySpy.mockResolvedValueOnce(null as never);
417
+ insertSpy.mockRejectedValueOnce(translatedUniqueViolation() as never);
418
+
419
+ const result: RumSessionPin = await RumSessionPinService.create(
420
+ pinRequest(
421
+ memberProps({
422
+ tenantId: VICTIM_PROJECT_ID,
423
+ permissions: [Permission.ProjectMember],
424
+ }),
425
+ ),
426
+ );
427
+
428
+ expectFullPin(result);
429
+ expect(findOneBySpy).toHaveBeenCalledTimes(2);
430
+ });
431
+ });
432
+
433
+ describe("caller who may create pins but not read them", () => {
434
+ test("an ingest-only API key learns the recording is pinned, nothing more", async () => {
435
+ /*
436
+ * CreateRumSessionReplay is on the pin's create list but not its read
437
+ * list; the same key is refused by get-list.
438
+ */
439
+ const result: RumSessionPin = await RumSessionPinService.create(
440
+ pinRequest(
441
+ apiKeyProps({
442
+ tenantId: VICTIM_PROJECT_ID,
443
+ permissions: [Permission.CreateRumSessionReplay],
444
+ }),
445
+ ),
446
+ );
447
+
448
+ expectAcknowledgementOnly(result);
449
+ expect(insertSpy).not.toHaveBeenCalled();
450
+ });
451
+
452
+ test("an API key that can also read gets the whole pin", async () => {
453
+ const result: RumSessionPin = await RumSessionPinService.create(
454
+ pinRequest(
455
+ apiKeyProps({
456
+ tenantId: VICTIM_PROJECT_ID,
457
+ permissions: [
458
+ Permission.CreateRumSessionReplay,
459
+ Permission.ReadRumSessionReplay,
460
+ ],
461
+ }),
462
+ ),
463
+ );
464
+
465
+ expectFullPin(result);
466
+ });
467
+
468
+ test("a member whose team blocks reading pins gets the acknowledgement", async () => {
469
+ const result: RumSessionPin = await RumSessionPinService.create(
470
+ pinRequest(
471
+ memberProps({
472
+ tenantId: VICTIM_PROJECT_ID,
473
+ permissions: [Permission.ProjectMember],
474
+ blockedPermissions: [Permission.ReadRumSessionReplay],
475
+ }),
476
+ ),
477
+ );
478
+
479
+ expectAcknowledgementOnly(result);
480
+ });
481
+
482
+ test("a label-scoped read block also gets the acknowledgement", async () => {
483
+ /*
484
+ * Pins carry no labels, so the read path cannot narrow a label-scoped
485
+ * block to rows and refuses the read outright.
486
+ */
487
+ const result: RumSessionPin = await RumSessionPinService.create(
488
+ pinRequest(
489
+ memberProps({
490
+ tenantId: VICTIM_PROJECT_ID,
491
+ permissions: [Permission.ProjectMember],
492
+ blockedPermissions: [Permission.ReadRumSessionReplay],
493
+ blockLabelIds: [
494
+ new ObjectID("00000000-0000-4000-8000-0000000000aa"),
495
+ ],
496
+ }),
497
+ ),
498
+ );
499
+
500
+ expectAcknowledgementOnly(result);
501
+ });
502
+
503
+ test("the race recovery is held to the same rule", async () => {
504
+ findOneBySpy.mockResolvedValueOnce(null as never);
505
+ insertSpy.mockRejectedValueOnce(translatedUniqueViolation() as never);
506
+
507
+ const result: RumSessionPin = await RumSessionPinService.create(
508
+ pinRequest(
509
+ apiKeyProps({
510
+ tenantId: VICTIM_PROJECT_ID,
511
+ permissions: [Permission.CreateRumSessionReplay],
512
+ }),
513
+ ),
514
+ );
515
+
516
+ expectAcknowledgementOnly(result);
517
+ });
518
+ });
519
+
520
+ describe("request body", () => {
521
+ const ingestKey: () => DatabaseCommonInteractionProps =
522
+ (): DatabaseCommonInteractionProps => {
523
+ return apiKeyProps({
524
+ tenantId: VICTIM_PROJECT_ID,
525
+ permissions: [Permission.CreateRumSessionReplay],
526
+ });
527
+ };
528
+
529
+ test("a query operator in sessionId is refused before the lookup", async () => {
530
+ /*
531
+ * Deserialized as a StartsWith, this would turn "is this recording
532
+ * pinned" into a search across every pin in the project.
533
+ */
534
+ await expectRefusedBeforeLookup(
535
+ pinRequestFromBody(
536
+ {
537
+ projectId: VICTIM_PROJECT_ID.toJSON(),
538
+ rumApplicationId: RUM_APPLICATION_ID.toJSON(),
539
+ sessionId: { _type: "StartsWith", value: "a" },
540
+ },
541
+ ingestKey(),
542
+ ),
543
+ BadDataException,
544
+ );
545
+ });
546
+
547
+ test("a query operator in rumApplicationId is refused before the lookup", async () => {
548
+ await expectRefusedBeforeLookup(
549
+ pinRequestFromBody(
550
+ {
551
+ projectId: VICTIM_PROJECT_ID.toJSON(),
552
+ rumApplicationId: { _type: "NotNull" },
553
+ sessionId: SESSION_ID,
554
+ },
555
+ ingestKey(),
556
+ ),
557
+ BadDataException,
558
+ );
559
+ });
560
+
561
+ test("a query operator in projectId is refused before the lookup", async () => {
562
+ await expectRefusedBeforeLookup(
563
+ pinRequestFromBody(
564
+ {
565
+ projectId: {
566
+ _type: "StartsWith",
567
+ value: VICTIM_PROJECT_ID.toString(),
568
+ },
569
+ rumApplicationId: RUM_APPLICATION_ID.toJSON(),
570
+ sessionId: SESSION_ID,
571
+ },
572
+ ingestKey(),
573
+ ),
574
+ BadDataException,
575
+ );
576
+ });
577
+
578
+ test("ids sent as plain UUID strings still work", async () => {
579
+ await RumSessionPinService.create(
580
+ pinRequestFromBody(
581
+ {
582
+ projectId: VICTIM_PROJECT_ID.toString(),
583
+ rumApplicationId: RUM_APPLICATION_ID.toString(),
584
+ sessionId: SESSION_ID,
585
+ },
586
+ ingestKey(),
587
+ ),
588
+ );
589
+
590
+ const lookup: FindOneBy<RumSessionPin> = findOneBySpy.mock
591
+ .calls[0]![0] as FindOneBy<RumSessionPin>;
592
+
593
+ expect(lookup.query.rumApplicationId).toBeInstanceOf(ObjectID);
594
+ expect((lookup.query.rumApplicationId as ObjectID).toString()).toBe(
595
+ RUM_APPLICATION_ID.toString(),
596
+ );
597
+ });
598
+
599
+ test("client-chosen system columns never reach super.create", async () => {
600
+ findOneBySpy.mockResolvedValue(null as never);
601
+
602
+ const createBy: CreateBy<RumSessionPin> = pinRequest(ingestKey());
603
+ createBy.data._id = "00000000-0000-4000-8000-0000000000ff";
604
+ createBy.data.deletedAt = new Date("2020-01-01T00:00:00Z");
605
+ createBy.data.createdAt = new Date("2020-01-01T00:00:00Z");
606
+
607
+ await RumSessionPinService.create(createBy);
608
+
609
+ const inserted: CreateBy<RumSessionPin> = insertSpy.mock
610
+ .calls[0]![0] as CreateBy<RumSessionPin>;
611
+
612
+ expect(inserted.data._id).toBeUndefined();
613
+ expect(inserted.data.deletedAt).toBeUndefined();
614
+ expect(inserted.data.createdAt).toBeUndefined();
615
+ });
616
+
617
+ test("a project relation in the body naming another project is refused", async () => {
618
+ await expectRefusedBeforeLookup(
619
+ pinRequestFromBody(
620
+ {
621
+ projectId: VICTIM_PROJECT_ID.toJSON(),
622
+ project: { _id: OTHER_PROJECT_ID.toString() },
623
+ rumApplicationId: RUM_APPLICATION_ID.toJSON(),
624
+ sessionId: SESSION_ID,
625
+ },
626
+ ingestKey(),
627
+ ),
628
+ NotAuthorizedException,
629
+ );
630
+ });
631
+
632
+ test("a project relation too nested to read is still dropped", async () => {
633
+ /*
634
+ * fromJSON leaves this as an array with no _id to check, so only the
635
+ * unconditional drop keeps it out of the save.
636
+ */
637
+ findOneBySpy.mockResolvedValue(null as never);
638
+
639
+ await RumSessionPinService.create(
640
+ pinRequestFromBody(
641
+ {
642
+ projectId: VICTIM_PROJECT_ID.toJSON(),
643
+ project: [[{ _id: OTHER_PROJECT_ID.toString() }]],
644
+ rumApplicationId: RUM_APPLICATION_ID.toJSON(),
645
+ sessionId: SESSION_ID,
646
+ },
647
+ ingestKey(),
648
+ ),
649
+ );
650
+
651
+ const inserted: CreateBy<RumSessionPin> = insertSpy.mock
652
+ .calls[0]![0] as CreateBy<RumSessionPin>;
653
+
654
+ expect(inserted.data.project).toBeUndefined();
655
+ });
656
+
657
+ test("a rumApplication relation that disagrees is refused", async () => {
658
+ const createBy: CreateBy<RumSessionPin> = pinRequest(ingestKey());
659
+ createBy.data.rumApplication = new RumApplication(
660
+ new ObjectID("00000000-0000-4000-8000-0000000000bb"),
661
+ );
662
+
663
+ await expectRefusedBeforeLookup(createBy, BadDataException);
664
+ });
665
+
666
+ test("a rumApplication relation that agrees is dropped before saving", async () => {
667
+ findOneBySpy.mockResolvedValue(null as never);
668
+
669
+ const createBy: CreateBy<RumSessionPin> = pinRequest(ingestKey());
670
+ createBy.data.rumApplication = new RumApplication(RUM_APPLICATION_ID);
671
+
672
+ await RumSessionPinService.create(createBy);
673
+
674
+ const inserted: CreateBy<RumSessionPin> = insertSpy.mock
675
+ .calls[0]![0] as CreateBy<RumSessionPin>;
676
+
677
+ expect(inserted.data.rumApplication).toBeUndefined();
678
+ });
679
+
680
+ test("a request without projectId goes to onBeforeCreate, not the lookup", async () => {
681
+ const createBy: CreateBy<RumSessionPin> = pinRequest(ingestKey());
682
+ delete createBy.data.projectId;
683
+
684
+ await RumSessionPinService.create(createBy);
685
+
686
+ expect(findOneBySpy).not.toHaveBeenCalled();
687
+ expect(insertSpy).toHaveBeenCalledTimes(1);
688
+ });
689
+ });
690
+
691
+ describe("internal callers", () => {
692
+ test("root is not gated", async () => {
693
+ const result: RumSessionPin = await RumSessionPinService.create(
694
+ pinRequest({ isRoot: true }),
695
+ );
696
+
697
+ expectFullPin(result);
698
+ });
699
+
700
+ test("a master admin is not gated", async () => {
701
+ const result: RumSessionPin = await RumSessionPinService.create(
702
+ pinRequest({ isMasterAdmin: true, userId: USER_ID }),
703
+ );
704
+
705
+ expectFullPin(result);
706
+ });
707
+
708
+ test("root still cannot save a project relation that disagrees", async () => {
709
+ const createBy: CreateBy<RumSessionPin> = pinRequest({ isRoot: true });
710
+ createBy.data.project = new Project(OTHER_PROJECT_ID);
711
+
712
+ await expectRefusedBeforeLookup(createBy, BadDataException);
713
+ });
714
+ });
715
+ });