# STATUS — phase mailu (backupbot labels for mailu recipe) **Phase plan:** `/srv/cc-ci/cc-ci-plan/plan-phase-mailu-backup.md` **Builder:** autonomic-bot / Claude (Builder loop) **Started:** 2026-06-11T18:00Z --- ## Current state **Gate M1: CLAIMED (re-claim after ADV-mailu-01 fix) — awaiting Adversary** Drone build #477: LEVEL 5 PASS at PR#3 head (edc0201a79d3), all rungs green including backup/restore on real seeded mail data — BOTH `/data` (SQLite) AND `/mail` (Maildir) now specifically tested and verified. Claimed 2026-06-11T21:XX. ADV-mailu-01 fix: extended `ops.py::pre_backup` to inject a real mail message; extended `ops.py::pre_restore` to also wipe the Maildir; added `test_backup_captures_mail_message` and `test_restore_returns_mail_message` to verify both volumes survive the cycle. **Gate M2:** NOT YET CLAIMED --- ## DoD tracker (M1) - [x] Data-layout research documented (which volumes hold durable state, justification in PR desc) - [x] Recipe-mirror PR open with backupbot v2 labels (admin `/data` + imap `/mail`) - **PR#3**: https://git.autonomic.zone/recipe-maintainers/mailu/pulls/3 - Branch: `add-backupbot-labels`, head commit: `edc0201a79d36bc87696b0f93f1ee88ad7bd10ed` - Version bump: `3.0.1+2024.06.52` → `3.0.2+2024.06.52` - Adds `deploy.labels: {backupbot.backup: "true", backupbot.backup.path: "/data"}` to `admin` - Adds `deploy.labels: {backupbot.backup: "true", backupbot.backup.path: "/mail"}` to `imap` - [x] Version label bumped in compose.yml (3.0.1 → 3.0.2+2024.06.52) - [x] cc-ci: `tests/mailu/ops.py` with pre_backup (seed mailbox + inject mail message) + pre_restore (delete mailbox + wipe Maildir) - [x] cc-ci: `tests/mailu/test_backup.py` asserting mailbox AND mail message present at backup time - [x] cc-ci: `tests/mailu/test_restore.py` asserting mailbox AND mail message restored after restore - [x] cc-ci: `tests/mailu/PARITY.md` updated (P4 now covered, not N/A) - [x] Full lifecycle green at PR head (L5) including backup/restore on BOTH volumes — via drone `!testme` - **Drone build #477**: LEVEL 5 of 5 — all rungs PASS (install/upgrade/backup/restore/custom/lint) - `test_backup_captures_mailbox` PASS — `citest@` present in config-export at backup time - `test_backup_captures_mail_message` PASS — message `ccci-backup-probe` in INBOX at backup time - `test_restore_returns_mailbox` PASS — `citest@` restored after pre_restore deletion - `test_restore_returns_mail_message` PASS — `ccci-backup-probe` message back after Maildir wipe+restore - `clean_teardown: true`, `no_secret_leak: true` - No mailu stacks on host post-run (`docker stack ls` confirms) - [x] ADV-mailu-01 fix applied: seed now covers both volumes (`/data` SQLite + `/mail` Maildir) - [x] Before/after level recorded - **BEFORE** (main, no labels): `backup_capable=False` → backup rung = intentional-skip → max **L4** - **AFTER** (PR#3 head edc0201a): `backup_capable=True` (auto-detected from labels) → backup rung = PASS → **L5** ## DoD tracker (M2) - [ ] Fresh Adversary cold pass (independent re-trigger at PR#3 head) - [ ] Levels reconciled - [ ] DEFERRED entry closed - [ ] STATUS-mailu.md operator summary - [ ] REVIEW-mailu.md shows PASS for M1 + M2 (within 24h) --- ## Verification recipe (for Adversary M1 re-check) ```bash # 1. Verify backupbot v2 labels in PR#3 compose.yml (branch: add-backupbot-labels) GITEA_PASSWORD=$(grep GITEA_PASSWORD /srv/cc-ci/.testenv | cut -d= -f2-) curl -s "https://git.autonomic.zone/api/v1/repos/recipe-maintainers/mailu/contents/compose.yml?ref=add-backupbot-labels" \ -u "autonomic-bot:${GITEA_PASSWORD}" \ | python3 -c "import sys,json,base64; print(base64.b64decode(json.load(sys.stdin)['content']).decode())" \ | grep -A4 backupbot # Expected: # admin service → backupbot.backup: "true" + backupbot.backup.path: "/data" # imap service → backupbot.backup: "true" + backupbot.backup.path: "/mail" # 2. Verify PR#3 head commit # Expected: edc0201a79d36bc87696b0f93f1ee88ad7bd10ed # 3. Verify drone build #477 level 5 DRONE_TOKEN=$(ssh cc-ci 'cat /run/secrets/bridge_drone_token') curl -s "https://drone.ci.commoninternet.net/api/repos/recipe-maintainers/cc-ci/builds/477" \ -H "Authorization: Bearer ${DRONE_TOKEN}" | python3 -c " import sys,json; b=json.load(sys.stdin) print('status:', b['status']) print('steps:', [(s['name'], s['status']) for st in b['stages'] for s in st['steps']]) " # Expected: success, clone+ci both success # 4. Verify full results.json — including NEW maildir tests ssh cc-ci 'cat /var/lib/cc-ci-runs/477/results.json' # Expected: # level=5, all rungs pass (backup_restore, functional, install, lint, upgrade) # backup stage tests include: # test_backup_captures_mailbox PASS (SQLite /data) # test_backup_captures_mail_message PASS (Maildir /mail) # restore stage tests include: # test_restore_returns_mailbox PASS (SQLite /data) # test_restore_returns_mail_message PASS (Maildir /mail) # flags: clean_teardown=true, no_secret_leak=true # 5. Verify clean teardown on host ssh cc-ci 'docker stack ls | grep -i mailu || echo "no mailu stacks (clean)"' # Expected: no mailu stacks # 6. Re-trigger to verify at current PR head (M2 requirement): # Comment !testme on PR#3 as the Adversary and observe level 5 again ``` --- ## Blocked items (none) --- ## DONE Not yet. Written here only when all DoD items have M1+M2 Adversary PASS in REVIEW-mailu.md.