@oneuptime/common 12.0.2 → 12.0.4

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 (384) hide show
  1. package/Models/DatabaseModels/CephCluster.ts +14 -0
  2. package/Models/DatabaseModels/CodeRepository.ts +14 -6
  3. package/Models/DatabaseModels/DatabaseBaseModel/DatabaseBaseModel.ts +14 -0
  4. package/Models/DatabaseModels/DockerHost.ts +14 -0
  5. package/Models/DatabaseModels/GlobalOidcProject.ts +18 -0
  6. package/Models/DatabaseModels/GlobalSsoProject.ts +18 -0
  7. package/Models/DatabaseModels/Index.ts +2 -0
  8. package/Models/DatabaseModels/IoTFleet.ts +14 -0
  9. package/Models/DatabaseModels/KubernetesCluster.ts +14 -0
  10. package/Models/DatabaseModels/LogDropFilter.ts +9 -20
  11. package/Models/DatabaseModels/NetworkDevice.ts +14 -0
  12. package/Models/DatabaseModels/NetworkInterface.ts +18 -0
  13. package/Models/DatabaseModels/Project.ts +16 -2
  14. package/Models/DatabaseModels/ProxmoxCluster.ts +14 -0
  15. package/Models/DatabaseModels/Service.ts +30 -0
  16. package/Models/DatabaseModels/StatusPageMonitorRule.ts +911 -0
  17. package/Models/DatabaseModels/StatusPagePrivateUser.ts +30 -0
  18. package/Models/DatabaseModels/StatusPageResource.ts +73 -0
  19. package/Models/DatabaseModels/TraceDropFilter.ts +9 -20
  20. package/Models/DatabaseModels/User.ts +30 -0
  21. package/Server/API/AIAgentDataAPI.ts +31 -0
  22. package/Server/API/BaseAPI.ts +13 -2
  23. package/Server/API/DashboardAPI.ts +458 -12
  24. package/Server/API/GitHubAPI.ts +119 -283
  25. package/Server/API/UserAPI.ts +263 -1
  26. package/Server/EnvironmentConfig.ts +38 -4
  27. package/Server/Infrastructure/GlobalCache.ts +152 -0
  28. package/Server/Infrastructure/Postgres/DataSourceOptions.ts +16 -0
  29. package/Server/Infrastructure/Postgres/SchemaMigrations/1786005052769-AddStatusPageMonitorRule.ts +123 -0
  30. package/Server/Infrastructure/Postgres/SchemaMigrations/1786018109307-AddPerUserPasswordSalt.ts +21 -0
  31. package/Server/Infrastructure/Postgres/SchemaMigrations/1786023262402-WidenHashedStringColumnsForScrypt.ts +68 -0
  32. package/Server/Infrastructure/Postgres/SchemaMigrations/1786100000000-RestoreServiceLowerNameIndex.ts +100 -0
  33. package/Server/Infrastructure/Postgres/SchemaMigrations/1786200000000-RestoreDroppedUniqueIndexes.ts +214 -0
  34. package/Server/Infrastructure/Postgres/SchemaMigrations/1786300000000-QuarantineUnboundGitHubInstallations.ts +69 -0
  35. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +12 -0
  36. package/Server/Services/AlertStateTimelineService.ts +20 -0
  37. package/Server/Services/AnalyticsDatabaseService.ts +72 -1
  38. package/Server/Services/CephClusterService.ts +26 -86
  39. package/Server/Services/CloudResourceService.ts +23 -83
  40. package/Server/Services/CodeRepositoryService.ts +105 -2
  41. package/Server/Services/DatabaseService.ts +296 -2
  42. package/Server/Services/DockerHostService.ts +19 -79
  43. package/Server/Services/DockerSwarmClusterService.ts +27 -88
  44. package/Server/Services/HostService.ts +46 -99
  45. package/Server/Services/IncidentStateTimelineService.ts +20 -0
  46. package/Server/Services/Index.ts +2 -0
  47. package/Server/Services/IoTFleetService.ts +19 -79
  48. package/Server/Services/KubernetesClusterService.ts +17 -78
  49. package/Server/Services/LabelService.ts +57 -10
  50. package/Server/Services/MetricTypeService.ts +84 -0
  51. package/Server/Services/MonitorService.ts +89 -14
  52. package/Server/Services/MonitorStatusTimelineService.ts +29 -0
  53. package/Server/Services/MonitorTemplateService.ts +65 -0
  54. package/Server/Services/OpenTelemetryIngestService.ts +230 -26
  55. package/Server/Services/PodmanHostService.ts +19 -79
  56. package/Server/Services/ProxmoxClusterService.ts +23 -83
  57. package/Server/Services/RumApplicationService.ts +19 -80
  58. package/Server/Services/ScheduledMaintenanceStateTimelineService.ts +21 -0
  59. package/Server/Services/ServerlessFunctionService.ts +24 -85
  60. package/Server/Services/ServiceService.ts +299 -73
  61. package/Server/Services/StatusPageMonitorRuleEngineService.ts +752 -0
  62. package/Server/Services/StatusPageMonitorRuleService.ts +471 -0
  63. package/Server/Services/TelemetryEntityRelationshipService.ts +1 -0
  64. package/Server/Services/TelemetryEntityService.ts +1 -0
  65. package/Server/Services/UserService.ts +184 -0
  66. package/Server/Utils/AI/Toolbox/CodeTools.ts +45 -4
  67. package/Server/Utils/AnalyticsDatabase/StatementGenerator.ts +13 -0
  68. package/Server/Utils/CodeRepository/GitHub/GitHub.ts +157 -4
  69. package/Server/Utils/CodeRepository/GitHub/GitHubInstallationBinding.ts +130 -0
  70. package/Server/Utils/Database/ProjectScopedReferenceValidator.ts +170 -39
  71. package/Server/Utils/Monitor/MonitorResource.ts +63 -36
  72. package/Server/Utils/Monitor/MonitorStatusTimeline.ts +36 -0
  73. package/Server/Utils/Monitor/MonitorStepsProjectValidator.ts +148 -127
  74. package/Server/Utils/Monitor/MonitorStepsReferenceExtractor.ts +434 -0
  75. package/Server/Utils/PasswordHash.ts +306 -0
  76. package/Server/Utils/SingleFlight.ts +83 -0
  77. package/Server/Utils/StatusPage/MonitorRulePatternValidator.ts +46 -0
  78. package/Server/Utils/Telemetry/EntityRegistry.ts +107 -26
  79. package/Server/Utils/Telemetry/ResourceHeartbeat.ts +314 -0
  80. package/Server/Utils/Telemetry/Telemetry.ts +351 -122
  81. package/Tests/App/Dashboard/OverviewCustomFields.test.tsx +333 -0
  82. package/Tests/App/Dashboard/UserCustomFields.test.tsx +392 -0
  83. package/Tests/App/Dashboard/WidgetCatalog.test.ts +2 -0
  84. package/Tests/Models/DatabaseModels/ColumnTransformerInvariants.test.ts +306 -0
  85. package/Tests/Models/DatabaseModels/NumberColumnDeserialization.test.ts +333 -0
  86. package/Tests/Models/DatabaseModels/StatusPageMonitorRuleModel.test.ts +190 -0
  87. package/Tests/Server/API/AIAgentDataRepositoryToken.test.ts +381 -0
  88. package/Tests/Server/API/DashboardPublicAttributeValuesAPI.test.ts +943 -0
  89. package/Tests/Server/API/DashboardPublicMetricsAggregateAPI.test.ts +1296 -0
  90. package/Tests/Server/API/DashboardPublicResourceListAPI.test.ts +26 -0
  91. package/Tests/Server/API/DashboardPublicTemplatePayloads.test.ts +598 -0
  92. package/Tests/Server/API/GitHubAppInstallationBindingAPI.test.ts +539 -0
  93. package/Tests/Server/API/Helpers.ts +6 -1
  94. package/Tests/Server/API/UserProjectsAPI.test.ts +852 -0
  95. package/Tests/Server/Infrastructure/GlobalCache.test.ts +354 -0
  96. package/Tests/Server/Infrastructure/PostgresLockTimeoutOptions.test.ts +181 -0
  97. package/Tests/Server/Infrastructure/SemaphoreMutex.test.ts +215 -0
  98. package/Tests/Server/Services/AddPerUserPasswordSaltMigration.test.ts +178 -0
  99. package/Tests/Server/Services/AnalyticsDatabasePaginationStability.test.ts +582 -0
  100. package/Tests/Server/Services/AnalyticsDatabaseService.test.ts +5 -0
  101. package/Tests/Server/Services/CodeRepositoryInstallationBinding.test.ts +305 -0
  102. package/Tests/Server/Services/CodeRepositoryResolutionBinding.test.ts +147 -0
  103. package/Tests/Server/Services/DatabaseServicePerUserPasswordSalt.test.ts +870 -0
  104. package/Tests/Server/Services/DatabaseServiceUpdateColumnsIfUnlocked.test.ts +342 -0
  105. package/Tests/Server/Services/DropFilterSaveValidation.test.ts +245 -0
  106. package/Tests/Server/Services/HostServiceUpdateLastSeen.test.ts +163 -15
  107. package/Tests/Server/Services/MetricTypeAttachServices.test.ts +222 -0
  108. package/Tests/Server/Services/MissingReferenceWriteGuard.test.ts +614 -0
  109. package/Tests/Server/Services/MonitorStatusTimelineFastPath.test.ts +23 -0
  110. package/Tests/Server/Services/OpenTelemetryServiceResolutionCache.test.ts +568 -0
  111. package/Tests/Server/Services/ResourceUpdateLastSeenLivenessFallback.test.ts +305 -56
  112. package/Tests/Server/Services/RestoreDroppedUniqueIndexesMigration.test.ts +386 -0
  113. package/Tests/Server/Services/RestoreServiceLowerNameIndexMigration.test.ts +240 -0
  114. package/Tests/Server/Services/ServiceUpdateLastSeenSplitGates.test.ts +705 -0
  115. package/Tests/Server/Services/StatusPageMonitorRuleEngineService.test.ts +1719 -0
  116. package/Tests/Server/Services/StatusPageMonitorRuleHooks.test.ts +1212 -0
  117. package/Tests/Server/Services/StatusPageMonitorRuleMonitorCreateHook.test.ts +228 -0
  118. package/Tests/Server/Services/UserServiceFirstMasterAdminElection.test.ts +885 -0
  119. package/Tests/Server/Services/WidenHashedStringColumnsForScryptMigration.test.ts +220 -0
  120. package/Tests/Server/Utils/AI/CodeTools.test.ts +47 -1
  121. package/Tests/Server/Utils/AI/CodeWriteTools.test.ts +10 -0
  122. package/Tests/Server/Utils/APIKey/AccessPermission.test.ts +267 -0
  123. package/Tests/Server/Utils/AnalyticsDatabase/StatementGenerator.test.ts +120 -0
  124. package/Tests/Server/Utils/CodeRepository/GitHubInstallationBinding.test.ts +292 -0
  125. package/Tests/Server/Utils/Database/ProjectScopedReferenceValidator.test.ts +260 -13
  126. package/Tests/Server/Utils/EntityRegistryRowFence.test.ts +302 -0
  127. package/Tests/Server/Utils/GitHubInstallationOwnershipVerification.test.ts +340 -0
  128. package/Tests/Server/Utils/GitHubWebhookAndTreeCacheIsolation.test.ts +250 -0
  129. package/Tests/Server/Utils/MetricTypeIndexConvergence.test.ts +598 -0
  130. package/Tests/Server/Utils/Monitor/MonitorStatusTimelineUnusableStatus.test.ts +154 -0
  131. package/Tests/Server/Utils/Monitor/MonitorStepsProjectValidator.test.ts +638 -92
  132. package/Tests/Server/Utils/Monitor/MonitorStepsReferenceExtractor.test.ts +724 -0
  133. package/Tests/Server/Utils/PasswordHash.test.ts +555 -0
  134. package/Tests/Server/Utils/SingleFlight.test.ts +221 -0
  135. package/Tests/Types/Dashboard/NetworkDashboardTemplate.test.ts +793 -0
  136. package/Tests/Types/Database/BigIntColumnTransformer.test.ts +147 -0
  137. package/Tests/Types/Database/ColumnLength.test.ts +7 -1
  138. package/Tests/Types/Database/DatabasePropertyTransformer.test.ts +140 -0
  139. package/Tests/Types/Database/NumericColumnValue.test.ts +127 -0
  140. package/Tests/Types/Decimal.test.ts +37 -0
  141. package/Tests/Types/HashedStringPerUserSalt.test.ts +476 -0
  142. package/Tests/Types/Monitor/DockerAlertTemplates.test.ts +293 -0
  143. package/Tests/Types/Monitor/HostAlertTemplates.test.ts +249 -0
  144. package/Tests/Types/Monitor/IotAlertTemplates.test.ts +320 -0
  145. package/Tests/Types/Monitor/PodmanAlertTemplates.test.ts +271 -0
  146. package/Tests/Types/Monitor/SnmpVersionParsing.test.ts +152 -0
  147. package/Tests/Types/Port.test.ts +38 -0
  148. package/Tests/UI/Components/CustomFields/CustomFieldsDetail.test.tsx +696 -0
  149. package/Tests/UI/Components/LogsHistogram.test.tsx +276 -0
  150. package/Tests/UI/Components/UseLiveLogsRefresh.test.tsx +489 -0
  151. package/Tests/UI/Components/UseLogsHistogram.test.tsx +500 -0
  152. package/Tests/UI/Utils/UserProjectsModelAPI.test.ts +714 -0
  153. package/Tests/Utils/Dashboard/Components/DashboardComponentsUtil.test.ts +120 -0
  154. package/Tests/Utils/Dashboard/DashboardNetworkMapComponent.test.ts +327 -0
  155. package/Tests/Utils/TeamMembersByProject.test.ts +655 -0
  156. package/Types/Dashboard/DashboardComponentType.ts +1 -0
  157. package/Types/Dashboard/DashboardComponents/ComponentArgument.ts +1 -0
  158. package/Types/Dashboard/DashboardComponents/DashboardNetworkMapComponent.ts +40 -0
  159. package/Types/Dashboard/DashboardTemplates.ts +397 -0
  160. package/Types/Database/BigIntColumnTransformer.ts +74 -0
  161. package/Types/Database/ColumnLength.ts +9 -1
  162. package/Types/Database/DatabaseProperty.ts +26 -0
  163. package/Types/Database/NumericColumnValue.ts +128 -0
  164. package/Types/Database/TableColumn.ts +11 -0
  165. package/Types/Database/UnsynchronizedIndex.ts +48 -0
  166. package/Types/Decimal.ts +16 -4
  167. package/Types/HashedString.ts +139 -4
  168. package/Types/Permission.ts +48 -0
  169. package/Types/Port.ts +16 -4
  170. package/UI/Components/CustomFields/CustomFieldsDetail.tsx +85 -11
  171. package/UI/Components/LogsViewer/useLiveLogsRefresh.ts +86 -0
  172. package/UI/Components/LogsViewer/useLogsHistogram.ts +113 -0
  173. package/UI/Components/Navbar/NavBar.tsx +12 -2
  174. package/UI/Components/Navbar/NavBarMenuModal.tsx +19 -7
  175. package/UI/Utils/ModelAPI/UserProjectsModelAPI.ts +257 -0
  176. package/Utils/Dashboard/Components/DashboardNetworkMapComponent.ts +136 -0
  177. package/Utils/Dashboard/Components/Index.ts +7 -0
  178. package/Utils/TeamMembersByProject.ts +237 -0
  179. package/build/dist/Models/DatabaseModels/CephCluster.js +16 -1
  180. package/build/dist/Models/DatabaseModels/CephCluster.js.map +1 -1
  181. package/build/dist/Models/DatabaseModels/CodeRepository.js +14 -6
  182. package/build/dist/Models/DatabaseModels/CodeRepository.js.map +1 -1
  183. package/build/dist/Models/DatabaseModels/DatabaseBaseModel/DatabaseBaseModel.js +12 -0
  184. package/build/dist/Models/DatabaseModels/DatabaseBaseModel/DatabaseBaseModel.js.map +1 -1
  185. package/build/dist/Models/DatabaseModels/DockerHost.js +16 -1
  186. package/build/dist/Models/DatabaseModels/DockerHost.js.map +1 -1
  187. package/build/dist/Models/DatabaseModels/GlobalOidcProject.js +16 -1
  188. package/build/dist/Models/DatabaseModels/GlobalOidcProject.js.map +1 -1
  189. package/build/dist/Models/DatabaseModels/GlobalSsoProject.js +16 -1
  190. package/build/dist/Models/DatabaseModels/GlobalSsoProject.js.map +1 -1
  191. package/build/dist/Models/DatabaseModels/Index.js +2 -0
  192. package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
  193. package/build/dist/Models/DatabaseModels/IoTFleet.js +16 -1
  194. package/build/dist/Models/DatabaseModels/IoTFleet.js.map +1 -1
  195. package/build/dist/Models/DatabaseModels/KubernetesCluster.js +16 -1
  196. package/build/dist/Models/DatabaseModels/KubernetesCluster.js.map +1 -1
  197. package/build/dist/Models/DatabaseModels/LogDropFilter.js +9 -20
  198. package/build/dist/Models/DatabaseModels/LogDropFilter.js.map +1 -1
  199. package/build/dist/Models/DatabaseModels/NetworkDevice.js +16 -1
  200. package/build/dist/Models/DatabaseModels/NetworkDevice.js.map +1 -1
  201. package/build/dist/Models/DatabaseModels/NetworkInterface.js +16 -1
  202. package/build/dist/Models/DatabaseModels/NetworkInterface.js.map +1 -1
  203. package/build/dist/Models/DatabaseModels/Project.js +16 -2
  204. package/build/dist/Models/DatabaseModels/Project.js.map +1 -1
  205. package/build/dist/Models/DatabaseModels/ProxmoxCluster.js +16 -1
  206. package/build/dist/Models/DatabaseModels/ProxmoxCluster.js.map +1 -1
  207. package/build/dist/Models/DatabaseModels/Service.js +28 -1
  208. package/build/dist/Models/DatabaseModels/Service.js.map +1 -1
  209. package/build/dist/Models/DatabaseModels/StatusPageMonitorRule.js +925 -0
  210. package/build/dist/Models/DatabaseModels/StatusPageMonitorRule.js.map +1 -0
  211. package/build/dist/Models/DatabaseModels/StatusPagePrivateUser.js +32 -0
  212. package/build/dist/Models/DatabaseModels/StatusPagePrivateUser.js.map +1 -1
  213. package/build/dist/Models/DatabaseModels/StatusPageResource.js +72 -0
  214. package/build/dist/Models/DatabaseModels/StatusPageResource.js.map +1 -1
  215. package/build/dist/Models/DatabaseModels/TraceDropFilter.js +9 -20
  216. package/build/dist/Models/DatabaseModels/TraceDropFilter.js.map +1 -1
  217. package/build/dist/Models/DatabaseModels/User.js +32 -0
  218. package/build/dist/Models/DatabaseModels/User.js.map +1 -1
  219. package/build/dist/Server/API/AIAgentDataAPI.js +21 -2
  220. package/build/dist/Server/API/AIAgentDataAPI.js.map +1 -1
  221. package/build/dist/Server/API/BaseAPI.js +11 -1
  222. package/build/dist/Server/API/BaseAPI.js.map +1 -1
  223. package/build/dist/Server/API/DashboardAPI.js +343 -10
  224. package/build/dist/Server/API/DashboardAPI.js.map +1 -1
  225. package/build/dist/Server/API/GitHubAPI.js +94 -167
  226. package/build/dist/Server/API/GitHubAPI.js.map +1 -1
  227. package/build/dist/Server/API/UserAPI.js +187 -2
  228. package/build/dist/Server/API/UserAPI.js.map +1 -1
  229. package/build/dist/Server/EnvironmentConfig.js +34 -4
  230. package/build/dist/Server/EnvironmentConfig.js.map +1 -1
  231. package/build/dist/Server/Infrastructure/GlobalCache.js +120 -0
  232. package/build/dist/Server/Infrastructure/GlobalCache.js.map +1 -1
  233. package/build/dist/Server/Infrastructure/Postgres/DataSourceOptions.js +5 -3
  234. package/build/dist/Server/Infrastructure/Postgres/DataSourceOptions.js.map +1 -1
  235. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786005052769-AddStatusPageMonitorRule.js +48 -0
  236. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786005052769-AddStatusPageMonitorRule.js.map +1 -0
  237. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786018109307-AddPerUserPasswordSalt.js +14 -0
  238. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786018109307-AddPerUserPasswordSalt.js.map +1 -0
  239. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786023262402-WidenHashedStringColumnsForScrypt.js +59 -0
  240. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786023262402-WidenHashedStringColumnsForScrypt.js.map +1 -0
  241. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786100000000-RestoreServiceLowerNameIndex.js +93 -0
  242. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786100000000-RestoreServiceLowerNameIndex.js.map +1 -0
  243. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786200000000-RestoreDroppedUniqueIndexes.js +101 -0
  244. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786200000000-RestoreDroppedUniqueIndexes.js.map +1 -0
  245. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786300000000-QuarantineUnboundGitHubInstallations.js +66 -0
  246. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786300000000-QuarantineUnboundGitHubInstallations.js.map +1 -0
  247. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +12 -0
  248. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  249. package/build/dist/Server/Services/AlertStateTimelineService.js +19 -0
  250. package/build/dist/Server/Services/AlertStateTimelineService.js.map +1 -1
  251. package/build/dist/Server/Services/AnalyticsDatabaseService.js +57 -1
  252. package/build/dist/Server/Services/AnalyticsDatabaseService.js.map +1 -1
  253. package/build/dist/Server/Services/CephClusterService.js +26 -76
  254. package/build/dist/Server/Services/CephClusterService.js.map +1 -1
  255. package/build/dist/Server/Services/CloudResourceService.js +23 -73
  256. package/build/dist/Server/Services/CloudResourceService.js.map +1 -1
  257. package/build/dist/Server/Services/CodeRepositoryService.js +90 -2
  258. package/build/dist/Server/Services/CodeRepositoryService.js.map +1 -1
  259. package/build/dist/Server/Services/DatabaseService.js +246 -2
  260. package/build/dist/Server/Services/DatabaseService.js.map +1 -1
  261. package/build/dist/Server/Services/DockerHostService.js +19 -69
  262. package/build/dist/Server/Services/DockerHostService.js.map +1 -1
  263. package/build/dist/Server/Services/DockerSwarmClusterService.js +27 -78
  264. package/build/dist/Server/Services/DockerSwarmClusterService.js.map +1 -1
  265. package/build/dist/Server/Services/HostService.js +58 -102
  266. package/build/dist/Server/Services/HostService.js.map +1 -1
  267. package/build/dist/Server/Services/IncidentStateTimelineService.js +19 -0
  268. package/build/dist/Server/Services/IncidentStateTimelineService.js.map +1 -1
  269. package/build/dist/Server/Services/Index.js +2 -0
  270. package/build/dist/Server/Services/Index.js.map +1 -1
  271. package/build/dist/Server/Services/IoTFleetService.js +19 -69
  272. package/build/dist/Server/Services/IoTFleetService.js.map +1 -1
  273. package/build/dist/Server/Services/KubernetesClusterService.js +17 -68
  274. package/build/dist/Server/Services/KubernetesClusterService.js.map +1 -1
  275. package/build/dist/Server/Services/LabelService.js +42 -7
  276. package/build/dist/Server/Services/LabelService.js.map +1 -1
  277. package/build/dist/Server/Services/MetricTypeService.js +74 -0
  278. package/build/dist/Server/Services/MetricTypeService.js.map +1 -1
  279. package/build/dist/Server/Services/MonitorService.js +81 -9
  280. package/build/dist/Server/Services/MonitorService.js.map +1 -1
  281. package/build/dist/Server/Services/MonitorStatusTimelineService.js +28 -0
  282. package/build/dist/Server/Services/MonitorStatusTimelineService.js.map +1 -1
  283. package/build/dist/Server/Services/MonitorTemplateService.js +60 -0
  284. package/build/dist/Server/Services/MonitorTemplateService.js.map +1 -1
  285. package/build/dist/Server/Services/OpenTelemetryIngestService.js +155 -25
  286. package/build/dist/Server/Services/OpenTelemetryIngestService.js.map +1 -1
  287. package/build/dist/Server/Services/PodmanHostService.js +19 -69
  288. package/build/dist/Server/Services/PodmanHostService.js.map +1 -1
  289. package/build/dist/Server/Services/ProxmoxClusterService.js +23 -73
  290. package/build/dist/Server/Services/ProxmoxClusterService.js.map +1 -1
  291. package/build/dist/Server/Services/RumApplicationService.js +19 -70
  292. package/build/dist/Server/Services/RumApplicationService.js.map +1 -1
  293. package/build/dist/Server/Services/ScheduledMaintenanceStateTimelineService.js +20 -0
  294. package/build/dist/Server/Services/ScheduledMaintenanceStateTimelineService.js.map +1 -1
  295. package/build/dist/Server/Services/ServerlessFunctionService.js +24 -75
  296. package/build/dist/Server/Services/ServerlessFunctionService.js.map +1 -1
  297. package/build/dist/Server/Services/ServiceService.js +236 -61
  298. package/build/dist/Server/Services/ServiceService.js.map +1 -1
  299. package/build/dist/Server/Services/StatusPageMonitorRuleEngineService.js +603 -0
  300. package/build/dist/Server/Services/StatusPageMonitorRuleEngineService.js.map +1 -0
  301. package/build/dist/Server/Services/StatusPageMonitorRuleService.js +401 -0
  302. package/build/dist/Server/Services/StatusPageMonitorRuleService.js.map +1 -0
  303. package/build/dist/Server/Services/TelemetryEntityRelationshipService.js +1 -0
  304. package/build/dist/Server/Services/TelemetryEntityRelationshipService.js.map +1 -1
  305. package/build/dist/Server/Services/TelemetryEntityService.js +1 -0
  306. package/build/dist/Server/Services/TelemetryEntityService.js.map +1 -1
  307. package/build/dist/Server/Services/UserService.js +165 -0
  308. package/build/dist/Server/Services/UserService.js.map +1 -1
  309. package/build/dist/Server/Utils/AI/Toolbox/CodeTools.js +31 -1
  310. package/build/dist/Server/Utils/AI/Toolbox/CodeTools.js.map +1 -1
  311. package/build/dist/Server/Utils/AnalyticsDatabase/StatementGenerator.js +13 -0
  312. package/build/dist/Server/Utils/AnalyticsDatabase/StatementGenerator.js.map +1 -1
  313. package/build/dist/Server/Utils/CodeRepository/GitHub/GitHub.js +126 -4
  314. package/build/dist/Server/Utils/CodeRepository/GitHub/GitHub.js.map +1 -1
  315. package/build/dist/Server/Utils/CodeRepository/GitHub/GitHubInstallationBinding.js +136 -0
  316. package/build/dist/Server/Utils/CodeRepository/GitHub/GitHubInstallationBinding.js.map +1 -0
  317. package/build/dist/Server/Utils/Database/ProjectScopedReferenceValidator.js +105 -29
  318. package/build/dist/Server/Utils/Database/ProjectScopedReferenceValidator.js.map +1 -1
  319. package/build/dist/Server/Utils/Monitor/MonitorResource.js +56 -32
  320. package/build/dist/Server/Utils/Monitor/MonitorResource.js.map +1 -1
  321. package/build/dist/Server/Utils/Monitor/MonitorStatusTimeline.js +30 -3
  322. package/build/dist/Server/Utils/Monitor/MonitorStatusTimeline.js.map +1 -1
  323. package/build/dist/Server/Utils/Monitor/MonitorStepsProjectValidator.js +110 -98
  324. package/build/dist/Server/Utils/Monitor/MonitorStepsProjectValidator.js.map +1 -1
  325. package/build/dist/Server/Utils/Monitor/MonitorStepsReferenceExtractor.js +312 -0
  326. package/build/dist/Server/Utils/Monitor/MonitorStepsReferenceExtractor.js.map +1 -0
  327. package/build/dist/Server/Utils/PasswordHash.js +237 -0
  328. package/build/dist/Server/Utils/PasswordHash.js.map +1 -0
  329. package/build/dist/Server/Utils/SingleFlight.js +76 -0
  330. package/build/dist/Server/Utils/SingleFlight.js.map +1 -0
  331. package/build/dist/Server/Utils/StatusPage/MonitorRulePatternValidator.js +29 -0
  332. package/build/dist/Server/Utils/StatusPage/MonitorRulePatternValidator.js.map +1 -0
  333. package/build/dist/Server/Utils/Telemetry/EntityRegistry.js +78 -19
  334. package/build/dist/Server/Utils/Telemetry/EntityRegistry.js.map +1 -1
  335. package/build/dist/Server/Utils/Telemetry/ResourceHeartbeat.js +160 -0
  336. package/build/dist/Server/Utils/Telemetry/ResourceHeartbeat.js.map +1 -0
  337. package/build/dist/Server/Utils/Telemetry/Telemetry.js +279 -104
  338. package/build/dist/Server/Utils/Telemetry/Telemetry.js.map +1 -1
  339. package/build/dist/Types/Dashboard/DashboardComponentType.js +1 -0
  340. package/build/dist/Types/Dashboard/DashboardComponentType.js.map +1 -1
  341. package/build/dist/Types/Dashboard/DashboardComponents/ComponentArgument.js +1 -0
  342. package/build/dist/Types/Dashboard/DashboardComponents/ComponentArgument.js.map +1 -1
  343. package/build/dist/Types/Dashboard/DashboardComponents/DashboardNetworkMapComponent.js +2 -0
  344. package/build/dist/Types/Dashboard/DashboardComponents/DashboardNetworkMapComponent.js.map +1 -0
  345. package/build/dist/Types/Dashboard/DashboardTemplates.js +368 -0
  346. package/build/dist/Types/Dashboard/DashboardTemplates.js.map +1 -1
  347. package/build/dist/Types/Database/BigIntColumnTransformer.js +66 -0
  348. package/build/dist/Types/Database/BigIntColumnTransformer.js.map +1 -0
  349. package/build/dist/Types/Database/ColumnLength.js +9 -1
  350. package/build/dist/Types/Database/ColumnLength.js.map +1 -1
  351. package/build/dist/Types/Database/DatabaseProperty.js +25 -0
  352. package/build/dist/Types/Database/DatabaseProperty.js.map +1 -1
  353. package/build/dist/Types/Database/NumericColumnValue.js +97 -0
  354. package/build/dist/Types/Database/NumericColumnValue.js.map +1 -0
  355. package/build/dist/Types/Database/TableColumn.js.map +1 -1
  356. package/build/dist/Types/Database/UnsynchronizedIndex.js +46 -0
  357. package/build/dist/Types/Database/UnsynchronizedIndex.js.map +1 -0
  358. package/build/dist/Types/Decimal.js +14 -3
  359. package/build/dist/Types/Decimal.js.map +1 -1
  360. package/build/dist/Types/HashedString.js +95 -5
  361. package/build/dist/Types/HashedString.js.map +1 -1
  362. package/build/dist/Types/Permission.js +42 -0
  363. package/build/dist/Types/Permission.js.map +1 -1
  364. package/build/dist/Types/Port.js +15 -5
  365. package/build/dist/Types/Port.js.map +1 -1
  366. package/build/dist/UI/Components/CustomFields/CustomFieldsDetail.js +51 -10
  367. package/build/dist/UI/Components/CustomFields/CustomFieldsDetail.js.map +1 -1
  368. package/build/dist/UI/Components/LogsViewer/useLiveLogsRefresh.js +44 -0
  369. package/build/dist/UI/Components/LogsViewer/useLiveLogsRefresh.js.map +1 -0
  370. package/build/dist/UI/Components/LogsViewer/useLogsHistogram.js +75 -0
  371. package/build/dist/UI/Components/LogsViewer/useLogsHistogram.js.map +1 -0
  372. package/build/dist/UI/Components/Navbar/NavBar.js +3 -1
  373. package/build/dist/UI/Components/Navbar/NavBar.js.map +1 -1
  374. package/build/dist/UI/Components/Navbar/NavBarMenuModal.js +19 -7
  375. package/build/dist/UI/Components/Navbar/NavBarMenuModal.js.map +1 -1
  376. package/build/dist/UI/Utils/ModelAPI/UserProjectsModelAPI.js +156 -0
  377. package/build/dist/UI/Utils/ModelAPI/UserProjectsModelAPI.js.map +1 -0
  378. package/build/dist/Utils/Dashboard/Components/DashboardNetworkMapComponent.js +114 -0
  379. package/build/dist/Utils/Dashboard/Components/DashboardNetworkMapComponent.js.map +1 -0
  380. package/build/dist/Utils/Dashboard/Components/Index.js +4 -0
  381. package/build/dist/Utils/Dashboard/Components/Index.js.map +1 -1
  382. package/build/dist/Utils/TeamMembersByProject.js +145 -0
  383. package/build/dist/Utils/TeamMembersByProject.js.map +1 -0
  384. package/package.json +1 -1
