release: 1.2.0: Panel 1.2.0-1.2.5: layout, RBAC, tests, GUI and CI fixes
[1.2.0] The second MINOR after 1.0.0: domain administrators with per-domain scope, a panel visual refresh on the SelfPost palette, and refinements to navigation and the send log. Upgrading runs one SQLite migration (`0005_panel_users`); the single administrator becomes a global user. Added: - panel: **domain-admin role** — global administrators manage panel users and Fixed: - Docker build: `LICENSE` is no longer excluded by `.dockerignore`, so the - panel: on signed-in pages with a narrow card (**Settings**, the user form) Changed: - panel: navigation session icons are distinct — **Settings** uses a gear, - panel: `/` redirects domain administrators to `/domains`; global users still - panel: **Sign out** in the navigation column uses the same type size and - panel: **visual style** brought in line with the SelfPost mark — brick accent - panel: the send log's **status is a badge**, in the same ok/warn/error/unknown … (1 more in CHANGELOG) [1.2.1] Panel refinements after 1.2.0: navigation icons, status-badge centreing, drill-down back-link placement, and safeguards for the sole global administrator. Upgrading is a tag bump; no migration. Fixed: - panel: status badge text sat low in the box (and below the heading or label - panel: the **Users** navigation icon was two full silhouettes with staggered - panel: the **Settings** navigation icon was a sun-with-rays (circle plus - panel: the user create/edit form placed «Back to users» at the bottom of the Changed: - panel: the user edit form disables role change and delete for the only global - panel: the user create/edit form hides **Assigned domains** when the role is - panel: **Settings** shows panel credentials and DMARC aggregate reports side [1.2.2] Status page layout after 1.2.1: paired cards in a wide column, denser machine and check copy, and a user-form checkbox fix. Upgrading is a tag bump; no migration. Changed: - panel: **Status** is wide again so paired cards fill the column. Layout: Fixed: - panel: cards inside `.split` used `margin: 0 auto`, which in a CSS grid - panel: on the user create/edit form, **Assigned domains** checkboxes stacked [1.2.3] Domain detail layout and panel polish after 1.2.2. Upgrading is a tag bump; no migration. Changed: - panel: the domain detail page is wide with paired cards (DKIM+SPF ‖ DMARC; - panel: Domains list — **Add domain** sits beside the domain field; the - panel: page URLs, browser titles, and headings are aligned — **Settings** is Fixed: - image: `mail.log` rotation no longer silently stops when the build context [1.2.4] Level-2 rate-limit semantics inverted after 1.2.3, plus a small DNS field height fix. Upgrading is a tag bump; no migration. Changed: - rate limiting (level 2): domain ceilings apply to every client IP (no IP Fixed: - panel: on the domain DNS status grid, the Type (TXT) field height matches [1.2.5] Rate-limit form polish after 1.2.4. Upgrading is a tag bump; no migration. Changed: - panel: rate-limit forms refined — level-1 backstop as muted copy on the Squashed CHANGELOG sections: [1.2.0], [1.2.1], [1.2.2], [1.2.3], [1.2.4], [1.2.5]. Full detail: CHANGELOG.md (1.2.0, 1.2.1, 1.2.2, 1.2.3, 1.2.4, 1.2.5).
This commit is contained in:
+22
-13
@@ -189,7 +189,7 @@ service healthy and will mail be accepted?"
|
||||
- **Status** (`/status`) — supervised processes (Postfix, OpenDKIM, panel),
|
||||
TLS certificate validity and expiry, milter socket presence, and a short
|
||||
Postfix queue summary. The **Machine** card adds the resource usage of the
|
||||
host underneath — processor (with the load average), memory and swap, and
|
||||
host underneath — processor (core and thread counts), memory and swap, and
|
||||
per-interface network throughput and totals — read from the kernel's
|
||||
counters; CPU and throughput are measured between refreshes, so they appear
|
||||
one refresh after the page opens. A fully busy processor or a machine out of
|
||||
@@ -202,7 +202,8 @@ service healthy and will mail be accepted?"
|
||||
shows after manual edits under `/data`.
|
||||
- **Domains** (`/domains`) — add sending domains, inspect each domain's DKIM
|
||||
TXT value, SPF/DMARC checks, and SASL applications. Per-domain rate limits
|
||||
(level 2) are configured here. *Export domain* writes a single-domain archive;
|
||||
(level 2) and trusted-IP application overrides are configured here.
|
||||
*Export domain* writes a single-domain archive;
|
||||
*Import a domain* on the Backup page reads one back in.
|
||||
- **Deliveries** (`/deliveries`) — searchable send log with server-side filters
|
||||
by domain and application. A row identifies its message and nothing more —
|
||||
@@ -229,7 +230,7 @@ service healthy and will mail be accepted?"
|
||||
- **Backup** (`/backup`) — download a full-server backup; the same page hosts
|
||||
the domain-import form (`POST /domains/import`). See
|
||||
[Backup, restore, and moving a single domain](#backup-restore-and-moving-a-single-domain).
|
||||
- **Settings** (`/account`) — change the administrator username and/or password.
|
||||
- **Settings** (`/settings`) — change the administrator username and/or password.
|
||||
Application SASL logins are separate and are not changed here.
|
||||
|
||||
**Sessions.** A login survives a container restart: sessions live in SQLite, not
|
||||
@@ -269,8 +270,10 @@ docker compose exec selfpost cat /data/setup-token
|
||||
|
||||
## Rate limiting
|
||||
|
||||
SelfPost applies two independent limits; both can refuse a submission, but only
|
||||
level 2 writes a `rejected` row in the send log.
|
||||
SelfPost applies two independent layers; both can refuse a submission, but only
|
||||
level 2 writes a `rejected` row in the send log. Level-2 ceilings set in the
|
||||
panel cannot exceed level 1 (the panel shows the level-1 values and rejects
|
||||
higher numbers).
|
||||
|
||||
**Level 1 (IP backstop)** — always on, configured via `.env`:
|
||||
|
||||
@@ -278,14 +281,20 @@ level 2 writes a `rejected` row in the send log.
|
||||
- `RATE_LIMIT_WINDOW_SECONDS` → Postfix `anvil_rate_time_unit`
|
||||
|
||||
This is an anvil limit per connecting client IP. It keeps working even if the
|
||||
journal-milter (level 2) is down.
|
||||
journal-milter (level 2) is down. There is no per-IP bypass.
|
||||
|
||||
**Level 2 (per domain / per application)** — optional, configured in the panel
|
||||
on each domain's page or on an individual application. You set a message
|
||||
ceiling, a time window, and optionally restrict the limit to specific client
|
||||
IPs; an empty IP list means the differentiated limit does not apply. When
|
||||
exceeded, Postfix returns a 4xx and the refusal is recorded in Deliveries as
|
||||
`rejected`.
|
||||
**Level 2 — domain** — optional, on each domain's page. A message ceiling and
|
||||
window for **every** client IP sending as that domain. When unset, only
|
||||
level 1 applies for non-privileged senders.
|
||||
|
||||
**Level 2 — application (trusted IPs)** — optional override on an application:
|
||||
list one or more client IPs and a ceiling **strictly above** the domain limit
|
||||
(still ≤ level 1). Connections from those IPs use the application ceiling and
|
||||
skip the domain check. Other IPs stay under the domain limit (or level 1 alone).
|
||||
An application override without trusted IPs is inactive.
|
||||
|
||||
When a level-2 ceiling is exceeded, Postfix returns a 4xx and the refusal is
|
||||
recorded in Deliveries as `rejected`.
|
||||
|
||||
## Backup, restore, and moving a single domain
|
||||
|
||||
@@ -381,7 +390,7 @@ but it can look like an open port in external scans.
|
||||
## Fixed image tag
|
||||
|
||||
`deploy/docker-compose.yml` pins an explicit version (`ghcr.io/mixeme/selfpost:X.Y.Z`),
|
||||
deliberately never `:latest`. The current pin is `1.1.0`. Intermediate
|
||||
deliberately never `:latest`. The current pin is `1.2.5`. Intermediate
|
||||
CHANGELOG sections (`0.2.0`…`0.6.0`) record development cuts from before that
|
||||
image was published. Pinning matters because of the backup version check above:
|
||||
the panel binary's embedded version and the image tag that produced it are the
|
||||
|
||||
Reference in New Issue
Block a user