@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.
- package/Models/AnalyticsModels/Span.ts +14 -0
- package/Models/DatabaseModels/AlertState.ts +0 -2
- package/Models/DatabaseModels/Domain.ts +1 -1
- package/Models/DatabaseModels/EnterpriseLicense.ts +56 -0
- package/Models/DatabaseModels/Incident.ts +1 -1
- package/Models/DatabaseModels/IncidentTemplate.ts +1 -1
- package/Models/DatabaseModels/Index.ts +12 -0
- package/Models/DatabaseModels/MetricType.ts +0 -2
- package/Models/DatabaseModels/Monitor.ts +76 -0
- package/Models/DatabaseModels/MonitorStatusTimeline.ts +0 -2
- package/Models/DatabaseModels/MonitorTest.ts +0 -2
- package/Models/DatabaseModels/NetworkAlertPolicy.ts +690 -0
- package/Models/DatabaseModels/NetworkDevice.ts +297 -3
- package/Models/DatabaseModels/NetworkDeviceOidTemplate.ts +3 -1
- package/Models/DatabaseModels/NetworkDeviceRole.ts +648 -0
- package/Models/DatabaseModels/NetworkSite.ts +201 -2
- package/Models/DatabaseModels/NetworkSiteType.ts +102 -3
- package/Models/DatabaseModels/NetworkSnmpCredentialProfile.ts +841 -0
- package/Models/DatabaseModels/ScheduledMaintenance.ts +1 -1
- package/Models/DatabaseModels/ScheduledMaintenanceTemplate.ts +1 -1
- package/Models/DatabaseModels/StatusPageAnnouncement.ts +0 -2
- package/Models/DatabaseModels/StatusPageAnnouncementTemplate.ts +0 -2
- package/Models/DatabaseModels/StatusPagePrivateUser.ts +0 -2
- package/Models/DatabaseModels/StatusPageResource.ts +0 -2
- package/Models/DatabaseModels/StatusPageSubscriber.ts +0 -2
- 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/1790800000000-AddNetworkDeviceRoleTable.ts +72 -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 +14 -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/DatabaseService.ts +39 -9
- package/Server/Services/EnterpriseLicenseInstanceService.ts +197 -0
- package/Server/Services/EnterpriseLicenseService.ts +55 -0
- package/Server/Services/Index.ts +12 -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/NetworkDeviceRoleService.ts +90 -0
- 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 +186 -44
- 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 -31
- 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 +158 -27
- package/Tests/App/Dashboard/AskAiSuggestedPrompts.test.ts +279 -0
- package/Tests/App/Dashboard/DashboardChartWidgetZoom.test.tsx +35 -8
- package/Tests/App/Dashboard/DashboardCommandPalette.test.tsx +107 -3
- package/Tests/App/Dashboard/DashboardEditPermissions.test.tsx +517 -0
- package/Tests/App/Dashboard/DashboardVariablesDiscard.test.tsx +26 -0
- package/Tests/App/Dashboard/DashboardWideChartZoom.test.tsx +401 -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/MonitorTemplateColumnAndFacet.test.tsx +318 -0
- package/Tests/App/Dashboard/MonitorTypePicker.test.tsx +4 -2
- package/Tests/App/Dashboard/NetworkDeviceBulkDelete.test.tsx +357 -0
- 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 +626 -0
- 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/SideMenuHarness.tsx +11 -3
- 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/DatabaseModels/ModelRegistryInvariants.test.ts +115 -41
- 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/NetworkDeviceRoleTableMigration.test.ts +476 -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/DatabaseServiceGenerateSlug.test.ts +215 -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/NetworkDeviceRoleModel.test.ts +672 -0
- package/Tests/Server/Services/NetworkDeviceRuleEngines.test.ts +1 -1
- 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/ProjectServiceCreateSubscriptionStarted.test.ts +67 -4
- package/Tests/Server/Services/ProjectServiceNetworkSiteTypeDefaults.test.ts +214 -0
- package/Tests/Server/Services/ScheduledMaintenanceSubscriberEndTime.test.ts +369 -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/UserNotificationSettingMonitorDefaults.test.ts +248 -0
- package/Tests/Server/Services/UserNotificationSettingRollupRouting.test.ts +856 -0
- package/Tests/Server/Services/UserNotificationSettingWorkspaceChannels.test.ts +145 -3
- 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/BasicCron.test.ts +283 -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/IncomingCallPhoneNumber.test.ts +174 -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/DefaultNetworkDeviceRole.test.ts +417 -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/Charts/ChartClickDoubleClickDisambiguation.test.tsx +221 -0
- package/Tests/UI/Components/Charts/ChartDoubleClickReset.test.tsx +220 -0
- package/Tests/UI/Components/ModelTable/BaseModelTableBulkDelete.test.tsx +751 -0
- package/Tests/UI/Components/ModelTable/BaseModelTableColumnCustomization.test.tsx +475 -43
- package/Tests/UI/Components/ModelTable/ColumnPreference.test.ts +89 -0
- package/Tests/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.test.ts +15 -0
- package/Tests/UI/Components/NavBarCommandKGating.test.tsx +103 -8
- package/Tests/UI/Components/ProgressBar.test.tsx +38 -2
- package/Tests/UI/Components/SideMenuItem.test.tsx +256 -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/UI/Utils/TableColumnsToCsv.test.ts +30 -0
- package/Tests/UI/Utils/UseDashboardTimeRangeZoom.test.tsx +187 -0
- package/Tests/Utils/Dashboard/DashboardResourceListSharedArgs.test.ts +302 -0
- package/Tests/Utils/Dashboard/DashboardTimeRangeZoom.test.ts +242 -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/NetworkDeviceRoleCatalog.test.ts +981 -0
- package/Tests/Utils/Monitor/NetworkTopologyRoleCatalog.test.ts +865 -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/DeviceRoleKeyUtil.test.ts +538 -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/Slo/SloEvaluation.test.ts +171 -0
- package/Tests/Utils/Slug.test.ts +61 -1
- package/Tests/Utils/Telemetry/CaptureSpanExportGating.test.ts +145 -0
- package/Tests/jest.setup.ts +19 -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/SnmpMonitor/NetworkTopology.ts +61 -0
- package/Types/Monitor/SqlConnectionConfig.ts +31 -0
- package/Types/NetworkDevice/DefaultNetworkDeviceRole.ts +145 -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 +135 -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/Charts/Area/AreaChart.tsx +7 -0
- package/UI/Components/Charts/Bar/BarChart.tsx +6 -0
- package/UI/Components/Charts/ChartGroup/ChartGroup.tsx +9 -1
- package/UI/Components/Charts/ChartLibrary/AreaChart/AreaChart.tsx +97 -35
- package/UI/Components/Charts/ChartLibrary/BarChart/BarChart.tsx +14 -0
- package/UI/Components/Charts/ChartLibrary/LineChart/LineChart.tsx +97 -35
- package/UI/Components/Charts/ChartLibrary/Utils/DoubleClick.ts +13 -0
- package/UI/Components/Charts/Line/LineChart.tsx +7 -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/ModelTable/BaseModelTable.tsx +50 -15
- package/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.ts +44 -0
- package/UI/Components/Navbar/NavBar.tsx +62 -13
- package/UI/Components/Navbar/NavBarMenuModal.tsx +7 -2
- package/UI/Components/ProgressBar/ProgressBar.tsx +12 -1
- package/UI/Components/RadioButtons/BasicRadioButtons.tsx +37 -7
- package/UI/Components/SideMenu/CountModelSideMenuItem.tsx +2 -0
- package/UI/Components/SideMenu/SideMenu.tsx +135 -7
- package/UI/Components/SideMenu/SideMenuItem.tsx +80 -85
- package/UI/Components/SideMenu/SideMenuSection.tsx +69 -25
- 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/UI/Utils/UseDashboardTimeRangeZoom.ts +77 -0
- package/Utils/Dashboard/DashboardTimeRangeZoom.ts +118 -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/NetworkDeviceRoleCatalog.ts +232 -0
- package/Utils/Monitor/NetworkDeviceRoleUtil.ts +2 -1
- package/Utils/Monitor/NetworkTopologyUtil.ts +139 -36
- package/Utils/NetworkDevice/DeviceHealthStateUtil.ts +65 -14
- package/Utils/NetworkDevice/DeviceReachabilityUtil.ts +43 -14
- package/Utils/NetworkDevice/DeviceRoleKeyUtil.ts +137 -0
- 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/Utils/Rules/RulePatternMatchUtil.ts +1 -1
- package/Utils/Slug.ts +34 -1
- package/build/dist/Models/AnalyticsModels/Span.js +14 -0
- package/build/dist/Models/AnalyticsModels/Span.js.map +1 -1
- package/build/dist/Models/DatabaseModels/AlertState.js +0 -2
- package/build/dist/Models/DatabaseModels/AlertState.js.map +1 -1
- package/build/dist/Models/DatabaseModels/Domain.js +1 -1
- package/build/dist/Models/DatabaseModels/Domain.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/Incident.js +1 -1
- package/build/dist/Models/DatabaseModels/Incident.js.map +1 -1
- package/build/dist/Models/DatabaseModels/IncidentTemplate.js +1 -1
- package/build/dist/Models/DatabaseModels/IncidentTemplate.js.map +1 -1
- package/build/dist/Models/DatabaseModels/Index.js +12 -0
- package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
- package/build/dist/Models/DatabaseModels/MetricType.js +0 -2
- package/build/dist/Models/DatabaseModels/MetricType.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/MonitorStatusTimeline.js +0 -2
- package/build/dist/Models/DatabaseModels/MonitorStatusTimeline.js.map +1 -1
- package/build/dist/Models/DatabaseModels/MonitorTest.js +0 -2
- package/build/dist/Models/DatabaseModels/MonitorTest.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 +304 -4
- package/build/dist/Models/DatabaseModels/NetworkDevice.js.map +1 -1
- package/build/dist/Models/DatabaseModels/NetworkDeviceOidTemplate.js +3 -1
- package/build/dist/Models/DatabaseModels/NetworkDeviceOidTemplate.js.map +1 -1
- package/build/dist/Models/DatabaseModels/NetworkDeviceRole.js +677 -0
- package/build/dist/Models/DatabaseModels/NetworkDeviceRole.js.map +1 -0
- 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/ScheduledMaintenance.js +1 -1
- package/build/dist/Models/DatabaseModels/ScheduledMaintenance.js.map +1 -1
- package/build/dist/Models/DatabaseModels/ScheduledMaintenanceTemplate.js +1 -1
- package/build/dist/Models/DatabaseModels/ScheduledMaintenanceTemplate.js.map +1 -1
- package/build/dist/Models/DatabaseModels/StatusPageAnnouncement.js +0 -2
- package/build/dist/Models/DatabaseModels/StatusPageAnnouncement.js.map +1 -1
- package/build/dist/Models/DatabaseModels/StatusPageAnnouncementTemplate.js +0 -2
- package/build/dist/Models/DatabaseModels/StatusPageAnnouncementTemplate.js.map +1 -1
- package/build/dist/Models/DatabaseModels/StatusPagePrivateUser.js +0 -2
- package/build/dist/Models/DatabaseModels/StatusPagePrivateUser.js.map +1 -1
- package/build/dist/Models/DatabaseModels/StatusPageResource.js +0 -2
- package/build/dist/Models/DatabaseModels/StatusPageResource.js.map +1 -1
- package/build/dist/Models/DatabaseModels/StatusPageSubscriber.js +0 -2
- package/build/dist/Models/DatabaseModels/StatusPageSubscriber.js.map +1 -1
- 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/1790800000000-AddNetworkDeviceRoleTable.js +39 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1790800000000-AddNetworkDeviceRoleTable.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 +14 -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/DatabaseService.js +31 -5
- package/build/dist/Server/Services/DatabaseService.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 +12 -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/NetworkDeviceRoleService.js +70 -0
- package/build/dist/Server/Services/NetworkDeviceRoleService.js.map +1 -0
- 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 +131 -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 -21
- 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/DefaultNetworkDeviceRole.js +105 -0
- package/build/dist/Types/NetworkDevice/DefaultNetworkDeviceRole.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 +120 -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/Charts/Area/AreaChart.js +1 -1
- package/build/dist/UI/Components/Charts/Area/AreaChart.js.map +1 -1
- package/build/dist/UI/Components/Charts/Bar/BarChart.js +1 -1
- package/build/dist/UI/Components/Charts/Bar/BarChart.js.map +1 -1
- package/build/dist/UI/Components/Charts/ChartGroup/ChartGroup.js +6 -1
- package/build/dist/UI/Components/Charts/ChartGroup/ChartGroup.js.map +1 -1
- package/build/dist/UI/Components/Charts/ChartLibrary/AreaChart/AreaChart.js +79 -31
- package/build/dist/UI/Components/Charts/ChartLibrary/AreaChart/AreaChart.js.map +1 -1
- package/build/dist/UI/Components/Charts/ChartLibrary/BarChart/BarChart.js +7 -1
- package/build/dist/UI/Components/Charts/ChartLibrary/BarChart/BarChart.js.map +1 -1
- package/build/dist/UI/Components/Charts/ChartLibrary/LineChart/LineChart.js +79 -31
- package/build/dist/UI/Components/Charts/ChartLibrary/LineChart/LineChart.js.map +1 -1
- package/build/dist/UI/Components/Charts/ChartLibrary/Utils/DoubleClick.js +14 -0
- package/build/dist/UI/Components/Charts/ChartLibrary/Utils/DoubleClick.js.map +1 -0
- package/build/dist/UI/Components/Charts/Line/LineChart.js +1 -1
- package/build/dist/UI/Components/Charts/Line/LineChart.js.map +1 -1
- 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/ModelTable/BaseModelTable.js +39 -13
- package/build/dist/UI/Components/ModelTable/BaseModelTable.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/Navbar/NavBar.js +44 -9
- package/build/dist/UI/Components/Navbar/NavBar.js.map +1 -1
- package/build/dist/UI/Components/Navbar/NavBarMenuModal.js +2 -2
- package/build/dist/UI/Components/Navbar/NavBarMenuModal.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/CountModelSideMenuItem.js +1 -1
- package/build/dist/UI/Components/SideMenu/CountModelSideMenuItem.js.map +1 -1
- package/build/dist/UI/Components/SideMenu/SideMenu.js +76 -11
- package/build/dist/UI/Components/SideMenu/SideMenu.js.map +1 -1
- package/build/dist/UI/Components/SideMenu/SideMenuItem.js +50 -54
- package/build/dist/UI/Components/SideMenu/SideMenuItem.js.map +1 -1
- package/build/dist/UI/Components/SideMenu/SideMenuSection.js +32 -9
- 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/UI/Utils/UseDashboardTimeRangeZoom.js +42 -0
- package/build/dist/UI/Utils/UseDashboardTimeRangeZoom.js.map +1 -0
- package/build/dist/Utils/Dashboard/DashboardTimeRangeZoom.js +74 -0
- package/build/dist/Utils/Dashboard/DashboardTimeRangeZoom.js.map +1 -0
- 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/NetworkDeviceRoleCatalog.js +126 -0
- package/build/dist/Utils/Monitor/NetworkDeviceRoleCatalog.js.map +1 -0
- package/build/dist/Utils/Monitor/NetworkDeviceRoleUtil.js +2 -1
- package/build/dist/Utils/Monitor/NetworkDeviceRoleUtil.js.map +1 -1
- package/build/dist/Utils/Monitor/NetworkTopologyUtil.js +75 -35
- 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/DeviceRoleKeyUtil.js +114 -0
- package/build/dist/Utils/NetworkDevice/DeviceRoleKeyUtil.js.map +1 -0
- 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/build/dist/Utils/Rules/RulePatternMatchUtil.js +1 -1
- package/build/dist/Utils/Slug.js +31 -1
- package/build/dist/Utils/Slug.js.map +1 -1
- 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
|
+
});
|