@@ -50,6 +50,7 @@ import PodmanResource from "../../Models/DatabaseModels/PodmanResource";
50
50
  import ProxmoxResource from "../../Models/DatabaseModels/ProxmoxResource";
51
51
  import CephResource from "../../Models/DatabaseModels/CephResource";
52
52
  import DockerSwarmResource from "../../Models/DatabaseModels/DockerSwarmResource";
53
+ import NetworkSite from "../../Models/DatabaseModels/NetworkSite";
53
54
  import Span from "../../Models/AnalyticsModels/Span";
54
55
  import Log from "../../Models/AnalyticsModels/Log";
55
56
  import IncidentService from "../Services/IncidentService";
@@ -64,9 +65,11 @@ import PodmanResourceService from "../Services/PodmanResourceService";
64
65
  import ProxmoxResourceService from "../Services/ProxmoxResourceService";
65
66
  import CephResourceService from "../Services/CephResourceService";
66
67
  import DockerSwarmResourceService from "../Services/DockerSwarmResourceService";
68
+ import NetworkSiteService from "../Services/NetworkSiteService";
67
69
  import SpanService from "../Services/SpanService";
68
70
  import LogService from "../Services/LogService";
69
71
  import DashboardComponentType from "../../Types/Dashboard/DashboardComponentType";
