Phase 4: MDaemon log source adapter (D-0013, D-0025) #7

Merged
hannah-vernon merged 1 commit from feature/mdaemon-source into dev 2026-08-20 16:23:53 -05:00

What does this PR do?

Implements the MDaemon log source adapter (D-0013 scope, D-0025 transport), the third Phase 4 data source. Format knowledge was derived from a real day of production MDaemon v26.0.3 logs supplied by Hannah; committed fixtures are fully sanitized.

  • Viegard.Sources.MDaemonLogs:
    • SessionTranscriptParser (SMTP-in/out, IMAP, POP3, Screening): banner skipping, Ddd YYYY-MM-DD HH:MM:SS.mmm: NN: lines, connection-accepted / 535-auth-failure / host-screening / location-screening extraction with source IPs.
    • DynScrnParser (Dynamic Screening compact format): hex message-code mapping; Blocking IP: ban decisions with reasons, Mgmt Add entries, enforcement chatter and TrustedIP noise flagged droppable.
    • MDaemonLogSource (IDataSource + health): configurable file patterns per log kind, per-file byte-offset resume via ISourceOffsetStore, per-day rotation handling, baseline-to-end on first sight unless IngestExistingOnFirstRun.
    • MDaemonEventNormalizer: line DTO -> MDaemonLogEvent payload with IP entity refs; fail-closed on malformed input.
  • Detection: MDaemonDetectionRules scoring AuthenticationFailed 0.4, IpBlocked 0.9 (MDaemon already decided), ScreeningBlocked 0.6, AccessRefused 0.2. Because the correlator keys on IP entities, MDaemon evidence and nginx evidence about the same address merge into one incident automatically.
  • PipelineHost: enabled-gated wiring mirroring the syslog source; disabled by default.

Deployment note: this adapter is designed to run in a satellite pipeline instance on the MDaemon Windows host per D-0025 (sources role only, shared Postgres over LAN). Live satellite deployment is tracked in TODO.md.

Fixes #

How was this tested?

  • dotnet build Viegard.slnx - 0 errors, 0 warnings
  • dotnet test Viegard.slnx - 197/197 pass including 18 live PostgreSQL integration tests
  • 34 new tests: both parser formats against sanitized real-log-derived fixtures, hostile/garbage input, injection text preserved as data, normalizer fail-closed paths, options validation, detection scoring
  • Host smoke test with the section disabled
  • Sanitization audited twice (agent + independent review): every IP in the diff is RFC 5737 / RFC 1918 / loopback; no real mailboxes, domains, or hostnames

Implementation drafted by a coding agent against a detailed spec, independently reviewed and re-verified.

Checklist

  • I have read the Contributing Guide
  • Changes are focused - one logical change per PR
  • Documentation updated (AGENT-README.md, TODO.md)
  • New dependencies: none
  • No secrets, credentials, or real infrastructure identifiers in the diff
  • No commented-out code or debug leftovers
## What does this PR do? Implements the MDaemon log source adapter (D-0013 scope, D-0025 transport), the third Phase 4 data source. Format knowledge was derived from a real day of production MDaemon v26.0.3 logs supplied by Hannah; committed fixtures are fully sanitized. - **`Viegard.Sources.MDaemonLogs`:** - `SessionTranscriptParser` (SMTP-in/out, IMAP, POP3, Screening): banner skipping, `Ddd YYYY-MM-DD HH:MM:SS.mmm: NN:` lines, connection-accepted / 535-auth-failure / host-screening / location-screening extraction with source IPs. - `DynScrnParser` (Dynamic Screening compact format): hex message-code mapping; `Blocking IP:` ban decisions with reasons, `Mgmt Add` entries, enforcement chatter and TrustedIP noise flagged droppable. - `MDaemonLogSource` (`IDataSource` + health): configurable file patterns per log kind, per-file byte-offset resume via `ISourceOffsetStore`, per-day rotation handling, baseline-to-end on first sight unless `IngestExistingOnFirstRun`. - `MDaemonEventNormalizer`: line DTO -> `MDaemonLogEvent` payload with IP entity refs; fail-closed on malformed input. - **Detection:** `MDaemonDetectionRules` scoring AuthenticationFailed 0.4, IpBlocked 0.9 (MDaemon already decided), ScreeningBlocked 0.6, AccessRefused 0.2. Because the correlator keys on IP entities, MDaemon evidence and nginx evidence about the same address merge into one incident automatically. - **PipelineHost:** enabled-gated wiring mirroring the syslog source; disabled by default. Deployment note: this adapter is designed to run in a satellite pipeline instance on the MDaemon Windows host per D-0025 (sources role only, shared Postgres over LAN). Live satellite deployment is tracked in TODO.md. Fixes # ## How was this tested? - [x] `dotnet build Viegard.slnx` - 0 errors, 0 warnings - [x] `dotnet test Viegard.slnx` - **197/197 pass including 18 live PostgreSQL integration tests** - [x] 34 new tests: both parser formats against sanitized real-log-derived fixtures, hostile/garbage input, injection text preserved as data, normalizer fail-closed paths, options validation, detection scoring - [x] Host smoke test with the section disabled - [x] **Sanitization audited twice** (agent + independent review): every IP in the diff is RFC 5737 / RFC 1918 / loopback; no real mailboxes, domains, or hostnames Implementation drafted by a coding agent against a detailed spec, independently reviewed and re-verified. ## Checklist - [x] I have read the [Contributing Guide](../CONTRIBUTING.md) - [x] Changes are focused - one logical change per PR - [x] Documentation updated (AGENT-README.md, TODO.md) - [x] New dependencies: none - [x] No secrets, credentials, or real infrastructure identifiers in the diff - [x] No commented-out code or debug leftovers
Add the MDaemon domain payload, flat-file tailing source, session-transcript and Dynamic Screening parsers, normalizer, disabled default configuration, and PipelineHost wiring. Add deterministic MDaemon evidence scoring and IP correlation support with sanitized parser fixtures and tests.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
hannah-vernon/viegard-sentinel!7
No description provided.