@oneuptime/common 14.0.1 → 14.0.3

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 (1241) hide show
  1. package/Models/DatabaseModels/AlertEpisodeMember.ts +8 -1
  2. package/Models/DatabaseModels/AlertFeed.ts +2 -0
  3. package/Models/DatabaseModels/AutoRemediationSuggestion.ts +63 -0
  4. package/Models/DatabaseModels/IncidentAlert.ts +540 -0
  5. package/Models/DatabaseModels/IncidentEpisodeMember.ts +8 -1
  6. package/Models/DatabaseModels/IncidentEpisodePublicNote.ts +9 -2
  7. package/Models/DatabaseModels/IncidentFeed.ts +2 -0
  8. package/Models/DatabaseModels/IncidentPublicNote.ts +9 -2
  9. package/Models/DatabaseModels/Index.ts +2 -0
  10. package/Models/DatabaseModels/KubernetesCluster.ts +429 -0
  11. package/Models/DatabaseModels/Monitor.ts +48 -0
  12. package/Models/DatabaseModels/Project.ts +60 -0
  13. package/Models/DatabaseModels/RumApplication.ts +52 -1
  14. package/Models/DatabaseModels/Runner.ts +5 -4
  15. package/Models/DatabaseModels/RunnerJob.ts +66 -0
  16. package/Models/DatabaseModels/ScheduledMaintenancePublicNote.ts +10 -2
  17. package/Models/DatabaseModels/WorkflowVariable.ts +479 -2
  18. package/Models/DatabaseModels/WorkspaceProjectAuthToken.ts +79 -25
  19. package/Server/API/AIInvestigationAPI.ts +341 -0
  20. package/Server/API/AutoRemediationAPI.ts +184 -2
  21. package/Server/API/CommonAPI.ts +70 -0
  22. package/Server/API/KubernetesClusterAiAccessAPI.ts +793 -0
  23. package/Server/API/MicrosoftTeamsAPI.ts +770 -315
  24. package/Server/API/MonitorAPI.ts +140 -0
  25. package/Server/API/OnCallScheduleTimelineAPI.ts +5 -21
  26. package/Server/API/SlackAPI.ts +447 -99
  27. package/Server/API/StatusPageAPI.ts +146 -26
  28. package/Server/API/TelemetryAPI.ts +216 -5
  29. package/Server/API/UserTwoFactorBackupCodeAPI.ts +1 -0
  30. package/Server/API/WorkflowVariableAPI.ts +156 -0
  31. package/Server/Infrastructure/GlobalCache.ts +35 -0
  32. package/Server/Infrastructure/Postgres/SchemaMigrations/1794300000000-AddOAuth2WorkflowVariables.ts +97 -0
  33. package/Server/Infrastructure/Postgres/SchemaMigrations/1794400000000-AddKubernetesClusterAiAccess.ts +129 -0
  34. package/Server/Infrastructure/Postgres/SchemaMigrations/1794500000000-AddIncomingEmailCustomAddressToMonitor.ts +25 -0
  35. package/Server/Infrastructure/Postgres/SchemaMigrations/1794600000000-AddAuthTokenExpiresAtToWorkspaceProjectAuthToken.ts +20 -0
  36. package/Server/Infrastructure/Postgres/SchemaMigrations/1794700000000-RemoveAppAccessTokenFromWorkspaceProjectAuthTokenMiscData.ts +38 -0
  37. package/Server/Infrastructure/Postgres/SchemaMigrations/1794800000000-AddSessionReplaySameOriginTracePropagation.ts +28 -0
  38. package/Server/Infrastructure/Postgres/SchemaMigrations/1794900000000-AddIncidentAlert.ts +89 -0
  39. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +14 -0
  40. package/Server/Middleware/MasterAdminAuthorization.ts +28 -0
  41. package/Server/Middleware/TelemetryIngest.ts +47 -2
  42. package/Server/Middleware/UserAuthorization.ts +56 -2
  43. package/Server/Services/AIAgentService.ts +1 -0
  44. package/Server/Services/AccessTokenService.ts +121 -48
  45. package/Server/Services/AlertEpisodeMemberService.ts +9 -0
  46. package/Server/Services/AlertEpisodeService.ts +14 -1
  47. package/Server/Services/AlertService.ts +134 -22
  48. package/Server/Services/AutoRemediationRuleEngineService.ts +968 -39
  49. package/Server/Services/AutoRemediationRuleService.ts +118 -0
  50. package/Server/Services/BillingService.ts +1 -0
  51. package/Server/Services/InboundEmail/Providers/SendGridInboundProvider.ts +16 -22
  52. package/Server/Services/IncidentAlertService.ts +1811 -0
  53. package/Server/Services/IncidentEpisodeMemberService.ts +9 -0
  54. package/Server/Services/IncidentEpisodePublicNoteService.ts +66 -0
  55. package/Server/Services/IncidentEpisodeRoleMemberService.ts +27 -0
  56. package/Server/Services/IncidentEpisodeService.ts +14 -1
  57. package/Server/Services/IncidentGroupingEngineService.ts +11 -0
  58. package/Server/Services/IncidentMemberService.ts +21 -0
  59. package/Server/Services/IncidentPublicNoteService.ts +63 -0
  60. package/Server/Services/IncidentService.ts +330 -30
  61. package/Server/Services/IncidentStateTimelineService.ts +39 -0
  62. package/Server/Services/IncidentTemplateService.ts +83 -3
  63. package/Server/Services/Index.ts +2 -0
  64. package/Server/Services/KubernetesClusterAiAccessService.ts +1943 -0
  65. package/Server/Services/KubernetesClusterService.ts +1570 -1
  66. package/Server/Services/LogAggregationService.ts +14 -6
  67. package/Server/Services/MonitorService.ts +651 -52
  68. package/Server/Services/MonitorStatusTimelineService.ts +639 -2
  69. package/Server/Services/OnCallDutyPolicyEscalationRuleScheduleService.ts +2 -0
  70. package/Server/Services/OnCallDutyPolicyEscalationRuleTeamService.ts +2 -0
  71. package/Server/Services/OnCallDutyPolicyEscalationRuleUserService.ts +2 -0
  72. package/Server/Services/OnCallDutyPolicyScheduleService.ts +3 -0
  73. package/Server/Services/OnCallNotificationAlertingService.ts +36 -12
  74. package/Server/Services/OnCallSetupReminderService.ts +1 -0
  75. package/Server/Services/ProbeService.ts +7 -1
  76. package/Server/Services/ProjectService.ts +11 -1
  77. package/Server/Services/RunbookCredentialService.ts +26 -1
  78. package/Server/Services/RunbookSecretService.ts +36 -0
  79. package/Server/Services/RunnerJobService.ts +941 -23
  80. package/Server/Services/RunnerService.ts +439 -6
  81. package/Server/Services/ScheduledMaintenancePublicNoteService.ts +66 -0
  82. package/Server/Services/ScheduledMaintenanceService.ts +124 -19
  83. package/Server/Services/ScheduledMaintenanceTemplateService.ts +82 -3
  84. package/Server/Services/ServiceLevelObjectiveService.ts +14 -1
  85. package/Server/Services/StatusPagePrivateUserService.ts +1 -0
  86. package/Server/Services/StatusPageService.ts +301 -74
  87. package/Server/Services/StatusPageSubscriberService.ts +4 -0
  88. package/Server/Services/TeamMemberService.ts +309 -7
  89. package/Server/Services/TraceAggregationService.ts +10 -6
  90. package/Server/Services/UserEmailService.ts +1 -0
  91. package/Server/Services/UserNotificationMethodAdminService.ts +1 -0
  92. package/Server/Services/UserNotificationRuleAdminService.ts +1 -0
  93. package/Server/Services/UserNotificationRuleService.ts +4 -0
  94. package/Server/Services/UserService.ts +122 -1
  95. package/Server/Services/WorkflowVariableService.ts +593 -8
  96. package/Server/Services/WorkspaceNotificationRuleService.ts +588 -8
  97. package/Server/Services/WorkspaceProjectAuthTokenService.ts +170 -1
  98. package/Server/Types/Database/QueryHelper.ts +22 -0
  99. package/Server/Types/Markdown.ts +502 -27
  100. package/Server/Utils/AI/ClusterAccess/ClusterAccessContext.ts +182 -0
  101. package/Server/Utils/AI/ClusterAccess/KubectlInvestigationToolkit.ts +525 -0
  102. package/Server/Utils/AI/ClusterAccess/KubectlJobRunner.ts +854 -0
  103. package/Server/Utils/AI/CodeFix/CodeFixAgentAuth.ts +22 -2
  104. package/Server/Utils/AI/Remediation/RemediationCommandTools.ts +1916 -307
  105. package/Server/Utils/AI/Remediation/RemediationExecutionRunner.ts +1601 -74
  106. package/Server/Utils/AI/SRE/AIInvestigationEngine.ts +139 -7
  107. package/Server/Utils/AI/SRE/AlertInvestigationRunner.ts +58 -1
  108. package/Server/Utils/AI/SRE/IncidentInvestigationRunner.ts +54 -1
  109. package/Server/Utils/AI/Toolbox/AIActionTools.ts +14 -6
  110. package/Server/Utils/AI/Toolbox/ResourceTools.ts +4 -2
  111. package/Server/Utils/AutoRemediation/CommandPlanExecutor.ts +1341 -150
  112. package/Server/Utils/AutoRemediation/RemediationVerifier.ts +375 -4
  113. package/Server/Utils/Database/AffectedResourceRelations.ts +127 -0
  114. package/Server/Utils/Database/ProjectScopedReferenceValidator.ts +240 -1
  115. package/Server/Utils/EmailRollup/EmailRollupFlushRunner.ts +1 -0
  116. package/Server/Utils/Monitor/MonitorAlert.ts +83 -9
  117. package/Server/Utils/Monitor/MonitorCriteriaObservationBuilder.ts +5 -1
  118. package/Server/Utils/Monitor/MonitorIncident.ts +104 -9
  119. package/Server/Utils/Monitor/MonitorPayloadRedaction.ts +124 -7
  120. package/Server/Utils/Monitor/ProbeMonitorsNotification.ts +407 -0
  121. package/Server/Utils/OnCall/OnCallShiftReminderRunner.ts +1 -0
  122. package/Server/Utils/PushNotificationUtil.ts +45 -0
  123. package/Server/Utils/Rules/OwnerRuleAssignment.ts +40 -3
  124. package/Server/Utils/Runbook/RunbookExecutePermission.ts +56 -6
  125. package/Server/Utils/SessionReplay/SessionReplayGateCache.ts +24 -2
  126. package/Server/Utils/SessionReplay/SessionReplayReadService.ts +223 -33
  127. package/Server/Utils/SessionReplay/SessionReplayUserFlowReadService.ts +559 -0
  128. package/Server/Utils/StartServer.ts +4 -3
  129. package/Server/Utils/TeamMember/ProjectLeaveResourceCleanup.ts +528 -0
  130. package/Server/Utils/TwoFactorBackupCodeNotification.ts +1 -0
  131. package/Server/Utils/UserPermission/UserPermission.ts +16 -0
  132. package/Server/Utils/Workflow/OAuth2TokenClient.ts +704 -0
  133. package/Server/Utils/Workflow/WorkflowVariableOAuthToken.ts +318 -0
  134. package/Server/Utils/Workspace/MicrosoftTeams/Actions/Alert.ts +47 -7
  135. package/Server/Utils/Workspace/MicrosoftTeams/Actions/AlertEpisode.ts +57 -16
  136. package/Server/Utils/Workspace/MicrosoftTeams/Actions/Incident.ts +193 -214
  137. package/Server/Utils/Workspace/MicrosoftTeams/Actions/IncidentEpisode.ts +57 -13
  138. package/Server/Utils/Workspace/MicrosoftTeams/Actions/Monitor.ts +54 -17
  139. package/Server/Utils/Workspace/MicrosoftTeams/Actions/ScheduledMaintenance.ts +179 -161
  140. package/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.ts +281 -167
  141. package/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsServiceUrl.ts +114 -0
  142. package/Server/Utils/Workspace/MicrosoftTeams/ReactionNoteSync.ts +895 -0
  143. package/Server/Utils/Workspace/Slack/Actions/ActionTypes.ts +7 -9
  144. package/Server/Utils/Workspace/Slack/Actions/Alert.ts +96 -227
  145. package/Server/Utils/Workspace/Slack/Actions/AlertEpisode.ts +93 -214
  146. package/Server/Utils/Workspace/Slack/Actions/Auth.ts +30 -3
  147. package/Server/Utils/Workspace/Slack/Actions/Authorization.ts +99 -0
  148. package/Server/Utils/Workspace/Slack/Actions/Incident.ts +117 -283
  149. package/Server/Utils/Workspace/Slack/Actions/IncidentEpisode.ts +101 -196
  150. package/Server/Utils/Workspace/Slack/Actions/ReactionNote.ts +329 -0
  151. package/Server/Utils/Workspace/Slack/Actions/ScheduledMaintenance.ts +111 -287
  152. package/Server/Utils/Workspace/Slack/Slack.ts +86 -17
  153. package/Server/Utils/Workspace/Slack/app-manifest.json +2 -0
  154. package/Server/Utils/Workspace/Workspace.ts +171 -54
  155. package/Server/Utils/Workspace/WorkspaceActionAuthorization.ts +252 -0
  156. package/Server/Utils/Workspace/WorkspaceBase.ts +39 -0
  157. package/Server/Utils/Workspace/WorkspaceOAuthState.ts +280 -0
  158. package/Server/Utils/Workspace/WorkspaceProjectReferenceValidator.ts +96 -0
  159. package/Server/Utils/Workspace/WorkspaceReactionNote.ts +620 -0
  160. package/Tests/App/Dashboard/AttributesJSONDashboardSurfaces.test.tsx +496 -0
  161. package/Tests/App/Dashboard/AutoRemediationRulesTableCommandRunners.test.tsx +152 -0
  162. package/Tests/App/Dashboard/BreadcrumbCoverage.test.tsx +32 -0
  163. package/Tests/App/Dashboard/BulkIncidentLinkActions.test.tsx +869 -0
  164. package/Tests/App/Dashboard/CephMetricTooltips.test.tsx +1777 -0
  165. package/Tests/App/Dashboard/CloudFleetSummary.test.ts +8 -0
  166. package/Tests/App/Dashboard/CloudMetricTooltips.test.tsx +887 -0
  167. package/Tests/App/Dashboard/ClusterAccessNotice.test.tsx +794 -0
  168. package/Tests/App/Dashboard/ContainerHostMetricTooltips.test.tsx +1309 -0
  169. package/Tests/App/Dashboard/CreateOAuthWorkflowVariableModal.test.tsx +840 -0
  170. package/Tests/App/Dashboard/CreateWorkflowModal.test.tsx +653 -0
  171. package/Tests/App/Dashboard/DatabaseMonitorStepForm.test.tsx +197 -0
  172. package/Tests/App/Dashboard/DatabaseMonitorView.test.tsx +376 -0
  173. package/Tests/App/Dashboard/DisabledWarningRobustness.test.tsx +262 -0
  174. package/Tests/App/Dashboard/DiscoveryScanLivePage.test.tsx +39 -0
  175. package/Tests/App/Dashboard/DockerSwarmClustersListTooltips.test.tsx +414 -0
  176. package/Tests/App/Dashboard/DockerSwarmMetricTooltips.test.ts +796 -0
  177. package/Tests/App/Dashboard/DockerSwarmOverviewTooltips.test.tsx +747 -0
  178. package/Tests/App/Dashboard/EventNotes.test.tsx +2080 -0
  179. package/Tests/App/Dashboard/EventNotesPages.test.tsx +486 -0
  180. package/Tests/App/Dashboard/EventNotesUtil.test.ts +933 -0
  181. package/Tests/App/Dashboard/ExceptionMonitorEnvironmentFilter.test.tsx +238 -0
  182. package/Tests/App/Dashboard/HostDetailViewTooltips.test.tsx +725 -0
  183. package/Tests/App/Dashboard/HostListColumnTooltips.test.tsx +472 -0
  184. package/Tests/App/Dashboard/HostMetricTooltips.test.ts +709 -0
  185. package/Tests/App/Dashboard/HostOverviewTooltips.test.tsx +698 -0
  186. package/Tests/App/Dashboard/HostTooltipHarness.ts +124 -0
  187. package/Tests/App/Dashboard/HostsListTooltips.test.tsx +395 -0
  188. package/Tests/App/Dashboard/IncidentAlertLinkDialog.test.tsx +691 -0
  189. package/Tests/App/Dashboard/IncidentAlertLinkHelpers.test.ts +458 -0
  190. package/Tests/App/Dashboard/IncidentAlertLinkPages.test.tsx +828 -0
  191. package/Tests/App/Dashboard/IncidentAlertLinkSideMenus.test.tsx +231 -0
  192. package/Tests/App/Dashboard/IncidentChangeStateNotifyDefault.test.tsx +665 -0
  193. package/Tests/App/Dashboard/IncidentCreateFromAlerts.test.tsx +689 -0
  194. package/Tests/App/Dashboard/IncidentEpisodeFeedPublicNoteNotifyDefault.test.tsx +494 -0
  195. package/Tests/App/Dashboard/IncidentEpisodeOverviewNotifyDefault.test.tsx +706 -0
  196. package/Tests/App/Dashboard/IncidentFeedPublicNoteNotifyDefault.test.tsx +472 -0
  197. package/Tests/App/Dashboard/IncidentOverviewNotifyDefault.test.tsx +858 -0
  198. package/Tests/App/Dashboard/IncomingEmailAddressSettings.test.tsx +567 -0
  199. package/Tests/App/Dashboard/InvestigationClusterToolFormat.test.ts +241 -0
  200. package/Tests/App/Dashboard/InvestigationEvidenceKubectl.test.tsx +322 -0
  201. package/Tests/App/Dashboard/InvestigationPanel.test.tsx +12 -0
  202. package/Tests/App/Dashboard/InvestigationPanelClusterAccess.test.tsx +476 -0
  203. package/Tests/App/Dashboard/InvestigationRunDetailsKubectl.test.tsx +383 -0
  204. package/Tests/App/Dashboard/IoTMetricTooltips.test.tsx +1123 -0
  205. package/Tests/App/Dashboard/KubectlActivitySummary.test.tsx +366 -0
  206. package/Tests/App/Dashboard/KubernetesClusterAiAccessSettings.test.ts +2886 -0
  207. package/Tests/App/Dashboard/KubernetesClusterAiPage.test.tsx +2688 -0
  208. package/Tests/App/Dashboard/KubernetesClusterAiPageServerParity.test.ts +915 -0
  209. package/Tests/App/Dashboard/KubernetesClusterMetricTooltips.test.ts +837 -0
  210. package/Tests/App/Dashboard/KubernetesClusterOverviewTooltips.test.tsx +699 -0
  211. package/Tests/App/Dashboard/KubernetesContainersTabTooltips.test.tsx +320 -0
  212. package/Tests/App/Dashboard/KubernetesCostTooltips.test.tsx +502 -0
  213. package/Tests/App/Dashboard/KubernetesInsightsTooltips.test.tsx +222 -0
  214. package/Tests/App/Dashboard/KubernetesResourceMetricTooltips.test.ts +561 -0
  215. package/Tests/App/Dashboard/KubernetesResourcePagesTooltips.test.tsx +1168 -0
  216. package/Tests/App/Dashboard/LayerDateTimeFieldTimezoneName.test.tsx +66 -0
  217. package/Tests/App/Dashboard/LinkIncidentAlertModal.test.tsx +154 -0
  218. package/Tests/App/Dashboard/LogMonitorPreview.test.tsx +174 -0
  219. package/Tests/App/Dashboard/MetricDescriptionRules.ts +170 -0
  220. package/Tests/App/Dashboard/MetricDescriptionsCatalog.test.ts +206 -0
  221. package/Tests/App/Dashboard/MetricDescriptionsConsistency.test.ts +275 -0
  222. package/Tests/App/Dashboard/MonitorFeedRefresh.test.tsx +279 -0
  223. package/Tests/App/Dashboard/MonitorMetricQueryConfig.test.ts +244 -0
  224. package/Tests/App/Dashboard/MonitorOpenWorkCard.test.tsx +381 -0
  225. package/Tests/App/Dashboard/MonitorOpenWorkHook.test.tsx +784 -0
  226. package/Tests/App/Dashboard/MonitorOverviewData.test.tsx +2199 -0
  227. package/Tests/App/Dashboard/MonitorOverviewHero.test.tsx +1169 -0
  228. package/Tests/App/Dashboard/MonitorOverviewInput.test.ts +1127 -0
  229. package/Tests/App/Dashboard/MonitorOverviewPage.test.tsx +2136 -0
  230. package/Tests/App/Dashboard/MonitorOverviewSelectReadable.test.ts +368 -0
  231. package/Tests/App/Dashboard/MonitorOverviewStatBar.test.tsx +526 -0
  232. package/Tests/App/Dashboard/MonitorOverviewSupportingCards.test.tsx +542 -0
  233. package/Tests/App/Dashboard/MonitorOwnersCombine.test.ts +299 -0
  234. package/Tests/App/Dashboard/MonitorProbesCard.test.tsx +602 -0
  235. package/Tests/App/Dashboard/MonitorResponseTimeCard.test.tsx +386 -0
  236. package/Tests/App/Dashboard/MonitorSetupAndConnectionCards.test.tsx +612 -0
  237. package/Tests/App/Dashboard/MonitorStatusChangesCard.test.tsx +257 -0
  238. package/Tests/App/Dashboard/MonitorSummaryTestMonitorButton.test.tsx +360 -1
  239. package/Tests/App/Dashboard/MonitorUptimeHistoryCard.test.tsx +835 -0
  240. package/Tests/App/Dashboard/MonitorUptimeSummaryHook.test.tsx +971 -0
  241. package/Tests/App/Dashboard/MonitorViewLayout.test.tsx +580 -0
  242. package/Tests/App/Dashboard/NetworkDeviceTooltips.test.tsx +852 -0
  243. package/Tests/App/Dashboard/NetworkDiagnosticsTooltips.test.tsx +556 -0
  244. package/Tests/App/Dashboard/NetworkMetricTooltips.test.ts +1348 -0
  245. package/Tests/App/Dashboard/NetworkSiteTooltips.test.tsx +679 -0
  246. package/Tests/App/Dashboard/OnCallLayerRestrictionTimesPreserved.test.tsx +441 -0
  247. package/Tests/App/Dashboard/OnCallNavbar.test.tsx +214 -0
  248. package/Tests/App/Dashboard/OnCallSchedulePreviewCalendarDisplay.test.tsx +1389 -0
  249. package/Tests/App/Dashboard/OnCallSchedulePreviewOverrides.test.tsx +205 -1
  250. package/Tests/App/Dashboard/OnCallScheduleTimeInputsSettingsZone.test.tsx +198 -0
  251. package/Tests/App/Dashboard/ProxmoxMetricTooltips.test.ts +592 -0
  252. package/Tests/App/Dashboard/ProxmoxOverviewTooltips.test.tsx +1002 -0
  253. package/Tests/App/Dashboard/ProxmoxResourcePageTooltips.test.tsx +923 -0
  254. package/Tests/App/Dashboard/PublicNotePagesNotifyDefault.test.tsx +524 -0
  255. package/Tests/App/Dashboard/RemediationSuggestionCardApproval.test.tsx +702 -0
  256. package/Tests/App/Dashboard/RemoveUserFromProject.test.tsx +427 -0
  257. package/Tests/App/Dashboard/ResourceArchiveSettings.test.tsx +4 -0
  258. package/Tests/App/Dashboard/ResourceOverviewTileTooltips.test.tsx +1066 -0
  259. package/Tests/App/Dashboard/RumOverviewPage.test.tsx +1195 -0
  260. package/Tests/App/Dashboard/RumSessionReplaySideMenu.test.tsx +3 -1
  261. package/Tests/App/Dashboard/RunbookStepTypeMaps.test.ts +166 -0
  262. package/Tests/App/Dashboard/RunnerKubernetesAgentForm.test.tsx +622 -0
  263. package/Tests/App/Dashboard/ScheduledMaintenanceChangeStateNotifyDefault.test.tsx +1491 -0
  264. package/Tests/App/Dashboard/ScheduledMaintenanceFeedPublicNoteNotifyDefault.test.tsx +489 -0
  265. package/Tests/App/Dashboard/ScheduledMaintenanceOverviewNotifyDefault.test.tsx +909 -0
  266. package/Tests/App/Dashboard/ScheduledMaintenanceOverviewPage.test.tsx +14 -0
  267. package/Tests/App/Dashboard/ScheduledMaintenanceWindowStatsTranslation.test.tsx +307 -0
  268. package/Tests/App/Dashboard/SecurityEventAttributeColumnPicker.test.tsx +542 -0
  269. package/Tests/App/Dashboard/SecurityEventConnectionFormModal.test.tsx +174 -0
  270. package/Tests/App/Dashboard/SecurityEventConnectionsEmptyState.test.tsx +973 -212
  271. package/Tests/App/Dashboard/SecurityEventConnectionsTable.test.tsx +491 -52
  272. package/Tests/App/Dashboard/SecurityEventDetailPanel.test.tsx +301 -0
  273. package/Tests/App/Dashboard/SecurityEventListRow.test.tsx +158 -1
  274. package/Tests/App/Dashboard/SecurityEventProviderTile.test.tsx +869 -0
  275. package/Tests/App/Dashboard/SecurityEventsEmptyState.test.tsx +959 -94
  276. package/Tests/App/Dashboard/SecurityEventsNoResults.test.tsx +2 -0
  277. package/Tests/App/Dashboard/SecurityEventsViewer.test.tsx +274 -1
  278. package/Tests/App/Dashboard/ServerlessMetricTooltips.test.tsx +474 -0
  279. package/Tests/App/Dashboard/ServiceMetricTooltips.test.tsx +772 -0
  280. package/Tests/App/Dashboard/SessionReplayAuditTable.test.tsx +56 -1
  281. package/Tests/App/Dashboard/TeamMembershipRemoval.test.ts +900 -0
  282. package/Tests/App/Dashboard/TeamMembershipRemovalPages.test.tsx +460 -0
  283. package/Tests/App/Dashboard/TelemetryMetricsSignals.test.ts +1207 -0
  284. package/Tests/App/Dashboard/TelemetryResourceTabTooltips.test.tsx +437 -0
  285. package/Tests/App/Dashboard/TimezoneElements.test.tsx +321 -0
  286. package/Tests/App/Dashboard/TimezoneSelectButton.test.tsx +634 -0
  287. package/Tests/App/Dashboard/TraceExplorer.test.tsx +260 -0
  288. package/Tests/App/Dashboard/TraceMonitorPreview.test.tsx +182 -0
  289. package/Tests/App/Dashboard/UserTimezoneInit.test.tsx +544 -0
  290. package/Tests/App/Dashboard/VMwareMetricTooltips.test.ts +801 -0
  291. package/Tests/App/Dashboard/VMwareOverviewTooltips.test.tsx +601 -0
  292. package/Tests/App/Dashboard/VMwareResourcePagesTooltips.test.tsx +646 -0
  293. package/Tests/App/Dashboard/VMwareTooltipHarness.ts +145 -0
  294. package/Tests/App/Dashboard/WorkflowVariableModals.test.tsx +1630 -0
  295. package/Tests/App/Dashboard/WorkflowVariableRoutes.test.tsx +603 -0
  296. package/Tests/App/Dashboard/WorkflowVariableTokenStatus.test.tsx +589 -0
  297. package/Tests/App/Dashboard/WorkflowVariableUtil.test.ts +1543 -0
  298. package/Tests/App/Dashboard/WorkflowVariableView.test.tsx +3227 -0
  299. package/Tests/App/Dashboard/WorkflowVariablesTable.test.tsx +1277 -395
  300. package/Tests/App/StatusPage/StatusPageOverviewMonitorGroupUptime.test.tsx +714 -0
  301. package/Tests/App/StatusPage/StatusPageOverviewUptimeBars.NewYork.test.tsx +1009 -0
  302. package/Tests/App/StatusPage/StatusPageOverviewUptimeBars.test.tsx +1092 -0
  303. package/Tests/Models/DatabaseModels/DomainRoleTierCoverage.test.ts +5 -0
  304. package/Tests/Models/DatabaseModels/IncidentAlertModel.test.ts +554 -0
  305. package/Tests/Models/DatabaseModels/KubernetesClusterAiAccessColumns.test.ts +520 -0
  306. package/Tests/Models/DatabaseModels/MonitorSecretKeyColumnAccessControl.test.ts +66 -2
  307. package/Tests/Models/DatabaseModels/SessionReplayModels.test.ts +117 -0
  308. package/Tests/Models/DatabaseModels/WorkspaceProjectAuthTokenAccessControl.test.ts +236 -0
  309. package/Tests/Models/IncidentEpisodePublicNoteNotifyColumnContract.test.ts +103 -0
  310. package/Tests/Models/IncidentPublicNoteNotifyColumnContract.test.ts +96 -0
  311. package/Tests/Models/ScheduledMaintenancePublicNoteNotifyColumnContract.test.ts +111 -0
  312. package/Tests/Server/API/AIInvestigationAPI.test.ts +976 -0
  313. package/Tests/Server/API/AutoRemediationApproveKubectlRecheck.test.ts +836 -0
  314. package/Tests/Server/API/CommonAPIAssertCanCreateTable.test.ts +565 -0
  315. package/Tests/Server/API/CommonAPIAssertCanReadTable.test.ts +282 -0
  316. package/Tests/Server/API/KubernetesClusterAiAccessAPI.test.ts +1744 -0
  317. package/Tests/Server/API/LogHistogramAPI.test.ts +371 -0
  318. package/Tests/Server/API/MicrosoftTeamsLegacyWebhookRemoval.test.ts +125 -30
  319. package/Tests/Server/API/MicrosoftTeamsOAuthState.test.ts +1121 -0
  320. package/Tests/Server/API/MonitorUptimeSummaryAPI.test.ts +685 -0
  321. package/Tests/Server/API/SessionReplayAPI.test.ts +602 -1
  322. package/Tests/Server/API/SlackChannelCacheAPI.test.ts +358 -0
  323. package/Tests/Server/API/SlackOAuthState.test.ts +688 -0
  324. package/Tests/Server/API/StatusPageOverviewMonitorGroupUptime.test.ts +527 -0
  325. package/Tests/Server/API/StatusPageTestEmailReportAuth.test.ts +2 -0
  326. package/Tests/Server/API/StatusPageUptimeAPI.test.ts +427 -0
  327. package/Tests/Server/API/UserProjectsAPI.test.ts +4 -0
  328. package/Tests/Server/API/WorkflowVariableAPI.test.ts +404 -0
  329. package/Tests/Server/API/WorkspaceOAuthTestHelpers.ts +289 -0
  330. package/Tests/Server/API/WorkspaceSendTestNotificationRoutes.test.ts +2064 -0
  331. package/Tests/Server/Infrastructure/GlobalCache.test.ts +86 -0
  332. package/Tests/Server/Infrastructure/Postgres/AddIncidentAlertMigration.test.ts +341 -0
  333. package/Tests/Server/Infrastructure/Postgres/AddKubernetesClusterAiAccessMigration.test.ts +589 -0
  334. package/Tests/Server/Infrastructure/Postgres/AddOAuth2WorkflowVariablesMigration.test.ts +254 -0
  335. package/Tests/Server/Infrastructure/Postgres/AddSessionReplaySameOriginTracePropagationMigration.test.ts +247 -0
  336. package/Tests/Server/Middleware/BlockedUserMiddleware.test.ts +403 -0
  337. package/Tests/Server/Middleware/MasterAdminAuthorization.test.ts +13 -0
  338. package/Tests/Server/Middleware/PublicRouteUserMiddleware.test.ts +2 -0
  339. package/Tests/Server/Middleware/RemovedProjectMemberAuthorization.test.ts +469 -0
  340. package/Tests/Server/Middleware/TelemetryIngestBrowserKey.test.ts +77 -1
  341. package/Tests/Server/Middleware/TelemetryIngestKubernetesAgentRunnerPinnedKey.test.ts +211 -0
  342. package/Tests/Server/Middleware/TelemetryIngestKubernetesAgentRunnerRateLimit.test.ts +358 -0
  343. package/Tests/Server/Middleware/UserAuthorization.test.ts +97 -0
  344. package/Tests/Server/Middleware/UserAuthorizationEditionEnforcement.test.ts +2 -0
  345. package/Tests/Server/Services/AccessTokenProjectUserGrant.test.ts +14 -2
  346. package/Tests/Server/Services/AccessTokenRemovedMemberAccess.test.ts +1044 -0
  347. package/Tests/Server/Services/AddOwnersIdempotency.test.ts +5 -0
  348. package/Tests/Server/Services/AlertEpisodeMemberCreatePermission.test.ts +139 -0
  349. package/Tests/Server/Services/AutoRemediationClusterRuleEngine.test.ts +1361 -0
  350. package/Tests/Server/Services/AutoRemediationRuleCommandRunners.test.ts +375 -0
  351. package/Tests/Server/Services/CrossProjectRelationWriteGuard.test.ts +2384 -0
  352. package/Tests/Server/Services/FindOwnersProjectMembership.test.ts +267 -0
  353. package/Tests/Server/Services/InboundEmail/SendGridInboundProviderAddress.test.ts +90 -0
  354. package/Tests/Server/Services/IncidentAlertPostgres.test.ts +903 -0
  355. package/Tests/Server/Services/IncidentAlertRegistration.test.ts +96 -0
  356. package/Tests/Server/Services/IncidentAlertService.test.ts +2225 -0
  357. package/Tests/Server/Services/IncidentAlertStateCascade.test.ts +970 -0
  358. package/Tests/Server/Services/IncidentCreateFromAlerts.test.ts +1284 -0
  359. package/Tests/Server/Services/IncidentEpisodeMemberCreatePermission.test.ts +143 -0
  360. package/Tests/Server/Services/IncidentEpisodePublicNoteNotifyDefault.test.ts +805 -0
  361. package/Tests/Server/Services/IncidentPublicNoteNotifyDefault.test.ts +724 -0
  362. package/Tests/Server/Services/IncidentRoleProjectMembership.test.ts +233 -0
  363. package/Tests/Server/Services/KubernetesClusterAiAccessAgentRunnerAssignments.test.ts +372 -0
  364. package/Tests/Server/Services/KubernetesClusterAiAccessBindingGuard.test.ts +1876 -0
  365. package/Tests/Server/Services/KubernetesClusterAiAccessDeletedRunnerRemedy.test.ts +620 -0
  366. package/Tests/Server/Services/KubernetesClusterAiAccessGapNextSteps.test.ts +421 -0
  367. package/Tests/Server/Services/KubernetesClusterAiAccessService.test.ts +3662 -0
  368. package/Tests/Server/Services/KubernetesClusterAiAccessSubjectClusters.test.ts +405 -0
  369. package/Tests/Server/Services/KubernetesClusterAiSettingsPermission.test.ts +975 -0
  370. package/Tests/Server/Services/KubernetesClusterServiceAiAccessFeed.test.ts +497 -0
  371. package/Tests/Server/Services/KubernetesClusterServiceDeleteSettlesRemediation.test.ts +328 -0
  372. package/Tests/Server/Services/LogAggregationService.test.ts +99 -0
  373. package/Tests/Server/Services/MonitorServiceIncomingEmailCustomAddress.test.ts +447 -0
  374. package/Tests/Server/Services/MonitorServiceProbeFlagSync.test.ts +1334 -0
  375. package/Tests/Server/Services/MonitorServiceProbeStatusGrouping.test.ts +1640 -0
  376. package/Tests/Server/Services/MonitorServiceRefreshCurrentStatus.test.ts +225 -0
  377. package/Tests/Server/Services/MonitorStatusBridgeProbePath.test.ts +8 -8
  378. package/Tests/Server/Services/MonitorStatusTimelineDailyAggregates.test.ts +264 -1
  379. package/Tests/Server/Services/MonitorStatusTimelineMergedDowntime.test.ts +284 -0
  380. package/Tests/Server/Services/MonitorUptimeSummaryService.test.ts +1043 -0
  381. package/Tests/Server/Services/NetworkDeviceRuleEngines.test.ts +5 -0
  382. package/Tests/Server/Services/OnCallUndeliverablePageOwnerMembership.test.ts +359 -0
  383. package/Tests/Server/Services/ProbeServiceDashboardLink.test.ts +191 -0
  384. package/Tests/Server/Services/ProjectOwnersProjectMembership.test.ts +221 -0
  385. package/Tests/Server/Services/RuleRun/IncidentAlertMaintenanceRuleEnginesRun.test.ts +5 -0
  386. package/Tests/Server/Services/RuleRun/OwnerRuleEnginesGroupARun.test.ts +28 -0
  387. package/Tests/Server/Services/RuleRun/OwnerRuleEnginesGroupBRun.test.ts +9 -1
  388. package/Tests/Server/Services/RunnerJobEnqueueAiCommandAgentRunner.test.ts +230 -0
  389. package/Tests/Server/Services/RunnerJobEnqueueKubectl.test.ts +978 -0
  390. package/Tests/Server/Services/RunnerJobKubectlWriteScope.test.ts +866 -0
  391. package/Tests/Server/Services/RunnerJobSubmitResultRedaction.test.ts +322 -0
  392. package/Tests/Server/Services/RunnerJobSubmitResultUnstorableText.test.ts +357 -0
  393. package/Tests/Server/Services/RunnerJobTimeoutReason.test.ts +227 -0
  394. package/Tests/Server/Services/RunnerServiceAgentName.test.ts +581 -0
  395. package/Tests/Server/Services/ScheduledMaintenancePublicNoteNotifyDefault.test.ts +802 -0
  396. package/Tests/Server/Services/ScheduledMaintenanceSubscriberTemplateFormats.test.ts +53 -0
  397. package/Tests/Server/Services/ServiceLevelObjectiveLabelAndOwnerRuleEngines.test.ts +5 -0
  398. package/Tests/Server/Services/ServiceLevelObjectiveService.test.ts +12 -0
  399. package/Tests/Server/Services/StatusPageSubscriberReport.test.ts +1176 -1
  400. package/Tests/Server/Services/TeamMemberBillingSeatSync.test.ts +9 -0
  401. package/Tests/Server/Services/TeamMemberOnCallCleanup.test.ts +18 -0
  402. package/Tests/Server/Services/TeamMemberProjectMembership.test.ts +255 -0
  403. package/Tests/Server/Services/TeamMemberRemovalRevokesProjectAccess.test.ts +600 -0
  404. package/Tests/Server/Services/TeamMemberResourceCleanup.test.ts +731 -0
  405. package/Tests/Server/Services/TeamMemberWorkspaceAccountCleanup.test.ts +164 -0
  406. package/Tests/Server/Services/TraceAggregationService.test.ts +64 -0
  407. package/Tests/Server/Services/UserServiceBlockedUser.test.ts +293 -0
  408. package/Tests/Server/Services/WorkflowVariableOAuthHooks.test.ts +1016 -0
  409. package/Tests/Server/Services/WorkflowVariableOAuthPostgres.test.ts +543 -0
  410. package/Tests/Server/Services/WorkflowVariableRenameUniqueness.test.ts +16 -5
  411. package/Tests/Server/Services/WorkspaceNotificationRuleNoteDelivery.test.ts +473 -0
  412. package/Tests/Server/Services/WorkspaceNotificationRuleSendTestNotification.test.ts +3690 -0
  413. package/Tests/Server/Services/WorkspaceProjectAuthTokenMiscDataSecrets.test.ts +374 -0
  414. package/Tests/Server/Services/WorkspaceProjectAuthTokenSlackChannelCache.test.ts +143 -0
  415. package/Tests/Server/Types/Database/Permissions/WorkflowVariableOAuthColumnPermission.test.ts +250 -0
  416. package/Tests/Server/Types/Database/QueryHelperJsonContains.test.ts +96 -0
  417. package/Tests/Server/Types/Markdown.test.ts +1033 -0
  418. package/Tests/Server/Utils/AI/ClusterAccessContext.test.ts +285 -0
  419. package/Tests/Server/Utils/AI/CodeFix/CodeFixAgentAuth.test.ts +159 -1
  420. package/Tests/Server/Utils/AI/InvestigationClusterAccessWiring.test.ts +752 -0
  421. package/Tests/Server/Utils/AI/KubectlInvestigationToolkit.test.ts +1840 -0
  422. package/Tests/Server/Utils/AI/KubectlJobRunner.test.ts +1067 -0
  423. package/Tests/Server/Utils/AI/KubectlJobRunnerFinishedJob.test.ts +355 -0
  424. package/Tests/Server/Utils/AI/PostIncidentStatusUpdateTool.test.ts +496 -0
  425. package/Tests/Server/Utils/AI/RemediationCommandTools.test.ts +305 -0
  426. package/Tests/Server/Utils/AI/RemediationCommandToolsKubectl.test.ts +1365 -0
  427. package/Tests/Server/Utils/AI/RemediationCommandToolsKubectlOutcome.test.ts +639 -0
  428. package/Tests/Server/Utils/AI/RemediationCommandToolsLiveCluster.test.ts +1585 -0
  429. package/Tests/Server/Utils/AI/RemediationCommandToolsRunnerScope.test.ts +1065 -0
  430. package/Tests/Server/Utils/AI/RemediationExecutionRunner.test.ts +2138 -1
  431. package/Tests/Server/Utils/AI/RemediationExecutionRunnerClusterMode.test.ts +1035 -0
  432. package/Tests/Server/Utils/AI/RemediationKubectlCopyParity.test.ts +517 -0
  433. package/Tests/Server/Utils/AI/ResourceTools.test.ts +27 -1
  434. package/Tests/Server/Utils/AutoRemediation/CommandPlanExecutor.test.ts +1371 -24
  435. package/Tests/Server/Utils/AutoRemediation/CommandPlanExecutorRollbackRace.test.ts +962 -0
  436. package/Tests/Server/Utils/AutoRemediation/CommandPlanExecutorUnknownRun.test.ts +518 -0
  437. package/Tests/Server/Utils/AutoRemediation/CommandPlanVerification.test.ts +939 -2
  438. package/Tests/Server/Utils/Database/ProjectScopedRelationReferences.test.ts +371 -0
  439. package/Tests/Server/Utils/Monitor/AffectedResourceList.test.ts +64 -0
  440. package/Tests/Server/Utils/Monitor/DatabaseMetricObservationRemediation.test.ts +102 -0
  441. package/Tests/Server/Utils/Monitor/MonitorAlertCriteriaReferences.test.ts +362 -0
  442. package/Tests/Server/Utils/Monitor/MonitorCriteriaEvaluatorBreachingSamples.test.ts +55 -0
  443. package/Tests/Server/Utils/Monitor/MonitorEmailAddressRedaction.test.ts +255 -0
  444. package/Tests/Server/Utils/Monitor/MonitorIncidentCriteriaReferences.test.ts +347 -0
  445. package/Tests/Server/Utils/Monitor/MonitorIncidentMemberRoleMembership.test.ts +203 -0
  446. package/Tests/Server/Utils/Monitor/ProbeMonitorsNotification.test.ts +1147 -0
  447. package/Tests/Server/Utils/PushNotificationUtilCreators.test.ts +79 -0
  448. package/Tests/Server/Utils/ResourceFeed/ResourceFeedUtil.test.ts +21 -1
  449. package/Tests/Server/Utils/Rules/OwnerRuleAssignment.test.ts +155 -1
  450. package/Tests/Server/Utils/SessionReplay/SessionReplayGateCachePolicy.test.ts +103 -0
  451. package/Tests/Server/Utils/SessionReplay/SessionReplayReadServiceQueries.test.ts +288 -0
  452. package/Tests/Server/Utils/SessionReplay/SessionReplayUserFlowReadService.test.ts +304 -0
  453. package/Tests/Server/Utils/Telemetry/TelemetryIngestionKeyGuard.test.ts +40 -3
  454. package/Tests/Server/Utils/Workflow/OAuth2TokenClient.test.ts +702 -0
  455. package/Tests/Server/Utils/Workflow/OAuth2TokenClientHttpIntegration.test.ts +507 -0
  456. package/Tests/Server/Utils/Workflow/WorkflowVariableOAuthToken.test.ts +831 -0
  457. package/Tests/Server/Utils/Workspace/MicrosoftTeamsActionAuthorization.test.ts +63 -1
  458. package/Tests/Server/Utils/Workspace/MicrosoftTeamsAppAccessToken.test.ts +256 -0
  459. package/Tests/Server/Utils/Workspace/MicrosoftTeamsChannelSend.test.ts +60 -0
  460. package/Tests/Server/Utils/Workspace/MicrosoftTeamsChatActionAuthorization.test.ts +442 -0
  461. package/Tests/Server/Utils/Workspace/MicrosoftTeamsChats.test.ts +44 -2
  462. package/Tests/Server/Utils/Workspace/MicrosoftTeamsDirectMessage.test.ts +55 -0
  463. package/Tests/Server/Utils/Workspace/MicrosoftTeamsReactionNoteSync.test.ts +1522 -0
  464. package/Tests/Server/Utils/Workspace/MicrosoftTeamsServiceUrl.test.ts +130 -0
  465. package/Tests/Server/Utils/Workspace/MicrosoftTeamsTeamInstalls.test.ts +4 -4
  466. package/Tests/Server/Utils/Workspace/Slack/SlackActionAuthorization.test.ts +691 -0
  467. package/Tests/Server/Utils/Workspace/Slack/SlackMessageByTimestamp.test.ts +253 -0
  468. package/Tests/Server/Utils/Workspace/Slack/SlackReactionNote.test.ts +574 -0
  469. package/Tests/Server/Utils/Workspace/WorkspaceActionAuthorization.test.ts +488 -0
  470. package/Tests/Server/Utils/Workspace/WorkspaceCreateProjectReferences.test.ts +861 -0
  471. package/Tests/Server/Utils/Workspace/WorkspaceMessageAuthor.test.ts +635 -0
  472. package/Tests/Server/Utils/Workspace/WorkspaceOAuthState.test.ts +548 -0
  473. package/Tests/Server/Utils/Workspace/WorkspaceReactionNote.test.ts +839 -0
  474. package/Tests/Server/Utils/Workspace/WorkspaceSendErrorMessage.test.ts +725 -0
  475. package/Tests/Types/AutoRemediation/AiRemediationCommandPlan.test.ts +283 -9
  476. package/Tests/Types/DateBrowserLocalWallClock.test.ts +280 -0
  477. package/Tests/Types/DateLocalShortMonthNameFallback.test.ts +389 -0
  478. package/Tests/Types/DateUserTimezone.test.ts +177 -4
  479. package/Tests/Types/Kubernetes/KubernetesAgentChartAiAccess.test.ts +306 -0
  480. package/Tests/Types/Kubernetes/KubernetesClusterAiAccess.test.ts +283 -0
  481. package/Tests/Types/Kubernetes/KubernetesRunnerPostureWriteScope.test.ts +68 -0
  482. package/Tests/Types/Monitor/DatabaseMonitor/SqlServerPlatform.test.ts +144 -0
  483. package/Tests/Types/Monitor/MonitorStepExceptionMonitor.test.ts +160 -0
  484. package/Tests/Types/Monitor/Recommendation/MonitorRecommendationCoverage.test.ts +53 -0
  485. package/Tests/Types/Rum/WebVitals.test.ts +173 -0
  486. package/Tests/Types/Runbook/RunbookStepType.test.ts +91 -16
  487. package/Tests/Types/Runner/RunnerLiveStatus.test.ts +14 -3
  488. package/Tests/Types/SecurityEvent/Connectors/SecurityEventConnectorCatalog.test.ts +15 -0
  489. package/Tests/Types/StatusPage/PublicNoteSubscriberNotificationDefault.test.ts +1868 -0
  490. package/Tests/Types/Timezone.test.ts +5 -0
  491. package/Tests/Types/TimezoneAlias.test.ts +1034 -0
  492. package/Tests/Types/Workflow/JiraTemplateFixtures.ts +833 -0
  493. package/Tests/Types/Workflow/JiraTemplateScripts.test.ts +5414 -0
  494. package/Tests/Types/Workflow/JiraTemplateSimulation.test.ts +4803 -0
  495. package/Tests/Types/Workflow/JiraTemplates.test.ts +5429 -0
  496. package/Tests/Types/Workflow/Templates.test.ts +79 -4
  497. package/Tests/Types/Workflow/WorkflowVariableOAuth.test.ts +520 -0
  498. package/Tests/Types/Workspace/WorkspaceNoteReaction.test.ts +177 -0
  499. package/Tests/UI/Components/AttributesJSON/AttributesJSONView.test.tsx +390 -0
  500. package/Tests/UI/Components/AttributesJSON/CopyAttributesAsJSONButton.test.tsx +566 -0
  501. package/Tests/UI/Components/AttributesJSON/JSONHighlight.test.ts +131 -0
  502. package/Tests/UI/Components/BasicFormDropdownNormalization.test.tsx +276 -1
  503. package/Tests/UI/Components/Calendar/Calendar.test.tsx +1611 -0
  504. package/Tests/UI/Components/Calendar/CalendarDayLayout.test.ts +1486 -0
  505. package/Tests/UI/Components/Calendar/CalendarDayLayoutDst.test.ts +632 -0
  506. package/Tests/UI/Components/Calendar/CalendarDst.test.tsx +388 -0
  507. package/Tests/UI/Components/Charts/ChartGroupPlotFloor.test.tsx +170 -0
  508. package/Tests/UI/Components/Charts/HistogramSelection.test.ts +282 -0
  509. package/Tests/UI/Components/CustomTimeRangeModal.test.tsx +6 -0
  510. package/Tests/UI/Components/CustomTimeRangeModalTimezoneTranslation.test.tsx +285 -0
  511. package/Tests/UI/Components/Dropdown.test.tsx +999 -2
  512. package/Tests/UI/Components/FieldLabelInfoCardTooltip.test.tsx +413 -0
  513. package/Tests/UI/Components/Forms/FormFieldCheckboxTranslation.test.tsx +216 -0
  514. package/Tests/UI/Components/Forms/FormFieldTimezoneDescriptionTranslation.test.tsx +461 -0
  515. package/Tests/UI/Components/Forms/IncidentEpisodePublicNoteNotifyPayload.test.tsx +641 -0
  516. package/Tests/UI/Components/Forms/IncidentPublicNoteNotifyPayload.test.tsx +346 -0
  517. package/Tests/UI/Components/Forms/ScheduledMaintenancePublicNoteNotifyPayload.test.tsx +493 -0
  518. package/Tests/UI/Components/Graphs/DayUptimeGraph.test.tsx +911 -2
  519. package/Tests/UI/Components/Graphs/DayUptimeGraphTimezone.NewYork.test.tsx +730 -0
  520. package/Tests/UI/Components/Graphs/DayUptimeGraphTimezone.Tokyo.test.tsx +506 -0
  521. package/Tests/UI/Components/HistogramClickToZoom.test.tsx +619 -0
  522. package/Tests/UI/Components/InfoTooltip.test.tsx +242 -0
  523. package/Tests/UI/Components/LogDetailsPanelAttributesJSON.test.tsx +248 -0
  524. package/Tests/UI/Components/LogsViewerHistogramZoom.test.tsx +47 -1
  525. package/Tests/UI/Components/LogsViewerSmallScreens.test.tsx +620 -0
  526. package/Tests/UI/Components/ModelPageModelChange.test.tsx +242 -3
  527. package/Tests/UI/Components/ModelTable/BaseModelTableBulkDelete.test.tsx +207 -3
  528. package/Tests/UI/Components/ModelTable/BaseModelTableBulkDeleteVerb.test.tsx +367 -0
  529. package/Tests/UI/Components/ModelTable/BaseModelTableCreateButtonTitle.test.tsx +275 -0
  530. package/Tests/UI/Components/ModelTable/BaseModelTableDeleteConfirmation.test.tsx +521 -0
  531. package/Tests/UI/Components/MonitorGraphs/Uptime.test.tsx +406 -2
  532. package/Tests/UI/Components/MonitorGraphs/UptimeBarDayModal.test.tsx +169 -2
  533. package/Tests/UI/Components/TableHeaderTooltip.test.tsx +662 -0
  534. package/Tests/UI/Components/TelemetryViewer/TelemetryViewerHistogramClickZoom.test.tsx +266 -0
  535. package/Tests/UI/Components/TelemetryViewer/TelemetryViewerSmallScreens.test.tsx +439 -0
  536. package/Tests/UI/Components/TimezoneDropdownLegacyValues.test.tsx +704 -0
  537. package/Tests/UI/Components/UseHistogramZoom.test.tsx +89 -1
  538. package/Tests/UI/Components/UseLogsHistogram.test.tsx +175 -0
  539. package/Tests/UI/Monitor/MonitorSummarySnapshotRender.test.tsx +5 -5
  540. package/Tests/UI/Rum/PrivacySummaryCard.test.tsx +166 -9
  541. package/Tests/UI/Rum/RecordingHealthTooltips.test.tsx +447 -0
  542. package/Tests/UI/Rum/ReplayCorrelationPanel.test.tsx +164 -0
  543. package/Tests/UI/Rum/ReplayFrameCapture.test.ts +6750 -0
  544. package/Tests/UI/Rum/ReplayRail.test.tsx +723 -12
  545. package/Tests/UI/Rum/ReplayRailDetail.test.tsx +86 -0
  546. package/Tests/UI/Rum/ReplayScreenshot.test.ts +2124 -0
  547. package/Tests/UI/Rum/ReplayScreenshotActions.test.tsx +3288 -0
  548. package/Tests/UI/Rum/ReplayStage.test.tsx +62 -0
  549. package/Tests/UI/Rum/ReplayStageOverlays.test.tsx +983 -2
  550. package/Tests/UI/Rum/SessionReplaySettingsPolicyLoading.test.tsx +149 -0
  551. package/Tests/UI/Rum/SessionReplaySetupGuide.test.tsx +107 -6
  552. package/Tests/UI/Rum/SessionReplayUsersTableTooltips.test.tsx +330 -0
  553. package/Tests/UI/Rum/UserFlowTooltips.test.tsx +886 -0
  554. package/Tests/UI/Telemetry/TelemetryDetailPanel.test.tsx +28 -0
  555. package/Tests/UI/Utils/Breadcrumb/fixtures/RealBreadcrumbTrails.ts +10 -0
  556. package/Tests/UI/Utils/Breadcrumb/fixtures/RealRoutePatterns.ts +2 -0
  557. package/Tests/UI/Utils/PermissionGate.test.ts +76 -0
  558. package/Tests/UI/Utils/ProjectUsersModelAPI.test.ts +51 -0
  559. package/Tests/UI/Utils/Timezone.test.ts +747 -33
  560. package/Tests/UI/Workspace/SendTestNotificationButton.test.tsx +1854 -0
  561. package/Tests/UI/Workspace/WorkspaceCardsSendTestNotification.test.tsx +1864 -0
  562. package/Tests/Utils/AI/InvestigationReport.test.ts +435 -7
  563. package/Tests/Utils/AiRemediation/KubectlAllowlistValidatorParity.test.ts +1084 -0
  564. package/Tests/Utils/AiRemediation/KubectlOutputRedactor.test.ts +2531 -0
  565. package/Tests/Utils/AiRemediation/KubectlPolicy.test.ts +1895 -0
  566. package/Tests/Utils/AiRemediation/KubectlPolicyAllowlist.test.ts +428 -0
  567. package/Tests/Utils/AiRemediation/KubectlPolicyChartRbacParity.test.ts +828 -0
  568. package/Tests/Utils/AiRemediation/KubectlPolicyCustomResourceScope.test.ts +573 -0
  569. package/Tests/Utils/AiRemediation/KubectlPolicyDenials.test.ts +1525 -0
  570. package/Tests/Utils/AiRemediation/KubectlPolicyExposeOverrides.test.ts +275 -0
  571. package/Tests/Utils/AiRemediation/KubectlPolicyNodePatch.test.ts +428 -0
  572. package/Tests/Utils/AiRemediation/KubectlPolicyObjectWords.test.ts +195 -0
  573. package/Tests/Utils/AiRemediation/KubectlPolicyPatchParents.test.ts +637 -0
  574. package/Tests/Utils/AiRemediation/KubectlPolicyPodSecurityBaseline.test.ts +322 -0
  575. package/Tests/Utils/AiRemediation/KubectlPolicySafeWriteScope.test.ts +1026 -0
  576. package/Tests/Utils/AiRemediation/KubectlWaitBudget.test.ts +267 -0
  577. package/Tests/Utils/AiRemediation/KubectlWriteScope.test.ts +390 -0
  578. package/Tests/Utils/AiRemediation/KubectlWriteScopeCallerParity.test.ts +777 -0
  579. package/Tests/Utils/AiRemediation/KubectlWriteScopeClusterScoped.test.ts +613 -0
  580. package/Tests/Utils/AiRemediation/KubectlWriteScopeEntryPoint.test.ts +576 -0
  581. package/Tests/Utils/AiRemediation/KubectlWriteScopeKubectlSpellings.test.ts +752 -0
  582. package/Tests/Utils/AiRemediation/KubectlWriteScopeObjectWords.test.ts +358 -0
  583. package/Tests/Utils/AiRemediation/KubectlWriteScopeOverrides.test.ts +293 -0
  584. package/Tests/Utils/AiRemediation/KubectlWriteScopeParityCases.ts +598 -0
  585. package/Tests/Utils/AiRemediation/KubectlWriteScopePolicyParity.test.ts +403 -0
  586. package/Tests/Utils/Dashboard/DashboardClockComponent.test.ts +154 -5
  587. package/Tests/Utils/Incident/IncidentFromAlerts.test.ts +696 -0
  588. package/Tests/Utils/Monitor/IncomingEmailMonitorAddress.test.ts +478 -0
  589. package/Tests/Utils/Monitor/MonitorCheckScheduleUtil.test.ts +646 -0
  590. package/Tests/Utils/Monitor/MonitorOverviewCriteriaUtil.test.ts +292 -0
  591. package/Tests/Utils/Monitor/MonitorOverviewFamily.test.ts +274 -0
  592. package/Tests/Utils/Monitor/MonitorOverviewPresentationUtil.test.ts +3100 -0
  593. package/Tests/Utils/Monitor/MonitorOverviewProbeUtil.test.ts +1412 -0
  594. package/Tests/Utils/Monitor/MonitorOverviewTargetUtil.test.ts +374 -0
  595. package/Tests/Utils/Monitor/MonitorStatusHistoryUtil.test.ts +332 -0
  596. package/Tests/Utils/Monitor/MonitorUptimeSummaryUtil.test.ts +946 -0
  597. package/Tests/Utils/Rum/SessionIdentity.test.ts +94 -0
  598. package/Tests/Utils/Rum/SessionReplayWafCompatibility.test.ts +840 -0
  599. package/Tests/Utils/Rum/SessionReplayWireEncoding.test.ts +208 -0
  600. package/Tests/Utils/Rum/SessionTraceState.test.ts +239 -0
  601. package/Tests/Utils/Rum/UserFlow.test.ts +1010 -0
  602. package/Tests/Utils/StatusPage/MonitorGroupMergedDowntimeUtil.test.ts +217 -0
  603. package/Tests/Utils/StatusPage/ResourceUptime.test.ts +1272 -1
  604. package/Tests/Utils/StatusPage/UptimeDailyAggregateTotals.test.ts +298 -0
  605. package/Tests/Utils/StatusPage/UptimeDailyAggregateUtil.test.ts +649 -1
  606. package/Tests/Utils/StatusPage/UptimeDailyAggregateWindow.test.ts +314 -0
  607. package/Tests/Utils/Telemetry/AttributesJSON.test.ts +454 -0
  608. package/Tests/Utils/Uptime/DayUptimeGraphUtil.test.ts +418 -2
  609. package/Tests/Utils/Uptime/DayUptimeGraphUtilMidnightDst.test.ts +160 -0
  610. package/Tests/Utils/Uptime/DayUptimeGraphUtilTimezone.Auckland.test.ts +45 -0
  611. package/Tests/Utils/Uptime/DayUptimeGraphUtilTimezone.Kolkata.test.ts +40 -0
  612. package/Tests/Utils/Uptime/DayUptimeGraphUtilTimezone.London.test.ts +147 -0
  613. package/Tests/Utils/Uptime/DayUptimeGraphUtilTimezone.NewYork.test.ts +48 -0
  614. package/Tests/Utils/Uptime/DayUptimeGraphUtilTimezone.Tokyo.test.ts +39 -0
  615. package/Tests/Utils/Uptime/DayUptimeGraphUtilTimezoneCases.ts +1015 -0
  616. package/Tests/Utils/Uptime/UptimeUtil.test.ts +75 -0
  617. package/Tests/Utils/Uptime/UptimeUtilChronologicalOrder.test.ts +1279 -0
  618. package/Types/AutoRemediation/AiRemediationCommandPlan.ts +203 -5
  619. package/Types/Date.ts +121 -7
  620. package/Types/Email/EmailMessage.ts +8 -0
  621. package/Types/Email/EmailTemplateType.ts +1 -0
  622. package/Types/Exception/ExceptionMessages.ts +1 -0
  623. package/Types/Incident/IncidentAlertLink.ts +38 -0
  624. package/Types/Kubernetes/KubernetesClusterAiAccess.ts +488 -0
  625. package/Types/Kubernetes/KubernetesClusterAiAccessPermissions.ts +54 -0
  626. package/Types/Kubernetes/KubernetesClusterAiAccessToolNames.ts +17 -0
  627. package/Types/Monitor/DatabaseMonitor/DatabaseMonitorResponse.ts +9 -0
  628. package/Types/Monitor/DatabaseMonitor/SqlServerPlatform.ts +117 -0
  629. package/Types/Monitor/KubernetesAlertTemplates.ts +6 -5
  630. package/Types/Monitor/MonitorStepExceptionMonitor.ts +56 -0
  631. package/Types/Monitor/MonitorUptimeSummary.ts +113 -0
  632. package/Types/Monitor/Recommendation/MonitorRecommendationUtil.ts +11 -0
  633. package/Types/Permission.ts +48 -0
  634. package/Types/Rum/SessionReplay.ts +80 -8
  635. package/Types/Rum/SessionReplayApi.ts +44 -1
  636. package/Types/Rum/UserFlow.ts +187 -0
  637. package/Types/Rum/WebVitals.ts +52 -0
  638. package/Types/Runbook/RunbookStepType.ts +10 -0
  639. package/Types/Runbook/RunnerJobOrigin.ts +15 -0
  640. package/Types/SecurityEvent/Connectors/SecurityEventConnectorCatalog.ts +6 -2
  641. package/Types/StatusPage/MergedDowntimeTotals.ts +17 -0
  642. package/Types/StatusPage/PublicNoteSubscriberNotificationDefault.ts +148 -0
  643. package/Types/StatusPage/UptimeDailyAggregate.ts +15 -0
  644. package/Types/Telemetry/TelemetryIngestSurface.ts +9 -0
  645. package/Types/Timezone.ts +5 -0
  646. package/Types/TimezoneAlias.ts +385 -0
  647. package/Types/Workflow/Templates.ts +3041 -2
  648. package/Types/Workflow/WorkflowVariableOAuth.ts +476 -0
  649. package/Types/Workspace/WorkspaceNoteReaction.ts +132 -0
  650. package/Typings/Index.d.ts +24 -0
  651. package/UI/Components/AttributesJSON/AttributesJSONPreferences.ts +175 -0
  652. package/UI/Components/AttributesJSON/AttributesJSONView.tsx +138 -0
  653. package/UI/Components/AttributesJSON/AttributesViewToggle.tsx +79 -0
  654. package/UI/Components/AttributesJSON/BracesGlyph.tsx +30 -0
  655. package/UI/Components/AttributesJSON/CopyAttributesAsJSONButton.tsx +491 -0
  656. package/UI/Components/AttributesJSON/JSONHighlight.ts +77 -0
  657. package/UI/Components/Calendar/Calendar.css +83 -0
  658. package/UI/Components/Calendar/Calendar.tsx +136 -7
  659. package/UI/Components/Calendar/CalendarDayLayout.ts +236 -0
  660. package/UI/Components/Charts/ChartGroup/ChartGroup.tsx +23 -1
  661. package/UI/Components/Charts/Utils/HistogramSelection.ts +117 -0
  662. package/UI/Components/Charts/Utils/useHistogramRangeSelection.ts +269 -0
  663. package/UI/Components/Charts/Utils/useHistogramZoom.ts +26 -2
  664. package/UI/Components/Date/CustomTimeRangeModal.tsx +26 -3
  665. package/UI/Components/Detail/FieldLabel.tsx +8 -0
  666. package/UI/Components/Dropdown/Dropdown.tsx +58 -9
  667. package/UI/Components/Forms/Fields/FormField.tsx +49 -14
  668. package/UI/Components/Graphs/DayUptimeGraph.tsx +166 -25
  669. package/UI/Components/Graphs/UptimeBarTooltip.tsx +10 -2
  670. package/UI/Components/Graphs/UptimeDaySummary.tsx +8 -0
  671. package/UI/Components/InfoCard/InfoCard.tsx +47 -1
  672. package/UI/Components/LogsViewer/LogsViewer.tsx +52 -5
  673. package/UI/Components/LogsViewer/components/ColumnSelector.tsx +13 -2
  674. package/UI/Components/LogsViewer/components/KeyboardShortcutsHelp.tsx +13 -1
  675. package/UI/Components/LogsViewer/components/LogDetailsPanel.tsx +91 -76
  676. package/UI/Components/LogsViewer/components/LogsFacetSidebar.tsx +15 -1
  677. package/UI/Components/LogsViewer/components/LogsHistogram.tsx +28 -106
  678. package/UI/Components/LogsViewer/components/LogsViewerToolbar.tsx +54 -6
  679. package/UI/Components/LogsViewer/components/SavedViewsDropdown.tsx +8 -2
  680. package/UI/Components/LogsViewer/useLogsHistogram.ts +39 -6
  681. package/UI/Components/ModelTable/BaseModelTable.tsx +161 -31
  682. package/UI/Components/ModelTable/Column.ts +5 -0
  683. package/UI/Components/MonitorGraphs/Uptime.tsx +12 -0
  684. package/UI/Components/MonitorGraphs/UptimeBarDayModal.tsx +10 -2
  685. package/UI/Components/Page/ModelPage.tsx +59 -3
  686. package/UI/Components/Table/TableHeader.tsx +47 -2
  687. package/UI/Components/Table/Types/Column.ts +7 -0
  688. package/UI/Components/TelemetryViewer/TelemetryViewer.tsx +69 -5
  689. package/UI/Components/TelemetryViewer/components/TelemetryDetailPanel.tsx +12 -1
  690. package/UI/Components/TelemetryViewer/components/TelemetryFacetSidebar.tsx +15 -1
  691. package/UI/Components/TelemetryViewer/components/TelemetryHistogram.tsx +36 -104
  692. package/UI/Components/TelemetryViewer/components/TelemetrySearchBar.tsx +9 -1
  693. package/UI/Components/Tooltip/InfoTooltip.tsx +78 -0
  694. package/UI/Utils/ModelAPI/ProjectUsersModelAPI.ts +19 -1
  695. package/UI/Utils/PermissionGate.ts +11 -2
  696. package/UI/Utils/Timezone.ts +69 -28
  697. package/Utils/AI/InvestigationReport.ts +195 -25
  698. package/Utils/AiRemediation/KubectlOutputRedactor.ts +1724 -0
  699. package/Utils/AiRemediation/KubectlPolicy.ts +4136 -0
  700. package/Utils/AiRemediation/KubectlWaitBudget.ts +156 -0
  701. package/Utils/AiRemediation/KubectlWriteScope.ts +1964 -0
  702. package/Utils/Dashboard/Components/DashboardClockComponent.ts +7 -6
  703. package/Utils/Incident/IncidentFromAlerts.ts +516 -0
  704. package/Utils/Monitor/IncomingEmailMonitorAddress.ts +292 -0
  705. package/Utils/Monitor/MonitorCheckScheduleUtil.ts +654 -0
  706. package/Utils/Monitor/MonitorOverviewCriteriaUtil.ts +188 -0
  707. package/Utils/Monitor/MonitorOverviewFamily.ts +263 -0
  708. package/Utils/Monitor/MonitorOverviewPresentationUtil.ts +1958 -0
  709. package/Utils/Monitor/MonitorOverviewProbeUtil.ts +979 -0
  710. package/Utils/Monitor/MonitorOverviewTargetUtil.ts +299 -0
  711. package/Utils/Monitor/MonitorStatusHistoryUtil.ts +201 -0
  712. package/Utils/Monitor/MonitorUptimeSummaryUtil.ts +638 -0
  713. package/Utils/Rum/SessionIdentity.ts +44 -0
  714. package/Utils/Rum/SessionReplayWireEncoding.ts +137 -0
  715. package/Utils/Rum/SessionTraceState.ts +212 -0
  716. package/Utils/Rum/UserFlow.ts +1527 -0
  717. package/Utils/StatusPage/MonitorGroupMergedDowntimeUtil.ts +107 -0
  718. package/Utils/StatusPage/ResourceUptime.ts +99 -0
  719. package/Utils/StatusPage/UptimeDailyAggregateUtil.ts +197 -0
  720. package/Utils/Telemetry/AttributesJSON.ts +367 -0
  721. package/Utils/Uptime/DayUptimeGraphUtil.ts +165 -0
  722. package/Utils/Uptime/UptimeUtil.ts +122 -38
  723. package/build/dist/Models/DatabaseModels/AlertEpisodeMember.js +8 -1
  724. package/build/dist/Models/DatabaseModels/AlertEpisodeMember.js.map +1 -1
  725. package/build/dist/Models/DatabaseModels/AlertFeed.js +2 -0
  726. package/build/dist/Models/DatabaseModels/AlertFeed.js.map +1 -1
  727. package/build/dist/Models/DatabaseModels/AutoRemediationSuggestion.js +62 -0
  728. package/build/dist/Models/DatabaseModels/AutoRemediationSuggestion.js.map +1 -1
  729. package/build/dist/Models/DatabaseModels/IncidentAlert.js +553 -0
  730. package/build/dist/Models/DatabaseModels/IncidentAlert.js.map +1 -0
  731. package/build/dist/Models/DatabaseModels/IncidentEpisodeMember.js +8 -1
  732. package/build/dist/Models/DatabaseModels/IncidentEpisodeMember.js.map +1 -1
  733. package/build/dist/Models/DatabaseModels/IncidentEpisodePublicNote.js +10 -3
  734. package/build/dist/Models/DatabaseModels/IncidentEpisodePublicNote.js.map +1 -1
  735. package/build/dist/Models/DatabaseModels/IncidentFeed.js +2 -0
  736. package/build/dist/Models/DatabaseModels/IncidentFeed.js.map +1 -1
  737. package/build/dist/Models/DatabaseModels/IncidentPublicNote.js +10 -3
  738. package/build/dist/Models/DatabaseModels/IncidentPublicNote.js.map +1 -1
  739. package/build/dist/Models/DatabaseModels/Index.js +2 -0
  740. package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
  741. package/build/dist/Models/DatabaseModels/KubernetesCluster.js +434 -0
  742. package/build/dist/Models/DatabaseModels/KubernetesCluster.js.map +1 -1
  743. package/build/dist/Models/DatabaseModels/Monitor.js +49 -0
  744. package/build/dist/Models/DatabaseModels/Monitor.js.map +1 -1
  745. package/build/dist/Models/DatabaseModels/Project.js +62 -0
  746. package/build/dist/Models/DatabaseModels/Project.js.map +1 -1
  747. package/build/dist/Models/DatabaseModels/RumApplication.js +53 -1
  748. package/build/dist/Models/DatabaseModels/RumApplication.js.map +1 -1
  749. package/build/dist/Models/DatabaseModels/Runner.js +4 -4
  750. package/build/dist/Models/DatabaseModels/Runner.js.map +1 -1
  751. package/build/dist/Models/DatabaseModels/RunnerJob.js +66 -0
  752. package/build/dist/Models/DatabaseModels/RunnerJob.js.map +1 -1
  753. package/build/dist/Models/DatabaseModels/ScheduledMaintenancePublicNote.js +11 -3
  754. package/build/dist/Models/DatabaseModels/ScheduledMaintenancePublicNote.js.map +1 -1
  755. package/build/dist/Models/DatabaseModels/WorkflowVariable.js +487 -3
  756. package/build/dist/Models/DatabaseModels/WorkflowVariable.js.map +1 -1
  757. package/build/dist/Models/DatabaseModels/WorkspaceProjectAuthToken.js +64 -16
  758. package/build/dist/Models/DatabaseModels/WorkspaceProjectAuthToken.js.map +1 -1
  759. package/build/dist/Server/API/AIInvestigationAPI.js +205 -0
  760. package/build/dist/Server/API/AIInvestigationAPI.js.map +1 -1
  761. package/build/dist/Server/API/AutoRemediationAPI.js +115 -2
  762. package/build/dist/Server/API/AutoRemediationAPI.js.map +1 -1
  763. package/build/dist/Server/API/CommonAPI.js +49 -0
  764. package/build/dist/Server/API/CommonAPI.js.map +1 -1
  765. package/build/dist/Server/API/KubernetesClusterAiAccessAPI.js +564 -0
  766. package/build/dist/Server/API/KubernetesClusterAiAccessAPI.js.map +1 -0
  767. package/build/dist/Server/API/MicrosoftTeamsAPI.js +465 -176
  768. package/build/dist/Server/API/MicrosoftTeamsAPI.js.map +1 -1
  769. package/build/dist/Server/API/MonitorAPI.js +107 -1
  770. package/build/dist/Server/API/MonitorAPI.js.map +1 -1
  771. package/build/dist/Server/API/OnCallScheduleTimelineAPI.js +5 -16
  772. package/build/dist/Server/API/OnCallScheduleTimelineAPI.js.map +1 -1
  773. package/build/dist/Server/API/SlackAPI.js +322 -78
  774. package/build/dist/Server/API/SlackAPI.js.map +1 -1
  775. package/build/dist/Server/API/StatusPageAPI.js +123 -17
  776. package/build/dist/Server/API/StatusPageAPI.js.map +1 -1
  777. package/build/dist/Server/API/TelemetryAPI.js +144 -5
  778. package/build/dist/Server/API/TelemetryAPI.js.map +1 -1
  779. package/build/dist/Server/API/UserTwoFactorBackupCodeAPI.js +1 -0
  780. package/build/dist/Server/API/UserTwoFactorBackupCodeAPI.js.map +1 -1
  781. package/build/dist/Server/API/WorkflowVariableAPI.js +109 -0
  782. package/build/dist/Server/API/WorkflowVariableAPI.js.map +1 -0
  783. package/build/dist/Server/Infrastructure/GlobalCache.js +29 -0
  784. package/build/dist/Server/Infrastructure/GlobalCache.js.map +1 -1
  785. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1794300000000-AddOAuth2WorkflowVariables.js +38 -0
  786. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1794300000000-AddOAuth2WorkflowVariables.js.map +1 -0
  787. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1794400000000-AddKubernetesClusterAiAccess.js +54 -0
  788. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1794400000000-AddKubernetesClusterAiAccess.js.map +1 -0
  789. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1794500000000-AddIncomingEmailCustomAddressToMonitor.js +14 -0
  790. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1794500000000-AddIncomingEmailCustomAddressToMonitor.js.map +1 -0
  791. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1794600000000-AddAuthTokenExpiresAtToWorkspaceProjectAuthToken.js +12 -0
  792. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1794600000000-AddAuthTokenExpiresAtToWorkspaceProjectAuthToken.js.map +1 -0
  793. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1794700000000-RemoveAppAccessTokenFromWorkspaceProjectAuthTokenMiscData.js +32 -0
  794. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1794700000000-RemoveAppAccessTokenFromWorkspaceProjectAuthTokenMiscData.js.map +1 -0
  795. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1794800000000-AddSessionReplaySameOriginTracePropagation.js +20 -0
  796. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1794800000000-AddSessionReplaySameOriginTracePropagation.js.map +1 -0
  797. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1794900000000-AddIncidentAlert.js +42 -0
  798. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1794900000000-AddIncidentAlert.js.map +1 -0
  799. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +14 -0
  800. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  801. package/build/dist/Server/Middleware/MasterAdminAuthorization.js +21 -0
  802. package/build/dist/Server/Middleware/MasterAdminAuthorization.js.map +1 -1
  803. package/build/dist/Server/Middleware/TelemetryIngest.js +32 -2
  804. package/build/dist/Server/Middleware/TelemetryIngest.js.map +1 -1
  805. package/build/dist/Server/Middleware/UserAuthorization.js +39 -6
  806. package/build/dist/Server/Middleware/UserAuthorization.js.map +1 -1
  807. package/build/dist/Server/Services/AIAgentService.js +1 -0
  808. package/build/dist/Server/Services/AIAgentService.js.map +1 -1
  809. package/build/dist/Server/Services/AccessTokenService.js +87 -42
  810. package/build/dist/Server/Services/AccessTokenService.js.map +1 -1
  811. package/build/dist/Server/Services/AlertEpisodeMemberService.js +4 -0
  812. package/build/dist/Server/Services/AlertEpisodeMemberService.js.map +1 -1
  813. package/build/dist/Server/Services/AlertEpisodeService.js +12 -1
  814. package/build/dist/Server/Services/AlertEpisodeService.js.map +1 -1
  815. package/build/dist/Server/Services/AlertService.js +110 -23
  816. package/build/dist/Server/Services/AlertService.js.map +1 -1
  817. package/build/dist/Server/Services/AutoRemediationRuleEngineService.js +716 -30
  818. package/build/dist/Server/Services/AutoRemediationRuleEngineService.js.map +1 -1
  819. package/build/dist/Server/Services/AutoRemediationRuleService.js +100 -0
  820. package/build/dist/Server/Services/AutoRemediationRuleService.js.map +1 -1
  821. package/build/dist/Server/Services/BillingService.js +1 -0
  822. package/build/dist/Server/Services/BillingService.js.map +1 -1
  823. package/build/dist/Server/Services/InboundEmail/Providers/SendGridInboundProvider.js +11 -16
  824. package/build/dist/Server/Services/InboundEmail/Providers/SendGridInboundProvider.js.map +1 -1
  825. package/build/dist/Server/Services/IncidentAlertService.js +1370 -0
  826. package/build/dist/Server/Services/IncidentAlertService.js.map +1 -0
  827. package/build/dist/Server/Services/IncidentEpisodeMemberService.js +4 -0
  828. package/build/dist/Server/Services/IncidentEpisodeMemberService.js.map +1 -1
  829. package/build/dist/Server/Services/IncidentEpisodePublicNoteService.js +48 -0
  830. package/build/dist/Server/Services/IncidentEpisodePublicNoteService.js.map +1 -1
  831. package/build/dist/Server/Services/IncidentEpisodeRoleMemberService.js +21 -0
  832. package/build/dist/Server/Services/IncidentEpisodeRoleMemberService.js.map +1 -1
  833. package/build/dist/Server/Services/IncidentEpisodeService.js +12 -1
  834. package/build/dist/Server/Services/IncidentEpisodeService.js.map +1 -1
  835. package/build/dist/Server/Services/IncidentGroupingEngineService.js +8 -0
  836. package/build/dist/Server/Services/IncidentGroupingEngineService.js.map +1 -1
  837. package/build/dist/Server/Services/IncidentMemberService.js +14 -0
  838. package/build/dist/Server/Services/IncidentMemberService.js.map +1 -1
  839. package/build/dist/Server/Services/IncidentPublicNoteService.js +48 -0
  840. package/build/dist/Server/Services/IncidentPublicNoteService.js.map +1 -1
  841. package/build/dist/Server/Services/IncidentService.js +263 -33
  842. package/build/dist/Server/Services/IncidentService.js.map +1 -1
  843. package/build/dist/Server/Services/IncidentStateTimelineService.js +33 -0
  844. package/build/dist/Server/Services/IncidentStateTimelineService.js.map +1 -1
  845. package/build/dist/Server/Services/IncidentTemplateService.js +68 -4
  846. package/build/dist/Server/Services/IncidentTemplateService.js.map +1 -1
  847. package/build/dist/Server/Services/Index.js +2 -0
  848. package/build/dist/Server/Services/Index.js.map +1 -1
  849. package/build/dist/Server/Services/KubernetesClusterAiAccessService.js +1470 -0
  850. package/build/dist/Server/Services/KubernetesClusterAiAccessService.js.map +1 -0
  851. package/build/dist/Server/Services/KubernetesClusterService.js +1097 -0
  852. package/build/dist/Server/Services/KubernetesClusterService.js.map +1 -1
  853. package/build/dist/Server/Services/LogAggregationService.js +14 -6
  854. package/build/dist/Server/Services/LogAggregationService.js.map +1 -1
  855. package/build/dist/Server/Services/MonitorService.js +487 -48
  856. package/build/dist/Server/Services/MonitorService.js.map +1 -1
  857. package/build/dist/Server/Services/MonitorStatusTimelineService.js +540 -3
  858. package/build/dist/Server/Services/MonitorStatusTimelineService.js.map +1 -1
  859. package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleScheduleService.js +2 -0
  860. package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleScheduleService.js.map +1 -1
  861. package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleTeamService.js +2 -0
  862. package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleTeamService.js.map +1 -1
  863. package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleUserService.js +2 -0
  864. package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleUserService.js.map +1 -1
  865. package/build/dist/Server/Services/OnCallDutyPolicyScheduleService.js +3 -0
  866. package/build/dist/Server/Services/OnCallDutyPolicyScheduleService.js.map +1 -1
  867. package/build/dist/Server/Services/OnCallNotificationAlertingService.js +29 -7
  868. package/build/dist/Server/Services/OnCallNotificationAlertingService.js.map +1 -1
  869. package/build/dist/Server/Services/OnCallSetupReminderService.js +1 -0
  870. package/build/dist/Server/Services/OnCallSetupReminderService.js.map +1 -1
  871. package/build/dist/Server/Services/ProbeService.js +7 -1
  872. package/build/dist/Server/Services/ProbeService.js.map +1 -1
  873. package/build/dist/Server/Services/ProjectService.js +11 -1
  874. package/build/dist/Server/Services/ProjectService.js.map +1 -1
  875. package/build/dist/Server/Services/RunbookCredentialService.js +24 -0
  876. package/build/dist/Server/Services/RunbookCredentialService.js.map +1 -1
  877. package/build/dist/Server/Services/RunbookSecretService.js +44 -0
  878. package/build/dist/Server/Services/RunbookSecretService.js.map +1 -1
  879. package/build/dist/Server/Services/RunnerJobService.js +641 -21
  880. package/build/dist/Server/Services/RunnerJobService.js.map +1 -1
  881. package/build/dist/Server/Services/RunnerService.js +344 -5
  882. package/build/dist/Server/Services/RunnerService.js.map +1 -1
  883. package/build/dist/Server/Services/ScheduledMaintenancePublicNoteService.js +48 -0
  884. package/build/dist/Server/Services/ScheduledMaintenancePublicNoteService.js.map +1 -1
  885. package/build/dist/Server/Services/ScheduledMaintenanceService.js +102 -20
  886. package/build/dist/Server/Services/ScheduledMaintenanceService.js.map +1 -1
  887. package/build/dist/Server/Services/ScheduledMaintenanceTemplateService.js +67 -4
  888. package/build/dist/Server/Services/ScheduledMaintenanceTemplateService.js.map +1 -1
  889. package/build/dist/Server/Services/ServiceLevelObjectiveService.js +12 -1
  890. package/build/dist/Server/Services/ServiceLevelObjectiveService.js.map +1 -1
  891. package/build/dist/Server/Services/StatusPagePrivateUserService.js +1 -0
  892. package/build/dist/Server/Services/StatusPagePrivateUserService.js.map +1 -1
  893. package/build/dist/Server/Services/StatusPageService.js +230 -32
  894. package/build/dist/Server/Services/StatusPageService.js.map +1 -1
  895. package/build/dist/Server/Services/StatusPageSubscriberService.js +4 -0
  896. package/build/dist/Server/Services/StatusPageSubscriberService.js.map +1 -1
  897. package/build/dist/Server/Services/TeamMemberService.js +270 -11
  898. package/build/dist/Server/Services/TeamMemberService.js.map +1 -1
  899. package/build/dist/Server/Services/TraceAggregationService.js +10 -6
  900. package/build/dist/Server/Services/TraceAggregationService.js.map +1 -1
  901. package/build/dist/Server/Services/UserEmailService.js +1 -0
  902. package/build/dist/Server/Services/UserEmailService.js.map +1 -1
  903. package/build/dist/Server/Services/UserNotificationMethodAdminService.js +1 -0
  904. package/build/dist/Server/Services/UserNotificationMethodAdminService.js.map +1 -1
  905. package/build/dist/Server/Services/UserNotificationRuleAdminService.js +1 -0
  906. package/build/dist/Server/Services/UserNotificationRuleAdminService.js.map +1 -1
  907. package/build/dist/Server/Services/UserNotificationRuleService.js +4 -0
  908. package/build/dist/Server/Services/UserNotificationRuleService.js.map +1 -1
  909. package/build/dist/Server/Services/UserService.js +107 -1
  910. package/build/dist/Server/Services/UserService.js.map +1 -1
  911. package/build/dist/Server/Services/WorkflowVariableService.js +396 -7
  912. package/build/dist/Server/Services/WorkflowVariableService.js.map +1 -1
  913. package/build/dist/Server/Services/WorkspaceNotificationRuleService.js +463 -7
  914. package/build/dist/Server/Services/WorkspaceNotificationRuleService.js.map +1 -1
  915. package/build/dist/Server/Services/WorkspaceProjectAuthTokenService.js +144 -2
  916. package/build/dist/Server/Services/WorkspaceProjectAuthTokenService.js.map +1 -1
  917. package/build/dist/Server/Types/Database/QueryHelper.js +20 -0
  918. package/build/dist/Server/Types/Database/QueryHelper.js.map +1 -1
  919. package/build/dist/Server/Types/Markdown.js +394 -27
  920. package/build/dist/Server/Types/Markdown.js.map +1 -1
  921. package/build/dist/Server/Utils/AI/ClusterAccess/ClusterAccessContext.js +123 -0
  922. package/build/dist/Server/Utils/AI/ClusterAccess/ClusterAccessContext.js.map +1 -0
  923. package/build/dist/Server/Utils/AI/ClusterAccess/KubectlInvestigationToolkit.js +344 -0
  924. package/build/dist/Server/Utils/AI/ClusterAccess/KubectlInvestigationToolkit.js.map +1 -0
  925. package/build/dist/Server/Utils/AI/ClusterAccess/KubectlJobRunner.js +587 -0
  926. package/build/dist/Server/Utils/AI/ClusterAccess/KubectlJobRunner.js.map +1 -0
  927. package/build/dist/Server/Utils/AI/CodeFix/CodeFixAgentAuth.js +18 -2
  928. package/build/dist/Server/Utils/AI/CodeFix/CodeFixAgentAuth.js.map +1 -1
  929. package/build/dist/Server/Utils/AI/Remediation/RemediationCommandTools.js +1380 -239
  930. package/build/dist/Server/Utils/AI/Remediation/RemediationCommandTools.js.map +1 -1
  931. package/build/dist/Server/Utils/AI/Remediation/RemediationExecutionRunner.js +1099 -68
  932. package/build/dist/Server/Utils/AI/Remediation/RemediationExecutionRunner.js.map +1 -1
  933. package/build/dist/Server/Utils/AI/SRE/AIInvestigationEngine.js +88 -6
  934. package/build/dist/Server/Utils/AI/SRE/AIInvestigationEngine.js.map +1 -1
  935. package/build/dist/Server/Utils/AI/SRE/AlertInvestigationRunner.js +45 -11
  936. package/build/dist/Server/Utils/AI/SRE/AlertInvestigationRunner.js.map +1 -1
  937. package/build/dist/Server/Utils/AI/SRE/IncidentInvestigationRunner.js +41 -11
  938. package/build/dist/Server/Utils/AI/SRE/IncidentInvestigationRunner.js.map +1 -1
  939. package/build/dist/Server/Utils/AI/Toolbox/AIActionTools.js +11 -4
  940. package/build/dist/Server/Utils/AI/Toolbox/AIActionTools.js.map +1 -1
  941. package/build/dist/Server/Utils/AI/Toolbox/ResourceTools.js +4 -2
  942. package/build/dist/Server/Utils/AI/Toolbox/ResourceTools.js.map +1 -1
  943. package/build/dist/Server/Utils/AutoRemediation/CommandPlanExecutor.js +997 -141
  944. package/build/dist/Server/Utils/AutoRemediation/CommandPlanExecutor.js.map +1 -1
  945. package/build/dist/Server/Utils/AutoRemediation/RemediationVerifier.js +299 -4
  946. package/build/dist/Server/Utils/AutoRemediation/RemediationVerifier.js.map +1 -1
  947. package/build/dist/Server/Utils/Database/AffectedResourceRelations.js +120 -0
  948. package/build/dist/Server/Utils/Database/AffectedResourceRelations.js.map +1 -0
  949. package/build/dist/Server/Utils/Database/ProjectScopedReferenceValidator.js +160 -1
  950. package/build/dist/Server/Utils/Database/ProjectScopedReferenceValidator.js.map +1 -1
  951. package/build/dist/Server/Utils/EmailRollup/EmailRollupFlushRunner.js +1 -0
  952. package/build/dist/Server/Utils/EmailRollup/EmailRollupFlushRunner.js.map +1 -1
  953. package/build/dist/Server/Utils/Monitor/MonitorAlert.js +59 -12
  954. package/build/dist/Server/Utils/Monitor/MonitorAlert.js.map +1 -1
  955. package/build/dist/Server/Utils/Monitor/MonitorCriteriaObservationBuilder.js +5 -1
  956. package/build/dist/Server/Utils/Monitor/MonitorCriteriaObservationBuilder.js.map +1 -1
  957. package/build/dist/Server/Utils/Monitor/MonitorIncident.js +84 -22
  958. package/build/dist/Server/Utils/Monitor/MonitorIncident.js.map +1 -1
  959. package/build/dist/Server/Utils/Monitor/MonitorPayloadRedaction.js +70 -5
  960. package/build/dist/Server/Utils/Monitor/MonitorPayloadRedaction.js.map +1 -1
  961. package/build/dist/Server/Utils/Monitor/ProbeMonitorsNotification.js +249 -0
  962. package/build/dist/Server/Utils/Monitor/ProbeMonitorsNotification.js.map +1 -0
  963. package/build/dist/Server/Utils/OnCall/OnCallShiftReminderRunner.js +1 -0
  964. package/build/dist/Server/Utils/OnCall/OnCallShiftReminderRunner.js.map +1 -1
  965. package/build/dist/Server/Utils/PushNotificationUtil.js +27 -0
  966. package/build/dist/Server/Utils/PushNotificationUtil.js.map +1 -1
  967. package/build/dist/Server/Utils/Rules/OwnerRuleAssignment.js +26 -3
  968. package/build/dist/Server/Utils/Rules/OwnerRuleAssignment.js.map +1 -1
  969. package/build/dist/Server/Utils/Runbook/RunbookExecutePermission.js +38 -3
  970. package/build/dist/Server/Utils/Runbook/RunbookExecutePermission.js.map +1 -1
  971. package/build/dist/Server/Utils/SessionReplay/SessionReplayGateCache.js +8 -0
  972. package/build/dist/Server/Utils/SessionReplay/SessionReplayGateCache.js.map +1 -1
  973. package/build/dist/Server/Utils/SessionReplay/SessionReplayReadService.js +143 -23
  974. package/build/dist/Server/Utils/SessionReplay/SessionReplayReadService.js.map +1 -1
  975. package/build/dist/Server/Utils/SessionReplay/SessionReplayUserFlowReadService.js +406 -0
  976. package/build/dist/Server/Utils/SessionReplay/SessionReplayUserFlowReadService.js.map +1 -0
  977. package/build/dist/Server/Utils/StartServer.js +4 -3
  978. package/build/dist/Server/Utils/StartServer.js.map +1 -1
  979. package/build/dist/Server/Utils/TeamMember/ProjectLeaveResourceCleanup.js +382 -0
  980. package/build/dist/Server/Utils/TeamMember/ProjectLeaveResourceCleanup.js.map +1 -0
  981. package/build/dist/Server/Utils/TwoFactorBackupCodeNotification.js +1 -0
  982. package/build/dist/Server/Utils/TwoFactorBackupCodeNotification.js.map +1 -1
  983. package/build/dist/Server/Utils/UserPermission/UserPermission.js +10 -0
  984. package/build/dist/Server/Utils/UserPermission/UserPermission.js.map +1 -1
  985. package/build/dist/Server/Utils/Workflow/OAuth2TokenClient.js +447 -0
  986. package/build/dist/Server/Utils/Workflow/OAuth2TokenClient.js.map +1 -0
  987. package/build/dist/Server/Utils/Workflow/WorkflowVariableOAuthToken.js +202 -0
  988. package/build/dist/Server/Utils/Workflow/WorkflowVariableOAuthToken.js.map +1 -0
  989. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/Alert.js +39 -1
  990. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/Alert.js.map +1 -1
  991. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/AlertEpisode.js +44 -4
  992. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/AlertEpisode.js.map +1 -1
  993. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/Incident.js +150 -191
  994. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/Incident.js.map +1 -1
  995. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/IncidentEpisode.js +44 -4
  996. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/IncidentEpisode.js.map +1 -1
  997. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/Monitor.js +39 -17
  998. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/Monitor.js.map +1 -1
  999. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/ScheduledMaintenance.js +151 -145
  1000. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/ScheduledMaintenance.js.map +1 -1
  1001. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js +221 -127
  1002. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js.map +1 -1
  1003. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsServiceUrl.js +91 -0
  1004. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsServiceUrl.js.map +1 -0
  1005. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/ReactionNoteSync.js +673 -0
  1006. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/ReactionNoteSync.js.map +1 -0
  1007. package/build/dist/Server/Utils/Workspace/Slack/Actions/ActionTypes.js +3 -9
  1008. package/build/dist/Server/Utils/Workspace/Slack/Actions/ActionTypes.js.map +1 -1
  1009. package/build/dist/Server/Utils/Workspace/Slack/Actions/Alert.js +65 -166
  1010. package/build/dist/Server/Utils/Workspace/Slack/Actions/Alert.js.map +1 -1
  1011. package/build/dist/Server/Utils/Workspace/Slack/Actions/AlertEpisode.js +63 -157
  1012. package/build/dist/Server/Utils/Workspace/Slack/Actions/AlertEpisode.js.map +1 -1
  1013. package/build/dist/Server/Utils/Workspace/Slack/Actions/Auth.js +23 -3
  1014. package/build/dist/Server/Utils/Workspace/Slack/Actions/Auth.js.map +1 -1
  1015. package/build/dist/Server/Utils/Workspace/Slack/Actions/Authorization.js +92 -0
  1016. package/build/dist/Server/Utils/Workspace/Slack/Actions/Authorization.js.map +1 -0
  1017. package/build/dist/Server/Utils/Workspace/Slack/Actions/Incident.js +81 -210
  1018. package/build/dist/Server/Utils/Workspace/Slack/Actions/Incident.js.map +1 -1
  1019. package/build/dist/Server/Utils/Workspace/Slack/Actions/IncidentEpisode.js +68 -138
  1020. package/build/dist/Server/Utils/Workspace/Slack/Actions/IncidentEpisode.js.map +1 -1
  1021. package/build/dist/Server/Utils/Workspace/Slack/Actions/ReactionNote.js +240 -0
  1022. package/build/dist/Server/Utils/Workspace/Slack/Actions/ReactionNote.js.map +1 -0
  1023. package/build/dist/Server/Utils/Workspace/Slack/Actions/ScheduledMaintenance.js +85 -212
  1024. package/build/dist/Server/Utils/Workspace/Slack/Actions/ScheduledMaintenance.js.map +1 -1
  1025. package/build/dist/Server/Utils/Workspace/Slack/Slack.js +60 -17
  1026. package/build/dist/Server/Utils/Workspace/Slack/Slack.js.map +1 -1
  1027. package/build/dist/Server/Utils/Workspace/Slack/app-manifest.json +2 -0
  1028. package/build/dist/Server/Utils/Workspace/Workspace.js +134 -41
  1029. package/build/dist/Server/Utils/Workspace/Workspace.js.map +1 -1
  1030. package/build/dist/Server/Utils/Workspace/WorkspaceActionAuthorization.js +197 -0
  1031. package/build/dist/Server/Utils/Workspace/WorkspaceActionAuthorization.js.map +1 -0
  1032. package/build/dist/Server/Utils/Workspace/WorkspaceBase.js +32 -0
  1033. package/build/dist/Server/Utils/Workspace/WorkspaceBase.js.map +1 -1
  1034. package/build/dist/Server/Utils/Workspace/WorkspaceOAuthState.js +199 -0
  1035. package/build/dist/Server/Utils/Workspace/WorkspaceOAuthState.js.map +1 -0
  1036. package/build/dist/Server/Utils/Workspace/WorkspaceProjectReferenceValidator.js +91 -0
  1037. package/build/dist/Server/Utils/Workspace/WorkspaceProjectReferenceValidator.js.map +1 -0
  1038. package/build/dist/Server/Utils/Workspace/WorkspaceReactionNote.js +450 -0
  1039. package/build/dist/Server/Utils/Workspace/WorkspaceReactionNote.js.map +1 -0
  1040. package/build/dist/Types/AutoRemediation/AiRemediationCommandPlan.js +103 -5
  1041. package/build/dist/Types/AutoRemediation/AiRemediationCommandPlan.js.map +1 -1
  1042. package/build/dist/Types/Date.js +97 -7
  1043. package/build/dist/Types/Date.js.map +1 -1
  1044. package/build/dist/Types/Email/EmailTemplateType.js +1 -0
  1045. package/build/dist/Types/Email/EmailTemplateType.js.map +1 -1
  1046. package/build/dist/Types/Exception/ExceptionMessages.js +1 -0
  1047. package/build/dist/Types/Exception/ExceptionMessages.js.map +1 -1
  1048. package/build/dist/Types/Incident/IncidentAlertLink.js +34 -0
  1049. package/build/dist/Types/Incident/IncidentAlertLink.js.map +1 -0
  1050. package/build/dist/Types/Kubernetes/KubernetesClusterAiAccess.js +245 -0
  1051. package/build/dist/Types/Kubernetes/KubernetesClusterAiAccess.js.map +1 -0
  1052. package/build/dist/Types/Kubernetes/KubernetesClusterAiAccessPermissions.js +49 -0
  1053. package/build/dist/Types/Kubernetes/KubernetesClusterAiAccessPermissions.js.map +1 -0
  1054. package/build/dist/Types/Kubernetes/KubernetesClusterAiAccessToolNames.js +16 -0
  1055. package/build/dist/Types/Kubernetes/KubernetesClusterAiAccessToolNames.js.map +1 -0
  1056. package/build/dist/Types/Monitor/DatabaseMonitor/SqlServerPlatform.js +104 -0
  1057. package/build/dist/Types/Monitor/DatabaseMonitor/SqlServerPlatform.js.map +1 -0
  1058. package/build/dist/Types/Monitor/KubernetesAlertTemplates.js +6 -5
  1059. package/build/dist/Types/Monitor/KubernetesAlertTemplates.js.map +1 -1
  1060. package/build/dist/Types/Monitor/MonitorStepExceptionMonitor.js +32 -0
  1061. package/build/dist/Types/Monitor/MonitorStepExceptionMonitor.js.map +1 -1
  1062. package/build/dist/Types/Monitor/MonitorUptimeSummary.js +52 -0
  1063. package/build/dist/Types/Monitor/MonitorUptimeSummary.js.map +1 -0
  1064. package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationUtil.js +9 -1
  1065. package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationUtil.js.map +1 -1
  1066. package/build/dist/Types/Permission.js +42 -0
  1067. package/build/dist/Types/Permission.js.map +1 -1
  1068. package/build/dist/Types/Rum/SessionReplay.js +52 -2
  1069. package/build/dist/Types/Rum/SessionReplay.js.map +1 -1
  1070. package/build/dist/Types/Rum/SessionReplayApi.js +11 -0
  1071. package/build/dist/Types/Rum/SessionReplayApi.js.map +1 -1
  1072. package/build/dist/Types/Rum/UserFlow.js +115 -0
  1073. package/build/dist/Types/Rum/UserFlow.js.map +1 -0
  1074. package/build/dist/Types/Rum/WebVitals.js +25 -0
  1075. package/build/dist/Types/Rum/WebVitals.js.map +1 -1
  1076. package/build/dist/Types/Runbook/RunbookStepType.js +10 -0
  1077. package/build/dist/Types/Runbook/RunbookStepType.js.map +1 -1
  1078. package/build/dist/Types/Runbook/RunnerJobOrigin.js +14 -0
  1079. package/build/dist/Types/Runbook/RunnerJobOrigin.js.map +1 -1
  1080. package/build/dist/Types/SecurityEvent/Connectors/SecurityEventConnectorCatalog.js +2 -2
  1081. package/build/dist/Types/SecurityEvent/Connectors/SecurityEventConnectorCatalog.js.map +1 -1
  1082. package/build/dist/Types/StatusPage/MergedDowntimeTotals.js +2 -0
  1083. package/build/dist/Types/StatusPage/MergedDowntimeTotals.js.map +1 -0
  1084. package/build/dist/Types/StatusPage/PublicNoteSubscriberNotificationDefault.js +65 -0
  1085. package/build/dist/Types/StatusPage/PublicNoteSubscriberNotificationDefault.js.map +1 -0
  1086. package/build/dist/Types/Telemetry/TelemetryIngestSurface.js +8 -0
  1087. package/build/dist/Types/Telemetry/TelemetryIngestSurface.js.map +1 -1
  1088. package/build/dist/Types/Timezone.js +5 -0
  1089. package/build/dist/Types/Timezone.js.map +1 -1
  1090. package/build/dist/Types/TimezoneAlias.js +340 -0
  1091. package/build/dist/Types/TimezoneAlias.js.map +1 -0
  1092. package/build/dist/Types/Workflow/Templates.js +2694 -2
  1093. package/build/dist/Types/Workflow/Templates.js.map +1 -1
  1094. package/build/dist/Types/Workflow/WorkflowVariableOAuth.js +314 -0
  1095. package/build/dist/Types/Workflow/WorkflowVariableOAuth.js.map +1 -0
  1096. package/build/dist/Types/Workspace/WorkspaceNoteReaction.js +98 -0
  1097. package/build/dist/Types/Workspace/WorkspaceNoteReaction.js.map +1 -0
  1098. package/build/dist/UI/Components/AttributesJSON/AttributesJSONPreferences.js +95 -0
  1099. package/build/dist/UI/Components/AttributesJSON/AttributesJSONPreferences.js.map +1 -0
  1100. package/build/dist/UI/Components/AttributesJSON/AttributesJSONView.js +44 -0
  1101. package/build/dist/UI/Components/AttributesJSON/AttributesJSONView.js.map +1 -0
  1102. package/build/dist/UI/Components/AttributesJSON/AttributesViewToggle.js +27 -0
  1103. package/build/dist/UI/Components/AttributesJSON/AttributesViewToggle.js.map +1 -0
  1104. package/build/dist/UI/Components/AttributesJSON/BracesGlyph.js +9 -0
  1105. package/build/dist/UI/Components/AttributesJSON/BracesGlyph.js.map +1 -0
  1106. package/build/dist/UI/Components/AttributesJSON/CopyAttributesAsJSONButton.js +260 -0
  1107. package/build/dist/UI/Components/AttributesJSON/CopyAttributesAsJSONButton.js.map +1 -0
  1108. package/build/dist/UI/Components/AttributesJSON/JSONHighlight.js +56 -0
  1109. package/build/dist/UI/Components/AttributesJSON/JSONHighlight.js.map +1 -0
  1110. package/build/dist/UI/Components/Calendar/Calendar.js +94 -7
  1111. package/build/dist/UI/Components/Calendar/Calendar.js.map +1 -1
  1112. package/build/dist/UI/Components/Calendar/CalendarDayLayout.js +136 -0
  1113. package/build/dist/UI/Components/Calendar/CalendarDayLayout.js.map +1 -0
  1114. package/build/dist/UI/Components/Charts/ChartGroup/ChartGroup.js +1 -1
  1115. package/build/dist/UI/Components/Charts/ChartGroup/ChartGroup.js.map +1 -1
  1116. package/build/dist/UI/Components/Charts/Utils/HistogramSelection.js +72 -0
  1117. package/build/dist/UI/Components/Charts/Utils/HistogramSelection.js.map +1 -0
  1118. package/build/dist/UI/Components/Charts/Utils/useHistogramRangeSelection.js +178 -0
  1119. package/build/dist/UI/Components/Charts/Utils/useHistogramRangeSelection.js.map +1 -0
  1120. package/build/dist/UI/Components/Charts/Utils/useHistogramZoom.js +13 -1
  1121. package/build/dist/UI/Components/Charts/Utils/useHistogramZoom.js.map +1 -1
  1122. package/build/dist/UI/Components/Date/CustomTimeRangeModal.js +20 -4
  1123. package/build/dist/UI/Components/Date/CustomTimeRangeModal.js.map +1 -1
  1124. package/build/dist/UI/Components/Detail/FieldLabel.js +2 -0
  1125. package/build/dist/UI/Components/Detail/FieldLabel.js.map +1 -1
  1126. package/build/dist/UI/Components/Dropdown/Dropdown.js +33 -9
  1127. package/build/dist/UI/Components/Dropdown/Dropdown.js.map +1 -1
  1128. package/build/dist/UI/Components/Forms/Fields/FormField.js +36 -13
  1129. package/build/dist/UI/Components/Forms/Fields/FormField.js.map +1 -1
  1130. package/build/dist/UI/Components/Graphs/DayUptimeGraph.js +117 -11
  1131. package/build/dist/UI/Components/Graphs/DayUptimeGraph.js.map +1 -1
  1132. package/build/dist/UI/Components/Graphs/UptimeBarTooltip.js +5 -1
  1133. package/build/dist/UI/Components/Graphs/UptimeBarTooltip.js.map +1 -1
  1134. package/build/dist/UI/Components/Graphs/UptimeDaySummary.js.map +1 -1
  1135. package/build/dist/UI/Components/InfoCard/InfoCard.js +22 -1
  1136. package/build/dist/UI/Components/InfoCard/InfoCard.js.map +1 -1
  1137. package/build/dist/UI/Components/LogsViewer/LogsViewer.js +36 -8
  1138. package/build/dist/UI/Components/LogsViewer/LogsViewer.js.map +1 -1
  1139. package/build/dist/UI/Components/LogsViewer/components/ColumnSelector.js +10 -2
  1140. package/build/dist/UI/Components/LogsViewer/components/ColumnSelector.js.map +1 -1
  1141. package/build/dist/UI/Components/LogsViewer/components/KeyboardShortcutsHelp.js +9 -1
  1142. package/build/dist/UI/Components/LogsViewer/components/KeyboardShortcutsHelp.js.map +1 -1
  1143. package/build/dist/UI/Components/LogsViewer/components/LogDetailsPanel.js +16 -15
  1144. package/build/dist/UI/Components/LogsViewer/components/LogDetailsPanel.js.map +1 -1
  1145. package/build/dist/UI/Components/LogsViewer/components/LogsFacetSidebar.js +1 -1
  1146. package/build/dist/UI/Components/LogsViewer/components/LogsFacetSidebar.js.map +1 -1
  1147. package/build/dist/UI/Components/LogsViewer/components/LogsHistogram.js +14 -74
  1148. package/build/dist/UI/Components/LogsViewer/components/LogsHistogram.js.map +1 -1
  1149. package/build/dist/UI/Components/LogsViewer/components/LogsViewerToolbar.js +22 -5
  1150. package/build/dist/UI/Components/LogsViewer/components/LogsViewerToolbar.js.map +1 -1
  1151. package/build/dist/UI/Components/LogsViewer/components/SavedViewsDropdown.js +9 -2
  1152. package/build/dist/UI/Components/LogsViewer/components/SavedViewsDropdown.js.map +1 -1
  1153. package/build/dist/UI/Components/LogsViewer/useLogsHistogram.js +16 -5
  1154. package/build/dist/UI/Components/LogsViewer/useLogsHistogram.js.map +1 -1
  1155. package/build/dist/UI/Components/ModelTable/BaseModelTable.js +89 -22
  1156. package/build/dist/UI/Components/ModelTable/BaseModelTable.js.map +1 -1
  1157. package/build/dist/UI/Components/MonitorGraphs/Uptime.js +7 -1
  1158. package/build/dist/UI/Components/MonitorGraphs/Uptime.js.map +1 -1
  1159. package/build/dist/UI/Components/MonitorGraphs/UptimeBarDayModal.js +5 -1
  1160. package/build/dist/UI/Components/MonitorGraphs/UptimeBarDayModal.js.map +1 -1
  1161. package/build/dist/UI/Components/Page/ModelPage.js +37 -3
  1162. package/build/dist/UI/Components/Page/ModelPage.js.map +1 -1
  1163. package/build/dist/UI/Components/Table/TableHeader.js +18 -2
  1164. package/build/dist/UI/Components/Table/TableHeader.js.map +1 -1
  1165. package/build/dist/UI/Components/TelemetryViewer/TelemetryViewer.js +27 -6
  1166. package/build/dist/UI/Components/TelemetryViewer/TelemetryViewer.js.map +1 -1
  1167. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryDetailPanel.js +7 -1
  1168. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryDetailPanel.js.map +1 -1
  1169. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryFacetSidebar.js +1 -1
  1170. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryFacetSidebar.js.map +1 -1
  1171. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryHistogram.js +17 -77
  1172. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryHistogram.js.map +1 -1
  1173. package/build/dist/UI/Components/TelemetryViewer/components/TelemetrySearchBar.js +10 -1
  1174. package/build/dist/UI/Components/TelemetryViewer/components/TelemetrySearchBar.js.map +1 -1
  1175. package/build/dist/UI/Components/Tooltip/InfoTooltip.js +28 -0
  1176. package/build/dist/UI/Components/Tooltip/InfoTooltip.js.map +1 -0
  1177. package/build/dist/UI/Utils/ModelAPI/ProjectUsersModelAPI.js +15 -1
  1178. package/build/dist/UI/Utils/ModelAPI/ProjectUsersModelAPI.js.map +1 -1
  1179. package/build/dist/UI/Utils/PermissionGate.js +4 -2
  1180. package/build/dist/UI/Utils/PermissionGate.js.map +1 -1
  1181. package/build/dist/UI/Utils/Timezone.js +52 -17
  1182. package/build/dist/UI/Utils/Timezone.js.map +1 -1
  1183. package/build/dist/Utils/AI/InvestigationReport.js +116 -21
  1184. package/build/dist/Utils/AI/InvestigationReport.js.map +1 -1
  1185. package/build/dist/Utils/AiRemediation/KubectlOutputRedactor.js +1209 -0
  1186. package/build/dist/Utils/AiRemediation/KubectlOutputRedactor.js.map +1 -0
  1187. package/build/dist/Utils/AiRemediation/KubectlPolicy.js +2973 -0
  1188. package/build/dist/Utils/AiRemediation/KubectlPolicy.js.map +1 -0
  1189. package/build/dist/Utils/AiRemediation/KubectlWaitBudget.js +99 -0
  1190. package/build/dist/Utils/AiRemediation/KubectlWaitBudget.js.map +1 -0
  1191. package/build/dist/Utils/AiRemediation/KubectlWriteScope.js +1429 -0
  1192. package/build/dist/Utils/AiRemediation/KubectlWriteScope.js.map +1 -0
  1193. package/build/dist/Utils/Dashboard/Components/DashboardClockComponent.js +7 -6
  1194. package/build/dist/Utils/Dashboard/Components/DashboardClockComponent.js.map +1 -1
  1195. package/build/dist/Utils/Incident/IncidentFromAlerts.js +306 -0
  1196. package/build/dist/Utils/Incident/IncidentFromAlerts.js.map +1 -0
  1197. package/build/dist/Utils/Monitor/IncomingEmailMonitorAddress.js +214 -0
  1198. package/build/dist/Utils/Monitor/IncomingEmailMonitorAddress.js.map +1 -0
  1199. package/build/dist/Utils/Monitor/MonitorCheckScheduleUtil.js +471 -0
  1200. package/build/dist/Utils/Monitor/MonitorCheckScheduleUtil.js.map +1 -0
  1201. package/build/dist/Utils/Monitor/MonitorOverviewCriteriaUtil.js +107 -0
  1202. package/build/dist/Utils/Monitor/MonitorOverviewCriteriaUtil.js.map +1 -0
  1203. package/build/dist/Utils/Monitor/MonitorOverviewFamily.js +191 -0
  1204. package/build/dist/Utils/Monitor/MonitorOverviewFamily.js.map +1 -0
  1205. package/build/dist/Utils/Monitor/MonitorOverviewPresentationUtil.js +1259 -0
  1206. package/build/dist/Utils/Monitor/MonitorOverviewPresentationUtil.js.map +1 -0
  1207. package/build/dist/Utils/Monitor/MonitorOverviewProbeUtil.js +593 -0
  1208. package/build/dist/Utils/Monitor/MonitorOverviewProbeUtil.js.map +1 -0
  1209. package/build/dist/Utils/Monitor/MonitorOverviewTargetUtil.js +195 -0
  1210. package/build/dist/Utils/Monitor/MonitorOverviewTargetUtil.js.map +1 -0
  1211. package/build/dist/Utils/Monitor/MonitorStatusHistoryUtil.js +127 -0
  1212. package/build/dist/Utils/Monitor/MonitorStatusHistoryUtil.js.map +1 -0
  1213. package/build/dist/Utils/Monitor/MonitorUptimeSummaryUtil.js +464 -0
  1214. package/build/dist/Utils/Monitor/MonitorUptimeSummaryUtil.js.map +1 -0
  1215. package/build/dist/Utils/Rum/SessionIdentity.js +31 -1
  1216. package/build/dist/Utils/Rum/SessionIdentity.js.map +1 -1
  1217. package/build/dist/Utils/Rum/SessionReplayWireEncoding.js +128 -0
  1218. package/build/dist/Utils/Rum/SessionReplayWireEncoding.js.map +1 -0
  1219. package/build/dist/Utils/Rum/SessionTraceState.js +154 -0
  1220. package/build/dist/Utils/Rum/SessionTraceState.js.map +1 -0
  1221. package/build/dist/Utils/Rum/UserFlow.js +941 -0
  1222. package/build/dist/Utils/Rum/UserFlow.js.map +1 -0
  1223. package/build/dist/Utils/StatusPage/MonitorGroupMergedDowntimeUtil.js +82 -0
  1224. package/build/dist/Utils/StatusPage/MonitorGroupMergedDowntimeUtil.js.map +1 -0
  1225. package/build/dist/Utils/StatusPage/ResourceUptime.js +46 -0
  1226. package/build/dist/Utils/StatusPage/ResourceUptime.js.map +1 -1
  1227. package/build/dist/Utils/StatusPage/UptimeDailyAggregateUtil.js +148 -0
  1228. package/build/dist/Utils/StatusPage/UptimeDailyAggregateUtil.js.map +1 -1
  1229. package/build/dist/Utils/Telemetry/AttributesJSON.js +245 -0
  1230. package/build/dist/Utils/Telemetry/AttributesJSON.js.map +1 -0
  1231. package/build/dist/Utils/Uptime/DayUptimeGraphUtil.js +103 -0
  1232. package/build/dist/Utils/Uptime/DayUptimeGraphUtil.js.map +1 -1
  1233. package/build/dist/Utils/Uptime/UptimeUtil.js +91 -27
  1234. package/build/dist/Utils/Uptime/UptimeUtil.js.map +1 -1
  1235. package/jest.config.json +2 -1
  1236. package/package.json +2 -1
  1237. package/tsconfig.tests.json +36 -0
  1238. package/Tests/UI/Components/EmptyState/EmptyStateGuideLinks.test.tsx +0 -337
  1239. package/UI/Components/EmptyState/EmptyStateGuideLinks.tsx +0 -124
  1240. package/build/dist/UI/Components/EmptyState/EmptyStateGuideLinks.js +0 -47
  1241. package/build/dist/UI/Components/EmptyState/EmptyStateGuideLinks.js.map +0 -1
