sprints work
This commit is contained in:
@@ -103,6 +103,7 @@ public sealed class FindingScoringService : IFindingScoringService
|
||||
private readonly IMemoryCache _cache;
|
||||
private readonly FindingScoringOptions _options;
|
||||
private readonly ILogger<FindingScoringService> _logger;
|
||||
private readonly TimeProvider _timeProvider;
|
||||
|
||||
private static readonly TimeSpan DefaultCacheDuration = TimeSpan.FromMinutes(60);
|
||||
|
||||
@@ -116,7 +117,8 @@ public sealed class FindingScoringService : IFindingScoringService
|
||||
IScoreHistoryStore historyStore,
|
||||
IMemoryCache cache,
|
||||
IOptions<FindingScoringOptions> options,
|
||||
ILogger<FindingScoringService> logger)
|
||||
ILogger<FindingScoringService> logger,
|
||||
TimeProvider? timeProvider = null)
|
||||
{
|
||||
_normalizer = normalizer;
|
||||
_calculator = calculator;
|
||||
@@ -126,6 +128,7 @@ public sealed class FindingScoringService : IFindingScoringService
|
||||
_cache = cache;
|
||||
_options = options.Value;
|
||||
_logger = logger;
|
||||
_timeProvider = timeProvider ?? TimeProvider.System;
|
||||
_environment = Environment.GetEnvironmentVariable("STELLAOPS_ENVIRONMENT") ?? "production";
|
||||
}
|
||||
|
||||
@@ -160,7 +163,7 @@ public sealed class FindingScoringService : IFindingScoringService
|
||||
var input = _normalizer.Aggregate(evidence);
|
||||
|
||||
var result = _calculator.Calculate(input, policy);
|
||||
var now = DateTimeOffset.UtcNow;
|
||||
var now = _timeProvider.GetUtcNow();
|
||||
var cacheDuration = TimeSpan.FromMinutes(_options.CacheTtlMinutes);
|
||||
|
||||
var response = MapToResponse(result, request.IncludeBreakdown, now, cacheDuration);
|
||||
@@ -288,7 +291,7 @@ public sealed class FindingScoringService : IFindingScoringService
|
||||
Summary = summary,
|
||||
Errors = errors.Count > 0 ? errors : null,
|
||||
PolicyDigest = policy.ComputeDigest(),
|
||||
CalculatedAt = DateTimeOffset.UtcNow
|
||||
CalculatedAt = _timeProvider.GetUtcNow()
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -46,6 +46,12 @@ public sealed class InMemoryScoreHistoryStore : IScoreHistoryStore
|
||||
private readonly ConcurrentDictionary<string, List<ScoreRecord>> _history = new();
|
||||
private readonly TimeSpan _retentionPeriod = TimeSpan.FromDays(90);
|
||||
private readonly int _maxEntriesPerFinding = 1000;
|
||||
private readonly TimeProvider _timeProvider;
|
||||
|
||||
public InMemoryScoreHistoryStore(TimeProvider? timeProvider = null)
|
||||
{
|
||||
_timeProvider = timeProvider ?? TimeProvider.System;
|
||||
}
|
||||
|
||||
public void RecordScore(ScoreRecord record)
|
||||
{
|
||||
@@ -68,7 +74,7 @@ public sealed class InMemoryScoreHistoryStore : IScoreHistoryStore
|
||||
entries.Add(record);
|
||||
|
||||
// Prune old entries
|
||||
var cutoff = DateTimeOffset.UtcNow - _retentionPeriod;
|
||||
var cutoff = _timeProvider.GetUtcNow() - _retentionPeriod;
|
||||
entries.RemoveAll(e => e.CalculatedAt < cutoff);
|
||||
|
||||
// Limit total entries
|
||||
|
||||
@@ -12,8 +12,14 @@ public sealed class VexConsensusService
|
||||
private readonly ConcurrentDictionary<string, VexProjectionRecord> _projections = new();
|
||||
private readonly ConcurrentDictionary<string, VexIssuerRecord> _issuers = new();
|
||||
private readonly ConcurrentDictionary<string, List<VexStatementRecord>> _statements = new();
|
||||
private readonly TimeProvider _timeProvider;
|
||||
private long _projectionCounter = 0;
|
||||
|
||||
public VexConsensusService(TimeProvider? timeProvider = null)
|
||||
{
|
||||
_timeProvider = timeProvider ?? TimeProvider.System;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Computes consensus for a vulnerability-product pair.
|
||||
/// </summary>
|
||||
@@ -84,7 +90,7 @@ public sealed class VexConsensusService
|
||||
Contributions: [],
|
||||
Conflicts: null,
|
||||
ProjectionId: null,
|
||||
ComputedAt: DateTimeOffset.UtcNow);
|
||||
ComputedAt: _timeProvider.GetUtcNow());
|
||||
|
||||
return Task.FromResult(defaultResponse);
|
||||
}
|
||||
@@ -121,7 +127,7 @@ public sealed class VexConsensusService
|
||||
Contributions: contributions,
|
||||
Conflicts: null,
|
||||
ProjectionId: projectionId,
|
||||
ComputedAt: DateTimeOffset.UtcNow);
|
||||
ComputedAt: _timeProvider.GetUtcNow());
|
||||
|
||||
return Task.FromResult(response);
|
||||
}
|
||||
@@ -163,7 +169,7 @@ public sealed class VexConsensusService
|
||||
TotalCount: request.Targets.Count,
|
||||
SuccessCount: results.Count,
|
||||
FailureCount: failures,
|
||||
CompletedAt: DateTimeOffset.UtcNow);
|
||||
CompletedAt: _timeProvider.GetUtcNow());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -299,7 +305,7 @@ public sealed class VexConsensusService
|
||||
: 0;
|
||||
|
||||
var withConflicts = projections.Count(p => p.ConflictCount > 0);
|
||||
var last24h = DateTimeOffset.UtcNow.AddDays(-1);
|
||||
var last24h = _timeProvider.GetUtcNow().AddDays(-1);
|
||||
var changesLast24h = projections.Count(p => p.StatusChanged && p.ComputedAt >= last24h);
|
||||
|
||||
return Task.FromResult(new VexConsensusStatisticsResponse(
|
||||
@@ -309,7 +315,7 @@ public sealed class VexConsensusService
|
||||
AverageConfidence: avgConfidence,
|
||||
ProjectionsWithConflicts: withConflicts,
|
||||
StatusChangesLast24h: changesLast24h,
|
||||
ComputedAt: DateTimeOffset.UtcNow));
|
||||
ComputedAt: _timeProvider.GetUtcNow()));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -367,6 +373,7 @@ public sealed class VexConsensusService
|
||||
RegisterVexIssuerRequest request,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
var now = _timeProvider.GetUtcNow();
|
||||
var record = new VexIssuerRecord(
|
||||
IssuerId: request.IssuerId,
|
||||
Name: request.Name,
|
||||
@@ -378,14 +385,14 @@ public sealed class VexConsensusService
|
||||
KeyType: k.KeyType,
|
||||
Algorithm: k.Algorithm,
|
||||
Status: "active",
|
||||
RegisteredAt: DateTimeOffset.UtcNow,
|
||||
RegisteredAt: now,
|
||||
ExpiresAt: k.ExpiresAt)).ToList() ?? [],
|
||||
Metadata: request.Metadata != null ? new VexIssuerMetadata(
|
||||
Description: request.Metadata.Description,
|
||||
Uri: request.Metadata.Uri,
|
||||
Email: request.Metadata.Email,
|
||||
Tags: request.Metadata.Tags?.ToList()) : null,
|
||||
RegisteredAt: DateTimeOffset.UtcNow,
|
||||
RegisteredAt: now,
|
||||
LastUpdatedAt: null,
|
||||
RevokedAt: null,
|
||||
RevocationReason: null);
|
||||
@@ -425,7 +432,7 @@ public sealed class VexConsensusService
|
||||
string status, string? justification, double confidence, string outcome, int statementCount)
|
||||
{
|
||||
var id = $"proj-{Interlocked.Increment(ref _projectionCounter):D8}";
|
||||
var now = DateTimeOffset.UtcNow;
|
||||
var now = _timeProvider.GetUtcNow();
|
||||
|
||||
var record = new VexProjectionRecord(
|
||||
ProjectionId: id,
|
||||
|
||||
@@ -4,6 +4,7 @@ using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using StellaOps.Determinism;
|
||||
using StellaOps.Findings.Ledger.WebService.Contracts;
|
||||
|
||||
namespace StellaOps.Findings.Ledger.WebService.Services;
|
||||
@@ -74,18 +75,26 @@ public interface IWebhookDeliveryService
|
||||
public sealed class InMemoryWebhookStore : IWebhookStore
|
||||
{
|
||||
private readonly ConcurrentDictionary<Guid, WebhookRegistration> _webhooks = new();
|
||||
private readonly TimeProvider _timeProvider;
|
||||
private readonly IGuidProvider _guidProvider;
|
||||
|
||||
public InMemoryWebhookStore(TimeProvider? timeProvider = null, IGuidProvider? guidProvider = null)
|
||||
{
|
||||
_timeProvider = timeProvider ?? TimeProvider.System;
|
||||
_guidProvider = guidProvider ?? SystemGuidProvider.Instance;
|
||||
}
|
||||
|
||||
public WebhookRegistration Register(RegisterWebhookRequest request)
|
||||
{
|
||||
var registration = new WebhookRegistration
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
Id = _guidProvider.NewGuid(),
|
||||
Url = request.Url,
|
||||
Secret = request.Secret,
|
||||
FindingPatterns = request.FindingPatterns,
|
||||
MinScoreChange = request.MinScoreChange,
|
||||
TriggerOnBucketChange = request.TriggerOnBucketChange,
|
||||
CreatedAt = DateTimeOffset.UtcNow,
|
||||
CreatedAt = _timeProvider.GetUtcNow(),
|
||||
IsActive = true
|
||||
};
|
||||
|
||||
@@ -171,6 +180,7 @@ public sealed class WebhookDeliveryService : IWebhookDeliveryService
|
||||
private readonly IWebhookStore _store;
|
||||
private readonly IHttpClientFactory _httpClientFactory;
|
||||
private readonly ILogger<WebhookDeliveryService> _logger;
|
||||
private readonly TimeProvider _timeProvider;
|
||||
|
||||
private static readonly JsonSerializerOptions JsonOptions = new(JsonSerializerDefaults.Web)
|
||||
{
|
||||
@@ -182,11 +192,13 @@ public sealed class WebhookDeliveryService : IWebhookDeliveryService
|
||||
public WebhookDeliveryService(
|
||||
IWebhookStore store,
|
||||
IHttpClientFactory httpClientFactory,
|
||||
ILogger<WebhookDeliveryService> logger)
|
||||
ILogger<WebhookDeliveryService> logger,
|
||||
TimeProvider? timeProvider = null)
|
||||
{
|
||||
_store = store;
|
||||
_httpClientFactory = httpClientFactory;
|
||||
_logger = logger;
|
||||
_timeProvider = timeProvider ?? TimeProvider.System;
|
||||
}
|
||||
|
||||
public async Task NotifyScoreChangeAsync(
|
||||
@@ -219,7 +231,7 @@ public sealed class WebhookDeliveryService : IWebhookDeliveryService
|
||||
ScoreChange = scoreChange,
|
||||
BucketChanged = bucketChanged,
|
||||
PolicyDigest = policyDigest,
|
||||
Timestamp = DateTimeOffset.UtcNow
|
||||
Timestamp = _timeProvider.GetUtcNow()
|
||||
};
|
||||
|
||||
var payloadJson = JsonSerializer.Serialize(payload, JsonOptions);
|
||||
@@ -258,7 +270,7 @@ public sealed class WebhookDeliveryService : IWebhookDeliveryService
|
||||
}
|
||||
|
||||
request.Headers.TryAddWithoutValidation("X-Webhook-Id", webhook.Id.ToString());
|
||||
request.Headers.TryAddWithoutValidation("X-Webhook-Timestamp", DateTimeOffset.UtcNow.ToUnixTimeSeconds().ToString());
|
||||
request.Headers.TryAddWithoutValidation("X-Webhook-Timestamp", _timeProvider.GetUtcNow().ToUnixTimeSeconds().ToString());
|
||||
|
||||
using var response = await client.SendAsync(request, ct).ConfigureAwait(false);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user