@oneuptime/common 12.0.5 → 12.0.6

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 (528) hide show
  1. package/Models/DatabaseModels/AIRun.ts +33 -0
  2. package/Models/DatabaseModels/DataSource.ts +744 -0
  3. package/Models/DatabaseModels/Index.ts +3 -0
  4. package/Models/DatabaseModels/ProjectCallSMSConfig.ts +10 -2
  5. package/Models/DatabaseModels/User.ts +2 -0
  6. package/Models/DatabaseModels/UserOnCallLog.ts +2 -0
  7. package/Models/DatabaseModels/UserOnCallLogTimeline.ts +2 -0
  8. package/Models/DatabaseModels/UserSession.ts +2 -0
  9. package/Models/DatabaseModels/UserTotpAuth.ts +6 -4
  10. package/Models/DatabaseModels/UserWebAuthn.ts +5 -3
  11. package/Server/API/AIInsightAPI.ts +47 -4
  12. package/Server/API/AIInvestigationAPI.ts +25 -0
  13. package/Server/API/DashboardAPI.ts +176 -492
  14. package/Server/API/DataSourceAPI.ts +268 -0
  15. package/Server/API/StatusPageAPI.ts +11 -1
  16. package/Server/API/UserAPI.ts +119 -0
  17. package/Server/Infrastructure/ClickhouseConfig.ts +59 -0
  18. package/Server/Infrastructure/Postgres/SchemaMigrations/1786303472848-AddDataSourceTable.ts +39 -0
  19. package/Server/Infrastructure/Postgres/SchemaMigrations/1786600000000-AddInvestigationAnalysisTldr.ts +24 -0
  20. package/Server/Infrastructure/Postgres/SchemaMigrations/1786700000000-DropProjectCallSMSConfigCredentialUniques.ts +76 -0
  21. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +6 -0
  22. package/Server/Infrastructure/Queue.ts +26 -0
  23. package/Server/Infrastructure/QueueWorker.ts +17 -0
  24. package/Server/Middleware/TelemetryIngest.ts +8 -3
  25. package/Server/Services/AIInsightService.ts +132 -12
  26. package/Server/Services/AIRunService.ts +34 -0
  27. package/Server/Services/AIService.ts +17 -2
  28. package/Server/Services/AlertService.ts +38 -32
  29. package/Server/Services/AnalyticsDatabaseService.ts +8 -4
  30. package/Server/Services/DataSourceService.ts +200 -0
  31. package/Server/Services/HostService.ts +92 -0
  32. package/Server/Services/IncidentService.ts +45 -0
  33. package/Server/Services/Index.ts +2 -0
  34. package/Server/Services/MonitorService.ts +49 -0
  35. package/Server/Services/MonitorStatusService.ts +166 -0
  36. package/Server/Services/OpenTelemetryIngestService.ts +255 -184
  37. package/Server/Services/RumSessionPinService.ts +7 -21
  38. package/Server/Services/StatusPageSubscriberService.ts +13 -0
  39. package/Server/Services/UserService.ts +280 -9
  40. package/Server/Static/Vendor/README.md +62 -0
  41. package/Server/Static/Vendor/fonts/InterVariable.woff2 +0 -0
  42. package/Server/Static/Vendor/highlight/highlight.min.js +1244 -0
  43. package/Server/Static/Vendor/highlight/languages/apache.min.js +15 -0
  44. package/Server/Static/Vendor/highlight/languages/bash.min.js +21 -0
  45. package/Server/Static/Vendor/highlight/languages/c.min.js +41 -0
  46. package/Server/Static/Vendor/highlight/languages/cpp.min.js +47 -0
  47. package/Server/Static/Vendor/highlight/languages/csharp.min.js +49 -0
  48. package/Server/Static/Vendor/highlight/languages/css.min.js +31 -0
  49. package/Server/Static/Vendor/highlight/languages/diff.min.js +9 -0
  50. package/Server/Static/Vendor/highlight/languages/dns.min.js +11 -0
  51. package/Server/Static/Vendor/highlight/languages/dockerfile.min.js +8 -0
  52. package/Server/Static/Vendor/highlight/languages/go.min.js +20 -0
  53. package/Server/Static/Vendor/highlight/languages/graphql.min.js +12 -0
  54. package/Server/Static/Vendor/highlight/languages/http.min.js +14 -0
  55. package/Server/Static/Vendor/highlight/languages/ini.min.js +15 -0
  56. package/Server/Static/Vendor/highlight/languages/java.min.js +38 -0
  57. package/Server/Static/Vendor/highlight/languages/javascript.min.js +81 -0
  58. package/Server/Static/Vendor/highlight/languages/json.min.js +8 -0
  59. package/Server/Static/Vendor/highlight/languages/kotlin.min.js +46 -0
  60. package/Server/Static/Vendor/highlight/languages/lua.min.js +15 -0
  61. package/Server/Static/Vendor/highlight/languages/makefile.min.js +14 -0
  62. package/Server/Static/Vendor/highlight/languages/nginx.min.js +21 -0
  63. package/Server/Static/Vendor/highlight/languages/perl.min.js +41 -0
  64. package/Server/Static/Vendor/highlight/languages/php.min.js +59 -0
  65. package/Server/Static/Vendor/highlight/languages/powershell.min.js +39 -0
  66. package/Server/Static/Vendor/highlight/languages/python.min.js +42 -0
  67. package/Server/Static/Vendor/highlight/languages/r.min.js +26 -0
  68. package/Server/Static/Vendor/highlight/languages/ruby.min.js +54 -0
  69. package/Server/Static/Vendor/highlight/languages/rust.min.js +27 -0
  70. package/Server/Static/Vendor/highlight/languages/scala.min.js +28 -0
  71. package/Server/Static/Vendor/highlight/languages/sql.min.js +21 -0
  72. package/Server/Static/Vendor/highlight/languages/swift.min.js +68 -0
  73. package/Server/Static/Vendor/highlight/languages/typescript.min.js +99 -0
  74. package/Server/Static/Vendor/highlight/languages/xml.min.js +29 -0
  75. package/Server/Static/Vendor/highlight/languages/yaml.min.js +28 -0
  76. package/Server/Static/Vendor/highlight/styles/github-dark.min.css +10 -0
  77. package/Server/Static/Vendor/highlight/styles/vs2015.min.css +1 -0
  78. package/Server/Static/Vendor/tailwind/tailwind-3.4.5.js +21028 -0
  79. package/Server/Types/Database/Permissions/BasePermission.ts +7 -0
  80. package/Server/Types/Database/Permissions/DeletePermission.ts +2 -0
  81. package/Server/Types/Database/Permissions/ReadPermission.ts +3 -0
  82. package/Server/Types/Database/Permissions/TenantPermission.ts +101 -16
  83. package/Server/Utils/AI/CodeFix/FixRunBudget.ts +2 -2
  84. package/Server/Utils/AI/SRE/AIInvestigationEngine.ts +90 -11
  85. package/Server/Utils/AI/SRE/AlertInvestigationRunner.ts +1 -0
  86. package/Server/Utils/AI/SRE/IncidentInvestigationRunner.ts +1 -0
  87. package/Server/Utils/AI/SRE/Insights/Detectors/ExceptionIdentity.ts +125 -0
  88. package/Server/Utils/AI/SRE/Insights/Detectors/ExceptionSpikeDetector.ts +25 -15
  89. package/Server/Utils/AI/SRE/Insights/Detectors/NewExceptionDetector.ts +256 -57
  90. package/Server/Utils/AI/SRE/Insights/InsightStore.ts +76 -18
  91. package/Server/Utils/AI/SRE/InvestigationTldr.ts +352 -0
  92. package/Server/Utils/AnalyticsDatabase/InsertDedupContext.ts +7 -2
  93. package/Server/Utils/Dashboard/PublicDashboardResourceListPolicy.ts +1793 -0
  94. package/Server/Utils/Dashboard/PublicDashboardViewConfig.ts +65 -0
  95. package/Server/Utils/DataSource/ConnectorRegistry.ts +53 -0
  96. package/Server/Utils/DataSource/Connectors/ClickHouseConnector.ts +338 -0
  97. package/Server/Utils/DataSource/Connectors/ElasticsearchConnector.ts +717 -0
  98. package/Server/Utils/DataSource/Connectors/LokiConnector.ts +606 -0
  99. package/Server/Utils/DataSource/Connectors/MySqlConnector.ts +307 -0
  100. package/Server/Utils/DataSource/Connectors/PostgresConnector.ts +260 -0
  101. package/Server/Utils/DataSource/Connectors/PrometheusConnector.ts +555 -0
  102. package/Server/Utils/DataSource/Connectors/RestApiConnector.ts +597 -0
  103. package/Server/Utils/DataSource/Connectors/SqlServerConnector.ts +318 -0
  104. package/Server/Utils/DataSource/EgressGuard.ts +446 -0
  105. package/Server/Utils/DataSource/HttpFetch.ts +221 -0
  106. package/Server/Utils/DataSource/SqlQueryGuard.ts +383 -0
  107. package/Server/Utils/DataSource/SqlResultShaper.ts +372 -0
  108. package/Server/Utils/DataSource/Types.ts +93 -0
  109. package/Server/Utils/Database/PostgresErrorTranslator.ts +172 -17
  110. package/Server/Utils/InProcessMemo.ts +141 -0
  111. package/Server/Utils/InstanceHealth/TelemetryIngestion.ts +628 -0
  112. package/Server/Utils/Monitor/MonitorMetricUtil.ts +58 -0
  113. package/Server/Utils/Monitor/MonitorResource.ts +14 -0
  114. package/Server/Utils/Response.ts +12 -1
  115. package/Server/Utils/SSRFProtection.ts +237 -0
  116. package/Server/Utils/StartServer.ts +8 -0
  117. package/Server/Utils/StatusPageSubscriberWebhook.ts +30 -0
  118. package/Server/Utils/Telemetry/CaptureSpan.ts +30 -18
  119. package/Server/Utils/Telemetry/IngestionTimestamp.ts +75 -0
  120. package/Server/Utils/Telemetry/ResourceHeartbeat.ts +99 -7
  121. package/Server/Utils/Telemetry/Telemetry.ts +112 -1
  122. package/Server/Utils/Telemetry.ts +104 -3
  123. package/Server/Utils/VendorAssets.ts +165 -0
  124. package/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.ts +28 -5
  125. package/Server/Utils/Workspace/Slack/Slack.ts +5 -0
  126. package/Server/Views/Partials/Head.ejs +21 -7
  127. package/Tests/App/AdminDashboard/AdminProjectsIdFilter.test.tsx +207 -0
  128. package/Tests/App/AdminDashboard/AdminUsersIdFilter.test.tsx +216 -0
  129. package/Tests/App/Dashboard/AIInsightViewActions.test.tsx +422 -0
  130. package/Tests/App/Dashboard/AddWidgetModal.test.tsx +10 -3
  131. package/Tests/App/Dashboard/AlertsSideMenu.test.tsx +387 -0
  132. package/Tests/App/Dashboard/ChatActivityFeed.test.tsx +199 -0
  133. package/Tests/App/Dashboard/DataSourceChartSyntheticConfig.test.tsx +736 -0
  134. package/Tests/App/Dashboard/DataSourceQueryEditor.test.tsx +868 -0
  135. package/Tests/App/Dashboard/DataSourceWidgetCatalog.test.ts +440 -0
  136. package/Tests/App/Dashboard/DataSourceWidgetFetching.test.tsx +2109 -0
  137. package/Tests/App/Dashboard/DataSourceWidgetViews.test.tsx +726 -0
  138. package/Tests/App/Dashboard/IncidentsSideMenu.test.tsx +447 -0
  139. package/Tests/App/Dashboard/InvestigationPanel.test.tsx +514 -3
  140. package/Tests/App/Dashboard/ProductMenuBreadcrumbs.test.tsx +391 -0
  141. package/Tests/App/Dashboard/ScheduledMaintenanceSideMenu.test.tsx +326 -0
  142. package/Tests/App/Dashboard/SideMenuHarness.tsx +187 -0
  143. package/Tests/App/Dashboard/WidgetCatalog.test.ts +6 -1
  144. package/Tests/App/StatusPage/StatusPageResourceExplorer.test.tsx +1858 -0
  145. package/Tests/Models/DatabaseModels/DataSourceModelSecrets.test.ts +70 -0
  146. package/Tests/Server/API/AIInvestigationAPI.test.ts +187 -0
  147. package/Tests/Server/API/DashboardPublicDataSourceStrip.test.ts +686 -0
  148. package/Tests/Server/API/DashboardPublicResourceListAPI.test.ts +585 -823
  149. package/Tests/Server/API/DataSourceAPIRoutes.test.ts +486 -0
  150. package/Tests/Server/API/StatusPageSubscriberOwnership.test.ts +291 -0
  151. package/Tests/Server/API/UserAuthenticationAPI.test.ts +641 -0
  152. package/Tests/Server/Infrastructure/ClickhouseKeepAliveOptions.test.ts +441 -0
  153. package/Tests/Server/Middleware/TelemetryIngestTokenLog.test.ts +140 -0
  154. package/Tests/Server/Services/AIInsightService.test.ts +266 -11
  155. package/Tests/Server/Services/AIRunAnalysisTldrPersistence.test.ts +160 -0
  156. package/Tests/Server/Services/AIServiceDailyBudget.test.ts +4 -0
  157. package/Tests/Server/Services/AlertMetricResourceAttributes.test.ts +352 -0
  158. package/Tests/Server/Services/DataSourceServiceSettings.test.ts +244 -0
  159. package/Tests/Server/Services/HostServiceFindOrCreateMemo.test.ts +397 -0
  160. package/Tests/Server/Services/HostServiceUpdateLastSeen.test.ts +41 -2
  161. package/Tests/Server/Services/IncidentMetricResourceAttributes.test.ts +408 -0
  162. package/Tests/Server/Services/MonitorStatusServiceDeleteReferenceCleanup.test.ts +351 -0
  163. package/Tests/Server/Services/MonitorStatusServiceValidation.test.ts +171 -0
  164. package/Tests/Server/Services/OpenTelemetryResourceRetentionMemo.test.ts +398 -0
  165. package/Tests/Server/Services/OpenTelemetryServiceResolutionCache.test.ts +19 -0
  166. package/Tests/Server/Services/ProjectCallSMSConfigCredentialUniqueness.test.ts +305 -0
  167. package/Tests/Server/Services/ResourceUpdateLastSeenLivenessFallback.test.ts +36 -1
  168. package/Tests/Server/Services/RumSessionPinUniqueViolationRecovery.test.ts +163 -0
  169. package/Tests/Server/Services/UserAuthenticationService.test.ts +973 -0
  170. package/Tests/Server/Types/Database/ObjectIdColumnQuery.test.ts +262 -0
  171. package/Tests/Server/Types/Database/Permissions/TenantPermission.test.ts +358 -0
  172. package/Tests/Server/Utils/AI/FixRunBudget.test.ts +2 -2
  173. package/Tests/Server/Utils/AI/Insights/ExceptionSpikeDetector.test.ts +6 -1
  174. package/Tests/Server/Utils/AI/Insights/InsightStore.test.ts +121 -4
  175. package/Tests/Server/Utils/AI/Insights/NewExceptionDetector.test.ts +361 -10
  176. package/Tests/Server/Utils/AI/InvestigationSettlement.test.ts +292 -0
  177. package/Tests/Server/Utils/AI/InvestigationTldr.test.ts +623 -0
  178. package/Tests/Server/Utils/AI/InvestigationTldrWiring.test.ts +98 -0
  179. package/Tests/Server/Utils/Dashboard/PublicDashboardResourceListPolicy.test.ts +857 -0
  180. package/Tests/Server/Utils/Dashboard/PublicDashboardViewConfig.test.ts +480 -0
  181. package/Tests/Server/Utils/DataSource/ClickHouseConnector.test.ts +759 -0
  182. package/Tests/Server/Utils/DataSource/ConnectorRegistry.test.ts +37 -0
  183. package/Tests/Server/Utils/DataSource/EgressGuard.test.ts +645 -0
  184. package/Tests/Server/Utils/DataSource/ElasticsearchConnector.test.ts +1206 -0
  185. package/Tests/Server/Utils/DataSource/HttpFetch.test.ts +616 -0
  186. package/Tests/Server/Utils/DataSource/LokiConnector.test.ts +970 -0
  187. package/Tests/Server/Utils/DataSource/MySqlConnector.test.ts +935 -0
  188. package/Tests/Server/Utils/DataSource/PostgresConnector.test.ts +854 -0
  189. package/Tests/Server/Utils/DataSource/PrometheusConnector.test.ts +881 -0
  190. package/Tests/Server/Utils/DataSource/RestApiConnector.test.ts +1020 -0
  191. package/Tests/Server/Utils/DataSource/SqlQueryGuard.test.ts +425 -0
  192. package/Tests/Server/Utils/DataSource/SqlResultShaper.test.ts +555 -0
  193. package/Tests/Server/Utils/DataSource/SqlServerConnector.test.ts +934 -0
  194. package/Tests/Server/Utils/Database/PostgresErrorTranslator.test.ts +228 -7
  195. package/Tests/Server/Utils/InProcessMemo.test.ts +292 -0
  196. package/Tests/Server/Utils/InstanceHealth/TelemetryIngestion.test.ts +960 -0
  197. package/Tests/Server/Utils/MicrosoftTeamsWebhookUrlValidation.test.ts +103 -0
  198. package/Tests/Server/Utils/Monitor/MonitorMetricResourceAttributes.test.ts +336 -0
  199. package/Tests/Server/Utils/OfflineAssetHygiene.test.ts +521 -0
  200. package/Tests/Server/Utils/ResponseRenderAnalytics.test.ts +143 -0
  201. package/Tests/Server/Utils/SSRFProtection.test.ts +193 -0
  202. package/Tests/Server/Utils/StatusPageSubscriberWebhook.test.ts +101 -0
  203. package/Tests/Server/Utils/TailwindBuildCopy.test.ts +225 -0
  204. package/Tests/Server/Utils/Telemetry/ResourceHeartbeatL1Memo.test.ts +355 -0
  205. package/Tests/Server/Utils/Telemetry/TelemetryFanInWriter.test.ts +128 -0
  206. package/Tests/Server/Utils/Telemetry/TelemetryUtilAttributeKeys.test.ts +381 -0
  207. package/Tests/Server/Utils/Telemetry.test.ts +87 -0
  208. package/Tests/Server/Utils/VendorAssetIntegrity.test.ts +343 -0
  209. package/Tests/Server/Utils/VendorAssets.test.ts +671 -0
  210. package/Tests/Server/Views/OfflineRender.test.ts +297 -0
  211. package/Tests/Types/Dashboard/DataSourceComponentTypes.test.ts +618 -0
  212. package/Tests/Types/DateClickhouseFormat.test.ts +192 -0
  213. package/Tests/Types/Password.test.ts +363 -0
  214. package/Tests/UI/Components/ConfirmModal.test.tsx +7 -0
  215. package/Tests/UI/Components/ErrorBoundary.test.tsx +53 -0
  216. package/Tests/UI/Components/Modal.test.tsx +281 -1
  217. package/Tests/UI/Components/ObjectIdFilterPipeline.test.tsx +396 -0
  218. package/Tests/UI/Components/StatusPage/ResourceGroupNavigator.test.tsx +1147 -0
  219. package/Tests/UI/Utils/Breadcrumb/fixtures/RealBreadcrumbTrails.ts +116 -1
  220. package/Tests/UI/Utils/Breadcrumb/fixtures/RealRoutePatterns.ts +2 -0
  221. package/Tests/Utils/Analytics.test.ts +23 -0
  222. package/Tests/Utils/Dashboard/Components/DashboardDataSourceComponents.test.ts +640 -0
  223. package/Tests/Utils/DataSource/DataSourceQueryText.test.ts +138 -0
  224. package/Tests/Utils/DataSource/DataSourceValueReducer.test.ts +526 -0
  225. package/Tests/Utils/Metrics/MetricResourceAttributeUtil.test.ts +691 -0
  226. package/Tests/Utils/StatusPage/GroupHierarchyView.test.ts +1452 -0
  227. package/Tests/Utils/StatusPage/ResourceExplorer.test.ts +931 -0
  228. package/Tests/Utils/Telemetry/CaptureSpanExportGating.test.ts +288 -0
  229. package/Tests/Utils/Telemetry/IngestionTimestamp.test.ts +170 -0
  230. package/Types/AI/AIInsightEvidence.ts +6 -0
  231. package/Types/Analytics/RevenueEvent.ts +31 -0
  232. package/Types/Dashboard/DashboardComponentType.ts +31 -0
  233. package/Types/Dashboard/DashboardComponents/DashboardDataSourceChartComponent.ts +27 -0
  234. package/Types/Dashboard/DashboardComponents/DashboardDataSourceGaugeComponent.ts +32 -0
  235. package/Types/Dashboard/DashboardComponents/DashboardDataSourceTableComponent.ts +30 -0
  236. package/Types/Dashboard/DashboardComponents/DashboardDataSourceValueComponent.ts +55 -0
  237. package/Types/DataSource/DataSourceLimits.ts +62 -0
  238. package/Types/DataSource/DataSourceQueryConfig.ts +41 -0
  239. package/Types/DataSource/DataSourceTableResult.ts +38 -0
  240. package/Types/DataSource/DataSourceType.ts +213 -0
  241. package/Types/Date.ts +43 -3
  242. package/Types/Password.ts +64 -0
  243. package/Types/Permission.ts +46 -0
  244. package/Types/UserAuthenticationStatus.ts +34 -0
  245. package/UI/Components/Button/Button.tsx +1 -1
  246. package/UI/Components/ErrorBoundary.tsx +459 -108
  247. package/UI/Components/Icon/Icon.tsx +10 -9
  248. package/UI/Components/Modal/ConfirmModal.tsx +6 -1
  249. package/UI/Components/Modal/Modal.tsx +267 -35
  250. package/UI/Components/Modal/ModalFooter.tsx +6 -1
  251. package/UI/Components/MoreMenu/MoreMenu.tsx +19 -4
  252. package/UI/Components/MoreMenu/MoreMenuItem.tsx +6 -1
  253. package/UI/Components/StatusPage/ResourceGrid.tsx +314 -0
  254. package/UI/Components/StatusPage/ResourceGroupNavigator.tsx +808 -0
  255. package/UI/Components/StatusPage/ResourceList.tsx +570 -0
  256. package/UI/Styles/Theme.css +18 -0
  257. package/UI/Utils/API/RequestOptions.ts +7 -0
  258. package/UI/Utils/AnalyticsModelAPI/AnalyticsModelAPI.ts +1 -0
  259. package/UI/Utils/ModelAPI/ModelAPI.ts +1 -0
  260. package/UI/Utils/TestDataSource.ts +61 -0
  261. package/UI/esbuild-config.js +45 -0
  262. package/Utils/Analytics.ts +15 -0
  263. package/Utils/Dashboard/Components/DashboardDataSourceChartComponent.ts +88 -0
  264. package/Utils/Dashboard/Components/DashboardDataSourceGaugeComponent.ts +123 -0
  265. package/Utils/Dashboard/Components/DashboardDataSourceShared.ts +16 -0
  266. package/Utils/Dashboard/Components/DashboardDataSourceTableComponent.ts +72 -0
  267. package/Utils/Dashboard/Components/DashboardDataSourceValueComponent.ts +126 -0
  268. package/Utils/Dashboard/Components/Index.ts +28 -0
  269. package/Utils/DataSource/DataSourceQueryText.ts +94 -0
  270. package/Utils/DataSource/DataSourceValueReducer.ts +156 -0
  271. package/Utils/Metrics/MetricResourceAttributeUtil.ts +380 -0
  272. package/Utils/NetworkDiscovery/ScanTargetUtil.ts +8 -6
  273. package/Utils/StatusPage/GroupHierarchyView.ts +931 -0
  274. package/Utils/StatusPage/ResourceExplorer.ts +853 -0
  275. package/build/dist/Models/DatabaseModels/AIRun.js +34 -0
  276. package/build/dist/Models/DatabaseModels/AIRun.js.map +1 -1
  277. package/build/dist/Models/DatabaseModels/DataSource.js +774 -0
  278. package/build/dist/Models/DatabaseModels/DataSource.js.map +1 -0
  279. package/build/dist/Models/DatabaseModels/Index.js +2 -0
  280. package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
  281. package/build/dist/Models/DatabaseModels/ProjectCallSMSConfig.js +14 -4
  282. package/build/dist/Models/DatabaseModels/ProjectCallSMSConfig.js.map +1 -1
  283. package/build/dist/Models/DatabaseModels/User.js +2 -0
  284. package/build/dist/Models/DatabaseModels/User.js.map +1 -1
  285. package/build/dist/Models/DatabaseModels/UserOnCallLog.js +2 -0
  286. package/build/dist/Models/DatabaseModels/UserOnCallLog.js.map +1 -1
  287. package/build/dist/Models/DatabaseModels/UserOnCallLogTimeline.js +2 -0
  288. package/build/dist/Models/DatabaseModels/UserOnCallLogTimeline.js.map +1 -1
  289. package/build/dist/Models/DatabaseModels/UserSession.js +2 -0
  290. package/build/dist/Models/DatabaseModels/UserSession.js.map +1 -1
  291. package/build/dist/Models/DatabaseModels/UserTotpAuth.js +6 -4
  292. package/build/dist/Models/DatabaseModels/UserTotpAuth.js.map +1 -1
  293. package/build/dist/Models/DatabaseModels/UserWebAuthn.js +5 -3
  294. package/build/dist/Models/DatabaseModels/UserWebAuthn.js.map +1 -1
  295. package/build/dist/Server/API/AIInsightAPI.js +34 -4
  296. package/build/dist/Server/API/AIInsightAPI.js.map +1 -1
  297. package/build/dist/Server/API/AIInvestigationAPI.js +23 -0
  298. package/build/dist/Server/API/AIInvestigationAPI.js.map +1 -1
  299. package/build/dist/Server/API/DashboardAPI.js +119 -433
  300. package/build/dist/Server/API/DashboardAPI.js.map +1 -1
  301. package/build/dist/Server/API/DataSourceAPI.js +173 -0
  302. package/build/dist/Server/API/DataSourceAPI.js.map +1 -0
  303. package/build/dist/Server/API/StatusPageAPI.js +11 -1
  304. package/build/dist/Server/API/StatusPageAPI.js.map +1 -1
  305. package/build/dist/Server/API/UserAPI.js +94 -2
  306. package/build/dist/Server/API/UserAPI.js.map +1 -1
  307. package/build/dist/Server/Infrastructure/ClickhouseConfig.js +49 -0
  308. package/build/dist/Server/Infrastructure/ClickhouseConfig.js.map +1 -1
  309. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786303472848-AddDataSourceTable.js +20 -0
  310. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786303472848-AddDataSourceTable.js.map +1 -0
  311. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786600000000-AddInvestigationAnalysisTldr.js +19 -0
  312. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786600000000-AddInvestigationAnalysisTldr.js.map +1 -0
  313. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786700000000-DropProjectCallSMSConfigCredentialUniques.js +64 -0
  314. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786700000000-DropProjectCallSMSConfigCredentialUniques.js.map +1 -0
  315. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +6 -0
  316. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  317. package/build/dist/Server/Infrastructure/Queue.js +27 -0
  318. package/build/dist/Server/Infrastructure/Queue.js.map +1 -1
  319. package/build/dist/Server/Infrastructure/QueueWorker.js +13 -0
  320. package/build/dist/Server/Infrastructure/QueueWorker.js.map +1 -1
  321. package/build/dist/Server/Middleware/TelemetryIngest.js +8 -3
  322. package/build/dist/Server/Middleware/TelemetryIngest.js.map +1 -1
  323. package/build/dist/Server/Services/AIInsightService.js +110 -10
  324. package/build/dist/Server/Services/AIInsightService.js.map +1 -1
  325. package/build/dist/Server/Services/AIRunService.js +34 -0
  326. package/build/dist/Server/Services/AIRunService.js.map +1 -1
  327. package/build/dist/Server/Services/AIService.js +16 -2
  328. package/build/dist/Server/Services/AIService.js.map +1 -1
  329. package/build/dist/Server/Services/AlertService.js +28 -35
  330. package/build/dist/Server/Services/AlertService.js.map +1 -1
  331. package/build/dist/Server/Services/AnalyticsDatabaseService.js +8 -4
  332. package/build/dist/Server/Services/AnalyticsDatabaseService.js.map +1 -1
  333. package/build/dist/Server/Services/DataSourceService.js +159 -0
  334. package/build/dist/Server/Services/DataSourceService.js.map +1 -0
  335. package/build/dist/Server/Services/HostService.js +74 -0
  336. package/build/dist/Server/Services/HostService.js.map +1 -1
  337. package/build/dist/Server/Services/IncidentService.js +35 -24
  338. package/build/dist/Server/Services/IncidentService.js.map +1 -1
  339. package/build/dist/Server/Services/Index.js +2 -0
  340. package/build/dist/Server/Services/Index.js.map +1 -1
  341. package/build/dist/Server/Services/MonitorService.js +45 -0
  342. package/build/dist/Server/Services/MonitorService.js.map +1 -1
  343. package/build/dist/Server/Services/MonitorStatusService.js +129 -0
  344. package/build/dist/Server/Services/MonitorStatusService.js.map +1 -1
  345. package/build/dist/Server/Services/OpenTelemetryIngestService.js +222 -159
  346. package/build/dist/Server/Services/OpenTelemetryIngestService.js.map +1 -1
  347. package/build/dist/Server/Services/RumSessionPinService.js +7 -15
  348. package/build/dist/Server/Services/RumSessionPinService.js.map +1 -1
  349. package/build/dist/Server/Services/StatusPageSubscriberService.js +10 -0
  350. package/build/dist/Server/Services/StatusPageSubscriberService.js.map +1 -1
  351. package/build/dist/Server/Services/UserService.js +241 -10
  352. package/build/dist/Server/Services/UserService.js.map +1 -1
  353. package/build/dist/Server/Types/Database/Permissions/BasePermission.js +6 -0
  354. package/build/dist/Server/Types/Database/Permissions/BasePermission.js.map +1 -1
  355. package/build/dist/Server/Types/Database/Permissions/DeletePermission.js +1 -0
  356. package/build/dist/Server/Types/Database/Permissions/DeletePermission.js.map +1 -1
  357. package/build/dist/Server/Types/Database/Permissions/ReadPermission.js +2 -0
  358. package/build/dist/Server/Types/Database/Permissions/ReadPermission.js.map +1 -1
  359. package/build/dist/Server/Types/Database/Permissions/TenantPermission.js +68 -12
  360. package/build/dist/Server/Types/Database/Permissions/TenantPermission.js.map +1 -1
  361. package/build/dist/Server/Utils/AI/CodeFix/FixRunBudget.js +2 -2
  362. package/build/dist/Server/Utils/AI/CodeFix/FixRunBudget.js.map +1 -1
  363. package/build/dist/Server/Utils/AI/SRE/AIInvestigationEngine.js +68 -8
  364. package/build/dist/Server/Utils/AI/SRE/AIInvestigationEngine.js.map +1 -1
  365. package/build/dist/Server/Utils/AI/SRE/AlertInvestigationRunner.js +1 -0
  366. package/build/dist/Server/Utils/AI/SRE/AlertInvestigationRunner.js.map +1 -1
  367. package/build/dist/Server/Utils/AI/SRE/IncidentInvestigationRunner.js +1 -0
  368. package/build/dist/Server/Utils/AI/SRE/IncidentInvestigationRunner.js.map +1 -1
  369. package/build/dist/Server/Utils/AI/SRE/Insights/Detectors/ExceptionIdentity.js +97 -0
  370. package/build/dist/Server/Utils/AI/SRE/Insights/Detectors/ExceptionIdentity.js.map +1 -0
  371. package/build/dist/Server/Utils/AI/SRE/Insights/Detectors/ExceptionSpikeDetector.js +17 -15
  372. package/build/dist/Server/Utils/AI/SRE/Insights/Detectors/ExceptionSpikeDetector.js.map +1 -1
  373. package/build/dist/Server/Utils/AI/SRE/Insights/Detectors/NewExceptionDetector.js +178 -54
  374. package/build/dist/Server/Utils/AI/SRE/Insights/Detectors/NewExceptionDetector.js.map +1 -1
  375. package/build/dist/Server/Utils/AI/SRE/Insights/InsightStore.js +65 -16
  376. package/build/dist/Server/Utils/AI/SRE/Insights/InsightStore.js.map +1 -1
  377. package/build/dist/Server/Utils/AI/SRE/InvestigationTldr.js +303 -0
  378. package/build/dist/Server/Utils/AI/SRE/InvestigationTldr.js.map +1 -0
  379. package/build/dist/Server/Utils/AnalyticsDatabase/InsertDedupContext.js.map +1 -1
  380. package/build/dist/Server/Utils/Dashboard/PublicDashboardResourceListPolicy.js +1261 -0
  381. package/build/dist/Server/Utils/Dashboard/PublicDashboardResourceListPolicy.js.map +1 -0
  382. package/build/dist/Server/Utils/Dashboard/PublicDashboardViewConfig.js +47 -0
  383. package/build/dist/Server/Utils/Dashboard/PublicDashboardViewConfig.js.map +1 -0
  384. package/build/dist/Server/Utils/DataSource/ConnectorRegistry.js +42 -0
  385. package/build/dist/Server/Utils/DataSource/ConnectorRegistry.js.map +1 -0
  386. package/build/dist/Server/Utils/DataSource/Connectors/ClickHouseConnector.js +187 -0
  387. package/build/dist/Server/Utils/DataSource/Connectors/ClickHouseConnector.js.map +1 -0
  388. package/build/dist/Server/Utils/DataSource/Connectors/ElasticsearchConnector.js +493 -0
  389. package/build/dist/Server/Utils/DataSource/Connectors/ElasticsearchConnector.js.map +1 -0
  390. package/build/dist/Server/Utils/DataSource/Connectors/LokiConnector.js +399 -0
  391. package/build/dist/Server/Utils/DataSource/Connectors/LokiConnector.js.map +1 -0
  392. package/build/dist/Server/Utils/DataSource/Connectors/MySqlConnector.js +195 -0
  393. package/build/dist/Server/Utils/DataSource/Connectors/MySqlConnector.js.map +1 -0
  394. package/build/dist/Server/Utils/DataSource/Connectors/PostgresConnector.js +149 -0
  395. package/build/dist/Server/Utils/DataSource/Connectors/PostgresConnector.js.map +1 -0
  396. package/build/dist/Server/Utils/DataSource/Connectors/PrometheusConnector.js +362 -0
  397. package/build/dist/Server/Utils/DataSource/Connectors/PrometheusConnector.js.map +1 -0
  398. package/build/dist/Server/Utils/DataSource/Connectors/RestApiConnector.js +342 -0
  399. package/build/dist/Server/Utils/DataSource/Connectors/RestApiConnector.js.map +1 -0
  400. package/build/dist/Server/Utils/DataSource/Connectors/SqlServerConnector.js +186 -0
  401. package/build/dist/Server/Utils/DataSource/Connectors/SqlServerConnector.js.map +1 -0
  402. package/build/dist/Server/Utils/DataSource/EgressGuard.js +305 -0
  403. package/build/dist/Server/Utils/DataSource/EgressGuard.js.map +1 -0
  404. package/build/dist/Server/Utils/DataSource/HttpFetch.js +134 -0
  405. package/build/dist/Server/Utils/DataSource/HttpFetch.js.map +1 -0
  406. package/build/dist/Server/Utils/DataSource/SqlQueryGuard.js +331 -0
  407. package/build/dist/Server/Utils/DataSource/SqlQueryGuard.js.map +1 -0
  408. package/build/dist/Server/Utils/DataSource/SqlResultShaper.js +280 -0
  409. package/build/dist/Server/Utils/DataSource/SqlResultShaper.js.map +1 -0
  410. package/build/dist/Server/Utils/DataSource/Types.js +2 -0
  411. package/build/dist/Server/Utils/DataSource/Types.js.map +1 -0
  412. package/build/dist/Server/Utils/Database/PostgresErrorTranslator.js +103 -9
  413. package/build/dist/Server/Utils/Database/PostgresErrorTranslator.js.map +1 -1
  414. package/build/dist/Server/Utils/InProcessMemo.js +113 -0
  415. package/build/dist/Server/Utils/InProcessMemo.js.map +1 -0
  416. package/build/dist/Server/Utils/InstanceHealth/TelemetryIngestion.js +406 -0
  417. package/build/dist/Server/Utils/InstanceHealth/TelemetryIngestion.js.map +1 -0
  418. package/build/dist/Server/Utils/Monitor/MonitorMetricUtil.js +34 -0
  419. package/build/dist/Server/Utils/Monitor/MonitorMetricUtil.js.map +1 -1
  420. package/build/dist/Server/Utils/Monitor/MonitorResource.js +14 -0
  421. package/build/dist/Server/Utils/Monitor/MonitorResource.js.map +1 -1
  422. package/build/dist/Server/Utils/Response.js +9 -1
  423. package/build/dist/Server/Utils/Response.js.map +1 -1
  424. package/build/dist/Server/Utils/SSRFProtection.js +192 -0
  425. package/build/dist/Server/Utils/SSRFProtection.js.map +1 -0
  426. package/build/dist/Server/Utils/StartServer.js +7 -0
  427. package/build/dist/Server/Utils/StartServer.js.map +1 -1
  428. package/build/dist/Server/Utils/StatusPageSubscriberWebhook.js +24 -0
  429. package/build/dist/Server/Utils/StatusPageSubscriberWebhook.js.map +1 -1
  430. package/build/dist/Server/Utils/Telemetry/CaptureSpan.js +25 -11
  431. package/build/dist/Server/Utils/Telemetry/CaptureSpan.js.map +1 -1
  432. package/build/dist/Server/Utils/Telemetry/IngestionTimestamp.js +32 -0
  433. package/build/dist/Server/Utils/Telemetry/IngestionTimestamp.js.map +1 -0
  434. package/build/dist/Server/Utils/Telemetry/ResourceHeartbeat.js +92 -5
  435. package/build/dist/Server/Utils/Telemetry/ResourceHeartbeat.js.map +1 -1
  436. package/build/dist/Server/Utils/Telemetry/Telemetry.js +92 -6
  437. package/build/dist/Server/Utils/Telemetry/Telemetry.js.map +1 -1
  438. package/build/dist/Server/Utils/Telemetry.js +93 -6
  439. package/build/dist/Server/Utils/Telemetry.js.map +1 -1
  440. package/build/dist/Server/Utils/VendorAssets.js +121 -0
  441. package/build/dist/Server/Utils/VendorAssets.js.map +1 -0
  442. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js +25 -4
  443. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js.map +1 -1
  444. package/build/dist/Server/Utils/Workspace/Slack/Slack.js +5 -0
  445. package/build/dist/Server/Utils/Workspace/Slack/Slack.js.map +1 -1
  446. package/build/dist/Types/Analytics/RevenueEvent.js +26 -0
  447. package/build/dist/Types/Analytics/RevenueEvent.js.map +1 -0
  448. package/build/dist/Types/Dashboard/DashboardComponentType.js +27 -0
  449. package/build/dist/Types/Dashboard/DashboardComponentType.js.map +1 -1
  450. package/build/dist/Types/Dashboard/DashboardComponents/DashboardDataSourceChartComponent.js +2 -0
  451. package/build/dist/Types/Dashboard/DashboardComponents/DashboardDataSourceChartComponent.js.map +1 -0
  452. package/build/dist/Types/Dashboard/DashboardComponents/DashboardDataSourceGaugeComponent.js +2 -0
  453. package/build/dist/Types/Dashboard/DashboardComponents/DashboardDataSourceGaugeComponent.js.map +1 -0
  454. package/build/dist/Types/Dashboard/DashboardComponents/DashboardDataSourceTableComponent.js +2 -0
  455. package/build/dist/Types/Dashboard/DashboardComponents/DashboardDataSourceTableComponent.js.map +1 -0
  456. package/build/dist/Types/Dashboard/DashboardComponents/DashboardDataSourceValueComponent.js +16 -0
  457. package/build/dist/Types/Dashboard/DashboardComponents/DashboardDataSourceValueComponent.js.map +1 -0
  458. package/build/dist/Types/DataSource/DataSourceLimits.js +47 -0
  459. package/build/dist/Types/DataSource/DataSourceLimits.js.map +1 -0
  460. package/build/dist/Types/DataSource/DataSourceQueryConfig.js +10 -0
  461. package/build/dist/Types/DataSource/DataSourceQueryConfig.js.map +1 -0
  462. package/build/dist/Types/DataSource/DataSourceTableResult.js +14 -0
  463. package/build/dist/Types/DataSource/DataSourceTableResult.js.map +1 -0
  464. package/build/dist/Types/DataSource/DataSourceType.js +183 -0
  465. package/build/dist/Types/DataSource/DataSourceType.js.map +1 -0
  466. package/build/dist/Types/Date.js +38 -3
  467. package/build/dist/Types/Date.js.map +1 -1
  468. package/build/dist/Types/Password.js +56 -0
  469. package/build/dist/Types/Password.js.map +1 -0
  470. package/build/dist/Types/Permission.js +42 -0
  471. package/build/dist/Types/Permission.js.map +1 -1
  472. package/build/dist/Types/UserAuthenticationStatus.js +2 -0
  473. package/build/dist/Types/UserAuthenticationStatus.js.map +1 -0
  474. package/build/dist/UI/Components/ErrorBoundary.js +388 -72
  475. package/build/dist/UI/Components/ErrorBoundary.js.map +1 -1
  476. package/build/dist/UI/Components/Icon/Icon.js +10 -4
  477. package/build/dist/UI/Components/Icon/Icon.js.map +1 -1
  478. package/build/dist/UI/Components/Modal/ConfirmModal.js +1 -1
  479. package/build/dist/UI/Components/Modal/ConfirmModal.js.map +1 -1
  480. package/build/dist/UI/Components/Modal/Modal.js +178 -19
  481. package/build/dist/UI/Components/Modal/Modal.js.map +1 -1
  482. package/build/dist/UI/Components/Modal/ModalFooter.js +3 -1
  483. package/build/dist/UI/Components/Modal/ModalFooter.js.map +1 -1
  484. package/build/dist/UI/Components/MoreMenu/MoreMenu.js +9 -6
  485. package/build/dist/UI/Components/MoreMenu/MoreMenu.js.map +1 -1
  486. package/build/dist/UI/Components/MoreMenu/MoreMenuItem.js +7 -1
  487. package/build/dist/UI/Components/MoreMenu/MoreMenuItem.js.map +1 -1
  488. package/build/dist/UI/Components/StatusPage/ResourceGrid.js +119 -0
  489. package/build/dist/UI/Components/StatusPage/ResourceGrid.js.map +1 -0
  490. package/build/dist/UI/Components/StatusPage/ResourceGroupNavigator.js +354 -0
  491. package/build/dist/UI/Components/StatusPage/ResourceGroupNavigator.js.map +1 -0
  492. package/build/dist/UI/Components/StatusPage/ResourceList.js +203 -0
  493. package/build/dist/UI/Components/StatusPage/ResourceList.js.map +1 -0
  494. package/build/dist/UI/Utils/AnalyticsModelAPI/AnalyticsModelAPI.js +1 -6
  495. package/build/dist/UI/Utils/AnalyticsModelAPI/AnalyticsModelAPI.js.map +1 -1
  496. package/build/dist/UI/Utils/ModelAPI/ModelAPI.js +3 -8
  497. package/build/dist/UI/Utils/ModelAPI/ModelAPI.js.map +1 -1
  498. package/build/dist/UI/Utils/TestDataSource.js +39 -0
  499. package/build/dist/UI/Utils/TestDataSource.js.map +1 -0
  500. package/build/dist/Utils/Analytics.js +4 -0
  501. package/build/dist/Utils/Analytics.js.map +1 -1
  502. package/build/dist/Utils/Dashboard/Components/DashboardDataSourceChartComponent.js +79 -0
  503. package/build/dist/Utils/Dashboard/Components/DashboardDataSourceChartComponent.js.map +1 -0
  504. package/build/dist/Utils/Dashboard/Components/DashboardDataSourceGaugeComponent.js +111 -0
  505. package/build/dist/Utils/Dashboard/Components/DashboardDataSourceGaugeComponent.js.map +1 -0
  506. package/build/dist/Utils/Dashboard/Components/DashboardDataSourceShared.js +15 -0
  507. package/build/dist/Utils/Dashboard/Components/DashboardDataSourceShared.js.map +1 -0
  508. package/build/dist/Utils/Dashboard/Components/DashboardDataSourceTableComponent.js +62 -0
  509. package/build/dist/Utils/Dashboard/Components/DashboardDataSourceTableComponent.js.map +1 -0
  510. package/build/dist/Utils/Dashboard/Components/DashboardDataSourceValueComponent.js +112 -0
  511. package/build/dist/Utils/Dashboard/Components/DashboardDataSourceValueComponent.js.map +1 -0
  512. package/build/dist/Utils/Dashboard/Components/Index.js +16 -0
  513. package/build/dist/Utils/Dashboard/Components/Index.js.map +1 -1
  514. package/build/dist/Utils/DataSource/DataSourceQueryText.js +64 -0
  515. package/build/dist/Utils/DataSource/DataSourceQueryText.js.map +1 -0
  516. package/build/dist/Utils/DataSource/DataSourceValueReducer.js +124 -0
  517. package/build/dist/Utils/DataSource/DataSourceValueReducer.js.map +1 -0
  518. package/build/dist/Utils/Metrics/MetricResourceAttributeUtil.js +281 -0
  519. package/build/dist/Utils/Metrics/MetricResourceAttributeUtil.js.map +1 -0
  520. package/build/dist/Utils/NetworkDiscovery/ScanTargetUtil.js +8 -6
  521. package/build/dist/Utils/NetworkDiscovery/ScanTargetUtil.js.map +1 -1
  522. package/build/dist/Utils/StatusPage/GroupHierarchyView.js +560 -0
  523. package/build/dist/Utils/StatusPage/GroupHierarchyView.js.map +1 -0
  524. package/build/dist/Utils/StatusPage/ResourceExplorer.js +519 -0
  525. package/build/dist/Utils/StatusPage/ResourceExplorer.js.map +1 -0
  526. package/jest.config.json +1 -0
  527. package/package.json +5 -1
  528. package/tsconfig.json +12 -10
