Files
scadaproj/components/audit/README.md
T

5.7 KiB

Audit (who-did-what)

Status: Draft. Normalized component — path to shared code. Goal: converge the three sister projects onto a canonical AuditEvent record + AuditOutcome enum + two thin seams (IAuditWriter, IAuditRedactor), proposed as the ZB.MOM.WW.Audit library, while each project keeps its own transport, storage, domain vocabulary, and redaction policy.

Why audit is a strong normalization candidate

All three projects record a structured who-did-what trail with an actor identity, an action verb, and a timestamp. Two (OtOpcUa + ScadaBridge) already have a named AuditEvent record with an EventId idempotency key, Actor, and CorrelationId. ScadaBridge already ships both canonical seams under slightly different names (IAuditWriter is byte-for-byte the spec; IAuditPayloadFilter is the canonical IAuditRedactor). OtOpcUa's record is almost field-for-field aligned. MxGateway has a narrow API-key-lifecycle log that maps cleanly.

The one new field across all three is AuditOutcome — no project stores it explicitly today; each encodes it implicitly and derives it at adoption. This is the bulk of the per-project work. Transport, storage, domain vocabulary, and redaction policy are not unified — each project keeps its own bespoke implementation behind the seam.

Audit closes the loop on Auth. Every audit row's Actor is exactly the identity that the ZB.MOM.WW.Auth component normalizes (LDAP/GLAuth principal, API-key name). The library keeps Actor as a plain string (no Auth dependency), but at adoption each emit site supplies the Auth principal.

IAuditRedactor naming is aligned with Telemetry's ILogRedactor — same shape and naming discipline so a future ZB.MOM.WW.Hosting aggregator wires both redactors with one mental model — but there is no cross-package dependency between the two libraries.

Status by project

Project Audit today Seams present AuditOutcome Adoption status
OtOpcUa Akka cluster-broadcast AuditEvent → cluster-singleton AuditWriterActor (batch 500/5 s, two-layer dedup) over EF ConfigAuditLog (SQL Server). Also a legacy SQL stored-procedure write path (bare EventType, NULL EventId). Admin UI page ClusterAudit.razor. No named IAuditWriter seam; no redactor seam. Not stored — encoded in EventType strings (OpcUaAccessDenied/CrossClusterNamespaceAttemptDenied; config-write verbs → Success). Not started
MxAccessGateway Single SQLite-backed IApiKeyAuditStore / ApiKeyAuditEntry — key lifecycle (CLI + dashboard) + constraint denials only. No authn events persisted; no production read consumer. Narrow custom seam (IApiKeyAuditStore); no general IAuditWriter; redaction is by-construction (secret never enters the record type). Not stored — derived: constraint-deniedDenied; all others → Success. Not started
ScadaBridge Full pipeline: site SQLite hot-path (SqliteAuditWriter + ring-buffer fallback) → Akka ClusterClient forwarder → central MS SQL (ingest / reconcile / purge / partition maintenance). Rich ~25-field AuditEvent record. CLI export/verify-chain; Blazor audit UI. IAuditWriter (matches canonical contract word-for-word); IAuditPayloadFilter (= canonical IAuditRedactor, identical signature, pure/never-throws/over-redacts). Not stored explicitly — derived from Status (DeliveredSuccess; Failed/Parked/DiscardedFailure; Kind = InboundAuthFailureDenied). Not started (align, don't replace)

See each project's current-state/<project>/CURRENT-STATE.md for code-verified detail and adoption plan:

Normalized vs. left per-project

Normalized (the shared ZB.MOM.WW.Audit library): the canonical AuditEvent record (5 required fields + 4 optional common + DetailsJson extension bag); the AuditOutcome enum (Success | Failure | Denied); the IAuditWriter seam (best-effort, never throws to caller); the IAuditRedactor seam (pure, never throws, over-redacts on failure); shipped helpers (NoOpAuditWriter, CompositeAuditWriter, RedactingAuditWriter, NullAuditRedactor, TruncatingAuditRedactor). Library has no Akka / EF / SQLite / Serilog dependency; its only non-BCL dependency is Microsoft.Extensions.DependencyInjection.Abstractions.

Left per-project (each project keeps these behind the seam): transport and storage (Akka singleton + EF/SQL Server; SQLite; site-SQLite + central MS SQL + forwarding/reconcile pipeline); domain vocabulary (EventType strings / API-key event-type literals / Channel + Kind + Status enums); query, CLI, and UI surfaces (ClusterAudit.razor; ListRecentAsync; export / verify-chain; Blazor audit pages); redaction policy (which fields/payloads are sensitive — only the IAuditRedactor seam is shared).

Adoption is deferred this round. The ZB.MOM.WW.Audit library is being designed and the shared contract defined, but none of the three apps wire it in yet — exactly where ZB.MOM.WW.Auth and ZB.MOM.WW.Theme sit today. The per-project adoption backlog is in GAPS.md.