< Summary

Information
Class: AsiBackbone.Core.Audit.AuditLedgerRecord
Assembly: AsiBackbone.Core
File(s): /home/runner/work/AsiBackbone/AsiBackbone/src/AsiBackbone.Core/Audit/AuditLedgerRecord.cs
Line coverage
100%
Covered lines: 231
Uncovered lines: 0
Coverable lines: 231
Total lines: 360
Line coverage: 100%
Branch coverage
89%
Covered branches: 41
Total branches: 46
Branch coverage: 89.1%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.cctor()100%11100%
.ctor(...)100%44100%
get_RecordId()100%11100%
get_SchemaVersion()100%11100%
get_EventId()100%11100%
get_AuditResidueId()100%11100%
get_OccurredUtc()100%11100%
get_RecordedUtc()100%11100%
get_ActorId()100%11100%
get_ActorType()100%11100%
get_ActorDisplayName()100%11100%
get_OperationName()100%11100%
get_Outcome()100%11100%
get_ReasonCodes()100%11100%
get_CorrelationId()100%11100%
get_TraceId()100%11100%
get_SpanId()100%11100%
get_ParentSpanId()100%11100%
get_DecisionLatencyMs()100%11100%
get_ConstraintSetHash()100%11100%
get_ConstraintCount()100%11100%
get_RiskScore()100%11100%
get_PolicyScope()100%11100%
get_TenantHash()100%11100%
get_OrganizationHash()100%11100%
get_EmitterStatus()100%11100%
get_EmitterProvider()100%11100%
get_OutboxSequence()100%11100%
get_GatewayExecutionId()100%11100%
get_DecisionStage()100%11100%
get_PolicyVersion()100%11100%
get_PolicyHash()100%11100%
get_HandshakeId()100%11100%
get_AcknowledgmentId()100%11100%
get_CapabilityTokenId()100%11100%
get_PreviousRecordHash()100%11100%
get_RecordHash()100%11100%
get_SigningHash()100%11100%
get_SignatureKeyId()100%11100%
get_SignatureKeyVersion()100%11100%
get_SignatureAlgorithm()100%11100%
get_SignatureValue()100%11100%
get_SignatureProvider()100%11100%
get_SignedUtc()100%11100%
get_SigningMetadata()100%11100%
get_Metadata()100%11100%
get_HasReasonCodes()100%11100%
get_HasMetadata()100%11100%
FromResidue(...)100%44100%
NormalizeIdentifier(...)100%22100%
NormalizeOptional(...)100%22100%
NormalizeNonNegative(...)50%22100%
NormalizeNonNegative(...)50%22100%
NormalizeRiskScore(...)62.5%88100%
NormalizeReasonCodes(...)100%66100%
NormalizeMetadata(...)100%1616100%

File(s)

/home/runner/work/AsiBackbone/AsiBackbone/src/AsiBackbone.Core/Audit/AuditLedgerRecord.cs

