@oneuptime/common 13.0.7 → 14.0.0

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 (759) hide show
  1. package/Models/AnalyticsModels/AuditLog.ts +23 -15
  2. package/Models/DatabaseModels/GlobalConfig.ts +24 -0
  3. package/Models/DatabaseModels/Monitor.ts +3 -2
  4. package/Models/DatabaseModels/MonitorTemplate.ts +2 -1
  5. package/Models/DatabaseModels/OnCallDutyPolicyScheduleCalendarFeed.ts +1 -1
  6. package/Models/DatabaseModels/ProjectOnCallCalendarFeed.ts +1 -1
  7. package/Models/DatabaseModels/UserOnCallCalendarFeed.ts +1 -1
  8. package/Scripts/generate-service-worker.js +65 -4
  9. package/Server/API/AIBillingAPI.ts +1 -0
  10. package/Server/API/AIInsightAPI.ts +1 -4
  11. package/Server/API/AIInvestigationAPI.ts +1 -4
  12. package/Server/API/AIReadinessAPI.ts +4 -5
  13. package/Server/API/AlertAPI.ts +1 -0
  14. package/Server/API/AutoRemediationAPI.ts +1 -4
  15. package/Server/API/BaseAPI.ts +34 -0
  16. package/Server/API/BaseAnalyticsAPI.ts +80 -9
  17. package/Server/API/BillingAPI.ts +2 -0
  18. package/Server/API/BillingInvoiceAPI.ts +1 -0
  19. package/Server/API/BillingPaymentMethodAPI.ts +2 -0
  20. package/Server/API/CodeFixRunAPI.ts +1 -3
  21. package/Server/API/CommonAPI.ts +68 -4
  22. package/Server/API/DashboardAPI.ts +12 -12
  23. package/Server/API/GlobalConfigAPI.ts +243 -460
  24. package/Server/API/IncidentAPI.ts +2 -0
  25. package/Server/API/IncidentEpisodeAPI.ts +1 -0
  26. package/Server/API/NotificationAPI.ts +1 -0
  27. package/Server/API/OnCallCalendarAPI.ts +4 -5
  28. package/Server/API/OnCallDutyPolicyAPI.ts +7 -0
  29. package/Server/API/OnCallReadinessAPI.ts +4 -1
  30. package/Server/API/OnCallScheduleTimelineAPI.ts +731 -0
  31. package/Server/API/ProjectAPI.ts +1 -0
  32. package/Server/API/ProjectOIDC.ts +25 -16
  33. package/Server/API/ProjectSSO.ts +24 -16
  34. package/Server/API/ScheduledMaintenanceAPI.ts +1 -0
  35. package/Server/API/StatusPageAPI.ts +261 -74
  36. package/Server/API/TeamMemberAPI.ts +13 -1
  37. package/Server/API/UserCallAPI.ts +2 -0
  38. package/Server/API/UserEmailAPI.ts +2 -0
  39. package/Server/API/UserIncomingCallNumberAPI.ts +2 -0
  40. package/Server/API/UserMicrosoftTeamsAPI.ts +1 -0
  41. package/Server/API/UserSlackAPI.ts +1 -0
  42. package/Server/API/UserSmsAPI.ts +2 -0
  43. package/Server/API/UserTotpAuthAPI.ts +1 -0
  44. package/Server/API/UserWebAuthnAPI.ts +2 -0
  45. package/Server/API/UserWebhookAPI.ts +1 -0
  46. package/Server/API/UserWhatsAppAPI.ts +2 -0
  47. package/Server/Enterprise/EnterpriseEdition.ts +649 -0
  48. package/Server/Enterprise/EnterpriseFeature.ts +48 -0
  49. package/Server/Enterprise/EnterpriseLicenseSnapshot.ts +192 -0
  50. package/Server/Enterprise/EnterpriseServerModule.ts +233 -0
  51. package/Server/EnvironmentConfig.ts +147 -2
  52. package/Server/Infrastructure/Postgres/SchemaMigrations/1793900000000-AddEnterpriseEditionFirstSeenAt.ts +25 -0
  53. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +2 -0
  54. package/Server/Middleware/MasterAdminAuthorization.ts +13 -2
  55. package/Server/Middleware/UserAuthorization.ts +117 -21
  56. package/Server/Services/ApiKeyPermissionService.ts +101 -4
  57. package/Server/Services/AuditLogService.ts +84 -1079
  58. package/Server/Services/DatabaseService.ts +245 -0
  59. package/Server/Services/DetectionRuleService.ts +5 -4
  60. package/Server/Services/EnterpriseLicenseService.ts +38 -0
  61. package/Server/Services/GlobalConfigService.ts +80 -1
  62. package/Server/Services/MonitorProbeService.ts +116 -20
  63. package/Server/Services/MonitorService.ts +56 -4
  64. package/Server/Services/MonitorStatusTimelineService.ts +284 -0
  65. package/Server/Services/MonitorTemplateService.ts +26 -0
  66. package/Server/Services/OnCallDutyPolicyChildService.ts +261 -0
  67. package/Server/Services/OnCallDutyPolicyEscalationRuleScheduleService.ts +2 -2
  68. package/Server/Services/OnCallDutyPolicyEscalationRuleService.ts +2 -2
  69. package/Server/Services/OnCallDutyPolicyEscalationRuleTeamService.ts +2 -2
  70. package/Server/Services/OnCallDutyPolicyEscalationRuleUserService.ts +2 -2
  71. package/Server/Services/PayAsYouGoBillingService.ts +23 -28
  72. package/Server/Services/ProjectService.ts +302 -0
  73. package/Server/Services/RumSessionPinService.ts +293 -22
  74. package/Server/Services/StatusPagePrivateUserService.ts +7 -3
  75. package/Server/Services/StatusPageService.ts +78 -1
  76. package/Server/Services/TeamMemberService.ts +11 -0
  77. package/Server/Services/TeamPermissionService.ts +120 -26
  78. package/Server/Services/TeamService.ts +10 -0
  79. package/Server/Services/ThreatIntelFeedService.ts +6 -3
  80. package/Server/Services/UserService.ts +10 -17
  81. package/Server/Types/Database/Permissions/BasePermission.ts +9 -7
  82. package/Server/Types/Database/Permissions/CreatePermission.ts +15 -0
  83. package/Server/Types/Database/Permissions/EditionPermission.ts +208 -18
  84. package/Server/Types/Database/Permissions/Index.ts +75 -11
  85. package/Server/Types/Database/Permissions/TablePermission.ts +34 -31
  86. package/Server/Types/Database/Permissions/UpdatePermission.ts +29 -0
  87. package/Server/Types/Markdown.ts +41 -0
  88. package/Server/Utils/AI/AIChatPrivacyFilter.ts +8 -0
  89. package/Server/Utils/AI/AIRunPrivacyFilter.ts +8 -0
  90. package/Server/Utils/CommunityEditionSsoReport.ts +361 -0
  91. package/Server/Utils/EditionEnforcement.ts +233 -0
  92. package/Server/Utils/FrontendEnvironment.ts +41 -2
  93. package/Server/Utils/InstanceHealth/RedisHealth.ts +12 -277
  94. package/Server/Utils/MasterAdminPageAccess.ts +61 -0
  95. package/Server/Utils/Monitor/AffectedResourceList.ts +190 -0
  96. package/Server/Utils/Monitor/Criteria/EvaluateOverTime.ts +10 -1
  97. package/Server/Utils/Monitor/MonitorAlert.ts +3 -1
  98. package/Server/Utils/Monitor/MonitorCriteriaEvaluator.ts +543 -333
  99. package/Server/Utils/Monitor/MonitorIncident.ts +3 -1
  100. package/Server/Utils/Monitor/MonitoringIntervalValidator.ts +116 -0
  101. package/Server/Utils/OnCall/OnCallCalendarFeedRenderer.ts +1 -1
  102. package/Server/Utils/Realtime.ts +163 -45
  103. package/Server/Utils/SecurityEvent/DetectionRuleEvaluator.ts +11 -28
  104. package/Server/Utils/SecurityEvent/GoogleSecOpsSeverityRepair.ts +170 -0
  105. package/Server/Utils/SecurityEvent/Sigma/SigmaClickhouseCompiler.ts +1 -1
  106. package/Server/Utils/SecurityEvent/ThreatIntel/ThreatIntelFeedPoller.ts +6 -2
  107. package/Server/Utils/SecurityEvent/ThreatIntel/ThreatIntelMatcher.ts +10 -9
  108. package/Server/Utils/Workspace/Slack/Slack.ts +423 -10
  109. package/Tests/App/Accounts/LoginPasskey.test.tsx +18 -0
  110. package/Tests/App/Accounts/LoginSsoEdition.test.tsx +616 -0
  111. package/Tests/App/AdminDashboard/AdminAuthenticationSsoEdition.test.tsx +217 -0
  112. package/Tests/App/AdminDashboard/AdminEnterprisePluginPage.test.tsx +357 -0
  113. package/Tests/App/AdminDashboard/EnterpriseLicensesShell.test.tsx +214 -0
  114. package/Tests/App/AdminDashboard/GlobalSSOEnterpriseShells.test.tsx +271 -0
  115. package/Tests/App/AdminDashboard/HealthShells.test.tsx +659 -0
  116. package/Tests/App/Dashboard/AffectedResourcesPicker.test.tsx +1059 -0
  117. package/Tests/App/Dashboard/AffectedResourcesPickerEditForm.test.tsx +376 -0
  118. package/Tests/App/Dashboard/AffectedResourcesPickerHiddenTypes.test.tsx +757 -0
  119. package/Tests/App/Dashboard/AffectedResourcesSummaryStep.test.tsx +307 -0
  120. package/Tests/App/Dashboard/ArgumentsFormGroupByUnlistedAttributes.test.tsx +131 -0
  121. package/Tests/App/Dashboard/AuditLogsAndComplianceShells.test.tsx +572 -0
  122. package/Tests/App/Dashboard/DashboardHeaderRequests.test.tsx +1 -1
  123. package/Tests/App/Dashboard/DashboardMonitorLabelVariable.test.tsx +9 -1
  124. package/Tests/App/Dashboard/DashboardVariableAllContract.test.tsx +24 -0
  125. package/Tests/App/Dashboard/DashboardVariableSelector.test.tsx +162 -8
  126. package/Tests/App/Dashboard/EnterpriseFeatureUpgrade.test.tsx +547 -0
  127. package/Tests/App/Dashboard/EnterprisePluginPage.test.tsx +667 -0
  128. package/Tests/App/Dashboard/EntityFilterDropdownArchivedSlos.test.tsx +105 -6
  129. package/Tests/App/Dashboard/EntityFilterDropdownUnlistedSelection.test.tsx +434 -0
  130. package/Tests/App/Dashboard/EscalationRuleReadiness.test.tsx +276 -1
  131. package/Tests/App/Dashboard/IdentityEnterpriseShells.test.tsx +319 -0
  132. package/Tests/App/Dashboard/OnCallCalendarFeedSideMenus.test.tsx +9 -1
  133. package/Tests/App/Dashboard/OnboardingSsoEmptyState.test.tsx +185 -0
  134. package/Tests/App/Dashboard/PayAsYouGoConsentGate.test.tsx +58 -42
  135. package/Tests/App/Dashboard/PayAsYouGoNotices.test.tsx +42 -5
  136. package/Tests/App/Dashboard/ResourceAuditLogsSideMenus.test.tsx +34 -23
  137. package/Tests/App/Dashboard/ScheduleTimeline.test.tsx +1580 -0
  138. package/Tests/App/Dashboard/ScheduleTimelineAPI.test.ts +280 -0
  139. package/Tests/App/Dashboard/ScheduleTimelineModel.test.ts +673 -0
  140. package/Tests/App/Dashboard/SecurityEventConnectionDiagnostics.test.tsx +133 -70
  141. package/Tests/App/Dashboard/SecurityEventDetailPanel.test.tsx +399 -0
  142. package/Tests/App/Dashboard/SecurityEventListRow.test.tsx +214 -0
  143. package/Tests/App/Dashboard/SecurityEventsDetectionRulesPage.test.tsx +86 -3
  144. package/Tests/App/Dashboard/SecurityEventsEmptyState.test.tsx +1 -58
  145. package/Tests/App/Dashboard/SecurityEventsGuideContent.test.ts +1313 -0
  146. package/Tests/App/Dashboard/SecurityEventsHowItWorksCard.test.tsx +536 -0
  147. package/Tests/App/Dashboard/SecurityEventsNavTabs.test.tsx +248 -0
  148. package/Tests/App/Dashboard/SecurityEventsNoResults.test.tsx +222 -0
  149. package/Tests/App/Dashboard/SecurityEventsThreatIntelPage.test.tsx +199 -0
  150. package/Tests/App/Dashboard/SecurityEventsViewer.test.tsx +1203 -0
  151. package/Tests/App/Dashboard/SloOverviewHero.test.tsx +171 -36
  152. package/Tests/App/Dashboard/SloViewSideMenu.test.tsx +215 -0
  153. package/Tests/App/Dashboard/SloViewSideMenuCounts.test.tsx +40 -3
  154. package/Tests/App/Dashboard/UserEmailCallSites.test.tsx +11 -91
  155. package/Tests/App/PublicDashboard/DashboardVariableSelector.test.tsx +12 -4
  156. package/Tests/App/PublicDashboard/PublicDashboardWidgetListAuth.test.tsx +623 -0
  157. package/Tests/App/StatusPage/StatusPageSsoEmptyState.test.tsx +319 -0
  158. package/Tests/Helpers/RefreshAwareApiScan.ts +757 -0
  159. package/Tests/Helpers/TenantScopedRequestScan.ts +515 -0
  160. package/Tests/Models/OnCallCalendarFeedModels.test.ts +23 -1
  161. package/Tests/Scripts/GenerateServiceWorker.test.ts +931 -0
  162. package/Tests/Server/API/AIChatRouteAuthorization.test.ts +138 -5
  163. package/Tests/Server/API/AIGenerationProjectAIToggle.test.ts +187 -0
  164. package/Tests/Server/API/AIInvestigationAvailabilityAuthorization.test.ts +51 -3
  165. package/Tests/Server/API/AIInvestigationEvidenceAPI.test.ts +55 -2
  166. package/Tests/Server/API/BaseAPICreateItemDoesNotMutateModel.test.ts +130 -0
  167. package/Tests/Server/API/BaseAnalyticsAPIAggregateCache.test.ts +729 -0
  168. package/Tests/Server/API/BillingPayAsYouGoStatus.test.ts +93 -7
  169. package/Tests/Server/API/BillingPaymentMethodAPI.test.ts +36 -3
  170. package/Tests/Server/API/CommonAPIAuthGuard.test.ts +1003 -24
  171. package/Tests/Server/API/DashboardPublicRateLimit.test.ts +6 -3
  172. package/Tests/Server/API/ExpiredSessionAIRoutes.test.ts +708 -0
  173. package/Tests/Server/API/ExpiredSessionCustomRoutes.test.ts +928 -0
  174. package/Tests/Server/API/ExpiredSessionMonitorTemplate.test.ts +319 -0
  175. package/Tests/Server/API/ExpiredSessionOnCallDutyPolicy.test.ts +336 -0
  176. package/Tests/Server/API/ExpiredSessionRouteGuards.test.ts +820 -0
  177. package/Tests/Server/API/GlobalConfigLicense.test.ts +766 -381
  178. package/Tests/Server/API/NotificationChannelVerificationAPI.test.ts +115 -12
  179. package/Tests/Server/API/OnCallCalendarAPI.test.ts +375 -8
  180. package/Tests/Server/API/OnCallReadinessAPI.test.ts +196 -912
  181. package/Tests/Server/API/OnCallScheduleTimelineAPI.test.ts +1513 -0
  182. package/Tests/Server/API/OnCallSetupReminderAPI.test.ts +119 -7
  183. package/Tests/Server/API/ProjectScopedCustomRouteAuth.test.ts +111 -4
  184. package/Tests/Server/API/PublicRouteInvalidAccessToken.test.ts +615 -0
  185. package/Tests/Server/API/SecurityEventAttributesAPI.test.ts +89 -2
  186. package/Tests/Server/API/SessionReplayAPI.test.ts +121 -0
  187. package/Tests/Server/API/SsoProviderListingsEdition.test.ts +432 -0
  188. package/Tests/Server/API/StatusPageMasterPasswordRateLimit.test.ts +4 -2
  189. package/Tests/Server/API/StatusPagePostmortemVisibility.test.ts +441 -0
  190. package/Tests/Server/API/StatusPageTestEmailReportAuth.test.ts +664 -0
  191. package/Tests/Server/API/TeamMemberLeaveScimLockEdition.test.ts +252 -0
  192. package/Tests/Server/API/TeamMemberRemoveUserFromProjectAPI.test.ts +7 -0
  193. package/Tests/Server/API/UserIncomingCallNumberApi.test.ts +6 -0
  194. package/Tests/Server/API/UserNotificationSettingAPI.test.ts +65 -4
  195. package/Tests/Server/API/UserProjectsAPI.test.ts +63 -3
  196. package/Tests/Server/API/UserTotpAuthAPI.test.ts +48 -2
  197. package/Tests/Server/API/UserWebAuthnAuthenticationOptionsRoute.test.ts +11 -2
  198. package/Tests/Server/API/UserWebAuthnBackupCodeMinting.test.ts +46 -3
  199. package/Tests/Server/API/UserWebAuthnPasskeyAPI.test.ts +18 -2
  200. package/Tests/Server/API/ZZVerifyChatsAuth.test.ts +24 -7
  201. package/Tests/Server/Enterprise/EnterpriseEdition.test.ts +824 -0
  202. package/Tests/Server/Enterprise/EnterpriseFeatureActive.test.ts +643 -0
  203. package/Tests/Server/Enterprise/EnterpriseLicenseSnapshot.test.ts +294 -0
  204. package/Tests/Server/Enterprise/EnterpriseModelFeatureMap.test.ts +93 -0
  205. package/Tests/Server/Enterprise/EnterpriseOnlyModulesLiveInEe.test.ts +582 -0
  206. package/Tests/Server/Enterprise/EnterpriseServerModule.test.ts +247 -0
  207. package/Tests/Server/Enterprise/FakeEnterpriseModule.ts +502 -0
  208. package/Tests/Server/Enterprise/TestBillingFlag.ts +70 -0
  209. package/Tests/Server/EnvironmentConfigEnterpriseEdition.test.ts +314 -0
  210. package/Tests/Server/Infrastructure/ContainerBootConfiguration.test.ts +289 -0
  211. package/Tests/Server/Infrastructure/E2EClickHouseFixtureAccess.test.ts +5 -1
  212. package/Tests/Server/Middleware/ExpiredSessionUserMiddleware.test.ts +563 -0
  213. package/Tests/Server/Middleware/MasterAdminAuthorization.test.ts +299 -19
  214. package/Tests/Server/Middleware/PublicRouteUserMiddleware.test.ts +453 -0
  215. package/Tests/Server/Middleware/UserAuthorization.test.ts +37 -2
  216. package/Tests/Server/Middleware/UserAuthorizationEditionEnforcement.test.ts +516 -0
  217. package/Tests/Server/Services/AIChatPrivacyPin.test.ts +24 -0
  218. package/Tests/Server/Services/ApiKeyPermissionSecurity.test.ts +2 -0
  219. package/Tests/Server/Services/ApiKeyPermissionService.test.ts +3 -3
  220. package/Tests/Server/Services/AuditLogService.test.ts +460 -990
  221. package/Tests/Server/Services/CreateAndReadResponsesKeepIds.test.ts +263 -0
  222. package/Tests/Server/Services/DatabaseServiceCreateSuppliedId.test.ts +147 -0
  223. package/Tests/Server/Services/DatabaseServiceLoginBeforeHooks.test.ts +1078 -0
  224. package/Tests/Server/Services/DatabaseServiceTenantRelationGuard.test.ts +259 -0
  225. package/Tests/Server/Services/DatabaseServiceWriteOperatorValues.test.ts +147 -0
  226. package/Tests/Server/Services/EnterpriseLicenseServiceKeyGeneration.test.ts +151 -0
  227. package/Tests/Server/Services/GlobalConfigServiceLicenseColumns.test.ts +357 -0
  228. package/Tests/Server/Services/MonitorDestinationInfoIPv6.test.ts +101 -0
  229. package/Tests/Server/Services/MonitorPayAsYouGoBilling.test.ts +115 -1
  230. package/Tests/Server/Services/MonitorProbeServiceIntervalScheduling.test.ts +333 -0
  231. package/Tests/Server/Services/MonitorStatusTimelineDailyAggregates.test.ts +303 -0
  232. package/Tests/Server/Services/OnCallChildCreateAuthorizationPostgres.test.ts +711 -0
  233. package/Tests/Server/Services/OnCallDutyPolicyChildService.test.ts +733 -0
  234. package/Tests/Server/Services/PayAsYouGoBillingService.test.ts +190 -140
  235. package/Tests/Server/Services/PayAsYouGoStripeRateLimitBudget.test.ts +4 -9
  236. package/Tests/Server/Services/PermissionBlockDeletion.test.ts +780 -0
  237. package/Tests/Server/Services/PermissionBlockDeletionPostgres.test.ts +628 -0
  238. package/Tests/Server/Services/ProjectServiceAuditLogLicense.test.ts +701 -0
  239. package/Tests/Server/Services/ProjectServiceAuditLogSettingsCache.test.ts +31 -35
  240. package/Tests/Server/Services/ProjectServiceCreateSubscriptionStarted.test.ts +77 -1
  241. package/Tests/Server/Services/RumSessionPinCreatePermission.test.ts +715 -0
  242. package/Tests/Server/Services/ScimPushGroupsTeamLocksEdition.test.ts +431 -0
  243. package/Tests/Server/Services/SsoRequirementReadMasking.test.ts +419 -0
  244. package/Tests/Server/Services/SsoRequirementWriteGuard.test.ts +769 -0
  245. package/Tests/Server/Services/StatusPagePrivateUserInvitationPolicy.test.ts +94 -0
  246. package/Tests/Server/Services/TeamMemberMultiTenantReadPostgres.test.ts +394 -0
  247. package/Tests/Server/Services/TeamPrivilegeEscalation.test.ts +6 -0
  248. package/Tests/Server/Services/TelemetryPayAsYouGoBilling.test.ts +131 -0
  249. package/Tests/Server/Services/UserAuthenticationService.test.ts +35 -0
  250. package/Tests/Server/Services/UserNotificationRuleAdminGuards.test.ts +13 -2
  251. package/Tests/Server/Services/UserServiceSeatLimit.test.ts +94 -56
  252. package/Tests/Server/Types/Database/Permissions/EditionPermission.test.ts +1823 -0
  253. package/Tests/Server/Types/Database/Permissions/ModelPermissionAnonymousRefusal.test.ts +518 -0
  254. package/Tests/Server/Types/Database/Permissions/MultiTenantPermissions.test.ts +350 -0
  255. package/Tests/Server/Types/Database/Permissions/OnCallCalendarFeedPermissions.test.ts +282 -25
  256. package/Tests/Server/Types/Database/Permissions/TableLevelBlockPermission.test.ts +459 -0
  257. package/Tests/Server/Types/Markdown.test.ts +181 -0
  258. package/Tests/Server/Utils/AI/AIRunPrivacyFilter.test.ts +101 -9
  259. package/Tests/Server/Utils/AI/ChatAgentHelpers.test.ts +88 -4
  260. package/Tests/Server/Utils/AI/Toolbox/ExceptionTools.test.ts +459 -0
  261. package/Tests/Server/Utils/AI/Toolbox/LogTools.test.ts +794 -0
  262. package/Tests/Server/Utils/AI/Toolbox/RecentChangesTools.test.ts +574 -0
  263. package/Tests/Server/Utils/AI/Toolbox/SecurityEventTools.test.ts +596 -0
  264. package/Tests/Server/Utils/CaptchaRequestAndLogging.test.ts +395 -0
  265. package/Tests/Server/Utils/CommunityEditionSsoReport.test.ts +565 -0
  266. package/Tests/Server/Utils/EditionEnforcement.test.ts +303 -0
  267. package/Tests/Server/Utils/FrontendEnvironment.test.ts +367 -0
  268. package/Tests/Server/Utils/InstanceHealth/RedisHealth.test.ts +38 -418
  269. package/Tests/Server/Utils/MasterAdminPageAccess.test.ts +251 -0
  270. package/Tests/Server/Utils/Monitor/AffectedResourceList.test.ts +518 -0
  271. package/Tests/Server/Utils/Monitor/Criteria/EvaluateOverTime.test.ts +24 -4
  272. package/Tests/Server/Utils/Monitor/MonitorActionTimestamps.test.ts +616 -0
  273. package/Tests/Server/Utils/Monitor/MonitorCriteriaEvaluator.test.ts +934 -96
  274. package/Tests/Server/Utils/Monitor/MonitoringIntervalValidator.test.ts +188 -0
  275. package/Tests/Server/Utils/Realtime.test.ts +502 -0
  276. package/Tests/Server/Utils/SecurityEvent/Connectors/GoogleSecOps/GoogleSecOpsConnectorSeverity.test.ts +216 -0
  277. package/Tests/Server/Utils/SecurityEvent/DetectionRuleEvaluator.test.ts +142 -0
  278. package/Tests/Server/Utils/SecurityEvent/GoogleSecOpsSeverityRepair.test.ts +140 -0
  279. package/Tests/Server/Utils/SecurityEvent/GoogleSecOpsSeverityRepairClickhouseIntegration.test.ts +542 -0
  280. package/Tests/Server/Utils/Telemetry/ChangeEventRow.test.ts +743 -0
  281. package/Tests/Server/Utils/Telemetry/RuntimeMetrics.test.ts +465 -0
  282. package/Tests/Server/Utils/Workspace/MicrosoftTeams/Messages/Alert.test.ts +202 -0
  283. package/Tests/Server/Utils/Workspace/MicrosoftTeams/Messages/Incident.test.ts +194 -0
  284. package/Tests/Server/Utils/Workspace/MicrosoftTeams/Messages/ScheduledMaintenance.test.ts +231 -0
  285. package/Tests/Server/Utils/Workspace/Slack/Messages/Alert.test.ts +194 -0
  286. package/Tests/Server/Utils/Workspace/Slack/Messages/AlertEpisode.test.ts +194 -0
  287. package/Tests/Server/Utils/Workspace/Slack/Messages/Incident.test.ts +194 -0
  288. package/Tests/Server/Utils/Workspace/Slack/Messages/IncidentEpisode.test.ts +194 -0
  289. package/Tests/Server/Utils/Workspace/Slack/Messages/ScheduledMaintenance.test.ts +247 -0
  290. package/Tests/Server/Utils/Workspace/Slack/SlackMarkdownSectionSplit.test.ts +1209 -0
  291. package/Tests/Types/AI/AIInsightEvidence.test.ts +206 -0
  292. package/Tests/Types/API/HostnameFromAuthority.test.ts +20 -10
  293. package/Tests/Types/API/HostnameIPv6.test.ts +149 -0
  294. package/Tests/Types/BaseDatabase/DatabaseCommonInteractionPropsUtilAnonymous.test.ts +144 -0
  295. package/Tests/Types/Call/CallProvider.test.ts +528 -0
  296. package/Tests/Types/Database/CanonicalModelInstance.test.ts +190 -0
  297. package/Tests/Types/Kubernetes/KubernetesCostIngest.test.ts +236 -0
  298. package/Tests/Types/OnCallDutyPolicy/ScheduleTimeline.test.ts +736 -0
  299. package/Tests/Types/OnCallDutyPolicy/ScheduleTimelineLayout.test.ts +996 -0
  300. package/Tests/Types/SecurityEvent/SigmaRule.test.ts +142 -0
  301. package/Tests/Types/Workflow/Components/JSON.test.ts +182 -0
  302. package/Tests/UI/Components/BasicFormDropdownNormalization.test.tsx +116 -1
  303. package/Tests/UI/Components/Dropdown/DropdownAsyncOptions.test.tsx +81 -0
  304. package/Tests/UI/Components/EditionLabelLapseCopy.ts +104 -0
  305. package/Tests/UI/Components/EditionLabelLicenseManagerWiring.test.tsx +254 -0
  306. package/Tests/UI/Components/EditionLabelLicenseRefresh.test.tsx +165 -171
  307. package/Tests/UI/Components/EditionLabelLicenseStatus.test.tsx +1586 -0
  308. package/Tests/UI/Components/EditionLabelLicenseWritesGuard.test.tsx +157 -0
  309. package/Tests/UI/Components/EventAttachmentList.test.tsx +174 -0
  310. package/Tests/UI/Components/Forms/BasicFormBurnRateTemplateDefaults.test.tsx +395 -0
  311. package/Tests/UI/Components/Forms/BasicFormCollapsibleSections.test.tsx +286 -0
  312. package/Tests/UI/Components/Forms/FormSummary.test.tsx +128 -0
  313. package/Tests/UI/Components/Graphs/DayUptimeGraph.test.tsx +49 -2
  314. package/Tests/UI/Components/MarkdownConverters.test.ts +684 -0
  315. package/Tests/UI/Components/ModelListEmptyState.test.tsx +289 -0
  316. package/Tests/UI/Components/ModelTable/BaseModelTableQueryChange.test.tsx +365 -0
  317. package/Tests/UI/Components/OpenAuthenticatedUrl.test.ts +358 -0
  318. package/Tests/UI/Components/SessionAwareImage.test.tsx +496 -0
  319. package/Tests/UI/Components/TelemetryHistogramZeroBuckets.test.tsx +190 -0
  320. package/Tests/UI/Components/TelemetryViewer/TelemetryViewerEmptyContent.test.tsx +131 -0
  321. package/Tests/UI/Components/TooltipInteractive.test.tsx +97 -0
  322. package/Tests/UI/EsbuildEnterpriseAlias.test.ts +1127 -0
  323. package/Tests/UI/MicrosoftTeams/MicrosoftTeamsChatsCardInstallGuidance.test.tsx +1 -1
  324. package/Tests/UI/Monitor/EvaluationLogListTimestamps.test.tsx +367 -0
  325. package/Tests/UI/Utils/API/BaseAPIRefreshSession.test.ts +1087 -0
  326. package/Tests/UI/Utils/API/DashboardHost.ts +12 -0
  327. package/Tests/UI/Utils/API/FakeAxiosServer.ts +183 -0
  328. package/Tests/UI/Utils/Breadcrumb/fixtures/RealBreadcrumbTrails.ts +10 -0
  329. package/Tests/UI/Utils/Breadcrumb/fixtures/RealRoutePatterns.ts +2 -0
  330. package/Tests/UI/Utils/Cookie.test.ts +440 -0
  331. package/Tests/UI/Utils/ModelAPIRequestClient.test.ts +278 -0
  332. package/Tests/UI/Utils/Navigation.test.ts +33 -0
  333. package/Tests/UI/Utils/PricingPlan.test.ts +295 -0
  334. package/Tests/UI/Utils/Realtime.test.ts +759 -0
  335. package/Tests/UI/Utils/Telemetry/Telemetry.test.ts +500 -0
  336. package/Tests/Utils/APIInstanceDispatch.test.ts +311 -0
  337. package/Tests/Utils/HostAddressUtil.test.ts +138 -0
  338. package/Tests/Utils/Monitor/MonitorDestinationUtil.test.ts +313 -0
  339. package/Tests/Utils/Monitor/MonitoringIntervalUtil.test.ts +304 -0
  340. package/Tests/Utils/SecurityEvent/GoogleSecOpsAlertNormalizerSeverity.test.ts +565 -0
  341. package/Tests/Utils/StatusPage/UptimeDailyAggregateUtil.test.ts +248 -0
  342. package/Types/API/Hostname.ts +63 -16
  343. package/Types/BaseDatabase/DatabaseCommonInteractionPropsUtil.ts +40 -0
  344. package/Types/Database/AccessControl/ColumnAccessControl.ts +19 -7
  345. package/Types/Database/AccessControl/ColumnBillingAccessControl.ts +19 -7
  346. package/Types/Database/AccessControl/OwnerOnlyColumn.ts +15 -6
  347. package/Types/Database/CanonicalModelInstance.ts +102 -0
  348. package/Types/Database/TableColumn.ts +20 -6
  349. package/Types/EnterpriseLicense/EnterpriseLicensePeriods.ts +29 -0
  350. package/Types/IP/IPv6.ts +6 -1
  351. package/Types/Monitor/MonitorEvaluationSummary.ts +3 -0
  352. package/Types/Monitor/MonitorStep.ts +6 -1
  353. package/Types/Monitor/ProxmoxAlertTemplates.ts +1 -1
  354. package/Types/OnCallDutyPolicy/ScheduleTimeline.ts +507 -0
  355. package/Types/OnCallDutyPolicy/ScheduleTimelineLayout.ts +589 -0
  356. package/Types/Realtime/EventName.ts +11 -0
  357. package/Types/SecurityEvent/DetectionFindingConstants.ts +14 -0
  358. package/Types/SecurityEvent/OcsfSeverity.ts +31 -26
  359. package/Types/SecurityEvent/SigmaRule.ts +51 -0
  360. package/Types/SecurityEvent/ThreatIntelConstants.ts +18 -0
  361. package/Types/StatusPage/UptimeDailyAggregate.ts +110 -0
  362. package/UI/Components/AttachmentList/EventAttachmentList.tsx +30 -2
  363. package/UI/Components/Dashboard/DashboardVariableControl.tsx +12 -2
  364. package/UI/Components/Dropdown/Dropdown.tsx +6 -1
  365. package/UI/Components/EditionLabel/EditionLabel.tsx +808 -1195
  366. package/UI/Components/EditionLabel/LicenseManager.ts +119 -0
  367. package/UI/Components/EventItem/EventItem.tsx +12 -1
  368. package/UI/Components/Forms/BasicForm.tsx +151 -126
  369. package/UI/Components/Forms/CollapsibleFormSection.tsx +63 -0
  370. package/UI/Components/Forms/Fields/FormField.tsx +10 -4
  371. package/UI/Components/Forms/FormSummary.tsx +7 -0
  372. package/UI/Components/Forms/Types/Field.ts +10 -0
  373. package/UI/Components/Graphs/DayUptimeGraph.tsx +123 -15
  374. package/UI/Components/Markdown.tsx/MarkdownConverters.ts +0 -0
  375. package/UI/Components/Markdown.tsx/MarkdownViewer.tsx +2 -1
  376. package/UI/Components/Markdown.tsx/SessionAwareImage.tsx +122 -0
  377. package/UI/Components/ModelList/ModelList.tsx +11 -1
  378. package/UI/Components/ModelTable/BaseModelTable.tsx +34 -5
  379. package/UI/Components/ModelTable/TableView.tsx +1 -1
  380. package/UI/Components/MonitorGraphs/Uptime.tsx +69 -0
  381. package/UI/Components/TelemetryViewer/TelemetryViewer.tsx +28 -12
  382. package/UI/Components/TelemetryViewer/components/TelemetryHistogram.tsx +8 -1
  383. package/UI/Components/Tooltip/Tooltip.tsx +8 -1
  384. package/UI/Utils/API/API.ts +173 -12
  385. package/UI/Utils/API/RequestOptions.ts +11 -0
  386. package/UI/Utils/AnalyticsModelAPI/AnalyticsModelAPI.ts +31 -7
  387. package/UI/Utils/ModelAPI/ModelAPI.ts +30 -9
  388. package/UI/Utils/Navigation.ts +9 -0
  389. package/UI/Utils/OpenAuthenticatedUrl.ts +154 -0
  390. package/UI/Utils/Realtime.ts +176 -30
  391. package/UI/esbuild-enterprise.js +263 -0
  392. package/Utils/API.ts +14 -5
  393. package/Utils/EnterpriseLicense/EnterpriseLicenseUsage.ts +7 -2
  394. package/Utils/HostAddressUtil.ts +94 -0
  395. package/Utils/Monitor/MonitorDestinationUtil.ts +157 -0
  396. package/Utils/Monitor/MonitoringIntervalUtil.ts +436 -0
  397. package/Utils/SecurityEvent/GoogleSecOpsAlertNormalizer.ts +157 -7
  398. package/Utils/SecurityEvent/Sigma/SigmaRuleParser.ts +9 -17
  399. package/Utils/Slo/SloBurnRateTemplate.ts +2 -2
  400. package/Utils/StatusPage/UptimeDailyAggregateUtil.ts +192 -0
  401. package/build/dist/Models/AnalyticsModels/AuditLog.js +23 -15
  402. package/build/dist/Models/AnalyticsModels/AuditLog.js.map +1 -1
  403. package/build/dist/Models/DatabaseModels/GlobalConfig.js +25 -0
  404. package/build/dist/Models/DatabaseModels/GlobalConfig.js.map +1 -1
  405. package/build/dist/Models/DatabaseModels/Monitor.js +2 -2
  406. package/build/dist/Models/DatabaseModels/Monitor.js.map +1 -1
  407. package/build/dist/Models/DatabaseModels/MonitorTemplate.js +2 -1
  408. package/build/dist/Models/DatabaseModels/MonitorTemplate.js.map +1 -1
  409. package/build/dist/Models/DatabaseModels/OnCallDutyPolicyScheduleCalendarFeed.js +1 -1
  410. package/build/dist/Models/DatabaseModels/OnCallDutyPolicyScheduleCalendarFeed.js.map +1 -1
  411. package/build/dist/Models/DatabaseModels/ProjectOnCallCalendarFeed.js +1 -1
  412. package/build/dist/Models/DatabaseModels/ProjectOnCallCalendarFeed.js.map +1 -1
  413. package/build/dist/Models/DatabaseModels/UserOnCallCalendarFeed.js +1 -1
  414. package/build/dist/Models/DatabaseModels/UserOnCallCalendarFeed.js.map +1 -1
  415. package/build/dist/Server/API/AIBillingAPI.js +1 -1
  416. package/build/dist/Server/API/AIBillingAPI.js.map +1 -1
  417. package/build/dist/Server/API/AIInsightAPI.js +1 -4
  418. package/build/dist/Server/API/AIInsightAPI.js.map +1 -1
  419. package/build/dist/Server/API/AIInvestigationAPI.js +1 -4
  420. package/build/dist/Server/API/AIInvestigationAPI.js.map +1 -1
  421. package/build/dist/Server/API/AIReadinessAPI.js +1 -3
  422. package/build/dist/Server/API/AIReadinessAPI.js.map +1 -1
  423. package/build/dist/Server/API/AlertAPI.js +1 -1
  424. package/build/dist/Server/API/AlertAPI.js.map +1 -1
  425. package/build/dist/Server/API/AutoRemediationAPI.js +1 -4
  426. package/build/dist/Server/API/AutoRemediationAPI.js.map +1 -1
  427. package/build/dist/Server/API/BaseAPI.js +33 -0
  428. package/build/dist/Server/API/BaseAPI.js.map +1 -1
  429. package/build/dist/Server/API/BaseAnalyticsAPI.js +55 -10
  430. package/build/dist/Server/API/BaseAnalyticsAPI.js.map +1 -1
  431. package/build/dist/Server/API/BillingAPI.js +2 -2
  432. package/build/dist/Server/API/BillingAPI.js.map +1 -1
  433. package/build/dist/Server/API/BillingInvoiceAPI.js +1 -1
  434. package/build/dist/Server/API/BillingInvoiceAPI.js.map +1 -1
  435. package/build/dist/Server/API/BillingPaymentMethodAPI.js +2 -2
  436. package/build/dist/Server/API/BillingPaymentMethodAPI.js.map +1 -1
  437. package/build/dist/Server/API/CodeFixRunAPI.js +1 -3
  438. package/build/dist/Server/API/CodeFixRunAPI.js.map +1 -1
  439. package/build/dist/Server/API/CommonAPI.js +50 -5
  440. package/build/dist/Server/API/CommonAPI.js.map +1 -1
  441. package/build/dist/Server/API/DashboardAPI.js +12 -12
  442. package/build/dist/Server/API/DashboardAPI.js.map +1 -1
  443. package/build/dist/Server/API/GlobalConfigAPI.js +158 -342
  444. package/build/dist/Server/API/GlobalConfigAPI.js.map +1 -1
  445. package/build/dist/Server/API/IncidentAPI.js +2 -2
  446. package/build/dist/Server/API/IncidentAPI.js.map +1 -1
  447. package/build/dist/Server/API/IncidentEpisodeAPI.js +1 -1
  448. package/build/dist/Server/API/IncidentEpisodeAPI.js.map +1 -1
  449. package/build/dist/Server/API/NotificationAPI.js +1 -1
  450. package/build/dist/Server/API/NotificationAPI.js.map +1 -1
  451. package/build/dist/Server/API/OnCallCalendarAPI.js +1 -4
  452. package/build/dist/Server/API/OnCallCalendarAPI.js.map +1 -1
  453. package/build/dist/Server/API/OnCallDutyPolicyAPI.js +6 -0
  454. package/build/dist/Server/API/OnCallDutyPolicyAPI.js.map +1 -1
  455. package/build/dist/Server/API/OnCallReadinessAPI.js +4 -1
  456. package/build/dist/Server/API/OnCallReadinessAPI.js.map +1 -1
  457. package/build/dist/Server/API/OnCallScheduleTimelineAPI.js +494 -0
  458. package/build/dist/Server/API/OnCallScheduleTimelineAPI.js.map +1 -0
  459. package/build/dist/Server/API/ProjectAPI.js +1 -1
  460. package/build/dist/Server/API/ProjectAPI.js.map +1 -1
  461. package/build/dist/Server/API/ProjectOIDC.js +24 -16
  462. package/build/dist/Server/API/ProjectOIDC.js.map +1 -1
  463. package/build/dist/Server/API/ProjectSSO.js +24 -16
  464. package/build/dist/Server/API/ProjectSSO.js.map +1 -1
  465. package/build/dist/Server/API/ScheduledMaintenanceAPI.js +1 -1
  466. package/build/dist/Server/API/ScheduledMaintenanceAPI.js.map +1 -1
  467. package/build/dist/Server/API/StatusPageAPI.js +218 -76
  468. package/build/dist/Server/API/StatusPageAPI.js.map +1 -1
  469. package/build/dist/Server/API/TeamMemberAPI.js +11 -4
  470. package/build/dist/Server/API/TeamMemberAPI.js.map +1 -1
  471. package/build/dist/Server/API/UserCallAPI.js +2 -2
  472. package/build/dist/Server/API/UserCallAPI.js.map +1 -1
  473. package/build/dist/Server/API/UserEmailAPI.js +2 -2
  474. package/build/dist/Server/API/UserEmailAPI.js.map +1 -1
  475. package/build/dist/Server/API/UserIncomingCallNumberAPI.js +2 -2
  476. package/build/dist/Server/API/UserIncomingCallNumberAPI.js.map +1 -1
  477. package/build/dist/Server/API/UserMicrosoftTeamsAPI.js +1 -1
  478. package/build/dist/Server/API/UserMicrosoftTeamsAPI.js.map +1 -1
  479. package/build/dist/Server/API/UserSlackAPI.js +1 -1
  480. package/build/dist/Server/API/UserSlackAPI.js.map +1 -1
  481. package/build/dist/Server/API/UserSmsAPI.js +2 -2
  482. package/build/dist/Server/API/UserSmsAPI.js.map +1 -1
  483. package/build/dist/Server/API/UserTotpAuthAPI.js +1 -1
  484. package/build/dist/Server/API/UserTotpAuthAPI.js.map +1 -1
  485. package/build/dist/Server/API/UserWebAuthnAPI.js +2 -2
  486. package/build/dist/Server/API/UserWebAuthnAPI.js.map +1 -1
  487. package/build/dist/Server/API/UserWebhookAPI.js +1 -1
  488. package/build/dist/Server/API/UserWebhookAPI.js.map +1 -1
  489. package/build/dist/Server/API/UserWhatsAppAPI.js +2 -2
  490. package/build/dist/Server/API/UserWhatsAppAPI.js.map +1 -1
  491. package/build/dist/Server/Enterprise/EnterpriseEdition.js +466 -0
  492. package/build/dist/Server/Enterprise/EnterpriseEdition.js.map +1 -0
  493. package/build/dist/Server/Enterprise/EnterpriseFeature.js +39 -0
  494. package/build/dist/Server/Enterprise/EnterpriseFeature.js.map +1 -0
  495. package/build/dist/Server/Enterprise/EnterpriseLicenseSnapshot.js +70 -0
  496. package/build/dist/Server/Enterprise/EnterpriseLicenseSnapshot.js.map +1 -0
  497. package/build/dist/Server/Enterprise/EnterpriseServerModule.js +84 -0
  498. package/build/dist/Server/Enterprise/EnterpriseServerModule.js.map +1 -0
  499. package/build/dist/Server/EnvironmentConfig.js +84 -2
  500. package/build/dist/Server/EnvironmentConfig.js.map +1 -1
  501. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1793900000000-AddEnterpriseEditionFirstSeenAt.js +18 -0
  502. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1793900000000-AddEnterpriseEditionFirstSeenAt.js.map +1 -0
  503. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +2 -0
  504. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  505. package/build/dist/Server/Middleware/MasterAdminAuthorization.js +11 -2
  506. package/build/dist/Server/Middleware/MasterAdminAuthorization.js.map +1 -1
  507. package/build/dist/Server/Middleware/UserAuthorization.js +94 -15
  508. package/build/dist/Server/Middleware/UserAuthorization.js.map +1 -1
  509. package/build/dist/Server/Services/ApiKeyPermissionService.js +80 -4
  510. package/build/dist/Server/Services/ApiKeyPermissionService.js.map +1 -1
  511. package/build/dist/Server/Services/AuditLogService.js +71 -740
  512. package/build/dist/Server/Services/AuditLogService.js.map +1 -1
  513. package/build/dist/Server/Services/DatabaseService.js +171 -0
  514. package/build/dist/Server/Services/DatabaseService.js.map +1 -1
  515. package/build/dist/Server/Services/DetectionRuleService.js +4 -4
  516. package/build/dist/Server/Services/DetectionRuleService.js.map +1 -1
  517. package/build/dist/Server/Services/EnterpriseLicenseService.js +34 -0
  518. package/build/dist/Server/Services/EnterpriseLicenseService.js.map +1 -1
  519. package/build/dist/Server/Services/GlobalConfigService.js +63 -0
  520. package/build/dist/Server/Services/GlobalConfigService.js.map +1 -1
  521. package/build/dist/Server/Services/MonitorProbeService.js +90 -17
  522. package/build/dist/Server/Services/MonitorProbeService.js.map +1 -1
  523. package/build/dist/Server/Services/MonitorService.js +45 -4
  524. package/build/dist/Server/Services/MonitorService.js.map +1 -1
  525. package/build/dist/Server/Services/MonitorStatusTimelineService.js +242 -0
  526. package/build/dist/Server/Services/MonitorStatusTimelineService.js.map +1 -1
  527. package/build/dist/Server/Services/MonitorTemplateService.js +16 -0
  528. package/build/dist/Server/Services/MonitorTemplateService.js.map +1 -1
  529. package/build/dist/Server/Services/OnCallDutyPolicyChildService.js +170 -0
  530. package/build/dist/Server/Services/OnCallDutyPolicyChildService.js.map +1 -0
  531. package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleScheduleService.js +2 -2
  532. package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleScheduleService.js.map +1 -1
  533. package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleService.js +2 -2
  534. package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleService.js.map +1 -1
  535. package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleTeamService.js +2 -2
  536. package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleTeamService.js.map +1 -1
  537. package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleUserService.js +2 -2
  538. package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleUserService.js.map +1 -1
  539. package/build/dist/Server/Services/PayAsYouGoBillingService.js +20 -27
  540. package/build/dist/Server/Services/PayAsYouGoBillingService.js.map +1 -1
  541. package/build/dist/Server/Services/ProjectService.js +231 -0
  542. package/build/dist/Server/Services/ProjectService.js.map +1 -1
  543. package/build/dist/Server/Services/RumSessionPinService.js +198 -16
  544. package/build/dist/Server/Services/RumSessionPinService.js.map +1 -1
  545. package/build/dist/Server/Services/StatusPagePrivateUserService.js +7 -3
  546. package/build/dist/Server/Services/StatusPagePrivateUserService.js.map +1 -1
  547. package/build/dist/Server/Services/StatusPageService.js +71 -0
  548. package/build/dist/Server/Services/StatusPageService.js.map +1 -1
  549. package/build/dist/Server/Services/TeamMemberService.js +10 -0
  550. package/build/dist/Server/Services/TeamMemberService.js.map +1 -1
  551. package/build/dist/Server/Services/TeamPermissionService.js +89 -27
  552. package/build/dist/Server/Services/TeamPermissionService.js.map +1 -1
  553. package/build/dist/Server/Services/TeamService.js +9 -0
  554. package/build/dist/Server/Services/TeamService.js.map +1 -1
  555. package/build/dist/Server/Services/ThreatIntelFeedService.js +5 -4
  556. package/build/dist/Server/Services/ThreatIntelFeedService.js.map +1 -1
  557. package/build/dist/Server/Services/UserService.js +10 -16
  558. package/build/dist/Server/Services/UserService.js.map +1 -1
  559. package/build/dist/Server/Types/Database/Permissions/BasePermission.js +9 -6
  560. package/build/dist/Server/Types/Database/Permissions/BasePermission.js.map +1 -1
  561. package/build/dist/Server/Types/Database/Permissions/CreatePermission.js +10 -0
  562. package/build/dist/Server/Types/Database/Permissions/CreatePermission.js.map +1 -1
  563. package/build/dist/Server/Types/Database/Permissions/EditionPermission.js +154 -14
  564. package/build/dist/Server/Types/Database/Permissions/EditionPermission.js.map +1 -1
  565. package/build/dist/Server/Types/Database/Permissions/Index.js +60 -6
  566. package/build/dist/Server/Types/Database/Permissions/Index.js.map +1 -1
  567. package/build/dist/Server/Types/Database/Permissions/TablePermission.js +24 -16
  568. package/build/dist/Server/Types/Database/Permissions/TablePermission.js.map +1 -1
  569. package/build/dist/Server/Types/Database/Permissions/UpdatePermission.js +17 -0
  570. package/build/dist/Server/Types/Database/Permissions/UpdatePermission.js.map +1 -1
  571. package/build/dist/Server/Types/Markdown.js +31 -0
  572. package/build/dist/Server/Types/Markdown.js.map +1 -1
  573. package/build/dist/Server/Utils/AI/AIChatPrivacyFilter.js +7 -0
  574. package/build/dist/Server/Utils/AI/AIChatPrivacyFilter.js.map +1 -1
  575. package/build/dist/Server/Utils/AI/AIRunPrivacyFilter.js +7 -0
  576. package/build/dist/Server/Utils/AI/AIRunPrivacyFilter.js.map +1 -1
  577. package/build/dist/Server/Utils/CommunityEditionSsoReport.js +223 -0
  578. package/build/dist/Server/Utils/CommunityEditionSsoReport.js.map +1 -0
  579. package/build/dist/Server/Utils/EditionEnforcement.js +187 -0
  580. package/build/dist/Server/Utils/EditionEnforcement.js.map +1 -0
  581. package/build/dist/Server/Utils/FrontendEnvironment.js +31 -2
  582. package/build/dist/Server/Utils/FrontendEnvironment.js.map +1 -1
  583. package/build/dist/Server/Utils/InstanceHealth/RedisHealth.js +6 -193
  584. package/build/dist/Server/Utils/InstanceHealth/RedisHealth.js.map +1 -1
  585. package/build/dist/Server/Utils/MasterAdminPageAccess.js +39 -0
  586. package/build/dist/Server/Utils/MasterAdminPageAccess.js.map +1 -0
  587. package/build/dist/Server/Utils/Monitor/AffectedResourceList.js +96 -0
  588. package/build/dist/Server/Utils/Monitor/AffectedResourceList.js.map +1 -0
  589. package/build/dist/Server/Utils/Monitor/Criteria/EvaluateOverTime.js +8 -1
  590. package/build/dist/Server/Utils/Monitor/Criteria/EvaluateOverTime.js.map +1 -1
  591. package/build/dist/Server/Utils/Monitor/MonitorAlert.js +3 -1
  592. package/build/dist/Server/Utils/Monitor/MonitorAlert.js.map +1 -1
  593. package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js +449 -261
  594. package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js.map +1 -1
  595. package/build/dist/Server/Utils/Monitor/MonitorIncident.js +3 -1
  596. package/build/dist/Server/Utils/Monitor/MonitorIncident.js.map +1 -1
  597. package/build/dist/Server/Utils/Monitor/MonitoringIntervalValidator.js +88 -0
  598. package/build/dist/Server/Utils/Monitor/MonitoringIntervalValidator.js.map +1 -0
  599. package/build/dist/Server/Utils/Realtime.js +126 -37
  600. package/build/dist/Server/Utils/Realtime.js.map +1 -1
  601. package/build/dist/Server/Utils/SecurityEvent/DetectionRuleEvaluator.js +7 -25
  602. package/build/dist/Server/Utils/SecurityEvent/DetectionRuleEvaluator.js.map +1 -1
  603. package/build/dist/Server/Utils/SecurityEvent/GoogleSecOpsSeverityRepair.js +127 -0
  604. package/build/dist/Server/Utils/SecurityEvent/GoogleSecOpsSeverityRepair.js.map +1 -0
  605. package/build/dist/Server/Utils/SecurityEvent/Sigma/SigmaClickhouseCompiler.js +1 -1
  606. package/build/dist/Server/Utils/SecurityEvent/Sigma/SigmaClickhouseCompiler.js.map +1 -1
  607. package/build/dist/Server/Utils/SecurityEvent/ThreatIntel/ThreatIntelFeedPoller.js +3 -2
  608. package/build/dist/Server/Utils/SecurityEvent/ThreatIntel/ThreatIntelFeedPoller.js.map +1 -1
  609. package/build/dist/Server/Utils/SecurityEvent/ThreatIntel/ThreatIntelMatcher.js +4 -8
  610. package/build/dist/Server/Utils/SecurityEvent/ThreatIntel/ThreatIntelMatcher.js.map +1 -1
  611. package/build/dist/Server/Utils/Workspace/Slack/Slack.js +331 -11
  612. package/build/dist/Server/Utils/Workspace/Slack/Slack.js.map +1 -1
  613. package/build/dist/Types/API/Hostname.js +59 -11
  614. package/build/dist/Types/API/Hostname.js.map +1 -1
  615. package/build/dist/Types/BaseDatabase/DatabaseCommonInteractionPropsUtil.js +31 -1
  616. package/build/dist/Types/BaseDatabase/DatabaseCommonInteractionPropsUtil.js.map +1 -1
  617. package/build/dist/Types/Database/AccessControl/ColumnAccessControl.js +19 -7
  618. package/build/dist/Types/Database/AccessControl/ColumnAccessControl.js.map +1 -1
  619. package/build/dist/Types/Database/AccessControl/ColumnBillingAccessControl.js +19 -7
  620. package/build/dist/Types/Database/AccessControl/ColumnBillingAccessControl.js.map +1 -1
  621. package/build/dist/Types/Database/AccessControl/OwnerOnlyColumn.js +13 -6
  622. package/build/dist/Types/Database/AccessControl/OwnerOnlyColumn.js.map +1 -1
  623. package/build/dist/Types/Database/CanonicalModelInstance.js +88 -0
  624. package/build/dist/Types/Database/CanonicalModelInstance.js.map +1 -0
  625. package/build/dist/Types/Database/TableColumn.js +19 -6
  626. package/build/dist/Types/Database/TableColumn.js.map +1 -1
  627. package/build/dist/Types/EnterpriseLicense/EnterpriseLicensePeriods.js +28 -0
  628. package/build/dist/Types/EnterpriseLicense/EnterpriseLicensePeriods.js.map +1 -0
  629. package/build/dist/Types/IP/IPv6.js +6 -1
  630. package/build/dist/Types/IP/IPv6.js.map +1 -1
  631. package/build/dist/Types/Monitor/MonitorStep.js +5 -0
  632. package/build/dist/Types/Monitor/MonitorStep.js.map +1 -1
  633. package/build/dist/Types/Monitor/ProxmoxAlertTemplates.js +1 -1
  634. package/build/dist/Types/OnCallDutyPolicy/ScheduleTimeline.js +321 -0
  635. package/build/dist/Types/OnCallDutyPolicy/ScheduleTimeline.js.map +1 -0
  636. package/build/dist/Types/OnCallDutyPolicy/ScheduleTimelineLayout.js +372 -0
  637. package/build/dist/Types/OnCallDutyPolicy/ScheduleTimelineLayout.js.map +1 -0
  638. package/build/dist/Types/Realtime/EventName.js +10 -0
  639. package/build/dist/Types/Realtime/EventName.js.map +1 -1
  640. package/build/dist/Types/SecurityEvent/DetectionFindingConstants.js +11 -0
  641. package/build/dist/Types/SecurityEvent/DetectionFindingConstants.js.map +1 -1
  642. package/build/dist/Types/SecurityEvent/OcsfSeverity.js +30 -25
  643. package/build/dist/Types/SecurityEvent/OcsfSeverity.js.map +1 -1
  644. package/build/dist/Types/SecurityEvent/SigmaRule.js +47 -0
  645. package/build/dist/Types/SecurityEvent/SigmaRule.js.map +1 -1
  646. package/build/dist/Types/SecurityEvent/ThreatIntelConstants.js +14 -0
  647. package/build/dist/Types/SecurityEvent/ThreatIntelConstants.js.map +1 -1
  648. package/build/dist/Types/StatusPage/UptimeDailyAggregate.js +32 -0
  649. package/build/dist/Types/StatusPage/UptimeDailyAggregate.js.map +1 -0
  650. package/build/dist/UI/Components/AttachmentList/EventAttachmentList.js +9 -4
  651. package/build/dist/UI/Components/AttachmentList/EventAttachmentList.js.map +1 -1
  652. package/build/dist/UI/Components/Dashboard/DashboardVariableControl.js +10 -2
  653. package/build/dist/UI/Components/Dashboard/DashboardVariableControl.js.map +1 -1
  654. package/build/dist/UI/Components/Dropdown/Dropdown.js +5 -1
  655. package/build/dist/UI/Components/Dropdown/Dropdown.js.map +1 -1
  656. package/build/dist/UI/Components/EditionLabel/EditionLabel.js +425 -585
  657. package/build/dist/UI/Components/EditionLabel/EditionLabel.js.map +1 -1
  658. package/build/dist/UI/Components/EditionLabel/LicenseManager.js +2 -0
  659. package/build/dist/UI/Components/EditionLabel/LicenseManager.js.map +1 -0
  660. package/build/dist/UI/Components/EventItem/EventItem.js +2 -2
  661. package/build/dist/UI/Components/EventItem/EventItem.js.map +1 -1
  662. package/build/dist/UI/Components/Forms/BasicForm.js +70 -64
  663. package/build/dist/UI/Components/Forms/BasicForm.js.map +1 -1
  664. package/build/dist/UI/Components/Forms/CollapsibleFormSection.js +27 -0
  665. package/build/dist/UI/Components/Forms/CollapsibleFormSection.js.map +1 -0
  666. package/build/dist/UI/Components/Forms/Fields/FormField.js +10 -7
  667. package/build/dist/UI/Components/Forms/Fields/FormField.js.map +1 -1
  668. package/build/dist/UI/Components/Forms/FormSummary.js +7 -0
  669. package/build/dist/UI/Components/Forms/FormSummary.js.map +1 -1
  670. package/build/dist/UI/Components/Graphs/DayUptimeGraph.js +90 -17
  671. package/build/dist/UI/Components/Graphs/DayUptimeGraph.js.map +1 -1
  672. package/build/dist/UI/Components/Markdown.tsx/MarkdownConverters.js +0 -0
  673. package/build/dist/UI/Components/Markdown.tsx/MarkdownConverters.js.map +1 -1
  674. package/build/dist/UI/Components/Markdown.tsx/MarkdownViewer.js +2 -1
  675. package/build/dist/UI/Components/Markdown.tsx/MarkdownViewer.js.map +1 -1
  676. package/build/dist/UI/Components/Markdown.tsx/SessionAwareImage.js +84 -0
  677. package/build/dist/UI/Components/Markdown.tsx/SessionAwareImage.js.map +1 -0
  678. package/build/dist/UI/Components/ModelList/ModelList.js +4 -1
  679. package/build/dist/UI/Components/ModelList/ModelList.js.map +1 -1
  680. package/build/dist/UI/Components/ModelTable/BaseModelTable.js +14 -1
  681. package/build/dist/UI/Components/ModelTable/BaseModelTable.js.map +1 -1
  682. package/build/dist/UI/Components/ModelTable/TableView.js +1 -1
  683. package/build/dist/UI/Components/ModelTable/TableView.js.map +1 -1
  684. package/build/dist/UI/Components/MonitorGraphs/Uptime.js +42 -1
  685. package/build/dist/UI/Components/MonitorGraphs/Uptime.js.map +1 -1
  686. package/build/dist/UI/Components/TelemetryViewer/TelemetryViewer.js +2 -2
  687. package/build/dist/UI/Components/TelemetryViewer/TelemetryViewer.js.map +1 -1
  688. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryHistogram.js +8 -1
  689. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryHistogram.js.map +1 -1
  690. package/build/dist/UI/Components/Tooltip/Tooltip.js +2 -1
  691. package/build/dist/UI/Components/Tooltip/Tooltip.js.map +1 -1
  692. package/build/dist/UI/Utils/API/API.js +143 -19
  693. package/build/dist/UI/Utils/API/API.js.map +1 -1
  694. package/build/dist/UI/Utils/AnalyticsModelAPI/AnalyticsModelAPI.js +21 -7
  695. package/build/dist/UI/Utils/AnalyticsModelAPI/AnalyticsModelAPI.js.map +1 -1
  696. package/build/dist/UI/Utils/ModelAPI/ModelAPI.js +26 -9
  697. package/build/dist/UI/Utils/ModelAPI/ModelAPI.js.map +1 -1
  698. package/build/dist/UI/Utils/Navigation.js +8 -0
  699. package/build/dist/UI/Utils/Navigation.js.map +1 -1
  700. package/build/dist/UI/Utils/OpenAuthenticatedUrl.js +92 -0
  701. package/build/dist/UI/Utils/OpenAuthenticatedUrl.js.map +1 -0
  702. package/build/dist/UI/Utils/Realtime.js +120 -15
  703. package/build/dist/UI/Utils/Realtime.js.map +1 -1
  704. package/build/dist/Utils/API.js +13 -5
  705. package/build/dist/Utils/API.js.map +1 -1
  706. package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseUsage.js +6 -2
  707. package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseUsage.js.map +1 -1
  708. package/build/dist/Utils/HostAddressUtil.js +80 -0
  709. package/build/dist/Utils/HostAddressUtil.js.map +1 -0
  710. package/build/dist/Utils/Monitor/MonitorDestinationUtil.js +127 -0
  711. package/build/dist/Utils/Monitor/MonitorDestinationUtil.js.map +1 -0
  712. package/build/dist/Utils/Monitor/MonitoringIntervalUtil.js +374 -0
  713. package/build/dist/Utils/Monitor/MonitoringIntervalUtil.js.map +1 -0
  714. package/build/dist/Utils/SecurityEvent/GoogleSecOpsAlertNormalizer.js +123 -6
  715. package/build/dist/Utils/SecurityEvent/GoogleSecOpsAlertNormalizer.js.map +1 -1
  716. package/build/dist/Utils/SecurityEvent/Sigma/SigmaRuleParser.js +4 -18
  717. package/build/dist/Utils/SecurityEvent/Sigma/SigmaRuleParser.js.map +1 -1
  718. package/build/dist/Utils/Slo/SloBurnRateTemplate.js +2 -2
  719. package/build/dist/Utils/StatusPage/UptimeDailyAggregateUtil.js +148 -0
  720. package/build/dist/Utils/StatusPage/UptimeDailyAggregateUtil.js.map +1 -0
  721. package/jest.config.json +3 -1
  722. package/package.json +1 -1
  723. package/test-setup.sh +103 -34
  724. package/tsconfig.json +13 -0
  725. package/Server/API/EnterpriseLicenseAPI.ts +0 -925
  726. package/Server/API/TeamComplianceAPI.ts +0 -158
  727. package/Server/Middleware/SCIMAuthorization.ts +0 -141
  728. package/Server/Services/TeamComplianceService.ts +0 -733
  729. package/Server/Utils/EnterpriseLicense/EnterpriseLicenseSeatUtil.ts +0 -186
  730. package/Server/Utils/InstanceHealth/PostgresHealth.ts +0 -286
  731. package/Tests/App/AdminDashboard/EnterpriseLicenseInstanceActivity.test.tsx +0 -451
  732. package/Tests/App/Dashboard/AuditLogsTable.test.tsx +0 -598
  733. package/Tests/App/Dashboard/SecurityEventsSideMenu.test.tsx +0 -247
  734. package/Tests/App/Dashboard/SecurityEventsTableColumns.test.tsx +0 -382
  735. package/Tests/Server/API/EnterpriseLicenseReportUserCount.test.ts +0 -1851
  736. package/Tests/Server/Middleware/SCIMAuthorization.test.ts +0 -525
  737. package/Tests/Server/Services/TeamComplianceServiceBehaviour.test.ts +0 -1845
  738. package/Tests/Server/Utils/EnterpriseLicense/EnterpriseLicenseSeatUtil.test.ts +0 -495
  739. package/Tests/Server/Utils/InstanceHealth/PostgresHealth.test.ts +0 -337
  740. package/Tests/Utils/EnterpriseLicenseSeats.test.ts +0 -576
  741. package/Tests/Utils/EnterpriseLicenseSync.test.ts +0 -568
  742. package/Utils/EnterpriseLicense/EnterpriseLicenseSeats.ts +0 -287
  743. package/Utils/EnterpriseLicense/EnterpriseLicenseSync.ts +0 -244
  744. package/build/dist/Server/API/EnterpriseLicenseAPI.js +0 -646
  745. package/build/dist/Server/API/EnterpriseLicenseAPI.js.map +0 -1
  746. package/build/dist/Server/API/TeamComplianceAPI.js +0 -111
  747. package/build/dist/Server/API/TeamComplianceAPI.js.map +0 -1
  748. package/build/dist/Server/Middleware/SCIMAuthorization.js +0 -124
  749. package/build/dist/Server/Middleware/SCIMAuthorization.js.map +0 -1
  750. package/build/dist/Server/Services/TeamComplianceService.js +0 -537
  751. package/build/dist/Server/Services/TeamComplianceService.js.map +0 -1
  752. package/build/dist/Server/Utils/EnterpriseLicense/EnterpriseLicenseSeatUtil.js +0 -145
  753. package/build/dist/Server/Utils/EnterpriseLicense/EnterpriseLicenseSeatUtil.js.map +0 -1
  754. package/build/dist/Server/Utils/InstanceHealth/PostgresHealth.js +0 -194
  755. package/build/dist/Server/Utils/InstanceHealth/PostgresHealth.js.map +0 -1
  756. package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseSeats.js +0 -168
  757. package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseSeats.js.map +0 -1
  758. package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseSync.js +0 -174
  759. package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseSync.js.map +0 -1
