From e6e450a257cb23094a2bb2559895f3843fead53d Mon Sep 17 00:00:00 2001 From: Joseph Doherty Date: Wed, 20 May 2026 08:42:04 -0400 Subject: [PATCH] docs(audit): add Centralized Audit Log requirements (AL-1..AL-12) to HighLevelReqs --- docs/requirements/HighLevelReqs.md | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/docs/requirements/HighLevelReqs.md b/docs/requirements/HighLevelReqs.md index a97e107..0871577 100644 --- a/docs/requirements/HighLevelReqs.md +++ b/docs/requirements/HighLevelReqs.md @@ -440,6 +440,25 @@ All system-modifying actions are logged, including: ### 10.4 Transactional Guarantee - Audit entries are written **synchronously** within the same database transaction as the change (via the unit-of-work pattern). If the change succeeds, the audit entry is guaranteed to be recorded. If the change rolls back, the audit entry rolls back too. +### 10.5 Centralized Audit Log (Script Trust Boundary) + +*See [Component-AuditLog.md](Component-AuditLog.md) (#23) for the full component design.* + +Sections 10.1–10.4 cover **configuration-database audit** (config-mutating user actions via `IAuditService`). This subsection defines the separate **runtime Audit Log** that captures every action crossing the **script trust boundary** at sites and central: + +- **AL-1**: The system maintains an **append-only** central Audit Log recording every script-trust-boundary action — outbound external system calls (sync `Call` and `CachedCall`), outbound database operations (sync `Connection` access and `CachedWrite`), notifications, and inbound API method invocations. +- **AL-2**: For cached calls and notifications, the Audit Log captures **one row per lifecycle event** (e.g., enqueued, retrying, delivered, parked, discarded), not a single mutable row per operation. +- **AL-3**: Site-originated events are appended to a **site-local SQLite hot-path** synchronously with the action, then **forwarded to central via gRPC telemetry**; central ingest is **idempotent on `EventId`** (insert-if-not-exists then upsert-on-newer-status). +- **AL-4**: A periodic **central→site reconciliation pull** detects and replays any telemetry events that were missed (e.g., during a central outage), making the central Audit Log eventually consistent with sites. +- **AL-5**: Each row captures **payload metadata** (target, method, status, timings, correlation IDs) plus a **truncated request/response body** — **8 KB default**, expanded to **64 KB on error** outcomes. +- **AL-6**: **HTTP headers are redacted by default**; **SQL parameter values are captured by default**. Per-target **redaction opt-in** is configurable on external systems, database connections, and inbound API methods. +- **AL-7**: A failure to write or forward an audit row **never aborts the user-facing action** — the hot-path action proceeds and the audit record is recovered via the local hot-path buffer plus reconciliation. +- **AL-8**: Central retention defaults to **365 days**, enforced by a **monthly partition switch-and-drop** purge — no row-by-row delete. +- **AL-9**: The site SQLite Audit Log is purged only when `ForwardState ∈ {Forwarded, Reconciled}` — i.e., a row must be either confirmed-forwarded *or* confirmed-reconciled before it can be removed. A central outage therefore **cannot cause audit loss at sites**. +- **AL-10**: The Central UI exposes an **Audit Log page** with a cross-channel filter (by site, target, status, time range, correlation ID), plus **drill-ins from existing operational pages** (Site Calls, Notification Outbox, Inbound API). +- **AL-11**: Append-only semantics are **enforced via DB roles** (no UPDATE/DELETE granted on the `AuditLog` table to application accounts); a **tamper-evidence hash chain is deferred to v1.x**. +- **AL-12**: The CLI provides a `scadalink audit` command group for query, export, and reconciliation operations against the central Audit Log. + ## 11. Health Monitoring ### 11.1 Monitored Metrics