feat(metrics): Implement scan metrics repository and PostgreSQL integration
Some checks failed
Docs CI / lint-and-preview (push) Has been cancelled
Some checks failed
Docs CI / lint-and-preview (push) Has been cancelled
- Added IScanMetricsRepository interface for scan metrics persistence and retrieval. - Implemented PostgresScanMetricsRepository for PostgreSQL database interactions, including methods for saving and retrieving scan metrics and execution phases. - Introduced methods for obtaining TTE statistics and recent scans for tenants. - Implemented deletion of old metrics for retention purposes. test(tests): Add SCA Failure Catalogue tests for FC6-FC10 - Created ScaCatalogueDeterminismTests to validate determinism properties of SCA Failure Catalogue fixtures. - Developed ScaFailureCatalogueTests to ensure correct handling of specific failure modes in the scanner. - Included tests for manifest validation, file existence, and expected findings across multiple failure cases. feat(telemetry): Integrate scan completion metrics into the pipeline - Introduced IScanCompletionMetricsIntegration interface and ScanCompletionMetricsIntegration class to record metrics upon scan completion. - Implemented proof coverage and TTE metrics recording with logging for scan completion summaries.
This commit is contained in:
@@ -0,0 +1,111 @@
|
||||
// -----------------------------------------------------------------------------
|
||||
// ScanCompletionMetricsIntegration.cs
|
||||
// Sprint: SPRINT_3401_0001_0001_determinism_scoring_foundations
|
||||
// Task: DET-3401-007
|
||||
// Description: Integrates proof coverage calculation into scan completion pipeline
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace StellaOps.Telemetry.Core;
|
||||
|
||||
/// <summary>
|
||||
/// Integrates proof coverage metrics into the scan completion pipeline.
|
||||
/// </summary>
|
||||
public interface IScanCompletionMetricsIntegration
|
||||
{
|
||||
/// <summary>
|
||||
/// Records metrics at scan completion.
|
||||
/// </summary>
|
||||
void OnScanCompleted(ScanCompletionData data);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Data required for scan completion metrics calculation.
|
||||
/// </summary>
|
||||
public sealed record ScanCompletionData
|
||||
{
|
||||
public required string TenantId { get; init; }
|
||||
public required string SurfaceId { get; init; }
|
||||
public required string ScanId { get; init; }
|
||||
|
||||
// Finding counts
|
||||
public required int TotalFindings { get; init; }
|
||||
public required int FindingsWithReceipts { get; init; }
|
||||
|
||||
// VEX counts
|
||||
public required int TotalVexItems { get; init; }
|
||||
public required int VexWithReceipts { get; init; }
|
||||
|
||||
// Reachability counts
|
||||
public required int TotalReachableFindings { get; init; }
|
||||
public required int ReachableWithProofs { get; init; }
|
||||
|
||||
// Timing
|
||||
public required DateTimeOffset StartedAt { get; init; }
|
||||
public required DateTimeOffset CompletedAt { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Total scan duration in milliseconds.
|
||||
/// </summary>
|
||||
public int DurationMs => (int)(CompletedAt - StartedAt).TotalMilliseconds;
|
||||
}
|
||||
|
||||
public sealed class ScanCompletionMetricsIntegration : IScanCompletionMetricsIntegration
|
||||
{
|
||||
private readonly ProofCoverageMetrics _proofCoverage;
|
||||
private readonly TimeToEvidenceMetrics _tteMetrics;
|
||||
private readonly ILogger<ScanCompletionMetricsIntegration> _logger;
|
||||
|
||||
public ScanCompletionMetricsIntegration(
|
||||
ProofCoverageMetrics proofCoverage,
|
||||
TimeToEvidenceMetrics tteMetrics,
|
||||
ILogger<ScanCompletionMetricsIntegration> logger)
|
||||
{
|
||||
_proofCoverage = proofCoverage ?? throw new ArgumentNullException(nameof(proofCoverage));
|
||||
_tteMetrics = tteMetrics ?? throw new ArgumentNullException(nameof(tteMetrics));
|
||||
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
||||
}
|
||||
|
||||
public void OnScanCompleted(ScanCompletionData data)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(data);
|
||||
|
||||
// Record proof coverage metrics
|
||||
_proofCoverage.RecordScanCoverage(
|
||||
tenantId: data.TenantId,
|
||||
surfaceId: data.SurfaceId,
|
||||
findingsWithReceipts: data.FindingsWithReceipts,
|
||||
totalFindings: data.TotalFindings,
|
||||
vexWithReceipts: data.VexWithReceipts,
|
||||
totalVex: data.TotalVexItems,
|
||||
reachableWithProofs: data.ReachableWithProofs,
|
||||
totalReachable: data.TotalReachableFindings);
|
||||
|
||||
// Record TTE metrics
|
||||
_tteMetrics.RecordScanDuration(
|
||||
tenantId: data.TenantId,
|
||||
surfaceId: data.SurfaceId,
|
||||
durationMs: data.DurationMs,
|
||||
findingCount: data.TotalFindings);
|
||||
|
||||
// Log summary
|
||||
var allCoverage = ComputePercentage(data.FindingsWithReceipts, data.TotalFindings);
|
||||
var vexCoverage = ComputePercentage(data.VexWithReceipts, data.TotalVexItems);
|
||||
var reachCoverage = ComputePercentage(data.ReachableWithProofs, data.TotalReachableFindings);
|
||||
|
||||
_logger.LogInformation(
|
||||
"Scan {ScanId} completed. TTE={DurationMs}ms, Proof coverage: all={AllCov}%, vex={VexCov}%, reachable={ReachCov}%",
|
||||
data.ScanId,
|
||||
data.DurationMs,
|
||||
allCoverage,
|
||||
vexCoverage,
|
||||
reachCoverage);
|
||||
}
|
||||
|
||||
private static int ComputePercentage(int numerator, int denominator)
|
||||
{
|
||||
if (denominator <= 0) return 100;
|
||||
return (numerator * 100) / denominator;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user