Phase 4: IMAP data source (D-0019..D-0022) #3
Loading…
Reference in a new issue
No description provided.
Delete branch "feature/imap-source"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
What does this PR do?
Implements the IMAP data source (Phase 4, first source) per decisions D-0019 through D-0022, and wires the front of the ingestion pipeline.
Viegard.Sources.Imap(MailKit 4.17.0, supply-chain reviewed 2026-08-18, low risk):ImapMailSource, one instance per configured account: implicit TLS (993), app-password authentication viaISecretProvider(D-0019), folders opened read-only so retrieval can never mark messages seen (D-0022), IMAP IDLE with automatic polling fallback after repeated failures plus a bounded IDLE cycle acting as the safety poll (D-0020), UIDVALIDITY-aware offset resume, reconnect-with-delay on any failure, per-account health contributor.ImapEventNormalizer:MailFetchDtoJSON ->MailMessageEvent; fails closed on malformed payloads; truncates oversized bodies; emits senderEntityRefs.LinkExtractor: http/https links from text bodies and HTML hrefs, deduplicated, capped at 100 against hostile mail.MailMessageEvent/MailAddressInfo/AttachmentInfopayload records (metadata only for attachments, D-0022).ObservedItem(observation + raw payload, so sources never touch persistence),SourceTypeonIDataSource,ISourceOffsetStoreport (+ in-memory implementation).IngestionWorkerpumps every registered source through persist-raw -> normalize -> store-event -> enqueue-for-correlation, auditing each stage separately; theeventsqueue is registered for D-0012 telemetry; ingestion is gated on thesourcesrole (D-0011).Notes for reviewer:
appsettings.jsonships an empty account list; real config belongs in user-secrets (dev) or mounted config (prod).IngestExistingOnFirstRun= false); flagged in TODO.md for your confirmation.Fixes #
How was this tested?
dotnet build Viegard.slnx- 0 errors, 0 warningsdotnet test Viegard.slnx- 99/99 pass (29 new: normalizer incl. prompt-injection-content-stays-data and truncation, malformed-payload fail-closed, link extraction incl. hostile-mail cap and scheme filtering, options validation)Checklist
- Viegard.Sources.Imap (MailKit 4.17.0, supply-chain reviewed): - ImapMailSource per account: implicit TLS (993), app-password auth via ISecretProvider, folders opened read-only (retrieval never sets Seen), IDLE with polling fallback and bounded IDLE cycle as safety poll, UIDVALIDITY-aware offset resume, reconnect with delay, IHealthContributor per account - ImapEventNormalizer: MailFetchDto JSON -> MailMessageEvent; fails closed on malformed payloads; body truncation; sender entity refs - LinkExtractor: http/https from text + hrefs, deduped, capped - Options validation refuses duplicate accounts, missing fields, and the unimplemented OAuth2 seam - Domain: MailMessageEvent/MailAddressInfo/AttachmentInfo payloads - Application: ObservedItem (observation + raw payload), SourceType on IDataSource, ISourceOffsetStore port - PipelineHost: IngestionWorker (persist raw -> normalize -> store -> enqueue -> audit, per stage); events ChannelWorkQueue registered for telemetry; per-account source registration; ingestion gated on the sources role - Tests: 99 passing (29 new: normalizer incl. prompt-injection-as-data and truncation, link extraction incl. hostile-mail cap, options validation) - Docs: THIRD-PARTY-NOTICES (MailKit, MimeKit, BouncyCastle, MS.Ext), AGENT-README integrations/structure, TODO (first-run baseline needs confirmation; live-account verification outstanding) Verified: dotnet build (0 warnings), dotnet test (99/99), host boots with ingestion worker idle when no accounts are configured. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>