@oneuptime/common 12.0.14 → 12.0.16

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 (853) hide show
  1. package/Models/AnalyticsModels/Index.ts +10 -0
  2. package/Models/AnalyticsModels/LogCountBaseline.ts +174 -0
  3. package/Models/AnalyticsModels/SecurityEvent.ts +794 -0
  4. package/Models/AnalyticsModels/Span.ts +29 -1
  5. package/Models/AnalyticsModels/SpanCountBaseline.ts +198 -0
  6. package/Models/DatabaseModels/Alert.ts +42 -0
  7. package/Models/DatabaseModels/AlertMeasurement.ts +1114 -0
  8. package/Models/DatabaseModels/AlertMeasurementValue.ts +501 -0
  9. package/Models/DatabaseModels/AlertStateTimeline.ts +10 -2
  10. package/Models/DatabaseModels/BillingPaymentMethod.ts +8 -10
  11. package/Models/DatabaseModels/DetectionRule.ts +487 -0
  12. package/Models/DatabaseModels/GlobalOidc.ts +20 -0
  13. package/Models/DatabaseModels/GlobalSso.ts +20 -0
  14. package/Models/DatabaseModels/GoogleSecOpsConnection.ts +382 -0
  15. package/Models/DatabaseModels/Incident.ts +42 -0
  16. package/Models/DatabaseModels/IncidentMeasurement.ts +1114 -0
  17. package/Models/DatabaseModels/IncidentMeasurementValue.ts +501 -0
  18. package/Models/DatabaseModels/IncidentStateTimeline.ts +10 -2
  19. package/Models/DatabaseModels/IncomingCallPolicyLabelRule.ts +36 -0
  20. package/Models/DatabaseModels/IncomingCallPolicyOwnerRule.ts +42 -0
  21. package/Models/DatabaseModels/Index.ts +20 -0
  22. package/Models/DatabaseModels/Label.ts +11 -0
  23. package/Models/DatabaseModels/LlmCostBudget.ts +655 -0
  24. package/Models/DatabaseModels/LlmModelPrice.ts +481 -0
  25. package/Models/DatabaseModels/LogSavedView.ts +87 -0
  26. package/Models/DatabaseModels/MarketingConversion.ts +222 -10
  27. package/Models/DatabaseModels/MetricSavedView.ts +59 -0
  28. package/Models/DatabaseModels/NetworkDeviceLinkRule.ts +46 -0
  29. package/Models/DatabaseModels/OnCallDutyPolicyLabelRule.ts +36 -0
  30. package/Models/DatabaseModels/OnCallDutyPolicyOwnerRule.ts +42 -0
  31. package/Models/DatabaseModels/OnCallDutyPolicyScheduleLabelRule.ts +36 -0
  32. package/Models/DatabaseModels/OnCallDutyPolicyScheduleOwnerRule.ts +42 -0
  33. package/Models/DatabaseModels/Probe.ts +21 -0
  34. package/Models/DatabaseModels/RunbookLabelRule.ts +36 -0
  35. package/Models/DatabaseModels/RunbookOwnerRule.ts +42 -0
  36. package/Models/DatabaseModels/ScheduledMaintenanceMeasurement.ts +1104 -0
  37. package/Models/DatabaseModels/ScheduledMaintenanceMeasurementValue.ts +491 -0
  38. package/Models/DatabaseModels/ScheduledMaintenanceStateTimeline.ts +10 -2
  39. package/Models/DatabaseModels/StatusPage.ts +7 -4
  40. package/Models/DatabaseModels/StatusPageLabelRule.ts +36 -0
  41. package/Models/DatabaseModels/StatusPageOwnerRule.ts +42 -0
  42. package/Models/DatabaseModels/TableView.ts +15 -0
  43. package/Models/DatabaseModels/Team.ts +13 -0
  44. package/Models/DatabaseModels/TeamMember.ts +8 -0
  45. package/Models/DatabaseModels/TraceSavedView.ts +52 -0
  46. package/Models/DatabaseModels/WorkflowLabelRule.ts +36 -0
  47. package/Models/DatabaseModels/WorkflowOwnerRule.ts +42 -0
  48. package/Server/API/StatusPageAPI.ts +29 -4
  49. package/Server/API/TelemetryAPI.ts +252 -6
  50. package/Server/API/UserAPI.ts +88 -0
  51. package/Server/EnvironmentConfig.ts +43 -1
  52. package/Server/Infrastructure/Postgres/SchemaMigrations/1787800000000-AddScopeToNetworkDeviceLinkRule.ts +19 -0
  53. package/Server/Infrastructure/Postgres/SchemaMigrations/1787900000000-AddRestrictToAttachedProjectsToGlobalSso.ts +40 -0
  54. package/Server/Infrastructure/Postgres/SchemaMigrations/1788000000000-AddDetectionRuleAndGoogleSecOpsConnection.ts +88 -0
  55. package/Server/Infrastructure/Postgres/SchemaMigrations/1788100000000-AddMeasurements.ts +457 -0
  56. package/Server/Infrastructure/Postgres/SchemaMigrations/1788200000000-AddLlmCostBudget.ts +97 -0
  57. package/Server/Infrastructure/Postgres/SchemaMigrations/1788300000000-AddLlmModelPrice.ts +45 -0
  58. package/Server/Infrastructure/Postgres/SchemaMigrations/1788400000000-AddMarketingConversionAttribution.ts +105 -0
  59. package/Server/Infrastructure/Postgres/SchemaMigrations/1788500000000-RemoveLlmCostBudgetAlertColumns.ts +77 -0
  60. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +16 -0
  61. package/Server/Middleware/IdentityRateLimit.ts +672 -0
  62. package/Server/Middleware/SlackAuthorization.ts +43 -6
  63. package/Server/Middleware/UserAuthorization.ts +236 -26
  64. package/Server/Middleware/WhatsAppAuthorization.ts +43 -3
  65. package/Server/Services/AccessTokenService.ts +15 -2
  66. package/Server/Services/AlertMeasurementService.ts +302 -0
  67. package/Server/Services/AlertMeasurementValueService.ts +508 -0
  68. package/Server/Services/AlertService.ts +50 -0
  69. package/Server/Services/AlertStateTimelineService.ts +54 -0
  70. package/Server/Services/DetectionRuleService.ts +74 -0
  71. package/Server/Services/GlobalOidcProjectService.ts +126 -1
  72. package/Server/Services/GlobalOidcService.ts +132 -0
  73. package/Server/Services/GlobalSsoProjectService.ts +126 -1
  74. package/Server/Services/GlobalSsoService.ts +132 -0
  75. package/Server/Services/GoogleSecOpsConnectionService.ts +89 -0
  76. package/Server/Services/IncidentMeasurementService.ts +304 -0
  77. package/Server/Services/IncidentMeasurementValueService.ts +523 -0
  78. package/Server/Services/IncidentService.ts +51 -0
  79. package/Server/Services/IncidentStateTimelineService.ts +54 -0
  80. package/Server/Services/Index.ts +30 -0
  81. package/Server/Services/LlmCostBudgetService.ts +93 -0
  82. package/Server/Services/LlmModelPriceService.ts +202 -0
  83. package/Server/Services/LogAggregationService.ts +1106 -2
  84. package/Server/Services/LogCountBaselineService.ts +163 -0
  85. package/Server/Services/MutableMetricService.ts +30 -9
  86. package/Server/Services/ScheduledMaintenanceMeasurementService.ts +311 -0
  87. package/Server/Services/ScheduledMaintenanceMeasurementValueService.ts +546 -0
  88. package/Server/Services/ScheduledMaintenanceService.ts +53 -0
  89. package/Server/Services/ScheduledMaintenanceStateTimelineService.ts +188 -1
  90. package/Server/Services/SecurityEventService.ts +104 -0
  91. package/Server/Services/SpanCountBaselineService.ts +173 -0
  92. package/Server/Services/StatusPageService.ts +4 -3
  93. package/Server/Services/TelemetryUsageBillingService.ts +17 -2
  94. package/Server/Services/UserEmailService.ts +4 -4
  95. package/Server/Services/UserService.ts +284 -51
  96. package/Server/Services/UserTotpAuthService.ts +27 -86
  97. package/Server/Services/UserWebAuthnService.ts +26 -86
  98. package/Server/Types/Billing/MeteredPlan/AllMeteredPlans.ts +14 -0
  99. package/Server/Types/Database/Permissions/TenantPermission.ts +10 -0
  100. package/Server/Types/Database/QueryHelper.ts +1 -1
  101. package/Server/Utils/AI/Chat/ObservabilityChatPrompt.ts +1 -1
  102. package/Server/Utils/AI/Toolbox/Index.ts +6 -0
  103. package/Server/Utils/AI/Toolbox/SecurityEventTools.ts +349 -0
  104. package/Server/Utils/AnalyticsDatabase/StatementGenerator.ts +13 -4
  105. package/Server/Utils/Attribution.ts +130 -34
  106. package/Server/Utils/CronTab.ts +73 -0
  107. package/Server/Utils/GlobalSsoAuthorization.ts +175 -0
  108. package/Server/Utils/Marketing/ConversionUploadProvider.ts +123 -11
  109. package/Server/Utils/Marketing/Providers/GoogleAds.ts +71 -8
  110. package/Server/Utils/Marketing/Providers/LinkedIn.ts +55 -17
  111. package/Server/Utils/Marketing/Providers/Meta.ts +53 -19
  112. package/Server/Utils/Marketing/Providers/MicrosoftAds.ts +38 -11
  113. package/Server/Utils/Marketing/Providers/Reddit.ts +46 -16
  114. package/Server/Utils/Measurement/MeasurementDefinitionValidator.ts +209 -0
  115. package/Server/Utils/Measurement/MeasurementMetricWriter.ts +189 -0
  116. package/Server/Utils/Monitor/Criteria/APIRequestCriteria.ts +48 -33
  117. package/Server/Utils/Monitor/Criteria/CountAnomaly.ts +182 -0
  118. package/Server/Utils/Monitor/Criteria/DnsMonitorCriteria.ts +35 -30
  119. package/Server/Utils/Monitor/Criteria/DomainMonitorCriteria.ts +33 -28
  120. package/Server/Utils/Monitor/Criteria/EvaluateOverTime.ts +475 -47
  121. package/Server/Utils/Monitor/Criteria/ExternalStatusPageMonitorCriteria.ts +35 -30
  122. package/Server/Utils/Monitor/Criteria/IncomingRequestCriteria.ts +34 -28
  123. package/Server/Utils/Monitor/Criteria/LogMonitorCriteria.ts +132 -0
  124. package/Server/Utils/Monitor/Criteria/SSLMonitorCriteria.ts +33 -28
  125. package/Server/Utils/Monitor/Criteria/SecurityEventsMonitorCriteria.ts +35 -0
  126. package/Server/Utils/Monitor/Criteria/ServerMonitorCriteria.ts +69 -40
  127. package/Server/Utils/Monitor/Criteria/SnmpMonitorCriteria.ts +35 -29
  128. package/Server/Utils/Monitor/Criteria/TraceMonitorCriteria.ts +132 -0
  129. package/Server/Utils/Monitor/DataToProcess.ts +2 -0
  130. package/Server/Utils/Monitor/MonitorCriteriaDataExtractor.ts +14 -0
  131. package/Server/Utils/Monitor/MonitorCriteriaEvaluator.ts +23 -0
  132. package/Server/Utils/Monitor/MonitorCriteriaObservationBuilder.ts +20 -0
  133. package/Server/Utils/Monitor/MonitorResource.ts +177 -21
  134. package/Server/Utils/Monitor/MonitorStepResourceIdentity.ts +1 -0
  135. package/Server/Utils/Monitor/MonitorStepsReferenceExtractor.ts +1 -0
  136. package/Server/Utils/SecurityEvent/DetectionRuleEvaluator.ts +548 -0
  137. package/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsClient.ts +262 -0
  138. package/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsPoller.ts +212 -0
  139. package/Server/Utils/SecurityEvent/SecurityEventRow.ts +101 -0
  140. package/Server/Utils/SecurityEvent/Sigma/SigmaClickhouseCompiler.ts +635 -0
  141. package/Server/Utils/StatusPageContentSecurityPolicy.ts +56 -0
  142. package/Server/Utils/StatusPageCustomizationAccess.ts +117 -0
  143. package/Server/Utils/Telemetry/LlmCostBudgetEvaluator.ts +379 -0
  144. package/Server/Utils/Telemetry/LlmSpan.ts +83 -4
  145. package/Server/Utils/Telemetry/LogErrorPatternSql.ts +136 -0
  146. package/Server/Utils/UserPermission/UserPermission.ts +57 -1
  147. package/Tests/App/Dashboard/AlertsSideMenu.test.tsx +4 -0
  148. package/Tests/App/Dashboard/CreatePageEntryPointPermissions.test.tsx +306 -0
  149. package/Tests/App/Dashboard/DangerZone.test.tsx +11 -0
  150. package/Tests/App/Dashboard/IncidentsSideMenu.test.tsx +4 -0
  151. package/Tests/App/Dashboard/LogMonitorAttributeOperatorPreview.test.tsx +459 -0
  152. package/Tests/App/Dashboard/OverviewCustomFields.test.tsx +24 -0
  153. package/Tests/App/Dashboard/ScheduledMaintenanceSideMenu.test.tsx +6 -0
  154. package/Tests/Models/DatabaseModels/DomainRoleTierCoverage.test.ts +323 -0
  155. package/Tests/Models/DatabaseModels/ProjectSharedResources.test.ts +386 -0
  156. package/Tests/Server/API/LogErrorPatternAPI.test.ts +811 -0
  157. package/Tests/Server/API/StatusPageCustomizationOrigin.test.ts +348 -0
  158. package/Tests/Server/API/UserAuthenticationAPI.test.ts +11 -0
  159. package/Tests/Server/API/UserProjectsAPI.test.ts +11 -2
  160. package/Tests/Server/API/UserTwoFactorAuthAdminAPI.test.ts +918 -0
  161. package/Tests/Server/Infrastructure/LocalCache.test.ts +149 -0
  162. package/Tests/Server/Infrastructure/Postgres/FixTotpOtpUrlAlgorithmMigration.test.ts +9 -59
  163. package/Tests/Server/Infrastructure/Postgres/SchemaMigrationsOrdering.test.ts +227 -0
  164. package/Tests/Server/Middleware/SlackAuthorization.test.ts +149 -0
  165. package/Tests/Server/Middleware/UserAuthorization.test.ts +27 -13
  166. package/Tests/Server/Middleware/UserAuthorizationGlobalSsoGovernance.test.ts +1455 -0
  167. package/Tests/Server/Middleware/UserAuthorizationSSOProvider.test.ts +91 -2
  168. package/Tests/Server/Middleware/WhatsAppAuthorization.test.ts +233 -0
  169. package/Tests/Server/Services/AccessTokenProjectUserGrant.test.ts +249 -0
  170. package/Tests/Server/Services/AlertMeasurementService.test.ts +665 -0
  171. package/Tests/Server/Services/AlertMeasurementValueService.test.ts +389 -0
  172. package/Tests/Server/Services/DetectionRuleService.test.ts +254 -0
  173. package/Tests/Server/Services/DiscoveryScanClaimHookFreeSafety.test.ts +21 -8
  174. package/Tests/Server/Services/GlobalSsoProviderAuthorization.test.ts +1242 -0
  175. package/Tests/Server/Services/IncidentMeasurementService.test.ts +394 -0
  176. package/Tests/Server/Services/IncidentMeasurementValueService.test.ts +816 -0
  177. package/Tests/Server/Services/LlmCostBudgetService.test.ts +104 -0
  178. package/Tests/Server/Services/LogAggregationAttributeOperators.test.ts +405 -0
  179. package/Tests/Server/Services/LogErrorPatternAggregation.test.ts +804 -0
  180. package/Tests/Server/Services/MonitorResourceProbeAgreementHydration.test.ts +459 -0
  181. package/Tests/Server/Services/MonitorResourceProbeAgreementReuse.test.ts +10 -0
  182. package/Tests/Server/Services/MutableMetricNameRouting.test.ts +83 -0
  183. package/Tests/Server/Services/ScheduledMaintenanceMeasurementService.test.ts +750 -0
  184. package/Tests/Server/Services/ScheduledMaintenanceMeasurementValueService.test.ts +478 -0
  185. package/Tests/Server/Services/UserAuthenticationService.test.ts +216 -4
  186. package/Tests/Server/Services/UserTwoFactorAuthAdmin.test.ts +1190 -0
  187. package/Tests/Server/Types/AnalyticsDatabase/AggregateUtilBucketTimestamp.test.ts +416 -0
  188. package/Tests/Server/Types/Database/Permissions/ScopedRoleSharedResourceAccess.test.ts +466 -0
  189. package/Tests/Server/Types/Database/QueryHelperManyToManyAndEmptyValues.test.ts +551 -0
  190. package/Tests/Server/Types/Database/QueryHelperOperators.test.ts +265 -0
  191. package/Tests/Server/Types/Database/QueryHelperTextAndStructuralOperators.test.ts +206 -0
  192. package/Tests/Server/Types/Database/SelectUtil.test.ts +348 -0
  193. package/Tests/Server/Utils/AnalyticsDatabase/ClusterAwareSchema.test.ts +6 -0
  194. package/Tests/Server/Utils/AnalyticsDatabase/FractionalAttributeThreshold.test.ts +224 -0
  195. package/Tests/Server/Utils/AnalyticsDatabase/StatementGenerator.test.ts +172 -2
  196. package/Tests/Server/Utils/Attribution.test.ts +228 -1
  197. package/Tests/Server/Utils/CronTab.test.ts +116 -0
  198. package/Tests/Server/Utils/GlobalSSOToken.test.ts +581 -0
  199. package/Tests/Server/Utils/GlobalSsoAuthorization.test.ts +1401 -0
  200. package/Tests/Server/Utils/Marketing/AdUploadableConversionTypes.test.ts +315 -0
  201. package/Tests/Server/Utils/Marketing/ConversionUploadProvider.test.ts +124 -7
  202. package/Tests/Server/Utils/Marketing/GoogleAds.test.ts +253 -1
  203. package/Tests/Server/Utils/Marketing/LinkedIn.test.ts +282 -0
  204. package/Tests/Server/Utils/Marketing/Meta.test.ts +304 -0
  205. package/Tests/Server/Utils/Marketing/MicrosoftAds.test.ts +263 -0
  206. package/Tests/Server/Utils/Marketing/Reddit.test.ts +259 -0
  207. package/Tests/Server/Utils/Measurement/MeasurementDefinitionValidator.test.ts +322 -0
  208. package/Tests/Server/Utils/Measurement/MeasurementMetricWriter.test.ts +373 -0
  209. package/Tests/Server/Utils/Monitor/Criteria/APIRequestCriteriaEvaluateOverTime.test.ts +508 -0
  210. package/Tests/Server/Utils/Monitor/Criteria/APIRequestCriteriaPortTimings.test.ts +30 -9
  211. package/Tests/Server/Utils/Monitor/Criteria/CountAnomaly.test.ts +221 -0
  212. package/Tests/Server/Utils/Monitor/Criteria/EvaluateOverTime.test.ts +987 -0
  213. package/Tests/Server/Utils/Monitor/Criteria/ExternalStatusPageMonitorCriteria.test.ts +916 -0
  214. package/Tests/Server/Utils/Monitor/Criteria/LogMonitorCriteria.test.ts +236 -0
  215. package/Tests/Server/Utils/Monitor/Criteria/ProfileMonitorCriteria.test.ts +382 -0
  216. package/Tests/Server/Utils/Monitor/Criteria/SecurityEventsMonitorCriteria.test.ts +147 -0
  217. package/Tests/Server/Utils/Monitor/Criteria/ServerMonitorCriteria.test.ts +1219 -0
  218. package/Tests/Server/Utils/Monitor/Criteria/TraceMonitorCriteria.test.ts +274 -0
  219. package/Tests/Server/Utils/Monitor/MonitorResourceIngestedStepSelection.test.ts +86 -0
  220. package/Tests/Server/Utils/Monitor/SecurityEventsMonitorDataExtractor.test.ts +93 -0
  221. package/Tests/Server/Utils/SecurityEvent/DetectionRuleEvaluator.test.ts +660 -0
  222. package/Tests/Server/Utils/SecurityEvent/GoogleSecOpsClient.test.ts +308 -0
  223. package/Tests/Server/Utils/SecurityEvent/GoogleSecOpsPoller.test.ts +271 -0
  224. package/Tests/Server/Utils/SecurityEvent/SecurityEventRow.test.ts +272 -0
  225. package/Tests/Server/Utils/SecurityEvent/SigmaClickhouseCompiler.test.ts +511 -0
  226. package/Tests/Server/Utils/StatusPageContentSecurityPolicy.test.ts +136 -0
  227. package/Tests/Server/Utils/StatusPageCustomizationAccess.test.ts +223 -0
  228. package/Tests/Server/Utils/Telemetry/LlmCostBudgetEvaluator.test.ts +497 -0
  229. package/Tests/Server/Utils/Telemetry/LlmSpan.test.ts +380 -0
  230. package/Tests/Server/Utils/Telemetry/LogErrorPatternSql.test.ts +207 -0
  231. package/Tests/Server/Utils/UserPermission/ProjectUserGrant.test.ts +293 -0
  232. package/Tests/Types/Monitor/MonitorStepConfigHelpers.test.ts +165 -0
  233. package/Tests/Types/Monitor/MonitorStepInfraMonitorUtils.test.ts +194 -0
  234. package/Tests/Types/Monitor/MonitorStepSecurityEventsMonitor.test.ts +201 -0
  235. package/Tests/Types/NetworkDevice/NetworkDeviceLinkRuleScope.test.ts +215 -0
  236. package/Tests/Types/SecurityEvent/OcsfEventClass.test.ts +105 -0
  237. package/Tests/Types/SecurityEvent/OcsfSeverity.test.ts +111 -0
  238. package/Tests/Types/Telemetry/LlmCostCatalog.test.ts +516 -0
  239. package/Tests/UI/Components/ActiveFilterChipsOperatorValues.test.tsx +222 -0
  240. package/Tests/UI/Components/BulkActionPermissionGating.test.tsx +296 -0
  241. package/Tests/UI/Components/CardModelDetailPermissionGating.test.tsx +305 -0
  242. package/Tests/UI/Components/CustomFields/CustomFieldsDetail.test.tsx +23 -0
  243. package/Tests/UI/Components/DictionaryFilterOperatorDisplay.test.ts +239 -0
  244. package/Tests/UI/Components/DisabledButtonTooltip.test.tsx +267 -0
  245. package/Tests/UI/Components/DuplicateModel.test.tsx +37 -0
  246. package/Tests/UI/Components/Forms/FormSubmitAnalytics.test.tsx +206 -0
  247. package/Tests/UI/Components/ModelCardPermissionGating.test.tsx +348 -0
  248. package/Tests/UI/Components/ModelDelete.test.tsx +25 -1
  249. package/Tests/UI/Components/ModelFormCreatePermission.test.tsx +342 -0
  250. package/Tests/UI/Components/ModelTable/BaseModelTablePermissionGating.test.tsx +680 -0
  251. package/Tests/UI/Components/OrderedStatesListCreateGate.test.tsx +174 -0
  252. package/Tests/UI/Components/SavedViewsDropdownSearch.test.tsx +1127 -0
  253. package/Tests/UI/Components/SavedViewsFacetSection.test.tsx +958 -0
  254. package/Tests/UI/Components/SavedViewsList.test.ts +699 -0
  255. package/Tests/UI/Components/SavedViewsSidebarIntegration.test.tsx +640 -0
  256. package/Tests/UI/Components/SavedViewsSurfaceParity.test.tsx +679 -0
  257. package/Tests/UI/Components/TableViewLoadFailure.test.tsx +248 -0
  258. package/Tests/UI/Types/UseComponentOutsideClick.test.tsx +226 -0
  259. package/Tests/UI/Utils/AIChatExport/ConversationMarkdown.test.ts +774 -0
  260. package/Tests/UI/Utils/AIChatExport/MarkdownBlocks.test.ts +791 -0
  261. package/Tests/UI/Utils/AIChatExport/MarkdownSafety.test.ts +544 -0
  262. package/Tests/UI/Utils/PermissionGate.test.ts +467 -0
  263. package/Tests/Utils/Analytics.test.ts +187 -0
  264. package/Tests/Utils/Measurement/MeasurementEvaluator.test.ts +639 -0
  265. package/Tests/Utils/Monitor/MonitorMetricType.test.ts +80 -0
  266. package/Tests/Utils/Monitor/MonitorSummarySnapshotUtil.test.ts +1 -0
  267. package/Tests/Utils/Monitor/NetworkDeviceLinkRuleUtil.test.ts +1576 -0
  268. package/Tests/Utils/NetworkDevice/DeviceHealthStateUtil.test.ts +433 -0
  269. package/Tests/Utils/NetworkDiscovery/UnclaimedScanDiagnosis.test.ts +214 -0
  270. package/Tests/Utils/SecurityEvent/GenericNormalizer.test.ts +204 -0
  271. package/Tests/Utils/SecurityEvent/GoogleSecOpsAlertNormalizer.test.ts +252 -0
  272. package/Tests/Utils/SecurityEvent/NormalizerHelpers.test.ts +274 -0
  273. package/Tests/Utils/SecurityEvent/OcsfNormalizer.test.ts +208 -0
  274. package/Tests/Utils/SecurityEvent/SecurityEventNormalizer.test.ts +172 -0
  275. package/Tests/Utils/SecurityEvent/SigmaRuleParser.test.ts +471 -0
  276. package/Tests/Utils/SecurityEvent/UdmNormalizer.test.ts +361 -0
  277. package/Tests/Utils/Telemetry/CrossSignalScope.test.ts +82 -0
  278. package/Tests/Utils/Telemetry/LogErrorPattern.test.ts +463 -0
  279. package/Types/AI/AIChatTypes.ts +1 -0
  280. package/Types/Alerts/AlertMeasurementAnchorType.ts +14 -0
  281. package/Types/Alerts/AlertStateRole.ts +11 -0
  282. package/Types/AnalyticsDatabase/AnalyticsTableName.ts +16 -0
  283. package/Types/Dashboard/Chart/ChartType.ts +1 -0
  284. package/Types/Dashboard/DashboardComponentType.ts +2 -0
  285. package/Types/Dashboard/DashboardComponents/DashboardSecurityEventsFlowComponent.ts +18 -0
  286. package/Types/Dashboard/DashboardComponents/DashboardSecurityEventsListComponent.ts +16 -0
  287. package/Types/Incident/IncidentMeasurementAnchorType.ts +34 -0
  288. package/Types/Incident/IncidentStateRole.ts +14 -0
  289. package/Types/Marketing/Attribution.ts +75 -0
  290. package/Types/Marketing/MarketingConversion.ts +43 -1
  291. package/Types/Measurement/MeasurementAggregationType.ts +43 -0
  292. package/Types/Measurement/MeasurementAnchorKind.ts +23 -0
  293. package/Types/Measurement/MeasurementOccurrence.ts +14 -0
  294. package/Types/Measurement/MeasurementStatus.ts +34 -0
  295. package/Types/MeteredPlan/ProductType.ts +1 -0
  296. package/Types/Monitor/CriteriaFilter.ts +12 -0
  297. package/Types/Monitor/MonitorCriteriaInstance.ts +64 -0
  298. package/Types/Monitor/MonitorStep.ts +28 -0
  299. package/Types/Monitor/MonitorStepSecurityEventsMonitor.ts +100 -0
  300. package/Types/Monitor/MonitorType.ts +20 -0
  301. package/Types/Monitor/SecurityEventsMonitor/SecurityEventsMonitorResponse.ts +17 -0
  302. package/Types/NetworkDevice/NetworkDeviceLinkRuleScope.ts +51 -0
  303. package/Types/Permission.ts +399 -2
  304. package/Types/ScheduledMaintenance/ScheduledMaintenanceMeasurementAnchorType.ts +20 -0
  305. package/Types/ScheduledMaintenance/ScheduledMaintenanceStateRole.ts +16 -0
  306. package/Types/SecurityEvent/NormalizedSecurityEvent.ts +92 -0
  307. package/Types/SecurityEvent/OcsfEventClass.ts +205 -0
  308. package/Types/SecurityEvent/OcsfSeverity.ts +88 -0
  309. package/Types/SecurityEvent/SecurityEventFormat.ts +23 -0
  310. package/Types/SecurityEvent/SigmaRule.ts +70 -0
  311. package/Types/Telemetry/LlmConventions.ts +20 -1
  312. package/Types/Telemetry/LlmCostCatalog.ts +557 -0
  313. package/Types/Telemetry/ServiceType.ts +1 -0
  314. package/Types/Telemetry/TelemetryRetentionConfig.ts +5 -1
  315. package/Types/Telemetry/TelemetryType.ts +1 -0
  316. package/Types/TwoFactorAuthStatus.ts +42 -0
  317. package/Types/UserAuthenticationStatus.ts +18 -0
  318. package/UI/Components/ActionButton/ActionButtonSchema.ts +7 -0
  319. package/UI/Components/BulkUpdate/BulkArchiveActions.tsx +35 -2
  320. package/UI/Components/BulkUpdate/BulkLabelActions.tsx +34 -1
  321. package/UI/Components/BulkUpdate/BulkOwnerActions.tsx +45 -1
  322. package/UI/Components/BulkUpdate/BulkUpdateForm.tsx +3 -0
  323. package/UI/Components/Button/Button.tsx +37 -2
  324. package/UI/Components/Card/Card.tsx +6 -0
  325. package/UI/Components/CustomFields/CustomFieldsDetail.tsx +24 -1
  326. package/UI/Components/Dictionary/DictionaryFilterOperator.ts +57 -0
  327. package/UI/Components/DuplicateModel/DuplicateModel.tsx +16 -0
  328. package/UI/Components/FormModal/BasicFormModal.tsx +12 -0
  329. package/UI/Components/Forms/BasicForm.tsx +13 -1
  330. package/UI/Components/Forms/BasicModelForm.tsx +2 -1
  331. package/UI/Components/Forms/ModelForm.tsx +64 -3
  332. package/UI/Components/Forms/Utils/FormAnalyticsName.ts +39 -0
  333. package/UI/Components/List/ListRow.tsx +6 -0
  334. package/UI/Components/LogsViewer/components/ActiveFilterChips.tsx +34 -7
  335. package/UI/Components/LogsViewer/components/LogsFacetSidebar.tsx +7 -40
  336. package/UI/Components/LogsViewer/components/SavedViewsDropdown.tsx +155 -3
  337. package/UI/Components/ModelDelete/ModelDelete.tsx +20 -0
  338. package/UI/Components/ModelDetail/CardModelDetail.tsx +36 -23
  339. package/UI/Components/ModelFormModal/ModelFormModal.tsx +6 -1
  340. package/UI/Components/ModelList/ModelList.tsx +21 -2
  341. package/UI/Components/ModelList/StaticModelList.tsx +11 -0
  342. package/UI/Components/ModelTable/BaseModelTable.tsx +168 -62
  343. package/UI/Components/ModelTable/ModelTable.tsx +16 -10
  344. package/UI/Components/ModelTable/TableView.tsx +36 -4
  345. package/UI/Components/MoreMenu/MoreMenuItem.tsx +36 -4
  346. package/UI/Components/OrderedStatesList/Item.tsx +6 -0
  347. package/UI/Components/OrderedStatesList/OrderedStatesList.tsx +81 -47
  348. package/UI/Components/ResetObjectID/ResetObjectID.tsx +16 -0
  349. package/UI/Components/SavedViews/SavedViewsFacetSection.tsx +242 -0
  350. package/UI/Components/SavedViews/SavedViewsList.ts +168 -0
  351. package/UI/Components/SavedViews/SavedViewsSearchInput.tsx +46 -0
  352. package/UI/Components/SavedViews/SavedViewsShowMoreButton.tsx +44 -0
  353. package/UI/Components/Table/TableRow.tsx +12 -0
  354. package/UI/Components/TelemetryViewer/components/SavedViewsDropdown.tsx +152 -2
  355. package/UI/Types/UseComponentOutsideClick.ts +47 -0
  356. package/UI/Utils/PermissionGate.ts +277 -0
  357. package/Utils/Analytics.ts +55 -2
  358. package/Utils/Dashboard/Components/DashboardSecurityEventsFlowComponent.ts +84 -0
  359. package/Utils/Dashboard/Components/DashboardSecurityEventsListComponent.ts +110 -0
  360. package/Utils/Dashboard/Components/Index.ts +14 -0
  361. package/Utils/Measurement/MeasurementEvaluator.ts +359 -0
  362. package/Utils/Monitor/MonitorMetricType.ts +40 -0
  363. package/Utils/Monitor/MonitorSummarySnapshotUtil.ts +1 -0
  364. package/Utils/Monitor/NetworkDeviceLinkRuleUtil.ts +669 -37
  365. package/Utils/NetworkDevice/DeviceHealthStateUtil.ts +231 -0
  366. package/Utils/NetworkDiscovery/UnclaimedScanDiagnosis.ts +115 -0
  367. package/Utils/SecurityEvent/GenericNormalizer.ts +208 -0
  368. package/Utils/SecurityEvent/GoogleSecOpsAlertNormalizer.ts +206 -0
  369. package/Utils/SecurityEvent/NormalizerHelpers.ts +263 -0
  370. package/Utils/SecurityEvent/OcsfNormalizer.ts +194 -0
  371. package/Utils/SecurityEvent/SecurityEventNormalizer.ts +82 -0
  372. package/Utils/SecurityEvent/Sigma/SigmaRuleParser.ts +579 -0
  373. package/Utils/SecurityEvent/UdmNormalizer.ts +442 -0
  374. package/Utils/Telemetry/CrossSignalScope.ts +46 -9
  375. package/Utils/Telemetry/LogErrorPattern.ts +350 -0
  376. package/build/dist/Models/AnalyticsModels/Index.js +10 -0
  377. package/build/dist/Models/AnalyticsModels/Index.js.map +1 -1
  378. package/build/dist/Models/AnalyticsModels/LogCountBaseline.js +159 -0
  379. package/build/dist/Models/AnalyticsModels/LogCountBaseline.js.map +1 -0
  380. package/build/dist/Models/AnalyticsModels/SecurityEvent.js +596 -0
  381. package/build/dist/Models/AnalyticsModels/SecurityEvent.js.map +1 -0
  382. package/build/dist/Models/AnalyticsModels/Span.js +24 -1
  383. package/build/dist/Models/AnalyticsModels/Span.js.map +1 -1
  384. package/build/dist/Models/AnalyticsModels/SpanCountBaseline.js +181 -0
  385. package/build/dist/Models/AnalyticsModels/SpanCountBaseline.js.map +1 -0
  386. package/build/dist/Models/DatabaseModels/Alert.js +43 -0
  387. package/build/dist/Models/DatabaseModels/Alert.js.map +1 -1
  388. package/build/dist/Models/DatabaseModels/AlertMeasurement.js +1143 -0
  389. package/build/dist/Models/DatabaseModels/AlertMeasurement.js.map +1 -0
  390. package/build/dist/Models/DatabaseModels/AlertMeasurementValue.js +523 -0
  391. package/build/dist/Models/DatabaseModels/AlertMeasurementValue.js.map +1 -0
  392. package/build/dist/Models/DatabaseModels/AlertStateTimeline.js +9 -2
  393. package/build/dist/Models/DatabaseModels/AlertStateTimeline.js.map +1 -1
  394. package/build/dist/Models/DatabaseModels/BillingPaymentMethod.js +10 -11
  395. package/build/dist/Models/DatabaseModels/BillingPaymentMethod.js.map +1 -1
  396. package/build/dist/Models/DatabaseModels/DetectionRule.js +517 -0
  397. package/build/dist/Models/DatabaseModels/DetectionRule.js.map +1 -0
  398. package/build/dist/Models/DatabaseModels/GlobalOidc.js +21 -0
  399. package/build/dist/Models/DatabaseModels/GlobalOidc.js.map +1 -1
  400. package/build/dist/Models/DatabaseModels/GlobalSso.js +21 -0
  401. package/build/dist/Models/DatabaseModels/GlobalSso.js.map +1 -1
  402. package/build/dist/Models/DatabaseModels/GoogleSecOpsConnection.js +410 -0
  403. package/build/dist/Models/DatabaseModels/GoogleSecOpsConnection.js.map +1 -0
  404. package/build/dist/Models/DatabaseModels/Incident.js +43 -0
  405. package/build/dist/Models/DatabaseModels/Incident.js.map +1 -1
  406. package/build/dist/Models/DatabaseModels/IncidentMeasurement.js +1143 -0
  407. package/build/dist/Models/DatabaseModels/IncidentMeasurement.js.map +1 -0
  408. package/build/dist/Models/DatabaseModels/IncidentMeasurementValue.js +523 -0
  409. package/build/dist/Models/DatabaseModels/IncidentMeasurementValue.js.map +1 -0
  410. package/build/dist/Models/DatabaseModels/IncidentStateTimeline.js +9 -2
  411. package/build/dist/Models/DatabaseModels/IncidentStateTimeline.js.map +1 -1
  412. package/build/dist/Models/DatabaseModels/IncomingCallPolicyLabelRule.js +36 -0
  413. package/build/dist/Models/DatabaseModels/IncomingCallPolicyLabelRule.js.map +1 -1
  414. package/build/dist/Models/DatabaseModels/IncomingCallPolicyOwnerRule.js +42 -0
  415. package/build/dist/Models/DatabaseModels/IncomingCallPolicyOwnerRule.js.map +1 -1
  416. package/build/dist/Models/DatabaseModels/Index.js +20 -0
  417. package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
  418. package/build/dist/Models/DatabaseModels/Label.js +11 -0
  419. package/build/dist/Models/DatabaseModels/Label.js.map +1 -1
  420. package/build/dist/Models/DatabaseModels/LlmCostBudget.js +681 -0
  421. package/build/dist/Models/DatabaseModels/LlmCostBudget.js.map +1 -0
  422. package/build/dist/Models/DatabaseModels/LlmModelPrice.js +503 -0
  423. package/build/dist/Models/DatabaseModels/LlmModelPrice.js.map +1 -0
  424. package/build/dist/Models/DatabaseModels/LogSavedView.js +87 -0
  425. package/build/dist/Models/DatabaseModels/LogSavedView.js.map +1 -1
  426. package/build/dist/Models/DatabaseModels/MarketingConversion.js +237 -11
  427. package/build/dist/Models/DatabaseModels/MarketingConversion.js.map +1 -1
  428. package/build/dist/Models/DatabaseModels/MetricSavedView.js +59 -0
  429. package/build/dist/Models/DatabaseModels/MetricSavedView.js.map +1 -1
  430. package/build/dist/Models/DatabaseModels/NetworkDeviceLinkRule.js +47 -0
  431. package/build/dist/Models/DatabaseModels/NetworkDeviceLinkRule.js.map +1 -1
  432. package/build/dist/Models/DatabaseModels/OnCallDutyPolicyLabelRule.js +36 -0
  433. package/build/dist/Models/DatabaseModels/OnCallDutyPolicyLabelRule.js.map +1 -1
  434. package/build/dist/Models/DatabaseModels/OnCallDutyPolicyOwnerRule.js +42 -0
  435. package/build/dist/Models/DatabaseModels/OnCallDutyPolicyOwnerRule.js.map +1 -1
  436. package/build/dist/Models/DatabaseModels/OnCallDutyPolicyScheduleLabelRule.js +36 -0
  437. package/build/dist/Models/DatabaseModels/OnCallDutyPolicyScheduleLabelRule.js.map +1 -1
  438. package/build/dist/Models/DatabaseModels/OnCallDutyPolicyScheduleOwnerRule.js +42 -0
  439. package/build/dist/Models/DatabaseModels/OnCallDutyPolicyScheduleOwnerRule.js.map +1 -1
  440. package/build/dist/Models/DatabaseModels/Probe.js +21 -0
  441. package/build/dist/Models/DatabaseModels/Probe.js.map +1 -1
  442. package/build/dist/Models/DatabaseModels/RunbookLabelRule.js +36 -0
  443. package/build/dist/Models/DatabaseModels/RunbookLabelRule.js.map +1 -1
  444. package/build/dist/Models/DatabaseModels/RunbookOwnerRule.js +42 -0
  445. package/build/dist/Models/DatabaseModels/RunbookOwnerRule.js.map +1 -1
  446. package/build/dist/Models/DatabaseModels/ScheduledMaintenanceMeasurement.js +1133 -0
  447. package/build/dist/Models/DatabaseModels/ScheduledMaintenanceMeasurement.js.map +1 -0
  448. package/build/dist/Models/DatabaseModels/ScheduledMaintenanceMeasurementValue.js +515 -0
  449. package/build/dist/Models/DatabaseModels/ScheduledMaintenanceMeasurementValue.js.map +1 -0
  450. package/build/dist/Models/DatabaseModels/ScheduledMaintenanceStateTimeline.js +9 -2
  451. package/build/dist/Models/DatabaseModels/ScheduledMaintenanceStateTimeline.js.map +1 -1
  452. package/build/dist/Models/DatabaseModels/StatusPage.js +4 -4
  453. package/build/dist/Models/DatabaseModels/StatusPage.js.map +1 -1
  454. package/build/dist/Models/DatabaseModels/StatusPageLabelRule.js +36 -0
  455. package/build/dist/Models/DatabaseModels/StatusPageLabelRule.js.map +1 -1
  456. package/build/dist/Models/DatabaseModels/StatusPageOwnerRule.js +42 -0
  457. package/build/dist/Models/DatabaseModels/StatusPageOwnerRule.js.map +1 -1
  458. package/build/dist/Models/DatabaseModels/TableView.js +15 -0
  459. package/build/dist/Models/DatabaseModels/TableView.js.map +1 -1
  460. package/build/dist/Models/DatabaseModels/Team.js +13 -0
  461. package/build/dist/Models/DatabaseModels/Team.js.map +1 -1
  462. package/build/dist/Models/DatabaseModels/TeamMember.js +8 -0
  463. package/build/dist/Models/DatabaseModels/TeamMember.js.map +1 -1
  464. package/build/dist/Models/DatabaseModels/TraceSavedView.js +52 -0
  465. package/build/dist/Models/DatabaseModels/TraceSavedView.js.map +1 -1
  466. package/build/dist/Models/DatabaseModels/WorkflowLabelRule.js +36 -0
  467. package/build/dist/Models/DatabaseModels/WorkflowLabelRule.js.map +1 -1
  468. package/build/dist/Models/DatabaseModels/WorkflowOwnerRule.js +42 -0
  469. package/build/dist/Models/DatabaseModels/WorkflowOwnerRule.js.map +1 -1
  470. package/build/dist/Server/API/StatusPageAPI.js +25 -4
  471. package/build/dist/Server/API/StatusPageAPI.js.map +1 -1
  472. package/build/dist/Server/API/TelemetryAPI.js +136 -0
  473. package/build/dist/Server/API/TelemetryAPI.js.map +1 -1
  474. package/build/dist/Server/API/UserAPI.js +75 -2
  475. package/build/dist/Server/API/UserAPI.js.map +1 -1
  476. package/build/dist/Server/EnvironmentConfig.js +35 -1
  477. package/build/dist/Server/EnvironmentConfig.js.map +1 -1
  478. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1787800000000-AddScopeToNetworkDeviceLinkRule.js +12 -0
  479. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1787800000000-AddScopeToNetworkDeviceLinkRule.js.map +1 -0
  480. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1787900000000-AddRestrictToAttachedProjectsToGlobalSso.js +29 -0
  481. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1787900000000-AddRestrictToAttachedProjectsToGlobalSso.js.map +1 -0
  482. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1788000000000-AddDetectionRuleAndGoogleSecOpsConnection.js +36 -0
  483. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1788000000000-AddDetectionRuleAndGoogleSecOpsConnection.js.map +1 -0
  484. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1788100000000-AddMeasurements.js +162 -0
  485. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1788100000000-AddMeasurements.js.map +1 -0
  486. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1788200000000-AddLlmCostBudget.js +40 -0
  487. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1788200000000-AddLlmCostBudget.js.map +1 -0
  488. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1788300000000-AddLlmModelPrice.js +22 -0
  489. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1788300000000-AddLlmModelPrice.js.map +1 -0
  490. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1788400000000-AddMarketingConversionAttribution.js +52 -0
  491. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1788400000000-AddMarketingConversionAttribution.js.map +1 -0
  492. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1788500000000-RemoveLlmCostBudgetAlertColumns.js +38 -0
  493. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1788500000000-RemoveLlmCostBudgetAlertColumns.js.map +1 -0
  494. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +16 -0
  495. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  496. package/build/dist/Server/Middleware/IdentityRateLimit.js +491 -0
  497. package/build/dist/Server/Middleware/IdentityRateLimit.js.map +1 -0
  498. package/build/dist/Server/Middleware/SlackAuthorization.js +28 -4
  499. package/build/dist/Server/Middleware/SlackAuthorization.js.map +1 -1
  500. package/build/dist/Server/Middleware/UserAuthorization.js +197 -22
  501. package/build/dist/Server/Middleware/UserAuthorization.js.map +1 -1
  502. package/build/dist/Server/Middleware/WhatsAppAuthorization.js +32 -2
  503. package/build/dist/Server/Middleware/WhatsAppAuthorization.js.map +1 -1
  504. package/build/dist/Server/Services/AccessTokenService.js +13 -2
  505. package/build/dist/Server/Services/AccessTokenService.js.map +1 -1
  506. package/build/dist/Server/Services/AlertMeasurementService.js +250 -0
  507. package/build/dist/Server/Services/AlertMeasurementService.js.map +1 -0
  508. package/build/dist/Server/Services/AlertMeasurementValueService.js +400 -0
  509. package/build/dist/Server/Services/AlertMeasurementValueService.js.map +1 -0
  510. package/build/dist/Server/Services/AlertService.js +37 -0
  511. package/build/dist/Server/Services/AlertService.js.map +1 -1
  512. package/build/dist/Server/Services/AlertStateTimelineService.js +48 -0
  513. package/build/dist/Server/Services/AlertStateTimelineService.js.map +1 -1
  514. package/build/dist/Server/Services/DetectionRuleService.js +50 -0
  515. package/build/dist/Server/Services/DetectionRuleService.js.map +1 -0
  516. package/build/dist/Server/Services/GlobalOidcProjectService.js +105 -0
  517. package/build/dist/Server/Services/GlobalOidcProjectService.js.map +1 -1
  518. package/build/dist/Server/Services/GlobalOidcService.js +127 -0
  519. package/build/dist/Server/Services/GlobalOidcService.js.map +1 -1
  520. package/build/dist/Server/Services/GlobalSsoProjectService.js +105 -0
  521. package/build/dist/Server/Services/GlobalSsoProjectService.js.map +1 -1
  522. package/build/dist/Server/Services/GlobalSsoService.js +127 -0
  523. package/build/dist/Server/Services/GlobalSsoService.js.map +1 -1
  524. package/build/dist/Server/Services/GoogleSecOpsConnectionService.js +55 -0
  525. package/build/dist/Server/Services/GoogleSecOpsConnectionService.js.map +1 -0
  526. package/build/dist/Server/Services/IncidentMeasurementService.js +252 -0
  527. package/build/dist/Server/Services/IncidentMeasurementService.js.map +1 -0
  528. package/build/dist/Server/Services/IncidentMeasurementValueService.js +413 -0
  529. package/build/dist/Server/Services/IncidentMeasurementValueService.js.map +1 -0
  530. package/build/dist/Server/Services/IncidentService.js +41 -0
  531. package/build/dist/Server/Services/IncidentService.js.map +1 -1
  532. package/build/dist/Server/Services/IncidentStateTimelineService.js +50 -0
  533. package/build/dist/Server/Services/IncidentStateTimelineService.js.map +1 -1
  534. package/build/dist/Server/Services/Index.js +30 -0
  535. package/build/dist/Server/Services/Index.js.map +1 -1
  536. package/build/dist/Server/Services/LlmCostBudgetService.js +89 -0
  537. package/build/dist/Server/Services/LlmCostBudgetService.js.map +1 -0
  538. package/build/dist/Server/Services/LlmModelPriceService.js +163 -0
  539. package/build/dist/Server/Services/LlmModelPriceService.js.map +1 -0
  540. package/build/dist/Server/Services/LogAggregationService.js +709 -0
  541. package/build/dist/Server/Services/LogAggregationService.js.map +1 -1
  542. package/build/dist/Server/Services/LogCountBaselineService.js +112 -0
  543. package/build/dist/Server/Services/LogCountBaselineService.js.map +1 -0
  544. package/build/dist/Server/Services/MutableMetricService.js +28 -9
  545. package/build/dist/Server/Services/MutableMetricService.js.map +1 -1
  546. package/build/dist/Server/Services/ScheduledMaintenanceMeasurementService.js +254 -0
  547. package/build/dist/Server/Services/ScheduledMaintenanceMeasurementService.js.map +1 -0
  548. package/build/dist/Server/Services/ScheduledMaintenanceMeasurementValueService.js +434 -0
  549. package/build/dist/Server/Services/ScheduledMaintenanceMeasurementValueService.js.map +1 -0
  550. package/build/dist/Server/Services/ScheduledMaintenanceService.js +37 -0
  551. package/build/dist/Server/Services/ScheduledMaintenanceService.js.map +1 -1
  552. package/build/dist/Server/Services/ScheduledMaintenanceStateTimelineService.js +134 -0
  553. package/build/dist/Server/Services/ScheduledMaintenanceStateTimelineService.js.map +1 -1
  554. package/build/dist/Server/Services/SecurityEventService.js +64 -0
  555. package/build/dist/Server/Services/SecurityEventService.js.map +1 -0
  556. package/build/dist/Server/Services/SpanCountBaselineService.js +122 -0
  557. package/build/dist/Server/Services/SpanCountBaselineService.js.map +1 -0
  558. package/build/dist/Server/Services/StatusPageService.js +4 -3
  559. package/build/dist/Server/Services/StatusPageService.js.map +1 -1
  560. package/build/dist/Server/Services/TelemetryUsageBillingService.js +15 -3
  561. package/build/dist/Server/Services/TelemetryUsageBillingService.js.map +1 -1
  562. package/build/dist/Server/Services/UserEmailService.js +4 -4
  563. package/build/dist/Server/Services/UserService.js +262 -42
  564. package/build/dist/Server/Services/UserService.js.map +1 -1
  565. package/build/dist/Server/Services/UserTotpAuthService.js +0 -73
  566. package/build/dist/Server/Services/UserTotpAuthService.js.map +1 -1
  567. package/build/dist/Server/Services/UserWebAuthnService.js +1 -73
  568. package/build/dist/Server/Services/UserWebAuthnService.js.map +1 -1
  569. package/build/dist/Server/Types/Billing/MeteredPlan/AllMeteredPlans.js +13 -0
  570. package/build/dist/Server/Types/Billing/MeteredPlan/AllMeteredPlans.js.map +1 -1
  571. package/build/dist/Server/Types/Database/Permissions/TenantPermission.js +10 -0
  572. package/build/dist/Server/Types/Database/Permissions/TenantPermission.js.map +1 -1
  573. package/build/dist/Server/Types/Database/QueryHelper.js +1 -1
  574. package/build/dist/Server/Types/Database/QueryHelper.js.map +1 -1
  575. package/build/dist/Server/Utils/AI/Chat/ObservabilityChatPrompt.js +1 -1
  576. package/build/dist/Server/Utils/AI/Toolbox/Index.js +3 -0
  577. package/build/dist/Server/Utils/AI/Toolbox/Index.js.map +1 -1
  578. package/build/dist/Server/Utils/AI/Toolbox/SecurityEventTools.js +257 -0
  579. package/build/dist/Server/Utils/AI/Toolbox/SecurityEventTools.js.map +1 -0
  580. package/build/dist/Server/Utils/AnalyticsDatabase/StatementGenerator.js +13 -4
  581. package/build/dist/Server/Utils/AnalyticsDatabase/StatementGenerator.js.map +1 -1
  582. package/build/dist/Server/Utils/Attribution.js +77 -33
  583. package/build/dist/Server/Utils/Attribution.js.map +1 -1
  584. package/build/dist/Server/Utils/CronTab.js +66 -0
  585. package/build/dist/Server/Utils/CronTab.js.map +1 -1
  586. package/build/dist/Server/Utils/GlobalSsoAuthorization.js +112 -0
  587. package/build/dist/Server/Utils/GlobalSsoAuthorization.js.map +1 -0
  588. package/build/dist/Server/Utils/Marketing/ConversionUploadProvider.js +57 -4
  589. package/build/dist/Server/Utils/Marketing/ConversionUploadProvider.js.map +1 -1
  590. package/build/dist/Server/Utils/Marketing/Providers/GoogleAds.js +53 -9
  591. package/build/dist/Server/Utils/Marketing/Providers/GoogleAds.js.map +1 -1
  592. package/build/dist/Server/Utils/Marketing/Providers/LinkedIn.js +42 -18
  593. package/build/dist/Server/Utils/Marketing/Providers/LinkedIn.js.map +1 -1
  594. package/build/dist/Server/Utils/Marketing/Providers/Meta.js +43 -19
  595. package/build/dist/Server/Utils/Marketing/Providers/Meta.js.map +1 -1
  596. package/build/dist/Server/Utils/Marketing/Providers/MicrosoftAds.js +25 -12
  597. package/build/dist/Server/Utils/Marketing/Providers/MicrosoftAds.js.map +1 -1
  598. package/build/dist/Server/Utils/Marketing/Providers/Reddit.js +35 -16
  599. package/build/dist/Server/Utils/Marketing/Providers/Reddit.js.map +1 -1
  600. package/build/dist/Server/Utils/Measurement/MeasurementDefinitionValidator.js +109 -0
  601. package/build/dist/Server/Utils/Measurement/MeasurementDefinitionValidator.js.map +1 -0
  602. package/build/dist/Server/Utils/Measurement/MeasurementMetricWriter.js +131 -0
  603. package/build/dist/Server/Utils/Measurement/MeasurementMetricWriter.js.map +1 -0
  604. package/build/dist/Server/Utils/Monitor/Criteria/APIRequestCriteria.js +37 -35
  605. package/build/dist/Server/Utils/Monitor/Criteria/APIRequestCriteria.js.map +1 -1
  606. package/build/dist/Server/Utils/Monitor/Criteria/CountAnomaly.js +111 -0
  607. package/build/dist/Server/Utils/Monitor/Criteria/CountAnomaly.js.map +1 -0
  608. package/build/dist/Server/Utils/Monitor/Criteria/DnsMonitorCriteria.js +21 -25
  609. package/build/dist/Server/Utils/Monitor/Criteria/DnsMonitorCriteria.js.map +1 -1
  610. package/build/dist/Server/Utils/Monitor/Criteria/DomainMonitorCriteria.js +20 -22
  611. package/build/dist/Server/Utils/Monitor/Criteria/DomainMonitorCriteria.js.map +1 -1
  612. package/build/dist/Server/Utils/Monitor/Criteria/EvaluateOverTime.js +370 -42
  613. package/build/dist/Server/Utils/Monitor/Criteria/EvaluateOverTime.js.map +1 -1
  614. package/build/dist/Server/Utils/Monitor/Criteria/ExternalStatusPageMonitorCriteria.js +21 -25
  615. package/build/dist/Server/Utils/Monitor/Criteria/ExternalStatusPageMonitorCriteria.js.map +1 -1
  616. package/build/dist/Server/Utils/Monitor/Criteria/IncomingRequestCriteria.js +21 -25
  617. package/build/dist/Server/Utils/Monitor/Criteria/IncomingRequestCriteria.js.map +1 -1
  618. package/build/dist/Server/Utils/Monitor/Criteria/LogMonitorCriteria.js +84 -1
  619. package/build/dist/Server/Utils/Monitor/Criteria/LogMonitorCriteria.js.map +1 -1
  620. package/build/dist/Server/Utils/Monitor/Criteria/SSLMonitorCriteria.js +21 -25
  621. package/build/dist/Server/Utils/Monitor/Criteria/SSLMonitorCriteria.js.map +1 -1
  622. package/build/dist/Server/Utils/Monitor/Criteria/SecurityEventsMonitorCriteria.js +35 -0
  623. package/build/dist/Server/Utils/Monitor/Criteria/SecurityEventsMonitorCriteria.js.map +1 -0
  624. package/build/dist/Server/Utils/Monitor/Criteria/ServerMonitorCriteria.js +64 -52
  625. package/build/dist/Server/Utils/Monitor/Criteria/ServerMonitorCriteria.js.map +1 -1
  626. package/build/dist/Server/Utils/Monitor/Criteria/SnmpMonitorCriteria.js +25 -29
  627. package/build/dist/Server/Utils/Monitor/Criteria/SnmpMonitorCriteria.js.map +1 -1
  628. package/build/dist/Server/Utils/Monitor/Criteria/TraceMonitorCriteria.js +84 -1
  629. package/build/dist/Server/Utils/Monitor/Criteria/TraceMonitorCriteria.js.map +1 -1
  630. package/build/dist/Server/Utils/Monitor/MonitorCriteriaDataExtractor.js +7 -0
  631. package/build/dist/Server/Utils/Monitor/MonitorCriteriaDataExtractor.js.map +1 -1
  632. package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js +20 -0
  633. package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js.map +1 -1
  634. package/build/dist/Server/Utils/Monitor/MonitorCriteriaObservationBuilder.js +9 -0
  635. package/build/dist/Server/Utils/Monitor/MonitorCriteriaObservationBuilder.js.map +1 -1
  636. package/build/dist/Server/Utils/Monitor/MonitorResource.js +133 -23
  637. package/build/dist/Server/Utils/Monitor/MonitorResource.js.map +1 -1
  638. package/build/dist/Server/Utils/Monitor/MonitorStepResourceIdentity.js +6 -5
  639. package/build/dist/Server/Utils/Monitor/MonitorStepResourceIdentity.js.map +1 -1
  640. package/build/dist/Server/Utils/Monitor/MonitorStepsReferenceExtractor.js +1 -0
  641. package/build/dist/Server/Utils/Monitor/MonitorStepsReferenceExtractor.js.map +1 -1
  642. package/build/dist/Server/Utils/SecurityEvent/DetectionRuleEvaluator.js +404 -0
  643. package/build/dist/Server/Utils/SecurityEvent/DetectionRuleEvaluator.js.map +1 -0
  644. package/build/dist/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsClient.js +145 -0
  645. package/build/dist/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsClient.js.map +1 -0
  646. package/build/dist/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsPoller.js +176 -0
  647. package/build/dist/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsPoller.js.map +1 -0
  648. package/build/dist/Server/Utils/SecurityEvent/SecurityEventRow.js +69 -0
  649. package/build/dist/Server/Utils/SecurityEvent/SecurityEventRow.js.map +1 -0
  650. package/build/dist/Server/Utils/SecurityEvent/Sigma/SigmaClickhouseCompiler.js +493 -0
  651. package/build/dist/Server/Utils/SecurityEvent/Sigma/SigmaClickhouseCompiler.js.map +1 -0
  652. package/build/dist/Server/Utils/StatusPageContentSecurityPolicy.js +39 -0
  653. package/build/dist/Server/Utils/StatusPageContentSecurityPolicy.js.map +1 -0
  654. package/build/dist/Server/Utils/StatusPageCustomizationAccess.js +85 -0
  655. package/build/dist/Server/Utils/StatusPageCustomizationAccess.js.map +1 -0
  656. package/build/dist/Server/Utils/Telemetry/LlmCostBudgetEvaluator.js +317 -0
  657. package/build/dist/Server/Utils/Telemetry/LlmCostBudgetEvaluator.js.map +1 -0
  658. package/build/dist/Server/Utils/Telemetry/LlmSpan.js +56 -4
  659. package/build/dist/Server/Utils/Telemetry/LlmSpan.js.map +1 -1
  660. package/build/dist/Server/Utils/Telemetry/LogErrorPatternSql.js +112 -0
  661. package/build/dist/Server/Utils/Telemetry/LogErrorPatternSql.js.map +1 -0
  662. package/build/dist/Server/Utils/UserPermission/UserPermission.js +46 -1
  663. package/build/dist/Server/Utils/UserPermission/UserPermission.js.map +1 -1
  664. package/build/dist/Types/AI/AIChatTypes.js +1 -0
  665. package/build/dist/Types/AI/AIChatTypes.js.map +1 -1
  666. package/build/dist/Types/Alerts/AlertMeasurementAnchorType.js +15 -0
  667. package/build/dist/Types/Alerts/AlertMeasurementAnchorType.js.map +1 -0
  668. package/build/dist/Types/Alerts/AlertStateRole.js +12 -0
  669. package/build/dist/Types/Alerts/AlertStateRole.js.map +1 -0
  670. package/build/dist/Types/AnalyticsDatabase/AnalyticsTableName.js +16 -0
  671. package/build/dist/Types/AnalyticsDatabase/AnalyticsTableName.js.map +1 -1
  672. package/build/dist/Types/Dashboard/Chart/ChartType.js +1 -0
  673. package/build/dist/Types/Dashboard/Chart/ChartType.js.map +1 -1
  674. package/build/dist/Types/Dashboard/DashboardComponentType.js +2 -0
  675. package/build/dist/Types/Dashboard/DashboardComponentType.js.map +1 -1
  676. package/build/dist/Types/Dashboard/DashboardComponents/DashboardSecurityEventsFlowComponent.js +2 -0
  677. package/build/dist/Types/Dashboard/DashboardComponents/DashboardSecurityEventsFlowComponent.js.map +1 -0
  678. package/build/dist/Types/Dashboard/DashboardComponents/DashboardSecurityEventsListComponent.js +2 -0
  679. package/build/dist/Types/Dashboard/DashboardComponents/DashboardSecurityEventsListComponent.js.map +1 -0
  680. package/build/dist/Types/Incident/IncidentMeasurementAnchorType.js +29 -0
  681. package/build/dist/Types/Incident/IncidentMeasurementAnchorType.js.map +1 -0
  682. package/build/dist/Types/Incident/IncidentStateRole.js +15 -0
  683. package/build/dist/Types/Incident/IncidentStateRole.js.map +1 -0
  684. package/build/dist/Types/Marketing/Attribution.js +68 -0
  685. package/build/dist/Types/Marketing/Attribution.js.map +1 -0
  686. package/build/dist/Types/Marketing/MarketingConversion.js +40 -1
  687. package/build/dist/Types/Marketing/MarketingConversion.js.map +1 -1
  688. package/build/dist/Types/Measurement/MeasurementAggregationType.js +40 -0
  689. package/build/dist/Types/Measurement/MeasurementAggregationType.js.map +1 -0
  690. package/build/dist/Types/Measurement/MeasurementAnchorKind.js +22 -0
  691. package/build/dist/Types/Measurement/MeasurementAnchorKind.js.map +1 -0
  692. package/build/dist/Types/Measurement/MeasurementOccurrence.js +15 -0
  693. package/build/dist/Types/Measurement/MeasurementOccurrence.js.map +1 -0
  694. package/build/dist/Types/Measurement/MeasurementStatus.js +32 -0
  695. package/build/dist/Types/Measurement/MeasurementStatus.js.map +1 -0
  696. package/build/dist/Types/MeteredPlan/ProductType.js +1 -0
  697. package/build/dist/Types/MeteredPlan/ProductType.js.map +1 -1
  698. package/build/dist/Types/Monitor/CriteriaFilter.js +3 -0
  699. package/build/dist/Types/Monitor/CriteriaFilter.js.map +1 -1
  700. package/build/dist/Types/Monitor/MonitorCriteriaInstance.js +59 -0
  701. package/build/dist/Types/Monitor/MonitorCriteriaInstance.js.map +1 -1
  702. package/build/dist/Types/Monitor/MonitorStep.js +17 -0
  703. package/build/dist/Types/Monitor/MonitorStep.js.map +1 -1
  704. package/build/dist/Types/Monitor/MonitorStepSecurityEventsMonitor.js +64 -0
  705. package/build/dist/Types/Monitor/MonitorStepSecurityEventsMonitor.js.map +1 -0
  706. package/build/dist/Types/Monitor/MonitorType.js +19 -0
  707. package/build/dist/Types/Monitor/MonitorType.js.map +1 -1
  708. package/build/dist/Types/Monitor/SecurityEventsMonitor/SecurityEventsMonitorResponse.js +2 -0
  709. package/build/dist/Types/Monitor/SecurityEventsMonitor/SecurityEventsMonitorResponse.js.map +1 -0
  710. package/build/dist/Types/NetworkDevice/NetworkDeviceLinkRuleScope.js +46 -0
  711. package/build/dist/Types/NetworkDevice/NetworkDeviceLinkRuleScope.js.map +1 -0
  712. package/build/dist/Types/Permission.js +347 -2
  713. package/build/dist/Types/Permission.js.map +1 -1
  714. package/build/dist/Types/ScheduledMaintenance/ScheduledMaintenanceMeasurementAnchorType.js +19 -0
  715. package/build/dist/Types/ScheduledMaintenance/ScheduledMaintenanceMeasurementAnchorType.js.map +1 -0
  716. package/build/dist/Types/ScheduledMaintenance/ScheduledMaintenanceStateRole.js +17 -0
  717. package/build/dist/Types/ScheduledMaintenance/ScheduledMaintenanceStateRole.js.map +1 -0
  718. package/build/dist/Types/SecurityEvent/NormalizedSecurityEvent.js +2 -0
  719. package/build/dist/Types/SecurityEvent/NormalizedSecurityEvent.js.map +1 -0
  720. package/build/dist/Types/SecurityEvent/OcsfEventClass.js +181 -0
  721. package/build/dist/Types/SecurityEvent/OcsfEventClass.js.map +1 -0
  722. package/build/dist/Types/SecurityEvent/OcsfSeverity.js +81 -0
  723. package/build/dist/Types/SecurityEvent/OcsfSeverity.js.map +1 -0
  724. package/build/dist/Types/SecurityEvent/SecurityEventFormat.js +21 -0
  725. package/build/dist/Types/SecurityEvent/SecurityEventFormat.js.map +1 -0
  726. package/build/dist/Types/SecurityEvent/SigmaRule.js +16 -0
  727. package/build/dist/Types/SecurityEvent/SigmaRule.js.map +1 -0
  728. package/build/dist/Types/Telemetry/LlmConventions.js +19 -1
  729. package/build/dist/Types/Telemetry/LlmConventions.js.map +1 -1
  730. package/build/dist/Types/Telemetry/LlmCostCatalog.js +484 -0
  731. package/build/dist/Types/Telemetry/LlmCostCatalog.js.map +1 -0
  732. package/build/dist/Types/Telemetry/ServiceType.js +1 -0
  733. package/build/dist/Types/Telemetry/ServiceType.js.map +1 -1
  734. package/build/dist/Types/Telemetry/TelemetryRetentionConfig.js.map +1 -1
  735. package/build/dist/Types/Telemetry/TelemetryType.js +1 -0
  736. package/build/dist/Types/Telemetry/TelemetryType.js.map +1 -1
  737. package/build/dist/Types/TwoFactorAuthStatus.js +41 -0
  738. package/build/dist/Types/TwoFactorAuthStatus.js.map +1 -0
  739. package/build/dist/UI/Components/BulkUpdate/BulkArchiveActions.js +16 -2
  740. package/build/dist/UI/Components/BulkUpdate/BulkArchiveActions.js.map +1 -1
  741. package/build/dist/UI/Components/BulkUpdate/BulkLabelActions.js +15 -1
  742. package/build/dist/UI/Components/BulkUpdate/BulkLabelActions.js.map +1 -1
  743. package/build/dist/UI/Components/BulkUpdate/BulkOwnerActions.js +20 -1
  744. package/build/dist/UI/Components/BulkUpdate/BulkOwnerActions.js.map +1 -1
  745. package/build/dist/UI/Components/BulkUpdate/BulkUpdateForm.js +1 -1
  746. package/build/dist/UI/Components/BulkUpdate/BulkUpdateForm.js.map +1 -1
  747. package/build/dist/UI/Components/Button/Button.js +22 -1
  748. package/build/dist/UI/Components/Button/Button.js.map +1 -1
  749. package/build/dist/UI/Components/Card/Card.js +1 -1
  750. package/build/dist/UI/Components/Card/Card.js.map +1 -1
  751. package/build/dist/UI/Components/CustomFields/CustomFieldsDetail.js +14 -1
  752. package/build/dist/UI/Components/CustomFields/CustomFieldsDetail.js.map +1 -1
  753. package/build/dist/UI/Components/Dictionary/DictionaryFilterOperator.js +47 -0
  754. package/build/dist/UI/Components/Dictionary/DictionaryFilterOperator.js.map +1 -1
  755. package/build/dist/UI/Components/DuplicateModel/DuplicateModel.js +8 -0
  756. package/build/dist/UI/Components/DuplicateModel/DuplicateModel.js.map +1 -1
  757. package/build/dist/UI/Components/FormModal/BasicFormModal.js +2 -1
  758. package/build/dist/UI/Components/FormModal/BasicFormModal.js.map +1 -1
  759. package/build/dist/UI/Components/Forms/BasicForm.js +10 -1
  760. package/build/dist/UI/Components/Forms/BasicForm.js.map +1 -1
  761. package/build/dist/UI/Components/Forms/BasicModelForm.js +2 -1
  762. package/build/dist/UI/Components/Forms/BasicModelForm.js.map +1 -1
  763. package/build/dist/UI/Components/Forms/ModelForm.js +44 -2
  764. package/build/dist/UI/Components/Forms/ModelForm.js.map +1 -1
  765. package/build/dist/UI/Components/Forms/Utils/FormAnalyticsName.js +33 -0
  766. package/build/dist/UI/Components/Forms/Utils/FormAnalyticsName.js.map +1 -0
  767. package/build/dist/UI/Components/List/ListRow.js +4 -1
  768. package/build/dist/UI/Components/List/ListRow.js.map +1 -1
  769. package/build/dist/UI/Components/LogsViewer/components/ActiveFilterChips.js +32 -7
  770. package/build/dist/UI/Components/LogsViewer/components/ActiveFilterChips.js.map +1 -1
  771. package/build/dist/UI/Components/LogsViewer/components/LogsFacetSidebar.js +2 -17
  772. package/build/dist/UI/Components/LogsViewer/components/LogsFacetSidebar.js.map +1 -1
  773. package/build/dist/UI/Components/LogsViewer/components/SavedViewsDropdown.js +93 -4
  774. package/build/dist/UI/Components/LogsViewer/components/SavedViewsDropdown.js.map +1 -1
  775. package/build/dist/UI/Components/ModelDelete/ModelDelete.js +13 -0
  776. package/build/dist/UI/Components/ModelDelete/ModelDelete.js.map +1 -1
  777. package/build/dist/UI/Components/ModelDetail/CardModelDetail.js +27 -11
  778. package/build/dist/UI/Components/ModelDetail/CardModelDetail.js.map +1 -1
  779. package/build/dist/UI/Components/ModelFormModal/ModelFormModal.js +2 -1
  780. package/build/dist/UI/Components/ModelFormModal/ModelFormModal.js.map +1 -1
  781. package/build/dist/UI/Components/ModelList/ModelList.js +13 -2
  782. package/build/dist/UI/Components/ModelList/ModelList.js.map +1 -1
  783. package/build/dist/UI/Components/ModelList/StaticModelList.js +4 -1
  784. package/build/dist/UI/Components/ModelList/StaticModelList.js.map +1 -1
  785. package/build/dist/UI/Components/ModelTable/BaseModelTable.js +101 -40
  786. package/build/dist/UI/Components/ModelTable/BaseModelTable.js.map +1 -1
  787. package/build/dist/UI/Components/ModelTable/ModelTable.js +9 -7
  788. package/build/dist/UI/Components/ModelTable/ModelTable.js.map +1 -1
  789. package/build/dist/UI/Components/ModelTable/TableView.js +32 -4
  790. package/build/dist/UI/Components/ModelTable/TableView.js.map +1 -1
  791. package/build/dist/UI/Components/MoreMenu/MoreMenuItem.js +19 -2
  792. package/build/dist/UI/Components/MoreMenu/MoreMenuItem.js.map +1 -1
  793. package/build/dist/UI/Components/OrderedStatesList/Item.js +4 -1
  794. package/build/dist/UI/Components/OrderedStatesList/Item.js.map +1 -1
  795. package/build/dist/UI/Components/OrderedStatesList/OrderedStatesList.js +33 -32
  796. package/build/dist/UI/Components/OrderedStatesList/OrderedStatesList.js.map +1 -1
  797. package/build/dist/UI/Components/ResetObjectID/ResetObjectID.js +8 -0
  798. package/build/dist/UI/Components/ResetObjectID/ResetObjectID.js.map +1 -1
  799. package/build/dist/UI/Components/SavedViews/SavedViewsFacetSection.js +98 -0
  800. package/build/dist/UI/Components/SavedViews/SavedViewsFacetSection.js.map +1 -0
  801. package/build/dist/UI/Components/SavedViews/SavedViewsList.js +99 -0
  802. package/build/dist/UI/Components/SavedViews/SavedViewsList.js.map +1 -0
  803. package/build/dist/UI/Components/SavedViews/SavedViewsSearchInput.js +17 -0
  804. package/build/dist/UI/Components/SavedViews/SavedViewsSearchInput.js.map +1 -0
  805. package/build/dist/UI/Components/SavedViews/SavedViewsShowMoreButton.js +15 -0
  806. package/build/dist/UI/Components/SavedViews/SavedViewsShowMoreButton.js.map +1 -0
  807. package/build/dist/UI/Components/Table/TableRow.js +8 -2
  808. package/build/dist/UI/Components/Table/TableRow.js.map +1 -1
  809. package/build/dist/UI/Components/TelemetryViewer/components/SavedViewsDropdown.js +93 -4
  810. package/build/dist/UI/Components/TelemetryViewer/components/SavedViewsDropdown.js.map +1 -1
  811. package/build/dist/UI/Types/UseComponentOutsideClick.js +39 -0
  812. package/build/dist/UI/Types/UseComponentOutsideClick.js.map +1 -1
  813. package/build/dist/UI/Utils/PermissionGate.js +164 -0
  814. package/build/dist/UI/Utils/PermissionGate.js.map +1 -0
  815. package/build/dist/Utils/Analytics.js +50 -2
  816. package/build/dist/Utils/Analytics.js.map +1 -1
  817. package/build/dist/Utils/Dashboard/Components/DashboardSecurityEventsFlowComponent.js +70 -0
  818. package/build/dist/Utils/Dashboard/Components/DashboardSecurityEventsFlowComponent.js.map +1 -0
  819. package/build/dist/Utils/Dashboard/Components/DashboardSecurityEventsListComponent.js +92 -0
  820. package/build/dist/Utils/Dashboard/Components/DashboardSecurityEventsListComponent.js.map +1 -0
  821. package/build/dist/Utils/Dashboard/Components/Index.js +8 -0
  822. package/build/dist/Utils/Dashboard/Components/Index.js.map +1 -1
  823. package/build/dist/Utils/Measurement/MeasurementEvaluator.js +210 -0
  824. package/build/dist/Utils/Measurement/MeasurementEvaluator.js.map +1 -0
  825. package/build/dist/Utils/Monitor/MonitorMetricType.js +37 -0
  826. package/build/dist/Utils/Monitor/MonitorMetricType.js.map +1 -1
  827. package/build/dist/Utils/Monitor/MonitorSummarySnapshotUtil.js +1 -0
  828. package/build/dist/Utils/Monitor/MonitorSummarySnapshotUtil.js.map +1 -1
  829. package/build/dist/Utils/Monitor/NetworkDeviceLinkRuleUtil.js +359 -37
  830. package/build/dist/Utils/Monitor/NetworkDeviceLinkRuleUtil.js.map +1 -1
  831. package/build/dist/Utils/NetworkDevice/DeviceHealthStateUtil.js +108 -0
  832. package/build/dist/Utils/NetworkDevice/DeviceHealthStateUtil.js.map +1 -0
  833. package/build/dist/Utils/NetworkDiscovery/UnclaimedScanDiagnosis.js +87 -0
  834. package/build/dist/Utils/NetworkDiscovery/UnclaimedScanDiagnosis.js.map +1 -0
  835. package/build/dist/Utils/SecurityEvent/GenericNormalizer.js +176 -0
  836. package/build/dist/Utils/SecurityEvent/GenericNormalizer.js.map +1 -0
  837. package/build/dist/Utils/SecurityEvent/GoogleSecOpsAlertNormalizer.js +146 -0
  838. package/build/dist/Utils/SecurityEvent/GoogleSecOpsAlertNormalizer.js.map +1 -0
  839. package/build/dist/Utils/SecurityEvent/NormalizerHelpers.js +196 -0
  840. package/build/dist/Utils/SecurityEvent/NormalizerHelpers.js.map +1 -0
  841. package/build/dist/Utils/SecurityEvent/OcsfNormalizer.js +136 -0
  842. package/build/dist/Utils/SecurityEvent/OcsfNormalizer.js.map +1 -0
  843. package/build/dist/Utils/SecurityEvent/SecurityEventNormalizer.js +64 -0
  844. package/build/dist/Utils/SecurityEvent/SecurityEventNormalizer.js.map +1 -0
  845. package/build/dist/Utils/SecurityEvent/Sigma/SigmaRuleParser.js +388 -0
  846. package/build/dist/Utils/SecurityEvent/Sigma/SigmaRuleParser.js.map +1 -0
  847. package/build/dist/Utils/SecurityEvent/UdmNormalizer.js +328 -0
  848. package/build/dist/Utils/SecurityEvent/UdmNormalizer.js.map +1 -0
  849. package/build/dist/Utils/Telemetry/CrossSignalScope.js +29 -7
  850. package/build/dist/Utils/Telemetry/CrossSignalScope.js.map +1 -1
  851. package/build/dist/Utils/Telemetry/LogErrorPattern.js +284 -0
  852. package/build/dist/Utils/Telemetry/LogErrorPattern.js.map +1 -0
  853. package/package.json +3 -1
