@oneuptime/common 12.0.31 → 12.0.33

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 (747) hide show
  1. package/Models/AnalyticsModels/Span.ts +14 -0
  2. package/Models/DatabaseModels/AlertState.ts +0 -2
  3. package/Models/DatabaseModels/Domain.ts +1 -1
  4. package/Models/DatabaseModels/EnterpriseLicense.ts +56 -0
  5. package/Models/DatabaseModels/Incident.ts +1 -1
  6. package/Models/DatabaseModels/IncidentTemplate.ts +1 -1
  7. package/Models/DatabaseModels/Index.ts +12 -0
  8. package/Models/DatabaseModels/MetricType.ts +0 -2
  9. package/Models/DatabaseModels/Monitor.ts +76 -0
  10. package/Models/DatabaseModels/MonitorStatusTimeline.ts +0 -2
  11. package/Models/DatabaseModels/MonitorTest.ts +0 -2
  12. package/Models/DatabaseModels/NetworkAlertPolicy.ts +690 -0
  13. package/Models/DatabaseModels/NetworkDevice.ts +297 -3
  14. package/Models/DatabaseModels/NetworkDeviceOidTemplate.ts +3 -1
  15. package/Models/DatabaseModels/NetworkDeviceRole.ts +648 -0
  16. package/Models/DatabaseModels/NetworkSite.ts +201 -2
  17. package/Models/DatabaseModels/NetworkSiteType.ts +102 -3
  18. package/Models/DatabaseModels/NetworkSnmpCredentialProfile.ts +841 -0
  19. package/Models/DatabaseModels/ScheduledMaintenance.ts +1 -1
  20. package/Models/DatabaseModels/ScheduledMaintenanceTemplate.ts +1 -1
  21. package/Models/DatabaseModels/StatusPageAnnouncement.ts +0 -2
  22. package/Models/DatabaseModels/StatusPageAnnouncementTemplate.ts +0 -2
  23. package/Models/DatabaseModels/StatusPagePrivateUser.ts +0 -2
  24. package/Models/DatabaseModels/StatusPageResource.ts +0 -2
  25. package/Models/DatabaseModels/StatusPageSubscriber.ts +0 -2
  26. package/Models/DatabaseModels/TelemetryException.ts +119 -0
  27. package/Models/DatabaseModels/UserNotificationEmailRollupBatch.ts +334 -0
  28. package/Models/DatabaseModels/UserNotificationEmailRollupItem.ts +370 -0
  29. package/Models/DatabaseModels/UserNotificationEmailRollupSetting.ts +282 -0
  30. package/Server/API/EnterpriseLicenseAPI.ts +391 -64
  31. package/Server/API/LlmProviderAPI.ts +137 -22
  32. package/Server/EnvironmentConfig.ts +14 -0
  33. package/Server/Infrastructure/Postgres/SchemaMigrations/1790700000000-AddNetworkSiteTypeParentHierarchy.ts +55 -0
  34. package/Server/Infrastructure/Postgres/SchemaMigrations/1790800000000-AddNetworkDeviceRoleTable.ts +72 -0
  35. package/Server/Infrastructure/Postgres/SchemaMigrations/1790900000000-AddEnterpriseLicenseUsageProvenance.ts +31 -0
  36. package/Server/Infrastructure/Postgres/SchemaMigrations/1790900000000-AddTelemetryExceptionErrorClass.ts +124 -0
  37. package/Server/Infrastructure/Postgres/SchemaMigrations/1791000000000-AddUserNotificationEmailRollup.ts +132 -0
  38. package/Server/Infrastructure/Postgres/SchemaMigrations/1791100000000-AddUserNotificationEmailRollupSetting.ts +79 -0
  39. package/Server/Infrastructure/Postgres/SchemaMigrations/1791200000000-AddNetworkSnmpCredentialProfilesAndAlertPolicies.ts +191 -0
  40. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +14 -0
  41. package/Server/Infrastructure/QueueWorker.ts +38 -8
  42. package/Server/Middleware/BearerTokenAuthorization.ts +12 -0
  43. package/Server/Middleware/ProjectAuthorization.ts +11 -0
  44. package/Server/Middleware/SCIMAuthorization.ts +12 -0
  45. package/Server/Middleware/TelemetryIngest.ts +11 -0
  46. package/Server/Services/AIBillingService.ts +101 -27
  47. package/Server/Services/DatabaseService.ts +39 -9
  48. package/Server/Services/EnterpriseLicenseInstanceService.ts +197 -0
  49. package/Server/Services/EnterpriseLicenseService.ts +55 -0
  50. package/Server/Services/Index.ts +12 -0
  51. package/Server/Services/MonitorService.ts +143 -21
  52. package/Server/Services/MonitorStatusTimelineService.ts +150 -8
  53. package/Server/Services/MonitorTemplateService.ts +217 -1
  54. package/Server/Services/NetworkAlertPolicyEngineService.ts +2159 -0
  55. package/Server/Services/NetworkAlertPolicyService.ts +944 -0
  56. package/Server/Services/NetworkDeviceAutoImportRuleEngineService.ts +9 -10
  57. package/Server/Services/NetworkDeviceAutoImportRuleService.ts +60 -15
  58. package/Server/Services/NetworkDeviceRoleService.ts +90 -0
  59. package/Server/Services/NetworkDeviceService.ts +1032 -73
  60. package/Server/Services/NetworkSiteService.ts +1502 -129
  61. package/Server/Services/NetworkSiteTypeService.ts +1216 -0
  62. package/Server/Services/NetworkSnmpCredentialProfileService.ts +238 -0
  63. package/Server/Services/NotificationService.ts +118 -28
  64. package/Server/Services/ProjectService.ts +186 -44
  65. package/Server/Services/StatusPagePrivateUserService.ts +103 -3
  66. package/Server/Services/UserNotificationEmailRollupBatchService.ts +78 -0
  67. package/Server/Services/UserNotificationEmailRollupItemService.ts +79 -0
  68. package/Server/Services/UserNotificationEmailRollupSettingService.ts +113 -0
  69. package/Server/Services/UserNotificationSettingService.ts +62 -31
  70. package/Server/Services/UserService.ts +95 -0
  71. package/Server/Types/Database/QueryHelper.ts +2 -2
  72. package/Server/Utils/AI/Chat/ObservabilityChatPrompt.ts +14 -3
  73. package/Server/Utils/AI/SRE/Insights/Detectors/ExceptionSpikeDetector.ts +10 -0
  74. package/Server/Utils/AI/SRE/Insights/Detectors/NewExceptionDetector.ts +10 -0
  75. package/Server/Utils/AI/SRE/Insights/InsightTriageRunner.ts +62 -1
  76. package/Server/Utils/AI/Toolbox/AlertTools.ts +15 -1
  77. package/Server/Utils/Billing/BillingFailureNoticeThrottle.ts +80 -0
  78. package/Server/Utils/DataSource/HttpFetch.ts +9 -2
  79. package/Server/Utils/EmailRollup/EmailRollupConstants.ts +98 -0
  80. package/Server/Utils/EmailRollup/EmailRollupFlushRunner.ts +872 -0
  81. package/Server/Utils/EmailRollup/EmailRollupRenderer.ts +781 -0
  82. package/Server/Utils/EmailRollup/EmailRollupWriter.ts +368 -0
  83. package/Server/Utils/LLM/LLMService.ts +78 -0
  84. package/Server/Utils/LogRedaction.ts +8 -0
  85. package/Server/Utils/Logger.ts +79 -1
  86. package/Server/Utils/Monitor/Criteria/DatabaseMonitorCriteria.ts +190 -0
  87. package/Server/Utils/Monitor/Criteria/EvaluateOverTime.ts +9 -2
  88. package/Server/Utils/Monitor/Criteria/SnmpMonitorCriteria.ts +61 -1
  89. package/Server/Utils/Monitor/MonitorCriteriaDataExtractor.ts +14 -0
  90. package/Server/Utils/Monitor/MonitorCriteriaEvaluator.ts +49 -0
  91. package/Server/Utils/Monitor/MonitorCriteriaObservationBuilder.ts +255 -4
  92. package/Server/Utils/Monitor/MonitorMetricUtil.ts +41 -0
  93. package/Server/Utils/Monitor/MonitorTemplateUtil.ts +43 -0
  94. package/Server/Utils/Monitor/NetworkDeviceHydrationUtil.ts +499 -19
  95. package/Server/Utils/Monitor/NetworkDeviceMetricUtil.ts +66 -10
  96. package/Server/Utils/Monitor/NetworkDeviceWalkUtil.ts +238 -44
  97. package/Server/Utils/Monitor/NetworkInventoryUtil.ts +146 -39
  98. package/Server/Utils/NetworkDevice/DeviceHealthAggregation.ts +31 -18
  99. package/Server/Utils/NetworkSite/NetworkSiteHierarchyLock.ts +213 -0
  100. package/Server/Utils/OutboundUserAgent.ts +152 -0
  101. package/Server/Utils/StartServer.ts +51 -19
  102. package/Server/Utils/Telemetry/CaptureSpan.ts +32 -8
  103. package/Server/Utils/Telemetry/ErrorClassResolver.ts +120 -0
  104. package/Server/Utils/Telemetry/SpanUtil.ts +33 -0
  105. package/Server/Utils/Telemetry.ts +198 -51
  106. package/Server/Views/Partials/SensitiveUrlToken.ejs +140 -0
  107. package/Tests/App/Dashboard/AddNeighborToMonitoringModal.test.tsx +158 -27
  108. package/Tests/App/Dashboard/AskAiSuggestedPrompts.test.ts +279 -0
  109. package/Tests/App/Dashboard/DashboardChartWidgetZoom.test.tsx +35 -8
  110. package/Tests/App/Dashboard/DashboardCommandPalette.test.tsx +107 -3
  111. package/Tests/App/Dashboard/DashboardEditPermissions.test.tsx +517 -0
  112. package/Tests/App/Dashboard/DashboardVariablesDiscard.test.tsx +26 -0
  113. package/Tests/App/Dashboard/DashboardWideChartZoom.test.tsx +401 -0
  114. package/Tests/App/Dashboard/DeviceStatusHero.test.tsx +588 -0
  115. package/Tests/App/Dashboard/DiscoveryScanWizardValidation.test.tsx +18 -9
  116. package/Tests/App/Dashboard/MonitorCreateFromMonitorBackedDevice.test.tsx +632 -0
  117. package/Tests/App/Dashboard/MonitorRecommendationCreateProgress.test.tsx +682 -0
  118. package/Tests/App/Dashboard/MonitorTemplateColumnAndFacet.test.tsx +318 -0
  119. package/Tests/App/Dashboard/MonitorTypePicker.test.tsx +4 -2
  120. package/Tests/App/Dashboard/NetworkDeviceBulkDelete.test.tsx +357 -0
  121. package/Tests/App/Dashboard/NetworkDeviceCreateFormMonitorBinding.test.tsx +676 -0
  122. package/Tests/App/Dashboard/NetworkDeviceCreateFormPingMonitor.test.tsx +791 -0
  123. package/Tests/App/Dashboard/NetworkDeviceCreateFormProbeAndSnmp.test.tsx +833 -0
  124. package/Tests/App/Dashboard/NetworkDeviceCriteriaFilter.test.ts +161 -0
  125. package/Tests/App/Dashboard/NetworkDeviceSettingsMonitoringSection.test.tsx +458 -0
  126. package/Tests/App/Dashboard/NetworkSideMenu.test.tsx +626 -0
  127. package/Tests/App/Dashboard/PingMonitorProvisioning.test.ts +368 -0
  128. package/Tests/App/Dashboard/RecommendationCard.test.tsx +796 -0
  129. package/Tests/App/Dashboard/RecommendationToolbar.test.tsx +519 -0
  130. package/Tests/App/Dashboard/RecommendationsList.test.tsx +661 -0
  131. package/Tests/App/Dashboard/SideMenuHarness.tsx +11 -3
  132. package/Tests/App/Dashboard/UseBulkCreatePingMonitors.test.tsx +899 -0
  133. package/Tests/App/Dashboard/UseBulkSnmpCredentialProfileActions.test.tsx +732 -0
  134. package/Tests/App/SensitiveUrlTokenBootstrap.test.ts +256 -0
  135. package/Tests/App/StatusPage/StatusPageIndexPageRobotsMeta.test.ts +11 -1
  136. package/Tests/App/StatusPage/StatusPageLoginCodeBootstrap.test.ts +9 -4
  137. package/Tests/Models/DatabaseModels/ModelRegistryInvariants.test.ts +115 -41
  138. package/Tests/Models/NetworkSiteHierarchy.test.ts +41 -4
  139. package/Tests/Server/API/EnterpriseLicenseReportUserCount.test.ts +951 -7
  140. package/Tests/Server/API/LlmProviderConnectionTest.test.ts +522 -0
  141. package/Tests/Server/Infrastructure/Postgres/NetworkDeviceRoleTableMigration.test.ts +476 -0
  142. package/Tests/Server/Infrastructure/Postgres/NetworkSnmpCredentialProfilesAndAlertPoliciesMigration.test.ts +854 -0
  143. package/Tests/Server/Infrastructure/Postgres/SchemaMigrationsOrdering.test.ts +18 -0
  144. package/Tests/Server/Infrastructure/Postgres/UserNotificationEmailRollupTableMigration.test.ts +535 -0
  145. package/Tests/Server/Services/AIChatPrivacyPin.test.ts +560 -0
  146. package/Tests/Server/Services/BillingRechargeOwnerEmailGuards.test.ts +783 -0
  147. package/Tests/Server/Services/DatabaseServiceGenerateSlug.test.ts +215 -0
  148. package/Tests/Server/Services/EnterpriseLicenseInstanceServiceDeletionUsage.test.ts +707 -0
  149. package/Tests/Server/Services/EnterpriseLicenseServiceUsageAggregationLock.test.ts +329 -0
  150. package/Tests/Server/Services/MonitorServiceDeleteNetworkDeviceCleanup.test.ts +294 -0
  151. package/Tests/Server/Services/MonitorStatusBridgeProbePath.test.ts +802 -0
  152. package/Tests/Server/Services/MonitorStatusTimelineService.test.ts +72 -2
  153. package/Tests/Server/Services/NetworkAlertPolicyEngineHooks.test.ts +752 -0
  154. package/Tests/Server/Services/NetworkAlertPolicyEngineService.test.ts +1849 -0
  155. package/Tests/Server/Services/NetworkAlertPolicyModel.test.ts +1793 -0
  156. package/Tests/Server/Services/NetworkDeviceAutoImportRuleEngineService.test.ts +47 -4
  157. package/Tests/Server/Services/NetworkDeviceAutoImportRuleService.test.ts +97 -12
  158. package/Tests/Server/Services/NetworkDeviceAutoMonitorLifecycle.test.ts +148 -3
  159. package/Tests/Server/Services/NetworkDeviceMonitorBindingUpdateGuard.test.ts +514 -0
  160. package/Tests/Server/Services/NetworkDeviceMonitorStatusStamp.test.ts +447 -58
  161. package/Tests/Server/Services/NetworkDeviceMonitoringMethodTransition.test.ts +739 -0
  162. package/Tests/Server/Services/NetworkDevicePollingTenancy.test.ts +501 -0
  163. package/Tests/Server/Services/NetworkDeviceRoleModel.test.ts +672 -0
  164. package/Tests/Server/Services/NetworkDeviceRuleEngines.test.ts +1 -1
  165. package/Tests/Server/Services/NetworkDeviceSiteDefaultProbe.test.ts +432 -0
  166. package/Tests/Server/Services/NetworkSiteMonitoringDefaults.test.ts +498 -0
  167. package/Tests/Server/Services/NetworkSiteRollupPolicyAndMaintenance.test.ts +337 -55
  168. package/Tests/Server/Services/NetworkSiteService.test.ts +1868 -131
  169. package/Tests/Server/Services/NetworkSiteTypeService.test.ts +1109 -0
  170. package/Tests/Server/Services/NetworkSnmpCredentialProfileModel.test.ts +926 -0
  171. package/Tests/Server/Services/NetworkSnmpCredentialProfileService.test.ts +796 -0
  172. package/Tests/Server/Services/ProjectServiceCreateSubscriptionStarted.test.ts +67 -4
  173. package/Tests/Server/Services/ProjectServiceNetworkSiteTypeDefaults.test.ts +214 -0
  174. package/Tests/Server/Services/ScheduledMaintenanceSubscriberEndTime.test.ts +369 -0
  175. package/Tests/Server/Services/StatusPagePrivateUserEmailChangePasswordResetExpiry.test.ts +269 -0
  176. package/Tests/Server/Services/UserEmailChangePasswordResetExpiry.test.ts +472 -0
  177. package/Tests/Server/Services/UserNotificationEmailRollupModels.test.ts +569 -0
  178. package/Tests/Server/Services/UserNotificationEmailRollupSettingModel.test.ts +314 -0
  179. package/Tests/Server/Services/UserNotificationEmailRollupSettingService.test.ts +409 -0
  180. package/Tests/Server/Services/UserNotificationSettingMonitorDefaults.test.ts +248 -0
  181. package/Tests/Server/Services/UserNotificationSettingRollupRouting.test.ts +856 -0
  182. package/Tests/Server/Services/UserNotificationSettingWorkspaceChannels.test.ts +145 -3
  183. package/Tests/Server/Types/Database/Permissions/DashboardAccessPermission.test.ts +321 -0
  184. package/Tests/Server/Types/Database/QueryHelperOperators.test.ts +17 -0
  185. package/Tests/Server/Utils/AI/AlertMonitorFilters.test.ts +124 -0
  186. package/Tests/Server/Utils/AI/Insights/InsightTriageRunner.test.ts +208 -0
  187. package/Tests/Server/Utils/AI/LLMServiceToolCalling.test.ts +235 -0
  188. package/Tests/Server/Utils/AI/ObservabilityChatPrompt.test.ts +253 -0
  189. package/Tests/Server/Utils/BasicCron.test.ts +283 -0
  190. package/Tests/Server/Utils/Captcha.test.ts +422 -0
  191. package/Tests/Server/Utils/DataSource/HttpFetch.test.ts +96 -2
  192. package/Tests/Server/Utils/Database/MigrationFailureLog.test.ts +466 -0
  193. package/Tests/Server/Utils/EmailRollup/EmailRollupFlushRunnerBehaviour.test.ts +1096 -0
  194. package/Tests/Server/Utils/EmailRollup/EmailRollupFlushRunnerClaim.test.ts +466 -0
  195. package/Tests/Server/Utils/EmailRollup/EmailRollupRenderer.test.ts +1428 -0
  196. package/Tests/Server/Utils/EmailRollup/EmailRollupTestHarness.ts +752 -0
  197. package/Tests/Server/Utils/EmailRollup/EmailRollupWriter.test.ts +864 -0
  198. package/Tests/Server/Utils/IncomingCallPhoneNumber.test.ts +174 -0
  199. package/Tests/Server/Utils/LoggerFaultDemotion.test.ts +346 -0
  200. package/Tests/Server/Utils/Monitor/Criteria/DatabaseMonitorCriteria.test.ts +633 -0
  201. package/Tests/Server/Utils/Monitor/Criteria/SnmpMonitorCriteria.test.ts +196 -0
  202. package/Tests/Server/Utils/Monitor/DatabaseMetricWrite.test.ts +367 -0
  203. package/Tests/Server/Utils/Monitor/MonitorCriteriaObservationBuilderUnits.test.ts +100 -0
  204. package/Tests/Server/Utils/Monitor/MonitorStepResourceIdentity.test.ts +5 -0
  205. package/Tests/Server/Utils/Monitor/NetworkDeviceHydrationUtil.test.ts +512 -31
  206. package/Tests/Server/Utils/Monitor/NetworkDeviceMetricUtil.test.ts +252 -0
  207. package/Tests/Server/Utils/Monitor/NetworkDeviceWalkUtil.test.ts +479 -42
  208. package/Tests/Server/Utils/Monitor/NetworkInventoryUtil.test.ts +351 -5
  209. package/Tests/Server/Utils/NetworkDevice/DeviceHealthAggregation.test.ts +136 -12
  210. package/Tests/Server/Utils/NetworkSite/NetworkSiteHierarchyLock.test.ts +306 -0
  211. package/Tests/Server/Utils/OutboundUserAgent.test.ts +266 -0
  212. package/Tests/Server/Utils/SecurityEvent/ThreatIntel/TaxiiClientUserAgent.test.ts +141 -0
  213. package/Tests/Server/Utils/Telemetry/ErrorClassResolver.test.ts +298 -0
  214. package/Tests/Server/Utils/Telemetry.test.ts +456 -66
  215. package/Tests/Types/Monitor/DatabaseMetricCatalog.test.ts +388 -0
  216. package/Tests/Types/Monitor/MonitorStepDatabaseMonitor.test.ts +243 -0
  217. package/Tests/Types/Monitor/MonitorStepDefaultTelemetryConfig.test.ts +1 -0
  218. package/Tests/Types/Monitor/MonitorType.test.ts +1 -0
  219. package/Tests/Types/Monitor/MonitorTypeKeywords.test.ts +16 -7
  220. package/Tests/Types/Monitor/NetworkDeviceAlertPack.test.ts +60 -0
  221. package/Tests/Types/NetworkDevice/DefaultNetworkDeviceRole.test.ts +417 -0
  222. package/Tests/Types/NetworkDevice/NetworkAlertPolicyScope.test.ts +655 -0
  223. package/Tests/Types/NetworkDevice/NetworkDeviceMonitoringMethod.test.ts +115 -26
  224. package/Tests/Types/NetworkSite/DefaultNetworkSiteType.test.ts +39 -0
  225. package/Tests/Types/NotificationSetting/NotificationEmailRollupPolicy.test.ts +299 -0
  226. package/Tests/Types/Telemetry/ErrorClass.test.ts +483 -0
  227. package/Tests/UI/Components/BasicRadioButtons.test.tsx +336 -0
  228. package/Tests/UI/Components/Charts/ChartClickDoubleClickDisambiguation.test.tsx +221 -0
  229. package/Tests/UI/Components/Charts/ChartDoubleClickReset.test.tsx +220 -0
  230. package/Tests/UI/Components/ModelTable/BaseModelTableBulkDelete.test.tsx +751 -0
  231. package/Tests/UI/Components/ModelTable/BaseModelTableColumnCustomization.test.tsx +475 -43
  232. package/Tests/UI/Components/ModelTable/ColumnPreference.test.ts +89 -0
  233. package/Tests/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.test.ts +15 -0
  234. package/Tests/UI/Components/NavBarCommandKGating.test.tsx +103 -8
  235. package/Tests/UI/Components/ProgressBar.test.tsx +38 -2
  236. package/Tests/UI/Components/SideMenuItem.test.tsx +256 -4
  237. package/Tests/UI/Components/SideMenuSection.test.tsx +310 -0
  238. package/Tests/UI/Components/SideOverSubmitState.test.tsx +335 -0
  239. package/Tests/UI/Utils/PageScrollLock.test.tsx +377 -0
  240. package/Tests/UI/Utils/PermissionGate.test.ts +78 -0
  241. package/Tests/UI/Utils/SensitiveUrlToken.test.ts +140 -0
  242. package/Tests/UI/Utils/TableColumnsToCsv.test.ts +30 -0
  243. package/Tests/UI/Utils/UseDashboardTimeRangeZoom.test.tsx +187 -0
  244. package/Tests/Utils/Dashboard/DashboardResourceListSharedArgs.test.ts +302 -0
  245. package/Tests/Utils/Dashboard/DashboardTimeRangeZoom.test.ts +242 -0
  246. package/Tests/Utils/EnterpriseLicenseSeats.test.ts +69 -0
  247. package/Tests/Utils/EnterpriseLicenseSync.test.ts +7 -1
  248. package/Tests/Utils/EnterpriseLicenseUsage.test.ts +433 -2
  249. package/Tests/Utils/Monitor/MonitorMetricType.test.ts +280 -1
  250. package/Tests/Utils/Monitor/MonitorSummarySnapshotUtil.test.ts +1 -0
  251. package/Tests/Utils/Monitor/NetworkDeviceRoleCatalog.test.ts +981 -0
  252. package/Tests/Utils/Monitor/NetworkTopologyRoleCatalog.test.ts +865 -0
  253. package/Tests/Utils/Monitor/NetworkTopologyUtil.test.ts +38 -0
  254. package/Tests/Utils/NetworkDevice/DeviceHealthStateUtil.test.ts +284 -23
  255. package/Tests/Utils/NetworkDevice/DeviceReachabilityUtil.test.ts +177 -0
  256. package/Tests/Utils/NetworkDevice/DeviceRoleKeyUtil.test.ts +538 -0
  257. package/Tests/Utils/NetworkDevice/MonitoringMethodThreadedClassifiers.test.ts +992 -0
  258. package/Tests/Utils/NetworkDevice/NetworkAlertPolicyBootstrapUtil.test.ts +427 -0
  259. package/Tests/Utils/NetworkDevice/ReachabilityStampConsistency.test.ts +185 -0
  260. package/Tests/Utils/NetworkDevice/SnmpCredentialUtil.test.ts +268 -0
  261. package/Tests/Utils/NetworkDiscovery/AutoImportRuleMatcher.test.ts +55 -5
  262. package/Tests/Utils/NetworkDiscovery/DiscoveredDeviceBuilder.test.ts +98 -21
  263. package/Tests/Utils/NetworkDiscovery/DiscoveryImportEligibility.test.ts +98 -20
  264. package/Tests/Utils/NetworkDiscovery/DiscoveryReverseDnsChain.test.ts +8 -7
  265. package/Tests/Utils/NetworkDiscovery/PingMonitorBuilderForAddress.test.ts +274 -0
  266. package/Tests/Utils/NetworkSite/SiteStatusRollupUtil.test.ts +230 -51
  267. package/Tests/Utils/NetworkSite/TypeHierarchyUtil.test.ts +209 -0
  268. package/Tests/Utils/Slo/SloEvaluation.test.ts +171 -0
  269. package/Tests/Utils/Slug.test.ts +61 -1
  270. package/Tests/Utils/Telemetry/CaptureSpanExportGating.test.ts +145 -0
  271. package/Tests/jest.setup.ts +19 -0
  272. package/Types/AI/ExceptionAIClassification.ts +10 -24
  273. package/Types/Email/EmailTemplateType.ts +2 -0
  274. package/Types/EnterpriseLicense/EnterpriseLicenseInstanceSummary.ts +5 -0
  275. package/Types/EnterpriseLicense/EnterpriseLicenseUsageSnapshot.ts +13 -0
  276. package/Types/EnterpriseLicense/EnterpriseLicenseUserCountSource.ts +6 -0
  277. package/Types/Exception/ApiException.ts +10 -0
  278. package/Types/Exception/BadDataException.ts +11 -0
  279. package/Types/Exception/BadRequestException.ts +11 -0
  280. package/Types/Exception/Exception.ts +65 -0
  281. package/Types/Exception/ForbiddenException.ts +10 -0
  282. package/Types/Exception/NotAuthenticatedException.ts +10 -0
  283. package/Types/Exception/NotAuthorizedException.ts +10 -0
  284. package/Types/Exception/NotFoundException.ts +11 -0
  285. package/Types/Exception/PayloadTooLargeException.ts +11 -0
  286. package/Types/Exception/PaymentRequiredException.ts +10 -0
  287. package/Types/Exception/ServiceUnavailableException.ts +10 -0
  288. package/Types/Exception/SsoAuthorizationException.ts +10 -0
  289. package/Types/Exception/TenantNotFoundException.ts +11 -0
  290. package/Types/Exception/TimeoutException.ts +10 -0
  291. package/Types/Exception/TooManyRequestsException.ts +10 -0
  292. package/Types/Exception/UnableToReachServer.ts +10 -0
  293. package/Types/Exception/WebsiteRequestException.ts +10 -0
  294. package/Types/Monitor/CriteriaFilter.ts +60 -2
  295. package/Types/Monitor/DatabaseMetricCatalog.ts +693 -0
  296. package/Types/Monitor/DatabaseMonitor/DatabaseMonitorResponse.ts +83 -0
  297. package/Types/Monitor/MonitorCriteriaInstance.ts +76 -0
  298. package/Types/Monitor/MonitorMetricType.ts +71 -0
  299. package/Types/Monitor/MonitorStep.ts +76 -0
  300. package/Types/Monitor/MonitorStepDatabaseMonitor.ts +171 -0
  301. package/Types/Monitor/MonitorStepSqlMonitor.ts +2 -20
  302. package/Types/Monitor/MonitorType.ts +47 -1
  303. package/Types/Monitor/SnmpMonitor/NetworkDeviceAlertPack.ts +22 -1
  304. package/Types/Monitor/SnmpMonitor/NetworkTopology.ts +61 -0
  305. package/Types/Monitor/SqlConnectionConfig.ts +31 -0
  306. package/Types/NetworkDevice/DefaultNetworkDeviceRole.ts +145 -0
  307. package/Types/NetworkDevice/NetworkAlertPolicyScope.ts +343 -0
  308. package/Types/NetworkDevice/NetworkDeviceMonitoringMethod.ts +42 -22
  309. package/Types/NetworkSite/DefaultNetworkSiteTypeHierarchy.ts +30 -0
  310. package/Types/NotificationSetting/NotificationEmailRollupCategory.ts +255 -0
  311. package/Types/NotificationSetting/NotificationEmailRollupPolicy.ts +104 -0
  312. package/Types/Permission.ts +135 -0
  313. package/Types/Probe/ProbeMonitorResponse.ts +16 -0
  314. package/Types/Telemetry/ErrorClass.ts +274 -0
  315. package/Types/Telemetry/UnitOfWork.ts +59 -0
  316. package/UI/Components/Charts/Area/AreaChart.tsx +7 -0
  317. package/UI/Components/Charts/Bar/BarChart.tsx +6 -0
  318. package/UI/Components/Charts/ChartGroup/ChartGroup.tsx +9 -1
  319. package/UI/Components/Charts/ChartLibrary/AreaChart/AreaChart.tsx +97 -35
  320. package/UI/Components/Charts/ChartLibrary/BarChart/BarChart.tsx +14 -0
  321. package/UI/Components/Charts/ChartLibrary/LineChart/LineChart.tsx +97 -35
  322. package/UI/Components/Charts/ChartLibrary/Utils/DoubleClick.ts +13 -0
  323. package/UI/Components/Charts/Line/LineChart.tsx +7 -0
  324. package/UI/Components/CommandPalette/CommandPalette.tsx +2 -8
  325. package/UI/Components/EditionLabel/EditionLabel.tsx +4 -0
  326. package/UI/Components/Modal/Modal.tsx +2 -8
  327. package/UI/Components/ModelTable/BaseModelTable.tsx +50 -15
  328. package/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.ts +44 -0
  329. package/UI/Components/Navbar/NavBar.tsx +62 -13
  330. package/UI/Components/Navbar/NavBarMenuModal.tsx +7 -2
  331. package/UI/Components/ProgressBar/ProgressBar.tsx +12 -1
  332. package/UI/Components/RadioButtons/BasicRadioButtons.tsx +37 -7
  333. package/UI/Components/SideMenu/CountModelSideMenuItem.tsx +2 -0
  334. package/UI/Components/SideMenu/SideMenu.tsx +135 -7
  335. package/UI/Components/SideMenu/SideMenuItem.tsx +80 -85
  336. package/UI/Components/SideMenu/SideMenuSection.tsx +69 -25
  337. package/UI/Components/SideOver/SideOver.tsx +21 -20
  338. package/UI/Utils/PageScrollLock.ts +79 -3
  339. package/UI/Utils/PermissionGate.ts +61 -0
  340. package/UI/Utils/SensitiveUrlToken.ts +112 -0
  341. package/UI/Utils/TestLLMProvider.ts +11 -0
  342. package/UI/Utils/UseDashboardTimeRangeZoom.ts +77 -0
  343. package/Utils/Dashboard/DashboardTimeRangeZoom.ts +118 -0
  344. package/Utils/EnterpriseLicense/EnterpriseLicenseSeats.ts +16 -0
  345. package/Utils/EnterpriseLicense/EnterpriseLicenseUsage.ts +191 -11
  346. package/Utils/Monitor/MonitorMetricType.ts +153 -1
  347. package/Utils/Monitor/NetworkDeviceRoleCatalog.ts +232 -0
  348. package/Utils/Monitor/NetworkDeviceRoleUtil.ts +2 -1
  349. package/Utils/Monitor/NetworkTopologyUtil.ts +139 -36
  350. package/Utils/NetworkDevice/DeviceHealthStateUtil.ts +65 -14
  351. package/Utils/NetworkDevice/DeviceReachabilityUtil.ts +43 -14
  352. package/Utils/NetworkDevice/DeviceRoleKeyUtil.ts +137 -0
  353. package/Utils/NetworkDevice/NetworkAlertPolicyBootstrapUtil.ts +247 -0
  354. package/Utils/NetworkDevice/SnmpCredentialUtil.ts +68 -0
  355. package/Utils/NetworkDiscovery/AutoImportRuleMatcher.ts +15 -7
  356. package/Utils/NetworkDiscovery/DiscoveredDeviceBuilder.ts +52 -17
  357. package/Utils/NetworkDiscovery/DiscoveryImportEligibility.ts +55 -23
  358. package/Utils/NetworkDiscovery/PingMonitorBuilder.ts +115 -13
  359. package/Utils/NetworkSite/SiteStatusRollupUtil.ts +66 -20
  360. package/Utils/NetworkSite/TypeHierarchyUtil.ts +313 -0
  361. package/Utils/Rules/RulePatternMatchUtil.ts +1 -1
  362. package/Utils/Slug.ts +34 -1
  363. package/build/dist/Models/AnalyticsModels/Span.js +14 -0
  364. package/build/dist/Models/AnalyticsModels/Span.js.map +1 -1
  365. package/build/dist/Models/DatabaseModels/AlertState.js +0 -2
  366. package/build/dist/Models/DatabaseModels/AlertState.js.map +1 -1
  367. package/build/dist/Models/DatabaseModels/Domain.js +1 -1
  368. package/build/dist/Models/DatabaseModels/Domain.js.map +1 -1
  369. package/build/dist/Models/DatabaseModels/EnterpriseLicense.js +59 -0
  370. package/build/dist/Models/DatabaseModels/EnterpriseLicense.js.map +1 -1
  371. package/build/dist/Models/DatabaseModels/Incident.js +1 -1
  372. package/build/dist/Models/DatabaseModels/Incident.js.map +1 -1
  373. package/build/dist/Models/DatabaseModels/IncidentTemplate.js +1 -1
  374. package/build/dist/Models/DatabaseModels/IncidentTemplate.js.map +1 -1
  375. package/build/dist/Models/DatabaseModels/Index.js +12 -0
  376. package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
  377. package/build/dist/Models/DatabaseModels/MetricType.js +0 -2
  378. package/build/dist/Models/DatabaseModels/MetricType.js.map +1 -1
  379. package/build/dist/Models/DatabaseModels/Monitor.js +75 -0
  380. package/build/dist/Models/DatabaseModels/Monitor.js.map +1 -1
  381. package/build/dist/Models/DatabaseModels/MonitorStatusTimeline.js +0 -2
  382. package/build/dist/Models/DatabaseModels/MonitorStatusTimeline.js.map +1 -1
  383. package/build/dist/Models/DatabaseModels/MonitorTest.js +0 -2
  384. package/build/dist/Models/DatabaseModels/MonitorTest.js.map +1 -1
  385. package/build/dist/Models/DatabaseModels/NetworkAlertPolicy.js +713 -0
  386. package/build/dist/Models/DatabaseModels/NetworkAlertPolicy.js.map +1 -0
  387. package/build/dist/Models/DatabaseModels/NetworkDevice.js +304 -4
  388. package/build/dist/Models/DatabaseModels/NetworkDevice.js.map +1 -1
  389. package/build/dist/Models/DatabaseModels/NetworkDeviceOidTemplate.js +3 -1
  390. package/build/dist/Models/DatabaseModels/NetworkDeviceOidTemplate.js.map +1 -1
  391. package/build/dist/Models/DatabaseModels/NetworkDeviceRole.js +677 -0
  392. package/build/dist/Models/DatabaseModels/NetworkDeviceRole.js.map +1 -0
  393. package/build/dist/Models/DatabaseModels/NetworkSite.js +200 -2
  394. package/build/dist/Models/DatabaseModels/NetworkSite.js.map +1 -1
  395. package/build/dist/Models/DatabaseModels/NetworkSiteType.js +102 -3
  396. package/build/dist/Models/DatabaseModels/NetworkSiteType.js.map +1 -1
  397. package/build/dist/Models/DatabaseModels/NetworkSnmpCredentialProfile.js +878 -0
  398. package/build/dist/Models/DatabaseModels/NetworkSnmpCredentialProfile.js.map +1 -0
  399. package/build/dist/Models/DatabaseModels/ScheduledMaintenance.js +1 -1
  400. package/build/dist/Models/DatabaseModels/ScheduledMaintenance.js.map +1 -1
  401. package/build/dist/Models/DatabaseModels/ScheduledMaintenanceTemplate.js +1 -1
  402. package/build/dist/Models/DatabaseModels/ScheduledMaintenanceTemplate.js.map +1 -1
  403. package/build/dist/Models/DatabaseModels/StatusPageAnnouncement.js +0 -2
  404. package/build/dist/Models/DatabaseModels/StatusPageAnnouncement.js.map +1 -1
  405. package/build/dist/Models/DatabaseModels/StatusPageAnnouncementTemplate.js +0 -2
  406. package/build/dist/Models/DatabaseModels/StatusPageAnnouncementTemplate.js.map +1 -1
  407. package/build/dist/Models/DatabaseModels/StatusPagePrivateUser.js +0 -2
  408. package/build/dist/Models/DatabaseModels/StatusPagePrivateUser.js.map +1 -1
  409. package/build/dist/Models/DatabaseModels/StatusPageResource.js +0 -2
  410. package/build/dist/Models/DatabaseModels/StatusPageResource.js.map +1 -1
  411. package/build/dist/Models/DatabaseModels/StatusPageSubscriber.js +0 -2
  412. package/build/dist/Models/DatabaseModels/StatusPageSubscriber.js.map +1 -1
  413. package/build/dist/Models/DatabaseModels/TelemetryException.js +123 -0
  414. package/build/dist/Models/DatabaseModels/TelemetryException.js.map +1 -1
  415. package/build/dist/Models/DatabaseModels/UserNotificationEmailRollupBatch.js +363 -0
  416. package/build/dist/Models/DatabaseModels/UserNotificationEmailRollupBatch.js.map +1 -0
  417. package/build/dist/Models/DatabaseModels/UserNotificationEmailRollupItem.js +402 -0
  418. package/build/dist/Models/DatabaseModels/UserNotificationEmailRollupItem.js.map +1 -0
  419. package/build/dist/Models/DatabaseModels/UserNotificationEmailRollupSetting.js +296 -0
  420. package/build/dist/Models/DatabaseModels/UserNotificationEmailRollupSetting.js.map +1 -0
  421. package/build/dist/Server/API/EnterpriseLicenseAPI.js +273 -60
  422. package/build/dist/Server/API/EnterpriseLicenseAPI.js.map +1 -1
  423. package/build/dist/Server/API/LlmProviderAPI.js +108 -13
  424. package/build/dist/Server/API/LlmProviderAPI.js.map +1 -1
  425. package/build/dist/Server/EnvironmentConfig.js +12 -0
  426. package/build/dist/Server/EnvironmentConfig.js.map +1 -1
  427. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1790700000000-AddNetworkSiteTypeParentHierarchy.js +24 -0
  428. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1790700000000-AddNetworkSiteTypeParentHierarchy.js.map +1 -0
  429. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1790800000000-AddNetworkDeviceRoleTable.js +39 -0
  430. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1790800000000-AddNetworkDeviceRoleTable.js.map +1 -0
  431. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1790900000000-AddEnterpriseLicenseUsageProvenance.js +16 -0
  432. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1790900000000-AddEnterpriseLicenseUsageProvenance.js.map +1 -0
  433. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1790900000000-AddTelemetryExceptionErrorClass.js +111 -0
  434. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1790900000000-AddTelemetryExceptionErrorClass.js.map +1 -0
  435. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1791000000000-AddUserNotificationEmailRollup.js +77 -0
  436. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1791000000000-AddUserNotificationEmailRollup.js.map +1 -0
  437. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1791100000000-AddUserNotificationEmailRollupSetting.js +50 -0
  438. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1791100000000-AddUserNotificationEmailRollupSetting.js.map +1 -0
  439. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1791200000000-AddNetworkSnmpCredentialProfilesAndAlertPolicies.js +83 -0
  440. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1791200000000-AddNetworkSnmpCredentialProfilesAndAlertPolicies.js.map +1 -0
  441. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +14 -0
  442. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  443. package/build/dist/Server/Infrastructure/QueueWorker.js +33 -5
  444. package/build/dist/Server/Infrastructure/QueueWorker.js.map +1 -1
  445. package/build/dist/Server/Middleware/BearerTokenAuthorization.js +12 -0
  446. package/build/dist/Server/Middleware/BearerTokenAuthorization.js.map +1 -1
  447. package/build/dist/Server/Middleware/ProjectAuthorization.js +11 -0
  448. package/build/dist/Server/Middleware/ProjectAuthorization.js.map +1 -1
  449. package/build/dist/Server/Middleware/SCIMAuthorization.js +12 -0
  450. package/build/dist/Server/Middleware/SCIMAuthorization.js.map +1 -1
  451. package/build/dist/Server/Middleware/TelemetryIngest.js +11 -0
  452. package/build/dist/Server/Middleware/TelemetryIngest.js.map +1 -1
  453. package/build/dist/Server/Services/AIBillingService.js +70 -16
  454. package/build/dist/Server/Services/AIBillingService.js.map +1 -1
  455. package/build/dist/Server/Services/DatabaseService.js +31 -5
  456. package/build/dist/Server/Services/DatabaseService.js.map +1 -1
  457. package/build/dist/Server/Services/EnterpriseLicenseInstanceService.js +167 -0
  458. package/build/dist/Server/Services/EnterpriseLicenseInstanceService.js.map +1 -1
  459. package/build/dist/Server/Services/EnterpriseLicenseService.js +39 -0
  460. package/build/dist/Server/Services/EnterpriseLicenseService.js.map +1 -1
  461. package/build/dist/Server/Services/Index.js +12 -0
  462. package/build/dist/Server/Services/Index.js.map +1 -1
  463. package/build/dist/Server/Services/MonitorService.js +119 -21
  464. package/build/dist/Server/Services/MonitorService.js.map +1 -1
  465. package/build/dist/Server/Services/MonitorStatusTimelineService.js +127 -8
  466. package/build/dist/Server/Services/MonitorStatusTimelineService.js.map +1 -1
  467. package/build/dist/Server/Services/MonitorTemplateService.js +162 -0
  468. package/build/dist/Server/Services/MonitorTemplateService.js.map +1 -1
  469. package/build/dist/Server/Services/NetworkAlertPolicyEngineService.js +1683 -0
  470. package/build/dist/Server/Services/NetworkAlertPolicyEngineService.js.map +1 -0
  471. package/build/dist/Server/Services/NetworkAlertPolicyService.js +732 -0
  472. package/build/dist/Server/Services/NetworkAlertPolicyService.js.map +1 -0
  473. package/build/dist/Server/Services/NetworkDeviceAutoImportRuleEngineService.js +10 -9
  474. package/build/dist/Server/Services/NetworkDeviceAutoImportRuleEngineService.js.map +1 -1
  475. package/build/dist/Server/Services/NetworkDeviceAutoImportRuleService.js +54 -11
  476. package/build/dist/Server/Services/NetworkDeviceAutoImportRuleService.js.map +1 -1
  477. package/build/dist/Server/Services/NetworkDeviceRoleService.js +70 -0
  478. package/build/dist/Server/Services/NetworkDeviceRoleService.js.map +1 -0
  479. package/build/dist/Server/Services/NetworkDeviceService.js +841 -70
  480. package/build/dist/Server/Services/NetworkDeviceService.js.map +1 -1
  481. package/build/dist/Server/Services/NetworkSiteService.js +1145 -107
  482. package/build/dist/Server/Services/NetworkSiteService.js.map +1 -1
  483. package/build/dist/Server/Services/NetworkSiteTypeService.js +863 -0
  484. package/build/dist/Server/Services/NetworkSiteTypeService.js.map +1 -1
  485. package/build/dist/Server/Services/NetworkSnmpCredentialProfileService.js +217 -0
  486. package/build/dist/Server/Services/NetworkSnmpCredentialProfileService.js.map +1 -0
  487. package/build/dist/Server/Services/NotificationService.js +80 -17
  488. package/build/dist/Server/Services/NotificationService.js.map +1 -1
  489. package/build/dist/Server/Services/ProjectService.js +131 -30
  490. package/build/dist/Server/Services/ProjectService.js.map +1 -1
  491. package/build/dist/Server/Services/StatusPagePrivateUserService.js +92 -2
  492. package/build/dist/Server/Services/StatusPagePrivateUserService.js.map +1 -1
  493. package/build/dist/Server/Services/UserNotificationEmailRollupBatchService.js +76 -0
  494. package/build/dist/Server/Services/UserNotificationEmailRollupBatchService.js.map +1 -0
  495. package/build/dist/Server/Services/UserNotificationEmailRollupItemService.js +77 -0
  496. package/build/dist/Server/Services/UserNotificationEmailRollupItemService.js.map +1 -0
  497. package/build/dist/Server/Services/UserNotificationEmailRollupSettingService.js +111 -0
  498. package/build/dist/Server/Services/UserNotificationEmailRollupSettingService.js.map +1 -0
  499. package/build/dist/Server/Services/UserNotificationSettingService.js +46 -21
  500. package/build/dist/Server/Services/UserNotificationSettingService.js.map +1 -1
  501. package/build/dist/Server/Services/UserService.js +90 -0
  502. package/build/dist/Server/Services/UserService.js.map +1 -1
  503. package/build/dist/Server/Types/Database/QueryHelper.js +1 -1
  504. package/build/dist/Server/Types/Database/QueryHelper.js.map +1 -1
  505. package/build/dist/Server/Utils/AI/Chat/ObservabilityChatPrompt.js +14 -3
  506. package/build/dist/Server/Utils/AI/Chat/ObservabilityChatPrompt.js.map +1 -1
  507. package/build/dist/Server/Utils/AI/SRE/Insights/Detectors/ExceptionSpikeDetector.js +10 -0
  508. package/build/dist/Server/Utils/AI/SRE/Insights/Detectors/ExceptionSpikeDetector.js.map +1 -1
  509. package/build/dist/Server/Utils/AI/SRE/Insights/Detectors/NewExceptionDetector.js +10 -0
  510. package/build/dist/Server/Utils/AI/SRE/Insights/Detectors/NewExceptionDetector.js.map +1 -1
  511. package/build/dist/Server/Utils/AI/SRE/Insights/InsightTriageRunner.js +54 -1
  512. package/build/dist/Server/Utils/AI/SRE/Insights/InsightTriageRunner.js.map +1 -1
  513. package/build/dist/Server/Utils/AI/Toolbox/AlertTools.js +18 -4
  514. package/build/dist/Server/Utils/AI/Toolbox/AlertTools.js.map +1 -1
  515. package/build/dist/Server/Utils/Billing/BillingFailureNoticeThrottle.js +59 -0
  516. package/build/dist/Server/Utils/Billing/BillingFailureNoticeThrottle.js.map +1 -0
  517. package/build/dist/Server/Utils/DataSource/HttpFetch.js +2 -1
  518. package/build/dist/Server/Utils/DataSource/HttpFetch.js.map +1 -1
  519. package/build/dist/Server/Utils/EmailRollup/EmailRollupConstants.js +91 -0
  520. package/build/dist/Server/Utils/EmailRollup/EmailRollupConstants.js.map +1 -0
  521. package/build/dist/Server/Utils/EmailRollup/EmailRollupFlushRunner.js +691 -0
  522. package/build/dist/Server/Utils/EmailRollup/EmailRollupFlushRunner.js.map +1 -0
  523. package/build/dist/Server/Utils/EmailRollup/EmailRollupRenderer.js +497 -0
  524. package/build/dist/Server/Utils/EmailRollup/EmailRollupRenderer.js.map +1 -0
  525. package/build/dist/Server/Utils/EmailRollup/EmailRollupWriter.js +257 -0
  526. package/build/dist/Server/Utils/EmailRollup/EmailRollupWriter.js.map +1 -0
  527. package/build/dist/Server/Utils/LLM/LLMService.js +64 -1
  528. package/build/dist/Server/Utils/LLM/LLMService.js.map +1 -1
  529. package/build/dist/Server/Utils/LogRedaction.js +8 -0
  530. package/build/dist/Server/Utils/LogRedaction.js.map +1 -1
  531. package/build/dist/Server/Utils/Logger.js +63 -1
  532. package/build/dist/Server/Utils/Logger.js.map +1 -1
  533. package/build/dist/Server/Utils/Monitor/Criteria/DatabaseMonitorCriteria.js +141 -0
  534. package/build/dist/Server/Utils/Monitor/Criteria/DatabaseMonitorCriteria.js.map +1 -0
  535. package/build/dist/Server/Utils/Monitor/Criteria/EvaluateOverTime.js +8 -1
  536. package/build/dist/Server/Utils/Monitor/Criteria/EvaluateOverTime.js.map +1 -1
  537. package/build/dist/Server/Utils/Monitor/Criteria/SnmpMonitorCriteria.js +51 -1
  538. package/build/dist/Server/Utils/Monitor/Criteria/SnmpMonitorCriteria.js.map +1 -1
  539. package/build/dist/Server/Utils/Monitor/MonitorCriteriaDataExtractor.js +7 -0
  540. package/build/dist/Server/Utils/Monitor/MonitorCriteriaDataExtractor.js.map +1 -1
  541. package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js +37 -0
  542. package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js.map +1 -1
  543. package/build/dist/Server/Utils/Monitor/MonitorCriteriaObservationBuilder.js +158 -6
  544. package/build/dist/Server/Utils/Monitor/MonitorCriteriaObservationBuilder.js.map +1 -1
  545. package/build/dist/Server/Utils/Monitor/MonitorMetricUtil.js +33 -0
  546. package/build/dist/Server/Utils/Monitor/MonitorMetricUtil.js.map +1 -1
  547. package/build/dist/Server/Utils/Monitor/MonitorTemplateUtil.js +32 -0
  548. package/build/dist/Server/Utils/Monitor/MonitorTemplateUtil.js.map +1 -1
  549. package/build/dist/Server/Utils/Monitor/NetworkDeviceHydrationUtil.js +330 -21
  550. package/build/dist/Server/Utils/Monitor/NetworkDeviceHydrationUtil.js.map +1 -1
  551. package/build/dist/Server/Utils/Monitor/NetworkDeviceMetricUtil.js +55 -10
  552. package/build/dist/Server/Utils/Monitor/NetworkDeviceMetricUtil.js.map +1 -1
  553. package/build/dist/Server/Utils/Monitor/NetworkDeviceWalkUtil.js +178 -49
  554. package/build/dist/Server/Utils/Monitor/NetworkDeviceWalkUtil.js.map +1 -1
  555. package/build/dist/Server/Utils/Monitor/NetworkInventoryUtil.js +119 -29
  556. package/build/dist/Server/Utils/Monitor/NetworkInventoryUtil.js.map +1 -1
  557. package/build/dist/Server/Utils/NetworkDevice/DeviceHealthAggregation.js +30 -17
  558. package/build/dist/Server/Utils/NetworkDevice/DeviceHealthAggregation.js.map +1 -1
  559. package/build/dist/Server/Utils/NetworkSite/NetworkSiteHierarchyLock.js +158 -0
  560. package/build/dist/Server/Utils/NetworkSite/NetworkSiteHierarchyLock.js.map +1 -0
  561. package/build/dist/Server/Utils/OutboundUserAgent.js +123 -0
  562. package/build/dist/Server/Utils/OutboundUserAgent.js.map +1 -0
  563. package/build/dist/Server/Utils/StartServer.js +38 -14
  564. package/build/dist/Server/Utils/StartServer.js.map +1 -1
  565. package/build/dist/Server/Utils/Telemetry/CaptureSpan.js +28 -8
  566. package/build/dist/Server/Utils/Telemetry/CaptureSpan.js.map +1 -1
  567. package/build/dist/Server/Utils/Telemetry/ErrorClassResolver.js +95 -0
  568. package/build/dist/Server/Utils/Telemetry/ErrorClassResolver.js.map +1 -0
  569. package/build/dist/Server/Utils/Telemetry/SpanUtil.js +29 -0
  570. package/build/dist/Server/Utils/Telemetry/SpanUtil.js.map +1 -1
  571. package/build/dist/Server/Utils/Telemetry.js +162 -46
  572. package/build/dist/Server/Utils/Telemetry.js.map +1 -1
  573. package/build/dist/Types/AI/ExceptionAIClassification.js +10 -24
  574. package/build/dist/Types/AI/ExceptionAIClassification.js.map +1 -1
  575. package/build/dist/Types/Email/EmailTemplateType.js +1 -0
  576. package/build/dist/Types/Email/EmailTemplateType.js.map +1 -1
  577. package/build/dist/Types/EnterpriseLicense/EnterpriseLicenseUsageSnapshot.js +2 -0
  578. package/build/dist/Types/EnterpriseLicense/EnterpriseLicenseUsageSnapshot.js.map +1 -0
  579. package/build/dist/Types/EnterpriseLicense/EnterpriseLicenseUserCountSource.js +7 -0
  580. package/build/dist/Types/EnterpriseLicense/EnterpriseLicenseUserCountSource.js.map +1 -0
  581. package/build/dist/Types/Exception/ApiException.js +9 -0
  582. package/build/dist/Types/Exception/ApiException.js.map +1 -1
  583. package/build/dist/Types/Exception/BadDataException.js +10 -0
  584. package/build/dist/Types/Exception/BadDataException.js.map +1 -1
  585. package/build/dist/Types/Exception/BadRequestException.js +10 -0
  586. package/build/dist/Types/Exception/BadRequestException.js.map +1 -1
  587. package/build/dist/Types/Exception/Exception.js +56 -0
  588. package/build/dist/Types/Exception/Exception.js.map +1 -1
  589. package/build/dist/Types/Exception/ForbiddenException.js +9 -0
  590. package/build/dist/Types/Exception/ForbiddenException.js.map +1 -1
  591. package/build/dist/Types/Exception/NotAuthenticatedException.js +9 -0
  592. package/build/dist/Types/Exception/NotAuthenticatedException.js.map +1 -1
  593. package/build/dist/Types/Exception/NotAuthorizedException.js +9 -0
  594. package/build/dist/Types/Exception/NotAuthorizedException.js.map +1 -1
  595. package/build/dist/Types/Exception/NotFoundException.js +10 -0
  596. package/build/dist/Types/Exception/NotFoundException.js.map +1 -1
  597. package/build/dist/Types/Exception/PayloadTooLargeException.js +10 -0
  598. package/build/dist/Types/Exception/PayloadTooLargeException.js.map +1 -1
  599. package/build/dist/Types/Exception/PaymentRequiredException.js +9 -0
  600. package/build/dist/Types/Exception/PaymentRequiredException.js.map +1 -1
  601. package/build/dist/Types/Exception/ServiceUnavailableException.js +9 -0
  602. package/build/dist/Types/Exception/ServiceUnavailableException.js.map +1 -1
  603. package/build/dist/Types/Exception/SsoAuthorizationException.js +9 -0
  604. package/build/dist/Types/Exception/SsoAuthorizationException.js.map +1 -1
  605. package/build/dist/Types/Exception/TenantNotFoundException.js +10 -0
  606. package/build/dist/Types/Exception/TenantNotFoundException.js.map +1 -1
  607. package/build/dist/Types/Exception/TimeoutException.js +9 -0
  608. package/build/dist/Types/Exception/TimeoutException.js.map +1 -1
  609. package/build/dist/Types/Exception/TooManyRequestsException.js +9 -0
  610. package/build/dist/Types/Exception/TooManyRequestsException.js.map +1 -1
  611. package/build/dist/Types/Exception/UnableToReachServer.js +9 -0
  612. package/build/dist/Types/Exception/UnableToReachServer.js.map +1 -1
  613. package/build/dist/Types/Exception/WebsiteRequestException.js +9 -0
  614. package/build/dist/Types/Exception/WebsiteRequestException.js.map +1 -1
  615. package/build/dist/Types/Monitor/CriteriaFilter.js +45 -2
  616. package/build/dist/Types/Monitor/CriteriaFilter.js.map +1 -1
  617. package/build/dist/Types/Monitor/DatabaseMetricCatalog.js +594 -0
  618. package/build/dist/Types/Monitor/DatabaseMetricCatalog.js.map +1 -0
  619. package/build/dist/Types/Monitor/DatabaseMonitor/DatabaseMonitorResponse.js +21 -0
  620. package/build/dist/Types/Monitor/DatabaseMonitor/DatabaseMonitorResponse.js.map +1 -0
  621. package/build/dist/Types/Monitor/MonitorCriteriaInstance.js +70 -0
  622. package/build/dist/Types/Monitor/MonitorCriteriaInstance.js.map +1 -1
  623. package/build/dist/Types/Monitor/MonitorMetricType.js +61 -0
  624. package/build/dist/Types/Monitor/MonitorMetricType.js.map +1 -1
  625. package/build/dist/Types/Monitor/MonitorStep.js +54 -0
  626. package/build/dist/Types/Monitor/MonitorStep.js.map +1 -1
  627. package/build/dist/Types/Monitor/MonitorStepDatabaseMonitor.js +122 -0
  628. package/build/dist/Types/Monitor/MonitorStepDatabaseMonitor.js.map +1 -0
  629. package/build/dist/Types/Monitor/MonitorStepSqlMonitor.js.map +1 -1
  630. package/build/dist/Types/Monitor/MonitorType.js +45 -1
  631. package/build/dist/Types/Monitor/MonitorType.js.map +1 -1
  632. package/build/dist/Types/Monitor/SnmpMonitor/NetworkDeviceAlertPack.js +21 -1
  633. package/build/dist/Types/Monitor/SnmpMonitor/NetworkDeviceAlertPack.js.map +1 -1
  634. package/build/dist/Types/Monitor/SqlConnectionConfig.js +2 -0
  635. package/build/dist/Types/Monitor/SqlConnectionConfig.js.map +1 -0
  636. package/build/dist/Types/NetworkDevice/DefaultNetworkDeviceRole.js +105 -0
  637. package/build/dist/Types/NetworkDevice/DefaultNetworkDeviceRole.js.map +1 -0
  638. package/build/dist/Types/NetworkDevice/NetworkAlertPolicyScope.js +172 -0
  639. package/build/dist/Types/NetworkDevice/NetworkAlertPolicyScope.js.map +1 -0
  640. package/build/dist/Types/NetworkDevice/NetworkDeviceMonitoringMethod.js +40 -22
  641. package/build/dist/Types/NetworkDevice/NetworkDeviceMonitoringMethod.js.map +1 -1
  642. package/build/dist/Types/NetworkSite/DefaultNetworkSiteTypeHierarchy.js +26 -0
  643. package/build/dist/Types/NetworkSite/DefaultNetworkSiteTypeHierarchy.js.map +1 -0
  644. package/build/dist/Types/NotificationSetting/NotificationEmailRollupCategory.js +186 -0
  645. package/build/dist/Types/NotificationSetting/NotificationEmailRollupCategory.js.map +1 -0
  646. package/build/dist/Types/NotificationSetting/NotificationEmailRollupPolicy.js +87 -0
  647. package/build/dist/Types/NotificationSetting/NotificationEmailRollupPolicy.js.map +1 -0
  648. package/build/dist/Types/Permission.js +120 -0
  649. package/build/dist/Types/Permission.js.map +1 -1
  650. package/build/dist/Types/Telemetry/ErrorClass.js +216 -0
  651. package/build/dist/Types/Telemetry/ErrorClass.js.map +1 -0
  652. package/build/dist/Types/Telemetry/UnitOfWork.js +59 -0
  653. package/build/dist/Types/Telemetry/UnitOfWork.js.map +1 -0
  654. package/build/dist/UI/Components/Charts/Area/AreaChart.js +1 -1
  655. package/build/dist/UI/Components/Charts/Area/AreaChart.js.map +1 -1
  656. package/build/dist/UI/Components/Charts/Bar/BarChart.js +1 -1
  657. package/build/dist/UI/Components/Charts/Bar/BarChart.js.map +1 -1
  658. package/build/dist/UI/Components/Charts/ChartGroup/ChartGroup.js +6 -1
  659. package/build/dist/UI/Components/Charts/ChartGroup/ChartGroup.js.map +1 -1
  660. package/build/dist/UI/Components/Charts/ChartLibrary/AreaChart/AreaChart.js +79 -31
  661. package/build/dist/UI/Components/Charts/ChartLibrary/AreaChart/AreaChart.js.map +1 -1
  662. package/build/dist/UI/Components/Charts/ChartLibrary/BarChart/BarChart.js +7 -1
  663. package/build/dist/UI/Components/Charts/ChartLibrary/BarChart/BarChart.js.map +1 -1
  664. package/build/dist/UI/Components/Charts/ChartLibrary/LineChart/LineChart.js +79 -31
  665. package/build/dist/UI/Components/Charts/ChartLibrary/LineChart/LineChart.js.map +1 -1
  666. package/build/dist/UI/Components/Charts/ChartLibrary/Utils/DoubleClick.js +14 -0
  667. package/build/dist/UI/Components/Charts/ChartLibrary/Utils/DoubleClick.js.map +1 -0
  668. package/build/dist/UI/Components/Charts/Line/LineChart.js +1 -1
  669. package/build/dist/UI/Components/Charts/Line/LineChart.js.map +1 -1
  670. package/build/dist/UI/Components/CommandPalette/CommandPalette.js +2 -7
  671. package/build/dist/UI/Components/CommandPalette/CommandPalette.js.map +1 -1
  672. package/build/dist/UI/Components/EditionLabel/EditionLabel.js +3 -0
  673. package/build/dist/UI/Components/EditionLabel/EditionLabel.js.map +1 -1
  674. package/build/dist/UI/Components/Modal/Modal.js +2 -7
  675. package/build/dist/UI/Components/Modal/Modal.js.map +1 -1
  676. package/build/dist/UI/Components/ModelTable/BaseModelTable.js +39 -13
  677. package/build/dist/UI/Components/ModelTable/BaseModelTable.js.map +1 -1
  678. package/build/dist/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.js +39 -0
  679. package/build/dist/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.js.map +1 -1
  680. package/build/dist/UI/Components/Navbar/NavBar.js +44 -9
  681. package/build/dist/UI/Components/Navbar/NavBar.js.map +1 -1
  682. package/build/dist/UI/Components/Navbar/NavBarMenuModal.js +2 -2
  683. package/build/dist/UI/Components/Navbar/NavBarMenuModal.js.map +1 -1
  684. package/build/dist/UI/Components/ProgressBar/ProgressBar.js +12 -1
  685. package/build/dist/UI/Components/ProgressBar/ProgressBar.js.map +1 -1
  686. package/build/dist/UI/Components/RadioButtons/BasicRadioButtons.js +6 -6
  687. package/build/dist/UI/Components/RadioButtons/BasicRadioButtons.js.map +1 -1
  688. package/build/dist/UI/Components/SideMenu/CountModelSideMenuItem.js +1 -1
  689. package/build/dist/UI/Components/SideMenu/CountModelSideMenuItem.js.map +1 -1
  690. package/build/dist/UI/Components/SideMenu/SideMenu.js +76 -11
  691. package/build/dist/UI/Components/SideMenu/SideMenu.js.map +1 -1
  692. package/build/dist/UI/Components/SideMenu/SideMenuItem.js +50 -54
  693. package/build/dist/UI/Components/SideMenu/SideMenuItem.js.map +1 -1
  694. package/build/dist/UI/Components/SideMenu/SideMenuSection.js +32 -9
  695. package/build/dist/UI/Components/SideMenu/SideMenuSection.js.map +1 -1
  696. package/build/dist/UI/Components/SideOver/SideOver.js +5 -20
  697. package/build/dist/UI/Components/SideOver/SideOver.js.map +1 -1
  698. package/build/dist/UI/Utils/PageScrollLock.js +31 -3
  699. package/build/dist/UI/Utils/PageScrollLock.js.map +1 -1
  700. package/build/dist/UI/Utils/PermissionGate.js +42 -1
  701. package/build/dist/UI/Utils/PermissionGate.js.map +1 -1
  702. package/build/dist/UI/Utils/SensitiveUrlToken.js +97 -0
  703. package/build/dist/UI/Utils/SensitiveUrlToken.js.map +1 -0
  704. package/build/dist/UI/Utils/TestLLMProvider.js +4 -5
  705. package/build/dist/UI/Utils/TestLLMProvider.js.map +1 -1
  706. package/build/dist/UI/Utils/UseDashboardTimeRangeZoom.js +42 -0
  707. package/build/dist/UI/Utils/UseDashboardTimeRangeZoom.js.map +1 -0
  708. package/build/dist/Utils/Dashboard/DashboardTimeRangeZoom.js +74 -0
  709. package/build/dist/Utils/Dashboard/DashboardTimeRangeZoom.js.map +1 -0
  710. package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseSeats.js +15 -0
  711. package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseSeats.js.map +1 -1
  712. package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseUsage.js +111 -9
  713. package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseUsage.js.map +1 -1
  714. package/build/dist/Utils/Monitor/MonitorMetricType.js +109 -1
  715. package/build/dist/Utils/Monitor/MonitorMetricType.js.map +1 -1
  716. package/build/dist/Utils/Monitor/NetworkDeviceRoleCatalog.js +126 -0
  717. package/build/dist/Utils/Monitor/NetworkDeviceRoleCatalog.js.map +1 -0
  718. package/build/dist/Utils/Monitor/NetworkDeviceRoleUtil.js +2 -1
  719. package/build/dist/Utils/Monitor/NetworkDeviceRoleUtil.js.map +1 -1
  720. package/build/dist/Utils/Monitor/NetworkTopologyUtil.js +75 -35
  721. package/build/dist/Utils/Monitor/NetworkTopologyUtil.js.map +1 -1
  722. package/build/dist/Utils/NetworkDevice/DeviceHealthStateUtil.js +27 -7
  723. package/build/dist/Utils/NetworkDevice/DeviceHealthStateUtil.js.map +1 -1
  724. package/build/dist/Utils/NetworkDevice/DeviceReachabilityUtil.js +7 -5
  725. package/build/dist/Utils/NetworkDevice/DeviceReachabilityUtil.js.map +1 -1
  726. package/build/dist/Utils/NetworkDevice/DeviceRoleKeyUtil.js +114 -0
  727. package/build/dist/Utils/NetworkDevice/DeviceRoleKeyUtil.js.map +1 -0
  728. package/build/dist/Utils/NetworkDevice/NetworkAlertPolicyBootstrapUtil.js +180 -0
  729. package/build/dist/Utils/NetworkDevice/NetworkAlertPolicyBootstrapUtil.js.map +1 -0
  730. package/build/dist/Utils/NetworkDevice/SnmpCredentialUtil.js +12 -0
  731. package/build/dist/Utils/NetworkDevice/SnmpCredentialUtil.js.map +1 -0
  732. package/build/dist/Utils/NetworkDiscovery/AutoImportRuleMatcher.js +15 -5
  733. package/build/dist/Utils/NetworkDiscovery/AutoImportRuleMatcher.js.map +1 -1
  734. package/build/dist/Utils/NetworkDiscovery/DiscoveredDeviceBuilder.js +44 -15
  735. package/build/dist/Utils/NetworkDiscovery/DiscoveredDeviceBuilder.js.map +1 -1
  736. package/build/dist/Utils/NetworkDiscovery/DiscoveryImportEligibility.js +52 -23
  737. package/build/dist/Utils/NetworkDiscovery/DiscoveryImportEligibility.js.map +1 -1
  738. package/build/dist/Utils/NetworkDiscovery/PingMonitorBuilder.js +85 -13
  739. package/build/dist/Utils/NetworkDiscovery/PingMonitorBuilder.js.map +1 -1
  740. package/build/dist/Utils/NetworkSite/SiteStatusRollupUtil.js +30 -15
  741. package/build/dist/Utils/NetworkSite/SiteStatusRollupUtil.js.map +1 -1
  742. package/build/dist/Utils/NetworkSite/TypeHierarchyUtil.js +191 -0
  743. package/build/dist/Utils/NetworkSite/TypeHierarchyUtil.js.map +1 -0
  744. package/build/dist/Utils/Rules/RulePatternMatchUtil.js +1 -1
  745. package/build/dist/Utils/Slug.js +31 -1
  746. package/build/dist/Utils/Slug.js.map +1 -1
  747. package/package.json +2 -2
