feat(mail): channel → nixos-26.05 #132

Merged
dominik.polakovics merged 1 commit from afk/107 into main 2026-06-08 10:39:18 +02:00

Bumps hosts/mail/channel to nixos-26.05 and ports the mail stack to the 26.05 module shapes. Minimal diff: channel flip + the forced module migrations. stateVersion stays 22.11. Only hosts/mail/ is touched, so the still-25.11 hosts (web-arm, amzebs-01) are unaffected.

Key finding: dovecot stays on 2.3

26.05's services.dovecot2 gates the default package on stateVersion, not the channel: >= 26.05 → dovecot (2.4.4), else dovecot_2_3 (2.3.21.1). mail is 22.11, so it stays on dovecot 2.3 — the raw 2.3 config is unchanged, only relocated. (A 2.4 move would be a separate change: explicit package + a 2.3→2.4 config rewrite.)

Changes

dovecot (26.05 rewrote the module, RFC-42 style):

  • enableImap/enableLmtp/mailLocation removed; mailUser/mailGroup/protocols renamed → settings.{protocols,mail_location,mail_uid,mail_gid}. The module still auto-creates the vmail user/group from mail_uid/mail_gid, as before.
  • extraConfig + mailboxes removed → raw 2.3 config relocated verbatim into !include-d files (includeFiles), ordered mkBefore (main) / mkAfter (rspamd) to preserve the 25.11 concat order (global mail_plugins before the protocol{} filters).
  • Reproduced 3 base settings 26.05 no longer auto-emits: service auth { user = root }, disable_plaintext_auth = no, pop3_uidl_format.
  • Dropped sieve.extensions (was overridden by extraConfig → already a no-op; keeping it would flip the effective value on 26.05).
  • settings.mail_plugins = mkForce null to drop the module's redundant trailing mail_plugins line (avoids a benign "won't change earlier filter" warning).
  • Pigeonhole ABI fix: pkgs.dovecot_pigeonhole now tracks the default dovecot 2.4; switched to config.services.dovecot2.package.dovecot_pigeonhole (0.5.21.1) so the 2.3 runtime loads matching sieve modules. Uncaught by eval/build — would have broken sieve/managesieve at runtime.
  • LDAP passdb/userdb wiring unchanged (both ldap.conf files still generated in preStart with the sops password; driver = ldap).

