@oneuptime/common 12.0.32 → 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.
- package/Models/AnalyticsModels/Span.ts +14 -0
- package/Models/DatabaseModels/EnterpriseLicense.ts +56 -0
- package/Models/DatabaseModels/Index.ts +10 -0
- package/Models/DatabaseModels/Monitor.ts +76 -0
- package/Models/DatabaseModels/NetworkAlertPolicy.ts +690 -0
- package/Models/DatabaseModels/NetworkDevice.ts +176 -1
- package/Models/DatabaseModels/NetworkSite.ts +201 -2
- package/Models/DatabaseModels/NetworkSiteType.ts +102 -3
- package/Models/DatabaseModels/NetworkSnmpCredentialProfile.ts +841 -0
- package/Models/DatabaseModels/TelemetryException.ts +119 -0
- package/Models/DatabaseModels/UserNotificationEmailRollupBatch.ts +334 -0
- package/Models/DatabaseModels/UserNotificationEmailRollupItem.ts +370 -0
- package/Models/DatabaseModels/UserNotificationEmailRollupSetting.ts +282 -0
- package/Server/API/EnterpriseLicenseAPI.ts +391 -64
- package/Server/API/LlmProviderAPI.ts +137 -22
- package/Server/EnvironmentConfig.ts +14 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1790700000000-AddNetworkSiteTypeParentHierarchy.ts +55 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1790900000000-AddEnterpriseLicenseUsageProvenance.ts +31 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1790900000000-AddTelemetryExceptionErrorClass.ts +124 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1791000000000-AddUserNotificationEmailRollup.ts +132 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1791100000000-AddUserNotificationEmailRollupSetting.ts +79 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1791200000000-AddNetworkSnmpCredentialProfilesAndAlertPolicies.ts +191 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +12 -0
- package/Server/Infrastructure/QueueWorker.ts +38 -8
- package/Server/Middleware/BearerTokenAuthorization.ts +12 -0
- package/Server/Middleware/ProjectAuthorization.ts +11 -0
- package/Server/Middleware/SCIMAuthorization.ts +12 -0
- package/Server/Middleware/TelemetryIngest.ts +11 -0
- package/Server/Services/AIBillingService.ts +101 -27
- package/Server/Services/EnterpriseLicenseInstanceService.ts +197 -0
- package/Server/Services/EnterpriseLicenseService.ts +55 -0
- package/Server/Services/Index.ts +10 -0
- package/Server/Services/MonitorService.ts +143 -21
- package/Server/Services/MonitorStatusTimelineService.ts +150 -8
- package/Server/Services/MonitorTemplateService.ts +217 -1
- package/Server/Services/NetworkAlertPolicyEngineService.ts +2159 -0
- package/Server/Services/NetworkAlertPolicyService.ts +944 -0
- package/Server/Services/NetworkDeviceAutoImportRuleEngineService.ts +9 -10
- package/Server/Services/NetworkDeviceAutoImportRuleService.ts +60 -15
- package/Server/Services/NetworkDeviceService.ts +1032 -73
- package/Server/Services/NetworkSiteService.ts +1502 -129
- package/Server/Services/NetworkSiteTypeService.ts +1216 -0
- package/Server/Services/NetworkSnmpCredentialProfileService.ts +238 -0
- package/Server/Services/NotificationService.ts +118 -28
- package/Server/Services/ProjectService.ts +105 -48
- package/Server/Services/StatusPagePrivateUserService.ts +103 -3
- package/Server/Services/UserNotificationEmailRollupBatchService.ts +78 -0
- package/Server/Services/UserNotificationEmailRollupItemService.ts +79 -0
- package/Server/Services/UserNotificationEmailRollupSettingService.ts +113 -0
- package/Server/Services/UserNotificationSettingService.ts +62 -25
- package/Server/Services/UserService.ts +95 -0
- package/Server/Types/Database/QueryHelper.ts +2 -2
- package/Server/Utils/AI/Chat/ObservabilityChatPrompt.ts +14 -3
- package/Server/Utils/AI/SRE/Insights/Detectors/ExceptionSpikeDetector.ts +10 -0
- package/Server/Utils/AI/SRE/Insights/Detectors/NewExceptionDetector.ts +10 -0
- package/Server/Utils/AI/SRE/Insights/InsightTriageRunner.ts +62 -1
- package/Server/Utils/AI/Toolbox/AlertTools.ts +15 -1
- package/Server/Utils/Billing/BillingFailureNoticeThrottle.ts +80 -0
- package/Server/Utils/DataSource/HttpFetch.ts +9 -2
- package/Server/Utils/EmailRollup/EmailRollupConstants.ts +98 -0
- package/Server/Utils/EmailRollup/EmailRollupFlushRunner.ts +872 -0
- package/Server/Utils/EmailRollup/EmailRollupRenderer.ts +781 -0
- package/Server/Utils/EmailRollup/EmailRollupWriter.ts +368 -0
- package/Server/Utils/LLM/LLMService.ts +78 -0
- package/Server/Utils/LogRedaction.ts +8 -0
- package/Server/Utils/Logger.ts +79 -1
- package/Server/Utils/Monitor/Criteria/DatabaseMonitorCriteria.ts +190 -0
- package/Server/Utils/Monitor/Criteria/EvaluateOverTime.ts +9 -2
- package/Server/Utils/Monitor/Criteria/SnmpMonitorCriteria.ts +61 -1
- package/Server/Utils/Monitor/MonitorCriteriaDataExtractor.ts +14 -0
- package/Server/Utils/Monitor/MonitorCriteriaEvaluator.ts +49 -0
- package/Server/Utils/Monitor/MonitorCriteriaObservationBuilder.ts +255 -4
- package/Server/Utils/Monitor/MonitorMetricUtil.ts +41 -0
- package/Server/Utils/Monitor/MonitorTemplateUtil.ts +43 -0
- package/Server/Utils/Monitor/NetworkDeviceHydrationUtil.ts +499 -19
- package/Server/Utils/Monitor/NetworkDeviceMetricUtil.ts +66 -10
- package/Server/Utils/Monitor/NetworkDeviceWalkUtil.ts +238 -44
- package/Server/Utils/Monitor/NetworkInventoryUtil.ts +146 -39
- package/Server/Utils/NetworkDevice/DeviceHealthAggregation.ts +31 -18
- package/Server/Utils/NetworkSite/NetworkSiteHierarchyLock.ts +213 -0
- package/Server/Utils/OutboundUserAgent.ts +152 -0
- package/Server/Utils/StartServer.ts +51 -19
- package/Server/Utils/Telemetry/CaptureSpan.ts +32 -8
- package/Server/Utils/Telemetry/ErrorClassResolver.ts +120 -0
- package/Server/Utils/Telemetry/SpanUtil.ts +33 -0
- package/Server/Utils/Telemetry.ts +198 -51
- package/Server/Views/Partials/SensitiveUrlToken.ejs +140 -0
- package/Tests/App/Dashboard/AddNeighborToMonitoringModal.test.tsx +134 -33
- package/Tests/App/Dashboard/AskAiSuggestedPrompts.test.ts +279 -0
- package/Tests/App/Dashboard/DashboardEditPermissions.test.tsx +517 -0
- package/Tests/App/Dashboard/DashboardVariablesDiscard.test.tsx +26 -0
- package/Tests/App/Dashboard/DeviceStatusHero.test.tsx +588 -0
- package/Tests/App/Dashboard/DiscoveryScanWizardValidation.test.tsx +18 -9
- package/Tests/App/Dashboard/MonitorCreateFromMonitorBackedDevice.test.tsx +632 -0
- package/Tests/App/Dashboard/MonitorRecommendationCreateProgress.test.tsx +682 -0
- package/Tests/App/Dashboard/MonitorTypePicker.test.tsx +4 -2
- package/Tests/App/Dashboard/NetworkDeviceCreateFormMonitorBinding.test.tsx +676 -0
- package/Tests/App/Dashboard/NetworkDeviceCreateFormPingMonitor.test.tsx +791 -0
- package/Tests/App/Dashboard/NetworkDeviceCreateFormProbeAndSnmp.test.tsx +833 -0
- package/Tests/App/Dashboard/NetworkDeviceCriteriaFilter.test.ts +161 -0
- package/Tests/App/Dashboard/NetworkDeviceSettingsMonitoringSection.test.tsx +458 -0
- package/Tests/App/Dashboard/NetworkSideMenu.test.tsx +41 -5
- package/Tests/App/Dashboard/PingMonitorProvisioning.test.ts +368 -0
- package/Tests/App/Dashboard/RecommendationCard.test.tsx +796 -0
- package/Tests/App/Dashboard/RecommendationToolbar.test.tsx +519 -0
- package/Tests/App/Dashboard/RecommendationsList.test.tsx +661 -0
- package/Tests/App/Dashboard/UseBulkCreatePingMonitors.test.tsx +899 -0
- package/Tests/App/Dashboard/UseBulkSnmpCredentialProfileActions.test.tsx +732 -0
- package/Tests/App/SensitiveUrlTokenBootstrap.test.ts +256 -0
- package/Tests/App/StatusPage/StatusPageIndexPageRobotsMeta.test.ts +11 -1
- package/Tests/App/StatusPage/StatusPageLoginCodeBootstrap.test.ts +9 -4
- package/Tests/Models/NetworkSiteHierarchy.test.ts +41 -4
- package/Tests/Server/API/EnterpriseLicenseReportUserCount.test.ts +951 -7
- package/Tests/Server/API/LlmProviderConnectionTest.test.ts +522 -0
- package/Tests/Server/Infrastructure/Postgres/NetworkSnmpCredentialProfilesAndAlertPoliciesMigration.test.ts +854 -0
- package/Tests/Server/Infrastructure/Postgres/SchemaMigrationsOrdering.test.ts +18 -0
- package/Tests/Server/Infrastructure/Postgres/UserNotificationEmailRollupTableMigration.test.ts +535 -0
- package/Tests/Server/Services/AIChatPrivacyPin.test.ts +560 -0
- package/Tests/Server/Services/BillingRechargeOwnerEmailGuards.test.ts +783 -0
- package/Tests/Server/Services/EnterpriseLicenseInstanceServiceDeletionUsage.test.ts +707 -0
- package/Tests/Server/Services/EnterpriseLicenseServiceUsageAggregationLock.test.ts +329 -0
- package/Tests/Server/Services/MonitorServiceDeleteNetworkDeviceCleanup.test.ts +294 -0
- package/Tests/Server/Services/MonitorStatusBridgeProbePath.test.ts +802 -0
- package/Tests/Server/Services/MonitorStatusTimelineService.test.ts +72 -2
- package/Tests/Server/Services/NetworkAlertPolicyEngineHooks.test.ts +752 -0
- package/Tests/Server/Services/NetworkAlertPolicyEngineService.test.ts +1849 -0
- package/Tests/Server/Services/NetworkAlertPolicyModel.test.ts +1793 -0
- package/Tests/Server/Services/NetworkDeviceAutoImportRuleEngineService.test.ts +47 -4
- package/Tests/Server/Services/NetworkDeviceAutoImportRuleService.test.ts +97 -12
- package/Tests/Server/Services/NetworkDeviceAutoMonitorLifecycle.test.ts +148 -3
- package/Tests/Server/Services/NetworkDeviceMonitorBindingUpdateGuard.test.ts +514 -0
- package/Tests/Server/Services/NetworkDeviceMonitorStatusStamp.test.ts +447 -58
- package/Tests/Server/Services/NetworkDeviceMonitoringMethodTransition.test.ts +739 -0
- package/Tests/Server/Services/NetworkDevicePollingTenancy.test.ts +501 -0
- package/Tests/Server/Services/NetworkDeviceSiteDefaultProbe.test.ts +432 -0
- package/Tests/Server/Services/NetworkSiteMonitoringDefaults.test.ts +498 -0
- package/Tests/Server/Services/NetworkSiteRollupPolicyAndMaintenance.test.ts +337 -55
- package/Tests/Server/Services/NetworkSiteService.test.ts +1868 -131
- package/Tests/Server/Services/NetworkSiteTypeService.test.ts +1109 -0
- package/Tests/Server/Services/NetworkSnmpCredentialProfileModel.test.ts +926 -0
- package/Tests/Server/Services/NetworkSnmpCredentialProfileService.test.ts +796 -0
- package/Tests/Server/Services/ProjectServiceNetworkSiteTypeDefaults.test.ts +214 -0
- package/Tests/Server/Services/StatusPagePrivateUserEmailChangePasswordResetExpiry.test.ts +269 -0
- package/Tests/Server/Services/UserEmailChangePasswordResetExpiry.test.ts +472 -0
- package/Tests/Server/Services/UserNotificationEmailRollupModels.test.ts +569 -0
- package/Tests/Server/Services/UserNotificationEmailRollupSettingModel.test.ts +314 -0
- package/Tests/Server/Services/UserNotificationEmailRollupSettingService.test.ts +409 -0
- package/Tests/Server/Services/UserNotificationSettingRollupRouting.test.ts +856 -0
- package/Tests/Server/Services/UserNotificationSettingWorkspaceChannels.test.ts +102 -1
- package/Tests/Server/Types/Database/Permissions/DashboardAccessPermission.test.ts +321 -0
- package/Tests/Server/Types/Database/QueryHelperOperators.test.ts +17 -0
- package/Tests/Server/Utils/AI/AlertMonitorFilters.test.ts +124 -0
- package/Tests/Server/Utils/AI/Insights/InsightTriageRunner.test.ts +208 -0
- package/Tests/Server/Utils/AI/LLMServiceToolCalling.test.ts +235 -0
- package/Tests/Server/Utils/AI/ObservabilityChatPrompt.test.ts +253 -0
- package/Tests/Server/Utils/Captcha.test.ts +422 -0
- package/Tests/Server/Utils/DataSource/HttpFetch.test.ts +96 -2
- package/Tests/Server/Utils/Database/MigrationFailureLog.test.ts +466 -0
- package/Tests/Server/Utils/EmailRollup/EmailRollupFlushRunnerBehaviour.test.ts +1096 -0
- package/Tests/Server/Utils/EmailRollup/EmailRollupFlushRunnerClaim.test.ts +466 -0
- package/Tests/Server/Utils/EmailRollup/EmailRollupRenderer.test.ts +1428 -0
- package/Tests/Server/Utils/EmailRollup/EmailRollupTestHarness.ts +752 -0
- package/Tests/Server/Utils/EmailRollup/EmailRollupWriter.test.ts +864 -0
- package/Tests/Server/Utils/LoggerFaultDemotion.test.ts +346 -0
- package/Tests/Server/Utils/Monitor/Criteria/DatabaseMonitorCriteria.test.ts +633 -0
- package/Tests/Server/Utils/Monitor/Criteria/SnmpMonitorCriteria.test.ts +196 -0
- package/Tests/Server/Utils/Monitor/DatabaseMetricWrite.test.ts +367 -0
- package/Tests/Server/Utils/Monitor/MonitorCriteriaObservationBuilderUnits.test.ts +100 -0
- package/Tests/Server/Utils/Monitor/MonitorStepResourceIdentity.test.ts +5 -0
- package/Tests/Server/Utils/Monitor/NetworkDeviceHydrationUtil.test.ts +512 -31
- package/Tests/Server/Utils/Monitor/NetworkDeviceMetricUtil.test.ts +252 -0
- package/Tests/Server/Utils/Monitor/NetworkDeviceWalkUtil.test.ts +479 -42
- package/Tests/Server/Utils/Monitor/NetworkInventoryUtil.test.ts +351 -5
- package/Tests/Server/Utils/NetworkDevice/DeviceHealthAggregation.test.ts +136 -12
- package/Tests/Server/Utils/NetworkSite/NetworkSiteHierarchyLock.test.ts +306 -0
- package/Tests/Server/Utils/OutboundUserAgent.test.ts +266 -0
- package/Tests/Server/Utils/SecurityEvent/ThreatIntel/TaxiiClientUserAgent.test.ts +141 -0
- package/Tests/Server/Utils/Telemetry/ErrorClassResolver.test.ts +298 -0
- package/Tests/Server/Utils/Telemetry.test.ts +456 -66
- package/Tests/Types/Monitor/DatabaseMetricCatalog.test.ts +388 -0
- package/Tests/Types/Monitor/MonitorStepDatabaseMonitor.test.ts +243 -0
- package/Tests/Types/Monitor/MonitorStepDefaultTelemetryConfig.test.ts +1 -0
- package/Tests/Types/Monitor/MonitorType.test.ts +1 -0
- package/Tests/Types/Monitor/MonitorTypeKeywords.test.ts +16 -7
- package/Tests/Types/Monitor/NetworkDeviceAlertPack.test.ts +60 -0
- package/Tests/Types/NetworkDevice/NetworkAlertPolicyScope.test.ts +655 -0
- package/Tests/Types/NetworkDevice/NetworkDeviceMonitoringMethod.test.ts +115 -26
- package/Tests/Types/NetworkSite/DefaultNetworkSiteType.test.ts +39 -0
- package/Tests/Types/NotificationSetting/NotificationEmailRollupPolicy.test.ts +299 -0
- package/Tests/Types/Telemetry/ErrorClass.test.ts +483 -0
- package/Tests/UI/Components/BasicRadioButtons.test.tsx +336 -0
- package/Tests/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.test.ts +15 -0
- package/Tests/UI/Components/ProgressBar.test.tsx +38 -2
- package/Tests/UI/Components/SideMenuItem.test.tsx +226 -4
- package/Tests/UI/Components/SideMenuSection.test.tsx +310 -0
- package/Tests/UI/Components/SideOverSubmitState.test.tsx +335 -0
- package/Tests/UI/Utils/PageScrollLock.test.tsx +377 -0
- package/Tests/UI/Utils/PermissionGate.test.ts +78 -0
- package/Tests/UI/Utils/SensitiveUrlToken.test.ts +140 -0
- package/Tests/Utils/EnterpriseLicenseSeats.test.ts +69 -0
- package/Tests/Utils/EnterpriseLicenseSync.test.ts +7 -1
- package/Tests/Utils/EnterpriseLicenseUsage.test.ts +433 -2
- package/Tests/Utils/Monitor/MonitorMetricType.test.ts +280 -1
- package/Tests/Utils/Monitor/MonitorSummarySnapshotUtil.test.ts +1 -0
- package/Tests/Utils/Monitor/NetworkTopologyUtil.test.ts +38 -0
- package/Tests/Utils/NetworkDevice/DeviceHealthStateUtil.test.ts +284 -23
- package/Tests/Utils/NetworkDevice/DeviceReachabilityUtil.test.ts +177 -0
- package/Tests/Utils/NetworkDevice/MonitoringMethodThreadedClassifiers.test.ts +992 -0
- package/Tests/Utils/NetworkDevice/NetworkAlertPolicyBootstrapUtil.test.ts +427 -0
- package/Tests/Utils/NetworkDevice/ReachabilityStampConsistency.test.ts +185 -0
- package/Tests/Utils/NetworkDevice/SnmpCredentialUtil.test.ts +268 -0
- package/Tests/Utils/NetworkDiscovery/AutoImportRuleMatcher.test.ts +55 -5
- package/Tests/Utils/NetworkDiscovery/DiscoveredDeviceBuilder.test.ts +98 -21
- package/Tests/Utils/NetworkDiscovery/DiscoveryImportEligibility.test.ts +98 -20
- package/Tests/Utils/NetworkDiscovery/DiscoveryReverseDnsChain.test.ts +8 -7
- package/Tests/Utils/NetworkDiscovery/PingMonitorBuilderForAddress.test.ts +274 -0
- package/Tests/Utils/NetworkSite/SiteStatusRollupUtil.test.ts +230 -51
- package/Tests/Utils/NetworkSite/TypeHierarchyUtil.test.ts +209 -0
- package/Tests/Utils/Telemetry/CaptureSpanExportGating.test.ts +145 -0
- package/Types/AI/ExceptionAIClassification.ts +10 -24
- package/Types/Email/EmailTemplateType.ts +2 -0
- package/Types/EnterpriseLicense/EnterpriseLicenseInstanceSummary.ts +5 -0
- package/Types/EnterpriseLicense/EnterpriseLicenseUsageSnapshot.ts +13 -0
- package/Types/EnterpriseLicense/EnterpriseLicenseUserCountSource.ts +6 -0
- package/Types/Exception/ApiException.ts +10 -0
- package/Types/Exception/BadDataException.ts +11 -0
- package/Types/Exception/BadRequestException.ts +11 -0
- package/Types/Exception/Exception.ts +65 -0
- package/Types/Exception/ForbiddenException.ts +10 -0
- package/Types/Exception/NotAuthenticatedException.ts +10 -0
- package/Types/Exception/NotAuthorizedException.ts +10 -0
- package/Types/Exception/NotFoundException.ts +11 -0
- package/Types/Exception/PayloadTooLargeException.ts +11 -0
- package/Types/Exception/PaymentRequiredException.ts +10 -0
- package/Types/Exception/ServiceUnavailableException.ts +10 -0
- package/Types/Exception/SsoAuthorizationException.ts +10 -0
- package/Types/Exception/TenantNotFoundException.ts +11 -0
- package/Types/Exception/TimeoutException.ts +10 -0
- package/Types/Exception/TooManyRequestsException.ts +10 -0
- package/Types/Exception/UnableToReachServer.ts +10 -0
- package/Types/Exception/WebsiteRequestException.ts +10 -0
- package/Types/Monitor/CriteriaFilter.ts +60 -2
- package/Types/Monitor/DatabaseMetricCatalog.ts +693 -0
- package/Types/Monitor/DatabaseMonitor/DatabaseMonitorResponse.ts +83 -0
- package/Types/Monitor/MonitorCriteriaInstance.ts +76 -0
- package/Types/Monitor/MonitorMetricType.ts +71 -0
- package/Types/Monitor/MonitorStep.ts +76 -0
- package/Types/Monitor/MonitorStepDatabaseMonitor.ts +171 -0
- package/Types/Monitor/MonitorStepSqlMonitor.ts +2 -20
- package/Types/Monitor/MonitorType.ts +47 -1
- package/Types/Monitor/SnmpMonitor/NetworkDeviceAlertPack.ts +22 -1
- package/Types/Monitor/SqlConnectionConfig.ts +31 -0
- package/Types/NetworkDevice/NetworkAlertPolicyScope.ts +343 -0
- package/Types/NetworkDevice/NetworkDeviceMonitoringMethod.ts +42 -22
- package/Types/NetworkSite/DefaultNetworkSiteTypeHierarchy.ts +30 -0
- package/Types/NotificationSetting/NotificationEmailRollupCategory.ts +255 -0
- package/Types/NotificationSetting/NotificationEmailRollupPolicy.ts +104 -0
- package/Types/Permission.ts +90 -0
- package/Types/Probe/ProbeMonitorResponse.ts +16 -0
- package/Types/Telemetry/ErrorClass.ts +274 -0
- package/Types/Telemetry/UnitOfWork.ts +59 -0
- package/UI/Components/CommandPalette/CommandPalette.tsx +2 -8
- package/UI/Components/EditionLabel/EditionLabel.tsx +4 -0
- package/UI/Components/Modal/Modal.tsx +2 -8
- package/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.ts +44 -0
- package/UI/Components/ProgressBar/ProgressBar.tsx +12 -1
- package/UI/Components/RadioButtons/BasicRadioButtons.tsx +37 -7
- package/UI/Components/SideMenu/SideMenu.tsx +123 -5
- package/UI/Components/SideMenu/SideMenuItem.tsx +76 -84
- package/UI/Components/SideMenu/SideMenuSection.tsx +55 -23
- package/UI/Components/SideOver/SideOver.tsx +21 -20
- package/UI/Utils/PageScrollLock.ts +79 -3
- package/UI/Utils/PermissionGate.ts +61 -0
- package/UI/Utils/SensitiveUrlToken.ts +112 -0
- package/UI/Utils/TestLLMProvider.ts +11 -0
- package/Utils/EnterpriseLicense/EnterpriseLicenseSeats.ts +16 -0
- package/Utils/EnterpriseLicense/EnterpriseLicenseUsage.ts +191 -11
- package/Utils/Monitor/MonitorMetricType.ts +153 -1
- package/Utils/Monitor/NetworkTopologyUtil.ts +23 -3
- package/Utils/NetworkDevice/DeviceHealthStateUtil.ts +65 -14
- package/Utils/NetworkDevice/DeviceReachabilityUtil.ts +43 -14
- package/Utils/NetworkDevice/NetworkAlertPolicyBootstrapUtil.ts +247 -0
- package/Utils/NetworkDevice/SnmpCredentialUtil.ts +68 -0
- package/Utils/NetworkDiscovery/AutoImportRuleMatcher.ts +15 -7
- package/Utils/NetworkDiscovery/DiscoveredDeviceBuilder.ts +52 -17
- package/Utils/NetworkDiscovery/DiscoveryImportEligibility.ts +55 -23
- package/Utils/NetworkDiscovery/PingMonitorBuilder.ts +115 -13
- package/Utils/NetworkSite/SiteStatusRollupUtil.ts +66 -20
- package/Utils/NetworkSite/TypeHierarchyUtil.ts +313 -0
- package/build/dist/Models/AnalyticsModels/Span.js +14 -0
- package/build/dist/Models/AnalyticsModels/Span.js.map +1 -1
- package/build/dist/Models/DatabaseModels/EnterpriseLicense.js +59 -0
- package/build/dist/Models/DatabaseModels/EnterpriseLicense.js.map +1 -1
- package/build/dist/Models/DatabaseModels/Index.js +10 -0
- package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
- package/build/dist/Models/DatabaseModels/Monitor.js +75 -0
- package/build/dist/Models/DatabaseModels/Monitor.js.map +1 -1
- package/build/dist/Models/DatabaseModels/NetworkAlertPolicy.js +713 -0
- package/build/dist/Models/DatabaseModels/NetworkAlertPolicy.js.map +1 -0
- package/build/dist/Models/DatabaseModels/NetworkDevice.js +180 -1
- package/build/dist/Models/DatabaseModels/NetworkDevice.js.map +1 -1
- package/build/dist/Models/DatabaseModels/NetworkSite.js +200 -2
- package/build/dist/Models/DatabaseModels/NetworkSite.js.map +1 -1
- package/build/dist/Models/DatabaseModels/NetworkSiteType.js +102 -3
- package/build/dist/Models/DatabaseModels/NetworkSiteType.js.map +1 -1
- package/build/dist/Models/DatabaseModels/NetworkSnmpCredentialProfile.js +878 -0
- package/build/dist/Models/DatabaseModels/NetworkSnmpCredentialProfile.js.map +1 -0
- package/build/dist/Models/DatabaseModels/TelemetryException.js +123 -0
- package/build/dist/Models/DatabaseModels/TelemetryException.js.map +1 -1
- package/build/dist/Models/DatabaseModels/UserNotificationEmailRollupBatch.js +363 -0
- package/build/dist/Models/DatabaseModels/UserNotificationEmailRollupBatch.js.map +1 -0
- package/build/dist/Models/DatabaseModels/UserNotificationEmailRollupItem.js +402 -0
- package/build/dist/Models/DatabaseModels/UserNotificationEmailRollupItem.js.map +1 -0
- package/build/dist/Models/DatabaseModels/UserNotificationEmailRollupSetting.js +296 -0
- package/build/dist/Models/DatabaseModels/UserNotificationEmailRollupSetting.js.map +1 -0
- package/build/dist/Server/API/EnterpriseLicenseAPI.js +273 -60
- package/build/dist/Server/API/EnterpriseLicenseAPI.js.map +1 -1
- package/build/dist/Server/API/LlmProviderAPI.js +108 -13
- package/build/dist/Server/API/LlmProviderAPI.js.map +1 -1
- package/build/dist/Server/EnvironmentConfig.js +12 -0
- package/build/dist/Server/EnvironmentConfig.js.map +1 -1
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1790700000000-AddNetworkSiteTypeParentHierarchy.js +24 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1790700000000-AddNetworkSiteTypeParentHierarchy.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1790900000000-AddEnterpriseLicenseUsageProvenance.js +16 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1790900000000-AddEnterpriseLicenseUsageProvenance.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1790900000000-AddTelemetryExceptionErrorClass.js +111 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1790900000000-AddTelemetryExceptionErrorClass.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1791000000000-AddUserNotificationEmailRollup.js +77 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1791000000000-AddUserNotificationEmailRollup.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1791100000000-AddUserNotificationEmailRollupSetting.js +50 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1791100000000-AddUserNotificationEmailRollupSetting.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1791200000000-AddNetworkSnmpCredentialProfilesAndAlertPolicies.js +83 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1791200000000-AddNetworkSnmpCredentialProfilesAndAlertPolicies.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +12 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
- package/build/dist/Server/Infrastructure/QueueWorker.js +33 -5
- package/build/dist/Server/Infrastructure/QueueWorker.js.map +1 -1
- package/build/dist/Server/Middleware/BearerTokenAuthorization.js +12 -0
- package/build/dist/Server/Middleware/BearerTokenAuthorization.js.map +1 -1
- package/build/dist/Server/Middleware/ProjectAuthorization.js +11 -0
- package/build/dist/Server/Middleware/ProjectAuthorization.js.map +1 -1
- package/build/dist/Server/Middleware/SCIMAuthorization.js +12 -0
- package/build/dist/Server/Middleware/SCIMAuthorization.js.map +1 -1
- package/build/dist/Server/Middleware/TelemetryIngest.js +11 -0
- package/build/dist/Server/Middleware/TelemetryIngest.js.map +1 -1
- package/build/dist/Server/Services/AIBillingService.js +70 -16
- package/build/dist/Server/Services/AIBillingService.js.map +1 -1
- package/build/dist/Server/Services/EnterpriseLicenseInstanceService.js +167 -0
- package/build/dist/Server/Services/EnterpriseLicenseInstanceService.js.map +1 -1
- package/build/dist/Server/Services/EnterpriseLicenseService.js +39 -0
- package/build/dist/Server/Services/EnterpriseLicenseService.js.map +1 -1
- package/build/dist/Server/Services/Index.js +10 -0
- package/build/dist/Server/Services/Index.js.map +1 -1
- package/build/dist/Server/Services/MonitorService.js +119 -21
- package/build/dist/Server/Services/MonitorService.js.map +1 -1
- package/build/dist/Server/Services/MonitorStatusTimelineService.js +127 -8
- package/build/dist/Server/Services/MonitorStatusTimelineService.js.map +1 -1
- package/build/dist/Server/Services/MonitorTemplateService.js +162 -0
- package/build/dist/Server/Services/MonitorTemplateService.js.map +1 -1
- package/build/dist/Server/Services/NetworkAlertPolicyEngineService.js +1683 -0
- package/build/dist/Server/Services/NetworkAlertPolicyEngineService.js.map +1 -0
- package/build/dist/Server/Services/NetworkAlertPolicyService.js +732 -0
- package/build/dist/Server/Services/NetworkAlertPolicyService.js.map +1 -0
- package/build/dist/Server/Services/NetworkDeviceAutoImportRuleEngineService.js +10 -9
- package/build/dist/Server/Services/NetworkDeviceAutoImportRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/NetworkDeviceAutoImportRuleService.js +54 -11
- package/build/dist/Server/Services/NetworkDeviceAutoImportRuleService.js.map +1 -1
- package/build/dist/Server/Services/NetworkDeviceService.js +841 -70
- package/build/dist/Server/Services/NetworkDeviceService.js.map +1 -1
- package/build/dist/Server/Services/NetworkSiteService.js +1145 -107
- package/build/dist/Server/Services/NetworkSiteService.js.map +1 -1
- package/build/dist/Server/Services/NetworkSiteTypeService.js +863 -0
- package/build/dist/Server/Services/NetworkSiteTypeService.js.map +1 -1
- package/build/dist/Server/Services/NetworkSnmpCredentialProfileService.js +217 -0
- package/build/dist/Server/Services/NetworkSnmpCredentialProfileService.js.map +1 -0
- package/build/dist/Server/Services/NotificationService.js +80 -17
- package/build/dist/Server/Services/NotificationService.js.map +1 -1
- package/build/dist/Server/Services/ProjectService.js +66 -30
- package/build/dist/Server/Services/ProjectService.js.map +1 -1
- package/build/dist/Server/Services/StatusPagePrivateUserService.js +92 -2
- package/build/dist/Server/Services/StatusPagePrivateUserService.js.map +1 -1
- package/build/dist/Server/Services/UserNotificationEmailRollupBatchService.js +76 -0
- package/build/dist/Server/Services/UserNotificationEmailRollupBatchService.js.map +1 -0
- package/build/dist/Server/Services/UserNotificationEmailRollupItemService.js +77 -0
- package/build/dist/Server/Services/UserNotificationEmailRollupItemService.js.map +1 -0
- package/build/dist/Server/Services/UserNotificationEmailRollupSettingService.js +111 -0
- package/build/dist/Server/Services/UserNotificationEmailRollupSettingService.js.map +1 -0
- package/build/dist/Server/Services/UserNotificationSettingService.js +46 -20
- package/build/dist/Server/Services/UserNotificationSettingService.js.map +1 -1
- package/build/dist/Server/Services/UserService.js +90 -0
- package/build/dist/Server/Services/UserService.js.map +1 -1
- package/build/dist/Server/Types/Database/QueryHelper.js +1 -1
- package/build/dist/Server/Types/Database/QueryHelper.js.map +1 -1
- package/build/dist/Server/Utils/AI/Chat/ObservabilityChatPrompt.js +14 -3
- package/build/dist/Server/Utils/AI/Chat/ObservabilityChatPrompt.js.map +1 -1
- package/build/dist/Server/Utils/AI/SRE/Insights/Detectors/ExceptionSpikeDetector.js +10 -0
- package/build/dist/Server/Utils/AI/SRE/Insights/Detectors/ExceptionSpikeDetector.js.map +1 -1
- package/build/dist/Server/Utils/AI/SRE/Insights/Detectors/NewExceptionDetector.js +10 -0
- package/build/dist/Server/Utils/AI/SRE/Insights/Detectors/NewExceptionDetector.js.map +1 -1
- package/build/dist/Server/Utils/AI/SRE/Insights/InsightTriageRunner.js +54 -1
- package/build/dist/Server/Utils/AI/SRE/Insights/InsightTriageRunner.js.map +1 -1
- package/build/dist/Server/Utils/AI/Toolbox/AlertTools.js +18 -4
- package/build/dist/Server/Utils/AI/Toolbox/AlertTools.js.map +1 -1
- package/build/dist/Server/Utils/Billing/BillingFailureNoticeThrottle.js +59 -0
- package/build/dist/Server/Utils/Billing/BillingFailureNoticeThrottle.js.map +1 -0
- package/build/dist/Server/Utils/DataSource/HttpFetch.js +2 -1
- package/build/dist/Server/Utils/DataSource/HttpFetch.js.map +1 -1
- package/build/dist/Server/Utils/EmailRollup/EmailRollupConstants.js +91 -0
- package/build/dist/Server/Utils/EmailRollup/EmailRollupConstants.js.map +1 -0
- package/build/dist/Server/Utils/EmailRollup/EmailRollupFlushRunner.js +691 -0
- package/build/dist/Server/Utils/EmailRollup/EmailRollupFlushRunner.js.map +1 -0
- package/build/dist/Server/Utils/EmailRollup/EmailRollupRenderer.js +497 -0
- package/build/dist/Server/Utils/EmailRollup/EmailRollupRenderer.js.map +1 -0
- package/build/dist/Server/Utils/EmailRollup/EmailRollupWriter.js +257 -0
- package/build/dist/Server/Utils/EmailRollup/EmailRollupWriter.js.map +1 -0
- package/build/dist/Server/Utils/LLM/LLMService.js +64 -1
- package/build/dist/Server/Utils/LLM/LLMService.js.map +1 -1
- package/build/dist/Server/Utils/LogRedaction.js +8 -0
- package/build/dist/Server/Utils/LogRedaction.js.map +1 -1
- package/build/dist/Server/Utils/Logger.js +63 -1
- package/build/dist/Server/Utils/Logger.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/Criteria/DatabaseMonitorCriteria.js +141 -0
- package/build/dist/Server/Utils/Monitor/Criteria/DatabaseMonitorCriteria.js.map +1 -0
- package/build/dist/Server/Utils/Monitor/Criteria/EvaluateOverTime.js +8 -1
- package/build/dist/Server/Utils/Monitor/Criteria/EvaluateOverTime.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/Criteria/SnmpMonitorCriteria.js +51 -1
- package/build/dist/Server/Utils/Monitor/Criteria/SnmpMonitorCriteria.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaDataExtractor.js +7 -0
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaDataExtractor.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js +37 -0
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaObservationBuilder.js +158 -6
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaObservationBuilder.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorMetricUtil.js +33 -0
- package/build/dist/Server/Utils/Monitor/MonitorMetricUtil.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorTemplateUtil.js +32 -0
- package/build/dist/Server/Utils/Monitor/MonitorTemplateUtil.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/NetworkDeviceHydrationUtil.js +330 -21
- package/build/dist/Server/Utils/Monitor/NetworkDeviceHydrationUtil.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/NetworkDeviceMetricUtil.js +55 -10
- package/build/dist/Server/Utils/Monitor/NetworkDeviceMetricUtil.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/NetworkDeviceWalkUtil.js +178 -49
- package/build/dist/Server/Utils/Monitor/NetworkDeviceWalkUtil.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/NetworkInventoryUtil.js +119 -29
- package/build/dist/Server/Utils/Monitor/NetworkInventoryUtil.js.map +1 -1
- package/build/dist/Server/Utils/NetworkDevice/DeviceHealthAggregation.js +30 -17
- package/build/dist/Server/Utils/NetworkDevice/DeviceHealthAggregation.js.map +1 -1
- package/build/dist/Server/Utils/NetworkSite/NetworkSiteHierarchyLock.js +158 -0
- package/build/dist/Server/Utils/NetworkSite/NetworkSiteHierarchyLock.js.map +1 -0
- package/build/dist/Server/Utils/OutboundUserAgent.js +123 -0
- package/build/dist/Server/Utils/OutboundUserAgent.js.map +1 -0
- package/build/dist/Server/Utils/StartServer.js +38 -14
- package/build/dist/Server/Utils/StartServer.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/CaptureSpan.js +28 -8
- package/build/dist/Server/Utils/Telemetry/CaptureSpan.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/ErrorClassResolver.js +95 -0
- package/build/dist/Server/Utils/Telemetry/ErrorClassResolver.js.map +1 -0
- package/build/dist/Server/Utils/Telemetry/SpanUtil.js +29 -0
- package/build/dist/Server/Utils/Telemetry/SpanUtil.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry.js +162 -46
- package/build/dist/Server/Utils/Telemetry.js.map +1 -1
- package/build/dist/Types/AI/ExceptionAIClassification.js +10 -24
- package/build/dist/Types/AI/ExceptionAIClassification.js.map +1 -1
- package/build/dist/Types/Email/EmailTemplateType.js +1 -0
- package/build/dist/Types/Email/EmailTemplateType.js.map +1 -1
- package/build/dist/Types/EnterpriseLicense/EnterpriseLicenseUsageSnapshot.js +2 -0
- package/build/dist/Types/EnterpriseLicense/EnterpriseLicenseUsageSnapshot.js.map +1 -0
- package/build/dist/Types/EnterpriseLicense/EnterpriseLicenseUserCountSource.js +7 -0
- package/build/dist/Types/EnterpriseLicense/EnterpriseLicenseUserCountSource.js.map +1 -0
- package/build/dist/Types/Exception/ApiException.js +9 -0
- package/build/dist/Types/Exception/ApiException.js.map +1 -1
- package/build/dist/Types/Exception/BadDataException.js +10 -0
- package/build/dist/Types/Exception/BadDataException.js.map +1 -1
- package/build/dist/Types/Exception/BadRequestException.js +10 -0
- package/build/dist/Types/Exception/BadRequestException.js.map +1 -1
- package/build/dist/Types/Exception/Exception.js +56 -0
- package/build/dist/Types/Exception/Exception.js.map +1 -1
- package/build/dist/Types/Exception/ForbiddenException.js +9 -0
- package/build/dist/Types/Exception/ForbiddenException.js.map +1 -1
- package/build/dist/Types/Exception/NotAuthenticatedException.js +9 -0
- package/build/dist/Types/Exception/NotAuthenticatedException.js.map +1 -1
- package/build/dist/Types/Exception/NotAuthorizedException.js +9 -0
- package/build/dist/Types/Exception/NotAuthorizedException.js.map +1 -1
- package/build/dist/Types/Exception/NotFoundException.js +10 -0
- package/build/dist/Types/Exception/NotFoundException.js.map +1 -1
- package/build/dist/Types/Exception/PayloadTooLargeException.js +10 -0
- package/build/dist/Types/Exception/PayloadTooLargeException.js.map +1 -1
- package/build/dist/Types/Exception/PaymentRequiredException.js +9 -0
- package/build/dist/Types/Exception/PaymentRequiredException.js.map +1 -1
- package/build/dist/Types/Exception/ServiceUnavailableException.js +9 -0
- package/build/dist/Types/Exception/ServiceUnavailableException.js.map +1 -1
- package/build/dist/Types/Exception/SsoAuthorizationException.js +9 -0
- package/build/dist/Types/Exception/SsoAuthorizationException.js.map +1 -1
- package/build/dist/Types/Exception/TenantNotFoundException.js +10 -0
- package/build/dist/Types/Exception/TenantNotFoundException.js.map +1 -1
- package/build/dist/Types/Exception/TimeoutException.js +9 -0
- package/build/dist/Types/Exception/TimeoutException.js.map +1 -1
- package/build/dist/Types/Exception/TooManyRequestsException.js +9 -0
- package/build/dist/Types/Exception/TooManyRequestsException.js.map +1 -1
- package/build/dist/Types/Exception/UnableToReachServer.js +9 -0
- package/build/dist/Types/Exception/UnableToReachServer.js.map +1 -1
- package/build/dist/Types/Exception/WebsiteRequestException.js +9 -0
- package/build/dist/Types/Exception/WebsiteRequestException.js.map +1 -1
- package/build/dist/Types/Monitor/CriteriaFilter.js +45 -2
- package/build/dist/Types/Monitor/CriteriaFilter.js.map +1 -1
- package/build/dist/Types/Monitor/DatabaseMetricCatalog.js +594 -0
- package/build/dist/Types/Monitor/DatabaseMetricCatalog.js.map +1 -0
- package/build/dist/Types/Monitor/DatabaseMonitor/DatabaseMonitorResponse.js +21 -0
- package/build/dist/Types/Monitor/DatabaseMonitor/DatabaseMonitorResponse.js.map +1 -0
- package/build/dist/Types/Monitor/MonitorCriteriaInstance.js +70 -0
- package/build/dist/Types/Monitor/MonitorCriteriaInstance.js.map +1 -1
- package/build/dist/Types/Monitor/MonitorMetricType.js +61 -0
- package/build/dist/Types/Monitor/MonitorMetricType.js.map +1 -1
- package/build/dist/Types/Monitor/MonitorStep.js +54 -0
- package/build/dist/Types/Monitor/MonitorStep.js.map +1 -1
- package/build/dist/Types/Monitor/MonitorStepDatabaseMonitor.js +122 -0
- package/build/dist/Types/Monitor/MonitorStepDatabaseMonitor.js.map +1 -0
- package/build/dist/Types/Monitor/MonitorStepSqlMonitor.js.map +1 -1
- package/build/dist/Types/Monitor/MonitorType.js +45 -1
- package/build/dist/Types/Monitor/MonitorType.js.map +1 -1
- package/build/dist/Types/Monitor/SnmpMonitor/NetworkDeviceAlertPack.js +21 -1
- package/build/dist/Types/Monitor/SnmpMonitor/NetworkDeviceAlertPack.js.map +1 -1
- package/build/dist/Types/Monitor/SqlConnectionConfig.js +2 -0
- package/build/dist/Types/Monitor/SqlConnectionConfig.js.map +1 -0
- package/build/dist/Types/NetworkDevice/NetworkAlertPolicyScope.js +172 -0
- package/build/dist/Types/NetworkDevice/NetworkAlertPolicyScope.js.map +1 -0
- package/build/dist/Types/NetworkDevice/NetworkDeviceMonitoringMethod.js +40 -22
- package/build/dist/Types/NetworkDevice/NetworkDeviceMonitoringMethod.js.map +1 -1
- package/build/dist/Types/NetworkSite/DefaultNetworkSiteTypeHierarchy.js +26 -0
- package/build/dist/Types/NetworkSite/DefaultNetworkSiteTypeHierarchy.js.map +1 -0
- package/build/dist/Types/NotificationSetting/NotificationEmailRollupCategory.js +186 -0
- package/build/dist/Types/NotificationSetting/NotificationEmailRollupCategory.js.map +1 -0
- package/build/dist/Types/NotificationSetting/NotificationEmailRollupPolicy.js +87 -0
- package/build/dist/Types/NotificationSetting/NotificationEmailRollupPolicy.js.map +1 -0
- package/build/dist/Types/Permission.js +80 -0
- package/build/dist/Types/Permission.js.map +1 -1
- package/build/dist/Types/Telemetry/ErrorClass.js +216 -0
- package/build/dist/Types/Telemetry/ErrorClass.js.map +1 -0
- package/build/dist/Types/Telemetry/UnitOfWork.js +59 -0
- package/build/dist/Types/Telemetry/UnitOfWork.js.map +1 -0
- package/build/dist/UI/Components/CommandPalette/CommandPalette.js +2 -7
- package/build/dist/UI/Components/CommandPalette/CommandPalette.js.map +1 -1
- package/build/dist/UI/Components/EditionLabel/EditionLabel.js +3 -0
- package/build/dist/UI/Components/EditionLabel/EditionLabel.js.map +1 -1
- package/build/dist/UI/Components/Modal/Modal.js +2 -7
- package/build/dist/UI/Components/Modal/Modal.js.map +1 -1
- package/build/dist/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.js +39 -0
- package/build/dist/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.js.map +1 -1
- package/build/dist/UI/Components/ProgressBar/ProgressBar.js +12 -1
- package/build/dist/UI/Components/ProgressBar/ProgressBar.js.map +1 -1
- package/build/dist/UI/Components/RadioButtons/BasicRadioButtons.js +6 -6
- package/build/dist/UI/Components/RadioButtons/BasicRadioButtons.js.map +1 -1
- package/build/dist/UI/Components/SideMenu/SideMenu.js +67 -5
- package/build/dist/UI/Components/SideMenu/SideMenu.js.map +1 -1
- package/build/dist/UI/Components/SideMenu/SideMenuItem.js +49 -53
- package/build/dist/UI/Components/SideMenu/SideMenuItem.js.map +1 -1
- package/build/dist/UI/Components/SideMenu/SideMenuSection.js +25 -7
- package/build/dist/UI/Components/SideMenu/SideMenuSection.js.map +1 -1
- package/build/dist/UI/Components/SideOver/SideOver.js +5 -20
- package/build/dist/UI/Components/SideOver/SideOver.js.map +1 -1
- package/build/dist/UI/Utils/PageScrollLock.js +31 -3
- package/build/dist/UI/Utils/PageScrollLock.js.map +1 -1
- package/build/dist/UI/Utils/PermissionGate.js +42 -1
- package/build/dist/UI/Utils/PermissionGate.js.map +1 -1
- package/build/dist/UI/Utils/SensitiveUrlToken.js +97 -0
- package/build/dist/UI/Utils/SensitiveUrlToken.js.map +1 -0
- package/build/dist/UI/Utils/TestLLMProvider.js +4 -5
- package/build/dist/UI/Utils/TestLLMProvider.js.map +1 -1
- package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseSeats.js +15 -0
- package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseSeats.js.map +1 -1
- package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseUsage.js +111 -9
- package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseUsage.js.map +1 -1
- package/build/dist/Utils/Monitor/MonitorMetricType.js +109 -1
- package/build/dist/Utils/Monitor/MonitorMetricType.js.map +1 -1
- package/build/dist/Utils/Monitor/NetworkTopologyUtil.js +8 -3
- package/build/dist/Utils/Monitor/NetworkTopologyUtil.js.map +1 -1
- package/build/dist/Utils/NetworkDevice/DeviceHealthStateUtil.js +27 -7
- package/build/dist/Utils/NetworkDevice/DeviceHealthStateUtil.js.map +1 -1
- package/build/dist/Utils/NetworkDevice/DeviceReachabilityUtil.js +7 -5
- package/build/dist/Utils/NetworkDevice/DeviceReachabilityUtil.js.map +1 -1
- package/build/dist/Utils/NetworkDevice/NetworkAlertPolicyBootstrapUtil.js +180 -0
- package/build/dist/Utils/NetworkDevice/NetworkAlertPolicyBootstrapUtil.js.map +1 -0
- package/build/dist/Utils/NetworkDevice/SnmpCredentialUtil.js +12 -0
- package/build/dist/Utils/NetworkDevice/SnmpCredentialUtil.js.map +1 -0
- package/build/dist/Utils/NetworkDiscovery/AutoImportRuleMatcher.js +15 -5
- package/build/dist/Utils/NetworkDiscovery/AutoImportRuleMatcher.js.map +1 -1
- package/build/dist/Utils/NetworkDiscovery/DiscoveredDeviceBuilder.js +44 -15
- package/build/dist/Utils/NetworkDiscovery/DiscoveredDeviceBuilder.js.map +1 -1
- package/build/dist/Utils/NetworkDiscovery/DiscoveryImportEligibility.js +52 -23
- package/build/dist/Utils/NetworkDiscovery/DiscoveryImportEligibility.js.map +1 -1
- package/build/dist/Utils/NetworkDiscovery/PingMonitorBuilder.js +85 -13
- package/build/dist/Utils/NetworkDiscovery/PingMonitorBuilder.js.map +1 -1
- package/build/dist/Utils/NetworkSite/SiteStatusRollupUtil.js +30 -15
- package/build/dist/Utils/NetworkSite/SiteStatusRollupUtil.js.map +1 -1
- package/build/dist/Utils/NetworkSite/TypeHierarchyUtil.js +191 -0
- package/build/dist/Utils/NetworkSite/TypeHierarchyUtil.js.map +1 -0
- package/package.json +2 -2
|
@@ -0,0 +1,796 @@
|
|
|
1
|
+
import NetworkSnmpCredentialProfileService, {
|
|
2
|
+
Service as NetworkSnmpCredentialProfileServiceType,
|
|
3
|
+
} from "../../../Server/Services/NetworkSnmpCredentialProfileService";
|
|
4
|
+
import NetworkDeviceService from "../../../Server/Services/NetworkDeviceService";
|
|
5
|
+
import NetworkSiteService from "../../../Server/Services/NetworkSiteService";
|
|
6
|
+
import CreateBy from "../../../Server/Types/Database/CreateBy";
|
|
7
|
+
import DeleteBy from "../../../Server/Types/Database/DeleteBy";
|
|
8
|
+
import UpdateBy from "../../../Server/Types/Database/UpdateBy";
|
|
9
|
+
import {
|
|
10
|
+
OnCreate,
|
|
11
|
+
OnDelete,
|
|
12
|
+
OnUpdate,
|
|
13
|
+
} from "../../../Server/Types/Database/Hooks";
|
|
14
|
+
import NetworkSnmpCredentialProfile from "../../../Models/DatabaseModels/NetworkSnmpCredentialProfile";
|
|
15
|
+
import DatabaseCommonInteractionProps from "../../../Types/BaseDatabase/DatabaseCommonInteractionProps";
|
|
16
|
+
import BadDataException from "../../../Types/Exception/BadDataException";
|
|
17
|
+
import ObjectID from "../../../Types/ObjectID";
|
|
18
|
+
import PositiveNumber from "../../../Types/PositiveNumber";
|
|
19
|
+
import * as SnmpCredentialUtil from "../../../Utils/NetworkDevice/SnmpCredentialUtil";
|
|
20
|
+
import { afterEach, beforeEach, describe, expect, test } from "@jest/globals";
|
|
21
|
+
|
|
22
|
+
/*
|
|
23
|
+
* NetworkDeviceService and NetworkSiteService each import the complete
|
|
24
|
+
* monitoring/alerting service graph. This suite tests the profile service at
|
|
25
|
+
* its own boundary, so both collaborators are replaced before modules load;
|
|
26
|
+
* the individual tests still assert every count made through the boundary.
|
|
27
|
+
*/
|
|
28
|
+
jest.mock("../../../Server/Services/NetworkDeviceService", () => {
|
|
29
|
+
return {
|
|
30
|
+
__esModule: true,
|
|
31
|
+
default: {
|
|
32
|
+
countBy: jest.fn(),
|
|
33
|
+
},
|
|
34
|
+
};
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
jest.mock("../../../Server/Services/NetworkSiteService", () => {
|
|
38
|
+
return {
|
|
39
|
+
__esModule: true,
|
|
40
|
+
default: {
|
|
41
|
+
countBy: jest.fn(),
|
|
42
|
+
},
|
|
43
|
+
};
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
/*
|
|
47
|
+
* The service owns two things and this suite pins both.
|
|
48
|
+
*
|
|
49
|
+
* THE NAME is trimmed on the way in and a blank one is refused, on create
|
|
50
|
+
* and on update alike. It is unique per project and is the label every
|
|
51
|
+
* device and site listing shows for the profile it joins. Without the trim,
|
|
52
|
+
* "Branch v2c" and "Branch v2c " are two profiles that render identically;
|
|
53
|
+
* without the blank check, " " sails past the required-column check (it
|
|
54
|
+
* is a truthy string) and produces a profile with no visible name in every
|
|
55
|
+
* picker.
|
|
56
|
+
*
|
|
57
|
+
* THE DELETE GUARD refuses to delete a profile any device or site still
|
|
58
|
+
* points at. Both foreign keys are ON DELETE SET NULL, so without the guard
|
|
59
|
+
* the delete succeeds and every device using the profile - directly, or
|
|
60
|
+
* through its site - silently goes from walked to ping-only on its next
|
|
61
|
+
* poll. The guard counts devices AND sites, reads as root but scoped to the
|
|
62
|
+
* caller's tenant, and names both counts in one message.
|
|
63
|
+
*
|
|
64
|
+
* Nothing here touches a database. The hooks are called directly; the
|
|
65
|
+
* service's own reads and the two collaborators' counts are spied.
|
|
66
|
+
*/
|
|
67
|
+
|
|
68
|
+
const PROJECT_ID: ObjectID = new ObjectID(
|
|
69
|
+
"11111111-1111-4111-8111-111111111111",
|
|
70
|
+
);
|
|
71
|
+
const OTHER_PROJECT_ID: ObjectID = new ObjectID(
|
|
72
|
+
"33333333-3333-4333-8333-333333333333",
|
|
73
|
+
);
|
|
74
|
+
const PROFILE_ID: ObjectID = new ObjectID(
|
|
75
|
+
"22222222-2222-4222-8222-222222222222",
|
|
76
|
+
);
|
|
77
|
+
const SECOND_PROFILE_ID: ObjectID = new ObjectID(
|
|
78
|
+
"44444444-4444-4444-8444-444444444444",
|
|
79
|
+
);
|
|
80
|
+
const USER_ID: ObjectID = new ObjectID("55555555-5555-4555-8555-555555555555");
|
|
81
|
+
|
|
82
|
+
type ServiceInternals = {
|
|
83
|
+
onBeforeCreate: (
|
|
84
|
+
createBy: CreateBy<NetworkSnmpCredentialProfile>,
|
|
85
|
+
) => Promise<OnCreate<NetworkSnmpCredentialProfile>>;
|
|
86
|
+
onBeforeUpdate: (
|
|
87
|
+
updateBy: UpdateBy<NetworkSnmpCredentialProfile>,
|
|
88
|
+
) => Promise<OnUpdate<NetworkSnmpCredentialProfile>>;
|
|
89
|
+
onBeforeDelete: (
|
|
90
|
+
deleteBy: DeleteBy<NetworkSnmpCredentialProfile>,
|
|
91
|
+
) => Promise<OnDelete<NetworkSnmpCredentialProfile>>;
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
function buildService(): {
|
|
95
|
+
service: NetworkSnmpCredentialProfileServiceType;
|
|
96
|
+
internals: ServiceInternals;
|
|
97
|
+
} {
|
|
98
|
+
const service: NetworkSnmpCredentialProfileServiceType =
|
|
99
|
+
new NetworkSnmpCredentialProfileServiceType();
|
|
100
|
+
|
|
101
|
+
const internals: ServiceInternals = service as unknown as ServiceInternals;
|
|
102
|
+
|
|
103
|
+
return { service, internals };
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function createBy(
|
|
107
|
+
name: string | undefined,
|
|
108
|
+
extra?: Partial<NetworkSnmpCredentialProfile>,
|
|
109
|
+
): CreateBy<NetworkSnmpCredentialProfile> {
|
|
110
|
+
const profile: NetworkSnmpCredentialProfile =
|
|
111
|
+
new NetworkSnmpCredentialProfile();
|
|
112
|
+
profile.projectId = PROJECT_ID;
|
|
113
|
+
|
|
114
|
+
if (name !== undefined) {
|
|
115
|
+
profile.name = name;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
Object.assign(profile, extra || {});
|
|
119
|
+
|
|
120
|
+
return {
|
|
121
|
+
data: profile,
|
|
122
|
+
props: { isRoot: true },
|
|
123
|
+
} as CreateBy<NetworkSnmpCredentialProfile>;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
function updateBy(
|
|
127
|
+
data: Partial<Record<keyof NetworkSnmpCredentialProfile, unknown>>,
|
|
128
|
+
): UpdateBy<NetworkSnmpCredentialProfile> {
|
|
129
|
+
return {
|
|
130
|
+
query: { _id: PROFILE_ID.toString() },
|
|
131
|
+
data: data,
|
|
132
|
+
props: { isRoot: true },
|
|
133
|
+
limit: new PositiveNumber(1),
|
|
134
|
+
skip: new PositiveNumber(0),
|
|
135
|
+
} as unknown as UpdateBy<NetworkSnmpCredentialProfile>;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function deleteBy(
|
|
139
|
+
props: DatabaseCommonInteractionProps,
|
|
140
|
+
): DeleteBy<NetworkSnmpCredentialProfile> {
|
|
141
|
+
return {
|
|
142
|
+
query: { _id: PROFILE_ID.toString() },
|
|
143
|
+
props: props,
|
|
144
|
+
limit: new PositiveNumber(1),
|
|
145
|
+
skip: new PositiveNumber(0),
|
|
146
|
+
} as unknown as DeleteBy<NetworkSnmpCredentialProfile>;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/*
|
|
150
|
+
* A row as the delete guard's own findBy returns it: id, name and projectId
|
|
151
|
+
* selected, nothing else.
|
|
152
|
+
*/
|
|
153
|
+
function profileRow(data: {
|
|
154
|
+
id?: ObjectID | undefined;
|
|
155
|
+
projectId?: ObjectID | undefined;
|
|
156
|
+
name?: string | undefined;
|
|
157
|
+
}): NetworkSnmpCredentialProfile {
|
|
158
|
+
const profile: NetworkSnmpCredentialProfile =
|
|
159
|
+
new NetworkSnmpCredentialProfile();
|
|
160
|
+
|
|
161
|
+
if (data.id) {
|
|
162
|
+
profile.id = data.id;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
if (data.projectId) {
|
|
166
|
+
profile.projectId = data.projectId;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
profile.name = data.name ?? "Branch v2c";
|
|
170
|
+
|
|
171
|
+
return profile;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/*
|
|
175
|
+
* A caller who is NOT root: a project member deleting through the API. This
|
|
176
|
+
* is the case the tenant scoping exists for.
|
|
177
|
+
*/
|
|
178
|
+
const MEMBER_PROPS: DatabaseCommonInteractionProps = {
|
|
179
|
+
isRoot: false,
|
|
180
|
+
tenantId: PROJECT_ID,
|
|
181
|
+
userId: USER_ID,
|
|
182
|
+
};
|
|
183
|
+
|
|
184
|
+
const ROOT_PROPS: DatabaseCommonInteractionProps = {
|
|
185
|
+
isRoot: true,
|
|
186
|
+
};
|
|
187
|
+
|
|
188
|
+
/*
|
|
189
|
+
* Every read the service inherits from DatabaseService, spied so a test can
|
|
190
|
+
* assert the create and update hooks made none of them. A hook that reads
|
|
191
|
+
* would need a database, and - more to the point - a hook that reads before
|
|
192
|
+
* the permission check runs is how a tenant leak starts (see the delete
|
|
193
|
+
* guard, which reads and therefore has to re-scope by hand).
|
|
194
|
+
*/
|
|
195
|
+
function spyOnReads(
|
|
196
|
+
service: NetworkSnmpCredentialProfileServiceType,
|
|
197
|
+
): Array<jest.SpyInstance> {
|
|
198
|
+
return [
|
|
199
|
+
jest
|
|
200
|
+
.spyOn(service, "findBy")
|
|
201
|
+
.mockRejectedValue(new Error("findBy must not be called")),
|
|
202
|
+
jest
|
|
203
|
+
.spyOn(service, "findOneBy")
|
|
204
|
+
.mockRejectedValue(new Error("findOneBy must not be called")),
|
|
205
|
+
jest
|
|
206
|
+
.spyOn(service, "countBy")
|
|
207
|
+
.mockRejectedValue(new Error("countBy must not be called")),
|
|
208
|
+
];
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
function deviceCountBy(): jest.Mock {
|
|
212
|
+
return NetworkDeviceService.countBy as unknown as jest.Mock;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
function siteCountBy(): jest.Mock {
|
|
216
|
+
return NetworkSiteService.countBy as unknown as jest.Mock;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
function stubCounts(data: { devices: number; sites: number }): void {
|
|
220
|
+
deviceCountBy().mockResolvedValue(new PositiveNumber(data.devices));
|
|
221
|
+
siteCountBy().mockResolvedValue(new PositiveNumber(data.sites));
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
beforeEach(() => {
|
|
225
|
+
deviceCountBy().mockReset();
|
|
226
|
+
siteCountBy().mockReset();
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
afterEach(() => {
|
|
230
|
+
jest.restoreAllMocks();
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
describe("onBeforeCreate - the name", () => {
|
|
234
|
+
test("is trimmed", async () => {
|
|
235
|
+
const { internals } = buildService();
|
|
236
|
+
|
|
237
|
+
const result: OnCreate<NetworkSnmpCredentialProfile> =
|
|
238
|
+
await internals.onBeforeCreate(createBy(" Branch offices v2c "));
|
|
239
|
+
|
|
240
|
+
expect(result.createBy.data.name).toBe("Branch offices v2c");
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
test("is returned unchanged when it has nothing to trim", async () => {
|
|
244
|
+
const { internals } = buildService();
|
|
245
|
+
|
|
246
|
+
const result: OnCreate<NetworkSnmpCredentialProfile> =
|
|
247
|
+
await internals.onBeforeCreate(createBy("Core switches v3"));
|
|
248
|
+
|
|
249
|
+
expect(result.createBy.data.name).toBe("Core switches v3");
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
/*
|
|
253
|
+
* Interior whitespace is part of the name. "Branch offices" with two
|
|
254
|
+
* spaces is odd but is what the operator typed; only the edges are
|
|
255
|
+
* anybody's business.
|
|
256
|
+
*/
|
|
257
|
+
test("keeps interior whitespace", async () => {
|
|
258
|
+
const { internals } = buildService();
|
|
259
|
+
|
|
260
|
+
const result: OnCreate<NetworkSnmpCredentialProfile> =
|
|
261
|
+
await internals.onBeforeCreate(createBy(" Branch offices "));
|
|
262
|
+
|
|
263
|
+
expect(result.createBy.data.name).toBe("Branch offices");
|
|
264
|
+
});
|
|
265
|
+
|
|
266
|
+
test.each(["", " ", " ", "\t", "\n", " \t\n "])(
|
|
267
|
+
"a blank name %p is refused",
|
|
268
|
+
async (name: string) => {
|
|
269
|
+
const { internals } = buildService();
|
|
270
|
+
|
|
271
|
+
await expect(internals.onBeforeCreate(createBy(name))).rejects.toThrow(
|
|
272
|
+
BadDataException,
|
|
273
|
+
);
|
|
274
|
+
},
|
|
275
|
+
);
|
|
276
|
+
|
|
277
|
+
/*
|
|
278
|
+
* The required-column check in DatabaseService also refuses an undefined
|
|
279
|
+
* name, but it runs after this hook, and the hook must not crash on the
|
|
280
|
+
* way there with a TypeError from calling trim() on undefined.
|
|
281
|
+
*/
|
|
282
|
+
test("a missing name is refused with a BadDataException, not a TypeError", async () => {
|
|
283
|
+
const { internals } = buildService();
|
|
284
|
+
|
|
285
|
+
await expect(internals.onBeforeCreate(createBy(undefined))).rejects.toThrow(
|
|
286
|
+
BadDataException,
|
|
287
|
+
);
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
test("the refusal names the profile so the form can show it", async () => {
|
|
291
|
+
const { internals } = buildService();
|
|
292
|
+
|
|
293
|
+
await expect(internals.onBeforeCreate(createBy(" "))).rejects.toThrow(
|
|
294
|
+
/SNMP Credential Profile name/,
|
|
295
|
+
);
|
|
296
|
+
});
|
|
297
|
+
});
|
|
298
|
+
|
|
299
|
+
describe("onBeforeCreate - everything that is not the name", () => {
|
|
300
|
+
/*
|
|
301
|
+
* The secrets are passed through byte for byte. A community string or a
|
|
302
|
+
* passphrase may legitimately begin or end with whitespace, and a service
|
|
303
|
+
* that "helpfully" trimmed one would produce a profile that never
|
|
304
|
+
* authenticates, with nothing anywhere to say why. (Encryption at rest
|
|
305
|
+
* happens in DatabaseService AFTER this hook, on the value as returned
|
|
306
|
+
* here - so what this hook returns is what gets encrypted.)
|
|
307
|
+
*/
|
|
308
|
+
test("the credentials are not trimmed or otherwise touched", async () => {
|
|
309
|
+
const { internals } = buildService();
|
|
310
|
+
|
|
311
|
+
const result: OnCreate<NetworkSnmpCredentialProfile> =
|
|
312
|
+
await internals.onBeforeCreate(
|
|
313
|
+
createBy("Branch", {
|
|
314
|
+
snmpVersion: "V3",
|
|
315
|
+
snmpCommunityString: " public ",
|
|
316
|
+
snmpPort: 1161,
|
|
317
|
+
snmpV3SecurityLevel: "authPriv",
|
|
318
|
+
snmpV3Username: " monitoring ",
|
|
319
|
+
snmpV3AuthProtocol: "SHA",
|
|
320
|
+
snmpV3AuthKey: " auth key with spaces ",
|
|
321
|
+
snmpV3PrivProtocol: "AES",
|
|
322
|
+
snmpV3PrivKey: " priv key with spaces ",
|
|
323
|
+
}),
|
|
324
|
+
);
|
|
325
|
+
|
|
326
|
+
expect(result.createBy.data.snmpVersion).toBe("V3");
|
|
327
|
+
expect(result.createBy.data.snmpCommunityString).toBe(" public ");
|
|
328
|
+
expect(result.createBy.data.snmpPort).toBe(1161);
|
|
329
|
+
expect(result.createBy.data.snmpV3SecurityLevel).toBe("authPriv");
|
|
330
|
+
expect(result.createBy.data.snmpV3Username).toBe(" monitoring ");
|
|
331
|
+
expect(result.createBy.data.snmpV3AuthProtocol).toBe("SHA");
|
|
332
|
+
expect(result.createBy.data.snmpV3AuthKey).toBe(" auth key with spaces ");
|
|
333
|
+
expect(result.createBy.data.snmpV3PrivProtocol).toBe("AES");
|
|
334
|
+
expect(result.createBy.data.snmpV3PrivKey).toBe(" priv key with spaces ");
|
|
335
|
+
});
|
|
336
|
+
|
|
337
|
+
/*
|
|
338
|
+
* A profile with no credentials at all is allowed. It is a name an
|
|
339
|
+
* operator can attach to devices now and fill in later, and the poller's
|
|
340
|
+
* predicate (hasUsableCredentials) is what decides it is not yet usable -
|
|
341
|
+
* refusing it here would just move the empty state to the form.
|
|
342
|
+
*/
|
|
343
|
+
test("a profile with no credentials is accepted", async () => {
|
|
344
|
+
const { internals } = buildService();
|
|
345
|
+
|
|
346
|
+
const result: OnCreate<NetworkSnmpCredentialProfile> =
|
|
347
|
+
await internals.onBeforeCreate(createBy("Not yet configured"));
|
|
348
|
+
|
|
349
|
+
expect(result.createBy.data.name).toBe("Not yet configured");
|
|
350
|
+
});
|
|
351
|
+
|
|
352
|
+
test("it carries nothing forward and makes no database read", async () => {
|
|
353
|
+
const { service, internals } = buildService();
|
|
354
|
+
const reads: Array<jest.SpyInstance> = spyOnReads(service);
|
|
355
|
+
|
|
356
|
+
const result: OnCreate<NetworkSnmpCredentialProfile> =
|
|
357
|
+
await internals.onBeforeCreate(createBy("Branch"));
|
|
358
|
+
|
|
359
|
+
expect(result.carryForward).toBeNull();
|
|
360
|
+
|
|
361
|
+
for (const read of reads) {
|
|
362
|
+
expect(read).not.toHaveBeenCalled();
|
|
363
|
+
}
|
|
364
|
+
});
|
|
365
|
+
});
|
|
366
|
+
|
|
367
|
+
describe("onBeforeUpdate - the name", () => {
|
|
368
|
+
test("is trimmed when the update carries one", async () => {
|
|
369
|
+
const { internals } = buildService();
|
|
370
|
+
|
|
371
|
+
const result: OnUpdate<NetworkSnmpCredentialProfile> =
|
|
372
|
+
await internals.onBeforeUpdate(updateBy({ name: " Renamed " }));
|
|
373
|
+
|
|
374
|
+
expect(result.updateBy.data.name).toBe("Renamed");
|
|
375
|
+
});
|
|
376
|
+
|
|
377
|
+
test.each(["", " ", "\t\n"])(
|
|
378
|
+
"a blank name %p is refused",
|
|
379
|
+
async (name: string) => {
|
|
380
|
+
const { internals } = buildService();
|
|
381
|
+
|
|
382
|
+
await expect(
|
|
383
|
+
internals.onBeforeUpdate(updateBy({ name: name })),
|
|
384
|
+
).rejects.toThrow(BadDataException);
|
|
385
|
+
},
|
|
386
|
+
);
|
|
387
|
+
|
|
388
|
+
/*
|
|
389
|
+
* null is what a form sends when a field is cleared, and PartialEntity
|
|
390
|
+
* allows it on every column. On the name it means "no name", which the
|
|
391
|
+
* NOT NULL constraint would reject anyway - but as a database error, not
|
|
392
|
+
* a form error. Refuse it here, where the message reaches the operator.
|
|
393
|
+
*/
|
|
394
|
+
test("a null name is refused as blank rather than left for the database", async () => {
|
|
395
|
+
const { internals } = buildService();
|
|
396
|
+
|
|
397
|
+
await expect(
|
|
398
|
+
internals.onBeforeUpdate(updateBy({ name: null })),
|
|
399
|
+
).rejects.toThrow(BadDataException);
|
|
400
|
+
});
|
|
401
|
+
|
|
402
|
+
/*
|
|
403
|
+
* PartialEntity also allows a `() => string` on any column, which is the
|
|
404
|
+
* raw-SQL-expression escape hatch. A label built from a SQL expression is
|
|
405
|
+
* not a thing, and letting one through would bypass both the trim and the
|
|
406
|
+
* blank check.
|
|
407
|
+
*/
|
|
408
|
+
test("a raw SQL expression is not accepted as a name", async () => {
|
|
409
|
+
const { internals } = buildService();
|
|
410
|
+
|
|
411
|
+
await expect(
|
|
412
|
+
internals.onBeforeUpdate(
|
|
413
|
+
updateBy({
|
|
414
|
+
name: (): string => {
|
|
415
|
+
return "UPPER(name)";
|
|
416
|
+
},
|
|
417
|
+
}),
|
|
418
|
+
),
|
|
419
|
+
).rejects.toThrow(BadDataException);
|
|
420
|
+
});
|
|
421
|
+
});
|
|
422
|
+
|
|
423
|
+
describe("onBeforeUpdate - updates that do not mention the name", () => {
|
|
424
|
+
/*
|
|
425
|
+
* THE CASE THAT MATTERS MOST for update. Rotating a community string is
|
|
426
|
+
* the whole reason profiles exist, and it is an update whose data has no
|
|
427
|
+
* `name` key at all. The hook must recognise "not mentioned" (undefined)
|
|
428
|
+
* as distinct from "blank" and leave the row's name alone - a truthiness
|
|
429
|
+
* check here would refuse every credential rotation as a blank rename.
|
|
430
|
+
*/
|
|
431
|
+
test("a credential rotation passes through with the name untouched", async () => {
|
|
432
|
+
const { internals } = buildService();
|
|
433
|
+
|
|
434
|
+
const result: OnUpdate<NetworkSnmpCredentialProfile> =
|
|
435
|
+
await internals.onBeforeUpdate(
|
|
436
|
+
updateBy({ snmpCommunityString: "rotated-2026" }),
|
|
437
|
+
);
|
|
438
|
+
|
|
439
|
+
expect(result.updateBy.data.snmpCommunityString).toBe("rotated-2026");
|
|
440
|
+
expect("name" in result.updateBy.data).toBe(false);
|
|
441
|
+
});
|
|
442
|
+
|
|
443
|
+
test("a description-only edit passes through", async () => {
|
|
444
|
+
const { internals } = buildService();
|
|
445
|
+
|
|
446
|
+
const result: OnUpdate<NetworkSnmpCredentialProfile> =
|
|
447
|
+
await internals.onBeforeUpdate(
|
|
448
|
+
updateBy({ description: "Used by the branch switches." }),
|
|
449
|
+
);
|
|
450
|
+
|
|
451
|
+
expect(result.updateBy.data.description).toBe(
|
|
452
|
+
"Used by the branch switches.",
|
|
453
|
+
);
|
|
454
|
+
expect(result.updateBy.data.name).toBeUndefined();
|
|
455
|
+
});
|
|
456
|
+
|
|
457
|
+
test("the credentials are not trimmed on update either", async () => {
|
|
458
|
+
const { internals } = buildService();
|
|
459
|
+
|
|
460
|
+
const result: OnUpdate<NetworkSnmpCredentialProfile> =
|
|
461
|
+
await internals.onBeforeUpdate(
|
|
462
|
+
updateBy({
|
|
463
|
+
name: " Renamed ",
|
|
464
|
+
snmpV3AuthKey: " key with spaces ",
|
|
465
|
+
snmpV3PrivKey: " other key ",
|
|
466
|
+
}),
|
|
467
|
+
);
|
|
468
|
+
|
|
469
|
+
expect(result.updateBy.data.name).toBe("Renamed");
|
|
470
|
+
expect(result.updateBy.data.snmpV3AuthKey).toBe(" key with spaces ");
|
|
471
|
+
expect(result.updateBy.data.snmpV3PrivKey).toBe(" other key ");
|
|
472
|
+
});
|
|
473
|
+
|
|
474
|
+
test("it carries nothing forward and makes no database read", async () => {
|
|
475
|
+
const { service, internals } = buildService();
|
|
476
|
+
const reads: Array<jest.SpyInstance> = spyOnReads(service);
|
|
477
|
+
|
|
478
|
+
const result: OnUpdate<NetworkSnmpCredentialProfile> =
|
|
479
|
+
await internals.onBeforeUpdate(updateBy({ name: "Renamed" }));
|
|
480
|
+
|
|
481
|
+
expect(result.carryForward).toBeNull();
|
|
482
|
+
|
|
483
|
+
for (const read of reads) {
|
|
484
|
+
expect(read).not.toHaveBeenCalled();
|
|
485
|
+
}
|
|
486
|
+
});
|
|
487
|
+
});
|
|
488
|
+
|
|
489
|
+
describe("onBeforeDelete - a profile still in use cannot be deleted", () => {
|
|
490
|
+
const EXPECTED_MESSAGE: (devices: number, sites: number) => string = (
|
|
491
|
+
devices: number,
|
|
492
|
+
sites: number,
|
|
493
|
+
): string => {
|
|
494
|
+
return `This SNMP Credential Profile is used by ${devices} devices and ${sites} sites. Remove it from them first, or point them at another profile.`;
|
|
495
|
+
};
|
|
496
|
+
|
|
497
|
+
test("refused when devices point at it", async () => {
|
|
498
|
+
const { service, internals } = buildService();
|
|
499
|
+
jest
|
|
500
|
+
.spyOn(service, "findBy")
|
|
501
|
+
.mockResolvedValue([
|
|
502
|
+
profileRow({ id: PROFILE_ID, projectId: PROJECT_ID }),
|
|
503
|
+
]);
|
|
504
|
+
stubCounts({ devices: 3, sites: 0 });
|
|
505
|
+
|
|
506
|
+
await expect(
|
|
507
|
+
internals.onBeforeDelete(deleteBy(MEMBER_PROPS)),
|
|
508
|
+
).rejects.toThrow(BadDataException);
|
|
509
|
+
await expect(
|
|
510
|
+
internals.onBeforeDelete(deleteBy(MEMBER_PROPS)),
|
|
511
|
+
).rejects.toThrow(EXPECTED_MESSAGE(3, 0));
|
|
512
|
+
});
|
|
513
|
+
|
|
514
|
+
/*
|
|
515
|
+
* THE CASE THE SITE COUNT EXISTS FOR. A site can hold the only reference
|
|
516
|
+
* to a profile while no device points at it directly - "set it once per
|
|
517
|
+
* site" means most devices never will - and the device count alone says
|
|
518
|
+
* this delete is safe when it is not.
|
|
519
|
+
*/
|
|
520
|
+
test("refused when only sites point at it", async () => {
|
|
521
|
+
const { service, internals } = buildService();
|
|
522
|
+
jest
|
|
523
|
+
.spyOn(service, "findBy")
|
|
524
|
+
.mockResolvedValue([
|
|
525
|
+
profileRow({ id: PROFILE_ID, projectId: PROJECT_ID }),
|
|
526
|
+
]);
|
|
527
|
+
stubCounts({ devices: 0, sites: 2 });
|
|
528
|
+
|
|
529
|
+
await expect(
|
|
530
|
+
internals.onBeforeDelete(deleteBy(MEMBER_PROPS)),
|
|
531
|
+
).rejects.toThrow(EXPECTED_MESSAGE(0, 2));
|
|
532
|
+
});
|
|
533
|
+
|
|
534
|
+
/*
|
|
535
|
+
* Both counts in one message, not the first non-zero one: the operator
|
|
536
|
+
* should learn everything that has to move before the delete can go
|
|
537
|
+
* through, rather than clearing the devices and then being told about
|
|
538
|
+
* the sites.
|
|
539
|
+
*/
|
|
540
|
+
test("refused naming both counts when both point at it", async () => {
|
|
541
|
+
const { service, internals } = buildService();
|
|
542
|
+
jest
|
|
543
|
+
.spyOn(service, "findBy")
|
|
544
|
+
.mockResolvedValue([
|
|
545
|
+
profileRow({ id: PROFILE_ID, projectId: PROJECT_ID }),
|
|
546
|
+
]);
|
|
547
|
+
stubCounts({ devices: 7, sites: 1 });
|
|
548
|
+
|
|
549
|
+
await expect(
|
|
550
|
+
internals.onBeforeDelete(deleteBy(MEMBER_PROPS)),
|
|
551
|
+
).rejects.toThrow(EXPECTED_MESSAGE(7, 1));
|
|
552
|
+
});
|
|
553
|
+
|
|
554
|
+
test("allowed when neither devices nor sites point at it", async () => {
|
|
555
|
+
const { service, internals } = buildService();
|
|
556
|
+
jest
|
|
557
|
+
.spyOn(service, "findBy")
|
|
558
|
+
.mockResolvedValue([
|
|
559
|
+
profileRow({ id: PROFILE_ID, projectId: PROJECT_ID }),
|
|
560
|
+
]);
|
|
561
|
+
stubCounts({ devices: 0, sites: 0 });
|
|
562
|
+
|
|
563
|
+
const input: DeleteBy<NetworkSnmpCredentialProfile> =
|
|
564
|
+
deleteBy(MEMBER_PROPS);
|
|
565
|
+
const result: OnDelete<NetworkSnmpCredentialProfile> =
|
|
566
|
+
await internals.onBeforeDelete(input);
|
|
567
|
+
|
|
568
|
+
expect(result.deleteBy).toBe(input);
|
|
569
|
+
expect(result.carryForward).toBeNull();
|
|
570
|
+
expect(deviceCountBy()).toHaveBeenCalledTimes(1);
|
|
571
|
+
expect(siteCountBy()).toHaveBeenCalledTimes(1);
|
|
572
|
+
});
|
|
573
|
+
|
|
574
|
+
test("a delete that matches no profile is allowed without counting anything", async () => {
|
|
575
|
+
const { service, internals } = buildService();
|
|
576
|
+
jest.spyOn(service, "findBy").mockResolvedValue([]);
|
|
577
|
+
|
|
578
|
+
await internals.onBeforeDelete(deleteBy(MEMBER_PROPS));
|
|
579
|
+
|
|
580
|
+
expect(deviceCountBy()).not.toHaveBeenCalled();
|
|
581
|
+
expect(siteCountBy()).not.toHaveBeenCalled();
|
|
582
|
+
});
|
|
583
|
+
|
|
584
|
+
/*
|
|
585
|
+
* A row the guard's own select could not fill in (no id, or no project)
|
|
586
|
+
* cannot be counted against and must not crash the hook. The database's
|
|
587
|
+
* own constraints make such a row impossible in practice; this pins that
|
|
588
|
+
* the loop is defensive rather than trusting.
|
|
589
|
+
*/
|
|
590
|
+
test("a row without an id or a project is skipped rather than counted", async () => {
|
|
591
|
+
const { service, internals } = buildService();
|
|
592
|
+
jest
|
|
593
|
+
.spyOn(service, "findBy")
|
|
594
|
+
.mockResolvedValue([
|
|
595
|
+
profileRow({ id: undefined, projectId: PROJECT_ID }),
|
|
596
|
+
profileRow({ id: PROFILE_ID, projectId: undefined }),
|
|
597
|
+
]);
|
|
598
|
+
stubCounts({ devices: 99, sites: 99 });
|
|
599
|
+
|
|
600
|
+
await internals.onBeforeDelete(deleteBy(MEMBER_PROPS));
|
|
601
|
+
|
|
602
|
+
expect(deviceCountBy()).not.toHaveBeenCalled();
|
|
603
|
+
expect(siteCountBy()).not.toHaveBeenCalled();
|
|
604
|
+
});
|
|
605
|
+
|
|
606
|
+
test("with several profiles, the first one in use stops the whole delete", async () => {
|
|
607
|
+
const { service, internals } = buildService();
|
|
608
|
+
jest.spyOn(service, "findBy").mockResolvedValue([
|
|
609
|
+
profileRow({ id: PROFILE_ID, projectId: PROJECT_ID, name: "Unused" }),
|
|
610
|
+
profileRow({
|
|
611
|
+
id: SECOND_PROFILE_ID,
|
|
612
|
+
projectId: PROJECT_ID,
|
|
613
|
+
name: "In use",
|
|
614
|
+
}),
|
|
615
|
+
]);
|
|
616
|
+
deviceCountBy()
|
|
617
|
+
.mockResolvedValueOnce(new PositiveNumber(0))
|
|
618
|
+
.mockResolvedValueOnce(new PositiveNumber(4));
|
|
619
|
+
siteCountBy()
|
|
620
|
+
.mockResolvedValueOnce(new PositiveNumber(0))
|
|
621
|
+
.mockResolvedValueOnce(new PositiveNumber(0));
|
|
622
|
+
|
|
623
|
+
await expect(
|
|
624
|
+
internals.onBeforeDelete(deleteBy(MEMBER_PROPS)),
|
|
625
|
+
).rejects.toThrow(EXPECTED_MESSAGE(4, 0));
|
|
626
|
+
});
|
|
627
|
+
});
|
|
628
|
+
|
|
629
|
+
describe("onBeforeDelete - the counts come from tenant-scoped queries", () => {
|
|
630
|
+
/*
|
|
631
|
+
* The hook runs BEFORE DatabaseService applies the caller's tenant to the
|
|
632
|
+
* delete query, and it reads as root so that it sees every profile the
|
|
633
|
+
* delete would touch. Root plus the caller's raw query would hand back
|
|
634
|
+
* other tenants' profiles - and then count other tenants' devices against
|
|
635
|
+
* them. The caller's tenant is re-applied by hand.
|
|
636
|
+
*/
|
|
637
|
+
test("the profiles are read as root, with the caller's tenant re-applied to the query", async () => {
|
|
638
|
+
const { service, internals } = buildService();
|
|
639
|
+
const findBySpy: jest.SpyInstance = jest
|
|
640
|
+
.spyOn(service, "findBy")
|
|
641
|
+
.mockResolvedValue([]);
|
|
642
|
+
|
|
643
|
+
await internals.onBeforeDelete(deleteBy(MEMBER_PROPS));
|
|
644
|
+
|
|
645
|
+
expect(findBySpy).toHaveBeenCalledTimes(1);
|
|
646
|
+
|
|
647
|
+
const call: {
|
|
648
|
+
query: Record<string, unknown>;
|
|
649
|
+
props: { isRoot?: boolean };
|
|
650
|
+
} = findBySpy.mock.calls[0]![0] as {
|
|
651
|
+
query: Record<string, unknown>;
|
|
652
|
+
props: { isRoot?: boolean };
|
|
653
|
+
};
|
|
654
|
+
|
|
655
|
+
expect(call.props.isRoot).toBe(true);
|
|
656
|
+
expect(call.query["_id"]).toBe(PROFILE_ID.toString());
|
|
657
|
+
expect(call.query["projectId"]).toBe(PROJECT_ID);
|
|
658
|
+
});
|
|
659
|
+
|
|
660
|
+
test("a root caller's query is passed through untouched", async () => {
|
|
661
|
+
const { service, internals } = buildService();
|
|
662
|
+
const findBySpy: jest.SpyInstance = jest
|
|
663
|
+
.spyOn(service, "findBy")
|
|
664
|
+
.mockResolvedValue([]);
|
|
665
|
+
|
|
666
|
+
await internals.onBeforeDelete(deleteBy(ROOT_PROPS));
|
|
667
|
+
|
|
668
|
+
const call: { query: Record<string, unknown> } = findBySpy.mock
|
|
669
|
+
.calls[0]![0] as { query: Record<string, unknown> };
|
|
670
|
+
|
|
671
|
+
expect(call.query).toEqual({ _id: PROFILE_ID.toString() });
|
|
672
|
+
});
|
|
673
|
+
|
|
674
|
+
/*
|
|
675
|
+
* The device and site counts are keyed on the PROFILE'S project, not the
|
|
676
|
+
* caller's, and on the profile's id: "how many rows in this project point
|
|
677
|
+
* at this row". Root, because the member deleting a profile is not
|
|
678
|
+
* necessarily allowed to read every device, and a partial count would let
|
|
679
|
+
* the delete through with devices still attached.
|
|
680
|
+
*/
|
|
681
|
+
test("devices and sites are counted as root, in the profile's project, by profile id", async () => {
|
|
682
|
+
const { service, internals } = buildService();
|
|
683
|
+
jest
|
|
684
|
+
.spyOn(service, "findBy")
|
|
685
|
+
.mockResolvedValue([
|
|
686
|
+
profileRow({ id: PROFILE_ID, projectId: OTHER_PROJECT_ID }),
|
|
687
|
+
]);
|
|
688
|
+
stubCounts({ devices: 0, sites: 0 });
|
|
689
|
+
|
|
690
|
+
await internals.onBeforeDelete(deleteBy(MEMBER_PROPS));
|
|
691
|
+
|
|
692
|
+
for (const countBy of [deviceCountBy(), siteCountBy()]) {
|
|
693
|
+
expect(countBy).toHaveBeenCalledTimes(1);
|
|
694
|
+
|
|
695
|
+
const call: {
|
|
696
|
+
query: Record<string, unknown>;
|
|
697
|
+
props: { isRoot?: boolean };
|
|
698
|
+
} = countBy.mock.calls[0]![0] as {
|
|
699
|
+
query: Record<string, unknown>;
|
|
700
|
+
props: { isRoot?: boolean };
|
|
701
|
+
};
|
|
702
|
+
|
|
703
|
+
expect(call.props.isRoot).toBe(true);
|
|
704
|
+
/*
|
|
705
|
+
* Compared by value: BaseModel.id is a getter that mints a fresh
|
|
706
|
+
* ObjectID from _id on every read, so the instance the service passed
|
|
707
|
+
* is never the one this test holds.
|
|
708
|
+
*/
|
|
709
|
+
expect(String(call.query["snmpCredentialProfileId"])).toBe(
|
|
710
|
+
PROFILE_ID.toString(),
|
|
711
|
+
);
|
|
712
|
+
expect(String(call.query["projectId"])).toBe(OTHER_PROJECT_ID.toString());
|
|
713
|
+
expect(Object.keys(call.query).sort()).toEqual([
|
|
714
|
+
"projectId",
|
|
715
|
+
"snmpCredentialProfileId",
|
|
716
|
+
]);
|
|
717
|
+
}
|
|
718
|
+
});
|
|
719
|
+
|
|
720
|
+
test("each profile being deleted is counted separately", async () => {
|
|
721
|
+
const { service, internals } = buildService();
|
|
722
|
+
jest
|
|
723
|
+
.spyOn(service, "findBy")
|
|
724
|
+
.mockResolvedValue([
|
|
725
|
+
profileRow({ id: PROFILE_ID, projectId: PROJECT_ID }),
|
|
726
|
+
profileRow({ id: SECOND_PROFILE_ID, projectId: PROJECT_ID }),
|
|
727
|
+
]);
|
|
728
|
+
stubCounts({ devices: 0, sites: 0 });
|
|
729
|
+
|
|
730
|
+
await internals.onBeforeDelete(deleteBy(MEMBER_PROPS));
|
|
731
|
+
|
|
732
|
+
const countedProfileIds: (countBy: jest.Mock) => Array<string> = (
|
|
733
|
+
countBy: jest.Mock,
|
|
734
|
+
): Array<string> => {
|
|
735
|
+
return countBy.mock.calls.map((call: Array<unknown>): string => {
|
|
736
|
+
return (
|
|
737
|
+
(call[0] as { query: { snmpCredentialProfileId: ObjectID } }).query
|
|
738
|
+
.snmpCredentialProfileId as ObjectID
|
|
739
|
+
).toString();
|
|
740
|
+
});
|
|
741
|
+
};
|
|
742
|
+
|
|
743
|
+
expect(countedProfileIds(deviceCountBy())).toEqual([
|
|
744
|
+
PROFILE_ID.toString(),
|
|
745
|
+
SECOND_PROFILE_ID.toString(),
|
|
746
|
+
]);
|
|
747
|
+
expect(countedProfileIds(siteCountBy())).toEqual([
|
|
748
|
+
PROFILE_ID.toString(),
|
|
749
|
+
SECOND_PROFILE_ID.toString(),
|
|
750
|
+
]);
|
|
751
|
+
});
|
|
752
|
+
});
|
|
753
|
+
|
|
754
|
+
describe("hasUsableCredentials on the service", () => {
|
|
755
|
+
/*
|
|
756
|
+
* The service exposes the predicate for callers that hold a service and
|
|
757
|
+
* not the util, and it must be THE predicate - the same function the
|
|
758
|
+
* poller applies to a device row - not a second opinion that could drift.
|
|
759
|
+
* Spying on the util's export pins the delegation.
|
|
760
|
+
*/
|
|
761
|
+
test("delegates to the shared util, so a device and a profile get one answer", () => {
|
|
762
|
+
const spy: jest.SpyInstance = jest
|
|
763
|
+
.spyOn(SnmpCredentialUtil, "hasUsableCredentials")
|
|
764
|
+
.mockReturnValue(true);
|
|
765
|
+
|
|
766
|
+
const profile: NetworkSnmpCredentialProfile =
|
|
767
|
+
new NetworkSnmpCredentialProfile();
|
|
768
|
+
profile.snmpVersion = "V3";
|
|
769
|
+
profile.snmpV3Username = "monitoring";
|
|
770
|
+
|
|
771
|
+
expect(
|
|
772
|
+
NetworkSnmpCredentialProfileService.hasUsableCredentials(profile),
|
|
773
|
+
).toBe(true);
|
|
774
|
+
expect(spy).toHaveBeenCalledTimes(1);
|
|
775
|
+
expect(spy).toHaveBeenCalledWith(profile);
|
|
776
|
+
});
|
|
777
|
+
|
|
778
|
+
test("answers for a real profile without a spy", () => {
|
|
779
|
+
const usable: NetworkSnmpCredentialProfile =
|
|
780
|
+
new NetworkSnmpCredentialProfile();
|
|
781
|
+
usable.snmpVersion = "V2c";
|
|
782
|
+
usable.snmpCommunityString = "public";
|
|
783
|
+
|
|
784
|
+
const unusable: NetworkSnmpCredentialProfile =
|
|
785
|
+
new NetworkSnmpCredentialProfile();
|
|
786
|
+
unusable.snmpVersion = "V2c";
|
|
787
|
+
unusable.snmpCommunityString = " ";
|
|
788
|
+
|
|
789
|
+
expect(
|
|
790
|
+
NetworkSnmpCredentialProfileService.hasUsableCredentials(usable),
|
|
791
|
+
).toBe(true);
|
|
792
|
+
expect(
|
|
793
|
+
NetworkSnmpCredentialProfileService.hasUsableCredentials(unusable),
|
|
794
|
+
).toBe(false);
|
|
795
|
+
});
|
|
796
|
+
});
|