@@ -0,0 +1,926 @@
1
+ import fs from "fs";
2
+ import path from "path";
3
+ import { afterEach, describe, expect, test } from "@jest/globals";
4
+ import { ColumnMetadataArgs } from "typeorm/metadata-args/ColumnMetadataArgs";
5
+ import { RelationMetadataArgs } from "typeorm/metadata-args/RelationMetadataArgs";
6
+ import { getMetadataArgsStorage } from "typeorm";
7
+ import AllModelTypes from "../../../Models/DatabaseModels/Index";
8
+ import BaseModel from "../../../Models/DatabaseModels/DatabaseBaseModel/DatabaseBaseModel";
9
+ import NetworkDevice from "../../../Models/DatabaseModels/NetworkDevice";
10
+ import NetworkSite from "../../../Models/DatabaseModels/NetworkSite";
11
+ import NetworkSnmpCredentialProfile from "../../../Models/DatabaseModels/NetworkSnmpCredentialProfile";
12
+ import Project from "../../../Models/DatabaseModels/Project";
13
+ import NetworkSnmpCredentialProfileService from "../../../Server/Services/NetworkSnmpCredentialProfileService";
14
+ import Services from "../../../Server/Services/Index";
15
+ import Encryption from "../../../Server/Utils/Encryption";
16
+ import { ColumnAccessControl } from "../../../Types/BaseDatabase/AccessControl";
17
+ import ColumnType from "../../../Types/Database/ColumnType";
18
+ import LIMIT_MAX from "../../../Types/Database/LimitMax";
19
+ import { TableColumnMetadata } from "../../../Types/Database/TableColumn";
20
+ import TableColumnType from "../../../Types/Database/TableColumnType";
21
+ import { getUniqueColumnBy } from "../../../Types/Database/UniqueColumnBy";
22
+ import GenericFunction from "../../../Types/GenericFunction";
23
+ import ObjectID from "../../../Types/ObjectID";
24
+ import Permission, {
25
+ PermissionGroup,
26
+ PermissionHelper,
27
+ PermissionProps,
28
+ } from "../../../Types/Permission";
29
+
30
+ /*
31
+ * NetworkSnmpCredentialProfile: the contracts that live in decorator metadata
32
+ * and in wiring, which no functional test would notice losing.
33
+ *
34
+ * A profile is a row of SNMP credentials that devices and sites point at
35
+ * instead of carrying their own, and the poller resolves them in a fixed
36
+ * order: the device's columns, then the device's profile, then the site's
37
+ * profile. Three properties of the table are what make that safe to ship:
38
+ *
39
+ * 1. THE SECRETS ARE EXACTLY AS RESTRICTED AS THEY WERE ON THE DEVICE. The
40
+ * community string and the two v3 keys were already hidden from Viewer
41
+ * and SettingsViewer on NetworkDevice, and never selectable through a
42
+ * relation. Moving them onto a row that devices and sites JOIN is the
43
+ * obvious way to leak them: a device listing that selects
44
+ * `snmpCredentialProfile: { snmpCommunityString: true }` must be refused
45
+ * for the same callers it was refused for before. So the three columns
46
+ * are compared against the device's, permission for permission.
47
+ *
48
+ * 2. THE SECRETS ARE ENCRYPTED AT REST. `encrypted: true` on exactly those
49
+ * three columns is what makes DatabaseService encrypt them on every
50
+ * write and decrypt them on every server-side read. Drop the flag from
51
+ * one and that column silently goes back to plaintext in the database
52
+ * with nothing else changing; add it to a fourth and a column nobody
53
+ * expected to be ciphertext becomes unreadable through any path that
54
+ * bypasses the service. The list is pinned exactly, and the round trip
55
+ * is exercised through the service's own encrypt and decrypt steps.
56
+ *
57
+ * 3. DELETING A PROFILE NEVER DELETES WHAT USES IT. Both foreign keys are
58
+ * ON DELETE SET NULL, so deleting a profile drops its devices and sites
59
+ * down the resolution order instead of taking them with it. A CASCADE on
60
+ * either - the action most NetworkDevice relations use - would make
61
+ * deleting "Branch v2c" delete every branch switch.
62
+ *
63
+ * Nothing here touches a database: the model is instantiated and read for
64
+ * its decorator metadata, the repository is stubbed for the one read that
65
+ * exercises decryption, and the router registration that lives in another
66
+ * workspace is read off the source.
67
+ */
68
+
69
+ /*
70
+ * The API router lives in the App workspace, which this suite cannot import.
71
+ * It is read as text - the same thing the other wiring tests in this
72
+ * directory do - so the assertion is on the registration itself rather than
73
+ * on a re-export somebody could add to make it pass.
74
+ */
75
+ const BASE_API_INDEX_SOURCE: string = fs.readFileSync(
76
+ path.join(__dirname, "../../../../App/FeatureSet/BaseAPI/Index.ts"),
77
+ "utf8",
78
+ );
79
+
80
+ const PROJECT_ID: ObjectID = new ObjectID(
81
+ "11111111-1111-4111-8111-111111111111",
82
+ );
83
+ const PROFILE_ID: ObjectID = new ObjectID(
84
+ "22222222-2222-4222-8222-222222222222",
85
+ );
86
+
87
+ const SECRET_COLUMNS: ReadonlyArray<string> = [
88
+ "snmpCommunityString",
89
+ "snmpV3AuthKey",
90
+ "snmpV3PrivKey",
91
+ ];
92
+
93
+ const NON_SECRET_CREDENTIAL_COLUMNS: ReadonlyArray<string> = [
94
+ "snmpVersion",
95
+ "snmpPort",
96
+ "snmpV3SecurityLevel",
97
+ "snmpV3Username",
98
+ "snmpV3AuthProtocol",
99
+ "snmpV3PrivProtocol",
100
+ ];
101
+
102
+ /*
103
+ * Every column an operator writes on the profile form, and the two audit
104
+ * relations. `_id`, `createdAt` and the rest come from BaseModel and are not
105
+ * listed - the test that walks every column reads them from the model.
106
+ */
107
+ const DECLARED_COLUMNS: ReadonlyArray<string> = [
108
+ "project",
109
+ "projectId",
110
+ "name",
111
+ "description",
112
+ ...NON_SECRET_CREDENTIAL_COLUMNS,
113
+ ...SECRET_COLUMNS,
114
+ "createdByUser",
115
+ "createdByUserId",
116
+ "deletedByUser",
117
+ "deletedByUserId",
118
+ ];
119
+
120
+ function profile(): NetworkSnmpCredentialProfile {
121
+ return new NetworkSnmpCredentialProfile();
122
+ }
123
+
124
+ function relationArgs(
125
+ target: GenericFunction,
126
+ propertyName: string,
127
+ ): RelationMetadataArgs | undefined {
128
+ return getMetadataArgsStorage().relations.find(
129
+ (relation: RelationMetadataArgs): boolean => {
130
+ return (
131
+ relation.target === target && relation.propertyName === propertyName
132
+ );
133
+ },
134
+ );
135
+ }
136
+
137
+ function columnArgs(
138
+ target: GenericFunction,
139
+ propertyName: string,
140
+ ): ColumnMetadataArgs | undefined {
141
+ return getMetadataArgsStorage().columns.find(
142
+ (column: ColumnMetadataArgs): boolean => {
143
+ return column.target === target && column.propertyName === propertyName;
144
+ },
145
+ );
146
+ }
147
+
148
+ function accessControlFor(
149
+ model: BaseModel,
150
+ columnName: string,
151
+ ): ColumnAccessControl {
152
+ const accessControl: ColumnAccessControl | null =
153
+ model.getColumnAccessControlFor(columnName);
154
+
155
+ expect(accessControl).not.toBeNull();
156
+
157
+ return accessControl as ColumnAccessControl;
158
+ }
159
+
160
+ function sorted(permissions: ReadonlyArray<Permission>): Array<string> {
161
+ return permissions
162
+ .map((permission: Permission): string => {
163
+ return permission.toString();
164
+ })
165
+ .sort();
166
+ }
167
+
168
+ /*
169
+ * The device's read list for a column, with the device's own granular
170
+ * permission swapped for the profile's. That is the ONLY difference the
171
+ * profile is allowed to have from the device on a secret column.
172
+ */
173
+ function deviceReadListAsProfile(columnName: string): Array<string> {
174
+ return sorted(
175
+ accessControlFor(new NetworkDevice(), columnName).read.map(
176
+ (permission: Permission): Permission => {
177
+ return permission === Permission.ReadNetworkDevice
178
+ ? Permission.ReadNetworkSnmpCredentialProfile
179
+ : permission;
180
+ },
181
+ ),
182
+ );
183
+ }
184
+
185
+ afterEach(() => {
186
+ jest.restoreAllMocks();
187
+ });
188
+
189
+ describe("NetworkSnmpCredentialProfile is a project-scoped, API-exposed table", () => {
190
+ /*
191
+ * The tenant column is what makes every read, write and permission check
192
+ * project-scoped by default. Without it a credential table is global, and
193
+ * one project's community strings are readable from another.
194
+ */
195
+ test("it is scoped to a project by projectId", () => {
196
+ expect(profile().getTenantColumn()).toBe("projectId");
197
+ });
198
+
199
+ test("it is served at /network-snmp-credential-profile", () => {
200
+ expect(profile().getCrudApiPath()?.toString()).toBe(
201
+ "/network-snmp-credential-profile",
202
+ );
203
+ });
204
+
205
+ test("it maps to the NetworkSnmpCredentialProfile table", () => {
206
+ expect(profile().tableName).toBe("NetworkSnmpCredentialProfile");
207
+ });
208
+
209
+ /*
210
+ * A model that is not in AllModelTypes gets no table created for it and no
211
+ * permission catalogue coverage - and the two relations that already point
212
+ * at it from NetworkDevice and NetworkSite would fail at connection time.
213
+ */
214
+ test("the model is registered", () => {
215
+ expect(AllModelTypes).toContain(NetworkSnmpCredentialProfile);
216
+ });
217
+
218
+ test("the service is registered", () => {
219
+ expect(Services).toContain(NetworkSnmpCredentialProfileService);
220
+ });
221
+
222
+ test("the CRUD router is mounted in the API", () => {
223
+ expect(BASE_API_INDEX_SOURCE).toContain(
224
+ 'import NetworkSnmpCredentialProfile from "Common/Models/DatabaseModels/NetworkSnmpCredentialProfile";',
225
+ );
226
+ /*
227
+ * Matched with whitespace wildcards rather than as a literal, because
228
+ * prettier decides how the generic and its arguments wrap and that must
229
+ * not be what this test is about.
230
+ */
231
+ expect(BASE_API_INDEX_SOURCE).toMatch(
232
+ /new BaseAPI<\s*NetworkSnmpCredentialProfile,\s*NetworkSnmpCredentialProfileServiceType\s*>\(\s*NetworkSnmpCredentialProfile,\s*NetworkSnmpCredentialProfileService,?\s*\)\.getRouter\(\)/,
233
+ );
234
+ });
235
+ });
236
+
237
+ describe("the columns", () => {
238
+ test("every column the form writes is declared", () => {
239
+ const model: NetworkSnmpCredentialProfile = profile();
240
+
241
+ for (const columnName of DECLARED_COLUMNS) {
242
+ expect(model.getTableColumns().hasColumn(columnName)).toBe(true);
243
+ }
244
+ });
245
+
246
+ /*
247
+ * Required is EXACTLY name and projectId. Every credential column is
248
+ * optional on purpose: a v2c profile has no username, a v3 profile has no
249
+ * community string, and a noAuthNoPriv profile has no keys. Making any of
250
+ * them required would make one of those shapes impossible to save, and
251
+ * a profile with no credentials at all is a legitimate "attach now, fill
252
+ * in later" state - the poller's predicate, not the schema, decides when
253
+ * it is usable.
254
+ */
255
+ test("required columns are exactly name and projectId", () => {
256
+ expect(profile().getRequiredColumns().columns.sort()).toEqual([
257
+ "name",
258
+ "projectId",
259
+ ]);
260
+ });
261
+
262
+ /*
263
+ * No slug, and no @SlugifyColumn. A profile is never addressed by URL
264
+ * slug - it is picked from a dropdown on a device or a site - and a slug
265
+ * column would be one more thing that has to stay unique per project for
266
+ * no reader.
267
+ */
268
+ test("there is no slug column", () => {
269
+ expect(profile().getTableColumns().hasColumn("slug")).toBe(false);
270
+ expect(profile().getSlugifyColumn()).toBeFalsy();
271
+ });
272
+
273
+ /*
274
+ * Global uniqueness would mean the first project to create "Default v2c"
275
+ * stops every other project from having one.
276
+ */
277
+ test("name is unique per project, not globally", () => {
278
+ expect(getUniqueColumnBy(profile(), "name")).toBe("projectId");
279
+ });
280
+
281
+ test("name is a required ShortText readable through a relation, so listings can show it", () => {
282
+ const metadata: TableColumnMetadata =
283
+ profile().getTableColumnMetadata("name");
284
+
285
+ expect(metadata.required).toBe(true);
286
+ expect(metadata.type).toBe(TableColumnType.ShortText);
287
+ expect(metadata.canReadOnRelationQuery).toBe(true);
288
+ });
289
+
290
+ test("project is a relation to Project that cascades on project delete", () => {
291
+ const metadata: TableColumnMetadata =
292
+ profile().getTableColumnMetadata("project");
293
+
294
+ expect(metadata.type).toBe(TableColumnType.Entity);
295
+ expect(metadata.modelType).toBe(Project);
296
+ expect(metadata.manyToOneRelationColumn).toBe("projectId");
297
+ expect(
298
+ relationArgs(NetworkSnmpCredentialProfile, "project")?.options.onDelete,
299
+ ).toBe("CASCADE");
300
+ });
301
+ });
302
+
303
+ describe("the non-secret credential columns are the device's, column for column", () => {
304
+ /*
305
+ * The poller reads a device row and a profile row through one predicate,
306
+ * and a profile has to be able to hold anything a device could. So each
307
+ * non-secret credential column carries the same TableColumn type and the
308
+ * same TypeORM column type, length and default as the device's column of
309
+ * the same name. (The secret columns deliberately differ - see the next
310
+ * block - because ciphertext does not fit in the device's varchar.)
311
+ */
312
+ test.each(NON_SECRET_CREDENTIAL_COLUMNS)(
313
+ "%s has the same type, length and default as on NetworkDevice",
314
+ (columnName: string) => {
315
+ const profileMetadata: TableColumnMetadata =
316
+ profile().getTableColumnMetadata(columnName);
317
+ const deviceMetadata: TableColumnMetadata =
318
+ new NetworkDevice().getTableColumnMetadata(columnName);
319
+
320
+ expect(profileMetadata.type).toBe(deviceMetadata.type);
321
+ expect(profileMetadata.required).toBe(false);
322
+ expect(deviceMetadata.required).toBe(false);
323
+
324
+ const profileColumn: ColumnMetadataArgs | undefined = columnArgs(
325
+ NetworkSnmpCredentialProfile,
326
+ columnName,
327
+ );
328
+ const deviceColumn: ColumnMetadataArgs | undefined = columnArgs(
329
+ NetworkDevice,
330
+ columnName,
331
+ );
332
+
333
+ expect(profileColumn).toBeDefined();
334
+ expect(deviceColumn).toBeDefined();
335
+ expect(profileColumn?.options.type).toBe(deviceColumn?.options.type);
336
+ expect(profileColumn?.options.length).toBe(deviceColumn?.options.length);
337
+ expect(profileColumn?.options.default).toBe(
338
+ deviceColumn?.options.default,
339
+ );
340
+ expect(profileColumn?.options.nullable).toBe(true);
341
+ },
342
+ );
343
+
344
+ /*
345
+ * The two defaults are spelled out as well as compared, because they are
346
+ * what a freshly created profile is polled with: "V2c" is the stored
347
+ * spelling SnmpVersionUtil.parse expects, and 161 is the SNMP port.
348
+ */
349
+ test("snmpVersion defaults to V2c and snmpPort to 161", () => {
350
+ expect(
351
+ columnArgs(NetworkSnmpCredentialProfile, "snmpVersion")?.options.default,
352
+ ).toBe("V2c");
353
+ expect(
354
+ columnArgs(NetworkSnmpCredentialProfile, "snmpPort")?.options.default,
355
+ ).toBe(161);
356
+ expect(
357
+ columnArgs(NetworkSnmpCredentialProfile, "snmpPort")?.options.type,
358
+ ).toBe(ColumnType.Number);
359
+ });
360
+ });
361
+
362
+ describe("the three secret columns are encrypted at rest", () => {
363
+ /*
364
+ * THE LIST, EXACTLY. getEncryptedColumns() is what DatabaseService.encrypt
365
+ * and DatabaseService.decrypt iterate, so this single assertion is the
366
+ * whole of "which columns are ciphertext in the database". Compared as a
367
+ * sorted array rather than three toContain checks so that a fourth column
368
+ * picking up the flag - the username, say, which the poller and the UI
369
+ * both expect to read as plain text - fails here rather than in
370
+ * production.
371
+ */
372
+ test("exactly snmpCommunityString, snmpV3AuthKey and snmpV3PrivKey are encrypted", () => {
373
+ expect(profile().getEncryptedColumns().columns.sort()).toEqual(
374
+ [...SECRET_COLUMNS].sort(),
375
+ );
376
+ });
377
+
378
+ test.each(SECRET_COLUMNS)(
379
+ "%s carries encrypted: true",
380
+ (columnName: string) => {
381
+ expect(profile().getTableColumnMetadata(columnName).encrypted).toBe(true);
382
+ },
383
+ );
384
+
385
+ test.each([...NON_SECRET_CREDENTIAL_COLUMNS, "name", "description"])(
386
+ "%s, by contrast, is stored as plain text",
387
+ (columnName: string) => {
388
+ expect(
389
+ profile().getTableColumnMetadata(columnName).encrypted,
390
+ ).toBeFalsy();
391
+ },
392
+ );
393
+
394
+ /*
395
+ * Ciphertext is salted base64, two to three times the plaintext, so an
396
+ * encrypted column cannot be the device's varchar(100): a long community
397
+ * string would overflow it on write. Every other encrypted text column in
398
+ * the schema is `text` for the same reason, and these three follow.
399
+ */
400
+ test.each(SECRET_COLUMNS)(
401
+ "%s is a nullable, defaultless text column, because ciphertext is longer than plaintext",
402
+ (columnName: string) => {
403
+ const metadata: TableColumnMetadata =
404
+ profile().getTableColumnMetadata(columnName);
405
+
406
+ expect(metadata.type).toBe(TableColumnType.VeryLongText);
407
+ expect(metadata.required).toBe(false);
408
+
409
+ const column: ColumnMetadataArgs | undefined = columnArgs(
410
+ NetworkSnmpCredentialProfile,
411
+ columnName,
412
+ );
413
+
414
+ expect(column).toBeDefined();
415
+ expect(column?.options.type).toBe(ColumnType.VeryLongText);
416
+ expect(column?.options.nullable).toBe(true);
417
+ expect(column?.options.default).toBeUndefined();
418
+ expect(column?.options.length).toBeUndefined();
419
+ },
420
+ );
421
+
422
+ /*
423
+ * The device's own three columns are NOT encrypted: they predate
424
+ * encryption at rest, still hold plaintext in a varchar, and bringing them
425
+ * in line means re-encrypting every existing row in a separate migration.
426
+ * This pins the gap the model's WHY comment describes; when that migration
427
+ * lands, this test flips and the comment can go with it.
428
+ */
429
+ test.each(SECRET_COLUMNS)(
430
+ "the device's own %s is still plaintext - a separate migration, not this table's job",
431
+ (columnName: string) => {
432
+ expect(
433
+ new NetworkDevice().getTableColumnMetadata(columnName).encrypted,
434
+ ).toBeFalsy();
435
+ },
436
+ );
437
+ });
438
+
439
+ describe("the secrets round-trip through the service's encrypt and decrypt", () => {
440
+ type ServiceCryptoInternals = {
441
+ encrypt: (
442
+ data: NetworkSnmpCredentialProfile,
443
+ ) => Promise<NetworkSnmpCredentialProfile>;
444
+ decrypt: (
445
+ data: NetworkSnmpCredentialProfile,
446
+ ) => Promise<NetworkSnmpCredentialProfile>;
447
+ };
448
+
449
+ const internals: ServiceCryptoInternals =
450
+ NetworkSnmpCredentialProfileService as unknown as ServiceCryptoInternals;
451
+
452
+ function plaintextProfile(): NetworkSnmpCredentialProfile {
453
+ const row: NetworkSnmpCredentialProfile = profile();
454
+ row.id = PROFILE_ID;
455
+ row.projectId = PROJECT_ID;
456
+ row.name = "Branch v3";
457
+ row.snmpVersion = "V3";
458
+ row.snmpV3Username = "monitoring";
459
+ row.snmpCommunityString = "public";
460
+ row.snmpV3AuthKey = "auth-passphrase";
461
+ row.snmpV3PrivKey = "priv-passphrase";
462
+
463
+ return row;
464
+ }
465
+
466
+ /*
467
+ * DatabaseService.encrypt is the step every create and update runs after
468
+ * the service's own hooks. Driving it directly pins that the model's
469
+ * metadata - not anything in the service - is what turns the three secrets
470
+ * into ciphertext, and that nothing else on the row is touched.
471
+ */
472
+ test("the create/update encrypt step turns exactly the three secrets into ciphertext", async () => {
473
+ const row: NetworkSnmpCredentialProfile = plaintextProfile();
474
+
475
+ const encrypted: NetworkSnmpCredentialProfile =
476
+ await internals.encrypt(row);
477
+
478
+ expect(encrypted.snmpCommunityString).not.toBe("public");
479
+ expect(encrypted.snmpV3AuthKey).not.toBe("auth-passphrase");
480
+ expect(encrypted.snmpV3PrivKey).not.toBe("priv-passphrase");
481
+
482
+ expect(await Encryption.decrypt(encrypted.snmpCommunityString!)).toBe(
483
+ "public",
484
+ );
485
+ expect(await Encryption.decrypt(encrypted.snmpV3AuthKey!)).toBe(
486
+ "auth-passphrase",
487
+ );
488
+ expect(await Encryption.decrypt(encrypted.snmpV3PrivKey!)).toBe(
489
+ "priv-passphrase",
490
+ );
491
+
492
+ expect(encrypted.name).toBe("Branch v3");
493
+ expect(encrypted.snmpVersion).toBe("V3");
494
+ expect(encrypted.snmpV3Username).toBe("monitoring");
495
+ });
496
+
497
+ test("the find decrypt step hands the plaintext back", async () => {
498
+ const stored: NetworkSnmpCredentialProfile =
499
+ await internals.encrypt(plaintextProfile());
500
+
501
+ const decrypted: NetworkSnmpCredentialProfile =
502
+ await internals.decrypt(stored);
503
+
504
+ expect(decrypted.snmpCommunityString).toBe("public");
505
+ expect(decrypted.snmpV3AuthKey).toBe("auth-passphrase");
506
+ expect(decrypted.snmpV3PrivKey).toBe("priv-passphrase");
507
+ });
508
+
509
+ /*
510
+ * An unset secret must stay unset rather than becoming the ciphertext of
511
+ * "" - a v2c profile has no keys and a v3 profile has no community
512
+ * string, and the poller's predicate reads absence as absence.
513
+ */
514
+ test("an absent secret is left absent on both sides", async () => {
515
+ const row: NetworkSnmpCredentialProfile = profile();
516
+ row.name = "v2c only";
517
+ row.snmpVersion = "V2c";
518
+ row.snmpCommunityString = "public";
519
+
520
+ const encrypted: NetworkSnmpCredentialProfile =
521
+ await internals.encrypt(row);
522
+
523
+ expect(encrypted.snmpV3AuthKey).toBeUndefined();
524
+ expect(encrypted.snmpV3PrivKey).toBeUndefined();
525
+
526
+ const decrypted: NetworkSnmpCredentialProfile =
527
+ await internals.decrypt(encrypted);
528
+
529
+ expect(decrypted.snmpV3AuthKey).toBeUndefined();
530
+ expect(decrypted.snmpV3PrivKey).toBeUndefined();
531
+ expect(decrypted.snmpCommunityString).toBe("public");
532
+ });
533
+
534
+ /*
535
+ * The same thing through the public read path: a findBy as root, with the
536
+ * repository stubbed to return a row exactly as the database holds it
537
+ * (ciphertext), comes back plaintext. This is the read the poller makes.
538
+ */
539
+ test("a findBy as root returns the secrets decrypted", async () => {
540
+ const stored: NetworkSnmpCredentialProfile =
541
+ await internals.encrypt(plaintextProfile());
542
+
543
+ jest
544
+ .spyOn(NetworkSnmpCredentialProfileService, "getRepository")
545
+ .mockReturnValue({
546
+ find: async (): Promise<Array<NetworkSnmpCredentialProfile>> => {
547
+ return [stored];
548
+ },
549
+ } as unknown as ReturnType<
550
+ typeof NetworkSnmpCredentialProfileService.getRepository
551
+ >);
552
+
553
+ const rows: Array<NetworkSnmpCredentialProfile> =
554
+ await NetworkSnmpCredentialProfileService.findBy({
555
+ query: {
556
+ projectId: PROJECT_ID,
557
+ },
558
+ select: {
559
+ _id: true,
560
+ snmpVersion: true,
561
+ snmpV3Username: true,
562
+ snmpCommunityString: true,
563
+ snmpV3AuthKey: true,
564
+ snmpV3PrivKey: true,
565
+ },
566
+ limit: LIMIT_MAX,
567
+ skip: 0,
568
+ props: {
569
+ isRoot: true,
570
+ },
571
+ });
572
+
573
+ expect(rows.length).toBe(1);
574
+ expect(rows[0]!.snmpCommunityString).toBe("public");
575
+ expect(rows[0]!.snmpV3AuthKey).toBe("auth-passphrase");
576
+ expect(rows[0]!.snmpV3PrivKey).toBe("priv-passphrase");
577
+ expect(rows[0]!.snmpV3Username).toBe("monitoring");
578
+ });
579
+ });
580
+
581
+ describe("every column carries column access control", () => {
582
+ /*
583
+ * A column with no ColumnAccessControl is invisible to the permission
584
+ * layer: it is neither readable nor writable by anybody, and the
585
+ * generated API reference documents it as if it did not exist. Walking
586
+ * every column THIS MODEL declares catches the one somebody adds without
587
+ * it. BaseModel's own columns (_id, createdAt, version and the rest) are
588
+ * excluded from the walk: they get their access control from the table's
589
+ * permissions inside getColumnAccessControlForAllColumns, or are
590
+ * server-managed and deliberately have none, and either way they are
591
+ * BaseModel's business rather than this table's.
592
+ */
593
+ test("no column this model declares is missing its access control", () => {
594
+ const model: NetworkSnmpCredentialProfile = profile();
595
+ const inheritedColumns: Set<string> = new Set<string>(
596
+ new BaseModel().getTableColumns().columns,
597
+ );
598
+ const declaredColumns: Array<string> = model
599
+ .getTableColumns()
600
+ .columns.filter((columnName: string): boolean => {
601
+ return !inheritedColumns.has(columnName);
602
+ });
603
+
604
+ /*
605
+ * The list at the top of the file is the whole of what this model adds.
606
+ * If the walk finds a column that list does not know about, somebody
607
+ * added one and this suite has nothing to say about it yet.
608
+ */
609
+ expect(declaredColumns.sort()).toEqual([...DECLARED_COLUMNS].sort());
610
+
611
+ for (const columnName of declaredColumns) {
612
+ const accessControl: ColumnAccessControl | null =
613
+ model.getColumnAccessControlFor(columnName);
614
+
615
+ expect(accessControl).not.toBeNull();
616
+ expect(Array.isArray(accessControl?.read)).toBe(true);
617
+ expect(Array.isArray(accessControl?.create)).toBe(true);
618
+ expect(Array.isArray(accessControl?.update)).toBe(true);
619
+ }
620
+ });
621
+
622
+ test("every declared column honours the granular read permission", () => {
623
+ const model: NetworkSnmpCredentialProfile = profile();
624
+
625
+ for (const columnName of DECLARED_COLUMNS) {
626
+ expect(accessControlFor(model, columnName).read).toContain(
627
+ Permission.ReadNetworkSnmpCredentialProfile,
628
+ );
629
+ }
630
+ });
631
+
632
+ /*
633
+ * The audit columns are written by the server, never by the API. Granting
634
+ * update on deletedByUserId would let a caller forge who deleted a row.
635
+ */
636
+ test.each(["deletedByUser", "deletedByUserId"])(
637
+ "%s is server-owned: nobody may create or update it",
638
+ (columnName: string) => {
639
+ const accessControl: ColumnAccessControl = accessControlFor(
640
+ profile(),
641
+ columnName,
642
+ );
643
+
644
+ expect(accessControl.create).toEqual([]);
645
+ expect(accessControl.update).toEqual([]);
646
+ },
647
+ );
648
+
649
+ test.each(["project", "projectId", "createdByUser", "createdByUserId"])(
650
+ "%s is set on create and never moved",
651
+ (columnName: string) => {
652
+ expect(accessControlFor(profile(), columnName).update).toEqual([]);
653
+ },
654
+ );
655
+ });
656
+
657
+ describe("the three secret columns are as restricted as the device's", () => {
658
+ /*
659
+ * Column for column, the profile's secret read list is the device's secret
660
+ * read list with ReadNetworkDevice swapped for the profile's own granular
661
+ * permission - nothing added, nothing removed. Compared as sorted arrays
662
+ * rather than as a list of "must not contain" assertions, so a role added
663
+ * to the device's list later shows up here as a diff to think about
664
+ * rather than as a silent pass.
665
+ */
666
+ test.each(SECRET_COLUMNS)(
667
+ "%s is exactly as restricted to read as it is on NetworkDevice",
668
+ (columnName: string) => {
669
+ expect(sorted(accessControlFor(profile(), columnName).read)).toEqual(
670
+ deviceReadListAsProfile(columnName),
671
+ );
672
+ },
673
+ );
674
+
675
+ /*
676
+ * ...which, spelled out, means Viewer and SettingsViewer cannot read them
677
+ * while ProjectMember and the granular permission can. Both halves are
678
+ * asserted: a list that excluded everybody would pass the "not Viewer"
679
+ * check and lock the operator out of their own credentials.
680
+ */
681
+ test.each(SECRET_COLUMNS)(
682
+ "%s is hidden from Viewer and SettingsViewer, and readable by members",
683
+ (columnName: string) => {
684
+ const read: Array<Permission> = accessControlFor(
685
+ profile(),
686
+ columnName,
687
+ ).read;
688
+
689
+ expect(read).not.toContain(Permission.Viewer);
690
+ expect(read).not.toContain(Permission.SettingsViewer);
691
+ expect(read).toContain(Permission.ProjectOwner);
692
+ expect(read).toContain(Permission.ProjectAdmin);
693
+ expect(read).toContain(Permission.ProjectMember);
694
+ expect(read).toContain(Permission.ReadNetworkSnmpCredentialProfile);
695
+ },
696
+ );
697
+
698
+ /*
699
+ * Not selectable through a relation, exactly as on the device. This is
700
+ * the property that makes a profile safe to JOIN: the device and site
701
+ * listings select their profile's name and version through the relation,
702
+ * and a select that reaches for a secret through it is refused for every
703
+ * caller, not just the restricted ones.
704
+ */
705
+ test.each(SECRET_COLUMNS)(
706
+ "%s is not readable on a relation query",
707
+ (columnName: string) => {
708
+ expect(
709
+ profile().getTableColumnMetadata(columnName).canReadOnRelationQuery,
710
+ ).toBeFalsy();
711
+ expect(
712
+ new NetworkDevice().getTableColumnMetadata(columnName)
713
+ .canReadOnRelationQuery,
714
+ ).toBeFalsy();
715
+ },
716
+ );
717
+
718
+ /*
719
+ * Secret to READ, not to write: the operator who may edit the profile may
720
+ * set and rotate its secrets. A write list narrower than the row's would
721
+ * make the form save everything except the credential.
722
+ */
723
+ test.each(SECRET_COLUMNS)(
724
+ "%s can still be written by whoever can edit the profile",
725
+ (columnName: string) => {
726
+ const accessControl: ColumnAccessControl = accessControlFor(
727
+ profile(),
728
+ columnName,
729
+ );
730
+
731
+ expect(sorted(accessControl.create)).toEqual(
732
+ sorted(profile().createRecordPermissions),
733
+ );
734
+ expect(sorted(accessControl.update)).toEqual(
735
+ sorted(profile().updateRecordPermissions),
736
+ );
737
+ },
738
+ );
739
+
740
+ /*
741
+ * The contrast is the point. The non-secret credential columns - version,
742
+ * port, protocols, the v3 security NAME - are as readable as the row
743
+ * itself, so a Viewer can see that a device is walked as "v3 authPriv as
744
+ * monitoring" without seeing the keys.
745
+ */
746
+ test.each(NON_SECRET_CREDENTIAL_COLUMNS)(
747
+ "%s, by contrast, is readable by Viewer and SettingsViewer",
748
+ (columnName: string) => {
749
+ const read: Array<Permission> = accessControlFor(
750
+ profile(),
751
+ columnName,
752
+ ).read;
753
+
754
+ expect(read).toContain(Permission.Viewer);
755
+ expect(read).toContain(Permission.SettingsViewer);
756
+ expect(sorted(read)).toEqual(sorted(profile().readRecordPermissions));
757
+ },
758
+ );
759
+ });
760
+
761
+ describe("deleting a profile detaches what uses it", () => {
762
+ /*
763
+ * NetworkDevice and NetworkSite both point at a profile, and both must
764
+ * do so with ON DELETE SET NULL. The resolution order is what makes SET
765
+ * NULL the right answer: a device whose profile is deleted falls through
766
+ * to its site's profile, or to ping-only, which is exactly what "no
767
+ * profile" has always meant. CASCADE would make deleting a credential set
768
+ * delete the inventory that used it. (The service's delete guard is what
769
+ * stops that fall-through happening by accident; the FK action is what
770
+ * stops it deleting anything if the guard is ever bypassed.)
771
+ */
772
+ test("NetworkDevice points at the profile with SET NULL", () => {
773
+ const metadata: TableColumnMetadata =
774
+ new NetworkDevice().getTableColumnMetadata("snmpCredentialProfile");
775
+
776
+ expect(metadata.type).toBe(TableColumnType.Entity);
777
+ expect(metadata.modelType).toBe(NetworkSnmpCredentialProfile);
778
+ expect(metadata.manyToOneRelationColumn).toBe("snmpCredentialProfileId");
779
+ expect(
780
+ relationArgs(NetworkDevice, "snmpCredentialProfile")?.options.onDelete,
781
+ ).toBe("SET NULL");
782
+ });
783
+
784
+ test("NetworkSite points at the profile with SET NULL", () => {
785
+ const metadata: TableColumnMetadata =
786
+ new NetworkSite().getTableColumnMetadata("snmpCredentialProfile");
787
+
788
+ expect(metadata.type).toBe(TableColumnType.Entity);
789
+ expect(metadata.modelType).toBe(NetworkSnmpCredentialProfile);
790
+ expect(metadata.manyToOneRelationColumn).toBe("snmpCredentialProfileId");
791
+ expect(
792
+ relationArgs(NetworkSite, "snmpCredentialProfile")?.options.onDelete,
793
+ ).toBe("SET NULL");
794
+ });
795
+
796
+ test("the pointer on each is optional, because no profile means ping-only", () => {
797
+ expect(
798
+ new NetworkDevice().getTableColumnMetadata("snmpCredentialProfileId")
799
+ .required,
800
+ ).toBe(false);
801
+ expect(
802
+ new NetworkSite().getTableColumnMetadata("snmpCredentialProfileId")
803
+ .required,
804
+ ).toBe(false);
805
+ });
806
+ });
807
+
808
+ describe("the four credential-profile permissions", () => {
809
+ interface ProfilePermissionUnderTest {
810
+ name: string;
811
+ permission: Permission;
812
+ }
813
+
814
+ /*
815
+ * The names are written out rather than derived from the enum, because
816
+ * the stored value is the half that matters: a team's permission row
817
+ * persists the string, so a value that ever drifts from its member name
818
+ * orphans every grant already handed out.
819
+ */
820
+ const PROFILE_PERMISSIONS: Array<ProfilePermissionUnderTest> = [
821
+ {
822
+ name: "CreateNetworkSnmpCredentialProfile",
823
+ permission: Permission.CreateNetworkSnmpCredentialProfile,
824
+ },
825
+ {
826
+ name: "ReadNetworkSnmpCredentialProfile",
827
+ permission: Permission.ReadNetworkSnmpCredentialProfile,
828
+ },
829
+ {
830
+ name: "EditNetworkSnmpCredentialProfile",
831
+ permission: Permission.EditNetworkSnmpCredentialProfile,
832
+ },
833
+ {
834
+ name: "DeleteNetworkSnmpCredentialProfile",
835
+ permission: Permission.DeleteNetworkSnmpCredentialProfile,
836
+ },
837
+ ];
838
+
839
+ /*
840
+ * A permission the enum declares but the catalogue does not describe
841
+ * cannot be granted: the team-permission editor renders from
842
+ * getAllPermissionProps, so a missing descriptor means the permission
843
+ * exists, gates the model, and can never be handed to anybody.
844
+ */
845
+ test.each(PROFILE_PERMISSIONS)(
846
+ "$name has a catalogue entry in the Monitor group",
847
+ (entry: ProfilePermissionUnderTest) => {
848
+ const descriptor: PermissionProps | undefined =
849
+ PermissionHelper.getAllPermissionProps().find(
850
+ (props: PermissionProps): boolean => {
851
+ return props.permission === entry.permission;
852
+ },
853
+ );
854
+
855
+ expect(descriptor).toBeDefined();
856
+ /*
857
+ * Monitor, not Settings: profiles are configured under Network next
858
+ * to device roles and site types, and the group is what decides which
859
+ * section of the permission editor they appear in.
860
+ */
861
+ expect(descriptor?.group).toBe(PermissionGroup.Monitor);
862
+ expect(descriptor?.isAssignableToTenant).toBe(true);
863
+ /*
864
+ * The wording the editor shows. "SNMP Credential Profile", not the
865
+ * enum member's "NetworkSnmpCredentialProfile", is what an operator
866
+ * granting it is looking for.
867
+ */
868
+ expect(descriptor?.title).toContain("SNMP Credential Profile");
869
+ },
870
+ );
871
+
872
+ test.each(PROFILE_PERMISSIONS)(
873
+ "$name is stored under exactly its own name",
874
+ (entry: ProfilePermissionUnderTest) => {
875
+ expect(entry.permission.toString()).toBe(entry.name);
876
+ },
877
+ );
878
+
879
+ /*
880
+ * The table's own access control has to accept the granular permissions,
881
+ * or granting "Create SNMP Credential Profile" to a team would grant
882
+ * nothing at all - the catalogue entry would exist and the gate would
883
+ * still refuse.
884
+ */
885
+ test("the model's table access control honours each of them", () => {
886
+ const model: NetworkSnmpCredentialProfile = profile();
887
+
888
+ expect(model.createRecordPermissions).toContain(
889
+ Permission.CreateNetworkSnmpCredentialProfile,
890
+ );
891
+ expect(model.readRecordPermissions).toContain(
892
+ Permission.ReadNetworkSnmpCredentialProfile,
893
+ );
894
+ expect(model.updateRecordPermissions).toContain(
895
+ Permission.EditNetworkSnmpCredentialProfile,
896
+ );
897
+ expect(model.deleteRecordPermissions).toContain(
898
+ Permission.DeleteNetworkSnmpCredentialProfile,
899
+ );
900
+ });
901
+
902
+ /*
903
+ * The row itself is readable by Viewer and SettingsViewer - they can see
904
+ * that a profile exists and what it is called - while the write side is
905
+ * members and up. The secret columns narrow the read side; nothing
906
+ * narrows it at the table.
907
+ */
908
+ test("the row is readable by viewers and writable by members and up", () => {
909
+ const model: NetworkSnmpCredentialProfile = profile();
910
+
911
+ expect(model.readRecordPermissions).toContain(Permission.Viewer);
912
+ expect(model.readRecordPermissions).toContain(Permission.SettingsViewer);
913
+
914
+ for (const writeSide of [
915
+ model.createRecordPermissions,
916
+ model.updateRecordPermissions,
917
+ model.deleteRecordPermissions,
918
+ ]) {
919
+ expect(writeSide).toContain(Permission.ProjectOwner);
920
+ expect(writeSide).toContain(Permission.ProjectAdmin);
921
+ expect(writeSide).toContain(Permission.ProjectMember);
922
+ expect(writeSide).not.toContain(Permission.Viewer);
923
+ expect(writeSide).not.toContain(Permission.SettingsViewer);
924
+ }
925
+ });
926
+ });