Files
bongo/contrib/testing/mail-dns-live-check.py
T
Mario Fetka 7f1bbf8587
Debian Trixie package bundle / packages (push) Failing after 12m24s
Cover mail DNS setup integration
2026-07-22 17:12:22 +02:00

85 lines
3.8 KiB
Python
Executable File

#!/usr/bin/env python3
"""Verify the setup-created mail-DNS task and administrator message."""
from __future__ import annotations
import http.cookiejar
import imaplib
import json
import os
import ssl
import urllib.request
from email import policy
from email.parser import BytesParser
from urllib.parse import urlsplit
base_url = os.environ.get("BONGO_TEST_WEB_URL", "http://127.0.0.1:8080").rstrip("/")
user = os.environ.get("BONGO_TEST_USER", "admin")
password = os.environ.get("BONGO_TEST_PASSWORD", "")
domain = os.environ.get("BONGO_TEST_DOMAIN", "bongo.test")
timeout = int(os.environ.get("BONGO_TEST_TIMEOUT", "90"))
if not password:
raise SystemExit("set BONGO_TEST_PASSWORD for the disposable administrator")
cookies = http.cookiejar.CookieJar()
opener = urllib.request.build_opener(urllib.request.HTTPCookieProcessor(cookies))
request = urllib.request.Request(
base_url + "/api/session",
data=json.dumps({"user": user, "password": password}).encode("utf-8"),
headers={"Content-Type": "application/json"}, method="POST")
with opener.open(request, timeout=timeout) as response:
if response.status != 201:
raise SystemExit(f"Web login returned HTTP {response.status}")
with opener.open(base_url + "/api/tasks?include_closed=1",
timeout=timeout) as response:
tasks = json.load(response).get("tasks", [])
matching = [task for task in tasks
if task.get("type") == "mail-dns" and task.get("key") == domain]
if len(matching) != 1:
raise SystemExit(f"expected one mail-dns task for {domain}, got {len(matching)}")
task = matching[0]
if task.get("severity") != "warning" or not task.get("dismissible"):
raise SystemExit("mail-dns task does not have the expected actionable policy")
details = task.get("details", {})
if details.get("domain") != domain or not details.get("actions"):
raise SystemExit("mail-dns task has no actionable DNS details")
if set(details.get("suggested", {})) != {"spf", "dkim", "dmarc"}:
raise SystemExit("mail-dns task lacks an SPF, DKIM, or DMARC suggestion")
host = os.environ.get("BONGO_TEST_IMAP_HOST") or urlsplit(base_url).hostname
context = ssl.create_default_context()
if os.environ.get("BONGO_TEST_INSECURE_TLS") == "1":
context.check_hostname = False
context.verify_mode = ssl.CERT_NONE
with imaplib.IMAP4_SSL(
host, int(os.environ.get("BONGO_TEST_IMAPS_PORT", "993")),
ssl_context=context, timeout=timeout) as client:
client.login(user, password)
status, _count = client.select("INBOX", readonly=True)
if status != "OK":
raise SystemExit("cannot select administrator INBOX")
status, identifiers = client.search(
None, "HEADER", "X-Bongo-Notification", "mail-dns")
if status != "OK" or not identifiers or not identifiers[0].split():
raise SystemExit("administrator mail-DNS notification was not found")
identifier = identifiers[0].split()[-1]
status, data = client.fetch(identifier, "(BODY.PEEK[])")
if status != "OK":
raise SystemExit("cannot read administrator mail-DNS notification")
payload = next((item[1] for item in data
if isinstance(item, tuple) and isinstance(item[1], bytes)), b"")
message = BytesParser(policy=policy.default).parsebytes(payload)
if message.get("X-Bongo-Notification") != "mail-dns":
raise SystemExit("administrator message has the wrong notification marker")
if domain not in str(message.get("To", "")):
raise SystemExit("administrator message has the wrong recipient domain")
upper_payload = payload.upper()
if (b"-----BEGIN PRIVATE KEY-----" in upper_payload or
b"-----BEGIN RSA PRIVATE KEY-----" in upper_payload or
b"-----BEGIN ENCRYPTED PRIVATE KEY-----" in upper_payload):
raise SystemExit("administrator message contains private-key material")
print("PASS actionable mail-DNS task and administrator notification")