From d6ed6bcb30cc895d5b414361c2185d774bae33af Mon Sep 17 00:00:00 2001 From: Mix Date: Thu, 15 Oct 2026 12:51:50 +0300 Subject: [PATCH] release: 2.5.4: audit stage 4 - panel behaviour Cut without asking, as the owner said on 2026-10-15. Signing in costs the same for an unknown name (M8) and ends the session the browser presented (L16); the Account password check has its own limit (L15). The HTTP server bounds the request, the answer and idle connections; the full backup moves its own deadline (L14). Monitoring refreshes are scheduled from htmx:afterRequest with a back-off and a 30 s timeout, and a lost session sends htmx to sign-in (M11). The Outbound log clamps its page (L10) and filters by status and day; the multiplier refuses NaN (L11); a rate-limited refusal is red (L18); Recalculate asks before it drops an unsaved edit (L19); Reload configuration writes what a restore writes and removes the keys of deleted domains (L13, L17). The cards layout orders by number. A notification is owed to each recipient (migration 0011). A DNS outage is unknown, each resolver with its own time (M14, M15). DMARC reports too large are refused for their size. An inbound upstream has one TLS mode, changed for all its domains (L5). Plus the findings of both reviews (eaa7de0). Commits 07be0cf, 643892a, ca876c1, 80e3979, 2b8e0c0, b90a2f0, eee089a, 006bed7, 32dfe4a, eaa7de0. Rolled out to the test server as 2.5.3-post.eaa7de0 (the same code): migration 0011 applied, schema 11; all programs RUNNING, the container healthy. Resync's key cleanup checked against the live data: every key directory is a domain's or the hostname's, nothing to remove. CHANGELOG cut; pin 2.5.4 in deploy/docker-compose.yml, README, guide (and its sample restore message); development.md "from pin" and the stage's row; roadmap row and recommended order; stage 4 marked shipped in the plan. No tag. Co-Authored-By: Claude Opus 5.5 --- CHANGELOG.md | 9 ++++++++- README.md | 6 +++--- deploy/docker-compose.yml | 2 +- docs/audit-2026-10-12.md | 2 +- docs/development.md | 4 ++-- docs/guide.md | 8 ++++---- docs/roadmap.md | 5 +++-- 7 files changed, 22 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6db0d6f..fd051a3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,14 @@ Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/); version ## [Unreleased] -Migration `0011` (a table, nothing existing changes). +## [2.5.4] - 2026-10-15 + +Stage 4 of the 2026-10-12 audit: the panel's behaviour. Signing in tells +nothing by its timing and ends a planted session; the server bounds its +connections; monitoring pages recover from a failed refresh; the Outbound +log filters by status and by day; a notification is owed to each recipient; +a DNS outage is unknown, not wrong; Reload configuration writes everything a +restore writes. Migration `0011` (a table, nothing existing changes). ### Added diff --git a/README.md b/README.md index ff56243..9b5b5af 100644 --- a/README.md +++ b/README.md @@ -112,8 +112,8 @@ outbound mail will not reach the real internet without DNS, PTR, and port 25. > local image and pulls nothing: > > ```sh -> docker build -f build/Dockerfile --build-arg VERSION=2.5.3 \ -> -t ghcr.io/mixeme/selfpost:2.5.3 . +> docker build -f build/Dockerfile --build-arg VERSION=2.5.4 \ +> -t ghcr.io/mixeme/selfpost:2.5.4 . > ``` ```sh @@ -122,7 +122,7 @@ docker run --rm -d --name selfpost-try \ -e SELFPOST_HOSTNAME=mail.local.test \ -e PANEL_COOKIE_SECURE=false \ -v selfpost-try-data:/data \ - ghcr.io/mixeme/selfpost:2.5.3 + ghcr.io/mixeme/selfpost:2.5.4 ``` **Get the setup URL** (pick one): diff --git a/deploy/docker-compose.yml b/deploy/docker-compose.yml index 56092cb..726a54a 100644 --- a/deploy/docker-compose.yml +++ b/deploy/docker-compose.yml @@ -23,7 +23,7 @@ services: selfpost: - image: ghcr.io/mixeme/selfpost:2.5.3 + image: ghcr.io/mixeme/selfpost:2.5.4 restart: unless-stopped environment: SELFPOST_HOSTNAME: "${SELFPOST_HOSTNAME:?set the mail/panel hostname, e.g. mail.example.com}" diff --git a/docs/audit-2026-10-12.md b/docs/audit-2026-10-12.md index b682fae..80cf624 100644 --- a/docs/audit-2026-10-12.md +++ b/docs/audit-2026-10-12.md @@ -1183,7 +1183,7 @@ for the milter sockets; a CLI killed by SIGKILL cannot clean its temporary file, and a handler for the gentler signals buys little for a one-off command whose leftover is the owner's alone. -### Stage 4 — panel behaviour (M8, M11, L10–L19) → `2.5.4` +### Stage 4 — panel behaviour (M8, M11, L10–L19) → `2.5.4` (shipped 2026-10-15) - [x] Login: dummy bcrypt on unknown user; a test that measures both paths within a tolerance. Account password change gets its own limiter bucket. Login diff --git a/docs/development.md b/docs/development.md index 4506958..bd05a3d 100644 --- a/docs/development.md +++ b/docs/development.md @@ -107,7 +107,7 @@ than the default «meaningful step» rule in [§ Commits and release build](#com 2. Git tag `vX.Y.Z` and publish the GitHub Release only on explicit request (see [§ Release image](#release-image)). -**Planned version cuts** (from pin `2.5.3`; adjust if semver changes mid-track): +**Planned version cuts** (from pin `2.5.4`; adjust if semver changes mid-track): | Stage | ID | Cut | |---|---|---| @@ -135,7 +135,7 @@ than the default «meaningful step» rule in [§ Commits and release build](#com | 22 | audit-2026-10-12 stage 2b: the log tailer | `2.5.1` | | 23 | audit-2026-10-12 stage 2c: the sender check reads From: as OpenDKIM does | `2.5.2` | | 24 | audit-2026-10-12 stage 3: persistence and restore | `2.5.3` | -| 25 | audit-2026-10-12 stage 4 | `2.5.4` | +| 25 | audit-2026-10-12 stage 4: panel behaviour | `2.5.4` | | 26 | audit-2026-10-12 stage 5 | `2.6.0` | Docs-only prep (checklists in plans, no product code) uses the same per-step diff --git a/docs/guide.md b/docs/guide.md index 7ecd7a1..853540e 100644 --- a/docs/guide.md +++ b/docs/guide.md @@ -190,14 +190,14 @@ cat ./data/setup-token #### 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 `2.5.3`. **No 2.x image is +deliberately never `:latest`. The current pin is `2.5.4`. **No 2.x image is published on ghcr.io yet** (the newest there is `1.3.0`); until one is, build it from the checkout under the pinned name, and Compose uses the local image instead of pulling: ```sh -docker build -f build/Dockerfile --build-arg VERSION=2.5.3 \ - -t ghcr.io/mixeme/selfpost:2.5.3 . +docker build -f build/Dockerfile --build-arg VERSION=2.5.4 \ + -t ghcr.io/mixeme/selfpost:2.5.4 . ``` `VERSION` must equal the tag: it is the version the backup check compares @@ -861,7 +861,7 @@ A version mismatch at step 5 refuses to start and leaves `/data` untouched — the panel exits with a message naming the tag to use, e.g.: ``` -backup: this backup was created by SelfPost 2.5.2 but this image is 2.5.3 — restore into the matching image (selfpost:2.5.2) +backup: this backup was created by SelfPost 2.5.3 but this image is 2.5.4 — restore into the matching image (selfpost:2.5.3) ``` Fix the tag in `docker-compose.yml` (build that tag as under [Fixed image diff --git a/docs/roadmap.md b/docs/roadmap.md index 1eac961..7f21999 100644 --- a/docs/roadmap.md +++ b/docs/roadmap.md @@ -45,7 +45,7 @@ in `git log` and [CHANGELOG.md](../CHANGELOG.md). | from-header-binding | Hold a message's `From:` header against the application that sends it | shipped `2.4.0` | 9/9 | [plans/from-header-binding.md](plans/from-header-binding.md) | | panel-redesign | Panel redesign (accepted mockups, design contract) | shipped `2.0.0` | 27/27 | [plans/panel-redesign.md](plans/panel-redesign.md) | | schema-squash | Squash SQLite migrations into a 2.x baseline | built in panel-redesign (stage 1) | — | [plans/panel-redesign.md](plans/panel-redesign.md) | -| audit-2026-10-12 | Follow-ups of the 2026-10-12 full-tree code audit, seven stages | in progress (stage 0 shipped `2.4.2`, stages 1+2 `2.5.0`, 2b `2.5.1`, 2c `2.5.2`, 3 `2.5.3`; next stage 4 → `2.5.4`) | 68/81 | [audit-2026-10-12.md](audit-2026-10-12.md) | +| audit-2026-10-12 | Follow-ups of the 2026-10-12 full-tree code audit, seven stages | in progress (stage 0 shipped `2.4.2`, stages 1+2 `2.5.0`, 2b `2.5.1`, 2c `2.5.2`, 3 `2.5.3`, 4 `2.5.4`; next stage 5 → `2.6.0`) | 68/81 | [audit-2026-10-12.md](audit-2026-10-12.md) | **Recommended order** (not binding; owner, 2026-10-09: feature order follows development convenience): **panel-redesign** shipped as `2.0.0` (2026-10-11) and @@ -55,7 +55,8 @@ shipped as `2.2.0` the same day, **panel-notifications** as `2.3.0` and **from-header-binding** as `2.4.0`. Stage 0 of [audit-2026-10-12](audit-2026-10-12.md) shipped as `2.4.2` (2026-10-14), its stages 1 and 2 as `2.5.0` the same day, stage 2b as `2.5.1`, stage 2c as -`2.5.2` (2026-10-15), and stage 3 as `2.5.3` the same day. +`2.5.2` (2026-10-15), and stages 3 and 4 as `2.5.3` and `2.5.4` the same +day. Nothing is agreed after it: every remaining item is a candidate. panel-docs shipped in [CHANGELOG.md](../CHANGELOG.md) `[1.8.0]`; dmarc-reports in `[1.7.0]`