main
3
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
faa3c11ae7 |
panel-dkim-signing stage 2: OpenDKIM removed
test / test (push) Waiting to run
The panel's signer is the only one. Gone: the opendkim package and its
configuration, the syslog-relay and opendkim programs, /dev/log and
/run/opendkim, the reload by USR1 through supervisord
(internal/supervisor/supervisor.go), internal/syslogrelay, the port of
OpenDKIM's From: parser (internal/milter/mailparse.go and its probe,
harness and test/upstream scripts), OPENDKIM_SOCKET and OPENDKIM_DIR.
Keys: internal/domain/keys.go (Keys, NewKeys, DKIM_DIR=/data/dkim) keeps
the keys and writes a selector table, /data/dkim/selectors ("<name>
<selector>"), which the signer reads in place of the KeyTable - it reads
no database, as the sender check reads none. The table is written before
the signer serves (EnsureServerSigned moved there from the notifier).
Keys and table 0600, directories 0700, the panel's. The entrypoint copies
/data/opendkim/keys once, as the panel user, into /data/dkim.new renamed
when whole, and stops the start if the copy fails; /data/opendkim is left
for a rollback to 2.7.x.
Sender check: one RFC 5322 address as a mail program reads it, held
against the bindings; the 256-byte refusal and the texts naming OpenDKIM
go. Allowed() folded the domain through strings.ToLower, which makes the
Kelvin sign a "k" - the comparison with OpenDKIM's reading had hidden it;
it folds ASCII only now.
Health: two dkim-signer rows (applications, notifications) in Milter
sockets, opendkim out of the liveness set; the card no longer takes any
row with a note for the spam filter. Texts as in the design commit.
KILL stays in deploy/docker-compose.yml: measured on the test server,
root without it cannot signal a process of another uid - supervisord
stopping the panel, Postfix's master its children. The plan's "only use
was the reload" was wrong; the comment now gives the real uses.
e2e: one signature, the panel's, verified by dkimpy; the /data/dkim modes;
the OpenDKIM log and process checks, testNeverSignedForAnother and the
cited opendkim, libopendkim11 and libmilter1.0.1 go.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
||
|
|
1c6e04b7d3 |
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
|
||
|
|
f2ad699473 |
supervision as supervisord does it: Postfix stopped, give-ups FATAL, reload's exit read
test / test (push) Canceled after 0s
C-P42. postfix-script's start-fg runs master as its child and master calls setsid() (Postfix 3.7.11, conf/postfix-script; src/master/master.c); supervisord signals the pid alone (supervisor 4.2.5, process.py, Subprocess.kill()). A stop of program postfix left master running - a restart then found "already running" - and a container stop cut Postfix off with SIGKILL. The wrapper now stays the parent of "postfix start-fg" and on TERM/INT runs "postfix stop", asking again while start-fg is still in its checks (master -t). stopwaitsecs=15. C-V6. The wrapper's give-up on the milter sockets came after the default startsecs, so it was EXITED and restarted for ever. startsecs is now MILTER_WAIT_TIMEOUT + 10, exported by the entrypoint as POSTFIX_STARTSECS and expanded by supervisord (options.py, processes_from_section(); a non-number MILTER_WAIT_TIMEOUT stops the start): a give-up is "Exited too quickly", BACKOFF, FATAL after startretries, crashexit. For those seconds after each start the program is STARTING (the healthcheck's 90 s start period covers it; the sender check counts no downtime then). C-V5. logrotate had startsecs=0, so a refused config restarted it every second for ever. startsecs=1: FATAL after startretries; crashexit reads the event's processname and leaves logrotate's FATAL on Server > Health. B-U2. "supervisorctl start" returns when a startsecs=0 program is RUNNING, not when it ends, and mapped "already started" to success. The panel now speaks supervisord's XML-RPC itself (internal/supervisor, RunOnce): startProcess without waiting, getProcessInfo until it leaves STARTING/RUNNING, exitstatus 0 or an error; a run in progress is waited out and one of its own follows. A failed reload while program postfix is not RUNNING is logged, not an error: the next master reads the files. C-V10: postfix-reload rests EXITED after a run; the e2e process check takes STOPPED or EXITED. C-P34: the dead "postfix set-permissions" branch goes - postfix check's create-missing builds the queue tree. Stand (2026-10-14, make e2e, exit 0; MILTER_WAIT_TIMEOUT=10 on the stand): new supervision_stops_postfix_and_gives_up - supervisorctl restart postfix writes postfix-script's "stopping the Postfix mail system" and leaves one master; with the panel's sockets removed, start answers "postfix: ERROR (spawn error)" (finish() sets spawnerr "Exited too quickly", onwait() reads it first) and Postfix comes up once the panel is back; a group-writable logrotate config ends FATAL with the container up; the panel's Reload configuration answers only after mail.log has "refreshing the Postfix mail system", postfix-reload EXITED. session_survives_restart sees the stop line for the container's restart. Measured: master's own "terminating on signal 15" never reaches mail.log (master TERMs its group, postlogd included, before it logs). go vet and go test ./... pass on the server (24 packages; new unit tests of RunOnce against a fake supervisord). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |