postfix: no reload for a map that did not change; DNS re-checks limited (audit W6/M9)

Security audit 2026-10-17, findings W6/M9 (low), stage 4. Every
application, upstream, recipient or report-address save reloaded Postfix
through supervisord, and POST .../dns-recheck bypassed the five-minute
cache for up to ~14 resolver queries - both at whatever rate an
authenticated user pressed.

- writeChanged: each generated map is written only when its content
  differs from the file on disk, and Postfix is reloaded only when one was
  (sender map, inbound maps, DMARC maps). Health's Reload configuration
  ends with an explicit reload (app.Service.ReloadPostfix, SenderMaps
  gains Reload), so it still re-reads whatever is on disk. No debounce:
  with unchanged saves gone, a burst is real changes Postfix must see.
- auth.AllowDNSRecheck: twenty forced re-checks in 15 minutes per user;
  past that the outbound, inbound and settings re-check show the cached
  result without the "re-checked" flash, and the log says why.

Tests: TestARebuildThatChangesNothingDoesNotReload,
TestDNSRechecksArePerUser; the fakes gain Reload. Docs: guide § Overview
and Health; CHANGELOG; plan.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
mix
2026-10-17 22:25:20 +03:00
co-authored by Claude Opus 5.5
parent dd950364a3
commit 668e299c69
18 changed files with 153 additions and 22 deletions
+4 -2
View File
@@ -516,7 +516,8 @@ readings, numbered in the order of what stops mail first:
- **Hostname and reverse DNS** — compares `SELFPOST_HOSTNAME` against the PTR
record the internet publishes for this server's IP (forward-confirmed
reverse DNS), see [Server-level DNS](#server-level-dns-ptrrdns); use
*Re-check DNS* after changing DNS. *Greeting* is the `220` line Postfix
*Re-check DNS* after changing DNS (twenty re-checks in 15 minutes per user;
past that the page shows the last result). *Greeting* is the `220` line Postfix
opens every connection with; it must name the hostname, and another name
there is a warning.
- **Notification mail** — whether the DNS records the panel's own mail is
@@ -538,7 +539,8 @@ readings, numbered in the order of what stops mail first:
selector table (`/data/dkim/selectors`), the Postfix sender map, the
inbound relay maps and the filter lists (with `INBOUND_RELAY_ENABLE=true`),
the DMARC report maps (with `DMARC_REPORTS_ENABLE=true`) - removes the keys
of deleted domains, and has Postfix re-read them; the signer needs no
of deleted domains, and has Postfix re-read them (a save elsewhere that
changes no file asks no reload; this button always does); the signer needs no
reload, it reads the table for every message. This is
what the first start after a restore does (see [Restore](#restore)). Use it
if the daemons drifted from what the panel shows after manual edits under