postfix (RFC-42 rewrite): configsettings.main, masterConfigsettings.master, hostname/domainsettings.main.{myhostname,mydomain} (upstream renames, values unchanged). IPv4 outbound pin (#97) + ADR-0016 TLS hardening preserved verbatim. sslCert/sslKey removed upstream but unused → N/A.

rspamd → 4.0.1: no module-option changes needed; only the dovecot integration moved (as above).

Validation (beyond the eval-only pre-commit gate)

  • Full mail system-closure nix-build on 26.05.
  • dovecot: doveconf -n of the generated config is byte-identical to the 25.11 config, on dovecot 2.3.21.1.
  • postfix: generated main.cf + master.cf are byte-identical to 25.11 and parse on postfix 3.11.3. (3.11 now warns that smtpd_use_tls / smtpd_tls_dh1024_param_file are deprecated — both still honoured; left as-is to avoid touching the hardened TLS config, a separate modernisation.)
  • rspamd: rspamadm configtest on 4.0.1 loads every module (dkim_signing, arc, dmarc, neural, phishing, milter_headers, bayes) + the controller password hash.
  • No insecure allowance needed — eval is clean (mail pulls no fish/Rust package that trips 26.05's pypy2.7 guard, unlike nb/nas/fw).

⚠ Deploy note (for the human landing)

bento auto-switches + restarts dovecot/postfix on deploy. A config-syntax break would deploy cleanly then kill the service on restart — land with a console ready, and consider pausing mail's bento-upgrade and deploying by hand. The keystone reboot + runtime verification (fleet-wide LDAP auth, real IMAP/SMTP, spam filtering) is the paired verify #108.

Closes #107

Bumps `hosts/mail/channel` to nixos-26.05 and ports the mail stack to the 26.05 module shapes. Minimal diff: channel flip + the forced module migrations. `stateVersion` stays `22.11`. Only `hosts/mail/` is touched, so the still-25.11 hosts (web-arm, amzebs-01) are unaffected. ## Key finding: dovecot stays on 2.3 26.05's `services.dovecot2` gates the default package on `stateVersion`, **not** the channel: `>= 26.05 → dovecot (2.4.4)`, else `dovecot_2_3 (2.3.21.1)`. mail is `22.11`, so it **stays on dovecot 2.3** — the raw 2.3 config is unchanged, only relocated. (A 2.4 move would be a separate change: explicit package + a 2.3→2.4 config rewrite.) ## Changes **dovecot** (26.05 rewrote the module, RFC-42 style): - `enableImap`/`enableLmtp`/`mailLocation` removed; `mailUser`/`mailGroup`/`protocols` renamed → `settings.{protocols,mail_location,mail_uid,mail_gid}`. The module still auto-creates the vmail user/group from `mail_uid`/`mail_gid`, as before. - `extraConfig` + `mailboxes` removed → raw 2.3 config relocated **verbatim** into `!include`-d files (`includeFiles`), ordered `mkBefore` (main) / `mkAfter` (rspamd) to preserve the 25.11 concat order (global `mail_plugins` before the `protocol{}` filters). - Reproduced 3 base settings 26.05 no longer auto-emits: `service auth { user = root }`, `disable_plaintext_auth = no`, `pop3_uidl_format`. - Dropped `sieve.extensions` (was overridden by extraConfig → already a no-op; keeping it would flip the effective value on 26.05). - `settings.mail_plugins = mkForce null` to drop the module's redundant trailing `mail_plugins` line (avoids a benign "won't change earlier filter" warning). - **Pigeonhole ABI fix**: `pkgs.dovecot_pigeonhole` now tracks the default dovecot 2.4; switched to `config.services.dovecot2.package.dovecot_pigeonhole` (0.5.21.1) so the 2.3 runtime loads matching sieve modules. **Uncaught by eval/build** — would have broken sieve/managesieve at runtime. - LDAP passdb/userdb wiring unchanged (both `ldap.conf` files still generated in preStart with the sops password; `driver = ldap`). **postfix** (RFC-42 rewrite): `config`→`settings.main`, `masterConfig`→`settings.master`, `hostname`/`domain`→`settings.main.{myhostname,mydomain}` (upstream renames, values unchanged). IPv4 outbound pin (#97) + ADR-0016 TLS hardening preserved verbatim. `sslCert`/`sslKey` removed upstream but unused → N/A. **rspamd** → 4.0.1: no module-option changes needed; only the dovecot integration moved (as above). ## Validation (beyond the eval-only pre-commit gate) - ✅ Full mail system-closure `nix-build` on 26.05. - ✅ **dovecot**: `doveconf -n` of the generated config is **byte-identical** to the 25.11 config, on dovecot 2.3.21.1. - ✅ **postfix**: generated `main.cf` + `master.cf` are **byte-identical** to 25.11 and parse on postfix 3.11.3. (3.11 now warns that `smtpd_use_tls` / `smtpd_tls_dh1024_param_file` are deprecated — both still honoured; left as-is to avoid touching the hardened TLS config, a separate modernisation.) - ✅ **rspamd**: `rspamadm configtest` on 4.0.1 loads every module (dkim_signing, arc, dmarc, neural, phishing, milter_headers, bayes) + the controller password hash. - No insecure allowance needed — eval is clean (mail pulls no fish/Rust package that trips 26.05's pypy2.7 guard, unlike nb/nas/fw). ## ⚠ Deploy note (for the human landing) bento auto-switches + restarts dovecot/postfix on deploy. A config-*syntax* break would deploy cleanly then kill the service on restart — land with a console ready, and consider pausing mail's `bento-upgrade` and deploying by hand. The keystone reboot + runtime verification (fleet-wide LDAP auth, real IMAP/SMTP, spam filtering) is the paired verify **#108**. Closes #107
Bump hosts/mail/channel to nixos-26.05 and port the mail stack to the 26.05
module shapes. Diff is the channel flip plus the forced module migrations;
behaviour is unchanged, verified by diffing the generated service configs
against the 25.11 ones. stateVersion stays 22.11.

Dovecot — the headline; 26.05 rewrote services.dovecot2 (RFC-42 style):

- stateVersion 22.11 < 26.05, so the module's package default resolves to
  pkgs.dovecot_2_3 (2.3.21.1), NOT the new 2.4 default. dovecot stays on 2.3,
  so the raw config is unchanged — only relocated. (Moving to 2.4 would be a
  separate change: explicit package + a 2.3→2.4 config rewrite.)
- enableImap/enableLmtp/mailLocation removed; mailUser/mailGroup/protocols
  renamed under `settings`. Ported to settings.{protocols,mail_location,
  mail_uid,mail_gid}. The module still auto-creates the vmail user/group from
  mail_uid/mail_gid (createMailUser defaults true), as the 25.11 module did.
- extraConfig removed (both this module's blob and rspamd's appended blob, plus
  mailboxes.Spam). The raw 2.3 config moves verbatim into !include-d files via
  the new `includeFiles` option, ordered mkBefore (main) / mkAfter (rspamd) so
  the global mail_plugins is defined before the protocol{} filters — the exact
  ordering the merged 25.11 extraConfig produced.
- Three base settings the 25.11 module auto-emitted but 26.05's does not are
  reproduced in the include: `service auth { user = root }`,
  `disable_plaintext_auth = no`, and `pop3_uidl_format`.
- sieve.extensions dropped: 25.11 rendered it into a plugin block that the
  extraConfig plugin then overrode (already a no-op); on 26.05 it would render
  after the include and win, changing the effective sieve_extensions. The
  include stays authoritative (+vacation +vacation-seconds +editheader).
- settings.mail_plugins = mkForce null: drops the module's redundant trailing
  `mail_plugins = $mail_plugins` (emitted after the !include), which otherwise
  logs a benign "won't change the setting inside an earlier filter" warning.
- Pigeonhole version match: pkgs.dovecot_pigeonhole now tracks the default
  dovecot (2.4.4); loading 2.4 sieve modules into the 2.3 runtime is an ABI
  mismatch that breaks sieve/managesieve at runtime (uncaught by eval/build).
  systemPackages and the rspamd sievec call now use
  config.services.dovecot2.package.dovecot_pigeonhole (0.5.21.1, matches 2.3).
- LDAP auth wiring unchanged: both /run/dovecot2/ldap{,-fallback}.conf are still
  generated in the dovecot preStart with the sops password injected; userdb/
  passdb still driver = ldap.
- Validated: doveconf -n on the built config is byte-identical to the 25.11
  config on dovecot 2.3.21.1.

Postfix — 26.05 RFC-42 rewrite of services.postfix:

- config → settings.main, masterConfig → settings.master, hostname →
  settings.main.myhostname, domain → settings.main.mydomain (upstream renames).
  Values unchanged; the IPv4 outbound pin (#97) and ADR-0016 TLS hardening are
  preserved verbatim.
- sslCert/sslKey were removed upstream but mail never used them (TLS via the raw
  smtpd_tls_*_file keys) — N/A.
- Validated: the generated main.cf and master.cf are byte-identical to 25.11 and
  parse on postfix 3.11.3. postfix 3.11 emits deprecation warnings for
  smtpd_use_tls and smtpd_tls_dh1024_param_file (both still honoured); left as-is
  to avoid touching the hardened TLS config — a separate modernisation.

rspamd — package bumps to 4.0.1:

- No module-option changes needed (enable/extraConfig/locals/workers/
  postfix.enable unchanged on 26.05). Only the dovecot integration moved
  (mailboxes.Spam + extraConfig → includeFiles, as above).
- Validated: rspamadm configtest on 4.0.1 loads every module (dkim_signing, arc,
  dmarc, neural, phishing, milter_headers, bayes) and the controller password.

No insecure allowance needed: eval is clean — mail pulls no fish/Rust package
that trips 26.05's pypy2.7 makePythonWriter guard (unlike nb/nas/fw).

Closes #107
Author
Owner

This was generated by AI while landing a PR.

Validation: PASS — landing now.

  • Verification signal: the pre-commit dry-build gates eval (clean here — no insecure allowance needed). Eval does not cover build-time, so I relied on the author's build validation: full mail system-closure nix-build on 26.05, doveconf -n byte-identical to the 25.11 config on dovecot 2.3.21.1, postfix main.cf/master.cf byte-identical, rspamadm configtest loads every module. I did not independently reproduce the nix-build.
  • Diff review: faithful RFC-42 migration — the three lines 25.11 auto-emitted but 26.05 drops (service auth { user = root }, disable_plaintext_auth = no, pop3_uidl_format) are reproduced; pigeonhole pinned to cfg.package.dovecot_pigeonhole (dovecot stays 2.3 via the stateVersion gate); mail_uid/mail_gid rename consistent with rspamd's chown; the IPv4 outbound pin (#97) and ADR-0016 TLS hardening preserved verbatim.
  • Conventions: Conventional-Commits title ✓; touches only hosts/mail/; no secrets.yaml edits; stateVersion unchanged (22.11); Closes #107 present.

⚠️ Deploy-on-merge: this merge triggers CD → bento on mail runs nixos-rebuild switch within ~5 min and restarts dovecot/postfix. A config-syntax break would deploy clean then kill the service on restart. The runtime keystone verify (fleet LDAP auth, real IMAP/SMTP, spam filtering) is the paired #108.

Merging via merge-commit.

> *This was generated by AI while landing a PR.* **Validation: PASS** — landing now. - **Verification signal:** the pre-commit dry-build gates *eval* (clean here — no insecure allowance needed). Eval does **not** cover build-time, so I relied on the author's build validation: full mail system-closure `nix-build` on 26.05, `doveconf -n` **byte-identical** to the 25.11 config on dovecot 2.3.21.1, postfix `main.cf`/`master.cf` byte-identical, `rspamadm configtest` loads every module. I did **not** independently reproduce the nix-build. - **Diff review:** faithful RFC-42 migration — the three lines 25.11 auto-emitted but 26.05 drops (`service auth { user = root }`, `disable_plaintext_auth = no`, `pop3_uidl_format`) are reproduced; pigeonhole pinned to `cfg.package.dovecot_pigeonhole` (dovecot stays 2.3 via the stateVersion gate); `mail_uid`/`mail_gid` rename consistent with rspamd's chown; the IPv4 outbound pin (#97) and ADR-0016 TLS hardening preserved verbatim. - **Conventions:** Conventional-Commits title ✓; touches only `hosts/mail/`; no `secrets.yaml` edits; `stateVersion` unchanged (22.11); `Closes #107` present. ⚠️ **Deploy-on-merge:** this merge triggers CD → bento on `mail` runs `nixos-rebuild switch` within ~5 min and restarts dovecot/postfix. A config-*syntax* break would deploy clean then kill the service on restart. The runtime keystone verify (fleet LDAP auth, real IMAP/SMTP, spam filtering) is the paired **#108**. Merging via merge-commit.
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
Cloonar/nixos!132
No description provided.