@oneuptime/common 14.0.0 → 14.0.2

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 (1270) hide show
  1. package/Models/DatabaseModels/AlertEpisodeMember.ts +8 -1
  2. package/Models/DatabaseModels/AutoRemediationSuggestion.ts +63 -0
  3. package/Models/DatabaseModels/IncidentEpisodeMember.ts +8 -1
  4. package/Models/DatabaseModels/IncidentEpisodePublicNote.ts +9 -2
  5. package/Models/DatabaseModels/IncidentPublicNote.ts +9 -2
  6. package/Models/DatabaseModels/Index.ts +4 -0
  7. package/Models/DatabaseModels/KubernetesCluster.ts +429 -0
  8. package/Models/DatabaseModels/Monitor.ts +48 -0
  9. package/Models/DatabaseModels/Runner.ts +5 -4
  10. package/Models/DatabaseModels/RunnerJob.ts +66 -0
  11. package/Models/DatabaseModels/ScheduledMaintenancePublicNote.ts +10 -2
  12. package/Models/DatabaseModels/ServiceLevelObjectiveFeed.ts +2 -0
  13. package/Models/DatabaseModels/ServiceLevelObjectiveLabelRule.ts +522 -0
  14. package/Models/DatabaseModels/ServiceLevelObjectiveMonitorRule.ts +38 -4
  15. package/Models/DatabaseModels/ServiceLevelObjectiveOwnerRule.ts +603 -0
  16. package/Models/DatabaseModels/WorkflowVariable.ts +479 -2
  17. package/Models/DatabaseModels/WorkspaceProjectAuthToken.ts +79 -25
  18. package/Server/API/AIInvestigationAPI.ts +341 -0
  19. package/Server/API/AutoRemediationAPI.ts +184 -2
  20. package/Server/API/CommonAPI.ts +70 -0
  21. package/Server/API/KubernetesClusterAiAccessAPI.ts +793 -0
  22. package/Server/API/MicrosoftTeamsAPI.ts +770 -315
  23. package/Server/API/MonitorAPI.ts +140 -0
  24. package/Server/API/OnCallScheduleTimelineAPI.ts +5 -21
  25. package/Server/API/SlackAPI.ts +447 -99
  26. package/Server/API/StatusPageAPI.ts +146 -26
  27. package/Server/API/TelemetryAPI.ts +216 -5
  28. package/Server/API/UserTwoFactorBackupCodeAPI.ts +1 -0
  29. package/Server/API/WorkflowVariableAPI.ts +156 -0
  30. package/Server/Infrastructure/GlobalCache.ts +35 -0
  31. package/Server/Infrastructure/Postgres/SchemaMigrations/1794100000000-AddSloLabelAndOwnerRules.ts +248 -0
  32. package/Server/Infrastructure/Postgres/SchemaMigrations/1794200000000-AddSloMonitorRuleMonitorType.ts +19 -0
  33. package/Server/Infrastructure/Postgres/SchemaMigrations/1794300000000-AddOAuth2WorkflowVariables.ts +97 -0
  34. package/Server/Infrastructure/Postgres/SchemaMigrations/1794400000000-AddKubernetesClusterAiAccess.ts +129 -0
  35. package/Server/Infrastructure/Postgres/SchemaMigrations/1794500000000-AddIncomingEmailCustomAddressToMonitor.ts +25 -0
  36. package/Server/Infrastructure/Postgres/SchemaMigrations/1794600000000-AddAuthTokenExpiresAtToWorkspaceProjectAuthToken.ts +20 -0
  37. package/Server/Infrastructure/Postgres/SchemaMigrations/1794700000000-RemoveAppAccessTokenFromWorkspaceProjectAuthTokenMiscData.ts +38 -0
  38. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +14 -0
  39. package/Server/Middleware/MasterAdminAuthorization.ts +28 -0
  40. package/Server/Middleware/TelemetryIngest.ts +47 -2
  41. package/Server/Middleware/UserAuthorization.ts +56 -2
  42. package/Server/Services/AIAgentService.ts +1 -0
  43. package/Server/Services/AccessTokenService.ts +121 -48
  44. package/Server/Services/AlertEpisodeMemberService.ts +9 -0
  45. package/Server/Services/AlertEpisodeService.ts +14 -1
  46. package/Server/Services/AlertService.ts +134 -22
  47. package/Server/Services/AutoRemediationRuleEngineService.ts +968 -39
  48. package/Server/Services/AutoRemediationRuleService.ts +118 -0
  49. package/Server/Services/BillingService.ts +1 -0
  50. package/Server/Services/DatabaseService.ts +10 -0
  51. package/Server/Services/InboundEmail/Providers/SendGridInboundProvider.ts +16 -22
  52. package/Server/Services/IncidentEpisodeMemberService.ts +9 -0
  53. package/Server/Services/IncidentEpisodePublicNoteService.ts +66 -0
  54. package/Server/Services/IncidentEpisodeRoleMemberService.ts +27 -0
  55. package/Server/Services/IncidentEpisodeService.ts +14 -1
  56. package/Server/Services/IncidentGroupingEngineService.ts +11 -0
  57. package/Server/Services/IncidentMemberService.ts +21 -0
  58. package/Server/Services/IncidentPublicNoteService.ts +63 -0
  59. package/Server/Services/IncidentService.ts +120 -20
  60. package/Server/Services/IncidentStateTimelineService.ts +15 -0
  61. package/Server/Services/IncidentTemplateService.ts +83 -3
  62. package/Server/Services/Index.ts +4 -0
  63. package/Server/Services/KubernetesClusterAiAccessService.ts +1943 -0
  64. package/Server/Services/KubernetesClusterService.ts +1570 -1
  65. package/Server/Services/LogAggregationService.ts +14 -6
  66. package/Server/Services/MonitorService.ts +654 -54
  67. package/Server/Services/MonitorStatusTimelineService.ts +639 -2
  68. package/Server/Services/OnCallDutyPolicyEscalationRuleScheduleService.ts +2 -0
  69. package/Server/Services/OnCallDutyPolicyEscalationRuleTeamService.ts +2 -0
  70. package/Server/Services/OnCallDutyPolicyEscalationRuleUserService.ts +2 -0
  71. package/Server/Services/OnCallDutyPolicyScheduleService.ts +3 -0
  72. package/Server/Services/OnCallNotificationAlertingService.ts +36 -12
  73. package/Server/Services/OnCallSetupReminderService.ts +1 -0
  74. package/Server/Services/ProbeService.ts +7 -1
  75. package/Server/Services/ProjectService.ts +11 -1
  76. package/Server/Services/RunbookCredentialService.ts +26 -1
  77. package/Server/Services/RunbookSecretService.ts +36 -0
  78. package/Server/Services/RunnerJobService.ts +941 -23
  79. package/Server/Services/RunnerService.ts +439 -6
  80. package/Server/Services/ScheduledMaintenancePublicNoteService.ts +66 -0
  81. package/Server/Services/ScheduledMaintenanceService.ts +124 -19
  82. package/Server/Services/ScheduledMaintenanceTemplateService.ts +82 -3
  83. package/Server/Services/ServiceLevelObjectiveLabelRuleEngineService.ts +385 -0
  84. package/Server/Services/ServiceLevelObjectiveLabelRuleService.ts +51 -0
  85. package/Server/Services/ServiceLevelObjectiveMonitorRuleEngineService.ts +92 -16
  86. package/Server/Services/ServiceLevelObjectiveMonitorRuleService.ts +36 -1
  87. package/Server/Services/ServiceLevelObjectiveOwnerRuleEngineService.ts +521 -0
  88. package/Server/Services/ServiceLevelObjectiveOwnerRuleService.ts +51 -0
  89. package/Server/Services/ServiceLevelObjectiveService.ts +42 -1
  90. package/Server/Services/StatusPagePrivateUserService.ts +1 -0
  91. package/Server/Services/StatusPageService.ts +301 -74
  92. package/Server/Services/StatusPageSubscriberService.ts +4 -0
  93. package/Server/Services/TeamMemberService.ts +309 -7
  94. package/Server/Services/TraceAggregationService.ts +10 -6
  95. package/Server/Services/UserEmailService.ts +1 -0
  96. package/Server/Services/UserNotificationMethodAdminService.ts +1 -0
  97. package/Server/Services/UserNotificationRuleAdminService.ts +1 -0
  98. package/Server/Services/UserNotificationRuleService.ts +4 -0
  99. package/Server/Services/UserService.ts +122 -1
  100. package/Server/Services/WorkflowVariableService.ts +593 -8
  101. package/Server/Services/WorkspaceNotificationRuleService.ts +588 -8
  102. package/Server/Services/WorkspaceProjectAuthTokenService.ts +170 -1
  103. package/Server/Types/Database/QueryHelper.ts +22 -0
  104. package/Server/Types/Markdown.ts +502 -27
  105. package/Server/Types/Workflow/Components/Telegram/SendMessageToChat.ts +27 -1
  106. package/Server/Utils/AI/ClusterAccess/ClusterAccessContext.ts +182 -0
  107. package/Server/Utils/AI/ClusterAccess/KubectlInvestigationToolkit.ts +525 -0
  108. package/Server/Utils/AI/ClusterAccess/KubectlJobRunner.ts +854 -0
  109. package/Server/Utils/AI/CodeFix/CodeFixAgentAuth.ts +22 -2
  110. package/Server/Utils/AI/Remediation/RemediationCommandTools.ts +1916 -307
  111. package/Server/Utils/AI/Remediation/RemediationExecutionRunner.ts +1601 -74
  112. package/Server/Utils/AI/SRE/AIInvestigationEngine.ts +139 -7
  113. package/Server/Utils/AI/SRE/AlertInvestigationRunner.ts +58 -1
  114. package/Server/Utils/AI/SRE/IncidentInvestigationRunner.ts +54 -1
  115. package/Server/Utils/AI/Toolbox/AIActionTools.ts +14 -6
  116. package/Server/Utils/AI/Toolbox/ResourceTools.ts +4 -2
  117. package/Server/Utils/AI/Toolbox/SloTools.ts +1 -0
  118. package/Server/Utils/AutoRemediation/CommandPlanExecutor.ts +1341 -150
  119. package/Server/Utils/AutoRemediation/RemediationVerifier.ts +375 -4
  120. package/Server/Utils/Database/AffectedResourceRelations.ts +127 -0
  121. package/Server/Utils/Database/ProjectScopedReferenceValidator.ts +240 -1
  122. package/Server/Utils/EmailRollup/EmailRollupFlushRunner.ts +1 -0
  123. package/Server/Utils/Monitor/AffectedResourceList.ts +31 -73
  124. package/Server/Utils/Monitor/Criteria/CompareCriteria.ts +1 -1
  125. package/Server/Utils/Monitor/Criteria/MetricMonitorCriteria.ts +1 -1
  126. package/Server/Utils/Monitor/MonitorAlert.ts +83 -9
  127. package/Server/Utils/Monitor/MonitorCriteriaEvaluator.ts +181 -136
  128. package/Server/Utils/Monitor/MonitorCriteriaObservationBuilder.ts +5 -1
  129. package/Server/Utils/Monitor/MonitorIncident.ts +104 -9
  130. package/Server/Utils/Monitor/MonitorPayloadRedaction.ts +124 -7
  131. package/Server/Utils/Monitor/ProbeMonitorsNotification.ts +407 -0
  132. package/Server/Utils/Monitor/RootCauseList.ts +139 -0
  133. package/Server/Utils/OnCall/OnCallShiftReminderRunner.ts +1 -0
  134. package/Server/Utils/PushNotificationUtil.ts +45 -0
  135. package/Server/Utils/Rules/OwnerRuleAssignment.ts +40 -3
  136. package/Server/Utils/Rules/RuleRun/RuleRunRegistry.ts +28 -0
  137. package/Server/Utils/Runbook/RunbookExecutePermission.ts +56 -6
  138. package/Server/Utils/SessionReplay/SessionReplayReadService.ts +223 -33
  139. package/Server/Utils/SessionReplay/SessionReplayUserFlowReadService.ts +559 -0
  140. package/Server/Utils/Slo/SloRulePatternValidator.ts +42 -0
  141. package/Server/Utils/StartServer.ts +4 -3
  142. package/Server/Utils/TeamMember/ProjectLeaveResourceCleanup.ts +528 -0
  143. package/Server/Utils/TwoFactorBackupCodeNotification.ts +1 -0
  144. package/Server/Utils/UserPermission/UserPermission.ts +16 -0
  145. package/Server/Utils/Workflow/OAuth2TokenClient.ts +704 -0
  146. package/Server/Utils/Workflow/WorkflowVariableOAuthToken.ts +318 -0
  147. package/Server/Utils/Workspace/MicrosoftTeams/Actions/Alert.ts +47 -7
  148. package/Server/Utils/Workspace/MicrosoftTeams/Actions/AlertEpisode.ts +57 -16
  149. package/Server/Utils/Workspace/MicrosoftTeams/Actions/Incident.ts +193 -214
  150. package/Server/Utils/Workspace/MicrosoftTeams/Actions/IncidentEpisode.ts +57 -13
  151. package/Server/Utils/Workspace/MicrosoftTeams/Actions/Monitor.ts +54 -17
  152. package/Server/Utils/Workspace/MicrosoftTeams/Actions/ScheduledMaintenance.ts +179 -161
  153. package/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.ts +281 -167
  154. package/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsServiceUrl.ts +114 -0
  155. package/Server/Utils/Workspace/MicrosoftTeams/ReactionNoteSync.ts +895 -0
  156. package/Server/Utils/Workspace/Slack/Actions/ActionTypes.ts +7 -9
  157. package/Server/Utils/Workspace/Slack/Actions/Alert.ts +96 -227
  158. package/Server/Utils/Workspace/Slack/Actions/AlertEpisode.ts +93 -214
  159. package/Server/Utils/Workspace/Slack/Actions/Auth.ts +30 -3
  160. package/Server/Utils/Workspace/Slack/Actions/Authorization.ts +99 -0
  161. package/Server/Utils/Workspace/Slack/Actions/Incident.ts +117 -283
  162. package/Server/Utils/Workspace/Slack/Actions/IncidentEpisode.ts +101 -196
  163. package/Server/Utils/Workspace/Slack/Actions/ReactionNote.ts +329 -0
  164. package/Server/Utils/Workspace/Slack/Actions/ScheduledMaintenance.ts +111 -287
  165. package/Server/Utils/Workspace/Slack/Slack.ts +86 -17
  166. package/Server/Utils/Workspace/Slack/app-manifest.json +2 -0
  167. package/Server/Utils/Workspace/Workspace.ts +171 -54
  168. package/Server/Utils/Workspace/WorkspaceActionAuthorization.ts +252 -0
  169. package/Server/Utils/Workspace/WorkspaceBase.ts +39 -0
  170. package/Server/Utils/Workspace/WorkspaceOAuthState.ts +280 -0
  171. package/Server/Utils/Workspace/WorkspaceProjectReferenceValidator.ts +96 -0
  172. package/Server/Utils/Workspace/WorkspaceReactionNote.ts +620 -0
  173. package/Tests/App/Dashboard/AttributesJSONDashboardSurfaces.test.tsx +496 -0
  174. package/Tests/App/Dashboard/AutoRemediationRulesTableCommandRunners.test.tsx +152 -0
  175. package/Tests/App/Dashboard/BreadcrumbCoverage.test.tsx +32 -0
  176. package/Tests/App/Dashboard/ClusterAccessNotice.test.tsx +794 -0
  177. package/Tests/App/Dashboard/CreateOAuthWorkflowVariableModal.test.tsx +840 -0
  178. package/Tests/App/Dashboard/CreateWorkflowModal.test.tsx +653 -0
  179. package/Tests/App/Dashboard/DatabaseMonitorStepForm.test.tsx +197 -0
  180. package/Tests/App/Dashboard/DatabaseMonitorView.test.tsx +376 -0
  181. package/Tests/App/Dashboard/DisabledWarningRobustness.test.tsx +262 -0
  182. package/Tests/App/Dashboard/EventNotes.test.tsx +2080 -0
  183. package/Tests/App/Dashboard/EventNotesPages.test.tsx +486 -0
  184. package/Tests/App/Dashboard/EventNotesUtil.test.ts +933 -0
  185. package/Tests/App/Dashboard/ExceptionMonitorEnvironmentFilter.test.tsx +218 -0
  186. package/Tests/App/Dashboard/FeedFilterSortIntegration.test.tsx +1632 -0
  187. package/Tests/App/Dashboard/FeedOptionsLocales.test.ts +250 -0
  188. package/Tests/App/Dashboard/FeedOrdering.test.ts +279 -9
  189. package/Tests/App/Dashboard/IncidentChangeStateNotifyDefault.test.tsx +665 -0
  190. package/Tests/App/Dashboard/IncidentEpisodeFeedPublicNoteNotifyDefault.test.tsx +494 -0
  191. package/Tests/App/Dashboard/IncidentEpisodeOverviewNotifyDefault.test.tsx +706 -0
  192. package/Tests/App/Dashboard/IncidentFeedPublicNoteNotifyDefault.test.tsx +472 -0
  193. package/Tests/App/Dashboard/IncidentOverviewNotifyDefault.test.tsx +858 -0
  194. package/Tests/App/Dashboard/IncomingEmailAddressSettings.test.tsx +567 -0
  195. package/Tests/App/Dashboard/InvestigationClusterToolFormat.test.ts +241 -0
  196. package/Tests/App/Dashboard/InvestigationEvidenceKubectl.test.tsx +322 -0
  197. package/Tests/App/Dashboard/InvestigationFeedRefresh.test.tsx +60 -1
  198. package/Tests/App/Dashboard/InvestigationPanel.test.tsx +606 -3
  199. package/Tests/App/Dashboard/InvestigationPanelClusterAccess.test.tsx +476 -0
  200. package/Tests/App/Dashboard/InvestigationRunDetailsKubectl.test.tsx +383 -0
  201. package/Tests/App/Dashboard/KubectlActivitySummary.test.tsx +366 -0
  202. package/Tests/App/Dashboard/KubernetesClusterAiAccessSettings.test.ts +2886 -0
  203. package/Tests/App/Dashboard/KubernetesClusterAiPage.test.tsx +2688 -0
  204. package/Tests/App/Dashboard/KubernetesClusterAiPageServerParity.test.ts +915 -0
  205. package/Tests/App/Dashboard/LayerDateTimeFieldTimezoneName.test.tsx +66 -0
  206. package/Tests/App/Dashboard/LogMonitorPreview.test.tsx +174 -0
  207. package/Tests/App/Dashboard/MonitorFeedRefresh.test.tsx +279 -0
  208. package/Tests/App/Dashboard/MonitorMetricQueryConfig.test.ts +244 -0
  209. package/Tests/App/Dashboard/MonitorOpenWorkCard.test.tsx +381 -0
  210. package/Tests/App/Dashboard/MonitorOpenWorkHook.test.tsx +784 -0
  211. package/Tests/App/Dashboard/MonitorOverviewData.test.tsx +2199 -0
  212. package/Tests/App/Dashboard/MonitorOverviewHero.test.tsx +1169 -0
  213. package/Tests/App/Dashboard/MonitorOverviewInput.test.ts +1127 -0
  214. package/Tests/App/Dashboard/MonitorOverviewPage.test.tsx +2136 -0
  215. package/Tests/App/Dashboard/MonitorOverviewSelectReadable.test.ts +368 -0
  216. package/Tests/App/Dashboard/MonitorOverviewStatBar.test.tsx +526 -0
  217. package/Tests/App/Dashboard/MonitorOverviewSupportingCards.test.tsx +542 -0
  218. package/Tests/App/Dashboard/MonitorOwnersCombine.test.ts +299 -0
  219. package/Tests/App/Dashboard/MonitorProbesCard.test.tsx +602 -0
  220. package/Tests/App/Dashboard/MonitorResponseTimeCard.test.tsx +386 -0
  221. package/Tests/App/Dashboard/MonitorSetupAndConnectionCards.test.tsx +612 -0
  222. package/Tests/App/Dashboard/MonitorStatusChangesCard.test.tsx +257 -0
  223. package/Tests/App/Dashboard/MonitorSummaryTestMonitorButton.test.tsx +360 -1
  224. package/Tests/App/Dashboard/MonitorUptimeHistoryCard.test.tsx +835 -0
  225. package/Tests/App/Dashboard/MonitorUptimeSummaryHook.test.tsx +971 -0
  226. package/Tests/App/Dashboard/MonitorViewLayout.test.tsx +580 -0
  227. package/Tests/App/Dashboard/OnCallLayerRestrictionTimesPreserved.test.tsx +441 -0
  228. package/Tests/App/Dashboard/OnCallNavbar.test.tsx +214 -0
  229. package/Tests/App/Dashboard/OnCallSchedulePreviewCalendarDisplay.test.tsx +1389 -0
  230. package/Tests/App/Dashboard/OnCallSchedulePreviewOverrides.test.tsx +205 -1
  231. package/Tests/App/Dashboard/OnCallScheduleTimeInputsSettingsZone.test.tsx +198 -0
  232. package/Tests/App/Dashboard/ProductOrientation.test.tsx +646 -0
  233. package/Tests/App/Dashboard/PublicNotePagesNotifyDefault.test.tsx +524 -0
  234. package/Tests/App/Dashboard/RemediationSuggestionCardApproval.test.tsx +702 -0
  235. package/Tests/App/Dashboard/RemoveUserFromProject.test.tsx +427 -0
  236. package/Tests/App/Dashboard/ResourceArchiveSettings.test.tsx +4 -0
  237. package/Tests/App/Dashboard/ResourceFeed.test.tsx +612 -2
  238. package/Tests/App/Dashboard/ResourceFeedPageWiring.test.ts +30 -0
  239. package/Tests/App/Dashboard/ResourceFeedPagesFilterSort.test.tsx +1202 -0
  240. package/Tests/App/Dashboard/RumSessionReplaySideMenu.test.tsx +3 -1
  241. package/Tests/App/Dashboard/RunbookStepTypeMaps.test.ts +166 -0
  242. package/Tests/App/Dashboard/RunnerKubernetesAgentForm.test.tsx +622 -0
  243. package/Tests/App/Dashboard/ScheduledMaintenanceChangeStateNotifyDefault.test.tsx +1491 -0
  244. package/Tests/App/Dashboard/ScheduledMaintenanceFeedPublicNoteNotifyDefault.test.tsx +489 -0
  245. package/Tests/App/Dashboard/ScheduledMaintenanceFeedRefresh.test.tsx +52 -1
  246. package/Tests/App/Dashboard/ScheduledMaintenanceOverviewNotifyDefault.test.tsx +909 -0
  247. package/Tests/App/Dashboard/ScheduledMaintenanceOverviewPage.test.tsx +14 -0
  248. package/Tests/App/Dashboard/ScheduledMaintenanceWindowStatsTranslation.test.tsx +307 -0
  249. package/Tests/App/Dashboard/SecurityEventAttributeColumnPicker.test.tsx +542 -0
  250. package/Tests/App/Dashboard/SecurityEventConnectionFormModal.test.tsx +174 -0
  251. package/Tests/App/Dashboard/SecurityEventConnectionsEmptyState.test.tsx +973 -212
  252. package/Tests/App/Dashboard/SecurityEventConnectionsTable.test.tsx +491 -52
  253. package/Tests/App/Dashboard/SecurityEventDetailPanel.test.tsx +301 -0
  254. package/Tests/App/Dashboard/SecurityEventListRow.test.tsx +158 -1
  255. package/Tests/App/Dashboard/SecurityEventProviderTile.test.tsx +869 -0
  256. package/Tests/App/Dashboard/SecurityEventsEmptyState.test.tsx +959 -94
  257. package/Tests/App/Dashboard/SecurityEventsNoResults.test.tsx +2 -0
  258. package/Tests/App/Dashboard/SecurityEventsViewer.test.tsx +274 -1
  259. package/Tests/App/Dashboard/SloFeed.test.tsx +106 -1
  260. package/Tests/App/Dashboard/SloMonitorRuleCriteria.test.tsx +566 -0
  261. package/Tests/App/Dashboard/SloNavigationWiring.test.tsx +6 -4
  262. package/Tests/App/Dashboard/SloNoticeBanner.test.tsx +186 -0
  263. package/Tests/App/Dashboard/SloOverviewKpiStrip.test.tsx +388 -44
  264. package/Tests/App/Dashboard/SloOverviewLayout.test.tsx +613 -0
  265. package/Tests/App/Dashboard/TeamMembershipRemoval.test.ts +900 -0
  266. package/Tests/App/Dashboard/TeamMembershipRemovalPages.test.tsx +460 -0
  267. package/Tests/App/Dashboard/TimezoneElements.test.tsx +321 -0
  268. package/Tests/App/Dashboard/TimezoneSelectButton.test.tsx +634 -0
  269. package/Tests/App/Dashboard/TraceExplorer.test.tsx +260 -0
  270. package/Tests/App/Dashboard/TraceMonitorPreview.test.tsx +182 -0
  271. package/Tests/App/Dashboard/UserTimezoneInit.test.tsx +544 -0
  272. package/Tests/App/Dashboard/WorkflowVariableModals.test.tsx +1630 -0
  273. package/Tests/App/Dashboard/WorkflowVariableRoutes.test.tsx +603 -0
  274. package/Tests/App/Dashboard/WorkflowVariableTokenStatus.test.tsx +589 -0
  275. package/Tests/App/Dashboard/WorkflowVariableUtil.test.ts +1543 -0
  276. package/Tests/App/Dashboard/WorkflowVariableView.test.tsx +3227 -0
  277. package/Tests/App/Dashboard/WorkflowVariablesTable.test.tsx +1277 -395
  278. package/Tests/App/StatusPage/StatusPageOverviewMonitorGroupUptime.test.tsx +714 -0
  279. package/Tests/App/StatusPage/StatusPageOverviewUptimeBars.NewYork.test.tsx +1009 -0
  280. package/Tests/App/StatusPage/StatusPageOverviewUptimeBars.test.tsx +1092 -0
  281. package/Tests/Models/DatabaseModels/DomainRoleTierCoverage.test.ts +5 -0
  282. package/Tests/Models/DatabaseModels/KubernetesClusterAiAccessColumns.test.ts +520 -0
  283. package/Tests/Models/DatabaseModels/MonitorSecretKeyColumnAccessControl.test.ts +66 -2
  284. package/Tests/Models/DatabaseModels/ResourceFeedModels.test.ts +0 -8
  285. package/Tests/Models/DatabaseModels/SloLabelAndOwnerRuleModels.test.ts +404 -0
  286. package/Tests/Models/DatabaseModels/SloOverhaulModels.test.ts +17 -1
  287. package/Tests/Models/DatabaseModels/StaticRuleCriteriaInheritance.test.ts +4 -2
  288. package/Tests/Models/DatabaseModels/WorkspaceProjectAuthTokenAccessControl.test.ts +236 -0
  289. package/Tests/Models/IncidentEpisodePublicNoteNotifyColumnContract.test.ts +103 -0
  290. package/Tests/Models/IncidentPublicNoteNotifyColumnContract.test.ts +96 -0
  291. package/Tests/Models/ScheduledMaintenancePublicNoteNotifyColumnContract.test.ts +111 -0
  292. package/Tests/Server/API/AIInvestigationAPI.test.ts +976 -0
  293. package/Tests/Server/API/AutoRemediationApproveKubectlRecheck.test.ts +836 -0
  294. package/Tests/Server/API/CommonAPIAssertCanCreateTable.test.ts +565 -0
  295. package/Tests/Server/API/CommonAPIAssertCanReadTable.test.ts +282 -0
  296. package/Tests/Server/API/KubernetesClusterAiAccessAPI.test.ts +1744 -0
  297. package/Tests/Server/API/LogHistogramAPI.test.ts +371 -0
  298. package/Tests/Server/API/MicrosoftTeamsLegacyWebhookRemoval.test.ts +125 -30
  299. package/Tests/Server/API/MicrosoftTeamsOAuthState.test.ts +1121 -0
  300. package/Tests/Server/API/MonitorUptimeSummaryAPI.test.ts +685 -0
  301. package/Tests/Server/API/SessionReplayAPI.test.ts +602 -1
  302. package/Tests/Server/API/SlackChannelCacheAPI.test.ts +358 -0
  303. package/Tests/Server/API/SlackOAuthState.test.ts +688 -0
  304. package/Tests/Server/API/StatusPageOverviewMonitorGroupUptime.test.ts +527 -0
  305. package/Tests/Server/API/StatusPageTestEmailReportAuth.test.ts +2 -0
  306. package/Tests/Server/API/StatusPageUptimeAPI.test.ts +427 -0
  307. package/Tests/Server/API/UserProjectsAPI.test.ts +4 -0
  308. package/Tests/Server/API/WorkflowVariableAPI.test.ts +404 -0
  309. package/Tests/Server/API/WorkspaceOAuthTestHelpers.ts +289 -0
  310. package/Tests/Server/API/WorkspaceSendTestNotificationRoutes.test.ts +2064 -0
  311. package/Tests/Server/Infrastructure/GlobalCache.test.ts +86 -0
  312. package/Tests/Server/Infrastructure/Postgres/AddConfigurableRuleCriteriaMigration.test.ts +3 -0
  313. package/Tests/Server/Infrastructure/Postgres/AddKubernetesClusterAiAccessMigration.test.ts +589 -0
  314. package/Tests/Server/Infrastructure/Postgres/AddOAuth2WorkflowVariablesMigration.test.ts +254 -0
  315. package/Tests/Server/Infrastructure/Postgres/AddSloLabelAndOwnerRulesMigration.test.ts +407 -0
  316. package/Tests/Server/Infrastructure/Postgres/AddSloMonitorRuleMonitorTypeMigration.test.ts +171 -0
  317. package/Tests/Server/Infrastructure/Postgres/SloProductOverhaulMigration.test.ts +88 -4
  318. package/Tests/Server/Middleware/BlockedUserMiddleware.test.ts +403 -0
  319. package/Tests/Server/Middleware/MasterAdminAuthorization.test.ts +13 -0
  320. package/Tests/Server/Middleware/PublicRouteUserMiddleware.test.ts +2 -0
  321. package/Tests/Server/Middleware/RemovedProjectMemberAuthorization.test.ts +469 -0
  322. package/Tests/Server/Middleware/TelemetryIngestBrowserKey.test.ts +77 -1
  323. package/Tests/Server/Middleware/TelemetryIngestKubernetesAgentRunnerPinnedKey.test.ts +211 -0
  324. package/Tests/Server/Middleware/TelemetryIngestKubernetesAgentRunnerRateLimit.test.ts +358 -0
  325. package/Tests/Server/Middleware/UserAuthorization.test.ts +97 -0
  326. package/Tests/Server/Middleware/UserAuthorizationEditionEnforcement.test.ts +2 -0
  327. package/Tests/Server/Services/AccessTokenProjectUserGrant.test.ts +14 -2
  328. package/Tests/Server/Services/AccessTokenRemovedMemberAccess.test.ts +1044 -0
  329. package/Tests/Server/Services/AddOwnersIdempotency.test.ts +5 -0
  330. package/Tests/Server/Services/AlertEpisodeMemberCreatePermission.test.ts +139 -0
  331. package/Tests/Server/Services/AutoRemediationClusterRuleEngine.test.ts +1361 -0
  332. package/Tests/Server/Services/AutoRemediationRuleCommandRunners.test.ts +375 -0
  333. package/Tests/Server/Services/CrossProjectRelationWriteGuard.test.ts +2384 -0
  334. package/Tests/Server/Services/DatabaseServiceRuleCriteriaValidation.test.ts +104 -0
  335. package/Tests/Server/Services/FindOwnersProjectMembership.test.ts +267 -0
  336. package/Tests/Server/Services/InboundEmail/SendGridInboundProviderAddress.test.ts +90 -0
  337. package/Tests/Server/Services/IncidentEpisodeMemberCreatePermission.test.ts +143 -0
  338. package/Tests/Server/Services/IncidentEpisodePublicNoteNotifyDefault.test.ts +805 -0
  339. package/Tests/Server/Services/IncidentPublicNoteNotifyDefault.test.ts +724 -0
  340. package/Tests/Server/Services/IncidentRoleProjectMembership.test.ts +233 -0
  341. package/Tests/Server/Services/KubernetesClusterAiAccessAgentRunnerAssignments.test.ts +372 -0
  342. package/Tests/Server/Services/KubernetesClusterAiAccessBindingGuard.test.ts +1876 -0
  343. package/Tests/Server/Services/KubernetesClusterAiAccessDeletedRunnerRemedy.test.ts +620 -0
  344. package/Tests/Server/Services/KubernetesClusterAiAccessGapNextSteps.test.ts +421 -0
  345. package/Tests/Server/Services/KubernetesClusterAiAccessService.test.ts +3662 -0
  346. package/Tests/Server/Services/KubernetesClusterAiAccessSubjectClusters.test.ts +405 -0
  347. package/Tests/Server/Services/KubernetesClusterAiSettingsPermission.test.ts +975 -0
  348. package/Tests/Server/Services/KubernetesClusterServiceAiAccessFeed.test.ts +497 -0
  349. package/Tests/Server/Services/KubernetesClusterServiceDeleteSettlesRemediation.test.ts +328 -0
  350. package/Tests/Server/Services/LogAggregationService.test.ts +99 -0
  351. package/Tests/Server/Services/MonitorServiceIncomingEmailCustomAddress.test.ts +447 -0
  352. package/Tests/Server/Services/MonitorServiceProbeFlagSync.test.ts +1334 -0
  353. package/Tests/Server/Services/MonitorServiceProbeStatusGrouping.test.ts +1640 -0
  354. package/Tests/Server/Services/MonitorServiceRefreshCurrentStatus.test.ts +225 -0
  355. package/Tests/Server/Services/MonitorStatusBridgeProbePath.test.ts +8 -8
  356. package/Tests/Server/Services/MonitorStatusTimelineDailyAggregates.test.ts +264 -1
  357. package/Tests/Server/Services/MonitorStatusTimelineMergedDowntime.test.ts +284 -0
  358. package/Tests/Server/Services/MonitorUptimeSummaryService.test.ts +1043 -0
  359. package/Tests/Server/Services/NetworkDeviceRuleEngines.test.ts +5 -0
  360. package/Tests/Server/Services/OnCallUndeliverablePageOwnerMembership.test.ts +359 -0
  361. package/Tests/Server/Services/ProbeServiceDashboardLink.test.ts +191 -0
  362. package/Tests/Server/Services/ProjectOwnersProjectMembership.test.ts +221 -0
  363. package/Tests/Server/Services/RuleRun/IncidentAlertMaintenanceRuleEnginesRun.test.ts +5 -0
  364. package/Tests/Server/Services/RuleRun/LabelRuleEnginesGroupBRun.test.ts +48 -1
  365. package/Tests/Server/Services/RuleRun/OwnerRuleEnginesGroupARun.test.ts +28 -0
  366. package/Tests/Server/Services/RuleRun/OwnerRuleEnginesGroupBRun.test.ts +39 -1
  367. package/Tests/Server/Services/RunnerJobEnqueueAiCommandAgentRunner.test.ts +230 -0
  368. package/Tests/Server/Services/RunnerJobEnqueueKubectl.test.ts +978 -0
  369. package/Tests/Server/Services/RunnerJobKubectlWriteScope.test.ts +866 -0
  370. package/Tests/Server/Services/RunnerJobSubmitResultRedaction.test.ts +322 -0
  371. package/Tests/Server/Services/RunnerJobSubmitResultUnstorableText.test.ts +357 -0
  372. package/Tests/Server/Services/RunnerJobTimeoutReason.test.ts +227 -0
  373. package/Tests/Server/Services/RunnerServiceAgentName.test.ts +581 -0
  374. package/Tests/Server/Services/ScheduledMaintenancePublicNoteNotifyDefault.test.ts +802 -0
  375. package/Tests/Server/Services/ScheduledMaintenanceSubscriberTemplateFormats.test.ts +53 -0
  376. package/Tests/Server/Services/ServiceLevelObjectiveLabelAndOwnerRuleEngines.test.ts +1175 -0
  377. package/Tests/Server/Services/ServiceLevelObjectiveLabelAndOwnerRuleServices.test.ts +172 -0
  378. package/Tests/Server/Services/ServiceLevelObjectiveMonitorRuleEngineService.test.ts +323 -0
  379. package/Tests/Server/Services/ServiceLevelObjectiveMonitorRuleService.test.ts +115 -0
  380. package/Tests/Server/Services/ServiceLevelObjectiveMonitorRuleTriggers.test.ts +21 -2
  381. package/Tests/Server/Services/ServiceLevelObjectiveMonitorTypePostgres.test.ts +480 -0
  382. package/Tests/Server/Services/ServiceLevelObjectiveService.test.ts +174 -0
  383. package/Tests/Server/Services/StaticRuleCriteriaRuntimeCoverage.test.ts +45 -6
  384. package/Tests/Server/Services/StatusPageSubscriberReport.test.ts +1176 -1
  385. package/Tests/Server/Services/TeamMemberBillingSeatSync.test.ts +9 -0
  386. package/Tests/Server/Services/TeamMemberOnCallCleanup.test.ts +18 -0
  387. package/Tests/Server/Services/TeamMemberProjectMembership.test.ts +255 -0
  388. package/Tests/Server/Services/TeamMemberRemovalRevokesProjectAccess.test.ts +600 -0
  389. package/Tests/Server/Services/TeamMemberResourceCleanup.test.ts +731 -0
  390. package/Tests/Server/Services/TeamMemberWorkspaceAccountCleanup.test.ts +164 -0
  391. package/Tests/Server/Services/TraceAggregationService.test.ts +64 -0
  392. package/Tests/Server/Services/UserServiceBlockedUser.test.ts +293 -0
  393. package/Tests/Server/Services/WorkflowVariableOAuthHooks.test.ts +1016 -0
  394. package/Tests/Server/Services/WorkflowVariableOAuthPostgres.test.ts +543 -0
  395. package/Tests/Server/Services/WorkflowVariableRenameUniqueness.test.ts +16 -5
  396. package/Tests/Server/Services/WorkspaceNotificationRuleNoteDelivery.test.ts +473 -0
  397. package/Tests/Server/Services/WorkspaceNotificationRuleSendTestNotification.test.ts +3690 -0
  398. package/Tests/Server/Services/WorkspaceProjectAuthTokenMiscDataSecrets.test.ts +374 -0
  399. package/Tests/Server/Services/WorkspaceProjectAuthTokenSlackChannelCache.test.ts +143 -0
  400. package/Tests/Server/Types/Database/FeedEventTypeFilterQuery.test.ts +745 -0
  401. package/Tests/Server/Types/Database/Permissions/WorkflowVariableOAuthColumnPermission.test.ts +250 -0
  402. package/Tests/Server/Types/Database/QueryHelperJsonContains.test.ts +96 -0
  403. package/Tests/Server/Types/Markdown.test.ts +1035 -1
  404. package/Tests/Server/Types/Workflow/Components/ApiComponentSsrf.test.ts +49 -0
  405. package/Tests/Server/Types/Workflow/Components/TelegramSendMessageToChat.test.ts +331 -0
  406. package/Tests/Server/Utils/AI/ClusterAccessContext.test.ts +285 -0
  407. package/Tests/Server/Utils/AI/CodeFix/CodeFixAgentAuth.test.ts +159 -1
  408. package/Tests/Server/Utils/AI/InvestigationClusterAccessWiring.test.ts +752 -0
  409. package/Tests/Server/Utils/AI/KubectlInvestigationToolkit.test.ts +1840 -0
  410. package/Tests/Server/Utils/AI/KubectlJobRunner.test.ts +1067 -0
  411. package/Tests/Server/Utils/AI/KubectlJobRunnerFinishedJob.test.ts +355 -0
  412. package/Tests/Server/Utils/AI/PostIncidentStatusUpdateTool.test.ts +496 -0
  413. package/Tests/Server/Utils/AI/RemediationCommandTools.test.ts +305 -0
  414. package/Tests/Server/Utils/AI/RemediationCommandToolsKubectl.test.ts +1365 -0
  415. package/Tests/Server/Utils/AI/RemediationCommandToolsKubectlOutcome.test.ts +639 -0
  416. package/Tests/Server/Utils/AI/RemediationCommandToolsLiveCluster.test.ts +1585 -0
  417. package/Tests/Server/Utils/AI/RemediationCommandToolsRunnerScope.test.ts +1065 -0
  418. package/Tests/Server/Utils/AI/RemediationExecutionRunner.test.ts +2138 -1
  419. package/Tests/Server/Utils/AI/RemediationExecutionRunnerClusterMode.test.ts +1035 -0
  420. package/Tests/Server/Utils/AI/RemediationKubectlCopyParity.test.ts +517 -0
  421. package/Tests/Server/Utils/AI/ResourceTools.test.ts +27 -1
  422. package/Tests/Server/Utils/AI/SloTools.test.ts +10 -0
  423. package/Tests/Server/Utils/AutoRemediation/CommandPlanExecutor.test.ts +1371 -24
  424. package/Tests/Server/Utils/AutoRemediation/CommandPlanExecutorRollbackRace.test.ts +962 -0
  425. package/Tests/Server/Utils/AutoRemediation/CommandPlanExecutorUnknownRun.test.ts +518 -0
  426. package/Tests/Server/Utils/AutoRemediation/CommandPlanVerification.test.ts +939 -2
  427. package/Tests/Server/Utils/Database/ProjectScopedRelationReferences.test.ts +371 -0
  428. package/Tests/Server/Utils/Monitor/AffectedResourceList.test.ts +64 -0
  429. package/Tests/Server/Utils/Monitor/Criteria/MetricMonitorCriteriaAnomalyUnits.test.ts +1 -1
  430. package/Tests/Server/Utils/Monitor/DatabaseMetricObservationRemediation.test.ts +102 -0
  431. package/Tests/Server/Utils/Monitor/MonitorAlertCriteriaReferences.test.ts +362 -0
  432. package/Tests/Server/Utils/Monitor/MonitorCriteriaEvaluator.test.ts +405 -0
  433. package/Tests/Server/Utils/Monitor/MonitorCriteriaEvaluatorBreachingSamples.test.ts +1156 -0
  434. package/Tests/Server/Utils/Monitor/MonitorCriteriaEvaluatorMetricUnits.test.ts +106 -80
  435. package/Tests/Server/Utils/Monitor/MonitorEmailAddressRedaction.test.ts +255 -0
  436. package/Tests/Server/Utils/Monitor/MonitorIncidentCriteriaReferences.test.ts +347 -0
  437. package/Tests/Server/Utils/Monitor/MonitorIncidentMemberRoleMembership.test.ts +203 -0
  438. package/Tests/Server/Utils/Monitor/ProbeMonitorsNotification.test.ts +1147 -0
  439. package/Tests/Server/Utils/Monitor/RootCauseList.test.ts +252 -0
  440. package/Tests/Server/Utils/PushNotificationUtilCreators.test.ts +79 -0
  441. package/Tests/Server/Utils/ResourceFeed/ResourceFeedUtil.test.ts +21 -1
  442. package/Tests/Server/Utils/Rules/OwnerRuleAssignment.test.ts +155 -1
  443. package/Tests/Server/Utils/Rules/RuleRun/RuleRunPermission.test.ts +154 -0
  444. package/Tests/Server/Utils/SSRFProtection.test.ts +111 -0
  445. package/Tests/Server/Utils/SessionReplay/SessionReplayReadServiceQueries.test.ts +288 -0
  446. package/Tests/Server/Utils/SessionReplay/SessionReplayUserFlowReadService.test.ts +304 -0
  447. package/Tests/Server/Utils/Slo/SloRulePatternValidator.test.ts +67 -0
  448. package/Tests/Server/Utils/Telemetry/TelemetryIngestionKeyGuard.test.ts +40 -3
  449. package/Tests/Server/Utils/VM/VMRunnerSsrf.test.ts +213 -0
  450. package/Tests/Server/Utils/Workflow/OAuth2TokenClient.test.ts +702 -0
  451. package/Tests/Server/Utils/Workflow/OAuth2TokenClientHttpIntegration.test.ts +507 -0
  452. package/Tests/Server/Utils/Workflow/WorkflowVariableOAuthToken.test.ts +831 -0
  453. package/Tests/Server/Utils/Workspace/MicrosoftTeamsActionAuthorization.test.ts +63 -1
  454. package/Tests/Server/Utils/Workspace/MicrosoftTeamsAppAccessToken.test.ts +256 -0
  455. package/Tests/Server/Utils/Workspace/MicrosoftTeamsChannelSend.test.ts +60 -0
  456. package/Tests/Server/Utils/Workspace/MicrosoftTeamsChatActionAuthorization.test.ts +442 -0
  457. package/Tests/Server/Utils/Workspace/MicrosoftTeamsChats.test.ts +44 -2
  458. package/Tests/Server/Utils/Workspace/MicrosoftTeamsDirectMessage.test.ts +55 -0
  459. package/Tests/Server/Utils/Workspace/MicrosoftTeamsReactionNoteSync.test.ts +1522 -0
  460. package/Tests/Server/Utils/Workspace/MicrosoftTeamsServiceUrl.test.ts +130 -0
  461. package/Tests/Server/Utils/Workspace/MicrosoftTeamsTeamInstalls.test.ts +4 -4
  462. package/Tests/Server/Utils/Workspace/Slack/SlackActionAuthorization.test.ts +691 -0
  463. package/Tests/Server/Utils/Workspace/Slack/SlackMessageByTimestamp.test.ts +253 -0
  464. package/Tests/Server/Utils/Workspace/Slack/SlackReactionNote.test.ts +574 -0
  465. package/Tests/Server/Utils/Workspace/WorkspaceActionAuthorization.test.ts +488 -0
  466. package/Tests/Server/Utils/Workspace/WorkspaceCreateProjectReferences.test.ts +861 -0
  467. package/Tests/Server/Utils/Workspace/WorkspaceMessageAuthor.test.ts +635 -0
  468. package/Tests/Server/Utils/Workspace/WorkspaceOAuthState.test.ts +548 -0
  469. package/Tests/Server/Utils/Workspace/WorkspaceReactionNote.test.ts +839 -0
  470. package/Tests/Server/Utils/Workspace/WorkspaceSendErrorMessage.test.ts +725 -0
  471. package/Tests/Types/API/Route.test.ts +56 -0
  472. package/Tests/Types/API/URLSchemeLikePath.test.ts +304 -0
  473. package/Tests/Types/AutoRemediation/AiRemediationCommandPlan.test.ts +283 -9
  474. package/Tests/Types/DateBrowserLocalWallClock.test.ts +280 -0
  475. package/Tests/Types/DateLocalShortMonthNameFallback.test.ts +389 -0
  476. package/Tests/Types/DateUserTimezone.test.ts +177 -4
  477. package/Tests/Types/Kubernetes/KubernetesAgentChartAiAccess.test.ts +306 -0
  478. package/Tests/Types/Kubernetes/KubernetesClusterAiAccess.test.ts +283 -0
  479. package/Tests/Types/Kubernetes/KubernetesRunnerPostureWriteScope.test.ts +68 -0
  480. package/Tests/Types/Monitor/DatabaseMonitor/SqlServerPlatform.test.ts +144 -0
  481. package/Tests/Types/Monitor/MonitorStepExceptionMonitor.test.ts +160 -0
  482. package/Tests/Types/Monitor/Recommendation/MonitorRecommendationCoverage.test.ts +53 -0
  483. package/Tests/Types/Runbook/RunbookStepType.test.ts +91 -16
  484. package/Tests/Types/Runner/RunnerLiveStatus.test.ts +14 -3
  485. package/Tests/Types/SecurityEvent/Connectors/SecurityEventConnectorCatalog.test.ts +15 -0
  486. package/Tests/Types/StatusPage/PublicNoteSubscriberNotificationDefault.test.ts +1868 -0
  487. package/Tests/Types/Timezone.test.ts +5 -0
  488. package/Tests/Types/TimezoneAlias.test.ts +1034 -0
  489. package/Tests/Types/Workflow/JiraTemplateFixtures.ts +833 -0
  490. package/Tests/Types/Workflow/JiraTemplateScripts.test.ts +5414 -0
  491. package/Tests/Types/Workflow/JiraTemplateSimulation.test.ts +4803 -0
  492. package/Tests/Types/Workflow/JiraTemplates.test.ts +5429 -0
  493. package/Tests/Types/Workflow/Templates.test.ts +79 -4
  494. package/Tests/Types/Workflow/WorkflowVariableOAuth.test.ts +520 -0
  495. package/Tests/Types/Workspace/WorkspaceNoteReaction.test.ts +177 -0
  496. package/Tests/UI/Components/AttributesJSON/AttributesJSONView.test.tsx +390 -0
  497. package/Tests/UI/Components/AttributesJSON/CopyAttributesAsJSONButton.test.tsx +566 -0
  498. package/Tests/UI/Components/AttributesJSON/JSONHighlight.test.ts +131 -0
  499. package/Tests/UI/Components/BasicFormDropdownNormalization.test.tsx +276 -1
  500. package/Tests/UI/Components/Calendar/Calendar.test.tsx +1611 -0
  501. package/Tests/UI/Components/Calendar/CalendarDayLayout.test.ts +1486 -0
  502. package/Tests/UI/Components/Calendar/CalendarDayLayoutDst.test.ts +632 -0
  503. package/Tests/UI/Components/Calendar/CalendarDst.test.tsx +388 -0
  504. package/Tests/UI/Components/Charts/ChartGroupPlotFloor.test.tsx +170 -0
  505. package/Tests/UI/Components/Charts/HistogramSelection.test.ts +282 -0
  506. package/Tests/UI/Components/CustomTimeRangeModal.test.tsx +6 -0
  507. package/Tests/UI/Components/CustomTimeRangeModalTimezoneTranslation.test.tsx +285 -0
  508. package/Tests/UI/Components/Dropdown.test.tsx +999 -2
  509. package/Tests/UI/Components/FeedOptions.test.ts +1404 -0
  510. package/Tests/UI/Components/FeedOptionsButton.test.tsx +2603 -0
  511. package/Tests/UI/Components/Forms/FormFieldCheckboxTranslation.test.tsx +216 -0
  512. package/Tests/UI/Components/Forms/FormFieldTimezoneDescriptionTranslation.test.tsx +461 -0
  513. package/Tests/UI/Components/Forms/IncidentEpisodePublicNoteNotifyPayload.test.tsx +641 -0
  514. package/Tests/UI/Components/Forms/IncidentPublicNoteNotifyPayload.test.tsx +346 -0
  515. package/Tests/UI/Components/Forms/ScheduledMaintenancePublicNoteNotifyPayload.test.tsx +493 -0
  516. package/Tests/UI/Components/Graphs/DayUptimeGraph.test.tsx +911 -2
  517. package/Tests/UI/Components/Graphs/DayUptimeGraphTimezone.NewYork.test.tsx +730 -0
  518. package/Tests/UI/Components/Graphs/DayUptimeGraphTimezone.Tokyo.test.tsx +506 -0
  519. package/Tests/UI/Components/HistogramClickToZoom.test.tsx +619 -0
  520. package/Tests/UI/Components/Icon.test.tsx +26 -0
  521. package/Tests/UI/Components/LogDetailsPanelAttributesJSON.test.tsx +248 -0
  522. package/Tests/UI/Components/LogsViewerHistogramZoom.test.tsx +47 -1
  523. package/Tests/UI/Components/LogsViewerSmallScreens.test.tsx +620 -0
  524. package/Tests/UI/Components/ModelPageModelChange.test.tsx +242 -3
  525. package/Tests/UI/Components/ModelTable/BaseModelTableDeleteConfirmation.test.tsx +521 -0
  526. package/Tests/UI/Components/MonitorGraphs/Uptime.test.tsx +406 -2
  527. package/Tests/UI/Components/MonitorGraphs/UptimeBarDayModal.test.tsx +169 -2
  528. package/Tests/UI/Components/RuleCriteria/RuleCriteriaModelTable.test.tsx +3 -3
  529. package/Tests/UI/Components/TelemetryViewer/TelemetryViewerHistogramClickZoom.test.tsx +266 -0
  530. package/Tests/UI/Components/TelemetryViewer/TelemetryViewerSmallScreens.test.tsx +439 -0
  531. package/Tests/UI/Components/TimezoneDropdownLegacyValues.test.tsx +704 -0
  532. package/Tests/UI/Components/UseHistogramZoom.test.tsx +89 -1
  533. package/Tests/UI/Components/UseLogsHistogram.test.tsx +175 -0
  534. package/Tests/UI/Components/useFeedItemsViewKey.test.tsx +1017 -0
  535. package/Tests/UI/Components/useFeedOptions.test.tsx +1107 -0
  536. package/Tests/UI/Monitor/MonitorSummarySnapshotRender.test.tsx +5 -5
  537. package/Tests/UI/Telemetry/TelemetryDetailPanel.test.tsx +28 -0
  538. package/Tests/UI/Utils/ProjectUsersModelAPI.test.ts +51 -0
  539. package/Tests/UI/Utils/Timezone.test.ts +747 -33
  540. package/Tests/UI/Workspace/SendTestNotificationButton.test.tsx +1854 -0
  541. package/Tests/UI/Workspace/WorkspaceCardsSendTestNotification.test.tsx +1864 -0
  542. package/Tests/Utils/AI/InvestigationReport.test.ts +435 -7
  543. package/Tests/Utils/AiRemediation/KubectlAllowlistValidatorParity.test.ts +1084 -0
  544. package/Tests/Utils/AiRemediation/KubectlOutputRedactor.test.ts +2531 -0
  545. package/Tests/Utils/AiRemediation/KubectlPolicy.test.ts +1895 -0
  546. package/Tests/Utils/AiRemediation/KubectlPolicyAllowlist.test.ts +428 -0
  547. package/Tests/Utils/AiRemediation/KubectlPolicyChartRbacParity.test.ts +828 -0
  548. package/Tests/Utils/AiRemediation/KubectlPolicyCustomResourceScope.test.ts +573 -0
  549. package/Tests/Utils/AiRemediation/KubectlPolicyDenials.test.ts +1525 -0
  550. package/Tests/Utils/AiRemediation/KubectlPolicyExposeOverrides.test.ts +275 -0
  551. package/Tests/Utils/AiRemediation/KubectlPolicyNodePatch.test.ts +428 -0
  552. package/Tests/Utils/AiRemediation/KubectlPolicyObjectWords.test.ts +195 -0
  553. package/Tests/Utils/AiRemediation/KubectlPolicyPatchParents.test.ts +637 -0
  554. package/Tests/Utils/AiRemediation/KubectlPolicyPodSecurityBaseline.test.ts +322 -0
  555. package/Tests/Utils/AiRemediation/KubectlPolicySafeWriteScope.test.ts +1026 -0
  556. package/Tests/Utils/AiRemediation/KubectlWaitBudget.test.ts +267 -0
  557. package/Tests/Utils/AiRemediation/KubectlWriteScope.test.ts +390 -0
  558. package/Tests/Utils/AiRemediation/KubectlWriteScopeCallerParity.test.ts +777 -0
  559. package/Tests/Utils/AiRemediation/KubectlWriteScopeClusterScoped.test.ts +613 -0
  560. package/Tests/Utils/AiRemediation/KubectlWriteScopeEntryPoint.test.ts +576 -0
  561. package/Tests/Utils/AiRemediation/KubectlWriteScopeKubectlSpellings.test.ts +752 -0
  562. package/Tests/Utils/AiRemediation/KubectlWriteScopeObjectWords.test.ts +358 -0
  563. package/Tests/Utils/AiRemediation/KubectlWriteScopeOverrides.test.ts +293 -0
  564. package/Tests/Utils/AiRemediation/KubectlWriteScopeParityCases.ts +598 -0
  565. package/Tests/Utils/AiRemediation/KubectlWriteScopePolicyParity.test.ts +403 -0
  566. package/Tests/Utils/Dashboard/DashboardClockComponent.test.ts +154 -5
  567. package/Tests/Utils/LabelRuleImportExport.test.ts +102 -0
  568. package/Tests/Utils/Monitor/IncomingEmailMonitorAddress.test.ts +478 -0
  569. package/Tests/Utils/Monitor/MonitorCheckScheduleUtil.test.ts +646 -0
  570. package/Tests/Utils/Monitor/MonitorOverviewCriteriaUtil.test.ts +292 -0
  571. package/Tests/Utils/Monitor/MonitorOverviewFamily.test.ts +274 -0
  572. package/Tests/Utils/Monitor/MonitorOverviewPresentationUtil.test.ts +3100 -0
  573. package/Tests/Utils/Monitor/MonitorOverviewProbeUtil.test.ts +1412 -0
  574. package/Tests/Utils/Monitor/MonitorOverviewTargetUtil.test.ts +374 -0
  575. package/Tests/Utils/Monitor/MonitorStatusHistoryUtil.test.ts +332 -0
  576. package/Tests/Utils/Monitor/MonitorUptimeSummaryUtil.test.ts +946 -0
  577. package/Tests/Utils/Rum/SessionIdentity.test.ts +94 -0
  578. package/Tests/Utils/Rum/SessionReplayWafCompatibility.test.ts +840 -0
  579. package/Tests/Utils/Rum/SessionReplayWireEncoding.test.ts +208 -0
  580. package/Tests/Utils/Rum/UserFlow.test.ts +1010 -0
  581. package/Tests/Utils/Slo/SloDuration.test.ts +115 -24
  582. package/Tests/Utils/Slo/SloHealth.test.ts +93 -10
  583. package/Tests/Utils/Slo/SloMonitorRuleCriteria.test.ts +109 -0
  584. package/Tests/Utils/Slo/SloOverviewText.test.ts +64 -0
  585. package/Tests/Utils/StatusPage/MonitorGroupMergedDowntimeUtil.test.ts +217 -0
  586. package/Tests/Utils/StatusPage/ResourceUptime.test.ts +1272 -1
  587. package/Tests/Utils/StatusPage/UptimeDailyAggregateTotals.test.ts +298 -0
  588. package/Tests/Utils/StatusPage/UptimeDailyAggregateUtil.test.ts +649 -1
  589. package/Tests/Utils/StatusPage/UptimeDailyAggregateWindow.test.ts +314 -0
  590. package/Tests/Utils/Telemetry/AttributesJSON.test.ts +454 -0
  591. package/Tests/Utils/Uptime/DayUptimeGraphUtil.test.ts +418 -2
  592. package/Tests/Utils/Uptime/DayUptimeGraphUtilMidnightDst.test.ts +160 -0
  593. package/Tests/Utils/Uptime/DayUptimeGraphUtilTimezone.Auckland.test.ts +45 -0
  594. package/Tests/Utils/Uptime/DayUptimeGraphUtilTimezone.Kolkata.test.ts +40 -0
  595. package/Tests/Utils/Uptime/DayUptimeGraphUtilTimezone.London.test.ts +147 -0
  596. package/Tests/Utils/Uptime/DayUptimeGraphUtilTimezone.NewYork.test.ts +48 -0
  597. package/Tests/Utils/Uptime/DayUptimeGraphUtilTimezone.Tokyo.test.ts +39 -0
  598. package/Tests/Utils/Uptime/DayUptimeGraphUtilTimezoneCases.ts +1015 -0
  599. package/Tests/Utils/Uptime/UptimeUtil.test.ts +75 -0
  600. package/Tests/Utils/Uptime/UptimeUtilChronologicalOrder.test.ts +1279 -0
  601. package/Types/API/Route.ts +19 -2
  602. package/Types/API/URL.ts +26 -2
  603. package/Types/AutoRemediation/AiRemediationCommandPlan.ts +203 -5
  604. package/Types/Date.ts +121 -7
  605. package/Types/Email/EmailMessage.ts +8 -0
  606. package/Types/Email/EmailTemplateType.ts +1 -0
  607. package/Types/Exception/ExceptionMessages.ts +1 -0
  608. package/Types/Kubernetes/KubernetesClusterAiAccess.ts +488 -0
  609. package/Types/Kubernetes/KubernetesClusterAiAccessPermissions.ts +54 -0
  610. package/Types/Kubernetes/KubernetesClusterAiAccessToolNames.ts +17 -0
  611. package/Types/Monitor/DatabaseMonitor/DatabaseMonitorResponse.ts +9 -0
  612. package/Types/Monitor/DatabaseMonitor/SqlServerPlatform.ts +117 -0
  613. package/Types/Monitor/KubernetesAlertTemplates.ts +6 -5
  614. package/Types/Monitor/MetricMonitor/MetricCriteriaContext.ts +6 -5
  615. package/Types/Monitor/MetricMonitor/MetricMonitorResponse.ts +9 -0
  616. package/Types/Monitor/MonitorStepExceptionMonitor.ts +56 -0
  617. package/Types/Monitor/MonitorUptimeSummary.ts +113 -0
  618. package/Types/Monitor/Recommendation/MonitorRecommendationUtil.ts +11 -0
  619. package/Types/Permission.ts +90 -0
  620. package/Types/Rules/RuleCriteriaFieldRegistry.ts +11 -0
  621. package/Types/Rules/RuleRun.ts +4 -0
  622. package/Types/Rum/SessionReplay.ts +55 -2
  623. package/Types/Rum/SessionReplayApi.ts +44 -1
  624. package/Types/Rum/UserFlow.ts +187 -0
  625. package/Types/Runbook/RunbookStepType.ts +10 -0
  626. package/Types/Runbook/RunnerJobOrigin.ts +15 -0
  627. package/Types/SecurityEvent/Connectors/SecurityEventConnectorCatalog.ts +6 -2
  628. package/Types/StatusPage/MergedDowntimeTotals.ts +17 -0
  629. package/Types/StatusPage/PublicNoteSubscriberNotificationDefault.ts +148 -0
  630. package/Types/StatusPage/UptimeDailyAggregate.ts +15 -0
  631. package/Types/Telemetry/TelemetryIngestSurface.ts +9 -0
  632. package/Types/Timezone.ts +5 -0
  633. package/Types/TimezoneAlias.ts +385 -0
  634. package/Types/Workflow/Templates.ts +3041 -2
  635. package/Types/Workflow/WorkflowVariableOAuth.ts +476 -0
  636. package/Types/Workspace/WorkspaceNoteReaction.ts +132 -0
  637. package/Typings/Index.d.ts +24 -0
  638. package/UI/Components/AttributesJSON/AttributesJSONPreferences.ts +175 -0
  639. package/UI/Components/AttributesJSON/AttributesJSONView.tsx +138 -0
  640. package/UI/Components/AttributesJSON/AttributesViewToggle.tsx +79 -0
  641. package/UI/Components/AttributesJSON/BracesGlyph.tsx +30 -0
  642. package/UI/Components/AttributesJSON/CopyAttributesAsJSONButton.tsx +491 -0
  643. package/UI/Components/AttributesJSON/JSONHighlight.ts +77 -0
  644. package/UI/Components/Calendar/Calendar.css +83 -0
  645. package/UI/Components/Calendar/Calendar.tsx +136 -7
  646. package/UI/Components/Calendar/CalendarDayLayout.ts +236 -0
  647. package/UI/Components/Charts/ChartGroup/ChartGroup.tsx +23 -1
  648. package/UI/Components/Charts/Utils/HistogramSelection.ts +117 -0
  649. package/UI/Components/Charts/Utils/useHistogramRangeSelection.ts +269 -0
  650. package/UI/Components/Charts/Utils/useHistogramZoom.ts +26 -2
  651. package/UI/Components/Date/CustomTimeRangeModal.tsx +26 -3
  652. package/UI/Components/Dropdown/Dropdown.tsx +58 -9
  653. package/UI/Components/Feed/FeedOptions.ts +427 -0
  654. package/UI/Components/Feed/FeedOptionsButton.tsx +692 -0
  655. package/UI/Components/Feed/useFeedItems.ts +28 -9
  656. package/UI/Components/Feed/useFeedOptions.ts +225 -0
  657. package/UI/Components/Forms/Fields/FormField.tsx +49 -14
  658. package/UI/Components/Graphs/DayUptimeGraph.tsx +166 -25
  659. package/UI/Components/Graphs/UptimeBarTooltip.tsx +10 -2
  660. package/UI/Components/Graphs/UptimeDaySummary.tsx +8 -0
  661. package/UI/Components/Icon/Icon.tsx +1 -1
  662. package/UI/Components/LogsViewer/LogsViewer.tsx +52 -5
  663. package/UI/Components/LogsViewer/components/ColumnSelector.tsx +13 -2
  664. package/UI/Components/LogsViewer/components/KeyboardShortcutsHelp.tsx +13 -1
  665. package/UI/Components/LogsViewer/components/LogDetailsPanel.tsx +91 -76
  666. package/UI/Components/LogsViewer/components/LogsFacetSidebar.tsx +15 -1
  667. package/UI/Components/LogsViewer/components/LogsHistogram.tsx +28 -106
  668. package/UI/Components/LogsViewer/components/LogsViewerToolbar.tsx +54 -6
  669. package/UI/Components/LogsViewer/components/SavedViewsDropdown.tsx +8 -2
  670. package/UI/Components/LogsViewer/useLogsHistogram.ts +39 -6
  671. package/UI/Components/ModelTable/BaseModelTable.tsx +66 -14
  672. package/UI/Components/MonitorGraphs/Uptime.tsx +12 -0
  673. package/UI/Components/MonitorGraphs/UptimeBarDayModal.tsx +10 -2
  674. package/UI/Components/Page/ModelPage.tsx +59 -3
  675. package/UI/Components/TelemetryViewer/TelemetryViewer.tsx +69 -5
  676. package/UI/Components/TelemetryViewer/components/TelemetryDetailPanel.tsx +12 -1
  677. package/UI/Components/TelemetryViewer/components/TelemetryFacetSidebar.tsx +15 -1
  678. package/UI/Components/TelemetryViewer/components/TelemetryHistogram.tsx +36 -104
  679. package/UI/Components/TelemetryViewer/components/TelemetrySearchBar.tsx +9 -1
  680. package/UI/Utils/ModelAPI/ProjectUsersModelAPI.ts +19 -1
  681. package/UI/Utils/Timezone.ts +69 -28
  682. package/Utils/AI/InvestigationReport.ts +195 -25
  683. package/Utils/AiRemediation/KubectlOutputRedactor.ts +1724 -0
  684. package/Utils/AiRemediation/KubectlPolicy.ts +4136 -0
  685. package/Utils/AiRemediation/KubectlWaitBudget.ts +156 -0
  686. package/Utils/AiRemediation/KubectlWriteScope.ts +1964 -0
  687. package/Utils/Dashboard/Components/DashboardClockComponent.ts +7 -6
  688. package/Utils/LabelRuleImportExport.ts +27 -9
  689. package/Utils/Monitor/IncomingEmailMonitorAddress.ts +292 -0
  690. package/Utils/Monitor/MetricValueFormatter.ts +2 -2
  691. package/Utils/Monitor/MonitorCheckScheduleUtil.ts +654 -0
  692. package/Utils/Monitor/MonitorOverviewCriteriaUtil.ts +188 -0
  693. package/Utils/Monitor/MonitorOverviewFamily.ts +263 -0
  694. package/Utils/Monitor/MonitorOverviewPresentationUtil.ts +1958 -0
  695. package/Utils/Monitor/MonitorOverviewProbeUtil.ts +979 -0
  696. package/Utils/Monitor/MonitorOverviewTargetUtil.ts +299 -0
  697. package/Utils/Monitor/MonitorStatusHistoryUtil.ts +201 -0
  698. package/Utils/Monitor/MonitorUptimeSummaryUtil.ts +638 -0
  699. package/Utils/Rules/MonitorTypeRuleCriteria.ts +31 -0
  700. package/Utils/Rum/SessionIdentity.ts +44 -0
  701. package/Utils/Rum/SessionReplayWireEncoding.ts +137 -0
  702. package/Utils/Rum/UserFlow.ts +1527 -0
  703. package/Utils/Slo/SloDuration.ts +22 -6
  704. package/Utils/Slo/SloHealth.ts +8 -7
  705. package/Utils/Slo/SloMonitorRuleCriteria.ts +33 -1
  706. package/Utils/Slo/SloOverviewText.ts +33 -0
  707. package/Utils/Slo/SloProjection.ts +4 -3
  708. package/Utils/StatusPage/MonitorGroupMergedDowntimeUtil.ts +107 -0
  709. package/Utils/StatusPage/ResourceUptime.ts +99 -0
  710. package/Utils/StatusPage/UptimeDailyAggregateUtil.ts +197 -0
  711. package/Utils/Telemetry/AttributesJSON.ts +367 -0
  712. package/Utils/Uptime/DayUptimeGraphUtil.ts +165 -0
  713. package/Utils/Uptime/UptimeUtil.ts +122 -38
  714. package/build/dist/Models/DatabaseModels/AlertEpisodeMember.js +8 -1
  715. package/build/dist/Models/DatabaseModels/AlertEpisodeMember.js.map +1 -1
  716. package/build/dist/Models/DatabaseModels/AutoRemediationSuggestion.js +62 -0
  717. package/build/dist/Models/DatabaseModels/AutoRemediationSuggestion.js.map +1 -1
  718. package/build/dist/Models/DatabaseModels/IncidentEpisodeMember.js +8 -1
  719. package/build/dist/Models/DatabaseModels/IncidentEpisodeMember.js.map +1 -1
  720. package/build/dist/Models/DatabaseModels/IncidentEpisodePublicNote.js +10 -3
  721. package/build/dist/Models/DatabaseModels/IncidentEpisodePublicNote.js.map +1 -1
  722. package/build/dist/Models/DatabaseModels/IncidentPublicNote.js +10 -3
  723. package/build/dist/Models/DatabaseModels/IncidentPublicNote.js.map +1 -1
  724. package/build/dist/Models/DatabaseModels/Index.js +4 -0
  725. package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
  726. package/build/dist/Models/DatabaseModels/KubernetesCluster.js +434 -0
  727. package/build/dist/Models/DatabaseModels/KubernetesCluster.js.map +1 -1
  728. package/build/dist/Models/DatabaseModels/Monitor.js +49 -0
  729. package/build/dist/Models/DatabaseModels/Monitor.js.map +1 -1
  730. package/build/dist/Models/DatabaseModels/Runner.js +4 -4
  731. package/build/dist/Models/DatabaseModels/Runner.js.map +1 -1
  732. package/build/dist/Models/DatabaseModels/RunnerJob.js +66 -0
  733. package/build/dist/Models/DatabaseModels/RunnerJob.js.map +1 -1
  734. package/build/dist/Models/DatabaseModels/ScheduledMaintenancePublicNote.js +11 -3
  735. package/build/dist/Models/DatabaseModels/ScheduledMaintenancePublicNote.js.map +1 -1
  736. package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveFeed.js +2 -0
  737. package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveFeed.js.map +1 -1
  738. package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveLabelRule.js +530 -0
  739. package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveLabelRule.js.map +1 -0
  740. package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveMonitorRule.js +39 -4
  741. package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveMonitorRule.js.map +1 -1
  742. package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveOwnerRule.js +612 -0
  743. package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveOwnerRule.js.map +1 -0
  744. package/build/dist/Models/DatabaseModels/WorkflowVariable.js +487 -3
  745. package/build/dist/Models/DatabaseModels/WorkflowVariable.js.map +1 -1
  746. package/build/dist/Models/DatabaseModels/WorkspaceProjectAuthToken.js +64 -16
  747. package/build/dist/Models/DatabaseModels/WorkspaceProjectAuthToken.js.map +1 -1
  748. package/build/dist/Server/API/AIInvestigationAPI.js +205 -0
  749. package/build/dist/Server/API/AIInvestigationAPI.js.map +1 -1
  750. package/build/dist/Server/API/AutoRemediationAPI.js +115 -2
  751. package/build/dist/Server/API/AutoRemediationAPI.js.map +1 -1
  752. package/build/dist/Server/API/CommonAPI.js +49 -0
  753. package/build/dist/Server/API/CommonAPI.js.map +1 -1
  754. package/build/dist/Server/API/KubernetesClusterAiAccessAPI.js +564 -0
  755. package/build/dist/Server/API/KubernetesClusterAiAccessAPI.js.map +1 -0
  756. package/build/dist/Server/API/MicrosoftTeamsAPI.js +465 -176
  757. package/build/dist/Server/API/MicrosoftTeamsAPI.js.map +1 -1
  758. package/build/dist/Server/API/MonitorAPI.js +107 -1
  759. package/build/dist/Server/API/MonitorAPI.js.map +1 -1
  760. package/build/dist/Server/API/OnCallScheduleTimelineAPI.js +5 -16
  761. package/build/dist/Server/API/OnCallScheduleTimelineAPI.js.map +1 -1
  762. package/build/dist/Server/API/SlackAPI.js +322 -78
  763. package/build/dist/Server/API/SlackAPI.js.map +1 -1
  764. package/build/dist/Server/API/StatusPageAPI.js +123 -17
  765. package/build/dist/Server/API/StatusPageAPI.js.map +1 -1
  766. package/build/dist/Server/API/TelemetryAPI.js +144 -5
  767. package/build/dist/Server/API/TelemetryAPI.js.map +1 -1
  768. package/build/dist/Server/API/UserTwoFactorBackupCodeAPI.js +1 -0
  769. package/build/dist/Server/API/UserTwoFactorBackupCodeAPI.js.map +1 -1
  770. package/build/dist/Server/API/WorkflowVariableAPI.js +109 -0
  771. package/build/dist/Server/API/WorkflowVariableAPI.js.map +1 -0
  772. package/build/dist/Server/Infrastructure/GlobalCache.js +29 -0
  773. package/build/dist/Server/Infrastructure/GlobalCache.js.map +1 -1
  774. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1794100000000-AddSloLabelAndOwnerRules.js +93 -0
  775. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1794100000000-AddSloLabelAndOwnerRules.js.map +1 -0
  776. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1794200000000-AddSloMonitorRuleMonitorType.js +12 -0
  777. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1794200000000-AddSloMonitorRuleMonitorType.js.map +1 -0
  778. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1794300000000-AddOAuth2WorkflowVariables.js +38 -0
  779. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1794300000000-AddOAuth2WorkflowVariables.js.map +1 -0
  780. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1794400000000-AddKubernetesClusterAiAccess.js +54 -0
  781. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1794400000000-AddKubernetesClusterAiAccess.js.map +1 -0
  782. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1794500000000-AddIncomingEmailCustomAddressToMonitor.js +14 -0
  783. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1794500000000-AddIncomingEmailCustomAddressToMonitor.js.map +1 -0
  784. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1794600000000-AddAuthTokenExpiresAtToWorkspaceProjectAuthToken.js +12 -0
  785. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1794600000000-AddAuthTokenExpiresAtToWorkspaceProjectAuthToken.js.map +1 -0
  786. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1794700000000-RemoveAppAccessTokenFromWorkspaceProjectAuthTokenMiscData.js +32 -0
  787. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1794700000000-RemoveAppAccessTokenFromWorkspaceProjectAuthTokenMiscData.js.map +1 -0
  788. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +14 -0
  789. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  790. package/build/dist/Server/Middleware/MasterAdminAuthorization.js +21 -0
  791. package/build/dist/Server/Middleware/MasterAdminAuthorization.js.map +1 -1
  792. package/build/dist/Server/Middleware/TelemetryIngest.js +32 -2
  793. package/build/dist/Server/Middleware/TelemetryIngest.js.map +1 -1
  794. package/build/dist/Server/Middleware/UserAuthorization.js +39 -6
  795. package/build/dist/Server/Middleware/UserAuthorization.js.map +1 -1
  796. package/build/dist/Server/Services/AIAgentService.js +1 -0
  797. package/build/dist/Server/Services/AIAgentService.js.map +1 -1
  798. package/build/dist/Server/Services/AccessTokenService.js +87 -42
  799. package/build/dist/Server/Services/AccessTokenService.js.map +1 -1
  800. package/build/dist/Server/Services/AlertEpisodeMemberService.js +4 -0
  801. package/build/dist/Server/Services/AlertEpisodeMemberService.js.map +1 -1
  802. package/build/dist/Server/Services/AlertEpisodeService.js +12 -1
  803. package/build/dist/Server/Services/AlertEpisodeService.js.map +1 -1
  804. package/build/dist/Server/Services/AlertService.js +110 -23
  805. package/build/dist/Server/Services/AlertService.js.map +1 -1
  806. package/build/dist/Server/Services/AutoRemediationRuleEngineService.js +716 -30
  807. package/build/dist/Server/Services/AutoRemediationRuleEngineService.js.map +1 -1
  808. package/build/dist/Server/Services/AutoRemediationRuleService.js +100 -0
  809. package/build/dist/Server/Services/AutoRemediationRuleService.js.map +1 -1
  810. package/build/dist/Server/Services/BillingService.js +1 -0
  811. package/build/dist/Server/Services/BillingService.js.map +1 -1
  812. package/build/dist/Server/Services/DatabaseService.js +7 -0
  813. package/build/dist/Server/Services/DatabaseService.js.map +1 -1
  814. package/build/dist/Server/Services/InboundEmail/Providers/SendGridInboundProvider.js +11 -16
  815. package/build/dist/Server/Services/InboundEmail/Providers/SendGridInboundProvider.js.map +1 -1
  816. package/build/dist/Server/Services/IncidentEpisodeMemberService.js +4 -0
  817. package/build/dist/Server/Services/IncidentEpisodeMemberService.js.map +1 -1
  818. package/build/dist/Server/Services/IncidentEpisodePublicNoteService.js +48 -0
  819. package/build/dist/Server/Services/IncidentEpisodePublicNoteService.js.map +1 -1
  820. package/build/dist/Server/Services/IncidentEpisodeRoleMemberService.js +21 -0
  821. package/build/dist/Server/Services/IncidentEpisodeRoleMemberService.js.map +1 -1
  822. package/build/dist/Server/Services/IncidentEpisodeService.js +12 -1
  823. package/build/dist/Server/Services/IncidentEpisodeService.js.map +1 -1
  824. package/build/dist/Server/Services/IncidentGroupingEngineService.js +8 -0
  825. package/build/dist/Server/Services/IncidentGroupingEngineService.js.map +1 -1
  826. package/build/dist/Server/Services/IncidentMemberService.js +14 -0
  827. package/build/dist/Server/Services/IncidentMemberService.js.map +1 -1
  828. package/build/dist/Server/Services/IncidentPublicNoteService.js +48 -0
  829. package/build/dist/Server/Services/IncidentPublicNoteService.js.map +1 -1
  830. package/build/dist/Server/Services/IncidentService.js +99 -21
  831. package/build/dist/Server/Services/IncidentService.js.map +1 -1
  832. package/build/dist/Server/Services/IncidentStateTimelineService.js +12 -0
  833. package/build/dist/Server/Services/IncidentStateTimelineService.js.map +1 -1
  834. package/build/dist/Server/Services/IncidentTemplateService.js +68 -4
  835. package/build/dist/Server/Services/IncidentTemplateService.js.map +1 -1
  836. package/build/dist/Server/Services/Index.js +4 -0
  837. package/build/dist/Server/Services/Index.js.map +1 -1
  838. package/build/dist/Server/Services/KubernetesClusterAiAccessService.js +1470 -0
  839. package/build/dist/Server/Services/KubernetesClusterAiAccessService.js.map +1 -0
  840. package/build/dist/Server/Services/KubernetesClusterService.js +1097 -0
  841. package/build/dist/Server/Services/KubernetesClusterService.js.map +1 -1
  842. package/build/dist/Server/Services/LogAggregationService.js +14 -6
  843. package/build/dist/Server/Services/LogAggregationService.js.map +1 -1
  844. package/build/dist/Server/Services/MonitorService.js +490 -50
  845. package/build/dist/Server/Services/MonitorService.js.map +1 -1
  846. package/build/dist/Server/Services/MonitorStatusTimelineService.js +540 -3
  847. package/build/dist/Server/Services/MonitorStatusTimelineService.js.map +1 -1
  848. package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleScheduleService.js +2 -0
  849. package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleScheduleService.js.map +1 -1
  850. package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleTeamService.js +2 -0
  851. package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleTeamService.js.map +1 -1
  852. package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleUserService.js +2 -0
  853. package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleUserService.js.map +1 -1
  854. package/build/dist/Server/Services/OnCallDutyPolicyScheduleService.js +3 -0
  855. package/build/dist/Server/Services/OnCallDutyPolicyScheduleService.js.map +1 -1
  856. package/build/dist/Server/Services/OnCallNotificationAlertingService.js +29 -7
  857. package/build/dist/Server/Services/OnCallNotificationAlertingService.js.map +1 -1
  858. package/build/dist/Server/Services/OnCallSetupReminderService.js +1 -0
  859. package/build/dist/Server/Services/OnCallSetupReminderService.js.map +1 -1
  860. package/build/dist/Server/Services/ProbeService.js +7 -1
  861. package/build/dist/Server/Services/ProbeService.js.map +1 -1
  862. package/build/dist/Server/Services/ProjectService.js +11 -1
  863. package/build/dist/Server/Services/ProjectService.js.map +1 -1
  864. package/build/dist/Server/Services/RunbookCredentialService.js +24 -0
  865. package/build/dist/Server/Services/RunbookCredentialService.js.map +1 -1
  866. package/build/dist/Server/Services/RunbookSecretService.js +44 -0
  867. package/build/dist/Server/Services/RunbookSecretService.js.map +1 -1
  868. package/build/dist/Server/Services/RunnerJobService.js +641 -21
  869. package/build/dist/Server/Services/RunnerJobService.js.map +1 -1
  870. package/build/dist/Server/Services/RunnerService.js +344 -5
  871. package/build/dist/Server/Services/RunnerService.js.map +1 -1
  872. package/build/dist/Server/Services/ScheduledMaintenancePublicNoteService.js +48 -0
  873. package/build/dist/Server/Services/ScheduledMaintenancePublicNoteService.js.map +1 -1
  874. package/build/dist/Server/Services/ScheduledMaintenanceService.js +102 -20
  875. package/build/dist/Server/Services/ScheduledMaintenanceService.js.map +1 -1
  876. package/build/dist/Server/Services/ScheduledMaintenanceTemplateService.js +67 -4
  877. package/build/dist/Server/Services/ScheduledMaintenanceTemplateService.js.map +1 -1
  878. package/build/dist/Server/Services/ServiceLevelObjectiveLabelRuleEngineService.js +295 -0
  879. package/build/dist/Server/Services/ServiceLevelObjectiveLabelRuleEngineService.js.map +1 -0
  880. package/build/dist/Server/Services/ServiceLevelObjectiveLabelRuleService.js +56 -0
  881. package/build/dist/Server/Services/ServiceLevelObjectiveLabelRuleService.js.map +1 -0
  882. package/build/dist/Server/Services/ServiceLevelObjectiveMonitorRuleEngineService.js +59 -14
  883. package/build/dist/Server/Services/ServiceLevelObjectiveMonitorRuleEngineService.js.map +1 -1
  884. package/build/dist/Server/Services/ServiceLevelObjectiveMonitorRuleService.js +22 -1
  885. package/build/dist/Server/Services/ServiceLevelObjectiveMonitorRuleService.js.map +1 -1
  886. package/build/dist/Server/Services/ServiceLevelObjectiveOwnerRuleEngineService.js +400 -0
  887. package/build/dist/Server/Services/ServiceLevelObjectiveOwnerRuleEngineService.js.map +1 -0
  888. package/build/dist/Server/Services/ServiceLevelObjectiveOwnerRuleService.js +56 -0
  889. package/build/dist/Server/Services/ServiceLevelObjectiveOwnerRuleService.js.map +1 -0
  890. package/build/dist/Server/Services/ServiceLevelObjectiveService.js +33 -1
  891. package/build/dist/Server/Services/ServiceLevelObjectiveService.js.map +1 -1
  892. package/build/dist/Server/Services/StatusPagePrivateUserService.js +1 -0
  893. package/build/dist/Server/Services/StatusPagePrivateUserService.js.map +1 -1
  894. package/build/dist/Server/Services/StatusPageService.js +230 -32
  895. package/build/dist/Server/Services/StatusPageService.js.map +1 -1
  896. package/build/dist/Server/Services/StatusPageSubscriberService.js +4 -0
  897. package/build/dist/Server/Services/StatusPageSubscriberService.js.map +1 -1
  898. package/build/dist/Server/Services/TeamMemberService.js +270 -11
  899. package/build/dist/Server/Services/TeamMemberService.js.map +1 -1
  900. package/build/dist/Server/Services/TraceAggregationService.js +10 -6
  901. package/build/dist/Server/Services/TraceAggregationService.js.map +1 -1
  902. package/build/dist/Server/Services/UserEmailService.js +1 -0
  903. package/build/dist/Server/Services/UserEmailService.js.map +1 -1
  904. package/build/dist/Server/Services/UserNotificationMethodAdminService.js +1 -0
  905. package/build/dist/Server/Services/UserNotificationMethodAdminService.js.map +1 -1
  906. package/build/dist/Server/Services/UserNotificationRuleAdminService.js +1 -0
  907. package/build/dist/Server/Services/UserNotificationRuleAdminService.js.map +1 -1
  908. package/build/dist/Server/Services/UserNotificationRuleService.js +4 -0
  909. package/build/dist/Server/Services/UserNotificationRuleService.js.map +1 -1
  910. package/build/dist/Server/Services/UserService.js +107 -1
  911. package/build/dist/Server/Services/UserService.js.map +1 -1
  912. package/build/dist/Server/Services/WorkflowVariableService.js +396 -7
  913. package/build/dist/Server/Services/WorkflowVariableService.js.map +1 -1
  914. package/build/dist/Server/Services/WorkspaceNotificationRuleService.js +463 -7
  915. package/build/dist/Server/Services/WorkspaceNotificationRuleService.js.map +1 -1
  916. package/build/dist/Server/Services/WorkspaceProjectAuthTokenService.js +144 -2
  917. package/build/dist/Server/Services/WorkspaceProjectAuthTokenService.js.map +1 -1
  918. package/build/dist/Server/Types/Database/QueryHelper.js +20 -0
  919. package/build/dist/Server/Types/Database/QueryHelper.js.map +1 -1
  920. package/build/dist/Server/Types/Markdown.js +394 -27
  921. package/build/dist/Server/Types/Markdown.js.map +1 -1
  922. package/build/dist/Server/Types/Workflow/Components/Telegram/SendMessageToChat.js +20 -1
  923. package/build/dist/Server/Types/Workflow/Components/Telegram/SendMessageToChat.js.map +1 -1
  924. package/build/dist/Server/Utils/AI/ClusterAccess/ClusterAccessContext.js +123 -0
  925. package/build/dist/Server/Utils/AI/ClusterAccess/ClusterAccessContext.js.map +1 -0
  926. package/build/dist/Server/Utils/AI/ClusterAccess/KubectlInvestigationToolkit.js +344 -0
  927. package/build/dist/Server/Utils/AI/ClusterAccess/KubectlInvestigationToolkit.js.map +1 -0
  928. package/build/dist/Server/Utils/AI/ClusterAccess/KubectlJobRunner.js +587 -0
  929. package/build/dist/Server/Utils/AI/ClusterAccess/KubectlJobRunner.js.map +1 -0
  930. package/build/dist/Server/Utils/AI/CodeFix/CodeFixAgentAuth.js +18 -2
  931. package/build/dist/Server/Utils/AI/CodeFix/CodeFixAgentAuth.js.map +1 -1
  932. package/build/dist/Server/Utils/AI/Remediation/RemediationCommandTools.js +1380 -239
  933. package/build/dist/Server/Utils/AI/Remediation/RemediationCommandTools.js.map +1 -1
  934. package/build/dist/Server/Utils/AI/Remediation/RemediationExecutionRunner.js +1099 -68
  935. package/build/dist/Server/Utils/AI/Remediation/RemediationExecutionRunner.js.map +1 -1
  936. package/build/dist/Server/Utils/AI/SRE/AIInvestigationEngine.js +88 -6
  937. package/build/dist/Server/Utils/AI/SRE/AIInvestigationEngine.js.map +1 -1
  938. package/build/dist/Server/Utils/AI/SRE/AlertInvestigationRunner.js +45 -11
  939. package/build/dist/Server/Utils/AI/SRE/AlertInvestigationRunner.js.map +1 -1
  940. package/build/dist/Server/Utils/AI/SRE/IncidentInvestigationRunner.js +41 -11
  941. package/build/dist/Server/Utils/AI/SRE/IncidentInvestigationRunner.js.map +1 -1
  942. package/build/dist/Server/Utils/AI/Toolbox/AIActionTools.js +11 -4
  943. package/build/dist/Server/Utils/AI/Toolbox/AIActionTools.js.map +1 -1
  944. package/build/dist/Server/Utils/AI/Toolbox/ResourceTools.js +4 -2
  945. package/build/dist/Server/Utils/AI/Toolbox/ResourceTools.js.map +1 -1
  946. package/build/dist/Server/Utils/AI/Toolbox/SloTools.js +1 -0
  947. package/build/dist/Server/Utils/AI/Toolbox/SloTools.js.map +1 -1
  948. package/build/dist/Server/Utils/AutoRemediation/CommandPlanExecutor.js +997 -141
  949. package/build/dist/Server/Utils/AutoRemediation/CommandPlanExecutor.js.map +1 -1
  950. package/build/dist/Server/Utils/AutoRemediation/RemediationVerifier.js +299 -4
  951. package/build/dist/Server/Utils/AutoRemediation/RemediationVerifier.js.map +1 -1
  952. package/build/dist/Server/Utils/Database/AffectedResourceRelations.js +120 -0
  953. package/build/dist/Server/Utils/Database/AffectedResourceRelations.js.map +1 -0
  954. package/build/dist/Server/Utils/Database/ProjectScopedReferenceValidator.js +160 -1
  955. package/build/dist/Server/Utils/Database/ProjectScopedReferenceValidator.js.map +1 -1
  956. package/build/dist/Server/Utils/EmailRollup/EmailRollupFlushRunner.js +1 -0
  957. package/build/dist/Server/Utils/EmailRollup/EmailRollupFlushRunner.js.map +1 -1
  958. package/build/dist/Server/Utils/Monitor/AffectedResourceList.js +22 -51
  959. package/build/dist/Server/Utils/Monitor/AffectedResourceList.js.map +1 -1
  960. package/build/dist/Server/Utils/Monitor/Criteria/CompareCriteria.js +1 -1
  961. package/build/dist/Server/Utils/Monitor/Criteria/MetricMonitorCriteria.js +1 -1
  962. package/build/dist/Server/Utils/Monitor/MonitorAlert.js +59 -12
  963. package/build/dist/Server/Utils/Monitor/MonitorAlert.js.map +1 -1
  964. package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js +139 -109
  965. package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js.map +1 -1
  966. package/build/dist/Server/Utils/Monitor/MonitorCriteriaObservationBuilder.js +5 -1
  967. package/build/dist/Server/Utils/Monitor/MonitorCriteriaObservationBuilder.js.map +1 -1
  968. package/build/dist/Server/Utils/Monitor/MonitorIncident.js +84 -22
  969. package/build/dist/Server/Utils/Monitor/MonitorIncident.js.map +1 -1
  970. package/build/dist/Server/Utils/Monitor/MonitorPayloadRedaction.js +70 -5
  971. package/build/dist/Server/Utils/Monitor/MonitorPayloadRedaction.js.map +1 -1
  972. package/build/dist/Server/Utils/Monitor/ProbeMonitorsNotification.js +249 -0
  973. package/build/dist/Server/Utils/Monitor/ProbeMonitorsNotification.js.map +1 -0
  974. package/build/dist/Server/Utils/Monitor/RootCauseList.js +101 -0
  975. package/build/dist/Server/Utils/Monitor/RootCauseList.js.map +1 -0
  976. package/build/dist/Server/Utils/OnCall/OnCallShiftReminderRunner.js +1 -0
  977. package/build/dist/Server/Utils/OnCall/OnCallShiftReminderRunner.js.map +1 -1
  978. package/build/dist/Server/Utils/PushNotificationUtil.js +27 -0
  979. package/build/dist/Server/Utils/PushNotificationUtil.js.map +1 -1
  980. package/build/dist/Server/Utils/Rules/OwnerRuleAssignment.js +26 -3
  981. package/build/dist/Server/Utils/Rules/OwnerRuleAssignment.js.map +1 -1
  982. package/build/dist/Server/Utils/Rules/RuleRun/RuleRunRegistry.js +28 -0
  983. package/build/dist/Server/Utils/Rules/RuleRun/RuleRunRegistry.js.map +1 -1
  984. package/build/dist/Server/Utils/Runbook/RunbookExecutePermission.js +38 -3
  985. package/build/dist/Server/Utils/Runbook/RunbookExecutePermission.js.map +1 -1
  986. package/build/dist/Server/Utils/SessionReplay/SessionReplayReadService.js +143 -23
  987. package/build/dist/Server/Utils/SessionReplay/SessionReplayReadService.js.map +1 -1
  988. package/build/dist/Server/Utils/SessionReplay/SessionReplayUserFlowReadService.js +406 -0
  989. package/build/dist/Server/Utils/SessionReplay/SessionReplayUserFlowReadService.js.map +1 -0
  990. package/build/dist/Server/Utils/Slo/SloRulePatternValidator.js +28 -0
  991. package/build/dist/Server/Utils/Slo/SloRulePatternValidator.js.map +1 -0
  992. package/build/dist/Server/Utils/StartServer.js +4 -3
  993. package/build/dist/Server/Utils/StartServer.js.map +1 -1
  994. package/build/dist/Server/Utils/TeamMember/ProjectLeaveResourceCleanup.js +382 -0
  995. package/build/dist/Server/Utils/TeamMember/ProjectLeaveResourceCleanup.js.map +1 -0
  996. package/build/dist/Server/Utils/TwoFactorBackupCodeNotification.js +1 -0
  997. package/build/dist/Server/Utils/TwoFactorBackupCodeNotification.js.map +1 -1
  998. package/build/dist/Server/Utils/UserPermission/UserPermission.js +10 -0
  999. package/build/dist/Server/Utils/UserPermission/UserPermission.js.map +1 -1
  1000. package/build/dist/Server/Utils/Workflow/OAuth2TokenClient.js +447 -0
  1001. package/build/dist/Server/Utils/Workflow/OAuth2TokenClient.js.map +1 -0
  1002. package/build/dist/Server/Utils/Workflow/WorkflowVariableOAuthToken.js +202 -0
  1003. package/build/dist/Server/Utils/Workflow/WorkflowVariableOAuthToken.js.map +1 -0
  1004. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/Alert.js +39 -1
  1005. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/Alert.js.map +1 -1
  1006. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/AlertEpisode.js +44 -4
  1007. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/AlertEpisode.js.map +1 -1
  1008. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/Incident.js +150 -191
  1009. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/Incident.js.map +1 -1
  1010. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/IncidentEpisode.js +44 -4
  1011. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/IncidentEpisode.js.map +1 -1
  1012. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/Monitor.js +39 -17
  1013. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/Monitor.js.map +1 -1
  1014. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/ScheduledMaintenance.js +151 -145
  1015. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/ScheduledMaintenance.js.map +1 -1
  1016. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js +221 -127
  1017. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js.map +1 -1
  1018. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsServiceUrl.js +91 -0
  1019. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsServiceUrl.js.map +1 -0
  1020. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/ReactionNoteSync.js +673 -0
  1021. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/ReactionNoteSync.js.map +1 -0
  1022. package/build/dist/Server/Utils/Workspace/Slack/Actions/ActionTypes.js +3 -9
  1023. package/build/dist/Server/Utils/Workspace/Slack/Actions/ActionTypes.js.map +1 -1
  1024. package/build/dist/Server/Utils/Workspace/Slack/Actions/Alert.js +65 -166
  1025. package/build/dist/Server/Utils/Workspace/Slack/Actions/Alert.js.map +1 -1
  1026. package/build/dist/Server/Utils/Workspace/Slack/Actions/AlertEpisode.js +63 -157
  1027. package/build/dist/Server/Utils/Workspace/Slack/Actions/AlertEpisode.js.map +1 -1
  1028. package/build/dist/Server/Utils/Workspace/Slack/Actions/Auth.js +23 -3
  1029. package/build/dist/Server/Utils/Workspace/Slack/Actions/Auth.js.map +1 -1
  1030. package/build/dist/Server/Utils/Workspace/Slack/Actions/Authorization.js +92 -0
  1031. package/build/dist/Server/Utils/Workspace/Slack/Actions/Authorization.js.map +1 -0
  1032. package/build/dist/Server/Utils/Workspace/Slack/Actions/Incident.js +81 -210
  1033. package/build/dist/Server/Utils/Workspace/Slack/Actions/Incident.js.map +1 -1
  1034. package/build/dist/Server/Utils/Workspace/Slack/Actions/IncidentEpisode.js +68 -138
  1035. package/build/dist/Server/Utils/Workspace/Slack/Actions/IncidentEpisode.js.map +1 -1
  1036. package/build/dist/Server/Utils/Workspace/Slack/Actions/ReactionNote.js +240 -0
  1037. package/build/dist/Server/Utils/Workspace/Slack/Actions/ReactionNote.js.map +1 -0
  1038. package/build/dist/Server/Utils/Workspace/Slack/Actions/ScheduledMaintenance.js +85 -212
  1039. package/build/dist/Server/Utils/Workspace/Slack/Actions/ScheduledMaintenance.js.map +1 -1
  1040. package/build/dist/Server/Utils/Workspace/Slack/Slack.js +60 -17
  1041. package/build/dist/Server/Utils/Workspace/Slack/Slack.js.map +1 -1
  1042. package/build/dist/Server/Utils/Workspace/Slack/app-manifest.json +2 -0
  1043. package/build/dist/Server/Utils/Workspace/Workspace.js +134 -41
  1044. package/build/dist/Server/Utils/Workspace/Workspace.js.map +1 -1
  1045. package/build/dist/Server/Utils/Workspace/WorkspaceActionAuthorization.js +197 -0
  1046. package/build/dist/Server/Utils/Workspace/WorkspaceActionAuthorization.js.map +1 -0
  1047. package/build/dist/Server/Utils/Workspace/WorkspaceBase.js +32 -0
  1048. package/build/dist/Server/Utils/Workspace/WorkspaceBase.js.map +1 -1
  1049. package/build/dist/Server/Utils/Workspace/WorkspaceOAuthState.js +199 -0
  1050. package/build/dist/Server/Utils/Workspace/WorkspaceOAuthState.js.map +1 -0
  1051. package/build/dist/Server/Utils/Workspace/WorkspaceProjectReferenceValidator.js +91 -0
  1052. package/build/dist/Server/Utils/Workspace/WorkspaceProjectReferenceValidator.js.map +1 -0
  1053. package/build/dist/Server/Utils/Workspace/WorkspaceReactionNote.js +450 -0
  1054. package/build/dist/Server/Utils/Workspace/WorkspaceReactionNote.js.map +1 -0
  1055. package/build/dist/Types/API/Route.js +18 -2
  1056. package/build/dist/Types/API/Route.js.map +1 -1
  1057. package/build/dist/Types/API/URL.js +23 -2
  1058. package/build/dist/Types/API/URL.js.map +1 -1
  1059. package/build/dist/Types/AutoRemediation/AiRemediationCommandPlan.js +103 -5
  1060. package/build/dist/Types/AutoRemediation/AiRemediationCommandPlan.js.map +1 -1
  1061. package/build/dist/Types/Date.js +97 -7
  1062. package/build/dist/Types/Date.js.map +1 -1
  1063. package/build/dist/Types/Email/EmailTemplateType.js +1 -0
  1064. package/build/dist/Types/Email/EmailTemplateType.js.map +1 -1
  1065. package/build/dist/Types/Exception/ExceptionMessages.js +1 -0
  1066. package/build/dist/Types/Exception/ExceptionMessages.js.map +1 -1
  1067. package/build/dist/Types/Kubernetes/KubernetesClusterAiAccess.js +245 -0
  1068. package/build/dist/Types/Kubernetes/KubernetesClusterAiAccess.js.map +1 -0
  1069. package/build/dist/Types/Kubernetes/KubernetesClusterAiAccessPermissions.js +49 -0
  1070. package/build/dist/Types/Kubernetes/KubernetesClusterAiAccessPermissions.js.map +1 -0
  1071. package/build/dist/Types/Kubernetes/KubernetesClusterAiAccessToolNames.js +16 -0
  1072. package/build/dist/Types/Kubernetes/KubernetesClusterAiAccessToolNames.js.map +1 -0
  1073. package/build/dist/Types/Monitor/DatabaseMonitor/SqlServerPlatform.js +104 -0
  1074. package/build/dist/Types/Monitor/DatabaseMonitor/SqlServerPlatform.js.map +1 -0
  1075. package/build/dist/Types/Monitor/KubernetesAlertTemplates.js +6 -5
  1076. package/build/dist/Types/Monitor/KubernetesAlertTemplates.js.map +1 -1
  1077. package/build/dist/Types/Monitor/MonitorStepExceptionMonitor.js +32 -0
  1078. package/build/dist/Types/Monitor/MonitorStepExceptionMonitor.js.map +1 -1
  1079. package/build/dist/Types/Monitor/MonitorUptimeSummary.js +52 -0
  1080. package/build/dist/Types/Monitor/MonitorUptimeSummary.js.map +1 -0
  1081. package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationUtil.js +9 -1
  1082. package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationUtil.js.map +1 -1
  1083. package/build/dist/Types/Permission.js +84 -0
  1084. package/build/dist/Types/Permission.js.map +1 -1
  1085. package/build/dist/Types/Rules/RuleCriteriaFieldRegistry.js +11 -0
  1086. package/build/dist/Types/Rules/RuleCriteriaFieldRegistry.js.map +1 -1
  1087. package/build/dist/Types/Rules/RuleRun.js +4 -0
  1088. package/build/dist/Types/Rules/RuleRun.js.map +1 -1
  1089. package/build/dist/Types/Rum/SessionReplay.js +52 -2
  1090. package/build/dist/Types/Rum/SessionReplay.js.map +1 -1
  1091. package/build/dist/Types/Rum/SessionReplayApi.js +11 -0
  1092. package/build/dist/Types/Rum/SessionReplayApi.js.map +1 -1
  1093. package/build/dist/Types/Rum/UserFlow.js +115 -0
  1094. package/build/dist/Types/Rum/UserFlow.js.map +1 -0
  1095. package/build/dist/Types/Runbook/RunbookStepType.js +10 -0
  1096. package/build/dist/Types/Runbook/RunbookStepType.js.map +1 -1
  1097. package/build/dist/Types/Runbook/RunnerJobOrigin.js +14 -0
  1098. package/build/dist/Types/Runbook/RunnerJobOrigin.js.map +1 -1
  1099. package/build/dist/Types/SecurityEvent/Connectors/SecurityEventConnectorCatalog.js +2 -2
  1100. package/build/dist/Types/SecurityEvent/Connectors/SecurityEventConnectorCatalog.js.map +1 -1
  1101. package/build/dist/Types/StatusPage/MergedDowntimeTotals.js +2 -0
  1102. package/build/dist/Types/StatusPage/MergedDowntimeTotals.js.map +1 -0
  1103. package/build/dist/Types/StatusPage/PublicNoteSubscriberNotificationDefault.js +65 -0
  1104. package/build/dist/Types/StatusPage/PublicNoteSubscriberNotificationDefault.js.map +1 -0
  1105. package/build/dist/Types/Telemetry/TelemetryIngestSurface.js +8 -0
  1106. package/build/dist/Types/Telemetry/TelemetryIngestSurface.js.map +1 -1
  1107. package/build/dist/Types/Timezone.js +5 -0
  1108. package/build/dist/Types/Timezone.js.map +1 -1
  1109. package/build/dist/Types/TimezoneAlias.js +340 -0
  1110. package/build/dist/Types/TimezoneAlias.js.map +1 -0
  1111. package/build/dist/Types/Workflow/Templates.js +2694 -2
  1112. package/build/dist/Types/Workflow/Templates.js.map +1 -1
  1113. package/build/dist/Types/Workflow/WorkflowVariableOAuth.js +314 -0
  1114. package/build/dist/Types/Workflow/WorkflowVariableOAuth.js.map +1 -0
  1115. package/build/dist/Types/Workspace/WorkspaceNoteReaction.js +98 -0
  1116. package/build/dist/Types/Workspace/WorkspaceNoteReaction.js.map +1 -0
  1117. package/build/dist/UI/Components/AttributesJSON/AttributesJSONPreferences.js +95 -0
  1118. package/build/dist/UI/Components/AttributesJSON/AttributesJSONPreferences.js.map +1 -0
  1119. package/build/dist/UI/Components/AttributesJSON/AttributesJSONView.js +44 -0
  1120. package/build/dist/UI/Components/AttributesJSON/AttributesJSONView.js.map +1 -0
  1121. package/build/dist/UI/Components/AttributesJSON/AttributesViewToggle.js +27 -0
  1122. package/build/dist/UI/Components/AttributesJSON/AttributesViewToggle.js.map +1 -0
  1123. package/build/dist/UI/Components/AttributesJSON/BracesGlyph.js +9 -0
  1124. package/build/dist/UI/Components/AttributesJSON/BracesGlyph.js.map +1 -0
  1125. package/build/dist/UI/Components/AttributesJSON/CopyAttributesAsJSONButton.js +260 -0
  1126. package/build/dist/UI/Components/AttributesJSON/CopyAttributesAsJSONButton.js.map +1 -0
  1127. package/build/dist/UI/Components/AttributesJSON/JSONHighlight.js +56 -0
  1128. package/build/dist/UI/Components/AttributesJSON/JSONHighlight.js.map +1 -0
  1129. package/build/dist/UI/Components/Calendar/Calendar.js +94 -7
  1130. package/build/dist/UI/Components/Calendar/Calendar.js.map +1 -1
  1131. package/build/dist/UI/Components/Calendar/CalendarDayLayout.js +136 -0
  1132. package/build/dist/UI/Components/Calendar/CalendarDayLayout.js.map +1 -0
  1133. package/build/dist/UI/Components/Charts/ChartGroup/ChartGroup.js +1 -1
  1134. package/build/dist/UI/Components/Charts/ChartGroup/ChartGroup.js.map +1 -1
  1135. package/build/dist/UI/Components/Charts/Utils/HistogramSelection.js +72 -0
  1136. package/build/dist/UI/Components/Charts/Utils/HistogramSelection.js.map +1 -0
  1137. package/build/dist/UI/Components/Charts/Utils/useHistogramRangeSelection.js +178 -0
  1138. package/build/dist/UI/Components/Charts/Utils/useHistogramRangeSelection.js.map +1 -0
  1139. package/build/dist/UI/Components/Charts/Utils/useHistogramZoom.js +13 -1
  1140. package/build/dist/UI/Components/Charts/Utils/useHistogramZoom.js.map +1 -1
  1141. package/build/dist/UI/Components/Date/CustomTimeRangeModal.js +20 -4
  1142. package/build/dist/UI/Components/Date/CustomTimeRangeModal.js.map +1 -1
  1143. package/build/dist/UI/Components/Dropdown/Dropdown.js +33 -9
  1144. package/build/dist/UI/Components/Dropdown/Dropdown.js.map +1 -1
  1145. package/build/dist/UI/Components/Feed/FeedOptions.js +235 -0
  1146. package/build/dist/UI/Components/Feed/FeedOptions.js.map +1 -0
  1147. package/build/dist/UI/Components/Feed/FeedOptionsButton.js +346 -0
  1148. package/build/dist/UI/Components/Feed/FeedOptionsButton.js.map +1 -0
  1149. package/build/dist/UI/Components/Feed/useFeedItems.js +17 -7
  1150. package/build/dist/UI/Components/Feed/useFeedItems.js.map +1 -1
  1151. package/build/dist/UI/Components/Feed/useFeedOptions.js +130 -0
  1152. package/build/dist/UI/Components/Feed/useFeedOptions.js.map +1 -0
  1153. package/build/dist/UI/Components/Forms/Fields/FormField.js +36 -13
  1154. package/build/dist/UI/Components/Forms/Fields/FormField.js.map +1 -1
  1155. package/build/dist/UI/Components/Graphs/DayUptimeGraph.js +117 -11
  1156. package/build/dist/UI/Components/Graphs/DayUptimeGraph.js.map +1 -1
  1157. package/build/dist/UI/Components/Graphs/UptimeBarTooltip.js +5 -1
  1158. package/build/dist/UI/Components/Graphs/UptimeBarTooltip.js.map +1 -1
  1159. package/build/dist/UI/Components/Graphs/UptimeDaySummary.js.map +1 -1
  1160. package/build/dist/UI/Components/Icon/Icon.js +1 -1
  1161. package/build/dist/UI/Components/Icon/Icon.js.map +1 -1
  1162. package/build/dist/UI/Components/LogsViewer/LogsViewer.js +36 -8
  1163. package/build/dist/UI/Components/LogsViewer/LogsViewer.js.map +1 -1
  1164. package/build/dist/UI/Components/LogsViewer/components/ColumnSelector.js +10 -2
  1165. package/build/dist/UI/Components/LogsViewer/components/ColumnSelector.js.map +1 -1
  1166. package/build/dist/UI/Components/LogsViewer/components/KeyboardShortcutsHelp.js +9 -1
  1167. package/build/dist/UI/Components/LogsViewer/components/KeyboardShortcutsHelp.js.map +1 -1
  1168. package/build/dist/UI/Components/LogsViewer/components/LogDetailsPanel.js +16 -15
  1169. package/build/dist/UI/Components/LogsViewer/components/LogDetailsPanel.js.map +1 -1
  1170. package/build/dist/UI/Components/LogsViewer/components/LogsFacetSidebar.js +1 -1
  1171. package/build/dist/UI/Components/LogsViewer/components/LogsFacetSidebar.js.map +1 -1
  1172. package/build/dist/UI/Components/LogsViewer/components/LogsHistogram.js +14 -74
  1173. package/build/dist/UI/Components/LogsViewer/components/LogsHistogram.js.map +1 -1
  1174. package/build/dist/UI/Components/LogsViewer/components/LogsViewerToolbar.js +22 -5
  1175. package/build/dist/UI/Components/LogsViewer/components/LogsViewerToolbar.js.map +1 -1
  1176. package/build/dist/UI/Components/LogsViewer/components/SavedViewsDropdown.js +9 -2
  1177. package/build/dist/UI/Components/LogsViewer/components/SavedViewsDropdown.js.map +1 -1
  1178. package/build/dist/UI/Components/LogsViewer/useLogsHistogram.js +16 -5
  1179. package/build/dist/UI/Components/LogsViewer/useLogsHistogram.js.map +1 -1
  1180. package/build/dist/UI/Components/ModelTable/BaseModelTable.js +23 -8
  1181. package/build/dist/UI/Components/ModelTable/BaseModelTable.js.map +1 -1
  1182. package/build/dist/UI/Components/MonitorGraphs/Uptime.js +7 -1
  1183. package/build/dist/UI/Components/MonitorGraphs/Uptime.js.map +1 -1
  1184. package/build/dist/UI/Components/MonitorGraphs/UptimeBarDayModal.js +5 -1
  1185. package/build/dist/UI/Components/MonitorGraphs/UptimeBarDayModal.js.map +1 -1
  1186. package/build/dist/UI/Components/Page/ModelPage.js +37 -3
  1187. package/build/dist/UI/Components/Page/ModelPage.js.map +1 -1
  1188. package/build/dist/UI/Components/TelemetryViewer/TelemetryViewer.js +27 -6
  1189. package/build/dist/UI/Components/TelemetryViewer/TelemetryViewer.js.map +1 -1
  1190. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryDetailPanel.js +7 -1
  1191. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryDetailPanel.js.map +1 -1
  1192. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryFacetSidebar.js +1 -1
  1193. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryFacetSidebar.js.map +1 -1
  1194. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryHistogram.js +17 -77
  1195. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryHistogram.js.map +1 -1
  1196. package/build/dist/UI/Components/TelemetryViewer/components/TelemetrySearchBar.js +10 -1
  1197. package/build/dist/UI/Components/TelemetryViewer/components/TelemetrySearchBar.js.map +1 -1
  1198. package/build/dist/UI/Utils/ModelAPI/ProjectUsersModelAPI.js +15 -1
  1199. package/build/dist/UI/Utils/ModelAPI/ProjectUsersModelAPI.js.map +1 -1
  1200. package/build/dist/UI/Utils/Timezone.js +52 -17
  1201. package/build/dist/UI/Utils/Timezone.js.map +1 -1
  1202. package/build/dist/Utils/AI/InvestigationReport.js +116 -21
  1203. package/build/dist/Utils/AI/InvestigationReport.js.map +1 -1
  1204. package/build/dist/Utils/AiRemediation/KubectlOutputRedactor.js +1209 -0
  1205. package/build/dist/Utils/AiRemediation/KubectlOutputRedactor.js.map +1 -0
  1206. package/build/dist/Utils/AiRemediation/KubectlPolicy.js +2973 -0
  1207. package/build/dist/Utils/AiRemediation/KubectlPolicy.js.map +1 -0
  1208. package/build/dist/Utils/AiRemediation/KubectlWaitBudget.js +99 -0
  1209. package/build/dist/Utils/AiRemediation/KubectlWaitBudget.js.map +1 -0
  1210. package/build/dist/Utils/AiRemediation/KubectlWriteScope.js +1429 -0
  1211. package/build/dist/Utils/AiRemediation/KubectlWriteScope.js.map +1 -0
  1212. package/build/dist/Utils/Dashboard/Components/DashboardClockComponent.js +7 -6
  1213. package/build/dist/Utils/Dashboard/Components/DashboardClockComponent.js.map +1 -1
  1214. package/build/dist/Utils/LabelRuleImportExport.js +22 -6
  1215. package/build/dist/Utils/LabelRuleImportExport.js.map +1 -1
  1216. package/build/dist/Utils/Monitor/IncomingEmailMonitorAddress.js +214 -0
  1217. package/build/dist/Utils/Monitor/IncomingEmailMonitorAddress.js.map +1 -0
  1218. package/build/dist/Utils/Monitor/MetricValueFormatter.js +2 -2
  1219. package/build/dist/Utils/Monitor/MonitorCheckScheduleUtil.js +471 -0
  1220. package/build/dist/Utils/Monitor/MonitorCheckScheduleUtil.js.map +1 -0
  1221. package/build/dist/Utils/Monitor/MonitorOverviewCriteriaUtil.js +107 -0
  1222. package/build/dist/Utils/Monitor/MonitorOverviewCriteriaUtil.js.map +1 -0
  1223. package/build/dist/Utils/Monitor/MonitorOverviewFamily.js +191 -0
  1224. package/build/dist/Utils/Monitor/MonitorOverviewFamily.js.map +1 -0
  1225. package/build/dist/Utils/Monitor/MonitorOverviewPresentationUtil.js +1259 -0
  1226. package/build/dist/Utils/Monitor/MonitorOverviewPresentationUtil.js.map +1 -0
  1227. package/build/dist/Utils/Monitor/MonitorOverviewProbeUtil.js +593 -0
  1228. package/build/dist/Utils/Monitor/MonitorOverviewProbeUtil.js.map +1 -0
  1229. package/build/dist/Utils/Monitor/MonitorOverviewTargetUtil.js +195 -0
  1230. package/build/dist/Utils/Monitor/MonitorOverviewTargetUtil.js.map +1 -0
  1231. package/build/dist/Utils/Monitor/MonitorStatusHistoryUtil.js +127 -0
  1232. package/build/dist/Utils/Monitor/MonitorStatusHistoryUtil.js.map +1 -0
  1233. package/build/dist/Utils/Monitor/MonitorUptimeSummaryUtil.js +464 -0
  1234. package/build/dist/Utils/Monitor/MonitorUptimeSummaryUtil.js.map +1 -0
  1235. package/build/dist/Utils/Rules/MonitorTypeRuleCriteria.js +18 -0
  1236. package/build/dist/Utils/Rules/MonitorTypeRuleCriteria.js.map +1 -0
  1237. package/build/dist/Utils/Rum/SessionIdentity.js +31 -1
  1238. package/build/dist/Utils/Rum/SessionIdentity.js.map +1 -1
  1239. package/build/dist/Utils/Rum/SessionReplayWireEncoding.js +128 -0
  1240. package/build/dist/Utils/Rum/SessionReplayWireEncoding.js.map +1 -0
  1241. package/build/dist/Utils/Rum/UserFlow.js +941 -0
  1242. package/build/dist/Utils/Rum/UserFlow.js.map +1 -0
  1243. package/build/dist/Utils/Slo/SloDuration.js +13 -5
  1244. package/build/dist/Utils/Slo/SloDuration.js.map +1 -1
  1245. package/build/dist/Utils/Slo/SloHealth.js +8 -7
  1246. package/build/dist/Utils/Slo/SloHealth.js.map +1 -1
  1247. package/build/dist/Utils/Slo/SloMonitorRuleCriteria.js +16 -1
  1248. package/build/dist/Utils/Slo/SloMonitorRuleCriteria.js.map +1 -1
  1249. package/build/dist/Utils/Slo/SloOverviewText.js +16 -0
  1250. package/build/dist/Utils/Slo/SloOverviewText.js.map +1 -1
  1251. package/build/dist/Utils/Slo/SloProjection.js.map +1 -1
  1252. package/build/dist/Utils/StatusPage/MonitorGroupMergedDowntimeUtil.js +82 -0
  1253. package/build/dist/Utils/StatusPage/MonitorGroupMergedDowntimeUtil.js.map +1 -0
  1254. package/build/dist/Utils/StatusPage/ResourceUptime.js +46 -0
  1255. package/build/dist/Utils/StatusPage/ResourceUptime.js.map +1 -1
  1256. package/build/dist/Utils/StatusPage/UptimeDailyAggregateUtil.js +148 -0
  1257. package/build/dist/Utils/StatusPage/UptimeDailyAggregateUtil.js.map +1 -1
  1258. package/build/dist/Utils/Telemetry/AttributesJSON.js +245 -0
  1259. package/build/dist/Utils/Telemetry/AttributesJSON.js.map +1 -0
  1260. package/build/dist/Utils/Uptime/DayUptimeGraphUtil.js +103 -0
  1261. package/build/dist/Utils/Uptime/DayUptimeGraphUtil.js.map +1 -1
  1262. package/build/dist/Utils/Uptime/UptimeUtil.js +91 -27
  1263. package/build/dist/Utils/Uptime/UptimeUtil.js.map +1 -1
  1264. package/jest.config.json +2 -1
  1265. package/package.json +2 -1
  1266. package/tsconfig.tests.json +36 -0
  1267. package/Tests/UI/Components/EmptyState/EmptyStateGuideLinks.test.tsx +0 -337
  1268. package/UI/Components/EmptyState/EmptyStateGuideLinks.tsx +0 -124
  1269. package/build/dist/UI/Components/EmptyState/EmptyStateGuideLinks.js +0 -47
  1270. package/build/dist/UI/Components/EmptyState/EmptyStateGuideLinks.js.map +0 -1
@@ -0,0 +1,1943 @@
1
+ import Alert from "../../Models/DatabaseModels/Alert";
2
+ import Incident from "../../Models/DatabaseModels/Incident";
3
+ import KubernetesCluster from "../../Models/DatabaseModels/KubernetesCluster";
4
+ import Monitor from "../../Models/DatabaseModels/Monitor";
5
+ import Project from "../../Models/DatabaseModels/Project";
6
+ import RunbookCredential from "../../Models/DatabaseModels/RunbookCredential";
7
+ import Runner, {
8
+ RunnerConnectionStatus,
9
+ } from "../../Models/DatabaseModels/Runner";
10
+ import BadDataException from "../../Types/Exception/BadDataException";
11
+ import ForbiddenException from "../../Types/Exception/ForbiddenException";
12
+ import TooManyRequestsException from "../../Types/Exception/TooManyRequestsException";
13
+ import ColumnLength from "../../Types/Database/ColumnLength";
14
+ import OneUptimeDate from "../../Types/Date";
15
+ import { JSONObject } from "../../Types/JSON";
16
+ import ObjectID from "../../Types/ObjectID";
17
+ import Version from "../../Types/Version";
18
+ import MonitorStep from "../../Types/Monitor/MonitorStep";
19
+ import { getDeletedAgentRunnerRebindNote } from "../../Types/Kubernetes/KubernetesClusterAiAccessPermissions";
20
+ import RunbookCredentialType from "../../Types/Runbook/RunbookCredentialType";
21
+ import {
22
+ RUNNER_ALIVE_WINDOW_IN_MINUTES,
23
+ RunnerLiveStatus,
24
+ getRunnerLiveStatus,
25
+ } from "../../Types/Runner/RunnerLiveStatus";
26
+ import {
27
+ KUBERNETES_AGENT_RUNNER_NAME_PREFIX,
28
+ KubernetesAgentRegistrationRefusalReason,
29
+ KubernetesAgentRunnerBindingState,
30
+ KubernetesAiAccessGap,
31
+ KubernetesAiRemediationMode,
32
+ KubernetesClusterAiAccessStatus,
33
+ KubernetesRunnerPosture,
34
+ isInClusterPostureForCluster,
35
+ isSameKubernetesClusterIdentifier,
36
+ normalizeKubernetesClusterIdentifier,
37
+ parseKubernetesRunnerPosture,
38
+ } from "../../Types/Kubernetes/KubernetesClusterAiAccess";
39
+ import { KubernetesClusterFeedEventType } from "../../Models/DatabaseModels/KubernetesClusterFeed";
40
+ import { Blue500, Green500, Yellow500 } from "../../Types/BrandColors";
41
+ import QueryHelper from "../Types/Database/QueryHelper";
42
+ import AlertService from "./AlertService";
43
+ import IncidentService from "./IncidentService";
44
+ import KubernetesClusterFeedService from "./KubernetesClusterFeedService";
45
+ import KubernetesClusterService from "./KubernetesClusterService";
46
+ import LlmProviderService from "./LlmProviderService";
47
+ import MonitorService from "./MonitorService";
48
+ import ProjectService from "./ProjectService";
49
+ import RunbookCredentialService from "./RunbookCredentialService";
50
+ import RunbookSecretService from "./RunbookSecretService";
51
+ import RunnerService, {
52
+ Service as RunnerServiceClass,
53
+ getKubernetesAgentRunnerNameForCluster,
54
+ } from "./RunnerService";
55
+ import CaptureSpan from "../Utils/Telemetry/CaptureSpan";
56
+ import logger from "../Utils/Logger";
57
+ import crypto from "crypto";
58
+
59
+ /*
60
+ * The agent Runner's name for a cluster, and the Runner name column bound.
61
+ * Defined next to the Runner guards that key on it (RunnerService) and
62
+ * re-exported here, where registration and its callers have always found
63
+ * them.
64
+ */
65
+ export {
66
+ MAX_KUBERNETES_AGENT_RUNNER_NAME_LENGTH,
67
+ getKubernetesAgentRunnerNameForCluster,
68
+ } from "./RunnerService";
69
+
70
+ /*
71
+ * OneUptime AI access to Kubernetes clusters.
72
+ *
73
+ * Answers, from CURRENT configuration, whether AI can reach a cluster with
74
+ * kubectl and what it may do there — and turns every reason it cannot into a
75
+ * row of a checklist with a next step. The same status feeds the cluster's
76
+ * AI page, the investigation panel ("we could not access the cluster, here
77
+ * is why") and the AI runs themselves (which only ever act on a cluster this
78
+ * module calls ready).
79
+ *
80
+ * It also binds the in-cluster Runner the kubernetes-agent chart installs:
81
+ * that Runner registers with the project's telemetry ingestion key and the
82
+ * cluster's name, and this module upserts its Runner row and points the
83
+ * cluster at it. One helm flag, no dashboard steps.
84
+ */
85
+
86
+ export interface KubernetesClusterAiAccessProjectGates {
87
+ isAiEnabled: boolean;
88
+ isAutoRemediationEnabled: boolean;
89
+ isAiCommandExecutionEnabled: boolean;
90
+ hasLlmProvider: boolean;
91
+ }
92
+
93
+ export interface RegisterKubernetesAgentRunnerResult {
94
+ runnerId: ObjectID;
95
+ runnerKey: string;
96
+ clusterId: ObjectID;
97
+ /*
98
+ * False when the cluster is bound to a DIFFERENT Runner that an operator
99
+ * chose in the dashboard, or when a cluster that had a Runner bound before
100
+ * has none now (an operator cleared it, or its Runner was deleted). The
101
+ * agent Runner row still exists and heartbeats, but the dashboard is the
102
+ * control plane: it never silently rebinds.
103
+ */
104
+ isBoundToCluster: boolean;
105
+ isFirstBind: boolean;
106
+ bindingState: KubernetesAgentRunnerBindingState;
107
+ }
108
+
109
+ /*
110
+ * Ceiling on agent Runner rows one project may hold, and on how many new
111
+ * ones may be minted per hour. Registration is authenticated by the
112
+ * project's telemetry ingestion key — a credential every collector and CI
113
+ * job holds — and every distinct clusterName creates a Runner row with the
114
+ * AI-commands capability on, so the rows must be bounded like any other
115
+ * thing an ingestion key can create. A legitimate fleet-wide install that
116
+ * trips the hourly brake is only delayed: the pod retries registration
117
+ * with backoff until it is admitted.
118
+ */
119
+ export const MAX_KUBERNETES_AGENT_RUNNERS_PER_PROJECT: number = 250;
120
+ export const MAX_NEW_KUBERNETES_AGENT_RUNNERS_PER_PROJECT_PER_HOUR: number = 30;
121
+
122
+ // What the status computation reads off a cluster row.
123
+ export const CLUSTER_AI_ACCESS_SELECT: Record<string, boolean> = {
124
+ _id: true,
125
+ projectId: true,
126
+ name: true,
127
+ clusterIdentifier: true,
128
+ aiAccessRunnerId: true,
129
+ aiAccessCredentialId: true,
130
+ isAiInvestigationEnabled: true,
131
+ aiRemediationMode: true,
132
+ aiKubectlCommandAllowlist: true,
133
+ aiAccessLastVerifiedAt: true,
134
+ aiAccessLastError: true,
135
+ aiAccessConfiguredAt: true,
136
+ aiAccessRunnerBoundAt: true,
137
+ isArchived: true,
138
+ };
139
+
140
+ const MAX_CLUSTERS_PER_SUBJECT: number = 10;
141
+
142
+ /*
143
+ * What to do about an in-cluster Runner that reports read-only RBAC while
144
+ * remediation is on. It points at the AI page's write-access section, which
145
+ * carries the complete helm commands (a bare --set line would miss the
146
+ * chart index refresh and --reuse-values), and names the two values that
147
+ * bound what the write role reaches: the namespaces it is bound in and the
148
+ * node switch. Shown verbatim on incident pages too, so it names the page
149
+ * rather than saying "this page".
150
+ */
151
+ export const REMEDIATION_WRITE_ACCESS_NEXT_STEP: string =
152
+ 'Grant the in-cluster Runner write access with a helm upgrade that adds --set aiAccess.remediation.enabled=true; the complete commands are under "Let AI apply fixes (write access)" on the cluster\'s AI page. List the namespaces AI may fix in aiAccess.remediation.namespaces (without it the write role is bound cluster-wide), and add aiAccess.remediation.nodeOperations=false to keep fixes off nodes.';
153
+
154
+ /*
155
+ * Why deleting an in-cluster Runner is a two-step remedy (the helper lives
156
+ * with the permissions it names, so RunnerService can use it too).
157
+ */
158
+ export { getDeletedAgentRunnerRebindNote };
159
+
160
+ /*
161
+ * Runner.name and KubernetesCluster.clusterIdentifier are both ShortText
162
+ * columns. A cluster name longer than the column can never become a cluster
163
+ * row, so registration refuses it up front with a message that says so.
164
+ */
165
+ export const MAX_KUBERNETES_CLUSTER_IDENTIFIER_LENGTH: number =
166
+ ColumnLength.ShortText;
167
+
168
+ /*
169
+ * A 403 from POST /runner-ingest/register-kubernetes-agent that says WHICH
170
+ * refusal it is (KubernetesAgentRegistrationRefusalReason), so the Runner can
171
+ * tell a wait that clears on its own from one that needs an operator instead
172
+ * of reading every 403 as "the previous instance is still online". The
173
+ * ingress sends `reason` (and, for previous_instance_online,
174
+ * `retryAfterSeconds` plus a Retry-After header) in the JSON error body.
175
+ */
176
+ export class KubernetesAgentRegistrationRefusedException extends ForbiddenException {
177
+ public readonly reason: KubernetesAgentRegistrationRefusalReason;
178
+ // Set only for a refusal that clears on its own: when to try again.
179
+ public readonly retryAfterSeconds: number | undefined;
180
+
181
+ public constructor(data: {
182
+ message: string;
183
+ reason: KubernetesAgentRegistrationRefusalReason;
184
+ retryAfterSeconds?: number | undefined;
185
+ }) {
186
+ super(data.message);
187
+ this.reason = data.reason;
188
+ this.retryAfterSeconds = data.retryAfterSeconds;
189
+ }
190
+ }
191
+
192
+ /*
193
+ * When a registration refused because the previous instance is online may
194
+ * try again: once that instance's last heartbeat is older than the alive
195
+ * window. Never less than a second, so a Runner never retries in a loop.
196
+ */
197
+ export function getPreviousInstanceRetryAfterSeconds(data: {
198
+ lastAlive: Date | undefined;
199
+ now?: Date | undefined;
200
+ }): number {
201
+ if (!data.lastAlive) {
202
+ return 1;
203
+ }
204
+
205
+ const admittedAt: number =
206
+ data.lastAlive.getTime() + RUNNER_ALIVE_WINDOW_IN_MINUTES * 60 * 1000;
207
+ const now: number = (data.now || OneUptimeDate.getCurrentDate()).getTime();
208
+
209
+ return Math.max(1, Math.ceil((admittedAt - now) / 1000));
210
+ }
211
+
212
+ /*
213
+ * One thing an agent Runner row holds beyond what registration gave it, and
214
+ * what an operator does under Project Settings → Runners to remove it.
215
+ */
216
+ export interface AgentRunnerHolding {
217
+ description: string;
218
+ remedy: string;
219
+ }
220
+
221
+ /*
222
+ * How a registration that re-keys an existing agent Runner row was admitted.
223
+ *
224
+ * continuity: it presented the row's current key — the same Runner.
225
+ * signed_off: no proof; the previous instance had signed off
226
+ * (/runner-ingest/disconnect), as on a pod restart.
227
+ * offline: no proof; the previous instance had stopped heartbeating.
228
+ * never_connected: no proof; the row had never heartbeated.
229
+ *
230
+ * Only "continuity" is proof. The other three are what a restarted pod
231
+ * looks like — and also what anyone holding the ingestion key looks like —
232
+ * so they are admitted only for a row that holds nothing but the agent
233
+ * defaults, and the feed says which one it was.
234
+ */
235
+ type AgentRunnerReKeyAdmission =
236
+ | "continuity"
237
+ | "signed_off"
238
+ | "offline"
239
+ | "never_connected";
240
+
241
+ interface RunnerPresence {
242
+ liveStatus: RunnerLiveStatus;
243
+ // The Runner shut down cleanly after its last heartbeat.
244
+ isSignedOff: boolean;
245
+ isOnline: boolean;
246
+ }
247
+
248
+ class KubernetesClusterAiAccessServiceClass {
249
+ /*
250
+ * ------------------------------------------------------------------
251
+ * Readiness
252
+ * ------------------------------------------------------------------
253
+ */
254
+
255
+ @CaptureSpan()
256
+ public async getProjectGates(
257
+ projectId: ObjectID,
258
+ ): Promise<KubernetesClusterAiAccessProjectGates> {
259
+ const project: Project | null = await ProjectService.findOneById({
260
+ id: projectId,
261
+ select: {
262
+ enableAi: true,
263
+ enableAutoRemediation: true,
264
+ enableAiCommandExecution: true,
265
+ },
266
+ props: { isRoot: true },
267
+ });
268
+
269
+ let hasLlmProvider: boolean = false;
270
+
271
+ try {
272
+ hasLlmProvider =
273
+ (await LlmProviderService.getLLMProviderForProject(projectId)) !== null;
274
+ } catch (error) {
275
+ logger.error(
276
+ `KubernetesClusterAiAccess: could not resolve the LLM provider for project ${projectId.toString()}: ${error}`,
277
+ );
278
+ }
279
+
280
+ return {
281
+ // Kill switches: a missing column counts as enabled (=== false idiom).
282
+ isAiEnabled: project?.enableAi !== false,
283
+ isAutoRemediationEnabled: project?.enableAutoRemediation !== false,
284
+ // Explicit opt-in (=== true idiom), same as the Bash/SSH lane.
285
+ isAiCommandExecutionEnabled: project?.enableAiCommandExecution === true,
286
+ hasLlmProvider,
287
+ };
288
+ }
289
+
290
+ @CaptureSpan()
291
+ public async getStatusForCluster(data: {
292
+ clusterId: ObjectID;
293
+ projectId: ObjectID;
294
+ gates?: KubernetesClusterAiAccessProjectGates | undefined;
295
+ }): Promise<KubernetesClusterAiAccessStatus | null> {
296
+ const cluster: KubernetesCluster | null =
297
+ await KubernetesClusterService.findOneBy({
298
+ query: {
299
+ _id: data.clusterId.toString(),
300
+ projectId: data.projectId,
301
+ },
302
+ select: CLUSTER_AI_ACCESS_SELECT,
303
+ props: { isRoot: true },
304
+ });
305
+
306
+ if (!cluster) {
307
+ return null;
308
+ }
309
+
310
+ return this.getStatusForClusterModel({
311
+ cluster,
312
+ gates: data.gates || (await this.getProjectGates(data.projectId)),
313
+ });
314
+ }
315
+
316
+ /*
317
+ * The readiness computation proper. Reads the bound Runner and credential
318
+ * as root (the cluster row is already tenant-scoped by the caller) and
319
+ * folds project gates in. Never throws: a lookup failure becomes a gap,
320
+ * because "we could not check" must not read as "ready".
321
+ */
322
+ @CaptureSpan()
323
+ public async getStatusForClusterModel(data: {
324
+ cluster: KubernetesCluster;
325
+ gates: KubernetesClusterAiAccessProjectGates;
326
+ }): Promise<KubernetesClusterAiAccessStatus> {
327
+ const { cluster, gates } = data;
328
+ const gaps: Array<KubernetesAiAccessGap> = [];
329
+
330
+ const remediationMode: KubernetesAiRemediationMode =
331
+ this.normalizeRemediationMode(cluster.aiRemediationMode);
332
+ const isInvestigationEnabled: boolean =
333
+ cluster.isAiInvestigationEnabled === true;
334
+
335
+ let runnerSummary: KubernetesClusterAiAccessStatus["runner"] = null;
336
+ let accessMethod: KubernetesClusterAiAccessStatus["accessMethod"] = "none";
337
+ let credentialId: string | undefined = undefined;
338
+ let credentialName: string | undefined = undefined;
339
+
340
+ if (!cluster.aiAccessRunnerId) {
341
+ gaps.push(await this.getNoRunnerBoundGap(cluster));
342
+ } else {
343
+ const runner: Runner | null = await RunnerService.findOneBy({
344
+ query: {
345
+ _id: cluster.aiAccessRunnerId.toString(),
346
+ projectId: cluster.projectId!,
347
+ },
348
+ select: {
349
+ _id: true,
350
+ name: true,
351
+ lastAlive: true,
352
+ connectionStatus: true,
353
+ canRunAiCommands: true,
354
+ // What would stop an offline agent row from re-registering.
355
+ canRunRunbooks: true,
356
+ canRunCodeFixTasks: true,
357
+ hostInfo: true,
358
+ },
359
+ props: { isRoot: true },
360
+ });
361
+
362
+ if (!runner) {
363
+ /*
364
+ * Only a race reaches this: the binding's foreign key is ON DELETE
365
+ * SET NULL, so deleting the bound Runner clears aiAccessRunnerId in
366
+ * the same statement, and the next read takes the no_runner_bound
367
+ * branch above. This is the window between reading the cluster row
368
+ * and reading its Runner while a delete lands.
369
+ */
370
+ gaps.push({
371
+ code: "runner_missing",
372
+ title: "The bound Runner was just deleted",
373
+ description:
374
+ "The Runner this cluster was bound to was deleted while its status was being read.",
375
+ nextStep:
376
+ "Reload the cluster's AI page, then bind another Runner there, or reinstall the in-cluster Runner with --set aiAccess.enabled=true.",
377
+ blocks: "both",
378
+ });
379
+ } else {
380
+ const posture: KubernetesRunnerPosture | undefined =
381
+ parseKubernetesRunnerPosture(runner.hostInfo);
382
+ const presence: RunnerPresence = this.getRunnerPresence(runner);
383
+ const isOnline: boolean = presence.isOnline;
384
+ // The one "is an agent row" rule: the name marker or an agent posture.
385
+ const isAgentRunnerRow: boolean =
386
+ RunnerServiceClass.isKubernetesAgentRunnerRow(runner);
387
+ const isAgentRunner: boolean =
388
+ isAgentRunnerRow || posture?.inCluster === true;
389
+
390
+ runnerSummary = {
391
+ id: runner.id!.toString(),
392
+ name: runner.name || "Runner",
393
+ isOnline,
394
+ lastAliveAt: runner.lastAlive
395
+ ? OneUptimeDate.toString(runner.lastAlive)
396
+ : undefined,
397
+ canRunAiCommands: runner.canRunAiCommands === true,
398
+ posture,
399
+ };
400
+
401
+ if (!isOnline) {
402
+ /*
403
+ * An offline agent Runner of THIS cluster that holds more than the
404
+ * agent defaults will be refused on every re-registration its
405
+ * restarted pod attempts (it cannot present the key it held), so
406
+ * "it reconnects within a minute" would be false: say what blocks
407
+ * it instead.
408
+ */
409
+ const holdingsGap: KubernetesAiAccessGap | null =
410
+ RunnerServiceClass.isKubernetesAgentRunnerOfCluster(
411
+ runner,
412
+ cluster.clusterIdentifier,
413
+ )
414
+ ? await this.getAgentRunnerHoldingsGap({ runner, cluster })
415
+ : null;
416
+
417
+ gaps.push(
418
+ holdingsGap ||
419
+ this.getRunnerOfflineGap({ runner, presence, isAgentRunner }),
420
+ );
421
+ }
422
+
423
+ if (runner.canRunAiCommands !== true) {
424
+ gaps.push({
425
+ code: "runner_ai_commands_disabled",
426
+ title: "The Runner does not accept AI commands",
427
+ description: `"Runs AI Remediation Commands" is turned off on Runner "${runner.name}", so it will not be served kubectl work.`,
428
+ nextStep:
429
+ 'Turn on "Runs AI Remediation Commands" on the Runner (Project Settings → Runners).',
430
+ blocks: "both",
431
+ });
432
+ }
433
+
434
+ /*
435
+ * In-cluster access means "kubectl with the pod's own
436
+ * ServiceAccount", which reaches whatever cluster the pod lives
437
+ * in. So it is usable only when the Runner's posture names THIS
438
+ * cluster — a Runner that is in-cluster somewhere else (the
439
+ * dashboard lets an operator pick any Runner) would run every
440
+ * command for this cluster against the wrong one.
441
+ */
442
+ const isInClusterForThisCluster: boolean = isInClusterPostureForCluster(
443
+ posture,
444
+ cluster.clusterIdentifier,
445
+ );
446
+
447
+ if (isInClusterForThisCluster) {
448
+ accessMethod = "in_cluster";
449
+ } else if (cluster.aiAccessCredentialId && isAgentRunnerRow) {
450
+ /*
451
+ * A kubernetes-agent Runner is never handed credential material:
452
+ * its row is minted and re-keyed with the project's telemetry
453
+ * ingestion key, so a credential it carried would be one leaked
454
+ * ingestion key away from anyone. The claim path refuses to
455
+ * resolve one for it (by the same name-or-posture rule);
456
+ * readiness says so instead of promising access that would fail
457
+ * on every command.
458
+ */
459
+ gaps.push({
460
+ code: "credential_on_agent_runner",
461
+ title: "An in-cluster Runner cannot carry a credential",
462
+ description: `Runner "${runner.name}" is ${
463
+ posture?.clusterIdentifier?.trim()
464
+ ? `the in-cluster Runner of cluster "${posture.clusterIdentifier.trim()}"`
465
+ : "a Kubernetes agent's in-cluster Runner"
466
+ }. It runs kubectl with its own ServiceAccount only and is never given a credential, so the Kubernetes credential selected for this cluster cannot be used through it.`,
467
+ nextStep:
468
+ "Create a Runner under Project Settings → Runners, assign the Kubernetes credential to it and select both on the cluster's AI page — or install the in-cluster Runner on THIS cluster with --set aiAccess.enabled=true, which needs no credential.",
469
+ blocks: "both",
470
+ });
471
+ } else if (cluster.aiAccessCredentialId) {
472
+ const credential: RunbookCredential | null =
473
+ await RunbookCredentialService.findOneBy({
474
+ query: {
475
+ _id: cluster.aiAccessCredentialId.toString(),
476
+ projectId: cluster.projectId!,
477
+ },
478
+ select: {
479
+ _id: true,
480
+ name: true,
481
+ credentialType: true,
482
+ runners: { _id: true },
483
+ },
484
+ props: { isRoot: true },
485
+ });
486
+
487
+ const isAssignedToRunner: boolean = Boolean(
488
+ credential?.runners?.some((assigned: Runner) => {
489
+ return assigned.id?.toString() === runner.id?.toString();
490
+ }),
491
+ );
492
+
493
+ if (
494
+ !credential ||
495
+ credential.credentialType !== RunbookCredentialType.Kubernetes ||
496
+ !isAssignedToRunner
497
+ ) {
498
+ gaps.push({
499
+ code: "credential_missing",
500
+ title: "The Kubernetes credential is not usable by the Runner",
501
+ description: !credential
502
+ ? "The credential bound to this cluster no longer exists."
503
+ : credential.credentialType !== RunbookCredentialType.Kubernetes
504
+ ? `"${credential.name}" is not a Kubernetes credential.`
505
+ : `"${credential.name}" is not assigned to Runner "${runner.name}".`,
506
+ nextStep:
507
+ "Create a Kubernetes credential (API server URL + ServiceAccount token) under Project Settings → Runner Credentials, assign it to the Runner, and select it on the cluster's AI page.",
508
+ blocks: "both",
509
+ });
510
+ } else {
511
+ accessMethod = "credential";
512
+ credentialId = credential.id!.toString();
513
+ credentialName = credential.name;
514
+ }
515
+ } else if (posture?.inCluster) {
516
+ /*
517
+ * In-cluster, but for another cluster (or for no named cluster
518
+ * at all). Say so explicitly: the operator picked this Runner
519
+ * believing "in-cluster" meant "in this cluster".
520
+ */
521
+ const reportedCluster: string | undefined =
522
+ posture.clusterIdentifier?.trim() || undefined;
523
+
524
+ gaps.push({
525
+ code: "runner_cluster_mismatch",
526
+ title: reportedCluster
527
+ ? "The bound Runner is the in-cluster Runner of a different cluster"
528
+ : "The bound Runner did not report which cluster it runs in",
529
+ description: reportedCluster
530
+ ? `Runner "${runner.name}" runs inside cluster "${reportedCluster}", not "${
531
+ cluster.clusterIdentifier || cluster.name || "this cluster"
532
+ }". Its ServiceAccount would run every kubectl command against "${reportedCluster}", so OneUptime AI will not use it for this cluster.`
533
+ : `Runner "${runner.name}" reports that it runs inside a Kubernetes cluster but not which one, so OneUptime AI cannot tell whether that is this cluster.`,
534
+ nextStep:
535
+ "Install the in-cluster Runner on THIS cluster with --set aiAccess.enabled=true and select it on the cluster's AI page as its Runner (a registering Runner never replaces the Runner a cluster is bound to), or bind a Runner that holds a Kubernetes credential for this cluster and select that credential on the cluster's AI page.",
536
+ blocks: "both",
537
+ });
538
+ } else {
539
+ gaps.push({
540
+ code: "credential_missing",
541
+ title: "The Runner has no credential for this cluster",
542
+ description: `Runner "${runner.name}" runs outside the cluster, so it needs a Kubernetes credential to reach the API server.`,
543
+ nextStep:
544
+ "Select a Kubernetes credential assigned to this Runner on the cluster's AI page — or install the in-cluster Runner with --set aiAccess.enabled=true, which needs no credential.",
545
+ blocks: "both",
546
+ });
547
+ }
548
+
549
+ if (
550
+ remediationMode !== KubernetesAiRemediationMode.Disabled &&
551
+ posture?.inCluster &&
552
+ posture.allowWrites !== true
553
+ ) {
554
+ gaps.push({
555
+ code: "remediation_write_access_missing",
556
+ title: "The in-cluster Runner is read-only",
557
+ description:
558
+ "The Kubernetes agent was installed without write access, so kubectl changes would be refused by the cluster.",
559
+ nextStep: REMEDIATION_WRITE_ACCESS_NEXT_STEP,
560
+ blocks: "remediation",
561
+ });
562
+ }
563
+ }
564
+ }
565
+
566
+ if (!isInvestigationEnabled) {
567
+ gaps.push({
568
+ code: "investigation_disabled",
569
+ title: "AI investigation is turned off for this cluster",
570
+ description:
571
+ "OneUptime AI will investigate incidents and alerts on this cluster with OneUptime data only — it will not run kubectl.",
572
+ nextStep:
573
+ 'Turn on "Let AI investigate with kubectl" on the cluster\'s AI page.',
574
+ blocks: "investigation",
575
+ });
576
+ }
577
+
578
+ if (remediationMode === KubernetesAiRemediationMode.Disabled) {
579
+ gaps.push({
580
+ code: "remediation_disabled",
581
+ title: "AI remediation is turned off for this cluster",
582
+ description:
583
+ "OneUptime AI will diagnose but never propose or apply a fix on this cluster.",
584
+ nextStep:
585
+ 'Set "AI remediation" to "Ask for approval", "Automatic" or "Bypass approval" on the cluster\'s AI page.',
586
+ blocks: "remediation",
587
+ });
588
+ }
589
+
590
+ if (!gates.isAiEnabled) {
591
+ gaps.push({
592
+ code: "project_ai_disabled",
593
+ title: "AI is disabled for this project",
594
+ description: "OneUptime AI is switched off at the project level.",
595
+ nextStep: "Enable AI under Project Settings → AI.",
596
+ blocks: "both",
597
+ });
598
+ }
599
+
600
+ if (!gates.hasLlmProvider) {
601
+ gaps.push({
602
+ code: "llm_provider_missing",
603
+ title: "No AI provider is configured",
604
+ description:
605
+ "OneUptime AI needs an LLM provider to investigate or remediate anything.",
606
+ nextStep:
607
+ "Add a provider under Project Settings → AI → LLM Providers (or use OneUptime AI credits).",
608
+ blocks: "both",
609
+ });
610
+ }
611
+
612
+ if (!gates.isAutoRemediationEnabled) {
613
+ gaps.push({
614
+ code: "project_auto_remediation_disabled",
615
+ title: "Auto-remediation is disabled for this project",
616
+ description:
617
+ "The project-level auto-remediation kill switch is off, so no AI fix can be proposed or run.",
618
+ nextStep: "Enable auto-remediation under Project Settings → AI.",
619
+ blocks: "remediation",
620
+ });
621
+ }
622
+
623
+ if (!gates.isAiCommandExecutionEnabled) {
624
+ gaps.push({
625
+ code: "project_ai_command_execution_disabled",
626
+ title: "AI command execution is not enabled for this project",
627
+ description:
628
+ "AI-composed commands (including kubectl fixes) never run in a project that has not opted in.",
629
+ nextStep:
630
+ 'Turn on "Enable AI Command Execution" under Project Settings → AI.',
631
+ blocks: "remediation",
632
+ });
633
+ }
634
+
635
+ const blocksInvestigation: boolean = gaps.some(
636
+ (gap: KubernetesAiAccessGap) => {
637
+ return gap.blocks === "investigation" || gap.blocks === "both";
638
+ },
639
+ );
640
+ const blocksRemediation: boolean = gaps.some(
641
+ (gap: KubernetesAiAccessGap) => {
642
+ return gap.blocks === "remediation" || gap.blocks === "both";
643
+ },
644
+ );
645
+
646
+ return {
647
+ clusterId: cluster.id!.toString(),
648
+ clusterName: cluster.name || cluster.clusterIdentifier || "cluster",
649
+ clusterIdentifier: cluster.clusterIdentifier,
650
+ runner: runnerSummary,
651
+ accessMethod,
652
+ credentialId,
653
+ credentialName,
654
+ kubectlAllowlist: this.normalizeAllowlist(
655
+ cluster.aiKubectlCommandAllowlist,
656
+ ),
657
+ isInvestigationEnabled,
658
+ isInvestigationReady: isInvestigationEnabled && !blocksInvestigation,
659
+ remediationMode,
660
+ isRemediationReady:
661
+ remediationMode !== KubernetesAiRemediationMode.Disabled &&
662
+ !blocksRemediation,
663
+ gaps,
664
+ lastVerifiedAt: cluster.aiAccessLastVerifiedAt
665
+ ? OneUptimeDate.toString(cluster.aiAccessLastVerifiedAt)
666
+ : undefined,
667
+ lastError: cluster.aiAccessLastError || undefined,
668
+ evaluatedAt: OneUptimeDate.toString(OneUptimeDate.getCurrentDate()),
669
+ };
670
+ }
671
+
672
+ /*
673
+ * Is this Runner online right now? One rule for readiness and for
674
+ * registration: it heartbeated within the alive window (RunnerLiveStatus)
675
+ * AND it has not signed off since. A Runner signs off on a clean shutdown
676
+ * (/runner-ingest/disconnect), which is what a helm uninstall or turning
677
+ * aiAccess off does to the agent's Runner pod — it must read offline at
678
+ * once, not stay "Connected" until its last heartbeat ages out while
679
+ * investigations queue kubectl it will never claim. A freshly created
680
+ * row is Disconnected with no heartbeat yet: that is "never connected",
681
+ * not a sign-off.
682
+ */
683
+ private getRunnerPresence(runner: Runner): RunnerPresence {
684
+ const liveStatus: RunnerLiveStatus = getRunnerLiveStatus(runner.lastAlive);
685
+
686
+ const isSignedOff: boolean =
687
+ runner.connectionStatus === RunnerConnectionStatus.Disconnected &&
688
+ liveStatus !== RunnerLiveStatus.NeverConnected;
689
+
690
+ return {
691
+ liveStatus,
692
+ isSignedOff,
693
+ isOnline: liveStatus === RunnerLiveStatus.Connected && !isSignedOff,
694
+ };
695
+ }
696
+
697
+ private getRunnerOfflineGap(data: {
698
+ runner: Runner;
699
+ presence: RunnerPresence;
700
+ // The Runner is a Kubernetes agent's in-cluster Runner.
701
+ isAgentRunner: boolean;
702
+ }): KubernetesAiAccessGap {
703
+ const { runner, presence, isAgentRunner } = data;
704
+ const lastAliveText: string = runner.lastAlive
705
+ ? OneUptimeDate.getDateAsFormattedString(runner.lastAlive)
706
+ : "an unknown time";
707
+
708
+ if (presence.isSignedOff) {
709
+ return {
710
+ code: "runner_offline",
711
+ title: isAgentRunner
712
+ ? "The in-cluster Runner signed off"
713
+ : "The Runner signed off",
714
+ description: isAgentRunner
715
+ ? `Runner "${runner.name}" shut down cleanly after its last heartbeat at ${lastAliveText}: the Kubernetes agent was uninstalled or upgraded with aiAccess turned off, or its Runner pod is being replaced.`
716
+ : `Runner "${runner.name}" shut down cleanly after its last heartbeat at ${lastAliveText}: its container was stopped.`,
717
+ nextStep: isAgentRunner
718
+ ? "If the agent was uninstalled or aiAccess was turned off on purpose, clear the Runner on the cluster's AI page. Otherwise upgrade the agent with --set aiAccess.enabled=true and the Runner reconnects within a minute."
719
+ : "Start the Runner container again, or bind another Runner on the cluster's AI page.",
720
+ blocks: "both",
721
+ };
722
+ }
723
+
724
+ const isNeverConnected: boolean =
725
+ presence.liveStatus === RunnerLiveStatus.NeverConnected;
726
+
727
+ return {
728
+ code: "runner_offline",
729
+ title: isNeverConnected
730
+ ? "The Runner has never connected"
731
+ : "The Runner is offline",
732
+ description: isNeverConnected
733
+ ? `Runner "${runner.name}" exists but has not reported in yet.`
734
+ : `Runner "${runner.name}" last reported in at ${lastAliveText}.`,
735
+ nextStep: isAgentRunner
736
+ ? "Check the in-cluster Runner pod: kubectl get pods -n <agent-namespace> -l component=ai-runner, then its logs. It must be able to reach your OneUptime URL."
737
+ : "Start the Runner container and make sure it can reach your OneUptime URL.",
738
+ blocks: "both",
739
+ };
740
+ }
741
+
742
+ /*
743
+ * The gap for an offline agent Runner of this cluster that holds more than
744
+ * the agent defaults, or null when it holds nothing extra. Such a row is
745
+ * refused on every registration that cannot present its current key — and
746
+ * a restarted pod never can, it keeps the key in memory only — so the
747
+ * Runner will not come back until an operator removes what it holds.
748
+ * Never throws: a failed lookup falls back to the ordinary offline gap.
749
+ */
750
+ private async getAgentRunnerHoldingsGap(data: {
751
+ runner: Runner;
752
+ cluster: KubernetesCluster;
753
+ }): Promise<KubernetesAiAccessGap | null> {
754
+ let holdings: Array<AgentRunnerHolding> = [];
755
+
756
+ try {
757
+ holdings = await this.getRunnerHoldingsBeyondDefaults({
758
+ runner: data.runner,
759
+ clusterId: data.cluster.id!,
760
+ projectId: data.cluster.projectId!,
761
+ });
762
+ } catch (error) {
763
+ logger.error(
764
+ `KubernetesClusterAiAccess: could not read what the agent Runner of cluster ${data.cluster.id?.toString()} holds: ${error}`,
765
+ );
766
+ return null;
767
+ }
768
+
769
+ if (holdings.length === 0) {
770
+ return null;
771
+ }
772
+
773
+ return {
774
+ code: "runner_offline",
775
+ title: "The in-cluster Runner cannot re-register until it holds less",
776
+ description: `Runner "${data.runner.name}" is offline, and it holds more than an in-cluster Runner's defaults (${this.describeHoldings(
777
+ holdings,
778
+ )}). A restarted in-cluster Runner cannot prove it is the same Runner, so every registration it attempts is refused and it will not reconnect on its own.`,
779
+ /*
780
+ * Removing what it holds comes first: the Runner row survives, so the
781
+ * cluster stays bound to it and it reconnects on its next retry.
782
+ * Deleting it works too, but only with the second step — the fresh
783
+ * Runner is not bound to this cluster until someone selects it.
784
+ */
785
+ nextStep: `Under Project Settings → Runners, on Runner "${data.runner.name}": ${this.describeHoldingRemedies(
786
+ holdings,
787
+ )}. The in-cluster Runner then reconnects on its next retry, still bound to this cluster. Or delete the Runner and, once the in-cluster Runner registers a fresh one (within a minute), select it on the cluster's AI page as its Runner. ${getDeletedAgentRunnerRebindNote()}`,
788
+ blocks: "both",
789
+ };
790
+ }
791
+
792
+ private describeHoldings(holdings: Array<AgentRunnerHolding>): string {
793
+ return holdings
794
+ .map((holding: AgentRunnerHolding) => {
795
+ return holding.description;
796
+ })
797
+ .join("; ");
798
+ }
799
+
800
+ private describeHoldingRemedies(holdings: Array<AgentRunnerHolding>): string {
801
+ return holdings
802
+ .map((holding: AgentRunnerHolding) => {
803
+ return holding.remedy;
804
+ })
805
+ .join("; ");
806
+ }
807
+
808
+ /*
809
+ * The gap for a cluster with no Runner bound. What to do depends on
810
+ * whether this cluster's in-cluster Runner is already registered: a
811
+ * registering Runner never binds a cluster whose AI access was configured
812
+ * before (an operator cleared the binding, or the Runner it was bound to
813
+ * was deleted), so re-running the helm upgrade would change nothing —
814
+ * selecting the Runner on the AI page is the step that works. Never
815
+ * throws: a failed lookup falls back to the install instruction.
816
+ */
817
+ private async getNoRunnerBoundGap(
818
+ cluster: KubernetesCluster,
819
+ ): Promise<KubernetesAiAccessGap> {
820
+ const agentRunner: Runner | null =
821
+ await this.findAgentRunnerForCluster(cluster);
822
+
823
+ if (agentRunner) {
824
+ const isOnline: boolean = this.getRunnerPresence(agentRunner).isOnline;
825
+
826
+ return {
827
+ code: "no_runner_bound",
828
+ title: "The in-cluster Runner is installed but not selected",
829
+ description: `Runner "${agentRunner.name}", this cluster's in-cluster Runner, is registered${
830
+ isOnline ? " and online" : " but not online right now"
831
+ }, but no Runner is bound to this cluster, so OneUptime AI does not use it. A registering Runner never re-binds a cluster that had a Runner bound before (or already ran kubectl) — its binding was cleared by an operator, or the Runner it was bound to was deleted.`,
832
+ nextStep: `Select the kubernetes-agent Runner "${agentRunner.name}" on the cluster's AI page as its Runner (leave the credential empty). No helm change is needed.`,
833
+ blocks: "both",
834
+ };
835
+ }
836
+
837
+ return {
838
+ code: "no_runner_bound",
839
+ title: "No Runner can reach this cluster",
840
+ description:
841
+ "OneUptime AI runs kubectl through a Runner. None is bound to this cluster yet.",
842
+ nextStep:
843
+ "Upgrade the Kubernetes agent with --set aiAccess.enabled=true to install an in-cluster Runner (one command), or bind an existing Runner and a Kubernetes credential on the cluster's AI page.",
844
+ blocks: "both",
845
+ };
846
+ }
847
+
848
+ /*
849
+ * This cluster's agent Runner row, by its (bounded) name, matched
850
+ * case-insensitively like registration matches it. A row whose posture
851
+ * names a DIFFERENT cluster is not this cluster's agent (a shortened
852
+ * name's hash collision, or a posture rewritten on heartbeat).
853
+ */
854
+ private async findAgentRunnerForCluster(
855
+ cluster: KubernetesCluster,
856
+ ): Promise<Runner | null> {
857
+ const clusterIdentifier: string = (cluster.clusterIdentifier || "").trim();
858
+
859
+ if (!clusterIdentifier || !cluster.projectId) {
860
+ return null;
861
+ }
862
+
863
+ try {
864
+ const runner: Runner | null = await RunnerService.findOneBy({
865
+ query: {
866
+ projectId: cluster.projectId,
867
+ name: QueryHelper.findWithSameText(
868
+ getKubernetesAgentRunnerNameForCluster(clusterIdentifier),
869
+ ),
870
+ },
871
+ select: {
872
+ _id: true,
873
+ name: true,
874
+ lastAlive: true,
875
+ connectionStatus: true,
876
+ hostInfo: true,
877
+ },
878
+ props: { isRoot: true },
879
+ });
880
+
881
+ if (
882
+ !runner ||
883
+ this.postureNamesAnotherCluster({ runner, clusterIdentifier })
884
+ ) {
885
+ return null;
886
+ }
887
+
888
+ return runner;
889
+ } catch (error) {
890
+ logger.error(
891
+ `KubernetesClusterAiAccess: could not look up the agent Runner of cluster ${cluster.id?.toString()}: ${error}`,
892
+ );
893
+ return null;
894
+ }
895
+ }
896
+
897
+ // The Runner's reported posture names a cluster, and it is not this one.
898
+ private postureNamesAnotherCluster(data: {
899
+ runner: Runner;
900
+ clusterIdentifier: string;
901
+ }): boolean {
902
+ const reported: string =
903
+ parseKubernetesRunnerPosture(
904
+ data.runner.hostInfo,
905
+ )?.clusterIdentifier?.trim() || "";
906
+
907
+ return (
908
+ reported.length > 0 &&
909
+ !isSameKubernetesClusterIdentifier(reported, data.clusterIdentifier)
910
+ );
911
+ }
912
+
913
+ /*
914
+ * ------------------------------------------------------------------
915
+ * Subject → clusters
916
+ * ------------------------------------------------------------------
917
+ */
918
+
919
+ /*
920
+ * The clusters an incident or alert is about: the ones linked on the
921
+ * subject (SeriesResourceLinker attaches them from the monitor's series
922
+ * labels at creation), falling back to the cluster a Kubernetes monitor
923
+ * step names when the linker had nothing to work with (a manually
924
+ * declared incident, or one whose linking found nothing).
925
+ *
926
+ * The fallback matches identifiers case-insensitively, like
927
+ * MonitorResourceContext and SeriesResourceLinker do for the same input:
928
+ * a step identifier is typed by a person (or Terraform) and may differ in
929
+ * case from the ingest-stamped cluster row, which keeps the casing it was
930
+ * first seen with. The (projectId, clusterIdentifier) uniqueness guard is
931
+ * itself case-insensitive, so this can never match extra rows.
932
+ */
933
+ @CaptureSpan()
934
+ public async getClustersForSubject(data: {
935
+ projectId: ObjectID;
936
+ incidentId?: ObjectID | undefined;
937
+ alertId?: ObjectID | undefined;
938
+ }): Promise<Array<KubernetesCluster>> {
939
+ const clusterIds: Set<string> = new Set<string>();
940
+ const monitorIds: Array<ObjectID> = [];
941
+
942
+ if (data.alertId) {
943
+ const alert: Alert | null = await AlertService.findOneBy({
944
+ query: { _id: data.alertId.toString(), projectId: data.projectId },
945
+ select: {
946
+ _id: true,
947
+ monitorId: true,
948
+ kubernetesClusters: { _id: true },
949
+ },
950
+ props: { isRoot: true },
951
+ });
952
+
953
+ for (const cluster of alert?.kubernetesClusters || []) {
954
+ if (cluster.id) {
955
+ clusterIds.add(cluster.id.toString());
956
+ }
957
+ }
958
+
959
+ if (alert?.monitorId) {
960
+ monitorIds.push(alert.monitorId);
961
+ }
962
+ } else if (data.incidentId) {
963
+ const incident: Incident | null = await IncidentService.findOneBy({
964
+ query: { _id: data.incidentId.toString(), projectId: data.projectId },
965
+ select: {
966
+ _id: true,
967
+ monitors: { _id: true },
968
+ kubernetesClusters: { _id: true },
969
+ },
970
+ props: { isRoot: true },
971
+ });
972
+
973
+ for (const cluster of incident?.kubernetesClusters || []) {
974
+ if (cluster.id) {
975
+ clusterIds.add(cluster.id.toString());
976
+ }
977
+ }
978
+
979
+ for (const monitor of incident?.monitors || []) {
980
+ if (monitor.id) {
981
+ monitorIds.push(monitor.id);
982
+ }
983
+ }
984
+ }
985
+
986
+ const clusterIdentifiers: Set<string> = new Set<string>();
987
+
988
+ if (clusterIds.size === 0 && monitorIds.length > 0) {
989
+ const monitors: Array<Monitor> = await MonitorService.findBy({
990
+ query: {
991
+ _id: QueryHelper.any(monitorIds.slice(0, MAX_CLUSTERS_PER_SUBJECT)),
992
+ projectId: data.projectId,
993
+ },
994
+ select: { _id: true, monitorSteps: true },
995
+ limit: MAX_CLUSTERS_PER_SUBJECT,
996
+ skip: 0,
997
+ props: { isRoot: true },
998
+ });
999
+
1000
+ for (const monitor of monitors) {
1001
+ const steps: Array<MonitorStep> =
1002
+ monitor.monitorSteps?.data?.monitorStepsInstanceArray || [];
1003
+ for (const step of steps) {
1004
+ const identifier: string = normalizeKubernetesClusterIdentifier(
1005
+ step.data?.kubernetesMonitor?.clusterIdentifier,
1006
+ );
1007
+ if (identifier) {
1008
+ clusterIdentifiers.add(identifier);
1009
+ }
1010
+ }
1011
+ }
1012
+ }
1013
+
1014
+ if (clusterIds.size === 0 && clusterIdentifiers.size === 0) {
1015
+ return [];
1016
+ }
1017
+
1018
+ const clusters: Array<KubernetesCluster> =
1019
+ await KubernetesClusterService.findBy({
1020
+ query: {
1021
+ projectId: data.projectId,
1022
+ isArchived: false,
1023
+ ...(clusterIds.size > 0
1024
+ ? {
1025
+ _id: QueryHelper.any(
1026
+ Array.from(clusterIds)
1027
+ .slice(0, MAX_CLUSTERS_PER_SUBJECT)
1028
+ .map((id: string) => {
1029
+ return new ObjectID(id);
1030
+ }),
1031
+ ),
1032
+ }
1033
+ : {
1034
+ clusterIdentifier: QueryHelper.findWithSameTextAnyOf(
1035
+ Array.from(clusterIdentifiers).slice(
1036
+ 0,
1037
+ MAX_CLUSTERS_PER_SUBJECT,
1038
+ ),
1039
+ ),
1040
+ }),
1041
+ },
1042
+ select: CLUSTER_AI_ACCESS_SELECT,
1043
+ limit: MAX_CLUSTERS_PER_SUBJECT,
1044
+ skip: 0,
1045
+ props: { isRoot: true },
1046
+ });
1047
+
1048
+ return clusters;
1049
+ }
1050
+
1051
+ @CaptureSpan()
1052
+ public async getStatusesForSubject(data: {
1053
+ projectId: ObjectID;
1054
+ incidentId?: ObjectID | undefined;
1055
+ alertId?: ObjectID | undefined;
1056
+ }): Promise<Array<KubernetesClusterAiAccessStatus>> {
1057
+ const clusters: Array<KubernetesCluster> =
1058
+ await this.getClustersForSubject(data);
1059
+
1060
+ if (clusters.length === 0) {
1061
+ return [];
1062
+ }
1063
+
1064
+ const gates: KubernetesClusterAiAccessProjectGates =
1065
+ await this.getProjectGates(data.projectId);
1066
+
1067
+ const statuses: Array<KubernetesClusterAiAccessStatus> = [];
1068
+
1069
+ for (const cluster of clusters) {
1070
+ statuses.push(await this.getStatusForClusterModel({ cluster, gates }));
1071
+ }
1072
+
1073
+ return statuses;
1074
+ }
1075
+
1076
+ /*
1077
+ * ------------------------------------------------------------------
1078
+ * In-cluster Runner registration
1079
+ * ------------------------------------------------------------------
1080
+ */
1081
+
1082
+ /*
1083
+ * Called by the Runner the kubernetes-agent chart deploys. Authenticated
1084
+ * by the project's telemetry ingestion key (the same key the agent ships
1085
+ * telemetry with), so installing the chart with one extra flag is the
1086
+ * whole setup. Idempotent per (project, cluster): a restarted pod gets a
1087
+ * fresh key for the same Runner row and the same cluster binding.
1088
+ *
1089
+ * The ingestion key is a credential every collector, CI job and sidecar
1090
+ * in the project holds, so what it can do here is deliberately narrow:
1091
+ *
1092
+ * - It can mint an agent Runner row for a cluster (bounded per project,
1093
+ * see MAX_KUBERNETES_AGENT_RUNNERS_PER_PROJECT).
1094
+ * - It can re-key that row only while the row is OFFLINE (no heartbeat
1095
+ * for RUNNER_ALIVE_WINDOW_IN_MINUTES, or signed off) or when the
1096
+ * request presents the row's current key. A Runner the dashboard shows
1097
+ * as connected can therefore not be taken over by anyone but itself:
1098
+ * whoever holds a leaked ingestion key cannot lock the live pod out and
1099
+ * be handed the identity every kubectl job for that cluster is targeted
1100
+ * at.
1101
+ *
1102
+ * The trade-off is availability after a pod restart: the new pod holds
1103
+ * no key, so it is refused until the previous instance's last heartbeat
1104
+ * ages out of the alive window (it retries with backoff and then
1105
+ * succeeds). A pod that shuts down cleanly avoids the wait by calling
1106
+ * /runner-ingest/disconnect on the way out, which marks the row offline
1107
+ * at once.
1108
+ * - Without that proof it can re-key only a row that holds NOTHING beyond
1109
+ * the agent defaults. An offline window is predictable (every helm
1110
+ * upgrade opens one), so a row an operator gave more — a credential or
1111
+ * secret assigned to it, runbooks or code fixes turned on, or another
1112
+ * cluster bound to it — is refused: re-keying it would hand all of that
1113
+ * to whoever holds the ingestion key. The operator removes the extras
1114
+ * (the Runner then comes back still bound), or deletes the Runner, lets
1115
+ * the agent register a fresh one and selects it on the cluster's AI
1116
+ * page — a deleted Runner's cluster is left unbound, see below.
1117
+ * - It finds the row it may re-key by this cluster's agent Runner NAME
1118
+ * only — never by the posture a Runner reports about itself — and only
1119
+ * binds a cluster that never had a Runner bound: a cluster whose
1120
+ * binding was cleared (or whose Runner was deleted) stays unbound, and
1121
+ * an operator's AI settings are never overwritten, only the chart's
1122
+ * defaults fill in a cluster nobody configured.
1123
+ * - Every refusal is a KubernetesAgentRegistrationRefusedException whose
1124
+ * reason tells the Runner whether waiting helps.
1125
+ *
1126
+ * Every bind and key rotation is written to the cluster's feed — saying
1127
+ * whether the rotation was proven (the current key was presented) or not
1128
+ * — so an operator can see when the identity behind AI access changed.
1129
+ */
1130
+ @CaptureSpan()
1131
+ public async registerKubernetesAgentRunner(data: {
1132
+ projectId: ObjectID;
1133
+ clusterIdentifier: string;
1134
+ agentVersion?: string | undefined;
1135
+ posture: KubernetesRunnerPosture;
1136
+ /*
1137
+ * The key the Runner currently holds, when it still has one. Proves
1138
+ * continuity, so a live Runner may rotate its own key without waiting
1139
+ * to be considered offline first.
1140
+ */
1141
+ previousRunnerKey?: string | undefined;
1142
+ }): Promise<RegisterKubernetesAgentRunnerResult> {
1143
+ const clusterIdentifier: string = (data.clusterIdentifier || "").trim();
1144
+
1145
+ if (!clusterIdentifier) {
1146
+ throw new BadDataException("clusterName is required.");
1147
+ }
1148
+
1149
+ /*
1150
+ * A name longer than the cluster identifier column can never become a
1151
+ * cluster row, so say so before anything is written. Every shorter
1152
+ * name works: the Runner row's name is bounded separately.
1153
+ */
1154
+ if (clusterIdentifier.length > MAX_KUBERNETES_CLUSTER_IDENTIFIER_LENGTH) {
1155
+ throw new BadDataException(
1156
+ `clusterName is ${clusterIdentifier.length} characters long; OneUptime accepts Kubernetes cluster names of up to ${MAX_KUBERNETES_CLUSTER_IDENTIFIER_LENGTH} characters. Set a shorter clusterName on the Kubernetes agent chart.`,
1157
+ );
1158
+ }
1159
+
1160
+ const agentRunnerName: string =
1161
+ getKubernetesAgentRunnerNameForCluster(clusterIdentifier);
1162
+
1163
+ const created: KubernetesCluster =
1164
+ await KubernetesClusterService.findOrCreateByClusterIdentifier({
1165
+ projectId: data.projectId,
1166
+ clusterIdentifier,
1167
+ });
1168
+
1169
+ const cluster: KubernetesCluster | null =
1170
+ await KubernetesClusterService.findOneBy({
1171
+ query: { _id: created.id!.toString(), projectId: data.projectId },
1172
+ select: CLUSTER_AI_ACCESS_SELECT,
1173
+ props: { isRoot: true },
1174
+ });
1175
+
1176
+ if (!cluster) {
1177
+ throw new BadDataException("Cluster could not be resolved.");
1178
+ }
1179
+
1180
+ /*
1181
+ * What the row stores: the body's posture, with the cluster and
1182
+ * in-cluster set by the service. A re-key may fill in the write scope
1183
+ * an older agent image left out of its body (keepStoredWriteScope).
1184
+ */
1185
+ let posture: KubernetesRunnerPosture = {
1186
+ ...data.posture,
1187
+ clusterIdentifier,
1188
+ inCluster: true,
1189
+ };
1190
+
1191
+ // What a re-key decision reads off an existing agent Runner row.
1192
+ const runnerSelect: Record<string, boolean> = {
1193
+ _id: true,
1194
+ name: true,
1195
+ hostInfo: true,
1196
+ lastAlive: true,
1197
+ connectionStatus: true,
1198
+ key: true,
1199
+ canRunRunbooks: true,
1200
+ canRunCodeFixTasks: true,
1201
+ };
1202
+
1203
+ /*
1204
+ * The agent Runner row for this cluster, bound or not — found by its
1205
+ * NAME, never by the posture a Runner reports about itself. The name is
1206
+ * the server-owned marker: only registration writes it, and
1207
+ * RunnerService refuses to let anyone else rename a row into or out of
1208
+ * it, whereas a posture is whatever the Runner last heartbeated. So a
1209
+ * bound Runner that merely CLAIMS to be this cluster's in-cluster Runner
1210
+ * (a renamed agent row, another cluster's pod, anything) is never
1211
+ * re-keyed here. Matched case-insensitively, like the cluster row
1212
+ * itself, so a chart that registers "Prod-US" finds the row a "prod-us"
1213
+ * registration made.
1214
+ */
1215
+ let runner: Runner | null = await RunnerService.findOneBy({
1216
+ query: {
1217
+ projectId: data.projectId,
1218
+ name: QueryHelper.findWithSameText(agentRunnerName),
1219
+ },
1220
+ select: runnerSelect,
1221
+ props: { isRoot: true },
1222
+ });
1223
+
1224
+ /*
1225
+ * The name is this cluster's, but the row says it is another cluster's
1226
+ * agent (a shortened name whose hash collided, or a posture rewritten on
1227
+ * heartbeat). Re-keying it would move another cluster's identity here,
1228
+ * and creating a second row would trip the unique name — so refuse, and
1229
+ * say which row is in the way. The instruction comes first: the Runner
1230
+ * logs only the start of a long reason.
1231
+ */
1232
+ if (
1233
+ runner &&
1234
+ this.postureNamesAnotherCluster({ runner, clusterIdentifier })
1235
+ ) {
1236
+ logger.warn(
1237
+ `KubernetesClusterAiAccess: refused to register an agent Runner for cluster "${clusterIdentifier}" in project ${data.projectId.toString()}: Runner "${runner.name}" (${runner.id?.toString()}) reports that it belongs to a different cluster.`,
1238
+ );
1239
+
1240
+ throw new KubernetesAgentRegistrationRefusedException({
1241
+ reason: "runner_belongs_to_another_cluster",
1242
+ message: `Delete Runner "${runner.name}" under Project Settings → Runners (an in-cluster Runner cannot be renamed) and, once the agent registers a fresh one on its next retry, select it on the AI page of cluster "${clusterIdentifier}" as its Runner. That Runner already exists in this project but reports that it is the in-cluster Runner of a different cluster, so it was not reused for cluster "${clusterIdentifier}". ${getDeletedAgentRunnerRebindNote()}`,
1243
+ });
1244
+ }
1245
+
1246
+ const agentRunnerExistedBefore: boolean = Boolean(runner);
1247
+ const runnerKey: string = ObjectID.generate().toString();
1248
+ let reKeyAdmission: AgentRunnerReKeyAdmission | undefined = undefined;
1249
+
1250
+ if (runner) {
1251
+ reKeyAdmission = await this.assertRunnerMayBeReKeyed({
1252
+ runner,
1253
+ clusterIdentifier,
1254
+ clusterId: cluster.id!,
1255
+ projectId: data.projectId,
1256
+ previousRunnerKey: data.previousRunnerKey,
1257
+ });
1258
+
1259
+ posture = this.keepStoredWriteScope({
1260
+ reported: posture,
1261
+ stored: parseKubernetesRunnerPosture(runner.hostInfo),
1262
+ });
1263
+
1264
+ await RunnerService.updateOneById({
1265
+ id: runner.id!,
1266
+ data: {
1267
+ key: runnerKey,
1268
+ hostInfo: { kubernetes: posture as unknown as JSONObject },
1269
+ lastAlive: OneUptimeDate.getCurrentDate(),
1270
+ connectionStatus: RunnerConnectionStatus.Connected,
1271
+ ...(data.agentVersion
1272
+ ? { agentVersion: new Version(data.agentVersion) }
1273
+ : {}),
1274
+ } as never,
1275
+ props: { isRoot: true },
1276
+ });
1277
+ } else {
1278
+ await this.assertAgentRunnerMayBeCreated({
1279
+ projectId: data.projectId,
1280
+ clusterIdentifier,
1281
+ });
1282
+
1283
+ const newRunner: Runner = new Runner();
1284
+ newRunner.projectId = data.projectId;
1285
+ newRunner.name = agentRunnerName;
1286
+ newRunner.description = `In-cluster Runner installed by the OneUptime Kubernetes agent chart (aiAccess.enabled=true). Gives OneUptime AI kubectl access to cluster "${clusterIdentifier}". It never runs runbooks or code fixes.`;
1287
+ newRunner.key = runnerKey;
1288
+ newRunner.canRunRunbooks = false;
1289
+ newRunner.canRunCodeFixTasks = false;
1290
+ newRunner.canRunAiCommands = true;
1291
+ newRunner.hostInfo = { kubernetes: posture as unknown as JSONObject };
1292
+ newRunner.lastAlive = OneUptimeDate.getCurrentDate();
1293
+ newRunner.connectionStatus = RunnerConnectionStatus.Connected;
1294
+ if (data.agentVersion) {
1295
+ newRunner.agentVersion = new Version(data.agentVersion);
1296
+ }
1297
+
1298
+ runner = await RunnerService.create({
1299
+ data: newRunner,
1300
+ props: { isRoot: true },
1301
+ });
1302
+ }
1303
+
1304
+ /*
1305
+ * Binding. The dashboard is the control plane:
1306
+ *
1307
+ * - A cluster already bound to this cluster's agent row stays so; only
1308
+ * the key (and posture) rotated.
1309
+ * - A cluster bound to any other Runner is left alone. A bound id whose
1310
+ * Runner row is gone is only the race with a Runner delete (the
1311
+ * foreign key is about to clear it) and is treated like the unbound
1312
+ * case below: never re-bound.
1313
+ * - A cluster with no Runner bound:
1314
+ * - that had a Runner bound before (aiAccessRunnerBoundAt, stamped
1315
+ * on every bind and never cleared) or has run kubectl (a recorded
1316
+ * verification or error) stays unbound and keeps its switches.
1317
+ * That covers both ways a binding goes away: an operator cleared
1318
+ * it on the AI page, or the bound Runner was DELETED — the
1319
+ * binding's foreign key is ON DELETE SET NULL, so Postgres clears
1320
+ * aiAccessRunnerId in the same statement. Deleting the Runner is
1321
+ * how an operator revokes or resets it, so it must not come back
1322
+ * bound a few heartbeats later. The AI page tells the operator to
1323
+ * select the Runner if they want it back.
1324
+ * - that never had a Runner bound but was configured on the AI page
1325
+ * (aiAccessConfiguredAt: an operator chose a mode, the switches
1326
+ * or an allowlist BEFORE installing the chart) is bound to this
1327
+ * agent Runner with every setting left exactly as the operator
1328
+ * chose it — the one-flag install still just works.
1329
+ * - that nobody ever configured takes the chart's intent:
1330
+ * investigation on, remediation "ask for approval" when the chart
1331
+ * also granted write RBAC (a mode already on the row is kept).
1332
+ */
1333
+ let bindingState: KubernetesAgentRunnerBindingState;
1334
+ let appliedRemediationMode: KubernetesAiRemediationMode | undefined =
1335
+ undefined;
1336
+
1337
+ const hadRunnerBound: boolean = Boolean(cluster.aiAccessRunnerBoundAt);
1338
+ const hasCommandHistory: boolean =
1339
+ Boolean(cluster.aiAccessLastVerifiedAt) ||
1340
+ Boolean(cluster.aiAccessLastError);
1341
+
1342
+ if (cluster.aiAccessRunnerId) {
1343
+ /*
1344
+ * A row this registration just created cannot already be bound, even
1345
+ * if the ids happened to compare equal.
1346
+ */
1347
+ const isBoundToThisRow: boolean =
1348
+ agentRunnerExistedBefore &&
1349
+ cluster.aiAccessRunnerId.toString() === runner.id!.toString();
1350
+
1351
+ if (isBoundToThisRow) {
1352
+ bindingState = "already_bound";
1353
+ } else {
1354
+ const boundRunner: Runner | null = await RunnerService.findOneBy({
1355
+ query: {
1356
+ _id: cluster.aiAccessRunnerId.toString(),
1357
+ projectId: data.projectId,
1358
+ },
1359
+ select: { _id: true },
1360
+ props: { isRoot: true },
1361
+ });
1362
+
1363
+ bindingState = boundRunner
1364
+ ? "bound_to_other_runner"
1365
+ : "left_unbound_by_operator";
1366
+ }
1367
+ } else if (hadRunnerBound || hasCommandHistory) {
1368
+ bindingState = "left_unbound_by_operator";
1369
+ } else if (cluster.aiAccessConfiguredAt) {
1370
+ bindingState = "bound_keeping_operator_settings";
1371
+
1372
+ // Only the binding: not one of the operator's switches moves.
1373
+ await KubernetesClusterService.updateOneById({
1374
+ id: cluster.id!,
1375
+ data: {
1376
+ aiAccessRunnerId: runner.id!,
1377
+ aiAccessRunnerBoundAt: OneUptimeDate.getCurrentDate(),
1378
+ } as never,
1379
+ props: { isRoot: true },
1380
+ });
1381
+ } else {
1382
+ bindingState = "first_bind";
1383
+
1384
+ appliedRemediationMode = this.getFirstBindRemediationMode({
1385
+ currentMode: cluster.aiRemediationMode,
1386
+ allowWrites: posture.allowWrites === true,
1387
+ });
1388
+
1389
+ await KubernetesClusterService.updateOneById({
1390
+ id: cluster.id!,
1391
+ data: {
1392
+ aiAccessRunnerId: runner.id!,
1393
+ aiAccessCredentialId: null,
1394
+ isAiInvestigationEnabled: true,
1395
+ aiRemediationMode: appliedRemediationMode,
1396
+ aiAccessConfiguredAt: OneUptimeDate.getCurrentDate(),
1397
+ aiAccessRunnerBoundAt: OneUptimeDate.getCurrentDate(),
1398
+ } as never,
1399
+ props: { isRoot: true },
1400
+ });
1401
+ }
1402
+
1403
+ if (bindingState === "left_unbound_by_operator") {
1404
+ logger.info(
1405
+ `KubernetesClusterAiAccess: cluster "${clusterIdentifier}" in project ${data.projectId.toString()} had a Runner bound before (or has run kubectl) but has none bound now — the binding was cleared, or its Runner was deleted; the in-cluster Runner registered without re-binding it.`,
1406
+ );
1407
+ }
1408
+
1409
+ const isBoundToCluster: boolean =
1410
+ bindingState === "first_bind" ||
1411
+ bindingState === "bound_keeping_operator_settings" ||
1412
+ bindingState === "already_bound";
1413
+
1414
+ await this.writeRegistrationFeedItem({
1415
+ cluster,
1416
+ runner,
1417
+ posture,
1418
+ bindingState,
1419
+ agentRunnerExistedBefore,
1420
+ appliedRemediationMode,
1421
+ reKeyAdmission,
1422
+ });
1423
+
1424
+ return {
1425
+ runnerId: runner.id!,
1426
+ runnerKey,
1427
+ clusterId: cluster.id!,
1428
+ isBoundToCluster,
1429
+ isFirstBind: bindingState === "first_bind",
1430
+ bindingState,
1431
+ };
1432
+ }
1433
+
1434
+ /*
1435
+ * The posture a re-keyed agent Runner row stores. An agent image older
1436
+ * than the write scope's registration fields sends neither
1437
+ * writeNamespaces nor podNamespace when it registers (its heartbeat
1438
+ * does). Storing that body as it is would clear the scope the row
1439
+ * already holds, and every server-side check — the enqueue chokepoint,
1440
+ * the remediation toolkit, the cluster's AI page — would read the Runner
1441
+ * as cluster-wide with no namespace of its own until its first
1442
+ * heartbeat. So a field the body leaves out keeps the value the row last
1443
+ * reported; a field it sends wins, an explicit empty list (cluster-wide)
1444
+ * included. Keeping a stored value can only make the server refuse more
1445
+ * than the Runner would, never less, until the heartbeat corrects it.
1446
+ */
1447
+ public keepStoredWriteScope(data: {
1448
+ reported: KubernetesRunnerPosture;
1449
+ stored: KubernetesRunnerPosture | undefined;
1450
+ }): KubernetesRunnerPosture {
1451
+ const { reported, stored } = data;
1452
+ const posture: KubernetesRunnerPosture = { ...reported };
1453
+
1454
+ if (
1455
+ reported.writeNamespaces === undefined &&
1456
+ stored?.writeNamespaces !== undefined
1457
+ ) {
1458
+ posture.writeNamespaces = [...stored.writeNamespaces];
1459
+ }
1460
+
1461
+ if (reported.podNamespace === undefined && stored?.podNamespace) {
1462
+ posture.podNamespace = stored.podNamespace;
1463
+ }
1464
+
1465
+ return posture;
1466
+ }
1467
+
1468
+ /*
1469
+ * The remediation mode a first bind leaves on the cluster. The chart's
1470
+ * intent fills in only what the operator has not set: a mode still at
1471
+ * its default (Disabled) becomes "ask for approval" when the chart
1472
+ * granted write RBAC, and stays Disabled otherwise. A mode an operator
1473
+ * already chose on the AI page — even before any Runner was bound — is
1474
+ * kept exactly as chosen: a pod registering never downgrades or upgrades
1475
+ * a dashboard decision. (A write mode on a read-only Runner is not a
1476
+ * hazard; it reads as a remediation_write_access_missing gap and nothing
1477
+ * runs.)
1478
+ */
1479
+ public getFirstBindRemediationMode(data: {
1480
+ currentMode: unknown;
1481
+ allowWrites: boolean;
1482
+ }): KubernetesAiRemediationMode {
1483
+ const currentMode: KubernetesAiRemediationMode =
1484
+ this.normalizeRemediationMode(data.currentMode);
1485
+
1486
+ if (currentMode !== KubernetesAiRemediationMode.Disabled) {
1487
+ return currentMode;
1488
+ }
1489
+
1490
+ return data.allowWrites
1491
+ ? KubernetesAiRemediationMode.RequireApproval
1492
+ : KubernetesAiRemediationMode.Disabled;
1493
+ }
1494
+
1495
+ /*
1496
+ * A registration may replace the key of an existing agent Runner row only
1497
+ * when it can be the same Runner coming back:
1498
+ *
1499
+ * - it presents the row's current key (proof of continuity) — always
1500
+ * admitted; or
1501
+ * - the row is offline or signed off (what a restarted pod looks like)
1502
+ * AND holds nothing beyond the agent defaults. Anyone holding the
1503
+ * ingestion key looks exactly like a restarted pod, and the offline
1504
+ * window is predictable (every helm upgrade opens one), so a row an
1505
+ * operator gave more — credentials or secrets assigned to it, runbooks
1506
+ * or code fixes turned on, another cluster bound to it — must not be
1507
+ * handed to a registration that cannot prove it is the same Runner.
1508
+ *
1509
+ * Refused otherwise — WITHOUT rotating anything — so an ingestion key
1510
+ * alone can never evict a live Runner or inherit what an operator
1511
+ * entrusted to one. Nothing about the current key is disclosed on
1512
+ * refusal. Returns how the re-key was admitted, for the feed.
1513
+ */
1514
+ private async assertRunnerMayBeReKeyed(data: {
1515
+ runner: Runner;
1516
+ clusterIdentifier: string;
1517
+ clusterId: ObjectID;
1518
+ projectId: ObjectID;
1519
+ previousRunnerKey?: string | undefined;
1520
+ }): Promise<AgentRunnerReKeyAdmission> {
1521
+ const provesContinuity: boolean = Boolean(
1522
+ data.previousRunnerKey &&
1523
+ data.runner.key &&
1524
+ this.isSameSecret(data.previousRunnerKey, data.runner.key),
1525
+ );
1526
+
1527
+ if (provesContinuity) {
1528
+ return "continuity";
1529
+ }
1530
+
1531
+ /*
1532
+ * connectionStatus is written by the Runner's own sign-off
1533
+ * (/runner-ingest/disconnect): a pod that shut down cleanly is offline
1534
+ * the moment it says so, whatever its last heartbeat's age.
1535
+ */
1536
+ const presence: RunnerPresence = this.getRunnerPresence(data.runner);
1537
+
1538
+ if (presence.isOnline) {
1539
+ logger.warn(
1540
+ `KubernetesClusterAiAccess: refused to re-key Runner "${
1541
+ data.runner.name
1542
+ }" (${data.runner.id?.toString()}) for cluster "${
1543
+ data.clusterIdentifier
1544
+ }" in project ${data.projectId.toString()}: the Runner is online and the registration did not present its current key.`,
1545
+ );
1546
+
1547
+ /*
1548
+ * The one refusal that clears on its own: the previous instance's
1549
+ * last heartbeat ages out of the alive window. Say when, so the
1550
+ * Runner retries then instead of guessing.
1551
+ */
1552
+ throw new KubernetesAgentRegistrationRefusedException({
1553
+ reason: "previous_instance_online",
1554
+ retryAfterSeconds: getPreviousInstanceRetryAfterSeconds({
1555
+ lastAlive: data.runner.lastAlive,
1556
+ }),
1557
+ message: `Runner "${data.runner.name}" for cluster "${data.clusterIdentifier}" is online, so this registration was refused and its key was not changed. A registration replaces a Runner only once it has been offline for ${RUNNER_ALIVE_WINDOW_IN_MINUTES} minutes, or when the request presents that Runner's current key as previousRunnerKey. If the Runner pod just restarted, keep retrying: it is admitted as soon as the previous instance's last heartbeat is older than ${RUNNER_ALIVE_WINDOW_IN_MINUTES} minutes (a pod that shuts down cleanly can call /runner-ingest/disconnect to skip the wait).`,
1558
+ });
1559
+ }
1560
+
1561
+ const holdings: Array<AgentRunnerHolding> =
1562
+ await this.getRunnerHoldingsBeyondDefaults({
1563
+ runner: data.runner,
1564
+ clusterId: data.clusterId,
1565
+ projectId: data.projectId,
1566
+ });
1567
+
1568
+ if (holdings.length > 0) {
1569
+ logger.warn(
1570
+ `KubernetesClusterAiAccess: refused to re-key Runner "${
1571
+ data.runner.name
1572
+ }" (${data.runner.id?.toString()}) for cluster "${
1573
+ data.clusterIdentifier
1574
+ }" in project ${data.projectId.toString()} without proof of continuity: it holds more than an in-cluster Runner's defaults (${this.describeHoldings(
1575
+ holdings,
1576
+ )}).`,
1577
+ );
1578
+
1579
+ /*
1580
+ * The instruction leads: the Runner logs only the start of a long
1581
+ * reason, and this refusal never clears until someone acts on it.
1582
+ */
1583
+ throw new KubernetesAgentRegistrationRefusedException({
1584
+ reason: "runner_holds_more_than_defaults",
1585
+ message: `Under Project Settings → Runners, on Runner "${data.runner.name}": ${this.describeHoldingRemedies(
1586
+ holdings,
1587
+ )} — or delete the Runner and, once the agent registers a fresh one on its next retry, select it on the cluster's AI page as its Runner. It is offline, but it holds more than an in-cluster Runner's defaults (${this.describeHoldings(
1588
+ holdings,
1589
+ )}), so a registration for cluster "${data.clusterIdentifier}" that does not present its current key may not take it over, and its key was not changed. ${getDeletedAgentRunnerRebindNote()}`,
1590
+ });
1591
+ }
1592
+
1593
+ if (presence.isSignedOff) {
1594
+ return "signed_off";
1595
+ }
1596
+
1597
+ return presence.liveStatus === RunnerLiveStatus.NeverConnected
1598
+ ? "never_connected"
1599
+ : "offline";
1600
+ }
1601
+
1602
+ /*
1603
+ * What an agent Runner row holds beyond what registration gave it, one
1604
+ * entry per kind with what removes it. Registration creates the row with
1605
+ * kubectl access only (no runbooks, no code fixes, nothing assigned) bound
1606
+ * to its own cluster; anything else was entrusted to the row by an
1607
+ * operator. "Runs Runbooks" is read the way the claim path reads it: on
1608
+ * unless explicitly false.
1609
+ */
1610
+ private async getRunnerHoldingsBeyondDefaults(data: {
1611
+ runner: Runner;
1612
+ clusterId: ObjectID;
1613
+ projectId: ObjectID;
1614
+ }): Promise<Array<AgentRunnerHolding>> {
1615
+ const holdings: Array<AgentRunnerHolding> = [];
1616
+
1617
+ if (data.runner.canRunRunbooks !== false) {
1618
+ holdings.push({
1619
+ description: '"Runs Runbooks" is on',
1620
+ remedy: 'turn off "Runs Runbooks"',
1621
+ });
1622
+ }
1623
+
1624
+ if (data.runner.canRunCodeFixTasks === true) {
1625
+ holdings.push({
1626
+ description: '"Runs AI Code Fixes" is on',
1627
+ remedy: 'turn off "Runs AI Code Fixes"',
1628
+ });
1629
+ }
1630
+
1631
+ const assignedCredentials: number = (
1632
+ await RunbookCredentialService.countBy({
1633
+ query: {
1634
+ projectId: data.projectId,
1635
+ runners: QueryHelper.inRelationArray([data.runner.id!]),
1636
+ },
1637
+ props: { isRoot: true },
1638
+ })
1639
+ ).toNumber();
1640
+
1641
+ if (assignedCredentials > 0) {
1642
+ holdings.push({
1643
+ description: `${assignedCredentials} Runner credential(s) assigned`,
1644
+ remedy: `unassign its ${assignedCredentials} Runner credential(s)`,
1645
+ });
1646
+ }
1647
+
1648
+ const assignedSecrets: number = (
1649
+ await RunbookSecretService.countBy({
1650
+ query: {
1651
+ projectId: data.projectId,
1652
+ runners: QueryHelper.inRelationArray([data.runner.id!]),
1653
+ },
1654
+ props: { isRoot: true },
1655
+ })
1656
+ ).toNumber();
1657
+
1658
+ if (assignedSecrets > 0) {
1659
+ holdings.push({
1660
+ description: `${assignedSecrets} runbook secret(s) assigned`,
1661
+ remedy: `unassign its ${assignedSecrets} runbook secret(s)`,
1662
+ });
1663
+ }
1664
+
1665
+ const otherBoundClusters: number = (
1666
+ await KubernetesClusterService.countBy({
1667
+ query: {
1668
+ projectId: data.projectId,
1669
+ aiAccessRunnerId: data.runner.id!,
1670
+ _id: QueryHelper.notEquals(data.clusterId),
1671
+ },
1672
+ props: { isRoot: true },
1673
+ })
1674
+ ).toNumber();
1675
+
1676
+ if (otherBoundClusters > 0) {
1677
+ holdings.push({
1678
+ description: `the AI access Runner of ${otherBoundClusters} other cluster(s)`,
1679
+ remedy: `select another Runner on the AI page of the ${otherBoundClusters} other cluster(s) bound to it`,
1680
+ });
1681
+ }
1682
+
1683
+ return holdings;
1684
+ }
1685
+
1686
+ /*
1687
+ * Bounds what an ingestion key can mint. Counted on the Runner rows
1688
+ * themselves (name prefix) so every registration path shares one brake.
1689
+ */
1690
+ private async assertAgentRunnerMayBeCreated(data: {
1691
+ projectId: ObjectID;
1692
+ clusterIdentifier: string;
1693
+ }): Promise<void> {
1694
+ const agentRunnerNameFilter: unknown = QueryHelper.startsWith(
1695
+ `${KUBERNETES_AGENT_RUNNER_NAME_PREFIX}/`,
1696
+ );
1697
+
1698
+ const totalAgentRunners: number = (
1699
+ await RunnerService.countBy({
1700
+ query: {
1701
+ projectId: data.projectId,
1702
+ name: agentRunnerNameFilter as never,
1703
+ },
1704
+ props: { isRoot: true },
1705
+ })
1706
+ ).toNumber();
1707
+
1708
+ if (totalAgentRunners >= MAX_KUBERNETES_AGENT_RUNNERS_PER_PROJECT) {
1709
+ logger.warn(
1710
+ `KubernetesClusterAiAccess: refused to create an agent Runner for cluster "${data.clusterIdentifier}" in project ${data.projectId.toString()}: the project already has ${totalAgentRunners} agent Runners (limit ${MAX_KUBERNETES_AGENT_RUNNERS_PER_PROJECT}).`,
1711
+ );
1712
+
1713
+ throw new TooManyRequestsException(
1714
+ `This project already has ${totalAgentRunners} in-cluster Runners, which is its limit (${MAX_KUBERNETES_AGENT_RUNNERS_PER_PROJECT}). Delete the Runners of clusters that no longer exist under Project Settings → Runners, then retry.`,
1715
+ );
1716
+ }
1717
+
1718
+ const createdInLastHour: number = (
1719
+ await RunnerService.countBy({
1720
+ query: {
1721
+ projectId: data.projectId,
1722
+ name: agentRunnerNameFilter as never,
1723
+ createdAt: QueryHelper.greaterThan(OneUptimeDate.getSomeHoursAgo(1)),
1724
+ },
1725
+ props: { isRoot: true },
1726
+ })
1727
+ ).toNumber();
1728
+
1729
+ if (
1730
+ createdInLastHour >= MAX_NEW_KUBERNETES_AGENT_RUNNERS_PER_PROJECT_PER_HOUR
1731
+ ) {
1732
+ logger.warn(
1733
+ `KubernetesClusterAiAccess: refused to create an agent Runner for cluster "${data.clusterIdentifier}" in project ${data.projectId.toString()}: ${createdInLastHour} agent Runners were created in the last hour (limit ${MAX_NEW_KUBERNETES_AGENT_RUNNERS_PER_PROJECT_PER_HOUR}).`,
1734
+ );
1735
+
1736
+ throw new TooManyRequestsException(
1737
+ `${createdInLastHour} in-cluster Runners were registered in this project in the last hour, which is its limit (${MAX_NEW_KUBERNETES_AGENT_RUNNERS_PER_PROJECT_PER_HOUR}). The Runner will be admitted when it retries later.`,
1738
+ );
1739
+ }
1740
+ }
1741
+
1742
+ // Best-effort: the feed must never fail the registration it describes.
1743
+ private async writeRegistrationFeedItem(data: {
1744
+ cluster: KubernetesCluster;
1745
+ runner: Runner;
1746
+ posture: KubernetesRunnerPosture;
1747
+ bindingState: KubernetesAgentRunnerBindingState;
1748
+ agentRunnerExistedBefore: boolean;
1749
+ // The mode a first bind left on the cluster; undefined otherwise.
1750
+ appliedRemediationMode?: KubernetesAiRemediationMode | undefined;
1751
+ // How an existing row's re-key was admitted; undefined for a new row.
1752
+ reKeyAdmission?: AgentRunnerReKeyAdmission | undefined;
1753
+ }): Promise<void> {
1754
+ try {
1755
+ const runnerName: string = data.runner.name || "kubernetes-agent";
1756
+ const writes: string = data.posture.allowWrites
1757
+ ? "writes allowed"
1758
+ : "read-only";
1759
+ const registered: string = this.describeRegistration(
1760
+ data.agentRunnerExistedBefore ? data.reKeyAdmission : undefined,
1761
+ );
1762
+
1763
+ let feedInfoInMarkdown: string;
1764
+ let displayColor: typeof Blue500 = Blue500;
1765
+
1766
+ if (data.bindingState === "first_bind") {
1767
+ displayColor = Green500;
1768
+ feedInfoInMarkdown = `🤖 The in-cluster Runner **${runnerName}** registered from the Kubernetes agent chart (${writes}) and was bound as this cluster's AI access Runner. AI investigation is on; AI remediation is ${this.describeRemediationMode(
1769
+ data.appliedRemediationMode,
1770
+ )}.`;
1771
+ } else if (data.bindingState === "bound_keeping_operator_settings") {
1772
+ displayColor = Green500;
1773
+ feedInfoInMarkdown = `🤖 The in-cluster Runner **${runnerName}** ${registered} from the Kubernetes agent chart (${writes}) and was bound as this cluster's AI access Runner. AI access had already been configured on the cluster's AI page, so no AI setting was changed: AI investigation with kubectl is ${
1774
+ data.cluster.isAiInvestigationEnabled === true ? "on" : "off"
1775
+ } and AI remediation is ${this.describeRemediationMode(
1776
+ data.cluster.aiRemediationMode,
1777
+ )}, as an operator chose.`;
1778
+ } else if (data.bindingState === "left_unbound_by_operator") {
1779
+ feedInfoInMarkdown = `🤖 The in-cluster Runner **${runnerName}** ${registered} (${writes}), but no Runner is bound to this cluster although one was before (or AI already ran kubectl here) — the binding was cleared by an operator, or the Runner it was bound to was deleted — so it was left unbound and no AI switch was changed. Select **${runnerName}** on the cluster's AI page to use it.`;
1780
+ } else if (data.bindingState === "bound_to_other_runner") {
1781
+ feedInfoInMarkdown = `🤖 The in-cluster Runner **${runnerName}** ${registered} (${writes}), but this cluster is bound to a different Runner in the dashboard, so it was not used.`;
1782
+ } else if (data.reKeyAdmission === "continuity") {
1783
+ feedInfoInMarkdown = `🔑 The in-cluster Runner **${runnerName}** re-registered and its key was rotated (${writes}). It presented its current key, so this is the same Runner.`;
1784
+ } else {
1785
+ /*
1786
+ * A re-key without proof is what a restarted pod looks like — and
1787
+ * also what anyone holding the telemetry ingestion key looks like.
1788
+ * Said plainly, so an unexpected one stands out from a restart.
1789
+ */
1790
+ displayColor = Yellow500;
1791
+ feedInfoInMarkdown = `🔑 The in-cluster Runner **${runnerName}** ${registered} (${writes}). That is expected when the agent's Runner pod restarts or is upgraded. If it did not, someone holding this project's telemetry ingestion key registered in its place: disable that key and delete this Runner so the agent registers afresh.`;
1792
+ }
1793
+
1794
+ await KubernetesClusterFeedService.createKubernetesClusterFeedItem({
1795
+ kubernetesClusterId: data.cluster.id!,
1796
+ projectId: data.cluster.projectId!,
1797
+ kubernetesClusterFeedEventType:
1798
+ KubernetesClusterFeedEventType.KubernetesClusterUpdated,
1799
+ displayColor,
1800
+ feedInfoInMarkdown,
1801
+ moreInformationInMarkdown: [
1802
+ `**Runner**: ${runnerName} (${data.runner.id?.toString() || "?"})`,
1803
+ `**Cluster identifier**: \`${data.posture.clusterIdentifier || ""}\``,
1804
+ `**kubectl**: ${data.posture.kubectlVersion || "not detected"}`,
1805
+ `**Agent chart**: ${data.posture.agentChartVersion || "unknown"}`,
1806
+ ].join("\n\n"),
1807
+ });
1808
+ } catch (error) {
1809
+ logger.error(
1810
+ `KubernetesClusterAiAccess: could not write the registration feed item for cluster ${data.cluster.id?.toString()}: ${error}`,
1811
+ );
1812
+ }
1813
+ }
1814
+
1815
+ /*
1816
+ * How the Runner came to hold its new key, in the feed's words: a new
1817
+ * row, a re-key the Runner proved (it presented its current key), or a
1818
+ * re-key without that proof — which names why it was admitted.
1819
+ */
1820
+ private describeRegistration(
1821
+ reKeyAdmission: AgentRunnerReKeyAdmission | undefined,
1822
+ ): string {
1823
+ switch (reKeyAdmission) {
1824
+ case undefined:
1825
+ return "registered";
1826
+ case "continuity":
1827
+ return "re-registered (its key was rotated; it presented its current key)";
1828
+ case "signed_off":
1829
+ return "re-registered and its key was rotated WITHOUT proof of continuity (it did not present its previous key; admitted because the previous instance had signed off)";
1830
+ case "never_connected":
1831
+ return "re-registered and its key was rotated WITHOUT proof of continuity (it did not present its previous key; admitted because the Runner had never connected)";
1832
+ default:
1833
+ return "re-registered and its key was rotated WITHOUT proof of continuity (it did not present its previous key; admitted because the previous instance had stopped heartbeating)";
1834
+ }
1835
+ }
1836
+
1837
+ // The AI page's label for a mode, quoted the way the page shows it.
1838
+ private describeRemediationMode(mode: unknown): string {
1839
+ switch (this.normalizeRemediationMode(mode)) {
1840
+ case KubernetesAiRemediationMode.RequireApproval:
1841
+ return '"Ask for approval"';
1842
+ case KubernetesAiRemediationMode.Automatic:
1843
+ return '"Automatic"';
1844
+ case KubernetesAiRemediationMode.BypassApproval:
1845
+ return '"Bypass approval"';
1846
+ default:
1847
+ return "Disabled";
1848
+ }
1849
+ }
1850
+
1851
+ // Constant-time comparison so a refusal cannot leak the key byte by byte.
1852
+ private isSameSecret(presented: string, current: string): boolean {
1853
+ const presentedBuffer: Buffer = Buffer.from(presented, "utf8");
1854
+ const currentBuffer: Buffer = Buffer.from(current, "utf8");
1855
+
1856
+ if (presentedBuffer.length !== currentBuffer.length) {
1857
+ return false;
1858
+ }
1859
+
1860
+ return crypto.timingSafeEqual(presentedBuffer, currentBuffer);
1861
+ }
1862
+
1863
+ /*
1864
+ * ------------------------------------------------------------------
1865
+ * Bookkeeping
1866
+ * ------------------------------------------------------------------
1867
+ */
1868
+
1869
+ // Best-effort: the AI page shows "last verified" / "last error" from this.
1870
+ @CaptureSpan()
1871
+ public async recordCommandOutcome(data: {
1872
+ clusterId: ObjectID;
1873
+ succeeded: boolean;
1874
+ errorMessage?: string | undefined;
1875
+ }): Promise<void> {
1876
+ try {
1877
+ await KubernetesClusterService.updateOneById({
1878
+ id: data.clusterId,
1879
+ data: (data.succeeded
1880
+ ? {
1881
+ aiAccessLastVerifiedAt: OneUptimeDate.getCurrentDate(),
1882
+ aiAccessLastError: null,
1883
+ }
1884
+ : {
1885
+ aiAccessLastError: (data.errorMessage || "Command failed.").slice(
1886
+ 0,
1887
+ 2000,
1888
+ ),
1889
+ }) as never,
1890
+ props: { isRoot: true },
1891
+ });
1892
+ } catch (error) {
1893
+ logger.error(
1894
+ `KubernetesClusterAiAccess: could not record command outcome for cluster ${data.clusterId.toString()}: ${error}`,
1895
+ );
1896
+ }
1897
+ }
1898
+
1899
+ public normalizeRemediationMode(value: unknown): KubernetesAiRemediationMode {
1900
+ if (
1901
+ value === KubernetesAiRemediationMode.RequireApproval ||
1902
+ value === KubernetesAiRemediationMode.Automatic ||
1903
+ value === KubernetesAiRemediationMode.BypassApproval
1904
+ ) {
1905
+ return value;
1906
+ }
1907
+ return KubernetesAiRemediationMode.Disabled;
1908
+ }
1909
+
1910
+ /*
1911
+ * The allowlist column is jsonb; the dashboard may save it as an array or
1912
+ * as a JSON string. Anything unusable normalizes to empty — nothing
1913
+ * risky auto-executes.
1914
+ */
1915
+ public normalizeAllowlist(value: unknown): Array<string> {
1916
+ let raw: unknown = value;
1917
+
1918
+ if (typeof raw === "string") {
1919
+ try {
1920
+ raw = JSON.parse(raw);
1921
+ } catch {
1922
+ raw = [value];
1923
+ }
1924
+ }
1925
+
1926
+ if (!Array.isArray(raw)) {
1927
+ return [];
1928
+ }
1929
+
1930
+ return raw
1931
+ .filter((pattern: unknown) => {
1932
+ return typeof pattern === "string" && pattern.trim().length > 0;
1933
+ })
1934
+ .map((pattern: string) => {
1935
+ return pattern.trim();
1936
+ });
1937
+ }
1938
+ }
1939
+
1940
+ const KubernetesClusterAiAccessService: KubernetesClusterAiAccessServiceClass =
1941
+ new KubernetesClusterAiAccessServiceClass();
1942
+
1943
+ export default KubernetesClusterAiAccessService;