@oneuptime/common 14.0.9 → 14.0.11
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/AIConversation.ts +127 -1
- package/Models/DatabaseModels/AutoRemediationSuggestion.ts +60 -0
- package/Models/DatabaseModels/CephCluster.ts +225 -0
- package/Models/DatabaseModels/CloudResource.ts +12 -0
- package/Models/DatabaseModels/DatabaseServer.ts +225 -0
- package/Models/DatabaseModels/DockerHost.ts +225 -0
- package/Models/DatabaseModels/DockerSwarmCluster.ts +225 -0
- package/Models/DatabaseModels/GlobalConfig.ts +1 -1
- package/Models/DatabaseModels/GlobalOidc.ts +0 -4
- package/Models/DatabaseModels/GlobalOidcProject.ts +0 -4
- package/Models/DatabaseModels/GlobalSso.ts +0 -4
- package/Models/DatabaseModels/GlobalSsoProject.ts +0 -4
- package/Models/DatabaseModels/Host.ts +225 -0
- package/Models/DatabaseModels/IncidentForm.ts +594 -0
- package/Models/DatabaseModels/IncidentFormSubmission.ts +283 -0
- package/Models/DatabaseModels/IncidentTemplate.ts +59 -0
- package/Models/DatabaseModels/Index.ts +16 -0
- package/Models/DatabaseModels/IoTFleet.ts +12 -0
- package/Models/DatabaseModels/KubernetesCluster.ts +12 -0
- package/Models/DatabaseModels/MessageQueue.ts +1102 -0
- package/Models/DatabaseModels/MessageQueueLabelRule.ts +553 -0
- package/Models/DatabaseModels/MessageQueueOwnerRule.ts +633 -0
- package/Models/DatabaseModels/MessageQueueOwnerTeam.ts +491 -0
- package/Models/DatabaseModels/MessageQueueOwnerUser.ts +490 -0
- package/Models/DatabaseModels/PodmanHost.ts +225 -0
- package/Models/DatabaseModels/Project.ts +59 -0
- package/Models/DatabaseModels/ProjectOidc.ts +0 -4
- package/Models/DatabaseModels/ProjectSso.ts +0 -4
- package/Models/DatabaseModels/ProxmoxCluster.ts +225 -0
- package/Models/DatabaseModels/ResourceAiAgent.ts +419 -0
- package/Models/DatabaseModels/RumApplication.ts +12 -0
- package/Models/DatabaseModels/RunnerJob.ts +144 -0
- package/Models/DatabaseModels/ServerlessFunction.ts +12 -0
- package/Models/DatabaseModels/Service.ts +12 -0
- package/Models/DatabaseModels/StatusPageOidc.ts +0 -4
- package/Models/DatabaseModels/StatusPageSso.ts +0 -4
- package/Models/DatabaseModels/TeamComplianceSetting.ts +47 -2
- package/Models/DatabaseModels/VMwareVCenter.ts +225 -0
- package/Server/API/AIChatAPI.ts +13 -114
- package/Server/API/AIInvestigationAPI.ts +3 -3
- package/Server/API/AIInvestigationConversationAPI.ts +266 -0
- package/Server/API/AutoRemediationAPI.ts +392 -1
- package/Server/API/IncidentFormAPI.ts +376 -0
- package/Server/API/ProjectOIDC.ts +16 -25
- package/Server/API/ProjectSSO.ts +16 -24
- package/Server/API/ResourceAiAccessAPI.ts +1669 -0
- package/Server/API/StatusPageAPI.ts +42 -77
- package/Server/Enterprise/EnterpriseEdition.ts +93 -28
- package/Server/Enterprise/EnterpriseFeature.ts +25 -3
- package/Server/Enterprise/EnterpriseLicenseSnapshot.ts +1 -1
- package/Server/Enterprise/EnterpriseServerModule.ts +4 -1
- package/Server/EnvironmentConfig.ts +1 -1
- package/Server/Infrastructure/Postgres/SchemaMigrations/1796300000000-AddResourceAiAgents.ts +423 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1796400000000-AddIncidentForms.ts +129 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1796500000000-AddTeamComplianceRuleNotificationChannels.ts +52 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1796600000000-AddAIInvestigationConversationAndTimeLimits.ts +75 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1796700000000-AddMessageQueueTables.ts +477 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +10 -0
- package/Server/Infrastructure/Semaphore.ts +22 -0
- package/Server/Middleware/IncidentFormRateLimit.ts +847 -0
- package/Server/Middleware/TelemetryIngest.ts +15 -5
- package/Server/Middleware/UserAuthorization.ts +16 -38
- package/Server/Services/AIService.ts +10 -13
- package/Server/Services/AnalyticsDatabaseService.ts +45 -1
- package/Server/Services/AutoRemediationRuleEngineService.ts +940 -112
- package/Server/Services/CephClusterService.ts +109 -1
- package/Server/Services/DatabaseServerService.ts +116 -1
- package/Server/Services/DockerHostService.ts +109 -1
- package/Server/Services/DockerSwarmClusterService.ts +113 -1
- package/Server/Services/HostService.ts +126 -4
- package/Server/Services/IncidentCustomFieldService.ts +112 -2
- package/Server/Services/IncidentEpisodeMemberService.ts +24 -4
- package/Server/Services/IncidentEpisodeService.ts +10 -1
- package/Server/Services/IncidentFormService.ts +1566 -0
- package/Server/Services/IncidentFormSubmissionService.ts +97 -0
- package/Server/Services/IncidentGroupingEngineService.ts +45 -8
- package/Server/Services/IncidentService.ts +123 -5
- package/Server/Services/IncidentTemplateService.ts +22 -0
- package/Server/Services/Index.ts +14 -0
- package/Server/Services/MessageQueueLabelRuleEngineService.ts +321 -0
- package/Server/Services/MessageQueueLabelRuleService.ts +14 -0
- package/Server/Services/MessageQueueOwnerRuleEngineService.ts +412 -0
- package/Server/Services/MessageQueueOwnerRuleService.ts +14 -0
- package/Server/Services/MessageQueueOwnerTeamService.ts +62 -0
- package/Server/Services/MessageQueueOwnerUserService.ts +62 -0
- package/Server/Services/MessageQueueService.ts +1463 -0
- package/Server/Services/MetricRecordingRuleService.ts +47 -0
- package/Server/Services/OpenTelemetryIngestService.ts +37 -4
- package/Server/Services/PodmanHostService.ts +109 -1
- package/Server/Services/ProjectService.ts +0 -59
- package/Server/Services/ProxmoxClusterService.ts +110 -1
- package/Server/Services/ResourceAiAccessService.ts +1439 -0
- package/Server/Services/ResourceAiAgentJobService.ts +202 -0
- package/Server/Services/ResourceAiAgentService.ts +2432 -0
- package/Server/Services/RunnerJobService.ts +611 -4
- package/Server/Services/StatusPagePrivateUserService.ts +1 -4
- package/Server/Services/StatusPageService.ts +1 -51
- package/Server/Services/TeamComplianceSettingService.ts +163 -42
- package/Server/Services/TelemetryUsageBillingService.ts +28 -0
- package/Server/Services/TraceRecordingRuleService.ts +33 -0
- package/Server/Services/UserNotificationRuleService.ts +8 -1
- package/Server/Services/VMwareVCenterService.ts +110 -1
- package/Server/Services/WorkspaceNotificationSummaryService.ts +12 -3
- package/Server/Types/Database/Permissions/CreatePermission.ts +17 -3
- package/Server/Types/Database/Permissions/EditionPermission.ts +140 -38
- package/Server/Types/Database/Permissions/OwnerTableRegistry.ts +16 -0
- package/Server/Types/Database/Permissions/TablePermission.ts +3 -3
- package/Server/Types/Database/Permissions/UpdatePermission.ts +20 -6
- package/Server/Utils/AI/Chat/AgentContextCompactor.ts +200 -0
- package/Server/Utils/AI/Chat/ChatAgentRunner.ts +307 -48
- package/Server/Utils/AI/Chat/ChatRunCancellation.ts +156 -0
- package/Server/Utils/AI/Chat/ObservabilityAssistant.ts +78 -18
- package/Server/Utils/AI/Chat/ObservabilityChatPrompt.ts +1 -1
- package/Server/Utils/AI/Chat/ToolOutputPager.ts +322 -0
- package/Server/Utils/AI/ClusterAccess/KubectlInvestigationToolkit.ts +88 -30
- package/Server/Utils/AI/ClusterAccess/KubectlJobRunner.ts +13 -1
- package/Server/Utils/AI/CodeFix/CodeFixReadiness.ts +0 -32
- package/Server/Utils/AI/CodeFix/FixRunBudget.ts +27 -25
- package/Server/Utils/AI/Remediation/RemediationCommandTools.ts +1442 -34
- package/Server/Utils/AI/Remediation/RemediationExecutionRunner.ts +968 -34
- package/Server/Utils/AI/Remediation/RemediationPlanRunner.ts +25 -1
- package/Server/Utils/AI/ResourceAccess/InfrastructureInvestigationToolkit.ts +622 -0
- package/Server/Utils/AI/ResourceAccess/ResourceAccessContext.ts +271 -0
- package/Server/Utils/AI/ResourceAccess/ResourceAccessToolNames.ts +45 -0
- package/Server/Utils/AI/ResourceAccess/ResourceAiAccessSettings.ts +964 -0
- package/Server/Utils/AI/ResourceAccess/ResourceAiDeleteCleanup.ts +333 -0
- package/Server/Utils/AI/ResourceAccess/ResourceCommandJobRunner.ts +882 -0
- package/Server/Utils/AI/SRE/AIInvestigationEngine.ts +125 -12
- package/Server/Utils/AI/SRE/AlertInvestigationRunner.ts +99 -15
- package/Server/Utils/AI/SRE/IncidentInvestigationRunner.ts +99 -15
- package/Server/Utils/AI/SRE/InvestigationQueue.ts +16 -19
- package/Server/Utils/AI/SRE/InvestigationThread.ts +646 -0
- package/Server/Utils/AI/SRE/InvestigationThreadService.ts +715 -0
- package/Server/Utils/AI/Toolbox/Serializer.ts +10 -3
- package/Server/Utils/AutoRemediation/CommandPlanExecutor.ts +396 -13
- package/Server/Utils/AutoRemediation/RemediationVerifier.ts +35 -2
- package/Server/Utils/Database/ProjectScopedReferenceValidator.ts +9 -1
- package/Server/Utils/EditionEnforcement.ts +19 -202
- package/Server/Utils/LLM/LLMService.ts +259 -63
- package/Server/Utils/RelaxedScimTeamLocksReport.ts +245 -0
- package/Server/Utils/Rules/RuleRun/RuleRunRegistry.ts +25 -0
- package/Server/Utils/SameOriginRequest.ts +203 -0
- package/Server/Utils/SessionReplay/SessionReplayBudgetMetrics.ts +920 -0
- package/Server/Utils/SessionReplay/SessionReplayUsage.ts +84 -6
- package/Server/Utils/TeamMember/ProjectLeaveResourceCleanup.ts +2 -0
- package/Server/Utils/Telemetry/EntityRegistry.ts +4 -1
- package/Server/Utils/Telemetry/MessageQueueDiscovery.ts +1402 -0
- package/Server/Utils/Telemetry/ResourceEntityFilter.ts +4 -1
- package/Server/Utils/VendorAssets.ts +3 -3
- package/Server/Utils/Workspace/MicrosoftTeams/Actions/Alert.ts +35 -15
- package/Server/Utils/Workspace/MicrosoftTeams/Actions/AlertEpisode.ts +33 -15
- package/Server/Utils/Workspace/MicrosoftTeams/Actions/Auth.ts +21 -1
- package/Server/Utils/Workspace/MicrosoftTeams/Actions/Incident.ts +301 -225
- package/Server/Utils/Workspace/MicrosoftTeams/Actions/IncidentEpisode.ts +38 -16
- package/Server/Utils/Workspace/MicrosoftTeams/Actions/ScheduledMaintenance.ts +389 -175
- package/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.ts +376 -144
- package/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsActivityDeduplicator.ts +163 -0
- package/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsCardChoices.ts +396 -0
- package/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsCreateCommands.ts +418 -0
- package/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsMessageSize.ts +152 -0
- package/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsReplies.ts +251 -0
- package/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsTimezone.ts +214 -0
- package/Tests/App/Accounts/IncidentFormPage.test.tsx +2036 -0
- package/Tests/App/Accounts/IncidentFormServerMessages.test.ts +119 -0
- package/Tests/App/Accounts/IncidentFormUtils.test.ts +1157 -0
- package/Tests/App/Accounts/LoginPasskey.test.tsx +6 -4
- package/Tests/App/Accounts/LoginSso.test.tsx +724 -0
- package/Tests/App/AdminDashboard/AdminAuthenticationRequireSso.test.tsx +338 -0
- package/Tests/App/AdminDashboard/AdminAuthenticationSsoCardLocales.test.tsx +331 -0
- package/Tests/App/AdminDashboard/AdminEnterprisePluginPage.test.tsx +47 -33
- package/Tests/App/AdminDashboard/GlobalSsoOidcPages.test.tsx +1021 -0
- package/Tests/App/Dashboard/AffectedResourcesDisplay.test.tsx +876 -78
- package/Tests/App/Dashboard/AffectedResourcesSlo.test.tsx +20 -3
- package/Tests/App/Dashboard/CephProxmoxVMwareDocumentationCards.test.tsx +359 -0
- package/Tests/App/Dashboard/CephSetupGuide.test.ts +961 -0
- package/Tests/App/Dashboard/CloudDocumentationCard.test.tsx +381 -95
- package/Tests/App/Dashboard/CloudSetupGuide.test.ts +1463 -0
- package/Tests/App/Dashboard/ClusterAccessNotice.test.tsx +267 -12
- package/Tests/App/Dashboard/ContainerSetupGuideCards.test.tsx +345 -0
- package/Tests/App/Dashboard/CoreListEmptyStates.test.tsx +501 -0
- package/Tests/App/Dashboard/DashboardLazyPages.test.tsx +0 -1
- package/Tests/App/Dashboard/DatabaseDocumentationCard.test.tsx +400 -0
- package/Tests/App/Dashboard/DatabaseDocumentationMarkdown.test.ts +23 -6
- package/Tests/App/Dashboard/DatabaseSetupGuide.test.ts +1869 -0
- package/Tests/App/Dashboard/DatabaseTelemetryScope.test.ts +44 -0
- package/Tests/App/Dashboard/DatabaseTelemetryTabs.test.tsx +50 -9
- package/Tests/App/Dashboard/DockerSetupGuide.test.ts +899 -0
- package/Tests/App/Dashboard/DockerSwarmSetupGuide.test.ts +964 -0
- package/Tests/App/Dashboard/EnterpriseFeatureUpgrade.test.tsx +141 -7
- package/Tests/App/Dashboard/EnterprisePluginPage.test.tsx +52 -39
- package/Tests/App/Dashboard/EventOverviewPages.test.tsx +7 -1
- package/Tests/App/Dashboard/GettingStartedTaskRoutes.test.tsx +331 -0
- package/Tests/App/Dashboard/HomeOverviewStatsFirstRun.test.tsx +925 -0
- package/Tests/App/Dashboard/HostDocumentationCard.test.tsx +225 -0
- package/Tests/App/Dashboard/HostSetupGuide.test.ts +1183 -0
- package/Tests/App/Dashboard/IdentityEnterpriseShells.test.tsx +69 -45
- package/Tests/App/Dashboard/IncidentCreateTemplateCustomFieldSettings.test.tsx +745 -0
- package/Tests/App/Dashboard/IncidentCreateTemplateOwners.test.tsx +414 -0
- package/Tests/App/Dashboard/IncidentCustomFieldCreateSettingsForm.test.ts +1042 -0
- package/Tests/App/Dashboard/IncidentCustomFieldSettingsCard.test.tsx +1816 -0
- package/Tests/App/Dashboard/IncidentFormPlan.test.ts +89 -0
- package/Tests/App/Dashboard/IncidentFormShareLinkCard.test.tsx +846 -0
- package/Tests/App/Dashboard/IncidentFormsPages.test.tsx +1324 -0
- package/Tests/App/Dashboard/IncidentTemplateCustomFieldSettings.test.tsx +630 -0
- package/Tests/App/Dashboard/IncidentsSideMenu.test.tsx +13 -0
- package/Tests/App/Dashboard/IncomingEmailMonitorLinkVerifyHint.test.tsx +104 -0
- package/Tests/App/Dashboard/InvestigationConversation.test.tsx +1107 -0
- package/Tests/App/Dashboard/InvestigationConversationData.test.ts +546 -0
- package/Tests/App/Dashboard/InvestigationEvidenceList.test.tsx +170 -5
- package/Tests/App/Dashboard/InvestigationInfrastructureTools.test.tsx +506 -0
- package/Tests/App/Dashboard/InvestigationNotStarted.test.tsx +207 -2
- package/Tests/App/Dashboard/InvestigationPanel.test.tsx +729 -34
- package/Tests/App/Dashboard/InvestigationPanelStatus.test.tsx +9 -21
- package/Tests/App/Dashboard/InvestigationReportView.test.tsx +274 -37
- package/Tests/App/Dashboard/InvestigationStatusBadge.test.tsx +130 -0
- package/Tests/App/Dashboard/IoTDocumentationCard.test.tsx +218 -0
- package/Tests/App/Dashboard/IoTSetupGuide.test.ts +1124 -0
- package/Tests/App/Dashboard/KubernetesClusterAiAccessSettings.test.ts +20 -6
- package/Tests/App/Dashboard/KubernetesClusterAiDocumentationMarkdown.test.ts +107 -83
- package/Tests/App/Dashboard/KubernetesSetupGuide.test.ts +787 -0
- package/Tests/App/Dashboard/MessageQueueBreadcrumbs.test.tsx +228 -0
- package/Tests/App/Dashboard/MessageQueueBrokerHealth.test.tsx +1538 -0
- package/Tests/App/Dashboard/MessageQueueBrokerHealthMetricChart.test.tsx +969 -0
- package/Tests/App/Dashboard/MessageQueueBrokerHealthReads.test.ts +889 -0
- package/Tests/App/Dashboard/MessageQueueBrokerMetricsReach.test.ts +236 -0
- package/Tests/App/Dashboard/MessageQueueDocumentationCard.test.tsx +479 -0
- package/Tests/App/Dashboard/MessageQueueListPages.test.tsx +1232 -0
- package/Tests/App/Dashboard/MessageQueueMetricDescriptions.test.ts +244 -0
- package/Tests/App/Dashboard/MessageQueueMonitorLink.test.ts +952 -0
- package/Tests/App/Dashboard/MessageQueueMonitorLinkMonitorCreate.test.tsx +859 -0
- package/Tests/App/Dashboard/MessageQueueOverview.test.tsx +1773 -0
- package/Tests/App/Dashboard/MessageQueueOverviewPresentation.test.ts +196 -0
- package/Tests/App/Dashboard/MessageQueuePresentation.test.ts +799 -0
- package/Tests/App/Dashboard/MessageQueueProducersConsumers.test.tsx +680 -0
- package/Tests/App/Dashboard/MessageQueueRoutes.test.tsx +383 -0
- package/Tests/App/Dashboard/MessageQueueRulePages.test.tsx +278 -0
- package/Tests/App/Dashboard/MessageQueueSetupGuide.test.ts +2778 -0
- package/Tests/App/Dashboard/MessageQueueSideMenus.test.tsx +273 -0
- package/Tests/App/Dashboard/MessageQueueSpanPopulations.test.ts +930 -0
- package/Tests/App/Dashboard/MessageQueueSpanStore.ts +351 -0
- package/Tests/App/Dashboard/MessageQueueTelemetryScope.test.ts +375 -0
- package/Tests/App/Dashboard/MessageQueueTelemetryScopeTabs.test.tsx +668 -0
- package/Tests/App/Dashboard/MessageQueueViewPages.test.tsx +685 -0
- package/Tests/App/Dashboard/MonitorAndHomeNotOperationalMenus.test.tsx +342 -0
- package/Tests/App/Dashboard/MonitorCreateFirstRunDefaults.test.tsx +623 -0
- package/Tests/App/Dashboard/MonitorCreateFromMonitorBackedDevice.test.tsx +442 -0
- package/Tests/App/Dashboard/MonitorLogsPageViewSummary.test.tsx +814 -0
- package/Tests/App/Dashboard/MonitorSetupCardBodies.test.tsx +246 -0
- package/Tests/App/Dashboard/NavigationSearchKeywords.test.tsx +8 -0
- package/Tests/App/Dashboard/OnboardingSsoEmptyState.test.tsx +27 -12
- package/Tests/App/Dashboard/PlanGatedPage.test.tsx +292 -0
- package/Tests/App/Dashboard/PodmanSetupGuide.test.ts +948 -0
- package/Tests/App/Dashboard/ProductOrientation.test.tsx +5 -4
- package/Tests/App/Dashboard/ProductSettingsSectionCollapsed.test.tsx +266 -0
- package/Tests/App/Dashboard/ProxmoxSetupGuide.test.ts +1318 -0
- package/Tests/App/Dashboard/RemediationSuggestionCardDescription.test.tsx +209 -0
- package/Tests/App/Dashboard/RemediationSuggestionCardResource.test.tsx +317 -0
- package/Tests/App/Dashboard/ResourceAiAccessSettingsUtil.test.ts +921 -0
- package/Tests/App/Dashboard/ResourceAiAgentAttentionServerParity.test.ts +555 -0
- package/Tests/App/Dashboard/ResourceAiAgentInstall.test.ts +860 -0
- package/Tests/App/Dashboard/ResourceAiAgentPage.test.tsx +2010 -0
- package/Tests/App/Dashboard/ResourceAiAgentStatus.test.ts +1455 -0
- package/Tests/App/Dashboard/ResourceAiInsightsPage.test.tsx +931 -0
- package/Tests/App/Dashboard/ResourceAiNavigation.test.tsx +575 -0
- package/Tests/App/Dashboard/ResourceArchiveSettings.test.tsx +16 -0
- package/Tests/App/Dashboard/ResourceConnectionGuideCard.test.tsx +444 -0
- package/Tests/App/Dashboard/ResourceConnectionGuideOverviewsInfra.test.tsx +798 -0
- package/Tests/App/Dashboard/ResourceConnectionGuideOverviewsPlatforms.test.tsx +717 -0
- package/Tests/App/Dashboard/ResourceConnectionGuides.test.ts +981 -0
- package/Tests/App/Dashboard/ResourceConnectionState.test.ts +132 -0
- package/Tests/App/Dashboard/RumDocumentationCard.test.tsx +293 -0
- package/Tests/App/Dashboard/RumSessionReplayRetentionSettings.test.tsx +467 -0
- package/Tests/App/Dashboard/RumSetupGuide.test.ts +758 -0
- package/Tests/App/Dashboard/RunbookStepTypeMaps.test.ts +38 -7
- package/Tests/App/Dashboard/ScheduledMaintenanceOverviewPage.test.tsx +25 -0
- package/Tests/App/Dashboard/ServerlessDocumentationCard.test.tsx +254 -0
- package/Tests/App/Dashboard/ServerlessSetupGuide.test.ts +1074 -0
- package/Tests/App/Dashboard/SetupGuide.test.ts +246 -0
- package/Tests/App/Dashboard/SetupGuideCard.test.tsx +756 -0
- package/Tests/App/Dashboard/SloListSideMenu.test.tsx +120 -0
- package/Tests/App/Dashboard/SsoPages.test.tsx +833 -0
- package/Tests/App/Dashboard/TelemetryDocumentation.test.tsx +253 -0
- package/Tests/App/Dashboard/TelemetryRetentionShells.test.tsx +730 -0
- package/Tests/App/Dashboard/VMwareSetupGuide.test.ts +1033 -0
- package/Tests/App/StatusPage/StatusPageSsoEmptyState.test.tsx +87 -7
- package/Tests/Models/DatabaseModels/DatabaseServerModels.test.ts +61 -10
- package/Tests/Models/DatabaseModels/IncidentFormModel.test.ts +1250 -0
- package/Tests/Models/DatabaseModels/MessageQueueModels.test.ts +1983 -0
- package/Tests/Models/DatabaseModels/ResourceAiAccessColumns.test.ts +738 -0
- package/Tests/Models/DatabaseModels/ResourceAiAgentModel.test.ts +842 -0
- package/Tests/Models/DatabaseModels/StaticRuleCriteriaInheritance.test.ts +4 -2
- package/Tests/Models/DatabaseModels/TeamComplianceSettingModel.test.ts +190 -14
- package/Tests/Models/IncidentTemplateCustomFieldSettingsColumn.test.ts +291 -0
- package/Tests/Server/API/AIInvestigationConversationAPI.test.ts +412 -0
- package/Tests/Server/API/AutoRemediationApproveResourceRound.test.ts +835 -0
- package/Tests/Server/API/GlobalConfigLicense.test.ts +38 -9
- package/Tests/Server/API/IncidentFormAPI.test.ts +942 -0
- package/Tests/Server/API/IncidentFormPublicRoutes.test.ts +1653 -0
- package/Tests/Server/API/KubernetesClusterAiAccessAPI.test.ts +2 -1
- package/Tests/Server/API/ResourceAiAccessAPI.test.ts +2730 -0
- package/Tests/Server/API/{SsoProviderListingsEdition.test.ts → SsoProviderListings.test.ts} +164 -110
- package/Tests/Server/Enterprise/EnterpriseEdition.test.ts +76 -54
- package/Tests/Server/Enterprise/EnterpriseFeatureActive.test.ts +125 -42
- package/Tests/Server/Enterprise/EnterpriseLicenseSnapshot.test.ts +36 -10
- package/Tests/Server/Enterprise/EnterpriseModelFeatureMap.test.ts +51 -9
- package/Tests/Server/Enterprise/FakeEnterpriseModule.ts +13 -8
- package/Tests/Server/Enterprise/SsoInCommunityEdition.test.ts +540 -0
- package/Tests/Server/Infrastructure/Postgres/AddConfigurableRuleCriteriaMigration.test.ts +3 -0
- package/Tests/Server/Infrastructure/Postgres/AddDatabaseServerTablesMigration.test.ts +60 -0
- package/Tests/Server/Infrastructure/Postgres/AddIncidentFormsMigration.test.ts +438 -0
- package/Tests/Server/Infrastructure/Postgres/AddResourceAiAgentsMigration.test.ts +659 -0
- package/Tests/Server/Infrastructure/Postgres/AddTeamComplianceRuleNotificationChannelsMigration.test.ts +255 -0
- package/Tests/Server/Infrastructure/Postgres/MessageQueueTablesMigration.test.ts +637 -0
- package/Tests/Server/Infrastructure/SemaphoreMutex.test.ts +31 -0
- package/Tests/Server/Middleware/IncidentFormRateLimit.test.ts +1630 -0
- package/Tests/Server/Middleware/TelemetryIngestBrowserKey.test.ts +63 -5
- package/Tests/Server/Middleware/TelemetryIngestKubernetesAgentRunnerPinnedKey.test.ts +103 -5
- package/Tests/Server/Middleware/TelemetryIngestKubernetesAgentRunnerRateLimit.test.ts +19 -1
- package/Tests/Server/Middleware/UserAuthorization.test.ts +16 -17
- package/Tests/Server/Middleware/UserAuthorizationSsoEnforcement.test.ts +544 -0
- package/Tests/Server/Services/AIServiceDailyBudget.test.ts +37 -8
- package/Tests/Server/Services/AutoRemediationResourceRuleEngine.test.ts +1279 -0
- package/Tests/Server/Services/DatabaseServerService.test.ts +55 -0
- package/Tests/Server/Services/GroupTelemetryUsageExcludeNames.test.ts +299 -0
- package/Tests/Server/Services/HostServiceFindOrCreateMemo.test.ts +44 -0
- package/Tests/Server/Services/IncidentCreatedFeedTitle.test.ts +212 -0
- package/Tests/Server/Services/IncidentCustomFieldDeleteFormQuestions.test.ts +297 -0
- package/Tests/Server/Services/IncidentFormOwnersCreatedNotification.test.ts +497 -0
- package/Tests/Server/Services/IncidentFormPostgres.test.ts +958 -0
- package/Tests/Server/Services/IncidentFormPublicForm.test.ts +1260 -0
- package/Tests/Server/Services/IncidentFormPublicSubmission.test.ts +2520 -0
- package/Tests/Server/Services/IncidentFormRegistration.test.ts +159 -0
- package/Tests/Server/Services/IncidentFormService.test.ts +663 -0
- package/Tests/Server/Services/IncidentFormSubmissionService.test.ts +430 -0
- package/Tests/Server/Services/IncidentFormSubmissionTemplateBranch.test.ts +473 -0
- package/Tests/Server/Services/IncidentGroupingTemplateSubstitution.test.ts +81 -0
- package/Tests/Server/Services/IncidentTemplateCustomFieldSettings.test.ts +262 -0
- package/Tests/Server/Services/IncidentTemplateOwnersOnDeclare.test.ts +566 -0
- package/Tests/Server/Services/IncidentTitleMarkdownSinks.test.ts +640 -0
- package/Tests/Server/Services/LlmLogServiceTokenAggregateParams.test.ts +3 -3
- package/Tests/Server/Services/MessageQueueOwnerServices.test.ts +440 -0
- package/Tests/Server/Services/MessageQueueRegistries.test.ts +577 -0
- package/Tests/Server/Services/MessageQueueRuleEngines.test.ts +900 -0
- package/Tests/Server/Services/MessageQueueService.test.ts +2210 -0
- package/Tests/Server/Services/MessageQueueSqlPostgres.test.ts +1271 -0
- package/Tests/Server/Services/MonitorProbeServiceIntervalScheduling.test.ts +45 -6
- package/Tests/Server/Services/OpenTelemetryResourceRetentionMemo.test.ts +28 -1
- package/Tests/Server/Services/OpenTelemetryRetentionOverrideEdition.test.ts +474 -0
- package/Tests/Server/Services/OpenTelemetryServiceResolutionCache.test.ts +21 -0
- package/Tests/Server/Services/OwnerRowUniqueness.test.ts +3 -0
- package/Tests/Server/Services/ProjectServiceAuditLogLicense.test.ts +0 -1
- package/Tests/Server/Services/RecordingRuleReservedMetricName.test.ts +171 -0
- package/Tests/Server/Services/ResourceAiAccessChangeAuthorization.test.ts +256 -0
- package/Tests/Server/Services/ResourceAiAccessService.test.ts +1373 -0
- package/Tests/Server/Services/ResourceAiAgentJobService.test.ts +375 -0
- package/Tests/Server/Services/ResourceAiAgentServiceHelpers.test.ts +1114 -0
- package/Tests/Server/Services/ResourceAiAgentServiceLifecycle.test.ts +1050 -0
- package/Tests/Server/Services/ResourceAiAgentServiceRegister.test.ts +2251 -0
- package/Tests/Server/Services/ResourceAiSettingsCreate.test.ts +373 -0
- package/Tests/Server/Services/ResourceAiSettingsPermission.test.ts +1042 -0
- package/Tests/Server/Services/ResourceServiceDeleteCleansUpAi.test.ts +319 -0
- package/Tests/Server/Services/RuleRun/LabelRuleEnginesGroupBRun.test.ts +56 -6
- package/Tests/Server/Services/RuleRun/OwnerRuleEnginesGroupBRun.test.ts +30 -1
- package/Tests/Server/Services/RunnerJobEnqueueKubectl.test.ts +105 -0
- package/Tests/Server/Services/RunnerJobEnqueueResourceCommand.test.ts +986 -0
- package/Tests/Server/Services/RunnerJobResourceCommandLane.test.ts +211 -0
- package/Tests/Server/Services/RunnerJobResourceCommandTimeoutAndRedaction.test.ts +352 -0
- package/Tests/Server/Services/SsoRequirementReads.test.ts +454 -0
- package/Tests/Server/Services/SsoRequirementWrites.test.ts +529 -0
- package/Tests/Server/Services/StaticRuleCriteriaRuntimeCoverage.test.ts +3 -3
- package/Tests/Server/Services/StatusPagePrivateUserInvitationPolicy.test.ts +107 -89
- package/Tests/Server/Services/TeamComplianceSettingPostgres.test.ts +1068 -176
- package/Tests/Server/Services/TeamComplianceSettingService.test.ts +1962 -200
- package/Tests/Server/Services/TelemetryUsageBillingSloExclusion.test.ts +218 -0
- package/Tests/Server/TestingUtils/Services/FakeRunnerJobCount.ts +145 -0
- package/Tests/Server/Types/Database/Permissions/EditionPermission.test.ts +654 -297
- package/Tests/Server/Types/Database/Permissions/RetentionOverrideColumns.test.ts +784 -0
- package/Tests/Server/Types/Database/Permissions/SsoScalePlanGate.test.ts +418 -0
- package/Tests/Server/Utils/AI/AIAlertGating.test.ts +0 -1
- package/Tests/Server/Utils/AI/AIInvestigationEngineRunLimits.test.ts +136 -0
- package/Tests/Server/Utils/AI/AIInvestigationQueue.test.ts +15 -14
- package/Tests/Server/Utils/AI/AgentContextCompactor.test.ts +351 -0
- package/Tests/Server/Utils/AI/ChatAgentRunnerSharedThread.test.ts +842 -0
- package/Tests/Server/Utils/AI/ChatRunCancellation.test.ts +195 -0
- package/Tests/Server/Utils/AI/CodeFixReadiness.test.ts +10 -57
- package/Tests/Server/Utils/AI/FixRunBudget.test.ts +20 -24
- package/Tests/Server/Utils/AI/Insights/InvestigationQueueInsightSubject.test.ts +7 -30
- package/Tests/Server/Utils/AI/InvestigationClusterAccessWiring.test.ts +225 -29
- package/Tests/Server/Utils/AI/InvestigationInfrastructureAccessWiring.test.ts +694 -0
- package/Tests/Server/Utils/AI/InvestigationInfrastructureReport.test.ts +721 -0
- package/Tests/Server/Utils/AI/InvestigationThread.test.ts +580 -0
- package/Tests/Server/Utils/AI/InvestigationThreadService.test.ts +801 -0
- package/Tests/Server/Utils/AI/KubectlInvestigationToolkit.test.ts +525 -43
- package/Tests/Server/Utils/AI/KubectlJobRunner.test.ts +4 -2
- package/Tests/Server/Utils/AI/LLMServiceUnreachableProvider.test.ts +435 -0
- package/Tests/Server/Utils/AI/ObservabilityAssistantLimits.test.ts +462 -0
- package/Tests/Server/Utils/AI/RemediationCommandTools.test.ts +94 -1
- package/Tests/Server/Utils/AI/RemediationCommandToolsResource.test.ts +1530 -0
- package/Tests/Server/Utils/AI/RemediationExecutionRunner.test.ts +14 -25
- package/Tests/Server/Utils/AI/RemediationExecutionRunnerResourceMode.test.ts +1251 -0
- package/Tests/Server/Utils/AI/RemediationPlanRunner.test.ts +117 -0
- package/Tests/Server/Utils/AI/RemediationResourceCopyParity.test.ts +463 -0
- package/Tests/Server/Utils/AI/ResourceAccess/InfrastructureInvestigationToolkit.test.ts +1004 -0
- package/Tests/Server/Utils/AI/ResourceAccess/ResourceAccessContext.test.ts +266 -0
- package/Tests/Server/Utils/AI/ResourceAccess/ResourceAiAccessSettings.test.ts +1220 -0
- package/Tests/Server/Utils/AI/ResourceAccess/ResourceAiDeleteCleanup.test.ts +569 -0
- package/Tests/Server/Utils/AI/ResourceAccess/ResourceCommandJobRunner.test.ts +834 -0
- package/Tests/Server/Utils/AI/ToolOutputPager.test.ts +382 -0
- package/Tests/Server/Utils/AI/ToolResultSerializer.test.ts +23 -4
- package/Tests/Server/Utils/AI/Toolbox/LogTools.test.ts +25 -6
- package/Tests/Server/Utils/AI/Toolbox/Serializer.test.ts +14 -3
- package/Tests/Server/Utils/AutoRemediation/CommandPlanExecutorResource.test.ts +717 -0
- package/Tests/Server/Utils/AutoRemediation/RemediationVerifierResourceFollowUp.test.ts +338 -0
- package/Tests/Server/Utils/EditionEnforcement.test.ts +107 -147
- package/Tests/Server/Utils/Monitor/Criteria/SessionReplayBudgetTemplateCriteria.test.ts +422 -0
- package/Tests/Server/Utils/{CommunityEditionSsoReport.test.ts → RelaxedScimTeamLocksReport.test.ts} +212 -208
- package/Tests/Server/Utils/SameOriginRequest.test.ts +372 -0
- package/Tests/Server/Utils/SessionReplay/SessionReplayBudgetMetrics.test.ts +1647 -0
- package/Tests/Server/Utils/SessionReplay/SessionReplayUsage.test.ts +143 -1
- package/Tests/Server/Utils/Telemetry/EntityRegistry.test.ts +20 -0
- package/Tests/Server/Utils/Telemetry/MessageQueueDiscovery.test.ts +2590 -0
- package/Tests/Server/Utils/Telemetry/MessageQueueSpanQueryTwin.ts +246 -0
- package/Tests/Server/Utils/Telemetry/TelemetryEntity.test.ts +23 -0
- package/Tests/Server/Utils/Telemetry/TelemetryIngestionKeyGuard.test.ts +33 -3
- package/Tests/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsAccountNotLinked.test.ts +1093 -0
- package/Tests/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsActivityDeduplicator.test.ts +1049 -0
- package/Tests/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsCardChoices.test.ts +1676 -0
- package/Tests/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsCreateCards.test.ts +2884 -0
- package/Tests/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsCreateCommands.test.ts +2490 -0
- package/Tests/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsCreateSubmit.test.ts +2293 -0
- package/Tests/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsCreateSubmitServerTimezone.test.ts +386 -0
- package/Tests/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsMessageSize.test.ts +1477 -0
- package/Tests/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsReplies.test.ts +1967 -0
- package/Tests/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsStripHtmlTags.test.ts +92 -0
- package/Tests/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsSubmittedFormRemoval.test.ts +1819 -0
- package/Tests/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsTimezone.test.ts +1033 -0
- package/Tests/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsTimezoneServerZone.test.ts +610 -0
- package/Tests/Server/Utils/Workspace/MicrosoftTeamsBotMessageHandling.test.ts +2610 -0
- package/Tests/Server/Utils/Workspace/MicrosoftTeamsCreateCommandsEndToEnd.test.ts +4672 -0
- package/Tests/Server/Utils/Workspace/WorkspaceCreateProjectReferences.test.ts +190 -65
- package/Tests/Types/AI/AIAgentRunLimits.test.ts +255 -0
- package/Tests/Types/AutoRemediation/AiRemediationCommandPlan.test.ts +10 -4
- package/Tests/Types/AutoRemediation/AiRemediationCommandPlanResourceCommand.test.ts +305 -0
- package/Tests/Types/Code/JsonSyntax.test.ts +1300 -0
- package/Tests/Types/CustomField/CustomFieldCreateSettings.test.ts +1113 -0
- package/Tests/Types/CustomField/CustomFieldMappingCatalog.test.ts +91 -0
- package/Tests/Types/CustomField/CustomFieldValueValidator.test.ts +30 -0
- package/Tests/Types/Incident/IncidentFormIpAllowlist.test.ts +227 -0
- package/Tests/Types/Incident/IncidentFormPublic.test.ts +1916 -0
- package/Tests/Types/MessageQueue/MessageQueueEntityKey.test.ts +916 -0
- package/Tests/Types/MessageQueue/MessageQueueIdentity.test.ts +567 -0
- package/Tests/Types/MessageQueue/MessageQueueManualIdentity.test.ts +686 -0
- package/Tests/Types/MessageQueue/MessageQueueMetricCatalog.test.ts +1726 -0
- package/Tests/Types/MessageQueue/MessageQueueMetricResolution.test.ts +1758 -0
- package/Tests/Types/MessageQueue/MessagingInstrumentationFixtures.test.ts +4686 -0
- package/Tests/Types/MessageQueue/MessagingSystem.test.ts +840 -0
- package/Tests/Types/MessageQueue/MessagingTelemetryFixtures.ts +3287 -0
- package/Tests/Types/MessageQueue/MessagingTelemetryResolver.test.ts +2966 -0
- package/Tests/Types/Monitor/MessageQueueAlertTemplates.test.ts +5401 -0
- package/Tests/Types/Monitor/MetricEngineFold.ts +154 -0
- package/Tests/Types/Monitor/Recommendation/MonitorRecommendationCatalog.test.ts +277 -13
- package/Tests/Types/Monitor/Recommendation/MonitorRecommendationUtil.test.ts +113 -0
- package/Tests/Types/Monitor/RumAlertTemplates.test.ts +773 -2
- package/Tests/Types/ResourceAiAgent/AiResourceType.test.ts +419 -0
- package/Tests/Types/ResourceAiAgent/ResourceAiAccess.test.ts +519 -0
- package/Tests/Types/Runbook/RunbookStepType.test.ts +147 -8
- package/Tests/Types/Team/ComplianceRule.test.ts +588 -37
- package/Tests/Types/Team/TeamComplianceStatus.test.ts +64 -11
- package/Tests/Types/XML.test.ts +51 -0
- package/Tests/UI/Components/CodeEditor/CodeEditor.test.tsx +2362 -0
- package/Tests/UI/Components/CodeEditor/CodeEditorCommands.test.ts +810 -0
- package/Tests/UI/Components/CodeEditor/CodeEditorHighlight.test.ts +338 -0
- package/Tests/UI/Components/CodeEditor/CodeEditorLanguages.test.ts +222 -0
- package/Tests/UI/Components/CodeEditor/CodeEditorStyles.test.ts +807 -0
- package/Tests/UI/Components/CodeEditor/NoMonaco.test.ts +245 -0
- package/Tests/UI/Components/CodeEditor/YamlEditor.test.tsx +729 -0
- package/Tests/UI/Components/CopyTextButton.test.tsx +76 -0
- package/Tests/UI/Components/EditionLabelLapseCopy.ts +51 -14
- package/Tests/UI/Components/EditionLabelLicenseStatus.test.tsx +131 -23
- package/Tests/UI/Components/ErrorMessageAction.test.tsx +142 -0
- package/Tests/UI/Components/FacetSidebarInScope.test.tsx +459 -0
- package/Tests/UI/Components/FacetValuesInScope.test.ts +270 -0
- package/Tests/UI/Components/Forms/FormFieldCodeEditors.test.tsx +294 -0
- package/Tests/UI/Components/Forms/FormFieldMarkdown.test.tsx +126 -0
- package/Tests/UI/Components/Forms/FormFieldYaml.test.tsx +22 -75
- package/Tests/UI/Components/Forms/ModelFormOnBeforeCreateMiscData.test.tsx +254 -0
- package/Tests/UI/Components/Icon.test.tsx +32 -0
- package/Tests/UI/Components/Input.test.tsx +31 -0
- package/Tests/UI/Components/LockedFilterChipScope.test.tsx +501 -0
- package/Tests/UI/Components/MarkdownConverters.test.ts +253 -1
- package/Tests/UI/Components/MarkdownEditor.test.tsx +2785 -2
- package/Tests/UI/Components/MarkdownEditorHistory.test.ts +243 -0
- package/Tests/UI/Components/MarkdownListEditing.test.ts +1118 -0
- package/Tests/UI/Components/MarkdownPaste.test.ts +1180 -0
- package/Tests/UI/Components/MarkdownViewerCopy.test.tsx +466 -0
- package/Tests/UI/Components/MarkdownVisualEditing.test.ts +1089 -0
- package/Tests/UI/Components/ModelTable/BaseModelTableEmptyStateAction.test.tsx +623 -0
- package/Tests/UI/Components/ResetObjectID.test.tsx +282 -0
- package/Tests/UI/Components/RuleCriteria/RuleCriteriaModelTable.test.tsx +3 -3
- package/Tests/UI/Components/Table/EmptyTableMessage.test.ts +439 -0
- package/Tests/UI/Components/Table/TableEmptyState.test.tsx +352 -0
- package/Tests/UI/Components/TableRowMobileTitles.test.tsx +78 -0
- package/Tests/UI/Components/TextArea.test.tsx +19 -0
- package/Tests/UI/Components/Workflow/ModelColumnEditor.render.test.tsx +12 -29
- package/Tests/UI/Components/fixtures/MarkdownPasteFixtures.ts +460 -0
- package/Tests/UI/EsbuildConfig.test.ts +115 -39
- package/Tests/UI/EsbuildEnterpriseAlias.test.ts +4 -4
- package/Tests/UI/Monitor/MonitorLogSummaryRender.test.tsx +377 -0
- package/Tests/UI/Rum/RecordingHealthDashboard.test.tsx +769 -1
- package/Tests/UI/Utils/Breadcrumb/fixtures/RealBreadcrumbTrails.ts +81 -1
- package/Tests/UI/Utils/Breadcrumb/fixtures/RealRoutePatterns.ts +17 -0
- package/Tests/Utils/AiRemediation/Resource/CephCommandPolicy.test.ts +1653 -0
- package/Tests/Utils/AiRemediation/Resource/CephOutputRedaction.test.ts +204 -0
- package/Tests/Utils/AiRemediation/Resource/DatabaseCommandPolicy.test.ts +1077 -0
- package/Tests/Utils/AiRemediation/Resource/DatabaseDiagnosticCatalog.test.ts +558 -0
- package/Tests/Utils/AiRemediation/Resource/DatabaseQueryRedactor.test.ts +834 -0
- package/Tests/Utils/AiRemediation/Resource/DockerCliGrammar.test.ts +747 -0
- package/Tests/Utils/AiRemediation/Resource/DockerEngineCommandPolicy.test.ts +1259 -0
- package/Tests/Utils/AiRemediation/Resource/DockerOutputRedaction.test.ts +386 -0
- package/Tests/Utils/AiRemediation/Resource/DockerSwarmCommandPolicy.test.ts +782 -0
- package/Tests/Utils/AiRemediation/Resource/GovcCommandPolicy.test.ts +2259 -0
- package/Tests/Utils/AiRemediation/Resource/HostCommandPolicy.test.ts +2019 -0
- package/Tests/Utils/AiRemediation/Resource/ProxmoxCommandPolicy.test.ts +2497 -0
- package/Tests/Utils/AiRemediation/Resource/ResourceCommandPolicy.test.ts +1305 -0
- package/Tests/Utils/AiRemediation/Resource/ResourceCommandPolicyCore.test.ts +585 -0
- package/Tests/Utils/AiRemediation/Resource/ResourceOutputRedactor.test.ts +334 -0
- package/Tests/Utils/AiRemediation/Resource/ResourceOutputRedactorCopyParity.test.ts +98 -0
- package/Tests/Utils/AiRemediation/Resource/ResourcePolicyImportClosure.test.ts +391 -0
- package/Tests/Utils/AiRemediation/ResourceAiAgentPolicyCopyParity.test.ts +497 -0
- package/Tests/Utils/LabelRuleImportExport.test.ts +5 -0
- package/Tests/Utils/Markdown/DashboardMarkdownRenderer.ts +81 -0
- package/Tests/Utils/Markdown/UntrustedMarkdown.test.ts +1339 -0
- package/Tests/Utils/Monitor/MonitorLogSummaryUtil.test.ts +862 -0
- package/Tests/Utils/SessionReplay/SessionReplayBudgetMetricType.test.ts +383 -0
- package/Types/AI/AIAgentRunLimits.ts +146 -0
- package/Types/AI/ResourceAiAccessApi.ts +140 -0
- package/Types/AI/ResourceAiAccessPermissions.ts +126 -0
- package/Types/AutoRemediation/AiRemediationCommandPlan.ts +183 -2
- package/Types/Code/CodeType.ts +2 -0
- package/Types/Code/JsonSyntax.ts +923 -0
- package/Types/CustomField/CustomFieldCreateSettings.ts +549 -0
- package/Types/CustomField/CustomFieldMappingCatalog.ts +77 -0
- package/Types/CustomField/CustomFieldValueValidator.ts +10 -7
- package/Types/EnterpriseLicense/EnterpriseLicensePeriods.ts +1 -1
- package/Types/Icon/IconProp.ts +2 -0
- package/Types/Incident/IncidentFormIpAllowlist.ts +206 -0
- package/Types/Incident/IncidentFormPublic.ts +1145 -0
- package/Types/Kubernetes/KubernetesClusterAiAccess.ts +10 -3
- package/Types/MessageQueue/MessageQueueIdentity.ts +256 -0
- package/Types/MessageQueue/MessageQueueManualIdentity.ts +325 -0
- package/Types/MessageQueue/MessageQueueMetricCatalog.ts +1357 -0
- package/Types/MessageQueue/MessagingSystem.ts +518 -0
- package/Types/MessageQueue/MessagingTelemetryResolver.ts +2311 -0
- package/Types/Monitor/MessageQueueAlertTemplates.ts +2128 -0
- package/Types/Monitor/Recommendation/MonitorRecommendationCatalog.ts +55 -22
- package/Types/Monitor/Recommendation/MonitorRecommendationTypes.ts +35 -3
- package/Types/Monitor/RumAlertTemplates.ts +351 -4
- package/Types/Permission.ts +310 -0
- package/Types/ResourceAiAgent/AiResourceType.ts +310 -0
- package/Types/ResourceAiAgent/ResourceAiAccess.ts +580 -0
- package/Types/Rules/RuleCriteriaFieldRegistry.ts +12 -0
- package/Types/Rules/RuleRun.ts +4 -0
- package/Types/Rum/SessionReplayBudgetMetricType.ts +47 -0
- package/Types/Runbook/RunbookStepType.ts +29 -0
- package/Types/Team/ComplianceNotificationChannel.ts +4 -3
- package/Types/Team/ComplianceRule.ts +71 -18
- package/Types/Team/ComplianceRuleType.ts +2 -2
- package/Types/Team/TeamComplianceStatus.ts +6 -2
- package/Types/Telemetry/EntityType.ts +16 -0
- package/Types/Telemetry/LockedFilterDetail.ts +22 -0
- package/Types/Telemetry/TelemetryIngestSurface.ts +14 -2
- package/Types/XML.ts +26 -0
- package/UI/Components/CodeEditor/CodeEditor.css +379 -0
- package/UI/Components/CodeEditor/CodeEditor.tsx +1128 -294
- package/UI/Components/CodeEditor/CodeEditorCommands.ts +774 -0
- package/UI/Components/CodeEditor/CodeEditorHighlight.ts +106 -0
- package/UI/Components/CodeEditor/CodeEditorLanguages.ts +164 -0
- package/UI/Components/CodeEditor/YamlEditor.tsx +28 -326
- package/UI/Components/CopyTextButton/CopyTextButton.tsx +5 -1
- package/UI/Components/CustomFields/CustomFieldModelFormFields.tsx +6 -25
- package/UI/Components/EditionLabel/EditionLabel.tsx +14 -13
- package/UI/Components/ErrorMessage/ErrorMessage.tsx +11 -1
- package/UI/Components/Forms/Fields/FormField.tsx +8 -0
- package/UI/Components/Forms/Types/Field.ts +8 -0
- package/UI/Components/Icon/Icon.tsx +18 -0
- package/UI/Components/Input/Input.tsx +11 -4
- package/UI/Components/LogsViewer/LogsViewer.tsx +4 -0
- package/UI/Components/LogsViewer/components/LogsFacetSidebar.tsx +21 -3
- package/UI/Components/Markdown.tsx/MarkdownConverters.ts +0 -0
- package/UI/Components/Markdown.tsx/MarkdownEditor.tsx +877 -79
- package/UI/Components/Markdown.tsx/MarkdownEditorHistory.ts +284 -0
- package/UI/Components/Markdown.tsx/MarkdownListEditing.ts +1362 -0
- package/UI/Components/Markdown.tsx/MarkdownPaste.ts +1326 -0
- package/UI/Components/Markdown.tsx/MarkdownViewer.tsx +106 -10
- package/UI/Components/Markdown.tsx/MarkdownVisualEditing.ts +1032 -0
- package/UI/Components/ModelTable/BaseModelTable.tsx +85 -7
- package/UI/Components/ResetObjectID/ResetObjectID.tsx +35 -9
- package/UI/Components/Table/EmptyTableMessage.ts +81 -0
- package/UI/Components/Table/Table.tsx +50 -21
- package/UI/Components/Table/TableRow.tsx +9 -1
- package/UI/Components/TelemetryViewer/FacetVisibility.ts +97 -2
- package/UI/Components/TelemetryViewer/TelemetryViewer.tsx +13 -0
- package/UI/Components/TelemetryViewer/components/LockedFilterChip.tsx +214 -7
- package/UI/Components/TelemetryViewer/components/TelemetryFacetSidebar.tsx +21 -3
- package/UI/Components/TextArea/TextArea.tsx +9 -2
- package/UI/Components/Workflow/ModelFieldPicker.tsx +10 -12
- package/UI/Styles/Theme.css +8 -0
- package/UI/esbuild-config.js +2 -32
- package/Utils/AI/InvestigationReport.ts +121 -15
- package/Utils/AiRemediation/Resource/CephCommandPolicy.ts +1936 -0
- package/Utils/AiRemediation/Resource/DatabaseCommandPolicy.ts +166 -0
- package/Utils/AiRemediation/Resource/DatabaseDiagnosticCatalog.ts +1532 -0
- package/Utils/AiRemediation/Resource/DatabaseQueryRedactor.ts +1394 -0
- package/Utils/AiRemediation/Resource/DockerCliGrammar.ts +1839 -0
- package/Utils/AiRemediation/Resource/DockerEngineCommandPolicy.ts +490 -0
- package/Utils/AiRemediation/Resource/DockerSwarmCommandPolicy.ts +687 -0
- package/Utils/AiRemediation/Resource/GovcCommandPolicy.ts +2096 -0
- package/Utils/AiRemediation/Resource/HostCommandPolicy.ts +2982 -0
- package/Utils/AiRemediation/Resource/ProxmoxCommandPolicy.ts +1679 -0
- package/Utils/AiRemediation/Resource/ResourceCommandPolicy.ts +851 -0
- package/Utils/AiRemediation/Resource/ResourceCommandPolicyCore.ts +593 -0
- package/Utils/AiRemediation/Resource/ResourceOutputRedactor.ts +2812 -0
- package/Utils/LabelRuleImportExport.ts +2 -0
- package/Utils/Markdown/UntrustedMarkdown.ts +1513 -0
- package/Utils/Monitor/IncomingEmailMonitorRequestUtil.ts +41 -0
- package/Utils/Monitor/MonitorLogSummaryUtil.ts +212 -0
- package/Utils/SessionReplay/SessionReplayBudgetMetricType.ts +184 -0
- package/Utils/Telemetry/EntityKey.ts +48 -0
- package/build/dist/Models/DatabaseModels/AIConversation.js +125 -1
- package/build/dist/Models/DatabaseModels/AIConversation.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/CephCluster.js +231 -0
- package/build/dist/Models/DatabaseModels/CephCluster.js.map +1 -1
- package/build/dist/Models/DatabaseModels/CloudResource.js +12 -0
- package/build/dist/Models/DatabaseModels/CloudResource.js.map +1 -1
- package/build/dist/Models/DatabaseModels/DatabaseServer.js +231 -0
- package/build/dist/Models/DatabaseModels/DatabaseServer.js.map +1 -1
- package/build/dist/Models/DatabaseModels/DockerHost.js +231 -0
- package/build/dist/Models/DatabaseModels/DockerHost.js.map +1 -1
- package/build/dist/Models/DatabaseModels/DockerSwarmCluster.js +231 -0
- package/build/dist/Models/DatabaseModels/DockerSwarmCluster.js.map +1 -1
- package/build/dist/Models/DatabaseModels/GlobalConfig.js +1 -1
- package/build/dist/Models/DatabaseModels/GlobalConfig.js.map +1 -1
- package/build/dist/Models/DatabaseModels/GlobalOidc.js +0 -4
- package/build/dist/Models/DatabaseModels/GlobalOidc.js.map +1 -1
- package/build/dist/Models/DatabaseModels/GlobalOidcProject.js +0 -4
- package/build/dist/Models/DatabaseModels/GlobalOidcProject.js.map +1 -1
- package/build/dist/Models/DatabaseModels/GlobalSso.js +0 -4
- package/build/dist/Models/DatabaseModels/GlobalSso.js.map +1 -1
- package/build/dist/Models/DatabaseModels/GlobalSsoProject.js +0 -4
- package/build/dist/Models/DatabaseModels/GlobalSsoProject.js.map +1 -1
- package/build/dist/Models/DatabaseModels/Host.js +231 -0
- package/build/dist/Models/DatabaseModels/Host.js.map +1 -1
- package/build/dist/Models/DatabaseModels/IncidentForm.js +605 -0
- package/build/dist/Models/DatabaseModels/IncidentForm.js.map +1 -0
- package/build/dist/Models/DatabaseModels/IncidentFormSubmission.js +299 -0
- package/build/dist/Models/DatabaseModels/IncidentFormSubmission.js.map +1 -0
- package/build/dist/Models/DatabaseModels/IncidentTemplate.js +60 -0
- package/build/dist/Models/DatabaseModels/IncidentTemplate.js.map +1 -1
- package/build/dist/Models/DatabaseModels/Index.js +16 -0
- package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
- package/build/dist/Models/DatabaseModels/IoTFleet.js +12 -0
- package/build/dist/Models/DatabaseModels/IoTFleet.js.map +1 -1
- package/build/dist/Models/DatabaseModels/KubernetesCluster.js +12 -0
- package/build/dist/Models/DatabaseModels/KubernetesCluster.js.map +1 -1
- package/build/dist/Models/DatabaseModels/MessageQueue.js +1106 -0
- package/build/dist/Models/DatabaseModels/MessageQueue.js.map +1 -0
- package/build/dist/Models/DatabaseModels/MessageQueueLabelRule.js +562 -0
- package/build/dist/Models/DatabaseModels/MessageQueueLabelRule.js.map +1 -0
- package/build/dist/Models/DatabaseModels/MessageQueueOwnerRule.js +643 -0
- package/build/dist/Models/DatabaseModels/MessageQueueOwnerRule.js.map +1 -0
- package/build/dist/Models/DatabaseModels/MessageQueueOwnerTeam.js +506 -0
- package/build/dist/Models/DatabaseModels/MessageQueueOwnerTeam.js.map +1 -0
- package/build/dist/Models/DatabaseModels/MessageQueueOwnerUser.js +505 -0
- package/build/dist/Models/DatabaseModels/MessageQueueOwnerUser.js.map +1 -0
- package/build/dist/Models/DatabaseModels/PodmanHost.js +231 -0
- package/build/dist/Models/DatabaseModels/PodmanHost.js.map +1 -1
- package/build/dist/Models/DatabaseModels/Project.js +61 -0
- package/build/dist/Models/DatabaseModels/Project.js.map +1 -1
- package/build/dist/Models/DatabaseModels/ProjectOidc.js +0 -4
- package/build/dist/Models/DatabaseModels/ProjectOidc.js.map +1 -1
- package/build/dist/Models/DatabaseModels/ProjectSso.js +0 -4
- package/build/dist/Models/DatabaseModels/ProjectSso.js.map +1 -1
- package/build/dist/Models/DatabaseModels/ProxmoxCluster.js +231 -0
- package/build/dist/Models/DatabaseModels/ProxmoxCluster.js.map +1 -1
- package/build/dist/Models/DatabaseModels/ResourceAiAgent.js +439 -0
- package/build/dist/Models/DatabaseModels/ResourceAiAgent.js.map +1 -0
- package/build/dist/Models/DatabaseModels/RumApplication.js +12 -0
- package/build/dist/Models/DatabaseModels/RumApplication.js.map +1 -1
- package/build/dist/Models/DatabaseModels/RunnerJob.js +145 -0
- package/build/dist/Models/DatabaseModels/RunnerJob.js.map +1 -1
- package/build/dist/Models/DatabaseModels/ServerlessFunction.js +12 -0
- package/build/dist/Models/DatabaseModels/ServerlessFunction.js.map +1 -1
- package/build/dist/Models/DatabaseModels/Service.js +12 -0
- package/build/dist/Models/DatabaseModels/Service.js.map +1 -1
- package/build/dist/Models/DatabaseModels/StatusPageOidc.js +0 -4
- package/build/dist/Models/DatabaseModels/StatusPageOidc.js.map +1 -1
- package/build/dist/Models/DatabaseModels/StatusPageSso.js +0 -4
- package/build/dist/Models/DatabaseModels/StatusPageSso.js.map +1 -1
- package/build/dist/Models/DatabaseModels/TeamComplianceSetting.js +49 -3
- package/build/dist/Models/DatabaseModels/TeamComplianceSetting.js.map +1 -1
- package/build/dist/Models/DatabaseModels/VMwareVCenter.js +231 -0
- package/build/dist/Models/DatabaseModels/VMwareVCenter.js.map +1 -1
- package/build/dist/Server/API/AIChatAPI.js +9 -103
- package/build/dist/Server/API/AIChatAPI.js.map +1 -1
- package/build/dist/Server/API/AIInvestigationAPI.js +3 -3
- package/build/dist/Server/API/AIInvestigationAPI.js.map +1 -1
- package/build/dist/Server/API/AIInvestigationConversationAPI.js +162 -0
- package/build/dist/Server/API/AIInvestigationConversationAPI.js.map +1 -0
- package/build/dist/Server/API/AutoRemediationAPI.js +231 -1
- package/build/dist/Server/API/AutoRemediationAPI.js.map +1 -1
- package/build/dist/Server/API/IncidentFormAPI.js +245 -0
- package/build/dist/Server/API/IncidentFormAPI.js.map +1 -0
- package/build/dist/Server/API/ProjectOIDC.js +16 -24
- package/build/dist/Server/API/ProjectOIDC.js.map +1 -1
- package/build/dist/Server/API/ProjectSSO.js +16 -24
- package/build/dist/Server/API/ProjectSSO.js.map +1 -1
- package/build/dist/Server/API/ResourceAiAccessAPI.js +1119 -0
- package/build/dist/Server/API/ResourceAiAccessAPI.js.map +1 -0
- package/build/dist/Server/API/StatusPageAPI.js +42 -75
- package/build/dist/Server/API/StatusPageAPI.js.map +1 -1
- package/build/dist/Server/Enterprise/EnterpriseEdition.js +79 -25
- package/build/dist/Server/Enterprise/EnterpriseEdition.js.map +1 -1
- package/build/dist/Server/Enterprise/EnterpriseFeature.js +24 -3
- package/build/dist/Server/Enterprise/EnterpriseFeature.js.map +1 -1
- package/build/dist/Server/Enterprise/EnterpriseLicenseSnapshot.js +1 -1
- package/build/dist/Server/Enterprise/EnterpriseServerModule.js.map +1 -1
- package/build/dist/Server/EnvironmentConfig.js +1 -1
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1796300000000-AddResourceAiAgents.js +168 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1796300000000-AddResourceAiAgents.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1796400000000-AddIncidentForms.js +63 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1796400000000-AddIncidentForms.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1796500000000-AddTeamComplianceRuleNotificationChannels.js +41 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1796500000000-AddTeamComplianceRuleNotificationChannels.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1796600000000-AddAIInvestigationConversationAndTimeLimits.js +40 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1796600000000-AddAIInvestigationConversationAndTimeLimits.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1796700000000-AddMessageQueueTables.js +183 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1796700000000-AddMessageQueueTables.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +10 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
- package/build/dist/Server/Infrastructure/Semaphore.js +6 -0
- package/build/dist/Server/Infrastructure/Semaphore.js.map +1 -1
- package/build/dist/Server/Middleware/IncidentFormRateLimit.js +559 -0
- package/build/dist/Server/Middleware/IncidentFormRateLimit.js.map +1 -0
- package/build/dist/Server/Middleware/TelemetryIngest.js +12 -5
- package/build/dist/Server/Middleware/TelemetryIngest.js.map +1 -1
- package/build/dist/Server/Middleware/UserAuthorization.js +11 -30
- package/build/dist/Server/Middleware/UserAuthorization.js.map +1 -1
- package/build/dist/Server/Services/AIService.js +10 -13
- package/build/dist/Server/Services/AIService.js.map +1 -1
- package/build/dist/Server/Services/AnalyticsDatabaseService.js +26 -1
- package/build/dist/Server/Services/AnalyticsDatabaseService.js.map +1 -1
- package/build/dist/Server/Services/AutoRemediationRuleEngineService.js +601 -3
- package/build/dist/Server/Services/AutoRemediationRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/CephClusterService.js +104 -0
- package/build/dist/Server/Services/CephClusterService.js.map +1 -1
- package/build/dist/Server/Services/DatabaseServerService.js +99 -0
- package/build/dist/Server/Services/DatabaseServerService.js.map +1 -1
- package/build/dist/Server/Services/DockerHostService.js +104 -0
- package/build/dist/Server/Services/DockerHostService.js.map +1 -1
- package/build/dist/Server/Services/DockerSwarmClusterService.js +104 -0
- package/build/dist/Server/Services/DockerSwarmClusterService.js.map +1 -1
- package/build/dist/Server/Services/HostService.js +114 -2
- package/build/dist/Server/Services/HostService.js.map +1 -1
- package/build/dist/Server/Services/IncidentCustomFieldService.js +83 -0
- package/build/dist/Server/Services/IncidentCustomFieldService.js.map +1 -1
- package/build/dist/Server/Services/IncidentEpisodeMemberService.js +8 -4
- package/build/dist/Server/Services/IncidentEpisodeMemberService.js.map +1 -1
- package/build/dist/Server/Services/IncidentEpisodeService.js +10 -1
- package/build/dist/Server/Services/IncidentEpisodeService.js.map +1 -1
- package/build/dist/Server/Services/IncidentFormService.js +1202 -0
- package/build/dist/Server/Services/IncidentFormService.js.map +1 -0
- package/build/dist/Server/Services/IncidentFormSubmissionService.js +91 -0
- package/build/dist/Server/Services/IncidentFormSubmissionService.js.map +1 -0
- package/build/dist/Server/Services/IncidentGroupingEngineService.js +20 -8
- package/build/dist/Server/Services/IncidentGroupingEngineService.js.map +1 -1
- package/build/dist/Server/Services/IncidentService.js +106 -4
- package/build/dist/Server/Services/IncidentService.js.map +1 -1
- package/build/dist/Server/Services/IncidentTemplateService.js +18 -0
- package/build/dist/Server/Services/IncidentTemplateService.js.map +1 -1
- package/build/dist/Server/Services/Index.js +14 -0
- package/build/dist/Server/Services/Index.js.map +1 -1
- package/build/dist/Server/Services/MessageQueueLabelRuleEngineService.js +262 -0
- package/build/dist/Server/Services/MessageQueueLabelRuleEngineService.js.map +1 -0
- package/build/dist/Server/Services/MessageQueueLabelRuleService.js +13 -0
- package/build/dist/Server/Services/MessageQueueLabelRuleService.js.map +1 -0
- package/build/dist/Server/Services/MessageQueueOwnerRuleEngineService.js +334 -0
- package/build/dist/Server/Services/MessageQueueOwnerRuleEngineService.js.map +1 -0
- package/build/dist/Server/Services/MessageQueueOwnerRuleService.js +13 -0
- package/build/dist/Server/Services/MessageQueueOwnerRuleService.js.map +1 -0
- package/build/dist/Server/Services/MessageQueueOwnerTeamService.js +62 -0
- package/build/dist/Server/Services/MessageQueueOwnerTeamService.js.map +1 -0
- package/build/dist/Server/Services/MessageQueueOwnerUserService.js +62 -0
- package/build/dist/Server/Services/MessageQueueOwnerUserService.js.map +1 -0
- package/build/dist/Server/Services/MessageQueueService.js +1140 -0
- package/build/dist/Server/Services/MessageQueueService.js.map +1 -0
- package/build/dist/Server/Services/MetricRecordingRuleService.js +46 -0
- package/build/dist/Server/Services/MetricRecordingRuleService.js.map +1 -1
- package/build/dist/Server/Services/OpenTelemetryIngestService.js +25 -4
- package/build/dist/Server/Services/OpenTelemetryIngestService.js.map +1 -1
- package/build/dist/Server/Services/PodmanHostService.js +104 -0
- package/build/dist/Server/Services/PodmanHostService.js.map +1 -1
- package/build/dist/Server/Services/ProjectService.js +0 -54
- package/build/dist/Server/Services/ProjectService.js.map +1 -1
- package/build/dist/Server/Services/ProxmoxClusterService.js +104 -0
- package/build/dist/Server/Services/ProxmoxClusterService.js.map +1 -1
- package/build/dist/Server/Services/ResourceAiAccessService.js +1028 -0
- package/build/dist/Server/Services/ResourceAiAccessService.js.map +1 -0
- package/build/dist/Server/Services/ResourceAiAgentJobService.js +173 -0
- package/build/dist/Server/Services/ResourceAiAgentJobService.js.map +1 -0
- package/build/dist/Server/Services/ResourceAiAgentService.js +1687 -0
- package/build/dist/Server/Services/ResourceAiAgentService.js.map +1 -0
- package/build/dist/Server/Services/RunnerJobService.js +344 -5
- package/build/dist/Server/Services/RunnerJobService.js.map +1 -1
- package/build/dist/Server/Services/StatusPagePrivateUserService.js +1 -4
- package/build/dist/Server/Services/StatusPagePrivateUserService.js.map +1 -1
- package/build/dist/Server/Services/StatusPageService.js +0 -46
- package/build/dist/Server/Services/StatusPageService.js.map +1 -1
- package/build/dist/Server/Services/TeamComplianceSettingService.js +120 -31
- package/build/dist/Server/Services/TeamComplianceSettingService.js.map +1 -1
- package/build/dist/Server/Services/TelemetryUsageBillingService.js +26 -0
- package/build/dist/Server/Services/TelemetryUsageBillingService.js.map +1 -1
- package/build/dist/Server/Services/TraceRecordingRuleService.js +37 -0
- package/build/dist/Server/Services/TraceRecordingRuleService.js.map +1 -1
- package/build/dist/Server/Services/UserNotificationRuleService.js +8 -1
- package/build/dist/Server/Services/UserNotificationRuleService.js.map +1 -1
- package/build/dist/Server/Services/VMwareVCenterService.js +104 -0
- package/build/dist/Server/Services/VMwareVCenterService.js.map +1 -1
- package/build/dist/Server/Services/WorkspaceNotificationSummaryService.js +12 -3
- package/build/dist/Server/Services/WorkspaceNotificationSummaryService.js.map +1 -1
- package/build/dist/Server/Types/Database/Permissions/CreatePermission.js +6 -3
- package/build/dist/Server/Types/Database/Permissions/CreatePermission.js.map +1 -1
- package/build/dist/Server/Types/Database/Permissions/EditionPermission.js +109 -37
- package/build/dist/Server/Types/Database/Permissions/EditionPermission.js.map +1 -1
- package/build/dist/Server/Types/Database/Permissions/OwnerTableRegistry.js +16 -0
- package/build/dist/Server/Types/Database/Permissions/OwnerTableRegistry.js.map +1 -1
- package/build/dist/Server/Types/Database/Permissions/TablePermission.js +3 -3
- package/build/dist/Server/Types/Database/Permissions/UpdatePermission.js +9 -6
- package/build/dist/Server/Types/Database/Permissions/UpdatePermission.js.map +1 -1
- package/build/dist/Server/Utils/AI/Chat/AgentContextCompactor.js +128 -0
- package/build/dist/Server/Utils/AI/Chat/AgentContextCompactor.js.map +1 -0
- package/build/dist/Server/Utils/AI/Chat/ChatAgentRunner.js +192 -50
- package/build/dist/Server/Utils/AI/Chat/ChatAgentRunner.js.map +1 -1
- package/build/dist/Server/Utils/AI/Chat/ChatRunCancellation.js +133 -0
- package/build/dist/Server/Utils/AI/Chat/ChatRunCancellation.js.map +1 -0
- package/build/dist/Server/Utils/AI/Chat/ObservabilityAssistant.js +53 -13
- package/build/dist/Server/Utils/AI/Chat/ObservabilityAssistant.js.map +1 -1
- package/build/dist/Server/Utils/AI/Chat/ObservabilityChatPrompt.js +1 -1
- package/build/dist/Server/Utils/AI/Chat/ToolOutputPager.js +206 -0
- package/build/dist/Server/Utils/AI/Chat/ToolOutputPager.js.map +1 -0
- package/build/dist/Server/Utils/AI/ClusterAccess/KubectlInvestigationToolkit.js +53 -26
- package/build/dist/Server/Utils/AI/ClusterAccess/KubectlInvestigationToolkit.js.map +1 -1
- package/build/dist/Server/Utils/AI/ClusterAccess/KubectlJobRunner.js +4 -2
- package/build/dist/Server/Utils/AI/ClusterAccess/KubectlJobRunner.js.map +1 -1
- package/build/dist/Server/Utils/AI/CodeFix/CodeFixReadiness.js +1 -29
- package/build/dist/Server/Utils/AI/CodeFix/CodeFixReadiness.js.map +1 -1
- package/build/dist/Server/Utils/AI/CodeFix/FixRunBudget.js +24 -24
- package/build/dist/Server/Utils/AI/CodeFix/FixRunBudget.js.map +1 -1
- package/build/dist/Server/Utils/AI/Remediation/RemediationCommandTools.js +1036 -32
- package/build/dist/Server/Utils/AI/Remediation/RemediationCommandTools.js.map +1 -1
- package/build/dist/Server/Utils/AI/Remediation/RemediationExecutionRunner.js +661 -41
- package/build/dist/Server/Utils/AI/Remediation/RemediationExecutionRunner.js.map +1 -1
- package/build/dist/Server/Utils/AI/Remediation/RemediationPlanRunner.js +21 -1
- package/build/dist/Server/Utils/AI/Remediation/RemediationPlanRunner.js.map +1 -1
- package/build/dist/Server/Utils/AI/ResourceAccess/InfrastructureInvestigationToolkit.js +354 -0
- package/build/dist/Server/Utils/AI/ResourceAccess/InfrastructureInvestigationToolkit.js.map +1 -0
- package/build/dist/Server/Utils/AI/ResourceAccess/ResourceAccessContext.js +160 -0
- package/build/dist/Server/Utils/AI/ResourceAccess/ResourceAccessContext.js.map +1 -0
- package/build/dist/Server/Utils/AI/ResourceAccess/ResourceAccessToolNames.js +33 -0
- package/build/dist/Server/Utils/AI/ResourceAccess/ResourceAccessToolNames.js.map +1 -0
- package/build/dist/Server/Utils/AI/ResourceAccess/ResourceAiAccessSettings.js +640 -0
- package/build/dist/Server/Utils/AI/ResourceAccess/ResourceAiAccessSettings.js.map +1 -0
- package/build/dist/Server/Utils/AI/ResourceAccess/ResourceAiDeleteCleanup.js +226 -0
- package/build/dist/Server/Utils/AI/ResourceAccess/ResourceAiDeleteCleanup.js.map +1 -0
- package/build/dist/Server/Utils/AI/ResourceAccess/ResourceCommandJobRunner.js +602 -0
- package/build/dist/Server/Utils/AI/ResourceAccess/ResourceCommandJobRunner.js.map +1 -0
- package/build/dist/Server/Utils/AI/SRE/AIInvestigationEngine.js +90 -14
- package/build/dist/Server/Utils/AI/SRE/AIInvestigationEngine.js.map +1 -1
- package/build/dist/Server/Utils/AI/SRE/AlertInvestigationRunner.js +73 -10
- package/build/dist/Server/Utils/AI/SRE/AlertInvestigationRunner.js.map +1 -1
- package/build/dist/Server/Utils/AI/SRE/IncidentInvestigationRunner.js +73 -10
- package/build/dist/Server/Utils/AI/SRE/IncidentInvestigationRunner.js.map +1 -1
- package/build/dist/Server/Utils/AI/SRE/InvestigationQueue.js +15 -18
- package/build/dist/Server/Utils/AI/SRE/InvestigationQueue.js.map +1 -1
- package/build/dist/Server/Utils/AI/SRE/InvestigationThread.js +412 -0
- package/build/dist/Server/Utils/AI/SRE/InvestigationThread.js.map +1 -0
- package/build/dist/Server/Utils/AI/SRE/InvestigationThreadService.js +495 -0
- package/build/dist/Server/Utils/AI/SRE/InvestigationThreadService.js.map +1 -0
- package/build/dist/Server/Utils/AI/Toolbox/Serializer.js +10 -3
- package/build/dist/Server/Utils/AI/Toolbox/Serializer.js.map +1 -1
- package/build/dist/Server/Utils/AutoRemediation/CommandPlanExecutor.js +290 -13
- package/build/dist/Server/Utils/AutoRemediation/CommandPlanExecutor.js.map +1 -1
- package/build/dist/Server/Utils/AutoRemediation/RemediationVerifier.js +29 -1
- package/build/dist/Server/Utils/AutoRemediation/RemediationVerifier.js.map +1 -1
- package/build/dist/Server/Utils/Database/ProjectScopedReferenceValidator.js +9 -1
- package/build/dist/Server/Utils/Database/ProjectScopedReferenceValidator.js.map +1 -1
- package/build/dist/Server/Utils/EditionEnforcement.js +20 -158
- package/build/dist/Server/Utils/EditionEnforcement.js.map +1 -1
- package/build/dist/Server/Utils/LLM/LLMService.js +193 -54
- package/build/dist/Server/Utils/LLM/LLMService.js.map +1 -1
- package/build/dist/Server/Utils/RelaxedScimTeamLocksReport.js +160 -0
- package/build/dist/Server/Utils/RelaxedScimTeamLocksReport.js.map +1 -0
- package/build/dist/Server/Utils/Rules/RuleRun/RuleRunRegistry.js +25 -0
- package/build/dist/Server/Utils/Rules/RuleRun/RuleRunRegistry.js.map +1 -1
- package/build/dist/Server/Utils/SameOriginRequest.js +151 -0
- package/build/dist/Server/Utils/SameOriginRequest.js.map +1 -0
- package/build/dist/Server/Utils/SessionReplay/SessionReplayBudgetMetrics.js +627 -0
- package/build/dist/Server/Utils/SessionReplay/SessionReplayBudgetMetrics.js.map +1 -0
- package/build/dist/Server/Utils/SessionReplay/SessionReplayUsage.js +60 -5
- package/build/dist/Server/Utils/SessionReplay/SessionReplayUsage.js.map +1 -1
- package/build/dist/Server/Utils/TeamMember/ProjectLeaveResourceCleanup.js +2 -0
- package/build/dist/Server/Utils/TeamMember/ProjectLeaveResourceCleanup.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/EntityRegistry.js +4 -1
- package/build/dist/Server/Utils/Telemetry/EntityRegistry.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/MessageQueueDiscovery.js +1015 -0
- package/build/dist/Server/Utils/Telemetry/MessageQueueDiscovery.js.map +1 -0
- package/build/dist/Server/Utils/Telemetry/ResourceEntityFilter.js +4 -1
- package/build/dist/Server/Utils/Telemetry/ResourceEntityFilter.js.map +1 -1
- package/build/dist/Server/Utils/VendorAssets.js +3 -3
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/Alert.js +19 -15
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/Alert.js.map +1 -1
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/AlertEpisode.js +19 -15
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/AlertEpisode.js.map +1 -1
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/Auth.js +17 -1
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/Auth.js.map +1 -1
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/Incident.js +186 -210
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/Incident.js.map +1 -1
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/IncidentEpisode.js +22 -16
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/IncidentEpisode.js.map +1 -1
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/ScheduledMaintenance.js +233 -167
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/ScheduledMaintenance.js.map +1 -1
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js +273 -111
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js.map +1 -1
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsActivityDeduplicator.js +129 -0
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsActivityDeduplicator.js.map +1 -0
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsCardChoices.js +266 -0
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsCardChoices.js.map +1 -0
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsCreateCommands.js +258 -0
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsCreateCommands.js.map +1 -0
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsMessageSize.js +104 -0
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsMessageSize.js.map +1 -0
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsReplies.js +183 -0
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsReplies.js.map +1 -0
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsTimezone.js +123 -0
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsTimezone.js.map +1 -0
- package/build/dist/Types/AI/AIAgentRunLimits.js +91 -0
- package/build/dist/Types/AI/AIAgentRunLimits.js.map +1 -0
- package/build/dist/Types/AI/ResourceAiAccessApi.js +30 -0
- package/build/dist/Types/AI/ResourceAiAccessApi.js.map +1 -0
- package/build/dist/Types/AI/ResourceAiAccessPermissions.js +98 -0
- package/build/dist/Types/AI/ResourceAiAccessPermissions.js.map +1 -0
- package/build/dist/Types/AutoRemediation/AiRemediationCommandPlan.js +116 -29
- package/build/dist/Types/AutoRemediation/AiRemediationCommandPlan.js.map +1 -1
- package/build/dist/Types/Code/CodeType.js +2 -0
- package/build/dist/Types/Code/CodeType.js.map +1 -1
- package/build/dist/Types/Code/JsonSyntax.js +604 -0
- package/build/dist/Types/Code/JsonSyntax.js.map +1 -0
- package/build/dist/Types/CustomField/CustomFieldCreateSettings.js +310 -0
- package/build/dist/Types/CustomField/CustomFieldCreateSettings.js.map +1 -0
- package/build/dist/Types/CustomField/CustomFieldMappingCatalog.js +38 -0
- package/build/dist/Types/CustomField/CustomFieldMappingCatalog.js.map +1 -1
- package/build/dist/Types/CustomField/CustomFieldValueValidator.js +10 -7
- package/build/dist/Types/CustomField/CustomFieldValueValidator.js.map +1 -1
- package/build/dist/Types/EnterpriseLicense/EnterpriseLicensePeriods.js +1 -1
- package/build/dist/Types/Icon/IconProp.js +2 -0
- package/build/dist/Types/Icon/IconProp.js.map +1 -1
- package/build/dist/Types/Incident/IncidentFormIpAllowlist.js +119 -0
- package/build/dist/Types/Incident/IncidentFormIpAllowlist.js.map +1 -0
- package/build/dist/Types/Incident/IncidentFormPublic.js +678 -0
- package/build/dist/Types/Incident/IncidentFormPublic.js.map +1 -0
- package/build/dist/Types/Kubernetes/KubernetesClusterAiAccess.js +10 -3
- package/build/dist/Types/Kubernetes/KubernetesClusterAiAccess.js.map +1 -1
- package/build/dist/Types/MessageQueue/MessageQueueIdentity.js +184 -0
- package/build/dist/Types/MessageQueue/MessageQueueIdentity.js.map +1 -0
- package/build/dist/Types/MessageQueue/MessageQueueManualIdentity.js +190 -0
- package/build/dist/Types/MessageQueue/MessageQueueManualIdentity.js.map +1 -0
- package/build/dist/Types/MessageQueue/MessageQueueMetricCatalog.js +1057 -0
- package/build/dist/Types/MessageQueue/MessageQueueMetricCatalog.js.map +1 -0
- package/build/dist/Types/MessageQueue/MessagingSystem.js +394 -0
- package/build/dist/Types/MessageQueue/MessagingSystem.js.map +1 -0
- package/build/dist/Types/MessageQueue/MessagingTelemetryResolver.js +1768 -0
- package/build/dist/Types/MessageQueue/MessagingTelemetryResolver.js.map +1 -0
- package/build/dist/Types/Monitor/MessageQueueAlertTemplates.js +1207 -0
- package/build/dist/Types/Monitor/MessageQueueAlertTemplates.js.map +1 -0
- package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationCatalog.js +47 -21
- package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationCatalog.js.map +1 -1
- package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationTypes.js +5 -0
- package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationTypes.js.map +1 -1
- package/build/dist/Types/Monitor/RumAlertTemplates.js +199 -3
- package/build/dist/Types/Monitor/RumAlertTemplates.js.map +1 -1
- package/build/dist/Types/Permission.js +274 -0
- package/build/dist/Types/Permission.js.map +1 -1
- package/build/dist/Types/ResourceAiAgent/AiResourceType.js +242 -0
- package/build/dist/Types/ResourceAiAgent/AiResourceType.js.map +1 -0
- package/build/dist/Types/ResourceAiAgent/ResourceAiAccess.js +281 -0
- package/build/dist/Types/ResourceAiAgent/ResourceAiAccess.js.map +1 -0
- package/build/dist/Types/Rules/RuleCriteriaFieldRegistry.js +12 -0
- package/build/dist/Types/Rules/RuleCriteriaFieldRegistry.js.map +1 -1
- package/build/dist/Types/Rules/RuleRun.js +4 -0
- package/build/dist/Types/Rules/RuleRun.js.map +1 -1
- package/build/dist/Types/Rum/SessionReplayBudgetMetricType.js +45 -0
- package/build/dist/Types/Rum/SessionReplayBudgetMetricType.js.map +1 -0
- package/build/dist/Types/Runbook/RunbookStepType.js +27 -0
- package/build/dist/Types/Runbook/RunbookStepType.js.map +1 -1
- package/build/dist/Types/Team/ComplianceNotificationChannel.js +4 -3
- package/build/dist/Types/Team/ComplianceNotificationChannel.js.map +1 -1
- package/build/dist/Types/Team/ComplianceRule.js +48 -14
- package/build/dist/Types/Team/ComplianceRule.js.map +1 -1
- package/build/dist/Types/Team/ComplianceRuleType.js +2 -2
- package/build/dist/Types/Telemetry/EntityType.js +16 -0
- package/build/dist/Types/Telemetry/EntityType.js.map +1 -1
- package/build/dist/Types/Telemetry/TelemetryIngestSurface.js +13 -2
- package/build/dist/Types/Telemetry/TelemetryIngestSurface.js.map +1 -1
- package/build/dist/Types/XML.js +23 -0
- package/build/dist/Types/XML.js.map +1 -1
- package/build/dist/UI/Components/CodeEditor/CodeEditor.js +641 -266
- package/build/dist/UI/Components/CodeEditor/CodeEditor.js.map +1 -1
- package/build/dist/UI/Components/CodeEditor/CodeEditorCommands.js +464 -0
- package/build/dist/UI/Components/CodeEditor/CodeEditorCommands.js.map +1 -0
- package/build/dist/UI/Components/CodeEditor/CodeEditorHighlight.js +69 -0
- package/build/dist/UI/Components/CodeEditor/CodeEditorHighlight.js.map +1 -0
- package/build/dist/UI/Components/CodeEditor/CodeEditorLanguages.js +108 -0
- package/build/dist/UI/Components/CodeEditor/CodeEditorLanguages.js.map +1 -0
- package/build/dist/UI/Components/CodeEditor/YamlEditor.js +14 -186
- package/build/dist/UI/Components/CodeEditor/YamlEditor.js.map +1 -1
- package/build/dist/UI/Components/CopyTextButton/CopyTextButton.js +5 -1
- package/build/dist/UI/Components/CopyTextButton/CopyTextButton.js.map +1 -1
- package/build/dist/UI/Components/CustomFields/CustomFieldModelFormFields.js +5 -14
- package/build/dist/UI/Components/CustomFields/CustomFieldModelFormFields.js.map +1 -1
- package/build/dist/UI/Components/EditionLabel/EditionLabel.js +14 -13
- package/build/dist/UI/Components/EditionLabel/EditionLabel.js.map +1 -1
- package/build/dist/UI/Components/ErrorMessage/ErrorMessage.js +1 -1
- package/build/dist/UI/Components/ErrorMessage/ErrorMessage.js.map +1 -1
- package/build/dist/UI/Components/Forms/Fields/FormField.js +8 -3
- package/build/dist/UI/Components/Forms/Fields/FormField.js.map +1 -1
- package/build/dist/UI/Components/Icon/Icon.js +8 -0
- package/build/dist/UI/Components/Icon/Icon.js.map +1 -1
- package/build/dist/UI/Components/Input/Input.js +11 -3
- package/build/dist/UI/Components/Input/Input.js.map +1 -1
- package/build/dist/UI/Components/LogsViewer/LogsViewer.js +2 -1
- package/build/dist/UI/Components/LogsViewer/LogsViewer.js.map +1 -1
- package/build/dist/UI/Components/LogsViewer/components/LogsFacetSidebar.js +14 -4
- package/build/dist/UI/Components/LogsViewer/components/LogsFacetSidebar.js.map +1 -1
- package/build/dist/UI/Components/Markdown.tsx/MarkdownConverters.js +0 -0
- package/build/dist/UI/Components/Markdown.tsx/MarkdownConverters.js.map +1 -1
- package/build/dist/UI/Components/Markdown.tsx/MarkdownEditor.js +710 -65
- package/build/dist/UI/Components/Markdown.tsx/MarkdownEditor.js.map +1 -1
- package/build/dist/UI/Components/Markdown.tsx/MarkdownEditorHistory.js +238 -0
- package/build/dist/UI/Components/Markdown.tsx/MarkdownEditorHistory.js.map +1 -0
- package/build/dist/UI/Components/Markdown.tsx/MarkdownListEditing.js +1028 -0
- package/build/dist/UI/Components/Markdown.tsx/MarkdownListEditing.js.map +1 -0
- package/build/dist/UI/Components/Markdown.tsx/MarkdownPaste.js +1088 -0
- package/build/dist/UI/Components/Markdown.tsx/MarkdownPaste.js.map +1 -0
- package/build/dist/UI/Components/Markdown.tsx/MarkdownViewer.js +70 -10
- package/build/dist/UI/Components/Markdown.tsx/MarkdownViewer.js.map +1 -1
- package/build/dist/UI/Components/Markdown.tsx/MarkdownVisualEditing.js +887 -0
- package/build/dist/UI/Components/Markdown.tsx/MarkdownVisualEditing.js.map +1 -0
- package/build/dist/UI/Components/ModelTable/BaseModelTable.js +57 -6
- package/build/dist/UI/Components/ModelTable/BaseModelTable.js.map +1 -1
- package/build/dist/UI/Components/ResetObjectID/ResetObjectID.js +7 -5
- package/build/dist/UI/Components/ResetObjectID/ResetObjectID.js.map +1 -1
- package/build/dist/UI/Components/Table/EmptyTableMessage.js +51 -0
- package/build/dist/UI/Components/Table/EmptyTableMessage.js.map +1 -0
- package/build/dist/UI/Components/Table/Table.js +30 -11
- package/build/dist/UI/Components/Table/Table.js.map +1 -1
- package/build/dist/UI/Components/Table/TableRow.js +9 -2
- package/build/dist/UI/Components/Table/TableRow.js.map +1 -1
- package/build/dist/UI/Components/TelemetryViewer/FacetVisibility.js +63 -1
- package/build/dist/UI/Components/TelemetryViewer/FacetVisibility.js.map +1 -1
- package/build/dist/UI/Components/TelemetryViewer/TelemetryViewer.js +4 -2
- package/build/dist/UI/Components/TelemetryViewer/TelemetryViewer.js.map +1 -1
- package/build/dist/UI/Components/TelemetryViewer/components/LockedFilterChip.js +91 -10
- package/build/dist/UI/Components/TelemetryViewer/components/LockedFilterChip.js.map +1 -1
- package/build/dist/UI/Components/TelemetryViewer/components/TelemetryFacetSidebar.js +14 -4
- package/build/dist/UI/Components/TelemetryViewer/components/TelemetryFacetSidebar.js.map +1 -1
- package/build/dist/UI/Components/TextArea/TextArea.js +9 -3
- package/build/dist/UI/Components/TextArea/TextArea.js.map +1 -1
- package/build/dist/UI/Components/Workflow/ModelFieldPicker.js +1 -2
- package/build/dist/UI/Components/Workflow/ModelFieldPicker.js.map +1 -1
- package/build/dist/Utils/AI/InvestigationReport.js +71 -11
- package/build/dist/Utils/AI/InvestigationReport.js.map +1 -1
- package/build/dist/Utils/AiRemediation/Resource/CephCommandPolicy.js +1462 -0
- package/build/dist/Utils/AiRemediation/Resource/CephCommandPolicy.js.map +1 -0
- package/build/dist/Utils/AiRemediation/Resource/DatabaseCommandPolicy.js +122 -0
- package/build/dist/Utils/AiRemediation/Resource/DatabaseCommandPolicy.js.map +1 -0
- package/build/dist/Utils/AiRemediation/Resource/DatabaseDiagnosticCatalog.js +1139 -0
- package/build/dist/Utils/AiRemediation/Resource/DatabaseDiagnosticCatalog.js.map +1 -0
- package/build/dist/Utils/AiRemediation/Resource/DatabaseQueryRedactor.js +1060 -0
- package/build/dist/Utils/AiRemediation/Resource/DatabaseQueryRedactor.js.map +1 -0
- package/build/dist/Utils/AiRemediation/Resource/DockerCliGrammar.js +1301 -0
- package/build/dist/Utils/AiRemediation/Resource/DockerCliGrammar.js.map +1 -0
- package/build/dist/Utils/AiRemediation/Resource/DockerEngineCommandPolicy.js +370 -0
- package/build/dist/Utils/AiRemediation/Resource/DockerEngineCommandPolicy.js.map +1 -0
- package/build/dist/Utils/AiRemediation/Resource/DockerSwarmCommandPolicy.js +498 -0
- package/build/dist/Utils/AiRemediation/Resource/DockerSwarmCommandPolicy.js.map +1 -0
- package/build/dist/Utils/AiRemediation/Resource/GovcCommandPolicy.js +1565 -0
- package/build/dist/Utils/AiRemediation/Resource/GovcCommandPolicy.js.map +1 -0
- package/build/dist/Utils/AiRemediation/Resource/HostCommandPolicy.js +2206 -0
- package/build/dist/Utils/AiRemediation/Resource/HostCommandPolicy.js.map +1 -0
- package/build/dist/Utils/AiRemediation/Resource/ProxmoxCommandPolicy.js +1129 -0
- package/build/dist/Utils/AiRemediation/Resource/ProxmoxCommandPolicy.js.map +1 -0
- package/build/dist/Utils/AiRemediation/Resource/ResourceCommandPolicy.js +565 -0
- package/build/dist/Utils/AiRemediation/Resource/ResourceCommandPolicy.js.map +1 -0
- package/build/dist/Utils/AiRemediation/Resource/ResourceCommandPolicyCore.js +408 -0
- package/build/dist/Utils/AiRemediation/Resource/ResourceCommandPolicyCore.js.map +1 -0
- package/build/dist/Utils/AiRemediation/Resource/ResourceOutputRedactor.js +1910 -0
- package/build/dist/Utils/AiRemediation/Resource/ResourceOutputRedactor.js.map +1 -0
- package/build/dist/Utils/LabelRuleImportExport.js +2 -0
- package/build/dist/Utils/LabelRuleImportExport.js.map +1 -1
- package/build/dist/Utils/Markdown/UntrustedMarkdown.js +988 -0
- package/build/dist/Utils/Markdown/UntrustedMarkdown.js.map +1 -0
- package/build/dist/Utils/Monitor/IncomingEmailMonitorRequestUtil.js +34 -0
- package/build/dist/Utils/Monitor/IncomingEmailMonitorRequestUtil.js.map +1 -0
- package/build/dist/Utils/Monitor/MonitorLogSummaryUtil.js +148 -0
- package/build/dist/Utils/Monitor/MonitorLogSummaryUtil.js.map +1 -0
- package/build/dist/Utils/SessionReplay/SessionReplayBudgetMetricType.js +160 -0
- package/build/dist/Utils/SessionReplay/SessionReplayBudgetMetricType.js.map +1 -0
- package/build/dist/Utils/Telemetry/EntityKey.js +36 -0
- package/build/dist/Utils/Telemetry/EntityKey.js.map +1 -1
- package/package.json +1 -3
- package/Server/Utils/CommunityEditionSsoReport.ts +0 -361
- package/Tests/App/Accounts/LoginSsoEdition.test.tsx +0 -616
- package/Tests/App/AdminDashboard/AdminAuthenticationSsoEdition.test.tsx +0 -217
- package/Tests/App/AdminDashboard/GlobalSSOEnterpriseShells.test.tsx +0 -271
- package/Tests/App/Dashboard/CloudDocumentationMarkdown.test.ts +0 -215
- package/Tests/App/Dashboard/TelemetryResourceRetentionSettings.test.tsx +0 -784
- package/Tests/Server/Middleware/UserAuthorizationEditionEnforcement.test.ts +0 -518
- package/Tests/Server/Services/SsoRequirementReadMasking.test.ts +0 -419
- package/Tests/Server/Services/SsoRequirementWriteGuard.test.ts +0 -769
- package/Tests/UI/Components/CodeEditor.test.tsx +0 -638
- package/Tests/UI/Components/MonacoLoader.test.ts +0 -67
- package/Tests/UI/Components/MonacoRuntime.test.ts +0 -121
- package/Tests/UI/Components/Telemetry/TelemetryRetentionConfigForm.test.tsx +0 -329
- package/Tests/UI/Components/YamlEditor.test.tsx +0 -847
- package/UI/Components/CodeEditor/MonacoLoader.ts +0 -36
- package/UI/Components/Telemetry/TelemetryRetentionConfigForm.tsx +0 -319
- package/UI/Components/Telemetry/TelemetryRetentionConfigSummary.tsx +0 -223
- package/build/dist/Server/Utils/CommunityEditionSsoReport.js +0 -223
- package/build/dist/Server/Utils/CommunityEditionSsoReport.js.map +0 -1
- package/build/dist/UI/Components/CodeEditor/MonacoLoader.js +0 -34
- package/build/dist/UI/Components/CodeEditor/MonacoLoader.js.map +0 -1
- package/build/dist/UI/Components/Telemetry/TelemetryRetentionConfigForm.js +0 -171
- package/build/dist/UI/Components/Telemetry/TelemetryRetentionConfigForm.js.map +0 -1
- package/build/dist/UI/Components/Telemetry/TelemetryRetentionConfigSummary.js +0 -119
- package/build/dist/UI/Components/Telemetry/TelemetryRetentionConfigSummary.js.map +0 -1
|
@@ -0,0 +1,2019 @@
|
|
|
1
|
+
import HostCommandPolicy, {
|
|
2
|
+
HOST_COMMAND_PROGRAMS,
|
|
3
|
+
HOST_READABLE_FILES,
|
|
4
|
+
MAX_JOURNALCTL_LINES,
|
|
5
|
+
MAX_SYSTEMCTL_STATUS_LINES,
|
|
6
|
+
PROTECTED_HOST_UNIT_PATTERNS,
|
|
7
|
+
SYSTEMCTL_SHOW_PROPERTIES,
|
|
8
|
+
canonicalSystemdUnitName,
|
|
9
|
+
} from "../../../../Utils/AiRemediation/Resource/HostCommandPolicy";
|
|
10
|
+
import ResourceCommandPolicy from "../../../../Utils/AiRemediation/Resource/ResourceCommandPolicy";
|
|
11
|
+
import {
|
|
12
|
+
ResourceAutoExecutionVerdict,
|
|
13
|
+
ResourceCommandPolicyResult,
|
|
14
|
+
renderResourceDisplayCommand,
|
|
15
|
+
tokenizeResourceCommand,
|
|
16
|
+
} from "../../../../Utils/AiRemediation/Resource/ResourceCommandPolicyCore";
|
|
17
|
+
import {
|
|
18
|
+
RESOURCE_OUTPUT_REDACTION_HOOKS,
|
|
19
|
+
ResourceOutputRedaction,
|
|
20
|
+
ResourceOutputRedactionHook,
|
|
21
|
+
getResourceOutputRedactionHooks,
|
|
22
|
+
redactResourceCommandOutput,
|
|
23
|
+
redactResourceCommandOutputWithCount,
|
|
24
|
+
} from "../../../../Utils/AiRemediation/Resource/ResourceOutputRedactor";
|
|
25
|
+
import AiResourceType, {
|
|
26
|
+
AI_RESOURCE_TYPE_INFO,
|
|
27
|
+
} from "../../../../Types/ResourceAiAgent/AiResourceType";
|
|
28
|
+
import { ResourceCommandTier } from "../../../../Types/ResourceAiAgent/ResourceAiAccess";
|
|
29
|
+
import { AiRemediationCommandPolicyVerdict } from "../../../../Types/AutoRemediation/AiRemediationCommandPolicyVerdict";
|
|
30
|
+
import { describe, expect, test } from "@jest/globals";
|
|
31
|
+
|
|
32
|
+
/*
|
|
33
|
+
* Contract under test — HostCommandPolicy, the tool policy for Host
|
|
34
|
+
* resources (the host's own CLIs, run through nsenter by the Host AI agent).
|
|
35
|
+
*
|
|
36
|
+
* - Read: systemctl's read commands (show only with allowlisted -p
|
|
37
|
+
* properties), journalctl bounded by -n or --since, df, free, uptime, ps
|
|
38
|
+
* (never BSD `e`), top once in batch mode, ss, ip show/route get, dmesg,
|
|
39
|
+
* lsblk, cat of the allowlisted files, uname, hostnamectl, timedatectl.
|
|
40
|
+
* - SafeWrite: one service/socket/timer/path unit restarted, started,
|
|
41
|
+
* reloaded, try-restarted, reload-or-restarted or reset-failed.
|
|
42
|
+
* - RiskyWrite: stop, several units, reset-failed of every unit, journal
|
|
43
|
+
* vacuum. RiskyWrite + requiresHuman: protected units, target/mount/
|
|
44
|
+
* automount/swap units, kill.
|
|
45
|
+
* - Denied: everything else, with a reason naming what IS allowed.
|
|
46
|
+
* - Flags are read the way each program reads them, so combined flags,
|
|
47
|
+
* `=` forms, flags after positionals, duplicates, value-swallowing,
|
|
48
|
+
* quotes, look-alike characters, empty words and long input never hide
|
|
49
|
+
* a denied flag or target.
|
|
50
|
+
* - Targets are canonical (nginx -> nginx.service, pid:N, journal), and the
|
|
51
|
+
* dispatcher's ladder, allowlist and write scope work over them.
|
|
52
|
+
* - The ps/top output hook masks credentials on process command lines.
|
|
53
|
+
*/
|
|
54
|
+
|
|
55
|
+
function evaluate(command: string): ResourceCommandPolicyResult {
|
|
56
|
+
return ResourceCommandPolicy.evaluateCommand({
|
|
57
|
+
resourceType: AiResourceType.Host,
|
|
58
|
+
command,
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function argvOf(command: string): Array<string> {
|
|
63
|
+
const argv: Array<string> | undefined = tokenizeResourceCommand(command).argv;
|
|
64
|
+
|
|
65
|
+
if (!argv) {
|
|
66
|
+
throw new Error(`test command does not tokenize: ${command}`);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return argv;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function autoExecution(
|
|
73
|
+
command: string,
|
|
74
|
+
allowlistPatterns: Array<string> = [],
|
|
75
|
+
bypassApproval: boolean = false,
|
|
76
|
+
): ResourceAutoExecutionVerdict {
|
|
77
|
+
return ResourceCommandPolicy.evaluateForAutoExecution({
|
|
78
|
+
resourceType: AiResourceType.Host,
|
|
79
|
+
command,
|
|
80
|
+
allowlistPatterns,
|
|
81
|
+
bypassApproval,
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function writeScope(
|
|
86
|
+
command: string,
|
|
87
|
+
scope: {
|
|
88
|
+
allowWrites?: boolean;
|
|
89
|
+
writeTargets?: Array<string>;
|
|
90
|
+
protectedTargets?: Array<string>;
|
|
91
|
+
} = {},
|
|
92
|
+
): string | null {
|
|
93
|
+
return ResourceCommandPolicy.getWriteScopeRefusal({
|
|
94
|
+
result: evaluate(command),
|
|
95
|
+
allowWrites: scope.allowWrites ?? true,
|
|
96
|
+
writeTargets: scope.writeTargets ?? [],
|
|
97
|
+
protectedTargets: scope.protectedTargets ?? [],
|
|
98
|
+
resourceType: AiResourceType.Host,
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// Every backticked example in a guide that starts with a host program.
|
|
103
|
+
function guideExamples(guide: string): Array<string> {
|
|
104
|
+
const examples: Array<string> = [];
|
|
105
|
+
const regex: RegExp = /`([^`]+)`/g;
|
|
106
|
+
let match: RegExpExecArray | null = regex.exec(guide);
|
|
107
|
+
|
|
108
|
+
while (match) {
|
|
109
|
+
const snippet: string = match[1] || "";
|
|
110
|
+
const program: string = snippet.split(" ")[0] || "";
|
|
111
|
+
|
|
112
|
+
if (HOST_COMMAND_PROGRAMS.includes(program)) {
|
|
113
|
+
examples.push(snippet);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
match = regex.exec(guide);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
return examples;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
describe("the module", () => {
|
|
123
|
+
test("is the host policy the dispatcher routes Host resources to", () => {
|
|
124
|
+
expect(HostCommandPolicy.name).toBe("host");
|
|
125
|
+
expect(ResourceCommandPolicy.getToolPolicy(AiResourceType.Host)).toBe(
|
|
126
|
+
HostCommandPolicy,
|
|
127
|
+
);
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
test("covers exactly the Host type's programs, timedatectl included", () => {
|
|
131
|
+
expect([...HostCommandPolicy.programs]).toEqual([
|
|
132
|
+
...AI_RESOURCE_TYPE_INFO[AiResourceType.Host].programs,
|
|
133
|
+
]);
|
|
134
|
+
expect([...HOST_COMMAND_PROGRAMS]).toEqual([...HostCommandPolicy.programs]);
|
|
135
|
+
expect(HostCommandPolicy.programs).toContain("timedatectl");
|
|
136
|
+
expect(HostCommandPolicy.programs).toHaveLength(16);
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
test("every Test connection command is Read", () => {
|
|
140
|
+
for (const command of AI_RESOURCE_TYPE_INFO[AiResourceType.Host]
|
|
141
|
+
.testCommands) {
|
|
142
|
+
expect(evaluate(command).tier).toBe(ResourceCommandTier.Read);
|
|
143
|
+
expect(
|
|
144
|
+
ResourceCommandPolicy.isReadOnly({
|
|
145
|
+
resourceType: AiResourceType.Host,
|
|
146
|
+
command,
|
|
147
|
+
}),
|
|
148
|
+
).toBe(true);
|
|
149
|
+
}
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
test("pins the limits and the allowlists the guides describe", () => {
|
|
153
|
+
expect(MAX_JOURNALCTL_LINES).toBe(2000);
|
|
154
|
+
expect(MAX_SYSTEMCTL_STATUS_LINES).toBe(200);
|
|
155
|
+
expect(SYSTEMCTL_SHOW_PROPERTIES).not.toContain("Environment");
|
|
156
|
+
expect(SYSTEMCTL_SHOW_PROPERTIES).not.toContain("EnvironmentFiles");
|
|
157
|
+
expect(SYSTEMCTL_SHOW_PROPERTIES).toContain("NRestarts");
|
|
158
|
+
expect(HOST_READABLE_FILES).toContain("/proc/loadavg");
|
|
159
|
+
expect(HOST_READABLE_FILES).toContain("/etc/os-release");
|
|
160
|
+
expect(HOST_READABLE_FILES).not.toContain("/etc/shadow");
|
|
161
|
+
expect(PROTECTED_HOST_UNIT_PATTERNS).toEqual(
|
|
162
|
+
expect.arrayContaining(["sshd", "systemd-*", "docker", "ufw"]),
|
|
163
|
+
);
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
test("the guides are compact markdown bullets naming the rules", () => {
|
|
167
|
+
const read: string = HostCommandPolicy.readCommandGuide;
|
|
168
|
+
const write: string = HostCommandPolicy.writeCommandGuide;
|
|
169
|
+
|
|
170
|
+
for (const line of [...read.split("\n"), ...write.split("\n")]) {
|
|
171
|
+
expect(line.startsWith("- ")).toBe(true);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
for (const program of HOST_COMMAND_PROGRAMS.filter((name: string) => {
|
|
175
|
+
return name !== "kill";
|
|
176
|
+
})) {
|
|
177
|
+
expect(read).toContain(program);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
expect(read).toContain("never -f");
|
|
181
|
+
expect(read).toContain(String(MAX_JOURNALCTL_LINES));
|
|
182
|
+
expect(read).toContain("never Environment");
|
|
183
|
+
expect(write).toContain("SafeWrite");
|
|
184
|
+
expect(write).toContain("RiskyWrite");
|
|
185
|
+
expect(write).toContain("Always a human");
|
|
186
|
+
expect(write).toContain("Never");
|
|
187
|
+
expect(write).toContain("kill");
|
|
188
|
+
expect(write).toContain("nginx.service");
|
|
189
|
+
expect(ResourceCommandPolicy.getReadCommandGuide(AiResourceType.Host)).toBe(
|
|
190
|
+
read,
|
|
191
|
+
);
|
|
192
|
+
expect(
|
|
193
|
+
ResourceCommandPolicy.getWriteCommandGuide(AiResourceType.Host),
|
|
194
|
+
).toBe(write);
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
test("every concrete example in the read guide is Read", () => {
|
|
198
|
+
const examples: Array<string> = guideExamples(
|
|
199
|
+
HostCommandPolicy.readCommandGuide,
|
|
200
|
+
)
|
|
201
|
+
.filter((snippet: string): boolean => {
|
|
202
|
+
return !snippet.includes("|");
|
|
203
|
+
})
|
|
204
|
+
.map((snippet: string): string => {
|
|
205
|
+
return snippet.replace(/\bUNIT\b/g, "nginx.service");
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
expect(examples.length).toBeGreaterThan(20);
|
|
209
|
+
|
|
210
|
+
for (const example of examples) {
|
|
211
|
+
expect([example, evaluate(example).tier]).toEqual([
|
|
212
|
+
example,
|
|
213
|
+
ResourceCommandTier.Read,
|
|
214
|
+
]);
|
|
215
|
+
}
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
test("every concrete example in the write guide is a write", () => {
|
|
219
|
+
const examples: Array<string> = guideExamples(
|
|
220
|
+
HostCommandPolicy.writeCommandGuide,
|
|
221
|
+
)
|
|
222
|
+
.filter((snippet: string): boolean => {
|
|
223
|
+
return !snippet.includes("|") && !snippet.includes("[");
|
|
224
|
+
})
|
|
225
|
+
.map((snippet: string): string => {
|
|
226
|
+
return snippet.replace(/\bUNIT\b/g, "nginx.service");
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
expect(examples.length).toBeGreaterThanOrEqual(3);
|
|
230
|
+
|
|
231
|
+
for (const example of examples) {
|
|
232
|
+
expect([
|
|
233
|
+
ResourceCommandTier.SafeWrite,
|
|
234
|
+
ResourceCommandTier.RiskyWrite,
|
|
235
|
+
]).toContain(evaluate(example).tier);
|
|
236
|
+
}
|
|
237
|
+
});
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
describe("Read commands", () => {
|
|
241
|
+
test.each([
|
|
242
|
+
// systemctl
|
|
243
|
+
["systemctl status nginx", "status"],
|
|
244
|
+
["systemctl status nginx.service --no-pager", "status"],
|
|
245
|
+
["systemctl status", "status"],
|
|
246
|
+
["systemctl status nginx -n 50 --no-pager -l", "status"],
|
|
247
|
+
["systemctl status nginx -n50", "status"],
|
|
248
|
+
["systemctl status nginx --lines=200", "status"],
|
|
249
|
+
["systemctl status nginx -n 0", "status"],
|
|
250
|
+
["systemctl status nginx -o cat", "status"],
|
|
251
|
+
["systemctl status nginx --output=json", "status"],
|
|
252
|
+
["systemctl status getty@tty1.service postgresql", "status"],
|
|
253
|
+
[
|
|
254
|
+
"systemctl status 'systemd-fsck@dev-disk-by\\x2duuid-1234.service'",
|
|
255
|
+
"status",
|
|
256
|
+
],
|
|
257
|
+
["systemctl --no-pager status nginx", "status"],
|
|
258
|
+
["systemctl --no-pager --no-pager status nginx", "status"],
|
|
259
|
+
["systemctl status -- nginx", "status"],
|
|
260
|
+
["systemctl is-active nginx", "is-active"],
|
|
261
|
+
["systemctl is-active --quiet nginx", "is-active"],
|
|
262
|
+
["systemctl is-failed nginx postgresql", "is-failed"],
|
|
263
|
+
["systemctl is-enabled nginx", "is-enabled"],
|
|
264
|
+
["systemctl is-system-running", "is-system-running"],
|
|
265
|
+
["systemctl list-units --failed --no-pager", "list-units"],
|
|
266
|
+
[
|
|
267
|
+
"systemctl list-units --type=service --state=failed,running --all",
|
|
268
|
+
"list-units",
|
|
269
|
+
],
|
|
270
|
+
["systemctl list-units --type service --plain --no-legend", "list-units"],
|
|
271
|
+
["systemctl list-units 'nginx*' 'php?-fpm*'", "list-units"],
|
|
272
|
+
["systemctl list-units --state=failed --state=activating", "list-units"],
|
|
273
|
+
["systemctl list-units -o json", "list-units"],
|
|
274
|
+
["systemctl", "list-units"],
|
|
275
|
+
["systemctl --failed", "list-units"],
|
|
276
|
+
["systemctl -t service", "list-units"],
|
|
277
|
+
["systemctl list-unit-files --state=enabled", "list-unit-files"],
|
|
278
|
+
["systemctl list-timers --all", "list-timers"],
|
|
279
|
+
["systemctl list-sockets", "list-sockets"],
|
|
280
|
+
["systemctl list-jobs", "list-jobs"],
|
|
281
|
+
["systemctl list-dependencies nginx", "list-dependencies"],
|
|
282
|
+
["systemctl list-dependencies --reverse nginx", "list-dependencies"],
|
|
283
|
+
["systemctl list-dependencies", "list-dependencies"],
|
|
284
|
+
["systemctl show nginx -p ActiveState", "show"],
|
|
285
|
+
["systemctl show nginx -p ActiveState,SubState,Result,NRestarts", "show"],
|
|
286
|
+
[
|
|
287
|
+
"systemctl show nginx --property=MainPID --property=MemoryCurrent",
|
|
288
|
+
"show",
|
|
289
|
+
],
|
|
290
|
+
["systemctl show nginx -pActiveState --value", "show"],
|
|
291
|
+
["systemctl show nginx -P ActiveState", "show"],
|
|
292
|
+
["systemctl --no-pager show nginx redis -p Id", "show"],
|
|
293
|
+
[`systemctl show nginx -p ${SYSTEMCTL_SHOW_PROPERTIES.join(",")}`, "show"],
|
|
294
|
+
// journalctl
|
|
295
|
+
["journalctl -u nginx -n 200 --no-pager", "logs"],
|
|
296
|
+
["journalctl -u nginx.service -n 50", "logs"],
|
|
297
|
+
["journalctl -n", "logs"],
|
|
298
|
+
["journalctl -n -u nginx", "logs"],
|
|
299
|
+
["journalctl -n50 -u nginx", "logs"],
|
|
300
|
+
["journalctl --lines=2000", "logs"],
|
|
301
|
+
["journalctl --lines 100 -u nginx", "logs"],
|
|
302
|
+
["journalctl -n +20", "logs"],
|
|
303
|
+
["journalctl -u nginx --since '1 hour ago'", "logs"],
|
|
304
|
+
["journalctl --since=-1h -p err", "logs"],
|
|
305
|
+
["journalctl --since -1h", "logs"],
|
|
306
|
+
["journalctl -S yesterday -U today", "logs"],
|
|
307
|
+
[
|
|
308
|
+
"journalctl --since '2024-05-01 10:00:00' --until '2024-05-01 11:00'",
|
|
309
|
+
"logs",
|
|
310
|
+
],
|
|
311
|
+
["journalctl --since @1714550400", "logs"],
|
|
312
|
+
["journalctl -k -n 100", "logs"],
|
|
313
|
+
["journalctl -kn 20", "logs"],
|
|
314
|
+
["journalctl -rn20", "logs"],
|
|
315
|
+
["journalctl -b -1 -n 100", "logs"],
|
|
316
|
+
["journalctl -b -n 100", "logs"],
|
|
317
|
+
["journalctl -b-1 -n 100", "logs"],
|
|
318
|
+
["journalctl --boot=0 -n 10", "logs"],
|
|
319
|
+
["journalctl -b all -n 10", "logs"],
|
|
320
|
+
["journalctl -b 0123456789abcdef0123456789abcdef -n 10", "logs"],
|
|
321
|
+
["journalctl -b 0123456789abcdef0123456789abcdef-1 -n 10", "logs"],
|
|
322
|
+
["journalctl -p err..warning -n 100", "logs"],
|
|
323
|
+
["journalctl -p 3 -n 10", "logs"],
|
|
324
|
+
["journalctl -g 'timeout|refused' -n 100", "logs"],
|
|
325
|
+
["journalctl -o short-iso -n 10 --utc", "logs"],
|
|
326
|
+
["journalctl -o json -n 10", "logs"],
|
|
327
|
+
["journalctl -o with-unit -n 10", "logs"],
|
|
328
|
+
["journalctl -r -n 20 -x -q --no-hostname", "logs"],
|
|
329
|
+
["journalctl -t sshd -n 20", "logs"],
|
|
330
|
+
["journalctl -u nginx -u php-fpm -n 20", "logs"],
|
|
331
|
+
["journalctl -u 'nginx*' -n 20", "logs"],
|
|
332
|
+
["journalctl --list-boots", "list-boots"],
|
|
333
|
+
["journalctl --disk-usage", "disk-usage"],
|
|
334
|
+
// df, free, uptime, uname
|
|
335
|
+
["df", "df"],
|
|
336
|
+
["df -h", "df"],
|
|
337
|
+
["df -hT", "df"],
|
|
338
|
+
["df -i /var", "df"],
|
|
339
|
+
["df -x tmpfs -x devtmpfs -h", "df"],
|
|
340
|
+
["df --exclude-type=overlay --total -h", "df"],
|
|
341
|
+
["df -t ext4 -P /", "df"],
|
|
342
|
+
["df -k /var/lib/docker", "df"],
|
|
343
|
+
["free", "free"],
|
|
344
|
+
["free -m", "free"],
|
|
345
|
+
["free -h -w", "free"],
|
|
346
|
+
["free --si -t", "free"],
|
|
347
|
+
["uptime", "uptime"],
|
|
348
|
+
["uptime -p", "uptime"],
|
|
349
|
+
["uptime --since", "uptime"],
|
|
350
|
+
["uname", "uname"],
|
|
351
|
+
["uname -a", "uname"],
|
|
352
|
+
["uname -rsm", "uname"],
|
|
353
|
+
["uname --kernel-release", "uname"],
|
|
354
|
+
// ps, top
|
|
355
|
+
["ps", "ps"],
|
|
356
|
+
["ps aux", "ps"],
|
|
357
|
+
["ps auxww", "ps"],
|
|
358
|
+
["ps auxf", "ps"],
|
|
359
|
+
["ps axo pid,ppid,comm", "ps"],
|
|
360
|
+
["ps axopid,comm", "ps"],
|
|
361
|
+
["ps aux --sort=-%cpu", "ps"],
|
|
362
|
+
["ps aux --sort -%mem", "ps"],
|
|
363
|
+
["ps -ef", "ps"],
|
|
364
|
+
["ps -eo pid,ppid,user,%cpu,%mem,etime,stat,args --sort=-%mem", "ps"],
|
|
365
|
+
["ps -p 1234 -o pid,args", "ps"],
|
|
366
|
+
["ps -p1234,5678", "ps"],
|
|
367
|
+
["ps -u root", "ps"],
|
|
368
|
+
["ps -C nginx -L", "ps"],
|
|
369
|
+
["ps -eLf", "ps"],
|
|
370
|
+
["ps -e --no-headers -o pid", "ps"],
|
|
371
|
+
["ps -e --forest", "ps"],
|
|
372
|
+
["ps -eo pid,args:50", "ps"],
|
|
373
|
+
["ps -o 'pid comm'", "ps"],
|
|
374
|
+
["ps -e -o pid=,comm=", "ps"],
|
|
375
|
+
["ps -eww -o args", "ps"],
|
|
376
|
+
["ps -A -F -H", "ps"],
|
|
377
|
+
["top -b -n 1", "top"],
|
|
378
|
+
["top -bn1", "top"],
|
|
379
|
+
["top -b -n1 -o %MEM", "top"],
|
|
380
|
+
["top -b -n 1 -o -PID", "top"],
|
|
381
|
+
["top -b -n 1 -c -w 200", "top"],
|
|
382
|
+
["top -b -n 1 -w200", "top"],
|
|
383
|
+
["top -b -n 1 -w", "top"],
|
|
384
|
+
["top --batch-mode --iterations=1", "top"],
|
|
385
|
+
["top -H -b -n 1", "top"],
|
|
386
|
+
// ss, ip
|
|
387
|
+
["ss -tulpn", "ss"],
|
|
388
|
+
["ss -s", "ss"],
|
|
389
|
+
["ss -tn state established", "ss"],
|
|
390
|
+
["ss -tlnp sport = :443", "ss"],
|
|
391
|
+
["ss -tan '( dport = :443 or sport = :443 )'", "ss"],
|
|
392
|
+
["ss -x -a", "ss"],
|
|
393
|
+
["ss -4 -t -i -m -o -e", "ss"],
|
|
394
|
+
["ss -H -t --numeric", "ss"],
|
|
395
|
+
["ip -br addr", "address show"],
|
|
396
|
+
["ip addr", "address show"],
|
|
397
|
+
["ip a", "address show"],
|
|
398
|
+
["ip addr show", "address show"],
|
|
399
|
+
["ip addr show dev eth0", "address show"],
|
|
400
|
+
["ip -4 addr show eth0", "address show"],
|
|
401
|
+
["ip address list", "address show"],
|
|
402
|
+
["ip link", "link show"],
|
|
403
|
+
["ip l", "link show"],
|
|
404
|
+
["ip -s link", "link show"],
|
|
405
|
+
["ip -s -s link show eth0", "link show"],
|
|
406
|
+
["ip -d link show", "link show"],
|
|
407
|
+
["ip --brief link", "link show"],
|
|
408
|
+
["ip route", "route show"],
|
|
409
|
+
["ip r", "route show"],
|
|
410
|
+
["ip route show table all", "route show"],
|
|
411
|
+
["ip route list", "route show"],
|
|
412
|
+
["ip -6 route ls", "route show"],
|
|
413
|
+
["ip -json route", "route show"],
|
|
414
|
+
["ip route get 1.1.1.1", "route get"],
|
|
415
|
+
["ip route get 2001:db8::1", "route get"],
|
|
416
|
+
["ip -j route get 10.0.0.5", "route get"],
|
|
417
|
+
["ip neigh", "neigh show"],
|
|
418
|
+
["ip neighbour show", "neigh show"],
|
|
419
|
+
["ip n", "neigh show"],
|
|
420
|
+
["ip rule", "rule show"],
|
|
421
|
+
["ip ru list", "rule show"],
|
|
422
|
+
["ip -j -p addr", "address show"],
|
|
423
|
+
// dmesg, lsblk
|
|
424
|
+
["dmesg", "dmesg"],
|
|
425
|
+
["dmesg -T", "dmesg"],
|
|
426
|
+
["dmesg --ctime --level=err,warn", "dmesg"],
|
|
427
|
+
["dmesg -l err", "dmesg"],
|
|
428
|
+
["dmesg -Tx", "dmesg"],
|
|
429
|
+
["dmesg -k -t", "dmesg"],
|
|
430
|
+
["dmesg --level err+", "dmesg"],
|
|
431
|
+
["lsblk", "lsblk"],
|
|
432
|
+
["lsblk -f", "lsblk"],
|
|
433
|
+
["lsblk -o NAME,SIZE,TYPE,MOUNTPOINTS,FSUSE%", "lsblk"],
|
|
434
|
+
["lsblk -J -b -p", "lsblk"],
|
|
435
|
+
["lsblk -dn", "lsblk"],
|
|
436
|
+
["lsblk /dev/sda", "lsblk"],
|
|
437
|
+
["lsblk -l -a /dev/nvme0n1 /dev/mapper/vg-root", "lsblk"],
|
|
438
|
+
// cat, hostnamectl, timedatectl
|
|
439
|
+
["cat /proc/loadavg", "cat"],
|
|
440
|
+
["cat /proc/meminfo /proc/loadavg", "cat"],
|
|
441
|
+
[`cat ${HOST_READABLE_FILES.join(" ")}`, "cat"],
|
|
442
|
+
["hostnamectl", "status"],
|
|
443
|
+
["hostnamectl status", "status"],
|
|
444
|
+
["timedatectl", "status"],
|
|
445
|
+
["timedatectl status", "status"],
|
|
446
|
+
["timedatectl show", "show"],
|
|
447
|
+
["timedatectl timesync-status", "timesync-status"],
|
|
448
|
+
])("%s is Read (%s)", (command: string, verb: string) => {
|
|
449
|
+
const argv: Array<string> = argvOf(command);
|
|
450
|
+
const result: ResourceCommandPolicyResult = evaluate(command);
|
|
451
|
+
|
|
452
|
+
expect([command, result.tier, result.reason]).toEqual([
|
|
453
|
+
command,
|
|
454
|
+
ResourceCommandTier.Read,
|
|
455
|
+
expect.any(String),
|
|
456
|
+
]);
|
|
457
|
+
expect(result.verb).toBe(verb);
|
|
458
|
+
expect(result.program).toBe(argv[0]);
|
|
459
|
+
expect(result.args).toEqual(argv.slice(1));
|
|
460
|
+
expect(result.targets).toEqual([]);
|
|
461
|
+
expect(result.requiresHuman).toBeUndefined();
|
|
462
|
+
expect(result.displayCommand).toBe(renderResourceDisplayCommand(argv));
|
|
463
|
+
expect(tokenizeResourceCommand(result.displayCommand).argv).toEqual(argv);
|
|
464
|
+
});
|
|
465
|
+
|
|
466
|
+
test.each(
|
|
467
|
+
HOST_READABLE_FILES.map((file: string) => {
|
|
468
|
+
return [file];
|
|
469
|
+
}),
|
|
470
|
+
)("cat %s is Read", (file: string) => {
|
|
471
|
+
expect(evaluate(`cat ${file}`).tier).toBe(ResourceCommandTier.Read);
|
|
472
|
+
});
|
|
473
|
+
|
|
474
|
+
test("a read never names a target, even one that looks like a unit", () => {
|
|
475
|
+
expect(evaluate("systemctl status sshd").targets).toEqual([]);
|
|
476
|
+
expect(evaluate("journalctl -u docker -n 10").targets).toEqual([]);
|
|
477
|
+
});
|
|
478
|
+
});
|
|
479
|
+
|
|
480
|
+
describe("SafeWrite: a reversible change to exactly one unit", () => {
|
|
481
|
+
test.each([
|
|
482
|
+
["systemctl restart nginx", "restart", ["nginx.service"]],
|
|
483
|
+
["systemctl restart nginx.service", "restart", ["nginx.service"]],
|
|
484
|
+
["systemctl start nginx", "start", ["nginx.service"]],
|
|
485
|
+
["systemctl reload nginx", "reload", ["nginx.service"]],
|
|
486
|
+
["systemctl try-restart nginx", "try-restart", ["nginx.service"]],
|
|
487
|
+
[
|
|
488
|
+
"systemctl reload-or-restart nginx",
|
|
489
|
+
"reload-or-restart",
|
|
490
|
+
["nginx.service"],
|
|
491
|
+
],
|
|
492
|
+
["systemctl reset-failed nginx", "reset-failed", ["nginx.service"]],
|
|
493
|
+
["systemctl restart --no-pager nginx", "restart", ["nginx.service"]],
|
|
494
|
+
["systemctl -q restart nginx", "restart", ["nginx.service"]],
|
|
495
|
+
["systemctl restart nginx --quiet", "restart", ["nginx.service"]],
|
|
496
|
+
["systemctl restart nginx nginx.service", "restart", ["nginx.service"]],
|
|
497
|
+
["systemctl restart backup.timer", "restart", ["backup.timer"]],
|
|
498
|
+
["systemctl restart cups.socket", "restart", ["cups.socket"]],
|
|
499
|
+
["systemctl start app.path", "start", ["app.path"]],
|
|
500
|
+
["systemctl restart worker@2", "restart", ["worker@2.service"]],
|
|
501
|
+
["systemctl restart php8.2-fpm", "restart", ["php8.2-fpm.service"]],
|
|
502
|
+
["systemctl restart -- nginx", "restart", ["nginx.service"]],
|
|
503
|
+
["systemctl reset-failed home.mount", "reset-failed", ["home.mount"]],
|
|
504
|
+
[`systemctl "restart" "nginx"`, "restart", ["nginx.service"]],
|
|
505
|
+
["systemctl 're''start' nginx", "restart", ["nginx.service"]],
|
|
506
|
+
])(
|
|
507
|
+
"%s is SafeWrite (%s %j)",
|
|
508
|
+
(command: string, verb: string, targets: Array<string>) => {
|
|
509
|
+
const result: ResourceCommandPolicyResult = evaluate(command);
|
|
510
|
+
|
|
511
|
+
expect([command, result.tier]).toEqual([
|
|
512
|
+
command,
|
|
513
|
+
ResourceCommandTier.SafeWrite,
|
|
514
|
+
]);
|
|
515
|
+
expect(result.verb).toBe(verb);
|
|
516
|
+
expect(result.targets).toEqual(targets);
|
|
517
|
+
expect(result.requiresHuman).toBeUndefined();
|
|
518
|
+
expect(result.reason).toContain("one unit");
|
|
519
|
+
expect(result.args).toEqual(argvOf(command).slice(1));
|
|
520
|
+
},
|
|
521
|
+
);
|
|
522
|
+
});
|
|
523
|
+
|
|
524
|
+
describe("RiskyWrite without a mandatory human", () => {
|
|
525
|
+
test.each([
|
|
526
|
+
["systemctl stop nginx", ["nginx.service"]],
|
|
527
|
+
["systemctl stop backup.timer", ["backup.timer"]],
|
|
528
|
+
["systemctl restart nginx php-fpm", ["nginx.service", "php-fpm.service"]],
|
|
529
|
+
["systemctl start a b c.socket", ["a.service", "b.service", "c.socket"]],
|
|
530
|
+
["systemctl stop nginx php-fpm", ["nginx.service", "php-fpm.service"]],
|
|
531
|
+
["systemctl reset-failed", []],
|
|
532
|
+
["systemctl reset-failed nginx redis", ["nginx.service", "redis.service"]],
|
|
533
|
+
["journalctl --vacuum-time=7d", ["journal"]],
|
|
534
|
+
["journalctl --vacuum-size=500M", ["journal"]],
|
|
535
|
+
["journalctl --vacuum-files 5", ["journal"]],
|
|
536
|
+
["journalctl --vacuum-time 12h -q", ["journal"]],
|
|
537
|
+
[
|
|
538
|
+
"journalctl --vacuum-time=2weeks --vacuum-size=1G --no-pager",
|
|
539
|
+
["journal"],
|
|
540
|
+
],
|
|
541
|
+
])("%s is RiskyWrite %j", (command: string, targets: Array<string>) => {
|
|
542
|
+
const result: ResourceCommandPolicyResult = evaluate(command);
|
|
543
|
+
|
|
544
|
+
expect([command, result.tier]).toEqual([
|
|
545
|
+
command,
|
|
546
|
+
ResourceCommandTier.RiskyWrite,
|
|
547
|
+
]);
|
|
548
|
+
expect(result.targets).toEqual(targets);
|
|
549
|
+
expect(result.requiresHuman).toBeUndefined();
|
|
550
|
+
});
|
|
551
|
+
|
|
552
|
+
test("a vacuum is labelled and explained", () => {
|
|
553
|
+
const result: ResourceCommandPolicyResult = evaluate(
|
|
554
|
+
"journalctl --vacuum-time=7d",
|
|
555
|
+
);
|
|
556
|
+
|
|
557
|
+
expect(result.verb).toBe("vacuum");
|
|
558
|
+
expect(result.reason).toContain("permanently deletes archived journal");
|
|
559
|
+
});
|
|
560
|
+
|
|
561
|
+
test("stop explains that the unit stays down", () => {
|
|
562
|
+
expect(evaluate("systemctl stop nginx").reason).toContain("stays down");
|
|
563
|
+
});
|
|
564
|
+
|
|
565
|
+
test("several units explain why they need approval", () => {
|
|
566
|
+
expect(evaluate("systemctl restart a b").reason).toContain(
|
|
567
|
+
"more than one unit",
|
|
568
|
+
);
|
|
569
|
+
});
|
|
570
|
+
});
|
|
571
|
+
|
|
572
|
+
describe("RiskyWrite that always needs a human", () => {
|
|
573
|
+
test.each([
|
|
574
|
+
["systemctl restart sshd", ["sshd.service"], "protected"],
|
|
575
|
+
["systemctl restart ssh.socket", ["ssh.socket"], "protected"],
|
|
576
|
+
["systemctl stop ssh", ["ssh.service"], "protected"],
|
|
577
|
+
[
|
|
578
|
+
"systemctl restart sshd@1-10.0.0.1:22",
|
|
579
|
+
["sshd@1-10.0.0.1:22.service"],
|
|
580
|
+
"protected",
|
|
581
|
+
],
|
|
582
|
+
[
|
|
583
|
+
"systemctl restart systemd-resolved",
|
|
584
|
+
["systemd-resolved.service"],
|
|
585
|
+
"protected",
|
|
586
|
+
],
|
|
587
|
+
[
|
|
588
|
+
"systemctl restart systemd-networkd",
|
|
589
|
+
["systemd-networkd.service"],
|
|
590
|
+
"protected",
|
|
591
|
+
],
|
|
592
|
+
[
|
|
593
|
+
"systemctl restart systemd-journald",
|
|
594
|
+
["systemd-journald.service"],
|
|
595
|
+
"protected",
|
|
596
|
+
],
|
|
597
|
+
["systemctl restart dbus", ["dbus.service"], "protected"],
|
|
598
|
+
["systemctl restart dbus-broker", ["dbus-broker.service"], "protected"],
|
|
599
|
+
["systemctl reload polkit", ["polkit.service"], "protected"],
|
|
600
|
+
[
|
|
601
|
+
"systemctl restart NetworkManager",
|
|
602
|
+
["NetworkManager.service"],
|
|
603
|
+
"protected",
|
|
604
|
+
],
|
|
605
|
+
[
|
|
606
|
+
"systemctl restart networkmanager",
|
|
607
|
+
["networkmanager.service"],
|
|
608
|
+
"protected",
|
|
609
|
+
],
|
|
610
|
+
["systemctl restart networking", ["networking.service"], "protected"],
|
|
611
|
+
["systemctl restart getty@tty1", ["getty@tty1.service"], "protected"],
|
|
612
|
+
[
|
|
613
|
+
"systemctl restart serial-getty@ttyS0",
|
|
614
|
+
["serial-getty@ttyS0.service"],
|
|
615
|
+
"protected",
|
|
616
|
+
],
|
|
617
|
+
// the aliases systemd ships for protected units
|
|
618
|
+
["systemctl restart autovt@tty1", ["autovt@tty1.service"], "protected"],
|
|
619
|
+
["systemctl restart udev", ["udev.service"], "protected"],
|
|
620
|
+
[
|
|
621
|
+
"systemctl restart container-getty@1",
|
|
622
|
+
["container-getty@1.service"],
|
|
623
|
+
"protected",
|
|
624
|
+
],
|
|
625
|
+
[
|
|
626
|
+
"systemctl restart dbus-org.freedesktop.login1",
|
|
627
|
+
["dbus-org.freedesktop.login1.service"],
|
|
628
|
+
"protected",
|
|
629
|
+
],
|
|
630
|
+
// package upgrades: they install packages and may reboot the host
|
|
631
|
+
[
|
|
632
|
+
"systemctl start apt-daily-upgrade",
|
|
633
|
+
["apt-daily-upgrade.service"],
|
|
634
|
+
"protected",
|
|
635
|
+
],
|
|
636
|
+
[
|
|
637
|
+
"systemctl start unattended-upgrades",
|
|
638
|
+
["unattended-upgrades.service"],
|
|
639
|
+
"protected",
|
|
640
|
+
],
|
|
641
|
+
[
|
|
642
|
+
"systemctl start dnf-automatic-install.service",
|
|
643
|
+
["dnf-automatic-install.service"],
|
|
644
|
+
"protected",
|
|
645
|
+
],
|
|
646
|
+
[
|
|
647
|
+
"systemctl start packagekit-offline-update",
|
|
648
|
+
["packagekit-offline-update.service"],
|
|
649
|
+
"protected",
|
|
650
|
+
],
|
|
651
|
+
["systemctl restart docker", ["docker.service"], "protected"],
|
|
652
|
+
["systemctl stop docker.socket", ["docker.socket"], "protected"],
|
|
653
|
+
["systemctl restart containerd", ["containerd.service"], "protected"],
|
|
654
|
+
["systemctl restart podman", ["podman.service"], "protected"],
|
|
655
|
+
["systemctl restart kubelet", ["kubelet.service"], "protected"],
|
|
656
|
+
["systemctl restart firewalld", ["firewalld.service"], "protected"],
|
|
657
|
+
["systemctl stop nftables", ["nftables.service"], "protected"],
|
|
658
|
+
["systemctl stop iptables", ["iptables.service"], "protected"],
|
|
659
|
+
["systemctl stop ufw", ["ufw.service"], "protected"],
|
|
660
|
+
["systemctl restart user@1000", ["user@1000.service"], "protected"],
|
|
661
|
+
["systemctl reset-failed sshd", ["sshd.service"], "protected"],
|
|
662
|
+
[
|
|
663
|
+
"systemctl restart nginx sshd",
|
|
664
|
+
["nginx.service", "sshd.service"],
|
|
665
|
+
"protected",
|
|
666
|
+
],
|
|
667
|
+
[
|
|
668
|
+
"systemctl restart network-online.target",
|
|
669
|
+
["network-online.target"],
|
|
670
|
+
"target",
|
|
671
|
+
],
|
|
672
|
+
["systemctl start multi-user.target", ["multi-user.target"], "target"],
|
|
673
|
+
["systemctl stop home.mount", ["home.mount"], "mount"],
|
|
674
|
+
["systemctl restart data.automount", ["data.automount"], "automount"],
|
|
675
|
+
["systemctl stop swapfile.swap", ["swapfile.swap"], "swap"],
|
|
676
|
+
["kill 1234", ["pid:1234"], "SIGTERM"],
|
|
677
|
+
["kill -TERM 1234", ["pid:1234"], "SIGTERM"],
|
|
678
|
+
["kill -SIGTERM 1234", ["pid:1234"], "SIGTERM"],
|
|
679
|
+
["kill -15 1234", ["pid:1234"], "SIGTERM"],
|
|
680
|
+
["kill -s TERM 1234", ["pid:1234"], "SIGTERM"],
|
|
681
|
+
["kill -HUP 1234", ["pid:1234"], "SIGHUP"],
|
|
682
|
+
["kill -INT 1234", ["pid:1234"], "SIGINT"],
|
|
683
|
+
["kill -KILL 1234", ["pid:1234"], "SIGKILL"],
|
|
684
|
+
["kill -9 1234", ["pid:1234"], "SIGKILL"],
|
|
685
|
+
["kill -SIGKILL 1234", ["pid:1234"], "SIGKILL"],
|
|
686
|
+
["kill -s KILL 1234", ["pid:1234"], "SIGKILL"],
|
|
687
|
+
["kill -s 9 1234", ["pid:1234"], "SIGKILL"],
|
|
688
|
+
["kill 1234 5678", ["pid:1234", "pid:5678"], "2 processes"],
|
|
689
|
+
["kill 1234 1234", ["pid:1234"], "SIGTERM"],
|
|
690
|
+
["kill 2", ["pid:2"], "SIGTERM"],
|
|
691
|
+
["kill 4194304", ["pid:4194304"], "SIGTERM"],
|
|
692
|
+
[`kill "-9" 1234`, ["pid:1234"], "SIGKILL"],
|
|
693
|
+
])(
|
|
694
|
+
"%s needs a human %j",
|
|
695
|
+
(command: string, targets: Array<string>, mentions: string) => {
|
|
696
|
+
const result: ResourceCommandPolicyResult = evaluate(command);
|
|
697
|
+
|
|
698
|
+
expect([command, result.tier]).toEqual([
|
|
699
|
+
command,
|
|
700
|
+
ResourceCommandTier.RiskyWrite,
|
|
701
|
+
]);
|
|
702
|
+
expect(result.requiresHuman).toBe(true);
|
|
703
|
+
expect(result.targets).toEqual(targets);
|
|
704
|
+
expect(result.reason).toContain(mentions);
|
|
705
|
+
},
|
|
706
|
+
);
|
|
707
|
+
|
|
708
|
+
test("kill is labelled and never unattended", () => {
|
|
709
|
+
const result: ResourceCommandPolicyResult = evaluate("kill -9 1234");
|
|
710
|
+
|
|
711
|
+
expect(result.verb).toBe("kill");
|
|
712
|
+
expect(result.reason).toContain("always needs a human");
|
|
713
|
+
});
|
|
714
|
+
});
|
|
715
|
+
|
|
716
|
+
describe("Denied, with a reason that names what is allowed", () => {
|
|
717
|
+
test.each([
|
|
718
|
+
// systemctl commands
|
|
719
|
+
["systemctl enable nginx", "persistent configuration"],
|
|
720
|
+
["systemctl disable nginx", "persistent configuration"],
|
|
721
|
+
["systemctl reenable nginx", "persistent configuration"],
|
|
722
|
+
["systemctl mask nginx", "persistent configuration"],
|
|
723
|
+
["systemctl unmask nginx", "persistent configuration"],
|
|
724
|
+
["systemctl link /etc/foo.service", "persistent configuration"],
|
|
725
|
+
["systemctl revert nginx", "persistent configuration"],
|
|
726
|
+
["systemctl preset nginx", "persistent configuration"],
|
|
727
|
+
["systemctl preset-all", "persistent configuration"],
|
|
728
|
+
["systemctl set-default graphical.target", "persistent configuration"],
|
|
729
|
+
["systemctl edit nginx", "editor"],
|
|
730
|
+
["systemctl cat nginx", "secrets"],
|
|
731
|
+
["systemctl show-environment", "secrets"],
|
|
732
|
+
["systemctl set-environment FOO=bar", "secrets"],
|
|
733
|
+
["systemctl unset-environment FOO", "secrets"],
|
|
734
|
+
["systemctl import-environment", "secrets"],
|
|
735
|
+
["systemctl daemon-reload", "service manager itself"],
|
|
736
|
+
["systemctl daemon-reexec", "service manager itself"],
|
|
737
|
+
["systemctl isolate rescue.target", "stops every unit"],
|
|
738
|
+
["systemctl kill nginx", "signals every process"],
|
|
739
|
+
["systemctl set-property nginx MemoryMax=1G", "resource controls"],
|
|
740
|
+
["systemctl clean nginx", "deletes"],
|
|
741
|
+
["systemctl freeze nginx", "freezes"],
|
|
742
|
+
["systemctl poweroff", "whole host"],
|
|
743
|
+
["systemctl reboot", "whole host"],
|
|
744
|
+
["systemctl halt", "whole host"],
|
|
745
|
+
["systemctl kexec", "whole host"],
|
|
746
|
+
["systemctl soft-reboot", "whole host"],
|
|
747
|
+
["systemctl suspend", "whole host"],
|
|
748
|
+
["systemctl hibernate", "whole host"],
|
|
749
|
+
["systemctl hybrid-sleep", "whole host"],
|
|
750
|
+
["systemctl suspend-then-hibernate", "whole host"],
|
|
751
|
+
["systemctl switch-root /new", "whole host"],
|
|
752
|
+
["systemctl default", "whole host"],
|
|
753
|
+
["systemctl rescue", "whole host"],
|
|
754
|
+
["systemctl emergency", "whole host"],
|
|
755
|
+
["systemctl exit", "whole host"],
|
|
756
|
+
["systemctl help nginx", "not a systemctl command"],
|
|
757
|
+
["systemctl Restart nginx", "lowercase"],
|
|
758
|
+
["systemctl condrestart nginx", "not a systemctl command"],
|
|
759
|
+
["systemctl restar nginx", "not a systemctl command"],
|
|
760
|
+
// systemctl units a write may never touch
|
|
761
|
+
["systemctl start reboot.target", "power or run-state"],
|
|
762
|
+
["systemctl start poweroff.target", "power or run-state"],
|
|
763
|
+
["systemctl restart systemd-reboot.service", "power or run-state"],
|
|
764
|
+
["systemctl start systemd-poweroff", "power or run-state"],
|
|
765
|
+
["systemctl start rescue.target", "power or run-state"],
|
|
766
|
+
["systemctl start emergency.service", "power or run-state"],
|
|
767
|
+
["systemctl start ctrl-alt-del.target", "power or run-state"],
|
|
768
|
+
["systemctl start suspend.target", "power or run-state"],
|
|
769
|
+
["systemctl start halt", "power or run-state"],
|
|
770
|
+
["systemctl start Reboot.target", "power or run-state"],
|
|
771
|
+
["systemctl restart default.target", "power or run-state"],
|
|
772
|
+
["systemctl reset-failed reboot.target", "power or run-state"],
|
|
773
|
+
// the SysV runlevel aliases of the power and run-state targets
|
|
774
|
+
["systemctl start runlevel6.target", "power or run-state"],
|
|
775
|
+
["systemctl start runlevel0.target", "power or run-state"],
|
|
776
|
+
["systemctl restart runlevel1.target", "power or run-state"],
|
|
777
|
+
["systemctl start runlevel3.target", "power or run-state"],
|
|
778
|
+
["systemctl start RUNLEVEL6.target", "power or run-state"],
|
|
779
|
+
// a root shell with no password on tty9
|
|
780
|
+
["systemctl start debug-shell", "root shell with no password"],
|
|
781
|
+
["systemctl start debug-shell.service", "root shell with no password"],
|
|
782
|
+
["systemctl restart debug-shell", "root shell with no password"],
|
|
783
|
+
["systemctl start nginx debug-shell", "root shell with no password"],
|
|
784
|
+
["systemctl stop system.slice", "slice unit"],
|
|
785
|
+
["systemctl stop user.slice", "slice unit"],
|
|
786
|
+
["systemctl stop init.scope", "scope unit"],
|
|
787
|
+
["systemctl restart session-3.scope", "scope unit"],
|
|
788
|
+
["systemctl stop dev-sda.device", "device unit"],
|
|
789
|
+
["systemctl restart foo@", "instance"],
|
|
790
|
+
["systemctl restart foo@.service", "instance"],
|
|
791
|
+
["systemctl restart 'nginx*'", "globs"],
|
|
792
|
+
["systemctl restart 'ngin?'", "globs"],
|
|
793
|
+
["systemctl restart /etc/nginx", "unit name"],
|
|
794
|
+
["systemctl restart -- -.mount", "unit name"],
|
|
795
|
+
["systemctl restart -- --force", "unit name"],
|
|
796
|
+
["systemctl status -- --host=db1", "unit name"],
|
|
797
|
+
["systemctl restart 'nginx sshd'", "unit name"],
|
|
798
|
+
["systemctl restart", "needs the unit"],
|
|
799
|
+
["systemctl stop", "needs the unit"],
|
|
800
|
+
["systemctl status 'nginx*'", "unit name"],
|
|
801
|
+
// systemctl flags
|
|
802
|
+
["systemctl -H db1 status nginx", "another machine"],
|
|
803
|
+
["systemctl --host=db1 status nginx", "another machine"],
|
|
804
|
+
["systemctl -M container status nginx", "container"],
|
|
805
|
+
["systemctl --machine=c status", "container"],
|
|
806
|
+
["systemctl --root=/mnt status", "another root"],
|
|
807
|
+
["systemctl --image=/x.img status", "disk image"],
|
|
808
|
+
["systemctl --user restart app", "user service managers"],
|
|
809
|
+
["systemctl --global enable x", "user service managers"],
|
|
810
|
+
["systemctl restart --runtime nginx", "current boot"],
|
|
811
|
+
["systemctl restart --force nginx", "safety checks"],
|
|
812
|
+
["systemctl restart -f nginx", "safety checks"],
|
|
813
|
+
["systemctl restart nginx --force", "safety checks"],
|
|
814
|
+
["systemctl -lf restart nginx", "safety checks"],
|
|
815
|
+
["systemctl stop -i nginx", "inhibitors"],
|
|
816
|
+
["systemctl restart --job-mode=isolate nginx", "queued jobs"],
|
|
817
|
+
["systemctl restart --wait nginx", "hang"],
|
|
818
|
+
["systemctl restart -s KILL nginx", "signal"],
|
|
819
|
+
["systemctl --signal=KILL restart nginx", "signal"],
|
|
820
|
+
["systemctl --now restart nginx", "enable/disable"],
|
|
821
|
+
["systemctl restart --no-block nginx", "not a systemctl flag"],
|
|
822
|
+
["systemctl status --no-pag nginx", "written in full"],
|
|
823
|
+
["systemctl status --no nginx", "written in full"],
|
|
824
|
+
["systemctl status nginx -n 500", "0 to 200"],
|
|
825
|
+
["systemctl status nginx -n all", "0 to 200"],
|
|
826
|
+
["systemctl status nginx -n=5", "0 to 200"],
|
|
827
|
+
["systemctl status nginx -n -5", 'starts with "-"'],
|
|
828
|
+
["systemctl status nginx -o verbose", "must be one of"],
|
|
829
|
+
["systemctl status nginx -o export", "must be one of"],
|
|
830
|
+
["systemctl status nginx --no-pager=1", "takes no value"],
|
|
831
|
+
["systemctl status --output", "needs a value"],
|
|
832
|
+
["systemctl list-units --state", "needs a value"],
|
|
833
|
+
["systemctl restart nginx -l", "does not apply"],
|
|
834
|
+
["systemctl restart nginx -n 5", "does not apply"],
|
|
835
|
+
["systemctl --failed restart nginx", "does not apply"],
|
|
836
|
+
["systemctl status nginx -p ActiveState", "does not apply"],
|
|
837
|
+
["systemctl status nginx -n 5 --lines=6", "only once"],
|
|
838
|
+
["systemctl show nginx", "must name the properties"],
|
|
839
|
+
["systemctl show nginx --all", "must name the properties"],
|
|
840
|
+
["systemctl show nginx -p Environment", "may only name"],
|
|
841
|
+
["systemctl show nginx -p EnvironmentFiles", "may only name"],
|
|
842
|
+
["systemctl show nginx -p ActiveState,Environment", "may only name"],
|
|
843
|
+
["systemctl show nginx --property=ExecStart", "may only name"],
|
|
844
|
+
["systemctl show nginx -P Environment", "may only name"],
|
|
845
|
+
["systemctl show nginx -p=ActiveState", "property names"],
|
|
846
|
+
["systemctl show -p ActiveState", "at least one unit"],
|
|
847
|
+
["systemctl is-active", "at least one unit"],
|
|
848
|
+
["systemctl list-dependencies a b", "at most one"],
|
|
849
|
+
["systemctl list-jobs nginx", "takes no unit names"],
|
|
850
|
+
["systemctl is-system-running nginx", "takes no unit names"],
|
|
851
|
+
["systemctl list-units --type 'service;x'", "unit types"],
|
|
852
|
+
// journalctl
|
|
853
|
+
["journalctl", "must be bounded"],
|
|
854
|
+
["journalctl -u nginx", "must be bounded"],
|
|
855
|
+
["journalctl -u nginx --until today", "must be bounded"],
|
|
856
|
+
["journalctl -f", "follows the journal forever"],
|
|
857
|
+
["journalctl -u nginx -f -n 10", "follows the journal forever"],
|
|
858
|
+
["journalctl --follow -n 10", "follows the journal forever"],
|
|
859
|
+
["journalctl -fn 10", "follows the journal forever"],
|
|
860
|
+
["journalctl -rf -n 5", "follows the journal forever"],
|
|
861
|
+
["journalctl -n 10 -u nginx --follow", "follows the journal forever"],
|
|
862
|
+
["journalctl -nf", "whole number"],
|
|
863
|
+
["journalctl -n 5000", "0 to 2000"],
|
|
864
|
+
["journalctl -n 2001", "0 to 2000"],
|
|
865
|
+
["journalctl -n all", "unbounded"],
|
|
866
|
+
["journalctl --lines=all", "unbounded"],
|
|
867
|
+
["journalctl --lines=", "0 to 2000"],
|
|
868
|
+
["journalctl -n 10 -n 20", "only once"],
|
|
869
|
+
["journalctl -p err -p warning -n 5", "only once"],
|
|
870
|
+
["journalctl -D /var/log/journal -n 10", "another place"],
|
|
871
|
+
["journalctl --directory=/x -n 10", "another place"],
|
|
872
|
+
["journalctl --file /x -n 10", "another place"],
|
|
873
|
+
["journalctl -i /x -n 10", "another place"],
|
|
874
|
+
["journalctl --root=/mnt -n 10", "another place"],
|
|
875
|
+
["journalctl --image=/x.img -n 10", "another place"],
|
|
876
|
+
["journalctl -M c -n 10", "another machine"],
|
|
877
|
+
["journalctl --namespace=x -n 10", "namespace"],
|
|
878
|
+
["journalctl --rotate", "stores the journal"],
|
|
879
|
+
["journalctl --flush", "stores the journal"],
|
|
880
|
+
["journalctl --sync", "stores the journal"],
|
|
881
|
+
["journalctl --relinquish-var", "stores the journal"],
|
|
882
|
+
["journalctl --smart-relinquish-var", "stores the journal"],
|
|
883
|
+
["journalctl --setup-keys", "Sealing"],
|
|
884
|
+
["journalctl --verify", "Sealing"],
|
|
885
|
+
["journalctl --update-catalog", "catalog"],
|
|
886
|
+
["journalctl --cursor-file=/tmp/c -n 5", "cursor file"],
|
|
887
|
+
["journalctl -n 10 _PID=1", "match words"],
|
|
888
|
+
["journalctl -n 10 /usr/bin/sshd", "match words"],
|
|
889
|
+
["journalctl -n 10 -- -f", "match words"],
|
|
890
|
+
["journalctl -n 10 +", "match words"],
|
|
891
|
+
["journalctl --vacuum-time=7d -n 10", "on its own"],
|
|
892
|
+
["journalctl --vacuum-time=7d -u nginx", "on its own"],
|
|
893
|
+
["journalctl --vacuum-size=lots", "size"],
|
|
894
|
+
["journalctl --vacuum-time=forever", "time span"],
|
|
895
|
+
["journalctl --vacuum-files=0", "whole number"],
|
|
896
|
+
["journalctl -o verbose -n 10", "must be one of"],
|
|
897
|
+
["journalctl -o export -n 10", "must be one of"],
|
|
898
|
+
["journalctl -p bogus -n 10", "priority"],
|
|
899
|
+
["journalctl -u -f -n 10", 'starts with "-"'],
|
|
900
|
+
["journalctl -u --follow -n 10", 'starts with "-"'],
|
|
901
|
+
["journalctl -u=nginx -n 10", "unit name"],
|
|
902
|
+
["journalctl -u 'nginx;reboot' -n 10", "unit name"],
|
|
903
|
+
["journalctl --since=-f -n 1", "must be a time"],
|
|
904
|
+
["journalctl --since '$(reboot)' -n 1", "must be a time"],
|
|
905
|
+
["journalctl -S --follow", "must be a time"],
|
|
906
|
+
["journalctl -g '' -n 1", "1 to 256"],
|
|
907
|
+
["journalctl -b nope -n 1", "match words"],
|
|
908
|
+
["journalctl --boot=nope -n 1", "boot offset"],
|
|
909
|
+
["journalctl --no-pag -n 10", "written in full"],
|
|
910
|
+
["journalctl --user -n 10", "not a journalctl flag"],
|
|
911
|
+
["journalctl -e", "not a journalctl flag"],
|
|
912
|
+
["journalctl -a -n 10", "not a journalctl flag"],
|
|
913
|
+
["journalctl -F _CMDLINE", "not a journalctl flag"],
|
|
914
|
+
["journalctl -m -n 10", "not a journalctl flag"],
|
|
915
|
+
// df, free, uptime, uname
|
|
916
|
+
["df --sync", "not a df flag"],
|
|
917
|
+
["df -B 1K", "not a df flag"],
|
|
918
|
+
["df relative/path", "absolute path"],
|
|
919
|
+
["df /var/../etc", "absolute path"],
|
|
920
|
+
["df -t 'ext4;x'", "filesystem type"],
|
|
921
|
+
["free -s 1", "repeats"],
|
|
922
|
+
["free -c 3", "repeats"],
|
|
923
|
+
["free --seconds=1", "repeats"],
|
|
924
|
+
["free -hs1", "repeats"],
|
|
925
|
+
["free extra", "takes no words"],
|
|
926
|
+
["uptime --help", "not a uptime flag"],
|
|
927
|
+
["uptime now", "takes no words"],
|
|
928
|
+
["uname -p", "not a uname flag"],
|
|
929
|
+
["uname -a extra", "takes no words"],
|
|
930
|
+
// ps
|
|
931
|
+
["ps e", "environment"],
|
|
932
|
+
["ps auxe", "environment"],
|
|
933
|
+
["ps eww", "environment"],
|
|
934
|
+
["ps aux --sort=-%cpu e", "environment"],
|
|
935
|
+
["ps -aux", '(in "-aux")'],
|
|
936
|
+
["ps -o environ", "not one"],
|
|
937
|
+
["ps -o pid,environ", "not one"],
|
|
938
|
+
["ps --sort=foo", "sort keys"],
|
|
939
|
+
["ps --sort", "needs a key"],
|
|
940
|
+
["ps -p", "needs a value"],
|
|
941
|
+
["ps -p abc", "pids"],
|
|
942
|
+
["ps -p -e", "pids"],
|
|
943
|
+
["ps --cols 100", "not a ps option"],
|
|
944
|
+
["ps --format pid", "not a ps option"],
|
|
945
|
+
["ps --no-headers=1", "takes no value"],
|
|
946
|
+
["ps 1234", "not a ps option"],
|
|
947
|
+
["ps --", "not a ps option"],
|
|
948
|
+
["ps -", "not a ps option"],
|
|
949
|
+
["ps -y", "not a ps option"],
|
|
950
|
+
["ps -N", "not a ps option"],
|
|
951
|
+
["ps axk -%cpu", "not a ps option"],
|
|
952
|
+
// top
|
|
953
|
+
["top", "batch mode"],
|
|
954
|
+
["top -b", "batch mode"],
|
|
955
|
+
["top -n 1", "batch mode"],
|
|
956
|
+
["top -b -n 2", "must be 1"],
|
|
957
|
+
["top -b -n 1 -d 1", "not a top flag"],
|
|
958
|
+
["top -b -n 1 -p 1", "not a top flag"],
|
|
959
|
+
["top -bn1 -d0.1", "not a top flag"],
|
|
960
|
+
["top -b -n 1 extra", "takes no words"],
|
|
961
|
+
["top -b -n 1 -w 5000", "1 to 512"],
|
|
962
|
+
["top -b -n1 -n1", "only once"],
|
|
963
|
+
["top -b -n 1 -o 'bad field'", "field name"],
|
|
964
|
+
// ss
|
|
965
|
+
["ss -K", "forcibly closes"],
|
|
966
|
+
["ss --kill", "forcibly closes"],
|
|
967
|
+
["ss -tK", "forcibly closes"],
|
|
968
|
+
["ss -tunlpK", "forcibly closes"],
|
|
969
|
+
["ss -D /tmp/x", "to a file"],
|
|
970
|
+
["ss -F /tmp/f", "from a file"],
|
|
971
|
+
["ss -N ns1", "network namespace"],
|
|
972
|
+
["ss -E", "streams"],
|
|
973
|
+
["ss -tnp -A all", "not a ss flag"],
|
|
974
|
+
["ss -tn '$(reboot)'", "filter expression"],
|
|
975
|
+
// ip
|
|
976
|
+
["ip addr add 10.0.0.1/24 dev eth0", "changes the host's network"],
|
|
977
|
+
["ip link set eth0 down", "changes the host's network"],
|
|
978
|
+
["ip route del default", "changes the host's network"],
|
|
979
|
+
["ip route flush table main", "changes the host's network"],
|
|
980
|
+
["ip neigh flush all", "changes the host's network"],
|
|
981
|
+
["ip rule add from all lookup 100", "changes the host's network"],
|
|
982
|
+
["ip route save", "changes the host's network"],
|
|
983
|
+
["ip route replace default via 10.0.0.1", "changes the host's network"],
|
|
984
|
+
["ip -b cmds.txt", "-batch"],
|
|
985
|
+
["ip -batch cmds.txt", "-batch"],
|
|
986
|
+
["ip --batch cmds.txt", "-batch"],
|
|
987
|
+
["ip -ba cmds.txt", "-batch"],
|
|
988
|
+
["ip -force -b x", "-force"],
|
|
989
|
+
["ip -n ns1 addr", "-netns"],
|
|
990
|
+
["ip -netns ns1 addr", "-netns"],
|
|
991
|
+
["ip -net ns1 addr", "-netns"],
|
|
992
|
+
["ip netns exec ns1 sh", "network namespaces"],
|
|
993
|
+
["ip netns list", "network namespaces"],
|
|
994
|
+
["ip xfrm state", "IPsec keys"],
|
|
995
|
+
["ip monitor", "streams"],
|
|
996
|
+
["ip tunnel", "not an object"],
|
|
997
|
+
["ip maddr", "not an object"],
|
|
998
|
+
["ip addr sh", "not an ip address read"],
|
|
999
|
+
["ip link lst", "not an ip link read"],
|
|
1000
|
+
["ip route get", "exactly one IP address"],
|
|
1001
|
+
["ip route get 1.1.1.1 from 10.0.0.1", "exactly one IP address"],
|
|
1002
|
+
["ip route get example.com", "exactly one IP address"],
|
|
1003
|
+
["ip", "needs an object"],
|
|
1004
|
+
["ip -br", "needs an object"],
|
|
1005
|
+
["ip -- addr", 'no "--"'],
|
|
1006
|
+
["ip -r addr", "not an ip option"],
|
|
1007
|
+
["ip -family inet addr", "not an ip option"],
|
|
1008
|
+
["ip -o addr", "not an ip option"],
|
|
1009
|
+
["ip -bri addr", "not an ip option"],
|
|
1010
|
+
["ip addr show -4", "filter word"],
|
|
1011
|
+
["ip addr show dev 'eth0;reboot'", "filter word"],
|
|
1012
|
+
// dmesg, lsblk
|
|
1013
|
+
["dmesg -w", "forever"],
|
|
1014
|
+
["dmesg --follow", "forever"],
|
|
1015
|
+
["dmesg -W", "forever"],
|
|
1016
|
+
["dmesg -Tw", "forever"],
|
|
1017
|
+
["dmesg -c", "clears"],
|
|
1018
|
+
["dmesg -C", "clears"],
|
|
1019
|
+
["dmesg --clear", "clears"],
|
|
1020
|
+
["dmesg -Tc", "clears"],
|
|
1021
|
+
["dmesg -n 1", "console"],
|
|
1022
|
+
["dmesg -D", "console"],
|
|
1023
|
+
["dmesg -E", "console"],
|
|
1024
|
+
["dmesg -F /var/log/x", "reads a file"],
|
|
1025
|
+
["dmesg -H", "pager"],
|
|
1026
|
+
["dmesg -l bogus", "levels"],
|
|
1027
|
+
["dmesg extra", "takes no words"],
|
|
1028
|
+
["lsblk --sysroot /mnt", "another root"],
|
|
1029
|
+
["lsblk -o 'NAME;X'", "column names"],
|
|
1030
|
+
["lsblk sda", "/dev device path"],
|
|
1031
|
+
["lsblk /dev/../etc/shadow", "/dev device path"],
|
|
1032
|
+
["lsblk -S", "not a lsblk flag"],
|
|
1033
|
+
// cat
|
|
1034
|
+
["cat /etc/shadow", "may not read"],
|
|
1035
|
+
["cat /proc/self/environ", "may not read"],
|
|
1036
|
+
["cat /proc/1/environ", "may not read"],
|
|
1037
|
+
["cat /proc/../etc/shadow", "may not read"],
|
|
1038
|
+
["cat /proc//loadavg", "may not read"],
|
|
1039
|
+
["cat /PROC/loadavg", "may not read"],
|
|
1040
|
+
["cat /proc/loadavg /etc/shadow", "may not read"],
|
|
1041
|
+
["cat '/proc/loadavg /etc/shadow'", "may not read"],
|
|
1042
|
+
["cat -A /proc/loadavg", "takes no flags"],
|
|
1043
|
+
["cat -- /proc/loadavg", "takes no flags"],
|
|
1044
|
+
["cat - /proc/loadavg", "takes no flags"],
|
|
1045
|
+
["cat", "needs a file"],
|
|
1046
|
+
// hostnamectl, timedatectl
|
|
1047
|
+
["hostnamectl set-hostname evil", "never changed"],
|
|
1048
|
+
["hostnamectl hostname new", "never changed"],
|
|
1049
|
+
["hostnamectl status extra", "never changed"],
|
|
1050
|
+
["hostnamectl --json=short", "takes no flags"],
|
|
1051
|
+
["hostnamectl -H db1", "takes no flags"],
|
|
1052
|
+
["timedatectl set-time '2024-01-01 10:00'", "never changed"],
|
|
1053
|
+
["timedatectl set-timezone UTC", "never changed"],
|
|
1054
|
+
["timedatectl set-ntp false", "never changed"],
|
|
1055
|
+
["timedatectl list-timezones", "never changed"],
|
|
1056
|
+
["timedatectl -H db1 status", "takes no flags"],
|
|
1057
|
+
// kill
|
|
1058
|
+
["kill 1", "init system"],
|
|
1059
|
+
["kill -9 1", "init system"],
|
|
1060
|
+
["kill 1234 1", "init system"],
|
|
1061
|
+
["kill 0", "not a pid"],
|
|
1062
|
+
["kill -9 -1", "process group"],
|
|
1063
|
+
["kill -- -1234", "process group"],
|
|
1064
|
+
["kill -TERM -- 1234", "process group"],
|
|
1065
|
+
["kill -9 1234 -15", "process group"],
|
|
1066
|
+
["kill -STOP 1234", "not a signal"],
|
|
1067
|
+
["kill -19 1234", "not a signal"],
|
|
1068
|
+
["kill -1 1234", "not a signal"],
|
|
1069
|
+
["kill -term 1234", "not a signal"],
|
|
1070
|
+
["kill -s STOP 1234", "allowed signals"],
|
|
1071
|
+
["kill -s", "allowed signals"],
|
|
1072
|
+
["kill -l", "not a signal"],
|
|
1073
|
+
["kill -L", "not a signal"],
|
|
1074
|
+
["kill --signal KILL 1234", "not a signal"],
|
|
1075
|
+
["kill", "needs the pid"],
|
|
1076
|
+
["kill -9", "needs the pid"],
|
|
1077
|
+
["kill abc", "not a pid"],
|
|
1078
|
+
["kill 0123", "not a pid"],
|
|
1079
|
+
["kill 4194305", "not a pid"],
|
|
1080
|
+
["kill 99999999", "not a pid"],
|
|
1081
|
+
["kill %1", "not a pid"],
|
|
1082
|
+
["kill 12.5", "not a pid"],
|
|
1083
|
+
])("%s is Denied (%s)", (command: string, fragment: string) => {
|
|
1084
|
+
const result: ResourceCommandPolicyResult = evaluate(command);
|
|
1085
|
+
|
|
1086
|
+
expect([command, result.tier]).toEqual([
|
|
1087
|
+
command,
|
|
1088
|
+
ResourceCommandTier.Denied,
|
|
1089
|
+
]);
|
|
1090
|
+
expect(result.reason).toContain(fragment);
|
|
1091
|
+
expect(result.targets).toEqual([]);
|
|
1092
|
+
expect(result.requiresHuman).toBeUndefined();
|
|
1093
|
+
});
|
|
1094
|
+
|
|
1095
|
+
test.each([
|
|
1096
|
+
["systemctl enable nginx", "systemctl reads with status"],
|
|
1097
|
+
["journalctl -f", "journalctl reads with -u UNIT"],
|
|
1098
|
+
["df --sync", "df takes -h"],
|
|
1099
|
+
["free -s 1", "free takes -b"],
|
|
1100
|
+
["uptime -x", "uptime takes -p"],
|
|
1101
|
+
["ps e", "ps takes BSD options"],
|
|
1102
|
+
["top", "top runs once in batch mode"],
|
|
1103
|
+
["ss -K", "ss takes -t"],
|
|
1104
|
+
["ip link set eth0 down", "ip takes -br"],
|
|
1105
|
+
["dmesg -c", "dmesg takes -T"],
|
|
1106
|
+
["lsblk --sysroot /", "lsblk takes -f"],
|
|
1107
|
+
["cat /etc/shadow", "/proc/loadavg"],
|
|
1108
|
+
["uname -p", "uname takes -a"],
|
|
1109
|
+
["hostnamectl set-hostname x", "hostnamectl runs as"],
|
|
1110
|
+
["timedatectl set-ntp no", "timedatectl runs as"],
|
|
1111
|
+
["kill 1", "kill takes at most one signal"],
|
|
1112
|
+
])(
|
|
1113
|
+
"the refusal of %s names what is allowed",
|
|
1114
|
+
(command: string, allowed: string) => {
|
|
1115
|
+
expect(evaluate(command).reason).toContain(allowed);
|
|
1116
|
+
},
|
|
1117
|
+
);
|
|
1118
|
+
|
|
1119
|
+
test.each([
|
|
1120
|
+
["bash -c id", "not a program the Host AI agent runs"],
|
|
1121
|
+
["sh", "not a program the Host AI agent runs"],
|
|
1122
|
+
["rm -rf /", "not a program the Host AI agent runs"],
|
|
1123
|
+
["nsenter -t 1 -m sh", "not a program the Host AI agent runs"],
|
|
1124
|
+
["docker ps", "not a program the Host AI agent runs"],
|
|
1125
|
+
["tail -f /var/log/syslog", "not a program the Host AI agent runs"],
|
|
1126
|
+
["SYSTEMCTL status nginx", "not a program the Host AI agent runs"],
|
|
1127
|
+
["/usr/bin/systemctl status nginx", "without a path"],
|
|
1128
|
+
["sudo systemctl restart nginx", "own permissions"],
|
|
1129
|
+
["systemctl status nginx | grep x", "pipes and redirects"],
|
|
1130
|
+
["journalctl -n 10 > /tmp/x", "pipes and redirects"],
|
|
1131
|
+
["systemctl status nginx; reboot", "pipes and redirects"],
|
|
1132
|
+
["systemctl status $(reboot)", "pipes and redirects"],
|
|
1133
|
+
["systemctl status `reboot`", "pipes and redirects"],
|
|
1134
|
+
["kill 1234 &", "pipes and redirects"],
|
|
1135
|
+
])(
|
|
1136
|
+
"%s is Denied before the host policy reads it",
|
|
1137
|
+
(command: string, fragment: string) => {
|
|
1138
|
+
const result: ResourceCommandPolicyResult = evaluate(command);
|
|
1139
|
+
|
|
1140
|
+
expect(result.tier).toBe(ResourceCommandTier.Denied);
|
|
1141
|
+
expect(result.reason).toContain(fragment);
|
|
1142
|
+
},
|
|
1143
|
+
);
|
|
1144
|
+
|
|
1145
|
+
test("the host policy itself refuses a program it does not know", () => {
|
|
1146
|
+
const result: ResourceCommandPolicyResult = HostCommandPolicy.evaluateArgv([
|
|
1147
|
+
"bash",
|
|
1148
|
+
"-c",
|
|
1149
|
+
"id",
|
|
1150
|
+
]);
|
|
1151
|
+
|
|
1152
|
+
expect(result.tier).toBe(ResourceCommandTier.Denied);
|
|
1153
|
+
expect(result.reason).toContain("never a path");
|
|
1154
|
+
expect(result.reason).toContain("systemctl");
|
|
1155
|
+
});
|
|
1156
|
+
});
|
|
1157
|
+
|
|
1158
|
+
describe("flags cannot be smuggled past the policy", () => {
|
|
1159
|
+
test.each([
|
|
1160
|
+
// A denied flag inside a cluster of allowed ones.
|
|
1161
|
+
["journalctl -rxf -n 5"],
|
|
1162
|
+
["journalctl -kqf -n 5"],
|
|
1163
|
+
["systemctl -qf restart nginx"],
|
|
1164
|
+
["dmesg -xTw"],
|
|
1165
|
+
["ss -tulnpK"],
|
|
1166
|
+
["free -mhs2"],
|
|
1167
|
+
// After positionals (GNU getopt permutes).
|
|
1168
|
+
["systemctl restart nginx --force"],
|
|
1169
|
+
["systemctl status nginx -H db1"],
|
|
1170
|
+
["journalctl -n 10 -u nginx -f"],
|
|
1171
|
+
["df -h / --sync"],
|
|
1172
|
+
// Written with = or attached.
|
|
1173
|
+
["systemctl --host=db1 status nginx"],
|
|
1174
|
+
["systemctl -Hdb1 status nginx"],
|
|
1175
|
+
["journalctl --directory=/tmp -n 1"],
|
|
1176
|
+
["journalctl -D/tmp -n 1"],
|
|
1177
|
+
["dmesg --console-level=1"],
|
|
1178
|
+
// As the value of a flag that takes one.
|
|
1179
|
+
["journalctl -u -f -n 10"],
|
|
1180
|
+
["journalctl -t --follow -n 10"],
|
|
1181
|
+
["systemctl list-units --type -H"],
|
|
1182
|
+
["systemctl status nginx -o -f"],
|
|
1183
|
+
["ps -o -e"],
|
|
1184
|
+
["ps -C -e"],
|
|
1185
|
+
// Behind "--".
|
|
1186
|
+
["systemctl restart -- --force"],
|
|
1187
|
+
["journalctl -n 1 -- --follow"],
|
|
1188
|
+
["kill -- -1"],
|
|
1189
|
+
// Abbreviated long flags getopt_long would resolve.
|
|
1190
|
+
["journalctl --foll -n 1"],
|
|
1191
|
+
["journalctl --direc=/tmp -n 1"],
|
|
1192
|
+
["systemctl --ho=db1 status"],
|
|
1193
|
+
["systemctl restart --forc nginx"],
|
|
1194
|
+
["dmesg --cl"],
|
|
1195
|
+
// Abbreviations ip resolves by prefix.
|
|
1196
|
+
["ip -b x"],
|
|
1197
|
+
["ip -n ns addr"],
|
|
1198
|
+
["ip -fo addr"],
|
|
1199
|
+
// Duplicated so an earlier harmless value hides a later bad one.
|
|
1200
|
+
["journalctl -n 10 -n all"],
|
|
1201
|
+
["top -b -n 1 -n 5"],
|
|
1202
|
+
["systemctl status nginx -n 5 -n 900"],
|
|
1203
|
+
["journalctl -o short -o export -n 1"],
|
|
1204
|
+
// Quotes are shell syntax, never a way around a flag check.
|
|
1205
|
+
[`journalctl "-f" -n 5`],
|
|
1206
|
+
[`journalctl '--follow' -n 5`],
|
|
1207
|
+
[`systemctl restart "--force" nginx`],
|
|
1208
|
+
[`systemctl "--host=db1" status`],
|
|
1209
|
+
[`kill "-9" "-1"`],
|
|
1210
|
+
])("%s is Denied", (command: string) => {
|
|
1211
|
+
expect(evaluate(command).tier).toBe(ResourceCommandTier.Denied);
|
|
1212
|
+
});
|
|
1213
|
+
|
|
1214
|
+
test("a switch may repeat harmlessly, a value flag may not", () => {
|
|
1215
|
+
expect(evaluate("systemctl status -l -l nginx").tier).toBe(
|
|
1216
|
+
ResourceCommandTier.Read,
|
|
1217
|
+
);
|
|
1218
|
+
expect(evaluate("ps -ww -e").tier).toBe(ResourceCommandTier.Read);
|
|
1219
|
+
expect(evaluate("journalctl -u a -u b -n 5").tier).toBe(
|
|
1220
|
+
ResourceCommandTier.Read,
|
|
1221
|
+
);
|
|
1222
|
+
expect(evaluate("journalctl -n 5 --lines 6").reason).toContain("only once");
|
|
1223
|
+
});
|
|
1224
|
+
|
|
1225
|
+
test("an Optional value is taken from the next word only when the program would", () => {
|
|
1226
|
+
// journalctl -n takes "50" (a line count) but not "-u" (another flag).
|
|
1227
|
+
expect(evaluate("journalctl -n 50 -u nginx").tier).toBe(
|
|
1228
|
+
ResourceCommandTier.Read,
|
|
1229
|
+
);
|
|
1230
|
+
expect(evaluate("journalctl -n -u nginx").tier).toBe(
|
|
1231
|
+
ResourceCommandTier.Read,
|
|
1232
|
+
);
|
|
1233
|
+
// -b takes "-1" (a boot offset) but not "-n".
|
|
1234
|
+
expect(evaluate("journalctl -b -1 -n 5").tier).toBe(
|
|
1235
|
+
ResourceCommandTier.Read,
|
|
1236
|
+
);
|
|
1237
|
+
expect(evaluate("journalctl -b -n 5").tier).toBe(ResourceCommandTier.Read);
|
|
1238
|
+
// Not a boot: stays a word, and journalctl takes no words.
|
|
1239
|
+
expect(evaluate("journalctl -b nginx -n 5").reason).toContain(
|
|
1240
|
+
"match words",
|
|
1241
|
+
);
|
|
1242
|
+
// top -w takes a width only when the next word is a number.
|
|
1243
|
+
expect(evaluate("top -b -n 1 -w 120").tier).toBe(ResourceCommandTier.Read);
|
|
1244
|
+
expect(evaluate("top -b -n 1 -w -c").tier).toBe(ResourceCommandTier.Read);
|
|
1245
|
+
});
|
|
1246
|
+
|
|
1247
|
+
test('getopt reads -n=5 as the value "=5", and so does the policy', () => {
|
|
1248
|
+
expect(evaluate("journalctl -n=5").reason).toContain('"=5"');
|
|
1249
|
+
expect(evaluate("systemctl status x -n=5").reason).toContain('"=5"');
|
|
1250
|
+
});
|
|
1251
|
+
});
|
|
1252
|
+
|
|
1253
|
+
describe("look-alike characters, empty words, quotes and long input", () => {
|
|
1254
|
+
test.each([
|
|
1255
|
+
["journalctl -u nginx \u2014follow -n 10"],
|
|
1256
|
+
["journalctl -u nginx \u2212f -n 10"],
|
|
1257
|
+
["journalctl -u nginx \u2013f -n 10"],
|
|
1258
|
+
["systemctl restart ngin\u0445"],
|
|
1259
|
+
["systemctl restart nginx\u200b"],
|
|
1260
|
+
["kill \uff11\uff12\uff13\uff14"],
|
|
1261
|
+
["cat /proc/loadavg\u00a0/etc/shadow"],
|
|
1262
|
+
["systemctl \uff52estart nginx"],
|
|
1263
|
+
["ps aux\u0435"],
|
|
1264
|
+
])("%p is Denied as non-ASCII", (command: string) => {
|
|
1265
|
+
const result: ResourceCommandPolicyResult = evaluate(command);
|
|
1266
|
+
|
|
1267
|
+
expect(result.tier).toBe(ResourceCommandTier.Denied);
|
|
1268
|
+
expect(result.reason).toMatch(/printable ASCII|not a program/);
|
|
1269
|
+
});
|
|
1270
|
+
|
|
1271
|
+
test("a look-alike program name never reaches the policy", () => {
|
|
1272
|
+
expect(evaluate("systemct\u04cf status nginx").reason).toContain(
|
|
1273
|
+
"not a program",
|
|
1274
|
+
);
|
|
1275
|
+
});
|
|
1276
|
+
|
|
1277
|
+
test("a control character inside a word is refused", () => {
|
|
1278
|
+
expect(
|
|
1279
|
+
HostCommandPolicy.evaluateArgv(["systemctl", "status", "ng\tinx"]).reason,
|
|
1280
|
+
).toContain("printable ASCII");
|
|
1281
|
+
expect(HostCommandPolicy.evaluateArgv(["kill", "12\u00073"]).tier).toBe(
|
|
1282
|
+
ResourceCommandTier.Denied,
|
|
1283
|
+
);
|
|
1284
|
+
});
|
|
1285
|
+
|
|
1286
|
+
test.each([
|
|
1287
|
+
[["systemctl", "restart", ""]],
|
|
1288
|
+
[["systemctl", "status", ""]],
|
|
1289
|
+
[["systemctl", ""]],
|
|
1290
|
+
[["journalctl", "-n", "10", ""]],
|
|
1291
|
+
[["journalctl", "-u", "", "-n", "1"]],
|
|
1292
|
+
[["kill", ""]],
|
|
1293
|
+
[["kill", "-9", ""]],
|
|
1294
|
+
[["cat", ""]],
|
|
1295
|
+
[["ps", ""]],
|
|
1296
|
+
[["ip", ""]],
|
|
1297
|
+
[["df", ""]],
|
|
1298
|
+
[["uptime", ""]],
|
|
1299
|
+
[["lsblk", ""]],
|
|
1300
|
+
[["top", "-b", "-n", ""]],
|
|
1301
|
+
[["hostnamectl", ""]],
|
|
1302
|
+
])("an empty word is Denied: %j", (argv: Array<string>) => {
|
|
1303
|
+
expect(
|
|
1304
|
+
ResourceCommandPolicy.evaluateArgv({
|
|
1305
|
+
resourceType: AiResourceType.Host,
|
|
1306
|
+
argv,
|
|
1307
|
+
}).tier,
|
|
1308
|
+
).toBe(ResourceCommandTier.Denied);
|
|
1309
|
+
expect(HostCommandPolicy.evaluateArgv(argv).tier).toBe(
|
|
1310
|
+
ResourceCommandTier.Denied,
|
|
1311
|
+
);
|
|
1312
|
+
});
|
|
1313
|
+
|
|
1314
|
+
test.each([[""], [" "], ["''"]])("%p is Denied", (command: string) => {
|
|
1315
|
+
expect(evaluate(command).tier).toBe(ResourceCommandTier.Denied);
|
|
1316
|
+
});
|
|
1317
|
+
|
|
1318
|
+
test("quoted values are one word, rendered back with quotes", () => {
|
|
1319
|
+
const since: ResourceCommandPolicyResult = evaluate(
|
|
1320
|
+
'journalctl -u nginx --since "2024-05-01 10:00:00" -n 100',
|
|
1321
|
+
);
|
|
1322
|
+
|
|
1323
|
+
expect(since.tier).toBe(ResourceCommandTier.Read);
|
|
1324
|
+
expect(since.args).toContain("2024-05-01 10:00:00");
|
|
1325
|
+
expect(since.displayCommand).toBe(
|
|
1326
|
+
"journalctl -u nginx --since '2024-05-01 10:00:00' -n 100",
|
|
1327
|
+
);
|
|
1328
|
+
|
|
1329
|
+
const grep: ResourceCommandPolicyResult = evaluate(
|
|
1330
|
+
'journalctl -g "a|b" -n 5',
|
|
1331
|
+
);
|
|
1332
|
+
|
|
1333
|
+
expect(grep.tier).toBe(ResourceCommandTier.Read);
|
|
1334
|
+
expect(grep.displayCommand).toBe("journalctl -g 'a|b' -n 5");
|
|
1335
|
+
expect(tokenizeResourceCommand(grep.displayCommand).argv).toEqual([
|
|
1336
|
+
"journalctl",
|
|
1337
|
+
"-g",
|
|
1338
|
+
"a|b",
|
|
1339
|
+
"-n",
|
|
1340
|
+
"5",
|
|
1341
|
+
]);
|
|
1342
|
+
});
|
|
1343
|
+
|
|
1344
|
+
test("very long input is refused, never slow and never thrown", () => {
|
|
1345
|
+
expect(evaluate(`journalctl -n 1 -g ${"a".repeat(3000)}`).tier).toBe(
|
|
1346
|
+
ResourceCommandTier.Denied,
|
|
1347
|
+
);
|
|
1348
|
+
expect(
|
|
1349
|
+
HostCommandPolicy.evaluateArgv([
|
|
1350
|
+
"journalctl",
|
|
1351
|
+
"-n",
|
|
1352
|
+
"10",
|
|
1353
|
+
"-g",
|
|
1354
|
+
"a".repeat(10000),
|
|
1355
|
+
]).reason,
|
|
1356
|
+
).toContain("1 to 256");
|
|
1357
|
+
expect(
|
|
1358
|
+
HostCommandPolicy.evaluateArgv(["systemctl", "status", "a".repeat(300)])
|
|
1359
|
+
.tier,
|
|
1360
|
+
).toBe(ResourceCommandTier.Denied);
|
|
1361
|
+
expect(
|
|
1362
|
+
HostCommandPolicy.evaluateArgv(["ps", "-o", `${"pid,".repeat(200)}pid`])
|
|
1363
|
+
.tier,
|
|
1364
|
+
).toBe(ResourceCommandTier.Denied);
|
|
1365
|
+
expect(
|
|
1366
|
+
HostCommandPolicy.evaluateArgv([
|
|
1367
|
+
"systemctl",
|
|
1368
|
+
"list-units",
|
|
1369
|
+
`${"*a".repeat(5000)}b`,
|
|
1370
|
+
]).tier,
|
|
1371
|
+
).toBe(ResourceCommandTier.Denied);
|
|
1372
|
+
|
|
1373
|
+
const started: number = Date.now();
|
|
1374
|
+
const many: Array<string> = ["kill", ...new Array(5000).fill("1234")];
|
|
1375
|
+
|
|
1376
|
+
expect(HostCommandPolicy.evaluateArgv(many).targets).toEqual(["pid:1234"]);
|
|
1377
|
+
expect(
|
|
1378
|
+
ResourceCommandPolicy.evaluateArgv({
|
|
1379
|
+
resourceType: AiResourceType.Host,
|
|
1380
|
+
argv: many,
|
|
1381
|
+
}).tier,
|
|
1382
|
+
).toBe(ResourceCommandTier.Denied);
|
|
1383
|
+
expect(Date.now() - started).toBeLessThan(2000);
|
|
1384
|
+
});
|
|
1385
|
+
|
|
1386
|
+
test.each([
|
|
1387
|
+
[["df", `/${"a".repeat(50000)}!`]],
|
|
1388
|
+
[["df", `/${"a/".repeat(20000)}!`]],
|
|
1389
|
+
[["lsblk", `/dev/${"a".repeat(50000)}!`]],
|
|
1390
|
+
[["journalctl", "-n", "1", "--since", `${"1".repeat(50000)}!`]],
|
|
1391
|
+
[["ps", "-p", `${"1,".repeat(20000)}x`]],
|
|
1392
|
+
[["ps", "-u", `${"a,".repeat(20000)}!`]],
|
|
1393
|
+
[["ss", `${"a".repeat(50000)}$`]],
|
|
1394
|
+
[["ip", "route", "get", `${"1".repeat(50000)}`]],
|
|
1395
|
+
[["systemctl", "list-units", `${"a".repeat(50000)}!`]],
|
|
1396
|
+
])(
|
|
1397
|
+
"a long pathological word is refused quickly: %#",
|
|
1398
|
+
(argv: Array<string>) => {
|
|
1399
|
+
const started: number = Date.now();
|
|
1400
|
+
|
|
1401
|
+
expect(HostCommandPolicy.evaluateArgv(argv).tier).toBe(
|
|
1402
|
+
ResourceCommandTier.Denied,
|
|
1403
|
+
);
|
|
1404
|
+
expect(Date.now() - started).toBeLessThan(1000);
|
|
1405
|
+
},
|
|
1406
|
+
);
|
|
1407
|
+
});
|
|
1408
|
+
|
|
1409
|
+
describe("totality", () => {
|
|
1410
|
+
test.each([
|
|
1411
|
+
[null],
|
|
1412
|
+
[undefined],
|
|
1413
|
+
[[]],
|
|
1414
|
+
[[1, {}, null]],
|
|
1415
|
+
[["systemctl", 7]],
|
|
1416
|
+
[["kill", null]],
|
|
1417
|
+
["systemctl status"],
|
|
1418
|
+
[{ length: 3 }],
|
|
1419
|
+
])("%p is Denied without throwing", (argv: unknown) => {
|
|
1420
|
+
const result: ResourceCommandPolicyResult = HostCommandPolicy.evaluateArgv(
|
|
1421
|
+
argv as Array<string>,
|
|
1422
|
+
);
|
|
1423
|
+
|
|
1424
|
+
expect(result.tier).toBe(ResourceCommandTier.Denied);
|
|
1425
|
+
expect(result.targets).toEqual([]);
|
|
1426
|
+
});
|
|
1427
|
+
|
|
1428
|
+
test("never throws for any program with odd words", () => {
|
|
1429
|
+
const oddWords: Array<string> = [
|
|
1430
|
+
"",
|
|
1431
|
+
"-",
|
|
1432
|
+
"--",
|
|
1433
|
+
"---",
|
|
1434
|
+
"-=",
|
|
1435
|
+
"--=",
|
|
1436
|
+
"=",
|
|
1437
|
+
"-\\",
|
|
1438
|
+
"'",
|
|
1439
|
+
"*",
|
|
1440
|
+
"-*",
|
|
1441
|
+
"__proto__",
|
|
1442
|
+
"constructor",
|
|
1443
|
+
"toString",
|
|
1444
|
+
"hasOwnProperty",
|
|
1445
|
+
];
|
|
1446
|
+
|
|
1447
|
+
for (const program of [...HOST_COMMAND_PROGRAMS, "__proto__", "toString"]) {
|
|
1448
|
+
for (const word of oddWords) {
|
|
1449
|
+
for (const argv of [
|
|
1450
|
+
[program, word],
|
|
1451
|
+
[program, word, word],
|
|
1452
|
+
[program, "-n", word],
|
|
1453
|
+
[program, word, "-n"],
|
|
1454
|
+
]) {
|
|
1455
|
+
const result: ResourceCommandPolicyResult =
|
|
1456
|
+
HostCommandPolicy.evaluateArgv(argv);
|
|
1457
|
+
|
|
1458
|
+
expect(typeof result.reason).toBe("string");
|
|
1459
|
+
expect(result.reason.length).toBeGreaterThan(0);
|
|
1460
|
+
}
|
|
1461
|
+
}
|
|
1462
|
+
}
|
|
1463
|
+
});
|
|
1464
|
+
|
|
1465
|
+
test("prototype names are never programs or verbs", () => {
|
|
1466
|
+
for (const command of [
|
|
1467
|
+
["__proto__"],
|
|
1468
|
+
["constructor"],
|
|
1469
|
+
["systemctl", "__proto__"],
|
|
1470
|
+
["systemctl", "constructor", "x"],
|
|
1471
|
+
["systemctl", "toString"],
|
|
1472
|
+
["ip", "__proto__"],
|
|
1473
|
+
["ip", "constructor"],
|
|
1474
|
+
["kill", "-constructor", "1234"],
|
|
1475
|
+
["kill", "-s", "__proto__", "1234"],
|
|
1476
|
+
["ps", "-__proto__"],
|
|
1477
|
+
]) {
|
|
1478
|
+
expect(HostCommandPolicy.evaluateArgv(command).tier).toBe(
|
|
1479
|
+
ResourceCommandTier.Denied,
|
|
1480
|
+
);
|
|
1481
|
+
}
|
|
1482
|
+
});
|
|
1483
|
+
|
|
1484
|
+
test("the caller's argv is never changed", () => {
|
|
1485
|
+
const argv: Array<string> = ["systemctl", "restart", "nginx"];
|
|
1486
|
+
|
|
1487
|
+
HostCommandPolicy.evaluateArgv(argv);
|
|
1488
|
+
|
|
1489
|
+
expect(argv).toEqual(["systemctl", "restart", "nginx"]);
|
|
1490
|
+
});
|
|
1491
|
+
});
|
|
1492
|
+
|
|
1493
|
+
describe("canonical unit names", () => {
|
|
1494
|
+
test.each([
|
|
1495
|
+
["nginx", "nginx.service"],
|
|
1496
|
+
["nginx.service", "nginx.service"],
|
|
1497
|
+
["backup.timer", "backup.timer"],
|
|
1498
|
+
["cups.socket", "cups.socket"],
|
|
1499
|
+
["app.path", "app.path"],
|
|
1500
|
+
["home.mount", "home.mount"],
|
|
1501
|
+
["data.automount", "data.automount"],
|
|
1502
|
+
["swapfile.swap", "swapfile.swap"],
|
|
1503
|
+
["multi-user.target", "multi-user.target"],
|
|
1504
|
+
["system.slice", "system.slice"],
|
|
1505
|
+
["init.scope", "init.scope"],
|
|
1506
|
+
["dev-sda.device", "dev-sda.device"],
|
|
1507
|
+
["php8.2-fpm", "php8.2-fpm.service"],
|
|
1508
|
+
["getty@tty1", "getty@tty1.service"],
|
|
1509
|
+
["nginx.foo", "nginx.foo.service"],
|
|
1510
|
+
["worker@2.service", "worker@2.service"],
|
|
1511
|
+
])("%s -> %s", (name: string, canonical: string) => {
|
|
1512
|
+
expect(canonicalSystemdUnitName(name)).toBe(canonical);
|
|
1513
|
+
});
|
|
1514
|
+
});
|
|
1515
|
+
|
|
1516
|
+
describe("through the dispatcher's ladder, allowlist and write scope", () => {
|
|
1517
|
+
test("reads are auto-approved and change nothing", () => {
|
|
1518
|
+
const verdict: ResourceAutoExecutionVerdict = autoExecution(
|
|
1519
|
+
"systemctl status nginx",
|
|
1520
|
+
);
|
|
1521
|
+
|
|
1522
|
+
expect(verdict.verdict).toBe(
|
|
1523
|
+
AiRemediationCommandPolicyVerdict.AutoApproved,
|
|
1524
|
+
);
|
|
1525
|
+
expect(verdict.tier).toBe(ResourceCommandTier.Read);
|
|
1526
|
+
});
|
|
1527
|
+
|
|
1528
|
+
test("one unit restarted runs unattended", () => {
|
|
1529
|
+
const verdict: ResourceAutoExecutionVerdict = autoExecution(
|
|
1530
|
+
"systemctl restart nginx",
|
|
1531
|
+
);
|
|
1532
|
+
|
|
1533
|
+
expect(verdict.verdict).toBe(
|
|
1534
|
+
AiRemediationCommandPolicyVerdict.AutoApproved,
|
|
1535
|
+
);
|
|
1536
|
+
expect(verdict.tier).toBe(ResourceCommandTier.SafeWrite);
|
|
1537
|
+
});
|
|
1538
|
+
|
|
1539
|
+
test("a stop needs approval unless allowlisted or bypassed", () => {
|
|
1540
|
+
expect(autoExecution("systemctl stop nginx").verdict).toBe(
|
|
1541
|
+
AiRemediationCommandPolicyVerdict.RequiresApproval,
|
|
1542
|
+
);
|
|
1543
|
+
expect(
|
|
1544
|
+
autoExecution("systemctl stop nginx", ["systemctl stop nginx"]).verdict,
|
|
1545
|
+
).toBe(AiRemediationCommandPolicyVerdict.AutoApproved);
|
|
1546
|
+
expect(
|
|
1547
|
+
autoExecution("systemctl stop nginx", ["systemctl stop *"]).reason,
|
|
1548
|
+
).toBe("Matched the resource's command allowlist.");
|
|
1549
|
+
expect(autoExecution("systemctl stop nginx", [], true).verdict).toBe(
|
|
1550
|
+
AiRemediationCommandPolicyVerdict.AutoApproved,
|
|
1551
|
+
);
|
|
1552
|
+
expect(
|
|
1553
|
+
autoExecution("systemctl stop nginx.service", ["systemctl stop nginx"])
|
|
1554
|
+
.verdict,
|
|
1555
|
+
).toBe(AiRemediationCommandPolicyVerdict.RequiresApproval);
|
|
1556
|
+
expect(
|
|
1557
|
+
autoExecution("systemctl stop nginx php-fpm", ["systemctl stop *"])
|
|
1558
|
+
.verdict,
|
|
1559
|
+
).toBe(AiRemediationCommandPolicyVerdict.RequiresApproval);
|
|
1560
|
+
});
|
|
1561
|
+
|
|
1562
|
+
test.each([
|
|
1563
|
+
[
|
|
1564
|
+
"systemctl restart sshd",
|
|
1565
|
+
["systemctl restart sshd", "systemctl restart *"],
|
|
1566
|
+
],
|
|
1567
|
+
["systemctl start multi-user.target", ["systemctl start *"]],
|
|
1568
|
+
["kill -9 1234", ["kill -9 *", "kill -9 1234"]],
|
|
1569
|
+
["kill 1234", ["kill 1234 *"]],
|
|
1570
|
+
])(
|
|
1571
|
+
"%s needs a human whatever the mode or allowlist",
|
|
1572
|
+
(command: string, allowlist: Array<string>) => {
|
|
1573
|
+
const verdict: ResourceAutoExecutionVerdict = autoExecution(
|
|
1574
|
+
command,
|
|
1575
|
+
allowlist,
|
|
1576
|
+
true,
|
|
1577
|
+
);
|
|
1578
|
+
|
|
1579
|
+
expect(verdict.verdict).toBe(
|
|
1580
|
+
AiRemediationCommandPolicyVerdict.RequiresApproval,
|
|
1581
|
+
);
|
|
1582
|
+
expect(verdict.requiresHuman).toBe(true);
|
|
1583
|
+
},
|
|
1584
|
+
);
|
|
1585
|
+
|
|
1586
|
+
test("Denied commands stay Denied whoever approves them", () => {
|
|
1587
|
+
for (const command of [
|
|
1588
|
+
"systemctl reboot",
|
|
1589
|
+
"systemctl start reboot.target",
|
|
1590
|
+
"journalctl -f",
|
|
1591
|
+
"kill 1",
|
|
1592
|
+
"cat /etc/shadow",
|
|
1593
|
+
]) {
|
|
1594
|
+
const verdict: ResourceAutoExecutionVerdict = autoExecution(
|
|
1595
|
+
command,
|
|
1596
|
+
[command],
|
|
1597
|
+
true,
|
|
1598
|
+
);
|
|
1599
|
+
|
|
1600
|
+
expect(verdict.verdict).toBe(AiRemediationCommandPolicyVerdict.Denied);
|
|
1601
|
+
expect(verdict.reason).toContain("cannot run even with human approval");
|
|
1602
|
+
}
|
|
1603
|
+
});
|
|
1604
|
+
|
|
1605
|
+
test("a journal vacuum can be allowlisted when its value is its own word", () => {
|
|
1606
|
+
expect(
|
|
1607
|
+
ResourceCommandPolicy.describeAllowlistPatternProblem({
|
|
1608
|
+
resourceType: AiResourceType.Host,
|
|
1609
|
+
pattern: "journalctl --vacuum-time 7d",
|
|
1610
|
+
}),
|
|
1611
|
+
).toBeNull();
|
|
1612
|
+
expect(
|
|
1613
|
+
autoExecution("journalctl --vacuum-time 7d", [
|
|
1614
|
+
"journalctl --vacuum-time 7d",
|
|
1615
|
+
]).verdict,
|
|
1616
|
+
).toBe(AiRemediationCommandPolicyVerdict.AutoApproved);
|
|
1617
|
+
expect(
|
|
1618
|
+
ResourceCommandPolicy.describeAllowlistPatternProblem({
|
|
1619
|
+
resourceType: AiResourceType.Host,
|
|
1620
|
+
pattern: "journalctl --vacuum-time=7d",
|
|
1621
|
+
}),
|
|
1622
|
+
).toContain("fewer than two words");
|
|
1623
|
+
});
|
|
1624
|
+
|
|
1625
|
+
test.each([
|
|
1626
|
+
["systemctl stop *", null],
|
|
1627
|
+
["systemctl restart *", null],
|
|
1628
|
+
["systemctl stop * *", null],
|
|
1629
|
+
["journalctl --vacuum-time *", null],
|
|
1630
|
+
["systemctl status *", "read-only command"],
|
|
1631
|
+
["journalctl -n *", "read-only command"],
|
|
1632
|
+
["systemctl * nginx", "where the command goes"],
|
|
1633
|
+
["systemctl isolate rescue.target", "can never match a command that runs"],
|
|
1634
|
+
["journalctl -u *", "can never match a command that runs"],
|
|
1635
|
+
["docker restart web", "does not start with a program"],
|
|
1636
|
+
["systemctl reboot", "fewer than two words"],
|
|
1637
|
+
])("allowlist entry %p: %p", (pattern: string, problem: string | null) => {
|
|
1638
|
+
const described: string | null =
|
|
1639
|
+
ResourceCommandPolicy.describeAllowlistPatternProblem({
|
|
1640
|
+
resourceType: AiResourceType.Host,
|
|
1641
|
+
pattern,
|
|
1642
|
+
});
|
|
1643
|
+
|
|
1644
|
+
if (problem === null) {
|
|
1645
|
+
expect(described).toBeNull();
|
|
1646
|
+
} else {
|
|
1647
|
+
expect(described).toContain(problem);
|
|
1648
|
+
}
|
|
1649
|
+
});
|
|
1650
|
+
|
|
1651
|
+
test.each([
|
|
1652
|
+
["systemctl stop *", true],
|
|
1653
|
+
["systemctl restart * nginx", true],
|
|
1654
|
+
["kill -9 *", true],
|
|
1655
|
+
["systemctl stop nginx", false],
|
|
1656
|
+
["journalctl --vacuum-time *", false],
|
|
1657
|
+
["systemctl status *", false],
|
|
1658
|
+
])("allowlist entry %p is broad: %p", (pattern: string, broad: boolean) => {
|
|
1659
|
+
expect(
|
|
1660
|
+
ResourceCommandPolicy.isBroadAllowlistPattern({
|
|
1661
|
+
resourceType: AiResourceType.Host,
|
|
1662
|
+
pattern,
|
|
1663
|
+
}),
|
|
1664
|
+
).toBe(broad);
|
|
1665
|
+
});
|
|
1666
|
+
|
|
1667
|
+
test("matchesAllowlist compares word by word", () => {
|
|
1668
|
+
const matches: (command: string, patterns: Array<string>) => boolean = (
|
|
1669
|
+
command: string,
|
|
1670
|
+
patterns: Array<string>,
|
|
1671
|
+
): boolean => {
|
|
1672
|
+
return ResourceCommandPolicy.matchesAllowlist({
|
|
1673
|
+
resourceType: AiResourceType.Host,
|
|
1674
|
+
command,
|
|
1675
|
+
patterns,
|
|
1676
|
+
});
|
|
1677
|
+
};
|
|
1678
|
+
|
|
1679
|
+
expect(matches("systemctl stop nginx", ["systemctl stop nginx"])).toBe(
|
|
1680
|
+
true,
|
|
1681
|
+
);
|
|
1682
|
+
expect(matches("systemctl stop nginx", ["systemctl stop *"])).toBe(true);
|
|
1683
|
+
expect(matches("systemctl stop nginx", ["systemctl * nginx"])).toBe(false);
|
|
1684
|
+
expect(matches("systemctl stop nginx", ["systemctl status nginx"])).toBe(
|
|
1685
|
+
false,
|
|
1686
|
+
);
|
|
1687
|
+
expect(matches("systemctl stop nginx", ["systemctl stop redis"])).toBe(
|
|
1688
|
+
false,
|
|
1689
|
+
);
|
|
1690
|
+
expect(matches("systemctl stop a b", ["systemctl stop *"])).toBe(false);
|
|
1691
|
+
});
|
|
1692
|
+
|
|
1693
|
+
test("writes are refused on a read-only agent, naming the switch", () => {
|
|
1694
|
+
const refusal: string | null = writeScope("systemctl restart nginx", {
|
|
1695
|
+
allowWrites: false,
|
|
1696
|
+
});
|
|
1697
|
+
|
|
1698
|
+
expect(refusal).toContain("ONEUPTIME_AI_ALLOW_WRITES=true");
|
|
1699
|
+
expect(refusal).toContain("Host AI agent");
|
|
1700
|
+
expect(writeScope("systemctl status nginx", { allowWrites: false })).toBe(
|
|
1701
|
+
null,
|
|
1702
|
+
);
|
|
1703
|
+
});
|
|
1704
|
+
|
|
1705
|
+
test("write targets are compared as canonical names", () => {
|
|
1706
|
+
expect(writeScope("systemctl restart nginx")).toBeNull();
|
|
1707
|
+
expect(
|
|
1708
|
+
writeScope("systemctl restart nginx", {
|
|
1709
|
+
writeTargets: ["nginx.service"],
|
|
1710
|
+
}),
|
|
1711
|
+
).toBeNull();
|
|
1712
|
+
expect(
|
|
1713
|
+
writeScope("systemctl restart nginx", { writeTargets: ["nginx*"] }),
|
|
1714
|
+
).toBeNull();
|
|
1715
|
+
expect(
|
|
1716
|
+
writeScope("systemctl restart nginx", { writeTargets: ["nginx"] }),
|
|
1717
|
+
).toContain("outside the targets");
|
|
1718
|
+
expect(
|
|
1719
|
+
writeScope("systemctl restart nginx redis", {
|
|
1720
|
+
writeTargets: ["nginx.service"],
|
|
1721
|
+
}),
|
|
1722
|
+
).toContain("redis.service");
|
|
1723
|
+
});
|
|
1724
|
+
|
|
1725
|
+
test("the agent's own unit and pid are protected", () => {
|
|
1726
|
+
expect(
|
|
1727
|
+
writeScope("systemctl restart oneuptime-host-ai-agent", {
|
|
1728
|
+
protectedTargets: ["oneuptime-host-ai-agent.service"],
|
|
1729
|
+
}),
|
|
1730
|
+
).toContain("protects");
|
|
1731
|
+
expect(
|
|
1732
|
+
writeScope("kill -9 4242", { protectedTargets: ["pid:4242"] }),
|
|
1733
|
+
).toContain("protects");
|
|
1734
|
+
expect(writeScope("kill -9 4242", { writeTargets: ["pid:*"] })).toBeNull();
|
|
1735
|
+
});
|
|
1736
|
+
|
|
1737
|
+
test("a vacuum and a reset of every unit are scoped too", () => {
|
|
1738
|
+
expect(
|
|
1739
|
+
writeScope("journalctl --vacuum-time=7d", { writeTargets: ["journal"] }),
|
|
1740
|
+
).toBeNull();
|
|
1741
|
+
expect(
|
|
1742
|
+
writeScope("journalctl --vacuum-time=7d", {
|
|
1743
|
+
writeTargets: ["nginx.service"],
|
|
1744
|
+
}),
|
|
1745
|
+
).toContain("journal");
|
|
1746
|
+
expect(
|
|
1747
|
+
writeScope("systemctl reset-failed", {
|
|
1748
|
+
writeTargets: ["nginx.service"],
|
|
1749
|
+
}),
|
|
1750
|
+
).toContain("does not name the objects");
|
|
1751
|
+
});
|
|
1752
|
+
|
|
1753
|
+
test("a Denied command is refused by the write scope as well", () => {
|
|
1754
|
+
expect(writeScope("systemctl reboot")).toContain(
|
|
1755
|
+
"denied by the command policy",
|
|
1756
|
+
);
|
|
1757
|
+
});
|
|
1758
|
+
});
|
|
1759
|
+
|
|
1760
|
+
describe("process listings are redacted (ps, top)", () => {
|
|
1761
|
+
function redactPs(text: string, program: string = "ps"): string {
|
|
1762
|
+
return redactResourceCommandOutput({
|
|
1763
|
+
resourceType: AiResourceType.Host,
|
|
1764
|
+
program,
|
|
1765
|
+
text,
|
|
1766
|
+
});
|
|
1767
|
+
}
|
|
1768
|
+
|
|
1769
|
+
function hook(program: string): ResourceOutputRedactionHook {
|
|
1770
|
+
const hooks: ReadonlyArray<ResourceOutputRedactionHook> =
|
|
1771
|
+
getResourceOutputRedactionHooks(program);
|
|
1772
|
+
|
|
1773
|
+
expect(hooks.length).toBeGreaterThan(0);
|
|
1774
|
+
|
|
1775
|
+
return hooks[0] as ResourceOutputRedactionHook;
|
|
1776
|
+
}
|
|
1777
|
+
|
|
1778
|
+
test("ps, top and systemctl share the hook, journalctl has its own, other host programs rely on the generic rules", () => {
|
|
1779
|
+
expect(RESOURCE_OUTPUT_REDACTION_HOOKS["ps"]).toBeDefined();
|
|
1780
|
+
expect(RESOURCE_OUTPUT_REDACTION_HOOKS["top"]).toBeDefined();
|
|
1781
|
+
expect(hook("ps")).toBe(hook("top"));
|
|
1782
|
+
expect(hook("systemctl")).toBe(hook("ps"));
|
|
1783
|
+
expect(hook("journalctl")).not.toBe(hook("ps"));
|
|
1784
|
+
expect(getResourceOutputRedactionHooks("df")).toEqual([]);
|
|
1785
|
+
expect(getResourceOutputRedactionHooks("ss")).toEqual([]);
|
|
1786
|
+
});
|
|
1787
|
+
|
|
1788
|
+
test("systemctl status: the command lines in a unit's cgroup tree are masked as ps masks them", () => {
|
|
1789
|
+
const text: string = [
|
|
1790
|
+
"● backup.service - Nightly backup",
|
|
1791
|
+
" Loaded: loaded (/etc/systemd/system/backup.service; enabled; preset: enabled)",
|
|
1792
|
+
" Active: active (running) since Tue 2026-09-29 10:00:00 UTC; 1min ago",
|
|
1793
|
+
" Main PID: 1234 (curl)",
|
|
1794
|
+
" Tasks: 2 (limit: 4915)",
|
|
1795
|
+
" CGroup: /system.slice/backup.service",
|
|
1796
|
+
" ├─1234 /usr/bin/curl -u admin:pw12345 https://backup.example.com/upload",
|
|
1797
|
+
" └─1240 /opt/app --token abcdef123456 -Dapp.db.password=hunter2 --port 80",
|
|
1798
|
+
"",
|
|
1799
|
+
"Sep 29 10:00:00 host systemd[1]: Started backup.service - Nightly backup.",
|
|
1800
|
+
].join("\n");
|
|
1801
|
+
const redacted: string = redactPs(text, "systemctl");
|
|
1802
|
+
|
|
1803
|
+
for (const secret of ["pw12345", "abcdef123456", "hunter2"]) {
|
|
1804
|
+
expect(redacted).not.toContain(secret);
|
|
1805
|
+
}
|
|
1806
|
+
expect(redacted).toContain(
|
|
1807
|
+
"-u admin:[redacted] https://backup.example.com/upload",
|
|
1808
|
+
);
|
|
1809
|
+
expect(redacted).toContain(
|
|
1810
|
+
"--token [redacted] -Dapp.db.password=[redacted] --port 80",
|
|
1811
|
+
);
|
|
1812
|
+
expect(redacted).toContain("Main PID: 1234 (curl)");
|
|
1813
|
+
expect(redacted).toContain("Tasks: 2 (limit: 4915)");
|
|
1814
|
+
});
|
|
1815
|
+
|
|
1816
|
+
test("journalctl: a message's command line, and -o json's _CMDLINE, decoded and re-encoded as valid JSON", () => {
|
|
1817
|
+
const record: Record<string, unknown> = {
|
|
1818
|
+
__CURSOR: "s=abc;i=1",
|
|
1819
|
+
__REALTIME_TIMESTAMP: "1790000000000000",
|
|
1820
|
+
_PID: "1234",
|
|
1821
|
+
_COMM: "curl",
|
|
1822
|
+
_CMDLINE: "/usr/bin/curl -u admin:pw12345 https://backup.example.com",
|
|
1823
|
+
MESSAGE: "upload started",
|
|
1824
|
+
PRIORITY: "6",
|
|
1825
|
+
_BINARY: [1, 2, 3],
|
|
1826
|
+
};
|
|
1827
|
+
const json: string = redactPs(
|
|
1828
|
+
[JSON.stringify(record), JSON.stringify({ MESSAGE: "all quiet" })].join(
|
|
1829
|
+
"\n",
|
|
1830
|
+
),
|
|
1831
|
+
"journalctl",
|
|
1832
|
+
);
|
|
1833
|
+
const lines: Array<string> = json.split("\n");
|
|
1834
|
+
const first: Record<string, unknown> = JSON.parse(lines[0]!);
|
|
1835
|
+
|
|
1836
|
+
expect(json).not.toContain("pw12345");
|
|
1837
|
+
expect(first["_CMDLINE"]).toBe(
|
|
1838
|
+
"/usr/bin/curl -u admin:[redacted] https://backup.example.com",
|
|
1839
|
+
);
|
|
1840
|
+
expect(first["_BINARY"]).toEqual([1, 2, 3]);
|
|
1841
|
+
expect(first["MESSAGE"]).toBe("upload started");
|
|
1842
|
+
expect(lines[1]).toBe(JSON.stringify({ MESSAGE: "all quiet" }));
|
|
1843
|
+
|
|
1844
|
+
// The last word of a command line: the record still parses.
|
|
1845
|
+
const last: string = redactPs(
|
|
1846
|
+
JSON.stringify({ _CMDLINE: "app --password hunter2" }),
|
|
1847
|
+
"journalctl",
|
|
1848
|
+
);
|
|
1849
|
+
expect(JSON.parse(last)).toEqual({ _CMDLINE: "app --password [redacted]" });
|
|
1850
|
+
|
|
1851
|
+
/*
|
|
1852
|
+
* A record whose MESSAGE holds a replacement pattern ("$&", "$'", "$`")
|
|
1853
|
+
* never gets the original, unmasked record pasted back in, and keeps
|
|
1854
|
+
* its surrounding whitespace.
|
|
1855
|
+
*/
|
|
1856
|
+
for (const pattern of ["$&", "$'", "$`", "$$"]) {
|
|
1857
|
+
const patterned: string = redactPs(
|
|
1858
|
+
` ${JSON.stringify({
|
|
1859
|
+
_CMDLINE: "/usr/bin/curl -u admin:pw12345 https://x",
|
|
1860
|
+
MESSAGE: `cost went up by ${pattern} today`,
|
|
1861
|
+
})} `,
|
|
1862
|
+
"journalctl",
|
|
1863
|
+
);
|
|
1864
|
+
|
|
1865
|
+
expect(patterned).not.toContain("pw12345");
|
|
1866
|
+
expect(patterned.startsWith(" {")).toBe(true);
|
|
1867
|
+
expect(patterned.endsWith("} ")).toBe(true);
|
|
1868
|
+
expect(JSON.parse(patterned)).toEqual({
|
|
1869
|
+
_CMDLINE: "/usr/bin/curl -u admin:[redacted] https://x",
|
|
1870
|
+
MESSAGE: `cost went up by ${pattern} today`,
|
|
1871
|
+
});
|
|
1872
|
+
}
|
|
1873
|
+
|
|
1874
|
+
const short: string = redactPs(
|
|
1875
|
+
"Sep 29 10:00:00 host backup[1234]: running curl -u admin:pw12345 https://x",
|
|
1876
|
+
"journalctl",
|
|
1877
|
+
);
|
|
1878
|
+
expect(short).not.toContain("pw12345");
|
|
1879
|
+
expect(short).toContain("-u admin:[redacted] https://x");
|
|
1880
|
+
|
|
1881
|
+
const plain: string =
|
|
1882
|
+
"Sep 29 10:00:00 host systemd[1]: Started nginx.service.";
|
|
1883
|
+
expect(redactPs(plain, "journalctl")).toBe(plain);
|
|
1884
|
+
});
|
|
1885
|
+
|
|
1886
|
+
test.each([
|
|
1887
|
+
[
|
|
1888
|
+
"root 1234 0.0 0.1 1 1 ? Ssl 10:00 0:00 /usr/bin/app --password=hunter2 --verbose",
|
|
1889
|
+
"--password=[redacted] --verbose",
|
|
1890
|
+
],
|
|
1891
|
+
[
|
|
1892
|
+
"root 1234 0.0 0.1 1 1 ? Ssl 10:00 0:00 /usr/bin/app --token abcdef123456 --port 80",
|
|
1893
|
+
"--token [redacted] --port 80",
|
|
1894
|
+
],
|
|
1895
|
+
[
|
|
1896
|
+
"root 1235 0.0 0.1 1 1 ? S 10:00 0:00 env PASSWORD=hunter2 node server.js",
|
|
1897
|
+
"PASSWORD=[redacted] node server.js",
|
|
1898
|
+
],
|
|
1899
|
+
[
|
|
1900
|
+
"app 7 0 0 1 1 ? S 1 0 app DB_PASSWORD=hunter2 API_TOKEN=tok123",
|
|
1901
|
+
"DB_PASSWORD=[redacted] API_TOKEN=[redacted]",
|
|
1902
|
+
],
|
|
1903
|
+
[
|
|
1904
|
+
"app 8 0 0 1 1 ? S 1 0 java -Dspring.datasource.password=hunter2 -jar app.jar",
|
|
1905
|
+
"-Dspring.datasource.password=[redacted] -jar app.jar",
|
|
1906
|
+
],
|
|
1907
|
+
[
|
|
1908
|
+
"app 9 0 0 1 1 ? S 1 0 curl -u admin:hunter2 https://example.com/x",
|
|
1909
|
+
"-u admin:[redacted] https://example.com/x",
|
|
1910
|
+
],
|
|
1911
|
+
[
|
|
1912
|
+
"app 10 0 0 1 1 ? S 1 0 curl --proxy-user bob:hunter2 https://x",
|
|
1913
|
+
"--proxy-user bob:[redacted] https://x",
|
|
1914
|
+
],
|
|
1915
|
+
[
|
|
1916
|
+
"redis 999 0.1 0.2 1 1 ? Ssl 10:00 0:01 redis-server *:6379 --requirepass hunter2",
|
|
1917
|
+
"--requirepass [redacted]",
|
|
1918
|
+
],
|
|
1919
|
+
[
|
|
1920
|
+
"app 11 0 0 1 1 ? S 1 0 /opt/app --api-key=K123 --client-secret S456 --auth-token A789",
|
|
1921
|
+
"--api-key=[redacted] --client-secret [redacted] --auth-token [redacted]",
|
|
1922
|
+
],
|
|
1923
|
+
[
|
|
1924
|
+
"app 12 0 0 1 1 ? S 1 0 app --db-pass hunter2 --secret=abc",
|
|
1925
|
+
"--db-pass [redacted] --secret=[redacted]",
|
|
1926
|
+
],
|
|
1927
|
+
])("the hook alone masks %p", (line: string, expected: string) => {
|
|
1928
|
+
const redaction: ResourceOutputRedaction = hook("ps")({
|
|
1929
|
+
resourceType: AiResourceType.Host,
|
|
1930
|
+
program: "ps",
|
|
1931
|
+
text: line,
|
|
1932
|
+
});
|
|
1933
|
+
|
|
1934
|
+
expect(redaction.text).toContain(expected);
|
|
1935
|
+
expect(redaction.text).not.toContain("hunter2");
|
|
1936
|
+
expect(redaction.redactionCount).toBeGreaterThan(0);
|
|
1937
|
+
expect(redactPs(line)).not.toContain("hunter2");
|
|
1938
|
+
});
|
|
1939
|
+
|
|
1940
|
+
test("top batch output is masked the same way", () => {
|
|
1941
|
+
const text: string = [
|
|
1942
|
+
"top - 10:00:00 up 3 days, 1 user, load average: 0.10, 0.20, 0.30",
|
|
1943
|
+
" PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND",
|
|
1944
|
+
" 1234 app 20 0 123456 6789 1234 S 0.0 0.1 0:00.01 app --token=s3cr3t-token --port 80",
|
|
1945
|
+
].join("\n");
|
|
1946
|
+
const redacted: string = redactPs(text, "top");
|
|
1947
|
+
|
|
1948
|
+
expect(redacted).not.toContain("s3cr3t-token");
|
|
1949
|
+
expect(redacted).toContain("--token=[redacted] --port 80");
|
|
1950
|
+
expect(redacted).toContain("load average: 0.10, 0.20, 0.30");
|
|
1951
|
+
});
|
|
1952
|
+
|
|
1953
|
+
test("ordinary process listings pass through unchanged", () => {
|
|
1954
|
+
const text: string = [
|
|
1955
|
+
"USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND",
|
|
1956
|
+
"root 1 0.0 0.1 167720 11852 ? Ss Sep01 0:12 /sbin/init splash",
|
|
1957
|
+
"www-data 4242 1.5 2.0 223344 45678 ? S 10:00 1:02 nginx: worker process",
|
|
1958
|
+
"postgres 777 0.3 1.1 400000 22222 ? Ss Sep01 3:00 postgres: checkpointer",
|
|
1959
|
+
"app 8080 0.0 0.5 100000 9999 ? Sl 10:00 0:00 docker run -u 1000:1000 --name web nginx:1.27",
|
|
1960
|
+
].join("\n");
|
|
1961
|
+
|
|
1962
|
+
expect(redactPs(text)).toBe(text);
|
|
1963
|
+
expect(
|
|
1964
|
+
redactResourceCommandOutputWithCount({
|
|
1965
|
+
resourceType: AiResourceType.Host,
|
|
1966
|
+
program: "ps",
|
|
1967
|
+
text,
|
|
1968
|
+
}).redactionCount,
|
|
1969
|
+
).toBe(0);
|
|
1970
|
+
});
|
|
1971
|
+
|
|
1972
|
+
test("edge cases: a flag with no value, a flag followed by a flag, empty values", () => {
|
|
1973
|
+
const run: (text: string) => ResourceOutputRedaction = (
|
|
1974
|
+
text: string,
|
|
1975
|
+
): ResourceOutputRedaction => {
|
|
1976
|
+
return hook("ps")({
|
|
1977
|
+
resourceType: AiResourceType.Host,
|
|
1978
|
+
program: "ps",
|
|
1979
|
+
text,
|
|
1980
|
+
});
|
|
1981
|
+
};
|
|
1982
|
+
|
|
1983
|
+
expect(run("app --password").text).toBe("app --password");
|
|
1984
|
+
expect(run("app --password --verbose").text).toBe(
|
|
1985
|
+
"app --password --verbose",
|
|
1986
|
+
);
|
|
1987
|
+
expect(run("app --password= --x").text).toBe("app --password= --x");
|
|
1988
|
+
expect(run("app --password=[redacted]").redactionCount).toBe(0);
|
|
1989
|
+
expect(run("").text).toBe("");
|
|
1990
|
+
expect(run("a\n--token t1\n--token t2").text).toBe(
|
|
1991
|
+
"a\n--token [redacted]\n--token [redacted]",
|
|
1992
|
+
);
|
|
1993
|
+
expect(run("a\n--token t1\n--token t2").redactionCount).toBe(2);
|
|
1994
|
+
});
|
|
1995
|
+
|
|
1996
|
+
test("counts every masked value, hook and generic rules together", () => {
|
|
1997
|
+
const counted: ResourceOutputRedaction =
|
|
1998
|
+
redactResourceCommandOutputWithCount({
|
|
1999
|
+
resourceType: AiResourceType.Host,
|
|
2000
|
+
program: "ps",
|
|
2001
|
+
text: "app --password=a1 --token b2 SECRET=c3",
|
|
2002
|
+
});
|
|
2003
|
+
|
|
2004
|
+
expect(counted.text).toBe(
|
|
2005
|
+
"app --password=[redacted] --token [redacted] SECRET=[redacted]",
|
|
2006
|
+
);
|
|
2007
|
+
expect(counted.redactionCount).toBe(3);
|
|
2008
|
+
});
|
|
2009
|
+
|
|
2010
|
+
test("journalctl and other host output still gets the generic rules", () => {
|
|
2011
|
+
expect(
|
|
2012
|
+
redactResourceCommandOutput({
|
|
2013
|
+
resourceType: AiResourceType.Host,
|
|
2014
|
+
program: "journalctl",
|
|
2015
|
+
text: "May 01 app[1]: connecting with DB_PASSWORD=hunter2",
|
|
2016
|
+
}),
|
|
2017
|
+
).not.toContain("hunter2");
|
|
2018
|
+
});
|
|
2019
|
+
});
|