72
+ import { DashboardVariableType } from "../../Types/Dashboard/DashboardVariable";
70
73
  import Includes from "../../Types/BaseDatabase/Includes";
71
74
 
72
75
  /*
@@ -165,6 +168,43 @@ const PUBLIC_DASHBOARD_RESOURCES: Record<
165
168
  currentMonitorStatus: { name: true, color: true },
166
169
  },
167
170
  },
171
+ "network-site": {
172
+ modelType: NetworkSite,
173
+ service: NetworkSiteService,
174
+ widgets: {
175
+ [DashboardComponentType.NetworkMap]: null,
176
+ },
177
+ /*
178
+ * The map filters by site type and by whether the rolled-up status is
179
+ * operational — nothing else. Notably NOT `parentSiteId` or
180
+ * `materializedPath`: the widget draws a flat set of pins rather than
181
+ * walking a hierarchy, so exposing the tree shape here would hand an
182
+ * anonymous viewer a structure the map never shows them.
183
+ */
184
+ allowedQueryKeys: [
185
+ "networkSiteTypeId",
186
+ "currentMonitorStatus",
187
+ "currentMonitorStatusId",
188
+ ],
189
+ select: {
190
+ _id: true,
191
+ name: true,
192
+ /*
193
+ * The type NAME comes from the networkSiteType relation. NetworkSite
194
+ * .siteType is the deprecated pre-lookup-table string and is dropped
195
+ * in a follow-up PR, so it must not be read from new code.
196
+ */
197
+ networkSiteType: { name: true },
198
+ latitude: true,
199
+ longitude: true,
200
+ currentMonitorStatus: {
201
+ name: true,
202
+ color: true,
203
+ priority: true,
204
+ isOperationalState: true,
205
+ },
206
+ },
207
+ },
168
208
  host: {
169
209
  modelType: Host,
170
210
  service: HostService,
@@ -955,6 +995,14 @@ export default class DashboardAPI extends BaseAPI<
955
995
  * the behaviour here scoped to the dashboard's owning projectId.
956
996
  * Authorization reuses DashboardService.hasReadAccess (public flag, IP
957
997
  * whitelist, master password) — never falls back to project-wide read.
998
+ *
999
+ * The requested attribute key is additionally allowlisted against the
1000
+ * keys this dashboard's own variables bind to. Project scoping alone is
1001
+ * not enough here: the underlying query is a SELECT DISTINCT over the
1002
+ * attribute map of every log, span, metric and exception in the project,
1003
+ * so an unrestricted key would let anyone holding a public dashboard id
1004
+ * read `user.email`, `db.statement`, `http.url`, ... out of telemetry the
1005
+ * dashboard never renders (GHSA-w332-x78m-vf3v).
958
1006
  */
959
1007
  this.router.post(
960
1008
  `${new this.entityType()
@@ -982,10 +1030,11 @@ export default class DashboardAPI extends BaseAPI<
982
1030
  );
983
1031
  }
984
1032
 
985
- const attributeKey: string | undefined =
986
- req.body && (req.body["attributeKey"] as string);
1033
+ const attributeKey: unknown = req.body
1034
+ ? req.body["attributeKey"]
1035
+ : undefined;
987
1036
 
988
- if (!attributeKey || !attributeKey.trim()) {
1037
+ if (typeof attributeKey !== "string" || !attributeKey.trim()) {
989
1038
  throw new BadDataException("attributeKey is required.");
990
1039
  }
991
1040
 
@@ -1009,6 +1058,7 @@ export default class DashboardAPI extends BaseAPI<
1009
1058
  select: {
1010
1059
  _id: true,
1011
1060
  projectId: true,
1061
+ dashboardViewConfig: true,
1012
1062
  },
1013
1063
  props: {
1014
1064
  isRoot: true,
@@ -1019,11 +1069,32 @@ export default class DashboardAPI extends BaseAPI<
1019
1069
  throw new NotFoundException("Dashboard not found");
1020
1070
  }
1021
1071
 
1072
+ /*
1073
+ * Only the attribute keys this dashboard's own variable dropdowns
1074
+ * offer may be read. Variable interpolation only ever substitutes
1075
+ * a variable's VALUE into a widget filter — never its key — so the
1076
+ * stored view config is an exact allowlist. A dashboard with no
1077
+ * telemetry-attribute variables has nothing to look up and is
1078
+ * refused outright.
1079
+ */
1080
+ const requestedAttributeKey: string = attributeKey.trim();
1081
+
1082
+ const allowedAttributeKeys: Set<string> =
1083
+ DashboardAPI.collectDashboardVariableAttributeKeys(
1084
+ dashboard.dashboardViewConfig,
1085
+ );
1086
+
1087
+ if (!allowedAttributeKeys.has(requestedAttributeKey)) {
1088
+ throw new BadDataException(
1089
+ "This attribute is not part of this dashboard.",
1090
+ );
1091
+ }
1092
+
1022
1093
  const values: Array<string> =
1023
1094
  await TelemetryAttributeService.fetchAttributeValues({
1024
1095
  projectId: dashboard.projectId,
1025
1096
  telemetryType,
1026
- attributeKey: attributeKey.trim(),
1097
+ attributeKey: requestedAttributeKey,
1027
1098
  });
1028
1099
 
1029
1100
  return Response.sendJsonObjectResponse(req, res, {
@@ -1226,9 +1297,25 @@ export default class DashboardAPI extends BaseAPI<
1226
1297
  DashboardAPI.collectDashboardMetricNames(
1227
1298
  dashboard.dashboardViewConfig,
1228
1299
  );
1229
- const requestedMetricName: unknown = aggregateBy.query
1230
- ? (aggregateBy.query as Record<string, unknown>)["name"]
1231
- : undefined;
1300
+
1301
+ /*
1302
+ * Read the query through an OWN-properties copy. JSON.parse turns a
1303
+ * literal "__proto__" member into a real own key and
1304
+ * JSONFunctions.deserialize copies it with `newVal[key] = ...`,
1305
+ * which fires Object.prototype's __proto__ setter — so a plain
1306
+ * `query["name"]` lookup walks the prototype chain and sees a name
1307
+ * that a later own-properties spread would silently drop, leaving
1308
+ * the aggregation with no metric predicate at all. The check and
1309
+ * the object that reaches the database must read the same keys.
1310
+ */
1311
+ const requestedQuery: Record<string, unknown> =
1312
+ aggregateBy.query &&
1313
+ typeof aggregateBy.query === "object" &&
1314
+ !Array.isArray(aggregateBy.query)
1315
+ ? { ...(aggregateBy.query as Record<string, unknown>) }
1316
+ : {};
1317
+
1318
+ const requestedMetricName: unknown = requestedQuery["name"];
1232
1319
 
1233
1320
  if (
1234
1321
  typeof requestedMetricName !== "string" ||
@@ -1240,14 +1327,156 @@ export default class DashboardAPI extends BaseAPI<
1240
1327
  }
1241
1328
 
1242
1329
  /*
1243
- * Security: never trust a client-supplied projectId on a public,
1244
- * unauthenticated endpoint. Pin the aggregation to the dashboard's
1245
- * project before it reaches the database service.
1330
+ * Pinning the metric name is not enough on its own: a grouped
1331
+ * aggregation echoes each group's key back in the result rows, so
1332
+ * `groupByAttributeKeys: ["enduser.id"]` or the blunter
1333
+ * `groupBy: { attributes: true }`, which returns the WHOLE
1334
+ * attribute map — turns an allowlisted metric into a reader for
1335
+ * attribute values the widget never renders. Both grouping
1336
+ * dimensions are therefore allowlisted against the stored view
1337
+ * config as well; interpolation never rewrites either of them.
1338
+ */
1339
+ const allowedGroupByAttributeKeys: Set<string> =
1340
+ DashboardAPI.collectDashboardGroupByAttributeKeys(
1341
+ dashboard.dashboardViewConfig,
1342
+ );
1343
+ const requestedGroupByAttributeKeys: unknown =
1344
+ aggregateBy.groupByAttributeKeys;
1345
+
1346
+ /*
1347
+ * `null` means "not grouped" here: JSONFunctions.serialize drops
1348
+ * undefined but preserves null, and both downstream sinks already
1349
+ * treat a null grouping as absent.
1350
+ */
1351
+ if (
1352
+ requestedGroupByAttributeKeys !== undefined &&
1353
+ requestedGroupByAttributeKeys !== null
1354
+ ) {
1355
+ if (!Array.isArray(requestedGroupByAttributeKeys)) {
1356
+ throw new BadDataException(
1357
+ "groupByAttributeKeys must be an array of attribute keys.",
1358
+ );
1359
+ }
1360
+
1361
+ for (const requestedKey of requestedGroupByAttributeKeys) {
1362
+ if (
1363
+ typeof requestedKey !== "string" ||
1364
+ !allowedGroupByAttributeKeys.has(requestedKey)
1365
+ ) {
1366
+ throw new BadDataException(
1367
+ "This attribute is not part of this dashboard.",
1368
+ );
1369
+ }
1370
+ }
1371
+ }
1372
+
1373
+ const allowedGroupByColumns: Set<string> =
1374
+ DashboardAPI.collectDashboardGroupByColumns(
1375
+ dashboard.dashboardViewConfig,
1376
+ );
1377
+ const requestedGroupBy: unknown = aggregateBy.groupBy;
1378
+
1379
+ if (requestedGroupBy !== undefined && requestedGroupBy !== null) {
1380
+ if (
1381
+ typeof requestedGroupBy !== "object" ||
1382
+ Array.isArray(requestedGroupBy)
1383
+ ) {
1384
+ throw new BadDataException("groupBy must be an object.");
1385
+ }
1386
+
1387
+ for (const requestedColumn of Object.keys(requestedGroupBy)) {
1388
+ if (!allowedGroupByColumns.has(requestedColumn)) {
1389
+ throw new BadDataException(
1390
+ "This grouping is not part of this dashboard.",
1391
+ );
1392
+ }
1393
+ }
1394
+
1395
+ /*
1396
+ * Hand the SQL builder the same keys this guard validated. The
1397
+ * guard reads Object.keys but the GROUP BY builder walks the
1398
+ * object with for...in, so an inherited key would otherwise
1399
+ * reach the query without ever being checked.
1400
+ */
1401
+ aggregateBy.groupBy = {
1402
+ ...(requestedGroupBy as Record<string, unknown>),
1403
+ } as typeof aggregateBy.groupBy;
1404
+ }
1405
+
1406
+ /*
1407
+ * The client never chooses what is aggregated over what: every
1408
+ * widget aggregates `value` over `time`. Left open, an anonymous
1409
+ * caller could aggregate `attributes` instead — `max(attributes)`
1410
+ * returns the whole map and the row mapper passes non-numeric
1411
+ * aggregates through untouched, handing back a full attribute map
1412
+ * per time bucket.
1413
+ */
1414
+ if (aggregateBy.aggregateColumnName !== "value") {
1415
+ throw new BadDataException("Invalid aggregateColumnName.");
1416
+ }
1417
+
1418
+ if (aggregateBy.aggregationTimestampColumnName !== "time") {
1419
+ throw new BadDataException(
1420
+ "Invalid aggregationTimestampColumnName.",
1421
+ );
1422
+ }
1423
+
1424
+ // Never let an anonymous caller choose an unbounded page.
1425
+ aggregateBy.limit = Math.min(
1426
+ Math.max(Number(aggregateBy.limit) || LIMIT_PER_PROJECT, 1),
1427
+ LIMIT_PER_PROJECT,
1428
+ );
1429
+ aggregateBy.skip = Math.max(Number(aggregateBy.skip) || 0, 0);
1430
+
1431
+ /*
1432
+ * Security: the client does not get to choose what is filtered on a
1433
+ * public, unauthenticated endpoint. Rebuild the query from the
1434
+ * fields the dashboard's own widgets legitimately send — the
1435
+ * allowlisted metric name, the time window, and attribute filters
1436
+ * on keys those widgets already filter by — and pin the project.
1437
+ * Everything else the client sent is dropped rather than merged: a
1438
+ * foreign projectId, a filter on an arbitrary attribute key used as
1439
+ * a blind ILIKE oracle, a key smuggled in on the prototype
1440
+ * (GHSA-w332-x78m-vf3v).
1246
1441
  */
1442
+ const allowedFilterAttributeKeys: Set<string> =
1443
+ DashboardAPI.collectDashboardFilterAttributeKeys(
1444
+ dashboard.dashboardViewConfig,
1445
+ );
1446
+
1447
+ const sanitizedAttributes: Record<string, unknown> = {};
1448
+ const requestedAttributes: unknown = requestedQuery["attributes"];
1449
+
1450
+ if (
1451
+ requestedAttributes &&
1452
+ typeof requestedAttributes === "object" &&
1453
+ !Array.isArray(requestedAttributes)
1454
+ ) {
1455
+ for (const requestedAttributeKey of Object.keys(
1456
+ requestedAttributes as Record<string, unknown>,
1457
+ )) {
1458
+ if (!allowedFilterAttributeKeys.has(requestedAttributeKey)) {
1459
+ throw new BadDataException(
1460
+ "This attribute is not part of this dashboard.",
1461
+ );
1462
+ }
1463
+
1464
+ sanitizedAttributes[requestedAttributeKey] = (
1465
+ requestedAttributes as Record<string, unknown>
1466
+ )[requestedAttributeKey];
1467
+ }
1468
+ }
1469
+
1247
1470
  aggregateBy.query = {
1248
- ...(aggregateBy.query || {}),
1471
+ name: requestedMetricName,
1472
+ ...(requestedQuery["time"] !== undefined
1473
+ ? { time: requestedQuery["time"] }
1474
+ : {}),
1475
+ ...(Object.keys(sanitizedAttributes).length > 0
1476
+ ? { attributes: sanitizedAttributes }
1477
+ : {}),
1249
1478
  projectId: dashboard.projectId,
1250
- };
1479
+ } as unknown as typeof aggregateBy.query;
1251
1480
 
1252
1481
  const aggregateResult: AggregatedResult =
1253
1482
  await MetricService.aggregateBy(aggregateBy);
@@ -1479,6 +1708,223 @@ export default class DashboardAPI extends BaseAPI<
1479
1708
  return metricNames;
1480
1709
  }
1481
1710
 
1711
+ /*
1712
+ * Walk a stored dashboard view config and collect every OpenTelemetry
1713
+ * attribute key its variables bind to (a `Telemetry Attribute` variable
1714
+ * carries the key its dropdown lists values for). Used as the allowlist
1715
+ * for the public attribute-values endpoint, so an anonymous viewer can
1716
+ * only read the values behind this dashboard's own variable pickers and
1717
+ * not every attribute in the owning project.
1718
+ */
1719
+ private static collectDashboardVariableAttributeKeys(
1720
+ dashboardViewConfig: unknown,
1721
+ ): Set<string> {
1722
+ const attributeKeys: Set<string> = new Set<string>();
1723
+
1724
+ const walk: (node: unknown) => void = (node: unknown): void => {
1725
+ if (!node || typeof node !== "object") {
1726
+ return;
1727
+ }
1728
+
1729
+ if (Array.isArray(node)) {
1730
+ for (const item of node) {
1731
+ walk(item);
1732
+ }
1733
+ return;
1734
+ }
1735
+
1736
+ const obj: Record<string, unknown> = node as Record<string, unknown>;
1737
+
1738
+ if (obj["type"] === DashboardVariableType.TelemetryAttribute) {
1739
+ const attributeKey: unknown = obj["attributeKey"];
1740
+
1741
+ if (
1742
+ typeof attributeKey === "string" &&
1743
+ attributeKey.trim().length > 0
1744
+ ) {
1745
+ attributeKeys.add(attributeKey.trim());
1746
+ }
1747
+ }
1748
+
1749
+ for (const key of Object.keys(obj)) {
1750
+ walk(obj[key]);
1751
+ }
1752
+ };
1753
+
1754
+ walk(dashboardViewConfig);
1755
+
1756
+ return attributeKeys;
1757
+ }
1758
+
1759
+ /*
1760
+ * Walk a stored dashboard view config and collect every OpenTelemetry
1761
+ * attribute key its metric widgets group by — `groupByAttributeKeys`
1762
+ * (chart / value / gauge / legacy table queries) and `groupByAttributes`
1763
+ * (the table widget's richer per-key form). Used as the allowlist for the
1764
+ * public metric-aggregate endpoint, whose grouped results echo each
1765
+ * group's key values back to the caller.
1766
+ */
1767
+ private static collectDashboardGroupByAttributeKeys(
1768
+ dashboardViewConfig: unknown,
1769
+ ): Set<string> {
1770
+ const attributeKeys: Set<string> = new Set<string>();
1771
+
1772
+ const addKey: (value: unknown) => void = (value: unknown): void => {
1773
+ if (typeof value === "string" && value.length > 0) {
1774
+ attributeKeys.add(value);
1775
+ }
1776
+ };
1777
+
1778
+ const walk: (node: unknown) => void = (node: unknown): void => {
1779
+ if (!node || typeof node !== "object") {
1780
+ return;
1781
+ }
1782
+
1783
+ if (Array.isArray(node)) {
1784
+ for (const item of node) {
1785
+ walk(item);
1786
+ }
1787
+ return;
1788
+ }
1789
+
1790
+ const obj: Record<string, unknown> = node as Record<string, unknown>;
1791
+
1792
+ const groupByAttributeKeys: unknown = obj["groupByAttributeKeys"];
1793
+ if (Array.isArray(groupByAttributeKeys)) {
1794
+ for (const key of groupByAttributeKeys) {
1795
+ addKey(key);
1796
+ }
1797
+ }
1798
+
1799
+ const groupByAttributes: unknown = obj["groupByAttributes"];
1800
+ if (Array.isArray(groupByAttributes)) {
1801
+ for (const groupByAttribute of groupByAttributes) {
1802
+ if (groupByAttribute && typeof groupByAttribute === "object") {
1803
+ addKey((groupByAttribute as Record<string, unknown>)["key"]);
1804
+ }
1805
+ }
1806
+ }
1807
+
1808
+ for (const key of Object.keys(obj)) {
1809
+ walk(obj[key]);
1810
+ }
1811
+ };
1812
+
1813
+ walk(dashboardViewConfig);
1814
+
1815
+ return attributeKeys;
1816
+ }
1817
+
1818
+ /*
1819
+ * Attribute keys a public metric aggregation may FILTER on.
1820
+ *
1821
+ * Two sources, and both are needed:
1822
+ *
1823
+ * - Keys the widgets themselves persist — `filterData.attributes` on a
1824
+ * chart/value/gauge query, and the table widget's widget-level
1825
+ * `attributeFilters`.
1826
+ * - Keys the dashboard's `Telemetry Attribute` variables bind to. The
1827
+ * shipped templates store `filterData: { metricName, aggegationType }`
1828
+ * and no attributes at all; the filter on e.g.
1829
+ * `resource.k8s.cluster.name` only appears once the viewer picks a value
1830
+ * and DashboardVariableInterpolation injects it at render time. An
1831
+ * allowlist built from stored filters alone would refuse every real
1832
+ * templated dashboard the moment its variable is used.
1833
+ */
1834
+ private static collectDashboardFilterAttributeKeys(
1835
+ dashboardViewConfig: unknown,
1836
+ ): Set<string> {
1837
+ const attributeKeys: Set<string> =
1838
+ DashboardAPI.collectDashboardVariableAttributeKeys(dashboardViewConfig);
1839
+
1840
+ const addKeysOf: (value: unknown) => void = (value: unknown): void => {
1841
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
1842
+ return;
1843
+ }
1844
+
1845
+ for (const key of Object.keys(value as Record<string, unknown>)) {
1846
+ if (key.length > 0) {
1847
+ attributeKeys.add(key);
1848
+ }
1849
+ }
1850
+ };
1851
+
1852
+ const walk: (node: unknown) => void = (node: unknown): void => {
1853
+ if (!node || typeof node !== "object") {
1854
+ return;
1855
+ }
1856
+
1857
+ if (Array.isArray(node)) {
1858
+ for (const item of node) {
1859
+ walk(item);
1860
+ }
1861
+ return;
1862
+ }
1863
+
1864
+ const obj: Record<string, unknown> = node as Record<string, unknown>;
1865
+
1866
+ const filterData: unknown = obj["filterData"];
1867
+ if (filterData && typeof filterData === "object") {
1868
+ addKeysOf((filterData as Record<string, unknown>)["attributes"]);
1869
+ }
1870
+
1871
+ addKeysOf(obj["attributeFilters"]);
1872
+
1873
+ for (const key of Object.keys(obj)) {
1874
+ walk(obj[key]);
1875
+ }
1876
+ };
1877
+
1878
+ walk(dashboardViewConfig);
1879
+
1880
+ return attributeKeys;
1881
+ }
1882
+
1883
+ /*
1884
+ * Walk a stored dashboard view config and collect every model column its
1885
+ * widgets group by. Used as the allowlist for the public metric-aggregate
1886
+ * endpoint: grouping echoes the grouped column back in every result row,
1887
+ * so `groupBy: { attributes: true }` would hand an anonymous viewer the
1888
+ * entire attribute map of an allowlisted metric.
1889
+ */
1890
+ private static collectDashboardGroupByColumns(
1891
+ dashboardViewConfig: unknown,
1892
+ ): Set<string> {
1893
+ const groupByColumns: Set<string> = new Set<string>();
1894
+
1895
+ const walk: (node: unknown) => void = (node: unknown): void => {
1896
+ if (!node || typeof node !== "object") {
1897
+ return;
1898
+ }
1899
+
1900
+ if (Array.isArray(node)) {
1901
+ for (const item of node) {
1902
+ walk(item);
1903
+ }
1904
+ return;
1905
+ }
1906
+
1907
+ const obj: Record<string, unknown> = node as Record<string, unknown>;
1908
+
1909
+ const groupBy: unknown = obj["groupBy"];
1910
+ if (groupBy && typeof groupBy === "object" && !Array.isArray(groupBy)) {
1911
+ for (const column of Object.keys(groupBy as Record<string, unknown>)) {
1912
+ if ((groupBy as Record<string, unknown>)[column]) {
1913
+ groupByColumns.add(column);
1914
+ }
1915
+ }
1916
+ }
1917
+
1918
+ for (const key of Object.keys(obj)) {
1919
+ walk(obj[key]);
1920
+ }
1921
+ };
1922
+
1923
+ walk(dashboardViewConfig);
1924
+
1925
+ return groupByColumns;
1926
+ }
1927
+
1482
1928
  /*
1483
1929
  * Walk a stored dashboard view config and collect every widget type it
1484
1930
  * renders. Used to build an allowlist for the public resource-list