@@ -0,0 +1,2973 @@
1
+ import { KubectlCommandTier, isProtectedKubernetesNamespace, } from "../../Types/Kubernetes/KubernetesClusterAiAccess";
2
+ import { AiRemediationCommandPolicyVerdict, MAX_COMMAND_LENGTH_CHARS, } from "../../Types/AutoRemediation/AiRemediationCommandPlan";
3
+ import CommandPolicy from "./CommandPolicy";
4
+ /*
5
+ * kubectl normalizes "_" to "-" in long flag names (pflag's
6
+ * WordSepNormalizeFunc), so --as_group IS --as-group and
7
+ * --insecure_skip_tls_verify IS --insecure-skip-tls-verify. Every flag
8
+ * lookup here goes through this first, so an underscore spelling can never
9
+ * slip past a deny list; anything else that inspects kubectl flags (the
10
+ * Runner's argv guard) should use it too.
11
+ */
12
+ export function normalizeKubectlFlagName(name) {
13
+ return (name || "").replace(/_/g, "-");
14
+ }
15
+ const MAX_TOKENS = 64;
16
+ // Tokens made only of these survive a shell split unquoted.
17
+ const SHELL_SAFE_TOKEN = /^[A-Za-z0-9_@%+=:,./-]+$/;
18
+ /*
19
+ * ---- Flags -----------------------------------------------------------------
20
+ *
21
+ * kubectl parses flags with pflag, and this policy has to see the SAME
22
+ * positionals kubectl will see, or a resource kind can hide inside what we
23
+ * took for a flag value, and a flag value can pose as the verb. pflag's
24
+ * rules, which parseArgs() mirrors exactly:
25
+ *
26
+ * - "--flag=value" carries its value inline. "--flag value" carries it in
27
+ * the next token ONLY when the flag takes a value: a boolean flag never
28
+ * consumes the next token, and neither does an optional-value flag
29
+ * ("--cascade" alone means background; "--cascade=orphan" is a value).
30
+ * - "-abc" is a cluster of short flags read letter by letter: each letter
31
+ * is a boolean flag until one that takes a value, whose value is the
32
+ * rest of the token ("-nweb") or, when nothing is left, the next token
33
+ * ("-n web"). "-n=web" works too.
34
+ * - A value flag takes the next token whatever it looks like: "-n -A" is
35
+ * the namespace "-A".
36
+ * - "--" ends flag parsing; everything after it is positional.
37
+ * - "_" in a long flag name reads as "-" ("--all_namespaces"); see
38
+ * normalizeKubectlFlagName, which runs before every lookup.
39
+ * - A flag kubectl does not know is an error.
40
+ * - The command is picked BEFORE flags are parsed (by cobra, not pflag),
41
+ * and at that point any flag that is not a global flag is assumed to
42
+ * take the next word as its value, whatever the verb makes of it later:
43
+ * `kubectl --all events delete -n web` runs `delete --all events`, and
44
+ * `kubectl cluster-info -A x dump` runs `cluster-info dump -A`. So only
45
+ * GLOBAL_FLAGS may precede the verb (and, for SUBCOMMAND_VERBS, the
46
+ * subcommand); every other flag must follow it. kubectl itself rejects
47
+ * most of the other orderings ("flags cannot be placed before plugin
48
+ * name"), so nothing that could have run is lost.
49
+ *
50
+ * Every flag OneUptime AI may use is listed here with its arity. A flag that
51
+ * is not listed is Denied: without knowing whether it swallows the next
52
+ * token we cannot know which token is the verb or the kind, so it is refused
53
+ * rather than guessed. kubectl rejects flags it does not know, so nothing
54
+ * that could have run is lost.
55
+ */
56
+ var FlagArity;
57
+ (function (FlagArity) {
58
+ // Never takes a value: "--all", "-A". ("--all=false" is the only value form.)
59
+ FlagArity["Boolean"] = "Boolean";
60
+ // Always takes a value: "-n web", "-nweb", "-n=web", "--namespace web".
61
+ FlagArity["Value"] = "Value";
62
+ /*
63
+ * Takes a value only when written "--flag=value". Written bare it means
64
+ * its default and never consumes the next token (pflag's NoOptDefVal).
65
+ */
66
+ FlagArity["OptionalValue"] = "OptionalValue";
67
+ })(FlagArity || (FlagArity = {}));
68
+ const KNOWN_FLAGS = {
69
+ // Global (any verb).
70
+ n: FlagArity.Value,
71
+ namespace: FlagArity.Value,
72
+ "request-timeout": FlagArity.Value,
73
+ "match-server-version": FlagArity.Boolean,
74
+ // Output and table shaping. The -o value itself is checked separately.
75
+ o: FlagArity.Value,
76
+ output: FlagArity.Value,
77
+ "allow-missing-template-keys": FlagArity.Boolean,
78
+ "show-labels": FlagArity.Boolean,
79
+ "show-kind": FlagArity.Boolean,
80
+ "show-managed-fields": FlagArity.Boolean,
81
+ "no-headers": FlagArity.Boolean,
82
+ "server-print": FlagArity.Boolean,
83
+ "ignore-not-found": FlagArity.Boolean,
84
+ "output-watch-events": FlagArity.Boolean,
85
+ L: FlagArity.Value,
86
+ "label-columns": FlagArity.Value,
87
+ "sort-by": FlagArity.Value,
88
+ "chunk-size": FlagArity.Value,
89
+ subresource: FlagArity.Value,
90
+ // Selecting objects.
91
+ A: FlagArity.Boolean,
92
+ "all-namespaces": FlagArity.Boolean,
93
+ all: FlagArity.Boolean,
94
+ l: FlagArity.Value,
95
+ selector: FlagArity.Value,
96
+ labels: FlagArity.Value,
97
+ "field-selector": FlagArity.Value,
98
+ // Streaming: booleans, but allowed only as "=false" (see STREAMING_FLAGS).
99
+ w: FlagArity.Boolean,
100
+ watch: FlagArity.Boolean,
101
+ "watch-only": FlagArity.Boolean,
102
+ follow: FlagArity.Boolean,
103
+ // logs.
104
+ c: FlagArity.Value,
105
+ container: FlagArity.Value,
106
+ since: FlagArity.Value,
107
+ "since-time": FlagArity.Value,
108
+ tail: FlagArity.Value,
109
+ "limit-bytes": FlagArity.Value,
110
+ "max-log-requests": FlagArity.Value,
111
+ "pod-running-timeout": FlagArity.Value,
112
+ previous: FlagArity.Boolean,
113
+ timestamps: FlagArity.Boolean,
114
+ "all-containers": FlagArity.Boolean,
115
+ "all-pods": FlagArity.Boolean,
116
+ "ignore-errors": FlagArity.Boolean,
117
+ "insecure-skip-tls-verify-backend": FlagArity.Boolean,
118
+ /*
119
+ * Three names mean different things on different verbs; the value form is
120
+ * the default and VERB_FLAG_OVERRIDES holds the exceptions:
121
+ * -p is --patch (value) on patch, --previous (boolean) on logs
122
+ * --prefix is a value on set env, a boolean on logs
123
+ * --containers is -c (value) on set env/resources, a boolean on top pod
124
+ */
125
+ p: FlagArity.Value,
126
+ patch: FlagArity.Value,
127
+ prefix: FlagArity.Value,
128
+ containers: FlagArity.Value,
129
+ // describe, top, events, api-resources, version, explain, auth.
130
+ "show-events": FlagArity.Boolean,
131
+ sum: FlagArity.Boolean,
132
+ "use-protocol-buffers": FlagArity.Boolean,
133
+ "show-capacity": FlagArity.Boolean,
134
+ for: FlagArity.Value,
135
+ types: FlagArity.Value,
136
+ "api-group": FlagArity.Value,
137
+ categories: FlagArity.Value,
138
+ verbs: FlagArity.Value,
139
+ cached: FlagArity.Boolean,
140
+ namespaced: FlagArity.Boolean,
141
+ client: FlagArity.Boolean,
142
+ "api-version": FlagArity.Value,
143
+ list: FlagArity.Boolean,
144
+ q: FlagArity.Boolean,
145
+ quiet: FlagArity.Boolean,
146
+ // rollout, scale, delete, drain, cordon, label, annotate, taint, patch, set.
147
+ revision: FlagArity.Value,
148
+ "to-revision": FlagArity.Value,
149
+ timeout: FlagArity.Value,
150
+ "field-manager": FlagArity.Value,
151
+ replicas: FlagArity.Value,
152
+ r: FlagArity.Value,
153
+ "current-replicas": FlagArity.Value,
154
+ "resource-version": FlagArity.Value,
155
+ "grace-period": FlagArity.Value,
156
+ "pod-selector": FlagArity.Value,
157
+ "skip-wait-for-delete-timeout": FlagArity.Value,
158
+ force: FlagArity.Boolean,
159
+ now: FlagArity.Boolean,
160
+ wait: FlagArity.Boolean,
161
+ "ignore-daemonsets": FlagArity.Boolean,
162
+ "delete-emptydir-data": FlagArity.Boolean,
163
+ "delete-local-data": FlagArity.Boolean,
164
+ "disable-eviction": FlagArity.Boolean,
165
+ overwrite: FlagArity.Boolean,
166
+ local: FlagArity.Boolean,
167
+ record: FlagArity.Boolean,
168
+ "save-config": FlagArity.Boolean,
169
+ cascade: FlagArity.OptionalValue,
170
+ "dry-run": FlagArity.OptionalValue,
171
+ validate: FlagArity.OptionalValue,
172
+ type: FlagArity.Value,
173
+ image: FlagArity.Value,
174
+ env: FlagArity.Value,
175
+ e: FlagArity.Value,
176
+ from: FlagArity.Value,
177
+ keys: FlagArity.Value,
178
+ limits: FlagArity.Value,
179
+ requests: FlagArity.Value,
180
+ // create, expose, autoscale.
181
+ restart: FlagArity.Value,
182
+ schedule: FlagArity.Value,
183
+ port: FlagArity.Value,
184
+ "target-port": FlagArity.Value,
185
+ protocol: FlagArity.Value,
186
+ name: FlagArity.Value,
187
+ "external-ip": FlagArity.Value,
188
+ "cluster-ip": FlagArity.Value,
189
+ "load-balancer-ip": FlagArity.Value,
190
+ // Listed for their arity only: every write refuses them (OBJECT_OVERRIDE_FLAGS).
191
+ overrides: FlagArity.Value,
192
+ "override-type": FlagArity.Value,
193
+ "session-affinity": FlagArity.Value,
194
+ min: FlagArity.Value,
195
+ max: FlagArity.Value,
196
+ cpu: FlagArity.Value,
197
+ "cpu-percent": FlagArity.Value,
198
+ "from-literal": FlagArity.Value,
199
+ "append-hash": FlagArity.Boolean,
200
+ resource: FlagArity.Value,
201
+ "resource-name": FlagArity.Value,
202
+ verb: FlagArity.Value,
203
+ "non-resource-url": FlagArity.Value,
204
+ "aggregation-rule": FlagArity.Value,
205
+ role: FlagArity.Value,
206
+ clusterrole: FlagArity.Value,
207
+ group: FlagArity.Value,
208
+ serviceaccount: FlagArity.Value,
209
+ hard: FlagArity.Value,
210
+ scopes: FlagArity.Value,
211
+ "min-available": FlagArity.Value,
212
+ "max-unavailable": FlagArity.Value,
213
+ value: FlagArity.Value,
214
+ "global-default": FlagArity.Boolean,
215
+ description: FlagArity.Value,
216
+ "preemption-policy": FlagArity.Value,
217
+ class: FlagArity.Value,
218
+ rule: FlagArity.Value,
219
+ annotation: FlagArity.Value,
220
+ "default-backend": FlagArity.Value,
221
+ tcp: FlagArity.Value,
222
+ "node-port": FlagArity.Value,
223
+ clusterip: FlagArity.Value,
224
+ "docker-server": FlagArity.Value,
225
+ "docker-username": FlagArity.Value,
226
+ "docker-password": FlagArity.Value,
227
+ "docker-email": FlagArity.Value,
228
+ "windows-line-endings": FlagArity.Boolean,
229
+ };
230
+ const KNOWN_FLAG_ARITY = new Map(Object.entries(KNOWN_FLAGS));
231
+ /*
232
+ * Flags whose meaning depends on the verb (see the note in KNOWN_FLAGS), and
233
+ * one that is Denied everywhere except on the verb where it is harmless
234
+ * (explain --recursive prints every field; -R/--recursive elsewhere walks a
235
+ * directory of manifests). The verb is the first positional; kubectl itself
236
+ * rejects a subcommand's boolean flag placed before the verb, so these can
237
+ * only ever follow it.
238
+ */
239
+ const VERB_FLAG_OVERRIDES = {
240
+ logs: { p: FlagArity.Boolean, prefix: FlagArity.Boolean },
241
+ top: { containers: FlagArity.Boolean },
242
+ explain: { recursive: FlagArity.Boolean },
243
+ };
244
+ const VERB_FLAG_OVERRIDE_ARITY = new Map(Object.entries(VERB_FLAG_OVERRIDES).map(([verb, overrides]) => {
245
+ return [verb, new Map(Object.entries(overrides))];
246
+ }));
247
+ /*
248
+ * kubectl's global flags that OneUptime AI may use. They are the only flags
249
+ * allowed before the verb (see the Flags section): kubectl parses them at
250
+ * the root, so writing them first cannot shift which command runs.
251
+ */
252
+ const GLOBAL_FLAGS = new Set([
253
+ "n",
254
+ "namespace",
255
+ "request-timeout",
256
+ "match-server-version",
257
+ ]);
258
+ /*
259
+ * Verbs whose next positional is a subcommand (rollout status, set image,
260
+ * create job, auth can-i, cluster-info dump, top pod). The ordering rule
261
+ * applies between the verb and the subcommand as well.
262
+ */
263
+ const SUBCOMMAND_VERBS = new Set([
264
+ "rollout",
265
+ "set",
266
+ "create",
267
+ "auth",
268
+ "cluster-info",
269
+ "top",
270
+ ]);
271
+ /*
272
+ * Flags that are Denied wherever they appear, with why. Short and long
273
+ * spellings are both listed because a short flag can hide inside a cluster
274
+ * ("-As", "-pf") and is found letter by letter.
275
+ *
276
+ * kubectl v1.36's global flags are --as --as-group --as-uid --as-user-extra
277
+ * --cache-dir --certificate-authority --client-certificate --client-key
278
+ * --cluster --context --disable-compression --insecure-skip-tls-verify
279
+ * --kubeconfig --kuberc --log-flush-frequency --match-server-version
280
+ * -n/--namespace --password --profile --profile-output --request-timeout
281
+ * -s/--server --tls-server-name --token --user --username -v/--v --vmodule
282
+ * --warnings-as-errors. Every one of them except GLOBAL_FLAGS is listed
283
+ * here: each selects credentials, an identity or a cluster, writes a file
284
+ * on the Runner, or logs request bodies. (An unlisted flag is refused
285
+ * anyway; listing them names the reason.)
286
+ */
287
+ const DENIED_FLAG_GROUPS = [
288
+ {
289
+ reason: "OneUptime AI may only use the cluster access it was given, never other credentials, another identity or another cluster",
290
+ flags: [
291
+ "kubeconfig",
292
+ "kuberc",
293
+ "token",
294
+ "server",
295
+ "s",
296
+ "as",
297
+ "as-group",
298
+ "as-uid",
299
+ "as-user-extra",
300
+ "context",
301
+ "cluster",
302
+ "user",
303
+ "username",
304
+ "password",
305
+ "client-certificate",
306
+ "client-key",
307
+ "certificate-authority",
308
+ "insecure-skip-tls-verify",
309
+ "tls-server-name",
310
+ ],
311
+ },
312
+ {
313
+ reason: "it makes kubectl read a file on the Runner (write templates and patches inline instead)",
314
+ flags: [
315
+ "filename",
316
+ "f",
317
+ "kustomize",
318
+ "k",
319
+ "recursive",
320
+ "R",
321
+ "patch-file",
322
+ "from-file",
323
+ "from-env-file",
324
+ "cert",
325
+ "key",
326
+ ],
327
+ },
328
+ {
329
+ reason: "it names the template that -o go-template-file reads from a file on the Runner (write it inline as -o go-template=... or -o jsonpath=... instead)",
330
+ flags: ["template"],
331
+ },
332
+ {
333
+ reason: "it turns kubectl into a raw API client",
334
+ flags: ["raw"],
335
+ },
336
+ {
337
+ reason: "it resolves Secret and ConfigMap references into their plaintext values (kubectl set env --list --resolve prints them)",
338
+ flags: ["resolve"],
339
+ },
340
+ {
341
+ reason: "kubectl's own logging, profiling and cache flags write on the Runner or print request bodies and credentials",
342
+ flags: [
343
+ "v",
344
+ "vmodule",
345
+ "log-file",
346
+ "log-dir",
347
+ "log-file-max-size",
348
+ "log-backtrace-at",
349
+ "log-flush-frequency",
350
+ "alsologtostderr",
351
+ "logtostderr",
352
+ "add-dir-header",
353
+ "one-output",
354
+ "skip-headers",
355
+ "skip-log-headers",
356
+ "stderrthreshold",
357
+ "profile",
358
+ "profile-output",
359
+ "cache-dir",
360
+ ],
361
+ },
362
+ {
363
+ reason: "it needs a terminal or an editor",
364
+ flags: ["i", "interactive", "t", "tty", "stdin", "edit"],
365
+ },
366
+ {
367
+ reason: "it has nothing to offer an SRE agent (kubectl explain documents resources)",
368
+ flags: ["h", "help", "warnings-as-errors", "disable-compression"],
369
+ },
370
+ ];
371
+ const DENIED_FLAG_REASONS = new Map();
372
+ for (const group of DENIED_FLAG_GROUPS) {
373
+ for (const flag of group.flags) {
374
+ DENIED_FLAG_REASONS.set(flag, group.reason);
375
+ }
376
+ }
377
+ /*
378
+ * Flags that keep kubectl running until it is killed. Boolean, so the only
379
+ * way to write them off is "=false", which is what the model should write
380
+ * on rollout status (which watches by default).
381
+ */
382
+ const STREAMING_FLAGS = new Set([
383
+ "w",
384
+ "watch",
385
+ "watch-only",
386
+ "follow",
387
+ ]);
388
+ /*
389
+ * Flags that replace the object kubectl generates with whatever their JSON
390
+ * describes (kubectl expose; see the header's Denied list). They stay in
391
+ * KNOWN_FLAGS with their real arity, so `--overrides '{...}'` is still split
392
+ * where kubectl splits it and the verb is still found, and every write that
393
+ * carries one is refused in evaluateArgs — in every spelling, because
394
+ * parseArgs files `--override_type` and `--overrides=x` under these names —
395
+ * as is an allowlist entry that spells one (readAllowlistEntry). A read
396
+ * keeps them: no read verb takes them (kubectl refuses the command) and a
397
+ * read creates nothing.
398
+ */
399
+ const OBJECT_OVERRIDE_FLAGS = ["overrides", "override-type"];
400
+ /*
401
+ * ---- Output formats --------------------------------------------------------
402
+ *
403
+ * -o/--output values, compared lowercased. Formats that take an argument
404
+ * must carry it inline after "=": -o jsonpath={.items[*].name}. Written bare
405
+ * they take it from --template, which is Denied, so the bare form is refused
406
+ * too. The *-file formats make kubectl read a path on the Runner and echo it
407
+ * — a Read-tier `get` would print the pod's ServiceAccount token — so they
408
+ * are Denied in every spelling (-o X=..., -oX=..., --output X=...,
409
+ * --output=X=...); anything not listed is refused rather than guessed.
410
+ */
411
+ const OUTPUT_FORMATS = new Set([
412
+ "json",
413
+ "yaml",
414
+ "name",
415
+ "wide",
416
+ "plaintext",
417
+ "plaintext-openapiv2",
418
+ ]);
419
+ const OUTPUT_FORMATS_WITH_ARGUMENT = new Set([
420
+ "jsonpath",
421
+ "jsonpath-as-json",
422
+ "go-template",
423
+ "template",
424
+ "custom-columns",
425
+ ]);
426
+ const FILE_OUTPUT_FORMATS = new Set([
427
+ "go-template-file",
428
+ "templatefile",
429
+ "jsonpath-file",
430
+ "custom-columns-file",
431
+ ]);
432
+ // ---- Verbs -------------------------------------------------------------------
433
+ const READ_VERBS = new Set([
434
+ "get",
435
+ "describe",
436
+ "logs",
437
+ "top",
438
+ "events",
439
+ "api-resources",
440
+ "api-versions",
441
+ "version",
442
+ "explain",
443
+ ]);
444
+ /*
445
+ * The write verbs that CAN be SafeWrite — rollout restart/undo/pause/resume,
446
+ * delete, scale, cordon, uncordon, label and annotate — each have their own
447
+ * branch in evaluateArgs, because each has its own "exactly one named
448
+ * object" shape. These are always at least RiskyWrite:
449
+ */
450
+ const RISKY_WRITE_VERBS = new Set([
451
+ "patch",
452
+ "set",
453
+ "taint",
454
+ "drain",
455
+ "create",
456
+ "expose",
457
+ "autoscale",
458
+ ]);
459
+ /*
460
+ * Verbs whose operands are node NAMES (or TYPE/NAME), and nodes live outside
461
+ * any namespace. taint acts on nodes too, but names its kind like any object
462
+ * verb ("taint nodes NAME ..."), so the kind rule reads it.
463
+ */
464
+ const NODE_NAME_VERBS = new Set([
465
+ "cordon",
466
+ "uncordon",
467
+ "drain",
468
+ ]);
469
+ /*
470
+ * Node verbs that move pods off a node in every namespace (a drain evicts
471
+ * them; a NoExecute taint makes the node evict them, and any taint decides
472
+ * which pods it keeps), with what the approval card says about each. They
473
+ * carry `requiresHuman`: nothing an operator sets on the cluster runs them
474
+ * unattended (see the header). A patch of a Node carries it too
475
+ * (NODE_PATCH_ALWAYS_HUMAN_REASON): a taint is only the Node's spec.taints.
476
+ * describeAlwaysHumanWrite() is the one place that reads these.
477
+ */
478
+ const ALWAYS_HUMAN_VERB_REASONS = {
479
+ drain: "kubectl drain evicts every pod on the node, in every namespace (kube-system and the OneUptime agent's own included), so a human always approves it",
480
+ taint: "kubectl taint decides which pods a node keeps, in every namespace (kube-system and the OneUptime agent's own included; a NoExecute taint evicts the rest at once), so a human always approves it",
481
+ };
482
+ const NODE_PATCH_ALWAYS_HUMAN_REASON = "kubectl patch of a Node can set, replace or clear its taints, which decide which pods the node keeps, in every namespace (kube-system and the OneUptime agent's own included; a NoExecute taint evicts the rest at once), so a human always approves it, whatever the patch body says (kubectl cordon and uncordon change scheduling on one node without one)";
483
+ /*
484
+ * The write verbs evaluateArgs tiers in a branch of their own (the ones that
485
+ * can be SafeWrite). With READ_VERBS, RISKY_WRITE_VERBS and the two
486
+ * read-only command groups below, these are every verb OneUptime AI may run;
487
+ * evaluateArgs refuses any other word as an unknown verb.
488
+ */
489
+ const OWN_BRANCH_WRITE_VERBS = new Set([
490
+ "rollout",
491
+ "delete",
492
+ "scale",
493
+ "cordon",
494
+ "uncordon",
495
+ "label",
496
+ "annotate",
497
+ ]);
498
+ const READ_COMMAND_GROUPS = new Set([
499
+ "cluster-info",
500
+ "auth",
501
+ ]);
502
+ // Verbs whose subcommand must be written out for the command to run at all.
503
+ const SUBCOMMAND_REQUIRED_VERBS = new Set([
504
+ "rollout",
505
+ "set",
506
+ "create",
507
+ ]);
508
+ function isVerbOneUptimeAiMayRun(verb) {
509
+ return (READ_VERBS.has(verb) ||
510
+ RISKY_WRITE_VERBS.has(verb) ||
511
+ OWN_BRANCH_WRITE_VERBS.has(verb) ||
512
+ READ_COMMAND_GROUPS.has(verb));
513
+ }
514
+ /*
515
+ * Verbs with nothing to offer an SRE agent, or that open an interactive or
516
+ * long-lived channel, or that could rewrite objects from input we do not
517
+ * support. Listed explicitly so the reason names the verb; any verb not in
518
+ * any list is Denied too — kubectl runs a `kubectl-<verb>` plugin from the
519
+ * Runner's PATH for a word it does not know (and a kuberc alias for one it
520
+ * has been taught), so an unknown verb is never a guess we can afford.
521
+ */
522
+ const DENIED_VERBS = new Set([
523
+ "kuberc",
524
+ "exec",
525
+ "attach",
526
+ "cp",
527
+ "port-forward",
528
+ "proxy",
529
+ "debug",
530
+ "run",
531
+ "edit",
532
+ "replace",
533
+ "apply",
534
+ "diff",
535
+ "kustomize",
536
+ "config",
537
+ "certificate",
538
+ "wait",
539
+ "plugin",
540
+ "completion",
541
+ "options",
542
+ "help",
543
+ "alpha",
544
+ "convert",
545
+ ]);
546
+ /*
547
+ * Kinds whose deletion is either unrecoverable or cluster-wide. Deleting
548
+ * them is Denied even with a human in the loop — this lane is for fixing a
549
+ * workload, not for tearing down a cluster. Matched on normalizeKind(), so
550
+ * every spelling kubectl accepts is covered: plural, singular, short name,
551
+ * Kind case and group-qualified (`crd`, `CustomResourceDefinition`,
552
+ * `customresourcedefinitions.apiextensions.k8s.io`, `ns/prod`, ...).
553
+ * Resource CATEGORIES (all, api-extensions) are refused separately, in every
554
+ * write verb (see RESOURCE_CATEGORIES).
555
+ */
556
+ const NEVER_DELETE_KINDS = new Set([
557
+ "namespace",
558
+ "node",
559
+ "persistentvolume",
560
+ "persistentvolumeclaim",
561
+ "customresourcedefinition",
562
+ "clusterrole",
563
+ "clusterrolebinding",
564
+ "role",
565
+ "rolebinding",
566
+ "storageclass",
567
+ "secret",
568
+ "priorityclass",
569
+ "apiservice",
570
+ "mutatingwebhookconfiguration",
571
+ "validatingwebhookconfiguration",
572
+ "validatingadmissionpolicy",
573
+ "validatingadmissionpolicybinding",
574
+ "mutatingadmissionpolicy",
575
+ "mutatingadmissionpolicybinding",
576
+ "certificatesigningrequest",
577
+ ]);
578
+ /*
579
+ * Resource categories. kubectl expands a category into every kind that
580
+ * declares it (ReplaceAliases, through discovery) BEFORE it resolves types,
581
+ * so `kubectl delete api-extensions -l x` deletes CRDs, APIServices and
582
+ * admission webhooks although none of those kinds appears in the command.
583
+ * A category is therefore never allowed in a write, whatever the verb.
584
+ * `all` and `api-extensions` are the categories the API server itself
585
+ * defines (the only ones that can reach built-in kinds); the rest are the
586
+ * categories widely used operators give their custom resources — a custom
587
+ * category can only reach custom resources, which are RiskyWrite anyway, so
588
+ * this list is a clearer refusal, not the only line. Reads (`get all`)
589
+ * stay Read.
590
+ */
591
+ const RESOURCE_CATEGORIES = new Set([
592
+ "all",
593
+ "api-extensions",
594
+ "crossplane",
595
+ "managed",
596
+ "composite",
597
+ "claim",
598
+ "knative",
599
+ "serving",
600
+ "eventing",
601
+ "istio-io",
602
+ "networking-istio-io",
603
+ "security-istio-io",
604
+ "telemetry-istio-io",
605
+ "extensions-istio-io",
606
+ "gateway-api",
607
+ "cert-manager",
608
+ "kyverno",
609
+ "cluster-api",
610
+ "tekton",
611
+ "tekton-pipelines",
612
+ ]);
613
+ /*
614
+ * Kinds that decide who may do what. OneUptime AI never creates or changes
615
+ * them in any write verb — label and annotate included (a label on a
616
+ * ClusterRole can aggregate its rules into admin/edit/view) — because a new
617
+ * or widened binding is a privilege grant, not a fix; nor does it delete
618
+ * them (NEVER_DELETE_KINDS). Reading them stays Read: an investigation needs
619
+ * to see why something is Forbidden.
620
+ */
621
+ const RBAC_KINDS = new Set([
622
+ "role",
623
+ "clusterrole",
624
+ "rolebinding",
625
+ "clusterrolebinding",
626
+ ]);
627
+ /*
628
+ * Kinds that decide, for the whole cluster, what the API server admits and
629
+ * serves: admission webhooks and admission policies (and their bindings)
630
+ * accept, reject or rewrite every object written; an APIService routes a
631
+ * whole API group to a Service; a CRD defines (and converts) a whole kind.
632
+ * Emptying a webhook's rules, setting a policy binding to Audit or
633
+ * repointing an APIService switches a cluster control off as surely as
634
+ * deleting it (which NEVER_DELETE_KINDS already refuses) — the same reason
635
+ * Pod Security Admission labels are Denied. So every write verb on these is
636
+ * Denied; reading them stays Read.
637
+ */
638
+ const ADMISSION_AND_API_EXTENSION_KINDS = new Set([
639
+ "mutatingwebhookconfiguration",
640
+ "validatingwebhookconfiguration",
641
+ "validatingadmissionpolicy",
642
+ "validatingadmissionpolicybinding",
643
+ "mutatingadmissionpolicy",
644
+ "mutatingadmissionpolicybinding",
645
+ "apiservice",
646
+ "customresourcedefinition",
647
+ ]);
648
+ /*
649
+ * Kinds whose objects ARE credentials. OneUptime AI never reads, changes or
650
+ * deletes them, in any spelling kubectl accepts (secret, secrets, Secret,
651
+ * secrets.v1., secret/name, pods,secrets, ...): get/describe would print
652
+ * their values to the model, and label/annotate/patch with -o yaml print the
653
+ * whole object too, so the rule is per kind, not per verb. `all` does not
654
+ * include secrets, so `get all` stays Read. Pods and ConfigMaps can carry
655
+ * plaintext env values as well; those cannot be denied without blinding the
656
+ * investigation, so output redaction covers them, not this policy.
657
+ */
658
+ const CREDENTIAL_KINDS = new Set(["secret"]);
659
+ /*
660
+ * Verbs whose positionals name objects as "kind name..." or "kind/name...",
661
+ * where CREDENTIAL_KINDS is enforced. For rollout and set the objects follow
662
+ * the subcommand. Node verbs (cordon, drain) name nodes, logs names pods and
663
+ * the remaining verbs take no objects, so the kind cannot appear there.
664
+ */
665
+ const OBJECT_VERBS = new Set([
666
+ "get",
667
+ "describe",
668
+ "delete",
669
+ "label",
670
+ "annotate",
671
+ "patch",
672
+ "scale",
673
+ "autoscale",
674
+ "expose",
675
+ "taint",
676
+ "rollout",
677
+ "set",
678
+ ]);
679
+ /*
680
+ * Kinds whose deletion is a safe change: exactly one, and only the pod. A
681
+ * pod with a controller (ReplicaSet, StatefulSet, DaemonSet, Job) is
682
+ * recreated by it. A Job is NOT recreated by anything — a standalone Job (a
683
+ * migration, a one-off batch run) is simply gone, and a CronJob only starts
684
+ * a new one on its next schedule — so deleting a Job is RiskyWrite.
685
+ * Matched on builtinKind(), so a custom resource that happens to be called
686
+ * `pods.example.com` is not a pod.
687
+ */
688
+ const SAFE_DELETE_KINDS = new Set(["pod"]);
689
+ // The workloads `kubectl rollout restart/undo/pause/resume` acts on.
690
+ const ROLLOUT_SAFE_KINDS = new Set([
691
+ "deployment",
692
+ "statefulset",
693
+ "daemonset",
694
+ ]);
695
+ /*
696
+ * The workloads a safe `kubectl scale` may target — the ones whose scale
697
+ * subresource the kubernetes-agent chart's remediation RBAC grants.
698
+ */
699
+ const SCALE_SAFE_KINDS = new Set([
700
+ "deployment",
701
+ "statefulset",
702
+ "replicaset",
703
+ ]);
704
+ /*
705
+ * The kinds a safe label/annotate may target: a pod or a workload. A label
706
+ * on these is metadata a fix may need (quarantine a pod by dropping its
707
+ * `app` label, note a restart). On any other kind a label is a control:
708
+ * Pod Security Admission reads namespace labels, DaemonSet nodeSelectors and
709
+ * cloud load balancers read node labels, Services and NetworkPolicies select
710
+ * by label, ClusterRole aggregation reads role labels, and ServiceAccount /
711
+ * Ingress annotations bind cloud identities and inject proxy config.
712
+ */
713
+ const LABEL_SAFE_KINDS = new Set([
714
+ "pod",
715
+ "deployment",
716
+ "statefulset",
717
+ "daemonset",
718
+ "replicaset",
719
+ "job",
720
+ "cronjob",
721
+ ]);
722
+ /*
723
+ * Built-in kinds that live outside any namespace, and the API group each
724
+ * lives in. A write that names only these is not "in" the namespace its -n
725
+ * flag names (kubectl ignores -n for them), so the protected-namespace rule
726
+ * looks at the object instead. Matched on builtinKind(), never on
727
+ * normalizeKind(): `nodes.example.com` or `namespaces.example.com` is some
728
+ * custom resource that happens to borrow the name. Its scope is unknown
729
+ * here, so it is judged by the namespace -n names like any namespaced
730
+ * object — the reading that can only add a human, never remove one.
731
+ */
732
+ const CLUSTER_SCOPED_KIND_GROUPS = {
733
+ node: "",
734
+ namespace: "",
735
+ persistentvolume: "",
736
+ customresourcedefinition: "apiextensions.k8s.io",
737
+ clusterrole: "rbac.authorization.k8s.io",
738
+ clusterrolebinding: "rbac.authorization.k8s.io",
739
+ storageclass: "storage.k8s.io",
740
+ priorityclass: "scheduling.k8s.io",
741
+ apiservice: "apiregistration.k8s.io",
742
+ mutatingwebhookconfiguration: "admissionregistration.k8s.io",
743
+ validatingwebhookconfiguration: "admissionregistration.k8s.io",
744
+ validatingadmissionpolicy: "admissionregistration.k8s.io",
745
+ validatingadmissionpolicybinding: "admissionregistration.k8s.io",
746
+ mutatingadmissionpolicy: "admissionregistration.k8s.io",
747
+ mutatingadmissionpolicybinding: "admissionregistration.k8s.io",
748
+ certificatesigningrequest: "certificates.k8s.io",
749
+ ingressclass: "networking.k8s.io",
750
+ runtimeclass: "node.k8s.io",
751
+ csidriver: "storage.k8s.io",
752
+ csinode: "storage.k8s.io",
753
+ volumeattachment: "storage.k8s.io",
754
+ flowschema: "flowcontrol.apiserver.k8s.io",
755
+ prioritylevelconfiguration: "flowcontrol.apiserver.k8s.io",
756
+ };
757
+ const CLUSTER_SCOPED_KINDS = new Set(Object.keys(CLUSTER_SCOPED_KIND_GROUPS));
758
+ /*
759
+ * The API group of every built-in kind a SAFE or SCOPE decision names: the
760
+ * kinds in the *_SAFE_KINDS sets and the cluster-scoped kinds above.
761
+ * builtinKind() accepts a group-qualified spelling only in this group, so
762
+ * `deployments.apps/web` is a Deployment and `storageclasses.storage.k8s.io`
763
+ * a StorageClass, while `jobs.batch.volcano.sh`, `pods.example.com` or
764
+ * `nodes.example.com` is some custom resource: never a safe target, and
765
+ * never exempt from the namespace -n names.
766
+ */
767
+ const BUILTIN_KIND_GROUPS = Object.assign({ pod: "", deployment: "apps", statefulset: "apps", daemonset: "apps", replicaset: "apps", job: "batch", cronjob: "batch" }, CLUSTER_SCOPED_KIND_GROUPS);
768
+ /*
769
+ * Label / annotation key prefixes (the DNS part before "/") that belong to
770
+ * Kubernetes itself — kubernetes.io and k8s.io and every subdomain
771
+ * (pod-security.kubernetes.io, node-role.kubernetes.io,
772
+ * rbac.authorization.k8s.io, kubectl.kubernetes.io, ...) — or to the
773
+ * identity, admission and GitOps controllers that act on them. Writing one
774
+ * of these steers a controller rather than annotating an object, so it is
775
+ * RiskyWrite on any kind. Matched as the domain itself or a subdomain.
776
+ */
777
+ const RESERVED_KEY_DOMAINS = [
778
+ "kubernetes.io",
779
+ "k8s.io",
780
+ "gatekeeper.sh",
781
+ "kyverno.io",
782
+ "argoproj.io",
783
+ "eks.amazonaws.com",
784
+ "iam.gke.io",
785
+ "azure.workload.identity",
786
+ ];
787
+ /*
788
+ * Pod Security Admission's namespace labels. Lowering or removing them lets
789
+ * privileged pods into the namespace, which is never a fix OneUptime AI
790
+ * makes (Denied, in label, annotate and patch alike).
791
+ */
792
+ const POD_SECURITY_KEY_DOMAIN = "pod-security.kubernetes.io";
793
+ /*
794
+ * The AppArmor profile as an annotation on a pod (or a pod template):
795
+ * `container.apparmor.security.beta.kubernetes.io/<container>: unconfined`.
796
+ * It is the deprecated spelling of securityContext.appArmorProfile (the API
797
+ * server copies it into that field when it creates a pod, for as long as it
798
+ * supports the annotation) and a Pod Security Standards baseline control of
799
+ * its own, so a patch body may not name one, like a POD_SECURITY_PATCH_KEYS
800
+ * field. Matched as this domain or a subdomain of it.
801
+ */
802
+ const APPARMOR_ANNOTATION_KEY_DOMAIN = "apparmor.security.beta.kubernetes.io";
803
+ /*
804
+ * ClusterRole aggregation: a ClusterRole labelled with one of these has its
805
+ * rules merged into admin / edit / view (and so granted to everyone bound
806
+ * to them). That is an RBAC grant, Denied like creating a binding.
807
+ */
808
+ const RBAC_AGGREGATION_KEY_PREFIX = "rbac.authorization.k8s.io/aggregate-to-";
809
+ /*
810
+ * Field names a `kubectl patch` body may never touch, matched by key name
811
+ * (case-insensitively) anywhere in the body — strategic-merge and merge
812
+ * patches as keys, JSON patches as path segments. Bodies are JSON only (a
813
+ * body JSON.parse rejects is Denied outright; see findPatchBodyProblem), so
814
+ * the walker sees exactly the keys kubectl applies. Each one
815
+ * changes which identity, privileges, host access, Secrets or program a pod
816
+ * runs with. With write RBAC on a workload that is the same as running any
817
+ * image as any ServiceAccount in the namespace and reading every Secret it
818
+ * can mount, which no approval card should be asked to wave through. Image,
819
+ * env values, resources and replicas stay patchable (set image / set env /
820
+ * set resources say the same thing more plainly). A patch that replaces or
821
+ * removes an object ABOVE these fields drops them without naming any; that
822
+ * is refused by findPodSpecReplacement (see POD_SPEC_PATH_STEPS).
823
+ *
824
+ * The host and isolation fields cover every control of the Pod Security
825
+ * Standards baseline profile (and the restricted profile adds nothing
826
+ * outside securityContext and volumes): the host namespaces (hostNetwork,
827
+ * hostPID, hostIPC), hostPath volumes, a container port's hostPort (it binds
828
+ * the node's own IP), and — under securityContext — privileged,
829
+ * capabilities, hostProcess, SELinux, AppArmor, seccomp, procMount and
830
+ * sysctls; plus what weakens a pod's isolation outside those: hostUsers
831
+ * (true, the default, takes away the user namespace false gives the pod),
832
+ * runtimeClassName (it can move the pod off a sandboxed runtime) and
833
+ * shareProcessNamespace. Two baseline controls are refused beside this list,
834
+ * because a name alone does not say what they are: the AppArmor annotation
835
+ * (APPARMOR_ANNOTATION_KEY_DOMAIN) and the host of a probe or lifecycle hook
836
+ * (HOST_FIELD_HANDLER_KEYS; `host` elsewhere is no pod field).
837
+ */
838
+ const POD_SECURITY_PATCH_KEYS = new Set([
839
+ "serviceAccountName",
840
+ "serviceAccount",
841
+ "automountServiceAccountToken",
842
+ "securityContext",
843
+ "privileged",
844
+ "capabilities",
845
+ "hostPath",
846
+ "hostNetwork",
847
+ "hostPID",
848
+ "hostIPC",
849
+ "hostPort",
850
+ "hostUsers",
851
+ "runtimeClassName",
852
+ "shareProcessNamespace",
853
+ "volumes",
854
+ "volumeMounts",
855
+ "initContainers",
856
+ "ephemeralContainers",
857
+ "command",
858
+ "args",
859
+ "envFrom",
860
+ "secretKeyRef",
861
+ "secretRef",
862
+ "secretName",
863
+ ].map((key) => {
864
+ return key.toLowerCase();
865
+ }));
866
+ /*
867
+ * kubectl create's subcommands and their aliases, exactly as cobra matches
868
+ * them (case-sensitively). Anything else is not a create subcommand:
869
+ * kubectl would look for a `kubectl-create-<name>` plugin on the Runner's
870
+ * PATH, so it is Denied rather than tiered.
871
+ */
872
+ const CREATE_SUBCOMMANDS = {
873
+ namespace: "namespace",
874
+ ns: "namespace",
875
+ quota: "resourcequota",
876
+ resourcequota: "resourcequota",
877
+ secret: "secret",
878
+ configmap: "configmap",
879
+ cm: "configmap",
880
+ serviceaccount: "serviceaccount",
881
+ sa: "serviceaccount",
882
+ service: "service",
883
+ svc: "service",
884
+ deployment: "deployment",
885
+ deploy: "deployment",
886
+ clusterrole: "clusterrole",
887
+ clusterrolebinding: "clusterrolebinding",
888
+ role: "role",
889
+ rolebinding: "rolebinding",
890
+ poddisruptionbudget: "poddisruptionbudget",
891
+ pdb: "poddisruptionbudget",
892
+ priorityclass: "priorityclass",
893
+ pc: "priorityclass",
894
+ job: "job",
895
+ cronjob: "cronjob",
896
+ cj: "cronjob",
897
+ ingress: "ingress",
898
+ ing: "ingress",
899
+ token: "token",
900
+ };
901
+ /*
902
+ * What `kubectl create <subcommand>` makes that OneUptime AI never makes:
903
+ * RBAC objects and ServiceAccounts decide who may do what, and a new
904
+ * ServiceAccount is an identity for someone to bind.
905
+ */
906
+ const DENIED_CREATE_KINDS = new Set([
907
+ "clusterrole",
908
+ "clusterrolebinding",
909
+ "role",
910
+ "rolebinding",
911
+ "serviceaccount",
912
+ ]);
913
+ /*
914
+ * `kubectl create` subcommands that start a NEW workload running the image
915
+ * named in the command: kubectl requires --image for both (it refuses them
916
+ * without one), so every such command runs an arbitrary image as a new
917
+ * program in the cluster — Denied, like `create job --image`.
918
+ */
919
+ const IMAGE_WORKLOAD_CREATE_KINDS = new Set([
920
+ "deployment",
921
+ "cronjob",
922
+ ]);
923
+ // Cluster-scoped objects `kubectl create` can make (for the namespace rule).
924
+ const CLUSTER_SCOPED_CREATE_KINDS = new Set([
925
+ "namespace",
926
+ "priorityclass",
927
+ ]);
928
+ /*
929
+ * kubectl set's subcommands OneUptime AI may use (set serviceaccount and set
930
+ * subject are Denied by name; anything else is not a set subcommand).
931
+ */
932
+ const SET_SUBCOMMANDS = new Set([
933
+ "env",
934
+ "image",
935
+ "resources",
936
+ "selector",
937
+ ]);
938
+ const KIND_ALIASES = {
939
+ po: "pod",
940
+ pods: "pod",
941
+ pod: "pod",
942
+ jobs: "job",
943
+ job: "job",
944
+ cj: "cronjob",
945
+ cronjobs: "cronjob",
946
+ cronjob: "cronjob",
947
+ deploy: "deployment",
948
+ deployments: "deployment",
949
+ deployment: "deployment",
950
+ sts: "statefulset",
951
+ statefulsets: "statefulset",
952
+ statefulset: "statefulset",
953
+ ds: "daemonset",
954
+ daemonsets: "daemonset",
955
+ daemonset: "daemonset",
956
+ rs: "replicaset",
957
+ replicasets: "replicaset",
958
+ replicaset: "replicaset",
959
+ rc: "replicationcontroller",
960
+ replicationcontrollers: "replicationcontroller",
961
+ replicationcontroller: "replicationcontroller",
962
+ hpa: "horizontalpodautoscaler",
963
+ horizontalpodautoscalers: "horizontalpodautoscaler",
964
+ horizontalpodautoscaler: "horizontalpodautoscaler",
965
+ svc: "service",
966
+ services: "service",
967
+ service: "service",
968
+ ep: "endpoints",
969
+ endpoints: "endpoints",
970
+ cm: "configmap",
971
+ configmaps: "configmap",
972
+ configmap: "configmap",
973
+ sa: "serviceaccount",
974
+ serviceaccounts: "serviceaccount",
975
+ serviceaccount: "serviceaccount",
976
+ ing: "ingress",
977
+ ingresses: "ingress",
978
+ ingress: "ingress",
979
+ ingressclasses: "ingressclass",
980
+ ingressclass: "ingressclass",
981
+ netpol: "networkpolicy",
982
+ networkpolicies: "networkpolicy",
983
+ networkpolicy: "networkpolicy",
984
+ pdb: "poddisruptionbudget",
985
+ poddisruptionbudgets: "poddisruptionbudget",
986
+ poddisruptionbudget: "poddisruptionbudget",
987
+ quota: "resourcequota",
988
+ resourcequotas: "resourcequota",
989
+ resourcequota: "resourcequota",
990
+ limits: "limitrange",
991
+ limitranges: "limitrange",
992
+ limitrange: "limitrange",
993
+ ns: "namespace",
994
+ namespaces: "namespace",
995
+ namespace: "namespace",
996
+ no: "node",
997
+ nodes: "node",
998
+ node: "node",
999
+ pv: "persistentvolume",
1000
+ persistentvolumes: "persistentvolume",
1001
+ persistentvolume: "persistentvolume",
1002
+ pvc: "persistentvolumeclaim",
1003
+ persistentvolumeclaims: "persistentvolumeclaim",
1004
+ persistentvolumeclaim: "persistentvolumeclaim",
1005
+ crd: "customresourcedefinition",
1006
+ crds: "customresourcedefinition",
1007
+ customresourcedefinitions: "customresourcedefinition",
1008
+ customresourcedefinition: "customresourcedefinition",
1009
+ roles: "role",
1010
+ role: "role",
1011
+ rolebindings: "rolebinding",
1012
+ rolebinding: "rolebinding",
1013
+ clusterroles: "clusterrole",
1014
+ clusterrole: "clusterrole",
1015
+ clusterrolebindings: "clusterrolebinding",
1016
+ clusterrolebinding: "clusterrolebinding",
1017
+ sc: "storageclass",
1018
+ storageclasses: "storageclass",
1019
+ storageclass: "storageclass",
1020
+ secrets: "secret",
1021
+ secret: "secret",
1022
+ pc: "priorityclass",
1023
+ priorityclasses: "priorityclass",
1024
+ priorityclass: "priorityclass",
1025
+ apiservices: "apiservice",
1026
+ apiservice: "apiservice",
1027
+ mutatingwebhookconfigurations: "mutatingwebhookconfiguration",
1028
+ mutatingwebhookconfiguration: "mutatingwebhookconfiguration",
1029
+ validatingwebhookconfigurations: "validatingwebhookconfiguration",
1030
+ validatingwebhookconfiguration: "validatingwebhookconfiguration",
1031
+ validatingadmissionpolicies: "validatingadmissionpolicy",
1032
+ validatingadmissionpolicy: "validatingadmissionpolicy",
1033
+ validatingadmissionpolicybindings: "validatingadmissionpolicybinding",
1034
+ validatingadmissionpolicybinding: "validatingadmissionpolicybinding",
1035
+ mutatingadmissionpolicies: "mutatingadmissionpolicy",
1036
+ mutatingadmissionpolicy: "mutatingadmissionpolicy",
1037
+ mutatingadmissionpolicybindings: "mutatingadmissionpolicybinding",
1038
+ mutatingadmissionpolicybinding: "mutatingadmissionpolicybinding",
1039
+ csr: "certificatesigningrequest",
1040
+ certificatesigningrequests: "certificatesigningrequest",
1041
+ certificatesigningrequest: "certificatesigningrequest",
1042
+ runtimeclasses: "runtimeclass",
1043
+ runtimeclass: "runtimeclass",
1044
+ csidrivers: "csidriver",
1045
+ csidriver: "csidriver",
1046
+ csinodes: "csinode",
1047
+ csinode: "csinode",
1048
+ volumeattachments: "volumeattachment",
1049
+ volumeattachment: "volumeattachment",
1050
+ flowschemas: "flowschema",
1051
+ flowschema: "flowschema",
1052
+ prioritylevelconfigurations: "prioritylevelconfiguration",
1053
+ prioritylevelconfiguration: "prioritylevelconfiguration",
1054
+ };
1055
+ /*
1056
+ * The kind a token names, for the DENY lists: lowercased, the head of a
1057
+ * group-qualified form ("pods.v1." / "deployments.apps" / "secrets.foo.io"
1058
+ * all keep the leading segment) mapped through KIND_ALIASES. Folding every
1059
+ * group into the built-in kind is the safe side for a deny list — a custom
1060
+ * `secrets.example.io` is refused like a Secret — and for a rule that can
1061
+ * only ADD a human (a Namespace object named kube-system). It must never be
1062
+ * used to decide that something is SAFE, or that a write is cluster-scoped
1063
+ * and so outside the namespace -n names (see builtinKind()).
1064
+ */
1065
+ function normalizeKind(token) {
1066
+ const lower = token.toLowerCase();
1067
+ const head = lower.split(".")[0] || lower;
1068
+ return Object.prototype.hasOwnProperty.call(KIND_ALIASES, head)
1069
+ ? KIND_ALIASES[head]
1070
+ : head;
1071
+ }
1072
+ /*
1073
+ * The built-in kind a token names, for the SAFE sets and the cluster-scoped
1074
+ * rule — or undefined when it is not one of BUILTIN_KIND_GROUPS in that
1075
+ * kind's own API group. kubectl (schema.ParseResourceArg) reads a token with
1076
+ * two dots or more first as "RESOURCE.VERSION.GROUP" and then as
1077
+ * "RESOURCE.GROUP", and one with a single dot only as "RESOURCE.GROUP"
1078
+ * ("pods." and "pods.v1." name the core group). So `deployments.apps`,
1079
+ * `deployments.v1.apps`, `pods.v1.`, `storageclasses.storage.k8s.io` and
1080
+ * `clusterroles.v1.rbac.authorization.k8s.io` are the built-in kinds, and
1081
+ * `pods.example.com`, `nodes.v1.example.com` or `jobs.batch.volcano.sh` are
1082
+ * custom resources.
1083
+ */
1084
+ function builtinKind(token) {
1085
+ const lower = token.toLowerCase();
1086
+ const parts = lower.split(".");
1087
+ const head = parts[0] || "";
1088
+ if (!Object.prototype.hasOwnProperty.call(KIND_ALIASES, head)) {
1089
+ return undefined;
1090
+ }
1091
+ const kind = KIND_ALIASES[head];
1092
+ if (!Object.prototype.hasOwnProperty.call(BUILTIN_KIND_GROUPS, kind)) {
1093
+ return undefined;
1094
+ }
1095
+ if (parts.length === 1) {
1096
+ return kind;
1097
+ }
1098
+ const group = BUILTIN_KIND_GROUPS[kind];
1099
+ // RESOURCE.GROUP
1100
+ if (parts.slice(1).join(".") === group) {
1101
+ return kind;
1102
+ }
1103
+ // RESOURCE.VERSION.GROUP
1104
+ if (parts.length >= 3 && parts.slice(2).join(".") === group) {
1105
+ return kind;
1106
+ }
1107
+ return undefined;
1108
+ }
1109
+ /*
1110
+ * True when every object a node verb names is a node: a bare NAME, or a
1111
+ * TYPE/NAME whose type is the built-in Node (kubectl's cordon, uncordon and
1112
+ * drain read "nodes/NAME" and also accept any other TYPE/NAME, such as a
1113
+ * custom `nodes.example.com/x`, which then is not a node at all).
1114
+ */
1115
+ function namesOnlyNodes(nodeTokens) {
1116
+ return nodeTokens.every((token) => {
1117
+ const slash = token.indexOf("/");
1118
+ return slash < 0 || builtinKind(token.slice(0, slash)) === "node";
1119
+ });
1120
+ }
1121
+ /*
1122
+ * The kinds named by the positionals after a verb, read the way kubectl's
1123
+ * resource builder reads them: either "kind name1 name2" (the first token
1124
+ * is the kind, possibly "pod,job"; the rest are names) or "kind/name
1125
+ * kind2/name2" (every token carries its own kind). Mixing the two is an
1126
+ * error in kubectl; here it just names both kinds, which is the safe side.
1127
+ */
1128
+ function namedKinds(resourceTokens) {
1129
+ const kinds = new Set();
1130
+ const rawKinds = [];
1131
+ const names = [];
1132
+ let namedCount = 0;
1133
+ for (let i = 0; i < resourceTokens.length; i++) {
1134
+ const token = resourceTokens[i];
1135
+ if (token.includes("/")) {
1136
+ const slash = token.indexOf("/");
1137
+ const rawKind = token.slice(0, slash);
1138
+ rawKinds.push(rawKind);
1139
+ kinds.add(normalizeKind(rawKind));
1140
+ names.push(token.slice(slash + 1));
1141
+ namedCount++;
1142
+ }
1143
+ else if (i === 0) {
1144
+ for (const part of token.split(",")) {
1145
+ rawKinds.push(part);
1146
+ kinds.add(normalizeKind(part));
1147
+ }
1148
+ }
1149
+ else {
1150
+ names.push(token);
1151
+ namedCount++;
1152
+ }
1153
+ }
1154
+ return { kinds, rawKinds, namedCount, names };
1155
+ }
1156
+ /*
1157
+ * True when the objects are exactly ONE named object of ONE kind — the
1158
+ * shape every SafeWrite needs. A bare kind is every object of that kind to
1159
+ * kubectl's rollout verbs, and a comma list of kinds or several names is
1160
+ * several objects.
1161
+ */
1162
+ function isOneNamedObject(targets) {
1163
+ return targets.namedCount === 1 && targets.rawKinds.length === 1;
1164
+ }
1165
+ // True when every kind is built in and in `allowed` (see builtinKind()).
1166
+ function everyBuiltinKindIn(targets, allowed) {
1167
+ return (targets.rawKinds.length > 0 &&
1168
+ targets.rawKinds.every((rawKind) => {
1169
+ const kind = builtinKind(rawKind);
1170
+ return kind !== undefined && allowed.has(kind);
1171
+ }));
1172
+ }
1173
+ /*
1174
+ * The commands that read the words after their objects as updates, KEY=VALUE
1175
+ * or KEY- (kubectl's GetResourcesAndPairs for label, annotate and set image,
1176
+ * SplitEnvironmentFromResources for set env, and taint's own split): for
1177
+ * these, and only these, the objects end at the first such word. (taint also
1178
+ * ends them at a KEY:EFFECT word; reading that as one more object only adds
1179
+ * an object.) Every other verb hands kubectl's resource builder ALL of its
1180
+ * words, `=` or not, and kubectl goes on to the next object when one fails:
1181
+ * checked with the pinned kubectl v1.36.4 against a fake API server, `get
1182
+ * pod/a=b secret/s` prints the Secret and `patch pod/a=b node/n1` patches
1183
+ * the Node, each after the missing pod's error.
1184
+ */
1185
+ function readsObjectsThenPairs(verb, subcommand) {
1186
+ if (verb === "label" || verb === "annotate" || verb === "taint") {
1187
+ return true;
1188
+ }
1189
+ return verb === "set" && (subcommand === "image" || subcommand === "env");
1190
+ }
1191
+ /*
1192
+ * The object tokens of a command, split the way kubectl splits positionals:
1193
+ * the words after the verb (and the subcommand, for rollout and set) — for
1194
+ * the commands that take updates (readsObjectsThenPairs), only the leading
1195
+ * words that are not KEY=VALUE or KEY- pairs. So `label pod web-1 app=web`
1196
+ * names only the pod, and `label pod web-1 secret/rotated=true` names no
1197
+ * Secret, while `get pod/a=b secret/s` names the Secret. For set selector
1198
+ * the last word is the selector expression, not an object; it is kept here,
1199
+ * which can only add an object to what the deny lists read.
1200
+ */
1201
+ function objectTokens(verb, positionals) {
1202
+ const start = verb === "rollout" || verb === "set" ? 2 : 1;
1203
+ const words = positionals.slice(start);
1204
+ if (!readsObjectsThenPairs(verb, (positionals[1] || "").toLowerCase())) {
1205
+ return words;
1206
+ }
1207
+ const tokens = [];
1208
+ for (const token of words) {
1209
+ if (token.includes("=") || token.endsWith("-")) {
1210
+ break;
1211
+ }
1212
+ tokens.push(token);
1213
+ }
1214
+ return tokens;
1215
+ }
1216
+ /*
1217
+ * The objects a write names: after the verb for delete, after the verb's
1218
+ * object tokens for the other object verbs (after the subcommand for
1219
+ * rollout and set), and none for node verbs and create. evaluateArgs and
1220
+ * the allowlist's reading of an entry (allowlistMayPromote) both use this,
1221
+ * so the two can never disagree about what a command acts on.
1222
+ */
1223
+ function commandTargets(verb, positionals) {
1224
+ if (verb === "delete") {
1225
+ return namedKinds(positionals.slice(1));
1226
+ }
1227
+ return OBJECT_VERBS.has(verb)
1228
+ ? namedKinds(objectTokens(verb, positionals))
1229
+ : namedKinds([]);
1230
+ }
1231
+ /*
1232
+ * True when one of the objects is the built-in Node, in any spelling kubectl
1233
+ * resolves to it (builtinKind(): node, nodes, no, Node, nodes.v1., no/NAME).
1234
+ * A custom resource that borrows the name (`nodes.example.com`) is not.
1235
+ */
1236
+ function namesBuiltinNode(targets) {
1237
+ return targets.rawKinds.some((rawKind) => {
1238
+ return builtinKind(rawKind) === "node";
1239
+ });
1240
+ }
1241
+ /*
1242
+ * Why nothing an operator sets on the cluster runs this write unattended —
1243
+ * a drain, a taint, or a patch of a Node (see the header) — or undefined.
1244
+ * A write that gets a reason here carries `requiresHuman`, and an allowlist
1245
+ * entry that names one pre-approves nothing.
1246
+ */
1247
+ function describeAlwaysHumanWrite(verb, targets) {
1248
+ if (Object.prototype.hasOwnProperty.call(ALWAYS_HUMAN_VERB_REASONS, verb)) {
1249
+ return ALWAYS_HUMAN_VERB_REASONS[verb];
1250
+ }
1251
+ if (verb === "patch" && namesBuiltinNode(targets)) {
1252
+ return NODE_PATCH_ALWAYS_HUMAN_REASON;
1253
+ }
1254
+ return undefined;
1255
+ }
1256
+ /*
1257
+ * The label / annotation KEYS a label or annotate command writes or removes:
1258
+ * the pair tokens after the objects, "KEY=VALUE" (the key is before the
1259
+ * first "=") or "KEY-" (removal). Values are never inspected, so a reserved
1260
+ * string in a value is just text.
1261
+ */
1262
+ function labelKeys(verb, positionals) {
1263
+ const start = 1 + objectTokens(verb, positionals).length;
1264
+ const keys = [];
1265
+ for (const token of positionals.slice(start)) {
1266
+ const eq = token.indexOf("=");
1267
+ if (eq >= 0) {
1268
+ keys.push(token.slice(0, eq));
1269
+ }
1270
+ else if (token.endsWith("-")) {
1271
+ keys.push(token.slice(0, -1));
1272
+ }
1273
+ }
1274
+ return keys;
1275
+ }
1276
+ // The DNS prefix of a label key ("pod-security.kubernetes.io/enforce"), lowercased.
1277
+ function keyDomain(key) {
1278
+ const slash = key.indexOf("/");
1279
+ return slash >= 0 ? key.slice(0, slash).toLowerCase() : "";
1280
+ }
1281
+ function isDomainOrSubdomain(domain, of) {
1282
+ return domain === of || domain.endsWith(`.${of}`);
1283
+ }
1284
+ function isReservedKey(key) {
1285
+ const domain = keyDomain(key);
1286
+ return (domain.length > 0 &&
1287
+ RESERVED_KEY_DOMAINS.some((reserved) => {
1288
+ return isDomainOrSubdomain(domain, reserved);
1289
+ }));
1290
+ }
1291
+ function isPodSecurityKey(key) {
1292
+ return isDomainOrSubdomain(keyDomain(key), POD_SECURITY_KEY_DOMAIN);
1293
+ }
1294
+ function isAppArmorAnnotationKey(key) {
1295
+ return isDomainOrSubdomain(keyDomain(key), APPARMOR_ANNOTATION_KEY_DOMAIN);
1296
+ }
1297
+ function isRbacAggregationKey(key) {
1298
+ return key.toLowerCase().startsWith(RBAC_AGGREGATION_KEY_PREFIX);
1299
+ }
1300
+ const MAX_PATCH_BODY_DEPTH = 64;
1301
+ /*
1302
+ * findForbiddenJsonField's answer for a body nested past
1303
+ * MAX_PATCH_BODY_DEPTH. It can never equal a field it reports, which are
1304
+ * POD_SECURITY_PATCH_KEYS, Pod Security Admission label keys, AppArmor
1305
+ * annotation keys and a probe's or hook's host (httpGet.host).
1306
+ */
1307
+ const PATCH_BODY_TOO_DEEP = "\0too-deep";
1308
+ /*
1309
+ * Why a `kubectl patch` body may not run, or null. The body must be JSON,
1310
+ * and the JSON is walked for POD_SECURITY_PATCH_KEYS, Pod Security
1311
+ * Admission labels, AppArmor annotations and the host of a probe or
1312
+ * lifecycle hook (keys, and the path/from of JSON-patch operations,
1313
+ * decoded, so a \u escape or a ~1 cannot hide a name).
1314
+ *
1315
+ * Why JSON only: kubectl sends a body whose first non-space byte is "{" to
1316
+ * the API server byte for byte, and decodes every other body as YAML 1.1
1317
+ * (apimachinery's yaml.ToJSON) — including a "[" body such as a JSON patch.
1318
+ * YAML honours type tags, anchors, aliases and merge keys, so `!!binary
1319
+ * c2VydmljZUFjY291bnROYW1l` is the key serviceAccountName although that
1320
+ * word appears nowhere in the text; no scan of the text can see what
1321
+ * kubectl will apply. A body that IS valid JSON decodes to the same keys
1322
+ * and paths either way: in JSON, tag, anchor and merge-key syntax can only
1323
+ * sit inside quoted strings, where YAML reads it as plain text, and a
1324
+ * repeated key keeps its last value in JSON.parse and in kubectl alike.
1325
+ * Every patch a fix needs can be written as JSON.
1326
+ *
1327
+ * A body that names no forbidden field can still drop them by replacing or
1328
+ * removing what holds them; findPodSpecReplacement refuses that, for the
1329
+ * patch types kubectl could apply the body as (`patchTypes`, see
1330
+ * readPatchTypes).
1331
+ */
1332
+ function findPatchBodyProblem(body, patchTypes) {
1333
+ let parsed = undefined;
1334
+ try {
1335
+ parsed = JSON.parse(body);
1336
+ }
1337
+ catch (_a) {
1338
+ return `kubectl patch with a body that is not JSON is never allowed for OneUptime AI: kubectl reads any other body as YAML, whose tags, anchors and merge keys can spell a field name that appears nowhere in the text (write the patch body as JSON, e.g. -p '{"spec":{"replicas":3}}')`;
1339
+ }
1340
+ const field = findForbiddenJsonField(parsed, 0, "");
1341
+ if (field === PATCH_BODY_TOO_DEEP) {
1342
+ return `kubectl patch with a body nested more than ${MAX_PATCH_BODY_DEPTH} levels deep is never allowed for OneUptime AI (no fix needs one)`;
1343
+ }
1344
+ if (field !== null) {
1345
+ return isPodSecurityKey(field)
1346
+ ? `kubectl patch of ${field} is never allowed for OneUptime AI: Pod Security Admission reads these labels to decide whether privileged pods may run in a namespace`
1347
+ : `kubectl patch that touches ${field} is never allowed for OneUptime AI: it changes which identity, privileges, host access, Secrets or program a pod runs with (patch other fields, or use set image / set env / set resources)`;
1348
+ }
1349
+ return findPodSpecReplacement(parsed, patchTypes);
1350
+ }
1351
+ /*
1352
+ * ---- Patches that replace what holds the pod-security fields ---------------
1353
+ *
1354
+ * POD_SECURITY_PATCH_KEYS are matched by NAME, which only sees a patch that
1355
+ * spells one. A patch that replaces or removes an object ABOVE them drops
1356
+ * them without naming any. Checked against the pinned kubectl v1.36.4 with
1357
+ * `patch --local` on a Deployment whose pod runs as a restricted
1358
+ * ServiceAccount with a securityContext, a command and a volume:
1359
+ * - strategic merge (the default type): `"$patch": "replace"` in the pod
1360
+ * spec (or in template, or spec) leaves only what the patch lists —
1361
+ * serviceAccountName back to default, securityContext and volumes
1362
+ * gone; `$retainKeys` in the pod spec clears every field it does not
1363
+ * list; a `{"$patch": "replace"}` element in the containers list drops
1364
+ * every container's command, securityContext, env and volumeMounts; a
1365
+ * `{"name": X, "$patch": "delete"}` element removes container X; null
1366
+ * for the pod spec or the containers list removes it;
1367
+ * - merge (--type=merge, RFC 7386): a list is replaced wholesale, so
1368
+ * `{"containers": [{"name": "web", "image": "x"}]}` leaves one container
1369
+ * with nothing but a name and an image; null removes, and a scalar
1370
+ * replaces;
1371
+ * - JSON patch: replace or remove of /spec/template/spec,
1372
+ * /spec/template/spec/containers or /spec/template/spec/containers/0
1373
+ * (/spec/containers/0 on a Pod), and an add whose path is an existing
1374
+ * object member — add replaces it — do the same.
1375
+ *
1376
+ * So nothing on the path from the object down to a pod-security field may be
1377
+ * replaced, removed, reordered or filtered. That path is POD_SPEC_PATH_STEPS
1378
+ * from the top of the body: through spec, template and jobTemplate (the pod
1379
+ * template of a Pod, a workload, a Job, a CronJob, a PodTemplate, and the
1380
+ * custom workloads that copy that layout) to the pod spec, then its
1381
+ * containers list, one container, its env list, one env entry and its
1382
+ * valueFrom. Refused along that path:
1383
+ * - any strategic-merge directive — a key starting with "$" ($patch,
1384
+ * $retainKeys, $setElementOrder/..., $deleteFromPrimitiveList/...) — in
1385
+ * a map on it, a `{"$patch": ...}` element of a list on it included;
1386
+ * - null for a key on it, or a value of the wrong shape (a scalar or a
1387
+ * list where the object goes, anything but a list where a list goes);
1388
+ * - under a merge patch, any value for the containers or env list;
1389
+ * - a JSON-patch remove, replace, move or copy whose path or from is on it
1390
+ * (the whole object, "", included), and an add whose path is on it and
1391
+ * names an object member rather than a list position.
1392
+ * Anything off that path — metadata and the pod template's labels and
1393
+ * annotations, replicas, the update strategy, a container's image or
1394
+ * resources, an env entry's value — stays patchable: a strategic-merge patch
1395
+ * that names one container and sets its image or resources, a JSON-patch
1396
+ * replace of /spec/replicas or /spec/template/spec/containers/0/image, a
1397
+ * merge patch of metadata/annotations. Adding a list element (a new env
1398
+ * entry, or a new container, whose fields the name check reads) is not a
1399
+ * replacement. Keys are matched case-insensitively, like the name check.
1400
+ */
1401
+ // The patch types kubectl patch accepts for --type (it lowercases the value).
1402
+ var PatchType;
1403
+ (function (PatchType) {
1404
+ PatchType["Strategic"] = "strategic";
1405
+ PatchType["Merge"] = "merge";
1406
+ PatchType["Json"] = "json";
1407
+ })(PatchType || (PatchType = {}));
1408
+ const PATCH_TYPES = [
1409
+ PatchType.Strategic,
1410
+ PatchType.Merge,
1411
+ PatchType.Json,
1412
+ ];
1413
+ /*
1414
+ * The types kubectl could apply a body as: strategic merge when --type is
1415
+ * not given, else every --type value (pflag keeps the last one; reading all
1416
+ * of them is the safe side). A value kubectl does not know makes it refuse
1417
+ * the command, so it is read as every type.
1418
+ */
1419
+ function readPatchTypes(typeValues) {
1420
+ const types = new Set();
1421
+ if (typeValues.length === 0) {
1422
+ types.add(PatchType.Strategic);
1423
+ return types;
1424
+ }
1425
+ for (const value of typeValues) {
1426
+ const known = PATCH_TYPES.find((type) => {
1427
+ return type === value.trim().toLowerCase();
1428
+ });
1429
+ if (known) {
1430
+ types.add(known);
1431
+ }
1432
+ else {
1433
+ for (const type of PATCH_TYPES) {
1434
+ types.add(type);
1435
+ }
1436
+ }
1437
+ }
1438
+ return types;
1439
+ }
1440
+ // Where a patch is on the path from the object to the pod-security fields.
1441
+ var PodSpecPathStep;
1442
+ (function (PodSpecPathStep) {
1443
+ // The object, spec, template, jobTemplate — and the pod spec itself.
1444
+ PodSpecPathStep["PodSpecOrAbove"] = "PodSpecOrAbove";
1445
+ PodSpecPathStep["ContainerList"] = "ContainerList";
1446
+ PodSpecPathStep["Container"] = "Container";
1447
+ PodSpecPathStep["EnvList"] = "EnvList";
1448
+ PodSpecPathStep["EnvEntry"] = "EnvEntry";
1449
+ PodSpecPathStep["ValueFrom"] = "ValueFrom";
1450
+ })(PodSpecPathStep || (PodSpecPathStep = {}));
1451
+ /*
1452
+ * The steps down the path, by lowercased key. A list step's elements are the
1453
+ * step in LIST_ELEMENT_STEPS. A key not listed for a step leaves the path.
1454
+ */
1455
+ const POD_SPEC_PATH_STEPS = {
1456
+ [PodSpecPathStep.PodSpecOrAbove]: {
1457
+ spec: PodSpecPathStep.PodSpecOrAbove,
1458
+ template: PodSpecPathStep.PodSpecOrAbove,
1459
+ jobtemplate: PodSpecPathStep.PodSpecOrAbove,
1460
+ containers: PodSpecPathStep.ContainerList,
1461
+ },
1462
+ [PodSpecPathStep.ContainerList]: {},
1463
+ [PodSpecPathStep.Container]: { env: PodSpecPathStep.EnvList },
1464
+ [PodSpecPathStep.EnvList]: {},
1465
+ [PodSpecPathStep.EnvEntry]: { valuefrom: PodSpecPathStep.ValueFrom },
1466
+ [PodSpecPathStep.ValueFrom]: {},
1467
+ };
1468
+ const LIST_ELEMENT_STEPS = new Map([
1469
+ [PodSpecPathStep.ContainerList, PodSpecPathStep.Container],
1470
+ [PodSpecPathStep.EnvList, PodSpecPathStep.EnvEntry],
1471
+ ]);
1472
+ function nextPodSpecPathStep(step, key) {
1473
+ const listElement = LIST_ELEMENT_STEPS.get(step);
1474
+ if (listElement) {
1475
+ return listElement;
1476
+ }
1477
+ const steps = POD_SPEC_PATH_STEPS[step];
1478
+ const lower = key.toLowerCase();
1479
+ return Object.prototype.hasOwnProperty.call(steps, lower)
1480
+ ? steps[lower]
1481
+ : undefined;
1482
+ }
1483
+ // What the refusals say a replacement drops.
1484
+ const POD_SPEC_REPLACEMENT_DROPS = "it replaces or removes a pod spec, a container or what holds them, and so drops the securityContext, serviceAccountName, command, args, volumes, volumeMounts and Secret references under it without naming any of them";
1485
+ const POD_SPEC_REPLACEMENT_INSTEAD = "patch the field itself (such as one container's image or resources, named in a strategic-merge patch, or /spec/template/spec/containers/0/image in a JSON patch), or use set image / set env / set resources";
1486
+ // A JSON-pointer segment: "~1" is "/" and "~0" is "~" (RFC 6901, in that order).
1487
+ const JSON_POINTER_SLASH_ESCAPE = /~1/g;
1488
+ const JSON_POINTER_TILDE_ESCAPE = /~0/g;
1489
+ function decodeJsonPointerSegment(segment) {
1490
+ return segment
1491
+ .replace(JSON_POINTER_SLASH_ESCAPE, "/")
1492
+ .replace(JSON_POINTER_TILDE_ESCAPE, "~");
1493
+ }
1494
+ // A list position in a JSON-patch path: an index, or "-" (the end).
1495
+ const JSON_PATCH_LIST_POSITION = /^(-|[0-9]+)$/;
1496
+ function describePodSpecPath(segments) {
1497
+ return segments.length === 0 ? "the whole object" : `/${segments.join("/")}`;
1498
+ }
1499
+ function isPlainObject(value) {
1500
+ return value !== null && typeof value === "object" && !Array.isArray(value);
1501
+ }
1502
+ function isListStep(step) {
1503
+ return LIST_ELEMENT_STEPS.has(step);
1504
+ }
1505
+ /*
1506
+ * Why a parsed patch body replaces or removes something on the pod-spec path
1507
+ * (see the section above), or null.
1508
+ */
1509
+ function findPodSpecReplacement(parsed, patchTypes) {
1510
+ if (Array.isArray(parsed)) {
1511
+ for (const operation of parsed) {
1512
+ if (!isPlainObject(operation)) {
1513
+ continue;
1514
+ }
1515
+ const problem = findJsonPatchReplacement(operation);
1516
+ if (problem) {
1517
+ return problem;
1518
+ }
1519
+ }
1520
+ return null;
1521
+ }
1522
+ if (!isPlainObject(parsed)) {
1523
+ return null;
1524
+ }
1525
+ return findObjectPatchReplacement(parsed, PodSpecPathStep.PodSpecOrAbove, [], patchTypes, 0);
1526
+ }
1527
+ // A strategic-merge or merge body, walked down the pod-spec path only.
1528
+ function findObjectPatchReplacement(map, step, segments, patchTypes, depth) {
1529
+ // findForbiddenJsonField already refused a body this deep.
1530
+ if (depth > MAX_PATCH_BODY_DEPTH) {
1531
+ return null;
1532
+ }
1533
+ for (const [key, value] of Object.entries(map)) {
1534
+ if (key.startsWith("$")) {
1535
+ return `kubectl patch with the strategic-merge directive "${key}" at ${describePodSpecPath(segments)} is never allowed for OneUptime AI: ${POD_SPEC_REPLACEMENT_DROPS} (${POD_SPEC_REPLACEMENT_INSTEAD})`;
1536
+ }
1537
+ const next = nextPodSpecPathStep(step, key);
1538
+ if (next === undefined) {
1539
+ continue;
1540
+ }
1541
+ const where = describePodSpecPath([...segments, key]);
1542
+ if (value === null) {
1543
+ return `kubectl patch that sets ${where} to null is never allowed for OneUptime AI: ${POD_SPEC_REPLACEMENT_DROPS} (${POD_SPEC_REPLACEMENT_INSTEAD})`;
1544
+ }
1545
+ if (!isListStep(next)) {
1546
+ if (!isPlainObject(value)) {
1547
+ return `kubectl patch that sets ${where} to something other than an object is never allowed for OneUptime AI: ${POD_SPEC_REPLACEMENT_DROPS} (${POD_SPEC_REPLACEMENT_INSTEAD})`;
1548
+ }
1549
+ const problem = findObjectPatchReplacement(value, next, [...segments, key], patchTypes, depth + 1);
1550
+ if (problem) {
1551
+ return problem;
1552
+ }
1553
+ continue;
1554
+ }
1555
+ if (patchTypes.has(PatchType.Merge)) {
1556
+ return `kubectl patch --type=merge that sets ${where} is never allowed for OneUptime AI: a merge patch replaces a list wholesale, so ${POD_SPEC_REPLACEMENT_DROPS} (use a strategic-merge patch that names the container, or set image / set env / set resources)`;
1557
+ }
1558
+ if (!Array.isArray(value)) {
1559
+ return `kubectl patch that sets ${where} to something other than a list is never allowed for OneUptime AI: ${POD_SPEC_REPLACEMENT_DROPS} (${POD_SPEC_REPLACEMENT_INSTEAD})`;
1560
+ }
1561
+ const element = LIST_ELEMENT_STEPS.get(next);
1562
+ for (let index = 0; index < value.length; index++) {
1563
+ const item = value[index];
1564
+ if (!isPlainObject(item)) {
1565
+ continue;
1566
+ }
1567
+ const problem = findObjectPatchReplacement(item, element, [...segments, key, String(index)], patchTypes, depth + 2);
1568
+ if (problem) {
1569
+ return problem;
1570
+ }
1571
+ }
1572
+ }
1573
+ return null;
1574
+ }
1575
+ function readJsonPatchTarget(pointer) {
1576
+ // "" is the whole object; every other pointer starts with "/".
1577
+ const segments = pointer === ""
1578
+ ? []
1579
+ : pointer.split("/").slice(1).map(decodeJsonPointerSegment);
1580
+ let step = PodSpecPathStep.PodSpecOrAbove;
1581
+ let isListPosition = false;
1582
+ for (const segment of segments) {
1583
+ isListPosition = isListStep(step) && JSON_PATCH_LIST_POSITION.test(segment);
1584
+ const next = nextPodSpecPathStep(step, segment);
1585
+ if (next === undefined) {
1586
+ return undefined;
1587
+ }
1588
+ step = next;
1589
+ }
1590
+ return { step, isListPosition };
1591
+ }
1592
+ function findJsonPatchReplacement(operation) {
1593
+ const op = operation["op"];
1594
+ const path = operation["path"];
1595
+ const from = operation["from"];
1596
+ // test only compares; add inserts at a list position and replaces a member.
1597
+ if (op === "test") {
1598
+ return null;
1599
+ }
1600
+ if (typeof path === "string") {
1601
+ const target = readJsonPatchTarget(path);
1602
+ if (target && !(op === "add" && target.isListPosition)) {
1603
+ return `kubectl patch with a JSON-patch "${String(op)}" of ${describeJsonPointer(path)} is never allowed for OneUptime AI: ${POD_SPEC_REPLACEMENT_DROPS} (${POD_SPEC_REPLACEMENT_INSTEAD})`;
1604
+ }
1605
+ }
1606
+ if (typeof from === "string" && op !== "add") {
1607
+ if (readJsonPatchTarget(from)) {
1608
+ return `kubectl patch with a JSON-patch "${String(op)}" from ${describeJsonPointer(from)} is never allowed for OneUptime AI: ${POD_SPEC_REPLACEMENT_DROPS} (${POD_SPEC_REPLACEMENT_INSTEAD})`;
1609
+ }
1610
+ }
1611
+ return null;
1612
+ }
1613
+ function describeJsonPointer(pointer) {
1614
+ return pointer === "" ? "the whole object" : pointer;
1615
+ }
1616
+ /*
1617
+ * The probe and lifecycle-hook handlers whose `host` the Pod Security
1618
+ * Standards baseline refuses (its Host Probes / Lifecycle Hooks control,
1619
+ * Kubernetes v1.34+): a liveness, readiness or startup probe, or a postStart
1620
+ * or preStop hook, with httpGet.host or tcpSocket.host makes the kubelet
1621
+ * connect from the node to any address it names instead of to the pod. The
1622
+ * name check reads `host` only as a member of one of these (lowercased): a
1623
+ * `host` anywhere else, such as an Ingress rule's, is no pod field.
1624
+ */
1625
+ const HOST_FIELD_HANDLER_KEYS = new Set([
1626
+ "httpget",
1627
+ "tcpsocket",
1628
+ ]);
1629
+ const HANDLER_HOST_KEY = "host";
1630
+ /*
1631
+ * Why a key (or a JSON-pointer segment) may not appear in a patch body, as
1632
+ * the field to name, or null. `parentKey` is the key of the object that
1633
+ * holds it ("" at the top, and for a list element), for the fields that are
1634
+ * forbidden only where they sit (HOST_FIELD_HANDLER_KEYS).
1635
+ */
1636
+ function forbiddenFieldInName(name, parentKey) {
1637
+ if (POD_SECURITY_PATCH_KEYS.has(name.toLowerCase())) {
1638
+ return name;
1639
+ }
1640
+ if (isPodSecurityKey(name) || isAppArmorAnnotationKey(name)) {
1641
+ return name;
1642
+ }
1643
+ if (name.toLowerCase() === HANDLER_HOST_KEY &&
1644
+ HOST_FIELD_HANDLER_KEYS.has(parentKey.toLowerCase())) {
1645
+ return `${parentKey}.${name}`;
1646
+ }
1647
+ return null;
1648
+ }
1649
+ // A JSON pointer ("/spec/template/spec/volumes/-"), decoded segment by segment.
1650
+ function jsonPointerSegments(pointer) {
1651
+ return pointer.split("/").map(decodeJsonPointerSegment);
1652
+ }
1653
+ // A JSON-pointer path ("/spec/template/spec/volumes/-"), segment by segment.
1654
+ function forbiddenFieldInPath(path) {
1655
+ const segments = jsonPointerSegments(path);
1656
+ for (let index = 0; index < segments.length; index++) {
1657
+ const found = forbiddenFieldInName(segments[index], index > 0 ? segments[index - 1] : "");
1658
+ if (found) {
1659
+ return found;
1660
+ }
1661
+ }
1662
+ return null;
1663
+ }
1664
+ /*
1665
+ * The first forbidden field a parsed patch body names (see
1666
+ * forbiddenFieldInName), PATCH_BODY_TOO_DEEP, or null. `parentKey` is the
1667
+ * key that holds `value` — for a JSON-patch operation's value, the last
1668
+ * segment of its path, so `{"op": "add", "path": ".../httpGet", "value":
1669
+ * {"host": ...}}` is read like the same object written in place.
1670
+ */
1671
+ function findForbiddenJsonField(value, depth, parentKey) {
1672
+ // Nesting this deep is not a patch a fix needs; refuse rather than recurse.
1673
+ if (depth > MAX_PATCH_BODY_DEPTH) {
1674
+ return PATCH_BODY_TOO_DEEP;
1675
+ }
1676
+ if (Array.isArray(value)) {
1677
+ for (const item of value) {
1678
+ const found = findForbiddenJsonField(item, depth + 1, "");
1679
+ if (found) {
1680
+ return found;
1681
+ }
1682
+ }
1683
+ return null;
1684
+ }
1685
+ if (value === null || typeof value !== "object") {
1686
+ return null;
1687
+ }
1688
+ const record = value;
1689
+ const isJsonPatchOperation = Object.prototype.hasOwnProperty.call(record, "op");
1690
+ const operationPath = record["path"];
1691
+ const operationValueParent = isJsonPatchOperation && typeof operationPath === "string"
1692
+ ? jsonPointerSegments(operationPath).pop() || ""
1693
+ : "";
1694
+ for (const [key, child] of Object.entries(record)) {
1695
+ const keyProblem = forbiddenFieldInName(key, parentKey);
1696
+ if (keyProblem) {
1697
+ return keyProblem;
1698
+ }
1699
+ /*
1700
+ * Strategic-merge directives name the list they edit after the slash:
1701
+ * "$setElementOrder/volumes", "$deleteFromPrimitiveList/args".
1702
+ */
1703
+ if (key.startsWith("$") && key.includes("/")) {
1704
+ const directiveProblem = forbiddenFieldInName(key.slice(key.indexOf("/") + 1), parentKey);
1705
+ if (directiveProblem) {
1706
+ return directiveProblem;
1707
+ }
1708
+ }
1709
+ if (isJsonPatchOperation &&
1710
+ (key === "path" || key === "from") &&
1711
+ typeof child === "string") {
1712
+ const pathProblem = forbiddenFieldInPath(child);
1713
+ if (pathProblem) {
1714
+ return pathProblem;
1715
+ }
1716
+ }
1717
+ const found = findForbiddenJsonField(child, depth + 1, isJsonPatchOperation && key === "value" ? operationValueParent : key);
1718
+ if (found) {
1719
+ return found;
1720
+ }
1721
+ }
1722
+ return null;
1723
+ }
1724
+ // Same bounds CommandPolicy applies to the Bash lane's allowlist.
1725
+ const MAX_ALLOWLIST_PATTERNS = 100;
1726
+ const MAX_ALLOWLIST_PATTERN_LENGTH = 500;
1727
+ /*
1728
+ * Exported so the server's save validation and the AI page's form
1729
+ * validation hold entries to exactly the bounds matchesAllowlist reads.
1730
+ */
1731
+ export const KUBECTL_ALLOWLIST_MAX_PATTERNS = MAX_ALLOWLIST_PATTERNS;
1732
+ export const KUBECTL_ALLOWLIST_MAX_PATTERN_LENGTH = MAX_ALLOWLIST_PATTERN_LENGTH;
1733
+ function isFlagToken(token) {
1734
+ return token.startsWith("-") && token !== "-";
1735
+ }
1736
+ // What tokenize() says for a command (or an allowlist entry) with no verb.
1737
+ const NO_VERB_MESSAGE = "The command names no kubectl verb.";
1738
+ // A word that holds whitespace was quoted together (see readAllowlistEntry).
1739
+ const WHITESPACE_REGEX = /\s/;
1740
+ /*
1741
+ * Flags whose value picks WHICH objects (or namespace) a command acts on —
1742
+ * the namespace, a selector, --all, the source object of --from — so a `*`
1743
+ * in their value makes an allowlist entry broad.
1744
+ */
1745
+ const WIDENING_FLAGS = [
1746
+ "n",
1747
+ "namespace",
1748
+ "l",
1749
+ "selector",
1750
+ "field-selector",
1751
+ "pod-selector",
1752
+ "all",
1753
+ "A",
1754
+ "all-namespaces",
1755
+ "from",
1756
+ ];
1757
+ // For the "write the subcommand out" message.
1758
+ const SUBCOMMAND_EXAMPLES = {
1759
+ rollout: "restart deployment/web -n web",
1760
+ set: "image deployment/web * -n web",
1761
+ create: "job manual-run --from=cronjob/nightly -n web",
1762
+ auth: "can-i get pods",
1763
+ top: "pod -n web",
1764
+ };
1765
+ function subcommandExample(verb) {
1766
+ const example = Object.prototype.hasOwnProperty.call(SUBCOMMAND_EXAMPLES, verb)
1767
+ ? SUBCOMMAND_EXAMPLES[verb]
1768
+ : undefined;
1769
+ return example ? `, as in "kubectl ${verb} ${example}"` : "";
1770
+ }
1771
+ function hasWildcard(token) {
1772
+ return token.includes("*");
1773
+ }
1774
+ /*
1775
+ * Whether evaluateForAutoExecution can ever promote a command this entry
1776
+ * matches through the allowlist: never a read (it runs anyway), and never a
1777
+ * drain, a taint or a patch that names a Node (it always needs a human;
1778
+ * describeAlwaysHumanWrite reads the entry's objects exactly as it reads a
1779
+ * command's, so `kubectl patch node * -p *` promotes nothing). A `*` where
1780
+ * the kind goes may still stand for a Node, but it stands for every other
1781
+ * kind as well, so such an entry is broad, and the Node commands it matches
1782
+ * need a human all the same.
1783
+ */
1784
+ function allowlistMayPromote(parsed) {
1785
+ const verb = parsed.positionals[0] || "";
1786
+ const subcommand = parsed.positionals[1] || "";
1787
+ if (READ_VERBS.has(verb) || READ_COMMAND_GROUPS.has(verb)) {
1788
+ return false;
1789
+ }
1790
+ if (describeAlwaysHumanWrite(verb, commandTargets(verb, parsed.positionals)) !==
1791
+ undefined) {
1792
+ return false;
1793
+ }
1794
+ return !(verb === "rollout" &&
1795
+ (subcommand === "status" || subcommand === "history"));
1796
+ }
1797
+ /*
1798
+ * The commands whose words after the objects are UPDATES kubectl requires
1799
+ * (label, annotate, set image, and set env unless -e/--env/--from supply the
1800
+ * variables): with no update word, kubectl refuses the command outright.
1801
+ */
1802
+ function readsUpdatePairs(verb, subcommand, flags) {
1803
+ if (verb === "label" || verb === "annotate") {
1804
+ return true;
1805
+ }
1806
+ if (verb !== "set") {
1807
+ return false;
1808
+ }
1809
+ if (subcommand === "image") {
1810
+ return true;
1811
+ }
1812
+ return (subcommand === "env" &&
1813
+ !flags.has("e") &&
1814
+ !flags.has("env") &&
1815
+ !flags.has("from"));
1816
+ }
1817
+ /*
1818
+ * An update word (KEY=VALUE or KEY-) in an allowlist entry: every word it
1819
+ * matches is one too, so it can never stand for another object.
1820
+ */
1821
+ function isUpdatePairToken(token) {
1822
+ return token.includes("=") || (token.endsWith("-") && token !== "-");
1823
+ }
1824
+ /*
1825
+ * One pattern token against one argv token (see the allowlist section in the
1826
+ * header). A flag is matched only by the same flag spelled literally: the
1827
+ * part up to "=" must be equal, and only a value after "=" may glob. A `*`
1828
+ * never matches whitespace; whitespace runs inside a quoted token must line
1829
+ * up with whitespace in the pattern (runs are collapsed on both sides).
1830
+ */
1831
+ function allowlistTokenMatches(pattern, token) {
1832
+ if (isFlagToken(token) || isFlagToken(pattern)) {
1833
+ if (!isFlagToken(token) || !isFlagToken(pattern)) {
1834
+ return false;
1835
+ }
1836
+ const tokenEq = token.indexOf("=");
1837
+ const patternEq = pattern.indexOf("=");
1838
+ if (tokenEq < 0 || patternEq < 0) {
1839
+ return pattern === token;
1840
+ }
1841
+ if (pattern.slice(0, patternEq) !== token.slice(0, tokenEq)) {
1842
+ return false;
1843
+ }
1844
+ return globWithinToken(pattern.slice(patternEq + 1), token.slice(tokenEq + 1));
1845
+ }
1846
+ return globWithinToken(pattern, token);
1847
+ }
1848
+ function globWithinToken(pattern, text) {
1849
+ const patternPieces = pattern.trim().split(/\s+/);
1850
+ const textPieces = text.trim().split(/\s+/);
1851
+ if (patternPieces.length !== textPieces.length) {
1852
+ return false;
1853
+ }
1854
+ for (let i = 0; i < patternPieces.length; i++) {
1855
+ if (!CommandPolicy.globMatches(patternPieces[i], textPieces[i])) {
1856
+ return false;
1857
+ }
1858
+ }
1859
+ return true;
1860
+ }
1861
+ // A replica count kubectl scale takes: digits only.
1862
+ const REPLICA_COUNT_PATTERN = /^[0-9]+$/;
1863
+ export default class KubectlPolicy {
1864
+ /*
1865
+ * Split a command line into an argv the way a POSIX shell would split it
1866
+ * for quoting purposes ONLY: single quotes, double quotes, backslash
1867
+ * escapes. No expansion, no operators, no redirection — those characters
1868
+ * stay literal inside their token. The command must fit on one line.
1869
+ */
1870
+ static tokenize(command) {
1871
+ const text = (command || "").trim();
1872
+ if (!text) {
1873
+ return { errorMessage: "Empty command." };
1874
+ }
1875
+ if (text.length > MAX_COMMAND_LENGTH_CHARS) {
1876
+ return {
1877
+ errorMessage: `Command exceeds the ${MAX_COMMAND_LENGTH_CHARS}-character limit.`,
1878
+ };
1879
+ }
1880
+ if (text.includes("\n") || text.includes("\r") || text.includes("\0")) {
1881
+ return { errorMessage: "A kubectl command must be a single line." };
1882
+ }
1883
+ const args = [];
1884
+ let current = "";
1885
+ let inSingle = false;
1886
+ let inDouble = false;
1887
+ let hasToken = false;
1888
+ for (let i = 0; i < text.length; i++) {
1889
+ const ch = text[i];
1890
+ if (inSingle) {
1891
+ if (ch === "'") {
1892
+ inSingle = false;
1893
+ }
1894
+ else {
1895
+ current += ch;
1896
+ }
1897
+ continue;
1898
+ }
1899
+ if (inDouble) {
1900
+ if (ch === '"') {
1901
+ inDouble = false;
1902
+ }
1903
+ else if (ch === "\\" && i + 1 < text.length) {
1904
+ const next = text[i + 1];
1905
+ if (next === '"' || next === "\\") {
1906
+ current += next;
1907
+ i++;
1908
+ }
1909
+ else {
1910
+ current += ch;
1911
+ }
1912
+ }
1913
+ else {
1914
+ current += ch;
1915
+ }
1916
+ continue;
1917
+ }
1918
+ if (ch === "'") {
1919
+ inSingle = true;
1920
+ hasToken = true;
1921
+ continue;
1922
+ }
1923
+ if (ch === '"') {
1924
+ inDouble = true;
1925
+ hasToken = true;
1926
+ continue;
1927
+ }
1928
+ if (ch === "\\" && i + 1 < text.length) {
1929
+ current += text[i + 1];
1930
+ hasToken = true;
1931
+ i++;
1932
+ continue;
1933
+ }
1934
+ if (ch === " " || ch === "\t") {
1935
+ if (hasToken) {
1936
+ args.push(current);
1937
+ current = "";
1938
+ hasToken = false;
1939
+ }
1940
+ continue;
1941
+ }
1942
+ current += ch;
1943
+ hasToken = true;
1944
+ }
1945
+ if (inSingle || inDouble) {
1946
+ return { errorMessage: "Unbalanced quotes in the command." };
1947
+ }
1948
+ if (hasToken) {
1949
+ args.push(current);
1950
+ }
1951
+ if (args.length === 0) {
1952
+ return { errorMessage: "Empty command." };
1953
+ }
1954
+ if (args.length > MAX_TOKENS) {
1955
+ return {
1956
+ errorMessage: `A kubectl command may have at most ${MAX_TOKENS} arguments.`,
1957
+ };
1958
+ }
1959
+ // The model may or may not write the binary name; the Runner adds it.
1960
+ if (args[0].toLowerCase() === "kubectl") {
1961
+ args.shift();
1962
+ }
1963
+ if (args.length === 0) {
1964
+ return { errorMessage: NO_VERB_MESSAGE };
1965
+ }
1966
+ return { args };
1967
+ }
1968
+ // Tokenize, then evaluate.
1969
+ static evaluateCommand(command) {
1970
+ const tokenized = KubectlPolicy.tokenize(command);
1971
+ if (!tokenized.args) {
1972
+ return {
1973
+ tier: KubectlCommandTier.Denied,
1974
+ reason: tokenized.errorMessage || "Could not parse the command.",
1975
+ args: [],
1976
+ verb: "",
1977
+ displayCommand: (command || "").trim().slice(0, 200),
1978
+ };
1979
+ }
1980
+ return KubectlPolicy.evaluateArgs(tokenized.args);
1981
+ }
1982
+ /*
1983
+ * The evaluation proper, on an argv. The Runner calls this on the argv it
1984
+ * received so its verdict never depends on re-tokenizing a string the
1985
+ * same way the server did.
1986
+ */
1987
+ static evaluateArgs(rawArgs) {
1988
+ const args = (rawArgs || []).filter((arg) => {
1989
+ return typeof arg === "string";
1990
+ });
1991
+ const displayCommand = KubectlPolicy.renderDisplayCommand(args);
1992
+ const deny = (reason, verb = "") => {
1993
+ return {
1994
+ tier: KubectlCommandTier.Denied,
1995
+ reason,
1996
+ args,
1997
+ verb,
1998
+ displayCommand,
1999
+ };
2000
+ };
2001
+ if (args.length === 0) {
2002
+ return deny(NO_VERB_MESSAGE);
2003
+ }
2004
+ if (args.length > MAX_TOKENS) {
2005
+ return deny(`A kubectl command may have at most ${MAX_TOKENS} arguments.`);
2006
+ }
2007
+ for (const arg of args) {
2008
+ if (arg.includes("\n") || arg.includes("\r") || arg.includes("\0")) {
2009
+ return deny("Arguments may not contain line breaks.");
2010
+ }
2011
+ }
2012
+ const parsed = KubectlPolicy.parseArgs(args);
2013
+ const rawVerb = parsed.positionals[0] || "";
2014
+ const verb = rawVerb.toLowerCase();
2015
+ // A denied verb is the most useful thing to say, whatever its flags.
2016
+ if (DENIED_VERBS.has(verb)) {
2017
+ return deny(`kubectl ${verb} is not allowed for OneUptime AI`, verb);
2018
+ }
2019
+ // Credential / cluster-selection / file / unknown flags: never.
2020
+ if (parsed.violation) {
2021
+ return deny(parsed.violation);
2022
+ }
2023
+ if (!verb) {
2024
+ return deny(NO_VERB_MESSAGE);
2025
+ }
2026
+ /*
2027
+ * cobra matches commands case-sensitively: "Get" is not the get command,
2028
+ * and kubectl would look for a kubectl-Get plugin on the Runner's PATH
2029
+ * and run it. The same holds one level down for subcommands.
2030
+ */
2031
+ if (rawVerb !== verb) {
2032
+ return deny(`kubectl matches commands case-sensitively, so "${rawVerb}" is not kubectl ${verb}: kubectl would look for a kubectl-${rawVerb} plugin on the Runner (write the verb in lowercase)`, verb);
2033
+ }
2034
+ const rawSubcommand = parsed.positionals[1] || "";
2035
+ const subcommand = rawSubcommand.toLowerCase();
2036
+ if (SUBCOMMAND_VERBS.has(verb) && rawSubcommand !== subcommand) {
2037
+ return deny(`kubectl matches commands case-sensitively, so "${rawSubcommand}" is not the kubectl ${verb} ${subcommand} command (write the subcommand in lowercase)`, `${verb} ${subcommand}`);
2038
+ }
2039
+ const streamingProblem = KubectlPolicy.findStreamingFlag(parsed.flags);
2040
+ if (streamingProblem) {
2041
+ return deny(streamingProblem);
2042
+ }
2043
+ const outputProblem = KubectlPolicy.findOutputFormatProblem(parsed.flags);
2044
+ if (outputProblem) {
2045
+ return deny(outputProblem);
2046
+ }
2047
+ /*
2048
+ * The namespace, resolved from -n / --namespace in every spelling
2049
+ * parseArgs accepts (-n X, -nX, -n=X, --namespace X, --namespace=X).
2050
+ * pflag keeps the LAST value of a repeated flag, so `-n web ... -n
2051
+ * kube-system` would run in kube-system while a reader (or an allowlist
2052
+ * pattern) saw web first: a namespace set twice is refused outright.
2053
+ */
2054
+ const namespaceValues = [
2055
+ ...(parsed.flags.get("n") || []),
2056
+ ...(parsed.flags.get("namespace") || []),
2057
+ ];
2058
+ if (namespaceValues.length > 1) {
2059
+ return deny(`the namespace is set more than once (${namespaceValues
2060
+ .map((value) => {
2061
+ return `"${value}"`;
2062
+ })
2063
+ .join(", ")}); kubectl silently uses the last one, so set -n once`, verb);
2064
+ }
2065
+ const namespace = namespaceValues[0];
2066
+ const hasAllNamespaces = parsed.flags.has("A") || parsed.flags.has("all-namespaces");
2067
+ const hasAll = parsed.flags.has("all");
2068
+ /*
2069
+ * A field selector selects exactly like a label selector (kubectl's
2070
+ * builder visits every match), so for a write both are "a selector".
2071
+ */
2072
+ const hasSelector = parsed.flags.has("l") ||
2073
+ parsed.flags.has("selector") ||
2074
+ parsed.flags.has("field-selector");
2075
+ const hasForce = parsed.flags.has("force");
2076
+ // The objects a write names (see commandTargets).
2077
+ const targets = commandTargets(verb, parsed.positionals);
2078
+ /*
2079
+ * Set for a drain, a taint and a patch of a Node: the write carries
2080
+ * requiresHuman, whatever tier it gets (see the header).
2081
+ */
2082
+ const alwaysHumanReason = describeAlwaysHumanWrite(verb, targets);
2083
+ const createKind = verb === "create" &&
2084
+ Object.prototype.hasOwnProperty.call(CREATE_SUBCOMMANDS, rawSubcommand)
2085
+ ? CREATE_SUBCOMMANDS[rawSubcommand]
2086
+ : undefined;
2087
+ /*
2088
+ * Where a write lands, for the protected-namespace rule. Nodes and the
2089
+ * other built-in cluster-scoped kinds have no namespace (kubectl ignores
2090
+ * -n for them); what could be protected there is a Namespace object
2091
+ * itself. Only the built-in kinds in their own API group count
2092
+ * (builtinKind()): a custom resource that borrows a built-in name —
2093
+ * `annotate nodes.example.com x -n kube-system` — has a scope this
2094
+ * policy cannot see, so it is judged by the namespace -n names.
2095
+ */
2096
+ const isClusterScopedWrite = (NODE_NAME_VERBS.has(verb) &&
2097
+ namesOnlyNodes(parsed.positionals.slice(1))) ||
2098
+ (createKind !== undefined &&
2099
+ CLUSTER_SCOPED_CREATE_KINDS.has(createKind)) ||
2100
+ everyBuiltinKindIn(targets, CLUSTER_SCOPED_KINDS);
2101
+ let protectedNamespace = undefined;
2102
+ /*
2103
+ * A Namespace object named after a protected namespace is protected
2104
+ * whatever -n says. That test reads the folded kind (normalizeKind), so
2105
+ * a custom resource that borrows the name `namespaces` and is NAMED
2106
+ * kube-system needs a human too: the folded reading can only add a
2107
+ * human, never remove one.
2108
+ */
2109
+ if (!isClusterScopedWrite && isProtectedKubernetesNamespace(namespace)) {
2110
+ protectedNamespace = namespace.trim().toLowerCase();
2111
+ }
2112
+ else if (targets.kinds.has("namespace")) {
2113
+ const protectedObject = targets.names.find((name) => {
2114
+ return isProtectedKubernetesNamespace(name);
2115
+ });
2116
+ protectedNamespace = protectedObject
2117
+ ? protectedObject.trim().toLowerCase()
2118
+ : undefined;
2119
+ }
2120
+ /*
2121
+ * The result for a command that may run. A write that lands in (or
2122
+ * targets) a protected namespace is lifted from SafeWrite to RiskyWrite
2123
+ * and marked, and a drain, a taint or a patch of a Node is marked too,
2124
+ * so evaluateForAutoExecution never runs either unattended.
2125
+ */
2126
+ const allowed = (tier, reason, verbLabel) => {
2127
+ const result = {
2128
+ tier,
2129
+ reason,
2130
+ args,
2131
+ verb: verbLabel,
2132
+ displayCommand,
2133
+ };
2134
+ if (namespace !== undefined) {
2135
+ result.namespace = namespace;
2136
+ }
2137
+ if (tier === KubectlCommandTier.Read) {
2138
+ return result;
2139
+ }
2140
+ if (alwaysHumanReason !== undefined) {
2141
+ result.requiresHuman = true;
2142
+ result.reason = alwaysHumanReason;
2143
+ }
2144
+ if (!protectedNamespace) {
2145
+ return result;
2146
+ }
2147
+ result.protectedNamespace = protectedNamespace;
2148
+ /*
2149
+ * Built on result.reason, so a write that needs a human for both
2150
+ * reasons (a patch of a Node and of a workload in kube-system) says
2151
+ * both.
2152
+ */
2153
+ if (tier === KubectlCommandTier.SafeWrite) {
2154
+ result.tier = KubectlCommandTier.RiskyWrite;
2155
+ result.reason = `${result.reason}, but it changes the protected namespace ${protectedNamespace}, so a human must approve it`;
2156
+ }
2157
+ else {
2158
+ result.reason = `${result.reason}; it changes the protected namespace ${protectedNamespace}, which always needs a human`;
2159
+ }
2160
+ return result;
2161
+ };
2162
+ // Kinds for messages: normalized for labels, as written for "not a ...".
2163
+ const kindList = Array.from(targets.kinds).join(",");
2164
+ const writtenKindList = targets.rawKinds.join(",");
2165
+ // ---- Credentials -----------------------------------------------------
2166
+ if (OBJECT_VERBS.has(verb)) {
2167
+ for (const kind of targets.kinds) {
2168
+ if (CREDENTIAL_KINDS.has(kind)) {
2169
+ return deny(`kubectl ${verb} on Secret objects is never allowed for OneUptime AI: it never reads, changes or deletes Secrets, whose values would otherwise reach the model and the job record (describe the workload that uses the Secret instead)`, `${verb} ${kind}`);
2170
+ }
2171
+ }
2172
+ }
2173
+ if (verb === "create") {
2174
+ // `create token` mints a ServiceAccount token and prints it.
2175
+ if (subcommand === "token") {
2176
+ return deny("kubectl create token mints a credential and prints it; OneUptime AI never handles credentials", "create token");
2177
+ }
2178
+ if (normalizeKind(subcommand) === "secret") {
2179
+ return deny("kubectl create secret is never allowed for OneUptime AI: it would put credential values in the command, the approval card and the job record (OneUptime AI never handles credentials)", "create secret");
2180
+ }
2181
+ const deniedCreateKind = createKind && DENIED_CREATE_KINDS.has(createKind)
2182
+ ? createKind
2183
+ : RBAC_KINDS.has(normalizeKind(subcommand))
2184
+ ? normalizeKind(subcommand)
2185
+ : undefined;
2186
+ if (deniedCreateKind) {
2187
+ return deny(`kubectl create ${subcommand} is never allowed for OneUptime AI: roles, role bindings and ServiceAccounts decide who may do what in the cluster, and creating one is a privilege grant, not a fix (a human makes RBAC changes)`, `create ${deniedCreateKind}`);
2188
+ }
2189
+ if (!createKind) {
2190
+ return deny(`kubectl create ${rawSubcommand || "(missing subcommand)"} is not a kubectl create subcommand OneUptime AI may run (for a word it does not know, kubectl would look for a kubectl-create-${rawSubcommand || "<name>"} plugin on the Runner and run it)`, `create ${subcommand}`);
2191
+ }
2192
+ if (IMAGE_WORKLOAD_CREATE_KINDS.has(createKind)) {
2193
+ return deny(`kubectl create ${createKind} starts a new workload running the image named in its --image flag (kubectl requires one): a new program in the cluster, not a fix. OneUptime AI changes existing workloads (set image, rollout undo) and re-runs an existing CronJob with kubectl create job NAME --from=cronjob/NAME`, `create ${createKind}`);
2194
+ }
2195
+ if (createKind === "job") {
2196
+ if (parsed.flags.has("image")) {
2197
+ return deny("kubectl create job --image runs an arbitrary image in the cluster; OneUptime AI only re-runs an existing CronJob: kubectl create job NAME --from=cronjob/NAME", "create job");
2198
+ }
2199
+ const fromValues = parsed.flags.get("from") || [];
2200
+ const from = fromValues.length === 1 ? fromValues[0] : "";
2201
+ const slash = from.indexOf("/");
2202
+ const fromName = slash > 0 ? from.slice(slash + 1) : "";
2203
+ const isCronJobRef = slash > 0 &&
2204
+ builtinKind(from.slice(0, slash)) === "cronjob" &&
2205
+ fromName.length > 0 &&
2206
+ !fromName.includes("/");
2207
+ if (!isCronJobRef) {
2208
+ return deny("kubectl create job may only re-run an existing CronJob: kubectl create job NAME --from=cronjob/NAME", "create job");
2209
+ }
2210
+ if (parsed.positionals.length > 3) {
2211
+ return deny("kubectl create job --from=cronjob/NAME takes one job NAME and no command (the CronJob's own spec runs)", "create job");
2212
+ }
2213
+ }
2214
+ }
2215
+ if (verb === "set") {
2216
+ if (subcommand === "serviceaccount" || subcommand === "sa") {
2217
+ return deny("kubectl set serviceaccount is never allowed for OneUptime AI: it changes the identity a workload's pods run as, and with it every permission and Secret they can reach", "set serviceaccount");
2218
+ }
2219
+ if (subcommand === "subject") {
2220
+ return deny("kubectl set subject is never allowed for OneUptime AI: adding users, groups or ServiceAccounts to a role binding is a privilege grant, not a fix", "set subject");
2221
+ }
2222
+ if (!SET_SUBCOMMANDS.has(subcommand)) {
2223
+ return deny(`kubectl set ${rawSubcommand || "(missing subcommand)"} is not allowed`, `set ${subcommand}`);
2224
+ }
2225
+ if (subcommand === "env") {
2226
+ for (const from of parsed.flags.get("from") || []) {
2227
+ if (CREDENTIAL_KINDS.has(normalizeKind(from.split("/")[0] || ""))) {
2228
+ return deny("kubectl set env --from=secret/... wires a Secret's keys into the workload's environment; OneUptime AI never attaches Secrets to workloads (set plain values, or --from=configmap/...)", "set env");
2229
+ }
2230
+ }
2231
+ }
2232
+ }
2233
+ // ---- Read tier -------------------------------------------------------
2234
+ if (READ_VERBS.has(verb)) {
2235
+ return allowed(KubectlCommandTier.Read, `kubectl ${verb} only reads the cluster`, verb);
2236
+ }
2237
+ if (verb === "cluster-info") {
2238
+ if (subcommand === "dump") {
2239
+ return deny("kubectl cluster-info dump exports the whole cluster; inspect specific resources instead", "cluster-info dump");
2240
+ }
2241
+ return allowed(KubectlCommandTier.Read, "kubectl cluster-info only reads the cluster", verb);
2242
+ }
2243
+ if (verb === "auth") {
2244
+ if (subcommand === "can-i" || subcommand === "whoami") {
2245
+ return allowed(KubectlCommandTier.Read, `kubectl auth ${subcommand} only reads the cluster`, `auth ${subcommand}`);
2246
+ }
2247
+ return deny(`kubectl auth ${subcommand || "(missing subcommand)"} is not allowed`, `auth ${subcommand}`);
2248
+ }
2249
+ if (verb === "rollout" &&
2250
+ (subcommand === "status" || subcommand === "history")) {
2251
+ return allowed(KubectlCommandTier.Read, `kubectl rollout ${subcommand} only reads the cluster`, `rollout ${subcommand}`);
2252
+ }
2253
+ // ---- Write tiers -----------------------------------------------------
2254
+ /*
2255
+ * --overrides decides what kubectl expose creates, so the command no
2256
+ * longer says it (see the header and OBJECT_OVERRIDE_FLAGS).
2257
+ */
2258
+ const overrideFlag = OBJECT_OVERRIDE_FLAGS.find((flag) => {
2259
+ return parsed.flags.has(flag);
2260
+ });
2261
+ if (overrideFlag !== undefined) {
2262
+ const label = SUBCOMMAND_VERBS.has(verb)
2263
+ ? `${verb} ${subcommand}`
2264
+ : verb;
2265
+ return deny(`kubectl ${label} with --${overrideFlag} is never allowed for OneUptime AI: --overrides (merged as --override-type says) replaces the object kubectl expose generates with whatever its JSON describes, of any kind and in any namespace (a ClusterRoleBinding, a PriorityClass, a Job running any image), so the command no longer says what it creates (write the Service kubectl expose makes with its own flags: --port, --target-port, --name, --type, --protocol)`, label);
2266
+ }
2267
+ if (hasAllNamespaces) {
2268
+ const label = verb === "rollout" ? `rollout ${subcommand}` : verb;
2269
+ return deny(`kubectl ${label} across all namespaces is not allowed`, label);
2270
+ }
2271
+ /*
2272
+ * A ClusterRole aggregation label names the grant it makes, so the
2273
+ * refusal names it too. Aggregation reads labels only; the same key as
2274
+ * an annotation is refused as a plain RBAC write below.
2275
+ */
2276
+ const clusterRoleAggregationKey = verb === "label" && targets.kinds.has("clusterrole")
2277
+ ? labelKeys(verb, parsed.positionals).find(isRbacAggregationKey)
2278
+ : undefined;
2279
+ if (OBJECT_VERBS.has(verb)) {
2280
+ for (const kind of targets.kinds) {
2281
+ if (RESOURCE_CATEGORIES.has(kind)) {
2282
+ return deny(`kubectl ${verb} on the resource category "${kind}" is never allowed for OneUptime AI: kubectl expands a category into every kind in it (api-extensions alone covers CRDs, APIServices and admission webhooks), so name the kind instead`, `${verb} ${kind}`);
2283
+ }
2284
+ // Deleting these is refused by NEVER_DELETE_KINDS, with its own reason.
2285
+ if (verb === "delete") {
2286
+ continue;
2287
+ }
2288
+ if (RBAC_KINDS.has(kind)) {
2289
+ if (clusterRoleAggregationKey) {
2290
+ return deny(`kubectl ${verb} of ${clusterRoleAggregationKey} on a ClusterRole is never allowed for OneUptime AI: it merges the role's rules into admin/edit/view and so grants them to everyone bound to those, a privilege grant, not a fix`, `${verb} clusterrole`);
2291
+ }
2292
+ return deny(`kubectl ${verb} on ${kind} objects is never allowed for OneUptime AI: roles and role bindings decide who may do what in the cluster, and changing them is a privilege grant, not a fix (a human makes RBAC changes)`, `${verb} ${kind}`);
2293
+ }
2294
+ if (ADMISSION_AND_API_EXTENSION_KINDS.has(kind)) {
2295
+ return deny(`kubectl ${verb} on ${kind} objects is never allowed for OneUptime AI: admission webhooks and policies, APIServices and CRDs decide what the API server admits and serves for the whole cluster, and changing one can switch a cluster control off as surely as deleting it (a human makes that change)`, `${verb} ${kind}`);
2296
+ }
2297
+ }
2298
+ }
2299
+ // Pod Security Admission's namespace labels, whichever namespaces they reach.
2300
+ if ((verb === "label" || verb === "annotate") &&
2301
+ targets.kinds.has("namespace")) {
2302
+ const podSecurityKey = labelKeys(verb, parsed.positionals).find(isPodSecurityKey);
2303
+ if (podSecurityKey) {
2304
+ return deny(`kubectl ${verb} of ${podSecurityKey} on a namespace is never allowed for OneUptime AI: pod-security.kubernetes.io keys are Pod Security Admission's controls, which decide whether privileged pods may run there`, `${verb} namespace`);
2305
+ }
2306
+ }
2307
+ /*
2308
+ * A write to Namespace objects must name each one. A selector, --all or
2309
+ * a bare kind reaches Namespace objects the command never names —
2310
+ * kube-system's among them — so the protected-namespace rule, which
2311
+ * reads the names, could not see it (see the header). Deleting a
2312
+ * Namespace is refused outright above (NEVER_DELETE_KINDS). Only the
2313
+ * built-in Namespace kind counts (builtinKind()): a custom resource that
2314
+ * borrows the name is judged by the namespace -n names.
2315
+ */
2316
+ if (verb !== "delete" &&
2317
+ targets.rawKinds.some((rawKind) => {
2318
+ return builtinKind(rawKind) === "namespace";
2319
+ }) &&
2320
+ (hasSelector || hasAll || targets.namedCount === 0)) {
2321
+ return deny(`kubectl ${verb} of Namespace objects ${hasSelector || hasAll
2322
+ ? "by a selector or --all"
2323
+ : "without naming any"} is never allowed for OneUptime AI: it can change kube-system's Namespace object (or another protected one) without naming it, so name each Namespace object (namespace/NAME)`, `${verb} namespace`);
2324
+ }
2325
+ if (verb === "rollout") {
2326
+ const rolloutVerb = `rollout ${subcommand}`;
2327
+ if (subcommand !== "restart" &&
2328
+ subcommand !== "undo" &&
2329
+ subcommand !== "pause" &&
2330
+ subcommand !== "resume") {
2331
+ return deny(`kubectl rollout ${subcommand || "(missing subcommand)"} is not allowed`, rolloutVerb);
2332
+ }
2333
+ if (hasSelector || hasAll) {
2334
+ return allowed(KubectlCommandTier.RiskyWrite, `kubectl ${rolloutVerb} with a selector or --all touches many workloads at once`, rolloutVerb);
2335
+ }
2336
+ if (targets.namedCount === 0) {
2337
+ return allowed(KubectlCommandTier.RiskyWrite, `kubectl ${rolloutVerb} names no workload, and kubectl reads a bare kind as every ${kindList || "workload"} in the namespace (name one: TYPE/NAME)`, rolloutVerb);
2338
+ }
2339
+ if (!isOneNamedObject(targets)) {
2340
+ return allowed(KubectlCommandTier.RiskyWrite, `kubectl ${rolloutVerb} names several workloads at once`, rolloutVerb);
2341
+ }
2342
+ if (!everyBuiltinKindIn(targets, ROLLOUT_SAFE_KINDS)) {
2343
+ return allowed(KubectlCommandTier.RiskyWrite, `kubectl ${rolloutVerb} on ${writtenKindList} is not a Deployment, StatefulSet or DaemonSet rollout`, rolloutVerb);
2344
+ }
2345
+ return allowed(KubectlCommandTier.SafeWrite, `kubectl ${rolloutVerb} of one named workload is a controller-managed, reversible change`, rolloutVerb);
2346
+ }
2347
+ if (verb === "delete") {
2348
+ if (hasAll) {
2349
+ return deny("kubectl delete --all is not allowed", "delete");
2350
+ }
2351
+ if (parsed.positionals.length < 2) {
2352
+ return deny("kubectl delete needs a resource kind and name", "delete");
2353
+ }
2354
+ for (const kind of targets.kinds) {
2355
+ if (NEVER_DELETE_KINDS.has(kind)) {
2356
+ return deny(`deleting ${kind} objects is never allowed for OneUptime AI`, "delete " + kind);
2357
+ }
2358
+ }
2359
+ const verbLabel = `delete ${kindList}`;
2360
+ if (targets.namedCount === 0 && !hasSelector) {
2361
+ return deny("kubectl delete needs the name of the object to delete (or a selector, which needs approval)", verbLabel);
2362
+ }
2363
+ if (!hasSelector &&
2364
+ !hasForce &&
2365
+ isOneNamedObject(targets) &&
2366
+ everyBuiltinKindIn(targets, SAFE_DELETE_KINDS)) {
2367
+ return allowed(KubectlCommandTier.SafeWrite, "deleting one named pod is a bounded change: its controller recreates it", verbLabel);
2368
+ }
2369
+ return allowed(KubectlCommandTier.RiskyWrite, hasForce
2370
+ ? "force-deleting skips graceful termination"
2371
+ : hasSelector
2372
+ ? "deleting by selector can remove many objects at once"
2373
+ : targets.namedCount > 1
2374
+ ? "deleting several objects at once"
2375
+ : targets.kinds.has("job")
2376
+ ? "a deleted Job is gone for good: no controller recreates it"
2377
+ : `deleting ${writtenKindList} objects changes what is deployed`, verbLabel);
2378
+ }
2379
+ if (verb === "scale") {
2380
+ if (hasAll || hasSelector) {
2381
+ return allowed(KubectlCommandTier.RiskyWrite, "kubectl scale with a selector or --all touches many objects at once", verb);
2382
+ }
2383
+ const replicas = parsed.flags.get("replicas") || [];
2384
+ if (replicas.length === 0) {
2385
+ return deny("kubectl scale needs --replicas", verb);
2386
+ }
2387
+ if (!isOneNamedObject(targets)) {
2388
+ return allowed(KubectlCommandTier.RiskyWrite, "kubectl scale names several workloads (or none) at once", verb);
2389
+ }
2390
+ if (!everyBuiltinKindIn(targets, SCALE_SAFE_KINDS)) {
2391
+ return allowed(KubectlCommandTier.RiskyWrite, `kubectl scale of ${writtenKindList} is not a safe change (only a Deployment, StatefulSet or ReplicaSet is)`, verb);
2392
+ }
2393
+ for (const value of replicas) {
2394
+ const count = value.trim();
2395
+ if (!REPLICA_COUNT_PATTERN.test(count)) {
2396
+ return allowed(KubectlCommandTier.RiskyWrite, `--replicas=${value} is not a replica count kubectl scale can apply safely`, verb);
2397
+ }
2398
+ if (parseInt(count, 10) === 0) {
2399
+ return allowed(KubectlCommandTier.RiskyWrite, "scaling to zero replicas stops the workload: an outage, not a reversible nudge", verb);
2400
+ }
2401
+ }
2402
+ return allowed(KubectlCommandTier.SafeWrite, "kubectl scale of one named workload to a non-zero count is a reversible change", verb);
2403
+ }
2404
+ if (verb === "cordon" || verb === "uncordon") {
2405
+ if (hasAll || hasSelector) {
2406
+ return allowed(KubectlCommandTier.RiskyWrite, `kubectl ${verb} with a selector or --all touches many nodes at once`, verb);
2407
+ }
2408
+ const nodes = parsed.positionals.slice(1);
2409
+ const node = nodes[0] || "";
2410
+ const namesOneNode = nodes.length === 1 &&
2411
+ (!node.includes("/") ||
2412
+ builtinKind(node.slice(0, node.indexOf("/"))) === "node");
2413
+ if (!namesOneNode) {
2414
+ return allowed(KubectlCommandTier.RiskyWrite, `kubectl ${verb} of anything but one named node touches several nodes (or none) at once`, verb);
2415
+ }
2416
+ return allowed(KubectlCommandTier.SafeWrite, `kubectl ${verb} of one node is a reversible change`, verb);
2417
+ }
2418
+ if (verb === "label" || verb === "annotate") {
2419
+ const keys = labelKeys(verb, parsed.positionals);
2420
+ if (hasAll || hasSelector) {
2421
+ return allowed(KubectlCommandTier.RiskyWrite, `kubectl ${verb} with a selector or --all touches many objects at once`, verb);
2422
+ }
2423
+ if (!isOneNamedObject(targets)) {
2424
+ return allowed(KubectlCommandTier.RiskyWrite, `kubectl ${verb} names several objects (or none) at once`, verb);
2425
+ }
2426
+ if (!everyBuiltinKindIn(targets, LABEL_SAFE_KINDS)) {
2427
+ return allowed(KubectlCommandTier.RiskyWrite, `${verb === "label" ? "labels" : "annotations"} on ${writtenKindList} can steer admission, scheduling, identity or traffic (only a pod or workload is a safe target)`, verb);
2428
+ }
2429
+ const reservedKey = keys.find(isReservedKey);
2430
+ if (reservedKey) {
2431
+ return allowed(KubectlCommandTier.RiskyWrite, `${reservedKey} is a key Kubernetes or a cluster controller acts on, not a plain ${verb === "label" ? "label" : "annotation"}`, verb);
2432
+ }
2433
+ return allowed(KubectlCommandTier.SafeWrite, `kubectl ${verb} of one named pod or workload is a reversible change`, verb);
2434
+ }
2435
+ if (verb === "patch") {
2436
+ const bodies = [
2437
+ ...(parsed.flags.get("p") || []),
2438
+ ...(parsed.flags.get("patch") || []),
2439
+ ];
2440
+ const patchTypes = readPatchTypes(parsed.flags.get("type") || []);
2441
+ for (const body of bodies) {
2442
+ const problem = findPatchBodyProblem(body, patchTypes);
2443
+ if (problem) {
2444
+ return deny(problem, "patch");
2445
+ }
2446
+ }
2447
+ }
2448
+ if (RISKY_WRITE_VERBS.has(verb)) {
2449
+ const verbLabel = verb === "set" || verb === "create" ? `${verb} ${subcommand}` : verb;
2450
+ return allowed(KubectlCommandTier.RiskyWrite, `kubectl ${verbLabel} can change what is deployed or affect many pods, so a human must approve it`, verbLabel);
2451
+ }
2452
+ return deny(`kubectl ${verb} is not a command OneUptime AI may run (for a word it does not know, kubectl would look for a kubectl-${verb} plugin on the Runner and run it)`, verb);
2453
+ }
2454
+ /*
2455
+ * The remediation verdict for one command under a cluster's settings.
2456
+ * Read and SafeWrite auto-approve; RiskyWrite auto-approves only when the
2457
+ * cluster bypasses approvals or the operator allowlisted its exact shape
2458
+ * (matchesAllowlist: token by token, see the allowlist section in the
2459
+ * header); Denied stays Denied; and a write in a protected namespace, a
2460
+ * node drain, a taint and a patch of a Node always need a human. Suggest
2461
+ * mode never consults this — everything there is RequiresApproval by
2462
+ * construction.
2463
+ */
2464
+ static evaluateForAutoExecution(data) {
2465
+ const result = KubectlPolicy.evaluateCommand(data.command);
2466
+ if (result.tier === KubectlCommandTier.Denied) {
2467
+ return {
2468
+ verdict: AiRemediationCommandPolicyVerdict.Denied,
2469
+ tier: result.tier,
2470
+ reason: `Denied by the kubectl command policy: ${result.reason}. This command cannot run even with human approval.`,
2471
+ };
2472
+ }
2473
+ if (result.tier === KubectlCommandTier.Read) {
2474
+ return {
2475
+ verdict: AiRemediationCommandPolicyVerdict.AutoApproved,
2476
+ tier: result.tier,
2477
+ reason: result.reason,
2478
+ };
2479
+ }
2480
+ /*
2481
+ * Before SafeWrite, bypass and the allowlist: nothing an operator set on
2482
+ * the cluster lets OneUptime AI change kube-system on its own.
2483
+ */
2484
+ if (result.protectedNamespace) {
2485
+ return {
2486
+ verdict: AiRemediationCommandPolicyVerdict.RequiresApproval,
2487
+ tier: result.tier,
2488
+ reason: `Requires human approval: ${result.reason}. Neither bypassing approvals nor the cluster's allowlist applies in ${result.protectedNamespace}.`,
2489
+ requiresHuman: true,
2490
+ };
2491
+ }
2492
+ // Nor does anything let it drain, taint or patch a node on its own.
2493
+ if (result.requiresHuman) {
2494
+ return {
2495
+ verdict: AiRemediationCommandPolicyVerdict.RequiresApproval,
2496
+ tier: result.tier,
2497
+ reason: `Requires human approval: ${result.reason}. Neither bypassing approvals nor the cluster's allowlist applies to a node drain or taint, or to a patch of a Node.`,
2498
+ requiresHuman: true,
2499
+ };
2500
+ }
2501
+ if (result.tier === KubectlCommandTier.SafeWrite) {
2502
+ return {
2503
+ verdict: AiRemediationCommandPolicyVerdict.AutoApproved,
2504
+ tier: result.tier,
2505
+ reason: result.reason,
2506
+ };
2507
+ }
2508
+ if (data.bypassApproval === true) {
2509
+ return {
2510
+ verdict: AiRemediationCommandPolicyVerdict.AutoApproved,
2511
+ tier: result.tier,
2512
+ reason: `Riskier change (${result.reason}) allowed without approval: the cluster bypasses approvals.`,
2513
+ };
2514
+ }
2515
+ if (KubectlPolicy.matchesAllowlist({
2516
+ args: result.args,
2517
+ allowlistPatterns: data.allowlistPatterns,
2518
+ })) {
2519
+ return {
2520
+ verdict: AiRemediationCommandPolicyVerdict.AutoApproved,
2521
+ tier: result.tier,
2522
+ reason: "Matched the cluster's kubectl allowlist.",
2523
+ };
2524
+ }
2525
+ return {
2526
+ verdict: AiRemediationCommandPolicyVerdict.RequiresApproval,
2527
+ tier: result.tier,
2528
+ reason: `Requires human approval: ${result.reason}.`,
2529
+ };
2530
+ }
2531
+ /*
2532
+ * Whether a cluster allowlist pattern names this argv (without the
2533
+ * leading "kubectl"), token by token — the semantics are spelled out in
2534
+ * the allowlist section of the header. Tier-blind on purpose: callers
2535
+ * (evaluateForAutoExecution) decide which tiers the allowlist may promote.
2536
+ */
2537
+ static matchesAllowlist(data) {
2538
+ const args = (data.args || []).filter((arg) => {
2539
+ return typeof arg === "string";
2540
+ });
2541
+ if (args.length === 0) {
2542
+ return false;
2543
+ }
2544
+ const patterns = (data.allowlistPatterns || [])
2545
+ .filter((pattern) => {
2546
+ return typeof pattern === "string" && pattern.trim().length > 0;
2547
+ })
2548
+ .slice(0, MAX_ALLOWLIST_PATTERNS);
2549
+ for (const pattern of patterns) {
2550
+ /*
2551
+ * An entry describeAllowlistPatternProblem refuses is skipped, so what
2552
+ * the matcher reads and what the server and the AI page accept are
2553
+ * one set — including an entry stored before a rule was added.
2554
+ */
2555
+ const patternArgs = KubectlPolicy.readAllowlistEntry(pattern).args;
2556
+ if (!patternArgs || patternArgs.length !== args.length) {
2557
+ continue;
2558
+ }
2559
+ const matches = patternArgs.every((patternToken, index) => {
2560
+ return allowlistTokenMatches(patternToken, args[index]);
2561
+ });
2562
+ if (matches) {
2563
+ return true;
2564
+ }
2565
+ }
2566
+ return false;
2567
+ }
2568
+ /*
2569
+ * Why an allowlist entry cannot work, in words for the person typing it —
2570
+ * or null when it is valid. This is the ONE definition of a valid entry
2571
+ * (see the allowlist section of the header): the server validates saves
2572
+ * with it, the AI page validates its form with it, and matchesAllowlist
2573
+ * skips every entry it refuses, so no entry is stored that the matcher
2574
+ * would silently ignore. (The entry count is checked by the callers
2575
+ * against KUBECTL_ALLOWLIST_MAX_PATTERNS.)
2576
+ */
2577
+ static describeAllowlistPatternProblem(pattern) {
2578
+ return KubectlPolicy.readAllowlistEntry(pattern).problem || null;
2579
+ }
2580
+ /*
2581
+ * Does this allowlist entry pre-approve riskier changes beyond the objects
2582
+ * it names? True when a `*` stands for the namespace, for an object the
2583
+ * command acts on, or for a selector or --from source — see the allowlist
2584
+ * section of the header. The AI page asks for an explicit confirmation
2585
+ * before saving a broad entry.
2586
+ *
2587
+ * The entry is read with the policy's own tokenizer and flag parser, the
2588
+ * way matchesAllowlist reads it (a leading "kubectl" is dropped once, in
2589
+ * any case), so every spelling of -n (`-n *`, `-n=*`, `--namespace=*`, a
2590
+ * cluster such as `-An *`) is seen, and a value flag's `*` (`-p *`,
2591
+ * `--replicas *`) is never mistaken for an object. An invalid entry is
2592
+ * never broad: it is refused before anyone could be asked to confirm it.
2593
+ */
2594
+ static isBroadAllowlistPattern(pattern) {
2595
+ const entry = KubectlPolicy.readAllowlistEntry(pattern);
2596
+ if (!entry.parsed) {
2597
+ return false;
2598
+ }
2599
+ const parsed = entry.parsed;
2600
+ const verb = parsed.positionals[0] || "";
2601
+ const subcommand = parsed.positionals[1] || "";
2602
+ /*
2603
+ * Reads, drains, taints and patches of a Node are never promoted: the
2604
+ * entry pre-approves nothing.
2605
+ */
2606
+ if (!allowlistMayPromote(parsed)) {
2607
+ return false;
2608
+ }
2609
+ for (const flag of WIDENING_FLAGS) {
2610
+ for (const value of parsed.flags.get(flag) || []) {
2611
+ if (value.includes("*")) {
2612
+ return true;
2613
+ }
2614
+ }
2615
+ }
2616
+ // A wildcard in create's positionals names the NEW object, not an existing one.
2617
+ if (verb === "create") {
2618
+ return false;
2619
+ }
2620
+ let operands = parsed.positionals.slice(SUBCOMMAND_VERBS.has(verb) ? 2 : 1);
2621
+ // kubectl set selector reads its LAST word as the selector expression.
2622
+ if (verb === "set" && subcommand === "selector") {
2623
+ operands = operands.slice(0, -1);
2624
+ }
2625
+ if (!readsUpdatePairs(verb, subcommand, parsed.flags)) {
2626
+ return operands.some(hasWildcard);
2627
+ }
2628
+ /*
2629
+ * label, annotate, set image and set env read their operands the way
2630
+ * kubectl's GetResourcesAndPairs does: objects first, then the updates
2631
+ * (KEY=VALUE or KEY-), and an object after an update is an error. So a
2632
+ * wildcard can stand for an object only before the first update, and
2633
+ * only when another word follows it: a wildcard that is the LAST word
2634
+ * is read either as the update or as one more object with no update at
2635
+ * all, which kubectl refuses ("at least one ... update is required").
2636
+ */
2637
+ for (let i = 0; i < operands.length; i++) {
2638
+ const operand = operands[i];
2639
+ if (isUpdatePairToken(operand)) {
2640
+ return false;
2641
+ }
2642
+ if (hasWildcard(operand) && i < operands.length - 1) {
2643
+ return true;
2644
+ }
2645
+ }
2646
+ return false;
2647
+ }
2648
+ /*
2649
+ * An allowlist entry read the way matchesAllowlist reads it: its argv
2650
+ * (the optional leading "kubectl" dropped by tokenize) and its parse when
2651
+ * it is valid, or the problem that makes it invalid.
2652
+ */
2653
+ static readAllowlistEntry(pattern) {
2654
+ if (typeof pattern !== "string" || pattern.trim().length === 0) {
2655
+ return { problem: "An allowlist entry cannot be blank." };
2656
+ }
2657
+ if (pattern.length > MAX_ALLOWLIST_PATTERN_LENGTH) {
2658
+ return {
2659
+ problem: `An allowlist entry can be at most ${MAX_ALLOWLIST_PATTERN_LENGTH} characters long.`,
2660
+ };
2661
+ }
2662
+ const shown = pattern.trim();
2663
+ const namesNoCommand = `"${shown}" names no kubectl command: write out the command it pre-approves, such as "kubectl set image deployment/web * -n web".`;
2664
+ const tokenized = KubectlPolicy.tokenize(pattern);
2665
+ if (!tokenized.args) {
2666
+ return {
2667
+ problem: tokenized.errorMessage === NO_VERB_MESSAGE
2668
+ ? namesNoCommand
2669
+ : `"${shown}" cannot be read as one kubectl command: ${tokenized.errorMessage || "it could not be split into words."}`,
2670
+ };
2671
+ }
2672
+ /*
2673
+ * One word after the optional "kubectl" can only match a one-word
2674
+ * command, and none is ever pre-approved: a read runs anyway, and every
2675
+ * write verb needs an object (and a change) to act on, so kubectl
2676
+ * refuses it bare. Quotes around a full command (a pasted JSON list, a
2677
+ * quoted line) make it one word too.
2678
+ */
2679
+ const quotedWords = `"${shown}" has quotes around several words where the kubectl verb goes, so they are read as one word (as in a pasted JSON list, or a full command in quotes). Write each entry on its own line without quotes or brackets, such as kubectl set image deployment/web * -n web.`;
2680
+ if (tokenized.args.length === 1) {
2681
+ return {
2682
+ problem: WHITESPACE_REGEX.test(tokenized.args[0])
2683
+ ? quotedWords
2684
+ : `"${shown}" is only one word after the optional "kubectl", so it could only match a one-word command, and a one-word command is never pre-approved (a read runs anyway; kubectl refuses a write verb with nothing to act on). Write out the full command it pre-approves, such as "kubectl set image deployment/web * -n web".`,
2685
+ };
2686
+ }
2687
+ const parsed = KubectlPolicy.parseArgs(tokenized.args);
2688
+ const verb = parsed.positionals[0];
2689
+ if (verb === undefined) {
2690
+ return { problem: namesNoCommand };
2691
+ }
2692
+ if (WHITESPACE_REGEX.test(verb)) {
2693
+ return { problem: quotedWords };
2694
+ }
2695
+ if (hasWildcard(verb)) {
2696
+ return {
2697
+ problem: `"${shown}" has a * where the kubectl verb goes. A * stands for exactly one word, and the first word is the verb (the leading "kubectl" is optional and never needs a wildcard), so write the verb out, as in "kubectl set image deployment/web * -n web".`,
2698
+ };
2699
+ }
2700
+ if (verb !== verb.toLowerCase()) {
2701
+ return {
2702
+ problem: `"${shown}" can never match a command that runs: kubectl matches commands case-sensitively, so "${verb}" is not kubectl ${verb.toLowerCase()} (write the verb in lowercase).`,
2703
+ };
2704
+ }
2705
+ if (!isVerbOneUptimeAiMayRun(verb)) {
2706
+ return {
2707
+ problem: `"${shown}" can never match a command that runs: kubectl ${verb} is not a command OneUptime AI may run.`,
2708
+ };
2709
+ }
2710
+ if (SUBCOMMAND_VERBS.has(verb)) {
2711
+ const subcommand = parsed.positionals[1];
2712
+ if (subcommand === undefined) {
2713
+ if (SUBCOMMAND_REQUIRED_VERBS.has(verb)) {
2714
+ return {
2715
+ problem: `"${shown}" names no kubectl ${verb} subcommand: write it out${subcommandExample(verb)}.`,
2716
+ };
2717
+ }
2718
+ }
2719
+ else if (hasWildcard(subcommand)) {
2720
+ return {
2721
+ problem: `"${shown}" has a * where the kubectl ${verb} subcommand goes: a * stands for exactly one word, and the subcommand decides what kind of change runs, so write it out${subcommandExample(verb)}.`,
2722
+ };
2723
+ }
2724
+ else if (subcommand !== subcommand.toLowerCase()) {
2725
+ return {
2726
+ problem: `"${shown}" can never match a command that runs: kubectl matches commands case-sensitively, so "${subcommand}" is not the kubectl ${verb} ${subcommand.toLowerCase()} command (write the subcommand in lowercase).`,
2727
+ };
2728
+ }
2729
+ }
2730
+ if (parsed.violation) {
2731
+ return {
2732
+ problem: `"${shown}" can never match a command that runs: ${parsed.violation}.`,
2733
+ };
2734
+ }
2735
+ /*
2736
+ * Refused by evaluateArgs rather than by the parser (see
2737
+ * OBJECT_OVERRIDE_FLAGS), so every command such an entry could match is
2738
+ * Denied all the same.
2739
+ */
2740
+ const overrideFlag = OBJECT_OVERRIDE_FLAGS.find((flag) => {
2741
+ return parsed.flags.has(flag);
2742
+ });
2743
+ if (overrideFlag !== undefined) {
2744
+ return {
2745
+ problem: `"${shown}" can never match a command that runs: the --${overrideFlag} flag is never allowed for OneUptime AI, because --overrides lets kubectl expose create an object of any kind, in any namespace, instead of the Service the command names.`,
2746
+ };
2747
+ }
2748
+ return { args: tokenized.args, parsed };
2749
+ }
2750
+ static isReadOnly(command) {
2751
+ return (KubectlPolicy.evaluateCommand(command).tier === KubectlCommandTier.Read);
2752
+ }
2753
+ /*
2754
+ * Render an argv back to the one-line form humans read on approval cards
2755
+ * and in the activity feed. Tokens that would not survive a shell split
2756
+ * are single-quoted, so the rendering round-trips through tokenize().
2757
+ */
2758
+ static renderDisplayCommand(args) {
2759
+ const rendered = ["kubectl"];
2760
+ for (const arg of args) {
2761
+ if (arg === "") {
2762
+ rendered.push("''");
2763
+ }
2764
+ else if (SHELL_SAFE_TOKEN.test(arg)) {
2765
+ rendered.push(arg);
2766
+ }
2767
+ else {
2768
+ rendered.push(`'${arg.replace(/'/g, `'\\''`)}'`);
2769
+ }
2770
+ }
2771
+ return rendered.join(" ");
2772
+ }
2773
+ /*
2774
+ * What a flag name means here: its arity, and whether it may be used at
2775
+ * all. `verb` is the first positional seen so far (undefined before it),
2776
+ * for the few flags whose meaning depends on it.
2777
+ */
2778
+ static lookupFlag(name, verb) {
2779
+ var _a;
2780
+ const override = verb !== undefined
2781
+ ? (_a = VERB_FLAG_OVERRIDE_ARITY.get(verb)) === null || _a === void 0 ? void 0 : _a.get(name)
2782
+ : undefined;
2783
+ if (override) {
2784
+ return { arity: override };
2785
+ }
2786
+ const denyReason = DENIED_FLAG_REASONS.get(name);
2787
+ if (denyReason) {
2788
+ return {
2789
+ arity: FlagArity.Boolean,
2790
+ problem: `is not allowed: ${denyReason}`,
2791
+ };
2792
+ }
2793
+ const arity = KNOWN_FLAG_ARITY.get(name);
2794
+ if (arity) {
2795
+ return { arity };
2796
+ }
2797
+ return {
2798
+ arity: FlagArity.Boolean,
2799
+ problem: "is not a kubectl flag OneUptime AI may use (an unknown flag could hide the verb or the resource behind its value, so it is refused rather than guessed)",
2800
+ };
2801
+ }
2802
+ // Streaming flags may only ever be switched off explicitly.
2803
+ static findStreamingFlag(flags) {
2804
+ for (const name of STREAMING_FLAGS) {
2805
+ const values = flags.get(name);
2806
+ if (!values) {
2807
+ continue;
2808
+ }
2809
+ for (const value of values) {
2810
+ if (value !== "false") {
2811
+ const shown = name.length === 1 ? `-${name}` : `--${name}`;
2812
+ return `the ${shown} flag streams until kubectl is killed; OneUptime AI reads a bounded snapshot (${shown}=false is fine)`;
2813
+ }
2814
+ }
2815
+ }
2816
+ return null;
2817
+ }
2818
+ // Every -o/--output value must be an inline format kubectl prints itself.
2819
+ static findOutputFormatProblem(flags) {
2820
+ const values = [
2821
+ ...(flags.get("o") || []),
2822
+ ...(flags.get("output") || []),
2823
+ ];
2824
+ for (const value of values) {
2825
+ const lower = value.toLowerCase();
2826
+ const eq = lower.indexOf("=");
2827
+ const format = eq >= 0 ? lower.slice(0, eq) : lower;
2828
+ if (FILE_OUTPUT_FORMATS.has(format)) {
2829
+ return `the output format "${value}" makes kubectl read a file on the Runner and echo it; write the template inline (-o jsonpath=..., -o go-template=..., -o custom-columns=...)`;
2830
+ }
2831
+ /*
2832
+ * A template format without its template would take it from
2833
+ * --template, which is Denied, so the bare form can never run.
2834
+ */
2835
+ if (OUTPUT_FORMATS_WITH_ARGUMENT.has(format)) {
2836
+ if (eq < 0) {
2837
+ return `the output format "${value}" needs its template inline: -o ${format}=... (--template is not allowed)`;
2838
+ }
2839
+ continue;
2840
+ }
2841
+ if (eq >= 0 || !OUTPUT_FORMATS.has(format)) {
2842
+ return `the output format "${value}" is not one OneUptime AI may use (json, yaml, name, wide, jsonpath=..., go-template=..., custom-columns=...)`;
2843
+ }
2844
+ }
2845
+ return null;
2846
+ }
2847
+ /*
2848
+ * Split an argv into positionals and flags exactly as pflag will (see the
2849
+ * Flags section above). Never throws and never stops early: it records the
2850
+ * first problem and keeps going, so the caller can still name the verb.
2851
+ */
2852
+ static parseArgs(args) {
2853
+ const positionals = [];
2854
+ const flags = new Map();
2855
+ const problems = [];
2856
+ let verb = undefined;
2857
+ let subcommand = undefined;
2858
+ let afterDoubleDash = false;
2859
+ const record = (name, value) => {
2860
+ const existing = flags.get(name) || [];
2861
+ existing.push(value);
2862
+ flags.set(name, existing);
2863
+ };
2864
+ /*
2865
+ * True once the positionals name the command kubectl will run: the verb,
2866
+ * plus its subcommand for SUBCOMMAND_VERBS. Until then only GLOBAL_FLAGS
2867
+ * may appear (see the Flags section: kubectl picks the command first and
2868
+ * would take the word after any other flag as that flag's value).
2869
+ */
2870
+ const commandFound = () => {
2871
+ return (verb !== undefined &&
2872
+ (!SUBCOMMAND_VERBS.has(verb) || subcommand !== undefined));
2873
+ };
2874
+ const orderingProblem = (name, shown) => {
2875
+ if (commandFound() || GLOBAL_FLAGS.has(name)) {
2876
+ return null;
2877
+ }
2878
+ const after = verb === undefined ? "the verb" : `the kubectl ${verb} subcommand`;
2879
+ return `the ${shown} flag must come after ${after}: kubectl picks the command before it parses flags and would take the word after this flag as its value`;
2880
+ };
2881
+ for (let i = 0; i < args.length; i++) {
2882
+ const token = args[i];
2883
+ if (afterDoubleDash || !token.startsWith("-") || token === "-") {
2884
+ positionals.push(token);
2885
+ if (verb === undefined) {
2886
+ verb = token.toLowerCase();
2887
+ }
2888
+ else if (subcommand === undefined) {
2889
+ subcommand = token.toLowerCase();
2890
+ }
2891
+ continue;
2892
+ }
2893
+ if (token === "--") {
2894
+ if (!commandFound()) {
2895
+ problems.push(`"--" must come after the verb`);
2896
+ }
2897
+ afterDoubleDash = true;
2898
+ continue;
2899
+ }
2900
+ if (token.startsWith("--")) {
2901
+ const eq = token.indexOf("=");
2902
+ const rawName = eq >= 0 ? token.slice(2, eq) : token.slice(2);
2903
+ const name = normalizeKubectlFlagName(rawName);
2904
+ if (!name || name.startsWith("-")) {
2905
+ problems.push(`"${token}" is not valid flag syntax`);
2906
+ continue;
2907
+ }
2908
+ const rule = KubectlPolicy.lookupFlag(name, verb);
2909
+ const ordering = orderingProblem(name, `--${rawName}`);
2910
+ if (rule.problem) {
2911
+ problems.push(`the --${rawName} flag ${rule.problem}`);
2912
+ }
2913
+ else if (ordering) {
2914
+ problems.push(ordering);
2915
+ }
2916
+ if (eq >= 0) {
2917
+ record(name, token.slice(eq + 1));
2918
+ }
2919
+ else if (rule.arity === FlagArity.Value && i + 1 < args.length) {
2920
+ record(name, args[i + 1]);
2921
+ i++;
2922
+ }
2923
+ else {
2924
+ record(name, "");
2925
+ }
2926
+ continue;
2927
+ }
2928
+ // "-abc": a cluster of short flags, read letter by letter like pflag.
2929
+ let rest = token.slice(1);
2930
+ while (rest.length > 0) {
2931
+ const letter = rest.charAt(0);
2932
+ const rule = KubectlPolicy.lookupFlag(letter, verb);
2933
+ const where = token === `-${letter}` || token.startsWith(`-${letter}=`)
2934
+ ? ""
2935
+ : ` (in "${token}")`;
2936
+ const ordering = orderingProblem(letter, `-${letter}${where}`);
2937
+ if (rule.problem) {
2938
+ problems.push(`the -${letter} flag${where} ${rule.problem}`);
2939
+ }
2940
+ else if (ordering) {
2941
+ problems.push(ordering);
2942
+ }
2943
+ // "-n=web"
2944
+ if (rest.charAt(1) === "=") {
2945
+ record(letter, rest.slice(2));
2946
+ break;
2947
+ }
2948
+ // A boolean (or optional-value) letter: the next letter is another flag.
2949
+ if (rule.arity !== FlagArity.Value) {
2950
+ record(letter, "");
2951
+ rest = rest.slice(1);
2952
+ continue;
2953
+ }
2954
+ // "-nweb"
2955
+ if (rest.length > 1) {
2956
+ record(letter, rest.slice(1));
2957
+ break;
2958
+ }
2959
+ // "-n web"
2960
+ if (i + 1 < args.length) {
2961
+ record(letter, args[i + 1]);
2962
+ i++;
2963
+ }
2964
+ else {
2965
+ record(letter, "");
2966
+ }
2967
+ break;
2968
+ }
2969
+ }
2970
+ return { positionals, flags, violation: problems[0] };
2971
+ }
2972
+ }
2973
+ //# sourceMappingURL=KubectlPolicy.js.map