@@ -1,100 +1,84 @@
1
1
  import ClickhouseDatabase from "../Infrastructure/ClickhouseDatabase";
2
2
  import AnalyticsDatabaseService from "./AnalyticsDatabaseService";
3
- import DatabaseService from "./DatabaseService";
4
- import ProjectService from "./ProjectService";
5
- import { IsBillingEnabled, IsEnterpriseEdition } from "../EnvironmentConfig";
6
- import Query from "../Types/Database/Query";
7
- import QueryHelper from "../Types/Database/QueryHelper";
8
- import Select from "../Types/Database/Select";
9
- import RelationValueUtil from "../Utils/Database/RelationValueUtil";
3
+ import EnterpriseEdition from "../Enterprise/EnterpriseEdition";
4
+ import { AuditLogRecorder } from "../Enterprise/EnterpriseServerModule";
5
+ import CreateManyBy from "../Types/AnalyticsDatabase/CreateManyBy";
10
6
  import logger from "../Utils/Logger";
11
7
  import AuditLog from "../../Models/AnalyticsModels/AuditLog";
12
8
  import BaseModel from "../../Models/DatabaseModels/DatabaseBaseModel/DatabaseBaseModel";
13
- import Project from "../../Models/DatabaseModels/Project";
14
- import User from "../../Models/DatabaseModels/User";
15
- import AuditLogAction from "../../Types/AuditLog/AuditLogAction";
16
9
  import DatabaseCommonInteractionProps from "../../Types/BaseDatabase/DatabaseCommonInteractionProps";
