@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.
Files changed (1146) hide show
  1. package/Models/DatabaseModels/AIConversation.ts +127 -1
  2. package/Models/DatabaseModels/AutoRemediationSuggestion.ts +60 -0
  3. package/Models/DatabaseModels/CephCluster.ts +225 -0
  4. package/Models/DatabaseModels/CloudResource.ts +12 -0
  5. package/Models/DatabaseModels/DatabaseServer.ts +225 -0
  6. package/Models/DatabaseModels/DockerHost.ts +225 -0
  7. package/Models/DatabaseModels/DockerSwarmCluster.ts +225 -0
  8. package/Models/DatabaseModels/GlobalConfig.ts +1 -1
  9. package/Models/DatabaseModels/GlobalOidc.ts +0 -4
  10. package/Models/DatabaseModels/GlobalOidcProject.ts +0 -4
  11. package/Models/DatabaseModels/GlobalSso.ts +0 -4
  12. package/Models/DatabaseModels/GlobalSsoProject.ts +0 -4
  13. package/Models/DatabaseModels/Host.ts +225 -0
  14. package/Models/DatabaseModels/IncidentForm.ts +594 -0
  15. package/Models/DatabaseModels/IncidentFormSubmission.ts +283 -0
  16. package/Models/DatabaseModels/IncidentTemplate.ts +59 -0
  17. package/Models/DatabaseModels/Index.ts +16 -0
  18. package/Models/DatabaseModels/IoTFleet.ts +12 -0
  19. package/Models/DatabaseModels/KubernetesCluster.ts +12 -0
  20. package/Models/DatabaseModels/MessageQueue.ts +1102 -0
  21. package/Models/DatabaseModels/MessageQueueLabelRule.ts +553 -0
  22. package/Models/DatabaseModels/MessageQueueOwnerRule.ts +633 -0
  23. package/Models/DatabaseModels/MessageQueueOwnerTeam.ts +491 -0
  24. package/Models/DatabaseModels/MessageQueueOwnerUser.ts +490 -0
  25. package/Models/DatabaseModels/PodmanHost.ts +225 -0
  26. package/Models/DatabaseModels/Project.ts +59 -0
  27. package/Models/DatabaseModels/ProjectOidc.ts +0 -4
  28. package/Models/DatabaseModels/ProjectSso.ts +0 -4
  29. package/Models/DatabaseModels/ProxmoxCluster.ts +225 -0
  30. package/Models/DatabaseModels/ResourceAiAgent.ts +419 -0
  31. package/Models/DatabaseModels/RumApplication.ts +12 -0
  32. package/Models/DatabaseModels/RunnerJob.ts +144 -0
  33. package/Models/DatabaseModels/ServerlessFunction.ts +12 -0
  34. package/Models/DatabaseModels/Service.ts +12 -0
  35. package/Models/DatabaseModels/StatusPageOidc.ts +0 -4
  36. package/Models/DatabaseModels/StatusPageSso.ts +0 -4
  37. package/Models/DatabaseModels/TeamComplianceSetting.ts +47 -2
  38. package/Models/DatabaseModels/VMwareVCenter.ts +225 -0
  39. package/Server/API/AIChatAPI.ts +13 -114
  40. package/Server/API/AIInvestigationAPI.ts +3 -3
  41. package/Server/API/AIInvestigationConversationAPI.ts +266 -0
  42. package/Server/API/AutoRemediationAPI.ts +392 -1
  43. package/Server/API/IncidentFormAPI.ts +376 -0
  44. package/Server/API/ProjectOIDC.ts +16 -25
  45. package/Server/API/ProjectSSO.ts +16 -24
  46. package/Server/API/ResourceAiAccessAPI.ts +1669 -0
  47. package/Server/API/StatusPageAPI.ts +42 -77
  48. package/Server/Enterprise/EnterpriseEdition.ts +93 -28
  49. package/Server/Enterprise/EnterpriseFeature.ts +25 -3
  50. package/Server/Enterprise/EnterpriseLicenseSnapshot.ts +1 -1
  51. package/Server/Enterprise/EnterpriseServerModule.ts +4 -1
  52. package/Server/EnvironmentConfig.ts +1 -1
  53. package/Server/Infrastructure/Postgres/SchemaMigrations/1796300000000-AddResourceAiAgents.ts +423 -0
  54. package/Server/Infrastructure/Postgres/SchemaMigrations/1796400000000-AddIncidentForms.ts +129 -0
  55. package/Server/Infrastructure/Postgres/SchemaMigrations/1796500000000-AddTeamComplianceRuleNotificationChannels.ts +52 -0
  56. package/Server/Infrastructure/Postgres/SchemaMigrations/1796600000000-AddAIInvestigationConversationAndTimeLimits.ts +75 -0
  57. package/Server/Infrastructure/Postgres/SchemaMigrations/1796700000000-AddMessageQueueTables.ts +477 -0
  58. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +10 -0
  59. package/Server/Infrastructure/Semaphore.ts +22 -0
  60. package/Server/Middleware/IncidentFormRateLimit.ts +847 -0
  61. package/Server/Middleware/TelemetryIngest.ts +15 -5
  62. package/Server/Middleware/UserAuthorization.ts +16 -38
  63. package/Server/Services/AIService.ts +10 -13
  64. package/Server/Services/AnalyticsDatabaseService.ts +45 -1
  65. package/Server/Services/AutoRemediationRuleEngineService.ts +940 -112
  66. package/Server/Services/CephClusterService.ts +109 -1
  67. package/Server/Services/DatabaseServerService.ts +116 -1
  68. package/Server/Services/DockerHostService.ts +109 -1
  69. package/Server/Services/DockerSwarmClusterService.ts +113 -1
  70. package/Server/Services/HostService.ts +126 -4
  71. package/Server/Services/IncidentCustomFieldService.ts +112 -2
  72. package/Server/Services/IncidentEpisodeMemberService.ts +24 -4
  73. package/Server/Services/IncidentEpisodeService.ts +10 -1
  74. package/Server/Services/IncidentFormService.ts +1566 -0
  75. package/Server/Services/IncidentFormSubmissionService.ts +97 -0
  76. package/Server/Services/IncidentGroupingEngineService.ts +45 -8
  77. package/Server/Services/IncidentService.ts +123 -5
  78. package/Server/Services/IncidentTemplateService.ts +22 -0
  79. package/Server/Services/Index.ts +14 -0
  80. package/Server/Services/MessageQueueLabelRuleEngineService.ts +321 -0
  81. package/Server/Services/MessageQueueLabelRuleService.ts +14 -0
  82. package/Server/Services/MessageQueueOwnerRuleEngineService.ts +412 -0
  83. package/Server/Services/MessageQueueOwnerRuleService.ts +14 -0
  84. package/Server/Services/MessageQueueOwnerTeamService.ts +62 -0
  85. package/Server/Services/MessageQueueOwnerUserService.ts +62 -0
  86. package/Server/Services/MessageQueueService.ts +1463 -0
  87. package/Server/Services/MetricRecordingRuleService.ts +47 -0
  88. package/Server/Services/OpenTelemetryIngestService.ts +37 -4
  89. package/Server/Services/PodmanHostService.ts +109 -1
  90. package/Server/Services/ProjectService.ts +0 -59
  91. package/Server/Services/ProxmoxClusterService.ts +110 -1
  92. package/Server/Services/ResourceAiAccessService.ts +1439 -0
  93. package/Server/Services/ResourceAiAgentJobService.ts +202 -0
  94. package/Server/Services/ResourceAiAgentService.ts +2432 -0
  95. package/Server/Services/RunnerJobService.ts +611 -4
  96. package/Server/Services/StatusPagePrivateUserService.ts +1 -4
  97. package/Server/Services/StatusPageService.ts +1 -51
  98. package/Server/Services/TeamComplianceSettingService.ts +163 -42
  99. package/Server/Services/TelemetryUsageBillingService.ts +28 -0
  100. package/Server/Services/TraceRecordingRuleService.ts +33 -0
  101. package/Server/Services/UserNotificationRuleService.ts +8 -1
  102. package/Server/Services/VMwareVCenterService.ts +110 -1
  103. package/Server/Services/WorkspaceNotificationSummaryService.ts +12 -3
  104. package/Server/Types/Database/Permissions/CreatePermission.ts +17 -3
  105. package/Server/Types/Database/Permissions/EditionPermission.ts +140 -38
  106. package/Server/Types/Database/Permissions/OwnerTableRegistry.ts +16 -0
  107. package/Server/Types/Database/Permissions/TablePermission.ts +3 -3
  108. package/Server/Types/Database/Permissions/UpdatePermission.ts +20 -6
  109. package/Server/Utils/AI/Chat/AgentContextCompactor.ts +200 -0
  110. package/Server/Utils/AI/Chat/ChatAgentRunner.ts +307 -48
  111. package/Server/Utils/AI/Chat/ChatRunCancellation.ts +156 -0
  112. package/Server/Utils/AI/Chat/ObservabilityAssistant.ts +78 -18
  113. package/Server/Utils/AI/Chat/ObservabilityChatPrompt.ts +1 -1
  114. package/Server/Utils/AI/Chat/ToolOutputPager.ts +322 -0
  115. package/Server/Utils/AI/ClusterAccess/KubectlInvestigationToolkit.ts +88 -30
  116. package/Server/Utils/AI/ClusterAccess/KubectlJobRunner.ts +13 -1
  117. package/Server/Utils/AI/CodeFix/CodeFixReadiness.ts +0 -32
  118. package/Server/Utils/AI/CodeFix/FixRunBudget.ts +27 -25
  119. package/Server/Utils/AI/Remediation/RemediationCommandTools.ts +1442 -34
  120. package/Server/Utils/AI/Remediation/RemediationExecutionRunner.ts +968 -34
  121. package/Server/Utils/AI/Remediation/RemediationPlanRunner.ts +25 -1
  122. package/Server/Utils/AI/ResourceAccess/InfrastructureInvestigationToolkit.ts +622 -0
  123. package/Server/Utils/AI/ResourceAccess/ResourceAccessContext.ts +271 -0
  124. package/Server/Utils/AI/ResourceAccess/ResourceAccessToolNames.ts +45 -0
  125. package/Server/Utils/AI/ResourceAccess/ResourceAiAccessSettings.ts +964 -0
  126. package/Server/Utils/AI/ResourceAccess/ResourceAiDeleteCleanup.ts +333 -0
  127. package/Server/Utils/AI/ResourceAccess/ResourceCommandJobRunner.ts +882 -0
  128. package/Server/Utils/AI/SRE/AIInvestigationEngine.ts +125 -12
  129. package/Server/Utils/AI/SRE/AlertInvestigationRunner.ts +99 -15
  130. package/Server/Utils/AI/SRE/IncidentInvestigationRunner.ts +99 -15
  131. package/Server/Utils/AI/SRE/InvestigationQueue.ts +16 -19
  132. package/Server/Utils/AI/SRE/InvestigationThread.ts +646 -0
  133. package/Server/Utils/AI/SRE/InvestigationThreadService.ts +715 -0
  134. package/Server/Utils/AI/Toolbox/Serializer.ts +10 -3
  135. package/Server/Utils/AutoRemediation/CommandPlanExecutor.ts +396 -13
  136. package/Server/Utils/AutoRemediation/RemediationVerifier.ts +35 -2
  137. package/Server/Utils/Database/ProjectScopedReferenceValidator.ts +9 -1
  138. package/Server/Utils/EditionEnforcement.ts +19 -202
  139. package/Server/Utils/LLM/LLMService.ts +259 -63
  140. package/Server/Utils/RelaxedScimTeamLocksReport.ts +245 -0
  141. package/Server/Utils/Rules/RuleRun/RuleRunRegistry.ts +25 -0
  142. package/Server/Utils/SameOriginRequest.ts +203 -0
  143. package/Server/Utils/SessionReplay/SessionReplayBudgetMetrics.ts +920 -0
  144. package/Server/Utils/SessionReplay/SessionReplayUsage.ts +84 -6
  145. package/Server/Utils/TeamMember/ProjectLeaveResourceCleanup.ts +2 -0
  146. package/Server/Utils/Telemetry/EntityRegistry.ts +4 -1
  147. package/Server/Utils/Telemetry/MessageQueueDiscovery.ts +1402 -0
  148. package/Server/Utils/Telemetry/ResourceEntityFilter.ts +4 -1
  149. package/Server/Utils/VendorAssets.ts +3 -3
  150. package/Server/Utils/Workspace/MicrosoftTeams/Actions/Alert.ts +35 -15
  151. package/Server/Utils/Workspace/MicrosoftTeams/Actions/AlertEpisode.ts +33 -15
  152. package/Server/Utils/Workspace/MicrosoftTeams/Actions/Auth.ts +21 -1
  153. package/Server/Utils/Workspace/MicrosoftTeams/Actions/Incident.ts +301 -225
  154. package/Server/Utils/Workspace/MicrosoftTeams/Actions/IncidentEpisode.ts +38 -16
  155. package/Server/Utils/Workspace/MicrosoftTeams/Actions/ScheduledMaintenance.ts +389 -175
  156. package/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.ts +376 -144
  157. package/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsActivityDeduplicator.ts +163 -0
  158. package/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsCardChoices.ts +396 -0
  159. package/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsCreateCommands.ts +418 -0
  160. package/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsMessageSize.ts +152 -0
  161. package/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsReplies.ts +251 -0
  162. package/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsTimezone.ts +214 -0
  163. package/Tests/App/Accounts/IncidentFormPage.test.tsx +2036 -0
  164. package/Tests/App/Accounts/IncidentFormServerMessages.test.ts +119 -0
  165. package/Tests/App/Accounts/IncidentFormUtils.test.ts +1157 -0
  166. package/Tests/App/Accounts/LoginPasskey.test.tsx +6 -4
  167. package/Tests/App/Accounts/LoginSso.test.tsx +724 -0
  168. package/Tests/App/AdminDashboard/AdminAuthenticationRequireSso.test.tsx +338 -0
  169. package/Tests/App/AdminDashboard/AdminAuthenticationSsoCardLocales.test.tsx +331 -0
  170. package/Tests/App/AdminDashboard/AdminEnterprisePluginPage.test.tsx +47 -33
  171. package/Tests/App/AdminDashboard/GlobalSsoOidcPages.test.tsx +1021 -0
  172. package/Tests/App/Dashboard/AffectedResourcesDisplay.test.tsx +876 -78
  173. package/Tests/App/Dashboard/AffectedResourcesSlo.test.tsx +20 -3
  174. package/Tests/App/Dashboard/CephProxmoxVMwareDocumentationCards.test.tsx +359 -0
  175. package/Tests/App/Dashboard/CephSetupGuide.test.ts +961 -0
  176. package/Tests/App/Dashboard/CloudDocumentationCard.test.tsx +381 -95
  177. package/Tests/App/Dashboard/CloudSetupGuide.test.ts +1463 -0
  178. package/Tests/App/Dashboard/ClusterAccessNotice.test.tsx +267 -12
  179. package/Tests/App/Dashboard/ContainerSetupGuideCards.test.tsx +345 -0
  180. package/Tests/App/Dashboard/CoreListEmptyStates.test.tsx +501 -0
  181. package/Tests/App/Dashboard/DashboardLazyPages.test.tsx +0 -1
  182. package/Tests/App/Dashboard/DatabaseDocumentationCard.test.tsx +400 -0
  183. package/Tests/App/Dashboard/DatabaseDocumentationMarkdown.test.ts +23 -6
  184. package/Tests/App/Dashboard/DatabaseSetupGuide.test.ts +1869 -0
  185. package/Tests/App/Dashboard/DatabaseTelemetryScope.test.ts +44 -0
  186. package/Tests/App/Dashboard/DatabaseTelemetryTabs.test.tsx +50 -9
  187. package/Tests/App/Dashboard/DockerSetupGuide.test.ts +899 -0
  188. package/Tests/App/Dashboard/DockerSwarmSetupGuide.test.ts +964 -0
  189. package/Tests/App/Dashboard/EnterpriseFeatureUpgrade.test.tsx +141 -7
  190. package/Tests/App/Dashboard/EnterprisePluginPage.test.tsx +52 -39
  191. package/Tests/App/Dashboard/EventOverviewPages.test.tsx +7 -1
  192. package/Tests/App/Dashboard/GettingStartedTaskRoutes.test.tsx +331 -0
  193. package/Tests/App/Dashboard/HomeOverviewStatsFirstRun.test.tsx +925 -0
  194. package/Tests/App/Dashboard/HostDocumentationCard.test.tsx +225 -0
  195. package/Tests/App/Dashboard/HostSetupGuide.test.ts +1183 -0
  196. package/Tests/App/Dashboard/IdentityEnterpriseShells.test.tsx +69 -45
  197. package/Tests/App/Dashboard/IncidentCreateTemplateCustomFieldSettings.test.tsx +745 -0
  198. package/Tests/App/Dashboard/IncidentCreateTemplateOwners.test.tsx +414 -0
  199. package/Tests/App/Dashboard/IncidentCustomFieldCreateSettingsForm.test.ts +1042 -0
  200. package/Tests/App/Dashboard/IncidentCustomFieldSettingsCard.test.tsx +1816 -0
  201. package/Tests/App/Dashboard/IncidentFormPlan.test.ts +89 -0
  202. package/Tests/App/Dashboard/IncidentFormShareLinkCard.test.tsx +846 -0
  203. package/Tests/App/Dashboard/IncidentFormsPages.test.tsx +1324 -0
  204. package/Tests/App/Dashboard/IncidentTemplateCustomFieldSettings.test.tsx +630 -0
  205. package/Tests/App/Dashboard/IncidentsSideMenu.test.tsx +13 -0
  206. package/Tests/App/Dashboard/IncomingEmailMonitorLinkVerifyHint.test.tsx +104 -0
  207. package/Tests/App/Dashboard/InvestigationConversation.test.tsx +1107 -0
  208. package/Tests/App/Dashboard/InvestigationConversationData.test.ts +546 -0
  209. package/Tests/App/Dashboard/InvestigationEvidenceList.test.tsx +170 -5
  210. package/Tests/App/Dashboard/InvestigationInfrastructureTools.test.tsx +506 -0
  211. package/Tests/App/Dashboard/InvestigationNotStarted.test.tsx +207 -2
  212. package/Tests/App/Dashboard/InvestigationPanel.test.tsx +729 -34
  213. package/Tests/App/Dashboard/InvestigationPanelStatus.test.tsx +9 -21
  214. package/Tests/App/Dashboard/InvestigationReportView.test.tsx +274 -37
  215. package/Tests/App/Dashboard/InvestigationStatusBadge.test.tsx +130 -0
  216. package/Tests/App/Dashboard/IoTDocumentationCard.test.tsx +218 -0
  217. package/Tests/App/Dashboard/IoTSetupGuide.test.ts +1124 -0
  218. package/Tests/App/Dashboard/KubernetesClusterAiAccessSettings.test.ts +20 -6
  219. package/Tests/App/Dashboard/KubernetesClusterAiDocumentationMarkdown.test.ts +107 -83
  220. package/Tests/App/Dashboard/KubernetesSetupGuide.test.ts +787 -0
  221. package/Tests/App/Dashboard/MessageQueueBreadcrumbs.test.tsx +228 -0
  222. package/Tests/App/Dashboard/MessageQueueBrokerHealth.test.tsx +1538 -0
  223. package/Tests/App/Dashboard/MessageQueueBrokerHealthMetricChart.test.tsx +969 -0
  224. package/Tests/App/Dashboard/MessageQueueBrokerHealthReads.test.ts +889 -0
  225. package/Tests/App/Dashboard/MessageQueueBrokerMetricsReach.test.ts +236 -0
  226. package/Tests/App/Dashboard/MessageQueueDocumentationCard.test.tsx +479 -0
  227. package/Tests/App/Dashboard/MessageQueueListPages.test.tsx +1232 -0
  228. package/Tests/App/Dashboard/MessageQueueMetricDescriptions.test.ts +244 -0
  229. package/Tests/App/Dashboard/MessageQueueMonitorLink.test.ts +952 -0
  230. package/Tests/App/Dashboard/MessageQueueMonitorLinkMonitorCreate.test.tsx +859 -0
  231. package/Tests/App/Dashboard/MessageQueueOverview.test.tsx +1773 -0
  232. package/Tests/App/Dashboard/MessageQueueOverviewPresentation.test.ts +196 -0
  233. package/Tests/App/Dashboard/MessageQueuePresentation.test.ts +799 -0
  234. package/Tests/App/Dashboard/MessageQueueProducersConsumers.test.tsx +680 -0
  235. package/Tests/App/Dashboard/MessageQueueRoutes.test.tsx +383 -0
  236. package/Tests/App/Dashboard/MessageQueueRulePages.test.tsx +278 -0
  237. package/Tests/App/Dashboard/MessageQueueSetupGuide.test.ts +2778 -0
  238. package/Tests/App/Dashboard/MessageQueueSideMenus.test.tsx +273 -0
  239. package/Tests/App/Dashboard/MessageQueueSpanPopulations.test.ts +930 -0
  240. package/Tests/App/Dashboard/MessageQueueSpanStore.ts +351 -0
  241. package/Tests/App/Dashboard/MessageQueueTelemetryScope.test.ts +375 -0
  242. package/Tests/App/Dashboard/MessageQueueTelemetryScopeTabs.test.tsx +668 -0
  243. package/Tests/App/Dashboard/MessageQueueViewPages.test.tsx +685 -0
  244. package/Tests/App/Dashboard/MonitorAndHomeNotOperationalMenus.test.tsx +342 -0
  245. package/Tests/App/Dashboard/MonitorCreateFirstRunDefaults.test.tsx +623 -0
  246. package/Tests/App/Dashboard/MonitorCreateFromMonitorBackedDevice.test.tsx +442 -0
  247. package/Tests/App/Dashboard/MonitorLogsPageViewSummary.test.tsx +814 -0
  248. package/Tests/App/Dashboard/MonitorSetupCardBodies.test.tsx +246 -0
  249. package/Tests/App/Dashboard/NavigationSearchKeywords.test.tsx +8 -0
  250. package/Tests/App/Dashboard/OnboardingSsoEmptyState.test.tsx +27 -12
  251. package/Tests/App/Dashboard/PlanGatedPage.test.tsx +292 -0
  252. package/Tests/App/Dashboard/PodmanSetupGuide.test.ts +948 -0
  253. package/Tests/App/Dashboard/ProductOrientation.test.tsx +5 -4
  254. package/Tests/App/Dashboard/ProductSettingsSectionCollapsed.test.tsx +266 -0
  255. package/Tests/App/Dashboard/ProxmoxSetupGuide.test.ts +1318 -0
  256. package/Tests/App/Dashboard/RemediationSuggestionCardDescription.test.tsx +209 -0
  257. package/Tests/App/Dashboard/RemediationSuggestionCardResource.test.tsx +317 -0
  258. package/Tests/App/Dashboard/ResourceAiAccessSettingsUtil.test.ts +921 -0
  259. package/Tests/App/Dashboard/ResourceAiAgentAttentionServerParity.test.ts +555 -0
  260. package/Tests/App/Dashboard/ResourceAiAgentInstall.test.ts +860 -0
  261. package/Tests/App/Dashboard/ResourceAiAgentPage.test.tsx +2010 -0
  262. package/Tests/App/Dashboard/ResourceAiAgentStatus.test.ts +1455 -0
  263. package/Tests/App/Dashboard/ResourceAiInsightsPage.test.tsx +931 -0
  264. package/Tests/App/Dashboard/ResourceAiNavigation.test.tsx +575 -0
  265. package/Tests/App/Dashboard/ResourceArchiveSettings.test.tsx +16 -0
  266. package/Tests/App/Dashboard/ResourceConnectionGuideCard.test.tsx +444 -0
  267. package/Tests/App/Dashboard/ResourceConnectionGuideOverviewsInfra.test.tsx +798 -0
  268. package/Tests/App/Dashboard/ResourceConnectionGuideOverviewsPlatforms.test.tsx +717 -0
  269. package/Tests/App/Dashboard/ResourceConnectionGuides.test.ts +981 -0
  270. package/Tests/App/Dashboard/ResourceConnectionState.test.ts +132 -0
  271. package/Tests/App/Dashboard/RumDocumentationCard.test.tsx +293 -0
  272. package/Tests/App/Dashboard/RumSessionReplayRetentionSettings.test.tsx +467 -0
  273. package/Tests/App/Dashboard/RumSetupGuide.test.ts +758 -0
  274. package/Tests/App/Dashboard/RunbookStepTypeMaps.test.ts +38 -7
  275. package/Tests/App/Dashboard/ScheduledMaintenanceOverviewPage.test.tsx +25 -0
  276. package/Tests/App/Dashboard/ServerlessDocumentationCard.test.tsx +254 -0
  277. package/Tests/App/Dashboard/ServerlessSetupGuide.test.ts +1074 -0
  278. package/Tests/App/Dashboard/SetupGuide.test.ts +246 -0
  279. package/Tests/App/Dashboard/SetupGuideCard.test.tsx +756 -0
  280. package/Tests/App/Dashboard/SloListSideMenu.test.tsx +120 -0
  281. package/Tests/App/Dashboard/SsoPages.test.tsx +833 -0
  282. package/Tests/App/Dashboard/TelemetryDocumentation.test.tsx +253 -0
  283. package/Tests/App/Dashboard/TelemetryRetentionShells.test.tsx +730 -0
  284. package/Tests/App/Dashboard/VMwareSetupGuide.test.ts +1033 -0
  285. package/Tests/App/StatusPage/StatusPageSsoEmptyState.test.tsx +87 -7
  286. package/Tests/Models/DatabaseModels/DatabaseServerModels.test.ts +61 -10
  287. package/Tests/Models/DatabaseModels/IncidentFormModel.test.ts +1250 -0
  288. package/Tests/Models/DatabaseModels/MessageQueueModels.test.ts +1983 -0
  289. package/Tests/Models/DatabaseModels/ResourceAiAccessColumns.test.ts +738 -0
  290. package/Tests/Models/DatabaseModels/ResourceAiAgentModel.test.ts +842 -0
  291. package/Tests/Models/DatabaseModels/StaticRuleCriteriaInheritance.test.ts +4 -2
  292. package/Tests/Models/DatabaseModels/TeamComplianceSettingModel.test.ts +190 -14
  293. package/Tests/Models/IncidentTemplateCustomFieldSettingsColumn.test.ts +291 -0
  294. package/Tests/Server/API/AIInvestigationConversationAPI.test.ts +412 -0
  295. package/Tests/Server/API/AutoRemediationApproveResourceRound.test.ts +835 -0
  296. package/Tests/Server/API/GlobalConfigLicense.test.ts +38 -9
  297. package/Tests/Server/API/IncidentFormAPI.test.ts +942 -0
  298. package/Tests/Server/API/IncidentFormPublicRoutes.test.ts +1653 -0
  299. package/Tests/Server/API/KubernetesClusterAiAccessAPI.test.ts +2 -1
  300. package/Tests/Server/API/ResourceAiAccessAPI.test.ts +2730 -0
  301. package/Tests/Server/API/{SsoProviderListingsEdition.test.ts → SsoProviderListings.test.ts} +164 -110
  302. package/Tests/Server/Enterprise/EnterpriseEdition.test.ts +76 -54
  303. package/Tests/Server/Enterprise/EnterpriseFeatureActive.test.ts +125 -42
  304. package/Tests/Server/Enterprise/EnterpriseLicenseSnapshot.test.ts +36 -10
  305. package/Tests/Server/Enterprise/EnterpriseModelFeatureMap.test.ts +51 -9
  306. package/Tests/Server/Enterprise/FakeEnterpriseModule.ts +13 -8
  307. package/Tests/Server/Enterprise/SsoInCommunityEdition.test.ts +540 -0
  308. package/Tests/Server/Infrastructure/Postgres/AddConfigurableRuleCriteriaMigration.test.ts +3 -0
  309. package/Tests/Server/Infrastructure/Postgres/AddDatabaseServerTablesMigration.test.ts +60 -0
  310. package/Tests/Server/Infrastructure/Postgres/AddIncidentFormsMigration.test.ts +438 -0
  311. package/Tests/Server/Infrastructure/Postgres/AddResourceAiAgentsMigration.test.ts +659 -0
  312. package/Tests/Server/Infrastructure/Postgres/AddTeamComplianceRuleNotificationChannelsMigration.test.ts +255 -0
  313. package/Tests/Server/Infrastructure/Postgres/MessageQueueTablesMigration.test.ts +637 -0
  314. package/Tests/Server/Infrastructure/SemaphoreMutex.test.ts +31 -0
  315. package/Tests/Server/Middleware/IncidentFormRateLimit.test.ts +1630 -0
  316. package/Tests/Server/Middleware/TelemetryIngestBrowserKey.test.ts +63 -5
  317. package/Tests/Server/Middleware/TelemetryIngestKubernetesAgentRunnerPinnedKey.test.ts +103 -5
  318. package/Tests/Server/Middleware/TelemetryIngestKubernetesAgentRunnerRateLimit.test.ts +19 -1
  319. package/Tests/Server/Middleware/UserAuthorization.test.ts +16 -17
  320. package/Tests/Server/Middleware/UserAuthorizationSsoEnforcement.test.ts +544 -0
  321. package/Tests/Server/Services/AIServiceDailyBudget.test.ts +37 -8
  322. package/Tests/Server/Services/AutoRemediationResourceRuleEngine.test.ts +1279 -0
  323. package/Tests/Server/Services/DatabaseServerService.test.ts +55 -0
  324. package/Tests/Server/Services/GroupTelemetryUsageExcludeNames.test.ts +299 -0
  325. package/Tests/Server/Services/HostServiceFindOrCreateMemo.test.ts +44 -0
  326. package/Tests/Server/Services/IncidentCreatedFeedTitle.test.ts +212 -0
  327. package/Tests/Server/Services/IncidentCustomFieldDeleteFormQuestions.test.ts +297 -0
  328. package/Tests/Server/Services/IncidentFormOwnersCreatedNotification.test.ts +497 -0
  329. package/Tests/Server/Services/IncidentFormPostgres.test.ts +958 -0
  330. package/Tests/Server/Services/IncidentFormPublicForm.test.ts +1260 -0
  331. package/Tests/Server/Services/IncidentFormPublicSubmission.test.ts +2520 -0
  332. package/Tests/Server/Services/IncidentFormRegistration.test.ts +159 -0
  333. package/Tests/Server/Services/IncidentFormService.test.ts +663 -0
  334. package/Tests/Server/Services/IncidentFormSubmissionService.test.ts +430 -0
  335. package/Tests/Server/Services/IncidentFormSubmissionTemplateBranch.test.ts +473 -0
  336. package/Tests/Server/Services/IncidentGroupingTemplateSubstitution.test.ts +81 -0
  337. package/Tests/Server/Services/IncidentTemplateCustomFieldSettings.test.ts +262 -0
  338. package/Tests/Server/Services/IncidentTemplateOwnersOnDeclare.test.ts +566 -0
  339. package/Tests/Server/Services/IncidentTitleMarkdownSinks.test.ts +640 -0
  340. package/Tests/Server/Services/LlmLogServiceTokenAggregateParams.test.ts +3 -3
  341. package/Tests/Server/Services/MessageQueueOwnerServices.test.ts +440 -0
  342. package/Tests/Server/Services/MessageQueueRegistries.test.ts +577 -0
  343. package/Tests/Server/Services/MessageQueueRuleEngines.test.ts +900 -0
  344. package/Tests/Server/Services/MessageQueueService.test.ts +2210 -0
  345. package/Tests/Server/Services/MessageQueueSqlPostgres.test.ts +1271 -0
  346. package/Tests/Server/Services/MonitorProbeServiceIntervalScheduling.test.ts +45 -6
  347. package/Tests/Server/Services/OpenTelemetryResourceRetentionMemo.test.ts +28 -1
  348. package/Tests/Server/Services/OpenTelemetryRetentionOverrideEdition.test.ts +474 -0
  349. package/Tests/Server/Services/OpenTelemetryServiceResolutionCache.test.ts +21 -0
  350. package/Tests/Server/Services/OwnerRowUniqueness.test.ts +3 -0
  351. package/Tests/Server/Services/ProjectServiceAuditLogLicense.test.ts +0 -1
  352. package/Tests/Server/Services/RecordingRuleReservedMetricName.test.ts +171 -0
  353. package/Tests/Server/Services/ResourceAiAccessChangeAuthorization.test.ts +256 -0
  354. package/Tests/Server/Services/ResourceAiAccessService.test.ts +1373 -0
  355. package/Tests/Server/Services/ResourceAiAgentJobService.test.ts +375 -0
  356. package/Tests/Server/Services/ResourceAiAgentServiceHelpers.test.ts +1114 -0
  357. package/Tests/Server/Services/ResourceAiAgentServiceLifecycle.test.ts +1050 -0
  358. package/Tests/Server/Services/ResourceAiAgentServiceRegister.test.ts +2251 -0
  359. package/Tests/Server/Services/ResourceAiSettingsCreate.test.ts +373 -0
  360. package/Tests/Server/Services/ResourceAiSettingsPermission.test.ts +1042 -0
  361. package/Tests/Server/Services/ResourceServiceDeleteCleansUpAi.test.ts +319 -0
  362. package/Tests/Server/Services/RuleRun/LabelRuleEnginesGroupBRun.test.ts +56 -6
  363. package/Tests/Server/Services/RuleRun/OwnerRuleEnginesGroupBRun.test.ts +30 -1
  364. package/Tests/Server/Services/RunnerJobEnqueueKubectl.test.ts +105 -0
  365. package/Tests/Server/Services/RunnerJobEnqueueResourceCommand.test.ts +986 -0
  366. package/Tests/Server/Services/RunnerJobResourceCommandLane.test.ts +211 -0
  367. package/Tests/Server/Services/RunnerJobResourceCommandTimeoutAndRedaction.test.ts +352 -0
  368. package/Tests/Server/Services/SsoRequirementReads.test.ts +454 -0
  369. package/Tests/Server/Services/SsoRequirementWrites.test.ts +529 -0
  370. package/Tests/Server/Services/StaticRuleCriteriaRuntimeCoverage.test.ts +3 -3
  371. package/Tests/Server/Services/StatusPagePrivateUserInvitationPolicy.test.ts +107 -89
  372. package/Tests/Server/Services/TeamComplianceSettingPostgres.test.ts +1068 -176
  373. package/Tests/Server/Services/TeamComplianceSettingService.test.ts +1962 -200
  374. package/Tests/Server/Services/TelemetryUsageBillingSloExclusion.test.ts +218 -0
  375. package/Tests/Server/TestingUtils/Services/FakeRunnerJobCount.ts +145 -0
  376. package/Tests/Server/Types/Database/Permissions/EditionPermission.test.ts +654 -297
  377. package/Tests/Server/Types/Database/Permissions/RetentionOverrideColumns.test.ts +784 -0
  378. package/Tests/Server/Types/Database/Permissions/SsoScalePlanGate.test.ts +418 -0
  379. package/Tests/Server/Utils/AI/AIAlertGating.test.ts +0 -1
  380. package/Tests/Server/Utils/AI/AIInvestigationEngineRunLimits.test.ts +136 -0
  381. package/Tests/Server/Utils/AI/AIInvestigationQueue.test.ts +15 -14
  382. package/Tests/Server/Utils/AI/AgentContextCompactor.test.ts +351 -0
  383. package/Tests/Server/Utils/AI/ChatAgentRunnerSharedThread.test.ts +842 -0
  384. package/Tests/Server/Utils/AI/ChatRunCancellation.test.ts +195 -0
  385. package/Tests/Server/Utils/AI/CodeFixReadiness.test.ts +10 -57
  386. package/Tests/Server/Utils/AI/FixRunBudget.test.ts +20 -24
  387. package/Tests/Server/Utils/AI/Insights/InvestigationQueueInsightSubject.test.ts +7 -30
  388. package/Tests/Server/Utils/AI/InvestigationClusterAccessWiring.test.ts +225 -29
  389. package/Tests/Server/Utils/AI/InvestigationInfrastructureAccessWiring.test.ts +694 -0
  390. package/Tests/Server/Utils/AI/InvestigationInfrastructureReport.test.ts +721 -0
  391. package/Tests/Server/Utils/AI/InvestigationThread.test.ts +580 -0
  392. package/Tests/Server/Utils/AI/InvestigationThreadService.test.ts +801 -0
  393. package/Tests/Server/Utils/AI/KubectlInvestigationToolkit.test.ts +525 -43
  394. package/Tests/Server/Utils/AI/KubectlJobRunner.test.ts +4 -2
  395. package/Tests/Server/Utils/AI/LLMServiceUnreachableProvider.test.ts +435 -0
  396. package/Tests/Server/Utils/AI/ObservabilityAssistantLimits.test.ts +462 -0
  397. package/Tests/Server/Utils/AI/RemediationCommandTools.test.ts +94 -1
  398. package/Tests/Server/Utils/AI/RemediationCommandToolsResource.test.ts +1530 -0
  399. package/Tests/Server/Utils/AI/RemediationExecutionRunner.test.ts +14 -25
  400. package/Tests/Server/Utils/AI/RemediationExecutionRunnerResourceMode.test.ts +1251 -0
  401. package/Tests/Server/Utils/AI/RemediationPlanRunner.test.ts +117 -0
  402. package/Tests/Server/Utils/AI/RemediationResourceCopyParity.test.ts +463 -0
  403. package/Tests/Server/Utils/AI/ResourceAccess/InfrastructureInvestigationToolkit.test.ts +1004 -0
  404. package/Tests/Server/Utils/AI/ResourceAccess/ResourceAccessContext.test.ts +266 -0
  405. package/Tests/Server/Utils/AI/ResourceAccess/ResourceAiAccessSettings.test.ts +1220 -0
  406. package/Tests/Server/Utils/AI/ResourceAccess/ResourceAiDeleteCleanup.test.ts +569 -0
  407. package/Tests/Server/Utils/AI/ResourceAccess/ResourceCommandJobRunner.test.ts +834 -0
  408. package/Tests/Server/Utils/AI/ToolOutputPager.test.ts +382 -0
  409. package/Tests/Server/Utils/AI/ToolResultSerializer.test.ts +23 -4
  410. package/Tests/Server/Utils/AI/Toolbox/LogTools.test.ts +25 -6
  411. package/Tests/Server/Utils/AI/Toolbox/Serializer.test.ts +14 -3
  412. package/Tests/Server/Utils/AutoRemediation/CommandPlanExecutorResource.test.ts +717 -0
  413. package/Tests/Server/Utils/AutoRemediation/RemediationVerifierResourceFollowUp.test.ts +338 -0
  414. package/Tests/Server/Utils/EditionEnforcement.test.ts +107 -147
  415. package/Tests/Server/Utils/Monitor/Criteria/SessionReplayBudgetTemplateCriteria.test.ts +422 -0
  416. package/Tests/Server/Utils/{CommunityEditionSsoReport.test.ts → RelaxedScimTeamLocksReport.test.ts} +212 -208
  417. package/Tests/Server/Utils/SameOriginRequest.test.ts +372 -0
  418. package/Tests/Server/Utils/SessionReplay/SessionReplayBudgetMetrics.test.ts +1647 -0
  419. package/Tests/Server/Utils/SessionReplay/SessionReplayUsage.test.ts +143 -1
  420. package/Tests/Server/Utils/Telemetry/EntityRegistry.test.ts +20 -0
  421. package/Tests/Server/Utils/Telemetry/MessageQueueDiscovery.test.ts +2590 -0
  422. package/Tests/Server/Utils/Telemetry/MessageQueueSpanQueryTwin.ts +246 -0
  423. package/Tests/Server/Utils/Telemetry/TelemetryEntity.test.ts +23 -0
  424. package/Tests/Server/Utils/Telemetry/TelemetryIngestionKeyGuard.test.ts +33 -3
  425. package/Tests/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsAccountNotLinked.test.ts +1093 -0
  426. package/Tests/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsActivityDeduplicator.test.ts +1049 -0
  427. package/Tests/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsCardChoices.test.ts +1676 -0
  428. package/Tests/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsCreateCards.test.ts +2884 -0
  429. package/Tests/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsCreateCommands.test.ts +2490 -0
  430. package/Tests/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsCreateSubmit.test.ts +2293 -0
  431. package/Tests/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsCreateSubmitServerTimezone.test.ts +386 -0
  432. package/Tests/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsMessageSize.test.ts +1477 -0
  433. package/Tests/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsReplies.test.ts +1967 -0
  434. package/Tests/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsStripHtmlTags.test.ts +92 -0
  435. package/Tests/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsSubmittedFormRemoval.test.ts +1819 -0
  436. package/Tests/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsTimezone.test.ts +1033 -0
  437. package/Tests/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsTimezoneServerZone.test.ts +610 -0
  438. package/Tests/Server/Utils/Workspace/MicrosoftTeamsBotMessageHandling.test.ts +2610 -0
  439. package/Tests/Server/Utils/Workspace/MicrosoftTeamsCreateCommandsEndToEnd.test.ts +4672 -0
  440. package/Tests/Server/Utils/Workspace/WorkspaceCreateProjectReferences.test.ts +190 -65
  441. package/Tests/Types/AI/AIAgentRunLimits.test.ts +255 -0
  442. package/Tests/Types/AutoRemediation/AiRemediationCommandPlan.test.ts +10 -4
  443. package/Tests/Types/AutoRemediation/AiRemediationCommandPlanResourceCommand.test.ts +305 -0
  444. package/Tests/Types/Code/JsonSyntax.test.ts +1300 -0
  445. package/Tests/Types/CustomField/CustomFieldCreateSettings.test.ts +1113 -0
  446. package/Tests/Types/CustomField/CustomFieldMappingCatalog.test.ts +91 -0
  447. package/Tests/Types/CustomField/CustomFieldValueValidator.test.ts +30 -0
  448. package/Tests/Types/Incident/IncidentFormIpAllowlist.test.ts +227 -0
  449. package/Tests/Types/Incident/IncidentFormPublic.test.ts +1916 -0
  450. package/Tests/Types/MessageQueue/MessageQueueEntityKey.test.ts +916 -0
  451. package/Tests/Types/MessageQueue/MessageQueueIdentity.test.ts +567 -0
  452. package/Tests/Types/MessageQueue/MessageQueueManualIdentity.test.ts +686 -0
  453. package/Tests/Types/MessageQueue/MessageQueueMetricCatalog.test.ts +1726 -0
  454. package/Tests/Types/MessageQueue/MessageQueueMetricResolution.test.ts +1758 -0
  455. package/Tests/Types/MessageQueue/MessagingInstrumentationFixtures.test.ts +4686 -0
  456. package/Tests/Types/MessageQueue/MessagingSystem.test.ts +840 -0
  457. package/Tests/Types/MessageQueue/MessagingTelemetryFixtures.ts +3287 -0
  458. package/Tests/Types/MessageQueue/MessagingTelemetryResolver.test.ts +2966 -0
  459. package/Tests/Types/Monitor/MessageQueueAlertTemplates.test.ts +5401 -0
  460. package/Tests/Types/Monitor/MetricEngineFold.ts +154 -0
  461. package/Tests/Types/Monitor/Recommendation/MonitorRecommendationCatalog.test.ts +277 -13
  462. package/Tests/Types/Monitor/Recommendation/MonitorRecommendationUtil.test.ts +113 -0
  463. package/Tests/Types/Monitor/RumAlertTemplates.test.ts +773 -2
  464. package/Tests/Types/ResourceAiAgent/AiResourceType.test.ts +419 -0
  465. package/Tests/Types/ResourceAiAgent/ResourceAiAccess.test.ts +519 -0
  466. package/Tests/Types/Runbook/RunbookStepType.test.ts +147 -8
  467. package/Tests/Types/Team/ComplianceRule.test.ts +588 -37
  468. package/Tests/Types/Team/TeamComplianceStatus.test.ts +64 -11
  469. package/Tests/Types/XML.test.ts +51 -0
  470. package/Tests/UI/Components/CodeEditor/CodeEditor.test.tsx +2362 -0
  471. package/Tests/UI/Components/CodeEditor/CodeEditorCommands.test.ts +810 -0
  472. package/Tests/UI/Components/CodeEditor/CodeEditorHighlight.test.ts +338 -0
  473. package/Tests/UI/Components/CodeEditor/CodeEditorLanguages.test.ts +222 -0
  474. package/Tests/UI/Components/CodeEditor/CodeEditorStyles.test.ts +807 -0
  475. package/Tests/UI/Components/CodeEditor/NoMonaco.test.ts +245 -0
  476. package/Tests/UI/Components/CodeEditor/YamlEditor.test.tsx +729 -0
  477. package/Tests/UI/Components/CopyTextButton.test.tsx +76 -0
  478. package/Tests/UI/Components/EditionLabelLapseCopy.ts +51 -14
  479. package/Tests/UI/Components/EditionLabelLicenseStatus.test.tsx +131 -23
  480. package/Tests/UI/Components/ErrorMessageAction.test.tsx +142 -0
  481. package/Tests/UI/Components/FacetSidebarInScope.test.tsx +459 -0
  482. package/Tests/UI/Components/FacetValuesInScope.test.ts +270 -0
  483. package/Tests/UI/Components/Forms/FormFieldCodeEditors.test.tsx +294 -0
  484. package/Tests/UI/Components/Forms/FormFieldMarkdown.test.tsx +126 -0
  485. package/Tests/UI/Components/Forms/FormFieldYaml.test.tsx +22 -75
  486. package/Tests/UI/Components/Forms/ModelFormOnBeforeCreateMiscData.test.tsx +254 -0
  487. package/Tests/UI/Components/Icon.test.tsx +32 -0
  488. package/Tests/UI/Components/Input.test.tsx +31 -0
  489. package/Tests/UI/Components/LockedFilterChipScope.test.tsx +501 -0
  490. package/Tests/UI/Components/MarkdownConverters.test.ts +253 -1
  491. package/Tests/UI/Components/MarkdownEditor.test.tsx +2785 -2
  492. package/Tests/UI/Components/MarkdownEditorHistory.test.ts +243 -0
  493. package/Tests/UI/Components/MarkdownListEditing.test.ts +1118 -0
  494. package/Tests/UI/Components/MarkdownPaste.test.ts +1180 -0
  495. package/Tests/UI/Components/MarkdownViewerCopy.test.tsx +466 -0
  496. package/Tests/UI/Components/MarkdownVisualEditing.test.ts +1089 -0
  497. package/Tests/UI/Components/ModelTable/BaseModelTableEmptyStateAction.test.tsx +623 -0
  498. package/Tests/UI/Components/ResetObjectID.test.tsx +282 -0
  499. package/Tests/UI/Components/RuleCriteria/RuleCriteriaModelTable.test.tsx +3 -3
  500. package/Tests/UI/Components/Table/EmptyTableMessage.test.ts +439 -0
  501. package/Tests/UI/Components/Table/TableEmptyState.test.tsx +352 -0
  502. package/Tests/UI/Components/TableRowMobileTitles.test.tsx +78 -0
  503. package/Tests/UI/Components/TextArea.test.tsx +19 -0
  504. package/Tests/UI/Components/Workflow/ModelColumnEditor.render.test.tsx +12 -29
  505. package/Tests/UI/Components/fixtures/MarkdownPasteFixtures.ts +460 -0
  506. package/Tests/UI/EsbuildConfig.test.ts +115 -39
  507. package/Tests/UI/EsbuildEnterpriseAlias.test.ts +4 -4
  508. package/Tests/UI/Monitor/MonitorLogSummaryRender.test.tsx +377 -0
  509. package/Tests/UI/Rum/RecordingHealthDashboard.test.tsx +769 -1
  510. package/Tests/UI/Utils/Breadcrumb/fixtures/RealBreadcrumbTrails.ts +81 -1
  511. package/Tests/UI/Utils/Breadcrumb/fixtures/RealRoutePatterns.ts +17 -0
  512. package/Tests/Utils/AiRemediation/Resource/CephCommandPolicy.test.ts +1653 -0
  513. package/Tests/Utils/AiRemediation/Resource/CephOutputRedaction.test.ts +204 -0
  514. package/Tests/Utils/AiRemediation/Resource/DatabaseCommandPolicy.test.ts +1077 -0
  515. package/Tests/Utils/AiRemediation/Resource/DatabaseDiagnosticCatalog.test.ts +558 -0
  516. package/Tests/Utils/AiRemediation/Resource/DatabaseQueryRedactor.test.ts +834 -0
  517. package/Tests/Utils/AiRemediation/Resource/DockerCliGrammar.test.ts +747 -0
  518. package/Tests/Utils/AiRemediation/Resource/DockerEngineCommandPolicy.test.ts +1259 -0
  519. package/Tests/Utils/AiRemediation/Resource/DockerOutputRedaction.test.ts +386 -0
  520. package/Tests/Utils/AiRemediation/Resource/DockerSwarmCommandPolicy.test.ts +782 -0
  521. package/Tests/Utils/AiRemediation/Resource/GovcCommandPolicy.test.ts +2259 -0
  522. package/Tests/Utils/AiRemediation/Resource/HostCommandPolicy.test.ts +2019 -0
  523. package/Tests/Utils/AiRemediation/Resource/ProxmoxCommandPolicy.test.ts +2497 -0
  524. package/Tests/Utils/AiRemediation/Resource/ResourceCommandPolicy.test.ts +1305 -0
  525. package/Tests/Utils/AiRemediation/Resource/ResourceCommandPolicyCore.test.ts +585 -0
  526. package/Tests/Utils/AiRemediation/Resource/ResourceOutputRedactor.test.ts +334 -0
  527. package/Tests/Utils/AiRemediation/Resource/ResourceOutputRedactorCopyParity.test.ts +98 -0
  528. package/Tests/Utils/AiRemediation/Resource/ResourcePolicyImportClosure.test.ts +391 -0
  529. package/Tests/Utils/AiRemediation/ResourceAiAgentPolicyCopyParity.test.ts +497 -0
  530. package/Tests/Utils/LabelRuleImportExport.test.ts +5 -0
  531. package/Tests/Utils/Markdown/DashboardMarkdownRenderer.ts +81 -0
  532. package/Tests/Utils/Markdown/UntrustedMarkdown.test.ts +1339 -0
  533. package/Tests/Utils/Monitor/MonitorLogSummaryUtil.test.ts +862 -0
  534. package/Tests/Utils/SessionReplay/SessionReplayBudgetMetricType.test.ts +383 -0
  535. package/Types/AI/AIAgentRunLimits.ts +146 -0
  536. package/Types/AI/ResourceAiAccessApi.ts +140 -0
  537. package/Types/AI/ResourceAiAccessPermissions.ts +126 -0
  538. package/Types/AutoRemediation/AiRemediationCommandPlan.ts +183 -2
  539. package/Types/Code/CodeType.ts +2 -0
  540. package/Types/Code/JsonSyntax.ts +923 -0
  541. package/Types/CustomField/CustomFieldCreateSettings.ts +549 -0
  542. package/Types/CustomField/CustomFieldMappingCatalog.ts +77 -0
  543. package/Types/CustomField/CustomFieldValueValidator.ts +10 -7
  544. package/Types/EnterpriseLicense/EnterpriseLicensePeriods.ts +1 -1
  545. package/Types/Icon/IconProp.ts +2 -0
  546. package/Types/Incident/IncidentFormIpAllowlist.ts +206 -0
  547. package/Types/Incident/IncidentFormPublic.ts +1145 -0
  548. package/Types/Kubernetes/KubernetesClusterAiAccess.ts +10 -3
  549. package/Types/MessageQueue/MessageQueueIdentity.ts +256 -0
  550. package/Types/MessageQueue/MessageQueueManualIdentity.ts +325 -0
  551. package/Types/MessageQueue/MessageQueueMetricCatalog.ts +1357 -0
  552. package/Types/MessageQueue/MessagingSystem.ts +518 -0
  553. package/Types/MessageQueue/MessagingTelemetryResolver.ts +2311 -0
  554. package/Types/Monitor/MessageQueueAlertTemplates.ts +2128 -0
  555. package/Types/Monitor/Recommendation/MonitorRecommendationCatalog.ts +55 -22
  556. package/Types/Monitor/Recommendation/MonitorRecommendationTypes.ts +35 -3
  557. package/Types/Monitor/RumAlertTemplates.ts +351 -4
  558. package/Types/Permission.ts +310 -0
  559. package/Types/ResourceAiAgent/AiResourceType.ts +310 -0
  560. package/Types/ResourceAiAgent/ResourceAiAccess.ts +580 -0
  561. package/Types/Rules/RuleCriteriaFieldRegistry.ts +12 -0
  562. package/Types/Rules/RuleRun.ts +4 -0
  563. package/Types/Rum/SessionReplayBudgetMetricType.ts +47 -0
  564. package/Types/Runbook/RunbookStepType.ts +29 -0
  565. package/Types/Team/ComplianceNotificationChannel.ts +4 -3
  566. package/Types/Team/ComplianceRule.ts +71 -18
  567. package/Types/Team/ComplianceRuleType.ts +2 -2
  568. package/Types/Team/TeamComplianceStatus.ts +6 -2
  569. package/Types/Telemetry/EntityType.ts +16 -0
  570. package/Types/Telemetry/LockedFilterDetail.ts +22 -0
  571. package/Types/Telemetry/TelemetryIngestSurface.ts +14 -2
  572. package/Types/XML.ts +26 -0
  573. package/UI/Components/CodeEditor/CodeEditor.css +379 -0
  574. package/UI/Components/CodeEditor/CodeEditor.tsx +1128 -294
  575. package/UI/Components/CodeEditor/CodeEditorCommands.ts +774 -0
  576. package/UI/Components/CodeEditor/CodeEditorHighlight.ts +106 -0
  577. package/UI/Components/CodeEditor/CodeEditorLanguages.ts +164 -0
  578. package/UI/Components/CodeEditor/YamlEditor.tsx +28 -326
  579. package/UI/Components/CopyTextButton/CopyTextButton.tsx +5 -1
  580. package/UI/Components/CustomFields/CustomFieldModelFormFields.tsx +6 -25
  581. package/UI/Components/EditionLabel/EditionLabel.tsx +14 -13
  582. package/UI/Components/ErrorMessage/ErrorMessage.tsx +11 -1
  583. package/UI/Components/Forms/Fields/FormField.tsx +8 -0
  584. package/UI/Components/Forms/Types/Field.ts +8 -0
  585. package/UI/Components/Icon/Icon.tsx +18 -0
  586. package/UI/Components/Input/Input.tsx +11 -4
  587. package/UI/Components/LogsViewer/LogsViewer.tsx +4 -0
  588. package/UI/Components/LogsViewer/components/LogsFacetSidebar.tsx +21 -3
  589. package/UI/Components/Markdown.tsx/MarkdownConverters.ts +0 -0
  590. package/UI/Components/Markdown.tsx/MarkdownEditor.tsx +877 -79
  591. package/UI/Components/Markdown.tsx/MarkdownEditorHistory.ts +284 -0
  592. package/UI/Components/Markdown.tsx/MarkdownListEditing.ts +1362 -0
  593. package/UI/Components/Markdown.tsx/MarkdownPaste.ts +1326 -0
  594. package/UI/Components/Markdown.tsx/MarkdownViewer.tsx +106 -10
  595. package/UI/Components/Markdown.tsx/MarkdownVisualEditing.ts +1032 -0
  596. package/UI/Components/ModelTable/BaseModelTable.tsx +85 -7
  597. package/UI/Components/ResetObjectID/ResetObjectID.tsx +35 -9
  598. package/UI/Components/Table/EmptyTableMessage.ts +81 -0
  599. package/UI/Components/Table/Table.tsx +50 -21
  600. package/UI/Components/Table/TableRow.tsx +9 -1
  601. package/UI/Components/TelemetryViewer/FacetVisibility.ts +97 -2
  602. package/UI/Components/TelemetryViewer/TelemetryViewer.tsx +13 -0
  603. package/UI/Components/TelemetryViewer/components/LockedFilterChip.tsx +214 -7
  604. package/UI/Components/TelemetryViewer/components/TelemetryFacetSidebar.tsx +21 -3
  605. package/UI/Components/TextArea/TextArea.tsx +9 -2
  606. package/UI/Components/Workflow/ModelFieldPicker.tsx +10 -12
  607. package/UI/Styles/Theme.css +8 -0
  608. package/UI/esbuild-config.js +2 -32
  609. package/Utils/AI/InvestigationReport.ts +121 -15
  610. package/Utils/AiRemediation/Resource/CephCommandPolicy.ts +1936 -0
  611. package/Utils/AiRemediation/Resource/DatabaseCommandPolicy.ts +166 -0
  612. package/Utils/AiRemediation/Resource/DatabaseDiagnosticCatalog.ts +1532 -0
  613. package/Utils/AiRemediation/Resource/DatabaseQueryRedactor.ts +1394 -0
  614. package/Utils/AiRemediation/Resource/DockerCliGrammar.ts +1839 -0
  615. package/Utils/AiRemediation/Resource/DockerEngineCommandPolicy.ts +490 -0
  616. package/Utils/AiRemediation/Resource/DockerSwarmCommandPolicy.ts +687 -0
  617. package/Utils/AiRemediation/Resource/GovcCommandPolicy.ts +2096 -0
  618. package/Utils/AiRemediation/Resource/HostCommandPolicy.ts +2982 -0
  619. package/Utils/AiRemediation/Resource/ProxmoxCommandPolicy.ts +1679 -0
  620. package/Utils/AiRemediation/Resource/ResourceCommandPolicy.ts +851 -0
  621. package/Utils/AiRemediation/Resource/ResourceCommandPolicyCore.ts +593 -0
  622. package/Utils/AiRemediation/Resource/ResourceOutputRedactor.ts +2812 -0
  623. package/Utils/LabelRuleImportExport.ts +2 -0
  624. package/Utils/Markdown/UntrustedMarkdown.ts +1513 -0
  625. package/Utils/Monitor/IncomingEmailMonitorRequestUtil.ts +41 -0
  626. package/Utils/Monitor/MonitorLogSummaryUtil.ts +212 -0
  627. package/Utils/SessionReplay/SessionReplayBudgetMetricType.ts +184 -0
  628. package/Utils/Telemetry/EntityKey.ts +48 -0
  629. package/build/dist/Models/DatabaseModels/AIConversation.js +125 -1
  630. package/build/dist/Models/DatabaseModels/AIConversation.js.map +1 -1
  631. package/build/dist/Models/DatabaseModels/AutoRemediationSuggestion.js +62 -0
  632. package/build/dist/Models/DatabaseModels/AutoRemediationSuggestion.js.map +1 -1
  633. package/build/dist/Models/DatabaseModels/CephCluster.js +231 -0
  634. package/build/dist/Models/DatabaseModels/CephCluster.js.map +1 -1
  635. package/build/dist/Models/DatabaseModels/CloudResource.js +12 -0
  636. package/build/dist/Models/DatabaseModels/CloudResource.js.map +1 -1
  637. package/build/dist/Models/DatabaseModels/DatabaseServer.js +231 -0
  638. package/build/dist/Models/DatabaseModels/DatabaseServer.js.map +1 -1
  639. package/build/dist/Models/DatabaseModels/DockerHost.js +231 -0
  640. package/build/dist/Models/DatabaseModels/DockerHost.js.map +1 -1
  641. package/build/dist/Models/DatabaseModels/DockerSwarmCluster.js +231 -0
  642. package/build/dist/Models/DatabaseModels/DockerSwarmCluster.js.map +1 -1
  643. package/build/dist/Models/DatabaseModels/GlobalConfig.js +1 -1
  644. package/build/dist/Models/DatabaseModels/GlobalConfig.js.map +1 -1
  645. package/build/dist/Models/DatabaseModels/GlobalOidc.js +0 -4
  646. package/build/dist/Models/DatabaseModels/GlobalOidc.js.map +1 -1
  647. package/build/dist/Models/DatabaseModels/GlobalOidcProject.js +0 -4
  648. package/build/dist/Models/DatabaseModels/GlobalOidcProject.js.map +1 -1
  649. package/build/dist/Models/DatabaseModels/GlobalSso.js +0 -4
  650. package/build/dist/Models/DatabaseModels/GlobalSso.js.map +1 -1
  651. package/build/dist/Models/DatabaseModels/GlobalSsoProject.js +0 -4
  652. package/build/dist/Models/DatabaseModels/GlobalSsoProject.js.map +1 -1
  653. package/build/dist/Models/DatabaseModels/Host.js +231 -0
  654. package/build/dist/Models/DatabaseModels/Host.js.map +1 -1
  655. package/build/dist/Models/DatabaseModels/IncidentForm.js +605 -0
  656. package/build/dist/Models/DatabaseModels/IncidentForm.js.map +1 -0
  657. package/build/dist/Models/DatabaseModels/IncidentFormSubmission.js +299 -0
  658. package/build/dist/Models/DatabaseModels/IncidentFormSubmission.js.map +1 -0
  659. package/build/dist/Models/DatabaseModels/IncidentTemplate.js +60 -0
  660. package/build/dist/Models/DatabaseModels/IncidentTemplate.js.map +1 -1
  661. package/build/dist/Models/DatabaseModels/Index.js +16 -0
  662. package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
  663. package/build/dist/Models/DatabaseModels/IoTFleet.js +12 -0
  664. package/build/dist/Models/DatabaseModels/IoTFleet.js.map +1 -1
  665. package/build/dist/Models/DatabaseModels/KubernetesCluster.js +12 -0
  666. package/build/dist/Models/DatabaseModels/KubernetesCluster.js.map +1 -1
  667. package/build/dist/Models/DatabaseModels/MessageQueue.js +1106 -0
  668. package/build/dist/Models/DatabaseModels/MessageQueue.js.map +1 -0
  669. package/build/dist/Models/DatabaseModels/MessageQueueLabelRule.js +562 -0
  670. package/build/dist/Models/DatabaseModels/MessageQueueLabelRule.js.map +1 -0
  671. package/build/dist/Models/DatabaseModels/MessageQueueOwnerRule.js +643 -0
  672. package/build/dist/Models/DatabaseModels/MessageQueueOwnerRule.js.map +1 -0
  673. package/build/dist/Models/DatabaseModels/MessageQueueOwnerTeam.js +506 -0
  674. package/build/dist/Models/DatabaseModels/MessageQueueOwnerTeam.js.map +1 -0
  675. package/build/dist/Models/DatabaseModels/MessageQueueOwnerUser.js +505 -0
  676. package/build/dist/Models/DatabaseModels/MessageQueueOwnerUser.js.map +1 -0
  677. package/build/dist/Models/DatabaseModels/PodmanHost.js +231 -0
  678. package/build/dist/Models/DatabaseModels/PodmanHost.js.map +1 -1
  679. package/build/dist/Models/DatabaseModels/Project.js +61 -0
  680. package/build/dist/Models/DatabaseModels/Project.js.map +1 -1
  681. package/build/dist/Models/DatabaseModels/ProjectOidc.js +0 -4
  682. package/build/dist/Models/DatabaseModels/ProjectOidc.js.map +1 -1
  683. package/build/dist/Models/DatabaseModels/ProjectSso.js +0 -4
  684. package/build/dist/Models/DatabaseModels/ProjectSso.js.map +1 -1
  685. package/build/dist/Models/DatabaseModels/ProxmoxCluster.js +231 -0
  686. package/build/dist/Models/DatabaseModels/ProxmoxCluster.js.map +1 -1
  687. package/build/dist/Models/DatabaseModels/ResourceAiAgent.js +439 -0
  688. package/build/dist/Models/DatabaseModels/ResourceAiAgent.js.map +1 -0
  689. package/build/dist/Models/DatabaseModels/RumApplication.js +12 -0
  690. package/build/dist/Models/DatabaseModels/RumApplication.js.map +1 -1
  691. package/build/dist/Models/DatabaseModels/RunnerJob.js +145 -0
  692. package/build/dist/Models/DatabaseModels/RunnerJob.js.map +1 -1
  693. package/build/dist/Models/DatabaseModels/ServerlessFunction.js +12 -0
  694. package/build/dist/Models/DatabaseModels/ServerlessFunction.js.map +1 -1
  695. package/build/dist/Models/DatabaseModels/Service.js +12 -0
  696. package/build/dist/Models/DatabaseModels/Service.js.map +1 -1
  697. package/build/dist/Models/DatabaseModels/StatusPageOidc.js +0 -4
  698. package/build/dist/Models/DatabaseModels/StatusPageOidc.js.map +1 -1
  699. package/build/dist/Models/DatabaseModels/StatusPageSso.js +0 -4
  700. package/build/dist/Models/DatabaseModels/StatusPageSso.js.map +1 -1
  701. package/build/dist/Models/DatabaseModels/TeamComplianceSetting.js +49 -3
  702. package/build/dist/Models/DatabaseModels/TeamComplianceSetting.js.map +1 -1
  703. package/build/dist/Models/DatabaseModels/VMwareVCenter.js +231 -0
  704. package/build/dist/Models/DatabaseModels/VMwareVCenter.js.map +1 -1
  705. package/build/dist/Server/API/AIChatAPI.js +9 -103
  706. package/build/dist/Server/API/AIChatAPI.js.map +1 -1
  707. package/build/dist/Server/API/AIInvestigationAPI.js +3 -3
  708. package/build/dist/Server/API/AIInvestigationAPI.js.map +1 -1
  709. package/build/dist/Server/API/AIInvestigationConversationAPI.js +162 -0
  710. package/build/dist/Server/API/AIInvestigationConversationAPI.js.map +1 -0
  711. package/build/dist/Server/API/AutoRemediationAPI.js +231 -1
  712. package/build/dist/Server/API/AutoRemediationAPI.js.map +1 -1
  713. package/build/dist/Server/API/IncidentFormAPI.js +245 -0
  714. package/build/dist/Server/API/IncidentFormAPI.js.map +1 -0
  715. package/build/dist/Server/API/ProjectOIDC.js +16 -24
  716. package/build/dist/Server/API/ProjectOIDC.js.map +1 -1
  717. package/build/dist/Server/API/ProjectSSO.js +16 -24
  718. package/build/dist/Server/API/ProjectSSO.js.map +1 -1
  719. package/build/dist/Server/API/ResourceAiAccessAPI.js +1119 -0
  720. package/build/dist/Server/API/ResourceAiAccessAPI.js.map +1 -0
  721. package/build/dist/Server/API/StatusPageAPI.js +42 -75
  722. package/build/dist/Server/API/StatusPageAPI.js.map +1 -1
  723. package/build/dist/Server/Enterprise/EnterpriseEdition.js +79 -25
  724. package/build/dist/Server/Enterprise/EnterpriseEdition.js.map +1 -1
  725. package/build/dist/Server/Enterprise/EnterpriseFeature.js +24 -3
  726. package/build/dist/Server/Enterprise/EnterpriseFeature.js.map +1 -1
  727. package/build/dist/Server/Enterprise/EnterpriseLicenseSnapshot.js +1 -1
  728. package/build/dist/Server/Enterprise/EnterpriseServerModule.js.map +1 -1
  729. package/build/dist/Server/EnvironmentConfig.js +1 -1
  730. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1796300000000-AddResourceAiAgents.js +168 -0
  731. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1796300000000-AddResourceAiAgents.js.map +1 -0
  732. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1796400000000-AddIncidentForms.js +63 -0
  733. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1796400000000-AddIncidentForms.js.map +1 -0
  734. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1796500000000-AddTeamComplianceRuleNotificationChannels.js +41 -0
  735. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1796500000000-AddTeamComplianceRuleNotificationChannels.js.map +1 -0
  736. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1796600000000-AddAIInvestigationConversationAndTimeLimits.js +40 -0
  737. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1796600000000-AddAIInvestigationConversationAndTimeLimits.js.map +1 -0
  738. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1796700000000-AddMessageQueueTables.js +183 -0
  739. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1796700000000-AddMessageQueueTables.js.map +1 -0
  740. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +10 -0
  741. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  742. package/build/dist/Server/Infrastructure/Semaphore.js +6 -0
  743. package/build/dist/Server/Infrastructure/Semaphore.js.map +1 -1
  744. package/build/dist/Server/Middleware/IncidentFormRateLimit.js +559 -0
  745. package/build/dist/Server/Middleware/IncidentFormRateLimit.js.map +1 -0
  746. package/build/dist/Server/Middleware/TelemetryIngest.js +12 -5
  747. package/build/dist/Server/Middleware/TelemetryIngest.js.map +1 -1
  748. package/build/dist/Server/Middleware/UserAuthorization.js +11 -30
  749. package/build/dist/Server/Middleware/UserAuthorization.js.map +1 -1
  750. package/build/dist/Server/Services/AIService.js +10 -13
  751. package/build/dist/Server/Services/AIService.js.map +1 -1
  752. package/build/dist/Server/Services/AnalyticsDatabaseService.js +26 -1
  753. package/build/dist/Server/Services/AnalyticsDatabaseService.js.map +1 -1
  754. package/build/dist/Server/Services/AutoRemediationRuleEngineService.js +601 -3
  755. package/build/dist/Server/Services/AutoRemediationRuleEngineService.js.map +1 -1
  756. package/build/dist/Server/Services/CephClusterService.js +104 -0
  757. package/build/dist/Server/Services/CephClusterService.js.map +1 -1
  758. package/build/dist/Server/Services/DatabaseServerService.js +99 -0
  759. package/build/dist/Server/Services/DatabaseServerService.js.map +1 -1
  760. package/build/dist/Server/Services/DockerHostService.js +104 -0
  761. package/build/dist/Server/Services/DockerHostService.js.map +1 -1
  762. package/build/dist/Server/Services/DockerSwarmClusterService.js +104 -0
  763. package/build/dist/Server/Services/DockerSwarmClusterService.js.map +1 -1
  764. package/build/dist/Server/Services/HostService.js +114 -2
  765. package/build/dist/Server/Services/HostService.js.map +1 -1
  766. package/build/dist/Server/Services/IncidentCustomFieldService.js +83 -0
  767. package/build/dist/Server/Services/IncidentCustomFieldService.js.map +1 -1
  768. package/build/dist/Server/Services/IncidentEpisodeMemberService.js +8 -4
  769. package/build/dist/Server/Services/IncidentEpisodeMemberService.js.map +1 -1
  770. package/build/dist/Server/Services/IncidentEpisodeService.js +10 -1
  771. package/build/dist/Server/Services/IncidentEpisodeService.js.map +1 -1
  772. package/build/dist/Server/Services/IncidentFormService.js +1202 -0
  773. package/build/dist/Server/Services/IncidentFormService.js.map +1 -0
  774. package/build/dist/Server/Services/IncidentFormSubmissionService.js +91 -0
  775. package/build/dist/Server/Services/IncidentFormSubmissionService.js.map +1 -0
  776. package/build/dist/Server/Services/IncidentGroupingEngineService.js +20 -8
  777. package/build/dist/Server/Services/IncidentGroupingEngineService.js.map +1 -1
  778. package/build/dist/Server/Services/IncidentService.js +106 -4
  779. package/build/dist/Server/Services/IncidentService.js.map +1 -1
  780. package/build/dist/Server/Services/IncidentTemplateService.js +18 -0
  781. package/build/dist/Server/Services/IncidentTemplateService.js.map +1 -1
  782. package/build/dist/Server/Services/Index.js +14 -0
  783. package/build/dist/Server/Services/Index.js.map +1 -1
  784. package/build/dist/Server/Services/MessageQueueLabelRuleEngineService.js +262 -0
  785. package/build/dist/Server/Services/MessageQueueLabelRuleEngineService.js.map +1 -0
  786. package/build/dist/Server/Services/MessageQueueLabelRuleService.js +13 -0
  787. package/build/dist/Server/Services/MessageQueueLabelRuleService.js.map +1 -0
  788. package/build/dist/Server/Services/MessageQueueOwnerRuleEngineService.js +334 -0
  789. package/build/dist/Server/Services/MessageQueueOwnerRuleEngineService.js.map +1 -0
  790. package/build/dist/Server/Services/MessageQueueOwnerRuleService.js +13 -0
  791. package/build/dist/Server/Services/MessageQueueOwnerRuleService.js.map +1 -0
  792. package/build/dist/Server/Services/MessageQueueOwnerTeamService.js +62 -0
  793. package/build/dist/Server/Services/MessageQueueOwnerTeamService.js.map +1 -0
  794. package/build/dist/Server/Services/MessageQueueOwnerUserService.js +62 -0
  795. package/build/dist/Server/Services/MessageQueueOwnerUserService.js.map +1 -0
  796. package/build/dist/Server/Services/MessageQueueService.js +1140 -0
  797. package/build/dist/Server/Services/MessageQueueService.js.map +1 -0
  798. package/build/dist/Server/Services/MetricRecordingRuleService.js +46 -0
  799. package/build/dist/Server/Services/MetricRecordingRuleService.js.map +1 -1
  800. package/build/dist/Server/Services/OpenTelemetryIngestService.js +25 -4
  801. package/build/dist/Server/Services/OpenTelemetryIngestService.js.map +1 -1
  802. package/build/dist/Server/Services/PodmanHostService.js +104 -0
  803. package/build/dist/Server/Services/PodmanHostService.js.map +1 -1
  804. package/build/dist/Server/Services/ProjectService.js +0 -54
  805. package/build/dist/Server/Services/ProjectService.js.map +1 -1
  806. package/build/dist/Server/Services/ProxmoxClusterService.js +104 -0
  807. package/build/dist/Server/Services/ProxmoxClusterService.js.map +1 -1
  808. package/build/dist/Server/Services/ResourceAiAccessService.js +1028 -0
  809. package/build/dist/Server/Services/ResourceAiAccessService.js.map +1 -0
  810. package/build/dist/Server/Services/ResourceAiAgentJobService.js +173 -0
  811. package/build/dist/Server/Services/ResourceAiAgentJobService.js.map +1 -0
  812. package/build/dist/Server/Services/ResourceAiAgentService.js +1687 -0
  813. package/build/dist/Server/Services/ResourceAiAgentService.js.map +1 -0
  814. package/build/dist/Server/Services/RunnerJobService.js +344 -5
  815. package/build/dist/Server/Services/RunnerJobService.js.map +1 -1
  816. package/build/dist/Server/Services/StatusPagePrivateUserService.js +1 -4
  817. package/build/dist/Server/Services/StatusPagePrivateUserService.js.map +1 -1
  818. package/build/dist/Server/Services/StatusPageService.js +0 -46
  819. package/build/dist/Server/Services/StatusPageService.js.map +1 -1
  820. package/build/dist/Server/Services/TeamComplianceSettingService.js +120 -31
  821. package/build/dist/Server/Services/TeamComplianceSettingService.js.map +1 -1
  822. package/build/dist/Server/Services/TelemetryUsageBillingService.js +26 -0
  823. package/build/dist/Server/Services/TelemetryUsageBillingService.js.map +1 -1
  824. package/build/dist/Server/Services/TraceRecordingRuleService.js +37 -0
  825. package/build/dist/Server/Services/TraceRecordingRuleService.js.map +1 -1
  826. package/build/dist/Server/Services/UserNotificationRuleService.js +8 -1
  827. package/build/dist/Server/Services/UserNotificationRuleService.js.map +1 -1
  828. package/build/dist/Server/Services/VMwareVCenterService.js +104 -0
  829. package/build/dist/Server/Services/VMwareVCenterService.js.map +1 -1
  830. package/build/dist/Server/Services/WorkspaceNotificationSummaryService.js +12 -3
  831. package/build/dist/Server/Services/WorkspaceNotificationSummaryService.js.map +1 -1
  832. package/build/dist/Server/Types/Database/Permissions/CreatePermission.js +6 -3
  833. package/build/dist/Server/Types/Database/Permissions/CreatePermission.js.map +1 -1
  834. package/build/dist/Server/Types/Database/Permissions/EditionPermission.js +109 -37
  835. package/build/dist/Server/Types/Database/Permissions/EditionPermission.js.map +1 -1
  836. package/build/dist/Server/Types/Database/Permissions/OwnerTableRegistry.js +16 -0
  837. package/build/dist/Server/Types/Database/Permissions/OwnerTableRegistry.js.map +1 -1
  838. package/build/dist/Server/Types/Database/Permissions/TablePermission.js +3 -3
  839. package/build/dist/Server/Types/Database/Permissions/UpdatePermission.js +9 -6
  840. package/build/dist/Server/Types/Database/Permissions/UpdatePermission.js.map +1 -1
  841. package/build/dist/Server/Utils/AI/Chat/AgentContextCompactor.js +128 -0
  842. package/build/dist/Server/Utils/AI/Chat/AgentContextCompactor.js.map +1 -0
  843. package/build/dist/Server/Utils/AI/Chat/ChatAgentRunner.js +192 -50
  844. package/build/dist/Server/Utils/AI/Chat/ChatAgentRunner.js.map +1 -1
  845. package/build/dist/Server/Utils/AI/Chat/ChatRunCancellation.js +133 -0
  846. package/build/dist/Server/Utils/AI/Chat/ChatRunCancellation.js.map +1 -0
  847. package/build/dist/Server/Utils/AI/Chat/ObservabilityAssistant.js +53 -13
  848. package/build/dist/Server/Utils/AI/Chat/ObservabilityAssistant.js.map +1 -1
  849. package/build/dist/Server/Utils/AI/Chat/ObservabilityChatPrompt.js +1 -1
  850. package/build/dist/Server/Utils/AI/Chat/ToolOutputPager.js +206 -0
  851. package/build/dist/Server/Utils/AI/Chat/ToolOutputPager.js.map +1 -0
  852. package/build/dist/Server/Utils/AI/ClusterAccess/KubectlInvestigationToolkit.js +53 -26
  853. package/build/dist/Server/Utils/AI/ClusterAccess/KubectlInvestigationToolkit.js.map +1 -1
  854. package/build/dist/Server/Utils/AI/ClusterAccess/KubectlJobRunner.js +4 -2
  855. package/build/dist/Server/Utils/AI/ClusterAccess/KubectlJobRunner.js.map +1 -1
  856. package/build/dist/Server/Utils/AI/CodeFix/CodeFixReadiness.js +1 -29
  857. package/build/dist/Server/Utils/AI/CodeFix/CodeFixReadiness.js.map +1 -1
  858. package/build/dist/Server/Utils/AI/CodeFix/FixRunBudget.js +24 -24
  859. package/build/dist/Server/Utils/AI/CodeFix/FixRunBudget.js.map +1 -1
  860. package/build/dist/Server/Utils/AI/Remediation/RemediationCommandTools.js +1036 -32
  861. package/build/dist/Server/Utils/AI/Remediation/RemediationCommandTools.js.map +1 -1
  862. package/build/dist/Server/Utils/AI/Remediation/RemediationExecutionRunner.js +661 -41
  863. package/build/dist/Server/Utils/AI/Remediation/RemediationExecutionRunner.js.map +1 -1
  864. package/build/dist/Server/Utils/AI/Remediation/RemediationPlanRunner.js +21 -1
  865. package/build/dist/Server/Utils/AI/Remediation/RemediationPlanRunner.js.map +1 -1
  866. package/build/dist/Server/Utils/AI/ResourceAccess/InfrastructureInvestigationToolkit.js +354 -0
  867. package/build/dist/Server/Utils/AI/ResourceAccess/InfrastructureInvestigationToolkit.js.map +1 -0
  868. package/build/dist/Server/Utils/AI/ResourceAccess/ResourceAccessContext.js +160 -0
  869. package/build/dist/Server/Utils/AI/ResourceAccess/ResourceAccessContext.js.map +1 -0
  870. package/build/dist/Server/Utils/AI/ResourceAccess/ResourceAccessToolNames.js +33 -0
  871. package/build/dist/Server/Utils/AI/ResourceAccess/ResourceAccessToolNames.js.map +1 -0
  872. package/build/dist/Server/Utils/AI/ResourceAccess/ResourceAiAccessSettings.js +640 -0
  873. package/build/dist/Server/Utils/AI/ResourceAccess/ResourceAiAccessSettings.js.map +1 -0
  874. package/build/dist/Server/Utils/AI/ResourceAccess/ResourceAiDeleteCleanup.js +226 -0
  875. package/build/dist/Server/Utils/AI/ResourceAccess/ResourceAiDeleteCleanup.js.map +1 -0
  876. package/build/dist/Server/Utils/AI/ResourceAccess/ResourceCommandJobRunner.js +602 -0
  877. package/build/dist/Server/Utils/AI/ResourceAccess/ResourceCommandJobRunner.js.map +1 -0
  878. package/build/dist/Server/Utils/AI/SRE/AIInvestigationEngine.js +90 -14
  879. package/build/dist/Server/Utils/AI/SRE/AIInvestigationEngine.js.map +1 -1
  880. package/build/dist/Server/Utils/AI/SRE/AlertInvestigationRunner.js +73 -10
  881. package/build/dist/Server/Utils/AI/SRE/AlertInvestigationRunner.js.map +1 -1
  882. package/build/dist/Server/Utils/AI/SRE/IncidentInvestigationRunner.js +73 -10
  883. package/build/dist/Server/Utils/AI/SRE/IncidentInvestigationRunner.js.map +1 -1
  884. package/build/dist/Server/Utils/AI/SRE/InvestigationQueue.js +15 -18
  885. package/build/dist/Server/Utils/AI/SRE/InvestigationQueue.js.map +1 -1
  886. package/build/dist/Server/Utils/AI/SRE/InvestigationThread.js +412 -0
  887. package/build/dist/Server/Utils/AI/SRE/InvestigationThread.js.map +1 -0
  888. package/build/dist/Server/Utils/AI/SRE/InvestigationThreadService.js +495 -0
  889. package/build/dist/Server/Utils/AI/SRE/InvestigationThreadService.js.map +1 -0
  890. package/build/dist/Server/Utils/AI/Toolbox/Serializer.js +10 -3
  891. package/build/dist/Server/Utils/AI/Toolbox/Serializer.js.map +1 -1
  892. package/build/dist/Server/Utils/AutoRemediation/CommandPlanExecutor.js +290 -13
  893. package/build/dist/Server/Utils/AutoRemediation/CommandPlanExecutor.js.map +1 -1
  894. package/build/dist/Server/Utils/AutoRemediation/RemediationVerifier.js +29 -1
  895. package/build/dist/Server/Utils/AutoRemediation/RemediationVerifier.js.map +1 -1
  896. package/build/dist/Server/Utils/Database/ProjectScopedReferenceValidator.js +9 -1
  897. package/build/dist/Server/Utils/Database/ProjectScopedReferenceValidator.js.map +1 -1
  898. package/build/dist/Server/Utils/EditionEnforcement.js +20 -158
  899. package/build/dist/Server/Utils/EditionEnforcement.js.map +1 -1
  900. package/build/dist/Server/Utils/LLM/LLMService.js +193 -54
  901. package/build/dist/Server/Utils/LLM/LLMService.js.map +1 -1
  902. package/build/dist/Server/Utils/RelaxedScimTeamLocksReport.js +160 -0
  903. package/build/dist/Server/Utils/RelaxedScimTeamLocksReport.js.map +1 -0
  904. package/build/dist/Server/Utils/Rules/RuleRun/RuleRunRegistry.js +25 -0
  905. package/build/dist/Server/Utils/Rules/RuleRun/RuleRunRegistry.js.map +1 -1
  906. package/build/dist/Server/Utils/SameOriginRequest.js +151 -0
  907. package/build/dist/Server/Utils/SameOriginRequest.js.map +1 -0
  908. package/build/dist/Server/Utils/SessionReplay/SessionReplayBudgetMetrics.js +627 -0
  909. package/build/dist/Server/Utils/SessionReplay/SessionReplayBudgetMetrics.js.map +1 -0
  910. package/build/dist/Server/Utils/SessionReplay/SessionReplayUsage.js +60 -5
  911. package/build/dist/Server/Utils/SessionReplay/SessionReplayUsage.js.map +1 -1
  912. package/build/dist/Server/Utils/TeamMember/ProjectLeaveResourceCleanup.js +2 -0
  913. package/build/dist/Server/Utils/TeamMember/ProjectLeaveResourceCleanup.js.map +1 -1
  914. package/build/dist/Server/Utils/Telemetry/EntityRegistry.js +4 -1
  915. package/build/dist/Server/Utils/Telemetry/EntityRegistry.js.map +1 -1
  916. package/build/dist/Server/Utils/Telemetry/MessageQueueDiscovery.js +1015 -0
  917. package/build/dist/Server/Utils/Telemetry/MessageQueueDiscovery.js.map +1 -0
  918. package/build/dist/Server/Utils/Telemetry/ResourceEntityFilter.js +4 -1
  919. package/build/dist/Server/Utils/Telemetry/ResourceEntityFilter.js.map +1 -1
  920. package/build/dist/Server/Utils/VendorAssets.js +3 -3
  921. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/Alert.js +19 -15
  922. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/Alert.js.map +1 -1
  923. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/AlertEpisode.js +19 -15
  924. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/AlertEpisode.js.map +1 -1
  925. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/Auth.js +17 -1
  926. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/Auth.js.map +1 -1
  927. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/Incident.js +186 -210
  928. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/Incident.js.map +1 -1
  929. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/IncidentEpisode.js +22 -16
  930. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/IncidentEpisode.js.map +1 -1
  931. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/ScheduledMaintenance.js +233 -167
  932. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/ScheduledMaintenance.js.map +1 -1
  933. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js +273 -111
  934. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js.map +1 -1
  935. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsActivityDeduplicator.js +129 -0
  936. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsActivityDeduplicator.js.map +1 -0
  937. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsCardChoices.js +266 -0
  938. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsCardChoices.js.map +1 -0
  939. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsCreateCommands.js +258 -0
  940. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsCreateCommands.js.map +1 -0
  941. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsMessageSize.js +104 -0
  942. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsMessageSize.js.map +1 -0
  943. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsReplies.js +183 -0
  944. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsReplies.js.map +1 -0
  945. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsTimezone.js +123 -0
  946. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsTimezone.js.map +1 -0
  947. package/build/dist/Types/AI/AIAgentRunLimits.js +91 -0
  948. package/build/dist/Types/AI/AIAgentRunLimits.js.map +1 -0
  949. package/build/dist/Types/AI/ResourceAiAccessApi.js +30 -0
  950. package/build/dist/Types/AI/ResourceAiAccessApi.js.map +1 -0
  951. package/build/dist/Types/AI/ResourceAiAccessPermissions.js +98 -0
  952. package/build/dist/Types/AI/ResourceAiAccessPermissions.js.map +1 -0
  953. package/build/dist/Types/AutoRemediation/AiRemediationCommandPlan.js +116 -29
  954. package/build/dist/Types/AutoRemediation/AiRemediationCommandPlan.js.map +1 -1
  955. package/build/dist/Types/Code/CodeType.js +2 -0
  956. package/build/dist/Types/Code/CodeType.js.map +1 -1
  957. package/build/dist/Types/Code/JsonSyntax.js +604 -0
  958. package/build/dist/Types/Code/JsonSyntax.js.map +1 -0
  959. package/build/dist/Types/CustomField/CustomFieldCreateSettings.js +310 -0
  960. package/build/dist/Types/CustomField/CustomFieldCreateSettings.js.map +1 -0
  961. package/build/dist/Types/CustomField/CustomFieldMappingCatalog.js +38 -0
  962. package/build/dist/Types/CustomField/CustomFieldMappingCatalog.js.map +1 -1
  963. package/build/dist/Types/CustomField/CustomFieldValueValidator.js +10 -7
  964. package/build/dist/Types/CustomField/CustomFieldValueValidator.js.map +1 -1
  965. package/build/dist/Types/EnterpriseLicense/EnterpriseLicensePeriods.js +1 -1
  966. package/build/dist/Types/Icon/IconProp.js +2 -0
  967. package/build/dist/Types/Icon/IconProp.js.map +1 -1
  968. package/build/dist/Types/Incident/IncidentFormIpAllowlist.js +119 -0
  969. package/build/dist/Types/Incident/IncidentFormIpAllowlist.js.map +1 -0
  970. package/build/dist/Types/Incident/IncidentFormPublic.js +678 -0
  971. package/build/dist/Types/Incident/IncidentFormPublic.js.map +1 -0
  972. package/build/dist/Types/Kubernetes/KubernetesClusterAiAccess.js +10 -3
  973. package/build/dist/Types/Kubernetes/KubernetesClusterAiAccess.js.map +1 -1
  974. package/build/dist/Types/MessageQueue/MessageQueueIdentity.js +184 -0
  975. package/build/dist/Types/MessageQueue/MessageQueueIdentity.js.map +1 -0
  976. package/build/dist/Types/MessageQueue/MessageQueueManualIdentity.js +190 -0
  977. package/build/dist/Types/MessageQueue/MessageQueueManualIdentity.js.map +1 -0
  978. package/build/dist/Types/MessageQueue/MessageQueueMetricCatalog.js +1057 -0
  979. package/build/dist/Types/MessageQueue/MessageQueueMetricCatalog.js.map +1 -0
  980. package/build/dist/Types/MessageQueue/MessagingSystem.js +394 -0
  981. package/build/dist/Types/MessageQueue/MessagingSystem.js.map +1 -0
  982. package/build/dist/Types/MessageQueue/MessagingTelemetryResolver.js +1768 -0
  983. package/build/dist/Types/MessageQueue/MessagingTelemetryResolver.js.map +1 -0
  984. package/build/dist/Types/Monitor/MessageQueueAlertTemplates.js +1207 -0
  985. package/build/dist/Types/Monitor/MessageQueueAlertTemplates.js.map +1 -0
  986. package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationCatalog.js +47 -21
  987. package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationCatalog.js.map +1 -1
  988. package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationTypes.js +5 -0
  989. package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationTypes.js.map +1 -1
  990. package/build/dist/Types/Monitor/RumAlertTemplates.js +199 -3
  991. package/build/dist/Types/Monitor/RumAlertTemplates.js.map +1 -1
  992. package/build/dist/Types/Permission.js +274 -0
  993. package/build/dist/Types/Permission.js.map +1 -1
  994. package/build/dist/Types/ResourceAiAgent/AiResourceType.js +242 -0
  995. package/build/dist/Types/ResourceAiAgent/AiResourceType.js.map +1 -0
  996. package/build/dist/Types/ResourceAiAgent/ResourceAiAccess.js +281 -0
  997. package/build/dist/Types/ResourceAiAgent/ResourceAiAccess.js.map +1 -0
  998. package/build/dist/Types/Rules/RuleCriteriaFieldRegistry.js +12 -0
  999. package/build/dist/Types/Rules/RuleCriteriaFieldRegistry.js.map +1 -1
  1000. package/build/dist/Types/Rules/RuleRun.js +4 -0
  1001. package/build/dist/Types/Rules/RuleRun.js.map +1 -1
  1002. package/build/dist/Types/Rum/SessionReplayBudgetMetricType.js +45 -0
  1003. package/build/dist/Types/Rum/SessionReplayBudgetMetricType.js.map +1 -0
  1004. package/build/dist/Types/Runbook/RunbookStepType.js +27 -0
  1005. package/build/dist/Types/Runbook/RunbookStepType.js.map +1 -1
  1006. package/build/dist/Types/Team/ComplianceNotificationChannel.js +4 -3
  1007. package/build/dist/Types/Team/ComplianceNotificationChannel.js.map +1 -1
  1008. package/build/dist/Types/Team/ComplianceRule.js +48 -14
  1009. package/build/dist/Types/Team/ComplianceRule.js.map +1 -1
  1010. package/build/dist/Types/Team/ComplianceRuleType.js +2 -2
  1011. package/build/dist/Types/Telemetry/EntityType.js +16 -0
  1012. package/build/dist/Types/Telemetry/EntityType.js.map +1 -1
  1013. package/build/dist/Types/Telemetry/TelemetryIngestSurface.js +13 -2
  1014. package/build/dist/Types/Telemetry/TelemetryIngestSurface.js.map +1 -1
  1015. package/build/dist/Types/XML.js +23 -0
  1016. package/build/dist/Types/XML.js.map +1 -1
  1017. package/build/dist/UI/Components/CodeEditor/CodeEditor.js +641 -266
  1018. package/build/dist/UI/Components/CodeEditor/CodeEditor.js.map +1 -1
  1019. package/build/dist/UI/Components/CodeEditor/CodeEditorCommands.js +464 -0
  1020. package/build/dist/UI/Components/CodeEditor/CodeEditorCommands.js.map +1 -0
  1021. package/build/dist/UI/Components/CodeEditor/CodeEditorHighlight.js +69 -0
  1022. package/build/dist/UI/Components/CodeEditor/CodeEditorHighlight.js.map +1 -0
  1023. package/build/dist/UI/Components/CodeEditor/CodeEditorLanguages.js +108 -0
  1024. package/build/dist/UI/Components/CodeEditor/CodeEditorLanguages.js.map +1 -0
  1025. package/build/dist/UI/Components/CodeEditor/YamlEditor.js +14 -186
  1026. package/build/dist/UI/Components/CodeEditor/YamlEditor.js.map +1 -1
  1027. package/build/dist/UI/Components/CopyTextButton/CopyTextButton.js +5 -1
  1028. package/build/dist/UI/Components/CopyTextButton/CopyTextButton.js.map +1 -1
  1029. package/build/dist/UI/Components/CustomFields/CustomFieldModelFormFields.js +5 -14
  1030. package/build/dist/UI/Components/CustomFields/CustomFieldModelFormFields.js.map +1 -1
  1031. package/build/dist/UI/Components/EditionLabel/EditionLabel.js +14 -13
  1032. package/build/dist/UI/Components/EditionLabel/EditionLabel.js.map +1 -1
  1033. package/build/dist/UI/Components/ErrorMessage/ErrorMessage.js +1 -1
  1034. package/build/dist/UI/Components/ErrorMessage/ErrorMessage.js.map +1 -1
  1035. package/build/dist/UI/Components/Forms/Fields/FormField.js +8 -3
  1036. package/build/dist/UI/Components/Forms/Fields/FormField.js.map +1 -1
  1037. package/build/dist/UI/Components/Icon/Icon.js +8 -0
  1038. package/build/dist/UI/Components/Icon/Icon.js.map +1 -1
  1039. package/build/dist/UI/Components/Input/Input.js +11 -3
  1040. package/build/dist/UI/Components/Input/Input.js.map +1 -1
  1041. package/build/dist/UI/Components/LogsViewer/LogsViewer.js +2 -1
  1042. package/build/dist/UI/Components/LogsViewer/LogsViewer.js.map +1 -1
  1043. package/build/dist/UI/Components/LogsViewer/components/LogsFacetSidebar.js +14 -4
  1044. package/build/dist/UI/Components/LogsViewer/components/LogsFacetSidebar.js.map +1 -1
  1045. package/build/dist/UI/Components/Markdown.tsx/MarkdownConverters.js +0 -0
  1046. package/build/dist/UI/Components/Markdown.tsx/MarkdownConverters.js.map +1 -1
  1047. package/build/dist/UI/Components/Markdown.tsx/MarkdownEditor.js +710 -65
  1048. package/build/dist/UI/Components/Markdown.tsx/MarkdownEditor.js.map +1 -1
  1049. package/build/dist/UI/Components/Markdown.tsx/MarkdownEditorHistory.js +238 -0
  1050. package/build/dist/UI/Components/Markdown.tsx/MarkdownEditorHistory.js.map +1 -0
  1051. package/build/dist/UI/Components/Markdown.tsx/MarkdownListEditing.js +1028 -0
  1052. package/build/dist/UI/Components/Markdown.tsx/MarkdownListEditing.js.map +1 -0
  1053. package/build/dist/UI/Components/Markdown.tsx/MarkdownPaste.js +1088 -0
  1054. package/build/dist/UI/Components/Markdown.tsx/MarkdownPaste.js.map +1 -0
  1055. package/build/dist/UI/Components/Markdown.tsx/MarkdownViewer.js +70 -10
  1056. package/build/dist/UI/Components/Markdown.tsx/MarkdownViewer.js.map +1 -1
  1057. package/build/dist/UI/Components/Markdown.tsx/MarkdownVisualEditing.js +887 -0
  1058. package/build/dist/UI/Components/Markdown.tsx/MarkdownVisualEditing.js.map +1 -0
  1059. package/build/dist/UI/Components/ModelTable/BaseModelTable.js +57 -6
  1060. package/build/dist/UI/Components/ModelTable/BaseModelTable.js.map +1 -1
  1061. package/build/dist/UI/Components/ResetObjectID/ResetObjectID.js +7 -5
  1062. package/build/dist/UI/Components/ResetObjectID/ResetObjectID.js.map +1 -1
  1063. package/build/dist/UI/Components/Table/EmptyTableMessage.js +51 -0
  1064. package/build/dist/UI/Components/Table/EmptyTableMessage.js.map +1 -0
  1065. package/build/dist/UI/Components/Table/Table.js +30 -11
  1066. package/build/dist/UI/Components/Table/Table.js.map +1 -1
  1067. package/build/dist/UI/Components/Table/TableRow.js +9 -2
  1068. package/build/dist/UI/Components/Table/TableRow.js.map +1 -1
  1069. package/build/dist/UI/Components/TelemetryViewer/FacetVisibility.js +63 -1
  1070. package/build/dist/UI/Components/TelemetryViewer/FacetVisibility.js.map +1 -1
  1071. package/build/dist/UI/Components/TelemetryViewer/TelemetryViewer.js +4 -2
  1072. package/build/dist/UI/Components/TelemetryViewer/TelemetryViewer.js.map +1 -1
  1073. package/build/dist/UI/Components/TelemetryViewer/components/LockedFilterChip.js +91 -10
  1074. package/build/dist/UI/Components/TelemetryViewer/components/LockedFilterChip.js.map +1 -1
  1075. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryFacetSidebar.js +14 -4
  1076. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryFacetSidebar.js.map +1 -1
  1077. package/build/dist/UI/Components/TextArea/TextArea.js +9 -3
  1078. package/build/dist/UI/Components/TextArea/TextArea.js.map +1 -1
  1079. package/build/dist/UI/Components/Workflow/ModelFieldPicker.js +1 -2
  1080. package/build/dist/UI/Components/Workflow/ModelFieldPicker.js.map +1 -1
  1081. package/build/dist/Utils/AI/InvestigationReport.js +71 -11
  1082. package/build/dist/Utils/AI/InvestigationReport.js.map +1 -1
  1083. package/build/dist/Utils/AiRemediation/Resource/CephCommandPolicy.js +1462 -0
  1084. package/build/dist/Utils/AiRemediation/Resource/CephCommandPolicy.js.map +1 -0
  1085. package/build/dist/Utils/AiRemediation/Resource/DatabaseCommandPolicy.js +122 -0
  1086. package/build/dist/Utils/AiRemediation/Resource/DatabaseCommandPolicy.js.map +1 -0
  1087. package/build/dist/Utils/AiRemediation/Resource/DatabaseDiagnosticCatalog.js +1139 -0
  1088. package/build/dist/Utils/AiRemediation/Resource/DatabaseDiagnosticCatalog.js.map +1 -0
  1089. package/build/dist/Utils/AiRemediation/Resource/DatabaseQueryRedactor.js +1060 -0
  1090. package/build/dist/Utils/AiRemediation/Resource/DatabaseQueryRedactor.js.map +1 -0
  1091. package/build/dist/Utils/AiRemediation/Resource/DockerCliGrammar.js +1301 -0
  1092. package/build/dist/Utils/AiRemediation/Resource/DockerCliGrammar.js.map +1 -0
  1093. package/build/dist/Utils/AiRemediation/Resource/DockerEngineCommandPolicy.js +370 -0
  1094. package/build/dist/Utils/AiRemediation/Resource/DockerEngineCommandPolicy.js.map +1 -0
  1095. package/build/dist/Utils/AiRemediation/Resource/DockerSwarmCommandPolicy.js +498 -0
  1096. package/build/dist/Utils/AiRemediation/Resource/DockerSwarmCommandPolicy.js.map +1 -0
  1097. package/build/dist/Utils/AiRemediation/Resource/GovcCommandPolicy.js +1565 -0
  1098. package/build/dist/Utils/AiRemediation/Resource/GovcCommandPolicy.js.map +1 -0
  1099. package/build/dist/Utils/AiRemediation/Resource/HostCommandPolicy.js +2206 -0
  1100. package/build/dist/Utils/AiRemediation/Resource/HostCommandPolicy.js.map +1 -0
  1101. package/build/dist/Utils/AiRemediation/Resource/ProxmoxCommandPolicy.js +1129 -0
  1102. package/build/dist/Utils/AiRemediation/Resource/ProxmoxCommandPolicy.js.map +1 -0
  1103. package/build/dist/Utils/AiRemediation/Resource/ResourceCommandPolicy.js +565 -0
  1104. package/build/dist/Utils/AiRemediation/Resource/ResourceCommandPolicy.js.map +1 -0
  1105. package/build/dist/Utils/AiRemediation/Resource/ResourceCommandPolicyCore.js +408 -0
  1106. package/build/dist/Utils/AiRemediation/Resource/ResourceCommandPolicyCore.js.map +1 -0
  1107. package/build/dist/Utils/AiRemediation/Resource/ResourceOutputRedactor.js +1910 -0
  1108. package/build/dist/Utils/AiRemediation/Resource/ResourceOutputRedactor.js.map +1 -0
  1109. package/build/dist/Utils/LabelRuleImportExport.js +2 -0
  1110. package/build/dist/Utils/LabelRuleImportExport.js.map +1 -1
  1111. package/build/dist/Utils/Markdown/UntrustedMarkdown.js +988 -0
  1112. package/build/dist/Utils/Markdown/UntrustedMarkdown.js.map +1 -0
  1113. package/build/dist/Utils/Monitor/IncomingEmailMonitorRequestUtil.js +34 -0
  1114. package/build/dist/Utils/Monitor/IncomingEmailMonitorRequestUtil.js.map +1 -0
  1115. package/build/dist/Utils/Monitor/MonitorLogSummaryUtil.js +148 -0
  1116. package/build/dist/Utils/Monitor/MonitorLogSummaryUtil.js.map +1 -0
  1117. package/build/dist/Utils/SessionReplay/SessionReplayBudgetMetricType.js +160 -0
  1118. package/build/dist/Utils/SessionReplay/SessionReplayBudgetMetricType.js.map +1 -0
  1119. package/build/dist/Utils/Telemetry/EntityKey.js +36 -0
  1120. package/build/dist/Utils/Telemetry/EntityKey.js.map +1 -1
  1121. package/package.json +1 -3
  1122. package/Server/Utils/CommunityEditionSsoReport.ts +0 -361
  1123. package/Tests/App/Accounts/LoginSsoEdition.test.tsx +0 -616
  1124. package/Tests/App/AdminDashboard/AdminAuthenticationSsoEdition.test.tsx +0 -217
  1125. package/Tests/App/AdminDashboard/GlobalSSOEnterpriseShells.test.tsx +0 -271
  1126. package/Tests/App/Dashboard/CloudDocumentationMarkdown.test.ts +0 -215
  1127. package/Tests/App/Dashboard/TelemetryResourceRetentionSettings.test.tsx +0 -784
  1128. package/Tests/Server/Middleware/UserAuthorizationEditionEnforcement.test.ts +0 -518
  1129. package/Tests/Server/Services/SsoRequirementReadMasking.test.ts +0 -419
  1130. package/Tests/Server/Services/SsoRequirementWriteGuard.test.ts +0 -769
  1131. package/Tests/UI/Components/CodeEditor.test.tsx +0 -638
  1132. package/Tests/UI/Components/MonacoLoader.test.ts +0 -67
  1133. package/Tests/UI/Components/MonacoRuntime.test.ts +0 -121
  1134. package/Tests/UI/Components/Telemetry/TelemetryRetentionConfigForm.test.tsx +0 -329
  1135. package/Tests/UI/Components/YamlEditor.test.tsx +0 -847
  1136. package/UI/Components/CodeEditor/MonacoLoader.ts +0 -36
  1137. package/UI/Components/Telemetry/TelemetryRetentionConfigForm.tsx +0 -319
  1138. package/UI/Components/Telemetry/TelemetryRetentionConfigSummary.tsx +0 -223
  1139. package/build/dist/Server/Utils/CommunityEditionSsoReport.js +0 -223
  1140. package/build/dist/Server/Utils/CommunityEditionSsoReport.js.map +0 -1
  1141. package/build/dist/UI/Components/CodeEditor/MonacoLoader.js +0 -34
  1142. package/build/dist/UI/Components/CodeEditor/MonacoLoader.js.map +0 -1
  1143. package/build/dist/UI/Components/Telemetry/TelemetryRetentionConfigForm.js +0 -171
  1144. package/build/dist/UI/Components/Telemetry/TelemetryRetentionConfigForm.js.map +0 -1
  1145. package/build/dist/UI/Components/Telemetry/TelemetryRetentionConfigSummary.js +0 -119
  1146. package/build/dist/UI/Components/Telemetry/TelemetryRetentionConfigSummary.js.map +0 -1
@@ -0,0 +1,2010 @@
1
+ import "@testing-library/jest-dom";
2
+ import {
3
+ afterEach,
4
+ beforeEach,
5
+ describe,
6
+ expect,
7
+ jest,
8
+ test,
9
+ } from "@jest/globals";
10
+ import {
11
+ act,
12
+ cleanup,
13
+ fireEvent,
14
+ render,
15
+ screen,
16
+ waitFor,
17
+ within,
18
+ } from "@testing-library/react";
19
+ import React from "react";
20
+ import { MemoryRouter, Route as PageRoute, Routes } from "react-router-dom";
21
+ import ResourceAiAgentPage from "../../../../App/FeatureSet/Dashboard/src/Components/ResourceAiAgent/ResourceAiAgentPage";
22
+ import {
23
+ ResourceAiAgentDescriptor,
24
+ getResourceAiAgentDescriptor,
25
+ } from "../../../../App/FeatureSet/Dashboard/src/Components/ResourceAiAgent/ResourceAiAgentDescriptors";
26
+ import {
27
+ RESOURCE_AI_AGENT_STATUS_POLL_INTERVAL_MS,
28
+ getResourceAiAgentNotInstalledText,
29
+ getResourceAiAgentPageSubtitle,
30
+ getResourceAiAgentReadyText,
31
+ getResourceAiAgentSignedOffText,
32
+ getResourceAiAgentSilentText,
33
+ } from "../../../../App/FeatureSet/Dashboard/src/Components/ResourceAiAgent/ResourceAiAgentStatus";
34
+ import {
35
+ RESOURCE_REMEDIATION_MODE_LABELS,
36
+ RESOURCE_REMEDIATION_MODE_SUMMARIES,
37
+ } from "../../../../App/FeatureSet/Dashboard/src/Components/ResourceAiAgent/ResourceAiAccessSettingsUtil";
38
+ import {
39
+ getResourceAiAgentComposeSnippet,
40
+ getResourceAiAgentLogsCommand,
41
+ getResourceAiAgentServiceName,
42
+ getResourceAiAgentWriteAccessCommands,
43
+ getResourceAiAgentWriteDisclosure,
44
+ } from "../../../../App/FeatureSet/Dashboard/src/Components/ResourceAiAgent/ResourceAiAgentInstall";
45
+ import RouteMap from "../../../../App/FeatureSet/Dashboard/src/Utils/RouteMap";
46
+ import DatabaseServer from "../../../Models/DatabaseModels/DatabaseServer";
47
+ import DockerHost from "../../../Models/DatabaseModels/DockerHost";
48
+ import Project from "../../../Models/DatabaseModels/Project";
49
+ import HTTPErrorResponse from "../../../Types/API/HTTPErrorResponse";
50
+ import HTTPResponse from "../../../Types/API/HTTPResponse";
51
+ import Route from "../../../Types/API/Route";
52
+ import ExceptionCode from "../../../Types/Exception/ExceptionCode";
53
+ import { JSONObject } from "../../../Types/JSON";
54
+ import ObjectID from "../../../Types/ObjectID";
55
+ import Permission from "../../../Types/Permission";
56
+ import AiResourceType, {
57
+ ALL_AI_RESOURCE_TYPES,
58
+ } from "../../../Types/ResourceAiAgent/AiResourceType";
59
+ import {
60
+ ResourceAiAccessGap,
61
+ ResourceAiAccessGapCode,
62
+ ResourceAiAccessStatus,
63
+ ResourceAiAgentPosture,
64
+ ResourceAiAgentSummary,
65
+ ResourceAiRemediationMode,
66
+ } from "../../../Types/ResourceAiAgent/ResourceAiAccess";
67
+ import API from "../../../UI/Utils/API/API";
68
+ import ModelAPI from "../../../UI/Utils/ModelAPI/ModelAPI";
69
+ import PermissionUtil from "../../../UI/Utils/Permission";
70
+ import User from "../../../UI/Utils/User";
71
+ import { goTo, PROJECT_ID } from "./SideMenuHarness";
72
+
73
+ jest.mock("react-i18next", () => {
74
+ return {
75
+ useTranslation: () => {
76
+ return {
77
+ t: (value: string): string => {
78
+ return value;
79
+ },
80
+ };
81
+ },
82
+ };
83
+ });
84
+
85
+ /*
86
+ * A resource's AI agent page (AI → AI agent) renders for real on its real
87
+ * route, with the status, test and reset-agent routes, the model API and
88
+ * the permission snapshot stubbed. One generic page serves every resource
89
+ * type through its descriptor; most cases run on a Docker host, and a
90
+ * table runs the page on each of the eight. Three cards at most: the
91
+ * agent's card in each of its states (connected, offline, unreachable, not
92
+ * installed — with the install instructions), "Needs attention" only when
93
+ * the server has gaps — as ONE item: a headline and a short step per gap —
94
+ * and "What AI may do" with its Change modal — whose
95
+ * loosening rules, allowlist checks and confirmations mirror the server's.
96
+ */
97
+
98
+ // Real components fetch; give the waits room on a loaded CI box.
99
+ const WAIT_TIMEOUT: number = 20000;
100
+
101
+ const RESOURCE_ID: string = "44444444-0000-4000-8000-000000000004";
102
+ const AGENT_ID: string = "99999999-0000-4000-8000-000000000009";
103
+
104
+ const DOCKER: ResourceAiAgentDescriptor = getResourceAiAgentDescriptor(
105
+ AiResourceType.DockerHost,
106
+ );
107
+
108
+ const STATUS_ROUTE: string = "/resource-ai-access/status";
109
+ const TEST_ROUTE: string = "/resource-ai-access/test";
110
+ const RESET_ROUTE: string = "/resource-ai-access/reset-agent";
111
+
112
+ const SETTINGS_CARD_TITLE: string = "What AI may do";
113
+ const GAPS_CARD_TITLE: string = "Needs attention";
114
+
115
+ const BASE_PERMISSIONS: Array<Permission> = [
116
+ Permission.Public,
117
+ Permission.User,
118
+ Permission.CurrentUser,
119
+ ];
120
+
121
+ // May edit the resource, but not loosen AI access.
122
+ const MEMBER_PERMISSIONS: Array<Permission> = [
123
+ ...BASE_PERMISSIONS,
124
+ Permission.ProjectMember,
125
+ ];
126
+
127
+ // May loosen AI access, reset the agent and change project AI settings.
128
+ const ADMIN_PERMISSIONS: Array<Permission> = [
129
+ ...BASE_PERMISSIONS,
130
+ Permission.ProjectAdmin,
131
+ ];
132
+
133
+ const READER_PERMISSIONS: Array<Permission> = [
134
+ ...BASE_PERMISSIONS,
135
+ Permission.ReadDockerHost,
136
+ ];
137
+
138
+ function minutesAgo(minutes: number): string {
139
+ return new Date(Date.now() - minutes * 60 * 1000).toISOString();
140
+ }
141
+
142
+ function makePosture(
143
+ overrides: Partial<ResourceAiAgentPosture> = {},
144
+ ): ResourceAiAgentPosture {
145
+ return {
146
+ resourceType: AiResourceType.DockerHost,
147
+ resourceIdentifier: "prod-docker-01",
148
+ agentVersion: "14.1.0",
149
+ allowWrites: false,
150
+ writeTargets: [],
151
+ protectedTargets: [],
152
+ toolVersion: "27.3.1",
153
+ reachable: true,
154
+ details: {},
155
+ ...overrides,
156
+ };
157
+ }
158
+
159
+ function makeAgent(
160
+ overrides: Partial<ResourceAiAgentSummary> = {},
161
+ ): ResourceAiAgentSummary {
162
+ return {
163
+ agentId: AGENT_ID,
164
+ connectionStatus: "connected",
165
+ isOnline: true,
166
+ agentVersion: "14.1.0",
167
+ lastAliveAt: new Date().toISOString(),
168
+ lastRegisteredAt: minutesAgo(60),
169
+ posture: makePosture(),
170
+ ...overrides,
171
+ };
172
+ }
173
+
174
+ function gap(code: ResourceAiAccessGapCode): ResourceAiAccessGap {
175
+ return {
176
+ code,
177
+ title: `Title of ${code}`,
178
+ nextStep: `Next step for ${code}`,
179
+ blocksInvestigation: true,
180
+ blocksRemediation: true,
181
+ };
182
+ }
183
+
184
+ // A gap with the flags the server gives it, for the headline's sake.
185
+ function flaggedGap(
186
+ code: ResourceAiAccessGapCode,
187
+ blocksInvestigation: boolean,
188
+ blocksRemediation: boolean,
189
+ ): ResourceAiAccessGap {
190
+ return { ...gap(code), blocksInvestigation, blocksRemediation };
191
+ }
192
+
193
+ function makeStatus(
194
+ overrides: Partial<ResourceAiAccessStatus> = {},
195
+ ): ResourceAiAccessStatus {
196
+ return {
197
+ resourceType: AiResourceType.DockerHost,
198
+ resourceId: RESOURCE_ID,
199
+ resourceName: "prod-docker-01",
200
+ isAiInvestigationEnabled: true,
201
+ aiRemediationMode: ResourceAiRemediationMode.Disabled,
202
+ aiCommandAllowlist: [],
203
+ agent: makeAgent(),
204
+ gaps: [gap("remediation_disabled")],
205
+ isInvestigationReady: true,
206
+ isRemediationReady: false,
207
+ ...overrides,
208
+ };
209
+ }
210
+
211
+ function notInstalledStatus(): ResourceAiAccessStatus {
212
+ return makeStatus({
213
+ agent: null,
214
+ isInvestigationReady: false,
215
+ gaps: [gap("ai_agent_not_connected")],
216
+ });
217
+ }
218
+
219
+ function statusResponse(
220
+ status: ResourceAiAccessStatus,
221
+ ): HTTPResponse<JSONObject> {
222
+ return new HTTPResponse<JSONObject>(200, status as unknown as JSONObject, {});
223
+ }
224
+
225
+ let postSpy: ReturnType<typeof jest.spyOn>;
226
+ let getItemSpy: ReturnType<typeof jest.spyOn>;
227
+ let updateByIdSpy: ReturnType<typeof jest.spyOn>;
228
+ let savedModel: JSONObject = {};
229
+
230
+ type RouteAnswer = () => Promise<HTTPResponse<JSONObject> | HTTPErrorResponse>;
231
+
232
+ /*
233
+ * Answers the status route with `status`, and the test and reset routes
234
+ * with their handlers (a plain 200 by default).
235
+ */
236
+ function serve(
237
+ status: ResourceAiAccessStatus,
238
+ handlers: { test?: RouteAnswer; reset?: RouteAnswer } = {},
239
+ ): void {
240
+ postSpy.mockImplementation(
241
+ async (
242
+ request: unknown,
243
+ ): Promise<HTTPResponse<JSONObject> | HTTPErrorResponse> => {
244
+ const url: string = String((request as JSONObject)["url"]);
245
+ if (url.endsWith(TEST_ROUTE) && handlers.test) {
246
+ return await handlers.test();
247
+ }
248
+ if (url.endsWith(RESET_ROUTE)) {
249
+ return handlers.reset
250
+ ? await handlers.reset()
251
+ : new HTTPResponse<JSONObject>(200, { ok: true }, {});
252
+ }
253
+ return statusResponse(status);
254
+ },
255
+ );
256
+ }
257
+
258
+ async function failStatusRequest(): Promise<HTTPResponse<JSONObject>> {
259
+ throw new Error("Network Error");
260
+ }
261
+
262
+ // The resource row the modal (and the install instructions) read.
263
+ function serveModel(overrides: JSONObject = {}): void {
264
+ savedModel = {
265
+ _id: RESOURCE_ID,
266
+ hostIdentifier: "prod-docker-01",
267
+ name: "prod-docker-01",
268
+ isAiInvestigationEnabled: true,
269
+ aiRemediationMode: ResourceAiRemediationMode.RequireApproval,
270
+ aiCommandAllowlist: [],
271
+ ...overrides,
272
+ };
273
+ }
274
+
275
+ function postsTo(route: string): Array<JSONObject> {
276
+ return postSpy.mock.calls
277
+ .map((call: Array<unknown>): JSONObject => {
278
+ return (call[0] || {}) as JSONObject;
279
+ })
280
+ .filter((request: JSONObject): boolean => {
281
+ return String(request["url"]).endsWith(route);
282
+ });
283
+ }
284
+
285
+ function updateRequests(): Array<JSONObject> {
286
+ return updateByIdSpy.mock.calls.map((call: Array<unknown>): JSONObject => {
287
+ return (call[0] || {}) as JSONObject;
288
+ });
289
+ }
290
+
291
+ function grant(permissions: Array<Permission>): void {
292
+ jest.spyOn(User, "isMasterAdmin").mockReturnValue(false);
293
+ jest.spyOn(PermissionUtil, "getAllPermissions").mockReturnValue(permissions);
294
+ jest.spyOn(PermissionUtil, "getGlobalPermissions").mockReturnValue(null);
295
+ jest.spyOn(PermissionUtil, "getProjectPermissions").mockReturnValue({
296
+ projectId: new ObjectID(PROJECT_ID),
297
+ userId: ObjectID.generate(),
298
+ permissions: permissions.map((permission: Permission) => {
299
+ return {
300
+ permission: permission,
301
+ labelIds: [],
302
+ _type: "UserPermission",
303
+ };
304
+ }),
305
+ _type: "UserTenantAccessPermission",
306
+ } as unknown as ReturnType<typeof PermissionUtil.getProjectPermissions>);
307
+ }
308
+
309
+ function pagePath(descriptor: ResourceAiAgentDescriptor): string {
310
+ return RouteMap[descriptor.agentPage]!.toString()
311
+ .replace(":projectId", PROJECT_ID)
312
+ .replace(":id", RESOURCE_ID);
313
+ }
314
+
315
+ function openAgentPage(descriptor: ResourceAiAgentDescriptor = DOCKER): void {
316
+ const path: string = pagePath(descriptor);
317
+ goTo(path);
318
+
319
+ render(
320
+ <MemoryRouter initialEntries={[path]}>
321
+ <Routes>
322
+ <PageRoute
323
+ path={String(RouteMap[descriptor.agentPage])}
324
+ element={
325
+ <ResourceAiAgentPage
326
+ descriptor={descriptor}
327
+ pageRoute={RouteMap[descriptor.agentPage] as Route}
328
+ currentProject={Object.assign(new Project(), { name: "Acme" })}
329
+ hasPaymentMethod={true}
330
+ />
331
+ }
332
+ />
333
+ </Routes>
334
+ </MemoryRouter>,
335
+ );
336
+ }
337
+
338
+ async function findText(text: string | RegExp): Promise<HTMLElement> {
339
+ return await screen.findByText(text, {}, { timeout: WAIT_TIMEOUT });
340
+ }
341
+
342
+ async function findTestId(testId: string): Promise<HTMLElement> {
343
+ return await screen.findByTestId(testId, {}, { timeout: WAIT_TIMEOUT });
344
+ }
345
+
346
+ // The command a CodeBlock inside the element shows, exactly.
347
+ function codeIn(element: HTMLElement): string {
348
+ return element.querySelector("code")?.textContent || "";
349
+ }
350
+
351
+ async function openChangeModal(
352
+ descriptor: ResourceAiAgentDescriptor = DOCKER,
353
+ ): Promise<HTMLElement> {
354
+ fireEvent.click(await findTestId("ai-access-change-button"));
355
+ const dialog: HTMLElement = await screen.findByRole(
356
+ "dialog",
357
+ {},
358
+ { timeout: WAIT_TIMEOUT },
359
+ );
360
+ // The form is on screen once its first field label is.
361
+ await within(dialog).findByText(
362
+ descriptor.investigateTitle,
363
+ {},
364
+ { timeout: WAIT_TIMEOUT },
365
+ );
366
+ return dialog;
367
+ }
368
+
369
+ // The open react-select menu's options (not native <option>s).
370
+ function menuOptions(): Array<HTMLElement> {
371
+ return screen
372
+ .queryAllByRole("option")
373
+ .filter((option: HTMLElement): boolean => {
374
+ return option.tagName !== "OPTION";
375
+ });
376
+ }
377
+
378
+ async function openDropdown(
379
+ dialog: HTMLElement,
380
+ name: RegExp,
381
+ ): Promise<Array<string>> {
382
+ const combobox: HTMLElement = within(dialog).getByRole("combobox", {
383
+ name,
384
+ });
385
+ fireEvent.keyDown(combobox, { key: "ArrowDown", code: "ArrowDown" });
386
+ await waitFor(
387
+ () => {
388
+ expect(menuOptions().length).toBeGreaterThan(0);
389
+ },
390
+ { timeout: WAIT_TIMEOUT },
391
+ );
392
+ return menuOptions().map((option: HTMLElement): string => {
393
+ return option.textContent || "";
394
+ });
395
+ }
396
+
397
+ async function pickOption(
398
+ dialog: HTMLElement,
399
+ name: RegExp,
400
+ optionText: string,
401
+ ): Promise<void> {
402
+ await openDropdown(dialog, name);
403
+ const option: HTMLElement | undefined = menuOptions().find(
404
+ (candidate: HTMLElement): boolean => {
405
+ return candidate.textContent === optionText;
406
+ },
407
+ );
408
+ if (!option) {
409
+ throw new Error(`No option "${optionText}" in the ${name} dropdown.`);
410
+ }
411
+ fireEvent.click(option);
412
+ }
413
+
414
+ async function toggleSwitch(
415
+ dialog: HTMLElement,
416
+ testId: string,
417
+ from: boolean,
418
+ ): Promise<void> {
419
+ const toggle: HTMLElement = within(dialog).getByTestId(testId);
420
+ await waitFor(
421
+ () => {
422
+ expect(toggle).toHaveAttribute("aria-checked", String(from));
423
+ },
424
+ { timeout: WAIT_TIMEOUT },
425
+ );
426
+ fireEvent.click(toggle);
427
+ expect(toggle).toHaveAttribute("aria-checked", String(!from));
428
+ }
429
+
430
+ async function setAllowlistText(
431
+ dialog: HTMLElement,
432
+ value: string,
433
+ ): Promise<void> {
434
+ const field: HTMLElement = await within(dialog).findByTestId(
435
+ "ai-command-allowlist-field",
436
+ {},
437
+ { timeout: WAIT_TIMEOUT },
438
+ );
439
+ fireEvent.change(field, { target: { value } });
440
+ }
441
+
442
+ async function waitForOneUpdate(): Promise<JSONObject> {
443
+ await waitFor(
444
+ () => {
445
+ expect(updateByIdSpy).toHaveBeenCalledTimes(1);
446
+ },
447
+ { timeout: WAIT_TIMEOUT },
448
+ );
449
+ return updateRequests()[0]!["data"] as JSONObject;
450
+ }
451
+
452
+ function saveChangeModal(dialog: HTMLElement): void {
453
+ fireEvent.click(within(dialog).getByTestId("modal-footer-submit-button"));
454
+ }
455
+
456
+ async function findDialogTitled(title: string): Promise<HTMLElement> {
457
+ const heading: HTMLElement = await findText(title);
458
+ const dialog: HTMLElement | null = heading.closest('[role="dialog"]');
459
+ if (!dialog) {
460
+ throw new Error(`"${title}" is not inside a dialog.`);
461
+ }
462
+ return dialog;
463
+ }
464
+
465
+ beforeEach(() => {
466
+ window.localStorage.clear();
467
+ window.sessionStorage.clear();
468
+ grant(MEMBER_PERMISSIONS);
469
+
470
+ postSpy = jest.spyOn(API, "post");
471
+ serve(makeStatus());
472
+
473
+ serveModel();
474
+ getItemSpy = jest.spyOn(ModelAPI, "getItem");
475
+ getItemSpy.mockImplementation(async (): Promise<unknown> => {
476
+ return Object.assign(new DockerHost(), savedModel);
477
+ });
478
+
479
+ updateByIdSpy = jest.spyOn(ModelAPI, "updateById");
480
+ updateByIdSpy.mockImplementation(
481
+ async (): Promise<HTTPResponse<JSONObject>> => {
482
+ return new HTTPResponse<JSONObject>(200, {}, {});
483
+ },
484
+ );
485
+ jest.spyOn(ModelAPI, "getCommonHeaders").mockReturnValue({});
486
+ });
487
+
488
+ afterEach(() => {
489
+ cleanup();
490
+ jest.useRealTimers();
491
+ jest.restoreAllMocks();
492
+ });
493
+
494
+ describe("the agent card", () => {
495
+ test("a connected agent: pill, sentence, meta line and the ready line", async () => {
496
+ openAgentPage();
497
+
498
+ expect(await findText("Docker AI agent")).toBeInTheDocument();
499
+ expect(await findTestId("ai-agent-status")).toHaveTextContent("Connected");
500
+ expect(screen.getByTestId("ai-agent-sentence")).toHaveTextContent(
501
+ "The Docker AI agent is running next to this Docker host.",
502
+ );
503
+ expect(screen.getByTestId("ai-agent-meta")).toHaveTextContent(
504
+ "agent v14.1.0 · Docker 27.3.1 · Read-only",
505
+ );
506
+ expect(screen.getByTestId("ai-agent-meta")).toHaveTextContent(
507
+ /^last seen /,
508
+ );
509
+ expect(screen.getByTestId("ai-agent-ready")).toHaveTextContent(
510
+ getResourceAiAgentReadyText(DOCKER),
511
+ );
512
+ expect(screen.queryByTestId("ai-agent-install")).not.toBeInTheDocument();
513
+ expect(
514
+ screen.queryByTestId("ai-agent-logs-command"),
515
+ ).not.toBeInTheDocument();
516
+ });
517
+
518
+ test("not installed: the service to add, pinned to this host's name, and nothing to test", async () => {
519
+ serve(notInstalledStatus());
520
+ openAgentPage();
521
+
522
+ expect(await findTestId("ai-agent-status")).toHaveTextContent(
523
+ "Not installed",
524
+ );
525
+ expect(screen.getByTestId("ai-agent-sentence")).toHaveTextContent(
526
+ getResourceAiAgentNotInstalledText(DOCKER),
527
+ );
528
+
529
+ // The name the collector reports, read from the host's row.
530
+ await waitFor(
531
+ () => {
532
+ expect(codeIn(screen.getByTestId("ai-agent-install-command"))).toBe(
533
+ getResourceAiAgentComposeSnippet({
534
+ resourceType: AiResourceType.DockerHost,
535
+ resourceId: RESOURCE_ID,
536
+ identity: "prod-docker-01",
537
+ }),
538
+ );
539
+ },
540
+ { timeout: WAIT_TIMEOUT },
541
+ );
542
+ const identityRequest: JSONObject = getItemSpy.mock
543
+ .calls[0]![0] as JSONObject;
544
+ expect(identityRequest["modelType"]).toBe(DockerHost);
545
+ expect(String(identityRequest["id"])).toBe(RESOURCE_ID);
546
+ expect(identityRequest["select"]).toEqual({
547
+ _id: true,
548
+ hostIdentifier: true,
549
+ });
550
+
551
+ // No installer creates a Docker agent directory: never `cd` into one.
552
+ expect(codeIn(screen.getByTestId("ai-agent-install-start"))).toBe(
553
+ "# In the directory of your docker-compose.yml:\ndocker compose up -d oneuptime-docker-ai-agent",
554
+ );
555
+ // install.sh, the usual way, comes first.
556
+ expect(screen.getByTestId("ai-agent-install-where")).toHaveTextContent(
557
+ /^Installed the Docker agent with install\.sh\? Run it again/,
558
+ );
559
+ expect(
560
+ screen.getByTestId("ai-agent-install-variable-DOCKER_HOST_NAME"),
561
+ ).toHaveTextContent("prod-docker-01");
562
+ expect(
563
+ screen.getByTestId("ai-agent-install-variable-ONEUPTIME_AI_ALLOW_WRITES"),
564
+ ).toHaveTextContent("false");
565
+ expect(
566
+ screen.getByTestId("ai-agent-install-prerequisites"),
567
+ ).toHaveTextContent("docker run");
568
+ expect(
569
+ screen.queryByTestId("ai-agent-test-button"),
570
+ ).not.toBeInTheDocument();
571
+ expect(screen.queryByTestId("ai-agent-ready")).not.toBeInTheDocument();
572
+ expect(screen.queryByTestId("ai-agent-meta")).not.toBeInTheDocument();
573
+ });
574
+
575
+ test("not installed, and the host's name cannot be read: the collector's own variable", async () => {
576
+ serve(notInstalledStatus());
577
+ getItemSpy.mockImplementation(async (): Promise<never> => {
578
+ throw new Error("no access");
579
+ });
580
+ openAgentPage();
581
+
582
+ expect(codeIn(await findTestId("ai-agent-install-command"))).toContain(
583
+ "DOCKER_HOST_NAME=${DOCKER_HOST_NAME:-docker-host}",
584
+ );
585
+ expect(
586
+ screen.getByTestId("ai-agent-install-variable-DOCKER_HOST_NAME"),
587
+ ).toHaveTextContent("from .env");
588
+ });
589
+
590
+ test("offline: the logs command for the agent's container", async () => {
591
+ serve(
592
+ makeStatus({
593
+ agent: makeAgent({ isOnline: false, lastAliveAt: minutesAgo(12) }),
594
+ }),
595
+ );
596
+ openAgentPage();
597
+
598
+ expect(await findTestId("ai-agent-status")).toHaveTextContent("Offline");
599
+ expect(screen.getByTestId("ai-agent-sentence")).toHaveTextContent(
600
+ getResourceAiAgentSilentText(DOCKER),
601
+ );
602
+ expect(codeIn(screen.getByTestId("ai-agent-logs-command"))).toBe(
603
+ getResourceAiAgentLogsCommand(AiResourceType.DockerHost),
604
+ );
605
+ expect(codeIn(screen.getByTestId("ai-agent-logs-command"))).toBe(
606
+ "docker logs --tail 100 oneuptime-docker-ai-agent",
607
+ );
608
+ });
609
+
610
+ test("offline right after a sign-off: says it reconnects", async () => {
611
+ serve(
612
+ makeStatus({
613
+ agent: makeAgent({
614
+ isOnline: false,
615
+ connectionStatus: "disconnected",
616
+ lastAliveAt: new Date().toISOString(),
617
+ }),
618
+ }),
619
+ );
620
+ openAgentPage();
621
+
622
+ expect(await findTestId("ai-agent-sentence")).toHaveTextContent(
623
+ getResourceAiAgentSignedOffText(DOCKER),
624
+ );
625
+ expect(screen.getByTestId("ai-agent-sentence")).not.toHaveTextContent(
626
+ "has not checked in",
627
+ );
628
+ });
629
+
630
+ test("online but unable to reach the host: why, the logs, and a test from the gap", async () => {
631
+ serve(
632
+ makeStatus({
633
+ agent: makeAgent({
634
+ posture: makePosture({
635
+ reachable: false,
636
+ reachError: "Cannot connect to the Docker daemon",
637
+ }),
638
+ }),
639
+ isInvestigationReady: false,
640
+ gaps: [gap("ai_agent_unreachable_resource")],
641
+ }),
642
+ {
643
+ test: async (): Promise<HTTPResponse<JSONObject>> => {
644
+ return new HTTPResponse<JSONObject>(
645
+ 200,
646
+ { ok: true, message: "It works.", results: [] },
647
+ {},
648
+ );
649
+ },
650
+ },
651
+ );
652
+ grant(ADMIN_PERMISSIONS);
653
+ openAgentPage();
654
+
655
+ expect(await findTestId("ai-agent-status")).toHaveTextContent("Connected");
656
+ expect(screen.getByTestId("ai-agent-sentence")).toHaveTextContent(
657
+ "could not reach this Docker host at its last check: Cannot connect to the Docker daemon",
658
+ );
659
+ expect(screen.getByTestId("ai-agent-logs-command")).toBeInTheDocument();
660
+
661
+ const row: HTMLElement = await findTestId(
662
+ "ai-agent-gap-ai_agent_unreachable_resource",
663
+ );
664
+ expect(row).toHaveTextContent(
665
+ "Let the Docker AI agent reach this Docker host (its error and the logs command are above), then test the connection.",
666
+ );
667
+ fireEvent.click(within(row).getByTestId("ai-agent-gap-test-connection"));
668
+ expect(await findText("The connection works")).toBeInTheDocument();
669
+ });
670
+
671
+ test("warns when another agent tried to register for the host", async () => {
672
+ serve(
673
+ makeStatus({
674
+ agent: makeAgent({
675
+ lastRefusedRegistrationAt: new Date().toISOString(),
676
+ lastRefusedRegistrationReason: "previous_instance_online",
677
+ }),
678
+ }),
679
+ );
680
+ openAgentPage();
681
+
682
+ const warning: HTMLElement = await findTestId(
683
+ "ai-agent-refused-registration",
684
+ );
685
+ expect(warning).toHaveTextContent(
686
+ "Another agent tried to register for this Docker host at",
687
+ );
688
+ expect(warning).toHaveTextContent("DOCKER_HOST_NAME");
689
+ });
690
+
691
+ test("shows the last command error the server recorded", async () => {
692
+ serve(
693
+ makeStatus({
694
+ aiAccessLastError: "docker: permission denied",
695
+ aiAccessLastVerifiedAt: minutesAgo(90),
696
+ }),
697
+ );
698
+ openAgentPage();
699
+
700
+ const line: HTMLElement = await findTestId("ai-agent-last-error");
701
+ expect(line).toHaveTextContent("Last command error (last worked");
702
+ expect(line).toHaveTextContent("docker: permission denied");
703
+ });
704
+ });
705
+
706
+ describe("the page heading", () => {
707
+ test("names the page and the resource", async () => {
708
+ openAgentPage();
709
+
710
+ const heading: HTMLElement = await screen.findByRole(
711
+ "heading",
712
+ { level: 2, name: "AI agent" },
713
+ { timeout: WAIT_TIMEOUT },
714
+ );
715
+ expect(heading).toBeInTheDocument();
716
+ expect(screen.getByTestId("ai-agent-page-heading")).toHaveTextContent(
717
+ getResourceAiAgentPageSubtitle(DOCKER),
718
+ );
719
+ });
720
+
721
+ test("is shown while the status loads, and above the error when it fails", async () => {
722
+ let answer: (value: HTTPResponse<JSONObject>) => void = () => {
723
+ return undefined;
724
+ };
725
+ postSpy.mockImplementation((): Promise<HTTPResponse<JSONObject>> => {
726
+ return new Promise<HTTPResponse<JSONObject>>(
727
+ (resolve: (value: HTTPResponse<JSONObject>) => void) => {
728
+ answer = resolve;
729
+ },
730
+ );
731
+ });
732
+ openAgentPage();
733
+
734
+ expect(screen.getByTestId("ai-agent-page-heading")).toHaveTextContent(
735
+ "AI agent",
736
+ );
737
+ expect(screen.queryByText("Docker AI agent")).not.toBeInTheDocument();
738
+
739
+ await act(async () => {
740
+ answer(statusResponse(makeStatus()));
741
+ });
742
+ expect(await findText("Docker AI agent")).toBeInTheDocument();
743
+ cleanup();
744
+
745
+ postSpy.mockImplementation(failStatusRequest);
746
+ openAgentPage();
747
+ expect(await findText("Network Error")).toBeInTheDocument();
748
+ expect(screen.getByTestId("ai-agent-page-heading")).toBeInTheDocument();
749
+ expect(screen.queryByText("Docker AI agent")).not.toBeInTheDocument();
750
+ });
751
+ });
752
+
753
+ describe("status polling", () => {
754
+ test("asks about this resource once on load, by type and id", async () => {
755
+ openAgentPage();
756
+
757
+ expect(await findText(SETTINGS_CARD_TITLE)).toBeInTheDocument();
758
+ expect(postsTo(STATUS_ROUTE)).toHaveLength(1);
759
+ expect(postsTo(STATUS_ROUTE)[0]!["data"]).toEqual({
760
+ resourceType: AiResourceType.DockerHost,
761
+ resourceId: RESOURCE_ID,
762
+ });
763
+ });
764
+
765
+ test("keeps the last good status and warns inline when a background poll fails", async () => {
766
+ jest.useFakeTimers();
767
+ postSpy
768
+ .mockResolvedValueOnce(statusResponse(makeStatus()))
769
+ .mockImplementationOnce(failStatusRequest)
770
+ .mockResolvedValue(statusResponse(makeStatus()));
771
+
772
+ openAgentPage();
773
+ expect(await findText("Docker AI agent")).toBeInTheDocument();
774
+
775
+ await act(async () => {
776
+ jest.advanceTimersByTime(RESOURCE_AI_AGENT_STATUS_POLL_INTERVAL_MS);
777
+ });
778
+
779
+ const warning: HTMLElement = await findTestId("ai-access-refresh-warning");
780
+ expect(warning).toHaveTextContent("Could not refresh the AI agent status");
781
+ expect(warning).toHaveTextContent("Network Error");
782
+ expect(screen.getByTestId("ai-agent-status")).toHaveTextContent(
783
+ "Connected",
784
+ );
785
+
786
+ await act(async () => {
787
+ jest.advanceTimersByTime(RESOURCE_AI_AGENT_STATUS_POLL_INTERVAL_MS);
788
+ });
789
+
790
+ await waitFor(
791
+ () => {
792
+ expect(
793
+ screen.queryByTestId("ai-access-refresh-warning"),
794
+ ).not.toBeInTheDocument();
795
+ },
796
+ { timeout: WAIT_TIMEOUT },
797
+ );
798
+ });
799
+
800
+ test("picks up an agent that connects while the page is open", async () => {
801
+ jest.useFakeTimers();
802
+ postSpy
803
+ .mockResolvedValueOnce(statusResponse(notInstalledStatus()))
804
+ .mockResolvedValue(statusResponse(makeStatus()));
805
+
806
+ openAgentPage();
807
+ expect(await findTestId("ai-agent-status")).toHaveTextContent(
808
+ "Not installed",
809
+ );
810
+
811
+ await act(async () => {
812
+ jest.advanceTimersByTime(RESOURCE_AI_AGENT_STATUS_POLL_INTERVAL_MS);
813
+ });
814
+
815
+ await waitFor(
816
+ () => {
817
+ expect(screen.getByTestId("ai-agent-status")).toHaveTextContent(
818
+ "Connected",
819
+ );
820
+ },
821
+ { timeout: WAIT_TIMEOUT },
822
+ );
823
+ expect(screen.queryByTestId("ai-agent-install")).not.toBeInTheDocument();
824
+ });
825
+
826
+ test("keeps the page when a poll returns a status it cannot read", async () => {
827
+ jest.useFakeTimers();
828
+ postSpy
829
+ .mockResolvedValueOnce(statusResponse(makeStatus()))
830
+ .mockResolvedValue(
831
+ new HTTPResponse<JSONObject>(200, { unexpected: true }, {}),
832
+ );
833
+
834
+ openAgentPage();
835
+ expect(await findText("Docker AI agent")).toBeInTheDocument();
836
+
837
+ await act(async () => {
838
+ jest.advanceTimersByTime(RESOURCE_AI_AGENT_STATUS_POLL_INTERVAL_MS);
839
+ });
840
+
841
+ expect(await findTestId("ai-access-refresh-warning")).toHaveTextContent(
842
+ "cannot read",
843
+ );
844
+ expect(screen.getByText("Docker AI agent")).toBeInTheDocument();
845
+ });
846
+ });
847
+
848
+ describe("Needs attention", () => {
849
+ test("is not shown when the only gap is the fixes-off choice", async () => {
850
+ openAgentPage();
851
+
852
+ expect(await findText(SETTINGS_CARD_TITLE)).toBeInTheDocument();
853
+ expect(screen.queryByText(GAPS_CARD_TITLE)).not.toBeInTheDocument();
854
+ });
855
+
856
+ test("merges every server gap into one item: a headline, then a numbered step each", async () => {
857
+ serve(
858
+ makeStatus({
859
+ isInvestigationReady: false,
860
+ gaps: [
861
+ gap("ai_balance_insufficient"),
862
+ gap("remediation_disabled"),
863
+ gap("llm_provider_missing"),
864
+ ],
865
+ }),
866
+ );
867
+ openAgentPage();
868
+
869
+ const item: HTMLElement = await findTestId("ai-agent-attention");
870
+ expect(screen.getAllByTestId("ai-agent-attention")).toHaveLength(1);
871
+ expect(screen.getByText(GAPS_CARD_TITLE)).toBeInTheDocument();
872
+ expect(
873
+ within(item).getByTestId("ai-agent-attention-title"),
874
+ ).toHaveTextContent("OneUptime AI can't investigate this Docker host");
875
+
876
+ // The fixes-off choice is not a step.
877
+ const steps: Array<HTMLElement> = within(
878
+ within(item).getByTestId("ai-agent-gaps"),
879
+ ).getAllByRole("listitem");
880
+ expect(steps).toHaveLength(2);
881
+ expect(steps[0]).toHaveAttribute(
882
+ "data-testid",
883
+ "ai-agent-gap-ai_balance_insufficient",
884
+ );
885
+ expect(
886
+ within(steps[0]!).getByTestId("ai-agent-gap-number"),
887
+ ).toHaveTextContent("1.");
888
+ expect(steps[0]).toHaveTextContent(
889
+ "Add AI credits to this project, or turn on auto-recharge.",
890
+ );
891
+ expect(steps[1]).toHaveAttribute(
892
+ "data-testid",
893
+ "ai-agent-gap-llm_provider_missing",
894
+ );
895
+ expect(
896
+ within(steps[1]!).getByTestId("ai-agent-gap-number"),
897
+ ).toHaveTextContent("2.");
898
+ expect(steps[1]).toHaveTextContent(
899
+ "Add an AI provider for this project, or use OneUptime AI credits.",
900
+ );
901
+
902
+ // Not a row per gap with the server's title and next step any more.
903
+ expect(item).not.toHaveTextContent("Title of");
904
+ expect(item).not.toHaveTextContent("Next step for");
905
+ expect(screen.queryByText(/Each item stops/)).not.toBeInTheDocument();
906
+ expect(screen.queryByTestId("ai-agent-ready")).not.toBeInTheDocument();
907
+ });
908
+
909
+ test("a new database server: what is wrong in one line, and the two steps that fix it", async () => {
910
+ const database: ResourceAiAgentDescriptor = getResourceAiAgentDescriptor(
911
+ AiResourceType.DatabaseServer,
912
+ );
913
+ serve(
914
+ makeStatus({
915
+ resourceType: AiResourceType.DatabaseServer,
916
+ resourceName: "orders-db",
917
+ agent: null,
918
+ isAiInvestigationEnabled: false,
919
+ isInvestigationReady: false,
920
+ // The server's own words, as the screenshot showed them.
921
+ gaps: [
922
+ {
923
+ code: "ai_agent_not_connected",
924
+ title: "No Database AI agent is connected",
925
+ nextStep: `Install the Database AI agent next to this database server's telemetry collector: run the oneuptime/resource-ai-agent image with ONEUPTIME_AI_AGENT_RESOURCE_TYPE=database and DATABASE_SERVER_ID=${RESOURCE_ID}. The complete snippet is on the database server's AI agent page (AI → AI agent).`,
926
+ blocksInvestigation: true,
927
+ blocksRemediation: true,
928
+ },
929
+ {
930
+ code: "investigation_disabled",
931
+ title: "AI investigation is turned off for this database server",
932
+ nextStep:
933
+ "Turn on AI investigation on the database server's AI agent page (AI → AI agent).",
934
+ blocksInvestigation: true,
935
+ blocksRemediation: false,
936
+ },
937
+ {
938
+ code: "remediation_disabled",
939
+ title: "AI fixes are turned off for this database server",
940
+ nextStep:
941
+ 'Set "Fixes" to "Ask for approval", "Automatic" or "Bypass approval" on the database server\'s AI agent page (AI → AI agent).',
942
+ blocksInvestigation: false,
943
+ blocksRemediation: true,
944
+ },
945
+ ],
946
+ }),
947
+ );
948
+ openAgentPage(database);
949
+
950
+ const item: HTMLElement = await findTestId("ai-agent-attention");
951
+ expect(
952
+ within(item).getByTestId("ai-agent-attention-title"),
953
+ ).toHaveTextContent("OneUptime AI can't investigate this database server");
954
+ const steps: Array<HTMLElement> = within(item).getAllByRole("listitem");
955
+ expect(steps).toHaveLength(2);
956
+ expect(steps[0]).toHaveTextContent(
957
+ "Install the Database AI agent with the instructions above.",
958
+ );
959
+ expect(within(steps[0]!).queryByRole("button")).not.toBeInTheDocument();
960
+ expect(steps[1]).toHaveTextContent("Turn on AI investigation.");
961
+
962
+ // Nothing sends the reader to the page they are on, or repeats the snippet.
963
+ expect(item).not.toHaveTextContent("AI → AI agent");
964
+ expect(item).not.toHaveTextContent("oneuptime/resource-ai-agent");
965
+ expect(item).not.toHaveTextContent(RESOURCE_ID);
966
+
967
+ // The instructions it points at are on the page, above it.
968
+ const install: HTMLElement = screen.getByTestId("ai-agent-install");
969
+ expect(
970
+ install.compareDocumentPosition(item) & Node.DOCUMENT_POSITION_FOLLOWING,
971
+ ).toBeTruthy();
972
+
973
+ fireEvent.click(
974
+ within(steps[1]!).getByTestId("ai-agent-gap-turn-on-investigation"),
975
+ );
976
+ expect(await waitForOneUpdate()).toEqual({
977
+ isAiInvestigationEnabled: true,
978
+ });
979
+ expect(updateRequests()[0]!["modelType"]).toBe(DatabaseServer);
980
+ expect(await findTestId("ai-agent-action-notice")).toHaveTextContent(
981
+ `AI may now investigate this database server with ${database.readOnlyCommandsPhrase}.`,
982
+ );
983
+ });
984
+
985
+ test("a single gap is a single sentence, without a number", async () => {
986
+ serve(
987
+ makeStatus({
988
+ isAiInvestigationEnabled: false,
989
+ isInvestigationReady: false,
990
+ gaps: [flaggedGap("investigation_disabled", true, false)],
991
+ }),
992
+ );
993
+ openAgentPage();
994
+
995
+ const item: HTMLElement = await findTestId("ai-agent-attention");
996
+ expect(within(item).getAllByRole("listitem")).toHaveLength(1);
997
+ expect(
998
+ within(item).queryByTestId("ai-agent-gap-number"),
999
+ ).not.toBeInTheDocument();
1000
+ expect(
1001
+ within(item).getByTestId("ai-agent-gap-investigation_disabled"),
1002
+ ).toHaveTextContent("Turn on AI investigation.");
1003
+ });
1004
+
1005
+ test("fixes on and nothing installed: the headline names both", async () => {
1006
+ serve(
1007
+ makeStatus({
1008
+ agent: null,
1009
+ aiRemediationMode: ResourceAiRemediationMode.RequireApproval,
1010
+ isInvestigationReady: false,
1011
+ gaps: [flaggedGap("ai_agent_not_connected", true, true)],
1012
+ }),
1013
+ );
1014
+ openAgentPage();
1015
+
1016
+ expect(await findTestId("ai-agent-attention-title")).toHaveTextContent(
1017
+ "OneUptime AI can't investigate this Docker host or run fixes on it",
1018
+ );
1019
+ expect(
1020
+ screen.getByTestId("ai-agent-gap-ai_agent_not_connected"),
1021
+ ).toHaveTextContent(
1022
+ "Install the Docker AI agent with the instructions above.",
1023
+ );
1024
+ });
1025
+
1026
+ test("fixes on with a read-only agent: only fixes are blocked, and the steps are below", async () => {
1027
+ serve(
1028
+ makeStatus({
1029
+ aiRemediationMode: ResourceAiRemediationMode.RequireApproval,
1030
+ gaps: [flaggedGap("remediation_write_access_missing", false, true)],
1031
+ }),
1032
+ );
1033
+ openAgentPage();
1034
+
1035
+ const item: HTMLElement = await findTestId("ai-agent-attention");
1036
+ expect(
1037
+ within(item).getByTestId("ai-agent-attention-title"),
1038
+ ).toHaveTextContent("OneUptime AI can't run fixes on this Docker host");
1039
+ expect(
1040
+ within(item).getByTestId("ai-agent-gap-remediation_write_access_missing"),
1041
+ ).toHaveTextContent(
1042
+ "Give the Docker AI agent write access with the steps below.",
1043
+ );
1044
+ // Investigation still works, so the agent card still says it is ready.
1045
+ expect(screen.getByTestId("ai-agent-ready")).toBeInTheDocument();
1046
+ const writeCommands: HTMLElement = screen.getByTestId(
1047
+ "ai-access-write-commands",
1048
+ );
1049
+ expect(
1050
+ item.compareDocumentPosition(writeCommands) &
1051
+ Node.DOCUMENT_POSITION_FOLLOWING,
1052
+ ).toBeTruthy();
1053
+ });
1054
+
1055
+ test("an offline agent: bring it back, with the logs command above", async () => {
1056
+ serve(
1057
+ makeStatus({
1058
+ agent: makeAgent({ isOnline: false, lastAliveAt: minutesAgo(30) }),
1059
+ isInvestigationReady: false,
1060
+ gaps: [flaggedGap("ai_agent_offline", true, true)],
1061
+ }),
1062
+ );
1063
+ openAgentPage();
1064
+
1065
+ const item: HTMLElement = await findTestId("ai-agent-attention");
1066
+ expect(
1067
+ within(item).getByTestId("ai-agent-attention-title"),
1068
+ ).toHaveTextContent("OneUptime AI can't investigate this Docker host");
1069
+ expect(item).toHaveTextContent(
1070
+ "Bring the Docker AI agent back online. Its logs say why it is offline (the command is above).",
1071
+ );
1072
+ expect(
1073
+ screen
1074
+ .getByTestId("ai-agent-logs-command")
1075
+ .compareDocumentPosition(item) & Node.DOCUMENT_POSITION_FOLLOWING,
1076
+ ).toBeTruthy();
1077
+ });
1078
+
1079
+ test("a member gets the button they may use and is told who to ask for the rest, in the same item", async () => {
1080
+ serve(
1081
+ makeStatus({
1082
+ isAiInvestigationEnabled: false,
1083
+ isInvestigationReady: false,
1084
+ gaps: [
1085
+ flaggedGap("investigation_disabled", true, false),
1086
+ flaggedGap("llm_provider_missing", true, true),
1087
+ ],
1088
+ }),
1089
+ );
1090
+ openAgentPage();
1091
+
1092
+ const item: HTMLElement = await findTestId("ai-agent-attention");
1093
+ const investigation: HTMLElement = within(item).getByTestId(
1094
+ "ai-agent-gap-investigation_disabled",
1095
+ );
1096
+ const provider: HTMLElement = within(item).getByTestId(
1097
+ "ai-agent-gap-llm_provider_missing",
1098
+ );
1099
+ expect(
1100
+ within(investigation).getByTestId("ai-agent-gap-turn-on-investigation"),
1101
+ ).toBeInTheDocument();
1102
+ expect(
1103
+ within(investigation).queryByTestId("ai-agent-gap-ask"),
1104
+ ).not.toBeInTheDocument();
1105
+ expect(within(provider).getByTestId("ai-agent-gap-ask")).toHaveTextContent(
1106
+ "Ask a project owner or admin.",
1107
+ );
1108
+ expect(
1109
+ within(provider).queryByText("Open LLM Providers"),
1110
+ ).not.toBeInTheDocument();
1111
+ expect(within(item).getAllByTestId("ai-agent-gap-ask")).toHaveLength(1);
1112
+ });
1113
+
1114
+ test("the item goes away once its last gap is fixed", async () => {
1115
+ serve(
1116
+ makeStatus({
1117
+ isAiInvestigationEnabled: false,
1118
+ isInvestigationReady: false,
1119
+ gaps: [flaggedGap("investigation_disabled", true, false)],
1120
+ }),
1121
+ );
1122
+ openAgentPage();
1123
+
1124
+ const button: HTMLElement = await findTestId(
1125
+ "ai-agent-gap-turn-on-investigation",
1126
+ );
1127
+ // What the server says once investigation is on.
1128
+ serve(makeStatus());
1129
+ fireEvent.click(button);
1130
+
1131
+ await waitFor(
1132
+ () => {
1133
+ expect(
1134
+ screen.queryByTestId("ai-agent-attention"),
1135
+ ).not.toBeInTheDocument();
1136
+ },
1137
+ { timeout: WAIT_TIMEOUT },
1138
+ );
1139
+ expect(screen.queryByText(GAPS_CARD_TITLE)).not.toBeInTheDocument();
1140
+ expect(await findTestId("ai-agent-ready")).toBeInTheDocument();
1141
+ });
1142
+
1143
+ test("an editor turns investigation on from its row", async () => {
1144
+ serve(
1145
+ makeStatus({
1146
+ isAiInvestigationEnabled: false,
1147
+ isInvestigationReady: false,
1148
+ gaps: [gap("investigation_disabled")],
1149
+ }),
1150
+ );
1151
+ openAgentPage();
1152
+
1153
+ fireEvent.click(await findTestId("ai-agent-gap-turn-on-investigation"));
1154
+
1155
+ expect(await waitForOneUpdate()).toEqual({
1156
+ isAiInvestigationEnabled: true,
1157
+ });
1158
+ expect(String(updateRequests()[0]!["id"])).toBe(RESOURCE_ID);
1159
+ expect(updateRequests()[0]!["modelType"]).toBe(DockerHost);
1160
+ expect(await findTestId("ai-agent-action-notice")).toHaveTextContent(
1161
+ "AI may now investigate this Docker host with read-only docker commands.",
1162
+ );
1163
+ await waitFor(
1164
+ () => {
1165
+ expect(postsTo(STATUS_ROUTE).length).toBeGreaterThanOrEqual(2);
1166
+ },
1167
+ { timeout: WAIT_TIMEOUT },
1168
+ );
1169
+ });
1170
+
1171
+ test("a failed one-click fix is shown on the page", async () => {
1172
+ serve(
1173
+ makeStatus({
1174
+ isAiInvestigationEnabled: false,
1175
+ isInvestigationReady: false,
1176
+ gaps: [gap("investigation_disabled")],
1177
+ }),
1178
+ );
1179
+ updateByIdSpy.mockImplementation(async (): Promise<never> => {
1180
+ throw new HTTPErrorResponse(422, { error: "Not allowed." }, {});
1181
+ });
1182
+ openAgentPage();
1183
+
1184
+ fireEvent.click(await findTestId("ai-agent-gap-turn-on-investigation"));
1185
+
1186
+ expect(await findTestId("ai-agent-action-error")).toHaveTextContent(
1187
+ "Not allowed.",
1188
+ );
1189
+ });
1190
+
1191
+ test("a reader is told who to ask instead of getting a button", async () => {
1192
+ grant(READER_PERMISSIONS);
1193
+ serve(
1194
+ makeStatus({
1195
+ isAiInvestigationEnabled: false,
1196
+ isInvestigationReady: false,
1197
+ gaps: [gap("investigation_disabled")],
1198
+ }),
1199
+ );
1200
+ openAgentPage();
1201
+
1202
+ const row: HTMLElement = await findTestId(
1203
+ "ai-agent-gap-investigation_disabled",
1204
+ );
1205
+ expect(within(row).getByTestId("ai-agent-gap-ask")).toHaveTextContent(
1206
+ "Ask a project owner or admin.",
1207
+ );
1208
+ expect(
1209
+ screen.queryByTestId("ai-agent-gap-turn-on-investigation"),
1210
+ ).not.toBeInTheDocument();
1211
+ });
1212
+
1213
+ test("project-level gaps link an admin to the page that fixes them", async () => {
1214
+ grant(ADMIN_PERMISSIONS);
1215
+ serve(
1216
+ makeStatus({
1217
+ isInvestigationReady: false,
1218
+ gaps: [
1219
+ gap("ai_disabled_for_project"),
1220
+ gap("llm_provider_missing"),
1221
+ gap("ai_balance_insufficient"),
1222
+ ],
1223
+ }),
1224
+ );
1225
+ openAgentPage();
1226
+
1227
+ const expected: Array<[string, string, string]> = [
1228
+ ["ai_disabled_for_project", "Open AI Features", "settings/ai-features"],
1229
+ ["llm_provider_missing", "Open LLM Providers", "settings/llm-providers"],
1230
+ ["ai_balance_insufficient", "Open AI Credits", "settings/ai-credits"],
1231
+ ];
1232
+ for (const [code, linkText, path] of expected) {
1233
+ const row: HTMLElement = await findTestId(`ai-agent-gap-${code}`);
1234
+ expect(
1235
+ within(row).getByText(linkText).closest("a")?.getAttribute("href"),
1236
+ ).toBe(`/dashboard/${PROJECT_ID}/${path}`);
1237
+ }
1238
+ });
1239
+
1240
+ test("project-level gaps tell a member who to ask", async () => {
1241
+ serve(
1242
+ makeStatus({
1243
+ isInvestigationReady: false,
1244
+ gaps: [gap("auto_remediation_disabled_for_project")],
1245
+ }),
1246
+ );
1247
+ openAgentPage();
1248
+
1249
+ const row: HTMLElement = await findTestId(
1250
+ "ai-agent-gap-auto_remediation_disabled_for_project",
1251
+ );
1252
+ expect(row).toHaveTextContent("Ask a project owner or admin.");
1253
+ expect(within(row).queryByText("Open AI Features")).not.toBeInTheDocument();
1254
+ });
1255
+
1256
+ test("the not-installed gap has no extra action: the instructions are on the card", async () => {
1257
+ serve(notInstalledStatus());
1258
+ openAgentPage();
1259
+
1260
+ const row: HTMLElement = await findTestId(
1261
+ "ai-agent-gap-ai_agent_not_connected",
1262
+ );
1263
+ expect(row).toHaveTextContent(
1264
+ "Install the Docker AI agent with the instructions above.",
1265
+ );
1266
+ expect(within(row).queryByRole("button")).not.toBeInTheDocument();
1267
+ expect(within(row).queryByRole("link")).not.toBeInTheDocument();
1268
+ });
1269
+ });
1270
+
1271
+ describe("What AI may do", () => {
1272
+ test("shows investigation and fixes in plain words, with the fixes-off hint", async () => {
1273
+ openAgentPage();
1274
+
1275
+ expect(await findTestId("ai-access-investigation-value")).toHaveTextContent(
1276
+ "Yes — read-only (ps, inspect, logs, stats, events)",
1277
+ );
1278
+ expect(screen.getByText(DOCKER.investigateTitle)).toBeInTheDocument();
1279
+ expect(screen.getByTestId("ai-access-fixes-value")).toHaveTextContent(
1280
+ `Off — ${RESOURCE_REMEDIATION_MODE_SUMMARIES[ResourceAiRemediationMode.Disabled]}`,
1281
+ );
1282
+ expect(screen.getByTestId("ai-access-fixes-off-hint")).toHaveTextContent(
1283
+ "Want AI to propose fixes? Choose Ask for approval.",
1284
+ );
1285
+ expect(
1286
+ screen.queryByTestId("ai-access-write-commands"),
1287
+ ).not.toBeInTheDocument();
1288
+ expect(
1289
+ screen.queryByTestId("ai-command-allowlist-in-effect"),
1290
+ ).not.toBeInTheDocument();
1291
+ });
1292
+
1293
+ test("investigation off says so", async () => {
1294
+ serve(
1295
+ makeStatus({
1296
+ isAiInvestigationEnabled: false,
1297
+ isInvestigationReady: false,
1298
+ }),
1299
+ );
1300
+ openAgentPage();
1301
+
1302
+ expect(await findTestId("ai-access-investigation-value")).toHaveTextContent(
1303
+ "No — AI investigates with OneUptime data only",
1304
+ );
1305
+ });
1306
+
1307
+ test("fixes on with a read-only agent: the write switch, scoped first, and the disclosure", async () => {
1308
+ serve(
1309
+ makeStatus({
1310
+ aiRemediationMode: ResourceAiRemediationMode.RequireApproval,
1311
+ gaps: [gap("remediation_write_access_missing")],
1312
+ }),
1313
+ );
1314
+ openAgentPage();
1315
+
1316
+ const section: HTMLElement = await findTestId("ai-access-write-commands");
1317
+ const commands: ReturnType<typeof getResourceAiAgentWriteAccessCommands> =
1318
+ getResourceAiAgentWriteAccessCommands(AiResourceType.DockerHost);
1319
+ expect(section).toHaveTextContent("Give the agent write access");
1320
+ expect(codeIn(screen.getByTestId("ai-access-write-scoped-env"))).toBe(
1321
+ commands.scopedEnv,
1322
+ );
1323
+ expect(codeIn(screen.getByTestId("ai-access-write-scoped-env"))).toBe(
1324
+ "ONEUPTIME_AI_ALLOW_WRITES=true\nONEUPTIME_AI_WRITE_TARGETS=web-*,api-*",
1325
+ );
1326
+ expect(codeIn(screen.getByTestId("ai-access-write-all-env"))).toBe(
1327
+ "ONEUPTIME_AI_ALLOW_WRITES=true",
1328
+ );
1329
+ expect(codeIn(screen.getByTestId("ai-access-write-restart-command"))).toBe(
1330
+ commands.restartCommand,
1331
+ );
1332
+ expect(
1333
+ codeIn(screen.getByTestId("ai-access-write-restart-command")),
1334
+ ).not.toContain("cd /opt/");
1335
+ const installerNote: HTMLElement = screen.getByTestId(
1336
+ "ai-access-write-installer-note",
1337
+ );
1338
+ const envIntro: HTMLElement = screen.getByTestId(
1339
+ "ai-access-write-env-intro",
1340
+ );
1341
+ expect(installerNote).toHaveTextContent(commands.installerNote!);
1342
+ expect(envIntro).toHaveTextContent(commands.envIntro);
1343
+ // install.sh, the usual way, before the Compose way.
1344
+ expect(
1345
+ installerNote.compareDocumentPosition(envIntro) &
1346
+ Node.DOCUMENT_POSITION_FOLLOWING,
1347
+ ).toBeTruthy();
1348
+ expect(
1349
+ installerNote.compareDocumentPosition(
1350
+ screen.getByTestId("ai-access-write-scoped-env"),
1351
+ ) & Node.DOCUMENT_POSITION_FOLLOWING,
1352
+ ).toBeTruthy();
1353
+ expect(screen.getByTestId("ai-access-write-disclosure")).toHaveTextContent(
1354
+ getResourceAiAgentWriteDisclosure(AiResourceType.DockerHost),
1355
+ );
1356
+ expect(
1357
+ screen.queryByTestId("ai-access-fixes-off-hint"),
1358
+ ).not.toBeInTheDocument();
1359
+ });
1360
+
1361
+ test("a database server has no targets to scope: just the switch", async () => {
1362
+ const database: ResourceAiAgentDescriptor = getResourceAiAgentDescriptor(
1363
+ AiResourceType.DatabaseServer,
1364
+ );
1365
+ serve(
1366
+ makeStatus({
1367
+ resourceType: AiResourceType.DatabaseServer,
1368
+ aiRemediationMode: ResourceAiRemediationMode.RequireApproval,
1369
+ agent: makeAgent({
1370
+ posture: makePosture({ resourceType: AiResourceType.DatabaseServer }),
1371
+ }),
1372
+ }),
1373
+ );
1374
+ openAgentPage(database);
1375
+
1376
+ await findTestId("ai-access-write-commands");
1377
+ expect(
1378
+ screen.queryByTestId("ai-access-write-scoped-env"),
1379
+ ).not.toBeInTheDocument();
1380
+ expect(codeIn(screen.getByTestId("ai-access-write-all-env"))).toBe(
1381
+ "ONEUPTIME_AI_ALLOW_WRITES=true",
1382
+ );
1383
+ expect(
1384
+ screen.queryByTestId("ai-access-write-installer-note"),
1385
+ ).not.toBeInTheDocument();
1386
+ });
1387
+
1388
+ test("an agent that already writes gets no instructions, and says where it may change", async () => {
1389
+ serve(
1390
+ makeStatus({
1391
+ aiRemediationMode: ResourceAiRemediationMode.RequireApproval,
1392
+ agent: makeAgent({
1393
+ posture: makePosture({
1394
+ allowWrites: true,
1395
+ writeTargets: ["web-*", "api"],
1396
+ }),
1397
+ }),
1398
+ }),
1399
+ );
1400
+ openAgentPage();
1401
+
1402
+ expect(await findTestId("ai-agent-meta")).toHaveTextContent(
1403
+ "Can change: web-*, api",
1404
+ );
1405
+ expect(
1406
+ screen.queryByTestId("ai-access-write-commands"),
1407
+ ).not.toBeInTheDocument();
1408
+ });
1409
+
1410
+ test("the allowlist in effect is listed in Automatic mode only", async () => {
1411
+ serve(
1412
+ makeStatus({
1413
+ aiRemediationMode: ResourceAiRemediationMode.Automatic,
1414
+ aiCommandAllowlist: ["docker stop web"],
1415
+ }),
1416
+ );
1417
+ openAgentPage();
1418
+
1419
+ expect(
1420
+ await findTestId("ai-command-allowlist-in-effect"),
1421
+ ).toHaveTextContent("docker stop web");
1422
+ cleanup();
1423
+
1424
+ serve(
1425
+ makeStatus({
1426
+ aiRemediationMode: ResourceAiRemediationMode.BypassApproval,
1427
+ aiCommandAllowlist: ["docker stop web"],
1428
+ }),
1429
+ );
1430
+ openAgentPage();
1431
+ expect(await findTestId("ai-access-fixes-value")).toHaveTextContent(
1432
+ "Bypass approval",
1433
+ );
1434
+ expect(
1435
+ screen.queryByTestId("ai-command-allowlist-in-effect"),
1436
+ ).not.toBeInTheDocument();
1437
+ });
1438
+
1439
+ test("an empty allowlist in Automatic mode reads None", async () => {
1440
+ serve(
1441
+ makeStatus({ aiRemediationMode: ResourceAiRemediationMode.Automatic }),
1442
+ );
1443
+ openAgentPage();
1444
+
1445
+ expect(
1446
+ await findTestId("ai-command-allowlist-in-effect"),
1447
+ ).toHaveTextContent("None");
1448
+ });
1449
+
1450
+ test("the Change button is locked, with the reason, for a reader", async () => {
1451
+ grant(READER_PERMISSIONS);
1452
+ openAgentPage();
1453
+
1454
+ const button: HTMLElement = await findTestId("ai-access-change-button");
1455
+ expect(button).toBeDisabled();
1456
+ fireEvent.click(button);
1457
+ expect(screen.queryByRole("dialog")).not.toBeInTheDocument();
1458
+ });
1459
+ });
1460
+
1461
+ describe("the Change modal: who may loosen", () => {
1462
+ test("reads the saved settings of this resource, and nothing else", async () => {
1463
+ openAgentPage();
1464
+ await openChangeModal();
1465
+
1466
+ const request: JSONObject = getItemSpy.mock.calls[0]![0] as JSONObject;
1467
+ expect(request["modelType"]).toBe(DockerHost);
1468
+ expect(String(request["id"])).toBe(RESOURCE_ID);
1469
+ expect(request["select"]).toEqual({
1470
+ _id: true,
1471
+ isAiInvestigationEnabled: true,
1472
+ aiRemediationMode: true,
1473
+ aiCommandAllowlist: true,
1474
+ });
1475
+ });
1476
+
1477
+ test("a member on an Ask-for-approval host is offered only Off and the current mode, and told why", async () => {
1478
+ openAgentPage();
1479
+ const dialog: HTMLElement = await openChangeModal();
1480
+
1481
+ expect(
1482
+ within(dialog).getByTestId("resource-ai-access-admin-note"),
1483
+ ).toHaveTextContent("Edit Auto Remediation Rule");
1484
+ // Nothing saved to remove: no allowlist field.
1485
+ expect(
1486
+ within(dialog).queryByTestId("ai-command-allowlist-field"),
1487
+ ).not.toBeInTheDocument();
1488
+
1489
+ expect(await openDropdown(dialog, /^Fixes/)).toEqual([
1490
+ RESOURCE_REMEDIATION_MODE_LABELS[ResourceAiRemediationMode.Disabled],
1491
+ `${RESOURCE_REMEDIATION_MODE_LABELS[ResourceAiRemediationMode.RequireApproval]} (current)`,
1492
+ ]);
1493
+ });
1494
+
1495
+ test("a member on an Off host cannot turn fixes on", async () => {
1496
+ serveModel({ aiRemediationMode: ResourceAiRemediationMode.Disabled });
1497
+ openAgentPage();
1498
+ const dialog: HTMLElement = await openChangeModal();
1499
+
1500
+ expect(await openDropdown(dialog, /^Fixes/)).toEqual([
1501
+ RESOURCE_REMEDIATION_MODE_LABELS[ResourceAiRemediationMode.Disabled],
1502
+ ]);
1503
+ });
1504
+
1505
+ test("an admin is offered every mode, and turns fixes on from Off", async () => {
1506
+ grant(ADMIN_PERMISSIONS);
1507
+ serveModel({ aiRemediationMode: ResourceAiRemediationMode.Disabled });
1508
+ openAgentPage();
1509
+ const dialog: HTMLElement = await openChangeModal();
1510
+
1511
+ expect(
1512
+ within(dialog).queryByTestId("resource-ai-access-admin-note"),
1513
+ ).not.toBeInTheDocument();
1514
+ expect(await openDropdown(dialog, /^Fixes/)).toEqual(
1515
+ Object.values(ResourceAiRemediationMode).map(
1516
+ (mode: ResourceAiRemediationMode): string => {
1517
+ return RESOURCE_REMEDIATION_MODE_LABELS[mode];
1518
+ },
1519
+ ),
1520
+ );
1521
+ fireEvent.click(
1522
+ menuOptions().find((option: HTMLElement): boolean => {
1523
+ return (
1524
+ option.textContent ===
1525
+ RESOURCE_REMEDIATION_MODE_LABELS[
1526
+ ResourceAiRemediationMode.RequireApproval
1527
+ ]
1528
+ );
1529
+ })!,
1530
+ );
1531
+ saveChangeModal(dialog);
1532
+
1533
+ expect(await waitForOneUpdate()).toEqual({
1534
+ aiRemediationMode: ResourceAiRemediationMode.RequireApproval,
1535
+ });
1536
+ expect(updateRequests()[0]!["modelType"]).toBe(DockerHost);
1537
+ });
1538
+
1539
+ test("a member turns investigation off, and only that is sent", async () => {
1540
+ serveModel({ aiRemediationMode: ResourceAiRemediationMode.Automatic });
1541
+ openAgentPage();
1542
+ const dialog: HTMLElement = await openChangeModal();
1543
+
1544
+ await toggleSwitch(dialog, "ai-investigation-field", true);
1545
+ saveChangeModal(dialog);
1546
+
1547
+ expect(await waitForOneUpdate()).toEqual({
1548
+ isAiInvestigationEnabled: false,
1549
+ });
1550
+ });
1551
+
1552
+ test("a member on a Bypass-approval host may step down to Automatic, unconfirmed", async () => {
1553
+ serveModel({ aiRemediationMode: ResourceAiRemediationMode.BypassApproval });
1554
+ openAgentPage();
1555
+ const dialog: HTMLElement = await openChangeModal();
1556
+
1557
+ await pickOption(
1558
+ dialog,
1559
+ /^Fixes/,
1560
+ RESOURCE_REMEDIATION_MODE_LABELS[ResourceAiRemediationMode.Automatic],
1561
+ );
1562
+ saveChangeModal(dialog);
1563
+
1564
+ expect(await waitForOneUpdate()).toEqual({
1565
+ aiRemediationMode: ResourceAiRemediationMode.Automatic,
1566
+ });
1567
+ expect(
1568
+ screen.queryByText("Let riskier changes run without approval?"),
1569
+ ).not.toBeInTheDocument();
1570
+ });
1571
+
1572
+ test("a member may remove an allowlist entry", async () => {
1573
+ serveModel({
1574
+ aiRemediationMode: ResourceAiRemediationMode.Automatic,
1575
+ aiCommandAllowlist: ["docker stop web", "docker stop api"],
1576
+ });
1577
+ openAgentPage();
1578
+ const dialog: HTMLElement = await openChangeModal();
1579
+
1580
+ expect(
1581
+ within(dialog).getByText(/You can remove entries or clear the list/),
1582
+ ).toBeInTheDocument();
1583
+ await setAllowlistText(dialog, "docker stop web");
1584
+ saveChangeModal(dialog);
1585
+
1586
+ expect(await waitForOneUpdate()).toEqual({
1587
+ aiCommandAllowlist: ["docker stop web"],
1588
+ });
1589
+ });
1590
+
1591
+ test("a member who adds an entry is told it needs the admin set, and nothing is sent", async () => {
1592
+ serveModel({
1593
+ aiRemediationMode: ResourceAiRemediationMode.Automatic,
1594
+ aiCommandAllowlist: ["docker stop web"],
1595
+ });
1596
+ openAgentPage();
1597
+ const dialog: HTMLElement = await openChangeModal();
1598
+
1599
+ await setAllowlistText(dialog, "docker stop web\ndocker stop api");
1600
+ saveChangeModal(dialog);
1601
+
1602
+ expect(
1603
+ await within(dialog).findByText(
1604
+ /is not in the saved allowlist/,
1605
+ {},
1606
+ { timeout: WAIT_TIMEOUT },
1607
+ ),
1608
+ ).toHaveTextContent("Edit Auto Remediation Rule");
1609
+ expect(updateByIdSpy).not.toHaveBeenCalled();
1610
+ });
1611
+
1612
+ test("the allowlist field is shown only while Automatic is chosen", async () => {
1613
+ grant(ADMIN_PERMISSIONS);
1614
+ serveModel({ aiRemediationMode: ResourceAiRemediationMode.Automatic });
1615
+ openAgentPage();
1616
+ const dialog: HTMLElement = await openChangeModal();
1617
+
1618
+ expect(
1619
+ await within(dialog).findByTestId(
1620
+ "ai-command-allowlist-field",
1621
+ {},
1622
+ { timeout: WAIT_TIMEOUT },
1623
+ ),
1624
+ ).toHaveAttribute("placeholder", DOCKER.allowlistPlaceholder);
1625
+
1626
+ await pickOption(
1627
+ dialog,
1628
+ /^Fixes/,
1629
+ RESOURCE_REMEDIATION_MODE_LABELS[
1630
+ ResourceAiRemediationMode.RequireApproval
1631
+ ],
1632
+ );
1633
+ await waitFor(
1634
+ () => {
1635
+ expect(
1636
+ within(dialog).queryByTestId("ai-command-allowlist-field"),
1637
+ ).not.toBeInTheDocument();
1638
+ },
1639
+ { timeout: WAIT_TIMEOUT },
1640
+ );
1641
+ });
1642
+
1643
+ test("an allowlist entry is checked with this resource type's policy", async () => {
1644
+ grant(ADMIN_PERMISSIONS);
1645
+ serveModel({ aiRemediationMode: ResourceAiRemediationMode.Automatic });
1646
+ openAgentPage();
1647
+ const dialog: HTMLElement = await openChangeModal();
1648
+
1649
+ // A host command means nothing on a Docker host.
1650
+ await setAllowlistText(dialog, "docker stop web\nsystemctl stop nginx");
1651
+ saveChangeModal(dialog);
1652
+
1653
+ expect(
1654
+ await within(dialog).findByText(
1655
+ /Entry 2: "systemctl stop nginx" does not start with a program the Docker AI agent runs/,
1656
+ {},
1657
+ { timeout: WAIT_TIMEOUT },
1658
+ ),
1659
+ ).toBeInTheDocument();
1660
+ expect(updateByIdSpy).not.toHaveBeenCalled();
1661
+ });
1662
+
1663
+ test("a failed save stays in the modal with the server's reason", async () => {
1664
+ grant(ADMIN_PERMISSIONS);
1665
+ serveModel({ aiRemediationMode: ResourceAiRemediationMode.Disabled });
1666
+ updateByIdSpy.mockImplementation(async (): Promise<never> => {
1667
+ throw new HTTPErrorResponse(
1668
+ 403,
1669
+ { error: "You need one of these permissions." },
1670
+ {},
1671
+ );
1672
+ });
1673
+ openAgentPage();
1674
+ const dialog: HTMLElement = await openChangeModal();
1675
+
1676
+ await pickOption(
1677
+ dialog,
1678
+ /^Fixes/,
1679
+ RESOURCE_REMEDIATION_MODE_LABELS[
1680
+ ResourceAiRemediationMode.RequireApproval
1681
+ ],
1682
+ );
1683
+ saveChangeModal(dialog);
1684
+
1685
+ expect(await findTestId("ai-access-save-error")).toHaveTextContent(
1686
+ "You need one of these permissions.",
1687
+ );
1688
+ expect(screen.getByRole("dialog")).toBe(dialog);
1689
+ });
1690
+
1691
+ test("the modal's read failing is said in the modal", async () => {
1692
+ getItemSpy.mockImplementation(async (): Promise<null> => {
1693
+ return null;
1694
+ });
1695
+ openAgentPage();
1696
+ fireEvent.click(await findTestId("ai-access-change-button"));
1697
+
1698
+ expect(
1699
+ await findText(/Could not read this Docker host's AI settings/),
1700
+ ).toBeInTheDocument();
1701
+ });
1702
+ });
1703
+
1704
+ describe("the Change modal: confirmations", () => {
1705
+ test("Bypass approval is confirmed before it is saved", async () => {
1706
+ grant(ADMIN_PERMISSIONS);
1707
+ openAgentPage();
1708
+ const dialog: HTMLElement = await openChangeModal();
1709
+
1710
+ await pickOption(
1711
+ dialog,
1712
+ /^Fixes/,
1713
+ RESOURCE_REMEDIATION_MODE_LABELS[
1714
+ ResourceAiRemediationMode.BypassApproval
1715
+ ],
1716
+ );
1717
+ saveChangeModal(dialog);
1718
+
1719
+ const confirm: HTMLElement = await findDialogTitled(
1720
+ "Turn on Bypass approval?",
1721
+ );
1722
+ expect(confirm).toHaveTextContent("on this Docker host on its own");
1723
+ expect(updateByIdSpy).not.toHaveBeenCalled();
1724
+
1725
+ fireEvent.click(within(confirm).getByText("Confirm and save"));
1726
+
1727
+ expect(await waitForOneUpdate()).toEqual({
1728
+ aiRemediationMode: ResourceAiRemediationMode.BypassApproval,
1729
+ });
1730
+ });
1731
+
1732
+ test("a broad entry is confirmed, and backing out sends nothing", async () => {
1733
+ grant(ADMIN_PERMISSIONS);
1734
+ serveModel({ aiRemediationMode: ResourceAiRemediationMode.Automatic });
1735
+ openAgentPage();
1736
+ const dialog: HTMLElement = await openChangeModal();
1737
+
1738
+ await setAllowlistText(dialog, "docker stop *");
1739
+ saveChangeModal(dialog);
1740
+
1741
+ const confirm: HTMLElement = await findDialogTitled(
1742
+ "Let riskier changes run without approval?",
1743
+ );
1744
+ expect(confirm).toHaveTextContent(
1745
+ 'The allowlist entry "docker stop *" uses a * for the object a change touches',
1746
+ );
1747
+
1748
+ fireEvent.click(within(confirm).getByText("Cancel"));
1749
+ await waitFor(
1750
+ () => {
1751
+ expect(
1752
+ screen.queryByText("Let riskier changes run without approval?"),
1753
+ ).not.toBeInTheDocument();
1754
+ },
1755
+ { timeout: WAIT_TIMEOUT },
1756
+ );
1757
+ expect(updateByIdSpy).not.toHaveBeenCalled();
1758
+ });
1759
+
1760
+ test("an entry that names its container saves without a question", async () => {
1761
+ grant(ADMIN_PERMISSIONS);
1762
+ serveModel({ aiRemediationMode: ResourceAiRemediationMode.Automatic });
1763
+ openAgentPage();
1764
+ const dialog: HTMLElement = await openChangeModal();
1765
+
1766
+ await setAllowlistText(dialog, "docker stop web");
1767
+ saveChangeModal(dialog);
1768
+
1769
+ expect(await waitForOneUpdate()).toEqual({
1770
+ aiCommandAllowlist: ["docker stop web"],
1771
+ });
1772
+ });
1773
+
1774
+ test("nothing changed: the modal closes without a write", async () => {
1775
+ openAgentPage();
1776
+ const dialog: HTMLElement = await openChangeModal();
1777
+
1778
+ saveChangeModal(dialog);
1779
+
1780
+ await waitFor(
1781
+ () => {
1782
+ expect(screen.queryByRole("dialog")).not.toBeInTheDocument();
1783
+ },
1784
+ { timeout: WAIT_TIMEOUT },
1785
+ );
1786
+ expect(updateByIdSpy).not.toHaveBeenCalled();
1787
+ });
1788
+ });
1789
+
1790
+ describe("Test connection", () => {
1791
+ test("runs the test for this resource and shows each command's result", async () => {
1792
+ serve(makeStatus(), {
1793
+ test: async (): Promise<HTTPResponse<JSONObject>> => {
1794
+ return new HTTPResponse<JSONObject>(
1795
+ 200,
1796
+ {
1797
+ ok: false,
1798
+ message: "docker info failed.",
1799
+ results: [
1800
+ {
1801
+ command: "docker version",
1802
+ succeeded: true,
1803
+ exitCode: 0,
1804
+ output: "Server: 27.3.1",
1805
+ errorMessage: null,
1806
+ },
1807
+ {
1808
+ command: "docker info",
1809
+ succeeded: false,
1810
+ exitCode: 1,
1811
+ output: "",
1812
+ errorMessage: "permission denied",
1813
+ },
1814
+ ],
1815
+ status: makeStatus({
1816
+ agent: makeAgent({ agentVersion: "14.2.0" }),
1817
+ }) as unknown as JSONObject,
1818
+ },
1819
+ {},
1820
+ );
1821
+ },
1822
+ });
1823
+ openAgentPage();
1824
+
1825
+ fireEvent.click(await findTestId("ai-agent-test-button"));
1826
+
1827
+ const results: HTMLElement = await findTestId("ai-agent-test-results");
1828
+ expect(results).toHaveTextContent("The connection is not working yet");
1829
+ expect(results).toHaveTextContent("docker info failed.");
1830
+ const rows: Array<HTMLElement> = within(results).getAllByTestId(
1831
+ "ai-agent-test-result-row",
1832
+ );
1833
+ expect(rows).toHaveLength(2);
1834
+ expect(rows[0]).toHaveTextContent("docker version");
1835
+ expect(rows[0]).toHaveTextContent("succeeded");
1836
+ expect(rows[0]).toHaveTextContent("Server: 27.3.1");
1837
+ expect(rows[1]).toHaveTextContent("failed (exit 1)");
1838
+ expect(rows[1]).toHaveTextContent("permission denied");
1839
+ expect(postsTo(TEST_ROUTE)[0]!["data"]).toEqual({
1840
+ resourceType: AiResourceType.DockerHost,
1841
+ resourceId: RESOURCE_ID,
1842
+ });
1843
+ // The status the test returned replaces the one on screen.
1844
+ await waitFor(
1845
+ () => {
1846
+ expect(screen.getByTestId("ai-agent-meta")).toHaveTextContent(
1847
+ "agent v14.2.0",
1848
+ );
1849
+ },
1850
+ { timeout: WAIT_TIMEOUT },
1851
+ );
1852
+ });
1853
+
1854
+ test("a refused test says what it needs, not what the server says about settings", async () => {
1855
+ serve(makeStatus(), {
1856
+ test: async (): Promise<HTTPErrorResponse> => {
1857
+ // The server's NotAuthorizedException, which OneUptime sends as 422.
1858
+ return new HTTPErrorResponse(
1859
+ ExceptionCode.NotAuthorizedException,
1860
+ { error: "You cannot change this resource's AI access." },
1861
+ {},
1862
+ );
1863
+ },
1864
+ });
1865
+ openAgentPage();
1866
+
1867
+ fireEvent.click(await findTestId("ai-agent-test-button"));
1868
+
1869
+ const error: HTMLElement = await findTestId("ai-agent-test-error");
1870
+ expect(error).toHaveTextContent(
1871
+ "Testing the connection needs permission to edit this Docker host",
1872
+ );
1873
+ expect(error).toHaveTextContent(
1874
+ "Nothing on the Docker host or in its AI settings was changed.",
1875
+ );
1876
+ });
1877
+
1878
+ test("another failure is shown as the server said it", async () => {
1879
+ serve(makeStatus(), {
1880
+ test: async (): Promise<HTTPErrorResponse> => {
1881
+ return new HTTPErrorResponse(
1882
+ 429,
1883
+ { error: "An AI access test is already running." },
1884
+ {},
1885
+ );
1886
+ },
1887
+ });
1888
+ openAgentPage();
1889
+
1890
+ fireEvent.click(await findTestId("ai-agent-test-button"));
1891
+
1892
+ expect(await findTestId("ai-agent-test-error")).toHaveTextContent(
1893
+ "An AI access test is already running.",
1894
+ );
1895
+ });
1896
+
1897
+ test("is locked for a reader, with the reason", async () => {
1898
+ grant(READER_PERMISSIONS);
1899
+ openAgentPage();
1900
+
1901
+ expect(await findTestId("ai-agent-test-button")).toBeDisabled();
1902
+ expect(
1903
+ screen.getByTestId("ai-agent-test-permission-note"),
1904
+ ).toHaveTextContent("Testing the connection needs permission to edit");
1905
+ });
1906
+ });
1907
+
1908
+ describe("Reset agent", () => {
1909
+ test("is only offered to the admin set", async () => {
1910
+ openAgentPage();
1911
+
1912
+ expect(await findText("Docker AI agent")).toBeInTheDocument();
1913
+ expect(
1914
+ screen.queryByTestId("ai-agent-reset-button"),
1915
+ ).not.toBeInTheDocument();
1916
+ });
1917
+
1918
+ test("an admin resets the agent after a confirmation", async () => {
1919
+ grant(ADMIN_PERMISSIONS);
1920
+ openAgentPage();
1921
+
1922
+ fireEvent.click(await findTestId("ai-agent-reset-button"));
1923
+ const confirm: HTMLElement = await findDialogTitled("Reset the AI agent?");
1924
+ expect(confirm).toHaveTextContent(
1925
+ "This revokes the Docker AI agent's key.",
1926
+ );
1927
+ expect(postsTo(RESET_ROUTE)).toHaveLength(0);
1928
+
1929
+ fireEvent.click(within(confirm).getByText("Reset agent"));
1930
+
1931
+ expect(await findTestId("ai-agent-action-notice")).toHaveTextContent(
1932
+ "The Docker AI agent was reset. It reconnects on its own within a few minutes.",
1933
+ );
1934
+ expect(postsTo(RESET_ROUTE)).toHaveLength(1);
1935
+ expect(postsTo(RESET_ROUTE)[0]!["data"]).toEqual({
1936
+ resourceType: AiResourceType.DockerHost,
1937
+ resourceId: RESOURCE_ID,
1938
+ });
1939
+ });
1940
+
1941
+ test("a refused reset stays in its dialog with the reason", async () => {
1942
+ grant(ADMIN_PERMISSIONS);
1943
+ serve(makeStatus(), {
1944
+ reset: async (): Promise<HTTPErrorResponse> => {
1945
+ return new HTTPErrorResponse(403, { error: "Not yours to reset." }, {});
1946
+ },
1947
+ });
1948
+ openAgentPage();
1949
+
1950
+ fireEvent.click(await findTestId("ai-agent-reset-button"));
1951
+ const confirm: HTMLElement = await findDialogTitled("Reset the AI agent?");
1952
+ fireEvent.click(within(confirm).getByText("Reset agent"));
1953
+
1954
+ expect(
1955
+ await within(confirm).findByText(
1956
+ "Not yours to reset.",
1957
+ {},
1958
+ { timeout: WAIT_TIMEOUT },
1959
+ ),
1960
+ ).toBeInTheDocument();
1961
+ });
1962
+
1963
+ test("nothing to reset before an agent registered", async () => {
1964
+ grant(ADMIN_PERMISSIONS);
1965
+ serve(notInstalledStatus());
1966
+ openAgentPage();
1967
+
1968
+ expect(await findTestId("ai-agent-status")).toHaveTextContent(
1969
+ "Not installed",
1970
+ );
1971
+ expect(
1972
+ screen.queryByTestId("ai-agent-reset-button"),
1973
+ ).not.toBeInTheDocument();
1974
+ });
1975
+ });
1976
+
1977
+ describe("every resource type", () => {
1978
+ test.each(ALL_AI_RESOURCE_TYPES)(
1979
+ "%s: the page asks about its own type and names its own agent",
1980
+ async (type: AiResourceType) => {
1981
+ const descriptor: ResourceAiAgentDescriptor =
1982
+ getResourceAiAgentDescriptor(type);
1983
+ serve({
1984
+ ...notInstalledStatus(),
1985
+ resourceType: type,
1986
+ });
1987
+ openAgentPage(descriptor);
1988
+
1989
+ expect(await findText(descriptor.agentName)).toBeInTheDocument();
1990
+ expect(screen.getByTestId("ai-agent-page-heading")).toHaveTextContent(
1991
+ getResourceAiAgentPageSubtitle(descriptor),
1992
+ );
1993
+ expect(postsTo(STATUS_ROUTE)[0]!["data"]).toEqual({
1994
+ resourceType: type,
1995
+ resourceId: RESOURCE_ID,
1996
+ });
1997
+ expect(codeIn(await findTestId("ai-agent-install-command"))).toContain(
1998
+ `${getResourceAiAgentServiceName(type)}:`,
1999
+ );
2000
+ expect(screen.getByTestId("ai-agent-attention-title")).toHaveTextContent(
2001
+ `OneUptime AI can't investigate this ${descriptor.noun}`,
2002
+ );
2003
+ expect(
2004
+ screen.getByTestId("ai-agent-gap-ai_agent_not_connected"),
2005
+ ).toHaveTextContent(
2006
+ `Install the ${descriptor.agentName} with the instructions above.`,
2007
+ );
2008
+ },
2009
+ );
2010
+ });