@oneuptime/common 14.0.1 → 14.0.3
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/AlertFeed.ts +2 -0
- package/Models/DatabaseModels/AutoRemediationSuggestion.ts +63 -0
- package/Models/DatabaseModels/IncidentAlert.ts +540 -0
- package/Models/DatabaseModels/IncidentEpisodeMember.ts +8 -1
- package/Models/DatabaseModels/IncidentEpisodePublicNote.ts +9 -2
- package/Models/DatabaseModels/IncidentFeed.ts +2 -0
- package/Models/DatabaseModels/IncidentPublicNote.ts +9 -2
- package/Models/DatabaseModels/Index.ts +2 -0
- package/Models/DatabaseModels/KubernetesCluster.ts +429 -0
- package/Models/DatabaseModels/Monitor.ts +48 -0
- package/Models/DatabaseModels/Project.ts +60 -0
- package/Models/DatabaseModels/RumApplication.ts +52 -1
- 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/1794800000000-AddSessionReplaySameOriginTracePropagation.ts +28 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1794900000000-AddIncidentAlert.ts +89 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +14 -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/IncidentAlertService.ts +1811 -0
- 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 +330 -30
- package/Server/Services/IncidentStateTimelineService.ts +39 -0
- package/Server/Services/IncidentTemplateService.ts +83 -3
- package/Server/Services/Index.ts +2 -0
- 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/SessionReplayGateCache.ts +24 -2
- 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/BulkIncidentLinkActions.test.tsx +869 -0
- package/Tests/App/Dashboard/CephMetricTooltips.test.tsx +1777 -0
- package/Tests/App/Dashboard/CloudFleetSummary.test.ts +8 -0
- package/Tests/App/Dashboard/CloudMetricTooltips.test.tsx +887 -0
- package/Tests/App/Dashboard/ClusterAccessNotice.test.tsx +794 -0
- package/Tests/App/Dashboard/ContainerHostMetricTooltips.test.tsx +1309 -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/DiscoveryScanLivePage.test.tsx +39 -0
- package/Tests/App/Dashboard/DockerSwarmClustersListTooltips.test.tsx +414 -0
- package/Tests/App/Dashboard/DockerSwarmMetricTooltips.test.ts +796 -0
- package/Tests/App/Dashboard/DockerSwarmOverviewTooltips.test.tsx +747 -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 +238 -0
- package/Tests/App/Dashboard/HostDetailViewTooltips.test.tsx +725 -0
- package/Tests/App/Dashboard/HostListColumnTooltips.test.tsx +472 -0
- package/Tests/App/Dashboard/HostMetricTooltips.test.ts +709 -0
- package/Tests/App/Dashboard/HostOverviewTooltips.test.tsx +698 -0
- package/Tests/App/Dashboard/HostTooltipHarness.ts +124 -0
- package/Tests/App/Dashboard/HostsListTooltips.test.tsx +395 -0
- package/Tests/App/Dashboard/IncidentAlertLinkDialog.test.tsx +691 -0
- package/Tests/App/Dashboard/IncidentAlertLinkHelpers.test.ts +458 -0
- package/Tests/App/Dashboard/IncidentAlertLinkPages.test.tsx +828 -0
- package/Tests/App/Dashboard/IncidentAlertLinkSideMenus.test.tsx +231 -0
- package/Tests/App/Dashboard/IncidentChangeStateNotifyDefault.test.tsx +665 -0
- package/Tests/App/Dashboard/IncidentCreateFromAlerts.test.tsx +689 -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/IoTMetricTooltips.test.tsx +1123 -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/KubernetesClusterMetricTooltips.test.ts +837 -0
- package/Tests/App/Dashboard/KubernetesClusterOverviewTooltips.test.tsx +699 -0
- package/Tests/App/Dashboard/KubernetesContainersTabTooltips.test.tsx +320 -0
- package/Tests/App/Dashboard/KubernetesCostTooltips.test.tsx +502 -0
- package/Tests/App/Dashboard/KubernetesInsightsTooltips.test.tsx +222 -0
- package/Tests/App/Dashboard/KubernetesResourceMetricTooltips.test.ts +561 -0
- package/Tests/App/Dashboard/KubernetesResourcePagesTooltips.test.tsx +1168 -0
- package/Tests/App/Dashboard/LayerDateTimeFieldTimezoneName.test.tsx +66 -0
- package/Tests/App/Dashboard/LinkIncidentAlertModal.test.tsx +154 -0
- package/Tests/App/Dashboard/LogMonitorPreview.test.tsx +174 -0
- package/Tests/App/Dashboard/MetricDescriptionRules.ts +170 -0
- package/Tests/App/Dashboard/MetricDescriptionsCatalog.test.ts +206 -0
- package/Tests/App/Dashboard/MetricDescriptionsConsistency.test.ts +275 -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/NetworkDeviceTooltips.test.tsx +852 -0
- package/Tests/App/Dashboard/NetworkDiagnosticsTooltips.test.tsx +556 -0
- package/Tests/App/Dashboard/NetworkMetricTooltips.test.ts +1348 -0
- package/Tests/App/Dashboard/NetworkSiteTooltips.test.tsx +679 -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/ProxmoxMetricTooltips.test.ts +592 -0
- package/Tests/App/Dashboard/ProxmoxOverviewTooltips.test.tsx +1002 -0
- package/Tests/App/Dashboard/ProxmoxResourcePageTooltips.test.tsx +923 -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/ResourceOverviewTileTooltips.test.tsx +1066 -0
- package/Tests/App/Dashboard/RumOverviewPage.test.tsx +1195 -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/ServerlessMetricTooltips.test.tsx +474 -0
- package/Tests/App/Dashboard/ServiceMetricTooltips.test.tsx +772 -0
- package/Tests/App/Dashboard/SessionReplayAuditTable.test.tsx +56 -1
- package/Tests/App/Dashboard/TeamMembershipRemoval.test.ts +900 -0
- package/Tests/App/Dashboard/TeamMembershipRemovalPages.test.tsx +460 -0
- package/Tests/App/Dashboard/TelemetryMetricsSignals.test.ts +1207 -0
- package/Tests/App/Dashboard/TelemetryResourceTabTooltips.test.tsx +437 -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/VMwareMetricTooltips.test.ts +801 -0
- package/Tests/App/Dashboard/VMwareOverviewTooltips.test.tsx +601 -0
- package/Tests/App/Dashboard/VMwareResourcePagesTooltips.test.tsx +646 -0
- package/Tests/App/Dashboard/VMwareTooltipHarness.ts +145 -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/IncidentAlertModel.test.ts +554 -0
- package/Tests/Models/DatabaseModels/KubernetesClusterAiAccessColumns.test.ts +520 -0
- package/Tests/Models/DatabaseModels/MonitorSecretKeyColumnAccessControl.test.ts +66 -2
- package/Tests/Models/DatabaseModels/SessionReplayModels.test.ts +117 -0
- 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/AddIncidentAlertMigration.test.ts +341 -0
- package/Tests/Server/Infrastructure/Postgres/AddKubernetesClusterAiAccessMigration.test.ts +589 -0
- package/Tests/Server/Infrastructure/Postgres/AddOAuth2WorkflowVariablesMigration.test.ts +254 -0
- package/Tests/Server/Infrastructure/Postgres/AddSessionReplaySameOriginTracePropagationMigration.test.ts +247 -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/IncidentAlertPostgres.test.ts +903 -0
- package/Tests/Server/Services/IncidentAlertRegistration.test.ts +96 -0
- package/Tests/Server/Services/IncidentAlertService.test.ts +2225 -0
- package/Tests/Server/Services/IncidentAlertStateCascade.test.ts +970 -0
- package/Tests/Server/Services/IncidentCreateFromAlerts.test.ts +1284 -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/SessionReplayGateCachePolicy.test.ts +103 -0
- 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/Rum/WebVitals.test.ts +173 -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/FieldLabelInfoCardTooltip.test.tsx +413 -0
- 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/InfoTooltip.test.tsx +242 -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/BaseModelTableBulkDelete.test.tsx +207 -3
- package/Tests/UI/Components/ModelTable/BaseModelTableBulkDeleteVerb.test.tsx +367 -0
- package/Tests/UI/Components/ModelTable/BaseModelTableCreateButtonTitle.test.tsx +275 -0
- 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/TableHeaderTooltip.test.tsx +662 -0
- 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/Rum/PrivacySummaryCard.test.tsx +166 -9
- package/Tests/UI/Rum/RecordingHealthTooltips.test.tsx +447 -0
- package/Tests/UI/Rum/ReplayCorrelationPanel.test.tsx +164 -0
- package/Tests/UI/Rum/ReplayFrameCapture.test.ts +6750 -0
- package/Tests/UI/Rum/ReplayRail.test.tsx +723 -12
- package/Tests/UI/Rum/ReplayRailDetail.test.tsx +86 -0
- package/Tests/UI/Rum/ReplayScreenshot.test.ts +2124 -0
- package/Tests/UI/Rum/ReplayScreenshotActions.test.tsx +3288 -0
- package/Tests/UI/Rum/ReplayStage.test.tsx +62 -0
- package/Tests/UI/Rum/ReplayStageOverlays.test.tsx +983 -2
- package/Tests/UI/Rum/SessionReplaySettingsPolicyLoading.test.tsx +149 -0
- package/Tests/UI/Rum/SessionReplaySetupGuide.test.tsx +107 -6
- package/Tests/UI/Rum/SessionReplayUsersTableTooltips.test.tsx +330 -0
- package/Tests/UI/Rum/UserFlowTooltips.test.tsx +886 -0
- package/Tests/UI/Telemetry/TelemetryDetailPanel.test.tsx +28 -0
- package/Tests/UI/Utils/Breadcrumb/fixtures/RealBreadcrumbTrails.ts +10 -0
- package/Tests/UI/Utils/Breadcrumb/fixtures/RealRoutePatterns.ts +2 -0
- package/Tests/UI/Utils/PermissionGate.test.ts +76 -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/Incident/IncidentFromAlerts.test.ts +696 -0
- 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/SessionTraceState.test.ts +239 -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/Incident/IncidentAlertLink.ts +38 -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/Permission.ts +48 -0
- package/Types/Rum/SessionReplay.ts +80 -8
- package/Types/Rum/SessionReplayApi.ts +44 -1
- package/Types/Rum/UserFlow.ts +187 -0
- package/Types/Rum/WebVitals.ts +52 -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/Detail/FieldLabel.tsx +8 -0
- 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/InfoCard/InfoCard.tsx +47 -1
- 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 +161 -31
- package/UI/Components/ModelTable/Column.ts +5 -0
- 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/Table/TableHeader.tsx +47 -2
- package/UI/Components/Table/Types/Column.ts +7 -0
- 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/Components/Tooltip/InfoTooltip.tsx +78 -0
- package/UI/Utils/ModelAPI/ProjectUsersModelAPI.ts +19 -1
- package/UI/Utils/PermissionGate.ts +11 -2
- 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/Incident/IncidentFromAlerts.ts +516 -0
- 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/SessionTraceState.ts +212 -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/AlertFeed.js +2 -0
- package/build/dist/Models/DatabaseModels/AlertFeed.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/IncidentAlert.js +553 -0
- package/build/dist/Models/DatabaseModels/IncidentAlert.js.map +1 -0
- 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/IncidentFeed.js +2 -0
- package/build/dist/Models/DatabaseModels/IncidentFeed.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/Index.js +2 -0
- package/build/dist/Models/DatabaseModels/Index.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/Project.js +62 -0
- package/build/dist/Models/DatabaseModels/Project.js.map +1 -1
- package/build/dist/Models/DatabaseModels/RumApplication.js +53 -1
- package/build/dist/Models/DatabaseModels/RumApplication.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/1794800000000-AddSessionReplaySameOriginTracePropagation.js +20 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1794800000000-AddSessionReplaySameOriginTracePropagation.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1794900000000-AddIncidentAlert.js +42 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1794900000000-AddIncidentAlert.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +14 -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/IncidentAlertService.js +1370 -0
- package/build/dist/Server/Services/IncidentAlertService.js.map +1 -0
- 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 +263 -33
- package/build/dist/Server/Services/IncidentService.js.map +1 -1
- package/build/dist/Server/Services/IncidentStateTimelineService.js +33 -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/Index.js +2 -0
- package/build/dist/Server/Services/Index.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/SessionReplayGateCache.js +8 -0
- package/build/dist/Server/Utils/SessionReplay/SessionReplayGateCache.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/Incident/IncidentAlertLink.js +34 -0
- package/build/dist/Types/Incident/IncidentAlertLink.js.map +1 -0
- 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/Permission.js +42 -0
- package/build/dist/Types/Permission.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/Rum/WebVitals.js +25 -0
- package/build/dist/Types/Rum/WebVitals.js.map +1 -1
- 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/Detail/FieldLabel.js +2 -0
- package/build/dist/UI/Components/Detail/FieldLabel.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/InfoCard/InfoCard.js +22 -1
- package/build/dist/UI/Components/InfoCard/InfoCard.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 +89 -22
- 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/Table/TableHeader.js +18 -2
- package/build/dist/UI/Components/Table/TableHeader.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/Components/Tooltip/InfoTooltip.js +28 -0
- package/build/dist/UI/Components/Tooltip/InfoTooltip.js.map +1 -0
- 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/PermissionGate.js +4 -2
- package/build/dist/UI/Utils/PermissionGate.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/Incident/IncidentFromAlerts.js +306 -0
- package/build/dist/Utils/Incident/IncidentFromAlerts.js.map +1 -0
- 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/SessionTraceState.js +154 -0
- package/build/dist/Utils/Rum/SessionTraceState.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
|
@@ -13,20 +13,44 @@ import {
|
|
|
13
13
|
AiRemediationCommandExecutionStatus,
|
|
14
14
|
AiRemediationCommandPlan,
|
|
15
15
|
AiRemediationCommandPlanUtil,
|
|
16
|
+
AiRemediationCommandPolicyVerdict,
|
|
16
17
|
AiRemediationPlanExecutionStatus,
|
|
17
18
|
AiRemediationRollbackStatus,
|
|
19
|
+
getForwardCommandStepId,
|
|
20
|
+
getRollbackCommandStepId,
|
|
21
|
+
isSettledCommandExecutionStatus,
|
|
18
22
|
} from "../../../Types/AutoRemediation/AiRemediationCommandPlan";
|
|
23
|
+
import SortOrder from "../../../Types/BaseDatabase/SortOrder";
|
|
19
24
|
import CommandPolicy from "../../../Utils/AiRemediation/CommandPolicy";
|
|
25
|
+
import KubectlPolicy, {
|
|
26
|
+
KubectlAutoExecutionVerdict,
|
|
27
|
+
KubectlPolicyResult,
|
|
28
|
+
} from "../../../Utils/AiRemediation/KubectlPolicy";
|
|
29
|
+
import {
|
|
30
|
+
KubectlCommandTier,
|
|
31
|
+
KubernetesAiAccessGap,
|
|
32
|
+
KubernetesAiRemediationMode,
|
|
33
|
+
KubernetesClusterAiAccessStatus,
|
|
34
|
+
} from "../../../Types/Kubernetes/KubernetesClusterAiAccess";
|
|
35
|
+
import RunbookStepType from "../../../Types/Runbook/RunbookStepType";
|
|
36
|
+
import RunnerJobOrigin from "../../../Types/Runbook/RunnerJobOrigin";
|
|
20
37
|
import { Green500, Red500 } from "../../../Types/BrandColors";
|
|
21
38
|
import Color from "../../../Types/Color";
|
|
22
39
|
import AlertFeedService from "../../Services/AlertFeedService";
|
|
23
40
|
import AutoRemediationSuggestionService from "../../Services/AutoRemediationSuggestionService";
|
|
24
41
|
import IncidentFeedService from "../../Services/IncidentFeedService";
|
|
42
|
+
import KubernetesClusterAiAccessService from "../../Services/KubernetesClusterAiAccessService";
|
|
25
43
|
import RunnerJobService, {
|
|
26
44
|
isTerminalAgentJobStatus,
|
|
27
45
|
} from "../../Services/RunnerJobService";
|
|
28
46
|
import RunnerJobStatus from "../../../Types/Runbook/RunnerJobStatus";
|
|
47
|
+
import Semaphore, { SemaphoreMutex } from "../../Infrastructure/Semaphore";
|
|
29
48
|
import ToolResultSerializer from "../AI/Toolbox/Serializer";
|
|
49
|
+
import KubectlJobRunner, {
|
|
50
|
+
KubectlRunState,
|
|
51
|
+
KubectlTerminalJobFacts,
|
|
52
|
+
} from "../AI/ClusterAccess/KubectlJobRunner";
|
|
53
|
+
import RemediationCommandToolkit from "../AI/Remediation/RemediationCommandTools";
|
|
30
54
|
import logger from "../Logger";
|
|
31
55
|
import CaptureSpan from "../Telemetry/CaptureSpan";
|
|
32
56
|
|
|
@@ -45,11 +69,122 @@ import CaptureSpan from "../Telemetry/CaptureSpan";
|
|
|
45
69
|
* executed command that carried a rollbackCommand is undone, in reverse
|
|
46
70
|
* order. Rollback commands were visible on the approval card (or, for
|
|
47
71
|
* FullAuto, passed the same policy the forward command did) and are
|
|
48
|
-
* re-checked against the hard denylist here anyway.
|
|
72
|
+
* re-checked against the hard denylist here anyway. A command that may
|
|
73
|
+
* have run without saying so — its record still Pending, or a kubectl
|
|
74
|
+
* command recorded as failed whose job a Runner took with no result back
|
|
75
|
+
* (KubectlJobRunner's Unknown run state) — is never treated as never run:
|
|
76
|
+
* its undo is not run blind either, a human is told to check and undo it.
|
|
77
|
+
*
|
|
78
|
+
* Kubectl commands — forward and rollback — are additionally re-checked
|
|
79
|
+
* against the cluster's AI page AS IT IS NOW, right before they are
|
|
80
|
+
* enqueued: an approval can be clicked hours after the plan was composed,
|
|
81
|
+
* and a rollback fires at the end of the verification window. The
|
|
82
|
+
* operator's current choice (remediation off, a different Runner bound, a
|
|
83
|
+
* mode that no longer bypasses approvals) wins over the frozen plan.
|
|
84
|
+
*
|
|
85
|
+
* The two arms can overlap: verification fails a plan that overran its
|
|
86
|
+
* window while the executor is still waiting on a command. Three rules keep
|
|
87
|
+
* them from undoing each other:
|
|
88
|
+
* - the executor starts each command (its stand-down check, the enqueue,
|
|
89
|
+
* and the write that names the job) under a per-plan lock, and the
|
|
90
|
+
* rollback arm reads the plan under the same lock — so every forward
|
|
91
|
+
* job that will ever exist is either on the record the rollback arm
|
|
92
|
+
* reads, or its command stands down;
|
|
93
|
+
* - the rollback arm WAITS for a forward job still in flight and rolls it
|
|
94
|
+
* back once it succeeds, instead of skipping it;
|
|
95
|
+
* - both write the plan read-modify-write under that lock, each writing
|
|
96
|
+
* only its own fields (the executor: forward executions and the plan's
|
|
97
|
+
* execution lifecycle; the rollback arm: rollbacks and rollbackStatus),
|
|
98
|
+
* so neither erases the other's record.
|
|
99
|
+
*
|
|
100
|
+
* A Worker restart mid-rollback leaves the plan's rollbackStatus unset with
|
|
101
|
+
* a heartbeat that goes stale; the verifier's recovery sweep resumes it
|
|
102
|
+
* (executeRollback settles rollbacks already handed to a Runner from their
|
|
103
|
+
* jobs, and never re-runs one that ran). The resumed rollback's outcome is
|
|
104
|
+
* the WHOLE plan's: an undo the interrupted attempt already settled as
|
|
105
|
+
* failed, or left for a human, keeps the rollback Failed — the verifier
|
|
106
|
+
* forces the follow-up round to ask first on exactly that.
|
|
49
107
|
*/
|
|
50
108
|
|
|
51
109
|
const AI_COMMAND_CLAIM_TIMEOUT_MS: number = 60_000;
|
|
52
110
|
const MAX_STORED_OUTPUT_CHARS: number = 6000;
|
|
111
|
+
const MAX_FEED_REASON_CHARS: number = 400;
|
|
112
|
+
|
|
113
|
+
/*
|
|
114
|
+
* The per-plan lock covers database writes and one enqueue — never a wait
|
|
115
|
+
* on a Runner. It expires on its own if the pod dies holding it.
|
|
116
|
+
*/
|
|
117
|
+
const PLAN_LOCK_NAMESPACE: string = "AutoRemediationCommandPlan";
|
|
118
|
+
const PLAN_LOCK_TIMEOUT_MS: number = 30_000;
|
|
119
|
+
const PLAN_LOCK_ACQUIRE_TIMEOUT_MS: number = 15_000;
|
|
120
|
+
|
|
121
|
+
// What the rollback arm needs from a RunnerJob to settle its command.
|
|
122
|
+
const RECONCILE_JOB_SELECT: {
|
|
123
|
+
_id: true;
|
|
124
|
+
status: true;
|
|
125
|
+
output: true;
|
|
126
|
+
exitCode: true;
|
|
127
|
+
errorMessage: true;
|
|
128
|
+
} = {
|
|
129
|
+
_id: true,
|
|
130
|
+
status: true,
|
|
131
|
+
output: true,
|
|
132
|
+
exitCode: true,
|
|
133
|
+
errorMessage: true,
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
/*
|
|
137
|
+
* What the rollback arm needs from a kubectl RunnerJob to tell whether
|
|
138
|
+
* kubectl ran (KubectlJobRunner.getRunStateOfJobRow): the outcome, and
|
|
139
|
+
* whether a Runner ever claimed or started the job.
|
|
140
|
+
*/
|
|
141
|
+
const RUN_STATE_JOB_SELECT: {
|
|
142
|
+
_id: true;
|
|
143
|
+
status: true;
|
|
144
|
+
output: true;
|
|
145
|
+
exitCode: true;
|
|
146
|
+
errorMessage: true;
|
|
147
|
+
claimedAt: true;
|
|
148
|
+
startedAt: true;
|
|
149
|
+
assignedAgentId: true;
|
|
150
|
+
} = {
|
|
151
|
+
...RECONCILE_JOB_SELECT,
|
|
152
|
+
claimedAt: true,
|
|
153
|
+
startedAt: true,
|
|
154
|
+
assignedAgentId: true,
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
// Who is writing the plan — each side owns different fields of it.
|
|
158
|
+
type PlanWriter = "executor" | "rollback";
|
|
159
|
+
|
|
160
|
+
/*
|
|
161
|
+
* What the rollback arm did, for the verifier: it gates the follow-up round
|
|
162
|
+
* on it and records it on the verification note. rollbackStatus is
|
|
163
|
+
* undefined when the arm could not settle the rollback (no plan, or the
|
|
164
|
+
* status could not be written).
|
|
165
|
+
*/
|
|
166
|
+
export interface CommandPlanRollbackOutcome {
|
|
167
|
+
rollbackStatus: AiRemediationRollbackStatus | undefined;
|
|
168
|
+
// Rollbacks that ran and succeeded.
|
|
169
|
+
rolledBack: number;
|
|
170
|
+
// Rollbacks that ran and failed, or that the command policy refused.
|
|
171
|
+
failed: number;
|
|
172
|
+
// Rollbacks left for a human to run by hand (their outcome says why).
|
|
173
|
+
leftForHuman: number;
|
|
174
|
+
// One sentence for the verification note.
|
|
175
|
+
summary: string;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
interface StartedCommand {
|
|
179
|
+
state: AiRemediationCommandExecutionState;
|
|
180
|
+
// Set when the command reached a Runner; null when it was refused first.
|
|
181
|
+
job: RunnerJob | null;
|
|
182
|
+
/*
|
|
183
|
+
* Whether the cluster's AI page may record this outcome at all (it then
|
|
184
|
+
* records a success, or a failure about the cluster's ACCESS only).
|
|
185
|
+
*/
|
|
186
|
+
recordsClusterOutcome: boolean;
|
|
187
|
+
}
|
|
53
188
|
|
|
54
189
|
export default class CommandPlanExecutor {
|
|
55
190
|
/*
|
|
@@ -110,9 +245,13 @@ export default class CommandPlanExecutor {
|
|
|
110
245
|
|
|
111
246
|
plan.executionStatus = AiRemediationPlanExecutionStatus.Running;
|
|
112
247
|
plan.executionStartedAt = OneUptimeDate.getCurrentDate().toISOString();
|
|
113
|
-
await this.persistPlan(suggestion, plan);
|
|
248
|
+
await this.persistPlan(suggestion, plan, "executor");
|
|
114
249
|
|
|
115
250
|
let failed: boolean = false;
|
|
251
|
+
// What stopped the plan, for the feed: the first non-Succeeded outcome.
|
|
252
|
+
let firstFailure: string | null = null;
|
|
253
|
+
// Verification settled the remediation while the plan was executing.
|
|
254
|
+
let settledMidPlan: boolean = false;
|
|
116
255
|
|
|
117
256
|
for (const command of plan.commands) {
|
|
118
257
|
// FullAuto-executed entries never appear in approved Suggest plans.
|
|
@@ -129,43 +268,76 @@ export default class CommandPlanExecutor {
|
|
|
129
268
|
}
|
|
130
269
|
|
|
131
270
|
/*
|
|
132
|
-
*
|
|
133
|
-
*
|
|
134
|
-
*
|
|
135
|
-
*
|
|
136
|
-
*
|
|
137
|
-
* undo end up fighting each other, so the executor stops the moment
|
|
138
|
-
* verification is no longer Pending or a human moved the
|
|
139
|
-
* suggestion off Approved.
|
|
271
|
+
* Start the command under the plan lock: the stand-down check, the
|
|
272
|
+
* Pending marker, the enqueue and the write that names the job. The
|
|
273
|
+
* rollback arm reads the plan under the same lock, so it either sees
|
|
274
|
+
* this command's job (and waits for it) or this command sees the
|
|
275
|
+
* settled verification and never starts.
|
|
140
276
|
*/
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
277
|
+
const mutex: SemaphoreMutex | null = await this.lockPlan(
|
|
278
|
+
suggestion.id!,
|
|
279
|
+
);
|
|
280
|
+
|
|
281
|
+
let started: StartedCommand | null = null;
|
|
282
|
+
|
|
283
|
+
try {
|
|
284
|
+
/*
|
|
285
|
+
* Abort check between commands. Verification runs on its own
|
|
286
|
+
* sweep and can fail this remediation while the plan is still
|
|
287
|
+
* executing (a slow Runner, a long command); once it does, it
|
|
288
|
+
* rolls the executed commands back. Continuing to push NEW
|
|
289
|
+
* forward commands into a rollback that is already under way is
|
|
290
|
+
* how a plan and its undo end up fighting each other, so the
|
|
291
|
+
* executor stops the moment verification is no longer Pending or
|
|
292
|
+
* a human moved the suggestion off Approved.
|
|
293
|
+
*/
|
|
294
|
+
if (!(await this.isStillExecutable(suggestion.id!))) {
|
|
295
|
+
command.execution = {
|
|
296
|
+
status: AiRemediationCommandExecutionStatus.Skipped,
|
|
297
|
+
errorMessage:
|
|
298
|
+
"Skipped: this remediation was settled (verified, failed, or actioned by a human) before the command ran.",
|
|
299
|
+
};
|
|
300
|
+
failed = true;
|
|
301
|
+
settledMidPlan = true;
|
|
302
|
+
} else {
|
|
303
|
+
/*
|
|
304
|
+
* Persist the Pending marker BEFORE the side effect: a pod death
|
|
305
|
+
* mid-command must leave a record that this command may have
|
|
306
|
+
* run.
|
|
307
|
+
*/
|
|
308
|
+
command.execution = {
|
|
309
|
+
status: AiRemediationCommandExecutionStatus.Pending,
|
|
310
|
+
startedAt: OneUptimeDate.getCurrentDate().toISOString(),
|
|
311
|
+
};
|
|
312
|
+
await this.persistPlan(suggestion, plan, "executor", {
|
|
313
|
+
planLocked: true,
|
|
314
|
+
});
|
|
315
|
+
|
|
316
|
+
started = await this.startOneCommand({ suggestion, plan, command });
|
|
317
|
+
}
|
|
318
|
+
} finally {
|
|
319
|
+
await this.unlockPlan(mutex);
|
|
149
320
|
}
|
|
150
321
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
*/
|
|
155
|
-
command.execution = {
|
|
156
|
-
status: AiRemediationCommandExecutionStatus.Pending,
|
|
157
|
-
startedAt: OneUptimeDate.getCurrentDate().toISOString(),
|
|
158
|
-
};
|
|
159
|
-
await this.persistPlan(suggestion, plan);
|
|
322
|
+
if (!started) {
|
|
323
|
+
continue;
|
|
324
|
+
}
|
|
160
325
|
|
|
161
326
|
const state: AiRemediationCommandExecutionState =
|
|
162
|
-
await this.
|
|
327
|
+
await this.finishOneCommand({ command, started });
|
|
163
328
|
|
|
164
329
|
command.execution = state;
|
|
165
|
-
await this.persistPlan(suggestion, plan);
|
|
330
|
+
await this.persistPlan(suggestion, plan, "executor");
|
|
166
331
|
|
|
167
332
|
if (state.status !== AiRemediationCommandExecutionStatus.Succeeded) {
|
|
168
333
|
failed = true;
|
|
334
|
+
firstFailure =
|
|
335
|
+
firstFailure ||
|
|
336
|
+
`command ${command.sequence} ${
|
|
337
|
+
state.errorMessage
|
|
338
|
+
? `failed: ${this.capForFeed(state.errorMessage)}`
|
|
339
|
+
: "failed"
|
|
340
|
+
}`;
|
|
169
341
|
}
|
|
170
342
|
}
|
|
171
343
|
|
|
@@ -173,15 +345,31 @@ export default class CommandPlanExecutor {
|
|
|
173
345
|
? AiRemediationPlanExecutionStatus.Failed
|
|
174
346
|
: AiRemediationPlanExecutionStatus.Completed;
|
|
175
347
|
plan.executionCompletedAt = OneUptimeDate.getCurrentDate().toISOString();
|
|
176
|
-
await this.persistPlan(suggestion, plan);
|
|
348
|
+
await this.persistPlan(suggestion, plan, "executor");
|
|
349
|
+
|
|
350
|
+
/*
|
|
351
|
+
* The last command can still be running when verification concludes
|
|
352
|
+
* (a plan that overran its window). "Verification is watching" would
|
|
353
|
+
* then contradict the verification and rollback notes already on the
|
|
354
|
+
* feed.
|
|
355
|
+
*/
|
|
356
|
+
if (!settledMidPlan && !(await this.isStillExecutable(suggestion.id!))) {
|
|
357
|
+
settledMidPlan = true;
|
|
358
|
+
}
|
|
177
359
|
|
|
178
360
|
await this.postFeedItem({
|
|
179
361
|
suggestion,
|
|
180
|
-
markdown:
|
|
181
|
-
? `⚠️ **Approved AI command plan
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
362
|
+
markdown: settledMidPlan
|
|
363
|
+
? `⚠️ **Approved AI command plan finished after its verification had already concluded**${
|
|
364
|
+
firstFailure ? ` — ${firstFailure}` : ""
|
|
365
|
+
}. Commands that had not started yet were skipped; the verification and rollback notes on this suggestion say what was judged and what was undone. Review the per-command record.`
|
|
366
|
+
: failed
|
|
367
|
+
? `⚠️ **Approved AI command plan did not complete** — ${
|
|
368
|
+
firstFailure || "a command failed"
|
|
369
|
+
}; the remaining commands were skipped. Review the per-command output on the suggestion. Verification will judge (and roll back) what ran.`
|
|
370
|
+
: `⚡ **Approved AI command plan executed** (${plan.commands.length} command(s)). Verification is watching the monitors for recovery.`,
|
|
371
|
+
pingWorkspace: failed || settledMidPlan,
|
|
372
|
+
displayColor: failed || settledMidPlan ? Red500 : Green500,
|
|
185
373
|
});
|
|
186
374
|
} catch (error) {
|
|
187
375
|
logger.error(
|
|
@@ -193,38 +381,145 @@ export default class CommandPlanExecutor {
|
|
|
193
381
|
/*
|
|
194
382
|
* Undo a failed remediation: run the rollbackCommand of every command
|
|
195
383
|
* that executed successfully, in REVERSE order. Called by the verifier
|
|
196
|
-
* after it wins the Failed verification transition
|
|
197
|
-
*
|
|
384
|
+
* after it wins the Failed verification transition, and by its recovery
|
|
385
|
+
* sweep for a rollback a Worker restart interrupted. Never throws.
|
|
198
386
|
*/
|
|
199
387
|
@CaptureSpan()
|
|
200
388
|
public static async executeRollback(data: {
|
|
201
389
|
suggestion: AutoRemediationSuggestion;
|
|
202
|
-
}): Promise<
|
|
390
|
+
}): Promise<CommandPlanRollbackOutcome> {
|
|
203
391
|
const { suggestion } = data;
|
|
204
392
|
|
|
393
|
+
let plan: AiRemediationCommandPlan | null = null;
|
|
394
|
+
|
|
205
395
|
try {
|
|
206
|
-
|
|
207
|
-
|
|
396
|
+
/*
|
|
397
|
+
* Read the plan as stored NOW, under the plan lock — not the copy the
|
|
398
|
+
* verifier read before it won the verification transition. An
|
|
399
|
+
* approved plan's executor may have enqueued a command since; the
|
|
400
|
+
* lock guarantees its job is on this read, or that the command stands
|
|
401
|
+
* down and never starts.
|
|
402
|
+
*/
|
|
403
|
+
plan = await this.readPlanForRollback(suggestion);
|
|
208
404
|
|
|
209
405
|
if (!plan) {
|
|
210
|
-
return;
|
|
406
|
+
return this.describeRollbackOutcome(null);
|
|
211
407
|
}
|
|
212
408
|
|
|
213
409
|
if (
|
|
214
410
|
plan.rollbackStatus &&
|
|
215
411
|
plan.rollbackStatus !== AiRemediationRollbackStatus.NotAttempted
|
|
216
412
|
) {
|
|
217
|
-
|
|
413
|
+
// Already rolled back (or judged not applicable).
|
|
414
|
+
return this.describeRollbackOutcome(plan);
|
|
218
415
|
}
|
|
219
416
|
|
|
417
|
+
plan.rollbackHeartbeatAt = OneUptimeDate.getCurrentDate().toISOString();
|
|
418
|
+
await this.persistPlan(suggestion, plan, "rollback");
|
|
419
|
+
|
|
220
420
|
/*
|
|
221
421
|
* A command whose record still says Pending may nonetheless have run:
|
|
222
422
|
* the executor persists Pending, enqueues, and can die before writing
|
|
223
|
-
* the outcome
|
|
224
|
-
*
|
|
225
|
-
*
|
|
423
|
+
* the outcome — or it is simply still waiting on the job. The
|
|
424
|
+
* RunnerJob row is the authority on what actually happened, so
|
|
425
|
+
* resolve those first, WAITING for a job still in flight: skipping it
|
|
426
|
+
* would leave a change that is about to land exempt from its undo.
|
|
226
427
|
*/
|
|
227
|
-
await this.reconcilePendingExecutions(suggestion, plan
|
|
428
|
+
await this.reconcilePendingExecutions(suggestion, plan, {
|
|
429
|
+
waitForInFlight: true,
|
|
430
|
+
});
|
|
431
|
+
|
|
432
|
+
/*
|
|
433
|
+
* A resumed rollback: undos an interrupted attempt already handed to
|
|
434
|
+
* a Runner are settled from their jobs, never run twice.
|
|
435
|
+
*/
|
|
436
|
+
await this.reconcilePendingRollbacks(suggestion, plan);
|
|
437
|
+
|
|
438
|
+
let anyFailed: boolean = false;
|
|
439
|
+
// Rollbacks nobody may run unattended now — a human undoes them.
|
|
440
|
+
const leftForHuman: Array<AiRemediationCommand> = [];
|
|
441
|
+
|
|
442
|
+
/*
|
|
443
|
+
* A resumed rollback reports the WHOLE plan, not just what this
|
|
444
|
+
* attempt does: an undo the interrupted attempt already settled as
|
|
445
|
+
* Failed — or that reconcilePendingRollbacks just settled Failed from
|
|
446
|
+
* its job — keeps the rollback Failed, and one it left for a human is
|
|
447
|
+
* named again on the feed. Otherwise a resumed rollback whose earlier
|
|
448
|
+
* undo failed would report "completed" (or "nothing to roll back"),
|
|
449
|
+
* and the follow-up round would run unattended on top of a change
|
|
450
|
+
* that is still applied.
|
|
451
|
+
*/
|
|
452
|
+
for (const command of plan.commands) {
|
|
453
|
+
const earlier: AiRemediationCommandExecutionState | undefined =
|
|
454
|
+
command.rollbackExecution;
|
|
455
|
+
|
|
456
|
+
if (earlier?.status === AiRemediationCommandExecutionStatus.Failed) {
|
|
457
|
+
anyFailed = true;
|
|
458
|
+
} else if (
|
|
459
|
+
earlier?.status === AiRemediationCommandExecutionStatus.Skipped
|
|
460
|
+
) {
|
|
461
|
+
anyFailed = true;
|
|
462
|
+
leftForHuman.push(command);
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
/*
|
|
467
|
+
* A forward command whose job could not be resolved even after
|
|
468
|
+
* waiting may or may not have run. Its undo is not run blind; a human
|
|
469
|
+
* is told to check.
|
|
470
|
+
*/
|
|
471
|
+
for (const command of plan.commands) {
|
|
472
|
+
const execution: AiRemediationCommandExecutionState | undefined =
|
|
473
|
+
command.execution;
|
|
474
|
+
|
|
475
|
+
if (
|
|
476
|
+
execution &&
|
|
477
|
+
!isSettledCommandExecutionStatus(execution.status) &&
|
|
478
|
+
execution.runnerJobId &&
|
|
479
|
+
command.rollbackCommand &&
|
|
480
|
+
!command.rollbackExecution
|
|
481
|
+
) {
|
|
482
|
+
command.rollbackExecution = {
|
|
483
|
+
status: AiRemediationCommandExecutionStatus.Skipped,
|
|
484
|
+
errorMessage: `Rollback not run: whether the command ran could not be confirmed from its job. If it ran, undo it manually: ${command.rollbackCommand}`,
|
|
485
|
+
};
|
|
486
|
+
leftForHuman.push(command);
|
|
487
|
+
anyFailed = true;
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
/*
|
|
492
|
+
* A kubectl command recorded as failed may still have changed the
|
|
493
|
+
* cluster: a Runner took it and no result came back, the wait for it
|
|
494
|
+
* broke while the job ran on, or kubectl was stopped before it
|
|
495
|
+
* finished. Its job is read again: one that succeeded after all is
|
|
496
|
+
* rolled back like any other, and one that may have changed the
|
|
497
|
+
* cluster gets the same answer as an unresolved one above — its undo
|
|
498
|
+
* is not run blind, a human is told to check.
|
|
499
|
+
*/
|
|
500
|
+
for (const command of await this.reconcileFailedKubectlExecutions(
|
|
501
|
+
suggestion,
|
|
502
|
+
plan,
|
|
503
|
+
)) {
|
|
504
|
+
command.rollbackExecution = {
|
|
505
|
+
status: AiRemediationCommandExecutionStatus.Skipped,
|
|
506
|
+
errorMessage: `Rollback not run: the command reached the cluster's Runner but kubectl did not report a finished result, so whether it changed the cluster is unknown. If it did, undo it manually: ${command.rollbackCommand}`,
|
|
507
|
+
};
|
|
508
|
+
leftForHuman.push(command);
|
|
509
|
+
anyFailed = true;
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
if (
|
|
513
|
+
plan.commands.some((command: AiRemediationCommand) => {
|
|
514
|
+
return (
|
|
515
|
+
command.rollbackExecution !== undefined &&
|
|
516
|
+
!isSettledCommandExecutionStatus(command.rollbackExecution.status)
|
|
517
|
+
);
|
|
518
|
+
})
|
|
519
|
+
) {
|
|
520
|
+
// A rollback of an interrupted attempt whose outcome is unknown.
|
|
521
|
+
anyFailed = true;
|
|
522
|
+
}
|
|
228
523
|
|
|
229
524
|
const rollbackTargets: Array<AiRemediationCommand> = plan.commands
|
|
230
525
|
.filter((command: AiRemediationCommand) => {
|
|
@@ -237,19 +532,35 @@ export default class CommandPlanExecutor {
|
|
|
237
532
|
})
|
|
238
533
|
.reverse();
|
|
239
534
|
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
535
|
+
/*
|
|
536
|
+
* Nothing to run and nothing that went wrong, now or in an
|
|
537
|
+
* interrupted attempt: Completed when some undo ran, NotApplicable
|
|
538
|
+
* when none was ever needed. Anything else goes through the end of
|
|
539
|
+
* this method, which settles the status from the whole plan and says
|
|
540
|
+
* so on the feed.
|
|
541
|
+
*/
|
|
542
|
+
if (rollbackTargets.length === 0 && !anyFailed) {
|
|
543
|
+
plan.rollbackStatus = plan.commands.some(
|
|
544
|
+
(command: AiRemediationCommand) => {
|
|
545
|
+
return (
|
|
546
|
+
command.rollbackExecution?.status ===
|
|
547
|
+
AiRemediationCommandExecutionStatus.Succeeded
|
|
548
|
+
);
|
|
549
|
+
},
|
|
550
|
+
)
|
|
551
|
+
? AiRemediationRollbackStatus.Completed
|
|
552
|
+
: AiRemediationRollbackStatus.NotApplicable;
|
|
553
|
+
await this.persistPlan(suggestion, plan, "rollback");
|
|
554
|
+
return this.describeRollbackOutcome(plan);
|
|
244
555
|
}
|
|
245
556
|
|
|
246
|
-
let anyFailed: boolean = false;
|
|
247
|
-
|
|
248
557
|
for (const command of rollbackTargets) {
|
|
249
558
|
const rollbackCommand: string = command.rollbackCommand as string;
|
|
250
559
|
|
|
251
|
-
const denyReason: string | null =
|
|
252
|
-
|
|
560
|
+
const denyReason: string | null = this.getDenyReason({
|
|
561
|
+
stepType: command.stepType,
|
|
562
|
+
command: rollbackCommand,
|
|
563
|
+
});
|
|
253
564
|
|
|
254
565
|
if (denyReason) {
|
|
255
566
|
command.rollbackExecution = {
|
|
@@ -257,7 +568,34 @@ export default class CommandPlanExecutor {
|
|
|
257
568
|
errorMessage: `Rollback refused by the command policy: ${denyReason}.`,
|
|
258
569
|
};
|
|
259
570
|
anyFailed = true;
|
|
260
|
-
await this.persistPlan(suggestion, plan);
|
|
571
|
+
await this.persistPlan(suggestion, plan, "rollback");
|
|
572
|
+
continue;
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
/*
|
|
576
|
+
* A rollback runs with nobody watching, so it has to be allowed
|
|
577
|
+
* unattended by the cluster as it is configured NOW — not as it was
|
|
578
|
+
* when the plan accepted the rollback. A RiskyWrite undo accepted
|
|
579
|
+
* while the operator bypassed approvals must not run once they
|
|
580
|
+
* stopped bypassing them; a cluster whose remediation was turned
|
|
581
|
+
* off must not be changed at all. Left for a human, and said so.
|
|
582
|
+
*/
|
|
583
|
+
const clusterRefusal: string | null =
|
|
584
|
+
await this.getClusterExecutionRefusal({
|
|
585
|
+
suggestion,
|
|
586
|
+
command,
|
|
587
|
+
commandText: rollbackCommand,
|
|
588
|
+
purpose: "rollback",
|
|
589
|
+
});
|
|
590
|
+
|
|
591
|
+
if (clusterRefusal) {
|
|
592
|
+
command.rollbackExecution = {
|
|
593
|
+
status: AiRemediationCommandExecutionStatus.Skipped,
|
|
594
|
+
errorMessage: `Rollback not run: ${clusterRefusal}. Undo it manually: ${rollbackCommand}`,
|
|
595
|
+
};
|
|
596
|
+
leftForHuman.push(command);
|
|
597
|
+
anyFailed = true;
|
|
598
|
+
await this.persistPlan(suggestion, plan, "rollback");
|
|
261
599
|
continue;
|
|
262
600
|
}
|
|
263
601
|
|
|
@@ -265,23 +603,20 @@ export default class CommandPlanExecutor {
|
|
|
265
603
|
status: AiRemediationCommandExecutionStatus.Pending,
|
|
266
604
|
startedAt: OneUptimeDate.getCurrentDate().toISOString(),
|
|
267
605
|
};
|
|
268
|
-
|
|
606
|
+
plan.rollbackHeartbeatAt = OneUptimeDate.getCurrentDate().toISOString();
|
|
607
|
+
await this.persistPlan(suggestion, plan, "rollback");
|
|
269
608
|
|
|
270
609
|
try {
|
|
271
|
-
const job: RunnerJob = await
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
stepId:
|
|
276
|
-
stepType: command.stepType,
|
|
277
|
-
targetAgentId: new ObjectID(command.runnerId),
|
|
278
|
-
command: rollbackCommand,
|
|
279
|
-
credentialId: command.credentialId,
|
|
280
|
-
timeoutInMs: command.timeoutInMs,
|
|
281
|
-
claimTimeoutInMs: AI_COMMAND_CLAIM_TIMEOUT_MS,
|
|
610
|
+
const job: RunnerJob = await this.enqueue({
|
|
611
|
+
suggestion,
|
|
612
|
+
command,
|
|
613
|
+
commandText: rollbackCommand,
|
|
614
|
+
stepId: getRollbackCommandStepId(command),
|
|
282
615
|
});
|
|
283
616
|
|
|
617
|
+
// The job id lands before the wait — see startOneCommand.
|
|
284
618
|
command.rollbackExecution.runnerJobId = job.id?.toString();
|
|
619
|
+
await this.persistPlan(suggestion, plan, "rollback");
|
|
285
620
|
|
|
286
621
|
const terminalJob: RunnerJob =
|
|
287
622
|
await RunnerJobService.pollUntilTerminal({
|
|
@@ -290,22 +625,15 @@ export default class CommandPlanExecutor {
|
|
|
290
625
|
executionTimeoutInMs: command.timeoutInMs,
|
|
291
626
|
});
|
|
292
627
|
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
? AiRemediationCommandExecutionStatus.Succeeded
|
|
298
|
-
: AiRemediationCommandExecutionStatus.Failed;
|
|
299
|
-
command.rollbackExecution.completedAt =
|
|
300
|
-
OneUptimeDate.getCurrentDate().toISOString();
|
|
301
|
-
command.rollbackExecution.exitCode = terminalJob.exitCode;
|
|
302
|
-
command.rollbackExecution.output = this.capOutput(
|
|
303
|
-
terminalJob.output || "",
|
|
628
|
+
this.settleFromJob(
|
|
629
|
+
command.rollbackExecution,
|
|
630
|
+
terminalJob,
|
|
631
|
+
"Rollback",
|
|
304
632
|
);
|
|
305
|
-
if (
|
|
306
|
-
command.rollbackExecution.
|
|
307
|
-
|
|
308
|
-
|
|
633
|
+
if (
|
|
634
|
+
command.rollbackExecution.status !==
|
|
635
|
+
AiRemediationCommandExecutionStatus.Succeeded
|
|
636
|
+
) {
|
|
309
637
|
anyFailed = true;
|
|
310
638
|
}
|
|
311
639
|
} catch (error) {
|
|
@@ -316,49 +644,127 @@ export default class CommandPlanExecutor {
|
|
|
316
644
|
anyFailed = true;
|
|
317
645
|
}
|
|
318
646
|
|
|
319
|
-
await this.persistPlan(suggestion, plan);
|
|
647
|
+
await this.persistPlan(suggestion, plan, "rollback");
|
|
320
648
|
}
|
|
321
649
|
|
|
322
650
|
plan.rollbackStatus = anyFailed
|
|
323
651
|
? AiRemediationRollbackStatus.Failed
|
|
324
652
|
: AiRemediationRollbackStatus.Completed;
|
|
325
|
-
await this.persistPlan(suggestion, plan);
|
|
653
|
+
await this.persistPlan(suggestion, plan, "rollback");
|
|
654
|
+
|
|
655
|
+
const failedUndos: number = plan.commands.filter(
|
|
656
|
+
(command: AiRemediationCommand) => {
|
|
657
|
+
return (
|
|
658
|
+
command.rollbackExecution?.status ===
|
|
659
|
+
AiRemediationCommandExecutionStatus.Failed
|
|
660
|
+
);
|
|
661
|
+
},
|
|
662
|
+
).length;
|
|
326
663
|
|
|
327
664
|
await this.postFeedItem({
|
|
328
665
|
suggestion,
|
|
329
|
-
markdown:
|
|
330
|
-
|
|
331
|
-
|
|
666
|
+
markdown:
|
|
667
|
+
leftForHuman.length > 0
|
|
668
|
+
? `⚠️ **Auto-remediation rollback was not run for ${leftForHuman.length} command(s)** — the cluster no longer allows them unattended, or whether they ran could not be confirmed, so a human has to undo them. ${leftForHuman
|
|
669
|
+
.map((command: AiRemediationCommand) => {
|
|
670
|
+
return this.capForFeed(
|
|
671
|
+
command.rollbackExecution?.errorMessage || "",
|
|
672
|
+
);
|
|
673
|
+
})
|
|
674
|
+
.join(" ")}${
|
|
675
|
+
failedUndos > 0
|
|
676
|
+
? ` ${failedUndos} other rollback command(s) failed.`
|
|
677
|
+
: ""
|
|
678
|
+
} Review the suggestion's per-command record; manual intervention is needed.`
|
|
679
|
+
: anyFailed
|
|
680
|
+
? `⚠️ **Auto-remediation rollback did not fully complete** — at least one rollback command failed, or its outcome is not known. Review the suggestion's per-command record; manual intervention may be needed.`
|
|
681
|
+
: `↩️ **Auto-remediation rolled back** — the executed commands' rollback commands ran after verification failed. Escalation continues as normal.`,
|
|
332
682
|
pingWorkspace: true,
|
|
333
683
|
displayColor: anyFailed ? Red500 : Green500,
|
|
334
684
|
});
|
|
685
|
+
|
|
686
|
+
return this.describeRollbackOutcome(plan);
|
|
335
687
|
} catch (error) {
|
|
336
688
|
logger.error(
|
|
337
689
|
`CommandPlanExecutor: rollback failed for suggestion ${suggestion.id?.toString()}: ${error}`,
|
|
338
690
|
);
|
|
691
|
+
|
|
692
|
+
/*
|
|
693
|
+
* Settle it as Failed so nobody assumes it was undone — and so the
|
|
694
|
+
* recovery sweep does not retry a rollback that throws every time.
|
|
695
|
+
*/
|
|
696
|
+
if (plan) {
|
|
697
|
+
plan.rollbackStatus = AiRemediationRollbackStatus.Failed;
|
|
698
|
+
await this.persistPlan(suggestion, plan, "rollback");
|
|
699
|
+
await this.postFeedItem({
|
|
700
|
+
suggestion,
|
|
701
|
+
markdown: `⚠️ **Auto-remediation rollback could not complete** — an unexpected error stopped it. Review the suggestion's per-command record; manual intervention may be needed.`,
|
|
702
|
+
pingWorkspace: true,
|
|
703
|
+
displayColor: Red500,
|
|
704
|
+
});
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
return this.describeRollbackOutcome(plan);
|
|
339
708
|
}
|
|
340
709
|
}
|
|
341
710
|
|
|
342
711
|
// ------------------------------------------------------------------
|
|
343
712
|
|
|
344
|
-
|
|
713
|
+
/*
|
|
714
|
+
* Everything up to and including the enqueue: the execution-time policy
|
|
715
|
+
* floor, the cluster re-check, the enqueue, and the write that names the
|
|
716
|
+
* job. Runs under the plan lock (see executeApprovedPlan).
|
|
717
|
+
*/
|
|
718
|
+
private static async startOneCommand(data: {
|
|
345
719
|
suggestion: AutoRemediationSuggestion;
|
|
720
|
+
plan: AiRemediationCommandPlan;
|
|
346
721
|
command: AiRemediationCommand;
|
|
347
|
-
}): Promise<
|
|
348
|
-
const { suggestion, command } = data;
|
|
722
|
+
}): Promise<StartedCommand> {
|
|
723
|
+
const { suggestion, plan, command } = data;
|
|
349
724
|
|
|
350
725
|
/*
|
|
351
726
|
* Execution-time denylist re-check: the plan was validated when it was
|
|
352
727
|
* composed, but the policy may have been tightened since.
|
|
353
728
|
*/
|
|
354
|
-
const denyReason: string | null =
|
|
355
|
-
command.
|
|
356
|
-
|
|
729
|
+
const denyReason: string | null = this.getDenyReason({
|
|
730
|
+
stepType: command.stepType,
|
|
731
|
+
command: command.command,
|
|
732
|
+
});
|
|
357
733
|
|
|
358
734
|
if (denyReason) {
|
|
359
735
|
return {
|
|
360
|
-
|
|
361
|
-
|
|
736
|
+
state: {
|
|
737
|
+
status: AiRemediationCommandExecutionStatus.Failed,
|
|
738
|
+
errorMessage: `Refused by the remediation command policy at execution time: ${denyReason}.`,
|
|
739
|
+
},
|
|
740
|
+
job: null,
|
|
741
|
+
recordsClusterOutcome: false,
|
|
742
|
+
};
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
/*
|
|
746
|
+
* Execution-time cluster re-check: the approve API re-checks the
|
|
747
|
+
* project switches, this re-checks the cluster's own AI page. An
|
|
748
|
+
* operator who turned remediation off, or bound a different Runner,
|
|
749
|
+
* after the plan was composed expects that to stop the plan too.
|
|
750
|
+
*/
|
|
751
|
+
const clusterRefusal: string | null = await this.getClusterExecutionRefusal(
|
|
752
|
+
{
|
|
753
|
+
suggestion,
|
|
754
|
+
command,
|
|
755
|
+
commandText: command.command,
|
|
756
|
+
purpose: "command",
|
|
757
|
+
},
|
|
758
|
+
);
|
|
759
|
+
|
|
760
|
+
if (clusterRefusal) {
|
|
761
|
+
return {
|
|
762
|
+
state: {
|
|
763
|
+
status: AiRemediationCommandExecutionStatus.Failed,
|
|
764
|
+
errorMessage: `Refused at execution time: ${clusterRefusal}.`,
|
|
765
|
+
},
|
|
766
|
+
job: null,
|
|
767
|
+
recordsClusterOutcome: false,
|
|
362
768
|
};
|
|
363
769
|
}
|
|
364
770
|
|
|
@@ -370,104 +776,451 @@ export default class CommandPlanExecutor {
|
|
|
370
776
|
};
|
|
371
777
|
|
|
372
778
|
try {
|
|
373
|
-
const job: RunnerJob = await
|
|
779
|
+
const job: RunnerJob = await this.enqueue({
|
|
780
|
+
suggestion,
|
|
781
|
+
command,
|
|
782
|
+
commandText: command.command,
|
|
783
|
+
// Approved plans never hold inline-executed commands (skipped above).
|
|
784
|
+
stepId: getForwardCommandStepId(command),
|
|
785
|
+
});
|
|
786
|
+
|
|
787
|
+
/*
|
|
788
|
+
* The job id lands on the record BEFORE the wait: a pod death while
|
|
789
|
+
* polling must leave a Pending command that names its RunnerJob, so
|
|
790
|
+
* the rollback arm can resolve what really happened instead of
|
|
791
|
+
* treating the command as one that never reached the Runner.
|
|
792
|
+
*/
|
|
793
|
+
state.runnerJobId = job.id?.toString();
|
|
794
|
+
command.execution = state;
|
|
795
|
+
await this.persistPlan(suggestion, plan, "executor", {
|
|
796
|
+
planLocked: true,
|
|
797
|
+
});
|
|
798
|
+
|
|
799
|
+
return { state, job, recordsClusterOutcome: true };
|
|
800
|
+
} catch (error) {
|
|
801
|
+
state.status = AiRemediationCommandExecutionStatus.Failed;
|
|
802
|
+
state.completedAt = OneUptimeDate.getCurrentDate().toISOString();
|
|
803
|
+
state.errorMessage =
|
|
804
|
+
error instanceof Error ? error.message : String(error);
|
|
805
|
+
|
|
806
|
+
return { state, job: null, recordsClusterOutcome: true };
|
|
807
|
+
}
|
|
808
|
+
}
|
|
809
|
+
|
|
810
|
+
// The wait (outside the plan lock) and the outcome.
|
|
811
|
+
private static async finishOneCommand(data: {
|
|
812
|
+
command: AiRemediationCommand;
|
|
813
|
+
started: StartedCommand;
|
|
814
|
+
}): Promise<AiRemediationCommandExecutionState> {
|
|
815
|
+
const { command, started } = data;
|
|
816
|
+
const state: AiRemediationCommandExecutionState = started.state;
|
|
817
|
+
|
|
818
|
+
/*
|
|
819
|
+
* What the job's end says about the cluster's ACCESS. A job that never
|
|
820
|
+
* reached a Runner (the enqueue refused it) is an access failure; a
|
|
821
|
+
* wait that threw says nothing about the cluster.
|
|
822
|
+
*/
|
|
823
|
+
let facts: KubectlTerminalJobFacts | null = started.job
|
|
824
|
+
? null
|
|
825
|
+
: { status: RunnerJobStatus.Failed, errorMessage: state.errorMessage };
|
|
826
|
+
|
|
827
|
+
if (started.job) {
|
|
828
|
+
try {
|
|
829
|
+
const terminalJob: RunnerJob = await RunnerJobService.pollUntilTerminal(
|
|
830
|
+
{
|
|
831
|
+
jobId: started.job.id!,
|
|
832
|
+
claimTimeoutInMs: AI_COMMAND_CLAIM_TIMEOUT_MS,
|
|
833
|
+
executionTimeoutInMs: command.timeoutInMs,
|
|
834
|
+
},
|
|
835
|
+
);
|
|
836
|
+
|
|
837
|
+
if (!isTerminalAgentJobStatus(terminalJob.status)) {
|
|
838
|
+
throw new Error("Command job did not reach a terminal state.");
|
|
839
|
+
}
|
|
840
|
+
|
|
841
|
+
this.settleFromJob(state, terminalJob, "Command");
|
|
842
|
+
facts = {
|
|
843
|
+
status: terminalJob.status,
|
|
844
|
+
exitCode: terminalJob.exitCode,
|
|
845
|
+
output: terminalJob.output,
|
|
846
|
+
errorMessage: terminalJob.errorMessage,
|
|
847
|
+
};
|
|
848
|
+
} catch (error) {
|
|
849
|
+
state.status = AiRemediationCommandExecutionStatus.Failed;
|
|
850
|
+
state.completedAt = OneUptimeDate.getCurrentDate().toISOString();
|
|
851
|
+
state.errorMessage =
|
|
852
|
+
error instanceof Error ? error.message : String(error);
|
|
853
|
+
}
|
|
854
|
+
}
|
|
855
|
+
|
|
856
|
+
/*
|
|
857
|
+
* The cluster's "Last error" is about its AI ACCESS: a success proves
|
|
858
|
+
* the access works, and a failure is recorded only when it is about
|
|
859
|
+
* the access (never claimed, refused, timed out, unauthorized,
|
|
860
|
+
* unreachable). A deployment the plan named wrong must neither become
|
|
861
|
+
* the cluster's last error nor clear a real one.
|
|
862
|
+
*/
|
|
863
|
+
const succeeded: boolean =
|
|
864
|
+
state.status === AiRemediationCommandExecutionStatus.Succeeded;
|
|
865
|
+
const recordsOutcome: boolean =
|
|
866
|
+
succeeded || (facts !== null && KubectlJobRunner.isAccessFailure(facts));
|
|
867
|
+
|
|
868
|
+
if (
|
|
869
|
+
started.recordsClusterOutcome &&
|
|
870
|
+
recordsOutcome &&
|
|
871
|
+
command.stepType === RunbookStepType.Kubectl &&
|
|
872
|
+
command.kubernetesClusterId &&
|
|
873
|
+
ObjectID.isValidUUID(command.kubernetesClusterId)
|
|
874
|
+
) {
|
|
875
|
+
await KubernetesClusterAiAccessService.recordCommandOutcome({
|
|
876
|
+
clusterId: new ObjectID(command.kubernetesClusterId),
|
|
877
|
+
succeeded:
|
|
878
|
+
state.status === AiRemediationCommandExecutionStatus.Succeeded,
|
|
879
|
+
errorMessage: state.errorMessage,
|
|
880
|
+
});
|
|
881
|
+
}
|
|
882
|
+
|
|
883
|
+
return state;
|
|
884
|
+
}
|
|
885
|
+
|
|
886
|
+
// Copy a terminal job's outcome onto an execution record.
|
|
887
|
+
private static settleFromJob(
|
|
888
|
+
state: AiRemediationCommandExecutionState,
|
|
889
|
+
job: RunnerJob,
|
|
890
|
+
label: "Command" | "Rollback",
|
|
891
|
+
): void {
|
|
892
|
+
const succeeded: boolean = job.status === RunnerJobStatus.Succeeded;
|
|
893
|
+
|
|
894
|
+
state.status = succeeded
|
|
895
|
+
? AiRemediationCommandExecutionStatus.Succeeded
|
|
896
|
+
: AiRemediationCommandExecutionStatus.Failed;
|
|
897
|
+
state.completedAt = OneUptimeDate.getCurrentDate().toISOString();
|
|
898
|
+
state.exitCode = job.exitCode;
|
|
899
|
+
state.output = this.capOutput(job.output || "");
|
|
900
|
+
state.errorMessage = succeeded
|
|
901
|
+
? undefined
|
|
902
|
+
: job.errorMessage || `${label} ended with status ${job.status}.`;
|
|
903
|
+
}
|
|
904
|
+
|
|
905
|
+
/*
|
|
906
|
+
* One enqueue for both lanes. Bash/SSH go through enqueueAiCommand
|
|
907
|
+
* (script or SSH payload); Kubectl goes through enqueueAiKubectlCommand
|
|
908
|
+
* (argv + cluster + optional credential), whose policy is re-run there.
|
|
909
|
+
*/
|
|
910
|
+
private static async enqueue(data: {
|
|
911
|
+
suggestion: AutoRemediationSuggestion;
|
|
912
|
+
command: AiRemediationCommand;
|
|
913
|
+
commandText: string;
|
|
914
|
+
stepId: string;
|
|
915
|
+
}): Promise<RunnerJob> {
|
|
916
|
+
const { suggestion, command } = data;
|
|
917
|
+
|
|
918
|
+
if (command.stepType === RunbookStepType.Kubectl) {
|
|
919
|
+
if (
|
|
920
|
+
!command.kubernetesClusterId ||
|
|
921
|
+
!ObjectID.isValidUUID(command.kubernetesClusterId)
|
|
922
|
+
) {
|
|
923
|
+
throw new Error("The kubectl command names no cluster.");
|
|
924
|
+
}
|
|
925
|
+
|
|
926
|
+
return RunnerJobService.enqueueAiKubectlCommand({
|
|
374
927
|
projectId: suggestion.projectId!,
|
|
375
928
|
aiRunId: suggestion.aiRunId!,
|
|
929
|
+
origin: RunnerJobOrigin.AiRemediation,
|
|
376
930
|
autoRemediationSuggestionId: suggestion.id!,
|
|
377
|
-
|
|
378
|
-
|
|
931
|
+
kubernetesClusterId: new ObjectID(command.kubernetesClusterId),
|
|
932
|
+
stepId: data.stepId,
|
|
379
933
|
targetAgentId: new ObjectID(command.runnerId),
|
|
380
|
-
command: command.command,
|
|
381
934
|
credentialId: command.credentialId,
|
|
935
|
+
command: data.commandText,
|
|
382
936
|
timeoutInMs: command.timeoutInMs,
|
|
383
937
|
claimTimeoutInMs: AI_COMMAND_CLAIM_TIMEOUT_MS,
|
|
384
938
|
});
|
|
939
|
+
}
|
|
385
940
|
|
|
386
|
-
|
|
941
|
+
return RunnerJobService.enqueueAiCommand({
|
|
942
|
+
projectId: suggestion.projectId!,
|
|
943
|
+
aiRunId: suggestion.aiRunId!,
|
|
944
|
+
autoRemediationSuggestionId: suggestion.id!,
|
|
945
|
+
stepId: data.stepId,
|
|
946
|
+
stepType: command.stepType,
|
|
947
|
+
targetAgentId: new ObjectID(command.runnerId),
|
|
948
|
+
command: data.commandText,
|
|
949
|
+
credentialId: command.credentialId,
|
|
950
|
+
timeoutInMs: command.timeoutInMs,
|
|
951
|
+
claimTimeoutInMs: AI_COMMAND_CLAIM_TIMEOUT_MS,
|
|
952
|
+
});
|
|
953
|
+
}
|
|
387
954
|
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
955
|
+
/*
|
|
956
|
+
* Why a kubectl command may NOT run on its cluster right now, or null.
|
|
957
|
+
*
|
|
958
|
+
* The plan froze the cluster, the Runner and the credential the cluster's
|
|
959
|
+
* AI page bound when the plan was composed. Before anything is enqueued
|
|
960
|
+
* the page is read again: remediation must still be enabled and ready
|
|
961
|
+
* (Disabled means "AI never runs a change on this cluster", whatever was
|
|
962
|
+
* approved earlier), and the bound Runner and credential must still be
|
|
963
|
+
* the ones on the plan — a re-bound cluster never receives a job meant
|
|
964
|
+
* for its previous access path. A rollback must ALSO be allowed
|
|
965
|
+
* unattended under the cluster's CURRENT mode and allowlist: nothing
|
|
966
|
+
* shows a rollback to a human when it fires.
|
|
967
|
+
*
|
|
968
|
+
* Fails closed: a status that cannot be read is a refusal. Bash/SSH
|
|
969
|
+
* commands have no cluster and pass through.
|
|
970
|
+
*/
|
|
971
|
+
private static async getClusterExecutionRefusal(data: {
|
|
972
|
+
suggestion: AutoRemediationSuggestion;
|
|
973
|
+
command: AiRemediationCommand;
|
|
974
|
+
commandText: string;
|
|
975
|
+
purpose: "command" | "rollback";
|
|
976
|
+
}): Promise<string | null> {
|
|
977
|
+
const { suggestion, command } = data;
|
|
978
|
+
|
|
979
|
+
if (command.stepType !== RunbookStepType.Kubectl) {
|
|
980
|
+
return null;
|
|
981
|
+
}
|
|
982
|
+
|
|
983
|
+
const clusterLabel: string =
|
|
984
|
+
command.kubernetesClusterNameSnapshot ||
|
|
985
|
+
command.kubernetesClusterId ||
|
|
986
|
+
"(unknown)";
|
|
987
|
+
|
|
988
|
+
if (
|
|
989
|
+
!command.kubernetesClusterId ||
|
|
990
|
+
!ObjectID.isValidUUID(command.kubernetesClusterId) ||
|
|
991
|
+
!suggestion.projectId
|
|
992
|
+
) {
|
|
993
|
+
return `the kubectl command names no valid cluster`;
|
|
994
|
+
}
|
|
995
|
+
|
|
996
|
+
let status: KubernetesClusterAiAccessStatus | null;
|
|
997
|
+
|
|
998
|
+
try {
|
|
999
|
+
status = await KubernetesClusterAiAccessService.getStatusForCluster({
|
|
1000
|
+
clusterId: new ObjectID(command.kubernetesClusterId),
|
|
1001
|
+
projectId: suggestion.projectId,
|
|
392
1002
|
});
|
|
1003
|
+
} catch (error) {
|
|
1004
|
+
logger.error(
|
|
1005
|
+
`CommandPlanExecutor: could not read the AI access status of cluster ${command.kubernetesClusterId} before a ${data.purpose}: ${error}`,
|
|
1006
|
+
);
|
|
1007
|
+
return `could not confirm that cluster "${clusterLabel}" still allows AI remediation`;
|
|
1008
|
+
}
|
|
393
1009
|
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
1010
|
+
if (!status) {
|
|
1011
|
+
return `cluster "${clusterLabel}" no longer exists in this project`;
|
|
1012
|
+
}
|
|
397
1013
|
|
|
398
|
-
|
|
399
|
-
|
|
1014
|
+
if (!status.isRemediationReady) {
|
|
1015
|
+
const gap: KubernetesAiAccessGap | undefined = status.gaps.find(
|
|
1016
|
+
(candidate: KubernetesAiAccessGap) => {
|
|
1017
|
+
return candidate.blocks !== "investigation";
|
|
1018
|
+
},
|
|
1019
|
+
);
|
|
1020
|
+
return `cluster "${status.clusterName}" no longer allows AI remediation${
|
|
1021
|
+
gap ? ` (${gap.title})` : ""
|
|
1022
|
+
}`;
|
|
1023
|
+
}
|
|
400
1024
|
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
1025
|
+
if (!status.runner || status.runner.id !== command.runnerId) {
|
|
1026
|
+
return `cluster "${status.clusterName}" is no longer reached through Runner "${command.runnerNameSnapshot}", which this plan was composed for`;
|
|
1027
|
+
}
|
|
1028
|
+
|
|
1029
|
+
if (
|
|
1030
|
+
(status.credentialId || undefined) !== (command.credentialId || undefined)
|
|
1031
|
+
) {
|
|
1032
|
+
return `cluster "${status.clusterName}" is no longer reached with the credential this plan was composed for`;
|
|
1033
|
+
}
|
|
1034
|
+
|
|
1035
|
+
/*
|
|
1036
|
+
* The Runner's write scope as it reports it now: a write it would
|
|
1037
|
+
* refuse is not enqueued (or, for a rollback, is left for a human with
|
|
1038
|
+
* the reason) — never sent only to be refused.
|
|
1039
|
+
*/
|
|
1040
|
+
const scopeRefusal: string | null =
|
|
1041
|
+
RemediationCommandToolkit.getRunnerScopeRefusal({
|
|
1042
|
+
cluster: status,
|
|
1043
|
+
command: data.commandText,
|
|
1044
|
+
});
|
|
1045
|
+
|
|
1046
|
+
if (scopeRefusal) {
|
|
1047
|
+
// The callers end the sentence themselves.
|
|
1048
|
+
return `the cluster's Runner would refuse it: ${
|
|
1049
|
+
scopeRefusal.endsWith(".") ? scopeRefusal.slice(0, -1) : scopeRefusal
|
|
1050
|
+
}`;
|
|
1051
|
+
}
|
|
1052
|
+
|
|
1053
|
+
if (data.purpose === "rollback") {
|
|
1054
|
+
const verdict: KubectlAutoExecutionVerdict =
|
|
1055
|
+
KubectlPolicy.evaluateForAutoExecution({
|
|
1056
|
+
command: data.commandText,
|
|
1057
|
+
allowlistPatterns: status.kubectlAllowlist,
|
|
1058
|
+
bypassApproval:
|
|
1059
|
+
status.remediationMode ===
|
|
1060
|
+
KubernetesAiRemediationMode.BypassApproval,
|
|
1061
|
+
});
|
|
1062
|
+
|
|
1063
|
+
if (verdict.verdict !== AiRemediationCommandPolicyVerdict.AutoApproved) {
|
|
1064
|
+
return `cluster "${status.clusterName}" no longer allows this change unattended (its AI remediation mode is now ${status.remediationMode}): ${verdict.reason}`;
|
|
411
1065
|
}
|
|
412
|
-
} catch (error) {
|
|
413
|
-
state.status = AiRemediationCommandExecutionStatus.Failed;
|
|
414
|
-
state.completedAt = OneUptimeDate.getCurrentDate().toISOString();
|
|
415
|
-
state.errorMessage =
|
|
416
|
-
error instanceof Error ? error.message : String(error);
|
|
417
1066
|
}
|
|
418
1067
|
|
|
419
|
-
return
|
|
1068
|
+
return null;
|
|
1069
|
+
}
|
|
1070
|
+
|
|
1071
|
+
/*
|
|
1072
|
+
* The job a command's step ran under, when its record never got the job
|
|
1073
|
+
* id. The enqueue and the write that names the job are two steps; a pod
|
|
1074
|
+
* death or a failed write between them leaves a Pending record for a job
|
|
1075
|
+
* the Runner was nonetheless handed. (suggestion, stepId) is unique per
|
|
1076
|
+
* forward command — a plan executes at most once and a retried run never
|
|
1077
|
+
* re-executes — and per rollback; the newest row wins should that ever
|
|
1078
|
+
* change.
|
|
1079
|
+
*/
|
|
1080
|
+
private static async findJobByStepId(data: {
|
|
1081
|
+
suggestion: AutoRemediationSuggestion;
|
|
1082
|
+
stepId: string;
|
|
1083
|
+
}): Promise<RunnerJob | null> {
|
|
1084
|
+
if (!data.suggestion.id) {
|
|
1085
|
+
return null;
|
|
1086
|
+
}
|
|
1087
|
+
|
|
1088
|
+
const jobs: Array<RunnerJob> = await RunnerJobService.findBy({
|
|
1089
|
+
query: {
|
|
1090
|
+
...(data.suggestion.projectId
|
|
1091
|
+
? { projectId: data.suggestion.projectId }
|
|
1092
|
+
: {}),
|
|
1093
|
+
autoRemediationSuggestionId: data.suggestion.id,
|
|
1094
|
+
origin: RunnerJobOrigin.AiRemediation,
|
|
1095
|
+
stepId: data.stepId,
|
|
1096
|
+
},
|
|
1097
|
+
select: RECONCILE_JOB_SELECT,
|
|
1098
|
+
sort: { createdAt: SortOrder.Descending },
|
|
1099
|
+
limit: 1,
|
|
1100
|
+
skip: 0,
|
|
1101
|
+
props: { isRoot: true },
|
|
1102
|
+
});
|
|
1103
|
+
|
|
1104
|
+
return jobs[0] || null;
|
|
1105
|
+
}
|
|
1106
|
+
|
|
1107
|
+
private static capForFeed(text: string): string {
|
|
1108
|
+
const collapsed: string = text.trim().replace(/\s+/g, " ");
|
|
1109
|
+
return collapsed.length > MAX_FEED_REASON_CHARS
|
|
1110
|
+
? `${collapsed.slice(0, MAX_FEED_REASON_CHARS)}…`
|
|
1111
|
+
: collapsed;
|
|
1112
|
+
}
|
|
1113
|
+
|
|
1114
|
+
/*
|
|
1115
|
+
* Execution-time policy floor per lane: the bash denylist for Bash/SSH,
|
|
1116
|
+
* the Denied tier for Kubectl. Null when the command may run.
|
|
1117
|
+
*/
|
|
1118
|
+
private static getDenyReason(data: {
|
|
1119
|
+
stepType: RunbookStepType;
|
|
1120
|
+
command: string;
|
|
1121
|
+
}): string | null {
|
|
1122
|
+
if (data.stepType === RunbookStepType.Kubectl) {
|
|
1123
|
+
const policy: KubectlPolicyResult = KubectlPolicy.evaluateCommand(
|
|
1124
|
+
data.command,
|
|
1125
|
+
);
|
|
1126
|
+
return policy.tier === KubectlCommandTier.Denied ? policy.reason : null;
|
|
1127
|
+
}
|
|
1128
|
+
|
|
1129
|
+
return CommandPolicy.getDenyReason(data.command);
|
|
420
1130
|
}
|
|
421
1131
|
|
|
422
1132
|
/*
|
|
423
1133
|
* Settle commands left in Pending/Running by reading their RunnerJob. A
|
|
424
1134
|
* job that reached Succeeded really ran, so the command becomes Succeeded
|
|
425
|
-
* (and therefore rollback-eligible); any other terminal state
|
|
426
|
-
*
|
|
1135
|
+
* (and therefore rollback-eligible); any other terminal state becomes
|
|
1136
|
+
* Failed. A job still in flight is WAITED for when `waitForInFlight` is
|
|
1137
|
+
* set (the rollback arm: the change is about to land, and its undo must
|
|
1138
|
+
* not be skipped); otherwise it is left alone.
|
|
1139
|
+
*
|
|
1140
|
+
* The job is found by the id on the record, or — when the record never
|
|
1141
|
+
* got one, because the pod died or the write failed between the enqueue
|
|
1142
|
+
* and the persist that names the job — by the (suggestion, stepId) pair
|
|
1143
|
+
* the lane enqueued it under. A command with neither never reached the
|
|
1144
|
+
* Runner and is left alone.
|
|
427
1145
|
*/
|
|
428
1146
|
private static async reconcilePendingExecutions(
|
|
429
1147
|
suggestion: AutoRemediationSuggestion,
|
|
430
1148
|
plan: AiRemediationCommandPlan,
|
|
1149
|
+
options: { waitForInFlight: boolean },
|
|
431
1150
|
): Promise<void> {
|
|
432
1151
|
let changed: boolean = false;
|
|
433
1152
|
|
|
434
1153
|
for (const command of plan.commands) {
|
|
435
|
-
const
|
|
436
|
-
command.execution
|
|
1154
|
+
const execution: AiRemediationCommandExecutionState | undefined =
|
|
1155
|
+
command.execution;
|
|
1156
|
+
|
|
1157
|
+
if (!execution) {
|
|
1158
|
+
continue;
|
|
1159
|
+
}
|
|
437
1160
|
|
|
438
1161
|
const isUnsettled: boolean =
|
|
439
|
-
status === AiRemediationCommandExecutionStatus.Pending ||
|
|
440
|
-
status === AiRemediationCommandExecutionStatus.Running;
|
|
1162
|
+
execution.status === AiRemediationCommandExecutionStatus.Pending ||
|
|
1163
|
+
execution.status === AiRemediationCommandExecutionStatus.Running;
|
|
441
1164
|
|
|
442
|
-
if (!isUnsettled
|
|
1165
|
+
if (!isUnsettled) {
|
|
443
1166
|
continue;
|
|
444
1167
|
}
|
|
445
1168
|
|
|
446
1169
|
try {
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
});
|
|
1170
|
+
let job: RunnerJob | null = execution.runnerJobId
|
|
1171
|
+
? await RunnerJobService.findOneById({
|
|
1172
|
+
id: new ObjectID(execution.runnerJobId),
|
|
1173
|
+
select: RECONCILE_JOB_SELECT,
|
|
1174
|
+
props: { isRoot: true },
|
|
1175
|
+
})
|
|
1176
|
+
: await this.findJobByStepId({
|
|
1177
|
+
suggestion,
|
|
1178
|
+
stepId: getForwardCommandStepId(command),
|
|
1179
|
+
});
|
|
458
1180
|
|
|
459
|
-
if (!job
|
|
1181
|
+
if (!job) {
|
|
460
1182
|
continue;
|
|
461
1183
|
}
|
|
462
1184
|
|
|
1185
|
+
// Recovered by stepId: name the job so the record stays resolvable.
|
|
1186
|
+
if (!execution.runnerJobId && job.id) {
|
|
1187
|
+
execution.runnerJobId = job.id.toString();
|
|
1188
|
+
changed = true;
|
|
1189
|
+
}
|
|
1190
|
+
|
|
1191
|
+
if (!isTerminalAgentJobStatus(job.status)) {
|
|
1192
|
+
if (!options.waitForInFlight || !job.id) {
|
|
1193
|
+
continue;
|
|
1194
|
+
}
|
|
1195
|
+
|
|
1196
|
+
// Say where the rollback stands before a wait that can take minutes.
|
|
1197
|
+
if (changed) {
|
|
1198
|
+
await this.persistPlan(suggestion, plan, "rollback");
|
|
1199
|
+
changed = false;
|
|
1200
|
+
}
|
|
1201
|
+
plan.rollbackHeartbeatAt =
|
|
1202
|
+
OneUptimeDate.getCurrentDate().toISOString();
|
|
1203
|
+
await this.persistPlan(suggestion, plan, "rollback");
|
|
1204
|
+
|
|
1205
|
+
job = await RunnerJobService.pollUntilTerminal({
|
|
1206
|
+
jobId: job.id,
|
|
1207
|
+
claimTimeoutInMs: AI_COMMAND_CLAIM_TIMEOUT_MS,
|
|
1208
|
+
executionTimeoutInMs: command.timeoutInMs,
|
|
1209
|
+
});
|
|
1210
|
+
|
|
1211
|
+
if (!isTerminalAgentJobStatus(job.status)) {
|
|
1212
|
+
continue;
|
|
1213
|
+
}
|
|
1214
|
+
}
|
|
1215
|
+
|
|
463
1216
|
const succeeded: boolean = job.status === RunnerJobStatus.Succeeded;
|
|
464
1217
|
|
|
465
|
-
|
|
1218
|
+
execution.status = succeeded
|
|
466
1219
|
? AiRemediationCommandExecutionStatus.Succeeded
|
|
467
1220
|
: AiRemediationCommandExecutionStatus.Failed;
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
1221
|
+
execution.exitCode = job.exitCode;
|
|
1222
|
+
execution.output = this.capOutput(job.output || "");
|
|
1223
|
+
execution.errorMessage = succeeded
|
|
471
1224
|
? undefined
|
|
472
1225
|
: job.errorMessage ||
|
|
473
1226
|
`Command ended with status ${job.status} (recovered from the job record).`;
|
|
@@ -480,10 +1233,231 @@ export default class CommandPlanExecutor {
|
|
|
480
1233
|
}
|
|
481
1234
|
|
|
482
1235
|
if (changed) {
|
|
483
|
-
await this.persistPlan(suggestion, plan);
|
|
1236
|
+
await this.persistPlan(suggestion, plan, "rollback");
|
|
1237
|
+
}
|
|
1238
|
+
}
|
|
1239
|
+
|
|
1240
|
+
/*
|
|
1241
|
+
* A rollback resumed after a Worker restart: settle the undos the
|
|
1242
|
+
* interrupted attempt had already started. One with a job — on the record
|
|
1243
|
+
* or found under its rollback step id — is settled from that job
|
|
1244
|
+
* (waiting for it when it is still running): it is never run a second
|
|
1245
|
+
* time, because running an undo twice (a second `rollout undo`) can put
|
|
1246
|
+
* the bad change right back. One that never reached a Runner is cleared,
|
|
1247
|
+
* so it runs now. One whose job cannot be looked up stays unsettled, and
|
|
1248
|
+
* the rollback is not reported complete.
|
|
1249
|
+
*/
|
|
1250
|
+
private static async reconcilePendingRollbacks(
|
|
1251
|
+
suggestion: AutoRemediationSuggestion,
|
|
1252
|
+
plan: AiRemediationCommandPlan,
|
|
1253
|
+
): Promise<void> {
|
|
1254
|
+
let changed: boolean = false;
|
|
1255
|
+
|
|
1256
|
+
for (const command of plan.commands) {
|
|
1257
|
+
const rollback: AiRemediationCommandExecutionState | undefined =
|
|
1258
|
+
command.rollbackExecution;
|
|
1259
|
+
|
|
1260
|
+
if (!rollback || isSettledCommandExecutionStatus(rollback.status)) {
|
|
1261
|
+
continue;
|
|
1262
|
+
}
|
|
1263
|
+
|
|
1264
|
+
try {
|
|
1265
|
+
let job: RunnerJob | null = rollback.runnerJobId
|
|
1266
|
+
? await RunnerJobService.findOneById({
|
|
1267
|
+
id: new ObjectID(rollback.runnerJobId),
|
|
1268
|
+
select: RECONCILE_JOB_SELECT,
|
|
1269
|
+
props: { isRoot: true },
|
|
1270
|
+
})
|
|
1271
|
+
: await this.findJobByStepId({
|
|
1272
|
+
suggestion,
|
|
1273
|
+
stepId: getRollbackCommandStepId(command),
|
|
1274
|
+
});
|
|
1275
|
+
|
|
1276
|
+
if (!job) {
|
|
1277
|
+
// Never reached a Runner: run it now.
|
|
1278
|
+
command.rollbackExecution = undefined;
|
|
1279
|
+
changed = true;
|
|
1280
|
+
continue;
|
|
1281
|
+
}
|
|
1282
|
+
|
|
1283
|
+
if (!rollback.runnerJobId && job.id) {
|
|
1284
|
+
rollback.runnerJobId = job.id.toString();
|
|
1285
|
+
changed = true;
|
|
1286
|
+
}
|
|
1287
|
+
|
|
1288
|
+
if (!isTerminalAgentJobStatus(job.status) && job.id) {
|
|
1289
|
+
plan.rollbackHeartbeatAt =
|
|
1290
|
+
OneUptimeDate.getCurrentDate().toISOString();
|
|
1291
|
+
await this.persistPlan(suggestion, plan, "rollback");
|
|
1292
|
+
|
|
1293
|
+
job = await RunnerJobService.pollUntilTerminal({
|
|
1294
|
+
jobId: job.id,
|
|
1295
|
+
claimTimeoutInMs: AI_COMMAND_CLAIM_TIMEOUT_MS,
|
|
1296
|
+
executionTimeoutInMs: command.timeoutInMs,
|
|
1297
|
+
});
|
|
1298
|
+
}
|
|
1299
|
+
|
|
1300
|
+
if (isTerminalAgentJobStatus(job.status)) {
|
|
1301
|
+
this.settleFromJob(rollback, job, "Rollback");
|
|
1302
|
+
changed = true;
|
|
1303
|
+
}
|
|
1304
|
+
} catch (error) {
|
|
1305
|
+
logger.error(
|
|
1306
|
+
`CommandPlanExecutor: could not reconcile the rollback of command ${command.sequence} of suggestion ${suggestion.id?.toString()}: ${error}`,
|
|
1307
|
+
);
|
|
1308
|
+
}
|
|
1309
|
+
}
|
|
1310
|
+
|
|
1311
|
+
if (changed) {
|
|
1312
|
+
await this.persistPlan(suggestion, plan, "rollback");
|
|
484
1313
|
}
|
|
485
1314
|
}
|
|
486
1315
|
|
|
1316
|
+
/*
|
|
1317
|
+
* The kubectl commands recorded as Failed that may nonetheless have
|
|
1318
|
+
* changed the cluster, read from their jobs the way KubectlJobRunner
|
|
1319
|
+
* reads every kubectl job (KubectlJobRunner.getRunStateOfJobRow). Only a
|
|
1320
|
+
* command that carries a rollbackCommand and has no rollback yet is read
|
|
1321
|
+
* — nothing else has an undo to owe.
|
|
1322
|
+
*
|
|
1323
|
+
* - A job that Succeeded after all (the wait for it broke, and the
|
|
1324
|
+
* record said Failed) is settled from the job: it becomes Succeeded,
|
|
1325
|
+
* and so a rollback target like any other.
|
|
1326
|
+
* - A job whose run is Unknown — a Runner took it and no result came
|
|
1327
|
+
* back, it is still in flight, or its row cannot be read — is
|
|
1328
|
+
* returned: whether it changed the cluster is not known. So is one
|
|
1329
|
+
* where kubectl ran but never finished (the Runner killed it at its
|
|
1330
|
+
* timeout, or it left output but no exit code): it may have applied
|
|
1331
|
+
* its change before it was stopped.
|
|
1332
|
+
* - A job that certainly never ran, or whose kubectl finished and
|
|
1333
|
+
* reported a failure (an exit code), owes no undo, as before.
|
|
1334
|
+
*/
|
|
1335
|
+
private static async reconcileFailedKubectlExecutions(
|
|
1336
|
+
suggestion: AutoRemediationSuggestion,
|
|
1337
|
+
plan: AiRemediationCommandPlan,
|
|
1338
|
+
): Promise<Array<AiRemediationCommand>> {
|
|
1339
|
+
const mayHaveRun: Array<AiRemediationCommand> = [];
|
|
1340
|
+
let changed: boolean = false;
|
|
1341
|
+
|
|
1342
|
+
for (const command of plan.commands) {
|
|
1343
|
+
const execution: AiRemediationCommandExecutionState | undefined =
|
|
1344
|
+
command.execution;
|
|
1345
|
+
|
|
1346
|
+
if (
|
|
1347
|
+
command.stepType !== RunbookStepType.Kubectl ||
|
|
1348
|
+
!execution ||
|
|
1349
|
+
execution.status !== AiRemediationCommandExecutionStatus.Failed ||
|
|
1350
|
+
!execution.runnerJobId ||
|
|
1351
|
+
!command.rollbackCommand ||
|
|
1352
|
+
command.rollbackExecution
|
|
1353
|
+
) {
|
|
1354
|
+
continue;
|
|
1355
|
+
}
|
|
1356
|
+
|
|
1357
|
+
let runState: KubectlRunState = KubectlRunState.Unknown;
|
|
1358
|
+
let job: RunnerJob | null = null;
|
|
1359
|
+
|
|
1360
|
+
try {
|
|
1361
|
+
job = ObjectID.isValidUUID(execution.runnerJobId)
|
|
1362
|
+
? await RunnerJobService.findOneById({
|
|
1363
|
+
id: new ObjectID(execution.runnerJobId),
|
|
1364
|
+
select: RUN_STATE_JOB_SELECT,
|
|
1365
|
+
props: { isRoot: true },
|
|
1366
|
+
})
|
|
1367
|
+
: null;
|
|
1368
|
+
|
|
1369
|
+
if (job) {
|
|
1370
|
+
runState = KubectlJobRunner.getRunStateOfJobRow(job);
|
|
1371
|
+
}
|
|
1372
|
+
} catch (error) {
|
|
1373
|
+
logger.error(
|
|
1374
|
+
`CommandPlanExecutor: could not read whether command ${command.sequence} of suggestion ${suggestion.id?.toString()} ran: ${error}`,
|
|
1375
|
+
);
|
|
1376
|
+
}
|
|
1377
|
+
|
|
1378
|
+
if (job && job.status === RunnerJobStatus.Succeeded) {
|
|
1379
|
+
this.settleFromJob(execution, job, "Command");
|
|
1380
|
+
changed = true;
|
|
1381
|
+
continue;
|
|
1382
|
+
}
|
|
1383
|
+
|
|
1384
|
+
const kubectlFinished: boolean =
|
|
1385
|
+
runState === KubectlRunState.Ran && typeof job?.exitCode === "number";
|
|
1386
|
+
|
|
1387
|
+
if (runState !== KubectlRunState.NotRun && !kubectlFinished) {
|
|
1388
|
+
mayHaveRun.push(command);
|
|
1389
|
+
}
|
|
1390
|
+
}
|
|
1391
|
+
|
|
1392
|
+
if (changed) {
|
|
1393
|
+
await this.persistPlan(suggestion, plan, "rollback");
|
|
1394
|
+
}
|
|
1395
|
+
|
|
1396
|
+
return mayHaveRun;
|
|
1397
|
+
}
|
|
1398
|
+
|
|
1399
|
+
private static describeRollbackOutcome(
|
|
1400
|
+
plan: AiRemediationCommandPlan | null,
|
|
1401
|
+
): CommandPlanRollbackOutcome {
|
|
1402
|
+
let rolledBack: number = 0;
|
|
1403
|
+
let failed: number = 0;
|
|
1404
|
+
let leftForHuman: number = 0;
|
|
1405
|
+
|
|
1406
|
+
for (const command of plan?.commands || []) {
|
|
1407
|
+
switch (command.rollbackExecution?.status) {
|
|
1408
|
+
case AiRemediationCommandExecutionStatus.Succeeded:
|
|
1409
|
+
rolledBack += 1;
|
|
1410
|
+
break;
|
|
1411
|
+
case AiRemediationCommandExecutionStatus.Failed:
|
|
1412
|
+
failed += 1;
|
|
1413
|
+
break;
|
|
1414
|
+
case AiRemediationCommandExecutionStatus.Skipped:
|
|
1415
|
+
leftForHuman += 1;
|
|
1416
|
+
break;
|
|
1417
|
+
default:
|
|
1418
|
+
break;
|
|
1419
|
+
}
|
|
1420
|
+
}
|
|
1421
|
+
|
|
1422
|
+
const storedStatus: AiRemediationRollbackStatus | undefined =
|
|
1423
|
+
plan?.rollbackStatus &&
|
|
1424
|
+
plan.rollbackStatus !== AiRemediationRollbackStatus.NotAttempted
|
|
1425
|
+
? plan.rollbackStatus
|
|
1426
|
+
: undefined;
|
|
1427
|
+
|
|
1428
|
+
/*
|
|
1429
|
+
* A status and its counts never contradict each other: an undo that
|
|
1430
|
+
* failed or was left for a human makes a settled rollback Failed, even
|
|
1431
|
+
* one recorded "completed" before resumed rollbacks carried earlier
|
|
1432
|
+
* failures forward.
|
|
1433
|
+
*/
|
|
1434
|
+
const rollbackStatus: AiRemediationRollbackStatus | undefined =
|
|
1435
|
+
storedStatus !== undefined && failed + leftForHuman > 0
|
|
1436
|
+
? AiRemediationRollbackStatus.Failed
|
|
1437
|
+
: storedStatus;
|
|
1438
|
+
|
|
1439
|
+
let summary: string;
|
|
1440
|
+
|
|
1441
|
+
switch (rollbackStatus) {
|
|
1442
|
+
case AiRemediationRollbackStatus.Completed:
|
|
1443
|
+
summary = `Rollback completed: ${rolledBack} command(s) undone.`;
|
|
1444
|
+
break;
|
|
1445
|
+
case AiRemediationRollbackStatus.NotApplicable:
|
|
1446
|
+
summary =
|
|
1447
|
+
"Nothing was rolled back: no executed command carried a rollback command.";
|
|
1448
|
+
break;
|
|
1449
|
+
case AiRemediationRollbackStatus.Failed:
|
|
1450
|
+
summary = `Rollback did NOT fully complete: ${rolledBack} command(s) undone, ${failed} rollback(s) failed, ${leftForHuman} left for a human to undo — the change may still be applied.`;
|
|
1451
|
+
break;
|
|
1452
|
+
default:
|
|
1453
|
+
summary =
|
|
1454
|
+
"The rollback did not finish; whatever it did not undo may still be applied.";
|
|
1455
|
+
break;
|
|
1456
|
+
}
|
|
1457
|
+
|
|
1458
|
+
return { rollbackStatus, rolledBack, failed, leftForHuman, summary };
|
|
1459
|
+
}
|
|
1460
|
+
|
|
487
1461
|
/*
|
|
488
1462
|
* Whether the suggestion is still an Approved remediation whose
|
|
489
1463
|
* verification window is open. False means someone (the verifier, or a
|
|
@@ -540,15 +1514,90 @@ export default class CommandPlanExecutor {
|
|
|
540
1514
|
}
|
|
541
1515
|
}
|
|
542
1516
|
|
|
1517
|
+
/*
|
|
1518
|
+
* The plan the rollback arm works from: the stored one, read under the
|
|
1519
|
+
* plan lock. Falls back to the copy the caller holds when the stored plan
|
|
1520
|
+
* cannot be read.
|
|
1521
|
+
*/
|
|
1522
|
+
private static async readPlanForRollback(
|
|
1523
|
+
suggestion: AutoRemediationSuggestion,
|
|
1524
|
+
): Promise<AiRemediationCommandPlan | null> {
|
|
1525
|
+
const mutex: SemaphoreMutex | null = suggestion.id
|
|
1526
|
+
? await this.lockPlan(suggestion.id)
|
|
1527
|
+
: null;
|
|
1528
|
+
|
|
1529
|
+
try {
|
|
1530
|
+
const stored: AiRemediationCommandPlan | null = suggestion.id
|
|
1531
|
+
? await this.readStoredPlan(suggestion.id)
|
|
1532
|
+
: null;
|
|
1533
|
+
|
|
1534
|
+
return (
|
|
1535
|
+
stored || AiRemediationCommandPlanUtil.parse(suggestion.commandPlan)
|
|
1536
|
+
);
|
|
1537
|
+
} finally {
|
|
1538
|
+
await this.unlockPlan(mutex);
|
|
1539
|
+
}
|
|
1540
|
+
}
|
|
1541
|
+
|
|
1542
|
+
// The plan as stored right now, or null when it cannot be read.
|
|
1543
|
+
private static async readStoredPlan(
|
|
1544
|
+
suggestionId: ObjectID,
|
|
1545
|
+
): Promise<AiRemediationCommandPlan | null> {
|
|
1546
|
+
try {
|
|
1547
|
+
/*
|
|
1548
|
+
* findOneBy, not findOneById: this is the column read for a merge,
|
|
1549
|
+
* not a status re-check, and it must not be mistaken for one.
|
|
1550
|
+
*/
|
|
1551
|
+
const stored: AutoRemediationSuggestion | null =
|
|
1552
|
+
await AutoRemediationSuggestionService.findOneBy({
|
|
1553
|
+
query: { _id: suggestionId.toString() },
|
|
1554
|
+
select: { _id: true, commandPlan: true },
|
|
1555
|
+
props: { isRoot: true },
|
|
1556
|
+
});
|
|
1557
|
+
|
|
1558
|
+
return AiRemediationCommandPlanUtil.parse(stored?.commandPlan);
|
|
1559
|
+
} catch (error) {
|
|
1560
|
+
logger.warn(
|
|
1561
|
+
`CommandPlanExecutor: could not read the stored plan of suggestion ${suggestionId.toString()} to merge into; writing this writer's copy as is: ${error}`,
|
|
1562
|
+
);
|
|
1563
|
+
return null;
|
|
1564
|
+
}
|
|
1565
|
+
}
|
|
1566
|
+
|
|
1567
|
+
/*
|
|
1568
|
+
* Persist the plan without erasing what the OTHER arm wrote. The stored
|
|
1569
|
+
* plan is re-read (under the plan lock) and only this writer's fields are
|
|
1570
|
+
* taken from its copy: the executor owns forward executions and the
|
|
1571
|
+
* plan's execution lifecycle; the rollback arm owns rollbacks,
|
|
1572
|
+
* rollbackStatus and the rollback heartbeat. A forward execution the
|
|
1573
|
+
* rollback arm settled from its job is kept over a stale unsettled copy
|
|
1574
|
+
* either way. When the stored plan cannot be read, this writer's copy is
|
|
1575
|
+
* written as is — the record must still land.
|
|
1576
|
+
*/
|
|
543
1577
|
private static async persistPlan(
|
|
544
1578
|
suggestion: AutoRemediationSuggestion,
|
|
545
1579
|
plan: AiRemediationCommandPlan,
|
|
1580
|
+
writer: PlanWriter,
|
|
1581
|
+
options?: { planLocked?: boolean | undefined },
|
|
546
1582
|
): Promise<void> {
|
|
1583
|
+
const mutex: SemaphoreMutex | null =
|
|
1584
|
+
options?.planLocked || !suggestion.id
|
|
1585
|
+
? null
|
|
1586
|
+
: await this.lockPlan(suggestion.id);
|
|
1587
|
+
|
|
547
1588
|
try {
|
|
1589
|
+
const stored: AiRemediationCommandPlan | null = suggestion.id
|
|
1590
|
+
? await this.readStoredPlan(suggestion.id)
|
|
1591
|
+
: null;
|
|
1592
|
+
|
|
1593
|
+
const toWrite: AiRemediationCommandPlan = stored
|
|
1594
|
+
? this.mergePlans({ mine: plan, stored, writer })
|
|
1595
|
+
: plan;
|
|
1596
|
+
|
|
548
1597
|
await AutoRemediationSuggestionService.updateOneById({
|
|
549
1598
|
id: suggestion.id!,
|
|
550
1599
|
data: {
|
|
551
|
-
commandPlan: AiRemediationCommandPlanUtil.toJSON(
|
|
1600
|
+
commandPlan: AiRemediationCommandPlanUtil.toJSON(toWrite),
|
|
552
1601
|
} as never,
|
|
553
1602
|
props: { isRoot: true },
|
|
554
1603
|
});
|
|
@@ -556,6 +1605,148 @@ export default class CommandPlanExecutor {
|
|
|
556
1605
|
logger.error(
|
|
557
1606
|
`CommandPlanExecutor: failed to persist plan progress for suggestion ${suggestion.id?.toString()}: ${error}`,
|
|
558
1607
|
);
|
|
1608
|
+
} finally {
|
|
1609
|
+
await this.unlockPlan(mutex);
|
|
1610
|
+
}
|
|
1611
|
+
}
|
|
1612
|
+
|
|
1613
|
+
private static mergePlans(data: {
|
|
1614
|
+
mine: AiRemediationCommandPlan;
|
|
1615
|
+
stored: AiRemediationCommandPlan;
|
|
1616
|
+
writer: PlanWriter;
|
|
1617
|
+
}): AiRemediationCommandPlan {
|
|
1618
|
+
const { mine, stored } = data;
|
|
1619
|
+
|
|
1620
|
+
if (data.writer === "executor") {
|
|
1621
|
+
const storedBySequence: Map<number, AiRemediationCommand> = new Map<
|
|
1622
|
+
number,
|
|
1623
|
+
AiRemediationCommand
|
|
1624
|
+
>(
|
|
1625
|
+
stored.commands.map((command: AiRemediationCommand) => {
|
|
1626
|
+
return [command.sequence, command];
|
|
1627
|
+
}),
|
|
1628
|
+
);
|
|
1629
|
+
|
|
1630
|
+
return {
|
|
1631
|
+
...mine,
|
|
1632
|
+
commands: mine.commands.map((command: AiRemediationCommand) => {
|
|
1633
|
+
const storedCommand: AiRemediationCommand | undefined =
|
|
1634
|
+
storedBySequence.get(command.sequence);
|
|
1635
|
+
|
|
1636
|
+
return {
|
|
1637
|
+
...command,
|
|
1638
|
+
execution: this.pickExecution(
|
|
1639
|
+
command.execution,
|
|
1640
|
+
storedCommand?.execution,
|
|
1641
|
+
),
|
|
1642
|
+
rollbackExecution: storedCommand?.rollbackExecution,
|
|
1643
|
+
};
|
|
1644
|
+
}),
|
|
1645
|
+
rollbackStatus: stored.rollbackStatus,
|
|
1646
|
+
rollbackHeartbeatAt: stored.rollbackHeartbeatAt,
|
|
1647
|
+
};
|
|
1648
|
+
}
|
|
1649
|
+
|
|
1650
|
+
const mineBySequence: Map<number, AiRemediationCommand> = new Map<
|
|
1651
|
+
number,
|
|
1652
|
+
AiRemediationCommand
|
|
1653
|
+
>(
|
|
1654
|
+
mine.commands.map((command: AiRemediationCommand) => {
|
|
1655
|
+
return [command.sequence, command];
|
|
1656
|
+
}),
|
|
1657
|
+
);
|
|
1658
|
+
|
|
1659
|
+
return {
|
|
1660
|
+
...stored,
|
|
1661
|
+
commands: stored.commands.map((storedCommand: AiRemediationCommand) => {
|
|
1662
|
+
const command: AiRemediationCommand | undefined = mineBySequence.get(
|
|
1663
|
+
storedCommand.sequence,
|
|
1664
|
+
);
|
|
1665
|
+
|
|
1666
|
+
if (!command) {
|
|
1667
|
+
return storedCommand;
|
|
1668
|
+
}
|
|
1669
|
+
|
|
1670
|
+
return {
|
|
1671
|
+
...storedCommand,
|
|
1672
|
+
execution: this.pickExecution(
|
|
1673
|
+
command.execution,
|
|
1674
|
+
storedCommand.execution,
|
|
1675
|
+
),
|
|
1676
|
+
rollbackExecution: command.rollbackExecution,
|
|
1677
|
+
};
|
|
1678
|
+
}),
|
|
1679
|
+
rollbackStatus: mine.rollbackStatus ?? stored.rollbackStatus,
|
|
1680
|
+
rollbackHeartbeatAt:
|
|
1681
|
+
mine.rollbackHeartbeatAt ?? stored.rollbackHeartbeatAt,
|
|
1682
|
+
};
|
|
1683
|
+
}
|
|
1684
|
+
|
|
1685
|
+
/*
|
|
1686
|
+
* The more settled of two records of one command's forward execution: a
|
|
1687
|
+
* record with an outcome beats one still waiting for it; with both
|
|
1688
|
+
* settled (or both not) the writer's own wins, keeping any job id either
|
|
1689
|
+
* of them knows.
|
|
1690
|
+
*/
|
|
1691
|
+
private static pickExecution(
|
|
1692
|
+
mine: AiRemediationCommandExecutionState | undefined,
|
|
1693
|
+
stored: AiRemediationCommandExecutionState | undefined,
|
|
1694
|
+
): AiRemediationCommandExecutionState | undefined {
|
|
1695
|
+
if (!mine) {
|
|
1696
|
+
return stored;
|
|
1697
|
+
}
|
|
1698
|
+
|
|
1699
|
+
if (!stored) {
|
|
1700
|
+
return mine;
|
|
1701
|
+
}
|
|
1702
|
+
|
|
1703
|
+
if (isSettledCommandExecutionStatus(mine.status)) {
|
|
1704
|
+
return mine;
|
|
1705
|
+
}
|
|
1706
|
+
|
|
1707
|
+
if (isSettledCommandExecutionStatus(stored.status)) {
|
|
1708
|
+
return stored;
|
|
1709
|
+
}
|
|
1710
|
+
|
|
1711
|
+
return mine.runnerJobId || !stored.runnerJobId
|
|
1712
|
+
? mine
|
|
1713
|
+
: { ...mine, runnerJobId: stored.runnerJobId };
|
|
1714
|
+
}
|
|
1715
|
+
|
|
1716
|
+
/*
|
|
1717
|
+
* The per-plan lock, or null when it cannot be had (Redis unavailable):
|
|
1718
|
+
* the plan's writes then proceed unserialized rather than not at all — a
|
|
1719
|
+
* remediation must never be stranded half-recorded for want of a lock.
|
|
1720
|
+
*/
|
|
1721
|
+
private static async lockPlan(
|
|
1722
|
+
suggestionId: ObjectID,
|
|
1723
|
+
): Promise<SemaphoreMutex | null> {
|
|
1724
|
+
try {
|
|
1725
|
+
return await Semaphore.lock({
|
|
1726
|
+
key: suggestionId.toString(),
|
|
1727
|
+
namespace: PLAN_LOCK_NAMESPACE,
|
|
1728
|
+
lockTimeout: PLAN_LOCK_TIMEOUT_MS,
|
|
1729
|
+
acquireTimeout: PLAN_LOCK_ACQUIRE_TIMEOUT_MS,
|
|
1730
|
+
});
|
|
1731
|
+
} catch (error) {
|
|
1732
|
+
logger.warn(
|
|
1733
|
+
`CommandPlanExecutor: could not take the plan lock of suggestion ${suggestionId.toString()}; continuing unserialized: ${error}`,
|
|
1734
|
+
);
|
|
1735
|
+
return null;
|
|
1736
|
+
}
|
|
1737
|
+
}
|
|
1738
|
+
|
|
1739
|
+
private static async unlockPlan(mutex: SemaphoreMutex | null): Promise<void> {
|
|
1740
|
+
if (!mutex) {
|
|
1741
|
+
return;
|
|
1742
|
+
}
|
|
1743
|
+
|
|
1744
|
+
try {
|
|
1745
|
+
await Semaphore.release(mutex);
|
|
1746
|
+
} catch (error) {
|
|
1747
|
+
logger.error(
|
|
1748
|
+
`CommandPlanExecutor: failed to release the plan lock: ${error}`,
|
|
1749
|
+
);
|
|
559
1750
|
}
|
|
560
1751
|
}
|
|
561
1752
|
|