@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
|
@@ -1,13 +1,50 @@
|
|
|
1
1
|
import DatabaseService from "./DatabaseService";
|
|
2
|
+
import AutoRemediationSuggestionService from "./AutoRemediationSuggestionService";
|
|
2
3
|
import KubernetesClusterLabelRuleEngineService from "./KubernetesClusterLabelRuleEngineService";
|
|
3
4
|
import KubernetesClusterOwnerRuleEngineService from "./KubernetesClusterOwnerRuleEngineService";
|
|
5
|
+
import RunbookCredentialService from "./RunbookCredentialService";
|
|
6
|
+
import RunnerService, { Service as RunnerServiceClass } from "./RunnerService";
|
|
7
|
+
import UserService from "./UserService";
|
|
8
|
+
import AutoRemediationSuggestion from "../../Models/DatabaseModels/AutoRemediationSuggestion";
|
|
4
9
|
import Model from "../../Models/DatabaseModels/KubernetesCluster";
|
|
5
10
|
import Label from "../../Models/DatabaseModels/Label";
|
|
6
|
-
import
|
|
11
|
+
import RunbookCredential from "../../Models/DatabaseModels/RunbookCredential";
|
|
12
|
+
import Runner from "../../Models/DatabaseModels/Runner";
|
|
13
|
+
import CreateBy from "../Types/Database/CreateBy";
|
|
14
|
+
import DeleteBy from "../Types/Database/DeleteBy";
|
|
15
|
+
import Select from "../Types/Database/Select";
|
|
16
|
+
import UpdateBy from "../Types/Database/UpdateBy";
|
|
17
|
+
import { OnCreate, OnDelete, OnUpdate } from "../Types/Database/Hooks";
|
|
18
|
+
import AutoRemediationSuggestionStatus from "../../Types/AutoRemediation/AutoRemediationSuggestionStatus";
|
|
19
|
+
import {
|
|
20
|
+
AiRemediationCommand,
|
|
21
|
+
AiRemediationCommandExecutionStatus,
|
|
22
|
+
AiRemediationCommandPlan,
|
|
23
|
+
AiRemediationCommandPlanUtil,
|
|
24
|
+
} from "../../Types/AutoRemediation/AiRemediationCommandPlan";
|
|
25
|
+
import KubectlPolicy, {
|
|
26
|
+
KUBECTL_ALLOWLIST_MAX_PATTERNS,
|
|
27
|
+
} from "../../Utils/AiRemediation/KubectlPolicy";
|
|
28
|
+
import RelationIdUtil from "../Utils/Database/RelationIdUtil";
|
|
29
|
+
import { holdsAnyPermission } from "../Utils/Runbook/RunbookExecutePermission";
|
|
30
|
+
import DatabaseCommonInteractionProps from "../../Types/BaseDatabase/DatabaseCommonInteractionProps";
|
|
31
|
+
import BadDataException from "../../Types/Exception/BadDataException";
|
|
32
|
+
import NotAuthorizedException from "../../Types/Exception/NotAuthorizedException";
|
|
33
|
+
import {
|
|
34
|
+
KubernetesAiRemediationMode,
|
|
35
|
+
isUnattendedRemediationMode,
|
|
36
|
+
} from "../../Types/Kubernetes/KubernetesClusterAiAccess";
|
|
37
|
+
import {
|
|
38
|
+
KUBERNETES_AI_ACCESS_ADMIN_PERMISSIONS,
|
|
39
|
+
KUBERNETES_AI_ACCESS_CREDENTIAL_PERMISSIONS,
|
|
40
|
+
} from "../../Types/Kubernetes/KubernetesClusterAiAccessPermissions";
|
|
41
|
+
import { PermissionHelper } from "../../Types/Permission";
|
|
42
|
+
import RunbookCredentialType from "../../Types/Runbook/RunbookCredentialType";
|
|
7
43
|
import KubernetesClusterFeedService from "./KubernetesClusterFeedService";
|
|
8
44
|
import { KubernetesClusterFeedEventType } from "../../Models/DatabaseModels/KubernetesClusterFeed";
|
|
9
45
|
import ResourceFeedUtil from "../Utils/ResourceFeed/ResourceFeedUtil";
|
|
10
46
|
import { Blue500, Gray500, Green500, Yellow500 } from "../../Types/BrandColors";
|
|
47
|
+
import Color from "../../Types/Color";
|
|
11
48
|
import { JSONObject } from "../../Types/JSON";
|
|
12
49
|
import URL from "../../Types/API/URL";
|
|
13
50
|
import DatabaseConfig from "../DatabaseConfig";
|
|
@@ -27,16 +64,1067 @@ const LAST_SEEN_THROTTLE_SECONDS: number = 60;
|
|
|
27
64
|
const LABELS_APPLIED_CACHE_NAMESPACE: string = "k8s-cluster-labels-applied";
|
|
28
65
|
const LABELS_APPLIED_CACHE_TTL_SECONDS: number = 60;
|
|
29
66
|
|
|
67
|
+
/*
|
|
68
|
+
* The two spellings each AI-access relation can arrive under: the FK column
|
|
69
|
+
* server-side callers write, and the relation object the dashboard's forms
|
|
70
|
+
* post. See RelationIdUtil for why a hook must read both.
|
|
71
|
+
*/
|
|
72
|
+
const AI_ACCESS_RUNNER_KEYS: Array<string> = [
|
|
73
|
+
"aiAccessRunnerId",
|
|
74
|
+
"aiAccessRunner",
|
|
75
|
+
];
|
|
76
|
+
const AI_ACCESS_CREDENTIAL_KEYS: Array<string> = [
|
|
77
|
+
"aiAccessCredentialId",
|
|
78
|
+
"aiAccessCredential",
|
|
79
|
+
];
|
|
80
|
+
|
|
81
|
+
/*
|
|
82
|
+
* Every AI access setting an operator can write — on the cluster's AI page,
|
|
83
|
+
* through the API or through Terraform. A non-root write of any of them is
|
|
84
|
+
* checked against who may loosen AI access, marks the cluster as
|
|
85
|
+
* AI-configured (aiAccessConfiguredAt) and is recorded on the cluster feed.
|
|
86
|
+
*/
|
|
87
|
+
export const AI_ACCESS_SETTING_KEYS: Array<string> = [
|
|
88
|
+
...AI_ACCESS_RUNNER_KEYS,
|
|
89
|
+
...AI_ACCESS_CREDENTIAL_KEYS,
|
|
90
|
+
"isAiInvestigationEnabled",
|
|
91
|
+
"aiRemediationMode",
|
|
92
|
+
"aiKubectlCommandAllowlist",
|
|
93
|
+
];
|
|
94
|
+
|
|
95
|
+
/*
|
|
96
|
+
* What the binding checks read off a Runner and a credential: whether the
|
|
97
|
+
* Runner is a kubernetes-agent row (and whose), and which Runners the
|
|
98
|
+
* credential is assigned to.
|
|
99
|
+
*/
|
|
100
|
+
const AI_ACCESS_BINDING_RUNNER_SELECT: Select<Runner> = {
|
|
101
|
+
_id: true,
|
|
102
|
+
name: true,
|
|
103
|
+
hostInfo: true,
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
const AI_ACCESS_BINDING_CREDENTIAL_SELECT: Select<RunbookCredential> = {
|
|
107
|
+
_id: true,
|
|
108
|
+
credentialType: true,
|
|
109
|
+
runners: { _id: true },
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
// Runner and credential rows the binding checks already loaded, by id.
|
|
113
|
+
interface AiAccessBindingRows {
|
|
114
|
+
runners: Map<string, Runner>;
|
|
115
|
+
credentials: Map<string, RunbookCredential>;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const KUBECTL_ALLOWLIST_SHAPE_HINT: string =
|
|
119
|
+
'The kubectl allowlist must be a JSON array of kubectl command patterns, for example ["kubectl set image deployment/web * -n web"].';
|
|
120
|
+
|
|
121
|
+
/*
|
|
122
|
+
* How much each remediation mode lets OneUptime AI do without a human,
|
|
123
|
+
* least first. Automatic runs a strict subset of what Bypass approval runs
|
|
124
|
+
* (safe changes and allowlisted shapes, never an unlisted riskier change),
|
|
125
|
+
* so moving from Bypass approval to Automatic is a tightening.
|
|
126
|
+
*/
|
|
127
|
+
const REMEDIATION_MODES_BY_AUTONOMY: Array<KubernetesAiRemediationMode> = [
|
|
128
|
+
KubernetesAiRemediationMode.Disabled,
|
|
129
|
+
KubernetesAiRemediationMode.RequireApproval,
|
|
130
|
+
KubernetesAiRemediationMode.Automatic,
|
|
131
|
+
KubernetesAiRemediationMode.BypassApproval,
|
|
132
|
+
];
|
|
133
|
+
|
|
134
|
+
// The AI page's short name for each mode, used on the cluster feed.
|
|
135
|
+
const REMEDIATION_MODE_FEED_LABELS: Record<
|
|
136
|
+
KubernetesAiRemediationMode,
|
|
137
|
+
string
|
|
138
|
+
> = {
|
|
139
|
+
[KubernetesAiRemediationMode.Disabled]: "Off",
|
|
140
|
+
[KubernetesAiRemediationMode.RequireApproval]: "Ask for approval",
|
|
141
|
+
[KubernetesAiRemediationMode.Automatic]: "Automatic",
|
|
142
|
+
[KubernetesAiRemediationMode.BypassApproval]: "Bypass approval",
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
/*
|
|
146
|
+
* One answer for "no such credential in this project" and "not a Kubernetes
|
|
147
|
+
* credential": a caller who may not read credentials must not be able to
|
|
148
|
+
* tell the two apart and so learn which ids exist and what type they are.
|
|
149
|
+
*/
|
|
150
|
+
export const AI_ACCESS_CREDENTIAL_REFUSAL: string =
|
|
151
|
+
"Credential not found, or it is not a Kubernetes credential in this project. The AI access credential must be a Kubernetes credential (API server URL and ServiceAccount token) that belongs to this project.";
|
|
152
|
+
|
|
153
|
+
export function getAiAccessAdminRefusal(): string {
|
|
154
|
+
return `You need one of these permissions to let OneUptime AI do more on a Kubernetes cluster (switch AI remediation to Automatic or Bypass approval, add kubectl allowlist patterns, or bind a Runner or credential): ${PermissionHelper.getPermissionTitles(
|
|
155
|
+
KUBERNETES_AI_ACCESS_ADMIN_PERMISSIONS,
|
|
156
|
+
).join(
|
|
157
|
+
", ",
|
|
158
|
+
)}. Anyone who may edit the cluster can still turn AI remediation off or back to Ask for approval, remove allowlist patterns, and clear the Runner or credential.`;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
export function getAiAccessCredentialRefusal(): string {
|
|
162
|
+
return `Binding a Kubernetes credential to a cluster also needs permission to read credentials. You need one of these permissions: ${PermissionHelper.getPermissionTitles(
|
|
163
|
+
KUBERNETES_AI_ACCESS_CREDENTIAL_PERMISSIONS,
|
|
164
|
+
).join(", ")}.`;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/*
|
|
168
|
+
* A cluster's AI access settings as they stood before an operator's write:
|
|
169
|
+
* the baseline "does this write loosen anything?" is decided against, and
|
|
170
|
+
* the "before" half of the feed item that records the change. Normalized
|
|
171
|
+
* the way the readers normalize them (an unknown mode is Disabled, an
|
|
172
|
+
* unusable allowlist is empty), because that is what was in effect.
|
|
173
|
+
*/
|
|
174
|
+
export interface AiAccessSettingsSnapshot {
|
|
175
|
+
projectId?: ObjectID | undefined;
|
|
176
|
+
/*
|
|
177
|
+
* Which cluster this is, for "is the chosen Runner THIS cluster's agent
|
|
178
|
+
* Runner?" (validateAiAccessBindingPairs). Not an AI setting itself.
|
|
179
|
+
*/
|
|
180
|
+
clusterIdentifier?: string | undefined;
|
|
181
|
+
isAiInvestigationEnabled: boolean;
|
|
182
|
+
aiRemediationMode: KubernetesAiRemediationMode;
|
|
183
|
+
aiKubectlCommandAllowlist: Array<string>;
|
|
184
|
+
aiAccessRunnerId: string | null;
|
|
185
|
+
aiAccessCredentialId: string | null;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// What a cluster that was never AI-configured has: the column defaults.
|
|
189
|
+
const NEVER_CONFIGURED_AI_ACCESS: AiAccessSettingsSnapshot = {
|
|
190
|
+
isAiInvestigationEnabled: false,
|
|
191
|
+
aiRemediationMode: KubernetesAiRemediationMode.Disabled,
|
|
192
|
+
aiKubectlCommandAllowlist: [],
|
|
193
|
+
aiAccessRunnerId: null,
|
|
194
|
+
aiAccessCredentialId: null,
|
|
195
|
+
};
|
|
196
|
+
|
|
197
|
+
/*
|
|
198
|
+
* Handed from onBeforeUpdate to onUpdateSuccess for an operator's write of
|
|
199
|
+
* an AI access setting, keyed by cluster id. Its presence is the signal that
|
|
200
|
+
* the write must mark the cluster configured and be recorded on the feed —
|
|
201
|
+
* both happen only after the update succeeded.
|
|
202
|
+
*/
|
|
203
|
+
export interface AiAccessWriteCarryForward {
|
|
204
|
+
previousAiAccessSettings: Record<string, AiAccessSettingsSnapshot>;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/*
|
|
208
|
+
* Handed from onBeforeDelete to onDeleteSuccess: the cluster-level AI
|
|
209
|
+
* remediation rounds still in flight on the clusters being deleted, read
|
|
210
|
+
* before the foreign key nulls their link, and the clusters' names.
|
|
211
|
+
*/
|
|
212
|
+
interface ClusterDeleteCarryForward {
|
|
213
|
+
inFlightRounds: Array<AutoRemediationSuggestion>;
|
|
214
|
+
clusterNames: Record<string, string>;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
function getClusterDeleteCarryForward(
|
|
218
|
+
carryForward: unknown,
|
|
219
|
+
): ClusterDeleteCarryForward | null {
|
|
220
|
+
if (
|
|
221
|
+
carryForward &&
|
|
222
|
+
typeof carryForward === "object" &&
|
|
223
|
+
"inFlightRounds" in carryForward
|
|
224
|
+
) {
|
|
225
|
+
return carryForward as ClusterDeleteCarryForward;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
return null;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
// What loosening an operator's write would do to one cluster.
|
|
232
|
+
interface AiAccessLoosening {
|
|
233
|
+
loosens: boolean;
|
|
234
|
+
bindsCredential: boolean;
|
|
235
|
+
}
|
|
236
|
+
|
|
30
237
|
export class Service extends DatabaseService<Model> {
|
|
31
238
|
public constructor() {
|
|
32
239
|
super(Model);
|
|
33
240
|
}
|
|
34
241
|
|
|
242
|
+
@CaptureSpan()
|
|
243
|
+
protected override async onBeforeCreate(
|
|
244
|
+
createBy: CreateBy<Model>,
|
|
245
|
+
): Promise<OnCreate<Model>> {
|
|
246
|
+
const projectId: ObjectID | undefined =
|
|
247
|
+
createBy.data.projectId ||
|
|
248
|
+
createBy.data.project?.id ||
|
|
249
|
+
createBy.props.tenantId ||
|
|
250
|
+
undefined;
|
|
251
|
+
|
|
252
|
+
const data: JSONObject = createBy.data as unknown as JSONObject;
|
|
253
|
+
|
|
254
|
+
this.validateAiRemediationSettings(data);
|
|
255
|
+
|
|
256
|
+
/*
|
|
257
|
+
* The AI columns' create ACLs are empty, so a user's create cannot carry
|
|
258
|
+
* them today and this is defence in depth: were one ever opened, a new
|
|
259
|
+
* cluster starts from the never-configured defaults, and anything above
|
|
260
|
+
* them is a loosening like any other.
|
|
261
|
+
*/
|
|
262
|
+
if (!createBy.props.isRoot && !createBy.props.isMasterAdmin) {
|
|
263
|
+
this.assertMayChangeAiAccess({
|
|
264
|
+
data,
|
|
265
|
+
props: createBy.props,
|
|
266
|
+
current: [{ ...NEVER_CONFIGURED_AI_ACCESS, projectId }],
|
|
267
|
+
});
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
const loaded: AiAccessBindingRows =
|
|
271
|
+
await this.validateAiAccessBindingsBelongToProject({
|
|
272
|
+
data,
|
|
273
|
+
projectId,
|
|
274
|
+
});
|
|
275
|
+
|
|
276
|
+
// An operator's binding must also be a pair that can work.
|
|
277
|
+
if (!createBy.props.isRoot) {
|
|
278
|
+
await this.validateAiAccessBindingPairs({
|
|
279
|
+
data,
|
|
280
|
+
clusters: [
|
|
281
|
+
{
|
|
282
|
+
...NEVER_CONFIGURED_AI_ACCESS,
|
|
283
|
+
projectId,
|
|
284
|
+
clusterIdentifier:
|
|
285
|
+
typeof data["clusterIdentifier"] === "string"
|
|
286
|
+
? (data["clusterIdentifier"] as string)
|
|
287
|
+
: undefined,
|
|
288
|
+
},
|
|
289
|
+
],
|
|
290
|
+
loaded,
|
|
291
|
+
});
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
return {
|
|
295
|
+
createBy,
|
|
296
|
+
carryForward: {
|
|
297
|
+
writesAiAccessSettings:
|
|
298
|
+
!createBy.props.isRoot && this.isAiAccessSettingWritten(data),
|
|
299
|
+
},
|
|
300
|
+
};
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
@CaptureSpan()
|
|
304
|
+
protected override async onBeforeUpdate(
|
|
305
|
+
updateBy: UpdateBy<Model>,
|
|
306
|
+
): Promise<OnUpdate<Model>> {
|
|
307
|
+
const data: JSONObject = (updateBy.data || {}) as unknown as JSONObject;
|
|
308
|
+
|
|
309
|
+
this.validateAiRemediationSettings(data);
|
|
310
|
+
|
|
311
|
+
/*
|
|
312
|
+
* An operator's write of an AI access setting is gated, marked and
|
|
313
|
+
* recorded. Root writes are the server's own — the in-cluster Runner's
|
|
314
|
+
* registration (which writes its own feed item and marker) and the
|
|
315
|
+
* outcome bookkeeping after each kubectl command — and are none of the
|
|
316
|
+
* three.
|
|
317
|
+
*/
|
|
318
|
+
let carryForward: AiAccessWriteCarryForward | null = null;
|
|
319
|
+
|
|
320
|
+
if (!updateBy.props.isRoot && this.isAiAccessSettingWritten(data)) {
|
|
321
|
+
const previousAiAccessSettings: Record<string, AiAccessSettingsSnapshot> =
|
|
322
|
+
await this.getAiAccessSettingsForUpdateQuery(updateBy);
|
|
323
|
+
|
|
324
|
+
if (!updateBy.props.isMasterAdmin) {
|
|
325
|
+
this.assertMayChangeAiAccess({
|
|
326
|
+
data,
|
|
327
|
+
props: updateBy.props,
|
|
328
|
+
current: Object.values(previousAiAccessSettings),
|
|
329
|
+
});
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
carryForward = { previousAiAccessSettings };
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
if (
|
|
336
|
+
RelationIdUtil.isWritten(Object.keys(data), [
|
|
337
|
+
...AI_ACCESS_RUNNER_KEYS,
|
|
338
|
+
...AI_ACCESS_CREDENTIAL_KEYS,
|
|
339
|
+
])
|
|
340
|
+
) {
|
|
341
|
+
/*
|
|
342
|
+
* Root/API updates do not always carry a tenantId, so fall back to
|
|
343
|
+
* the project of each cluster the query actually matches — a Runner
|
|
344
|
+
* must belong to every one of them.
|
|
345
|
+
*/
|
|
346
|
+
const projectIds: Array<ObjectID> = updateBy.props.tenantId
|
|
347
|
+
? [updateBy.props.tenantId]
|
|
348
|
+
: await this.getProjectIdsForUpdateQuery(updateBy);
|
|
349
|
+
|
|
350
|
+
const loaded: AiAccessBindingRows = {
|
|
351
|
+
runners: new Map<string, Runner>(),
|
|
352
|
+
credentials: new Map<string, RunbookCredential>(),
|
|
353
|
+
};
|
|
354
|
+
|
|
355
|
+
for (const projectId of projectIds) {
|
|
356
|
+
await this.validateAiAccessBindingsBelongToProject({
|
|
357
|
+
data,
|
|
358
|
+
projectId,
|
|
359
|
+
loaded,
|
|
360
|
+
});
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
/*
|
|
364
|
+
* Nothing matched: there is no project to check against, and the
|
|
365
|
+
* update will write nothing — unless the query was empty, which
|
|
366
|
+
* would never happen through updateOneById. Fail closed on a
|
|
367
|
+
* binding that cannot be checked.
|
|
368
|
+
*/
|
|
369
|
+
if (projectIds.length === 0) {
|
|
370
|
+
await this.validateAiAccessBindingsBelongToProject({
|
|
371
|
+
data,
|
|
372
|
+
projectId: undefined,
|
|
373
|
+
});
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
/*
|
|
377
|
+
* An operator's binding must also be a pair that can work, judged
|
|
378
|
+
* per cluster against what it is bound to now (read above). The
|
|
379
|
+
* server's own writes — registration binds this cluster's agent Runner
|
|
380
|
+
* and clears the credential — are not operator choices.
|
|
381
|
+
*/
|
|
382
|
+
if (carryForward) {
|
|
383
|
+
await this.validateAiAccessBindingPairs({
|
|
384
|
+
data,
|
|
385
|
+
clusters: Object.values(carryForward.previousAiAccessSettings),
|
|
386
|
+
loaded,
|
|
387
|
+
});
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
return { updateBy, carryForward };
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
/*
|
|
395
|
+
* A cluster-level AI remediation round (a suggestion the cluster's mode
|
|
396
|
+
* produced, not a rule) still Planning or waiting in Suggested for the
|
|
397
|
+
* cluster being deleted can never finish: its kubectl names a cluster
|
|
398
|
+
* that is about to be gone, and the foreign key nulls its link. Read here,
|
|
399
|
+
* before the delete, which ones there are; settled in onDeleteSuccess for
|
|
400
|
+
* the clusters that were actually deleted (the delete may still be
|
|
401
|
+
* refused after this hook runs).
|
|
402
|
+
*/
|
|
403
|
+
@CaptureSpan()
|
|
404
|
+
protected override async onBeforeDelete(
|
|
405
|
+
deleteBy: DeleteBy<Model>,
|
|
406
|
+
): Promise<OnDelete<Model>> {
|
|
407
|
+
let inFlightRounds: Array<AutoRemediationSuggestion> = [];
|
|
408
|
+
const clusterNames: Record<string, string> = {};
|
|
409
|
+
|
|
410
|
+
try {
|
|
411
|
+
const clusters: Array<Model> = await this.findBy({
|
|
412
|
+
query: {
|
|
413
|
+
...deleteBy.query,
|
|
414
|
+
...(deleteBy.props.tenantId
|
|
415
|
+
? { projectId: deleteBy.props.tenantId }
|
|
416
|
+
: {}),
|
|
417
|
+
},
|
|
418
|
+
select: { _id: true, name: true, clusterIdentifier: true },
|
|
419
|
+
limit: LIMIT_MAX,
|
|
420
|
+
skip: 0,
|
|
421
|
+
props: { isRoot: true },
|
|
422
|
+
});
|
|
423
|
+
|
|
424
|
+
const clusterIds: Array<ObjectID> = [];
|
|
425
|
+
|
|
426
|
+
for (const cluster of clusters) {
|
|
427
|
+
if (cluster.id) {
|
|
428
|
+
clusterIds.push(cluster.id);
|
|
429
|
+
clusterNames[cluster.id.toString()] =
|
|
430
|
+
cluster.name || cluster.clusterIdentifier || "this cluster";
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
if (clusterIds.length > 0) {
|
|
435
|
+
inFlightRounds = await AutoRemediationSuggestionService.findBy({
|
|
436
|
+
query: {
|
|
437
|
+
kubernetesClusterId: QueryHelper.any(clusterIds),
|
|
438
|
+
status: QueryHelper.any([
|
|
439
|
+
AutoRemediationSuggestionStatus.Planning,
|
|
440
|
+
AutoRemediationSuggestionStatus.Suggested,
|
|
441
|
+
]),
|
|
442
|
+
},
|
|
443
|
+
select: {
|
|
444
|
+
_id: true,
|
|
445
|
+
status: true,
|
|
446
|
+
kubernetesClusterId: true,
|
|
447
|
+
rationaleMarkdown: true,
|
|
448
|
+
commandPlan: true,
|
|
449
|
+
},
|
|
450
|
+
limit: LIMIT_MAX,
|
|
451
|
+
skip: 0,
|
|
452
|
+
props: { isRoot: true },
|
|
453
|
+
});
|
|
454
|
+
}
|
|
455
|
+
} catch (error) {
|
|
456
|
+
/*
|
|
457
|
+
* Best effort: a failed read must not block deleting the cluster;
|
|
458
|
+
* the rounds then fail on their next command as the cluster is gone.
|
|
459
|
+
*/
|
|
460
|
+
logger.error(
|
|
461
|
+
`KubernetesClusterService: could not read the in-flight AI remediation rounds of the cluster(s) being deleted: ${error}`,
|
|
462
|
+
);
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
const carryForward: ClusterDeleteCarryForward = {
|
|
466
|
+
inFlightRounds,
|
|
467
|
+
clusterNames,
|
|
468
|
+
};
|
|
469
|
+
|
|
470
|
+
return { deleteBy, carryForward };
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
@CaptureSpan()
|
|
474
|
+
protected override async onDeleteSuccess(
|
|
475
|
+
onDelete: OnDelete<Model>,
|
|
476
|
+
deletedItemIds: Array<ObjectID>,
|
|
477
|
+
): Promise<OnDelete<Model>> {
|
|
478
|
+
const carryForward: ClusterDeleteCarryForward | null =
|
|
479
|
+
getClusterDeleteCarryForward(onDelete.carryForward);
|
|
480
|
+
|
|
481
|
+
if (carryForward && carryForward.inFlightRounds.length > 0) {
|
|
482
|
+
const deleted: Set<string> = new Set<string>(
|
|
483
|
+
deletedItemIds.map((id: ObjectID) => {
|
|
484
|
+
return id.toString();
|
|
485
|
+
}),
|
|
486
|
+
);
|
|
487
|
+
|
|
488
|
+
for (const suggestion of carryForward.inFlightRounds) {
|
|
489
|
+
const clusterId: string =
|
|
490
|
+
suggestion.kubernetesClusterId?.toString() || "";
|
|
491
|
+
|
|
492
|
+
if (!deleted.has(clusterId)) {
|
|
493
|
+
continue;
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
await this.settleRoundOfDeletedCluster({
|
|
497
|
+
suggestion,
|
|
498
|
+
clusterName: carryForward.clusterNames[clusterId] || "this cluster",
|
|
499
|
+
deletedByUserId: onDelete.deleteBy.props.userId,
|
|
500
|
+
});
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
return onDelete;
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
/*
|
|
508
|
+
* Settle one in-flight cluster-level round of a deleted cluster the way a
|
|
509
|
+
* human dismissal settles it (the conditional status transition, so a
|
|
510
|
+
* planner finishing at the same moment loses cleanly and writes nothing),
|
|
511
|
+
* with a note on the suggestion saying why — and, for a round that had
|
|
512
|
+
* already run commands, that those changes were made and nothing was
|
|
513
|
+
* rolled back. Best effort: a settle that fails must not fail the delete
|
|
514
|
+
* that already happened.
|
|
515
|
+
*/
|
|
516
|
+
private async settleRoundOfDeletedCluster(data: {
|
|
517
|
+
suggestion: AutoRemediationSuggestion;
|
|
518
|
+
clusterName: string;
|
|
519
|
+
deletedByUserId?: ObjectID | undefined;
|
|
520
|
+
}): Promise<void> {
|
|
521
|
+
const { suggestion } = data;
|
|
522
|
+
|
|
523
|
+
try {
|
|
524
|
+
const plan: AiRemediationCommandPlan | null =
|
|
525
|
+
AiRemediationCommandPlanUtil.parse(suggestion.commandPlan);
|
|
526
|
+
// A Skipped command never ran; any other execution record may have.
|
|
527
|
+
const executedCount: number = (plan?.commands || []).filter(
|
|
528
|
+
(command: AiRemediationCommand) => {
|
|
529
|
+
return (
|
|
530
|
+
command.execution !== undefined &&
|
|
531
|
+
command.execution.status !==
|
|
532
|
+
AiRemediationCommandExecutionStatus.Skipped
|
|
533
|
+
);
|
|
534
|
+
},
|
|
535
|
+
).length;
|
|
536
|
+
|
|
537
|
+
const note: string =
|
|
538
|
+
executedCount > 0
|
|
539
|
+
? `**Dismissed: the Kubernetes cluster "${data.clusterName}" this remediation was for was deleted.** ${executedCount} command(s) had already run on it before; nothing was rolled back and no further command will run.`
|
|
540
|
+
: `**Dismissed: the Kubernetes cluster "${data.clusterName}" this remediation was for was deleted.** None of its kubectl commands ran, and none will.`;
|
|
541
|
+
|
|
542
|
+
await AutoRemediationSuggestionService.attemptStatusTransition({
|
|
543
|
+
suggestionId: suggestion.id!,
|
|
544
|
+
fromStatus: suggestion.status!,
|
|
545
|
+
set: {
|
|
546
|
+
status: AutoRemediationSuggestionStatus.Dismissed,
|
|
547
|
+
dismissedAt: OneUptimeDate.getCurrentDate(),
|
|
548
|
+
...(data.deletedByUserId
|
|
549
|
+
? { dismissedByUserId: data.deletedByUserId.toString() }
|
|
550
|
+
: {}),
|
|
551
|
+
rationaleMarkdown: suggestion.rationaleMarkdown
|
|
552
|
+
? `${note}\n\n${suggestion.rationaleMarkdown}`
|
|
553
|
+
: note,
|
|
554
|
+
},
|
|
555
|
+
});
|
|
556
|
+
} catch (error) {
|
|
557
|
+
logger.error(
|
|
558
|
+
`KubernetesClusterService: could not settle AI remediation suggestion ${suggestion.id?.toString()} of a deleted cluster: ${error}`,
|
|
559
|
+
);
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
private isAiAccessSettingWritten(data: JSONObject): boolean {
|
|
564
|
+
return isAnyKeyWritten(data, AI_ACCESS_SETTING_KEYS);
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
/*
|
|
568
|
+
* aiRemediationMode is a plain text column and aiKubectlCommandAllowlist
|
|
569
|
+
* untyped JSON, and both of their readers fail safe: an unknown mode reads
|
|
570
|
+
* as Disabled and an unusable pattern as no pattern. Accepting such a value
|
|
571
|
+
* would answer an API or Terraform write with success for a setting that
|
|
572
|
+
* never takes effect (and shows no drift), so refuse it here — and store
|
|
573
|
+
* the allowlist in the one shape its readers expect.
|
|
574
|
+
*/
|
|
575
|
+
private validateAiRemediationSettings(data: JSONObject): void {
|
|
576
|
+
const mode: unknown = data["aiRemediationMode"];
|
|
577
|
+
|
|
578
|
+
if (
|
|
579
|
+
mode !== undefined &&
|
|
580
|
+
!Object.values(KubernetesAiRemediationMode).includes(
|
|
581
|
+
mode as KubernetesAiRemediationMode,
|
|
582
|
+
)
|
|
583
|
+
) {
|
|
584
|
+
throw new BadDataException(
|
|
585
|
+
`AI remediation mode must be one of ${Object.values(
|
|
586
|
+
KubernetesAiRemediationMode,
|
|
587
|
+
).join(", ")} (got ${JSON.stringify(mode)}).`,
|
|
588
|
+
);
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
if (data["aiKubectlCommandAllowlist"] !== undefined) {
|
|
592
|
+
data["aiKubectlCommandAllowlist"] = normalizeKubectlAllowlistForWrite(
|
|
593
|
+
data["aiKubectlCommandAllowlist"],
|
|
594
|
+
);
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
/*
|
|
599
|
+
* A cluster's AI mode does the job of a FullAuto AutoRemediationRule with
|
|
600
|
+
* no rule row, so making AI do MORE on a cluster takes the same
|
|
601
|
+
* permissions as authoring such a rule (KUBERNETES_AI_ACCESS_ADMIN_
|
|
602
|
+
* PERMISSIONS), and binding a credential additionally takes the right to
|
|
603
|
+
* read credentials — the rule the dashboard's picker applies, now enforced
|
|
604
|
+
* where it cannot be skipped. The column ACLs stay open to every cluster
|
|
605
|
+
* editor on purpose: a column ACL cannot say "tightening is free", and
|
|
606
|
+
* turning AI remediation off must never need more than editing the
|
|
607
|
+
* cluster.
|
|
608
|
+
*
|
|
609
|
+
* `current` holds the settings of every cluster the write reaches. When it
|
|
610
|
+
* matched none, the write is judged against the never-configured defaults
|
|
611
|
+
* in the caller's tenant, so the answer does not depend on whether the id
|
|
612
|
+
* exists; with no project to check against at all it fails closed.
|
|
613
|
+
*/
|
|
614
|
+
private assertMayChangeAiAccess(data: {
|
|
615
|
+
data: JSONObject;
|
|
616
|
+
props: DatabaseCommonInteractionProps;
|
|
617
|
+
current: Array<AiAccessSettingsSnapshot>;
|
|
618
|
+
}): void {
|
|
619
|
+
const baselines: Array<AiAccessSettingsSnapshot> =
|
|
620
|
+
data.current.length > 0
|
|
621
|
+
? data.current
|
|
622
|
+
: [{ ...NEVER_CONFIGURED_AI_ACCESS, projectId: data.props.tenantId }];
|
|
623
|
+
|
|
624
|
+
for (const baseline of baselines) {
|
|
625
|
+
const loosening: AiAccessLoosening = this.getAiAccessLoosening(
|
|
626
|
+
data.data,
|
|
627
|
+
baseline,
|
|
628
|
+
);
|
|
629
|
+
|
|
630
|
+
if (!loosening.loosens) {
|
|
631
|
+
continue;
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
if (
|
|
635
|
+
!baseline.projectId ||
|
|
636
|
+
!holdsAnyPermission({
|
|
637
|
+
props: data.props,
|
|
638
|
+
projectId: baseline.projectId,
|
|
639
|
+
allowed: KUBERNETES_AI_ACCESS_ADMIN_PERMISSIONS,
|
|
640
|
+
})
|
|
641
|
+
) {
|
|
642
|
+
throw new NotAuthorizedException(getAiAccessAdminRefusal());
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
if (
|
|
646
|
+
loosening.bindsCredential &&
|
|
647
|
+
!holdsAnyPermission({
|
|
648
|
+
props: data.props,
|
|
649
|
+
projectId: baseline.projectId,
|
|
650
|
+
allowed: KUBERNETES_AI_ACCESS_CREDENTIAL_PERMISSIONS,
|
|
651
|
+
})
|
|
652
|
+
) {
|
|
653
|
+
throw new NotAuthorizedException(getAiAccessCredentialRefusal());
|
|
654
|
+
}
|
|
655
|
+
}
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
/*
|
|
659
|
+
* Does this write let AI do more on a cluster whose settings are
|
|
660
|
+
* `current`? Only a real change counts: the AI page posts every field of
|
|
661
|
+
* its form, so an editor who only flips the investigation switch re-posts
|
|
662
|
+
* an unchanged mode, allowlist and binding, and must not be refused for
|
|
663
|
+
* settings someone else chose.
|
|
664
|
+
*
|
|
665
|
+
* - mode: moving UP to Automatic or Bypass approval (Bypass approval ->
|
|
666
|
+
* Automatic is a tightening);
|
|
667
|
+
* - allowlist: adding a pattern the cluster did not already have
|
|
668
|
+
* (removing patterns, or clearing the list, tightens);
|
|
669
|
+
* - Runner or credential: binding one other than the current one
|
|
670
|
+
* (clearing tightens).
|
|
671
|
+
*
|
|
672
|
+
* `data` has been through validateAiRemediationSettings, so the mode is a
|
|
673
|
+
* known value and the allowlist a trimmed array or null.
|
|
674
|
+
*/
|
|
675
|
+
private getAiAccessLoosening(
|
|
676
|
+
data: JSONObject,
|
|
677
|
+
current: AiAccessSettingsSnapshot,
|
|
678
|
+
): AiAccessLoosening {
|
|
679
|
+
let loosens: boolean = false;
|
|
680
|
+
let bindsCredential: boolean = false;
|
|
681
|
+
|
|
682
|
+
const mode: KubernetesAiRemediationMode | undefined = data[
|
|
683
|
+
"aiRemediationMode"
|
|
684
|
+
] as KubernetesAiRemediationMode | undefined;
|
|
685
|
+
|
|
686
|
+
if (
|
|
687
|
+
mode !== undefined &&
|
|
688
|
+
isUnattendedRemediationMode(mode) &&
|
|
689
|
+
REMEDIATION_MODES_BY_AUTONOMY.indexOf(mode) >
|
|
690
|
+
REMEDIATION_MODES_BY_AUTONOMY.indexOf(current.aiRemediationMode)
|
|
691
|
+
) {
|
|
692
|
+
loosens = true;
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
if (data["aiKubectlCommandAllowlist"] !== undefined) {
|
|
696
|
+
const patterns: Array<string> =
|
|
697
|
+
(data["aiKubectlCommandAllowlist"] as Array<string> | null) || [];
|
|
698
|
+
|
|
699
|
+
if (
|
|
700
|
+
patterns.some((pattern: string) => {
|
|
701
|
+
return !current.aiKubectlCommandAllowlist.includes(pattern);
|
|
702
|
+
})
|
|
703
|
+
) {
|
|
704
|
+
loosens = true;
|
|
705
|
+
}
|
|
706
|
+
}
|
|
707
|
+
|
|
708
|
+
const runnerId: ObjectID | null = RelationIdUtil.readConsistent(
|
|
709
|
+
data,
|
|
710
|
+
AI_ACCESS_RUNNER_KEYS,
|
|
711
|
+
"AI access Runner",
|
|
712
|
+
);
|
|
713
|
+
|
|
714
|
+
if (runnerId && runnerId.toString() !== current.aiAccessRunnerId) {
|
|
715
|
+
loosens = true;
|
|
716
|
+
}
|
|
717
|
+
|
|
718
|
+
const credentialId: ObjectID | null = RelationIdUtil.readConsistent(
|
|
719
|
+
data,
|
|
720
|
+
AI_ACCESS_CREDENTIAL_KEYS,
|
|
721
|
+
"AI access credential",
|
|
722
|
+
);
|
|
723
|
+
|
|
724
|
+
if (
|
|
725
|
+
credentialId &&
|
|
726
|
+
credentialId.toString() !== current.aiAccessCredentialId
|
|
727
|
+
) {
|
|
728
|
+
loosens = true;
|
|
729
|
+
bindsCredential = true;
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
return { loosens, bindsCredential };
|
|
733
|
+
}
|
|
734
|
+
|
|
735
|
+
/*
|
|
736
|
+
* The AI access settings of every cluster an operator's update reaches,
|
|
737
|
+
* read before the write. onBeforeUpdate runs before the framework scopes
|
|
738
|
+
* the query to the caller's project, so scope it here: a caller must
|
|
739
|
+
* never learn anything about, or be judged against, another project's
|
|
740
|
+
* cluster.
|
|
741
|
+
*/
|
|
742
|
+
@CaptureSpan()
|
|
743
|
+
private async getAiAccessSettingsForUpdateQuery(
|
|
744
|
+
updateBy: UpdateBy<Model>,
|
|
745
|
+
): Promise<Record<string, AiAccessSettingsSnapshot>> {
|
|
746
|
+
const clusters: Array<Model> = await this.findBy({
|
|
747
|
+
query: {
|
|
748
|
+
...updateBy.query,
|
|
749
|
+
...(updateBy.props.tenantId
|
|
750
|
+
? { projectId: updateBy.props.tenantId }
|
|
751
|
+
: {}),
|
|
752
|
+
},
|
|
753
|
+
select: {
|
|
754
|
+
_id: true,
|
|
755
|
+
projectId: true,
|
|
756
|
+
clusterIdentifier: true,
|
|
757
|
+
isAiInvestigationEnabled: true,
|
|
758
|
+
aiRemediationMode: true,
|
|
759
|
+
aiKubectlCommandAllowlist: true,
|
|
760
|
+
aiAccessRunnerId: true,
|
|
761
|
+
aiAccessCredentialId: true,
|
|
762
|
+
},
|
|
763
|
+
limit: LIMIT_MAX,
|
|
764
|
+
skip: 0,
|
|
765
|
+
props: {
|
|
766
|
+
isRoot: true,
|
|
767
|
+
},
|
|
768
|
+
});
|
|
769
|
+
|
|
770
|
+
const settings: Record<string, AiAccessSettingsSnapshot> = {};
|
|
771
|
+
|
|
772
|
+
for (const cluster of clusters) {
|
|
773
|
+
const clusterId: string | undefined =
|
|
774
|
+
cluster.id?.toString() || cluster._id?.toString();
|
|
775
|
+
|
|
776
|
+
if (!clusterId) {
|
|
777
|
+
continue;
|
|
778
|
+
}
|
|
779
|
+
|
|
780
|
+
settings[clusterId] = {
|
|
781
|
+
projectId: cluster.projectId,
|
|
782
|
+
clusterIdentifier: cluster.clusterIdentifier,
|
|
783
|
+
isAiInvestigationEnabled: cluster.isAiInvestigationEnabled === true,
|
|
784
|
+
aiRemediationMode: readStoredRemediationMode(cluster.aiRemediationMode),
|
|
785
|
+
aiKubectlCommandAllowlist: readStoredKubectlAllowlist(
|
|
786
|
+
cluster.aiKubectlCommandAllowlist,
|
|
787
|
+
),
|
|
788
|
+
aiAccessRunnerId: cluster.aiAccessRunnerId?.toString() || null,
|
|
789
|
+
aiAccessCredentialId: cluster.aiAccessCredentialId?.toString() || null,
|
|
790
|
+
};
|
|
791
|
+
}
|
|
792
|
+
|
|
793
|
+
return settings;
|
|
794
|
+
}
|
|
795
|
+
|
|
796
|
+
/*
|
|
797
|
+
* aiAccessRunnerId / aiAccessCredentialId are editable through ordinary
|
|
798
|
+
* CRUD by every member who may edit a cluster, and nothing in the
|
|
799
|
+
* framework checks that a ManyToOne target belongs to the row's own
|
|
800
|
+
* project (only the tenant relation itself is checked). Unchecked, a
|
|
801
|
+
* member of project A could point a cluster at project B's Runner or
|
|
802
|
+
* credential — and then read that Runner's name, liveness and status,
|
|
803
|
+
* or that credential's name and type, through the relation join, and use
|
|
804
|
+
* the FK as an existence oracle for foreign ids. Same class of guard as
|
|
805
|
+
* MonitorProbeService ("Probe not found or it does not belong to this
|
|
806
|
+
* project.") and IoTDeviceCredentialService.
|
|
807
|
+
*
|
|
808
|
+
* WHO may bind is decided before this runs (assertMayChangeAiAccess); this
|
|
809
|
+
* only decides WHAT may be bound. Clearing a binding (null) is always
|
|
810
|
+
* allowed.
|
|
811
|
+
*
|
|
812
|
+
* Returns the rows it loaded (with what validateAiAccessBindingPairs
|
|
813
|
+
* reads off them), so the pair check does not look them up again.
|
|
814
|
+
*/
|
|
815
|
+
@CaptureSpan()
|
|
816
|
+
private async validateAiAccessBindingsBelongToProject(data: {
|
|
817
|
+
data: JSONObject;
|
|
818
|
+
projectId: ObjectID | undefined;
|
|
819
|
+
// Filled with what this call loads, when given.
|
|
820
|
+
loaded?: AiAccessBindingRows | undefined;
|
|
821
|
+
}): Promise<AiAccessBindingRows> {
|
|
822
|
+
const loaded: AiAccessBindingRows = data.loaded || {
|
|
823
|
+
runners: new Map<string, Runner>(),
|
|
824
|
+
credentials: new Map<string, RunbookCredential>(),
|
|
825
|
+
};
|
|
826
|
+
|
|
827
|
+
const runnerId: ObjectID | null = RelationIdUtil.readConsistent(
|
|
828
|
+
data.data,
|
|
829
|
+
AI_ACCESS_RUNNER_KEYS,
|
|
830
|
+
"AI access Runner",
|
|
831
|
+
);
|
|
832
|
+
|
|
833
|
+
const credentialId: ObjectID | null = RelationIdUtil.readConsistent(
|
|
834
|
+
data.data,
|
|
835
|
+
AI_ACCESS_CREDENTIAL_KEYS,
|
|
836
|
+
"AI access credential",
|
|
837
|
+
);
|
|
838
|
+
|
|
839
|
+
if (!runnerId && !credentialId) {
|
|
840
|
+
return loaded;
|
|
841
|
+
}
|
|
842
|
+
|
|
843
|
+
if (!data.projectId) {
|
|
844
|
+
throw new BadDataException(
|
|
845
|
+
"The project of this Kubernetes cluster could not be resolved, so its AI access Runner or credential cannot be checked.",
|
|
846
|
+
);
|
|
847
|
+
}
|
|
848
|
+
|
|
849
|
+
if (runnerId) {
|
|
850
|
+
const runner: Runner | null = await RunnerService.findOneBy({
|
|
851
|
+
query: {
|
|
852
|
+
_id: runnerId.toString(),
|
|
853
|
+
projectId: data.projectId,
|
|
854
|
+
},
|
|
855
|
+
select: AI_ACCESS_BINDING_RUNNER_SELECT,
|
|
856
|
+
props: { isRoot: true },
|
|
857
|
+
});
|
|
858
|
+
|
|
859
|
+
if (!runner) {
|
|
860
|
+
throw new BadDataException(
|
|
861
|
+
"Runner not found or it does not belong to this project.",
|
|
862
|
+
);
|
|
863
|
+
}
|
|
864
|
+
|
|
865
|
+
loaded.runners.set(runnerId.toString(), runner);
|
|
866
|
+
}
|
|
867
|
+
|
|
868
|
+
if (credentialId) {
|
|
869
|
+
const credential: RunbookCredential | null =
|
|
870
|
+
await RunbookCredentialService.findOneBy({
|
|
871
|
+
query: {
|
|
872
|
+
_id: credentialId.toString(),
|
|
873
|
+
projectId: data.projectId,
|
|
874
|
+
},
|
|
875
|
+
select: AI_ACCESS_BINDING_CREDENTIAL_SELECT,
|
|
876
|
+
props: { isRoot: true },
|
|
877
|
+
});
|
|
878
|
+
|
|
879
|
+
if (
|
|
880
|
+
!credential ||
|
|
881
|
+
credential.credentialType !== RunbookCredentialType.Kubernetes
|
|
882
|
+
) {
|
|
883
|
+
throw new BadDataException(AI_ACCESS_CREDENTIAL_REFUSAL);
|
|
884
|
+
}
|
|
885
|
+
|
|
886
|
+
loaded.credentials.set(credentialId.toString(), credential);
|
|
887
|
+
}
|
|
888
|
+
|
|
889
|
+
return loaded;
|
|
890
|
+
}
|
|
891
|
+
|
|
892
|
+
/*
|
|
893
|
+
* Whether the Runner and credential a write leaves a cluster with can
|
|
894
|
+
* work together — checked for an operator's write (the dashboard no
|
|
895
|
+
* longer offers these pairs, but the API and Terraform can still send
|
|
896
|
+
* them), per cluster the write reaches, and only where the pair actually
|
|
897
|
+
* changes (the AI page re-posts unchanged values):
|
|
898
|
+
*
|
|
899
|
+
* - a kubernetes-agent Runner of ANOTHER cluster is refused: its
|
|
900
|
+
* ServiceAccount reaches only the cluster its pod runs in, and it is
|
|
901
|
+
* never given a credential, so it can never reach this one. This
|
|
902
|
+
* cluster's own agent Runner (by its name for this cluster, or a
|
|
903
|
+
* posture naming it) is of course fine.
|
|
904
|
+
* - a credential together with a kubernetes-agent Runner of another
|
|
905
|
+
* cluster is refused — such a Runner is never handed credential
|
|
906
|
+
* material (this cluster's own agent ignores a credential: in-cluster
|
|
907
|
+
* access wins).
|
|
908
|
+
* - a credential the chosen Runner is not assigned is refused: the claim
|
|
909
|
+
* path resolves a credential only for a Runner it is assigned to, so
|
|
910
|
+
* every command would fail.
|
|
911
|
+
*/
|
|
912
|
+
@CaptureSpan()
|
|
913
|
+
private async validateAiAccessBindingPairs(data: {
|
|
914
|
+
data: JSONObject;
|
|
915
|
+
clusters: Array<AiAccessSettingsSnapshot>;
|
|
916
|
+
loaded: AiAccessBindingRows;
|
|
917
|
+
}): Promise<void> {
|
|
918
|
+
const isRunnerWritten: boolean = isAnyKeyWritten(
|
|
919
|
+
data.data,
|
|
920
|
+
AI_ACCESS_RUNNER_KEYS,
|
|
921
|
+
);
|
|
922
|
+
const isCredentialWritten: boolean = isAnyKeyWritten(
|
|
923
|
+
data.data,
|
|
924
|
+
AI_ACCESS_CREDENTIAL_KEYS,
|
|
925
|
+
);
|
|
926
|
+
|
|
927
|
+
if (!isRunnerWritten && !isCredentialWritten) {
|
|
928
|
+
return;
|
|
929
|
+
}
|
|
930
|
+
|
|
931
|
+
const writtenRunnerId: string | null =
|
|
932
|
+
RelationIdUtil.readConsistent(
|
|
933
|
+
data.data,
|
|
934
|
+
AI_ACCESS_RUNNER_KEYS,
|
|
935
|
+
"AI access Runner",
|
|
936
|
+
)?.toString() || null;
|
|
937
|
+
const writtenCredentialId: string | null =
|
|
938
|
+
RelationIdUtil.readConsistent(
|
|
939
|
+
data.data,
|
|
940
|
+
AI_ACCESS_CREDENTIAL_KEYS,
|
|
941
|
+
"AI access credential",
|
|
942
|
+
)?.toString() || null;
|
|
943
|
+
|
|
944
|
+
for (const cluster of data.clusters) {
|
|
945
|
+
const runnerId: string | null = isRunnerWritten
|
|
946
|
+
? writtenRunnerId
|
|
947
|
+
: cluster.aiAccessRunnerId;
|
|
948
|
+
const credentialId: string | null = isCredentialWritten
|
|
949
|
+
? writtenCredentialId
|
|
950
|
+
: cluster.aiAccessCredentialId;
|
|
951
|
+
const isRunnerChanged: boolean = runnerId !== cluster.aiAccessRunnerId;
|
|
952
|
+
const isCredentialChanged: boolean =
|
|
953
|
+
credentialId !== cluster.aiAccessCredentialId;
|
|
954
|
+
|
|
955
|
+
if (!runnerId || (!isRunnerChanged && !isCredentialChanged)) {
|
|
956
|
+
continue;
|
|
957
|
+
}
|
|
958
|
+
|
|
959
|
+
const runner: Runner | null = await this.loadBindingRunner({
|
|
960
|
+
runnerId,
|
|
961
|
+
projectId: cluster.projectId,
|
|
962
|
+
loaded: data.loaded,
|
|
963
|
+
});
|
|
964
|
+
|
|
965
|
+
// A bound Runner that is gone is the Runner delete race: nothing to pair.
|
|
966
|
+
if (!runner) {
|
|
967
|
+
continue;
|
|
968
|
+
}
|
|
969
|
+
|
|
970
|
+
const isAgentRunner: boolean =
|
|
971
|
+
RunnerServiceClass.isKubernetesAgentRunnerRow(runner);
|
|
972
|
+
const isThisClustersAgent: boolean =
|
|
973
|
+
RunnerServiceClass.isKubernetesAgentRunnerOfCluster(
|
|
974
|
+
runner,
|
|
975
|
+
cluster.clusterIdentifier,
|
|
976
|
+
);
|
|
977
|
+
|
|
978
|
+
if (isAgentRunner && !isThisClustersAgent && isRunnerChanged) {
|
|
979
|
+
throw new BadDataException(
|
|
980
|
+
`Runner "${runner.name}" is the in-cluster Runner the Kubernetes agent chart installed on another cluster. Its ServiceAccount reaches only the cluster its pod runs in, and it is never given a credential, so it cannot run kubectl for this cluster. Install the in-cluster Runner on this cluster with --set aiAccess.enabled=true, or bind a Runner you created under Project Settings → Runners together with a Kubernetes credential for this cluster.`,
|
|
981
|
+
);
|
|
982
|
+
}
|
|
983
|
+
|
|
984
|
+
if (!credentialId || isThisClustersAgent) {
|
|
985
|
+
continue;
|
|
986
|
+
}
|
|
987
|
+
|
|
988
|
+
if (isAgentRunner) {
|
|
989
|
+
throw new BadDataException(
|
|
990
|
+
`Runner "${runner.name}" is an in-cluster Runner the Kubernetes agent chart installed: it runs kubectl with its own ServiceAccount only and is never given a credential. Clear the credential, or bind a Runner you created under Project Settings → Runners that the credential is assigned to.`,
|
|
991
|
+
);
|
|
992
|
+
}
|
|
993
|
+
|
|
994
|
+
const credential: RunbookCredential | null =
|
|
995
|
+
await this.loadBindingCredential({
|
|
996
|
+
credentialId,
|
|
997
|
+
projectId: cluster.projectId,
|
|
998
|
+
loaded: data.loaded,
|
|
999
|
+
});
|
|
1000
|
+
|
|
1001
|
+
// A bound credential that is gone is reported by the readiness check.
|
|
1002
|
+
if (!credential) {
|
|
1003
|
+
continue;
|
|
1004
|
+
}
|
|
1005
|
+
|
|
1006
|
+
const isAssigned: boolean = (credential.runners || []).some(
|
|
1007
|
+
(assigned: Runner) => {
|
|
1008
|
+
return (
|
|
1009
|
+
(assigned.id?.toString() || assigned._id?.toString()) === runnerId
|
|
1010
|
+
);
|
|
1011
|
+
},
|
|
1012
|
+
);
|
|
1013
|
+
|
|
1014
|
+
if (!isAssigned) {
|
|
1015
|
+
throw new BadDataException(
|
|
1016
|
+
`The Kubernetes credential is not assigned to Runner "${runner.name}", so that Runner could never use it for this cluster (a credential is handed only to the Runners it is assigned to). Assign it to the Runner under Project Settings → Runner Credentials first, or choose a credential that is assigned to it.`,
|
|
1017
|
+
);
|
|
1018
|
+
}
|
|
1019
|
+
}
|
|
1020
|
+
}
|
|
1021
|
+
|
|
1022
|
+
private async loadBindingRunner(data: {
|
|
1023
|
+
runnerId: string;
|
|
1024
|
+
projectId: ObjectID | undefined;
|
|
1025
|
+
loaded: AiAccessBindingRows;
|
|
1026
|
+
}): Promise<Runner | null> {
|
|
1027
|
+
const cached: Runner | undefined = data.loaded.runners.get(data.runnerId);
|
|
1028
|
+
|
|
1029
|
+
if (cached) {
|
|
1030
|
+
return cached;
|
|
1031
|
+
}
|
|
1032
|
+
|
|
1033
|
+
const runner: Runner | null = await RunnerService.findOneBy({
|
|
1034
|
+
query: {
|
|
1035
|
+
_id: data.runnerId,
|
|
1036
|
+
...(data.projectId ? { projectId: data.projectId } : {}),
|
|
1037
|
+
},
|
|
1038
|
+
select: AI_ACCESS_BINDING_RUNNER_SELECT,
|
|
1039
|
+
props: { isRoot: true },
|
|
1040
|
+
});
|
|
1041
|
+
|
|
1042
|
+
if (runner) {
|
|
1043
|
+
data.loaded.runners.set(data.runnerId, runner);
|
|
1044
|
+
}
|
|
1045
|
+
|
|
1046
|
+
return runner;
|
|
1047
|
+
}
|
|
1048
|
+
|
|
1049
|
+
private async loadBindingCredential(data: {
|
|
1050
|
+
credentialId: string;
|
|
1051
|
+
projectId: ObjectID | undefined;
|
|
1052
|
+
loaded: AiAccessBindingRows;
|
|
1053
|
+
}): Promise<RunbookCredential | null> {
|
|
1054
|
+
const cached: RunbookCredential | undefined = data.loaded.credentials.get(
|
|
1055
|
+
data.credentialId,
|
|
1056
|
+
);
|
|
1057
|
+
|
|
1058
|
+
if (cached) {
|
|
1059
|
+
return cached;
|
|
1060
|
+
}
|
|
1061
|
+
|
|
1062
|
+
const credential: RunbookCredential | null =
|
|
1063
|
+
await RunbookCredentialService.findOneBy({
|
|
1064
|
+
query: {
|
|
1065
|
+
_id: data.credentialId,
|
|
1066
|
+
...(data.projectId ? { projectId: data.projectId } : {}),
|
|
1067
|
+
},
|
|
1068
|
+
select: AI_ACCESS_BINDING_CREDENTIAL_SELECT,
|
|
1069
|
+
props: { isRoot: true },
|
|
1070
|
+
});
|
|
1071
|
+
|
|
1072
|
+
if (credential) {
|
|
1073
|
+
data.loaded.credentials.set(data.credentialId, credential);
|
|
1074
|
+
}
|
|
1075
|
+
|
|
1076
|
+
return credential;
|
|
1077
|
+
}
|
|
1078
|
+
|
|
1079
|
+
@CaptureSpan()
|
|
1080
|
+
private async getProjectIdsForUpdateQuery(
|
|
1081
|
+
updateBy: UpdateBy<Model>,
|
|
1082
|
+
): Promise<Array<ObjectID>> {
|
|
1083
|
+
const clusters: Array<Model> = await this.findBy({
|
|
1084
|
+
query: updateBy.query,
|
|
1085
|
+
select: {
|
|
1086
|
+
projectId: true,
|
|
1087
|
+
},
|
|
1088
|
+
limit: LIMIT_MAX,
|
|
1089
|
+
skip: 0,
|
|
1090
|
+
props: {
|
|
1091
|
+
isRoot: true,
|
|
1092
|
+
},
|
|
1093
|
+
});
|
|
1094
|
+
|
|
1095
|
+
const projectIds: Record<string, ObjectID> = {};
|
|
1096
|
+
|
|
1097
|
+
for (const cluster of clusters) {
|
|
1098
|
+
if (cluster.projectId) {
|
|
1099
|
+
projectIds[cluster.projectId.toString()] = cluster.projectId;
|
|
1100
|
+
}
|
|
1101
|
+
}
|
|
1102
|
+
|
|
1103
|
+
return Object.values(projectIds);
|
|
1104
|
+
}
|
|
1105
|
+
|
|
35
1106
|
@CaptureSpan()
|
|
36
1107
|
protected override async onCreateSuccess(
|
|
37
1108
|
onCreate: OnCreate<Model>,
|
|
38
1109
|
createdItem: Model,
|
|
39
1110
|
): Promise<Model> {
|
|
1111
|
+
/*
|
|
1112
|
+
* Decided in onBeforeCreate, from the payload as the caller sent it: by
|
|
1113
|
+
* now the saved row carries the column defaults, which would read as an
|
|
1114
|
+
* AI access setting on every create.
|
|
1115
|
+
*/
|
|
1116
|
+
if (
|
|
1117
|
+
createdItem.id &&
|
|
1118
|
+
(onCreate.carryForward as { writesAiAccessSettings?: boolean } | null)
|
|
1119
|
+
?.writesAiAccessSettings === true
|
|
1120
|
+
) {
|
|
1121
|
+
await this.markAiAccessConfigured([createdItem.id]);
|
|
1122
|
+
|
|
1123
|
+
if (this.bindsRunner(onCreate.createBy.data as unknown as JSONObject)) {
|
|
1124
|
+
await this.markAiAccessRunnerBound([createdItem.id]);
|
|
1125
|
+
}
|
|
1126
|
+
}
|
|
1127
|
+
|
|
40
1128
|
if (createdItem.projectId && createdItem.id) {
|
|
41
1129
|
Promise.resolve()
|
|
42
1130
|
.then(async () => {
|
|
@@ -436,15 +1524,339 @@ export class Service extends DatabaseService<Model> {
|
|
|
436
1524
|
onUpdate: OnUpdate<Model>,
|
|
437
1525
|
updatedItemIds: Array<ObjectID>,
|
|
438
1526
|
): Promise<OnUpdate<Model>> {
|
|
1527
|
+
const aiAccessWrite: AiAccessWriteCarryForward | null =
|
|
1528
|
+
getAiAccessWriteCarryForward(onUpdate.carryForward);
|
|
1529
|
+
|
|
1530
|
+
/*
|
|
1531
|
+
* The feed items first, fire and forget: the operator's write has
|
|
1532
|
+
* committed, so who changed what AI may do is recorded even when the
|
|
1533
|
+
* marker writes below fail (and the save reports that failure).
|
|
1534
|
+
*/
|
|
439
1535
|
this.writeKubernetesClusterUpdatedFeed(onUpdate, updatedItemIds).catch(
|
|
440
1536
|
(error: Error) => {
|
|
441
1537
|
logger.error(error);
|
|
442
1538
|
},
|
|
443
1539
|
);
|
|
444
1540
|
|
|
1541
|
+
if (aiAccessWrite) {
|
|
1542
|
+
this.writeAiAccessSettingsChangedFeed({
|
|
1543
|
+
onUpdate,
|
|
1544
|
+
updatedItemIds,
|
|
1545
|
+
previousAiAccessSettings: aiAccessWrite.previousAiAccessSettings,
|
|
1546
|
+
}).catch((error: Error) => {
|
|
1547
|
+
logger.error(error);
|
|
1548
|
+
});
|
|
1549
|
+
}
|
|
1550
|
+
|
|
1551
|
+
/*
|
|
1552
|
+
* Awaited, unlike the feed: registration reads the markers to tell an
|
|
1553
|
+
* operator's "off" (or a cleared binding) from a cluster nobody ever
|
|
1554
|
+
* configured, so a save that could not record them must not look like
|
|
1555
|
+
* one that did.
|
|
1556
|
+
*/
|
|
1557
|
+
if (aiAccessWrite && updatedItemIds.length > 0) {
|
|
1558
|
+
await this.markAiAccessConfigured(updatedItemIds);
|
|
1559
|
+
|
|
1560
|
+
if (this.bindsRunner(onUpdate.updateBy.data as unknown as JSONObject)) {
|
|
1561
|
+
await this.markAiAccessRunnerBound(updatedItemIds);
|
|
1562
|
+
}
|
|
1563
|
+
}
|
|
1564
|
+
|
|
445
1565
|
return onUpdate;
|
|
446
1566
|
}
|
|
447
1567
|
|
|
1568
|
+
// The write binds a Runner (not merely clears the binding).
|
|
1569
|
+
private bindsRunner(data: JSONObject | undefined): boolean {
|
|
1570
|
+
return Boolean(
|
|
1571
|
+
data &&
|
|
1572
|
+
RelationIdUtil.readConsistent(
|
|
1573
|
+
data,
|
|
1574
|
+
AI_ACCESS_RUNNER_KEYS,
|
|
1575
|
+
"AI access Runner",
|
|
1576
|
+
),
|
|
1577
|
+
);
|
|
1578
|
+
}
|
|
1579
|
+
|
|
1580
|
+
/*
|
|
1581
|
+
* Set aiAccessRunnerBoundAt on each cluster that does not have it yet —
|
|
1582
|
+
* "a Runner was bound here", never cleared. Registration reads it to leave
|
|
1583
|
+
* a cluster whose binding was later cleared (or whose Runner was deleted)
|
|
1584
|
+
* unbound, while still binding one an operator only configured before
|
|
1585
|
+
* installing the chart. Written as root after the operator's own write
|
|
1586
|
+
* succeeded; the column's update ACL is empty.
|
|
1587
|
+
*/
|
|
1588
|
+
@CaptureSpan()
|
|
1589
|
+
private async markAiAccessRunnerBound(
|
|
1590
|
+
clusterIds: Array<ObjectID>,
|
|
1591
|
+
): Promise<void> {
|
|
1592
|
+
await this.updateBy({
|
|
1593
|
+
query: {
|
|
1594
|
+
_id: QueryHelper.any(clusterIds),
|
|
1595
|
+
aiAccessRunnerBoundAt: QueryHelper.isNull(),
|
|
1596
|
+
},
|
|
1597
|
+
data: {
|
|
1598
|
+
aiAccessRunnerBoundAt: OneUptimeDate.getCurrentDate(),
|
|
1599
|
+
},
|
|
1600
|
+
limit: LIMIT_MAX,
|
|
1601
|
+
skip: 0,
|
|
1602
|
+
props: {
|
|
1603
|
+
isRoot: true,
|
|
1604
|
+
},
|
|
1605
|
+
});
|
|
1606
|
+
}
|
|
1607
|
+
|
|
1608
|
+
/*
|
|
1609
|
+
* Set aiAccessConfiguredAt on each cluster that does not have it yet, and
|
|
1610
|
+
* never touch one that does: the marker records when AI access was FIRST
|
|
1611
|
+
* configured. A server-only column (its update ACL is empty), so it is
|
|
1612
|
+
* written here, as root, after the operator's own write succeeded, rather
|
|
1613
|
+
* than slipped into that write.
|
|
1614
|
+
*/
|
|
1615
|
+
@CaptureSpan()
|
|
1616
|
+
private async markAiAccessConfigured(
|
|
1617
|
+
clusterIds: Array<ObjectID>,
|
|
1618
|
+
): Promise<void> {
|
|
1619
|
+
await this.updateBy({
|
|
1620
|
+
query: {
|
|
1621
|
+
_id: QueryHelper.any(clusterIds),
|
|
1622
|
+
aiAccessConfiguredAt: QueryHelper.isNull(),
|
|
1623
|
+
},
|
|
1624
|
+
data: {
|
|
1625
|
+
aiAccessConfiguredAt: OneUptimeDate.getCurrentDate(),
|
|
1626
|
+
},
|
|
1627
|
+
limit: LIMIT_MAX,
|
|
1628
|
+
skip: 0,
|
|
1629
|
+
props: {
|
|
1630
|
+
isRoot: true,
|
|
1631
|
+
},
|
|
1632
|
+
});
|
|
1633
|
+
}
|
|
1634
|
+
|
|
1635
|
+
/*
|
|
1636
|
+
* Who changed what OneUptime AI may do on a cluster, and when. The generic
|
|
1637
|
+
* "was updated" item only covers MEANINGFUL_UPDATE_COLUMNS (shared by ten
|
|
1638
|
+
* resource types and deliberately left alone), and the registration path
|
|
1639
|
+
* records only its own binds, so without this an operator switching a
|
|
1640
|
+
* production cluster to Bypass approval - or back off - left no trace.
|
|
1641
|
+
*
|
|
1642
|
+
* One item per cluster that actually changed; a save that re-posts
|
|
1643
|
+
* unchanged values (the AI page posts its whole form) records nothing.
|
|
1644
|
+
* API-key and Terraform writes carry no user and are attributed to an API
|
|
1645
|
+
* key rather than dropped.
|
|
1646
|
+
*/
|
|
1647
|
+
private async writeAiAccessSettingsChangedFeed(data: {
|
|
1648
|
+
onUpdate: OnUpdate<Model>;
|
|
1649
|
+
updatedItemIds: Array<ObjectID>;
|
|
1650
|
+
previousAiAccessSettings: Record<string, AiAccessSettingsSnapshot>;
|
|
1651
|
+
}): Promise<void> {
|
|
1652
|
+
const updateData: JSONObject = (data.onUpdate.updateBy.data ||
|
|
1653
|
+
{}) as unknown as JSONObject;
|
|
1654
|
+
const updatedByUserId: ObjectID | undefined =
|
|
1655
|
+
data.onUpdate.updateBy.props.userId || undefined;
|
|
1656
|
+
|
|
1657
|
+
for (const kubernetesClusterId of data.updatedItemIds) {
|
|
1658
|
+
const previous: AiAccessSettingsSnapshot | undefined =
|
|
1659
|
+
data.previousAiAccessSettings[kubernetesClusterId.toString()];
|
|
1660
|
+
|
|
1661
|
+
const changes: Array<string> = await this.describeAiAccessChanges(
|
|
1662
|
+
updateData,
|
|
1663
|
+
previous,
|
|
1664
|
+
);
|
|
1665
|
+
|
|
1666
|
+
if (changes.length === 0) {
|
|
1667
|
+
continue;
|
|
1668
|
+
}
|
|
1669
|
+
|
|
1670
|
+
const projectId: ObjectID | undefined =
|
|
1671
|
+
previous?.projectId ||
|
|
1672
|
+
(
|
|
1673
|
+
await this.findOneById({
|
|
1674
|
+
id: kubernetesClusterId,
|
|
1675
|
+
select: { projectId: true },
|
|
1676
|
+
props: { isRoot: true },
|
|
1677
|
+
})
|
|
1678
|
+
)?.projectId;
|
|
1679
|
+
|
|
1680
|
+
if (!projectId) {
|
|
1681
|
+
continue;
|
|
1682
|
+
}
|
|
1683
|
+
|
|
1684
|
+
const userMarkdown: string = updatedByUserId
|
|
1685
|
+
? (await UserService.getUserMarkdownString({
|
|
1686
|
+
userId: updatedByUserId,
|
|
1687
|
+
projectId,
|
|
1688
|
+
})) || "A user"
|
|
1689
|
+
: "";
|
|
1690
|
+
|
|
1691
|
+
const actor: string = userMarkdown ? `**${userMarkdown}**` : "An API key";
|
|
1692
|
+
|
|
1693
|
+
/*
|
|
1694
|
+
* Yellow when the change lets AI do more (the same test the permission
|
|
1695
|
+
* check applies), grey when it tightens or only flips investigation.
|
|
1696
|
+
*/
|
|
1697
|
+
const displayColor: Color = this.getAiAccessLoosening(
|
|
1698
|
+
updateData,
|
|
1699
|
+
previous || NEVER_CONFIGURED_AI_ACCESS,
|
|
1700
|
+
).loosens
|
|
1701
|
+
? Yellow500
|
|
1702
|
+
: Gray500;
|
|
1703
|
+
|
|
1704
|
+
const moreInformation: Array<string> = [
|
|
1705
|
+
`**Changed by**: ${userMarkdown || "An API key (no user)"}`,
|
|
1706
|
+
];
|
|
1707
|
+
|
|
1708
|
+
const allowlist: unknown = updateData["aiKubectlCommandAllowlist"];
|
|
1709
|
+
|
|
1710
|
+
if (Array.isArray(allowlist) && allowlist.length > 0) {
|
|
1711
|
+
moreInformation.push(
|
|
1712
|
+
`**kubectl allowlist**:\n\n${allowlist
|
|
1713
|
+
.map((pattern: string) => {
|
|
1714
|
+
return `- \`${pattern.replace(/`/g, "'")}\``;
|
|
1715
|
+
})
|
|
1716
|
+
.join("\n")}`,
|
|
1717
|
+
);
|
|
1718
|
+
}
|
|
1719
|
+
|
|
1720
|
+
await KubernetesClusterFeedService.createKubernetesClusterFeedItem({
|
|
1721
|
+
kubernetesClusterId,
|
|
1722
|
+
projectId,
|
|
1723
|
+
kubernetesClusterFeedEventType:
|
|
1724
|
+
KubernetesClusterFeedEventType.KubernetesClusterUpdated,
|
|
1725
|
+
displayColor,
|
|
1726
|
+
feedInfoInMarkdown: `🤖 ${actor} changed what OneUptime AI may do on ${await this.getKubernetesClusterMarkdownLink(
|
|
1727
|
+
projectId,
|
|
1728
|
+
kubernetesClusterId,
|
|
1729
|
+
)}:\n\n${changes
|
|
1730
|
+
.map((change: string) => {
|
|
1731
|
+
return `- ${change}`;
|
|
1732
|
+
})
|
|
1733
|
+
.join("\n")}`,
|
|
1734
|
+
moreInformationInMarkdown: moreInformation.join("\n\n"),
|
|
1735
|
+
userId: updatedByUserId,
|
|
1736
|
+
});
|
|
1737
|
+
}
|
|
1738
|
+
}
|
|
1739
|
+
|
|
1740
|
+
/*
|
|
1741
|
+
* One line per AI access setting this write actually changed, old -> new.
|
|
1742
|
+
* With no `previous` (the cluster was not among those read before the
|
|
1743
|
+
* write) every written setting is reported as set, without a "from".
|
|
1744
|
+
*
|
|
1745
|
+
* A credential is reported without its name: the feed is readable by
|
|
1746
|
+
* everyone who may read the cluster, credentials only by those who may
|
|
1747
|
+
* read credentials.
|
|
1748
|
+
*/
|
|
1749
|
+
private async describeAiAccessChanges(
|
|
1750
|
+
updateData: JSONObject,
|
|
1751
|
+
previous: AiAccessSettingsSnapshot | undefined,
|
|
1752
|
+
): Promise<Array<string>> {
|
|
1753
|
+
const changes: Array<string> = [];
|
|
1754
|
+
|
|
1755
|
+
if (updateData["isAiInvestigationEnabled"] !== undefined) {
|
|
1756
|
+
const isEnabled: boolean =
|
|
1757
|
+
updateData["isAiInvestigationEnabled"] === true;
|
|
1758
|
+
|
|
1759
|
+
if (!previous || previous.isAiInvestigationEnabled !== isEnabled) {
|
|
1760
|
+
changes.push(
|
|
1761
|
+
`AI investigation with kubectl turned **${isEnabled ? "on" : "off"}**`,
|
|
1762
|
+
);
|
|
1763
|
+
}
|
|
1764
|
+
}
|
|
1765
|
+
|
|
1766
|
+
if (updateData["aiRemediationMode"] !== undefined) {
|
|
1767
|
+
const mode: KubernetesAiRemediationMode = readStoredRemediationMode(
|
|
1768
|
+
updateData["aiRemediationMode"],
|
|
1769
|
+
);
|
|
1770
|
+
|
|
1771
|
+
if (!previous) {
|
|
1772
|
+
changes.push(
|
|
1773
|
+
`AI remediation set to **${REMEDIATION_MODE_FEED_LABELS[mode]}**`,
|
|
1774
|
+
);
|
|
1775
|
+
} else if (previous.aiRemediationMode !== mode) {
|
|
1776
|
+
changes.push(
|
|
1777
|
+
`AI remediation changed from **${
|
|
1778
|
+
REMEDIATION_MODE_FEED_LABELS[previous.aiRemediationMode]
|
|
1779
|
+
}** to **${REMEDIATION_MODE_FEED_LABELS[mode]}**`,
|
|
1780
|
+
);
|
|
1781
|
+
}
|
|
1782
|
+
}
|
|
1783
|
+
|
|
1784
|
+
if (updateData["aiKubectlCommandAllowlist"] !== undefined) {
|
|
1785
|
+
const patterns: Array<string> = readStoredKubectlAllowlist(
|
|
1786
|
+
updateData["aiKubectlCommandAllowlist"],
|
|
1787
|
+
);
|
|
1788
|
+
|
|
1789
|
+
if (
|
|
1790
|
+
!previous ||
|
|
1791
|
+
!isSameKubectlAllowlist(previous.aiKubectlCommandAllowlist, patterns)
|
|
1792
|
+
) {
|
|
1793
|
+
changes.push(
|
|
1794
|
+
patterns.length === 0
|
|
1795
|
+
? "kubectl allowlist cleared"
|
|
1796
|
+
: `kubectl allowlist changed to ${describePatternCount(
|
|
1797
|
+
patterns.length,
|
|
1798
|
+
)}${
|
|
1799
|
+
previous
|
|
1800
|
+
? ` (was ${describePatternCount(
|
|
1801
|
+
previous.aiKubectlCommandAllowlist.length,
|
|
1802
|
+
)})`
|
|
1803
|
+
: ""
|
|
1804
|
+
}`,
|
|
1805
|
+
);
|
|
1806
|
+
}
|
|
1807
|
+
}
|
|
1808
|
+
|
|
1809
|
+
if (isAnyKeyWritten(updateData, AI_ACCESS_RUNNER_KEYS)) {
|
|
1810
|
+
const runnerId: ObjectID | null = RelationIdUtil.readConsistent(
|
|
1811
|
+
updateData,
|
|
1812
|
+
AI_ACCESS_RUNNER_KEYS,
|
|
1813
|
+
"AI access Runner",
|
|
1814
|
+
);
|
|
1815
|
+
|
|
1816
|
+
if (
|
|
1817
|
+
!previous ||
|
|
1818
|
+
previous.aiAccessRunnerId !== (runnerId?.toString() || null)
|
|
1819
|
+
) {
|
|
1820
|
+
if (runnerId) {
|
|
1821
|
+
const runner: Runner | null = await RunnerService.findOneById({
|
|
1822
|
+
id: runnerId,
|
|
1823
|
+
select: { name: true },
|
|
1824
|
+
props: { isRoot: true },
|
|
1825
|
+
});
|
|
1826
|
+
|
|
1827
|
+
changes.push(
|
|
1828
|
+
`Runner **${runner?.name || runnerId.toString()}** bound to run kubectl`,
|
|
1829
|
+
);
|
|
1830
|
+
} else {
|
|
1831
|
+
changes.push("Runner cleared, so AI runs no kubectl on this cluster");
|
|
1832
|
+
}
|
|
1833
|
+
}
|
|
1834
|
+
}
|
|
1835
|
+
|
|
1836
|
+
if (isAnyKeyWritten(updateData, AI_ACCESS_CREDENTIAL_KEYS)) {
|
|
1837
|
+
const credentialId: ObjectID | null = RelationIdUtil.readConsistent(
|
|
1838
|
+
updateData,
|
|
1839
|
+
AI_ACCESS_CREDENTIAL_KEYS,
|
|
1840
|
+
"AI access credential",
|
|
1841
|
+
);
|
|
1842
|
+
|
|
1843
|
+
if (
|
|
1844
|
+
!previous ||
|
|
1845
|
+
previous.aiAccessCredentialId !== (credentialId?.toString() || null)
|
|
1846
|
+
) {
|
|
1847
|
+
changes.push(
|
|
1848
|
+
credentialId
|
|
1849
|
+
? previous?.aiAccessCredentialId
|
|
1850
|
+
? "Kubernetes credential changed"
|
|
1851
|
+
: "Kubernetes credential bound"
|
|
1852
|
+
: "Kubernetes credential cleared",
|
|
1853
|
+
);
|
|
1854
|
+
}
|
|
1855
|
+
}
|
|
1856
|
+
|
|
1857
|
+
return changes;
|
|
1858
|
+
}
|
|
1859
|
+
|
|
448
1860
|
private async writeKubernetesClusterUpdatedFeed(
|
|
449
1861
|
onUpdate: OnUpdate<Model>,
|
|
450
1862
|
updatedItemIds: Array<ObjectID>,
|
|
@@ -547,4 +1959,161 @@ function fingerprintLabelIds(labelIds: Array<ObjectID>): string {
|
|
|
547
1959
|
return crypto.createHash("sha1").update(sorted.join(",")).digest("hex");
|
|
548
1960
|
}
|
|
549
1961
|
|
|
1962
|
+
// Undefined is an omitted property; null is an explicit clear, so a write.
|
|
1963
|
+
function isAnyKeyWritten(data: JSONObject, keys: Array<string>): boolean {
|
|
1964
|
+
return keys.some((key: string) => {
|
|
1965
|
+
return data[key] !== undefined;
|
|
1966
|
+
});
|
|
1967
|
+
}
|
|
1968
|
+
|
|
1969
|
+
function getAiAccessWriteCarryForward(
|
|
1970
|
+
carryForward: unknown,
|
|
1971
|
+
): AiAccessWriteCarryForward | null {
|
|
1972
|
+
if (
|
|
1973
|
+
carryForward &&
|
|
1974
|
+
typeof carryForward === "object" &&
|
|
1975
|
+
"previousAiAccessSettings" in carryForward
|
|
1976
|
+
) {
|
|
1977
|
+
return carryForward as AiAccessWriteCarryForward;
|
|
1978
|
+
}
|
|
1979
|
+
|
|
1980
|
+
return null;
|
|
1981
|
+
}
|
|
1982
|
+
|
|
1983
|
+
// A stored mode as the readers see it: anything unknown is Disabled.
|
|
1984
|
+
function readStoredRemediationMode(
|
|
1985
|
+
value: unknown,
|
|
1986
|
+
): KubernetesAiRemediationMode {
|
|
1987
|
+
return Object.values(KubernetesAiRemediationMode).includes(
|
|
1988
|
+
value as KubernetesAiRemediationMode,
|
|
1989
|
+
)
|
|
1990
|
+
? (value as KubernetesAiRemediationMode)
|
|
1991
|
+
: KubernetesAiRemediationMode.Disabled;
|
|
1992
|
+
}
|
|
1993
|
+
|
|
1994
|
+
/*
|
|
1995
|
+
* A stored allowlist as the readers see it (KubernetesClusterAiAccessService
|
|
1996
|
+
* .normalizeAllowlist, which this module cannot import without a cycle):
|
|
1997
|
+
* trimmed non-empty strings, a JSON-encoded array accepted, anything else
|
|
1998
|
+
* empty. Rows written before the write-side validation existed may hold any
|
|
1999
|
+
* of those shapes.
|
|
2000
|
+
*/
|
|
2001
|
+
function readStoredKubectlAllowlist(value: unknown): Array<string> {
|
|
2002
|
+
let raw: unknown = value;
|
|
2003
|
+
|
|
2004
|
+
if (typeof raw === "string") {
|
|
2005
|
+
try {
|
|
2006
|
+
raw = JSON.parse(raw);
|
|
2007
|
+
} catch {
|
|
2008
|
+
raw = [value];
|
|
2009
|
+
}
|
|
2010
|
+
}
|
|
2011
|
+
|
|
2012
|
+
if (!Array.isArray(raw)) {
|
|
2013
|
+
return [];
|
|
2014
|
+
}
|
|
2015
|
+
|
|
2016
|
+
return raw
|
|
2017
|
+
.filter((pattern: unknown) => {
|
|
2018
|
+
return typeof pattern === "string" && pattern.trim().length > 0;
|
|
2019
|
+
})
|
|
2020
|
+
.map((pattern: string) => {
|
|
2021
|
+
return pattern.trim();
|
|
2022
|
+
});
|
|
2023
|
+
}
|
|
2024
|
+
|
|
2025
|
+
/*
|
|
2026
|
+
* What an operator's allowlist write stores: null (no allowlist) or an array
|
|
2027
|
+
* of trimmed patterns the matcher can actually use. Refused, with the entry
|
|
2028
|
+
* and the rule it broke:
|
|
2029
|
+
*
|
|
2030
|
+
* - anything but an array (a JSON-encoded array in a string is accepted, the
|
|
2031
|
+
* form the readers already understand, and stored as the array);
|
|
2032
|
+
* - an entry that is not text;
|
|
2033
|
+
* - more than KUBECTL_ALLOWLIST_MAX_PATTERNS entries — the matcher skips
|
|
2034
|
+
* every pattern past that silently;
|
|
2035
|
+
* - an entry KubectlPolicy.describeAllowlistPatternProblem says the matcher
|
|
2036
|
+
* cannot use (blank, too long, not one kubectl command line, no verb).
|
|
2037
|
+
* That is the ONE definition of a valid entry, shared with the AI page:
|
|
2038
|
+
* KubectlPolicy.matchesAllowlist compares word by word, `*` stands for
|
|
2039
|
+
* exactly one word, and the leading "kubectl" is optional.
|
|
2040
|
+
*/
|
|
2041
|
+
export function normalizeKubectlAllowlistForWrite(
|
|
2042
|
+
value: unknown,
|
|
2043
|
+
): Array<string> | null {
|
|
2044
|
+
let raw: unknown = value;
|
|
2045
|
+
|
|
2046
|
+
if (raw === null) {
|
|
2047
|
+
return null;
|
|
2048
|
+
}
|
|
2049
|
+
|
|
2050
|
+
if (typeof raw === "string") {
|
|
2051
|
+
if (raw.trim().length === 0) {
|
|
2052
|
+
return null;
|
|
2053
|
+
}
|
|
2054
|
+
|
|
2055
|
+
try {
|
|
2056
|
+
raw = JSON.parse(raw);
|
|
2057
|
+
} catch {
|
|
2058
|
+
throw new BadDataException(KUBECTL_ALLOWLIST_SHAPE_HINT);
|
|
2059
|
+
}
|
|
2060
|
+
}
|
|
2061
|
+
|
|
2062
|
+
if (!Array.isArray(raw)) {
|
|
2063
|
+
throw new BadDataException(KUBECTL_ALLOWLIST_SHAPE_HINT);
|
|
2064
|
+
}
|
|
2065
|
+
|
|
2066
|
+
if (raw.length > KUBECTL_ALLOWLIST_MAX_PATTERNS) {
|
|
2067
|
+
throw new BadDataException(
|
|
2068
|
+
`The kubectl allowlist can hold at most ${KUBECTL_ALLOWLIST_MAX_PATTERNS} patterns (got ${raw.length}).`,
|
|
2069
|
+
);
|
|
2070
|
+
}
|
|
2071
|
+
|
|
2072
|
+
return raw.map((entry: unknown, index: number): string => {
|
|
2073
|
+
const position: string = `Pattern ${index + 1} of the kubectl allowlist`;
|
|
2074
|
+
|
|
2075
|
+
if (typeof entry !== "string") {
|
|
2076
|
+
throw new BadDataException(
|
|
2077
|
+
`${position} must be text (got ${entry === null ? "null" : typeof entry}). ${KUBECTL_ALLOWLIST_SHAPE_HINT}`,
|
|
2078
|
+
);
|
|
2079
|
+
}
|
|
2080
|
+
|
|
2081
|
+
// Stored trimmed, so it is judged exactly as it will be read.
|
|
2082
|
+
const pattern: string = entry.trim();
|
|
2083
|
+
|
|
2084
|
+
const problem: string | null =
|
|
2085
|
+
KubectlPolicy.describeAllowlistPatternProblem(pattern);
|
|
2086
|
+
|
|
2087
|
+
if (problem) {
|
|
2088
|
+
throw new BadDataException(
|
|
2089
|
+
`${position} cannot be used: ${
|
|
2090
|
+
problem.endsWith(".") ? problem : `${problem}.`
|
|
2091
|
+
} Patterns are compared with the command word by word; * stands for exactly one word, and the leading "kubectl" is optional.`,
|
|
2092
|
+
);
|
|
2093
|
+
}
|
|
2094
|
+
|
|
2095
|
+
return pattern;
|
|
2096
|
+
});
|
|
2097
|
+
}
|
|
2098
|
+
|
|
2099
|
+
function isSameKubectlAllowlist(
|
|
2100
|
+
left: Array<string>,
|
|
2101
|
+
right: Array<string>,
|
|
2102
|
+
): boolean {
|
|
2103
|
+
return (
|
|
2104
|
+
left.length === right.length &&
|
|
2105
|
+
left.every((pattern: string, index: number) => {
|
|
2106
|
+
return pattern === right[index];
|
|
2107
|
+
})
|
|
2108
|
+
);
|
|
2109
|
+
}
|
|
2110
|
+
|
|
2111
|
+
function describePatternCount(count: number): string {
|
|
2112
|
+
if (count === 0) {
|
|
2113
|
+
return "none";
|
|
2114
|
+
}
|
|
2115
|
+
|
|
2116
|
+
return `${count} pattern${count === 1 ? "" : "s"}`;
|
|
2117
|
+
}
|
|
2118
|
+
|
|
550
2119
|
export default new Service();
|