nixos/dovecot: Fix createMailUser implementation

This option got introduced in 7904499542814b8a4d04fce8dc7ca8c383c083e7
and it didn't check whether mailUser and mailGroup are null, which they
are by default.

Now we're only creating the user if createMailUser is set in conjunction
with mailUser and the group if mailGroup is set as well.

I've added a NixOS VM test so that we can verify whether dovecot works
without any additional options set, so it serves as a regression test
for issue #29466 and other issues that might come up with future changes
to the Dovecot service.

Signed-off-by: aszlig <aszlig@redmoonstudios.org>
Fixes: #29466
Cc: @qknight, @abbradar, @ixmatus, @siddharthist

aszlig 3ba2095a 222e1869

+73 -5
+8 -5
nixos/modules/services/mail/dovecot.nix
··· 9 baseDir = "/run/dovecot2"; 10 stateDir = "/var/lib/dovecot"; 11 12 dovecotConf = concatStrings [ 13 '' 14 base_dir = ${baseDir} ··· 314 description = "Dovecot user"; 315 group = cfg.group; 316 } 317 - ++ optional cfg.createMailUser 318 - { name = cfg.mailUser; 319 - description = "Virtual Mail User"; 320 group = cfg.mailGroup; 321 - }; 322 323 users.extraGroups = optional (cfg.group == "dovecot2") 324 { name = "dovecot2"; 325 gid = config.ids.gids.dovecot2; 326 } 327 - ++ optional cfg.createMailUser 328 { name = cfg.mailGroup; 329 }; 330
··· 9 baseDir = "/run/dovecot2"; 10 stateDir = "/var/lib/dovecot"; 11 12 + canCreateMailUserGroup = cfg.mailUser != null && cfg.mailGroup != null; 13 + 14 dovecotConf = concatStrings [ 15 '' 16 base_dir = ${baseDir} ··· 316 description = "Dovecot user"; 317 group = cfg.group; 318 } 319 + ++ optional (cfg.createMailUser && cfg.mailUser != null) 320 + ({ name = cfg.mailUser; 321 + description = "Virtual Mail User"; 322 + } // optionalAttrs (cfg.mailGroup != null) { 323 group = cfg.mailGroup; 324 + }); 325 326 users.extraGroups = optional (cfg.group == "dovecot2") 327 { name = "dovecot2"; 328 gid = config.ids.gids.dovecot2; 329 } 330 + ++ optional (cfg.createMailUser && cfg.mailGroup != null) 331 { name = cfg.mailGroup; 332 }; 333
+1
nixos/release.nix
··· 236 tests.containers-macvlans = callTest tests/containers-macvlans.nix {}; 237 tests.docker = hydraJob (import tests/docker.nix { system = "x86_64-linux"; }); 238 tests.docker-edge = hydraJob (import tests/docker-edge.nix { system = "x86_64-linux"; }); 239 tests.dnscrypt-proxy = callTest tests/dnscrypt-proxy.nix { system = "x86_64-linux"; }; 240 tests.ecryptfs = callTest tests/ecryptfs.nix {}; 241 tests.etcd = hydraJob (import tests/etcd.nix { system = "x86_64-linux"; });
··· 236 tests.containers-macvlans = callTest tests/containers-macvlans.nix {}; 237 tests.docker = hydraJob (import tests/docker.nix { system = "x86_64-linux"; }); 238 tests.docker-edge = hydraJob (import tests/docker-edge.nix { system = "x86_64-linux"; }); 239 + tests.dovecot = callTest tests/dovecot.nix {}; 240 tests.dnscrypt-proxy = callTest tests/dnscrypt-proxy.nix { system = "x86_64-linux"; }; 241 tests.ecryptfs = callTest tests/ecryptfs.nix {}; 242 tests.etcd = hydraJob (import tests/etcd.nix { system = "x86_64-linux"; });
+64
nixos/tests/dovecot.nix
···
··· 1 + import ./make-test.nix { 2 + name = "dovecot"; 3 + 4 + machine = { pkgs, ... }: { 5 + imports = [ common/user-account.nix ]; 6 + services.postfix.enable = true; 7 + services.dovecot2.enable = true; 8 + services.dovecot2.protocols = [ "imap" "pop3" ]; 9 + environment.systemPackages = let 10 + sendTestMail = pkgs.writeScriptBin "send-testmail" '' 11 + #!${pkgs.stdenv.shell} 12 + exec sendmail -vt <<MAIL 13 + From: root@localhost 14 + To: alice@localhost 15 + Subject: Very important! 16 + 17 + Hello world! 18 + MAIL 19 + ''; 20 + 21 + testImap = pkgs.writeScriptBin "test-imap" '' 22 + #!${pkgs.python3.interpreter} 23 + import imaplib 24 + 25 + with imaplib.IMAP4('localhost') as imap: 26 + imap.login('alice', 'foobar') 27 + imap.select() 28 + status, refs = imap.search(None, 'ALL') 29 + assert status == 'OK' 30 + assert len(refs) == 1 31 + status, msg = imap.fetch(refs[0], 'BODY[TEXT]') 32 + assert status == 'OK' 33 + assert msg[0][1].strip() == b'Hello world!' 34 + ''; 35 + 36 + testPop = pkgs.writeScriptBin "test-pop" '' 37 + #!${pkgs.python3.interpreter} 38 + import poplib 39 + 40 + pop = poplib.POP3('localhost') 41 + try: 42 + pop.user('alice') 43 + pop.pass_('foobar') 44 + assert len(pop.list()[1]) == 1 45 + status, fullmail, size = pop.retr(1) 46 + assert status.startswith(b'+OK ') 47 + body = b"".join(fullmail[fullmail.index(b""):]).strip() 48 + assert body == b'Hello world!' 49 + finally: 50 + pop.quit() 51 + ''; 52 + 53 + in [ sendTestMail testImap testPop ]; 54 + }; 55 + 56 + testScript = '' 57 + $machine->waitForUnit('postfix.service'); 58 + $machine->waitForUnit('dovecot2.service'); 59 + $machine->succeed('send-testmail'); 60 + $machine->waitUntilFails('[ "$(postqueue -p)" != "Mail queue is empty" ]'); 61 + $machine->succeed('test-imap'); 62 + $machine->succeed('test-pop'); 63 + ''; 64 + }