@oneuptime/common 14.0.9 → 14.0.10
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/AutoRemediationSuggestion.ts +60 -0
- package/Models/DatabaseModels/CephCluster.ts +213 -0
- package/Models/DatabaseModels/DatabaseServer.ts +213 -0
- package/Models/DatabaseModels/DockerHost.ts +213 -0
- package/Models/DatabaseModels/DockerSwarmCluster.ts +213 -0
- package/Models/DatabaseModels/GlobalConfig.ts +1 -1
- package/Models/DatabaseModels/Host.ts +213 -0
- package/Models/DatabaseModels/Index.ts +2 -0
- package/Models/DatabaseModels/PodmanHost.ts +213 -0
- package/Models/DatabaseModels/ProxmoxCluster.ts +213 -0
- package/Models/DatabaseModels/ResourceAiAgent.ts +419 -0
- package/Models/DatabaseModels/RunnerJob.ts +144 -0
- package/Models/DatabaseModels/VMwareVCenter.ts +213 -0
- package/Server/API/AutoRemediationAPI.ts +392 -1
- package/Server/API/ResourceAiAccessAPI.ts +1669 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1796300000000-AddResourceAiAgents.ts +423 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +2 -0
- package/Server/Infrastructure/Semaphore.ts +22 -0
- package/Server/Middleware/TelemetryIngest.ts +15 -5
- 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/MetricRecordingRuleService.ts +47 -0
- package/Server/Services/PodmanHostService.ts +109 -1
- 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/TelemetryUsageBillingService.ts +28 -0
- package/Server/Services/TraceRecordingRuleService.ts +33 -0
- package/Server/Services/VMwareVCenterService.ts +110 -1
- package/Server/Utils/AI/Remediation/RemediationCommandTools.ts +1434 -32
- package/Server/Utils/AI/Remediation/RemediationExecutionRunner.ts +935 -21
- package/Server/Utils/AI/Remediation/RemediationPlanRunner.ts +25 -1
- package/Server/Utils/AI/ResourceAccess/InfrastructureInvestigationToolkit.ts +577 -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 +873 -0
- package/Server/Utils/AI/SRE/AIInvestigationEngine.ts +72 -2
- package/Server/Utils/AI/SRE/AlertInvestigationRunner.ts +72 -5
- package/Server/Utils/AI/SRE/IncidentInvestigationRunner.ts +72 -5
- 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/SessionReplay/SessionReplayBudgetMetrics.ts +920 -0
- package/Server/Utils/SessionReplay/SessionReplayUsage.ts +84 -6
- 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 +298 -224
- package/Server/Utils/Workspace/MicrosoftTeams/Actions/IncidentEpisode.ts +35 -15
- package/Server/Utils/Workspace/MicrosoftTeams/Actions/ScheduledMaintenance.ts +389 -175
- package/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.ts +366 -143
- 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/Dashboard/ClusterAccessNotice.test.tsx +93 -0
- package/Tests/App/Dashboard/DatabaseDocumentationMarkdown.test.ts +18 -6
- package/Tests/App/Dashboard/InvestigationInfrastructureTools.test.tsx +506 -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/ResourceAiAgentInstall.test.ts +860 -0
- package/Tests/App/Dashboard/ResourceAiAgentPage.test.tsx +1721 -0
- package/Tests/App/Dashboard/ResourceAiAgentStatus.test.ts +1002 -0
- package/Tests/App/Dashboard/ResourceAiInsightsPage.test.tsx +931 -0
- package/Tests/App/Dashboard/ResourceAiNavigation.test.tsx +575 -0
- package/Tests/App/Dashboard/RunbookStepTypeMaps.test.ts +38 -7
- package/Tests/Models/DatabaseModels/DatabaseServerModels.test.ts +33 -1
- package/Tests/Models/DatabaseModels/ResourceAiAccessColumns.test.ts +738 -0
- package/Tests/Models/DatabaseModels/ResourceAiAgentModel.test.ts +842 -0
- package/Tests/Server/API/AutoRemediationApproveResourceRound.test.ts +835 -0
- package/Tests/Server/API/ResourceAiAccessAPI.test.ts +2730 -0
- package/Tests/Server/Infrastructure/Postgres/AddDatabaseServerTablesMigration.test.ts +60 -0
- package/Tests/Server/Infrastructure/Postgres/AddResourceAiAgentsMigration.test.ts +659 -0
- package/Tests/Server/Infrastructure/SemaphoreMutex.test.ts +31 -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/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/MonitorProbeServiceIntervalScheduling.test.ts +45 -6
- 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/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/TelemetryUsageBillingSloExclusion.test.ts +218 -0
- package/Tests/Server/TestingUtils/Services/FakeRunnerJobCount.ts +145 -0
- package/Tests/Server/Utils/AI/InvestigationInfrastructureAccessWiring.test.ts +453 -0
- package/Tests/Server/Utils/AI/InvestigationInfrastructureReport.test.ts +721 -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/RemediationExecutionRunnerResourceMode.test.ts +1249 -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 +722 -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 +830 -0
- package/Tests/Server/Utils/AutoRemediation/CommandPlanExecutorResource.test.ts +717 -0
- package/Tests/Server/Utils/AutoRemediation/RemediationVerifierResourceFollowUp.test.ts +338 -0
- package/Tests/Server/Utils/Monitor/Criteria/SessionReplayBudgetTemplateCriteria.test.ts +422 -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/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/AutoRemediation/AiRemediationCommandPlan.test.ts +10 -4
- package/Tests/Types/AutoRemediation/AiRemediationCommandPlanResourceCommand.test.ts +305 -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 +517 -0
- package/Tests/Types/Runbook/RunbookStepType.test.ts +147 -8
- package/Tests/UI/Rum/RecordingHealthDashboard.test.tsx +769 -1
- 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/SessionReplay/SessionReplayBudgetMetricType.test.ts +383 -0
- package/Types/AI/ResourceAiAccessApi.ts +140 -0
- package/Types/AI/ResourceAiAccessPermissions.ts +126 -0
- package/Types/AutoRemediation/AiRemediationCommandPlan.ts +183 -2
- 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/ResourceAiAgent/AiResourceType.ts +310 -0
- package/Types/ResourceAiAgent/ResourceAiAccess.ts +574 -0
- package/Types/Rum/SessionReplayBudgetMetricType.ts +47 -0
- package/Types/Runbook/RunbookStepType.ts +29 -0
- package/Types/Telemetry/TelemetryIngestSurface.ts +14 -2
- 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/SessionReplay/SessionReplayBudgetMetricType.ts +184 -0
- 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 +219 -0
- package/build/dist/Models/DatabaseModels/CephCluster.js.map +1 -1
- package/build/dist/Models/DatabaseModels/DatabaseServer.js +219 -0
- package/build/dist/Models/DatabaseModels/DatabaseServer.js.map +1 -1
- package/build/dist/Models/DatabaseModels/DockerHost.js +219 -0
- package/build/dist/Models/DatabaseModels/DockerHost.js.map +1 -1
- package/build/dist/Models/DatabaseModels/DockerSwarmCluster.js +219 -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/Host.js +219 -0
- package/build/dist/Models/DatabaseModels/Host.js.map +1 -1
- package/build/dist/Models/DatabaseModels/Index.js +2 -0
- package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
- package/build/dist/Models/DatabaseModels/PodmanHost.js +219 -0
- package/build/dist/Models/DatabaseModels/PodmanHost.js.map +1 -1
- package/build/dist/Models/DatabaseModels/ProxmoxCluster.js +219 -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/RunnerJob.js +145 -0
- package/build/dist/Models/DatabaseModels/RunnerJob.js.map +1 -1
- package/build/dist/Models/DatabaseModels/VMwareVCenter.js +219 -0
- package/build/dist/Models/DatabaseModels/VMwareVCenter.js.map +1 -1
- package/build/dist/Server/API/AutoRemediationAPI.js +231 -1
- package/build/dist/Server/API/AutoRemediationAPI.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/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/Index.js +2 -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/TelemetryIngest.js +12 -5
- package/build/dist/Server/Middleware/TelemetryIngest.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/MetricRecordingRuleService.js +46 -0
- package/build/dist/Server/Services/MetricRecordingRuleService.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/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/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/VMwareVCenterService.js +104 -0
- package/build/dist/Server/Services/VMwareVCenterService.js.map +1 -1
- package/build/dist/Server/Utils/AI/Remediation/RemediationCommandTools.js +1029 -30
- package/build/dist/Server/Utils/AI/Remediation/RemediationCommandTools.js.map +1 -1
- package/build/dist/Server/Utils/AI/Remediation/RemediationExecutionRunner.js +633 -28
- 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 +330 -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 +600 -0
- package/build/dist/Server/Utils/AI/ResourceAccess/ResourceCommandJobRunner.js.map +1 -0
- package/build/dist/Server/Utils/AI/SRE/AIInvestigationEngine.js +50 -4
- package/build/dist/Server/Utils/AI/SRE/AIInvestigationEngine.js.map +1 -1
- package/build/dist/Server/Utils/AI/SRE/AlertInvestigationRunner.js +55 -4
- package/build/dist/Server/Utils/AI/SRE/AlertInvestigationRunner.js.map +1 -1
- package/build/dist/Server/Utils/AI/SRE/IncidentInvestigationRunner.js +55 -4
- package/build/dist/Server/Utils/AI/SRE/IncidentInvestigationRunner.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/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/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 +183 -209
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/Incident.js.map +1 -1
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/IncidentEpisode.js +19 -15
- 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 +263 -110
- 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/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/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/ResourceAiAgent/AiResourceType.js +242 -0
- package/build/dist/Types/ResourceAiAgent/AiResourceType.js.map +1 -0
- package/build/dist/Types/ResourceAiAgent/ResourceAiAccess.js +275 -0
- package/build/dist/Types/ResourceAiAgent/ResourceAiAccess.js.map +1 -0
- 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/Telemetry/TelemetryIngestSurface.js +13 -2
- package/build/dist/Types/Telemetry/TelemetryIngestSurface.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/SessionReplay/SessionReplayBudgetMetricType.js +160 -0
- package/build/dist/Utils/SessionReplay/SessionReplayBudgetMetricType.js.map +1 -0
- package/package.json +1 -1
|
@@ -18,7 +18,9 @@ import Incident from "../../../../Models/DatabaseModels/Incident";
|
|
|
18
18
|
import Runbook from "../../../../Models/DatabaseModels/Runbook";
|
|
19
19
|
import AIRunStatus from "../../../../Types/AI/AIRunStatus";
|
|
20
20
|
import AutoRemediationSuggestionStatus from "../../../../Types/AutoRemediation/AutoRemediationSuggestionStatus";
|
|
21
|
+
import AutoRemediationSuggestionType from "../../../../Types/AutoRemediation/AutoRemediationSuggestionType";
|
|
21
22
|
import ObjectID from "../../../../Types/ObjectID";
|
|
23
|
+
import AiResourceType from "../../../../Types/ResourceAiAgent/AiResourceType";
|
|
22
24
|
import { afterEach, beforeEach, describe, expect, it } from "@jest/globals";
|
|
23
25
|
|
|
24
26
|
/*
|
|
@@ -744,4 +746,119 @@ describe("RemediationPlanRunner.settleStrandedPlanningSuggestions", () => {
|
|
|
744
746
|
|
|
745
747
|
expect(feed).not.toHaveBeenCalled();
|
|
746
748
|
});
|
|
749
|
+
|
|
750
|
+
/*
|
|
751
|
+
* A resource round (a Docker host's, a database server's, ...) is named
|
|
752
|
+
* by its resource on the feed, never as "Auto Remediation Rule ...";
|
|
753
|
+
* rule and cluster rounds read exactly as before.
|
|
754
|
+
*/
|
|
755
|
+
describe("how the feed note names the stranded round", () => {
|
|
756
|
+
const RESOURCE_ID: ObjectID = new ObjectID(
|
|
757
|
+
"dddddddd-dddd-4ddd-8ddd-dddddddddddd",
|
|
758
|
+
);
|
|
759
|
+
|
|
760
|
+
function resourceRound(
|
|
761
|
+
overrides: Partial<Record<string, unknown>> = {},
|
|
762
|
+
): Partial<Record<string, unknown>> {
|
|
763
|
+
return {
|
|
764
|
+
autoRemediationRuleId: undefined,
|
|
765
|
+
ruleNameSnapshot: 'AI remediation for Docker host "web-1"',
|
|
766
|
+
suggestionType: AutoRemediationSuggestionType.CommandPlan,
|
|
767
|
+
resourceType: AiResourceType.DockerHost,
|
|
768
|
+
resourceId: RESOURCE_ID,
|
|
769
|
+
...overrides,
|
|
770
|
+
};
|
|
771
|
+
}
|
|
772
|
+
|
|
773
|
+
async function settleAndReadFeed(): Promise<string> {
|
|
774
|
+
const feed: jest.SpyInstance = jest
|
|
775
|
+
.spyOn(IncidentFeedService, "createIncidentFeedItem")
|
|
776
|
+
.mockResolvedValue(undefined as never);
|
|
777
|
+
jest
|
|
778
|
+
.spyOn(AutoRemediationSuggestionService, "attemptStatusTransition")
|
|
779
|
+
.mockResolvedValue(1 as never);
|
|
780
|
+
|
|
781
|
+
await RemediationPlanRunner.settleStrandedPlanningSuggestions();
|
|
782
|
+
|
|
783
|
+
expect(feed).toHaveBeenCalledTimes(1);
|
|
784
|
+
|
|
785
|
+
return String(
|
|
786
|
+
(feed.mock.calls[0]![0] as { feedInfoInMarkdown: string })
|
|
787
|
+
.feedInfoInMarkdown,
|
|
788
|
+
);
|
|
789
|
+
}
|
|
790
|
+
|
|
791
|
+
it("reads the resource columns of the Planning rounds", async () => {
|
|
792
|
+
mockPlanningList();
|
|
793
|
+
mockRun({ status: AIRunStatus.Running });
|
|
794
|
+
|
|
795
|
+
await RemediationPlanRunner.settleStrandedPlanningSuggestions();
|
|
796
|
+
|
|
797
|
+
const select: Record<string, unknown> = (
|
|
798
|
+
(AutoRemediationSuggestionService.findBy as unknown as jest.Mock).mock
|
|
799
|
+
.calls[0]![0] as { select: Record<string, unknown> }
|
|
800
|
+
).select;
|
|
801
|
+
expect(select["resourceType"]).toBe(true);
|
|
802
|
+
expect(select["resourceId"]).toBe(true);
|
|
803
|
+
});
|
|
804
|
+
|
|
805
|
+
it("a resource round is named by its resource", async () => {
|
|
806
|
+
mockPlanningList(resourceRound());
|
|
807
|
+
mockRun({ status: AIRunStatus.Error });
|
|
808
|
+
|
|
809
|
+
expect(await settleAndReadFeed()).toBe(
|
|
810
|
+
'⚡ **AI remediation for Docker host "web-1": AI planning did not complete** (the planning run failed) — no runbook was proposed.',
|
|
811
|
+
);
|
|
812
|
+
});
|
|
813
|
+
|
|
814
|
+
it("a resource round that had already run commands is named by its resource too", async () => {
|
|
815
|
+
mockPlanningList(
|
|
816
|
+
resourceRound({
|
|
817
|
+
commandPlan: {
|
|
818
|
+
commands: [
|
|
819
|
+
{
|
|
820
|
+
sequence: 1,
|
|
821
|
+
stepType: "ResourceCommand",
|
|
822
|
+
command: "docker restart web",
|
|
823
|
+
runnerId: RUN_ID.toString(),
|
|
824
|
+
resourceType: AiResourceType.DockerHost,
|
|
825
|
+
resourceId: RESOURCE_ID.toString(),
|
|
826
|
+
resourceNameSnapshot: "web-1",
|
|
827
|
+
policyVerdict: "AutoApproved",
|
|
828
|
+
rationale: "restart",
|
|
829
|
+
execution: { status: "Succeeded" },
|
|
830
|
+
},
|
|
831
|
+
],
|
|
832
|
+
},
|
|
833
|
+
}),
|
|
834
|
+
);
|
|
835
|
+
mockRun({ status: AIRunStatus.Stale });
|
|
836
|
+
|
|
837
|
+
expect(await settleAndReadFeed()).toMatch(
|
|
838
|
+
/^⚡ \*\*AI remediation for Docker host "web-1": the AI command run was interrupted after executing 1 command\(s\)\.\*\*/,
|
|
839
|
+
);
|
|
840
|
+
});
|
|
841
|
+
|
|
842
|
+
it("negative control: a rule round keeps its rule label", async () => {
|
|
843
|
+
mockPlanningList();
|
|
844
|
+
mockRun({ status: AIRunStatus.Error });
|
|
845
|
+
|
|
846
|
+
expect(await settleAndReadFeed()).toBe(
|
|
847
|
+
'⚡ **Auto Remediation Rule "Restart API pods": AI planning did not complete** (the planning run failed) — no runbook was proposed.',
|
|
848
|
+
);
|
|
849
|
+
});
|
|
850
|
+
|
|
851
|
+
it("negative control: a cluster round's note is unchanged", async () => {
|
|
852
|
+
mockPlanningList({
|
|
853
|
+
autoRemediationRuleId: undefined,
|
|
854
|
+
kubernetesClusterId: RULE_ID,
|
|
855
|
+
ruleNameSnapshot: 'AI remediation for cluster "prod-us"',
|
|
856
|
+
});
|
|
857
|
+
mockRun({ status: AIRunStatus.Error });
|
|
858
|
+
|
|
859
|
+
expect(await settleAndReadFeed()).toBe(
|
|
860
|
+
'⚡ **Auto Remediation Rule "AI remediation for cluster "prod-us"": AI planning did not complete** (the planning run failed) — no runbook was proposed.',
|
|
861
|
+
);
|
|
862
|
+
});
|
|
863
|
+
});
|
|
747
864
|
});
|
|
@@ -0,0 +1,463 @@
|
|
|
1
|
+
import {
|
|
2
|
+
buildResourceFullAutoPersona,
|
|
3
|
+
buildResourceQuestion,
|
|
4
|
+
buildResourceSuggestPersona,
|
|
5
|
+
getResourceUndoExamples,
|
|
6
|
+
} from "../../../../Server/Utils/AI/Remediation/RemediationExecutionRunner";
|
|
7
|
+
import {
|
|
8
|
+
RESOURCE_ALLOWLIST_SUMMARY,
|
|
9
|
+
RESOURCE_ALWAYS_ASKS_SUMMARY,
|
|
10
|
+
RESOURCE_AUTOMATIC_MODE_SUMMARY,
|
|
11
|
+
RESOURCE_BYPASS_MODE_SUMMARY,
|
|
12
|
+
RESOURCE_EVERY_MODE_LIMITS_SUMMARY,
|
|
13
|
+
RESOURCE_NEVER_RUNS_SUMMARY,
|
|
14
|
+
RESOURCE_RISKIER_CHANGES_SUMMARY,
|
|
15
|
+
RESOURCE_SAFE_CHANGES_SUMMARY,
|
|
16
|
+
RESOURCE_UNATTENDED_ROUND_BECOMES_PROPOSAL_SUMMARY,
|
|
17
|
+
} from "../../../../Types/AutoRemediation/AiRemediationCommandPlan";
|
|
18
|
+
import AiResourceType, {
|
|
19
|
+
AI_RESOURCE_TYPE_INFO,
|
|
20
|
+
ALL_AI_RESOURCE_TYPES,
|
|
21
|
+
} from "../../../../Types/ResourceAiAgent/AiResourceType";
|
|
22
|
+
import {
|
|
23
|
+
RESOURCE_AI_ALLOW_WRITES_ENV,
|
|
24
|
+
RESOURCE_AI_WRITE_TARGETS_ENV,
|
|
25
|
+
ResourceAiAccessStatus,
|
|
26
|
+
ResourceAiRemediationMode,
|
|
27
|
+
ResourceCommandTier,
|
|
28
|
+
} from "../../../../Types/ResourceAiAgent/ResourceAiAccess";
|
|
29
|
+
import { AiRemediationCommandPolicyVerdict } from "../../../../Types/AutoRemediation/AiRemediationCommandPolicyVerdict";
|
|
30
|
+
import ResourceCommandPolicy from "../../../../Utils/AiRemediation/Resource/ResourceCommandPolicy";
|
|
31
|
+
import {
|
|
32
|
+
ResourceAutoExecutionVerdict,
|
|
33
|
+
tokenizeResourceCommand,
|
|
34
|
+
} from "../../../../Utils/AiRemediation/Resource/ResourceCommandPolicyCore";
|
|
35
|
+
import { RUN_INFRASTRUCTURE_COMMAND_TOOL_NAME } from "../../../../Server/Utils/AI/ResourceAccess/ResourceAccessToolNames";
|
|
36
|
+
import { describe, expect, it } from "@jest/globals";
|
|
37
|
+
|
|
38
|
+
/*
|
|
39
|
+
* Contract under test — every LLM-facing description of the resource
|
|
40
|
+
* command tiers and the unattended resource modes says what the resource
|
|
41
|
+
* command policy does NOW, the way RemediationKubectlCopyParity pins the
|
|
42
|
+
* kubectl copy:
|
|
43
|
+
*
|
|
44
|
+
* - the shared summaries (AiRemediationCommandPlan's RESOURCE_*_SUMMARY)
|
|
45
|
+
* restate the canonical ResourceCommandTier / ResourceAiRemediationMode
|
|
46
|
+
* semantics: SafeWrite is ONE named object; stop, kill, scale to zero,
|
|
47
|
+
* power off and terminate are riskier; a node drain, a VM migration, host
|
|
48
|
+
* maintenance and killing a host process always need a human; destructive
|
|
49
|
+
* commands never run; the allowlist is word-wise;
|
|
50
|
+
* - each example they name, and every undo a persona recommends, is tiered
|
|
51
|
+
* that way by ResourceCommandPolicy itself — so the copy cannot drift
|
|
52
|
+
* from the policy unnoticed;
|
|
53
|
+
* - the resource personas and the question use those summaries, name the
|
|
54
|
+
* resource and its programs, and send reads to run_infrastructure_command.
|
|
55
|
+
*/
|
|
56
|
+
|
|
57
|
+
// Each phrase of the safe summary, as the model would write it, per resource type.
|
|
58
|
+
const SAFE_EXAMPLES: Array<[AiResourceType, string]> = [
|
|
59
|
+
[AiResourceType.DockerHost, "docker restart web"],
|
|
60
|
+
[AiResourceType.PodmanHost, "docker start web"],
|
|
61
|
+
[AiResourceType.DockerSwarmCluster, "docker service update --force api"],
|
|
62
|
+
[
|
|
63
|
+
AiResourceType.ProxmoxCluster,
|
|
64
|
+
"pvesh create /nodes/pve1/qemu/100/status/start",
|
|
65
|
+
],
|
|
66
|
+
[AiResourceType.VMwareVCenter, "govc vm.power -on /DC1/vm/web-01"],
|
|
67
|
+
[AiResourceType.CephCluster, "ceph osd in 3"],
|
|
68
|
+
[AiResourceType.DatabaseServer, "db cancel-query 4242"],
|
|
69
|
+
[AiResourceType.Host, "systemctl restart nginx"],
|
|
70
|
+
];
|
|
71
|
+
|
|
72
|
+
const RISKIER_EXAMPLES: Array<[AiResourceType, string]> = [
|
|
73
|
+
[AiResourceType.DockerHost, "docker stop web"],
|
|
74
|
+
[AiResourceType.DockerHost, "docker kill -s TERM web"],
|
|
75
|
+
[AiResourceType.DockerHost, "docker pause web"],
|
|
76
|
+
[AiResourceType.DockerHost, "docker update --memory 1g web"],
|
|
77
|
+
[AiResourceType.DockerSwarmCluster, "docker service scale web=0"],
|
|
78
|
+
[
|
|
79
|
+
AiResourceType.ProxmoxCluster,
|
|
80
|
+
"pvesh create /nodes/pve1/qemu/100/status/shutdown",
|
|
81
|
+
],
|
|
82
|
+
[AiResourceType.VMwareVCenter, "govc vm.power -off web-01"],
|
|
83
|
+
[AiResourceType.VMwareVCenter, "govc vm.power -reset web-01"],
|
|
84
|
+
[AiResourceType.CephCluster, "ceph osd out 3"],
|
|
85
|
+
[AiResourceType.Host, "systemctl stop nginx"],
|
|
86
|
+
[AiResourceType.DatabaseServer, "db terminate-session 4242"],
|
|
87
|
+
// Several objects at once.
|
|
88
|
+
[AiResourceType.DockerHost, "docker restart web api"],
|
|
89
|
+
];
|
|
90
|
+
|
|
91
|
+
const ALWAYS_ASKS_EXAMPLES: Array<[AiResourceType, string]> = [
|
|
92
|
+
[
|
|
93
|
+
AiResourceType.DockerSwarmCluster,
|
|
94
|
+
"docker node update --availability drain n1",
|
|
95
|
+
],
|
|
96
|
+
[
|
|
97
|
+
AiResourceType.ProxmoxCluster,
|
|
98
|
+
"pvesh create /nodes/pve1/qemu/100/migrate --target pve2",
|
|
99
|
+
],
|
|
100
|
+
[AiResourceType.VMwareVCenter, "govc host.maintenance.enter esx-01"],
|
|
101
|
+
[AiResourceType.Host, "kill -TERM 1234"],
|
|
102
|
+
];
|
|
103
|
+
|
|
104
|
+
const NEVER_RUNS_EXAMPLES: Array<[AiResourceType, string]> = [
|
|
105
|
+
[AiResourceType.DockerHost, "docker exec web sh"],
|
|
106
|
+
[AiResourceType.DockerHost, "docker run alpine"],
|
|
107
|
+
[AiResourceType.DockerHost, "docker rm web"],
|
|
108
|
+
[AiResourceType.DockerHost, "docker system prune -f"],
|
|
109
|
+
[AiResourceType.Host, "sudo systemctl restart nginx"],
|
|
110
|
+
[AiResourceType.Host, "systemctl restart nginx | tee /tmp/x"],
|
|
111
|
+
[AiResourceType.VMwareVCenter, "govc vm.destroy web-01"],
|
|
112
|
+
[AiResourceType.CephCluster, "ceph auth get client.admin"],
|
|
113
|
+
];
|
|
114
|
+
|
|
115
|
+
function readyResource(
|
|
116
|
+
resourceType: AiResourceType,
|
|
117
|
+
overrides: Partial<ResourceAiAccessStatus> = {},
|
|
118
|
+
): ResourceAiAccessStatus {
|
|
119
|
+
return {
|
|
120
|
+
resourceType,
|
|
121
|
+
resourceId: "33333333-3333-4333-8333-333333333333",
|
|
122
|
+
resourceName: "web-1",
|
|
123
|
+
isAiInvestigationEnabled: true,
|
|
124
|
+
aiRemediationMode: ResourceAiRemediationMode.Automatic,
|
|
125
|
+
aiCommandAllowlist: [],
|
|
126
|
+
agent: {
|
|
127
|
+
agentId: "44444444-4444-4444-8444-444444444444",
|
|
128
|
+
connectionStatus: "connected",
|
|
129
|
+
isOnline: true,
|
|
130
|
+
posture: {
|
|
131
|
+
resourceType,
|
|
132
|
+
resourceIdentifier: "web-1",
|
|
133
|
+
allowWrites: true,
|
|
134
|
+
writeTargets: [],
|
|
135
|
+
protectedTargets: [],
|
|
136
|
+
reachable: true,
|
|
137
|
+
},
|
|
138
|
+
},
|
|
139
|
+
gaps: [],
|
|
140
|
+
isInvestigationReady: true,
|
|
141
|
+
isRemediationReady: true,
|
|
142
|
+
...overrides,
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
describe("the shared resource tier summaries match what ResourceCommandPolicy does", () => {
|
|
147
|
+
it.each(SAFE_EXAMPLES)(
|
|
148
|
+
"a safe change is SafeWrite on a %s: %s",
|
|
149
|
+
(resourceType: AiResourceType, command: string) => {
|
|
150
|
+
expect(
|
|
151
|
+
ResourceCommandPolicy.evaluateCommand({ resourceType, command }).tier,
|
|
152
|
+
).toBe(ResourceCommandTier.SafeWrite);
|
|
153
|
+
},
|
|
154
|
+
);
|
|
155
|
+
|
|
156
|
+
it.each(RISKIER_EXAMPLES)(
|
|
157
|
+
"a riskier change is RiskyWrite on a %s: %s",
|
|
158
|
+
(resourceType: AiResourceType, command: string) => {
|
|
159
|
+
expect(
|
|
160
|
+
ResourceCommandPolicy.evaluateCommand({ resourceType, command }).tier,
|
|
161
|
+
).toBe(ResourceCommandTier.RiskyWrite);
|
|
162
|
+
},
|
|
163
|
+
);
|
|
164
|
+
|
|
165
|
+
it.each(ALWAYS_ASKS_EXAMPLES)(
|
|
166
|
+
"a change that always asks a human does so on a %s even bypassed and allowlisted: %s",
|
|
167
|
+
(resourceType: AiResourceType, command: string) => {
|
|
168
|
+
const verdict: ResourceAutoExecutionVerdict =
|
|
169
|
+
ResourceCommandPolicy.evaluateForAutoExecution({
|
|
170
|
+
resourceType,
|
|
171
|
+
command,
|
|
172
|
+
allowlistPatterns: [command],
|
|
173
|
+
bypassApproval: true,
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
expect(verdict.verdict).toBe(
|
|
177
|
+
AiRemediationCommandPolicyVerdict.RequiresApproval,
|
|
178
|
+
);
|
|
179
|
+
expect(verdict.requiresHuman).toBe(true);
|
|
180
|
+
},
|
|
181
|
+
);
|
|
182
|
+
|
|
183
|
+
it.each(NEVER_RUNS_EXAMPLES)(
|
|
184
|
+
"a destructive command never runs on a %s: %s",
|
|
185
|
+
(resourceType: AiResourceType, command: string) => {
|
|
186
|
+
expect(
|
|
187
|
+
ResourceCommandPolicy.evaluateCommand({ resourceType, command }).tier,
|
|
188
|
+
).toBe(ResourceCommandTier.Denied);
|
|
189
|
+
},
|
|
190
|
+
);
|
|
191
|
+
|
|
192
|
+
it("the summaries name what each tier covers, in the canonical words", () => {
|
|
193
|
+
expect(RESOURCE_SAFE_CHANGES_SUMMARY).toContain("exactly ONE named object");
|
|
194
|
+
expect(RESOURCE_SAFE_CHANGES_SUMMARY).toContain(
|
|
195
|
+
"never several objects at once",
|
|
196
|
+
);
|
|
197
|
+
for (const riskier of [
|
|
198
|
+
"stop",
|
|
199
|
+
"kill",
|
|
200
|
+
"scale a service to zero",
|
|
201
|
+
"power off",
|
|
202
|
+
"terminate a session",
|
|
203
|
+
"several objects at once",
|
|
204
|
+
]) {
|
|
205
|
+
expect(RESOURCE_RISKIER_CHANGES_SUMMARY).toContain(riskier);
|
|
206
|
+
}
|
|
207
|
+
for (const asks of [
|
|
208
|
+
"draining a Swarm node",
|
|
209
|
+
"migrating a VM",
|
|
210
|
+
"maintenance",
|
|
211
|
+
"killing a process on a host",
|
|
212
|
+
"in every mode — Bypass approval and the allowlist included",
|
|
213
|
+
]) {
|
|
214
|
+
expect(RESOURCE_ALWAYS_ASKS_SUMMARY).toContain(asks);
|
|
215
|
+
}
|
|
216
|
+
for (const never of ["exec", "run", "rm", "prune", "credentials", "sudo"]) {
|
|
217
|
+
expect(RESOURCE_NEVER_RUNS_SUMMARY).toContain(never);
|
|
218
|
+
}
|
|
219
|
+
expect(RESOURCE_ALLOWLIST_SUMMARY).toContain(
|
|
220
|
+
"a * stands for exactly one whole word",
|
|
221
|
+
);
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
it("the allowlist summary describes how the matcher really reads a pattern", () => {
|
|
225
|
+
// Exactly one whole word, never part of one; same length.
|
|
226
|
+
expect(
|
|
227
|
+
ResourceCommandPolicy.matchesAllowlist({
|
|
228
|
+
resourceType: AiResourceType.DockerHost,
|
|
229
|
+
command: "docker stop web",
|
|
230
|
+
patterns: ["docker stop *"],
|
|
231
|
+
}),
|
|
232
|
+
).toBe(true);
|
|
233
|
+
expect(
|
|
234
|
+
ResourceCommandPolicy.matchesAllowlist({
|
|
235
|
+
resourceType: AiResourceType.DockerHost,
|
|
236
|
+
command: "docker stop -t 5 web",
|
|
237
|
+
patterns: ["docker stop *"],
|
|
238
|
+
}),
|
|
239
|
+
).toBe(false);
|
|
240
|
+
expect(
|
|
241
|
+
ResourceCommandPolicy.matchesAllowlist({
|
|
242
|
+
resourceType: AiResourceType.DockerHost,
|
|
243
|
+
command: "docker stop web-1",
|
|
244
|
+
patterns: ["docker stop web-*"],
|
|
245
|
+
}),
|
|
246
|
+
).toBe(false);
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
it("the every-mode clause names the agent's own write switches and ends with the proposal rule", () => {
|
|
250
|
+
expect(RESOURCE_EVERY_MODE_LIMITS_SUMMARY).toContain(
|
|
251
|
+
`${RESOURCE_AI_ALLOW_WRITES_ENV}=true`,
|
|
252
|
+
);
|
|
253
|
+
expect(RESOURCE_EVERY_MODE_LIMITS_SUMMARY).toContain(
|
|
254
|
+
RESOURCE_AI_WRITE_TARGETS_ENV,
|
|
255
|
+
);
|
|
256
|
+
expect(
|
|
257
|
+
RESOURCE_EVERY_MODE_LIMITS_SUMMARY.endsWith(
|
|
258
|
+
`and ${RESOURCE_UNATTENDED_ROUND_BECOMES_PROPOSAL_SUMMARY}.`,
|
|
259
|
+
),
|
|
260
|
+
).toBe(true);
|
|
261
|
+
expect(RESOURCE_UNATTENDED_ROUND_BECOMES_PROPOSAL_SUMMARY).toBe(
|
|
262
|
+
"an unattended run becomes a proposal when the hourly per-resource circuit breaker trips or another unattended round already holds the resource",
|
|
263
|
+
);
|
|
264
|
+
});
|
|
265
|
+
|
|
266
|
+
it("the Automatic and Bypass summaries state the canonical ResourceAiRemediationMode semantics", () => {
|
|
267
|
+
expect(RESOURCE_AUTOMATIC_MODE_SUMMARY).toContain(
|
|
268
|
+
"when the round could only find riskier fixes it ends by proposing exactly those for one-click approval",
|
|
269
|
+
);
|
|
270
|
+
expect(RESOURCE_AUTOMATIC_MODE_SUMMARY).toContain(
|
|
271
|
+
"a riskier fix is proposed only if verification shows the safe ones did not recover the signal (the follow-up round, which asks)",
|
|
272
|
+
);
|
|
273
|
+
expect(RESOURCE_AUTOMATIC_MODE_SUMMARY).toContain(
|
|
274
|
+
"Shapes on the resource's command allowlist run on their own.",
|
|
275
|
+
);
|
|
276
|
+
expect(RESOURCE_BYPASS_MODE_SUMMARY).toContain("AI does not ask.");
|
|
277
|
+
expect(RESOURCE_BYPASS_MODE_SUMMARY).toContain(
|
|
278
|
+
"Every change the policy allows — safe AND riskier — runs on its own, follow-up rounds included, except for what always needs a human.",
|
|
279
|
+
);
|
|
280
|
+
expect(RESOURCE_BYPASS_MODE_SUMMARY).not.toContain("below");
|
|
281
|
+
});
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
describe("the undo every persona recommends is a safe change the policy accepts", () => {
|
|
285
|
+
/*
|
|
286
|
+
* A rollback runs unattended: on an Automatic resource the planner refuses
|
|
287
|
+
* a riskier one. Every concrete undo the personas name must therefore be
|
|
288
|
+
* a SafeWrite on ONE named object — filled in with sample names.
|
|
289
|
+
*/
|
|
290
|
+
const SAMPLE_UNDOS: Array<[AiResourceType, string]> = [
|
|
291
|
+
[AiResourceType.DockerHost, "docker start web"],
|
|
292
|
+
[AiResourceType.DockerHost, "docker unpause web"],
|
|
293
|
+
[AiResourceType.PodmanHost, "docker start web"],
|
|
294
|
+
[AiResourceType.DockerSwarmCluster, "docker service rollback web"],
|
|
295
|
+
[AiResourceType.DockerSwarmCluster, "docker service scale web=3"],
|
|
296
|
+
[
|
|
297
|
+
AiResourceType.ProxmoxCluster,
|
|
298
|
+
"pvesh create /nodes/pve1/qemu/100/status/start",
|
|
299
|
+
],
|
|
300
|
+
[AiResourceType.VMwareVCenter, "govc vm.power -on /DC1/vm/web-01"],
|
|
301
|
+
[AiResourceType.CephCluster, "ceph osd in 3"],
|
|
302
|
+
[AiResourceType.CephCluster, "ceph osd unset noout"],
|
|
303
|
+
[AiResourceType.Host, "systemctl start nginx"],
|
|
304
|
+
];
|
|
305
|
+
|
|
306
|
+
it.each(SAMPLE_UNDOS)(
|
|
307
|
+
"%s: %s is SafeWrite",
|
|
308
|
+
(resourceType: AiResourceType, command: string) => {
|
|
309
|
+
expect(
|
|
310
|
+
ResourceCommandPolicy.evaluateCommand({ resourceType, command }).tier,
|
|
311
|
+
).toBe(ResourceCommandTier.SafeWrite);
|
|
312
|
+
},
|
|
313
|
+
);
|
|
314
|
+
|
|
315
|
+
it.each(ALL_AI_RESOURCE_TYPES)(
|
|
316
|
+
"the %s undo examples start with the type's program (or say there is none)",
|
|
317
|
+
(resourceType: AiResourceType) => {
|
|
318
|
+
const examples: string = getResourceUndoExamples(resourceType);
|
|
319
|
+
const programs: ReadonlyArray<string> =
|
|
320
|
+
AI_RESOURCE_TYPE_INFO[resourceType].programs;
|
|
321
|
+
|
|
322
|
+
if (resourceType === AiResourceType.DatabaseServer) {
|
|
323
|
+
expect(examples).toContain("omit it");
|
|
324
|
+
return;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
const firstWord: string = examples.split(" ")[0] || "";
|
|
328
|
+
expect(programs).toContain(firstWord);
|
|
329
|
+
},
|
|
330
|
+
);
|
|
331
|
+
|
|
332
|
+
it("an unknown resource type gets advice, never a command", () => {
|
|
333
|
+
expect(getResourceUndoExamples("Nope" as AiResourceType)).toContain(
|
|
334
|
+
"omit the rollbackCommand",
|
|
335
|
+
);
|
|
336
|
+
});
|
|
337
|
+
});
|
|
338
|
+
|
|
339
|
+
describe("the resource personas use the shared summaries", () => {
|
|
340
|
+
it.each(ALL_AI_RESOURCE_TYPES)(
|
|
341
|
+
"the Automatic persona for a %s",
|
|
342
|
+
(resourceType: AiResourceType) => {
|
|
343
|
+
const resource: ResourceAiAccessStatus = readyResource(resourceType);
|
|
344
|
+
const persona: string = buildResourceFullAutoPersona({
|
|
345
|
+
bypassApproval: false,
|
|
346
|
+
resource,
|
|
347
|
+
});
|
|
348
|
+
|
|
349
|
+
expect(persona).toContain(RESOURCE_AUTOMATIC_MODE_SUMMARY);
|
|
350
|
+
expect(persona).toContain(RESOURCE_SAFE_CHANGES_SUMMARY);
|
|
351
|
+
expect(persona).toContain(RESOURCE_RISKIER_CHANGES_SUMMARY);
|
|
352
|
+
expect(persona).toContain(RESOURCE_ALWAYS_ASKS_SUMMARY);
|
|
353
|
+
expect(persona).toContain(RESOURCE_ALLOWLIST_SUMMARY);
|
|
354
|
+
expect(persona).toContain(
|
|
355
|
+
ResourceCommandPolicy.getWriteCommandGuide(resourceType),
|
|
356
|
+
);
|
|
357
|
+
expect(persona).toContain(RUN_INFRASTRUCTURE_COMMAND_TOOL_NAME);
|
|
358
|
+
expect(persona).toContain("stepType ResourceCommand");
|
|
359
|
+
expect(persona).toContain('"web-1"');
|
|
360
|
+
expect(persona).toContain(
|
|
361
|
+
AI_RESOURCE_TYPE_INFO[resourceType].agentDisplayName,
|
|
362
|
+
);
|
|
363
|
+
for (const program of AI_RESOURCE_TYPE_INFO[resourceType].programs) {
|
|
364
|
+
expect(persona).toContain(program);
|
|
365
|
+
}
|
|
366
|
+
expect(persona).toContain(getResourceUndoExamples(resourceType));
|
|
367
|
+
expect(persona).toContain(
|
|
368
|
+
"A rollback must itself be a safe change on ONE named object",
|
|
369
|
+
);
|
|
370
|
+
// A resource's agent is never given a credential.
|
|
371
|
+
expect(persona).not.toContain("credentialId");
|
|
372
|
+
expect(persona).not.toContain("kubectl");
|
|
373
|
+
},
|
|
374
|
+
);
|
|
375
|
+
|
|
376
|
+
it("the Bypass persona asks nothing but what always needs a human", () => {
|
|
377
|
+
const persona: string = buildResourceFullAutoPersona({
|
|
378
|
+
bypassApproval: true,
|
|
379
|
+
resource: readyResource(AiResourceType.DockerHost, {
|
|
380
|
+
aiRemediationMode: ResourceAiRemediationMode.BypassApproval,
|
|
381
|
+
}),
|
|
382
|
+
});
|
|
383
|
+
|
|
384
|
+
expect(persona).toContain(RESOURCE_BYPASS_MODE_SUMMARY);
|
|
385
|
+
expect(persona).toContain("EXCEPT that");
|
|
386
|
+
expect(persona).toContain("proposes it to a human for one-click approval");
|
|
387
|
+
expect(persona).toContain(
|
|
388
|
+
RESOURCE_UNATTENDED_ROUND_BECOMES_PROPOSAL_SUMMARY,
|
|
389
|
+
);
|
|
390
|
+
expect(persona).toContain("chose to bypass approvals entirely");
|
|
391
|
+
expect(persona).not.toContain(RESOURCE_AUTOMATIC_MODE_SUMMARY);
|
|
392
|
+
});
|
|
393
|
+
|
|
394
|
+
it.each(ALL_AI_RESOURCE_TYPES)(
|
|
395
|
+
"the planning persona for a %s proposes ResourceCommand steps, never runs them",
|
|
396
|
+
(resourceType: AiResourceType) => {
|
|
397
|
+
const persona: string = buildResourceSuggestPersona({
|
|
398
|
+
resource: readyResource(resourceType),
|
|
399
|
+
});
|
|
400
|
+
|
|
401
|
+
expect(persona).toContain("REMEDIATION PLANNING");
|
|
402
|
+
expect(persona).toContain(
|
|
403
|
+
"NOTHING you propose executes until a human approves it",
|
|
404
|
+
);
|
|
405
|
+
expect(persona).toContain("propose_remediation_commands");
|
|
406
|
+
expect(persona).toContain("stepType ResourceCommand");
|
|
407
|
+
expect(persona).toContain(
|
|
408
|
+
ResourceCommandPolicy.getWriteCommandGuide(resourceType),
|
|
409
|
+
);
|
|
410
|
+
expect(persona).toContain(getResourceUndoExamples(resourceType));
|
|
411
|
+
expect(persona).not.toContain("execute_remediation_command");
|
|
412
|
+
},
|
|
413
|
+
);
|
|
414
|
+
});
|
|
415
|
+
|
|
416
|
+
describe("the resource round's question", () => {
|
|
417
|
+
it("names the resource and its programs, and the mode's promise", () => {
|
|
418
|
+
const automatic: string = buildResourceQuestion({
|
|
419
|
+
resource: readyResource(AiResourceType.Host),
|
|
420
|
+
mode: "FullAuto",
|
|
421
|
+
});
|
|
422
|
+
expect(automatic).toContain('Host "web-1"');
|
|
423
|
+
expect(automatic).toContain("systemctl");
|
|
424
|
+
expect(automatic).toContain(
|
|
425
|
+
"a riskier fix never runs without a human's one-click approval",
|
|
426
|
+
);
|
|
427
|
+
expect(automatic).toContain("remediate now");
|
|
428
|
+
|
|
429
|
+
const bypass: string = buildResourceQuestion({
|
|
430
|
+
resource: readyResource(AiResourceType.DockerHost, {
|
|
431
|
+
aiRemediationMode: ResourceAiRemediationMode.BypassApproval,
|
|
432
|
+
}),
|
|
433
|
+
mode: "FullAuto",
|
|
434
|
+
});
|
|
435
|
+
expect(bypass).toContain("its operator bypassed approvals");
|
|
436
|
+
expect(bypass).toContain(RESOURCE_ALWAYS_ASKS_SUMMARY);
|
|
437
|
+
expect(bypass).toContain(
|
|
438
|
+
"the round becomes a proposal if the hourly circuit breaker trips or another unattended round holds the resource",
|
|
439
|
+
);
|
|
440
|
+
|
|
441
|
+
const suggest: string = buildResourceQuestion({
|
|
442
|
+
resource: readyResource(AiResourceType.CephCluster),
|
|
443
|
+
mode: "Suggest",
|
|
444
|
+
});
|
|
445
|
+
expect(suggest).toContain('Ceph cluster "web-1"');
|
|
446
|
+
expect(suggest).toContain("compose a plan for human approval");
|
|
447
|
+
expect(suggest).not.toContain("remediate now");
|
|
448
|
+
});
|
|
449
|
+
});
|
|
450
|
+
|
|
451
|
+
describe("the remediation tool's command examples are what they claim", () => {
|
|
452
|
+
/*
|
|
453
|
+
* RemediationCommandToolkit's ResourceCommand schema offers these as
|
|
454
|
+
* examples of a change; each must parse as one argv and be a SafeWrite
|
|
455
|
+
* for the type it is meant for.
|
|
456
|
+
*/
|
|
457
|
+
it.each(SAFE_EXAMPLES)(
|
|
458
|
+
"%s: %s tokenizes as one argv",
|
|
459
|
+
(_resourceType: AiResourceType, command: string) => {
|
|
460
|
+
expect(tokenizeResourceCommand(command).argv).toBeDefined();
|
|
461
|
+
},
|
|
462
|
+
);
|
|
463
|
+
});
|