< 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(...)75%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{
 413    private static readonly ReadOnlyCollection<string> EmptyReasonCodes =
 414        Array.AsReadOnly(Array.Empty<string>());
 15
 416    private static readonly IReadOnlyDictionary<string, string> EmptyMetadata =
 417        new ReadOnlyDictionary<string, string>(
 418            new Dictionary<string, string>(StringComparer.Ordinal));
 19
 8420    private AuditLedgerRecord(
 8421        string recordId,
 8422        string? schemaVersion,
 8423        string eventId,
 8424        string? auditResidueId,
 8425        DateTimeOffset occurredUtc,
 8426        DateTimeOffset recordedUtc,
 8427        string actorId,
 8428        AsiBackboneActorType actorType,
 8429        string? actorDisplayName,
 8430        string operationName,
 8431        string outcome,
 8432        IReadOnlyList<string> reasonCodes,
 8433        string? correlationId,
 8434        string? traceId,
 8435        string? spanId,
 8436        string? parentSpanId,
 8437        long? decisionLatencyMs,
 8438        string? constraintSetHash,
 8439        int? constraintCount,
 8440        double? riskScore,
 8441        string? policyScope,
 8442        string? tenantHash,
 8443        string? organizationHash,
 8444        string? emitterStatus,
 8445        string? emitterProvider,
 8446        long? outboxSequence,
 8447        string? gatewayExecutionId,
 8448        string? decisionStage,
 8449        string? policyVersion,
 8450        string? policyHash,
 8451        string? handshakeId,
 8452        string? acknowledgmentId,
 8453        string? capabilityTokenId,
 8454        string? previousRecordHash,
 8455        string? recordHash,
 8456        string? signatureKeyId,
 8457        string? signatureAlgorithm,
 8458        string? signatureValue,
 8459        string? signingHash,
 8460        string? signatureKeyVersion,
 8461        string? signatureProvider,
 8462        DateTimeOffset? signedUtc,
 8463        IReadOnlyDictionary<string, string> metadata)
 64    {
 8465        ArgumentException.ThrowIfNullOrWhiteSpace(recordId);
 8466        ArgumentException.ThrowIfNullOrWhiteSpace(eventId);
 8367        ArgumentException.ThrowIfNullOrWhiteSpace(actorId);
 8268        ArgumentException.ThrowIfNullOrWhiteSpace(operationName);
 8169        ArgumentException.ThrowIfNullOrWhiteSpace(outcome);
 70
 8071        RecordId = recordId.Trim();
 8072        SchemaVersion = AsiBackboneSchemaVersions.Normalize(schemaVersion);
 8073        EventId = eventId.Trim();
 8074        AuditResidueId = NormalizeOptional(auditResidueId) ?? EventId;
 8075        OccurredUtc = occurredUtc.ToUniversalTime();
 8076        RecordedUtc = recordedUtc.ToUniversalTime();
 8077        ActorId = actorId.Trim();
 8078        ActorType = actorType;
 8079        ActorDisplayName = NormalizeOptional(actorDisplayName);
 8080        OperationName = operationName.Trim();
 8081        Outcome = outcome.Trim();
 8082        ReasonCodes = reasonCodes;
 8083        CorrelationId = NormalizeOptional(correlationId);
 8084        TraceId = NormalizeOptional(traceId);
 8085        SpanId = NormalizeOptional(spanId);
 8086        ParentSpanId = NormalizeOptional(parentSpanId);
 8087        DecisionLatencyMs = NormalizeNonNegative(decisionLatencyMs, nameof(decisionLatencyMs));
 8088        ConstraintSetHash = NormalizeOptional(constraintSetHash);
 8089        ConstraintCount = NormalizeNonNegative(constraintCount, nameof(constraintCount));
 8090        RiskScore = NormalizeRiskScore(riskScore);
 8091        PolicyScope = NormalizeOptional(policyScope);
 8092        TenantHash = NormalizeOptional(tenantHash);
 8093        OrganizationHash = NormalizeOptional(organizationHash);
 8094        EmitterStatus = NormalizeOptional(emitterStatus);
 8095        EmitterProvider = NormalizeOptional(emitterProvider);
 8096        OutboxSequence = NormalizeNonNegative(outboxSequence, nameof(outboxSequence));
 8097        GatewayExecutionId = NormalizeOptional(gatewayExecutionId);
 8098        DecisionStage = NormalizeOptional(decisionStage);
 8099        PolicyVersion = NormalizeOptional(policyVersion);
 80100        PolicyHash = NormalizeOptional(policyHash);
 80101        HandshakeId = NormalizeOptional(handshakeId);
 80102        AcknowledgmentId = NormalizeOptional(acknowledgmentId);
 80103        CapabilityTokenId = NormalizeOptional(capabilityTokenId);
 80104        PreviousRecordHash = NormalizeOptional(previousRecordHash);
 80105        RecordHash = NormalizeOptional(recordHash);
 80106        SignatureKeyId = NormalizeOptional(signatureKeyId);
 80107        SignatureAlgorithm = NormalizeOptional(signatureAlgorithm);
 80108        SignatureValue = NormalizeOptional(signatureValue);
 80109        SigningHash = NormalizeOptional(signingHash);
 80110        SignatureKeyVersion = NormalizeOptional(signatureKeyVersion);
 80111        SignatureProvider = NormalizeOptional(signatureProvider);
 80112        SignedUtc = signedUtc?.ToUniversalTime();
 80113        SigningMetadata = SigningMetadataValue.Create(
 80114            SigningHash,
 80115            null,
 80116            SignatureValue,
 80117            SignatureAlgorithm,
 80118            SignatureKeyId,
 80119            SignatureKeyVersion,
 80120            SignatureProvider,
 80121            SignedUtc);
 80122        Metadata = metadata;
 80123    }
 124
 82125    public string RecordId { get; }
 126
 43127    public string SchemaVersion { get; }
 128
 34129    public string EventId { get; }
 130
 28131    public string AuditResidueId { get; }
 132
 32133    public DateTimeOffset OccurredUtc { get; }
 134
 45135    public DateTimeOffset RecordedUtc { get; }
 136
 35137    public string ActorId { get; }
 138
 32139    public AsiBackboneActorType ActorType { get; }
 140
 33141    public string? ActorDisplayName { get; }
 142
 32143    public string OperationName { get; }
 144
 32145    public string Outcome { get; }
 146
 58147    public IReadOnlyList<string> ReasonCodes { get; }
 148
 37149    public string? CorrelationId { get; }
 150
 37151    public string? TraceId { get; }
 152
 28153    public string? SpanId { get; }
 154
 28155    public string? ParentSpanId { get; }
 156
 28157    public long? DecisionLatencyMs { get; }
 158
 28159    public string? ConstraintSetHash { get; }
 160
 28161    public int? ConstraintCount { get; }
 162
 28163    public double? RiskScore { get; }
 164
 28165    public string? PolicyScope { get; }
 166
 28167    public string? TenantHash { get; }
 168
 28169    public string? OrganizationHash { get; }
 170
 28171    public string? EmitterStatus { get; }
 172
 28173    public string? EmitterProvider { get; }
 174
 28175    public long? OutboxSequence { get; }
 176
 28177    public string? GatewayExecutionId { get; }
 178
 28179    public string? DecisionStage { get; }
 180
 33181    public string? PolicyVersion { get; }
 182
 33183    public string? PolicyHash { get; }
 184
 33185    public string? HandshakeId { get; }
 186
 33187    public string? AcknowledgmentId { get; }
 188
 34189    public string? CapabilityTokenId { get; }
 190
 33191    public string? PreviousRecordHash { get; }
 192
 23193    public string? RecordHash { get; }
 194
 84195    public string? SigningHash { get; }
 196
 103197    public string? SignatureKeyId { get; }
 198
 84199    public string? SignatureKeyVersion { get; }
 200
 103201    public string? SignatureAlgorithm { get; }
 202
 103203    public string? SignatureValue { get; }
 204
 83205    public string? SignatureProvider { get; }
 206
 83207    public DateTimeOffset? SignedUtc { get; }
 208
 5209    public SigningMetadataValue SigningMetadata { get; }
 210
 78211    public IReadOnlyDictionary<string, string> Metadata { get; }
 212
 6213    public bool HasReasonCodes => ReasonCodes.Count > 0;
 214
 10215    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    {
 85236        ArgumentNullException.ThrowIfNull(residue);
 237
 84238        return new AuditLedgerRecord(
 84239            NormalizeIdentifier(recordId),
 84240            schemaVersion ?? residue.SchemaVersion,
 84241            residue.EventId,
 84242            residue.AuditResidueId,
 84243            residue.OccurredUtc,
 84244            recordedUtc ?? DateTimeOffset.UtcNow,
 84245            residue.ActorId,
 84246            residue.ActorType,
 84247            residue.ActorDisplayName,
 84248            residue.OperationName,
 84249            residue.Outcome,
 84250            NormalizeReasonCodes(residue.ReasonCodes),
 84251            residue.CorrelationId,
 84252            residue.TraceId,
 84253            residue.SpanId,
 84254            residue.ParentSpanId,
 84255            residue.DecisionLatencyMs,
 84256            residue.ConstraintSetHash,
 84257            residue.ConstraintCount,
 84258            residue.RiskScore,
 84259            residue.PolicyScope,
 84260            residue.TenantHash,
 84261            residue.OrganizationHash,
 84262            residue.EmitterStatus,
 84263            residue.EmitterProvider,
 84264            residue.OutboxSequence,
 84265            residue.GatewayExecutionId,
 84266            residue.DecisionStage,
 84267            residue.PolicyVersion,
 84268            residue.PolicyHash,
 84269            handshakeId,
 84270            acknowledgmentId,
 84271            capabilityTokenId,
 84272            previousRecordHash,
 84273            recordHash,
 84274            signatureKeyId,
 84275            signatureAlgorithm,
 84276            signatureValue,
 84277            signingHash,
 84278            signatureKeyVersion,
 84279            signatureProvider,
 84280            signedUtc,
 84281            NormalizeMetadata(residue.Metadata, metadata));
 282    }
 283
 284    private static string NormalizeIdentifier(string? identifier)
 285    {
 84286        return string.IsNullOrWhiteSpace(identifier)
 84287            ? Guid.NewGuid().ToString("N")
 84288            : identifier.Trim();
 289    }
 290
 291    private static string? NormalizeOptional(string? value)
 292    {
 2160293        return string.IsNullOrWhiteSpace(value)
 2160294            ? null
 2160295            : value.Trim();
 296    }
 297
 298    private static long? NormalizeNonNegative(long? value, string parameterName)
 299    {
 160300        return value < 0
 160301            ? throw new ArgumentOutOfRangeException(parameterName, value, "Value must be greater than or equal to zero."
 160302            : value;
 303    }
 304
 305    private static int? NormalizeNonNegative(int? value, string parameterName)
 306    {
 80307        return value < 0
 80308            ? throw new ArgumentOutOfRangeException(parameterName, value, "Value must be greater than or equal to zero."
 80309            : value;
 310    }
 311
 312    private static double? NormalizeRiskScore(double? riskScore)
 313    {
 80314        return riskScore is null
 80315            ? null
 80316            : double.IsNaN(riskScore.Value) || double.IsInfinity(riskScore.Value) || riskScore.Value < 0
 80317            ? throw new ArgumentOutOfRangeException(nameof(riskScore), riskScore, "Risk score must be a finite value gre
 80318            : riskScore;
 319    }
 320
 321    private static ReadOnlyCollection<string> NormalizeReasonCodes(IEnumerable<string>? reasonCodes)
 322    {
 84323        string[] normalizedReasonCodes = reasonCodes?
 56324            .Where(reasonCode => !string.IsNullOrWhiteSpace(reasonCode))
 53325            .Select(reasonCode => reasonCode.Trim())
 84326            .ToArray() ?? [];
 327
 84328        return normalizedReasonCodes.Length == 0
 84329            ? EmptyReasonCodes
 84330            : Array.AsReadOnly(normalizedReasonCodes);
 331    }
 332
 333    private static IReadOnlyDictionary<string, string> NormalizeMetadata(
 334        params IReadOnlyDictionary<string, string>?[] metadataSets)
 335    {
 84336        Dictionary<string, string> normalizedMetadata = new(StringComparer.Ordinal);
 337
 504338        foreach (IReadOnlyDictionary<string, string>? metadata in metadataSets)
 339        {
 168340            if (metadata is null || metadata.Count == 0)
 341            {
 342                continue;
 343            }
 344
 188345            foreach (KeyValuePair<string, string> item in metadata)
 346            {
 54347                if (string.IsNullOrWhiteSpace(item.Key))
 348                {
 349                    continue;
 350                }
 351
 51352                normalizedMetadata[item.Key.Trim()] = item.Value?.Trim() ?? string.Empty;
 353            }
 354        }
 355
 84356        return normalizedMetadata.Count == 0
 84357            ? EmptyMetadata
 84358            : 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>[])