mirror of
https://github.com/docker-mailserver/docker-mailserver.git
synced 2025-08-04 10:05:00 +02:00
tests(chore): Rename test files to serial and parallel types
- `test_helper.bats` needs more work than this PR provides to be compatible with parallel tests, so must remain as a serial test for now. - `spam_bounced.bats` had failures as a serial test, but works well converted to a parallel test in a future commit.
This commit is contained in:
parent
2bc4078e35
commit
59127e2b25
41 changed files with 0 additions and 0 deletions
79
test/tests/parallel/set1/clamav.bats
Normal file
79
test/tests/parallel/set1/clamav.bats
Normal file
|
@ -0,0 +1,79 @@
|
|||
load 'test_helper/common'
|
||||
|
||||
TEST_NAME_PREFIX='ClamAV:'
|
||||
CONTAINER_NAME='dms-test-clamav'
|
||||
RUN_COMMAND=('run' 'docker' 'exec' "${CONTAINER_NAME}")
|
||||
|
||||
function setup_file() {
|
||||
local PRIVATE_CONFIG
|
||||
PRIVATE_CONFIG=$(duplicate_config_for_container . "${CONTAINER_NAME}")
|
||||
|
||||
docker run --rm --detach --tty \
|
||||
--name "${CONTAINER_NAME}" \
|
||||
--hostname mail.my-domain.com \
|
||||
--volume "${PRIVATE_CONFIG}:/tmp/docker-mailserver" \
|
||||
--volume "${PWD}/test/test-files:/tmp/docker-mailserver-test:ro" \
|
||||
--env ENABLE_AMAVIS=1 \
|
||||
--env AMAVIS_LOGLEVEL=2 \
|
||||
--env ENABLE_CLAMAV=1 \
|
||||
--env ENABLE_UPDATE_CHECK=0 \
|
||||
--env ENABLE_SPAMASSASSIN=0 \
|
||||
--env ENABLE_FAIL2BAN=0 \
|
||||
--env PERMIT_DOCKER=host \
|
||||
--env CLAMAV_MESSAGE_SIZE_LIMIT=30M \
|
||||
--env LOG_LEVEL=debug \
|
||||
"${IMAGE_NAME}"
|
||||
|
||||
wait_for_finished_setup_in_container "${CONTAINER_NAME}"
|
||||
|
||||
# wait for ClamAV to be fully setup or we will get errors on the log
|
||||
repeat_in_container_until_success_or_timeout 60 "${CONTAINER_NAME}" test -e /var/run/clamav/clamd.ctl
|
||||
|
||||
wait_for_service "${CONTAINER_NAME}" postfix
|
||||
wait_for_smtp_port_in_container "${CONTAINER_NAME}"
|
||||
|
||||
"${RUN_COMMAND[@]}" bash -c "nc 0.0.0.0 25 < /tmp/docker-mailserver-test/email-templates/amavis-virus.txt"
|
||||
assert_success
|
||||
|
||||
wait_for_empty_mail_queue_in_container "${CONTAINER_NAME}"
|
||||
}
|
||||
|
||||
function teardown_file() {
|
||||
docker rm -f "${CONTAINER_NAME}"
|
||||
}
|
||||
|
||||
@test "${TEST_NAME_PREFIX} process clamd is running" {
|
||||
"${RUN_COMMAND[@]}" bash -c "ps aux --forest | grep -v grep | grep '/usr/sbin/clamd'"
|
||||
assert_success
|
||||
}
|
||||
|
||||
@test "${TEST_NAME_PREFIX} log files exist at /var/log/mail directory" {
|
||||
"${RUN_COMMAND[@]}" bash -c "ls -1 /var/log/mail/ | grep -E 'clamav|freshclam|mail.log'| wc -l"
|
||||
assert_success
|
||||
assert_output 3
|
||||
}
|
||||
|
||||
@test "${TEST_NAME_PREFIX} should be identified by Amavis" {
|
||||
"${RUN_COMMAND[@]}" grep -i 'Found secondary av scanner ClamAV-clamscan' /var/log/mail/mail.log
|
||||
assert_success
|
||||
}
|
||||
|
||||
@test "${TEST_NAME_PREFIX} freshclam cron is enabled" {
|
||||
"${RUN_COMMAND[@]}" bash -c "grep '/usr/bin/freshclam' -r /etc/cron.d"
|
||||
assert_success
|
||||
}
|
||||
|
||||
@test "${TEST_NAME_PREFIX} env CLAMAV_MESSAGE_SIZE_LIMIT is set correctly" {
|
||||
"${RUN_COMMAND[@]}" grep -q '^MaxFileSize 30M$' /etc/clamav/clamd.conf
|
||||
assert_success
|
||||
}
|
||||
|
||||
@test "${TEST_NAME_PREFIX} rejects virus" {
|
||||
"${RUN_COMMAND[@]}" bash -c "grep 'Blocked INFECTED' /var/log/mail/mail.log | grep '<virus@external.tld> -> <user1@localhost.localdomain>'"
|
||||
assert_success
|
||||
}
|
||||
|
||||
@test "${TEST_NAME_PREFIX} process clamd restarts when killed" {
|
||||
"${RUN_COMMAND[@]}" bash -c "pkill clamd && sleep 10 && ps aux --forest | grep -v grep | grep '/usr/sbin/clamd'"
|
||||
assert_success
|
||||
}
|
28
test/tests/parallel/set1/default_relay_host.bats
Normal file
28
test/tests/parallel/set1/default_relay_host.bats
Normal file
|
@ -0,0 +1,28 @@
|
|||
load 'test_helper/common'
|
||||
|
||||
function setup() {
|
||||
local PRIVATE_CONFIG
|
||||
PRIVATE_CONFIG=$(duplicate_config_for_container relay-hosts)
|
||||
|
||||
docker run -d --name mail_with_default_relay \
|
||||
-v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \
|
||||
-v "$(pwd)/test/test-files":/tmp/docker-mailserver-test:ro \
|
||||
-e DEFAULT_RELAY_HOST=default.relay.host.invalid:25 \
|
||||
-e PERMIT_DOCKER=host \
|
||||
-h mail.my-domain.com -t "${NAME}"
|
||||
|
||||
wait_for_finished_setup_in_container mail_with_default_relay
|
||||
}
|
||||
|
||||
function teardown() {
|
||||
docker rm -f mail_with_default_relay
|
||||
}
|
||||
|
||||
#
|
||||
# default relay host
|
||||
#
|
||||
|
||||
@test "checking default relay host: default relay host is added to main.cf" {
|
||||
run docker exec mail_with_default_relay /bin/sh -c 'grep -e "^relayhost =" /etc/postfix/main.cf'
|
||||
assert_output 'relayhost = default.relay.host.invalid:25'
|
||||
}
|
49
test/tests/parallel/set2/spam_bounced.bats
Normal file
49
test/tests/parallel/set2/spam_bounced.bats
Normal file
|
@ -0,0 +1,49 @@
|
|||
load 'test_helper/common'
|
||||
# Globals referenced from `test_helper/common`:
|
||||
# TEST_NAME
|
||||
|
||||
# Can run tests in parallel?: No
|
||||
# Shared static container name: TEST_NAME
|
||||
|
||||
# Test case
|
||||
# ---------
|
||||
# When SPAMASSASSIN_SPAM_TO_INBOX=0, spam messages must be bounced (rejected).
|
||||
# SPAMASSASSIN_SPAM_TO_INBOX=1 is covered in `mail_spam_junk_folder.bats`.
|
||||
# Original test PR: https://github.com/docker-mailserver/docker-mailserver/pull/1485
|
||||
|
||||
function teardown() {
|
||||
docker rm -f "${TEST_NAME}"
|
||||
}
|
||||
|
||||
function setup_file() {
|
||||
init_with_defaults
|
||||
}
|
||||
|
||||
# Not used
|
||||
# function teardown_file() {
|
||||
# }
|
||||
|
||||
@test "checking amavis: spam message is bounced (rejected)" {
|
||||
# shellcheck disable=SC2034
|
||||
local TEST_DOCKER_ARGS=(
|
||||
--env ENABLE_SPAMASSASSIN=1
|
||||
--env PERMIT_DOCKER=container
|
||||
--env SPAMASSASSIN_SPAM_TO_INBOX=0
|
||||
)
|
||||
|
||||
common_container_setup 'TEST_DOCKER_ARGS'
|
||||
|
||||
_should_bounce_spam
|
||||
}
|
||||
|
||||
function _should_bounce_spam() {
|
||||
wait_for_smtp_port_in_container_to_respond "${TEST_NAME}"
|
||||
|
||||
# send a spam message
|
||||
run docker exec "${TEST_NAME}" /bin/sh -c "nc 0.0.0.0 25 < /tmp/docker-mailserver-test/email-templates/amavis-spam.txt"
|
||||
assert_success
|
||||
|
||||
# message will be added to a queue with varying delay until amavis receives it
|
||||
run repeat_until_success_or_timeout 60 sh -c "docker logs ${TEST_NAME} | grep 'Blocked SPAM {NoBounceInbound,Quarantined}'"
|
||||
assert_success
|
||||
}
|
54
test/tests/parallel/set3/dovecot_inet_protocol.bats
Normal file
54
test/tests/parallel/set3/dovecot_inet_protocol.bats
Normal file
|
@ -0,0 +1,54 @@
|
|||
load 'test_helper/common'
|
||||
|
||||
function setup_file() {
|
||||
local PRIVATE_CONFIG
|
||||
export ALL IPV4 IPV6
|
||||
|
||||
PRIVATE_CONFIG=$(duplicate_config_for_container . "${IPV4}")
|
||||
ALL="mail_dovecot_all_protocols"
|
||||
IPV4="mail_dovecot_ipv4"
|
||||
IPV6="mail_dovecot_ipv6"
|
||||
|
||||
docker run --rm -d --name "${ALL}" \
|
||||
-v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \
|
||||
-e DOVECOT_INET_PROTOCOLS= \
|
||||
-h mail.my-domain.com \
|
||||
-t "${NAME}"
|
||||
|
||||
docker run --rm -d --name "${IPV4}" \
|
||||
-v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \
|
||||
-e DOVECOT_INET_PROTOCOLS=ipv4 \
|
||||
-h mail.my-domain.com \
|
||||
-t "${NAME}"
|
||||
|
||||
docker run --rm -d --name "${IPV6}" \
|
||||
-v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \
|
||||
-e DOVECOT_INET_PROTOCOLS=ipv6 \
|
||||
-h mail.my-domain.com \
|
||||
-t "${NAME}"
|
||||
}
|
||||
|
||||
@test 'checking dovecot IP configuration' {
|
||||
wait_for_finished_setup_in_container "${ALL}"
|
||||
run docker exec "${ALL}" grep '^#listen = \*, ::' /etc/dovecot/dovecot.conf
|
||||
assert_success
|
||||
assert_output '#listen = *, ::'
|
||||
}
|
||||
|
||||
@test 'checking dovecot IPv4 configuration' {
|
||||
wait_for_finished_setup_in_container "${IPV4}"
|
||||
run docker exec "${IPV4}" grep '^listen = \*$' /etc/dovecot/dovecot.conf
|
||||
assert_success
|
||||
assert_output 'listen = *'
|
||||
}
|
||||
|
||||
@test 'checking dovecot IPv6 configuration' {
|
||||
wait_for_finished_setup_in_container "${IPV6}"
|
||||
run docker exec "${IPV6}" grep '^listen = \[::\]$' /etc/dovecot/dovecot.conf
|
||||
assert_success
|
||||
assert_output 'listen = [::]'
|
||||
}
|
||||
|
||||
function teardown_file {
|
||||
docker rm -f "${ALL}" "${IPV4}" "${IPV6}"
|
||||
}
|
30
test/tests/parallel/set3/helper-functions.bats
Normal file
30
test/tests/parallel/set3/helper-functions.bats
Normal file
|
@ -0,0 +1,30 @@
|
|||
load 'test_helper/common'
|
||||
|
||||
function setup_file() {
|
||||
local PRIVATE_CONFIG
|
||||
PRIVATE_CONFIG=$(duplicate_config_for_container .)
|
||||
|
||||
docker run -d --name mail_helper_functions \
|
||||
--cap-add=NET_ADMIN \
|
||||
-v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \
|
||||
-v "$(pwd)/test/test-files":/tmp/docker-mailserver-test:ro \
|
||||
-e ENABLE_FETCHMAIL=1 \
|
||||
-h mail.my-domain.com -t "${NAME}"
|
||||
|
||||
wait_for_finished_setup_in_container mail_helper_functions
|
||||
}
|
||||
|
||||
function teardown_file() {
|
||||
docker rm -f mail_helper_functions
|
||||
}
|
||||
|
||||
@test "check helper functions (network.sh): _sanitize_ipv4_to_subnet_cidr" {
|
||||
run docker exec mail_helper_functions bash -c "source /usr/local/bin/helpers/index.sh; _sanitize_ipv4_to_subnet_cidr 255.255.255.255/0"
|
||||
assert_output "0.0.0.0/0"
|
||||
|
||||
run docker exec mail_helper_functions bash -c "source /usr/local/bin/helpers/index.sh; _sanitize_ipv4_to_subnet_cidr 192.168.255.14/20"
|
||||
assert_output "192.168.240.0/20"
|
||||
|
||||
run docker exec mail_helper_functions bash -c "source /usr/local/bin/helpers/index.sh; _sanitize_ipv4_to_subnet_cidr 192.168.255.14/32"
|
||||
assert_output "192.168.255.14/32"
|
||||
}
|
87
test/tests/serial/mail_changedetector.bats
Normal file
87
test/tests/serial/mail_changedetector.bats
Normal file
|
@ -0,0 +1,87 @@
|
|||
load 'test_helper/common'
|
||||
|
||||
# Note if tests fail asserting against `supervisorctl tail changedetector` output,
|
||||
# use `supervisorctl tail -<num bytes> changedetector` instead to increase log output.
|
||||
# Default `<num bytes>` appears to be around 1500.
|
||||
|
||||
function setup_file() {
|
||||
local PRIVATE_CONFIG
|
||||
PRIVATE_CONFIG=$(duplicate_config_for_container . mail_changedetector_one)
|
||||
|
||||
docker run -d --name mail_changedetector_one \
|
||||
-v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \
|
||||
-v "$(pwd)/test/test-files":/tmp/docker-mailserver-test:ro \
|
||||
-e LOG_LEVEL=trace \
|
||||
-h mail.my-domain.com -t "${NAME}"
|
||||
|
||||
docker run -d --name mail_changedetector_two \
|
||||
-v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \
|
||||
-v "$(pwd)/test/test-files":/tmp/docker-mailserver-test:ro \
|
||||
-e LOG_LEVEL=trace \
|
||||
-h mail.my-domain.com -t "${NAME}"
|
||||
|
||||
wait_for_finished_setup_in_container mail_changedetector_one
|
||||
wait_for_finished_setup_in_container mail_changedetector_two
|
||||
}
|
||||
|
||||
function teardown_file() {
|
||||
docker rm -f mail_changedetector_one
|
||||
docker rm -f mail_changedetector_two
|
||||
}
|
||||
|
||||
@test "checking changedetector: servers are ready" {
|
||||
wait_for_service mail_changedetector_one changedetector
|
||||
wait_for_service mail_changedetector_two changedetector
|
||||
}
|
||||
|
||||
@test "checking changedetector: can detect changes & between two containers using same config" {
|
||||
echo "" >> "$(private_config_path mail_changedetector_one)/postfix-accounts.cf"
|
||||
sleep 25
|
||||
|
||||
run docker exec mail_changedetector_one /bin/bash -c "supervisorctl tail -3000 changedetector"
|
||||
assert_output --partial "postfix: stopped"
|
||||
assert_output --partial "postfix: started"
|
||||
assert_output --partial "Change detected"
|
||||
assert_output --partial "Removed lock"
|
||||
|
||||
run docker exec mail_changedetector_two /bin/bash -c "supervisorctl tail -3000 changedetector"
|
||||
assert_output --partial "postfix: stopped"
|
||||
assert_output --partial "postfix: started"
|
||||
assert_output --partial "Change detected"
|
||||
assert_output --partial "Removed lock"
|
||||
}
|
||||
|
||||
@test "checking changedetector: lock file found, blocks, and doesn't get prematurely removed" {
|
||||
run docker exec mail_changedetector_two /bin/bash -c "supervisorctl stop changedetector"
|
||||
docker exec mail_changedetector_one /bin/bash -c "touch /tmp/docker-mailserver/check-for-changes.sh.lock"
|
||||
echo "" >> "$(private_config_path mail_changedetector_one)/postfix-accounts.cf"
|
||||
run docker exec mail_changedetector_two /bin/bash -c "supervisorctl start changedetector"
|
||||
sleep 15
|
||||
|
||||
run docker exec mail_changedetector_one /bin/bash -c "supervisorctl tail changedetector"
|
||||
assert_output --partial "another execution of 'check-for-changes.sh' is happening"
|
||||
run docker exec mail_changedetector_two /bin/bash -c "supervisorctl tail changedetector"
|
||||
assert_output --partial "another execution of 'check-for-changes.sh' is happening"
|
||||
|
||||
# Ensure starting a new check-for-changes.sh instance (restarting here) doesn't delete the lock
|
||||
docker exec mail_changedetector_two /bin/bash -c "rm -f /var/log/supervisor/changedetector.log"
|
||||
run docker exec mail_changedetector_two /bin/bash -c "supervisorctl restart changedetector"
|
||||
sleep 5
|
||||
run docker exec mail_changedetector_two /bin/bash -c "supervisorctl tail changedetector"
|
||||
refute_output --partial "another execution of 'check-for-changes.sh' is happening"
|
||||
refute_output --partial "Removed lock"
|
||||
}
|
||||
|
||||
@test "checking changedetector: lock stale and cleaned up" {
|
||||
docker rm -f mail_changedetector_two
|
||||
docker exec mail_changedetector_one /bin/bash -c "touch /tmp/docker-mailserver/check-for-changes.sh.lock"
|
||||
echo "" >> "$(private_config_path mail_changedetector_one)/postfix-accounts.cf"
|
||||
sleep 15
|
||||
|
||||
run docker exec mail_changedetector_one /bin/bash -c "supervisorctl tail changedetector"
|
||||
assert_output --partial "another execution of 'check-for-changes.sh' is happening"
|
||||
sleep 65
|
||||
|
||||
run docker exec mail_changedetector_one /bin/bash -c "supervisorctl tail -3000 changedetector"
|
||||
assert_output --partial "removing stale lock file"
|
||||
}
|
48
test/tests/serial/mail_disabled_clamav_spamassassin.bats
Normal file
48
test/tests/serial/mail_disabled_clamav_spamassassin.bats
Normal file
|
@ -0,0 +1,48 @@
|
|||
load 'test_helper/common'
|
||||
|
||||
setup_file() {
|
||||
local PRIVATE_CONFIG
|
||||
PRIVATE_CONFIG=$(duplicate_config_for_container .)
|
||||
|
||||
docker run --rm -d --name mail_disabled_clamav_spamassassin \
|
||||
-v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \
|
||||
-v "$(pwd)/test/test-files":/tmp/docker-mailserver-test:ro \
|
||||
-e ENABLE_CLAMAV=0 \
|
||||
-e ENABLE_SPAMASSASSIN=0 \
|
||||
-e AMAVIS_LOGLEVEL=2 \
|
||||
-h mail.my-domain.com -t "${NAME}"
|
||||
|
||||
# TODO: find a better way to know when we have waited long enough
|
||||
# for ClamAV to should have come up, if it were enabled
|
||||
wait_for_smtp_port_in_container mail_disabled_clamav_spamassassin
|
||||
docker exec mail_disabled_clamav_spamassassin /bin/sh -c "nc 0.0.0.0 25 < /tmp/docker-mailserver-test/email-templates/existing-user1.txt"
|
||||
}
|
||||
|
||||
teardown_file() {
|
||||
docker rm -f mail_disabled_clamav_spamassassin
|
||||
}
|
||||
|
||||
@test "checking process: ClamAV (ClamAV disabled by ENABLED_CLAMAV=0)" {
|
||||
run docker exec mail_disabled_clamav_spamassassin /bin/bash -c "ps aux --forest | grep -v grep | grep '/usr/sbin/clamd'"
|
||||
assert_failure
|
||||
}
|
||||
|
||||
@test "checking spamassassin: should not be listed in amavis when disabled" {
|
||||
run docker exec mail_disabled_clamav_spamassassin /bin/sh -c "grep -i 'ANTI-SPAM-SA code' /var/log/mail/mail.log | grep 'NOT loaded'"
|
||||
assert_success
|
||||
}
|
||||
|
||||
@test "checking ClamAV: should not be listed in amavis when disabled" {
|
||||
run docker exec mail_disabled_clamav_spamassassin grep -i 'Found secondary av scanner ClamAV-clamscan' /var/log/mail/mail.log
|
||||
assert_failure
|
||||
}
|
||||
|
||||
@test "checking ClamAV: should not be called when disabled" {
|
||||
run docker exec mail_disabled_clamav_spamassassin grep -i 'connect to /var/run/clamav/clamd.ctl failed' /var/log/mail/mail.log
|
||||
assert_failure
|
||||
}
|
||||
|
||||
@test "checking restart of process: ClamAV (ClamAV disabled by ENABLED_CLAMAV=0)" {
|
||||
run docker exec mail_disabled_clamav_spamassassin /bin/bash -c "pkill -f clamd && sleep 10 && ps aux --forest | grep -v grep | grep '/usr/sbin/clamd'"
|
||||
assert_failure
|
||||
}
|
61
test/tests/serial/mail_dnsbl.bats
Normal file
61
test/tests/serial/mail_dnsbl.bats
Normal file
|
@ -0,0 +1,61 @@
|
|||
load 'test_helper/common'
|
||||
|
||||
CONTAINER="mail_dnsbl_enabled"
|
||||
CONTAINER2="mail_dnsbl_disabled"
|
||||
|
||||
function setup_file() {
|
||||
local PRIVATE_CONFIG
|
||||
PRIVATE_CONFIG=$(duplicate_config_for_container . "${CONTAINER}")
|
||||
|
||||
docker run --rm -d --name "${CONTAINER}" \
|
||||
-v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \
|
||||
-e ENABLE_DNSBL=1 \
|
||||
-h mail.my-domain.com \
|
||||
-t "${NAME}"
|
||||
|
||||
docker run --rm -d --name "${CONTAINER2}" \
|
||||
-v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \
|
||||
-e ENABLE_DNSBL=0 \
|
||||
-h mail.my-domain.com \
|
||||
-t "${NAME}"
|
||||
|
||||
wait_for_smtp_port_in_container "${CONTAINER}"
|
||||
wait_for_smtp_port_in_container "${CONTAINER2}"
|
||||
}
|
||||
|
||||
# ENABLE_DNSBL=1
|
||||
@test "checking enabled postfix DNS block list zen.spamhaus.org" {
|
||||
run docker exec "${CONTAINER}" postconf smtpd_recipient_restrictions
|
||||
assert_output --partial 'reject_rbl_client zen.spamhaus.org'
|
||||
}
|
||||
|
||||
@test "checking enabled postscreen DNS block lists --> postscreen_dnsbl_action" {
|
||||
run docker exec "${CONTAINER}" postconf postscreen_dnsbl_action
|
||||
assert_output 'postscreen_dnsbl_action = enforce'
|
||||
}
|
||||
|
||||
@test "checking enabled postscreen DNS block lists --> postscreen_dnsbl_sites" {
|
||||
run docker exec "${CONTAINER}" postconf postscreen_dnsbl_sites
|
||||
assert_output 'postscreen_dnsbl_sites = zen.spamhaus.org=127.0.0.[2..11]*3 bl.mailspike.net=127.0.0.[2;14;13;12;11;10] b.barracudacentral.org*2 bl.spameatingmonkey.net=127.0.0.2 dnsbl.sorbs.net psbl.surriel.com list.dnswl.org=127.0.[0..255].0*-2 list.dnswl.org=127.0.[0..255].1*-3 list.dnswl.org=127.0.[0..255].[2..3]*-4'
|
||||
}
|
||||
|
||||
# ENABLE_DNSBL=0
|
||||
@test "checking disabled postfix DNS block list zen.spamhaus.org" {
|
||||
run docker exec "${CONTAINER2}" postconf smtpd_recipient_restrictions
|
||||
refute_output --partial 'reject_rbl_client zen.spamhaus.org'
|
||||
}
|
||||
|
||||
@test "checking disabled postscreen DNS block lists --> postscreen_dnsbl_action" {
|
||||
run docker exec "${CONTAINER2}" postconf postscreen_dnsbl_action
|
||||
assert_output 'postscreen_dnsbl_action = ignore'
|
||||
}
|
||||
|
||||
@test "checking disabled postscreen DNS block lists --> postscreen_dnsbl_sites" {
|
||||
run docker exec "${CONTAINER2}" postconf postscreen_dnsbl_sites
|
||||
assert_output 'postscreen_dnsbl_sites ='
|
||||
}
|
||||
|
||||
# cleanup
|
||||
function teardown_file() {
|
||||
docker rm -f "${CONTAINER}" "${CONTAINER2}"
|
||||
}
|
200
test/tests/serial/mail_fail2ban.bats
Normal file
200
test/tests/serial/mail_fail2ban.bats
Normal file
|
@ -0,0 +1,200 @@
|
|||
load 'test_helper/common'
|
||||
|
||||
function setup_file() {
|
||||
local PRIVATE_CONFIG
|
||||
PRIVATE_CONFIG=$(duplicate_config_for_container .)
|
||||
docker run --rm -d --name mail_fail2ban \
|
||||
-v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \
|
||||
-v "$(pwd)/test/test-files":/tmp/docker-mailserver-test:ro \
|
||||
-e ENABLE_FAIL2BAN=1 \
|
||||
-e POSTSCREEN_ACTION=ignore \
|
||||
--cap-add=NET_ADMIN \
|
||||
--hostname mail.my-domain.com \
|
||||
--tty \
|
||||
--ulimit "nofile=$(ulimit -Sn):$(ulimit -Hn)" \
|
||||
"${NAME}"
|
||||
|
||||
# Create a container which will send wrong authentications and should get banned
|
||||
docker run --name fail-auth-mailer \
|
||||
-e MAIL_FAIL2BAN_IP="$(docker inspect --format '{{ .NetworkSettings.IPAddress }}' mail_fail2ban)" \
|
||||
-v "$(pwd)/test/test-files":/tmp/docker-mailserver-test \
|
||||
-d "${NAME}" \
|
||||
tail -f /var/log/faillog
|
||||
|
||||
wait_for_finished_setup_in_container mail_fail2ban
|
||||
}
|
||||
|
||||
function teardown_file() {
|
||||
docker rm -f mail_fail2ban fail-auth-mailer
|
||||
}
|
||||
|
||||
#
|
||||
# processes
|
||||
#
|
||||
|
||||
@test "checking process: fail2ban (fail2ban server enabled)" {
|
||||
run docker exec mail_fail2ban /bin/bash -c "ps aux --forest | grep -v grep | grep '/usr/bin/python3 /usr/bin/fail2ban-server'"
|
||||
assert_success
|
||||
}
|
||||
|
||||
#
|
||||
# fail2ban
|
||||
#
|
||||
|
||||
@test "checking fail2ban: localhost is not banned because ignored" {
|
||||
run docker exec mail_fail2ban /bin/sh -c "fail2ban-client status postfix-sasl | grep 'IP list:.*127.0.0.1'"
|
||||
assert_failure
|
||||
run docker exec mail_fail2ban /bin/sh -c "grep 'ignoreip = 127.0.0.1/8' /etc/fail2ban/jail.conf"
|
||||
assert_success
|
||||
}
|
||||
|
||||
@test "checking fail2ban: fail2ban-fail2ban.cf overrides" {
|
||||
run docker exec mail_fail2ban /bin/sh -c "fail2ban-client get loglevel | grep DEBUG"
|
||||
assert_success
|
||||
}
|
||||
|
||||
@test "checking fail2ban: fail2ban-jail.cf overrides" {
|
||||
FILTERS=(dovecot postfix postfix-sasl)
|
||||
|
||||
for FILTER in "${FILTERS[@]}"; do
|
||||
run docker exec mail_fail2ban /bin/sh -c "fail2ban-client get ${FILTER} bantime"
|
||||
assert_output 1234
|
||||
|
||||
run docker exec mail_fail2ban /bin/sh -c "fail2ban-client get ${FILTER} findtime"
|
||||
assert_output 321
|
||||
|
||||
run docker exec mail_fail2ban /bin/sh -c "fail2ban-client get ${FILTER} maxretry"
|
||||
assert_output 2
|
||||
|
||||
run docker exec mail_fail2ban /bin/sh -c "fail2ban-client -d | grep -F \"['set', 'dovecot', 'addaction', 'nftables-multiport']\""
|
||||
assert_output "['set', 'dovecot', 'addaction', 'nftables-multiport']"
|
||||
|
||||
run docker exec mail_fail2ban /bin/sh -c "fail2ban-client -d | grep -F \"['set', 'postfix', 'addaction', 'nftables-multiport']\""
|
||||
assert_output "['set', 'postfix', 'addaction', 'nftables-multiport']"
|
||||
|
||||
run docker exec mail_fail2ban /bin/sh -c "fail2ban-client -d | grep -F \"['set', 'postfix-sasl', 'addaction', 'nftables-multiport']\""
|
||||
assert_output "['set', 'postfix-sasl', 'addaction', 'nftables-multiport']"
|
||||
done
|
||||
}
|
||||
|
||||
@test "checking fail2ban: ban ip on multiple failed login" {
|
||||
# can't pipe the file as usual due to postscreen. (respecting postscreen_greet_wait time and talking in turn):
|
||||
# shellcheck disable=SC1004
|
||||
for _ in {1,2}
|
||||
do
|
||||
docker exec fail-auth-mailer /bin/bash -c \
|
||||
'exec 3<>/dev/tcp/${MAIL_FAIL2BAN_IP}/25 && \
|
||||
while IFS= read -r cmd; do \
|
||||
head -1 <&3; \
|
||||
[[ ${cmd} == "EHLO"* ]] && sleep 6; \
|
||||
echo ${cmd} >&3; \
|
||||
done < "/tmp/docker-mailserver-test/auth/smtp-auth-login-wrong.txt"'
|
||||
done
|
||||
|
||||
sleep 5
|
||||
|
||||
FAIL_AUTH_MAILER_IP=$(docker inspect --format '{{ .NetworkSettings.IPAddress }}' fail-auth-mailer)
|
||||
# Checking that FAIL_AUTH_MAILER_IP is banned in mail_fail2ban
|
||||
run docker exec mail_fail2ban /bin/sh -c "fail2ban-client status postfix-sasl | grep '${FAIL_AUTH_MAILER_IP}'"
|
||||
assert_success
|
||||
|
||||
# Checking that FAIL_AUTH_MAILER_IP is banned by nftables
|
||||
run docker exec mail_fail2ban /bin/sh -c "nft list set inet f2b-table addr-set-postfix-sasl"
|
||||
assert_output --partial "elements = { ${FAIL_AUTH_MAILER_IP} }"
|
||||
}
|
||||
|
||||
@test "checking fail2ban: unban ip works" {
|
||||
FAIL_AUTH_MAILER_IP=$(docker inspect --format '{{ .NetworkSettings.IPAddress }}' fail-auth-mailer)
|
||||
docker exec mail_fail2ban fail2ban-client set postfix-sasl unbanip "${FAIL_AUTH_MAILER_IP}"
|
||||
|
||||
sleep 5
|
||||
|
||||
run docker exec mail_fail2ban /bin/sh -c "fail2ban-client status postfix-sasl | grep 'IP list:.*${FAIL_AUTH_MAILER_IP}'"
|
||||
assert_failure
|
||||
|
||||
# Checking that FAIL_AUTH_MAILER_IP is unbanned by nftables
|
||||
run docker exec mail_fail2ban /bin/sh -c "nft list set inet f2b-table addr-set-postfix-sasl"
|
||||
refute_output --partial "${FAIL_AUTH_MAILER_IP}"
|
||||
}
|
||||
|
||||
@test "checking fail2ban ban" {
|
||||
# Ban single IP address
|
||||
run docker exec mail_fail2ban fail2ban ban 192.0.66.7
|
||||
assert_success
|
||||
assert_output "Banned custom IP: 1"
|
||||
|
||||
run docker exec mail_fail2ban fail2ban
|
||||
assert_success
|
||||
assert_output --regexp "Banned in custom:.*192\.0\.66\.7"
|
||||
|
||||
run docker exec mail_fail2ban nft list set inet f2b-table addr-set-custom
|
||||
assert_success
|
||||
assert_output --partial "elements = { 192.0.66.7 }"
|
||||
|
||||
run docker exec mail_fail2ban fail2ban unban 192.0.66.7
|
||||
assert_success
|
||||
assert_output --partial "Unbanned IP from custom: 1"
|
||||
|
||||
run docker exec mail_fail2ban nft list set inet f2b-table addr-set-custom
|
||||
refute_output --partial "192.0.66.7"
|
||||
|
||||
# Ban IP network
|
||||
run docker exec mail_fail2ban fail2ban ban 192.0.66.0/24
|
||||
assert_success
|
||||
assert_output "Banned custom IP: 1"
|
||||
|
||||
run docker exec mail_fail2ban fail2ban
|
||||
assert_success
|
||||
assert_output --regexp "Banned in custom:.*192\.0\.66\.0/24"
|
||||
|
||||
run docker exec mail_fail2ban nft list set inet f2b-table addr-set-custom
|
||||
assert_success
|
||||
assert_output --partial "elements = { 192.0.66.0/24 }"
|
||||
|
||||
run docker exec mail_fail2ban fail2ban unban 192.0.66.0/24
|
||||
assert_success
|
||||
assert_output --partial "Unbanned IP from custom: 1"
|
||||
|
||||
run docker exec mail_fail2ban nft list set inet f2b-table addr-set-custom
|
||||
refute_output --partial "192.0.66.0/24"
|
||||
}
|
||||
|
||||
@test "checking FAIL2BAN_BLOCKTYPE is really set to drop" {
|
||||
run docker exec mail_fail2ban bash -c 'nft list table inet f2b-table'
|
||||
assert_success
|
||||
assert_output --partial 'tcp dport { 110, 143, 465, 587, 993, 995, 4190 } ip saddr @addr-set-dovecot drop'
|
||||
assert_output --partial 'tcp dport { 25, 110, 143, 465, 587, 993, 995 } ip saddr @addr-set-postfix-sasl drop'
|
||||
assert_output --partial 'tcp dport { 25, 110, 143, 465, 587, 993, 995, 4190 } ip saddr @addr-set-custom drop'
|
||||
}
|
||||
|
||||
@test "checking setup.sh: setup.sh fail2ban" {
|
||||
run docker exec mail_fail2ban /bin/sh -c "fail2ban-client set dovecot banip 192.0.66.4"
|
||||
run docker exec mail_fail2ban /bin/sh -c "fail2ban-client set dovecot banip 192.0.66.5"
|
||||
|
||||
sleep 10
|
||||
|
||||
run ./setup.sh -c mail_fail2ban fail2ban
|
||||
assert_output --regexp '^Banned in dovecot:.*192\.0\.66\.4'
|
||||
assert_output --regexp '^Banned in dovecot:.*192\.0\.66\.5'
|
||||
|
||||
run ./setup.sh -c mail_fail2ban fail2ban unban 192.0.66.4
|
||||
assert_output --partial "Unbanned IP from dovecot: 1"
|
||||
|
||||
run ./setup.sh -c mail_fail2ban fail2ban
|
||||
assert_output --regexp "^Banned in dovecot:.*192\.0\.66\.5"
|
||||
|
||||
run ./setup.sh -c mail_fail2ban fail2ban unban 192.0.66.5
|
||||
assert_output --partial "Unbanned IP from dovecot: 1"
|
||||
|
||||
run ./setup.sh -c mail_fail2ban fail2ban unban
|
||||
assert_output --partial "You need to specify an IP address: Run"
|
||||
}
|
||||
|
||||
#
|
||||
# supervisor
|
||||
#
|
||||
|
||||
@test "checking restart of process: fail2ban (fail2ban server enabled)" {
|
||||
run docker exec mail_fail2ban /bin/bash -c "pkill fail2ban && sleep 10 && ps aux --forest | grep -v grep | grep '/usr/bin/python3 /usr/bin/fail2ban-server'"
|
||||
assert_success
|
||||
}
|
51
test/tests/serial/mail_fetchmail.bats
Normal file
51
test/tests/serial/mail_fetchmail.bats
Normal file
|
@ -0,0 +1,51 @@
|
|||
load 'test_helper/common'
|
||||
|
||||
function setup_file() {
|
||||
local PRIVATE_CONFIG
|
||||
PRIVATE_CONFIG=$(duplicate_config_for_container .)
|
||||
|
||||
docker run -d --name mail_fetchmail \
|
||||
-v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \
|
||||
-v "$(pwd)/test/test-files":/tmp/docker-mailserver-test:ro \
|
||||
-e ENABLE_FETCHMAIL=1 \
|
||||
--cap-add=NET_ADMIN \
|
||||
-h mail.my-domain.com -t "${NAME}"
|
||||
|
||||
wait_for_finished_setup_in_container mail_fetchmail
|
||||
}
|
||||
|
||||
function teardown_file() {
|
||||
docker rm -f mail_fetchmail
|
||||
}
|
||||
|
||||
#
|
||||
# processes
|
||||
#
|
||||
|
||||
@test "checking process: fetchmail (fetchmail server enabled)" {
|
||||
run docker exec mail_fetchmail /bin/bash -c "ps aux --forest | grep -v grep | grep '/usr/bin/fetchmail'"
|
||||
assert_success
|
||||
}
|
||||
|
||||
#
|
||||
# fetchmail
|
||||
#
|
||||
|
||||
@test "checking fetchmail: gerneral options in fetchmailrc are loaded" {
|
||||
run docker exec mail_fetchmail grep 'set syslog' /etc/fetchmailrc
|
||||
assert_success
|
||||
}
|
||||
|
||||
@test "checking fetchmail: fetchmail.cf is loaded" {
|
||||
run docker exec mail_fetchmail grep 'pop3.example.com' /etc/fetchmailrc
|
||||
assert_success
|
||||
}
|
||||
|
||||
#
|
||||
# supervisor
|
||||
#
|
||||
|
||||
@test "checking restart of process: fetchmail" {
|
||||
run docker exec mail_fetchmail /bin/bash -c "pkill fetchmail && sleep 10 && ps aux --forest | grep -v grep | grep '/usr/bin/fetchmail'"
|
||||
assert_success
|
||||
}
|
82
test/tests/serial/mail_fetchmail_parallel.bats
Normal file
82
test/tests/serial/mail_fetchmail_parallel.bats
Normal file
|
@ -0,0 +1,82 @@
|
|||
load 'test_helper/common'
|
||||
|
||||
function setup_file() {
|
||||
local PRIVATE_CONFIG
|
||||
PRIVATE_CONFIG=$(duplicate_config_for_container .)
|
||||
|
||||
docker run -d --name mail_fetchmail_parallel \
|
||||
-v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \
|
||||
-v "$(pwd)/test/test-files":/tmp/docker-mailserver-test:ro \
|
||||
-e ENABLE_FETCHMAIL=1 \
|
||||
-e FETCHMAIL_PARALLEL=1 \
|
||||
--cap-add=NET_ADMIN \
|
||||
-h mail.my-domain.com -t "${NAME}"
|
||||
|
||||
wait_for_finished_setup_in_container mail_fetchmail_parallel
|
||||
}
|
||||
|
||||
function teardown_file() {
|
||||
docker rm -f mail_fetchmail_parallel
|
||||
}
|
||||
|
||||
#
|
||||
# processes
|
||||
#
|
||||
|
||||
@test "checking process: fetchmail 1 (fetchmail server enabled)" {
|
||||
run docker exec mail_fetchmail_parallel /bin/bash -c "ps aux --forest | grep -v grep | grep '/usr/bin/fetchmail -f /etc/fetchmailrc.d/fetchmail-1.rc'"
|
||||
assert_success
|
||||
}
|
||||
|
||||
@test "checking process: fetchmail 2 (fetchmail server enabled)" {
|
||||
run docker exec mail_fetchmail_parallel /bin/bash -c "ps aux --forest | grep -v grep | grep '/usr/bin/fetchmail -f /etc/fetchmailrc.d/fetchmail-2.rc'"
|
||||
assert_success
|
||||
}
|
||||
|
||||
#
|
||||
# fetchmail
|
||||
#
|
||||
|
||||
@test "checking fetchmail: gerneral options in fetchmail-1.rc are loaded" {
|
||||
run docker exec mail_fetchmail_parallel grep 'set syslog' /etc/fetchmailrc.d/fetchmail-1.rc
|
||||
assert_success
|
||||
}
|
||||
|
||||
@test "checking fetchmail: gerneral options in fetchmail-2.rc are loaded" {
|
||||
run docker exec mail_fetchmail_parallel grep 'set syslog' /etc/fetchmailrc.d/fetchmail-2.rc
|
||||
assert_success
|
||||
}
|
||||
|
||||
@test "checking fetchmail: fetchmail-1.rc is loaded with pop3.example.com" {
|
||||
run docker exec mail_fetchmail_parallel grep 'pop3.example.com' /etc/fetchmailrc.d/fetchmail-1.rc
|
||||
assert_success
|
||||
}
|
||||
|
||||
@test "checking fetchmail: fetchmail-1.rc is loaded without pop3-2.example.com" {
|
||||
run docker exec mail_fetchmail_parallel grep 'pop3-2.example.com' /etc/fetchmailrc.d/fetchmail-1.rc
|
||||
assert_failure
|
||||
}
|
||||
|
||||
@test "checking fetchmail: fetchmail-2.rc is loaded without pop3.example.com" {
|
||||
run docker exec mail_fetchmail_parallel grep 'pop3.example.com' /etc/fetchmailrc.d/fetchmail-2.rc
|
||||
assert_failure
|
||||
}
|
||||
|
||||
@test "checking fetchmail: fetchmail-2.rc is loaded with pop3-2.example.com" {
|
||||
run docker exec mail_fetchmail_parallel grep 'pop3-2.example.com' /etc/fetchmailrc.d/fetchmail-2.rc
|
||||
assert_success
|
||||
}
|
||||
|
||||
#
|
||||
# supervisor
|
||||
#
|
||||
|
||||
@test "checking restart of process: fetchmail-1" {
|
||||
run docker exec mail_fetchmail_parallel /bin/bash -c "pkill fetchmail && sleep 10 && ps aux --forest | grep -v grep | grep '/usr/bin/fetchmail -f /etc/fetchmailrc.d/fetchmail-1.rc'"
|
||||
assert_success
|
||||
}
|
||||
|
||||
@test "checking restart of process: fetchmail-2" {
|
||||
run docker exec mail_fetchmail_parallel /bin/bash -c "pkill fetchmail && sleep 10 && ps aux --forest | grep -v grep | grep '/usr/bin/fetchmail -f /etc/fetchmailrc.d/fetchmail-2.rc'"
|
||||
assert_success
|
||||
}
|
214
test/tests/serial/mail_hostname.bats
Normal file
214
test/tests/serial/mail_hostname.bats
Normal file
|
@ -0,0 +1,214 @@
|
|||
load 'test_helper/common'
|
||||
|
||||
|
||||
function setup_file() {
|
||||
local PRIVATE_CONFIG
|
||||
|
||||
PRIVATE_CONFIG=$(duplicate_config_for_container . mail_override_hostname)
|
||||
docker run --rm -d --name mail_override_hostname \
|
||||
-v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \
|
||||
-v "$(pwd)/test/test-files":/tmp/docker-mailserver-test:ro \
|
||||
-e PERMIT_DOCKER=network \
|
||||
-e ENABLE_SRS=1 \
|
||||
-e OVERRIDE_HOSTNAME=mail.my-domain.com \
|
||||
--hostname unknown.domain.tld \
|
||||
--tty \
|
||||
--ulimit "nofile=$(ulimit -Sn):$(ulimit -Hn)" \
|
||||
"${NAME}"
|
||||
|
||||
PRIVATE_CONFIG_TWO=$(duplicate_config_for_container . mail_non_subdomain_hostname)
|
||||
docker run --rm -d --name mail_non_subdomain_hostname \
|
||||
-v "${PRIVATE_CONFIG_TWO}":/tmp/docker-mailserver \
|
||||
-v "$(pwd)/test/test-files":/tmp/docker-mailserver-test:ro \
|
||||
-e PERMIT_DOCKER=network \
|
||||
-e ENABLE_SRS=1 \
|
||||
--hostname domain.com \
|
||||
--tty \
|
||||
--ulimit "nofile=$(ulimit -Sn):$(ulimit -Hn)" \
|
||||
"${NAME}"
|
||||
|
||||
PRIVATE_CONFIG_THREE=$(duplicate_config_for_container . mail_srs_domainname)
|
||||
docker run --rm -d --name mail_srs_domainname \
|
||||
-v "${PRIVATE_CONFIG_THREE}":/tmp/docker-mailserver \
|
||||
-v "$(pwd)/test/test-files":/tmp/docker-mailserver-test:ro \
|
||||
-e PERMIT_DOCKER=network \
|
||||
-e ENABLE_SRS=1 \
|
||||
-e SRS_DOMAINNAME='srs.my-domain.com' \
|
||||
--domainname 'my-domain.com' \
|
||||
--hostname 'mail' \
|
||||
--tty \
|
||||
--ulimit "nofile=$(ulimit -Sn):$(ulimit -Hn)" \
|
||||
"${NAME}"
|
||||
|
||||
PRIVATE_CONFIG_FOUR=$(duplicate_config_for_container . mail_domainname)
|
||||
docker run --rm -d --name mail_domainname \
|
||||
-v "${PRIVATE_CONFIG_FOUR}":/tmp/docker-mailserver \
|
||||
-v "$(pwd)/test/test-files":/tmp/docker-mailserver-test:ro \
|
||||
-e PERMIT_DOCKER=network \
|
||||
-e ENABLE_SRS=1 \
|
||||
--domainname 'my-domain.com' \
|
||||
--hostname 'mail' \
|
||||
--tty \
|
||||
--ulimit "nofile=$(ulimit -Sn):$(ulimit -Hn)" \
|
||||
"${NAME}"
|
||||
|
||||
wait_for_smtp_port_in_container mail_override_hostname
|
||||
wait_for_smtp_port_in_container mail_non_subdomain_hostname
|
||||
wait_for_smtp_port_in_container mail_srs_domainname
|
||||
wait_for_smtp_port_in_container mail_domainname
|
||||
|
||||
# postfix virtual transport lmtp
|
||||
docker exec mail_override_hostname /bin/sh -c "nc 0.0.0.0 25 < /tmp/docker-mailserver-test/email-templates/existing-user1.txt"
|
||||
docker exec mail_non_subdomain_hostname /bin/sh -c "nc 0.0.0.0 25 < /tmp/docker-mailserver-test/email-templates/existing-user1.txt"
|
||||
}
|
||||
|
||||
function teardown_file() {
|
||||
# Running `docker rm -f` too soon after `docker stop` can result in failure during teardown with:
|
||||
# "Error response from daemon: removal of container mail_domainname is already in progress"
|
||||
sleep 1
|
||||
|
||||
docker rm -f mail_override_hostname mail_non_subdomain_hostname mail_srs_domainname mail_domainname
|
||||
}
|
||||
|
||||
@test "checking SRS: SRS_DOMAINNAME is used correctly" {
|
||||
repeat_until_success_or_timeout 15 docker exec mail_srs_domainname grep "SRS_DOMAIN=srs.my-domain.com" /etc/default/postsrsd
|
||||
}
|
||||
|
||||
@test "checking SRS: DOMAINNAME is handled correctly" {
|
||||
repeat_until_success_or_timeout 15 docker exec mail_domainname grep "SRS_DOMAIN=my-domain.com" /etc/default/postsrsd
|
||||
}
|
||||
|
||||
@test "checking configuration: hostname/domainname override: check container hostname is applied correctly" {
|
||||
run docker exec mail_override_hostname /bin/bash -c "hostname | grep unknown.domain.tld"
|
||||
assert_success
|
||||
}
|
||||
|
||||
@test "checking configuration: hostname/domainname override: check overriden hostname is applied to all configs" {
|
||||
run docker exec mail_override_hostname /bin/bash -c "cat /etc/mailname | grep my-domain.com"
|
||||
assert_success
|
||||
|
||||
run docker exec mail_override_hostname /bin/bash -c "postconf -n | grep mydomain | grep my-domain.com"
|
||||
assert_success
|
||||
|
||||
run docker exec mail_override_hostname /bin/bash -c "postconf -n | grep myhostname | grep mail.my-domain.com"
|
||||
assert_success
|
||||
|
||||
run docker exec mail_override_hostname /bin/bash -c "doveconf | grep hostname | grep mail.my-domain.com"
|
||||
assert_success
|
||||
|
||||
run docker exec mail_override_hostname /bin/bash -c "cat /etc/opendmarc.conf | grep AuthservID | grep mail.my-domain.com"
|
||||
assert_success
|
||||
|
||||
run docker exec mail_override_hostname /bin/bash -c "cat /etc/opendmarc.conf | grep TrustedAuthservIDs | grep mail.my-domain.com"
|
||||
assert_success
|
||||
|
||||
run docker exec mail_override_hostname /bin/bash -c "cat /etc/amavis/conf.d/05-node_id | grep myhostname | grep mail.my-domain.com"
|
||||
assert_success
|
||||
}
|
||||
|
||||
@test "checking configuration: hostname/domainname override: check hostname in postfix HELO message" {
|
||||
run docker exec mail_override_hostname /bin/bash -c "nc -w 1 0.0.0.0 25 | grep mail.my-domain.com"
|
||||
assert_success
|
||||
}
|
||||
|
||||
@test "checking configuration: hostname/domainname override: check headers of received mail" {
|
||||
run docker exec mail_override_hostname /bin/sh -c "ls -A /var/mail/localhost.localdomain/user1/new | wc -l | grep 1"
|
||||
assert_success
|
||||
|
||||
run docker exec mail_override_hostname /bin/sh -c "cat /var/mail/localhost.localdomain/user1/new/* | grep mail.my-domain.com"
|
||||
assert_success
|
||||
|
||||
# test whether the container hostname is not found in received mail
|
||||
run docker exec mail_override_hostname /bin/sh -c "cat /var/mail/localhost.localdomain/user1/new/* | grep unknown.domain.tld"
|
||||
assert_failure
|
||||
}
|
||||
|
||||
@test "checking SRS: OVERRIDE_HOSTNAME is handled correctly" {
|
||||
run docker exec mail_override_hostname grep "SRS_DOMAIN=my-domain.com" /etc/default/postsrsd
|
||||
assert_success
|
||||
}
|
||||
|
||||
@test "checking dovecot: postmaster address" {
|
||||
run docker exec mail_override_hostname /bin/sh -c "grep 'postmaster_address = postmaster@my-domain.com' /etc/dovecot/conf.d/15-lda.conf"
|
||||
assert_success
|
||||
}
|
||||
|
||||
#
|
||||
# non-subdomain tests
|
||||
#
|
||||
|
||||
@test "checking configuration: non-subdomain: check container hostname is applied correctly" {
|
||||
run docker exec mail_non_subdomain_hostname /bin/bash -c "hostname | grep domain.com"
|
||||
assert_success
|
||||
}
|
||||
|
||||
@test "checking configuration: non-subdomain: check overriden hostname is applied to all configs" {
|
||||
run docker exec mail_non_subdomain_hostname /bin/bash -c "cat /etc/mailname | grep domain.com"
|
||||
assert_success
|
||||
|
||||
run docker exec mail_non_subdomain_hostname /bin/bash -c "postconf -n | grep mydomain | grep domain.com"
|
||||
assert_success
|
||||
|
||||
run docker exec mail_non_subdomain_hostname /bin/bash -c "postconf -n | grep myhostname | grep domain.com"
|
||||
assert_success
|
||||
|
||||
run docker exec mail_non_subdomain_hostname /bin/bash -c "doveconf | grep hostname | grep domain.com"
|
||||
assert_success
|
||||
|
||||
run docker exec mail_non_subdomain_hostname /bin/bash -c "cat /etc/opendmarc.conf | grep AuthservID | grep domain.com"
|
||||
assert_success
|
||||
|
||||
run docker exec mail_non_subdomain_hostname /bin/bash -c "cat /etc/opendmarc.conf | grep TrustedAuthservIDs | grep domain.com"
|
||||
assert_success
|
||||
|
||||
run docker exec mail_non_subdomain_hostname /bin/bash -c "cat /etc/amavis/conf.d/05-node_id | grep myhostname | grep domain.com"
|
||||
assert_success
|
||||
}
|
||||
|
||||
@test "checking configuration: non-subdomain: check hostname in postfix HELO message" {
|
||||
run docker exec mail_non_subdomain_hostname /bin/bash -c "nc -w 1 0.0.0.0 25 | grep domain.com"
|
||||
assert_success
|
||||
}
|
||||
|
||||
@test "checking configuration: non-subdomain: check headers of received mail" {
|
||||
run docker exec mail_non_subdomain_hostname /bin/sh -c "ls -A /var/mail/localhost.localdomain/user1/new | wc -l | grep 1"
|
||||
assert_success
|
||||
|
||||
run docker exec mail_non_subdomain_hostname /bin/sh -c "cat /var/mail/localhost.localdomain/user1/new/* | grep domain.com"
|
||||
assert_success
|
||||
}
|
||||
|
||||
@test "checking SRS: non-subdomain is handled correctly" {
|
||||
docker exec mail_non_subdomain_hostname cat /etc/default/postsrsd
|
||||
run docker exec mail_non_subdomain_hostname grep "SRS_DOMAIN=domain.com" /etc/default/postsrsd
|
||||
assert_success
|
||||
}
|
||||
|
||||
@test "checking dovecot: non-subdomain postmaster address" {
|
||||
run docker exec mail_non_subdomain_hostname /bin/sh -c "grep 'postmaster_address = postmaster@domain.com' /etc/dovecot/conf.d/15-lda.conf"
|
||||
assert_success
|
||||
}
|
||||
|
||||
#
|
||||
# clean exit
|
||||
#
|
||||
|
||||
@test "checking that the container stops cleanly: mail_override_hostname" {
|
||||
run docker stop -t 60 mail_override_hostname
|
||||
assert_success
|
||||
}
|
||||
|
||||
@test "checking that the container stops cleanly: mail_non_subdomain_hostname" {
|
||||
run docker stop -t 60 mail_non_subdomain_hostname
|
||||
assert_success
|
||||
}
|
||||
|
||||
@test "checking that the container stops cleanly: mail_srs_domainname" {
|
||||
run docker stop -t 60 mail_srs_domainname
|
||||
assert_success
|
||||
}
|
||||
|
||||
@test "checking that the container stops cleanly: mail_domainname" {
|
||||
run docker stop -t 60 mail_domainname
|
||||
assert_success
|
||||
}
|
44
test/tests/serial/mail_lmtp_ip.bats
Normal file
44
test/tests/serial/mail_lmtp_ip.bats
Normal file
|
@ -0,0 +1,44 @@
|
|||
load 'test_helper/common'
|
||||
|
||||
setup_file() {
|
||||
local PRIVATE_CONFIG PRIVATE_ETC
|
||||
PRIVATE_CONFIG=$(duplicate_config_for_container .)
|
||||
PRIVATE_ETC=$(duplicate_config_for_container dovecot-lmtp/ mail_lmtp_ip_dovecot-lmtp)
|
||||
|
||||
docker run -d --name mail_lmtp_ip \
|
||||
-v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \
|
||||
-v "${PRIVATE_ETC}":/etc/dovecot \
|
||||
-v "$(pwd)/test/test-files":/tmp/docker-mailserver-test:ro \
|
||||
-e ENABLE_POSTFIX_VIRTUAL_TRANSPORT=1 \
|
||||
-e POSTFIX_DAGENT=lmtp:127.0.0.1:24 \
|
||||
-e PERMIT_DOCKER=container \
|
||||
-h mail.my-domain.com -t "${NAME}"
|
||||
|
||||
wait_for_finished_setup_in_container mail_lmtp_ip
|
||||
}
|
||||
|
||||
teardown_file() {
|
||||
docker rm -f mail_lmtp_ip
|
||||
}
|
||||
|
||||
#
|
||||
# Postfix VIRTUAL_TRANSPORT
|
||||
#
|
||||
@test "checking postfix-lmtp: virtual_transport config is set" {
|
||||
run docker exec mail_lmtp_ip /bin/sh -c "grep 'virtual_transport = lmtp:127.0.0.1:24' /etc/postfix/main.cf"
|
||||
assert_success
|
||||
}
|
||||
|
||||
@test "checking postfix-lmtp: delivers mail to existing account" {
|
||||
# maybe we can move this into the setup to speed things up futher.
|
||||
# this likely would need an async coroutine to avoid blocking the other tests while waiting for the server to come up
|
||||
wait_for_smtp_port_in_container mail_lmtp_ip
|
||||
run docker exec mail_lmtp_ip /bin/sh -c "nc 0.0.0.0 25 < /tmp/docker-mailserver-test/email-templates/existing-user1.txt"
|
||||
assert_success
|
||||
|
||||
# polling needs to avoid wc -l's unconditionally successful return status
|
||||
repeat_until_success_or_timeout 60 docker exec mail_lmtp_ip /bin/sh -c "grep 'postfix/lmtp' /var/log/mail/mail.log | grep 'status=sent' | grep ' Saved)'"
|
||||
run docker exec mail_lmtp_ip /bin/sh -c "grep 'postfix/lmtp' /var/log/mail/mail.log | grep 'status=sent' | grep ' Saved)' | wc -l"
|
||||
assert_success
|
||||
assert_output 1
|
||||
}
|
85
test/tests/serial/mail_pop3.bats
Normal file
85
test/tests/serial/mail_pop3.bats
Normal file
|
@ -0,0 +1,85 @@
|
|||
load 'test_helper/common'
|
||||
|
||||
function setup_file() {
|
||||
local PRIVATE_CONFIG
|
||||
PRIVATE_CONFIG=$(duplicate_config_for_container .)
|
||||
|
||||
docker run -d --name mail_pop3 \
|
||||
-v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \
|
||||
-v "$(pwd)/test/test-files":/tmp/docker-mailserver-test:ro \
|
||||
-e ENABLE_POP3=1 \
|
||||
-e PERMIT_DOCKER=container \
|
||||
-h mail.my-domain.com -t "${NAME}"
|
||||
|
||||
wait_for_finished_setup_in_container mail_pop3
|
||||
}
|
||||
|
||||
function teardown_file() {
|
||||
docker rm -f mail_pop3
|
||||
}
|
||||
|
||||
#
|
||||
# pop
|
||||
#
|
||||
|
||||
@test "checking pop: server is ready" {
|
||||
run docker exec mail_pop3 /bin/bash -c "nc -w 1 0.0.0.0 110 | grep '+OK'"
|
||||
assert_success
|
||||
}
|
||||
|
||||
@test "checking pop: authentication works" {
|
||||
run docker exec mail_pop3 /bin/sh -c "nc -w 1 0.0.0.0 110 < /tmp/docker-mailserver-test/auth/pop3-auth.txt"
|
||||
assert_success
|
||||
}
|
||||
|
||||
@test "checking pop: added user authentication works" {
|
||||
run docker exec mail_pop3 /bin/sh -c "nc -w 1 0.0.0.0 110 < /tmp/docker-mailserver-test/auth/added-pop3-auth.txt"
|
||||
assert_success
|
||||
}
|
||||
|
||||
#
|
||||
# spamassassin
|
||||
#
|
||||
|
||||
@test "checking spamassassin: docker env variables are set correctly (default)" {
|
||||
run docker exec mail_pop3 /bin/sh -c "grep '\$sa_tag_level_deflt' /etc/amavis/conf.d/20-debian_defaults | grep '= 2.0'"
|
||||
assert_success
|
||||
|
||||
run docker exec mail_pop3 /bin/sh -c "grep '\$sa_tag2_level_deflt' /etc/amavis/conf.d/20-debian_defaults | grep '= 6.31'"
|
||||
assert_success
|
||||
|
||||
run docker exec mail_pop3 /bin/sh -c "grep '\$sa_kill_level_deflt' /etc/amavis/conf.d/20-debian_defaults | grep '= 6.31'"
|
||||
assert_success
|
||||
|
||||
run docker exec mail_pop3 /bin/sh -c "grep '\$sa_spam_subject_tag' /etc/amavis/conf.d/20-debian_defaults | grep '= .\*\*\*SPAM\*\*\* .'"
|
||||
assert_success
|
||||
}
|
||||
|
||||
#
|
||||
# system
|
||||
#
|
||||
|
||||
@test "checking system: /var/log/mail/mail.log is error free" {
|
||||
run docker exec mail_pop3 grep 'non-null host address bits in' /var/log/mail/mail.log
|
||||
assert_failure
|
||||
|
||||
run docker exec mail_pop3 grep ': error:' /var/log/mail/mail.log
|
||||
assert_failure
|
||||
}
|
||||
|
||||
#
|
||||
# sieve
|
||||
#
|
||||
|
||||
@test "checking manage sieve: disabled per default" {
|
||||
run docker exec mail_pop3 /bin/bash -c "nc -z 0.0.0.0 4190"
|
||||
assert_failure
|
||||
}
|
||||
|
||||
#
|
||||
# PERMIT_DOCKER mynetworks
|
||||
#
|
||||
@test "checking PERMIT_DOCKER: my network value" {
|
||||
run docker exec mail_pop3 /bin/sh -c "postconf | grep '^mynetworks =' | egrep '[[:digit:]]{1,3}\.[[:digit:]]{1,3}\.[[:digit:]]{1,3}\.[[:digit:]]{1,3}/32'"
|
||||
assert_success
|
||||
}
|
80
test/tests/serial/mail_postfix_inet.bats
Normal file
80
test/tests/serial/mail_postfix_inet.bats
Normal file
|
@ -0,0 +1,80 @@
|
|||
load 'test_helper/common'
|
||||
|
||||
# Test case
|
||||
# ---------
|
||||
# POSTFIX_INET_PROTOCOLS value is set
|
||||
|
||||
@test "checking postfix: inet default" {
|
||||
local PRIVATE_CONFIG
|
||||
PRIVATE_CONFIG=$(duplicate_config_for_container . )
|
||||
|
||||
docker run -d --name mail_postfix_inet_default \
|
||||
-v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \
|
||||
-v "$(pwd)/test/test-files":/tmp/docker-mailserver-test:ro \
|
||||
-h mail.my-domain.com -t "${NAME}"
|
||||
|
||||
teardown() { docker rm -f mail_postfix_inet_default; }
|
||||
|
||||
wait_for_finished_setup_in_container mail_postfix_inet_default
|
||||
|
||||
run docker exec mail_postfix_inet_default postconf inet_protocols
|
||||
assert_output "inet_protocols = all"
|
||||
assert_success
|
||||
}
|
||||
|
||||
@test "checking postfix: inet all" {
|
||||
local PRIVATE_CONFIG
|
||||
PRIVATE_CONFIG=$(duplicate_config_for_container . )
|
||||
|
||||
docker run -d --name mail_postfix_inet_all \
|
||||
-v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \
|
||||
-v "$(pwd)/test/test-files":/tmp/docker-mailserver-test:ro \
|
||||
-e POSTFIX_INET_PROTOCOLS=all \
|
||||
-h mail.my-domain.com -t "${NAME}"
|
||||
|
||||
teardown() { docker rm -f mail_postfix_inet_all; }
|
||||
|
||||
wait_for_finished_setup_in_container mail_postfix_inet_all
|
||||
|
||||
run docker exec mail_postfix_inet_all postconf inet_protocols
|
||||
assert_output "inet_protocols = all"
|
||||
assert_success
|
||||
}
|
||||
|
||||
@test "checking postfix: inet ipv4" {
|
||||
local PRIVATE_CONFIG
|
||||
PRIVATE_CONFIG=$(duplicate_config_for_container . )
|
||||
|
||||
docker run -d --name mail_postfix_inet_ipv4 \
|
||||
-v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \
|
||||
-v "$(pwd)/test/test-files":/tmp/docker-mailserver-test:ro \
|
||||
-e POSTFIX_INET_PROTOCOLS=ipv4 \
|
||||
-h mail.my-domain.com -t "${NAME}"
|
||||
|
||||
teardown() { docker rm -f mail_postfix_inet_ipv4; }
|
||||
|
||||
wait_for_finished_setup_in_container mail_postfix_inet_ipv4
|
||||
|
||||
run docker exec mail_postfix_inet_ipv4 postconf inet_protocols
|
||||
assert_output "inet_protocols = ipv4"
|
||||
assert_success
|
||||
}
|
||||
|
||||
@test "checking postfix: inet ipv6" {
|
||||
local PRIVATE_CONFIG
|
||||
PRIVATE_CONFIG=$(duplicate_config_for_container . )
|
||||
|
||||
docker run -d --name mail_postfix_inet_ipv6 \
|
||||
-v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \
|
||||
-v "$(pwd)/test/test-files":/tmp/docker-mailserver-test:ro \
|
||||
-e POSTFIX_INET_PROTOCOLS=ipv6 \
|
||||
-h mail.my-domain.com -t "${NAME}"
|
||||
|
||||
teardown() { docker rm -f mail_postfix_inet_ipv6; }
|
||||
|
||||
wait_for_finished_setup_in_container mail_postfix_inet_ipv6
|
||||
|
||||
run docker exec mail_postfix_inet_ipv6 postconf inet_protocols
|
||||
assert_output "inet_protocols = ipv6"
|
||||
assert_success
|
||||
}
|
52
test/tests/serial/mail_postscreen.bats
Normal file
52
test/tests/serial/mail_postscreen.bats
Normal file
|
@ -0,0 +1,52 @@
|
|||
load 'test_helper/common'
|
||||
|
||||
setup() {
|
||||
# Getting mail container IP
|
||||
MAIL_POSTSCREEN_IP=$(docker inspect --format '{{ .NetworkSettings.IPAddress }}' mail_postscreen)
|
||||
}
|
||||
|
||||
setup_file() {
|
||||
local PRIVATE_CONFIG
|
||||
PRIVATE_CONFIG=$(duplicate_config_for_container .)
|
||||
|
||||
docker run -d --name mail_postscreen \
|
||||
-v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \
|
||||
-v "$(pwd)/test/test-files":/tmp/docker-mailserver-test:ro \
|
||||
-e POSTSCREEN_ACTION=enforce \
|
||||
--cap-add=NET_ADMIN \
|
||||
-h mail.my-domain.com -t "${NAME}"
|
||||
|
||||
docker run --name mail_postscreen_sender \
|
||||
-v "$(pwd)/test/test-files":/tmp/docker-mailserver-test:ro \
|
||||
-d "${NAME}" \
|
||||
tail -f /var/log/faillog
|
||||
|
||||
wait_for_smtp_port_in_container mail_postscreen
|
||||
}
|
||||
|
||||
teardown_file() {
|
||||
docker rm -f mail_postscreen mail_postscreen_sender
|
||||
}
|
||||
|
||||
@test "checking postscreen: talk too fast" {
|
||||
docker exec mail_postscreen_sender /bin/sh -c "nc ${MAIL_POSTSCREEN_IP} 25 < /tmp/docker-mailserver-test/auth/smtp-auth-login.txt"
|
||||
|
||||
repeat_until_success_or_timeout 10 run docker exec mail_postscreen grep 'COMMAND PIPELINING' /var/log/mail/mail.log
|
||||
assert_success
|
||||
}
|
||||
|
||||
@test "checking postscreen: positive test (respecting postscreen_greet_wait time and talking in turn)" {
|
||||
for _ in {1,2}; do
|
||||
# shellcheck disable=SC1004
|
||||
docker exec mail_postscreen_sender /bin/bash -c \
|
||||
'exec 3<>/dev/tcp/'"${MAIL_POSTSCREEN_IP}"'/25 && \
|
||||
while IFS= read -r cmd; do \
|
||||
head -1 <&3; \
|
||||
[[ ${cmd} == "EHLO"* ]] && sleep 6; \
|
||||
echo ${cmd} >&3; \
|
||||
done < "/tmp/docker-mailserver-test/auth/smtp-auth-login.txt"'
|
||||
done
|
||||
|
||||
repeat_until_success_or_timeout 10 run docker exec mail_postscreen grep 'PASS NEW ' /var/log/mail/mail.log
|
||||
assert_success
|
||||
}
|
39
test/tests/serial/mail_privacy.bats
Normal file
39
test/tests/serial/mail_privacy.bats
Normal file
|
@ -0,0 +1,39 @@
|
|||
load 'test_helper/common'
|
||||
|
||||
function setup_file() {
|
||||
local PRIVATE_CONFIG
|
||||
PRIVATE_CONFIG=$(duplicate_config_for_container .)
|
||||
|
||||
docker run -d --name mail_privacy \
|
||||
-v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \
|
||||
-v "$(pwd)/test/test-files":/tmp/docker-mailserver-test:ro \
|
||||
-e ENABLE_MANAGESIEVE=1 \
|
||||
-e PERMIT_DOCKER=host \
|
||||
-h mail.my-domain.com \
|
||||
-e SSL_TYPE='snakeoil' \
|
||||
--tty \
|
||||
"${NAME}" # Image name
|
||||
|
||||
wait_for_amavis_port_in_container mail_privacy
|
||||
wait_for_smtp_port_in_container mail_privacy
|
||||
}
|
||||
|
||||
function teardown_file() {
|
||||
docker rm -f mail_privacy
|
||||
}
|
||||
|
||||
# What this test should cover: https://github.com/docker-mailserver/docker-mailserver/issues/681
|
||||
@test "checking postfix: remove privacy details of the sender" {
|
||||
docker exec mail_privacy /bin/sh -c "openssl s_client -quiet -starttls smtp -connect 0.0.0.0:587 < /tmp/docker-mailserver-test/email-templates/send-privacy-email.txt"
|
||||
# shellcheck disable=SC2016
|
||||
repeat_until_success_or_timeout 120 docker exec mail_privacy /bin/bash -c '[[ $(ls /var/mail/localhost.localdomain/user1/new | wc -l) -eq 1 ]]'
|
||||
docker logs mail_privacy
|
||||
|
||||
run docker exec mail_privacy /bin/sh -c "ls /var/mail/localhost.localdomain/user1/new | wc -l"
|
||||
assert_success
|
||||
assert_output 1
|
||||
|
||||
run docker exec mail_privacy /bin/sh -c 'grep -rE "^User-Agent:" /var/mail/localhost.localdomain/user1/new | wc -l'
|
||||
assert_success
|
||||
assert_output 0
|
||||
}
|
43
test/tests/serial/mail_quotas_disabled.bats
Normal file
43
test/tests/serial/mail_quotas_disabled.bats
Normal file
|
@ -0,0 +1,43 @@
|
|||
load 'test_helper/common'
|
||||
|
||||
# Test case
|
||||
# ---------
|
||||
# When ENABLE_QUOTAS is explicitly disabled (ENABLE_QUOTAS=0), dovecot quota must not be enabled.
|
||||
|
||||
|
||||
function setup_file() {
|
||||
local PRIVATE_CONFIG
|
||||
PRIVATE_CONFIG=$(duplicate_config_for_container .)
|
||||
|
||||
docker run -d --name mail_no_quotas \
|
||||
-v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \
|
||||
-v "$(pwd)/test/test-files":/tmp/docker-mailserver-test:ro \
|
||||
-e ENABLE_QUOTAS=0 \
|
||||
-h mail.my-domain.com -t "${NAME}"
|
||||
|
||||
wait_for_finished_setup_in_container mail_no_quotas
|
||||
}
|
||||
|
||||
function teardown_file() {
|
||||
docker rm -f mail_no_quotas
|
||||
}
|
||||
|
||||
@test "checking dovecot: (ENABLE_QUOTAS=0) quota plugin is disabled" {
|
||||
run docker exec mail_no_quotas /bin/sh -c "grep '\$mail_plugins quota' /etc/dovecot/conf.d/10-mail.conf"
|
||||
assert_failure
|
||||
|
||||
run docker exec mail_no_quotas /bin/sh -c "grep '\$mail_plugins imap_quota' /etc/dovecot/conf.d/20-imap.conf"
|
||||
assert_failure
|
||||
|
||||
run docker exec mail_no_quotas ls /etc/dovecot/conf.d/90-quota.conf
|
||||
assert_failure
|
||||
|
||||
run docker exec mail_no_quotas ls /etc/dovecot/conf.d/90-quota.conf.disab
|
||||
assert_success
|
||||
}
|
||||
|
||||
@test "checking postfix: (ENABLE_QUOTAS=0) dovecot quota absent in postconf" {
|
||||
run docker exec mail_no_quotas /bin/bash -c "postconf | grep 'check_policy_service inet:localhost:65265'"
|
||||
assert_failure
|
||||
}
|
||||
|
68
test/tests/serial/mail_smtponly.bats
Normal file
68
test/tests/serial/mail_smtponly.bats
Normal file
|
@ -0,0 +1,68 @@
|
|||
load 'test_helper/common'
|
||||
|
||||
function setup_file() {
|
||||
docker run --rm -d --name mail_smtponly \
|
||||
-v "$(pwd)/test/test-files":/tmp/docker-mailserver-test:ro \
|
||||
-e SMTP_ONLY=1 \
|
||||
-e PERMIT_DOCKER=network \
|
||||
-e OVERRIDE_HOSTNAME=mail.my-domain.com \
|
||||
-t "${NAME}"
|
||||
|
||||
wait_for_finished_setup_in_container mail_smtponly
|
||||
}
|
||||
|
||||
function teardown_file() {
|
||||
docker rm -f mail_smtponly
|
||||
}
|
||||
|
||||
#
|
||||
# configuration checks
|
||||
#
|
||||
|
||||
@test "checking configuration: hostname/domainname override" {
|
||||
run docker exec mail_smtponly /bin/bash -c "cat /etc/mailname | grep my-domain.com"
|
||||
assert_success
|
||||
}
|
||||
|
||||
#
|
||||
# imap
|
||||
#
|
||||
|
||||
@test "checking process: dovecot imaplogin (disabled using SMTP_ONLY)" {
|
||||
run docker exec mail_smtponly /bin/bash -c "ps aux --forest | grep -v grep | grep '/usr/sbin/dovecot'"
|
||||
assert_failure
|
||||
}
|
||||
|
||||
@test "checking configuration: dovecot quota absent in postconf (disabled using SMTP_ONLY)" {
|
||||
run docker exec mail_smtponly /bin/bash -c "postconf | grep 'check_policy_service inet:localhost:65265'"
|
||||
assert_failure
|
||||
}
|
||||
|
||||
#
|
||||
# smtp
|
||||
#
|
||||
|
||||
@test "checking smtp_only: mail send should work" {
|
||||
run docker exec mail_smtponly /bin/sh -c "postconf smtp_host_lookup=no"
|
||||
assert_success
|
||||
run docker exec mail_smtponly /bin/sh -c "/etc/init.d/postfix reload"
|
||||
assert_success
|
||||
|
||||
wait_for_smtp_port_in_container mail_smtponly
|
||||
run docker exec mail_smtponly /bin/sh -c "nc 0.0.0.0 25 < /tmp/docker-mailserver-test/email-templates/smtp-only.txt"
|
||||
assert_success
|
||||
run docker exec mail_smtponly /bin/sh -c 'grep -cE "to=<user2\@external.tld>.*status\=sent" /var/log/mail/mail.log'
|
||||
[[ ${status} -ge 0 ]]
|
||||
}
|
||||
|
||||
#
|
||||
# PERMIT_DOCKER=network
|
||||
#
|
||||
|
||||
@test "checking PERMIT_DOCKER=network: opendmarc/opendkim config" {
|
||||
run docker exec mail_smtponly /bin/sh -c "cat /etc/opendmarc/ignore.hosts | grep '172.16.0.0/12'"
|
||||
assert_success
|
||||
|
||||
run docker exec mail_smtponly /bin/sh -c "cat /etc/opendkim/TrustedHosts | grep '172.16.0.0/12'"
|
||||
assert_success
|
||||
}
|
67
test/tests/serial/mail_spam_junk_folder.bats
Normal file
67
test/tests/serial/mail_spam_junk_folder.bats
Normal file
|
@ -0,0 +1,67 @@
|
|||
load 'test_helper/common'
|
||||
|
||||
# Test case
|
||||
# ---------
|
||||
# When SPAMASSASSIN_SPAM_TO_INBOX=1, spam messages must be delivered and eventually (MOVE_SPAM_TO_JUNK=1) moved to the Junk folder.
|
||||
|
||||
@test "checking amavis: spam message is delivered and moved to the Junk folder (MOVE_SPAM_TO_JUNK=1)" {
|
||||
local PRIVATE_CONFIG
|
||||
PRIVATE_CONFIG=$(duplicate_config_for_container . mail_spam_moved_junk)
|
||||
|
||||
docker run -d --name mail_spam_moved_junk \
|
||||
-v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \
|
||||
-v "$(pwd)/test/test-files":/tmp/docker-mailserver-test:ro \
|
||||
-e ENABLE_SPAMASSASSIN=1 \
|
||||
-e MOVE_SPAM_TO_JUNK=1 \
|
||||
-e PERMIT_DOCKER=container \
|
||||
-e SA_SPAM_SUBJECT="SPAM: " \
|
||||
-e SPAMASSASSIN_SPAM_TO_INBOX=1 \
|
||||
-h mail.my-domain.com -t "${NAME}"
|
||||
|
||||
teardown() { docker rm -f mail_spam_moved_junk; }
|
||||
|
||||
wait_for_smtp_port_in_container mail_spam_moved_junk
|
||||
|
||||
# send a spam message
|
||||
run docker exec mail_spam_moved_junk /bin/sh -c "nc 0.0.0.0 25 < /tmp/docker-mailserver-test/email-templates/amavis-spam.txt"
|
||||
assert_success
|
||||
|
||||
# message will be added to a queue with varying delay until amavis receives it
|
||||
run repeat_until_success_or_timeout 60 sh -c "docker logs mail_spam_moved_junk | grep 'Passed SPAM {RelayedTaggedInbound,Quarantined}'"
|
||||
assert_success
|
||||
|
||||
# spam moved to Junk folder
|
||||
run repeat_until_success_or_timeout 20 sh -c "docker exec mail_spam_moved_junk sh -c 'grep \"Subject: SPAM: \" /var/mail/localhost.localdomain/user1/.Junk/new/ -R'"
|
||||
assert_success
|
||||
}
|
||||
|
||||
@test "checking amavis: spam message is delivered to INBOX (MOVE_SPAM_TO_JUNK=0)" {
|
||||
local PRIVATE_CONFIG
|
||||
PRIVATE_CONFIG=$(duplicate_config_for_container . mail_spam_moved_new)
|
||||
|
||||
docker run -d --name mail_spam_moved_new \
|
||||
-v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \
|
||||
-v "$(pwd)/test/test-files":/tmp/docker-mailserver-test:ro \
|
||||
-e ENABLE_SPAMASSASSIN=1 \
|
||||
-e MOVE_SPAM_TO_JUNK=0 \
|
||||
-e PERMIT_DOCKER=container \
|
||||
-e SA_SPAM_SUBJECT="SPAM: " \
|
||||
-e SPAMASSASSIN_SPAM_TO_INBOX=1 \
|
||||
-h mail.my-domain.com -t "${NAME}"
|
||||
|
||||
teardown() { docker rm -f mail_spam_moved_new; }
|
||||
|
||||
wait_for_smtp_port_in_container mail_spam_moved_new
|
||||
|
||||
# send a spam message
|
||||
run docker exec mail_spam_moved_new /bin/sh -c "nc 0.0.0.0 25 < /tmp/docker-mailserver-test/email-templates/amavis-spam.txt"
|
||||
assert_success
|
||||
|
||||
# message will be added to a queue with varying delay until amavis receives it
|
||||
run repeat_until_success_or_timeout 60 sh -c "docker logs mail_spam_moved_new | grep 'Passed SPAM {RelayedTaggedInbound,Quarantined}'"
|
||||
assert_success
|
||||
|
||||
# spam moved to INBOX
|
||||
run repeat_until_success_or_timeout 20 sh -c "docker exec mail_spam_moved_new sh -c 'grep \"Subject: SPAM: \" /var/mail/localhost.localdomain/user1/new/ -R'"
|
||||
assert_success
|
||||
}
|
41
test/tests/serial/mail_special_use_folders.bats
Normal file
41
test/tests/serial/mail_special_use_folders.bats
Normal file
|
@ -0,0 +1,41 @@
|
|||
load 'test_helper/common'
|
||||
|
||||
setup_file() {
|
||||
local PRIVATE_CONFIG
|
||||
PRIVATE_CONFIG=$(duplicate_config_for_container .)
|
||||
|
||||
docker run -d --name mail_special_use_folders \
|
||||
-v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \
|
||||
-v "$(pwd)/test/test-files":/tmp/docker-mailserver-test:ro \
|
||||
-e SASL_PASSWD="external-domain.com username:password" \
|
||||
-e ENABLE_CLAMAV=0 \
|
||||
-e ENABLE_SPAMASSASSIN=0 \
|
||||
-e PERMIT_DOCKER=host \
|
||||
-h mail.my-domain.com -t "${NAME}"
|
||||
|
||||
wait_for_smtp_port_in_container mail_special_use_folders
|
||||
}
|
||||
|
||||
teardown_file() {
|
||||
docker rm -f mail_special_use_folders
|
||||
}
|
||||
|
||||
@test "checking normal delivery" {
|
||||
run docker exec mail_special_use_folders /bin/sh -c "nc 0.0.0.0 25 < /tmp/docker-mailserver-test/email-templates/existing-user1.txt"
|
||||
assert_success
|
||||
|
||||
# shellcheck disable=SC2016
|
||||
repeat_until_success_or_timeout 30 docker exec mail_special_use_folders /bin/sh -c '[ $(ls /var/mail/localhost.localdomain/user1/new | wc -l) -eq 1 ]'
|
||||
}
|
||||
|
||||
@test "checking special-use folders not yet created" {
|
||||
run docker exec mail_special_use_folders /bin/bash -c "ls -A /var/mail/localhost.localdomain/user1 | grep -E '.Drafts|.Sent|.Trash' | wc -l"
|
||||
assert_success
|
||||
assert_output 0
|
||||
}
|
||||
|
||||
@test "checking special-use folders available in IMAP" {
|
||||
run docker exec mail_special_use_folders /bin/sh -c "nc -w 8 0.0.0.0 143 < /tmp/docker-mailserver-test/nc_templates/imap_special_use_folders.txt | grep -E 'Drafts|Junk|Trash|Sent' | wc -l"
|
||||
assert_success
|
||||
assert_output 4
|
||||
}
|
311
test/tests/serial/mail_ssl_letsencrypt.bats
Normal file
311
test/tests/serial/mail_ssl_letsencrypt.bats
Normal file
|
@ -0,0 +1,311 @@
|
|||
load 'test_helper/common'
|
||||
load 'test_helper/tls'
|
||||
|
||||
# Globals referenced from `test_helper/common`:
|
||||
# TEST_NAME TEST_FQDN TEST_TMP_CONFIG
|
||||
|
||||
# Requires maintenance (TODO): Yes
|
||||
# Can run tests in parallel?: No
|
||||
|
||||
# Not parallelize friendly when TEST_NAME is static,
|
||||
# presently name of test file: `mail_ssl_letsencrypt`.
|
||||
#
|
||||
# Also shares a common TEST_TMP_CONFIG local folder,
|
||||
# Instead of individual PRIVATE_CONFIG copies.
|
||||
# For this test that is a non-issue, unless run in parallel.
|
||||
|
||||
|
||||
# Applies to all tests:
|
||||
function setup_file() {
|
||||
init_with_defaults
|
||||
|
||||
# Override default to match the hostname we want to test against instead:
|
||||
export TEST_FQDN='mail.example.test'
|
||||
|
||||
# Prepare certificates in the letsencrypt supported file structure:
|
||||
# Note Certbot uses `privkey.pem`.
|
||||
# `fullchain.pem` is currently what's detected, but we're actually providing the equivalent of `cert.pem` here.
|
||||
# TODO: Verify format/structure is supported for nginx-proxy + acme-companion (uses `acme.sh` to provision).
|
||||
|
||||
# `mail.example.test` (Only this FQDN is supported by this certificate):
|
||||
_copy_to_letsencrypt_storage 'example.test/with_ca/ecdsa/cert.ecdsa.pem' 'mail.example.test/fullchain.pem'
|
||||
_copy_to_letsencrypt_storage 'example.test/with_ca/ecdsa/key.ecdsa.pem' "mail.example.test/privkey.pem"
|
||||
|
||||
# `example.test` (Only this FQDN is supported by this certificate):
|
||||
_copy_to_letsencrypt_storage 'example.test/with_ca/ecdsa/cert.rsa.pem' 'example.test/fullchain.pem'
|
||||
_copy_to_letsencrypt_storage 'example.test/with_ca/ecdsa/key.rsa.pem' 'example.test/privkey.pem'
|
||||
}
|
||||
|
||||
# Not used
|
||||
# function teardown_file() {
|
||||
# }
|
||||
|
||||
function teardown() {
|
||||
docker rm -f "${TEST_NAME}"
|
||||
}
|
||||
|
||||
# Should detect and choose the cert for FQDN `mail.example.test` (HOSTNAME):
|
||||
@test "ssl(letsencrypt): Should default to HOSTNAME (mail.example.test)" {
|
||||
local TARGET_DOMAIN='mail.example.test'
|
||||
|
||||
local TEST_DOCKER_ARGS=(
|
||||
--volume "${TEST_TMP_CONFIG}/letsencrypt/${TARGET_DOMAIN}/:/etc/letsencrypt/live/${TARGET_DOMAIN}/:ro"
|
||||
--env PERMIT_DOCKER='container'
|
||||
--env SSL_TYPE='letsencrypt'
|
||||
)
|
||||
|
||||
common_container_setup 'TEST_DOCKER_ARGS'
|
||||
|
||||
#test hostname has certificate files
|
||||
_should_have_valid_config "${TARGET_DOMAIN}" 'privkey.pem' 'fullchain.pem'
|
||||
_should_succesfully_negotiate_tls "${TARGET_DOMAIN}"
|
||||
_should_not_support_fqdn_in_cert 'example.test'
|
||||
}
|
||||
|
||||
|
||||
# Should detect and choose cert for FQDN `example.test` (DOMAINNAME),
|
||||
# as fallback when no cert for FQDN `mail.example.test` (HOSTNAME) exists:
|
||||
@test "ssl(letsencrypt): Should fallback to DOMAINNAME (example.test)" {
|
||||
local TARGET_DOMAIN='example.test'
|
||||
|
||||
local TEST_DOCKER_ARGS=(
|
||||
--volume "${TEST_TMP_CONFIG}/letsencrypt/${TARGET_DOMAIN}/:/etc/letsencrypt/live/${TARGET_DOMAIN}/:ro"
|
||||
--env PERMIT_DOCKER='container'
|
||||
--env SSL_TYPE='letsencrypt'
|
||||
)
|
||||
|
||||
common_container_setup 'TEST_DOCKER_ARGS'
|
||||
|
||||
#test domain has certificate files
|
||||
_should_have_valid_config "${TARGET_DOMAIN}" 'privkey.pem' 'fullchain.pem'
|
||||
_should_succesfully_negotiate_tls "${TARGET_DOMAIN}"
|
||||
_should_not_support_fqdn_in_cert 'mail.example.test'
|
||||
}
|
||||
|
||||
# When using `acme.json` (Traefik) - a wildcard cert `*.example.test` (SSL_DOMAIN)
|
||||
# should be extracted and be chosen over an existing FQDN `mail.example.test` (HOSTNAME):
|
||||
#
|
||||
# NOTE: Currently all of the `acme.json` configs have the FQDN match a SAN value,
|
||||
# all Subject CN (`main` in acme.json) are `Smallstep Leaf` which is not an FQDN.
|
||||
# While valid for that field, it does mean there is no test coverage against `main`.
|
||||
@test "ssl(letsencrypt): Traefik 'acme.json' (*.example.test)" {
|
||||
# This test group changes to certs signed with an RSA Root CA key,
|
||||
# These certs all support both FQDNs: `mail.example.test` and `example.test`,
|
||||
# Except for the wildcard cert `*.example.test`, which intentionally excluded `example.test` when created.
|
||||
# We want to maintain the same FQDN (mail.example.test) between the _acme_ecdsa and _acme_rsa tests.
|
||||
local LOCAL_BASE_PATH="${PWD}/test/test-files/ssl/example.test/with_ca/rsa"
|
||||
|
||||
# Change default Root CA cert used for verifying chain of trust with openssl:
|
||||
# shellcheck disable=SC2034
|
||||
local TEST_CA_CERT="${TEST_FILES_CONTAINER_PATH}/ssl/example.test/with_ca/rsa/ca-cert.rsa.pem"
|
||||
|
||||
function _prepare() {
|
||||
# Default `acme.json` for _acme_ecdsa test:
|
||||
cp "${LOCAL_BASE_PATH}/ecdsa.acme.json" "${TEST_TMP_CONFIG}/letsencrypt/acme.json"
|
||||
|
||||
# TODO: Provision wildcard certs via Traefik to inspect if `example.test` non-wildcard is also added to the cert.
|
||||
# shellcheck disable=SC2034
|
||||
local TEST_DOCKER_ARGS=(
|
||||
--volume "${TEST_TMP_CONFIG}/letsencrypt/acme.json:/etc/letsencrypt/acme.json:ro"
|
||||
--env LOG_LEVEL='trace'
|
||||
--env PERMIT_DOCKER='container'
|
||||
--env SSL_DOMAIN='*.example.test'
|
||||
--env SSL_TYPE='letsencrypt'
|
||||
)
|
||||
|
||||
common_container_setup 'TEST_DOCKER_ARGS'
|
||||
wait_for_service "${TEST_NAME}" 'changedetector'
|
||||
|
||||
# Wait until the changedetector service startup delay is over:
|
||||
repeat_until_success_or_timeout 20 sh -c "$(_get_service_logs 'changedetector') | grep 'Changedetector is ready'"
|
||||
}
|
||||
|
||||
# Test `acme.json` extraction works at container startup:
|
||||
# It should have already extracted `mail.example.test` from the original mounted `acme.json`.
|
||||
function _acme_ecdsa() {
|
||||
_should_have_succeeded_at_extraction 'mail.example.test'
|
||||
|
||||
# SSL_DOMAIN set as ENV, but startup should not have match in `acme.json`:
|
||||
_should_have_failed_at_extraction '*.example.test' 'mailserver'
|
||||
_should_have_valid_config 'mail.example.test' 'key.pem' 'fullchain.pem'
|
||||
|
||||
local ECDSA_KEY_PATH="${LOCAL_BASE_PATH}/key.ecdsa.pem"
|
||||
local ECDSA_CERT_PATH="${LOCAL_BASE_PATH}/cert.ecdsa.pem"
|
||||
_should_have_expected_files 'mail.example.test' "${ECDSA_KEY_PATH}" "${ECDSA_CERT_PATH}"
|
||||
}
|
||||
|
||||
# Test `acme.json` extraction is triggered via change detection:
|
||||
# The updated `acme.json` roughly emulates a renewal, but changes from an ECDSA cert to an RSA one.
|
||||
# It should replace the cert files in the existing `letsencrypt/live/mail.example.test/` folder.
|
||||
function _acme_rsa() {
|
||||
_should_extract_on_changes 'mail.example.test' "${LOCAL_BASE_PATH}/rsa.acme.json"
|
||||
_should_have_service_restart_count '1'
|
||||
|
||||
local RSA_KEY_PATH="${LOCAL_BASE_PATH}/key.rsa.pem"
|
||||
local RSA_CERT_PATH="${LOCAL_BASE_PATH}/cert.rsa.pem"
|
||||
_should_have_expected_files 'mail.example.test' "${RSA_KEY_PATH}" "${RSA_CERT_PATH}"
|
||||
}
|
||||
|
||||
# Test that `acme.json` also works with wildcard certificates:
|
||||
# Additionally tests that SSL_DOMAIN is prioritized when `letsencrypt/live/` already has a HOSTNAME dir available.
|
||||
# Wildcard `*.example.test` should extract to `example.test/` in `letsencrypt/live/`:
|
||||
function _acme_wildcard() {
|
||||
_should_extract_on_changes 'example.test' "${LOCAL_BASE_PATH}/wildcard/rsa.acme.json"
|
||||
_should_have_service_restart_count '2'
|
||||
|
||||
# As the FQDN has changed since startup, the Postfix + Dovecot configs should be updated:
|
||||
_should_have_valid_config 'example.test' 'key.pem' 'fullchain.pem'
|
||||
|
||||
local WILDCARD_KEY_PATH="${LOCAL_BASE_PATH}/wildcard/key.rsa.pem"
|
||||
local WILDCARD_CERT_PATH="${LOCAL_BASE_PATH}/wildcard/cert.rsa.pem"
|
||||
_should_have_expected_files 'example.test' "${WILDCARD_KEY_PATH}" "${WILDCARD_CERT_PATH}"
|
||||
|
||||
# These two tests will confirm wildcard support is working, the supported SANs changed:
|
||||
# Before (_acme_rsa cert): `DNS:example.test, DNS:mail.example.test`
|
||||
# After (_acme_wildcard cert): `DNS:*.example.test`
|
||||
# The difference in support is:
|
||||
# - `example.test` should no longer be valid.
|
||||
# - `mail.example.test` should remain valid, but also allow any other subdomain/hostname.
|
||||
_should_succesfully_negotiate_tls 'mail.example.test'
|
||||
_should_support_fqdn_in_cert 'fake.example.test'
|
||||
_should_not_support_fqdn_in_cert 'example.test'
|
||||
}
|
||||
|
||||
_prepare
|
||||
|
||||
# Unleash the `acme.json` tests!
|
||||
# TODO: Extract methods to separate test cases.
|
||||
_acme_ecdsa
|
||||
_acme_rsa
|
||||
_acme_wildcard
|
||||
}
|
||||
|
||||
#
|
||||
# Test Methods
|
||||
#
|
||||
|
||||
|
||||
# Check that Dovecot and Postfix are configured to use a cert for the expected FQDN:
|
||||
function _should_have_valid_config() {
|
||||
local EXPECTED_FQDN=${1}
|
||||
local LE_KEY_PATH="/etc/letsencrypt/live/${EXPECTED_FQDN}/${2}"
|
||||
local LE_CERT_PATH="/etc/letsencrypt/live/${EXPECTED_FQDN}/${3}"
|
||||
|
||||
_has_matching_line 'postconf' "smtpd_tls_chain_files = ${LE_KEY_PATH} ${LE_CERT_PATH}"
|
||||
_has_matching_line 'doveconf' "ssl_cert = <${LE_CERT_PATH}"
|
||||
# `-P` is required to prevent redacting secrets
|
||||
_has_matching_line 'doveconf -P' "ssl_key = <${LE_KEY_PATH}"
|
||||
}
|
||||
|
||||
# CMD ${1} run in container with output checked to match value of ${2}:
|
||||
function _has_matching_line() {
|
||||
run docker exec "${TEST_NAME}" sh -c "${1} | grep '${2}'"
|
||||
assert_output "${2}"
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# Traefik `acme.json` specific
|
||||
#
|
||||
|
||||
|
||||
# It should log success of extraction for the expected domain and restart Postfix.
|
||||
function _should_have_succeeded_at_extraction() {
|
||||
local EXPECTED_DOMAIN=${1}
|
||||
local SERVICE=${2}
|
||||
|
||||
run $(_get_service_logs "${SERVICE}")
|
||||
assert_output --partial "_extract_certs_from_acme | Certificate successfully extracted for '${EXPECTED_DOMAIN}'"
|
||||
}
|
||||
|
||||
function _should_have_failed_at_extraction() {
|
||||
local EXPECTED_DOMAIN=${1}
|
||||
local SERVICE=${2}
|
||||
|
||||
run $(_get_service_logs "${SERVICE}")
|
||||
assert_output --partial "_extract_certs_from_acme | Unable to find key and/or cert for '${EXPECTED_DOMAIN}' in '/etc/letsencrypt/acme.json'"
|
||||
}
|
||||
|
||||
# Replace the mounted `acme.json` and wait to see if changes were detected.
|
||||
function _should_extract_on_changes() {
|
||||
local EXPECTED_DOMAIN=${1}
|
||||
local ACME_JSON=${2}
|
||||
|
||||
cp "${ACME_JSON}" "${TEST_TMP_CONFIG}/letsencrypt/acme.json"
|
||||
# Change detection takes a little over 5 seconds to complete (restart services)
|
||||
sleep 10
|
||||
|
||||
# Expected log lines from the changedetector service:
|
||||
run $(_get_service_logs 'changedetector')
|
||||
assert_output --partial 'Change detected'
|
||||
assert_output --partial "'/etc/letsencrypt/acme.json' has changed - extracting certificates"
|
||||
assert_output --partial "_extract_certs_from_acme | Certificate successfully extracted for '${EXPECTED_DOMAIN}'"
|
||||
assert_output --partial 'Restarting services due to detected changes'
|
||||
assert_output --partial 'postfix: stopped'
|
||||
assert_output --partial 'postfix: started'
|
||||
assert_output --partial 'dovecot: stopped'
|
||||
assert_output --partial 'dovecot: started'
|
||||
}
|
||||
|
||||
# Ensure change detection is not mistakenly validating against previous change events:
|
||||
function _should_have_service_restart_count() {
|
||||
local NUM_RESTARTS=${1}
|
||||
|
||||
# Count how many times postfix was restarted by the `changedetector` service:
|
||||
run docker exec "${TEST_NAME}" sh -c "grep -c 'postfix: started' /var/log/supervisor/changedetector.log"
|
||||
assert_output "${NUM_RESTARTS}"
|
||||
}
|
||||
|
||||
# Extracted cert files from `acme.json` have content matching the expected reference files:
|
||||
function _should_have_expected_files() {
|
||||
local LE_BASE_PATH="/etc/letsencrypt/live/${1}"
|
||||
local LE_KEY_PATH="${LE_BASE_PATH}/key.pem"
|
||||
local LE_CERT_PATH="${LE_BASE_PATH}/fullchain.pem"
|
||||
local EXPECTED_KEY_PATH=${2}
|
||||
local EXPECTED_CERT_PATH=${3}
|
||||
|
||||
_should_be_equal_in_content "${LE_KEY_PATH}" "${EXPECTED_KEY_PATH}"
|
||||
_should_be_equal_in_content "${LE_CERT_PATH}" "${EXPECTED_CERT_PATH}"
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# Misc
|
||||
#
|
||||
|
||||
|
||||
# Rename test certificate files to match the expected file structure for letsencrypt:
|
||||
function _copy_to_letsencrypt_storage() {
|
||||
local SRC=${1}
|
||||
local DEST=${2}
|
||||
|
||||
local FQDN_DIR
|
||||
FQDN_DIR=$(echo "${DEST}" | cut -d '/' -f1)
|
||||
mkdir -p "${TEST_TMP_CONFIG}/letsencrypt/${FQDN_DIR}"
|
||||
|
||||
cp "${PWD}/test/test-files/ssl/${SRC}" "${TEST_TMP_CONFIG}/letsencrypt/${DEST}"
|
||||
}
|
||||
|
||||
function _should_be_equal_in_content() {
|
||||
local CONTAINER_PATH=${1}
|
||||
local LOCAL_PATH=${2}
|
||||
|
||||
run docker exec "${TEST_NAME}" sh -c "cat ${CONTAINER_PATH}"
|
||||
assert_output "$(cat "${LOCAL_PATH}")"
|
||||
assert_success
|
||||
}
|
||||
|
||||
function _get_service_logs() {
|
||||
local SERVICE=${1:-'mailserver'}
|
||||
|
||||
local CMD_LOGS=(docker exec "${TEST_NAME}" "supervisorctl tail -2200 ${SERVICE}")
|
||||
|
||||
# As the `mailserver` service logs are not stored in a file but output to stdout/stderr,
|
||||
# The `supervisorctl tail` command won't work; we must instead query via `docker logs`:
|
||||
if [[ ${SERVICE} == 'mailserver' ]]
|
||||
then
|
||||
CMD_LOGS=(docker logs "${TEST_NAME}")
|
||||
fi
|
||||
|
||||
echo "${CMD_LOGS[@]}"
|
||||
}
|
111
test/tests/serial/mail_ssl_manual.bats
Normal file
111
test/tests/serial/mail_ssl_manual.bats
Normal file
|
@ -0,0 +1,111 @@
|
|||
#!/usr/bin/env bats
|
||||
load 'test_helper/common'
|
||||
|
||||
function setup_file() {
|
||||
# Internal copies made by `start-mailserver.sh`:
|
||||
export PRIMARY_KEY='/etc/dms/tls/key'
|
||||
export PRIMARY_CERT='/etc/dms/tls/cert'
|
||||
export FALLBACK_KEY='/etc/dms/tls/fallback_key'
|
||||
export FALLBACK_CERT='/etc/dms/tls/fallback_cert'
|
||||
|
||||
# Volume mounted certs:
|
||||
export SSL_KEY_PATH='/config/ssl/key.ecdsa.pem'
|
||||
export SSL_CERT_PATH='/config/ssl/cert.ecdsa.pem'
|
||||
export SSL_ALT_KEY_PATH='/config/ssl/key.rsa.pem'
|
||||
export SSL_ALT_CERT_PATH='/config/ssl/cert.rsa.pem'
|
||||
|
||||
local PRIVATE_CONFIG
|
||||
export DOMAIN_SSL_MANUAL='example.test'
|
||||
PRIVATE_CONFIG=$(duplicate_config_for_container .)
|
||||
|
||||
docker run -d --name mail_manual_ssl \
|
||||
--volume "${PRIVATE_CONFIG}/:/tmp/docker-mailserver/" \
|
||||
--volume "$(pwd)/test/test-files/ssl/${DOMAIN_SSL_MANUAL}/with_ca/ecdsa/:/config/ssl/:ro" \
|
||||
--env LOG_LEVEL='trace' \
|
||||
--env SSL_TYPE='manual' \
|
||||
--env TLS_LEVEL='modern' \
|
||||
--env SSL_KEY_PATH="${SSL_KEY_PATH}" \
|
||||
--env SSL_CERT_PATH="${SSL_CERT_PATH}" \
|
||||
--env SSL_ALT_KEY_PATH="${SSL_ALT_KEY_PATH}" \
|
||||
--env SSL_ALT_CERT_PATH="${SSL_ALT_CERT_PATH}" \
|
||||
--hostname "mail.${DOMAIN_SSL_MANUAL}" \
|
||||
--tty \
|
||||
"${NAME}" # Image name
|
||||
|
||||
wait_for_finished_setup_in_container mail_manual_ssl
|
||||
}
|
||||
|
||||
function teardown_file() {
|
||||
docker rm -f mail_manual_ssl
|
||||
}
|
||||
|
||||
@test "checking ssl: ENV vars provided are valid files" {
|
||||
assert docker exec mail_manual_ssl [ -f "${SSL_CERT_PATH}" ]
|
||||
assert docker exec mail_manual_ssl [ -f "${SSL_KEY_PATH}" ]
|
||||
assert docker exec mail_manual_ssl [ -f "${SSL_ALT_CERT_PATH}" ]
|
||||
assert docker exec mail_manual_ssl [ -f "${SSL_ALT_KEY_PATH}" ]
|
||||
}
|
||||
|
||||
@test "checking ssl: manual configuration is correct" {
|
||||
local DOVECOT_CONFIG_SSL='/etc/dovecot/conf.d/10-ssl.conf'
|
||||
|
||||
run docker exec mail_manual_ssl grep '^smtpd_tls_chain_files =' '/etc/postfix/main.cf'
|
||||
assert_success
|
||||
assert_output "smtpd_tls_chain_files = ${PRIMARY_KEY} ${PRIMARY_CERT} ${FALLBACK_KEY} ${FALLBACK_CERT}"
|
||||
|
||||
run docker exec mail_manual_ssl grep '^ssl_key =' "${DOVECOT_CONFIG_SSL}"
|
||||
assert_success
|
||||
assert_output "ssl_key = <${PRIMARY_KEY}"
|
||||
|
||||
run docker exec mail_manual_ssl grep '^ssl_cert =' "${DOVECOT_CONFIG_SSL}"
|
||||
assert_success
|
||||
assert_output "ssl_cert = <${PRIMARY_CERT}"
|
||||
|
||||
run docker exec mail_manual_ssl grep '^ssl_alt_key =' "${DOVECOT_CONFIG_SSL}"
|
||||
assert_success
|
||||
assert_output "ssl_alt_key = <${FALLBACK_KEY}"
|
||||
|
||||
run docker exec mail_manual_ssl grep '^ssl_alt_cert =' "${DOVECOT_CONFIG_SSL}"
|
||||
assert_success
|
||||
assert_output "ssl_alt_cert = <${FALLBACK_CERT}"
|
||||
}
|
||||
|
||||
@test "checking ssl: manual configuration copied files correctly " {
|
||||
run docker exec mail_manual_ssl cmp -s "${PRIMARY_KEY}" "${SSL_KEY_PATH}"
|
||||
assert_success
|
||||
run docker exec mail_manual_ssl cmp -s "${PRIMARY_CERT}" "${SSL_CERT_PATH}"
|
||||
assert_success
|
||||
|
||||
# Fallback cert
|
||||
run docker exec mail_manual_ssl cmp -s "${FALLBACK_KEY}" "${SSL_ALT_KEY_PATH}"
|
||||
assert_success
|
||||
run docker exec mail_manual_ssl cmp -s "${FALLBACK_CERT}" "${SSL_ALT_CERT_PATH}"
|
||||
assert_success
|
||||
}
|
||||
|
||||
@test "checking ssl: manual cert works correctly" {
|
||||
wait_for_tcp_port_in_container 587 mail_manual_ssl
|
||||
|
||||
local TEST_COMMAND=(timeout 1 openssl s_client -connect mail.example.test:587 -starttls smtp)
|
||||
local RESULT
|
||||
|
||||
# Should fail as a chain of trust is required to verify successfully:
|
||||
RESULT=$(docker exec mail_manual_ssl "${TEST_COMMAND[@]}" | grep 'Verification error:')
|
||||
assert_equal "${RESULT}" 'Verification error: unable to verify the first certificate'
|
||||
|
||||
# Provide the Root CA cert for successful verification:
|
||||
local CA_CERT='/config/ssl/ca-cert.ecdsa.pem'
|
||||
assert docker exec mail_manual_ssl [ -f "${CA_CERT}" ]
|
||||
RESULT=$(docker exec mail_manual_ssl "${TEST_COMMAND[@]}" -CAfile "${CA_CERT}" | grep 'Verification: OK')
|
||||
assert_equal "${RESULT}" 'Verification: OK'
|
||||
}
|
||||
|
||||
@test "checking ssl: manual cert changes are picked up by check-for-changes" {
|
||||
printf '%s' 'someThingsChangedHere' \
|
||||
>>"$(pwd)/test/test-files/ssl/${DOMAIN_SSL_MANUAL}/with_ca/ecdsa/key.ecdsa.pem"
|
||||
|
||||
run timeout 15 docker exec mail_manual_ssl bash -c "tail -F /var/log/supervisor/changedetector.log | sed '/Manual certificates have changed/ q'"
|
||||
assert_success
|
||||
|
||||
sed -i '/someThingsChangedHere/d' "$(pwd)/test/test-files/ssl/${DOMAIN_SSL_MANUAL}/with_ca/ecdsa/key.ecdsa.pem"
|
||||
}
|
29
test/tests/serial/mail_time.bats
Normal file
29
test/tests/serial/mail_time.bats
Normal file
|
@ -0,0 +1,29 @@
|
|||
load 'test_helper/common'
|
||||
|
||||
setup_file() {
|
||||
local PRIVATE_CONFIG
|
||||
PRIVATE_CONFIG=$(duplicate_config_for_container .)
|
||||
|
||||
docker run -d --name mail_time \
|
||||
-v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \
|
||||
-v "$(pwd)/test/test-files":/tmp/docker-mailserver-test:ro \
|
||||
-e TZ='Asia/Jakarta' \
|
||||
-e LOG_LEVEL=debug \
|
||||
-h mail.my-domain.com -t "${NAME}"
|
||||
|
||||
wait_for_smtp_port_in_container mail_time
|
||||
}
|
||||
|
||||
teardown_file() {
|
||||
docker rm -f mail_time
|
||||
}
|
||||
|
||||
@test "checking time: setting the time with TZ works correctly" {
|
||||
run docker exec mail_time cat /etc/timezone
|
||||
assert_success
|
||||
assert_output 'Asia/Jakarta'
|
||||
|
||||
run docker exec mail_time date '+%Z'
|
||||
assert_success
|
||||
assert_output 'WIB'
|
||||
}
|
127
test/tests/serial/mail_tls_dhparams.bats
Normal file
127
test/tests/serial/mail_tls_dhparams.bats
Normal file
|
@ -0,0 +1,127 @@
|
|||
load 'test_helper/common'
|
||||
|
||||
# Test case
|
||||
# ---------
|
||||
# By default, this image is using audited FFDHE groups (https://github.com/docker-mailserver/docker-mailserver/pull/1463)
|
||||
#
|
||||
# This test case covers the described case against both boolean states for `ONE_DIR`.
|
||||
#
|
||||
# Description:
|
||||
# 1. Verify that the file `ffdhe4096.pem` has not been modified (checksum verification).
|
||||
# 2. Verify Postfix and Dovecot are using the default `ffdhe4096.pem` from Dockerfile build.
|
||||
# 3. When custom DHE parameters are supplied by the user as `/tmp/docker-mailserver/dhparams.pem`:
|
||||
# - Verify Postfix and Dovecot use the custom `custom-dhe-params.pem` (contents is actually `ffdhe2048.pem`).
|
||||
# - A warning is raised about usage of potentially insecure parameters.
|
||||
|
||||
function teardown() {
|
||||
docker rm -f mail_dhparams
|
||||
}
|
||||
|
||||
function setup_file() {
|
||||
# Delegated container setup to common_container_setup
|
||||
# DRY - Explicit config changes between tests are more apparent this way.
|
||||
|
||||
# Global scope
|
||||
# Copies all of `./test/config/` to specific directory for testing
|
||||
# `${PRIVATE_CONFIG}` becomes `$(pwd)/test/duplicate_configs/<bats test filename>`
|
||||
export PRIVATE_CONFIG
|
||||
|
||||
export DMS_ONE_DIR=1 # default
|
||||
|
||||
local DH_DEFAULT_PARAMS
|
||||
export DH_DEFAULT_CHECKSUM
|
||||
export DH_CUSTOM_PARAMS
|
||||
export DH_CUSTOM_CHECKSUM
|
||||
|
||||
DH_DEFAULT_PARAMS="$(pwd)/target/shared/ffdhe4096.pem"
|
||||
DH_DEFAULT_CHECKSUM=$(sha512sum "${DH_DEFAULT_PARAMS}" | awk '{print $1}')
|
||||
|
||||
DH_CUSTOM_PARAMS="$(pwd)/test/test-files/ssl/custom-dhe-params.pem"
|
||||
DH_CUSTOM_CHECKSUM=$(sha512sum "${DH_CUSTOM_PARAMS}" | awk '{print $1}')
|
||||
}
|
||||
|
||||
# Not used
|
||||
# function teardown_file() {
|
||||
# }
|
||||
|
||||
@test "testing tls: DH Parameters - Verify integrity of Default (ffdhe4096)" {
|
||||
# Reference used (22/04/2020):
|
||||
# https://english.ncsc.nl/publications/publications/2019/juni/01/it-security-guidelines-for-transport-layer-security-tls
|
||||
|
||||
run echo "${DH_DEFAULT_CHECKSUM}"
|
||||
refute_output '' # checksum must not be empty
|
||||
|
||||
# Verify the FFDHE params file has not been modified (equivalent to `target/shared/ffdhe4096.pem.sha512sum`):
|
||||
local DH_MOZILLA_CHECKSUM
|
||||
DH_MOZILLA_CHECKSUM=$(curl https://ssl-config.mozilla.org/ffdhe4096.txt -s | sha512sum | awk '{print $1}')
|
||||
assert_equal "${DH_DEFAULT_CHECKSUM}" "${DH_MOZILLA_CHECKSUM}"
|
||||
}
|
||||
|
||||
@test "testing tls: DH Parameters - Default [ONE_DIR=0]" {
|
||||
PRIVATE_CONFIG=$(duplicate_config_for_container . mail_dhparams_default_0)
|
||||
DMS_ONE_DIR=0
|
||||
|
||||
common_container_setup
|
||||
should_have_valid_checksum "${DH_DEFAULT_CHECKSUM}"
|
||||
}
|
||||
|
||||
@test "testing tls: DH Parameters - Default [ONE_DIR=1]" {
|
||||
PRIVATE_CONFIG=$(duplicate_config_for_container . mail_dhparams_default_1)
|
||||
|
||||
common_container_setup
|
||||
should_have_valid_checksum "${DH_DEFAULT_CHECKSUM}"
|
||||
}
|
||||
|
||||
@test "testing tls: DH Parameters - Custom [ONE_DIR=0]" {
|
||||
PRIVATE_CONFIG=$(duplicate_config_for_container . mail_dhparams_custom_0)
|
||||
# shellcheck disable=SC2030
|
||||
DMS_ONE_DIR=0
|
||||
|
||||
cp "${DH_CUSTOM_PARAMS}" "${PRIVATE_CONFIG}/dhparams.pem"
|
||||
|
||||
common_container_setup
|
||||
should_have_valid_checksum "${DH_CUSTOM_CHECKSUM}"
|
||||
should_emit_warning
|
||||
}
|
||||
|
||||
@test "testing tls: DH Parameters - Custom [ONE_DIR=1]" {
|
||||
# shellcheck disable=SC2030
|
||||
PRIVATE_CONFIG=$(duplicate_config_for_container . mail_dhparams_custom_1)
|
||||
|
||||
cp "${DH_CUSTOM_PARAMS}" "${PRIVATE_CONFIG}/dhparams.pem"
|
||||
|
||||
common_container_setup
|
||||
should_have_valid_checksum "${DH_CUSTOM_CHECKSUM}"
|
||||
should_emit_warning
|
||||
}
|
||||
|
||||
function common_container_setup() {
|
||||
# shellcheck disable=SC2031
|
||||
docker run -d --name mail_dhparams \
|
||||
-v "${PRIVATE_CONFIG}:/tmp/docker-mailserver" \
|
||||
-v "$(pwd)/test/test-files:/tmp/docker-mailserver-test:ro" \
|
||||
-e ONE_DIR="${DMS_ONE_DIR}" \
|
||||
-h mail.my-domain.com \
|
||||
--tty \
|
||||
"${NAME}"
|
||||
|
||||
wait_for_finished_setup_in_container mail_dhparams
|
||||
}
|
||||
|
||||
# Ensures the docker image services (Postfix and Dovecot) have the intended DH files
|
||||
function should_have_valid_checksum() {
|
||||
local DH_CHECKSUM=$1
|
||||
|
||||
local DH_CHECKSUM_DOVECOT
|
||||
DH_CHECKSUM_DOVECOT=$(docker exec mail_dhparams sha512sum /etc/dovecot/dh.pem | awk '{print $1}')
|
||||
assert_equal "${DH_CHECKSUM_DOVECOT}" "${DH_CHECKSUM}"
|
||||
|
||||
local DH_CHECKSUM_POSTFIX
|
||||
DH_CHECKSUM_POSTFIX=$(docker exec mail_dhparams sha512sum /etc/postfix/dhparams.pem | awk '{print $1}')
|
||||
assert_equal "${DH_CHECKSUM_POSTFIX}" "${DH_CHECKSUM}"
|
||||
}
|
||||
|
||||
function should_emit_warning() {
|
||||
run sh -c "docker logs mail_dhparams | grep 'Using self-generated dhparams is considered insecure.'"
|
||||
assert_success
|
||||
}
|
65
test/tests/serial/mail_undef_spam_subject.bats
Normal file
65
test/tests/serial/mail_undef_spam_subject.bats
Normal file
|
@ -0,0 +1,65 @@
|
|||
load 'test_helper/common'
|
||||
|
||||
function setup() {
|
||||
local PRIVATE_CONFIG
|
||||
|
||||
PRIVATE_CONFIG=$(duplicate_config_for_container .)
|
||||
docker run -d --name mail_undef_spam_subject \
|
||||
-v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \
|
||||
-v "$(pwd)/test/test-files":/tmp/docker-mailserver-test:ro \
|
||||
-e ENABLE_SPAMASSASSIN=1 \
|
||||
-e SA_SPAM_SUBJECT="undef" \
|
||||
--hostname mail.my-domain.com \
|
||||
--tty \
|
||||
"${NAME}"
|
||||
|
||||
CONTAINER='mail_undef_spam_subject_2'
|
||||
PRIVATE_CONFIG=$(duplicate_config_for_container . "${CONTAINER}")
|
||||
docker run -d \
|
||||
-v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \
|
||||
-v "$(pwd)/test/test-files":/tmp/docker-mailserver-test:ro \
|
||||
-v "$(pwd)/test/onedir":/var/mail-state \
|
||||
-e ENABLE_CLAMAV=1 \
|
||||
-e SPOOF_PROTECTION=1 \
|
||||
-e ENABLE_SPAMASSASSIN=1 \
|
||||
-e REPORT_RECIPIENT=user1@localhost.localdomain \
|
||||
-e REPORT_SENDER=report1@mail.my-domain.com \
|
||||
-e SA_TAG=-5.0 \
|
||||
-e SA_TAG2=2.0 \
|
||||
-e SA_KILL=3.0 \
|
||||
-e SA_SPAM_SUBJECT="SPAM: " \
|
||||
-e VIRUSMAILS_DELETE_DELAY=7 \
|
||||
-e ENABLE_SRS=1 \
|
||||
-e SASL_PASSWD="external-domain.com username:password" \
|
||||
-e ENABLE_MANAGESIEVE=1 \
|
||||
-e PERMIT_DOCKER=host \
|
||||
--name "${CONTAINER}" \
|
||||
--hostname mail.my-domain.com \
|
||||
--tty \
|
||||
--ulimit "nofile=$(ulimit -Sn):$(ulimit -Hn)" \
|
||||
"${NAME}"
|
||||
|
||||
wait_for_finished_setup_in_container mail_undef_spam_subject
|
||||
wait_for_finished_setup_in_container "${CONTAINER}"
|
||||
}
|
||||
|
||||
function teardown() {
|
||||
docker rm -f mail_undef_spam_subject "${CONTAINER}"
|
||||
}
|
||||
|
||||
@test "checking spamassassin: docker env variables are set correctly (custom)" {
|
||||
run docker exec "${CONTAINER}" /bin/sh -c "grep '\$sa_tag_level_deflt' /etc/amavis/conf.d/20-debian_defaults | grep '= -5.0'"
|
||||
assert_success
|
||||
|
||||
run docker exec "${CONTAINER}" /bin/sh -c "grep '\$sa_tag2_level_deflt' /etc/amavis/conf.d/20-debian_defaults | grep '= 2.0'"
|
||||
assert_success
|
||||
|
||||
run docker exec "${CONTAINER}" /bin/sh -c "grep '\$sa_kill_level_deflt' /etc/amavis/conf.d/20-debian_defaults | grep '= 3.0'"
|
||||
assert_success
|
||||
|
||||
run docker exec "${CONTAINER}" /bin/sh -c "grep '\$sa_spam_subject_tag' /etc/amavis/conf.d/20-debian_defaults | grep '= .SPAM: .'"
|
||||
assert_success
|
||||
|
||||
run docker exec mail_undef_spam_subject /bin/sh -c "grep '\$sa_spam_subject_tag' /etc/amavis/conf.d/20-debian_defaults | grep '= undef'"
|
||||
assert_success
|
||||
}
|
49
test/tests/serial/mail_with_imap.bats
Normal file
49
test/tests/serial/mail_with_imap.bats
Normal file
|
@ -0,0 +1,49 @@
|
|||
load 'test_helper/common'
|
||||
|
||||
setup_file() {
|
||||
local PRIVATE_CONFIG
|
||||
PRIVATE_CONFIG=$(duplicate_config_for_container .)
|
||||
|
||||
docker run -d --name mail_with_imap \
|
||||
-v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \
|
||||
-v "$(pwd)/test/test-files":/tmp/docker-mailserver-test:ro \
|
||||
-e ENABLE_SASLAUTHD=1 \
|
||||
-e POSTMASTER_ADDRESS=postmaster@localhost.localdomain \
|
||||
-e SASLAUTHD_MECH_OPTIONS=127.0.0.1 \
|
||||
-e SASLAUTHD_MECHANISMS=rimap \
|
||||
-e PERMIT_DOCKER=container \
|
||||
-h mail.my-domain.com -t "${NAME}"
|
||||
|
||||
wait_for_smtp_port_in_container mail_with_imap
|
||||
}
|
||||
|
||||
teardown_file() {
|
||||
docker rm -f mail_with_imap
|
||||
}
|
||||
|
||||
#
|
||||
# RIMAP
|
||||
#
|
||||
|
||||
# dovecot
|
||||
@test "checking dovecot: ldap rimap connection and authentication works" {
|
||||
run docker exec mail_with_imap /bin/sh -c "nc -w 1 0.0.0.0 143 < /tmp/docker-mailserver-test/auth/imap-auth.txt"
|
||||
assert_success
|
||||
}
|
||||
|
||||
# saslauthd
|
||||
@test "checking saslauthd: sasl rimap authentication works" {
|
||||
run docker exec mail_with_imap bash -c "testsaslauthd -u user1@localhost.localdomain -p mypassword"
|
||||
assert_success
|
||||
}
|
||||
|
||||
@test "checking saslauthd: rimap smtp authentication" {
|
||||
run docker exec mail_with_imap /bin/sh -c "nc -w 5 0.0.0.0 25 < /tmp/docker-mailserver-test/auth/smtp-auth-login.txt | grep 'Authentication successful'"
|
||||
assert_success
|
||||
}
|
||||
|
||||
# master account
|
||||
@test "checking dovecot: master account can login" {
|
||||
run docker exec mail_with_imap bash -c "testsaslauthd -u user1@localhost.localdomain*masterusername -p masterpassword"
|
||||
assert_success
|
||||
}
|
258
test/tests/serial/mail_with_ldap.bats
Normal file
258
test/tests/serial/mail_with_ldap.bats
Normal file
|
@ -0,0 +1,258 @@
|
|||
load 'test_helper/common'
|
||||
|
||||
function setup_file() {
|
||||
pushd test/docker-openldap/ || return 1
|
||||
docker build -f Dockerfile -t ldap --no-cache .
|
||||
popd || return 1
|
||||
|
||||
export DOMAIN='my-domain.com'
|
||||
export FQDN_MAIL="mail.${DOMAIN}"
|
||||
export FQDN_LDAP="ldap.${DOMAIN}"
|
||||
export FQDN_LOCALHOST_A='localhost.localdomain'
|
||||
export FQDN_LOCALHOST_B='localhost.otherdomain'
|
||||
export DMS_TEST_NETWORK='test-network-ldap'
|
||||
|
||||
# NOTE: If the network already exists, test will fail to start.
|
||||
docker network create "${DMS_TEST_NETWORK}"
|
||||
|
||||
docker run -d --name ldap_for_mail \
|
||||
--env LDAP_DOMAIN="${FQDN_LOCALHOST_A}" \
|
||||
--network "${DMS_TEST_NETWORK}" \
|
||||
--network-alias 'ldap' \
|
||||
--hostname "${FQDN_LDAP}" \
|
||||
--tty \
|
||||
ldap # Image name
|
||||
|
||||
# _setup_ldap uses configomat with .ext files and ENV vars like DOVECOT_TLS with a prefix (eg DOVECOT_ or LDAP_)
|
||||
local PRIVATE_CONFIG
|
||||
PRIVATE_CONFIG=$(duplicate_config_for_container .)
|
||||
docker run -d --name mail_with_ldap \
|
||||
-v "${PRIVATE_CONFIG}:/tmp/docker-mailserver" \
|
||||
-v "$(pwd)/test/test-files:/tmp/docker-mailserver-test:ro" \
|
||||
-e DOVECOT_PASS_FILTER="(&(objectClass=PostfixBookMailAccount)(uniqueIdentifier=%n))" \
|
||||
-e DOVECOT_TLS=no \
|
||||
-e DOVECOT_USER_FILTER="(&(objectClass=PostfixBookMailAccount)(uniqueIdentifier=%n))" \
|
||||
-e ACCOUNT_PROVISIONER=LDAP \
|
||||
-e PFLOGSUMM_TRIGGER=logrotate \
|
||||
-e ENABLE_SASLAUTHD=1 \
|
||||
-e LDAP_BIND_DN=cn=admin,dc=localhost,dc=localdomain \
|
||||
-e LDAP_BIND_PW=admin \
|
||||
-e LDAP_QUERY_FILTER_ALIAS="(|(&(mailAlias=%s)(objectClass=PostfixBookMailForward))(&(mailAlias=%s)(objectClass=PostfixBookMailAccount)(mailEnabled=TRUE)))" \
|
||||
-e LDAP_QUERY_FILTER_DOMAIN="(|(&(mail=*@%s)(objectClass=PostfixBookMailAccount)(mailEnabled=TRUE))(&(mailGroupMember=*@%s)(objectClass=PostfixBookMailAccount)(mailEnabled=TRUE))(&(mailalias=*@%s)(objectClass=PostfixBookMailForward)))" \
|
||||
-e LDAP_QUERY_FILTER_GROUP="(&(mailGroupMember=%s)(mailEnabled=TRUE))" \
|
||||
-e LDAP_QUERY_FILTER_SENDERS="(|(&(mail=%s)(mailEnabled=TRUE))(&(mailGroupMember=%s)(mailEnabled=TRUE))(|(&(mailAlias=%s)(objectClass=PostfixBookMailForward))(&(mailAlias=%s)(objectClass=PostfixBookMailAccount)(mailEnabled=TRUE)))(uniqueIdentifier=some.user.id))" \
|
||||
-e LDAP_QUERY_FILTER_USER="(&(mail=%s)(mailEnabled=TRUE))" \
|
||||
-e LDAP_START_TLS=no \
|
||||
-e LDAP_SEARCH_BASE=ou=people,dc=localhost,dc=localdomain \
|
||||
-e LDAP_SERVER_HOST=ldap \
|
||||
-e PERMIT_DOCKER=container \
|
||||
-e POSTMASTER_ADDRESS="postmaster@${FQDN_LOCALHOST_A}" \
|
||||
-e REPORT_RECIPIENT=1 \
|
||||
-e SASLAUTHD_MECHANISMS=ldap \
|
||||
-e SPOOF_PROTECTION=1 \
|
||||
-e SSL_TYPE='snakeoil' \
|
||||
--network "${DMS_TEST_NETWORK}" \
|
||||
--hostname "${FQDN_MAIL}" \
|
||||
--tty \
|
||||
"${NAME}" # Image name
|
||||
|
||||
wait_for_smtp_port_in_container mail_with_ldap
|
||||
}
|
||||
|
||||
function teardown_file() {
|
||||
docker rm -f ldap_for_mail mail_with_ldap
|
||||
docker network rm "${DMS_TEST_NETWORK}"
|
||||
}
|
||||
|
||||
# processes
|
||||
|
||||
@test "checking process: saslauthd (saslauthd server enabled)" {
|
||||
run docker exec mail_with_ldap /bin/bash -c "ps aux --forest | grep -v grep | grep '/usr/sbin/saslauthd'"
|
||||
assert_success
|
||||
}
|
||||
|
||||
# postfix
|
||||
@test "checking postfix: ldap lookup works correctly" {
|
||||
run docker exec mail_with_ldap /bin/sh -c "postmap -q some.user@${FQDN_LOCALHOST_A} ldap:/etc/postfix/ldap-users.cf"
|
||||
assert_success
|
||||
assert_output "some.user@${FQDN_LOCALHOST_A}"
|
||||
run docker exec mail_with_ldap /bin/sh -c "postmap -q postmaster@${FQDN_LOCALHOST_A} ldap:/etc/postfix/ldap-aliases.cf"
|
||||
assert_success
|
||||
assert_output "some.user@${FQDN_LOCALHOST_A}"
|
||||
run docker exec mail_with_ldap /bin/sh -c "postmap -q employees@${FQDN_LOCALHOST_A} ldap:/etc/postfix/ldap-groups.cf"
|
||||
assert_success
|
||||
assert_output "some.user@${FQDN_LOCALHOST_A}"
|
||||
|
||||
# Test of the user part of the domain is not the same as the uniqueIdentifier part in the ldap
|
||||
run docker exec mail_with_ldap /bin/sh -c "postmap -q some.user.email@${FQDN_LOCALHOST_A} ldap:/etc/postfix/ldap-users.cf"
|
||||
assert_success
|
||||
assert_output "some.user.email@${FQDN_LOCALHOST_A}"
|
||||
|
||||
# Test email receiving from a other domain then the primary domain of the mailserver
|
||||
run docker exec mail_with_ldap /bin/sh -c "postmap -q some.other.user@${FQDN_LOCALHOST_B} ldap:/etc/postfix/ldap-users.cf"
|
||||
assert_success
|
||||
assert_output "some.other.user@${FQDN_LOCALHOST_B}"
|
||||
run docker exec mail_with_ldap /bin/sh -c "postmap -q postmaster@${FQDN_LOCALHOST_B} ldap:/etc/postfix/ldap-aliases.cf"
|
||||
assert_success
|
||||
assert_output "some.other.user@${FQDN_LOCALHOST_B}"
|
||||
run docker exec mail_with_ldap /bin/sh -c "postmap -q employees@${FQDN_LOCALHOST_B} ldap:/etc/postfix/ldap-groups.cf"
|
||||
assert_success
|
||||
assert_output "some.other.user@${FQDN_LOCALHOST_B}"
|
||||
}
|
||||
|
||||
@test "checking postfix: ldap custom config files copied" {
|
||||
run docker exec mail_with_ldap /bin/sh -c "grep '# Testconfig for ldap integration' /etc/postfix/ldap-users.cf"
|
||||
assert_success
|
||||
|
||||
run docker exec mail_with_ldap /bin/sh -c "grep '# Testconfig for ldap integration' /etc/postfix/ldap-groups.cf"
|
||||
assert_success
|
||||
|
||||
run docker exec mail_with_ldap /bin/sh -c "grep '# Testconfig for ldap integration' /etc/postfix/ldap-aliases.cf"
|
||||
assert_success
|
||||
}
|
||||
|
||||
@test "checking postfix: ldap config overwrites success" {
|
||||
run docker exec mail_with_ldap /bin/sh -c "grep 'server_host = ldap' /etc/postfix/ldap-users.cf"
|
||||
assert_success
|
||||
|
||||
run docker exec mail_with_ldap /bin/sh -c "grep 'start_tls = no' /etc/postfix/ldap-users.cf"
|
||||
assert_success
|
||||
|
||||
run docker exec mail_with_ldap /bin/sh -c "grep 'search_base = ou=people,dc=localhost,dc=localdomain' /etc/postfix/ldap-users.cf"
|
||||
assert_success
|
||||
|
||||
run docker exec mail_with_ldap /bin/sh -c "grep 'bind_dn = cn=admin,dc=localhost,dc=localdomain' /etc/postfix/ldap-users.cf"
|
||||
assert_success
|
||||
|
||||
run docker exec mail_with_ldap /bin/sh -c "grep 'server_host = ldap' /etc/postfix/ldap-groups.cf"
|
||||
assert_success
|
||||
|
||||
run docker exec mail_with_ldap /bin/sh -c "grep 'start_tls = no' /etc/postfix/ldap-groups.cf"
|
||||
assert_success
|
||||
|
||||
run docker exec mail_with_ldap /bin/sh -c "grep 'search_base = ou=people,dc=localhost,dc=localdomain' /etc/postfix/ldap-groups.cf"
|
||||
assert_success
|
||||
|
||||
run docker exec mail_with_ldap /bin/sh -c "grep 'bind_dn = cn=admin,dc=localhost,dc=localdomain' /etc/postfix/ldap-groups.cf"
|
||||
assert_success
|
||||
|
||||
run docker exec mail_with_ldap /bin/sh -c "grep 'server_host = ldap' /etc/postfix/ldap-aliases.cf"
|
||||
assert_success
|
||||
|
||||
run docker exec mail_with_ldap /bin/sh -c "grep 'start_tls = no' /etc/postfix/ldap-aliases.cf"
|
||||
assert_success
|
||||
|
||||
run docker exec mail_with_ldap /bin/sh -c "grep 'search_base = ou=people,dc=localhost,dc=localdomain' /etc/postfix/ldap-aliases.cf"
|
||||
assert_success
|
||||
|
||||
run docker exec mail_with_ldap /bin/sh -c "grep 'bind_dn = cn=admin,dc=localhost,dc=localdomain' /etc/postfix/ldap-aliases.cf"
|
||||
assert_success
|
||||
}
|
||||
|
||||
# dovecot
|
||||
@test "checking dovecot: ldap imap connection and authentication works" {
|
||||
run docker exec mail_with_ldap /bin/sh -c "nc -w 1 0.0.0.0 143 < /tmp/docker-mailserver-test/auth/imap-ldap-auth.txt"
|
||||
assert_success
|
||||
}
|
||||
|
||||
@test "checking dovecot: ldap mail delivery works" {
|
||||
run docker exec mail_with_ldap /bin/sh -c "sendmail -f user@external.tld some.user@${FQDN_LOCALHOST_A} < /tmp/docker-mailserver-test/email-templates/test-email.txt"
|
||||
sleep 10
|
||||
run docker exec mail_with_ldap /bin/sh -c "ls -A /var/mail/${FQDN_LOCALHOST_A}/some.user/new | wc -l"
|
||||
assert_success
|
||||
assert_output 1
|
||||
}
|
||||
|
||||
@test "checking dovecot: ldap mail delivery works for a different domain then the mailserver" {
|
||||
run docker exec mail_with_ldap /bin/sh -c "sendmail -f user@external.tld some.other.user@${FQDN_LOCALHOST_B} < /tmp/docker-mailserver-test/email-templates/test-email.txt"
|
||||
sleep 10
|
||||
run docker exec mail_with_ldap /bin/sh -c "ls -A /var/mail/${FQDN_LOCALHOST_A}/some.other.user/new | wc -l"
|
||||
assert_success
|
||||
assert_output 1
|
||||
}
|
||||
|
||||
@test "checking dovecot: ldap config overwrites success" {
|
||||
run docker exec mail_with_ldap /bin/sh -c "grep 'uris = ldap://ldap' /etc/dovecot/dovecot-ldap.conf.ext"
|
||||
assert_success
|
||||
run docker exec mail_with_ldap /bin/sh -c "grep 'tls = no' /etc/dovecot/dovecot-ldap.conf.ext"
|
||||
assert_success
|
||||
run docker exec mail_with_ldap /bin/sh -c "grep 'base = ou=people,dc=localhost,dc=localdomain' /etc/dovecot/dovecot-ldap.conf.ext"
|
||||
assert_success
|
||||
run docker exec mail_with_ldap /bin/sh -c "grep 'dn = cn=admin,dc=localhost,dc=localdomain' /etc/dovecot/dovecot-ldap.conf.ext"
|
||||
assert_success
|
||||
}
|
||||
|
||||
@test "checking dovecot: postmaster address" {
|
||||
run docker exec mail_with_ldap /bin/sh -c "grep 'postmaster_address = postmaster@${FQDN_LOCALHOST_A}' /etc/dovecot/conf.d/15-lda.conf"
|
||||
assert_success
|
||||
}
|
||||
|
||||
@test "checking dovecot: quota plugin is disabled" {
|
||||
run docker exec mail_with_ldap /bin/sh -c "grep '\$mail_plugins quota' /etc/dovecot/conf.d/10-mail.conf"
|
||||
assert_failure
|
||||
run docker exec mail_with_ldap /bin/sh -c "grep '\$mail_plugins imap_quota' /etc/dovecot/conf.d/20-imap.conf"
|
||||
assert_failure
|
||||
run docker exec mail_with_ldap ls /etc/dovecot/conf.d/90-quota.conf
|
||||
assert_failure
|
||||
run docker exec mail_with_ldap ls /etc/dovecot/conf.d/90-quota.conf.disab
|
||||
assert_success
|
||||
}
|
||||
|
||||
@test "checking postfix: dovecot quota absent in postconf" {
|
||||
run docker exec mail_with_ldap /bin/bash -c "postconf | grep 'check_policy_service inet:localhost:65265'"
|
||||
assert_failure
|
||||
}
|
||||
|
||||
@test "checking spoofing (with LDAP): rejects sender forging" {
|
||||
wait_for_smtp_port_in_container_to_respond mail_with_ldap
|
||||
run docker exec mail_with_ldap /bin/sh -c "nc 0.0.0.0 25 < /tmp/docker-mailserver-test/auth/ldap-smtp-auth-spoofed.txt | grep 'Sender address rejected: not owned by user'"
|
||||
assert_success
|
||||
}
|
||||
|
||||
# ATTENTION: these tests must come after "checking dovecot: ldap mail delivery works" since they will deliver an email which skews the count in said test, leading to failure
|
||||
@test "checking spoofing: accepts sending as alias (with LDAP)" {
|
||||
run docker exec mail_with_ldap /bin/sh -c "nc 0.0.0.0 25 < /tmp/docker-mailserver-test/auth/ldap-smtp-auth-spoofed-alias.txt | grep 'End data with'"
|
||||
assert_success
|
||||
}
|
||||
@test "checking spoofing: uses senders filter" {
|
||||
run docker exec mail_with_ldap /bin/sh -c "nc 0.0.0.0 25 < /tmp/docker-mailserver-test/auth/ldap-smtp-auth-spoofed-sender-with-filter-exception.txt | grep 'End data with'"
|
||||
assert_success
|
||||
}
|
||||
|
||||
# saslauthd
|
||||
@test "checking saslauthd: sasl ldap authentication works" {
|
||||
run docker exec mail_with_ldap bash -c "testsaslauthd -u some.user -p secret"
|
||||
assert_success
|
||||
}
|
||||
|
||||
@test "checking saslauthd: ldap smtp authentication" {
|
||||
run docker exec mail_with_ldap /bin/sh -c "nc -w 5 0.0.0.0 25 < /tmp/docker-mailserver-test/auth/sasl-ldap-smtp-auth.txt | grep 'Authentication successful'"
|
||||
assert_success
|
||||
run docker exec mail_with_ldap /bin/sh -c "openssl s_client -quiet -connect 0.0.0.0:465 < /tmp/docker-mailserver-test/auth/sasl-ldap-smtp-auth.txt | grep 'Authentication successful'"
|
||||
assert_success
|
||||
run docker exec mail_with_ldap /bin/sh -c "openssl s_client -quiet -starttls smtp -connect 0.0.0.0:587 < /tmp/docker-mailserver-test/auth/sasl-ldap-smtp-auth.txt | grep 'Authentication successful'"
|
||||
assert_success
|
||||
}
|
||||
|
||||
#
|
||||
# Pflogsumm delivery check
|
||||
#
|
||||
|
||||
@test "checking pflogsum delivery" {
|
||||
# checking default sender is correctly set when env variable not defined
|
||||
run docker exec mail_with_ldap grep "mailserver-report@${FQDN_MAIL}" /etc/logrotate.d/maillog
|
||||
assert_success
|
||||
|
||||
# checking default logrotation setup
|
||||
run docker exec mail_with_ldap grep "weekly" /etc/logrotate.d/maillog
|
||||
assert_success
|
||||
}
|
||||
|
||||
#
|
||||
# supervisor
|
||||
#
|
||||
|
||||
@test "checking restart of process: saslauthd (saslauthd server enabled)" {
|
||||
run docker exec mail_with_ldap /bin/bash -c "pkill saslauthd && sleep 10 && ps aux --forest | grep -v grep | grep '/usr/sbin/saslauthd'"
|
||||
assert_success
|
||||
}
|
30
test/tests/serial/mail_with_mdbox.bats
Normal file
30
test/tests/serial/mail_with_mdbox.bats
Normal file
|
@ -0,0 +1,30 @@
|
|||
load 'test_helper/common'
|
||||
|
||||
setup_file() {
|
||||
local PRIVATE_CONFIG
|
||||
PRIVATE_CONFIG=$(duplicate_config_for_container .)
|
||||
|
||||
docker run -d --name mail_with_mdbox_format \
|
||||
-v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \
|
||||
-v "$(pwd)/test/test-files":/tmp/docker-mailserver-test:ro \
|
||||
-e SASL_PASSWD="external-domain.com username:password" \
|
||||
-e ENABLE_CLAMAV=0 \
|
||||
-e ENABLE_SPAMASSASSIN=0 \
|
||||
-e DOVECOT_MAILBOX_FORMAT=mdbox \
|
||||
-e PERMIT_DOCKER=host \
|
||||
-h mail.my-domain.com -t "${NAME}"
|
||||
|
||||
wait_for_smtp_port_in_container mail_with_mdbox_format
|
||||
}
|
||||
|
||||
teardown_file() {
|
||||
docker rm -f mail_with_mdbox_format
|
||||
}
|
||||
|
||||
@test "checking dovecot mailbox format: mdbox file created" {
|
||||
run docker exec mail_with_mdbox_format /bin/sh -c "nc 0.0.0.0 25 < /tmp/docker-mailserver-test/email-templates/existing-user1.txt"
|
||||
assert_success
|
||||
|
||||
# shellcheck disable=SC2016
|
||||
repeat_until_success_or_timeout 30 docker exec mail_with_mdbox_format /bin/sh -c '[ $(ls /var/mail/localhost.localdomain/user1/storage/m.1 | wc -l) -eq 1 ]'
|
||||
}
|
92
test/tests/serial/mail_with_postgrey.bats
Normal file
92
test/tests/serial/mail_with_postgrey.bats
Normal file
|
@ -0,0 +1,92 @@
|
|||
load 'test_helper/common'
|
||||
|
||||
function setup_file() {
|
||||
local PRIVATE_CONFIG
|
||||
PRIVATE_CONFIG=$(duplicate_config_for_container .)
|
||||
|
||||
docker run -d --name mail_with_postgrey \
|
||||
-v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \
|
||||
-v "$(pwd)/test/test-files":/tmp/docker-mailserver-test:ro \
|
||||
-e ENABLE_DNSBL=1 \
|
||||
-e ENABLE_POSTGREY=1 \
|
||||
-e PERMIT_DOCKER=container \
|
||||
-e POSTGREY_AUTO_WHITELIST_CLIENTS=5 \
|
||||
-e POSTGREY_DELAY=15 \
|
||||
-e POSTGREY_MAX_AGE=35 \
|
||||
-e POSTGREY_TEXT="Delayed by Postgrey" \
|
||||
-h mail.my-domain.com -t "${NAME}"
|
||||
|
||||
# using postfix availability as start indicator, this might be insufficient for postgrey
|
||||
wait_for_smtp_port_in_container mail_with_postgrey
|
||||
}
|
||||
|
||||
function teardown_file() {
|
||||
docker rm -f mail_with_postgrey
|
||||
}
|
||||
|
||||
@test "checking postgrey: /etc/postfix/main.cf correctly edited" {
|
||||
run docker exec mail_with_postgrey /bin/bash -c "grep -F 'zen.spamhaus.org=127.0.0.[2..11], check_policy_service inet:127.0.0.1:10023' /etc/postfix/main.cf | wc -l"
|
||||
assert_success
|
||||
assert_output 1
|
||||
}
|
||||
|
||||
@test "checking postgrey: /etc/default/postgrey correctly edited and has the default values" {
|
||||
run docker exec mail_with_postgrey /bin/bash -c "grep '^POSTGREY_OPTS=\"--inet=127.0.0.1:10023 --delay=15 --max-age=35 --auto-whitelist-clients=5\"$' /etc/default/postgrey | wc -l"
|
||||
assert_success
|
||||
assert_output 1
|
||||
|
||||
run docker exec mail_with_postgrey /bin/bash -c "grep '^POSTGREY_TEXT=\"Delayed by Postgrey\"$' /etc/default/postgrey | wc -l"
|
||||
assert_success
|
||||
assert_output 1
|
||||
}
|
||||
|
||||
@test "checking process: postgrey (postgrey server enabled)" {
|
||||
run docker exec mail_with_postgrey /bin/bash -c "ps aux --forest | grep -v grep | grep 'postgrey'"
|
||||
assert_success
|
||||
}
|
||||
|
||||
@test "checking postgrey: there should be a log entry about a new greylisted e-mail user@external.tld in /var/log/mail/mail.log" {
|
||||
#editing the postfix config in order to ensure that postgrey handles the test e-mail. The other spam checks at smtpd_recipient_restrictions would interfere with it.
|
||||
run docker exec mail_with_postgrey /bin/sh -c "sed -ie 's/permit_sasl_authenticated.*policyd-spf,$//g' /etc/postfix/main.cf"
|
||||
run docker exec mail_with_postgrey /bin/sh -c "sed -ie 's/reject_unauth_pipelining.*reject_unknown_recipient_domain,$//g' /etc/postfix/main.cf"
|
||||
run docker exec mail_with_postgrey /bin/sh -c "sed -ie 's/reject_rbl_client.*inet:127\.0\.0\.1:10023$//g' /etc/postfix/main.cf"
|
||||
run docker exec mail_with_postgrey /bin/sh -c "sed -ie 's/smtpd_recipient_restrictions =/smtpd_recipient_restrictions = check_policy_service inet:127.0.0.1:10023/g' /etc/postfix/main.cf"
|
||||
|
||||
run docker exec mail_with_postgrey /bin/sh -c "/etc/init.d/postfix reload"
|
||||
run docker exec mail_with_postgrey /bin/sh -c "nc 0.0.0.0 25 < /tmp/docker-mailserver-test/email-templates/postgrey.txt"
|
||||
sleep 5 #ensure that the information has been written into the log
|
||||
run docker exec mail_with_postgrey /bin/bash -c "grep -i 'action=greylist.*user@external\.tld' /var/log/mail/mail.log | wc -l"
|
||||
assert_success
|
||||
assert_output 1
|
||||
}
|
||||
|
||||
@test "checking postgrey: there should be a log entry about the retried and passed e-mail user@external.tld in /var/log/mail/mail.log" {
|
||||
sleep 20 #wait 20 seconds so that postgrey would accept the message
|
||||
run docker exec mail_with_postgrey /bin/sh -c "nc 0.0.0.0 25 < /tmp/docker-mailserver-test/email-templates/postgrey.txt"
|
||||
sleep 8
|
||||
|
||||
run docker exec mail_with_postgrey /bin/sh -c "grep -i 'action=pass, reason=triplet found.*user@external\.tld' /var/log/mail/mail.log | wc -l"
|
||||
assert_success
|
||||
assert_output 1
|
||||
}
|
||||
|
||||
@test "checking postgrey: there should be a log entry about the whitelisted and passed e-mail user@whitelist.tld in /var/log/mail/mail.log" {
|
||||
run docker exec mail_with_postgrey /bin/sh -c "nc -w 8 0.0.0.0 10023 < /tmp/docker-mailserver-test/nc_templates/postgrey_whitelist.txt"
|
||||
run docker exec mail_with_postgrey /bin/sh -c "grep -i 'action=pass, reason=client whitelist' /var/log/mail/mail.log | wc -l"
|
||||
assert_success
|
||||
assert_output 1
|
||||
}
|
||||
|
||||
@test "checking postgrey: there should be a log entry about the whitelisted local and passed e-mail user@whitelistlocal.tld in /var/log/mail/mail.log" {
|
||||
run docker exec mail_with_postgrey /bin/sh -c "nc -w 8 0.0.0.0 10023 < /tmp/docker-mailserver-test/nc_templates/postgrey_whitelist_local.txt"
|
||||
run docker exec mail_with_postgrey /bin/sh -c "grep -i 'action=pass, reason=client whitelist' /var/log/mail/mail.log | wc -l"
|
||||
assert_success
|
||||
assert_output 1
|
||||
}
|
||||
|
||||
@test "checking postgrey: there should be a log entry about the whitelisted recipient user2@otherdomain.tld in /var/log/mail/mail.log" {
|
||||
run docker exec mail_with_postgrey /bin/sh -c "nc -w 8 0.0.0.0 10023 < /tmp/docker-mailserver-test/nc_templates/postgrey_whitelist_recipients.txt"
|
||||
run docker exec mail_with_postgrey /bin/sh -c "grep -i 'action=pass, reason=recipient whitelist' /var/log/mail/mail.log | wc -l"
|
||||
assert_success
|
||||
assert_output 1
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
load 'test_helper/common'
|
||||
|
||||
function setup() {
|
||||
local PRIVATE_CONFIG
|
||||
PRIVATE_CONFIG=$(duplicate_config_for_container .)
|
||||
|
||||
CONTAINER=$(docker run -d \
|
||||
-v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \
|
||||
-v "$(pwd)/test/test-files":/tmp/docker-mailserver-test:ro \
|
||||
-h mail.my-domain.com -t "${NAME}")
|
||||
|
||||
# using postfix availability as start indicator, this might be insufficient for postgrey
|
||||
wait_for_smtp_port_in_container "${CONTAINER}"
|
||||
}
|
||||
|
||||
function teardown() {
|
||||
docker rm -f "${CONTAINER}"
|
||||
}
|
||||
|
||||
@test "checking process: postgrey (disabled in default configuration)" {
|
||||
run docker exec "${CONTAINER}" /bin/bash -c "ps aux --forest | grep -v grep | grep 'postgrey'"
|
||||
assert_failure
|
||||
}
|
81
test/tests/serial/mail_with_relays.bats
Normal file
81
test/tests/serial/mail_with_relays.bats
Normal file
|
@ -0,0 +1,81 @@
|
|||
load 'test_helper/common'
|
||||
|
||||
function setup_file() {
|
||||
# We use a temporary config directory since we'll be dynamically editing
|
||||
# it with setup.sh.
|
||||
tmp_confdir=$(mktemp -d /tmp/docker-mailserver-config-relay-hosts-XXXXX)
|
||||
cp -a test/config/relay-hosts/* "${tmp_confdir}/"
|
||||
|
||||
docker run -d --name mail_with_relays \
|
||||
-v "${tmp_confdir}":/tmp/docker-mailserver \
|
||||
-v "$(pwd)/test/test-files":/tmp/docker-mailserver-test:ro \
|
||||
-e RELAY_HOST=default.relay.com \
|
||||
-e RELAY_PORT=2525 \
|
||||
-e RELAY_USER=smtp_user \
|
||||
-e RELAY_PASSWORD=smtp_password \
|
||||
-e PERMIT_DOCKER=host \
|
||||
-h mail.my-domain.com -t "${NAME}"
|
||||
|
||||
wait_for_finished_setup_in_container mail_with_relays
|
||||
}
|
||||
|
||||
function teardown_file() {
|
||||
docker rm -f mail_with_relays
|
||||
rm -rf "${tmp_confdir}"
|
||||
}
|
||||
|
||||
@test "checking relay hosts: default mapping is added from env vars" {
|
||||
run docker exec mail_with_relays grep -e domainone.tld /etc/postfix/relayhost_map
|
||||
assert_output -e '^@domainone.tld[[:space:]]+\[default.relay.com\]:2525$'
|
||||
}
|
||||
|
||||
@test "checking relay hosts: default mapping is added from env vars for virtual user entry" {
|
||||
run docker exec mail_with_relays grep -e domain1.tld /etc/postfix/relayhost_map
|
||||
assert_output -e '^@domain1.tld[[:space:]]+\[default.relay.com\]:2525$'
|
||||
}
|
||||
|
||||
@test "checking relay hosts: default mapping is added from env vars for new user entry" {
|
||||
run docker exec mail_with_relays grep -e domainzero.tld /etc/postfix/relayhost_map
|
||||
assert_output ''
|
||||
|
||||
run ./setup.sh -c mail_with_relays email add user0@domainzero.tld password123
|
||||
run_until_success_or_timeout 10 docker exec mail_with_relays grep -e domainzero.tld /etc/postfix/relayhost_map
|
||||
assert_output -e '^@domainzero.tld[[:space:]]+\[default.relay.com\]:2525$'
|
||||
}
|
||||
|
||||
@test "checking relay hosts: default mapping is added from env vars for new virtual user entry" {
|
||||
run docker exec mail_with_relays grep -e domain2.tld /etc/postfix/relayhost_map
|
||||
assert_output ''
|
||||
|
||||
run ./setup.sh -c mail_with_relays alias add user2@domain2.tld user2@domaintwo.tld
|
||||
run_until_success_or_timeout 10 docker exec mail_with_relays grep -e domain2.tld /etc/postfix/relayhost_map
|
||||
assert_output -e '^@domain2.tld[[:space:]]+\[default.relay.com\]:2525$'
|
||||
}
|
||||
|
||||
@test "checking relay hosts: custom mapping is added from file" {
|
||||
run docker exec mail_with_relays grep -e domaintwo.tld /etc/postfix/relayhost_map
|
||||
assert_output -e '^@domaintwo.tld[[:space:]]+\[other.relay.com\]:587$'
|
||||
}
|
||||
|
||||
@test "checking relay hosts: ignored domain is not added" {
|
||||
run docker exec mail_with_relays grep -e domainthree.tld /etc/postfix/relayhost_map
|
||||
assert_failure 1
|
||||
assert_output ''
|
||||
}
|
||||
|
||||
@test "checking relay hosts: sasl_passwd exists" {
|
||||
run docker exec mail_with_relays [ -f /etc/postfix/sasl_passwd ]
|
||||
assert_success
|
||||
}
|
||||
|
||||
@test "checking relay hosts: auth entry is added" {
|
||||
run docker exec mail_with_relays /bin/sh -c 'cat /etc/postfix/sasl_passwd | grep -e "^@domaintwo.tld\s\+smtp_user_2:smtp_password_2" | wc -l'
|
||||
assert_success
|
||||
assert_output 1
|
||||
}
|
||||
|
||||
@test "checking relay hosts: default auth entry is added" {
|
||||
run docker exec mail_with_relays /bin/sh -c 'cat /etc/postfix/sasl_passwd | grep -e "^\[default.relay.com\]:2525\s\+smtp_user:smtp_password" | wc -l'
|
||||
assert_success
|
||||
assert_output 1
|
||||
}
|
30
test/tests/serial/mail_with_sdbox.bats
Normal file
30
test/tests/serial/mail_with_sdbox.bats
Normal file
|
@ -0,0 +1,30 @@
|
|||
load 'test_helper/common'
|
||||
|
||||
setup_file() {
|
||||
local PRIVATE_CONFIG
|
||||
PRIVATE_CONFIG=$(duplicate_config_for_container .)
|
||||
|
||||
docker run -d --name mail_with_sdbox_format \
|
||||
-v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \
|
||||
-v "$(pwd)/test/test-files":/tmp/docker-mailserver-test:ro \
|
||||
-e SASL_PASSWD="external-domain.com username:password" \
|
||||
-e ENABLE_CLAMAV=0 \
|
||||
-e ENABLE_SPAMASSASSIN=0 \
|
||||
-e DOVECOT_MAILBOX_FORMAT=sdbox \
|
||||
-e PERMIT_DOCKER=host \
|
||||
-h mail.my-domain.com -t "${NAME}"
|
||||
|
||||
wait_for_smtp_port_in_container mail_with_sdbox_format
|
||||
}
|
||||
|
||||
teardown_file() {
|
||||
docker rm -f mail_with_sdbox_format
|
||||
}
|
||||
|
||||
@test "checking dovecot mailbox format: sdbox file created" {
|
||||
run docker exec mail_with_sdbox_format /bin/sh -c "nc 0.0.0.0 25 < /tmp/docker-mailserver-test/email-templates/existing-user1.txt"
|
||||
assert_success
|
||||
|
||||
# shellcheck disable=SC2016
|
||||
repeat_until_success_or_timeout 30 docker exec mail_with_sdbox_format /bin/sh -c '[ $(ls /var/mail/localhost.localdomain/user1/mailboxes/INBOX/dbox-Mails/u.1 | wc -l) -eq 1 ]'
|
||||
}
|
144
test/tests/serial/no_container.bats
Normal file
144
test/tests/serial/no_container.bats
Normal file
|
@ -0,0 +1,144 @@
|
|||
load 'test_helper/common'
|
||||
|
||||
function setup_file() {
|
||||
# Fail early if the test image is already running:
|
||||
assert_not_equal "$(docker ps | grep -o "${NAME}")" "${NAME}"
|
||||
# Test may fail if an existing DMS container is running,
|
||||
# Which can occur from a prior test failing before reaching `no_container.bats`
|
||||
# and that failure not properly handling teardown.
|
||||
}
|
||||
|
||||
@test "[No Existing Container] checking setup.sh: setup.sh alias list" {
|
||||
mkdir -p ./test/alias/config && echo "test@example.org test@forward.com" > ./test/alias/config/postfix-virtual.cf
|
||||
run ./setup.sh -p ./test/alias/config alias list
|
||||
assert_success
|
||||
}
|
||||
|
||||
@test "[No Existing Container] checking setup.sh: setup.sh alias add" {
|
||||
mkdir -p ./test/alias/config && echo "" > ./test/alias/config/postfix-virtual.cf
|
||||
./setup.sh -p ./test/alias/config alias add alias@example.com target1@forward.com
|
||||
./setup.sh -p ./test/alias/config alias add alias@example.com target2@forward.com
|
||||
sleep 5
|
||||
run /bin/sh -c 'cat ./test/alias/config/postfix-virtual.cf | grep "alias@example.com target1@forward.com,target2@forward.com" | wc -l | grep 1'
|
||||
assert_success
|
||||
}
|
||||
|
||||
@test "[No Existing Container] checking setup.sh: setup.sh alias del" {
|
||||
# start with a1 -> t1,t2 and a2 -> t1
|
||||
mkdir -p ./test/alias/config && echo -e 'alias1@example.org target1@forward.com,target2@forward.com\nalias2@example.org target1@forward.com' > ./test/alias/config/postfix-virtual.cf
|
||||
|
||||
# we remove a1 -> t1 ==> a1 -> t2 and a2 -> t1
|
||||
./setup.sh -p ./test/alias/config alias del alias1@example.org target1@forward.com
|
||||
run grep "target1@forward.com" ./test/alias/config/postfix-virtual.cf
|
||||
assert_output --regexp "^alias2@example.org +target1@forward.com$"
|
||||
|
||||
run grep "target2@forward.com" ./test/alias/config/postfix-virtual.cf
|
||||
assert_output --regexp "^alias1@example.org +target2@forward.com$"
|
||||
|
||||
# we remove a1 -> t2 ==> a2 -> t1
|
||||
./setup.sh -p ./test/alias/config alias del alias1@example.org target2@forward.com
|
||||
run grep "alias1@example.org" ./test/alias/config/postfix-virtual.cf
|
||||
assert_failure
|
||||
|
||||
run grep "alias2@example.org" ./test/alias/config/postfix-virtual.cf
|
||||
assert_success
|
||||
|
||||
# we remove a2 -> t1 ==> empty
|
||||
./setup.sh -p ./test/alias/config alias del alias2@example.org target1@forward.com
|
||||
run grep "alias2@example.org" ./test/alias/config/postfix-virtual.cf
|
||||
assert_failure
|
||||
}
|
||||
|
||||
# quota
|
||||
@test "[No Existing Container] checking setup.sh: setup.sh setquota" {
|
||||
mkdir -p ./test/quota/config && echo "" > ./test/quota/config/dovecot-quotas.cf
|
||||
|
||||
run ./setup.sh -p ./test/quota/config email add quota_user@example.com test_password
|
||||
run ./setup.sh -p ./test/quota/config email add quota_user2@example.com test_password
|
||||
|
||||
run ./setup.sh -p ./test/quota/config quota set quota_user@example.com 12M
|
||||
assert_success
|
||||
run ./setup.sh -p ./test/quota/config quota set 51M quota_user@example.com
|
||||
assert_failure
|
||||
run ./setup.sh -p ./test/quota/config quota set unknown@domain.com 150M
|
||||
assert_failure
|
||||
|
||||
run ./setup.sh -p ./test/quota/config quota set quota_user2 51M
|
||||
assert_failure
|
||||
|
||||
run /bin/sh -c 'cat ./test/quota/config/dovecot-quotas.cf | grep -E "^quota_user@example.com\:12M\$" | wc -l | grep 1'
|
||||
assert_success
|
||||
|
||||
run ./setup.sh -p ./test/quota/config quota set quota_user@example.com 26M
|
||||
assert_success
|
||||
run /bin/sh -c 'cat ./test/quota/config/dovecot-quotas.cf | grep -E "^quota_user@example.com\:26M\$" | wc -l | grep 1'
|
||||
assert_success
|
||||
|
||||
run grep "quota_user2@example.com" ./test/alias/config/dovecot-quotas.cf
|
||||
assert_failure
|
||||
}
|
||||
|
||||
@test "[No Existing Container] checking setup.sh: setup.sh delquota" {
|
||||
mkdir -p ./test/quota/config && echo "" > ./test/quota/config/dovecot-quotas.cf
|
||||
|
||||
run ./setup.sh -p ./test/quota/config email add quota_user@example.com test_password
|
||||
run ./setup.sh -p ./test/quota/config email add quota_user2@example.com test_password
|
||||
|
||||
run ./setup.sh -p ./test/quota/config quota set quota_user@example.com 12M
|
||||
assert_success
|
||||
run /bin/sh -c 'cat ./test/quota/config/dovecot-quotas.cf | grep -E "^quota_user@example.com\:12M\$" | wc -l | grep 1'
|
||||
assert_success
|
||||
|
||||
|
||||
run ./setup.sh -p ./test/quota/config quota del unknown@domain.com
|
||||
assert_failure
|
||||
run /bin/sh -c 'cat ./test/quota/config/dovecot-quotas.cf | grep -E "^quota_user@example.com\:12M\$" | wc -l | grep 1'
|
||||
assert_success
|
||||
|
||||
run ./setup.sh -p ./test/quota/config quota del quota_user@example.com
|
||||
assert_success
|
||||
run grep "quota_user@example.com" ./test/alias/config/dovecot-quotas.cf
|
||||
assert_failure
|
||||
}
|
||||
|
||||
# debug
|
||||
|
||||
@test "[No Existing Container] checking setup.sh: setup.sh relay add-domain" {
|
||||
mkdir -p ./test/relay/config && echo -n > ./test/relay/config/postfix-relaymap.cf
|
||||
./setup.sh -p ./test/relay/config relay add-domain example1.org smtp.relay1.com 2525
|
||||
./setup.sh -p ./test/relay/config relay add-domain example2.org smtp.relay2.com
|
||||
./setup.sh -p ./test/relay/config relay add-domain example3.org smtp.relay3.com 2525
|
||||
./setup.sh -p ./test/relay/config relay add-domain example3.org smtp.relay.com 587
|
||||
|
||||
# check adding
|
||||
run /bin/sh -c 'cat ./test/relay/config/postfix-relaymap.cf | grep -e "^@example1.org\s\+\[smtp.relay1.com\]:2525" | wc -l | grep 1'
|
||||
assert_success
|
||||
# test default port
|
||||
run /bin/sh -c 'cat ./test/relay/config/postfix-relaymap.cf | grep -e "^@example2.org\s\+\[smtp.relay2.com\]:25" | wc -l | grep 1'
|
||||
assert_success
|
||||
# test modifying
|
||||
run /bin/sh -c 'cat ./test/relay/config/postfix-relaymap.cf | grep -e "^@example3.org\s\+\[smtp.relay.com\]:587" | wc -l | grep 1'
|
||||
assert_success
|
||||
}
|
||||
|
||||
@test "[No Existing Container] checking setup.sh: setup.sh relay add-auth" {
|
||||
mkdir -p ./test/relay/config && echo -n > ./test/relay/config/postfix-sasl-password.cf
|
||||
./setup.sh -p ./test/relay/config relay add-auth example.org smtp_user smtp_pass
|
||||
./setup.sh -p ./test/relay/config relay add-auth example2.org smtp_user2 smtp_pass2
|
||||
./setup.sh -p ./test/relay/config relay add-auth example2.org smtp_user2 smtp_pass_new
|
||||
|
||||
# test adding
|
||||
run /bin/sh -c 'cat ./test/relay/config/postfix-sasl-password.cf | grep -e "^@example.org\s\+smtp_user:smtp_pass" | wc -l | grep 1'
|
||||
assert_success
|
||||
# test updating
|
||||
run /bin/sh -c 'cat ./test/relay/config/postfix-sasl-password.cf | grep -e "^@example2.org\s\+smtp_user2:smtp_pass_new" | wc -l | grep 1'
|
||||
assert_success
|
||||
}
|
||||
|
||||
@test "[No Existing Container] checking setup.sh: setup.sh relay exclude-domain" {
|
||||
mkdir -p ./test/relay/config && echo -n > ./test/relay/config/postfix-relaymap.cf
|
||||
./setup.sh -p ./test/relay/config relay exclude-domain example.org
|
||||
|
||||
run /bin/sh -c 'cat ./test/relay/config/postfix-relaymap.cf | grep -e "^@example.org\s*$" | wc -l | grep 1'
|
||||
assert_success
|
||||
}
|
465
test/tests/serial/open_dkim.bats
Normal file
465
test/tests/serial/open_dkim.bats
Normal file
|
@ -0,0 +1,465 @@
|
|||
load 'test_helper/common'
|
||||
|
||||
export IMAGE_NAME CONTAINER_NAME TEST_FILE
|
||||
|
||||
IMAGE_NAME="${NAME:?Image name must be set}"
|
||||
CONTAINER_NAME='open-dkim'
|
||||
TEST_FILE='checking OpenDKIM: '
|
||||
|
||||
# WHY IS THIS CONTAINER EVEN CREATED WHEN MOST TESTS DO NOT USE IT?
|
||||
function setup_file
|
||||
{
|
||||
local PRIVATE_CONFIG
|
||||
PRIVATE_CONFIG=$(duplicate_config_for_container . "${CONTAINER_NAME}")
|
||||
|
||||
docker run -d \
|
||||
--name "${CONTAINER_NAME}" \
|
||||
-v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \
|
||||
-v "${PWD}/test/test-files":/tmp/docker-mailserver-test:ro \
|
||||
-e DEFAULT_RELAY_HOST=default.relay.host.invalid:25 \
|
||||
-e PERMIT_DOCKER=host \
|
||||
-e LOG_LEVEL='trace' \
|
||||
-h mail.my-domain.com \
|
||||
-t "${IMAGE_NAME}"
|
||||
|
||||
wait_for_finished_setup_in_container "${CONTAINER_NAME}"
|
||||
}
|
||||
|
||||
function teardown_file
|
||||
{
|
||||
docker rm -f "${CONTAINER_NAME}"
|
||||
}
|
||||
|
||||
# -----------------------------------------------
|
||||
# --- Actual Tests ------------------------------
|
||||
# -----------------------------------------------
|
||||
|
||||
@test "${TEST_FILE}/etc/opendkim/KeyTable should contain 2 entries" {
|
||||
run docker exec "${CONTAINER_NAME}" /bin/bash -c "cat /etc/opendkim/KeyTable | wc -l"
|
||||
assert_success
|
||||
assert_output 2
|
||||
}
|
||||
|
||||
# TODO piping ls into grep ...
|
||||
@test "${TEST_FILE}/etc/opendkim/keys/ should contain 2 entries" {
|
||||
run docker exec "${CONTAINER_NAME}" /bin/bash -c "ls -l /etc/opendkim/keys/ | grep '^d' | wc -l"
|
||||
assert_success
|
||||
assert_output 2
|
||||
}
|
||||
|
||||
@test "${TEST_FILE}/etc/opendkim.conf contains nameservers copied from /etc/resolv.conf" {
|
||||
run docker exec "${CONTAINER_NAME}" /bin/bash -c \
|
||||
"grep -E '^Nameservers ((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)' \
|
||||
/etc/opendkim.conf"
|
||||
assert_success
|
||||
}
|
||||
|
||||
# this set of tests is of low quality. WHAT? <- DELETE AFTER REWRITE
|
||||
# It does not test the RSA-Key size properly via openssl or similar WHAT??? <- DELETE AFTER REWRITE
|
||||
# Instead it tests the file-size (here 861) - which may differ with a different domain names WWHHHHHHAAAT??? <- DELETE AFTER REWRITE
|
||||
|
||||
# TODO Needs complete re-write
|
||||
@test "${TEST_FILE}generator creates default keys size" {
|
||||
local PRIVATE_CONFIG
|
||||
PRIVATE_CONFIG=$(duplicate_config_for_container . mail_default_key_size)
|
||||
|
||||
# Prepare default key size 4096
|
||||
rm -rf "${PRIVATE_CONFIG}/keyDefault"
|
||||
mkdir -p "${PRIVATE_CONFIG}/keyDefault"
|
||||
|
||||
run docker run --rm \
|
||||
-e LOG_LEVEL='trace' \
|
||||
-v "${PRIVATE_CONFIG}/keyDefault/":/tmp/docker-mailserver/ \
|
||||
-v "${PRIVATE_CONFIG}/postfix-accounts.cf":/tmp/docker-mailserver/postfix-accounts.cf \
|
||||
-v "${PRIVATE_CONFIG}/postfix-virtual.cf":/tmp/docker-mailserver/postfix-virtual.cf \
|
||||
"${IMAGE_NAME}" /bin/bash -c 'open-dkim | wc -l'
|
||||
|
||||
assert_success
|
||||
assert_output 6
|
||||
|
||||
run docker run --rm \
|
||||
-v "${PRIVATE_CONFIG}/keyDefault/opendkim":/etc/opendkim \
|
||||
"${IMAGE_NAME}" \
|
||||
/bin/bash -c 'stat -c%s /etc/opendkim/keys/localhost.localdomain/mail.txt'
|
||||
|
||||
assert_success
|
||||
assert_output 861
|
||||
}
|
||||
|
||||
# this set of tests is of low quality. It does not test the RSA-Key size properly via openssl or similar <- DELETE AFTER REWRITE
|
||||
# Instead it tests the file-size (here 861) - which may differ with a different domain names <- DELETE AFTER REWRITE
|
||||
|
||||
# TODO Needs complete re-write
|
||||
@test "${TEST_FILE}generator creates key size 4096" {
|
||||
local PRIVATE_CONFIG
|
||||
PRIVATE_CONFIG=$(duplicate_config_for_container . mail_key_size_4096)
|
||||
|
||||
rm -rf "${PRIVATE_CONFIG}/key4096"
|
||||
mkdir -p "${PRIVATE_CONFIG}/config/key4096"
|
||||
|
||||
run docker run --rm \
|
||||
-e LOG_LEVEL='trace' \
|
||||
-v "${PRIVATE_CONFIG}/key2048/":/tmp/docker-mailserver/ \
|
||||
-v "${PRIVATE_CONFIG}/postfix-accounts.cf":/tmp/docker-mailserver/postfix-accounts.cf \
|
||||
-v "${PRIVATE_CONFIG}/postfix-virtual.cf":/tmp/docker-mailserver/postfix-virtual.cf \
|
||||
"${IMAGE_NAME}" /bin/bash -c 'open-dkim keysize 4096 | wc -l'
|
||||
|
||||
assert_success
|
||||
assert_output 6
|
||||
|
||||
run docker run --rm \
|
||||
-v "${PRIVATE_CONFIG}/key2048/opendkim":/etc/opendkim \
|
||||
"${IMAGE_NAME}" \
|
||||
/bin/bash -c 'stat -c%s /etc/opendkim/keys/localhost.localdomain/mail.txt'
|
||||
|
||||
assert_success
|
||||
assert_output 861
|
||||
}
|
||||
|
||||
# Instead it tests the file-size (here 511) - which may differ with a different domain names <- DELETE AFTER REWRITE
|
||||
# This test may be re-used as a global test to provide better test coverage. <- DELETE AFTER REWRITE
|
||||
|
||||
# TODO Needs complete re-write
|
||||
@test "${TEST_FILE}generator creates key size 2048" {
|
||||
local PRIVATE_CONFIG
|
||||
PRIVATE_CONFIG=$(duplicate_config_for_container . mail_key_size_2048)
|
||||
|
||||
rm -rf "${PRIVATE_CONFIG}/key2048"
|
||||
mkdir -p "${PRIVATE_CONFIG}/config/key2048"
|
||||
|
||||
run docker run --rm \
|
||||
-e LOG_LEVEL='trace' \
|
||||
-v "${PRIVATE_CONFIG}/key2048/":/tmp/docker-mailserver/ \
|
||||
-v "${PRIVATE_CONFIG}/postfix-accounts.cf":/tmp/docker-mailserver/postfix-accounts.cf \
|
||||
-v "${PRIVATE_CONFIG}/postfix-virtual.cf":/tmp/docker-mailserver/postfix-virtual.cf \
|
||||
"${IMAGE_NAME}" /bin/bash -c 'open-dkim keysize 2048 | wc -l'
|
||||
|
||||
assert_success
|
||||
assert_output 6
|
||||
|
||||
run docker run --rm \
|
||||
-v "${PRIVATE_CONFIG}/key2048/opendkim":/etc/opendkim \
|
||||
"${IMAGE_NAME}" \
|
||||
/bin/bash -c 'stat -c%s /etc/opendkim/keys/localhost.localdomain/mail.txt'
|
||||
|
||||
assert_success
|
||||
assert_output 511
|
||||
}
|
||||
|
||||
# this set of tests is of low quality. It does not test the RSA-Key size properly via openssl or similar <- DELETE AFTER REWRITE
|
||||
# Instead it tests the file-size (here 329) - which may differ with a different domain names <- DELETE AFTER REWRITE
|
||||
|
||||
# TODO Needs complete re-write
|
||||
@test "${TEST_FILE}generator creates key size 1024" {
|
||||
local PRIVATE_CONFIG
|
||||
PRIVATE_CONFIG=$(duplicate_config_for_container . mail_key_size_1024)
|
||||
|
||||
rm -rf "${PRIVATE_CONFIG}/key1024"
|
||||
mkdir -p "${PRIVATE_CONFIG}/key1024"
|
||||
|
||||
run docker run --rm \
|
||||
-e LOG_LEVEL='trace' \
|
||||
-v "${PRIVATE_CONFIG}/key1024/":/tmp/docker-mailserver/ \
|
||||
-v "${PRIVATE_CONFIG}/postfix-accounts.cf":/tmp/docker-mailserver/postfix-accounts.cf \
|
||||
-v "${PRIVATE_CONFIG}/postfix-virtual.cf":/tmp/docker-mailserver/postfix-virtual.cf \
|
||||
"${IMAGE_NAME}" /bin/bash -c 'open-dkim keysize 1024 | wc -l'
|
||||
|
||||
assert_success
|
||||
assert_output 6
|
||||
|
||||
run docker run --rm \
|
||||
-v "${PRIVATE_CONFIG}/key1024/opendkim":/etc/opendkim \
|
||||
"${IMAGE_NAME}" \
|
||||
/bin/bash -c 'stat -c%s /etc/opendkim/keys/localhost.localdomain/mail.txt'
|
||||
|
||||
assert_success
|
||||
assert_output 329
|
||||
}
|
||||
|
||||
@test "${TEST_FILE}generator creates keys, tables and TrustedHosts" {
|
||||
local PRIVATE_CONFIG
|
||||
PRIVATE_CONFIG=$(duplicate_config_for_container . mail_dkim_generator_creates_keys_tables_TrustedHosts)
|
||||
|
||||
rm -rf "${PRIVATE_CONFIG}/empty"
|
||||
mkdir -p "${PRIVATE_CONFIG}/empty"
|
||||
|
||||
run docker run --rm \
|
||||
-e LOG_LEVEL='trace' \
|
||||
-v "${PRIVATE_CONFIG}/empty/":/tmp/docker-mailserver/ \
|
||||
-v "${PRIVATE_CONFIG}/postfix-accounts.cf":/tmp/docker-mailserver/postfix-accounts.cf \
|
||||
-v "${PRIVATE_CONFIG}/postfix-virtual.cf":/tmp/docker-mailserver/postfix-virtual.cf \
|
||||
"${IMAGE_NAME}" /bin/bash -c 'open-dkim | wc -l'
|
||||
|
||||
assert_success
|
||||
assert_output 6
|
||||
|
||||
# check keys for localhost.localdomain
|
||||
run docker run --rm \
|
||||
-v "${PRIVATE_CONFIG}/empty/opendkim":/etc/opendkim \
|
||||
"${IMAGE_NAME}" /bin/bash -c 'ls -1 /etc/opendkim/keys/localhost.localdomain/ | wc -l'
|
||||
|
||||
assert_success
|
||||
assert_output 2
|
||||
|
||||
# check keys for otherdomain.tld
|
||||
run docker run --rm \
|
||||
-v "${PRIVATE_CONFIG}/empty/opendkim":/etc/opendkim \
|
||||
"${IMAGE_NAME}" /bin/bash -c 'ls -1 /etc/opendkim/keys/otherdomain.tld | wc -l'
|
||||
|
||||
assert_success
|
||||
assert_output 2
|
||||
|
||||
# check presence of tables and TrustedHosts
|
||||
run docker run --rm \
|
||||
-v "${PRIVATE_CONFIG}/empty/opendkim":/etc/opendkim \
|
||||
"${IMAGE_NAME}" /bin/bash -c "ls -1 /etc/opendkim | grep -E 'KeyTable|SigningTable|TrustedHosts|keys'|wc -l"
|
||||
|
||||
assert_success
|
||||
assert_output 4
|
||||
}
|
||||
|
||||
@test "${TEST_FILE}generator creates keys, tables and TrustedHosts without postfix-accounts.cf" {
|
||||
local PRIVATE_CONFIG
|
||||
PRIVATE_CONFIG=$(duplicate_config_for_container . )
|
||||
|
||||
rm -rf "${PRIVATE_CONFIG}/without-accounts"
|
||||
mkdir -p "${PRIVATE_CONFIG}/without-accounts"
|
||||
|
||||
run docker run --rm \
|
||||
-e LOG_LEVEL='trace' \
|
||||
-v "${PRIVATE_CONFIG}/without-accounts/":/tmp/docker-mailserver/ \
|
||||
-v "${PRIVATE_CONFIG}/postfix-virtual.cf":/tmp/docker-mailserver/postfix-virtual.cf \
|
||||
"${IMAGE_NAME}" /bin/bash -c 'open-dkim | wc -l'
|
||||
|
||||
assert_success
|
||||
assert_output 5
|
||||
|
||||
# check keys for localhost.localdomain
|
||||
run docker run --rm \
|
||||
-e LOG_LEVEL='trace' \
|
||||
-v "${PRIVATE_CONFIG}/without-accounts/opendkim":/etc/opendkim \
|
||||
"${IMAGE_NAME}" /bin/bash -c 'ls -1 /etc/opendkim/keys/localhost.localdomain/ | wc -l'
|
||||
|
||||
assert_success
|
||||
assert_output 2
|
||||
|
||||
# check keys for otherdomain.tld
|
||||
# run docker run --rm \
|
||||
# -v "${PRIVATE_CONFIG}/without-accounts/opendkim":/etc/opendkim \
|
||||
# "${IMAGE_NAME}" /bin/bash -c 'ls -1 /etc/opendkim/keys/otherdomain.tld | wc -l'
|
||||
# assert_success
|
||||
# [ "${output}" -eq 0 ]
|
||||
|
||||
# check presence of tables and TrustedHosts
|
||||
run docker run --rm \
|
||||
-e LOG_LEVEL='trace' \
|
||||
-v "${PRIVATE_CONFIG}/without-accounts/opendkim":/etc/opendkim \
|
||||
"${IMAGE_NAME}" /bin/bash -c "ls -1 /etc/opendkim | grep -E 'KeyTable|SigningTable|TrustedHosts|keys'|wc -l"
|
||||
|
||||
assert_success
|
||||
assert_output 4
|
||||
}
|
||||
|
||||
@test "${TEST_FILE}generator creates keys, tables and TrustedHosts without postfix-virtual.cf" {
|
||||
local PRIVATE_CONFIG
|
||||
PRIVATE_CONFIG=$(duplicate_config_for_container . "${BATS_TEST_NAME}")
|
||||
|
||||
rm -rf "${PRIVATE_CONFIG}/without-virtual"
|
||||
mkdir -p "${PRIVATE_CONFIG}/without-virtual"
|
||||
|
||||
run docker run --rm \
|
||||
-e LOG_LEVEL='trace' \
|
||||
-v "${PRIVATE_CONFIG}/without-virtual/":/tmp/docker-mailserver/ \
|
||||
-v "${PRIVATE_CONFIG}/postfix-accounts.cf":/tmp/docker-mailserver/postfix-accounts.cf \
|
||||
"${IMAGE_NAME}" /bin/bash -c 'open-dkim | wc -l'
|
||||
|
||||
assert_success
|
||||
assert_output 5
|
||||
|
||||
# check keys for localhost.localdomain
|
||||
run docker run --rm \
|
||||
-e LOG_LEVEL='trace' \
|
||||
-v "${PRIVATE_CONFIG}/without-virtual/opendkim":/etc/opendkim \
|
||||
"${IMAGE_NAME}" /bin/bash -c 'ls -1 /etc/opendkim/keys/localhost.localdomain/ | wc -l'
|
||||
|
||||
assert_success
|
||||
assert_output 2
|
||||
|
||||
# check keys for otherdomain.tld
|
||||
run docker run --rm \
|
||||
-e LOG_LEVEL='trace' \
|
||||
-v "${PRIVATE_CONFIG}/without-virtual/opendkim":/etc/opendkim \
|
||||
"${IMAGE_NAME}" /bin/bash -c 'ls -1 /etc/opendkim/keys/otherdomain.tld | wc -l'
|
||||
|
||||
assert_success
|
||||
assert_output 2
|
||||
|
||||
# check presence of tables and TrustedHosts
|
||||
run docker run --rm \
|
||||
-e LOG_LEVEL='trace' \
|
||||
-v "${PRIVATE_CONFIG}/without-virtual/opendkim":/etc/opendkim \
|
||||
"${IMAGE_NAME}" /bin/bash -c "ls -1 /etc/opendkim | grep -E 'KeyTable|SigningTable|TrustedHosts|keys'|wc -l"
|
||||
|
||||
assert_success
|
||||
assert_output 4
|
||||
}
|
||||
|
||||
@test "${TEST_FILE}generator creates keys, tables and TrustedHosts using manual provided domain name" {
|
||||
local PRIVATE_CONFIG
|
||||
PRIVATE_CONFIG=$(duplicate_config_for_container . "${BATS_TEST_NAME}")
|
||||
rm -rf "${PRIVATE_CONFIG}/with-domain" && mkdir -p "${PRIVATE_CONFIG}/with-domain"
|
||||
|
||||
# generate first key
|
||||
run docker run --rm \
|
||||
-e LOG_LEVEL='trace' \
|
||||
-v "${PRIVATE_CONFIG}/with-domain/":/tmp/docker-mailserver/ \
|
||||
"${IMAGE_NAME}" /bin/bash -c 'open-dkim keysize 2048 domain domain1.tld | wc -l'
|
||||
|
||||
assert_success
|
||||
assert_output 4
|
||||
|
||||
# generate two additional keys different to the previous one
|
||||
run docker run --rm \
|
||||
-e LOG_LEVEL='trace' \
|
||||
-v "${PRIVATE_CONFIG}/with-domain/":/tmp/docker-mailserver/ \
|
||||
"${IMAGE_NAME}" /bin/bash -c 'open-dkim keysize 2048 domain "domain2.tld,domain3.tld" | wc -l'
|
||||
|
||||
assert_success
|
||||
assert_output 2
|
||||
|
||||
# generate an additional key whilst providing already existing domains
|
||||
run docker run --rm \
|
||||
-e LOG_LEVEL='trace' \
|
||||
-v "${PRIVATE_CONFIG}/with-domain/":/tmp/docker-mailserver/ \
|
||||
"${IMAGE_NAME}" /bin/bash -c 'open-dkim keysize 2048 domain "domain3.tld,domain4.tld" | wc -l'
|
||||
|
||||
assert_success
|
||||
assert_output 1
|
||||
|
||||
# check keys for domain1.tld
|
||||
run docker run --rm \
|
||||
-e LOG_LEVEL='trace' \
|
||||
-v "${PRIVATE_CONFIG}/with-domain/opendkim":/etc/opendkim \
|
||||
"${IMAGE_NAME}" /bin/bash -c 'ls -1 /etc/opendkim/keys/domain1.tld/ | wc -l'
|
||||
|
||||
assert_success
|
||||
assert_output 2
|
||||
|
||||
# check keys for domain2.tld
|
||||
run docker run --rm \
|
||||
-e LOG_LEVEL='trace' \
|
||||
-v "${PRIVATE_CONFIG}/with-domain/opendkim":/etc/opendkim \
|
||||
"${IMAGE_NAME}" /bin/bash -c 'ls -1 /etc/opendkim/keys/domain2.tld | wc -l'
|
||||
|
||||
assert_success
|
||||
assert_output 2
|
||||
|
||||
# check keys for domain3.tld
|
||||
run docker run --rm \
|
||||
-e LOG_LEVEL='trace' \
|
||||
-v "${PRIVATE_CONFIG}/with-domain/opendkim":/etc/opendkim \
|
||||
"${IMAGE_NAME}" /bin/bash -c 'ls -1 /etc/opendkim/keys/domain3.tld | wc -l'
|
||||
|
||||
assert_success
|
||||
assert_output 2
|
||||
|
||||
# check keys for domain4.tld
|
||||
run docker run --rm \
|
||||
-e LOG_LEVEL='trace' \
|
||||
-v "${PRIVATE_CONFIG}/with-domain/opendkim":/etc/opendkim \
|
||||
"${IMAGE_NAME}" /bin/bash -c 'ls -1 /etc/opendkim/keys/domain4.tld | wc -l'
|
||||
|
||||
assert_success
|
||||
assert_output 2
|
||||
|
||||
# check presence of tables and TrustedHosts
|
||||
run docker run --rm \
|
||||
-e LOG_LEVEL='trace' \
|
||||
-v "${PRIVATE_CONFIG}/with-domain/opendkim":/etc/opendkim \
|
||||
"${IMAGE_NAME}" /bin/bash -c "ls -1 /etc/opendkim | grep -E 'KeyTable|SigningTable|TrustedHosts|keys' | wc -l"
|
||||
|
||||
assert_success
|
||||
assert_output 4
|
||||
|
||||
# check valid entries actually present in KeyTable
|
||||
run docker run --rm \
|
||||
-e LOG_LEVEL='trace' \
|
||||
-v "${PRIVATE_CONFIG}/with-domain/opendkim":/etc/opendkim \
|
||||
"${IMAGE_NAME}" /bin/bash -c \
|
||||
"egrep 'domain1.tld|domain2.tld|domain3.tld|domain4.tld' /etc/opendkim/KeyTable | wc -l"
|
||||
|
||||
assert_success
|
||||
assert_output 4
|
||||
|
||||
# check valid entries actually present in SigningTable
|
||||
run docker run --rm \
|
||||
-e LOG_LEVEL='trace' \
|
||||
-v "${PRIVATE_CONFIG}/with-domain/opendkim":/etc/opendkim \
|
||||
"${IMAGE_NAME}" /bin/bash -c \
|
||||
"egrep 'domain1.tld|domain2.tld|domain3.tld|domain4.tld' /etc/opendkim/SigningTable | wc -l"
|
||||
|
||||
assert_success
|
||||
assert_output 4
|
||||
}
|
||||
|
||||
@test "${TEST_FILE}generator creates keys, tables and TrustedHosts using manual provided selector name" {
|
||||
local PRIVATE_CONFIG
|
||||
PRIVATE_CONFIG=$(duplicate_config_for_container . "${BATS_TEST_NAME}")
|
||||
rm -rf "${PRIVATE_CONFIG}/with-selector" && mkdir -p "${PRIVATE_CONFIG}/with-selector"
|
||||
|
||||
# Generate first key
|
||||
run docker run --rm \
|
||||
-e LOG_LEVEL='trace' \
|
||||
-v "${PRIVATE_CONFIG}/with-selector/":/tmp/docker-mailserver/ \
|
||||
"${IMAGE_NAME:?}" /bin/sh -c "open-dkim keysize 2048 domain 'domain1.tld' selector mailer| wc -l"
|
||||
|
||||
assert_success
|
||||
assert_output 4
|
||||
|
||||
# Check keys for domain1.tld
|
||||
run docker run --rm \
|
||||
-e LOG_LEVEL='trace' \
|
||||
-v "${PRIVATE_CONFIG}/with-selector/opendkim":/etc/opendkim \
|
||||
"${IMAGE_NAME:?}" /bin/sh -c 'ls -1 /etc/opendkim/keys/domain1.tld/ | wc -l'
|
||||
|
||||
assert_success
|
||||
assert_output 2
|
||||
|
||||
# Check key names with selector for domain1.tld
|
||||
run docker run --rm \
|
||||
-e LOG_LEVEL='trace' \
|
||||
-v "${PRIVATE_CONFIG}/with-selector/opendkim":/etc/opendkim \
|
||||
"${IMAGE_NAME:?}" /bin/sh -c "ls -1 /etc/opendkim/keys/domain1.tld | grep -E 'mailer.private|mailer.txt' | wc -l"
|
||||
|
||||
assert_success
|
||||
assert_output 2
|
||||
|
||||
# Check presence of tables and TrustedHosts
|
||||
run docker run --rm \
|
||||
-e LOG_LEVEL='trace' \
|
||||
-v "${PRIVATE_CONFIG}/with-selector/opendkim":/etc/opendkim \
|
||||
"${IMAGE_NAME:?}" /bin/sh -c "ls -1 /etc/opendkim | grep -E 'KeyTable|SigningTable|TrustedHosts|keys' | wc -l"
|
||||
|
||||
assert_success
|
||||
assert_output 4
|
||||
|
||||
# Check valid entries actually present in KeyTable
|
||||
run docker run --rm \
|
||||
-e LOG_LEVEL='trace' \
|
||||
-v "${PRIVATE_CONFIG}/with-selector/opendkim":/etc/opendkim \
|
||||
"${IMAGE_NAME:?}" /bin/sh -c \
|
||||
"grep 'domain1.tld' /etc/opendkim/KeyTable | wc -l"
|
||||
|
||||
assert_success
|
||||
assert_output 1
|
||||
|
||||
# Check valid entries actually present in SigningTable
|
||||
run docker run --rm \
|
||||
-e LOG_LEVEL='trace' \
|
||||
-v "${PRIVATE_CONFIG}/with-selector/opendkim":/etc/opendkim \
|
||||
"${IMAGE_NAME:?}" /bin/sh -c \
|
||||
"grep 'domain1.tld' /etc/opendkim/SigningTable | wc -l"
|
||||
|
||||
assert_success
|
||||
assert_output 1
|
||||
}
|
89
test/tests/serial/permit_docker.bats
Normal file
89
test/tests/serial/permit_docker.bats
Normal file
|
@ -0,0 +1,89 @@
|
|||
load 'test_helper/common'
|
||||
|
||||
NON_DEFAULT_DOCKER_MAIL_NETWORK_NAME=non-default-docker-mail-network
|
||||
setup_file() {
|
||||
docker network create --driver bridge "${NON_DEFAULT_DOCKER_MAIL_NETWORK_NAME}"
|
||||
docker network create --driver bridge "${NON_DEFAULT_DOCKER_MAIL_NETWORK_NAME}2"
|
||||
|
||||
# use two networks (default ("bridge") and our custom network) to recreate problematic test case where PERMIT_DOCKER=host would not help
|
||||
# currently we cannot use --network in `docker run` multiple times, it will just use the last one
|
||||
# instead we need to use create, network connect and start (see https://success.docker.com/article/multiple-docker-networks)
|
||||
local PRIVATE_CONFIG
|
||||
|
||||
PRIVATE_CONFIG=$(duplicate_config_for_container . mail_smtponly_second_network)
|
||||
docker create --name mail_smtponly_second_network \
|
||||
-v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \
|
||||
-v "$(pwd)/test/test-files":/tmp/docker-mailserver-test:ro \
|
||||
-e SMTP_ONLY=1 \
|
||||
-e PERMIT_DOCKER=connected-networks \
|
||||
-e OVERRIDE_HOSTNAME=mail.my-domain.com \
|
||||
--network "${NON_DEFAULT_DOCKER_MAIL_NETWORK_NAME}" \
|
||||
-t "${NAME}"
|
||||
|
||||
docker network connect "${NON_DEFAULT_DOCKER_MAIL_NETWORK_NAME}2" mail_smtponly_second_network
|
||||
docker start mail_smtponly_second_network
|
||||
|
||||
PRIVATE_CONFIG=$(duplicate_config_for_container . mail_smtponly_second_network_sender)
|
||||
docker run -d --name mail_smtponly_second_network_sender \
|
||||
-v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \
|
||||
-v "$(pwd)/test/test-files":/tmp/docker-mailserver-test:ro \
|
||||
-e SMTP_ONLY=1 \
|
||||
-e PERMIT_DOCKER=connected-networks \
|
||||
-e OVERRIDE_HOSTNAME=mail.my-domain.com \
|
||||
--network "${NON_DEFAULT_DOCKER_MAIL_NETWORK_NAME}2" \
|
||||
-t "${NAME}"
|
||||
|
||||
# wait until postfix is up
|
||||
wait_for_smtp_port_in_container mail_smtponly_second_network
|
||||
|
||||
# create another container that enforces authentication even on local connections
|
||||
docker run -d --name mail_smtponly_force_authentication \
|
||||
-v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \
|
||||
-v "$(pwd)/test/test-files":/tmp/docker-mailserver-test:ro \
|
||||
-e SMTP_ONLY=1 \
|
||||
-e PERMIT_DOCKER=none \
|
||||
-e OVERRIDE_HOSTNAME=mail.my-domain.com \
|
||||
-t "${NAME}"
|
||||
|
||||
# wait until postfix is up
|
||||
wait_for_smtp_port_in_container mail_smtponly_force_authentication
|
||||
}
|
||||
|
||||
teardown_file() {
|
||||
docker logs mail_smtponly_second_network
|
||||
docker rm -f mail_smtponly_second_network mail_smtponly_second_network_sender mail_smtponly_force_authentication
|
||||
docker network rm "${NON_DEFAULT_DOCKER_MAIL_NETWORK_NAME}" "${NON_DEFAULT_DOCKER_MAIL_NETWORK_NAME}2"
|
||||
}
|
||||
|
||||
@test "checking PERMIT_DOCKER: connected-networks" {
|
||||
IPNET1=$(docker network inspect --format '{{(index .IPAM.Config 0).Subnet}}' non-default-docker-mail-network)
|
||||
IPNET2=$(docker network inspect --format '{{(index .IPAM.Config 0).Subnet}}' non-default-docker-mail-network2)
|
||||
run docker exec mail_smtponly_second_network /bin/sh -c "postconf | grep '^mynetworks ='"
|
||||
assert_output --partial "${IPNET1}"
|
||||
assert_output --partial "${IPNET2}"
|
||||
|
||||
run docker exec mail_smtponly_second_network /bin/sh -c "postconf smtp_host_lookup=no"
|
||||
assert_success
|
||||
|
||||
run docker exec mail_smtponly_second_network /bin/sh -c "/etc/init.d/postfix reload"
|
||||
assert_success
|
||||
|
||||
# we should be able to send from the other container on the second network!
|
||||
run docker exec mail_smtponly_second_network_sender /bin/sh -c "nc mail_smtponly_second_network 25 < /tmp/docker-mailserver-test/email-templates/smtp-only.txt"
|
||||
assert_output --partial "250 2.0.0 Ok: queued as "
|
||||
repeat_until_success_or_timeout 60 run docker exec mail_smtponly_second_network /bin/sh -c 'grep -cE "to=<user2\@external.tld>.*status\=sent" /var/log/mail/mail.log'
|
||||
[[ ${status} -ge 0 ]]
|
||||
}
|
||||
|
||||
@test "checking PERMIT_DOCKER: none" {
|
||||
run docker exec mail_smtponly_force_authentication /bin/sh -c "postconf smtp_host_lookup=no"
|
||||
assert_success
|
||||
|
||||
run docker exec mail_smtponly_force_authentication /bin/sh -c "/etc/init.d/postfix reload"
|
||||
assert_success
|
||||
|
||||
# the mailserver should require authentication and a protocol error should occur when using TLS
|
||||
run docker exec mail_smtponly_force_authentication /bin/sh -c "nc localhost 25 < /tmp/docker-mailserver-test/email-templates/smtp-only.txt"
|
||||
assert_output --partial "550 5.5.1 Protocol error"
|
||||
[[ ${status} -ge 0 ]]
|
||||
}
|
243
test/tests/serial/security_tls_cipherlists.bats
Normal file
243
test/tests/serial/security_tls_cipherlists.bats
Normal file
|
@ -0,0 +1,243 @@
|
|||
#!/usr/bin/env bats
|
||||
load 'test_helper/common'
|
||||
# Globals ${BATS_TMPDIR} and ${NAME}
|
||||
# `${NAME}` defaults to `mailserver-testing:ci`
|
||||
|
||||
function teardown() {
|
||||
docker rm -f tls_test_cipherlists
|
||||
}
|
||||
|
||||
function setup_file() {
|
||||
export DOMAIN="example.test"
|
||||
export NETWORK="test-network"
|
||||
|
||||
# Shared config for TLS testing (read-only)
|
||||
export TLS_CONFIG_VOLUME
|
||||
TLS_CONFIG_VOLUME="$(pwd)/test/test-files/ssl/${DOMAIN}/:/config/ssl/:ro"
|
||||
# `${BATS_TMPDIR}` maps to `/tmp`
|
||||
export TLS_RESULTS_DIR="${BATS_TMPDIR}/results"
|
||||
|
||||
# NOTE: If the network already exists, test will fail to start.
|
||||
docker network create "${NETWORK}"
|
||||
|
||||
# Copies all of `./test/config/` to specific directory for testing
|
||||
# `${PRIVATE_CONFIG}` becomes `$(pwd)/test/duplicate_configs/<bats test filename>`
|
||||
export PRIVATE_CONFIG
|
||||
PRIVATE_CONFIG=$(duplicate_config_for_container .)
|
||||
|
||||
# Pull `testssl.sh` image in advance to avoid it interfering with the `run` captured output.
|
||||
# Only interferes (potential test failure) with `assert_output` not `assert_success`?
|
||||
docker pull drwetter/testssl.sh:3.1dev
|
||||
}
|
||||
|
||||
function teardown_file() {
|
||||
docker network rm "${NETWORK}"
|
||||
}
|
||||
|
||||
@test "checking tls: cipher list - rsa intermediate" {
|
||||
check_ports 'rsa' 'intermediate'
|
||||
}
|
||||
|
||||
@test "checking tls: cipher list - rsa modern" {
|
||||
check_ports 'rsa' 'modern'
|
||||
}
|
||||
|
||||
@test "checking tls: cipher list - ecdsa intermediate" {
|
||||
check_ports 'ecdsa' 'intermediate'
|
||||
}
|
||||
|
||||
@test "checking tls: cipher list - ecdsa modern" {
|
||||
check_ports 'ecdsa' 'modern'
|
||||
}
|
||||
|
||||
|
||||
# Only ECDSA with RSA fallback is tested.
|
||||
# There isn't a situation where RSA with ECDSA fallback would make sense.
|
||||
@test "checking tls: cipher list - ecdsa intermediate, with rsa fallback" {
|
||||
check_ports 'ecdsa' 'intermediate' 'rsa'
|
||||
}
|
||||
|
||||
@test "checking tls: cipher list - ecdsa modern, with rsa fallback" {
|
||||
check_ports 'ecdsa' 'modern' 'rsa'
|
||||
}
|
||||
|
||||
function check_ports() {
|
||||
local KEY_TYPE=$1
|
||||
local TLS_LEVEL=$2
|
||||
local ALT_KEY_TYPE=$3 # Optional parameter
|
||||
|
||||
local KEY_TYPE_LABEL="${KEY_TYPE}"
|
||||
# This is just to add a `_` delimiter between the two key types for readability
|
||||
if [[ -n ${ALT_KEY_TYPE} ]]
|
||||
then
|
||||
KEY_TYPE_LABEL="${KEY_TYPE}_${ALT_KEY_TYPE}"
|
||||
fi
|
||||
local RESULTS_PATH="${KEY_TYPE_LABEL}/${TLS_LEVEL}"
|
||||
|
||||
collect_cipherlist_data
|
||||
|
||||
# SMTP: Opportunistic STARTTLS Explicit(25)
|
||||
# Needs to test against cipher lists specific to Port 25 ('_p25' parameter)
|
||||
check_cipherlists "${RESULTS_PATH}/port_25.json" '_p25'
|
||||
|
||||
# SMTP Submission: Mandatory STARTTLS Explicit(587) and Implicit(465) TLS
|
||||
check_cipherlists "${RESULTS_PATH}/port_587.json"
|
||||
check_cipherlists "${RESULTS_PATH}/port_465.json"
|
||||
|
||||
# IMAP: Mandatory STARTTLS Explicit(143) and Implicit(993) TLS
|
||||
check_cipherlists "${RESULTS_PATH}/port_143.json"
|
||||
check_cipherlists "${RESULTS_PATH}/port_993.json"
|
||||
|
||||
# POP3: Mandatory STARTTLS Explicit(110) and Implicit(995)
|
||||
check_cipherlists "${RESULTS_PATH}/port_110.json"
|
||||
check_cipherlists "${RESULTS_PATH}/port_995.json"
|
||||
}
|
||||
|
||||
function collect_cipherlist_data() {
|
||||
local ALT_CERT=()
|
||||
local ALT_KEY=()
|
||||
|
||||
if [[ -n ${ALT_KEY_TYPE} ]]
|
||||
then
|
||||
ALT_CERT=(--env SSL_ALT_CERT_PATH="/config/ssl/cert.${ALT_KEY_TYPE}.pem")
|
||||
ALT_KEY=(--env SSL_ALT_KEY_PATH="/config/ssl/key.${ALT_KEY_TYPE}.pem")
|
||||
fi
|
||||
|
||||
run docker run -d --name tls_test_cipherlists \
|
||||
--volume "${PRIVATE_CONFIG}/:/tmp/docker-mailserver/" \
|
||||
--volume "${TLS_CONFIG_VOLUME}" \
|
||||
--env ENABLE_POP3=1 \
|
||||
--env SSL_TYPE="manual" \
|
||||
--env SSL_CERT_PATH="/config/ssl/cert.${KEY_TYPE}.pem" \
|
||||
--env SSL_KEY_PATH="/config/ssl/key.${KEY_TYPE}.pem" \
|
||||
"${ALT_CERT[@]}" \
|
||||
"${ALT_KEY[@]}" \
|
||||
--env TLS_LEVEL="${TLS_LEVEL}" \
|
||||
--network "${NETWORK}" \
|
||||
--network-alias "${DOMAIN}" \
|
||||
--hostname "mail.${DOMAIN}" \
|
||||
--tty \
|
||||
"${NAME}" # Image name
|
||||
|
||||
assert_success
|
||||
|
||||
wait_for_tcp_port_in_container 25 tls_test_cipherlists
|
||||
# NOTE: An rDNS query for the container IP will resolve to `<container name>.<network name>.`
|
||||
|
||||
# Make directory with test user ownership. Avoids Docker creating with root ownership.
|
||||
# TODO: Can switch to filename prefix for JSON output when this is resolved: https://github.com/drwetter/testssl.sh/issues/1845
|
||||
mkdir -p "${TLS_RESULTS_DIR}/${RESULTS_PATH}"
|
||||
|
||||
# For non-CI test runs, instead of removing prior test files after this test suite completes,
|
||||
# they're retained and overwritten by future test runs instead. Useful for inspection.
|
||||
# `--preference` reduces the test scope to the cipher suites reported as supported by the server. Completes in ~35% of the time.
|
||||
local TESTSSL_CMD=(--quiet --file "/config/ssl/testssl.txt" --mode parallel --overwrite --preference)
|
||||
# NOTE: Batch testing ports via `--file` doesn't properly bubble up failure.
|
||||
# If the failure for a test is misleading consider testing a single port with:
|
||||
# local TESTSSL_CMD=(--quiet --jsonfile-pretty "${RESULTS_PATH}/port_${PORT}.json" --starttls smtp "${DOMAIN}:${PORT}")
|
||||
# TODO: Can use `jq` to check for failure when this is resolved: https://github.com/drwetter/testssl.sh/issues/1844
|
||||
|
||||
# `--user "<uid>:<gid>"` is a workaround: Avoids `permission denied` write errors for json output, uses `id` to match user uid & gid.
|
||||
run docker run --rm \
|
||||
--user "$(id -u):$(id -g)" \
|
||||
--network "${NETWORK}" \
|
||||
--volume "${TLS_CONFIG_VOLUME}" \
|
||||
--volume "${TLS_RESULTS_DIR}/${RESULTS_PATH}/:/output" \
|
||||
--workdir "/output" \
|
||||
drwetter/testssl.sh:3.1dev "${TESTSSL_CMD[@]}"
|
||||
|
||||
assert_success
|
||||
}
|
||||
|
||||
# Use `jq` to extract a specific cipher list from the target`testssl.sh` results json output file
|
||||
function compare_cipherlist() {
|
||||
local TARGET_CIPHERLIST=$1
|
||||
local RESULTS_FILE=$2
|
||||
local EXPECTED_CIPHERLIST=$3
|
||||
|
||||
run jq '.scanResult[0].serverPreferences[] | select(.id=="'"${TARGET_CIPHERLIST}"'") | .finding' "${TLS_RESULTS_DIR}/${RESULTS_FILE}"
|
||||
assert_success
|
||||
assert_output "${EXPECTED_CIPHERLIST}"
|
||||
}
|
||||
|
||||
# Compares the expected cipher lists against logged test results from `testssl.sh`
|
||||
function check_cipherlists() {
|
||||
local RESULTS_FILE=$1
|
||||
local p25=$2 # optional suffix
|
||||
|
||||
# TLS_LEVEL `modern` doesn't have TLS v1.0 or v1.1 cipher suites. Sets TLS v1.2 as minimum.
|
||||
if [[ ${TLS_LEVEL} == "intermediate" ]]
|
||||
then
|
||||
compare_cipherlist "cipherorder_TLSv1" "${RESULTS_FILE}" "$(get_cipherlist "TLSv1${p25}")"
|
||||
compare_cipherlist "cipherorder_TLSv1_1" "${RESULTS_FILE}" "$(get_cipherlist "TLSv1_1${p25}")"
|
||||
fi
|
||||
|
||||
compare_cipherlist "cipherorder_TLSv1_2" "${RESULTS_FILE}" "$(get_cipherlist "TLSv1_2${p25}")"
|
||||
compare_cipherlist "cipherorder_TLSv1_3" "${RESULTS_FILE}" "$(get_cipherlist 'TLSv1_3')"
|
||||
}
|
||||
|
||||
# Expected cipher lists. Should match `TLS_LEVEL` cipher lists set in `start-mailserver.sh`.
|
||||
# Excluding Port 25 which uses defaults from Postfix after applying `smtpd_tls_exclude_ciphers` rules.
|
||||
# NOTE: If a test fails, look at the `check_ports` params, then update the corresponding associative key's value
|
||||
# with the `actual` error value (assuming an update needs to be made, and not a valid security issue to look into).
|
||||
function get_cipherlist() {
|
||||
local TLS_VERSION=$1
|
||||
|
||||
if [[ ${TLS_VERSION} == "TLSv1_3" ]]
|
||||
then
|
||||
# TLS v1.3 cipher suites are not user defineable and not unique to the available certificate(s).
|
||||
# They do not support server enforced order either.
|
||||
echo '"TLS_AES_256_GCM_SHA384 TLS_CHACHA20_POLY1305_SHA256 TLS_AES_128_GCM_SHA256"'
|
||||
else
|
||||
# Associative array for easy querying of required cipher list
|
||||
declare -A CIPHER_LIST
|
||||
|
||||
# `intermediate` cipher lists TLS v1.0 and v1.1 cipher suites should be the same:
|
||||
CIPHER_LIST["rsa_intermediate_TLSv1"]='"ECDHE-RSA-AES128-SHA ECDHE-RSA-AES256-SHA DHE-RSA-AES128-SHA DHE-RSA-AES256-SHA"'
|
||||
CIPHER_LIST["rsa_intermediate_TLSv1_1"]=${CIPHER_LIST["rsa_intermediate_TLSv1"]}
|
||||
CIPHER_LIST["rsa_intermediate_TLSv1_2"]='"ECDHE-RSA-CHACHA20-POLY1305 ECDHE-RSA-AES128-GCM-SHA256 ECDHE-RSA-AES256-GCM-SHA384 DHE-RSA-AES128-GCM-SHA256 DHE-RSA-AES256-GCM-SHA384 ECDHE-RSA-AES128-SHA256 ECDHE-RSA-AES256-SHA384 ECDHE-RSA-AES128-SHA ECDHE-RSA-AES256-SHA DHE-RSA-AES128-SHA256 DHE-RSA-AES128-SHA DHE-RSA-AES256-SHA256 DHE-RSA-AES256-SHA"'
|
||||
# `modern` cipher lists shouldn't have TLS v1.0 or v1.1 cipher suites:
|
||||
CIPHER_LIST["rsa_modern_TLSv1_2"]='"ECDHE-RSA-AES128-GCM-SHA256 ECDHE-RSA-AES256-GCM-SHA384 ECDHE-RSA-CHACHA20-POLY1305 DHE-RSA-AES128-GCM-SHA256 DHE-RSA-AES256-GCM-SHA384"'
|
||||
|
||||
# ECDSA:
|
||||
CIPHER_LIST["ecdsa_intermediate_TLSv1"]='"ECDHE-ECDSA-AES128-SHA ECDHE-ECDSA-AES256-SHA"'
|
||||
CIPHER_LIST["ecdsa_intermediate_TLSv1_1"]=${CIPHER_LIST["ecdsa_intermediate_TLSv1"]}
|
||||
CIPHER_LIST["ecdsa_intermediate_TLSv1_2"]='"ECDHE-ECDSA-CHACHA20-POLY1305 ECDHE-ECDSA-AES128-GCM-SHA256 ECDHE-ECDSA-AES256-GCM-SHA384 ECDHE-ECDSA-AES128-SHA256 ECDHE-ECDSA-AES128-SHA ECDHE-ECDSA-AES256-SHA384 ECDHE-ECDSA-AES256-SHA"'
|
||||
CIPHER_LIST["ecdsa_modern_TLSv1_2"]='"ECDHE-ECDSA-AES128-GCM-SHA256 ECDHE-ECDSA-AES256-GCM-SHA384 ECDHE-ECDSA-CHACHA20-POLY1305"'
|
||||
|
||||
# ECDSA + RSA fallback, dual cert support:
|
||||
CIPHER_LIST["ecdsa_rsa_intermediate_TLSv1"]='"ECDHE-ECDSA-AES128-SHA ECDHE-RSA-AES128-SHA ECDHE-ECDSA-AES256-SHA ECDHE-RSA-AES256-SHA DHE-RSA-AES128-SHA DHE-RSA-AES256-SHA"'
|
||||
CIPHER_LIST["ecdsa_rsa_intermediate_TLSv1_1"]=${CIPHER_LIST["ecdsa_rsa_intermediate_TLSv1"]}
|
||||
CIPHER_LIST["ecdsa_rsa_intermediate_TLSv1_2"]='"ECDHE-ECDSA-CHACHA20-POLY1305 ECDHE-RSA-CHACHA20-POLY1305 ECDHE-ECDSA-AES128-GCM-SHA256 ECDHE-RSA-AES128-GCM-SHA256 ECDHE-ECDSA-AES256-GCM-SHA384 ECDHE-RSA-AES256-GCM-SHA384 DHE-RSA-AES128-GCM-SHA256 DHE-RSA-AES256-GCM-SHA384 ECDHE-ECDSA-AES128-SHA256 ECDHE-RSA-AES128-SHA256 ECDHE-ECDSA-AES128-SHA ECDHE-RSA-AES256-SHA384 ECDHE-RSA-AES128-SHA ECDHE-ECDSA-AES256-SHA384 ECDHE-ECDSA-AES256-SHA ECDHE-RSA-AES256-SHA DHE-RSA-AES128-SHA256 DHE-RSA-AES128-SHA DHE-RSA-AES256-SHA256 DHE-RSA-AES256-SHA"'
|
||||
CIPHER_LIST["ecdsa_rsa_modern_TLSv1_2"]='"ECDHE-ECDSA-AES128-GCM-SHA256 ECDHE-RSA-AES128-GCM-SHA256 ECDHE-ECDSA-AES256-GCM-SHA384 ECDHE-RSA-AES256-GCM-SHA384 ECDHE-ECDSA-CHACHA20-POLY1305 ECDHE-RSA-CHACHA20-POLY1305 DHE-RSA-AES128-GCM-SHA256 DHE-RSA-AES256-GCM-SHA384"'
|
||||
|
||||
|
||||
# Port 25
|
||||
# TLSv1 and TLSv1_1 share the same cipher suites as other ports have. But the server order differs:
|
||||
CIPHER_LIST["rsa_intermediate_TLSv1_p25"]='"ECDHE-RSA-AES256-SHA DHE-RSA-AES256-SHA ECDHE-RSA-AES128-SHA DHE-RSA-AES128-SHA"'
|
||||
CIPHER_LIST["rsa_intermediate_TLSv1_1_p25"]=${CIPHER_LIST["rsa_intermediate_TLSv1_p25"]}
|
||||
# TLSv1_2 has different server order and also includes ARIA, CCM, DHE+CHACHA20-POLY1305 cipher suites:
|
||||
CIPHER_LIST["rsa_intermediate_TLSv1_2_p25"]='"ECDHE-RSA-AES256-GCM-SHA384 DHE-RSA-AES256-GCM-SHA384 ECDHE-RSA-CHACHA20-POLY1305 DHE-RSA-CHACHA20-POLY1305 DHE-RSA-AES256-CCM8 DHE-RSA-AES256-CCM ECDHE-ARIA256-GCM-SHA384 DHE-RSA-ARIA256-GCM-SHA384 ECDHE-RSA-AES256-SHA384 DHE-RSA-AES256-SHA256 ECDHE-RSA-AES256-SHA DHE-RSA-AES256-SHA ARIA256-GCM-SHA384 ECDHE-RSA-AES128-GCM-SHA256 DHE-RSA-AES128-GCM-SHA256 DHE-RSA-AES128-CCM8 DHE-RSA-AES128-CCM ECDHE-ARIA128-GCM-SHA256 DHE-RSA-ARIA128-GCM-SHA256 ECDHE-RSA-AES128-SHA256 DHE-RSA-AES128-SHA256 ECDHE-RSA-AES128-SHA DHE-RSA-AES128-SHA ARIA128-GCM-SHA256"'
|
||||
# Port 25 is unaffected by `TLS_LEVEL` profiles (other than min TLS version), it has the same TLS v1.2 cipher list under both:
|
||||
CIPHER_LIST["rsa_modern_TLSv1_2_p25"]=${CIPHER_LIST["rsa_intermediate_TLSv1_2_p25"]}
|
||||
|
||||
# ECDSA (Port 25):
|
||||
CIPHER_LIST["ecdsa_intermediate_TLSv1_p25"]='"ECDHE-ECDSA-AES256-SHA ECDHE-ECDSA-AES128-SHA"'
|
||||
CIPHER_LIST["ecdsa_intermediate_TLSv1_1_p25"]=${CIPHER_LIST["ecdsa_intermediate_TLSv1_p25"]}
|
||||
|
||||
CIPHER_LIST["ecdsa_intermediate_TLSv1_2_p25"]='"ECDHE-ECDSA-AES256-GCM-SHA384 ECDHE-ECDSA-CHACHA20-POLY1305 ECDHE-ECDSA-AES256-CCM8 ECDHE-ECDSA-AES256-CCM ECDHE-ECDSA-ARIA256-GCM-SHA384 ECDHE-ECDSA-AES256-SHA384 ECDHE-ECDSA-AES256-SHA ECDHE-ECDSA-AES128-GCM-SHA256 ECDHE-ECDSA-AES128-CCM8 ECDHE-ECDSA-AES128-CCM ECDHE-ECDSA-ARIA128-GCM-SHA256 ECDHE-ECDSA-AES128-SHA256 ECDHE-ECDSA-AES128-SHA"'
|
||||
CIPHER_LIST["ecdsa_modern_TLSv1_2_p25"]=${CIPHER_LIST["ecdsa_intermediate_TLSv1_2_p25"]}
|
||||
|
||||
|
||||
# ECDSA + RSA fallback, dual cert support (Port 25):
|
||||
CIPHER_LIST["ecdsa_rsa_intermediate_TLSv1_p25"]='"ECDHE-ECDSA-AES256-SHA ECDHE-RSA-AES256-SHA DHE-RSA-AES256-SHA ECDHE-ECDSA-AES128-SHA ECDHE-RSA-AES128-SHA DHE-RSA-AES128-SHA"'
|
||||
CIPHER_LIST["ecdsa_rsa_intermediate_TLSv1_1_p25"]=${CIPHER_LIST["ecdsa_rsa_intermediate_TLSv1_p25"]}
|
||||
|
||||
CIPHER_LIST["ecdsa_rsa_intermediate_TLSv1_2_p25"]='"ECDHE-ECDSA-AES256-GCM-SHA384 ECDHE-RSA-AES256-GCM-SHA384 DHE-RSA-AES256-GCM-SHA384 ECDHE-ECDSA-CHACHA20-POLY1305 ECDHE-RSA-CHACHA20-POLY1305 DHE-RSA-CHACHA20-POLY1305 ECDHE-ECDSA-AES256-CCM8 ECDHE-ECDSA-AES256-CCM DHE-RSA-AES256-CCM8 DHE-RSA-AES256-CCM ECDHE-ECDSA-ARIA256-GCM-SHA384 ECDHE-ARIA256-GCM-SHA384 DHE-RSA-ARIA256-GCM-SHA384 ECDHE-ECDSA-AES256-SHA384 ECDHE-RSA-AES256-SHA384 DHE-RSA-AES256-SHA256 ECDHE-ECDSA-AES256-SHA ECDHE-RSA-AES256-SHA DHE-RSA-AES256-SHA ARIA256-GCM-SHA384 ECDHE-ECDSA-AES128-GCM-SHA256 ECDHE-RSA-AES128-GCM-SHA256 DHE-RSA-AES128-GCM-SHA256 ECDHE-ECDSA-AES128-CCM8 ECDHE-ECDSA-AES128-CCM DHE-RSA-AES128-CCM8 DHE-RSA-AES128-CCM ECDHE-ECDSA-ARIA128-GCM-SHA256 ECDHE-ARIA128-GCM-SHA256 DHE-RSA-ARIA128-GCM-SHA256 ECDHE-ECDSA-AES128-SHA256 ECDHE-RSA-AES128-SHA256 DHE-RSA-AES128-SHA256 ECDHE-ECDSA-AES128-SHA ECDHE-RSA-AES128-SHA DHE-RSA-AES128-SHA ARIA128-GCM-SHA256"'
|
||||
CIPHER_LIST["ecdsa_rsa_modern_TLSv1_2_p25"]=${CIPHER_LIST["ecdsa_rsa_intermediate_TLSv1_2_p25"]}
|
||||
|
||||
|
||||
local TARGET_QUERY="${KEY_TYPE_LABEL}_${TLS_LEVEL}_${TLS_VERSION}"
|
||||
echo "${CIPHER_LIST[${TARGET_QUERY}]}"
|
||||
fi
|
||||
}
|
88
test/tests/serial/sedfile.bats
Normal file
88
test/tests/serial/sedfile.bats
Normal file
|
@ -0,0 +1,88 @@
|
|||
load 'test_helper/common'
|
||||
|
||||
CONTAINER='sedfile'
|
||||
TEST_FILE='/tmp/sedfile-test.txt'
|
||||
|
||||
# prepare tests
|
||||
function setup_file() {
|
||||
local PRIVATE_CONFIG
|
||||
PRIVATE_CONFIG="$(duplicate_config_for_container . )"
|
||||
|
||||
docker run -d --name "${CONTAINER}" \
|
||||
-v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \
|
||||
-h mail.my-domain.com "${NAME}"
|
||||
|
||||
wait_for_finished_setup_in_container "${CONTAINER}"
|
||||
}
|
||||
|
||||
function setup() {
|
||||
# create test file
|
||||
docker exec "${CONTAINER}" bash -c 'echo "foo bar" > "'"${TEST_FILE}"'"'
|
||||
}
|
||||
|
||||
@test "checking sedfile parameter count" {
|
||||
run docker exec "${CONTAINER}" sedfile
|
||||
assert_failure
|
||||
assert_output --partial 'At least three parameters must be given'
|
||||
}
|
||||
|
||||
@test "checking sedfile substitute success" {
|
||||
# change 'bar' to 'baz'
|
||||
run docker exec "${CONTAINER}" sedfile -i 's|bar|baz|' "${TEST_FILE}"
|
||||
assert_success
|
||||
assert_output ''
|
||||
|
||||
# file modified?
|
||||
run docker exec "${CONTAINER}" cat "${TEST_FILE}"
|
||||
assert_success
|
||||
assert_output 'foo baz'
|
||||
}
|
||||
|
||||
@test "checking sedfile substitute failure (on first container start)" {
|
||||
# delete marker
|
||||
run docker exec "${CONTAINER}" rm '/CONTAINER_START'
|
||||
assert_success
|
||||
|
||||
# try to change 'baz' to 'something' and fail
|
||||
run docker exec "${CONTAINER}" sedfile -i 's|baz|something|' "${TEST_FILE}"
|
||||
assert_failure
|
||||
assert_output --partial "No difference after call to 'sed' in 'sedfile' (sed -i s|baz|something| /tmp/sedfile-test.txt)"
|
||||
|
||||
# file unchanged?
|
||||
run docker exec "${CONTAINER}" cat "${TEST_FILE}"
|
||||
assert_success
|
||||
assert_output 'foo bar'
|
||||
|
||||
# recreate marker
|
||||
run docker exec "${CONTAINER}" touch '/CONTAINER_START'
|
||||
assert_success
|
||||
}
|
||||
|
||||
@test "checking sedfile silent failure on substitute (when DMS was restarted)" {
|
||||
# try to change 'baz' to 'something' and fail silently
|
||||
run docker exec "${CONTAINER}" sedfile -i 's|baz|something|' "${TEST_FILE}"
|
||||
assert_success
|
||||
assert_output ''
|
||||
|
||||
# file unchanged?
|
||||
run docker exec "${CONTAINER}" cat "${TEST_FILE}"
|
||||
assert_success
|
||||
assert_output 'foo bar'
|
||||
}
|
||||
|
||||
@test "checking sedfile substitude failure (strict)" {
|
||||
# try to change 'baz' to 'something' and fail
|
||||
run docker exec "${CONTAINER}" sedfile --strict -i 's|baz|something|' "${TEST_FILE}"
|
||||
assert_failure
|
||||
assert_output --partial "No difference after call to 'sed' in 'sedfile' (sed -i s|baz|something| /tmp/sedfile-test.txt)"
|
||||
|
||||
# file unchanged?
|
||||
run docker exec "${CONTAINER}" cat "${TEST_FILE}"
|
||||
assert_success
|
||||
assert_output 'foo bar'
|
||||
}
|
||||
|
||||
# clean up
|
||||
function teardown_file() {
|
||||
docker rm -f "${CONTAINER}"
|
||||
}
|
289
test/tests/serial/setup-cli.bats
Normal file
289
test/tests/serial/setup-cli.bats
Normal file
|
@ -0,0 +1,289 @@
|
|||
load 'test_helper/common'
|
||||
|
||||
# Globals referenced from `test_helper/common`:
|
||||
# TEST_NAME (should match the filename, minus the bats extension)
|
||||
|
||||
# This is a bare minimal container setup.
|
||||
# All test-cases run sequentially against the same container instance,
|
||||
# no state is reset between test-cases.
|
||||
function setup_file() {
|
||||
# Initializes common default vars to prepare a DMS container with:
|
||||
init_with_defaults
|
||||
|
||||
# Creates and starts the container with additional ENV needed:
|
||||
# `LOG_LEVEL=debug` required for using `wait_until_change_detection_event_completes()`
|
||||
# shellcheck disable=SC2034
|
||||
local CONTAINER_ARGS_ENV_CUSTOM=(
|
||||
--env LOG_LEVEL='debug'
|
||||
)
|
||||
|
||||
common_container_setup 'CONTAINER_ARGS_ENV_CUSTOM'
|
||||
}
|
||||
|
||||
function teardown_file() {
|
||||
docker rm -f "${TEST_NAME}"
|
||||
}
|
||||
|
||||
@test "checking setup.sh: show usage when no arguments provided" {
|
||||
run ./setup.sh
|
||||
assert_success
|
||||
assert_output --partial "This is the main administration script that you use for all your interactions with"
|
||||
}
|
||||
|
||||
@test "checking setup.sh: exit with error when wrong arguments provided" {
|
||||
run ./setup.sh lol troll
|
||||
assert_failure
|
||||
assert_line --index 0 --partial "The command 'lol troll' is invalid."
|
||||
}
|
||||
|
||||
# Create a new account for subsequent tests to depend upon
|
||||
@test "checking setup.sh: setup.sh email add and login" {
|
||||
local MAIL_ACCOUNT='user@example.com'
|
||||
local MAIL_PASS='test_password'
|
||||
local DATABASE_ACCOUNTS="${TEST_TMP_CONFIG}/postfix-accounts.cf"
|
||||
|
||||
# Create an account
|
||||
run ./setup.sh -c "${TEST_NAME}" email add "${MAIL_ACCOUNT}" "${MAIL_PASS}"
|
||||
assert_success
|
||||
|
||||
# Verify account was added to `postfix-accounts.cf`:
|
||||
local ACCOUNT
|
||||
ACCOUNT=$(grep "${MAIL_ACCOUNT}" "${DATABASE_ACCOUNTS}" | awk -F '|' '{print $1}')
|
||||
assert_equal "${ACCOUNT}" "${MAIL_ACCOUNT}"
|
||||
|
||||
# Wait for change detection event to complete (create maildir and add account to Dovecot UserDB+PassDB)
|
||||
wait_until_account_maildir_exists "${TEST_NAME}" "${MAIL_ACCOUNT}"
|
||||
# Dovecot is stopped briefly at the end of processing a change event (should change to reload in future),
|
||||
# to more accurately use `wait_for_service` ensure you wait until `changedetector` is done.
|
||||
wait_until_change_detection_event_completes "${TEST_NAME}"
|
||||
wait_for_service "${TEST_NAME}" dovecot
|
||||
|
||||
# Verify account authentication is successful:
|
||||
local RESPONSE
|
||||
RESPONSE=$(docker exec "${TEST_NAME}" doveadm auth test "${MAIL_ACCOUNT}" "${MAIL_PASS}" | grep 'passdb')
|
||||
assert_equal "${RESPONSE}" "passdb: ${MAIL_ACCOUNT} auth succeeded"
|
||||
}
|
||||
|
||||
@test "checking setup.sh: setup.sh email list" {
|
||||
run ./setup.sh -c "${TEST_NAME}" email list
|
||||
assert_success
|
||||
}
|
||||
|
||||
# Update an existing account
|
||||
@test "checking setup.sh: setup.sh email update" {
|
||||
local MAIL_ACCOUNT='user@example.com'
|
||||
local MAIL_PASS='test_password'
|
||||
local DATABASE_ACCOUNTS="${TEST_TMP_CONFIG}/postfix-accounts.cf"
|
||||
|
||||
# `postfix-accounts.cf` should already have an account with a non-empty hashed password:
|
||||
local MAIL_PASS_HASH
|
||||
MAIL_PASS_HASH=$(grep "${MAIL_ACCOUNT}" "${DATABASE_ACCOUNTS}" | awk -F '|' '{print $2}')
|
||||
assert_not_equal "${MAIL_PASS_HASH}" ""
|
||||
|
||||
# Update the password should be successful:
|
||||
local NEW_PASS='new_password'
|
||||
run ./setup.sh -c "${TEST_NAME}" email update "${MAIL_ACCOUNT}" "${NEW_PASS}"
|
||||
refute_output --partial 'Password must not be empty'
|
||||
assert_success
|
||||
|
||||
# NOTE: this was put in place for the next test `setup.sh email del` to properly work.
|
||||
wait_until_change_detection_event_completes "${TEST_NAME}"
|
||||
|
||||
# `postfix-accounts.cf` should have an updated password hash stored:
|
||||
local NEW_PASS_HASH
|
||||
NEW_PASS_HASH=$(grep "${MAIL_ACCOUNT}" "${DATABASE_ACCOUNTS}" | awk -F '|' '{print $2}')
|
||||
assert_not_equal "${NEW_PASS_HASH}" ""
|
||||
assert_not_equal "${NEW_PASS_HASH}" "${MAIL_PASS_HASH}"
|
||||
|
||||
# Verify Dovecot derives NEW_PASS_HASH from NEW_PASS:
|
||||
run docker exec "${TEST_NAME}" doveadm pw -t "${NEW_PASS_HASH}" -p "${NEW_PASS}"
|
||||
refute_output 'Fatal: reverse password verification check failed: Password mismatch'
|
||||
assert_output "${NEW_PASS_HASH} (verified)"
|
||||
}
|
||||
|
||||
# Delete an existing account
|
||||
# WARNING: While this feature works via the internal `setup` command, the external `setup.sh`
|
||||
# has no support to mount a volume to `/var/mail` (only via `-c` to use a running container),
|
||||
# thus the `-y` option to delete the account maildir has no effect nor informs the user.
|
||||
# https://github.com/docker-mailserver/docker-mailserver/issues/949
|
||||
@test "checking setup.sh: setup.sh email del" {
|
||||
local MAIL_ACCOUNT='user@example.com'
|
||||
local MAIL_PASS='test_password'
|
||||
|
||||
# Account deletion is successful:
|
||||
run ./setup.sh -c "${TEST_NAME}" email del -y "${MAIL_ACCOUNT}"
|
||||
assert_success
|
||||
|
||||
# NOTE: Sometimes the directory still exists, possibly from change detection
|
||||
# of the previous test (`email udpate`) triggering. Therefore, the function
|
||||
# `wait_until_change_detection_event_completes was added to the
|
||||
# `setup.sh email update` test.
|
||||
repeat_in_container_until_success_or_timeout 60 "${TEST_NAME}" bash -c '[[ ! -d /var/mail/example.com/user ]]'
|
||||
|
||||
# Account is not present in `postfix-accounts.cf`:
|
||||
run grep "${MAIL_ACCOUNT}" "${TEST_TMP_CONFIG}/postfix-accounts.cf"
|
||||
assert_failure
|
||||
|
||||
# NOTE: Actual account will still exist briefly in Dovecot UserDB+PassDB
|
||||
# until `changedetector` service is triggered by `postfix-accounts.cf`
|
||||
# which will rebuild Dovecots accounts from scratch.
|
||||
}
|
||||
|
||||
@test "checking setup.sh: setup.sh email restrict" {
|
||||
run ./setup.sh -c "${TEST_NAME}" email restrict
|
||||
assert_failure
|
||||
run ./setup.sh -c "${TEST_NAME}" email restrict add
|
||||
assert_failure
|
||||
./setup.sh -c "${TEST_NAME}" email restrict add send lorem@impsum.org
|
||||
run ./setup.sh -c "${TEST_NAME}" email restrict list send
|
||||
assert_output --regexp "^lorem@impsum.org.*REJECT"
|
||||
|
||||
run ./setup.sh -c "${TEST_NAME}" email restrict del send lorem@impsum.org
|
||||
assert_success
|
||||
run ./setup.sh -c "${TEST_NAME}" email restrict list send
|
||||
assert_output --partial "Everyone is allowed"
|
||||
|
||||
./setup.sh -c "${TEST_NAME}" email restrict add receive rec_lorem@impsum.org
|
||||
run ./setup.sh -c "${TEST_NAME}" email restrict list receive
|
||||
assert_output --regexp "^rec_lorem@impsum.org.*REJECT"
|
||||
run ./setup.sh -c "${TEST_NAME}" email restrict del receive rec_lorem@impsum.org
|
||||
assert_success
|
||||
}
|
||||
|
||||
# alias
|
||||
@test "checking setup.sh: setup.sh alias list" {
|
||||
run ./setup.sh -c "${TEST_NAME}" alias list
|
||||
assert_success
|
||||
assert_output --partial "alias1@localhost.localdomain user1@localhost.localdomain"
|
||||
assert_output --partial "@localdomain2.com user1@localhost.localdomain"
|
||||
}
|
||||
|
||||
@test "checking setup.sh: setup.sh alias add" {
|
||||
./setup.sh -c "${TEST_NAME}" alias add alias@example.com target1@forward.com
|
||||
./setup.sh -c "${TEST_NAME}" alias add alias@example.com target2@forward.com
|
||||
./setup.sh -c "${TEST_NAME}" alias add alias2@example.org target3@forward.com
|
||||
sleep 5
|
||||
run grep "alias@example.com target1@forward.com,target2@forward.com" "${TEST_TMP_CONFIG}/postfix-virtual.cf"
|
||||
assert_success
|
||||
}
|
||||
|
||||
@test "checking setup.sh: setup.sh alias del" {
|
||||
./setup.sh -c "${TEST_NAME}" alias del alias@example.com target1@forward.com
|
||||
run grep "target1@forward.com" "${TEST_TMP_CONFIG}/postfix-virtual.cf"
|
||||
assert_failure
|
||||
|
||||
run grep "target2@forward.com" "${TEST_TMP_CONFIG}/postfix-virtual.cf"
|
||||
assert_output "alias@example.com target2@forward.com"
|
||||
|
||||
./setup.sh -c "${TEST_NAME}" alias del alias@example.org target2@forward.com
|
||||
run grep "alias@example.org" "${TEST_TMP_CONFIG}/postfix-virtual.cf"
|
||||
assert_failure
|
||||
|
||||
run grep "alias2@example.org" "${TEST_TMP_CONFIG}/postfix-virtual.cf"
|
||||
assert_success
|
||||
|
||||
./setup.sh -c "${TEST_NAME}" alias del alias2@example.org target3@forward.com
|
||||
run grep "alias2@example.org" "${TEST_TMP_CONFIG}/postfix-virtual.cf"
|
||||
assert_failure
|
||||
}
|
||||
|
||||
# quota
|
||||
@test "checking setup.sh: setup.sh setquota" {
|
||||
./setup.sh -c "${TEST_NAME}" email add quota_user@example.com test_password
|
||||
./setup.sh -c "${TEST_NAME}" email add quota_user2@example.com test_password
|
||||
|
||||
run ./setup.sh -c "${TEST_NAME}" quota set quota_user@example.com 12M
|
||||
assert_success
|
||||
run ./setup.sh -c "${TEST_NAME}" quota set 51M quota_user@example.com
|
||||
assert_failure
|
||||
run ./setup.sh -c "${TEST_NAME}" quota set unknown@domain.com 150M
|
||||
assert_failure
|
||||
|
||||
run ./setup.sh -c "${TEST_NAME}" quota set quota_user2 51M
|
||||
assert_failure
|
||||
|
||||
run /bin/sh -c "cat ${TEST_TMP_CONFIG}/dovecot-quotas.cf | grep -E '^quota_user@example.com\:12M\$' | wc -l | grep 1"
|
||||
assert_success
|
||||
|
||||
run ./setup.sh -c "${TEST_NAME}" quota set quota_user@example.com 26M
|
||||
assert_success
|
||||
run /bin/sh -c "cat ${TEST_TMP_CONFIG}/dovecot-quotas.cf | grep -E '^quota_user@example.com\:26M\$' | wc -l | grep 1"
|
||||
assert_success
|
||||
|
||||
run grep "quota_user2@example.com" "${TEST_TMP_CONFIG}/dovecot-quotas.cf"
|
||||
assert_failure
|
||||
}
|
||||
|
||||
# `quota_user@example.com` created in previous `setquota` test
|
||||
@test "checking setup.sh: setup.sh delquota" {
|
||||
run ./setup.sh -c "${TEST_NAME}" quota set quota_user@example.com 12M
|
||||
assert_success
|
||||
run /bin/sh -c "cat ${TEST_TMP_CONFIG}/dovecot-quotas.cf | grep -E '^quota_user@example.com\:12M\$' | wc -l | grep 1"
|
||||
assert_success
|
||||
|
||||
run ./setup.sh -c "${TEST_NAME}" quota del unknown@domain.com
|
||||
assert_failure
|
||||
run /bin/sh -c "cat ${TEST_TMP_CONFIG}/dovecot-quotas.cf | grep -E '^quota_user@example.com\:12M\$' | wc -l | grep 1"
|
||||
assert_success
|
||||
|
||||
run ./setup.sh -c "${TEST_NAME}" quota del quota_user@example.com
|
||||
assert_success
|
||||
run grep "quota_user@example.com" "${TEST_TMP_CONFIG}/dovecot-quotas.cf"
|
||||
assert_failure
|
||||
}
|
||||
|
||||
@test "checking setup.sh: setup.sh config dkim help correctly displayed" {
|
||||
run ./setup.sh -c "${TEST_NAME}" config dkim help
|
||||
assert_success
|
||||
assert_line --index 3 --partial " open-dkim - configure DomainKeys Identified Mail (DKIM)"
|
||||
}
|
||||
|
||||
# debug
|
||||
|
||||
@test "checking setup.sh: setup.sh debug fetchmail" {
|
||||
run ./setup.sh -c "${TEST_NAME}" debug fetchmail
|
||||
assert_failure
|
||||
assert_output --partial "fetchmail: normal termination, status 11"
|
||||
}
|
||||
|
||||
@test "checking setup.sh: setup.sh debug login ls" {
|
||||
run ./setup.sh -c "${TEST_NAME}" debug login ls
|
||||
assert_success
|
||||
}
|
||||
|
||||
@test "checking setup.sh: setup.sh relay add-domain" {
|
||||
./setup.sh -c "${TEST_NAME}" relay add-domain example1.org smtp.relay1.com 2525
|
||||
./setup.sh -c "${TEST_NAME}" relay add-domain example2.org smtp.relay2.com
|
||||
./setup.sh -c "${TEST_NAME}" relay add-domain example3.org smtp.relay3.com 2525
|
||||
./setup.sh -c "${TEST_NAME}" relay add-domain example3.org smtp.relay.com 587
|
||||
|
||||
# check adding
|
||||
run /bin/sh -c "cat ${TEST_TMP_CONFIG}/postfix-relaymap.cf | grep -e '^@example1.org\s\+\[smtp.relay1.com\]:2525' | wc -l | grep 1"
|
||||
assert_success
|
||||
# test default port
|
||||
run /bin/sh -c "cat ${TEST_TMP_CONFIG}/postfix-relaymap.cf | grep -e '^@example2.org\s\+\[smtp.relay2.com\]:25' | wc -l | grep 1"
|
||||
assert_success
|
||||
# test modifying
|
||||
run /bin/sh -c "cat ${TEST_TMP_CONFIG}/postfix-relaymap.cf | grep -e '^@example3.org\s\+\[smtp.relay.com\]:587' | wc -l | grep 1"
|
||||
assert_success
|
||||
}
|
||||
|
||||
@test "checking setup.sh: setup.sh relay add-auth" {
|
||||
./setup.sh -c "${TEST_NAME}" relay add-auth example.org smtp_user smtp_pass
|
||||
./setup.sh -c "${TEST_NAME}" relay add-auth example2.org smtp_user2 smtp_pass2
|
||||
./setup.sh -c "${TEST_NAME}" relay add-auth example2.org smtp_user2 smtp_pass_new
|
||||
|
||||
# test adding
|
||||
run /bin/sh -c "cat ${TEST_TMP_CONFIG}/postfix-sasl-password.cf | grep -e '^@example.org\s\+smtp_user:smtp_pass' | wc -l | grep 1"
|
||||
assert_success
|
||||
# test updating
|
||||
run /bin/sh -c "cat ${TEST_TMP_CONFIG}/postfix-sasl-password.cf | grep -e '^@example2.org\s\+smtp_user2:smtp_pass_new' | wc -l | grep 1"
|
||||
assert_success
|
||||
}
|
||||
|
||||
@test "checking setup.sh: setup.sh relay exclude-domain" {
|
||||
./setup.sh -c "${TEST_NAME}" relay exclude-domain example.org
|
||||
|
||||
run /bin/sh -c "cat ${TEST_TMP_CONFIG}/postfix-relaymap.cf | grep -e '^@example.org\s*$' | wc -l | grep 1"
|
||||
assert_success
|
||||
}
|
271
test/tests/serial/test_helper.bats
Normal file
271
test/tests/serial/test_helper.bats
Normal file
|
@ -0,0 +1,271 @@
|
|||
load 'test_helper/bats-support/load'
|
||||
load 'test_helper/bats-assert/load'
|
||||
load 'test_helper/common'
|
||||
|
||||
@test "repeat_until_success_or_timeout returns instantly on success" {
|
||||
SECONDS=0
|
||||
repeat_until_success_or_timeout 1 true
|
||||
[[ ${SECONDS} -le 1 ]]
|
||||
}
|
||||
|
||||
@test "repeat_until_success_or_timeout waits for timeout on persistent failure" {
|
||||
SECONDS=0
|
||||
run repeat_until_success_or_timeout 2 false
|
||||
[[ ${SECONDS} -ge 2 ]]
|
||||
assert_failure
|
||||
assert_output --partial "Timed out on command"
|
||||
}
|
||||
|
||||
@test "repeat_until_success_or_timeout aborts immediately on fatal failure" {
|
||||
SECONDS=0
|
||||
run repeat_until_success_or_timeout --fatal-test false 2 false
|
||||
[[ ${SECONDS} -le 1 ]]
|
||||
assert_failure
|
||||
assert_output --partial "early aborting"
|
||||
}
|
||||
|
||||
@test "repeat_until_success_or_timeout expects integer timeout" {
|
||||
run repeat_until_success_or_timeout 1 true
|
||||
assert_success
|
||||
|
||||
run repeat_until_success_or_timeout timeout true
|
||||
assert_failure
|
||||
|
||||
run repeat_until_success_or_timeout --fatal-test true timeout true
|
||||
assert_failure
|
||||
}
|
||||
|
||||
@test "run_until_success_or_timeout returns instantly on success" {
|
||||
SECONDS=0
|
||||
run_until_success_or_timeout 2 true
|
||||
[[ ${SECONDS} -le 1 ]]
|
||||
assert_success
|
||||
}
|
||||
|
||||
@test "run_until_success_or_timeout waits for timeout on persistent failure" {
|
||||
SECONDS=0
|
||||
! run_until_success_or_timeout 2 false
|
||||
[[ ${SECONDS} -ge 2 ]]
|
||||
assert_failure
|
||||
}
|
||||
|
||||
@test "repeat_in_container_until_success_or_timeout fails immediately for non-running container" {
|
||||
SECONDS=0
|
||||
! repeat_in_container_until_success_or_timeout 10 name-of-non-existing-container true
|
||||
[[ ${SECONDS} -le 1 ]]
|
||||
}
|
||||
|
||||
@test "repeat_in_container_until_success_or_timeout run command in container" {
|
||||
local CONTAINER_NAME
|
||||
CONTAINER_NAME=$(docker run --rm -d alpine sleep 100)
|
||||
SECONDS=0
|
||||
! repeat_in_container_until_success_or_timeout 10 "${CONTAINER_NAME}" sh -c "echo '${CONTAINER_NAME}' > /tmp/marker"
|
||||
[[ ${SECONDS} -le 1 ]]
|
||||
run docker exec "${CONTAINER_NAME}" cat /tmp/marker
|
||||
assert_output "${CONTAINER_NAME}"
|
||||
}
|
||||
|
||||
@test "container_is_running" {
|
||||
local CONTAINER_NAME
|
||||
CONTAINER_NAME=$(docker run --rm -d alpine sleep 100)
|
||||
container_is_running "${CONTAINER_NAME}"
|
||||
docker rm -f "${CONTAINER_NAME}"
|
||||
! container_is_running "${CONTAINER_NAME}"
|
||||
}
|
||||
|
||||
@test "wait_for_smtp_port_in_container aborts wait after timeout" {
|
||||
local CONTAINER_NAME
|
||||
CONTAINER_NAME=$(docker run --rm -d alpine sleep 100)
|
||||
SECONDS=0
|
||||
TEST_TIMEOUT_IN_SECONDS=2 run wait_for_smtp_port_in_container "${CONTAINER_NAME}"
|
||||
[[ ${SECONDS} -ge 2 ]]
|
||||
assert_failure
|
||||
assert_output --partial "Timed out on command"
|
||||
}
|
||||
|
||||
# NOTE: Test requires external network access available
|
||||
@test "wait_for_smtp_port_in_container returns immediately when port found" {
|
||||
local CONTAINER_NAME
|
||||
CONTAINER_NAME=$(docker run --rm -d alpine sh -c "sleep 10")
|
||||
|
||||
docker exec "${CONTAINER_NAME}" apk add netcat-openbsd
|
||||
docker exec "${CONTAINER_NAME}" nc -l 25 &
|
||||
|
||||
SECONDS=0
|
||||
TEST_TIMEOUT_IN_SECONDS=5 run wait_for_smtp_port_in_container "${CONTAINER_NAME}"
|
||||
[[ ${SECONDS} -lt 5 ]]
|
||||
assert_success
|
||||
}
|
||||
|
||||
@test "wait_for_finished_setup_in_container" {
|
||||
# variable not local to make visible to teardown
|
||||
local PRIVATE_CONFIG
|
||||
PRIVATE_CONFIG=$(duplicate_config_for_container .)
|
||||
|
||||
CONTAINER_NAME=$(docker run -d --rm \
|
||||
-v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \
|
||||
-h mail.my-domain.com \
|
||||
-t "${NAME}")
|
||||
|
||||
teardown() { docker rm -f "${CONTAINER_NAME}"; }
|
||||
|
||||
# the setup should not be finished immediately after starting
|
||||
! TEST_TIMEOUT_IN_SECONDS=0 wait_for_finished_setup_in_container "${CONTAINER_NAME}"
|
||||
|
||||
# but it will finish eventually
|
||||
SECONDS=1
|
||||
|
||||
wait_for_finished_setup_in_container "${CONTAINER_NAME}"
|
||||
[[ ${SECONDS} -gt 0 ]]
|
||||
}
|
||||
|
||||
@test "duplicate_config_for_container" {
|
||||
local path
|
||||
path=$(duplicate_config_for_container duplicate_config_test)
|
||||
|
||||
run cat "${path}/marker"
|
||||
assert_line "This marker file is there to identify the correct config being copied"
|
||||
|
||||
run duplicate_config_for_container non-existant-source-folder "${BATS_TEST_NAME}2"
|
||||
assert_failure
|
||||
}
|
||||
|
||||
@test "container_has_service_running/wait_for_service" {
|
||||
local PRIVATE_CONFIG
|
||||
PRIVATE_CONFIG=$(duplicate_config_for_container .)
|
||||
|
||||
# variable not local to make visible to teardown
|
||||
CONTAINER_NAME=$(docker run -d --rm \
|
||||
-v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \
|
||||
-h mail.my-domain.com \
|
||||
-t "${NAME}")
|
||||
|
||||
teardown() { docker rm -f "${CONTAINER_NAME}"; }
|
||||
|
||||
# pick a service that was not started
|
||||
! container_has_service_running "${CONTAINER_NAME}" clamav
|
||||
|
||||
# wait for a service that should be started
|
||||
wait_for_service "${CONTAINER_NAME}" postfix
|
||||
|
||||
# shut down the service
|
||||
docker exec "${CONTAINER_NAME}" supervisorctl stop postfix
|
||||
|
||||
# now it should be off
|
||||
SECONDS=0
|
||||
TEST_TIMEOUT_IN_SECONDS=5 run wait_for_service "${CONTAINER_NAME}" postfix
|
||||
[[ ${SECONDS} -ge 5 ]]
|
||||
assert_failure
|
||||
}
|
||||
|
||||
@test "wait_for_changes_to_be_detected_in_container fails when timeout is reached" {
|
||||
local PRIVATE_CONFIG
|
||||
PRIVATE_CONFIG=$(duplicate_config_for_container .)
|
||||
|
||||
# variable not local to make visible to teardown
|
||||
CONTAINER_NAME=$(docker run -d --rm \
|
||||
-v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \
|
||||
-h mail.my-domain.com \
|
||||
-t "${NAME}")
|
||||
|
||||
teardown() { docker rm -f "${CONTAINER_NAME}"; }
|
||||
|
||||
# wait for the initial checksum file to be created
|
||||
# shellcheck disable=SC2016
|
||||
repeat_in_container_until_success_or_timeout 60 "${CONTAINER_NAME}" bash -c 'source /usr/local/bin/helpers/index.sh; test -e "${CHKSUM_FILE}"'
|
||||
|
||||
# there should be no changes in the beginning
|
||||
TEST_TIMEOUT_IN_SECONDS=0 wait_for_changes_to_be_detected_in_container "${CONTAINER_NAME}"
|
||||
|
||||
# trigger some change
|
||||
docker exec "${CONTAINER_NAME}" /bin/sh -c "addmailuser auser3@mail.my-domain.com mypassword"
|
||||
|
||||
# that should be picked up as not yet detected
|
||||
! TEST_TIMEOUT_IN_SECONDS=0 wait_for_changes_to_be_detected_in_container "${CONTAINER_NAME}"
|
||||
}
|
||||
|
||||
@test "wait_for_changes_to_be_detected_in_container succeeds within timeout" {
|
||||
local PRIVATE_CONFIG
|
||||
PRIVATE_CONFIG=$(duplicate_config_for_container .)
|
||||
|
||||
# variable not local to make visible to teardown
|
||||
CONTAINER_NAME=$(docker run -d --rm \
|
||||
-v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \
|
||||
-h mail.my-domain.com \
|
||||
-t "${NAME}")
|
||||
|
||||
teardown() { docker rm -f "${CONTAINER_NAME}"; }
|
||||
|
||||
# wait for the initial checksum file to be created
|
||||
# shellcheck disable=SC2016
|
||||
repeat_in_container_until_success_or_timeout 60 "${CONTAINER_NAME}" bash -c 'source /usr/local/bin/helpers/index.sh; test -e "${CHKSUM_FILE}"'
|
||||
|
||||
# trigger some change
|
||||
docker exec "${CONTAINER_NAME}" /bin/sh -c "addmailuser auser3@mail.my-domain.com mypassword"
|
||||
|
||||
# that should eventually be detected
|
||||
SECONDS=0
|
||||
wait_for_changes_to_be_detected_in_container "${CONTAINER_NAME}"
|
||||
[[ ${SECONDS} -gt 0 ]]
|
||||
}
|
||||
|
||||
# TODO investigate why this test fails
|
||||
@test "wait_for_empty_mail_queue_in_container fails when timeout reached" {
|
||||
skip 'disabled as it fails randomly: https://github.com/docker-mailserver/docker-mailserver/pull/2177'
|
||||
|
||||
local PRIVATE_CONFIG
|
||||
PRIVATE_CONFIG=$(duplicate_config_for_container .)
|
||||
|
||||
# variable not local to make visible to teardown
|
||||
# enable ClamAV to make message delivery slower, so we can detect it
|
||||
CONTAINER_NAME=$(docker run -d --rm \
|
||||
-v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \
|
||||
-v "$(pwd)/test/test-files":/tmp/docker-mailserver-test:ro \
|
||||
-e ENABLE_CLAMAV=1 \
|
||||
-h mail.my-domain.com \
|
||||
-t "${NAME}")
|
||||
|
||||
teardown() { docker rm -f "${CONTAINER_NAME}"; }
|
||||
|
||||
wait_for_smtp_port_in_container "${CONTAINER_NAME}" || docker logs "${CONTAINER_NAME}"
|
||||
|
||||
SECONDS=0
|
||||
# no mails -> should return immediately
|
||||
TEST_TIMEOUT_IN_SECONDS=5 wait_for_empty_mail_queue_in_container "${CONTAINER_NAME}"
|
||||
[[ ${SECONDS} -lt 5 ]]
|
||||
|
||||
# fill the queue with a message
|
||||
docker exec "${CONTAINER_NAME}" /bin/sh -c "nc 0.0.0.0 25 < /tmp/docker-mailserver-test/email-templates/amavis-virus.txt"
|
||||
|
||||
# that should still be stuck in the queue
|
||||
! TEST_TIMEOUT_IN_SECONDS=0 wait_for_empty_mail_queue_in_container "${CONTAINER_NAME}"
|
||||
}
|
||||
|
||||
# TODO investigate why this test fails
|
||||
@test "wait_for_empty_mail_queue_in_container succeeds within timeout" {
|
||||
skip 'disabled as it fails randomly: https://github.com/docker-mailserver/docker-mailserver/pull/2177'
|
||||
|
||||
local PRIVATE_CONFIG
|
||||
PRIVATE_CONFIG=$(duplicate_config_for_container .)
|
||||
|
||||
# variable not local to make visible to teardown
|
||||
# enable ClamAV to make message delivery slower, so we can detect it
|
||||
CONTAINER_NAME=$(docker run -d --rm \
|
||||
-v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \
|
||||
-v "$(pwd)/test/test-files":/tmp/docker-mailserver-test:ro \
|
||||
-e ENABLE_CLAMAV=1 \
|
||||
-h mail.my-domain.com \
|
||||
-t "${NAME}")
|
||||
|
||||
teardown() { docker rm -f "${CONTAINER_NAME}"; }
|
||||
|
||||
wait_for_smtp_port_in_container "${CONTAINER_NAME}" || docker logs "${CONTAINER_NAME}"
|
||||
|
||||
# fill the queue with a message
|
||||
docker exec "${CONTAINER_NAME}" /bin/sh -c "nc 0.0.0.0 25 < /tmp/docker-mailserver-test/email-templates/amavis-virus.txt"
|
||||
|
||||
# give it some time to clear the queue
|
||||
SECONDS=0
|
||||
wait_for_empty_mail_queue_in_container "${CONTAINER_NAME}"
|
||||
[[ ${SECONDS} -gt 0 ]]
|
||||
}
|
982
test/tests/serial/tests.bats
Normal file
982
test/tests/serial/tests.bats
Normal file
|
@ -0,0 +1,982 @@
|
|||
load 'test_helper/common'
|
||||
|
||||
setup_file() {
|
||||
local PRIVATE_CONFIG
|
||||
PRIVATE_CONFIG=$(duplicate_config_for_container . mail)
|
||||
mv "${PRIVATE_CONFIG}/user-patches/user-patches.sh" "${PRIVATE_CONFIG}/user-patches.sh"
|
||||
|
||||
# `LOG_LEVEL=debug` required for using `wait_until_change_detection_event_completes()`
|
||||
docker run --rm -d --name mail \
|
||||
-v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \
|
||||
-v "$(pwd)/test/test-files":/tmp/docker-mailserver-test:ro \
|
||||
-v "$(pwd)/test/onedir":/var/mail-state \
|
||||
-e AMAVIS_LOGLEVEL=2 \
|
||||
-e CLAMAV_MESSAGE_SIZE_LIMIT=30M \
|
||||
-e ENABLE_CLAMAV=0 \
|
||||
-e ENABLE_MANAGESIEVE=1 \
|
||||
-e ENABLE_QUOTAS=1 \
|
||||
-e ENABLE_SPAMASSASSIN=1 \
|
||||
-e ENABLE_SRS=1 \
|
||||
-e ENABLE_UPDATE_CHECK=0 \
|
||||
-e LOG_LEVEL='debug' \
|
||||
-e PERMIT_DOCKER=host \
|
||||
-e PFLOGSUMM_TRIGGER=logrotate \
|
||||
-e REPORT_RECIPIENT=user1@localhost.localdomain \
|
||||
-e REPORT_SENDER=report1@mail.my-domain.com \
|
||||
-e SA_KILL=3.0 \
|
||||
-e SA_SPAM_SUBJECT="SPAM: " \
|
||||
-e SA_TAG=-5.0 \
|
||||
-e SA_TAG2=2.0 \
|
||||
-e SPAMASSASSIN_SPAM_TO_INBOX=0 \
|
||||
-e SPOOF_PROTECTION=1 \
|
||||
-e SSL_TYPE='snakeoil' \
|
||||
-e VIRUSMAILS_DELETE_DELAY=7 \
|
||||
--hostname mail.my-domain.com \
|
||||
--tty \
|
||||
--ulimit "nofile=$(ulimit -Sn):$(ulimit -Hn)" \
|
||||
--health-cmd "ss --listening --tcp | grep -P 'LISTEN.+:smtp' || exit 1" \
|
||||
"${NAME}"
|
||||
|
||||
wait_for_finished_setup_in_container mail
|
||||
|
||||
# generate accounts after container has been started
|
||||
docker exec mail setup email add 'added@localhost.localdomain' 'mypassword'
|
||||
docker exec mail setup email add 'pass@localhost.localdomain' 'may be \a `p^a.*ssword'
|
||||
|
||||
# setup sieve
|
||||
docker cp "${PRIVATE_CONFIG}/sieve/dovecot.sieve" mail:/var/mail/localhost.localdomain/user1/.dovecot.sieve
|
||||
|
||||
# this relies on the checksum file being updated after all changes have been applied
|
||||
wait_until_change_detection_event_completes mail
|
||||
wait_for_service mail postfix
|
||||
wait_for_smtp_port_in_container mail
|
||||
|
||||
# The first mail sent leverages an assert for better error output if a failure occurs:
|
||||
run docker exec mail /bin/sh -c "nc 0.0.0.0 25 < /tmp/docker-mailserver-test/email-templates/amavis-spam.txt"
|
||||
assert_success
|
||||
|
||||
docker exec mail /bin/sh -c "nc 0.0.0.0 25 < /tmp/docker-mailserver-test/email-templates/existing-alias-external.txt"
|
||||
docker exec mail /bin/sh -c "nc 0.0.0.0 25 < /tmp/docker-mailserver-test/email-templates/existing-alias-local.txt"
|
||||
docker exec mail /bin/sh -c "nc 0.0.0.0 25 < /tmp/docker-mailserver-test/email-templates/existing-alias-recipient-delimiter.txt"
|
||||
docker exec mail /bin/sh -c "nc 0.0.0.0 25 < /tmp/docker-mailserver-test/email-templates/existing-user1.txt"
|
||||
docker exec mail /bin/sh -c "nc 0.0.0.0 25 < /tmp/docker-mailserver-test/email-templates/existing-user2.txt"
|
||||
docker exec mail /bin/sh -c "nc 0.0.0.0 25 < /tmp/docker-mailserver-test/email-templates/existing-user3.txt"
|
||||
docker exec mail /bin/sh -c "nc 0.0.0.0 25 < /tmp/docker-mailserver-test/email-templates/existing-added.txt"
|
||||
docker exec mail /bin/sh -c "nc 0.0.0.0 25 < /tmp/docker-mailserver-test/email-templates/existing-user-and-cc-local-alias.txt"
|
||||
docker exec mail /bin/sh -c "nc 0.0.0.0 25 < /tmp/docker-mailserver-test/email-templates/existing-regexp-alias-external.txt"
|
||||
docker exec mail /bin/sh -c "nc 0.0.0.0 25 < /tmp/docker-mailserver-test/email-templates/existing-regexp-alias-local.txt"
|
||||
docker exec mail /bin/sh -c "nc 0.0.0.0 25 < /tmp/docker-mailserver-test/email-templates/existing-catchall-local.txt"
|
||||
docker exec mail /bin/sh -c "nc 0.0.0.0 25 < /tmp/docker-mailserver-test/email-templates/sieve-spam-folder.txt"
|
||||
docker exec mail /bin/sh -c "nc 0.0.0.0 25 < /tmp/docker-mailserver-test/email-templates/sieve-pipe.txt"
|
||||
docker exec mail /bin/sh -c "nc 0.0.0.0 25 < /tmp/docker-mailserver-test/email-templates/non-existing-user.txt"
|
||||
docker exec mail /bin/sh -c "sendmail root < /tmp/docker-mailserver-test/email-templates/root-email.txt"
|
||||
|
||||
wait_for_empty_mail_queue_in_container mail
|
||||
}
|
||||
|
||||
teardown_file() {
|
||||
docker rm -f mail
|
||||
}
|
||||
|
||||
#
|
||||
# configuration checks
|
||||
#
|
||||
|
||||
@test "checking configuration: user-patches.sh executed" {
|
||||
run docker logs mail
|
||||
assert_output --partial "Default user-patches.sh successfully executed"
|
||||
}
|
||||
|
||||
@test "checking configuration: hostname/domainname" {
|
||||
run docker run "${IMAGE_NAME:?}"
|
||||
assert_success
|
||||
}
|
||||
|
||||
#
|
||||
# healthcheck
|
||||
#
|
||||
|
||||
# NOTE: Healthcheck defaults an interval of 30 seconds
|
||||
# If Postfix is temporarily down (eg: restart triggered by `check-for-changes.sh`),
|
||||
# it may result in a false-positive `unhealthy` state.
|
||||
# Be careful with re-locating this test if earlier tests could potentially fail it by
|
||||
# triggering the `changedetector` service.
|
||||
@test "checking container healthcheck" {
|
||||
# ensure, that at least 30 seconds have passed since container start
|
||||
while [[ "$(docker inspect --format='{{.State.Health.Status}}' mail)" == "starting" ]]; do
|
||||
sleep 1
|
||||
done
|
||||
run docker inspect --format='{{.State.Health.Status}}' mail
|
||||
assert_output "healthy"
|
||||
assert_success
|
||||
}
|
||||
|
||||
#
|
||||
# processes
|
||||
#
|
||||
|
||||
@test "checking process: postfix" {
|
||||
run docker exec mail /bin/bash -c "ps aux --forest | grep -v grep | grep '/usr/lib/postfix/sbin/master'"
|
||||
assert_success
|
||||
}
|
||||
|
||||
@test "checking process: clamd (is not runnning)" {
|
||||
run docker exec mail /bin/bash -c "ps aux --forest | grep -v grep | grep '/usr/sbin/clamd'"
|
||||
assert_failure
|
||||
}
|
||||
|
||||
@test "checking process: new" {
|
||||
run docker exec mail /bin/bash -c "ps aux --forest | grep -v grep | grep '/usr/sbin/amavisd-new'"
|
||||
assert_success
|
||||
}
|
||||
|
||||
@test "checking process: opendkim" {
|
||||
run docker exec mail /bin/bash -c "ps aux --forest | grep -v grep | grep '/usr/sbin/opendkim'"
|
||||
assert_success
|
||||
}
|
||||
|
||||
@test "checking process: opendmarc" {
|
||||
run docker exec mail /bin/bash -c "ps aux --forest | grep -v grep | grep '/usr/sbin/opendmarc'"
|
||||
assert_success
|
||||
}
|
||||
|
||||
@test "checking process: fail2ban (disabled in default configuration)" {
|
||||
run docker exec mail /bin/bash -c "ps aux --forest | grep -v grep | grep '/usr/bin/python3 /usr/bin/fail2ban-server'"
|
||||
assert_failure
|
||||
}
|
||||
|
||||
@test "checking process: fetchmail (disabled in default configuration)" {
|
||||
run docker exec mail /bin/bash -c "ps aux --forest | grep -v grep | grep '/usr/bin/fetchmail'"
|
||||
assert_failure
|
||||
}
|
||||
|
||||
#
|
||||
# imap
|
||||
#
|
||||
|
||||
@test "checking process: dovecot imaplogin (enabled in default configuration)" {
|
||||
run docker exec mail /bin/bash -c "ps aux --forest | grep -v grep | grep '/usr/sbin/dovecot'"
|
||||
assert_success
|
||||
}
|
||||
|
||||
@test "checking imap: server is ready with STARTTLS" {
|
||||
run docker exec mail /bin/bash -c "nc -w 2 0.0.0.0 143 | grep '* OK' | grep 'STARTTLS' | grep 'ready'"
|
||||
assert_success
|
||||
}
|
||||
|
||||
@test "checking imap: authentication works" {
|
||||
run docker exec mail /bin/sh -c "nc -w 1 0.0.0.0 143 < /tmp/docker-mailserver-test/auth/imap-auth.txt"
|
||||
assert_success
|
||||
}
|
||||
|
||||
@test "checking imap: added user authentication works" {
|
||||
run docker exec mail /bin/sh -c "nc -w 1 0.0.0.0 143 < /tmp/docker-mailserver-test/auth/added-imap-auth.txt"
|
||||
assert_success
|
||||
}
|
||||
|
||||
#
|
||||
# sasl
|
||||
#
|
||||
|
||||
@test "checking sasl: doveadm auth test works with good password" {
|
||||
run docker exec mail /bin/sh -c "doveadm auth test -x service=smtp user2@otherdomain.tld mypassword | grep 'auth succeeded'"
|
||||
assert_success
|
||||
}
|
||||
|
||||
@test "checking sasl: doveadm auth test fails with bad password" {
|
||||
run docker exec mail /bin/sh -c "doveadm auth test -x service=smtp user2@otherdomain.tld BADPASSWORD | grep 'auth failed'"
|
||||
assert_success
|
||||
}
|
||||
|
||||
#
|
||||
# logs
|
||||
#
|
||||
|
||||
@test "checking logs: mail related logs should be located in a subdirectory" {
|
||||
run docker exec mail /bin/sh -c "ls -1 /var/log/mail/ | grep -E 'mail.log'"
|
||||
assert_success
|
||||
}
|
||||
|
||||
#
|
||||
# smtp
|
||||
#
|
||||
|
||||
@test "checking smtp: authentication works with good password (plain)" {
|
||||
run docker exec mail /bin/sh -c "nc -w 5 0.0.0.0 25 < /tmp/docker-mailserver-test/auth/smtp-auth-plain.txt | grep 'Authentication successful'"
|
||||
assert_success
|
||||
}
|
||||
|
||||
@test "checking smtp: authentication fails with wrong password (plain)" {
|
||||
run docker exec mail /bin/sh -c "nc -w 20 0.0.0.0 25 < /tmp/docker-mailserver-test/auth/smtp-auth-plain-wrong.txt"
|
||||
assert_output --partial 'authentication failed'
|
||||
assert_success
|
||||
}
|
||||
|
||||
@test "checking smtp: authentication works with good password (login)" {
|
||||
run docker exec mail /bin/sh -c "nc -w 5 0.0.0.0 25 < /tmp/docker-mailserver-test/auth/smtp-auth-login.txt | grep 'Authentication successful'"
|
||||
assert_success
|
||||
}
|
||||
|
||||
@test "checking smtp: authentication fails with wrong password (login)" {
|
||||
run docker exec mail /bin/sh -c "nc -w 20 0.0.0.0 25 < /tmp/docker-mailserver-test/auth/smtp-auth-login-wrong.txt"
|
||||
assert_output --partial 'authentication failed'
|
||||
assert_success
|
||||
}
|
||||
|
||||
@test "checking smtp: added user authentication works with good password (plain)" {
|
||||
run docker exec mail /bin/sh -c "nc -w 5 0.0.0.0 25 < /tmp/docker-mailserver-test/auth/added-smtp-auth-plain.txt | grep 'Authentication successful'"
|
||||
assert_success
|
||||
}
|
||||
|
||||
@test "checking smtp: added user authentication fails with wrong password (plain)" {
|
||||
run docker exec mail /bin/sh -c "nc -w 20 0.0.0.0 25 < /tmp/docker-mailserver-test/auth/added-smtp-auth-plain-wrong.txt | grep 'authentication failed'"
|
||||
assert_success
|
||||
}
|
||||
|
||||
@test "checking smtp: added user authentication works with good password (login)" {
|
||||
run docker exec mail /bin/sh -c "nc -w 5 0.0.0.0 25 < /tmp/docker-mailserver-test/auth/added-smtp-auth-login.txt | grep 'Authentication successful'"
|
||||
assert_success
|
||||
}
|
||||
|
||||
@test "checking smtp: added user authentication fails with wrong password (login)" {
|
||||
run docker exec mail /bin/sh -c "nc -w 20 0.0.0.0 25 < /tmp/docker-mailserver-test/auth/added-smtp-auth-login-wrong.txt | grep 'authentication failed'"
|
||||
assert_success
|
||||
}
|
||||
|
||||
# TODO add a test covering case SPAMASSASSIN_SPAM_TO_INBOX=1 (default)
|
||||
@test "checking smtp: delivers mail to existing account" {
|
||||
run docker exec mail /bin/sh -c "grep 'postfix/lmtp' /var/log/mail/mail.log | grep 'status=sent' | grep ' Saved)' | sed 's/.* to=</</g' | sed 's/, relay.*//g' | sort | uniq -c | tr -s \" \""
|
||||
assert_success
|
||||
assert_output <<'EOF'
|
||||
1 <added@localhost.localdomain>
|
||||
6 <user1@localhost.localdomain>
|
||||
1 <user1@localhost.localdomain>, orig_to=<postmaster@my-domain.com>
|
||||
1 <user1@localhost.localdomain>, orig_to=<root>
|
||||
1 <user1~test@localhost.localdomain>
|
||||
2 <user2@otherdomain.tld>
|
||||
1 <user3@localhost.localdomain>
|
||||
EOF
|
||||
}
|
||||
|
||||
@test "checking smtp: delivers mail to existing alias" {
|
||||
run docker exec mail /bin/sh -c "grep 'to=<user1@localhost.localdomain>, orig_to=<alias1@localhost.localdomain>' /var/log/mail/mail.log | grep 'status=sent' | wc -l"
|
||||
assert_success
|
||||
assert_output 1
|
||||
}
|
||||
|
||||
@test "checking smtp: delivers mail to existing alias with recipient delimiter" {
|
||||
run docker exec mail /bin/sh -c "grep 'to=<user1~test@localhost.localdomain>, orig_to=<alias1~test@localhost.localdomain>' /var/log/mail/mail.log | grep 'status=sent' | wc -l"
|
||||
assert_success
|
||||
assert_output 1
|
||||
|
||||
run docker exec mail /bin/sh -c "grep 'to=<user1~test@localhost.localdomain>' /var/log/mail/mail.log | grep 'status=bounced'"
|
||||
assert_failure
|
||||
}
|
||||
|
||||
@test "checking smtp: delivers mail to existing catchall" {
|
||||
run docker exec mail /bin/sh -c "grep 'to=<user1@localhost.localdomain>, orig_to=<wildcard@localdomain2.com>' /var/log/mail/mail.log | grep 'status=sent' | wc -l"
|
||||
assert_success
|
||||
assert_output 1
|
||||
}
|
||||
|
||||
@test "checking smtp: delivers mail to regexp alias" {
|
||||
run docker exec mail /bin/sh -c "grep 'to=<user1@localhost.localdomain>, orig_to=<test123@localhost.localdomain>' /var/log/mail/mail.log | grep 'status=sent' | wc -l"
|
||||
assert_success
|
||||
assert_output 1
|
||||
}
|
||||
|
||||
@test "checking smtp: user1 should have received 9 mails" {
|
||||
run docker exec mail /bin/sh -c "grep Subject /var/mail/localhost.localdomain/user1/new/* | sed 's/.*Subject: //g' | sed 's/\.txt.*//g' | sed 's/VIRUS.*/VIRUS/g' | sort"
|
||||
assert_success
|
||||
# 9 messages, the virus mail has three subject lines
|
||||
cat <<'EOF' | assert_output
|
||||
Root Test Message
|
||||
Test Message amavis-virus
|
||||
Test Message amavis-virus
|
||||
Test Message existing-alias-external
|
||||
Test Message existing-alias-recipient-delimiter
|
||||
Test Message existing-catchall-local
|
||||
Test Message existing-regexp-alias-local
|
||||
Test Message existing-user-and-cc-local-alias
|
||||
Test Message existing-user1
|
||||
Test Message sieve-spam-folder
|
||||
VIRUS
|
||||
EOF
|
||||
}
|
||||
|
||||
@test "checking smtp: rejects mail to unknown user" {
|
||||
run docker exec mail /bin/sh -c "grep '<nouser@localhost.localdomain>: Recipient address rejected: User unknown in virtual mailbox table' /var/log/mail/mail.log | wc -l"
|
||||
assert_success
|
||||
assert_output 1
|
||||
}
|
||||
|
||||
@test "checking smtp: redirects mail to external aliases" {
|
||||
run docker exec mail /bin/sh -c "grep -- '-> <external1@otherdomain.tld>' /var/log/mail/mail.log* | grep RelayedInbound | wc -l"
|
||||
assert_success
|
||||
assert_output 2
|
||||
}
|
||||
|
||||
# TODO add a test covering case SPAMASSASSIN_SPAM_TO_INBOX=1 (default)
|
||||
@test "checking smtp: rejects spam" {
|
||||
run docker exec mail /bin/sh -c "grep 'Blocked SPAM' /var/log/mail/mail.log | grep external.tld=spam@my-domain.com | wc -l"
|
||||
assert_success
|
||||
assert_output 1
|
||||
}
|
||||
|
||||
@test "checking smtp: not advertising smtputf8" {
|
||||
# Dovecot does not support SMTPUTF8, so while we can send we cannot receive
|
||||
# Better disable SMTPUTF8 support entirely if we can't handle it correctly
|
||||
run docker exec mail /bin/sh -c "nc 0.0.0.0 25 < /tmp/docker-mailserver-test/email-templates/smtp-ehlo.txt | grep SMTPUTF8 | wc -l"
|
||||
assert_success
|
||||
assert_output 0
|
||||
}
|
||||
|
||||
#
|
||||
# accounts
|
||||
#
|
||||
|
||||
@test "checking accounts: user accounts" {
|
||||
run docker exec mail doveadm user '*'
|
||||
assert_success
|
||||
assert_line --index 0 "user1@localhost.localdomain"
|
||||
assert_line --index 1 "user2@otherdomain.tld"
|
||||
assert_line --index 2 "user3@localhost.localdomain"
|
||||
assert_line --index 3 "added@localhost.localdomain"
|
||||
}
|
||||
|
||||
@test "checking accounts: user mail folder for user1" {
|
||||
run docker exec mail /bin/bash -c "ls -d /var/mail/localhost.localdomain/user1"
|
||||
assert_success
|
||||
}
|
||||
|
||||
@test "checking accounts: user mail folder for user2" {
|
||||
run docker exec mail /bin/bash -c "ls -d /var/mail/otherdomain.tld/user2"
|
||||
assert_success
|
||||
}
|
||||
|
||||
@test "checking accounts: user mail folder for user3" {
|
||||
run docker exec mail /bin/bash -c "ls -d /var/mail/localhost.localdomain/user3/mail"
|
||||
assert_success
|
||||
}
|
||||
|
||||
@test "checking accounts: user mail folder for added user" {
|
||||
run docker exec mail /bin/bash -c "ls -d /var/mail/localhost.localdomain/added"
|
||||
assert_success
|
||||
}
|
||||
|
||||
@test "checking accounts: comments are not parsed" {
|
||||
run docker exec mail /bin/bash -c "ls /var/mail | grep 'comment'"
|
||||
assert_failure
|
||||
}
|
||||
|
||||
#
|
||||
# postfix
|
||||
#
|
||||
|
||||
@test "checking postfix: vhost file is correct" {
|
||||
run docker exec mail cat /etc/postfix/vhost
|
||||
assert_success
|
||||
assert_line --index 0 "localdomain2.com"
|
||||
assert_line --index 1 "localhost.localdomain"
|
||||
assert_line --index 2 "otherdomain.tld"
|
||||
}
|
||||
|
||||
@test "checking postfix: main.cf overrides" {
|
||||
run docker exec mail grep -q 'max_idle = 600s' /tmp/docker-mailserver/postfix-main.cf
|
||||
assert_success
|
||||
run docker exec mail grep -q 'readme_directory = /tmp' /tmp/docker-mailserver/postfix-main.cf
|
||||
assert_success
|
||||
}
|
||||
|
||||
@test "checking postfix: master.cf overrides" {
|
||||
run docker exec mail grep -q 'submission/inet/smtpd_sasl_security_options=noanonymous' /tmp/docker-mailserver/postfix-master.cf
|
||||
assert_success
|
||||
}
|
||||
|
||||
#
|
||||
# dovecot
|
||||
#
|
||||
|
||||
@test "checking dovecot: config additions" {
|
||||
run docker exec mail grep -q 'mail_max_userip_connections = 69' /tmp/docker-mailserver/dovecot.cf
|
||||
assert_success
|
||||
run docker exec mail /bin/sh -c "doveconf | grep 'mail_max_userip_connections = 69'"
|
||||
assert_success
|
||||
assert_output 'mail_max_userip_connections = 69'
|
||||
}
|
||||
|
||||
#
|
||||
# spamassassin
|
||||
#
|
||||
|
||||
@test "checking spamassassin: should be listed in amavis when enabled" {
|
||||
run docker exec mail /bin/sh -c "grep -i 'ANTI-SPAM-SA code' /var/log/mail/mail.log | grep 'NOT loaded'"
|
||||
assert_failure
|
||||
}
|
||||
|
||||
@test "checking spamassassin: all registered domains should see spam headers" {
|
||||
run docker exec mail /bin/sh -c "grep -ir 'X-Spam-' /var/mail/localhost.localdomain/user1/new"
|
||||
assert_success
|
||||
run docker exec mail /bin/sh -c "grep -ir 'X-Spam-' /var/mail/otherdomain.tld/user2/new"
|
||||
assert_success
|
||||
}
|
||||
|
||||
#
|
||||
# postsrsd
|
||||
#
|
||||
|
||||
@test "checking SRS: main.cf entries" {
|
||||
run docker exec mail grep "sender_canonical_maps = tcp:localhost:10001" /etc/postfix/main.cf
|
||||
assert_success
|
||||
run docker exec mail grep "sender_canonical_classes = envelope_sender" /etc/postfix/main.cf
|
||||
assert_success
|
||||
run docker exec mail grep "recipient_canonical_maps = tcp:localhost:10002" /etc/postfix/main.cf
|
||||
assert_success
|
||||
run docker exec mail grep "recipient_canonical_classes = envelope_recipient,header_recipient" /etc/postfix/main.cf
|
||||
assert_success
|
||||
}
|
||||
|
||||
@test "checking SRS: postsrsd running" {
|
||||
run docker exec mail /bin/sh -c "ps aux | grep ^postsrsd"
|
||||
assert_success
|
||||
}
|
||||
|
||||
|
||||
@test "checking SRS: fallback to hostname is handled correctly" {
|
||||
run docker exec mail grep "SRS_DOMAIN=my-domain.com" /etc/default/postsrsd
|
||||
assert_success
|
||||
}
|
||||
|
||||
#
|
||||
# system
|
||||
#
|
||||
|
||||
@test "checking system: freshclam cron is disabled" {
|
||||
run docker exec mail bash -c "grep '/usr/bin/freshclam' -r /etc/cron.d"
|
||||
assert_failure
|
||||
}
|
||||
|
||||
@test "checking amavis: virusmail wiper cron exists" {
|
||||
run docker exec mail bash -c "crontab -l | grep '/usr/local/bin/virus-wiper'"
|
||||
assert_success
|
||||
}
|
||||
|
||||
@test "checking amavis: VIRUSMAILS_DELETE_DELAY override works as expected" {
|
||||
# shellcheck disable=SC2016
|
||||
run docker run --rm -e VIRUSMAILS_DELETE_DELAY=2 "${IMAGE_NAME:?}" /bin/bash -c 'echo "${VIRUSMAILS_DELETE_DELAY}"'
|
||||
assert_output 2
|
||||
}
|
||||
|
||||
@test "checking amavis: old virusmail is wipped by cron" {
|
||||
docker exec mail bash -c 'touch -d "`date --date=2000-01-01`" /var/lib/amavis/virusmails/should-be-deleted'
|
||||
run docker exec mail bash -c '/usr/local/bin/virus-wiper'
|
||||
assert_success
|
||||
run docker exec mail bash -c 'ls -la /var/lib/amavis/virusmails/ | grep should-be-deleted'
|
||||
assert_failure
|
||||
}
|
||||
|
||||
@test "checking amavis: recent virusmail is not wipped by cron" {
|
||||
docker exec mail bash -c 'touch -d "`date`" /var/lib/amavis/virusmails/should-not-be-deleted'
|
||||
run docker exec mail bash -c '/usr/local/bin/virus-wiper'
|
||||
assert_success
|
||||
run docker exec mail bash -c 'ls -la /var/lib/amavis/virusmails/ | grep should-not-be-deleted'
|
||||
assert_success
|
||||
}
|
||||
|
||||
@test "checking system: /var/log/mail/mail.log is error free" {
|
||||
run docker exec mail grep 'non-null host address bits in' /var/log/mail/mail.log
|
||||
assert_failure
|
||||
run docker exec mail grep 'mail system configuration error' /var/log/mail/mail.log
|
||||
assert_failure
|
||||
run docker exec mail grep ': error:' /var/log/mail/mail.log
|
||||
assert_failure
|
||||
run docker exec mail grep -i 'is not writable' /var/log/mail/mail.log
|
||||
assert_failure
|
||||
run docker exec mail grep -i 'permission denied' /var/log/mail/mail.log
|
||||
assert_failure
|
||||
run docker exec mail grep -i '(!)connect' /var/log/mail/mail.log
|
||||
assert_failure
|
||||
run docker exec mail grep -i 'using backwards-compatible default setting' /var/log/mail/mail.log
|
||||
assert_failure
|
||||
run docker exec mail grep -i 'connect to 127.0.0.1:10023: Connection refused' /var/log/mail/mail.log
|
||||
assert_failure
|
||||
}
|
||||
|
||||
@test "checking system: /var/log/auth.log is error free" {
|
||||
run docker exec mail grep 'Unable to open env file: /etc/default/locale' /var/log/auth.log
|
||||
assert_failure
|
||||
}
|
||||
|
||||
@test "checking system: sets the server fqdn" {
|
||||
run docker exec mail hostname
|
||||
assert_success
|
||||
assert_output "mail.my-domain.com"
|
||||
}
|
||||
|
||||
@test "checking system: sets the server domain name in /etc/mailname" {
|
||||
run docker exec mail cat /etc/mailname
|
||||
assert_success
|
||||
assert_output "my-domain.com"
|
||||
}
|
||||
|
||||
@test "checking system: postfix should not log to syslog" {
|
||||
run docker exec mail grep 'postfix' /var/log/syslog
|
||||
assert_failure
|
||||
}
|
||||
|
||||
@test "checking system: amavis decoders installed and available" {
|
||||
run docker exec mail /bin/sh -c "grep -E '.*(Internal decoder|Found decoder) for\s+\..*' /var/log/mail/mail.log*|grep -Eo '(mail|Z|gz|bz2|xz|lzma|lrz|lzo|lz4|rpm|cpio|tar|deb|rar|arj|arc|zoo|doc|cab|tnef|zip|kmz|7z|jar|swf|lha|iso|exe)' | sort | uniq"
|
||||
assert_success
|
||||
# Support for doc and zoo removed in buster
|
||||
cat <<'EOF' | assert_output
|
||||
7z
|
||||
Z
|
||||
arc
|
||||
arj
|
||||
bz2
|
||||
cab
|
||||
cpio
|
||||
deb
|
||||
exe
|
||||
gz
|
||||
iso
|
||||
jar
|
||||
kmz
|
||||
lha
|
||||
lrz
|
||||
lz4
|
||||
lzma
|
||||
lzo
|
||||
mail
|
||||
rar
|
||||
rpm
|
||||
swf
|
||||
tar
|
||||
tnef
|
||||
xz
|
||||
zip
|
||||
EOF
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# sieve
|
||||
#
|
||||
|
||||
@test "checking sieve: user1 should have received 1 email in folder INBOX.spam" {
|
||||
run docker exec mail /bin/sh -c "ls -A /var/mail/localhost.localdomain/user1/.INBOX.spam/new | wc -l"
|
||||
assert_success
|
||||
assert_output 1
|
||||
}
|
||||
|
||||
@test "checking manage sieve: server is ready when ENABLE_MANAGESIEVE has been set" {
|
||||
run docker exec mail /bin/bash -c "nc -z 0.0.0.0 4190"
|
||||
assert_success
|
||||
}
|
||||
|
||||
@test "checking sieve: user2 should have piped 1 email to /tmp/" {
|
||||
run docker exec mail /bin/sh -c "ls -A /tmp/pipe-test.out | wc -l"
|
||||
assert_success
|
||||
assert_output 1
|
||||
}
|
||||
|
||||
@test "checking sieve global: user1 should have gotten a copy of his spam mail" {
|
||||
run docker exec mail /bin/sh -c "grep 'Spambot <spam@spam.com>' -R /var/mail/localhost.localdomain/user1/new/"
|
||||
assert_success
|
||||
}
|
||||
|
||||
#
|
||||
# accounts
|
||||
#
|
||||
@test "checking accounts: user_without_domain creation should be rejected since user@domain format is required" {
|
||||
run docker exec mail /bin/sh -c "addmailuser user_without_domain mypassword"
|
||||
assert_failure
|
||||
assert_output --partial 'should include the domain (eg: user@example.com)'
|
||||
}
|
||||
|
||||
@test "checking accounts: user3 should have been added to /tmp/docker-mailserver/postfix-accounts.cf" {
|
||||
docker exec mail /bin/sh -c "addmailuser user3@domain.tld mypassword"
|
||||
|
||||
run docker exec mail /bin/sh -c "grep '^user3@domain\.tld|' -i /tmp/docker-mailserver/postfix-accounts.cf"
|
||||
assert_success
|
||||
[[ -n ${output} ]]
|
||||
}
|
||||
|
||||
@test "checking accounts: auser3 should have been added to /tmp/docker-mailserver/postfix-accounts.cf" {
|
||||
docker exec mail /bin/sh -c "addmailuser auser3@domain.tld mypassword"
|
||||
|
||||
run docker exec mail /bin/sh -c "grep '^auser3@domain\.tld|' -i /tmp/docker-mailserver/postfix-accounts.cf"
|
||||
assert_success
|
||||
[[ -n ${output} ]]
|
||||
}
|
||||
|
||||
@test "checking accounts: a.ser3 should have been added to /tmp/docker-mailserver/postfix-accounts.cf" {
|
||||
docker exec mail /bin/sh -c "addmailuser a.ser3@domain.tld mypassword"
|
||||
|
||||
run docker exec mail /bin/sh -c "grep '^a\.ser3@domain\.tld|' -i /tmp/docker-mailserver/postfix-accounts.cf"
|
||||
assert_success
|
||||
[[ -n ${output} ]]
|
||||
}
|
||||
|
||||
@test "checking accounts: user3 should have been removed from /tmp/docker-mailserver/postfix-accounts.cf but not auser3" {
|
||||
wait_until_account_maildir_exists mail 'user3@domain.tld'
|
||||
|
||||
docker exec mail /bin/sh -c "delmailuser -y user3@domain.tld"
|
||||
|
||||
run docker exec mail /bin/sh -c "grep '^user3@domain\.tld' -i /tmp/docker-mailserver/postfix-accounts.cf"
|
||||
assert_failure
|
||||
[[ -z ${output} ]]
|
||||
|
||||
run docker exec mail /bin/sh -c "grep '^auser3@domain\.tld' -i /tmp/docker-mailserver/postfix-accounts.cf"
|
||||
assert_success
|
||||
[[ -n ${output} ]]
|
||||
}
|
||||
|
||||
@test "checking user updating password for user in /tmp/docker-mailserver/postfix-accounts.cf" {
|
||||
add_mail_account_then_wait_until_ready mail 'user4@domain.tld'
|
||||
|
||||
initialpass=$(docker exec mail /bin/sh -c "grep '^user4@domain\.tld' -i /tmp/docker-mailserver/postfix-accounts.cf")
|
||||
sleep 2
|
||||
docker exec mail /bin/sh -c "updatemailuser user4@domain.tld mynewpassword"
|
||||
sleep 2
|
||||
changepass=$(docker exec mail /bin/sh -c "grep '^user4@domain\.tld' -i /tmp/docker-mailserver/postfix-accounts.cf")
|
||||
|
||||
[[ ${initialpass} != "${changepass}" ]]
|
||||
|
||||
run docker exec mail /bin/sh -c "delmailuser -y auser3@domain.tld"
|
||||
assert_success
|
||||
}
|
||||
|
||||
@test "checking accounts: listmailuser (quotas disabled)" {
|
||||
run docker exec mail /bin/sh -c "echo 'ENABLE_QUOTAS=0' >> /etc/dms-settings && listmailuser | head -n 1"
|
||||
assert_success
|
||||
assert_output '* user1@localhost.localdomain'
|
||||
}
|
||||
|
||||
@test "checking accounts: listmailuser (quotas enabled)" {
|
||||
run docker exec mail /bin/sh -c "sed -i '/ENABLE_QUOTAS=0/d' /etc/dms-settings; listmailuser | head -n 1"
|
||||
assert_success
|
||||
assert_output '* user1@localhost.localdomain ( 10K / ~ ) [0%]'
|
||||
}
|
||||
|
||||
@test "checking accounts: no error is generated when deleting a user if /tmp/docker-mailserver/postfix-accounts.cf is missing" {
|
||||
run docker run --rm \
|
||||
-v "$(duplicate_config_for_container without-accounts/ without-accounts-deleting-user)":/tmp/docker-mailserver/ \
|
||||
"${IMAGE_NAME:?}" /bin/sh -c 'delmailuser -y user3@domain.tld'
|
||||
assert_success
|
||||
[[ -z ${output} ]]
|
||||
}
|
||||
|
||||
@test "checking accounts: user3 should have been added to /tmp/docker-mailserver/postfix-accounts.cf even when that file does not exist" {
|
||||
local PRIVATE_CONFIG
|
||||
PRIVATE_CONFIG=$(duplicate_config_for_container without-accounts/ without-accounts_file_does_not_exist)
|
||||
run docker run --rm \
|
||||
-v "${PRIVATE_CONFIG}/without-accounts/":/tmp/docker-mailserver/ \
|
||||
"${IMAGE_NAME:?}" /bin/sh -c 'addmailuser user3@domain.tld mypassword'
|
||||
assert_success
|
||||
run docker run --rm \
|
||||
-v "${PRIVATE_CONFIG}/without-accounts/":/tmp/docker-mailserver/ \
|
||||
"${IMAGE_NAME:?}" /bin/sh -c 'grep user3@domain.tld -i /tmp/docker-mailserver/postfix-accounts.cf'
|
||||
assert_success
|
||||
[[ -n ${output} ]]
|
||||
}
|
||||
|
||||
|
||||
@test "checking quota: setquota user must be existing" {
|
||||
add_mail_account_then_wait_until_ready mail 'quota_user@domain.tld'
|
||||
|
||||
run docker exec mail /bin/sh -c "setquota quota_user 50M"
|
||||
assert_failure
|
||||
run docker exec mail /bin/sh -c "setquota quota_user@domain.tld 50M"
|
||||
assert_success
|
||||
|
||||
run docker exec mail /bin/sh -c "setquota username@fulldomain 50M"
|
||||
assert_failure
|
||||
|
||||
run docker exec mail /bin/sh -c "delmailuser -y quota_user@domain.tld"
|
||||
assert_success
|
||||
}
|
||||
|
||||
@test "checking quota: setquota <quota> must be well formatted" {
|
||||
add_mail_account_then_wait_until_ready mail 'quota_user@domain.tld'
|
||||
|
||||
run docker exec mail /bin/sh -c "setquota quota_user@domain.tld 26GIGOTS"
|
||||
assert_failure
|
||||
run docker exec mail /bin/sh -c "setquota quota_user@domain.tld 123"
|
||||
assert_failure
|
||||
run docker exec mail /bin/sh -c "setquota quota_user@domain.tld M"
|
||||
assert_failure
|
||||
run docker exec mail /bin/sh -c "setquota quota_user@domain.tld -60M"
|
||||
assert_failure
|
||||
|
||||
|
||||
run docker exec mail /bin/sh -c "setquota quota_user@domain.tld 10B"
|
||||
assert_success
|
||||
run docker exec mail /bin/sh -c "setquota quota_user@domain.tld 10k"
|
||||
assert_success
|
||||
run docker exec mail /bin/sh -c "setquota quota_user@domain.tld 10M"
|
||||
assert_success
|
||||
run docker exec mail /bin/sh -c "setquota quota_user@domain.tld 10G"
|
||||
assert_success
|
||||
run docker exec mail /bin/sh -c "setquota quota_user@domain.tld 10T"
|
||||
assert_success
|
||||
|
||||
|
||||
run docker exec mail /bin/sh -c "delmailuser -y quota_user@domain.tld"
|
||||
assert_success
|
||||
}
|
||||
|
||||
@test "checking quota: delquota user must be existing" {
|
||||
add_mail_account_then_wait_until_ready mail 'quota_user@domain.tld'
|
||||
|
||||
run docker exec mail /bin/sh -c "delquota uota_user@domain.tld"
|
||||
assert_failure
|
||||
run docker exec mail /bin/sh -c "delquota quota_user"
|
||||
assert_failure
|
||||
run docker exec mail /bin/sh -c "delquota dontknowyou@domain.tld"
|
||||
assert_failure
|
||||
|
||||
run docker exec mail /bin/sh -c "setquota quota_user@domain.tld 10T"
|
||||
assert_success
|
||||
run docker exec mail /bin/sh -c "delquota quota_user@domain.tld"
|
||||
assert_success
|
||||
run docker exec mail /bin/sh -c "grep -i 'quota_user@domain.tld' /tmp/docker-mailserver/dovecot-quotas.cf"
|
||||
assert_failure
|
||||
|
||||
run docker exec mail /bin/sh -c "delmailuser -y quota_user@domain.tld"
|
||||
assert_success
|
||||
}
|
||||
|
||||
@test "checking quota: delquota allow when no quota for existing user" {
|
||||
add_mail_account_then_wait_until_ready mail 'quota_user@domain.tld'
|
||||
|
||||
run docker exec mail /bin/sh -c "grep -i 'quota_user@domain.tld' /tmp/docker-mailserver/dovecot-quotas.cf"
|
||||
assert_failure
|
||||
|
||||
run docker exec mail /bin/sh -c "delquota quota_user@domain.tld"
|
||||
assert_success
|
||||
run docker exec mail /bin/sh -c "delquota quota_user@domain.tld"
|
||||
assert_success
|
||||
|
||||
run docker exec mail /bin/sh -c "delmailuser -y quota_user@domain.tld"
|
||||
assert_success
|
||||
}
|
||||
|
||||
@test "checking quota: dovecot quota present in postconf" {
|
||||
run docker exec mail /bin/bash -c "postconf | grep 'check_policy_service inet:localhost:65265'"
|
||||
assert_success
|
||||
}
|
||||
|
||||
|
||||
@test "checking quota: dovecot mailbox max size must be equal to postfix mailbox max size" {
|
||||
postfix_mailbox_size=$(docker exec mail sh -c "postconf | grep -Po '(?<=mailbox_size_limit = )[0-9]+'")
|
||||
run echo "${postfix_mailbox_size}"
|
||||
refute_output ""
|
||||
|
||||
# dovecot relies on virtual_mailbox_size by default
|
||||
postfix_virtual_mailbox_size=$(docker exec mail sh -c "postconf | grep -Po '(?<=virtual_mailbox_limit = )[0-9]+'")
|
||||
assert_equal "${postfix_virtual_mailbox_size}" "${postfix_mailbox_size}"
|
||||
|
||||
postfix_mailbox_size_mb=$(( postfix_mailbox_size / 1000000))
|
||||
|
||||
dovecot_mailbox_size_mb=$(docker exec mail sh -c "doveconf | grep -oP '(?<=quota_rule \= \*\:storage=)[0-9]+'")
|
||||
run echo "${dovecot_mailbox_size_mb}"
|
||||
refute_output ""
|
||||
|
||||
assert_equal "${postfix_mailbox_size_mb}" "${dovecot_mailbox_size_mb}"
|
||||
}
|
||||
|
||||
|
||||
@test "checking quota: dovecot message max size must be equal to postfix messsage max size" {
|
||||
postfix_message_size=$(docker exec mail sh -c "postconf | grep -Po '(?<=message_size_limit = )[0-9]+'")
|
||||
run echo "${postfix_message_size}"
|
||||
refute_output ""
|
||||
|
||||
postfix_message_size_mb=$(( postfix_message_size / 1000000))
|
||||
|
||||
dovecot_message_size_mb=$(docker exec mail sh -c "doveconf | grep -oP '(?<=quota_max_mail_size = )[0-9]+'")
|
||||
run echo "${dovecot_message_size_mb}"
|
||||
refute_output ""
|
||||
|
||||
assert_equal "${postfix_message_size_mb}" "${dovecot_message_size_mb}"
|
||||
}
|
||||
|
||||
@test "checking quota: quota directive is removed when mailbox is removed" {
|
||||
add_mail_account_then_wait_until_ready mail 'quserremoved@domain.tld'
|
||||
|
||||
run docker exec mail /bin/sh -c "setquota quserremoved@domain.tld 12M"
|
||||
assert_success
|
||||
|
||||
run docker exec mail /bin/sh -c 'cat /tmp/docker-mailserver/dovecot-quotas.cf | grep -E "^quserremoved@domain.tld\:12M\$" | wc -l | grep 1'
|
||||
assert_success
|
||||
|
||||
run docker exec mail /bin/sh -c "delmailuser -y quserremoved@domain.tld"
|
||||
assert_success
|
||||
|
||||
run docker exec mail /bin/sh -c 'cat /tmp/docker-mailserver/dovecot-quotas.cf | grep -E "^quserremoved@domain.tld\:12M\$"'
|
||||
assert_failure
|
||||
}
|
||||
|
||||
@test "checking quota: dovecot applies user quota" {
|
||||
run docker exec mail /bin/sh -c "doveadm quota get -u 'user1@localhost.localdomain' | grep 'User quota STORAGE'"
|
||||
assert_output --partial "- 0"
|
||||
|
||||
run docker exec mail /bin/sh -c "setquota user1@localhost.localdomain 50M"
|
||||
assert_success
|
||||
|
||||
# wait until quota has been updated
|
||||
run repeat_until_success_or_timeout 20 sh -c "docker exec mail sh -c 'doveadm quota get -u user1@localhost.localdomain | grep -oP \"(User quota STORAGE\s+[0-9]+\s+)51200(.*)\"'"
|
||||
assert_success
|
||||
|
||||
run docker exec mail /bin/sh -c "delquota user1@localhost.localdomain"
|
||||
assert_success
|
||||
|
||||
# wait until quota has been updated
|
||||
run repeat_until_success_or_timeout 20 sh -c "docker exec mail sh -c 'doveadm quota get -u user1@localhost.localdomain | grep -oP \"(User quota STORAGE\s+[0-9]+\s+)-(.*)\"'"
|
||||
assert_success
|
||||
}
|
||||
|
||||
@test "checking quota: warn message received when quota exceeded" {
|
||||
skip 'disabled as it fails randomly: https://github.com/docker-mailserver/docker-mailserver/pull/2511'
|
||||
|
||||
# create user
|
||||
add_mail_account_then_wait_until_ready mail 'quotauser@otherdomain.tld'
|
||||
run docker exec mail /bin/sh -c 'setquota quotauser@otherdomain.tld 10k'
|
||||
assert_success
|
||||
|
||||
# wait until quota has been updated
|
||||
run repeat_until_success_or_timeout 20 sh -c "docker exec mail sh -c 'doveadm quota get -u quotauser@otherdomain.tld | grep -oP \"(User quota STORAGE\s+[0-9]+\s+)10(.*)\"'"
|
||||
assert_success
|
||||
|
||||
# dovecot and postfix has been restarted
|
||||
wait_for_service mail postfix
|
||||
wait_for_service mail dovecot
|
||||
sleep 10
|
||||
|
||||
# send some big emails
|
||||
run docker exec mail /bin/sh -c "nc 0.0.0.0 25 < /tmp/docker-mailserver-test/email-templates/quota-exceeded.txt"
|
||||
assert_success
|
||||
run docker exec mail /bin/sh -c "nc 0.0.0.0 25 < /tmp/docker-mailserver-test/email-templates/quota-exceeded.txt"
|
||||
assert_success
|
||||
run docker exec mail /bin/sh -c "nc 0.0.0.0 25 < /tmp/docker-mailserver-test/email-templates/quota-exceeded.txt"
|
||||
assert_success
|
||||
# check for quota warn message existence
|
||||
run repeat_until_success_or_timeout 20 sh -c "docker exec mail sh -c 'grep \"Subject: quota warning\" /var/mail/otherdomain.tld/quotauser/new/ -R'"
|
||||
assert_success
|
||||
|
||||
run repeat_until_success_or_timeout 20 sh -c "docker logs mail | grep 'Quota exceeded (mailbox for user is full)'"
|
||||
assert_success
|
||||
|
||||
# ensure only the first big message and the warn message are present (other messages are rejected: mailbox is full)
|
||||
run docker exec mail sh -c 'ls /var/mail/otherdomain.tld/quotauser/new/ | wc -l'
|
||||
assert_success
|
||||
assert_output "2"
|
||||
|
||||
run docker exec mail /bin/sh -c "delmailuser -y quotauser@otherdomain.tld"
|
||||
assert_success
|
||||
}
|
||||
|
||||
#
|
||||
# PERMIT_DOCKER mynetworks
|
||||
#
|
||||
|
||||
@test "checking PERMIT_DOCKER: can get container ip" {
|
||||
run docker exec mail /bin/sh -c "ip addr show eth0 | grep 'inet ' | sed 's/[^0-9\.\/]*//g' | cut -d '/' -f 1 | egrep '[[:digit:]]{1,3}\.[[:digit:]]{1,3}\.[[:digit:]]{1,3}\.[[:digit:]]{1,3}'"
|
||||
assert_success
|
||||
}
|
||||
|
||||
@test "checking PERMIT_DOCKER: my network value" {
|
||||
run docker exec mail /bin/sh -c "postconf | grep '^mynetworks =' | egrep '[[:digit:]]{1,3}\.[[:digit:]]{1,3}\.0\.0/16'"
|
||||
assert_success
|
||||
}
|
||||
|
||||
#
|
||||
# amavis
|
||||
#
|
||||
|
||||
@test "checking amavis: config overrides" {
|
||||
run docker exec mail /bin/sh -c "grep 'Test Verification' /etc/amavis/conf.d/50-user | wc -l"
|
||||
assert_success
|
||||
assert_output 1
|
||||
}
|
||||
|
||||
# TODO investigate why this test fails
|
||||
@test "checking user login: predefined user can login" {
|
||||
skip 'disabled as it fails randomly: https://github.com/docker-mailserver/docker-mailserver/pull/2177'
|
||||
run docker exec mail /bin/bash -c "doveadm auth test -x service=smtp pass@localhost.localdomain 'may be \\a \`p^a.*ssword' | grep 'passdb'"
|
||||
assert_output "passdb: pass@localhost.localdomain auth succeeded"
|
||||
}
|
||||
|
||||
#
|
||||
# LDAP
|
||||
#
|
||||
|
||||
# postfix
|
||||
|
||||
@test "checking dovecot: postmaster address" {
|
||||
run docker exec mail /bin/sh -c "grep 'postmaster_address = postmaster@my-domain.com' /etc/dovecot/conf.d/15-lda.conf"
|
||||
assert_success
|
||||
}
|
||||
|
||||
@test "checking spoofing: rejects sender forging" {
|
||||
# checking rejection of spoofed sender
|
||||
wait_for_smtp_port_in_container_to_respond mail
|
||||
run docker exec mail /bin/sh -c "nc 0.0.0.0 25 < /tmp/docker-mailserver-test/auth/added-smtp-auth-spoofed.txt"
|
||||
assert_output --partial 'Sender address rejected: not owned by user'
|
||||
}
|
||||
|
||||
@test "checking spoofing: accepts sending as alias" {
|
||||
run docker exec mail /bin/sh -c "nc 0.0.0.0 25 < /tmp/docker-mailserver-test/auth/added-smtp-auth-spoofed-alias.txt | grep 'End data with'"
|
||||
assert_success
|
||||
}
|
||||
|
||||
#
|
||||
# Pflogsumm delivery check
|
||||
#
|
||||
|
||||
@test "checking pflogsum delivery" {
|
||||
# checking logrotation working and report being sent
|
||||
docker exec mail logrotate --force /etc/logrotate.d/maillog
|
||||
sleep 10
|
||||
run docker exec mail grep "Subject: Postfix Summary for " /var/mail/localhost.localdomain/user1/new/ -R
|
||||
assert_success
|
||||
# check sender is the one specified in REPORT_SENDER
|
||||
run docker exec mail grep "From: report1@mail.my-domain.com" /var/mail/localhost.localdomain/user1/new/ -R
|
||||
assert_success
|
||||
# check sender is not the default one.
|
||||
run docker exec mail grep "From: mailserver-report@mail.my-domain.com" /var/mail/localhost.localdomain/user1/new/ -R
|
||||
assert_failure
|
||||
}
|
||||
|
||||
#
|
||||
# supervisor
|
||||
#
|
||||
|
||||
@test "checking restart of process: postfix" {
|
||||
run docker exec mail /bin/bash -c "pkill master && sleep 10 && ps aux --forest | grep -v grep | grep '/usr/lib/postfix/sbin/master'"
|
||||
assert_success
|
||||
}
|
||||
|
||||
@test "checking restart of process: amavisd-new" {
|
||||
run docker exec mail /bin/bash -c "pkill amavi && sleep 12 && ps aux --forest | grep -v grep | grep '/usr/sbin/amavisd-new (master)'"
|
||||
assert_success
|
||||
}
|
||||
|
||||
@test "checking restart of process: opendkim" {
|
||||
run docker exec mail /bin/bash -c "pkill opendkim && sleep 10 && ps aux --forest | grep -v grep | grep '/usr/sbin/opendkim'"
|
||||
assert_success
|
||||
}
|
||||
|
||||
@test "checking restart of process: opendmarc" {
|
||||
run docker exec mail /bin/bash -c "pkill opendmarc && sleep 10 && ps aux --forest | grep -v grep | grep '/usr/sbin/opendmarc'"
|
||||
assert_success
|
||||
}
|
||||
|
||||
#
|
||||
# root mail delivery
|
||||
#
|
||||
|
||||
@test "checking that mail for root was delivered" {
|
||||
run docker exec mail grep "Subject: Root Test Message" /var/mail/localhost.localdomain/user1/new/ -R
|
||||
assert_success
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue