30014f0f416877e21c9fe10822d4d2a129b688e7
2
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
9fa19291d4 |
#4: implement F2 sub-project 1 - IMAP core (auth, LIST, SELECT, FETCH, STORE)
Adds a real :143 IMAP listener to the Go protocols service: a mailbox owner authenticates over IMAP (Argon2id against mailboxes.password_hash, enumeration-resistant per PLAN.md section 14.6), lists folders, selects INBOX, fetches messages F1's SMTP path already persisted - including real ENVELOPE/BODY[] built from the actual stored MIME bytes via go-imap/v2's own ExtractEnvelope/ExtractBodySection helpers, not reconstructed from denormalized columns - and sets/reads flags via STORE. - ImapSessionUseCase orchestrates auth, folder listing/selection, message querying, and flag mutation against new Postgres repositories (auth, folders, message query, flags) and a local-disk blob reader. - A github.com/emersion/go-imap/v2 (pinned v2.0.0-beta.8) Backend/Session implements 7 real methods (Login, List, Select, Unselect, Status, Fetch, Store) plus a correct no-op Poll; the other 10 of the interface's 18 methods (Create/Delete/Rename/Subscribe/Unsubscribe/Append/Idle/Expunge/ Search/Copy) are explicit stubs returning a clear "not yet implemented" IMAP error - SEARCH/EXPUNGE/COPY/MOVE, IDLE/CONDSTORE, mailbox management, and APPEND are separate follow-up sub-projects per the design doc's agreed ordering with the user. Verified end-to-end with a real go-imap/v2 imapclient (embedded Postgres, no Docker needed) driving Login -> Select -> Fetch -> Store -> List against a message seeded through F1's real SMTP use case, proving true SMTP-write/IMAP-read interop, not just isolated unit tests. Built via 8 sequential tasks under subagent-driven development, each independently reviewed, plus a final whole-branch review. Two real bugs were found and fixed before merge, both exactly the kind unit tests with fakes cannot catch: - Store's UID-set resolution silently no-op'd on dynamic ranges like "UID STORE 1:*" (the common "mark all as read" operation) after an earlier draft bypassed the folder's real message list; restored to resolve against real messages via the same pattern Fetch already used correctly, with tests proving both dynamic ranges and non-UID STORE. - go-imap/v2's server calls Session.Poll() implicitly before the status response of nearly every authenticated command (FETCH/STORE/SEARCH/ APPEND/COPY), not just IDLE as assumed - a hard-stubbed Poll broke every real command through this path; fixed to a correct no-op. - List had zero test coverage despite being committed scope; added unit tests for wildcard/delimiter matching plus a real E2E LIST assertion. Known follow-up, not blocking: a pre-existing test-fixture hygiene gap (hardcoded content_sha256 blob hashes with no cleanup, shared across several Postgres integration test files including one new to this branch) causes local-dev test collisions on repeated runs against a persistent database - invisible to CI (fresh Postgres per run) but worth a cleanup pass. |
||
|
|
e501cdc69e |
#2: implement F1 sub-project 1 - inbound SMTP listener with EML storage
Adds a real :25 SMTP listener to the Go protocols service, giving F1's "Nucleo SMTP" milestone its first working sub-project: application, infrastructure, and presentation layers on top of F0's domain-only Clean Architecture. - ProcessInboundEmailUseCase resolves recipients against Postgres and persists accepted mail (blob dedup by content hash, transactional UID allocation + outbox event, never sending 250 OK before durable commit per PLAN.md section 6.1). - Postgres repositories via pgx/v5 (replacing lib/pq entirely). - Local-disk blob storage with content-hash dedup, rename-before-commit ordering so a DB row can never reference a file that isn't actually on disk. - A local-file TLS cert provider for STARTTLS, with an ephemeral self-signed fallback so a missing/misconfigured cert degrades gracefully instead of crash-looping the service (PLAN.md section 8.4). - A github.com/emersion/go-smtp Backend/Session adapting real SMTP traffic to the use case: unknown recipients get 550 5.1.1 before DATA, duplicate RCPT TO for the same address is deduplicated, TLS is hardened to the project's required PFS-only cipher/curve policy. - A dev-seed script and Makefile target for local testing. Explicitly out of scope (separate follow-up sub-projects): alias resolution, SPF/DKIM/DMARC/ARC verification, Rspamd/ClamAV, Submission ports with SASL auth, DKIM signing, outbound delivery, and the real Traefik acme.json cert watcher. Verified live end-to-end via WSL Docker: the full compose stack (db, redis, migrate, auth, storage, protocols, web) reaches healthy, and a real swaks SMTP session is accepted and durably persisted with correct sequential UIDs, while an unknown recipient is correctly rejected with 550 5.1.1 and zero rows persisted. Built via 10 sequential tasks under subagent-driven development, each independently reviewed, plus a final whole-branch review that caught and fixed a TLS-crash bug, a blob commit-ordering bug, missing TLS hardening, and missing CI integration coverage before merge. Known follow-up, not blocking: email_messages' partition only covers July 2026 and needs a partition-management job before 2026-08-01. |