@oneuptime/common 12.0.30 → 12.0.31
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/SecurityEvent.ts +48 -16
- package/Models/AnalyticsModels/ThreatIntelIndicator.ts +10 -5
- package/Models/DatabaseModels/AlertSeverity.ts +44 -0
- package/Models/DatabaseModels/DetectionRule.ts +16 -5
- package/Models/DatabaseModels/GoogleSecOpsConnection.ts +14 -5
- package/Models/DatabaseModels/IncidentSeverity.ts +44 -0
- package/Models/DatabaseModels/Index.ts +2 -0
- package/Models/DatabaseModels/NetworkDevice.ts +113 -3
- package/Models/DatabaseModels/NetworkDeviceAutoImportRule.ts +88 -0
- package/Models/DatabaseModels/NetworkDeviceDiscoveryScan.ts +22 -0
- package/Models/DatabaseModels/NetworkDeviceOidTemplate.ts +499 -0
- package/Models/DatabaseModels/ThreatIntelFeed.ts +16 -5
- package/Server/API/GlobalConfigAPI.ts +362 -183
- package/Server/API/TelemetryAPI.ts +42 -4
- package/Server/EnvironmentConfig.ts +112 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1790500000000-AddNetworkDeviceOidTemplate.ts +59 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1790600000000-AddAutoImportRuleOidTemplate.ts +25 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +4 -0
- package/Server/Middleware/MultipartFormData.ts +118 -32
- package/Server/Services/AlertEpisodeLabelRuleEngineService.ts +9 -1
- package/Server/Services/AlertEpisodeOnCallRuleEngineService.ts +9 -1
- package/Server/Services/AlertEpisodeOwnerRuleEngineService.ts +9 -1
- package/Server/Services/AlertEpisodePrivacyRuleEngineService.ts +9 -1
- package/Server/Services/AlertGroupingEngineService.ts +9 -1
- package/Server/Services/AlertLabelRuleEngineService.ts +9 -1
- package/Server/Services/AlertOnCallRuleEngineService.ts +9 -1
- package/Server/Services/AlertOwnerRuleEngineService.ts +9 -1
- package/Server/Services/AlertPrivacyRuleEngineService.ts +9 -1
- package/Server/Services/AlertReminderRuleService.ts +9 -1
- package/Server/Services/AutoRemediationRuleEngineService.ts +9 -1
- package/Server/Services/CephClusterLabelRuleEngineService.ts +9 -1
- package/Server/Services/CephClusterOwnerRuleEngineService.ts +9 -1
- package/Server/Services/CloudResourceLabelRuleEngineService.ts +9 -1
- package/Server/Services/CloudResourceOwnerRuleEngineService.ts +9 -1
- package/Server/Services/DashboardLabelRuleEngineService.ts +9 -1
- package/Server/Services/DashboardOwnerRuleEngineService.ts +9 -1
- package/Server/Services/DockerHostLabelRuleEngineService.ts +9 -1
- package/Server/Services/DockerHostOwnerRuleEngineService.ts +9 -1
- package/Server/Services/DockerSwarmClusterLabelRuleEngineService.ts +9 -1
- package/Server/Services/DockerSwarmClusterOwnerRuleEngineService.ts +9 -1
- package/Server/Services/HostLabelRuleEngineService.ts +9 -1
- package/Server/Services/HostOwnerRuleEngineService.ts +9 -1
- package/Server/Services/IncidentEpisodeLabelRuleEngineService.ts +9 -1
- package/Server/Services/IncidentEpisodeOnCallRuleEngineService.ts +9 -1
- package/Server/Services/IncidentEpisodeOwnerRuleEngineService.ts +9 -1
- package/Server/Services/IncidentEpisodePrivacyRuleEngineService.ts +9 -1
- package/Server/Services/IncidentGroupingEngineService.ts +9 -1
- package/Server/Services/IncidentLabelRuleEngineService.ts +9 -1
- package/Server/Services/IncidentOnCallRuleEngineService.ts +9 -1
- package/Server/Services/IncidentOwnerRuleEngineService.ts +9 -1
- package/Server/Services/IncidentPrivacyRuleEngineService.ts +9 -1
- package/Server/Services/IncidentReminderRuleService.ts +9 -1
- package/Server/Services/IncidentSlaRuleService.ts +9 -1
- package/Server/Services/IncomingCallPolicyLabelRuleEngineService.ts +9 -1
- package/Server/Services/IncomingCallPolicyOwnerRuleEngineService.ts +9 -1
- package/Server/Services/Index.ts +2 -0
- package/Server/Services/IoTFleetLabelRuleEngineService.ts +9 -1
- package/Server/Services/IoTFleetOwnerRuleEngineService.ts +9 -1
- package/Server/Services/KubernetesClusterLabelRuleEngineService.ts +9 -1
- package/Server/Services/KubernetesClusterOwnerRuleEngineService.ts +9 -1
- package/Server/Services/KubernetesResourceService.ts +5 -1
- package/Server/Services/MonitorLabelRuleEngineService.ts +9 -1
- package/Server/Services/MonitorOwnerRuleEngineService.ts +9 -1
- package/Server/Services/NetworkDeviceAutoImportRuleEngineService.ts +35 -0
- package/Server/Services/NetworkDeviceAutoImportRuleService.ts +96 -0
- package/Server/Services/NetworkDeviceLabelRuleEngineService.ts +9 -1
- package/Server/Services/NetworkDeviceOidTemplateService.ts +201 -0
- package/Server/Services/NetworkDeviceOwnerRuleEngineService.ts +9 -1
- package/Server/Services/NetworkDeviceService.ts +209 -1
- package/Server/Services/OnCallDutyPolicyLabelRuleEngineService.ts +9 -1
- package/Server/Services/OnCallDutyPolicyOwnerRuleEngineService.ts +9 -1
- package/Server/Services/OnCallDutyPolicyScheduleLabelRuleEngineService.ts +9 -1
- package/Server/Services/OnCallDutyPolicyScheduleOwnerRuleEngineService.ts +9 -1
- package/Server/Services/PodmanHostLabelRuleEngineService.ts +9 -1
- package/Server/Services/PodmanHostOwnerRuleEngineService.ts +9 -1
- package/Server/Services/ProxmoxClusterLabelRuleEngineService.ts +9 -1
- package/Server/Services/ProxmoxClusterOwnerRuleEngineService.ts +9 -1
- package/Server/Services/RumApplicationLabelRuleEngineService.ts +9 -1
- package/Server/Services/RumApplicationOwnerRuleEngineService.ts +9 -1
- package/Server/Services/RunbookLabelRuleEngineService.ts +9 -1
- package/Server/Services/RunbookOwnerRuleEngineService.ts +9 -1
- package/Server/Services/RunbookRuleEngineService.ts +9 -1
- package/Server/Services/ScheduledMaintenanceLabelRuleEngineService.ts +9 -1
- package/Server/Services/ScheduledMaintenanceOwnerRuleEngineService.ts +9 -1
- package/Server/Services/ScheduledMaintenanceReminderRuleService.ts +9 -1
- package/Server/Services/ServerlessFunctionLabelRuleEngineService.ts +9 -1
- package/Server/Services/ServerlessFunctionOwnerRuleEngineService.ts +9 -1
- package/Server/Services/ServiceLabelRuleEngineService.ts +9 -1
- package/Server/Services/ServiceOwnerRuleEngineService.ts +9 -1
- package/Server/Services/StatusPageLabelRuleEngineService.ts +9 -1
- package/Server/Services/StatusPageMonitorRuleEngineService.ts +7 -0
- package/Server/Services/StatusPageOwnerRuleEngineService.ts +9 -1
- package/Server/Services/TelemetrySourceMapService.ts +266 -23
- package/Server/Services/UserService.ts +27 -0
- package/Server/Services/WorkflowLabelRuleEngineService.ts +9 -1
- package/Server/Services/WorkflowOwnerRuleEngineService.ts +9 -1
- package/Server/Utils/EnterpriseLicense/EnterpriseLicenseSeatUtil.ts +186 -0
- package/Server/Utils/Monitor/CapturedMetricAttributeUtil.ts +245 -0
- package/Server/Utils/Monitor/Criteria/SnmpMonitorCriteria.ts +21 -2
- package/Server/Utils/Monitor/MonitorMetricUtil.ts +55 -21
- package/Server/Utils/Monitor/MonitorTemplateUtil.ts +32 -0
- package/Server/Utils/Monitor/NetworkDeviceMetricUtil.ts +15 -2
- package/Server/Utils/Monitor/NetworkDeviceWalkUtil.ts +18 -1
- package/Server/Utils/Monitor/NetworkInventoryUtil.ts +10 -0
- package/Server/Utils/Monitor/SeriesResourceLabels.ts +34 -0
- package/Server/Utils/Rules/RuleEngineRuleRead.ts +48 -0
- package/Server/Utils/Telemetry/ExceptionSanitizer.ts +14 -1
- package/Server/Utils/Telemetry/LogExceptionExtractor.ts +14 -2
- package/Server/Utils/Telemetry/SourceMapResolver.ts +16 -5
- package/Server/Utils/Telemetry/StackTraceParser.ts +399 -0
- package/Tests/App/Dashboard/EventOverlayHook.test.tsx +125 -0
- package/Tests/App/Dashboard/HeaderImageAssets.test.tsx +93 -0
- package/Tests/App/Dashboard/OnCallReadinessSurfaces.test.tsx +3 -3
- package/Tests/App/Dashboard/UserElementEmail.test.tsx +12 -4
- package/Tests/App/Dashboard/UserEmailCallSites.test.tsx +1 -1
- package/Tests/Models/DatabaseModels/DomainRoleTierCoverage.test.ts +14 -0
- package/Tests/Models/DatabaseModels/ModelRegistryInvariants.test.ts +469 -0
- package/Tests/Models/SecurityDomainAccessControl.test.ts +429 -0
- package/Tests/Server/API/GlobalConfigLicense.test.ts +657 -0
- package/Tests/Server/API/SecurityEventAttributesAPI.test.ts +84 -6
- package/Tests/Server/API/TelemetryResolveStackTraceAPI.test.ts +805 -0
- package/Tests/Server/Infrastructure/Postgres/AddOnCallCalendarFeedsMigration.test.ts +32 -7
- package/Tests/Server/Middleware/IdentityRateLimit.test.ts +1144 -0
- package/Tests/Server/Middleware/MultipartFormData.test.ts +618 -3
- package/Tests/Server/Services/MonitorLabelRuleEngineScale.test.ts +520 -0
- package/Tests/Server/Services/NetworkDeviceOidTemplateService.test.ts +332 -0
- package/Tests/Server/Services/NetworkDeviceOidTemplateWriteGuards.test.ts +409 -0
- package/Tests/Server/Services/RuleEngineRuleFetchLimit.test.ts +239 -0
- package/Tests/Server/Services/TelemetrySourceMapService.test.ts +1210 -2
- package/Tests/Server/Services/UserServiceSeatLimit.test.ts +182 -0
- package/Tests/Server/Types/AnalyticsDatabase/SecurityEventModelPermission.test.ts +255 -0
- package/Tests/Server/Types/Database/Permissions/ReadBlockPermission.test.ts +212 -0
- package/Tests/Server/Types/Database/Permissions/SecurityRoleAccess.test.ts +413 -0
- package/Tests/Server/Utils/CodeRepository.test.ts +689 -0
- package/Tests/Server/Utils/EnterpriseLicense/EnterpriseLicenseSeatUtil.test.ts +495 -0
- package/Tests/Server/Utils/ExceptionSanitizer.test.ts +77 -0
- package/Tests/Server/Utils/Monitor/CapturedMetricAttributeUtil.test.ts +284 -0
- package/Tests/Server/Utils/Monitor/MonitorCustomMetricAttributes.test.ts +503 -0
- package/Tests/Server/Utils/Monitor/MonitorTemplatePrototypePollution.test.ts +106 -0
- package/Tests/Server/Utils/Monitor/NetworkDeviceWalkLogWritePath.test.ts +33 -4
- package/Tests/Server/Utils/Monitor/NetworkDeviceWalkUtil.test.ts +14 -4
- package/Tests/Server/Utils/Monitor/NetworkInventoryUtil.test.ts +44 -0
- package/Tests/Server/Utils/OpenAPISpec.test.ts +536 -0
- package/Tests/Server/Utils/Rules/RuleEngineRuleRead.test.ts +115 -0
- package/Tests/Server/Utils/StackTraceParser.test.ts +610 -0
- package/Tests/Server/Utils/Telemetry/LogExceptionExtractor.test.ts +0 -0
- package/Tests/Server/Utils/Telemetry/SourceMapLimits.test.ts +656 -0
- package/Tests/Server/Utils/Telemetry/SourceMapResolver.test.ts +100 -0
- package/Tests/Types/Monitor/SnmpMonitor/SnmpOidListUtil.test.ts +454 -0
- package/Tests/Types/SecurityRolePermissions.test.ts +193 -0
- package/Tests/UI/Components/Charts/AnnotationLayout.test.ts +773 -0
- package/Tests/UI/Components/Charts/ChartAnnotationRail.test.tsx +789 -0
- package/Tests/UI/Components/Charts/ChartBucketIdentity.test.ts +254 -0
- package/Tests/UI/Components/Charts/TimeAnnotation.test.ts +471 -0
- package/Tests/UI/Components/EditionLabelLicenseRefresh.test.tsx +405 -0
- package/Tests/UI/Components/ErrorMessageRefreshControl.test.tsx +83 -0
- package/Tests/UI/Components/MarkdownConverters.test.ts +686 -0
- package/Tests/UI/Components/ModelTable/BaseModelTableDeleteAndEmptyStates.test.tsx +341 -0
- package/Tests/UI/Components/OrderedStatesList.test.tsx +5 -5
- package/Tests/UI/Components/PendingProjectInvitations.test.tsx +1 -1
- package/Tests/UI/Components/TableSortAndMobileColumns.test.tsx +195 -0
- package/Tests/UI/Components/XAxis.test.ts +270 -5
- package/Tests/UI/Components/XAxisDaylightSaving.test.ts +113 -0
- package/Tests/UI/Styles/ChartFocusRing.test.ts +153 -0
- package/Tests/UI/Styles/ChartFocusRingCoverage.test.tsx +377 -0
- package/Tests/UI/Styles/ThemeStylesheet.ts +162 -0
- package/Tests/Utils/EnterpriseLicenseSeats.test.ts +507 -0
- package/Tests/Utils/NetworkDiscovery/DiscoveredDeviceBuilder.test.ts +951 -1
- package/Tests/Utils/NetworkDiscovery/DiscoveredHostUtil.test.ts +238 -0
- package/Tests/Utils/NetworkDiscovery/DiscoveryReverseDnsChain.test.ts +1056 -0
- package/Tests/Utils/NetworkDiscovery/ReverseDnsNameUtil.test.ts +882 -0
- package/Types/Date.ts +39 -0
- package/Types/Monitor/SnmpMonitor/SnmpOidListUtil.ts +333 -0
- package/Types/Permission.ts +96 -0
- package/Types/Rum/SessionReplay.ts +21 -0
- package/Types/Telemetry/SourceMap.ts +8 -0
- package/UI/Components/Charts/ChartLibrary/Annotations/AnnotationHoverCard.tsx +176 -0
- package/UI/Components/Charts/ChartLibrary/Annotations/AnnotationLayout.ts +745 -0
- package/UI/Components/Charts/ChartLibrary/Annotations/ChartAnnotationLayer.tsx +576 -0
- package/UI/Components/Charts/ChartLibrary/Annotations/UseChartAnnotations.tsx +204 -0
- package/UI/Components/Charts/ChartLibrary/AreaChart/AreaChart.tsx +491 -544
- package/UI/Components/Charts/ChartLibrary/BarChart/BarChart.tsx +324 -372
- package/UI/Components/Charts/ChartLibrary/LineChart/LineChart.tsx +487 -540
- package/UI/Components/Charts/ChartLibrary/Types/FormattedReferenceRegion.ts +7 -3
- package/UI/Components/Charts/ChartLibrary/Types/FormattedTimeReferenceLine.ts +14 -3
- package/UI/Components/Charts/Types/ChartEventKind.ts +13 -0
- package/UI/Components/Charts/Types/ReferenceRegionProps.ts +6 -0
- package/UI/Components/Charts/Types/TimeReferenceLineProps.ts +20 -3
- package/UI/Components/Charts/Utils/TimeAnnotation.ts +69 -35
- package/UI/Components/Charts/Utils/XAxis.ts +125 -18
- package/UI/Components/EditionLabel/EditionLabel.tsx +280 -26
- package/UI/Components/ErrorMessage/ErrorMessage.tsx +21 -10
- package/UI/Components/Feed/FeedItem.tsx +4 -5
- package/UI/Components/Header/HeaderIconDropdownButton.tsx +1 -2
- package/UI/Components/Header/UserProfile/UserProfile.tsx +1 -2
- package/UI/Components/Image/Image.tsx +20 -3
- package/UI/Components/Markdown.tsx/MarkdownConverters.ts +0 -0
- package/UI/Components/MemberRoleAssignment/MemberRoleAssignment.tsx +1 -2
- package/UI/Components/ModelTable/BaseModelTable.tsx +150 -24
- package/UI/Components/Table/TableHeader.tsx +64 -48
- package/UI/Components/Table/TableRow.tsx +13 -3
- package/UI/Styles/Theme.css +38 -0
- package/Utils/EnterpriseLicense/EnterpriseLicenseSeats.ts +271 -0
- package/Utils/NetworkDiscovery/AutoImportRuleMatcher.ts +6 -0
- package/Utils/NetworkDiscovery/DiscoveredDeviceBuilder.ts +141 -10
- package/Utils/NetworkDiscovery/DiscoveredHostUtil.ts +55 -3
- package/Utils/NetworkDiscovery/ReverseDnsNameUtil.ts +151 -0
- package/Utils/Rules/RuleEngineLimits.ts +32 -0
- package/build/dist/Models/AnalyticsModels/SecurityEvent.js +48 -16
- package/build/dist/Models/AnalyticsModels/SecurityEvent.js.map +1 -1
- package/build/dist/Models/AnalyticsModels/ThreatIntelIndicator.js +10 -5
- package/build/dist/Models/AnalyticsModels/ThreatIntelIndicator.js.map +1 -1
- package/build/dist/Models/DatabaseModels/AlertSeverity.js +46 -1
- package/build/dist/Models/DatabaseModels/AlertSeverity.js.map +1 -1
- package/build/dist/Models/DatabaseModels/DetectionRule.js +16 -5
- package/build/dist/Models/DatabaseModels/DetectionRule.js.map +1 -1
- package/build/dist/Models/DatabaseModels/GoogleSecOpsConnection.js +14 -5
- package/build/dist/Models/DatabaseModels/GoogleSecOpsConnection.js.map +1 -1
- package/build/dist/Models/DatabaseModels/IncidentSeverity.js +46 -1
- package/build/dist/Models/DatabaseModels/IncidentSeverity.js.map +1 -1
- package/build/dist/Models/DatabaseModels/Index.js +2 -0
- package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
- package/build/dist/Models/DatabaseModels/NetworkDevice.js +115 -3
- package/build/dist/Models/DatabaseModels/NetworkDevice.js.map +1 -1
- package/build/dist/Models/DatabaseModels/NetworkDeviceAutoImportRule.js +88 -0
- package/build/dist/Models/DatabaseModels/NetworkDeviceAutoImportRule.js.map +1 -1
- package/build/dist/Models/DatabaseModels/NetworkDeviceDiscoveryScan.js.map +1 -1
- package/build/dist/Models/DatabaseModels/NetworkDeviceOidTemplate.js +519 -0
- package/build/dist/Models/DatabaseModels/NetworkDeviceOidTemplate.js.map +1 -0
- package/build/dist/Models/DatabaseModels/ThreatIntelFeed.js +16 -5
- package/build/dist/Models/DatabaseModels/ThreatIntelFeed.js.map +1 -1
- package/build/dist/Server/API/GlobalConfigAPI.js +293 -176
- package/build/dist/Server/API/GlobalConfigAPI.js.map +1 -1
- package/build/dist/Server/API/TelemetryAPI.js +31 -3
- package/build/dist/Server/API/TelemetryAPI.js.map +1 -1
- package/build/dist/Server/EnvironmentConfig.js +83 -0
- package/build/dist/Server/EnvironmentConfig.js.map +1 -1
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1790500000000-AddNetworkDeviceOidTemplate.js +26 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1790500000000-AddNetworkDeviceOidTemplate.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1790600000000-AddAutoImportRuleOidTemplate.js +14 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1790600000000-AddAutoImportRuleOidTemplate.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +4 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
- package/build/dist/Server/Middleware/MultipartFormData.js +93 -28
- package/build/dist/Server/Middleware/MultipartFormData.js.map +1 -1
- package/build/dist/Server/Services/AlertEpisodeLabelRuleEngineService.js +8 -1
- package/build/dist/Server/Services/AlertEpisodeLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/AlertEpisodeOnCallRuleEngineService.js +8 -1
- package/build/dist/Server/Services/AlertEpisodeOnCallRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/AlertEpisodeOwnerRuleEngineService.js +8 -1
- package/build/dist/Server/Services/AlertEpisodeOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/AlertEpisodePrivacyRuleEngineService.js +8 -1
- package/build/dist/Server/Services/AlertEpisodePrivacyRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/AlertGroupingEngineService.js +8 -1
- package/build/dist/Server/Services/AlertGroupingEngineService.js.map +1 -1
- package/build/dist/Server/Services/AlertLabelRuleEngineService.js +8 -1
- package/build/dist/Server/Services/AlertLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/AlertOnCallRuleEngineService.js +8 -1
- package/build/dist/Server/Services/AlertOnCallRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/AlertOwnerRuleEngineService.js +8 -1
- package/build/dist/Server/Services/AlertOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/AlertPrivacyRuleEngineService.js +8 -1
- package/build/dist/Server/Services/AlertPrivacyRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/AlertReminderRuleService.js +8 -1
- package/build/dist/Server/Services/AlertReminderRuleService.js.map +1 -1
- package/build/dist/Server/Services/AutoRemediationRuleEngineService.js +8 -1
- package/build/dist/Server/Services/AutoRemediationRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/CephClusterLabelRuleEngineService.js +8 -1
- package/build/dist/Server/Services/CephClusterLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/CephClusterOwnerRuleEngineService.js +8 -1
- package/build/dist/Server/Services/CephClusterOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/CloudResourceLabelRuleEngineService.js +8 -1
- package/build/dist/Server/Services/CloudResourceLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/CloudResourceOwnerRuleEngineService.js +8 -1
- package/build/dist/Server/Services/CloudResourceOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/DashboardLabelRuleEngineService.js +8 -1
- package/build/dist/Server/Services/DashboardLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/DashboardOwnerRuleEngineService.js +8 -1
- package/build/dist/Server/Services/DashboardOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/DockerHostLabelRuleEngineService.js +8 -1
- package/build/dist/Server/Services/DockerHostLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/DockerHostOwnerRuleEngineService.js +8 -1
- package/build/dist/Server/Services/DockerHostOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/DockerSwarmClusterLabelRuleEngineService.js +8 -1
- package/build/dist/Server/Services/DockerSwarmClusterLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/DockerSwarmClusterOwnerRuleEngineService.js +8 -1
- package/build/dist/Server/Services/DockerSwarmClusterOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/HostLabelRuleEngineService.js +8 -1
- package/build/dist/Server/Services/HostLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/HostOwnerRuleEngineService.js +8 -1
- package/build/dist/Server/Services/HostOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/IncidentEpisodeLabelRuleEngineService.js +8 -1
- package/build/dist/Server/Services/IncidentEpisodeLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/IncidentEpisodeOnCallRuleEngineService.js +8 -1
- package/build/dist/Server/Services/IncidentEpisodeOnCallRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/IncidentEpisodeOwnerRuleEngineService.js +8 -1
- package/build/dist/Server/Services/IncidentEpisodeOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/IncidentEpisodePrivacyRuleEngineService.js +8 -1
- package/build/dist/Server/Services/IncidentEpisodePrivacyRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/IncidentGroupingEngineService.js +8 -1
- package/build/dist/Server/Services/IncidentGroupingEngineService.js.map +1 -1
- package/build/dist/Server/Services/IncidentLabelRuleEngineService.js +8 -1
- package/build/dist/Server/Services/IncidentLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/IncidentOnCallRuleEngineService.js +8 -1
- package/build/dist/Server/Services/IncidentOnCallRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/IncidentOwnerRuleEngineService.js +8 -1
- package/build/dist/Server/Services/IncidentOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/IncidentPrivacyRuleEngineService.js +8 -1
- package/build/dist/Server/Services/IncidentPrivacyRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/IncidentReminderRuleService.js +8 -1
- package/build/dist/Server/Services/IncidentReminderRuleService.js.map +1 -1
- package/build/dist/Server/Services/IncidentSlaRuleService.js +8 -1
- package/build/dist/Server/Services/IncidentSlaRuleService.js.map +1 -1
- package/build/dist/Server/Services/IncomingCallPolicyLabelRuleEngineService.js +8 -1
- package/build/dist/Server/Services/IncomingCallPolicyLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/IncomingCallPolicyOwnerRuleEngineService.js +8 -1
- package/build/dist/Server/Services/IncomingCallPolicyOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/Index.js +2 -0
- package/build/dist/Server/Services/Index.js.map +1 -1
- package/build/dist/Server/Services/IoTFleetLabelRuleEngineService.js +8 -1
- package/build/dist/Server/Services/IoTFleetLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/IoTFleetOwnerRuleEngineService.js +8 -1
- package/build/dist/Server/Services/IoTFleetOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/KubernetesClusterLabelRuleEngineService.js +8 -1
- package/build/dist/Server/Services/KubernetesClusterLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/KubernetesClusterOwnerRuleEngineService.js +8 -1
- package/build/dist/Server/Services/KubernetesClusterOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/KubernetesResourceService.js +5 -1
- package/build/dist/Server/Services/KubernetesResourceService.js.map +1 -1
- package/build/dist/Server/Services/MonitorLabelRuleEngineService.js +8 -1
- package/build/dist/Server/Services/MonitorLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/MonitorOwnerRuleEngineService.js +8 -1
- package/build/dist/Server/Services/MonitorOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/NetworkDeviceAutoImportRuleEngineService.js +30 -21
- package/build/dist/Server/Services/NetworkDeviceAutoImportRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/NetworkDeviceAutoImportRuleService.js +64 -0
- package/build/dist/Server/Services/NetworkDeviceAutoImportRuleService.js.map +1 -1
- package/build/dist/Server/Services/NetworkDeviceLabelRuleEngineService.js +8 -1
- package/build/dist/Server/Services/NetworkDeviceLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/NetworkDeviceOidTemplateService.js +180 -0
- package/build/dist/Server/Services/NetworkDeviceOidTemplateService.js.map +1 -0
- package/build/dist/Server/Services/NetworkDeviceOwnerRuleEngineService.js +8 -1
- package/build/dist/Server/Services/NetworkDeviceOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/NetworkDeviceService.js +154 -1
- package/build/dist/Server/Services/NetworkDeviceService.js.map +1 -1
- package/build/dist/Server/Services/OnCallDutyPolicyLabelRuleEngineService.js +8 -1
- package/build/dist/Server/Services/OnCallDutyPolicyLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/OnCallDutyPolicyOwnerRuleEngineService.js +8 -1
- package/build/dist/Server/Services/OnCallDutyPolicyOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/OnCallDutyPolicyScheduleLabelRuleEngineService.js +8 -1
- package/build/dist/Server/Services/OnCallDutyPolicyScheduleLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/OnCallDutyPolicyScheduleOwnerRuleEngineService.js +8 -1
- package/build/dist/Server/Services/OnCallDutyPolicyScheduleOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/PodmanHostLabelRuleEngineService.js +8 -1
- package/build/dist/Server/Services/PodmanHostLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/PodmanHostOwnerRuleEngineService.js +8 -1
- package/build/dist/Server/Services/PodmanHostOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/ProxmoxClusterLabelRuleEngineService.js +8 -1
- package/build/dist/Server/Services/ProxmoxClusterLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/ProxmoxClusterOwnerRuleEngineService.js +8 -1
- package/build/dist/Server/Services/ProxmoxClusterOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/RumApplicationLabelRuleEngineService.js +8 -1
- package/build/dist/Server/Services/RumApplicationLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/RumApplicationOwnerRuleEngineService.js +8 -1
- package/build/dist/Server/Services/RumApplicationOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/RunbookLabelRuleEngineService.js +8 -1
- package/build/dist/Server/Services/RunbookLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/RunbookOwnerRuleEngineService.js +8 -1
- package/build/dist/Server/Services/RunbookOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/RunbookRuleEngineService.js +8 -1
- package/build/dist/Server/Services/RunbookRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/ScheduledMaintenanceLabelRuleEngineService.js +8 -1
- package/build/dist/Server/Services/ScheduledMaintenanceLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/ScheduledMaintenanceOwnerRuleEngineService.js +8 -1
- package/build/dist/Server/Services/ScheduledMaintenanceOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/ScheduledMaintenanceReminderRuleService.js +8 -1
- package/build/dist/Server/Services/ScheduledMaintenanceReminderRuleService.js.map +1 -1
- package/build/dist/Server/Services/ServerlessFunctionLabelRuleEngineService.js +8 -1
- package/build/dist/Server/Services/ServerlessFunctionLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/ServerlessFunctionOwnerRuleEngineService.js +8 -1
- package/build/dist/Server/Services/ServerlessFunctionOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/ServiceLabelRuleEngineService.js +8 -1
- package/build/dist/Server/Services/ServiceLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/ServiceOwnerRuleEngineService.js +8 -1
- package/build/dist/Server/Services/ServiceOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/StatusPageLabelRuleEngineService.js +8 -1
- package/build/dist/Server/Services/StatusPageLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/StatusPageMonitorRuleEngineService.js +6 -0
- package/build/dist/Server/Services/StatusPageMonitorRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/StatusPageOwnerRuleEngineService.js +8 -1
- package/build/dist/Server/Services/StatusPageOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/TelemetrySourceMapService.js +213 -19
- package/build/dist/Server/Services/TelemetrySourceMapService.js.map +1 -1
- package/build/dist/Server/Services/UserService.js +25 -0
- package/build/dist/Server/Services/UserService.js.map +1 -1
- package/build/dist/Server/Services/WorkflowLabelRuleEngineService.js +8 -1
- package/build/dist/Server/Services/WorkflowLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/WorkflowOwnerRuleEngineService.js +8 -1
- package/build/dist/Server/Services/WorkflowOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Utils/EnterpriseLicense/EnterpriseLicenseSeatUtil.js +145 -0
- package/build/dist/Server/Utils/EnterpriseLicense/EnterpriseLicenseSeatUtil.js.map +1 -0
- package/build/dist/Server/Utils/Monitor/CapturedMetricAttributeUtil.js +201 -0
- package/build/dist/Server/Utils/Monitor/CapturedMetricAttributeUtil.js.map +1 -0
- package/build/dist/Server/Utils/Monitor/Criteria/SnmpMonitorCriteria.js +19 -2
- package/build/dist/Server/Utils/Monitor/Criteria/SnmpMonitorCriteria.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorMetricUtil.js +42 -23
- package/build/dist/Server/Utils/Monitor/MonitorMetricUtil.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorTemplateUtil.js +29 -0
- package/build/dist/Server/Utils/Monitor/MonitorTemplateUtil.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/NetworkDeviceMetricUtil.js +11 -2
- package/build/dist/Server/Utils/Monitor/NetworkDeviceMetricUtil.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/NetworkDeviceWalkUtil.js +16 -1
- package/build/dist/Server/Utils/Monitor/NetworkDeviceWalkUtil.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/NetworkInventoryUtil.js +10 -0
- package/build/dist/Server/Utils/Monitor/NetworkInventoryUtil.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/SeriesResourceLabels.js +33 -0
- package/build/dist/Server/Utils/Monitor/SeriesResourceLabels.js.map +1 -1
- package/build/dist/Server/Utils/Rules/RuleEngineRuleRead.js +37 -0
- package/build/dist/Server/Utils/Rules/RuleEngineRuleRead.js.map +1 -0
- package/build/dist/Server/Utils/Telemetry/ExceptionSanitizer.js +12 -1
- package/build/dist/Server/Utils/Telemetry/ExceptionSanitizer.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/LogExceptionExtractor.js +14 -2
- package/build/dist/Server/Utils/Telemetry/LogExceptionExtractor.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/SourceMapResolver.js +15 -5
- package/build/dist/Server/Utils/Telemetry/SourceMapResolver.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/StackTraceParser.js +307 -0
- package/build/dist/Server/Utils/Telemetry/StackTraceParser.js.map +1 -1
- package/build/dist/Types/Date.js +27 -0
- package/build/dist/Types/Date.js.map +1 -1
- package/build/dist/Types/Monitor/SnmpMonitor/SnmpOidListUtil.js +253 -0
- package/build/dist/Types/Monitor/SnmpMonitor/SnmpOidListUtil.js.map +1 -0
- package/build/dist/Types/Permission.js +86 -0
- package/build/dist/Types/Permission.js.map +1 -1
- package/build/dist/Types/Rum/SessionReplay.js +19 -0
- package/build/dist/Types/Rum/SessionReplay.js.map +1 -1
- package/build/dist/UI/Components/Charts/ChartLibrary/Annotations/AnnotationHoverCard.js +83 -0
- package/build/dist/UI/Components/Charts/ChartLibrary/Annotations/AnnotationHoverCard.js.map +1 -0
- package/build/dist/UI/Components/Charts/ChartLibrary/Annotations/AnnotationLayout.js +531 -0
- package/build/dist/UI/Components/Charts/ChartLibrary/Annotations/AnnotationLayout.js.map +1 -0
- package/build/dist/UI/Components/Charts/ChartLibrary/Annotations/ChartAnnotationLayer.js +264 -0
- package/build/dist/UI/Components/Charts/ChartLibrary/Annotations/ChartAnnotationLayer.js.map +1 -0
- package/build/dist/UI/Components/Charts/ChartLibrary/Annotations/UseChartAnnotations.js +122 -0
- package/build/dist/UI/Components/Charts/ChartLibrary/Annotations/UseChartAnnotations.js.map +1 -0
- package/build/dist/UI/Components/Charts/ChartLibrary/AreaChart/AreaChart.js +213 -233
- package/build/dist/UI/Components/Charts/ChartLibrary/AreaChart/AreaChart.js.map +1 -1
- package/build/dist/UI/Components/Charts/ChartLibrary/BarChart/BarChart.js +139 -152
- package/build/dist/UI/Components/Charts/ChartLibrary/BarChart/BarChart.js.map +1 -1
- package/build/dist/UI/Components/Charts/ChartLibrary/LineChart/LineChart.js +212 -232
- package/build/dist/UI/Components/Charts/ChartLibrary/LineChart/LineChart.js.map +1 -1
- package/build/dist/UI/Components/Charts/Types/ChartEventKind.js +14 -0
- package/build/dist/UI/Components/Charts/Types/ChartEventKind.js.map +1 -0
- package/build/dist/UI/Components/Charts/Utils/TimeAnnotation.js +57 -28
- package/build/dist/UI/Components/Charts/Utils/TimeAnnotation.js.map +1 -1
- package/build/dist/UI/Components/Charts/Utils/XAxis.js +103 -17
- package/build/dist/UI/Components/Charts/Utils/XAxis.js.map +1 -1
- package/build/dist/UI/Components/EditionLabel/EditionLabel.js +198 -23
- package/build/dist/UI/Components/EditionLabel/EditionLabel.js.map +1 -1
- package/build/dist/UI/Components/ErrorMessage/ErrorMessage.js +15 -5
- package/build/dist/UI/Components/ErrorMessage/ErrorMessage.js.map +1 -1
- package/build/dist/UI/Components/Feed/FeedItem.js +4 -5
- package/build/dist/UI/Components/Feed/FeedItem.js.map +1 -1
- package/build/dist/UI/Components/Header/HeaderIconDropdownButton.js +1 -2
- package/build/dist/UI/Components/Header/HeaderIconDropdownButton.js.map +1 -1
- package/build/dist/UI/Components/Header/UserProfile/UserProfile.js.map +1 -1
- package/build/dist/UI/Components/Image/Image.js +6 -1
- package/build/dist/UI/Components/Image/Image.js.map +1 -1
- package/build/dist/UI/Components/Markdown.tsx/MarkdownConverters.js +0 -0
- package/build/dist/UI/Components/Markdown.tsx/MarkdownConverters.js.map +1 -1
- package/build/dist/UI/Components/MemberRoleAssignment/MemberRoleAssignment.js +1 -2
- package/build/dist/UI/Components/MemberRoleAssignment/MemberRoleAssignment.js.map +1 -1
- package/build/dist/UI/Components/ModelTable/BaseModelTable.js +104 -23
- package/build/dist/UI/Components/ModelTable/BaseModelTable.js.map +1 -1
- package/build/dist/UI/Components/Table/TableHeader.js +20 -22
- package/build/dist/UI/Components/Table/TableHeader.js.map +1 -1
- package/build/dist/UI/Components/Table/TableRow.js +13 -4
- package/build/dist/UI/Components/Table/TableRow.js.map +1 -1
- package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseSeats.js +153 -0
- package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseSeats.js.map +1 -0
- package/build/dist/Utils/NetworkDiscovery/AutoImportRuleMatcher.js.map +1 -1
- package/build/dist/Utils/NetworkDiscovery/DiscoveredDeviceBuilder.js +127 -7
- package/build/dist/Utils/NetworkDiscovery/DiscoveredDeviceBuilder.js.map +1 -1
- package/build/dist/Utils/NetworkDiscovery/DiscoveredHostUtil.js +50 -3
- package/build/dist/Utils/NetworkDiscovery/DiscoveredHostUtil.js.map +1 -1
- package/build/dist/Utils/NetworkDiscovery/ReverseDnsNameUtil.js +132 -0
- package/build/dist/Utils/NetworkDiscovery/ReverseDnsNameUtil.js.map +1 -0
- package/build/dist/Utils/Rules/RuleEngineLimits.js +31 -0
- package/build/dist/Utils/Rules/RuleEngineLimits.js.map +1 -0
- package/jest.config.json +1 -0
- package/package.json +2 -2
|
@@ -0,0 +1,882 @@
|
|
|
1
|
+
import {
|
|
2
|
+
MAX_REVERSE_DNS_LABEL_LENGTH,
|
|
3
|
+
MAX_REVERSE_DNS_NAME_LENGTH,
|
|
4
|
+
normalizeReverseDnsName,
|
|
5
|
+
} from "../../../Utils/NetworkDiscovery/ReverseDnsNameUtil";
|
|
6
|
+
import Slug from "../../../Utils/Slug";
|
|
7
|
+
import { describe, expect, it } from "@jest/globals";
|
|
8
|
+
|
|
9
|
+
/*
|
|
10
|
+
* OneUptime issue #3529 — discovery results should carry the reverse-DNS name
|
|
11
|
+
* of each host, not just its address.
|
|
12
|
+
*
|
|
13
|
+
* This is the gate on the ONE field in a scan result whose value is chosen by
|
|
14
|
+
* the scanned network rather than by OneUptime or by the operator. A PTR
|
|
15
|
+
* record is published by whoever runs DNS for the subnet being swept, and a
|
|
16
|
+
* discovery scan is routinely pointed at a subnet this project does not
|
|
17
|
+
* administer — so what comes back is untrusted input that goes on to become a
|
|
18
|
+
* rendered line in the Review dialog, a NetworkDevice's name, and that
|
|
19
|
+
* device's slug.
|
|
20
|
+
*
|
|
21
|
+
* The suite therefore has two halves that pull in opposite directions, and
|
|
22
|
+
* both matter:
|
|
23
|
+
*
|
|
24
|
+
* - Real names must survive. A rule that is too strict silently drops the
|
|
25
|
+
* very names the issue asked for, and does it invisibly: the operator
|
|
26
|
+
* sees the address they always saw and has no way to tell "no PTR record"
|
|
27
|
+
* from "we threw your PTR record away". Underscores, single labels,
|
|
28
|
+
* dashes-with-digits, a purely numeric label sitting next to alphabetic
|
|
29
|
+
* ones, and long FQDNs are all real, and all pass.
|
|
30
|
+
* - Everything that is not a hostname must not. Whitespace, quotes, angle
|
|
31
|
+
* brackets, control characters, non-ASCII and over-length values are what
|
|
32
|
+
* a hostile or broken reverse zone answers with, and they must never
|
|
33
|
+
* reach a name column.
|
|
34
|
+
*
|
|
35
|
+
* The two rules that are written as a quantifier over labels — "reject when
|
|
36
|
+
* EVERY label is numeric" and "reject when the name ends AT A LABEL BOUNDARY
|
|
37
|
+
* with a reverse-lookup zone" — are the ones where a one-token edit (`every`
|
|
38
|
+
* to `some`, `.${zone}` to `zone`) turns a narrow rejection into a broad one
|
|
39
|
+
* and deletes real names without a single error surfacing anywhere. Those two
|
|
40
|
+
* survive-directions have describe blocks of their own below.
|
|
41
|
+
*
|
|
42
|
+
* Every non-printing and non-ASCII character in this file is written as a
|
|
43
|
+
* \uXXXX escape rather than pasted literally. The whole point of several of
|
|
44
|
+
* these cases is that the character is INVISIBLE — a literal NUL, zero-width
|
|
45
|
+
* joiner or right-to-left override in the source is unreviewable in a diff,
|
|
46
|
+
* survives a careless copy-paste into the source it is meant to guard, and is
|
|
47
|
+
* mangled by tooling that normalises text. The escape is the test.
|
|
48
|
+
*/
|
|
49
|
+
|
|
50
|
+
describe("normalizeReverseDnsName — names that must survive", () => {
|
|
51
|
+
it("accepts an ordinary FQDN", () => {
|
|
52
|
+
expect(normalizeReverseDnsName("core-switch-01.corp.example.com")).toBe(
|
|
53
|
+
"core-switch-01.corp.example.com",
|
|
54
|
+
);
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
it("accepts a single-label name", () => {
|
|
58
|
+
/*
|
|
59
|
+
* Flat internal zones and small networks publish bare names, and
|
|
60
|
+
* "printer-3" is a strictly better answer for the Review dialog than
|
|
61
|
+
* 10.18.166.51. Rejecting single labels would throw those away.
|
|
62
|
+
*/
|
|
63
|
+
expect(normalizeReverseDnsName("printer-3")).toBe("printer-3");
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it("accepts underscores, which are illegal in a hostname but common in the wild", () => {
|
|
67
|
+
/*
|
|
68
|
+
* Windows/DHCP-registered names and hand-authored reverse zones use them
|
|
69
|
+
* constantly. The rule here is "is this safe to store and render", not
|
|
70
|
+
* "does this satisfy RFC 952".
|
|
71
|
+
*/
|
|
72
|
+
expect(normalizeReverseDnsName("ws_finance_12.corp.example.com")).toBe(
|
|
73
|
+
"ws_finance_12.corp.example.com",
|
|
74
|
+
);
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
it("accepts a generated name built out of the address's octets", () => {
|
|
78
|
+
/*
|
|
79
|
+
* NOT all-numeric — the octets are joined by dashes into one label — so
|
|
80
|
+
* this is a real name that happens to encode the address, and it carries
|
|
81
|
+
* the zone it lives in. It is more useful than the bare address.
|
|
82
|
+
*/
|
|
83
|
+
expect(normalizeReverseDnsName("10-18-166-51.dhcp.corp.example.com")).toBe(
|
|
84
|
+
"10-18-166-51.dhcp.corp.example.com",
|
|
85
|
+
);
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
it("strips exactly one trailing root dot", () => {
|
|
89
|
+
expect(normalizeReverseDnsName("host.example.com.")).toBe(
|
|
90
|
+
"host.example.com",
|
|
91
|
+
);
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
it("trims surrounding whitespace", () => {
|
|
95
|
+
expect(normalizeReverseDnsName(" host.example.com ")).toBe(
|
|
96
|
+
"host.example.com",
|
|
97
|
+
);
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
it("preserves case as the reverse zone authored it", () => {
|
|
101
|
+
/*
|
|
102
|
+
* DNS is case-insensitive, which is a reason not to COMPARE on case — not
|
|
103
|
+
* a reason to discard it. "SW-Core-01" is how somebody wrote it down, and
|
|
104
|
+
* that is as close to operator intent as this data gets.
|
|
105
|
+
*/
|
|
106
|
+
expect(normalizeReverseDnsName("SW-Core-01.Corp.Example.COM")).toBe(
|
|
107
|
+
"SW-Core-01.Corp.Example.COM",
|
|
108
|
+
);
|
|
109
|
+
});
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
describe("normalizeReverseDnsName — a numeric label beside alphabetic ones", () => {
|
|
113
|
+
/*
|
|
114
|
+
* The single most load-bearing acceptance in the file, and the one the rest
|
|
115
|
+
* of the suite could not see.
|
|
116
|
+
*
|
|
117
|
+
* The address-restating rule is "reject when EVERY label is numeric". Its
|
|
118
|
+
* rejection direction is pinned three times over ("10.18.166.51", "51",
|
|
119
|
+
* "10.18"). Its SURVIVE direction — a name that merely CONTAINS an
|
|
120
|
+
* all-digit label — had no case at all, so rewriting
|
|
121
|
+
* `labels.every(isNumeric)` as `labels.some(isNumeric)` left the whole
|
|
122
|
+
* suite green while deleting exactly the names issue #3529 is about: a
|
|
123
|
+
* reverse zone that publishes each host as `<last octet>.<zone>`, so hosts
|
|
124
|
+
* .51, .53, .54 and .55 answer "51.corp.example.com" and friends. Under the
|
|
125
|
+
* `some` mutation every one of those hosts silently loses its name and the
|
|
126
|
+
* operator sees the addresses they always saw, with nothing logged.
|
|
127
|
+
*
|
|
128
|
+
* These cases fail under that mutation and pass under the real rule, which
|
|
129
|
+
* is the whole reason they are here.
|
|
130
|
+
*/
|
|
131
|
+
|
|
132
|
+
it("accepts a name whose leading label is purely numeric", () => {
|
|
133
|
+
/*
|
|
134
|
+
* The canonical shape from the issue: the PTR for 10.18.166.51 in a zone
|
|
135
|
+
* that names hosts by octet. It is not the address restated — "corp" and
|
|
136
|
+
* "example" and "com" are not digits — so it is a real name and must be
|
|
137
|
+
* kept.
|
|
138
|
+
*/
|
|
139
|
+
expect(normalizeReverseDnsName("51.corp.example.com")).toBe(
|
|
140
|
+
"51.corp.example.com",
|
|
141
|
+
);
|
|
142
|
+
expect(normalizeReverseDnsName("10.corp.example.com")).toBe(
|
|
143
|
+
"10.corp.example.com",
|
|
144
|
+
);
|
|
145
|
+
|
|
146
|
+
/*
|
|
147
|
+
* "0.pool.ntp.org" is the real-world one: a leading zero, a single digit,
|
|
148
|
+
* and a name millions of hosts genuinely resolve to. If a numeric label
|
|
149
|
+
* anywhere were disqualifying, this would come back undefined.
|
|
150
|
+
*/
|
|
151
|
+
expect(normalizeReverseDnsName("0.pool.ntp.org")).toBe("0.pool.ntp.org");
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
it("accepts a numeric label in an interior or trailing position", () => {
|
|
155
|
+
/*
|
|
156
|
+
* Position must not matter either — the rule is a quantifier over ALL
|
|
157
|
+
* labels, not an inspection of the first one. A rule written as "reject
|
|
158
|
+
* if the first label is numeric" would pass the case above's mutation
|
|
159
|
+
* test but fail here, so both shapes are pinned.
|
|
160
|
+
*/
|
|
161
|
+
expect(normalizeReverseDnsName("gw.51.example.com")).toBe(
|
|
162
|
+
"gw.51.example.com",
|
|
163
|
+
);
|
|
164
|
+
expect(normalizeReverseDnsName("printer.3")).toBe("printer.3");
|
|
165
|
+
expect(normalizeReverseDnsName("a.1")).toBe("a.1");
|
|
166
|
+
});
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
describe("normalizeReverseDnsName — length boundaries", () => {
|
|
170
|
+
/*
|
|
171
|
+
* These are the off-by-one seams in the function, pinned on both sides.
|
|
172
|
+
* Each one is a place where a "<" that should be "<=" either silently
|
|
173
|
+
* discards a legitimate long FQDN (the failure nobody notices, because the
|
|
174
|
+
* dialog just shows the address it always showed) or lets an over-length
|
|
175
|
+
* value through into a varchar column.
|
|
176
|
+
*/
|
|
177
|
+
|
|
178
|
+
const LABEL_AT_LIMIT: string = "a".repeat(MAX_REVERSE_DNS_LABEL_LENGTH);
|
|
179
|
+
|
|
180
|
+
/*
|
|
181
|
+
* 3 * 63 + 3 separators + 61 = 253. Built out of maximum-length labels so
|
|
182
|
+
* the per-label rule cannot be what decides any of the whole-name cases
|
|
183
|
+
* below — only the whole-name limit can. Note that this arithmetic is
|
|
184
|
+
* load-bearing on MAX_REVERSE_DNS_LABEL_LENGTH staying 63: the
|
|
185
|
+
* `toHaveLength` assertions below are what re-derive both constants, so a
|
|
186
|
+
* change to either number turns this block red rather than silently
|
|
187
|
+
* shifting what "at the limit" means.
|
|
188
|
+
*/
|
|
189
|
+
const NAME_AT_LIMIT: string = `${LABEL_AT_LIMIT}.${LABEL_AT_LIMIT}.${LABEL_AT_LIMIT}.${"b".repeat(61)}`;
|
|
190
|
+
|
|
191
|
+
it("accepts a label of exactly the maximum length and rejects one character more", () => {
|
|
192
|
+
expect(LABEL_AT_LIMIT).toHaveLength(63);
|
|
193
|
+
expect(normalizeReverseDnsName(`${LABEL_AT_LIMIT}.example.com`)).toBe(
|
|
194
|
+
`${LABEL_AT_LIMIT}.example.com`,
|
|
195
|
+
);
|
|
196
|
+
|
|
197
|
+
const overLimit: string = "a".repeat(MAX_REVERSE_DNS_LABEL_LENGTH + 1);
|
|
198
|
+
expect(normalizeReverseDnsName(`${overLimit}.example.com`)).toBeUndefined();
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
it("accepts a name that is one label of exactly the maximum length", () => {
|
|
202
|
+
/*
|
|
203
|
+
* The label limit and the name limit are different numbers, and a single
|
|
204
|
+
* maximal label exercises both at once: it must be judged by the label
|
|
205
|
+
* rule (63) and pass the name rule (253) without either being applied to
|
|
206
|
+
* the other's value.
|
|
207
|
+
*/
|
|
208
|
+
expect(normalizeReverseDnsName(LABEL_AT_LIMIT)).toBe(LABEL_AT_LIMIT);
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
it("accepts a name of exactly the maximum length and rejects one character more", () => {
|
|
212
|
+
expect(NAME_AT_LIMIT).toHaveLength(MAX_REVERSE_DNS_NAME_LENGTH);
|
|
213
|
+
expect(normalizeReverseDnsName(NAME_AT_LIMIT)).toBe(NAME_AT_LIMIT);
|
|
214
|
+
|
|
215
|
+
const overLimit: string = `${LABEL_AT_LIMIT}.${LABEL_AT_LIMIT}.${LABEL_AT_LIMIT}.${"b".repeat(62)}`;
|
|
216
|
+
expect(overLimit).toHaveLength(MAX_REVERSE_DNS_NAME_LENGTH + 1);
|
|
217
|
+
expect(normalizeReverseDnsName(overLimit)).toBeUndefined();
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
it("accepts a name whose trailing dot is what pushes it over the limit", () => {
|
|
221
|
+
/*
|
|
222
|
+
* The root label is not part of the name, so a 253-character name written
|
|
223
|
+
* fully qualified is 254 characters of INPUT and must still be accepted.
|
|
224
|
+
* Measuring before stripping would reject it — and the resolvers that
|
|
225
|
+
* emit fully qualified answers are exactly the well-run ones whose names
|
|
226
|
+
* are worth having.
|
|
227
|
+
*/
|
|
228
|
+
expect(`${NAME_AT_LIMIT}.`).toHaveLength(MAX_REVERSE_DNS_NAME_LENGTH + 1);
|
|
229
|
+
expect(normalizeReverseDnsName(`${NAME_AT_LIMIT}.`)).toBe(NAME_AT_LIMIT);
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
it("trims before it strips the root label and before it measures", () => {
|
|
233
|
+
/*
|
|
234
|
+
* The two orderings the cases above leave open, pinned in one input.
|
|
235
|
+
* " <253 chars>. " is 258 characters of raw input, and it is the answer
|
|
236
|
+
* a well-run resolver's fully qualified reply looks like once it has been
|
|
237
|
+
* through a text field or a log line that padded it.
|
|
238
|
+
*
|
|
239
|
+
* Reasoned against the mutated implementations:
|
|
240
|
+
* - measure-then-trim: 258 > 253, rejected, name silently lost.
|
|
241
|
+
* - strip-root-then-trim: the raw value ends in a SPACE, so nothing is
|
|
242
|
+
* stripped; after trimming, the trailing dot survives into the label
|
|
243
|
+
* split as an empty final label, and the name is rejected.
|
|
244
|
+
* Only trim -> strip -> measure returns NAME_AT_LIMIT, so this case dies
|
|
245
|
+
* under either reordering.
|
|
246
|
+
*
|
|
247
|
+
* It also pins the returned value byte-for-byte at the maximum length:
|
|
248
|
+
* what comes back is the trimmed, root-stripped INPUT, unmodified and
|
|
249
|
+
* untruncated.
|
|
250
|
+
*/
|
|
251
|
+
const padded: string = ` ${NAME_AT_LIMIT}. `;
|
|
252
|
+
expect(padded).toHaveLength(MAX_REVERSE_DNS_NAME_LENGTH + 5);
|
|
253
|
+
expect(normalizeReverseDnsName(padded)).toBe(NAME_AT_LIMIT);
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
it("rejects an absurdly long value made entirely of legal labels", () => {
|
|
257
|
+
/*
|
|
258
|
+
* Ten thousand characters in which EVERY label is a legal two-character
|
|
259
|
+
* label, so the per-label rule has nothing to object to and the whole-name
|
|
260
|
+
* limit is the only thing that can reject it. Delete the
|
|
261
|
+
* MAX_REVERSE_DNS_NAME_LENGTH check and this value is accepted — a
|
|
262
|
+
* ten-thousand-character "hostname" on its way to a varchar(100) column.
|
|
263
|
+
*
|
|
264
|
+
* (Its earlier form, "a".repeat(10000), was a single 10,000-character
|
|
265
|
+
* label and so was rejected by the 63-character label rule first; it
|
|
266
|
+
* could not fail if the name limit were removed, which is the point of
|
|
267
|
+
* building this one out of legal labels instead.)
|
|
268
|
+
*/
|
|
269
|
+
const legalLabelsOverLimit: string = "ab.".repeat(3334);
|
|
270
|
+
expect(legalLabelsOverLimit.length).toBeGreaterThan(
|
|
271
|
+
MAX_REVERSE_DNS_NAME_LENGTH,
|
|
272
|
+
);
|
|
273
|
+
expect(normalizeReverseDnsName(legalLabelsOverLimit)).toBeUndefined();
|
|
274
|
+
});
|
|
275
|
+
});
|
|
276
|
+
|
|
277
|
+
describe("normalizeReverseDnsName — answers that restate the address", () => {
|
|
278
|
+
/*
|
|
279
|
+
* The entire premise of the feature is that a name tells the operator more
|
|
280
|
+
* than an address does. A "name" that IS the address is not a name — and
|
|
281
|
+
* worse, presenting it as one asserts a resolved hostname that nobody
|
|
282
|
+
* published. These must fall through so the caller uses the address it
|
|
283
|
+
* already had.
|
|
284
|
+
*
|
|
285
|
+
* The complement — a numeric label that sits BESIDE alphabetic ones and
|
|
286
|
+
* must survive — is its own describe block above; neither half of the rule
|
|
287
|
+
* is safe without the other.
|
|
288
|
+
*/
|
|
289
|
+
|
|
290
|
+
it("rejects a dotted-quad", () => {
|
|
291
|
+
expect(normalizeReverseDnsName("10.18.166.51")).toBeUndefined();
|
|
292
|
+
});
|
|
293
|
+
|
|
294
|
+
it("rejects a single numeric label", () => {
|
|
295
|
+
expect(normalizeReverseDnsName("51")).toBeUndefined();
|
|
296
|
+
});
|
|
297
|
+
|
|
298
|
+
it("rejects a partially numeric answer with no alphabetic label", () => {
|
|
299
|
+
expect(normalizeReverseDnsName("10.18")).toBeUndefined();
|
|
300
|
+
});
|
|
301
|
+
|
|
302
|
+
it("rejects an in-addr.arpa query name echoed back", () => {
|
|
303
|
+
/*
|
|
304
|
+
* Some resolvers hand the query name back on certain failures. It passes
|
|
305
|
+
* every character rule and is a strictly worse label than the address it
|
|
306
|
+
* was derived from.
|
|
307
|
+
*/
|
|
308
|
+
expect(
|
|
309
|
+
normalizeReverseDnsName("51.166.18.10.in-addr.arpa"),
|
|
310
|
+
).toBeUndefined();
|
|
311
|
+
expect(
|
|
312
|
+
normalizeReverseDnsName("51.166.18.10.IN-ADDR.ARPA."),
|
|
313
|
+
).toBeUndefined();
|
|
314
|
+
});
|
|
315
|
+
|
|
316
|
+
it("rejects an ip6.arpa query name echoed back", () => {
|
|
317
|
+
expect(
|
|
318
|
+
normalizeReverseDnsName(
|
|
319
|
+
"1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2.ip6.arpa",
|
|
320
|
+
),
|
|
321
|
+
).toBeUndefined();
|
|
322
|
+
});
|
|
323
|
+
});
|
|
324
|
+
|
|
325
|
+
describe("normalizeReverseDnsName — the reverse zones as an apex", () => {
|
|
326
|
+
/*
|
|
327
|
+
* The suffix rule alone left a hole: a resolver that echoes a TRUNCATED
|
|
328
|
+
* query name, or a zone whose PTR points at the zone apex itself, answers
|
|
329
|
+
* with the bare zone. "in-addr.arpa" is a perfectly well-formed hostname
|
|
330
|
+
* string — right charset, right label lengths, not all-numeric — so
|
|
331
|
+
* everything else in this function waves it through, and the operator gets
|
|
332
|
+
* a fleet of devices all called "in-addr.arpa" instead of their addresses.
|
|
333
|
+
* That is why the check is `lowerCased === zone` as well as `endsWith`.
|
|
334
|
+
*/
|
|
335
|
+
|
|
336
|
+
it("rejects the bare in-addr.arpa apex", () => {
|
|
337
|
+
expect(normalizeReverseDnsName("in-addr.arpa")).toBeUndefined();
|
|
338
|
+
});
|
|
339
|
+
|
|
340
|
+
it("rejects the bare ip6.arpa apex", () => {
|
|
341
|
+
expect(normalizeReverseDnsName("ip6.arpa")).toBeUndefined();
|
|
342
|
+
});
|
|
343
|
+
|
|
344
|
+
it("rejects the apex with a trailing root dot, in any case", () => {
|
|
345
|
+
/*
|
|
346
|
+
* Two orderings in one case, because the separate lower-case-with-dot
|
|
347
|
+
* test was fully contained in this one's inputs and pinned nothing extra.
|
|
348
|
+
*
|
|
349
|
+
* Root-dot ordering: the apex comparison runs AFTER the root label is
|
|
350
|
+
* stripped. Reversed, "in-addr.arpa." would match neither the apex (extra
|
|
351
|
+
* dot) nor the suffix (nothing before it) and would sail through.
|
|
352
|
+
*
|
|
353
|
+
* Case ordering: DNS is case-insensitive and resolvers echo whatever case
|
|
354
|
+
* they were handed — 0x20 query randomisation makes mixed case the NORMAL
|
|
355
|
+
* shape of an echoed name, not an exotic one. Comparing the raw string
|
|
356
|
+
* would accept "In-Addr.ARPA"; lower-casing the value but not comparing
|
|
357
|
+
* against a lower-case zone would reject everything.
|
|
358
|
+
*/
|
|
359
|
+
expect(normalizeReverseDnsName("in-addr.arpa.")).toBeUndefined();
|
|
360
|
+
expect(normalizeReverseDnsName("ip6.arpa.")).toBeUndefined();
|
|
361
|
+
expect(normalizeReverseDnsName("IN-ADDR.ARPA")).toBeUndefined();
|
|
362
|
+
expect(normalizeReverseDnsName("In-Addr.Arpa")).toBeUndefined();
|
|
363
|
+
expect(normalizeReverseDnsName("iN-aDdR.aRpA.")).toBeUndefined();
|
|
364
|
+
expect(normalizeReverseDnsName("IP6.ARPA")).toBeUndefined();
|
|
365
|
+
expect(normalizeReverseDnsName("Ip6.Arpa.")).toBeUndefined();
|
|
366
|
+
});
|
|
367
|
+
|
|
368
|
+
it("keeps a real name that merely CONTAINS arpa", () => {
|
|
369
|
+
// The suffix rule must be a suffix rule, not a substring rule.
|
|
370
|
+
expect(normalizeReverseDnsName("arpa-gw.example.com")).toBe(
|
|
371
|
+
"arpa-gw.example.com",
|
|
372
|
+
);
|
|
373
|
+
expect(normalizeReverseDnsName("in-addr.arpa.example.com")).toBe(
|
|
374
|
+
"in-addr.arpa.example.com",
|
|
375
|
+
);
|
|
376
|
+
});
|
|
377
|
+
|
|
378
|
+
it("matches the zone at a label boundary, not as a bare string suffix", () => {
|
|
379
|
+
/*
|
|
380
|
+
* The other half of "it is a suffix rule", and the one the CONTAINS cases
|
|
381
|
+
* above could not see. Every accepted arpa name in this file
|
|
382
|
+
* ("arpa-gw.example.com", "in-addr.arpa.example.com",
|
|
383
|
+
* "gw.arpa.example.com", "something.arpa") ends somewhere OTHER than the
|
|
384
|
+
* zone string, so rewriting `lowerCased.endsWith(`.${zone}`)` as
|
|
385
|
+
* `lowerCased.endsWith(zone)` — dropping one character — survived the
|
|
386
|
+
* entire suite.
|
|
387
|
+
*
|
|
388
|
+
* Under that mutation "notin-addr.arpa" and "voip6.arpa" are rejected:
|
|
389
|
+
* both end with the zone's characters while their final labels are
|
|
390
|
+
* "notin-addr" and "voip6", which are somebody's real hostnames and are
|
|
391
|
+
* nothing to do with a reverse-lookup zone. The dot is what makes the
|
|
392
|
+
* difference between "this name lives IN the zone" and "this name happens
|
|
393
|
+
* to end with those letters", so it is asserted here.
|
|
394
|
+
*/
|
|
395
|
+
expect(normalizeReverseDnsName("notin-addr.arpa")).toBe("notin-addr.arpa");
|
|
396
|
+
expect(normalizeReverseDnsName("voip6.arpa")).toBe("voip6.arpa");
|
|
397
|
+
expect(normalizeReverseDnsName("myip6.arpa")).toBe("myip6.arpa");
|
|
398
|
+
|
|
399
|
+
/*
|
|
400
|
+
* ...while the genuine label-boundary forms of the same strings stay
|
|
401
|
+
* rejected, so the case above cannot be satisfied by deleting the zone
|
|
402
|
+
* rule outright.
|
|
403
|
+
*/
|
|
404
|
+
expect(normalizeReverseDnsName("x.in-addr.arpa")).toBeUndefined();
|
|
405
|
+
expect(normalizeReverseDnsName("x.ip6.arpa")).toBeUndefined();
|
|
406
|
+
});
|
|
407
|
+
|
|
408
|
+
it("keeps a name with an interior or trailing label called arpa", () => {
|
|
409
|
+
/*
|
|
410
|
+
* ACCEPTED, deliberately, and this is the line the apex check must not
|
|
411
|
+
* cross. The rule targets the two REVERSE-LOOKUP zones, not the .arpa
|
|
412
|
+
* TLD: `arpa` is a real, delegated top-level domain, and "gw.arpa" or
|
|
413
|
+
* "gw.arpa.example.com" is a name somebody published on purpose. It is
|
|
414
|
+
* still a better label for the Review dialog than 10.18.166.51, which is
|
|
415
|
+
* the only thing the operator would otherwise see.
|
|
416
|
+
*
|
|
417
|
+
* Widening the check to "ends in .arpa" would silently delete these — the
|
|
418
|
+
* exact invisible over-rejection this suite exists to prevent — and would
|
|
419
|
+
* buy nothing, because the harm is specific to the two zones whose names
|
|
420
|
+
* merely restate the address.
|
|
421
|
+
*/
|
|
422
|
+
expect(normalizeReverseDnsName("gw.arpa.example.com")).toBe(
|
|
423
|
+
"gw.arpa.example.com",
|
|
424
|
+
);
|
|
425
|
+
expect(normalizeReverseDnsName("something.arpa")).toBe("something.arpa");
|
|
426
|
+
});
|
|
427
|
+
});
|
|
428
|
+
|
|
429
|
+
describe("normalizeReverseDnsName — values that are not names at all", () => {
|
|
430
|
+
it("rejects empty and whitespace-only input", () => {
|
|
431
|
+
expect(normalizeReverseDnsName("")).toBeUndefined();
|
|
432
|
+
expect(normalizeReverseDnsName(" ")).toBeUndefined();
|
|
433
|
+
expect(normalizeReverseDnsName("\t\n")).toBeUndefined();
|
|
434
|
+
});
|
|
435
|
+
|
|
436
|
+
it("rejects a bare root label", () => {
|
|
437
|
+
expect(normalizeReverseDnsName(".")).toBeUndefined();
|
|
438
|
+
});
|
|
439
|
+
|
|
440
|
+
it("rejects empty labels", () => {
|
|
441
|
+
/*
|
|
442
|
+
* Only ONE trailing dot is the root label. A second leaves an empty final
|
|
443
|
+
* label, which is malformed rather than a typo to repair — inventing the
|
|
444
|
+
* repair would be inventing a name.
|
|
445
|
+
*/
|
|
446
|
+
expect(normalizeReverseDnsName("host.example.com..")).toBeUndefined();
|
|
447
|
+
expect(normalizeReverseDnsName("host..example.com")).toBeUndefined();
|
|
448
|
+
expect(normalizeReverseDnsName(".host.example.com")).toBeUndefined();
|
|
449
|
+
});
|
|
450
|
+
|
|
451
|
+
it("rejects a leading or trailing hyphen in a label", () => {
|
|
452
|
+
expect(normalizeReverseDnsName("-host.example.com")).toBeUndefined();
|
|
453
|
+
expect(normalizeReverseDnsName("host-.example.com")).toBeUndefined();
|
|
454
|
+
});
|
|
455
|
+
|
|
456
|
+
it("rejects whitespace inside the name", () => {
|
|
457
|
+
/*
|
|
458
|
+
* " " is truthy, and a name with a space in it renders as a plausible
|
|
459
|
+
* device name and slugifies into something else entirely. This is the
|
|
460
|
+
* same class of bug normalizeDiscoveredHosts fixed for ipAddress.
|
|
461
|
+
*/
|
|
462
|
+
expect(normalizeReverseDnsName("core switch.example.com")).toBeUndefined();
|
|
463
|
+
expect(normalizeReverseDnsName("host.example .com")).toBeUndefined();
|
|
464
|
+
});
|
|
465
|
+
|
|
466
|
+
it("rejects markup, quotes and path characters", () => {
|
|
467
|
+
/*
|
|
468
|
+
* React escapes on render, so this is not an XSS test — it is a "this was
|
|
469
|
+
* never a hostname" test. A reverse zone that answers with any of these
|
|
470
|
+
* is broken or hostile, and either way the address is the better answer.
|
|
471
|
+
*/
|
|
472
|
+
const hostile: Array<string> = [
|
|
473
|
+
"<script>alert(1)</script>",
|
|
474
|
+
'"><img src=x onerror=alert(1)>',
|
|
475
|
+
"host.example.com/../../etc/passwd",
|
|
476
|
+
"host.example.com:8080",
|
|
477
|
+
"host@example.com",
|
|
478
|
+
"host;rm -rf /",
|
|
479
|
+
"host,example,com",
|
|
480
|
+
"host\\example",
|
|
481
|
+
"host%00.example.com",
|
|
482
|
+
"host|example.com",
|
|
483
|
+
"$(whoami).example.com",
|
|
484
|
+
"{{constructor}}.example.com",
|
|
485
|
+
];
|
|
486
|
+
|
|
487
|
+
for (const value of hostile) {
|
|
488
|
+
expect(normalizeReverseDnsName(value)).toBeUndefined();
|
|
489
|
+
}
|
|
490
|
+
});
|
|
491
|
+
|
|
492
|
+
it("rejects control characters, including ones that survive a trim", () => {
|
|
493
|
+
/*
|
|
494
|
+
* trim() only removes whitespace at the ENDS, so an interior control
|
|
495
|
+
* character reaches the charset check or nothing does. A newline puts a
|
|
496
|
+
* second line into a name column and into the Review dialog row; a NUL
|
|
497
|
+
* truncates the value in anything that reaches a C string boundary
|
|
498
|
+
* (Postgres rejects it outright in a text column, failing the import);
|
|
499
|
+
* ESC starts a terminal escape sequence in probe and server logs, which
|
|
500
|
+
* is where an operator reads these names back.
|
|
501
|
+
*
|
|
502
|
+
* Written as escapes on purpose — see the file header.
|
|
503
|
+
*/
|
|
504
|
+
expect(normalizeReverseDnsName("host\n.example.com")).toBeUndefined();
|
|
505
|
+
expect(normalizeReverseDnsName("host\r\n.example.com")).toBeUndefined();
|
|
506
|
+
// U+0000 NUL.
|
|
507
|
+
expect(normalizeReverseDnsName("host.exa\u0000mple.com")).toBeUndefined();
|
|
508
|
+
// U+001B ESC — the lead byte of an ANSI terminal escape sequence.
|
|
509
|
+
expect(normalizeReverseDnsName("host.exa\u001Bmple.com")).toBeUndefined();
|
|
510
|
+
// U+007F DEL.
|
|
511
|
+
expect(normalizeReverseDnsName("host\u007F.example.com")).toBeUndefined();
|
|
512
|
+
});
|
|
513
|
+
|
|
514
|
+
it("rejects non-ASCII, including homoglyphs of a legitimate name", () => {
|
|
515
|
+
/*
|
|
516
|
+
* Punycode ("xn--...") is the encoding a real internationalised name
|
|
517
|
+
* arrives in and is pure ASCII, so rejecting non-ASCII rejects nothing a
|
|
518
|
+
* resolver would actually answer with.
|
|
519
|
+
*/
|
|
520
|
+
// U+0441 CYRILLIC SMALL LETTER ES — renders identically to Latin "c".
|
|
521
|
+
expect(
|
|
522
|
+
normalizeReverseDnsName("\u0441ore-switch.example.com"),
|
|
523
|
+
).toBeUndefined();
|
|
524
|
+
// U+00F4 LATIN SMALL LETTER O WITH CIRCUMFLEX.
|
|
525
|
+
expect(normalizeReverseDnsName("h\u00F4te.example.com")).toBeUndefined();
|
|
526
|
+
// U+200B ZERO WIDTH SPACE — invisible, and not stripped by trim().
|
|
527
|
+
expect(normalizeReverseDnsName("router\u200B.example.com")).toBeUndefined();
|
|
528
|
+
// ...while the punycode form of the same idea is fine.
|
|
529
|
+
expect(normalizeReverseDnsName("xn--hte-snab.example.com")).toBe(
|
|
530
|
+
"xn--hte-snab.example.com",
|
|
531
|
+
);
|
|
532
|
+
});
|
|
533
|
+
|
|
534
|
+
it("rejects unicode that renders as ASCII to a human reading the dialog", () => {
|
|
535
|
+
/*
|
|
536
|
+
* This is the class the charset rule exists for. Every one of these
|
|
537
|
+
* renders in the Review dialog as something the operator would read as an
|
|
538
|
+
* ordinary hostname, while being a different string underneath — so an
|
|
539
|
+
* operator ticking "core-switch" cannot be shown a device that is not it.
|
|
540
|
+
* A blocklist of "suspicious" codepoints would be an arms race; the
|
|
541
|
+
* ASCII-only rule ends it, and costs nothing because PTR answers are
|
|
542
|
+
* ASCII on the wire.
|
|
543
|
+
*/
|
|
544
|
+
// U+FF48 U+FF4F U+FF53 U+FF54 — FULLWIDTH h, o, s, t.
|
|
545
|
+
expect(
|
|
546
|
+
normalizeReverseDnsName("\uFF48\uFF4F\uFF53\uFF54.example.com"),
|
|
547
|
+
).toBeUndefined();
|
|
548
|
+
// U+0430 CYRILLIC SMALL LETTER A inside an otherwise Latin word.
|
|
549
|
+
expect(normalizeReverseDnsName("g\u0430teway.example.com")).toBeUndefined();
|
|
550
|
+
// U+200D ZERO WIDTH JOINER — invisible, and splits a word for search.
|
|
551
|
+
expect(
|
|
552
|
+
normalizeReverseDnsName("core\u200Dswitch.example.com"),
|
|
553
|
+
).toBeUndefined();
|
|
554
|
+
// U+202E RIGHT-TO-LEFT OVERRIDE — reverses everything rendered after it.
|
|
555
|
+
expect(
|
|
556
|
+
normalizeReverseDnsName("host\u202Emoc.elpmaxe.example.com"),
|
|
557
|
+
).toBeUndefined();
|
|
558
|
+
/*
|
|
559
|
+
* U+FEFF ZERO WIDTH NO-BREAK SPACE (BOM) in the middle, where trim() is
|
|
560
|
+
* no help.
|
|
561
|
+
*/
|
|
562
|
+
expect(
|
|
563
|
+
normalizeReverseDnsName("host\uFEFFname.example.com"),
|
|
564
|
+
).toBeUndefined();
|
|
565
|
+
});
|
|
566
|
+
});
|
|
567
|
+
|
|
568
|
+
describe("normalizeReverseDnsName — hostile-looking values that the charset allows", () => {
|
|
569
|
+
/*
|
|
570
|
+
* These pass every rule in the function, and that is the correct outcome:
|
|
571
|
+
* this gate decides "is this string shaped like a hostname", not "is this
|
|
572
|
+
* string a good idea". Pinning the acceptances matters as much as pinning
|
|
573
|
+
* the rejections, because each one is a place somebody might later be
|
|
574
|
+
* tempted to add a blocklist — and a blocklist here would silently delete
|
|
575
|
+
* real names while the actual defence lives where the value is USED.
|
|
576
|
+
*/
|
|
577
|
+
|
|
578
|
+
it("accepts a name that collides with a Review dialog badge", () => {
|
|
579
|
+
/*
|
|
580
|
+
* "Already-added" is the badge the dialog puts on a host that is already
|
|
581
|
+
* imported. A PTR record can legitimately say exactly that, and the
|
|
582
|
+
* function cannot tell the difference — nor should it try. The dialog
|
|
583
|
+
* must keep the badge distinguishable by POSITION (its own element),
|
|
584
|
+
* never by comparing it against the name text, and this case is the
|
|
585
|
+
* standing reminder that name text can be anything.
|
|
586
|
+
*/
|
|
587
|
+
expect(normalizeReverseDnsName("Already-added")).toBe("Already-added");
|
|
588
|
+
});
|
|
589
|
+
|
|
590
|
+
it("accepts a single label at the full 63 characters", () => {
|
|
591
|
+
/*
|
|
592
|
+
* Nothing here clamps for display — MAX_DEVICE_NAME_LENGTH (80) in
|
|
593
|
+
* DiscoveredDeviceBuilder and the `truncate` class in the dialog do that.
|
|
594
|
+
* If this function ever started truncating too, the displayed name and
|
|
595
|
+
* the created name would diverge, which is the bug the dialog was fixed
|
|
596
|
+
* to avoid.
|
|
597
|
+
*/
|
|
598
|
+
const longLabel: string =
|
|
599
|
+
"very-long-single-label-".repeat(2) + "a".repeat(17);
|
|
600
|
+
expect(longLabel).toHaveLength(MAX_REVERSE_DNS_LABEL_LENGTH);
|
|
601
|
+
expect(normalizeReverseDnsName(longLabel)).toBe(longLabel);
|
|
602
|
+
});
|
|
603
|
+
|
|
604
|
+
it("accepts a name of only underscores", () => {
|
|
605
|
+
/*
|
|
606
|
+
* Ugly, and real: an underscore is a legal first and last character here
|
|
607
|
+
* precisely because Windows/DHCP-registered names use them. "___" is not
|
|
608
|
+
* a value to invent a special rule for — it slugifies fine (see the slug
|
|
609
|
+
* suite below) and it is still a name somebody published.
|
|
610
|
+
*/
|
|
611
|
+
expect(normalizeReverseDnsName("___")).toBe("___");
|
|
612
|
+
expect(normalizeReverseDnsName("_")).toBe("_");
|
|
613
|
+
});
|
|
614
|
+
|
|
615
|
+
it("rejects a name of only hyphens", () => {
|
|
616
|
+
/*
|
|
617
|
+
* The mirror image of the underscore case, and it falls out of the
|
|
618
|
+
* "hyphen may not lead or trail" rule rather than a special case: with
|
|
619
|
+
* every character a hyphen, the first one always leads. Worth pinning
|
|
620
|
+
* because "-" and "--" are what a placeholder or a truncated answer looks
|
|
621
|
+
* like, and either would render as a device named nothing at all.
|
|
622
|
+
*/
|
|
623
|
+
expect(normalizeReverseDnsName("-")).toBeUndefined();
|
|
624
|
+
expect(normalizeReverseDnsName("--")).toBeUndefined();
|
|
625
|
+
expect(normalizeReverseDnsName("---")).toBeUndefined();
|
|
626
|
+
expect(normalizeReverseDnsName("-.-")).toBeUndefined();
|
|
627
|
+
});
|
|
628
|
+
|
|
629
|
+
it("treats prototype-shaped values as the ordinary strings they are", () => {
|
|
630
|
+
/*
|
|
631
|
+
* "__proto__", "constructor" and "prototype" are valid DNS labels and are
|
|
632
|
+
* returned verbatim. That is correct AND safe here for a specific reason:
|
|
633
|
+
* this function only ever tests and returns the VALUE, never uses it as
|
|
634
|
+
* an object key, so there is no lookup for a magic name to hijack — the
|
|
635
|
+
* string's destinations are a varchar column and a React text node.
|
|
636
|
+
*
|
|
637
|
+
* The assertion that matters is `toBe`: a returned "__proto__" must be
|
|
638
|
+
* that literal string. If a future implementation routed names through
|
|
639
|
+
* an object map (a cache keyed by name, say), "__proto__" would come back
|
|
640
|
+
* as something else entirely, and this case would catch it.
|
|
641
|
+
*
|
|
642
|
+
* There is deliberately no `typeof ... === "string"` assertion alongside:
|
|
643
|
+
* `toBe("__proto__")` already implies it, so the typeof line could not
|
|
644
|
+
* fail on its own and only made the case look broader than it was.
|
|
645
|
+
*/
|
|
646
|
+
expect(normalizeReverseDnsName("__proto__")).toBe("__proto__");
|
|
647
|
+
expect(normalizeReverseDnsName("constructor")).toBe("constructor");
|
|
648
|
+
expect(normalizeReverseDnsName("prototype.example.com")).toBe(
|
|
649
|
+
"prototype.example.com",
|
|
650
|
+
);
|
|
651
|
+
});
|
|
652
|
+
});
|
|
653
|
+
|
|
654
|
+
describe("normalizeReverseDnsName — accepted names are safe to slugify", () => {
|
|
655
|
+
/*
|
|
656
|
+
* NetworkDevice is @SlugifyColumn("name", "slug") with slug varchar(100),
|
|
657
|
+
* so every accepted name here becomes a URL segment without anyone looking
|
|
658
|
+
* at it again. Slug.getSlug strips [&*+~.,\\/()|'"!:@] — which includes the
|
|
659
|
+
* dot, the one character a hostname is made of — and then appends a
|
|
660
|
+
* ten-digit random suffix.
|
|
661
|
+
*
|
|
662
|
+
* The suffix is random but its SHAPE is not, and the regex below rests on
|
|
663
|
+
* that: Faker.getRandomNumbers(10) pushes ten digits each in 1..9 (never 0)
|
|
664
|
+
* and parses the joined string, so no leading zero can ever be dropped and
|
|
665
|
+
* the suffix is always exactly ten digits. Without that guarantee this
|
|
666
|
+
* suite would be intermittently red on roughly one run in ten.
|
|
667
|
+
*
|
|
668
|
+
* Because the suffix means getSlug's return value is never literally empty,
|
|
669
|
+
* a bare "is it non-empty" assertion would be unfalsifiable. So these cases
|
|
670
|
+
* assert on the NAME-DERIVED STEM: the slug must be more than the random
|
|
671
|
+
* suffix, AND it must still contain a recognisable piece of the name. A
|
|
672
|
+
* name that slugified away to nothing would give every such device a slug
|
|
673
|
+
* that is pure entropy, with no trace of what it names.
|
|
674
|
+
*/
|
|
675
|
+
|
|
676
|
+
/*
|
|
677
|
+
* [name, the lower-case fragment of it that must survive slugification].
|
|
678
|
+
* The fragment is what a human would use to recognise the device in a URL,
|
|
679
|
+
* and it is written out rather than derived so that a change in getSlug
|
|
680
|
+
* that quietly mangled names has something concrete to fail against.
|
|
681
|
+
*/
|
|
682
|
+
const acceptedNames: Array<[string, string]> = [
|
|
683
|
+
["core-switch-01.corp.example.com", "core-switch-01"],
|
|
684
|
+
["printer-3", "printer-3"],
|
|
685
|
+
["ws_finance_12.corp.example.com", "ws_finance_12"],
|
|
686
|
+
["10-18-166-51.dhcp.corp.example.com", "10-18-166-51"],
|
|
687
|
+
["SW-Core-01.Corp.Example.COM", "sw-core-01"],
|
|
688
|
+
["xn--hte-snab.example.com", "hte-snab"],
|
|
689
|
+
["Already-added", "already-added"],
|
|
690
|
+
["something.arpa", "somethingarpa"],
|
|
691
|
+
["51.corp.example.com", "51corpexamplecom"],
|
|
692
|
+
["notin-addr.arpa", "notin-addrarpa"],
|
|
693
|
+
["___", "___"],
|
|
694
|
+
["_", "_"],
|
|
695
|
+
["a.b", "ab"],
|
|
696
|
+
["a".repeat(MAX_REVERSE_DNS_LABEL_LENGTH), "a".repeat(20)],
|
|
697
|
+
];
|
|
698
|
+
|
|
699
|
+
it("leaves a name-derived stem in the slug for every accepted name", () => {
|
|
700
|
+
for (const [name, fragment] of acceptedNames) {
|
|
701
|
+
/*
|
|
702
|
+
* Guard the guard: if the gate stopped accepting one of these, the slug
|
|
703
|
+
* assertion below would be testing a value that never reaches a device.
|
|
704
|
+
*/
|
|
705
|
+
expect(normalizeReverseDnsName(name)).toBe(name);
|
|
706
|
+
|
|
707
|
+
const slug: string = Slug.getSlug(name);
|
|
708
|
+
|
|
709
|
+
/*
|
|
710
|
+
* getSlug always appends "-" plus ten digits, so a name that slugified
|
|
711
|
+
* to "" yields exactly "-##########" — which fails this match, because
|
|
712
|
+
* the capture needs at least one character before the suffix.
|
|
713
|
+
*/
|
|
714
|
+
const stem: RegExpMatchArray | null = slug.match(/^(.+)-\d{10}$/);
|
|
715
|
+
expect(stem).not.toBeNull();
|
|
716
|
+
|
|
717
|
+
/*
|
|
718
|
+
* And the stem must be THIS name's stem, not merely some non-empty
|
|
719
|
+
* string. The old assertion here was `expect(stem?.[1]).not.toBe("")`,
|
|
720
|
+
* which could not fail in either branch: a matched capture of `.+` is
|
|
721
|
+
* non-empty by construction, and an unmatched one is `undefined`, which
|
|
722
|
+
* also is not "". Comparing against the fragment is what makes the case
|
|
723
|
+
* die if the name stopped reaching the slug.
|
|
724
|
+
*/
|
|
725
|
+
expect(stem?.[1]).toContain(fragment);
|
|
726
|
+
}
|
|
727
|
+
});
|
|
728
|
+
|
|
729
|
+
it("does not itself keep a name short enough for the slug column", () => {
|
|
730
|
+
/*
|
|
731
|
+
* The complement of the case above, and the reason MAX_DEVICE_NAME_LENGTH
|
|
732
|
+
* exists: this gate accepts up to 253 characters, which is well past the
|
|
733
|
+
* slug column's varchar(100). Length safety is DiscoveredDeviceBuilder's
|
|
734
|
+
* clamp to 80, not this function's — asserting it here pins where the
|
|
735
|
+
* responsibility lives, so nobody removes the clamp believing the DNS
|
|
736
|
+
* limit already covers it.
|
|
737
|
+
*
|
|
738
|
+
* Asserted on the length of what THIS function returns rather than on
|
|
739
|
+
* Slug.getSlug(...).length, deliberately: the claim is about this gate
|
|
740
|
+
* not truncating, and routing it through Slug would put a foreign
|
|
741
|
+
* module's behaviour (if Slug ever gained a clamp of its own) on the
|
|
742
|
+
* failure path of a suite that does not own it.
|
|
743
|
+
*/
|
|
744
|
+
const label: string = "a".repeat(MAX_REVERSE_DNS_LABEL_LENGTH);
|
|
745
|
+
const maximalName: string = `${label}.${label}.${label}.${"b".repeat(61)}`;
|
|
746
|
+
const normalized: string | undefined = normalizeReverseDnsName(maximalName);
|
|
747
|
+
expect(normalized).toBe(maximalName);
|
|
748
|
+
expect(normalized?.length).toBeGreaterThan(100);
|
|
749
|
+
});
|
|
750
|
+
});
|
|
751
|
+
|
|
752
|
+
describe("normalizeReverseDnsName — non-string input", () => {
|
|
753
|
+
/*
|
|
754
|
+
* On the server side the input is read out of a jsonb column, so "the probe
|
|
755
|
+
* sent a number" and "the key is missing" are cases that have to return
|
|
756
|
+
* undefined rather than throw inside a React render. This is the same
|
|
757
|
+
* lesson normalizeDiscoveredHosts learned from a null row in the same
|
|
758
|
+
* column.
|
|
759
|
+
*
|
|
760
|
+
* This block is also what covers re-normalising the `undefined` that a
|
|
761
|
+
* rejected name produces: a later stage feeding its own output back in is
|
|
762
|
+
* exactly `normalizeReverseDnsName(undefined)`, pinned once here rather
|
|
763
|
+
* than re-spelled in a loop that only ever passed it the same value.
|
|
764
|
+
*/
|
|
765
|
+
|
|
766
|
+
it("returns undefined for nullish input", () => {
|
|
767
|
+
expect(normalizeReverseDnsName(undefined)).toBeUndefined();
|
|
768
|
+
expect(normalizeReverseDnsName(null)).toBeUndefined();
|
|
769
|
+
});
|
|
770
|
+
|
|
771
|
+
it("returns undefined rather than coercing a number", () => {
|
|
772
|
+
expect(normalizeReverseDnsName(51)).toBeUndefined();
|
|
773
|
+
expect(normalizeReverseDnsName(0)).toBeUndefined();
|
|
774
|
+
expect(normalizeReverseDnsName(NaN)).toBeUndefined();
|
|
775
|
+
});
|
|
776
|
+
|
|
777
|
+
it("returns undefined for booleans, objects and arrays", () => {
|
|
778
|
+
expect(normalizeReverseDnsName(true)).toBeUndefined();
|
|
779
|
+
expect(
|
|
780
|
+
normalizeReverseDnsName({
|
|
781
|
+
toString: () => {
|
|
782
|
+
return "host.example.com";
|
|
783
|
+
},
|
|
784
|
+
}),
|
|
785
|
+
).toBeUndefined();
|
|
786
|
+
expect(normalizeReverseDnsName(["host.example.com"])).toBeUndefined();
|
|
787
|
+
});
|
|
788
|
+
});
|
|
789
|
+
|
|
790
|
+
describe("normalizeReverseDnsName — idempotence and repeat-call stability", () => {
|
|
791
|
+
/*
|
|
792
|
+
* The value is normalised on the probe, again by normalizeDiscoveredHosts
|
|
793
|
+
* on the way out of the jsonb column, and again by
|
|
794
|
+
* getDiscoveredHostDisplayName at the point of use. Three passes must
|
|
795
|
+
* produce what one pass produced, or the name an operator ticks in the
|
|
796
|
+
* Review dialog and the name the created device gets could differ.
|
|
797
|
+
*/
|
|
798
|
+
|
|
799
|
+
it("returns an accepted name unchanged on every later pass", () => {
|
|
800
|
+
/*
|
|
801
|
+
* Each of these CHANGES on the first pass — a root dot dropped, surrounding
|
|
802
|
+
* whitespace trimmed — so the second pass is a real test of convergence
|
|
803
|
+
* rather than a repeat of a no-op.
|
|
804
|
+
*/
|
|
805
|
+
const changedByNormalisation: Array<[string, string]> = [
|
|
806
|
+
["host.example.com.", "host.example.com"],
|
|
807
|
+
[" SW-Core-01.corp.example.com ", "SW-Core-01.corp.example.com"],
|
|
808
|
+
["\tprinter_2\n", "printer_2"],
|
|
809
|
+
[" 51.corp.example.com. ", "51.corp.example.com"],
|
|
810
|
+
];
|
|
811
|
+
|
|
812
|
+
for (const [input, expected] of changedByNormalisation) {
|
|
813
|
+
const first: string | undefined = normalizeReverseDnsName(input);
|
|
814
|
+
expect(first).toBe(expected);
|
|
815
|
+
|
|
816
|
+
const second: string | undefined = normalizeReverseDnsName(first);
|
|
817
|
+
const third: string | undefined = normalizeReverseDnsName(second);
|
|
818
|
+
|
|
819
|
+
/*
|
|
820
|
+
* Compared against the expected STRING, not against `first`: comparing
|
|
821
|
+
* the passes to each other would be satisfied by `undefined ===
|
|
822
|
+
* undefined` if a later pass dropped the name entirely.
|
|
823
|
+
*/
|
|
824
|
+
expect(second).toBe(expected);
|
|
825
|
+
expect(third).toBe(expected);
|
|
826
|
+
}
|
|
827
|
+
});
|
|
828
|
+
|
|
829
|
+
it("keeps an already-normalised name byte-identical", () => {
|
|
830
|
+
const alreadyNormal: Array<string> = [
|
|
831
|
+
"core-switch-01.corp.example.com",
|
|
832
|
+
"ws_finance_12.corp.example.com",
|
|
833
|
+
"something.arpa",
|
|
834
|
+
"notin-addr.arpa",
|
|
835
|
+
"51.corp.example.com",
|
|
836
|
+
"xn--hte-snab.example.com",
|
|
837
|
+
];
|
|
838
|
+
|
|
839
|
+
for (const name of alreadyNormal) {
|
|
840
|
+
expect(normalizeReverseDnsName(name)).toBe(name);
|
|
841
|
+
}
|
|
842
|
+
});
|
|
843
|
+
|
|
844
|
+
it("gives the same answer when the same value is passed again", () => {
|
|
845
|
+
/*
|
|
846
|
+
* Purity, asserted by calling the function repeatedly on the IDENTICAL
|
|
847
|
+
* input and requiring the identical answer each time.
|
|
848
|
+
*
|
|
849
|
+
* This is not the tautology it looks like, and it replaces a loop whose
|
|
850
|
+
* second assertion was always `normalizeReverseDnsName(undefined)` — the
|
|
851
|
+
* same call for every input, unable to fail unless the nullish case
|
|
852
|
+
* already had. The mutation this one exists for is a `g` flag on either
|
|
853
|
+
* module-level regex, a one-character edit that reads as harmless
|
|
854
|
+
* housekeeping: `RegExp.prototype.test` with /g advances `lastIndex`, so
|
|
855
|
+
* `/^[0-9]+$/g.test("51")` is true, then false, then true again on
|
|
856
|
+
* successive calls. Under it "51" would be rejected on the probe and
|
|
857
|
+
* ACCEPTED on the server's re-normalisation of the same string — the
|
|
858
|
+
* dialog and the created device disagreeing about a device's name, with
|
|
859
|
+
* nothing to show for it in a single-call test. A memoising cache keyed
|
|
860
|
+
* by name would land here too.
|
|
861
|
+
*
|
|
862
|
+
* Both directions are in the table on purpose: a rejected value must stay
|
|
863
|
+
* rejected across calls, and an accepted one must stay accepted.
|
|
864
|
+
*/
|
|
865
|
+
const repeated: Array<[unknown, string | undefined]> = [
|
|
866
|
+
["51", undefined],
|
|
867
|
+
["10.18.166.51", undefined],
|
|
868
|
+
["in-addr.arpa", undefined],
|
|
869
|
+
["host..example.com", undefined],
|
|
870
|
+
["a".repeat(MAX_REVERSE_DNS_NAME_LENGTH + 1), undefined],
|
|
871
|
+
["51.corp.example.com", "51.corp.example.com"],
|
|
872
|
+
["core-switch-01.corp.example.com", "core-switch-01.corp.example.com"],
|
|
873
|
+
["___", "___"],
|
|
874
|
+
];
|
|
875
|
+
|
|
876
|
+
for (const [value, expected] of repeated) {
|
|
877
|
+
expect(normalizeReverseDnsName(value)).toBe(expected);
|
|
878
|
+
expect(normalizeReverseDnsName(value)).toBe(expected);
|
|
879
|
+
expect(normalizeReverseDnsName(value)).toBe(expected);
|
|
880
|
+
}
|
|
881
|
+
});
|
|
882
|
+
});
|