@oneuptime/common 13.0.5 → 13.0.7
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 +81 -1
- package/Models/AnalyticsModels/SecurityEvent.ts +4 -4
- package/Models/DatabaseModels/AIAgentOwnerTeam.ts +6 -0
- package/Models/DatabaseModels/AIAgentOwnerUser.ts +6 -0
- package/Models/DatabaseModels/Alert.ts +74 -0
- package/Models/DatabaseModels/AlertEpisodeOwnerTeam.ts +6 -1
- package/Models/DatabaseModels/AlertEpisodeOwnerUser.ts +6 -1
- package/Models/DatabaseModels/AlertOwnerTeam.ts +6 -1
- package/Models/DatabaseModels/AlertOwnerUser.ts +6 -1
- package/Models/DatabaseModels/CephClusterOwnerTeam.ts +6 -0
- package/Models/DatabaseModels/CephClusterOwnerUser.ts +6 -0
- package/Models/DatabaseModels/CloudResourceOwnerTeam.ts +6 -0
- package/Models/DatabaseModels/CloudResourceOwnerUser.ts +6 -0
- package/Models/DatabaseModels/DashboardOwnerTeam.ts +6 -1
- package/Models/DatabaseModels/DashboardOwnerUser.ts +6 -1
- package/Models/DatabaseModels/DatabaseBaseModel/DatabaseBaseModel.ts +8 -0
- package/Models/DatabaseModels/DockerHostOwnerTeam.ts +6 -0
- package/Models/DatabaseModels/DockerHostOwnerUser.ts +6 -0
- package/Models/DatabaseModels/DockerSwarmClusterOwnerTeam.ts +6 -0
- package/Models/DatabaseModels/DockerSwarmClusterOwnerUser.ts +6 -0
- package/Models/DatabaseModels/GlobalConfig.ts +1 -1
- package/Models/DatabaseModels/HostOwnerTeam.ts +6 -0
- package/Models/DatabaseModels/HostOwnerUser.ts +6 -0
- package/Models/DatabaseModels/Incident.ts +78 -0
- package/Models/DatabaseModels/IncidentEpisodeOwnerTeam.ts +6 -1
- package/Models/DatabaseModels/IncidentEpisodeOwnerUser.ts +6 -1
- package/Models/DatabaseModels/IncidentEpisodePublicNote.ts +74 -0
- package/Models/DatabaseModels/IncidentOwnerTeam.ts +6 -1
- package/Models/DatabaseModels/IncidentOwnerUser.ts +6 -1
- package/Models/DatabaseModels/IncidentPublicNote.ts +74 -0
- package/Models/DatabaseModels/IncidentTemplateOwnerTeam.ts +6 -0
- package/Models/DatabaseModels/IncidentTemplateOwnerUser.ts +6 -0
- package/Models/DatabaseModels/IncomingCallPolicyOwnerTeam.ts +6 -1
- package/Models/DatabaseModels/IncomingCallPolicyOwnerUser.ts +6 -1
- package/Models/DatabaseModels/Index.ts +6 -4
- package/Models/DatabaseModels/IoTFleetOwnerTeam.ts +6 -0
- package/Models/DatabaseModels/IoTFleetOwnerUser.ts +6 -0
- package/Models/DatabaseModels/KubernetesClusterOwnerTeam.ts +6 -0
- package/Models/DatabaseModels/KubernetesClusterOwnerUser.ts +6 -0
- package/Models/DatabaseModels/Monitor.ts +2 -3
- package/Models/DatabaseModels/MonitorGroupOwnerTeam.ts +6 -0
- package/Models/DatabaseModels/MonitorGroupOwnerUser.ts +6 -0
- package/Models/DatabaseModels/MonitorOwnerTeam.ts +6 -1
- package/Models/DatabaseModels/MonitorOwnerUser.ts +6 -1
- package/Models/DatabaseModels/MonitorTemplate.ts +2 -3
- package/Models/DatabaseModels/NetworkDevice.ts +67 -0
- package/Models/DatabaseModels/NetworkDeviceDiagnostic.ts +746 -0
- package/Models/DatabaseModels/NetworkDeviceDiscoveryScan.ts +151 -0
- package/Models/DatabaseModels/NetworkDeviceOwnerTeam.ts +6 -0
- package/Models/DatabaseModels/NetworkDeviceOwnerUser.ts +6 -0
- package/Models/DatabaseModels/NetworkSiteAssignmentRule.ts +1 -1
- package/Models/DatabaseModels/OnCallDutyPolicyOwnerTeam.ts +6 -1
- package/Models/DatabaseModels/OnCallDutyPolicyOwnerUser.ts +6 -1
- package/Models/DatabaseModels/OnCallDutyPolicyScheduleOwnerTeam.ts +6 -1
- package/Models/DatabaseModels/OnCallDutyPolicyScheduleOwnerUser.ts +6 -1
- package/Models/DatabaseModels/PodmanHostOwnerTeam.ts +6 -0
- package/Models/DatabaseModels/PodmanHostOwnerUser.ts +6 -0
- package/Models/DatabaseModels/ProbeOwnerTeam.ts +6 -0
- package/Models/DatabaseModels/ProbeOwnerUser.ts +6 -0
- package/Models/DatabaseModels/Project.ts +41 -0
- package/Models/DatabaseModels/ProxmoxClusterOwnerTeam.ts +6 -0
- package/Models/DatabaseModels/ProxmoxClusterOwnerUser.ts +6 -0
- package/Models/DatabaseModels/RumApplicationOwnerTeam.ts +6 -0
- package/Models/DatabaseModels/RumApplicationOwnerUser.ts +6 -0
- package/Models/DatabaseModels/RunbookOwnerTeam.ts +6 -1
- package/Models/DatabaseModels/RunbookOwnerUser.ts +6 -1
- package/Models/DatabaseModels/RunnerOwnerTeam.ts +6 -1
- package/Models/DatabaseModels/RunnerOwnerUser.ts +6 -1
- package/Models/DatabaseModels/ScheduledMaintenanceOwnerTeam.ts +6 -1
- package/Models/DatabaseModels/ScheduledMaintenanceOwnerUser.ts +6 -1
- package/Models/DatabaseModels/ScheduledMaintenancePublicNote.ts +74 -0
- package/Models/DatabaseModels/ScheduledMaintenanceTemplateOwnerTeam.ts +8 -0
- package/Models/DatabaseModels/ScheduledMaintenanceTemplateOwnerUser.ts +8 -0
- package/Models/DatabaseModels/SecurityEventConnection.ts +11 -11
- package/Models/DatabaseModels/ServerlessFunctionOwnerTeam.ts +6 -0
- package/Models/DatabaseModels/ServerlessFunctionOwnerUser.ts +6 -0
- package/Models/DatabaseModels/ServiceLevelObjective.ts +185 -8
- package/Models/DatabaseModels/ServiceLevelObjectiveBurnRateRule.ts +746 -43
- package/Models/DatabaseModels/ServiceLevelObjectiveFeed.ts +575 -0
- package/Models/DatabaseModels/ServiceLevelObjectiveMonitorRule.ts +582 -0
- package/Models/DatabaseModels/ServiceLevelObjectiveOwnerTeam.ts +22 -1
- package/Models/DatabaseModels/ServiceLevelObjectiveOwnerUser.ts +22 -1
- package/Models/DatabaseModels/ServiceOwnerTeam.ts +6 -0
- package/Models/DatabaseModels/ServiceOwnerUser.ts +6 -0
- package/Models/DatabaseModels/StatusPageAnnouncement.ts +75 -0
- package/Models/DatabaseModels/StatusPageOwnerTeam.ts +6 -1
- package/Models/DatabaseModels/StatusPageOwnerUser.ts +6 -1
- package/Models/DatabaseModels/ThreatIntelFeed.ts +1 -1
- package/Models/DatabaseModels/VMwareVCenterOwnerTeam.ts +6 -0
- package/Models/DatabaseModels/VMwareVCenterOwnerUser.ts +6 -0
- package/Models/DatabaseModels/WorkflowOwnerTeam.ts +6 -1
- package/Models/DatabaseModels/WorkflowOwnerUser.ts +6 -1
- package/Scripts/benchmark-fanin-capacity.js +2 -2
- package/Server/API/AIAgentDataAPI.ts +1 -1
- package/Server/API/AIChatAPI.ts +6 -4
- package/Server/API/AIInvestigationAPI.ts +7 -0
- package/Server/API/BaseAPI.ts +17 -0
- package/Server/API/BillingInvoiceAPI.ts +343 -30
- package/Server/API/BillingPaymentMethodAPI.ts +126 -5
- package/Server/API/DashboardAPI.ts +96 -2
- package/Server/API/SecurityEventConnectionAPI.ts +141 -11
- package/Server/API/StatusPageAPI.ts +321 -199
- package/Server/Infrastructure/Postgres/LocalMigrationGenerationDataSource.ts +1 -1
- package/Server/Infrastructure/Postgres/SchemaMigrations/1792800000000-AddNetworkDeviceDiagnostic.ts +83 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1792900000000-AddNetworkDeviceDnsNameAndShortDeviceNames.ts +36 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1793000000000-AddNetbiosLookupToNetworkDeviceDiscoveryScan.ts +29 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1793100000000-SloProductOverhaul.ts +516 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1793200000000-BackfillSloMonitorRulesAndAffectedResources.ts +98 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1793300000000-AddDataResidencyToProject.ts +27 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1793400000000-AddSubscriberUpdateNotificationStatus.ts +97 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1793500000000-MakeOwnerRowsUnique.ts +1057 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1793700000000-AddAIInvestigationDecision.ts +25 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1793800000000-RemoveMonitorDescriptionLengthLimit.ts +31 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +20 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/Readme.md +6 -4
- package/Server/Middleware/IdentityRateLimit.ts +34 -1
- package/Server/Middleware/PublicDashboardRateLimit.ts +169 -39
- package/Server/Services/AlertEpisodeLabelRuleEngineService.ts +138 -67
- package/Server/Services/AlertEpisodeOwnerRuleEngineService.ts +213 -84
- package/Server/Services/AlertEpisodePrivacyRuleEngineService.ts +112 -35
- package/Server/Services/AlertEpisodeService.ts +13 -34
- package/Server/Services/AlertGroupingEngineService.ts +7 -4
- package/Server/Services/AlertLabelRuleEngineService.ts +299 -217
- package/Server/Services/AlertOwnerRuleEngineService.ts +572 -396
- package/Server/Services/AlertPrivacyRuleEngineService.ts +116 -40
- package/Server/Services/AlertService.ts +124 -36
- package/Server/Services/AuditLogService.ts +612 -59
- package/Server/Services/BillingInvoiceService.ts +112 -102
- package/Server/Services/BillingService.ts +539 -11
- package/Server/Services/CephClusterLabelRuleEngineService.ts +170 -109
- package/Server/Services/CephClusterOwnerRuleEngineService.ts +237 -111
- package/Server/Services/CloudResourceLabelRuleEngineService.ts +163 -100
- package/Server/Services/CloudResourceOwnerRuleEngineService.ts +240 -111
- package/Server/Services/DashboardLabelRuleEngineService.ts +145 -84
- package/Server/Services/DashboardOwnerRuleEngineService.ts +217 -91
- package/Server/Services/DatabaseService.ts +272 -22
- package/Server/Services/DockerHostLabelRuleEngineService.ts +171 -110
- package/Server/Services/DockerHostOwnerRuleEngineService.ts +237 -111
- package/Server/Services/DockerSwarmClusterLabelRuleEngineService.ts +181 -112
- package/Server/Services/DockerSwarmClusterOwnerRuleEngineService.ts +247 -114
- package/Server/Services/HostLabelRuleEngineService.ts +167 -106
- package/Server/Services/HostOwnerRuleEngineService.ts +233 -107
- package/Server/Services/IncidentEpisodeLabelRuleEngineService.ts +141 -67
- package/Server/Services/IncidentEpisodeOwnerRuleEngineService.ts +274 -72
- package/Server/Services/IncidentEpisodePrivacyRuleEngineService.ts +112 -35
- package/Server/Services/IncidentEpisodePublicNoteService.ts +24 -0
- package/Server/Services/IncidentEpisodeService.ts +15 -75
- package/Server/Services/IncidentGroupingEngineService.ts +7 -4
- package/Server/Services/IncidentLabelRuleEngineService.ts +279 -204
- package/Server/Services/IncidentOwnerRuleEngineService.ts +595 -425
- package/Server/Services/IncidentPrivacyRuleEngineService.ts +117 -44
- package/Server/Services/IncidentPublicNoteService.ts +24 -0
- package/Server/Services/IncidentService.ts +127 -35
- package/Server/Services/IncidentTemplateService.ts +13 -36
- package/Server/Services/IncomingCallPolicyLabelRuleEngineService.ts +147 -83
- package/Server/Services/IncomingCallPolicyOwnerRuleEngineService.ts +225 -96
- package/Server/Services/Index.ts +6 -4
- package/Server/Services/IoTFleetLabelRuleEngineService.ts +145 -84
- package/Server/Services/IoTFleetOwnerRuleEngineService.ts +217 -91
- package/Server/Services/KubernetesClusterLabelRuleEngineService.ts +181 -112
- package/Server/Services/KubernetesClusterOwnerRuleEngineService.ts +247 -114
- package/Server/Services/LabelService.ts +23 -28
- package/Server/Services/MonitorLabelRuleEngineService.ts +152 -92
- package/Server/Services/MonitorOwnerRuleEngineService.ts +220 -104
- package/Server/Services/MonitorProbeService.ts +20 -2
- package/Server/Services/MonitorService.ts +24 -41
- package/Server/Services/NetworkDeviceAutoImportRuleEngineService.ts +376 -5
- package/Server/Services/NetworkDeviceDiagnosticService.ts +417 -0
- package/Server/Services/NetworkDeviceLabelRuleEngineService.ts +147 -83
- package/Server/Services/NetworkDeviceOwnerRuleEngineService.ts +222 -93
- package/Server/Services/NetworkDeviceService.ts +39 -2
- package/Server/Services/OnCallDutyPolicyLabelRuleEngineService.ts +151 -80
- package/Server/Services/OnCallDutyPolicyOwnerRuleEngineService.ts +226 -93
- package/Server/Services/OnCallDutyPolicyScheduleLabelRuleEngineService.ts +154 -83
- package/Server/Services/OnCallDutyPolicyScheduleOwnerRuleEngineService.ts +229 -96
- package/Server/Services/PodmanHostLabelRuleEngineService.ts +171 -110
- package/Server/Services/PodmanHostOwnerRuleEngineService.ts +239 -111
- package/Server/Services/ProjectService.ts +111 -10
- package/Server/Services/ProxmoxClusterLabelRuleEngineService.ts +174 -110
- package/Server/Services/ProxmoxClusterOwnerRuleEngineService.ts +243 -112
- package/Server/Services/RumApplicationLabelRuleEngineService.ts +137 -73
- package/Server/Services/RumApplicationOwnerRuleEngineService.ts +204 -79
- package/Server/Services/RunbookLabelRuleEngineService.ts +146 -84
- package/Server/Services/RunbookOwnerRuleEngineService.ts +220 -91
- package/Server/Services/ScheduledMaintenanceLabelRuleEngineService.ts +324 -230
- package/Server/Services/ScheduledMaintenanceOwnerRuleEngineService.ts +613 -428
- package/Server/Services/ScheduledMaintenancePublicNoteService.ts +24 -0
- package/Server/Services/ScheduledMaintenanceService.ts +56 -48
- package/Server/Services/ScheduledMaintenanceTemplateService.ts +12 -34
- package/Server/Services/SecurityEventConnectionService.ts +56 -4
- package/Server/Services/ServerlessFunctionLabelRuleEngineService.ts +143 -74
- package/Server/Services/ServerlessFunctionOwnerRuleEngineService.ts +210 -81
- package/Server/Services/ServiceLabelRuleEngineService.ts +172 -110
- package/Server/Services/ServiceLevelObjectiveBurnRateRuleService.ts +1057 -18
- package/Server/Services/ServiceLevelObjectiveFeedService.ts +108 -0
- package/Server/Services/ServiceLevelObjectiveMonitorRuleEngineService.ts +793 -97
- package/Server/Services/ServiceLevelObjectiveMonitorRuleService.ts +1069 -0
- package/Server/Services/ServiceLevelObjectiveOwnerTeamService.ts +240 -1
- package/Server/Services/ServiceLevelObjectiveOwnerUserService.ts +257 -1
- package/Server/Services/ServiceLevelObjectiveService.ts +1356 -56
- package/Server/Services/ServiceOwnerRuleEngineService.ts +242 -112
- package/Server/Services/StatusPageAnnouncementService.ts +13 -0
- package/Server/Services/StatusPageLabelRuleEngineService.ts +146 -85
- package/Server/Services/StatusPageOwnerRuleEngineService.ts +210 -99
- package/Server/Services/StatusPagePrivateUserService.ts +38 -29
- package/Server/Services/StatusPagePrivateUserSessionService.ts +49 -1
- package/Server/Services/StatusPageService.ts +59 -36
- package/Server/Services/StatusPageSubscriberNotificationTemplateService.ts +28 -232
- package/Server/Services/StatusPageSubscriberService.ts +6 -0
- package/Server/Services/TelemetryUsageBillingService.ts +38 -7
- package/Server/Services/ThreatIntelFeedService.ts +1 -1
- package/Server/Services/UserSessionService.ts +6 -0
- package/Server/Services/VMwareVCenterLabelRuleEngineService.ts +173 -110
- package/Server/Services/VMwareVCenterOwnerRuleEngineService.ts +242 -112
- package/Server/Services/WorkflowLabelRuleEngineService.ts +145 -84
- package/Server/Services/WorkflowOwnerRuleEngineService.ts +219 -91
- package/Server/Static/Brand/README.md +7 -7
- package/Server/Static/Vendor/README.md +7 -7
- package/Server/Types/Database/Permissions/OwnedScopePermission.ts +18 -9
- package/Server/Types/Database/Permissions/OwnerTableRegistry.ts +82 -0
- package/Server/Types/Database/UpdateByID.ts +3 -0
- package/Server/Types/Database/UpdateOneBy.ts +7 -0
- package/Server/Utils/AI/AlertAIContextBuilder.ts +19 -0
- package/Server/Utils/AI/Chat/ChatAgentRunner.ts +21 -8
- package/Server/Utils/AI/Chat/ObservabilityChatPrompt.ts +41 -4
- package/Server/Utils/AI/CodeFix/CodeAgentWorkspaceGuard.ts +1 -1
- package/Server/Utils/AI/CodeFix/CodeFixAgentCompletion.ts +1 -1
- package/Server/Utils/AI/IncidentAIContextBuilder.ts +39 -0
- package/Server/Utils/AI/SRE/AIInvestigationEngine.ts +13 -5
- package/Server/Utils/AI/SRE/AlertInvestigationRunner.ts +53 -13
- package/Server/Utils/AI/SRE/IncidentInvestigationRunner.ts +51 -14
- package/Server/Utils/AI/SRE/InvestigationEligibility.ts +292 -0
- package/Server/Utils/AI/SRE/InvestigationQueue.ts +25 -0
- package/Server/Utils/AI/Toolbox/AlertTools.ts +37 -1
- package/Server/Utils/AI/Toolbox/IncidentTools.ts +22 -1
- package/Server/Utils/AI/Toolbox/Index.ts +43 -13
- package/Server/Utils/AI/Toolbox/ResourceTools.ts +952 -0
- package/Server/Utils/AI/Toolbox/RumTools.ts +424 -0
- package/Server/Utils/AI/Toolbox/SloTools.ts +416 -51
- package/Server/Utils/AI/Toolbox/ToolTypes.ts +10 -0
- package/Server/Utils/AI/Toolbox/TraceTools.ts +2 -1
- package/Server/Utils/Dashboard/PublicDashboardResourceListPolicy.ts +151 -13
- package/Server/Utils/Dashboard/PublicDashboardSloHistoryPolicy.ts +17 -4
- package/Server/Utils/Dashboard/PublicDashboardSloWidget.ts +155 -8
- package/Server/Utils/Database/PostgresErrorTranslator.ts +14 -0
- package/Server/Utils/Database/ProjectScopedReferenceValidator.ts +16 -0
- package/Server/Utils/Database/RelationValueUtil.ts +106 -0
- package/Server/Utils/Monitor/Criteria/CompareCriteria.ts +143 -127
- package/Server/Utils/Monitor/Criteria/EvaluateOverTime.ts +22 -27
- package/Server/Utils/Monitor/Criteria/MetricMonitorCriteria.ts +4 -1
- package/Server/Utils/Monitor/MonitorCriteriaExpectationBuilder.ts +3 -1
- package/Server/Utils/Monitor/MonitorStepsProjectValidator.ts +50 -20
- package/Server/Utils/Monitor/NetworkDeviceHydrationUtil.ts +13 -1
- package/Server/Utils/Monitor/NetworkDeviceMetricUtil.ts +6 -11
- package/Server/Utils/Rules/MonitorRulePatternValidator.ts +51 -0
- package/Server/Utils/Rules/OwnerRuleAssignment.ts +261 -0
- package/Server/Utils/Rules/RuleRun/RuleApplication.ts +81 -0
- package/Server/Utils/Rules/RuleRun/RuleRunPermission.ts +188 -0
- package/Server/Utils/Rules/RuleRun/RuleRunRegistry.ts +803 -0
- package/Server/Utils/Rules/RuleRun/RuleRunner.ts +341 -0
- package/Server/Utils/SecurityEvent/ConnectorErrorMessage.ts +3 -2
- package/Server/Utils/SecurityEvent/Connectors/ConnectorPlatformHealth.ts +6 -4
- package/Server/Utils/SecurityEvent/{GoogleSecOps → Connectors/GoogleSecOps}/GoogleSecOpsClient.ts +263 -16
- package/Server/Utils/SecurityEvent/Connectors/GoogleSecOps/GoogleSecOpsConnector.ts +2101 -0
- package/Server/Utils/SecurityEvent/Connectors/SecurityEventConnectionPoller.ts +194 -14
- package/Server/Utils/SecurityEvent/Connectors/SecurityEventConnectionRunExecutor.ts +1 -2
- package/Server/Utils/SecurityEvent/Connectors/SecurityEventConnectionTester.ts +38 -7
- package/Server/Utils/SecurityEvent/Connectors/SecurityEventConnectorRegistry.ts +2 -0
- package/Server/Utils/SecurityEvent/Connectors/Types.ts +242 -2
- package/Server/Utils/SecurityEvent/DetectionRuleEvaluator.ts +1 -1
- package/Server/Utils/SecurityEvent/SecurityEventDedupe.ts +3 -3
- package/Server/Utils/SecurityEvent/ThreatIntel/ThreatIntelFeedPoller.ts +2 -2
- package/Server/Utils/SessionReplay/SessionReplayReadService.ts +217 -56
- package/Server/Utils/Slo/SloFeedUtil.ts +200 -0
- package/Server/Utils/Slo/SloLegacyMonitorLabelAdoption.ts +173 -0
- package/Server/Utils/Slo/SloMetricUtil.ts +327 -0
- package/Server/Utils/Slo/SloOwnerReferenceValidator.ts +208 -0
- package/Server/Utils/Slo/SloRecordReferenceValidator.ts +169 -0
- package/Server/Utils/StatusPage/MonitorRulePatternValidator.ts +6 -43
- package/Server/Utils/StatusPageResource.ts +50 -5
- package/Server/Utils/Telemetry/TelemetryEntity.ts +205 -6
- package/SslCertificates/GlobalSign.crt +26 -0
- package/SslCertificates/Readme.md +3 -0
- package/Tests/App/AdminDashboard/EnterpriseLicenseInstanceActivity.test.tsx +451 -0
- package/Tests/App/Dashboard/AIInsightsChatPanel.test.tsx +881 -0
- package/Tests/App/Dashboard/AIInsightsPageContext.test.ts +458 -0
- package/Tests/App/Dashboard/AIInsightsResourceCitations.test.ts +124 -0
- package/Tests/App/Dashboard/AIInsightsResourcePageContext.test.ts +798 -0
- package/Tests/App/Dashboard/AIInvestigationHeaderStatus.test.tsx +664 -15
- package/Tests/App/Dashboard/AddWidgetModal.test.tsx +4 -1
- package/Tests/App/Dashboard/AffectedResourcesSlo.test.tsx +307 -0
- package/Tests/App/Dashboard/ArchiveResourceCard.test.tsx +289 -0
- package/Tests/App/Dashboard/AskAiSuggestedPrompts.test.ts +7 -0
- package/Tests/App/Dashboard/AuditLogsTable.test.tsx +598 -0
- package/Tests/App/Dashboard/BillingDefaultPaymentMethod.test.tsx +1046 -0
- package/Tests/App/Dashboard/BillingPaidUsageFlow.test.tsx +3 -0
- package/Tests/App/Dashboard/BillingPaymentMethodForm.test.tsx +201 -7
- package/Tests/App/Dashboard/BooleanSeriesCriteriaFilterText.test.ts +82 -0
- package/Tests/App/Dashboard/BreadcrumbCoverage.test.tsx +16 -1
- package/Tests/App/Dashboard/ChangeAlertStateAIHeader.test.tsx +116 -8
- package/Tests/App/Dashboard/ChatActivityFeed.test.tsx +168 -1
- package/Tests/App/Dashboard/ConnectionTestModal.test.tsx +1 -1
- package/Tests/App/Dashboard/ConnectorTestReportView.test.tsx +20 -3
- package/Tests/App/Dashboard/CorrelateFilterBuilder.test.tsx +1095 -1
- package/Tests/App/Dashboard/CorrelateFilterChips.test.tsx +910 -0
- package/Tests/App/Dashboard/CorrelateGraph.test.tsx +3747 -25
- package/Tests/App/Dashboard/CorrelateGraphHelpers.test.ts +1085 -0
- package/Tests/App/Dashboard/CorrelateInspector.test.tsx +1534 -0
- package/Tests/App/Dashboard/CorrelateNodeCard.test.tsx +965 -0
- package/Tests/App/Dashboard/CorrelateResultSummary.test.tsx +1525 -0
- package/Tests/App/Dashboard/CorrelationGraph.test.ts +1030 -0
- package/Tests/App/Dashboard/CorrelationGraphLayout.test.ts +526 -0
- package/Tests/App/Dashboard/DashboardChartWidgetZoom.test.tsx +104 -0
- package/Tests/App/Dashboard/DashboardCommandPalette.test.tsx +156 -64
- package/Tests/App/Dashboard/DeviceDiagnostics.test.tsx +787 -0
- package/Tests/App/Dashboard/DeviceLatencyTrend.test.tsx +278 -0
- package/Tests/App/Dashboard/DiscoveryReviewInventoryRefresh.test.tsx +279 -0
- package/Tests/App/Dashboard/DiscoveryScanEditForm.test.tsx +87 -0
- package/Tests/App/Dashboard/DiscoveryScanStatusMessage.test.tsx +970 -0
- package/Tests/App/Dashboard/DiscoveryScanWizardValidation.test.tsx +849 -20
- package/Tests/App/Dashboard/EmbeddedMetricEventScope.test.tsx +358 -0
- package/Tests/App/Dashboard/EntityFilterDropdownArchivedSlos.test.tsx +340 -0
- package/Tests/App/Dashboard/ErrorPatternEventScope.test.tsx +148 -0
- package/Tests/App/Dashboard/EventOverlayAdditionalResourceScope.test.ts +255 -0
- package/Tests/App/Dashboard/EventOverlayScope.test.ts +845 -0
- package/Tests/App/Dashboard/EventOverlayScopeHook.test.tsx +903 -0
- package/Tests/App/Dashboard/EventOverviewPages.test.tsx +98 -2
- package/Tests/App/Dashboard/ExceptionSegmentedControl.test.tsx +1020 -0
- package/Tests/App/Dashboard/ExternalStatusPageCriteriaFilter.test.ts +3 -3
- package/Tests/App/Dashboard/InvestigationDrawer.test.tsx +21 -0
- package/Tests/App/Dashboard/InvestigationEvidenceList.test.tsx +268 -47
- package/Tests/App/Dashboard/InvestigationNotStarted.test.tsx +761 -0
- package/Tests/App/Dashboard/InvestigationPanel.test.tsx +1122 -81
- package/Tests/App/Dashboard/InvestigationPanelStatus.test.tsx +139 -9
- package/Tests/App/Dashboard/InvestigationReportView.test.tsx +279 -176
- package/Tests/App/Dashboard/InvestigationRunDetails.test.tsx +1166 -0
- package/Tests/App/Dashboard/InvoicesPayInvoice.test.tsx +437 -0
- package/Tests/App/Dashboard/MetricsViewerEventScopeNavigation.test.tsx +264 -0
- package/Tests/App/Dashboard/MonitorSummaryTestMonitorButton.test.tsx +342 -0
- package/Tests/App/Dashboard/MonitorTestForm.test.tsx +612 -0
- package/Tests/App/Dashboard/NavigationSearchKeywords.test.tsx +301 -0
- package/Tests/App/Dashboard/NetworkDeviceBulkDelete.test.tsx +65 -0
- package/Tests/App/Dashboard/NetworkTopologyLiveView.test.tsx +5 -0
- package/Tests/App/Dashboard/ResourceAuditLogsSideMenus.test.tsx +74 -0
- package/Tests/App/Dashboard/ResourceFeed.test.tsx +125 -5
- package/Tests/App/Dashboard/ResourceFeedPageWiring.test.ts +8 -1
- package/Tests/App/Dashboard/SecurityEventConnectionDiagnostics.test.tsx +1764 -0
- package/Tests/App/Dashboard/SecurityEventConnectionFormModal.test.tsx +1000 -64
- package/Tests/App/Dashboard/SecurityEventConnectionsEmptyState.test.tsx +448 -0
- package/Tests/App/Dashboard/SecurityEventConnectionsTable.test.tsx +739 -189
- package/Tests/App/Dashboard/SecurityEventSeverityPill.test.tsx +233 -0
- package/Tests/App/Dashboard/SecurityEventsEmptyState.test.tsx +282 -0
- package/Tests/App/Dashboard/ServiceMapGraph.test.tsx +74 -2
- package/Tests/App/Dashboard/SloActiveBurnEventsCard.test.tsx +538 -0
- package/Tests/App/Dashboard/SloBulkActionsArchive.test.tsx +252 -0
- package/Tests/App/Dashboard/SloDashboardTemplateWidgets.test.tsx +322 -518
- package/Tests/App/Dashboard/SloElement.test.tsx +194 -0
- package/Tests/App/Dashboard/SloFeed.test.tsx +289 -0
- package/Tests/App/Dashboard/SloHistoryCharts.test.tsx +471 -0
- package/Tests/App/Dashboard/SloHistorySeries.test.tsx +607 -0
- package/Tests/App/Dashboard/SloListWidget.test.tsx +783 -0
- package/Tests/App/Dashboard/SloMetricsPage.test.tsx +346 -0
- package/Tests/App/Dashboard/SloMonitorsPage.test.tsx +661 -0
- package/Tests/App/Dashboard/SloMonitorsSummaryCard.test.tsx +489 -0
- package/Tests/App/Dashboard/SloNavigationWiring.test.tsx +437 -0
- package/Tests/App/Dashboard/SloNoticeBanner.test.tsx +305 -0
- package/Tests/App/Dashboard/SloOverviewData.test.tsx +563 -0
- package/Tests/App/Dashboard/SloOverviewHero.test.tsx +311 -0
- package/Tests/App/Dashboard/SloOverviewKpiStrip.test.tsx +426 -0
- package/Tests/App/Dashboard/SloOverviewSidebarCards.test.tsx +493 -0
- package/Tests/App/Dashboard/SloSettings.test.tsx +633 -0
- package/Tests/App/Dashboard/SloStatusSummaryCards.test.tsx +403 -0
- package/Tests/App/Dashboard/SloViewSideMenuCounts.test.tsx +373 -0
- package/Tests/App/Dashboard/SloWidgetVariableBinding.test.tsx +689 -0
- package/Tests/App/Dashboard/TextClampLayoutHarness.ts +224 -0
- package/Tests/App/Dashboard/TopologyConnectivitySection.test.tsx +206 -0
- package/Tests/App/Dashboard/TracesEntityNames.test.tsx +47 -15
- package/Tests/App/Dashboard/UseBulkShortenDeviceNames.test.tsx +1312 -0
- package/Tests/App/Dashboard/WidgetCatalog.test.ts +9 -1
- package/Tests/Models/AnalyticsModels/RumSessionReplayColumns.test.ts +14 -16
- package/Tests/Models/DatabaseModels/AuditLogModelConfiguration.test.ts +442 -0
- package/Tests/Models/DatabaseModels/DomainRoleTierCoverage.test.ts +9 -10
- package/Tests/Models/DatabaseModels/ResourceFeedModels.test.ts +48 -1
- package/Tests/Models/DatabaseModels/SloOverhaulModels.test.ts +835 -0
- package/Tests/Models/DatabaseModels/StaticRuleCriteriaInheritance.test.ts +3 -2
- package/Tests/Models/DiscoveryScanNetbiosLookupColumn.test.ts +328 -0
- package/Tests/Models/DiscoveryScanShortDeviceNamesColumn.test.ts +335 -0
- package/Tests/Models/InventoryItemNaming.test.ts +54 -0
- package/Tests/Models/NetworkDeviceDiagnosticContract.test.ts +194 -0
- package/Tests/Models/NetworkDeviceDnsNameColumn.test.ts +321 -0
- package/Tests/Models/ProjectDataResidencyColumn.test.ts +154 -0
- package/Tests/Models/SecurityDomainAccessControl.test.ts +181 -50
- package/Tests/Server/API/AIChatRouteAuthorization.test.ts +161 -0
- package/Tests/Server/API/AIInvestigationAPI.test.ts +14 -0
- package/Tests/Server/API/AIInvestigationAvailabilityAuthorization.test.ts +260 -0
- package/Tests/Server/API/BaseAPI.test.ts +6 -0
- package/Tests/Server/API/BaseAPIUpdateMiscDataProps.test.ts +217 -0
- package/Tests/Server/API/BillingInvoiceAPI.test.ts +7 -0
- package/Tests/Server/API/BillingInvoiceAPIPaymentStates.test.ts +990 -0
- package/Tests/Server/API/BillingPaymentMethodAPI.test.ts +498 -0
- package/Tests/Server/API/DashboardPublicSloAPI.test.ts +405 -0
- package/Tests/Server/API/EnterpriseLicenseReportUserCount.test.ts +133 -0
- package/Tests/Server/API/SecurityEventConnectionAPI.test.ts +901 -7
- package/Tests/Server/API/SessionReplayAPI.test.ts +116 -0
- package/Tests/Server/API/StatusPageManageSubscriptionRecipient.test.ts +857 -0
- package/Tests/Server/API/StatusPageManageSubscriptionTemplateVariables.test.ts +1084 -0
- package/Tests/Server/API/StatusPageMasterPasswordRateLimit.test.ts +482 -0
- package/Tests/Server/EnvironmentConfigOnCallCalendarFeed.test.ts +1 -1
- package/Tests/Server/Infrastructure/ClickhouseKeepAliveOptions.test.ts +1 -1
- package/Tests/Server/Infrastructure/ContainerBootConfiguration.test.ts +38 -16
- package/Tests/Server/Infrastructure/E2EClickHouseFixtureAccess.test.ts +106 -31
- package/Tests/Server/Infrastructure/ExampleDockerfiles.test.ts +46 -12
- package/Tests/Server/Infrastructure/Postgres/AddConfigurableRuleCriteriaMigration.test.ts +33 -3
- package/Tests/Server/Infrastructure/Postgres/AddDataResidencyToProjectMigration.test.ts +202 -0
- package/Tests/Server/Infrastructure/Postgres/AddNetbiosLookupToNetworkDeviceDiscoveryScanMigration.test.ts +330 -0
- package/Tests/Server/Infrastructure/Postgres/AddNetworkDeviceDnsNameAndShortDeviceNamesMigration.test.ts +340 -0
- package/Tests/Server/Infrastructure/Postgres/BackfillSloMonitorRulesAndAffectedResourcesMigration.test.ts +343 -0
- package/Tests/Server/Infrastructure/Postgres/MonitorDescriptionMigration.test.ts +422 -0
- package/Tests/Server/Infrastructure/Postgres/SloProductOverhaulMigration.test.ts +801 -0
- package/Tests/Server/Infrastructure/TelemetryExporterDeploymentConfig.test.ts +1 -1
- package/Tests/Server/Infrastructure/ValkeyDeploymentConfig.test.ts +25 -4
- package/Tests/Server/Middleware/IdentityRateLimit.test.ts +72 -0
- package/Tests/Server/Middleware/PublicDashboardRateLimit.test.ts +12 -12
- package/Tests/Server/Middleware/PublicDashboardRateLimitStatusPage.test.ts +800 -0
- package/Tests/Server/Services/AIInvestigationDecisionPostgres.test.ts +346 -0
- package/Tests/Server/Services/AddOwnersIdempotency.test.ts +471 -0
- package/Tests/Server/Services/AddSubscriberUpdateNotificationStatusMigration.test.ts +307 -0
- package/Tests/Server/Services/AuditLogService.test.ts +1124 -0
- package/Tests/Server/Services/AutoImportScanCredentialSelect.test.ts +200 -1
- package/Tests/Server/Services/BillingInvoiceServiceMutexRelease.test.ts +254 -0
- package/Tests/Server/Services/BillingService.test.ts +70 -0
- package/Tests/Server/Services/BillingServicePayInvoiceStates.test.ts +723 -0
- package/Tests/Server/Services/BillingServicePaymentMethodReads.test.ts +14 -2
- package/Tests/Server/Services/BillingServiceSubscriptionPaymentMethodSync.test.ts +1634 -0
- package/Tests/Server/Services/DatabaseServiceAuditRelationDiff.test.ts +492 -0
- package/Tests/Server/Services/DatabaseServiceAutoOwnerOnCreate.test.ts +250 -0
- package/Tests/Server/Services/DatabaseServicePasswordFieldSecrets.test.ts +629 -0
- package/Tests/Server/Services/DatabaseServiceUniqueColumnsTogether.test.ts +622 -0
- package/Tests/Server/Services/IncidentAlertSloLinkSurvivesEdit.test.ts +431 -0
- package/Tests/Server/Services/IncidentAlertSloReferenceGuard.test.ts +358 -0
- package/Tests/Server/Services/MonitorDescriptionValidation.test.ts +211 -0
- package/Tests/Server/Services/MonitorProbeServicePastDueMonitoring.test.ts +362 -0
- package/Tests/Server/Services/MonitorTemplateDescriptionPropagation.test.ts +269 -0
- package/Tests/Server/Services/NetworkDeviceAutoImportRuleEngineService.test.ts +1460 -1
- package/Tests/Server/Services/NetworkDeviceDiagnosticService.test.ts +962 -0
- package/Tests/Server/Services/NetworkDeviceDiscoveryScanService.test.ts +106 -0
- package/Tests/Server/Services/NetworkDeviceRuleEngines.test.ts +10 -1
- package/Tests/Server/Services/NetworkDeviceServicePastDueMonitoring.test.ts +335 -0
- package/Tests/Server/Services/NetworkDeviceSiteRuleDnsName.test.ts +568 -0
- package/Tests/Server/Services/OwnerRowUniqueness.test.ts +504 -0
- package/Tests/Server/Services/ProjectDataResidencyPostgres.test.ts +344 -0
- package/Tests/Server/Services/ProjectServiceAuditLogSettingsCache.test.ts +187 -0
- package/Tests/Server/Services/ProjectServiceDataResidency.test.ts +369 -0
- package/Tests/Server/Services/ProjectServiceDataResidencySelfHosted.test.ts +176 -0
- package/Tests/Server/Services/ProjectServicePastDueMonitoring.test.ts +289 -0
- package/Tests/Server/Services/ResourceFeedServices.test.ts +24 -8
- package/Tests/Server/Services/RuleRun/IncidentAlertMaintenanceRuleEnginesRun.test.ts +1396 -0
- package/Tests/Server/Services/RuleRun/LabelRuleEnginesGroupARun.test.ts +917 -0
- package/Tests/Server/Services/RuleRun/LabelRuleEnginesGroupBRun.test.ts +1262 -0
- package/Tests/Server/Services/RuleRun/OwnerRuleEnginesGroupARun.test.ts +945 -0
- package/Tests/Server/Services/RuleRun/OwnerRuleEnginesGroupBRun.test.ts +1163 -0
- package/Tests/Server/Services/RuleRun/PrivacyRuleEnginesRun.test.ts +843 -0
- package/Tests/Server/Services/ScheduledMaintenanceSubscriberTemplateFormats.test.ts +465 -0
- package/Tests/Server/Services/SecurityEventConnectionService.test.ts +525 -4
- package/Tests/Server/Services/SecurityEventLastErrorColumnWidth.test.ts +77 -23
- package/Tests/Server/Services/ServiceLevelObjectiveBurnRateRuleFeedWrites.test.ts +777 -0
- package/Tests/Server/Services/ServiceLevelObjectiveBurnRateRuleOptions.test.ts +1399 -0
- package/Tests/Server/Services/ServiceLevelObjectiveBurnRateRuleService.test.ts +67 -74
- package/Tests/Server/Services/ServiceLevelObjectiveChildRowTenancy.test.ts +906 -0
- package/Tests/Server/Services/ServiceLevelObjectiveDeleteTenancy.test.ts +1029 -0
- package/Tests/Server/Services/ServiceLevelObjectiveFeedService.test.ts +313 -0
- package/Tests/Server/Services/ServiceLevelObjectiveFeedWrites.test.ts +1214 -0
- package/Tests/Server/Services/ServiceLevelObjectiveMarkdownLink.test.ts +289 -0
- package/Tests/Server/Services/ServiceLevelObjectiveMonitorRuleEngineService.test.ts +1455 -430
- package/Tests/Server/Services/ServiceLevelObjectiveMonitorRuleLegacyLabelAdoption.test.ts +634 -0
- package/Tests/Server/Services/ServiceLevelObjectiveMonitorRuleService.test.ts +1193 -0
- package/Tests/Server/Services/{SloMonitorLabelRuleHooks.test.ts → ServiceLevelObjectiveMonitorRuleTriggers.test.ts} +135 -41
- package/Tests/Server/Services/ServiceLevelObjectiveOwnerFeedWrites.test.ts +671 -0
- package/Tests/Server/Services/ServiceLevelObjectiveService.test.ts +180 -85
- package/Tests/Server/Services/ServiceLevelObjectiveServiceArchive.test.ts +537 -0
- package/Tests/Server/Services/ServiceLevelObjectiveServiceLegacyMonitorLabelWrite.test.ts +870 -0
- package/Tests/Server/Services/ServiceLevelObjectiveServiceMonitorRuleGuard.test.ts +343 -0
- package/Tests/Server/Services/ServiceLevelObjectiveServiceReEvaluation.test.ts +246 -0
- package/Tests/Server/Services/SessionRetention.test.ts +334 -0
- package/Tests/Server/Services/SloAffectedResourceCreatedFeed.test.ts +501 -0
- package/Tests/Server/Services/SloAffectedResourceLinkContract.test.ts +86 -0
- package/Tests/Server/Services/SloAffectedResourceMetricAttributes.test.ts +547 -0
- package/Tests/Server/Services/StaticRuleCriteriaRuntimeCoverage.test.ts +10 -4
- package/Tests/Server/Services/StatusPageMonitorRuleHooks.test.ts +7 -2
- package/Tests/Server/Services/StatusPagePrivateUserInvitationPolicy.test.ts +172 -0
- package/Tests/Server/Services/StatusPagePrivateUserReadAccess.test.ts +178 -0
- package/Tests/Server/Services/StatusPagePrivateUserReadAccessPostgres.test.ts +311 -0
- package/Tests/Server/Services/StatusPagePrivateUserSessionService.test.ts +216 -1
- package/Tests/Server/Services/StatusPageSubscriberNotificationTemplateCompile.test.ts +174 -0
- package/Tests/Server/Services/StatusPageSubscriberNotificationTemplateServiceVariables.test.ts +40 -0
- package/Tests/Server/Services/SubscriberUpdateNotificationHooks.test.ts +541 -0
- package/Tests/Server/Services/TeamComplianceServiceBehaviour.test.ts +1 -1
- package/Tests/Server/Services/TelemetryUsageBillingSloExclusion.test.ts +288 -0
- package/Tests/Server/Services/UserOnCallLogNoNotificationRules.test.ts +1 -1
- package/Tests/Server/TestingUtils/PastDueMonitoringClaimSql.ts +177 -0
- package/Tests/Server/TestingUtils/Services/BillingServiceHelper.ts +51 -10
- package/Tests/Server/TestingUtils/__mocks__/Stripe.mock.ts +16 -1
- package/Tests/Server/Types/Database/EventOverlayScopePostgres.test.ts +626 -0
- package/Tests/Server/Types/Database/Permissions/InfrastructureOwnershipScope.test.ts +668 -0
- package/Tests/Server/Types/Database/Permissions/ProjectDataResidencyColumn.test.ts +386 -0
- package/Tests/Server/Types/Database/Permissions/SecurityRoleAccess.test.ts +26 -36
- package/Tests/Server/Types/Database/Permissions/SelectRejectionMessageContract.test.ts +1 -0
- package/Tests/Server/Types/Database/Permissions/UserNotificationRuleScoping.test.ts +1 -1
- package/Tests/Server/Utils/AI/AIIncidentGating.test.ts +16 -9
- package/Tests/Server/Utils/AI/ChatAgentRunner.test.ts +137 -1
- package/Tests/Server/Utils/AI/InvestigationEligibility.test.ts +697 -0
- package/Tests/Server/Utils/AI/ObservabilityChatPrompt.test.ts +105 -0
- package/Tests/Server/Utils/AI/RemediationHandoff.test.ts +16 -5
- package/Tests/Server/Utils/AI/ResourceTools.test.ts +1304 -0
- package/Tests/Server/Utils/AI/RumTools.test.ts +769 -0
- package/Tests/Server/Utils/AI/SloAffectedResourceAIContext.test.ts +445 -0
- package/Tests/Server/Utils/AI/SloTools.test.ts +423 -1
- package/Tests/Server/Utils/AI/SloToolsArchive.test.ts +294 -0
- package/Tests/Server/Utils/AI/SloToolsRuleReadPermissions.test.ts +297 -0
- package/Tests/Server/Utils/Dashboard/PublicDashboardSloHistoryPolicy.test.ts +255 -10
- package/Tests/Server/Utils/Dashboard/SloTemplatePublicDashboard.test.ts +404 -750
- package/Tests/Server/Utils/Database/PostgresErrorTranslator.test.ts +63 -0
- package/Tests/Server/Utils/Database/ProjectScopedReferenceValidator.test.ts +45 -0
- package/Tests/Server/Utils/Database/RelationValueUtil.test.ts +157 -0
- package/Tests/Server/Utils/Monitor/Criteria/APIRequestCriteriaEvaluateOverTime.test.ts +11 -9
- package/Tests/Server/Utils/Monitor/Criteria/BooleanSeriesEvaluateOverTime.test.ts +260 -0
- package/Tests/Server/Utils/Monitor/Criteria/CompareCriteria.test.ts +62 -45
- package/Tests/Server/Utils/Monitor/Criteria/CompareCriteriaAggregation.test.ts +25 -24
- package/Tests/Server/Utils/Monitor/Criteria/CompareCriteriaHumanMessages.test.ts +513 -0
- package/Tests/Server/Utils/Monitor/Criteria/CustomCodeMonitorCriteria.test.ts +2 -2
- package/Tests/Server/Utils/Monitor/Criteria/DatabaseMonitorCriteria.test.ts +181 -0
- package/Tests/Server/Utils/Monitor/Criteria/DnsMonitorCriteria.test.ts +1 -1
- package/Tests/Server/Utils/Monitor/Criteria/EvaluateOverTime.test.ts +147 -30
- package/Tests/Server/Utils/Monitor/Criteria/ExternalStatusPageMonitorCriteria.test.ts +9 -9
- package/Tests/Server/Utils/Monitor/Criteria/MetricMonitorCriteria.test.ts +7 -5
- package/Tests/Server/Utils/Monitor/Criteria/ProfileMonitorCriteria.test.ts +2 -2
- package/Tests/Server/Utils/Monitor/Criteria/ServerMonitorCriteria.test.ts +4 -3
- package/Tests/Server/Utils/Monitor/Criteria/SnmpMonitorCriteria.test.ts +2 -2
- package/Tests/Server/Utils/Monitor/MonitorCriteriaEvaluatorMetricUnits.test.ts +3 -2
- package/Tests/Server/Utils/Monitor/MonitorCriteriaExpectationBuilder.test.ts +17 -0
- package/Tests/Server/Utils/Monitor/MonitorCriteriaHumanMessages.test.ts +529 -0
- package/Tests/Server/Utils/Monitor/MonitorStepsProjectValidator.test.ts +136 -0
- package/Tests/Server/Utils/Monitor/MonitorStepsProjectValidatorLoadOrder.test.ts +472 -0
- package/Tests/Server/Utils/Monitor/NetworkDeviceHydrationUtil.test.ts +48 -2
- package/Tests/Server/Utils/Monitor/SloTemplateMetricEmitterContract.test.ts +435 -475
- package/Tests/Server/Utils/Rules/MonitorRulePatternValidator.test.ts +77 -0
- package/Tests/Server/Utils/Rules/OwnerRuleAssignment.test.ts +585 -0
- package/Tests/Server/Utils/Rules/RuleRun/RuleRunPermission.test.ts +365 -0
- package/Tests/Server/Utils/Rules/RuleRun/RuleRunRegistry.test.ts +173 -0
- package/Tests/Server/Utils/Rules/RuleRun/RuleRunner.test.ts +675 -0
- package/Tests/Server/Utils/SecurityEvent/ConnectorErrorMessage.test.ts +8 -8
- package/Tests/Server/Utils/SecurityEvent/Connectors/ConnectorFetchSummary.test.ts +261 -0
- package/Tests/Server/Utils/SecurityEvent/Connectors/ConnectorPlatformHealth.test.ts +68 -13
- package/Tests/Server/Utils/SecurityEvent/{GoogleSecOpsAuth.test.ts → Connectors/GoogleSecOps/GoogleSecOpsAuth.test.ts} +5 -5
- package/Tests/Server/Utils/SecurityEvent/{GoogleSecOpsClient.test.ts → Connectors/GoogleSecOps/GoogleSecOpsClient.test.ts} +4 -4
- package/Tests/Server/Utils/SecurityEvent/Connectors/GoogleSecOps/GoogleSecOpsConnector.test.ts +483 -0
- package/Tests/Server/Utils/SecurityEvent/Connectors/GoogleSecOps/GoogleSecOpsConnectorCuratedAndLateAlerts.test.ts +676 -0
- package/Tests/Server/Utils/SecurityEvent/Connectors/GoogleSecOps/GoogleSecOpsConnectorFetchEvents.test.ts +1994 -0
- package/Tests/Server/Utils/SecurityEvent/Connectors/GoogleSecOps/GoogleSecOpsConnectorFixtures.ts +332 -0
- package/Tests/Server/Utils/SecurityEvent/Connectors/GoogleSecOps/GoogleSecOpsConnectorHttpIntegration.test.ts +680 -0
- package/Tests/Server/Utils/SecurityEvent/Connectors/GoogleSecOps/GoogleSecOpsConnectorRequestContract.test.ts +1206 -0
- package/Tests/Server/Utils/SecurityEvent/Connectors/GoogleSecOps/GoogleSecOpsConnectorTestConnection.test.ts +1136 -0
- package/Tests/Server/Utils/SecurityEvent/Connectors/GoogleSecOps/GoogleSecOpsCuratedRuleCounts.test.ts +407 -0
- package/Tests/Server/Utils/SecurityEvent/{GoogleSecOpsErrorHandling.test.ts → Connectors/GoogleSecOps/GoogleSecOpsErrorHandling.test.ts} +5 -5
- package/Tests/Server/Utils/SecurityEvent/Connectors/GoogleSecOps/GoogleSecOpsPollingAdaptiveCatchUp.test.ts +730 -0
- package/Tests/Server/Utils/SecurityEvent/{GoogleSecOpsClickhouseIntegration.test.ts → Connectors/GoogleSecOps/GoogleSecOpsPollingClickhouseIntegration.test.ts} +131 -36
- package/Tests/Server/Utils/SecurityEvent/Connectors/GoogleSecOps/GoogleSecOpsPollingFailureTaxonomy.test.ts +772 -0
- package/Tests/Server/Utils/SecurityEvent/Connectors/GoogleSecOps/GoogleSecOpsPollingFixtures.ts +648 -0
- package/Tests/Server/Utils/SecurityEvent/{GoogleSecOpsHttpIntegration.test.ts → Connectors/GoogleSecOps/GoogleSecOpsPollingHttpIntegration.test.ts} +230 -225
- package/Tests/Server/Utils/SecurityEvent/Connectors/GoogleSecOps/GoogleSecOpsPollingIntegration.test.ts +1390 -0
- package/Tests/Server/Utils/SecurityEvent/Connectors/GoogleSecOps/GoogleSecOpsPollingLoop.test.ts +981 -0
- package/Tests/Server/Utils/SecurityEvent/Connectors/GoogleSecOps/GoogleSecOpsPollingNothingImportedRegression.test.ts +290 -0
- package/Tests/Server/Utils/SecurityEvent/{GoogleSecOpsRequestContract.test.ts → Connectors/GoogleSecOps/GoogleSecOpsRequestContract.test.ts} +2 -2
- package/Tests/Server/Utils/SecurityEvent/{GoogleSecOpsResponseParsing.test.ts → Connectors/GoogleSecOps/GoogleSecOpsResponseParsing.test.ts} +5 -5
- package/Tests/Server/Utils/SecurityEvent/{GoogleSecOpsSearchDetections.test.ts → Connectors/GoogleSecOps/GoogleSecOpsSearchDetections.test.ts} +38 -5
- package/Tests/Server/Utils/SecurityEvent/Connectors/GoogleSecOps/GoogleSecOpsTesterIntegration.test.ts +421 -0
- package/Tests/Server/Utils/SecurityEvent/Connectors/SecurityEventConnectionPoller.test.ts +1445 -3
- package/Tests/Server/Utils/SecurityEvent/Connectors/SecurityEventConnectionRunExecutor.test.ts +14 -4
- package/Tests/Server/Utils/SecurityEvent/Connectors/SecurityEventConnectionTester.test.ts +313 -4
- package/Tests/Server/Utils/SessionReplay/SessionReplayReadServiceQueries.test.ts +352 -0
- package/Tests/Server/Utils/Slo/SloFeedUtil.test.ts +326 -0
- package/Tests/Server/Utils/Slo/SloLegacyMonitorLabelAdoption.test.ts +260 -0
- package/Tests/Server/Utils/Slo/SloMetricUtil.test.ts +592 -0
- package/Tests/Server/Utils/Slo/SloRecordReferenceValidator.test.ts +311 -0
- package/Tests/Server/Utils/StatusPageResource.test.ts +91 -3
- package/Tests/Server/Utils/TailwindBuildCopy.test.ts +14 -2
- package/Tests/Server/Utils/Telemetry/HostAssetAttributesFromOtlp.test.ts +235 -0
- package/Tests/Server/Utils/Telemetry/TelemetryEntity.test.ts +385 -2
- package/Tests/Server/Utils/VendorAssets.test.ts +17 -3
- package/Tests/Types/AI/AIChatPageContext.test.ts +0 -0
- package/Tests/Types/AI/AIResourceContext.test.ts +312 -0
- package/Tests/Types/Billing/SubscriptionStatus.test.ts +176 -0
- package/Tests/Types/Billing/SubscriptionStatusPastDueMonitoring.test.ts +187 -0
- package/Tests/Types/Dashboard/DashboardTemplateInvariants.test.ts +53 -7
- package/Tests/Types/Dashboard/SloDashboardTemplate.test.ts +816 -792
- package/Tests/Types/Database/UniqueColumnsTogether.test.ts +100 -0
- package/Tests/Types/Monitor/CriteriaFilter.test.ts +216 -24
- package/Tests/Types/Monitor/MetricAndProfileDefaultCriteria.test.ts +4 -4
- package/Tests/Types/Monitor/MonitorStepDnssecMonitor.test.ts +14 -1
- package/Tests/Types/Monitor/MonitorStepDomainMonitor.test.ts +14 -1
- package/Tests/Types/Monitor/MonitorStepExternalStatusPageMonitor.test.ts +14 -1
- package/Tests/Types/Monitor/MonitorStepRetriesParsing.test.ts +201 -0
- package/Tests/Types/Monitor/MonitorStepRetryPersistence.test.ts +125 -0
- package/Tests/Types/Rules/RuleRun.test.ts +315 -0
- package/Tests/Types/Rum/SessionReplayApiContracts.test.ts +60 -0
- package/Tests/Types/SecurityEvent/Connectors/SecurityEventConnectorCatalog.test.ts +29 -4
- package/Tests/Types/StatusPage/SubscriberNotificationTemplateVariables.test.ts +217 -0
- package/Tests/Types/StatusPage/SubscriberUpdateNotification.test.ts +200 -0
- package/Tests/Types/WebsiteRequest.test.ts +44 -0
- package/Tests/UI/Components/ActiveFilterChipsLockedFilters.test.tsx +141 -87
- package/Tests/UI/Components/AlertBanner.test.tsx +319 -0
- package/Tests/UI/Components/BulkArchiveActionsCopy.test.tsx +310 -0
- package/Tests/UI/Components/Detail/DetailIdIsUnique.test.tsx +87 -0
- package/Tests/UI/Components/Dropdown/DropdownClearable.test.tsx +393 -0
- package/Tests/UI/Components/Dropdown/DropdownMultiSelectChipAccessibleName.test.tsx +64 -0
- package/Tests/UI/Components/EmptyState/EmptyState.test.tsx +335 -4
- package/Tests/UI/Components/EmptyState/EmptyStateGuideLinks.test.tsx +337 -0
- package/Tests/UI/Components/Forms/ModelFormJsonColumns.test.tsx +21 -20
- package/Tests/UI/Components/Forms/MonitorDescriptionForm.test.tsx +410 -0
- package/Tests/UI/Components/LabelRuleImportExport.test.tsx +15 -2
- package/Tests/UI/Components/LockedFilterChip.test.tsx +281 -144
- package/Tests/UI/Components/ModelTable/BaseModelTableReadPermissions.test.tsx +439 -0
- package/Tests/UI/Components/MoreMenu.test.tsx +133 -0
- package/Tests/UI/Components/MoreMenuMotion.test.tsx +84 -3
- package/Tests/UI/Components/NavBarMenuSearch.test.tsx +372 -0
- package/Tests/UI/Components/RuleCriteria/RuleCriteriaModelTable.test.tsx +3 -3
- package/Tests/UI/Components/RuleRun/RuleDetailFields.test.tsx +336 -0
- package/Tests/UI/Components/RuleRun/RuleTable.test.tsx +304 -0
- package/Tests/UI/Components/RuleRun/RunRuleNowModal.test.tsx +231 -0
- package/Tests/UI/Components/RuleRun/RunRulesBulkAction.test.ts +213 -0
- package/Tests/UI/Components/TelemetryActiveFilterChipsLockedFilters.test.tsx +124 -61
- package/Tests/UI/EsbuildConfig.test.ts +1 -1
- package/Tests/UI/Monitor/MonitorStepRetrySettings.test.tsx +616 -0
- package/Tests/UI/ReactRouterSingletonBuild.test.ts +4 -2
- package/Tests/UI/Rum/ReplayEngine.test.ts +333 -0
- package/Tests/UI/Rum/ReplayHeader.test.tsx +257 -123
- package/Tests/UI/Rum/ReplayPinControl.test.tsx +122 -0
- package/Tests/UI/Rum/ReplayPlayerChrome.test.tsx +245 -0
- package/Tests/UI/Rum/ReplayRail.test.tsx +294 -0
- package/Tests/UI/Rum/ReplayScrubber.test.tsx +301 -1
- package/Tests/UI/Rum/ReplayStage.test.tsx +565 -172
- package/Tests/UI/Rum/ReplayStageOverlays.test.tsx +343 -3
- package/Tests/UI/Rum/ReplayTabSwitcher.test.tsx +1424 -0
- package/Tests/UI/Rum/ReplayTimeline.test.tsx +222 -0
- package/Tests/UI/Utils/DashboardStackingLayers.test.ts +8 -1
- package/Tests/UI/Utils/RuleRunClient.test.ts +303 -0
- package/Tests/UI/Utils/Telemetry/TelemetryEntityNames.test.ts +1 -0
- package/Tests/Utils/API.test.ts +96 -0
- package/Tests/Utils/Dashboard/Components/DashboardComponentDefaults.test.ts +2 -0
- package/Tests/Utils/Dashboard/Components/DashboardSloListComponent.test.ts +206 -0
- package/Tests/Utils/Dashboard/DashboardSloComponent.test.ts +36 -2
- package/Tests/Utils/Dashboard/SloTemplateVariableScoping.test.ts +409 -588
- package/Tests/Utils/Dashboard/SloWidgetSource.test.ts +351 -0
- package/Tests/Utils/HTTPResponseBodyReader.test.ts +188 -1
- package/Tests/Utils/Markdown/MarkdownEscape.test.ts +361 -0
- package/Tests/Utils/Metrics/MetricEventScopeUrl.test.ts +101 -0
- package/Tests/Utils/Monitor/MonitorTestAvailabilityUtil.test.ts +256 -0
- package/Tests/Utils/NetworkDiscovery/DiscoveredDeviceBuilder.test.ts +1425 -118
- package/Tests/Utils/NetworkDiscovery/DiscoveredHostUtil.test.ts +188 -3
- package/Tests/Utils/NetworkDiscovery/DiscoveryReverseDnsChain.test.ts +661 -13
- package/Tests/Utils/NetworkDiscovery/NetbiosNameUtil.test.ts +349 -0
- package/Tests/Utils/NetworkDiscovery/RunImportedDeviceNaming.test.ts +656 -0
- package/Tests/Utils/NetworkDiscovery/ShortDeviceNamePlanner.test.ts +1020 -0
- package/Tests/Utils/NetworkDiscovery/ShortHostnameUtil.test.ts +619 -0
- package/Tests/Utils/NetworkSite/CidrMatchUtil.test.ts +317 -0
- package/Tests/Utils/Project/DataResidency.test.ts +198 -0
- package/Tests/Utils/Rules/RuleRunSummary.test.ts +394 -0
- package/Tests/Utils/Slo/SloAffectedResourceMarkdown.test.ts +302 -0
- package/Tests/Utils/Slo/SloBurnRateTemplate.test.ts +468 -0
- package/Tests/Utils/Slo/SloEvaluation.test.ts +20 -4
- package/Tests/Utils/Slo/SloFeedMarkdown.test.ts +1185 -0
- package/Tests/Utils/Slo/SloHealth.test.ts +262 -0
- package/Tests/Utils/Slo/SloHistoryMetricName.test.ts +102 -0
- package/Tests/Utils/Slo/SloListWidgetFormat.test.ts +522 -0
- package/Tests/Utils/Slo/SloMetricType.test.ts +355 -0
- package/Tests/Utils/Slo/SloMonitorRuleCriteria.test.ts +387 -0
- package/Tests/Utils/Slo/SloMonitorStatusSummary.test.ts +210 -0
- package/Tests/Utils/Slo/SloOverviewText.test.ts +226 -0
- package/Tests/Utils/Slo/SloProjection.test.ts +1039 -0
- package/Tests/Utils/Slo/SloWidgetFormat.test.ts +47 -0
- package/Tests/Utils/Telemetry/HostIpAddresses.test.ts +105 -0
- package/Tests/Utils/Telemetry/LockedFilterSearch.test.ts +1 -80
- package/Types/AI/AIChatPageContext.ts +87 -2
- package/Types/AI/AIChatTypes.ts +4 -0
- package/Types/AI/AIResourceContext.ts +198 -0
- package/Types/AI/InvestigationNotStartedReason.ts +30 -0
- package/Types/BaseDatabase/EnableAuditLogOn.ts +41 -0
- package/Types/Billing/SubscriptionStatus.ts +39 -4
- package/Types/Dashboard/DashboardComponentType.ts +1 -0
- package/Types/Dashboard/DashboardComponents/ComponentArgument.ts +5 -0
- package/Types/Dashboard/DashboardComponents/DashboardSloComponent.ts +10 -0
- package/Types/Dashboard/DashboardComponents/DashboardSloListComponent.ts +29 -0
- package/Types/Dashboard/DashboardTemplates.ts +290 -297
- package/Types/Database/EnableAuditLog.ts +23 -1
- package/Types/Database/UniqueColumnsTogether.ts +55 -0
- package/Types/Email/EmailTemplateType.ts +4 -0
- package/Types/Metrics/MetricQueryConfigData.ts +8 -0
- package/Types/Monitor/CriteriaFilter.ts +55 -8
- package/Types/Monitor/MonitorStep.ts +5 -2
- package/Types/Monitor/MonitorStepDnsMonitor.ts +3 -1
- package/Types/Monitor/MonitorStepDnssecMonitor.ts +3 -1
- package/Types/Monitor/MonitorStepDomainMonitor.ts +3 -1
- package/Types/Monitor/MonitorStepExternalStatusPageMonitor.ts +3 -1
- package/Types/Monitor/MonitorStepRetries.ts +59 -0
- package/Types/Monitor/MonitorStepSnmpMonitor.ts +9 -2
- package/Types/NetworkDevice/NetworkDeviceDiagnosticResult.ts +104 -0
- package/Types/NetworkDevice/NetworkDeviceDiagnosticStatus.ts +47 -0
- package/Types/NetworkDevice/NetworkDeviceDiagnosticType.ts +47 -0
- package/Types/NetworkDevice/NetworkDevicePingMetricNames.ts +20 -0
- package/Types/Permission.ts +127 -0
- package/Types/Rules/RuleCriteriaFieldRegistry.ts +5 -0
- package/Types/Rules/RuleRun.ts +518 -0
- package/Types/Rum/SessionReplayApi.ts +18 -0
- package/Types/Rum/WebVitals.ts +71 -0
- package/Types/SecurityEvent/Connectors/ConnectorDiagnostics.ts +6 -0
- package/Types/SecurityEvent/Connectors/SecurityEventConnectionDiagnostics.ts +30 -4
- package/Types/SecurityEvent/Connectors/SecurityEventConnectorCatalog.ts +108 -1
- package/Types/SecurityEvent/Connectors/SecurityEventConnectorProvider.ts +6 -2
- package/Types/ServiceLevelObjective/SloHistoryMetricName.ts +25 -0
- package/Types/ServiceLevelObjective/SloMetricType.ts +49 -0
- package/Types/StatusPage/StatusPageSubscriberNotificationEventType.ts +4 -0
- package/Types/StatusPage/SubscriberNotificationTemplateVariables.ts +331 -0
- package/Types/StatusPage/SubscriberNotificationTrigger.ts +12 -0
- package/Types/StatusPage/SubscriberUpdateNotification.ts +89 -0
- package/Types/Telemetry/LockedFilterDetail.ts +7 -28
- package/Types/Telemetry/ServiceType.ts +7 -0
- package/Types/WebsiteRequest.ts +2 -0
- package/Typings/Index.d.ts +53 -3
- package/UI/Components/AlertBanner/AlertBanner.tsx +85 -27
- package/UI/Components/BulkUpdate/BulkArchiveActions.tsx +21 -2
- package/UI/Components/Detail/Detail.tsx +9 -2
- package/UI/Components/Dropdown/Dropdown.tsx +64 -1
- package/UI/Components/EditionLabel/EditionLabel.tsx +7 -5
- package/UI/Components/EmptyState/EmptyState.tsx +27 -3
- package/UI/Components/EmptyState/EmptyStateGuideLinks.tsx +124 -0
- package/UI/Components/Forms/ModelForm.tsx +6 -5
- package/UI/Components/KeyboardShortcut/Screenshots/README.md +1 -1
- package/UI/Components/LabelRule/LabelRuleTable.tsx +8 -2
- package/UI/Components/LogsViewer/LogsViewer.tsx +2 -6
- package/UI/Components/LogsViewer/components/ActiveFilterChips.tsx +2 -13
- package/UI/Components/LogsViewer/types.ts +2 -2
- package/UI/Components/ModelTable/BaseModelTable.tsx +8 -0
- package/UI/Components/MoreMenu/MoreMenu.tsx +14 -3
- package/UI/Components/Navbar/NavBar.tsx +2 -0
- package/UI/Components/Navbar/NavBarMenuModal.tsx +6 -2
- package/UI/Components/RuleRun/RuleDetailFields.tsx +359 -0
- package/UI/Components/RuleRun/RuleTable.tsx +183 -0
- package/UI/Components/RuleRun/RuleView.tsx +170 -0
- package/UI/Components/RuleRun/RunRuleNowModal.tsx +147 -0
- package/UI/Components/RuleRun/RunRulesBulkAction.ts +103 -0
- package/UI/Components/TelemetryViewer/TelemetryViewer.tsx +2 -6
- package/UI/Components/TelemetryViewer/components/LockedFilterChip.tsx +38 -104
- package/UI/Components/TelemetryViewer/components/TelemetryActiveFilterChips.tsx +2 -18
- package/UI/Components/TelemetryViewer/types.ts +2 -2
- package/UI/Utils/Rules/RuleRunClient.ts +178 -0
- package/UI/Utils/Telemetry/TelemetryEntityNames.ts +8 -0
- package/UI/esbuild-config.js +4 -4
- package/Utils/API.ts +10 -1
- package/Utils/Dashboard/Components/DashboardSloComponent.ts +19 -2
- package/Utils/Dashboard/Components/DashboardSloListComponent.ts +126 -0
- package/Utils/Dashboard/Components/Index.ts +7 -0
- package/Utils/Dashboard/HtmlWidgetDocument.ts +1 -1
- package/Utils/Dashboard/SloWidgetSource.ts +188 -0
- package/Utils/HTTPResponseBodyReader.ts +64 -8
- package/Utils/Markdown/MarkdownEscape.ts +63 -0
- package/Utils/Metrics/MetricExplorerUrl.ts +19 -0
- package/Utils/Monitor/MonitorTestAvailabilityUtil.ts +92 -0
- package/Utils/NetworkDiscovery/DiscoveredDeviceBuilder.ts +161 -36
- package/Utils/NetworkDiscovery/DiscoveredHostUtil.ts +25 -0
- package/Utils/NetworkDiscovery/NetbiosNameUtil.ts +146 -0
- package/Utils/NetworkDiscovery/RunImportedDeviceNaming.ts +390 -0
- package/Utils/NetworkDiscovery/ShortDeviceNamePlanner.ts +291 -0
- package/Utils/NetworkDiscovery/ShortHostnameUtil.ts +91 -0
- package/Utils/NetworkSite/CidrMatchUtil.ts +37 -12
- package/Utils/Project/DataResidency.ts +63 -0
- package/Utils/Rules/RuleRunSummary.ts +323 -0
- package/Utils/Slo/SloAffectedResourceMarkdown.ts +123 -0
- package/Utils/Slo/SloBurnRateTemplate.ts +373 -0
- package/Utils/Slo/SloFeedMarkdown.ts +1507 -0
- package/Utils/Slo/SloHealth.ts +96 -9
- package/Utils/Slo/SloListWidgetFormat.ts +370 -0
- package/Utils/Slo/SloMetricType.ts +237 -0
- package/Utils/Slo/SloMonitorRuleCriteria.ts +364 -0
- package/Utils/Slo/SloMonitorStatusSummary.ts +210 -0
- package/Utils/Slo/SloOverviewText.ts +265 -0
- package/Utils/Slo/SloProjection.ts +967 -0
- package/Utils/Slo/SloWidgetFormat.ts +12 -2
- package/Utils/Telemetry/HostIpAddresses.ts +46 -2
- package/Utils/Telemetry/LockedFilterSearch.ts +3 -49
- package/build/dist/Models/AnalyticsModels/AuditLog.js +70 -1
- package/build/dist/Models/AnalyticsModels/AuditLog.js.map +1 -1
- package/build/dist/Models/AnalyticsModels/SecurityEvent.js +4 -4
- package/build/dist/Models/DatabaseModels/AIAgentOwnerTeam.js +4 -1
- package/build/dist/Models/DatabaseModels/AIAgentOwnerTeam.js.map +1 -1
- package/build/dist/Models/DatabaseModels/AIAgentOwnerUser.js +4 -1
- package/build/dist/Models/DatabaseModels/AIAgentOwnerUser.js.map +1 -1
- package/build/dist/Models/DatabaseModels/Alert.js +72 -0
- package/build/dist/Models/DatabaseModels/Alert.js.map +1 -1
- package/build/dist/Models/DatabaseModels/AlertEpisodeOwnerTeam.js +3 -1
- package/build/dist/Models/DatabaseModels/AlertEpisodeOwnerTeam.js.map +1 -1
- package/build/dist/Models/DatabaseModels/AlertEpisodeOwnerUser.js +3 -1
- package/build/dist/Models/DatabaseModels/AlertEpisodeOwnerUser.js.map +1 -1
- package/build/dist/Models/DatabaseModels/AlertOwnerTeam.js +3 -1
- package/build/dist/Models/DatabaseModels/AlertOwnerTeam.js.map +1 -1
- package/build/dist/Models/DatabaseModels/AlertOwnerUser.js +3 -1
- package/build/dist/Models/DatabaseModels/AlertOwnerUser.js.map +1 -1
- package/build/dist/Models/DatabaseModels/CephClusterOwnerTeam.js +4 -1
- package/build/dist/Models/DatabaseModels/CephClusterOwnerTeam.js.map +1 -1
- package/build/dist/Models/DatabaseModels/CephClusterOwnerUser.js +4 -1
- package/build/dist/Models/DatabaseModels/CephClusterOwnerUser.js.map +1 -1
- package/build/dist/Models/DatabaseModels/CloudResourceOwnerTeam.js +4 -1
- package/build/dist/Models/DatabaseModels/CloudResourceOwnerTeam.js.map +1 -1
- package/build/dist/Models/DatabaseModels/CloudResourceOwnerUser.js +4 -1
- package/build/dist/Models/DatabaseModels/CloudResourceOwnerUser.js.map +1 -1
- package/build/dist/Models/DatabaseModels/DashboardOwnerTeam.js +3 -1
- package/build/dist/Models/DatabaseModels/DashboardOwnerTeam.js.map +1 -1
- package/build/dist/Models/DatabaseModels/DashboardOwnerUser.js +3 -1
- package/build/dist/Models/DatabaseModels/DashboardOwnerUser.js.map +1 -1
- package/build/dist/Models/DatabaseModels/DatabaseBaseModel/DatabaseBaseModel.js +3 -0
- package/build/dist/Models/DatabaseModels/DatabaseBaseModel/DatabaseBaseModel.js.map +1 -1
- package/build/dist/Models/DatabaseModels/DockerHostOwnerTeam.js +4 -1
- package/build/dist/Models/DatabaseModels/DockerHostOwnerTeam.js.map +1 -1
- package/build/dist/Models/DatabaseModels/DockerHostOwnerUser.js +4 -1
- package/build/dist/Models/DatabaseModels/DockerHostOwnerUser.js.map +1 -1
- package/build/dist/Models/DatabaseModels/DockerSwarmClusterOwnerTeam.js +4 -1
- package/build/dist/Models/DatabaseModels/DockerSwarmClusterOwnerTeam.js.map +1 -1
- package/build/dist/Models/DatabaseModels/DockerSwarmClusterOwnerUser.js +4 -1
- package/build/dist/Models/DatabaseModels/DockerSwarmClusterOwnerUser.js.map +1 -1
- package/build/dist/Models/DatabaseModels/GlobalConfig.js +1 -1
- package/build/dist/Models/DatabaseModels/GlobalConfig.js.map +1 -1
- package/build/dist/Models/DatabaseModels/HostOwnerTeam.js +4 -1
- package/build/dist/Models/DatabaseModels/HostOwnerTeam.js.map +1 -1
- package/build/dist/Models/DatabaseModels/HostOwnerUser.js +4 -1
- package/build/dist/Models/DatabaseModels/HostOwnerUser.js.map +1 -1
- package/build/dist/Models/DatabaseModels/Incident.js +76 -0
- package/build/dist/Models/DatabaseModels/Incident.js.map +1 -1
- package/build/dist/Models/DatabaseModels/IncidentEpisodeOwnerTeam.js +3 -1
- package/build/dist/Models/DatabaseModels/IncidentEpisodeOwnerTeam.js.map +1 -1
- package/build/dist/Models/DatabaseModels/IncidentEpisodeOwnerUser.js +3 -1
- package/build/dist/Models/DatabaseModels/IncidentEpisodeOwnerUser.js.map +1 -1
- package/build/dist/Models/DatabaseModels/IncidentEpisodePublicNote.js +75 -0
- package/build/dist/Models/DatabaseModels/IncidentEpisodePublicNote.js.map +1 -1
- package/build/dist/Models/DatabaseModels/IncidentOwnerTeam.js +3 -1
- package/build/dist/Models/DatabaseModels/IncidentOwnerTeam.js.map +1 -1
- package/build/dist/Models/DatabaseModels/IncidentOwnerUser.js +3 -1
- package/build/dist/Models/DatabaseModels/IncidentOwnerUser.js.map +1 -1
- package/build/dist/Models/DatabaseModels/IncidentPublicNote.js +75 -0
- package/build/dist/Models/DatabaseModels/IncidentPublicNote.js.map +1 -1
- package/build/dist/Models/DatabaseModels/IncidentTemplateOwnerTeam.js +4 -1
- package/build/dist/Models/DatabaseModels/IncidentTemplateOwnerTeam.js.map +1 -1
- package/build/dist/Models/DatabaseModels/IncidentTemplateOwnerUser.js +4 -1
- package/build/dist/Models/DatabaseModels/IncidentTemplateOwnerUser.js.map +1 -1
- package/build/dist/Models/DatabaseModels/IncomingCallPolicyOwnerTeam.js +3 -1
- package/build/dist/Models/DatabaseModels/IncomingCallPolicyOwnerTeam.js.map +1 -1
- package/build/dist/Models/DatabaseModels/IncomingCallPolicyOwnerUser.js +3 -1
- package/build/dist/Models/DatabaseModels/IncomingCallPolicyOwnerUser.js.map +1 -1
- package/build/dist/Models/DatabaseModels/Index.js +6 -4
- package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
- package/build/dist/Models/DatabaseModels/IoTFleetOwnerTeam.js +4 -1
- package/build/dist/Models/DatabaseModels/IoTFleetOwnerTeam.js.map +1 -1
- package/build/dist/Models/DatabaseModels/IoTFleetOwnerUser.js +4 -1
- package/build/dist/Models/DatabaseModels/IoTFleetOwnerUser.js.map +1 -1
- package/build/dist/Models/DatabaseModels/KubernetesClusterOwnerTeam.js +4 -1
- package/build/dist/Models/DatabaseModels/KubernetesClusterOwnerTeam.js.map +1 -1
- package/build/dist/Models/DatabaseModels/KubernetesClusterOwnerUser.js +4 -1
- package/build/dist/Models/DatabaseModels/KubernetesClusterOwnerUser.js.map +1 -1
- package/build/dist/Models/DatabaseModels/Monitor.js +2 -3
- package/build/dist/Models/DatabaseModels/Monitor.js.map +1 -1
- package/build/dist/Models/DatabaseModels/MonitorGroupOwnerTeam.js +4 -1
- package/build/dist/Models/DatabaseModels/MonitorGroupOwnerTeam.js.map +1 -1
- package/build/dist/Models/DatabaseModels/MonitorGroupOwnerUser.js +4 -1
- package/build/dist/Models/DatabaseModels/MonitorGroupOwnerUser.js.map +1 -1
- package/build/dist/Models/DatabaseModels/MonitorOwnerTeam.js +3 -1
- package/build/dist/Models/DatabaseModels/MonitorOwnerTeam.js.map +1 -1
- package/build/dist/Models/DatabaseModels/MonitorOwnerUser.js +3 -1
- package/build/dist/Models/DatabaseModels/MonitorOwnerUser.js.map +1 -1
- package/build/dist/Models/DatabaseModels/MonitorTemplate.js +2 -3
- package/build/dist/Models/DatabaseModels/MonitorTemplate.js.map +1 -1
- package/build/dist/Models/DatabaseModels/NetworkDevice.js +68 -0
- package/build/dist/Models/DatabaseModels/NetworkDevice.js.map +1 -1
- package/build/dist/Models/DatabaseModels/NetworkDeviceDiagnostic.js +772 -0
- package/build/dist/Models/DatabaseModels/NetworkDeviceDiagnostic.js.map +1 -0
- package/build/dist/Models/DatabaseModels/NetworkDeviceDiscoveryScan.js +140 -0
- package/build/dist/Models/DatabaseModels/NetworkDeviceDiscoveryScan.js.map +1 -1
- package/build/dist/Models/DatabaseModels/NetworkDeviceOwnerTeam.js +4 -1
- package/build/dist/Models/DatabaseModels/NetworkDeviceOwnerTeam.js.map +1 -1
- package/build/dist/Models/DatabaseModels/NetworkDeviceOwnerUser.js +4 -1
- package/build/dist/Models/DatabaseModels/NetworkDeviceOwnerUser.js.map +1 -1
- package/build/dist/Models/DatabaseModels/NetworkSiteAssignmentRule.js +1 -1
- package/build/dist/Models/DatabaseModels/NetworkSiteAssignmentRule.js.map +1 -1
- package/build/dist/Models/DatabaseModels/OnCallDutyPolicyOwnerTeam.js +3 -1
- package/build/dist/Models/DatabaseModels/OnCallDutyPolicyOwnerTeam.js.map +1 -1
- package/build/dist/Models/DatabaseModels/OnCallDutyPolicyOwnerUser.js +3 -1
- package/build/dist/Models/DatabaseModels/OnCallDutyPolicyOwnerUser.js.map +1 -1
- package/build/dist/Models/DatabaseModels/OnCallDutyPolicyScheduleOwnerTeam.js +3 -1
- package/build/dist/Models/DatabaseModels/OnCallDutyPolicyScheduleOwnerTeam.js.map +1 -1
- package/build/dist/Models/DatabaseModels/OnCallDutyPolicyScheduleOwnerUser.js +3 -1
- package/build/dist/Models/DatabaseModels/OnCallDutyPolicyScheduleOwnerUser.js.map +1 -1
- package/build/dist/Models/DatabaseModels/PodmanHostOwnerTeam.js +4 -1
- package/build/dist/Models/DatabaseModels/PodmanHostOwnerTeam.js.map +1 -1
- package/build/dist/Models/DatabaseModels/PodmanHostOwnerUser.js +4 -1
- package/build/dist/Models/DatabaseModels/PodmanHostOwnerUser.js.map +1 -1
- package/build/dist/Models/DatabaseModels/ProbeOwnerTeam.js +4 -1
- package/build/dist/Models/DatabaseModels/ProbeOwnerTeam.js.map +1 -1
- package/build/dist/Models/DatabaseModels/ProbeOwnerUser.js +4 -1
- package/build/dist/Models/DatabaseModels/ProbeOwnerUser.js.map +1 -1
- package/build/dist/Models/DatabaseModels/Project.js +42 -0
- package/build/dist/Models/DatabaseModels/Project.js.map +1 -1
- package/build/dist/Models/DatabaseModels/ProxmoxClusterOwnerTeam.js +4 -1
- package/build/dist/Models/DatabaseModels/ProxmoxClusterOwnerTeam.js.map +1 -1
- package/build/dist/Models/DatabaseModels/ProxmoxClusterOwnerUser.js +4 -1
- package/build/dist/Models/DatabaseModels/ProxmoxClusterOwnerUser.js.map +1 -1
- package/build/dist/Models/DatabaseModels/RumApplicationOwnerTeam.js +4 -1
- package/build/dist/Models/DatabaseModels/RumApplicationOwnerTeam.js.map +1 -1
- package/build/dist/Models/DatabaseModels/RumApplicationOwnerUser.js +4 -1
- package/build/dist/Models/DatabaseModels/RumApplicationOwnerUser.js.map +1 -1
- package/build/dist/Models/DatabaseModels/RunbookOwnerTeam.js +3 -1
- package/build/dist/Models/DatabaseModels/RunbookOwnerTeam.js.map +1 -1
- package/build/dist/Models/DatabaseModels/RunbookOwnerUser.js +3 -1
- package/build/dist/Models/DatabaseModels/RunbookOwnerUser.js.map +1 -1
- package/build/dist/Models/DatabaseModels/RunnerOwnerTeam.js +3 -1
- package/build/dist/Models/DatabaseModels/RunnerOwnerTeam.js.map +1 -1
- package/build/dist/Models/DatabaseModels/RunnerOwnerUser.js +3 -1
- package/build/dist/Models/DatabaseModels/RunnerOwnerUser.js.map +1 -1
- package/build/dist/Models/DatabaseModels/ScheduledMaintenanceOwnerTeam.js +3 -1
- package/build/dist/Models/DatabaseModels/ScheduledMaintenanceOwnerTeam.js.map +1 -1
- package/build/dist/Models/DatabaseModels/ScheduledMaintenanceOwnerUser.js +3 -1
- package/build/dist/Models/DatabaseModels/ScheduledMaintenanceOwnerUser.js.map +1 -1
- package/build/dist/Models/DatabaseModels/ScheduledMaintenancePublicNote.js +75 -0
- package/build/dist/Models/DatabaseModels/ScheduledMaintenancePublicNote.js.map +1 -1
- package/build/dist/Models/DatabaseModels/ScheduledMaintenanceTemplateOwnerTeam.js +6 -1
- package/build/dist/Models/DatabaseModels/ScheduledMaintenanceTemplateOwnerTeam.js.map +1 -1
- package/build/dist/Models/DatabaseModels/ScheduledMaintenanceTemplateOwnerUser.js +6 -1
- package/build/dist/Models/DatabaseModels/ScheduledMaintenanceTemplateOwnerUser.js.map +1 -1
- package/build/dist/Models/DatabaseModels/SecurityEventConnection.js +11 -11
- package/build/dist/Models/DatabaseModels/ServerlessFunctionOwnerTeam.js +4 -1
- package/build/dist/Models/DatabaseModels/ServerlessFunctionOwnerTeam.js.map +1 -1
- package/build/dist/Models/DatabaseModels/ServerlessFunctionOwnerUser.js +4 -1
- package/build/dist/Models/DatabaseModels/ServerlessFunctionOwnerUser.js.map +1 -1
- package/build/dist/Models/DatabaseModels/ServiceLevelObjective.js +192 -10
- package/build/dist/Models/DatabaseModels/ServiceLevelObjective.js.map +1 -1
- package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveBurnRateRule.js +798 -96
- package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveBurnRateRule.js.map +1 -1
- package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveFeed.js +596 -0
- package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveFeed.js.map +1 -0
- package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveMonitorRule.js +590 -0
- package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveMonitorRule.js.map +1 -0
- package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveOwnerTeam.js +19 -1
- package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveOwnerTeam.js.map +1 -1
- package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveOwnerUser.js +19 -1
- package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveOwnerUser.js.map +1 -1
- package/build/dist/Models/DatabaseModels/ServiceOwnerTeam.js +4 -1
- package/build/dist/Models/DatabaseModels/ServiceOwnerTeam.js.map +1 -1
- package/build/dist/Models/DatabaseModels/ServiceOwnerUser.js +4 -1
- package/build/dist/Models/DatabaseModels/ServiceOwnerUser.js.map +1 -1
- package/build/dist/Models/DatabaseModels/StatusPageAnnouncement.js +75 -0
- package/build/dist/Models/DatabaseModels/StatusPageAnnouncement.js.map +1 -1
- package/build/dist/Models/DatabaseModels/StatusPageOwnerTeam.js +3 -1
- package/build/dist/Models/DatabaseModels/StatusPageOwnerTeam.js.map +1 -1
- package/build/dist/Models/DatabaseModels/StatusPageOwnerUser.js +3 -1
- package/build/dist/Models/DatabaseModels/StatusPageOwnerUser.js.map +1 -1
- package/build/dist/Models/DatabaseModels/ThreatIntelFeed.js +1 -1
- package/build/dist/Models/DatabaseModels/VMwareVCenterOwnerTeam.js +4 -1
- package/build/dist/Models/DatabaseModels/VMwareVCenterOwnerTeam.js.map +1 -1
- package/build/dist/Models/DatabaseModels/VMwareVCenterOwnerUser.js +4 -1
- package/build/dist/Models/DatabaseModels/VMwareVCenterOwnerUser.js.map +1 -1
- package/build/dist/Models/DatabaseModels/WorkflowOwnerTeam.js +3 -1
- package/build/dist/Models/DatabaseModels/WorkflowOwnerTeam.js.map +1 -1
- package/build/dist/Models/DatabaseModels/WorkflowOwnerUser.js +3 -1
- package/build/dist/Models/DatabaseModels/WorkflowOwnerUser.js.map +1 -1
- package/build/dist/Server/API/AIAgentDataAPI.js +1 -1
- package/build/dist/Server/API/AIChatAPI.js +3 -1
- package/build/dist/Server/API/AIChatAPI.js.map +1 -1
- package/build/dist/Server/API/AIInvestigationAPI.js +3 -0
- package/build/dist/Server/API/AIInvestigationAPI.js.map +1 -1
- package/build/dist/Server/API/BaseAPI.js +14 -0
- package/build/dist/Server/API/BaseAPI.js.map +1 -1
- package/build/dist/Server/API/BillingInvoiceAPI.js +233 -19
- package/build/dist/Server/API/BillingInvoiceAPI.js.map +1 -1
- package/build/dist/Server/API/BillingPaymentMethodAPI.js +86 -5
- package/build/dist/Server/API/BillingPaymentMethodAPI.js.map +1 -1
- package/build/dist/Server/API/DashboardAPI.js +72 -2
- package/build/dist/Server/API/DashboardAPI.js.map +1 -1
- package/build/dist/Server/API/SecurityEventConnectionAPI.js +102 -10
- package/build/dist/Server/API/SecurityEventConnectionAPI.js.map +1 -1
- package/build/dist/Server/API/StatusPageAPI.js +245 -155
- package/build/dist/Server/API/StatusPageAPI.js.map +1 -1
- package/build/dist/Server/Infrastructure/Postgres/LocalMigrationGenerationDataSource.js +1 -1
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1792800000000-AddNetworkDeviceDiagnostic.js +34 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1792800000000-AddNetworkDeviceDiagnostic.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1792900000000-AddNetworkDeviceDnsNameAndShortDeviceNames.js +24 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1792900000000-AddNetworkDeviceDnsNameAndShortDeviceNames.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1793000000000-AddNetbiosLookupToNetworkDeviceDiscoveryScan.js +21 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1793000000000-AddNetbiosLookupToNetworkDeviceDiscoveryScan.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1793100000000-SloProductOverhaul.js +207 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1793100000000-SloProductOverhaul.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1793200000000-BackfillSloMonitorRulesAndAffectedResources.js +72 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1793200000000-BackfillSloMonitorRulesAndAffectedResources.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1793300000000-AddDataResidencyToProject.js +20 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1793300000000-AddDataResidencyToProject.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1793400000000-AddSubscriberUpdateNotificationStatus.js +46 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1793400000000-AddSubscriberUpdateNotificationStatus.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1793500000000-MakeOwnerRowsUnique.js +602 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1793500000000-MakeOwnerRowsUnique.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1793700000000-AddAIInvestigationDecision.js +14 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1793700000000-AddAIInvestigationDecision.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1793800000000-RemoveMonitorDescriptionLengthLimit.js +20 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1793800000000-RemoveMonitorDescriptionLengthLimit.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +20 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
- package/build/dist/Server/Middleware/IdentityRateLimit.js +22 -1
- package/build/dist/Server/Middleware/IdentityRateLimit.js.map +1 -1
- package/build/dist/Server/Middleware/PublicDashboardRateLimit.js +117 -36
- package/build/dist/Server/Middleware/PublicDashboardRateLimit.js.map +1 -1
- package/build/dist/Server/Services/AlertEpisodeLabelRuleEngineService.js +112 -56
- package/build/dist/Server/Services/AlertEpisodeLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/AlertEpisodeOwnerRuleEngineService.js +167 -68
- package/build/dist/Server/Services/AlertEpisodeOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/AlertEpisodePrivacyRuleEngineService.js +87 -26
- package/build/dist/Server/Services/AlertEpisodePrivacyRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/AlertEpisodeService.js +13 -31
- package/build/dist/Server/Services/AlertEpisodeService.js.map +1 -1
- package/build/dist/Server/Services/AlertGroupingEngineService.js +7 -4
- package/build/dist/Server/Services/AlertGroupingEngineService.js.map +1 -1
- package/build/dist/Server/Services/AlertLabelRuleEngineService.js +270 -203
- package/build/dist/Server/Services/AlertLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/AlertOwnerRuleEngineService.js +498 -354
- package/build/dist/Server/Services/AlertOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/AlertPrivacyRuleEngineService.js +97 -34
- package/build/dist/Server/Services/AlertPrivacyRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/AlertService.js +104 -39
- package/build/dist/Server/Services/AlertService.js.map +1 -1
- package/build/dist/Server/Services/AuditLogService.js +408 -44
- package/build/dist/Server/Services/AuditLogService.js.map +1 -1
- package/build/dist/Server/Services/BillingInvoiceService.js +94 -85
- package/build/dist/Server/Services/BillingInvoiceService.js.map +1 -1
- package/build/dist/Server/Services/BillingService.js +406 -14
- package/build/dist/Server/Services/BillingService.js.map +1 -1
- package/build/dist/Server/Services/CephClusterLabelRuleEngineService.js +141 -92
- package/build/dist/Server/Services/CephClusterLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/CephClusterOwnerRuleEngineService.js +191 -99
- package/build/dist/Server/Services/CephClusterOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/CloudResourceLabelRuleEngineService.js +135 -86
- package/build/dist/Server/Services/CloudResourceLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/CloudResourceOwnerRuleEngineService.js +192 -99
- package/build/dist/Server/Services/CloudResourceOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/DashboardLabelRuleEngineService.js +117 -69
- package/build/dist/Server/Services/DashboardLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/DashboardOwnerRuleEngineService.js +173 -81
- package/build/dist/Server/Services/DashboardOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/DatabaseService.js +196 -19
- package/build/dist/Server/Services/DatabaseService.js.map +1 -1
- package/build/dist/Server/Services/DockerHostLabelRuleEngineService.js +141 -92
- package/build/dist/Server/Services/DockerHostLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/DockerHostOwnerRuleEngineService.js +191 -99
- package/build/dist/Server/Services/DockerHostOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/DockerSwarmClusterLabelRuleEngineService.js +145 -91
- package/build/dist/Server/Services/DockerSwarmClusterLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/DockerSwarmClusterOwnerRuleEngineService.js +193 -99
- package/build/dist/Server/Services/DockerSwarmClusterOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/HostLabelRuleEngineService.js +141 -92
- package/build/dist/Server/Services/HostLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/HostOwnerRuleEngineService.js +193 -101
- package/build/dist/Server/Services/HostOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/IncidentEpisodeLabelRuleEngineService.js +112 -56
- package/build/dist/Server/Services/IncidentEpisodeLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/IncidentEpisodeOwnerRuleEngineService.js +222 -63
- package/build/dist/Server/Services/IncidentEpisodeOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/IncidentEpisodePrivacyRuleEngineService.js +87 -26
- package/build/dist/Server/Services/IncidentEpisodePrivacyRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/IncidentEpisodePublicNoteService.js +24 -0
- package/build/dist/Server/Services/IncidentEpisodePublicNoteService.js.map +1 -1
- package/build/dist/Server/Services/IncidentEpisodeService.js +15 -68
- package/build/dist/Server/Services/IncidentEpisodeService.js.map +1 -1
- package/build/dist/Server/Services/IncidentGroupingEngineService.js +7 -4
- package/build/dist/Server/Services/IncidentGroupingEngineService.js.map +1 -1
- package/build/dist/Server/Services/IncidentLabelRuleEngineService.js +258 -192
- package/build/dist/Server/Services/IncidentLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/IncidentOwnerRuleEngineService.js +519 -376
- package/build/dist/Server/Services/IncidentOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/IncidentPrivacyRuleEngineService.js +95 -32
- package/build/dist/Server/Services/IncidentPrivacyRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/IncidentPublicNoteService.js +24 -0
- package/build/dist/Server/Services/IncidentPublicNoteService.js.map +1 -1
- package/build/dist/Server/Services/IncidentService.js +103 -36
- package/build/dist/Server/Services/IncidentService.js.map +1 -1
- package/build/dist/Server/Services/IncidentTemplateService.js +13 -31
- package/build/dist/Server/Services/IncidentTemplateService.js.map +1 -1
- package/build/dist/Server/Services/IncomingCallPolicyLabelRuleEngineService.js +113 -65
- package/build/dist/Server/Services/IncomingCallPolicyLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/IncomingCallPolicyOwnerRuleEngineService.js +173 -81
- package/build/dist/Server/Services/IncomingCallPolicyOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/Index.js +6 -4
- package/build/dist/Server/Services/Index.js.map +1 -1
- package/build/dist/Server/Services/IoTFleetLabelRuleEngineService.js +117 -69
- package/build/dist/Server/Services/IoTFleetLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/IoTFleetOwnerRuleEngineService.js +173 -81
- package/build/dist/Server/Services/IoTFleetOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/KubernetesClusterLabelRuleEngineService.js +145 -91
- package/build/dist/Server/Services/KubernetesClusterLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/KubernetesClusterOwnerRuleEngineService.js +193 -99
- package/build/dist/Server/Services/KubernetesClusterOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/LabelService.js +20 -25
- package/build/dist/Server/Services/LabelService.js.map +1 -1
- package/build/dist/Server/Services/MonitorLabelRuleEngineService.js +123 -77
- package/build/dist/Server/Services/MonitorLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/MonitorOwnerRuleEngineService.js +167 -82
- package/build/dist/Server/Services/MonitorOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/MonitorProbeService.js +18 -2
- package/build/dist/Server/Services/MonitorProbeService.js.map +1 -1
- package/build/dist/Server/Services/MonitorService.js +24 -40
- package/build/dist/Server/Services/MonitorService.js.map +1 -1
- package/build/dist/Server/Services/NetworkDeviceAutoImportRuleEngineService.js +287 -5
- package/build/dist/Server/Services/NetworkDeviceAutoImportRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/NetworkDeviceDiagnosticService.js +333 -0
- package/build/dist/Server/Services/NetworkDeviceDiagnosticService.js.map +1 -0
- package/build/dist/Server/Services/NetworkDeviceLabelRuleEngineService.js +117 -69
- package/build/dist/Server/Services/NetworkDeviceLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/NetworkDeviceOwnerRuleEngineService.js +173 -81
- package/build/dist/Server/Services/NetworkDeviceOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/NetworkDeviceService.js +36 -2
- package/build/dist/Server/Services/NetworkDeviceService.js.map +1 -1
- package/build/dist/Server/Services/OnCallDutyPolicyLabelRuleEngineService.js +117 -64
- package/build/dist/Server/Services/OnCallDutyPolicyLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/OnCallDutyPolicyOwnerRuleEngineService.js +175 -81
- package/build/dist/Server/Services/OnCallDutyPolicyOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/OnCallDutyPolicyScheduleLabelRuleEngineService.js +116 -65
- package/build/dist/Server/Services/OnCallDutyPolicyScheduleLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/OnCallDutyPolicyScheduleOwnerRuleEngineService.js +173 -81
- package/build/dist/Server/Services/OnCallDutyPolicyScheduleOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/PodmanHostLabelRuleEngineService.js +141 -92
- package/build/dist/Server/Services/PodmanHostLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/PodmanHostOwnerRuleEngineService.js +191 -99
- package/build/dist/Server/Services/PodmanHostOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/ProjectService.js +82 -10
- package/build/dist/Server/Services/ProjectService.js.map +1 -1
- package/build/dist/Server/Services/ProxmoxClusterLabelRuleEngineService.js +141 -92
- package/build/dist/Server/Services/ProxmoxClusterLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/ProxmoxClusterOwnerRuleEngineService.js +191 -99
- package/build/dist/Server/Services/ProxmoxClusterOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/RumApplicationLabelRuleEngineService.js +111 -63
- package/build/dist/Server/Services/RumApplicationLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/RumApplicationOwnerRuleEngineService.js +164 -76
- package/build/dist/Server/Services/RumApplicationOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/RunbookLabelRuleEngineService.js +117 -69
- package/build/dist/Server/Services/RunbookLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/RunbookOwnerRuleEngineService.js +173 -81
- package/build/dist/Server/Services/RunbookOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/ScheduledMaintenanceLabelRuleEngineService.js +280 -209
- package/build/dist/Server/Services/ScheduledMaintenanceLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/ScheduledMaintenanceOwnerRuleEngineService.js +521 -376
- package/build/dist/Server/Services/ScheduledMaintenanceOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/ScheduledMaintenancePublicNoteService.js +24 -0
- package/build/dist/Server/Services/ScheduledMaintenancePublicNoteService.js.map +1 -1
- package/build/dist/Server/Services/ScheduledMaintenanceService.js +37 -39
- package/build/dist/Server/Services/ScheduledMaintenanceService.js.map +1 -1
- package/build/dist/Server/Services/ScheduledMaintenanceTemplateService.js +12 -29
- package/build/dist/Server/Services/ScheduledMaintenanceTemplateService.js.map +1 -1
- package/build/dist/Server/Services/SecurityEventConnectionService.js +43 -3
- package/build/dist/Server/Services/SecurityEventConnectionService.js.map +1 -1
- package/build/dist/Server/Services/ServerlessFunctionLabelRuleEngineService.js +115 -62
- package/build/dist/Server/Services/ServerlessFunctionLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/ServerlessFunctionOwnerRuleEngineService.js +166 -76
- package/build/dist/Server/Services/ServerlessFunctionOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/ServiceLabelRuleEngineService.js +141 -92
- package/build/dist/Server/Services/ServiceLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/ServiceLevelObjectiveBurnRateRuleService.js +769 -18
- package/build/dist/Server/Services/ServiceLevelObjectiveBurnRateRuleService.js.map +1 -1
- package/build/dist/Server/Services/ServiceLevelObjectiveFeedService.js +96 -0
- package/build/dist/Server/Services/ServiceLevelObjectiveFeedService.js.map +1 -0
- package/build/dist/Server/Services/ServiceLevelObjectiveMonitorRuleEngineService.js +614 -87
- package/build/dist/Server/Services/ServiceLevelObjectiveMonitorRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/ServiceLevelObjectiveMonitorRuleService.js +844 -0
- package/build/dist/Server/Services/ServiceLevelObjectiveMonitorRuleService.js.map +1 -0
- package/build/dist/Server/Services/ServiceLevelObjectiveOwnerTeamService.js +207 -1
- package/build/dist/Server/Services/ServiceLevelObjectiveOwnerTeamService.js.map +1 -1
- package/build/dist/Server/Services/ServiceLevelObjectiveOwnerUserService.js +221 -1
- package/build/dist/Server/Services/ServiceLevelObjectiveOwnerUserService.js.map +1 -1
- package/build/dist/Server/Services/ServiceLevelObjectiveService.js +997 -50
- package/build/dist/Server/Services/ServiceLevelObjectiveService.js.map +1 -1
- package/build/dist/Server/Services/ServiceOwnerRuleEngineService.js +193 -100
- package/build/dist/Server/Services/ServiceOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/StatusPageAnnouncementService.js +12 -0
- package/build/dist/Server/Services/StatusPageAnnouncementService.js.map +1 -1
- package/build/dist/Server/Services/StatusPageLabelRuleEngineService.js +118 -70
- package/build/dist/Server/Services/StatusPageLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/StatusPageOwnerRuleEngineService.js +158 -76
- package/build/dist/Server/Services/StatusPageOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/StatusPagePrivateUserService.js +33 -25
- package/build/dist/Server/Services/StatusPagePrivateUserService.js.map +1 -1
- package/build/dist/Server/Services/StatusPagePrivateUserSessionService.js +36 -1
- package/build/dist/Server/Services/StatusPagePrivateUserSessionService.js.map +1 -1
- package/build/dist/Server/Services/StatusPageService.js +50 -35
- package/build/dist/Server/Services/StatusPageService.js.map +1 -1
- package/build/dist/Server/Services/StatusPageSubscriberNotificationTemplateService.js +19 -215
- package/build/dist/Server/Services/StatusPageSubscriberNotificationTemplateService.js.map +1 -1
- package/build/dist/Server/Services/StatusPageSubscriberService.js +6 -0
- package/build/dist/Server/Services/StatusPageSubscriberService.js.map +1 -1
- package/build/dist/Server/Services/TelemetryUsageBillingService.js +27 -5
- package/build/dist/Server/Services/TelemetryUsageBillingService.js.map +1 -1
- package/build/dist/Server/Services/ThreatIntelFeedService.js +1 -1
- package/build/dist/Server/Services/UserSessionService.js +5 -0
- package/build/dist/Server/Services/UserSessionService.js.map +1 -1
- package/build/dist/Server/Services/VMwareVCenterLabelRuleEngineService.js +141 -92
- package/build/dist/Server/Services/VMwareVCenterLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/VMwareVCenterOwnerRuleEngineService.js +191 -99
- package/build/dist/Server/Services/VMwareVCenterOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/WorkflowLabelRuleEngineService.js +117 -69
- package/build/dist/Server/Services/WorkflowLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/WorkflowOwnerRuleEngineService.js +173 -81
- package/build/dist/Server/Services/WorkflowOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Types/Database/Permissions/OwnedScopePermission.js +15 -10
- package/build/dist/Server/Types/Database/Permissions/OwnedScopePermission.js.map +1 -1
- package/build/dist/Server/Types/Database/Permissions/OwnerTableRegistry.js +82 -0
- package/build/dist/Server/Types/Database/Permissions/OwnerTableRegistry.js.map +1 -1
- package/build/dist/Server/Utils/AI/AlertAIContextBuilder.js +17 -0
- package/build/dist/Server/Utils/AI/AlertAIContextBuilder.js.map +1 -1
- package/build/dist/Server/Utils/AI/Chat/ChatAgentRunner.js +12 -3
- package/build/dist/Server/Utils/AI/Chat/ChatAgentRunner.js.map +1 -1
- package/build/dist/Server/Utils/AI/Chat/ObservabilityChatPrompt.js +32 -4
- package/build/dist/Server/Utils/AI/Chat/ObservabilityChatPrompt.js.map +1 -1
- package/build/dist/Server/Utils/AI/CodeFix/CodeAgentWorkspaceGuard.js +1 -1
- package/build/dist/Server/Utils/AI/CodeFix/CodeFixAgentCompletion.js +1 -1
- package/build/dist/Server/Utils/AI/IncidentAIContextBuilder.js +31 -0
- package/build/dist/Server/Utils/AI/IncidentAIContextBuilder.js.map +1 -1
- package/build/dist/Server/Utils/AI/SRE/AIInvestigationEngine.js +8 -5
- package/build/dist/Server/Utils/AI/SRE/AIInvestigationEngine.js.map +1 -1
- package/build/dist/Server/Utils/AI/SRE/AlertInvestigationRunner.js +33 -13
- package/build/dist/Server/Utils/AI/SRE/AlertInvestigationRunner.js.map +1 -1
- package/build/dist/Server/Utils/AI/SRE/IncidentInvestigationRunner.js +31 -10
- package/build/dist/Server/Utils/AI/SRE/IncidentInvestigationRunner.js.map +1 -1
- package/build/dist/Server/Utils/AI/SRE/InvestigationEligibility.js +205 -0
- package/build/dist/Server/Utils/AI/SRE/InvestigationEligibility.js.map +1 -0
- package/build/dist/Server/Utils/AI/SRE/InvestigationQueue.js +13 -0
- package/build/dist/Server/Utils/AI/SRE/InvestigationQueue.js.map +1 -1
- package/build/dist/Server/Utils/AI/Toolbox/AlertTools.js +24 -1
- package/build/dist/Server/Utils/AI/Toolbox/AlertTools.js.map +1 -1
- package/build/dist/Server/Utils/AI/Toolbox/IncidentTools.js +21 -1
- package/build/dist/Server/Utils/AI/Toolbox/IncidentTools.js.map +1 -1
- package/build/dist/Server/Utils/AI/Toolbox/Index.js +30 -6
- package/build/dist/Server/Utils/AI/Toolbox/Index.js.map +1 -1
- package/build/dist/Server/Utils/AI/Toolbox/ResourceTools.js +721 -0
- package/build/dist/Server/Utils/AI/Toolbox/ResourceTools.js.map +1 -0
- package/build/dist/Server/Utils/AI/Toolbox/RumTools.js +330 -0
- package/build/dist/Server/Utils/AI/Toolbox/RumTools.js.map +1 -0
- package/build/dist/Server/Utils/AI/Toolbox/SloTools.js +337 -53
- package/build/dist/Server/Utils/AI/Toolbox/SloTools.js.map +1 -1
- package/build/dist/Server/Utils/AI/Toolbox/ToolTypes.js.map +1 -1
- package/build/dist/Server/Utils/AI/Toolbox/TraceTools.js +1 -1
- package/build/dist/Server/Utils/AI/Toolbox/TraceTools.js.map +1 -1
- package/build/dist/Server/Utils/Dashboard/PublicDashboardResourceListPolicy.js +108 -15
- package/build/dist/Server/Utils/Dashboard/PublicDashboardResourceListPolicy.js.map +1 -1
- package/build/dist/Server/Utils/Dashboard/PublicDashboardSloHistoryPolicy.js +2 -2
- package/build/dist/Server/Utils/Dashboard/PublicDashboardSloHistoryPolicy.js.map +1 -1
- package/build/dist/Server/Utils/Dashboard/PublicDashboardSloWidget.js +115 -6
- package/build/dist/Server/Utils/Dashboard/PublicDashboardSloWidget.js.map +1 -1
- package/build/dist/Server/Utils/Database/PostgresErrorTranslator.js +11 -0
- package/build/dist/Server/Utils/Database/PostgresErrorTranslator.js.map +1 -1
- package/build/dist/Server/Utils/Database/ProjectScopedReferenceValidator.js +13 -0
- package/build/dist/Server/Utils/Database/ProjectScopedReferenceValidator.js.map +1 -1
- package/build/dist/Server/Utils/Database/RelationValueUtil.js +82 -0
- package/build/dist/Server/Utils/Database/RelationValueUtil.js.map +1 -0
- package/build/dist/Server/Utils/Monitor/Criteria/CompareCriteria.js +115 -106
- package/build/dist/Server/Utils/Monitor/Criteria/CompareCriteria.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/Criteria/EvaluateOverTime.js +17 -21
- package/build/dist/Server/Utils/Monitor/Criteria/EvaluateOverTime.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/Criteria/MetricMonitorCriteria.js +4 -2
- package/build/dist/Server/Utils/Monitor/Criteria/MetricMonitorCriteria.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaExpectationBuilder.js +5 -4
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaExpectationBuilder.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorStepsProjectValidator.js +50 -10
- package/build/dist/Server/Utils/Monitor/MonitorStepsProjectValidator.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/NetworkDeviceHydrationUtil.js +13 -1
- package/build/dist/Server/Utils/Monitor/NetworkDeviceHydrationUtil.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/NetworkDeviceMetricUtil.js +6 -10
- package/build/dist/Server/Utils/Monitor/NetworkDeviceMetricUtil.js.map +1 -1
- package/build/dist/Server/Utils/Rules/MonitorRulePatternValidator.js +34 -0
- package/build/dist/Server/Utils/Rules/MonitorRulePatternValidator.js.map +1 -0
- package/build/dist/Server/Utils/Rules/OwnerRuleAssignment.js +163 -0
- package/build/dist/Server/Utils/Rules/OwnerRuleAssignment.js.map +1 -0
- package/build/dist/Server/Utils/Rules/RuleRun/RuleApplication.js +25 -0
- package/build/dist/Server/Utils/Rules/RuleRun/RuleApplication.js.map +1 -0
- package/build/dist/Server/Utils/Rules/RuleRun/RuleRunPermission.js +128 -0
- package/build/dist/Server/Utils/Rules/RuleRun/RuleRunPermission.js.map +1 -0
- package/build/dist/Server/Utils/Rules/RuleRun/RuleRunRegistry.js +746 -0
- package/build/dist/Server/Utils/Rules/RuleRun/RuleRunRegistry.js.map +1 -0
- package/build/dist/Server/Utils/Rules/RuleRun/RuleRunner.js +221 -0
- package/build/dist/Server/Utils/Rules/RuleRun/RuleRunner.js.map +1 -0
- package/build/dist/Server/Utils/SecurityEvent/ConnectorErrorMessage.js +3 -2
- package/build/dist/Server/Utils/SecurityEvent/ConnectorErrorMessage.js.map +1 -1
- package/build/dist/Server/Utils/SecurityEvent/Connectors/ConnectorPlatformHealth.js +6 -4
- package/build/dist/Server/Utils/SecurityEvent/Connectors/ConnectorPlatformHealth.js.map +1 -1
- package/build/dist/Server/Utils/SecurityEvent/{GoogleSecOps → Connectors/GoogleSecOps}/GoogleSecOpsClient.js +174 -14
- package/build/dist/Server/Utils/SecurityEvent/Connectors/GoogleSecOps/GoogleSecOpsClient.js.map +1 -0
- package/build/dist/Server/Utils/SecurityEvent/Connectors/GoogleSecOps/GoogleSecOpsConnector.js +1417 -0
- package/build/dist/Server/Utils/SecurityEvent/Connectors/GoogleSecOps/GoogleSecOpsConnector.js.map +1 -0
- package/build/dist/Server/Utils/SecurityEvent/Connectors/SecurityEventConnectionPoller.js +138 -18
- package/build/dist/Server/Utils/SecurityEvent/Connectors/SecurityEventConnectionPoller.js.map +1 -1
- package/build/dist/Server/Utils/SecurityEvent/Connectors/SecurityEventConnectionRunExecutor.js +1 -2
- package/build/dist/Server/Utils/SecurityEvent/Connectors/SecurityEventConnectionRunExecutor.js.map +1 -1
- package/build/dist/Server/Utils/SecurityEvent/Connectors/SecurityEventConnectionTester.js +23 -18
- package/build/dist/Server/Utils/SecurityEvent/Connectors/SecurityEventConnectionTester.js.map +1 -1
- package/build/dist/Server/Utils/SecurityEvent/Connectors/SecurityEventConnectorRegistry.js +2 -0
- package/build/dist/Server/Utils/SecurityEvent/Connectors/SecurityEventConnectorRegistry.js.map +1 -1
- package/build/dist/Server/Utils/SecurityEvent/Connectors/Types.js +95 -0
- package/build/dist/Server/Utils/SecurityEvent/Connectors/Types.js.map +1 -1
- package/build/dist/Server/Utils/SecurityEvent/DetectionRuleEvaluator.js +1 -1
- package/build/dist/Server/Utils/SecurityEvent/SecurityEventDedupe.js +3 -3
- package/build/dist/Server/Utils/SecurityEvent/ThreatIntel/ThreatIntelFeedPoller.js +2 -2
- package/build/dist/Server/Utils/SessionReplay/SessionReplayReadService.js +118 -40
- package/build/dist/Server/Utils/SessionReplay/SessionReplayReadService.js.map +1 -1
- package/build/dist/Server/Utils/Slo/SloFeedUtil.js +150 -0
- package/build/dist/Server/Utils/Slo/SloFeedUtil.js.map +1 -0
- package/build/dist/Server/Utils/Slo/SloLegacyMonitorLabelAdoption.js +136 -0
- package/build/dist/Server/Utils/Slo/SloLegacyMonitorLabelAdoption.js.map +1 -0
- package/build/dist/Server/Utils/Slo/SloMetricUtil.js +269 -0
- package/build/dist/Server/Utils/Slo/SloMetricUtil.js.map +1 -0
- package/build/dist/Server/Utils/Slo/SloOwnerReferenceValidator.js +134 -0
- package/build/dist/Server/Utils/Slo/SloOwnerReferenceValidator.js.map +1 -0
- package/build/dist/Server/Utils/Slo/SloRecordReferenceValidator.js +137 -0
- package/build/dist/Server/Utils/Slo/SloRecordReferenceValidator.js.map +1 -0
- package/build/dist/Server/Utils/StatusPage/MonitorRulePatternValidator.js +6 -26
- package/build/dist/Server/Utils/StatusPage/MonitorRulePatternValidator.js.map +1 -1
- package/build/dist/Server/Utils/StatusPageResource.js +31 -5
- package/build/dist/Server/Utils/StatusPageResource.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/TelemetryEntity.js +171 -6
- package/build/dist/Server/Utils/Telemetry/TelemetryEntity.js.map +1 -1
- package/build/dist/Types/AI/AIChatPageContext.js +68 -2
- package/build/dist/Types/AI/AIChatPageContext.js.map +1 -1
- package/build/dist/Types/AI/AIChatTypes.js +4 -0
- package/build/dist/Types/AI/AIChatTypes.js.map +1 -1
- package/build/dist/Types/AI/AIResourceContext.js +162 -0
- package/build/dist/Types/AI/AIResourceContext.js.map +1 -0
- package/build/dist/Types/AI/InvestigationNotStartedReason.js +2 -0
- package/build/dist/Types/AI/InvestigationNotStartedReason.js.map +1 -0
- package/build/dist/Types/Billing/SubscriptionStatus.js +37 -3
- package/build/dist/Types/Billing/SubscriptionStatus.js.map +1 -1
- package/build/dist/Types/Dashboard/DashboardComponentType.js +1 -0
- package/build/dist/Types/Dashboard/DashboardComponentType.js.map +1 -1
- package/build/dist/Types/Dashboard/DashboardComponents/ComponentArgument.js +5 -0
- package/build/dist/Types/Dashboard/DashboardComponents/ComponentArgument.js.map +1 -1
- package/build/dist/Types/Dashboard/DashboardComponents/DashboardSloListComponent.js +2 -0
- package/build/dist/Types/Dashboard/DashboardComponents/DashboardSloListComponent.js.map +1 -0
- package/build/dist/Types/Dashboard/DashboardTemplates.js +275 -286
- package/build/dist/Types/Dashboard/DashboardTemplates.js.map +1 -1
- package/build/dist/Types/Database/EnableAuditLog.js +19 -1
- package/build/dist/Types/Database/EnableAuditLog.js.map +1 -1
- package/build/dist/Types/Database/UniqueColumnsTogether.js +19 -0
- package/build/dist/Types/Database/UniqueColumnsTogether.js.map +1 -0
- package/build/dist/Types/Email/EmailTemplateType.js +4 -0
- package/build/dist/Types/Email/EmailTemplateType.js.map +1 -1
- package/build/dist/Types/Metrics/MetricQueryConfigData.js.map +1 -1
- package/build/dist/Types/Monitor/CriteriaFilter.js +45 -6
- package/build/dist/Types/Monitor/CriteriaFilter.js.map +1 -1
- package/build/dist/Types/Monitor/MonitorStep.js +2 -0
- package/build/dist/Types/Monitor/MonitorStep.js.map +1 -1
- package/build/dist/Types/Monitor/MonitorStepDnsMonitor.js +3 -1
- package/build/dist/Types/Monitor/MonitorStepDnsMonitor.js.map +1 -1
- package/build/dist/Types/Monitor/MonitorStepDnssecMonitor.js +3 -1
- package/build/dist/Types/Monitor/MonitorStepDnssecMonitor.js.map +1 -1
- package/build/dist/Types/Monitor/MonitorStepDomainMonitor.js +3 -1
- package/build/dist/Types/Monitor/MonitorStepDomainMonitor.js.map +1 -1
- package/build/dist/Types/Monitor/MonitorStepExternalStatusPageMonitor.js +3 -1
- package/build/dist/Types/Monitor/MonitorStepExternalStatusPageMonitor.js.map +1 -1
- package/build/dist/Types/Monitor/MonitorStepRetries.js +47 -0
- package/build/dist/Types/Monitor/MonitorStepRetries.js.map +1 -0
- package/build/dist/Types/Monitor/MonitorStepSnmpMonitor.js +3 -1
- package/build/dist/Types/Monitor/MonitorStepSnmpMonitor.js.map +1 -1
- package/build/dist/Types/NetworkDevice/NetworkDeviceDiagnosticResult.js +29 -0
- package/build/dist/Types/NetworkDevice/NetworkDeviceDiagnosticResult.js.map +1 -0
- package/build/dist/Types/NetworkDevice/NetworkDeviceDiagnosticStatus.js +37 -0
- package/build/dist/Types/NetworkDevice/NetworkDeviceDiagnosticStatus.js.map +1 -0
- package/build/dist/Types/NetworkDevice/NetworkDeviceDiagnosticType.js +42 -0
- package/build/dist/Types/NetworkDevice/NetworkDeviceDiagnosticType.js.map +1 -0
- package/build/dist/Types/NetworkDevice/NetworkDevicePingMetricNames.js +20 -0
- package/build/dist/Types/NetworkDevice/NetworkDevicePingMetricNames.js.map +1 -0
- package/build/dist/Types/Permission.js +114 -0
- package/build/dist/Types/Permission.js.map +1 -1
- package/build/dist/Types/Rules/RuleCriteriaFieldRegistry.js +5 -0
- package/build/dist/Types/Rules/RuleCriteriaFieldRegistry.js.map +1 -1
- package/build/dist/Types/Rules/RuleRun.js +267 -0
- package/build/dist/Types/Rules/RuleRun.js.map +1 -0
- package/build/dist/Types/Rum/SessionReplayApi.js.map +1 -1
- package/build/dist/Types/Rum/WebVitals.js +64 -0
- package/build/dist/Types/Rum/WebVitals.js.map +1 -0
- package/build/dist/Types/SecurityEvent/Connectors/ConnectorDiagnostics.js.map +1 -1
- package/build/dist/Types/SecurityEvent/Connectors/SecurityEventConnectionDiagnostics.js +16 -1
- package/build/dist/Types/SecurityEvent/Connectors/SecurityEventConnectionDiagnostics.js.map +1 -1
- package/build/dist/Types/SecurityEvent/Connectors/SecurityEventConnectorCatalog.js +65 -0
- package/build/dist/Types/SecurityEvent/Connectors/SecurityEventConnectorCatalog.js.map +1 -1
- package/build/dist/Types/SecurityEvent/Connectors/SecurityEventConnectorProvider.js +6 -2
- package/build/dist/Types/SecurityEvent/Connectors/SecurityEventConnectorProvider.js.map +1 -1
- package/build/dist/Types/ServiceLevelObjective/SloHistoryMetricName.js +26 -0
- package/build/dist/Types/ServiceLevelObjective/SloHistoryMetricName.js.map +1 -0
- package/build/dist/Types/ServiceLevelObjective/SloMetricType.js +45 -0
- package/build/dist/Types/ServiceLevelObjective/SloMetricType.js.map +1 -0
- package/build/dist/Types/StatusPage/StatusPageSubscriberNotificationEventType.js +4 -0
- package/build/dist/Types/StatusPage/StatusPageSubscriberNotificationEventType.js.map +1 -1
- package/build/dist/Types/StatusPage/SubscriberNotificationTemplateVariables.js +295 -0
- package/build/dist/Types/StatusPage/SubscriberNotificationTemplateVariables.js.map +1 -0
- package/build/dist/Types/StatusPage/SubscriberNotificationTrigger.js +13 -0
- package/build/dist/Types/StatusPage/SubscriberNotificationTrigger.js.map +1 -0
- package/build/dist/Types/StatusPage/SubscriberUpdateNotification.js +67 -0
- package/build/dist/Types/StatusPage/SubscriberUpdateNotification.js.map +1 -0
- package/build/dist/Types/Telemetry/LockedFilterDetail.js +7 -7
- package/build/dist/Types/Telemetry/ServiceType.js +7 -0
- package/build/dist/Types/Telemetry/ServiceType.js.map +1 -1
- package/build/dist/Types/WebsiteRequest.js +2 -0
- package/build/dist/Types/WebsiteRequest.js.map +1 -1
- package/build/dist/UI/Components/AlertBanner/AlertBanner.js +48 -19
- package/build/dist/UI/Components/AlertBanner/AlertBanner.js.map +1 -1
- package/build/dist/UI/Components/BulkUpdate/BulkArchiveActions.js +10 -2
- package/build/dist/UI/Components/BulkUpdate/BulkArchiveActions.js.map +1 -1
- package/build/dist/UI/Components/Detail/Detail.js +12 -3
- package/build/dist/UI/Components/Detail/Detail.js.map +1 -1
- package/build/dist/UI/Components/Dropdown/Dropdown.js +33 -5
- package/build/dist/UI/Components/Dropdown/Dropdown.js.map +1 -1
- package/build/dist/UI/Components/EditionLabel/EditionLabel.js +7 -5
- package/build/dist/UI/Components/EditionLabel/EditionLabel.js.map +1 -1
- package/build/dist/UI/Components/EmptyState/EmptyState.js +3 -3
- package/build/dist/UI/Components/EmptyState/EmptyState.js.map +1 -1
- package/build/dist/UI/Components/EmptyState/EmptyStateGuideLinks.js +47 -0
- package/build/dist/UI/Components/EmptyState/EmptyStateGuideLinks.js.map +1 -0
- package/build/dist/UI/Components/Forms/ModelForm.js +6 -5
- package/build/dist/UI/Components/Forms/ModelForm.js.map +1 -1
- package/build/dist/UI/Components/LabelRule/LabelRuleTable.js +6 -2
- package/build/dist/UI/Components/LabelRule/LabelRuleTable.js.map +1 -1
- package/build/dist/UI/Components/LogsViewer/LogsViewer.js +1 -1
- package/build/dist/UI/Components/LogsViewer/LogsViewer.js.map +1 -1
- package/build/dist/UI/Components/LogsViewer/components/ActiveFilterChips.js +0 -2
- package/build/dist/UI/Components/LogsViewer/components/ActiveFilterChips.js.map +1 -1
- package/build/dist/UI/Components/ModelTable/BaseModelTable.js +7 -0
- package/build/dist/UI/Components/ModelTable/BaseModelTable.js.map +1 -1
- package/build/dist/UI/Components/MoreMenu/MoreMenu.js +3 -1
- package/build/dist/UI/Components/MoreMenu/MoreMenu.js.map +1 -1
- package/build/dist/UI/Components/Navbar/NavBar.js.map +1 -1
- package/build/dist/UI/Components/Navbar/NavBarMenuModal.js +4 -2
- package/build/dist/UI/Components/Navbar/NavBarMenuModal.js.map +1 -1
- package/build/dist/UI/Components/RuleRun/RuleDetailFields.js +226 -0
- package/build/dist/UI/Components/RuleRun/RuleDetailFields.js.map +1 -0
- package/build/dist/UI/Components/RuleRun/RuleTable.js +97 -0
- package/build/dist/UI/Components/RuleRun/RuleTable.js.map +1 -0
- package/build/dist/UI/Components/RuleRun/RuleView.js +83 -0
- package/build/dist/UI/Components/RuleRun/RuleView.js.map +1 -0
- package/build/dist/UI/Components/RuleRun/RunRuleNowModal.js +74 -0
- package/build/dist/UI/Components/RuleRun/RunRuleNowModal.js.map +1 -0
- package/build/dist/UI/Components/RuleRun/RunRulesBulkAction.js +78 -0
- package/build/dist/UI/Components/RuleRun/RunRulesBulkAction.js.map +1 -0
- package/build/dist/UI/Components/TelemetryViewer/TelemetryViewer.js +1 -1
- package/build/dist/UI/Components/TelemetryViewer/TelemetryViewer.js.map +1 -1
- package/build/dist/UI/Components/TelemetryViewer/components/LockedFilterChip.js +24 -50
- package/build/dist/UI/Components/TelemetryViewer/components/LockedFilterChip.js.map +1 -1
- package/build/dist/UI/Components/TelemetryViewer/components/TelemetryActiveFilterChips.js +0 -4
- package/build/dist/UI/Components/TelemetryViewer/components/TelemetryActiveFilterChips.js.map +1 -1
- package/build/dist/UI/Utils/Rules/RuleRunClient.js +98 -0
- package/build/dist/UI/Utils/Rules/RuleRunClient.js.map +1 -0
- package/build/dist/UI/Utils/Telemetry/TelemetryEntityNames.js +8 -0
- package/build/dist/UI/Utils/Telemetry/TelemetryEntityNames.js.map +1 -1
- package/build/dist/Utils/API.js +8 -4
- package/build/dist/Utils/API.js.map +1 -1
- package/build/dist/Utils/Dashboard/Components/DashboardSloComponent.js +16 -2
- package/build/dist/Utils/Dashboard/Components/DashboardSloComponent.js.map +1 -1
- package/build/dist/Utils/Dashboard/Components/DashboardSloListComponent.js +94 -0
- package/build/dist/Utils/Dashboard/Components/DashboardSloListComponent.js.map +1 -0
- package/build/dist/Utils/Dashboard/Components/Index.js +4 -0
- package/build/dist/Utils/Dashboard/Components/Index.js.map +1 -1
- package/build/dist/Utils/Dashboard/SloWidgetSource.js +125 -0
- package/build/dist/Utils/Dashboard/SloWidgetSource.js.map +1 -0
- package/build/dist/Utils/HTTPResponseBodyReader.js +50 -6
- package/build/dist/Utils/HTTPResponseBodyReader.js.map +1 -1
- package/build/dist/Utils/Markdown/MarkdownEscape.js +49 -0
- package/build/dist/Utils/Markdown/MarkdownEscape.js.map +1 -0
- package/build/dist/Utils/Metrics/MetricExplorerUrl.js +14 -3
- package/build/dist/Utils/Metrics/MetricExplorerUrl.js.map +1 -1
- package/build/dist/Utils/Monitor/MonitorTestAvailabilityUtil.js +68 -0
- package/build/dist/Utils/Monitor/MonitorTestAvailabilityUtil.js.map +1 -0
- package/build/dist/Utils/NetworkDiscovery/DiscoveredDeviceBuilder.js +112 -34
- package/build/dist/Utils/NetworkDiscovery/DiscoveredDeviceBuilder.js.map +1 -1
- package/build/dist/Utils/NetworkDiscovery/DiscoveredHostUtil.js +22 -0
- package/build/dist/Utils/NetworkDiscovery/DiscoveredHostUtil.js.map +1 -1
- package/build/dist/Utils/NetworkDiscovery/NetbiosNameUtil.js +129 -0
- package/build/dist/Utils/NetworkDiscovery/NetbiosNameUtil.js.map +1 -0
- package/build/dist/Utils/NetworkDiscovery/RunImportedDeviceNaming.js +255 -0
- package/build/dist/Utils/NetworkDiscovery/RunImportedDeviceNaming.js.map +1 -0
- package/build/dist/Utils/NetworkDiscovery/ShortDeviceNamePlanner.js +184 -0
- package/build/dist/Utils/NetworkDiscovery/ShortDeviceNamePlanner.js.map +1 -0
- package/build/dist/Utils/NetworkDiscovery/ShortHostnameUtil.js +79 -0
- package/build/dist/Utils/NetworkDiscovery/ShortHostnameUtil.js.map +1 -0
- package/build/dist/Utils/NetworkSite/CidrMatchUtil.js +21 -12
- package/build/dist/Utils/NetworkSite/CidrMatchUtil.js.map +1 -1
- package/build/dist/Utils/Project/DataResidency.js +51 -0
- package/build/dist/Utils/Project/DataResidency.js.map +1 -0
- package/build/dist/Utils/Rules/RuleRunSummary.js +197 -0
- package/build/dist/Utils/Rules/RuleRunSummary.js.map +1 -0
- package/build/dist/Utils/Slo/SloAffectedResourceMarkdown.js +51 -0
- package/build/dist/Utils/Slo/SloAffectedResourceMarkdown.js.map +1 -0
- package/build/dist/Utils/Slo/SloBurnRateTemplate.js +228 -0
- package/build/dist/Utils/Slo/SloBurnRateTemplate.js.map +1 -0
- package/build/dist/Utils/Slo/SloFeedMarkdown.js +934 -0
- package/build/dist/Utils/Slo/SloFeedMarkdown.js.map +1 -0
- package/build/dist/Utils/Slo/SloHealth.js +75 -9
- package/build/dist/Utils/Slo/SloHealth.js.map +1 -1
- package/build/dist/Utils/Slo/SloListWidgetFormat.js +217 -0
- package/build/dist/Utils/Slo/SloListWidgetFormat.js.map +1 -0
- package/build/dist/Utils/Slo/SloMetricType.js +212 -0
- package/build/dist/Utils/Slo/SloMetricType.js.map +1 -0
- package/build/dist/Utils/Slo/SloMonitorRuleCriteria.js +216 -0
- package/build/dist/Utils/Slo/SloMonitorRuleCriteria.js.map +1 -0
- package/build/dist/Utils/Slo/SloMonitorStatusSummary.js +129 -0
- package/build/dist/Utils/Slo/SloMonitorStatusSummary.js.map +1 -0
- package/build/dist/Utils/Slo/SloOverviewText.js +110 -0
- package/build/dist/Utils/Slo/SloOverviewText.js.map +1 -0
- package/build/dist/Utils/Slo/SloProjection.js +448 -0
- package/build/dist/Utils/Slo/SloProjection.js.map +1 -0
- package/build/dist/Utils/Slo/SloWidgetFormat.js +4 -2
- package/build/dist/Utils/Slo/SloWidgetFormat.js.map +1 -1
- package/build/dist/Utils/Telemetry/HostIpAddresses.js +42 -3
- package/build/dist/Utils/Telemetry/HostIpAddresses.js.map +1 -1
- package/build/dist/Utils/Telemetry/LockedFilterSearch.js +1 -26
- package/build/dist/Utils/Telemetry/LockedFilterSearch.js.map +1 -1
- package/package.json +5 -5
- package/test-setup.sh +2 -2
- package/Models/DatabaseModels/GoogleSecOpsConnection.ts +0 -447
- package/Models/DatabaseModels/GoogleSecOpsConnectionRun.ts +0 -263
- package/Server/API/GoogleSecOpsConnectionAPI.ts +0 -320
- package/Server/Services/GoogleSecOpsConnectionRunService.ts +0 -10
- package/Server/Services/GoogleSecOpsConnectionService.ts +0 -116
- package/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsConnectionTester.ts +0 -777
- package/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsPoller.ts +0 -1373
- package/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsRunExecutor.ts +0 -512
- package/Tests/App/Dashboard/GoogleSecOpsConnectionForm.test.tsx +0 -838
- package/Tests/App/Dashboard/GoogleSecOpsConnectionsErrors.test.tsx +0 -441
- package/Tests/App/Dashboard/GoogleSecOpsDiagnostics.test.tsx +0 -1001
- package/Tests/Server/API/GoogleSecOpsConnectionAPI.test.ts +0 -657
- package/Tests/Server/Services/GoogleSecOpsDiagnosticsModel.test.ts +0 -153
- package/Tests/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsConnectionTester.test.ts +0 -784
- package/Tests/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsRunExecutor.test.ts +0 -823
- package/Tests/Server/Utils/SecurityEvent/GoogleSecOpsDiagnostics.test.ts +0 -918
- package/Tests/Server/Utils/SecurityEvent/GoogleSecOpsPoller.test.ts +0 -738
- package/Tests/Server/Utils/SecurityEvent/GoogleSecOpsPollerFailureTaxonomy.test.ts +0 -874
- package/Tests/Server/Utils/SecurityEvent/GoogleSecOpsPollerHardening.test.ts +0 -1297
- package/Tests/Server/Utils/SecurityEvent/GoogleSecOpsThreePassPoller.test.ts +0 -1577
- package/Tests/UI/Components/LockedFilterActions.test.tsx +0 -396
- package/Types/SecurityEvent/GoogleSecOpsDiagnostics.ts +0 -111
- package/UI/Components/TelemetryViewer/components/LockedFilterActions.tsx +0 -205
- package/build/dist/Models/DatabaseModels/GoogleSecOpsConnection.js +0 -478
- package/build/dist/Models/DatabaseModels/GoogleSecOpsConnection.js.map +0 -1
- package/build/dist/Models/DatabaseModels/GoogleSecOpsConnectionRun.js +0 -287
- package/build/dist/Models/DatabaseModels/GoogleSecOpsConnectionRun.js.map +0 -1
- package/build/dist/Server/API/GoogleSecOpsConnectionAPI.js +0 -231
- package/build/dist/Server/API/GoogleSecOpsConnectionAPI.js.map +0 -1
- package/build/dist/Server/Services/GoogleSecOpsConnectionRunService.js +0 -9
- package/build/dist/Server/Services/GoogleSecOpsConnectionRunService.js.map +0 -1
- package/build/dist/Server/Services/GoogleSecOpsConnectionService.js +0 -70
- package/build/dist/Server/Services/GoogleSecOpsConnectionService.js.map +0 -1
- package/build/dist/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsClient.js.map +0 -1
- package/build/dist/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsConnectionTester.js +0 -537
- package/build/dist/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsConnectionTester.js.map +0 -1
- package/build/dist/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsPoller.js +0 -1034
- package/build/dist/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsPoller.js.map +0 -1
- package/build/dist/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsRunExecutor.js +0 -410
- package/build/dist/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsRunExecutor.js.map +0 -1
- package/build/dist/Types/SecurityEvent/GoogleSecOpsDiagnostics.js +0 -2
- package/build/dist/Types/SecurityEvent/GoogleSecOpsDiagnostics.js.map +0 -1
- package/build/dist/UI/Components/TelemetryViewer/components/LockedFilterActions.js +0 -88
- package/build/dist/UI/Components/TelemetryViewer/components/LockedFilterActions.js.map +0 -1
|
@@ -0,0 +1,2101 @@
|
|
|
1
|
+
import OneUptimeDate from "../../../../../Types/Date";
|
|
2
|
+
import BadDataException from "../../../../../Types/Exception/BadDataException";
|
|
3
|
+
import { JSONObject, JSONValue } from "../../../../../Types/JSON";
|
|
4
|
+
import NormalizedSecurityEvent from "../../../../../Types/SecurityEvent/NormalizedSecurityEvent";
|
|
5
|
+
import {
|
|
6
|
+
SecurityConnectorCheck,
|
|
7
|
+
SecurityConnectorCheckStatus,
|
|
8
|
+
SecurityConnectorSample,
|
|
9
|
+
} from "../../../../../Types/SecurityEvent/Connectors/ConnectorDiagnostics";
|
|
10
|
+
import SecurityEventConnectorProvider from "../../../../../Types/SecurityEvent/Connectors/SecurityEventConnectorProvider";
|
|
11
|
+
import {
|
|
12
|
+
SecurityEventConnectorDefinition,
|
|
13
|
+
getSecurityEventConnectorDefinition,
|
|
14
|
+
} from "../../../../../Types/SecurityEvent/Connectors/SecurityEventConnectorCatalog";
|
|
15
|
+
import GoogleSecOpsAlertNormalizer from "../../../../../Utils/SecurityEvent/GoogleSecOpsAlertNormalizer";
|
|
16
|
+
import {
|
|
17
|
+
contentHashEventUid,
|
|
18
|
+
parseEventTime,
|
|
19
|
+
readString,
|
|
20
|
+
readValue,
|
|
21
|
+
} from "../../../../../Utils/SecurityEvent/NormalizerHelpers";
|
|
22
|
+
import { redactLogString } from "../../../LogRedaction";
|
|
23
|
+
import ConnectorErrorMessage from "../../ConnectorErrorMessage";
|
|
24
|
+
import {
|
|
25
|
+
ConnectorFetchBudget,
|
|
26
|
+
ConnectorFetchOptions,
|
|
27
|
+
ConnectorFetchResult,
|
|
28
|
+
ConnectorFetchWindow,
|
|
29
|
+
ConnectorTestOptions,
|
|
30
|
+
ConnectorTestResult,
|
|
31
|
+
SecurityConnectorSettings,
|
|
32
|
+
SecurityEventConnector,
|
|
33
|
+
attachConnectorChecks,
|
|
34
|
+
attachConnectorFetchSummary,
|
|
35
|
+
makeCheck,
|
|
36
|
+
readSettingString,
|
|
37
|
+
} from "../Types";
|
|
38
|
+
import GoogleSecOpsClient, {
|
|
39
|
+
CuratedRuleDetectionCount,
|
|
40
|
+
FetchAlertsResult,
|
|
41
|
+
FetchLike,
|
|
42
|
+
GoogleSecOpsListBasis,
|
|
43
|
+
SearchDetectionsResult,
|
|
44
|
+
} from "./GoogleSecOpsClient";
|
|
45
|
+
|
|
46
|
+
/*
|
|
47
|
+
* Google SecOps (Chronicle) connector: imports rule detections and alerts
|
|
48
|
+
* as OCSF Detection Findings.
|
|
49
|
+
*
|
|
50
|
+
* One window is read in three passes and unioned by Collection.id:
|
|
51
|
+
* 1. rule detections by CREATED time (legacySearchDetections),
|
|
52
|
+
* 2. curated rule detections by created time (legacySearchCuratedDetections),
|
|
53
|
+
* one search per curated rule that countAllCuratedRuleSetDetections
|
|
54
|
+
* reports detections for — the curated route has no wildcard,
|
|
55
|
+
* 3. the alerts view by DETECTION time (legacyFetchAlertsView).
|
|
56
|
+
* The alerts view alone filters on detection time, and a rule that runs
|
|
57
|
+
* hourly creates detections whose detection time is already behind a
|
|
58
|
+
* forward-only cursor, so it can never be the primary read (see
|
|
59
|
+
* Connectors/Types.ts for why creation time is the cursor basis). A
|
|
60
|
+
* scheduled poll therefore also sweeps the alerts view over the day before
|
|
61
|
+
* its window, alerts only, so an alert Google makes readable hours after
|
|
62
|
+
* its detection time is still imported; that sweep is best effort and never
|
|
63
|
+
* holds the cursor.
|
|
64
|
+
*
|
|
65
|
+
* Settings come from the catalog's keys: config.region,
|
|
66
|
+
* config.instanceResourceName and secrets.serviceAccountJson, the pasted
|
|
67
|
+
* service-account key as TEXT. The transport is GoogleSecOpsClient's own
|
|
68
|
+
* injectable FetchLike rather than DataSourceHttpFetch: that fetch throws
|
|
69
|
+
* on every status >= 300 (which breaks the client's 401 re-mint and cuts
|
|
70
|
+
* the google.rpc details its operator hints read) and caps responses at
|
|
71
|
+
* 20 MB, which a full page of detections can exceed, failing every poll
|
|
72
|
+
* of that window for good. The hosts are fixed googleapis.com names
|
|
73
|
+
* behind the region allowlist and the token_uri host rule.
|
|
74
|
+
*/
|
|
75
|
+
|
|
76
|
+
const PROVIDER_TITLE: string = "Google SecOps";
|
|
77
|
+
|
|
78
|
+
/*
|
|
79
|
+
* Separate request budgets per kind of read. The created-time search
|
|
80
|
+
* passes are the authoritative read of rule detections and share one page
|
|
81
|
+
* budget (both bases, on a preview or backfill); the alerts view splits
|
|
82
|
+
* truncated windows and gets its own, so a burst that the alerts view has
|
|
83
|
+
* to split can no longer starve the searches (or the other way round).
|
|
84
|
+
*/
|
|
85
|
+
export const GOOGLE_SECOPS_SEARCH_PAGE_BUDGET: number = 20;
|
|
86
|
+
/*
|
|
87
|
+
* The curated pass: one count request plus at least one search page per
|
|
88
|
+
* curated rule that produced detections that week, per basis. It has its own
|
|
89
|
+
* budget because its request count grows with the number of active curated
|
|
90
|
+
* rules, not with the volume in the window, so sharing the rule pass's pages
|
|
91
|
+
* would let a tenant with many curated rules starve its own rule detections.
|
|
92
|
+
* It is a ceiling sized for tenants with many curated rule sets enabled; a
|
|
93
|
+
* quiet tenant spends one request per active rule.
|
|
94
|
+
*/
|
|
95
|
+
export const GOOGLE_SECOPS_CURATED_REQUEST_BUDGET: number = 200;
|
|
96
|
+
/*
|
|
97
|
+
* The share of the fetch's wall clock after which the curated pass starts no
|
|
98
|
+
* further curated rule, so the alerts view still gets its turn when a tenant
|
|
99
|
+
* has more active curated rules than one poll can search.
|
|
100
|
+
*/
|
|
101
|
+
const CURATED_PASS_TIME_SHARE: number = 0.6;
|
|
102
|
+
export const GOOGLE_SECOPS_ALERTS_VIEW_REQUEST_BUDGET: number = 16;
|
|
103
|
+
// The worker job times out at ten minutes; importing follows the fetch.
|
|
104
|
+
export const GOOGLE_SECOPS_FETCH_DURATION_MS: number = 4 * 60 * 1000;
|
|
105
|
+
/*
|
|
106
|
+
* How far before a scheduled poll's window the alerts view is swept for
|
|
107
|
+
* alerts Google made readable after their detection time. A day covers
|
|
108
|
+
* Google's documented rule run frequencies (up to daily) and ingestion
|
|
109
|
+
* delay; the created-time passes, not this sweep, are the authoritative
|
|
110
|
+
* read of rule and curated detections.
|
|
111
|
+
* https://docs.cloud.google.com/chronicle/docs/detection/detection-delays
|
|
112
|
+
*/
|
|
113
|
+
export const GOOGLE_SECOPS_LATE_ALERTS_LOOKBACK_IN_MINUTES: number = 24 * 60;
|
|
114
|
+
/*
|
|
115
|
+
* How far before the window's start the curated rule counts reach. The
|
|
116
|
+
* counts are what names the rules to search, and a detection created in the
|
|
117
|
+
* window can carry a detection time days earlier; a week is also the longest
|
|
118
|
+
* range a preview or backfill reads.
|
|
119
|
+
*/
|
|
120
|
+
export const GOOGLE_SECOPS_CURATED_DISCOVERY_LOOKBACK_IN_MINUTES: number =
|
|
121
|
+
7 * 24 * 60;
|
|
122
|
+
const MAX_ALERTS_PER_REQUEST: number = 1000;
|
|
123
|
+
const MAX_SEARCH_PAGE_SIZE: number = 1000;
|
|
124
|
+
const DEFAULT_POLL_INTERVAL_IN_MINUTES: number = 5;
|
|
125
|
+
const MINUTE_IN_MS: number = 60 * 1000;
|
|
126
|
+
/*
|
|
127
|
+
* A detection created within one poll interval plus this grace of its
|
|
128
|
+
* detection time would still have been caught by a detection-time cursor;
|
|
129
|
+
* anything later is exactly the record that basis lost.
|
|
130
|
+
*/
|
|
131
|
+
const CREATION_LAG_GRACE_IN_MINUTES: number = 1;
|
|
132
|
+
/*
|
|
133
|
+
* The alerts view has no pagination, so a truncated window is split at its
|
|
134
|
+
* midpoint until it is no longer than this and then reported as unread.
|
|
135
|
+
*/
|
|
136
|
+
const MIN_SPLIT_WINDOW_IN_MS: number = 1000;
|
|
137
|
+
/*
|
|
138
|
+
* Curated (Google-authored) rule detections are optional: tenants without
|
|
139
|
+
* that entitlement answer 403 (and some 400/404) on the curated route. Those
|
|
140
|
+
* statuses degrade the pass to a warning; 401, 429, 5xx, timeouts and parse
|
|
141
|
+
* failures still fail the fetch like any other pass.
|
|
142
|
+
*/
|
|
143
|
+
const CURATED_OPTIONAL_STATUSES: Array<number> = [400, 403, 404];
|
|
144
|
+
const CURATED_OPTIONAL_REMEDIATION: string =
|
|
145
|
+
"Curated (Google-authored) rule detections need that entitlement on the tenant. Nothing to fix unless you expect curated detections to be imported.";
|
|
146
|
+
|
|
147
|
+
const DAY_IN_MS: number = 24 * 60 * 60 * 1000;
|
|
148
|
+
const WEEK_IN_MS: number = 7 * DAY_IN_MS;
|
|
149
|
+
const AVAILABILITY_PAGE_SIZE: number = 1000;
|
|
150
|
+
/*
|
|
151
|
+
* Names the form control as it ships: a "Data to import" group where Alerts
|
|
152
|
+
* is fixed and a Detections checkbox widens the import.
|
|
153
|
+
*/
|
|
154
|
+
const SCOPE_MISMATCH_REMEDIATION: string =
|
|
155
|
+
"Your rules create detections but alerting is not enabled on them. Edit the connection and select Detections under Data to import, or enable alerting on the rules in Google SecOps.";
|
|
156
|
+
const NO_DETECTIONS_MESSAGE: string =
|
|
157
|
+
"No detections were created in the last 7 days. Polling will import new detections as Google creates them.";
|
|
158
|
+
const CONFIGURATION_REMEDIATION: string =
|
|
159
|
+
"Correct the highlighted setting and test again. Nothing was contacted.";
|
|
160
|
+
const READ_REMEDIATION: string =
|
|
161
|
+
"Grant roles/chronicle.viewer on the instance to the service account (it includes chronicle.legacies.legacySearchDetections, legacySearchCuratedDetections and chronicle.curatedRuleSetCategories.countAllCuratedRuleSetDetections), and confirm the instance resource name and region.";
|
|
162
|
+
|
|
163
|
+
type ScopeLabel = "alerts-only" | "alerts-and-detections";
|
|
164
|
+
|
|
165
|
+
/*
|
|
166
|
+
* What one Data to import selection has to offer, bounded: the alerts view
|
|
167
|
+
* reports its matched count without returning records (maxReturnedAlerts=1),
|
|
168
|
+
* and the created-time search reads one page of up to 1000, reported as
|
|
169
|
+
* "1000+" when a further page exists.
|
|
170
|
+
*/
|
|
171
|
+
interface ScopeAvailability {
|
|
172
|
+
scope: ScopeLabel;
|
|
173
|
+
alertsViewLast24h: number;
|
|
174
|
+
alertsViewLast7d: number;
|
|
175
|
+
ruleDetectionsCreatedLast24h: string;
|
|
176
|
+
ruleDetectionsCreatedLast7d: string;
|
|
177
|
+
hasMoreLast7d: boolean;
|
|
178
|
+
totalLast7d: number;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
interface ReadProbeOutcome {
|
|
182
|
+
ok: boolean;
|
|
183
|
+
record: JSONObject | null;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
interface ResolvedSettings {
|
|
187
|
+
region: string;
|
|
188
|
+
instanceResourceName: string;
|
|
189
|
+
serviceAccountJson: string;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/*
|
|
193
|
+
* Builds the client for one call. The default constructs a real
|
|
194
|
+
* GoogleSecOpsClient over the connector's FetchLike; tests inject one that
|
|
195
|
+
* returns a scripted client.
|
|
196
|
+
*/
|
|
197
|
+
export type GoogleSecOpsClientFactory = (data: {
|
|
198
|
+
region: string;
|
|
199
|
+
instanceResourceName: string;
|
|
200
|
+
serviceAccountJson: string;
|
|
201
|
+
requestTimeoutInMs: number;
|
|
202
|
+
}) => GoogleSecOpsClient;
|
|
203
|
+
|
|
204
|
+
/*
|
|
205
|
+
* Why a read pass stopped before it had read everything it was asked for:
|
|
206
|
+
* its own request budget, the fetch's total request or record bound, or
|
|
207
|
+
* the wall clock.
|
|
208
|
+
*/
|
|
209
|
+
type PassStop = "requests" | "total" | "events" | "time" | null;
|
|
210
|
+
|
|
211
|
+
interface PassOutcome {
|
|
212
|
+
// Records Google returned across every request of the pass.
|
|
213
|
+
returned: number;
|
|
214
|
+
requests: number;
|
|
215
|
+
stoppedBy: PassStop;
|
|
216
|
+
// Google itself left part of the window unread (truncation, unfinished stream).
|
|
217
|
+
leftUnread: boolean;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
// Everything one fetch accumulates across its passes.
|
|
221
|
+
interface FetchRun {
|
|
222
|
+
startedMs: number;
|
|
223
|
+
maxDurationMs: number;
|
|
224
|
+
maxRequests: number;
|
|
225
|
+
maxEvents: number;
|
|
226
|
+
alertingOnly: boolean;
|
|
227
|
+
searchRequests: number;
|
|
228
|
+
curatedRequests: number;
|
|
229
|
+
alertsViewRequests: number;
|
|
230
|
+
requestCount: number;
|
|
231
|
+
complete: boolean;
|
|
232
|
+
// A record was dropped because the record bound was reached.
|
|
233
|
+
eventLimitHit: boolean;
|
|
234
|
+
seen: Map<string, JSONObject>;
|
|
235
|
+
/*
|
|
236
|
+
* Records only the late-alert sweep returned. They were created long
|
|
237
|
+
* after their detection time by definition, so creation lag is measured
|
|
238
|
+
* without them.
|
|
239
|
+
*/
|
|
240
|
+
sweptOnly: Set<string>;
|
|
241
|
+
warnings: Array<string>;
|
|
242
|
+
checks: Array<SecurityConnectorCheck>;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
/*
|
|
246
|
+
* How one alerts-view read treats what it could not read. The poll window
|
|
247
|
+
* read is authoritative: a truncated or budget-stopped part makes the fetch
|
|
248
|
+
* incomplete, so the poller narrows and retries it. The late-alert sweep is
|
|
249
|
+
* best effort: it reaches back over windows earlier polls already
|
|
250
|
+
* completed, so narrowing the next window could never shrink it, and
|
|
251
|
+
* holding the cursor for it would stall polling for good.
|
|
252
|
+
*/
|
|
253
|
+
interface AlertsViewReadOptions {
|
|
254
|
+
includeNonAlertingDetections: boolean;
|
|
255
|
+
bestEffort: boolean;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
// What the curated pass read, beyond the shared pass outcome.
|
|
259
|
+
interface CuratedPassOutcome extends PassOutcome {
|
|
260
|
+
rulesWithDetections: number;
|
|
261
|
+
rulesSearched: number;
|
|
262
|
+
// Rules whose own search answered 400, 403 or 404 and were skipped.
|
|
263
|
+
rulesUnreadable: number;
|
|
264
|
+
/*
|
|
265
|
+
* Rules a bound stopped the pass before it started: their count does not
|
|
266
|
+
* shrink with the window, so this is reported, never made incomplete.
|
|
267
|
+
*/
|
|
268
|
+
rulesNotStarted: number;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
interface CreationLag {
|
|
272
|
+
measured: number;
|
|
273
|
+
lateCount: number;
|
|
274
|
+
maxLagMinutes: number;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
export default class GoogleSecOpsConnector implements SecurityEventConnector {
|
|
278
|
+
public provider: SecurityEventConnectorProvider =
|
|
279
|
+
SecurityEventConnectorProvider.GoogleSecOps;
|
|
280
|
+
|
|
281
|
+
/*
|
|
282
|
+
* The poller's single-list defaults (20 requests, 10000 records) would
|
|
283
|
+
* collapse the split budgets below into one and let the alerts view
|
|
284
|
+
* starve the searches. The total is both budgets together, the record
|
|
285
|
+
* bound is what those requests can return (the retired poller had no
|
|
286
|
+
* record cap, so it never binds in normal operation), and the wall clock
|
|
287
|
+
* leaves the ten-minute worker job room to import.
|
|
288
|
+
*/
|
|
289
|
+
public fetchBudget: ConnectorFetchBudget = {
|
|
290
|
+
maxRequests:
|
|
291
|
+
GOOGLE_SECOPS_SEARCH_PAGE_BUDGET +
|
|
292
|
+
GOOGLE_SECOPS_CURATED_REQUEST_BUDGET +
|
|
293
|
+
GOOGLE_SECOPS_ALERTS_VIEW_REQUEST_BUDGET,
|
|
294
|
+
maxEvents:
|
|
295
|
+
(GOOGLE_SECOPS_SEARCH_PAGE_BUDGET +
|
|
296
|
+
GOOGLE_SECOPS_CURATED_REQUEST_BUDGET) *
|
|
297
|
+
MAX_SEARCH_PAGE_SIZE +
|
|
298
|
+
GOOGLE_SECOPS_ALERTS_VIEW_REQUEST_BUDGET * MAX_ALERTS_PER_REQUEST,
|
|
299
|
+
maxDurationMs: GOOGLE_SECOPS_FETCH_DURATION_MS,
|
|
300
|
+
};
|
|
301
|
+
|
|
302
|
+
private fetchImplementation: FetchLike | undefined;
|
|
303
|
+
private clientFactory: GoogleSecOpsClientFactory | undefined;
|
|
304
|
+
|
|
305
|
+
public constructor(
|
|
306
|
+
fetchImplementation?: FetchLike | undefined,
|
|
307
|
+
clientFactory?: GoogleSecOpsClientFactory | undefined,
|
|
308
|
+
) {
|
|
309
|
+
this.fetchImplementation = fetchImplementation;
|
|
310
|
+
this.clientFactory = clientFactory;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
private static getDefinition(): SecurityEventConnectorDefinition {
|
|
314
|
+
const definition: SecurityEventConnectorDefinition | undefined =
|
|
315
|
+
getSecurityEventConnectorDefinition(
|
|
316
|
+
SecurityEventConnectorProvider.GoogleSecOps,
|
|
317
|
+
);
|
|
318
|
+
|
|
319
|
+
if (!definition) {
|
|
320
|
+
throw new BadDataException(
|
|
321
|
+
"Google SecOps is missing from the connector catalog.",
|
|
322
|
+
);
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
return definition;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
private static fieldTitle(key: string): string {
|
|
329
|
+
const definition: SecurityEventConnectorDefinition = this.getDefinition();
|
|
330
|
+
const field: { title: string } | undefined = [
|
|
331
|
+
...definition.configFields,
|
|
332
|
+
...definition.secretFields,
|
|
333
|
+
].find((candidate: { key: string }): boolean => {
|
|
334
|
+
return candidate.key === key;
|
|
335
|
+
});
|
|
336
|
+
|
|
337
|
+
return field?.title || key;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
/*
|
|
341
|
+
* Runs one of GoogleSecOpsClient's save-time rules and makes sure its
|
|
342
|
+
* rejection opens with the catalog title of the field it is about, the
|
|
343
|
+
* way every connector names its fields. The client's messages already do;
|
|
344
|
+
* the prefix only guards against a future message that does not.
|
|
345
|
+
*/
|
|
346
|
+
private static checkField(key: string, validate: () => void): void {
|
|
347
|
+
try {
|
|
348
|
+
validate();
|
|
349
|
+
} catch (error) {
|
|
350
|
+
const title: string = this.fieldTitle(key);
|
|
351
|
+
const message: string = ConnectorErrorMessage.toMessage(error, {
|
|
352
|
+
truncate: false,
|
|
353
|
+
});
|
|
354
|
+
|
|
355
|
+
throw new BadDataException(
|
|
356
|
+
message.startsWith(title) ? message : `${title}: ${message}`,
|
|
357
|
+
);
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
/*
|
|
362
|
+
* The pasted key is stored as text. Anything else in that slot is a
|
|
363
|
+
* storage bug, named as such rather than surfaced as "not valid JSON" for
|
|
364
|
+
* a value the person never typed.
|
|
365
|
+
*/
|
|
366
|
+
private static readServiceAccountJson(secrets: JSONObject): string {
|
|
367
|
+
const value: JSONValue | undefined = secrets["serviceAccountJson"];
|
|
368
|
+
|
|
369
|
+
if (value === null || value === undefined) {
|
|
370
|
+
return "";
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
if (typeof value !== "string") {
|
|
374
|
+
throw new BadDataException(
|
|
375
|
+
`${this.fieldTitle("serviceAccountJson")} must be the key file's JSON text.`,
|
|
376
|
+
);
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
return value.trim();
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
/*
|
|
383
|
+
* Every GoogleSecOpsClient constructor rule, without the network: region
|
|
384
|
+
* allowlist, instance resource name shape, region matching the
|
|
385
|
+
* instance's location (eu/europe are one place), and a service-account
|
|
386
|
+
* key with string client_email and private_key, a readable PEM and a
|
|
387
|
+
* token_uri on a Google host.
|
|
388
|
+
*/
|
|
389
|
+
private static resolveSettings(
|
|
390
|
+
settings: SecurityConnectorSettings,
|
|
391
|
+
): ResolvedSettings {
|
|
392
|
+
const config: JSONObject = settings.config || {};
|
|
393
|
+
const secrets: JSONObject = settings.secrets || {};
|
|
394
|
+
const region: string = readSettingString(config, "region");
|
|
395
|
+
const instanceResourceName: string = readSettingString(
|
|
396
|
+
config,
|
|
397
|
+
"instanceResourceName",
|
|
398
|
+
);
|
|
399
|
+
const serviceAccountJson: string = this.readServiceAccountJson(secrets);
|
|
400
|
+
|
|
401
|
+
if (!region) {
|
|
402
|
+
throw new BadDataException(`${this.fieldTitle("region")} is required.`);
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
this.checkField("region", (): void => {
|
|
406
|
+
GoogleSecOpsClient.validateRegion(region);
|
|
407
|
+
});
|
|
408
|
+
|
|
409
|
+
if (!instanceResourceName) {
|
|
410
|
+
throw new BadDataException(
|
|
411
|
+
`${this.fieldTitle("instanceResourceName")} is required.`,
|
|
412
|
+
);
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
this.checkField("instanceResourceName", (): void => {
|
|
416
|
+
GoogleSecOpsClient.validateInstanceResourceName(instanceResourceName);
|
|
417
|
+
});
|
|
418
|
+
this.checkField("region", (): void => {
|
|
419
|
+
GoogleSecOpsClient.validateRegionMatchesInstance(
|
|
420
|
+
region,
|
|
421
|
+
instanceResourceName,
|
|
422
|
+
);
|
|
423
|
+
});
|
|
424
|
+
|
|
425
|
+
if (!serviceAccountJson) {
|
|
426
|
+
throw new BadDataException(
|
|
427
|
+
`${this.fieldTitle("serviceAccountJson")} is required.`,
|
|
428
|
+
);
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
this.checkField("serviceAccountJson", (): void => {
|
|
432
|
+
GoogleSecOpsClient.parseServiceAccountJson(serviceAccountJson);
|
|
433
|
+
});
|
|
434
|
+
|
|
435
|
+
return { region, instanceResourceName, serviceAccountJson };
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
public validateSettings(settings: SecurityConnectorSettings): void {
|
|
439
|
+
if (settings.provider !== this.provider) {
|
|
440
|
+
throw new BadDataException(
|
|
441
|
+
`Settings are for provider "${String(settings.provider)}", not ${PROVIDER_TITLE}.`,
|
|
442
|
+
);
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
GoogleSecOpsConnector.resolveSettings(settings);
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
private createClient(
|
|
449
|
+
settings: SecurityConnectorSettings,
|
|
450
|
+
requestTimeoutInMs: number,
|
|
451
|
+
): GoogleSecOpsClient {
|
|
452
|
+
const resolved: ResolvedSettings =
|
|
453
|
+
GoogleSecOpsConnector.resolveSettings(settings);
|
|
454
|
+
|
|
455
|
+
if (this.clientFactory) {
|
|
456
|
+
return this.clientFactory({ ...resolved, requestTimeoutInMs });
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
return new GoogleSecOpsClient({
|
|
460
|
+
...resolved,
|
|
461
|
+
requestTimeoutInMs,
|
|
462
|
+
fetchImplementation: this.fetchImplementation,
|
|
463
|
+
});
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
/*
|
|
467
|
+
* ---------------------------------------------------------------------
|
|
468
|
+
* Test connection
|
|
469
|
+
* ---------------------------------------------------------------------
|
|
470
|
+
*/
|
|
471
|
+
|
|
472
|
+
/*
|
|
473
|
+
* The provider checks mirror the three read passes, then count what is
|
|
474
|
+
* available to import with AND without Detections selected under Data to
|
|
475
|
+
* import, because "connected but nothing ingests" is very often "the
|
|
476
|
+
* rules create detections, none of them alert, and only Alerts are
|
|
477
|
+
* imported". Platform and schedule checks are added by the shared tester.
|
|
478
|
+
* Never throws: every failure is a check.
|
|
479
|
+
*/
|
|
480
|
+
public async testConnection(
|
|
481
|
+
settings: SecurityConnectorSettings,
|
|
482
|
+
options: ConnectorTestOptions,
|
|
483
|
+
): Promise<ConnectorTestResult> {
|
|
484
|
+
const checks: Array<SecurityConnectorCheck> = [];
|
|
485
|
+
const samples: Array<SecurityConnectorSample> = [];
|
|
486
|
+
const now: Date = OneUptimeDate.getCurrentDate();
|
|
487
|
+
const alertingOnly: boolean = settings.alertingOnly !== false;
|
|
488
|
+
let counts: JSONObject | undefined = undefined;
|
|
489
|
+
let client: GoogleSecOpsClient;
|
|
490
|
+
|
|
491
|
+
try {
|
|
492
|
+
client = this.createClient(settings, options.requestTimeoutInMs);
|
|
493
|
+
} catch (error) {
|
|
494
|
+
checks.push(
|
|
495
|
+
makeCheck({
|
|
496
|
+
key: "authentication",
|
|
497
|
+
name: "Authenticate with Google",
|
|
498
|
+
status: "fail",
|
|
499
|
+
startedAtMs: Date.now(),
|
|
500
|
+
message: redactLogString(ConnectorErrorMessage.toMessage(error)),
|
|
501
|
+
remediation: CONFIGURATION_REMEDIATION,
|
|
502
|
+
}),
|
|
503
|
+
);
|
|
504
|
+
checks.push(
|
|
505
|
+
GoogleSecOpsConnector.skipped(
|
|
506
|
+
"Skipped because the configuration is not usable.",
|
|
507
|
+
),
|
|
508
|
+
);
|
|
509
|
+
return { checks };
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
const authenticated: boolean =
|
|
513
|
+
await GoogleSecOpsConnector.authenticationCheck(client, checks);
|
|
514
|
+
|
|
515
|
+
if (!authenticated) {
|
|
516
|
+
checks.push(
|
|
517
|
+
GoogleSecOpsConnector.skipped("Skipped because authentication failed."),
|
|
518
|
+
);
|
|
519
|
+
return { checks };
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
const ruleRead: ReadProbeOutcome =
|
|
523
|
+
await GoogleSecOpsConnector.searchReadCheck(client, checks, {
|
|
524
|
+
curated: false,
|
|
525
|
+
now,
|
|
526
|
+
alertingOnly,
|
|
527
|
+
});
|
|
528
|
+
/*
|
|
529
|
+
* The curated read does not gate availability: a tenant without curated
|
|
530
|
+
* rules still has rule detections and alerts to count.
|
|
531
|
+
*/
|
|
532
|
+
await GoogleSecOpsConnector.searchReadCheck(client, checks, {
|
|
533
|
+
curated: true,
|
|
534
|
+
now,
|
|
535
|
+
alertingOnly,
|
|
536
|
+
});
|
|
537
|
+
const alertsRead: ReadProbeOutcome =
|
|
538
|
+
await GoogleSecOpsConnector.alertsViewReadCheck(client, checks, {
|
|
539
|
+
now,
|
|
540
|
+
alertingOnly,
|
|
541
|
+
});
|
|
542
|
+
|
|
543
|
+
for (const record of [ruleRead.record, alertsRead.record]) {
|
|
544
|
+
const sample: SecurityConnectorSample | null =
|
|
545
|
+
GoogleSecOpsConnector.toTestSample(record);
|
|
546
|
+
|
|
547
|
+
if (sample) {
|
|
548
|
+
samples.push(sample);
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
if (!ruleRead.ok || !alertsRead.ok) {
|
|
553
|
+
checks.push(
|
|
554
|
+
GoogleSecOpsConnector.skipped(
|
|
555
|
+
"Skipped because a read check failed; fix that first and test again.",
|
|
556
|
+
),
|
|
557
|
+
);
|
|
558
|
+
} else if (options.skipAvailability) {
|
|
559
|
+
/*
|
|
560
|
+
* A queued test run only needs to know whether access works; eight
|
|
561
|
+
* more probes at the worker's request deadline could outlive its job.
|
|
562
|
+
*/
|
|
563
|
+
checks.push(
|
|
564
|
+
GoogleSecOpsConnector.skipped(
|
|
565
|
+
"Skipped in a queued test run: availability is only counted by the synchronous Test connection.",
|
|
566
|
+
),
|
|
567
|
+
);
|
|
568
|
+
} else {
|
|
569
|
+
counts = await GoogleSecOpsConnector.availabilityCheck(client, checks, {
|
|
570
|
+
now,
|
|
571
|
+
alertingOnly,
|
|
572
|
+
});
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
return {
|
|
576
|
+
checks,
|
|
577
|
+
...(counts ? { counts } : {}),
|
|
578
|
+
...(samples.length > 0 ? { samples } : {}),
|
|
579
|
+
};
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
private static skipped(message: string): SecurityConnectorCheck {
|
|
583
|
+
return makeCheck({
|
|
584
|
+
key: "detections-available",
|
|
585
|
+
name: "Detections available to import",
|
|
586
|
+
status: "skip",
|
|
587
|
+
startedAtMs: Date.now(),
|
|
588
|
+
message,
|
|
589
|
+
});
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
private static async authenticationCheck(
|
|
593
|
+
client: GoogleSecOpsClient,
|
|
594
|
+
checks: Array<SecurityConnectorCheck>,
|
|
595
|
+
): Promise<boolean> {
|
|
596
|
+
const startedAtMs: number = Date.now();
|
|
597
|
+
|
|
598
|
+
try {
|
|
599
|
+
await client.testAuthentication();
|
|
600
|
+
checks.push(
|
|
601
|
+
makeCheck({
|
|
602
|
+
key: "authentication",
|
|
603
|
+
name: "Authenticate with Google",
|
|
604
|
+
status: "pass",
|
|
605
|
+
startedAtMs,
|
|
606
|
+
message: "Google accepted the service account credentials.",
|
|
607
|
+
}),
|
|
608
|
+
);
|
|
609
|
+
return true;
|
|
610
|
+
} catch (error) {
|
|
611
|
+
checks.push(
|
|
612
|
+
makeCheck({
|
|
613
|
+
key: "authentication",
|
|
614
|
+
name: "Authenticate with Google",
|
|
615
|
+
status: "fail",
|
|
616
|
+
startedAtMs,
|
|
617
|
+
message: redactLogString(
|
|
618
|
+
ConnectorErrorMessage.toMessage(error, { truncate: false }),
|
|
619
|
+
),
|
|
620
|
+
remediation:
|
|
621
|
+
"The token exchange happens at Google's OAuth endpoint before Chronicle is contacted. Re-download the service account key, confirm it belongs to the project the instance is bound to, and check this host's clock.",
|
|
622
|
+
}),
|
|
623
|
+
);
|
|
624
|
+
return false;
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
/*
|
|
629
|
+
* One created-time page of size 1 over the last 24 hours: proves the
|
|
630
|
+
* legacySearchDetections (or curated) permission without reading data.
|
|
631
|
+
*/
|
|
632
|
+
private static async searchReadCheck(
|
|
633
|
+
client: GoogleSecOpsClient,
|
|
634
|
+
checks: Array<SecurityConnectorCheck>,
|
|
635
|
+
options: { curated: boolean; now: Date; alertingOnly: boolean },
|
|
636
|
+
): Promise<ReadProbeOutcome> {
|
|
637
|
+
const startedAtMs: number = Date.now();
|
|
638
|
+
const key: string = options.curated
|
|
639
|
+
? "curated-detections-read"
|
|
640
|
+
: "rule-detections-read";
|
|
641
|
+
const name: string = options.curated
|
|
642
|
+
? "Read curated rule detections"
|
|
643
|
+
: "Read rule detections";
|
|
644
|
+
|
|
645
|
+
try {
|
|
646
|
+
if (options.curated) {
|
|
647
|
+
return await this.curatedReadProbe(client, checks, {
|
|
648
|
+
key,
|
|
649
|
+
name,
|
|
650
|
+
startedAtMs,
|
|
651
|
+
now: options.now,
|
|
652
|
+
alertingOnly: options.alertingOnly,
|
|
653
|
+
});
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
const page: SearchDetectionsResult = await client.searchDetections({
|
|
657
|
+
startTime: new Date(options.now.getTime() - DAY_IN_MS),
|
|
658
|
+
endTime: options.now,
|
|
659
|
+
listBasis: "CREATED_TIME",
|
|
660
|
+
alertingOnly: options.alertingOnly,
|
|
661
|
+
pageSize: 1,
|
|
662
|
+
});
|
|
663
|
+
checks.push(
|
|
664
|
+
makeCheck({
|
|
665
|
+
key,
|
|
666
|
+
name,
|
|
667
|
+
status: "pass",
|
|
668
|
+
startedAtMs,
|
|
669
|
+
message: `Rule detections can be read by created time (${page.detections.length} returned for a one-record probe over the last 24 hours).`,
|
|
670
|
+
details: { returned: page.detections.length },
|
|
671
|
+
}),
|
|
672
|
+
);
|
|
673
|
+
return { ok: true, record: page.detections[0] || null };
|
|
674
|
+
} catch (error) {
|
|
675
|
+
const status: number | null = GoogleSecOpsClient.readHttpStatus(error);
|
|
676
|
+
const message: string = redactLogString(
|
|
677
|
+
ConnectorErrorMessage.toMessage(error, { truncate: false }),
|
|
678
|
+
);
|
|
679
|
+
|
|
680
|
+
if (
|
|
681
|
+
options.curated &&
|
|
682
|
+
status !== null &&
|
|
683
|
+
CURATED_OPTIONAL_STATUSES.includes(status)
|
|
684
|
+
) {
|
|
685
|
+
checks.push(
|
|
686
|
+
makeCheck({
|
|
687
|
+
key,
|
|
688
|
+
name,
|
|
689
|
+
status: "warn",
|
|
690
|
+
startedAtMs,
|
|
691
|
+
message: `Curated rule detections are not readable on this tenant (HTTP ${status}). Polling continues with rule detections and the alerts view.`,
|
|
692
|
+
remediation: CURATED_OPTIONAL_REMEDIATION,
|
|
693
|
+
details: { httpStatus: status, error: message },
|
|
694
|
+
}),
|
|
695
|
+
);
|
|
696
|
+
return { ok: true, record: null };
|
|
697
|
+
}
|
|
698
|
+
|
|
699
|
+
checks.push(
|
|
700
|
+
makeCheck({
|
|
701
|
+
key,
|
|
702
|
+
name,
|
|
703
|
+
status: "fail",
|
|
704
|
+
startedAtMs,
|
|
705
|
+
message,
|
|
706
|
+
remediation: READ_REMEDIATION,
|
|
707
|
+
}),
|
|
708
|
+
);
|
|
709
|
+
return { ok: false, record: null };
|
|
710
|
+
}
|
|
711
|
+
}
|
|
712
|
+
|
|
713
|
+
/*
|
|
714
|
+
* The curated pass's two reads: the curated rule counts over the last 7
|
|
715
|
+
* days, then, when a curated rule produced detections, a one-record
|
|
716
|
+
* created-time search of the rule with the most detections over the same
|
|
717
|
+
* week. The curated search has no wildcard, so a tenant whose curated
|
|
718
|
+
* rules have not fired has nothing it could probe; that is still a pass,
|
|
719
|
+
* because the count proves the curated read is permitted.
|
|
720
|
+
*/
|
|
721
|
+
private static async curatedReadProbe(
|
|
722
|
+
client: GoogleSecOpsClient,
|
|
723
|
+
checks: Array<SecurityConnectorCheck>,
|
|
724
|
+
options: {
|
|
725
|
+
key: string;
|
|
726
|
+
name: string;
|
|
727
|
+
startedAtMs: number;
|
|
728
|
+
now: Date;
|
|
729
|
+
alertingOnly: boolean;
|
|
730
|
+
},
|
|
731
|
+
): Promise<ReadProbeOutcome> {
|
|
732
|
+
const weekAgo: Date = new Date(options.now.getTime() - WEEK_IN_MS);
|
|
733
|
+
const rules: Array<CuratedRuleDetectionCount> =
|
|
734
|
+
await client.countCuratedRuleDetections({
|
|
735
|
+
startTime: weekAgo,
|
|
736
|
+
endTime: options.now,
|
|
737
|
+
});
|
|
738
|
+
|
|
739
|
+
if (rules.length === 0) {
|
|
740
|
+
checks.push(
|
|
741
|
+
makeCheck({
|
|
742
|
+
key: options.key,
|
|
743
|
+
name: options.name,
|
|
744
|
+
status: "pass",
|
|
745
|
+
startedAtMs: options.startedAtMs,
|
|
746
|
+
message:
|
|
747
|
+
"Curated rule detection counts can be read. No curated rule produced detections in the last 7 days, so there are no curated detections to import yet.",
|
|
748
|
+
details: { curatedRulesWithDetections: 0, returned: 0 },
|
|
749
|
+
}),
|
|
750
|
+
);
|
|
751
|
+
return { ok: true, record: null };
|
|
752
|
+
}
|
|
753
|
+
|
|
754
|
+
const busiest: CuratedRuleDetectionCount = rules.reduce(
|
|
755
|
+
(
|
|
756
|
+
best: CuratedRuleDetectionCount,
|
|
757
|
+
candidate: CuratedRuleDetectionCount,
|
|
758
|
+
): CuratedRuleDetectionCount => {
|
|
759
|
+
return candidate.count > best.count ? candidate : best;
|
|
760
|
+
},
|
|
761
|
+
);
|
|
762
|
+
const page: SearchDetectionsResult = await client.searchDetections({
|
|
763
|
+
startTime: weekAgo,
|
|
764
|
+
endTime: options.now,
|
|
765
|
+
listBasis: "CREATED_TIME",
|
|
766
|
+
alertingOnly: options.alertingOnly,
|
|
767
|
+
pageSize: 1,
|
|
768
|
+
curated: true,
|
|
769
|
+
ruleId: busiest.ruleId,
|
|
770
|
+
});
|
|
771
|
+
|
|
772
|
+
checks.push(
|
|
773
|
+
makeCheck({
|
|
774
|
+
key: options.key,
|
|
775
|
+
name: options.name,
|
|
776
|
+
status: "pass",
|
|
777
|
+
startedAtMs: options.startedAtMs,
|
|
778
|
+
message: `Curated rule detections can be read by created time: ${rules.length} curated ${rules.length === 1 ? "rule" : "rules"} produced detections in the last 7 days (${page.detections.length} returned for a one-record probe of ${busiest.ruleId}).`,
|
|
779
|
+
details: {
|
|
780
|
+
curatedRulesWithDetections: rules.length,
|
|
781
|
+
returned: page.detections.length,
|
|
782
|
+
},
|
|
783
|
+
}),
|
|
784
|
+
);
|
|
785
|
+
return { ok: true, record: page.detections[0] || null };
|
|
786
|
+
}
|
|
787
|
+
|
|
788
|
+
/*
|
|
789
|
+
* One alerts-view read with maxReturnedAlerts=1 over the last 24 hours:
|
|
790
|
+
* proves the legacyFetchAlertsView permission the third pass needs.
|
|
791
|
+
*/
|
|
792
|
+
private static async alertsViewReadCheck(
|
|
793
|
+
client: GoogleSecOpsClient,
|
|
794
|
+
checks: Array<SecurityConnectorCheck>,
|
|
795
|
+
options: { now: Date; alertingOnly: boolean },
|
|
796
|
+
): Promise<ReadProbeOutcome> {
|
|
797
|
+
const startedAtMs: number = Date.now();
|
|
798
|
+
|
|
799
|
+
try {
|
|
800
|
+
const fetched: FetchAlertsResult = await client.fetchDetectionAlerts({
|
|
801
|
+
startTime: new Date(options.now.getTime() - DAY_IN_MS),
|
|
802
|
+
endTime: options.now,
|
|
803
|
+
maxAlerts: 1,
|
|
804
|
+
includeNonAlertingDetections: !options.alertingOnly,
|
|
805
|
+
});
|
|
806
|
+
checks.push(
|
|
807
|
+
makeCheck({
|
|
808
|
+
key: "alerts-view-read",
|
|
809
|
+
name: "Read the alerts view",
|
|
810
|
+
status: fetched.complete ? "pass" : "warn",
|
|
811
|
+
startedAtMs,
|
|
812
|
+
message: fetched.complete
|
|
813
|
+
? `The alerts view can be read by detection time (${fetched.baselineAlertsCount} matched in the last 24 hours).`
|
|
814
|
+
: "The alerts view answered but the stream ended without confirming it was complete. Reads work; a complete read is not confirmed.",
|
|
815
|
+
details: {
|
|
816
|
+
baselineAlertsCount: fetched.baselineAlertsCount,
|
|
817
|
+
complete: fetched.complete,
|
|
818
|
+
},
|
|
819
|
+
}),
|
|
820
|
+
);
|
|
821
|
+
return { ok: true, record: fetched.alerts[0] || null };
|
|
822
|
+
} catch (error) {
|
|
823
|
+
checks.push(
|
|
824
|
+
makeCheck({
|
|
825
|
+
key: "alerts-view-read",
|
|
826
|
+
name: "Read the alerts view",
|
|
827
|
+
status: "fail",
|
|
828
|
+
startedAtMs,
|
|
829
|
+
message: redactLogString(
|
|
830
|
+
ConnectorErrorMessage.toMessage(error, { truncate: false }),
|
|
831
|
+
),
|
|
832
|
+
remediation:
|
|
833
|
+
"Grant roles/chronicle.viewer on the instance to the service account (it includes chronicle.legacies.legacyFetchAlertsView), and confirm the instance resource name and region.",
|
|
834
|
+
}),
|
|
835
|
+
);
|
|
836
|
+
return { ok: false, record: null };
|
|
837
|
+
}
|
|
838
|
+
}
|
|
839
|
+
|
|
840
|
+
/*
|
|
841
|
+
* Counts under the saved Data to import selection AND the other one, over
|
|
842
|
+
* 24 hours and 7 days. The mismatch this exists to catch: rules create
|
|
843
|
+
* detections, none of them alert, Detections is not selected, and every
|
|
844
|
+
* poll is honestly empty.
|
|
845
|
+
*/
|
|
846
|
+
private static async availabilityCheck(
|
|
847
|
+
client: GoogleSecOpsClient,
|
|
848
|
+
checks: Array<SecurityConnectorCheck>,
|
|
849
|
+
options: { now: Date; alertingOnly: boolean },
|
|
850
|
+
): Promise<JSONObject | undefined> {
|
|
851
|
+
const startedAtMs: number = Date.now();
|
|
852
|
+
|
|
853
|
+
try {
|
|
854
|
+
const saved: ScopeAvailability = await this.probeScope(
|
|
855
|
+
client,
|
|
856
|
+
options.now,
|
|
857
|
+
options.alertingOnly,
|
|
858
|
+
);
|
|
859
|
+
const other: ScopeAvailability = await this.probeScope(
|
|
860
|
+
client,
|
|
861
|
+
options.now,
|
|
862
|
+
!options.alertingOnly,
|
|
863
|
+
);
|
|
864
|
+
const counts: JSONObject = {
|
|
865
|
+
scope: saved.scope,
|
|
866
|
+
alertsViewLast24h: saved.alertsViewLast24h,
|
|
867
|
+
alertsViewLast7d: saved.alertsViewLast7d,
|
|
868
|
+
ruleDetectionsCreatedLast24h: saved.ruleDetectionsCreatedLast24h,
|
|
869
|
+
ruleDetectionsCreatedLast7d: saved.ruleDetectionsCreatedLast7d,
|
|
870
|
+
hasMoreLast7d: saved.hasMoreLast7d,
|
|
871
|
+
otherScope: {
|
|
872
|
+
scope: other.scope,
|
|
873
|
+
alertsViewLast24h: other.alertsViewLast24h,
|
|
874
|
+
alertsViewLast7d: other.alertsViewLast7d,
|
|
875
|
+
ruleDetectionsCreatedLast24h: other.ruleDetectionsCreatedLast24h,
|
|
876
|
+
ruleDetectionsCreatedLast7d: other.ruleDetectionsCreatedLast7d,
|
|
877
|
+
hasMoreLast7d: other.hasMoreLast7d,
|
|
878
|
+
},
|
|
879
|
+
};
|
|
880
|
+
|
|
881
|
+
if (saved.totalLast7d > 0) {
|
|
882
|
+
checks.push(
|
|
883
|
+
makeCheck({
|
|
884
|
+
key: "detections-available",
|
|
885
|
+
name: "Detections available to import",
|
|
886
|
+
status: "pass",
|
|
887
|
+
startedAtMs,
|
|
888
|
+
message: `With the saved Data to import (${this.describeScope(saved.scope)}): last 24 hours ${saved.ruleDetectionsCreatedLast24h} rule detections created and ${saved.alertsViewLast24h} alerts in the alerts view; last 7 days ${saved.ruleDetectionsCreatedLast7d} and ${saved.alertsViewLast7d}.`,
|
|
889
|
+
details: counts,
|
|
890
|
+
}),
|
|
891
|
+
);
|
|
892
|
+
} else if (other.totalLast7d > 0) {
|
|
893
|
+
checks.push(
|
|
894
|
+
makeCheck({
|
|
895
|
+
key: "detections-available",
|
|
896
|
+
name: "Detections available to import",
|
|
897
|
+
status: "warn",
|
|
898
|
+
startedAtMs,
|
|
899
|
+
message: `Nothing is available with the saved Data to import (${this.describeScope(saved.scope)}) in the last 7 days, but ${other.ruleDetectionsCreatedLast7d} rule detections and ${other.alertsViewLast7d} alerts-view records exist with ${this.describeScope(other.scope)}.`,
|
|
900
|
+
remediation:
|
|
901
|
+
saved.scope === "alerts-only"
|
|
902
|
+
? SCOPE_MISMATCH_REMEDIATION
|
|
903
|
+
: "Reading Alerts only returned records that reading Alerts and Detections did not; re-run the test, and if it persists inspect the tenant's alerting configuration.",
|
|
904
|
+
details: counts,
|
|
905
|
+
}),
|
|
906
|
+
);
|
|
907
|
+
} else {
|
|
908
|
+
checks.push(
|
|
909
|
+
makeCheck({
|
|
910
|
+
key: "detections-available",
|
|
911
|
+
name: "Detections available to import",
|
|
912
|
+
status: "warn",
|
|
913
|
+
startedAtMs,
|
|
914
|
+
message: NO_DETECTIONS_MESSAGE,
|
|
915
|
+
remediation:
|
|
916
|
+
"Check that your rules are enabled and run on a schedule in Google SecOps. A quiet tenant is not a connector fault.",
|
|
917
|
+
details: counts,
|
|
918
|
+
}),
|
|
919
|
+
);
|
|
920
|
+
}
|
|
921
|
+
|
|
922
|
+
return counts;
|
|
923
|
+
} catch (error) {
|
|
924
|
+
checks.push(
|
|
925
|
+
makeCheck({
|
|
926
|
+
key: "detections-available",
|
|
927
|
+
name: "Detections available to import",
|
|
928
|
+
status: "warn",
|
|
929
|
+
startedAtMs,
|
|
930
|
+
message: `Could not count the detections available to import: ${redactLogString(ConnectorErrorMessage.toMessage(error, { truncate: false }))}`,
|
|
931
|
+
remediation:
|
|
932
|
+
"Reads work, so polling can proceed; re-run the test to retry the counts.",
|
|
933
|
+
}),
|
|
934
|
+
);
|
|
935
|
+
return undefined;
|
|
936
|
+
}
|
|
937
|
+
}
|
|
938
|
+
|
|
939
|
+
private static async probeScope(
|
|
940
|
+
client: GoogleSecOpsClient,
|
|
941
|
+
now: Date,
|
|
942
|
+
alertingOnly: boolean,
|
|
943
|
+
): Promise<ScopeAvailability> {
|
|
944
|
+
const dayAgo: Date = new Date(now.getTime() - DAY_IN_MS);
|
|
945
|
+
const weekAgo: Date = new Date(now.getTime() - WEEK_IN_MS);
|
|
946
|
+
|
|
947
|
+
const alertsLast24h: FetchAlertsResult = await client.fetchDetectionAlerts({
|
|
948
|
+
startTime: dayAgo,
|
|
949
|
+
endTime: now,
|
|
950
|
+
maxAlerts: 1,
|
|
951
|
+
includeNonAlertingDetections: !alertingOnly,
|
|
952
|
+
});
|
|
953
|
+
const alertsLast7d: FetchAlertsResult = await client.fetchDetectionAlerts({
|
|
954
|
+
startTime: weekAgo,
|
|
955
|
+
endTime: now,
|
|
956
|
+
maxAlerts: 1,
|
|
957
|
+
includeNonAlertingDetections: !alertingOnly,
|
|
958
|
+
});
|
|
959
|
+
const rulesLast24h: SearchDetectionsResult = await client.searchDetections({
|
|
960
|
+
startTime: dayAgo,
|
|
961
|
+
endTime: now,
|
|
962
|
+
listBasis: "CREATED_TIME",
|
|
963
|
+
alertingOnly,
|
|
964
|
+
pageSize: AVAILABILITY_PAGE_SIZE,
|
|
965
|
+
});
|
|
966
|
+
const rulesLast7d: SearchDetectionsResult = await client.searchDetections({
|
|
967
|
+
startTime: weekAgo,
|
|
968
|
+
endTime: now,
|
|
969
|
+
listBasis: "CREATED_TIME",
|
|
970
|
+
alertingOnly,
|
|
971
|
+
pageSize: AVAILABILITY_PAGE_SIZE,
|
|
972
|
+
});
|
|
973
|
+
|
|
974
|
+
const alertsViewLast7d: number = this.matchedCount(alertsLast7d);
|
|
975
|
+
|
|
976
|
+
return {
|
|
977
|
+
scope: alertingOnly ? "alerts-only" : "alerts-and-detections",
|
|
978
|
+
alertsViewLast24h: this.matchedCount(alertsLast24h),
|
|
979
|
+
alertsViewLast7d,
|
|
980
|
+
ruleDetectionsCreatedLast24h: this.boundedCount(rulesLast24h),
|
|
981
|
+
ruleDetectionsCreatedLast7d: this.boundedCount(rulesLast7d),
|
|
982
|
+
hasMoreLast7d:
|
|
983
|
+
rulesLast7d.nextPageToken !== null || rulesLast7d.truncated,
|
|
984
|
+
totalLast7d: alertsViewLast7d + rulesLast7d.detections.length,
|
|
985
|
+
};
|
|
986
|
+
}
|
|
987
|
+
|
|
988
|
+
/*
|
|
989
|
+
* The alerts view reports how many alerts matched even when only one is
|
|
990
|
+
* returned; a tenant answering without the count still counts the
|
|
991
|
+
* returned record.
|
|
992
|
+
*/
|
|
993
|
+
private static matchedCount(fetched: FetchAlertsResult): number {
|
|
994
|
+
return Math.max(
|
|
995
|
+
fetched.baselineAlertsCount,
|
|
996
|
+
fetched.filteredAlertsCount,
|
|
997
|
+
fetched.alerts.length,
|
|
998
|
+
);
|
|
999
|
+
}
|
|
1000
|
+
|
|
1001
|
+
private static boundedCount(page: SearchDetectionsResult): string {
|
|
1002
|
+
if (
|
|
1003
|
+
page.nextPageToken !== null ||
|
|
1004
|
+
page.truncated ||
|
|
1005
|
+
page.detections.length >= AVAILABILITY_PAGE_SIZE
|
|
1006
|
+
) {
|
|
1007
|
+
return `${AVAILABILITY_PAGE_SIZE}+`;
|
|
1008
|
+
}
|
|
1009
|
+
|
|
1010
|
+
return String(page.detections.length);
|
|
1011
|
+
}
|
|
1012
|
+
|
|
1013
|
+
/*
|
|
1014
|
+
* Read as "with <this>" in the messages above, so it names what the Data
|
|
1015
|
+
* to import group has checked.
|
|
1016
|
+
*/
|
|
1017
|
+
private static describeScope(scope: ScopeLabel): string {
|
|
1018
|
+
return scope === "alerts-only"
|
|
1019
|
+
? "Alerts only"
|
|
1020
|
+
: "Alerts and Detections selected";
|
|
1021
|
+
}
|
|
1022
|
+
|
|
1023
|
+
private static toTestSample(
|
|
1024
|
+
record: JSONObject | null,
|
|
1025
|
+
): SecurityConnectorSample | null {
|
|
1026
|
+
if (!record) {
|
|
1027
|
+
return null;
|
|
1028
|
+
}
|
|
1029
|
+
|
|
1030
|
+
try {
|
|
1031
|
+
if (!GoogleSecOpsAlertNormalizer.isGoogleSecOpsAlert(record)) {
|
|
1032
|
+
return null;
|
|
1033
|
+
}
|
|
1034
|
+
|
|
1035
|
+
const event: NormalizedSecurityEvent =
|
|
1036
|
+
GoogleSecOpsAlertNormalizer.normalize(record);
|
|
1037
|
+
const createdTime: Date | null = parseEventTime(
|
|
1038
|
+
readValue(record, "createdTime") ?? readValue(record, "created_time"),
|
|
1039
|
+
);
|
|
1040
|
+
const detectionTime: Date | null = parseEventTime(
|
|
1041
|
+
readValue(record, "detectionTime") ??
|
|
1042
|
+
readValue(record, "detection_time"),
|
|
1043
|
+
);
|
|
1044
|
+
|
|
1045
|
+
return {
|
|
1046
|
+
id: redactLogString(event.eventUid),
|
|
1047
|
+
title: redactLogString(event.message),
|
|
1048
|
+
severity: event.severityName,
|
|
1049
|
+
...(createdTime ? { createdTime: createdTime.toISOString() } : {}),
|
|
1050
|
+
...(detectionTime ? { eventTime: detectionTime.toISOString() } : {}),
|
|
1051
|
+
};
|
|
1052
|
+
} catch {
|
|
1053
|
+
return null;
|
|
1054
|
+
}
|
|
1055
|
+
}
|
|
1056
|
+
|
|
1057
|
+
/*
|
|
1058
|
+
* ---------------------------------------------------------------------
|
|
1059
|
+
* Fetch
|
|
1060
|
+
* ---------------------------------------------------------------------
|
|
1061
|
+
*/
|
|
1062
|
+
|
|
1063
|
+
/*
|
|
1064
|
+
* Three passes over one window, unioned by Collection.id. A poll reads
|
|
1065
|
+
* the searches by created time only; a preview or backfill takes a range
|
|
1066
|
+
* a person picked (which is how the SecOps alerts view frames time) and
|
|
1067
|
+
* reads created AND detection time, so an import of "yesterday" also
|
|
1068
|
+
* carries detections created yesterday about older events.
|
|
1069
|
+
*
|
|
1070
|
+
* Google's searches return newest first, so a fetch a bound stopped has
|
|
1071
|
+
* no "everything before here was read" point: resumeAfter stays undefined
|
|
1072
|
+
* and the poller narrows the next window instead.
|
|
1073
|
+
*
|
|
1074
|
+
* A pass that throws (authentication, HTTP, an unreadable body, a
|
|
1075
|
+
* timeout) rethrows the ORIGINAL error, whose message prefix the docs
|
|
1076
|
+
* quote, with the checks of the passes that ran and a failed check named
|
|
1077
|
+
* after the failing pass attached to it, and a summary of what those
|
|
1078
|
+
* passes gathered (warnings, request and record counts, basis and
|
|
1079
|
+
* per-pass counts) attached beside them.
|
|
1080
|
+
*/
|
|
1081
|
+
public async fetchEvents(
|
|
1082
|
+
settings: SecurityConnectorSettings,
|
|
1083
|
+
window: ConnectorFetchWindow,
|
|
1084
|
+
options: ConnectorFetchOptions,
|
|
1085
|
+
): Promise<ConnectorFetchResult> {
|
|
1086
|
+
const client: GoogleSecOpsClient = this.createClient(
|
|
1087
|
+
settings,
|
|
1088
|
+
options.requestTimeoutInMs,
|
|
1089
|
+
);
|
|
1090
|
+
const isHistorical: boolean =
|
|
1091
|
+
options.purpose === "preview" || options.purpose === "backfill";
|
|
1092
|
+
const searchBases: Array<GoogleSecOpsListBasis> = isHistorical
|
|
1093
|
+
? ["CREATED_TIME", "DETECTION_TIME"]
|
|
1094
|
+
: ["CREATED_TIME"];
|
|
1095
|
+
const basisLabel: string = isHistorical
|
|
1096
|
+
? "created and detection time"
|
|
1097
|
+
: "created time";
|
|
1098
|
+
// Reported in details on success and on the summary a failure carries.
|
|
1099
|
+
const basis: string = isHistorical ? "detection-time" : "created-time";
|
|
1100
|
+
const alertingOnly: boolean = settings.alertingOnly !== false;
|
|
1101
|
+
const run: FetchRun = {
|
|
1102
|
+
startedMs: Date.now(),
|
|
1103
|
+
maxDurationMs: GoogleSecOpsConnector.readBound(
|
|
1104
|
+
options.maxDurationMs,
|
|
1105
|
+
GOOGLE_SECOPS_FETCH_DURATION_MS,
|
|
1106
|
+
),
|
|
1107
|
+
maxRequests: GoogleSecOpsConnector.readBound(
|
|
1108
|
+
options.maxRequests,
|
|
1109
|
+
this.fetchBudget.maxRequests!,
|
|
1110
|
+
),
|
|
1111
|
+
maxEvents: GoogleSecOpsConnector.readBound(
|
|
1112
|
+
options.maxEvents,
|
|
1113
|
+
this.fetchBudget.maxEvents!,
|
|
1114
|
+
),
|
|
1115
|
+
alertingOnly,
|
|
1116
|
+
searchRequests: 0,
|
|
1117
|
+
curatedRequests: 0,
|
|
1118
|
+
alertsViewRequests: 0,
|
|
1119
|
+
requestCount: 0,
|
|
1120
|
+
complete: true,
|
|
1121
|
+
eventLimitHit: false,
|
|
1122
|
+
seen: new Map<string, JSONObject>(),
|
|
1123
|
+
sweptOnly: new Set<string>(),
|
|
1124
|
+
warnings: [],
|
|
1125
|
+
checks: [],
|
|
1126
|
+
};
|
|
1127
|
+
const sourceCounts: {
|
|
1128
|
+
ruleDetections: number;
|
|
1129
|
+
curatedDetections: number;
|
|
1130
|
+
alertsView: number;
|
|
1131
|
+
// Present only when the late-alert sweep ran.
|
|
1132
|
+
lateAlertsView?: number | undefined;
|
|
1133
|
+
} = { ruleDetections: 0, curatedDetections: 0, alertsView: 0 };
|
|
1134
|
+
let curatedRulesWithDetections: number = 0;
|
|
1135
|
+
|
|
1136
|
+
let phaseKey: string = "read-rule-detections";
|
|
1137
|
+
let phaseName: string = `Read rule detections by ${basisLabel}`;
|
|
1138
|
+
let phaseStartedMs: number = Date.now();
|
|
1139
|
+
|
|
1140
|
+
try {
|
|
1141
|
+
const rulePass: PassOutcome = await GoogleSecOpsConnector.searchPass(
|
|
1142
|
+
client,
|
|
1143
|
+
window,
|
|
1144
|
+
run,
|
|
1145
|
+
{ bases: searchBases },
|
|
1146
|
+
);
|
|
1147
|
+
sourceCounts.ruleDetections = rulePass.returned;
|
|
1148
|
+
GoogleSecOpsConnector.recordPass({
|
|
1149
|
+
run,
|
|
1150
|
+
key: phaseKey,
|
|
1151
|
+
name: phaseName,
|
|
1152
|
+
startedMs: phaseStartedMs,
|
|
1153
|
+
outcome: rulePass,
|
|
1154
|
+
countMessage: `${rulePass.returned} rule detections returned for the window by ${basisLabel}.`,
|
|
1155
|
+
});
|
|
1156
|
+
|
|
1157
|
+
phaseKey = "read-curated-detections";
|
|
1158
|
+
phaseName = `Read curated rule detections by ${basisLabel}`;
|
|
1159
|
+
phaseStartedMs = Date.now();
|
|
1160
|
+
|
|
1161
|
+
try {
|
|
1162
|
+
const curatedPass: CuratedPassOutcome =
|
|
1163
|
+
await GoogleSecOpsConnector.curatedPass(client, window, run, {
|
|
1164
|
+
bases: searchBases,
|
|
1165
|
+
});
|
|
1166
|
+
sourceCounts.curatedDetections = curatedPass.returned;
|
|
1167
|
+
curatedRulesWithDetections = curatedPass.rulesWithDetections;
|
|
1168
|
+
GoogleSecOpsConnector.recordPass({
|
|
1169
|
+
run,
|
|
1170
|
+
key: phaseKey,
|
|
1171
|
+
name: phaseName,
|
|
1172
|
+
startedMs: phaseStartedMs,
|
|
1173
|
+
outcome: curatedPass,
|
|
1174
|
+
countMessage: `${curatedPass.returned} curated rule detections returned for the window by ${basisLabel} (${curatedPass.rulesSearched} of ${curatedPass.rulesWithDetections} curated ${curatedPass.rulesWithDetections === 1 ? "rule" : "rules"} with recent detections searched${curatedPass.rulesUnreadable > 0 ? `, ${curatedPass.rulesUnreadable} could not be read` : ""}).`,
|
|
1175
|
+
});
|
|
1176
|
+
} catch (curatedError) {
|
|
1177
|
+
const status: number | null =
|
|
1178
|
+
GoogleSecOpsClient.readHttpStatus(curatedError);
|
|
1179
|
+
|
|
1180
|
+
if (status === null || !CURATED_OPTIONAL_STATUSES.includes(status)) {
|
|
1181
|
+
throw curatedError;
|
|
1182
|
+
}
|
|
1183
|
+
|
|
1184
|
+
run.warnings.push(
|
|
1185
|
+
`Curated rule detections could not be read (HTTP ${status}); this tenant may not have curated rule access. Rule detections and the alerts view were still read.`,
|
|
1186
|
+
);
|
|
1187
|
+
run.checks.push(
|
|
1188
|
+
makeCheck({
|
|
1189
|
+
key: phaseKey,
|
|
1190
|
+
name: phaseName,
|
|
1191
|
+
status: "warn",
|
|
1192
|
+
startedAtMs: phaseStartedMs,
|
|
1193
|
+
/*
|
|
1194
|
+
* Whole, like every failure check: a clamped 403 body would hide
|
|
1195
|
+
* the part of Google's answer that says which entitlement is
|
|
1196
|
+
* missing.
|
|
1197
|
+
*/
|
|
1198
|
+
message: redactLogString(
|
|
1199
|
+
ConnectorErrorMessage.toMessage(curatedError, {
|
|
1200
|
+
truncate: false,
|
|
1201
|
+
}),
|
|
1202
|
+
),
|
|
1203
|
+
remediation: CURATED_OPTIONAL_REMEDIATION,
|
|
1204
|
+
details: { httpStatus: status },
|
|
1205
|
+
}),
|
|
1206
|
+
);
|
|
1207
|
+
}
|
|
1208
|
+
|
|
1209
|
+
phaseKey = "read-alerts-view";
|
|
1210
|
+
phaseName = "Read alerts view by detection time";
|
|
1211
|
+
phaseStartedMs = Date.now();
|
|
1212
|
+
const alertsPass: PassOutcome = await GoogleSecOpsConnector.fetchWindows(
|
|
1213
|
+
client,
|
|
1214
|
+
window,
|
|
1215
|
+
run,
|
|
1216
|
+
{
|
|
1217
|
+
includeNonAlertingDetections: !alertingOnly,
|
|
1218
|
+
bestEffort: false,
|
|
1219
|
+
},
|
|
1220
|
+
);
|
|
1221
|
+
sourceCounts.alertsView = alertsPass.returned;
|
|
1222
|
+
GoogleSecOpsConnector.recordPass({
|
|
1223
|
+
run,
|
|
1224
|
+
key: phaseKey,
|
|
1225
|
+
name: phaseName,
|
|
1226
|
+
startedMs: phaseStartedMs,
|
|
1227
|
+
outcome: alertsPass,
|
|
1228
|
+
countMessage: `${alertsPass.returned} alerts returned by detection time.`,
|
|
1229
|
+
successMessage: `${alertsPass.returned} alerts returned by detection time. The configured Google SecOps instance is reachable and allows reading detections.`,
|
|
1230
|
+
});
|
|
1231
|
+
|
|
1232
|
+
const sweep: ConnectorFetchWindow | null = isHistorical
|
|
1233
|
+
? null
|
|
1234
|
+
: GoogleSecOpsConnector.lateAlertsWindow(window);
|
|
1235
|
+
|
|
1236
|
+
if (sweep) {
|
|
1237
|
+
await GoogleSecOpsConnector.sweepLateAlerts(
|
|
1238
|
+
client,
|
|
1239
|
+
sweep,
|
|
1240
|
+
run,
|
|
1241
|
+
sourceCounts,
|
|
1242
|
+
);
|
|
1243
|
+
}
|
|
1244
|
+
} catch (error) {
|
|
1245
|
+
run.checks.push(
|
|
1246
|
+
makeCheck({
|
|
1247
|
+
key: phaseKey,
|
|
1248
|
+
name: phaseName,
|
|
1249
|
+
status: "fail",
|
|
1250
|
+
startedAtMs: phaseStartedMs,
|
|
1251
|
+
message: redactLogString(
|
|
1252
|
+
ConnectorErrorMessage.toMessage(error, { truncate: false }),
|
|
1253
|
+
),
|
|
1254
|
+
}),
|
|
1255
|
+
);
|
|
1256
|
+
/*
|
|
1257
|
+
* What the passes that ran gathered goes with their checks, so the
|
|
1258
|
+
* failed run keeps their warnings, request and record counts, basis
|
|
1259
|
+
* and per-pass counts, as the retired poller's failed result did.
|
|
1260
|
+
* Creation lag is measured only over a finished read, so it is left
|
|
1261
|
+
* out here.
|
|
1262
|
+
*/
|
|
1263
|
+
throw attachConnectorFetchSummary(
|
|
1264
|
+
attachConnectorChecks(error, [...run.checks]),
|
|
1265
|
+
{
|
|
1266
|
+
warnings: [...run.warnings],
|
|
1267
|
+
requestCount: run.requestCount,
|
|
1268
|
+
fetchedCount: run.seen.size,
|
|
1269
|
+
details: {
|
|
1270
|
+
basis,
|
|
1271
|
+
sourceCounts: { ...sourceCounts },
|
|
1272
|
+
includeNonAlertingDetections: !alertingOnly,
|
|
1273
|
+
},
|
|
1274
|
+
},
|
|
1275
|
+
);
|
|
1276
|
+
}
|
|
1277
|
+
|
|
1278
|
+
const creationLag: CreationLag = GoogleSecOpsConnector.measureCreationLag(
|
|
1279
|
+
Array.from(run.seen.entries())
|
|
1280
|
+
.filter((entry: [string, JSONObject]): boolean => {
|
|
1281
|
+
return !run.sweptOnly.has(entry[0]);
|
|
1282
|
+
})
|
|
1283
|
+
.map((entry: [string, JSONObject]): JSONObject => {
|
|
1284
|
+
return entry[1];
|
|
1285
|
+
}),
|
|
1286
|
+
options.pollIntervalInMinutes,
|
|
1287
|
+
run.warnings,
|
|
1288
|
+
);
|
|
1289
|
+
|
|
1290
|
+
/*
|
|
1291
|
+
* Google's raw objects go to the normalizer untouched: a record with no
|
|
1292
|
+
* id is identified by a hash of its content, so anything added here
|
|
1293
|
+
* would re-import it under a new identifier.
|
|
1294
|
+
*/
|
|
1295
|
+
const events: Array<NormalizedSecurityEvent> = [];
|
|
1296
|
+
const samples: Array<SecurityConnectorSample> = [];
|
|
1297
|
+
const sampleLimit: number = Math.max(0, Math.floor(options.sampleLimit));
|
|
1298
|
+
let rejectedCount: number = 0;
|
|
1299
|
+
let failedCount: number = 0;
|
|
1300
|
+
let sweptFailedCount: number = 0;
|
|
1301
|
+
|
|
1302
|
+
for (const [key, alert] of run.seen.entries()) {
|
|
1303
|
+
try {
|
|
1304
|
+
if (!GoogleSecOpsAlertNormalizer.isGoogleSecOpsAlert(alert)) {
|
|
1305
|
+
rejectedCount++;
|
|
1306
|
+
continue;
|
|
1307
|
+
}
|
|
1308
|
+
|
|
1309
|
+
const event: NormalizedSecurityEvent =
|
|
1310
|
+
GoogleSecOpsAlertNormalizer.normalize(alert);
|
|
1311
|
+
events.push(event);
|
|
1312
|
+
|
|
1313
|
+
if (samples.length < sampleLimit) {
|
|
1314
|
+
samples.push(GoogleSecOpsConnector.toSample(alert, event));
|
|
1315
|
+
}
|
|
1316
|
+
} catch {
|
|
1317
|
+
/*
|
|
1318
|
+
* A failure makes the fetch incomplete so the poller narrows and
|
|
1319
|
+
* retries the window. A record only the late-alert sweep found sits
|
|
1320
|
+
* behind the window, and the sweep returns it on every poll for a
|
|
1321
|
+
* day, so counting it would pin polling to narrowing for that day.
|
|
1322
|
+
* It is reported instead.
|
|
1323
|
+
*/
|
|
1324
|
+
if (run.sweptOnly.has(key)) {
|
|
1325
|
+
sweptFailedCount++;
|
|
1326
|
+
} else {
|
|
1327
|
+
failedCount++;
|
|
1328
|
+
}
|
|
1329
|
+
}
|
|
1330
|
+
}
|
|
1331
|
+
|
|
1332
|
+
if (sweptFailedCount > 0) {
|
|
1333
|
+
run.warnings.push(
|
|
1334
|
+
`${sweptFailedCount} alerts found by the late-alert sweep could not be normalized and were not imported.`,
|
|
1335
|
+
);
|
|
1336
|
+
}
|
|
1337
|
+
|
|
1338
|
+
return {
|
|
1339
|
+
events,
|
|
1340
|
+
fetchedCount: run.seen.size,
|
|
1341
|
+
rejectedCount,
|
|
1342
|
+
failedCount,
|
|
1343
|
+
complete: run.complete,
|
|
1344
|
+
requestCount: run.requestCount,
|
|
1345
|
+
warnings: run.warnings,
|
|
1346
|
+
samples,
|
|
1347
|
+
checks: run.checks,
|
|
1348
|
+
details: {
|
|
1349
|
+
basis,
|
|
1350
|
+
sourceCounts,
|
|
1351
|
+
curatedRulesWithDetections,
|
|
1352
|
+
creationLag: { ...creationLag },
|
|
1353
|
+
includeNonAlertingDetections: !alertingOnly,
|
|
1354
|
+
},
|
|
1355
|
+
};
|
|
1356
|
+
}
|
|
1357
|
+
|
|
1358
|
+
// A positive finite bound, floored; anything else falls back.
|
|
1359
|
+
private static readBound(
|
|
1360
|
+
value: number | undefined,
|
|
1361
|
+
fallback: number,
|
|
1362
|
+
): number {
|
|
1363
|
+
if (typeof value !== "number" || !Number.isFinite(value) || value < 1) {
|
|
1364
|
+
return fallback;
|
|
1365
|
+
}
|
|
1366
|
+
|
|
1367
|
+
return Math.floor(value);
|
|
1368
|
+
}
|
|
1369
|
+
|
|
1370
|
+
/*
|
|
1371
|
+
* One check per read pass. A pass a budget stopped part way is a warning
|
|
1372
|
+
* naming the budget, never a success: a green step that did not read its
|
|
1373
|
+
* window hid which data went unread. A pass a budget never let start is
|
|
1374
|
+
* skipped, with the budget in its message and in the run's warnings.
|
|
1375
|
+
*/
|
|
1376
|
+
private static recordPass(data: {
|
|
1377
|
+
run: FetchRun;
|
|
1378
|
+
key: string;
|
|
1379
|
+
name: string;
|
|
1380
|
+
startedMs: number;
|
|
1381
|
+
outcome: PassOutcome;
|
|
1382
|
+
// What the pass returned; the whole message when it read everything.
|
|
1383
|
+
countMessage: string;
|
|
1384
|
+
// Replaces countMessage when the pass read everything, if given.
|
|
1385
|
+
successMessage?: string | undefined;
|
|
1386
|
+
}): void {
|
|
1387
|
+
const outcome: PassOutcome = data.outcome;
|
|
1388
|
+
let status: SecurityConnectorCheckStatus = "pass";
|
|
1389
|
+
let message: string = data.successMessage || data.countMessage;
|
|
1390
|
+
|
|
1391
|
+
if (outcome.stoppedBy === "time" && outcome.requests === 0) {
|
|
1392
|
+
status = "skip";
|
|
1393
|
+
message = "Not run: the poll time budget was spent.";
|
|
1394
|
+
this.addWarning(
|
|
1395
|
+
data.run,
|
|
1396
|
+
`${data.name} was not run: the poll time budget was spent.`,
|
|
1397
|
+
);
|
|
1398
|
+
} else if (outcome.stoppedBy) {
|
|
1399
|
+
const stop: string = `stopped by the ${this.budgetName(outcome.stoppedBy)} after ${outcome.requests} ${outcome.requests === 1 ? "request" : "requests"}`;
|
|
1400
|
+
|
|
1401
|
+
if (outcome.requests === 0) {
|
|
1402
|
+
status = "skip";
|
|
1403
|
+
message = `Not run: ${stop}. ${this.notRunReason(outcome.stoppedBy)}`;
|
|
1404
|
+
} else {
|
|
1405
|
+
status = "warn";
|
|
1406
|
+
message = `${data.countMessage} The pass was ${stop}.`;
|
|
1407
|
+
}
|
|
1408
|
+
|
|
1409
|
+
this.addWarning(data.run, `${data.name} was ${stop}.`);
|
|
1410
|
+
} else if (outcome.leftUnread) {
|
|
1411
|
+
status = "warn";
|
|
1412
|
+
message = `${data.countMessage} Google did not return part of the window.`;
|
|
1413
|
+
}
|
|
1414
|
+
|
|
1415
|
+
data.run.checks.push(
|
|
1416
|
+
makeCheck({
|
|
1417
|
+
key: data.key,
|
|
1418
|
+
name: data.name,
|
|
1419
|
+
status,
|
|
1420
|
+
startedAtMs: data.startedMs,
|
|
1421
|
+
message,
|
|
1422
|
+
}),
|
|
1423
|
+
);
|
|
1424
|
+
}
|
|
1425
|
+
|
|
1426
|
+
private static budgetName(stop: Exclude<PassStop, null>): string {
|
|
1427
|
+
if (stop === "time") {
|
|
1428
|
+
return "poll time budget";
|
|
1429
|
+
}
|
|
1430
|
+
|
|
1431
|
+
if (stop === "total") {
|
|
1432
|
+
return "per-run request limit";
|
|
1433
|
+
}
|
|
1434
|
+
|
|
1435
|
+
if (stop === "events") {
|
|
1436
|
+
return "per-run record limit";
|
|
1437
|
+
}
|
|
1438
|
+
|
|
1439
|
+
return "request budget";
|
|
1440
|
+
}
|
|
1441
|
+
|
|
1442
|
+
private static notRunReason(stop: Exclude<PassStop, null>): string {
|
|
1443
|
+
if (stop === "total") {
|
|
1444
|
+
return "The earlier passes used every request this run allows.";
|
|
1445
|
+
}
|
|
1446
|
+
|
|
1447
|
+
if (stop === "events") {
|
|
1448
|
+
return "The earlier passes collected every record this run allows.";
|
|
1449
|
+
}
|
|
1450
|
+
|
|
1451
|
+
// Only a pass that shares its budget can find it spent before it starts.
|
|
1452
|
+
return "The passes that share this request budget spent it before this pass started.";
|
|
1453
|
+
}
|
|
1454
|
+
|
|
1455
|
+
/*
|
|
1456
|
+
* The late-alert sweep of a scheduled poll: the day before the window's
|
|
1457
|
+
* start, ending where the window's own alerts-view read begins. Null when
|
|
1458
|
+
* the window already reaches that far back (a first poll reads a whole
|
|
1459
|
+
* day).
|
|
1460
|
+
*/
|
|
1461
|
+
private static lateAlertsWindow(
|
|
1462
|
+
window: ConnectorFetchWindow,
|
|
1463
|
+
): ConnectorFetchWindow | null {
|
|
1464
|
+
const startTime: Date = new Date(
|
|
1465
|
+
window.endTime.getTime() -
|
|
1466
|
+
GOOGLE_SECOPS_LATE_ALERTS_LOOKBACK_IN_MINUTES * MINUTE_IN_MS,
|
|
1467
|
+
);
|
|
1468
|
+
|
|
1469
|
+
if (startTime.getTime() >= window.startTime.getTime()) {
|
|
1470
|
+
return null;
|
|
1471
|
+
}
|
|
1472
|
+
|
|
1473
|
+
return { startTime, endTime: window.startTime };
|
|
1474
|
+
}
|
|
1475
|
+
|
|
1476
|
+
/*
|
|
1477
|
+
* Runs the sweep and records it as its own check. Best effort all the
|
|
1478
|
+
* way: a sweep Google rejects, truncates or times out is a warning on the
|
|
1479
|
+
* run, never a failed or incomplete poll, because the window it reads was
|
|
1480
|
+
* already completed by earlier polls and holding the cursor for it would
|
|
1481
|
+
* re-read the same day forever.
|
|
1482
|
+
*/
|
|
1483
|
+
private static async sweepLateAlerts(
|
|
1484
|
+
client: GoogleSecOpsClient,
|
|
1485
|
+
sweep: ConnectorFetchWindow,
|
|
1486
|
+
run: FetchRun,
|
|
1487
|
+
sourceCounts: { lateAlertsView?: number | undefined },
|
|
1488
|
+
): Promise<void> {
|
|
1489
|
+
const key: string = "read-late-alerts-view";
|
|
1490
|
+
const name: string = "Read late alerts by detection time";
|
|
1491
|
+
const startedMs: number = Date.now();
|
|
1492
|
+
|
|
1493
|
+
try {
|
|
1494
|
+
const outcome: PassOutcome = await this.fetchWindows(client, sweep, run, {
|
|
1495
|
+
/*
|
|
1496
|
+
* Alerts only: non-alerting rule and curated detections are read by
|
|
1497
|
+
* created time, so the sweep only looks for what the alerts view
|
|
1498
|
+
* alone can see, without re-reading every detection of the past day
|
|
1499
|
+
* on every poll.
|
|
1500
|
+
*/
|
|
1501
|
+
includeNonAlertingDetections: false,
|
|
1502
|
+
bestEffort: true,
|
|
1503
|
+
});
|
|
1504
|
+
sourceCounts.lateAlertsView = outcome.returned;
|
|
1505
|
+
this.recordPass({
|
|
1506
|
+
run,
|
|
1507
|
+
key,
|
|
1508
|
+
name,
|
|
1509
|
+
startedMs,
|
|
1510
|
+
outcome,
|
|
1511
|
+
/*
|
|
1512
|
+
* The sweep's own range, not the lookback constant: a catch-up poll's
|
|
1513
|
+
* window already covers part of the day, so its sweep is shorter.
|
|
1514
|
+
*/
|
|
1515
|
+
countMessage: `${outcome.returned} alerts returned with a detection time from ${sweep.startTime.toISOString()} to ${sweep.endTime.toISOString()}, before the window, so alerts Google made readable after their detection time are imported.`,
|
|
1516
|
+
});
|
|
1517
|
+
} catch (error) {
|
|
1518
|
+
const message: string = redactLogString(
|
|
1519
|
+
ConnectorErrorMessage.toMessage(error, { truncate: false }),
|
|
1520
|
+
);
|
|
1521
|
+
|
|
1522
|
+
this.addWarning(
|
|
1523
|
+
run,
|
|
1524
|
+
`The late-alert sweep of the alerts view could not be read, so alerts Google made readable more than one poll after their detection time may be missing from this poll: ${message}`,
|
|
1525
|
+
);
|
|
1526
|
+
run.checks.push(
|
|
1527
|
+
makeCheck({
|
|
1528
|
+
key,
|
|
1529
|
+
name,
|
|
1530
|
+
status: "warn",
|
|
1531
|
+
startedAtMs: startedMs,
|
|
1532
|
+
message,
|
|
1533
|
+
remediation:
|
|
1534
|
+
"Polling continues and later polls sweep the same day again. If this repeats, check the alerts view permission and Chronicle quota for the service account.",
|
|
1535
|
+
}),
|
|
1536
|
+
);
|
|
1537
|
+
}
|
|
1538
|
+
}
|
|
1539
|
+
|
|
1540
|
+
/*
|
|
1541
|
+
* The curated pass. legacySearchCuratedDetections takes one curated rule
|
|
1542
|
+
* id and no wildcard, so the pass first asks
|
|
1543
|
+
* countAllCuratedRuleSetDetections which curated rules produced
|
|
1544
|
+
* detections from a week before the window to its end, then searches each
|
|
1545
|
+
* of those rules over the window, one basis at a time, following
|
|
1546
|
+
* nextPageToken under the curated budget. A curated rule the search can
|
|
1547
|
+
* no longer find (a 400, 403 or 404 for that rule alone) is a warning, and
|
|
1548
|
+
* the remaining rules are still read.
|
|
1549
|
+
*/
|
|
1550
|
+
private static async curatedPass(
|
|
1551
|
+
client: GoogleSecOpsClient,
|
|
1552
|
+
window: ConnectorFetchWindow,
|
|
1553
|
+
run: FetchRun,
|
|
1554
|
+
options: { bases: Array<GoogleSecOpsListBasis> },
|
|
1555
|
+
): Promise<CuratedPassOutcome> {
|
|
1556
|
+
const outcome: CuratedPassOutcome = {
|
|
1557
|
+
returned: 0,
|
|
1558
|
+
requests: 0,
|
|
1559
|
+
stoppedBy: null,
|
|
1560
|
+
leftUnread: false,
|
|
1561
|
+
rulesWithDetections: 0,
|
|
1562
|
+
rulesSearched: 0,
|
|
1563
|
+
rulesUnreadable: 0,
|
|
1564
|
+
rulesNotStarted: 0,
|
|
1565
|
+
};
|
|
1566
|
+
const countStop: PassStop = this.budgetStop(
|
|
1567
|
+
run,
|
|
1568
|
+
run.curatedRequests,
|
|
1569
|
+
GOOGLE_SECOPS_CURATED_REQUEST_BUDGET,
|
|
1570
|
+
);
|
|
1571
|
+
|
|
1572
|
+
if (countStop) {
|
|
1573
|
+
outcome.stoppedBy = countStop;
|
|
1574
|
+
run.complete = false;
|
|
1575
|
+
return outcome;
|
|
1576
|
+
}
|
|
1577
|
+
|
|
1578
|
+
run.curatedRequests++;
|
|
1579
|
+
outcome.requests++;
|
|
1580
|
+
run.requestCount++;
|
|
1581
|
+
|
|
1582
|
+
const rules: Array<CuratedRuleDetectionCount> =
|
|
1583
|
+
await client.countCuratedRuleDetections({
|
|
1584
|
+
startTime: new Date(
|
|
1585
|
+
window.startTime.getTime() -
|
|
1586
|
+
GOOGLE_SECOPS_CURATED_DISCOVERY_LOOKBACK_IN_MINUTES * MINUTE_IN_MS,
|
|
1587
|
+
),
|
|
1588
|
+
endTime: window.endTime,
|
|
1589
|
+
});
|
|
1590
|
+
outcome.rulesWithDetections = rules.length;
|
|
1591
|
+
|
|
1592
|
+
/*
|
|
1593
|
+
* Busiest first: when a poll cannot search every active curated rule,
|
|
1594
|
+
* the rules most likely to have created something new are the ones read.
|
|
1595
|
+
*/
|
|
1596
|
+
const ordered: Array<CuratedRuleDetectionCount> = [...rules].sort(
|
|
1597
|
+
(a: CuratedRuleDetectionCount, b: CuratedRuleDetectionCount): number => {
|
|
1598
|
+
return b.count - a.count || (a.ruleId < b.ruleId ? -1 : 1);
|
|
1599
|
+
},
|
|
1600
|
+
);
|
|
1601
|
+
|
|
1602
|
+
for (let index: number = 0; index < ordered.length; index++) {
|
|
1603
|
+
const rule: CuratedRuleDetectionCount = ordered[
|
|
1604
|
+
index
|
|
1605
|
+
] as CuratedRuleDetectionCount;
|
|
1606
|
+
const requestsBefore: number = run.curatedRequests;
|
|
1607
|
+
/*
|
|
1608
|
+
* Checked at the rule boundary, before searchPass would mark the fetch
|
|
1609
|
+
* incomplete. The poller answers an incomplete fetch by narrowing the
|
|
1610
|
+
* window, and a narrower window still has every one of these rules to
|
|
1611
|
+
* search, so a boundary stop would pin polling to one-minute forced
|
|
1612
|
+
* advances. It is reported instead: those rules' detections in this
|
|
1613
|
+
* window are not read, and the warning says how many.
|
|
1614
|
+
*/
|
|
1615
|
+
const boundaryStop: PassStop =
|
|
1616
|
+
this.budgetStop(
|
|
1617
|
+
run,
|
|
1618
|
+
run.curatedRequests,
|
|
1619
|
+
GOOGLE_SECOPS_CURATED_REQUEST_BUDGET,
|
|
1620
|
+
) ||
|
|
1621
|
+
(Date.now() - run.startedMs >=
|
|
1622
|
+
run.maxDurationMs * CURATED_PASS_TIME_SHARE
|
|
1623
|
+
? "time"
|
|
1624
|
+
: null);
|
|
1625
|
+
|
|
1626
|
+
if (boundaryStop) {
|
|
1627
|
+
outcome.stoppedBy = boundaryStop;
|
|
1628
|
+
outcome.rulesNotStarted = ordered.length - index;
|
|
1629
|
+
outcome.leftUnread = true;
|
|
1630
|
+
this.addWarning(
|
|
1631
|
+
run,
|
|
1632
|
+
`${outcome.rulesNotStarted} of ${ordered.length} curated rules with recent detections were not searched in this poll because the curated pass reached the ${this.budgetName(boundaryStop)}; their detections created in this window were not imported. The rules with the most detections were searched first.`,
|
|
1633
|
+
);
|
|
1634
|
+
break;
|
|
1635
|
+
}
|
|
1636
|
+
|
|
1637
|
+
try {
|
|
1638
|
+
const rulePass: PassOutcome = await this.searchPass(
|
|
1639
|
+
client,
|
|
1640
|
+
window,
|
|
1641
|
+
run,
|
|
1642
|
+
{ bases: options.bases, curatedRuleId: rule.ruleId },
|
|
1643
|
+
);
|
|
1644
|
+
outcome.returned += rulePass.returned;
|
|
1645
|
+
outcome.leftUnread = outcome.leftUnread || rulePass.leftUnread;
|
|
1646
|
+
|
|
1647
|
+
if (rulePass.stoppedBy) {
|
|
1648
|
+
outcome.stoppedBy = rulePass.stoppedBy;
|
|
1649
|
+
}
|
|
1650
|
+
} catch (error) {
|
|
1651
|
+
const status: number | null = GoogleSecOpsClient.readHttpStatus(error);
|
|
1652
|
+
|
|
1653
|
+
if (status === null || !CURATED_OPTIONAL_STATUSES.includes(status)) {
|
|
1654
|
+
throw error;
|
|
1655
|
+
}
|
|
1656
|
+
|
|
1657
|
+
/*
|
|
1658
|
+
* Not a reason to hold the cursor (re-reading will not make the rule
|
|
1659
|
+
* readable), but never a green check either: that rule's detections
|
|
1660
|
+
* were not read.
|
|
1661
|
+
*/
|
|
1662
|
+
outcome.rulesUnreadable++;
|
|
1663
|
+
outcome.leftUnread = true;
|
|
1664
|
+
this.addWarning(
|
|
1665
|
+
run,
|
|
1666
|
+
`Detections of curated rule ${rule.ruleId} could not be read (HTTP ${status}); the other curated rules were still read.`,
|
|
1667
|
+
);
|
|
1668
|
+
} finally {
|
|
1669
|
+
outcome.requests = run.curatedRequests;
|
|
1670
|
+
|
|
1671
|
+
if (run.curatedRequests > requestsBefore) {
|
|
1672
|
+
outcome.rulesSearched++;
|
|
1673
|
+
}
|
|
1674
|
+
}
|
|
1675
|
+
|
|
1676
|
+
if (outcome.stoppedBy) {
|
|
1677
|
+
break;
|
|
1678
|
+
}
|
|
1679
|
+
}
|
|
1680
|
+
|
|
1681
|
+
return outcome;
|
|
1682
|
+
}
|
|
1683
|
+
|
|
1684
|
+
/*
|
|
1685
|
+
* The alerts-view pass (legacyFetchAlertsView, detection time). The
|
|
1686
|
+
* endpoint has no pagination, so a truncated window is split in half and
|
|
1687
|
+
* both halves are re-read until they fit or the alerts-view budget runs
|
|
1688
|
+
* out. A best-effort read (the late-alert sweep) reads the newest half
|
|
1689
|
+
* first, so a budget that runs out leaves the oldest alerts unread, and it
|
|
1690
|
+
* never makes the fetch incomplete.
|
|
1691
|
+
*/
|
|
1692
|
+
private static async fetchWindows(
|
|
1693
|
+
client: GoogleSecOpsClient,
|
|
1694
|
+
window: ConnectorFetchWindow,
|
|
1695
|
+
run: FetchRun,
|
|
1696
|
+
options: AlertsViewReadOptions,
|
|
1697
|
+
): Promise<PassOutcome> {
|
|
1698
|
+
const outcome: PassOutcome = {
|
|
1699
|
+
returned: 0,
|
|
1700
|
+
requests: 0,
|
|
1701
|
+
stoppedBy: null,
|
|
1702
|
+
leftUnread: false,
|
|
1703
|
+
};
|
|
1704
|
+
const pending: Array<{ startTime: Date; endTime: Date }> = [
|
|
1705
|
+
{ startTime: window.startTime, endTime: window.endTime },
|
|
1706
|
+
];
|
|
1707
|
+
let splits: number = 0;
|
|
1708
|
+
|
|
1709
|
+
while (pending.length > 0) {
|
|
1710
|
+
const stop: PassStop = this.budgetStop(
|
|
1711
|
+
run,
|
|
1712
|
+
run.alertsViewRequests,
|
|
1713
|
+
GOOGLE_SECOPS_ALERTS_VIEW_REQUEST_BUDGET,
|
|
1714
|
+
);
|
|
1715
|
+
|
|
1716
|
+
if (stop) {
|
|
1717
|
+
outcome.stoppedBy = stop;
|
|
1718
|
+
|
|
1719
|
+
if (!options.bestEffort) {
|
|
1720
|
+
run.complete = false;
|
|
1721
|
+
}
|
|
1722
|
+
|
|
1723
|
+
break;
|
|
1724
|
+
}
|
|
1725
|
+
|
|
1726
|
+
const current: { startTime: Date; endTime: Date } = pending.shift()!;
|
|
1727
|
+
run.alertsViewRequests++;
|
|
1728
|
+
outcome.requests++;
|
|
1729
|
+
run.requestCount++;
|
|
1730
|
+
|
|
1731
|
+
const fetched: FetchAlertsResult = await client.fetchDetectionAlerts({
|
|
1732
|
+
startTime: current.startTime,
|
|
1733
|
+
endTime: current.endTime,
|
|
1734
|
+
maxAlerts: MAX_ALERTS_PER_REQUEST,
|
|
1735
|
+
includeNonAlertingDetections: options.includeNonAlertingDetections,
|
|
1736
|
+
});
|
|
1737
|
+
outcome.returned += fetched.alerts.length;
|
|
1738
|
+
|
|
1739
|
+
if (!this.collectAll(run, fetched.alerts, options.bestEffort)) {
|
|
1740
|
+
outcome.stoppedBy = "events";
|
|
1741
|
+
break;
|
|
1742
|
+
}
|
|
1743
|
+
|
|
1744
|
+
const truncated: boolean =
|
|
1745
|
+
fetched.truncatedByCount ||
|
|
1746
|
+
fetched.truncatedByBytes ||
|
|
1747
|
+
Math.max(fetched.filteredAlertsCount, fetched.baselineAlertsCount) >
|
|
1748
|
+
fetched.alerts.length;
|
|
1749
|
+
const midpoint: number = Math.floor(
|
|
1750
|
+
(current.startTime.getTime() + current.endTime.getTime()) / 2,
|
|
1751
|
+
);
|
|
1752
|
+
|
|
1753
|
+
if (
|
|
1754
|
+
truncated &&
|
|
1755
|
+
current.endTime.getTime() - current.startTime.getTime() >
|
|
1756
|
+
MIN_SPLIT_WINDOW_IN_MS
|
|
1757
|
+
) {
|
|
1758
|
+
splits++;
|
|
1759
|
+
const older: { startTime: Date; endTime: Date } = {
|
|
1760
|
+
startTime: current.startTime,
|
|
1761
|
+
endTime: new Date(midpoint),
|
|
1762
|
+
};
|
|
1763
|
+
const newer: { startTime: Date; endTime: Date } = {
|
|
1764
|
+
startTime: new Date(midpoint),
|
|
1765
|
+
endTime: current.endTime,
|
|
1766
|
+
};
|
|
1767
|
+
|
|
1768
|
+
if (options.bestEffort) {
|
|
1769
|
+
pending.unshift(newer, older);
|
|
1770
|
+
} else {
|
|
1771
|
+
pending.unshift(older, newer);
|
|
1772
|
+
}
|
|
1773
|
+
} else if (!fetched.complete || truncated) {
|
|
1774
|
+
if (!options.bestEffort) {
|
|
1775
|
+
run.complete = false;
|
|
1776
|
+
}
|
|
1777
|
+
|
|
1778
|
+
outcome.leftUnread = true;
|
|
1779
|
+
this.addWarning(
|
|
1780
|
+
run,
|
|
1781
|
+
truncated
|
|
1782
|
+
? "Google still truncated a one-second window of the alerts view, so some alerts in it were not read."
|
|
1783
|
+
: "Google ended an alerts view response without confirming it was complete.",
|
|
1784
|
+
);
|
|
1785
|
+
}
|
|
1786
|
+
}
|
|
1787
|
+
|
|
1788
|
+
if (splits > 0) {
|
|
1789
|
+
// One line rather than one per split: lastError joins every warning.
|
|
1790
|
+
run.warnings.push(
|
|
1791
|
+
`Google limited the alerts view response for ${window.startTime.toISOString()} to ${window.endTime.toISOString()}, so it was split into smaller windows ${splits} ${splits === 1 ? "time" : "times"}.`,
|
|
1792
|
+
);
|
|
1793
|
+
}
|
|
1794
|
+
|
|
1795
|
+
return outcome;
|
|
1796
|
+
}
|
|
1797
|
+
|
|
1798
|
+
/*
|
|
1799
|
+
* A detections search, one basis at a time, following nextPageToken:
|
|
1800
|
+
* every rule through legacySearchDetections under the rule page budget,
|
|
1801
|
+
* or one curated rule through legacySearchCuratedDetections under the
|
|
1802
|
+
* curated budget.
|
|
1803
|
+
*/
|
|
1804
|
+
private static async searchPass(
|
|
1805
|
+
client: GoogleSecOpsClient,
|
|
1806
|
+
window: ConnectorFetchWindow,
|
|
1807
|
+
run: FetchRun,
|
|
1808
|
+
options: {
|
|
1809
|
+
bases: Array<GoogleSecOpsListBasis>;
|
|
1810
|
+
curatedRuleId?: string | undefined;
|
|
1811
|
+
},
|
|
1812
|
+
): Promise<PassOutcome> {
|
|
1813
|
+
const curated: boolean = Boolean(options.curatedRuleId);
|
|
1814
|
+
const label: string = curated
|
|
1815
|
+
? "curated rule detections"
|
|
1816
|
+
: "rule detections";
|
|
1817
|
+
const outcome: PassOutcome = {
|
|
1818
|
+
returned: 0,
|
|
1819
|
+
requests: 0,
|
|
1820
|
+
stoppedBy: null,
|
|
1821
|
+
leftUnread: false,
|
|
1822
|
+
};
|
|
1823
|
+
|
|
1824
|
+
for (const listBasis of options.bases) {
|
|
1825
|
+
let pageToken: string | undefined = undefined;
|
|
1826
|
+
|
|
1827
|
+
do {
|
|
1828
|
+
const stop: PassStop = curated
|
|
1829
|
+
? this.budgetStop(
|
|
1830
|
+
run,
|
|
1831
|
+
run.curatedRequests,
|
|
1832
|
+
GOOGLE_SECOPS_CURATED_REQUEST_BUDGET,
|
|
1833
|
+
)
|
|
1834
|
+
: this.budgetStop(
|
|
1835
|
+
run,
|
|
1836
|
+
run.searchRequests,
|
|
1837
|
+
GOOGLE_SECOPS_SEARCH_PAGE_BUDGET,
|
|
1838
|
+
);
|
|
1839
|
+
|
|
1840
|
+
if (stop) {
|
|
1841
|
+
outcome.stoppedBy = stop;
|
|
1842
|
+
run.complete = false;
|
|
1843
|
+
return outcome;
|
|
1844
|
+
}
|
|
1845
|
+
|
|
1846
|
+
if (curated) {
|
|
1847
|
+
run.curatedRequests++;
|
|
1848
|
+
} else {
|
|
1849
|
+
run.searchRequests++;
|
|
1850
|
+
}
|
|
1851
|
+
|
|
1852
|
+
outcome.requests++;
|
|
1853
|
+
run.requestCount++;
|
|
1854
|
+
|
|
1855
|
+
const page: SearchDetectionsResult = await client.searchDetections({
|
|
1856
|
+
startTime: window.startTime,
|
|
1857
|
+
endTime: window.endTime,
|
|
1858
|
+
listBasis,
|
|
1859
|
+
alertingOnly: run.alertingOnly,
|
|
1860
|
+
pageSize: MAX_SEARCH_PAGE_SIZE,
|
|
1861
|
+
pageToken,
|
|
1862
|
+
curated,
|
|
1863
|
+
...(curated ? { ruleId: options.curatedRuleId } : {}),
|
|
1864
|
+
});
|
|
1865
|
+
outcome.returned += page.detections.length;
|
|
1866
|
+
|
|
1867
|
+
if (!this.collectAll(run, page.detections)) {
|
|
1868
|
+
outcome.stoppedBy = "events";
|
|
1869
|
+
return outcome;
|
|
1870
|
+
}
|
|
1871
|
+
|
|
1872
|
+
if (page.truncated) {
|
|
1873
|
+
/*
|
|
1874
|
+
* respTooLargeDetectionsTruncated: Google cut the page by byte
|
|
1875
|
+
* size and the rest is not reachable through a page token, so the
|
|
1876
|
+
* window is not fully read.
|
|
1877
|
+
*/
|
|
1878
|
+
run.complete = false;
|
|
1879
|
+
outcome.leftUnread = true;
|
|
1880
|
+
this.addWarning(
|
|
1881
|
+
run,
|
|
1882
|
+
`Google truncated a page of ${label} by size for ${window.startTime.toISOString()} to ${window.endTime.toISOString()}, so part of the window was not read.`,
|
|
1883
|
+
);
|
|
1884
|
+
}
|
|
1885
|
+
|
|
1886
|
+
pageToken = page.nextPageToken || undefined;
|
|
1887
|
+
} while (pageToken);
|
|
1888
|
+
}
|
|
1889
|
+
|
|
1890
|
+
return outcome;
|
|
1891
|
+
}
|
|
1892
|
+
|
|
1893
|
+
/*
|
|
1894
|
+
* Whether a pass may make another request: each kind of read has its own
|
|
1895
|
+
* request count, the fetch has a total request and record bound, and all
|
|
1896
|
+
* of them share the fetch's wall-clock bound so a slow endpoint cannot
|
|
1897
|
+
* run the worker job into its timeout.
|
|
1898
|
+
*/
|
|
1899
|
+
private static budgetStop(
|
|
1900
|
+
run: FetchRun,
|
|
1901
|
+
used: number,
|
|
1902
|
+
limit: number,
|
|
1903
|
+
): PassStop {
|
|
1904
|
+
if (used >= limit) {
|
|
1905
|
+
return "requests";
|
|
1906
|
+
}
|
|
1907
|
+
|
|
1908
|
+
if (run.requestCount >= run.maxRequests) {
|
|
1909
|
+
return "total";
|
|
1910
|
+
}
|
|
1911
|
+
|
|
1912
|
+
if (run.eventLimitHit || run.seen.size >= run.maxEvents) {
|
|
1913
|
+
return "events";
|
|
1914
|
+
}
|
|
1915
|
+
|
|
1916
|
+
if (Date.now() - run.startedMs >= run.maxDurationMs) {
|
|
1917
|
+
return "time";
|
|
1918
|
+
}
|
|
1919
|
+
|
|
1920
|
+
return null;
|
|
1921
|
+
}
|
|
1922
|
+
|
|
1923
|
+
// Repeated conditions (every one-second window, every page) are said once.
|
|
1924
|
+
private static addWarning(run: FetchRun, warning: string): void {
|
|
1925
|
+
if (!run.warnings.includes(warning)) {
|
|
1926
|
+
run.warnings.push(warning);
|
|
1927
|
+
}
|
|
1928
|
+
}
|
|
1929
|
+
|
|
1930
|
+
/*
|
|
1931
|
+
* Collects one response's records. False when the record bound dropped
|
|
1932
|
+
* at least one new record; records already collected are still refreshed,
|
|
1933
|
+
* since they do not grow the union.
|
|
1934
|
+
*/
|
|
1935
|
+
private static collectAll(
|
|
1936
|
+
run: FetchRun,
|
|
1937
|
+
records: Array<JSONObject>,
|
|
1938
|
+
bestEffort: boolean = false,
|
|
1939
|
+
): boolean {
|
|
1940
|
+
let kept: boolean = true;
|
|
1941
|
+
|
|
1942
|
+
for (const record of records) {
|
|
1943
|
+
if (!this.collect(run, record, bestEffort)) {
|
|
1944
|
+
kept = false;
|
|
1945
|
+
}
|
|
1946
|
+
}
|
|
1947
|
+
|
|
1948
|
+
return kept;
|
|
1949
|
+
}
|
|
1950
|
+
|
|
1951
|
+
/*
|
|
1952
|
+
* Union by Collection.id across passes and across the alerts view's
|
|
1953
|
+
* chunks; a record with no id falls back to a content hash, and an
|
|
1954
|
+
* object that cannot even be inspected is kept under a positional key so
|
|
1955
|
+
* it is counted as rejected without hiding the valid records beside it.
|
|
1956
|
+
* A best-effort read that reaches the record bound stops without making
|
|
1957
|
+
* the fetch incomplete, and what it alone found is marked as swept.
|
|
1958
|
+
*/
|
|
1959
|
+
private static collect(
|
|
1960
|
+
run: FetchRun,
|
|
1961
|
+
record: JSONObject,
|
|
1962
|
+
bestEffort: boolean = false,
|
|
1963
|
+
): boolean {
|
|
1964
|
+
let key: string;
|
|
1965
|
+
|
|
1966
|
+
try {
|
|
1967
|
+
key = readString(record, "id") || contentHashEventUid(record);
|
|
1968
|
+
} catch {
|
|
1969
|
+
key = `malformed:${run.requestCount}:${run.seen.size}`;
|
|
1970
|
+
}
|
|
1971
|
+
|
|
1972
|
+
if (!run.seen.has(key) && run.seen.size >= run.maxEvents) {
|
|
1973
|
+
/*
|
|
1974
|
+
* A best-effort read stops itself here, but must not mark the run:
|
|
1975
|
+
* eventLimitHit stops every later pass outright, and complete=false
|
|
1976
|
+
* would have the poller narrow a window that is not what filled the
|
|
1977
|
+
* record bound.
|
|
1978
|
+
*/
|
|
1979
|
+
if (!bestEffort) {
|
|
1980
|
+
run.eventLimitHit = true;
|
|
1981
|
+
run.complete = false;
|
|
1982
|
+
}
|
|
1983
|
+
|
|
1984
|
+
return false;
|
|
1985
|
+
}
|
|
1986
|
+
|
|
1987
|
+
if (bestEffort && !run.seen.has(key)) {
|
|
1988
|
+
run.sweptOnly.add(key);
|
|
1989
|
+
}
|
|
1990
|
+
|
|
1991
|
+
run.seen.set(key, record);
|
|
1992
|
+
return true;
|
|
1993
|
+
}
|
|
1994
|
+
|
|
1995
|
+
/*
|
|
1996
|
+
* createdTime minus detectionTime over what was fetched. A lag beyond one
|
|
1997
|
+
* poll interval is the record a detection-time cursor skips, so the
|
|
1998
|
+
* warning names the reason polling reads created time.
|
|
1999
|
+
*/
|
|
2000
|
+
private static measureCreationLag(
|
|
2001
|
+
alerts: Array<JSONObject>,
|
|
2002
|
+
pollIntervalInMinutes: number | undefined,
|
|
2003
|
+
warnings: Array<string>,
|
|
2004
|
+
): CreationLag {
|
|
2005
|
+
const intervalInMinutes: number = Math.max(
|
|
2006
|
+
1,
|
|
2007
|
+
pollIntervalInMinutes || DEFAULT_POLL_INTERVAL_IN_MINUTES,
|
|
2008
|
+
);
|
|
2009
|
+
const thresholdInMinutes: number =
|
|
2010
|
+
intervalInMinutes + CREATION_LAG_GRACE_IN_MINUTES;
|
|
2011
|
+
let measured: number = 0;
|
|
2012
|
+
let lateCount: number = 0;
|
|
2013
|
+
let maxLagMs: number = 0;
|
|
2014
|
+
|
|
2015
|
+
for (const alert of alerts) {
|
|
2016
|
+
let detectionTime: Date | null = null;
|
|
2017
|
+
let createdTime: Date | null = null;
|
|
2018
|
+
|
|
2019
|
+
try {
|
|
2020
|
+
detectionTime = parseEventTime(
|
|
2021
|
+
readValue(alert, "detectionTime") ??
|
|
2022
|
+
readValue(alert, "detection_time"),
|
|
2023
|
+
);
|
|
2024
|
+
createdTime = parseEventTime(
|
|
2025
|
+
readValue(alert, "createdTime") ?? readValue(alert, "created_time"),
|
|
2026
|
+
);
|
|
2027
|
+
} catch {
|
|
2028
|
+
continue;
|
|
2029
|
+
}
|
|
2030
|
+
|
|
2031
|
+
if (!detectionTime || !createdTime) {
|
|
2032
|
+
continue;
|
|
2033
|
+
}
|
|
2034
|
+
|
|
2035
|
+
measured++;
|
|
2036
|
+
const lagMs: number = createdTime.getTime() - detectionTime.getTime();
|
|
2037
|
+
|
|
2038
|
+
if (lagMs > maxLagMs) {
|
|
2039
|
+
maxLagMs = lagMs;
|
|
2040
|
+
}
|
|
2041
|
+
|
|
2042
|
+
if (lagMs > thresholdInMinutes * 60 * 1000) {
|
|
2043
|
+
lateCount++;
|
|
2044
|
+
}
|
|
2045
|
+
}
|
|
2046
|
+
|
|
2047
|
+
const lag: CreationLag = {
|
|
2048
|
+
measured,
|
|
2049
|
+
lateCount,
|
|
2050
|
+
maxLagMinutes: Math.round(maxLagMs / 60000),
|
|
2051
|
+
};
|
|
2052
|
+
|
|
2053
|
+
if (lateCount > 0) {
|
|
2054
|
+
warnings.push(
|
|
2055
|
+
`${lateCount} of ${measured} detections were created more than ${thresholdInMinutes} minutes after their detection time (up to ${lag.maxLagMinutes} minutes). This is why the connector polls by created time: a cursor over detection time would already have moved past them.`,
|
|
2056
|
+
);
|
|
2057
|
+
}
|
|
2058
|
+
|
|
2059
|
+
return lag;
|
|
2060
|
+
}
|
|
2061
|
+
|
|
2062
|
+
/*
|
|
2063
|
+
* A run sample: the rule name as the title (the finding's message when a
|
|
2064
|
+
* collection has no rule), the detection time as the event time, and
|
|
2065
|
+
* whether Google marked it alerting. Identifier and title are redacted:
|
|
2066
|
+
* both come from the source.
|
|
2067
|
+
*/
|
|
2068
|
+
private static toSample(
|
|
2069
|
+
alert: JSONObject,
|
|
2070
|
+
event: NormalizedSecurityEvent,
|
|
2071
|
+
): SecurityConnectorSample {
|
|
2072
|
+
const detectionTime: Date | null = parseEventTime(
|
|
2073
|
+
readValue(alert, "detectionTime") ?? readValue(alert, "detection_time"),
|
|
2074
|
+
);
|
|
2075
|
+
const createdTime: Date | null = parseEventTime(
|
|
2076
|
+
readValue(alert, "createdTime") ?? readValue(alert, "created_time"),
|
|
2077
|
+
);
|
|
2078
|
+
const detection: unknown = readValue(alert, "detection");
|
|
2079
|
+
const entry: JSONObject | undefined = Array.isArray(detection)
|
|
2080
|
+
? (detection[0] as JSONObject)
|
|
2081
|
+
: (detection as JSONObject | undefined);
|
|
2082
|
+
const isAlert: unknown = entry
|
|
2083
|
+
? entry["alertState"] ?? entry["alert_state"] ?? entry["alerting"]
|
|
2084
|
+
: undefined;
|
|
2085
|
+
|
|
2086
|
+
return {
|
|
2087
|
+
id: redactLogString(event.eventUid),
|
|
2088
|
+
title: redactLogString(event.ruleName || event.message),
|
|
2089
|
+
severity: event.severityName,
|
|
2090
|
+
...(createdTime ? { createdTime: createdTime.toISOString() } : {}),
|
|
2091
|
+
...(detectionTime ? { eventTime: detectionTime.toISOString() } : {}),
|
|
2092
|
+
...(typeof isAlert === "boolean"
|
|
2093
|
+
? { isAlert }
|
|
2094
|
+
: isAlert === "ALERTING"
|
|
2095
|
+
? { isAlert: true }
|
|
2096
|
+
: isAlert === "NOT_ALERTING" || isAlert === "NON_ALERTING"
|
|
2097
|
+
? { isAlert: false }
|
|
2098
|
+
: {}),
|
|
2099
|
+
};
|
|
2100
|
+
}
|
|
2101
|
+
}
|