@oneuptime/common 14.0.9 → 14.0.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (383) hide show
  1. package/Models/DatabaseModels/AutoRemediationSuggestion.ts +60 -0
  2. package/Models/DatabaseModels/CephCluster.ts +213 -0
  3. package/Models/DatabaseModels/DatabaseServer.ts +213 -0
  4. package/Models/DatabaseModels/DockerHost.ts +213 -0
  5. package/Models/DatabaseModels/DockerSwarmCluster.ts +213 -0
  6. package/Models/DatabaseModels/GlobalConfig.ts +1 -1
  7. package/Models/DatabaseModels/Host.ts +213 -0
  8. package/Models/DatabaseModels/Index.ts +2 -0
  9. package/Models/DatabaseModels/PodmanHost.ts +213 -0
  10. package/Models/DatabaseModels/ProxmoxCluster.ts +213 -0
  11. package/Models/DatabaseModels/ResourceAiAgent.ts +419 -0
  12. package/Models/DatabaseModels/RunnerJob.ts +144 -0
  13. package/Models/DatabaseModels/VMwareVCenter.ts +213 -0
  14. package/Server/API/AutoRemediationAPI.ts +392 -1
  15. package/Server/API/ResourceAiAccessAPI.ts +1669 -0
  16. package/Server/Infrastructure/Postgres/SchemaMigrations/1796300000000-AddResourceAiAgents.ts +423 -0
  17. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +2 -0
  18. package/Server/Infrastructure/Semaphore.ts +22 -0
  19. package/Server/Middleware/TelemetryIngest.ts +15 -5
  20. package/Server/Services/AnalyticsDatabaseService.ts +45 -1
  21. package/Server/Services/AutoRemediationRuleEngineService.ts +940 -112
  22. package/Server/Services/CephClusterService.ts +109 -1
  23. package/Server/Services/DatabaseServerService.ts +116 -1
  24. package/Server/Services/DockerHostService.ts +109 -1
  25. package/Server/Services/DockerSwarmClusterService.ts +113 -1
  26. package/Server/Services/HostService.ts +126 -4
  27. package/Server/Services/MetricRecordingRuleService.ts +47 -0
  28. package/Server/Services/PodmanHostService.ts +109 -1
  29. package/Server/Services/ProxmoxClusterService.ts +110 -1
  30. package/Server/Services/ResourceAiAccessService.ts +1439 -0
  31. package/Server/Services/ResourceAiAgentJobService.ts +202 -0
  32. package/Server/Services/ResourceAiAgentService.ts +2432 -0
  33. package/Server/Services/RunnerJobService.ts +611 -4
  34. package/Server/Services/TelemetryUsageBillingService.ts +28 -0
  35. package/Server/Services/TraceRecordingRuleService.ts +33 -0
  36. package/Server/Services/VMwareVCenterService.ts +110 -1
  37. package/Server/Utils/AI/Remediation/RemediationCommandTools.ts +1434 -32
  38. package/Server/Utils/AI/Remediation/RemediationExecutionRunner.ts +935 -21
  39. package/Server/Utils/AI/Remediation/RemediationPlanRunner.ts +25 -1
  40. package/Server/Utils/AI/ResourceAccess/InfrastructureInvestigationToolkit.ts +577 -0
  41. package/Server/Utils/AI/ResourceAccess/ResourceAccessContext.ts +271 -0
  42. package/Server/Utils/AI/ResourceAccess/ResourceAccessToolNames.ts +45 -0
  43. package/Server/Utils/AI/ResourceAccess/ResourceAiAccessSettings.ts +964 -0
  44. package/Server/Utils/AI/ResourceAccess/ResourceAiDeleteCleanup.ts +333 -0
  45. package/Server/Utils/AI/ResourceAccess/ResourceCommandJobRunner.ts +873 -0
  46. package/Server/Utils/AI/SRE/AIInvestigationEngine.ts +72 -2
  47. package/Server/Utils/AI/SRE/AlertInvestigationRunner.ts +72 -5
  48. package/Server/Utils/AI/SRE/IncidentInvestigationRunner.ts +72 -5
  49. package/Server/Utils/AutoRemediation/CommandPlanExecutor.ts +396 -13
  50. package/Server/Utils/AutoRemediation/RemediationVerifier.ts +35 -2
  51. package/Server/Utils/Database/ProjectScopedReferenceValidator.ts +9 -1
  52. package/Server/Utils/SessionReplay/SessionReplayBudgetMetrics.ts +920 -0
  53. package/Server/Utils/SessionReplay/SessionReplayUsage.ts +84 -6
  54. package/Server/Utils/Workspace/MicrosoftTeams/Actions/Alert.ts +35 -15
  55. package/Server/Utils/Workspace/MicrosoftTeams/Actions/AlertEpisode.ts +33 -15
  56. package/Server/Utils/Workspace/MicrosoftTeams/Actions/Auth.ts +21 -1
  57. package/Server/Utils/Workspace/MicrosoftTeams/Actions/Incident.ts +298 -224
  58. package/Server/Utils/Workspace/MicrosoftTeams/Actions/IncidentEpisode.ts +35 -15
  59. package/Server/Utils/Workspace/MicrosoftTeams/Actions/ScheduledMaintenance.ts +389 -175
  60. package/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.ts +366 -143
  61. package/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsActivityDeduplicator.ts +163 -0
  62. package/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsCardChoices.ts +396 -0
  63. package/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsCreateCommands.ts +418 -0
  64. package/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsMessageSize.ts +152 -0
  65. package/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsReplies.ts +251 -0
  66. package/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsTimezone.ts +214 -0
  67. package/Tests/App/Dashboard/ClusterAccessNotice.test.tsx +93 -0
  68. package/Tests/App/Dashboard/DatabaseDocumentationMarkdown.test.ts +18 -6
  69. package/Tests/App/Dashboard/InvestigationInfrastructureTools.test.tsx +506 -0
  70. package/Tests/App/Dashboard/RemediationSuggestionCardDescription.test.tsx +209 -0
  71. package/Tests/App/Dashboard/RemediationSuggestionCardResource.test.tsx +317 -0
  72. package/Tests/App/Dashboard/ResourceAiAccessSettingsUtil.test.ts +921 -0
  73. package/Tests/App/Dashboard/ResourceAiAgentInstall.test.ts +860 -0
  74. package/Tests/App/Dashboard/ResourceAiAgentPage.test.tsx +1721 -0
  75. package/Tests/App/Dashboard/ResourceAiAgentStatus.test.ts +1002 -0
  76. package/Tests/App/Dashboard/ResourceAiInsightsPage.test.tsx +931 -0
  77. package/Tests/App/Dashboard/ResourceAiNavigation.test.tsx +575 -0
  78. package/Tests/App/Dashboard/RunbookStepTypeMaps.test.ts +38 -7
  79. package/Tests/Models/DatabaseModels/DatabaseServerModels.test.ts +33 -1
  80. package/Tests/Models/DatabaseModels/ResourceAiAccessColumns.test.ts +738 -0
  81. package/Tests/Models/DatabaseModels/ResourceAiAgentModel.test.ts +842 -0
  82. package/Tests/Server/API/AutoRemediationApproveResourceRound.test.ts +835 -0
  83. package/Tests/Server/API/ResourceAiAccessAPI.test.ts +2730 -0
  84. package/Tests/Server/Infrastructure/Postgres/AddDatabaseServerTablesMigration.test.ts +60 -0
  85. package/Tests/Server/Infrastructure/Postgres/AddResourceAiAgentsMigration.test.ts +659 -0
  86. package/Tests/Server/Infrastructure/SemaphoreMutex.test.ts +31 -0
  87. package/Tests/Server/Middleware/TelemetryIngestBrowserKey.test.ts +63 -5
  88. package/Tests/Server/Middleware/TelemetryIngestKubernetesAgentRunnerPinnedKey.test.ts +103 -5
  89. package/Tests/Server/Middleware/TelemetryIngestKubernetesAgentRunnerRateLimit.test.ts +19 -1
  90. package/Tests/Server/Services/AutoRemediationResourceRuleEngine.test.ts +1279 -0
  91. package/Tests/Server/Services/DatabaseServerService.test.ts +55 -0
  92. package/Tests/Server/Services/GroupTelemetryUsageExcludeNames.test.ts +299 -0
  93. package/Tests/Server/Services/HostServiceFindOrCreateMemo.test.ts +44 -0
  94. package/Tests/Server/Services/MonitorProbeServiceIntervalScheduling.test.ts +45 -6
  95. package/Tests/Server/Services/RecordingRuleReservedMetricName.test.ts +171 -0
  96. package/Tests/Server/Services/ResourceAiAccessChangeAuthorization.test.ts +256 -0
  97. package/Tests/Server/Services/ResourceAiAccessService.test.ts +1373 -0
  98. package/Tests/Server/Services/ResourceAiAgentJobService.test.ts +375 -0
  99. package/Tests/Server/Services/ResourceAiAgentServiceHelpers.test.ts +1114 -0
  100. package/Tests/Server/Services/ResourceAiAgentServiceLifecycle.test.ts +1050 -0
  101. package/Tests/Server/Services/ResourceAiAgentServiceRegister.test.ts +2251 -0
  102. package/Tests/Server/Services/ResourceAiSettingsCreate.test.ts +373 -0
  103. package/Tests/Server/Services/ResourceAiSettingsPermission.test.ts +1042 -0
  104. package/Tests/Server/Services/ResourceServiceDeleteCleansUpAi.test.ts +319 -0
  105. package/Tests/Server/Services/RunnerJobEnqueueKubectl.test.ts +105 -0
  106. package/Tests/Server/Services/RunnerJobEnqueueResourceCommand.test.ts +986 -0
  107. package/Tests/Server/Services/RunnerJobResourceCommandLane.test.ts +211 -0
  108. package/Tests/Server/Services/RunnerJobResourceCommandTimeoutAndRedaction.test.ts +352 -0
  109. package/Tests/Server/Services/TelemetryUsageBillingSloExclusion.test.ts +218 -0
  110. package/Tests/Server/TestingUtils/Services/FakeRunnerJobCount.ts +145 -0
  111. package/Tests/Server/Utils/AI/InvestigationInfrastructureAccessWiring.test.ts +453 -0
  112. package/Tests/Server/Utils/AI/InvestigationInfrastructureReport.test.ts +721 -0
  113. package/Tests/Server/Utils/AI/RemediationCommandTools.test.ts +94 -1
  114. package/Tests/Server/Utils/AI/RemediationCommandToolsResource.test.ts +1530 -0
  115. package/Tests/Server/Utils/AI/RemediationExecutionRunnerResourceMode.test.ts +1249 -0
  116. package/Tests/Server/Utils/AI/RemediationPlanRunner.test.ts +117 -0
  117. package/Tests/Server/Utils/AI/RemediationResourceCopyParity.test.ts +463 -0
  118. package/Tests/Server/Utils/AI/ResourceAccess/InfrastructureInvestigationToolkit.test.ts +722 -0
  119. package/Tests/Server/Utils/AI/ResourceAccess/ResourceAccessContext.test.ts +266 -0
  120. package/Tests/Server/Utils/AI/ResourceAccess/ResourceAiAccessSettings.test.ts +1220 -0
  121. package/Tests/Server/Utils/AI/ResourceAccess/ResourceAiDeleteCleanup.test.ts +569 -0
  122. package/Tests/Server/Utils/AI/ResourceAccess/ResourceCommandJobRunner.test.ts +830 -0
  123. package/Tests/Server/Utils/AutoRemediation/CommandPlanExecutorResource.test.ts +717 -0
  124. package/Tests/Server/Utils/AutoRemediation/RemediationVerifierResourceFollowUp.test.ts +338 -0
  125. package/Tests/Server/Utils/Monitor/Criteria/SessionReplayBudgetTemplateCriteria.test.ts +422 -0
  126. package/Tests/Server/Utils/SessionReplay/SessionReplayBudgetMetrics.test.ts +1647 -0
  127. package/Tests/Server/Utils/SessionReplay/SessionReplayUsage.test.ts +143 -1
  128. package/Tests/Server/Utils/Telemetry/TelemetryIngestionKeyGuard.test.ts +33 -3
  129. package/Tests/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsAccountNotLinked.test.ts +1093 -0
  130. package/Tests/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsActivityDeduplicator.test.ts +1049 -0
  131. package/Tests/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsCardChoices.test.ts +1676 -0
  132. package/Tests/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsCreateCards.test.ts +2884 -0
  133. package/Tests/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsCreateCommands.test.ts +2490 -0
  134. package/Tests/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsCreateSubmit.test.ts +2293 -0
  135. package/Tests/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsCreateSubmitServerTimezone.test.ts +386 -0
  136. package/Tests/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsMessageSize.test.ts +1477 -0
  137. package/Tests/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsReplies.test.ts +1967 -0
  138. package/Tests/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsStripHtmlTags.test.ts +92 -0
  139. package/Tests/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsSubmittedFormRemoval.test.ts +1819 -0
  140. package/Tests/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsTimezone.test.ts +1033 -0
  141. package/Tests/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsTimezoneServerZone.test.ts +610 -0
  142. package/Tests/Server/Utils/Workspace/MicrosoftTeamsBotMessageHandling.test.ts +2610 -0
  143. package/Tests/Server/Utils/Workspace/MicrosoftTeamsCreateCommandsEndToEnd.test.ts +4672 -0
  144. package/Tests/Server/Utils/Workspace/WorkspaceCreateProjectReferences.test.ts +190 -65
  145. package/Tests/Types/AutoRemediation/AiRemediationCommandPlan.test.ts +10 -4
  146. package/Tests/Types/AutoRemediation/AiRemediationCommandPlanResourceCommand.test.ts +305 -0
  147. package/Tests/Types/Monitor/Recommendation/MonitorRecommendationCatalog.test.ts +277 -13
  148. package/Tests/Types/Monitor/Recommendation/MonitorRecommendationUtil.test.ts +113 -0
  149. package/Tests/Types/Monitor/RumAlertTemplates.test.ts +773 -2
  150. package/Tests/Types/ResourceAiAgent/AiResourceType.test.ts +419 -0
  151. package/Tests/Types/ResourceAiAgent/ResourceAiAccess.test.ts +517 -0
  152. package/Tests/Types/Runbook/RunbookStepType.test.ts +147 -8
  153. package/Tests/UI/Rum/RecordingHealthDashboard.test.tsx +769 -1
  154. package/Tests/Utils/AiRemediation/Resource/CephCommandPolicy.test.ts +1653 -0
  155. package/Tests/Utils/AiRemediation/Resource/CephOutputRedaction.test.ts +204 -0
  156. package/Tests/Utils/AiRemediation/Resource/DatabaseCommandPolicy.test.ts +1077 -0
  157. package/Tests/Utils/AiRemediation/Resource/DatabaseDiagnosticCatalog.test.ts +558 -0
  158. package/Tests/Utils/AiRemediation/Resource/DatabaseQueryRedactor.test.ts +834 -0
  159. package/Tests/Utils/AiRemediation/Resource/DockerCliGrammar.test.ts +747 -0
  160. package/Tests/Utils/AiRemediation/Resource/DockerEngineCommandPolicy.test.ts +1259 -0
  161. package/Tests/Utils/AiRemediation/Resource/DockerOutputRedaction.test.ts +386 -0
  162. package/Tests/Utils/AiRemediation/Resource/DockerSwarmCommandPolicy.test.ts +782 -0
  163. package/Tests/Utils/AiRemediation/Resource/GovcCommandPolicy.test.ts +2259 -0
  164. package/Tests/Utils/AiRemediation/Resource/HostCommandPolicy.test.ts +2019 -0
  165. package/Tests/Utils/AiRemediation/Resource/ProxmoxCommandPolicy.test.ts +2497 -0
  166. package/Tests/Utils/AiRemediation/Resource/ResourceCommandPolicy.test.ts +1305 -0
  167. package/Tests/Utils/AiRemediation/Resource/ResourceCommandPolicyCore.test.ts +585 -0
  168. package/Tests/Utils/AiRemediation/Resource/ResourceOutputRedactor.test.ts +334 -0
  169. package/Tests/Utils/AiRemediation/Resource/ResourceOutputRedactorCopyParity.test.ts +98 -0
  170. package/Tests/Utils/AiRemediation/Resource/ResourcePolicyImportClosure.test.ts +391 -0
  171. package/Tests/Utils/AiRemediation/ResourceAiAgentPolicyCopyParity.test.ts +497 -0
  172. package/Tests/Utils/SessionReplay/SessionReplayBudgetMetricType.test.ts +383 -0
  173. package/Types/AI/ResourceAiAccessApi.ts +140 -0
  174. package/Types/AI/ResourceAiAccessPermissions.ts +126 -0
  175. package/Types/AutoRemediation/AiRemediationCommandPlan.ts +183 -2
  176. package/Types/Monitor/Recommendation/MonitorRecommendationCatalog.ts +55 -22
  177. package/Types/Monitor/Recommendation/MonitorRecommendationTypes.ts +35 -3
  178. package/Types/Monitor/RumAlertTemplates.ts +351 -4
  179. package/Types/ResourceAiAgent/AiResourceType.ts +310 -0
  180. package/Types/ResourceAiAgent/ResourceAiAccess.ts +574 -0
  181. package/Types/Rum/SessionReplayBudgetMetricType.ts +47 -0
  182. package/Types/Runbook/RunbookStepType.ts +29 -0
  183. package/Types/Telemetry/TelemetryIngestSurface.ts +14 -2
  184. package/Utils/AI/InvestigationReport.ts +121 -15
  185. package/Utils/AiRemediation/Resource/CephCommandPolicy.ts +1936 -0
  186. package/Utils/AiRemediation/Resource/DatabaseCommandPolicy.ts +166 -0
  187. package/Utils/AiRemediation/Resource/DatabaseDiagnosticCatalog.ts +1532 -0
  188. package/Utils/AiRemediation/Resource/DatabaseQueryRedactor.ts +1394 -0
  189. package/Utils/AiRemediation/Resource/DockerCliGrammar.ts +1839 -0
  190. package/Utils/AiRemediation/Resource/DockerEngineCommandPolicy.ts +490 -0
  191. package/Utils/AiRemediation/Resource/DockerSwarmCommandPolicy.ts +687 -0
  192. package/Utils/AiRemediation/Resource/GovcCommandPolicy.ts +2096 -0
  193. package/Utils/AiRemediation/Resource/HostCommandPolicy.ts +2982 -0
  194. package/Utils/AiRemediation/Resource/ProxmoxCommandPolicy.ts +1679 -0
  195. package/Utils/AiRemediation/Resource/ResourceCommandPolicy.ts +851 -0
  196. package/Utils/AiRemediation/Resource/ResourceCommandPolicyCore.ts +593 -0
  197. package/Utils/AiRemediation/Resource/ResourceOutputRedactor.ts +2812 -0
  198. package/Utils/SessionReplay/SessionReplayBudgetMetricType.ts +184 -0
  199. package/build/dist/Models/DatabaseModels/AutoRemediationSuggestion.js +62 -0
  200. package/build/dist/Models/DatabaseModels/AutoRemediationSuggestion.js.map +1 -1
  201. package/build/dist/Models/DatabaseModels/CephCluster.js +219 -0
  202. package/build/dist/Models/DatabaseModels/CephCluster.js.map +1 -1
  203. package/build/dist/Models/DatabaseModels/DatabaseServer.js +219 -0
  204. package/build/dist/Models/DatabaseModels/DatabaseServer.js.map +1 -1
  205. package/build/dist/Models/DatabaseModels/DockerHost.js +219 -0
  206. package/build/dist/Models/DatabaseModels/DockerHost.js.map +1 -1
  207. package/build/dist/Models/DatabaseModels/DockerSwarmCluster.js +219 -0
  208. package/build/dist/Models/DatabaseModels/DockerSwarmCluster.js.map +1 -1
  209. package/build/dist/Models/DatabaseModels/GlobalConfig.js +1 -1
  210. package/build/dist/Models/DatabaseModels/GlobalConfig.js.map +1 -1
  211. package/build/dist/Models/DatabaseModels/Host.js +219 -0
  212. package/build/dist/Models/DatabaseModels/Host.js.map +1 -1
  213. package/build/dist/Models/DatabaseModels/Index.js +2 -0
  214. package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
  215. package/build/dist/Models/DatabaseModels/PodmanHost.js +219 -0
  216. package/build/dist/Models/DatabaseModels/PodmanHost.js.map +1 -1
  217. package/build/dist/Models/DatabaseModels/ProxmoxCluster.js +219 -0
  218. package/build/dist/Models/DatabaseModels/ProxmoxCluster.js.map +1 -1
  219. package/build/dist/Models/DatabaseModels/ResourceAiAgent.js +439 -0
  220. package/build/dist/Models/DatabaseModels/ResourceAiAgent.js.map +1 -0
  221. package/build/dist/Models/DatabaseModels/RunnerJob.js +145 -0
  222. package/build/dist/Models/DatabaseModels/RunnerJob.js.map +1 -1
  223. package/build/dist/Models/DatabaseModels/VMwareVCenter.js +219 -0
  224. package/build/dist/Models/DatabaseModels/VMwareVCenter.js.map +1 -1
  225. package/build/dist/Server/API/AutoRemediationAPI.js +231 -1
  226. package/build/dist/Server/API/AutoRemediationAPI.js.map +1 -1
  227. package/build/dist/Server/API/ResourceAiAccessAPI.js +1119 -0
  228. package/build/dist/Server/API/ResourceAiAccessAPI.js.map +1 -0
  229. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1796300000000-AddResourceAiAgents.js +168 -0
  230. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1796300000000-AddResourceAiAgents.js.map +1 -0
  231. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +2 -0
  232. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  233. package/build/dist/Server/Infrastructure/Semaphore.js +6 -0
  234. package/build/dist/Server/Infrastructure/Semaphore.js.map +1 -1
  235. package/build/dist/Server/Middleware/TelemetryIngest.js +12 -5
  236. package/build/dist/Server/Middleware/TelemetryIngest.js.map +1 -1
  237. package/build/dist/Server/Services/AnalyticsDatabaseService.js +26 -1
  238. package/build/dist/Server/Services/AnalyticsDatabaseService.js.map +1 -1
  239. package/build/dist/Server/Services/AutoRemediationRuleEngineService.js +601 -3
  240. package/build/dist/Server/Services/AutoRemediationRuleEngineService.js.map +1 -1
  241. package/build/dist/Server/Services/CephClusterService.js +104 -0
  242. package/build/dist/Server/Services/CephClusterService.js.map +1 -1
  243. package/build/dist/Server/Services/DatabaseServerService.js +99 -0
  244. package/build/dist/Server/Services/DatabaseServerService.js.map +1 -1
  245. package/build/dist/Server/Services/DockerHostService.js +104 -0
  246. package/build/dist/Server/Services/DockerHostService.js.map +1 -1
  247. package/build/dist/Server/Services/DockerSwarmClusterService.js +104 -0
  248. package/build/dist/Server/Services/DockerSwarmClusterService.js.map +1 -1
  249. package/build/dist/Server/Services/HostService.js +114 -2
  250. package/build/dist/Server/Services/HostService.js.map +1 -1
  251. package/build/dist/Server/Services/MetricRecordingRuleService.js +46 -0
  252. package/build/dist/Server/Services/MetricRecordingRuleService.js.map +1 -1
  253. package/build/dist/Server/Services/PodmanHostService.js +104 -0
  254. package/build/dist/Server/Services/PodmanHostService.js.map +1 -1
  255. package/build/dist/Server/Services/ProxmoxClusterService.js +104 -0
  256. package/build/dist/Server/Services/ProxmoxClusterService.js.map +1 -1
  257. package/build/dist/Server/Services/ResourceAiAccessService.js +1028 -0
  258. package/build/dist/Server/Services/ResourceAiAccessService.js.map +1 -0
  259. package/build/dist/Server/Services/ResourceAiAgentJobService.js +173 -0
  260. package/build/dist/Server/Services/ResourceAiAgentJobService.js.map +1 -0
  261. package/build/dist/Server/Services/ResourceAiAgentService.js +1687 -0
  262. package/build/dist/Server/Services/ResourceAiAgentService.js.map +1 -0
  263. package/build/dist/Server/Services/RunnerJobService.js +344 -5
  264. package/build/dist/Server/Services/RunnerJobService.js.map +1 -1
  265. package/build/dist/Server/Services/TelemetryUsageBillingService.js +26 -0
  266. package/build/dist/Server/Services/TelemetryUsageBillingService.js.map +1 -1
  267. package/build/dist/Server/Services/TraceRecordingRuleService.js +37 -0
  268. package/build/dist/Server/Services/TraceRecordingRuleService.js.map +1 -1
  269. package/build/dist/Server/Services/VMwareVCenterService.js +104 -0
  270. package/build/dist/Server/Services/VMwareVCenterService.js.map +1 -1
  271. package/build/dist/Server/Utils/AI/Remediation/RemediationCommandTools.js +1029 -30
  272. package/build/dist/Server/Utils/AI/Remediation/RemediationCommandTools.js.map +1 -1
  273. package/build/dist/Server/Utils/AI/Remediation/RemediationExecutionRunner.js +633 -28
  274. package/build/dist/Server/Utils/AI/Remediation/RemediationExecutionRunner.js.map +1 -1
  275. package/build/dist/Server/Utils/AI/Remediation/RemediationPlanRunner.js +21 -1
  276. package/build/dist/Server/Utils/AI/Remediation/RemediationPlanRunner.js.map +1 -1
  277. package/build/dist/Server/Utils/AI/ResourceAccess/InfrastructureInvestigationToolkit.js +330 -0
  278. package/build/dist/Server/Utils/AI/ResourceAccess/InfrastructureInvestigationToolkit.js.map +1 -0
  279. package/build/dist/Server/Utils/AI/ResourceAccess/ResourceAccessContext.js +160 -0
  280. package/build/dist/Server/Utils/AI/ResourceAccess/ResourceAccessContext.js.map +1 -0
  281. package/build/dist/Server/Utils/AI/ResourceAccess/ResourceAccessToolNames.js +33 -0
  282. package/build/dist/Server/Utils/AI/ResourceAccess/ResourceAccessToolNames.js.map +1 -0
  283. package/build/dist/Server/Utils/AI/ResourceAccess/ResourceAiAccessSettings.js +640 -0
  284. package/build/dist/Server/Utils/AI/ResourceAccess/ResourceAiAccessSettings.js.map +1 -0
  285. package/build/dist/Server/Utils/AI/ResourceAccess/ResourceAiDeleteCleanup.js +226 -0
  286. package/build/dist/Server/Utils/AI/ResourceAccess/ResourceAiDeleteCleanup.js.map +1 -0
  287. package/build/dist/Server/Utils/AI/ResourceAccess/ResourceCommandJobRunner.js +600 -0
  288. package/build/dist/Server/Utils/AI/ResourceAccess/ResourceCommandJobRunner.js.map +1 -0
  289. package/build/dist/Server/Utils/AI/SRE/AIInvestigationEngine.js +50 -4
  290. package/build/dist/Server/Utils/AI/SRE/AIInvestigationEngine.js.map +1 -1
  291. package/build/dist/Server/Utils/AI/SRE/AlertInvestigationRunner.js +55 -4
  292. package/build/dist/Server/Utils/AI/SRE/AlertInvestigationRunner.js.map +1 -1
  293. package/build/dist/Server/Utils/AI/SRE/IncidentInvestigationRunner.js +55 -4
  294. package/build/dist/Server/Utils/AI/SRE/IncidentInvestigationRunner.js.map +1 -1
  295. package/build/dist/Server/Utils/AutoRemediation/CommandPlanExecutor.js +290 -13
  296. package/build/dist/Server/Utils/AutoRemediation/CommandPlanExecutor.js.map +1 -1
  297. package/build/dist/Server/Utils/AutoRemediation/RemediationVerifier.js +29 -1
  298. package/build/dist/Server/Utils/AutoRemediation/RemediationVerifier.js.map +1 -1
  299. package/build/dist/Server/Utils/Database/ProjectScopedReferenceValidator.js +9 -1
  300. package/build/dist/Server/Utils/Database/ProjectScopedReferenceValidator.js.map +1 -1
  301. package/build/dist/Server/Utils/SessionReplay/SessionReplayBudgetMetrics.js +627 -0
  302. package/build/dist/Server/Utils/SessionReplay/SessionReplayBudgetMetrics.js.map +1 -0
  303. package/build/dist/Server/Utils/SessionReplay/SessionReplayUsage.js +60 -5
  304. package/build/dist/Server/Utils/SessionReplay/SessionReplayUsage.js.map +1 -1
  305. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/Alert.js +19 -15
  306. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/Alert.js.map +1 -1
  307. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/AlertEpisode.js +19 -15
  308. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/AlertEpisode.js.map +1 -1
  309. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/Auth.js +17 -1
  310. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/Auth.js.map +1 -1
  311. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/Incident.js +183 -209
  312. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/Incident.js.map +1 -1
  313. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/IncidentEpisode.js +19 -15
  314. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/IncidentEpisode.js.map +1 -1
  315. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/ScheduledMaintenance.js +233 -167
  316. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/ScheduledMaintenance.js.map +1 -1
  317. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js +263 -110
  318. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js.map +1 -1
  319. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsActivityDeduplicator.js +129 -0
  320. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsActivityDeduplicator.js.map +1 -0
  321. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsCardChoices.js +266 -0
  322. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsCardChoices.js.map +1 -0
  323. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsCreateCommands.js +258 -0
  324. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsCreateCommands.js.map +1 -0
  325. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsMessageSize.js +104 -0
  326. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsMessageSize.js.map +1 -0
  327. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsReplies.js +183 -0
  328. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsReplies.js.map +1 -0
  329. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsTimezone.js +123 -0
  330. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsTimezone.js.map +1 -0
  331. package/build/dist/Types/AI/ResourceAiAccessApi.js +30 -0
  332. package/build/dist/Types/AI/ResourceAiAccessApi.js.map +1 -0
  333. package/build/dist/Types/AI/ResourceAiAccessPermissions.js +98 -0
  334. package/build/dist/Types/AI/ResourceAiAccessPermissions.js.map +1 -0
  335. package/build/dist/Types/AutoRemediation/AiRemediationCommandPlan.js +116 -29
  336. package/build/dist/Types/AutoRemediation/AiRemediationCommandPlan.js.map +1 -1
  337. package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationCatalog.js +47 -21
  338. package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationCatalog.js.map +1 -1
  339. package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationTypes.js +5 -0
  340. package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationTypes.js.map +1 -1
  341. package/build/dist/Types/Monitor/RumAlertTemplates.js +199 -3
  342. package/build/dist/Types/Monitor/RumAlertTemplates.js.map +1 -1
  343. package/build/dist/Types/ResourceAiAgent/AiResourceType.js +242 -0
  344. package/build/dist/Types/ResourceAiAgent/AiResourceType.js.map +1 -0
  345. package/build/dist/Types/ResourceAiAgent/ResourceAiAccess.js +275 -0
  346. package/build/dist/Types/ResourceAiAgent/ResourceAiAccess.js.map +1 -0
  347. package/build/dist/Types/Rum/SessionReplayBudgetMetricType.js +45 -0
  348. package/build/dist/Types/Rum/SessionReplayBudgetMetricType.js.map +1 -0
  349. package/build/dist/Types/Runbook/RunbookStepType.js +27 -0
  350. package/build/dist/Types/Runbook/RunbookStepType.js.map +1 -1
  351. package/build/dist/Types/Telemetry/TelemetryIngestSurface.js +13 -2
  352. package/build/dist/Types/Telemetry/TelemetryIngestSurface.js.map +1 -1
  353. package/build/dist/Utils/AI/InvestigationReport.js +71 -11
  354. package/build/dist/Utils/AI/InvestigationReport.js.map +1 -1
  355. package/build/dist/Utils/AiRemediation/Resource/CephCommandPolicy.js +1462 -0
  356. package/build/dist/Utils/AiRemediation/Resource/CephCommandPolicy.js.map +1 -0
  357. package/build/dist/Utils/AiRemediation/Resource/DatabaseCommandPolicy.js +122 -0
  358. package/build/dist/Utils/AiRemediation/Resource/DatabaseCommandPolicy.js.map +1 -0
  359. package/build/dist/Utils/AiRemediation/Resource/DatabaseDiagnosticCatalog.js +1139 -0
  360. package/build/dist/Utils/AiRemediation/Resource/DatabaseDiagnosticCatalog.js.map +1 -0
  361. package/build/dist/Utils/AiRemediation/Resource/DatabaseQueryRedactor.js +1060 -0
  362. package/build/dist/Utils/AiRemediation/Resource/DatabaseQueryRedactor.js.map +1 -0
  363. package/build/dist/Utils/AiRemediation/Resource/DockerCliGrammar.js +1301 -0
  364. package/build/dist/Utils/AiRemediation/Resource/DockerCliGrammar.js.map +1 -0
  365. package/build/dist/Utils/AiRemediation/Resource/DockerEngineCommandPolicy.js +370 -0
  366. package/build/dist/Utils/AiRemediation/Resource/DockerEngineCommandPolicy.js.map +1 -0
  367. package/build/dist/Utils/AiRemediation/Resource/DockerSwarmCommandPolicy.js +498 -0
  368. package/build/dist/Utils/AiRemediation/Resource/DockerSwarmCommandPolicy.js.map +1 -0
  369. package/build/dist/Utils/AiRemediation/Resource/GovcCommandPolicy.js +1565 -0
  370. package/build/dist/Utils/AiRemediation/Resource/GovcCommandPolicy.js.map +1 -0
  371. package/build/dist/Utils/AiRemediation/Resource/HostCommandPolicy.js +2206 -0
  372. package/build/dist/Utils/AiRemediation/Resource/HostCommandPolicy.js.map +1 -0
  373. package/build/dist/Utils/AiRemediation/Resource/ProxmoxCommandPolicy.js +1129 -0
  374. package/build/dist/Utils/AiRemediation/Resource/ProxmoxCommandPolicy.js.map +1 -0
  375. package/build/dist/Utils/AiRemediation/Resource/ResourceCommandPolicy.js +565 -0
  376. package/build/dist/Utils/AiRemediation/Resource/ResourceCommandPolicy.js.map +1 -0
  377. package/build/dist/Utils/AiRemediation/Resource/ResourceCommandPolicyCore.js +408 -0
  378. package/build/dist/Utils/AiRemediation/Resource/ResourceCommandPolicyCore.js.map +1 -0
  379. package/build/dist/Utils/AiRemediation/Resource/ResourceOutputRedactor.js +1910 -0
  380. package/build/dist/Utils/AiRemediation/Resource/ResourceOutputRedactor.js.map +1 -0
  381. package/build/dist/Utils/SessionReplay/SessionReplayBudgetMetricType.js +160 -0
  382. package/build/dist/Utils/SessionReplay/SessionReplayBudgetMetricType.js.map +1 -0
  383. package/package.json +1 -1
