@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.
- package/Models/AnalyticsModels/AuditLog.ts +23 -15
- package/Models/DatabaseModels/GlobalConfig.ts +24 -0
- package/Models/DatabaseModels/Monitor.ts +3 -2
- package/Models/DatabaseModels/MonitorTemplate.ts +2 -1
- package/Models/DatabaseModels/OnCallDutyPolicyScheduleCalendarFeed.ts +1 -1
- package/Models/DatabaseModels/ProjectOnCallCalendarFeed.ts +1 -1
- package/Models/DatabaseModels/UserOnCallCalendarFeed.ts +1 -1
- package/Scripts/generate-service-worker.js +65 -4
- package/Server/API/AIBillingAPI.ts +1 -0
- package/Server/API/AIInsightAPI.ts +1 -4
- package/Server/API/AIInvestigationAPI.ts +1 -4
- package/Server/API/AIReadinessAPI.ts +4 -5
- package/Server/API/AlertAPI.ts +1 -0
- package/Server/API/AutoRemediationAPI.ts +1 -4
- package/Server/API/BaseAPI.ts +34 -0
- package/Server/API/BaseAnalyticsAPI.ts +80 -9
- package/Server/API/BillingAPI.ts +2 -0
- package/Server/API/BillingInvoiceAPI.ts +1 -0
- package/Server/API/BillingPaymentMethodAPI.ts +2 -0
- package/Server/API/CodeFixRunAPI.ts +1 -3
- package/Server/API/CommonAPI.ts +68 -4
- package/Server/API/DashboardAPI.ts +12 -12
- package/Server/API/GlobalConfigAPI.ts +243 -460
- package/Server/API/IncidentAPI.ts +2 -0
- package/Server/API/IncidentEpisodeAPI.ts +1 -0
- package/Server/API/NotificationAPI.ts +1 -0
- package/Server/API/OnCallCalendarAPI.ts +4 -5
- package/Server/API/OnCallDutyPolicyAPI.ts +7 -0
- package/Server/API/OnCallReadinessAPI.ts +4 -1
- package/Server/API/OnCallScheduleTimelineAPI.ts +731 -0
- package/Server/API/ProjectAPI.ts +1 -0
- package/Server/API/ProjectOIDC.ts +25 -16
- package/Server/API/ProjectSSO.ts +24 -16
- package/Server/API/ScheduledMaintenanceAPI.ts +1 -0
- package/Server/API/StatusPageAPI.ts +261 -74
- package/Server/API/TeamMemberAPI.ts +13 -1
- package/Server/API/UserCallAPI.ts +2 -0
- package/Server/API/UserEmailAPI.ts +2 -0
- package/Server/API/UserIncomingCallNumberAPI.ts +2 -0
- package/Server/API/UserMicrosoftTeamsAPI.ts +1 -0
- package/Server/API/UserSlackAPI.ts +1 -0
- package/Server/API/UserSmsAPI.ts +2 -0
- package/Server/API/UserTotpAuthAPI.ts +1 -0
- package/Server/API/UserWebAuthnAPI.ts +2 -0
- package/Server/API/UserWebhookAPI.ts +1 -0
- package/Server/API/UserWhatsAppAPI.ts +2 -0
- package/Server/Enterprise/EnterpriseEdition.ts +649 -0
- package/Server/Enterprise/EnterpriseFeature.ts +48 -0
- package/Server/Enterprise/EnterpriseLicenseSnapshot.ts +192 -0
- package/Server/Enterprise/EnterpriseServerModule.ts +233 -0
- package/Server/EnvironmentConfig.ts +147 -2
- package/Server/Infrastructure/Postgres/SchemaMigrations/1793900000000-AddEnterpriseEditionFirstSeenAt.ts +25 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +2 -0
- package/Server/Middleware/MasterAdminAuthorization.ts +13 -2
- package/Server/Middleware/UserAuthorization.ts +117 -21
- package/Server/Services/ApiKeyPermissionService.ts +101 -4
- package/Server/Services/AuditLogService.ts +84 -1079
- package/Server/Services/DatabaseService.ts +245 -0
- package/Server/Services/DetectionRuleService.ts +5 -4
- package/Server/Services/EnterpriseLicenseService.ts +38 -0
- package/Server/Services/GlobalConfigService.ts +80 -1
- package/Server/Services/MonitorProbeService.ts +116 -20
- package/Server/Services/MonitorService.ts +56 -4
- package/Server/Services/MonitorStatusTimelineService.ts +284 -0
- package/Server/Services/MonitorTemplateService.ts +26 -0
- package/Server/Services/OnCallDutyPolicyChildService.ts +261 -0
- package/Server/Services/OnCallDutyPolicyEscalationRuleScheduleService.ts +2 -2
- package/Server/Services/OnCallDutyPolicyEscalationRuleService.ts +2 -2
- package/Server/Services/OnCallDutyPolicyEscalationRuleTeamService.ts +2 -2
- package/Server/Services/OnCallDutyPolicyEscalationRuleUserService.ts +2 -2
- package/Server/Services/PayAsYouGoBillingService.ts +23 -28
- package/Server/Services/ProjectService.ts +302 -0
- package/Server/Services/RumSessionPinService.ts +293 -22
- package/Server/Services/StatusPagePrivateUserService.ts +7 -3
- package/Server/Services/StatusPageService.ts +78 -1
- package/Server/Services/TeamMemberService.ts +11 -0
- package/Server/Services/TeamPermissionService.ts +120 -26
- package/Server/Services/TeamService.ts +10 -0
- package/Server/Services/ThreatIntelFeedService.ts +6 -3
- package/Server/Services/UserService.ts +10 -17
- package/Server/Types/Database/Permissions/BasePermission.ts +9 -7
- package/Server/Types/Database/Permissions/CreatePermission.ts +15 -0
- package/Server/Types/Database/Permissions/EditionPermission.ts +208 -18
- package/Server/Types/Database/Permissions/Index.ts +75 -11
- package/Server/Types/Database/Permissions/TablePermission.ts +34 -31
- package/Server/Types/Database/Permissions/UpdatePermission.ts +29 -0
- package/Server/Types/Markdown.ts +41 -0
- package/Server/Utils/AI/AIChatPrivacyFilter.ts +8 -0
- package/Server/Utils/AI/AIRunPrivacyFilter.ts +8 -0
- package/Server/Utils/CommunityEditionSsoReport.ts +361 -0
- package/Server/Utils/EditionEnforcement.ts +233 -0
- package/Server/Utils/FrontendEnvironment.ts +41 -2
- package/Server/Utils/InstanceHealth/RedisHealth.ts +12 -277
- package/Server/Utils/MasterAdminPageAccess.ts +61 -0
- package/Server/Utils/Monitor/AffectedResourceList.ts +190 -0
- package/Server/Utils/Monitor/Criteria/EvaluateOverTime.ts +10 -1
- package/Server/Utils/Monitor/MonitorAlert.ts +3 -1
- package/Server/Utils/Monitor/MonitorCriteriaEvaluator.ts +543 -333
- package/Server/Utils/Monitor/MonitorIncident.ts +3 -1
- package/Server/Utils/Monitor/MonitoringIntervalValidator.ts +116 -0
- package/Server/Utils/OnCall/OnCallCalendarFeedRenderer.ts +1 -1
- package/Server/Utils/Realtime.ts +163 -45
- package/Server/Utils/SecurityEvent/DetectionRuleEvaluator.ts +11 -28
- package/Server/Utils/SecurityEvent/GoogleSecOpsSeverityRepair.ts +170 -0
- package/Server/Utils/SecurityEvent/Sigma/SigmaClickhouseCompiler.ts +1 -1
- package/Server/Utils/SecurityEvent/ThreatIntel/ThreatIntelFeedPoller.ts +6 -2
- package/Server/Utils/SecurityEvent/ThreatIntel/ThreatIntelMatcher.ts +10 -9
- package/Server/Utils/Workspace/Slack/Slack.ts +423 -10
- package/Tests/App/Accounts/LoginPasskey.test.tsx +18 -0
- package/Tests/App/Accounts/LoginSsoEdition.test.tsx +616 -0
- package/Tests/App/AdminDashboard/AdminAuthenticationSsoEdition.test.tsx +217 -0
- package/Tests/App/AdminDashboard/AdminEnterprisePluginPage.test.tsx +357 -0
- package/Tests/App/AdminDashboard/EnterpriseLicensesShell.test.tsx +214 -0
- package/Tests/App/AdminDashboard/GlobalSSOEnterpriseShells.test.tsx +271 -0
- package/Tests/App/AdminDashboard/HealthShells.test.tsx +659 -0
- package/Tests/App/Dashboard/AffectedResourcesPicker.test.tsx +1059 -0
- package/Tests/App/Dashboard/AffectedResourcesPickerEditForm.test.tsx +376 -0
- package/Tests/App/Dashboard/AffectedResourcesPickerHiddenTypes.test.tsx +757 -0
- package/Tests/App/Dashboard/AffectedResourcesSummaryStep.test.tsx +307 -0
- package/Tests/App/Dashboard/ArgumentsFormGroupByUnlistedAttributes.test.tsx +131 -0
- package/Tests/App/Dashboard/AuditLogsAndComplianceShells.test.tsx +572 -0
- package/Tests/App/Dashboard/DashboardHeaderRequests.test.tsx +1 -1
- package/Tests/App/Dashboard/DashboardMonitorLabelVariable.test.tsx +9 -1
- package/Tests/App/Dashboard/DashboardVariableAllContract.test.tsx +24 -0
- package/Tests/App/Dashboard/DashboardVariableSelector.test.tsx +162 -8
- package/Tests/App/Dashboard/EnterpriseFeatureUpgrade.test.tsx +547 -0
- package/Tests/App/Dashboard/EnterprisePluginPage.test.tsx +667 -0
- package/Tests/App/Dashboard/EntityFilterDropdownArchivedSlos.test.tsx +105 -6
- package/Tests/App/Dashboard/EntityFilterDropdownUnlistedSelection.test.tsx +434 -0
- package/Tests/App/Dashboard/EscalationRuleReadiness.test.tsx +276 -1
- package/Tests/App/Dashboard/IdentityEnterpriseShells.test.tsx +319 -0
- package/Tests/App/Dashboard/OnCallCalendarFeedSideMenus.test.tsx +9 -1
- package/Tests/App/Dashboard/OnboardingSsoEmptyState.test.tsx +185 -0
- package/Tests/App/Dashboard/PayAsYouGoConsentGate.test.tsx +58 -42
- package/Tests/App/Dashboard/PayAsYouGoNotices.test.tsx +42 -5
- package/Tests/App/Dashboard/ResourceAuditLogsSideMenus.test.tsx +34 -23
- package/Tests/App/Dashboard/ScheduleTimeline.test.tsx +1580 -0
- package/Tests/App/Dashboard/ScheduleTimelineAPI.test.ts +280 -0
- package/Tests/App/Dashboard/ScheduleTimelineModel.test.ts +673 -0
- package/Tests/App/Dashboard/SecurityEventConnectionDiagnostics.test.tsx +133 -70
- package/Tests/App/Dashboard/SecurityEventDetailPanel.test.tsx +399 -0
- package/Tests/App/Dashboard/SecurityEventListRow.test.tsx +214 -0
- package/Tests/App/Dashboard/SecurityEventsDetectionRulesPage.test.tsx +86 -3
- package/Tests/App/Dashboard/SecurityEventsEmptyState.test.tsx +1 -58
- package/Tests/App/Dashboard/SecurityEventsGuideContent.test.ts +1313 -0
- package/Tests/App/Dashboard/SecurityEventsHowItWorksCard.test.tsx +536 -0
- package/Tests/App/Dashboard/SecurityEventsNavTabs.test.tsx +248 -0
- package/Tests/App/Dashboard/SecurityEventsNoResults.test.tsx +222 -0
- package/Tests/App/Dashboard/SecurityEventsThreatIntelPage.test.tsx +199 -0
- package/Tests/App/Dashboard/SecurityEventsViewer.test.tsx +1203 -0
- package/Tests/App/Dashboard/SloOverviewHero.test.tsx +171 -36
- package/Tests/App/Dashboard/SloViewSideMenu.test.tsx +215 -0
- package/Tests/App/Dashboard/SloViewSideMenuCounts.test.tsx +40 -3
- package/Tests/App/Dashboard/UserEmailCallSites.test.tsx +11 -91
- package/Tests/App/PublicDashboard/DashboardVariableSelector.test.tsx +12 -4
- package/Tests/App/PublicDashboard/PublicDashboardWidgetListAuth.test.tsx +623 -0
- package/Tests/App/StatusPage/StatusPageSsoEmptyState.test.tsx +319 -0
- package/Tests/Helpers/RefreshAwareApiScan.ts +757 -0
- package/Tests/Helpers/TenantScopedRequestScan.ts +515 -0
- package/Tests/Models/OnCallCalendarFeedModels.test.ts +23 -1
- package/Tests/Scripts/GenerateServiceWorker.test.ts +931 -0
- package/Tests/Server/API/AIChatRouteAuthorization.test.ts +138 -5
- package/Tests/Server/API/AIGenerationProjectAIToggle.test.ts +187 -0
- package/Tests/Server/API/AIInvestigationAvailabilityAuthorization.test.ts +51 -3
- package/Tests/Server/API/AIInvestigationEvidenceAPI.test.ts +55 -2
- package/Tests/Server/API/BaseAPICreateItemDoesNotMutateModel.test.ts +130 -0
- package/Tests/Server/API/BaseAnalyticsAPIAggregateCache.test.ts +729 -0
- package/Tests/Server/API/BillingPayAsYouGoStatus.test.ts +93 -7
- package/Tests/Server/API/BillingPaymentMethodAPI.test.ts +36 -3
- package/Tests/Server/API/CommonAPIAuthGuard.test.ts +1003 -24
- package/Tests/Server/API/DashboardPublicRateLimit.test.ts +6 -3
- package/Tests/Server/API/ExpiredSessionAIRoutes.test.ts +708 -0
- package/Tests/Server/API/ExpiredSessionCustomRoutes.test.ts +928 -0
- package/Tests/Server/API/ExpiredSessionMonitorTemplate.test.ts +319 -0
- package/Tests/Server/API/ExpiredSessionOnCallDutyPolicy.test.ts +336 -0
- package/Tests/Server/API/ExpiredSessionRouteGuards.test.ts +820 -0
- package/Tests/Server/API/GlobalConfigLicense.test.ts +766 -381
- package/Tests/Server/API/NotificationChannelVerificationAPI.test.ts +115 -12
- package/Tests/Server/API/OnCallCalendarAPI.test.ts +375 -8
- package/Tests/Server/API/OnCallReadinessAPI.test.ts +196 -912
- package/Tests/Server/API/OnCallScheduleTimelineAPI.test.ts +1513 -0
- package/Tests/Server/API/OnCallSetupReminderAPI.test.ts +119 -7
- package/Tests/Server/API/ProjectScopedCustomRouteAuth.test.ts +111 -4
- package/Tests/Server/API/PublicRouteInvalidAccessToken.test.ts +615 -0
- package/Tests/Server/API/SecurityEventAttributesAPI.test.ts +89 -2
- package/Tests/Server/API/SessionReplayAPI.test.ts +121 -0
- package/Tests/Server/API/SsoProviderListingsEdition.test.ts +432 -0
- package/Tests/Server/API/StatusPageMasterPasswordRateLimit.test.ts +4 -2
- package/Tests/Server/API/StatusPagePostmortemVisibility.test.ts +441 -0
- package/Tests/Server/API/StatusPageTestEmailReportAuth.test.ts +664 -0
- package/Tests/Server/API/TeamMemberLeaveScimLockEdition.test.ts +252 -0
- package/Tests/Server/API/TeamMemberRemoveUserFromProjectAPI.test.ts +7 -0
- package/Tests/Server/API/UserIncomingCallNumberApi.test.ts +6 -0
- package/Tests/Server/API/UserNotificationSettingAPI.test.ts +65 -4
- package/Tests/Server/API/UserProjectsAPI.test.ts +63 -3
- package/Tests/Server/API/UserTotpAuthAPI.test.ts +48 -2
- package/Tests/Server/API/UserWebAuthnAuthenticationOptionsRoute.test.ts +11 -2
- package/Tests/Server/API/UserWebAuthnBackupCodeMinting.test.ts +46 -3
- package/Tests/Server/API/UserWebAuthnPasskeyAPI.test.ts +18 -2
- package/Tests/Server/API/ZZVerifyChatsAuth.test.ts +24 -7
- package/Tests/Server/Enterprise/EnterpriseEdition.test.ts +824 -0
- package/Tests/Server/Enterprise/EnterpriseFeatureActive.test.ts +643 -0
- package/Tests/Server/Enterprise/EnterpriseLicenseSnapshot.test.ts +294 -0
- package/Tests/Server/Enterprise/EnterpriseModelFeatureMap.test.ts +93 -0
- package/Tests/Server/Enterprise/EnterpriseOnlyModulesLiveInEe.test.ts +582 -0
- package/Tests/Server/Enterprise/EnterpriseServerModule.test.ts +247 -0
- package/Tests/Server/Enterprise/FakeEnterpriseModule.ts +502 -0
- package/Tests/Server/Enterprise/TestBillingFlag.ts +70 -0
- package/Tests/Server/EnvironmentConfigEnterpriseEdition.test.ts +314 -0
- package/Tests/Server/Infrastructure/ContainerBootConfiguration.test.ts +289 -0
- package/Tests/Server/Infrastructure/E2EClickHouseFixtureAccess.test.ts +5 -1
- package/Tests/Server/Middleware/ExpiredSessionUserMiddleware.test.ts +563 -0
- package/Tests/Server/Middleware/MasterAdminAuthorization.test.ts +299 -19
- package/Tests/Server/Middleware/PublicRouteUserMiddleware.test.ts +453 -0
- package/Tests/Server/Middleware/UserAuthorization.test.ts +37 -2
- package/Tests/Server/Middleware/UserAuthorizationEditionEnforcement.test.ts +516 -0
- package/Tests/Server/Services/AIChatPrivacyPin.test.ts +24 -0
- package/Tests/Server/Services/ApiKeyPermissionSecurity.test.ts +2 -0
- package/Tests/Server/Services/ApiKeyPermissionService.test.ts +3 -3
- package/Tests/Server/Services/AuditLogService.test.ts +460 -990
- package/Tests/Server/Services/CreateAndReadResponsesKeepIds.test.ts +263 -0
- package/Tests/Server/Services/DatabaseServiceCreateSuppliedId.test.ts +147 -0
- package/Tests/Server/Services/DatabaseServiceLoginBeforeHooks.test.ts +1078 -0
- package/Tests/Server/Services/DatabaseServiceTenantRelationGuard.test.ts +259 -0
- package/Tests/Server/Services/DatabaseServiceWriteOperatorValues.test.ts +147 -0
- package/Tests/Server/Services/EnterpriseLicenseServiceKeyGeneration.test.ts +151 -0
- package/Tests/Server/Services/GlobalConfigServiceLicenseColumns.test.ts +357 -0
- package/Tests/Server/Services/MonitorDestinationInfoIPv6.test.ts +101 -0
- package/Tests/Server/Services/MonitorPayAsYouGoBilling.test.ts +115 -1
- package/Tests/Server/Services/MonitorProbeServiceIntervalScheduling.test.ts +333 -0
- package/Tests/Server/Services/MonitorStatusTimelineDailyAggregates.test.ts +303 -0
- package/Tests/Server/Services/OnCallChildCreateAuthorizationPostgres.test.ts +711 -0
- package/Tests/Server/Services/OnCallDutyPolicyChildService.test.ts +733 -0
- package/Tests/Server/Services/PayAsYouGoBillingService.test.ts +190 -140
- package/Tests/Server/Services/PayAsYouGoStripeRateLimitBudget.test.ts +4 -9
- package/Tests/Server/Services/PermissionBlockDeletion.test.ts +780 -0
- package/Tests/Server/Services/PermissionBlockDeletionPostgres.test.ts +628 -0
- package/Tests/Server/Services/ProjectServiceAuditLogLicense.test.ts +701 -0
- package/Tests/Server/Services/ProjectServiceAuditLogSettingsCache.test.ts +31 -35
- package/Tests/Server/Services/ProjectServiceCreateSubscriptionStarted.test.ts +77 -1
- package/Tests/Server/Services/RumSessionPinCreatePermission.test.ts +715 -0
- package/Tests/Server/Services/ScimPushGroupsTeamLocksEdition.test.ts +431 -0
- package/Tests/Server/Services/SsoRequirementReadMasking.test.ts +419 -0
- package/Tests/Server/Services/SsoRequirementWriteGuard.test.ts +769 -0
- package/Tests/Server/Services/StatusPagePrivateUserInvitationPolicy.test.ts +94 -0
- package/Tests/Server/Services/TeamMemberMultiTenantReadPostgres.test.ts +394 -0
- package/Tests/Server/Services/TeamPrivilegeEscalation.test.ts +6 -0
- package/Tests/Server/Services/TelemetryPayAsYouGoBilling.test.ts +131 -0
- package/Tests/Server/Services/UserAuthenticationService.test.ts +35 -0
- package/Tests/Server/Services/UserNotificationRuleAdminGuards.test.ts +13 -2
- package/Tests/Server/Services/UserServiceSeatLimit.test.ts +94 -56
- package/Tests/Server/Types/Database/Permissions/EditionPermission.test.ts +1823 -0
- package/Tests/Server/Types/Database/Permissions/ModelPermissionAnonymousRefusal.test.ts +518 -0
- package/Tests/Server/Types/Database/Permissions/MultiTenantPermissions.test.ts +350 -0
- package/Tests/Server/Types/Database/Permissions/OnCallCalendarFeedPermissions.test.ts +282 -25
- package/Tests/Server/Types/Database/Permissions/TableLevelBlockPermission.test.ts +459 -0
- package/Tests/Server/Types/Markdown.test.ts +181 -0
- package/Tests/Server/Utils/AI/AIRunPrivacyFilter.test.ts +101 -9
- package/Tests/Server/Utils/AI/ChatAgentHelpers.test.ts +88 -4
- package/Tests/Server/Utils/AI/Toolbox/ExceptionTools.test.ts +459 -0
- package/Tests/Server/Utils/AI/Toolbox/LogTools.test.ts +794 -0
- package/Tests/Server/Utils/AI/Toolbox/RecentChangesTools.test.ts +574 -0
- package/Tests/Server/Utils/AI/Toolbox/SecurityEventTools.test.ts +596 -0
- package/Tests/Server/Utils/CaptchaRequestAndLogging.test.ts +395 -0
- package/Tests/Server/Utils/CommunityEditionSsoReport.test.ts +565 -0
- package/Tests/Server/Utils/EditionEnforcement.test.ts +303 -0
- package/Tests/Server/Utils/FrontendEnvironment.test.ts +367 -0
- package/Tests/Server/Utils/InstanceHealth/RedisHealth.test.ts +38 -418
- package/Tests/Server/Utils/MasterAdminPageAccess.test.ts +251 -0
- package/Tests/Server/Utils/Monitor/AffectedResourceList.test.ts +518 -0
- package/Tests/Server/Utils/Monitor/Criteria/EvaluateOverTime.test.ts +24 -4
- package/Tests/Server/Utils/Monitor/MonitorActionTimestamps.test.ts +616 -0
- package/Tests/Server/Utils/Monitor/MonitorCriteriaEvaluator.test.ts +934 -96
- package/Tests/Server/Utils/Monitor/MonitoringIntervalValidator.test.ts +188 -0
- package/Tests/Server/Utils/Realtime.test.ts +502 -0
- package/Tests/Server/Utils/SecurityEvent/Connectors/GoogleSecOps/GoogleSecOpsConnectorSeverity.test.ts +216 -0
- package/Tests/Server/Utils/SecurityEvent/DetectionRuleEvaluator.test.ts +142 -0
- package/Tests/Server/Utils/SecurityEvent/GoogleSecOpsSeverityRepair.test.ts +140 -0
- package/Tests/Server/Utils/SecurityEvent/GoogleSecOpsSeverityRepairClickhouseIntegration.test.ts +542 -0
- package/Tests/Server/Utils/Telemetry/ChangeEventRow.test.ts +743 -0
- package/Tests/Server/Utils/Telemetry/RuntimeMetrics.test.ts +465 -0
- package/Tests/Server/Utils/Workspace/MicrosoftTeams/Messages/Alert.test.ts +202 -0
- package/Tests/Server/Utils/Workspace/MicrosoftTeams/Messages/Incident.test.ts +194 -0
- package/Tests/Server/Utils/Workspace/MicrosoftTeams/Messages/ScheduledMaintenance.test.ts +231 -0
- package/Tests/Server/Utils/Workspace/Slack/Messages/Alert.test.ts +194 -0
- package/Tests/Server/Utils/Workspace/Slack/Messages/AlertEpisode.test.ts +194 -0
- package/Tests/Server/Utils/Workspace/Slack/Messages/Incident.test.ts +194 -0
- package/Tests/Server/Utils/Workspace/Slack/Messages/IncidentEpisode.test.ts +194 -0
- package/Tests/Server/Utils/Workspace/Slack/Messages/ScheduledMaintenance.test.ts +247 -0
- package/Tests/Server/Utils/Workspace/Slack/SlackMarkdownSectionSplit.test.ts +1209 -0
- package/Tests/Types/AI/AIInsightEvidence.test.ts +206 -0
- package/Tests/Types/API/HostnameFromAuthority.test.ts +20 -10
- package/Tests/Types/API/HostnameIPv6.test.ts +149 -0
- package/Tests/Types/BaseDatabase/DatabaseCommonInteractionPropsUtilAnonymous.test.ts +144 -0
- package/Tests/Types/Call/CallProvider.test.ts +528 -0
- package/Tests/Types/Database/CanonicalModelInstance.test.ts +190 -0
- package/Tests/Types/Kubernetes/KubernetesCostIngest.test.ts +236 -0
- package/Tests/Types/OnCallDutyPolicy/ScheduleTimeline.test.ts +736 -0
- package/Tests/Types/OnCallDutyPolicy/ScheduleTimelineLayout.test.ts +996 -0
- package/Tests/Types/SecurityEvent/SigmaRule.test.ts +142 -0
- package/Tests/Types/Workflow/Components/JSON.test.ts +182 -0
- package/Tests/UI/Components/BasicFormDropdownNormalization.test.tsx +116 -1
- package/Tests/UI/Components/Dropdown/DropdownAsyncOptions.test.tsx +81 -0
- package/Tests/UI/Components/EditionLabelLapseCopy.ts +104 -0
- package/Tests/UI/Components/EditionLabelLicenseManagerWiring.test.tsx +254 -0
- package/Tests/UI/Components/EditionLabelLicenseRefresh.test.tsx +165 -171
- package/Tests/UI/Components/EditionLabelLicenseStatus.test.tsx +1586 -0
- package/Tests/UI/Components/EditionLabelLicenseWritesGuard.test.tsx +157 -0
- package/Tests/UI/Components/EventAttachmentList.test.tsx +174 -0
- package/Tests/UI/Components/Forms/BasicFormBurnRateTemplateDefaults.test.tsx +395 -0
- package/Tests/UI/Components/Forms/BasicFormCollapsibleSections.test.tsx +286 -0
- package/Tests/UI/Components/Forms/FormSummary.test.tsx +128 -0
- package/Tests/UI/Components/Graphs/DayUptimeGraph.test.tsx +49 -2
- package/Tests/UI/Components/MarkdownConverters.test.ts +684 -0
- package/Tests/UI/Components/ModelListEmptyState.test.tsx +289 -0
- package/Tests/UI/Components/ModelTable/BaseModelTableQueryChange.test.tsx +365 -0
- package/Tests/UI/Components/OpenAuthenticatedUrl.test.ts +358 -0
- package/Tests/UI/Components/SessionAwareImage.test.tsx +496 -0
- package/Tests/UI/Components/TelemetryHistogramZeroBuckets.test.tsx +190 -0
- package/Tests/UI/Components/TelemetryViewer/TelemetryViewerEmptyContent.test.tsx +131 -0
- package/Tests/UI/Components/TooltipInteractive.test.tsx +97 -0
- package/Tests/UI/EsbuildEnterpriseAlias.test.ts +1127 -0
- package/Tests/UI/MicrosoftTeams/MicrosoftTeamsChatsCardInstallGuidance.test.tsx +1 -1
- package/Tests/UI/Monitor/EvaluationLogListTimestamps.test.tsx +367 -0
- package/Tests/UI/Utils/API/BaseAPIRefreshSession.test.ts +1087 -0
- package/Tests/UI/Utils/API/DashboardHost.ts +12 -0
- package/Tests/UI/Utils/API/FakeAxiosServer.ts +183 -0
- package/Tests/UI/Utils/Breadcrumb/fixtures/RealBreadcrumbTrails.ts +10 -0
- package/Tests/UI/Utils/Breadcrumb/fixtures/RealRoutePatterns.ts +2 -0
- package/Tests/UI/Utils/Cookie.test.ts +440 -0
- package/Tests/UI/Utils/ModelAPIRequestClient.test.ts +278 -0
- package/Tests/UI/Utils/Navigation.test.ts +33 -0
- package/Tests/UI/Utils/PricingPlan.test.ts +295 -0
- package/Tests/UI/Utils/Realtime.test.ts +759 -0
- package/Tests/UI/Utils/Telemetry/Telemetry.test.ts +500 -0
- package/Tests/Utils/APIInstanceDispatch.test.ts +311 -0
- package/Tests/Utils/HostAddressUtil.test.ts +138 -0
- package/Tests/Utils/Monitor/MonitorDestinationUtil.test.ts +313 -0
- package/Tests/Utils/Monitor/MonitoringIntervalUtil.test.ts +304 -0
- package/Tests/Utils/SecurityEvent/GoogleSecOpsAlertNormalizerSeverity.test.ts +565 -0
- package/Tests/Utils/StatusPage/UptimeDailyAggregateUtil.test.ts +248 -0
- package/Types/API/Hostname.ts +63 -16
- package/Types/BaseDatabase/DatabaseCommonInteractionPropsUtil.ts +40 -0
- package/Types/Database/AccessControl/ColumnAccessControl.ts +19 -7
- package/Types/Database/AccessControl/ColumnBillingAccessControl.ts +19 -7
- package/Types/Database/AccessControl/OwnerOnlyColumn.ts +15 -6
- package/Types/Database/CanonicalModelInstance.ts +102 -0
- package/Types/Database/TableColumn.ts +20 -6
- package/Types/EnterpriseLicense/EnterpriseLicensePeriods.ts +29 -0
- package/Types/IP/IPv6.ts +6 -1
- package/Types/Monitor/MonitorEvaluationSummary.ts +3 -0
- package/Types/Monitor/MonitorStep.ts +6 -1
- package/Types/Monitor/ProxmoxAlertTemplates.ts +1 -1
- package/Types/OnCallDutyPolicy/ScheduleTimeline.ts +507 -0
- package/Types/OnCallDutyPolicy/ScheduleTimelineLayout.ts +589 -0
- package/Types/Realtime/EventName.ts +11 -0
- package/Types/SecurityEvent/DetectionFindingConstants.ts +14 -0
- package/Types/SecurityEvent/OcsfSeverity.ts +31 -26
- package/Types/SecurityEvent/SigmaRule.ts +51 -0
- package/Types/SecurityEvent/ThreatIntelConstants.ts +18 -0
- package/Types/StatusPage/UptimeDailyAggregate.ts +110 -0
- package/UI/Components/AttachmentList/EventAttachmentList.tsx +30 -2
- package/UI/Components/Dashboard/DashboardVariableControl.tsx +12 -2
- package/UI/Components/Dropdown/Dropdown.tsx +6 -1
- package/UI/Components/EditionLabel/EditionLabel.tsx +808 -1195
- package/UI/Components/EditionLabel/LicenseManager.ts +119 -0
- package/UI/Components/EventItem/EventItem.tsx +12 -1
- package/UI/Components/Forms/BasicForm.tsx +151 -126
- package/UI/Components/Forms/CollapsibleFormSection.tsx +63 -0
- package/UI/Components/Forms/Fields/FormField.tsx +10 -4
- package/UI/Components/Forms/FormSummary.tsx +7 -0
- package/UI/Components/Forms/Types/Field.ts +10 -0
- package/UI/Components/Graphs/DayUptimeGraph.tsx +123 -15
- package/UI/Components/Markdown.tsx/MarkdownConverters.ts +0 -0
- package/UI/Components/Markdown.tsx/MarkdownViewer.tsx +2 -1
- package/UI/Components/Markdown.tsx/SessionAwareImage.tsx +122 -0
- package/UI/Components/ModelList/ModelList.tsx +11 -1
- package/UI/Components/ModelTable/BaseModelTable.tsx +34 -5
- package/UI/Components/ModelTable/TableView.tsx +1 -1
- package/UI/Components/MonitorGraphs/Uptime.tsx +69 -0
- package/UI/Components/TelemetryViewer/TelemetryViewer.tsx +28 -12
- package/UI/Components/TelemetryViewer/components/TelemetryHistogram.tsx +8 -1
- package/UI/Components/Tooltip/Tooltip.tsx +8 -1
- package/UI/Utils/API/API.ts +173 -12
- package/UI/Utils/API/RequestOptions.ts +11 -0
- package/UI/Utils/AnalyticsModelAPI/AnalyticsModelAPI.ts +31 -7
- package/UI/Utils/ModelAPI/ModelAPI.ts +30 -9
- package/UI/Utils/Navigation.ts +9 -0
- package/UI/Utils/OpenAuthenticatedUrl.ts +154 -0
- package/UI/Utils/Realtime.ts +176 -30
- package/UI/esbuild-enterprise.js +263 -0
- package/Utils/API.ts +14 -5
- package/Utils/EnterpriseLicense/EnterpriseLicenseUsage.ts +7 -2
- package/Utils/HostAddressUtil.ts +94 -0
- package/Utils/Monitor/MonitorDestinationUtil.ts +157 -0
- package/Utils/Monitor/MonitoringIntervalUtil.ts +436 -0
- package/Utils/SecurityEvent/GoogleSecOpsAlertNormalizer.ts +157 -7
- package/Utils/SecurityEvent/Sigma/SigmaRuleParser.ts +9 -17
- package/Utils/Slo/SloBurnRateTemplate.ts +2 -2
- package/Utils/StatusPage/UptimeDailyAggregateUtil.ts +192 -0
- package/build/dist/Models/AnalyticsModels/AuditLog.js +23 -15
- package/build/dist/Models/AnalyticsModels/AuditLog.js.map +1 -1
- package/build/dist/Models/DatabaseModels/GlobalConfig.js +25 -0
- package/build/dist/Models/DatabaseModels/GlobalConfig.js.map +1 -1
- package/build/dist/Models/DatabaseModels/Monitor.js +2 -2
- package/build/dist/Models/DatabaseModels/Monitor.js.map +1 -1
- package/build/dist/Models/DatabaseModels/MonitorTemplate.js +2 -1
- package/build/dist/Models/DatabaseModels/MonitorTemplate.js.map +1 -1
- package/build/dist/Models/DatabaseModels/OnCallDutyPolicyScheduleCalendarFeed.js +1 -1
- package/build/dist/Models/DatabaseModels/OnCallDutyPolicyScheduleCalendarFeed.js.map +1 -1
- package/build/dist/Models/DatabaseModels/ProjectOnCallCalendarFeed.js +1 -1
- package/build/dist/Models/DatabaseModels/ProjectOnCallCalendarFeed.js.map +1 -1
- package/build/dist/Models/DatabaseModels/UserOnCallCalendarFeed.js +1 -1
- package/build/dist/Models/DatabaseModels/UserOnCallCalendarFeed.js.map +1 -1
- package/build/dist/Server/API/AIBillingAPI.js +1 -1
- package/build/dist/Server/API/AIBillingAPI.js.map +1 -1
- package/build/dist/Server/API/AIInsightAPI.js +1 -4
- package/build/dist/Server/API/AIInsightAPI.js.map +1 -1
- package/build/dist/Server/API/AIInvestigationAPI.js +1 -4
- package/build/dist/Server/API/AIInvestigationAPI.js.map +1 -1
- package/build/dist/Server/API/AIReadinessAPI.js +1 -3
- package/build/dist/Server/API/AIReadinessAPI.js.map +1 -1
- package/build/dist/Server/API/AlertAPI.js +1 -1
- package/build/dist/Server/API/AlertAPI.js.map +1 -1
- package/build/dist/Server/API/AutoRemediationAPI.js +1 -4
- package/build/dist/Server/API/AutoRemediationAPI.js.map +1 -1
- package/build/dist/Server/API/BaseAPI.js +33 -0
- package/build/dist/Server/API/BaseAPI.js.map +1 -1
- package/build/dist/Server/API/BaseAnalyticsAPI.js +55 -10
- package/build/dist/Server/API/BaseAnalyticsAPI.js.map +1 -1
- package/build/dist/Server/API/BillingAPI.js +2 -2
- package/build/dist/Server/API/BillingAPI.js.map +1 -1
- package/build/dist/Server/API/BillingInvoiceAPI.js +1 -1
- package/build/dist/Server/API/BillingInvoiceAPI.js.map +1 -1
- package/build/dist/Server/API/BillingPaymentMethodAPI.js +2 -2
- package/build/dist/Server/API/BillingPaymentMethodAPI.js.map +1 -1
- package/build/dist/Server/API/CodeFixRunAPI.js +1 -3
- package/build/dist/Server/API/CodeFixRunAPI.js.map +1 -1
- package/build/dist/Server/API/CommonAPI.js +50 -5
- package/build/dist/Server/API/CommonAPI.js.map +1 -1
- package/build/dist/Server/API/DashboardAPI.js +12 -12
- package/build/dist/Server/API/DashboardAPI.js.map +1 -1
- package/build/dist/Server/API/GlobalConfigAPI.js +158 -342
- package/build/dist/Server/API/GlobalConfigAPI.js.map +1 -1
- package/build/dist/Server/API/IncidentAPI.js +2 -2
- package/build/dist/Server/API/IncidentAPI.js.map +1 -1
- package/build/dist/Server/API/IncidentEpisodeAPI.js +1 -1
- package/build/dist/Server/API/IncidentEpisodeAPI.js.map +1 -1
- package/build/dist/Server/API/NotificationAPI.js +1 -1
- package/build/dist/Server/API/NotificationAPI.js.map +1 -1
- package/build/dist/Server/API/OnCallCalendarAPI.js +1 -4
- package/build/dist/Server/API/OnCallCalendarAPI.js.map +1 -1
- package/build/dist/Server/API/OnCallDutyPolicyAPI.js +6 -0
- package/build/dist/Server/API/OnCallDutyPolicyAPI.js.map +1 -1
- package/build/dist/Server/API/OnCallReadinessAPI.js +4 -1
- package/build/dist/Server/API/OnCallReadinessAPI.js.map +1 -1
- package/build/dist/Server/API/OnCallScheduleTimelineAPI.js +494 -0
- package/build/dist/Server/API/OnCallScheduleTimelineAPI.js.map +1 -0
- package/build/dist/Server/API/ProjectAPI.js +1 -1
- package/build/dist/Server/API/ProjectAPI.js.map +1 -1
- package/build/dist/Server/API/ProjectOIDC.js +24 -16
- package/build/dist/Server/API/ProjectOIDC.js.map +1 -1
- package/build/dist/Server/API/ProjectSSO.js +24 -16
- package/build/dist/Server/API/ProjectSSO.js.map +1 -1
- package/build/dist/Server/API/ScheduledMaintenanceAPI.js +1 -1
- package/build/dist/Server/API/ScheduledMaintenanceAPI.js.map +1 -1
- package/build/dist/Server/API/StatusPageAPI.js +218 -76
- package/build/dist/Server/API/StatusPageAPI.js.map +1 -1
- package/build/dist/Server/API/TeamMemberAPI.js +11 -4
- package/build/dist/Server/API/TeamMemberAPI.js.map +1 -1
- package/build/dist/Server/API/UserCallAPI.js +2 -2
- package/build/dist/Server/API/UserCallAPI.js.map +1 -1
- package/build/dist/Server/API/UserEmailAPI.js +2 -2
- package/build/dist/Server/API/UserEmailAPI.js.map +1 -1
- package/build/dist/Server/API/UserIncomingCallNumberAPI.js +2 -2
- package/build/dist/Server/API/UserIncomingCallNumberAPI.js.map +1 -1
- package/build/dist/Server/API/UserMicrosoftTeamsAPI.js +1 -1
- package/build/dist/Server/API/UserMicrosoftTeamsAPI.js.map +1 -1
- package/build/dist/Server/API/UserSlackAPI.js +1 -1
- package/build/dist/Server/API/UserSlackAPI.js.map +1 -1
- package/build/dist/Server/API/UserSmsAPI.js +2 -2
- package/build/dist/Server/API/UserSmsAPI.js.map +1 -1
- package/build/dist/Server/API/UserTotpAuthAPI.js +1 -1
- package/build/dist/Server/API/UserTotpAuthAPI.js.map +1 -1
- package/build/dist/Server/API/UserWebAuthnAPI.js +2 -2
- package/build/dist/Server/API/UserWebAuthnAPI.js.map +1 -1
- package/build/dist/Server/API/UserWebhookAPI.js +1 -1
- package/build/dist/Server/API/UserWebhookAPI.js.map +1 -1
- package/build/dist/Server/API/UserWhatsAppAPI.js +2 -2
- package/build/dist/Server/API/UserWhatsAppAPI.js.map +1 -1
- package/build/dist/Server/Enterprise/EnterpriseEdition.js +466 -0
- package/build/dist/Server/Enterprise/EnterpriseEdition.js.map +1 -0
- package/build/dist/Server/Enterprise/EnterpriseFeature.js +39 -0
- package/build/dist/Server/Enterprise/EnterpriseFeature.js.map +1 -0
- package/build/dist/Server/Enterprise/EnterpriseLicenseSnapshot.js +70 -0
- package/build/dist/Server/Enterprise/EnterpriseLicenseSnapshot.js.map +1 -0
- package/build/dist/Server/Enterprise/EnterpriseServerModule.js +84 -0
- package/build/dist/Server/Enterprise/EnterpriseServerModule.js.map +1 -0
- package/build/dist/Server/EnvironmentConfig.js +84 -2
- package/build/dist/Server/EnvironmentConfig.js.map +1 -1
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1793900000000-AddEnterpriseEditionFirstSeenAt.js +18 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1793900000000-AddEnterpriseEditionFirstSeenAt.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +2 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
- package/build/dist/Server/Middleware/MasterAdminAuthorization.js +11 -2
- package/build/dist/Server/Middleware/MasterAdminAuthorization.js.map +1 -1
- package/build/dist/Server/Middleware/UserAuthorization.js +94 -15
- package/build/dist/Server/Middleware/UserAuthorization.js.map +1 -1
- package/build/dist/Server/Services/ApiKeyPermissionService.js +80 -4
- package/build/dist/Server/Services/ApiKeyPermissionService.js.map +1 -1
- package/build/dist/Server/Services/AuditLogService.js +71 -740
- package/build/dist/Server/Services/AuditLogService.js.map +1 -1
- package/build/dist/Server/Services/DatabaseService.js +171 -0
- package/build/dist/Server/Services/DatabaseService.js.map +1 -1
- package/build/dist/Server/Services/DetectionRuleService.js +4 -4
- package/build/dist/Server/Services/DetectionRuleService.js.map +1 -1
- package/build/dist/Server/Services/EnterpriseLicenseService.js +34 -0
- package/build/dist/Server/Services/EnterpriseLicenseService.js.map +1 -1
- package/build/dist/Server/Services/GlobalConfigService.js +63 -0
- package/build/dist/Server/Services/GlobalConfigService.js.map +1 -1
- package/build/dist/Server/Services/MonitorProbeService.js +90 -17
- package/build/dist/Server/Services/MonitorProbeService.js.map +1 -1
- package/build/dist/Server/Services/MonitorService.js +45 -4
- package/build/dist/Server/Services/MonitorService.js.map +1 -1
- package/build/dist/Server/Services/MonitorStatusTimelineService.js +242 -0
- package/build/dist/Server/Services/MonitorStatusTimelineService.js.map +1 -1
- package/build/dist/Server/Services/MonitorTemplateService.js +16 -0
- package/build/dist/Server/Services/MonitorTemplateService.js.map +1 -1
- package/build/dist/Server/Services/OnCallDutyPolicyChildService.js +170 -0
- package/build/dist/Server/Services/OnCallDutyPolicyChildService.js.map +1 -0
- package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleScheduleService.js +2 -2
- package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleScheduleService.js.map +1 -1
- package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleService.js +2 -2
- package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleService.js.map +1 -1
- package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleTeamService.js +2 -2
- package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleTeamService.js.map +1 -1
- package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleUserService.js +2 -2
- package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleUserService.js.map +1 -1
- package/build/dist/Server/Services/PayAsYouGoBillingService.js +20 -27
- package/build/dist/Server/Services/PayAsYouGoBillingService.js.map +1 -1
- package/build/dist/Server/Services/ProjectService.js +231 -0
- package/build/dist/Server/Services/ProjectService.js.map +1 -1
- package/build/dist/Server/Services/RumSessionPinService.js +198 -16
- package/build/dist/Server/Services/RumSessionPinService.js.map +1 -1
- package/build/dist/Server/Services/StatusPagePrivateUserService.js +7 -3
- package/build/dist/Server/Services/StatusPagePrivateUserService.js.map +1 -1
- package/build/dist/Server/Services/StatusPageService.js +71 -0
- package/build/dist/Server/Services/StatusPageService.js.map +1 -1
- package/build/dist/Server/Services/TeamMemberService.js +10 -0
- package/build/dist/Server/Services/TeamMemberService.js.map +1 -1
- package/build/dist/Server/Services/TeamPermissionService.js +89 -27
- package/build/dist/Server/Services/TeamPermissionService.js.map +1 -1
- package/build/dist/Server/Services/TeamService.js +9 -0
- package/build/dist/Server/Services/TeamService.js.map +1 -1
- package/build/dist/Server/Services/ThreatIntelFeedService.js +5 -4
- package/build/dist/Server/Services/ThreatIntelFeedService.js.map +1 -1
- package/build/dist/Server/Services/UserService.js +10 -16
- package/build/dist/Server/Services/UserService.js.map +1 -1
- package/build/dist/Server/Types/Database/Permissions/BasePermission.js +9 -6
- package/build/dist/Server/Types/Database/Permissions/BasePermission.js.map +1 -1
- package/build/dist/Server/Types/Database/Permissions/CreatePermission.js +10 -0
- package/build/dist/Server/Types/Database/Permissions/CreatePermission.js.map +1 -1
- package/build/dist/Server/Types/Database/Permissions/EditionPermission.js +154 -14
- package/build/dist/Server/Types/Database/Permissions/EditionPermission.js.map +1 -1
- package/build/dist/Server/Types/Database/Permissions/Index.js +60 -6
- package/build/dist/Server/Types/Database/Permissions/Index.js.map +1 -1
- package/build/dist/Server/Types/Database/Permissions/TablePermission.js +24 -16
- package/build/dist/Server/Types/Database/Permissions/TablePermission.js.map +1 -1
- package/build/dist/Server/Types/Database/Permissions/UpdatePermission.js +17 -0
- package/build/dist/Server/Types/Database/Permissions/UpdatePermission.js.map +1 -1
- package/build/dist/Server/Types/Markdown.js +31 -0
- package/build/dist/Server/Types/Markdown.js.map +1 -1
- package/build/dist/Server/Utils/AI/AIChatPrivacyFilter.js +7 -0
- package/build/dist/Server/Utils/AI/AIChatPrivacyFilter.js.map +1 -1
- package/build/dist/Server/Utils/AI/AIRunPrivacyFilter.js +7 -0
- package/build/dist/Server/Utils/AI/AIRunPrivacyFilter.js.map +1 -1
- package/build/dist/Server/Utils/CommunityEditionSsoReport.js +223 -0
- package/build/dist/Server/Utils/CommunityEditionSsoReport.js.map +1 -0
- package/build/dist/Server/Utils/EditionEnforcement.js +187 -0
- package/build/dist/Server/Utils/EditionEnforcement.js.map +1 -0
- package/build/dist/Server/Utils/FrontendEnvironment.js +31 -2
- package/build/dist/Server/Utils/FrontendEnvironment.js.map +1 -1
- package/build/dist/Server/Utils/InstanceHealth/RedisHealth.js +6 -193
- package/build/dist/Server/Utils/InstanceHealth/RedisHealth.js.map +1 -1
- package/build/dist/Server/Utils/MasterAdminPageAccess.js +39 -0
- package/build/dist/Server/Utils/MasterAdminPageAccess.js.map +1 -0
- package/build/dist/Server/Utils/Monitor/AffectedResourceList.js +96 -0
- package/build/dist/Server/Utils/Monitor/AffectedResourceList.js.map +1 -0
- package/build/dist/Server/Utils/Monitor/Criteria/EvaluateOverTime.js +8 -1
- package/build/dist/Server/Utils/Monitor/Criteria/EvaluateOverTime.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorAlert.js +3 -1
- package/build/dist/Server/Utils/Monitor/MonitorAlert.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js +449 -261
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorIncident.js +3 -1
- package/build/dist/Server/Utils/Monitor/MonitorIncident.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitoringIntervalValidator.js +88 -0
- package/build/dist/Server/Utils/Monitor/MonitoringIntervalValidator.js.map +1 -0
- package/build/dist/Server/Utils/Realtime.js +126 -37
- package/build/dist/Server/Utils/Realtime.js.map +1 -1
- package/build/dist/Server/Utils/SecurityEvent/DetectionRuleEvaluator.js +7 -25
- package/build/dist/Server/Utils/SecurityEvent/DetectionRuleEvaluator.js.map +1 -1
- package/build/dist/Server/Utils/SecurityEvent/GoogleSecOpsSeverityRepair.js +127 -0
- package/build/dist/Server/Utils/SecurityEvent/GoogleSecOpsSeverityRepair.js.map +1 -0
- package/build/dist/Server/Utils/SecurityEvent/Sigma/SigmaClickhouseCompiler.js +1 -1
- package/build/dist/Server/Utils/SecurityEvent/Sigma/SigmaClickhouseCompiler.js.map +1 -1
- package/build/dist/Server/Utils/SecurityEvent/ThreatIntel/ThreatIntelFeedPoller.js +3 -2
- package/build/dist/Server/Utils/SecurityEvent/ThreatIntel/ThreatIntelFeedPoller.js.map +1 -1
- package/build/dist/Server/Utils/SecurityEvent/ThreatIntel/ThreatIntelMatcher.js +4 -8
- package/build/dist/Server/Utils/SecurityEvent/ThreatIntel/ThreatIntelMatcher.js.map +1 -1
- package/build/dist/Server/Utils/Workspace/Slack/Slack.js +331 -11
- package/build/dist/Server/Utils/Workspace/Slack/Slack.js.map +1 -1
- package/build/dist/Types/API/Hostname.js +59 -11
- package/build/dist/Types/API/Hostname.js.map +1 -1
- package/build/dist/Types/BaseDatabase/DatabaseCommonInteractionPropsUtil.js +31 -1
- package/build/dist/Types/BaseDatabase/DatabaseCommonInteractionPropsUtil.js.map +1 -1
- package/build/dist/Types/Database/AccessControl/ColumnAccessControl.js +19 -7
- package/build/dist/Types/Database/AccessControl/ColumnAccessControl.js.map +1 -1
- package/build/dist/Types/Database/AccessControl/ColumnBillingAccessControl.js +19 -7
- package/build/dist/Types/Database/AccessControl/ColumnBillingAccessControl.js.map +1 -1
- package/build/dist/Types/Database/AccessControl/OwnerOnlyColumn.js +13 -6
- package/build/dist/Types/Database/AccessControl/OwnerOnlyColumn.js.map +1 -1
- package/build/dist/Types/Database/CanonicalModelInstance.js +88 -0
- package/build/dist/Types/Database/CanonicalModelInstance.js.map +1 -0
- package/build/dist/Types/Database/TableColumn.js +19 -6
- package/build/dist/Types/Database/TableColumn.js.map +1 -1
- package/build/dist/Types/EnterpriseLicense/EnterpriseLicensePeriods.js +28 -0
- package/build/dist/Types/EnterpriseLicense/EnterpriseLicensePeriods.js.map +1 -0
- package/build/dist/Types/IP/IPv6.js +6 -1
- package/build/dist/Types/IP/IPv6.js.map +1 -1
- package/build/dist/Types/Monitor/MonitorStep.js +5 -0
- package/build/dist/Types/Monitor/MonitorStep.js.map +1 -1
- package/build/dist/Types/Monitor/ProxmoxAlertTemplates.js +1 -1
- package/build/dist/Types/OnCallDutyPolicy/ScheduleTimeline.js +321 -0
- package/build/dist/Types/OnCallDutyPolicy/ScheduleTimeline.js.map +1 -0
- package/build/dist/Types/OnCallDutyPolicy/ScheduleTimelineLayout.js +372 -0
- package/build/dist/Types/OnCallDutyPolicy/ScheduleTimelineLayout.js.map +1 -0
- package/build/dist/Types/Realtime/EventName.js +10 -0
- package/build/dist/Types/Realtime/EventName.js.map +1 -1
- package/build/dist/Types/SecurityEvent/DetectionFindingConstants.js +11 -0
- package/build/dist/Types/SecurityEvent/DetectionFindingConstants.js.map +1 -1
- package/build/dist/Types/SecurityEvent/OcsfSeverity.js +30 -25
- package/build/dist/Types/SecurityEvent/OcsfSeverity.js.map +1 -1
- package/build/dist/Types/SecurityEvent/SigmaRule.js +47 -0
- package/build/dist/Types/SecurityEvent/SigmaRule.js.map +1 -1
- package/build/dist/Types/SecurityEvent/ThreatIntelConstants.js +14 -0
- package/build/dist/Types/SecurityEvent/ThreatIntelConstants.js.map +1 -1
- package/build/dist/Types/StatusPage/UptimeDailyAggregate.js +32 -0
- package/build/dist/Types/StatusPage/UptimeDailyAggregate.js.map +1 -0
- package/build/dist/UI/Components/AttachmentList/EventAttachmentList.js +9 -4
- package/build/dist/UI/Components/AttachmentList/EventAttachmentList.js.map +1 -1
- package/build/dist/UI/Components/Dashboard/DashboardVariableControl.js +10 -2
- package/build/dist/UI/Components/Dashboard/DashboardVariableControl.js.map +1 -1
- package/build/dist/UI/Components/Dropdown/Dropdown.js +5 -1
- package/build/dist/UI/Components/Dropdown/Dropdown.js.map +1 -1
- package/build/dist/UI/Components/EditionLabel/EditionLabel.js +425 -585
- package/build/dist/UI/Components/EditionLabel/EditionLabel.js.map +1 -1
- package/build/dist/UI/Components/EditionLabel/LicenseManager.js +2 -0
- package/build/dist/UI/Components/EditionLabel/LicenseManager.js.map +1 -0
- package/build/dist/UI/Components/EventItem/EventItem.js +2 -2
- package/build/dist/UI/Components/EventItem/EventItem.js.map +1 -1
- package/build/dist/UI/Components/Forms/BasicForm.js +70 -64
- package/build/dist/UI/Components/Forms/BasicForm.js.map +1 -1
- package/build/dist/UI/Components/Forms/CollapsibleFormSection.js +27 -0
- package/build/dist/UI/Components/Forms/CollapsibleFormSection.js.map +1 -0
- package/build/dist/UI/Components/Forms/Fields/FormField.js +10 -7
- package/build/dist/UI/Components/Forms/Fields/FormField.js.map +1 -1
- package/build/dist/UI/Components/Forms/FormSummary.js +7 -0
- package/build/dist/UI/Components/Forms/FormSummary.js.map +1 -1
- package/build/dist/UI/Components/Graphs/DayUptimeGraph.js +90 -17
- package/build/dist/UI/Components/Graphs/DayUptimeGraph.js.map +1 -1
- package/build/dist/UI/Components/Markdown.tsx/MarkdownConverters.js +0 -0
- package/build/dist/UI/Components/Markdown.tsx/MarkdownConverters.js.map +1 -1
- package/build/dist/UI/Components/Markdown.tsx/MarkdownViewer.js +2 -1
- package/build/dist/UI/Components/Markdown.tsx/MarkdownViewer.js.map +1 -1
- package/build/dist/UI/Components/Markdown.tsx/SessionAwareImage.js +84 -0
- package/build/dist/UI/Components/Markdown.tsx/SessionAwareImage.js.map +1 -0
- package/build/dist/UI/Components/ModelList/ModelList.js +4 -1
- package/build/dist/UI/Components/ModelList/ModelList.js.map +1 -1
- package/build/dist/UI/Components/ModelTable/BaseModelTable.js +14 -1
- package/build/dist/UI/Components/ModelTable/BaseModelTable.js.map +1 -1
- package/build/dist/UI/Components/ModelTable/TableView.js +1 -1
- package/build/dist/UI/Components/ModelTable/TableView.js.map +1 -1
- package/build/dist/UI/Components/MonitorGraphs/Uptime.js +42 -1
- package/build/dist/UI/Components/MonitorGraphs/Uptime.js.map +1 -1
- package/build/dist/UI/Components/TelemetryViewer/TelemetryViewer.js +2 -2
- package/build/dist/UI/Components/TelemetryViewer/TelemetryViewer.js.map +1 -1
- package/build/dist/UI/Components/TelemetryViewer/components/TelemetryHistogram.js +8 -1
- package/build/dist/UI/Components/TelemetryViewer/components/TelemetryHistogram.js.map +1 -1
- package/build/dist/UI/Components/Tooltip/Tooltip.js +2 -1
- package/build/dist/UI/Components/Tooltip/Tooltip.js.map +1 -1
- package/build/dist/UI/Utils/API/API.js +143 -19
- package/build/dist/UI/Utils/API/API.js.map +1 -1
- package/build/dist/UI/Utils/AnalyticsModelAPI/AnalyticsModelAPI.js +21 -7
- package/build/dist/UI/Utils/AnalyticsModelAPI/AnalyticsModelAPI.js.map +1 -1
- package/build/dist/UI/Utils/ModelAPI/ModelAPI.js +26 -9
- package/build/dist/UI/Utils/ModelAPI/ModelAPI.js.map +1 -1
- package/build/dist/UI/Utils/Navigation.js +8 -0
- package/build/dist/UI/Utils/Navigation.js.map +1 -1
- package/build/dist/UI/Utils/OpenAuthenticatedUrl.js +92 -0
- package/build/dist/UI/Utils/OpenAuthenticatedUrl.js.map +1 -0
- package/build/dist/UI/Utils/Realtime.js +120 -15
- package/build/dist/UI/Utils/Realtime.js.map +1 -1
- package/build/dist/Utils/API.js +13 -5
- package/build/dist/Utils/API.js.map +1 -1
- package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseUsage.js +6 -2
- package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseUsage.js.map +1 -1
- package/build/dist/Utils/HostAddressUtil.js +80 -0
- package/build/dist/Utils/HostAddressUtil.js.map +1 -0
- package/build/dist/Utils/Monitor/MonitorDestinationUtil.js +127 -0
- package/build/dist/Utils/Monitor/MonitorDestinationUtil.js.map +1 -0
- package/build/dist/Utils/Monitor/MonitoringIntervalUtil.js +374 -0
- package/build/dist/Utils/Monitor/MonitoringIntervalUtil.js.map +1 -0
- package/build/dist/Utils/SecurityEvent/GoogleSecOpsAlertNormalizer.js +123 -6
- package/build/dist/Utils/SecurityEvent/GoogleSecOpsAlertNormalizer.js.map +1 -1
- package/build/dist/Utils/SecurityEvent/Sigma/SigmaRuleParser.js +4 -18
- package/build/dist/Utils/SecurityEvent/Sigma/SigmaRuleParser.js.map +1 -1
- package/build/dist/Utils/Slo/SloBurnRateTemplate.js +2 -2
- package/build/dist/Utils/StatusPage/UptimeDailyAggregateUtil.js +148 -0
- package/build/dist/Utils/StatusPage/UptimeDailyAggregateUtil.js.map +1 -0
- package/jest.config.json +3 -1
- package/package.json +1 -1
- package/test-setup.sh +103 -34
- package/tsconfig.json +13 -0
- package/Server/API/EnterpriseLicenseAPI.ts +0 -925
- package/Server/API/TeamComplianceAPI.ts +0 -158
- package/Server/Middleware/SCIMAuthorization.ts +0 -141
- package/Server/Services/TeamComplianceService.ts +0 -733
- package/Server/Utils/EnterpriseLicense/EnterpriseLicenseSeatUtil.ts +0 -186
- package/Server/Utils/InstanceHealth/PostgresHealth.ts +0 -286
- package/Tests/App/AdminDashboard/EnterpriseLicenseInstanceActivity.test.tsx +0 -451
- package/Tests/App/Dashboard/AuditLogsTable.test.tsx +0 -598
- package/Tests/App/Dashboard/SecurityEventsSideMenu.test.tsx +0 -247
- package/Tests/App/Dashboard/SecurityEventsTableColumns.test.tsx +0 -382
- package/Tests/Server/API/EnterpriseLicenseReportUserCount.test.ts +0 -1851
- package/Tests/Server/Middleware/SCIMAuthorization.test.ts +0 -525
- package/Tests/Server/Services/TeamComplianceServiceBehaviour.test.ts +0 -1845
- package/Tests/Server/Utils/EnterpriseLicense/EnterpriseLicenseSeatUtil.test.ts +0 -495
- package/Tests/Server/Utils/InstanceHealth/PostgresHealth.test.ts +0 -337
- package/Tests/Utils/EnterpriseLicenseSeats.test.ts +0 -576
- package/Tests/Utils/EnterpriseLicenseSync.test.ts +0 -568
- package/Utils/EnterpriseLicense/EnterpriseLicenseSeats.ts +0 -287
- package/Utils/EnterpriseLicense/EnterpriseLicenseSync.ts +0 -244
- package/build/dist/Server/API/EnterpriseLicenseAPI.js +0 -646
- package/build/dist/Server/API/EnterpriseLicenseAPI.js.map +0 -1
- package/build/dist/Server/API/TeamComplianceAPI.js +0 -111
- package/build/dist/Server/API/TeamComplianceAPI.js.map +0 -1
- package/build/dist/Server/Middleware/SCIMAuthorization.js +0 -124
- package/build/dist/Server/Middleware/SCIMAuthorization.js.map +0 -1
- package/build/dist/Server/Services/TeamComplianceService.js +0 -537
- package/build/dist/Server/Services/TeamComplianceService.js.map +0 -1
- package/build/dist/Server/Utils/EnterpriseLicense/EnterpriseLicenseSeatUtil.js +0 -145
- package/build/dist/Server/Utils/EnterpriseLicense/EnterpriseLicenseSeatUtil.js.map +0 -1
- package/build/dist/Server/Utils/InstanceHealth/PostgresHealth.js +0 -194
- package/build/dist/Server/Utils/InstanceHealth/PostgresHealth.js.map +0 -1
- package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseSeats.js +0 -168
- package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseSeats.js.map +0 -1
- package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseSync.js +0 -174
- 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
|
|
4
|
-
import
|
|
5
|
-
import
|
|
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
|
|
18
|
-
import {
|
|
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
|
-
|
|
29
|
-
const
|
|
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
|
-
*
|
|
33
|
-
*
|
|
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.
|
|
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
|
-
|
|
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
|
-
|
|
124
|
-
|
|
125
|
-
|
|
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
|
-
|
|
136
|
-
|
|
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
|
-
|
|
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
|
-
|
|
172
|
-
|
|
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
|
-
|
|
199
|
-
|
|
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
|
-
|
|
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
|
-
|
|
873
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1124
|
-
|
|
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
|
|