warnings fixes, tests fixes, sprints completions
This commit is contained in:
@@ -20,10 +20,12 @@ public sealed class RvaBuilder
|
||||
private DateTimeOffset? _expiresAt;
|
||||
private readonly Dictionary<string, string> _metadata = [];
|
||||
private readonly ICryptoHash _cryptoHash;
|
||||
private readonly TimeProvider _timeProvider;
|
||||
|
||||
public RvaBuilder(ICryptoHash cryptoHash)
|
||||
public RvaBuilder(ICryptoHash cryptoHash, TimeProvider timeProvider)
|
||||
{
|
||||
_cryptoHash = cryptoHash ?? throw new ArgumentNullException(nameof(cryptoHash));
|
||||
_timeProvider = timeProvider ?? throw new ArgumentNullException(nameof(timeProvider));
|
||||
}
|
||||
|
||||
public RvaBuilder WithVerdict(RiskVerdictStatus verdict)
|
||||
@@ -162,7 +164,7 @@ public sealed class RvaBuilder
|
||||
if (_snapshotId is null)
|
||||
throw new InvalidOperationException("Knowledge snapshot ID is required");
|
||||
|
||||
var createdAt = DateTimeOffset.UtcNow;
|
||||
var createdAt = _timeProvider.GetUtcNow();
|
||||
|
||||
var attestation = new RiskVerdictAttestation
|
||||
{
|
||||
|
||||
@@ -16,14 +16,17 @@ public sealed class RvaVerifier : IRvaVerifier
|
||||
private readonly ICryptoSigner? _signer;
|
||||
private readonly ISnapshotService _snapshotService;
|
||||
private readonly ILogger<RvaVerifier> _logger;
|
||||
private readonly TimeProvider _timeProvider;
|
||||
|
||||
public RvaVerifier(
|
||||
ISnapshotService snapshotService,
|
||||
ILogger<RvaVerifier> logger,
|
||||
TimeProvider timeProvider,
|
||||
ICryptoSigner? signer = null)
|
||||
{
|
||||
_snapshotService = snapshotService ?? throw new ArgumentNullException(nameof(snapshotService));
|
||||
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
||||
_timeProvider = timeProvider ?? throw new ArgumentNullException(nameof(timeProvider));
|
||||
_signer = signer;
|
||||
}
|
||||
|
||||
@@ -51,7 +54,7 @@ public sealed class RvaVerifier : IRvaVerifier
|
||||
issues.Add($"Signature verification failed: {sigResult.Error}");
|
||||
if (!options.ContinueOnSignatureFailure)
|
||||
{
|
||||
return RvaVerificationResult.Fail(issues);
|
||||
return RvaVerificationResult.Fail(issues, _timeProvider);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -61,7 +64,7 @@ public sealed class RvaVerifier : IRvaVerifier
|
||||
if (attestation is null)
|
||||
{
|
||||
issues.Add("Failed to parse RVA payload");
|
||||
return RvaVerificationResult.Fail(issues);
|
||||
return RvaVerificationResult.Fail(issues, _timeProvider);
|
||||
}
|
||||
|
||||
// Step 3: Verify content-addressed ID
|
||||
@@ -69,18 +72,18 @@ public sealed class RvaVerifier : IRvaVerifier
|
||||
if (!idValid)
|
||||
{
|
||||
issues.Add("Attestation ID does not match content");
|
||||
return RvaVerificationResult.Fail(issues);
|
||||
return RvaVerificationResult.Fail(issues, _timeProvider);
|
||||
}
|
||||
|
||||
// Step 4: Verify expiration
|
||||
if (options.CheckExpiration && attestation.ExpiresAt.HasValue)
|
||||
{
|
||||
if (attestation.ExpiresAt.Value < DateTimeOffset.UtcNow)
|
||||
if (attestation.ExpiresAt.Value < _timeProvider.GetUtcNow())
|
||||
{
|
||||
issues.Add($"Attestation expired at {attestation.ExpiresAt.Value:o}");
|
||||
if (!options.AllowExpired)
|
||||
{
|
||||
return RvaVerificationResult.Fail(issues);
|
||||
return RvaVerificationResult.Fail(issues, _timeProvider);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -106,7 +109,7 @@ public sealed class RvaVerifier : IRvaVerifier
|
||||
Attestation = attestation,
|
||||
SignerIdentity = signerIdentity,
|
||||
Issues = issues,
|
||||
VerifiedAt = DateTimeOffset.UtcNow
|
||||
VerifiedAt = _timeProvider.GetUtcNow()
|
||||
};
|
||||
}
|
||||
|
||||
@@ -127,18 +130,18 @@ public sealed class RvaVerifier : IRvaVerifier
|
||||
if (!idValid)
|
||||
{
|
||||
issues.Add("Attestation ID does not match content");
|
||||
return Task.FromResult(RvaVerificationResult.Fail(issues));
|
||||
return Task.FromResult(RvaVerificationResult.Fail(issues, _timeProvider));
|
||||
}
|
||||
|
||||
// Verify expiration
|
||||
if (options.CheckExpiration && attestation.ExpiresAt.HasValue)
|
||||
{
|
||||
if (attestation.ExpiresAt.Value < DateTimeOffset.UtcNow)
|
||||
if (attestation.ExpiresAt.Value < _timeProvider.GetUtcNow())
|
||||
{
|
||||
issues.Add($"Attestation expired at {attestation.ExpiresAt.Value:o}");
|
||||
if (!options.AllowExpired)
|
||||
{
|
||||
return Task.FromResult(RvaVerificationResult.Fail(issues));
|
||||
return Task.FromResult(RvaVerificationResult.Fail(issues, _timeProvider));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -152,7 +155,7 @@ public sealed class RvaVerifier : IRvaVerifier
|
||||
Attestation = attestation,
|
||||
SignerIdentity = null,
|
||||
Issues = issues,
|
||||
VerifiedAt = DateTimeOffset.UtcNow
|
||||
VerifiedAt = _timeProvider.GetUtcNow()
|
||||
});
|
||||
}
|
||||
|
||||
@@ -291,10 +294,10 @@ public sealed record RvaVerificationResult
|
||||
public RiskVerdictAttestation? Attestation { get; init; }
|
||||
public string? SignerIdentity { get; init; }
|
||||
public IReadOnlyList<string> Issues { get; init; } = [];
|
||||
public DateTimeOffset VerifiedAt { get; init; }
|
||||
public required DateTimeOffset VerifiedAt { get; init; }
|
||||
|
||||
public static RvaVerificationResult Fail(IReadOnlyList<string> issues) =>
|
||||
new() { IsValid = false, Issues = issues, VerifiedAt = DateTimeOffset.UtcNow };
|
||||
public static RvaVerificationResult Fail(IReadOnlyList<string> issues, TimeProvider timeProvider) =>
|
||||
new() { IsValid = false, Issues = issues, VerifiedAt = timeProvider.GetUtcNow() };
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -143,13 +143,15 @@ public sealed record ScoreProvenanceChain
|
||||
public static ScoreProvenanceChain FromVerdictPredicate(
|
||||
VerdictPredicate predicate,
|
||||
ProvenanceFindingRef finding,
|
||||
ProvenanceEvidenceSet evidenceSet)
|
||||
ProvenanceEvidenceSet evidenceSet,
|
||||
TimeProvider timeProvider)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(predicate);
|
||||
ArgumentNullException.ThrowIfNull(finding);
|
||||
ArgumentNullException.ThrowIfNull(evidenceSet);
|
||||
ArgumentNullException.ThrowIfNull(timeProvider);
|
||||
|
||||
var scoreNode = ProvenanceScoreNode.FromVerdictEws(predicate.EvidenceWeightedScore, predicate.FindingId);
|
||||
var scoreNode = ProvenanceScoreNode.FromVerdictEws(predicate.EvidenceWeightedScore, predicate.FindingId, timeProvider);
|
||||
var verdictRef = ProvenanceVerdictRef.FromVerdictPredicate(predicate);
|
||||
|
||||
return new ScoreProvenanceChain(
|
||||
@@ -157,7 +159,7 @@ public sealed record ScoreProvenanceChain
|
||||
evidenceSet: evidenceSet,
|
||||
score: scoreNode,
|
||||
verdict: verdictRef,
|
||||
createdAt: DateTimeOffset.UtcNow
|
||||
createdAt: timeProvider.GetUtcNow()
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -533,8 +535,9 @@ public sealed record ProvenanceScoreNode
|
||||
/// <summary>
|
||||
/// Creates a ProvenanceScoreNode from a VerdictEvidenceWeightedScore.
|
||||
/// </summary>
|
||||
public static ProvenanceScoreNode FromVerdictEws(VerdictEvidenceWeightedScore? ews, string findingId)
|
||||
public static ProvenanceScoreNode FromVerdictEws(VerdictEvidenceWeightedScore? ews, string findingId, TimeProvider timeProvider)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(timeProvider);
|
||||
if (ews is null)
|
||||
{
|
||||
// No EWS - create a placeholder node
|
||||
@@ -545,7 +548,7 @@ public sealed record ProvenanceScoreNode
|
||||
weights: new VerdictEvidenceWeights(0, 0, 0, 0, 0, 0),
|
||||
policyDigest: "none",
|
||||
calculatorVersion: "none",
|
||||
calculatedAt: DateTimeOffset.UtcNow
|
||||
calculatedAt: timeProvider.GetUtcNow()
|
||||
);
|
||||
}
|
||||
|
||||
@@ -560,7 +563,7 @@ public sealed record ProvenanceScoreNode
|
||||
weights: new VerdictEvidenceWeights(0, 0, 0, 0, 0, 0),
|
||||
policyDigest: ews.PolicyDigest ?? "unknown",
|
||||
calculatorVersion: "unknown",
|
||||
calculatedAt: ews.CalculatedAt ?? DateTimeOffset.UtcNow,
|
||||
calculatedAt: ews.CalculatedAt ?? timeProvider.GetUtcNow(),
|
||||
appliedFlags: ews.Flags,
|
||||
guardrails: ews.Guardrails
|
||||
);
|
||||
|
||||
@@ -12,7 +12,9 @@ public static class ExceptionMapper
|
||||
/// <summary>
|
||||
/// Maps an ExceptionObject to a full DTO.
|
||||
/// </summary>
|
||||
public static ExceptionDto ToDto(ExceptionObject exception)
|
||||
/// <param name="exception">The exception to map.</param>
|
||||
/// <param name="referenceTime">The reference time for IsEffective/HasExpired checks.</param>
|
||||
public static ExceptionDto ToDto(ExceptionObject exception, DateTimeOffset referenceTime)
|
||||
{
|
||||
return new ExceptionDto
|
||||
{
|
||||
@@ -34,15 +36,17 @@ public static class ExceptionMapper
|
||||
CompensatingControls = exception.CompensatingControls.ToList(),
|
||||
Metadata = exception.Metadata,
|
||||
TicketRef = exception.TicketRef,
|
||||
IsEffective = exception.IsEffective,
|
||||
HasExpired = exception.HasExpired
|
||||
IsEffective = exception.IsEffectiveAt(referenceTime),
|
||||
HasExpired = exception.HasExpiredAt(referenceTime)
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Maps an ExceptionObject to a summary DTO for list responses.
|
||||
/// </summary>
|
||||
public static ExceptionSummaryDto ToSummaryDto(ExceptionObject exception)
|
||||
/// <param name="exception">The exception to map.</param>
|
||||
/// <param name="referenceTime">The reference time for IsEffective check.</param>
|
||||
public static ExceptionSummaryDto ToSummaryDto(ExceptionObject exception, DateTimeOffset referenceTime)
|
||||
{
|
||||
return new ExceptionSummaryDto
|
||||
{
|
||||
@@ -54,7 +58,7 @@ public static class ExceptionMapper
|
||||
OwnerId = exception.OwnerId,
|
||||
ExpiresAt = exception.ExpiresAt,
|
||||
ReasonCode = ReasonToString(exception.ReasonCode),
|
||||
IsEffective = exception.IsEffective
|
||||
IsEffective = exception.IsEffectiveAt(referenceTime)
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using Microsoft.AspNetCore.Http.HttpResults;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using StellaOps.Auth.Abstractions;
|
||||
using StellaOps.Determinism.Abstractions;
|
||||
using StellaOps.Policy.Engine.Services;
|
||||
using StellaOps.Policy.Persistence.Postgres.Models;
|
||||
using StellaOps.Policy.Persistence.Postgres.Repositories;
|
||||
@@ -335,6 +336,8 @@ internal static class ViolationEndpoints
|
||||
HttpContext context,
|
||||
[FromBody] CreateViolationRequest request,
|
||||
IViolationEventRepository repository,
|
||||
TimeProvider timeProvider,
|
||||
IGuidProvider guidProvider,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var scopeResult = ScopeAuthorization.RequireScope(context, StellaOpsScopes.PolicyEdit);
|
||||
@@ -356,7 +359,7 @@ internal static class ViolationEndpoints
|
||||
|
||||
var entity = new ViolationEventEntity
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
Id = guidProvider.NewGuid(),
|
||||
TenantId = tenantId,
|
||||
PolicyId = request.PolicyId,
|
||||
RuleId = request.RuleId,
|
||||
@@ -366,7 +369,7 @@ internal static class ViolationEndpoints
|
||||
Details = request.Details ?? "{}",
|
||||
Remediation = request.Remediation,
|
||||
CorrelationId = request.CorrelationId,
|
||||
OccurredAt = request.OccurredAt ?? DateTimeOffset.UtcNow
|
||||
OccurredAt = request.OccurredAt ?? timeProvider.GetUtcNow()
|
||||
};
|
||||
|
||||
try
|
||||
@@ -389,6 +392,8 @@ internal static class ViolationEndpoints
|
||||
HttpContext context,
|
||||
[FromBody] CreateViolationBatchRequest request,
|
||||
IViolationEventRepository repository,
|
||||
TimeProvider timeProvider,
|
||||
IGuidProvider guidProvider,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var scopeResult = ScopeAuthorization.RequireScope(context, StellaOpsScopes.PolicyEdit);
|
||||
@@ -408,9 +413,10 @@ internal static class ViolationEndpoints
|
||||
});
|
||||
}
|
||||
|
||||
var now = timeProvider.GetUtcNow();
|
||||
var entities = request.Violations.Select(v => new ViolationEventEntity
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
Id = guidProvider.NewGuid(),
|
||||
TenantId = tenantId,
|
||||
PolicyId = v.PolicyId,
|
||||
RuleId = v.RuleId,
|
||||
@@ -420,7 +426,7 @@ internal static class ViolationEndpoints
|
||||
Details = v.Details ?? "{}",
|
||||
Remediation = v.Remediation,
|
||||
CorrelationId = v.CorrelationId,
|
||||
OccurredAt = v.OccurredAt ?? DateTimeOffset.UtcNow
|
||||
OccurredAt = v.OccurredAt ?? now
|
||||
}).ToList();
|
||||
|
||||
try
|
||||
|
||||
@@ -185,7 +185,7 @@ public sealed record VexTrustGateResult
|
||||
/// <summary>
|
||||
/// Timestamp when decision was made.
|
||||
/// </summary>
|
||||
public DateTimeOffset EvaluatedAt { get; init; } = DateTimeOffset.UtcNow;
|
||||
public required DateTimeOffset EvaluatedAt { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Additional details for audit.
|
||||
@@ -400,7 +400,7 @@ public sealed class VexTrustGate : IVexTrustGate
|
||||
};
|
||||
}
|
||||
|
||||
private static VexTrustGateResult CreateAllowResult(
|
||||
private VexTrustGateResult CreateAllowResult(
|
||||
string gateId,
|
||||
string reason,
|
||||
VexTrustStatus? trustStatus)
|
||||
@@ -415,7 +415,7 @@ public sealed class VexTrustGate : IVexTrustGate
|
||||
? ComputeTier(trustStatus.TrustScore)
|
||||
: null,
|
||||
IssuerId = trustStatus?.IssuerId,
|
||||
EvaluatedAt = DateTimeOffset.UtcNow
|
||||
EvaluatedAt = _timeProvider.GetUtcNow()
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -6,12 +6,18 @@ namespace StellaOps.Policy.Engine.Services;
|
||||
internal sealed class InMemoryPolicyPackRepository : IPolicyPackRepository
|
||||
{
|
||||
private readonly ConcurrentDictionary<string, PolicyPackRecord> packs = new(StringComparer.OrdinalIgnoreCase);
|
||||
private readonly TimeProvider _timeProvider;
|
||||
|
||||
public InMemoryPolicyPackRepository(TimeProvider timeProvider)
|
||||
{
|
||||
_timeProvider = timeProvider ?? throw new ArgumentNullException(nameof(timeProvider));
|
||||
}
|
||||
|
||||
public Task<PolicyPackRecord> CreateAsync(string packId, string? displayName, CancellationToken cancellationToken)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(packId);
|
||||
|
||||
var created = packs.GetOrAdd(packId, id => new PolicyPackRecord(id, displayName, DateTimeOffset.UtcNow));
|
||||
var created = packs.GetOrAdd(packId, id => new PolicyPackRecord(id, displayName, _timeProvider.GetUtcNow()));
|
||||
return Task.FromResult(created);
|
||||
}
|
||||
|
||||
@@ -25,15 +31,16 @@ internal sealed class InMemoryPolicyPackRepository : IPolicyPackRepository
|
||||
|
||||
public Task<PolicyRevisionRecord> UpsertRevisionAsync(string packId, int version, bool requiresTwoPersonApproval, PolicyRevisionStatus initialStatus, CancellationToken cancellationToken)
|
||||
{
|
||||
var pack = packs.GetOrAdd(packId, id => new PolicyPackRecord(id, null, DateTimeOffset.UtcNow));
|
||||
var now = _timeProvider.GetUtcNow();
|
||||
var pack = packs.GetOrAdd(packId, id => new PolicyPackRecord(id, null, now));
|
||||
int revisionVersion = version > 0 ? version : pack.GetNextVersion();
|
||||
var revision = pack.GetOrAddRevision(
|
||||
revisionVersion,
|
||||
v => new PolicyRevisionRecord(v, requiresTwoPersonApproval, initialStatus, DateTimeOffset.UtcNow));
|
||||
v => new PolicyRevisionRecord(v, requiresTwoPersonApproval, initialStatus, now));
|
||||
|
||||
if (revision.Status != initialStatus)
|
||||
{
|
||||
revision.SetStatus(initialStatus, DateTimeOffset.UtcNow);
|
||||
revision.SetStatus(initialStatus, now);
|
||||
}
|
||||
|
||||
return Task.FromResult(revision);
|
||||
@@ -95,9 +102,10 @@ internal sealed class InMemoryPolicyPackRepository : IPolicyPackRepository
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(bundle);
|
||||
|
||||
var pack = packs.GetOrAdd(packId, id => new PolicyPackRecord(id, null, DateTimeOffset.UtcNow));
|
||||
var now = _timeProvider.GetUtcNow();
|
||||
var pack = packs.GetOrAdd(packId, id => new PolicyPackRecord(id, null, now));
|
||||
var revision = pack.GetOrAddRevision(version > 0 ? version : pack.GetNextVersion(),
|
||||
v => new PolicyRevisionRecord(v, requiresTwoPerson: false, status: PolicyRevisionStatus.Draft, DateTimeOffset.UtcNow));
|
||||
v => new PolicyRevisionRecord(v, requiresTwoPerson: false, status: PolicyRevisionStatus.Draft, now));
|
||||
|
||||
revision.SetBundle(bundle);
|
||||
return Task.FromResult(bundle);
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
using Microsoft.Extensions.Logging;
|
||||
using StellaOps.Determinism.Abstractions;
|
||||
using StellaOps.SbomService.Repositories;
|
||||
|
||||
namespace StellaOps.Policy.Engine.Services;
|
||||
@@ -94,13 +95,19 @@ public sealed class VerdictLinkService : IVerdictLinkService
|
||||
{
|
||||
private readonly ISbomVerdictLinkRepository _repository;
|
||||
private readonly ILogger<VerdictLinkService> _logger;
|
||||
private readonly TimeProvider _timeProvider;
|
||||
private readonly IGuidProvider _guidProvider;
|
||||
|
||||
public VerdictLinkService(
|
||||
ISbomVerdictLinkRepository repository,
|
||||
ILogger<VerdictLinkService> logger)
|
||||
ILogger<VerdictLinkService> logger,
|
||||
TimeProvider timeProvider,
|
||||
IGuidProvider guidProvider)
|
||||
{
|
||||
_repository = repository ?? throw new ArgumentNullException(nameof(repository));
|
||||
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
||||
_timeProvider = timeProvider ?? throw new ArgumentNullException(nameof(timeProvider));
|
||||
_guidProvider = guidProvider ?? throw new ArgumentNullException(nameof(guidProvider));
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
@@ -114,14 +121,14 @@ public sealed class VerdictLinkService : IVerdictLinkService
|
||||
return;
|
||||
}
|
||||
|
||||
var now = DateTimeOffset.UtcNow;
|
||||
var now = _timeProvider.GetUtcNow();
|
||||
var links = new List<SbomVerdictLink>();
|
||||
|
||||
foreach (var verdict in request.Verdicts)
|
||||
{
|
||||
var link = new SbomVerdictLink
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
Id = _guidProvider.NewGuid(),
|
||||
SbomVersionId = request.SbomVersionId,
|
||||
Cve = verdict.Cve,
|
||||
ConsensusProjectionId = verdict.ConsensusProjectionId,
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Immutable;
|
||||
using System.Text.RegularExpressions;
|
||||
using StellaOps.Determinism.Abstractions;
|
||||
using StellaOps.Policy.Persistence.Postgres.Models;
|
||||
using StellaOps.Policy.Persistence.Postgres.Repositories;
|
||||
|
||||
@@ -10,13 +11,15 @@ namespace StellaOps.Policy.Engine.Storage.InMemory;
|
||||
/// In-memory implementation of IExceptionRepository for offline/test runs.
|
||||
/// Provides minimal semantics needed for lifecycle processing.
|
||||
/// </summary>
|
||||
public sealed class InMemoryExceptionRepository : IExceptionRepository
|
||||
public sealed class InMemoryExceptionRepository(TimeProvider timeProvider, IGuidProvider guidProvider) : IExceptionRepository
|
||||
{
|
||||
private readonly TimeProvider _timeProvider = timeProvider;
|
||||
private readonly IGuidProvider _guidProvider = guidProvider;
|
||||
private readonly ConcurrentDictionary<(string Tenant, Guid Id), ExceptionEntity> _exceptions = new();
|
||||
|
||||
public Task<ExceptionEntity> CreateAsync(ExceptionEntity exception, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var id = exception.Id == Guid.Empty ? Guid.NewGuid() : exception.Id;
|
||||
var id = exception.Id == Guid.Empty ? _guidProvider.NewGuid() : exception.Id;
|
||||
var stored = Copy(exception, id);
|
||||
_exceptions[(Normalize(exception.TenantId), id)] = stored;
|
||||
return Task.FromResult(stored);
|
||||
@@ -123,7 +126,7 @@ public sealed class InMemoryExceptionRepository : IExceptionRepository
|
||||
_exceptions[key] = Copy(
|
||||
existing,
|
||||
statusOverride: ExceptionStatus.Revoked,
|
||||
revokedAtOverride: DateTimeOffset.UtcNow,
|
||||
revokedAtOverride: _timeProvider.GetUtcNow(),
|
||||
revokedByOverride: revokedBy);
|
||||
return Task.FromResult(true);
|
||||
}
|
||||
@@ -133,7 +136,7 @@ public sealed class InMemoryExceptionRepository : IExceptionRepository
|
||||
|
||||
public Task<int> ExpireAsync(string tenantId, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var now = DateTimeOffset.UtcNow;
|
||||
var now = _timeProvider.GetUtcNow();
|
||||
var normalizedTenant = Normalize(tenantId);
|
||||
var expired = 0;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user