@@ -0,0 +1,1077 @@
1
+ import DatabaseCommandPolicy, {
2
+ databaseSessionTarget,
3
+ getDatabaseReadCommandGuide as reExportedReadGuide,
4
+ getDatabaseWriteCommandGuide as reExportedWriteGuide,
5
+ } from "../../../../Utils/AiRemediation/Resource/DatabaseCommandPolicy";
6
+ import {
7
+ DATABASE_DIAGNOSTIC_OPERATIONS,
8
+ DatabaseOperationSpec,
9
+ getDatabaseReadCommandGuide,
10
+ getDatabaseWriteCommandGuide,
11
+ } from "../../../../Utils/AiRemediation/Resource/DatabaseDiagnosticCatalog";
12
+ import ResourceCommandPolicy from "../../../../Utils/AiRemediation/Resource/ResourceCommandPolicy";
13
+ import {
14
+ MAX_RESOURCE_COMMAND_TOKENS,
15
+ RESOURCE_SHELL_SYNTAX_RULE,
16
+ ResourceAutoExecutionVerdict,
17
+ ResourceCommandPolicyResult,
18
+ tokenizeResourceCommand,
19
+ } from "../../../../Utils/AiRemediation/Resource/ResourceCommandPolicyCore";
20
+ import AiResourceType, {
21
+ AI_RESOURCE_TYPE_INFO,
22
+ } from "../../../../Types/ResourceAiAgent/AiResourceType";
23
+ import {
24
+ RESOURCE_AI_ALLOW_WRITES_ENV,
25
+ RESOURCE_AI_WRITE_TARGETS_ENV,
26
+ ResourceCommandTier,
27
+ } from "../../../../Types/ResourceAiAgent/ResourceAiAccess";
28
+ import {
29
+ AiRemediationCommandPolicyVerdict,
30
+ MAX_COMMAND_LENGTH_CHARS,
31
+ } from "../../../../Types/AutoRemediation/AiRemediationCommandPolicyVerdict";
32
+ import { describe, expect, test } from "@jest/globals";
33
+
34
+ /*
35
+ * Contract under test — DatabaseCommandPolicy, the tier of every `db`
36
+ * command OneUptime AI composes for a database server.
37
+ *
38
+ * - The grammar: `db <operation> [argument] [--flag value|--flag=value]`,
39
+ * the operation first and spelled exactly, long flags only, every flag a
40
+ * typed value that never swallows a flag-looking word, "--" ending the
41
+ * flags, no duplicates, no unknown or connection flags.
42
+ * - Read: every catalog diagnostic. SafeWrite: `db cancel-query ID`.
43
+ * RiskyWrite: `db terminate-session ID`. The target is `session:ID`.
44
+ * - Denied: free SQL / commands / scripts, every other change, unknown
45
+ * operations and flags, bad values, look-alike characters, shell syntax,
46
+ * the wrong program — each with a reason that says what IS available.
47
+ * - The args and displayCommand are the canonical argv, a fixed point.
48
+ * - Totality, and the dispatcher's ladder / allowlist / write scope and
49
+ * guides for DatabaseServer.
50
+ */
51
+
52
+ const DATABASE: AiResourceType = AiResourceType.DatabaseServer;
53
+
54
+ function db(command: string): ResourceCommandPolicyResult {
55
+ return ResourceCommandPolicy.evaluateCommand({
56
+ resourceType: DATABASE,
57
+ command,
58
+ });
59
+ }
60
+
61
+ function direct(argv: unknown): ResourceCommandPolicyResult {
62
+ return DatabaseCommandPolicy.evaluateArgv(argv as Array<string>);
63
+ }
64
+
65
+ function autoExecution(
66
+ command: string,
67
+ options: { allowlistPatterns?: Array<string>; bypassApproval?: boolean } = {},
68
+ ): ResourceAutoExecutionVerdict {
69
+ return ResourceCommandPolicy.evaluateForAutoExecution({
70
+ resourceType: DATABASE,
71
+ command,
72
+ allowlistPatterns: options.allowlistPatterns || [],
73
+ bypassApproval: options.bypassApproval === true,
74
+ });
75
+ }
76
+
77
+ function expectDenied(command: string, mentions: string): void {
78
+ const result: ResourceCommandPolicyResult = db(command);
79
+
80
+ expect(result.tier).toBe(ResourceCommandTier.Denied);
81
+ expect(result.targets).toEqual([]);
82
+ expect(result.reason).toContain(mentions);
83
+ expect(
84
+ ResourceCommandPolicy.isReadOnly({ resourceType: DATABASE, command }),
85
+ ).toBe(false);
86
+ }
87
+
88
+ describe("the db tool policy", () => {
89
+ test("is the DatabaseServer policy, named db, running only db", () => {
90
+ expect(ResourceCommandPolicy.getToolPolicy(DATABASE)).toBe(
91
+ DatabaseCommandPolicy,
92
+ );
93
+ expect(DatabaseCommandPolicy.name).toBe("db");
94
+ expect([...DatabaseCommandPolicy.programs]).toEqual(["db"]);
95
+ expect([...DatabaseCommandPolicy.programs]).toEqual([
96
+ ...AI_RESOURCE_TYPE_INFO[DATABASE].programs,
97
+ ]);
98
+ });
99
+
100
+ test("Test connection runs only Read commands", () => {
101
+ for (const command of AI_RESOURCE_TYPE_INFO[DATABASE].testCommands) {
102
+ expect(db(command).tier).toBe(ResourceCommandTier.Read);
103
+ expect(
104
+ ResourceCommandPolicy.isReadOnly({ resourceType: DATABASE, command }),
105
+ ).toBe(true);
106
+ }
107
+ });
108
+
109
+ test("session targets are session:ID", () => {
110
+ expect(databaseSessionTarget(42)).toBe("session:42");
111
+ expect(databaseSessionTarget("7")).toBe("session:7");
112
+ });
113
+ });
114
+
115
+ describe("Read: every diagnostic in the catalog", () => {
116
+ test.each([
117
+ ["db ping", "ping", "db ping"],
118
+ ["db version", "version", "db version"],
119
+ ["db sessions", "sessions", "db sessions"],
120
+ ["db sessions --limit 10", "sessions", "db sessions --limit 10"],
121
+ ["db sessions --limit=10", "sessions", "db sessions --limit 10"],
122
+ ["db sessions --limit 1", "sessions", "db sessions --limit 1"],
123
+ ["db sessions --limit 200", "sessions", "db sessions --limit 200"],
124
+ ["db sessions --state active", "sessions", "db sessions --state active"],
125
+ ["db sessions --state=idle", "sessions", "db sessions --state idle"],
126
+ [
127
+ "db sessions --state idle-in-transaction",
128
+ "sessions",
129
+ "db sessions --state idle-in-transaction",
130
+ ],
131
+ [
132
+ "db sessions --user app_user --database orders",
133
+ "sessions",
134
+ "db sessions --user app_user --database orders",
135
+ ],
136
+ ["db sessions --database 0", "sessions", "db sessions --database 0"],
137
+ [
138
+ "db sessions --user svc.reporting$1 --database my-db",
139
+ "sessions",
140
+ "db sessions --user 'svc.reporting$1' --database my-db",
141
+ ],
142
+ [
143
+ "db sessions --database=orders --limit 200 --state idle --user bob",
144
+ "sessions",
145
+ "db sessions --limit 200 --state idle --user bob --database orders",
146
+ ],
147
+ ["db current-ops", "sessions", "db sessions"],
148
+ ["db current-ops --limit 5", "sessions", "db sessions --limit 5"],
149
+ ["db long-queries", "long-queries", "db long-queries"],
150
+ [
151
+ "db long-queries --min-seconds 30",
152
+ "long-queries",
153
+ "db long-queries --min-seconds 30",
154
+ ],
155
+ [
156
+ "db long-queries --limit 1 --min-seconds=0",
157
+ "long-queries",
158
+ "db long-queries --min-seconds 0 --limit 1",
159
+ ],
160
+ [
161
+ "db long-queries --min-seconds 86400",
162
+ "long-queries",
163
+ "db long-queries --min-seconds 86400",
164
+ ],
165
+ ["db blocking", "blocking", "db blocking"],
166
+ ["db blocking --limit 20", "blocking", "db blocking --limit 20"],
167
+ ["db locks", "locks", "db locks"],
168
+ ["db locks --limit=200", "locks", "db locks --limit 200"],
169
+ ["db replication", "replication", "db replication"],
170
+ ["db connections", "connections", "db connections"],
171
+ ["db database-sizes", "database-sizes", "db database-sizes"],
172
+ ["db table-sizes", "table-sizes", "db table-sizes"],
173
+ [
174
+ "db table-sizes --limit 25 --database app",
175
+ "table-sizes",
176
+ "db table-sizes --database app --limit 25",
177
+ ],
178
+ ["db top-statements", "top-statements", "db top-statements"],
179
+ [
180
+ "db top-statements --limit 20",
181
+ "top-statements",
182
+ "db top-statements --limit 20",
183
+ ],
184
+ ["db settings", "settings", "db settings"],
185
+ ["db settings work_mem", "settings", "db settings work_mem"],
186
+ ["db settings max_connections", "settings", "db settings max_connections"],
187
+ [
188
+ "db settings maxmemory-policy",
189
+ "settings",
190
+ "db settings maxmemory-policy",
191
+ ],
192
+ [
193
+ "db settings maxIncomingConnections",
194
+ "settings",
195
+ "db settings maxIncomingConnections",
196
+ ],
197
+ [
198
+ "db settings pg_stat_statements.max",
199
+ "settings",
200
+ "db settings pg_stat_statements.max",
201
+ ],
202
+ ["db settings -- work_mem", "settings", "db settings work_mem"],
203
+ ["db slowlog", "slowlog", "db slowlog"],
204
+ ["db slowlog --limit 10", "slowlog", "db slowlog --limit 10"],
205
+ ["db info", "info", "db info"],
206
+ ["db info memory", "info", "db info memory"],
207
+ ["db info commandstats", "info", "db info commandstats"],
208
+ ["db info globalLock", "info", "db info globalLock"],
209
+ ["db info wiredTiger", "info", "db info wiredTiger"],
210
+ ["db innodb-status", "innodb-status", "db innodb-status"],
211
+ ["db memory", "memory", "db memory"],
212
+ ["db keyspace", "keyspace", "db keyspace"],
213
+ ["db ping --", "ping", "db ping"],
214
+ ["db 'sessions' '--limit' '5'", "sessions", "db sessions --limit 5"],
215
+ ['db "settings" "work_mem"', "settings", "db settings work_mem"],
216
+ ])("%s", (command: string, verb: string, display: string) => {
217
+ const result: ResourceCommandPolicyResult = db(command);
218
+
219
+ expect(result.tier).toBe(ResourceCommandTier.Read);
220
+ expect(result.verb).toBe(verb);
221
+ expect(result.program).toBe("db");
222
+ expect(result.displayCommand).toBe(display);
223
+ expect(result.args).toEqual(
224
+ tokenizeResourceCommand(display).argv!.slice(1),
225
+ );
226
+ expect(result.targets).toEqual([]);
227
+ expect(result.requiresHuman).toBeUndefined();
228
+ expect(result.reason).toContain("read-only");
229
+ expect(
230
+ ResourceCommandPolicy.isReadOnly({ resourceType: DATABASE, command }),
231
+ ).toBe(true);
232
+ });
233
+
234
+ test.each(
235
+ DATABASE_DIAGNOSTIC_OPERATIONS.filter(
236
+ (operation: DatabaseOperationSpec): boolean => {
237
+ return operation.tier === ResourceCommandTier.Read;
238
+ },
239
+ ).map((operation: DatabaseOperationSpec): [string] => {
240
+ return [operation.name];
241
+ }),
242
+ )("db %s with no argument is Read", (name: string) => {
243
+ const result: ResourceCommandPolicyResult = db(`db ${name}`);
244
+
245
+ expect(result.tier).toBe(ResourceCommandTier.Read);
246
+ expect(result.verb).toBe(name);
247
+ });
248
+ });
249
+
250
+ describe("SafeWrite and RiskyWrite: one named session", () => {
251
+ test.each([
252
+ ["db cancel-query 42", ResourceCommandTier.SafeWrite, "cancel-query", "42"],
253
+ ["db cancel-query 1", ResourceCommandTier.SafeWrite, "cancel-query", "1"],
254
+ [
255
+ "db cancel-query 999999999999999",
256
+ ResourceCommandTier.SafeWrite,
257
+ "cancel-query",
258
+ "999999999999999",
259
+ ],
260
+ [
261
+ "db cancel-query -- 42",
262
+ ResourceCommandTier.SafeWrite,
263
+ "cancel-query",
264
+ "42",
265
+ ],
266
+ [
267
+ "db 'cancel-query' '42'",
268
+ ResourceCommandTier.SafeWrite,
269
+ "cancel-query",
270
+ "42",
271
+ ],
272
+ [
273
+ "db terminate-session 42",
274
+ ResourceCommandTier.RiskyWrite,
275
+ "terminate-session",
276
+ "42",
277
+ ],
278
+ [
279
+ "db terminate-session 123456",
280
+ ResourceCommandTier.RiskyWrite,
281
+ "terminate-session",
282
+ "123456",
283
+ ],
284
+ [
285
+ "db terminate-session -- 9",
286
+ ResourceCommandTier.RiskyWrite,
287
+ "terminate-session",
288
+ "9",
289
+ ],
290
+ ])(
291
+ "%s",
292
+ (command: string, tier: ResourceCommandTier, verb: string, id: string) => {
293
+ const result: ResourceCommandPolicyResult = db(command);
294
+
295
+ expect(result.tier).toBe(tier);
296
+ expect(result.verb).toBe(verb);
297
+ expect(result.targets).toEqual([`session:${id}`]);
298
+ expect(result.args).toEqual([verb, id]);
299
+ expect(result.displayCommand).toBe(`db ${verb} ${id}`);
300
+ expect(result.requiresHuman).toBeUndefined();
301
+ expect(result.reason).toContain(`session:${id}`);
302
+ expect(
303
+ ResourceCommandPolicy.isReadOnly({ resourceType: DATABASE, command }),
304
+ ).toBe(false);
305
+ },
306
+ );
307
+
308
+ test("the reasons say what each change does", () => {
309
+ expect(db("db cancel-query 42").reason).toContain("stays connected");
310
+ expect(db("db terminate-session 42").reason).toContain("rolling back");
311
+ expect(db("db terminate-session 42").reason).toContain("cannot be undone");
312
+ });
313
+ });
314
+
315
+ describe("Denied: free SQL, database commands and scripts", () => {
316
+ test.each([
317
+ ["db sql 'select 1'"],
318
+ ["db query 'SELECT * FROM users'"],
319
+ ["db exec x"],
320
+ ["db execute 'DROP TABLE users'"],
321
+ ["db eval 'return 1' 0"],
322
+ ["db evalsha abc 0"],
323
+ ["db script load x"],
324
+ ["db select 1"],
325
+ ["db explain 'select 1'"],
326
+ ["db run x"],
327
+ ["db shell"],
328
+ ["db raw 'FLUSHALL'"],
329
+ ["db command '{\"dropDatabase\": 1}'"],
330
+ ["db psql -c x"],
331
+ ["db mysql"],
332
+ ["db mongosh"],
333
+ ["db redis-cli"],
334
+ ["db aggregate x"],
335
+ ["db find users"],
336
+ ])("%s", (command: string) => {
337
+ expectDenied(command, "never runs SQL");
338
+ });
339
+ });
340
+
341
+ describe("Denied: every change but the two session changes", () => {
342
+ test.each([
343
+ ["db config set maxmemory 1gb"],
344
+ ["db config-set maxmemory 1gb"],
345
+ ["db set work_mem 64MB"],
346
+ ["db alter-system x"],
347
+ ["db flushall"],
348
+ ["db flushdb"],
349
+ ["db shutdown"],
350
+ ["db restart"],
351
+ ["db drop table users"],
352
+ ["db truncate users"],
353
+ ["db delete users"],
354
+ ["db del key"],
355
+ ["db insert x"],
356
+ ["db update x"],
357
+ ["db create index x"],
358
+ ["db grant all"],
359
+ ["db revoke all"],
360
+ ["db vacuum"],
361
+ ["db analyze"],
362
+ ["db reindex x"],
363
+ ["db optimize x"],
364
+ ["db bgsave"],
365
+ ["db replicaof no one"],
366
+ ["db failover"],
367
+ ["db client kill id 5"],
368
+ ["db acl setuser x"],
369
+ ["db debug sleep 10"],
370
+ ["db compact users"],
371
+ ])("%s", (command: string) => {
372
+ expectDenied(
373
+ command,
374
+ "the only changes db makes are cancel-query and terminate-session",
375
+ );
376
+ });
377
+
378
+ test.each([
379
+ ["db kill 42"],
380
+ ["db killop 42"],
381
+ ["db kill-query 42"],
382
+ ["db cancel 42"],
383
+ ["db terminate 42"],
384
+ ["db pg_cancel_backend 42"],
385
+ ["db pg_terminate_backend 42"],
386
+ ["db kill-session 42"],
387
+ ["db disconnect 42"],
388
+ ])("%s points at cancel-query and terminate-session", (command: string) => {
389
+ const result: ResourceCommandPolicyResult = db(command);
390
+
391
+ expect(result.tier).toBe(ResourceCommandTier.Denied);
392
+ expect(result.reason).toContain("db cancel-query ID");
393
+ expect(result.reason).toContain("db terminate-session ID");
394
+ });
395
+ });
396
+
397
+ describe("Denied: the operation must be exact", () => {
398
+ test.each([
399
+ ["db foo", "is not a db operation"],
400
+ ["db status", "is not a db operation"],
401
+ ["db help", "is not a db operation"],
402
+ ["db health", "is not a db operation"],
403
+ ["db PING", 'write "db ping"'],
404
+ ["db Sessions", 'write "db sessions"'],
405
+ ["db cancel_query 42", 'write "db cancel-query"'],
406
+ ["db CANCEL-QUERY 42", 'write "db cancel-query"'],
407
+ ["db top_statements", 'write "db top-statements"'],
408
+ ["db Current-Ops", 'write "db sessions"'],
409
+ ["db", "name an operation"],
410
+ ["db ''", "name an operation"],
411
+ ["db --limit 5 sessions", "the operation comes right after"],
412
+ ["db -- ping", "the operation comes right after"],
413
+ ["db --help", "the operation comes right after"],
414
+ ["db -h", "the operation comes right after"],
415
+ ])("%s", (command: string, mentions: string) => {
416
+ expectDenied(command, mentions);
417
+ });
418
+
419
+ test("an unknown operation lists what is available", () => {
420
+ const reason: string = db("db foo").reason;
421
+
422
+ for (const operation of DATABASE_DIAGNOSTIC_OPERATIONS) {
423
+ expect(reason).toContain(operation.name);
424
+ }
425
+ });
426
+ });
427
+
428
+ describe("Denied: flags", () => {
429
+ test.each([
430
+ ["db sessions -l 5", "long flags only"],
431
+ ["db sessions -h", "long flags only"],
432
+ ["db sessions -abc", "long flags only"],
433
+ ["db sessions -5", "long flags only"],
434
+ ["db ping -v", "long flags only"],
435
+ ["db sessions --limit 5 -s idle", "long flags only"],
436
+ [
437
+ "db sessions --verbose",
438
+ "db sessions takes --limit, --state, --user and --database, not --verbose",
439
+ ],
440
+ ["db ping --limit 5", "db ping takes no flags"],
441
+ ["db cancel-query 42 --force", "db cancel-query takes no flags"],
442
+ ["db terminate-session 42 --all", "db terminate-session takes no flags"],
443
+ ["db sessions --sql 'select 1'", "not --sql"],
444
+ ["db settings --all", "db settings takes no flags"],
445
+ ["db long-queries --state idle", "not --state"],
446
+ ["db sessions --=5", "is not a flag db knows"],
447
+ ["db sessions ---limit 5", "is not a flag db knows"],
448
+ ["db sessions --limit_x 5", "is not a flag db knows"],
449
+ ["db sessions '--limit 5'", "is not a flag db knows"],
450
+ ["db sessions --LIMIT 5", "write --limit"],
451
+ ["db sessions --Limit=5", "write --limit"],
452
+ ["db long-queries --min_seconds 5", "write --min-seconds"],
453
+ ["db sessions --host db.example.com", "connects to its own database"],
454
+ ["db ping --password hunter2", "connects to its own database"],
455
+ ["db ping --port=5432", "connects to its own database"],
456
+ ["db sessions --uri postgres://x", "connects to its own database"],
457
+ ["db ping --tls", "connects to its own database"],
458
+ ["db ping --dsn x", "connects to its own database"],
459
+ ["db ping --config /etc/x", "connects to its own database"],
460
+ [
461
+ "db sessions --defaults-file=/root/.my.cnf",
462
+ "connects to its own database",
463
+ ],
464
+ ])("%s", (command: string, mentions: string) => {
465
+ expectDenied(command, mentions);
466
+ });
467
+
468
+ test.each([
469
+ ["db sessions --limit"],
470
+ ["db sessions --limit="],
471
+ ["db sessions --user"],
472
+ ["db sessions --user ''"],
473
+ ["db sessions --limit --state idle"],
474
+ ["db sessions --user --sql"],
475
+ ["db sessions --user -- x"],
476
+ ["db sessions --state -x"],
477
+ ["db sessions --limit -1"],
478
+ ["db long-queries --min-seconds --limit 5"],
479
+ ])(
480
+ "%s: a value-taking flag never swallows a flag-looking word",
481
+ (command: string) => {
482
+ expectDenied(command, "needs a value");
483
+ },
484
+ );
485
+
486
+ test.each([
487
+ ["db sessions --limit 5 --limit 6"],
488
+ ["db sessions --limit 5 --limit=5"],
489
+ ["db sessions --state idle --state=active"],
490
+ ["db table-sizes --database a --database b"],
491
+ ])("%s: each flag once", (command: string) => {
492
+ expectDenied(command, "more than once");
493
+ });
494
+
495
+ test.each([
496
+ ["db sessions --limit 0", "from 1 to 200"],
497
+ ["db sessions --limit 201", "from 1 to 200"],
498
+ ["db sessions --limit 05", "without leading zeros"],
499
+ ["db sessions --limit=-1", "whole number"],
500
+ ["db sessions --limit 1.5", "whole number"],
501
+ ["db sessions --limit 1e2", "whole number"],
502
+ ["db sessions --limit ten", "whole number"],
503
+ ["db sessions --limit 5", "whole number"],
504
+ ["db sessions --limit 99999999999", "whole number"],
505
+ ["db sessions '--limit=5 --sql'", "whole number"],
506
+ ["db sessions --limit=5=6", "whole number"],
507
+ ["db long-queries --min-seconds 86401", "from 0 to 86400"],
508
+ [
509
+ "db sessions --state running",
510
+ "must be one of active, idle, idle-in-transaction",
511
+ ],
512
+ ["db sessions --state ACTIVE", 'write "active"'],
513
+ ["db sessions --user 'bob smith'", "must be a name"],
514
+ ["db sessions --user=-bob", "must be a name"],
515
+ ["db sessions --database 'a;b'", "must be a name"],
516
+ ["db sessions --user 'bob​'", "must be a name"],
517
+ ["db sessions --user 'bоb'", "must be a name"],
518
+ [`db sessions --user ${"a".repeat(129)}`, "must be a name"],
519
+ ])("%s", (command: string, mentions: string) => {
520
+ expectDenied(command, mentions);
521
+ });
522
+
523
+ test("a 128-character name is accepted", () => {
524
+ expect(db(`db sessions --user ${"a".repeat(128)}`).tier).toBe(
525
+ ResourceCommandTier.Read,
526
+ );
527
+ });
528
+ });
529
+
530
+ describe("Denied: arguments", () => {
531
+ test.each([
532
+ ["db ping now", "db ping takes no argument"],
533
+ ["db sessions all", "db sessions takes no argument"],
534
+ ["db sessions ''", "db sessions takes no argument"],
535
+ ["db sessions -- --limit 5", "db sessions takes no argument"],
536
+ ["db settings work_mem shared_buffers", "takes one NAME"],
537
+ ["db settings 'work mem'", "no wildcards"],
538
+ ["db settings 'work_mem*'", "no wildcards"],
539
+ ["db settings '%'", "no wildcards"],
540
+ ["db settings ''", "no wildcards"],
541
+ ["db settings -- -work_mem", "no wildcards"],
542
+ ["db settings .hidden", "no wildcards"],
543
+ [`db settings ${"a".repeat(65)}`, "no wildcards"],
544
+ ["db settings requirepass", "credential setting"],
545
+ ["db settings masterauth", "credential setting"],
546
+ ["db settings primaryauth", "credential setting"],
547
+ ["db settings password_encryption", "credential setting"],
548
+ ["db settings ssl_key_file", "credential setting"],
549
+ ["db settings security.keyFile", "credential setting"],
550
+ ["db info Memory", 'write "memory"'],
551
+ ["db info globallock", 'write "globalLock"'],
552
+ ["db info everything", "must be one of"],
553
+ ["db info all", "must be one of"],
554
+ ["db info memory stats", "takes one SECTION"],
555
+ ["db cancel-query", "db cancel-query needs ID"],
556
+ ["db terminate-session", "db terminate-session needs ID"],
557
+ ["db cancel-query 0", "numeric session id"],
558
+ ["db cancel-query 042", "numeric session id"],
559
+ ["db cancel-query 4.2", "numeric session id"],
560
+ ["db cancel-query abc", "numeric session id"],
561
+ ["db cancel-query 1234567890123456", "numeric session id"],
562
+ ["db cancel-query 42", "numeric session id"],
563
+ ["db cancel-query ' 42'", "numeric session id"],
564
+ ["db cancel-query 0x2A", "numeric session id"],
565
+ ["db terminate-session 1e3", "numeric session id"],
566
+ ["db terminate-session -- -1", "numeric session id"],
567
+ ["db cancel-query session:42", 'write "42"'],
568
+ ["db terminate-session session:42", 'write "42"'],
569
+ ["db cancel-query 42 43", "takes one ID"],
570
+ ["db terminate-session 42 -- 43", "takes one ID"],
571
+ ["db terminate-session -1", "long flags only"],
572
+ ])("%s", (command: string, mentions: string) => {
573
+ expectDenied(command, mentions);
574
+ });
575
+
576
+ test("a 64-character setting name is accepted", () => {
577
+ expect(db(`db settings ${"a".repeat(64)}`).tier).toBe(
578
+ ResourceCommandTier.Read,
579
+ );
580
+ });
581
+ });
582
+
583
+ describe("Denied: look-alike and invisible characters", () => {
584
+ test.each([
585
+ ["db ѕessions", "is not a db operation"],
586
+ ["db sessions —limit 5", "db sessions takes no argument"],
587
+ ["db sessions ‐‐limit 5", "db sessions takes no argument"],
588
+ ["db sessions --limit 5", "db sessions takes no argument"],
589
+ ["db sessions --lіmit 5", "is not a flag db knows"],
590
+ ["db cancel‐query 42", "is not a db operation"],
591
+ ["db 'ping​'", "is not a db operation"],
592
+ ["db 'ping '", "is not a db operation"],
593
+ ["db 'sessions --limit 5'", "is not a db operation"],
594
+ ["db terminate-session '42 '", "numeric session id"],
595
+ ])("%s", (command: string, mentions: string) => {
596
+ expectDenied(command, mentions);
597
+ });
598
+
599
+ test("a look-alike program is not db", () => {
600
+ expectDenied("db ping", "is not a program the Database AI agent runs");
601
+ expectDenied("DB ping", "is not a program the Database AI agent runs");
602
+ expectDenied("/usr/bin/db ping", "without a path");
603
+ });
604
+ });
605
+
606
+ describe("Denied before the policy: shell syntax, privilege, the wrong program, size", () => {
607
+ test.each([
608
+ ["db sessions | grep idle"],
609
+ ["db sessions; db flushall"],
610
+ ["db sessions && db flushall"],
611
+ ["db ping > /tmp/out"],
612
+ ["db ping < /etc/passwd"],
613
+ ["db ping $(id)"],
614
+ ["db ping `id`"],
615
+ ['db ping "$(id)"'],
616
+ ])("%s", (command: string) => {
617
+ expectDenied(command, RESOURCE_SHELL_SYNTAX_RULE);
618
+ });
619
+
620
+ test.each([
621
+ ["sudo db ping", "its own permissions only"],
622
+ ["psql -c 'select 1'", "is not a program the Database AI agent runs"],
623
+ ["mysql -e 'select 1'", "is not a program the Database AI agent runs"],
624
+ ["redis-cli FLUSHALL", "is not a program the Database AI agent runs"],
625
+ ["mongosh --eval x", "is not a program the Database AI agent runs"],
626
+ ["kubectl get pods", "is not a program the Database AI agent runs"],
627
+ ["db ping\ndb flushall", "single line"],
628
+ [
629
+ `db sessions --user ${"a".repeat(MAX_COMMAND_LENGTH_CHARS)}`,
630
+ `${MAX_COMMAND_LENGTH_CHARS}-character limit`,
631
+ ],
632
+ [
633
+ `db sessions${" --limit 5".repeat(MAX_RESOURCE_COMMAND_TOKENS)}`,
634
+ `at most ${MAX_RESOURCE_COMMAND_TOKENS} words`,
635
+ ],
636
+ ["", "Empty command"],
637
+ [" ", "Empty command"],
638
+ ])("%p", (command: string, mentions: string) => {
639
+ expectDenied(command, mentions);
640
+ });
641
+ });
642
+
643
+ describe("displayCommand and args", () => {
644
+ test.each([
645
+ ["db sessions --state idle --limit 5 --user bob"],
646
+ ["db current-ops --database=orders"],
647
+ ["db long-queries --limit=3 --min-seconds=10"],
648
+ ["db settings -- work_mem"],
649
+ ["db cancel-query -- 42"],
650
+ ["db terminate-session 7"],
651
+ ["db info globalLock"],
652
+ ["db sessions --user 'svc$1'"],
653
+ ])("%s is canonical and evaluates to itself", (command: string) => {
654
+ const first: ResourceCommandPolicyResult = db(command);
655
+ const second: ResourceCommandPolicyResult = db(first.displayCommand);
656
+
657
+ expect(first.tier).not.toBe(ResourceCommandTier.Denied);
658
+ expect(second).toEqual(first);
659
+ expect(
660
+ ResourceCommandPolicy.evaluateArgv({
661
+ resourceType: DATABASE,
662
+ argv: ["db", ...first.args],
663
+ }),
664
+ ).toEqual(first);
665
+ expect(tokenizeResourceCommand(first.displayCommand).argv).toEqual([
666
+ "db",
667
+ ...first.args,
668
+ ]);
669
+ });
670
+
671
+ test("a Denied command is shown as written, quoted to round-trip", () => {
672
+ const result: ResourceCommandPolicyResult = db("db sql 'select 1'");
673
+
674
+ expect(result.displayCommand).toBe("db sql 'select 1'");
675
+ expect(result.args).toEqual(["sql", "select 1"]);
676
+ expect(result.verb).toBe("");
677
+ });
678
+
679
+ test("the reason for a refused word quotes it safely, cut when long", () => {
680
+ const reason: string = db(`db ${"x".repeat(300)}`).reason;
681
+
682
+ expect(reason).toContain(`"${"x".repeat(64)}..."`);
683
+ expect(reason).not.toContain("x".repeat(65));
684
+ expect(db("db 'a\"b'").reason).toContain('"a\\"b"');
685
+ });
686
+ });
687
+
688
+ describe("totality", () => {
689
+ test.each([
690
+ [null],
691
+ [undefined],
692
+ [[]],
693
+ [{}],
694
+ ["db ping"],
695
+ [42],
696
+ [[1, 2]],
697
+ [["db", null]],
698
+ [["db", "ping", 7]],
699
+ [["db", {}]],
700
+ [["psql", "ping"]],
701
+ [[""]],
702
+ ])("argv %p is Denied without throwing", (argv: unknown) => {
703
+ const result: ResourceCommandPolicyResult = direct(argv);
704
+
705
+ expect(result.tier).toBe(ResourceCommandTier.Denied);
706
+ expect(result.targets).toEqual([]);
707
+ expect(typeof result.reason).toBe("string");
708
+ expect(result.reason.length).toBeGreaterThan(0);
709
+ });
710
+
711
+ test("a direct call reads the argv exactly like the dispatcher", () => {
712
+ expect(direct(["db", "ping"]).tier).toBe(ResourceCommandTier.Read);
713
+ expect(direct(["db", "cancel-query", "5"]).targets).toEqual(["session:5"]);
714
+ expect(direct(["db", "sessions", "--limit", "5"]).args).toEqual([
715
+ "sessions",
716
+ "--limit",
717
+ "5",
718
+ ]);
719
+ expect(direct(["db", ""]).reason).toContain("name an operation");
720
+ expect(direct(["db", "sessions", ""]).reason).toContain(
721
+ "takes no argument",
722
+ );
723
+ });
724
+
725
+ test("an argv that throws when read is Denied, not thrown", () => {
726
+ const hostile: Array<string> = new Proxy(["db", "ping"], {
727
+ get(): never {
728
+ throw new Error("hostile argv");
729
+ },
730
+ });
731
+
732
+ const result: ResourceCommandPolicyResult = direct(hostile);
733
+
734
+ expect(result.tier).toBe(ResourceCommandTier.Denied);
735
+ expect(result.program).toBe("db");
736
+ expect(result.targets).toEqual([]);
737
+ });
738
+
739
+ test("the caller's argv is never changed", () => {
740
+ const argv: Array<string> = Object.freeze([
741
+ "db",
742
+ "sessions",
743
+ "--limit=5",
744
+ ]) as unknown as Array<string>;
745
+
746
+ expect(direct(argv).tier).toBe(ResourceCommandTier.Read);
747
+ expect(argv).toEqual(["db", "sessions", "--limit=5"]);
748
+ });
749
+
750
+ test("the returned args are a copy", () => {
751
+ const first: ResourceCommandPolicyResult = direct(["db", "ping"]);
752
+ first.args.push("--oops");
753
+
754
+ expect(direct(["db", "ping"]).args).toEqual(["ping"]);
755
+ });
756
+ });
757
+
758
+ describe("the auto-execution ladder for DatabaseServer", () => {
759
+ test.each([
760
+ [
761
+ "db sessions",
762
+ [],
763
+ false,
764
+ AiRemediationCommandPolicyVerdict.AutoApproved,
765
+ ResourceCommandTier.Read,
766
+ ],
767
+ [
768
+ "db cancel-query 42",
769
+ [],
770
+ false,
771
+ AiRemediationCommandPolicyVerdict.AutoApproved,
772
+ ResourceCommandTier.SafeWrite,
773
+ ],
774
+ [
775
+ "db terminate-session 42",
776
+ [],
777
+ false,
778
+ AiRemediationCommandPolicyVerdict.RequiresApproval,
779
+ ResourceCommandTier.RiskyWrite,
780
+ ],
781
+ [
782
+ "db terminate-session 42",
783
+ ["db terminate-session *"],
784
+ false,
785
+ AiRemediationCommandPolicyVerdict.AutoApproved,
786
+ ResourceCommandTier.RiskyWrite,
787
+ ],
788
+ [
789
+ "db terminate-session 42",
790
+ ["db terminate-session 42"],
791
+ false,
792
+ AiRemediationCommandPolicyVerdict.AutoApproved,
793
+ ResourceCommandTier.RiskyWrite,
794
+ ],
795
+ [
796
+ "db terminate-session 42",
797
+ ["db terminate-session 43"],
798
+ false,
799
+ AiRemediationCommandPolicyVerdict.RequiresApproval,
800
+ ResourceCommandTier.RiskyWrite,
801
+ ],
802
+ [
803
+ "db terminate-session 42",
804
+ [],
805
+ true,
806
+ AiRemediationCommandPolicyVerdict.AutoApproved,
807
+ ResourceCommandTier.RiskyWrite,
808
+ ],
809
+ [
810
+ "db terminate-session -- 42",
811
+ ["db terminate-session *"],
812
+ false,
813
+ AiRemediationCommandPolicyVerdict.RequiresApproval,
814
+ ResourceCommandTier.RiskyWrite,
815
+ ],
816
+ [
817
+ "db terminate-session 42",
818
+ ["db sessions"],
819
+ false,
820
+ AiRemediationCommandPolicyVerdict.RequiresApproval,
821
+ ResourceCommandTier.RiskyWrite,
822
+ ],
823
+ [
824
+ "db sql 'select 1'",
825
+ ["db sql *"],
826
+ true,
827
+ AiRemediationCommandPolicyVerdict.Denied,
828
+ ResourceCommandTier.Denied,
829
+ ],
830
+ [
831
+ "db flushall",
832
+ [],
833
+ true,
834
+ AiRemediationCommandPolicyVerdict.Denied,
835
+ ResourceCommandTier.Denied,
836
+ ],
837
+ [
838
+ "db terminate-session session:42",
839
+ ["db terminate-session *"],
840
+ true,
841
+ AiRemediationCommandPolicyVerdict.Denied,
842
+ ResourceCommandTier.Denied,
843
+ ],
844
+ ])(
845
+ "%s (allowlist %p, bypass %p)",
846
+ (
847
+ command: string,
848
+ allowlistPatterns: Array<string>,
849
+ bypassApproval: boolean,
850
+ verdict: AiRemediationCommandPolicyVerdict,
851
+ tier: ResourceCommandTier,
852
+ ) => {
853
+ const result: ResourceAutoExecutionVerdict = autoExecution(command, {
854
+ allowlistPatterns,
855
+ bypassApproval,
856
+ });
857
+
858
+ expect(result.verdict).toBe(verdict);
859
+ expect(result.tier).toBe(tier);
860
+ expect(result.requiresHuman).toBeUndefined();
861
+ },
862
+ );
863
+
864
+ test("an allowlisted change says so; a Denied one says it never runs", () => {
865
+ expect(
866
+ autoExecution("db terminate-session 42", {
867
+ allowlistPatterns: ["db terminate-session *"],
868
+ }).reason,
869
+ ).toBe("Matched the resource's command allowlist.");
870
+ expect(autoExecution("db flushall").reason).toContain(
871
+ "cannot run even with human approval",
872
+ );
873
+ });
874
+ });
875
+
876
+ describe("the allowlist for DatabaseServer", () => {
877
+ test.each([
878
+ ["db terminate-session 42", ["db terminate-session *"], true],
879
+ ["db terminate-session 42", ["db terminate-session 42"], true],
880
+ ["db terminate-session 42", ["db terminate-session 4"], false],
881
+ ["db terminate-session 42", ["db terminate-session 4*"], false],
882
+ ["db cancel-query 42", ["db cancel-query *"], true],
883
+ ["db cancel-query 42", ["db terminate-session *"], false],
884
+ ["db terminate-session 42", ["db * 42"], false],
885
+ ["db terminate-session 42", ["db *"], false],
886
+ ["db terminate-session 42", ["psql *"], false],
887
+ ["db sessions", ["db sessions"], false],
888
+ ["db sessions --limit 5", ["db sessions --limit *"], false],
889
+ ])(
890
+ "%s against %p",
891
+ (command: string, patterns: Array<string>, expected: boolean) => {
892
+ expect(
893
+ ResourceCommandPolicy.matchesAllowlist({
894
+ resourceType: DATABASE,
895
+ command,
896
+ patterns,
897
+ }),
898
+ ).toBe(expected);
899
+ },
900
+ );
901
+
902
+ test.each([
903
+ ["db terminate-session *", null],
904
+ ["db terminate-session 42", null],
905
+ ["db cancel-query *", null],
906
+ ["db cancel-query 7", null],
907
+ ["db sessions --limit *", "read-only"],
908
+ ["db info *", "can never match a command that runs"],
909
+ ["db ping *", "can never match a command that runs"],
910
+ ["db sql *", "can never match a command that runs"],
911
+ ["db flushall *", "can never match a command that runs"],
912
+ ["db *", "fewer than two words"],
913
+ ["db terminate-session", "fewer than two words"],
914
+ ["db * 42", "has a * where the command goes"],
915
+ ["psql -c *", "does not start with a program"],
916
+ ["", "cannot be blank"],
917
+ ["db terminate-session *; db flushall", "cannot be read as one command"],
918
+ ])("entry %p", (pattern: string, problem: string | null) => {
919
+ const described: string | null =
920
+ ResourceCommandPolicy.describeAllowlistPatternProblem({
921
+ resourceType: DATABASE,
922
+ pattern,
923
+ });
924
+
925
+ if (problem === null) {
926
+ expect(described).toBeNull();
927
+ } else {
928
+ expect(described).toContain(problem);
929
+ }
930
+ });
931
+
932
+ test.each([
933
+ ["db terminate-session *", true],
934
+ ["db cancel-query *", true],
935
+ ["db terminate-session 42", false],
936
+ ["db cancel-query 7", false],
937
+ ["db sessions --limit *", false],
938
+ ["db sql *", false],
939
+ ])("%s is broad: %p", (pattern: string, broad: boolean) => {
940
+ expect(
941
+ ResourceCommandPolicy.isBroadAllowlistPattern({
942
+ resourceType: DATABASE,
943
+ pattern,
944
+ }),
945
+ ).toBe(broad);
946
+ });
947
+
948
+ test("the allowlist as a whole", () => {
949
+ expect(
950
+ ResourceCommandPolicy.describeAllowlistProblems({
951
+ resourceType: DATABASE,
952
+ patterns: ["db terminate-session *", "db cancel-query *"],
953
+ }),
954
+ ).toBeNull();
955
+ expect(
956
+ ResourceCommandPolicy.describeAllowlistProblems({
957
+ resourceType: DATABASE,
958
+ patterns: ["db terminate-session *", "db sessions"],
959
+ }),
960
+ ).toContain("fewer than two words");
961
+ });
962
+ });
963
+
964
+ describe("the agent's write scope for DatabaseServer", () => {
965
+ function scope(
966
+ command: string,
967
+ posture: {
968
+ allowWrites?: boolean;
969
+ writeTargets?: Array<string>;
970
+ protectedTargets?: Array<string>;
971
+ } = {},
972
+ ): string | null {
973
+ return ResourceCommandPolicy.getWriteScopeRefusal({
974
+ result: db(command),
975
+ allowWrites: posture.allowWrites !== false,
976
+ writeTargets: posture.writeTargets || [],
977
+ protectedTargets: posture.protectedTargets || [],
978
+ resourceType: DATABASE,
979
+ });
980
+ }
981
+
982
+ test("a read is never refused, even by a read-only agent", () => {
983
+ expect(scope("db sessions", { allowWrites: false })).toBeNull();
984
+ expect(
985
+ scope("db long-queries", {
986
+ allowWrites: false,
987
+ writeTargets: ["session:1"],
988
+ protectedTargets: ["session:*"],
989
+ }),
990
+ ).toBeNull();
991
+ });
992
+
993
+ test("a read-only agent refuses both changes, naming the switch", () => {
994
+ for (const command of ["db cancel-query 42", "db terminate-session 42"]) {
995
+ const refusal: string | null = scope(command, { allowWrites: false });
996
+
997
+ expect(refusal).toContain(`${RESOURCE_AI_ALLOW_WRITES_ENV}=true`);
998
+ expect(refusal).toContain("Database AI agent");
999
+ }
1000
+ });
1001
+
1002
+ test("a writable agent without scope runs a session change", () => {
1003
+ expect(scope("db cancel-query 42")).toBeNull();
1004
+ expect(scope("db terminate-session 42")).toBeNull();
1005
+ });
1006
+
1007
+ test("the agent's own session is protected", () => {
1008
+ expect(
1009
+ scope("db terminate-session 42", { protectedTargets: ["session:42"] }),
1010
+ ).toContain("protects");
1011
+ expect(
1012
+ scope("db cancel-query 42", { protectedTargets: ["session:4*"] }),
1013
+ ).toContain("protects");
1014
+ expect(
1015
+ scope("db cancel-query 42", { protectedTargets: ["session:43"] }),
1016
+ ).toBeNull();
1017
+ });
1018
+
1019
+ test("ONEUPTIME_AI_WRITE_TARGETS bounds which sessions change", () => {
1020
+ expect(
1021
+ scope("db terminate-session 12", { writeTargets: ["session:1*"] }),
1022
+ ).toBeNull();
1023
+
1024
+ const refusal: string | null = scope("db terminate-session 42", {
1025
+ writeTargets: ["session:1*"],
1026
+ });
1027
+
1028
+ expect(refusal).toContain("session:42");
1029
+ expect(refusal).toContain(RESOURCE_AI_WRITE_TARGETS_ENV);
1030
+ });
1031
+
1032
+ test("a Denied command never runs", () => {
1033
+ expect(scope("db flushall")).toContain("denied by the command policy");
1034
+ });
1035
+ });
1036
+
1037
+ describe("the guides", () => {
1038
+ test("come from the catalog, through the dispatcher and the re-exports", () => {
1039
+ expect(DatabaseCommandPolicy.readCommandGuide).toBe(
1040
+ getDatabaseReadCommandGuide(),
1041
+ );
1042
+ expect(DatabaseCommandPolicy.writeCommandGuide).toBe(
1043
+ getDatabaseWriteCommandGuide(),
1044
+ );
1045
+ expect(ResourceCommandPolicy.getReadCommandGuide(DATABASE)).toBe(
1046
+ DatabaseCommandPolicy.readCommandGuide,
1047
+ );
1048
+ expect(ResourceCommandPolicy.getWriteCommandGuide(DATABASE)).toBe(
1049
+ DatabaseCommandPolicy.writeCommandGuide,
1050
+ );
1051
+ expect(reExportedReadGuide).toBe(getDatabaseReadCommandGuide);
1052
+ expect(reExportedWriteGuide).toBe(getDatabaseWriteCommandGuide);
1053
+ });
1054
+
1055
+ test("every command a guide shows is the tier it claims", () => {
1056
+ const usageRegex: RegExp = /^- `(db [a-z-]+)[ `]/;
1057
+
1058
+ for (const line of DatabaseCommandPolicy.readCommandGuide.split("\n")) {
1059
+ const usage: RegExpExecArray | null = usageRegex.exec(line);
1060
+
1061
+ if (usage && usage[1] !== "db <operation>") {
1062
+ expect(db(usage[1]!).tier).toBe(ResourceCommandTier.Read);
1063
+ }
1064
+ }
1065
+
1066
+ expect(DatabaseCommandPolicy.writeCommandGuide).toContain(
1067
+ "`db cancel-query ID` (safe",
1068
+ );
1069
+ expect(db("db cancel-query 1").tier).toBe(ResourceCommandTier.SafeWrite);
1070
+ expect(DatabaseCommandPolicy.writeCommandGuide).toContain(
1071
+ "`db terminate-session ID` (risky",
1072
+ );
1073
+ expect(db("db terminate-session 1").tier).toBe(
1074
+ ResourceCommandTier.RiskyWrite,
1075
+ );
1076
+ });
1077
+ });