EMAIL-WP-0005-T02: add GreenMail test harness
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s

Adds tests/harness/docker-compose.yml running GreenMail 2.1.12 (digest-pinned)
with SMTP 3025, IMAP 3143 and the API bound to 127.0.0.1 only, plus a
config/harness-imap.yml scanner profile and harness README. Auth is disabled
and no users are declared, so a mailbox is created on first login and per-test
users need no provisioning.

GreenMail standalone offers no STARTTLS, only plaintext or implicit TLS, while
SMTPProvider hardcoded starttls() -- so no send could reach it. SMTPProvider
now takes a security mode via EMAIL_CONNECT_SMTP_SECURITY, defaulting to
starttls. plaintext is refused for any non-loopback host, and hostnames are
never resolved to decide that, so a misconfigured deployment fails at startup
rather than sending credentials in the clear. Trusting GreenMail's self-signed
cert was rejected as the wider risk; see DECISIONS.md.

Verified end to end against the live harness: SMTPProvider.send -> GreenMail ->
ImapMailboxSource, and the documented scan-mailbox CLI. Suite: 52 passed with
the harness down.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
tegwick 2026-08-14 01:41:38 +02:00
parent 86f22c2e65
commit 89fd13ac2d
8 changed files with 329 additions and 4 deletions

View file

@ -150,7 +150,7 @@ Done 2026-08-14:
```task
id: EMAIL-WP-0005-T02
status: todo
status: done
priority: high
state_hub_task_id: "967d2bab-43e3-4240-8bd5-c657ba4178ff"
```
@ -183,6 +183,30 @@ accounts on demand. Mailpit is the fallback for send-side-only inspection and
does not exercise the IMAP source. Record the choice in DECISIONS.md.
```
Done 2026-08-14:
* `tests/harness/docker-compose.yml` runs GreenMail `2.1.12`, digest-pinned,
SMTP 3025 / IMAP 3143 / API 8080, all bound to `127.0.0.1` only. The image
ships no curl/wget/nc, so the healthcheck probes both mail ports with bash
`/dev/tcp`. Verified healthy.
* `greenmail.auth.disabled` with no declared users: any login is accepted and
the mailbox is created on first use, so T03 needs no provisioning step.
Declaring users *and* enabling auth-disabled conflicts — GreenMail tries to
auto-create the login and collides with the declared address.
* `config/harness-imap.yml` scanner profile; env-var recipe for the send side in
`tests/harness/README.md`.
* GreenMail standalone has no STARTTLS support (confirmed against the shipped
jar's property builder — only plain and implicit-TLS setups exist), and
`SMTPProvider` hardcoded `starttls()`, so no send could reach it. Added an
`EMAIL_CONNECT_SMTP_SECURITY` mode defaulting to `starttls`; `plaintext` is
refused for any non-loopback host and hostnames are never resolved to decide
it. See DECISIONS.md.
* Verified end to end: `SMTPProvider.send` → GreenMail → `ImapMailboxSource`
fetch, then the documented CLI (`scan-mailbox --config config/harness-imap.yml`)
against the live harness — 1 message seen, parsed, 1 evidence event.
* Tests: 14 offline cases for the transport-security guard in
`tests/test_transactional.py`. Full suite 52 passed, still container-free.
## T03 - Test-user account provisioning and reset
```task