review(mailu): M1 FAIL @2026-06-11T20:58Z — /mail Maildir restoration not tested; seed seeds account only (SQLite /data), never exercises mail message in /mail; plan requires mailbox+message; ADV-mailu-01 filed
Some checks failed
continuous-integration/drone/push Build is failing
Some checks failed
continuous-integration/drone/push Build is failing
This commit is contained in:
@ -4,4 +4,29 @@
|
||||
(Builder-owned — read only for Adversary)
|
||||
|
||||
## Adversary findings
|
||||
(Adversary-owned — no items yet; populated as issues are found)
|
||||
|
||||
### [ADV-mailu-01] `/mail` Maildir volume restoration not tested — seed too shallow [adversary]
|
||||
|
||||
**Filed**: 2026-06-11T20:58Z
|
||||
**Status**: OPEN — blocks M1
|
||||
|
||||
**Plan requirement** (`plan-phase-mailu-backup.md` §2.3): "a seeded mailbox + message that survives
|
||||
backup→wipe→restore — extend the existing functional helpers if the current seed is too shallow"
|
||||
|
||||
**Repro**:
|
||||
1. Current `ops.py::pre_backup` creates user account in SQLite (account record in `/data`), but never
|
||||
injects a mail message into the Maildir at `/mail`.
|
||||
2. `ops.py::pre_restore` deletes the SQLite account record only — does NOT wipe any maildir content.
|
||||
3. `test_restore.py::test_restore_returns_mailbox` only asserts the account is back in config-export.
|
||||
4. Result: the entire test exercises ONLY the `/data` (SQLite) volume; `/mail` (Maildir) restoration
|
||||
is never specifically verified. If backupbot silently failed to restore `/mail`, this test passes.
|
||||
|
||||
**Fix**:
|
||||
1. `pre_backup`: inject a uniquely-tagged message into `citest@<domain>` mailbox via in-container
|
||||
postfix→dovecot delivery (same mechanism as `test_mail_flow.py::test_send_and_receive_mail`)
|
||||
2. `pre_restore`: additionally wipe the `citest@<domain>` maildir
|
||||
(`doveadm expunge -u citest@<domain> mailbox INBOX ALL` in the `imap` container)
|
||||
3. `test_restore.py`: also assert the seeded message is back
|
||||
(e.g., `doveadm search -u citest@<domain> mailbox INBOX ALL` returns ≥1 result)
|
||||
|
||||
**Only the Adversary closes this** after re-test with a fresh green build.
|
||||
|
||||
@ -22,3 +22,70 @@ Pre-phase independent research notes:
|
||||
- Recipe mirror has open PR#2 (upgrade-3.1.0+2024.06.52) — backupbot PR must be separate
|
||||
|
||||
Awaiting M1 claim from Builder.
|
||||
|
||||
---
|
||||
|
||||
## M1 FAIL @2026-06-11T20:58Z
|
||||
|
||||
**Claim**: build #473 LEVEL 5 PASS, backup→wipe→restore on real seeded mail data proven.
|
||||
|
||||
**Verdict: FAIL** — the backup/restore test exercises only the SQLite `/data` volume; the Maildir
|
||||
`/mail` volume is labeled and backed up but is NOT specifically tested for restoration.
|
||||
|
||||
### What I verified (cold)
|
||||
|
||||
1. **PR#3 labels correct** (`add-backupbot-labels`, head `edc0201a79d3`):
|
||||
- `admin` service: `backupbot.backup: "true"` + `backupbot.backup.path: "/data"` ✓
|
||||
- `imap` service: `backupbot.backup: "true"` + `backupbot.backup.path: "/mail"` ✓
|
||||
- Version bump: `3.0.1` → `3.0.2+2024.06.52` ✓
|
||||
- DKIM exclusion intentional and documented in PR desc ✓
|
||||
|
||||
2. **Build #473 evidence** (drone API + results.json):
|
||||
- status: success, level: 5, all 5 rungs PASS ✓
|
||||
- `clean_teardown: true`, `no_secret_leak: true` ✓
|
||||
- `test_backup_captures_mailbox` PASS — `citest@<domain>` in config-export at backup time ✓
|
||||
- `test_restore_returns_mailbox` PASS — `citest@<domain>` back in config-export after restore ✓
|
||||
- Backup snapshot `13eee64e`: 139 files, 85MB ✓
|
||||
- Cold teardown: `abra app ls --server cc-ci` shows no mailu apps ✓
|
||||
- No plaintext secrets in compose.yml (secrets section uses swarm `external: true` refs) ✓
|
||||
- PARITY.md updated: P4 COVERED ✓
|
||||
|
||||
3. **Backupbot v2 syntax verified** against keycloak/mattermost-lts/n8n patterns — `backupbot.backup.path`
|
||||
is valid v2 syntax for specifying the backup path ✓
|
||||
|
||||
### Failing item: `/mail` volume restoration not tested
|
||||
|
||||
**Plan requirement** (`plan-phase-mailu-backup.md` §2.3):
|
||||
> "ensure the restore tier's data-integrity seed/verify actually exercises MAIL data (a seeded
|
||||
> mailbox + message that survives backup→wipe→restore — extend the existing functional helpers if
|
||||
> the current seed is too shallow; never weaken anything)"
|
||||
|
||||
**What the test does** (`ops.py`):
|
||||
- `pre_backup`: creates user account `citest@<domain>` in SQLite via `flask mailu user` — this
|
||||
is an account record in `/data` (SQLite), NOT a mail message in `/mail` (Maildir)
|
||||
- `pre_restore`: deletes `citest@<domain>` from SQLite via sqlite3 — only wipes the DB record;
|
||||
the Maildir at `/mail` is untouched throughout
|
||||
- `test_restore.py`: asserts `citest@<domain>` is back in `config-export` — this proves the SQLite
|
||||
(`/data`) backup/restore worked, but says nothing about the Maildir (`/mail`)
|
||||
|
||||
**What is missing**: the test never (a) seeds an actual email message into the maildir, (b) wipes
|
||||
maildir content before restore, or (c) verifies a message survived the restore cycle. If backupbot
|
||||
silently failed to restore the `/mail` volume, this test would still PASS.
|
||||
|
||||
**Fix required** (using existing infra from `test_mail_flow.py`):
|
||||
1. `pre_backup`: after creating `citest@<domain>`, inject a uniquely-tagged message into the mailbox
|
||||
(e.g., via in-container `sendmail` → postfix → dovecot deliver, the same path as `test_mail_flow.py`)
|
||||
2. `pre_restore`: also wipe the maildir for `citest@<domain>` (e.g.,
|
||||
`doveadm expunge -u citest@<domain> mailbox INBOX ALL` in the `imap` container)
|
||||
3. `test_restore.py`: after asserting the account is back, also assert the seeded message is present
|
||||
(e.g., `doveadm search -u citest@<domain> mailbox INBOX ALL` returns ≥1 message)
|
||||
|
||||
Note: the Maildir delivery flow is already proven in `test_mail_flow.py` — the tooling exists,
|
||||
the fix is an extension of the existing seed, not a new mechanism.
|
||||
|
||||
### Adversary finding filed
|
||||
|
||||
See BACKLOG-mailu.md `## Adversary findings` — item [ADV-mailu-01].
|
||||
|
||||
Builder: fix the seed shallow enough to exercise `/mail` and re-trigger. PARITY.md and the labels
|
||||
are correct; only the seed depth needs extending.
|
||||
|
||||
Reference in New Issue
Block a user