#LineLine coverage
 1using System.Collections.ObjectModel;
 2using AsiBackbone.Core.Actors;
 3using AsiBackbone.Core.Serialization;
 4using SigningMetadataValue = AsiBackbone.Core.Signing.SigningMetadata;
 5
 6namespace AsiBackbone.Core.Audit;
 7
 8/// <summary>
 9/// Represents a persistence-ready audit ledger record captured from AsiBackbone audit residue.
 10/// </summary>
 11public sealed class AuditLedgerRecord : IAsiBackboneAuditResidue
 12{
 613    private static readonly ReadOnlyCollection<string> EmptyReasonCodes =
 614        Array.AsReadOnly(Array.Empty<string>());
 15
 616    private static readonly IReadOnlyDictionary<string, string> EmptyMetadata =
 617        new ReadOnlyDictionary<string, string>(
 618            new Dictionary<string, string>(StringComparer.Ordinal));
 19
 13620    private AuditLedgerRecord(
 13621        string recordId,
 13622        string? schemaVersion,
 13623        string eventId,
 13624        string? auditResidueId,
 13625        DateTimeOffset occurredUtc,
 13626        DateTimeOffset recordedUtc,
 13627        string actorId,
 13628        AsiBackboneActorType actorType,
 13629        string? actorDisplayName,
 13630        string operationName,
 13631        string outcome,
 13632        IReadOnlyList<string> reasonCodes,
 13633        string? correlationId,
 13634        string? traceId,
 13635        string? spanId,
 13636        string? parentSpanId,
 13637        long? decisionLatencyMs,
 13638        string? constraintSetHash,
 13639        int? constraintCount,
 13640        double? riskScore,
 13641        string? policyScope,
 13642        string? tenantHash,
 13643        string? organizationHash,
 13644        string? emitterStatus,
 13645        string? emitterProvider,
 13646        long? outboxSequence,
 13647        string? gatewayExecutionId,
 13648        string? decisionStage,
 13649        string? policyVersion,
 13650        string? policyHash,
 13651        string? handshakeId,
 13652        string? acknowledgmentId,
 13653        string? capabilityTokenId,
 13654        string? previousRecordHash,
 13655        string? recordHash,
 13656        string? signatureKeyId,
 13657        string? signatureAlgorithm,
 13658        string? signatureValue,
 13659        string? signingHash,
 13660        string? signatureKeyVersion,
 13661        string? signatureProvider,
 13662        DateTimeOffset? signedUtc,
 13663        IReadOnlyDictionary<string, string> metadata)
 64    {
 13665        ArgumentException.ThrowIfNullOrWhiteSpace(recordId);
 13666        ArgumentException.ThrowIfNullOrWhiteSpace(eventId);
 13467        ArgumentException.ThrowIfNullOrWhiteSpace(actorId);
 13268        ArgumentException.ThrowIfNullOrWhiteSpace(operationName);
 13069        ArgumentException.ThrowIfNullOrWhiteSpace(outcome);
 70
 12871        RecordId = recordId.Trim();
 12872        SchemaVersion = AsiBackboneSchemaVersions.Normalize(schemaVersion);
 12873        EventId = eventId.Trim();
 12874        AuditResidueId = NormalizeOptional(auditResidueId) ?? EventId;
 12875        OccurredUtc = occurredUtc.ToUniversalTime();
 12876        RecordedUtc = recordedUtc.ToUniversalTime();
 12877        ActorId = actorId.Trim();
 12878        ActorType = actorType;
 12879        ActorDisplayName = NormalizeOptional(actorDisplayName);
 12880        OperationName = operationName.Trim();
 12881        Outcome = outcome.Trim();
 12882        ReasonCodes = reasonCodes;
 12883        CorrelationId = NormalizeOptional(correlationId);
 12884        TraceId = NormalizeOptional(traceId);
 12885        SpanId = NormalizeOptional(spanId);
 12886        ParentSpanId = NormalizeOptional(parentSpanId);
 12887        DecisionLatencyMs = NormalizeNonNegative(decisionLatencyMs, nameof(decisionLatencyMs));
 12888        ConstraintSetHash = NormalizeOptional(constraintSetHash);
 12889        ConstraintCount = NormalizeNonNegative(constraintCount, nameof(constraintCount));
 12890        RiskScore = NormalizeRiskScore(riskScore);
 12891        PolicyScope = NormalizeOptional(policyScope);
 12892        TenantHash = NormalizeOptional(tenantHash);
 12893        OrganizationHash = NormalizeOptional(organizationHash);
 12894        EmitterStatus = NormalizeOptional(emitterStatus);
 12895        EmitterProvider = NormalizeOptional(emitterProvider);
 12896        OutboxSequence = NormalizeNonNegative(outboxSequence, nameof(outboxSequence));
 12897        GatewayExecutionId = NormalizeOptional(gatewayExecutionId);
 12898        DecisionStage = NormalizeOptional(decisionStage);
 12899        PolicyVersion = NormalizeOptional(policyVersion);
 128100        PolicyHash = NormalizeOptional(policyHash);
 128101        HandshakeId = NormalizeOptional(handshakeId);
 128102        AcknowledgmentId = NormalizeOptional(acknowledgmentId);
 128103        CapabilityTokenId = NormalizeOptional(capabilityTokenId);
 128104        PreviousRecordHash = NormalizeOptional(previousRecordHash);
 128105        RecordHash = NormalizeOptional(recordHash);
 128106        SignatureKeyId = NormalizeOptional(signatureKeyId);
 128107        SignatureAlgorithm = NormalizeOptional(signatureAlgorithm);
 128108        SignatureValue = NormalizeOptional(signatureValue);
 128109        SigningHash = NormalizeOptional(signingHash);
 128110        SignatureKeyVersion = NormalizeOptional(signatureKeyVersion);
 128111        SignatureProvider = NormalizeOptional(signatureProvider);
 128112        SignedUtc = signedUtc?.ToUniversalTime();
 128113        SigningMetadata = SigningMetadataValue.Create(
 128114            SigningHash,
 128115            null,
 128116            SignatureValue,
 128117            SignatureAlgorithm,
 128118            SignatureKeyId,
 128119            SignatureKeyVersion,
 128120            SignatureProvider,
 128121            SignedUtc);
 128122        Metadata = metadata;
 128123    }
 124
 134125    public string RecordId { get; }
 126
 72127    public string SchemaVersion { get; }
 128
 50129    public string EventId { get; }
 130
 44131    public string AuditResidueId { get; }
 132
 48133    public DateTimeOffset OccurredUtc { get; }
 134
 74135    public DateTimeOffset RecordedUtc { get; }
 136
 54137    public string ActorId { get; }
 138
 48139    public AsiBackboneActorType ActorType { get; }
 140
 50141    public string? ActorDisplayName { get; }
 142
 48143    public string OperationName { get; }
 144
 48145    public string Outcome { get; }
 146
 86147    public IReadOnlyList<string> ReasonCodes { get; }
 148
 58149    public string? CorrelationId { get; }
 150
 58151    public string? TraceId { get; }
 152
 44153    public string? SpanId { get; }
 154
 44155    public string? ParentSpanId { get; }
 156
 44157    public long? DecisionLatencyMs { get; }
 158
 44159    public string? ConstraintSetHash { get; }
 160
 44161    public int? ConstraintCount { get; }
 162
 44163    public double? RiskScore { get; }
 164
 44165    public string? PolicyScope { get; }
 166
 44167    public string? TenantHash { get; }
 168
 44169    public string? OrganizationHash { get; }
 170
 44171    public string? EmitterStatus { get; }
 172
 44173    public string? EmitterProvider { get; }
 174
 44175    public long? OutboxSequence { get; }
 176
 44177    public string? GatewayExecutionId { get; }
 178
 44179    public string? DecisionStage { get; }
 180
 50181    public string? PolicyVersion { get; }
 182
 50183    public string? PolicyHash { get; }
 184
 50185    public string? HandshakeId { get; }
 186
 50187    public string? AcknowledgmentId { get; }
 188
 52189    public string? CapabilityTokenId { get; }
 190
 50191    public string? PreviousRecordHash { get; }
 192
 30193    public string? RecordHash { get; }
 194
 156195    public string? SigningHash { get; }
 196
 158197    public string? SignatureKeyId { get; }
 198
 156199    public string? SignatureKeyVersion { get; }
 200
 158201    public string? SignatureAlgorithm { get; }
 202
 158203    public string? SignatureValue { get; }
 204
 154205    public string? SignatureProvider { get; }
 206
 154207    public DateTimeOffset? SignedUtc { get; }
 208
 38209    public SigningMetadataValue SigningMetadata { get; }
 210
 126211    public IReadOnlyDictionary<string, string> Metadata { get; }
 212
 12213    public bool HasReasonCodes => ReasonCodes.Count > 0;
 214
 20215    public bool HasMetadata => Metadata.Count > 0;
 216
 217    public static AuditLedgerRecord FromResidue(
 218        IAsiBackboneAuditResidue residue,
 219        string? recordId = null,
 220        DateTimeOffset? recordedUtc = null,
 221        string? handshakeId = null,
 222        string? acknowledgmentId = null,
 223        string? capabilityTokenId = null,
 224        string? previousRecordHash = null,
 225        string? recordHash = null,
 226        string? signatureKeyId = null,
 227        string? signatureAlgorithm = null,
 228        string? signatureValue = null,
 229        string? signingHash = null,
 230        string? signatureKeyVersion = null,
 231        string? signatureProvider = null,
 232        DateTimeOffset? signedUtc = null,
 233        IReadOnlyDictionary<string, string>? metadata = null,
 234        string? schemaVersion = null)
 235    {
 138236        ArgumentNullException.ThrowIfNull(residue);
 237
 136238        return new AuditLedgerRecord(
 136239            NormalizeIdentifier(recordId),
 136240            schemaVersion ?? residue.SchemaVersion,
 136241            residue.EventId,
 136242            residue.AuditResidueId,
 136243            residue.OccurredUtc,
 136244            recordedUtc ?? DateTimeOffset.UtcNow,
 136245            residue.ActorId,
 136246            residue.ActorType,
 136247            residue.ActorDisplayName,
 136248            residue.OperationName,
 136249            residue.Outcome,
 136250            NormalizeReasonCodes(residue.ReasonCodes),
 136251            residue.CorrelationId,
 136252            residue.TraceId,
 136253            residue.SpanId,
 136254            residue.ParentSpanId,
 136255            residue.DecisionLatencyMs,
 136256            residue.ConstraintSetHash,
 136257            residue.ConstraintCount,
 136258            residue.RiskScore,
 136259            residue.PolicyScope,
 136260            residue.TenantHash,
 136261            residue.OrganizationHash,
 136262            residue.EmitterStatus,
 136263            residue.EmitterProvider,
 136264            residue.OutboxSequence,
 136265            residue.GatewayExecutionId,
 136266            residue.DecisionStage,
 136267            residue.PolicyVersion,
 136268            residue.PolicyHash,
 136269            handshakeId,
 136270            acknowledgmentId,
 136271            capabilityTokenId,
 136272            previousRecordHash,
 136273            recordHash,
 136274            signatureKeyId,
 136275            signatureAlgorithm,
 136276            signatureValue,
 136277            signingHash,
 136278            signatureKeyVersion,
 136279            signatureProvider,
 136280            signedUtc,
 136281            NormalizeMetadata(residue.Metadata, metadata));
 282    }
 283
 284    private static string NormalizeIdentifier(string? identifier)
 285    {
 136286        return string.IsNullOrWhiteSpace(identifier)
 136287            ? Guid.NewGuid().ToString("N")
 136288            : identifier.Trim();
 289    }
 290
 291    private static string? NormalizeOptional(string? value)
 292    {
 3456293        return string.IsNullOrWhiteSpace(value)
 3456294            ? null
 3456295            : value.Trim();
 296    }
 297
 298    private static long? NormalizeNonNegative(long? value, string parameterName)
 299    {
 256300        return value < 0
 256301            ? throw new ArgumentOutOfRangeException(parameterName, value, "Value must be greater than or equal to zero."
 256302            : value;
 303    }
 304
 305    private static int? NormalizeNonNegative(int? value, string parameterName)
 306    {
 128307        return value < 0
 128308            ? throw new ArgumentOutOfRangeException(parameterName, value, "Value must be greater than or equal to zero."
 128309            : value;
 310    }
 311
 312    private static double? NormalizeRiskScore(double? riskScore)
 313    {
 128314        return riskScore is null
 128315            ? null
 128316            : double.IsNaN(riskScore.Value) || double.IsInfinity(riskScore.Value) || riskScore.Value < 0
 128317            ? throw new ArgumentOutOfRangeException(nameof(riskScore), riskScore, "Risk score must be a finite value gre
 128318            : riskScore;
 319    }
 320
 321    private static ReadOnlyCollection<string> NormalizeReasonCodes(IEnumerable<string>? reasonCodes)
 322    {
 136323        string[] normalizedReasonCodes = reasonCodes?
 96324            .Where(reasonCode => !string.IsNullOrWhiteSpace(reasonCode))
 90325            .Select(reasonCode => reasonCode.Trim())
 136326            .ToArray() ?? [];
 327
 136328        return normalizedReasonCodes.Length == 0
 136329            ? EmptyReasonCodes
 136330            : Array.AsReadOnly(normalizedReasonCodes);
 331    }
 332
 333    private static IReadOnlyDictionary<string, string> NormalizeMetadata(
 334        params IReadOnlyDictionary<string, string>?[] metadataSets)
 335    {
 136336        Dictionary<string, string> normalizedMetadata = new(StringComparer.Ordinal);
 337
 816338        foreach (IReadOnlyDictionary<string, string>? metadata in metadataSets)
 339        {
 272340            if (metadata is null || metadata.Count == 0)
 341            {
 342                continue;
 343            }
 344
 336345            foreach (KeyValuePair<string, string> item in metadata)
 346            {
 96347                if (string.IsNullOrWhiteSpace(item.Key))
 348                {
 349                    continue;
 350                }
 351
 90352                normalizedMetadata[item.Key.Trim()] = item.Value?.Trim() ?? string.Empty;
 353            }
 354        }
 355
 136356        return normalizedMetadata.Count == 0
 136357            ? EmptyMetadata
 136358            : new ReadOnlyDictionary<string, string>(normalizedMetadata);
 359    }
 360}

Methods/Properties

.cctor()
.ctor(System.String,System.String,System.String,System.String,System.DateTimeOffset,System.DateTimeOffset,System.String,AsiBackbone.Core.Actors.AsiBackboneActorType,System.String,System.String,System.String,System.Collections.Generic.IReadOnlyList`1<System.String>,System.String,System.String,System.String,System.String,System.Nullable`1<System.Int64>,System.String,System.Nullable`1<System.Int32>,System.Nullable`1<System.Double>,System.String,System.String,System.String,System.String,System.String,System.Nullable`1<System.Int64>,System.String,System.String,System.String,System.String,System.String,System.String,System.String,System.String,System.String,System.String,System.String,System.String,System.String,System.String,System.String,System.Nullable`1<System.DateTimeOffset>,System.Collections.Generic.IReadOnlyDictionary`2<System.String,System.String>)
get_RecordId()
get_SchemaVersion()
get_EventId()
get_AuditResidueId()
get_OccurredUtc()
get_RecordedUtc()
get_ActorId()
get_ActorType()
get_ActorDisplayName()
get_OperationName()
get_Outcome()
get_ReasonCodes()
get_CorrelationId()
get_TraceId()
get_SpanId()
get_ParentSpanId()
get_DecisionLatencyMs()
get_ConstraintSetHash()
get_ConstraintCount()
get_RiskScore()
get_PolicyScope()
get_TenantHash()
get_OrganizationHash()
get_EmitterStatus()
get_EmitterProvider()
get_OutboxSequence()
get_GatewayExecutionId()
get_DecisionStage()
get_PolicyVersion()
get_PolicyHash()
get_HandshakeId()
get_AcknowledgmentId()
get_CapabilityTokenId()
get_PreviousRecordHash()
get_RecordHash()
get_SigningHash()
get_SignatureKeyId()
get_SignatureKeyVersion()
get_SignatureAlgorithm()
get_SignatureValue()
get_SignatureProvider()
get_SignedUtc()
get_SigningMetadata()
get_Metadata()
get_HasReasonCodes()
get_HasMetadata()
FromResidue(AsiBackbone.Core.Audit.IAsiBackboneAuditResidue,System.String,System.Nullable`1<System.DateTimeOffset>,System.String,System.String,System.String,System.String,System.String,System.String,System.String,System.String,System.String,System.String,System.String,System.Nullable`1<System.DateTimeOffset>,System.Collections.Generic.IReadOnlyDictionary`2<System.String,System.String>,System.String)
NormalizeIdentifier(System.String)
NormalizeOptional(System.String)
NormalizeNonNegative(System.Nullable`1<System.Int64>,System.String)
NormalizeNonNegative(System.Nullable`1<System.Int32>,System.String)
NormalizeRiskScore(System.Nullable`1<System.Double>)
NormalizeReasonCodes(System.Collections.Generic.IEnumerable`1<System.String>)
NormalizeMetadata(System.Collections.Generic.IReadOnlyDictionary`2<System.String,System.String>[])