@@ -0,0 +1,1401 @@
1
+ import {
2
+ GLOBAL_SSO_AUTHORIZATION_CACHE_TTL_MS,
3
+ GlobalProviderAttachments,
4
+ GlobalProviderTrust,
5
+ clearGlobalSsoAuthorizationCaches,
6
+ doAttachmentsGovernProject,
7
+ globalProviderCacheKey,
8
+ globalSsoAttachmentsCache,
9
+ globalSsoProviderTrustCache,
10
+ loadAttachmentsOnce,
11
+ loadTrustOnce,
12
+ } from "../../../Server/Utils/GlobalSsoAuthorization";
13
+ import ObjectID from "../../../Types/ObjectID";
14
+ import {
15
+ afterEach,
16
+ beforeEach,
17
+ describe,
18
+ expect,
19
+ jest,
20
+ test,
21
+ } from "@jest/globals";
22
+
23
+ /*
24
+ * The stateful half of Global SSO enforcement, at the level of the pure
25
+ * helpers the two provider services are built out of.
26
+ *
27
+ * A Global SSO/OIDC token is a 30-day JWT with NO project binding. The
28
+ * stateless checks it can answer on its own (signature / expiry / Global type /
29
+ * user / pinned provider) belong to
30
+ * Common/Tests/Server/Utils/GlobalSSOToken.test.ts and
31
+ * Common/Tests/Server/Middleware/UserAuthorizationSSOProvider.test.ts, and the
32
+ * service-level wiring (getProviderTrust / doesProviderGovernProject actually
33
+ * querying Postgres, and the write hooks invalidating) belongs to
34
+ * Common/Tests/Server/Services/GlobalSsoProviderAuthorization.test.ts. None of
35
+ * that is repeated here.
36
+ *
37
+ * What this file pins down is everything those layers stand on:
38
+ *
39
+ * - doAttachmentsGovernProject, the policy decision itself. The dangerous
40
+ * case is not "attached project is allowed"; it is "rows exist but every
41
+ * one of them is disabled", which must DENY. Reading that as "no
42
+ * attachments, therefore instance-wide" would mean an admin disabling the
43
+ * last attachment WIDENS the provider to every project on the instance.
44
+ * - globalProviderCacheKey, where the dangerous case is a Global SSO row
45
+ * vouching for a Global OIDC row that happens to share its id.
46
+ * - the two caches, where the dangerous case is a cached negative
47
+ * (isUsable:false, or an empty attachment set) being mistaken for a cache
48
+ * miss - the reason the services read with an explicit `undefined` check.
49
+ * - loadTrustOnce / loadAttachmentsOnce, the in-flight de-duplication that
50
+ * collapses the multi-tenant permission fan-out (N projects, concurrently)
51
+ * from N copies of the same query down to one.
52
+ */
53
+
54
+ /*
55
+ * Minimal structural view of a jest spy - the @jest/globals and @types/jest spy
56
+ * types disagree in this repo, so annotate with just the surface used here.
57
+ * (Same workaround as Common/Tests/Server/Infrastructure/InMemoryTTLCache.test.ts.)
58
+ */
59
+ type NowSpyLike = {
60
+ mockReturnValue: (value: number) => unknown;
61
+ mockRestore: () => void;
62
+ };
63
+
64
+ function spyNow(value: number): NowSpyLike {
65
+ const spy: NowSpyLike = jest.spyOn(Date, "now") as unknown as NowSpyLike;
66
+ spy.mockReturnValue(value);
67
+ return spy;
68
+ }
69
+
70
+ interface Deferred<T> {
71
+ promise: Promise<T>;
72
+ resolve: (value: T) => void;
73
+ reject: (error: Error) => void;
74
+ }
75
+
76
+ function createDeferred<T>(): Deferred<T> {
77
+ let resolveFn!: (value: T) => void;
78
+ let rejectFn!: (error: Error) => void;
79
+
80
+ const promise: Promise<T> = new Promise<T>(
81
+ (resolve: (value: T) => void, reject: (error: Error) => void): void => {
82
+ resolveFn = resolve;
83
+ rejectFn = reject;
84
+ },
85
+ );
86
+
87
+ return { promise: promise, resolve: resolveFn, reject: rejectFn };
88
+ }
89
+
90
+ function attachments(data: {
91
+ hasAnyAttachmentRows: boolean;
92
+ enabledProjectIds: Array<string>;
93
+ }): GlobalProviderAttachments {
94
+ return {
95
+ hasAnyAttachmentRows: data.hasAnyAttachmentRows,
96
+ enabledProjectIds: data.enabledProjectIds,
97
+ };
98
+ }
99
+
100
+ const USABLE_UNRESTRICTED: GlobalProviderTrust = {
101
+ isUsable: true,
102
+ restrictToAttachedProjects: false,
103
+ };
104
+
105
+ const DISABLED_PROVIDER: GlobalProviderTrust = {
106
+ isUsable: false,
107
+ restrictToAttachedProjects: false,
108
+ };
109
+
110
+ /*
111
+ * The caches and the in-flight maps are module-level singletons shared by every
112
+ * service, so each test starts and ends from a clean slate.
113
+ */
114
+ beforeEach(() => {
115
+ clearGlobalSsoAuthorizationCaches();
116
+ });
117
+
118
+ afterEach(() => {
119
+ jest.restoreAllMocks();
120
+ clearGlobalSsoAuthorizationCaches();
121
+ });
122
+
123
+ describe("doAttachmentsGovernProject - no attachment rows at all is instance-wide", () => {
124
+ test("a provider with no attachment rows governs ANY project", () => {
125
+ const noRows: GlobalProviderAttachments = attachments({
126
+ hasAnyAttachmentRows: false,
127
+ enabledProjectIds: [],
128
+ });
129
+
130
+ const projects: Array<ObjectID> = [
131
+ ObjectID.generate(),
132
+ ObjectID.generate(),
133
+ ObjectID.generate(),
134
+ ];
135
+
136
+ for (const projectId of projects) {
137
+ expect(doAttachmentsGovernProject(noRows, projectId)).toBe(true);
138
+ }
139
+ });
140
+
141
+ test("`hasAnyAttachmentRows` is the gate, not the length of the enabled list", () => {
142
+ const projectId: ObjectID = ObjectID.generate();
143
+
144
+ /*
145
+ * The flag - not the emptiness of `enabledProjectIds` - decides whether the
146
+ * provider is in instance-wide mode. Both directions are asserted so that
147
+ * neither a blanket true nor a blanket false would satisfy this test.
148
+ */
149
+ expect(
150
+ doAttachmentsGovernProject(
151
+ attachments({ hasAnyAttachmentRows: false, enabledProjectIds: [] }),
152
+ projectId,
153
+ ),
154
+ ).toBe(true);
155
+
156
+ expect(
157
+ doAttachmentsGovernProject(
158
+ attachments({ hasAnyAttachmentRows: true, enabledProjectIds: [] }),
159
+ projectId,
160
+ ),
161
+ ).toBe(false);
162
+ });
163
+ });
164
+
165
+ describe("doAttachmentsGovernProject - explicit attachment mode", () => {
166
+ test("a project inside the enabled set is governed", () => {
167
+ const projectId: ObjectID = ObjectID.generate();
168
+
169
+ expect(
170
+ doAttachmentsGovernProject(
171
+ attachments({
172
+ hasAnyAttachmentRows: true,
173
+ enabledProjectIds: [projectId.toString()],
174
+ }),
175
+ projectId,
176
+ ),
177
+ ).toBe(true);
178
+ });
179
+
180
+ test("a project OUTSIDE the enabled set is NOT governed", () => {
181
+ const attachedProject: ObjectID = ObjectID.generate();
182
+ const otherProject: ObjectID = ObjectID.generate();
183
+
184
+ const oneAttachment: GlobalProviderAttachments = attachments({
185
+ hasAnyAttachmentRows: true,
186
+ enabledProjectIds: [attachedProject.toString()],
187
+ });
188
+
189
+ // Denied for the project that is not attached...
190
+ expect(doAttachmentsGovernProject(oneAttachment, otherProject)).toBe(false);
191
+
192
+ // ...and granted for the one that is, from the very same attachment set.
193
+ expect(doAttachmentsGovernProject(oneAttachment, attachedProject)).toBe(
194
+ true,
195
+ );
196
+
197
+ // Attaching the other project as well is all it takes to flip the deny.
198
+ expect(
199
+ doAttachmentsGovernProject(
200
+ attachments({
201
+ hasAnyAttachmentRows: true,
202
+ enabledProjectIds: [
203
+ attachedProject.toString(),
204
+ otherProject.toString(),
205
+ ],
206
+ }),
207
+ otherProject,
208
+ ),
209
+ ).toBe(true);
210
+ });
211
+
212
+ test("THE ONE THAT MATTERS: rows exist but every one is disabled DENIES, it does not widen", () => {
213
+ /*
214
+ * An admin who disables the last remaining attachment is NARROWING the
215
+ * provider. If "rows exist, none enabled" collapsed into the same answer as
216
+ * "no rows at all", that click would instead WIDEN the provider from one
217
+ * project to every project on the instance - the exact opposite of the
218
+ * intent, and silently. Disabling an attachment must never grant access.
219
+ */
220
+ const projectId: ObjectID = ObjectID.generate();
221
+
222
+ const allAttachmentsDisabled: GlobalProviderAttachments = attachments({
223
+ hasAnyAttachmentRows: true,
224
+ enabledProjectIds: [],
225
+ });
226
+
227
+ expect(doAttachmentsGovernProject(allAttachmentsDisabled, projectId)).toBe(
228
+ false,
229
+ );
230
+
231
+ // The same provider, same project, with that one attachment re-enabled.
232
+ expect(
233
+ doAttachmentsGovernProject(
234
+ attachments({
235
+ hasAnyAttachmentRows: true,
236
+ enabledProjectIds: [projectId.toString()],
237
+ }),
238
+ projectId,
239
+ ),
240
+ ).toBe(true);
241
+
242
+ /*
243
+ * And deleting the rows outright (rather than disabling them) is the
244
+ * genuinely instance-wide state, which does grant. The two states are
245
+ * reached by different admin actions and must not be conflated.
246
+ */
247
+ expect(
248
+ doAttachmentsGovernProject(
249
+ attachments({ hasAnyAttachmentRows: false, enabledProjectIds: [] }),
250
+ projectId,
251
+ ),
252
+ ).toBe(true);
253
+ });
254
+
255
+ test("a large attachment set is matched at the start, middle and end", () => {
256
+ const target: ObjectID = ObjectID.generate();
257
+
258
+ const filler: Array<string> = [];
259
+ for (let index: number = 0; index < 50; index++) {
260
+ filler.push(ObjectID.generate().toString());
261
+ }
262
+
263
+ const atStart: GlobalProviderAttachments = attachments({
264
+ hasAnyAttachmentRows: true,
265
+ enabledProjectIds: [target.toString(), ...filler],
266
+ });
267
+ const atMiddle: GlobalProviderAttachments = attachments({
268
+ hasAnyAttachmentRows: true,
269
+ enabledProjectIds: [
270
+ ...filler.slice(0, 25),
271
+ target.toString(),
272
+ ...filler.slice(25),
273
+ ],
274
+ });
275
+ const atEnd: GlobalProviderAttachments = attachments({
276
+ hasAnyAttachmentRows: true,
277
+ enabledProjectIds: [...filler, target.toString()],
278
+ });
279
+
280
+ expect(doAttachmentsGovernProject(atStart, target)).toBe(true);
281
+ expect(doAttachmentsGovernProject(atMiddle, target)).toBe(true);
282
+ expect(doAttachmentsGovernProject(atEnd, target)).toBe(true);
283
+
284
+ // A set of the same size that simply does not contain the target denies.
285
+ expect(
286
+ doAttachmentsGovernProject(
287
+ attachments({ hasAnyAttachmentRows: true, enabledProjectIds: filler }),
288
+ target,
289
+ ),
290
+ ).toBe(false);
291
+ });
292
+
293
+ test("ids are compared exactly - prefixes, suffixes and case variants do not match", () => {
294
+ const projectId: ObjectID = ObjectID.generate();
295
+ const id: string = projectId.toString();
296
+
297
+ const nearMisses: Array<string> = [
298
+ id.slice(0, -1), // one character short
299
+ `${id}0`, // one character too long
300
+ id.toUpperCase(), // same uuid, different case
301
+ ` ${id}`, // leading whitespace
302
+ `${id} `, // trailing whitespace
303
+ id.replace(/-/g, ""), // dashes stripped
304
+ ];
305
+
306
+ for (const nearMiss of nearMisses) {
307
+ expect(
308
+ doAttachmentsGovernProject(
309
+ attachments({
310
+ hasAnyAttachmentRows: true,
311
+ enabledProjectIds: [nearMiss],
312
+ }),
313
+ projectId,
314
+ ),
315
+ ).toBe(false);
316
+ }
317
+
318
+ // All of the near misses together still deny...
319
+ expect(
320
+ doAttachmentsGovernProject(
321
+ attachments({
322
+ hasAnyAttachmentRows: true,
323
+ enabledProjectIds: nearMisses,
324
+ }),
325
+ projectId,
326
+ ),
327
+ ).toBe(false);
328
+
329
+ // ...and adding the exact id to that same list grants.
330
+ expect(
331
+ doAttachmentsGovernProject(
332
+ attachments({
333
+ hasAnyAttachmentRows: true,
334
+ enabledProjectIds: [...nearMisses, id],
335
+ }),
336
+ projectId,
337
+ ),
338
+ ).toBe(true);
339
+ });
340
+
341
+ test("substring relationships between short ids never match", () => {
342
+ const projectId: ObjectID = new ObjectID("abc");
343
+
344
+ expect(
345
+ doAttachmentsGovernProject(
346
+ attachments({
347
+ hasAnyAttachmentRows: true,
348
+ enabledProjectIds: ["abcd"],
349
+ }),
350
+ projectId,
351
+ ),
352
+ ).toBe(false);
353
+ expect(
354
+ doAttachmentsGovernProject(
355
+ attachments({
356
+ hasAnyAttachmentRows: true,
357
+ enabledProjectIds: ["zabc"],
358
+ }),
359
+ projectId,
360
+ ),
361
+ ).toBe(false);
362
+ expect(
363
+ doAttachmentsGovernProject(
364
+ attachments({ hasAnyAttachmentRows: true, enabledProjectIds: ["abc"] }),
365
+ projectId,
366
+ ),
367
+ ).toBe(true);
368
+ });
369
+
370
+ test("the decision does not mutate the attachment set it was handed", () => {
371
+ /*
372
+ * The cached GlobalProviderAttachments object is shared by every concurrent
373
+ * request for that provider, so a decision that sorted or spliced the array
374
+ * in place would corrupt the answer for everyone else.
375
+ */
376
+ const target: ObjectID = ObjectID.generate();
377
+ const enabledProjectIds: Array<string> = [
378
+ ObjectID.generate().toString(),
379
+ target.toString(),
380
+ ObjectID.generate().toString(),
381
+ ];
382
+ const snapshot: Array<string> = [...enabledProjectIds];
383
+
384
+ const shared: GlobalProviderAttachments = attachments({
385
+ hasAnyAttachmentRows: true,
386
+ enabledProjectIds: enabledProjectIds,
387
+ });
388
+
389
+ expect(doAttachmentsGovernProject(shared, target)).toBe(true);
390
+ expect(doAttachmentsGovernProject(shared, ObjectID.generate())).toBe(false);
391
+ expect(doAttachmentsGovernProject(shared, target)).toBe(true);
392
+
393
+ expect(shared.enabledProjectIds).toEqual(snapshot);
394
+ expect(shared.hasAnyAttachmentRows).toBe(true);
395
+ });
396
+ });
397
+
398
+ describe("doAttachmentsGovernProject - agreement with the login router's isDefaultAllMode", () => {
399
+ /*
400
+ * App/FeatureSet/Identity/API/GlobalSSO.ts loads the attachments with
401
+ * `findBy({ globalSsoId, isEnabled: true })` and then computes
402
+ * `const isDefaultAllMode: boolean = attachments.length === 0;`.
403
+ *
404
+ * These helpers reproduce both readings from the same raw rows so the two can
405
+ * be compared directly.
406
+ */
407
+ interface AttachmentRow {
408
+ projectId: string;
409
+ isEnabled: boolean;
410
+ }
411
+
412
+ function routerIsDefaultAllMode(rows: Array<AttachmentRow>): boolean {
413
+ return (
414
+ rows.filter((row: AttachmentRow) => {
415
+ return row.isEnabled;
416
+ }).length === 0
417
+ );
418
+ }
419
+
420
+ function toAttachments(
421
+ rows: Array<AttachmentRow>,
422
+ ): GlobalProviderAttachments {
423
+ // Mirrors GlobalSsoProjectService.doesProviderGovernProject's loader.
424
+ return {
425
+ hasAnyAttachmentRows: rows.length > 0,
426
+ enabledProjectIds: rows
427
+ .filter((row: AttachmentRow) => {
428
+ return row.isEnabled;
429
+ })
430
+ .map((row: AttachmentRow) => {
431
+ return row.projectId;
432
+ }),
433
+ };
434
+ }
435
+
436
+ test("no rows at all: both layers read it as instance-wide", () => {
437
+ const rows: Array<AttachmentRow> = [];
438
+
439
+ expect(routerIsDefaultAllMode(rows)).toBe(true);
440
+ expect(
441
+ doAttachmentsGovernProject(toAttachments(rows), ObjectID.generate()),
442
+ ).toBe(true);
443
+ });
444
+
445
+ test("an enabled row: both layers leave instance-wide mode", () => {
446
+ const attachedProject: ObjectID = ObjectID.generate();
447
+ const rows: Array<AttachmentRow> = [
448
+ { projectId: attachedProject.toString(), isEnabled: true },
449
+ ];
450
+
451
+ expect(routerIsDefaultAllMode(rows)).toBe(false);
452
+ expect(
453
+ doAttachmentsGovernProject(toAttachments(rows), attachedProject),
454
+ ).toBe(true);
455
+ expect(
456
+ doAttachmentsGovernProject(toAttachments(rows), ObjectID.generate()),
457
+ ).toBe(false);
458
+ });
459
+
460
+ test("rows that exist but are all disabled: the router widens, enforcement narrows - deliberately", () => {
461
+ /*
462
+ * The one place the two readings diverge, and it is intentional.
463
+ *
464
+ * The router's `isDefaultAllMode` only ever REMOVES capability: in
465
+ * default-all mode it disables SSO sign-up and skips auto-provisioning,
466
+ * because there is no attachment telling it which project or team to place
467
+ * a new user in. It never grants project access. This module's answer IS an
468
+ * access decision, so the same state has to deny - otherwise disabling the
469
+ * last attachment would hand the provider every project on the instance.
470
+ */
471
+ const attachedProject: ObjectID = ObjectID.generate();
472
+ const rows: Array<AttachmentRow> = [
473
+ { projectId: attachedProject.toString(), isEnabled: false },
474
+ ];
475
+
476
+ expect(routerIsDefaultAllMode(rows)).toBe(true);
477
+ expect(
478
+ doAttachmentsGovernProject(toAttachments(rows), attachedProject),
479
+ ).toBe(false);
480
+
481
+ // Re-enabling that same row is what grants access back.
482
+ expect(
483
+ doAttachmentsGovernProject(
484
+ toAttachments([
485
+ { projectId: attachedProject.toString(), isEnabled: true },
486
+ ]),
487
+ attachedProject,
488
+ ),
489
+ ).toBe(true);
490
+ });
491
+ });
492
+
493
+ describe("globalProviderCacheKey", () => {
494
+ test("the same provider id under 'sso' and 'oidc' produces DIFFERENT keys", () => {
495
+ const providerId: ObjectID = ObjectID.generate();
496
+
497
+ const ssoKey: string = globalProviderCacheKey("sso", providerId);
498
+ const oidcKey: string = globalProviderCacheKey("oidc", providerId);
499
+
500
+ expect(ssoKey).not.toBe(oidcKey);
501
+ expect(ssoKey.startsWith("sso:")).toBe(true);
502
+ expect(oidcKey.startsWith("oidc:")).toBe(true);
503
+ expect(ssoKey).toContain(providerId.toString());
504
+ expect(oidcKey).toContain(providerId.toString());
505
+ });
506
+
507
+ test("the key is stable for the same kind and id", () => {
508
+ const id: string = ObjectID.generate().toString();
509
+
510
+ // Two distinct ObjectID instances carrying the same id must agree.
511
+ expect(globalProviderCacheKey("sso", new ObjectID(id))).toBe(
512
+ globalProviderCacheKey("sso", new ObjectID(id)),
513
+ );
514
+ expect(globalProviderCacheKey("oidc", new ObjectID(id))).toBe(
515
+ globalProviderCacheKey("oidc", new ObjectID(id)),
516
+ );
517
+ });
518
+
519
+ test("different provider ids of the same kind produce different keys", () => {
520
+ const first: ObjectID = ObjectID.generate();
521
+ const second: ObjectID = ObjectID.generate();
522
+
523
+ expect(globalProviderCacheKey("sso", first)).not.toBe(
524
+ globalProviderCacheKey("sso", second),
525
+ );
526
+ expect(globalProviderCacheKey("oidc", first)).not.toBe(
527
+ globalProviderCacheKey("oidc", second),
528
+ );
529
+ });
530
+
531
+ test("no crafted id can make an OIDC key collide with an SSO key", () => {
532
+ /*
533
+ * The namespace prefix is what stops a Global OIDC row from vouching for a
534
+ * Global SSO row. Ids that look like a namespace of their own must not be
535
+ * able to forge the other side's key.
536
+ */
537
+ const crafted: Array<string> = [
538
+ "oidc:11111111-1111-1111-1111-111111111111",
539
+ "sso:11111111-1111-1111-1111-111111111111",
540
+ ":",
541
+ "",
542
+ ];
543
+
544
+ const ssoKeys: Array<string> = crafted.map((id: string) => {
545
+ return globalProviderCacheKey("sso", new ObjectID(id));
546
+ });
547
+ const oidcKeys: Array<string> = crafted.map((id: string) => {
548
+ return globalProviderCacheKey("oidc", new ObjectID(id));
549
+ });
550
+
551
+ for (const ssoKey of ssoKeys) {
552
+ expect(oidcKeys).not.toContain(ssoKey);
553
+ }
554
+ });
555
+
556
+ test("a trust answer stored under one namespace is invisible to the other", () => {
557
+ const providerId: ObjectID = ObjectID.generate();
558
+ const ssoKey: string = globalProviderCacheKey("sso", providerId);
559
+ const oidcKey: string = globalProviderCacheKey("oidc", providerId);
560
+
561
+ globalSsoProviderTrustCache.set(
562
+ ssoKey,
563
+ USABLE_UNRESTRICTED,
564
+ GLOBAL_SSO_AUTHORIZATION_CACHE_TTL_MS,
565
+ );
566
+
567
+ // The enabled SAML provider does not make an OIDC provider of the same id usable.
568
+ expect(globalSsoProviderTrustCache.get(oidcKey)).toBeUndefined();
569
+ expect(globalSsoProviderTrustCache.get(ssoKey)).toEqual(
570
+ USABLE_UNRESTRICTED,
571
+ );
572
+
573
+ // And the OIDC side can hold the opposite answer at the same time.
574
+ globalSsoProviderTrustCache.set(
575
+ oidcKey,
576
+ DISABLED_PROVIDER,
577
+ GLOBAL_SSO_AUTHORIZATION_CACHE_TTL_MS,
578
+ );
579
+
580
+ expect(globalSsoProviderTrustCache.get(ssoKey)?.isUsable).toBe(true);
581
+ expect(globalSsoProviderTrustCache.get(oidcKey)?.isUsable).toBe(false);
582
+ });
583
+
584
+ test("an attachment set stored under one namespace is invisible to the other", () => {
585
+ const providerId: ObjectID = ObjectID.generate();
586
+ const projectId: ObjectID = ObjectID.generate();
587
+ const ssoKey: string = globalProviderCacheKey("sso", providerId);
588
+ const oidcKey: string = globalProviderCacheKey("oidc", providerId);
589
+
590
+ globalSsoAttachmentsCache.set(
591
+ ssoKey,
592
+ attachments({
593
+ hasAnyAttachmentRows: true,
594
+ enabledProjectIds: [projectId.toString()],
595
+ }),
596
+ GLOBAL_SSO_AUTHORIZATION_CACHE_TTL_MS,
597
+ );
598
+
599
+ expect(globalSsoAttachmentsCache.get(oidcKey)).toBeUndefined();
600
+
601
+ const cached: GlobalProviderAttachments | undefined =
602
+ globalSsoAttachmentsCache.get(ssoKey);
603
+ expect(cached).toBeDefined();
604
+ expect(doAttachmentsGovernProject(cached!, projectId)).toBe(true);
605
+ });
606
+ });
607
+
608
+ describe("the caches - round trip", () => {
609
+ test("the trust cache round-trips a value", () => {
610
+ const key: string = globalProviderCacheKey("sso", ObjectID.generate());
611
+ const trust: GlobalProviderTrust = {
612
+ isUsable: true,
613
+ restrictToAttachedProjects: true,
614
+ };
615
+
616
+ expect(globalSsoProviderTrustCache.get(key)).toBeUndefined();
617
+
618
+ globalSsoProviderTrustCache.set(
619
+ key,
620
+ trust,
621
+ GLOBAL_SSO_AUTHORIZATION_CACHE_TTL_MS,
622
+ );
623
+
624
+ expect(globalSsoProviderTrustCache.get(key)).toEqual(trust);
625
+ expect(
626
+ globalSsoProviderTrustCache.get(key)?.restrictToAttachedProjects,
627
+ ).toBe(true);
628
+ });
629
+
630
+ test("the attachments cache round-trips a value", () => {
631
+ const key: string = globalProviderCacheKey("oidc", ObjectID.generate());
632
+ const attached: ObjectID = ObjectID.generate();
633
+ const value: GlobalProviderAttachments = attachments({
634
+ hasAnyAttachmentRows: true,
635
+ enabledProjectIds: [attached.toString()],
636
+ });
637
+
638
+ expect(globalSsoAttachmentsCache.get(key)).toBeUndefined();
639
+
640
+ globalSsoAttachmentsCache.set(
641
+ key,
642
+ value,
643
+ GLOBAL_SSO_AUTHORIZATION_CACHE_TTL_MS,
644
+ );
645
+
646
+ const cached: GlobalProviderAttachments | undefined =
647
+ globalSsoAttachmentsCache.get(key);
648
+
649
+ expect(cached).toEqual(value);
650
+ expect(doAttachmentsGovernProject(cached!, attached)).toBe(true);
651
+ expect(doAttachmentsGovernProject(cached!, ObjectID.generate())).toBe(
652
+ false,
653
+ );
654
+ });
655
+
656
+ test("the two caches are separate stores - the same key in each holds its own value", () => {
657
+ const key: string = globalProviderCacheKey("sso", ObjectID.generate());
658
+
659
+ globalSsoProviderTrustCache.set(
660
+ key,
661
+ USABLE_UNRESTRICTED,
662
+ GLOBAL_SSO_AUTHORIZATION_CACHE_TTL_MS,
663
+ );
664
+
665
+ expect(globalSsoAttachmentsCache.get(key)).toBeUndefined();
666
+
667
+ globalSsoAttachmentsCache.set(
668
+ key,
669
+ attachments({ hasAnyAttachmentRows: false, enabledProjectIds: [] }),
670
+ GLOBAL_SSO_AUTHORIZATION_CACHE_TTL_MS,
671
+ );
672
+
673
+ expect(globalSsoProviderTrustCache.get(key)).toEqual(USABLE_UNRESTRICTED);
674
+ expect(globalSsoAttachmentsCache.get(key)?.hasAnyAttachmentRows).toBe(
675
+ false,
676
+ );
677
+ });
678
+ });
679
+
680
+ describe("the caches - a cached negative is a HIT, not a miss", () => {
681
+ test("a cached isUsable:false is served from cache rather than re-queried", () => {
682
+ /*
683
+ * The services read with `if (cached !== undefined) { return cached; }`.
684
+ * A truthiness read of the interesting FIELD - `if (cached?.isUsable)` -
685
+ * would treat a cached "this provider is disabled" as a cache miss and send
686
+ * a query to Postgres on every single request from every still-signed-in
687
+ * holder of that provider's 30-day tokens. Exactly the population that is
688
+ * largest right after an admin disables a provider.
689
+ */
690
+ const disabledKey: string = globalProviderCacheKey(
691
+ "sso",
692
+ ObjectID.generate(),
693
+ );
694
+ const neverLookedUpKey: string = globalProviderCacheKey(
695
+ "sso",
696
+ ObjectID.generate(),
697
+ );
698
+
699
+ globalSsoProviderTrustCache.set(
700
+ disabledKey,
701
+ DISABLED_PROVIDER,
702
+ GLOBAL_SSO_AUTHORIZATION_CACHE_TTL_MS,
703
+ );
704
+
705
+ const cachedNegative: GlobalProviderTrust | undefined =
706
+ globalSsoProviderTrustCache.get(disabledKey);
707
+
708
+ // The cached negative is present and says "no".
709
+ expect(cachedNegative).toBeDefined();
710
+ expect(cachedNegative).not.toBeUndefined();
711
+ expect(cachedNegative?.isUsable).toBe(false);
712
+ expect(globalSsoProviderTrustCache.has(disabledKey)).toBe(true);
713
+
714
+ // A key that was genuinely never looked up is the other answer entirely.
715
+ expect(globalSsoProviderTrustCache.get(neverLookedUpKey)).toBeUndefined();
716
+ expect(globalSsoProviderTrustCache.has(neverLookedUpKey)).toBe(false);
717
+
718
+ /*
719
+ * The distinction the explicit undefined check preserves, spelled out: the
720
+ * correct read sees a hit for the disabled provider, the truthiness-on-the-
721
+ * field read does not.
722
+ */
723
+ const correctReadIsAHit: boolean = cachedNegative !== undefined;
724
+ const truthinessOnFieldIsAHit: boolean = Boolean(cachedNegative?.isUsable);
725
+
726
+ expect(correctReadIsAHit).toBe(true);
727
+ expect(truthinessOnFieldIsAHit).toBe(false);
728
+ });
729
+
730
+ test("a cached EMPTY attachment set is a hit too - default-all does not re-query", () => {
731
+ const key: string = globalProviderCacheKey("oidc", ObjectID.generate());
732
+
733
+ const instanceWide: GlobalProviderAttachments = attachments({
734
+ hasAnyAttachmentRows: false,
735
+ enabledProjectIds: [],
736
+ });
737
+
738
+ globalSsoAttachmentsCache.set(
739
+ key,
740
+ instanceWide,
741
+ GLOBAL_SSO_AUTHORIZATION_CACHE_TTL_MS,
742
+ );
743
+
744
+ const cached: GlobalProviderAttachments | undefined =
745
+ globalSsoAttachmentsCache.get(key);
746
+
747
+ expect(cached).toBeDefined();
748
+ expect(cached?.enabledProjectIds).toEqual([]);
749
+ expect(globalSsoAttachmentsCache.has(key)).toBe(true);
750
+
751
+ // An empty list is falsy-adjacent but must still count as an answer.
752
+ const correctReadIsAHit: boolean = cached !== undefined;
753
+ const truthinessOnLengthIsAHit: boolean = Boolean(
754
+ cached?.enabledProjectIds.length,
755
+ );
756
+
757
+ expect(correctReadIsAHit).toBe(true);
758
+ expect(truthinessOnLengthIsAHit).toBe(false);
759
+ });
760
+ });
761
+
762
+ describe("the caches - TTL", () => {
763
+ test("a trust entry survives to its TTL boundary and is gone after it", () => {
764
+ const t0: number = 1_700_000_000_000;
765
+ const nowSpy: NowSpyLike = spyNow(t0);
766
+ const key: string = globalProviderCacheKey("sso", ObjectID.generate());
767
+
768
+ globalSsoProviderTrustCache.set(
769
+ key,
770
+ USABLE_UNRESTRICTED,
771
+ GLOBAL_SSO_AUTHORIZATION_CACHE_TTL_MS,
772
+ );
773
+
774
+ expect(globalSsoProviderTrustCache.get(key)).toEqual(USABLE_UNRESTRICTED);
775
+
776
+ nowSpy.mockReturnValue(t0 + GLOBAL_SSO_AUTHORIZATION_CACHE_TTL_MS - 1);
777
+ expect(globalSsoProviderTrustCache.get(key)).toEqual(USABLE_UNRESTRICTED);
778
+
779
+ nowSpy.mockReturnValue(t0 + GLOBAL_SSO_AUTHORIZATION_CACHE_TTL_MS);
780
+ expect(globalSsoProviderTrustCache.get(key)).toEqual(USABLE_UNRESTRICTED);
781
+
782
+ nowSpy.mockReturnValue(t0 + GLOBAL_SSO_AUTHORIZATION_CACHE_TTL_MS + 1);
783
+ expect(globalSsoProviderTrustCache.get(key)).toBeUndefined();
784
+ });
785
+
786
+ test("an expired trust entry is a miss, not a stale negative or a stale positive", () => {
787
+ const t0: number = 1_700_000_000_000;
788
+ const nowSpy: NowSpyLike = spyNow(t0);
789
+ const key: string = globalProviderCacheKey("sso", ObjectID.generate());
790
+
791
+ globalSsoProviderTrustCache.set(
792
+ key,
793
+ DISABLED_PROVIDER,
794
+ GLOBAL_SSO_AUTHORIZATION_CACHE_TTL_MS,
795
+ );
796
+
797
+ expect(globalSsoProviderTrustCache.has(key)).toBe(true);
798
+
799
+ nowSpy.mockReturnValue(t0 + GLOBAL_SSO_AUTHORIZATION_CACHE_TTL_MS + 1);
800
+
801
+ expect(globalSsoProviderTrustCache.get(key)).toBeUndefined();
802
+ expect(globalSsoProviderTrustCache.has(key)).toBe(false);
803
+
804
+ // Re-populating at the later clock gives the entry a fresh full TTL.
805
+ globalSsoProviderTrustCache.set(
806
+ key,
807
+ USABLE_UNRESTRICTED,
808
+ GLOBAL_SSO_AUTHORIZATION_CACHE_TTL_MS,
809
+ );
810
+
811
+ expect(globalSsoProviderTrustCache.get(key)).toEqual(USABLE_UNRESTRICTED);
812
+ });
813
+
814
+ test("an attachment entry expires on the same 60s TTL", () => {
815
+ const t0: number = 1_700_000_000_000;
816
+ const nowSpy: NowSpyLike = spyNow(t0);
817
+ const key: string = globalProviderCacheKey("oidc", ObjectID.generate());
818
+ const projectId: ObjectID = ObjectID.generate();
819
+
820
+ globalSsoAttachmentsCache.set(
821
+ key,
822
+ attachments({
823
+ hasAnyAttachmentRows: true,
824
+ enabledProjectIds: [projectId.toString()],
825
+ }),
826
+ GLOBAL_SSO_AUTHORIZATION_CACHE_TTL_MS,
827
+ );
828
+
829
+ expect(globalSsoAttachmentsCache.get(key)).toBeDefined();
830
+
831
+ nowSpy.mockReturnValue(t0 + GLOBAL_SSO_AUTHORIZATION_CACHE_TTL_MS);
832
+ expect(globalSsoAttachmentsCache.get(key)).toBeDefined();
833
+
834
+ nowSpy.mockReturnValue(t0 + GLOBAL_SSO_AUTHORIZATION_CACHE_TTL_MS + 1);
835
+ expect(globalSsoAttachmentsCache.get(key)).toBeUndefined();
836
+ });
837
+ });
838
+
839
+ describe("clearGlobalSsoAuthorizationCaches", () => {
840
+ test("it empties BOTH caches", () => {
841
+ const ssoKey: string = globalProviderCacheKey("sso", ObjectID.generate());
842
+ const oidcKey: string = globalProviderCacheKey("oidc", ObjectID.generate());
843
+
844
+ globalSsoProviderTrustCache.set(
845
+ ssoKey,
846
+ USABLE_UNRESTRICTED,
847
+ GLOBAL_SSO_AUTHORIZATION_CACHE_TTL_MS,
848
+ );
849
+ globalSsoProviderTrustCache.set(
850
+ oidcKey,
851
+ DISABLED_PROVIDER,
852
+ GLOBAL_SSO_AUTHORIZATION_CACHE_TTL_MS,
853
+ );
854
+ globalSsoAttachmentsCache.set(
855
+ ssoKey,
856
+ attachments({ hasAnyAttachmentRows: false, enabledProjectIds: [] }),
857
+ GLOBAL_SSO_AUTHORIZATION_CACHE_TTL_MS,
858
+ );
859
+ globalSsoAttachmentsCache.set(
860
+ oidcKey,
861
+ attachments({ hasAnyAttachmentRows: true, enabledProjectIds: [] }),
862
+ GLOBAL_SSO_AUTHORIZATION_CACHE_TTL_MS,
863
+ );
864
+
865
+ expect(globalSsoProviderTrustCache.size()).toBe(2);
866
+ expect(globalSsoAttachmentsCache.size()).toBe(2);
867
+
868
+ clearGlobalSsoAuthorizationCaches();
869
+
870
+ expect(globalSsoProviderTrustCache.size()).toBe(0);
871
+ expect(globalSsoAttachmentsCache.size()).toBe(0);
872
+ expect(globalSsoProviderTrustCache.get(ssoKey)).toBeUndefined();
873
+ expect(globalSsoProviderTrustCache.get(oidcKey)).toBeUndefined();
874
+ expect(globalSsoAttachmentsCache.get(ssoKey)).toBeUndefined();
875
+ expect(globalSsoAttachmentsCache.get(oidcKey)).toBeUndefined();
876
+ });
877
+
878
+ test("clearing twice is harmless, and the caches are usable again afterwards", () => {
879
+ const key: string = globalProviderCacheKey("sso", ObjectID.generate());
880
+
881
+ clearGlobalSsoAuthorizationCaches();
882
+ clearGlobalSsoAuthorizationCaches();
883
+
884
+ globalSsoProviderTrustCache.set(
885
+ key,
886
+ USABLE_UNRESTRICTED,
887
+ GLOBAL_SSO_AUTHORIZATION_CACHE_TTL_MS,
888
+ );
889
+
890
+ expect(globalSsoProviderTrustCache.get(key)).toEqual(USABLE_UNRESTRICTED);
891
+ });
892
+ });
893
+
894
+ describe("loadTrustOnce / loadAttachmentsOnce - in-flight de-duplication", () => {
895
+ test("N concurrent callers for the SAME key run the loader ONCE and all get the same value", async () => {
896
+ /*
897
+ * This is the multi-tenant fan-out: the permission path asks about every
898
+ * project the user belongs to concurrently, and on a cold cache each of
899
+ * those asks would otherwise issue its own copy of the same provider query.
900
+ */
901
+ const key: string = globalProviderCacheKey("sso", ObjectID.generate());
902
+ const gate: Deferred<GlobalProviderTrust> =
903
+ createDeferred<GlobalProviderTrust>();
904
+
905
+ let loaderCalls: number = 0;
906
+
907
+ const load: () => Promise<GlobalProviderTrust> =
908
+ (): Promise<GlobalProviderTrust> => {
909
+ loaderCalls++;
910
+ return gate.promise;
911
+ };
912
+
913
+ const pending: Array<Promise<GlobalProviderTrust>> = [];
914
+ for (let index: number = 0; index < 50; index++) {
915
+ pending.push(loadTrustOnce(key, load));
916
+ }
917
+
918
+ // Fifty callers, one query.
919
+ expect(pending).toHaveLength(50);
920
+ expect(loaderCalls).toBe(1);
921
+
922
+ gate.resolve(USABLE_UNRESTRICTED);
923
+
924
+ const results: Array<GlobalProviderTrust> = await Promise.all(pending);
925
+
926
+ /*
927
+ * Every caller resolves with the very same object, not merely an equal one:
928
+ * they are all reading the single shared load rather than fifty of their
929
+ * own.
930
+ */
931
+ expect(results).toHaveLength(50);
932
+ for (const result of results) {
933
+ expect(result).toBe(USABLE_UNRESTRICTED);
934
+ }
935
+ expect(loaderCalls).toBe(1);
936
+ });
937
+
938
+ test("without the de-duplication the same fan-out would issue one load per caller", () => {
939
+ /*
940
+ * The control for the test above: the counting harness itself is capable of
941
+ * seeing N loads, so "loaderCalls === 1" there is a real observation and not
942
+ * an artefact of how the loader is written.
943
+ */
944
+ const key: string = globalProviderCacheKey("sso", ObjectID.generate());
945
+ const gate: Deferred<GlobalProviderTrust> =
946
+ createDeferred<GlobalProviderTrust>();
947
+
948
+ let loaderCalls: number = 0;
949
+
950
+ const load: () => Promise<GlobalProviderTrust> =
951
+ (): Promise<GlobalProviderTrust> => {
952
+ loaderCalls++;
953
+ return gate.promise;
954
+ };
955
+
956
+ for (let index: number = 0; index < 50; index++) {
957
+ // Calling the loader directly - i.e. skipping loadTrustOnce entirely.
958
+ void load();
959
+ }
960
+
961
+ expect(loaderCalls).toBe(50);
962
+
963
+ // And through loadTrustOnce, the same fifty asks cost one load.
964
+ loaderCalls = 0;
965
+ for (let index: number = 0; index < 50; index++) {
966
+ void loadTrustOnce(key, load);
967
+ }
968
+
969
+ expect(loaderCalls).toBe(1);
970
+
971
+ gate.resolve(USABLE_UNRESTRICTED);
972
+ });
973
+
974
+ test("concurrent callers for DIFFERENT keys each run their own loader", async () => {
975
+ const firstKey: string = globalProviderCacheKey("sso", ObjectID.generate());
976
+ const secondKey: string = globalProviderCacheKey(
977
+ "sso",
978
+ ObjectID.generate(),
979
+ );
980
+ // Same provider id, other namespace: still a different key, still its own loader.
981
+ const sharedId: ObjectID = ObjectID.generate();
982
+ const ssoKey: string = globalProviderCacheKey("sso", sharedId);
983
+ const oidcKey: string = globalProviderCacheKey("oidc", sharedId);
984
+
985
+ const calls: Array<string> = [];
986
+
987
+ function loaderFor(
988
+ key: string,
989
+ value: GlobalProviderTrust,
990
+ ): () => Promise<GlobalProviderTrust> {
991
+ return async (): Promise<GlobalProviderTrust> => {
992
+ calls.push(key);
993
+ return value;
994
+ };
995
+ }
996
+
997
+ const results: Array<GlobalProviderTrust> = await Promise.all([
998
+ loadTrustOnce(firstKey, loaderFor(firstKey, USABLE_UNRESTRICTED)),
999
+ loadTrustOnce(secondKey, loaderFor(secondKey, DISABLED_PROVIDER)),
1000
+ loadTrustOnce(ssoKey, loaderFor(ssoKey, USABLE_UNRESTRICTED)),
1001
+ loadTrustOnce(oidcKey, loaderFor(oidcKey, DISABLED_PROVIDER)),
1002
+ ]);
1003
+
1004
+ expect(calls.sort()).toEqual([firstKey, secondKey, ssoKey, oidcKey].sort());
1005
+ expect(results[0]).toBe(USABLE_UNRESTRICTED);
1006
+ expect(results[1]).toBe(DISABLED_PROVIDER);
1007
+ expect(results[2]).toBe(USABLE_UNRESTRICTED);
1008
+ expect(results[3]).toBe(DISABLED_PROVIDER);
1009
+ });
1010
+
1011
+ test("the trust and attachment lookups are de-duplicated independently", async () => {
1012
+ const key: string = globalProviderCacheKey("sso", ObjectID.generate());
1013
+
1014
+ let trustCalls: number = 0;
1015
+ let attachmentCalls: number = 0;
1016
+
1017
+ const trust: Promise<GlobalProviderTrust> = loadTrustOnce(
1018
+ key,
1019
+ async (): Promise<GlobalProviderTrust> => {
1020
+ trustCalls++;
1021
+ return USABLE_UNRESTRICTED;
1022
+ },
1023
+ );
1024
+ const attached: Promise<GlobalProviderAttachments> = loadAttachmentsOnce(
1025
+ key,
1026
+ async (): Promise<GlobalProviderAttachments> => {
1027
+ attachmentCalls++;
1028
+ return attachments({
1029
+ hasAnyAttachmentRows: false,
1030
+ enabledProjectIds: [],
1031
+ });
1032
+ },
1033
+ );
1034
+
1035
+ // The same key string in the two maps must not shadow one another.
1036
+ expect(await trust).toBe(USABLE_UNRESTRICTED);
1037
+ expect((await attached).hasAnyAttachmentRows).toBe(false);
1038
+ expect(trustCalls).toBe(1);
1039
+ expect(attachmentCalls).toBe(1);
1040
+ });
1041
+
1042
+ test("the in-flight entry is released once it settles, so a later caller loads again", async () => {
1043
+ const key: string = globalProviderCacheKey("oidc", ObjectID.generate());
1044
+
1045
+ const values: Array<GlobalProviderAttachments> = [
1046
+ attachments({ hasAnyAttachmentRows: false, enabledProjectIds: [] }),
1047
+ attachments({ hasAnyAttachmentRows: true, enabledProjectIds: [] }),
1048
+ ];
1049
+
1050
+ let loaderCalls: number = 0;
1051
+
1052
+ const load: () => Promise<GlobalProviderAttachments> =
1053
+ async (): Promise<GlobalProviderAttachments> => {
1054
+ const value: GlobalProviderAttachments | undefined =
1055
+ values[loaderCalls];
1056
+ loaderCalls++;
1057
+ return value!;
1058
+ };
1059
+
1060
+ const first: GlobalProviderAttachments = await loadAttachmentsOnce(
1061
+ key,
1062
+ load,
1063
+ );
1064
+ expect(first).toBe(values[0]);
1065
+ expect(loaderCalls).toBe(1);
1066
+
1067
+ /*
1068
+ * The de-dup window is one settle, not one process lifetime - otherwise a
1069
+ * provider's very first answer would be pinned forever and the 60s TTL
1070
+ * would never take effect.
1071
+ */
1072
+ const second: GlobalProviderAttachments = await loadAttachmentsOnce(
1073
+ key,
1074
+ load,
1075
+ );
1076
+ expect(second).toBe(values[1]);
1077
+ expect(loaderCalls).toBe(2);
1078
+ });
1079
+
1080
+ test("a REJECTING loader is shared by every concurrent caller and is then released for a retry", async () => {
1081
+ const key: string = globalProviderCacheKey("sso", ObjectID.generate());
1082
+ const gate: Deferred<GlobalProviderTrust> =
1083
+ createDeferred<GlobalProviderTrust>();
1084
+ const failure: Error = new Error("connection terminated unexpectedly");
1085
+
1086
+ let loaderCalls: number = 0;
1087
+
1088
+ const failingLoad: () => Promise<GlobalProviderTrust> =
1089
+ (): Promise<GlobalProviderTrust> => {
1090
+ loaderCalls++;
1091
+ return gate.promise;
1092
+ };
1093
+
1094
+ const pending: Array<Promise<GlobalProviderTrust>> = [
1095
+ loadTrustOnce(key, failingLoad),
1096
+ loadTrustOnce(key, failingLoad),
1097
+ loadTrustOnce(key, failingLoad),
1098
+ ];
1099
+
1100
+ expect(loaderCalls).toBe(1);
1101
+
1102
+ gate.reject(failure);
1103
+
1104
+ /*
1105
+ * All three see the failure. A lookup failure must surface as a failure -
1106
+ * the enforcement path THROWS rather than turning "could not find out" into
1107
+ * "not allowed here" - so a shared rejection has to reach every caller.
1108
+ */
1109
+ const outcomes: Array<unknown> = await Promise.all(
1110
+ pending.map((promise: Promise<GlobalProviderTrust>) => {
1111
+ return promise.then(
1112
+ (): unknown => {
1113
+ return "resolved";
1114
+ },
1115
+ (error: unknown): unknown => {
1116
+ return error;
1117
+ },
1118
+ );
1119
+ }),
1120
+ );
1121
+
1122
+ for (const outcome of outcomes) {
1123
+ expect(outcome).toBe(failure);
1124
+ }
1125
+ expect(loaderCalls).toBe(1);
1126
+
1127
+ /*
1128
+ * ...and the key is NOT poisoned. A transient database blip must not pin a
1129
+ * rejected promise in the map, which would fail every later request for
1130
+ * that provider for the life of the process.
1131
+ */
1132
+ const retried: GlobalProviderTrust = await loadTrustOnce(
1133
+ key,
1134
+ async (): Promise<GlobalProviderTrust> => {
1135
+ loaderCalls++;
1136
+ return USABLE_UNRESTRICTED;
1137
+ },
1138
+ );
1139
+
1140
+ expect(retried).toBe(USABLE_UNRESTRICTED);
1141
+ expect(loaderCalls).toBe(2);
1142
+ });
1143
+
1144
+ test("a rejecting attachment loader behaves the same way", async () => {
1145
+ const key: string = globalProviderCacheKey("oidc", ObjectID.generate());
1146
+ const failure: Error = new Error("attachment lookup failed");
1147
+
1148
+ let loaderCalls: number = 0;
1149
+
1150
+ await expect(
1151
+ loadAttachmentsOnce(key, async (): Promise<GlobalProviderAttachments> => {
1152
+ loaderCalls++;
1153
+ throw failure;
1154
+ }),
1155
+ ).rejects.toBe(failure);
1156
+
1157
+ const retried: GlobalProviderAttachments = await loadAttachmentsOnce(
1158
+ key,
1159
+ async (): Promise<GlobalProviderAttachments> => {
1160
+ loaderCalls++;
1161
+ return attachments({
1162
+ hasAnyAttachmentRows: true,
1163
+ enabledProjectIds: [],
1164
+ });
1165
+ },
1166
+ );
1167
+
1168
+ expect(retried.hasAnyAttachmentRows).toBe(true);
1169
+ expect(loaderCalls).toBe(2);
1170
+ });
1171
+
1172
+ test("clearGlobalSsoAuthorizationCaches drops IN-FLIGHT entries as well as cached ones", async () => {
1173
+ /*
1174
+ * A write hook fires while a lookup is already in flight. The in-flight
1175
+ * promise is carrying the pre-change answer, so a caller arriving after the
1176
+ * clear must start its own lookup instead of joining it.
1177
+ */
1178
+ const trustKey: string = globalProviderCacheKey("sso", ObjectID.generate());
1179
+ const attachmentKey: string = globalProviderCacheKey(
1180
+ "sso",
1181
+ ObjectID.generate(),
1182
+ );
1183
+
1184
+ const trustGate: Deferred<GlobalProviderTrust> =
1185
+ createDeferred<GlobalProviderTrust>();
1186
+ const attachmentGate: Deferred<GlobalProviderAttachments> =
1187
+ createDeferred<GlobalProviderAttachments>();
1188
+
1189
+ let trustCalls: number = 0;
1190
+ let attachmentCalls: number = 0;
1191
+
1192
+ const staleTrust: () => Promise<GlobalProviderTrust> =
1193
+ (): Promise<GlobalProviderTrust> => {
1194
+ trustCalls++;
1195
+ return trustGate.promise;
1196
+ };
1197
+ const staleAttachments: () => Promise<GlobalProviderAttachments> =
1198
+ (): Promise<GlobalProviderAttachments> => {
1199
+ attachmentCalls++;
1200
+ return attachmentGate.promise;
1201
+ };
1202
+
1203
+ const inFlightTrust: Promise<GlobalProviderTrust> = loadTrustOnce(
1204
+ trustKey,
1205
+ staleTrust,
1206
+ );
1207
+ const inFlightAttachments: Promise<GlobalProviderAttachments> =
1208
+ loadAttachmentsOnce(attachmentKey, staleAttachments);
1209
+
1210
+ expect(trustCalls).toBe(1);
1211
+ expect(attachmentCalls).toBe(1);
1212
+
1213
+ /*
1214
+ * Without a clear, a second caller joins the in-flight lookup: no new load,
1215
+ * and it will be handed the pre-change answer.
1216
+ */
1217
+ const joinedTrust: Promise<GlobalProviderTrust> = loadTrustOnce(
1218
+ trustKey,
1219
+ staleTrust,
1220
+ );
1221
+ const joinedAttachments: Promise<GlobalProviderAttachments> =
1222
+ loadAttachmentsOnce(attachmentKey, staleAttachments);
1223
+
1224
+ expect(trustCalls).toBe(1);
1225
+ expect(attachmentCalls).toBe(1);
1226
+
1227
+ clearGlobalSsoAuthorizationCaches();
1228
+
1229
+ const freshTrust: Promise<GlobalProviderTrust> = loadTrustOnce(
1230
+ trustKey,
1231
+ async (): Promise<GlobalProviderTrust> => {
1232
+ trustCalls++;
1233
+ return DISABLED_PROVIDER;
1234
+ },
1235
+ );
1236
+ const freshAttachments: Promise<GlobalProviderAttachments> =
1237
+ loadAttachmentsOnce(
1238
+ attachmentKey,
1239
+ async (): Promise<GlobalProviderAttachments> => {
1240
+ attachmentCalls++;
1241
+ return attachments({
1242
+ hasAnyAttachmentRows: true,
1243
+ enabledProjectIds: [],
1244
+ });
1245
+ },
1246
+ );
1247
+
1248
+ /*
1249
+ * The clear is what forces the new load. Compare with the two calls above,
1250
+ * which added nothing to these counters.
1251
+ */
1252
+ expect(trustCalls).toBe(2);
1253
+ expect(attachmentCalls).toBe(2);
1254
+
1255
+ // The post-clear lookup is the one that sees the admin's change.
1256
+ expect(await freshTrust).toBe(DISABLED_PROVIDER);
1257
+ expect((await freshAttachments).hasAnyAttachmentRows).toBe(true);
1258
+
1259
+ // Let the pre-clear lookups finish so nothing is left dangling.
1260
+ trustGate.resolve(USABLE_UNRESTRICTED);
1261
+ attachmentGate.resolve(
1262
+ attachments({ hasAnyAttachmentRows: false, enabledProjectIds: [] }),
1263
+ );
1264
+
1265
+ /*
1266
+ * The callers that joined before the clear still get the pre-change answer -
1267
+ * their query was already on the wire. That staleness is bounded by the
1268
+ * request in flight, which is why the write hooks clear in the success hook
1269
+ * as well as the before-hook.
1270
+ */
1271
+ expect(await inFlightTrust).toBe(USABLE_UNRESTRICTED);
1272
+ expect(await joinedTrust).toBe(USABLE_UNRESTRICTED);
1273
+ expect((await inFlightAttachments).hasAnyAttachmentRows).toBe(false);
1274
+ expect((await joinedAttachments).hasAnyAttachmentRows).toBe(false);
1275
+ });
1276
+
1277
+ test("de-duplication does not populate the cache by itself", () => {
1278
+ /*
1279
+ * loadOnce only shares the promise; writing the answer into the 60s cache
1280
+ * is the loader's job. If sharing implied caching, a loader that threw
1281
+ * would still leave something behind.
1282
+ */
1283
+ const key: string = globalProviderCacheKey("sso", ObjectID.generate());
1284
+
1285
+ const pending: Promise<GlobalProviderTrust> = loadTrustOnce(
1286
+ key,
1287
+ async (): Promise<GlobalProviderTrust> => {
1288
+ return USABLE_UNRESTRICTED;
1289
+ },
1290
+ );
1291
+
1292
+ expect(globalSsoProviderTrustCache.get(key)).toBeUndefined();
1293
+ expect(globalSsoProviderTrustCache.size()).toBe(0);
1294
+
1295
+ return pending.then((): void => {
1296
+ expect(globalSsoProviderTrustCache.get(key)).toBeUndefined();
1297
+ });
1298
+ });
1299
+ });
1300
+
1301
+ /*
1302
+ * The in-flight slot is released only by the lookup that owns it.
1303
+ *
1304
+ * A cache clear can happen WHILE a lookup is on the wire - every write to any
1305
+ * of the four Global SSO/OIDC services calls clearGlobalSsoAuthorizationCaches
1306
+ * twice, and the multi-tenant permission path fans out immediately afterwards.
1307
+ * If the older lookup deleted the key blindly when it finally settled, it
1308
+ * would evict the NEWER lookup that had since taken the slot, and every
1309
+ * caller arriving after that would start its own query - de-duplication
1310
+ * silently off in exactly the situation it exists for.
1311
+ */
1312
+ describe("loadTrustOnce - a settling lookup does not evict a newer one", () => {
1313
+ const evictionProviderId: ObjectID = ObjectID.generate();
1314
+
1315
+ test("a caller arriving after a clear joins the second lookup rather than starting a third", async () => {
1316
+ const key: string = globalProviderCacheKey("sso", evictionProviderId);
1317
+
1318
+ let loadCount: number = 0;
1319
+ const releases: Array<(trust: GlobalProviderTrust) => void> = [];
1320
+
1321
+ const blockingLoader: () => Promise<GlobalProviderTrust> =
1322
+ (): Promise<GlobalProviderTrust> => {
1323
+ loadCount += 1;
1324
+
1325
+ return new Promise((resolve: (trust: GlobalProviderTrust) => void) => {
1326
+ releases.push(resolve);
1327
+ });
1328
+ };
1329
+
1330
+ // Lookup #1 starts and is still in flight.
1331
+ const first: Promise<GlobalProviderTrust> = loadTrustOnce(
1332
+ key,
1333
+ blockingLoader,
1334
+ );
1335
+
1336
+ // A write happens: the caches, and the in-flight slot, are dropped.
1337
+ clearGlobalSsoAuthorizationCaches();
1338
+
1339
+ // Lookup #2 takes the slot and is also still in flight.
1340
+ const second: Promise<GlobalProviderTrust> = loadTrustOnce(
1341
+ key,
1342
+ blockingLoader,
1343
+ );
1344
+
1345
+ expect(loadCount).toBe(2);
1346
+
1347
+ // Lookup #1 now settles. It must NOT take lookup #2's slot with it.
1348
+ releases[0]!({ isUsable: true, restrictToAttachedProjects: false });
1349
+ await first;
1350
+
1351
+ // A third caller arrives while lookup #2 is STILL in flight.
1352
+ const third: Promise<GlobalProviderTrust> = loadTrustOnce(
1353
+ key,
1354
+ blockingLoader,
1355
+ );
1356
+
1357
+ expect(loadCount).toBe(2);
1358
+
1359
+ releases[1]!({ isUsable: false, restrictToAttachedProjects: true });
1360
+
1361
+ await expect(second).resolves.toEqual({
1362
+ isUsable: false,
1363
+ restrictToAttachedProjects: true,
1364
+ });
1365
+ await expect(third).resolves.toEqual({
1366
+ isUsable: false,
1367
+ restrictToAttachedProjects: true,
1368
+ });
1369
+ });
1370
+
1371
+ test("the owning lookup still releases its own slot, so a later call re-loads", async () => {
1372
+ // The guard must not turn into "never release".
1373
+ const key: string = globalProviderCacheKey("oidc", evictionProviderId);
1374
+
1375
+ let loadCount: number = 0;
1376
+ const loader: () => Promise<GlobalProviderTrust> =
1377
+ async (): Promise<GlobalProviderTrust> => {
1378
+ loadCount += 1;
1379
+ return { isUsable: true, restrictToAttachedProjects: false };
1380
+ };
1381
+
1382
+ await loadTrustOnce(key, loader);
1383
+ await loadTrustOnce(key, loader);
1384
+
1385
+ expect(loadCount).toBe(2);
1386
+ });
1387
+ });
1388
+
1389
+ describe("GLOBAL_SSO_AUTHORIZATION_CACHE_TTL_MS", () => {
1390
+ test("is 60 seconds", () => {
1391
+ /*
1392
+ * This number is the blast radius of a revoked provider: the caches are
1393
+ * per-process with no cross-process invalidation, so on any node that did
1394
+ * NOT serve the disable, a provider that an admin turned off keeps
1395
+ * satisfying SSO enforcement for up to this long. Changing it changes that
1396
+ * exposure window.
1397
+ */
1398
+ expect(GLOBAL_SSO_AUTHORIZATION_CACHE_TTL_MS).toBe(60_000);
1399
+ expect(GLOBAL_SSO_AUTHORIZATION_CACHE_TTL_MS).toBe(60 * 1000);
1400
+ });
1401
+ });