@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
@@ -1,3 +1,25 @@
1
+ import { ResponseJSON, ResultSet } from "@clickhouse/client";
2
+ import TableColumnType from "../../../../Types/AnalyticsDatabase/TableColumnType";
3
+ import { SQL, Statement } from "../../AnalyticsDatabase/Statement";
4
+ import {
5
+ getClickhouseClusterName,
6
+ getClickhouseDatabaseName,
7
+ getStorageTableName,
8
+ } from "../../AnalyticsDatabase/ClusterConfig";
9
+ import { getQuerySettings } from "../../AnalyticsDatabase/QuerySettingsHelper";
10
+ import BadDataException from "../../../../Types/Exception/BadDataException";
11
+ import {
12
+ GoogleSecOpsDetectionSample,
13
+ GoogleSecOpsRunOptions,
14
+ GoogleSecOpsRunResult,
15
+ } from "../../../../Types/SecurityEvent/GoogleSecOpsDiagnostics";
16
+ import {
17
+ contentHashEventUid,
18
+ parseEventTime,
19
+ readString,
20
+ readValue,
21
+ } from "../../../../Utils/SecurityEvent/NormalizerHelpers";
22
+ import Semaphore, { SemaphoreMutex } from "../../../Infrastructure/Semaphore";
1
23
  import GoogleSecOpsConnection from "../../../../Models/DatabaseModels/GoogleSecOpsConnection";
2
24
  import LIMIT_MAX from "../../../../Types/Database/LimitMax";
3
25
  import OneUptimeDate from "../../../../Types/Date";
@@ -12,6 +34,7 @@ import OTelIngestService, {
12
34
  import SecurityEventService from "../../../Services/SecurityEventService";
13
35
  import { resolveTelemetryRetentionInDays } from "../../../../Types/Telemetry/TelemetryRetentionConfig";
14
36
  import logger from "../../Logger";
37
+ import { redactLogString } from "../../LogRedaction";
15
38
  import CaptureSpan from "../../Telemetry/CaptureSpan";
16
39
  import ConnectorErrorMessage from "../ConnectorErrorMessage";
17
40
  import { buildSecurityEventDbRow } from "../SecurityEventRow";
@@ -20,23 +43,24 @@ import GoogleSecOpsClient, { FetchAlertsResult } from "./GoogleSecOpsClient";
20
43
 
21
44
  const SECOPS_SERVICE_NAME: string = "Google SecOps";
22
45
 
23
- /*
24
- * First poll (no cursor) and the cap for how far back a stale cursor may
25
- * reach. A connection disabled for a week must not replay a week of
26
- * alerts in one tick.
27
- */
28
46
  const DEFAULT_LOOKBACK_IN_MINUTES: number = 15;
29
47
  const MAX_LOOKBACK_IN_MINUTES: number = 24 * 60;
30
-
31
- /*
32
- * Overlap between windows so boundary alerts are never missed; the
33
- * eventUid content hash keeps redelivered alerts deduplicatable.
34
- *
35
- * Still open (out of scope here): the overlap does produce genuine
36
- * duplicate rows, because SecurityEvent is a plain MergeTree with
37
- * eventUid outside the sort key, so nothing collapses them at write time.
38
- */
39
48
  const WINDOW_OVERLAP_IN_MINUTES: number = 1;
49
+ const MAX_FETCH_REQUESTS: number = 12;
50
+ const MAX_FETCH_DURATION_MS: number = 2 * 60 * 1000;
51
+ const MAX_ALERTS_PER_REQUEST: number = 1000;
52
+ const MAX_DIAGNOSTIC_SAMPLES: number = 25;
53
+ const MAX_RANGE_MS: number = 7 * 24 * 60 * 60 * 1000;
54
+ export const GOOGLE_SECOPS_SOURCE_LOCK_NAMESPACE: string = "GoogleSecOpsSource";
55
+
56
+ interface PollWindow {
57
+ startTime: Date;
58
+ endTime: Date;
59
+ warnings: Array<string>;
60
+ hasUsableCursor: boolean;
61
+ }
62
+
63
+ class RecordedPollFailure extends Error {}
40
64
 
41
65
  export default class GoogleSecOpsPoller {
42
66
  @CaptureSpan()
@@ -56,6 +80,7 @@ export default class GoogleSecOpsPoller {
56
80
  pollIntervalInMinutes: true,
57
81
  lastPolledAt: true,
58
82
  cursor: true,
83
+ includeNonAlertingDetections: true,
59
84
  },
60
85
  skip: 0,
61
86
  limit: LIMIT_MAX,
@@ -102,6 +127,10 @@ export default class GoogleSecOpsPoller {
102
127
  );
103
128
  logger.error(error);
104
129
 
130
+ if (error instanceof RecordedPollFailure) {
131
+ continue;
132
+ }
133
+
105
134
  /*
106
135
  * Stamping the failure is best-effort and must never take the
107
136
  * loop down with it: a throw here would skip every connection
@@ -119,7 +148,9 @@ export default class GoogleSecOpsPoller {
119
148
  id: connectionId,
120
149
  data: {
121
150
  lastPolledAt: OneUptimeDate.getCurrentDate(),
122
- lastError: ConnectorErrorMessage.toMessage(error),
151
+ lastError: redactLogString(
152
+ ConnectorErrorMessage.toMessage(error, { truncate: false }),
153
+ ),
123
154
  },
124
155
  props: {
125
156
  isRoot: true,
@@ -137,6 +168,84 @@ export default class GoogleSecOpsPoller {
137
168
  connection: GoogleSecOpsConnection,
138
169
  clientOverride?: GoogleSecOpsClient | undefined,
139
170
  ): Promise<number> {
171
+ const result: GoogleSecOpsRunResult = await this.executeConnection(
172
+ connection,
173
+ { type: "poll" },
174
+ clientOverride,
175
+ );
176
+ if (result.status === "failed") {
177
+ throw new RecordedPollFailure(
178
+ result.error || "Google SecOps poll failed.",
179
+ );
180
+ }
181
+ return result.ingestedCount;
182
+ }
183
+
184
+ /**
185
+ * Source-scoped serialization is required because ClickHouse does not
186
+ * deduplicate eventUid: a lookup followed by insert is only safe under this
187
+ * lock. The same lock covers different connections to the same source.
188
+ */
189
+ @CaptureSpan()
190
+ public static async executeConnection(
191
+ connection: GoogleSecOpsConnection,
192
+ options: GoogleSecOpsRunOptions,
193
+ clientOverride?: GoogleSecOpsClient | undefined,
194
+ ): Promise<GoogleSecOpsRunResult> {
195
+ this.validateConnection(connection);
196
+ if (options.type === "test" || options.type === "preview") {
197
+ return this.executeUnlocked(connection, options, clientOverride);
198
+ }
199
+
200
+ const mutex: SemaphoreMutex = await Semaphore.lock({
201
+ namespace: GOOGLE_SECOPS_SOURCE_LOCK_NAMESPACE,
202
+ key: connection.projectId!.toString(),
203
+ lockTimeout: 30000,
204
+ acquireTimeout: 10000,
205
+ retryInterval: 100,
206
+ });
207
+ try {
208
+ /*
209
+ * An injected client also injects the connection snapshot for tests.
210
+ * Production always reloads after waiting for another poll or backfill.
211
+ */
212
+ const current: GoogleSecOpsConnection | null = clientOverride
213
+ ? connection
214
+ : await GoogleSecOpsConnectionService.findOneById({
215
+ id: connection.id!,
216
+ select: {
217
+ _id: true,
218
+ projectId: true,
219
+ name: true,
220
+ region: true,
221
+ instanceResourceName: true,
222
+ serviceAccountJson: true,
223
+ cursor: true,
224
+ includeNonAlertingDetections: true,
225
+ },
226
+ props: { isRoot: true },
227
+ });
228
+ if (
229
+ !current ||
230
+ current.projectId?.toString() !== connection.projectId!.toString()
231
+ ) {
232
+ throw new BadDataException(
233
+ "Google SecOps connection no longer exists in this project.",
234
+ );
235
+ }
236
+ return await this.executeUnlocked(current, options, clientOverride);
237
+ } finally {
238
+ try {
239
+ await Semaphore.release(mutex);
240
+ } catch (error) {
241
+ logger.error(
242
+ `GoogleSecOpsPoller: could not release source lock: ${redactLogString(ConnectorErrorMessage.toMessage(error))}`,
243
+ );
244
+ }
245
+ }
246
+ }
247
+
248
+ private static validateConnection(connection: GoogleSecOpsConnection): void {
140
249
  if (
141
250
  !connection.id ||
142
251
  !connection.projectId ||
@@ -144,232 +253,522 @@ export default class GoogleSecOpsPoller {
144
253
  !connection.instanceResourceName ||
145
254
  !connection.serviceAccountJson
146
255
  ) {
147
- throw new Error(
256
+ throw new BadDataException(
148
257
  "Google SecOps connection is missing id, projectId, region, instance, or credentials.",
149
258
  );
150
259
  }
260
+ }
151
261
 
152
- const connectionId: string = connection.id.toString();
153
-
154
- const client: GoogleSecOpsClient =
155
- clientOverride ||
156
- new GoogleSecOpsClient({
157
- region: connection.region,
158
- instanceResourceName: connection.instanceResourceName,
159
- serviceAccountJson: connection.serviceAccountJson,
160
- });
161
-
162
- const endTime: Date = OneUptimeDate.getCurrentDate();
163
-
164
- const earliestAllowed: Date = OneUptimeDate.addRemoveMinutes(
165
- endTime,
166
- -MAX_LOOKBACK_IN_MINUTES,
167
- );
168
-
169
- const defaultStartTime: Date = OneUptimeDate.addRemoveMinutes(
170
- endTime,
262
+ private static getWindow(
263
+ connection: GoogleSecOpsConnection,
264
+ options: GoogleSecOpsRunOptions,
265
+ ): PollWindow {
266
+ const now: Date = OneUptimeDate.getCurrentDate();
267
+ let endTime: Date = now;
268
+ let startTime: Date = OneUptimeDate.addRemoveMinutes(
269
+ now,
171
270
  -DEFAULT_LOOKBACK_IN_MINUTES,
172
271
  );
173
-
174
- let startTime: Date = defaultStartTime;
175
-
176
- if (connection.cursor) {
272
+ const warnings: Array<string> = [];
273
+ let hasUsableCursor: boolean = false;
274
+
275
+ if (options.type === "preview" || options.type === "backfill") {
276
+ startTime = new Date(options.startTime || "");
277
+ endTime = new Date(options.endTime || "");
278
+ if (
279
+ !Number.isFinite(startTime.getTime()) ||
280
+ !Number.isFinite(endTime.getTime()) ||
281
+ startTime >= endTime ||
282
+ endTime.getTime() > now.getTime() + 60000 ||
283
+ endTime.getTime() - startTime.getTime() > MAX_RANGE_MS
284
+ ) {
285
+ throw new BadDataException(
286
+ "Select a valid past time range of at most seven days.",
287
+ );
288
+ }
289
+ } else if (options.type === "poll" && connection.cursor) {
177
290
  const cursorTime: Date = new Date(connection.cursor);
178
-
179
- if (Number.isNaN(cursorTime.getTime())) {
180
- /*
181
- * An unreadable cursor used to share a branch with a stale one and
182
- * open the full 24 hour window — the widest possible blast radius
183
- * for the least trustworthy input. It means "no usable cursor",
184
- * which is what a first poll means too.
185
- */
186
- logger.warn(
187
- `GoogleSecOpsPoller: connection ${connectionId} has an unreadable cursor ${JSON.stringify(
188
- connection.cursor,
189
- )}; polling the default ${DEFAULT_LOOKBACK_IN_MINUTES} minute window instead.`,
291
+ if (!Number.isFinite(cursorTime.getTime())) {
292
+ warnings.push(
293
+ "The saved cursor is unreadable; polling the default 15 minute window.",
294
+ );
295
+ } else if (cursorTime >= now) {
296
+ warnings.push(
297
+ "The saved cursor is in the future; polling the default 15 minute window.",
190
298
  );
191
299
  } else {
300
+ hasUsableCursor = true;
192
301
  startTime = OneUptimeDate.addRemoveMinutes(
193
302
  cursorTime,
194
303
  -WINDOW_OVERLAP_IN_MINUTES,
195
304
  );
305
+ const chunkEnd: Date = OneUptimeDate.addRemoveMinutes(
306
+ startTime,
307
+ MAX_LOOKBACK_IN_MINUTES,
308
+ );
309
+ if (chunkEnd < endTime) {
310
+ endTime = chunkEnd;
311
+ warnings.push(
312
+ "Catching up from the saved cursor in 24 hour windows. Later detections will be fetched by subsequent polls.",
313
+ );
314
+ }
196
315
  }
197
316
  }
317
+ return { startTime, endTime, warnings, hasUsableCursor };
318
+ }
198
319
 
199
- if (OneUptimeDate.isBefore(startTime, earliestAllowed)) {
200
- /*
201
- * The alerts between the cursor and the cap are skipped and will
202
- * never be fetched again, so the gap has to be stated. Silently
203
- * truncating it is how a connector comes back from an outage
204
- * looking healthy while a day of detections is simply missing.
205
- */
206
- logger.warn(
207
- `GoogleSecOpsPoller: connection ${connectionId} would poll from ${startTime.toISOString()}, ${OneUptimeDate.getMinutesBetweenTwoDates(
208
- startTime,
209
- endTime,
210
- )} minutes back and past the ${MAX_LOOKBACK_IN_MINUTES} minute cap; alerts before ${earliestAllowed.toISOString()} are skipped and will not be fetched again.`,
320
+ private static async executeUnlocked(
321
+ connection: GoogleSecOpsConnection,
322
+ options: GoogleSecOpsRunOptions,
323
+ clientOverride?: GoogleSecOpsClient | undefined,
324
+ ): Promise<GoogleSecOpsRunResult> {
325
+ const window: PollWindow = this.getWindow(connection, options);
326
+ const startedMs: number = Date.now();
327
+ const result: GoogleSecOpsRunResult = {
328
+ type: options.type,
329
+ ...(options.runId ? { runId: options.runId } : {}),
330
+ status: "running",
331
+ startedAt: new Date(startedMs).toISOString(),
332
+ completedAt: new Date(startedMs).toISOString(),
333
+ durationMs: 0,
334
+ windowStart: window.startTime.toISOString(),
335
+ windowEnd: window.endTime.toISOString(),
336
+ includeNonAlertingDetections:
337
+ connection.includeNonAlertingDetections === true,
338
+ fetchedCount: 0,
339
+ ingestedCount: 0,
340
+ duplicateCount: 0,
341
+ rejectedCount: 0,
342
+ failedCount: 0,
343
+ complete: true,
344
+ requestCount: 0,
345
+ warnings: window.warnings,
346
+ samples: [],
347
+ checks: [],
348
+ };
349
+ let phase: string = "Validate configuration";
350
+ let phaseStartedMs: number = Date.now();
351
+ try {
352
+ const client: GoogleSecOpsClient =
353
+ clientOverride ||
354
+ new GoogleSecOpsClient({
355
+ region: connection.region!,
356
+ instanceResourceName: connection.instanceResourceName!,
357
+ serviceAccountJson: connection.serviceAccountJson!,
358
+ });
359
+ result.checks.push({
360
+ name: phase,
361
+ status: "success",
362
+ durationMs: Date.now() - phaseStartedMs,
363
+ message:
364
+ "The region, instance and service account configuration are valid.",
365
+ });
366
+ if (options.type === "test") {
367
+ phase = "Authenticate with Google";
368
+ phaseStartedMs = Date.now();
369
+ await client.testAuthentication();
370
+ result.checks.push({
371
+ name: phase,
372
+ status: "success",
373
+ durationMs: Date.now() - phaseStartedMs,
374
+ message: "Google accepted the service account credentials.",
375
+ });
376
+ }
377
+ phase = "Read detections from the configured instance";
378
+ phaseStartedMs = Date.now();
379
+ const alerts: Array<JSONObject> = await this.fetchWindows(
380
+ client,
381
+ window,
382
+ result,
383
+ startedMs,
211
384
  );
385
+ result.fetchedCount = alerts.length;
386
+ result.checks.push({
387
+ name: phase,
388
+ status: "success",
389
+ durationMs: Date.now() - phaseStartedMs,
390
+ message:
391
+ "The configured Google SecOps instance is reachable and allows reading detections.",
392
+ });
212
393
 
213
- startTime = earliestAllowed;
214
- }
394
+ phase = "Normalize detections";
395
+ phaseStartedMs = Date.now();
396
+ const normalized: Array<NormalizedSecurityEvent> = [];
397
+ for (const alert of alerts) {
398
+ try {
399
+ if (!GoogleSecOpsAlertNormalizer.isGoogleSecOpsAlert(alert)) {
400
+ result.rejectedCount++;
401
+ continue;
402
+ }
403
+ const event: NormalizedSecurityEvent =
404
+ GoogleSecOpsAlertNormalizer.normalize(alert);
405
+ normalized.push(event);
406
+ if (result.samples.length < MAX_DIAGNOSTIC_SAMPLES) {
407
+ result.samples.push(this.sample(alert, event));
408
+ }
409
+ } catch {
410
+ result.failedCount++;
411
+ }
412
+ }
413
+ if (result.rejectedCount) {
414
+ result.warnings.push(
415
+ `${result.rejectedCount} returned objects were discarded because they do not look like Google SecOps detections.`,
416
+ );
417
+ }
418
+ if (result.failedCount) {
419
+ result.warnings.push(
420
+ `${result.failedCount} detections could not be normalized. The poll cursor is held for retry.`,
421
+ );
422
+ }
423
+ result.complete =
424
+ result.complete &&
425
+ result.failedCount === 0 &&
426
+ result.rejectedCount === 0;
427
+ result.checks.push({
428
+ name: phase,
429
+ status:
430
+ result.failedCount || result.rejectedCount ? "failed" : "success",
431
+ durationMs: Date.now() - phaseStartedMs,
432
+ message: `${normalized.length} detections recognized; ${result.rejectedCount} rejected; ${result.failedCount} failed.`,
433
+ });
215
434
 
216
- if (!OneUptimeDate.isBefore(startTime, endTime)) {
217
- /*
218
- * A cursor in the future — clock skew on the writer, or a restored
219
- * backup — used to send Chronicle an inverted timeRange, which is
220
- * neither an error the operator sees nor a window that returns
221
- * anything.
222
- */
223
- logger.warn(
224
- `GoogleSecOpsPoller: connection ${connectionId} cursor resolves to ${startTime.toISOString()}, at or after the current time; polling the default ${DEFAULT_LOOKBACK_IN_MINUTES} minute window instead.`,
435
+ if (options.type === "poll" || options.type === "backfill") {
436
+ phase = "Import detections";
437
+ phaseStartedMs = Date.now();
438
+ await this.ingest(connection, normalized, result);
439
+ result.checks.push({
440
+ name: phase,
441
+ status: "success",
442
+ durationMs: Date.now() - phaseStartedMs,
443
+ message: `${result.ingestedCount} imported; ${result.duplicateCount} already imported.`,
444
+ });
445
+ }
446
+ result.status = !result.complete
447
+ ? "partial"
448
+ : options.type === "test" || result.fetchedCount > 0
449
+ ? "success"
450
+ : "empty";
451
+ } catch (error) {
452
+ result.status = "failed";
453
+ result.complete = false;
454
+ result.error = redactLogString(
455
+ ConnectorErrorMessage.toMessage(error, { truncate: false }),
225
456
  );
226
-
227
- startTime = defaultStartTime;
457
+ result.checks.push({
458
+ name: phase,
459
+ status: "failed",
460
+ durationMs: Date.now() - phaseStartedMs,
461
+ message: result.error,
462
+ });
228
463
  }
229
-
230
- const fetched: FetchAlertsResult = await client.fetchDetectionAlerts({
231
- startTime,
232
- endTime,
233
- });
234
-
235
- if (fetched.truncatedByCount) {
464
+ result.completedAt = OneUptimeDate.getCurrentDate().toISOString();
465
+ result.durationMs = Math.max(0, Date.now() - startedMs);
466
+ for (const warning of result.warnings) {
236
467
  logger.warn(
237
- `GoogleSecOpsPoller: connection ${connectionId} window ${startTime.toISOString()} to ${endTime.toISOString()} matched more alerts than Chronicle will return, and this endpoint has no pagination — alerts in this window were dropped. Lower pollIntervalInMinutes.`,
468
+ `GoogleSecOpsPoller: connection ${connection.id!.toString()}: ${warning}`,
238
469
  );
239
470
  }
471
+ logger.debug(
472
+ `GoogleSecOpsPoller: connection ${connection.id!.toString()} fetched ${result.fetchedCount} alerts and ingested ${result.ingestedCount} security events for ${result.windowStart} to ${result.windowEnd}.`,
473
+ );
240
474
 
241
- if (fetched.truncatedByBytes) {
242
- logger.warn(
243
- `GoogleSecOpsPoller: connection ${connectionId} window ${startTime.toISOString()} to ${endTime.toISOString()} was truncated by Chronicle's memory limit — alerts in this window were dropped. Lower pollIntervalInMinutes.`,
244
- );
475
+ if (options.type === "poll") {
476
+ /*
477
+ * A failed first poll must keep its original start. Otherwise the next
478
+ * default lookback would slide past records before we ever imported them.
479
+ */
480
+ const cursor: string | undefined = result.complete
481
+ ? result.windowEnd
482
+ : !window.hasUsableCursor
483
+ ? OneUptimeDate.addRemoveMinutes(
484
+ window.startTime,
485
+ WINDOW_OVERLAP_IN_MINUTES,
486
+ ).toISOString()
487
+ : undefined;
488
+ await GoogleSecOpsConnectionService.updateOneById({
489
+ id: connection.id!,
490
+ data: {
491
+ lastPolledAt: new Date(result.completedAt),
492
+ lastPollResult: result as never,
493
+ lastError: (result.error ||
494
+ (result.complete
495
+ ? null
496
+ : result.warnings.join(" ") ||
497
+ "Poll incomplete; retrying the same window.")) as unknown as string,
498
+ ...(cursor ? { cursor } : {}),
499
+ ...(result.complete
500
+ ? { lastSuccessfulPollAt: new Date(result.completedAt) }
501
+ : {}),
502
+ ...(result.ingestedCount
503
+ ? { lastEventIngestedAt: new Date(result.completedAt) }
504
+ : {}),
505
+ },
506
+ props: { isRoot: true },
507
+ });
508
+ } else if (options.type === "backfill" && result.ingestedCount) {
509
+ await GoogleSecOpsConnectionService.updateOneById({
510
+ id: connection.id!,
511
+ data: { lastEventIngestedAt: new Date(result.completedAt) },
512
+ props: { isRoot: true },
513
+ });
245
514
  }
515
+ return result;
516
+ }
246
517
 
247
- const alerts: Array<JSONObject> = fetched.alerts;
248
-
249
- const normalizedAlerts: Array<NormalizedSecurityEvent> = [];
250
-
251
- /*
252
- * Objects the alert gate refused, and objects that blew up on the way
253
- * through it. They are kept apart because they mean opposite things
254
- * for the cursor: a refusal is deterministic and re-fetching it would
255
- * refuse it again forever, a failure may well succeed next time.
256
- */
257
- let rejectedCount: number = 0;
258
- let failedCount: number = 0;
259
-
260
- if (alerts.length > 0) {
261
- const serviceMetadata: TelemetryServiceMetadata =
262
- await OTelIngestService.telemetryServiceFromName({
263
- serviceName: SECOPS_SERVICE_NAME,
264
- projectId: connection.projectId,
265
- });
266
-
267
- const retentionDays: number = resolveTelemetryRetentionInDays({
268
- pillar: "securityEvents",
269
- serviceConfig: serviceMetadata.serviceRetentionConfig,
270
- serviceRetentionInDays: serviceMetadata.serviceRetentionInDays,
271
- projectConfig: serviceMetadata.projectRetentionConfig,
272
- projectRetentionInDays: serviceMetadata.projectRetentionInDays,
518
+ private static async fetchWindows(
519
+ client: GoogleSecOpsClient,
520
+ window: PollWindow,
521
+ result: GoogleSecOpsRunResult,
522
+ startedMs: number,
523
+ ): Promise<Array<JSONObject>> {
524
+ const pending: Array<{ startTime: Date; endTime: Date }> = [window];
525
+ const seen: Map<string, JSONObject> = new Map();
526
+ while (pending.length > 0) {
527
+ if (
528
+ result.requestCount >= MAX_FETCH_REQUESTS ||
529
+ Date.now() - startedMs >= MAX_FETCH_DURATION_MS
530
+ ) {
531
+ result.complete = false;
532
+ result.warnings.push(
533
+ "The recovery request limit was reached. Narrow the time range; the poll cursor has not advanced.",
534
+ );
535
+ break;
536
+ }
537
+ const current: { startTime: Date; endTime: Date } = pending.shift()!;
538
+ result.requestCount++;
539
+ const fetched: FetchAlertsResult = await client.fetchDetectionAlerts({
540
+ ...current,
541
+ maxAlerts: result.type === "test" ? 1 : MAX_ALERTS_PER_REQUEST,
542
+ includeNonAlertingDetections: result.includeNonAlertingDetections,
273
543
  });
274
-
275
- for (const alert of alerts) {
544
+ for (const alert of fetched.alerts) {
545
+ let key: string;
276
546
  try {
547
+ key = readString(alert, "id") || contentHashEventUid(alert);
548
+ } catch {
277
549
  /*
278
- * The normalizer is a total function whose class, category,
279
- * vendor and product are constants, so anything handed to it
280
- * comes back out as a plausible Detection Finding row. The gate
281
- * is what keeps a stray envelope chunk from being stored as a
282
- * severity-Unknown detection nobody can tell from a real one.
550
+ * Keep an uninspectable object in the normalization failure count
551
+ * without preventing valid detections in this response from importing.
283
552
  */
284
- if (!GoogleSecOpsAlertNormalizer.isGoogleSecOpsAlert(alert)) {
285
- rejectedCount++;
286
- continue;
287
- }
288
-
289
- normalizedAlerts.push(GoogleSecOpsAlertNormalizer.normalize(alert));
290
- } catch (normalizeError) {
291
- failedCount++;
292
- logger.error("GoogleSecOpsPoller: error normalizing alert");
293
- logger.error(normalizeError);
553
+ key = `malformed:${result.requestCount}:${seen.size}`;
294
554
  }
555
+ seen.set(key, alert);
295
556
  }
296
-
297
- if (rejectedCount > 0) {
298
- logger.warn(
299
- `GoogleSecOpsPoller: connection ${connectionId} discarded ${rejectedCount} of ${alerts.length} fetched objects that do not look like Google SecOps alerts.`,
300
- );
557
+ result.fetchedCount = seen.size;
558
+ const truncated: boolean =
559
+ fetched.truncatedByCount ||
560
+ fetched.truncatedByBytes ||
561
+ Math.max(fetched.filteredAlertsCount, fetched.baselineAlertsCount) >
562
+ fetched.alerts.length;
563
+ if (result.type === "test") {
564
+ /*
565
+ * A one-record permission probe is deliberately limited; it makes no
566
+ * assertion about whether the full detection window can be imported.
567
+ */
568
+ result.complete = fetched.complete;
569
+ if (truncated) {
570
+ result.warnings.push(
571
+ "Connection test reads at most one detection. Use Preview to inspect the full time range.",
572
+ );
573
+ }
574
+ if (!fetched.complete) {
575
+ result.warnings.push(
576
+ "Google returned an incomplete response. Connectivity works, but a complete read is not confirmed.",
577
+ );
578
+ }
579
+ break;
301
580
  }
302
-
303
- /*
304
- * Threat-intel enrichment before row building, same seam as the
305
- * HTTP ingest path — polled alerts get the same threat.* stamps.
306
- */
307
- await ThreatIntelEnricher.enrichNormalizedEvents({
308
- projectId: connection.projectId,
309
- events: normalizedAlerts,
310
- });
311
-
312
- const rows: Array<JSONObject> = normalizedAlerts.map(
313
- (normalized: NormalizedSecurityEvent): JSONObject => {
314
- return buildSecurityEventDbRow({
315
- normalized,
316
- projectId: connection.projectId!,
317
- serviceMetadata,
318
- retentionDays,
319
- });
320
- },
581
+ const midpoint: number = Math.floor(
582
+ (current.startTime.getTime() + current.endTime.getTime()) / 2,
321
583
  );
322
-
323
- if (rows.length > 0) {
324
- await SecurityEventService.insertJsonRows(rows);
584
+ if (
585
+ truncated &&
586
+ current.endTime.getTime() - current.startTime.getTime() > 1000
587
+ ) {
588
+ result.warnings.push(
589
+ `Google limited the response for ${current.startTime.toISOString()} to ${current.endTime.toISOString()}; retrying smaller windows.`,
590
+ );
591
+ pending.unshift(
592
+ { startTime: current.startTime, endTime: new Date(midpoint) },
593
+ { startTime: new Date(midpoint), endTime: current.endTime },
594
+ );
595
+ } else if (!fetched.complete || truncated) {
596
+ result.complete = false;
597
+ result.warnings.push(
598
+ truncated
599
+ ? "Google still truncated a one-second window. Some detections may be missing; the cursor has not advanced."
600
+ : "Google ended the response without confirming it was complete; the cursor has not advanced.",
601
+ );
325
602
  }
326
603
  }
604
+ return Array.from(seen.values());
605
+ }
327
606
 
328
- const ingested: number = normalizedAlerts.length;
329
-
330
- /*
331
- * Nothing storable came out of a window that did contain alerts, and
332
- * the reason was a failure rather than a refusal — so the alerts still
333
- * exist at Chronicle and the window has to be re-fetched. Advancing
334
- * here is what turned a normalizer fault into permanent, silent data
335
- * loss: the insert-failure path leaves the cursor alone by throwing,
336
- * and this path did not.
337
- */
338
- const advanceCursor: boolean = ingested > 0 || failedCount === 0;
607
+ private static sample(
608
+ alert: JSONObject,
609
+ event: NormalizedSecurityEvent,
610
+ ): GoogleSecOpsDetectionSample {
611
+ const detectionTime: Date | null = parseEventTime(
612
+ readValue(alert, "detectionTime") ?? readValue(alert, "detection_time"),
613
+ );
614
+ const createdTime: Date | null = parseEventTime(
615
+ readValue(alert, "createdTime") ?? readValue(alert, "created_time"),
616
+ );
617
+ const detection: unknown = readValue(alert, "detection");
618
+ const entry: JSONObject | undefined = Array.isArray(detection)
619
+ ? (detection[0] as JSONObject)
620
+ : (detection as JSONObject | undefined);
621
+ const isAlert: unknown = entry
622
+ ? entry["alertState"] ?? entry["alert_state"] ?? entry["alerting"]
623
+ : undefined;
624
+ return {
625
+ id: redactLogString(event.eventUid),
626
+ ruleName: redactLogString(event.ruleName),
627
+ ...(detectionTime ? { detectionTime: detectionTime.toISOString() } : {}),
628
+ ...(createdTime ? { createdTime: createdTime.toISOString() } : {}),
629
+ ...(typeof isAlert === "boolean"
630
+ ? { isAlert }
631
+ : isAlert === "ALERTING"
632
+ ? { isAlert: true }
633
+ : isAlert === "NOT_ALERTING" || isAlert === "NON_ALERTING"
634
+ ? { isAlert: false }
635
+ : {}),
636
+ };
637
+ }
339
638
 
340
- if (!advanceCursor) {
341
- logger.warn(
342
- `GoogleSecOpsPoller: connection ${connectionId} normalized none of its ${alerts.length} fetched alerts; holding the cursor so the window is polled again rather than skipped.`,
639
+ /**
640
+ * This is a correctness lookup, not a dashboard query: returning a partial
641
+ * result on timeout or reading a lagging replica would create duplicates.
642
+ * Read every replica and fail closed on an unavailable shard. The preceding
643
+ * source lock plus synchronous inserts make at least one replica contain
644
+ * every earlier acknowledged import before this query begins.
645
+ */
646
+ public static async findExistingEventUids(
647
+ projectId: ObjectID,
648
+ ids: Array<string>,
649
+ ): Promise<Set<string>> {
650
+ const existing: Set<string> = new Set();
651
+ const startedMs: number = Date.now();
652
+ for (
653
+ let offset: number = 0;
654
+ offset < ids.length;
655
+ offset += MAX_ALERTS_PER_REQUEST
656
+ ) {
657
+ if (Date.now() - startedMs >= 2 * 60 * 1000) {
658
+ throw new Error(
659
+ "Duplicate lookup exceeded its time limit. Retry a smaller import window.",
660
+ );
661
+ }
662
+ const statement: Statement = SQL`SELECT DISTINCT eventUid FROM clusterAllReplicas(
663
+ ${{ type: TableColumnType.Text, value: getClickhouseClusterName() }},
664
+ ${{ type: TableColumnType.Text, value: getClickhouseDatabaseName() }},
665
+ ${{ type: TableColumnType.Text, value: getStorageTableName(SecurityEventService.model.tableName) }}
666
+ ) WHERE projectId = ${{ type: TableColumnType.ObjectID, value: projectId }}
667
+ AND vendorName = ${{ type: TableColumnType.Text, value: "Google" }}
668
+ AND productName = ${{ type: TableColumnType.Text, value: SECOPS_SERVICE_NAME }}
669
+ AND eventUid IN ${{ type: TableColumnType.ArrayText, value: ids.slice(offset, offset + MAX_ALERTS_PER_REQUEST) }}`;
670
+ statement.append(
671
+ getQuerySettings({
672
+ maxExecutionTimeInSeconds: 30,
673
+ timeoutOverflowMode: "throw",
674
+ boundScanMemory: true,
675
+ additionalSettings: { skip_unavailable_shards: 0 },
676
+ }),
343
677
  );
678
+ const response: ResultSet<"JSON"> =
679
+ await SecurityEventService.executeQuery(statement);
680
+ const data: ResponseJSON<JSONObject> = await response.json<JSONObject>();
681
+ for (const row of data.data) {
682
+ if (typeof row["eventUid"] === "string") {
683
+ existing.add(row["eventUid"]);
684
+ }
685
+ }
344
686
  }
687
+ return existing;
688
+ }
345
689
 
346
- const cursorUpdate: { cursor?: string } = advanceCursor
347
- ? {
348
- /*
349
- * Still open (out of scope here): this stores the end of the
350
- * window rather than the newest detection timestamp actually
351
- * ingested, which is what the column documents itself as.
352
- */
353
- cursor: endTime.toISOString(),
690
+ private static async ingest(
691
+ connection: GoogleSecOpsConnection,
692
+ normalized: Array<NormalizedSecurityEvent>,
693
+ result: GoogleSecOpsRunResult,
694
+ ): Promise<void> {
695
+ if (!normalized.length) {
696
+ return;
697
+ }
698
+ const seen: Set<string> = new Set();
699
+ const unique: Array<NormalizedSecurityEvent> = normalized.filter(
700
+ (event: NormalizedSecurityEvent): boolean => {
701
+ if (seen.has(event.eventUid)) {
702
+ result.duplicateCount++;
703
+ return false;
354
704
  }
355
- : {};
356
-
357
- await GoogleSecOpsConnectionService.updateOneById({
358
- id: connection.id,
359
- data: {
360
- lastPolledAt: endTime,
361
- ...cursorUpdate,
362
- lastError: null as unknown as string,
705
+ seen.add(event.eventUid);
706
+ return true;
363
707
  },
364
- props: {
365
- isRoot: true,
708
+ );
709
+ const existing: Set<string> = await this.findExistingEventUids(
710
+ connection.projectId!,
711
+ unique.map((event: NormalizedSecurityEvent): string => {
712
+ return event.eventUid;
713
+ }),
714
+ );
715
+ const fresh: Array<NormalizedSecurityEvent> = unique.filter(
716
+ (event: NormalizedSecurityEvent): boolean => {
717
+ if (existing.has(event.eventUid)) {
718
+ result.duplicateCount++;
719
+ return false;
720
+ }
721
+ return true;
366
722
  },
723
+ );
724
+ if (!fresh.length) {
725
+ return;
726
+ }
727
+ const serviceMetadata: TelemetryServiceMetadata =
728
+ await OTelIngestService.telemetryServiceFromName({
729
+ serviceName: SECOPS_SERVICE_NAME,
730
+ projectId: connection.projectId!,
731
+ });
732
+ const retentionDays: number = resolveTelemetryRetentionInDays({
733
+ pillar: "securityEvents",
734
+ serviceConfig: serviceMetadata.serviceRetentionConfig,
735
+ serviceRetentionInDays: serviceMetadata.serviceRetentionInDays,
736
+ projectConfig: serviceMetadata.projectRetentionConfig,
737
+ projectRetentionInDays: serviceMetadata.projectRetentionInDays,
367
738
  });
368
-
369
- logger.debug(
370
- `GoogleSecOpsPoller: connection ${connectionId} fetched ${alerts.length} alerts and ingested ${ingested} security events for ${startTime.toISOString()} to ${endTime.toISOString()}.`,
739
+ await ThreatIntelEnricher.enrichNormalizedEvents({
740
+ projectId: connection.projectId!,
741
+ events: fresh,
742
+ });
743
+ const rows: Array<JSONObject> = fresh.map(
744
+ (event: NormalizedSecurityEvent): JSONObject => {
745
+ event.attributes["oneuptime.google_secops.connection_id"] =
746
+ connection.id!.toString();
747
+ return buildSecurityEventDbRow({
748
+ normalized: event,
749
+ projectId: connection.projectId!,
750
+ serviceMetadata,
751
+ retentionDays,
752
+ });
753
+ },
371
754
  );
372
-
373
- return ingested;
755
+ /*
756
+ * The source lock cannot be released before buffered writes are visible.
757
+ * This low-volume connector needs synchronous acknowledgements regardless
758
+ * of the high-volume telemetry ingestion defaults.
759
+ */
760
+ await SecurityEventService.insertJsonRows(rows, {
761
+ clickhouseSettings: { async_insert: 0, insert_distributed_sync: 1 },
762
+ });
763
+ result.ingestedCount = rows.length;
764
+ const times: Array<string> = rows
765
+ .map((row: JSONObject): string => {
766
+ return new Date(
767
+ String(row["time"]).replace(" ", "T") + "Z",
768
+ ).toISOString();
769
+ })
770
+ .sort();
771
+ result.eventTimeStart = times[0];
772
+ result.eventTimeEnd = times[times.length - 1];
374
773
  }
375
774
  }