@oneuptime/common 14.0.1 → 14.0.2
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/DatabaseModels/AlertEpisodeMember.ts +8 -1
- package/Models/DatabaseModels/AutoRemediationSuggestion.ts +63 -0
- package/Models/DatabaseModels/IncidentEpisodeMember.ts +8 -1
- package/Models/DatabaseModels/IncidentEpisodePublicNote.ts +9 -2
- package/Models/DatabaseModels/IncidentPublicNote.ts +9 -2
- package/Models/DatabaseModels/KubernetesCluster.ts +429 -0
- package/Models/DatabaseModels/Monitor.ts +48 -0
- package/Models/DatabaseModels/Runner.ts +5 -4
- package/Models/DatabaseModels/RunnerJob.ts +66 -0
- package/Models/DatabaseModels/ScheduledMaintenancePublicNote.ts +10 -2
- package/Models/DatabaseModels/WorkflowVariable.ts +479 -2
- package/Models/DatabaseModels/WorkspaceProjectAuthToken.ts +79 -25
- package/Server/API/AIInvestigationAPI.ts +341 -0
- package/Server/API/AutoRemediationAPI.ts +184 -2
- package/Server/API/CommonAPI.ts +70 -0
- package/Server/API/KubernetesClusterAiAccessAPI.ts +793 -0
- package/Server/API/MicrosoftTeamsAPI.ts +770 -315
- package/Server/API/MonitorAPI.ts +140 -0
- package/Server/API/OnCallScheduleTimelineAPI.ts +5 -21
- package/Server/API/SlackAPI.ts +447 -99
- package/Server/API/StatusPageAPI.ts +146 -26
- package/Server/API/TelemetryAPI.ts +216 -5
- package/Server/API/UserTwoFactorBackupCodeAPI.ts +1 -0
- package/Server/API/WorkflowVariableAPI.ts +156 -0
- package/Server/Infrastructure/GlobalCache.ts +35 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1794300000000-AddOAuth2WorkflowVariables.ts +97 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1794400000000-AddKubernetesClusterAiAccess.ts +129 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1794500000000-AddIncomingEmailCustomAddressToMonitor.ts +25 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1794600000000-AddAuthTokenExpiresAtToWorkspaceProjectAuthToken.ts +20 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1794700000000-RemoveAppAccessTokenFromWorkspaceProjectAuthTokenMiscData.ts +38 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +10 -0
- package/Server/Middleware/MasterAdminAuthorization.ts +28 -0
- package/Server/Middleware/TelemetryIngest.ts +47 -2
- package/Server/Middleware/UserAuthorization.ts +56 -2
- package/Server/Services/AIAgentService.ts +1 -0
- package/Server/Services/AccessTokenService.ts +121 -48
- package/Server/Services/AlertEpisodeMemberService.ts +9 -0
- package/Server/Services/AlertEpisodeService.ts +14 -1
- package/Server/Services/AlertService.ts +134 -22
- package/Server/Services/AutoRemediationRuleEngineService.ts +968 -39
- package/Server/Services/AutoRemediationRuleService.ts +118 -0
- package/Server/Services/BillingService.ts +1 -0
- package/Server/Services/InboundEmail/Providers/SendGridInboundProvider.ts +16 -22
- package/Server/Services/IncidentEpisodeMemberService.ts +9 -0
- package/Server/Services/IncidentEpisodePublicNoteService.ts +66 -0
- package/Server/Services/IncidentEpisodeRoleMemberService.ts +27 -0
- package/Server/Services/IncidentEpisodeService.ts +14 -1
- package/Server/Services/IncidentGroupingEngineService.ts +11 -0
- package/Server/Services/IncidentMemberService.ts +21 -0
- package/Server/Services/IncidentPublicNoteService.ts +63 -0
- package/Server/Services/IncidentService.ts +120 -20
- package/Server/Services/IncidentStateTimelineService.ts +15 -0
- package/Server/Services/IncidentTemplateService.ts +83 -3
- package/Server/Services/KubernetesClusterAiAccessService.ts +1943 -0
- package/Server/Services/KubernetesClusterService.ts +1570 -1
- package/Server/Services/LogAggregationService.ts +14 -6
- package/Server/Services/MonitorService.ts +651 -52
- package/Server/Services/MonitorStatusTimelineService.ts +639 -2
- package/Server/Services/OnCallDutyPolicyEscalationRuleScheduleService.ts +2 -0
- package/Server/Services/OnCallDutyPolicyEscalationRuleTeamService.ts +2 -0
- package/Server/Services/OnCallDutyPolicyEscalationRuleUserService.ts +2 -0
- package/Server/Services/OnCallDutyPolicyScheduleService.ts +3 -0
- package/Server/Services/OnCallNotificationAlertingService.ts +36 -12
- package/Server/Services/OnCallSetupReminderService.ts +1 -0
- package/Server/Services/ProbeService.ts +7 -1
- package/Server/Services/ProjectService.ts +11 -1
- package/Server/Services/RunbookCredentialService.ts +26 -1
- package/Server/Services/RunbookSecretService.ts +36 -0
- package/Server/Services/RunnerJobService.ts +941 -23
- package/Server/Services/RunnerService.ts +439 -6
- package/Server/Services/ScheduledMaintenancePublicNoteService.ts +66 -0
- package/Server/Services/ScheduledMaintenanceService.ts +124 -19
- package/Server/Services/ScheduledMaintenanceTemplateService.ts +82 -3
- package/Server/Services/ServiceLevelObjectiveService.ts +14 -1
- package/Server/Services/StatusPagePrivateUserService.ts +1 -0
- package/Server/Services/StatusPageService.ts +301 -74
- package/Server/Services/StatusPageSubscriberService.ts +4 -0
- package/Server/Services/TeamMemberService.ts +309 -7
- package/Server/Services/TraceAggregationService.ts +10 -6
- package/Server/Services/UserEmailService.ts +1 -0
- package/Server/Services/UserNotificationMethodAdminService.ts +1 -0
- package/Server/Services/UserNotificationRuleAdminService.ts +1 -0
- package/Server/Services/UserNotificationRuleService.ts +4 -0
- package/Server/Services/UserService.ts +122 -1
- package/Server/Services/WorkflowVariableService.ts +593 -8
- package/Server/Services/WorkspaceNotificationRuleService.ts +588 -8
- package/Server/Services/WorkspaceProjectAuthTokenService.ts +170 -1
- package/Server/Types/Database/QueryHelper.ts +22 -0
- package/Server/Types/Markdown.ts +502 -27
- package/Server/Utils/AI/ClusterAccess/ClusterAccessContext.ts +182 -0
- package/Server/Utils/AI/ClusterAccess/KubectlInvestigationToolkit.ts +525 -0
- package/Server/Utils/AI/ClusterAccess/KubectlJobRunner.ts +854 -0
- package/Server/Utils/AI/CodeFix/CodeFixAgentAuth.ts +22 -2
- package/Server/Utils/AI/Remediation/RemediationCommandTools.ts +1916 -307
- package/Server/Utils/AI/Remediation/RemediationExecutionRunner.ts +1601 -74
- package/Server/Utils/AI/SRE/AIInvestigationEngine.ts +139 -7
- package/Server/Utils/AI/SRE/AlertInvestigationRunner.ts +58 -1
- package/Server/Utils/AI/SRE/IncidentInvestigationRunner.ts +54 -1
- package/Server/Utils/AI/Toolbox/AIActionTools.ts +14 -6
- package/Server/Utils/AI/Toolbox/ResourceTools.ts +4 -2
- package/Server/Utils/AutoRemediation/CommandPlanExecutor.ts +1341 -150
- package/Server/Utils/AutoRemediation/RemediationVerifier.ts +375 -4
- package/Server/Utils/Database/AffectedResourceRelations.ts +127 -0
- package/Server/Utils/Database/ProjectScopedReferenceValidator.ts +240 -1
- package/Server/Utils/EmailRollup/EmailRollupFlushRunner.ts +1 -0
- package/Server/Utils/Monitor/MonitorAlert.ts +83 -9
- package/Server/Utils/Monitor/MonitorCriteriaObservationBuilder.ts +5 -1
- package/Server/Utils/Monitor/MonitorIncident.ts +104 -9
- package/Server/Utils/Monitor/MonitorPayloadRedaction.ts +124 -7
- package/Server/Utils/Monitor/ProbeMonitorsNotification.ts +407 -0
- package/Server/Utils/OnCall/OnCallShiftReminderRunner.ts +1 -0
- package/Server/Utils/PushNotificationUtil.ts +45 -0
- package/Server/Utils/Rules/OwnerRuleAssignment.ts +40 -3
- package/Server/Utils/Runbook/RunbookExecutePermission.ts +56 -6
- package/Server/Utils/SessionReplay/SessionReplayReadService.ts +223 -33
- package/Server/Utils/SessionReplay/SessionReplayUserFlowReadService.ts +559 -0
- package/Server/Utils/StartServer.ts +4 -3
- package/Server/Utils/TeamMember/ProjectLeaveResourceCleanup.ts +528 -0
- package/Server/Utils/TwoFactorBackupCodeNotification.ts +1 -0
- package/Server/Utils/UserPermission/UserPermission.ts +16 -0
- package/Server/Utils/Workflow/OAuth2TokenClient.ts +704 -0
- package/Server/Utils/Workflow/WorkflowVariableOAuthToken.ts +318 -0
- package/Server/Utils/Workspace/MicrosoftTeams/Actions/Alert.ts +47 -7
- package/Server/Utils/Workspace/MicrosoftTeams/Actions/AlertEpisode.ts +57 -16
- package/Server/Utils/Workspace/MicrosoftTeams/Actions/Incident.ts +193 -214
- package/Server/Utils/Workspace/MicrosoftTeams/Actions/IncidentEpisode.ts +57 -13
- package/Server/Utils/Workspace/MicrosoftTeams/Actions/Monitor.ts +54 -17
- package/Server/Utils/Workspace/MicrosoftTeams/Actions/ScheduledMaintenance.ts +179 -161
- package/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.ts +281 -167
- package/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsServiceUrl.ts +114 -0
- package/Server/Utils/Workspace/MicrosoftTeams/ReactionNoteSync.ts +895 -0
- package/Server/Utils/Workspace/Slack/Actions/ActionTypes.ts +7 -9
- package/Server/Utils/Workspace/Slack/Actions/Alert.ts +96 -227
- package/Server/Utils/Workspace/Slack/Actions/AlertEpisode.ts +93 -214
- package/Server/Utils/Workspace/Slack/Actions/Auth.ts +30 -3
- package/Server/Utils/Workspace/Slack/Actions/Authorization.ts +99 -0
- package/Server/Utils/Workspace/Slack/Actions/Incident.ts +117 -283
- package/Server/Utils/Workspace/Slack/Actions/IncidentEpisode.ts +101 -196
- package/Server/Utils/Workspace/Slack/Actions/ReactionNote.ts +329 -0
- package/Server/Utils/Workspace/Slack/Actions/ScheduledMaintenance.ts +111 -287
- package/Server/Utils/Workspace/Slack/Slack.ts +86 -17
- package/Server/Utils/Workspace/Slack/app-manifest.json +2 -0
- package/Server/Utils/Workspace/Workspace.ts +171 -54
- package/Server/Utils/Workspace/WorkspaceActionAuthorization.ts +252 -0
- package/Server/Utils/Workspace/WorkspaceBase.ts +39 -0
- package/Server/Utils/Workspace/WorkspaceOAuthState.ts +280 -0
- package/Server/Utils/Workspace/WorkspaceProjectReferenceValidator.ts +96 -0
- package/Server/Utils/Workspace/WorkspaceReactionNote.ts +620 -0
- package/Tests/App/Dashboard/AttributesJSONDashboardSurfaces.test.tsx +496 -0
- package/Tests/App/Dashboard/AutoRemediationRulesTableCommandRunners.test.tsx +152 -0
- package/Tests/App/Dashboard/BreadcrumbCoverage.test.tsx +32 -0
- package/Tests/App/Dashboard/ClusterAccessNotice.test.tsx +794 -0
- package/Tests/App/Dashboard/CreateOAuthWorkflowVariableModal.test.tsx +840 -0
- package/Tests/App/Dashboard/CreateWorkflowModal.test.tsx +653 -0
- package/Tests/App/Dashboard/DatabaseMonitorStepForm.test.tsx +197 -0
- package/Tests/App/Dashboard/DatabaseMonitorView.test.tsx +376 -0
- package/Tests/App/Dashboard/DisabledWarningRobustness.test.tsx +262 -0
- package/Tests/App/Dashboard/EventNotes.test.tsx +2080 -0
- package/Tests/App/Dashboard/EventNotesPages.test.tsx +486 -0
- package/Tests/App/Dashboard/EventNotesUtil.test.ts +933 -0
- package/Tests/App/Dashboard/ExceptionMonitorEnvironmentFilter.test.tsx +218 -0
- package/Tests/App/Dashboard/IncidentChangeStateNotifyDefault.test.tsx +665 -0
- package/Tests/App/Dashboard/IncidentEpisodeFeedPublicNoteNotifyDefault.test.tsx +494 -0
- package/Tests/App/Dashboard/IncidentEpisodeOverviewNotifyDefault.test.tsx +706 -0
- package/Tests/App/Dashboard/IncidentFeedPublicNoteNotifyDefault.test.tsx +472 -0
- package/Tests/App/Dashboard/IncidentOverviewNotifyDefault.test.tsx +858 -0
- package/Tests/App/Dashboard/IncomingEmailAddressSettings.test.tsx +567 -0
- package/Tests/App/Dashboard/InvestigationClusterToolFormat.test.ts +241 -0
- package/Tests/App/Dashboard/InvestigationEvidenceKubectl.test.tsx +322 -0
- package/Tests/App/Dashboard/InvestigationPanel.test.tsx +12 -0
- package/Tests/App/Dashboard/InvestigationPanelClusterAccess.test.tsx +476 -0
- package/Tests/App/Dashboard/InvestigationRunDetailsKubectl.test.tsx +383 -0
- package/Tests/App/Dashboard/KubectlActivitySummary.test.tsx +366 -0
- package/Tests/App/Dashboard/KubernetesClusterAiAccessSettings.test.ts +2886 -0
- package/Tests/App/Dashboard/KubernetesClusterAiPage.test.tsx +2688 -0
- package/Tests/App/Dashboard/KubernetesClusterAiPageServerParity.test.ts +915 -0
- package/Tests/App/Dashboard/LayerDateTimeFieldTimezoneName.test.tsx +66 -0
- package/Tests/App/Dashboard/LogMonitorPreview.test.tsx +174 -0
- package/Tests/App/Dashboard/MonitorFeedRefresh.test.tsx +279 -0
- package/Tests/App/Dashboard/MonitorMetricQueryConfig.test.ts +244 -0
- package/Tests/App/Dashboard/MonitorOpenWorkCard.test.tsx +381 -0
- package/Tests/App/Dashboard/MonitorOpenWorkHook.test.tsx +784 -0
- package/Tests/App/Dashboard/MonitorOverviewData.test.tsx +2199 -0
- package/Tests/App/Dashboard/MonitorOverviewHero.test.tsx +1169 -0
- package/Tests/App/Dashboard/MonitorOverviewInput.test.ts +1127 -0
- package/Tests/App/Dashboard/MonitorOverviewPage.test.tsx +2136 -0
- package/Tests/App/Dashboard/MonitorOverviewSelectReadable.test.ts +368 -0
- package/Tests/App/Dashboard/MonitorOverviewStatBar.test.tsx +526 -0
- package/Tests/App/Dashboard/MonitorOverviewSupportingCards.test.tsx +542 -0
- package/Tests/App/Dashboard/MonitorOwnersCombine.test.ts +299 -0
- package/Tests/App/Dashboard/MonitorProbesCard.test.tsx +602 -0
- package/Tests/App/Dashboard/MonitorResponseTimeCard.test.tsx +386 -0
- package/Tests/App/Dashboard/MonitorSetupAndConnectionCards.test.tsx +612 -0
- package/Tests/App/Dashboard/MonitorStatusChangesCard.test.tsx +257 -0
- package/Tests/App/Dashboard/MonitorSummaryTestMonitorButton.test.tsx +360 -1
- package/Tests/App/Dashboard/MonitorUptimeHistoryCard.test.tsx +835 -0
- package/Tests/App/Dashboard/MonitorUptimeSummaryHook.test.tsx +971 -0
- package/Tests/App/Dashboard/MonitorViewLayout.test.tsx +580 -0
- package/Tests/App/Dashboard/OnCallLayerRestrictionTimesPreserved.test.tsx +441 -0
- package/Tests/App/Dashboard/OnCallNavbar.test.tsx +214 -0
- package/Tests/App/Dashboard/OnCallSchedulePreviewCalendarDisplay.test.tsx +1389 -0
- package/Tests/App/Dashboard/OnCallSchedulePreviewOverrides.test.tsx +205 -1
- package/Tests/App/Dashboard/OnCallScheduleTimeInputsSettingsZone.test.tsx +198 -0
- package/Tests/App/Dashboard/PublicNotePagesNotifyDefault.test.tsx +524 -0
- package/Tests/App/Dashboard/RemediationSuggestionCardApproval.test.tsx +702 -0
- package/Tests/App/Dashboard/RemoveUserFromProject.test.tsx +427 -0
- package/Tests/App/Dashboard/ResourceArchiveSettings.test.tsx +4 -0
- package/Tests/App/Dashboard/RumSessionReplaySideMenu.test.tsx +3 -1
- package/Tests/App/Dashboard/RunbookStepTypeMaps.test.ts +166 -0
- package/Tests/App/Dashboard/RunnerKubernetesAgentForm.test.tsx +622 -0
- package/Tests/App/Dashboard/ScheduledMaintenanceChangeStateNotifyDefault.test.tsx +1491 -0
- package/Tests/App/Dashboard/ScheduledMaintenanceFeedPublicNoteNotifyDefault.test.tsx +489 -0
- package/Tests/App/Dashboard/ScheduledMaintenanceOverviewNotifyDefault.test.tsx +909 -0
- package/Tests/App/Dashboard/ScheduledMaintenanceOverviewPage.test.tsx +14 -0
- package/Tests/App/Dashboard/ScheduledMaintenanceWindowStatsTranslation.test.tsx +307 -0
- package/Tests/App/Dashboard/SecurityEventAttributeColumnPicker.test.tsx +542 -0
- package/Tests/App/Dashboard/SecurityEventConnectionFormModal.test.tsx +174 -0
- package/Tests/App/Dashboard/SecurityEventConnectionsEmptyState.test.tsx +973 -212
- package/Tests/App/Dashboard/SecurityEventConnectionsTable.test.tsx +491 -52
- package/Tests/App/Dashboard/SecurityEventDetailPanel.test.tsx +301 -0
- package/Tests/App/Dashboard/SecurityEventListRow.test.tsx +158 -1
- package/Tests/App/Dashboard/SecurityEventProviderTile.test.tsx +869 -0
- package/Tests/App/Dashboard/SecurityEventsEmptyState.test.tsx +959 -94
- package/Tests/App/Dashboard/SecurityEventsNoResults.test.tsx +2 -0
- package/Tests/App/Dashboard/SecurityEventsViewer.test.tsx +274 -1
- package/Tests/App/Dashboard/TeamMembershipRemoval.test.ts +900 -0
- package/Tests/App/Dashboard/TeamMembershipRemovalPages.test.tsx +460 -0
- package/Tests/App/Dashboard/TimezoneElements.test.tsx +321 -0
- package/Tests/App/Dashboard/TimezoneSelectButton.test.tsx +634 -0
- package/Tests/App/Dashboard/TraceExplorer.test.tsx +260 -0
- package/Tests/App/Dashboard/TraceMonitorPreview.test.tsx +182 -0
- package/Tests/App/Dashboard/UserTimezoneInit.test.tsx +544 -0
- package/Tests/App/Dashboard/WorkflowVariableModals.test.tsx +1630 -0
- package/Tests/App/Dashboard/WorkflowVariableRoutes.test.tsx +603 -0
- package/Tests/App/Dashboard/WorkflowVariableTokenStatus.test.tsx +589 -0
- package/Tests/App/Dashboard/WorkflowVariableUtil.test.ts +1543 -0
- package/Tests/App/Dashboard/WorkflowVariableView.test.tsx +3227 -0
- package/Tests/App/Dashboard/WorkflowVariablesTable.test.tsx +1277 -395
- package/Tests/App/StatusPage/StatusPageOverviewMonitorGroupUptime.test.tsx +714 -0
- package/Tests/App/StatusPage/StatusPageOverviewUptimeBars.NewYork.test.tsx +1009 -0
- package/Tests/App/StatusPage/StatusPageOverviewUptimeBars.test.tsx +1092 -0
- package/Tests/Models/DatabaseModels/DomainRoleTierCoverage.test.ts +5 -0
- package/Tests/Models/DatabaseModels/KubernetesClusterAiAccessColumns.test.ts +520 -0
- package/Tests/Models/DatabaseModels/MonitorSecretKeyColumnAccessControl.test.ts +66 -2
- package/Tests/Models/DatabaseModels/WorkspaceProjectAuthTokenAccessControl.test.ts +236 -0
- package/Tests/Models/IncidentEpisodePublicNoteNotifyColumnContract.test.ts +103 -0
- package/Tests/Models/IncidentPublicNoteNotifyColumnContract.test.ts +96 -0
- package/Tests/Models/ScheduledMaintenancePublicNoteNotifyColumnContract.test.ts +111 -0
- package/Tests/Server/API/AIInvestigationAPI.test.ts +976 -0
- package/Tests/Server/API/AutoRemediationApproveKubectlRecheck.test.ts +836 -0
- package/Tests/Server/API/CommonAPIAssertCanCreateTable.test.ts +565 -0
- package/Tests/Server/API/CommonAPIAssertCanReadTable.test.ts +282 -0
- package/Tests/Server/API/KubernetesClusterAiAccessAPI.test.ts +1744 -0
- package/Tests/Server/API/LogHistogramAPI.test.ts +371 -0
- package/Tests/Server/API/MicrosoftTeamsLegacyWebhookRemoval.test.ts +125 -30
- package/Tests/Server/API/MicrosoftTeamsOAuthState.test.ts +1121 -0
- package/Tests/Server/API/MonitorUptimeSummaryAPI.test.ts +685 -0
- package/Tests/Server/API/SessionReplayAPI.test.ts +602 -1
- package/Tests/Server/API/SlackChannelCacheAPI.test.ts +358 -0
- package/Tests/Server/API/SlackOAuthState.test.ts +688 -0
- package/Tests/Server/API/StatusPageOverviewMonitorGroupUptime.test.ts +527 -0
- package/Tests/Server/API/StatusPageTestEmailReportAuth.test.ts +2 -0
- package/Tests/Server/API/StatusPageUptimeAPI.test.ts +427 -0
- package/Tests/Server/API/UserProjectsAPI.test.ts +4 -0
- package/Tests/Server/API/WorkflowVariableAPI.test.ts +404 -0
- package/Tests/Server/API/WorkspaceOAuthTestHelpers.ts +289 -0
- package/Tests/Server/API/WorkspaceSendTestNotificationRoutes.test.ts +2064 -0
- package/Tests/Server/Infrastructure/GlobalCache.test.ts +86 -0
- package/Tests/Server/Infrastructure/Postgres/AddKubernetesClusterAiAccessMigration.test.ts +589 -0
- package/Tests/Server/Infrastructure/Postgres/AddOAuth2WorkflowVariablesMigration.test.ts +254 -0
- package/Tests/Server/Middleware/BlockedUserMiddleware.test.ts +403 -0
- package/Tests/Server/Middleware/MasterAdminAuthorization.test.ts +13 -0
- package/Tests/Server/Middleware/PublicRouteUserMiddleware.test.ts +2 -0
- package/Tests/Server/Middleware/RemovedProjectMemberAuthorization.test.ts +469 -0
- package/Tests/Server/Middleware/TelemetryIngestBrowserKey.test.ts +77 -1
- package/Tests/Server/Middleware/TelemetryIngestKubernetesAgentRunnerPinnedKey.test.ts +211 -0
- package/Tests/Server/Middleware/TelemetryIngestKubernetesAgentRunnerRateLimit.test.ts +358 -0
- package/Tests/Server/Middleware/UserAuthorization.test.ts +97 -0
- package/Tests/Server/Middleware/UserAuthorizationEditionEnforcement.test.ts +2 -0
- package/Tests/Server/Services/AccessTokenProjectUserGrant.test.ts +14 -2
- package/Tests/Server/Services/AccessTokenRemovedMemberAccess.test.ts +1044 -0
- package/Tests/Server/Services/AddOwnersIdempotency.test.ts +5 -0
- package/Tests/Server/Services/AlertEpisodeMemberCreatePermission.test.ts +139 -0
- package/Tests/Server/Services/AutoRemediationClusterRuleEngine.test.ts +1361 -0
- package/Tests/Server/Services/AutoRemediationRuleCommandRunners.test.ts +375 -0
- package/Tests/Server/Services/CrossProjectRelationWriteGuard.test.ts +2384 -0
- package/Tests/Server/Services/FindOwnersProjectMembership.test.ts +267 -0
- package/Tests/Server/Services/InboundEmail/SendGridInboundProviderAddress.test.ts +90 -0
- package/Tests/Server/Services/IncidentEpisodeMemberCreatePermission.test.ts +143 -0
- package/Tests/Server/Services/IncidentEpisodePublicNoteNotifyDefault.test.ts +805 -0
- package/Tests/Server/Services/IncidentPublicNoteNotifyDefault.test.ts +724 -0
- package/Tests/Server/Services/IncidentRoleProjectMembership.test.ts +233 -0
- package/Tests/Server/Services/KubernetesClusterAiAccessAgentRunnerAssignments.test.ts +372 -0
- package/Tests/Server/Services/KubernetesClusterAiAccessBindingGuard.test.ts +1876 -0
- package/Tests/Server/Services/KubernetesClusterAiAccessDeletedRunnerRemedy.test.ts +620 -0
- package/Tests/Server/Services/KubernetesClusterAiAccessGapNextSteps.test.ts +421 -0
- package/Tests/Server/Services/KubernetesClusterAiAccessService.test.ts +3662 -0
- package/Tests/Server/Services/KubernetesClusterAiAccessSubjectClusters.test.ts +405 -0
- package/Tests/Server/Services/KubernetesClusterAiSettingsPermission.test.ts +975 -0
- package/Tests/Server/Services/KubernetesClusterServiceAiAccessFeed.test.ts +497 -0
- package/Tests/Server/Services/KubernetesClusterServiceDeleteSettlesRemediation.test.ts +328 -0
- package/Tests/Server/Services/LogAggregationService.test.ts +99 -0
- package/Tests/Server/Services/MonitorServiceIncomingEmailCustomAddress.test.ts +447 -0
- package/Tests/Server/Services/MonitorServiceProbeFlagSync.test.ts +1334 -0
- package/Tests/Server/Services/MonitorServiceProbeStatusGrouping.test.ts +1640 -0
- package/Tests/Server/Services/MonitorServiceRefreshCurrentStatus.test.ts +225 -0
- package/Tests/Server/Services/MonitorStatusBridgeProbePath.test.ts +8 -8
- package/Tests/Server/Services/MonitorStatusTimelineDailyAggregates.test.ts +264 -1
- package/Tests/Server/Services/MonitorStatusTimelineMergedDowntime.test.ts +284 -0
- package/Tests/Server/Services/MonitorUptimeSummaryService.test.ts +1043 -0
- package/Tests/Server/Services/NetworkDeviceRuleEngines.test.ts +5 -0
- package/Tests/Server/Services/OnCallUndeliverablePageOwnerMembership.test.ts +359 -0
- package/Tests/Server/Services/ProbeServiceDashboardLink.test.ts +191 -0
- package/Tests/Server/Services/ProjectOwnersProjectMembership.test.ts +221 -0
- package/Tests/Server/Services/RuleRun/IncidentAlertMaintenanceRuleEnginesRun.test.ts +5 -0
- package/Tests/Server/Services/RuleRun/OwnerRuleEnginesGroupARun.test.ts +28 -0
- package/Tests/Server/Services/RuleRun/OwnerRuleEnginesGroupBRun.test.ts +9 -1
- package/Tests/Server/Services/RunnerJobEnqueueAiCommandAgentRunner.test.ts +230 -0
- package/Tests/Server/Services/RunnerJobEnqueueKubectl.test.ts +978 -0
- package/Tests/Server/Services/RunnerJobKubectlWriteScope.test.ts +866 -0
- package/Tests/Server/Services/RunnerJobSubmitResultRedaction.test.ts +322 -0
- package/Tests/Server/Services/RunnerJobSubmitResultUnstorableText.test.ts +357 -0
- package/Tests/Server/Services/RunnerJobTimeoutReason.test.ts +227 -0
- package/Tests/Server/Services/RunnerServiceAgentName.test.ts +581 -0
- package/Tests/Server/Services/ScheduledMaintenancePublicNoteNotifyDefault.test.ts +802 -0
- package/Tests/Server/Services/ScheduledMaintenanceSubscriberTemplateFormats.test.ts +53 -0
- package/Tests/Server/Services/ServiceLevelObjectiveLabelAndOwnerRuleEngines.test.ts +5 -0
- package/Tests/Server/Services/ServiceLevelObjectiveService.test.ts +12 -0
- package/Tests/Server/Services/StatusPageSubscriberReport.test.ts +1176 -1
- package/Tests/Server/Services/TeamMemberBillingSeatSync.test.ts +9 -0
- package/Tests/Server/Services/TeamMemberOnCallCleanup.test.ts +18 -0
- package/Tests/Server/Services/TeamMemberProjectMembership.test.ts +255 -0
- package/Tests/Server/Services/TeamMemberRemovalRevokesProjectAccess.test.ts +600 -0
- package/Tests/Server/Services/TeamMemberResourceCleanup.test.ts +731 -0
- package/Tests/Server/Services/TeamMemberWorkspaceAccountCleanup.test.ts +164 -0
- package/Tests/Server/Services/TraceAggregationService.test.ts +64 -0
- package/Tests/Server/Services/UserServiceBlockedUser.test.ts +293 -0
- package/Tests/Server/Services/WorkflowVariableOAuthHooks.test.ts +1016 -0
- package/Tests/Server/Services/WorkflowVariableOAuthPostgres.test.ts +543 -0
- package/Tests/Server/Services/WorkflowVariableRenameUniqueness.test.ts +16 -5
- package/Tests/Server/Services/WorkspaceNotificationRuleNoteDelivery.test.ts +473 -0
- package/Tests/Server/Services/WorkspaceNotificationRuleSendTestNotification.test.ts +3690 -0
- package/Tests/Server/Services/WorkspaceProjectAuthTokenMiscDataSecrets.test.ts +374 -0
- package/Tests/Server/Services/WorkspaceProjectAuthTokenSlackChannelCache.test.ts +143 -0
- package/Tests/Server/Types/Database/Permissions/WorkflowVariableOAuthColumnPermission.test.ts +250 -0
- package/Tests/Server/Types/Database/QueryHelperJsonContains.test.ts +96 -0
- package/Tests/Server/Types/Markdown.test.ts +1033 -0
- package/Tests/Server/Utils/AI/ClusterAccessContext.test.ts +285 -0
- package/Tests/Server/Utils/AI/CodeFix/CodeFixAgentAuth.test.ts +159 -1
- package/Tests/Server/Utils/AI/InvestigationClusterAccessWiring.test.ts +752 -0
- package/Tests/Server/Utils/AI/KubectlInvestigationToolkit.test.ts +1840 -0
- package/Tests/Server/Utils/AI/KubectlJobRunner.test.ts +1067 -0
- package/Tests/Server/Utils/AI/KubectlJobRunnerFinishedJob.test.ts +355 -0
- package/Tests/Server/Utils/AI/PostIncidentStatusUpdateTool.test.ts +496 -0
- package/Tests/Server/Utils/AI/RemediationCommandTools.test.ts +305 -0
- package/Tests/Server/Utils/AI/RemediationCommandToolsKubectl.test.ts +1365 -0
- package/Tests/Server/Utils/AI/RemediationCommandToolsKubectlOutcome.test.ts +639 -0
- package/Tests/Server/Utils/AI/RemediationCommandToolsLiveCluster.test.ts +1585 -0
- package/Tests/Server/Utils/AI/RemediationCommandToolsRunnerScope.test.ts +1065 -0
- package/Tests/Server/Utils/AI/RemediationExecutionRunner.test.ts +2138 -1
- package/Tests/Server/Utils/AI/RemediationExecutionRunnerClusterMode.test.ts +1035 -0
- package/Tests/Server/Utils/AI/RemediationKubectlCopyParity.test.ts +517 -0
- package/Tests/Server/Utils/AI/ResourceTools.test.ts +27 -1
- package/Tests/Server/Utils/AutoRemediation/CommandPlanExecutor.test.ts +1371 -24
- package/Tests/Server/Utils/AutoRemediation/CommandPlanExecutorRollbackRace.test.ts +962 -0
- package/Tests/Server/Utils/AutoRemediation/CommandPlanExecutorUnknownRun.test.ts +518 -0
- package/Tests/Server/Utils/AutoRemediation/CommandPlanVerification.test.ts +939 -2
- package/Tests/Server/Utils/Database/ProjectScopedRelationReferences.test.ts +371 -0
- package/Tests/Server/Utils/Monitor/AffectedResourceList.test.ts +64 -0
- package/Tests/Server/Utils/Monitor/DatabaseMetricObservationRemediation.test.ts +102 -0
- package/Tests/Server/Utils/Monitor/MonitorAlertCriteriaReferences.test.ts +362 -0
- package/Tests/Server/Utils/Monitor/MonitorCriteriaEvaluatorBreachingSamples.test.ts +55 -0
- package/Tests/Server/Utils/Monitor/MonitorEmailAddressRedaction.test.ts +255 -0
- package/Tests/Server/Utils/Monitor/MonitorIncidentCriteriaReferences.test.ts +347 -0
- package/Tests/Server/Utils/Monitor/MonitorIncidentMemberRoleMembership.test.ts +203 -0
- package/Tests/Server/Utils/Monitor/ProbeMonitorsNotification.test.ts +1147 -0
- package/Tests/Server/Utils/PushNotificationUtilCreators.test.ts +79 -0
- package/Tests/Server/Utils/ResourceFeed/ResourceFeedUtil.test.ts +21 -1
- package/Tests/Server/Utils/Rules/OwnerRuleAssignment.test.ts +155 -1
- package/Tests/Server/Utils/SessionReplay/SessionReplayReadServiceQueries.test.ts +288 -0
- package/Tests/Server/Utils/SessionReplay/SessionReplayUserFlowReadService.test.ts +304 -0
- package/Tests/Server/Utils/Telemetry/TelemetryIngestionKeyGuard.test.ts +40 -3
- package/Tests/Server/Utils/Workflow/OAuth2TokenClient.test.ts +702 -0
- package/Tests/Server/Utils/Workflow/OAuth2TokenClientHttpIntegration.test.ts +507 -0
- package/Tests/Server/Utils/Workflow/WorkflowVariableOAuthToken.test.ts +831 -0
- package/Tests/Server/Utils/Workspace/MicrosoftTeamsActionAuthorization.test.ts +63 -1
- package/Tests/Server/Utils/Workspace/MicrosoftTeamsAppAccessToken.test.ts +256 -0
- package/Tests/Server/Utils/Workspace/MicrosoftTeamsChannelSend.test.ts +60 -0
- package/Tests/Server/Utils/Workspace/MicrosoftTeamsChatActionAuthorization.test.ts +442 -0
- package/Tests/Server/Utils/Workspace/MicrosoftTeamsChats.test.ts +44 -2
- package/Tests/Server/Utils/Workspace/MicrosoftTeamsDirectMessage.test.ts +55 -0
- package/Tests/Server/Utils/Workspace/MicrosoftTeamsReactionNoteSync.test.ts +1522 -0
- package/Tests/Server/Utils/Workspace/MicrosoftTeamsServiceUrl.test.ts +130 -0
- package/Tests/Server/Utils/Workspace/MicrosoftTeamsTeamInstalls.test.ts +4 -4
- package/Tests/Server/Utils/Workspace/Slack/SlackActionAuthorization.test.ts +691 -0
- package/Tests/Server/Utils/Workspace/Slack/SlackMessageByTimestamp.test.ts +253 -0
- package/Tests/Server/Utils/Workspace/Slack/SlackReactionNote.test.ts +574 -0
- package/Tests/Server/Utils/Workspace/WorkspaceActionAuthorization.test.ts +488 -0
- package/Tests/Server/Utils/Workspace/WorkspaceCreateProjectReferences.test.ts +861 -0
- package/Tests/Server/Utils/Workspace/WorkspaceMessageAuthor.test.ts +635 -0
- package/Tests/Server/Utils/Workspace/WorkspaceOAuthState.test.ts +548 -0
- package/Tests/Server/Utils/Workspace/WorkspaceReactionNote.test.ts +839 -0
- package/Tests/Server/Utils/Workspace/WorkspaceSendErrorMessage.test.ts +725 -0
- package/Tests/Types/AutoRemediation/AiRemediationCommandPlan.test.ts +283 -9
- package/Tests/Types/DateBrowserLocalWallClock.test.ts +280 -0
- package/Tests/Types/DateLocalShortMonthNameFallback.test.ts +389 -0
- package/Tests/Types/DateUserTimezone.test.ts +177 -4
- package/Tests/Types/Kubernetes/KubernetesAgentChartAiAccess.test.ts +306 -0
- package/Tests/Types/Kubernetes/KubernetesClusterAiAccess.test.ts +283 -0
- package/Tests/Types/Kubernetes/KubernetesRunnerPostureWriteScope.test.ts +68 -0
- package/Tests/Types/Monitor/DatabaseMonitor/SqlServerPlatform.test.ts +144 -0
- package/Tests/Types/Monitor/MonitorStepExceptionMonitor.test.ts +160 -0
- package/Tests/Types/Monitor/Recommendation/MonitorRecommendationCoverage.test.ts +53 -0
- package/Tests/Types/Runbook/RunbookStepType.test.ts +91 -16
- package/Tests/Types/Runner/RunnerLiveStatus.test.ts +14 -3
- package/Tests/Types/SecurityEvent/Connectors/SecurityEventConnectorCatalog.test.ts +15 -0
- package/Tests/Types/StatusPage/PublicNoteSubscriberNotificationDefault.test.ts +1868 -0
- package/Tests/Types/Timezone.test.ts +5 -0
- package/Tests/Types/TimezoneAlias.test.ts +1034 -0
- package/Tests/Types/Workflow/JiraTemplateFixtures.ts +833 -0
- package/Tests/Types/Workflow/JiraTemplateScripts.test.ts +5414 -0
- package/Tests/Types/Workflow/JiraTemplateSimulation.test.ts +4803 -0
- package/Tests/Types/Workflow/JiraTemplates.test.ts +5429 -0
- package/Tests/Types/Workflow/Templates.test.ts +79 -4
- package/Tests/Types/Workflow/WorkflowVariableOAuth.test.ts +520 -0
- package/Tests/Types/Workspace/WorkspaceNoteReaction.test.ts +177 -0
- package/Tests/UI/Components/AttributesJSON/AttributesJSONView.test.tsx +390 -0
- package/Tests/UI/Components/AttributesJSON/CopyAttributesAsJSONButton.test.tsx +566 -0
- package/Tests/UI/Components/AttributesJSON/JSONHighlight.test.ts +131 -0
- package/Tests/UI/Components/BasicFormDropdownNormalization.test.tsx +276 -1
- package/Tests/UI/Components/Calendar/Calendar.test.tsx +1611 -0
- package/Tests/UI/Components/Calendar/CalendarDayLayout.test.ts +1486 -0
- package/Tests/UI/Components/Calendar/CalendarDayLayoutDst.test.ts +632 -0
- package/Tests/UI/Components/Calendar/CalendarDst.test.tsx +388 -0
- package/Tests/UI/Components/Charts/ChartGroupPlotFloor.test.tsx +170 -0
- package/Tests/UI/Components/Charts/HistogramSelection.test.ts +282 -0
- package/Tests/UI/Components/CustomTimeRangeModal.test.tsx +6 -0
- package/Tests/UI/Components/CustomTimeRangeModalTimezoneTranslation.test.tsx +285 -0
- package/Tests/UI/Components/Dropdown.test.tsx +999 -2
- package/Tests/UI/Components/Forms/FormFieldCheckboxTranslation.test.tsx +216 -0
- package/Tests/UI/Components/Forms/FormFieldTimezoneDescriptionTranslation.test.tsx +461 -0
- package/Tests/UI/Components/Forms/IncidentEpisodePublicNoteNotifyPayload.test.tsx +641 -0
- package/Tests/UI/Components/Forms/IncidentPublicNoteNotifyPayload.test.tsx +346 -0
- package/Tests/UI/Components/Forms/ScheduledMaintenancePublicNoteNotifyPayload.test.tsx +493 -0
- package/Tests/UI/Components/Graphs/DayUptimeGraph.test.tsx +911 -2
- package/Tests/UI/Components/Graphs/DayUptimeGraphTimezone.NewYork.test.tsx +730 -0
- package/Tests/UI/Components/Graphs/DayUptimeGraphTimezone.Tokyo.test.tsx +506 -0
- package/Tests/UI/Components/HistogramClickToZoom.test.tsx +619 -0
- package/Tests/UI/Components/LogDetailsPanelAttributesJSON.test.tsx +248 -0
- package/Tests/UI/Components/LogsViewerHistogramZoom.test.tsx +47 -1
- package/Tests/UI/Components/LogsViewerSmallScreens.test.tsx +620 -0
- package/Tests/UI/Components/ModelPageModelChange.test.tsx +242 -3
- package/Tests/UI/Components/ModelTable/BaseModelTableDeleteConfirmation.test.tsx +521 -0
- package/Tests/UI/Components/MonitorGraphs/Uptime.test.tsx +406 -2
- package/Tests/UI/Components/MonitorGraphs/UptimeBarDayModal.test.tsx +169 -2
- package/Tests/UI/Components/TelemetryViewer/TelemetryViewerHistogramClickZoom.test.tsx +266 -0
- package/Tests/UI/Components/TelemetryViewer/TelemetryViewerSmallScreens.test.tsx +439 -0
- package/Tests/UI/Components/TimezoneDropdownLegacyValues.test.tsx +704 -0
- package/Tests/UI/Components/UseHistogramZoom.test.tsx +89 -1
- package/Tests/UI/Components/UseLogsHistogram.test.tsx +175 -0
- package/Tests/UI/Monitor/MonitorSummarySnapshotRender.test.tsx +5 -5
- package/Tests/UI/Telemetry/TelemetryDetailPanel.test.tsx +28 -0
- package/Tests/UI/Utils/ProjectUsersModelAPI.test.ts +51 -0
- package/Tests/UI/Utils/Timezone.test.ts +747 -33
- package/Tests/UI/Workspace/SendTestNotificationButton.test.tsx +1854 -0
- package/Tests/UI/Workspace/WorkspaceCardsSendTestNotification.test.tsx +1864 -0
- package/Tests/Utils/AI/InvestigationReport.test.ts +435 -7
- package/Tests/Utils/AiRemediation/KubectlAllowlistValidatorParity.test.ts +1084 -0
- package/Tests/Utils/AiRemediation/KubectlOutputRedactor.test.ts +2531 -0
- package/Tests/Utils/AiRemediation/KubectlPolicy.test.ts +1895 -0
- package/Tests/Utils/AiRemediation/KubectlPolicyAllowlist.test.ts +428 -0
- package/Tests/Utils/AiRemediation/KubectlPolicyChartRbacParity.test.ts +828 -0
- package/Tests/Utils/AiRemediation/KubectlPolicyCustomResourceScope.test.ts +573 -0
- package/Tests/Utils/AiRemediation/KubectlPolicyDenials.test.ts +1525 -0
- package/Tests/Utils/AiRemediation/KubectlPolicyExposeOverrides.test.ts +275 -0
- package/Tests/Utils/AiRemediation/KubectlPolicyNodePatch.test.ts +428 -0
- package/Tests/Utils/AiRemediation/KubectlPolicyObjectWords.test.ts +195 -0
- package/Tests/Utils/AiRemediation/KubectlPolicyPatchParents.test.ts +637 -0
- package/Tests/Utils/AiRemediation/KubectlPolicyPodSecurityBaseline.test.ts +322 -0
- package/Tests/Utils/AiRemediation/KubectlPolicySafeWriteScope.test.ts +1026 -0
- package/Tests/Utils/AiRemediation/KubectlWaitBudget.test.ts +267 -0
- package/Tests/Utils/AiRemediation/KubectlWriteScope.test.ts +390 -0
- package/Tests/Utils/AiRemediation/KubectlWriteScopeCallerParity.test.ts +777 -0
- package/Tests/Utils/AiRemediation/KubectlWriteScopeClusterScoped.test.ts +613 -0
- package/Tests/Utils/AiRemediation/KubectlWriteScopeEntryPoint.test.ts +576 -0
- package/Tests/Utils/AiRemediation/KubectlWriteScopeKubectlSpellings.test.ts +752 -0
- package/Tests/Utils/AiRemediation/KubectlWriteScopeObjectWords.test.ts +358 -0
- package/Tests/Utils/AiRemediation/KubectlWriteScopeOverrides.test.ts +293 -0
- package/Tests/Utils/AiRemediation/KubectlWriteScopeParityCases.ts +598 -0
- package/Tests/Utils/AiRemediation/KubectlWriteScopePolicyParity.test.ts +403 -0
- package/Tests/Utils/Dashboard/DashboardClockComponent.test.ts +154 -5
- package/Tests/Utils/Monitor/IncomingEmailMonitorAddress.test.ts +478 -0
- package/Tests/Utils/Monitor/MonitorCheckScheduleUtil.test.ts +646 -0
- package/Tests/Utils/Monitor/MonitorOverviewCriteriaUtil.test.ts +292 -0
- package/Tests/Utils/Monitor/MonitorOverviewFamily.test.ts +274 -0
- package/Tests/Utils/Monitor/MonitorOverviewPresentationUtil.test.ts +3100 -0
- package/Tests/Utils/Monitor/MonitorOverviewProbeUtil.test.ts +1412 -0
- package/Tests/Utils/Monitor/MonitorOverviewTargetUtil.test.ts +374 -0
- package/Tests/Utils/Monitor/MonitorStatusHistoryUtil.test.ts +332 -0
- package/Tests/Utils/Monitor/MonitorUptimeSummaryUtil.test.ts +946 -0
- package/Tests/Utils/Rum/SessionIdentity.test.ts +94 -0
- package/Tests/Utils/Rum/SessionReplayWafCompatibility.test.ts +840 -0
- package/Tests/Utils/Rum/SessionReplayWireEncoding.test.ts +208 -0
- package/Tests/Utils/Rum/UserFlow.test.ts +1010 -0
- package/Tests/Utils/StatusPage/MonitorGroupMergedDowntimeUtil.test.ts +217 -0
- package/Tests/Utils/StatusPage/ResourceUptime.test.ts +1272 -1
- package/Tests/Utils/StatusPage/UptimeDailyAggregateTotals.test.ts +298 -0
- package/Tests/Utils/StatusPage/UptimeDailyAggregateUtil.test.ts +649 -1
- package/Tests/Utils/StatusPage/UptimeDailyAggregateWindow.test.ts +314 -0
- package/Tests/Utils/Telemetry/AttributesJSON.test.ts +454 -0
- package/Tests/Utils/Uptime/DayUptimeGraphUtil.test.ts +418 -2
- package/Tests/Utils/Uptime/DayUptimeGraphUtilMidnightDst.test.ts +160 -0
- package/Tests/Utils/Uptime/DayUptimeGraphUtilTimezone.Auckland.test.ts +45 -0
- package/Tests/Utils/Uptime/DayUptimeGraphUtilTimezone.Kolkata.test.ts +40 -0
- package/Tests/Utils/Uptime/DayUptimeGraphUtilTimezone.London.test.ts +147 -0
- package/Tests/Utils/Uptime/DayUptimeGraphUtilTimezone.NewYork.test.ts +48 -0
- package/Tests/Utils/Uptime/DayUptimeGraphUtilTimezone.Tokyo.test.ts +39 -0
- package/Tests/Utils/Uptime/DayUptimeGraphUtilTimezoneCases.ts +1015 -0
- package/Tests/Utils/Uptime/UptimeUtil.test.ts +75 -0
- package/Tests/Utils/Uptime/UptimeUtilChronologicalOrder.test.ts +1279 -0
- package/Types/AutoRemediation/AiRemediationCommandPlan.ts +203 -5
- package/Types/Date.ts +121 -7
- package/Types/Email/EmailMessage.ts +8 -0
- package/Types/Email/EmailTemplateType.ts +1 -0
- package/Types/Exception/ExceptionMessages.ts +1 -0
- package/Types/Kubernetes/KubernetesClusterAiAccess.ts +488 -0
- package/Types/Kubernetes/KubernetesClusterAiAccessPermissions.ts +54 -0
- package/Types/Kubernetes/KubernetesClusterAiAccessToolNames.ts +17 -0
- package/Types/Monitor/DatabaseMonitor/DatabaseMonitorResponse.ts +9 -0
- package/Types/Monitor/DatabaseMonitor/SqlServerPlatform.ts +117 -0
- package/Types/Monitor/KubernetesAlertTemplates.ts +6 -5
- package/Types/Monitor/MonitorStepExceptionMonitor.ts +56 -0
- package/Types/Monitor/MonitorUptimeSummary.ts +113 -0
- package/Types/Monitor/Recommendation/MonitorRecommendationUtil.ts +11 -0
- package/Types/Rum/SessionReplay.ts +55 -2
- package/Types/Rum/SessionReplayApi.ts +44 -1
- package/Types/Rum/UserFlow.ts +187 -0
- package/Types/Runbook/RunbookStepType.ts +10 -0
- package/Types/Runbook/RunnerJobOrigin.ts +15 -0
- package/Types/SecurityEvent/Connectors/SecurityEventConnectorCatalog.ts +6 -2
- package/Types/StatusPage/MergedDowntimeTotals.ts +17 -0
- package/Types/StatusPage/PublicNoteSubscriberNotificationDefault.ts +148 -0
- package/Types/StatusPage/UptimeDailyAggregate.ts +15 -0
- package/Types/Telemetry/TelemetryIngestSurface.ts +9 -0
- package/Types/Timezone.ts +5 -0
- package/Types/TimezoneAlias.ts +385 -0
- package/Types/Workflow/Templates.ts +3041 -2
- package/Types/Workflow/WorkflowVariableOAuth.ts +476 -0
- package/Types/Workspace/WorkspaceNoteReaction.ts +132 -0
- package/Typings/Index.d.ts +24 -0
- package/UI/Components/AttributesJSON/AttributesJSONPreferences.ts +175 -0
- package/UI/Components/AttributesJSON/AttributesJSONView.tsx +138 -0
- package/UI/Components/AttributesJSON/AttributesViewToggle.tsx +79 -0
- package/UI/Components/AttributesJSON/BracesGlyph.tsx +30 -0
- package/UI/Components/AttributesJSON/CopyAttributesAsJSONButton.tsx +491 -0
- package/UI/Components/AttributesJSON/JSONHighlight.ts +77 -0
- package/UI/Components/Calendar/Calendar.css +83 -0
- package/UI/Components/Calendar/Calendar.tsx +136 -7
- package/UI/Components/Calendar/CalendarDayLayout.ts +236 -0
- package/UI/Components/Charts/ChartGroup/ChartGroup.tsx +23 -1
- package/UI/Components/Charts/Utils/HistogramSelection.ts +117 -0
- package/UI/Components/Charts/Utils/useHistogramRangeSelection.ts +269 -0
- package/UI/Components/Charts/Utils/useHistogramZoom.ts +26 -2
- package/UI/Components/Date/CustomTimeRangeModal.tsx +26 -3
- package/UI/Components/Dropdown/Dropdown.tsx +58 -9
- package/UI/Components/Forms/Fields/FormField.tsx +49 -14
- package/UI/Components/Graphs/DayUptimeGraph.tsx +166 -25
- package/UI/Components/Graphs/UptimeBarTooltip.tsx +10 -2
- package/UI/Components/Graphs/UptimeDaySummary.tsx +8 -0
- package/UI/Components/LogsViewer/LogsViewer.tsx +52 -5
- package/UI/Components/LogsViewer/components/ColumnSelector.tsx +13 -2
- package/UI/Components/LogsViewer/components/KeyboardShortcutsHelp.tsx +13 -1
- package/UI/Components/LogsViewer/components/LogDetailsPanel.tsx +91 -76
- package/UI/Components/LogsViewer/components/LogsFacetSidebar.tsx +15 -1
- package/UI/Components/LogsViewer/components/LogsHistogram.tsx +28 -106
- package/UI/Components/LogsViewer/components/LogsViewerToolbar.tsx +54 -6
- package/UI/Components/LogsViewer/components/SavedViewsDropdown.tsx +8 -2
- package/UI/Components/LogsViewer/useLogsHistogram.ts +39 -6
- package/UI/Components/ModelTable/BaseModelTable.tsx +66 -14
- package/UI/Components/MonitorGraphs/Uptime.tsx +12 -0
- package/UI/Components/MonitorGraphs/UptimeBarDayModal.tsx +10 -2
- package/UI/Components/Page/ModelPage.tsx +59 -3
- package/UI/Components/TelemetryViewer/TelemetryViewer.tsx +69 -5
- package/UI/Components/TelemetryViewer/components/TelemetryDetailPanel.tsx +12 -1
- package/UI/Components/TelemetryViewer/components/TelemetryFacetSidebar.tsx +15 -1
- package/UI/Components/TelemetryViewer/components/TelemetryHistogram.tsx +36 -104
- package/UI/Components/TelemetryViewer/components/TelemetrySearchBar.tsx +9 -1
- package/UI/Utils/ModelAPI/ProjectUsersModelAPI.ts +19 -1
- package/UI/Utils/Timezone.ts +69 -28
- package/Utils/AI/InvestigationReport.ts +195 -25
- package/Utils/AiRemediation/KubectlOutputRedactor.ts +1724 -0
- package/Utils/AiRemediation/KubectlPolicy.ts +4136 -0
- package/Utils/AiRemediation/KubectlWaitBudget.ts +156 -0
- package/Utils/AiRemediation/KubectlWriteScope.ts +1964 -0
- package/Utils/Dashboard/Components/DashboardClockComponent.ts +7 -6
- package/Utils/Monitor/IncomingEmailMonitorAddress.ts +292 -0
- package/Utils/Monitor/MonitorCheckScheduleUtil.ts +654 -0
- package/Utils/Monitor/MonitorOverviewCriteriaUtil.ts +188 -0
- package/Utils/Monitor/MonitorOverviewFamily.ts +263 -0
- package/Utils/Monitor/MonitorOverviewPresentationUtil.ts +1958 -0
- package/Utils/Monitor/MonitorOverviewProbeUtil.ts +979 -0
- package/Utils/Monitor/MonitorOverviewTargetUtil.ts +299 -0
- package/Utils/Monitor/MonitorStatusHistoryUtil.ts +201 -0
- package/Utils/Monitor/MonitorUptimeSummaryUtil.ts +638 -0
- package/Utils/Rum/SessionIdentity.ts +44 -0
- package/Utils/Rum/SessionReplayWireEncoding.ts +137 -0
- package/Utils/Rum/UserFlow.ts +1527 -0
- package/Utils/StatusPage/MonitorGroupMergedDowntimeUtil.ts +107 -0
- package/Utils/StatusPage/ResourceUptime.ts +99 -0
- package/Utils/StatusPage/UptimeDailyAggregateUtil.ts +197 -0
- package/Utils/Telemetry/AttributesJSON.ts +367 -0
- package/Utils/Uptime/DayUptimeGraphUtil.ts +165 -0
- package/Utils/Uptime/UptimeUtil.ts +122 -38
- package/build/dist/Models/DatabaseModels/AlertEpisodeMember.js +8 -1
- package/build/dist/Models/DatabaseModels/AlertEpisodeMember.js.map +1 -1
- package/build/dist/Models/DatabaseModels/AutoRemediationSuggestion.js +62 -0
- package/build/dist/Models/DatabaseModels/AutoRemediationSuggestion.js.map +1 -1
- package/build/dist/Models/DatabaseModels/IncidentEpisodeMember.js +8 -1
- package/build/dist/Models/DatabaseModels/IncidentEpisodeMember.js.map +1 -1
- package/build/dist/Models/DatabaseModels/IncidentEpisodePublicNote.js +10 -3
- package/build/dist/Models/DatabaseModels/IncidentEpisodePublicNote.js.map +1 -1
- package/build/dist/Models/DatabaseModels/IncidentPublicNote.js +10 -3
- package/build/dist/Models/DatabaseModels/IncidentPublicNote.js.map +1 -1
- package/build/dist/Models/DatabaseModels/KubernetesCluster.js +434 -0
- package/build/dist/Models/DatabaseModels/KubernetesCluster.js.map +1 -1
- package/build/dist/Models/DatabaseModels/Monitor.js +49 -0
- package/build/dist/Models/DatabaseModels/Monitor.js.map +1 -1
- package/build/dist/Models/DatabaseModels/Runner.js +4 -4
- package/build/dist/Models/DatabaseModels/Runner.js.map +1 -1
- package/build/dist/Models/DatabaseModels/RunnerJob.js +66 -0
- package/build/dist/Models/DatabaseModels/RunnerJob.js.map +1 -1
- package/build/dist/Models/DatabaseModels/ScheduledMaintenancePublicNote.js +11 -3
- package/build/dist/Models/DatabaseModels/ScheduledMaintenancePublicNote.js.map +1 -1
- package/build/dist/Models/DatabaseModels/WorkflowVariable.js +487 -3
- package/build/dist/Models/DatabaseModels/WorkflowVariable.js.map +1 -1
- package/build/dist/Models/DatabaseModels/WorkspaceProjectAuthToken.js +64 -16
- package/build/dist/Models/DatabaseModels/WorkspaceProjectAuthToken.js.map +1 -1
- package/build/dist/Server/API/AIInvestigationAPI.js +205 -0
- package/build/dist/Server/API/AIInvestigationAPI.js.map +1 -1
- package/build/dist/Server/API/AutoRemediationAPI.js +115 -2
- package/build/dist/Server/API/AutoRemediationAPI.js.map +1 -1
- package/build/dist/Server/API/CommonAPI.js +49 -0
- package/build/dist/Server/API/CommonAPI.js.map +1 -1
- package/build/dist/Server/API/KubernetesClusterAiAccessAPI.js +564 -0
- package/build/dist/Server/API/KubernetesClusterAiAccessAPI.js.map +1 -0
- package/build/dist/Server/API/MicrosoftTeamsAPI.js +465 -176
- package/build/dist/Server/API/MicrosoftTeamsAPI.js.map +1 -1
- package/build/dist/Server/API/MonitorAPI.js +107 -1
- package/build/dist/Server/API/MonitorAPI.js.map +1 -1
- package/build/dist/Server/API/OnCallScheduleTimelineAPI.js +5 -16
- package/build/dist/Server/API/OnCallScheduleTimelineAPI.js.map +1 -1
- package/build/dist/Server/API/SlackAPI.js +322 -78
- package/build/dist/Server/API/SlackAPI.js.map +1 -1
- package/build/dist/Server/API/StatusPageAPI.js +123 -17
- package/build/dist/Server/API/StatusPageAPI.js.map +1 -1
- package/build/dist/Server/API/TelemetryAPI.js +144 -5
- package/build/dist/Server/API/TelemetryAPI.js.map +1 -1
- package/build/dist/Server/API/UserTwoFactorBackupCodeAPI.js +1 -0
- package/build/dist/Server/API/UserTwoFactorBackupCodeAPI.js.map +1 -1
- package/build/dist/Server/API/WorkflowVariableAPI.js +109 -0
- package/build/dist/Server/API/WorkflowVariableAPI.js.map +1 -0
- package/build/dist/Server/Infrastructure/GlobalCache.js +29 -0
- package/build/dist/Server/Infrastructure/GlobalCache.js.map +1 -1
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1794300000000-AddOAuth2WorkflowVariables.js +38 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1794300000000-AddOAuth2WorkflowVariables.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1794400000000-AddKubernetesClusterAiAccess.js +54 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1794400000000-AddKubernetesClusterAiAccess.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1794500000000-AddIncomingEmailCustomAddressToMonitor.js +14 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1794500000000-AddIncomingEmailCustomAddressToMonitor.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1794600000000-AddAuthTokenExpiresAtToWorkspaceProjectAuthToken.js +12 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1794600000000-AddAuthTokenExpiresAtToWorkspaceProjectAuthToken.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1794700000000-RemoveAppAccessTokenFromWorkspaceProjectAuthTokenMiscData.js +32 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1794700000000-RemoveAppAccessTokenFromWorkspaceProjectAuthTokenMiscData.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +10 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
- package/build/dist/Server/Middleware/MasterAdminAuthorization.js +21 -0
- package/build/dist/Server/Middleware/MasterAdminAuthorization.js.map +1 -1
- package/build/dist/Server/Middleware/TelemetryIngest.js +32 -2
- package/build/dist/Server/Middleware/TelemetryIngest.js.map +1 -1
- package/build/dist/Server/Middleware/UserAuthorization.js +39 -6
- package/build/dist/Server/Middleware/UserAuthorization.js.map +1 -1
- package/build/dist/Server/Services/AIAgentService.js +1 -0
- package/build/dist/Server/Services/AIAgentService.js.map +1 -1
- package/build/dist/Server/Services/AccessTokenService.js +87 -42
- package/build/dist/Server/Services/AccessTokenService.js.map +1 -1
- package/build/dist/Server/Services/AlertEpisodeMemberService.js +4 -0
- package/build/dist/Server/Services/AlertEpisodeMemberService.js.map +1 -1
- package/build/dist/Server/Services/AlertEpisodeService.js +12 -1
- package/build/dist/Server/Services/AlertEpisodeService.js.map +1 -1
- package/build/dist/Server/Services/AlertService.js +110 -23
- package/build/dist/Server/Services/AlertService.js.map +1 -1
- package/build/dist/Server/Services/AutoRemediationRuleEngineService.js +716 -30
- package/build/dist/Server/Services/AutoRemediationRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/AutoRemediationRuleService.js +100 -0
- package/build/dist/Server/Services/AutoRemediationRuleService.js.map +1 -1
- package/build/dist/Server/Services/BillingService.js +1 -0
- package/build/dist/Server/Services/BillingService.js.map +1 -1
- package/build/dist/Server/Services/InboundEmail/Providers/SendGridInboundProvider.js +11 -16
- package/build/dist/Server/Services/InboundEmail/Providers/SendGridInboundProvider.js.map +1 -1
- package/build/dist/Server/Services/IncidentEpisodeMemberService.js +4 -0
- package/build/dist/Server/Services/IncidentEpisodeMemberService.js.map +1 -1
- package/build/dist/Server/Services/IncidentEpisodePublicNoteService.js +48 -0
- package/build/dist/Server/Services/IncidentEpisodePublicNoteService.js.map +1 -1
- package/build/dist/Server/Services/IncidentEpisodeRoleMemberService.js +21 -0
- package/build/dist/Server/Services/IncidentEpisodeRoleMemberService.js.map +1 -1
- package/build/dist/Server/Services/IncidentEpisodeService.js +12 -1
- package/build/dist/Server/Services/IncidentEpisodeService.js.map +1 -1
- package/build/dist/Server/Services/IncidentGroupingEngineService.js +8 -0
- package/build/dist/Server/Services/IncidentGroupingEngineService.js.map +1 -1
- package/build/dist/Server/Services/IncidentMemberService.js +14 -0
- package/build/dist/Server/Services/IncidentMemberService.js.map +1 -1
- package/build/dist/Server/Services/IncidentPublicNoteService.js +48 -0
- package/build/dist/Server/Services/IncidentPublicNoteService.js.map +1 -1
- package/build/dist/Server/Services/IncidentService.js +99 -21
- package/build/dist/Server/Services/IncidentService.js.map +1 -1
- package/build/dist/Server/Services/IncidentStateTimelineService.js +12 -0
- package/build/dist/Server/Services/IncidentStateTimelineService.js.map +1 -1
- package/build/dist/Server/Services/IncidentTemplateService.js +68 -4
- package/build/dist/Server/Services/IncidentTemplateService.js.map +1 -1
- package/build/dist/Server/Services/KubernetesClusterAiAccessService.js +1470 -0
- package/build/dist/Server/Services/KubernetesClusterAiAccessService.js.map +1 -0
- package/build/dist/Server/Services/KubernetesClusterService.js +1097 -0
- package/build/dist/Server/Services/KubernetesClusterService.js.map +1 -1
- package/build/dist/Server/Services/LogAggregationService.js +14 -6
- package/build/dist/Server/Services/LogAggregationService.js.map +1 -1
- package/build/dist/Server/Services/MonitorService.js +487 -48
- package/build/dist/Server/Services/MonitorService.js.map +1 -1
- package/build/dist/Server/Services/MonitorStatusTimelineService.js +540 -3
- package/build/dist/Server/Services/MonitorStatusTimelineService.js.map +1 -1
- package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleScheduleService.js +2 -0
- package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleScheduleService.js.map +1 -1
- package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleTeamService.js +2 -0
- package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleTeamService.js.map +1 -1
- package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleUserService.js +2 -0
- package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleUserService.js.map +1 -1
- package/build/dist/Server/Services/OnCallDutyPolicyScheduleService.js +3 -0
- package/build/dist/Server/Services/OnCallDutyPolicyScheduleService.js.map +1 -1
- package/build/dist/Server/Services/OnCallNotificationAlertingService.js +29 -7
- package/build/dist/Server/Services/OnCallNotificationAlertingService.js.map +1 -1
- package/build/dist/Server/Services/OnCallSetupReminderService.js +1 -0
- package/build/dist/Server/Services/OnCallSetupReminderService.js.map +1 -1
- package/build/dist/Server/Services/ProbeService.js +7 -1
- package/build/dist/Server/Services/ProbeService.js.map +1 -1
- package/build/dist/Server/Services/ProjectService.js +11 -1
- package/build/dist/Server/Services/ProjectService.js.map +1 -1
- package/build/dist/Server/Services/RunbookCredentialService.js +24 -0
- package/build/dist/Server/Services/RunbookCredentialService.js.map +1 -1
- package/build/dist/Server/Services/RunbookSecretService.js +44 -0
- package/build/dist/Server/Services/RunbookSecretService.js.map +1 -1
- package/build/dist/Server/Services/RunnerJobService.js +641 -21
- package/build/dist/Server/Services/RunnerJobService.js.map +1 -1
- package/build/dist/Server/Services/RunnerService.js +344 -5
- package/build/dist/Server/Services/RunnerService.js.map +1 -1
- package/build/dist/Server/Services/ScheduledMaintenancePublicNoteService.js +48 -0
- package/build/dist/Server/Services/ScheduledMaintenancePublicNoteService.js.map +1 -1
- package/build/dist/Server/Services/ScheduledMaintenanceService.js +102 -20
- package/build/dist/Server/Services/ScheduledMaintenanceService.js.map +1 -1
- package/build/dist/Server/Services/ScheduledMaintenanceTemplateService.js +67 -4
- package/build/dist/Server/Services/ScheduledMaintenanceTemplateService.js.map +1 -1
- package/build/dist/Server/Services/ServiceLevelObjectiveService.js +12 -1
- package/build/dist/Server/Services/ServiceLevelObjectiveService.js.map +1 -1
- package/build/dist/Server/Services/StatusPagePrivateUserService.js +1 -0
- package/build/dist/Server/Services/StatusPagePrivateUserService.js.map +1 -1
- package/build/dist/Server/Services/StatusPageService.js +230 -32
- package/build/dist/Server/Services/StatusPageService.js.map +1 -1
- package/build/dist/Server/Services/StatusPageSubscriberService.js +4 -0
- package/build/dist/Server/Services/StatusPageSubscriberService.js.map +1 -1
- package/build/dist/Server/Services/TeamMemberService.js +270 -11
- package/build/dist/Server/Services/TeamMemberService.js.map +1 -1
- package/build/dist/Server/Services/TraceAggregationService.js +10 -6
- package/build/dist/Server/Services/TraceAggregationService.js.map +1 -1
- package/build/dist/Server/Services/UserEmailService.js +1 -0
- package/build/dist/Server/Services/UserEmailService.js.map +1 -1
- package/build/dist/Server/Services/UserNotificationMethodAdminService.js +1 -0
- package/build/dist/Server/Services/UserNotificationMethodAdminService.js.map +1 -1
- package/build/dist/Server/Services/UserNotificationRuleAdminService.js +1 -0
- package/build/dist/Server/Services/UserNotificationRuleAdminService.js.map +1 -1
- package/build/dist/Server/Services/UserNotificationRuleService.js +4 -0
- package/build/dist/Server/Services/UserNotificationRuleService.js.map +1 -1
- package/build/dist/Server/Services/UserService.js +107 -1
- package/build/dist/Server/Services/UserService.js.map +1 -1
- package/build/dist/Server/Services/WorkflowVariableService.js +396 -7
- package/build/dist/Server/Services/WorkflowVariableService.js.map +1 -1
- package/build/dist/Server/Services/WorkspaceNotificationRuleService.js +463 -7
- package/build/dist/Server/Services/WorkspaceNotificationRuleService.js.map +1 -1
- package/build/dist/Server/Services/WorkspaceProjectAuthTokenService.js +144 -2
- package/build/dist/Server/Services/WorkspaceProjectAuthTokenService.js.map +1 -1
- package/build/dist/Server/Types/Database/QueryHelper.js +20 -0
- package/build/dist/Server/Types/Database/QueryHelper.js.map +1 -1
- package/build/dist/Server/Types/Markdown.js +394 -27
- package/build/dist/Server/Types/Markdown.js.map +1 -1
- package/build/dist/Server/Utils/AI/ClusterAccess/ClusterAccessContext.js +123 -0
- package/build/dist/Server/Utils/AI/ClusterAccess/ClusterAccessContext.js.map +1 -0
- package/build/dist/Server/Utils/AI/ClusterAccess/KubectlInvestigationToolkit.js +344 -0
- package/build/dist/Server/Utils/AI/ClusterAccess/KubectlInvestigationToolkit.js.map +1 -0
- package/build/dist/Server/Utils/AI/ClusterAccess/KubectlJobRunner.js +587 -0
- package/build/dist/Server/Utils/AI/ClusterAccess/KubectlJobRunner.js.map +1 -0
- package/build/dist/Server/Utils/AI/CodeFix/CodeFixAgentAuth.js +18 -2
- package/build/dist/Server/Utils/AI/CodeFix/CodeFixAgentAuth.js.map +1 -1
- package/build/dist/Server/Utils/AI/Remediation/RemediationCommandTools.js +1380 -239
- package/build/dist/Server/Utils/AI/Remediation/RemediationCommandTools.js.map +1 -1
- package/build/dist/Server/Utils/AI/Remediation/RemediationExecutionRunner.js +1099 -68
- package/build/dist/Server/Utils/AI/Remediation/RemediationExecutionRunner.js.map +1 -1
- package/build/dist/Server/Utils/AI/SRE/AIInvestigationEngine.js +88 -6
- package/build/dist/Server/Utils/AI/SRE/AIInvestigationEngine.js.map +1 -1
- package/build/dist/Server/Utils/AI/SRE/AlertInvestigationRunner.js +45 -11
- package/build/dist/Server/Utils/AI/SRE/AlertInvestigationRunner.js.map +1 -1
- package/build/dist/Server/Utils/AI/SRE/IncidentInvestigationRunner.js +41 -11
- package/build/dist/Server/Utils/AI/SRE/IncidentInvestigationRunner.js.map +1 -1
- package/build/dist/Server/Utils/AI/Toolbox/AIActionTools.js +11 -4
- package/build/dist/Server/Utils/AI/Toolbox/AIActionTools.js.map +1 -1
- package/build/dist/Server/Utils/AI/Toolbox/ResourceTools.js +4 -2
- package/build/dist/Server/Utils/AI/Toolbox/ResourceTools.js.map +1 -1
- package/build/dist/Server/Utils/AutoRemediation/CommandPlanExecutor.js +997 -141
- package/build/dist/Server/Utils/AutoRemediation/CommandPlanExecutor.js.map +1 -1
- package/build/dist/Server/Utils/AutoRemediation/RemediationVerifier.js +299 -4
- package/build/dist/Server/Utils/AutoRemediation/RemediationVerifier.js.map +1 -1
- package/build/dist/Server/Utils/Database/AffectedResourceRelations.js +120 -0
- package/build/dist/Server/Utils/Database/AffectedResourceRelations.js.map +1 -0
- package/build/dist/Server/Utils/Database/ProjectScopedReferenceValidator.js +160 -1
- package/build/dist/Server/Utils/Database/ProjectScopedReferenceValidator.js.map +1 -1
- package/build/dist/Server/Utils/EmailRollup/EmailRollupFlushRunner.js +1 -0
- package/build/dist/Server/Utils/EmailRollup/EmailRollupFlushRunner.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorAlert.js +59 -12
- package/build/dist/Server/Utils/Monitor/MonitorAlert.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaObservationBuilder.js +5 -1
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaObservationBuilder.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorIncident.js +84 -22
- package/build/dist/Server/Utils/Monitor/MonitorIncident.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorPayloadRedaction.js +70 -5
- package/build/dist/Server/Utils/Monitor/MonitorPayloadRedaction.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/ProbeMonitorsNotification.js +249 -0
- package/build/dist/Server/Utils/Monitor/ProbeMonitorsNotification.js.map +1 -0
- package/build/dist/Server/Utils/OnCall/OnCallShiftReminderRunner.js +1 -0
- package/build/dist/Server/Utils/OnCall/OnCallShiftReminderRunner.js.map +1 -1
- package/build/dist/Server/Utils/PushNotificationUtil.js +27 -0
- package/build/dist/Server/Utils/PushNotificationUtil.js.map +1 -1
- package/build/dist/Server/Utils/Rules/OwnerRuleAssignment.js +26 -3
- package/build/dist/Server/Utils/Rules/OwnerRuleAssignment.js.map +1 -1
- package/build/dist/Server/Utils/Runbook/RunbookExecutePermission.js +38 -3
- package/build/dist/Server/Utils/Runbook/RunbookExecutePermission.js.map +1 -1
- package/build/dist/Server/Utils/SessionReplay/SessionReplayReadService.js +143 -23
- package/build/dist/Server/Utils/SessionReplay/SessionReplayReadService.js.map +1 -1
- package/build/dist/Server/Utils/SessionReplay/SessionReplayUserFlowReadService.js +406 -0
- package/build/dist/Server/Utils/SessionReplay/SessionReplayUserFlowReadService.js.map +1 -0
- package/build/dist/Server/Utils/StartServer.js +4 -3
- package/build/dist/Server/Utils/StartServer.js.map +1 -1
- package/build/dist/Server/Utils/TeamMember/ProjectLeaveResourceCleanup.js +382 -0
- package/build/dist/Server/Utils/TeamMember/ProjectLeaveResourceCleanup.js.map +1 -0
- package/build/dist/Server/Utils/TwoFactorBackupCodeNotification.js +1 -0
- package/build/dist/Server/Utils/TwoFactorBackupCodeNotification.js.map +1 -1
- package/build/dist/Server/Utils/UserPermission/UserPermission.js +10 -0
- package/build/dist/Server/Utils/UserPermission/UserPermission.js.map +1 -1
- package/build/dist/Server/Utils/Workflow/OAuth2TokenClient.js +447 -0
- package/build/dist/Server/Utils/Workflow/OAuth2TokenClient.js.map +1 -0
- package/build/dist/Server/Utils/Workflow/WorkflowVariableOAuthToken.js +202 -0
- package/build/dist/Server/Utils/Workflow/WorkflowVariableOAuthToken.js.map +1 -0
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/Alert.js +39 -1
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/Alert.js.map +1 -1
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/AlertEpisode.js +44 -4
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/AlertEpisode.js.map +1 -1
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/Incident.js +150 -191
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/Incident.js.map +1 -1
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/IncidentEpisode.js +44 -4
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/IncidentEpisode.js.map +1 -1
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/Monitor.js +39 -17
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/Monitor.js.map +1 -1
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/ScheduledMaintenance.js +151 -145
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/ScheduledMaintenance.js.map +1 -1
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js +221 -127
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js.map +1 -1
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsServiceUrl.js +91 -0
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsServiceUrl.js.map +1 -0
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/ReactionNoteSync.js +673 -0
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/ReactionNoteSync.js.map +1 -0
- package/build/dist/Server/Utils/Workspace/Slack/Actions/ActionTypes.js +3 -9
- package/build/dist/Server/Utils/Workspace/Slack/Actions/ActionTypes.js.map +1 -1
- package/build/dist/Server/Utils/Workspace/Slack/Actions/Alert.js +65 -166
- package/build/dist/Server/Utils/Workspace/Slack/Actions/Alert.js.map +1 -1
- package/build/dist/Server/Utils/Workspace/Slack/Actions/AlertEpisode.js +63 -157
- package/build/dist/Server/Utils/Workspace/Slack/Actions/AlertEpisode.js.map +1 -1
- package/build/dist/Server/Utils/Workspace/Slack/Actions/Auth.js +23 -3
- package/build/dist/Server/Utils/Workspace/Slack/Actions/Auth.js.map +1 -1
- package/build/dist/Server/Utils/Workspace/Slack/Actions/Authorization.js +92 -0
- package/build/dist/Server/Utils/Workspace/Slack/Actions/Authorization.js.map +1 -0
- package/build/dist/Server/Utils/Workspace/Slack/Actions/Incident.js +81 -210
- package/build/dist/Server/Utils/Workspace/Slack/Actions/Incident.js.map +1 -1
- package/build/dist/Server/Utils/Workspace/Slack/Actions/IncidentEpisode.js +68 -138
- package/build/dist/Server/Utils/Workspace/Slack/Actions/IncidentEpisode.js.map +1 -1
- package/build/dist/Server/Utils/Workspace/Slack/Actions/ReactionNote.js +240 -0
- package/build/dist/Server/Utils/Workspace/Slack/Actions/ReactionNote.js.map +1 -0
- package/build/dist/Server/Utils/Workspace/Slack/Actions/ScheduledMaintenance.js +85 -212
- package/build/dist/Server/Utils/Workspace/Slack/Actions/ScheduledMaintenance.js.map +1 -1
- package/build/dist/Server/Utils/Workspace/Slack/Slack.js +60 -17
- package/build/dist/Server/Utils/Workspace/Slack/Slack.js.map +1 -1
- package/build/dist/Server/Utils/Workspace/Slack/app-manifest.json +2 -0
- package/build/dist/Server/Utils/Workspace/Workspace.js +134 -41
- package/build/dist/Server/Utils/Workspace/Workspace.js.map +1 -1
- package/build/dist/Server/Utils/Workspace/WorkspaceActionAuthorization.js +197 -0
- package/build/dist/Server/Utils/Workspace/WorkspaceActionAuthorization.js.map +1 -0
- package/build/dist/Server/Utils/Workspace/WorkspaceBase.js +32 -0
- package/build/dist/Server/Utils/Workspace/WorkspaceBase.js.map +1 -1
- package/build/dist/Server/Utils/Workspace/WorkspaceOAuthState.js +199 -0
- package/build/dist/Server/Utils/Workspace/WorkspaceOAuthState.js.map +1 -0
- package/build/dist/Server/Utils/Workspace/WorkspaceProjectReferenceValidator.js +91 -0
- package/build/dist/Server/Utils/Workspace/WorkspaceProjectReferenceValidator.js.map +1 -0
- package/build/dist/Server/Utils/Workspace/WorkspaceReactionNote.js +450 -0
- package/build/dist/Server/Utils/Workspace/WorkspaceReactionNote.js.map +1 -0
- package/build/dist/Types/AutoRemediation/AiRemediationCommandPlan.js +103 -5
- package/build/dist/Types/AutoRemediation/AiRemediationCommandPlan.js.map +1 -1
- package/build/dist/Types/Date.js +97 -7
- package/build/dist/Types/Date.js.map +1 -1
- package/build/dist/Types/Email/EmailTemplateType.js +1 -0
- package/build/dist/Types/Email/EmailTemplateType.js.map +1 -1
- package/build/dist/Types/Exception/ExceptionMessages.js +1 -0
- package/build/dist/Types/Exception/ExceptionMessages.js.map +1 -1
- package/build/dist/Types/Kubernetes/KubernetesClusterAiAccess.js +245 -0
- package/build/dist/Types/Kubernetes/KubernetesClusterAiAccess.js.map +1 -0
- package/build/dist/Types/Kubernetes/KubernetesClusterAiAccessPermissions.js +49 -0
- package/build/dist/Types/Kubernetes/KubernetesClusterAiAccessPermissions.js.map +1 -0
- package/build/dist/Types/Kubernetes/KubernetesClusterAiAccessToolNames.js +16 -0
- package/build/dist/Types/Kubernetes/KubernetesClusterAiAccessToolNames.js.map +1 -0
- package/build/dist/Types/Monitor/DatabaseMonitor/SqlServerPlatform.js +104 -0
- package/build/dist/Types/Monitor/DatabaseMonitor/SqlServerPlatform.js.map +1 -0
- package/build/dist/Types/Monitor/KubernetesAlertTemplates.js +6 -5
- package/build/dist/Types/Monitor/KubernetesAlertTemplates.js.map +1 -1
- package/build/dist/Types/Monitor/MonitorStepExceptionMonitor.js +32 -0
- package/build/dist/Types/Monitor/MonitorStepExceptionMonitor.js.map +1 -1
- package/build/dist/Types/Monitor/MonitorUptimeSummary.js +52 -0
- package/build/dist/Types/Monitor/MonitorUptimeSummary.js.map +1 -0
- package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationUtil.js +9 -1
- package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationUtil.js.map +1 -1
- package/build/dist/Types/Rum/SessionReplay.js +52 -2
- package/build/dist/Types/Rum/SessionReplay.js.map +1 -1
- package/build/dist/Types/Rum/SessionReplayApi.js +11 -0
- package/build/dist/Types/Rum/SessionReplayApi.js.map +1 -1
- package/build/dist/Types/Rum/UserFlow.js +115 -0
- package/build/dist/Types/Rum/UserFlow.js.map +1 -0
- package/build/dist/Types/Runbook/RunbookStepType.js +10 -0
- package/build/dist/Types/Runbook/RunbookStepType.js.map +1 -1
- package/build/dist/Types/Runbook/RunnerJobOrigin.js +14 -0
- package/build/dist/Types/Runbook/RunnerJobOrigin.js.map +1 -1
- package/build/dist/Types/SecurityEvent/Connectors/SecurityEventConnectorCatalog.js +2 -2
- package/build/dist/Types/SecurityEvent/Connectors/SecurityEventConnectorCatalog.js.map +1 -1
- package/build/dist/Types/StatusPage/MergedDowntimeTotals.js +2 -0
- package/build/dist/Types/StatusPage/MergedDowntimeTotals.js.map +1 -0
- package/build/dist/Types/StatusPage/PublicNoteSubscriberNotificationDefault.js +65 -0
- package/build/dist/Types/StatusPage/PublicNoteSubscriberNotificationDefault.js.map +1 -0
- package/build/dist/Types/Telemetry/TelemetryIngestSurface.js +8 -0
- package/build/dist/Types/Telemetry/TelemetryIngestSurface.js.map +1 -1
- package/build/dist/Types/Timezone.js +5 -0
- package/build/dist/Types/Timezone.js.map +1 -1
- package/build/dist/Types/TimezoneAlias.js +340 -0
- package/build/dist/Types/TimezoneAlias.js.map +1 -0
- package/build/dist/Types/Workflow/Templates.js +2694 -2
- package/build/dist/Types/Workflow/Templates.js.map +1 -1
- package/build/dist/Types/Workflow/WorkflowVariableOAuth.js +314 -0
- package/build/dist/Types/Workflow/WorkflowVariableOAuth.js.map +1 -0
- package/build/dist/Types/Workspace/WorkspaceNoteReaction.js +98 -0
- package/build/dist/Types/Workspace/WorkspaceNoteReaction.js.map +1 -0
- package/build/dist/UI/Components/AttributesJSON/AttributesJSONPreferences.js +95 -0
- package/build/dist/UI/Components/AttributesJSON/AttributesJSONPreferences.js.map +1 -0
- package/build/dist/UI/Components/AttributesJSON/AttributesJSONView.js +44 -0
- package/build/dist/UI/Components/AttributesJSON/AttributesJSONView.js.map +1 -0
- package/build/dist/UI/Components/AttributesJSON/AttributesViewToggle.js +27 -0
- package/build/dist/UI/Components/AttributesJSON/AttributesViewToggle.js.map +1 -0
- package/build/dist/UI/Components/AttributesJSON/BracesGlyph.js +9 -0
- package/build/dist/UI/Components/AttributesJSON/BracesGlyph.js.map +1 -0
- package/build/dist/UI/Components/AttributesJSON/CopyAttributesAsJSONButton.js +260 -0
- package/build/dist/UI/Components/AttributesJSON/CopyAttributesAsJSONButton.js.map +1 -0
- package/build/dist/UI/Components/AttributesJSON/JSONHighlight.js +56 -0
- package/build/dist/UI/Components/AttributesJSON/JSONHighlight.js.map +1 -0
- package/build/dist/UI/Components/Calendar/Calendar.js +94 -7
- package/build/dist/UI/Components/Calendar/Calendar.js.map +1 -1
- package/build/dist/UI/Components/Calendar/CalendarDayLayout.js +136 -0
- package/build/dist/UI/Components/Calendar/CalendarDayLayout.js.map +1 -0
- package/build/dist/UI/Components/Charts/ChartGroup/ChartGroup.js +1 -1
- package/build/dist/UI/Components/Charts/ChartGroup/ChartGroup.js.map +1 -1
- package/build/dist/UI/Components/Charts/Utils/HistogramSelection.js +72 -0
- package/build/dist/UI/Components/Charts/Utils/HistogramSelection.js.map +1 -0
- package/build/dist/UI/Components/Charts/Utils/useHistogramRangeSelection.js +178 -0
- package/build/dist/UI/Components/Charts/Utils/useHistogramRangeSelection.js.map +1 -0
- package/build/dist/UI/Components/Charts/Utils/useHistogramZoom.js +13 -1
- package/build/dist/UI/Components/Charts/Utils/useHistogramZoom.js.map +1 -1
- package/build/dist/UI/Components/Date/CustomTimeRangeModal.js +20 -4
- package/build/dist/UI/Components/Date/CustomTimeRangeModal.js.map +1 -1
- package/build/dist/UI/Components/Dropdown/Dropdown.js +33 -9
- package/build/dist/UI/Components/Dropdown/Dropdown.js.map +1 -1
- package/build/dist/UI/Components/Forms/Fields/FormField.js +36 -13
- package/build/dist/UI/Components/Forms/Fields/FormField.js.map +1 -1
- package/build/dist/UI/Components/Graphs/DayUptimeGraph.js +117 -11
- package/build/dist/UI/Components/Graphs/DayUptimeGraph.js.map +1 -1
- package/build/dist/UI/Components/Graphs/UptimeBarTooltip.js +5 -1
- package/build/dist/UI/Components/Graphs/UptimeBarTooltip.js.map +1 -1
- package/build/dist/UI/Components/Graphs/UptimeDaySummary.js.map +1 -1
- package/build/dist/UI/Components/LogsViewer/LogsViewer.js +36 -8
- package/build/dist/UI/Components/LogsViewer/LogsViewer.js.map +1 -1
- package/build/dist/UI/Components/LogsViewer/components/ColumnSelector.js +10 -2
- package/build/dist/UI/Components/LogsViewer/components/ColumnSelector.js.map +1 -1
- package/build/dist/UI/Components/LogsViewer/components/KeyboardShortcutsHelp.js +9 -1
- package/build/dist/UI/Components/LogsViewer/components/KeyboardShortcutsHelp.js.map +1 -1
- package/build/dist/UI/Components/LogsViewer/components/LogDetailsPanel.js +16 -15
- package/build/dist/UI/Components/LogsViewer/components/LogDetailsPanel.js.map +1 -1
- package/build/dist/UI/Components/LogsViewer/components/LogsFacetSidebar.js +1 -1
- package/build/dist/UI/Components/LogsViewer/components/LogsFacetSidebar.js.map +1 -1
- package/build/dist/UI/Components/LogsViewer/components/LogsHistogram.js +14 -74
- package/build/dist/UI/Components/LogsViewer/components/LogsHistogram.js.map +1 -1
- package/build/dist/UI/Components/LogsViewer/components/LogsViewerToolbar.js +22 -5
- package/build/dist/UI/Components/LogsViewer/components/LogsViewerToolbar.js.map +1 -1
- package/build/dist/UI/Components/LogsViewer/components/SavedViewsDropdown.js +9 -2
- package/build/dist/UI/Components/LogsViewer/components/SavedViewsDropdown.js.map +1 -1
- package/build/dist/UI/Components/LogsViewer/useLogsHistogram.js +16 -5
- package/build/dist/UI/Components/LogsViewer/useLogsHistogram.js.map +1 -1
- package/build/dist/UI/Components/ModelTable/BaseModelTable.js +23 -8
- package/build/dist/UI/Components/ModelTable/BaseModelTable.js.map +1 -1
- package/build/dist/UI/Components/MonitorGraphs/Uptime.js +7 -1
- package/build/dist/UI/Components/MonitorGraphs/Uptime.js.map +1 -1
- package/build/dist/UI/Components/MonitorGraphs/UptimeBarDayModal.js +5 -1
- package/build/dist/UI/Components/MonitorGraphs/UptimeBarDayModal.js.map +1 -1
- package/build/dist/UI/Components/Page/ModelPage.js +37 -3
- package/build/dist/UI/Components/Page/ModelPage.js.map +1 -1
- package/build/dist/UI/Components/TelemetryViewer/TelemetryViewer.js +27 -6
- package/build/dist/UI/Components/TelemetryViewer/TelemetryViewer.js.map +1 -1
- package/build/dist/UI/Components/TelemetryViewer/components/TelemetryDetailPanel.js +7 -1
- package/build/dist/UI/Components/TelemetryViewer/components/TelemetryDetailPanel.js.map +1 -1
- package/build/dist/UI/Components/TelemetryViewer/components/TelemetryFacetSidebar.js +1 -1
- package/build/dist/UI/Components/TelemetryViewer/components/TelemetryFacetSidebar.js.map +1 -1
- package/build/dist/UI/Components/TelemetryViewer/components/TelemetryHistogram.js +17 -77
- package/build/dist/UI/Components/TelemetryViewer/components/TelemetryHistogram.js.map +1 -1
- package/build/dist/UI/Components/TelemetryViewer/components/TelemetrySearchBar.js +10 -1
- package/build/dist/UI/Components/TelemetryViewer/components/TelemetrySearchBar.js.map +1 -1
- package/build/dist/UI/Utils/ModelAPI/ProjectUsersModelAPI.js +15 -1
- package/build/dist/UI/Utils/ModelAPI/ProjectUsersModelAPI.js.map +1 -1
- package/build/dist/UI/Utils/Timezone.js +52 -17
- package/build/dist/UI/Utils/Timezone.js.map +1 -1
- package/build/dist/Utils/AI/InvestigationReport.js +116 -21
- package/build/dist/Utils/AI/InvestigationReport.js.map +1 -1
- package/build/dist/Utils/AiRemediation/KubectlOutputRedactor.js +1209 -0
- package/build/dist/Utils/AiRemediation/KubectlOutputRedactor.js.map +1 -0
- package/build/dist/Utils/AiRemediation/KubectlPolicy.js +2973 -0
- package/build/dist/Utils/AiRemediation/KubectlPolicy.js.map +1 -0
- package/build/dist/Utils/AiRemediation/KubectlWaitBudget.js +99 -0
- package/build/dist/Utils/AiRemediation/KubectlWaitBudget.js.map +1 -0
- package/build/dist/Utils/AiRemediation/KubectlWriteScope.js +1429 -0
- package/build/dist/Utils/AiRemediation/KubectlWriteScope.js.map +1 -0
- package/build/dist/Utils/Dashboard/Components/DashboardClockComponent.js +7 -6
- package/build/dist/Utils/Dashboard/Components/DashboardClockComponent.js.map +1 -1
- package/build/dist/Utils/Monitor/IncomingEmailMonitorAddress.js +214 -0
- package/build/dist/Utils/Monitor/IncomingEmailMonitorAddress.js.map +1 -0
- package/build/dist/Utils/Monitor/MonitorCheckScheduleUtil.js +471 -0
- package/build/dist/Utils/Monitor/MonitorCheckScheduleUtil.js.map +1 -0
- package/build/dist/Utils/Monitor/MonitorOverviewCriteriaUtil.js +107 -0
- package/build/dist/Utils/Monitor/MonitorOverviewCriteriaUtil.js.map +1 -0
- package/build/dist/Utils/Monitor/MonitorOverviewFamily.js +191 -0
- package/build/dist/Utils/Monitor/MonitorOverviewFamily.js.map +1 -0
- package/build/dist/Utils/Monitor/MonitorOverviewPresentationUtil.js +1259 -0
- package/build/dist/Utils/Monitor/MonitorOverviewPresentationUtil.js.map +1 -0
- package/build/dist/Utils/Monitor/MonitorOverviewProbeUtil.js +593 -0
- package/build/dist/Utils/Monitor/MonitorOverviewProbeUtil.js.map +1 -0
- package/build/dist/Utils/Monitor/MonitorOverviewTargetUtil.js +195 -0
- package/build/dist/Utils/Monitor/MonitorOverviewTargetUtil.js.map +1 -0
- package/build/dist/Utils/Monitor/MonitorStatusHistoryUtil.js +127 -0
- package/build/dist/Utils/Monitor/MonitorStatusHistoryUtil.js.map +1 -0
- package/build/dist/Utils/Monitor/MonitorUptimeSummaryUtil.js +464 -0
- package/build/dist/Utils/Monitor/MonitorUptimeSummaryUtil.js.map +1 -0
- package/build/dist/Utils/Rum/SessionIdentity.js +31 -1
- package/build/dist/Utils/Rum/SessionIdentity.js.map +1 -1
- package/build/dist/Utils/Rum/SessionReplayWireEncoding.js +128 -0
- package/build/dist/Utils/Rum/SessionReplayWireEncoding.js.map +1 -0
- package/build/dist/Utils/Rum/UserFlow.js +941 -0
- package/build/dist/Utils/Rum/UserFlow.js.map +1 -0
- package/build/dist/Utils/StatusPage/MonitorGroupMergedDowntimeUtil.js +82 -0
- package/build/dist/Utils/StatusPage/MonitorGroupMergedDowntimeUtil.js.map +1 -0
- package/build/dist/Utils/StatusPage/ResourceUptime.js +46 -0
- package/build/dist/Utils/StatusPage/ResourceUptime.js.map +1 -1
- package/build/dist/Utils/StatusPage/UptimeDailyAggregateUtil.js +148 -0
- package/build/dist/Utils/StatusPage/UptimeDailyAggregateUtil.js.map +1 -1
- package/build/dist/Utils/Telemetry/AttributesJSON.js +245 -0
- package/build/dist/Utils/Telemetry/AttributesJSON.js.map +1 -0
- package/build/dist/Utils/Uptime/DayUptimeGraphUtil.js +103 -0
- package/build/dist/Utils/Uptime/DayUptimeGraphUtil.js.map +1 -1
- package/build/dist/Utils/Uptime/UptimeUtil.js +91 -27
- package/build/dist/Utils/Uptime/UptimeUtil.js.map +1 -1
- package/jest.config.json +2 -1
- package/package.json +2 -1
- package/tsconfig.tests.json +36 -0
- package/Tests/UI/Components/EmptyState/EmptyStateGuideLinks.test.tsx +0 -337
- package/UI/Components/EmptyState/EmptyStateGuideLinks.tsx +0 -124
- package/build/dist/UI/Components/EmptyState/EmptyStateGuideLinks.js +0 -47
- package/build/dist/UI/Components/EmptyState/EmptyStateGuideLinks.js.map +0 -1
|
@@ -0,0 +1,1361 @@
|
|
|
1
|
+
import AutoRemediationRuleEngineService, {
|
|
2
|
+
ClusterRoundHold,
|
|
3
|
+
DEFAULT_VERIFICATION_WINDOW_MINUTES,
|
|
4
|
+
MAX_CLUSTER_REMEDIATION_ROUNDS_PER_SUBJECT,
|
|
5
|
+
MAX_SUGGESTIONS_PER_SUBJECT,
|
|
6
|
+
getClusterRoundNameSnapshot,
|
|
7
|
+
parseClusterRoundNameSnapshot,
|
|
8
|
+
} from "../../../Server/Services/AutoRemediationRuleEngineService";
|
|
9
|
+
import AutoRemediationRuleService from "../../../Server/Services/AutoRemediationRuleService";
|
|
10
|
+
import AutoRemediationSuggestionService from "../../../Server/Services/AutoRemediationSuggestionService";
|
|
11
|
+
import AlertFeedService from "../../../Server/Services/AlertFeedService";
|
|
12
|
+
import IncidentFeedService from "../../../Server/Services/IncidentFeedService";
|
|
13
|
+
import KubernetesClusterAiAccessService from "../../../Server/Services/KubernetesClusterAiAccessService";
|
|
14
|
+
import ProjectService from "../../../Server/Services/ProjectService";
|
|
15
|
+
import RunnerJobService from "../../../Server/Services/RunnerJobService";
|
|
16
|
+
import AIInvestigationQueue from "../../../Server/Utils/AI/SRE/InvestigationQueue";
|
|
17
|
+
import logger from "../../../Server/Utils/Logger";
|
|
18
|
+
import AutoRemediationSuggestion from "../../../Models/DatabaseModels/AutoRemediationSuggestion";
|
|
19
|
+
import Alert from "../../../Models/DatabaseModels/Alert";
|
|
20
|
+
import Incident from "../../../Models/DatabaseModels/Incident";
|
|
21
|
+
import Project from "../../../Models/DatabaseModels/Project";
|
|
22
|
+
import RunnerJob from "../../../Models/DatabaseModels/RunnerJob";
|
|
23
|
+
import AIRunType from "../../../Types/AI/AIRunType";
|
|
24
|
+
import AutoRemediationExecutionMode from "../../../Types/AutoRemediation/AutoRemediationExecutionMode";
|
|
25
|
+
import AutoRemediationSuggestionStatus from "../../../Types/AutoRemediation/AutoRemediationSuggestionStatus";
|
|
26
|
+
import AutoRemediationSuggestionType from "../../../Types/AutoRemediation/AutoRemediationSuggestionType";
|
|
27
|
+
import AutoRemediationVerificationStatus from "../../../Types/AutoRemediation/AutoRemediationVerificationStatus";
|
|
28
|
+
import {
|
|
29
|
+
KubernetesAiRemediationMode,
|
|
30
|
+
KubernetesClusterAiAccessStatus,
|
|
31
|
+
} from "../../../Types/Kubernetes/KubernetesClusterAiAccess";
|
|
32
|
+
import {
|
|
33
|
+
KUBECTL_ALWAYS_ASKS_SUMMARY,
|
|
34
|
+
KUBECTL_SAFE_CHANGES_SUMMARY,
|
|
35
|
+
} from "../../../Types/AutoRemediation/AiRemediationCommandPlan";
|
|
36
|
+
import ObjectID from "../../../Types/ObjectID";
|
|
37
|
+
import PositiveNumber from "../../../Types/PositiveNumber";
|
|
38
|
+
import { afterEach, beforeEach, describe, expect, it } from "@jest/globals";
|
|
39
|
+
|
|
40
|
+
// A node taint always needs a human, in every mode (the canonical comment).
|
|
41
|
+
const TAINT_WORD_PATTERN: RegExp = /\btaint\b/;
|
|
42
|
+
|
|
43
|
+
/*
|
|
44
|
+
* Contract under test — cluster-level remediation in the rule engine, the
|
|
45
|
+
* lane a cluster's AI page turns on without any AutoRemediationRule:
|
|
46
|
+
*
|
|
47
|
+
* - every remediation-ready cluster the signal is about gets ONE Planning
|
|
48
|
+
* CommandPlan suggestion that carries the cluster id, snapshots the mode
|
|
49
|
+
* (Automatic → FullAuto with auto-resolve, RequireApproval → Suggest) and
|
|
50
|
+
* enqueues a RemediationExecution run linked back onto it;
|
|
51
|
+
* - a cluster that is not ready, or already has a round on this subject,
|
|
52
|
+
* is skipped; the per-subject suggestion cap still applies;
|
|
53
|
+
* - the cluster lane runs BEFORE rules and never depends on a rule
|
|
54
|
+
* matching; a rule read that returns nothing changes nothing;
|
|
55
|
+
* - a failed access lookup skips the lane quietly;
|
|
56
|
+
* - the follow-up round ("ask again") is Suggest for Automatic and
|
|
57
|
+
* RequireApproval clusters, FullAuto again for BypassApproval clusters,
|
|
58
|
+
* and stops at MAX_CLUSTER_REMEDIATION_ROUNDS_PER_SUBJECT for all;
|
|
59
|
+
* - a BypassApproval cluster's rounds do not ask: round 1 and the follow-up
|
|
60
|
+
* are both FullAuto with auto-resolve, and the feed says approvals are
|
|
61
|
+
* bypassed — except for what always needs a human;
|
|
62
|
+
* - the feed states exactly what each round does, in the canonical mode
|
|
63
|
+
* terms: an Automatic round runs safe (and allowlisted) changes on its
|
|
64
|
+
* own and a riskier change never runs on its own — a round that finds
|
|
65
|
+
* only riskier fixes proposes exactly those for one-click approval (the
|
|
66
|
+
* execution runner settles a round that ran nothing but refused riskier
|
|
67
|
+
* changes as an approval card for exactly those), and after safe fixes
|
|
68
|
+
* a riskier one is proposed only if verification fails; in both
|
|
69
|
+
* unattended modes a protected-namespace write, a node drain and a node
|
|
70
|
+
* taint always need a human, and the round becomes a proposal when the
|
|
71
|
+
* breaker trips or another unattended round holds the cluster;
|
|
72
|
+
* - at most one UNATTENDED round per cluster at a time, whatever the
|
|
73
|
+
* subject: a round that would run unattended while another round on the
|
|
74
|
+
* same cluster is still running or verifying its fix is created asking
|
|
75
|
+
* first — the alert and the incident of one monitor never both change a
|
|
76
|
+
* cluster at once. A failed check asks first too;
|
|
77
|
+
* - a follow-up forced to ask (its predecessor's rollback did not complete)
|
|
78
|
+
* asks first even on a BypassApproval cluster, and says why;
|
|
79
|
+
* - the in-flight round check and the cluster-round name snapshot helpers
|
|
80
|
+
* classify exactly what they claim to.
|
|
81
|
+
*/
|
|
82
|
+
|
|
83
|
+
const PROJECT_ID: ObjectID = new ObjectID(
|
|
84
|
+
"22222222-2222-4222-8222-222222222222",
|
|
85
|
+
);
|
|
86
|
+
const INCIDENT_ID: ObjectID = new ObjectID(
|
|
87
|
+
"cccccccc-cccc-4ccc-8ccc-cccccccccccc",
|
|
88
|
+
);
|
|
89
|
+
const ALERT_ID: ObjectID = new ObjectID("dddddddd-dddd-4ddd-8ddd-dddddddddddd");
|
|
90
|
+
const CLUSTER_ID: ObjectID = new ObjectID(
|
|
91
|
+
"33333333-3333-4333-8333-333333333333",
|
|
92
|
+
);
|
|
93
|
+
const SUGGESTION_ID: ObjectID = new ObjectID(
|
|
94
|
+
"77777777-7777-4777-8777-777777777777",
|
|
95
|
+
);
|
|
96
|
+
const AI_RUN_ID: ObjectID = new ObjectID(
|
|
97
|
+
"88888888-8888-4888-8888-888888888888",
|
|
98
|
+
);
|
|
99
|
+
|
|
100
|
+
function readyCluster(
|
|
101
|
+
overrides: Partial<KubernetesClusterAiAccessStatus> = {},
|
|
102
|
+
): KubernetesClusterAiAccessStatus {
|
|
103
|
+
return {
|
|
104
|
+
clusterId: CLUSTER_ID.toString(),
|
|
105
|
+
clusterName: "prod-us",
|
|
106
|
+
runner: {
|
|
107
|
+
id: "44444444-4444-4444-8444-444444444444",
|
|
108
|
+
name: "kubernetes-agent/prod-us",
|
|
109
|
+
isOnline: true,
|
|
110
|
+
canRunAiCommands: true,
|
|
111
|
+
},
|
|
112
|
+
accessMethod: "in_cluster",
|
|
113
|
+
kubectlAllowlist: [],
|
|
114
|
+
isInvestigationEnabled: true,
|
|
115
|
+
isInvestigationReady: true,
|
|
116
|
+
remediationMode: KubernetesAiRemediationMode.Automatic,
|
|
117
|
+
isRemediationReady: true,
|
|
118
|
+
gaps: [],
|
|
119
|
+
evaluatedAt: new Date().toISOString(),
|
|
120
|
+
...overrides,
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function fakeIncident(): Incident {
|
|
125
|
+
return {
|
|
126
|
+
id: INCIDENT_ID,
|
|
127
|
+
_id: INCIDENT_ID.toString(),
|
|
128
|
+
projectId: PROJECT_ID,
|
|
129
|
+
title: "Pods stuck in Pending",
|
|
130
|
+
monitors: [],
|
|
131
|
+
labels: [],
|
|
132
|
+
} as unknown as Incident;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
let createdSuggestions: Array<AutoRemediationSuggestion>;
|
|
136
|
+
let suggestionUpdates: Array<Record<string, unknown>>;
|
|
137
|
+
let enqueue: jest.SpyInstance;
|
|
138
|
+
|
|
139
|
+
function mockBaseline(data: {
|
|
140
|
+
existing?: Array<AutoRemediationSuggestion> | undefined;
|
|
141
|
+
statuses?: Array<KubernetesClusterAiAccessStatus> | undefined;
|
|
142
|
+
}): void {
|
|
143
|
+
createdSuggestions = [];
|
|
144
|
+
suggestionUpdates = [];
|
|
145
|
+
|
|
146
|
+
jest.spyOn(logger, "error").mockImplementation((): void => {
|
|
147
|
+
return undefined;
|
|
148
|
+
});
|
|
149
|
+
jest.spyOn(logger, "warn").mockImplementation((): void => {
|
|
150
|
+
return undefined;
|
|
151
|
+
});
|
|
152
|
+
jest.spyOn(logger, "debug").mockImplementation((): void => {
|
|
153
|
+
return undefined;
|
|
154
|
+
});
|
|
155
|
+
jest.spyOn(ProjectService, "findOneById").mockResolvedValue({
|
|
156
|
+
enableAi: true,
|
|
157
|
+
enableAutoRemediation: true,
|
|
158
|
+
enableAiCommandExecution: true,
|
|
159
|
+
} as unknown as Project);
|
|
160
|
+
jest
|
|
161
|
+
.spyOn(AutoRemediationSuggestionService, "findBy")
|
|
162
|
+
.mockResolvedValue(data.existing || []);
|
|
163
|
+
jest
|
|
164
|
+
.spyOn(AutoRemediationSuggestionService, "create")
|
|
165
|
+
.mockImplementation(
|
|
166
|
+
async (args: unknown): Promise<AutoRemediationSuggestion> => {
|
|
167
|
+
const suggestion: AutoRemediationSuggestion = (
|
|
168
|
+
args as { data: AutoRemediationSuggestion }
|
|
169
|
+
).data;
|
|
170
|
+
suggestion.id = SUGGESTION_ID;
|
|
171
|
+
createdSuggestions.push(suggestion);
|
|
172
|
+
return suggestion;
|
|
173
|
+
},
|
|
174
|
+
);
|
|
175
|
+
jest
|
|
176
|
+
.spyOn(AutoRemediationSuggestionService, "updateOneById")
|
|
177
|
+
.mockImplementation(async (args: unknown): Promise<never> => {
|
|
178
|
+
suggestionUpdates.push((args as { data: Record<string, unknown> }).data);
|
|
179
|
+
return undefined as never;
|
|
180
|
+
});
|
|
181
|
+
jest
|
|
182
|
+
.spyOn(KubernetesClusterAiAccessService, "getStatusesForSubject")
|
|
183
|
+
.mockResolvedValue(data.statuses || [readyCluster()]);
|
|
184
|
+
enqueue = jest
|
|
185
|
+
.spyOn(AIInvestigationQueue, "enqueue")
|
|
186
|
+
.mockResolvedValue(AI_RUN_ID);
|
|
187
|
+
jest.spyOn(AutoRemediationRuleService, "findBy").mockResolvedValue([]);
|
|
188
|
+
jest
|
|
189
|
+
.spyOn(IncidentFeedService, "createIncidentFeedItem")
|
|
190
|
+
.mockResolvedValue(undefined as never);
|
|
191
|
+
jest
|
|
192
|
+
.spyOn(AlertFeedService, "createAlertFeedItem")
|
|
193
|
+
.mockResolvedValue(undefined as never);
|
|
194
|
+
/*
|
|
195
|
+
* The in-flight check also reads the AI kubectl jobs on the cluster (a
|
|
196
|
+
* rule-driven run that changed it holds it too): none unless a test
|
|
197
|
+
* says otherwise.
|
|
198
|
+
*/
|
|
199
|
+
jest.spyOn(RunnerJobService, "findBy").mockResolvedValue([]);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
describe("AutoRemediationRuleEngineService cluster-level remediation", () => {
|
|
203
|
+
afterEach(() => {
|
|
204
|
+
jest.restoreAllMocks();
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
it("starts a FullAuto command run for an Automatic cluster with no rule involved", async () => {
|
|
208
|
+
mockBaseline({});
|
|
209
|
+
|
|
210
|
+
await AutoRemediationRuleEngineService.applyRulesToIncident(fakeIncident());
|
|
211
|
+
|
|
212
|
+
expect(createdSuggestions).toHaveLength(1);
|
|
213
|
+
const suggestion: AutoRemediationSuggestion = createdSuggestions[0]!;
|
|
214
|
+
expect(suggestion.kubernetesClusterId?.toString()).toBe(
|
|
215
|
+
CLUSTER_ID.toString(),
|
|
216
|
+
);
|
|
217
|
+
expect(suggestion.autoRemediationRuleId).toBeUndefined();
|
|
218
|
+
expect(suggestion.status).toBe(AutoRemediationSuggestionStatus.Planning);
|
|
219
|
+
expect(suggestion.suggestionType).toBe(
|
|
220
|
+
AutoRemediationSuggestionType.CommandPlan,
|
|
221
|
+
);
|
|
222
|
+
expect(suggestion.executionMode).toBe(
|
|
223
|
+
AutoRemediationExecutionMode.FullAuto,
|
|
224
|
+
);
|
|
225
|
+
expect(suggestion.autoResolveOnRecovery).toBe(true);
|
|
226
|
+
expect(suggestion.verificationWindowMinutes).toBe(
|
|
227
|
+
DEFAULT_VERIFICATION_WINDOW_MINUTES,
|
|
228
|
+
);
|
|
229
|
+
expect(suggestion.ruleNameSnapshot).toBe(
|
|
230
|
+
'AI remediation for cluster "prod-us"',
|
|
231
|
+
);
|
|
232
|
+
expect(suggestion.incidentId?.toString()).toBe(INCIDENT_ID.toString());
|
|
233
|
+
|
|
234
|
+
expect(enqueue).toHaveBeenCalledTimes(1);
|
|
235
|
+
expect(enqueue.mock.calls[0]![0]).toMatchObject({
|
|
236
|
+
projectId: PROJECT_ID,
|
|
237
|
+
subjectIncidentId: INCIDENT_ID,
|
|
238
|
+
subjectAutoRemediationSuggestionId: SUGGESTION_ID,
|
|
239
|
+
remediationRunType: AIRunType.RemediationExecution,
|
|
240
|
+
});
|
|
241
|
+
expect(suggestionUpdates).toContainEqual({ aiRunId: AI_RUN_ID });
|
|
242
|
+
expect(IncidentFeedService.createIncidentFeedItem).toHaveBeenCalledTimes(1);
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
it("starts a Suggest run without auto-resolve for a RequireApproval cluster, on an alert", async () => {
|
|
246
|
+
mockBaseline({
|
|
247
|
+
statuses: [
|
|
248
|
+
readyCluster({
|
|
249
|
+
remediationMode: KubernetesAiRemediationMode.RequireApproval,
|
|
250
|
+
}),
|
|
251
|
+
],
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
await AutoRemediationRuleEngineService.applyRulesToAlert({
|
|
255
|
+
id: ALERT_ID,
|
|
256
|
+
_id: ALERT_ID.toString(),
|
|
257
|
+
projectId: PROJECT_ID,
|
|
258
|
+
title: "Pods stuck in Pending",
|
|
259
|
+
} as unknown as Alert);
|
|
260
|
+
|
|
261
|
+
expect(createdSuggestions).toHaveLength(1);
|
|
262
|
+
expect(createdSuggestions[0]!.executionMode).toBe(
|
|
263
|
+
AutoRemediationExecutionMode.Suggest,
|
|
264
|
+
);
|
|
265
|
+
expect(createdSuggestions[0]!.autoResolveOnRecovery).toBe(false);
|
|
266
|
+
expect(createdSuggestions[0]!.alertId?.toString()).toBe(
|
|
267
|
+
ALERT_ID.toString(),
|
|
268
|
+
);
|
|
269
|
+
expect(enqueue.mock.calls[0]![0]).toMatchObject({
|
|
270
|
+
subjectAlertId: ALERT_ID,
|
|
271
|
+
});
|
|
272
|
+
expect(AlertFeedService.createAlertFeedItem).toHaveBeenCalledTimes(1);
|
|
273
|
+
});
|
|
274
|
+
|
|
275
|
+
it("starts a FullAuto run with auto-resolve for a BypassApproval cluster and says approvals are bypassed", async () => {
|
|
276
|
+
mockBaseline({
|
|
277
|
+
statuses: [
|
|
278
|
+
readyCluster({
|
|
279
|
+
remediationMode: KubernetesAiRemediationMode.BypassApproval,
|
|
280
|
+
}),
|
|
281
|
+
],
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
await AutoRemediationRuleEngineService.applyRulesToIncident(fakeIncident());
|
|
285
|
+
|
|
286
|
+
expect(createdSuggestions).toHaveLength(1);
|
|
287
|
+
expect(createdSuggestions[0]!.executionMode).toBe(
|
|
288
|
+
AutoRemediationExecutionMode.FullAuto,
|
|
289
|
+
);
|
|
290
|
+
expect(createdSuggestions[0]!.autoResolveOnRecovery).toBe(true);
|
|
291
|
+
expect(createdSuggestions[0]!.ruleNameSnapshot).toBe(
|
|
292
|
+
'AI remediation for cluster "prod-us"',
|
|
293
|
+
);
|
|
294
|
+
expect(enqueue).toHaveBeenCalledTimes(1);
|
|
295
|
+
|
|
296
|
+
const feed: jest.SpyInstance =
|
|
297
|
+
IncidentFeedService.createIncidentFeedItem as unknown as jest.SpyInstance;
|
|
298
|
+
expect(feed).toHaveBeenCalledTimes(1);
|
|
299
|
+
const markdown: string = (
|
|
300
|
+
feed.mock.calls[0]![0] as { feedInfoInMarkdown: string }
|
|
301
|
+
).feedInfoInMarkdown;
|
|
302
|
+
expect(markdown).toContain("Approvals are bypassed");
|
|
303
|
+
expect(markdown).not.toContain("riskier changes will ask");
|
|
304
|
+
expect(markdown).not.toContain("for approval");
|
|
305
|
+
});
|
|
306
|
+
|
|
307
|
+
it("skips a cluster that is not remediation-ready", async () => {
|
|
308
|
+
mockBaseline({
|
|
309
|
+
statuses: [readyCluster({ isRemediationReady: false })],
|
|
310
|
+
});
|
|
311
|
+
|
|
312
|
+
await AutoRemediationRuleEngineService.applyRulesToIncident(fakeIncident());
|
|
313
|
+
|
|
314
|
+
expect(createdSuggestions).toHaveLength(0);
|
|
315
|
+
expect(enqueue).not.toHaveBeenCalled();
|
|
316
|
+
});
|
|
317
|
+
|
|
318
|
+
it("does not start a second round for a cluster that already has a suggestion on this subject", async () => {
|
|
319
|
+
mockBaseline({
|
|
320
|
+
existing: [
|
|
321
|
+
{
|
|
322
|
+
id: SUGGESTION_ID,
|
|
323
|
+
_id: SUGGESTION_ID.toString(),
|
|
324
|
+
kubernetesClusterId: CLUSTER_ID,
|
|
325
|
+
} as unknown as AutoRemediationSuggestion,
|
|
326
|
+
],
|
|
327
|
+
});
|
|
328
|
+
|
|
329
|
+
await AutoRemediationRuleEngineService.applyRulesToIncident(fakeIncident());
|
|
330
|
+
|
|
331
|
+
expect(createdSuggestions).toHaveLength(0);
|
|
332
|
+
});
|
|
333
|
+
|
|
334
|
+
it("respects the per-subject suggestion cap", async () => {
|
|
335
|
+
const existing: Array<AutoRemediationSuggestion> = [];
|
|
336
|
+
for (let i: number = 0; i < MAX_SUGGESTIONS_PER_SUBJECT; i++) {
|
|
337
|
+
existing.push({
|
|
338
|
+
id: ObjectID.generate(),
|
|
339
|
+
_id: ObjectID.generate().toString(),
|
|
340
|
+
} as unknown as AutoRemediationSuggestion);
|
|
341
|
+
}
|
|
342
|
+
mockBaseline({ existing });
|
|
343
|
+
|
|
344
|
+
await AutoRemediationRuleEngineService.applyRulesToIncident(fakeIncident());
|
|
345
|
+
|
|
346
|
+
expect(createdSuggestions).toHaveLength(0);
|
|
347
|
+
expect(AutoRemediationRuleService.findBy).not.toHaveBeenCalled();
|
|
348
|
+
});
|
|
349
|
+
|
|
350
|
+
it("settles the suggestion as NoneApplicable when the run cannot be queued", async () => {
|
|
351
|
+
mockBaseline({});
|
|
352
|
+
enqueue.mockResolvedValue(null);
|
|
353
|
+
|
|
354
|
+
await AutoRemediationRuleEngineService.applyRulesToIncident(fakeIncident());
|
|
355
|
+
|
|
356
|
+
expect(createdSuggestions).toHaveLength(1);
|
|
357
|
+
expect(suggestionUpdates[0]).toMatchObject({
|
|
358
|
+
status: AutoRemediationSuggestionStatus.NoneApplicable,
|
|
359
|
+
});
|
|
360
|
+
});
|
|
361
|
+
|
|
362
|
+
it("skips the lane quietly when the access lookup fails and still evaluates rules", async () => {
|
|
363
|
+
mockBaseline({});
|
|
364
|
+
(
|
|
365
|
+
KubernetesClusterAiAccessService.getStatusesForSubject as unknown as jest.SpyInstance
|
|
366
|
+
).mockRejectedValue(new Error("db down"));
|
|
367
|
+
|
|
368
|
+
await AutoRemediationRuleEngineService.applyRulesToIncident(fakeIncident());
|
|
369
|
+
|
|
370
|
+
expect(createdSuggestions).toHaveLength(0);
|
|
371
|
+
expect(AutoRemediationRuleService.findBy).toHaveBeenCalledTimes(1);
|
|
372
|
+
});
|
|
373
|
+
});
|
|
374
|
+
|
|
375
|
+
describe("AutoRemediationRuleEngineService.startFollowUpClusterRemediation", () => {
|
|
376
|
+
let getStatusForCluster: jest.SpyInstance;
|
|
377
|
+
|
|
378
|
+
beforeEach(() => {
|
|
379
|
+
mockBaseline({});
|
|
380
|
+
getStatusForCluster = jest
|
|
381
|
+
.spyOn(KubernetesClusterAiAccessService, "getStatusForCluster")
|
|
382
|
+
.mockResolvedValue(readyCluster());
|
|
383
|
+
});
|
|
384
|
+
|
|
385
|
+
afterEach(() => {
|
|
386
|
+
jest.restoreAllMocks();
|
|
387
|
+
});
|
|
388
|
+
|
|
389
|
+
it("starts a Suggest round even on an Automatic cluster and labels it as round 2", async () => {
|
|
390
|
+
jest
|
|
391
|
+
.spyOn(AutoRemediationSuggestionService, "countBy")
|
|
392
|
+
.mockResolvedValue(new PositiveNumber(1));
|
|
393
|
+
|
|
394
|
+
const started: boolean =
|
|
395
|
+
await AutoRemediationRuleEngineService.startFollowUpClusterRemediation({
|
|
396
|
+
projectId: PROJECT_ID,
|
|
397
|
+
kubernetesClusterId: CLUSTER_ID,
|
|
398
|
+
incidentId: INCIDENT_ID,
|
|
399
|
+
});
|
|
400
|
+
|
|
401
|
+
expect(started).toBe(true);
|
|
402
|
+
expect(createdSuggestions).toHaveLength(1);
|
|
403
|
+
expect(createdSuggestions[0]!.executionMode).toBe(
|
|
404
|
+
AutoRemediationExecutionMode.Suggest,
|
|
405
|
+
);
|
|
406
|
+
expect(createdSuggestions[0]!.autoResolveOnRecovery).toBe(false);
|
|
407
|
+
expect(createdSuggestions[0]!.ruleNameSnapshot).toContain("round 2");
|
|
408
|
+
expect(enqueue).toHaveBeenCalledTimes(1);
|
|
409
|
+
});
|
|
410
|
+
|
|
411
|
+
it("runs the follow-up round unattended again on a BypassApproval cluster", async () => {
|
|
412
|
+
jest
|
|
413
|
+
.spyOn(AutoRemediationSuggestionService, "countBy")
|
|
414
|
+
.mockResolvedValue(new PositiveNumber(1));
|
|
415
|
+
getStatusForCluster.mockResolvedValue(
|
|
416
|
+
readyCluster({
|
|
417
|
+
remediationMode: KubernetesAiRemediationMode.BypassApproval,
|
|
418
|
+
}),
|
|
419
|
+
);
|
|
420
|
+
|
|
421
|
+
const started: boolean =
|
|
422
|
+
await AutoRemediationRuleEngineService.startFollowUpClusterRemediation({
|
|
423
|
+
projectId: PROJECT_ID,
|
|
424
|
+
kubernetesClusterId: CLUSTER_ID,
|
|
425
|
+
incidentId: INCIDENT_ID,
|
|
426
|
+
});
|
|
427
|
+
|
|
428
|
+
expect(started).toBe(true);
|
|
429
|
+
expect(createdSuggestions).toHaveLength(1);
|
|
430
|
+
expect(createdSuggestions[0]!.executionMode).toBe(
|
|
431
|
+
AutoRemediationExecutionMode.FullAuto,
|
|
432
|
+
);
|
|
433
|
+
expect(createdSuggestions[0]!.autoResolveOnRecovery).toBe(true);
|
|
434
|
+
expect(createdSuggestions[0]!.ruleNameSnapshot).toContain("round 2");
|
|
435
|
+
|
|
436
|
+
const markdown: string = (
|
|
437
|
+
(
|
|
438
|
+
IncidentFeedService.createIncidentFeedItem as unknown as jest.SpyInstance
|
|
439
|
+
).mock.calls[0]![0] as { feedInfoInMarkdown: string }
|
|
440
|
+
).feedInfoInMarkdown;
|
|
441
|
+
expect(markdown).toContain("round 2");
|
|
442
|
+
expect(markdown).toContain("Approvals are bypassed");
|
|
443
|
+
expect(markdown).not.toContain("for approval");
|
|
444
|
+
});
|
|
445
|
+
|
|
446
|
+
it("still stops the BypassApproval follow-up at the round cap", async () => {
|
|
447
|
+
jest
|
|
448
|
+
.spyOn(AutoRemediationSuggestionService, "countBy")
|
|
449
|
+
.mockResolvedValue(
|
|
450
|
+
new PositiveNumber(MAX_CLUSTER_REMEDIATION_ROUNDS_PER_SUBJECT),
|
|
451
|
+
);
|
|
452
|
+
getStatusForCluster.mockResolvedValue(
|
|
453
|
+
readyCluster({
|
|
454
|
+
remediationMode: KubernetesAiRemediationMode.BypassApproval,
|
|
455
|
+
}),
|
|
456
|
+
);
|
|
457
|
+
|
|
458
|
+
expect(
|
|
459
|
+
await AutoRemediationRuleEngineService.startFollowUpClusterRemediation({
|
|
460
|
+
projectId: PROJECT_ID,
|
|
461
|
+
kubernetesClusterId: CLUSTER_ID,
|
|
462
|
+
incidentId: INCIDENT_ID,
|
|
463
|
+
}),
|
|
464
|
+
).toBe(false);
|
|
465
|
+
expect(createdSuggestions).toHaveLength(0);
|
|
466
|
+
});
|
|
467
|
+
|
|
468
|
+
it("stops asking once the round cap is spent", async () => {
|
|
469
|
+
jest
|
|
470
|
+
.spyOn(AutoRemediationSuggestionService, "countBy")
|
|
471
|
+
.mockResolvedValue(
|
|
472
|
+
new PositiveNumber(MAX_CLUSTER_REMEDIATION_ROUNDS_PER_SUBJECT),
|
|
473
|
+
);
|
|
474
|
+
|
|
475
|
+
const started: boolean =
|
|
476
|
+
await AutoRemediationRuleEngineService.startFollowUpClusterRemediation({
|
|
477
|
+
projectId: PROJECT_ID,
|
|
478
|
+
kubernetesClusterId: CLUSTER_ID,
|
|
479
|
+
incidentId: INCIDENT_ID,
|
|
480
|
+
});
|
|
481
|
+
|
|
482
|
+
expect(started).toBe(false);
|
|
483
|
+
expect(createdSuggestions).toHaveLength(0);
|
|
484
|
+
expect(getStatusForCluster).not.toHaveBeenCalled();
|
|
485
|
+
});
|
|
486
|
+
|
|
487
|
+
it("does nothing when the cluster is no longer ready or auto-remediation is off", async () => {
|
|
488
|
+
jest
|
|
489
|
+
.spyOn(AutoRemediationSuggestionService, "countBy")
|
|
490
|
+
.mockResolvedValue(new PositiveNumber(1));
|
|
491
|
+
getStatusForCluster.mockResolvedValue(
|
|
492
|
+
readyCluster({ isRemediationReady: false }),
|
|
493
|
+
);
|
|
494
|
+
|
|
495
|
+
expect(
|
|
496
|
+
await AutoRemediationRuleEngineService.startFollowUpClusterRemediation({
|
|
497
|
+
projectId: PROJECT_ID,
|
|
498
|
+
kubernetesClusterId: CLUSTER_ID,
|
|
499
|
+
alertId: ALERT_ID,
|
|
500
|
+
}),
|
|
501
|
+
).toBe(false);
|
|
502
|
+
|
|
503
|
+
(
|
|
504
|
+
ProjectService.findOneById as unknown as jest.SpyInstance
|
|
505
|
+
).mockResolvedValue({ enableAutoRemediation: false } as unknown as Project);
|
|
506
|
+
|
|
507
|
+
expect(
|
|
508
|
+
await AutoRemediationRuleEngineService.startFollowUpClusterRemediation({
|
|
509
|
+
projectId: PROJECT_ID,
|
|
510
|
+
kubernetesClusterId: CLUSTER_ID,
|
|
511
|
+
alertId: ALERT_ID,
|
|
512
|
+
}),
|
|
513
|
+
).toBe(false);
|
|
514
|
+
|
|
515
|
+
expect(createdSuggestions).toHaveLength(0);
|
|
516
|
+
});
|
|
517
|
+
});
|
|
518
|
+
|
|
519
|
+
describe("AutoRemediationRuleEngineService cluster feed copy states exactly what each round does", () => {
|
|
520
|
+
afterEach(() => {
|
|
521
|
+
jest.restoreAllMocks();
|
|
522
|
+
});
|
|
523
|
+
|
|
524
|
+
function incidentFeedMarkdown(): string {
|
|
525
|
+
const feed: jest.SpyInstance =
|
|
526
|
+
IncidentFeedService.createIncidentFeedItem as unknown as jest.SpyInstance;
|
|
527
|
+
expect(feed).toHaveBeenCalledTimes(1);
|
|
528
|
+
return (feed.mock.calls[0]![0] as { feedInfoInMarkdown: string })
|
|
529
|
+
.feedInfoInMarkdown;
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
async function followUp(mode: KubernetesAiRemediationMode): Promise<string> {
|
|
533
|
+
mockBaseline({});
|
|
534
|
+
jest
|
|
535
|
+
.spyOn(AutoRemediationSuggestionService, "countBy")
|
|
536
|
+
.mockResolvedValue(new PositiveNumber(1));
|
|
537
|
+
jest
|
|
538
|
+
.spyOn(KubernetesClusterAiAccessService, "getStatusForCluster")
|
|
539
|
+
.mockResolvedValue(readyCluster({ remediationMode: mode }));
|
|
540
|
+
|
|
541
|
+
expect(
|
|
542
|
+
await AutoRemediationRuleEngineService.startFollowUpClusterRemediation({
|
|
543
|
+
projectId: PROJECT_ID,
|
|
544
|
+
kubernetesClusterId: CLUSTER_ID,
|
|
545
|
+
incidentId: INCIDENT_ID,
|
|
546
|
+
}),
|
|
547
|
+
).toBe(true);
|
|
548
|
+
|
|
549
|
+
return incidentFeedMarkdown();
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
it("Automatic, round 1: safe changes run on their own; a riskier change never runs on its own — it is proposed for one-click approval", async () => {
|
|
553
|
+
/*
|
|
554
|
+
* Changed with the "Automatic proposes the riskier fix" fix: this copy
|
|
555
|
+
* used to say a riskier change is "neither run nor proposed in this
|
|
556
|
+
* round". A round that ran nothing but refused a riskier change now
|
|
557
|
+
* ends as an approval card for it, so the copy promises exactly that.
|
|
558
|
+
*/
|
|
559
|
+
mockBaseline({
|
|
560
|
+
statuses: [
|
|
561
|
+
readyCluster({
|
|
562
|
+
remediationMode: KubernetesAiRemediationMode.Automatic,
|
|
563
|
+
}),
|
|
564
|
+
],
|
|
565
|
+
});
|
|
566
|
+
|
|
567
|
+
await AutoRemediationRuleEngineService.applyRulesToIncident(fakeIncident());
|
|
568
|
+
|
|
569
|
+
const markdown: string = incidentFeedMarkdown();
|
|
570
|
+
expect(markdown).toContain("Automatic remediation is on for this cluster");
|
|
571
|
+
expect(markdown).toContain("on its own");
|
|
572
|
+
/*
|
|
573
|
+
* The shared SafeWrite wording (PR #3953 round-two review): one named
|
|
574
|
+
* object, and never "delete a named pod or job" — deleting a job is a
|
|
575
|
+
* riskier change.
|
|
576
|
+
*/
|
|
577
|
+
expect(markdown).toContain(KUBECTL_SAFE_CHANGES_SUMMARY);
|
|
578
|
+
expect(markdown).not.toContain("pod or job");
|
|
579
|
+
expect(markdown).toContain("cluster's kubectl allowlist");
|
|
580
|
+
expect(markdown).toContain("A riskier change never runs on its own");
|
|
581
|
+
/*
|
|
582
|
+
* Changed in the round-three review: "AI proposes it for your one-click
|
|
583
|
+
* approval instead" was unconditional. The canonical Automatic
|
|
584
|
+
* semantics have two cases — a round that finds only riskier fixes
|
|
585
|
+
* proposes exactly those; after safe fixes, a riskier one is proposed
|
|
586
|
+
* only if verification shows the service did not recover — and the
|
|
587
|
+
* every-mode rules (a protected-namespace write, a node drain and a
|
|
588
|
+
* node taint always need a human; the breaker or another round's hold
|
|
589
|
+
* turns the round into a proposal) apply to Automatic too.
|
|
590
|
+
*/
|
|
591
|
+
expect(markdown).toContain(
|
|
592
|
+
"if the round finds only riskier fixes, AI proposes exactly those for your one-click approval",
|
|
593
|
+
);
|
|
594
|
+
expect(markdown).toContain(
|
|
595
|
+
"a riskier fix is proposed only if verification shows the service did not recover",
|
|
596
|
+
);
|
|
597
|
+
expect(markdown).toContain(
|
|
598
|
+
"riskier changes whose shape the cluster's kubectl allowlist names",
|
|
599
|
+
);
|
|
600
|
+
expect(markdown.toLowerCase()).toContain(
|
|
601
|
+
KUBECTL_ALWAYS_ASKS_SUMMARY.toLowerCase(),
|
|
602
|
+
);
|
|
603
|
+
expect(markdown).toMatch(TAINT_WORD_PATTERN);
|
|
604
|
+
expect(markdown).toContain("hourly circuit breaker for this cluster trips");
|
|
605
|
+
expect(markdown).toContain(
|
|
606
|
+
"another unattended OneUptime AI round already holds the cluster",
|
|
607
|
+
);
|
|
608
|
+
expect(markdown).toContain("destructive commands never run");
|
|
609
|
+
expect(markdown).not.toContain("proposes it for your one-click approval");
|
|
610
|
+
expect(markdown).not.toContain("neither run nor proposed");
|
|
611
|
+
expect(markdown).not.toContain("asks first");
|
|
612
|
+
expect(markdown).not.toContain("bypassed");
|
|
613
|
+
});
|
|
614
|
+
|
|
615
|
+
it("Automatic, round 2: the follow-up asks first — nothing runs until the new plan is approved", async () => {
|
|
616
|
+
const markdown: string = await followUp(
|
|
617
|
+
KubernetesAiRemediationMode.Automatic,
|
|
618
|
+
);
|
|
619
|
+
|
|
620
|
+
expect(markdown).toContain("round 2");
|
|
621
|
+
expect(markdown).toContain("did not recover the service");
|
|
622
|
+
expect(markdown).toContain("nothing runs until you approve the new plan");
|
|
623
|
+
expect(markdown).not.toContain("on its own");
|
|
624
|
+
expect(markdown).not.toContain("recommendations");
|
|
625
|
+
});
|
|
626
|
+
|
|
627
|
+
it("RequireApproval, round 1: nothing runs until the plan is approved", async () => {
|
|
628
|
+
mockBaseline({
|
|
629
|
+
statuses: [
|
|
630
|
+
readyCluster({
|
|
631
|
+
remediationMode: KubernetesAiRemediationMode.RequireApproval,
|
|
632
|
+
}),
|
|
633
|
+
],
|
|
634
|
+
});
|
|
635
|
+
|
|
636
|
+
await AutoRemediationRuleEngineService.applyRulesToIncident(fakeIncident());
|
|
637
|
+
|
|
638
|
+
const markdown: string = incidentFeedMarkdown();
|
|
639
|
+
expect(markdown).toContain("composing a kubectl fix");
|
|
640
|
+
expect(markdown).toContain("Nothing runs until you approve the plan");
|
|
641
|
+
expect(markdown).not.toContain("on its own");
|
|
642
|
+
});
|
|
643
|
+
|
|
644
|
+
it("RequireApproval, round 2: the follow-up asks again", async () => {
|
|
645
|
+
const markdown: string = await followUp(
|
|
646
|
+
KubernetesAiRemediationMode.RequireApproval,
|
|
647
|
+
);
|
|
648
|
+
|
|
649
|
+
expect(markdown).toContain("round 2");
|
|
650
|
+
expect(markdown).toContain("nothing runs until you approve the new plan");
|
|
651
|
+
expect(markdown).not.toContain("on its own");
|
|
652
|
+
});
|
|
653
|
+
|
|
654
|
+
it("BypassApproval, round 1 and 2: every allowed change runs on its own, riskier ones included, destructive never", async () => {
|
|
655
|
+
mockBaseline({
|
|
656
|
+
statuses: [
|
|
657
|
+
readyCluster({
|
|
658
|
+
remediationMode: KubernetesAiRemediationMode.BypassApproval,
|
|
659
|
+
}),
|
|
660
|
+
],
|
|
661
|
+
});
|
|
662
|
+
|
|
663
|
+
await AutoRemediationRuleEngineService.applyRulesToIncident(fakeIncident());
|
|
664
|
+
|
|
665
|
+
const first: string = incidentFeedMarkdown();
|
|
666
|
+
expect(first).toContain("Approvals are bypassed for this cluster");
|
|
667
|
+
expect(first).toContain("safe or riskier");
|
|
668
|
+
expect(first).toContain("without asking");
|
|
669
|
+
expect(first).toContain("destructive commands never run");
|
|
670
|
+
// Bypass approval still asks for what needs a human in every mode.
|
|
671
|
+
expect(first).toContain(KUBECTL_ALWAYS_ASKS_SUMMARY);
|
|
672
|
+
expect(first).toMatch(TAINT_WORD_PATTERN);
|
|
673
|
+
/*
|
|
674
|
+
* ...and a Bypass round still becomes a proposal when the breaker trips
|
|
675
|
+
* or another unattended round holds the cluster (the canonical
|
|
676
|
+
* KubernetesAiRemediationMode comment's Bypass exceptions).
|
|
677
|
+
*/
|
|
678
|
+
expect(first).toContain("hourly circuit breaker for this cluster trips");
|
|
679
|
+
expect(first).toContain(
|
|
680
|
+
"another unattended OneUptime AI round already holds the cluster",
|
|
681
|
+
);
|
|
682
|
+
expect(first).toContain("this round becomes a proposal");
|
|
683
|
+
expect(first).not.toContain("approve");
|
|
684
|
+
expect(first).not.toContain("recommendations");
|
|
685
|
+
|
|
686
|
+
jest.restoreAllMocks();
|
|
687
|
+
|
|
688
|
+
const second: string = await followUp(
|
|
689
|
+
KubernetesAiRemediationMode.BypassApproval,
|
|
690
|
+
);
|
|
691
|
+
expect(second).toContain("round 2");
|
|
692
|
+
expect(second).toContain("runs on its own");
|
|
693
|
+
expect(second).toContain("safe or riskier");
|
|
694
|
+
expect(second).toContain("destructive commands never run");
|
|
695
|
+
expect(second).toContain(KUBECTL_ALWAYS_ASKS_SUMMARY);
|
|
696
|
+
expect(second).toContain("this round becomes a proposal");
|
|
697
|
+
expect(second).not.toContain("approve");
|
|
698
|
+
});
|
|
699
|
+
});
|
|
700
|
+
|
|
701
|
+
/*
|
|
702
|
+
* The other rounds on the cluster, as the in-flight round check reads them
|
|
703
|
+
* (its query names the cluster; the per-subject dedupe's does not).
|
|
704
|
+
*/
|
|
705
|
+
function mockRoundsOnCluster(
|
|
706
|
+
rows: Array<Record<string, unknown>>,
|
|
707
|
+
existing: Array<AutoRemediationSuggestion> = [],
|
|
708
|
+
): jest.SpyInstance {
|
|
709
|
+
return (
|
|
710
|
+
AutoRemediationSuggestionService.findBy as unknown as jest.SpyInstance
|
|
711
|
+
).mockImplementation(
|
|
712
|
+
async (args: unknown): Promise<Array<AutoRemediationSuggestion>> => {
|
|
713
|
+
const query: Record<string, unknown> =
|
|
714
|
+
(args as { query?: Record<string, unknown> }).query || {};
|
|
715
|
+
return (query["kubernetesClusterId"]
|
|
716
|
+
? rows
|
|
717
|
+
: existing) as unknown as Array<AutoRemediationSuggestion>;
|
|
718
|
+
},
|
|
719
|
+
);
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
function roundOnCluster(
|
|
723
|
+
overrides: Record<string, unknown> = {},
|
|
724
|
+
): Record<string, unknown> {
|
|
725
|
+
const id: ObjectID = ObjectID.generate();
|
|
726
|
+
return {
|
|
727
|
+
id,
|
|
728
|
+
_id: id.toString(),
|
|
729
|
+
status: AutoRemediationSuggestionStatus.AutoExecuted,
|
|
730
|
+
executionMode: AutoRemediationExecutionMode.FullAuto,
|
|
731
|
+
verificationStatus: AutoRemediationVerificationStatus.Pending,
|
|
732
|
+
verificationDeadlineAt: new Date(Date.now() + 10 * 60 * 1000),
|
|
733
|
+
incidentId: INCIDENT_ID,
|
|
734
|
+
ruleNameSnapshot: 'AI remediation for cluster "prod-us"',
|
|
735
|
+
createdAt: new Date(Date.now() - 5 * 60 * 1000),
|
|
736
|
+
...overrides,
|
|
737
|
+
};
|
|
738
|
+
}
|
|
739
|
+
|
|
740
|
+
describe("AutoRemediationRuleEngineService — one unattended round per cluster at a time", () => {
|
|
741
|
+
afterEach(() => {
|
|
742
|
+
jest.restoreAllMocks();
|
|
743
|
+
});
|
|
744
|
+
|
|
745
|
+
async function startAlertRound(): Promise<string> {
|
|
746
|
+
await AutoRemediationRuleEngineService.applyRulesToAlert({
|
|
747
|
+
id: ALERT_ID,
|
|
748
|
+
_id: ALERT_ID.toString(),
|
|
749
|
+
projectId: PROJECT_ID,
|
|
750
|
+
title: "Pods stuck in Pending",
|
|
751
|
+
} as unknown as Alert);
|
|
752
|
+
|
|
753
|
+
const feed: jest.SpyInstance =
|
|
754
|
+
AlertFeedService.createAlertFeedItem as unknown as jest.SpyInstance;
|
|
755
|
+
expect(feed).toHaveBeenCalledTimes(1);
|
|
756
|
+
return (feed.mock.calls[0]![0] as { feedInfoInMarkdown: string })
|
|
757
|
+
.feedInfoInMarkdown;
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
it("creates the alert's round ASKING FIRST while the incident's round on the same cluster is still being verified — the alert and the incident of one monitor", async () => {
|
|
761
|
+
mockBaseline({});
|
|
762
|
+
const holdRead: jest.SpyInstance = mockRoundsOnCluster([roundOnCluster()]);
|
|
763
|
+
|
|
764
|
+
const markdown: string = await startAlertRound();
|
|
765
|
+
|
|
766
|
+
expect(createdSuggestions).toHaveLength(1);
|
|
767
|
+
expect(createdSuggestions[0]!.executionMode).toBe(
|
|
768
|
+
AutoRemediationExecutionMode.Suggest,
|
|
769
|
+
);
|
|
770
|
+
expect(createdSuggestions[0]!.autoResolveOnRecovery).toBe(false);
|
|
771
|
+
expect(markdown).toContain(
|
|
772
|
+
"This round asks first because another OneUptime AI round on this cluster applied a fix that is still being verified",
|
|
773
|
+
);
|
|
774
|
+
expect(markdown).toContain("nothing runs until you approve the plan");
|
|
775
|
+
expect(markdown).not.toContain("on its own");
|
|
776
|
+
|
|
777
|
+
// The check read this cluster, in this project, across subjects.
|
|
778
|
+
const query: Record<string, unknown> = (
|
|
779
|
+
holdRead.mock.calls.find((call: Array<unknown>) => {
|
|
780
|
+
return Boolean(
|
|
781
|
+
(call[0] as { query: Record<string, unknown> }).query[
|
|
782
|
+
"kubernetesClusterId"
|
|
783
|
+
],
|
|
784
|
+
);
|
|
785
|
+
})![0] as { query: Record<string, unknown> }
|
|
786
|
+
).query;
|
|
787
|
+
expect((query["kubernetesClusterId"] as ObjectID).toString()).toBe(
|
|
788
|
+
CLUSTER_ID.toString(),
|
|
789
|
+
);
|
|
790
|
+
expect((query["projectId"] as ObjectID).toString()).toBe(
|
|
791
|
+
PROJECT_ID.toString(),
|
|
792
|
+
);
|
|
793
|
+
expect(query["incidentId"]).toBeUndefined();
|
|
794
|
+
expect(query["alertId"]).toBeUndefined();
|
|
795
|
+
});
|
|
796
|
+
|
|
797
|
+
it("asks first while another round on the cluster is still running unattended — on a BypassApproval cluster too", async () => {
|
|
798
|
+
mockBaseline({
|
|
799
|
+
statuses: [
|
|
800
|
+
readyCluster({
|
|
801
|
+
remediationMode: KubernetesAiRemediationMode.BypassApproval,
|
|
802
|
+
}),
|
|
803
|
+
],
|
|
804
|
+
});
|
|
805
|
+
mockRoundsOnCluster([
|
|
806
|
+
roundOnCluster({
|
|
807
|
+
status: AutoRemediationSuggestionStatus.Planning,
|
|
808
|
+
verificationStatus: undefined,
|
|
809
|
+
verificationDeadlineAt: undefined,
|
|
810
|
+
createdAt: new Date(Date.now() - 60 * 1000),
|
|
811
|
+
}),
|
|
812
|
+
]);
|
|
813
|
+
|
|
814
|
+
const markdown: string = await startAlertRound();
|
|
815
|
+
|
|
816
|
+
expect(createdSuggestions[0]!.executionMode).toBe(
|
|
817
|
+
AutoRemediationExecutionMode.Suggest,
|
|
818
|
+
);
|
|
819
|
+
expect(markdown).toContain("is still running unattended");
|
|
820
|
+
expect(markdown).not.toContain("Approvals are bypassed");
|
|
821
|
+
});
|
|
822
|
+
|
|
823
|
+
it("creates the alert's round ASKING FIRST while a rule-driven run on the monitor's incident still has its fix on the cluster under verification", async () => {
|
|
824
|
+
mockBaseline({});
|
|
825
|
+
const ruleRunId: ObjectID = ObjectID.generate();
|
|
826
|
+
(
|
|
827
|
+
AutoRemediationSuggestionService.findBy as unknown as jest.SpyInstance
|
|
828
|
+
).mockImplementation(
|
|
829
|
+
async (args: unknown): Promise<Array<AutoRemediationSuggestion>> => {
|
|
830
|
+
const query: Record<string, unknown> =
|
|
831
|
+
(args as { query?: Record<string, unknown> }).query || {};
|
|
832
|
+
if (!query["_id"]) {
|
|
833
|
+
return [];
|
|
834
|
+
}
|
|
835
|
+
return [
|
|
836
|
+
{
|
|
837
|
+
id: ruleRunId,
|
|
838
|
+
_id: ruleRunId.toString(),
|
|
839
|
+
status: AutoRemediationSuggestionStatus.AutoExecuted,
|
|
840
|
+
executionMode: AutoRemediationExecutionMode.FullAuto,
|
|
841
|
+
verificationStatus: AutoRemediationVerificationStatus.Pending,
|
|
842
|
+
verificationDeadlineAt: new Date(Date.now() + 10 * 60 * 1000),
|
|
843
|
+
incidentId: INCIDENT_ID,
|
|
844
|
+
ruleNameSnapshot: "Restart web on 5xx",
|
|
845
|
+
createdAt: new Date(Date.now() - 5 * 60 * 1000),
|
|
846
|
+
},
|
|
847
|
+
] as unknown as Array<AutoRemediationSuggestion>;
|
|
848
|
+
},
|
|
849
|
+
);
|
|
850
|
+
(RunnerJobService.findBy as unknown as jest.SpyInstance).mockResolvedValue([
|
|
851
|
+
{
|
|
852
|
+
id: ObjectID.generate(),
|
|
853
|
+
autoRemediationSuggestionId: ruleRunId,
|
|
854
|
+
stepId: "ai-command-1",
|
|
855
|
+
} as unknown as RunnerJob,
|
|
856
|
+
]);
|
|
857
|
+
|
|
858
|
+
const markdown: string = await startAlertRound();
|
|
859
|
+
|
|
860
|
+
expect(createdSuggestions[0]!.executionMode).toBe(
|
|
861
|
+
AutoRemediationExecutionMode.Suggest,
|
|
862
|
+
);
|
|
863
|
+
expect(markdown).toContain(
|
|
864
|
+
"This round asks first because another OneUptime AI round on this cluster applied a fix that is still being verified",
|
|
865
|
+
);
|
|
866
|
+
});
|
|
867
|
+
|
|
868
|
+
it("negative control: with no rule-driven kubectl job on the cluster the alert's round runs unattended", async () => {
|
|
869
|
+
mockBaseline({});
|
|
870
|
+
|
|
871
|
+
const markdown: string = await startAlertRound();
|
|
872
|
+
|
|
873
|
+
expect(createdSuggestions[0]!.executionMode).toBe(
|
|
874
|
+
AutoRemediationExecutionMode.FullAuto,
|
|
875
|
+
);
|
|
876
|
+
expect(markdown).toContain("Automatic remediation is on for this cluster");
|
|
877
|
+
});
|
|
878
|
+
|
|
879
|
+
it("asks first when the in-flight round check itself fails", async () => {
|
|
880
|
+
mockBaseline({});
|
|
881
|
+
(
|
|
882
|
+
AutoRemediationSuggestionService.findBy as unknown as jest.SpyInstance
|
|
883
|
+
).mockImplementation(
|
|
884
|
+
async (args: unknown): Promise<Array<AutoRemediationSuggestion>> => {
|
|
885
|
+
const query: Record<string, unknown> =
|
|
886
|
+
(args as { query?: Record<string, unknown> }).query || {};
|
|
887
|
+
if (query["kubernetesClusterId"]) {
|
|
888
|
+
throw new Error("db down");
|
|
889
|
+
}
|
|
890
|
+
return [];
|
|
891
|
+
},
|
|
892
|
+
);
|
|
893
|
+
|
|
894
|
+
const markdown: string = await startAlertRound();
|
|
895
|
+
|
|
896
|
+
expect(createdSuggestions[0]!.executionMode).toBe(
|
|
897
|
+
AutoRemediationExecutionMode.Suggest,
|
|
898
|
+
);
|
|
899
|
+
expect(markdown).toContain(
|
|
900
|
+
"OneUptime AI could not confirm that no other AI round is changing this cluster",
|
|
901
|
+
);
|
|
902
|
+
});
|
|
903
|
+
|
|
904
|
+
it.each([
|
|
905
|
+
[
|
|
906
|
+
"a verified fix",
|
|
907
|
+
{
|
|
908
|
+
verificationStatus: AutoRemediationVerificationStatus.Verified,
|
|
909
|
+
},
|
|
910
|
+
],
|
|
911
|
+
[
|
|
912
|
+
"a fix whose verification deadline passed long ago (the verifier is not running)",
|
|
913
|
+
{
|
|
914
|
+
verificationDeadlineAt: new Date(Date.now() - 60 * 60 * 1000),
|
|
915
|
+
},
|
|
916
|
+
],
|
|
917
|
+
[
|
|
918
|
+
"a round stuck in Planning for hours",
|
|
919
|
+
{
|
|
920
|
+
status: AutoRemediationSuggestionStatus.Planning,
|
|
921
|
+
verificationStatus: undefined,
|
|
922
|
+
createdAt: new Date(Date.now() - 3 * 60 * 60 * 1000),
|
|
923
|
+
},
|
|
924
|
+
],
|
|
925
|
+
[
|
|
926
|
+
"a round that only asks",
|
|
927
|
+
{
|
|
928
|
+
status: AutoRemediationSuggestionStatus.Planning,
|
|
929
|
+
executionMode: AutoRemediationExecutionMode.Suggest,
|
|
930
|
+
verificationStatus: undefined,
|
|
931
|
+
},
|
|
932
|
+
],
|
|
933
|
+
])(
|
|
934
|
+
"negative control: %s does not hold the cluster — the round runs unattended as its mode says",
|
|
935
|
+
async (_label: string, overrides: Record<string, unknown>) => {
|
|
936
|
+
mockBaseline({});
|
|
937
|
+
mockRoundsOnCluster([roundOnCluster(overrides)]);
|
|
938
|
+
|
|
939
|
+
const markdown: string = await startAlertRound();
|
|
940
|
+
|
|
941
|
+
expect(createdSuggestions[0]!.executionMode).toBe(
|
|
942
|
+
AutoRemediationExecutionMode.FullAuto,
|
|
943
|
+
);
|
|
944
|
+
expect(createdSuggestions[0]!.autoResolveOnRecovery).toBe(true);
|
|
945
|
+
expect(markdown).toContain(
|
|
946
|
+
"Automatic remediation is on for this cluster",
|
|
947
|
+
);
|
|
948
|
+
},
|
|
949
|
+
);
|
|
950
|
+
|
|
951
|
+
it("negative control: a cluster that asks for approval never needs the check — its round asks anyway", async () => {
|
|
952
|
+
mockBaseline({
|
|
953
|
+
statuses: [
|
|
954
|
+
readyCluster({
|
|
955
|
+
remediationMode: KubernetesAiRemediationMode.RequireApproval,
|
|
956
|
+
}),
|
|
957
|
+
],
|
|
958
|
+
});
|
|
959
|
+
const holdRead: jest.SpyInstance = mockRoundsOnCluster([roundOnCluster()]);
|
|
960
|
+
|
|
961
|
+
await startAlertRound();
|
|
962
|
+
|
|
963
|
+
expect(createdSuggestions[0]!.executionMode).toBe(
|
|
964
|
+
AutoRemediationExecutionMode.Suggest,
|
|
965
|
+
);
|
|
966
|
+
expect(
|
|
967
|
+
holdRead.mock.calls.some((call: Array<unknown>) => {
|
|
968
|
+
return Boolean(
|
|
969
|
+
(call[0] as { query: Record<string, unknown> }).query[
|
|
970
|
+
"kubernetesClusterId"
|
|
971
|
+
],
|
|
972
|
+
);
|
|
973
|
+
}),
|
|
974
|
+
).toBe(false);
|
|
975
|
+
});
|
|
976
|
+
});
|
|
977
|
+
|
|
978
|
+
describe("AutoRemediationRuleEngineService.startFollowUpClusterRemediation — forced to ask first", () => {
|
|
979
|
+
beforeEach(() => {
|
|
980
|
+
mockBaseline({});
|
|
981
|
+
jest
|
|
982
|
+
.spyOn(AutoRemediationSuggestionService, "countBy")
|
|
983
|
+
.mockResolvedValue(new PositiveNumber(1));
|
|
984
|
+
jest
|
|
985
|
+
.spyOn(KubernetesClusterAiAccessService, "getStatusForCluster")
|
|
986
|
+
.mockResolvedValue(
|
|
987
|
+
readyCluster({
|
|
988
|
+
remediationMode: KubernetesAiRemediationMode.BypassApproval,
|
|
989
|
+
}),
|
|
990
|
+
);
|
|
991
|
+
});
|
|
992
|
+
|
|
993
|
+
afterEach(() => {
|
|
994
|
+
jest.restoreAllMocks();
|
|
995
|
+
});
|
|
996
|
+
|
|
997
|
+
it("asks first on a BypassApproval cluster when the previous round's rollback did not complete, and says why", async () => {
|
|
998
|
+
const started: boolean =
|
|
999
|
+
await AutoRemediationRuleEngineService.startFollowUpClusterRemediation({
|
|
1000
|
+
projectId: PROJECT_ID,
|
|
1001
|
+
kubernetesClusterId: CLUSTER_ID,
|
|
1002
|
+
incidentId: INCIDENT_ID,
|
|
1003
|
+
forceSuggest: true,
|
|
1004
|
+
});
|
|
1005
|
+
|
|
1006
|
+
expect(started).toBe(true);
|
|
1007
|
+
expect(createdSuggestions[0]!.executionMode).toBe(
|
|
1008
|
+
AutoRemediationExecutionMode.Suggest,
|
|
1009
|
+
);
|
|
1010
|
+
expect(createdSuggestions[0]!.autoResolveOnRecovery).toBe(false);
|
|
1011
|
+
expect(createdSuggestions[0]!.ruleNameSnapshot).toContain("round 2");
|
|
1012
|
+
|
|
1013
|
+
const markdown: string = (
|
|
1014
|
+
(
|
|
1015
|
+
IncidentFeedService.createIncidentFeedItem as unknown as jest.SpyInstance
|
|
1016
|
+
).mock.calls[0]![0] as { feedInfoInMarkdown: string }
|
|
1017
|
+
).feedInfoInMarkdown;
|
|
1018
|
+
expect(markdown).toContain("round 2");
|
|
1019
|
+
expect(markdown).toContain(
|
|
1020
|
+
"This round asks first because the previous fix's rollback did not complete",
|
|
1021
|
+
);
|
|
1022
|
+
expect(markdown).not.toContain("Approvals are bypassed");
|
|
1023
|
+
});
|
|
1024
|
+
|
|
1025
|
+
it("uses the reason it was given", async () => {
|
|
1026
|
+
await AutoRemediationRuleEngineService.startFollowUpClusterRemediation({
|
|
1027
|
+
projectId: PROJECT_ID,
|
|
1028
|
+
kubernetesClusterId: CLUSTER_ID,
|
|
1029
|
+
incidentId: INCIDENT_ID,
|
|
1030
|
+
forceSuggest: true,
|
|
1031
|
+
forceSuggestReason: "a human must look first",
|
|
1032
|
+
});
|
|
1033
|
+
|
|
1034
|
+
const markdown: string = (
|
|
1035
|
+
(
|
|
1036
|
+
IncidentFeedService.createIncidentFeedItem as unknown as jest.SpyInstance
|
|
1037
|
+
).mock.calls[0]![0] as { feedInfoInMarkdown: string }
|
|
1038
|
+
).feedInfoInMarkdown;
|
|
1039
|
+
expect(markdown).toContain("asks first because a human must look first");
|
|
1040
|
+
});
|
|
1041
|
+
|
|
1042
|
+
it("negative control: without forceSuggest the BypassApproval follow-up runs unattended, as before", async () => {
|
|
1043
|
+
await AutoRemediationRuleEngineService.startFollowUpClusterRemediation({
|
|
1044
|
+
projectId: PROJECT_ID,
|
|
1045
|
+
kubernetesClusterId: CLUSTER_ID,
|
|
1046
|
+
incidentId: INCIDENT_ID,
|
|
1047
|
+
});
|
|
1048
|
+
|
|
1049
|
+
expect(createdSuggestions[0]!.executionMode).toBe(
|
|
1050
|
+
AutoRemediationExecutionMode.FullAuto,
|
|
1051
|
+
);
|
|
1052
|
+
expect(createdSuggestions[0]!.autoResolveOnRecovery).toBe(true);
|
|
1053
|
+
});
|
|
1054
|
+
});
|
|
1055
|
+
|
|
1056
|
+
describe("AutoRemediationRuleEngineService.findRoundHoldingCluster", () => {
|
|
1057
|
+
const MINE: ObjectID = new ObjectID("12121212-1212-4212-8212-121212121212");
|
|
1058
|
+
const NOW: number = Date.now();
|
|
1059
|
+
|
|
1060
|
+
afterEach(() => {
|
|
1061
|
+
jest.restoreAllMocks();
|
|
1062
|
+
});
|
|
1063
|
+
|
|
1064
|
+
function holding(
|
|
1065
|
+
rows: Array<Record<string, unknown>>,
|
|
1066
|
+
data: {
|
|
1067
|
+
anyOrder?: boolean;
|
|
1068
|
+
subject?: { incidentId?: ObjectID; alertId?: ObjectID };
|
|
1069
|
+
} = {},
|
|
1070
|
+
): Promise<ClusterRoundHold | null> {
|
|
1071
|
+
jest
|
|
1072
|
+
.spyOn(AutoRemediationSuggestionService, "findBy")
|
|
1073
|
+
.mockResolvedValue(rows as unknown as Array<AutoRemediationSuggestion>);
|
|
1074
|
+
jest.spyOn(RunnerJobService, "findBy").mockResolvedValue([]);
|
|
1075
|
+
return AutoRemediationRuleEngineService.findRoundHoldingCluster({
|
|
1076
|
+
projectId: PROJECT_ID,
|
|
1077
|
+
clusterId: CLUSTER_ID.toString(),
|
|
1078
|
+
forRound: { suggestionId: MINE, createdAt: new Date(NOW - 1000) },
|
|
1079
|
+
...data,
|
|
1080
|
+
});
|
|
1081
|
+
}
|
|
1082
|
+
|
|
1083
|
+
it("never holds a cluster against the round itself", async () => {
|
|
1084
|
+
expect(
|
|
1085
|
+
await holding([
|
|
1086
|
+
roundOnCluster({
|
|
1087
|
+
id: MINE,
|
|
1088
|
+
_id: MINE.toString(),
|
|
1089
|
+
status: AutoRemediationSuggestionStatus.Planning,
|
|
1090
|
+
}),
|
|
1091
|
+
]),
|
|
1092
|
+
).toBeNull();
|
|
1093
|
+
});
|
|
1094
|
+
|
|
1095
|
+
it("orders Planning unattended rounds: an earlier one holds, a later one does not — unless any order counts", async () => {
|
|
1096
|
+
const earlier: Record<string, unknown> = roundOnCluster({
|
|
1097
|
+
status: AutoRemediationSuggestionStatus.Planning,
|
|
1098
|
+
verificationStatus: undefined,
|
|
1099
|
+
createdAt: new Date(NOW - 5000),
|
|
1100
|
+
});
|
|
1101
|
+
const later: Record<string, unknown> = roundOnCluster({
|
|
1102
|
+
status: AutoRemediationSuggestionStatus.Planning,
|
|
1103
|
+
verificationStatus: undefined,
|
|
1104
|
+
createdAt: new Date(NOW),
|
|
1105
|
+
});
|
|
1106
|
+
|
|
1107
|
+
expect((await holding([earlier]))?.description).toContain(
|
|
1108
|
+
"still running unattended",
|
|
1109
|
+
);
|
|
1110
|
+
expect(await holding([later])).toBeNull();
|
|
1111
|
+
expect(await holding([later], { anyOrder: true })).not.toBeNull();
|
|
1112
|
+
});
|
|
1113
|
+
|
|
1114
|
+
it("holds for the same signal's round that is still composing — asking or not — only when a subject is given", async () => {
|
|
1115
|
+
const composing: Record<string, unknown> = roundOnCluster({
|
|
1116
|
+
status: AutoRemediationSuggestionStatus.Planning,
|
|
1117
|
+
executionMode: AutoRemediationExecutionMode.Suggest,
|
|
1118
|
+
verificationStatus: undefined,
|
|
1119
|
+
});
|
|
1120
|
+
|
|
1121
|
+
const sameSignal: ClusterRoundHold | null = await holding([composing], {
|
|
1122
|
+
subject: { incidentId: INCIDENT_ID },
|
|
1123
|
+
});
|
|
1124
|
+
expect(sameSignal?.isSameSubject).toBe(true);
|
|
1125
|
+
expect(sameSignal?.description).toContain("same signal");
|
|
1126
|
+
|
|
1127
|
+
expect(
|
|
1128
|
+
await holding([composing], { subject: { alertId: ALERT_ID } }),
|
|
1129
|
+
).toBeNull();
|
|
1130
|
+
expect(await holding([composing])).toBeNull();
|
|
1131
|
+
});
|
|
1132
|
+
|
|
1133
|
+
it("holds while an Approved (human-approved) fix is still being verified", async () => {
|
|
1134
|
+
expect(
|
|
1135
|
+
(
|
|
1136
|
+
await holding([
|
|
1137
|
+
roundOnCluster({ status: AutoRemediationSuggestionStatus.Approved }),
|
|
1138
|
+
])
|
|
1139
|
+
)?.description,
|
|
1140
|
+
).toContain("still being verified");
|
|
1141
|
+
});
|
|
1142
|
+
|
|
1143
|
+
/*
|
|
1144
|
+
* A rule-driven run carries no cluster id; its kubectl jobs do. One that
|
|
1145
|
+
* changed the cluster holds it like a cluster round would (PR #3953
|
|
1146
|
+
* review, remediation-r2-04) — so "one unattended AI run per cluster at a
|
|
1147
|
+
* time" holds in both directions.
|
|
1148
|
+
*/
|
|
1149
|
+
describe("a rule-driven run found through its kubectl jobs on the cluster", () => {
|
|
1150
|
+
const RULE_RUN: ObjectID = new ObjectID(
|
|
1151
|
+
"abababab-abab-4bab-8bab-abababababab",
|
|
1152
|
+
);
|
|
1153
|
+
|
|
1154
|
+
function ruleRun(
|
|
1155
|
+
overrides: Record<string, unknown> = {},
|
|
1156
|
+
): Record<string, unknown> {
|
|
1157
|
+
return {
|
|
1158
|
+
id: RULE_RUN,
|
|
1159
|
+
_id: RULE_RUN.toString(),
|
|
1160
|
+
status: AutoRemediationSuggestionStatus.AutoExecuted,
|
|
1161
|
+
executionMode: AutoRemediationExecutionMode.FullAuto,
|
|
1162
|
+
verificationStatus: AutoRemediationVerificationStatus.Pending,
|
|
1163
|
+
verificationDeadlineAt: new Date(NOW + 10 * 60 * 1000),
|
|
1164
|
+
incidentId: INCIDENT_ID,
|
|
1165
|
+
ruleNameSnapshot: "Restart web on 5xx",
|
|
1166
|
+
createdAt: new Date(NOW - 5 * 60 * 1000),
|
|
1167
|
+
...overrides,
|
|
1168
|
+
};
|
|
1169
|
+
}
|
|
1170
|
+
|
|
1171
|
+
function holdingThroughJobs(data: {
|
|
1172
|
+
jobs: Array<{ suggestionId: ObjectID; stepId: string }>;
|
|
1173
|
+
runs: Array<Record<string, unknown>>;
|
|
1174
|
+
forRound?: ObjectID | undefined;
|
|
1175
|
+
}): {
|
|
1176
|
+
hold: Promise<ClusterRoundHold | null>;
|
|
1177
|
+
runRead: jest.SpyInstance;
|
|
1178
|
+
} {
|
|
1179
|
+
const runRead: jest.SpyInstance = jest
|
|
1180
|
+
.spyOn(AutoRemediationSuggestionService, "findBy")
|
|
1181
|
+
.mockImplementation(
|
|
1182
|
+
async (args: unknown): Promise<Array<AutoRemediationSuggestion>> => {
|
|
1183
|
+
const query: Record<string, unknown> =
|
|
1184
|
+
(args as { query?: Record<string, unknown> }).query || {};
|
|
1185
|
+
// No cluster round on the cluster; the runs behind the jobs by id.
|
|
1186
|
+
return (query["kubernetesClusterId"]
|
|
1187
|
+
? []
|
|
1188
|
+
: data.runs) as unknown as Array<AutoRemediationSuggestion>;
|
|
1189
|
+
},
|
|
1190
|
+
);
|
|
1191
|
+
jest.spyOn(RunnerJobService, "findBy").mockResolvedValue(
|
|
1192
|
+
data.jobs.map(
|
|
1193
|
+
(job: { suggestionId: ObjectID; stepId: string }): RunnerJob => {
|
|
1194
|
+
return {
|
|
1195
|
+
id: ObjectID.generate(),
|
|
1196
|
+
autoRemediationSuggestionId: job.suggestionId,
|
|
1197
|
+
stepId: job.stepId,
|
|
1198
|
+
} as unknown as RunnerJob;
|
|
1199
|
+
},
|
|
1200
|
+
),
|
|
1201
|
+
);
|
|
1202
|
+
|
|
1203
|
+
return {
|
|
1204
|
+
hold: AutoRemediationRuleEngineService.findRoundHoldingCluster({
|
|
1205
|
+
projectId: PROJECT_ID,
|
|
1206
|
+
clusterId: CLUSTER_ID.toString(),
|
|
1207
|
+
forRound: {
|
|
1208
|
+
suggestionId: data.forRound || MINE,
|
|
1209
|
+
createdAt: new Date(NOW - 1000),
|
|
1210
|
+
},
|
|
1211
|
+
}),
|
|
1212
|
+
runRead,
|
|
1213
|
+
};
|
|
1214
|
+
}
|
|
1215
|
+
|
|
1216
|
+
it("holds while its fix on the cluster is still being verified, naming the run", async () => {
|
|
1217
|
+
const hold: ClusterRoundHold | null = await holdingThroughJobs({
|
|
1218
|
+
jobs: [{ suggestionId: RULE_RUN, stepId: "ai-command-1" }],
|
|
1219
|
+
runs: [ruleRun()],
|
|
1220
|
+
}).hold;
|
|
1221
|
+
|
|
1222
|
+
expect(hold?.suggestionId).toBe(RULE_RUN.toString());
|
|
1223
|
+
expect(hold?.ruleNameSnapshot).toBe("Restart web on 5xx");
|
|
1224
|
+
expect(hold?.description).toBe(
|
|
1225
|
+
"applied a fix that is still being verified",
|
|
1226
|
+
);
|
|
1227
|
+
});
|
|
1228
|
+
|
|
1229
|
+
it("holds while it is still running and already changed the cluster — created after the asking round, without anyOrder", async () => {
|
|
1230
|
+
const hold: ClusterRoundHold | null = await holdingThroughJobs({
|
|
1231
|
+
jobs: [{ suggestionId: RULE_RUN, stepId: "ai-command-2" }],
|
|
1232
|
+
runs: [
|
|
1233
|
+
ruleRun({
|
|
1234
|
+
status: AutoRemediationSuggestionStatus.Planning,
|
|
1235
|
+
verificationStatus: undefined,
|
|
1236
|
+
createdAt: new Date(NOW),
|
|
1237
|
+
}),
|
|
1238
|
+
],
|
|
1239
|
+
}).hold;
|
|
1240
|
+
|
|
1241
|
+
expect(hold?.description).toBe("is still changing it");
|
|
1242
|
+
});
|
|
1243
|
+
|
|
1244
|
+
it("reads the runs behind the jobs by id, in this project, CommandPlan only", async () => {
|
|
1245
|
+
const lookup: {
|
|
1246
|
+
hold: Promise<ClusterRoundHold | null>;
|
|
1247
|
+
runRead: jest.SpyInstance;
|
|
1248
|
+
} = holdingThroughJobs({
|
|
1249
|
+
jobs: [{ suggestionId: RULE_RUN, stepId: "ai-command-1" }],
|
|
1250
|
+
runs: [ruleRun()],
|
|
1251
|
+
});
|
|
1252
|
+
await lookup.hold;
|
|
1253
|
+
|
|
1254
|
+
const byId: Record<string, unknown> | undefined =
|
|
1255
|
+
lookup.runRead.mock.calls
|
|
1256
|
+
.map((call: Array<unknown>) => {
|
|
1257
|
+
return (call[0] as { query: Record<string, unknown> }).query;
|
|
1258
|
+
})
|
|
1259
|
+
.find((query: Record<string, unknown>) => {
|
|
1260
|
+
return Boolean(query["_id"]);
|
|
1261
|
+
});
|
|
1262
|
+
expect(byId).toBeDefined();
|
|
1263
|
+
expect((byId!["projectId"] as ObjectID).toString()).toBe(
|
|
1264
|
+
PROJECT_ID.toString(),
|
|
1265
|
+
);
|
|
1266
|
+
expect(byId!["suggestionType"]).toBe(
|
|
1267
|
+
AutoRemediationSuggestionType.CommandPlan,
|
|
1268
|
+
);
|
|
1269
|
+
});
|
|
1270
|
+
|
|
1271
|
+
it.each([
|
|
1272
|
+
[
|
|
1273
|
+
"its fix was verified",
|
|
1274
|
+
[{ stepId: "ai-command-1" }],
|
|
1275
|
+
{ verificationStatus: AutoRemediationVerificationStatus.Verified },
|
|
1276
|
+
],
|
|
1277
|
+
[
|
|
1278
|
+
"its only job on the cluster is a rollback of a failed fix",
|
|
1279
|
+
[{ stepId: "ai-rollback-1" }],
|
|
1280
|
+
{},
|
|
1281
|
+
],
|
|
1282
|
+
["it has no job on the cluster", [], {}],
|
|
1283
|
+
])(
|
|
1284
|
+
"negative control: no hold when %s",
|
|
1285
|
+
async (
|
|
1286
|
+
_label: string,
|
|
1287
|
+
jobs: Array<{ stepId: string }>,
|
|
1288
|
+
overrides: Record<string, unknown>,
|
|
1289
|
+
) => {
|
|
1290
|
+
const lookup: {
|
|
1291
|
+
hold: Promise<ClusterRoundHold | null>;
|
|
1292
|
+
runRead: jest.SpyInstance;
|
|
1293
|
+
} = holdingThroughJobs({
|
|
1294
|
+
jobs: jobs.map((job: { stepId: string }) => {
|
|
1295
|
+
return { suggestionId: RULE_RUN, stepId: job.stepId };
|
|
1296
|
+
}),
|
|
1297
|
+
runs: [ruleRun(overrides)],
|
|
1298
|
+
});
|
|
1299
|
+
|
|
1300
|
+
expect(await lookup.hold).toBeNull();
|
|
1301
|
+
},
|
|
1302
|
+
);
|
|
1303
|
+
|
|
1304
|
+
it("negative control: the asking run's own jobs never hold the cluster against it", async () => {
|
|
1305
|
+
expect(
|
|
1306
|
+
await holdingThroughJobs({
|
|
1307
|
+
jobs: [{ suggestionId: RULE_RUN, stepId: "ai-command-1" }],
|
|
1308
|
+
runs: [ruleRun()],
|
|
1309
|
+
forRound: RULE_RUN,
|
|
1310
|
+
}).hold,
|
|
1311
|
+
).toBeNull();
|
|
1312
|
+
});
|
|
1313
|
+
|
|
1314
|
+
it("negative control: a run the read returns that no job named is ignored", async () => {
|
|
1315
|
+
expect(
|
|
1316
|
+
await holdingThroughJobs({
|
|
1317
|
+
jobs: [{ suggestionId: ObjectID.generate(), stepId: "ai-command-1" }],
|
|
1318
|
+
runs: [ruleRun()],
|
|
1319
|
+
}).hold,
|
|
1320
|
+
).toBeNull();
|
|
1321
|
+
});
|
|
1322
|
+
});
|
|
1323
|
+
|
|
1324
|
+
it("propagates a failed read so callers fail safe", async () => {
|
|
1325
|
+
jest
|
|
1326
|
+
.spyOn(AutoRemediationSuggestionService, "findBy")
|
|
1327
|
+
.mockRejectedValue(new Error("db down"));
|
|
1328
|
+
|
|
1329
|
+
await expect(
|
|
1330
|
+
AutoRemediationRuleEngineService.findRoundHoldingCluster({
|
|
1331
|
+
projectId: PROJECT_ID,
|
|
1332
|
+
clusterId: CLUSTER_ID.toString(),
|
|
1333
|
+
}),
|
|
1334
|
+
).rejects.toThrow("db down");
|
|
1335
|
+
});
|
|
1336
|
+
});
|
|
1337
|
+
|
|
1338
|
+
describe("cluster round name snapshots", () => {
|
|
1339
|
+
it("round-trips the server-written name, rounds included", () => {
|
|
1340
|
+
expect(getClusterRoundNameSnapshot("prod-us", 1)).toBe(
|
|
1341
|
+
'AI remediation for cluster "prod-us"',
|
|
1342
|
+
);
|
|
1343
|
+
expect(getClusterRoundNameSnapshot("prod-us", 2)).toBe(
|
|
1344
|
+
'AI remediation for cluster "prod-us" (round 2)',
|
|
1345
|
+
);
|
|
1346
|
+
expect(
|
|
1347
|
+
parseClusterRoundNameSnapshot(getClusterRoundNameSnapshot("prod-us", 2)),
|
|
1348
|
+
).toEqual({ clusterName: "prod-us" });
|
|
1349
|
+
expect(
|
|
1350
|
+
parseClusterRoundNameSnapshot('AI remediation for cluster "a "b" c"'),
|
|
1351
|
+
).toEqual({ clusterName: 'a "b" c' });
|
|
1352
|
+
});
|
|
1353
|
+
|
|
1354
|
+
it("does not take an ordinary rule name for a cluster round", () => {
|
|
1355
|
+
expect(parseClusterRoundNameSnapshot("Restart the API service")).toBeNull();
|
|
1356
|
+
expect(
|
|
1357
|
+
parseClusterRoundNameSnapshot('Custom: AI remediation for cluster "x"'),
|
|
1358
|
+
).toBeNull();
|
|
1359
|
+
expect(parseClusterRoundNameSnapshot(undefined)).toBeNull();
|
|
1360
|
+
});
|
|
1361
|
+
});
|