From fb834ec7ee3744e8dbb34274b543bc5bf98d0e0e Mon Sep 17 00:00:00 2001 From: Thomas Preisner Date: Wed, 25 Dec 2024 12:39:48 +0100 Subject: [PATCH] tests: Add basic tests for sending/receiving mails and verification of headers --- flake.nix | 2 +- tests/basic.nix | 83 +++++++++++++++++++++++++++++++++++++++++ tests/common/client.nix | 17 +++++++++ 3 files changed, 101 insertions(+), 1 deletion(-) create mode 100644 tests/basic.nix create mode 100644 tests/common/client.nix diff --git a/flake.nix b/flake.nix index 87b3dd8..3066fc6 100644 --- a/flake.nix +++ b/flake.nix @@ -36,7 +36,7 @@ ... }: { checks = let - tests = ["internal"]; + tests = ["internal" "basic"]; genTest = testName: { "name" = testName; "value" = import (./tests + "/${testName}.nix") {inherit pkgs;}; diff --git a/tests/basic.nix b/tests/basic.nix new file mode 100644 index 0000000..615d2a1 --- /dev/null +++ b/tests/basic.nix @@ -0,0 +1,83 @@ +{pkgs, ...}: +with (import ./common/lib.nix {inherit pkgs;}); let + accounts = { + "normal" = { + address = "user1@example.com"; + password = "secret-password1"; + }; + "normal2" = { + address = "user2@example.com"; + password = "secret-password2"; + }; + }; +in + pkgs.nixosTest { + name = "basic"; + nodes = { + server = {pkgs, ...}: { + imports = [./common/server.nix]; + environment.systemPackages = with pkgs; [netcat]; + mailsystem = { + fqdn = "mail.example.com"; + domains = ["example.com"]; + accounts = mkAccounts accounts; + }; + }; + client = {...}: { + imports = [./common/client.nix]; + }; + }; + testScript = {nodes, ...}: let + serverAddr = nodes.server.networking.primaryIPAddress; + clientAddr = nodes.client.networking.primaryIPAddress; + smtpSettings = { + address = serverAddr; + port = 465; + }; + sendMail = mkSendMail smtpSettings accounts; + recvMail = mkRecvMail serverAddr accounts; + cfg = nodes.server.mailsystem; + in '' + start_all() + + server.wait_for_unit("multi-user.target") + client.wait_for_unit("multi-user.target") + server.wait_until_succeeds("${waitForRspamd nodes.server}") + + with subtest("imap works and retrieves no new mails"): + # fetchmail returns EXIT_CODE 1 when no new mail is available + client.succeed("${recvMail "normal"} || [ $? -eq 1 ] >&2") + + with subtest("send succeeds for normal user"): + client.succeed("${sendMail "normal" "" accounts."normal2".address '' + Message-ID: <123456asdf@host.local.network> + Subject: Testmail1 + + Hello User2, + this is some text! + ''}") + # give the mail server some time to process the mail + server.wait_until_fails('${pendingPostqueue}') + + with subtest("mail can be retrieved via imap"): + client.succeed("${recvMail "normal2"} >&2") + + with subtest("mail header contains no sensitive information"): + client.fail("grep '${clientAddr}' $HOME/mail/*") + client.succeed("grep '^Message-ID:.*@${cfg.fqdn}>$' $HOME/mail/*") + + with subtest("mail header contains correct fqdn in received from"): + client.succeed("grep 'Received: from ${cfg.fqdn}' $HOME/mail/*") + + with subtest("user cannot forge from-address"): + client.fail("${sendMail "normal" "someotheraddress@example.com" accounts."normal2".address '' + Subject: I actually do not own this from-address + + Hello User2, + I'm pretending to be someotheraddress@example.com and the mailserver should reject this attempt. + ''}") + + with subtest("server issues no warnings nor errors"): + ${checkLogs "server"} + ''; + } diff --git a/tests/common/client.nix b/tests/common/client.nix new file mode 100644 index 0000000..82dd41b --- /dev/null +++ b/tests/common/client.nix @@ -0,0 +1,17 @@ +{pkgs, ...}: { + config = { + # added to the environment for manual verification via interactiveDriver if necessary + environment.systemPackages = with pkgs; [fetchmail msmtp procmail openssl]; + systemd.tmpfiles.settings."10-mailtest" = let + dirPerms = { + user = "root"; + mode = "0700"; + }; + in { + "/root/mail".d = dirPerms; + "/root/.procmailrc"."L+".argument = "${pkgs.writeText ".procmailrc" '' + DEFAULT=$HOME/mail + ''}"; + }; + }; +}