17
- import { AuditLogRootResource } from "../../Types/BaseDatabase/EnableAuditLogOn";
18
- import { PlanType } from "../../Types/Billing/SubscriptionPlan";
19
- import { getColumnAccessControlForAllColumns } from "../../Types/Database/AccessControl/ColumnAccessControl";
20
- import { TableColumnMetadata } from "../../Types/Database/TableColumn";
21
- import TableColumnType from "../../Types/Database/TableColumnType";
22
- import { JSONArray, JSONObject } from "../../Types/JSON";
10
+ import NotAuthorizedException from "../../Types/Exception/NotAuthorizedException";
11
+ import { JSONObject } from "../../Types/JSON";
23
12
  import ObjectID from "../../Types/ObjectID";
24
- import UserType from "../../Types/UserType";
25
- import UserService from "./UserService";
26
- import OneUptimeDate from "../../Types/Date";
27
13
 
28
- const PROJECT_SETTINGS_CACHE_TTL_MS: number = 60 * 1000;
29
- const USER_CACHE_TTL_MS: number = 5 * 60 * 1000;
14
+ // Why a create that is not the recorder's is refused.
15
+ export const AUDIT_LOG_CREATE_REFUSED_MESSAGE: string =
16
+ "Audit log entries are recorded by OneUptime and cannot be created directly.";
30
17
 
