Commit Graph
8 Commits
Author SHA1 Message Date
mixandClaude Opus 5 23d52bab7c fix: port-25 milter chain, DMARC report validation, auto rate-limit window
test / test (push) Has been cancelled
Review pass over the 1.4.0-1.9.1 work.

Port 25 no longer inherits main.cf's submission milter chain: smtpd_milters
is always overridden on smtp/inet, to the antispam milter or to nothing.
Without that, OpenDKIM (strict, tempfail) gated relayed mail during a signing
outage, and the journal-milter filed inbound mail into the outbound send log
under the sender's domain -- so Deliveries showed other people's mail and a
forged From: consumed that domain's level-2 budget. architecture.md already
described the intended behaviour; the code now matches.

DMARC reports are checked before they are stored: the policy domain must be a
configured sending domain, and must match the +tag of a per-domain hosted
address. The rua address form is predictable, so anyone able to reach it could
file reports under any domain and evict genuine ones through the retention cap.
Zip attachments are now decompressed as well as gzip.

The auto level-2 ceiling is scaled to the level-1 window before the multiplier
is applied; any window other than 3600s shifted the allowance by window/3600.

Migration 0010 indexes send_log(app_login, created_at) -- both the per-MAIL
FROM rate-limit count and the per-application statistics were scanning the
created_at range.

e2e now regenerates the Postfix config in-container for all four port-25 flag
combinations and requires postfix check to pass; the 1.9.1 crash-loop shipped
in 1.4.0 and survived three releases because only the flags-off path was
exercised.

Migration 0009 stays as shipped -- its conversion branch only fires for a
database carrying application-scope allowed_ips from before 1.9.0. The schema
reference notes that the old list was permissive and the new column is
restrictive; the guide documents the allow-list as a sending control on a
fail-open path, not an authentication boundary.

Also: gofmt across cmd/ and internal/, unused duplicate validators dropped from
internal/web/validate, export no longer swallows store errors.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-19 14:17:39 +03:00
mixandCursor 909145e5c8 Add send-log retention days to panel Settings.
Global administrators can set delivery journal retention (7-365 days) in SQLite;
SEND_LOG_RETENTION_DAYS seeds the initial default and the log-tailer re-reads
the value every prune cycle without a restart.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-18 21:57:48 +03:00
mixandCursor 705239568b Show this Postfix's retry policy on Mail queue and delivery history.
test / test (push) Has been cancelled
Numbers come from a one-shot postconf -h at panel start so a manual override is visible after restart, without inventing an attempt count.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-17 22:12:03 +03:00
mixandCursor a1e7e05d26 ci: gofmt files that failed the formatting workflow check
test / test (push) Has been cancelled
Whitespace-only alignment from gofmt; removes a stray BOM in web.go.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-13 12:24:34 +03:00
fae0068c4a panel: scope the send log to a domain admin's own domains
test / test (push) Has been cancelled
The Deliveries list narrowed the journal only when exactly one domain was assigned, so an administrator with none or with two or more read every domain's rows. The domain scope is now an IN constraint the store query carries, a filter that states no scope matches nothing, and the domain/app query parameters are validated against the principal before the query runs.

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-13 12:20:51 +03:00
mixandClaude Opus 5 7cc499d57c panel: show the send log's status as a badge
test / test (push) Has been cancelled
The send log was the one place in the panel where a status was bare text, next
to a delivery's own page where the same value is a badge, and a domain list
where the DNS verdict is one too — so a message's outcome looked like a
different kind of fact depending on which page you read it from.

The level travels on the row rather than being worked out in the template:
deliveryLevel is the one place that decides what a status means, the delivery
page already reads it, and a second mapping written into the template or the
stylesheet would have been free to drift from it. sent is ok, deferred a
warning, bounced and rejected errors, and queued unknown — nothing has gone
wrong, nothing has been reported yet.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-11 01:23:52 +03:00
mixandCursor 15baa1e5d0 feat(panel): add domain-admin role with per-domain authorization
test / test (push) Has been cancelled
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-10 23:43:59 +03:00
mixandCursor 155b721438 Split internal/web into subpackages before domain-admin growth.
test / test (push) Has been cancelled
Lay out view, auth, validate, and handlers under internal/web while keeping
the cmd/panel API unchanged; update roadmap and changelog for web-split closure.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-10 23:19:09 +03:00