feat: Implement PostgreSQL repositories for various entities
- Added BootstrapInviteRepository for managing bootstrap invites. - Added ClientRepository for handling OAuth/OpenID clients. - Introduced LoginAttemptRepository for logging login attempts. - Created OidcTokenRepository for managing OpenIddict tokens and refresh tokens. - Implemented RevocationExportStateRepository for persisting revocation export state. - Added RevocationRepository for managing revocations. - Introduced ServiceAccountRepository for handling service accounts.
This commit is contained in:
@@ -71,8 +71,10 @@ internal static class AirGapEndpoints
|
||||
var budget = request.StalenessBudget ?? StalenessBudget.Default;
|
||||
|
||||
var now = timeProvider.GetUtcNow();
|
||||
var state = await service.SealAsync(tenantId, request.PolicyHash!, anchor, budget, now, cancellationToken);
|
||||
var status = new AirGapStatus(state, stalenessCalculator.Evaluate(anchor, budget, now), now);
|
||||
var state = await service.SealAsync(tenantId, request.PolicyHash!, anchor, budget, now, request.ContentBudgets, cancellationToken);
|
||||
var staleness = stalenessCalculator.Evaluate(anchor, budget, now);
|
||||
var contentStaleness = stalenessCalculator.EvaluateContent(anchor, state.ContentBudgets, now);
|
||||
var status = new AirGapStatus(state, staleness, contentStaleness, now);
|
||||
telemetry.RecordSeal(tenantId, status);
|
||||
return Results.Ok(AirGapStatusResponse.FromStatus(status));
|
||||
}
|
||||
@@ -86,8 +88,10 @@ internal static class AirGapEndpoints
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var tenantId = ResolveTenant(httpContext);
|
||||
var state = await service.UnsealAsync(tenantId, timeProvider.GetUtcNow(), cancellationToken);
|
||||
var status = new AirGapStatus(state, StalenessEvaluation.Unknown, timeProvider.GetUtcNow());
|
||||
var now = timeProvider.GetUtcNow();
|
||||
var state = await service.UnsealAsync(tenantId, now, cancellationToken);
|
||||
var emptyContentStaleness = new Dictionary<string, StalenessEvaluation>(StringComparer.OrdinalIgnoreCase);
|
||||
var status = new AirGapStatus(state, StalenessEvaluation.Unknown, emptyContentStaleness, now);
|
||||
telemetry.RecordUnseal(tenantId, status);
|
||||
return Results.Ok(AirGapStatusResponse.FromStatus(status));
|
||||
}
|
||||
|
||||
@@ -11,7 +11,9 @@ public sealed record AirGapStatusResponse(
|
||||
TimeAnchor TimeAnchor,
|
||||
StalenessEvaluation Staleness,
|
||||
long DriftSeconds,
|
||||
long DriftBaselineSeconds,
|
||||
long SecondsRemaining,
|
||||
IReadOnlyDictionary<string, ContentStalenessEntry> ContentStaleness,
|
||||
DateTimeOffset LastTransitionAt,
|
||||
DateTimeOffset EvaluatedAt)
|
||||
{
|
||||
@@ -23,7 +25,30 @@ public sealed record AirGapStatusResponse(
|
||||
status.State.TimeAnchor,
|
||||
status.Staleness,
|
||||
status.Staleness.AgeSeconds,
|
||||
status.State.DriftBaselineSeconds,
|
||||
status.Staleness.SecondsRemaining,
|
||||
BuildContentStaleness(status.ContentStaleness),
|
||||
status.State.LastTransitionAt,
|
||||
status.EvaluatedAt);
|
||||
|
||||
private static IReadOnlyDictionary<string, ContentStalenessEntry> BuildContentStaleness(
|
||||
IReadOnlyDictionary<string, StalenessEvaluation> evaluations)
|
||||
{
|
||||
var result = new Dictionary<string, ContentStalenessEntry>(StringComparer.OrdinalIgnoreCase);
|
||||
foreach (var kvp in evaluations)
|
||||
{
|
||||
result[kvp.Key] = ContentStalenessEntry.FromEvaluation(kvp.Value);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
public sealed record ContentStalenessEntry(
|
||||
long AgeSeconds,
|
||||
long SecondsRemaining,
|
||||
bool IsWarning,
|
||||
bool IsBreach)
|
||||
{
|
||||
public static ContentStalenessEntry FromEvaluation(StalenessEvaluation eval) =>
|
||||
new(eval.AgeSeconds, eval.SecondsRemaining, eval.IsWarning, eval.IsBreach);
|
||||
}
|
||||
|
||||
@@ -11,4 +11,10 @@ public sealed class SealRequest
|
||||
public TimeAnchor? TimeAnchor { get; set; }
|
||||
|
||||
public StalenessBudget? StalenessBudget { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Optional per-content staleness budgets (advisories, vex, policy).
|
||||
/// Falls back to StalenessBudget when not provided.
|
||||
/// </summary>
|
||||
public Dictionary<string, StalenessBudget>? ContentBudgets { get; set; }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user