diff --git a/contrib/debian/build-trixie-bundle.sh b/contrib/debian/build-trixie-bundle.sh index 8dab923..752656d 100755 --- a/contrib/debian/build-trixie-bundle.sh +++ b/contrib/debian/build-trixie-bundle.sh @@ -307,6 +307,11 @@ for requirement in \ die "$package: expected $expected after Bongo install, found $actual" done +set -- "$BUILDS"/bongo_"${BONGO_DEBIAN_VERSION}"_*.deb +[ "$#" -eq 1 ] || die "expected exactly one Bongo binary package" +"$BONGO_BUILD_DIR/debian/tests/package-lifecycle" "$1" \ + "$WORK_DIR/package-lifecycle" + copy_artifacts "$BUILDS" "$BUNDLE/sources/bongo" \ "bongo_${BONGO_DEBIAN_VERSION}*.dsc" \ "bongo_${BONGO_DEBIAN_VERSION}*.tar.*" \ diff --git a/debian/bongo.postinst b/debian/bongo.postinst index 87249c0..4b7a63f 100755 --- a/debian/bongo.postinst +++ b/debian/bongo.postinst @@ -7,9 +7,6 @@ if [ "$1" = configure ]; then elif ! getent passwd bongo >/dev/null 2>&1; then adduser --system --group --home /var/lib/bongo --no-create-home bongo fi - if command -v systemd-tmpfiles >/dev/null 2>&1; then - systemd-tmpfiles --create bongo.conf - fi fi #DEBHELPER# diff --git a/debian/tests/package-lifecycle b/debian/tests/package-lifecycle new file mode 100755 index 0000000..83114fb --- /dev/null +++ b/debian/tests/package-lifecycle @@ -0,0 +1,107 @@ +#!/bin/sh +set -eu + +package_file=${1:?usage: package-lifecycle /path/to/bongo.deb} +work_dir=${2:-/tmp/bongo-package-lifecycle} + +die() +{ + echo "package-lifecycle: $*" >&2 + exit 1 +} + +assert_marker() +{ + path=$1 + expected=$2 + [ -f "$path" ] || die "state marker disappeared: $path" + actual=$(cat "$path") + [ "$actual" = "$expected" ] || + die "state marker changed: $path" +} + +assert_state() +{ + assert_marker /etc/bongo/config.d/lifecycle-test \ + configuration-preserved + assert_marker /etc/bongo/ssl.d/lifecycle-test.key \ + private-key-preserved + assert_marker /var/lib/bongo/users/lifecycle-test/message \ + user-mail-preserved + assert_marker /var/lib/bongo/system/lifecycle-test \ + system-store-preserved + assert_marker /var/lib/bongo/spool/lifecycle-test \ + queue-state-preserved +} + +[ "$(id -u)" -eq 0 ] || die "this test must run as root" +[ -f "$package_file" ] || die "package not found: $package_file" +[ "$(dpkg-deb -f "$package_file" Package)" = bongo ] || + die "not a bongo binary package: $package_file" + +version=$(dpkg-deb -f "$package_file" Version) +architecture=$(dpkg-deb -f "$package_file" Architecture) +upgrade_version="${version}+lifecycle1" + +rm -rf "$work_dir" +mkdir -p "$work_dir/unpacked" + +install -d -m 0750 -o root -g bongo \ + /etc/bongo/config.d /etc/bongo/ssl.d +install -d -m 0750 -o bongo -g bongo \ + /var/lib/bongo/users/lifecycle-test \ + /var/lib/bongo/system /var/lib/bongo/spool +printf '%s\n' configuration-preserved > \ + /etc/bongo/config.d/lifecycle-test +printf '%s\n' private-key-preserved > \ + /etc/bongo/ssl.d/lifecycle-test.key +chmod 0640 /etc/bongo/ssl.d/lifecycle-test.key +printf '%s\n' user-mail-preserved > \ + /var/lib/bongo/users/lifecycle-test/message +printf '%s\n' system-store-preserved > \ + /var/lib/bongo/system/lifecycle-test +printf '%s\n' queue-state-preserved > \ + /var/lib/bongo/spool/lifecycle-test +chown -R bongo:bongo /var/lib/bongo/users/lifecycle-test \ + /var/lib/bongo/system/lifecycle-test \ + /var/lib/bongo/spool/lifecycle-test + +# A same-version reinstall must leave administrator configuration, keys, +# mailboxes, Store data, and a possibly non-empty queue untouched. +apt-get install --reinstall -y "$package_file" +assert_state + +# Repack the identical payload with a higher test-only version. This exercises +# dpkg's real upgrade maintainer-script path without publishing a fake release. +dpkg-deb --raw-extract "$package_file" "$work_dir/unpacked" +sed -i "s/^Version: .*/Version: ${upgrade_version}/" \ + "$work_dir/unpacked/DEBIAN/control" +upgrade_package="$work_dir/bongo_${upgrade_version}_${architecture}.deb" +dpkg-deb --root-owner-group --build "$work_dir/unpacked" "$upgrade_package" +apt-get install -y "$upgrade_package" +[ "$(dpkg-query -W -f='${Version}' bongo)" = "$upgrade_version" ] || + die "test upgrade version was not installed" +assert_state + +# Normal removal deletes programs while retaining Debian conffiles and all +# site-created configuration and persistent state. +apt-get remove -y bongo +[ ! -e /usr/sbin/bongo-manager ] || + die "program payload remained after package removal" +[ -f /etc/fail2ban/filter.d/bongo-auth.conf ] || + die "Debian conffile disappeared during normal removal" +assert_state + +# Purge removes package-owned conffiles, but deliberately does not destroy +# setup-generated keys/configuration or mail and Store state. +apt-get purge -y bongo +[ ! -e /etc/fail2ban/filter.d/bongo-auth.conf ] || + die "package-owned Fail2ban conffile remained after purge" +[ ! -e /etc/fail2ban/jail.d/bongo-auth.conf ] || + die "package-owned Fail2ban jail remained after purge" +if dpkg-query -W bongo >/dev/null 2>&1; then + die "package database entry remained after purge" +fi +assert_state + +echo "package-lifecycle: install/reinstall/upgrade/remove/purge passed" diff --git a/docs/directory-layout.md b/docs/directory-layout.md index ee950d0..78612c2 100644 --- a/docs/directory-layout.md +++ b/docs/directory-layout.md @@ -70,3 +70,21 @@ TLS, DKIM, DMARC and SRS material below `/etc/bongo` must be included in backup and permission reviews. ACME deployments may point configuration at paths managed by their deploy hook instead. Runtime credentials required to access the Store remain protected state below `/var/lib/bongo`. + +## Package removal and upgrades + +Distribution upgrades and same-version reinstalls preserve all +administrator-created configuration and key material below `/etc/bongo` and +all persistent mail, Store, queue, account, Web, and worker state below +`/var/lib/bongo`. + +On Debian, a normal package removal deletes Bongo programs and service units +but retains package-owned conffiles as well as both Bongo trees. A purge also +deletes the package-owned Fail2ban filter and disabled jail template. It still +does **not** delete `/etc/bongo` or `/var/lib/bongo`: destroying keys, server +configuration, queued messages, or user mail as a side effect of package +removal would be unsafe. Remove those two trees explicitly only after making +and verifying any required backup. + +`/run/bongo` contains no persistent state. Its contents can remain until the +next boot after a package removal and must never be relied upon for recovery.