Harden mm3-hk-export: safe handoff, no-cred policy lookup, gated destroy
Address three hardening findings: - Gate the README backup-and-destroy loop so `mailman-wrapper remove` only runs after both the export and member dump succeed; a failed backup now leaves the list intact instead of falling through to an irreversible delete. Empty/no-archive lists still pass (exit 0 by design), so only real failures block removal. - Replace the curl/REST archive_policy lookup with `mailman-wrapper shell`, reading archive_policy straight from core's DB via getUtility(IListManager). Eliminates REST credential handling entirely (no secret in argv / /proc), drops the curl dependency, and removes the @->. list-id conversion. - Make the final publish a safe privilege handoff: reject non-regular / symlinked temp files, copy the web-user mkstemp output into a root-owned temp file on the destination filesystem, chmod 600, then atomically rename into place. Fixes inherited web-user ownership and the cross-filesystem mv that could leave a partial or clobbered backup.
This commit is contained in:
parent
f7a9714e93
commit
c2b304e4a9
2 changed files with 62 additions and 27 deletions
25
README.md
25
README.md
|
|
@ -23,9 +23,10 @@ separate from Mailman **core**. That is why the export must go through
|
|||
(Django site at `/usr/share/mailman3-web/`, HyperKitty installed).
|
||||
- Run as **root**: `mailman-web` drops privileges to the web user to read the
|
||||
archive, and the script (as root) moves the finished file into place.
|
||||
- Optional, only to enrich the "not archived" notice: `curl` and the
|
||||
`mailman-wrapper` core CLI (for a best-effort `archive_policy` lookup over the
|
||||
core REST API). Missing either just falls back to a generic message.
|
||||
- Optional, only to enrich the "not archived" notice: the `mailman-wrapper`
|
||||
core CLI (for a best-effort `archive_policy` lookup via `mailman shell`,
|
||||
reading core's DB directly, no REST, no credentials). Missing it just falls
|
||||
back to a generic message.
|
||||
|
||||
## Usage
|
||||
|
||||
|
|
@ -64,14 +65,22 @@ output on stderr.
|
|||
mkdir -p /root/mm3
|
||||
for list in list1 list2; do
|
||||
addr="$list@domain.tld"
|
||||
mm3-hk-export "$addr" "/root/mm3/$list.mbox" # skips cleanly if no archive
|
||||
mailman-wrapper members "$addr" > "/root/mm3/$list"
|
||||
mailman-wrapper remove "$addr"
|
||||
# Only destroy a list once BOTH the archive export and the member dump
|
||||
# succeed. mm3-hk-export exits 0 (writing no file) for a list with no
|
||||
# archive, so &&-gating still lets genuinely-empty lists through — it only
|
||||
# blocks remove on a real failure (mailman-web error, disk full, bad mv).
|
||||
if mm3-hk-export "$addr" "/root/mm3/$list.mbox" \
|
||||
&& mailman-wrapper members "$addr" > "/root/mm3/$list.members"; then
|
||||
mailman-wrapper remove "$addr"
|
||||
else
|
||||
echo "mm3-hk-export: backup FAILED for $addr — leaving list intact" >&2
|
||||
fi
|
||||
done
|
||||
```
|
||||
|
||||
Export before `remove`. (HyperKitty's archive lives in a separate database and
|
||||
is not deleted by core's `remove`, but exporting first keeps the intent clear.)
|
||||
Export before `remove`, and never `remove` on a failed backup. (HyperKitty's
|
||||
archive lives in a separate database and is not deleted by core's `remove`, but
|
||||
a failed export must still halt the destroy step.)
|
||||
|
||||
## Caveats
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue