@oneuptime/common 13.0.0 → 13.0.1

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 (734) hide show
  1. package/Models/DatabaseModels/Alert.ts +55 -0
  2. package/Models/DatabaseModels/CloudResource.ts +45 -7
  3. package/Models/DatabaseModels/CodeRepository.ts +85 -0
  4. package/Models/DatabaseModels/GoogleSecOpsConnection.ts +57 -7
  5. package/Models/DatabaseModels/GoogleSecOpsConnectionRun.ts +263 -0
  6. package/Models/DatabaseModels/Incident.ts +55 -0
  7. package/Models/DatabaseModels/Index.ts +16 -0
  8. package/Models/DatabaseModels/ScheduledMaintenance.ts +55 -0
  9. package/Models/DatabaseModels/User.ts +51 -2
  10. package/Models/DatabaseModels/UserNotificationEmailRollupItem.ts +43 -2
  11. package/Models/DatabaseModels/UserWebAuthn.ts +17 -0
  12. package/Models/DatabaseModels/VMwareResource.ts +1149 -0
  13. package/Models/DatabaseModels/VMwareVCenter.ts +1122 -0
  14. package/Models/DatabaseModels/VMwareVCenterFeed.ts +625 -0
  15. package/Models/DatabaseModels/VMwareVCenterLabelRule.ts +514 -0
  16. package/Models/DatabaseModels/VMwareVCenterOwnerRule.ts +596 -0
  17. package/Models/DatabaseModels/VMwareVCenterOwnerTeam.ts +485 -0
  18. package/Models/DatabaseModels/VMwareVCenterOwnerUser.ts +484 -0
  19. package/Models/DatabaseModels/WorkflowVariable.ts +22 -1
  20. package/Server/API/AIAgentDataAPI.ts +79 -4
  21. package/Server/API/AIAgentGitHubAPI.ts +523 -0
  22. package/Server/API/AIChatAPI.ts +20 -1
  23. package/Server/API/BillingAPI.ts +33 -0
  24. package/Server/API/DashboardAPI.ts +10 -0
  25. package/Server/API/GitHubAPI.ts +47 -5
  26. package/Server/API/GoogleSecOpsConnectionAPI.ts +79 -0
  27. package/Server/API/UserWebAuthnAPI.ts +21 -1
  28. package/Server/API/VMwareResourceAPI.ts +143 -0
  29. package/Server/Infrastructure/Postgres/SchemaMigrations/1791800000000-SplitWebAuthnChallengeByPurpose.ts +68 -0
  30. package/Server/Infrastructure/Postgres/SchemaMigrations/1791900000000-AddSeverityAndStateToNotificationEmailRollup.ts +26 -0
  31. package/Server/Infrastructure/Postgres/SchemaMigrations/1792000000000-AddVMwareTables.ts +636 -0
  32. package/Server/Infrastructure/Postgres/SchemaMigrations/1792100000000-AddGitHubCommandSettingsToCodeRepository.ts +47 -0
  33. package/Server/Infrastructure/Postgres/SchemaMigrations/1792200000000-AddUserWebAuthnPurpose.ts +17 -0
  34. package/Server/Infrastructure/Postgres/SchemaMigrations/1792300000000-AddGoogleSecOpsDiagnostics.ts +83 -0
  35. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +12 -0
  36. package/Server/Middleware/IdentityRateLimit.ts +101 -0
  37. package/Server/Services/AIRunService.ts +13 -0
  38. package/Server/Services/BillingPaymentMethodService.ts +99 -28
  39. package/Server/Services/BillingService.ts +287 -20
  40. package/Server/Services/CloudResourceInstanceService.ts +70 -0
  41. package/Server/Services/ExceptionAggregationService.ts +1 -0
  42. package/Server/Services/GoogleSecOpsConnectionRunService.ts +10 -0
  43. package/Server/Services/GoogleSecOpsConnectionService.ts +12 -0
  44. package/Server/Services/Index.ts +16 -0
  45. package/Server/Services/LogAggregationService.ts +1 -0
  46. package/Server/Services/MetricAggregationService.ts +1 -0
  47. package/Server/Services/MobilePasskeyLoginService.ts +216 -0
  48. package/Server/Services/MonitorService.ts +51 -1
  49. package/Server/Services/MonitorTemplateService.ts +91 -29
  50. package/Server/Services/NetworkDeviceAutoImportRuleEngineService.ts +132 -1
  51. package/Server/Services/NetworkDeviceAutoImportRuleService.ts +176 -2
  52. package/Server/Services/OpenTelemetryIngestService.ts +17 -0
  53. package/Server/Services/PayAsYouGoBillingService.ts +446 -0
  54. package/Server/Services/ProjectService.ts +46 -2
  55. package/Server/Services/ServerlessFunctionInstanceService.ts +71 -0
  56. package/Server/Services/TeamMemberService.ts +96 -36
  57. package/Server/Services/TelemetryIngestionKeyService.ts +80 -10
  58. package/Server/Services/TelemetryUsageBillingService.ts +95 -5
  59. package/Server/Services/TraceAggregationService.ts +5 -4
  60. package/Server/Services/UserWebAuthnService.ts +592 -133
  61. package/Server/Services/VMwareResourceService.ts +648 -0
  62. package/Server/Services/VMwareVCenterFeedService.ts +99 -0
  63. package/Server/Services/VMwareVCenterLabelRuleEngineService.ts +240 -0
  64. package/Server/Services/VMwareVCenterLabelRuleService.ts +14 -0
  65. package/Server/Services/VMwareVCenterOwnerRuleEngineService.ts +252 -0
  66. package/Server/Services/VMwareVCenterOwnerRuleService.ts +14 -0
  67. package/Server/Services/VMwareVCenterOwnerTeamService.ts +139 -0
  68. package/Server/Services/VMwareVCenterOwnerUserService.ts +133 -0
  69. package/Server/Services/VMwareVCenterService.ts +629 -0
  70. package/Server/Services/WorkflowVariableService.ts +203 -0
  71. package/Server/Types/Billing/MeteredPlan/ActiveMonitoringMeteredPlan.ts +17 -0
  72. package/Server/Types/Billing/MeteredPlan/TelemetryMeteredPlan.ts +31 -1
  73. package/Server/Utils/CodeRepository/GitHub/GitHub.ts +7 -0
  74. package/Server/Utils/CodeRepository/GitHub/GitHubAgentTaskTrigger.ts +341 -0
  75. package/Server/Utils/CodeRepository/GitHub/GitHubCommandAuthorizer.ts +274 -0
  76. package/Server/Utils/CodeRepository/GitHub/GitHubCommandParser.ts +375 -0
  77. package/Server/Utils/CodeRepository/GitHub/GitHubConversation.ts +846 -0
  78. package/Server/Utils/CodeRepository/GitHub/GitHubReplyComposer.ts +360 -0
  79. package/Server/Utils/CodeRepository/GitHub/GitHubRunReply.ts +421 -0
  80. package/Server/Utils/CodeRepository/GitHub/GitHubWebhookEvents.ts +140 -0
  81. package/Server/Utils/CodeRepository/GitHub/GitHubWebhookHandler.ts +906 -0
  82. package/Server/Utils/Dashboard/PublicDashboardResourceListPolicy.ts +143 -0
  83. package/Server/Utils/DataSource/EgressGuard.ts +160 -15
  84. package/Server/Utils/Database/TruncateColumnValue.ts +1 -1
  85. package/Server/Utils/EmailRollup/EmailRollupFlushRunner.ts +2 -0
  86. package/Server/Utils/EmailRollup/EmailRollupRenderer.ts +33 -0
  87. package/Server/Utils/EmailRollup/EmailRollupWriter.ts +44 -0
  88. package/Server/Utils/LogRedaction.ts +2 -1
  89. package/Server/Utils/Monitor/MonitorAlert.ts +1 -1
  90. package/Server/Utils/Monitor/MonitorCriteriaEvaluator.ts +302 -3
  91. package/Server/Utils/Monitor/MonitorMaintenanceSuppression.ts +26 -4
  92. package/Server/Utils/Monitor/MonitorResourceContext.ts +5 -3
  93. package/Server/Utils/Monitor/MonitorStepResourceIdentity.ts +14 -0
  94. package/Server/Utils/Monitor/MonitorTemplateUtil.ts +1 -0
  95. package/Server/Utils/Monitor/SeriesResourceLabels.ts +26 -0
  96. package/Server/Utils/Monitor/SeriesResourceLinker.ts +28 -5
  97. package/Server/Utils/ResourceFeed/ResourceFeedUtil.ts +3 -3
  98. package/Server/Utils/SecurityEvent/ConnectorErrorMessage.ts +14 -9
  99. package/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsClient.ts +116 -84
  100. package/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsPoller.ts +594 -195
  101. package/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsRunExecutor.ts +466 -0
  102. package/Server/Utils/Telemetry/EntityRegistry.ts +5 -0
  103. package/Server/Utils/Telemetry/ResourceHeartbeat.ts +2 -1
  104. package/Server/Utils/Telemetry/TelemetryEntity.ts +181 -1
  105. package/Server/Utils/Telemetry/VMwareSnapshotScan.ts +1352 -0
  106. package/Tests/App/Accounts/LoginPasskey.test.tsx +529 -0
  107. package/Tests/App/Accounts/MobilePasskey.test.tsx +620 -0
  108. package/Tests/App/Accounts/PasswordRequirements.test.tsx +254 -0
  109. package/Tests/App/Accounts/RegisterPassword.test.tsx +553 -0
  110. package/Tests/App/Dashboard/AskAiAvailability.test.ts +224 -0
  111. package/Tests/App/Dashboard/AskAiDisabled.test.tsx +432 -0
  112. package/Tests/App/Dashboard/BackupCodes.test.tsx +414 -0
  113. package/Tests/App/Dashboard/BillingPaidUsageFlow.test.tsx +530 -0
  114. package/Tests/App/Dashboard/BillingPaymentMethodForm.test.tsx +195 -0
  115. package/Tests/App/Dashboard/BreadcrumbCoverage.test.tsx +199 -0
  116. package/Tests/App/Dashboard/CloudDocumentationCard.test.tsx +198 -0
  117. package/Tests/App/Dashboard/CloudDocumentationMarkdown.test.ts +215 -0
  118. package/Tests/App/Dashboard/CloudFleetSummary.test.ts +183 -0
  119. package/Tests/App/Dashboard/CloudFleetSummaryComponent.test.tsx +248 -0
  120. package/Tests/App/Dashboard/CloudResourceTelemetryScope.test.ts +215 -0
  121. package/Tests/App/Dashboard/CriteriaFilterDefaults.test.ts +3 -0
  122. package/Tests/App/Dashboard/DashboardHeaderRequests.test.tsx +441 -0
  123. package/Tests/App/Dashboard/DashboardLazyPages.test.tsx +458 -0
  124. package/Tests/App/Dashboard/DashboardToolbarPopupLayering.test.tsx +566 -0
  125. package/Tests/App/Dashboard/DiscoveryScanLivePage.test.tsx +376 -0
  126. package/Tests/App/Dashboard/DiscoveryScanLiveUpdates.test.tsx +642 -0
  127. package/Tests/App/Dashboard/DiscoveryScanProgress.test.tsx +267 -0
  128. package/Tests/App/Dashboard/DiscoveryScanWizardValidation.test.tsx +69 -231
  129. package/Tests/App/Dashboard/GoogleSecOpsConnectionsErrors.test.tsx +244 -0
  130. package/Tests/App/Dashboard/GoogleSecOpsDiagnostics.test.tsx +724 -0
  131. package/Tests/App/Dashboard/MonitorTemplateSyncFields.test.tsx +539 -0
  132. package/Tests/App/Dashboard/OnCallLayerCardOverrides.test.tsx +24 -7
  133. package/Tests/App/Dashboard/OnCallOverridePresentation.test.ts +496 -0
  134. package/Tests/App/Dashboard/OnCallScheduleOverrideClarity.test.tsx +677 -0
  135. package/Tests/App/Dashboard/OnCallSchedulePreviewOverrides.test.tsx +31 -3
  136. package/Tests/App/Dashboard/PaidUsageConsent.test.tsx +180 -0
  137. package/Tests/App/Dashboard/PasskeySettings.test.tsx +1220 -0
  138. package/Tests/App/Dashboard/PayAsYouGoConsentGate.test.tsx +176 -275
  139. package/Tests/App/Dashboard/PayAsYouGoNotices.test.tsx +380 -233
  140. package/Tests/App/Dashboard/ProductMenuBreadcrumbs.test.tsx +3 -23
  141. package/Tests/App/Dashboard/ResourceFeed.test.tsx +1 -0
  142. package/Tests/App/Dashboard/ResourceFeedPageWiring.test.ts +8 -1
  143. package/Tests/App/Dashboard/TwoFactorStatus.test.tsx +260 -0
  144. package/Tests/App/Dashboard/VMwareDashboardWidgets.test.ts +573 -0
  145. package/Tests/App/Dashboard/WidgetCatalog.test.ts +2 -0
  146. package/Tests/App/Dashboard/WorkflowVariablesTable.test.tsx +768 -0
  147. package/Tests/App/StatusPage/StatusPageOverviewLiveAndSearch.test.tsx +532 -40
  148. package/Tests/App/StatusPage/StatusPageResourceSearchBox.test.tsx +19 -2
  149. package/Tests/Fixtures/MobilePasskeyUser.json +8 -0
  150. package/Tests/Models/DatabaseModels/ResourceFeedModels.test.ts +25 -6
  151. package/Tests/Models/DatabaseModels/VMwareModels.test.ts +1134 -0
  152. package/Tests/Models/RunnerVersionLabel.test.ts +4 -2
  153. package/Tests/Server/API/AIChatProvidersAIEnabled.test.ts +259 -0
  154. package/Tests/Server/API/AIChatRouteAuthorization.test.ts +31 -2
  155. package/Tests/Server/API/BillingPayAsYouGoStatus.test.ts +116 -0
  156. package/Tests/Server/API/DashboardPublicResourceListAPI.test.ts +29 -1
  157. package/Tests/Server/API/EnterpriseLicenseReportUserCount.test.ts +13 -2
  158. package/Tests/Server/API/GitHubWebhookSignature.test.ts +368 -0
  159. package/Tests/Server/API/GoogleSecOpsConnectionAPI.test.ts +248 -0
  160. package/Tests/Server/API/UserWebAuthnAuthenticationOptionsRoute.test.ts +330 -0
  161. package/Tests/Server/API/UserWebAuthnPasskeyAPI.test.ts +172 -0
  162. package/Tests/Server/API/VMwareResourceAPI.test.ts +546 -0
  163. package/Tests/Server/Infrastructure/Postgres/UserNotificationEmailRollupMetadataMigration.test.ts +85 -0
  164. package/Tests/Server/Infrastructure/Postgres/UserNotificationEmailRollupTableMigration.test.ts +34 -3
  165. package/Tests/Server/Middleware/PasskeyRateLimit.test.ts +141 -0
  166. package/Tests/Server/Services/AutoImportRuleRearmRecentScans.test.ts +343 -0
  167. package/Tests/Server/Services/AutoImportRuleWriteRearmsScans.test.ts +381 -0
  168. package/Tests/Server/Services/BillingPaymentMethodServiceSync.test.ts +175 -0
  169. package/Tests/Server/Services/BillingService.test.ts +26 -11
  170. package/Tests/Server/Services/BillingServiceMeteredPaymentAuthorization.test.ts +245 -0
  171. package/Tests/Server/Services/BillingServicePaymentMethodReads.test.ts +362 -0
  172. package/Tests/Server/Services/CloudResourceInstanceStalePrune.test.ts +188 -0
  173. package/Tests/Server/Services/DiscoveryScanClaimHookFreeSafety.test.ts +16 -2
  174. package/Tests/Server/Services/GoogleSecOpsDiagnosticsModel.test.ts +153 -0
  175. package/Tests/Server/Services/HookFreeWriteLengthClamp.test.ts +13 -0
  176. package/Tests/Server/Services/InventoryItemPromotionGate.test.ts +5 -0
  177. package/Tests/Server/Services/InventoryUpsertSchemaParity.test.ts +36 -0
  178. package/Tests/Server/Services/InventoryUpsertTruncationGuard.test.ts +151 -0
  179. package/Tests/Server/Services/MobilePasskeyLoginIntegration.test.ts +231 -0
  180. package/Tests/Server/Services/MobilePasskeyLoginService.test.ts +315 -0
  181. package/Tests/Server/Services/MonitorPayAsYouGoBilling.test.ts +302 -0
  182. package/Tests/Server/Services/MonitorTemplateServiceFieldSync.test.ts +994 -0
  183. package/Tests/Server/Services/NetworkDeviceAutoImportRuleService.test.ts +22 -0
  184. package/Tests/Server/Services/OpenTelemetryResourceRetentionMemo.test.ts +7 -1
  185. package/Tests/Server/Services/PayAsYouGoBillingService.test.ts +857 -0
  186. package/Tests/Server/Services/PayAsYouGoStripeRateLimitBudget.test.ts +379 -0
  187. package/Tests/Server/Services/ProjectServiceExtendTrial.test.ts +99 -1
  188. package/Tests/Server/Services/ProjectServiceSubscriptionSeats.test.ts +134 -0
  189. package/Tests/Server/Services/ResourceFeedServices.test.ts +3 -2
  190. package/Tests/Server/Services/ResourceUpdateLastSeenLivenessFallback.test.ts +32 -6
  191. package/Tests/Server/Services/SecurityEventLastErrorColumnWidth.test.ts +363 -175
  192. package/Tests/Server/Services/ServerlessFunctionInstanceStalePrune.test.ts +200 -0
  193. package/Tests/Server/Services/TeamMemberAutoAcceptInvitation.test.ts +3 -0
  194. package/Tests/Server/Services/TeamMemberBillingSeatSync.test.ts +762 -0
  195. package/Tests/Server/Services/TeamMemberInviteRegistrationToken.test.ts +3 -0
  196. package/Tests/Server/Services/TelemetryIngestionKeyPolicyResolution.test.ts +72 -0
  197. package/Tests/Server/Services/TelemetryIngestionKeyValidation.test.ts +17 -4
  198. package/Tests/Server/Services/TelemetryPayAsYouGoBilling.test.ts +355 -0
  199. package/Tests/Server/Services/TraceAnalyticsResourceDisplayNames.test.ts +41 -4
  200. package/Tests/Server/Services/UserNotificationEmailRollupModels.test.ts +37 -0
  201. package/Tests/Server/Services/UserWebAuthnPasskeyIntegration.test.ts +401 -0
  202. package/Tests/Server/Services/UserWebAuthnPasskeyService.test.ts +769 -0
  203. package/Tests/Server/Services/UserWebAuthnUserVerification.test.ts +649 -0
  204. package/Tests/Server/Services/VMwareResourceService.test.ts +945 -0
  205. package/Tests/Server/Services/VMwareVCenterService.test.ts +722 -0
  206. package/Tests/Server/Services/WorkflowVariableRenameUniqueness.test.ts +842 -0
  207. package/Tests/Server/TestingUtils/PasskeyHttpIntegration.ts +102 -0
  208. package/Tests/Server/TestingUtils/SecurityKey.ts +464 -0
  209. package/Tests/Server/TestingUtils/WebAuthnServiceMocks.ts +60 -0
  210. package/Tests/Server/Types/Billing/PayAsYouGoMeteredAuthorization.test.ts +573 -0
  211. package/Tests/Server/Types/Database/Permissions/ProjectCustomerSupportAccessColumn.test.ts +261 -0
  212. package/Tests/Server/Types/Database/Permissions/WorkflowVariableColumnPermission.test.ts +95 -0
  213. package/Tests/Server/Utils/CodeRepository/GitHubAgentTaskTrigger.test.ts +2101 -0
  214. package/Tests/Server/Utils/CodeRepository/GitHubCommandAuthorizer.test.ts +883 -0
  215. package/Tests/Server/Utils/CodeRepository/GitHubCommandParser.test.ts +1474 -0
  216. package/Tests/Server/Utils/CodeRepository/GitHubConversation.test.ts +1526 -0
  217. package/Tests/Server/Utils/CodeRepository/GitHubReplyComposer.test.ts +1389 -0
  218. package/Tests/Server/Utils/CodeRepository/GitHubRunReply.test.ts +1707 -0
  219. package/Tests/Server/Utils/CodeRepository/GitHubWebhookHandler.test.ts +2202 -0
  220. package/Tests/Server/Utils/Dashboard/PublicDashboardResourceListPolicy.test.ts +345 -0
  221. package/Tests/Server/Utils/DataSource/EgressGuard.test.ts +896 -0
  222. package/Tests/Server/Utils/EmailRollup/EmailRollupMetadataIntegration.test.ts +246 -0
  223. package/Tests/Server/Utils/EmailRollup/EmailRollupRenderer.test.ts +299 -1
  224. package/Tests/Server/Utils/EmailRollup/EmailRollupTestHarness.ts +6 -0
  225. package/Tests/Server/Utils/EmailRollup/EmailRollupWriter.test.ts +185 -0
  226. package/Tests/Server/Utils/LogRedaction.test.ts +33 -0
  227. package/Tests/Server/Utils/Monitor/CapturedMetricAttributeUtil.test.ts +2 -1
  228. package/Tests/Server/Utils/Monitor/Criteria/TelemetryStepMetricAlias.test.ts +10 -0
  229. package/Tests/Server/Utils/Monitor/MonitorAlertResourceLinking.test.ts +66 -1
  230. package/Tests/Server/Utils/Monitor/MonitorCriteriaEvaluator.test.ts +362 -0
  231. package/Tests/Server/Utils/Monitor/MonitorDependencySuppressionCreatorSkip.test.ts +1 -0
  232. package/Tests/Server/Utils/Monitor/MonitorIncidentResourceLinking.test.ts +60 -1
  233. package/Tests/Server/Utils/Monitor/MonitorMaintenanceSuppression.test.ts +60 -0
  234. package/Tests/Server/Utils/Monitor/MonitorRootCauseTargetResolution.test.ts +423 -0
  235. package/Tests/Server/Utils/Monitor/MonitorStepResourceIdentity.test.ts +6 -0
  236. package/Tests/Server/Utils/Monitor/MonitorSummaryPersistence.test.ts +1 -0
  237. package/Tests/Server/Utils/Monitor/PerSeriesSecondEntityAlerting.test.ts +1 -0
  238. package/Tests/Server/Utils/Monitor/SeriesResourceLinker.test.ts +46 -2
  239. package/Tests/Server/Utils/SecurityEvent/ConnectorErrorMessage.test.ts +81 -45
  240. package/Tests/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsRunExecutor.test.ts +711 -0
  241. package/Tests/Server/Utils/SecurityEvent/GoogleSecOpsClickhouseIntegration.test.ts +223 -0
  242. package/Tests/Server/Utils/SecurityEvent/GoogleSecOpsClient.test.ts +69 -1
  243. package/Tests/Server/Utils/SecurityEvent/GoogleSecOpsDiagnostics.test.ts +838 -0
  244. package/Tests/Server/Utils/SecurityEvent/GoogleSecOpsErrorHandling.test.ts +241 -28
  245. package/Tests/Server/Utils/SecurityEvent/GoogleSecOpsHttpIntegration.test.ts +651 -0
  246. package/Tests/Server/Utils/SecurityEvent/GoogleSecOpsPoller.test.ts +11 -0
  247. package/Tests/Server/Utils/SecurityEvent/GoogleSecOpsPollerFailureTaxonomy.test.ts +13 -12
  248. package/Tests/Server/Utils/SecurityEvent/GoogleSecOpsPollerHardening.test.ts +112 -127
  249. package/Tests/Server/Utils/SecurityEvent/GoogleSecOpsRequestContract.test.ts +12 -18
  250. package/Tests/Server/Utils/SecurityEvent/GoogleSecOpsResponseParsing.test.ts +43 -0
  251. package/Tests/Server/Utils/Telemetry/TelemetryEntity.test.ts +580 -0
  252. package/Tests/Server/Utils/Telemetry/VMwareSnapshotScan.test.ts +1748 -0
  253. package/Tests/Types/Cloud/CloudPlatform.test.ts +574 -0
  254. package/Tests/Types/Monitor/MetricAndProfileDefaultCriteria.test.ts +2 -0
  255. package/Tests/Types/Monitor/MonitorCriteriaMetricVariables.test.ts +9 -0
  256. package/Tests/Types/Monitor/MonitorStepDefaultTelemetryConfig.test.ts +1 -0
  257. package/Tests/Types/Monitor/MonitorStepInfraMonitorUtils.test.ts +53 -8
  258. package/Tests/Types/Monitor/MonitorStepInfrastructureMonitors.test.ts +97 -0
  259. package/Tests/Types/Monitor/MonitorStepMetricViewConfigUtil.test.ts +1 -0
  260. package/Tests/Types/Monitor/MonitorStepTemplateSyncFields.test.ts +107 -0
  261. package/Tests/Types/Monitor/MonitorTemplateSyncField.test.ts +172 -0
  262. package/Tests/Types/Monitor/MonitorType.test.ts +1 -0
  263. package/Tests/Types/Monitor/MonitorTypeKeywords.test.ts +2 -0
  264. package/Tests/Types/Monitor/Recommendation/MonitorRecommendationAlertDebuggability.test.ts +1 -0
  265. package/Tests/Types/Monitor/Recommendation/MonitorRecommendationCatalog.test.ts +9 -0
  266. package/Tests/Types/Monitor/Recommendation/MonitorRecommendationCoverage.test.ts +1 -1
  267. package/Tests/Types/Monitor/Recommendation/MonitorRecommendationNotificationMode.test.ts +1 -1
  268. package/Tests/Types/Monitor/SeriesContext/SeriesDebugHints.test.ts +131 -0
  269. package/Tests/Types/Monitor/SeriesContext/SeriesLabelDisplay.test.ts +10 -0
  270. package/Tests/Types/Monitor/VMwareAlertTemplates.test.ts +1608 -0
  271. package/Tests/Types/Monitor/VMwareMetricCatalog.test.ts +488 -0
  272. package/Tests/Types/OnCallDutyPolicy/OverrideProvenance.test.ts +295 -0
  273. package/Tests/Types/Runner/RunnerLiveStatus.test.ts +2 -2
  274. package/Tests/Types/SignupPassword.test.ts +205 -0
  275. package/Tests/Types/StatusPage/StatusPageLanguage.test.ts +44 -0
  276. package/Tests/Types/SupportedLanguages.test.ts +119 -0
  277. package/Tests/Types/Telemetry/EntityTypeGroups.test.ts +19 -0
  278. package/Tests/UI/ColorPickerBuild.test.ts +86 -0
  279. package/Tests/UI/Components/Breadcrumbs.test.tsx +32 -0
  280. package/Tests/UI/Components/Forms/ModelFormPreservesUserInput.test.tsx +937 -0
  281. package/Tests/UI/Components/Forms/ModelFormWriteOnlyColumnSelect.test.tsx +230 -0
  282. package/Tests/UI/Components/Forms/ValidationFormSteps.test.ts +3 -4
  283. package/Tests/UI/Components/LabelRuleImportExport.test.tsx +907 -0
  284. package/Tests/UI/Components/ModelTable/ModelTableCreateAfterEdit.test.tsx +514 -0
  285. package/Tests/UI/Components/MonitorGraphs/Uptime.test.tsx +301 -0
  286. package/Tests/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.test.ts +2 -1
  287. package/Tests/UI/Components/TooltipLazyContent.test.tsx +373 -0
  288. package/Tests/UI/MicrosoftTeams/MicrosoftTeamsMessagingEndpointGuidance.test.tsx +43 -12
  289. package/Tests/UI/ReactDomBuild.test.ts +104 -0
  290. package/Tests/UI/ReactRouterSingletonBuild.test.ts +11 -1
  291. package/Tests/UI/Utils/Breadcrumb/fixtures/RealBreadcrumbTrails.ts +148 -0
  292. package/Tests/UI/Utils/Breadcrumb/fixtures/RealRoutePatterns.ts +29 -0
  293. package/Tests/UI/Utils/DashboardStackingLayers.test.ts +197 -0
  294. package/Tests/UI/Utils/LabelRuleImportExport.test.ts +546 -0
  295. package/Tests/UI/Utils/ModelAPITenantHeader.test.ts +109 -2
  296. package/Tests/UI/Utils/UseDashboardGridDnd.test.tsx +7 -2
  297. package/Tests/UI/Utils/UserEmailRegistrationStatus.test.tsx +295 -0
  298. package/Tests/UI/Utils/WebAuthn.test.ts +265 -0
  299. package/Tests/Utils/Dashboard/Components/DashboardComponentDefaults.test.ts +5 -0
  300. package/Tests/Utils/Dashboard/Components/DashboardVMwareListComponents.test.ts +548 -0
  301. package/Tests/Utils/Dashboard/DashboardResourceListSharedArgs.test.ts +17 -3
  302. package/Tests/Utils/LabelRuleImportExport.test.ts +583 -0
  303. package/Tests/Utils/Monitor/MonitorSummarySnapshotUtil.test.ts +1 -0
  304. package/Tests/Utils/Monitor/MonitorTemplateSyncUtil.test.ts +590 -0
  305. package/Tests/Utils/RequestFailedDetails.test.ts +325 -0
  306. package/Tests/Utils/Telemetry/CloudInstanceIdentity.test.ts +255 -0
  307. package/Tests/Utils/Telemetry/EntityRelationship.test.ts +167 -0
  308. package/Tests/Utils/WebAuthnTestUtil.ts +79 -0
  309. package/Tests/__mocks__/simplewebauthn.js +33 -4
  310. package/Types/AI/CodeFixTaskContext.ts +122 -0
  311. package/Types/AI/CodeFixTaskType.ts +62 -0
  312. package/Types/Accounts/AccountsLanguage.ts +1 -0
  313. package/Types/AdminDashboard/AdminDashboardLanguage.ts +1 -0
  314. package/Types/Calendar/CalendarEvent.ts +16 -0
  315. package/Types/Cloud/CloudPlatform.ts +372 -0
  316. package/Types/CodeRepository/GitHubCommand.ts +69 -0
  317. package/Types/Dashboard/DashboardComponentType.ts +2 -0
  318. package/Types/Dashboard/DashboardComponents/ComponentArgument.ts +1 -0
  319. package/Types/Dashboard/DashboardComponents/DashboardVMwareHostListComponent.ts +23 -0
  320. package/Types/Dashboard/DashboardComponents/DashboardVMwareVirtualMachineListComponent.ts +30 -0
  321. package/Types/Dashboard/DashboardLanguage.ts +1 -0
  322. package/Types/Dashboard/DashboardTemplates.ts +314 -0
  323. package/Types/Docs/DocsLanguage.ts +1 -0
  324. package/Types/Exception/EgressGuardException.ts +65 -0
  325. package/Types/Icon/IconProp.ts +1 -0
  326. package/Types/Monitor/MetricMonitor/MetricMonitorResponse.ts +36 -0
  327. package/Types/Monitor/MonitorCriteriaInstance.ts +1 -0
  328. package/Types/Monitor/MonitorStep.ts +78 -17
  329. package/Types/Monitor/MonitorStepMetricViewConfigUtil.ts +1 -0
  330. package/Types/Monitor/MonitorStepVMwareMonitor.ts +127 -0
  331. package/Types/Monitor/MonitorTemplateSyncField.ts +291 -0
  332. package/Types/Monitor/MonitorType.ts +24 -0
  333. package/Types/Monitor/Recommendation/MonitorRecommendationCatalog.ts +33 -0
  334. package/Types/Monitor/Recommendation/MonitorRecommendationTypes.ts +2 -0
  335. package/Types/Monitor/Recommendation/MonitorRecommendationUtil.ts +3 -0
  336. package/Types/Monitor/SeriesContext/SeriesDebugHints.ts +158 -0
  337. package/Types/Monitor/SeriesContext/SeriesLabelDisplay.ts +61 -0
  338. package/Types/Monitor/VMwareAlertTemplates.ts +1070 -0
  339. package/Types/Monitor/VMwareMetricCatalog.ts +914 -0
  340. package/Types/OnCallDutyPolicy/ScheduleShiftUtil.ts +29 -0
  341. package/Types/OnCallDutyPolicy/UserOverrideUtil.ts +16 -0
  342. package/Types/Password.ts +84 -5
  343. package/Types/Permission.ts +265 -0
  344. package/Types/Probe/RequestFailedDetails.ts +7 -0
  345. package/Types/Runner/RunnerLiveStatus.ts +1 -1
  346. package/Types/SecurityEvent/GoogleSecOpsDiagnostics.ts +56 -0
  347. package/Types/StatusPage/StatusPageLanguage.ts +1 -0
  348. package/Types/Telemetry/EntityType.ts +21 -0
  349. package/Types/Telemetry/ServiceType.ts +1 -0
  350. package/Typings/Index.d.ts +63 -0
  351. package/UI/Components/Breadcrumbs/Breadcrumbs.tsx +2 -2
  352. package/UI/Components/Calendar/Calendar.css +78 -0
  353. package/UI/Components/Calendar/Calendar.tsx +28 -3
  354. package/UI/Components/Forms/BasicForm.tsx +44 -2
  355. package/UI/Components/Forms/Fields/ColorPicker.tsx +2 -1
  356. package/UI/Components/Forms/Fields/FormField.tsx +16 -3
  357. package/UI/Components/Forms/ModelForm.tsx +159 -5
  358. package/UI/Components/Forms/Types/Field.ts +8 -1
  359. package/UI/Components/Graphs/DayUptimeGraph.tsx +8 -10
  360. package/UI/Components/Icon/Icon.tsx +16 -0
  361. package/UI/Components/Input/Input.tsx +42 -7
  362. package/UI/Components/LabelRule/ImportLabelRulesModal.tsx +441 -0
  363. package/UI/Components/LabelRule/LabelRuleTable.tsx +142 -0
  364. package/UI/Components/ModelTable/BaseModelTable.tsx +22 -5
  365. package/UI/Components/ModelTable/ModelTable.tsx +14 -6
  366. package/UI/Components/MonitorGraphs/Uptime.tsx +17 -27
  367. package/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.ts +3 -1
  368. package/UI/Components/Tooltip/Tooltip.tsx +52 -6
  369. package/UI/Utils/DashboardStackingLayers.ts +85 -0
  370. package/UI/Utils/LabelRuleImportExport.ts +310 -0
  371. package/UI/Utils/ModelAPI/ModelAPI.ts +4 -3
  372. package/UI/Utils/TelemetryService.ts +4 -3
  373. package/UI/Utils/UseDashboardGridDnd.ts +4 -1
  374. package/UI/Utils/UserEmailRegistrationStatus.ts +33 -5
  375. package/UI/Utils/WebAuthn.ts +220 -0
  376. package/UI/esbuild-config.js +4 -0
  377. package/Utils/API.ts +34 -0
  378. package/Utils/Dashboard/Components/DashboardVMwareHostListComponent.ts +38 -0
  379. package/Utils/Dashboard/Components/DashboardVMwareResourceListShared.ts +70 -0
  380. package/Utils/Dashboard/Components/DashboardVMwareVirtualMachineListComponent.ts +76 -0
  381. package/Utils/Dashboard/Components/Index.ts +16 -0
  382. package/Utils/LabelRuleImportExport.ts +496 -0
  383. package/Utils/Monitor/MonitorTemplateSyncUtil.ts +164 -0
  384. package/Utils/NetworkDiscovery/DiscoveryScanStatus.ts +8 -0
  385. package/Utils/Telemetry/CloudInstanceIdentity.ts +94 -0
  386. package/Utils/Telemetry/EntityKey.ts +19 -0
  387. package/Utils/Telemetry/EntityRelationship.ts +19 -0
  388. package/build/dist/Models/DatabaseModels/Alert.js +54 -0
  389. package/build/dist/Models/DatabaseModels/Alert.js.map +1 -1
  390. package/build/dist/Models/DatabaseModels/CloudResource.js +44 -7
  391. package/build/dist/Models/DatabaseModels/CloudResource.js.map +1 -1
  392. package/build/dist/Models/DatabaseModels/CodeRepository.js +87 -0
  393. package/build/dist/Models/DatabaseModels/CodeRepository.js.map +1 -1
  394. package/build/dist/Models/DatabaseModels/GoogleSecOpsConnection.js +60 -7
  395. package/build/dist/Models/DatabaseModels/GoogleSecOpsConnection.js.map +1 -1
  396. package/build/dist/Models/DatabaseModels/GoogleSecOpsConnectionRun.js +287 -0
  397. package/build/dist/Models/DatabaseModels/GoogleSecOpsConnectionRun.js.map +1 -0
  398. package/build/dist/Models/DatabaseModels/Incident.js +54 -0
  399. package/build/dist/Models/DatabaseModels/Incident.js.map +1 -1
  400. package/build/dist/Models/DatabaseModels/Index.js +16 -0
  401. package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
  402. package/build/dist/Models/DatabaseModels/ScheduledMaintenance.js +54 -0
  403. package/build/dist/Models/DatabaseModels/ScheduledMaintenance.js.map +1 -1
  404. package/build/dist/Models/DatabaseModels/User.js +57 -4
  405. package/build/dist/Models/DatabaseModels/User.js.map +1 -1
  406. package/build/dist/Models/DatabaseModels/UserNotificationEmailRollupItem.js +47 -2
  407. package/build/dist/Models/DatabaseModels/UserNotificationEmailRollupItem.js.map +1 -1
  408. package/build/dist/Models/DatabaseModels/UserWebAuthn.js +18 -0
  409. package/build/dist/Models/DatabaseModels/UserWebAuthn.js.map +1 -1
  410. package/build/dist/Models/DatabaseModels/VMwareResource.js +1201 -0
  411. package/build/dist/Models/DatabaseModels/VMwareResource.js.map +1 -0
  412. package/build/dist/Models/DatabaseModels/VMwareVCenter.js +1149 -0
  413. package/build/dist/Models/DatabaseModels/VMwareVCenter.js.map +1 -0
  414. package/build/dist/Models/DatabaseModels/VMwareVCenterFeed.js +648 -0
  415. package/build/dist/Models/DatabaseModels/VMwareVCenterFeed.js.map +1 -0
  416. package/build/dist/Models/DatabaseModels/VMwareVCenterLabelRule.js +522 -0
  417. package/build/dist/Models/DatabaseModels/VMwareVCenterLabelRule.js.map +1 -0
  418. package/build/dist/Models/DatabaseModels/VMwareVCenterOwnerRule.js +603 -0
  419. package/build/dist/Models/DatabaseModels/VMwareVCenterOwnerRule.js.map +1 -0
  420. package/build/dist/Models/DatabaseModels/VMwareVCenterOwnerTeam.js +503 -0
  421. package/build/dist/Models/DatabaseModels/VMwareVCenterOwnerTeam.js.map +1 -0
  422. package/build/dist/Models/DatabaseModels/VMwareVCenterOwnerUser.js +502 -0
  423. package/build/dist/Models/DatabaseModels/VMwareVCenterOwnerUser.js.map +1 -0
  424. package/build/dist/Models/DatabaseModels/WorkflowVariable.js +22 -1
  425. package/build/dist/Models/DatabaseModels/WorkflowVariable.js.map +1 -1
  426. package/build/dist/Server/API/AIAgentDataAPI.js +63 -3
  427. package/build/dist/Server/API/AIAgentDataAPI.js.map +1 -1
  428. package/build/dist/Server/API/AIAgentGitHubAPI.js +363 -0
  429. package/build/dist/Server/API/AIAgentGitHubAPI.js.map +1 -0
  430. package/build/dist/Server/API/AIChatAPI.js +19 -1
  431. package/build/dist/Server/API/AIChatAPI.js.map +1 -1
  432. package/build/dist/Server/API/BillingAPI.js +22 -0
  433. package/build/dist/Server/API/BillingAPI.js.map +1 -1
  434. package/build/dist/Server/API/DashboardAPI.js +10 -0
  435. package/build/dist/Server/API/DashboardAPI.js.map +1 -1
  436. package/build/dist/Server/API/GitHubAPI.js +33 -5
  437. package/build/dist/Server/API/GitHubAPI.js.map +1 -1
  438. package/build/dist/Server/API/GoogleSecOpsConnectionAPI.js +56 -0
  439. package/build/dist/Server/API/GoogleSecOpsConnectionAPI.js.map +1 -0
  440. package/build/dist/Server/API/UserWebAuthnAPI.js +17 -1
  441. package/build/dist/Server/API/UserWebAuthnAPI.js.map +1 -1
  442. package/build/dist/Server/API/VMwareResourceAPI.js +106 -0
  443. package/build/dist/Server/API/VMwareResourceAPI.js.map +1 -0
  444. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1791800000000-SplitWebAuthnChallengeByPurpose.js +41 -0
  445. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1791800000000-SplitWebAuthnChallengeByPurpose.js.map +1 -0
  446. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1791900000000-AddSeverityAndStateToNotificationEmailRollup.js +14 -0
  447. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1791900000000-AddSeverityAndStateToNotificationEmailRollup.js.map +1 -0
  448. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1792000000000-AddVMwareTables.js +241 -0
  449. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1792000000000-AddVMwareTables.js.map +1 -0
  450. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1792100000000-AddGitHubCommandSettingsToCodeRepository.js +36 -0
  451. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1792100000000-AddGitHubCommandSettingsToCodeRepository.js.map +1 -0
  452. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1792200000000-AddUserWebAuthnPurpose.js +12 -0
  453. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1792200000000-AddUserWebAuthnPurpose.js.map +1 -0
  454. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1792300000000-AddGoogleSecOpsDiagnostics.js +34 -0
  455. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1792300000000-AddGoogleSecOpsDiagnostics.js.map +1 -0
  456. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +12 -0
  457. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  458. package/build/dist/Server/Middleware/IdentityRateLimit.js +80 -0
  459. package/build/dist/Server/Middleware/IdentityRateLimit.js.map +1 -1
  460. package/build/dist/Server/Services/AIRunService.js +14 -1
  461. package/build/dist/Server/Services/AIRunService.js.map +1 -1
  462. package/build/dist/Server/Services/BillingPaymentMethodService.js +71 -21
  463. package/build/dist/Server/Services/BillingPaymentMethodService.js.map +1 -1
  464. package/build/dist/Server/Services/BillingService.js +210 -22
  465. package/build/dist/Server/Services/BillingService.js.map +1 -1
  466. package/build/dist/Server/Services/CloudResourceInstanceService.js +66 -0
  467. package/build/dist/Server/Services/CloudResourceInstanceService.js.map +1 -1
  468. package/build/dist/Server/Services/ExceptionAggregationService.js +1 -0
  469. package/build/dist/Server/Services/ExceptionAggregationService.js.map +1 -1
  470. package/build/dist/Server/Services/GoogleSecOpsConnectionRunService.js +9 -0
  471. package/build/dist/Server/Services/GoogleSecOpsConnectionRunService.js.map +1 -0
  472. package/build/dist/Server/Services/GoogleSecOpsConnectionService.js +7 -0
  473. package/build/dist/Server/Services/GoogleSecOpsConnectionService.js.map +1 -1
  474. package/build/dist/Server/Services/Index.js +16 -0
  475. package/build/dist/Server/Services/Index.js.map +1 -1
  476. package/build/dist/Server/Services/LogAggregationService.js +1 -0
  477. package/build/dist/Server/Services/LogAggregationService.js.map +1 -1
  478. package/build/dist/Server/Services/MetricAggregationService.js +1 -0
  479. package/build/dist/Server/Services/MetricAggregationService.js.map +1 -1
  480. package/build/dist/Server/Services/MobilePasskeyLoginService.js +137 -0
  481. package/build/dist/Server/Services/MobilePasskeyLoginService.js.map +1 -0
  482. package/build/dist/Server/Services/MonitorService.js +34 -1
  483. package/build/dist/Server/Services/MonitorService.js.map +1 -1
  484. package/build/dist/Server/Services/MonitorTemplateService.js +64 -26
  485. package/build/dist/Server/Services/MonitorTemplateService.js.map +1 -1
  486. package/build/dist/Server/Services/NetworkDeviceAutoImportRuleEngineService.js +124 -1
  487. package/build/dist/Server/Services/NetworkDeviceAutoImportRuleEngineService.js.map +1 -1
  488. package/build/dist/Server/Services/NetworkDeviceAutoImportRuleService.js +142 -2
  489. package/build/dist/Server/Services/NetworkDeviceAutoImportRuleService.js.map +1 -1
  490. package/build/dist/Server/Services/OpenTelemetryIngestService.js +28 -13
  491. package/build/dist/Server/Services/OpenTelemetryIngestService.js.map +1 -1
  492. package/build/dist/Server/Services/PayAsYouGoBillingService.js +297 -0
  493. package/build/dist/Server/Services/PayAsYouGoBillingService.js.map +1 -0
  494. package/build/dist/Server/Services/ProjectService.js +38 -2
  495. package/build/dist/Server/Services/ProjectService.js.map +1 -1
  496. package/build/dist/Server/Services/ServerlessFunctionInstanceService.js +66 -0
  497. package/build/dist/Server/Services/ServerlessFunctionInstanceService.js.map +1 -1
  498. package/build/dist/Server/Services/TeamMemberService.js +85 -28
  499. package/build/dist/Server/Services/TeamMemberService.js.map +1 -1
  500. package/build/dist/Server/Services/TelemetryIngestionKeyService.js +61 -10
  501. package/build/dist/Server/Services/TelemetryIngestionKeyService.js.map +1 -1
  502. package/build/dist/Server/Services/TelemetryUsageBillingService.js +62 -5
  503. package/build/dist/Server/Services/TelemetryUsageBillingService.js.map +1 -1
  504. package/build/dist/Server/Services/TraceAggregationService.js +5 -4
  505. package/build/dist/Server/Services/TraceAggregationService.js.map +1 -1
  506. package/build/dist/Server/Services/UserWebAuthnService.js +345 -113
  507. package/build/dist/Server/Services/UserWebAuthnService.js.map +1 -1
  508. package/build/dist/Server/Services/VMwareResourceService.js +395 -0
  509. package/build/dist/Server/Services/VMwareResourceService.js.map +1 -0
  510. package/build/dist/Server/Services/VMwareVCenterFeedService.js +89 -0
  511. package/build/dist/Server/Services/VMwareVCenterFeedService.js.map +1 -0
  512. package/build/dist/Server/Services/VMwareVCenterLabelRuleEngineService.js +197 -0
  513. package/build/dist/Server/Services/VMwareVCenterLabelRuleEngineService.js.map +1 -0
  514. package/build/dist/Server/Services/VMwareVCenterLabelRuleService.js +13 -0
  515. package/build/dist/Server/Services/VMwareVCenterLabelRuleService.js.map +1 -0
  516. package/build/dist/Server/Services/VMwareVCenterOwnerRuleEngineService.js +214 -0
  517. package/build/dist/Server/Services/VMwareVCenterOwnerRuleEngineService.js.map +1 -0
  518. package/build/dist/Server/Services/VMwareVCenterOwnerRuleService.js +13 -0
  519. package/build/dist/Server/Services/VMwareVCenterOwnerRuleService.js.map +1 -0
  520. package/build/dist/Server/Services/VMwareVCenterOwnerTeamService.js +129 -0
  521. package/build/dist/Server/Services/VMwareVCenterOwnerTeamService.js.map +1 -0
  522. package/build/dist/Server/Services/VMwareVCenterOwnerUserService.js +122 -0
  523. package/build/dist/Server/Services/VMwareVCenterOwnerUserService.js.map +1 -0
  524. package/build/dist/Server/Services/VMwareVCenterService.js +533 -0
  525. package/build/dist/Server/Services/VMwareVCenterService.js.map +1 -0
  526. package/build/dist/Server/Services/WorkflowVariableService.js +169 -0
  527. package/build/dist/Server/Services/WorkflowVariableService.js.map +1 -1
  528. package/build/dist/Server/Types/Billing/MeteredPlan/ActiveMonitoringMeteredPlan.js +12 -1
  529. package/build/dist/Server/Types/Billing/MeteredPlan/ActiveMonitoringMeteredPlan.js.map +1 -1
  530. package/build/dist/Server/Types/Billing/MeteredPlan/TelemetryMeteredPlan.js +25 -2
  531. package/build/dist/Server/Types/Billing/MeteredPlan/TelemetryMeteredPlan.js.map +1 -1
  532. package/build/dist/Server/Utils/CodeRepository/GitHub/GitHub.js.map +1 -1
  533. package/build/dist/Server/Utils/CodeRepository/GitHub/GitHubAgentTaskTrigger.js +275 -0
  534. package/build/dist/Server/Utils/CodeRepository/GitHub/GitHubAgentTaskTrigger.js.map +1 -0
  535. package/build/dist/Server/Utils/CodeRepository/GitHub/GitHubCommandAuthorizer.js +226 -0
  536. package/build/dist/Server/Utils/CodeRepository/GitHub/GitHubCommandAuthorizer.js.map +1 -0
  537. package/build/dist/Server/Utils/CodeRepository/GitHub/GitHubCommandParser.js +297 -0
  538. package/build/dist/Server/Utils/CodeRepository/GitHub/GitHubCommandParser.js.map +1 -0
  539. package/build/dist/Server/Utils/CodeRepository/GitHub/GitHubConversation.js +582 -0
  540. package/build/dist/Server/Utils/CodeRepository/GitHub/GitHubConversation.js.map +1 -0
  541. package/build/dist/Server/Utils/CodeRepository/GitHub/GitHubReplyComposer.js +275 -0
  542. package/build/dist/Server/Utils/CodeRepository/GitHub/GitHubReplyComposer.js.map +1 -0
  543. package/build/dist/Server/Utils/CodeRepository/GitHub/GitHubRunReply.js +365 -0
  544. package/build/dist/Server/Utils/CodeRepository/GitHub/GitHubRunReply.js.map +1 -0
  545. package/build/dist/Server/Utils/CodeRepository/GitHub/GitHubWebhookEvents.js +103 -0
  546. package/build/dist/Server/Utils/CodeRepository/GitHub/GitHubWebhookEvents.js.map +1 -0
  547. package/build/dist/Server/Utils/CodeRepository/GitHub/GitHubWebhookHandler.js +661 -0
  548. package/build/dist/Server/Utils/CodeRepository/GitHub/GitHubWebhookHandler.js.map +1 -0
  549. package/build/dist/Server/Utils/Dashboard/PublicDashboardResourceListPolicy.js +113 -0
  550. package/build/dist/Server/Utils/Dashboard/PublicDashboardResourceListPolicy.js.map +1 -1
  551. package/build/dist/Server/Utils/DataSource/EgressGuard.js +99 -15
  552. package/build/dist/Server/Utils/DataSource/EgressGuard.js.map +1 -1
  553. package/build/dist/Server/Utils/EmailRollup/EmailRollupFlushRunner.js +2 -0
  554. package/build/dist/Server/Utils/EmailRollup/EmailRollupFlushRunner.js.map +1 -1
  555. package/build/dist/Server/Utils/EmailRollup/EmailRollupRenderer.js +18 -0
  556. package/build/dist/Server/Utils/EmailRollup/EmailRollupRenderer.js.map +1 -1
  557. package/build/dist/Server/Utils/EmailRollup/EmailRollupWriter.js +31 -2
  558. package/build/dist/Server/Utils/EmailRollup/EmailRollupWriter.js.map +1 -1
  559. package/build/dist/Server/Utils/LogRedaction.js +2 -1
  560. package/build/dist/Server/Utils/LogRedaction.js.map +1 -1
  561. package/build/dist/Server/Utils/Monitor/MonitorAlert.js +1 -1
  562. package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js +219 -4
  563. package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js.map +1 -1
  564. package/build/dist/Server/Utils/Monitor/MonitorMaintenanceSuppression.js +12 -4
  565. package/build/dist/Server/Utils/Monitor/MonitorMaintenanceSuppression.js.map +1 -1
  566. package/build/dist/Server/Utils/Monitor/MonitorResourceContext.js +5 -3
  567. package/build/dist/Server/Utils/Monitor/MonitorResourceContext.js.map +1 -1
  568. package/build/dist/Server/Utils/Monitor/MonitorStepResourceIdentity.js +22 -9
  569. package/build/dist/Server/Utils/Monitor/MonitorStepResourceIdentity.js.map +1 -1
  570. package/build/dist/Server/Utils/Monitor/MonitorTemplateUtil.js +1 -0
  571. package/build/dist/Server/Utils/Monitor/MonitorTemplateUtil.js.map +1 -1
  572. package/build/dist/Server/Utils/Monitor/SeriesResourceLabels.js +21 -0
  573. package/build/dist/Server/Utils/Monitor/SeriesResourceLabels.js.map +1 -1
  574. package/build/dist/Server/Utils/Monitor/SeriesResourceLinker.js +21 -6
  575. package/build/dist/Server/Utils/Monitor/SeriesResourceLinker.js.map +1 -1
  576. package/build/dist/Server/Utils/ResourceFeed/ResourceFeedUtil.js +3 -3
  577. package/build/dist/Server/Utils/SecurityEvent/ConnectorErrorMessage.js +9 -9
  578. package/build/dist/Server/Utils/SecurityEvent/ConnectorErrorMessage.js.map +1 -1
  579. package/build/dist/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsClient.js +92 -71
  580. package/build/dist/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsClient.js.map +1 -1
  581. package/build/dist/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsPoller.js +428 -143
  582. package/build/dist/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsPoller.js.map +1 -1
  583. package/build/dist/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsRunExecutor.js +376 -0
  584. package/build/dist/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsRunExecutor.js.map +1 -0
  585. package/build/dist/Server/Utils/Telemetry/EntityRegistry.js +5 -0
  586. package/build/dist/Server/Utils/Telemetry/EntityRegistry.js.map +1 -1
  587. package/build/dist/Server/Utils/Telemetry/ResourceHeartbeat.js.map +1 -1
  588. package/build/dist/Server/Utils/Telemetry/TelemetryEntity.js +136 -1
  589. package/build/dist/Server/Utils/Telemetry/TelemetryEntity.js.map +1 -1
  590. package/build/dist/Server/Utils/Telemetry/VMwareSnapshotScan.js +933 -0
  591. package/build/dist/Server/Utils/Telemetry/VMwareSnapshotScan.js.map +1 -0
  592. package/build/dist/Types/AI/CodeFixTaskContext.js +40 -0
  593. package/build/dist/Types/AI/CodeFixTaskContext.js.map +1 -1
  594. package/build/dist/Types/AI/CodeFixTaskType.js +57 -0
  595. package/build/dist/Types/AI/CodeFixTaskType.js.map +1 -1
  596. package/build/dist/Types/Accounts/AccountsLanguage.js +1 -0
  597. package/build/dist/Types/Accounts/AccountsLanguage.js.map +1 -1
  598. package/build/dist/Types/AdminDashboard/AdminDashboardLanguage.js +1 -0
  599. package/build/dist/Types/AdminDashboard/AdminDashboardLanguage.js.map +1 -1
  600. package/build/dist/Types/Cloud/CloudPlatform.js +277 -0
  601. package/build/dist/Types/Cloud/CloudPlatform.js.map +1 -0
  602. package/build/dist/Types/CodeRepository/GitHubCommand.js +52 -0
  603. package/build/dist/Types/CodeRepository/GitHubCommand.js.map +1 -0
  604. package/build/dist/Types/Dashboard/DashboardComponentType.js +2 -0
  605. package/build/dist/Types/Dashboard/DashboardComponentType.js.map +1 -1
  606. package/build/dist/Types/Dashboard/DashboardComponents/ComponentArgument.js +1 -0
  607. package/build/dist/Types/Dashboard/DashboardComponents/ComponentArgument.js.map +1 -1
  608. package/build/dist/Types/Dashboard/DashboardComponents/DashboardVMwareHostListComponent.js +2 -0
  609. package/build/dist/Types/Dashboard/DashboardComponents/DashboardVMwareHostListComponent.js.map +1 -0
  610. package/build/dist/Types/Dashboard/DashboardComponents/DashboardVMwareVirtualMachineListComponent.js +2 -0
  611. package/build/dist/Types/Dashboard/DashboardComponents/DashboardVMwareVirtualMachineListComponent.js.map +1 -0
  612. package/build/dist/Types/Dashboard/DashboardLanguage.js +1 -0
  613. package/build/dist/Types/Dashboard/DashboardLanguage.js.map +1 -1
  614. package/build/dist/Types/Dashboard/DashboardTemplates.js +286 -0
  615. package/build/dist/Types/Dashboard/DashboardTemplates.js.map +1 -1
  616. package/build/dist/Types/Docs/DocsLanguage.js +1 -0
  617. package/build/dist/Types/Docs/DocsLanguage.js.map +1 -1
  618. package/build/dist/Types/Exception/EgressGuardException.js +59 -0
  619. package/build/dist/Types/Exception/EgressGuardException.js.map +1 -0
  620. package/build/dist/Types/Icon/IconProp.js +1 -0
  621. package/build/dist/Types/Icon/IconProp.js.map +1 -1
  622. package/build/dist/Types/Monitor/MonitorCriteriaInstance.js +1 -0
  623. package/build/dist/Types/Monitor/MonitorCriteriaInstance.js.map +1 -1
  624. package/build/dist/Types/Monitor/MonitorStep.js +61 -18
  625. package/build/dist/Types/Monitor/MonitorStep.js.map +1 -1
  626. package/build/dist/Types/Monitor/MonitorStepMetricViewConfigUtil.js +1 -0
  627. package/build/dist/Types/Monitor/MonitorStepMetricViewConfigUtil.js.map +1 -1
  628. package/build/dist/Types/Monitor/MonitorStepVMwareMonitor.js +71 -0
  629. package/build/dist/Types/Monitor/MonitorStepVMwareMonitor.js.map +1 -0
  630. package/build/dist/Types/Monitor/MonitorTemplateSyncField.js +211 -0
  631. package/build/dist/Types/Monitor/MonitorTemplateSyncField.js.map +1 -0
  632. package/build/dist/Types/Monitor/MonitorType.js +23 -0
  633. package/build/dist/Types/Monitor/MonitorType.js.map +1 -1
  634. package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationCatalog.js +28 -0
  635. package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationCatalog.js.map +1 -1
  636. package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationTypes.js +1 -0
  637. package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationTypes.js.map +1 -1
  638. package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationUtil.js +2 -0
  639. package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationUtil.js.map +1 -1
  640. package/build/dist/Types/Monitor/SeriesContext/SeriesDebugHints.js +120 -0
  641. package/build/dist/Types/Monitor/SeriesContext/SeriesDebugHints.js.map +1 -1
  642. package/build/dist/Types/Monitor/SeriesContext/SeriesLabelDisplay.js +60 -0
  643. package/build/dist/Types/Monitor/SeriesContext/SeriesLabelDisplay.js.map +1 -1
  644. package/build/dist/Types/Monitor/VMwareAlertTemplates.js +775 -0
  645. package/build/dist/Types/Monitor/VMwareAlertTemplates.js.map +1 -0
  646. package/build/dist/Types/Monitor/VMwareMetricCatalog.js +799 -0
  647. package/build/dist/Types/Monitor/VMwareMetricCatalog.js.map +1 -0
  648. package/build/dist/Types/OnCallDutyPolicy/ScheduleShiftUtil.js +25 -0
  649. package/build/dist/Types/OnCallDutyPolicy/ScheduleShiftUtil.js.map +1 -1
  650. package/build/dist/Types/OnCallDutyPolicy/UserOverrideUtil.js +5 -0
  651. package/build/dist/Types/OnCallDutyPolicy/UserOverrideUtil.js.map +1 -1
  652. package/build/dist/Types/Password.js +63 -5
  653. package/build/dist/Types/Password.js.map +1 -1
  654. package/build/dist/Types/Permission.js +234 -0
  655. package/build/dist/Types/Permission.js.map +1 -1
  656. package/build/dist/Types/Probe/RequestFailedDetails.js +7 -0
  657. package/build/dist/Types/Probe/RequestFailedDetails.js.map +1 -1
  658. package/build/dist/Types/SecurityEvent/GoogleSecOpsDiagnostics.js +2 -0
  659. package/build/dist/Types/SecurityEvent/GoogleSecOpsDiagnostics.js.map +1 -0
  660. package/build/dist/Types/StatusPage/StatusPageLanguage.js +1 -0
  661. package/build/dist/Types/StatusPage/StatusPageLanguage.js.map +1 -1
  662. package/build/dist/Types/Telemetry/EntityType.js +21 -0
  663. package/build/dist/Types/Telemetry/EntityType.js.map +1 -1
  664. package/build/dist/Types/Telemetry/ServiceType.js +1 -0
  665. package/build/dist/Types/Telemetry/ServiceType.js.map +1 -1
  666. package/build/dist/UI/Components/Breadcrumbs/Breadcrumbs.js +2 -2
  667. package/build/dist/UI/Components/Breadcrumbs/Breadcrumbs.js.map +1 -1
  668. package/build/dist/UI/Components/Calendar/Calendar.js +24 -4
  669. package/build/dist/UI/Components/Calendar/Calendar.js.map +1 -1
  670. package/build/dist/UI/Components/Forms/BasicForm.js +28 -3
  671. package/build/dist/UI/Components/Forms/BasicForm.js.map +1 -1
  672. package/build/dist/UI/Components/Forms/Fields/ColorPicker.js +1 -1
  673. package/build/dist/UI/Components/Forms/Fields/ColorPicker.js.map +1 -1
  674. package/build/dist/UI/Components/Forms/Fields/FormField.js +10 -3
  675. package/build/dist/UI/Components/Forms/Fields/FormField.js.map +1 -1
  676. package/build/dist/UI/Components/Forms/ModelForm.js +89 -6
  677. package/build/dist/UI/Components/Forms/ModelForm.js.map +1 -1
  678. package/build/dist/UI/Components/Graphs/DayUptimeGraph.js +5 -6
  679. package/build/dist/UI/Components/Graphs/DayUptimeGraph.js.map +1 -1
  680. package/build/dist/UI/Components/Icon/Icon.js +14 -0
  681. package/build/dist/UI/Components/Icon/Icon.js.map +1 -1
  682. package/build/dist/UI/Components/Input/Input.js +37 -8
  683. package/build/dist/UI/Components/Input/Input.js.map +1 -1
  684. package/build/dist/UI/Components/LabelRule/ImportLabelRulesModal.js +228 -0
  685. package/build/dist/UI/Components/LabelRule/ImportLabelRulesModal.js.map +1 -0
  686. package/build/dist/UI/Components/LabelRule/LabelRuleTable.js +102 -0
  687. package/build/dist/UI/Components/LabelRule/LabelRuleTable.js.map +1 -0
  688. package/build/dist/UI/Components/ModelTable/BaseModelTable.js +15 -2
  689. package/build/dist/UI/Components/ModelTable/BaseModelTable.js.map +1 -1
  690. package/build/dist/UI/Components/ModelTable/ModelTable.js +13 -5
  691. package/build/dist/UI/Components/ModelTable/ModelTable.js.map +1 -1
  692. package/build/dist/UI/Components/MonitorGraphs/Uptime.js +14 -15
  693. package/build/dist/UI/Components/MonitorGraphs/Uptime.js.map +1 -1
  694. package/build/dist/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.js +2 -0
  695. package/build/dist/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.js.map +1 -1
  696. package/build/dist/UI/Components/Tooltip/Tooltip.js +33 -4
  697. package/build/dist/UI/Components/Tooltip/Tooltip.js.map +1 -1
  698. package/build/dist/UI/Utils/DashboardStackingLayers.js +44 -0
  699. package/build/dist/UI/Utils/DashboardStackingLayers.js.map +1 -0
  700. package/build/dist/UI/Utils/LabelRuleImportExport.js +195 -0
  701. package/build/dist/UI/Utils/LabelRuleImportExport.js.map +1 -0
  702. package/build/dist/UI/Utils/ModelAPI/ModelAPI.js +4 -4
  703. package/build/dist/UI/Utils/ModelAPI/ModelAPI.js.map +1 -1
  704. package/build/dist/UI/Utils/TelemetryService.js +3 -2
  705. package/build/dist/UI/Utils/TelemetryService.js.map +1 -1
  706. package/build/dist/UI/Utils/UseDashboardGridDnd.js +2 -1
  707. package/build/dist/UI/Utils/UseDashboardGridDnd.js.map +1 -1
  708. package/build/dist/UI/Utils/UserEmailRegistrationStatus.js +21 -4
  709. package/build/dist/UI/Utils/UserEmailRegistrationStatus.js.map +1 -1
  710. package/build/dist/UI/Utils/WebAuthn.js +121 -0
  711. package/build/dist/UI/Utils/WebAuthn.js.map +1 -0
  712. package/build/dist/Utils/API.js +29 -0
  713. package/build/dist/Utils/API.js.map +1 -1
  714. package/build/dist/Utils/Dashboard/Components/DashboardVMwareHostListComponent.js +33 -0
  715. package/build/dist/Utils/Dashboard/Components/DashboardVMwareHostListComponent.js.map +1 -0
  716. package/build/dist/Utils/Dashboard/Components/DashboardVMwareResourceListShared.js +54 -0
  717. package/build/dist/Utils/Dashboard/Components/DashboardVMwareResourceListShared.js.map +1 -0
  718. package/build/dist/Utils/Dashboard/Components/DashboardVMwareVirtualMachineListComponent.js +60 -0
  719. package/build/dist/Utils/Dashboard/Components/DashboardVMwareVirtualMachineListComponent.js.map +1 -0
  720. package/build/dist/Utils/Dashboard/Components/Index.js +8 -0
  721. package/build/dist/Utils/Dashboard/Components/Index.js.map +1 -1
  722. package/build/dist/Utils/LabelRuleImportExport.js +356 -0
  723. package/build/dist/Utils/LabelRuleImportExport.js.map +1 -0
  724. package/build/dist/Utils/Monitor/MonitorTemplateSyncUtil.js +110 -0
  725. package/build/dist/Utils/Monitor/MonitorTemplateSyncUtil.js.map +1 -0
  726. package/build/dist/Utils/NetworkDiscovery/DiscoveryScanStatus.js +6 -0
  727. package/build/dist/Utils/NetworkDiscovery/DiscoveryScanStatus.js.map +1 -1
  728. package/build/dist/Utils/Telemetry/CloudInstanceIdentity.js +88 -0
  729. package/build/dist/Utils/Telemetry/CloudInstanceIdentity.js.map +1 -0
  730. package/build/dist/Utils/Telemetry/EntityKey.js +15 -0
  731. package/build/dist/Utils/Telemetry/EntityKey.js.map +1 -1
  732. package/build/dist/Utils/Telemetry/EntityRelationship.js +13 -0
  733. package/build/dist/Utils/Telemetry/EntityRelationship.js.map +1 -1
  734. package/package.json +1 -1
