Close the remaining low-risk items from the full-tree review: rename the settings handler, query assigned domains in SQL, bound the login limiter map, collapse panel.js show/hide helpers, and soften DMARC copy that promised a future in-panel receiver.
Co-authored-by: Cursor <cursoragent@cursor.com>
- internal/web/auth/ratelimit_test.go: the login/setup limiter's ceiling,
per-address scope, window reset and the sweep that keeps finished
buckets out of memory.
- internal/web/auth/handlers_test.go: sign-in (session issued, refusals
that do not reveal which usernames exist, a lockout a correct password
cannot bypass, the setup hint before the first administrator) and the
one-time setup link (creates the first global administrator and then
closes, rejects a wrong or expired token, refuses credentials the panel
would not accept later, rate-limited).
- internal/web/handlers/authz_test.go: every global-only route answers a
domain administrator — and a request with no principal — with 404, with
a positive control so the table cannot pass on a handler that always
404s. This is the check that would have caught the send-log leak.
- test/e2e: CoreDNS pinned to 1.14.6 instead of latest; the level-1
failure message quoted RATE_LIMIT_MESSAGES_PER_IP=5 while the stand
sets 50.
docs/plans/code-review.md P4 checked off except the optional backup-boot
test; CHANGELOG updated. No production code changed.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
The CSRF ADR, guide.md, architecture.md route table, the internal/backup
package comment, roadmap/dmarc-reports admin.dmarc_report_email references,
the e2e coverage summary, and the setupManager/store package comments still
described the pre-1.2.0 single-administrator panel or stale implementation
details. Closes P2 of docs/plans/code-review.md; no behaviour change.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
The level-2 limiter counted stored plus in-flight messages and reserved its own slot in two critical sections, so SMTP sessions that overlapped could each take the last free slot; tryAdmit now does both under one lock. A session that cannot be written no longer yields a cookie the browser would carry while every request bounced to /login. Deleting an application clears its SASL account before its registry row, matching domain delete, so a saslpasswd2 failure leaves a retryable application rather than an account that still authenticates.
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
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>