fix(auditlog): populate the Actor column on outbound and central rows
Per the Audit Log Actor-column spec, Actor should carry the calling script identity on outbound rows (ApiCall, DbWrite, NotifySend) and a system identity on central-dispatch rows (NotifyDeliver). The original emission code hard-coded Actor=null at all four sites, so only Inbound API rows (API key name) ever filled it. Stamp the script identity and 'system' respectively.
This commit is contained in:
@@ -30,6 +30,13 @@ public class NotificationOutboxActor : ReceiveActor, IWithTimers
|
|||||||
private const int FallbackMaxRetries = 10;
|
private const int FallbackMaxRetries = 10;
|
||||||
private static readonly TimeSpan FallbackRetryDelay = TimeSpan.FromMinutes(1);
|
private static readonly TimeSpan FallbackRetryDelay = TimeSpan.FromMinutes(1);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Audit <c>Actor</c> stamped on central-dispatch (<c>NotifyDeliver</c>) rows.
|
||||||
|
/// The Actor-column spec assigns central-originated audit rows a system
|
||||||
|
/// identity — there is no per-call authenticated user at dispatch time.
|
||||||
|
/// </summary>
|
||||||
|
private const string SystemActor = "system";
|
||||||
|
|
||||||
private readonly IServiceProvider _serviceProvider;
|
private readonly IServiceProvider _serviceProvider;
|
||||||
private readonly NotificationOutboxOptions _options;
|
private readonly NotificationOutboxOptions _options;
|
||||||
private readonly ICentralAuditWriter _auditWriter;
|
private readonly ICentralAuditWriter _auditWriter;
|
||||||
@@ -500,9 +507,11 @@ public class NotificationOutboxActor : ReceiveActor, IWithTimers
|
|||||||
Channel = AuditChannel.Notification,
|
Channel = AuditChannel.Notification,
|
||||||
Kind = AuditKind.NotifyDeliver,
|
Kind = AuditKind.NotifyDeliver,
|
||||||
CorrelationId = correlationId,
|
CorrelationId = correlationId,
|
||||||
// Central dispatch — no authenticated actor (the originating
|
// Central dispatch — a system identity per the Actor-column spec;
|
||||||
// script's identity is captured on the upstream NotifySend row).
|
// there is no per-call authenticated user here. The originating
|
||||||
Actor = null,
|
// script is still captured on SourceScript (and on the upstream
|
||||||
|
// NotifySend row).
|
||||||
|
Actor = SystemActor,
|
||||||
SourceSiteId = notification.SourceSiteId,
|
SourceSiteId = notification.SourceSiteId,
|
||||||
SourceInstanceId = notification.SourceInstanceId,
|
SourceInstanceId = notification.SourceInstanceId,
|
||||||
SourceScript = notification.SourceScript,
|
SourceScript = notification.SourceScript,
|
||||||
|
|||||||
@@ -430,7 +430,10 @@ internal sealed class AuditingDbCommand : DbCommand
|
|||||||
SourceSiteId = string.IsNullOrEmpty(_siteId) ? null : _siteId,
|
SourceSiteId = string.IsNullOrEmpty(_siteId) ? null : _siteId,
|
||||||
SourceInstanceId = _instanceName,
|
SourceInstanceId = _instanceName,
|
||||||
SourceScript = _sourceScript,
|
SourceScript = _sourceScript,
|
||||||
Actor = null,
|
// Outbound channel: per the Audit Log Actor-column spec the actor is
|
||||||
|
// the calling script. Null when no single script owns the call
|
||||||
|
// (e.g. a shared script running inline).
|
||||||
|
Actor = _sourceScript,
|
||||||
Target = target,
|
Target = target,
|
||||||
Status = status,
|
Status = status,
|
||||||
HttpStatus = null,
|
HttpStatus = null,
|
||||||
|
|||||||
@@ -875,7 +875,10 @@ public class ScriptRuntimeContext
|
|||||||
SourceSiteId = string.IsNullOrEmpty(_siteId) ? null : _siteId,
|
SourceSiteId = string.IsNullOrEmpty(_siteId) ? null : _siteId,
|
||||||
SourceInstanceId = _instanceName,
|
SourceInstanceId = _instanceName,
|
||||||
SourceScript = _sourceScript,
|
SourceScript = _sourceScript,
|
||||||
Actor = null,
|
// Outbound channel: per the Audit Log Actor-column spec the actor
|
||||||
|
// is the calling script. Null when no single script owns the call
|
||||||
|
// (e.g. a shared script running inline).
|
||||||
|
Actor = _sourceScript,
|
||||||
Target = $"{systemName}.{methodName}",
|
Target = $"{systemName}.{methodName}",
|
||||||
Status = status,
|
Status = status,
|
||||||
HttpStatus = httpStatus,
|
HttpStatus = httpStatus,
|
||||||
@@ -1355,7 +1358,10 @@ public class ScriptRuntimeContext
|
|||||||
SourceSiteId = string.IsNullOrEmpty(_siteId) ? null : _siteId,
|
SourceSiteId = string.IsNullOrEmpty(_siteId) ? null : _siteId,
|
||||||
SourceInstanceId = _instanceName,
|
SourceInstanceId = _instanceName,
|
||||||
SourceScript = _sourceScript,
|
SourceScript = _sourceScript,
|
||||||
Actor = null,
|
// Outbound channel: per the Audit Log Actor-column spec the
|
||||||
|
// actor is the calling script. Null when no single script
|
||||||
|
// owns the call (e.g. a shared script running inline).
|
||||||
|
Actor = _sourceScript,
|
||||||
Target = _listName,
|
Target = _listName,
|
||||||
Status = AuditStatus.Submitted,
|
Status = AuditStatus.Submitted,
|
||||||
HttpStatus = null,
|
HttpStatus = null,
|
||||||
|
|||||||
@@ -155,8 +155,8 @@ public class NotificationOutboxActorAttemptEmissionTests : TestKit
|
|||||||
Assert.Equal("site-alpha", evt.SourceSiteId);
|
Assert.Equal("site-alpha", evt.SourceSiteId);
|
||||||
Assert.Equal("instance-42", evt.SourceInstanceId);
|
Assert.Equal("instance-42", evt.SourceInstanceId);
|
||||||
Assert.Equal("AlarmScript", evt.SourceScript);
|
Assert.Equal("AlarmScript", evt.SourceScript);
|
||||||
// Central dispatch: actor is null (no authenticated end-user).
|
// Central dispatch: Actor is the system identity (no per-call user).
|
||||||
Assert.Null(evt.Actor);
|
Assert.Equal("system", evt.Actor);
|
||||||
// Successful attempt: no error message.
|
// Successful attempt: no error message.
|
||||||
Assert.Null(evt.ErrorMessage);
|
Assert.Null(evt.ErrorMessage);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -266,7 +266,8 @@ public class DatabaseSyncEmissionTests
|
|||||||
Assert.Equal(SiteId, evt.SourceSiteId);
|
Assert.Equal(SiteId, evt.SourceSiteId);
|
||||||
Assert.Equal(InstanceName, evt.SourceInstanceId);
|
Assert.Equal(InstanceName, evt.SourceInstanceId);
|
||||||
Assert.Equal(SourceScript, evt.SourceScript);
|
Assert.Equal(SourceScript, evt.SourceScript);
|
||||||
Assert.Null(evt.Actor);
|
// Outbound channel: Actor carries the calling script identity.
|
||||||
|
Assert.Equal(SourceScript, evt.Actor);
|
||||||
Assert.Null(evt.CorrelationId);
|
Assert.Null(evt.CorrelationId);
|
||||||
Assert.NotEqual(Guid.Empty, evt.EventId);
|
Assert.NotEqual(Guid.Empty, evt.EventId);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -186,7 +186,8 @@ public class ExternalSystemCallAuditEmissionTests
|
|||||||
Assert.Equal(SiteId, evt.SourceSiteId);
|
Assert.Equal(SiteId, evt.SourceSiteId);
|
||||||
Assert.Equal(InstanceName, evt.SourceInstanceId);
|
Assert.Equal(InstanceName, evt.SourceInstanceId);
|
||||||
Assert.Equal(SourceScript, evt.SourceScript);
|
Assert.Equal(SourceScript, evt.SourceScript);
|
||||||
Assert.Null(evt.Actor);
|
// Outbound channel: Actor carries the calling script identity.
|
||||||
|
Assert.Equal(SourceScript, evt.Actor);
|
||||||
Assert.Null(evt.CorrelationId);
|
Assert.Null(evt.CorrelationId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -127,7 +127,8 @@ public class NotifySendAuditEmissionTests : TestKit, IAsyncLifetime, IDisposable
|
|||||||
Assert.Null(evt.HttpStatus);
|
Assert.Null(evt.HttpStatus);
|
||||||
Assert.Null(evt.ErrorMessage);
|
Assert.Null(evt.ErrorMessage);
|
||||||
Assert.Null(evt.ErrorDetail);
|
Assert.Null(evt.ErrorDetail);
|
||||||
Assert.Null(evt.Actor);
|
// Outbound channel: Actor carries the calling script identity.
|
||||||
|
Assert.Equal(SourceScript, evt.Actor);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@@ -199,7 +200,8 @@ public class NotifySendAuditEmissionTests : TestKit, IAsyncLifetime, IDisposable
|
|||||||
Assert.Equal(SiteId, evt.SourceSiteId);
|
Assert.Equal(SiteId, evt.SourceSiteId);
|
||||||
Assert.Equal(InstanceName, evt.SourceInstanceId);
|
Assert.Equal(InstanceName, evt.SourceInstanceId);
|
||||||
Assert.Equal(SourceScript, evt.SourceScript);
|
Assert.Equal(SourceScript, evt.SourceScript);
|
||||||
Assert.Null(evt.Actor);
|
// Outbound channel: Actor carries the calling script identity.
|
||||||
|
Assert.Equal(SourceScript, evt.Actor);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|||||||
Reference in New Issue
Block a user