Release: phases 1-5 complete (skeleton, sources, persistence, detection, policy, classification) #10
Loading…
Reference in a new issue
No description provided.
Delete branch "dev"
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?
Release PR bringing
mainup to date with everything merged todevsince repository bootstrap: PRs #1 through #9, decisions D-0001 through D-0028.Delivered, in merge order:
Viegard.slnx, NuGetAudit enforced), domain model, application ports, broker-semantics channel queue, secret providers, prompt-injection-resistantPromptAssembler, fail-closedClassificationOutputValidator, queue telemetry with traffic-light evaluation, Dockerfiles + compose example.SKIP LOCKED+LISTEN/NOTIFYqueues with crash-safe dead-lettering, nightly pg_dump rigging; defects fixed via live integration testing (18/18 against postgres:17).TimeWindowCorrelator,CorrelationWorker.Docs kept current throughout: ARCHITECTURE.md (approved D-0017), DECISIONS.md, TODO.md, AGENT-README.md (agent-readme.md draft v0.1 spec-conformant).
How was this tested?
dotnet build Viegard.slnx- 0 errors, 0 warnings (re-verified on dev tipea9192b)dotnet test Viegard.slnx- 240/240 unit tests; 18/18 PostgreSQL integration tests passed live 2026-08-20Checklist
- 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>- Viegard.Sources.Syslog: - SyslogUdpSource: thin UDP loop; per-source health incl. drop counters - SyslogDatagramHandler (testable core): fail-closed source-IP allowlist, datagram size cap, per-source token-bucket rate cap, replacement-character decoding so hostile bytes never throw - SyslogEnvelopeParser: RFC 3164 (incl. pid tags, year inference with Dec/Jan wrap) and RFC 5424; garbage degrades to message-only - NginxAccessLogParser: combined format + Viegard host=/rt= extension; malformed/hostile request lines yield partial fields, never throw - SyslogEventNormalizer: nginx_access tags -> HttpRequestEvent with IP/host/URI/UA entity refs; everything else -> generic SyslogEvent keyed to peer IP (claimed hostname untrusted) - Options validation: enabled listener requires non-empty allowlist - Domain: HttpRequestEvent + SyslogEvent payloads - PipelineHost: syslog registration (off by default); debug log on successful ingestion - docs/swag-syslog-setup.md: sanitized SWAG nginx configuration guide - Tests: 130 passing (31 new incl. spoofed-hostname handling, injection text as data, rate-limit recovery with FakeTimeProvider) Verified end-to-end: live UDP datagrams to the running host produced a normalized HttpRequestEvent (nginx line) and generic SyslogEvent (hostile message) queued for correlation. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>- Viegard.Persistence.Postgres: - ViegardDbContext + InitialSchema migration: raw observations, events (jsonb entities/payload), incidents, classifications, decisions, actions, audit records, corrections, queue telemetry, source offsets, queue messages + counters - Postgres store implementations for every persistence port, mapping immutable domain records to EF row types - PostgresWorkQueue: SKIP LOCKED visibility-timeout leases, delivery counting with dead-lettering enforced at lease time (crash-safe poison protection), LISTEN/NOTIFY wakeups with fallback poll, per-queue counters; PostgresCommandQueue for admin commands - DatabaseOptions (+ validator): password via ISecretProvider secret name, never configuration; AutoMigrate at host startup - Service registration extension + design-time factory for dotnet-ef - Domain: JSON polymorphism discriminators on EventPayload - Application: IQueueStatsSource.GetStatsAsync (durable queues compute stats in the database); ChannelWorkQueue keeps a sync core - PipelineHost: persistence provider switch (inmemory default, postgres via Viegard:Persistence:Provider) with startup migration - Tests: 140 passing + 7 PostgreSQL integration tests (queue round-trip, redelivery, dead-letter, lease expiry, concurrent consumers, LISTEN/NOTIFY wakeup, polymorphic store round-trip) gated on VIEGARD_TEST_POSTGRES pending local Docker (WSL reboot) - Deps (supply-chain reviewed): Npgsql.EntityFrameworkCore.PostgreSQL 10.0.3, EF Core 10.0.11, recorded in THIRD-PARTY-NOTICES.md Verified: dotnet build (0 warnings), dotnet test (140/140 + 7 skips), host boots with default inmemory provider. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>