Add comprehensive security tests for OWASP A02, A05, A07, and A08 categories
Some checks failed
Docs CI / lint-and-preview (push) Has been cancelled
Export Center CI / export-ci (push) Has been cancelled
Findings Ledger CI / build-test (push) Has been cancelled
Findings Ledger CI / migration-validation (push) Has been cancelled
Findings Ledger CI / generate-manifest (push) Has been cancelled
Manifest Integrity / Validate Schema Integrity (push) Has been cancelled
Lighthouse CI / Lighthouse Audit (push) Has been cancelled
Lighthouse CI / Axe Accessibility Audit (push) Has been cancelled
Manifest Integrity / Validate Contract Documents (push) Has been cancelled
Manifest Integrity / Validate Pack Fixtures (push) Has been cancelled
Manifest Integrity / Audit SHA256SUMS Files (push) Has been cancelled
Manifest Integrity / Verify Merkle Roots (push) Has been cancelled
Policy Lint & Smoke / policy-lint (push) Has been cancelled
Policy Simulation / policy-simulate (push) Has been cancelled

- Implemented tests for Cryptographic Failures (A02) to ensure proper handling of sensitive data, secure algorithms, and key management.
- Added tests for Security Misconfiguration (A05) to validate production configurations, security headers, CORS settings, and feature management.
- Developed tests for Authentication Failures (A07) to enforce strong password policies, rate limiting, session management, and MFA support.
- Created tests for Software and Data Integrity Failures (A08) to verify artifact signatures, SBOM integrity, attestation chains, and feed updates.
This commit is contained in:
master
2025-12-16 16:40:19 +02:00
parent 415eff1207
commit 2170a58734
206 changed files with 30547 additions and 534 deletions

View File

