Add db migration and DNS dmarc entries

This commit is contained in:
2026-05-20 13:20:58 -03:00
parent 636d3b73cb
commit e57df39562
19 changed files with 850 additions and 12 deletions
+35 -1
View File
@@ -41,6 +41,11 @@ def _report(
dkim_aligned: bool | None = None,
report_time: datetime | None = None,
org_name: str = "google.com",
policy_p: str | None = None,
policy_sp: str | None = None,
policy_pct: int | None = None,
disposition: str = "none",
reason_type: str | None = None,
) -> Report:
dkim_aligned = dmarc_pass if dkim_aligned is None else dkim_aligned
report_time = report_time or datetime.now(timezone.utc)
@@ -52,6 +57,9 @@ def _report(
domain="tukutoi.com",
date_begin=report_time - timedelta(hours=1),
date_end=report_time,
policy_p=policy_p,
policy_sp=policy_sp,
policy_pct=policy_pct,
)
session.add(report)
session.flush()
@@ -60,7 +68,7 @@ def _report(
report=report,
source_ip=source_ip,
count=count,
disposition="none",
disposition=disposition,
policy_dkim="pass" if dkim_aligned else "fail",
policy_spf="pass" if spf_aligned else "fail",
dkim_aligned=dkim_aligned,
@@ -70,6 +78,7 @@ def _report(
known_sender_id="mailcow" if known else None,
known_sender_name="mailcow outbound" if known else None,
is_known_sender=known,
reason_type=reason_type,
)
)
session.commit()
@@ -175,3 +184,28 @@ def test_missing_reporter_gap_does_not_create_alert():
alerts = analyze_report(session, settings, report)
assert not any(alert.type == "missing_reporter" for alert, _, _ in alerts)
def test_alert_details_include_published_policy_and_receiver_action():
session = _session()
report = _report(
session,
source_ip="203.0.113.91",
count=25,
known=False,
dmarc_pass=False,
policy_p="reject",
policy_sp="quarantine",
policy_pct=100,
disposition="reject",
)
alerts = analyze_report(session, _settings(), report)
alert = next(alert for alert, _, _ in alerts if alert.type == "unknown_source_failed_both")
details = json.loads(alert.details_json)
assert details["published_policy"]["p"] == "reject"
assert details["published_policy"]["effective"] == "reject"
assert details["published_policy"]["effective_source"] == "p"
assert details["receiver_action"]["disposition"] == "reject"
assert "Published DMARC policy was p=reject; pct=100" in alert.summary
+47
View File
@@ -0,0 +1,47 @@
from app.dns_policy import collect_domain_dns_policy, parse_dmarc_records, parse_spf_records
def test_parse_dmarc_record_extracts_policy_tags():
parsed, errors = parse_dmarc_records(["v=DMARC1; p=reject; sp=quarantine; pct=50; adkim=s; aspf=r; rua=mailto:d@example.com"])
assert errors == []
assert parsed.p == "reject"
assert parsed.sp == "quarantine"
assert parsed.pct == 50
assert parsed.adkim == "s"
assert parsed.rua == "mailto:d@example.com"
def test_parse_spf_record_extracts_includes_and_all_mechanism():
parsed, errors = parse_spf_records(["v=spf1 include:_spf.google.com include:mailgun.org -all"])
assert errors == []
assert parsed.includes == ["_spf.google.com", "mailgun.org"]
assert parsed.all_mechanism == "-all"
def test_collect_domain_dns_policy_uses_observed_dkim_selectors():
txt_records = {
"_dmarc.example.com": ["v=DMARC1; p=reject; pct=100"],
"example.com": ["v=spf1 include:_spf.example.net -all"],
"s1._domainkey.example.com": ["v=DKIM1; k=rsa; p=abc"],
}
def txt_lookup(name: str) -> list[str]:
if name not in txt_records:
raise RuntimeError("not found")
return txt_records[name]
policy = collect_domain_dns_policy(
"example.com",
selectors=["s1"],
txt_lookup=txt_lookup,
mx_lookup=lambda name: ["10 mail.example.com"],
)
assert policy.dmarc.p == "reject"
assert policy.spf.all_mechanism == "-all"
assert policy.mx_records == ["10 mail.example.com"]
assert policy.dkim[0].selector == "s1"
assert policy.dkim[0].record == "v=DKIM1; k=rsa; p=abc"
assert policy.errors == []