fix(audit): route SecuredWrite audit via ICentralAuditWriter for SourceNode stamping (#206)
This commit is contained in:
@@ -969,15 +969,25 @@ public class ManagementActor : ReceiveActor
|
||||
|
||||
/// <summary>
|
||||
/// Best-effort emission of ONE secured-write AuditLog row via the central direct-write
|
||||
/// path (<see cref="IAuditLogRepository.InsertIfNotExistsAsync"/>) — mirrors the
|
||||
/// Notification Outbox / Inbound API central-origin pattern. The row is built through
|
||||
/// the canonical <see cref="ScadaBridgeAuditEventFactory"/> so Action/Category/Outcome
|
||||
/// map identically to every other emit site.
|
||||
/// path (<see cref="ICentralAuditWriter.WriteAsync"/>) — mirrors the Notification
|
||||
/// Outbox dispatch / Inbound API central-origin pattern. The row is built through the
|
||||
/// canonical <see cref="ScadaBridgeAuditEventFactory"/> so Action/Category/Outcome map
|
||||
/// identically to every other emit site.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// #206: routes through <see cref="ICentralAuditWriter"/> (rather than calling
|
||||
/// <see cref="IAuditLogRepository.InsertIfNotExistsAsync"/> directly) so the writing
|
||||
/// central node's <c>SourceNode</c> (<c>central-a</c>/<c>central-b</c>) is stamped via
|
||||
/// the writer's <see cref="INodeIdentityProvider"/> — satisfying the design's
|
||||
/// node-of-origin invariant. The rows are otherwise unchanged (same channel/kind,
|
||||
/// same <c>CorrelationId</c> = the row id, same payload).
|
||||
/// <para>
|
||||
/// Standing audit invariant: an audit-write failure NEVER aborts the secured-write
|
||||
/// action. Every exception (repository resolution OR the insert) is caught, logged at
|
||||
/// warning, and swallowed — the caller's own success/failure path is authoritative.
|
||||
/// action. <see cref="ICentralAuditWriter"/> is best-effort and swallows its own
|
||||
/// internal failures; the surrounding try/catch is defensive belt-and-braces (it also
|
||||
/// guards writer resolution) — either way the caller's own success/failure path is
|
||||
/// authoritative.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
private static async Task EmitSecuredWriteAuditAsync(
|
||||
IServiceProvider sp,
|
||||
@@ -1006,9 +1016,11 @@ public class ManagementActor : ReceiveActor
|
||||
verifierUser = row.VerifierUser
|
||||
}));
|
||||
|
||||
using var scope = sp.CreateScope();
|
||||
var auditRepo = scope.ServiceProvider.GetRequiredService<IAuditLogRepository>();
|
||||
await auditRepo.InsertIfNotExistsAsync(evt);
|
||||
// #206: the central direct-write writer is a singleton that opens its own
|
||||
// per-call scope for the (scoped) IAuditLogRepository and stamps SourceNode
|
||||
// from the local INodeIdentityProvider — no scope needed here.
|
||||
var auditWriter = sp.GetRequiredService<ICentralAuditWriter>();
|
||||
await auditWriter.WriteAsync(evt);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user