From ac21180d585f3230131b70508d86f2d7faec34d7 Mon Sep 17 00:00:00 2001 From: Mix Date: Fri, 16 Oct 2026 11:36:54 +0300 Subject: [PATCH] release: 2.8.0: panel-dkim-signing - the panel signs, OpenDKIM gone MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cut at the owner's word (2026-10-16, "Выпускай"). The panel signs outgoing mail in a milter of its own (go-msgauth, relaxed/simple, the login's key on 465/587 and the server's name's on local mail); OpenDKIM, the syslog relay, the USR1 reload and the From: parser port are gone. Keys move to /data/dkim (copied once; /data/opendkim kept for a rollback, left out of backups). The sender check holds Sender: like From:. go-milter is built patched not to keep every header. The queue is handed to Postfix's users by name before "postfix check". Commits 005922b..ca3a183 (005922b, faa3c11, c2f63d2, f0dd9f9, 2cfd239, d9d9af3, 0cceb54, 80faf1a, f1d90a2, ca3a183). On the test server since 2026-10-15 22:48 UTC (2.7.0-post.c2f63d2, now 2.7.0-post.f1d90a2, the same code as this cut): healthy, keys unchanged. The first rollout (faa3c11) crash-looped five minutes on the queue's owner numbers and was rolled back; fixed in c2f63d2. The owner's canary: Gmail dkim/spf/dmarc pass with d=carrel.mixfed.ru, Yandex dkim/spf pass, not spam; his From:/Sender: check, thirteen cases, all as expected. CHANGELOG [2.8.0]; pins in deploy/docker-compose.yml, README and the guide (the guide's rollback command keeps naming 2.7.0 on purpose); development's "from pin"; roadmap row and recommended order; plan stage 3 closed. No tag. Co-Authored-By: Claude Opus 5.5 --- CHANGELOG.md | 9 +++++++++ README.md | 6 +++--- deploy/docker-compose.yml | 2 +- docs/development.md | 2 +- docs/guide.md | 8 ++++---- docs/plans/panel-dkim-signing.md | 19 ++++++++++++++++--- docs/roadmap.md | 4 ++-- 7 files changed, 36 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 03b7a38..47dbd1f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,15 @@ Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/); version ## [Unreleased] +## [2.8.0] - 2026-10-16 + +The panel signs outgoing mail with DKIM itself, and OpenDKIM - a 2018 beta +with open 2026 CVEs - has left the image. Keys, selectors and DNS records do +not change; the first start copies the keys to `/data/dkim`. The sender +check holds a `Sender:` line too. Nothing for an operator to do; a rollback +to 2.7.x needs one command first (guide, § Upgrading). No migration; +schema 11. + ### Added - **The panel signs outgoing mail with DKIM itself** (panel-dkim-signing, diff --git a/README.md b/README.md index 133cab6..b4fd2d7 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.7.0 \ -> -t ghcr.io/mixeme/selfpost:2.7.0 . +> docker build -f build/Dockerfile --build-arg VERSION=2.8.0 \ +> -t ghcr.io/mixeme/selfpost:2.8.0 . > ``` ```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.7.0 + ghcr.io/mixeme/selfpost:2.8.0 ``` **Get the setup URL** (pick one): diff --git a/deploy/docker-compose.yml b/deploy/docker-compose.yml index d57dbd9..d7caefd 100644 --- a/deploy/docker-compose.yml +++ b/deploy/docker-compose.yml @@ -23,7 +23,7 @@ services: selfpost: - image: ghcr.io/mixeme/selfpost:2.7.0 + image: ghcr.io/mixeme/selfpost:2.8.0 restart: unless-stopped environment: SELFPOST_HOSTNAME: "${SELFPOST_HOSTNAME:?set the mail/panel hostname, e.g. mail.example.com}" diff --git a/docs/development.md b/docs/development.md index b426eea..901ba9f 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.7.0`; adjust if semver changes mid-track): +**Planned version cuts** (from pin `2.8.0`; adjust if semver changes mid-track): | Stage | ID | Cut | |---|---|---| diff --git a/docs/guide.md b/docs/guide.md index 891b476..02ca053 100644 --- a/docs/guide.md +++ b/docs/guide.md @@ -204,14 +204,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.7.0`. **No 2.x image is +deliberately never `:latest`. The current pin is `2.8.0`. **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.7.0 \ - -t ghcr.io/mixeme/selfpost:2.7.0 . +docker build -f build/Dockerfile --build-arg VERSION=2.8.0 \ + -t ghcr.io/mixeme/selfpost:2.8.0 . ``` `VERSION` must equal the tag: it is the version the backup check compares @@ -934,7 +934,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.6.1 but this image is 2.7.0 — restore into the matching image (selfpost:2.6.1) +backup: this backup was created by SelfPost 2.7.0 but this image is 2.8.0 — restore into the matching image (selfpost:2.7.0) ``` Fix the tag in `docker-compose.yml` (build that tag as under [Fixed image diff --git a/docs/plans/panel-dkim-signing.md b/docs/plans/panel-dkim-signing.md index e09c3ca..8e8af34 100644 --- a/docs/plans/panel-dkim-signing.md +++ b/docs/plans/panel-dkim-signing.md @@ -1,6 +1,6 @@ # Plan: panel-dkim-signing -**Status:** agreed, 2026-10-15 - the row is agreed (owner, 2026-10-15, the +**Status:** shipped `2.8.0` (2026-10-16); agreed 2026-10-15 - the row is agreed (owner, 2026-10-15, the order port25-bare-newline -> base-trixie -> panel-dkim-signing); three questions below were settled one at a time the same day. **Date:** 2026-10-15 @@ -214,10 +214,23 @@ documents in the commit after it. `Sender:` is held to the login like v0.4.1 kept every header in a map of its own per session, on 465/587 and on port 25 alike: the panel builds it patched not to (`third_party/go-milter/PATCHES.md`; the owner's decision, 2026-10-16). -- [ ] On the test server: a day of the owner's mail; one message from an +- [x] On the test server: a day of the owner's mail; one message from an application through 465 and one notification to a real mailbox, the headers read (dkim=pass with the panel's `d=`). -- [ ] Cut `2.8.0`. +- [x] Cut `2.8.0`. + +*Done (2026-10-16):* the owner's message through 465 (`dev/send-check.ps1`) +arrived at Gmail with `dkim=pass header.i=@carrel.mixfed.ru +header.s=selfpost`, `spf=pass`, `dmarc=pass`, and at Yandex with +`dkim=pass` and `X-Yandex-Spam: 1`; its `h=` over-signs the shown headers. +His `dev/from-check.ps1` sent thirteen `From:`/`Sender:` cases: four +accepted and delivered, nine refused as expected, each a send-log row of +reason `from` or `sender`. The notification to a real mailbox was not +sent - nothing raised one; its signature is verified by dkimpy on every e2e +run, and the server name's key, unchanged by the move (digests compared), +matched its published record on 2026-10-15. The day of mail was cut short +at the owner's word ("Выпускай", 2026-10-16), the test server having run +the stage's code since 2026-10-15 22:48 UTC. Cut as `2.8.0`, no tag. ## Risks diff --git a/docs/roadmap.md b/docs/roadmap.md index bb021a5..6be676d 100644 --- a/docs/roadmap.md +++ b/docs/roadmap.md @@ -45,7 +45,7 @@ in `git log` and [CHANGELOG.md](../CHANGELOG.md). | own-mta-builds | Analysis: build Postfix and OpenDKIM ourselves, patched, instead of Debian's packages | analysed 2026-10-15: no own builds; three rows proposed instead | — | [own-mta-builds-2026-10-15.md](own-mta-builds-2026-10-15.md) | | port25-bare-newline | The inbound relay's port 25 refuses bare newlines in DATA (`smtpd_forbid_bare_newline=normalize`) | shipped `2.6.1` | — | — | | base-trixie | The image's base from Debian bookworm (LTS since 2026-07-12) to trixie: Postfix 3.10 with the 2026 security batches | shipped `2.7.0` | — | — | -| panel-dkim-signing | DKIM signing in the panel's own milter; OpenDKIM, the syslog relay and the parser port removed | agreed (2026-10-15; stages 1-2 done, documents and reviews) | 12/14 | [plans/panel-dkim-signing.md](plans/panel-dkim-signing.md) | +| panel-dkim-signing | DKIM signing in the panel's own milter; OpenDKIM, the syslog relay and the parser port removed | shipped `2.8.0` | 14/14 | [plans/panel-dkim-signing.md](plans/panel-dkim-signing.md) | | phone-desktop-mode | A phone browser in "desktop site" mode gets the phone navigation | agreed (2026-10-13: after stages 1 and 2 of audit-2026-10-12) | — | — | | 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) | @@ -64,7 +64,7 @@ stages 1 and 2 as `2.5.0` the same day, stage 2b as `2.5.1`, stage 2c as `2.6.0` the same day; stage 6 (documents and tests, no cut) closed the audit. Of the three rows from [own-mta-builds](#own-mta-builds), **port25-bare-newline** shipped as `2.6.1` the same day and -**base-trixie** as `2.7.0`; panel-dkim-signing follows. What is agreed after it is marked so in the index; every other +**base-trixie** as `2.7.0`, and **panel-dkim-signing** as `2.8.0` (2026-10-16). What is agreed after it is marked so in the index; every other remaining item is a candidate. panel-docs shipped in [CHANGELOG.md](../CHANGELOG.md) `[1.8.0]`; dmarc-reports in `[1.7.0]` (its ingest path first ran in `2.0.0` and was reviewed on 2026-10-11, see