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:**
- 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)
### 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');
}
/* 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 */
font-family: 'external-link';
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 */
margin-right: 4px;
}
/* ============================================================================================================= */
@ -98,3 +102,8 @@ div.md-content article.md-content__inner a.toclink code {
.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
- 'Tests': contributing/tests.md
- 'Issues and Pull Requests': contributing/issues-and-pull-requests.md
- '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>DockerHub': https://hub.docker.com/r/mailserver/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 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
-o syslog_name=postfix/sender-cleanup
-o header_checks=pcre:/etc/postfix/maps/sender_header_filter.pcre

View File

@ -19,16 +19,9 @@ function _create_accounts() {
_create_masters
if [[ -f ${DATABASE_ACCOUNTS} ]]; then
_log 'trace' "Checking file line endings"
sed -i 's|\r||g' "${DATABASE_ACCOUNTS}"
_log 'trace' "Regenerating postfix user list"
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}"
chmod 640 "${DOVECOT_USERDB_FILE}"
@ -158,15 +151,8 @@ function _create_masters() {
local DATABASE_DOVECOT_MASTERS='/tmp/docker-mailserver/dovecot-masters.cf'
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"
# 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}"
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
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
else
_log 'debug' "'${DATABASE_VIRTUAL}' not provided - no mail alias/forward created"

View File

@ -15,14 +15,19 @@ function __do_as_rspamd_user() {
# they cannot be modified. Use this function when you require common directory
# names, file names, etc.
function _rspamd_get_envs() {
readonly RSPAMD_LOCAL_D='/etc/rspamd/local.d'
readonly RSPAMD_OVERRIDE_D='/etc/rspamd/override.d'
# 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_OVERRIDE_D='/etc/rspamd/override.d'
readonly RSPAMD_DMS_D='/tmp/docker-mailserver/rspamd'
readonly RSPAMD_DMS_DKIM_D="${RSPAMD_DMS_D}/dkim"
readonly RSPAMD_DMS_OVERRIDE_D="${RSPAMD_DMS_D}/override.d"
readonly RSPAMD_DMS_D='/tmp/docker-mailserver/rspamd'
readonly RSPAMD_DMS_DKIM_D="${RSPAMD_DMS_D}/dkim"
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.

View File

@ -17,9 +17,44 @@ function _escape_for_sed() {
# Returns input after filtering out lines that are:
# empty, white-space, comments (`#` as the first non-whitespace character)
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
}
# 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
# and it will return its value stored in /etc/dms-settings
function _get_dms_env_value() {

View File

@ -19,7 +19,7 @@ function _check_improper_restart() {
if [[ -f /CONTAINER_START ]]; then
_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
}

View File

@ -109,8 +109,9 @@ function _setup_postfix_late() {
function __postfix__setup_override_configuration() {
__postfix__log 'debug' 'Overriding / adjusting configuration with user-supplied values'
if [[ -f /tmp/docker-mailserver/postfix-main.cf ]]; then
cat /tmp/docker-mailserver/postfix-main.cf >>/etc/postfix/main.cf
local OVERRIDE_CONFIG_POSTFIX_MAIN='/tmp/docker-mailserver/postfix-main.cf'
if [[ -f ${OVERRIDE_CONFIG_POSTFIX_MAIN} ]]; then
cat "${OVERRIDE_CONFIG_POSTFIX_MAIN}" >>/etc/postfix/main.cf
_adjust_mtime_for_postfix_maincf
# 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
_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
__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
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
if [[ ${LINE} =~ ^[0-9a-z] ]]; then
postconf -P "${LINE}"
fi
done < /tmp/docker-mailserver/postfix-master.cf
__postfix__log 'trace' "Adjusted '/etc/postfix/master.cf' according to '/tmp/docker-mailserver/postfix-master.cf'"
[[ ${LINE} =~ ^[0-9a-z] ]] && postconf -P "${LINE}"
done < <(_get_valid_lines_from_file "${OVERRIDE_CONFIG_POSTFIX_MASTER}")
__postfix__log 'trace' "Adjusted '/etc/postfix/master.cf' according to '${OVERRIDE_CONFIG_POSTFIX_MASTER}'"
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
}

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
#
# - two sed failures (unknown lines)
# - dovecot-quotas.cf (setup-stack.sh:_setup_dovecot_quotas)
# - 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.

View File

@ -70,3 +70,45 @@ SOURCE_BASE_PATH="${REPOSITORY_ROOT:?Expected REPOSITORY_ROOT to be set}/target/
assert_failure
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'
}