feat: Add initial implementation of Vulnerability Resolver Jobs
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:
master
2025-11-18 07:52:15 +02:00
parent e69b57d467
commit 8355e2ff75
299 changed files with 13293 additions and 2444 deletions

View File

@@ -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)