audit, advisories and doctors/setup work

This commit is contained in:
master
2026-01-13 18:53:39 +02:00
parent 9ca7cb183e
commit d7be6ba34b
811 changed files with 54242 additions and 4056 deletions

View File

@@ -1,7 +1,9 @@
using System.Globalization;
using System.Diagnostics.Metrics;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;
using StellaOps.SbomService.Auth;
using StellaOps.SbomService.Models;
using StellaOps.SbomService.Services;
using StellaOps.SbomService.Observability;
@@ -17,6 +19,12 @@ builder.Configuration
builder.Services.AddOptions();
builder.Services.AddLogging();
builder.Services.AddSingleton<TimeProvider>(TimeProvider.System);
builder.Services.AddSingleton<IGuidProvider>(SystemGuidProvider.Instance);
builder.Services.AddAuthentication(HeaderAuthenticationHandler.SchemeName)
.AddScheme<AuthenticationSchemeOptions, HeaderAuthenticationHandler>(HeaderAuthenticationHandler.SchemeName, _ => { });
builder.Services.AddAuthorization();
// Register SBOM query services using file-backed fixtures when present; fallback to in-memory seeds.
builder.Services.AddSingleton<IComponentLookupRepository>(sp =>
@@ -50,7 +58,7 @@ builder.Services.AddSingleton<ICatalogRepository>(sp =>
? new FileCatalogRepository(candidate)
: new InMemoryCatalogRepository();
});
builder.Services.AddSingleton<IClock, SystemClock>();
builder.Services.AddSingleton<IClock, StellaOps.SbomService.Services.SystemClock>();
builder.Services.AddSingleton<ISbomEventStore, InMemorySbomEventStore>();
builder.Services.AddSingleton<ISbomEventPublisher>(sp => sp.GetRequiredService<ISbomEventStore>());
builder.Services.AddSingleton<ISbomQueryService, InMemorySbomQueryService>();
@@ -63,7 +71,23 @@ builder.Services.AddSingleton<IOrchestratorControlService>(sp =>
SbomMetrics.Meter));
builder.Services.AddSingleton<IWatermarkService, InMemoryWatermarkService>();
builder.Services.AddOptions<SbomLedgerOptions>()
.Bind(builder.Configuration.GetSection("SbomService:Ledger"));
.Bind(builder.Configuration.GetSection("SbomService:Ledger"))
.ValidateDataAnnotations()
.Validate(options => options.MaxVersionsPerArtifact <= 0 || options.MinVersionsToKeep <= options.MaxVersionsPerArtifact,
"MinVersionsToKeep must be less than or equal to MaxVersionsPerArtifact.")
.ValidateOnStart();
builder.Services.AddOptions<RegistryHttpOptions>()
.Bind(builder.Configuration.GetSection($"SbomService:{RegistryHttpOptions.SectionName}"))
.ValidateDataAnnotations()
.ValidateOnStart();
builder.Services.AddOptions<ScannerHttpOptions>()
.Bind(builder.Configuration.GetSection($"SbomService:{ScannerHttpOptions.SectionName}"))
.ValidateDataAnnotations()
.ValidateOnStart();
builder.Services.AddOptions<RegistrySourceQueryOptions>()
.Bind(builder.Configuration.GetSection($"SbomService:{RegistrySourceQueryOptions.SectionName}"))
.ValidateDataAnnotations()
.ValidateOnStart();
builder.Services.AddSingleton<ISbomLedgerRepository, InMemorySbomLedgerRepository>();
builder.Services.AddSingleton<ISbomNormalizationService, SbomNormalizationService>();
builder.Services.AddSingleton<ISbomQualityScorer, SbomQualityScorer>();
@@ -76,6 +100,11 @@ builder.Services.AddSingleton<ISbomLineageEdgeRepository, InMemorySbomLineageEdg
// LIN-BE-015: Hover card cache for <150ms response times
// Use distributed cache if configured, otherwise in-memory
builder.Services.AddOptions<LineageHoverCacheOptions>()
.Bind(builder.Configuration.GetSection("SbomService:HoverCache"))
.ValidateDataAnnotations()
.Validate(options => options.Ttl > TimeSpan.Zero, "Hover cache TTL must be positive.")
.ValidateOnStart();
var hoverCacheConfig = builder.Configuration.GetSection("SbomService:HoverCache");
if (hoverCacheConfig.GetValue<bool>("UseDistributed"))
{
@@ -101,7 +130,10 @@ builder.Services.AddSingleton<IReplayHashService, ReplayHashService>();
builder.Services.AddSingleton<IReplayVerificationService, ReplayVerificationService>();
// LIN-BE-034: Compare cache with TTL and VEX invalidation
builder.Services.Configure<CompareCacheOptions>(builder.Configuration.GetSection("SbomService:CompareCache"));
builder.Services.AddOptions<CompareCacheOptions>()
.Bind(builder.Configuration.GetSection("SbomService:CompareCache"))
.ValidateDataAnnotations()
.ValidateOnStart();
builder.Services.AddSingleton<ILineageCompareCache, InMemoryLineageCompareCache>();
// REG-SRC: Registry source management (SPRINT_20251229_012)
@@ -109,8 +141,22 @@ builder.Services.AddSingleton<IRegistrySourceRepository, InMemoryRegistrySourceR
builder.Services.AddSingleton<IRegistrySourceRunRepository, InMemoryRegistrySourceRunRepository>();
builder.Services.AddSingleton<IRegistrySourceService, RegistrySourceService>();
builder.Services.AddSingleton<IRegistryWebhookService, RegistryWebhookService>();
builder.Services.AddHttpClient("RegistryDiscovery");
builder.Services.AddHttpClient("Scanner");
builder.Services.AddHttpClient("RegistryDiscovery", (sp, client) =>
{
var options = sp.GetRequiredService<IOptions<RegistryHttpOptions>>().Value;
if (options.Timeout > TimeSpan.Zero && options.Timeout != Timeout.InfiniteTimeSpan)
{
client.Timeout = options.Timeout;
}
});
builder.Services.AddHttpClient("Scanner", (sp, client) =>
{
var options = sp.GetRequiredService<IOptions<ScannerHttpOptions>>().Value;
if (options.Timeout > TimeSpan.Zero && options.Timeout != Timeout.InfiniteTimeSpan)
{
client.Timeout = options.Timeout;
}
});
builder.Services.AddSingleton<IRegistryDiscoveryService, RegistryDiscoveryService>();
builder.Services.AddSingleton<IScanJobEmitterService, ScanJobEmitterService>();
@@ -186,21 +232,12 @@ var app = builder.Build();
if (app.Environment.IsDevelopment())
{
app.Use(async (context, next) =>
{
try
{
await next();
}
catch (Exception ex)
{
Console.WriteLine($"[dev-exception] {ex}");
throw;
}
});
app.UseDeveloperExceptionPage();
}
app.UseAuthentication();
app.UseAuthorization();
app.MapGet("/healthz", () => Results.Ok(new { status = "ok" }));
app.MapGet("/readyz", () => Results.Ok(new { status = "warming" }));