From 8034a9306ea86a385d1dff276facaab7834080d4 Mon Sep 17 00:00:00 2001 From: mixeme Date: Sun, 9 Aug 2026 10:22:50 +0300 Subject: [PATCH] fix(postfix): root-own TLS copies for postfix check CI showed postfix check failing after all postconf stages with the key owned by host UID 1001 on a :ro mount. Copy cert/key into /etc/postfix/tls-internal as root:root mode 644/600 before configuring Postfix; keep step logs for verification. Co-Authored-By: Composer Co-authored-by: Cursor --- CHANGELOG.md | 7 +++++++ build/postfix-config.sh | 39 +++++++++++++++++++++++++++++++++------ 2 files changed, 40 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1c423c6..a946f5f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,13 @@ Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/); version ## [Unreleased] +### Fixed + +- Postfix config: copy TLS cert/key from the (often `:ro`, host-owned) mount + into `/etc/postfix/tls-internal` as `root:root` before `postconf` / + `postfix check`. Bind-mounted keys owned by the CI/host UID made + `postfix check` fail and the container exit before supervisord started. + ## [1.0.0] - 2026-08-09 ### Added diff --git a/build/postfix-config.sh b/build/postfix-config.sh index b4f155c..0b2be06 100644 --- a/build/postfix-config.sh +++ b/build/postfix-config.sh @@ -29,8 +29,27 @@ HOSTNAME_VALUE="${SELFPOST_HOSTNAME:-$(hostname -f 2>/dev/null || hostname)}" # TLS material supplied by the reverse-proxy through a read-only bind mount # (spec 5.2). The relay requires TLS on 465; if these files are absent the # master still starts but TLS handshakes on 465 fail until they appear. -TLS_CERT="${TLS_CERT_FILE:-/etc/postfix/tls/fullchain.pem}" -TLS_KEY="${TLS_KEY_FILE:-/etc/postfix/tls/privkey.pem}" +# +# Postfix insists the private key is root-owned and mode 0600. The bind mount +# is often :ro and owned by the host user (e2e TempDir / CI runner UID 1001), +# so copy into a writable internal dir and normalise ownership before postconf +# and `postfix check` — otherwise check fails and the container never reaches +# supervisord (CI: "postfix check failed" after all postconf stages). +TLS_CERT_SRC="${TLS_CERT_FILE:-/etc/postfix/tls/fullchain.pem}" +TLS_KEY_SRC="${TLS_KEY_FILE:-/etc/postfix/tls/privkey.pem}" +TLS_INTERNAL_DIR=/etc/postfix/tls-internal +TLS_CERT="$TLS_CERT_SRC" +TLS_KEY="$TLS_KEY_SRC" +if [ -f "$TLS_CERT_SRC" ] && [ -f "$TLS_KEY_SRC" ]; then + mkdir -p "$TLS_INTERNAL_DIR" + cp -f "$TLS_CERT_SRC" "$TLS_INTERNAL_DIR/fullchain.pem" + cp -f "$TLS_KEY_SRC" "$TLS_INTERNAL_DIR/privkey.pem" + chown root:root "$TLS_INTERNAL_DIR/fullchain.pem" "$TLS_INTERNAL_DIR/privkey.pem" + chmod 0644 "$TLS_INTERNAL_DIR/fullchain.pem" + chmod 0600 "$TLS_INTERNAL_DIR/privkey.pem" + TLS_CERT="$TLS_INTERNAL_DIR/fullchain.pem" + TLS_KEY="$TLS_INTERNAL_DIR/privkey.pem" +fi # Level-1 rate limit (native Postfix anvil, spec 5 p.5 / 7.4). Conservative # defaults, sensible during IP warm-up (spec 10). @@ -214,8 +233,16 @@ EOF # Validate the generated configuration; fail loudly if postconf produced # anything Postfix rejects, before the wrapper tries to start it. pcstep "postfix check" -if ! postfix check; then - echo "postfix-config: postfix check failed exit $?" >&2 - exit 1 +set +e +check_out=$(postfix check 2>&1) +ec=$? +set -e +if [ "$ec" -ne 0 ]; then + echo "postfix-config: postfix check failed exit $ec" >&2 + echo "postfix-config: --- check output ---" >&2 + printf '%s\n' "$check_out" >&2 + echo "postfix-config: --- mail.log ---" >&2 + cat "$MAIL_LOG_PATH" 2>&1 >&2 || true + exit "$ec" fi -pcstep "done" +pcstep "done tls=$(ls -la "$TLS_CERT" "$TLS_KEY" 2>&1 || true)"