AuditService¶
Target
This page describes intended behaviour or structure. No implementation is claimed unless a section is explicitly marked Current implementation or Evidence.
| Bounded context | BC-19 Audit |
| Platform / plane | Governance / Trust & Operations |
| Deployment granularity | module of host · host GovernanceHost |
| Status | target · ConnectSoft.Factory.Governance.Audit |
| Built from | connectsoft-microservice · libraries: connectsoft-extensions-audit-net, connectsoft-extensions-compliance, connectsoft-extensions-saas-abstractions, connectsoft-extensions-messaging-model, connectsoft-extensions-persistence-model-nhibernate, connectsoft-extensions-data-storage-abstractions |
| Decisions | ADR-0014, ADR-0019 |
| Traceability | FR-06 FR-08 FUX-05 FUX-06 NFR-03 NFR-04 NFR-10 XL-05 XL-13 XL-14 |
Purpose and responsibilities¶
Every autonomous action must be observable (original handoff §3.8). AuditService turns the events of every platform into evidence: append-only entries (audit-evidence-v1) with actor, scope, action, target version or hash, reason and outcome, chained by hash per tenant, mirrored to the immutable store, head-signed daily and verified on a schedule; a broken chain is a Critical finding. It also owns the classification registry (data classes with retention, redaction rules and residency) that context assembly, artifacts, ingestion and the model gateway obey (D31), and the findings that evidence raises (chain breaks, prohibited attempts, unresolved uncertain effects, overdue rotations). Tenants export their evidence with chain proofs in open formats.
It absorbs DataClassificationService, MemoryClassificationService and MemoryRedactionService; ComplianceReportService, RiskScoringService and SecurityFindingService stay later rows.
Context and boundaries¶
flowchart LR
S["AuditService"]
ContextBuilderService["ContextBuilderService"] -->|grpc| S
ArtifactService["ArtifactService"] -->|grpc| S
StudioBff["StudioBff"] -->|sync-http| S
S -->|grpc| ArtifactService["ArtifactService"]
S -->|sync-http| ext_key_vault["ext-key-vault"]
S -. "AuditEntryRecorded" .-> E_AuditEntryRecorded(("event"))
S -. "AuditChainVerified" .-> E_AuditChainVerified(("event"))
S -. "ClassificationChanged" .-> E_ClassificationChanged(("event"))
S -. "FindingRaised" .-> E_FindingRaised(("event"))
S -. "FindingResolved" .-> E_FindingResolved(("event"))
Domain model¶
AuditEntry — One immutable evidence record (audit-evidence-v1) — kind, actor, scope, action, target with version or hash, reason, outcome, correlation ids and the hash of the previous entry in the tenant's chain. (catalog entry)
| Field | Type | Required | Description |
|---|---|---|---|
entryId |
guid |
yes | |
tenantId |
string |
yes | |
projectId |
string |
no | |
sequence |
long |
yes | Monotonic per tenant. |
kind |
enum:EvidenceKind |
yes | |
actor |
json |
yes | Identity kind and id, roles, delegation, break-glass flag |
action |
string |
yes | |
target |
json |
yes | Type, id, version or hash |
reason |
string |
no | |
outcome |
string |
yes | |
correlationId |
guid |
yes | |
causationId |
guid |
no | |
runId |
guid |
no | |
sourceEvent |
string |
yes | Producing service and event name. |
previousHash |
hash |
yes | |
entryHash |
hash |
yes | |
recordedAt |
datetime |
yes |
Invariants:
- Entries are append-only and hash-chained per tenant; the chain head is signed daily and verified on a schedule; a broken chain is a Critical finding.
- Evidence never contains prompt text, payloads or secret values; it references hashes and artifact ids.
- Retention is 7 years (D31); personal identifiers are redacted after the project's retention window while the chain stays verifiable.
Events: AuditEntryRecorded, AuditChainVerified · Tables: AuditEntries, ChainHeads · Repository: AuditEntryRepository
ClassificationLabel — The registry entry that classifies a resource type or instance (source, artifact kind, connection, profile) and binds retention, redaction and routing rules to the class. (catalog entry)
| Field | Type | Required | Description |
|---|---|---|---|
labelId |
guid |
yes | |
tenantId |
string |
yes | |
resourceType |
string |
yes | |
resourceId |
string |
no | Null for a type-level default. |
dataClass |
enum:DataClass |
yes | |
retentionDays |
int |
yes | |
redactionRuleIds |
list:string |
yes | |
residency |
string |
yes | Region constraint. |
setBy |
string |
yes | |
setAt |
datetime |
yes |
Invariants:
- An instance label may only be stricter than its type default; Restricted never leaves its region and is never promoted to Shared memory.
- Changing a label emits an event that retention sweepers, context assembly and the model gateway honour from the next operation on.
Events: ClassificationChanged · Tables: Classifications, RedactionRules · Repository: ClassificationLabelRepository
Finding — A compliance or security finding raised from evidence (chain break, policy prohibited attempts, uncertain effects unresolved, rotation overdue) with severity, owner and resolution. (catalog entry)
| Field | Type | Required | Description |
|---|---|---|---|
findingId |
guid |
yes | |
tenantId |
string |
yes | |
severity |
enum:FindingSeverity |
yes | |
category |
string |
yes | |
evidenceEntryIds |
list:guid |
yes | |
owner |
string |
no | |
state |
string |
yes | open |
raisedAt |
datetime |
yes | |
resolvedAt |
datetime |
no |
Invariants:
- A finding references the evidence entries that justify it; resolution is itself evidence.
Events: FindingRaised, FindingResolved · Tables: Findings · Repository: FindingRepository
erDiagram
AuditEntry {
guid entryId PK
string tenantId
string projectId
long sequence
enum_EvidenceKind kind
json actor
string action
json target
string reason
string outcome
guid correlationId
guid causationId
guid runId
string sourceEvent
hash previousHash
hash entryHash
datetime recordedAt
}
ClassificationLabel {
guid labelId PK
string tenantId
string resourceType
string resourceId
enum_DataClass dataClass
int retentionDays
list_string redactionRuleIds
string residency
string setBy
datetime setAt
}
Finding {
guid findingId PK
string tenantId
enum_FindingSeverity severity
string category
list_guid evidenceEntryIds
string owner
string state
datetime raisedAt
datetime resolvedAt
}
RedactionRule {
string ruleId
string detector
string action
list_string appliesTo
}
ClassificationLabel ||--o{ RedactionRule : contains
Entities and value objects¶
RedactionRule (entity, in ClassificationLabel) — A redaction pattern or detector bound to a data class (ConnectSoft.Extensions.Compliance).
| Field | Type | Required | Description |
|---|---|---|---|
ruleId |
string |
yes | |
detector |
string |
yes | regex |
action |
string |
yes | mask |
appliesTo |
list:string |
yes | prompt |
Data model and storage¶
| Store | Role | Engine / profile | Tables |
|---|---|---|---|
| Governance store | primary | azure-sql / nhibernate-sqlserver | AuditEntries, ChainHeads, Classifications, RedactionRules, Findings |
| Immutable audit store | blob | blob / azure-blob-immutable | — |
| Table | Owner | Columns | Indexes |
|---|---|---|---|
dbo.AuditEntries |
AuditEntry | 17 | 3 |
dbo.ChainHeads |
AuditEntry | 5 | 0 |
dbo.Classifications |
ClassificationLabel | 10 | 1 |
dbo.RedactionRules |
RedactionRule | 5 | 0 |
dbo.Findings |
Finding | 9 | 1 |
Full DDL: appendix.
Entries are written to governance-sql for query and mirrored to audit-immutable (write-once blob) for integrity; the chain head is signed with a Key Vault key. Personal identifiers are redacted after the project's retention window while the chain stays verifiable.
APIs¶
| Method | Path | Operation | Scope | Side effects | Idempotency | Gateway | Summary |
|---|---|---|---|---|---|---|---|
GET |
/factory/audit |
SearchAudit | factory.audit.read |
read | natural | GW-03 | Evidence by scope, kind, actor, run and time; verifiable chain positions. |
POST |
/factory/projects/{projectId}/audit/export |
ExportAudit | factory.audit.export |
external | key-header | GW-03 | Export a project's evidence in open formats with chain proofs (D31 |
GET |
/factory/classifications |
ListClassifications | factory.audit.read |
read | natural | GW-03 | Classification labels and redaction rules per resource type. |
PUT |
/factory/classifications/{resourceType} |
SetClassification | factory.audit.admin |
production | natural | GW-03 | Set the data class |
GET |
/factory/findings |
ListFindings | factory.audit.read |
read | natural | GW-03 | Open and resolved findings by severity and category. |
POST |
/factory/findings/{findingId}/resolve |
ResolveFinding | factory.audit.admin |
shared-write | natural | GW-03 | Resolve or accept the risk of a finding with a reason (evidence). |
| gRPC service | Method | Streaming | Visibility | Side effects | Summary |
|---|---|---|---|---|---|
Audit |
Record |
none | internal | shared-write | Append evidence directly (for commands that are not events). |
Audit |
Classify |
none | internal | read | Resolve the data class |
Audit |
Redact |
none | internal | shared-write | Apply redaction rules of a class to a content reference and return the redacted artifact reference. |
Messages¶
| Event | Topic | Scope / v | Aggregate | Consumers | Summary |
|---|---|---|---|---|---|
| AuditEntryRecorded | audit.evidence.v1.audit-entry-recorded |
integration / 1 | AuditEntry | DashboardService | Evidence appended to the chain. |
| AuditChainVerified | audit.evidence.v1.audit-chain-verified |
integration / 1 | AuditEntry | DashboardService | The tenant chain was verified and its head signed. |
| ClassificationChanged | audit.classification.v1.classification-changed |
integration / 1 | ClassificationLabel | ContextBuilderService, ArtifactService, KnowledgeIngestionService, ModelRouterService, StudioBff | A label changed; retention |
| FindingRaised | audit.findings.v1.finding-raised |
integration / 1 | Finding | AlertRuleService, StudioBff, StudioNotificationService, DashboardService | A finding was raised from evidence. |
| FindingResolved | audit.findings.v1.finding-resolved |
integration / 1 | Finding | StudioBff, DashboardService | A finding was resolved or its risk accepted. |
AuditEntryRecorded payload:
| Field | Type | Required | Description |
|---|---|---|---|
entryId |
guid |
yes | |
tenantId |
string |
yes | |
sequence |
long |
yes | |
kind |
enum:EvidenceKind |
yes | |
action |
string |
yes | |
runId |
guid |
no |
AuditChainVerified payload:
| Field | Type | Required | Description |
|---|---|---|---|
tenantId |
string |
yes | |
headSequence |
long |
yes | |
valid |
bool |
yes |
ClassificationChanged payload:
| Field | Type | Required | Description |
|---|---|---|---|
labelId |
guid |
yes | |
tenantId |
string |
yes | |
resourceType |
string |
yes | |
resourceId |
string |
no | |
dataClass |
enum:DataClass |
yes | |
retentionDays |
int |
yes |
FindingRaised payload:
| Field | Type | Required | Description |
|---|---|---|---|
findingId |
guid |
yes | |
tenantId |
string |
yes | |
severity |
enum:FindingSeverity |
yes | |
category |
string |
yes |
FindingResolved payload:
| Field | Type | Required | Description |
|---|---|---|---|
findingId |
guid |
yes | |
tenantId |
string |
yes | |
state |
string |
yes |
| Command | Handled by | Result events | Summary |
|---|---|---|---|
Record |
AuditEntry | AuditEntryRecorded | |
SetClassification |
ClassificationLabel | ClassificationChanged | |
ResolveFinding |
Finding | FindingResolved |
| Event | Producer | Handler | Purpose |
|---|---|---|---|
| ApprovalRequested | RunControlService | RecordEvidence |
Approval requests as evidence. |
| ApprovalDecided | RunControlService | RecordEvidence |
Approval decisions as evidence. |
| ProjectStateChanged | ProjectService | RecordEvidence |
Project lifecycle |
| MembershipChanged | ProjectService | RecordEvidence |
Access changes. |
| DelegationChanged | ProjectService | RecordEvidence |
Delegations (D18). |
| AssetReleasePublished | AgentRegistryService | RecordEvidence |
Publications. |
| AssetReleaseRevoked | AgentRegistryService | RecordEvidence |
Revocations. |
| PolicyDecisionRecorded | PolicyEngineService | RecordEvidence |
Policy decisions. |
| ApprovalDecisionValidated | ApprovalPolicyService | RecordEvidence |
Decision validity incl. break-glass. |
| ToolInvoked | ToolAdapterService | RecordEvidence |
Tool effects. |
| ToolEffectUncertain | ToolAdapterService | RaiseUncertainFinding |
Unresolved uncertain effects become findings after the operator window. |
| CredentialIssued | SecretBrokerService | RecordEvidence |
Credential issuances. |
| SourceDeleted | KnowledgeIngestionService | RecordEvidence |
Data lifecycle. |
| ArtifactDeleted | ArtifactService | RecordEvidence |
Data lifecycle. |
| MemoryPromoted | MemoryPromotionService | RecordEvidence |
Promotions. |
| ConnectionStateChanged | IntegrationService | RecordEvidence |
Connection lifecycle incl. revocation. |
Workers and jobs¶
| Worker | Trigger | Output events | Retry | Idempotency key | Summary |
|---|---|---|---|---|---|
| EvidenceWriter | event | AuditEntryRecorded | exponential | sourceEvent + eventId |
Appends consumed events as evidence entries in tenant sequence with the hash chain and mirrors them to the immutable store. |
| ChainVerifier | schedule 0 1 * * * |
AuditChainVerified, FindingRaised | fixed | tenantId + day |
Re-computes and verifies each tenant's hash chain since the last signed head, signs the new head and raises a Critical finding on a break. |
| RetentionAndRedactionSweeper | schedule 0 3 * * * |
— | fixed | entryId |
Redacts personal identifiers in evidence past the project retention window while keeping the chain verifiable; enforces classification retention across stores by emitting lifecycle tasks. |
| ExportWorker | manual on ExportAudit |
AuditEntryRecorded | exponential | projectId + exportRequestId |
Produces an export package of a project's evidence with chain proofs in open formats. |
Actors and grains¶
None modelled
No grains are modelled for this item yet.
Sagas and long-running flows¶
None modelled
No sagas are modelled for this item yet.
Options and configuration¶
| Section | Key | Type | Default | Reloadable | Secret | Summary |
|---|---|---|---|---|---|---|
Governance:Audit |
ChainSigningKeyId |
string | `` | no | yes | Key Vault key for daily head signatures. |
Governance:Audit |
UncertainFindingAfterHours |
int | 24 |
yes | no | Unresolved uncertain tool effects become findings after this window. |
Governance:Classification |
DefaultClass |
enum | Internal |
yes | no | Class of resources without a label. |
Metrics and observability¶
| Metric | Instrument | Unit | Dimensions | Summary |
|---|---|---|---|---|
connectsoft.factory.audit.entries |
counter | {entry} | tenant, kind | Evidence appended. |
connectsoft.factory.audit.chain_lag |
gauge | s | tenant | Age of the oldest consumed event not yet appended. |
connectsoft.factory.audit.chain_valid |
gauge | 1 | tenant | 1 when the last verification passed. |
connectsoft.factory.audit.findings_open |
updown | {finding} | tenant, severity | Open findings. |
Security¶
| Authentication | client-credentials |
| Scopes | factory.audit.read (Read evidence); factory.audit.export (Export evidence (Platform admin); factory.audit.admin (Classifications and finding resolution (Platform admin).) |
| Roles | Reviewer, Operator, WorkspaceAdmin, PlatformAdmin, Observer |
| Tenant isolation | row-filter |
| Data classification | restricted |
| Max side-effect class | production |
| Secrets | audit-chain-key (key-vault, rotate 365 d) |
Dependencies¶
Outbound
| Target | Kind | Purpose | Failure mode | Required |
|---|---|---|---|---|
| ArtifactService | grpc | Redacted artifacts and export packages. | fail-fast | yes |
| ext-key-vault | sync-http | Chain signing. | fail-fast | yes |
Inbound
| Target | Kind | Purpose | Failure mode | Required |
|---|---|---|---|---|
| ContextBuilderService | grpc | Classify and Redact. | — | yes |
| ArtifactService | grpc | Classify on store and preview. | — | yes |
| StudioBff | sync-http | Audit search | — | yes |
Failure and recovery¶
| Scenario | Detection | Recovery | Data impact | RTO (min) |
|---|---|---|---|---|
| Chain break detected | ChainVerifier mismatch | Critical finding; evidence writing continues on a new segment anchored to the last valid head; investigation from the immutable mirror | integrity question on the segment | 60 |
| Evidence backlog | chain_lag above threshold | writer scales per tenant partition; no event is dropped (inbox) | delayed evidence | 60 |
NFR targets¶
| Target | Class value (pilot-interactive) | Override |
|---|---|---|
| latency_p95_ms | 2000 | — |
| availability_pct | 99.5 | — |
| throughput_rps | 50 | — |
| rpo_minutes | 15 | — |
| rto_minutes | 240 | — |
| cost_class | low | — |
Deployment¶
| Granularity | module of host · host GovernanceHost |
| Topologies | saas-default, hybrid, on-prem, hybrid-compute |
| Runtime | —; replicas —–— |
| Ports | — |
Current implementation¶
ConnectSoft.Extensions.AuditNet integrates Audit.NET for application audit trails and ConnectSoft.Extensions.Compliance standardizes classification and redaction; no evidence chain, immutable mirror, classification registry or findings exist.
Later capabilities¶
Compliance reports (later row); risk scoring from evidence; security findings from scanners; evidence attestations for customers' auditors.
Decisions and traceability¶
| Family | Ids |
|---|---|
| FR | FR-06, FR-08 |
| FUX | FUX-05, FUX-06 |
| NFR | NFR-03, NFR-04, NFR-10 |
| XL | XL-05, XL-13, XL-14 |