@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,842 @@
1
+ import WorkflowVariableService from "../../../Server/Services/WorkflowVariableService";
2
+ import { OnUpdate } from "../../../Server/Types/Database/Hooks";
3
+ import UpdateBy from "../../../Server/Types/Database/UpdateBy";
4
+ import WorkflowVariable from "../../../Models/DatabaseModels/WorkflowVariable";
5
+ import BadDataException from "../../../Types/Exception/BadDataException";
6
+ import ObjectID from "../../../Types/ObjectID";
7
+ import { LIMIT_PER_PROJECT } from "../../../Types/Database/LimitMax";
8
+ import PositiveNumber from "../../../Types/PositiveNumber";
9
+ import { afterEach, describe, expect, jest, test } from "@jest/globals";
10
+
11
+ /*
12
+ * Workflow variables became editable from the dashboard, which made renaming a
13
+ * variable possible for the first time. Renaming is the one write that can put
14
+ * two rows with the same name in the same scope:
15
+ *
16
+ * - @UniqueColumnBy(["workflowId", "projectId"]) on `name` is enforced by
17
+ * DatabaseService.checkUniqueColumnBy, and _updateBy never calls it;
18
+ * - there is no unique index on WorkflowVariable to catch what it misses
19
+ * (the initial migration creates plain indexes on projectId and workflowId
20
+ * and nothing else).
21
+ *
22
+ * The damage is silent. RunWorkflow.getVariables builds
23
+ * `storageMap.local.variables[variable.name] = variable.content`, a plain
24
+ * dictionary, so a duplicate does not error - the second row overwrites the
25
+ * first and {{local.variables.X}} resolves to whichever row the query happened
26
+ * to return last. Nothing looks broken; the workflow just runs on the wrong
27
+ * value, possibly the wrong credential.
28
+ *
29
+ * These drive the hook directly. It is protected, and an ordinary prototype
30
+ * method at runtime, so it is reached through a structural cast - going through
31
+ * updateBy() instead would drag in the entire ORM to prove one comparison.
32
+ */
33
+
34
+ const PROJECT_ID: ObjectID = new ObjectID(
35
+ "aaaa1111-1111-4111-8111-111111111111",
36
+ );
37
+ const OTHER_PROJECT_ID: ObjectID = new ObjectID(
38
+ "bbbb1111-1111-4111-8111-111111111111",
39
+ );
40
+ const WORKFLOW_ID: ObjectID = new ObjectID(
41
+ "aaaa2222-2222-4222-8222-222222222222",
42
+ );
43
+ const VARIABLE_ID: ObjectID = new ObjectID(
44
+ "aaaa3333-3333-4333-8333-333333333333",
45
+ );
46
+ const USER_ID: ObjectID = new ObjectID("aaaa5555-5555-4555-8555-555555555555");
47
+ const OTHER_VARIABLE_ID: ObjectID = new ObjectID(
48
+ "aaaa4444-4444-4444-8444-444444444444",
49
+ );
50
+
51
+ interface ServiceInternals {
52
+ onBeforeUpdate: (
53
+ updateBy: UpdateBy<WorkflowVariable>,
54
+ ) => Promise<OnUpdate<WorkflowVariable>>;
55
+ }
56
+
57
+ function hook(): ServiceInternals["onBeforeUpdate"] {
58
+ const internals: ServiceInternals =
59
+ WorkflowVariableService as unknown as ServiceInternals;
60
+
61
+ return internals.onBeforeUpdate.bind(WorkflowVariableService);
62
+ }
63
+
64
+ type MakeVariableOptions = {
65
+ id?: ObjectID | undefined;
66
+ name: string;
67
+ workflowId?: ObjectID | undefined;
68
+ projectId?: ObjectID | undefined;
69
+ isSecret?: boolean | string | undefined;
70
+ };
71
+
72
+ function makeVariable(options: MakeVariableOptions): WorkflowVariable {
73
+ const variable: WorkflowVariable = new WorkflowVariable();
74
+
75
+ variable._id = (options.id || VARIABLE_ID).toString();
76
+ variable.name = options.name;
77
+ variable.projectId = options.projectId || PROJECT_ID;
78
+
79
+ if (options.workflowId) {
80
+ variable.workflowId = options.workflowId;
81
+ }
82
+
83
+ if (options.isSecret !== undefined) {
84
+ (variable as unknown as { isSecret?: unknown }).isSecret = options.isSecret;
85
+ }
86
+
87
+ return variable;
88
+ }
89
+
90
+ /*
91
+ * Built structurally and cast through unknown. UpdateBy's `data` is a
92
+ * PartialEntity, whose conditional mapped type over a model with relation
93
+ * columns is deep enough that naming it here trips TS2589.
94
+ */
95
+ function makeUpdateBy(
96
+ data: Partial<WorkflowVariable>,
97
+ props?: Record<string, unknown> | undefined,
98
+ ): UpdateBy<WorkflowVariable> {
99
+ return {
100
+ query: { _id: VARIABLE_ID.toString() },
101
+ data: data,
102
+ limit: 1,
103
+ skip: 0,
104
+ props: props || { isRoot: true },
105
+ } as unknown as UpdateBy<WorkflowVariable>;
106
+ }
107
+
108
+ /*
109
+ * Stub the two reads the hook makes. findBy answers "which rows does this
110
+ * update touch"; countBy answers "does the new name already exist in that row's
111
+ * scope". Both calls are recorded WHOLE - query, select and props - because
112
+ * every assertion worth making here is about what was asked for rather than
113
+ * about what a stub chose to answer.
114
+ */
115
+ type RecordedCall = {
116
+ query: Record<string, unknown>;
117
+ select?: Record<string, unknown> | undefined;
118
+ props?: Record<string, unknown> | undefined;
119
+ limit?: unknown;
120
+ };
121
+
122
+ function stubReads(options: {
123
+ itemsBeingUpdated: Array<WorkflowVariable>;
124
+ conflictCount: number;
125
+ }): { countByCalls: Array<RecordedCall>; findByCalls: Array<RecordedCall> } {
126
+ const countByCalls: Array<RecordedCall> = [];
127
+ const findByCalls: Array<RecordedCall> = [];
128
+
129
+ function record(call: unknown): RecordedCall {
130
+ const typed: RecordedCall = call as RecordedCall;
131
+
132
+ return {
133
+ query: typed.query,
134
+ select: typed.select,
135
+ props: typed.props,
136
+ limit: typed.limit,
137
+ };
138
+ }
139
+
140
+ jest
141
+ .spyOn(WorkflowVariableService, "findBy")
142
+ .mockImplementation(
143
+ async (findBy: unknown): Promise<Array<WorkflowVariable>> => {
144
+ findByCalls.push(record(findBy));
145
+ return options.itemsBeingUpdated;
146
+ },
147
+ );
148
+
149
+ jest
150
+ .spyOn(WorkflowVariableService, "countBy")
151
+ .mockImplementation(async (countBy: unknown): Promise<PositiveNumber> => {
152
+ countByCalls.push(record(countBy));
153
+ return new PositiveNumber(options.conflictCount);
154
+ });
155
+
156
+ return { countByCalls, findByCalls };
157
+ }
158
+
159
+ /*
160
+ * QueryHelper builds TypeORM Raw() operators, so a query value is a
161
+ * FindOperator carrying the SQL fragment it will emit and the parameter bound
162
+ * into it. Asserting "it is defined" would accept the exact inversion of every
163
+ * one of these predicates, so the tests below read the operator instead.
164
+ */
165
+ type RawOperator = {
166
+ type?: string | undefined;
167
+ getSql?: ((alias: string) => string) | undefined;
168
+ objectLiteralParameters?: Record<string, unknown> | undefined;
169
+ };
170
+
171
+ function sqlOf(value: unknown, alias: string): string {
172
+ const operator: RawOperator = value as RawOperator;
173
+
174
+ if (!operator || typeof operator.getSql !== "function") {
175
+ throw new Error(
176
+ `Expected a Raw() operator for "${alias}", got ${JSON.stringify(value)}`,
177
+ );
178
+ }
179
+
180
+ return operator.getSql(alias).replace(/\s+/g, " ");
181
+ }
182
+
183
+ function paramsOf(value: unknown): Array<unknown> {
184
+ const operator: RawOperator = value as RawOperator;
185
+
186
+ return Object.values(operator?.objectLiteralParameters || {});
187
+ }
188
+
189
+ describe("WorkflowVariableService rename uniqueness", () => {
190
+ afterEach(() => {
191
+ jest.restoreAllMocks();
192
+ });
193
+
194
+ describe("updates that are not renames", () => {
195
+ /*
196
+ * The overwhelmingly common update from the dashboard edit form carries no
197
+ * name at all, or carries only content through the "Update Content" modal.
198
+ * Neither should cost a round trip.
199
+ */
200
+ test("a content-only update reads nothing and is allowed through", async () => {
201
+ const { countByCalls } = stubReads({
202
+ itemsBeingUpdated: [],
203
+ conflictCount: 99,
204
+ });
205
+
206
+ const result: OnUpdate<WorkflowVariable> = await hook()(
207
+ makeUpdateBy({ content: "rotated-token" }),
208
+ );
209
+
210
+ expect(
211
+ (result.updateBy.data as unknown as Partial<WorkflowVariable>).content,
212
+ ).toBe("rotated-token");
213
+ expect(countByCalls).toHaveLength(0);
214
+ expect(WorkflowVariableService.findBy).not.toHaveBeenCalled();
215
+ });
216
+
217
+ test("a description-and-secret update is allowed through", async () => {
218
+ stubReads({ itemsBeingUpdated: [], conflictCount: 99 });
219
+
220
+ await expect(
221
+ hook()(
222
+ makeUpdateBy({
223
+ description: "Token for the nightly Airflow sync",
224
+ isSecret: "true",
225
+ } as Partial<WorkflowVariable>),
226
+ ),
227
+ ).resolves.toBeDefined();
228
+
229
+ expect(WorkflowVariableService.findBy).not.toHaveBeenCalled();
230
+ });
231
+ });
232
+
233
+ describe("renames", () => {
234
+ test("allows a rename when nothing else holds the new name", async () => {
235
+ stubReads({
236
+ itemsBeingUpdated: [
237
+ makeVariable({ name: "OldName", workflowId: WORKFLOW_ID }),
238
+ ],
239
+ conflictCount: 0,
240
+ });
241
+
242
+ const result: OnUpdate<WorkflowVariable> = await hook()(
243
+ makeUpdateBy({ name: "NewName" }),
244
+ );
245
+
246
+ expect(
247
+ (result.updateBy.data as unknown as Partial<WorkflowVariable>).name,
248
+ ).toBe("NewName");
249
+ });
250
+
251
+ test("refuses a rename onto a name that already exists on the same workflow", async () => {
252
+ stubReads({
253
+ itemsBeingUpdated: [
254
+ makeVariable({ name: "OldName", workflowId: WORKFLOW_ID }),
255
+ ],
256
+ conflictCount: 1,
257
+ });
258
+
259
+ await expect(hook()(makeUpdateBy({ name: "Taken" }))).rejects.toThrow(
260
+ BadDataException,
261
+ );
262
+
263
+ await expect(hook()(makeUpdateBy({ name: "Taken" }))).rejects.toThrow(
264
+ /already exists on this workflow/,
265
+ );
266
+ });
267
+
268
+ /*
269
+ * The two namespaces get different wording because they are reached from
270
+ * different pages. A global-variable collision that says "on this workflow"
271
+ * sends the reader looking at a workflow they never opened.
272
+ */
273
+ test("names the global namespace when the row is a global variable", async () => {
274
+ stubReads({
275
+ itemsBeingUpdated: [makeVariable({ name: "OldName" })],
276
+ conflictCount: 1,
277
+ });
278
+
279
+ await expect(hook()(makeUpdateBy({ name: "Taken" }))).rejects.toThrow(
280
+ /global variable named "Taken" already exists in this project/,
281
+ );
282
+ });
283
+ });
284
+
285
+ describe("which rows the guard inspects", () => {
286
+ /*
287
+ * The hook resolves the update's own query to real rows before it can judge
288
+ * anything, and every part of that read matters: the query decides which
289
+ * rows, isRoot lets it see rows the caller cannot read, the select supplies
290
+ * the scope the lookup is built from, and the limit is what lets the
291
+ * multi-row guard below see all of them. A stub that answers regardless of
292
+ * its arguments would hide all four.
293
+ */
294
+ test("reads exactly the rows this update targets, as root, with the scope columns", async () => {
295
+ const { findByCalls } = stubReads({
296
+ itemsBeingUpdated: [
297
+ makeVariable({ name: "OldName", workflowId: WORKFLOW_ID }),
298
+ ],
299
+ conflictCount: 0,
300
+ });
301
+
302
+ await hook()(makeUpdateBy({ name: "NewName" }));
303
+
304
+ expect(findByCalls).toHaveLength(1);
305
+
306
+ const call: RecordedCall = findByCalls[0]!;
307
+
308
+ expect(call.query).toEqual({ _id: VARIABLE_ID.toString() });
309
+ expect(call.props).toEqual({ isRoot: true });
310
+ expect(call.props).not.toHaveProperty("userId");
311
+ expect(call.select).toEqual(
312
+ expect.objectContaining({
313
+ _id: true,
314
+ name: true,
315
+ projectId: true,
316
+ workflowId: true,
317
+ }),
318
+ );
319
+ expect(call.limit).toBe(LIMIT_PER_PROJECT);
320
+ });
321
+ });
322
+
323
+ describe("the scope the conflict is looked up in", () => {
324
+ test("a workflow-local rename is checked against that workflow only", async () => {
325
+ const { countByCalls } = stubReads({
326
+ itemsBeingUpdated: [
327
+ makeVariable({ name: "OldName", workflowId: WORKFLOW_ID }),
328
+ ],
329
+ conflictCount: 0,
330
+ });
331
+
332
+ await hook()(makeUpdateBy({ name: "NewName" }));
333
+
334
+ expect(countByCalls).toHaveLength(1);
335
+
336
+ const call: RecordedCall = countByCalls[0]!;
337
+ const query: Record<string, unknown> = call.query;
338
+
339
+ expect(query["projectId"]).toBe(PROJECT_ID);
340
+ expect(query["workflowId"]).toBe(WORKFLOW_ID);
341
+
342
+ /*
343
+ * As root: the conflicting row can easily be one the caller cannot read -
344
+ * read access is permission- and label-gated - and a count that cannot
345
+ * see it reports zero and waves the duplicate through.
346
+ */
347
+ expect(call.props).toEqual({ isRoot: true });
348
+
349
+ /*
350
+ * The row must be excluded from its own lookup. Asserting the operator
351
+ * rather than its presence, because `equalTo` would also be "defined" -
352
+ * and would make the row collide with itself, refusing every rename.
353
+ */
354
+ expect(sqlOf(query["_id"], "_id")).toContain("!=");
355
+ expect(paramsOf(query["_id"])).toContain(VARIABLE_ID.toString());
356
+
357
+ /*
358
+ * Case-insensitive, on the NEW name. A lookup built from the old name
359
+ * asks "does anything else already have my current name", answers no, and
360
+ * lets the rename land on top of an existing variable.
361
+ */
362
+ expect(sqlOf(query["name"], "name")).toContain("LOWER");
363
+ expect(paramsOf(query["name"])).toContain("newname");
364
+ });
365
+
366
+ /*
367
+ * Global variables are the rows whose workflowId is null, and they share a
368
+ * namespace of their own. Passing `workflowId: undefined` would drop the
369
+ * clause altogether and compare a global variable against every
370
+ * workflow-local variable in the project - which would reject renames that
371
+ * are perfectly legal, and is exactly the shape of bug that makes people
372
+ * give up and go back to delete-and-recreate. IS NOT NULL would do the same
373
+ * thing, which is why the SQL is read rather than merely required to exist.
374
+ */
375
+ test("a global rename is checked against the project's global variables, not every workflow's", async () => {
376
+ const { countByCalls } = stubReads({
377
+ itemsBeingUpdated: [makeVariable({ name: "OldName" })],
378
+ conflictCount: 0,
379
+ });
380
+
381
+ await hook()(makeUpdateBy({ name: "NewName" }));
382
+
383
+ expect(countByCalls).toHaveLength(1);
384
+
385
+ const query: Record<string, unknown> = countByCalls[0]!.query;
386
+
387
+ expect(query["projectId"]).toBe(PROJECT_ID);
388
+
389
+ const workflowSql: string = sqlOf(query["workflowId"], "workflowId");
390
+
391
+ expect(workflowSql).toContain("IS NULL");
392
+ expect(workflowSql).not.toContain("IS NOT NULL");
393
+ });
394
+
395
+ /*
396
+ * The count must run as root whoever is calling. Asserting that against a
397
+ * root fixture proves nothing - `props: updateBy.props` is indistinguishable
398
+ * from `props: { isRoot: true }` when the caller already is root - so this
399
+ * one calls as an ordinary user and checks the lookup did NOT inherit those
400
+ * props. It matters because the conflicting row can be one the caller
401
+ * cannot read: read access is label-gated, and a count that cannot see the
402
+ * duplicate reports zero and waves it through.
403
+ */
404
+ test("counts as root even when the caller is not", async () => {
405
+ const { countByCalls } = stubReads({
406
+ itemsBeingUpdated: [
407
+ makeVariable({ name: "OldName", workflowId: WORKFLOW_ID }),
408
+ ],
409
+ conflictCount: 0,
410
+ });
411
+
412
+ await hook()(
413
+ makeUpdateBy(
414
+ { name: "NewName" },
415
+ { userId: USER_ID, tenantId: PROJECT_ID },
416
+ ),
417
+ );
418
+
419
+ expect(countByCalls).toHaveLength(1);
420
+ expect(countByCalls[0]!.props).toEqual({ isRoot: true });
421
+ expect(countByCalls[0]!.props).not.toHaveProperty("userId");
422
+ });
423
+
424
+ test("the row's own project scopes the lookup, not the caller's", async () => {
425
+ const { countByCalls } = stubReads({
426
+ itemsBeingUpdated: [
427
+ makeVariable({ name: "OldName", projectId: OTHER_PROJECT_ID }),
428
+ ],
429
+ conflictCount: 0,
430
+ });
431
+
432
+ await hook()(makeUpdateBy({ name: "NewName" }));
433
+
434
+ expect(countByCalls[0]!.query["projectId"]).toBe(OTHER_PROJECT_ID);
435
+ });
436
+
437
+ /*
438
+ * projectId is non-nullable on the table, so a row without one means the
439
+ * select or the row is wrong. Dropping the clause would count the name
440
+ * across every project on the instance and refuse legitimate renames, so
441
+ * the guard refuses rather than answering the wrong question.
442
+ */
443
+ test("refuses rather than issuing an unscoped lookup when the row has no project", async () => {
444
+ const orphan: WorkflowVariable = makeVariable({ name: "OldName" });
445
+ delete orphan.projectId;
446
+
447
+ const { countByCalls } = stubReads({
448
+ itemsBeingUpdated: [orphan],
449
+ conflictCount: 0,
450
+ });
451
+
452
+ await expect(hook()(makeUpdateBy({ name: "NewName" }))).rejects.toThrow(
453
+ BadDataException,
454
+ );
455
+
456
+ expect(countByCalls).toHaveLength(0);
457
+ });
458
+ });
459
+
460
+ describe("renames that are not really renames", () => {
461
+ /*
462
+ * Saving the edit form without touching the name resubmits the name it
463
+ * already has. That must not be reported as a collision with itself - and
464
+ * it does not even need the lookup.
465
+ */
466
+ test("re-submitting the same name costs nothing and is allowed", async () => {
467
+ const { countByCalls } = stubReads({
468
+ itemsBeingUpdated: [
469
+ makeVariable({ name: "SameName", workflowId: WORKFLOW_ID }),
470
+ ],
471
+ conflictCount: 1,
472
+ });
473
+
474
+ await expect(
475
+ hook()(makeUpdateBy({ name: "SameName" })),
476
+ ).resolves.toBeDefined();
477
+
478
+ expect(countByCalls).toHaveLength(0);
479
+
480
+ /*
481
+ * The zero above is only meaningful next to a one: a hook that had been
482
+ * deleted outright would also never call countBy. A genuine rename
483
+ * through the same stubs proves the short-circuit is a short-circuit
484
+ * rather than an absence.
485
+ */
486
+ await expect(
487
+ hook()(makeUpdateBy({ name: "GenuinelyDifferent" })),
488
+ ).rejects.toThrow(BadDataException);
489
+
490
+ expect(countByCalls).toHaveLength(1);
491
+ });
492
+
493
+ test("changing only the casing of the row's own name is allowed", async () => {
494
+ const { countByCalls } = stubReads({
495
+ itemsBeingUpdated: [
496
+ makeVariable({ name: "apitoken", workflowId: WORKFLOW_ID }),
497
+ ],
498
+ conflictCount: 1,
499
+ });
500
+
501
+ /*
502
+ * The uniqueness lookup is case-insensitive (QueryHelper.findWithSameText
503
+ * lowercases both sides), so "apitoken" -> "APIToken" is the same row
504
+ * changing how it is spelled, not a collision. Without the guard this
505
+ * would count itself and refuse.
506
+ */
507
+ await expect(
508
+ hook()(makeUpdateBy({ name: "APIToken" })),
509
+ ).resolves.toBeDefined();
510
+
511
+ expect(countByCalls).toHaveLength(0);
512
+ });
513
+
514
+ /*
515
+ * The other half of case-insensitivity, and the one that matters more: a
516
+ * DIFFERENT row already holding the name in another case is a real
517
+ * collision, because the lookup lowercases both sides. The short-circuit
518
+ * above must not swallow it.
519
+ */
520
+ test("still refuses a rename that collides with another row only by casing", async () => {
521
+ const { countByCalls } = stubReads({
522
+ itemsBeingUpdated: [
523
+ makeVariable({ name: "OldName", workflowId: WORKFLOW_ID }),
524
+ ],
525
+ conflictCount: 1,
526
+ });
527
+
528
+ await expect(hook()(makeUpdateBy({ name: "APIToken" }))).rejects.toThrow(
529
+ /already exists on this workflow/,
530
+ );
531
+
532
+ expect(paramsOf(countByCalls[0]!.query["name"])).toContain("apitoken");
533
+ });
534
+
535
+ /*
536
+ * A blank name is a write to the column, not the absence of one. Two rows
537
+ * blanked in the same workflow would both become "" and collide like any
538
+ * other duplicate, so the guard has to run rather than treat it as "no
539
+ * rename".
540
+ */
541
+ test("treats a blanked name as a rename rather than skipping the guard", async () => {
542
+ const { countByCalls } = stubReads({
543
+ itemsBeingUpdated: [
544
+ makeVariable({ name: "OldName", workflowId: WORKFLOW_ID }),
545
+ ],
546
+ conflictCount: 1,
547
+ });
548
+
549
+ await expect(hook()(makeUpdateBy({ name: "" }))).rejects.toThrow(
550
+ BadDataException,
551
+ );
552
+
553
+ expect(countByCalls).toHaveLength(1);
554
+ });
555
+
556
+ /*
557
+ * An update that does not carry the column at all IS exempt, and must stay
558
+ * so - that is every content-only and description-only save.
559
+ */
560
+ test("an update carrying no name at all still skips the guard", async () => {
561
+ const { findByCalls } = stubReads({
562
+ itemsBeingUpdated: [
563
+ makeVariable({ name: "OldName", workflowId: WORKFLOW_ID }),
564
+ ],
565
+ conflictCount: 1,
566
+ });
567
+
568
+ await expect(
569
+ hook()(makeUpdateBy({ description: "Just a note" })),
570
+ ).resolves.toBeDefined();
571
+
572
+ expect(findByCalls).toHaveLength(0);
573
+ });
574
+ });
575
+
576
+ /*
577
+ * _updateBy calls this hook BEFORE ModelPermission.checkUpdateQueryPermissions,
578
+ * which is the step that appends the project clause. A hook reading
579
+ * unscoped-as-root would therefore answer questions about another project's
580
+ * rows - and its refusal messages say whether a variable is global and
581
+ * whether a name is taken there - before any authorization had run. So the
582
+ * hook applies the tenant scope itself.
583
+ */
584
+ describe("tenant scoping, which the permission layer has not applied yet", () => {
585
+ test("narrows the lookup to the calling project", async () => {
586
+ const { findByCalls } = stubReads({
587
+ itemsBeingUpdated: [],
588
+ conflictCount: 0,
589
+ });
590
+
591
+ await hook()(
592
+ makeUpdateBy(
593
+ { name: "NewName" },
594
+ { userId: USER_ID, tenantId: PROJECT_ID },
595
+ ),
596
+ );
597
+
598
+ expect(findByCalls[0]!.query).toEqual({
599
+ _id: VARIABLE_ID.toString(),
600
+ projectId: PROJECT_ID,
601
+ });
602
+ });
603
+
604
+ /*
605
+ * The oracle this closes: a variable id belonging to a project the caller
606
+ * cannot see resolves to no rows, so the hook says nothing at all and the
607
+ * permission layer refuses the update on its own terms.
608
+ */
609
+ test("says nothing about a row outside the calling project", async () => {
610
+ const { countByCalls } = stubReads({
611
+ itemsBeingUpdated: [],
612
+ conflictCount: 1,
613
+ });
614
+
615
+ await expect(
616
+ hook()(
617
+ makeUpdateBy(
618
+ { name: "STRIPE_SECRET_KEY" },
619
+ { userId: USER_ID, tenantId: OTHER_PROJECT_ID },
620
+ ),
621
+ ),
622
+ ).resolves.toBeDefined();
623
+
624
+ expect(countByCalls).toHaveLength(0);
625
+ });
626
+
627
+ /*
628
+ * Internal callers run as root with no tenant. Scoping those to a tenant
629
+ * they do not have would silently stop the guard from working at all.
630
+ */
631
+ test("leaves a root call with no tenant unscoped", async () => {
632
+ const { findByCalls } = stubReads({
633
+ itemsBeingUpdated: [],
634
+ conflictCount: 0,
635
+ });
636
+
637
+ await hook()(makeUpdateBy({ name: "NewName" }));
638
+
639
+ expect(findByCalls[0]!.query).toEqual({ _id: VARIABLE_ID.toString() });
640
+ });
641
+ });
642
+
643
+ /*
644
+ * isSecret is a one-way flag, and the service is the only place that can say
645
+ * so - a ColumnAccessControl list cannot express "you may set this but not
646
+ * clear it".
647
+ *
648
+ * Clearing it is the direction that exposes something. `content` is
649
+ * unreadable through the API by anyone, and this flag is what keeps its value
650
+ * out of the run logs - so a caller who may write a variable but not read it
651
+ * could otherwise clear the flag, trigger a run, and read the value out of a
652
+ * log it had been redacted from.
653
+ */
654
+ describe("the secret flag is a ratchet", () => {
655
+ test("lets a variable be marked secret", async () => {
656
+ stubReads({
657
+ itemsBeingUpdated: [
658
+ makeVariable({ name: "Token", workflowId: WORKFLOW_ID }),
659
+ ],
660
+ conflictCount: 0,
661
+ });
662
+
663
+ await expect(
664
+ hook()(makeUpdateBy({ isSecret: "true" } as Partial<WorkflowVariable>)),
665
+ ).resolves.toBeDefined();
666
+ });
667
+
668
+ test("refuses to un-mark a variable that is secret", async () => {
669
+ stubReads({
670
+ itemsBeingUpdated: [
671
+ makeVariable({
672
+ name: "Token",
673
+ workflowId: WORKFLOW_ID,
674
+ isSecret: true,
675
+ }),
676
+ ],
677
+ conflictCount: 0,
678
+ });
679
+
680
+ await expect(
681
+ hook()(
682
+ makeUpdateBy({ isSecret: "false" } as Partial<WorkflowVariable>),
683
+ ),
684
+ ).rejects.toThrow(BadDataException);
685
+
686
+ await expect(
687
+ hook()(
688
+ makeUpdateBy({
689
+ isSecret: false,
690
+ } as unknown as Partial<WorkflowVariable>),
691
+ ),
692
+ ).rejects.toThrow(/cannot be un-marked/);
693
+ });
694
+
695
+ /*
696
+ * The flag comes back from Postgres as a real boolean and can arrive from a
697
+ * request body as the string "true". RunWorkflow reads it exactly this way
698
+ * (getSecretWorkflowVariableValues), and a guard that disagreed with the
699
+ * redaction it protects would be worse than no guard.
700
+ */
701
+ test("reads the string form of the flag the way the run logs do", async () => {
702
+ stubReads({
703
+ itemsBeingUpdated: [
704
+ makeVariable({
705
+ name: "Token",
706
+ workflowId: WORKFLOW_ID,
707
+ isSecret: "true",
708
+ }),
709
+ ],
710
+ conflictCount: 0,
711
+ });
712
+
713
+ await expect(
714
+ hook()(
715
+ makeUpdateBy({
716
+ isSecret: false,
717
+ } as unknown as Partial<WorkflowVariable>),
718
+ ),
719
+ ).rejects.toThrow(BadDataException);
720
+ });
721
+
722
+ test("leaves a variable that was never secret alone", async () => {
723
+ stubReads({
724
+ itemsBeingUpdated: [
725
+ makeVariable({
726
+ name: "Token",
727
+ workflowId: WORKFLOW_ID,
728
+ isSecret: false,
729
+ }),
730
+ ],
731
+ conflictCount: 0,
732
+ });
733
+
734
+ await expect(
735
+ hook()(
736
+ makeUpdateBy({ isSecret: "false" } as Partial<WorkflowVariable>),
737
+ ),
738
+ ).resolves.toBeDefined();
739
+ });
740
+
741
+ test("an update that does not mention the flag reads nothing", async () => {
742
+ const { findByCalls } = stubReads({
743
+ itemsBeingUpdated: [
744
+ makeVariable({
745
+ name: "Token",
746
+ workflowId: WORKFLOW_ID,
747
+ isSecret: true,
748
+ }),
749
+ ],
750
+ conflictCount: 0,
751
+ });
752
+
753
+ await expect(
754
+ hook()(makeUpdateBy({ content: "rotated-token" })),
755
+ ).resolves.toBeDefined();
756
+
757
+ expect(findByCalls).toHaveLength(0);
758
+ });
759
+ });
760
+
761
+ /*
762
+ * sanitizeUpdateData passes plain objects straight through, so `name` is
763
+ * whatever the request body said it was. Without the type check this reached
764
+ * newName.toLowerCase() and became a 500 with a stack trace rather than a 400
765
+ * naming the field.
766
+ */
767
+ describe("a name that is not text", () => {
768
+ test("is refused as bad data rather than crashing the request", async () => {
769
+ const { findByCalls } = stubReads({
770
+ itemsBeingUpdated: [
771
+ makeVariable({ name: "OldName", workflowId: WORKFLOW_ID }),
772
+ ],
773
+ conflictCount: 0,
774
+ });
775
+
776
+ await expect(
777
+ hook()(
778
+ makeUpdateBy({
779
+ name: { $ne: null },
780
+ } as unknown as Partial<WorkflowVariable>),
781
+ ),
782
+ ).rejects.toThrow(BadDataException);
783
+
784
+ await expect(
785
+ hook()(
786
+ makeUpdateBy({ name: 42 } as unknown as Partial<WorkflowVariable>),
787
+ ),
788
+ ).rejects.toThrow(/must be text/);
789
+
790
+ expect(findByCalls).toHaveLength(0);
791
+ });
792
+ });
793
+
794
+ describe("multi-row updates", () => {
795
+ /*
796
+ * The dashboard always sends a single _id, but the CRUD API accepts a
797
+ * broader query. Renaming two rows to one name is a collision the database
798
+ * lookup cannot see: neither row conflicts with anything that exists yet,
799
+ * they conflict with each other once both are written.
800
+ */
801
+ test("refuses to rename more than one variable to the same name at once", async () => {
802
+ const { countByCalls } = stubReads({
803
+ itemsBeingUpdated: [
804
+ makeVariable({
805
+ id: VARIABLE_ID,
806
+ name: "First",
807
+ workflowId: WORKFLOW_ID,
808
+ }),
809
+ makeVariable({
810
+ id: OTHER_VARIABLE_ID,
811
+ name: "Second",
812
+ workflowId: WORKFLOW_ID,
813
+ }),
814
+ ],
815
+ conflictCount: 0,
816
+ });
817
+
818
+ await expect(hook()(makeUpdateBy({ name: "Merged" }))).rejects.toThrow(
819
+ BadDataException,
820
+ );
821
+
822
+ await expect(hook()(makeUpdateBy({ name: "Merged" }))).rejects.toThrow(
823
+ /Cannot rename 2 workflow variables/,
824
+ );
825
+
826
+ expect(countByCalls).toHaveLength(0);
827
+ });
828
+
829
+ /*
830
+ * A rename whose query matches nothing is a no-op update, not a conflict.
831
+ * Throwing here would turn "the row was already deleted" into a confusing
832
+ * uniqueness error.
833
+ */
834
+ test("allows a rename whose query matches no rows", async () => {
835
+ stubReads({ itemsBeingUpdated: [], conflictCount: 0 });
836
+
837
+ await expect(
838
+ hook()(makeUpdateBy({ name: "NewName" })),
839
+ ).resolves.toBeDefined();
840
+ });
841
+ });
842
+ });