base-trixie: the image on Debian trixie, Postfix 3.10.13; Received: hidden on 465/587
test / test (push) Canceled after 0s

The runtime base is debian:trixie-slim, the build stage golang:1.26-trixie:
Postfix 3.10.13 with upstream's 2026 security fixes up to the August
batch, libmilter 8.18.1, OpenSSL 3.5. Every citation of another program in
code, scripts and documents was re-read against the trixie sources
(dev/upstream; bookworm's kept in dev/upstream-bookworm) and updated;
development.md's cited-package table holds the trixie versions.

What the re-reading changed in behaviour:
- logtail: reject lines with sasl_method/sasl_username/sasl_sender
  (smtpd_check.c:1019-1026); cleanup's "removed (canceled)" forgets a
  port-25 id (cleanup_api.c:363-364).
- internal/postfix/retry.go reads postconf's stdout only: since 3.9 a
  deprecated-parameter warning on stderr made one value too many and the
  panel fell back to the compiled-in retry policy.
- logrotate-loop.sh: logrotate 3.22 exits 1 when it ignores a config;
  the loop refuses on that output whatever the status.
- postfix-config.sh: cyrus_sasl_config_path set explicitly (bookworm's
  07_sasl_config.diff is gone); maillog_file_permissions=0640; mynetworks
  explicit; Dockerfile: SYNC_CHROOT= in /etc/default/postfix,
  opendkim-tools dropped, openssl named, systemd-standalone-sysusers so
  cron does not bring the whole of systemd.
- The selfpost group is 10998, outside the system range 100-999: in
  trixie a package took 998 and the build failed (owner's decision:
  a conflict-free id, the distribution's own ids untouched). The
  entrypoint hands /data back by name when the user or the group differs.
  Guide, backup refusal text, help (design commit 68ec8b2), e2e.
- smtpd_hide_client_session=yes on smtps and submission (owner's
  decision): Received: names no client, TLS, login or protocol; port 25
  keeps the full header. e2e checks both.
- test/upstream/opendkim-probe.sh makes keys with openssl genrsa.

Tests: on the server, make e2e exit 0 (674 s, the image built on trixie),
go vet + go test 27 packages ok. CHANGELOG [Unreleased], guide,
architecture.md, security.md, roadmap.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
mix
2026-10-15 19:31:35 +03:00
co-authored by Claude Opus 5.5
parent 68ec8b274c
commit 1c6e04b7d3
80 changed files with 970 additions and 454 deletions
+23 -16
View File
@@ -70,8 +70,13 @@ chmod 755 /data
# under /data; make sure they stay writable without disturbing anything that a
# later phase deliberately hands to another service. /data/log is exempt: it is
# deliberately owned by postfix (postlogd writes the delivery log there) and is
# normalised on its own below.
find /data -mindepth 1 -maxdepth 1 ! -user panel ! -name log ! -name postfix -exec chown -R panel:panel {} +
# normalised on its own below, as are the trees shared through group selfpost.
# A file's owner is a number: an entry whose user or group is not the panel's
# by that number - unpacked by root, or written under another image whose
# useradd gave the panel other ids (bookworm's 999:999, until 2.7.0) - is
# handed over whole.
find /data -mindepth 1 -maxdepth 1 ! -name log ! -name postfix ! -name opendkim ! -name sasl ! -name antispam \
\( ! -user panel -o ! -group panel \) -exec chown -R panel:panel {} +
# DKIM key tree. The panel (user `panel`) generates keys and writes
# the OpenDKIM tables; OpenDKIM (user `opendkim`) must read them. Normalise the
@@ -133,7 +138,7 @@ chmod 2750 /data/postfix
# so the directory and its files are readable by anyone: they hold sender
# addresses and networks, no secrets.
mkdir -p /data/antispam
chown panel:selfpost /data/antispam
chown -R panel:selfpost /data/antispam
chmod 0755 /data/antispam
# Delivery log (architecture.md § Log tailer). postlogd writes it as user
@@ -141,17 +146,19 @@ chmod 0755 /data/antispam
# lives under /data — not the ephemeral /var/log — so the delivery lines that
# resolve a "queued" send-log row survive a container recreate.
#
# postlogd creates a missing log itself, but at 0600, which the unprivileged
# panel cannot read; so create it here (and re-normalise an existing one, plus
# whatever logrotate left behind) at 0640 owned postfix:selfpost. The setgid
# postlogd creates a missing log itself, by default at 0600, which the
# unprivileged panel cannot read (postfix-config.sh now asks it for 0640,
# maillog_file_permissions); so create it here (and re-normalise an existing
# one, plus whatever logrotate left behind) at 0640 owned postfix:selfpost. The setgid
# directory keeps the shared group on anything created inside it later, and
# 2750 keeps it group-traversable but not group-writable — logrotate refuses to
# rotate a log whose directory is writable by a non-root group.
# Postfix 3.7.11: src/util/logwriter.c, logwriter_open_or_die(), creates the
# file 0644, under master's umask(077) (src/master/master.c) - 0600. logrotate
# 3.21.0, logrotate.c, findNeedRotating(): "skipping ... because parent
# directory has insecure permissions" when the directory's group is not root
# and has write permission.
# Postfix 3.10.13: src/util/logwriter.c:99, logwriter_open_or_die(), creates the
# file with logwriter_perms, 0600 (:86) unless maillog_file_permissions says
# otherwise (proto/postconf.proto:18500, default 0600; Postfix 3.9 and later).
# logrotate 3.22.0, logrotate.c:1406-1408, findNeedRotating(): "skipping ...
# because parent directory has insecure permissions" when the directory's
# group is not root and has write permission.
mkdir -p /data/log
[ -e /data/log/mail.log ] || : > /data/log/mail.log
chown -R postfix:selfpost /data/log
@@ -199,8 +206,8 @@ ln -sfn /run/syslog/log /dev/log
# The queue tree, on a first start or after a restore, is already built here:
# postfix-config.sh ends with "postfix check", whose check-fatal runs
# "post-install create-missing" (Postfix 3.7.11, conf/postfix-script;
# conf/postfix-files, "$queue_directory/active:d:$mail_owner:-:700:ucr").
# "post-install create-missing" (Postfix 3.10.13, conf/postfix-script:314;
# conf/postfix-files:55, "$queue_directory/active:d:$mail_owner:-:700:ucr").
# A "postfix set-permissions" for a missing active/ stood here and never ran
# (assumptions C-P34).
chown -R postfix:postfix /data/postfix/queue
@@ -214,10 +221,10 @@ chgrp postdrop /data/postfix/queue/public /data/postfix/queue/maildrop
# It would also leave the queue directory itself and pid/ owned by postfix.
# Postfix keeps those two owned by root (master, which runs as root, is the only
# writer) and logs "warning: not owned by root" for each at every start.
# (Postfix 3.7.11, conf/postfix-files: $queue_directory root 755, maildrop
# (Postfix 3.10.13, conf/postfix-files:51-68: $queue_directory root 755, maildrop
# $setgid_group 730, public $setgid_group 710, pid root 755, the other queue
# directories $mail_owner 700; conf/postfix-script, "check-warn": "not owned by
# root".)
# directories $mail_owner 700; conf/postfix-script:354-356, "check-warn": "not
# owned by root".)
chown root /data/postfix/queue /data/postfix/queue/pid
# [program:postfix]'s startsecs (build/supervisord.conf): longer than the