@@ -0,0 +1,1608 @@
1
+ import {
2
+ VMwareAlertTemplate,
3
+ VMwareAlertTemplateArgs,
4
+ VMwareGroupByKey,
5
+ getAllVMwareAlertTemplates,
6
+ getVMwareAlertTemplateById,
7
+ getVMwareAlertTemplatesByCategory,
8
+ } from "../../../Types/Monitor/VMwareAlertTemplates";
9
+ import {
10
+ VMwareMetricDefinition,
11
+ getVMwareMetricByMetricName,
12
+ } from "../../../Types/Monitor/VMwareMetricCatalog";
13
+ import { getRecoveryThreshold } from "../../../Types/Monitor/Recommendation/RecommendationCriteriaBuilder";
14
+ import {
15
+ getComplementFilterType,
16
+ hasRecoveryDeadBand,
17
+ } from "./Utils/RecommendationCriteriaAssertions";
18
+ import MonitorStep from "../../../Types/Monitor/MonitorStep";
19
+ import MonitorStepVMwareMonitor from "../../../Types/Monitor/MonitorStepVMwareMonitor";
20
+ import MonitorCriteriaInstance from "../../../Types/Monitor/MonitorCriteriaInstance";
21
+ import {
22
+ EvaluateOverTimeType,
23
+ FilterType,
24
+ } from "../../../Types/Monitor/CriteriaFilter";
25
+ import MetricsAggregationType from "../../../Types/Metrics/MetricsAggregationType";
26
+ import RollingTime from "../../../Types/RollingTime/RollingTime";
27
+ import ObjectID from "../../../Types/ObjectID";
28
+ import SeriesLabelDisplay from "../../../Types/Monitor/SeriesContext/SeriesLabelDisplay";
29
+
30
+ /*
31
+ * Lock in the VMware alert-template contracts (design spec §6). Two layers:
32
+ *
33
+ * 1. ENUMERATED invariants run over getAllVMwareAlertTemplates(), so a
34
+ * newly added template is automatically covered: it must build a
35
+ * valid MonitorStep, reference only catalog metrics, resolve every
36
+ * criteria alias, group by a `resource.vcenter.*` RESOURCE attribute
37
+ * (the OTel vcenter receiver's identity lives in resource attributes —
38
+ * the inverse of the Proxmox rule), and use disjoint fire/recover
39
+ * thresholds on the same alias.
40
+ *
41
+ * 2. A per-template expectation table pins the spec'd metric /
42
+ * aggregation / threshold / attribute-filter / group-by decisions.
43
+ * The table is exhaustive both ways — adding a template without a
44
+ * row here fails loudly, which is the point.
45
+ */
46
+
47
+ interface QueryExpectation {
48
+ metricName: string;
49
+ aggregation: MetricsAggregationType;
50
+ attributes: Record<string, string>;
51
+ legendUnit: string | undefined;
52
+ }
53
+
54
+ interface ThresholdExpectation {
55
+ alias: string;
56
+ filterType: FilterType;
57
+ value: number;
58
+ }
59
+
60
+ interface TemplateExpectation {
61
+ id: string;
62
+ category: string;
63
+ severity: string;
64
+ rollingTime: RollingTime;
65
+ queries: Array<QueryExpectation>;
66
+ groupBy: string;
67
+ fire: ThresholdExpectation;
68
+ recover: ThresholdExpectation;
69
+ }
70
+
71
+ const HOST: string = "resource.vcenter.host.name";
72
+ const VM: string = "resource.vcenter.vm.name";
73
+ const DATASTORE: string = "resource.vcenter.datastore.name";
74
+ const CLUSTER: string = "resource.vcenter.cluster.name";
75
+ const DATACENTER: string = "resource.vcenter.datacenter.name";
76
+ const RESOURCE_POOL: string = "resource.vcenter.resource_pool.inventory_path";
77
+
78
+ const EXPECTED_TEMPLATES: Array<TemplateExpectation> = [
79
+ {
80
+ id: "vmware-host-cpu-saturation",
81
+ category: "Host",
82
+ severity: "Warning",
83
+ rollingTime: RollingTime.Past5Minutes,
84
+ queries: [
85
+ {
86
+ metricName: "vcenter.host.cpu.utilization",
87
+ aggregation: MetricsAggregationType.Avg,
88
+ attributes: {},
89
+ legendUnit: "%",
90
+ },
91
+ ],
92
+ groupBy: HOST,
93
+ fire: {
94
+ alias: "host_cpu_utilization",
95
+ filterType: FilterType.GreaterThan,
96
+ value: 90,
97
+ },
98
+ recover: {
99
+ alias: "host_cpu_utilization",
100
+ filterType: FilterType.LessThanOrEqualTo,
101
+ value: 90,
102
+ },
103
+ },
104
+ {
105
+ id: "vmware-host-memory-saturation",
106
+ category: "Host",
107
+ severity: "Warning",
108
+ rollingTime: RollingTime.Past5Minutes,
109
+ queries: [
110
+ {
111
+ metricName: "vcenter.host.memory.utilization",
112
+ aggregation: MetricsAggregationType.Avg,
113
+ attributes: {},
114
+ legendUnit: "%",
115
+ },
116
+ ],
117
+ groupBy: HOST,
118
+ fire: {
119
+ alias: "host_memory_utilization",
120
+ filterType: FilterType.GreaterThan,
121
+ value: 90,
122
+ },
123
+ recover: {
124
+ alias: "host_memory_utilization",
125
+ filterType: FilterType.LessThanOrEqualTo,
126
+ value: 90,
127
+ },
128
+ },
129
+ {
130
+ /*
131
+ * Max, not Avg: the metric is itself the worst latency across the
132
+ * host's disks, and the threshold is in the receiver's native ms.
133
+ */
134
+ id: "vmware-host-disk-latency-high",
135
+ category: "Host",
136
+ severity: "Warning",
137
+ rollingTime: RollingTime.Past5Minutes,
138
+ queries: [
139
+ {
140
+ metricName: "vcenter.host.disk.latency.max",
141
+ aggregation: MetricsAggregationType.Max,
142
+ attributes: {},
143
+ legendUnit: "ms",
144
+ },
145
+ ],
146
+ groupBy: HOST,
147
+ fire: {
148
+ alias: "host_disk_latency_max",
149
+ filterType: FilterType.GreaterThan,
150
+ value: 50,
151
+ },
152
+ recover: {
153
+ alias: "host_disk_latency_max",
154
+ filterType: FilterType.LessThanOrEqualTo,
155
+ value: 50,
156
+ },
157
+ },
158
+ {
159
+ id: "vmware-host-network-packet-errors",
160
+ category: "Host",
161
+ severity: "Warning",
162
+ rollingTime: RollingTime.Past5Minutes,
163
+ queries: [
164
+ {
165
+ metricName: "vcenter.host.network.packet.error.rate",
166
+ aggregation: MetricsAggregationType.Max,
167
+ attributes: {},
168
+ legendUnit: undefined,
169
+ },
170
+ ],
171
+ groupBy: HOST,
172
+ fire: {
173
+ alias: "host_packet_error_rate",
174
+ filterType: FilterType.GreaterThan,
175
+ value: 0,
176
+ },
177
+ recover: {
178
+ alias: "host_packet_error_rate",
179
+ filterType: FilterType.EqualTo,
180
+ value: 0,
181
+ },
182
+ },
183
+ {
184
+ id: "vmware-host-network-packet-drops",
185
+ category: "Host",
186
+ severity: "Warning",
187
+ rollingTime: RollingTime.Past5Minutes,
188
+ queries: [
189
+ {
190
+ metricName: "vcenter.host.network.packet.drop.rate",
191
+ aggregation: MetricsAggregationType.Max,
192
+ attributes: {},
193
+ legendUnit: undefined,
194
+ },
195
+ ],
196
+ groupBy: HOST,
197
+ fire: {
198
+ alias: "host_packet_drop_rate",
199
+ filterType: FilterType.GreaterThan,
200
+ value: 0,
201
+ },
202
+ recover: {
203
+ alias: "host_packet_drop_rate",
204
+ filterType: FilterType.EqualTo,
205
+ value: 0,
206
+ },
207
+ },
208
+ {
209
+ /*
210
+ * The only 15-minute window: a VM is entitled to spend its vCPUs, so
211
+ * only sustained saturation is worth a page (see the asymmetry suite).
212
+ */
213
+ id: "vmware-vm-cpu-saturation",
214
+ category: "Virtual Machine",
215
+ severity: "Warning",
216
+ rollingTime: RollingTime.Past15Minutes,
217
+ queries: [
218
+ {
219
+ metricName: "vcenter.vm.cpu.utilization",
220
+ aggregation: MetricsAggregationType.Avg,
221
+ attributes: {},
222
+ legendUnit: "%",
223
+ },
224
+ ],
225
+ groupBy: VM,
226
+ fire: {
227
+ alias: "vm_cpu_utilization",
228
+ filterType: FilterType.GreaterThan,
229
+ value: 90,
230
+ },
231
+ recover: {
232
+ alias: "vm_cpu_utilization",
233
+ filterType: FilterType.LessThanOrEqualTo,
234
+ value: 90,
235
+ },
236
+ },
237
+ {
238
+ id: "vmware-vm-cpu-ready-contention",
239
+ category: "Virtual Machine",
240
+ severity: "Warning",
241
+ rollingTime: RollingTime.Past5Minutes,
242
+ queries: [
243
+ {
244
+ metricName: "vcenter.vm.cpu.readiness",
245
+ aggregation: MetricsAggregationType.Avg,
246
+ attributes: {},
247
+ legendUnit: "%",
248
+ },
249
+ ],
250
+ groupBy: VM,
251
+ fire: {
252
+ alias: "vm_cpu_ready",
253
+ filterType: FilterType.GreaterThan,
254
+ value: 10,
255
+ },
256
+ recover: {
257
+ alias: "vm_cpu_ready",
258
+ filterType: FilterType.LessThanOrEqualTo,
259
+ value: 10,
260
+ },
261
+ },
262
+ {
263
+ id: "vmware-vm-memory-saturation",
264
+ category: "Virtual Machine",
265
+ severity: "Warning",
266
+ rollingTime: RollingTime.Past5Minutes,
267
+ queries: [
268
+ {
269
+ metricName: "vcenter.vm.memory.utilization",
270
+ aggregation: MetricsAggregationType.Avg,
271
+ attributes: {},
272
+ legendUnit: "%",
273
+ },
274
+ ],
275
+ groupBy: VM,
276
+ fire: {
277
+ alias: "vm_memory_utilization",
278
+ filterType: FilterType.GreaterThan,
279
+ value: 90,
280
+ },
281
+ recover: {
282
+ alias: "vm_memory_utilization",
283
+ filterType: FilterType.LessThanOrEqualTo,
284
+ value: 90,
285
+ },
286
+ },
287
+ {
288
+ id: "vmware-vm-memory-ballooning",
289
+ category: "Virtual Machine",
290
+ severity: "Warning",
291
+ rollingTime: RollingTime.Past5Minutes,
292
+ queries: [
293
+ {
294
+ metricName: "vcenter.vm.memory.ballooned",
295
+ aggregation: MetricsAggregationType.Max,
296
+ attributes: {},
297
+ legendUnit: undefined,
298
+ },
299
+ ],
300
+ groupBy: VM,
301
+ fire: {
302
+ alias: "vm_memory_ballooned",
303
+ filterType: FilterType.GreaterThan,
304
+ value: 0,
305
+ },
306
+ recover: {
307
+ alias: "vm_memory_ballooned",
308
+ filterType: FilterType.EqualTo,
309
+ value: 0,
310
+ },
311
+ },
312
+ {
313
+ id: "vmware-vm-memory-swapping",
314
+ category: "Virtual Machine",
315
+ severity: "Critical",
316
+ rollingTime: RollingTime.Past5Minutes,
317
+ queries: [
318
+ {
319
+ metricName: "vcenter.vm.memory.swapped",
320
+ aggregation: MetricsAggregationType.Max,
321
+ attributes: {},
322
+ legendUnit: undefined,
323
+ },
324
+ ],
325
+ groupBy: VM,
326
+ fire: {
327
+ alias: "vm_memory_swapped",
328
+ filterType: FilterType.GreaterThan,
329
+ value: 0,
330
+ },
331
+ recover: {
332
+ alias: "vm_memory_swapped",
333
+ filterType: FilterType.EqualTo,
334
+ value: 0,
335
+ },
336
+ },
337
+ {
338
+ id: "vmware-vm-disk-latency-high",
339
+ category: "Virtual Machine",
340
+ severity: "Warning",
341
+ rollingTime: RollingTime.Past5Minutes,
342
+ queries: [
343
+ {
344
+ metricName: "vcenter.vm.disk.latency.max",
345
+ aggregation: MetricsAggregationType.Max,
346
+ attributes: {},
347
+ legendUnit: "ms",
348
+ },
349
+ ],
350
+ groupBy: VM,
351
+ fire: {
352
+ alias: "vm_disk_latency_max",
353
+ filterType: FilterType.GreaterThan,
354
+ value: 50,
355
+ },
356
+ recover: {
357
+ alias: "vm_disk_latency_max",
358
+ filterType: FilterType.LessThanOrEqualTo,
359
+ value: 50,
360
+ },
361
+ },
362
+ {
363
+ id: "vmware-vm-disk-usage-high",
364
+ category: "Virtual Machine",
365
+ severity: "Warning",
366
+ rollingTime: RollingTime.Past5Minutes,
367
+ queries: [
368
+ {
369
+ metricName: "vcenter.vm.disk.utilization",
370
+ aggregation: MetricsAggregationType.Avg,
371
+ attributes: {},
372
+ legendUnit: "%",
373
+ },
374
+ ],
375
+ groupBy: VM,
376
+ fire: {
377
+ alias: "vm_disk_utilization",
378
+ filterType: FilterType.GreaterThan,
379
+ value: 90,
380
+ },
381
+ recover: {
382
+ alias: "vm_disk_utilization",
383
+ filterType: FilterType.LessThanOrEqualTo,
384
+ value: 90,
385
+ },
386
+ },
387
+ {
388
+ id: "vmware-datastore-capacity-warning",
389
+ category: "Datastore",
390
+ severity: "Warning",
391
+ rollingTime: RollingTime.Past5Minutes,
392
+ queries: [
393
+ {
394
+ metricName: "vcenter.datastore.disk.utilization",
395
+ aggregation: MetricsAggregationType.Avg,
396
+ attributes: {},
397
+ legendUnit: "%",
398
+ },
399
+ ],
400
+ groupBy: DATASTORE,
401
+ fire: {
402
+ alias: "datastore_utilization",
403
+ filterType: FilterType.GreaterThan,
404
+ value: 80,
405
+ },
406
+ recover: {
407
+ alias: "datastore_utilization",
408
+ filterType: FilterType.LessThanOrEqualTo,
409
+ value: 80,
410
+ },
411
+ },
412
+ {
413
+ id: "vmware-datastore-capacity-critical",
414
+ category: "Datastore",
415
+ severity: "Critical",
416
+ rollingTime: RollingTime.Past5Minutes,
417
+ queries: [
418
+ {
419
+ metricName: "vcenter.datastore.disk.utilization",
420
+ aggregation: MetricsAggregationType.Avg,
421
+ attributes: {},
422
+ legendUnit: "%",
423
+ },
424
+ ],
425
+ groupBy: DATASTORE,
426
+ fire: {
427
+ alias: "datastore_utilization",
428
+ filterType: FilterType.GreaterThan,
429
+ value: 90,
430
+ },
431
+ recover: {
432
+ alias: "datastore_utilization",
433
+ filterType: FilterType.LessThanOrEqualTo,
434
+ value: 90,
435
+ },
436
+ },
437
+ {
438
+ /*
439
+ * The receiver's boolean `effective` attribute is stored as the
440
+ * STRING "false" — the filter must use the string, not a boolean.
441
+ */
442
+ id: "vmware-cluster-host-not-effective",
443
+ category: "Cluster",
444
+ severity: "Critical",
445
+ rollingTime: RollingTime.Past5Minutes,
446
+ queries: [
447
+ {
448
+ metricName: "vcenter.cluster.host.count",
449
+ aggregation: MetricsAggregationType.Max,
450
+ attributes: { effective: "false" },
451
+ legendUnit: undefined,
452
+ },
453
+ ],
454
+ groupBy: CLUSTER,
455
+ fire: {
456
+ alias: "cluster_hosts_not_effective",
457
+ filterType: FilterType.GreaterThan,
458
+ value: 0,
459
+ },
460
+ recover: {
461
+ alias: "cluster_hosts_not_effective",
462
+ filterType: FilterType.EqualTo,
463
+ value: 0,
464
+ },
465
+ },
466
+ {
467
+ id: "vmware-datacenter-hosts-unhealthy",
468
+ category: "Datacenter",
469
+ severity: "Critical",
470
+ rollingTime: RollingTime.Past5Minutes,
471
+ queries: [
472
+ {
473
+ metricName: "vcenter.datacenter.host.count",
474
+ aggregation: MetricsAggregationType.Max,
475
+ attributes: { status: "red" },
476
+ legendUnit: undefined,
477
+ },
478
+ ],
479
+ groupBy: DATACENTER,
480
+ fire: {
481
+ alias: "datacenter_hosts_red",
482
+ filterType: FilterType.GreaterThan,
483
+ value: 0,
484
+ },
485
+ recover: {
486
+ alias: "datacenter_hosts_red",
487
+ filterType: FilterType.EqualTo,
488
+ value: 0,
489
+ },
490
+ },
491
+ {
492
+ id: "vmware-datacenter-hosts-degraded",
493
+ category: "Datacenter",
494
+ severity: "Warning",
495
+ rollingTime: RollingTime.Past5Minutes,
496
+ queries: [
497
+ {
498
+ metricName: "vcenter.datacenter.host.count",
499
+ aggregation: MetricsAggregationType.Max,
500
+ attributes: { status: "yellow" },
501
+ legendUnit: undefined,
502
+ },
503
+ ],
504
+ groupBy: DATACENTER,
505
+ fire: {
506
+ alias: "datacenter_hosts_yellow",
507
+ filterType: FilterType.GreaterThan,
508
+ value: 0,
509
+ },
510
+ recover: {
511
+ alias: "datacenter_hosts_yellow",
512
+ filterType: FilterType.EqualTo,
513
+ value: 0,
514
+ },
515
+ },
516
+ {
517
+ id: "vmware-datacenter-hosts-powered-off",
518
+ category: "Datacenter",
519
+ severity: "Warning",
520
+ rollingTime: RollingTime.Past5Minutes,
521
+ queries: [
522
+ {
523
+ metricName: "vcenter.datacenter.host.count",
524
+ aggregation: MetricsAggregationType.Max,
525
+ attributes: { power_state: "off" },
526
+ legendUnit: undefined,
527
+ },
528
+ ],
529
+ groupBy: DATACENTER,
530
+ fire: {
531
+ alias: "datacenter_hosts_powered_off",
532
+ filterType: FilterType.GreaterThan,
533
+ value: 0,
534
+ },
535
+ recover: {
536
+ alias: "datacenter_hosts_powered_off",
537
+ filterType: FilterType.EqualTo,
538
+ value: 0,
539
+ },
540
+ },
541
+ {
542
+ id: "vmware-datacenter-vms-unhealthy",
543
+ category: "Datacenter",
544
+ severity: "Warning",
545
+ rollingTime: RollingTime.Past5Minutes,
546
+ queries: [
547
+ {
548
+ metricName: "vcenter.datacenter.vm.count",
549
+ aggregation: MetricsAggregationType.Max,
550
+ attributes: { status: "red" },
551
+ legendUnit: undefined,
552
+ },
553
+ ],
554
+ groupBy: DATACENTER,
555
+ fire: {
556
+ alias: "datacenter_vms_red",
557
+ filterType: FilterType.GreaterThan,
558
+ value: 0,
559
+ },
560
+ recover: {
561
+ alias: "datacenter_vms_red",
562
+ filterType: FilterType.EqualTo,
563
+ value: 0,
564
+ },
565
+ },
566
+ {
567
+ id: "vmware-datacenter-clusters-unhealthy",
568
+ category: "Datacenter",
569
+ severity: "Critical",
570
+ rollingTime: RollingTime.Past5Minutes,
571
+ queries: [
572
+ {
573
+ metricName: "vcenter.datacenter.cluster.count",
574
+ aggregation: MetricsAggregationType.Max,
575
+ attributes: { status: "red" },
576
+ legendUnit: undefined,
577
+ },
578
+ ],
579
+ groupBy: DATACENTER,
580
+ fire: {
581
+ alias: "datacenter_clusters_red",
582
+ filterType: FilterType.GreaterThan,
583
+ value: 0,
584
+ },
585
+ recover: {
586
+ alias: "datacenter_clusters_red",
587
+ filterType: FilterType.EqualTo,
588
+ value: 0,
589
+ },
590
+ },
591
+ {
592
+ /*
593
+ * vSAN latency is reported in MICROseconds by the receiver; the
594
+ * 20 ms threshold is written in the native unit (20 000 us) and pinned.
595
+ */
596
+ id: "vmware-vsan-latency-high",
597
+ category: "vSAN",
598
+ severity: "Warning",
599
+ rollingTime: RollingTime.Past5Minutes,
600
+ queries: [
601
+ {
602
+ metricName: "vcenter.cluster.vsan.latency.avg",
603
+ aggregation: MetricsAggregationType.Avg,
604
+ attributes: {},
605
+ legendUnit: "us",
606
+ },
607
+ ],
608
+ groupBy: CLUSTER,
609
+ fire: {
610
+ alias: "vsan_latency_avg",
611
+ filterType: FilterType.GreaterThan,
612
+ value: 20000,
613
+ },
614
+ recover: {
615
+ alias: "vsan_latency_avg",
616
+ filterType: FilterType.LessThanOrEqualTo,
617
+ value: 20000,
618
+ },
619
+ },
620
+ {
621
+ id: "vmware-vsan-congestion",
622
+ category: "vSAN",
623
+ severity: "Warning",
624
+ rollingTime: RollingTime.Past5Minutes,
625
+ queries: [
626
+ {
627
+ metricName: "vcenter.cluster.vsan.congestions",
628
+ aggregation: MetricsAggregationType.Max,
629
+ attributes: {},
630
+ legendUnit: undefined,
631
+ },
632
+ ],
633
+ groupBy: CLUSTER,
634
+ fire: {
635
+ alias: "vsan_congestions",
636
+ filterType: FilterType.GreaterThan,
637
+ value: 0,
638
+ },
639
+ recover: {
640
+ alias: "vsan_congestions",
641
+ filterType: FilterType.EqualTo,
642
+ value: 0,
643
+ },
644
+ },
645
+ {
646
+ /*
647
+ * Grouped by the pool's inventory PATH, not its name: pool names are
648
+ * only unique within their parent.
649
+ */
650
+ id: "vmware-resource-pool-memory-swapped",
651
+ category: "Cluster",
652
+ severity: "Warning",
653
+ rollingTime: RollingTime.Past5Minutes,
654
+ queries: [
655
+ {
656
+ metricName: "vcenter.resource_pool.memory.swapped",
657
+ aggregation: MetricsAggregationType.Max,
658
+ attributes: {},
659
+ legendUnit: undefined,
660
+ },
661
+ ],
662
+ groupBy: RESOURCE_POOL,
663
+ fire: {
664
+ alias: "resource_pool_memory_swapped",
665
+ filterType: FilterType.GreaterThan,
666
+ value: 0,
667
+ },
668
+ recover: {
669
+ alias: "resource_pool_memory_swapped",
670
+ filterType: FilterType.EqualTo,
671
+ value: 0,
672
+ },
673
+ },
674
+ ];
675
+
676
+ function buildArgs(): VMwareAlertTemplateArgs {
677
+ return {
678
+ vcenterIdentifier: "vcsa-prod",
679
+ onlineMonitorStatusId: ObjectID.generate(),
680
+ offlineMonitorStatusId: ObjectID.generate(),
681
+ defaultIncidentSeverityId: ObjectID.generate(),
682
+ defaultAlertSeverityId: ObjectID.generate(),
683
+ monitorName: "Test Monitor",
684
+ };
685
+ }
686
+
687
+ function getVMwareMonitor(step: MonitorStep): MonitorStepVMwareMonitor {
688
+ const vmwareMonitor: MonitorStepVMwareMonitor | undefined =
689
+ step.data?.vmwareMonitor;
690
+ if (!vmwareMonitor) {
691
+ throw new Error("vmwareMonitor missing from monitor step");
692
+ }
693
+ return vmwareMonitor;
694
+ }
695
+
696
+ function getCriteriaInstances(
697
+ step: MonitorStep,
698
+ ): Array<MonitorCriteriaInstance> {
699
+ const instances: Array<MonitorCriteriaInstance> | undefined =
700
+ step.data?.monitorCriteria.data?.monitorCriteriaInstanceArray;
701
+ if (!instances || instances.length === 0) {
702
+ throw new Error("monitorCriteria missing from monitor step");
703
+ }
704
+ return instances;
705
+ }
706
+
707
+ // Aliases a criteria filter may legally reference: query + formula variables.
708
+ function getReferencableAliases(
709
+ monitor: MonitorStepVMwareMonitor,
710
+ ): Set<string> {
711
+ const aliases: Set<string> = new Set<string>();
712
+ for (const queryConfig of monitor.metricViewConfig
713
+ .queryConfigs as Array<any>) {
714
+ aliases.add(queryConfig.metricAliasData.metricVariable);
715
+ }
716
+ for (const formulaConfig of (monitor.metricViewConfig.formulaConfigs ||
717
+ []) as Array<any>) {
718
+ aliases.add(formulaConfig.metricAliasData.metricVariable);
719
+ }
720
+ return aliases;
721
+ }
722
+
723
+ /*
724
+ * No VMware template thresholds a strictly 0/1 gauge (the vcenter
725
+ * receiver emits no up/down boolean — power state is inferred from metric
726
+ * presence at ingest), so every pair is checked with the shared dead-band
727
+ * assertion; the `> 0` / `= 0` count pairs are accepted by it as-is.
728
+ */
729
+ function expectedRecoveryValue(recover: {
730
+ filterType: FilterType;
731
+ value: number;
732
+ }): number {
733
+ return (
734
+ getRecoveryThreshold({
735
+ filterType: getComplementFilterType(recover.filterType)!,
736
+ value: recover.value,
737
+ }) ?? recover.value
738
+ );
739
+ }
740
+
741
+ const ALL_TEMPLATES: Array<VMwareAlertTemplate> = getAllVMwareAlertTemplates();
742
+
743
+ describe("VMwareAlertTemplates - registry", () => {
744
+ test("template ids are unique and match the expectation table exactly", () => {
745
+ const ids: Array<string> = ALL_TEMPLATES.map((t: VMwareAlertTemplate) => {
746
+ return t.id;
747
+ });
748
+ expect(new Set(ids).size).toBe(ids.length);
749
+ // Exhaustive both ways: a new template must get an expectation row.
750
+ expect([...ids].sort()).toEqual(
751
+ EXPECTED_TEMPLATES.map((t: TemplateExpectation) => {
752
+ return t.id;
753
+ }).sort(),
754
+ );
755
+ });
756
+
757
+ test("ships the 23 templates the design spec lists", () => {
758
+ expect(ALL_TEMPLATES).toHaveLength(23);
759
+ });
760
+
761
+ test("every template id carries the vmware- prefix", () => {
762
+ /*
763
+ * Template ids are only guaranteed unique within a module; the
764
+ * registry canary asserts they happen to be globally unique. A
765
+ * distinct prefix is what keeps that true against pve-/k8s-/ceph-.
766
+ */
767
+ for (const template of ALL_TEMPLATES) {
768
+ expect(template.id).toMatch(/^vmware-[a-z0-9-]+$/);
769
+ }
770
+ });
771
+
772
+ test("template names are unique within the module", () => {
773
+ const names: Array<string> = ALL_TEMPLATES.map((t: VMwareAlertTemplate) => {
774
+ return t.name;
775
+ });
776
+ expect(new Set(names).size).toBe(names.length);
777
+ });
778
+
779
+ test("getVMwareAlertTemplateById round-trips every template and misses unknown ids", () => {
780
+ for (const template of ALL_TEMPLATES) {
781
+ expect(getVMwareAlertTemplateById(template.id)).toBe(template);
782
+ }
783
+ expect(getVMwareAlertTemplateById("pve-node-offline")).toBeUndefined();
784
+ expect(getVMwareAlertTemplateById("")).toBeUndefined();
785
+ });
786
+
787
+ test("getVMwareAlertTemplatesByCategory partitions the registry", () => {
788
+ const categories: Array<string> = [
789
+ "Host",
790
+ "Virtual Machine",
791
+ "Datastore",
792
+ "Cluster",
793
+ "Datacenter",
794
+ "vSAN",
795
+ ];
796
+
797
+ let total: number = 0;
798
+ for (const category of categories) {
799
+ const templates: Array<VMwareAlertTemplate> =
800
+ getVMwareAlertTemplatesByCategory(category as any);
801
+ expect(templates.length).toBeGreaterThan(0);
802
+ for (const template of templates) {
803
+ expect(template.category).toBe(category);
804
+ }
805
+ total += templates.length;
806
+ }
807
+ expect(total).toBe(ALL_TEMPLATES.length);
808
+ });
809
+
810
+ test("severities are the two-member vocabulary the recommendation mapper understands", () => {
811
+ for (const template of ALL_TEMPLATES) {
812
+ expect(["Critical", "Warning"]).toContain(template.severity);
813
+ }
814
+ });
815
+ });
816
+
817
+ describe("VMwareAlertTemplates - enumerated invariants (every template)", () => {
818
+ test.each(
819
+ ALL_TEMPLATES.map((t: VMwareAlertTemplate) => {
820
+ return [t.id, t];
821
+ }),
822
+ )("%s builds a valid MonitorStep", (_id: unknown, template: unknown) => {
823
+ const args: VMwareAlertTemplateArgs = buildArgs();
824
+ const step: MonitorStep = (template as VMwareAlertTemplate).getMonitorStep(
825
+ args,
826
+ );
827
+ const monitor: MonitorStepVMwareMonitor = getVMwareMonitor(step);
828
+
829
+ // The vCenter identity is injected from the template args.
830
+ expect(monitor.vcenterIdentifier).toBe(args.vcenterIdentifier);
831
+ expect(monitor.resourceFilters).toEqual({});
832
+ expect(monitor.metricViewConfig.queryConfigs.length).toBeGreaterThan(0);
833
+
834
+ // Only the VMware sub-config is populated; no sibling leaks through.
835
+ expect(step.data?.proxmoxMonitor).toBeUndefined();
836
+ expect(step.data?.kubernetesMonitor).toBeUndefined();
837
+ expect(step.data?.metricMonitor).toBeUndefined();
838
+
839
+ const instances: Array<MonitorCriteriaInstance> =
840
+ getCriteriaInstances(step);
841
+ expect(instances.length).toBeGreaterThanOrEqual(2);
842
+
843
+ /*
844
+ * Criteria are evaluated first-match-wins: every instance before
845
+ * the last is an unhealthy tier (creates incidents + alerts,
846
+ * flips to the offline status); the LAST is the recover instance
847
+ * (no incidents, flips to the online status).
848
+ */
849
+ const offlineInstances: Array<MonitorCriteriaInstance> = instances.slice(
850
+ 0,
851
+ -1,
852
+ );
853
+ const onlineInstance: MonitorCriteriaInstance =
854
+ instances[instances.length - 1]!;
855
+
856
+ for (const offline of offlineInstances) {
857
+ expect(offline.data?.monitorStatusId).toBe(args.offlineMonitorStatusId);
858
+ expect(offline.data?.createIncidents).toBe(true);
859
+ expect(offline.data?.createAlerts).toBe(true);
860
+ expect(offline.data?.incidents).toHaveLength(1);
861
+ expect(offline.data?.alerts).toHaveLength(1);
862
+ expect(offline.data?.incidents?.[0]?.autoResolveIncident).toBe(true);
863
+ expect(offline.data?.alerts?.[0]?.autoResolveAlert).toBe(true);
864
+ expect(offline.data?.incidents?.[0]?.incidentSeverityId).toBe(
865
+ args.defaultIncidentSeverityId,
866
+ );
867
+ expect(offline.data?.alerts?.[0]?.alertSeverityId).toBe(
868
+ args.defaultAlertSeverityId,
869
+ );
870
+ }
871
+
872
+ expect(onlineInstance.data?.monitorStatusId).toBe(
873
+ args.onlineMonitorStatusId,
874
+ );
875
+ expect(onlineInstance.data?.createIncidents).toBe(false);
876
+ expect(onlineInstance.data?.createAlerts).toBe(false);
877
+ expect(onlineInstance.data?.name).toBe("Healthy");
878
+ });
879
+
880
+ test.each(
881
+ ALL_TEMPLATES.map((t: VMwareAlertTemplate) => {
882
+ return [t.id, t];
883
+ }),
884
+ )(
885
+ "%s references only catalog metrics and resolvable aliases",
886
+ (_id: unknown, template: unknown) => {
887
+ const step: MonitorStep = (
888
+ template as VMwareAlertTemplate
889
+ ).getMonitorStep(buildArgs());
890
+ const monitor: MonitorStepVMwareMonitor = getVMwareMonitor(step);
891
+
892
+ for (const queryConfig of monitor.metricViewConfig
893
+ .queryConfigs as Array<any>) {
894
+ const metricName: string =
895
+ queryConfig.metricQueryData.filterData.metricName;
896
+ expect(getVMwareMetricByMetricName(metricName)).toBeDefined();
897
+ }
898
+
899
+ const aliases: Set<string> = getReferencableAliases(monitor);
900
+ for (const instance of getCriteriaInstances(step)) {
901
+ for (const filter of instance.data?.filters || []) {
902
+ expect(aliases).toContain(
903
+ (filter as any).metricMonitorOptions.metricAlias,
904
+ );
905
+ }
906
+ }
907
+ },
908
+ );
909
+
910
+ test.each(
911
+ ALL_TEMPLATES.map((t: VMwareAlertTemplate) => {
912
+ return [t.id, t];
913
+ }),
914
+ )(
915
+ "%s groups by a resource.vcenter.* attribute the display layer can name",
916
+ (_id: unknown, template: unknown) => {
917
+ const step: MonitorStep = (
918
+ template as VMwareAlertTemplate
919
+ ).getMonitorStep(buildArgs());
920
+ const monitor: MonitorStepVMwareMonitor = getVMwareMonitor(step);
921
+
922
+ for (const queryConfig of monitor.metricViewConfig
923
+ .queryConfigs as Array<any>) {
924
+ const groupBys: Array<string> =
925
+ queryConfig.metricQueryData.groupByAttributeKeys || [];
926
+
927
+ /*
928
+ * Every VMware template is per-object: one incident per host /
929
+ * VM / datastore / cluster / datacenter / pool. An ungrouped
930
+ * template would collapse the whole vCenter into one alert that
931
+ * cannot say which object broke.
932
+ */
933
+ expect(groupBys).toHaveLength(1);
934
+
935
+ for (const key of groupBys) {
936
+ /*
937
+ * The vcenter receiver's identity lives in OTel RESOURCE
938
+ * attributes, stored `resource.`-prefixed in ClickHouse. A bare
939
+ * `vcenter.host.name` would match nothing and collapse every
940
+ * host into one mislabeled series — the inverse of the Proxmox
941
+ * rule, where identity is an unprefixed datapoint label.
942
+ */
943
+ expect(key).toMatch(/^resource\.vcenter\./);
944
+ expect(Object.values(VMwareGroupByKey)).toContain(key);
945
+ expect(SeriesLabelDisplay.isKnownLabelKey(key)).toBe(true);
946
+ }
947
+ }
948
+ },
949
+ );
950
+
951
+ test.each(
952
+ ALL_TEMPLATES.map((t: VMwareAlertTemplate) => {
953
+ return [t.id, t];
954
+ }),
955
+ )(
956
+ "%s groups by the identity attribute of the object its metric describes",
957
+ (_id: unknown, template: unknown) => {
958
+ /*
959
+ * A host metric grouped by the VM name would fan out on an attribute
960
+ * the series does not carry. The catalog's defaultResourceScope says
961
+ * which object a metric belongs to; the group-by must agree.
962
+ */
963
+ const scopeToGroupBy: Record<string, string> = {
964
+ datacenter: VMwareGroupByKey.Datacenter,
965
+ cluster: VMwareGroupByKey.Cluster,
966
+ host: VMwareGroupByKey.Host,
967
+ vm: VMwareGroupByKey.VirtualMachine,
968
+ datastore: VMwareGroupByKey.Datastore,
969
+ resource_pool: VMwareGroupByKey.ResourcePool,
970
+ };
971
+
972
+ const step: MonitorStep = (
973
+ template as VMwareAlertTemplate
974
+ ).getMonitorStep(buildArgs());
975
+ const monitor: MonitorStepVMwareMonitor = getVMwareMonitor(step);
976
+
977
+ for (const queryConfig of monitor.metricViewConfig
978
+ .queryConfigs as Array<any>) {
979
+ const definition: VMwareMetricDefinition | undefined =
980
+ getVMwareMetricByMetricName(
981
+ queryConfig.metricQueryData.filterData.metricName,
982
+ );
983
+ expect(definition).toBeDefined();
984
+
985
+ expect(queryConfig.metricQueryData.groupByAttributeKeys).toEqual([
986
+ scopeToGroupBy[definition!.defaultResourceScope],
987
+ ]);
988
+ }
989
+ },
990
+ );
991
+
992
+ test.each(
993
+ ALL_TEMPLATES.map((t: VMwareAlertTemplate) => {
994
+ return [t.id, t];
995
+ }),
996
+ )(
997
+ "%s filters only on bare datapoint attributes, never resource.-prefixed ones",
998
+ (_id: unknown, template: unknown) => {
999
+ /*
1000
+ * `status`, `power_state` and `effective` are DATAPOINT attributes
1001
+ * and are stored bare. Prefixing one would make the filter match
1002
+ * nothing, and the template would never fire — silently.
1003
+ */
1004
+ const step: MonitorStep = (
1005
+ template as VMwareAlertTemplate
1006
+ ).getMonitorStep(buildArgs());
1007
+ const monitor: MonitorStepVMwareMonitor = getVMwareMonitor(step);
1008
+
1009
+ for (const queryConfig of monitor.metricViewConfig
1010
+ .queryConfigs as Array<any>) {
1011
+ const attributes: Record<string, string> =
1012
+ queryConfig.metricQueryData.filterData.attributes;
1013
+
1014
+ for (const key of Object.keys(attributes)) {
1015
+ expect(key.startsWith("resource.")).toBe(false);
1016
+ expect(["status", "power_state", "effective"]).toContain(key);
1017
+ expect(typeof attributes[key]).toBe("string");
1018
+ }
1019
+ }
1020
+ },
1021
+ );
1022
+
1023
+ test.each(
1024
+ ALL_TEMPLATES.map((t: VMwareAlertTemplate) => {
1025
+ return [t.id, t];
1026
+ }),
1027
+ )(
1028
+ "%s has disjoint fire/recover thresholds on the same alias",
1029
+ (_id: unknown, template: unknown) => {
1030
+ const step: MonitorStep = (
1031
+ template as VMwareAlertTemplate
1032
+ ).getMonitorStep(buildArgs());
1033
+ const instances: Array<MonitorCriteriaInstance> =
1034
+ getCriteriaInstances(step);
1035
+ const onlineFilters: Array<any> = (instances[instances.length - 1]!.data
1036
+ ?.filters || []) as Array<any>;
1037
+
1038
+ for (const offline of instances.slice(0, -1)) {
1039
+ for (const fireFilter of (offline.data?.filters || []) as Array<any>) {
1040
+ const recoverFilter: any = onlineFilters.find((f: any) => {
1041
+ return (
1042
+ f.metricMonitorOptions.metricAlias ===
1043
+ fireFilter.metricMonitorOptions.metricAlias
1044
+ );
1045
+ });
1046
+ expect(recoverFilter).toBeDefined();
1047
+ expect(
1048
+ hasRecoveryDeadBand(
1049
+ {
1050
+ filterType: fireFilter.filterType,
1051
+ value: fireFilter.value as number,
1052
+ },
1053
+ {
1054
+ filterType: recoverFilter.filterType,
1055
+ value: recoverFilter.value as number,
1056
+ },
1057
+ ),
1058
+ ).toBe(true);
1059
+ }
1060
+ }
1061
+ },
1062
+ );
1063
+
1064
+ test.each(
1065
+ ALL_TEMPLATES.map((t: VMwareAlertTemplate) => {
1066
+ return [t.id, t];
1067
+ }),
1068
+ )(
1069
+ "%s evaluates sustained over the whole window, not on a single sample",
1070
+ (_id: unknown, template: unknown) => {
1071
+ /*
1072
+ * The rolling window is only the alert's patience because the
1073
+ * quantifier is "every sample". With AnyValue a 15-minute and a
1074
+ * 1-minute window are identical for anything that spikes.
1075
+ */
1076
+ const step: MonitorStep = (
1077
+ template as VMwareAlertTemplate
1078
+ ).getMonitorStep(buildArgs());
1079
+
1080
+ for (const instance of getCriteriaInstances(step)) {
1081
+ for (const filter of (instance.data?.filters || []) as Array<any>) {
1082
+ expect(filter.metricMonitorOptions.metricAggregationType).toBe(
1083
+ EvaluateOverTimeType.AllValues,
1084
+ );
1085
+ }
1086
+ }
1087
+ },
1088
+ );
1089
+
1090
+ test.each(
1091
+ ALL_TEMPLATES.map((t: VMwareAlertTemplate) => {
1092
+ return [t.id, t];
1093
+ }),
1094
+ )(
1095
+ "%s pins the display unit whenever the threshold is written in a unit",
1096
+ (_id: unknown, template: unknown) => {
1097
+ /*
1098
+ * A percentage / latency threshold only means what it says if the
1099
+ * query's samples are in that unit. The vcenter receiver's native
1100
+ * unit matches, so the pin is a no-op today — it is there so the
1101
+ * threshold does not silently change meaning if a receiver build
1102
+ * ever ships a different unit string. Zero-thresholded counts and
1103
+ * rates need no unit.
1104
+ */
1105
+ const step: MonitorStep = (
1106
+ template as VMwareAlertTemplate
1107
+ ).getMonitorStep(buildArgs());
1108
+ const monitor: MonitorStepVMwareMonitor = getVMwareMonitor(step);
1109
+ const fireFilter: any = (
1110
+ getCriteriaInstances(step)[0]!.data?.filters as Array<any>
1111
+ )[0];
1112
+
1113
+ for (const queryConfig of monitor.metricViewConfig
1114
+ .queryConfigs as Array<any>) {
1115
+ const definition: VMwareMetricDefinition | undefined =
1116
+ getVMwareMetricByMetricName(
1117
+ queryConfig.metricQueryData.filterData.metricName,
1118
+ );
1119
+ const legendUnit: string | undefined =
1120
+ queryConfig.metricAliasData.legendUnit;
1121
+
1122
+ if (fireFilter.value === 0) {
1123
+ expect(legendUnit).toBeUndefined();
1124
+ } else {
1125
+ expect(legendUnit).toBeDefined();
1126
+ // ...and it is the receiver's own unit, so no conversion happens.
1127
+ expect(legendUnit).toBe(definition!.unit);
1128
+ }
1129
+ }
1130
+ },
1131
+ );
1132
+
1133
+ test.each(
1134
+ ALL_TEMPLATES.map((t: VMwareAlertTemplate) => {
1135
+ return [t.id, t];
1136
+ }),
1137
+ )(
1138
+ "%s names the vSphere object kind in its title and tells the reader where to look",
1139
+ (_id: unknown, template: unknown) => {
1140
+ const step: MonitorStep = (
1141
+ template as VMwareAlertTemplate
1142
+ ).getMonitorStep(buildArgs());
1143
+ const fireInstance: MonitorCriteriaInstance =
1144
+ getCriteriaInstances(step)[0]!;
1145
+ const incident: any = fireInstance.data?.incidents?.[0];
1146
+ const alert: any = fireInstance.data?.alerts?.[0];
1147
+
1148
+ expect(incident.title).toMatch(/^\[VMware\] /);
1149
+ expect(incident.title).toContain("Test Monitor");
1150
+ expect(alert.title).toBe(incident.title);
1151
+ expect(alert.description).toBe(incident.description);
1152
+
1153
+ // The description tells the engineer to read the affected resource.
1154
+ expect(incident.description).toMatch(/affected resource on this alert/i);
1155
+
1156
+ // Named criteria, not the builder's generic fallback.
1157
+ expect(fireInstance.data?.name).not.toMatch(/Unhealthy$/);
1158
+ expect(fireInstance.data?.description).toMatch(/^Triggers when /);
1159
+
1160
+ // Never leaks Proxmox vocabulary into a vSphere alert.
1161
+ for (const text of [
1162
+ (template as VMwareAlertTemplate).description,
1163
+ incident.title,
1164
+ incident.description,
1165
+ fireInstance.data?.name || "",
1166
+ fireInstance.data?.description || "",
1167
+ ]) {
1168
+ expect(text).not.toMatch(/proxmox|pve|lxc|qemu|guest agent/i);
1169
+ }
1170
+ },
1171
+ );
1172
+
1173
+ test("Critical templates announce themselves in the incident title", () => {
1174
+ for (const template of ALL_TEMPLATES) {
1175
+ const step: MonitorStep = template.getMonitorStep(buildArgs());
1176
+ const title: string =
1177
+ getCriteriaInstances(step)[0]!.data?.incidents?.[0]?.title || "";
1178
+
1179
+ if (template.severity === "Critical") {
1180
+ expect(title).toContain("CRITICAL:");
1181
+ } else {
1182
+ expect(title).not.toContain("CRITICAL:");
1183
+ }
1184
+ }
1185
+ });
1186
+ });
1187
+
1188
+ describe("VMwareAlertTemplates - spec table expectations", () => {
1189
+ test.each(
1190
+ EXPECTED_TEMPLATES.map((t: TemplateExpectation) => {
1191
+ return [t.id, t];
1192
+ }),
1193
+ )(
1194
+ "%s matches the spec'd metric/aggregation/threshold contract",
1195
+ (_id: unknown, expected: unknown) => {
1196
+ const tc: TemplateExpectation = expected as TemplateExpectation;
1197
+ const template: VMwareAlertTemplate | undefined =
1198
+ getVMwareAlertTemplateById(tc.id);
1199
+ expect(template).toBeDefined();
1200
+
1201
+ expect(template!.category).toBe(tc.category);
1202
+ expect(template!.severity).toBe(tc.severity);
1203
+
1204
+ const step: MonitorStep = template!.getMonitorStep(buildArgs());
1205
+ const monitor: MonitorStepVMwareMonitor = getVMwareMonitor(step);
1206
+
1207
+ expect(monitor.rollingTime).toBe(tc.rollingTime);
1208
+
1209
+ const queryConfigs: Array<any> = monitor.metricViewConfig
1210
+ .queryConfigs as Array<any>;
1211
+ expect(queryConfigs).toHaveLength(tc.queries.length);
1212
+
1213
+ for (let i: number = 0; i < tc.queries.length; i++) {
1214
+ const expectedQuery: QueryExpectation = tc.queries[i]!;
1215
+ const filterData: any = queryConfigs[i].metricQueryData.filterData;
1216
+ expect(filterData.metricName).toBe(expectedQuery.metricName);
1217
+ expect(filterData.aggegationType).toBe(expectedQuery.aggregation);
1218
+ expect(filterData.attributes).toEqual(expectedQuery.attributes);
1219
+ expect(queryConfigs[i].metricAliasData.legendUnit).toBe(
1220
+ expectedQuery.legendUnit,
1221
+ );
1222
+
1223
+ const groupBys: Array<string> =
1224
+ queryConfigs[i].metricQueryData.groupByAttributeKeys || [];
1225
+ expect(groupBys).toEqual([tc.groupBy]);
1226
+ }
1227
+
1228
+ // No ratio formulas: the receiver ships ready-made percentages.
1229
+ expect(monitor.metricViewConfig.formulaConfigs || []).toHaveLength(0);
1230
+
1231
+ const instances: Array<MonitorCriteriaInstance> =
1232
+ getCriteriaInstances(step);
1233
+ expect(instances).toHaveLength(2);
1234
+
1235
+ const fireFilter: any = (instances[0]!.data?.filters as Array<any>)[0];
1236
+ expect(fireFilter.metricMonitorOptions.metricAlias).toBe(tc.fire.alias);
1237
+ expect(fireFilter.filterType).toBe(tc.fire.filterType);
1238
+ expect(fireFilter.value).toBe(tc.fire.value);
1239
+
1240
+ const recoverFilter: any = (instances[1]!.data?.filters as Array<any>)[0];
1241
+ expect(recoverFilter.metricMonitorOptions.metricAlias).toBe(
1242
+ tc.recover.alias,
1243
+ );
1244
+ expect(recoverFilter.filterType).toBe(tc.recover.filterType);
1245
+ /*
1246
+ * The spec table states the FIRING threshold; the recovery threshold
1247
+ * is derived from it so the dead band lives in one place rather than
1248
+ * being restated in every spec table.
1249
+ */
1250
+ expect(recoverFilter.value).toBe(expectedRecoveryValue(tc.recover));
1251
+ },
1252
+ );
1253
+ });
1254
+
1255
+ /*
1256
+ * Regression suites below. Each pins a decision that is easy to "tidy up"
1257
+ * into a defect: reverting it must turn one of these red.
1258
+ */
1259
+
1260
+ function getTemplate(id: string): VMwareAlertTemplate {
1261
+ const template: VMwareAlertTemplate | undefined =
1262
+ getVMwareAlertTemplateById(id);
1263
+ if (!template) {
1264
+ throw new Error(`template ${id} is not registered`);
1265
+ }
1266
+ return template;
1267
+ }
1268
+
1269
+ function findFilterByAlias(
1270
+ instance: MonitorCriteriaInstance,
1271
+ alias: string,
1272
+ ): any {
1273
+ return ((instance.data?.filters || []) as Array<any>).find((filter: any) => {
1274
+ return filter.metricMonitorOptions.metricAlias === alias;
1275
+ });
1276
+ }
1277
+
1278
+ describe("VMwareAlertTemplates - VM vs host CPU asymmetry (regression)", () => {
1279
+ const ROLLING_MINUTES: Record<string, number> = {
1280
+ [RollingTime.Past5Minutes]: 5,
1281
+ [RollingTime.Past15Minutes]: 15,
1282
+ };
1283
+
1284
+ /*
1285
+ * `vcenter.vm.cpu.utilization` is usage as a fraction of the VM's OWN
1286
+ * vCPU allocation, which the VM is entitled to spend. A right-sized
1287
+ * 2-vCPU VM running a build sits at 100% by design, so the host's
1288
+ * 5-minute window pages for a workload doing exactly what it was
1289
+ * provisioned to do. The asymmetry IS the fix; assert the relationship,
1290
+ * not only the numbers.
1291
+ */
1292
+ test("the VM template waits longer than the host one", () => {
1293
+ const hostStep: MonitorStep = getTemplate(
1294
+ "vmware-host-cpu-saturation",
1295
+ ).getMonitorStep(buildArgs());
1296
+ const vmStep: MonitorStep = getTemplate(
1297
+ "vmware-vm-cpu-saturation",
1298
+ ).getMonitorStep(buildArgs());
1299
+
1300
+ const hostWindow: number =
1301
+ ROLLING_MINUTES[getVMwareMonitor(hostStep).rollingTime as string]!;
1302
+ const vmWindow: number =
1303
+ ROLLING_MINUTES[getVMwareMonitor(vmStep).rollingTime as string]!;
1304
+ expect(vmWindow).toBeGreaterThan(hostWindow);
1305
+ });
1306
+
1307
+ test("vmware-vm-cpu-saturation is 90% sustained across a 15-minute window", () => {
1308
+ const step: MonitorStep = getTemplate(
1309
+ "vmware-vm-cpu-saturation",
1310
+ ).getMonitorStep(buildArgs());
1311
+ const monitor: MonitorStepVMwareMonitor = getVMwareMonitor(step);
1312
+
1313
+ expect(monitor.rollingTime).toBe(RollingTime.Past15Minutes);
1314
+
1315
+ const fire: any = findFilterByAlias(
1316
+ getCriteriaInstances(step)[0]!,
1317
+ "vm_cpu_utilization",
1318
+ );
1319
+ expect(fire.filterType).toBe(FilterType.GreaterThan);
1320
+ expect(fire.value).toBe(90);
1321
+ expect(fire.metricMonitorOptions.metricAggregationType).toBe(
1322
+ EvaluateOverTimeType.AllValues,
1323
+ );
1324
+ });
1325
+
1326
+ test("vmware-vm-cpu-saturation recovers at 81, strictly inside its firing threshold", () => {
1327
+ const step: MonitorStep = getTemplate(
1328
+ "vmware-vm-cpu-saturation",
1329
+ ).getMonitorStep(buildArgs());
1330
+ const instances: Array<MonitorCriteriaInstance> =
1331
+ getCriteriaInstances(step);
1332
+ const recover: any = findFilterByAlias(
1333
+ instances[instances.length - 1]!,
1334
+ "vm_cpu_utilization",
1335
+ );
1336
+
1337
+ expect(recover.filterType).toBe(FilterType.LessThanOrEqualTo);
1338
+ // 90% minus the shared 10% dead band. A VM parked at 90 cannot toggle.
1339
+ expect(recover.value).toBeCloseTo(81, 10);
1340
+ expect(recover.value).toBeLessThan(90);
1341
+ });
1342
+
1343
+ test("every other template uses the 5-minute window", () => {
1344
+ for (const template of ALL_TEMPLATES) {
1345
+ if (template.id === "vmware-vm-cpu-saturation") {
1346
+ continue;
1347
+ }
1348
+ expect(
1349
+ getVMwareMonitor(template.getMonitorStep(buildArgs())).rollingTime,
1350
+ ).toBe(RollingTime.Past5Minutes);
1351
+ }
1352
+ });
1353
+ });
1354
+
1355
+ describe("VMwareAlertTemplates - datastore warning/critical tiering (regression)", () => {
1356
+ /*
1357
+ * Two templates on ONE metric with different thresholds and severities.
1358
+ * They must stay ordered (warning strictly below critical), their
1359
+ * recovery bands must not overlap the other tier's firing threshold, and
1360
+ * they must fingerprint differently or the recommendation diff would
1361
+ * treat creating one as covering both.
1362
+ */
1363
+ test("the warning tier fires below the critical tier and the bands do not cross", () => {
1364
+ const warningStep: MonitorStep = getTemplate(
1365
+ "vmware-datastore-capacity-warning",
1366
+ ).getMonitorStep(buildArgs());
1367
+ const criticalStep: MonitorStep = getTemplate(
1368
+ "vmware-datastore-capacity-critical",
1369
+ ).getMonitorStep(buildArgs());
1370
+
1371
+ const warningFire: any = findFilterByAlias(
1372
+ getCriteriaInstances(warningStep)[0]!,
1373
+ "datastore_utilization",
1374
+ );
1375
+ const criticalFire: any = findFilterByAlias(
1376
+ getCriteriaInstances(criticalStep)[0]!,
1377
+ "datastore_utilization",
1378
+ );
1379
+ const criticalRecover: any = findFilterByAlias(
1380
+ getCriteriaInstances(criticalStep)[1]!,
1381
+ "datastore_utilization",
1382
+ );
1383
+
1384
+ expect(warningFire.value).toBe(80);
1385
+ expect(criticalFire.value).toBe(90);
1386
+ expect(warningFire.value).toBeLessThan(criticalFire.value);
1387
+ // Critical recovers at 81 — still above the warning tier's 80.
1388
+ expect(criticalRecover.value).toBeCloseTo(81, 10);
1389
+ expect(criticalRecover.value).toBeGreaterThan(warningFire.value);
1390
+
1391
+ expect(getTemplate("vmware-datastore-capacity-warning").severity).toBe(
1392
+ "Warning",
1393
+ );
1394
+ expect(getTemplate("vmware-datastore-capacity-critical").severity).toBe(
1395
+ "Critical",
1396
+ );
1397
+ });
1398
+ });
1399
+
1400
+ describe("VMwareAlertTemplates - attribute-filtered count templates (regression)", () => {
1401
+ /*
1402
+ * The datacenter / cluster count metrics fan out over `status`,
1403
+ * `power_state` and `effective`. Without the equality filter the
1404
+ * template would count EVERY host (green ones included) and fire on
1405
+ * any datacenter with a host in it.
1406
+ */
1407
+ test.each([
1408
+ ["vmware-cluster-host-not-effective", { effective: "false" }],
1409
+ ["vmware-datacenter-hosts-unhealthy", { status: "red" }],
1410
+ ["vmware-datacenter-hosts-degraded", { status: "yellow" }],
1411
+ ["vmware-datacenter-hosts-powered-off", { power_state: "off" }],
1412
+ ["vmware-datacenter-vms-unhealthy", { status: "red" }],
1413
+ ["vmware-datacenter-clusters-unhealthy", { status: "red" }],
1414
+ ])(
1415
+ "%s narrows the count to the unhealthy attribute value",
1416
+ (id: string, attributes: Record<string, string>) => {
1417
+ const step: MonitorStep = getTemplate(id).getMonitorStep(buildArgs());
1418
+ const monitor: MonitorStepVMwareMonitor = getVMwareMonitor(step);
1419
+ const queryConfig: any = monitor.metricViewConfig.queryConfigs[0];
1420
+
1421
+ expect(queryConfig.metricQueryData.filterData.attributes).toEqual(
1422
+ attributes,
1423
+ );
1424
+ // Max — one collection reporting an unhealthy object trips it.
1425
+ expect(queryConfig.metricQueryData.filterData.aggegationType).toBe(
1426
+ MetricsAggregationType.Max,
1427
+ );
1428
+
1429
+ const fire: any = (
1430
+ getCriteriaInstances(step)[0]!.data?.filters as Array<any>
1431
+ )[0];
1432
+ expect(fire.filterType).toBe(FilterType.GreaterThan);
1433
+ expect(fire.value).toBe(0);
1434
+ },
1435
+ );
1436
+
1437
+ test('the effective filter is the string "false", never a boolean', () => {
1438
+ /*
1439
+ * The receiver declares `effective` as a bool, but attribute values
1440
+ * are stored as strings, so a boolean `false` here would compare a
1441
+ * string column against a boolean and match nothing.
1442
+ */
1443
+ const step: MonitorStep = getTemplate(
1444
+ "vmware-cluster-host-not-effective",
1445
+ ).getMonitorStep(buildArgs());
1446
+ const attributes: Record<string, unknown> = (
1447
+ getVMwareMonitor(step).metricViewConfig.queryConfigs[0] as any
1448
+ ).metricQueryData.filterData.attributes;
1449
+
1450
+ expect(attributes["effective"]).toBe("false");
1451
+ expect(typeof attributes["effective"]).toBe("string");
1452
+ });
1453
+
1454
+ test("every template that filters on a count metric names the datacenter or cluster, not the counted object", () => {
1455
+ /*
1456
+ * `vcenter.datacenter.host.count` is a property of the DATACENTER: the
1457
+ * series carries only `vcenter.datacenter.name`. Grouping it by host
1458
+ * would key on an attribute the series never has.
1459
+ */
1460
+ for (const template of ALL_TEMPLATES) {
1461
+ const monitor: MonitorStepVMwareMonitor = getVMwareMonitor(
1462
+ template.getMonitorStep(buildArgs()),
1463
+ );
1464
+ const queryConfig: any = monitor.metricViewConfig.queryConfigs[0];
1465
+ const metricName: string = queryConfig.metricQueryData.filterData
1466
+ .metricName as string;
1467
+
1468
+ if (metricName.startsWith("vcenter.datacenter.")) {
1469
+ expect(queryConfig.metricQueryData.groupByAttributeKeys).toEqual([
1470
+ VMwareGroupByKey.Datacenter,
1471
+ ]);
1472
+ }
1473
+ if (metricName.startsWith("vcenter.cluster.")) {
1474
+ expect(queryConfig.metricQueryData.groupByAttributeKeys).toEqual([
1475
+ VMwareGroupByKey.Cluster,
1476
+ ]);
1477
+ }
1478
+ }
1479
+ });
1480
+ });
1481
+
1482
+ describe("VMwareAlertTemplates - vSAN latency unit (regression)", () => {
1483
+ /*
1484
+ * Host and VM disk latency are milliseconds; vSAN latency is
1485
+ * MICROseconds. A copy-pasted "50" from the disk templates would be
1486
+ * 50 µs and page constantly. The threshold must be 20 000 in the native
1487
+ * unit, pinned as "us".
1488
+ */
1489
+ test("thresholds 20 000 µs with the unit pinned, not 20 or 50 ms", () => {
1490
+ const step: MonitorStep = getTemplate(
1491
+ "vmware-vsan-latency-high",
1492
+ ).getMonitorStep(buildArgs());
1493
+ const queryConfig: any =
1494
+ getVMwareMonitor(step).metricViewConfig.queryConfigs[0];
1495
+ const fire: any = (
1496
+ getCriteriaInstances(step)[0]!.data?.filters as Array<any>
1497
+ )[0];
1498
+
1499
+ expect(queryConfig.metricAliasData.legendUnit).toBe("us");
1500
+ expect(
1501
+ getVMwareMetricByMetricName("vcenter.cluster.vsan.latency.avg")?.unit,
1502
+ ).toBe("us");
1503
+ expect(fire.value).toBe(20000);
1504
+ expect(fire.value).not.toBe(20);
1505
+ expect(fire.value).not.toBe(50);
1506
+ });
1507
+
1508
+ test("disk latency templates threshold in milliseconds", () => {
1509
+ for (const id of [
1510
+ "vmware-host-disk-latency-high",
1511
+ "vmware-vm-disk-latency-high",
1512
+ ]) {
1513
+ const step: MonitorStep = getTemplate(id).getMonitorStep(buildArgs());
1514
+ const queryConfig: any =
1515
+ getVMwareMonitor(step).metricViewConfig.queryConfigs[0];
1516
+ const fire: any = (
1517
+ getCriteriaInstances(step)[0]!.data?.filters as Array<any>
1518
+ )[0];
1519
+
1520
+ expect(queryConfig.metricAliasData.legendUnit).toBe("ms");
1521
+ expect(fire.value).toBe(50);
1522
+ }
1523
+ });
1524
+ });
1525
+
1526
+ describe("VMwareAlertTemplates - memory pressure ladder (regression)", () => {
1527
+ /*
1528
+ * Ballooning precedes swapping in ESXi's reclamation order, so
1529
+ * swapping is the more severe signal. A later "harmonisation" that made
1530
+ * both Warning would lose the escalation.
1531
+ */
1532
+ test("swapping is Critical, ballooning is Warning", () => {
1533
+ expect(getTemplate("vmware-vm-memory-swapping").severity).toBe("Critical");
1534
+ expect(getTemplate("vmware-vm-memory-ballooning").severity).toBe("Warning");
1535
+ expect(getTemplate("vmware-resource-pool-memory-swapped").severity).toBe(
1536
+ "Warning",
1537
+ );
1538
+ });
1539
+
1540
+ test("zero-thresholded count pairs recover at exactly 0, with no dead band", () => {
1541
+ for (const id of [
1542
+ "vmware-vm-memory-ballooning",
1543
+ "vmware-vm-memory-swapping",
1544
+ "vmware-resource-pool-memory-swapped",
1545
+ "vmware-vsan-congestion",
1546
+ "vmware-host-network-packet-errors",
1547
+ "vmware-host-network-packet-drops",
1548
+ ]) {
1549
+ const step: MonitorStep = getTemplate(id).getMonitorStep(buildArgs());
1550
+ const instances: Array<MonitorCriteriaInstance> =
1551
+ getCriteriaInstances(step);
1552
+ const fire: any = (instances[0]!.data?.filters as Array<any>)[0];
1553
+ const recover: any = (instances[1]!.data?.filters as Array<any>)[0];
1554
+
1555
+ expect(fire.filterType).toBe(FilterType.GreaterThan);
1556
+ expect(fire.value).toBe(0);
1557
+ expect(recover.filterType).toBe(FilterType.EqualTo);
1558
+ expect(recover.value).toBe(0);
1559
+ }
1560
+ });
1561
+ });
1562
+
1563
+ describe("VMwareAlertTemplates - coverage fingerprints", () => {
1564
+ /*
1565
+ * The recommendation coverage diff resolves "already created" by
1566
+ * fingerprint (metric names + query attributes + criteria thresholds).
1567
+ * Two templates that fingerprint identically would make creating one
1568
+ * grey out the other. Every template must therefore differ from every
1569
+ * other in at least (metric, attribute filter, firing threshold) — and
1570
+ * the module as a whole must watch many metrics, so the coverage test's
1571
+ * "two templates with different fingerprints" precondition can never
1572
+ * degrade into threshold-only variants of one metric.
1573
+ */
1574
+ test("every template has a distinct (metric, attributes, threshold) signature", () => {
1575
+ const signatures: Array<string> = ALL_TEMPLATES.map(
1576
+ (template: VMwareAlertTemplate) => {
1577
+ const step: MonitorStep = template.getMonitorStep(buildArgs());
1578
+ const queryConfig: any =
1579
+ getVMwareMonitor(step).metricViewConfig.queryConfigs[0];
1580
+ const fire: any = (
1581
+ getCriteriaInstances(step)[0]!.data?.filters as Array<any>
1582
+ )[0];
1583
+
1584
+ return [
1585
+ queryConfig.metricQueryData.filterData.metricName,
1586
+ JSON.stringify(queryConfig.metricQueryData.filterData.attributes),
1587
+ fire.filterType,
1588
+ fire.value,
1589
+ ].join("|");
1590
+ },
1591
+ );
1592
+
1593
+ expect(new Set(signatures).size).toBe(signatures.length);
1594
+ });
1595
+
1596
+ test("the module watches well over a dozen distinct metrics", () => {
1597
+ const metricNames: Set<string> = new Set<string>(
1598
+ ALL_TEMPLATES.map((template: VMwareAlertTemplate) => {
1599
+ const queryConfig: any = getVMwareMonitor(
1600
+ template.getMonitorStep(buildArgs()),
1601
+ ).metricViewConfig.queryConfigs[0];
1602
+ return queryConfig.metricQueryData.filterData.metricName as string;
1603
+ }),
1604
+ );
1605
+
1606
+ expect(metricNames.size).toBeGreaterThanOrEqual(15);
1607
+ });
1608
+ });