Compare commits

..

2 Commits

Author SHA1 Message Date
Serge Matveenko
134d533aa0 Test dig output with dns comments 2025-11-06 10:55:36 +01:00
Serge Matveenko
8110a3f3a9 Improve dns responses parsing 2025-11-06 10:55:36 +01:00
5 changed files with 52 additions and 48 deletions

View File

@@ -681,7 +681,7 @@ def deploy_chatmail(config_path: Path, disable_mail: bool) -> None:
check_config(config) check_config(config)
mail_domain = config.mail_domain mail_domain = config.mail_domain
from .www import build_webpages, find_merge_conflict, get_paths from .www import build_webpages, get_paths
server.group(name="Create vmail group", group="vmail", system=True) server.group(name="Create vmail group", group="vmail", system=True)
server.user(name="Create vmail user", user="vmail", group="vmail", system=True) server.user(name="Create vmail user", user="vmail", group="vmail", system=True)
@@ -823,8 +823,6 @@ def deploy_chatmail(config_path: Path, disable_mail: bool) -> None:
# if www_folder was set to a non-existing folder, skip upload # if www_folder was set to a non-existing folder, skip upload
if not www_path.is_dir(): if not www_path.is_dir():
logger.warning("Building web pages is disabled in chatmail.ini, skipping") logger.warning("Building web pages is disabled in chatmail.ini, skipping")
elif (path := find_merge_conflict(src_dir)) is not None:
logger.warning(f"Merge conflict found in {path}, skipping")
else: else:
# if www_folder is a hugo page, build it # if www_folder is a hugo page, build it
if build_dir: if build_dir:

View File

@@ -73,9 +73,7 @@ def query_dns(typ, domain):
# Query authoritative nameserver directly to bypass DNS cache. # Query authoritative nameserver directly to bypass DNS cache.
res = shell(f"dig @{ns} -r -q {domain} -t {typ} +short", print=log_progress) res = shell(f"dig @{ns} -r -q {domain} -t {typ} +short", print=log_progress)
if res: return next((line for line in res.split("\n") if not line.startswith(';')), '')
return res.split("\n")[0]
return ""
def check_zonefile(zonefile, verbose=True): def check_zonefile(zonefile, verbose=True):

View File

