Replace per-field regex extractor methods with a single parseDKIMTags call,
removing eight redundant private methods and unifying DMARC tag parsing with
the existing DKIM tag parser. Tests are updated to drive through parseDMARCRecord
instead of the removed helpers, and the NP scoring logic is corrected to award
+15/−15 symmetrically like the SP scoring path.
Replace RFC 7489 PSL-based org-domain lookup and RFC 9091 PSD DMARC
fallback with the DMARCbis DNS Tree Walk algorithm (max 8 queries,
8-label shortcut, TLD records require psd=y). Add parsing for the new
t= (test mode), psd= (y/n/u), and deprecated tag detection (pct, rf,
ri). Update validateDMARC to accept p=-absent records with rua= per
DMARCbis §4.7. Score t=y by downgrading effective policy one level.
Surface user-facing advisories in DmarcRecordDisplay: deprecation
warnings for pct=/rf=/ri=, test mode explanation with per-policy
impact, and PSD/org-domain boundary notices.
Implements parsing, scoring, CLI output, and UI display for the DMARC
np= tag (DMARCbis draft-ietf-dmarc-dmarcbis), which controls policy for
NXDOMAIN subdomains independently of sp=. The score deducts 15 points
from the base and awards them back when np= is absent (good default) or
its strength is equal to or stricter than the effective sp=/p= policy.
DMARC lookup now follows the full RFC 7489 §6.6.3 fallback chain: exact
From domain → organizational domain (eTLD+1 via PSL) → public suffix
domain (RFC 9091, only when psd=y is present). DNS errors abort
immediately without triggering fallback; NXDOMAIN and missing v=DMARC1
records do trigger it. The found domain is exposed in the new
DMARCRecord.domain field for reporting purposes.
Also promote getOrganizationalDomain to a package-level function so both
HeaderAnalyzer and DNSAnalyzer can share it, and fix pre-existing
rbl_test.go compilation errors and stale score expectations.
Closes: #98
Split api/openapi.yaml schemas into api/schemas.yaml so structs can be
generated independently from the API server code. Models now generate
into internal/model/ via oapi-codegen, with the server referencing them
through import-mapping. Moved PtrTo helper to internal/utils and removed
storage.ReportSummary in favor of model.TestSummary.