up
Some checks failed
Concelier Attestation Tests / attestation-tests (push) Has been cancelled
Policy Simulation / policy-simulate (push) Has been cancelled
AOC Guard CI / aoc-guard (push) Has been cancelled
AOC Guard CI / aoc-verify (push) Has been cancelled
Signals CI & Image / signals-ci (push) Has been cancelled
Signals Reachability Scoring & Events / reachability-smoke (push) Has been cancelled
Signals Reachability Scoring & Events / sign-and-upload (push) Has been cancelled
Docs CI / lint-and-preview (push) Has been cancelled
Policy Lint & Smoke / policy-lint (push) Has been cancelled
Scanner Analyzers / Discover Analyzers (push) Has been cancelled
Scanner Analyzers / Build Analyzers (push) Has been cancelled
Scanner Analyzers / Test Language Analyzers (push) Has been cancelled
Scanner Analyzers / Validate Test Fixtures (push) Has been cancelled
Scanner Analyzers / Verify Deterministic Output (push) Has been cancelled
Some checks failed
Concelier Attestation Tests / attestation-tests (push) Has been cancelled
Policy Simulation / policy-simulate (push) Has been cancelled
AOC Guard CI / aoc-guard (push) Has been cancelled
AOC Guard CI / aoc-verify (push) Has been cancelled
Signals CI & Image / signals-ci (push) Has been cancelled
Signals Reachability Scoring & Events / reachability-smoke (push) Has been cancelled
Signals Reachability Scoring & Events / sign-and-upload (push) Has been cancelled
Docs CI / lint-and-preview (push) Has been cancelled
Policy Lint & Smoke / policy-lint (push) Has been cancelled
Scanner Analyzers / Discover Analyzers (push) Has been cancelled
Scanner Analyzers / Build Analyzers (push) Has been cancelled
Scanner Analyzers / Test Language Analyzers (push) Has been cancelled
Scanner Analyzers / Validate Test Fixtures (push) Has been cancelled
Scanner Analyzers / Verify Deterministic Output (push) Has been cancelled
This commit is contained in:
@@ -13,6 +13,7 @@ using StellaOps.Attestor.Core.Storage;
|
||||
using StellaOps.Attestor.Core.Submission;
|
||||
using StellaOps.Attestor.Core.Transparency;
|
||||
using StellaOps.Attestor.Core.Verification;
|
||||
using StellaOps.Attestor.Core.Bulk;
|
||||
using StellaOps.Attestor.Infrastructure.Rekor;
|
||||
using StellaOps.Attestor.Infrastructure.Storage;
|
||||
using StellaOps.Attestor.Infrastructure.Submission;
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
<ProjectReference Include="..\..\..\__Libraries\StellaOps.Cryptography.Plugin.BouncyCastle\StellaOps.Cryptography.Plugin.BouncyCastle.csproj" />
|
||||
<ProjectReference Include="..\..\..\__Libraries\StellaOps.Cryptography.Kms\StellaOps.Cryptography.Kms.csproj" />
|
||||
<ProjectReference Include="..\..\..\__Libraries\StellaOps.Cryptography.Plugin.SmSoft\StellaOps.Cryptography.Plugin.SmSoft.csproj" />
|
||||
<ProjectReference Include="..\..\..\__Libraries\StellaOps.Messaging\StellaOps.Messaging.csproj" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="10.0.0" />
|
||||
|
||||
@@ -0,0 +1,107 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
using StellaOps.Attestor.Core.Options;
|
||||
using StellaOps.Attestor.Core.Verification;
|
||||
using StellaOps.Messaging;
|
||||
using StellaOps.Messaging.Abstractions;
|
||||
|
||||
namespace StellaOps.Attestor.Infrastructure.Verification;
|
||||
|
||||
/// <summary>
|
||||
/// Attestor verification cache backed by <see cref="IDistributedCache{TValue}"/>.
|
||||
/// Supports any transport (InMemory, Valkey, PostgreSQL) via factory injection.
|
||||
/// </summary>
|
||||
internal sealed class MessagingAttestorVerificationCache : IAttestorVerificationCache
|
||||
{
|
||||
private readonly IDistributedCache<AttestorVerificationResult> _cache;
|
||||
private readonly ILogger<MessagingAttestorVerificationCache> _logger;
|
||||
private readonly TimeSpan _ttl;
|
||||
|
||||
public MessagingAttestorVerificationCache(
|
||||
IDistributedCacheFactory cacheFactory,
|
||||
IOptions<AttestorOptions> options,
|
||||
ILogger<MessagingAttestorVerificationCache> logger)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(cacheFactory);
|
||||
ArgumentNullException.ThrowIfNull(options);
|
||||
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
||||
|
||||
var ttlSeconds = Math.Max(1, options.Value.Cache.Verification.TtlSeconds);
|
||||
_ttl = TimeSpan.FromSeconds(ttlSeconds);
|
||||
|
||||
_cache = cacheFactory.Create<AttestorVerificationResult>(new CacheOptions
|
||||
{
|
||||
KeyPrefix = "attestor:verify:",
|
||||
DefaultTtl = _ttl,
|
||||
});
|
||||
|
||||
_logger.LogInformation(
|
||||
"Initialized MessagingAttestorVerificationCache with provider {Provider}, TTL {Ttl}s",
|
||||
_cache.ProviderName,
|
||||
_ttl.TotalSeconds.ToString(CultureInfo.InvariantCulture));
|
||||
}
|
||||
|
||||
public async Task<AttestorVerificationResult?> GetAsync(
|
||||
string subject,
|
||||
string envelopeId,
|
||||
string policyVersion,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
var cacheKey = BuildCacheKey(subject, envelopeId, policyVersion);
|
||||
var result = await _cache.GetAsync(cacheKey, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
if (result.HasValue)
|
||||
{
|
||||
return result.Value;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public async Task SetAsync(
|
||||
string subject,
|
||||
string envelopeId,
|
||||
string policyVersion,
|
||||
AttestorVerificationResult result,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(result);
|
||||
|
||||
var cacheKey = BuildCacheKey(subject, envelopeId, policyVersion);
|
||||
var entryOptions = new CacheEntryOptions { TimeToLive = _ttl };
|
||||
|
||||
await _cache.SetAsync(cacheKey, result, entryOptions, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
var subjectKey = Normalize(subject);
|
||||
_logger.LogDebug(
|
||||
"Cached verification result for subject {Subject} envelope {Envelope} policy {Policy} with TTL {TtlSeconds}s.",
|
||||
subjectKey,
|
||||
Normalize(envelopeId),
|
||||
Normalize(policyVersion),
|
||||
_ttl.TotalSeconds.ToString(CultureInfo.InvariantCulture));
|
||||
}
|
||||
|
||||
public async Task InvalidateSubjectAsync(string subject, CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(subject))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var subjectKey = Normalize(subject);
|
||||
// Pattern: attestor:verify:<subject>|*
|
||||
var pattern = $"{subjectKey}|*";
|
||||
var count = await _cache.InvalidateByPatternAsync(pattern, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
_logger.LogDebug("Invalidated {Count} verification cache entries for subject {Subject}.", count, subjectKey);
|
||||
}
|
||||
|
||||
private static string BuildCacheKey(string subject, string envelopeId, string policyVersion) =>
|
||||
string.Concat(Normalize(subject), "|", Normalize(envelopeId), "|", Normalize(policyVersion));
|
||||
|
||||
private static string Normalize(string? value) => (value ?? string.Empty).Trim();
|
||||
}
|
||||
Reference in New Issue
Block a user