77 lines
3.9 KiB
Bash
Executable File
77 lines
3.9 KiB
Bash
Executable File
#!/bin/bash
|
|
# Dovecot shared mailboxes. info@produktor.io gets access to the mailboxes of
|
|
# two owner classes (issue #79, issue #251 / epic #250):
|
|
# - production owners (ano@, andriy.oblivantsev@, postmaster@): read-only
|
|
# (`lookup read`) — one login in Roundcube covers the whole account list;
|
|
# - incubator owners: read + delete (`lookup read delete expunge
|
|
# write-deleted`) — the mailbox owner never logs in, mail is imported via
|
|
# doveadm; deleting a message in Roundcube = filter/exclusion from the
|
|
# corpus (autosync, epic B).
|
|
# Incubator model (corrected 2026-09-02, issue #252): the incubator mailbox IS
|
|
# the owner's HISTORICAL ADDRESS per period, not an abstract "source" mailbox.
|
|
# The wheregroup period = andriy.oblivantsev@wheregroup.com; later periods get
|
|
# their own account (eslider@gmail.com, ...@viscreation.de, ...). The A1 pilot
|
|
# box wheregroup@produktor.io (abstract "source" model) was deleted after its
|
|
# 1000 messages were migrated to the historical account — grant_share skips
|
|
# owners that are not (yet) in postfix-accounts.cf, so a not-yet-created
|
|
# account is a silent no-op.
|
|
# DMS runs this only on the FIRST start of each container instance (plain
|
|
# `docker compose restart` skips the setup step by design — /CONTAINER_START
|
|
# marker), so it must stay idempotent. ACLs, the shared dict and subscriptions
|
|
# persist in mail-state / maildirs across restarts.
|
|
set -euo pipefail
|
|
|
|
# 1. acl_shared_dict directory: must exist and be writable by the mail user.
|
|
SHARED_DB_DIR=/var/lib/dovecot/db
|
|
mkdir -p "${SHARED_DB_DIR}"
|
|
chown docker:docker "${SHARED_DB_DIR}"
|
|
chmod 0770 "${SHARED_DB_DIR}"
|
|
|
|
# 2. Grant info@ rights on every current mailbox of the shared owners.
|
|
# doveadm acl set is the only way Dovecot records the share in acl_shared_dict
|
|
# (manual dovecot-acl files do NOT populate the dictionary — Dovecot docs).
|
|
# NOTE: this Dovecot build accepts full right NAMES ("lookup read"), single
|
|
# letters ("lr") are rejected with "Invalid right". The incubator set below
|
|
# was verified on live (issue #251): `write-deleted` is enough for the
|
|
# \Deleted flag that Roundcube sets on Delete — the extra `write` right is
|
|
# NOT required; `expunge` is also what Dovecot MOVE needs on the source side
|
|
# when Roundcube moves a deleted message to Trash.
|
|
READER='info@produktor.io'
|
|
PRODUCTION_OWNERS='ano@produktor.io andriy.oblivantsev@produktor.io postmaster@produktor.io'
|
|
INCUBATOR_OWNERS='andriy.oblivantsev@wheregroup.com'
|
|
|
|
grant_share() { # $1=owner, remaining=right names
|
|
local owner=$1
|
|
shift
|
|
# Skip owners not (yet) in postfix-accounts.cf — e.g. right after a fresh
|
|
# clone, before `setup email add` was run for the incubator source.
|
|
if ! doveadm mailbox list -u "${owner}" >/dev/null 2>&1; then
|
|
echo "user-patches: skip ${owner}: account does not exist yet (run 'setup email add ${owner}')"
|
|
return 0
|
|
fi
|
|
# The shared mailbox "shared/<owner>" maps to the owner's INBOX (Dovecot
|
|
# shared-storage semantics) — subscribe it explicitly so Roundcube's
|
|
# subscribed folder list shows it.
|
|
doveadm mailbox subscribe -u "${READER}" "shared/${owner}"
|
|
# A brand-new mailbox owner has no INBOX yet and `doveadm mailbox list`
|
|
# above would be empty, so no share would be recorded. Ensure INBOX exists
|
|
# first (issue #251); "Mailbox already exists" is fine.
|
|
doveadm mailbox create -u "${owner}" INBOX >/dev/null 2>&1 || true
|
|
for mb in $(doveadm mailbox list -u "${owner}"); do
|
|
doveadm acl set -u "${owner}" "${mb}" "user=${READER}" "$@"
|
|
if [ "${mb}" != "INBOX" ]; then
|
|
doveadm mailbox subscribe -u "${READER}" "shared/${owner}/${mb}"
|
|
fi
|
|
done
|
|
}
|
|
|
|
# Production owners stay read-only for info@ (regression guard for #79).
|
|
for owner in ${PRODUCTION_OWNERS}; do
|
|
grant_share "${owner}" lookup read
|
|
done
|
|
|
|
# Incubator owners: info@ can read AND delete (filter semantics, epic #250).
|
|
for owner in ${INCUBATOR_OWNERS}; do
|
|
grant_share "${owner}" lookup read delete expunge write-deleted
|
|
done
|