31
18
  /*
32
- * Upper bound on the related rows one audit entry looks up to name. An entry
33
- * that references more is still recorded in full; the rest keep their ids.
19
+ * The audit log's ClickHouse table (reads, retention, migrations) and the four
20
+ * entry points every audited write calls.
21
+ *
22
+ * RECORDING is an Enterprise Edition feature and lives in ee/
23
+ * (ee/Server/AuditLog/AuditLogRecorder.ts): which changes are recorded, the
24
+ * diff, redaction, relation names, the actor and the project-settings cache.
25
+ * recordCreate / recordUpdate / recordDelete / invalidateProjectSettings stay
26
+ * here as thin delegates to the recorder the enterprise module registered, so
27
+ * DatabaseService, ProjectService and the user-notification services call
28
+ * exactly what they always called.
29
+ *
30
+ * On the Community Edition there is no recorder: every call is a no-op, and no
31
+ * entry is ever written.
32
+ *
33
+ * The recorder is looked up on EVERY call, never cached at import: the
34
+ * enterprise module registers after core's modules have loaded.
35
+ *
36
+ * An audited write must never fail because of its audit entry, so a delegate
37
+ * never throws - even when a recorder breaks its own promise not to.
38
+ *
39
+ * Entries are written ONLY by the recorder, as root. Any other create is
40
+ * refused (see createMany), so nobody can forge the audit trail.
34
41
  */
35
- const MAX_RELATION_NAME_LOOKUPS: number = 100;
36
-
37
- const SKIPPED_FIELDS: ReadonlySet<string> = new Set<string>([
38
- "_id",
39
- "id",
40
- "createdAt",
41
- "updatedAt",
42
- "deletedAt",
43
- "version",
44
- "slug",
45
- ]);
46
-
47
- const NAME_CANDIDATE_FIELDS: ReadonlyArray<string> = [
48
- "name",
49
- "title",
50
- "displayName",
51
- ];
52
-
53
- type RelatedModelType = { new (): BaseModel };
54
-
55
- interface CachedProjectSettings {
56
- enableAuditLogs: boolean;
57
- retentionInDays: number;
58
- storeSystemEventsInAuditLogs: boolean;
59
- planName: PlanType | undefined;
60
- expiresAt: number;
61
- }
62
-
63
- interface CachedUser {
64
- name: string | null;
65
- email: string | null;
66
- expiresAt: number;
67
- }
68
-
69
- interface RootResourcePointer {
70
- rootResourceType: string | null;
71
- rootResourceId: ObjectID | null;
72
- }
73
-
74
- /*
75
- * Relation references still waiting for a name, grouped by the model they
76
- * point at so each model is queried once per entry.
77
- */
78
- interface PendingRelationNames {
79
- modelType: RelatedModelType;
80
- ids: Set<string>;
81
- references: Array<JSONObject>;
82
- }
83
-
84
42
  export class AuditLogService extends AnalyticsDatabaseService<AuditLog> {
85
- private projectSettingsCache: Map<string, CachedProjectSettings> = new Map();
86
- private userCache: Map<string, CachedUser> = new Map();
87
- private relatedModelServices: Map<
88
- RelatedModelType,
89
- DatabaseService<BaseModel>
90
- > = new Map();
91
-
92
43
  public constructor(clickhouseDatabase?: ClickhouseDatabase | undefined) {
93
44
  super({ modelType: AuditLog, database: clickhouseDatabase });
94
45
  }
95
46
 
47
+ /*
48
+ * Refuses every create that is not root. The recorder writes as root
49
+ * (EnterpriseEdition.getAuditLogRecorder()); anyone else - a project owner
50
+ * or admin through POST /audit-log, a master admin, an API key - would be
51
+ * forging entries. The model's create permissions are empty as well, but
52
+ * master admins pass those, so this is the rule that holds for everyone.
53
+ * Checked here rather than in onBeforeCreate: every create goes through
54
+ * this method (create() delegates to it), and hooks can be skipped with
55
+ * props.ignoreHooks.
56
+ */
57
+ public override async createMany(
58
+ createBy: CreateManyBy<AuditLog>,
59
+ ): Promise<Array<AuditLog>> {
60
+ if (!createBy.props.isRoot) {
61
+ throw new NotAuthorizedException(AUDIT_LOG_CREATE_REFUSED_MESSAGE);
62
+ }
63
+
64
+ return await super.createMany(createBy);
65
+ }
66
+
96
67
  public invalidateProjectSettings(projectId: ObjectID): void {
97
- this.projectSettingsCache.delete(projectId.toString());
68
+ const recorder: AuditLogRecorder | null = this.getRecorder();
69
+
70
+ if (!recorder) {
71
+ return;
72
+ }
73
+
74
+ try {
75
+ recorder.invalidateProjectSettings(projectId);
76
+ } catch (err) {
77
+ logger.warn(
78
+ "AuditLog: failed to invalidate the cached project audit settings",
79
+ );
80
+ logger.warn(err);
81
+ }
98
82
  }
99
83
 
100
84
  public async recordCreate<TModel extends BaseModel>(data: {
@@ -102,46 +86,14 @@ export class AuditLogService extends AnalyticsDatabaseService<AuditLog> {
102
86
  createdItem: TModel;
103
87
  props: DatabaseCommonInteractionProps;
104
88
  }): Promise<void> {
105
- try {
106
- const projectId: ObjectID | undefined = this.resolveProjectId(
107
- data.model,
108
- data.createdItem,
109
- data.props,
110
- );
111
-
112
- if (!projectId) {
113
- return;
114
- }
115
-
116
- const settings: CachedProjectSettings | null =
117
- await this.getProjectSettings(projectId);
118
-
119
- if (!this.isEligible(settings, data.props)) {
120
- return;
121
- }
89
+ const recorder: AuditLogRecorder | null = this.getRecorder();
122
90
 
123
- const changes: JSONArray = this.buildSnapshotChanges({
124
- model: data.model,
125
- item: data.createdItem,
126
- valueKey: "newValue",
127
- });
128
-
129
- await this.addRelationNames({
130
- model: data.model,
131
- changes,
132
- projectId,
133
- });
91
+ if (!recorder) {
92
+ return;
93
+ }
134
94
 
135
- await this.insert({
136
- projectId,
137
- model: data.model,
138
- item: data.createdItem,
139
- resourceId: data.createdItem.id ?? null,
140
- action: AuditLogAction.Create,
141
- changes,
142
- props: data.props,
143
- retentionInDays: settings!.retentionInDays,
144
- });
95
+ try {
96
+ await recorder.recordCreate(data);
145
97
  } catch (err) {
146
98
  logger.warn("AuditLog: failed to record create event");
147
99
  logger.warn(err);
@@ -155,56 +107,14 @@ export class AuditLogService extends AnalyticsDatabaseService<AuditLog> {
155
107
  itemId: ObjectID;
156
108
  props: DatabaseCommonInteractionProps;
157
109
  }): Promise<void> {
158
- try {
159
- /*
160
- * The diff comes first because it needs no I/O: an update that changed
161
- * nothing the audit trail tracks - an evaluation tick that rewrote only
162
- * ignored columns, several times an hour per SLO - should not cost a
163
- * settings lookup.
164
- */
165
- const changes: JSONArray = this.buildUpdateDiff({
166
- model: data.model,
167
- before: data.before,
168
- updatedFields: data.updatedFields,
169
- });
110
+ const recorder: AuditLogRecorder | null = this.getRecorder();
170
111
 
171
- if (changes.length === 0) {
172
- return;
173
- }
174
-
175
- const projectId: ObjectID | undefined = this.resolveProjectId(
176
- data.model,
177
- data.before,
178
- data.props,
179
- );
180
-
181
- if (!projectId) {
182
- return;
183
- }
184
-
185
- const settings: CachedProjectSettings | null =
186
- await this.getProjectSettings(projectId);
187
-
188
- if (!this.isEligible(settings, data.props)) {
189
- return;
190
- }
191
-
192
- await this.addRelationNames({
193
- model: data.model,
194
- changes,
195
- projectId,
196
- });
112
+ if (!recorder) {
113
+ return;
114
+ }
197
115
 
198
- await this.insert({
199
- projectId,
200
- model: data.model,
201
- item: data.before,
202
- resourceId: data.itemId,
203
- action: AuditLogAction.Update,
204
- changes,
205
- props: data.props,
206
- retentionInDays: settings!.retentionInDays,
207
- });
116
+ try {
117
+ await recorder.recordUpdate(data);
208
118
  } catch (err) {
209
119
  logger.warn("AuditLog: failed to record update event");
210
120
  logger.warn(err);
@@ -217,928 +127,23 @@ export class AuditLogService extends AnalyticsDatabaseService<AuditLog> {
217
127
  itemId: ObjectID;
218
128
  props: DatabaseCommonInteractionProps;
219
129
  }): Promise<void> {
220
- try {
221
- const projectId: ObjectID | undefined = this.resolveProjectId(
222
- data.model,
223
- data.deletedItem,
224
- data.props,
225
- );
226
-
227
- if (!projectId) {
228
- return;
229
- }
230
-
231
- const settings: CachedProjectSettings | null =
232
- await this.getProjectSettings(projectId);
233
-
234
- if (!this.isEligible(settings, data.props)) {
235
- return;
236
- }
237
-
238
- const changes: JSONArray = this.buildSnapshotChanges({
239
- model: data.model,
240
- item: data.deletedItem,
241
- valueKey: "oldValue",
242
- });
243
-
244
- await this.addRelationNames({
245
- model: data.model,
246
- changes,
247
- projectId,
248
- });
249
-
250
- await this.insert({
251
- projectId,
252
- model: data.model,
253
- item: data.deletedItem,
254
- resourceId: data.itemId,
255
- action: AuditLogAction.Delete,
256
- changes,
257
- props: data.props,
258
- retentionInDays: settings!.retentionInDays,
259
- });
260
- } catch (err) {
261
- logger.warn("AuditLog: failed to record delete event");
262
- logger.warn(err);
263
- }
264
- }
265
-
266
- private async insert<TModel extends BaseModel>(params: {
267
- projectId: ObjectID;
268
- model: TModel;
269
- // The row as recorded: the created row, the row before the update, or the deleted row.
270
- item: TModel;
271
- resourceId: ObjectID | null;
272
- action: AuditLogAction;
273
- changes: JSONArray;
274
- props: DatabaseCommonInteractionProps;
275
- retentionInDays: number;
276
- }): Promise<void> {
277
- const resourceType: string = this.getResourceType(params.model);
278
-
279
- const resourceName: string | null = await this.resolveResourceName({
280
- model: params.model,
281
- item: params.item,
282
- projectId: params.projectId,
283
- });
284
-
285
- const rootResource: RootResourcePointer = this.getRootResource({
286
- model: params.model,
287
- item: params.item,
288
- resourceType,
289
- resourceId: params.resourceId,
290
- });
291
-
292
- const auditLog: AuditLog = new AuditLog();
293
- auditLog.projectId = params.projectId;
294
- auditLog.resourceType = resourceType;
295
- if (params.resourceId) {
296
- auditLog.resourceId = params.resourceId;
297
- }
298
- if (resourceName) {
299
- auditLog.resourceName = resourceName;
300
- }
301
- if (rootResource.rootResourceType && rootResource.rootResourceId) {
302
- auditLog.rootResourceType = rootResource.rootResourceType;
303
- auditLog.rootResourceId = rootResource.rootResourceId;
304
- }
305
- auditLog.action = params.action;
306
-
307
- const actor: {
308
- userId: ObjectID | null;
309
- userName: string | null;
310
- userEmail: string | null;
311
- userType: string | null;
312
- } = await this.resolveActor(params.props);
313
-
314
- if (actor.userId) {
315
- auditLog.userId = actor.userId;
316
- }
317
- if (actor.userName) {
318
- auditLog.userName = actor.userName;
319
- }
320
- if (actor.userEmail) {
321
- auditLog.userEmail = actor.userEmail;
322
- }
323
- if (actor.userType) {
324
- auditLog.userType = actor.userType;
325
- }
326
-
327
- auditLog.changes = params.changes;
328
- auditLog.retentionDate = this.computeRetentionDate(params.retentionInDays);
329
-
330
- await this.create({
331
- data: auditLog,
332
- props: { isRoot: true },
333
- });
334
- }
335
-
336
- private computeRetentionDate(retentionInDays: number): Date {
337
- const days: number = Math.max(1, Math.min(retentionInDays || 7, 180));
338
- return OneUptimeDate.addRemoveDays(OneUptimeDate.getCurrentDate(), days);
339
- }
340
-
341
- private isEligible(
342
- settings: CachedProjectSettings | null,
343
- props: DatabaseCommonInteractionProps,
344
- ): boolean {
345
- if (!settings) {
346
- return false;
347
- }
348
-
349
- if (!settings.enableAuditLogs) {
350
- return false;
351
- }
352
-
353
- if (!settings.storeSystemEventsInAuditLogs && this.isSystemEvent(props)) {
354
- return false;
355
- }
356
-
357
- if (IsEnterpriseEdition) {
358
- return true;
359
- }
360
-
361
- if (IsBillingEnabled) {
362
- return settings.planName === PlanType.Enterprise;
363
- }
364
-
365
- /*
366
- * Neither enterprise edition nor billing is enabled — audit logs are not
367
- * available on the free self-hosted build.
368
- */
369
- return false;
370
- }
371
-
372
- private isSystemEvent(props: DatabaseCommonInteractionProps): boolean {
373
- /*
374
- * A system event is one not initiated by a user — no userType is set and
375
- * the operation is running with root privileges (e.g. background jobs,
376
- * internal cleanup tasks).
377
- */
378
- return !props.userType && Boolean(props.isRoot);
379
- }
380
-
381
- private async getProjectSettings(
382
- projectId: ObjectID,
383
- ): Promise<CachedProjectSettings | null> {
384
- const key: string = projectId.toString();
385
- const now: number = Date.now();
386
- const cached: CachedProjectSettings | undefined =
387
- this.projectSettingsCache.get(key);
388
-
389
- if (cached && cached.expiresAt > now) {
390
- return cached;
391
- }
392
-
393
- const project: Project | null = await ProjectService.findOneById({
394
- id: projectId,
395
- select: {
396
- _id: true,
397
- enableAuditLogs: true,
398
- auditLogsRetentionInDays: true,
399
- storeSystemEventsInAuditLogs: true,
400
- planName: true,
401
- },
402
- props: { isRoot: true },
403
- });
404
-
405
- if (!project) {
406
- return null;
407
- }
408
-
409
- const settings: CachedProjectSettings = {
410
- enableAuditLogs: Boolean(project.enableAuditLogs),
411
- retentionInDays: project.auditLogsRetentionInDays ?? 7,
412
- storeSystemEventsInAuditLogs: Boolean(
413
- project.storeSystemEventsInAuditLogs,
414
- ),
415
- planName: project.planName,
416
- expiresAt: now + PROJECT_SETTINGS_CACHE_TTL_MS,
417
- };
418
-
419
- this.projectSettingsCache.set(key, settings);
420
- return settings;
421
- }
422
-
423
- private async resolveActor(props: DatabaseCommonInteractionProps): Promise<{
424
- userId: ObjectID | null;
425
- userName: string | null;
426
- userEmail: string | null;
427
- userType: string | null;
428
- }> {
429
- const userType: string | null = props.userType
430
- ? String(props.userType)
431
- : props.isRoot
432
- ? "System"
433
- : null;
434
-
435
- if (!props.userId) {
436
- return {
437
- userId: null,
438
- userName: null,
439
- userEmail: null,
440
- userType,
441
- };
442
- }
443
-
444
- // API-key actions don't have a user record to look up.
445
- if (props.userType === UserType.API) {
446
- return {
447
- userId: props.userId,
448
- userName: null,
449
- userEmail: null,
450
- userType,
451
- };
452
- }
453
-
454
- const cached: { name: string | null; email: string | null } | null =
455
- await this.getUserInfo(props.userId);
456
-
457
- return {
458
- userId: props.userId,
459
- userName: cached?.name ?? null,
460
- userEmail: cached?.email ?? null,
461
- userType,
462
- };
463
- }
464
-
465
- private async getUserInfo(
466
- userId: ObjectID,
467
- ): Promise<{ name: string | null; email: string | null } | null> {
468
- const key: string = userId.toString();
469
- const now: number = Date.now();
470
- const cached: CachedUser | undefined = this.userCache.get(key);
471
-
472
- if (cached && cached.expiresAt > now) {
473
- return { name: cached.name, email: cached.email };
474
- }
475
-
476
- const user: User | null = await UserService.findOneById({
477
- id: userId,
478
- select: { _id: true, name: true, email: true },
479
- props: { isRoot: true },
480
- });
481
-
482
- const name: string | null = user?.name?.toString() ?? null;
483
- const email: string | null = user?.email?.toString() ?? null;
484
-
485
- this.userCache.set(key, {
486
- name,
487
- email,
488
- expiresAt: now + USER_CACHE_TTL_MS,
489
- });
490
-
491
- return { name, email };
492
- }
493
-
494
- private resolveProjectId<TModel extends BaseModel>(
495
- model: TModel,
496
- item: TModel,
497
- props: DatabaseCommonInteractionProps,
498
- ): ObjectID | undefined {
499
- if (props.tenantId) {
500
- return props.tenantId;
501
- }
502
-
503
- const tenantColumn: string | null = model.getTenantColumn();
504
- if (!tenantColumn) {
505
- return undefined;
506
- }
507
-
508
- const value: ObjectID | undefined = item.getValue<ObjectID>(tenantColumn);
509
- return value ?? undefined;
510
- }
511
-
512
- /*
513
- * Where this entry rolls up to (see EnableAuditLogOn.rootResource). A
514
- * top-level resource points at itself; a child points at the parent id it
515
- * carries in its configured column.
516
- */
517
- private getRootResource<TModel extends BaseModel>(data: {
518
- model: TModel;
519
- item: TModel;
520
- resourceType: string;
521
- resourceId: ObjectID | null;
522
- }): RootResourcePointer {
523
- const rootResource: AuditLogRootResource | undefined =
524
- data.model.enableAuditLogOn?.rootResource;
525
-
526
- if (!rootResource) {
527
- return {
528
- rootResourceType: data.resourceType,
529
- rootResourceId: data.resourceId,
530
- };
531
- }
532
-
533
- const rootResourceId: string | null = RelationValueUtil.getRelationId(
534
- (data.item as unknown as Record<string, unknown>)[rootResource.column],
535
- );
536
-
537
- if (!rootResourceId) {
538
- /*
539
- * A child row that cannot name its parent. Filing it under itself would
540
- * give it a root type it is not, so it gets no pointer: the entry still
541
- * shows in the project-wide audit log, just not on a resource's page.
542
- */
543
- return { rootResourceType: null, rootResourceId: null };
544
- }
545
-
546
- return {
547
- rootResourceType: rootResource.resourceType,
548
- rootResourceId: new ObjectID(rootResourceId),
549
- };
550
- }
551
-
552
- /*
553
- * Everything an entry leaves out: bookkeeping fields, columns nobody may read
554
- * (read ACL `[]`, so recording them would leak them to audit readers), and
555
- * the model's ignored columns.
556
- */
557
- private getExcludedFields<TModel extends BaseModel>(
558
- model: TModel,
559
- ): Set<string> {
560
- const excluded: Set<string> = new Set<string>(SKIPPED_FIELDS);
561
-
562
- for (const field of this.getRedactedFields(model)) {
563
- excluded.add(field);
564
- }
565
-
566
- for (const field of model.enableAuditLogOn?.ignoreColumns || []) {
567
- excluded.add(field);
568
- }
569
-
570
- return excluded;
571
- }
572
-
573
- private getRedactedFields<TModel extends BaseModel>(
574
- model: TModel,
575
- ): Set<string> {
576
- const redacted: Set<string> = new Set<string>();
577
- const allAccessControl: { [key: string]: { read?: unknown[] } } =
578
- getColumnAccessControlForAllColumns(model) as {
579
- [key: string]: { read?: unknown[] };
580
- };
581
-
582
- for (const key of Object.keys(allAccessControl)) {
583
- const ac: { read?: unknown[] } | undefined = allAccessControl[key];
584
- if (ac && Array.isArray(ac.read) && ac.read.length === 0) {
585
- redacted.add(key);
586
- }
587
- }
588
-
589
- return redacted;
590
- }
591
-
592
- private buildSnapshotChanges<TModel extends BaseModel>(data: {
593
- model: TModel;
594
- item: TModel;
595
- valueKey: "oldValue" | "newValue";
596
- }): JSONArray {
597
- const changes: JSONArray = [];
598
- const excludedFields: Set<string> = this.getExcludedFields(data.model);
599
- const columns: Array<string> = data.model.getTableColumns().columns;
600
- const itemRecord: Record<string, unknown> = data.item as unknown as Record<
601
- string,
602
- unknown
603
- >;
604
-
605
- for (const column of columns) {
606
- if (excludedFields.has(column)) {
607
- continue;
608
- }
609
-
610
- const value: unknown = itemRecord[column];
611
-
612
- if (value === undefined) {
613
- continue;
614
- }
615
-
616
- changes.push({
617
- field: column,
618
- [data.valueKey]: this.serializeValue(data.model, column, value),
619
- } as JSONObject);
620
- }
621
-
622
- return changes;
623
- }
624
-
625
- private buildUpdateDiff<TModel extends BaseModel>(data: {
626
- model: TModel;
627
- before: TModel;
628
- updatedFields: JSONObject;
629
- }): JSONArray {
630
- const changes: JSONArray = [];
631
- const excludedFields: Set<string> = this.getExcludedFields(data.model);
632
- const beforeRecord: Record<string, unknown> =
633
- data.before as unknown as Record<string, unknown>;
634
-
635
- for (const field of Object.keys(data.updatedFields)) {
636
- if (excludedFields.has(field)) {
637
- continue;
638
- }
639
-
640
- const newValue: unknown = data.updatedFields[field];
641
- const oldValue: unknown = beforeRecord[field];
642
-
643
- if (
644
- this.areValuesEqual({
645
- model: data.model,
646
- field,
647
- oldValue,
648
- newValue,
649
- })
650
- ) {
651
- continue;
652
- }
653
-
654
- changes.push({
655
- field,
656
- oldValue: this.serializeValue(data.model, field, oldValue),
657
- newValue: this.serializeValue(data.model, field, newValue),
658
- } as JSONObject);
659
- }
660
-
661
- return changes;
662
- }
663
-
664
- private areValuesEqual<TModel extends BaseModel>(data: {
665
- model: TModel;
666
- field: string;
667
- oldValue: unknown;
668
- newValue: unknown;
669
- }): boolean {
670
- const a: unknown = data.oldValue;
671
- const b: unknown = data.newValue;
672
-
673
- if (a === b) {
674
- return true;
675
- }
676
- if (a === null || a === undefined) {
677
- return b === null || b === undefined;
678
- }
679
- if (b === null || b === undefined) {
680
- return false;
681
- }
682
-
683
- /*
684
- * A relation is the set of rows it references. Its JSON also carries
685
- * whatever else happened to be loaded - the before-row's names, the
686
- * payload's bare ids, the order the join returned - so an unchanged
687
- * relation would otherwise read as changed.
688
- */
689
- if (this.getRelationMetadata(data.model, data.field)) {
690
- const sameRelationIds: boolean | null =
691
- RelationValueUtil.haveSameRelationIds(a, b);
692
-
693
- if (sameRelationIds !== null) {
694
- return sameRelationIds;
695
- }
696
- }
697
-
698
- try {
699
- return JSON.stringify(a) === JSON.stringify(b);
700
- } catch {
701
- return false;
702
- }
703
- }
704
-
705
- // The column's metadata when it is a relation (Entity / EntityArray), else null.
706
- private getRelationMetadata<TModel extends BaseModel>(
707
- model: TModel,
708
- field: string,
709
- ): TableColumnMetadata | null {
710
- if (!model.isTableColumn(field)) {
711
- return null;
712
- }
713
-
714
- const metadata: TableColumnMetadata | undefined =
715
- model.getTableColumnMetadata(field);
716
-
717
- if (
718
- !metadata ||
719
- !metadata.modelType ||
720
- (metadata.type !== TableColumnType.Entity &&
721
- metadata.type !== TableColumnType.EntityArray)
722
- ) {
723
- return null;
724
- }
725
-
726
- return metadata;
727
- }
728
-
729
- private serializeValue<TModel extends BaseModel>(
730
- model: TModel,
731
- field: string,
732
- value: unknown,
733
- ): unknown {
734
- if (value === null || value === undefined) {
735
- return null;
736
- }
737
-
738
- /*
739
- * A related row is recorded as `{ _id, name }`. Serialized as it arrives
740
- * it would be a model instance's JSON: a bare `{ _id }` from a payload, or
741
- * whatever columns the read happened to load.
742
- */
743
- if (this.getRelationMetadata(model, field)) {
744
- if (Array.isArray(value)) {
745
- return value.map((element: unknown): unknown => {
746
- return this.serializeRelationReference(element);
747
- });
748
- }
749
-
750
- return this.serializeRelationReference(value);
751
- }
752
-
753
- return this.serializePlainValue(value);
754
- }
755
-
756
- private serializeRelationReference(value: unknown): unknown {
757
- const id: string | null = RelationValueUtil.getRelationId(value);
758
-
759
- // Not a reference at all: record it as it is rather than drop it.
760
- if (!id) {
761
- return this.serializePlainValue(value);
762
- }
763
-
764
- const reference: JSONObject = { _id: id };
765
-
766
- if (value && typeof value === "object") {
767
- const name: string | null = this.toDisplayString(
768
- (value as Record<string, unknown>)["name"],
769
- );
770
-
771
- if (name) {
772
- reference["name"] = name;
773
- }
774
- }
775
-
776
- return reference;
777
- }
778
-
779
- private serializePlainValue(value: unknown): unknown {
780
- if (value === null || value === undefined) {
781
- return null;
782
- }
783
- if (value instanceof ObjectID) {
784
- return value.toString();
785
- }
786
- if (value instanceof Date) {
787
- return value.toISOString();
788
- }
789
- if (
790
- typeof value === "string" ||
791
- typeof value === "number" ||
792
- typeof value === "boolean"
793
- ) {
794
- return value;
795
- }
796
- try {
797
- return JSON.parse(JSON.stringify(value));
798
- } catch {
799
- return String(value);
800
- }
801
- }
802
-
803
- /*
804
- * Relation references are recorded with names so an entry reads
805
- * "Production -> Staging" rather than as two ids. An update's before-row
806
- * already carries the old names (DatabaseService selects them), but a
807
- * payload usually carries ids only - so an unnamed reference first borrows
808
- * the name of another reference to the same row in the same change, and
809
- * whatever is still unnamed is looked up. Best effort: a failed lookup leaves
810
- * the ids, and never costs the entry.
811
- */
812
- private async addRelationNames<TModel extends BaseModel>(data: {
813
- model: TModel;
814
- changes: JSONArray;
815
- projectId: ObjectID;
816
- }): Promise<void> {
817
- const pendingByModel: Map<RelatedModelType, PendingRelationNames> =
818
- new Map();
819
-
820
- for (const change of data.changes) {
821
- const entry: JSONObject = change as JSONObject;
822
- const metadata: TableColumnMetadata | null = this.getRelationMetadata(
823
- data.model,
824
- String(entry["field"]),
825
- );
826
-
827
- if (!metadata || !metadata.modelType) {
828
- continue;
829
- }
830
-
831
- const references: Array<JSONObject> = [
832
- ...this.getRelationReferences(entry["oldValue"]),
833
- ...this.getRelationReferences(entry["newValue"]),
834
- ];
835
-
836
- const knownNames: Map<string, string> = new Map<string, string>();
837
-
838
- for (const reference of references) {
839
- const name: unknown = reference["name"];
840
-
841
- if (typeof name === "string" && name.length > 0) {
842
- knownNames.set(String(reference["_id"]).toLowerCase(), name);
843
- }
844
- }
845
-
846
- for (const reference of references) {
847
- if (reference["name"]) {
848
- continue;
849
- }
850
-
851
- const id: string = String(reference["_id"]).toLowerCase();
852
- const knownName: string | undefined = knownNames.get(id);
853
-
854
- if (knownName) {
855
- reference["name"] = knownName;
856
- continue;
857
- }
858
-
859
- let pending: PendingRelationNames | undefined = pendingByModel.get(
860
- metadata.modelType,
861
- );
862
-
863
- if (!pending) {
864
- pending = {
865
- modelType: metadata.modelType,
866
- ids: new Set<string>(),
867
- references: [],
868
- };
869
- pendingByModel.set(metadata.modelType, pending);
870
- }
130
+ const recorder: AuditLogRecorder | null = this.getRecorder();
871
131
 
872
- pending.ids.add(id);
873
- pending.references.push(reference);
874
- }
875
- }
876
-
877
- let remainingLookups: number = MAX_RELATION_NAME_LOOKUPS;
878
-
879
- for (const pending of pendingByModel.values()) {
880
- if (remainingLookups <= 0) {
881
- break;
882
- }
883
-
884
- const ids: Array<string> = Array.from(pending.ids).slice(
885
- 0,
886
- remainingLookups,
887
- );
888
- remainingLookups -= ids.length;
889
-
890
- try {
891
- const names: Map<string, string> = await this.findRelationNames({
892
- modelType: pending.modelType,
893
- ids,
894
- projectId: data.projectId,
895
- });
896
-
897
- for (const reference of pending.references) {
898
- const name: string | undefined = names.get(
899
- String(reference["_id"]).toLowerCase(),
900
- );
901
-
902
- if (name) {
903
- reference["name"] = name;
904
- }
905
- }
906
- } catch (err) {
907
- logger.warn(
908
- "AuditLog: could not resolve the names of related resources; recording their ids only",
909
- );
910
- logger.warn(err);
911
- }
912
- }
913
- }
914
-
915
- private getRelationReferences(value: unknown): Array<JSONObject> {
916
- const candidates: Array<unknown> = Array.isArray(value) ? value : [value];
917
-
918
- return candidates.filter((candidate: unknown): candidate is JSONObject => {
919
- return (
920
- candidate !== null &&
921
- typeof candidate === "object" &&
922
- !Array.isArray(candidate) &&
923
- typeof (candidate as JSONObject)["_id"] === "string"
924
- );
925
- });
926
- }
927
-
928
- /*
929
- * Display names for related rows, keyed by lower-cased id.
930
- *
931
- * A user is named by their name, else their email, through the same cache
932
- * the actor lookup uses. Any other model is named by its `name` column, and
933
- * only rows inside the audited project are read: the ids come from the
934
- * caller's payload, and naming a row that belongs to another project would
935
- * copy that project's data into this project's audit trail. A model with no
936
- * tenant column or no name column resolves nothing.
937
- */
938
- private async findRelationNames(data: {
939
- modelType: RelatedModelType;
940
- ids: Array<string>;
941
- projectId: ObjectID;
942
- }): Promise<Map<string, string>> {
943
- const names: Map<string, string> = new Map<string, string>();
944
- const ids: Array<string> = Array.from(
945
- new Set<string>(
946
- data.ids.map((id: string): string => {
947
- return id.toLowerCase();
948
- }),
949
- ),
950
- );
951
-
952
- if (ids.length === 0) {
953
- return names;
954
- }
955
-
956
- const relatedModel: BaseModel = new data.modelType();
957
-
958
- if (relatedModel instanceof User) {
959
- for (const id of ids) {
960
- const user: { name: string | null; email: string | null } | null =
961
- await this.getUserInfo(new ObjectID(id));
962
- const name: string | null = user?.name || user?.email || null;
963
-
964
- if (name) {
965
- names.set(id, name);
966
- }
967
- }
968
-
969
- return names;
970
- }
971
-
972
- const tenantColumn: string | null = relatedModel.getTenantColumn();
973
-
974
- if (!tenantColumn || !relatedModel.isTableColumn("name")) {
975
- return names;
976
- }
977
-
978
- const rows: Array<BaseModel> = await this.getRelatedModelService(
979
- data.modelType,
980
- ).findBy({
981
- query: {
982
- _id: QueryHelper.any(
983
- ids.map((id: string): ObjectID => {
984
- return new ObjectID(id);
985
- }),
986
- ),
987
- [tenantColumn]: data.projectId,
988
- } as Query<BaseModel>,
989
- select: { _id: true, name: true } as Select<BaseModel>,
990
- skip: 0,
991
- limit: ids.length,
992
- props: { isRoot: true, ignoreHooks: true },
993
- });
994
-
995
- for (const row of rows) {
996
- const name: string | null = this.toDisplayString(
997
- (row as unknown as Record<string, unknown>)["name"],
998
- );
999
-
1000
- if (row._id && name) {
1001
- names.set(row._id.toString().toLowerCase(), name);
1002
- }
1003
- }
1004
-
1005
- return names;
1006
- }
1007
-
1008
- /*
1009
- * A plain DatabaseService reads the related rows: the lookup needs no
1010
- * service hooks (it runs as root with hooks off), and going through a
1011
- * registry of concrete services would import every service into this one.
1012
- */
1013
- private getRelatedModelService(
1014
- modelType: RelatedModelType,
1015
- ): DatabaseService<BaseModel> {
1016
- let service: DatabaseService<BaseModel> | undefined =
1017
- this.relatedModelServices.get(modelType);
1018
-
1019
- if (!service) {
1020
- service = new DatabaseService<BaseModel>(modelType);
1021
- this.relatedModelServices.set(modelType, service);
1022
- }
1023
-
1024
- return service;
1025
- }
1026
-
1027
- private getResourceType<TModel extends BaseModel>(model: TModel): string {
1028
- if (model.singularName) {
1029
- return model.singularName;
1030
- }
1031
- return (model as unknown as { constructor: { name: string } }).constructor
1032
- .name;
1033
- }
1034
-
1035
- private getResourceName<TModel extends BaseModel>(
1036
- item: TModel,
1037
- ): string | null {
1038
- const itemRecord: Record<string, unknown> = item as unknown as Record<
1039
- string,
1040
- unknown
1041
- >;
1042
-
1043
- for (const field of NAME_CANDIDATE_FIELDS) {
1044
- if (!item.isTableColumn(field)) {
1045
- continue;
1046
- }
1047
-
1048
- const name: string | null = this.toDisplayString(itemRecord[field]);
1049
-
1050
- if (name) {
1051
- return name;
1052
- }
1053
- }
1054
-
1055
- return null;
1056
- }
1057
-
1058
- /*
1059
- * The name a row has, or failing that the name of the row its
1060
- * resourceNameRelation points at - an SLO owner row is named after its user
1061
- * or team. Best effort: an entry is never lost for want of a name.
1062
- */
1063
- private async resolveResourceName<TModel extends BaseModel>(data: {
1064
- model: TModel;
1065
- item: TModel;
1066
- projectId: ObjectID;
1067
- }): Promise<string | null> {
1068
- const ownName: string | null = this.getResourceName(data.item);
1069
-
1070
- if (ownName) {
1071
- return ownName;
1072
- }
1073
-
1074
- const relation: string | undefined =
1075
- data.model.enableAuditLogOn?.resourceNameRelation;
1076
-
1077
- if (!relation) {
1078
- return null;
1079
- }
1080
-
1081
- const metadata: TableColumnMetadata | null = this.getRelationMetadata(
1082
- data.model,
1083
- relation,
1084
- );
1085
-
1086
- if (
1087
- !metadata ||
1088
- !metadata.modelType ||
1089
- metadata.type !== TableColumnType.Entity ||
1090
- !metadata.manyToOneRelationColumn
1091
- ) {
1092
- return null;
1093
- }
1094
-
1095
- const relatedId: string | null = RelationValueUtil.getRelationId(
1096
- (data.item as unknown as Record<string, unknown>)[
1097
- metadata.manyToOneRelationColumn
1098
- ],
1099
- );
1100
-
1101
- if (!relatedId) {
1102
- return null;
132
+ if (!recorder) {
133
+ return;
1103
134
  }
1104
135
 
1105
136
  try {
1106
- const names: Map<string, string> = await this.findRelationNames({
1107
- modelType: metadata.modelType,
1108
- ids: [relatedId],
1109
- projectId: data.projectId,
1110
- });
1111
-
1112
- return names.get(relatedId.toLowerCase()) ?? null;
137
+ await recorder.recordDelete(data);
1113
138
  } catch (err) {
1114
- logger.warn(
1115
- "AuditLog: could not resolve the resource name; recording the entry without one",
1116
- );
139
+ logger.warn("AuditLog: failed to record delete event");
1117
140
  logger.warn(err);
1118
- return null;
1119
141
  }
1120
142
  }
1121
143
 
1122
- /*
1123
- * A non-empty display string for a stored value: a string as it is, and a
1124
- * value object (Name, Email) through its own toString. Anything else - a
1125
- * plain object stringifying to "[object Object]" - is not a name.
1126
- */
1127
- private toDisplayString(value: unknown): string | null {
1128
- if (typeof value === "string") {
1129
- return value.trim().length > 0 ? value : null;
1130
- }
1131
-
1132
- if (value instanceof ObjectID || value === null || value === undefined) {
1133
- return null;
1134
- }
1135
-
1136
- if (typeof value === "object") {
1137
- const text: string = String(value);
1138
- return text.trim().length > 0 && text !== "[object Object]" ? text : null;
1139
- }
1140
-
1141
- return null;
144
+ // Null on the Community Edition (the facade also swallows a module's errors).
145
+ private getRecorder(): AuditLogRecorder | null {
146
+ return EnterpriseEdition.getAuditLogRecorder();
1142
147
  }
1143
148
  }
1144
149