@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,851 @@
1
+ /*
2
+ * The resource command policy: the ONE entry point every caller uses to
3
+ * decide what a command for an infrastructure resource may do — the server's
4
+ * investigation and remediation tools, the enqueue chokepoint
5
+ * (RunnerJobService.enqueueAiResourceCommand), the approval path, the
6
+ * dashboard's allowlist form and the resource AI agent itself.
7
+ *
8
+ * It tokenizes (never a shell), checks that the command starts with one of
9
+ * the resource type's programs, dispatches the argv to that type's tool
10
+ * policy, and wraps the answer in the shared rules: the auto-execution
11
+ * ladder, the allowlist, and the agent's write scope (read-only unless
12
+ * ONEUPTIME_AI_ALLOW_WRITES=true, only ONEUPTIME_AI_WRITE_TARGETS, never the
13
+ * agent's own protected targets).
14
+ *
15
+ * Import-closed like the rest of this directory (see
16
+ * ResourceCommandPolicyCore): the agent carries a byte-identical copy.
17
+ */
18
+
19
+ import AiResourceType, {
20
+ AI_RESOURCE_TYPE_INFO,
21
+ AiResourceTypeInfo,
22
+ isAiResourceType,
23
+ } from "../../../Types/ResourceAiAgent/AiResourceType";
24
+ import {
25
+ RESOURCE_AI_ALLOW_WRITES_ENV,
26
+ RESOURCE_AI_WRITE_TARGETS_ENV,
27
+ ResourceCommandTier,
28
+ } from "../../../Types/ResourceAiAgent/ResourceAiAccess";
29
+ import { MAX_COMMAND_LENGTH_CHARS } from "../../../Types/AutoRemediation/AiRemediationCommandPolicyVerdict";
30
+ import {
31
+ ALLOWLIST_WILDCARD_TOKEN,
32
+ MAX_RESOURCE_COMMAND_TOKENS,
33
+ ResourceAutoExecutionVerdict,
34
+ ResourceCommandPolicyResult,
35
+ ResourceTokenizeResult,
36
+ ResourceToolPolicy,
37
+ allowlistPatternMatches,
38
+ applyAutoExecutionLadder,
39
+ deniedResult,
40
+ getPrivilegeEscalationRefusal,
41
+ globMatchesTarget,
42
+ tokenizeResourceCommand,
43
+ } from "./ResourceCommandPolicyCore";
44
+ import DockerEngineCommandPolicy from "./DockerEngineCommandPolicy";
45
+ import DockerSwarmCommandPolicy from "./DockerSwarmCommandPolicy";
46
+ import ProxmoxCommandPolicy from "./ProxmoxCommandPolicy";
47
+ import GovcCommandPolicy from "./GovcCommandPolicy";
48
+ import CephCommandPolicy from "./CephCommandPolicy";
49
+ import DatabaseCommandPolicy from "./DatabaseCommandPolicy";
50
+ import HostCommandPolicy from "./HostCommandPolicy";
51
+
52
+ /*
53
+ * Bounds on a resource's command allowlist, exported so the server's save
54
+ * validation and the dashboard's form hold entries to exactly what the
55
+ * matcher reads.
56
+ */
57
+ export const RESOURCE_ALLOWLIST_MAX_PATTERNS: number = 50;
58
+ export const RESOURCE_ALLOWLIST_MAX_PATTERN_LENGTH: number = 500;
59
+
60
+ /*
61
+ * Values a `*` in an allowlist entry is tried as, when deciding whether the
62
+ * entry could ever pre-approve a change: two names, two large numbers (a
63
+ * pid, a VMID) and two small ones (an OSD id), plus the words the tool's
64
+ * own grammar accepts there (ResourceToolPolicy.allowlistStandIns). The
65
+ * entry is valid when ANY combination makes it a write. Two values of each
66
+ * kind let isBroadAllowlistPattern see whether a `*` changes what a write
67
+ * touches.
68
+ */
69
+ const GENERIC_WILDCARD_STAND_INS: ReadonlyArray<string> = [
70
+ "placeholder-1",
71
+ "placeholder-2",
72
+ "1000",
73
+ "1001",
74
+ "1",
75
+ "2",
76
+ ];
77
+
78
+ /*
79
+ * How many combinations of stand-ins an entry is tried with at most. Every
80
+ * `*` multiplies them, so an entry with many `*`s is only partly explored —
81
+ * it can then be refused as "can never match" although some value would
82
+ * make it a write, which fails toward pre-approving less.
83
+ */
84
+ const MAX_WILDCARD_COMBINATIONS: number = 4096;
85
+
86
+ // Which tool policy answers for each resource type.
87
+ const TOOL_POLICY_BY_TYPE: Readonly<
88
+ Record<AiResourceType, ResourceToolPolicy>
89
+ > = {
90
+ [AiResourceType.DockerHost]: DockerEngineCommandPolicy,
91
+ [AiResourceType.PodmanHost]: DockerEngineCommandPolicy,
92
+ [AiResourceType.DockerSwarmCluster]: DockerSwarmCommandPolicy,
93
+ [AiResourceType.ProxmoxCluster]: ProxmoxCommandPolicy,
94
+ [AiResourceType.VMwareVCenter]: GovcCommandPolicy,
95
+ [AiResourceType.CephCluster]: CephCommandPolicy,
96
+ [AiResourceType.DatabaseServer]: DatabaseCommandPolicy,
97
+ [AiResourceType.Host]: HostCommandPolicy,
98
+ };
99
+
100
+ // Refuses everything, for a resource type this build does not know.
101
+ const UNKNOWN_TYPE_POLICY: ResourceToolPolicy = {
102
+ name: "unknown",
103
+ programs: [],
104
+ readCommandGuide:
105
+ "- Unavailable: this resource type has no command policy, so every command is refused.",
106
+ writeCommandGuide:
107
+ "- Unavailable: this resource type has no command policy, so every command is refused.",
108
+ evaluateArgv(argv: Array<string>): ResourceCommandPolicyResult {
109
+ return deniedResult(
110
+ argv,
111
+ "this resource type has no command policy, so every command is refused",
112
+ );
113
+ },
114
+ };
115
+
116
+ const ALL_TIERS: ReadonlyArray<string> = Object.values(ResourceCommandTier);
117
+
118
+ function isWriteTier(tier: ResourceCommandTier): boolean {
119
+ return (
120
+ tier === ResourceCommandTier.SafeWrite ||
121
+ tier === ResourceCommandTier.RiskyWrite
122
+ );
123
+ }
124
+
125
+ // Hex a container or image id (or a prefix of one) is written in.
126
+ const HEX_ID_REGEX: RegExp = /^[0-9a-f]+$/;
127
+ const FULL_HEX_ID_REGEX: RegExp = /^[0-9a-f]{12,}$/;
128
+
129
+ /*
130
+ * Does this target name a protected one? Over-matching is the safe
131
+ * direction here, so the comparison is case-insensitive, ignores a leading
132
+ * "/" (docker prints container names as "/name"), honours `*` in the
133
+ * protected entry, and treats a hex word as the id PREFIX docker would
134
+ * resolve it as ("3f2a" names the protected container 3f2a9c...).
135
+ */
136
+ function isProtectedTarget(target: string, protectedTarget: string): boolean {
137
+ const left: string = target.trim().replace(/^\/+/, "").toLowerCase();
138
+ const right: string = protectedTarget
139
+ .trim()
140
+ .replace(/^\/+/, "")
141
+ .toLowerCase();
142
+
143
+ if (!left || !right) {
144
+ return false;
145
+ }
146
+
147
+ if (left === right || globMatchesTarget(right, left)) {
148
+ return true;
149
+ }
150
+
151
+ return (
152
+ HEX_ID_REGEX.test(left) &&
153
+ FULL_HEX_ID_REGEX.test(right) &&
154
+ right.startsWith(left)
155
+ );
156
+ }
157
+
158
+ function typeInfo(resourceType: AiResourceType): AiResourceTypeInfo | null {
159
+ return isAiResourceType(resourceType)
160
+ ? AI_RESOURCE_TYPE_INFO[resourceType]
161
+ : null;
162
+ }
163
+
164
+ /*
165
+ * A tool policy's answer, checked before anyone acts on it: a tool that
166
+ * throws, returns something that is not a result, or names a tier that does
167
+ * not exist is read as Denied. The program is always argv[0] (the dispatcher
168
+ * already checked it against the type's programs, and a job's payload is
169
+ * built from this result); the arguments the tool normalized are kept; a
170
+ * missing list becomes [].
171
+ */
172
+ function sanitizeToolResult(
173
+ argv: Array<string>,
174
+ raw: unknown,
175
+ ): ResourceCommandPolicyResult {
176
+ if (!raw || typeof raw !== "object") {
177
+ return deniedResult(
178
+ argv,
179
+ "the command policy returned no verdict for this command",
180
+ );
181
+ }
182
+
183
+ const result: Record<string, unknown> = raw as Record<string, unknown>;
184
+ const tier: unknown = result["tier"];
185
+
186
+ if (typeof tier !== "string" || !ALL_TIERS.includes(tier)) {
187
+ return deniedResult(
188
+ argv,
189
+ "the command policy returned an unknown tier for this command",
190
+ );
191
+ }
192
+
193
+ const words: (value: unknown) => Array<string> = (
194
+ value: unknown,
195
+ ): Array<string> => {
196
+ return Array.isArray(value)
197
+ ? value.filter((word: unknown): word is string => {
198
+ return typeof word === "string";
199
+ })
200
+ : [];
201
+ };
202
+
203
+ const reason: unknown = result["reason"];
204
+ const verb: unknown = result["verb"];
205
+ const displayCommand: unknown = result["displayCommand"];
206
+
207
+ const sanitized: ResourceCommandPolicyResult = {
208
+ tier: tier as ResourceCommandTier,
209
+ reason:
210
+ typeof reason === "string" && reason ? reason : "no reason was given",
211
+ program: argv[0] || "",
212
+ args: Array.isArray(result["args"]) ? words(result["args"]) : argv.slice(1),
213
+ verb: typeof verb === "string" ? verb : "",
214
+ displayCommand:
215
+ typeof displayCommand === "string" && displayCommand
216
+ ? displayCommand
217
+ : deniedResult(argv, "").displayCommand,
218
+ targets: words(result["targets"]),
219
+ };
220
+
221
+ if (result["requiresHuman"] === true) {
222
+ sanitized.requiresHuman = true;
223
+ }
224
+
225
+ return sanitized;
226
+ }
227
+
228
+ export default class ResourceCommandPolicy {
229
+ /*
230
+ * The tool policy for a resource type: DockerHost and PodmanHost share the
231
+ * docker engine policy, DockerSwarmCluster has the swarm one, and so on.
232
+ * An unknown type gets a policy that refuses everything.
233
+ */
234
+ public static getToolPolicy(
235
+ resourceType: AiResourceType,
236
+ ): ResourceToolPolicy {
237
+ if (!isAiResourceType(resourceType)) {
238
+ return UNKNOWN_TYPE_POLICY;
239
+ }
240
+
241
+ return TOOL_POLICY_BY_TYPE[resourceType];
242
+ }
243
+
244
+ // Tokenize (never a shell), then evaluate the argv.
245
+ public static evaluateCommand(data: {
246
+ resourceType: AiResourceType;
247
+ command: string;
248
+ }): ResourceCommandPolicyResult {
249
+ const command: string =
250
+ data && typeof data.command === "string" ? data.command : "";
251
+ const tokenized: ResourceTokenizeResult = tokenizeResourceCommand(command);
252
+
253
+ if (!tokenized.argv) {
254
+ return {
255
+ tier: ResourceCommandTier.Denied,
256
+ reason: tokenized.errorMessage || "Could not parse the command.",
257
+ program: "",
258
+ args: [],
259
+ verb: "",
260
+ displayCommand: command.trim().slice(0, 200),
261
+ targets: [],
262
+ };
263
+ }
264
+
265
+ return ResourceCommandPolicy.evaluateArgv({
266
+ resourceType: data.resourceType,
267
+ argv: tokenized.argv,
268
+ });
269
+ }
270
+
271
+ /*
272
+ * The evaluation proper, on an argv that includes the program. The agent
273
+ * calls this on the argv it received, so its verdict never depends on
274
+ * re-tokenizing a string the same way the server did. Fails closed on
275
+ * anything malformed before a tool policy ever sees it.
276
+ */
277
+ public static evaluateArgv(data: {
278
+ resourceType: AiResourceType;
279
+ argv: Array<string>;
280
+ }): ResourceCommandPolicyResult {
281
+ const rawArgv: unknown = data ? data.argv : undefined;
282
+
283
+ if (!Array.isArray(rawArgv) || rawArgv.length === 0) {
284
+ return deniedResult([], "Empty command.");
285
+ }
286
+
287
+ if (
288
+ rawArgv.some((word: unknown): boolean => {
289
+ return typeof word !== "string";
290
+ })
291
+ ) {
292
+ return deniedResult(
293
+ rawArgv as Array<string>,
294
+ "Every word of the command must be a string.",
295
+ );
296
+ }
297
+
298
+ const argv: Array<string> = (rawArgv as Array<string>).slice();
299
+
300
+ if (argv.length > MAX_RESOURCE_COMMAND_TOKENS) {
301
+ return deniedResult(
302
+ argv,
303
+ `A command may have at most ${MAX_RESOURCE_COMMAND_TOKENS} words.`,
304
+ );
305
+ }
306
+
307
+ const totalLength: number = argv.reduce(
308
+ (sum: number, word: string): number => {
309
+ return sum + word.length;
310
+ },
311
+ 0,
312
+ );
313
+
314
+ if (totalLength > MAX_COMMAND_LENGTH_CHARS) {
315
+ return deniedResult(
316
+ argv,
317
+ `Command exceeds the ${MAX_COMMAND_LENGTH_CHARS}-character limit.`,
318
+ );
319
+ }
320
+
321
+ if (
322
+ argv.some((word: string): boolean => {
323
+ return (
324
+ word.includes("\n") || word.includes("\r") || word.includes("\0")
325
+ );
326
+ })
327
+ ) {
328
+ return deniedResult(
329
+ argv,
330
+ "A command must be a single line: no word may hold a newline or a NUL character.",
331
+ );
332
+ }
333
+
334
+ const program: string = argv[0] || "";
335
+ const privilegeRefusal: string | null =
336
+ getPrivilegeEscalationRefusal(program);
337
+
338
+ if (privilegeRefusal) {
339
+ return deniedResult(argv, privilegeRefusal);
340
+ }
341
+
342
+ const info: AiResourceTypeInfo | null = typeInfo(data.resourceType);
343
+
344
+ if (!info) {
345
+ return deniedResult(
346
+ argv,
347
+ "this resource type has no command policy, so every command is refused",
348
+ );
349
+ }
350
+
351
+ if (!info.programs.includes(program)) {
352
+ const programList: string = info.programs
353
+ .map((name: string): string => {
354
+ return `"${name}"`;
355
+ })
356
+ .join(", ");
357
+
358
+ return deniedResult(
359
+ argv,
360
+ `"${program}" is not a program the ${info.agentDisplayName} runs: a command for a ${info.displayName} starts with ${programList}${
361
+ program.includes("/")
362
+ ? " (write the program name without a path)"
363
+ : ""
364
+ }`,
365
+ );
366
+ }
367
+
368
+ const tool: ResourceToolPolicy = ResourceCommandPolicy.getToolPolicy(
369
+ data.resourceType,
370
+ );
371
+
372
+ if (!tool.programs.includes(program)) {
373
+ return deniedResult(
374
+ argv,
375
+ `the ${tool.name} command policy does not cover "${program}"`,
376
+ );
377
+ }
378
+
379
+ let raw: unknown;
380
+
381
+ try {
382
+ // A copy: a tool policy must never be able to change the caller's argv.
383
+ raw = tool.evaluateArgv(argv.slice());
384
+ } catch {
385
+ return deniedResult(
386
+ argv,
387
+ `the ${tool.name} command policy could not evaluate this command`,
388
+ );
389
+ }
390
+
391
+ return sanitizeToolResult(argv, raw);
392
+ }
393
+
394
+ public static isReadOnly(data: {
395
+ resourceType: AiResourceType;
396
+ command: string;
397
+ }): boolean {
398
+ return (
399
+ ResourceCommandPolicy.evaluateCommand(data).tier ===
400
+ ResourceCommandTier.Read
401
+ );
402
+ }
403
+
404
+ /*
405
+ * The remediation verdict for one command under a resource's settings
406
+ * (see applyAutoExecutionLadder). The allowlist is consulted only for a
407
+ * RiskyWrite, the one tier it can promote.
408
+ */
409
+ public static evaluateForAutoExecution(data: {
410
+ resourceType: AiResourceType;
411
+ command: string;
412
+ allowlistPatterns: Array<string>;
413
+ bypassApproval: boolean;
414
+ }): ResourceAutoExecutionVerdict {
415
+ const result: ResourceCommandPolicyResult =
416
+ ResourceCommandPolicy.evaluateCommand({
417
+ resourceType: data.resourceType,
418
+ command: data.command,
419
+ });
420
+
421
+ const allowlistMatched: boolean =
422
+ result.tier === ResourceCommandTier.RiskyWrite &&
423
+ result.requiresHuman !== true &&
424
+ ResourceCommandPolicy.matchesAllowlist({
425
+ resourceType: data.resourceType,
426
+ command: data.command,
427
+ patterns: data.allowlistPatterns,
428
+ });
429
+
430
+ return applyAutoExecutionLadder(result, {
431
+ allowlistMatched,
432
+ bypassApproval: data.bypassApproval === true,
433
+ });
434
+ }
435
+
436
+ /*
437
+ * Whether any of the resource's allowlist entries names this command,
438
+ * word by word (allowlistPatternMatches). Only the first
439
+ * RESOURCE_ALLOWLIST_MAX_PATTERNS entries are read, and an entry
440
+ * describeAllowlistPatternProblem refuses is skipped — so what the matcher
441
+ * reads and what the server and the dashboard accept are one set.
442
+ * Tier-blind: the ladder decides what a match may promote.
443
+ */
444
+ public static matchesAllowlist(data: {
445
+ resourceType: AiResourceType;
446
+ command: string;
447
+ patterns: Array<string>;
448
+ }): boolean {
449
+ const tokenized: ResourceTokenizeResult = tokenizeResourceCommand(
450
+ data ? data.command : "",
451
+ );
452
+
453
+ if (!tokenized.argv || !Array.isArray(data.patterns)) {
454
+ return false;
455
+ }
456
+
457
+ const patterns: Array<unknown> = data.patterns.slice(
458
+ 0,
459
+ RESOURCE_ALLOWLIST_MAX_PATTERNS,
460
+ );
461
+
462
+ for (const pattern of patterns) {
463
+ if (
464
+ ResourceCommandPolicy.describeAllowlistPatternProblem({
465
+ resourceType: data.resourceType,
466
+ pattern,
467
+ }) !== null
468
+ ) {
469
+ continue;
470
+ }
471
+
472
+ const patternArgv: Array<string> | undefined = tokenizeResourceCommand(
473
+ pattern as string,
474
+ ).argv;
475
+
476
+ if (patternArgv && allowlistPatternMatches(patternArgv, tokenized.argv)) {
477
+ return true;
478
+ }
479
+ }
480
+
481
+ return false;
482
+ }
483
+
484
+ /*
485
+ * Why an allowlist entry can never pre-approve anything, in words for the
486
+ * person typing it — or null when it is valid. The ONE definition of a
487
+ * valid entry: the server validates saves with it, the dashboard validates
488
+ * its form with it, and matchesAllowlist skips every entry it refuses.
489
+ * (The number of entries is checked by describeAllowlistProblems.)
490
+ */
491
+ public static describeAllowlistPatternProblem(data: {
492
+ resourceType: AiResourceType;
493
+ pattern: unknown;
494
+ }): string | null {
495
+ const pattern: unknown = data ? data.pattern : undefined;
496
+
497
+ if (typeof pattern !== "string" || !pattern.trim()) {
498
+ return "An allowlist entry cannot be blank.";
499
+ }
500
+
501
+ if (pattern.length > RESOURCE_ALLOWLIST_MAX_PATTERN_LENGTH) {
502
+ return `An allowlist entry can be at most ${RESOURCE_ALLOWLIST_MAX_PATTERN_LENGTH} characters long.`;
503
+ }
504
+
505
+ const shown: string = pattern.trim();
506
+ const info: AiResourceTypeInfo | null = typeInfo(data.resourceType);
507
+
508
+ if (!info) {
509
+ return `"${shown}" cannot be checked: this resource type has no command policy.`;
510
+ }
511
+
512
+ const tokenized: ResourceTokenizeResult = tokenizeResourceCommand(pattern);
513
+
514
+ if (!tokenized.argv) {
515
+ return `"${shown}" cannot be read as one command: ${
516
+ tokenized.errorMessage || "it could not be split into words."
517
+ }`;
518
+ }
519
+
520
+ const argv: Array<string> = tokenized.argv;
521
+ const program: string = argv[0] || "";
522
+
523
+ if (!info.programs.includes(program)) {
524
+ return `"${shown}" does not start with a program the ${
525
+ info.agentDisplayName
526
+ } runs (${info.programs.join(", ")}), so it can never match one of its commands.`;
527
+ }
528
+
529
+ if (argv.length < 3) {
530
+ return `"${shown}" has fewer than two words after "${program}", so it can never name a change to pre-approve. Write out the full command, with a * for each word that may vary.`;
531
+ }
532
+
533
+ if (argv[1] === ALLOWLIST_WILDCARD_TOKEN) {
534
+ return `"${shown}" has a * where the command goes (right after "${program}"). A * stands for exactly one word, and that word decides what kind of change runs, so write it out.`;
535
+ }
536
+
537
+ const results: Array<ResourceCommandPolicyResult> =
538
+ ResourceCommandPolicy.evaluateWithStandIns(data.resourceType, argv);
539
+
540
+ if (
541
+ results.some((result: ResourceCommandPolicyResult): boolean => {
542
+ return isWriteTier(result.tier);
543
+ })
544
+ ) {
545
+ return null;
546
+ }
547
+
548
+ const read: ResourceCommandPolicyResult | undefined = results.find(
549
+ (result: ResourceCommandPolicyResult): boolean => {
550
+ return result.tier === ResourceCommandTier.Read;
551
+ },
552
+ );
553
+
554
+ if (read) {
555
+ return `"${shown}" is a read-only command (${read.reason}). Reads never need approval, so an allowlist entry for one pre-approves nothing.`;
556
+ }
557
+
558
+ return `"${shown}" can never match a command that runs: ${
559
+ results[0] ? results[0].reason : "the command policy refuses it"
560
+ }.`;
561
+ }
562
+
563
+ /*
564
+ * Every problem with a whole allowlist, or null when it is valid: not a
565
+ * list, more than RESOURCE_ALLOWLIST_MAX_PATTERNS entries, or the first
566
+ * entry describeAllowlistPatternProblem refuses.
567
+ */
568
+ public static describeAllowlistProblems(data: {
569
+ resourceType: AiResourceType;
570
+ patterns: unknown;
571
+ }): string | null {
572
+ const patterns: unknown = data ? data.patterns : undefined;
573
+
574
+ if (!Array.isArray(patterns)) {
575
+ return "The allowlist must be a list of commands.";
576
+ }
577
+
578
+ if (patterns.length > RESOURCE_ALLOWLIST_MAX_PATTERNS) {
579
+ return `An allowlist can hold at most ${RESOURCE_ALLOWLIST_MAX_PATTERNS} entries (this one has ${patterns.length}).`;
580
+ }
581
+
582
+ for (const pattern of patterns) {
583
+ const problem: string | null =
584
+ ResourceCommandPolicy.describeAllowlistPatternProblem({
585
+ resourceType: data.resourceType,
586
+ pattern,
587
+ });
588
+
589
+ if (problem) {
590
+ return problem;
591
+ }
592
+ }
593
+
594
+ return null;
595
+ }
596
+
597
+ /*
598
+ * Does this allowlist entry pre-approve changes to objects it does not
599
+ * name? True when a `*` stands for a target of the change (a container, a
600
+ * service, a VM, a unit, a pid, ...) — the dashboard asks for an explicit
601
+ * confirmation before saving such an entry. An invalid entry is never
602
+ * broad: it is refused before anyone could be asked to confirm it.
603
+ */
604
+ public static isBroadAllowlistPattern(data: {
605
+ resourceType: AiResourceType;
606
+ pattern: unknown;
607
+ }): boolean {
608
+ if (ResourceCommandPolicy.describeAllowlistPatternProblem(data) !== null) {
609
+ return false;
610
+ }
611
+
612
+ const argv: Array<string> | undefined = tokenizeResourceCommand(
613
+ data.pattern as string,
614
+ ).argv;
615
+
616
+ if (!argv) {
617
+ return false;
618
+ }
619
+
620
+ if (!argv.includes(ALLOWLIST_WILDCARD_TOKEN)) {
621
+ return false;
622
+ }
623
+
624
+ /*
625
+ * A `*` names a target when putting different words in its place
626
+ * changes what the write touches: the entry then pre-approves changes
627
+ * to objects nobody typed. A `*` in a value (a timeout, a replica
628
+ * count) leaves the targets alone.
629
+ */
630
+ const targetSets: Set<string> = new Set<string>();
631
+
632
+ for (const result of ResourceCommandPolicy.evaluateWithStandIns(
633
+ data.resourceType,
634
+ argv,
635
+ )) {
636
+ if (!isWriteTier(result.tier)) {
637
+ continue;
638
+ }
639
+
640
+ targetSets.add(JSON.stringify([...result.targets].sort()));
641
+
642
+ if (targetSets.size > 1) {
643
+ return true;
644
+ }
645
+ }
646
+
647
+ return false;
648
+ }
649
+
650
+ /*
651
+ * Where the agent's own posture stops a write, or null when it may run.
652
+ * The same rule is asked at every enforcement point — the remediation
653
+ * tools, the enqueue chokepoint, the approval path and the agent — with
654
+ * the agent's reported (or, on the agent, configured) posture:
655
+ * - a read is never refused here;
656
+ * - a Denied command is refused (it never runs anywhere);
657
+ * - an agent without ONEUPTIME_AI_ALLOW_WRITES=true runs no write;
658
+ * - a write never touches one of the agent's protected targets;
659
+ * - with ONEUPTIME_AI_WRITE_TARGETS set, every target must match one of
660
+ * its globs, and a write that names no target is refused (it cannot
661
+ * be shown to stay inside them).
662
+ */
663
+ public static getWriteScopeRefusal(data: {
664
+ result: ResourceCommandPolicyResult;
665
+ allowWrites: boolean;
666
+ writeTargets: Array<string>;
667
+ protectedTargets: Array<string>;
668
+ resourceType: AiResourceType;
669
+ }): string | null {
670
+ const result: ResourceCommandPolicyResult | undefined = data
671
+ ? data.result
672
+ : undefined;
673
+
674
+ if (!result || typeof result !== "object") {
675
+ return "The command could not be evaluated, so it cannot run.";
676
+ }
677
+
678
+ if (result.tier === ResourceCommandTier.Read) {
679
+ return null;
680
+ }
681
+
682
+ const info: AiResourceTypeInfo | null = typeInfo(data.resourceType);
683
+ const agentName: string = info ? info.agentDisplayName : "AI agent";
684
+ const shown: string = result.displayCommand || "this command";
685
+
686
+ if (!isWriteTier(result.tier)) {
687
+ return `"${shown}" is denied by the command policy (${result.reason}), so it never runs.`;
688
+ }
689
+
690
+ if (data.allowWrites !== true) {
691
+ return `The ${agentName} for this ${
692
+ info ? info.displayName : "resource"
693
+ } is read-only, so it refuses every change, including "${shown}". To let OneUptime AI change it, set ${RESOURCE_AI_ALLOW_WRITES_ENV}=true on the agent and restart it.`;
694
+ }
695
+
696
+ const targets: Array<string> = Array.isArray(result.targets)
697
+ ? result.targets.filter((target: unknown): target is string => {
698
+ return typeof target === "string" && target.trim().length > 0;
699
+ })
700
+ : [];
701
+
702
+ const protectedTargets: Array<string> = Array.isArray(data.protectedTargets)
703
+ ? data.protectedTargets.filter((entry: unknown): entry is string => {
704
+ return typeof entry === "string" && entry.trim().length > 0;
705
+ })
706
+ : [];
707
+
708
+ const toolPolicy: ResourceToolPolicy = ResourceCommandPolicy.getToolPolicy(
709
+ data.resourceType,
710
+ );
711
+
712
+ for (const target of targets) {
713
+ const protectedTarget: string | undefined = protectedTargets.find(
714
+ (entry: string): boolean => {
715
+ if (isProtectedTarget(target, entry)) {
716
+ return true;
717
+ }
718
+
719
+ if (!toolPolicy.isProtectedTarget) {
720
+ return false;
721
+ }
722
+
723
+ try {
724
+ return toolPolicy.isProtectedTarget(target, entry) !== false;
725
+ } catch {
726
+ // Over-matching is the safe direction.
727
+ return true;
728
+ }
729
+ },
730
+ );
731
+
732
+ if (protectedTarget !== undefined) {
733
+ return `"${shown}" would change ${target}, which the ${agentName} protects (${protectedTarget}): OneUptime AI never changes the agent itself or what it runs in.`;
734
+ }
735
+ }
736
+
737
+ const writeTargets: Array<string> = Array.isArray(data.writeTargets)
738
+ ? data.writeTargets
739
+ .filter((entry: unknown): entry is string => {
740
+ return typeof entry === "string";
741
+ })
742
+ .map((entry: string): string => {
743
+ return entry.trim();
744
+ })
745
+ .filter((entry: string): boolean => {
746
+ return entry.length > 0;
747
+ })
748
+ : [];
749
+
750
+ if (writeTargets.length === 0) {
751
+ return null;
752
+ }
753
+
754
+ const allowed: string = `${RESOURCE_AI_WRITE_TARGETS_ENV}=${writeTargets.join(",")}`;
755
+
756
+ if (targets.length === 0) {
757
+ return `"${shown}" does not name the objects it changes, and the ${agentName} only changes the targets its ${allowed} allows. Leave this change to a human, or clear ${RESOURCE_AI_WRITE_TARGETS_ENV} on the agent.`;
758
+ }
759
+
760
+ for (const target of targets) {
761
+ const inScope: boolean = writeTargets.some((glob: string): boolean => {
762
+ return globMatchesTarget(glob, target);
763
+ });
764
+
765
+ if (!inScope) {
766
+ return `"${shown}" would change ${target}, which is outside the targets the ${agentName} may change (${allowed}). Add it to ${RESOURCE_AI_WRITE_TARGETS_ENV} on the agent and restart it, or leave this change to a human.`;
767
+ }
768
+ }
769
+
770
+ return null;
771
+ }
772
+
773
+ // The tool's read-command cheat-sheet, for the investigation tool's description.
774
+ public static getReadCommandGuide(resourceType: AiResourceType): string {
775
+ return ResourceCommandPolicy.getToolPolicy(resourceType).readCommandGuide;
776
+ }
777
+
778
+ // The tool's write-command cheat-sheet, for the remediation tools' descriptions.
779
+ public static getWriteCommandGuide(resourceType: AiResourceType): string {
780
+ return ResourceCommandPolicy.getToolPolicy(resourceType).writeCommandGuide;
781
+ }
782
+
783
+ /*
784
+ * The entry's argv evaluated with its `*`s replaced by every combination
785
+ * of stand-ins (the generic ones and the tool's own), up to
786
+ * MAX_WILDCARD_COMBINATIONS. An entry without a `*` is evaluated once.
787
+ */
788
+ private static evaluateWithStandIns(
789
+ resourceType: AiResourceType,
790
+ argv: Array<string>,
791
+ ): Array<ResourceCommandPolicyResult> {
792
+ const positions: Array<number> = [];
793
+
794
+ argv.forEach((word: string, index: number): void => {
795
+ if (word === ALLOWLIST_WILDCARD_TOKEN) {
796
+ positions.push(index);
797
+ }
798
+ });
799
+
800
+ if (positions.length === 0) {
801
+ return [ResourceCommandPolicy.evaluateArgv({ resourceType, argv })];
802
+ }
803
+
804
+ const toolStandIns: ReadonlyArray<string> =
805
+ ResourceCommandPolicy.getToolPolicy(resourceType).allowlistStandIns || [];
806
+
807
+ const candidates: Array<string> = Array.from(
808
+ new Set<string>([...GENERIC_WILDCARD_STAND_INS, ...toolStandIns]),
809
+ ).filter((word: string): boolean => {
810
+ return typeof word === "string" && word !== ALLOWLIST_WILDCARD_TOKEN;
811
+ });
812
+
813
+ const results: Array<ResourceCommandPolicyResult> = [];
814
+
815
+ // One counter per `*`, counting in base candidates.length.
816
+ const counters: Array<number> = positions.map((): number => {
817
+ return 0;
818
+ });
819
+
820
+ while (results.length < MAX_WILDCARD_COMBINATIONS) {
821
+ const concrete: Array<string> = [...argv];
822
+
823
+ positions.forEach((position: number, index: number): void => {
824
+ concrete[position] = candidates[counters[index] || 0] || "";
825
+ });
826
+
827
+ results.push(
828
+ ResourceCommandPolicy.evaluateArgv({ resourceType, argv: concrete }),
829
+ );
830
+
831
+ let carry: number = counters.length - 1;
832
+
833
+ while (carry >= 0) {
834
+ counters[carry] = (counters[carry] || 0) + 1;
835
+
836
+ if ((counters[carry] || 0) < candidates.length) {
837
+ break;
838
+ }
839
+
840
+ counters[carry] = 0;
841
+ carry--;
842
+ }
843
+
844
+ if (carry < 0) {
845
+ break;
846
+ }
847
+ }
848
+
849
+ return results;
850
+ }
851
+ }