@@ -1,3 +1,5 @@
from copy import deepcopy
import pytest import pytest
from cmdeploy import remote from cmdeploy import remote
@@ -8,38 +10,63 @@ from cmdeploy.dns import check_full_zone, check_initial_remote_data
def mockdns_base(monkeypatch): def mockdns_base(monkeypatch):
qdict = {} qdict = {}
def query_dns(typ, domain): def shell(command, fail_ok=False, print=print):
try: if command.startswith("dig"):
return qdict[typ][domain] if command == "dig":
except KeyError: return "."
return "" if "SOA" in command:
return (
"delta.chat. 21600 IN SOA ns1.first-ns.de. dns.hetzner.com."
" 2025102800 14400 1800 604800 3600"
)
command_chunks = command.split()
domain, typ = command_chunks[4], command_chunks[6]
try:
return qdict[typ][domain]
except KeyError:
return ""
return remote.rshell.shell(command=command, fail_ok=fail_ok, print=print)
monkeypatch.setattr(remote.rdns, query_dns.__name__, query_dns) monkeypatch.setattr(remote.rdns, shell.__name__, shell)
return qdict return qdict
@pytest.fixture @pytest.fixture
def mockdns(mockdns_base): def mockdns_expected():
mockdns_base.update( return {
{ "A": {"some.domain": "1.1.1.1"},
"A": {"some.domain": "1.1.1.1"}, "AAAA": {"some.domain": "fde5:cd7a:9e1c:3240:5a99:936f:cdac:53ae"},
"AAAA": {"some.domain": "fde5:cd7a:9e1c:3240:5a99:936f:cdac:53ae"}, "CNAME": {
"CNAME": { "mta-sts.some.domain": "some.domain.",
"mta-sts.some.domain": "some.domain.", "www.some.domain": "some.domain.",
"www.some.domain": "some.domain.", },
}, }
}
)
@pytest.fixture(params=["plain", "with-dns-comments"])
def mockdns(request, mockdns_base, mockdns_expected):
mockdns_base.update(deepcopy(mockdns_expected))
match request.param:
case "plain":
pass
case "with-dns-comments":
for typ, data in mockdns_base.items():
for host, result in data.items():
mockdns_base[typ][host] = (
";; some unsuccessful attempt result\n"
"; and another with a single semicolon\n"
f"{result}"
)
return mockdns_base return mockdns_base
class TestPerformInitialChecks: class TestPerformInitialChecks:
def test_perform_initial_checks_ok1(self, mockdns): def test_perform_initial_checks_ok1(self, mockdns, mockdns_expected):
remote_data = remote.rdns.perform_initial_checks("some.domain") remote_data = remote.rdns.perform_initial_checks("some.domain")
assert remote_data["A"] == mockdns["A"]["some.domain"] assert remote_data["A"] == mockdns_expected["A"]["some.domain"]
assert remote_data["AAAA"] == mockdns["AAAA"]["some.domain"] assert remote_data["AAAA"] == mockdns_expected["AAAA"]["some.domain"]
assert remote_data["MTA_STS"] == mockdns["CNAME"]["mta-sts.some.domain"] assert remote_data["MTA_STS"] == mockdns_expected["CNAME"]["mta-sts.some.domain"]
assert remote_data["WWW"] == mockdns["CNAME"]["www.some.domain"] assert remote_data["WWW"] == mockdns_expected["CNAME"]["www.some.domain"]
@pytest.mark.parametrize("drop", ["A", "AAAA"]) @pytest.mark.parametrize("drop", ["A", "AAAA"])
def test_perform_initial_checks_with_one_of_A_AAAA(self, mockdns, drop): def test_perform_initial_checks_with_one_of_A_AAAA(self, mockdns, drop):

View File

@@ -4,7 +4,6 @@ import time
import traceback import traceback
import webbrowser import webbrowser
from pathlib import Path from pathlib import Path
import re
import markdown import markdown
from chatmaild.config import read_config from chatmaild.config import read_config
@@ -13,9 +12,6 @@ from jinja2 import Template
from .genqr import gen_qr_png_data from .genqr import gen_qr_png_data
_MERGE_CONFLICT_RE = re.compile(r"^<<<<<<<.+^=======.+^>>>>>>>", re.DOTALL | re.MULTILINE)
def snapshot_dir_stats(somedir): def snapshot_dir_stats(somedir):
d = {} d = {}
for path in somedir.iterdir(): for path in somedir.iterdir():
@@ -120,17 +116,6 @@ def _build_webpages(src_dir, build_dir, config):
return build_dir return build_dir
def find_merge_conflict(src_dir) -> Path:
assert src_dir.exists(), src_dir
result = None
for path in src_dir.iterdir():
if path.suffix in [".css", ".html", ".md"]:
if _MERGE_CONFLICT_RE.search(path.read_text()):
result = path
break
return result
def main(): def main():
path = importlib.resources.files(__package__) path = importlib.resources.files(__package__)
reporoot = path.joinpath("../../../").resolve() reporoot = path.joinpath("../../../").resolve()

View File

@@ -9,11 +9,7 @@
<title>{{ config.mail_domain }} {{ pagename }}</title> <title>{{ config.mail_domain }} {{ pagename }}</title>
<link rel="stylesheet" href="./main.css"> <link rel="stylesheet" href="./main.css">
<link rel="icon" href="/logo.svg"> <link rel="icon" href="/logo.svg">
<<<<<<< HEAD <link rel=”mask-icon” href=”/logo.svg” color=”#000000">
<link rel="mask-icon" href="/logo.svg" color="#000000">
=======
<link rel=”mask-icon” href=”/logo.svg” color=”#000001">
>>>>>>> 2da7de8 (make logo slightly brighter)
</head> </head>
<body> <body>