feat(mail): build dovecot 2.3 with GSSAPI #293

Merged
dominik.polakovics merged 1 commit from afk/290 into main 2026-08-07 23:41:55 +02:00

Builds Dovecot 2.3 with GSSAPI on mail. Package change only — inert until the follow-up enables the mechanism.

grep -rn 'auth_mechanisms\|auth_krb5_keytab\|auth_username_format' --include=*.nix over the repo returns nothing, so no config references GSSAPI and nothing about IMAP/SMTP auth changes.

Why an overlay, and why it must replace the attribute

.override cannot help — nixpkgs' pkgs/by-name/do/dovecot/generic.nix exposes no withGSSAPI argument — so the derivation's attributes are extended instead.

The override has to replace the pkgs.dovecot_2_3 attribute rather than sit inline on services.dovecot2.package, and this is the pigeonhole trap the issue flags. In pkgs/top-level/all-packages.nix:

dovecot_2_3 = callPackage ../by-name/do/dovecot/2.3.nix { dovecot_pigeonhole = dovecot_pigeonhole_0_5; };
dovecot_pigeonhole_0_5 = callPackage ../by-name/do/dovecot_pigeonhole/0.5.nix { dovecot = dovecot_2_3; };

all-packages.nix is res: pkgs: super:with pkgs;, and pkgs is the final overlaid fixpoint (lib.extends is final: let prev = f final; …, and allPackages sits below overlays in stage.nix's toFix). So replacing the attribute makes dovecot_pigeonhole_0_5 rebuild against the overridden dovecot, and passthru.dovecot_pigeonhole — which overrideAttrs leaves untouched — resolves to that same rebuilt pigeonhole. An inline overrideAttrs at the use site would instead leave the passthru pointing at pigeonhole built against the un-overridden dovecot, which is the version mismatch that broke sieve/managesieve on this host once before.

No eval cycle: passthru is in argumentAttrsToRemove in make-derivation.nix, so it is stripped before derivationArg and forcing dovecot's drvPath never forces it. The dovecot↔pigeonhole mutual reference already exists in unmodified nixpkgs; this replaces a node, it adds no edge.

Two call sites ride on this, not one — the issue names hosts/mail/modules/dovecot.nix:263, and hosts/mail/modules/rspamd.nix:157 also runs ${config.services.dovecot2.package.dovecot_pigeonhole}/bin/sievec in dovecot's preStart to compile the spam-filter scripts. Both take the same passthru, so both stay consistent.

Deviation from the issue's stated scope: krb5 also in nativeBuildInputs

The issue specifies krb5 in buildInputs + --with-gssapi=yes. That alone does not compile, and the failure is at configure time. Four facts, all from the pinned channel rev 445d861c:

  1. pkgs/by-name/do/dovecot/generic.nix:231strictDeps = true;
  2. pkgs/stdenv/generic/setup.sh:850if [[ -z "${strictDeps-}" || "$hostOffset" -le -1 ]]; then addToSearchPath _PATH "$pkg/bin". With strictDeps set, only nativeBuildInputs (hostOffset ≤ -1) reach PATH; buildInputs go to _HOST_PATH, which is never folded into PATH.
  3. pkgs/by-name/kr/krb5/package.nix:157moveToOutput bin/krb5-config "$dev".
  4. dovecot 2.3.21.1 m4/want_gssapi.m4 detects GSSAPI only via AC_CHECK_PROG(KRB5CONFIG, krb5-config, krb5-config, NO) — a bare $PATH walk, no pkg-config, no direct lib probe — and on NO with want_gssapi != auto raises AC_ERROR([Can't build with GSSAPI support: krb5-config not found]).

So --with-gssapi=yes makes a missing krb5-config a hard error. Adding krb5 to nativeBuildInputs fixes it: make-derivation.nix:559,715 maps getDev over that list, so it resolves to krb5.dev, whose bin/ holds krb5-config. This mirrors openssh's withKerberos in nixpkgs, which puts krb5 in both lists for exactly this reason. buildInputs is still needed — that is what supplies gssapi/gssapi.h and the link inputs.

Note --with-gssapi=<path> is not an option: dovecot's TEST_WITH macro accepts only yes|no|auto|plugin and AC_ERRORs on a path.

=yes is correct for the issue's verification step — want_gssapi != plugin takes the AUTH_LIBS="$AUTH_LIBS $KRB5_LIBS" + AC_DEFINE(BUILTIN_GSSAPI) branch, linking GSSAPI into libexec/dovecot/auth rather than emitting a separate .so.

pkgs.krb5 is already in mail's closure (hosts/mail/modules/kerberos.nix sets security.krb5.package = pkgs.krb5 and runs the KDC), so this adds no new component.

configureFlags uses ++, preserving --with-lucene (the host's mail_plugins includes fts_lucene), --with-ldap, --with-systemd and --with-moduledir. An assignment there would have broken the host.

Blast radius

mail previously had no nixpkgs.overlays at all; the new list contains only this overlay and deliberately does not pull in utils/overlays/packages.nix. No other host uses dovecot, so the overlay stays host-local — putting it in utils/ would drag every host through the pre-commit dry-build for nothing.

version is untouched, so the module's isPre24 = versionOlder cfg.package.version "2.4" gate and every 2.3-shaped default stay exactly as they are. Postfix, the dovecot exporter and hosts/mail/pkgs/sieve-spam-filter are unaffected. Expect dovecot and pigeonhole to be binary-cache misses and compile on the host, and dovecot to restart on the deploy (the preStart store path changes).

Verification — please read

The dry-build gate did not run. This branch was prepared in an environment with no Nix (/nix absent, nix-instantiate not on PATH), so scripts/pre-commit / scripts/test-configuration mail could not execute — test-configuration exits early on its own command -v nix-instantiate check. Everything above is static verification against the pinned channel rev, not a build. Please run ./scripts/test-configuration mail before merging.

After deploy, the issue's gate for starting the follow-up:

  1. The auth binary links GSSAPI:
    a=$(find /nix/store -maxdepth 4 -path '*dovecot-2*/libexec/dovecot/auth' | head -1)
    ldd "$a" | grep -iE 'gss|krb5'
    
  2. Pigeonhole was rebuilt against the override — readlink -f $(command -v sieve-test) must resolve under the same dovecot store path as above.
  3. systemctl status dovecot2 clean; send and receive mail normally.
  4. A sieve filter still fires — the pigeonhole risk, and the one failure that would not show up in the service status.

Rollback is reverting the commit. If a future channel bump breaks this build, mail stays on its previous generation — stale rather than down.

Closes #290

Builds Dovecot 2.3 with GSSAPI on `mail`. Package change only — inert until the follow-up enables the mechanism. `grep -rn 'auth_mechanisms\|auth_krb5_keytab\|auth_username_format' --include=*.nix` over the repo returns nothing, so no config references GSSAPI and nothing about IMAP/SMTP auth changes. ## Why an overlay, and why it must replace the attribute `.override` cannot help — nixpkgs' `pkgs/by-name/do/dovecot/generic.nix` exposes no `withGSSAPI` argument — so the derivation's attributes are extended instead. The override has to replace the `pkgs.dovecot_2_3` **attribute** rather than sit inline on `services.dovecot2.package`, and this is the pigeonhole trap the issue flags. In `pkgs/top-level/all-packages.nix`: ```nix dovecot_2_3 = callPackage ../by-name/do/dovecot/2.3.nix { dovecot_pigeonhole = dovecot_pigeonhole_0_5; }; dovecot_pigeonhole_0_5 = callPackage ../by-name/do/dovecot_pigeonhole/0.5.nix { dovecot = dovecot_2_3; }; ``` `all-packages.nix` is `res: pkgs: super:` … `with pkgs;`, and `pkgs` is the *final* overlaid fixpoint (`lib.extends` is `final: let prev = f final; …`, and `allPackages` sits below `overlays` in `stage.nix`'s `toFix`). So replacing the attribute makes `dovecot_pigeonhole_0_5` rebuild against the overridden dovecot, and `passthru.dovecot_pigeonhole` — which `overrideAttrs` leaves untouched — resolves to that same rebuilt pigeonhole. An inline `overrideAttrs` at the use site would instead leave the passthru pointing at pigeonhole built against the *un-overridden* dovecot, which is the version mismatch that broke sieve/managesieve on this host once before. No eval cycle: `passthru` is in `argumentAttrsToRemove` in `make-derivation.nix`, so it is stripped before `derivationArg` and forcing dovecot's `drvPath` never forces it. The dovecot↔pigeonhole mutual reference already exists in unmodified nixpkgs; this replaces a node, it adds no edge. Two call sites ride on this, not one — the issue names `hosts/mail/modules/dovecot.nix:263`, and `hosts/mail/modules/rspamd.nix:157` also runs `${config.services.dovecot2.package.dovecot_pigeonhole}/bin/sievec` in dovecot's `preStart` to compile the spam-filter scripts. Both take the same passthru, so both stay consistent. ## Deviation from the issue's stated scope: `krb5` also in `nativeBuildInputs` The issue specifies `krb5` in `buildInputs` + `--with-gssapi=yes`. **That alone does not compile**, and the failure is at configure time. Four facts, all from the pinned channel rev `445d861c`: 1. `pkgs/by-name/do/dovecot/generic.nix:231` — `strictDeps = true;` 2. `pkgs/stdenv/generic/setup.sh:850` — `if [[ -z "${strictDeps-}" || "$hostOffset" -le -1 ]]; then addToSearchPath _PATH "$pkg/bin"`. With `strictDeps` set, only `nativeBuildInputs` (hostOffset ≤ -1) reach `PATH`; `buildInputs` go to `_HOST_PATH`, which is never folded into `PATH`. 3. `pkgs/by-name/kr/krb5/package.nix:157` — `moveToOutput bin/krb5-config "$dev"`. 4. dovecot 2.3.21.1 `m4/want_gssapi.m4` detects GSSAPI *only* via `AC_CHECK_PROG(KRB5CONFIG, krb5-config, krb5-config, NO)` — a bare `$PATH` walk, no pkg-config, no direct lib probe — and on `NO` with `want_gssapi != auto` raises `AC_ERROR([Can't build with GSSAPI support: krb5-config not found])`. So `--with-gssapi=yes` makes a missing `krb5-config` a hard error. Adding `krb5` to `nativeBuildInputs` fixes it: `make-derivation.nix:559,715` maps `getDev` over that list, so it resolves to `krb5.dev`, whose `bin/` holds `krb5-config`. This mirrors openssh's `withKerberos` in nixpkgs, which puts krb5 in *both* lists for exactly this reason. `buildInputs` is still needed — that is what supplies `gssapi/gssapi.h` and the link inputs. Note `--with-gssapi=<path>` is not an option: dovecot's `TEST_WITH` macro accepts only `yes|no|auto|plugin` and `AC_ERROR`s on a path. `=yes` is correct for the issue's verification step — `want_gssapi != plugin` takes the `AUTH_LIBS="$AUTH_LIBS $KRB5_LIBS"` + `AC_DEFINE(BUILTIN_GSSAPI)` branch, linking GSSAPI into `libexec/dovecot/auth` rather than emitting a separate `.so`. `pkgs.krb5` is already in mail's closure (`hosts/mail/modules/kerberos.nix` sets `security.krb5.package = pkgs.krb5` and runs the KDC), so this adds no new component. `configureFlags` uses `++`, preserving `--with-lucene` (the host's `mail_plugins` includes `fts_lucene`), `--with-ldap`, `--with-systemd` and `--with-moduledir`. An assignment there would have broken the host. ## Blast radius `mail` previously had no `nixpkgs.overlays` at all; the new list contains only this overlay and deliberately does not pull in `utils/overlays/packages.nix`. No other host uses dovecot, so the overlay stays host-local — putting it in `utils/` would drag every host through the pre-commit dry-build for nothing. `version` is untouched, so the module's `isPre24 = versionOlder cfg.package.version "2.4"` gate and every 2.3-shaped default stay exactly as they are. Postfix, the dovecot exporter and `hosts/mail/pkgs/sieve-spam-filter` are unaffected. Expect dovecot and pigeonhole to be binary-cache misses and compile on the host, and dovecot to restart on the deploy (the `preStart` store path changes). ## Verification — please read **The dry-build gate did not run.** This branch was prepared in an environment with no Nix (`/nix` absent, `nix-instantiate` not on `PATH`), so `scripts/pre-commit` / `scripts/test-configuration mail` could not execute — `test-configuration` exits early on its own `command -v nix-instantiate` check. Everything above is static verification against the pinned channel rev, not a build. **Please run `./scripts/test-configuration mail` before merging.** After deploy, the issue's gate for starting the follow-up: 1. The auth binary links GSSAPI: ```bash a=$(find /nix/store -maxdepth 4 -path '*dovecot-2*/libexec/dovecot/auth' | head -1) ldd "$a" | grep -iE 'gss|krb5' ``` 2. Pigeonhole was rebuilt against the override — `readlink -f $(command -v sieve-test)` must resolve under the same dovecot store path as above. 3. `systemctl status dovecot2` clean; send and receive mail normally. 4. A sieve filter still fires — the pigeonhole risk, and the one failure that would not show up in the service status. Rollback is reverting the commit. If a future channel bump breaks this build, `mail` stays on its previous generation — stale rather than down. Closes #290
Package change only — nothing sets auth_mechanisms, so the mechanism stays
unoffered until the follow-up. Enabling it before the build is proven would be
a fatal dovecot startup error.

Replaces the pkgs.dovecot_2_3 attribute rather than overriding
services.dovecot2.package inline, so pigeonhole is rebuilt against this dovecot.
An inline override would leave the passthru pointing at pigeonhole built against
the un-overridden binary — the version mismatch that broke sieve/managesieve on
this host once before.

krb5 goes in nativeBuildInputs as well as buildInputs: dovecot sets strictDeps,
so buildInputs never reach PATH, and dovecot's configure detects GSSAPI only via
krb5-config on PATH, hard-erroring when it is absent.
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!293
No description provided.