sprints and audit work
This commit is contained in:
@@ -0,0 +1,113 @@
|
||||
using Microsoft.Extensions.Logging;
|
||||
using StellaOps.Policy.Determinization.Models;
|
||||
using StellaOps.Policy.Engine.Gates;
|
||||
|
||||
namespace StellaOps.Policy.Engine.Subscriptions;
|
||||
|
||||
/// <summary>
|
||||
/// Implementation of signal update handling.
|
||||
/// </summary>
|
||||
public sealed class SignalUpdateHandler : ISignalUpdateSubscription
|
||||
{
|
||||
private readonly IObservationRepository _observations;
|
||||
private readonly IDeterminizationGate _gate;
|
||||
private readonly IEventPublisher _eventPublisher;
|
||||
private readonly ILogger<SignalUpdateHandler> _logger;
|
||||
|
||||
public SignalUpdateHandler(
|
||||
IObservationRepository observations,
|
||||
IDeterminizationGate gate,
|
||||
IEventPublisher eventPublisher,
|
||||
ILogger<SignalUpdateHandler> logger)
|
||||
{
|
||||
_observations = observations;
|
||||
_gate = gate;
|
||||
_eventPublisher = eventPublisher;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public async Task HandleAsync(SignalUpdatedEvent evt, CancellationToken ct = default)
|
||||
{
|
||||
_logger.LogInformation(
|
||||
"Processing signal update: {EventType} for CVE {CveId} on {Purl}",
|
||||
evt.EventType,
|
||||
evt.CveId,
|
||||
evt.Purl);
|
||||
|
||||
// Find observations affected by this signal
|
||||
var affected = await _observations.FindByCveAndPurlAsync(evt.CveId, evt.Purl, ct);
|
||||
|
||||
foreach (var obs in affected)
|
||||
{
|
||||
try
|
||||
{
|
||||
await ReEvaluateObservationAsync(obs, evt, ct);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex,
|
||||
"Failed to re-evaluate observation {ObservationId} after signal update",
|
||||
obs.Id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async Task ReEvaluateObservationAsync(
|
||||
CveObservation obs,
|
||||
SignalUpdatedEvent trigger,
|
||||
CancellationToken ct)
|
||||
{
|
||||
// This is a placeholder for re-evaluation logic
|
||||
// In a full implementation, this would:
|
||||
// 1. Build PolicyGateContext from observation
|
||||
// 2. Call gate.EvaluateDeterminizationAsync()
|
||||
// 3. Compare new verdict with old verdict
|
||||
// 4. Publish ObservationStateChangedEvent if state changed
|
||||
// 5. Update observation in repository
|
||||
|
||||
_logger.LogDebug(
|
||||
"Re-evaluating observation {ObservationId} after {EventType}",
|
||||
obs.Id,
|
||||
trigger.EventType);
|
||||
|
||||
await Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Repository for CVE observations.
|
||||
/// </summary>
|
||||
public interface IObservationRepository
|
||||
{
|
||||
/// <summary>
|
||||
/// Find observations by CVE ID and component PURL.
|
||||
/// </summary>
|
||||
Task<IReadOnlyList<CveObservation>> FindByCveAndPurlAsync(
|
||||
string cveId,
|
||||
string purl,
|
||||
CancellationToken ct = default);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Event publisher abstraction.
|
||||
/// </summary>
|
||||
public interface IEventPublisher
|
||||
{
|
||||
/// <summary>
|
||||
/// Publish an event.
|
||||
/// </summary>
|
||||
Task PublishAsync<TEvent>(TEvent evt, CancellationToken ct = default)
|
||||
where TEvent : class;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// CVE observation model.
|
||||
/// </summary>
|
||||
public sealed record CveObservation
|
||||
{
|
||||
public required Guid Id { get; init; }
|
||||
public required string CveId { get; init; }
|
||||
public required string SubjectPurl { get; init; }
|
||||
public required ObservationState State { get; init; }
|
||||
public required DateTimeOffset ObservedAt { get; init; }
|
||||
}
|
||||
Reference in New Issue
Block a user