"""NS is a first-class self-service DNS record type (2026-06-09). Until now self-service was restricted to A / AAAA / CNAME / TXT and NS was admin-direct-write only. Subdomain delegation to an external nameserver is a routine need, so NS is now allowed through the employee-facing request flow — validated as an FQDN (same shape as a CNAME target) and dispatched through the same cloud-DNS path. These tests pin down: * NS is in the self-service whitelist. * Both validators (the schema-level ``_validate_dns_value`` used by ``DnsRecordRequestCreate`` and the service-level ``_validate_value_for_type`` used at submit time) accept a valid nameserver FQDN and reject a bare IP / empty value. * ``DnsRecordRequestCreate`` accepts a create-NS body. * MX / SRV / CAA stay admin-only — they must NOT leak into self-service alongside NS. """ from __future__ import annotations import uuid import pytest from pydantic import ValidationError as PydanticValidationError from app.core.exceptions import ValidationError from app.domains.cmdb.dns_request_service import _validate_value_for_type from app.domains.cmdb.models import DNS_REQ_SELF_SERVICE_TYPES from app.domains.cmdb.schemas import DnsRecordRequestCreate, _validate_dns_value def test_ns_is_self_service_type() -> None: assert "NS" in DNS_REQ_SELF_SERVICE_TYPES def test_ns_admin_only_types_unchanged() -> None: # NS joined the whitelist; the genuinely-dangerous types stay out. for t in ("MX", "SRV", "CAA"): assert t not in DNS_REQ_SELF_SERVICE_TYPES @pytest.mark.parametrize("value", ["ns1.example.com", "a.ns.cloudflare.com", "dns1.p09.nsone.net"]) def test_ns_valid_fqdn_accepted(value: str) -> None: _validate_dns_value("NS", value) # schema-level _validate_value_for_type("NS", value) # service-level @pytest.mark.parametrize("value", ["1.2.3.4", "not a host", ""]) def test_ns_bad_value_rejected_service_level(value: str) -> None: with pytest.raises(ValidationError): _validate_value_for_type("NS", value) def test_ns_create_request_schema_accepts() -> None: body = DnsRecordRequestCreate( action="create", integration_id=uuid.uuid4(), zone_name="example.com", name="sub", record_type="NS", value="ns1.external-dns.com", ttl=600, purpose="delegate sub.example.com to external DNS", ) assert body.record_type == "NS" def test_mx_still_rejected_by_self_service_schema() -> None: # The self-service literal must NOT accept MX even though NS was added. with pytest.raises(PydanticValidationError): DnsRecordRequestCreate( action="create", integration_id=uuid.uuid4(), zone_name="example.com", name="mail", record_type="MX", value="10 mail.example.com", ttl=600, purpose="should be rejected", )