diff --git a/tests/internal.nix b/tests/internal.nix index af552c3..93441b0 100644 --- a/tests/internal.nix +++ b/tests/internal.nix @@ -100,117 +100,128 @@ in vmailGroupName = "vmail"; vmailUID = 5000; + indexDir = "/var/lib/dovecot/indices"; enableImap = false; }; }; }; - testScript = '' - machine.start() - machine.wait_for_unit("multi-user.target") + testScript = + { + nodes, + ... + }: + '' + machine.start() + machine.wait_for_unit("multi-user.target") - # Regression test for https://gitlab.com/simple-nixos-mailserver/nixos-mailserver/-/issues/205 - with subtest("mail forwarded can are locally kept"): - # A mail sent to user2@example.com is in the user1@example.com mailbox - machine.succeed( - " ".join( - [ - "mail-check send-and-read", - "--smtp-port 587", - "--smtp-starttls", - "--smtp-host localhost", - "--imap-host localhost", - "--imap-username user1@example.com", - "--from-addr user1@example.com", - "--to-addr user2@example.com", - "--src-password-file ${passwordFile}", - "--dst-password-file ${passwordFile}", - "--ignore-dkim-spf", - ] - ) - ) - # A mail sent to user2@example.com is in the user2@example.com mailbox - machine.succeed( - " ".join( - [ - "mail-check send-and-read", - "--smtp-port 587", - "--smtp-starttls", - "--smtp-host localhost", - "--imap-host localhost", - "--imap-username user2@example.com", - "--from-addr user1@example.com", - "--to-addr user2@example.com", - "--src-password-file ${passwordFile}", - "--dst-password-file ${passwordFile}", - "--ignore-dkim-spf", - ] - ) - ) + # Regression test for https://gitlab.com/simple-nixos-mailserver/nixos-mailserver/-/issues/205 + with subtest("mail forwarded can are locally kept"): + # A mail sent to user2@example.com is in the user1@example.com mailbox + machine.succeed( + " ".join( + [ + "mail-check send-and-read", + "--smtp-port 587", + "--smtp-starttls", + "--smtp-host localhost", + "--imap-host localhost", + "--imap-username user1@example.com", + "--from-addr user1@example.com", + "--to-addr user2@example.com", + "--src-password-file ${passwordFile}", + "--dst-password-file ${passwordFile}", + "--ignore-dkim-spf", + ] + ) + ) + # A mail sent to user2@example.com is in the user2@example.com mailbox + machine.succeed( + " ".join( + [ + "mail-check send-and-read", + "--smtp-port 587", + "--smtp-starttls", + "--smtp-host localhost", + "--imap-host localhost", + "--imap-username user2@example.com", + "--from-addr user1@example.com", + "--to-addr user2@example.com", + "--src-password-file ${passwordFile}", + "--dst-password-file ${passwordFile}", + "--ignore-dkim-spf", + ] + ) + ) - with subtest("regex email alias are received"): - # A mail sent to user2-regex-alias@domain.com is in the user2@example.com mailbox - machine.succeed( - " ".join( - [ - "mail-check send-and-read", - "--smtp-port 587", - "--smtp-starttls", - "--smtp-host localhost", - "--imap-host localhost", - "--imap-username user2@example.com", - "--from-addr user1@example.com", - "--to-addr user2-regex-alias@domain.com", - "--src-password-file ${passwordFile}", - "--dst-password-file ${passwordFile}", - "--ignore-dkim-spf", - ] - ) - ) + with subtest("regex email alias are received"): + # A mail sent to user2-regex-alias@domain.com is in the user2@example.com mailbox + machine.succeed( + " ".join( + [ + "mail-check send-and-read", + "--smtp-port 587", + "--smtp-starttls", + "--smtp-host localhost", + "--imap-host localhost", + "--imap-username user2@example.com", + "--from-addr user1@example.com", + "--to-addr user2-regex-alias@domain.com", + "--src-password-file ${passwordFile}", + "--dst-password-file ${passwordFile}", + "--ignore-dkim-spf", + ] + ) + ) - with subtest("user can send from regex email alias"): - # A mail sent from user2-regex-alias@domain.com, using user2@example.com credentials is received - machine.succeed( - " ".join( - [ - "mail-check send-and-read", - "--smtp-port 587", - "--smtp-starttls", - "--smtp-host localhost", - "--imap-host localhost", - "--smtp-username user2@example.com", - "--from-addr user2-regex-alias@domain.com", - "--to-addr user1@example.com", - "--src-password-file ${passwordFile}", - "--dst-password-file ${passwordFile}", - "--ignore-dkim-spf", - ] - ) - ) + with subtest("user can send from regex email alias"): + # A mail sent from user2-regex-alias@domain.com, using user2@example.com credentials is received + machine.succeed( + " ".join( + [ + "mail-check send-and-read", + "--smtp-port 587", + "--smtp-starttls", + "--smtp-host localhost", + "--imap-host localhost", + "--smtp-username user2@example.com", + "--from-addr user2-regex-alias@domain.com", + "--to-addr user1@example.com", + "--src-password-file ${passwordFile}", + "--dst-password-file ${passwordFile}", + "--ignore-dkim-spf", + ] + ) + ) - with subtest("vmail gid is set correctly"): - machine.succeed("getent group vmail | grep 5000") + with subtest("vmail gid is set correctly"): + machine.succeed("getent group vmail | grep 5000") - with subtest("mail to send only accounts is rejected"): - machine.wait_for_open_port(25) - # TODO put this blocking into the systemd units - machine.wait_until_succeeds( - "set +e; timeout 1 nc -U /run/rspamd/rspamd-milter.sock < /dev/null; [ $? -eq 124 ]" - ) - machine.succeed( - "cat ${sendMail} | nc localhost 25 | grep -q '554 5.5.0 Error'" - ) + with subtest("Check dovecot maildir and index locations"): + # If these paths change we need a migration + machine.succeed("doveadm user -f home user1@example.com | grep ${nodes.machine.config.mailserver.mailDirectory}/example.com/user1") + machine.succeed("doveadm user -f mail user1@example.com | grep 'maildir:~/mail:INDEX=${nodes.machine.config.mailserver.indexDir}/example.com/user1'") - with subtest("rspamd controller serves web ui"): - machine.succeed( - "set +o pipefail; curl --unix-socket /run/rspamd/worker-controller.sock http://localhost/ | grep -q ''" - ) + with subtest("mail to send only accounts is rejected"): + machine.wait_for_open_port(25) + # TODO put this blocking into the systemd units + machine.wait_until_succeeds( + "set +e; timeout 1 nc -U /run/rspamd/rspamd-milter.sock < /dev/null; [ $? -eq 124 ]" + ) + machine.succeed( + "cat ${sendMail} | nc localhost 25 | grep -q '554 5.5.0 Error'" + ) - with subtest("imap port 143 is closed and imaps is serving SSL"): - machine.wait_for_closed_port(143) - machine.wait_for_open_port(993) - machine.succeed( - "echo | openssl s_client -connect localhost:993 | grep 'New, TLS'" - ) - ''; + with subtest("rspamd controller serves web ui"): + machine.succeed( + "set +o pipefail; curl --unix-socket /run/rspamd/worker-controller.sock http://localhost/ | grep -q ''" + ) + + with subtest("imap port 143 is closed and imaps is serving SSL"): + machine.wait_for_closed_port(143) + machine.wait_for_open_port(993) + machine.succeed( + "echo | openssl s_client -connect localhost:993 | grep 'New, TLS'" + ) + ''; } diff --git a/tests/ldap.nix b/tests/ldap.nix index 1c92572..0948357 100644 --- a/tests/ldap.nix +++ b/tests/ldap.nix @@ -90,6 +90,7 @@ in fqdn = "mail.example.com"; domains = [ "example.com" ]; localDnsResolver = false; + indexDir = "/var/lib/dovecot/indices"; ldap = { enable = true; @@ -115,107 +116,116 @@ in }; }; }; - testScript = '' - import sys - import re + testScript = + { + nodes, + ... + }: + '' + import sys + import re - machine.start() - machine.wait_for_unit("multi-user.target") + machine.start() + machine.wait_for_unit("multi-user.target") - # This function retrieves the ldap table file from a postconf - # command. - # A key lookup is achived and the returned value is compared - # to the expected value. - def test_lookup(postconf_cmdline, key, expected): - conf = machine.succeed(postconf_cmdline).rstrip() - ldap_table_path = re.match('.* =.*ldap:(.*)', conf).group(1) - value = machine.succeed(f"postmap -q {key} ldap:{ldap_table_path}").rstrip() - try: - assert value == expected - except AssertionError: - print(f"Expected {conf} lookup for key '{key}' to return '{expected}, but got '{value}'", file=sys.stderr) - raise + # This function retrieves the ldap table file from a postconf + # command. + # A key lookup is achived and the returned value is compared + # to the expected value. + def test_lookup(postconf_cmdline, key, expected): + conf = machine.succeed(postconf_cmdline).rstrip() + ldap_table_path = re.match('.* =.*ldap:(.*)', conf).group(1) + value = machine.succeed(f"postmap -q {key} ldap:{ldap_table_path}").rstrip() + try: + assert value == expected + except AssertionError: + print(f"Expected {conf} lookup for key '{key}' to return '{expected}, but got '{value}'", file=sys.stderr) + raise - with subtest("Test postmap lookups"): - test_lookup("postconf virtual_mailbox_maps", "alice@example.com", "alice@example.com") - test_lookup("postconf -P submission/inet/smtpd_sender_login_maps", "alice@example.com", "alice@example.com") + with subtest("Test postmap lookups"): + test_lookup("postconf virtual_mailbox_maps", "alice@example.com", "alice@example.com") + test_lookup("postconf -P submission/inet/smtpd_sender_login_maps", "alice@example.com", "alice@example.com") - test_lookup("postconf virtual_mailbox_maps", "bob@example.com", "bob@example.com") - test_lookup("postconf -P submission/inet/smtpd_sender_login_maps", "bob@example.com", "bob@example.com") + test_lookup("postconf virtual_mailbox_maps", "bob@example.com", "bob@example.com") + test_lookup("postconf -P submission/inet/smtpd_sender_login_maps", "bob@example.com", "bob@example.com") - with subtest("Test doveadm lookups"): - machine.succeed("doveadm user -u alice@example.com") - machine.succeed("doveadm user -u bob@example.com") + with subtest("Test doveadm lookups"): + machine.succeed("doveadm user -u alice@example.com") + machine.succeed("doveadm user -u bob@example.com") - with subtest("Files containing secrets are only readable by root"): - machine.succeed("ls -l /run/postfix/*.cf | grep -e '-rw------- 1 root root'") - machine.succeed("ls -l /run/dovecot2/dovecot-ldap.conf.ext | grep -e '-rw------- 1 root root'") + with subtest("Files containing secrets are only readable by root"): + machine.succeed("ls -l /run/postfix/*.cf | grep -e '-rw------- 1 root root'") + machine.succeed("ls -l /run/dovecot2/dovecot-ldap.conf.ext | grep -e '-rw------- 1 root root'") - with subtest("Test account/mail address binding"): - machine.fail(" ".join([ - "mail-check send-and-read", - "--smtp-port 587", - "--smtp-starttls", - "--smtp-host localhost", - "--smtp-username alice@example.com", - "--imap-host localhost", - "--imap-username bob@example.com", - "--from-addr bob@example.com", - "--to-addr aliceb@example.com", - "--src-password-file <(echo '${alicePassword}')", - "--dst-password-file <(echo '${bobPassword}')", - "--ignore-dkim-spf" - ])) - machine.succeed("journalctl -u postfix | grep -q 'Sender address rejected: not owned by user alice@example.com'") + with subtest("Test account/mail address binding"): + machine.fail(" ".join([ + "mail-check send-and-read", + "--smtp-port 587", + "--smtp-starttls", + "--smtp-host localhost", + "--smtp-username alice@example.com", + "--imap-host localhost", + "--imap-username bob@example.com", + "--from-addr bob@example.com", + "--to-addr aliceb@example.com", + "--src-password-file <(echo '${alicePassword}')", + "--dst-password-file <(echo '${bobPassword}')", + "--ignore-dkim-spf" + ])) + machine.succeed("journalctl -u postfix | grep -q 'Sender address rejected: not owned by user alice@example.com'") - with subtest("Test mail delivery"): - machine.succeed(" ".join([ - "mail-check send-and-read", - "--smtp-port 587", - "--smtp-starttls", - "--smtp-host localhost", - "--smtp-username alice@example.com", - "--imap-host localhost", - "--imap-username bob@example.com", - "--from-addr alice@example.com", - "--to-addr bob@example.com", - "--src-password-file <(echo '${alicePassword}')", - "--dst-password-file <(echo '${bobPassword}')", - "--ignore-dkim-spf" - ])) + with subtest("Test mail delivery"): + machine.succeed(" ".join([ + "mail-check send-and-read", + "--smtp-port 587", + "--smtp-starttls", + "--smtp-host localhost", + "--smtp-username alice@example.com", + "--imap-host localhost", + "--imap-username bob@example.com", + "--from-addr alice@example.com", + "--to-addr bob@example.com", + "--src-password-file <(echo '${alicePassword}')", + "--dst-password-file <(echo '${bobPassword}')", + "--ignore-dkim-spf" + ])) - with subtest("Test mail forwarding works"): - machine.succeed(" ".join([ - "mail-check send-and-read", - "--smtp-port 587", - "--smtp-starttls", - "--smtp-host localhost", - "--smtp-username alice@example.com", - "--imap-host localhost", - "--imap-username bob@example.com", - "--from-addr alice@example.com", - "--to-addr bob_fw@example.com", - "--src-password-file <(echo '${alicePassword}')", - "--dst-password-file <(echo '${bobPassword}')", - "--ignore-dkim-spf" - ])) + with subtest("Test mail forwarding works"): + machine.succeed(" ".join([ + "mail-check send-and-read", + "--smtp-port 587", + "--smtp-starttls", + "--smtp-host localhost", + "--smtp-username alice@example.com", + "--imap-host localhost", + "--imap-username bob@example.com", + "--from-addr alice@example.com", + "--to-addr bob_fw@example.com", + "--src-password-file <(echo '${alicePassword}')", + "--dst-password-file <(echo '${bobPassword}')", + "--ignore-dkim-spf" + ])) - with subtest("Test cannot send mail from forwarded address"): - machine.fail(" ".join([ - "mail-check send-and-read", - "--smtp-port 587", - "--smtp-starttls", - "--smtp-host localhost", - "--smtp-username bob@example.com", - "--imap-host localhost", - "--imap-username alice@example.com", - "--from-addr bob_fw@example.com", - "--to-addr alice@example.com", - "--src-password-file <(echo '${bobPassword}')", - "--dst-password-file <(echo '${alicePassword}')", - "--ignore-dkim-spf" - ])) - machine.succeed("journalctl -u postfix | grep -q 'Sender address rejected: not owned by user bob@example.com'") + with subtest("Test cannot send mail from forwarded address"): + machine.fail(" ".join([ + "mail-check send-and-read", + "--smtp-port 587", + "--smtp-starttls", + "--smtp-host localhost", + "--smtp-username bob@example.com", + "--imap-host localhost", + "--imap-username alice@example.com", + "--from-addr bob_fw@example.com", + "--to-addr alice@example.com", + "--src-password-file <(echo '${bobPassword}')", + "--dst-password-file <(echo '${alicePassword}')", + "--ignore-dkim-spf" + ])) + machine.succeed("journalctl -u postfix | grep -q 'Sender address rejected: not owned by user bob@example.com'") - ''; + with subtest("Check dovecot mail and index locations"): + # If these paths change we need a migration + machine.succeed("doveadm user -f home bob@example.com | grep ${nodes.machine.config.mailserver.mailDirectory}/ldap/bob@example.com") + machine.succeed("doveadm user -f mail bob@example.com | grep 'maildir:~/mail:INDEX=${nodes.machine.config.mailserver.indexDir}/ldap/bob@example.com'") + ''; }