feat: Add initial implementation of Vulnerability Resolver Jobs
Some checks failed
Docs CI / lint-and-preview (push) Has been cancelled
Some checks failed
Docs CI / lint-and-preview (push) Has been cancelled
- Created project for StellaOps.Scanner.Analyzers.Native.Tests with necessary dependencies. - Documented roles and guidelines in AGENTS.md for Scheduler module. - Implemented IResolverJobService interface and InMemoryResolverJobService for handling resolver jobs. - Added ResolverBacklogNotifier and ResolverBacklogService for monitoring job metrics. - Developed API endpoints for managing resolver jobs and retrieving metrics. - Defined models for resolver job requests and responses. - Integrated dependency injection for resolver job services. - Implemented ImpactIndexSnapshot for persisting impact index data. - Introduced SignalsScoringOptions for configurable scoring weights in reachability scoring. - Added unit tests for ReachabilityScoringService and RuntimeFactsIngestionService. - Created dotnet-filter.sh script to handle command-line arguments for dotnet. - Established nuget-prime project for managing package downloads.
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
using System.Diagnostics;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
@@ -5,6 +6,7 @@ using StellaOps.Findings.Ledger.Domain;
|
||||
using StellaOps.Findings.Ledger.Infrastructure;
|
||||
using StellaOps.Findings.Ledger.Infrastructure.Policy;
|
||||
using StellaOps.Findings.Ledger.Options;
|
||||
using StellaOps.Findings.Ledger.Observability;
|
||||
using StellaOps.Findings.Ledger.Services;
|
||||
|
||||
namespace StellaOps.Findings.Ledger.Infrastructure.Projection;
|
||||
@@ -74,9 +76,21 @@ public sealed class LedgerProjectionWorker : BackgroundService
|
||||
|
||||
foreach (var record in batch)
|
||||
{
|
||||
using var scope = _logger.BeginScope(new Dictionary<string, object?>
|
||||
{
|
||||
["tenant"] = record.TenantId,
|
||||
["chainId"] = record.ChainId,
|
||||
["eventId"] = record.EventId,
|
||||
["eventType"] = record.EventType,
|
||||
["policyVersion"] = record.PolicyVersion
|
||||
});
|
||||
using var activity = LedgerTelemetry.StartProjectionApply(record);
|
||||
var applyStopwatch = Stopwatch.StartNew();
|
||||
string? evaluationStatus = null;
|
||||
|
||||
try
|
||||
{
|
||||
await ApplyAsync(record, stoppingToken).ConfigureAwait(false);
|
||||
evaluationStatus = await ApplyAsync(record, stoppingToken).ConfigureAwait(false);
|
||||
|
||||
checkpoint = checkpoint with
|
||||
{
|
||||
@@ -86,13 +100,36 @@ public sealed class LedgerProjectionWorker : BackgroundService
|
||||
};
|
||||
|
||||
await _repository.SaveCheckpointAsync(checkpoint, stoppingToken).ConfigureAwait(false);
|
||||
|
||||
_logger.LogInformation(
|
||||
"Projected ledger event {EventId} for tenant {Tenant} chain {ChainId} seq {Sequence} finding {FindingId}.",
|
||||
record.EventId,
|
||||
record.TenantId,
|
||||
record.ChainId,
|
||||
record.SequenceNumber,
|
||||
record.FindingId);
|
||||
activity?.SetStatus(System.Diagnostics.ActivityStatusCode.Ok);
|
||||
|
||||
applyStopwatch.Stop();
|
||||
var now = _timeProvider.GetUtcNow();
|
||||
var lagSeconds = Math.Max(0, (now - record.RecordedAt).TotalSeconds);
|
||||
LedgerMetrics.RecordProjectionApply(
|
||||
applyStopwatch.Elapsed,
|
||||
lagSeconds,
|
||||
record.TenantId,
|
||||
record.EventType,
|
||||
record.PolicyVersion,
|
||||
evaluationStatus ?? string.Empty);
|
||||
LedgerTimeline.EmitProjectionUpdated(_logger, record, evaluationStatus, evidenceBundleRef: null);
|
||||
}
|
||||
catch (OperationCanceledException) when (stoppingToken.IsCancellationRequested)
|
||||
{
|
||||
LedgerTelemetry.MarkError(activity, "projection_cancelled");
|
||||
return;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LedgerTelemetry.MarkError(activity, "projection_failed");
|
||||
_logger.LogError(ex, "Failed to project ledger event {EventId} for tenant {TenantId}.", record.EventId, record.TenantId);
|
||||
await DelayAsync(stoppingToken).ConfigureAwait(false);
|
||||
break;
|
||||
@@ -101,7 +138,7 @@ public sealed class LedgerProjectionWorker : BackgroundService
|
||||
}
|
||||
}
|
||||
|
||||
private async Task ApplyAsync(LedgerEventRecord record, CancellationToken cancellationToken)
|
||||
private async Task<string?> ApplyAsync(LedgerEventRecord record, CancellationToken cancellationToken)
|
||||
{
|
||||
var current = await _repository.GetAsync(record.TenantId, record.FindingId, record.PolicyVersion, cancellationToken).ConfigureAwait(false);
|
||||
var evaluation = await _policyEvaluationService.EvaluateAsync(record, current, cancellationToken).ConfigureAwait(false);
|
||||
@@ -114,6 +151,8 @@ public sealed class LedgerProjectionWorker : BackgroundService
|
||||
{
|
||||
await _repository.InsertActionAsync(result.Action, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
return evaluation.Status;
|
||||
}
|
||||
|
||||
private async Task DelayAsync(CancellationToken cancellationToken)
|
||||
|
||||
Reference in New Issue
Block a user