@@ -17,7 +17,8 @@ public sealed record DeterminismReport(
double OverallScore,
double ThresholdOverall,
double ThresholdImage,
IReadOnlyList<DeterminismImageReport> Images)
IReadOnlyList<DeterminismImageReport> Images,
FidelityMetrics? Fidelity = null)
;
public sealed record DeterminismImageReport(
@@ -26,7 +27,8 @@ public sealed record DeterminismImageReport(
int Identical,
double Score,
IReadOnlyDictionary<string, string> ArtifactHashes,
IReadOnlyList<DeterminismRunReport> RunsDetail);
IReadOnlyList<DeterminismRunReport> RunsDetail,
FidelityMetrics? Fidelity = null);
public sealed record DeterminismRunReport(
int RunIndex,

View File

@@ -0,0 +1,23 @@
// -----------------------------------------------------------------------------
// IScanMetricsCollectorFactory.cs
// Sprint: SPRINT_3406_0001_0001_metrics_tables
// Task: METRICS-3406-009
// Description: Factory for creating ScanMetricsCollector instances per scan
// -----------------------------------------------------------------------------
namespace StellaOps.Scanner.Worker.Metrics;
/// <summary>
/// Factory for creating ScanMetricsCollector instances per scan.
/// </summary>
public interface IScanMetricsCollectorFactory
{
/// <summary>
/// Create a new metrics collector for a scan.
/// </summary>
ScanMetricsCollector Create(
Guid scanId,
Guid tenantId,
string artifactDigest,
string artifactType);
}

View File

@@ -0,0 +1,137 @@
// -----------------------------------------------------------------------------
// ScanCompletionMetricsIntegration.cs
// Sprint: SPRINT_3406_0001_0001_metrics_tables
// Task: METRICS-3406-009
// Description: Integrates metrics collection into scan completion pipeline
// -----------------------------------------------------------------------------
using Microsoft.Extensions.Logging;
using StellaOps.Scanner.Core.Contracts;
using StellaOps.Scanner.Storage.Repositories;
namespace StellaOps.Scanner.Worker.Metrics;
/// <summary>
/// Integrates metrics collection into the scan completion pipeline.
/// Call this after successful scan processing to persist metrics.
/// </summary>
public sealed class ScanCompletionMetricsIntegration
{
private readonly IScanMetricsCollectorFactory _collectorFactory;
private readonly ILogger<ScanCompletionMetricsIntegration> _logger;
public ScanCompletionMetricsIntegration(
IScanMetricsCollectorFactory collectorFactory,
ILogger<ScanCompletionMetricsIntegration> logger)
{
_collectorFactory = collectorFactory ?? throw new ArgumentNullException(nameof(collectorFactory));
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
}
/// <summary>
/// Capture metrics for a completed scan.
/// </summary>
public async Task CaptureAsync(
ScanCompletionContext completion,
CancellationToken cancellationToken = default)
{
ArgumentNullException.ThrowIfNull(completion);
try
{
using var collector = _collectorFactory.Create(
completion.ScanId,
completion.TenantId,
completion.ArtifactDigest,
completion.ArtifactType);
collector.Start();
// Record phase timings from context
foreach (var phase in completion.Phases)
{
using (collector.StartPhase(phase.PhaseName))
{
// Phase timing is set via SetPhaseCompleted
}
collector.CompletePhase(phase.PhaseName, phase.Metrics);
}
// Set digests
collector.SetDigests(
completion.FindingsSha256,
completion.VexBundleSha256,
completion.ProofBundleSha256,
completion.SbomSha256);
// Set policy reference
collector.SetPolicy(
completion.PolicyDigest,
completion.FeedSnapshotId);
// Set counts
collector.SetCounts(
completion.PackageCount,
completion.FindingCount,
completion.VexDecisionCount);
// Set metadata
collector.SetMetadata(
completion.SurfaceId,
completion.ReplayManifestHash,
completion.ScannerImageDigest,
completion.IsReplay);
await collector.CompleteAsync(cancellationToken);
_logger.LogDebug(
"Captured metrics for scan {ScanId}: {FindingCount} findings, {PackageCount} packages",
completion.ScanId, completion.FindingCount, completion.PackageCount);
}
catch (Exception ex)
{
_logger.LogWarning(ex, "Failed to capture metrics for scan {ScanId}", completion.ScanId);
// Don't fail the scan if metrics capture fails
}
}
}
/// <summary>
/// Context for scan completion metrics capture.
/// </summary>
public sealed record ScanCompletionContext
{
public required Guid ScanId { get; init; }
public required Guid TenantId { get; init; }
public required string ArtifactDigest { get; init; }
public required string ArtifactType { get; init; }
public required string FindingsSha256 { get; init; }
public Guid? SurfaceId { get; init; }
public string? VexBundleSha256 { get; init; }
public string? ProofBundleSha256 { get; init; }
public string? SbomSha256 { get; init; }
public string? PolicyDigest { get; init; }
public string? FeedSnapshotId { get; init; }
public string? ReplayManifestHash { get; init; }
public string? ScannerImageDigest { get; init; }
public bool IsReplay { get; init; }
public int? PackageCount { get; init; }
public int? FindingCount { get; init; }
public int? VexDecisionCount { get; init; }
public IReadOnlyList<PhaseCompletionInfo> Phases { get; init; } = [];
}
/// <summary>
/// Information about a completed phase.
/// </summary>
public sealed record PhaseCompletionInfo
{
public required string PhaseName { get; init; }
public DateTimeOffset StartedAt { get; init; }
public DateTimeOffset FinishedAt { get; init; }
public bool Success { get; init; } = true;
public Dictionary<string, object>? Metrics { get; init; }
}

View File

@@ -0,0 +1,49 @@
// -----------------------------------------------------------------------------
// ScanMetricsCollectorFactory.cs
// Sprint: SPRINT_3406_0001_0001_metrics_tables
// Task: METRICS-3406-009
// Description: Factory implementation for creating ScanMetricsCollector instances
// -----------------------------------------------------------------------------
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using StellaOps.Scanner.Storage.Repositories;
using StellaOps.Scanner.Worker.Options;
namespace StellaOps.Scanner.Worker.Metrics;
/// <summary>
/// Factory for creating ScanMetricsCollector instances per scan.
/// </summary>
public sealed class ScanMetricsCollectorFactory : IScanMetricsCollectorFactory
{
private readonly IScanMetricsRepository _repository;
private readonly ILoggerFactory _loggerFactory;
private readonly string _scannerVersion;
public ScanMetricsCollectorFactory(
IScanMetricsRepository repository,
ILoggerFactory loggerFactory,
IOptions<ScannerWorkerOptions> options)
{
_repository = repository ?? throw new ArgumentNullException(nameof(repository));
_loggerFactory = loggerFactory ?? throw new ArgumentNullException(nameof(loggerFactory));
_scannerVersion = options?.Value.ScannerVersion ?? "unknown";
}
public ScanMetricsCollector Create(
Guid scanId,
Guid tenantId,
string artifactDigest,
string artifactType)
{
return new ScanMetricsCollector(
_repository,
_loggerFactory.CreateLogger<ScanMetricsCollector>(),
scanId,
tenantId,
artifactDigest,
artifactType,
_scannerVersion);
}
}