From b89316d910f90ea9178f16710faee072708b0f04 Mon Sep 17 00:00:00 2001 From: Ali EL BROUDI Date: Fri, 13 Feb 2026 14:17:23 +0100 Subject: [PATCH 1/3] Add ALIAS record support for custom domain --- src/aleph/sdk/domain.py | 65 +++++++++++++++++++++++++++++++++-------- 1 file changed, 53 insertions(+), 12 deletions(-) diff --git a/src/aleph/sdk/domain.py b/src/aleph/sdk/domain.py index 79a0c5d4..00a77f10 100644 --- a/src/aleph/sdk/domain.py +++ b/src/aleph/sdk/domain.py @@ -198,6 +198,28 @@ async def check_domain( record_type = dns_rule.dns["type"] record_value = dns_rule.dns["value"] + if record_type == "alias": + # ALIAS records are resolved as A records by the DNS provider. + # To validate, resolve the target hostname to its IPs and compare + # against the A records returned for the user's domain. + try: + entries = await resolver.query(record_name, "A") + except aiodns.error.DNSError: + entries = None + + if entries: + try: + target_entries = await self.resolver.query(record_value, "A") + target_ips = {e.host for e in target_entries if hasattr(e, "host")} + except aiodns.error.DNSError: + target_ips = set() + + domain_ips = {e.host for e in entries if hasattr(e, "host")} + if target_ips and domain_ips & target_ips: + status[dns_rule.name] = True + + continue + try: entries = await resolver.query(record_name, record_type.upper()) except aiodns.error.DNSError: @@ -249,19 +271,35 @@ def get_required_dns_rules( elif target == TargetType.INSTANCE: cname_value = f"{hostname}.{settings.DNS_INSTANCE_DOMAIN}" - # cname rule - dns_rules.append( - DNSRule( - name="cname", - dns={ - "type": "cname", - "name": hostname, - "value": cname_value, - }, - info=f"Create a CNAME record for {hostname} with value {cname_value}", - on_error=f"CNAME record not found: {hostname}", + # cname or alias rule + if self.is_root_domain(hostname): + record_type = "alias" + dns_rules.append( + DNSRule( + name=record_type, + dns={ + "type": record_type, + "name": hostname, + "value": cname_value, + }, + info=f"Create an ALIAS record for {hostname} with value {cname_value}", + on_error=f"ALIAS record not found: {hostname}", + ) + ) + else: + record_type = "cname" + dns_rules.append( + DNSRule( + name=record_type, + dns={ + "type": record_type, + "name": hostname, + "value": cname_value, + }, + info=f"Create a CNAME record for {hostname} with value {cname_value}", + on_error=f"CNAME record not found: {hostname}", + ) ) - ) if target == TargetType.IPFS: # ipfs rule @@ -294,3 +332,6 @@ def get_required_dns_rules( ) return dns_rules + + def is_root_domain(self, hostname: Hostname) -> bool: + return len(hostname.split(".")) == 2 From 9999d8e8145d01d7e006624e5b99f70b91384e8a Mon Sep 17 00:00:00 2001 From: Ali EL BROUDI Date: Fri, 13 Feb 2026 14:38:54 +0100 Subject: [PATCH 2/3] fix: conser the rule as valid and trust the user's configuration. --- src/aleph/sdk/domain.py | 23 ++++------------------- 1 file changed, 4 insertions(+), 19 deletions(-) diff --git a/src/aleph/sdk/domain.py b/src/aleph/sdk/domain.py index 00a77f10..1a5983b0 100644 --- a/src/aleph/sdk/domain.py +++ b/src/aleph/sdk/domain.py @@ -199,25 +199,10 @@ async def check_domain( record_value = dns_rule.dns["value"] if record_type == "alias": - # ALIAS records are resolved as A records by the DNS provider. - # To validate, resolve the target hostname to its IPs and compare - # against the A records returned for the user's domain. - try: - entries = await resolver.query(record_name, "A") - except aiodns.error.DNSError: - entries = None - - if entries: - try: - target_entries = await self.resolver.query(record_value, "A") - target_ips = {e.host for e in target_entries if hasattr(e, "host")} - except aiodns.error.DNSError: - target_ips = set() - - domain_ips = {e.host for e in entries if hasattr(e, "host")} - if target_ips and domain_ips & target_ips: - status[dns_rule.name] = True - + # ALIAS records cannot be reliably validated via DNS since the + # provider resolves them to A records asynchronously. Consider + # the rule as valid and trust the user's configuration. + status[dns_rule.name] = True continue try: From 0154075ba78bf08ab114551cbc35922ec8a9b88a Mon Sep 17 00:00:00 2001 From: Ali EL BROUDI Date: Fri, 13 Feb 2026 17:48:17 +0100 Subject: [PATCH 3/3] add tldextract for root domain detection that support multilevel TLDs --- pyproject.toml | 1 + src/aleph/sdk/domain.py | 7 +++++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 46adc715..325b87a3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -56,6 +56,7 @@ optional-dependencies.cosmos = [ ] optional-dependencies.dns = [ "aiodns", + "tldextract", ] optional-dependencies.docs = [ "sphinxcontrib-plantuml", diff --git a/src/aleph/sdk/domain.py b/src/aleph/sdk/domain.py index 1a5983b0..70a53b08 100644 --- a/src/aleph/sdk/domain.py +++ b/src/aleph/sdk/domain.py @@ -5,6 +5,7 @@ from urllib.parse import urlparse import aiodns +import tldextract from pydantic import BaseModel, HttpUrl from .conf import settings @@ -318,5 +319,7 @@ def get_required_dns_rules( return dns_rules - def is_root_domain(self, hostname: Hostname) -> bool: - return len(hostname.split(".")) == 2 + @staticmethod + def is_root_domain(hostname: Hostname) -> bool: + extracted = tldextract.extract(hostname) + return bool(extracted.domain) and not extracted.subdomain