Merge branch 'master' into master-fix_setup_stack

This commit is contained in:
Georg Lauterbach 2024-01-26 14:11:23 +01:00 committed by GitHub
commit 1957196813
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 120 additions and 42 deletions

View File

@ -38,6 +38,11 @@ The most noteworthy change of this release is the update of the container's base
- **Tests:** - **Tests:**
- Refactored helper methods for sending e-mails with specific `Message-ID` headers and the helpers for retrieving + filtering logs, which together help isolate logs relevant to specific mail when multiple mails have been processed within a single test. ([#3786](https://github.com/docker-mailserver/docker-mailserver/pull/3786)) - Refactored helper methods for sending e-mails with specific `Message-ID` headers and the helpers for retrieving + filtering logs, which together help isolate logs relevant to specific mail when multiple mails have been processed within a single test. ([#3786](https://github.com/docker-mailserver/docker-mailserver/pull/3786))
### Fixes
- DMS config files that are parsed line by line are now more robust to parse by detecting and fixing line-endings ([#3819](https://github.com/docker-mailserver/docker-mailserver/pull/3819))
- Variables related to Rspamd are declared as `readonly`, which would cause warnings in the log when being re-declared; we now guard against this issue ([#3837](https://github.com/docker-mailserver/docker-mailserver/pull/3837))
## [v13.3.1](https://github.com/docker-mailserver/docker-mailserver/releases/tag/v13.3.1) ## [v13.3.1](https://github.com/docker-mailserver/docker-mailserver/releases/tag/v13.3.1)
### Fixes ### Fixes

View File

@ -16,12 +16,16 @@ If you want to append instead, switch `::before` to `::after`.
src: url('../fonts/external-link.woff') format('woff'); src: url('../fonts/external-link.woff') format('woff');
} }
/* Matches the two nav link classes that start with `http` `href` values, regular docs pages use relative URLs instead. */ /*
.md-tabs__link[href^="http"]::before, .md-nav__link[href^="http"]::before { Since mkdocs-material 9.5.5 broke support in our docs from DMS v13.3.1, we now use our own class name,
which has been included for the two external nav links in mkdocs.yml via workaround (insert HTML).
*/
.icon-external-link::before {
display: inline-block; /* treat similar to text */ display: inline-block; /* treat similar to text */
font-family: 'external-link'; font-family: 'external-link';
content:'\0041'; /* represents "A" which our font renders as an icon instead of the "A" glyph */ content:'\0041'; /* represents "A" which our font renders as an icon instead of the "A" glyph */
font-size: 80%; /* icon is a little too big by default, scale it down */ font-size: 80%; /* icon is a little too big by default, scale it down */
margin-right: 4px;
} }
/* ============================================================================================================= */ /* ============================================================================================================= */
@ -98,3 +102,8 @@ div.md-content article.md-content__inner a.toclink code {
.highlight.no-copy .md-clipboard { display: none; } .highlight.no-copy .md-clipboard { display: none; }
/* ============================================================================================================= */ /* ============================================================================================================= */
/* Make the left-sidebar nav categories better distinguished from page links (bold text) */
.md-nav__item--nested > .md-nav__link {
font-weight: 700;
}

View File

@ -173,5 +173,5 @@ nav:
- 'General Information': contributing/general.md - 'General Information': contributing/general.md
- 'Tests': contributing/tests.md - 'Tests': contributing/tests.md
- 'Issues and Pull Requests': contributing/issues-and-pull-requests.md - 'Issues and Pull Requests': contributing/issues-and-pull-requests.md
- 'DockerHub': https://hub.docker.com/r/mailserver/docker-mailserver/ - '<span class="icon-external-link"></span>DockerHub': https://hub.docker.com/r/mailserver/docker-mailserver/
- 'GHCR': https://github.com/docker-mailserver/docker-mailserver/pkgs/container/docker-mailserver - '<span class="icon-external-link"></span>GHCR': https://github.com/docker-mailserver/docker-mailserver/pkgs/container/docker-mailserver

View File

@ -46,6 +46,8 @@ pickup fifo n - n 60 1 pickup
-o content_filter= -o content_filter=
-o receive_override_options=no_header_body_checks -o receive_override_options=no_header_body_checks
# This relates to submission(s) services defined above:
# https://www.postfix.org/BUILTIN_FILTER_README.html#mx_submission
sender-cleanup unix n - n - 0 cleanup sender-cleanup unix n - n - 0 cleanup
-o syslog_name=postfix/sender-cleanup -o syslog_name=postfix/sender-cleanup
-o header_checks=pcre:/etc/postfix/maps/sender_header_filter.pcre -o header_checks=pcre:/etc/postfix/maps/sender_header_filter.pcre

View File

@ -19,16 +19,9 @@ function _create_accounts() {
_create_masters _create_masters
if [[ -f ${DATABASE_ACCOUNTS} ]]; then if [[ -f ${DATABASE_ACCOUNTS} ]]; then
_log 'trace' "Checking file line endings"
sed -i 's|\r||g' "${DATABASE_ACCOUNTS}"
_log 'trace' "Regenerating postfix user list" _log 'trace' "Regenerating postfix user list"
echo "# WARNING: this file is auto-generated. Modify ${DATABASE_ACCOUNTS} to edit the user list." > /etc/postfix/vmailbox echo "# WARNING: this file is auto-generated. Modify ${DATABASE_ACCOUNTS} to edit the user list." > /etc/postfix/vmailbox
# checking that ${DATABASE_ACCOUNTS} ends with a newline
# shellcheck disable=SC1003
sed -i -e '$a\' "${DATABASE_ACCOUNTS}"
chown dovecot:dovecot "${DOVECOT_USERDB_FILE}" chown dovecot:dovecot "${DOVECOT_USERDB_FILE}"
chmod 640 "${DOVECOT_USERDB_FILE}" chmod 640 "${DOVECOT_USERDB_FILE}"
@ -158,15 +151,8 @@ function _create_masters() {
local DATABASE_DOVECOT_MASTERS='/tmp/docker-mailserver/dovecot-masters.cf' local DATABASE_DOVECOT_MASTERS='/tmp/docker-mailserver/dovecot-masters.cf'
if [[ -f ${DATABASE_DOVECOT_MASTERS} ]]; then if [[ -f ${DATABASE_DOVECOT_MASTERS} ]]; then
_log 'trace' "Checking file line endings"
sed -i 's|\r||g' "${DATABASE_DOVECOT_MASTERS}"
_log 'trace' "Regenerating dovecot masters list" _log 'trace' "Regenerating dovecot masters list"
# checking that ${DATABASE_DOVECOT_MASTERS} ends with a newline
# shellcheck disable=SC1003
sed -i -e '$a\' "${DATABASE_DOVECOT_MASTERS}"
chown dovecot:dovecot "${DOVECOT_MASTERDB_FILE}" chown dovecot:dovecot "${DOVECOT_MASTERDB_FILE}"
chmod 640 "${DOVECOT_MASTERDB_FILE}" chmod 640 "${DOVECOT_MASTERDB_FILE}"

View File

@ -12,11 +12,6 @@ function _handle_postfix_virtual_config() {
local DATABASE_VIRTUAL=/tmp/docker-mailserver/postfix-virtual.cf local DATABASE_VIRTUAL=/tmp/docker-mailserver/postfix-virtual.cf
if [[ -f ${DATABASE_VIRTUAL} ]]; then if [[ -f ${DATABASE_VIRTUAL} ]]; then
# fixing old virtual user file
if grep -q ",$" "${DATABASE_VIRTUAL}"; then
sed -i -e "s|, |,|g" -e "s|,$||g" "${DATABASE_VIRTUAL}"
fi
cp -f "${DATABASE_VIRTUAL}" /etc/postfix/virtual cp -f "${DATABASE_VIRTUAL}" /etc/postfix/virtual
else else
_log 'debug' "'${DATABASE_VIRTUAL}' not provided - no mail alias/forward created" _log 'debug' "'${DATABASE_VIRTUAL}' not provided - no mail alias/forward created"

View File

@ -15,6 +15,10 @@ function __do_as_rspamd_user() {
# they cannot be modified. Use this function when you require common directory # they cannot be modified. Use this function when you require common directory
# names, file names, etc. # names, file names, etc.
function _rspamd_get_envs() { function _rspamd_get_envs() {
# If the variables are already set, we cannot set them again as they are declared
# with `readonly`. Checking whether one is declared suffices, because either all
# are declared at once, or none.
if [[ ! -v RSPAMD_LOCAL_D ]]; then
readonly RSPAMD_LOCAL_D='/etc/rspamd/local.d' readonly RSPAMD_LOCAL_D='/etc/rspamd/local.d'
readonly RSPAMD_OVERRIDE_D='/etc/rspamd/override.d' readonly RSPAMD_OVERRIDE_D='/etc/rspamd/override.d'
@ -23,6 +27,7 @@ function _rspamd_get_envs() {
readonly RSPAMD_DMS_OVERRIDE_D="${RSPAMD_DMS_D}/override.d" readonly RSPAMD_DMS_OVERRIDE_D="${RSPAMD_DMS_D}/override.d"
readonly RSPAMD_DMS_CUSTOM_COMMANDS_F="${RSPAMD_DMS_D}/custom-commands.conf" readonly RSPAMD_DMS_CUSTOM_COMMANDS_F="${RSPAMD_DMS_D}/custom-commands.conf"
fi
} }
# Parses `RSPAMD_DMS_CUSTOM_COMMANDS_F` and executed the directives given by the file. # Parses `RSPAMD_DMS_CUSTOM_COMMANDS_F` and executed the directives given by the file.

View File

@ -17,9 +17,44 @@ function _escape_for_sed() {
# Returns input after filtering out lines that are: # Returns input after filtering out lines that are:
# empty, white-space, comments (`#` as the first non-whitespace character) # empty, white-space, comments (`#` as the first non-whitespace character)
function _get_valid_lines_from_file() { function _get_valid_lines_from_file() {
_convert_crlf_to_lf_if_necessary "${1}"
_append_final_newline_if_missing "${1}"
grep --extended-regexp --invert-match "^\s*$|^\s*#" "${1}" || true grep --extended-regexp --invert-match "^\s*$|^\s*#" "${1}" || true
} }
# This is to sanitize configs from users that unknowingly introduced CRLF:
function _convert_crlf_to_lf_if_necessary() {
if [[ $(file "${1}") =~ 'CRLF' ]]; then
_log 'warn' "File '${1}' contains CRLF line-endings"
if [[ -w ${1} ]]; then
_log 'debug' 'Converting CRLF to LF'
sed -i 's|\r||g' "${1}"
else
_log 'warn' "File '${1}' is not writable - cannot change CRLF to LF"
fi
fi
}
# This is to sanitize configs from users that unknowingly removed the end-of-file LF:
function _append_final_newline_if_missing() {
# Correctly detect a missing final newline and fix it:
# https://stackoverflow.com/questions/38746/how-to-detect-file-ends-in-newline#comment82380232_25749716
# https://unix.stackexchange.com/questions/31947/how-to-add-a-newline-to-the-end-of-a-file/441200#441200
# https://unix.stackexchange.com/questions/159557/how-to-non-invasively-test-for-write-access-to-a-file
if [[ $(tail -c1 "${1}" | wc -l) -eq 0 ]]; then
# Avoid fixing when the destination is read-only:
if [[ -w ${1} ]]; then
printf '\n' >> "${1}"
_log 'info' "File '${1}' was missing a final newline - this has been fixed"
else
_log 'warn' "File '${1}' is missing a final newline - it is not writable, hence it was not fixed - the last line will not be processed!"
fi
fi
}
# Provide the name of an environment variable to this function # Provide the name of an environment variable to this function
# and it will return its value stored in /etc/dms-settings # and it will return its value stored in /etc/dms-settings
function _get_dms_env_value() { function _get_dms_env_value() {

View File

@ -19,7 +19,7 @@ function _check_improper_restart() {
if [[ -f /CONTAINER_START ]]; then if [[ -f /CONTAINER_START ]]; then
_log 'warn' 'This container was (likely) improperly restarted which can result in undefined behavior' _log 'warn' 'This container was (likely) improperly restarted which can result in undefined behavior'
_log 'warn' 'Please destroy the container properly and then start DMS again' _log 'warn' "Please use 'docker compose up --force-recreate' or equivalent (view our troubleshooting docs)"
fi fi
} }

View File

@ -109,8 +109,9 @@ function _setup_postfix_late() {
function __postfix__setup_override_configuration() { function __postfix__setup_override_configuration() {
__postfix__log 'debug' 'Overriding / adjusting configuration with user-supplied values' __postfix__log 'debug' 'Overriding / adjusting configuration with user-supplied values'
if [[ -f /tmp/docker-mailserver/postfix-main.cf ]]; then local OVERRIDE_CONFIG_POSTFIX_MAIN='/tmp/docker-mailserver/postfix-main.cf'
cat /tmp/docker-mailserver/postfix-main.cf >>/etc/postfix/main.cf if [[ -f ${OVERRIDE_CONFIG_POSTFIX_MAIN} ]]; then
cat "${OVERRIDE_CONFIG_POSTFIX_MAIN}" >>/etc/postfix/main.cf
_adjust_mtime_for_postfix_maincf _adjust_mtime_for_postfix_maincf
# do not directly output to 'main.cf' as this causes a read-write-conflict # do not directly output to 'main.cf' as this causes a read-write-conflict
@ -118,20 +119,19 @@ function __postfix__setup_override_configuration() {
mv /tmp/postfix-main-new.cf /etc/postfix/main.cf mv /tmp/postfix-main-new.cf /etc/postfix/main.cf
_adjust_mtime_for_postfix_maincf _adjust_mtime_for_postfix_maincf
__postfix__log 'trace' "Adjusted '/etc/postfix/main.cf' according to '/tmp/docker-mailserver/postfix-main.cf'" __postfix__log 'trace' "Adjusted '/etc/postfix/main.cf' according to '${OVERRIDE_CONFIG_POSTFIX_MAIN}'"
else else
__postfix__log 'trace' "No extra Postfix settings loaded because optional '/tmp/docker-mailserver/postfix-main.cf' was not provided" __postfix__log 'trace' "No extra Postfix settings loaded because optional '${OVERRIDE_CONFIG_POSTFIX_MAIN}' was not provided"
fi fi
if [[ -f /tmp/docker-mailserver/postfix-master.cf ]]; then local OVERRIDE_CONFIG_POSTFIX_MASTER='/tmp/docker-mailserver/postfix-master.cf'
if [[ -f ${OVERRIDE_CONFIG_POSTFIX_MASTER} ]]; then
while read -r LINE; do while read -r LINE; do
if [[ ${LINE} =~ ^[0-9a-z] ]]; then [[ ${LINE} =~ ^[0-9a-z] ]] && postconf -P "${LINE}"
postconf -P "${LINE}" done < <(_get_valid_lines_from_file "${OVERRIDE_CONFIG_POSTFIX_MASTER}")
fi __postfix__log 'trace' "Adjusted '/etc/postfix/master.cf' according to '${OVERRIDE_CONFIG_POSTFIX_MASTER}'"
done < /tmp/docker-mailserver/postfix-master.cf
__postfix__log 'trace' "Adjusted '/etc/postfix/master.cf' according to '/tmp/docker-mailserver/postfix-master.cf'"
else else
__postfix__log 'trace' "No extra Postfix settings loaded because optional '/tmp/docker-mailserver/postfix-master.cf' was not provided" __postfix__log 'trace' "No extra Postfix settings loaded because optional '${OVERRIDE_CONFIG_POSTFIX_MASTER}' was not provided"
fi fi
} }

View File

@ -102,7 +102,6 @@ function _init_with_defaults() {
# The config volume cannot be read-only as some data needs to be written at container startup # The config volume cannot be read-only as some data needs to be written at container startup
# #
# - two sed failures (unknown lines)
# - dovecot-quotas.cf (setup-stack.sh:_setup_dovecot_quotas) # - dovecot-quotas.cf (setup-stack.sh:_setup_dovecot_quotas)
# - postfix-aliases.cf (setup-stack.sh:_setup_postfix_aliases) # - postfix-aliases.cf (setup-stack.sh:_setup_postfix_aliases)
# TODO: Check how many tests need write access. Consider using `docker create` + `docker cp` for easier cleanup. # TODO: Check how many tests need write access. Consider using `docker create` + `docker cp` for easier cleanup.

View File

@ -70,3 +70,45 @@ SOURCE_BASE_PATH="${REPOSITORY_ROOT:?Expected REPOSITORY_ROOT to be set}/target/
assert_failure assert_failure
assert_output --partial "ENV var name must be provided to _env_var_expect_integer" assert_output --partial "ENV var name must be provided to _env_var_expect_integer"
} }
@test '(utils.sh) _convert_crlf_to_lf_if_necessary' {
# shellcheck source=../../../../../target/scripts/helpers/log.sh
source "${SOURCE_BASE_PATH}/log.sh"
# shellcheck source=../../../../../target/scripts/helpers/utils.sh
source "${SOURCE_BASE_PATH}/utils.sh"
# Create a temporary file in the BATS test-case folder:
local TMP_DMS_CONFIG=$(mktemp -p "${BATS_TEST_TMPDIR}" -t 'dms_XXX.cf')
# A file with mixed line-endings including CRLF:
echo -en 'line one\nline two\r\n' > "${TMP_DMS_CONFIG}"
# Confirm CRLF detected:
run file "${TMP_DMS_CONFIG}"
assert_output --partial 'CRLF'
# Helper method detects and fixes:
_convert_crlf_to_lf_if_necessary "${TMP_DMS_CONFIG}"
run file "${TMP_DMS_CONFIG}"
refute_output --partial 'CRLF'
}
@test '(utils.sh) _append_final_newline_if_missing' {
# shellcheck source=../../../../../target/scripts/helpers/log.sh
source "${SOURCE_BASE_PATH}/log.sh"
# shellcheck source=../../../../../target/scripts/helpers/utils.sh
source "${SOURCE_BASE_PATH}/utils.sh"
# Create a temporary file in the BATS test-case folder:
local TMP_DMS_CONFIG=$(mktemp -p "${BATS_TEST_TMPDIR}" -t 'dms_XXX.cf')
# A file missing a final newline:
echo -en 'line one\nline two' > "${TMP_DMS_CONFIG}"
# Confirm missing newline:
run bash -c "tail -c 1 '${TMP_DMS_CONFIG}' | wc -l"
assert_output '0'
# Helper method detects and fixes:
_append_final_newline_if_missing "${TMP_DMS_CONFIG}"
run bash -c "tail -c 1 '${TMP_DMS_CONFIG}' | wc -l"
assert_output '1'
}