mailu (full email stack). TLS_FLAVOR=notls avoids certdumper/ACME dep (cc-ci file-provider cert); MAIL_DOMAIN/HOSTNAMES=run domain; TRAEFIK_STACK_NAME for the letsencrypt-volume mount. P2 vacuous (no corpus). P3: test_mailbox (flask mailu user create + config-export read-back), test_imap_login (mailbox authenticates over dovecot IMAP:143), test_mail_flow (SMTP submission send → IMAP retrieve, auth to avoid greylisting). P4 N/A (no backupbot label) — DEFERRED.md + PARITY.md, Adversary §7.1 sign-off pending. Smoke-validated: 8 services converge, mail ports 25/587/143/993 host-open, flask CLI. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
40 lines
2.9 KiB
Markdown
40 lines
2.9 KiB
Markdown
# mailu — recipe-maintainer → cc-ci parity (Phase 2 P2)
|
|
|
|
**P2 is VACUOUS for mailu:** there is no `recipe-info/mailu/tests/` corpus in the recipe-maintainer
|
|
workspace (`/srv/recipe-maintainer`), so there are no recipe-maintainer tests to port. Coverage is
|
|
therefore health + recipe-specific functional tests (P3), authored from what mailu *is* (a full
|
|
email stack: nginx front + admin + postfix/smtp + dovecot/imap + rspamd/antispam + webmail + redis).
|
|
|
|
## cc-ci deployment notes
|
|
- `COMPOSE_FILE=compose.yml` (base). recipe_meta.EXTRA_ENV(domain) pins `MAIL_DOMAIN`/`HOSTNAMES` to
|
|
the per-run domain, `TRAEFIK_STACK_NAME=traefik_ci_commoninternet_net` (so the external
|
|
`*_letsencrypt` volume the certdumper mounts resolves), and **`TLS_FLAVOR=notls`** — mailu's
|
|
mail-port TLS normally comes from `certdumper` dumping traefik's ACME `acme.json`, but cc-ci uses a
|
|
file-provider wildcard cert (no ACME), so there is no acme.json; `notls` removes that dependency.
|
|
(certdumper still runs idle; harmless — it converges 1/1.) Web/admin is served over the real
|
|
wildcard TLS via Traefik. Mail ports 25/465/587/110/143/993/995 are published mode:host → on-host
|
|
(cc-ci-run) tests reach SMTP/IMAP at 127.0.0.1.
|
|
|
|
## Recipe-specific functional tests (P3 — ≥2; here 3)
|
|
1. `functional/test_mailbox.py` — §4.3 create-an-object + read-back: create a mailbox via the admin
|
|
container's `flask mailu user` CLI, then read it back from `flask mailu config-export --json` and
|
|
assert the address is present (admin-DB provisioning round-trip).
|
|
2. `functional/test_imap_login.py` — distinctive (working mail account): the provisioned mailbox
|
|
AUTHENTICATES against dovecot over IMAP (127.0.0.1:143) and SELECTs its INBOX — proving the
|
|
account is real end-to-end (admin → dovecot auth), not just a DB row.
|
|
3. `functional/test_mail_flow.py` — the characteristic end-to-end flow: SEND a uniquely-marked
|
|
message to the mailbox over SMTP (authenticated submission to avoid rspamd greylisting), then
|
|
RETRIEVE it over IMAP and assert the marker arrived (postfix → rspamd → dovecot deliver/store/fetch).
|
|
|
|
## Backup data-integrity (P4) — N/A (recipe ships no backup config)
|
|
The upstream mailu recipe declares **no `backupbot.backup` label** on any service, so the cc-ci
|
|
backup/restore tiers cleanly SKIP (`backup_capable=False`). There is no recipe backup mechanism to
|
|
exercise — P4 is genuinely N/A for mailu as published, not a cut corner. The durable fix (if P4
|
|
coverage is wanted) is a recipe-PR adding backupbot labels (mailu admin sqlite at /data + mail
|
|
volume), filed as a deferral mirroring the immich Q3.5 / Q3.2b pattern — see DEFERRED.md. Pending
|
|
Adversary §7.1 sign-off on the N/A.
|
|
|
|
## Browser flow (P6)
|
|
Not added: mailu's user-facing UX (webmail/admin) is a standard web UI; the characteristic behaviour
|
|
(mail send/receive, account auth) is covered functionally above. No Playwright flow owed.
|