@@ -0,0 +1,262 @@
1
+ import QueryPermission from "../../../../Server/Types/Database/Permissions/QueryPermission";
2
+ import QueryUtil from "../../../../Server/Types/Database/QueryUtil";
3
+ import Project from "../../../../Models/DatabaseModels/Project";
4
+ import User from "../../../../Models/DatabaseModels/User";
5
+ import DatabaseCommonInteractionProps from "../../../../Types/BaseDatabase/DatabaseCommonInteractionProps";
6
+ import EqualTo from "../../../../Types/BaseDatabase/EqualTo";
7
+ import NotEqual from "../../../../Types/BaseDatabase/NotEqual";
8
+ import Search from "../../../../Types/BaseDatabase/Search";
9
+ import StartsWith from "../../../../Types/BaseDatabase/StartsWith";
10
+ import ObjectID from "../../../../Types/ObjectID";
11
+ import { DatabaseBaseModelType } from "../../../../Models/DatabaseModels/DatabaseBaseModel/DatabaseBaseModel";
12
+ import { FindOperator } from "typeorm";
13
+ import { describe, expect, it } from "@jest/globals";
14
+
15
+ /*
16
+ * The server half of "filter users and projects by ID" in the admin
17
+ * dashboard.
18
+ *
19
+ * `_id` is not an ordinary text column - it is a Postgres `uuid`, and uuid has
20
+ * no ILIKE. A partial-match filter on it only works because QueryHelper.search
21
+ * wraps the column in `CAST(... AS TEXT)` first; emit the ILIKE against the
22
+ * raw column and Postgres rejects the whole statement with
23
+ * `operator does not exist: uuid ~~* unknown`. That cast is invisible from the
24
+ * UI - the filter looks identical either way and simply errors at fetch time -
25
+ * so it is asserted here rather than inferred.
26
+ *
27
+ * The other half is the permission layer: every queried column is checked
28
+ * against what the caller may read, and a column it does not recognise is
29
+ * rejected outright. `_id` passes as an always-readable column, which is what
30
+ * lets the filter reach the database at all.
31
+ */
32
+
33
+ const A_UUID: string = "5f0e8e3a-1f24-4a2f-9e4c-2b1d3c4e5f60";
34
+
35
+ type SerializeFunction = (
36
+ modelType: DatabaseBaseModelType,
37
+ query: Record<string, unknown>,
38
+ ) => Record<string, any>;
39
+
40
+ const serialize: SerializeFunction = (
41
+ modelType: DatabaseBaseModelType,
42
+ query: Record<string, unknown>,
43
+ ): Record<string, any> => {
44
+ return QueryUtil.serializeQuery(modelType, query as any) as unknown as Record<
45
+ string,
46
+ any
47
+ >;
48
+ };
49
+
50
+ type RawSqlFunction = (operator: unknown, aliasPath: string) => string;
51
+
52
+ const rawSql: RawSqlFunction = (
53
+ operator: unknown,
54
+ aliasPath: string,
55
+ ): string => {
56
+ const getSql: ((aliasPath: string) => string) | undefined = (
57
+ operator as FindOperator<unknown>
58
+ ).getSql;
59
+
60
+ if (!getSql) {
61
+ throw new Error("Expected a Raw FindOperator with a SQL generator.");
62
+ }
63
+
64
+ return getSql(aliasPath);
65
+ };
66
+
67
+ type ParamsFunction = (operator: unknown) => Array<unknown>;
68
+
69
+ const params: ParamsFunction = (operator: unknown): Array<unknown> => {
70
+ return Object.values(
71
+ (
72
+ operator as unknown as {
73
+ objectLiteralParameters: Record<string, unknown>;
74
+ }
75
+ ).objectLiteralParameters,
76
+ );
77
+ };
78
+
79
+ describe("QueryUtil.serializeQuery — filtering on the _id column", () => {
80
+ describe("User", () => {
81
+ /*
82
+ * The default operator in the ID filter. A Search that reached TypeORM
83
+ * un-serialized would silently degrade into an exact equality, so pasting
84
+ * a fragment of an id would quietly match nothing at all.
85
+ */
86
+ it("turns a partial-id Search into an ILIKE over the id cast to text", () => {
87
+ const result: Record<string, any> = serialize(User, {
88
+ _id: new Search("5f0e8e3a"),
89
+ });
90
+
91
+ expect(result["_id"]).toBeInstanceOf(FindOperator);
92
+ expect(result["_id"]).not.toBeInstanceOf(Search);
93
+ expect(result["_id"].type).toBe("raw");
94
+
95
+ const sql: string = rawSql(result["_id"], "User._id");
96
+
97
+ // Without the cast this is invalid SQL against a uuid column.
98
+ expect(sql).toContain("CAST(User._id AS TEXT)");
99
+ expect(sql).toContain("ILIKE");
100
+ expect(params(result["_id"])).toEqual(["%5f0e8e3a%"]);
101
+ });
102
+
103
+ it("turns a whole-id EqualTo into a plain equality", () => {
104
+ const result: Record<string, any> = serialize(User, {
105
+ _id: new EqualTo(A_UUID),
106
+ });
107
+
108
+ expect(result["_id"].type).toBe("raw");
109
+ expect(rawSql(result["_id"], "User._id")).toContain("User._id = :");
110
+ expect(params(result["_id"])).toEqual([A_UUID]);
111
+ });
112
+
113
+ it("turns a NotEqual into an inequality", () => {
114
+ const result: Record<string, any> = serialize(User, {
115
+ _id: new NotEqual(A_UUID),
116
+ });
117
+
118
+ expect(rawSql(result["_id"], "User._id")).toContain("User._id != :");
119
+ expect(params(result["_id"])).toEqual([A_UUID]);
120
+ });
121
+
122
+ /*
123
+ * Prefix matching is the operator an admin reaches for with a truncated
124
+ * id, so it needs the same cast as `contains` - and an anchored pattern,
125
+ * not a floating one.
126
+ */
127
+ it("anchors a StartsWith to the front of the id", () => {
128
+ const result: Record<string, any> = serialize(User, {
129
+ _id: new StartsWith("5f0e8e3a"),
130
+ });
131
+
132
+ expect(rawSql(result["_id"], "User._id")).toContain(
133
+ "CAST(User._id AS TEXT)",
134
+ );
135
+ expect(params(result["_id"])).toEqual(["5f0e8e3a%"]);
136
+ });
137
+
138
+ /*
139
+ * Ids are copied out of the UI with whatever case the source used, and
140
+ * ILIKE is case-insensitive anyway - but the bound parameter has to be
141
+ * lower-cased consistently or a mixed-case paste behaves differently from
142
+ * the same id typed in lower case.
143
+ */
144
+ it("matches an id regardless of the case it was pasted in", () => {
145
+ expect(
146
+ params(
147
+ serialize(User, { _id: new Search(A_UUID.toUpperCase()) })["_id"],
148
+ ),
149
+ ).toEqual([`%${A_UUID}%`]);
150
+ });
151
+
152
+ it("leaves a bare id string as a plain equality value", () => {
153
+ expect(serialize(User, { _id: A_UUID })["_id"]).toBe(A_UUID);
154
+ });
155
+
156
+ it("unwraps an ObjectID into an equality on the id", () => {
157
+ const result: Record<string, any> = serialize(User, {
158
+ _id: new ObjectID(A_UUID),
159
+ });
160
+
161
+ expect(result["_id"].type).toBe("raw");
162
+ expect(params(result["_id"])).toEqual([A_UUID]);
163
+ });
164
+ });
165
+
166
+ /*
167
+ * Project is a different model with a different column set, and the admin
168
+ * dashboard filters it the same way. Nothing about the _id handling is
169
+ * per-model, and this is what says so.
170
+ */
171
+ describe("Project", () => {
172
+ it("turns a partial-id Search into an ILIKE over the id cast to text", () => {
173
+ const result: Record<string, any> = serialize(Project, {
174
+ _id: new Search("5f0e8e3a"),
175
+ });
176
+
177
+ expect(result["_id"].type).toBe("raw");
178
+ expect(rawSql(result["_id"], "Project._id")).toContain(
179
+ "CAST(Project._id AS TEXT)",
180
+ );
181
+ expect(params(result["_id"])).toEqual(["%5f0e8e3a%"]);
182
+ });
183
+
184
+ it("turns a whole-id EqualTo into a plain equality", () => {
185
+ const result: Record<string, any> = serialize(Project, {
186
+ _id: new EqualTo(A_UUID),
187
+ });
188
+
189
+ expect(rawSql(result["_id"], "Project._id")).toContain("Project._id = :");
190
+ expect(params(result["_id"])).toEqual([A_UUID]);
191
+ });
192
+ });
193
+ });
194
+
195
+ /*
196
+ * `checkQueryPermission` walks every key of the incoming query and rejects
197
+ * anything the caller cannot read. An id filter arrives as a query key like
198
+ * any other, so it has to survive that walk.
199
+ */
200
+ describe("QueryPermission.checkQueryPermission — querying by _id", () => {
201
+ /*
202
+ * No permissions at all: the weakest caller there is. `_id` is one of the
203
+ * always-readable columns, so even this caller may filter on it - which is
204
+ * what keeps the ID filter working for every table that offers one, without
205
+ * a per-model permission grant.
206
+ */
207
+ const noPermissions: DatabaseCommonInteractionProps = {
208
+ userGlobalAccessPermission: {
209
+ projectIds: [],
210
+ globalPermissions: [],
211
+ _type: "UserGlobalAccessPermission",
212
+ },
213
+ } as unknown as DatabaseCommonInteractionProps;
214
+
215
+ it("allows filtering users by _id", () => {
216
+ expect(() => {
217
+ QueryPermission.checkQueryPermission<User>(
218
+ User,
219
+ { _id: new Search("5f0e8e3a") } as any,
220
+ noPermissions,
221
+ );
222
+ }).not.toThrow();
223
+ });
224
+
225
+ it("allows filtering projects by _id", () => {
226
+ expect(() => {
227
+ QueryPermission.checkQueryPermission<Project>(
228
+ Project,
229
+ { _id: new Search("5f0e8e3a") } as any,
230
+ noPermissions,
231
+ );
232
+ }).not.toThrow();
233
+ });
234
+
235
+ /*
236
+ * The counter-case. Without it the two tests above would pass just as well
237
+ * against a permission check that waves everything through.
238
+ */
239
+ it("still rejects a column that does not exist", () => {
240
+ expect(() => {
241
+ QueryPermission.checkQueryPermission<User>(
242
+ User,
243
+ { notAColumn: new Search("x") } as any,
244
+ noPermissions,
245
+ );
246
+ }).toThrow(/Invalid column on User/);
247
+ });
248
+
249
+ /*
250
+ * ...and a real column that this caller has no permission to read, which is
251
+ * the check `_id` is deliberately exempt from.
252
+ */
253
+ it("still rejects a real column the caller cannot read", () => {
254
+ expect(() => {
255
+ QueryPermission.checkQueryPermission<User>(
256
+ User,
257
+ { isMasterAdmin: true } as any,
258
+ noPermissions,
259
+ );
260
+ }).toThrow();
261
+ });
262
+ });
@@ -0,0 +1,358 @@
1
+ import User from "../../../../../Models/DatabaseModels/User";
2
+ import UserOnCallLog from "../../../../../Models/DatabaseModels/UserOnCallLog";
3
+ import UserOnCallLogTimeline from "../../../../../Models/DatabaseModels/UserOnCallLogTimeline";
4
+ import UserSession from "../../../../../Models/DatabaseModels/UserSession";
5
+ import UserTotpAuth from "../../../../../Models/DatabaseModels/UserTotpAuth";
6
+ import UserWebAuthn from "../../../../../Models/DatabaseModels/UserWebAuthn";
7
+ import BaseModel from "../../../../../Models/DatabaseModels/DatabaseBaseModel/DatabaseBaseModel";
8
+ import UserService from "../../../../../Server/Services/UserService";
9
+ import DatabaseRequestType from "../../../../../Server/Types/BaseDatabase/DatabaseRequestType";
10
+ import DeleteBy from "../../../../../Server/Types/Database/DeleteBy";
11
+ import BasePermission from "../../../../../Server/Types/Database/Permissions/BasePermission";
12
+ import TenantPermission from "../../../../../Server/Types/Database/Permissions/TenantPermission";
13
+ import Query from "../../../../../Server/Types/Database/Query";
14
+ import UpdateBy from "../../../../../Server/Types/Database/UpdateBy";
15
+ import NotEqual from "../../../../../Types/BaseDatabase/NotEqual";
16
+ import DatabaseCommonInteractionProps from "../../../../../Types/BaseDatabase/DatabaseCommonInteractionProps";
17
+ import ColumnAccessControl from "../../../../../Types/Database/AccessControl/ColumnAccessControl";
18
+ import TableAccessControl from "../../../../../Types/Database/AccessControl/TableAccessControl";
19
+ import CurrentUserCanAccessRecordBy from "../../../../../Types/Database/CurrentUserCanAccessRecordBy";
20
+ import TableColumn from "../../../../../Types/Database/TableColumn";
21
+ import TableColumnType from "../../../../../Types/Database/TableColumnType";
22
+ import TenantColumn from "../../../../../Types/Database/TenantColumn";
23
+ import NotAuthorizedException from "../../../../../Types/Exception/NotAuthorizedException";
24
+ import ObjectID from "../../../../../Types/ObjectID";
25
+ import Permission from "../../../../../Types/Permission";
26
+ import UserType from "../../../../../Types/UserType";
27
+
28
+ @TableAccessControl({
29
+ create: [Permission.CurrentUser],
30
+ read: [Permission.CurrentUser],
31
+ update: [Permission.CurrentUser],
32
+ delete: [Permission.CurrentUser],
33
+ })
34
+ @CurrentUserCanAccessRecordBy("userId")
35
+ class MisconfiguredCurrentUserModel extends BaseModel {}
36
+
37
+ @TableAccessControl({
38
+ create: [Permission.CurrentUser],
39
+ read: [Permission.CurrentUser],
40
+ update: [Permission.CurrentUser],
41
+ delete: [Permission.CurrentUser],
42
+ })
43
+ class MissingCurrentUserScopeModel extends BaseModel {}
44
+
45
+ @TableAccessControl({
46
+ create: [Permission.CurrentUser],
47
+ read: [Permission.CurrentUser, Permission.ProjectAdmin],
48
+ update: [Permission.CurrentUser],
49
+ delete: [Permission.CurrentUser],
50
+ })
51
+ @CurrentUserCanAccessRecordBy("userId")
52
+ @TenantColumn("projectId")
53
+ class TenantScopedCurrentUserModel extends BaseModel {
54
+ @ColumnAccessControl({
55
+ create: [],
56
+ read: [Permission.CurrentUser, Permission.ProjectAdmin],
57
+ update: [],
58
+ })
59
+ @TableColumn({
60
+ type: TableColumnType.ObjectID,
61
+ title: "Project ID",
62
+ })
63
+ public projectId?: ObjectID = undefined;
64
+
65
+ @ColumnAccessControl({
66
+ create: [],
67
+ read: [Permission.CurrentUser, Permission.ProjectAdmin],
68
+ update: [],
69
+ })
70
+ @TableColumn({
71
+ type: TableColumnType.ObjectID,
72
+ title: "User ID",
73
+ })
74
+ public userId?: ObjectID = undefined;
75
+ }
76
+
77
+ describe("TenantPermission current-user ownership scope", () => {
78
+ const userId: ObjectID = ObjectID.generate();
79
+ const victimUserId: ObjectID = ObjectID.generate();
80
+
81
+ function makeUserProps(): DatabaseCommonInteractionProps {
82
+ return {
83
+ userId,
84
+ };
85
+ }
86
+
87
+ it.each([UserTotpAuth, UserWebAuthn, UserSession])(
88
+ "scopes %p queries to the authenticated user's records",
89
+ async (modelType: { new (): BaseModel }) => {
90
+ for (const requestType of [
91
+ DatabaseRequestType.Read,
92
+ DatabaseRequestType.Update,
93
+ DatabaseRequestType.Delete,
94
+ ]) {
95
+ const query: Query<BaseModel> =
96
+ await TenantPermission.addTenantScopeToQuery(
97
+ modelType,
98
+ {},
99
+ null,
100
+ makeUserProps(),
101
+ requestType,
102
+ );
103
+
104
+ expect((query as any).userId?.toString()).toBe(userId.toString());
105
+ }
106
+ },
107
+ );
108
+
109
+ it.each([UserTotpAuth, UserWebAuthn, UserSession])(
110
+ "rejects %p operations that explicitly target another user",
111
+ async (modelType: { new (): BaseModel }) => {
112
+ for (const requestType of [
113
+ DatabaseRequestType.Read,
114
+ DatabaseRequestType.Update,
115
+ DatabaseRequestType.Delete,
116
+ ]) {
117
+ await expect(
118
+ TenantPermission.addTenantScopeToQuery(
119
+ modelType,
120
+ { userId: victimUserId } as any,
121
+ null,
122
+ makeUserProps(),
123
+ requestType,
124
+ ),
125
+ ).rejects.toThrow(NotAuthorizedException);
126
+ }
127
+ },
128
+ );
129
+
130
+ it("rejects CurrentUser access when a non-user caller has no user identity", async () => {
131
+ const apiKeyProps: DatabaseCommonInteractionProps = {
132
+ userType: UserType.API,
133
+ userGlobalAccessPermission: {
134
+ projectIds: [ObjectID.generate()],
135
+ globalPermissions: [
136
+ Permission.Public,
137
+ Permission.User,
138
+ Permission.CurrentUser,
139
+ ],
140
+ _type: "UserGlobalAccessPermission",
141
+ },
142
+ };
143
+
144
+ await expect(
145
+ BasePermission.checkPermissions(
146
+ UserTotpAuth,
147
+ {},
148
+ null,
149
+ apiKeyProps,
150
+ DatabaseRequestType.Read,
151
+ ),
152
+ ).rejects.toThrow(NotAuthorizedException);
153
+ });
154
+
155
+ it("fails closed when a CurrentUser model resolves no ownership filter", async () => {
156
+ await expect(
157
+ TenantPermission.addTenantScopeToQuery(
158
+ MisconfiguredCurrentUserModel,
159
+ {},
160
+ null,
161
+ makeUserProps(),
162
+ DatabaseRequestType.Read,
163
+ ),
164
+ ).rejects.toThrow(NotAuthorizedException);
165
+ });
166
+
167
+ it("fails closed when CurrentUser ownership metadata is missing", async () => {
168
+ await expect(
169
+ TenantPermission.addTenantScopeToQuery(
170
+ MissingCurrentUserScopeModel,
171
+ {},
172
+ null,
173
+ makeUserProps(),
174
+ DatabaseRequestType.Read,
175
+ ),
176
+ ).rejects.toThrow(NotAuthorizedException);
177
+ });
178
+
179
+ it("keeps User reads scoped to the authenticated user's primary key", async () => {
180
+ const query: Query<User> = await TenantPermission.addTenantScopeToQuery(
181
+ User,
182
+ {},
183
+ null,
184
+ makeUserProps(),
185
+ DatabaseRequestType.Read,
186
+ );
187
+
188
+ expect((query as any)._id?.toString()).toBe(userId.toString());
189
+ });
190
+
191
+ it("rejects query operators that disguise a broad ownership filter", async () => {
192
+ await expect(
193
+ TenantPermission.addTenantScopeToQuery(
194
+ User,
195
+ { _id: new NotEqual<string>(userId.toString()) },
196
+ null,
197
+ makeUserProps(),
198
+ DatabaseRequestType.Update,
199
+ ),
200
+ ).rejects.toThrow(NotAuthorizedException);
201
+ });
202
+
203
+ it("rejects deleting another User instead of redirecting the delete", async () => {
204
+ await expect(
205
+ TenantPermission.addTenantScopeToQuery(
206
+ User,
207
+ { _id: victimUserId },
208
+ null,
209
+ makeUserProps(),
210
+ DatabaseRequestType.Delete,
211
+ ),
212
+ ).rejects.toThrow(NotAuthorizedException);
213
+ });
214
+
215
+ it("allows deleting the authenticated User's own record", async () => {
216
+ const deleteQuery: Query<User> =
217
+ await TenantPermission.addTenantScopeToQuery(
218
+ User,
219
+ { _id: userId },
220
+ null,
221
+ makeUserProps(),
222
+ DatabaseRequestType.Delete,
223
+ );
224
+
225
+ expect((deleteQuery as any)._id?.toString()).toBe(userId.toString());
226
+ });
227
+
228
+ it.each([UserOnCallLog, UserOnCallLogTimeline])(
229
+ "scopes %p reads to the current user within the tenant",
230
+ async (modelType: { new (): BaseModel }) => {
231
+ const projectId: ObjectID = ObjectID.generate();
232
+ const query: Query<BaseModel> =
233
+ await TenantPermission.addTenantScopeToQuery(
234
+ modelType,
235
+ {},
236
+ null,
237
+ { ...makeUserProps(), tenantId: projectId },
238
+ DatabaseRequestType.Read,
239
+ );
240
+
241
+ expect((query as any).projectId?.toString()).toBe(projectId.toString());
242
+ expect((query as any).userId?.toString()).toBe(userId.toString());
243
+ },
244
+ );
245
+
246
+ it("does not mutate a query reused for list and count permission checks", async () => {
247
+ const reusedQuery: Query<UserTotpAuth> = {};
248
+
249
+ await BasePermission.checkPermissions(
250
+ UserTotpAuth,
251
+ reusedQuery,
252
+ null,
253
+ makeUserProps(),
254
+ DatabaseRequestType.Read,
255
+ );
256
+ await expect(
257
+ BasePermission.checkPermissions(
258
+ UserTotpAuth,
259
+ reusedQuery,
260
+ null,
261
+ makeUserProps(),
262
+ DatabaseRequestType.Read,
263
+ ),
264
+ ).resolves.toBeDefined();
265
+
266
+ expect(reusedQuery).toEqual({});
267
+ });
268
+
269
+ it("isolates CurrentUser scope for every project in a multi-tenant query", async () => {
270
+ const currentUserProjectId: ObjectID = ObjectID.generate();
271
+ const adminProjectId: ObjectID = ObjectID.generate();
272
+
273
+ for (const projectIds of [
274
+ [currentUserProjectId, adminProjectId],
275
+ [adminProjectId, currentUserProjectId],
276
+ ]) {
277
+ const queries: Array<Record<string, unknown>> =
278
+ (await TenantPermission.addTenantScopeToQuery(
279
+ TenantScopedCurrentUserModel,
280
+ {},
281
+ null,
282
+ {
283
+ userId,
284
+ userGlobalAccessPermission: {
285
+ projectIds,
286
+ globalPermissions: [Permission.Public, Permission.CurrentUser],
287
+ _type: "UserGlobalAccessPermission",
288
+ },
289
+ userTenantAccessPermission: {
290
+ [adminProjectId.toString()]: {
291
+ projectId: adminProjectId,
292
+ permissions: [
293
+ {
294
+ permission: Permission.ProjectAdmin,
295
+ labelIds: [],
296
+ isBlockPermission: false,
297
+ _type: "UserPermission",
298
+ },
299
+ ],
300
+ _type: "UserTenantAccessPermission",
301
+ },
302
+ },
303
+ },
304
+ DatabaseRequestType.Read,
305
+ )) as unknown as Array<Record<string, unknown>>;
306
+
307
+ expect(queries).toHaveLength(2);
308
+ expect(
309
+ queries[projectIds.indexOf(currentUserProjectId)]?.["userId"],
310
+ ).toBeDefined();
311
+ expect(
312
+ queries[projectIds.indexOf(adminProjectId)]?.["userId"],
313
+ ).toBeUndefined();
314
+ }
315
+ });
316
+
317
+ it("rejects a cross-user delete before UserService inspects memberships", async () => {
318
+ await expect(
319
+ (UserService as any).onBeforeDelete({
320
+ query: { _id: victimUserId },
321
+ props: makeUserProps(),
322
+ limit: 1,
323
+ skip: 0,
324
+ } as DeleteBy<User>),
325
+ ).rejects.toThrow(NotAuthorizedException);
326
+ });
327
+
328
+ it("rejects broad update operators before UserService runs user hooks", async () => {
329
+ await expect(
330
+ (UserService as any).onBeforeUpdate({
331
+ query: { _id: new NotEqual<string>(userId.toString()) },
332
+ data: { password: "new-password" },
333
+ props: makeUserProps(),
334
+ limit: 1,
335
+ skip: 0,
336
+ } as unknown as UpdateBy<User>),
337
+ ).rejects.toThrow(NotAuthorizedException);
338
+ });
339
+ });
340
+
341
+ describe("two-factor credential ownership columns", () => {
342
+ it("prevents TOTP ownership and verification from being changed via CRUD", () => {
343
+ const model: UserTotpAuth = new UserTotpAuth();
344
+
345
+ expect(model.getColumnAccessControlFor("user")?.update).toEqual([]);
346
+ expect(model.getColumnAccessControlFor("user")?.create).toEqual([]);
347
+ expect(model.getColumnAccessControlFor("userId")?.update).toEqual([]);
348
+ expect(model.getColumnAccessControlFor("isVerified")?.update).toEqual([]);
349
+ });
350
+
351
+ it("prevents WebAuthn ownership from being changed via CRUD", () => {
352
+ const model: UserWebAuthn = new UserWebAuthn();
353
+
354
+ expect(model.getColumnAccessControlFor("user")?.update).toEqual([]);
355
+ expect(model.getColumnAccessControlFor("user")?.create).toEqual([]);
356
+ expect(model.getColumnAccessControlFor("userId")?.update).toEqual([]);
357
+ });
358
+ });
@@ -100,7 +100,7 @@ describe("FixRunBudget.describeRejection", () => {
100
100
  );
101
101
 
102
102
  expect(message).toMatch(/Daily Incident AI Fix Task Limit/);
103
- expect(message).toMatch(/Incidents > Settings > AI/);
103
+ expect(message).toMatch(/Incidents > AI > Investigation/);
104
104
  expect(message).toMatch(/0/);
105
105
  });
106
106
 
@@ -112,7 +112,7 @@ describe("FixRunBudget.describeRejection", () => {
112
112
 
113
113
  expect(message).toMatch(/10 of 10/);
114
114
  expect(message).toMatch(/Daily Alert AI Fix Task Limit/);
115
- expect(message).toMatch(/Alerts > Settings > AI/);
115
+ expect(message).toMatch(/Alerts > AI > Investigation/);
116
116
  expect(message).toMatch(new RegExp(String(DEFAULT_DAILY_FIX_RUN_LIMIT)));
117
117
  });
118
118
 
@@ -208,8 +208,13 @@ describe("ExceptionSpikeDetector.detect (IO wiring)", () => {
208
208
  `exception-spike:${exceptionId.toString()}`,
209
209
  );
210
210
  expect(candidate.severity).toBe(AIInsightSeverity.High);
211
+ /*
212
+ * Type AND message: the type alone collides across findings (a service
213
+ * whose instrumentation types every failure by HTTP status renders a wall
214
+ * of identical rows).
215
+ */
211
216
  expect(candidate.title).toBe(
212
- "Exception spike: ConnectionError at 50.0x normal rate in payments",
217
+ "Exception spike: ConnectionError: connection reset by peer at 50.0x normal rate in payments",
213
218
  );
214
219
  expect(candidate.evidence.exception).toEqual(
215
220
  expect.objectContaining({