180 lines
5.6 KiB
C#
180 lines
5.6 KiB
C#
namespace StellaOps.Scanner.Sources.Domain;
|
|
|
|
#pragma warning disable CA1062 // Validate arguments of public methods - TimeProvider validated at DI boundary
|
|
|
|
/// <summary>
|
|
/// Represents a single execution run of an SBOM source.
|
|
/// Tracks status, timing, item counts, and any errors.
|
|
/// </summary>
|
|
public sealed class SbomSourceRun
|
|
{
|
|
/// <summary>Unique run identifier.</summary>
|
|
public Guid RunId { get; init; }
|
|
|
|
/// <summary>Source that was run.</summary>
|
|
public Guid SourceId { get; init; }
|
|
|
|
/// <summary>Tenant owning the source.</summary>
|
|
public string TenantId { get; init; } = null!;
|
|
|
|
/// <summary>What triggered this run.</summary>
|
|
public SbomSourceRunTrigger Trigger { get; init; }
|
|
|
|
/// <summary>Additional trigger details (webhook payload digest, cron expression, etc.).</summary>
|
|
public string? TriggerDetails { get; init; }
|
|
|
|
/// <summary>Current status of the run.</summary>
|
|
public SbomSourceRunStatus Status { get; private set; } = SbomSourceRunStatus.Running;
|
|
|
|
/// <summary>When the run started.</summary>
|
|
public DateTimeOffset StartedAt { get; init; }
|
|
|
|
/// <summary>When the run completed (if finished).</summary>
|
|
public DateTimeOffset? CompletedAt { get; private set; }
|
|
|
|
/// <summary>
|
|
/// Duration in milliseconds. Pass a TimeProvider to get the live duration for in-progress runs.
|
|
/// </summary>
|
|
public long GetDurationMs(TimeProvider? timeProvider = null)
|
|
{
|
|
if (CompletedAt.HasValue)
|
|
return (long)(CompletedAt.Value - StartedAt).TotalMilliseconds;
|
|
|
|
var now = timeProvider?.GetUtcNow() ?? DateTimeOffset.UtcNow;
|
|
return (long)(now - StartedAt).TotalMilliseconds;
|
|
}
|
|
|
|
/// <summary>Number of items discovered to scan.</summary>
|
|
public int ItemsDiscovered { get; private set; }
|
|
|
|
/// <summary>Number of items that were scanned.</summary>
|
|
public int ItemsScanned { get; private set; }
|
|
|
|
/// <summary>Number of items that succeeded.</summary>
|
|
public int ItemsSucceeded { get; private set; }
|
|
|
|
/// <summary>Number of items that failed.</summary>
|
|
public int ItemsFailed { get; private set; }
|
|
|
|
/// <summary>Number of items that were skipped.</summary>
|
|
public int ItemsSkipped { get; private set; }
|
|
|
|
/// <summary>IDs of scan jobs created by this run.</summary>
|
|
public List<Guid> ScanJobIds { get; init; } = [];
|
|
|
|
/// <summary>Error message if failed.</summary>
|
|
public string? ErrorMessage { get; private set; }
|
|
|
|
/// <summary>Error stack trace if failed.</summary>
|
|
public string? ErrorStackTrace { get; private set; }
|
|
|
|
/// <summary>Correlation ID for distributed tracing.</summary>
|
|
public string CorrelationId { get; init; } = null!;
|
|
|
|
// -------------------------------------------------------------------------
|
|
// Factory Methods
|
|
// -------------------------------------------------------------------------
|
|
|
|
/// <summary>
|
|
/// Create a new source run.
|
|
/// </summary>
|
|
public static SbomSourceRun Create(
|
|
Guid sourceId,
|
|
string tenantId,
|
|
SbomSourceRunTrigger trigger,
|
|
string correlationId,
|
|
TimeProvider timeProvider,
|
|
string? triggerDetails = null)
|
|
{
|
|
return new SbomSourceRun
|
|
{
|
|
RunId = Guid.NewGuid(),
|
|
SourceId = sourceId,
|
|
TenantId = tenantId,
|
|
Trigger = trigger,
|
|
TriggerDetails = triggerDetails,
|
|
Status = SbomSourceRunStatus.Running,
|
|
StartedAt = timeProvider.GetUtcNow(),
|
|
CorrelationId = correlationId
|
|
};
|
|
}
|
|
|
|
// -------------------------------------------------------------------------
|
|
// Progress Updates
|
|
// -------------------------------------------------------------------------
|
|
|
|
/// <summary>
|
|
/// Set the number of discovered items.
|
|
/// </summary>
|
|
public void SetDiscoveredItems(int count)
|
|
{
|
|
ItemsDiscovered = count;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Record a successfully scanned item.
|
|
/// </summary>
|
|
public void RecordItemSuccess(Guid scanJobId)
|
|
{
|
|
ItemsScanned++;
|
|
ItemsSucceeded++;
|
|
ScanJobIds.Add(scanJobId);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Record a failed item.
|
|
/// </summary>
|
|
public void RecordItemFailure()
|
|
{
|
|
ItemsScanned++;
|
|
ItemsFailed++;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Record a skipped item.
|
|
/// </summary>
|
|
public void RecordItemSkipped()
|
|
{
|
|
ItemsSkipped++;
|
|
}
|
|
|
|
// -------------------------------------------------------------------------
|
|
// Completion
|
|
// -------------------------------------------------------------------------
|
|
|
|
/// <summary>
|
|
/// Complete the run successfully.
|
|
/// </summary>
|
|
public void Complete(TimeProvider timeProvider)
|
|
{
|
|
Status = ItemsFailed > 0
|
|
? SbomSourceRunStatus.PartialSuccess
|
|
: ItemsSucceeded > 0
|
|
? SbomSourceRunStatus.Succeeded
|
|
: SbomSourceRunStatus.Skipped;
|
|
|
|
CompletedAt = timeProvider.GetUtcNow();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Fail the run with an error.
|
|
/// </summary>
|
|
public void Fail(string message, TimeProvider timeProvider, string? stackTrace = null)
|
|
{
|
|
Status = SbomSourceRunStatus.Failed;
|
|
ErrorMessage = message;
|
|
ErrorStackTrace = stackTrace;
|
|
CompletedAt = timeProvider.GetUtcNow();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Cancel the run.
|
|
/// </summary>
|
|
public void Cancel(string reason, TimeProvider timeProvider)
|
|
{
|
|
Status = SbomSourceRunStatus.Cancelled;
|
|
ErrorMessage = reason;
|
|
CompletedAt = timeProvider.GetUtcNow();
|
|
}
|
|
}
|