consolidation of some of the modules, localization fixes, product advisories work, qa work

This commit is contained in:
master
2026-03-05 03:54:22 +02:00
parent 7bafcc3eef
commit 8e1cb9448d
3878 changed files with 72600 additions and 46861 deletions

View File

@@ -1,11 +1,17 @@
using Microsoft.Extensions.DependencyInjection;
using StellaOps.Auth.ServerIntegration;
using StellaOps.Auth.ServerIntegration.Tenancy;
using StellaOps.Infrastructure.Postgres.Options;
using StellaOps.Localization;
using StellaOps.Remediation.Core.Abstractions;
using StellaOps.Remediation.Core.Services;
using StellaOps.Remediation.Persistence.Postgres;
using StellaOps.Remediation.Persistence.Repositories;
using StellaOps.Auth.ServerIntegration.Tenancy;
using StellaOps.Remediation.WebService.Endpoints;
using StellaOps.Router.AspNet;
var builder = WebApplication.CreateBuilder(args);
var storageDriver = ResolveStorageDriver(builder.Configuration, "Remediation");
builder.Services.AddProblemDetails();
builder.Services.AddHealthChecks();
@@ -18,6 +24,7 @@ builder.Services.AddAuthorization(options =>
});
builder.Services.AddAuthentication();
builder.Services.AddStellaOpsTenantServices();
builder.Services.AddStellaOpsCors(builder.Environment, builder.Configuration);
builder.Services.AddStellaOpsLocalization(builder.Configuration);
builder.Services.AddTranslationBundle(System.Reflection.Assembly.GetExecutingAssembly());
@@ -25,26 +32,28 @@ builder.Services.AddTranslationBundle(System.Reflection.Assembly.GetExecutingAss
builder.Services.AddSingleton<IContributorTrustScorer, ContributorTrustScorer>();
builder.Services.AddSingleton<IRemediationVerifier, RemediationVerifier>();
// Persistence (in-memory stubs for now; swap to Postgres in production)
var templateRepo = new PostgresFixTemplateRepository();
var submissionRepo = new PostgresPrSubmissionRepository();
builder.Services.AddSingleton<IFixTemplateRepository>(templateRepo);
builder.Services.AddSingleton<IPrSubmissionRepository>(submissionRepo);
RegisterPersistence(builder.Services, builder.Configuration, builder.Environment, storageDriver);
// Registry: compose from repositories
builder.Services.AddSingleton<IRemediationRegistry>(sp =>
new InMemoryRemediationRegistry(templateRepo, submissionRepo));
// Registry/matcher: compose from repositories.
builder.Services.AddSingleton<IRemediationRegistry, RepositoryBackedRemediationRegistry>();
builder.Services.AddSingleton<IRemediationMatcher, RepositoryBackedRemediationMatcher>();
// Matcher: compose from template repository
builder.Services.AddSingleton<IRemediationMatcher>(sp =>
new InMemoryRemediationMatcher(templateRepo));
var routerEnabled = builder.Services.AddRouterMicroservice(
builder.Configuration,
serviceName: "remediation",
version: System.Reflection.CustomAttributeExtensions.GetCustomAttribute<System.Reflection.AssemblyInformationalVersionAttribute>(System.Reflection.Assembly.GetExecutingAssembly())?.InformationalVersion ?? "1.0.0",
routerOptionsSection: "Router");
builder.TryAddStellaOpsLocalBinding("remediation");
var app = builder.Build();
app.LogStellaOpsLocalHostname("remediation");
app.UseAuthentication();
app.UseStellaOpsCors();
app.UseStellaOpsLocalization();
app.UseAuthorization();
app.UseStellaOpsTenantMiddleware();
app.TryUseStellaRouter(routerEnabled);
app.MapHealthChecks("/healthz").AllowAnonymous();
@@ -53,17 +62,112 @@ app.MapRemediationMatchEndpoints();
app.MapRemediationSourceEndpoints();
await app.LoadTranslationsAsync();
app.TryRefreshStellaRouterEndpoints(routerEnabled);
app.Run();
static void RegisterPersistence(
IServiceCollection services,
IConfiguration configuration,
IHostEnvironment environment,
string storageDriver)
{
if (string.Equals(storageDriver, "postgres", StringComparison.OrdinalIgnoreCase))
{
var connectionString = ResolvePostgresConnectionString(configuration, "Remediation");
if (string.IsNullOrWhiteSpace(connectionString))
{
throw new InvalidOperationException(
"Remediation requires PostgreSQL connection settings when Storage:Driver=postgres. " +
"Set ConnectionStrings:Default or Remediation:Storage:Postgres:ConnectionString.");
}
var schemaName = ResolveSchemaName(configuration, "Remediation") ?? RemediationDataSource.DefaultSchemaName;
services.Configure<PostgresOptions>(options =>
{
options.ConnectionString = connectionString;
options.SchemaName = schemaName;
});
services.AddSingleton<RemediationDataSource>();
services.AddSingleton<IFixTemplateRepository, PostgresFixTemplateRepository>();
services.AddSingleton<IPrSubmissionRepository, PostgresPrSubmissionRepository>();
services.AddSingleton<IMarketplaceSourceRepository, PostgresMarketplaceSourceRepository>();
return;
}
if (string.Equals(storageDriver, "inmemory", StringComparison.OrdinalIgnoreCase))
{
if (!IsTestEnvironment(environment))
{
throw new InvalidOperationException(
"Remediation in-memory storage driver is restricted to Test/Testing environments.");
}
services.AddSingleton<IFixTemplateRepository>(_ => new PostgresFixTemplateRepository());
services.AddSingleton<IPrSubmissionRepository>(_ => new PostgresPrSubmissionRepository());
services.AddSingleton<IMarketplaceSourceRepository>(_ => new PostgresMarketplaceSourceRepository());
return;
}
throw new InvalidOperationException(
$"Unsupported Remediation storage driver '{storageDriver}'. Allowed values: postgres, inmemory.");
}
static bool IsTestEnvironment(IHostEnvironment environment)
{
return environment.IsEnvironment("Test") || environment.IsEnvironment("Testing");
}
static string ResolveStorageDriver(IConfiguration configuration, string serviceName)
{
return FirstNonEmpty(
configuration[$"{serviceName}:Storage:Driver"],
configuration["Storage:Driver"])
?? "postgres";
}
static string? ResolveSchemaName(IConfiguration configuration, string serviceName)
{
return FirstNonEmpty(
configuration[$"{serviceName}:Storage:Postgres:SchemaName"],
configuration["Storage:Postgres:SchemaName"],
configuration[$"Postgres:{serviceName}:SchemaName"]);
}
static string? ResolvePostgresConnectionString(IConfiguration configuration, string serviceName)
{
return FirstNonEmpty(
configuration[$"{serviceName}:Storage:Postgres:ConnectionString"],
configuration["Storage:Postgres:ConnectionString"],
configuration[$"Postgres:{serviceName}:ConnectionString"],
configuration[$"ConnectionStrings:{serviceName}"],
configuration["ConnectionStrings:Default"]);
}
static string? FirstNonEmpty(params string?[] values)
{
foreach (var value in values)
{
if (!string.IsNullOrWhiteSpace(value))
{
return value;
}
}
return null;
}
public partial class Program { }
/// <summary>
/// In-memory registry implementation composed from repositories.
/// Repository-backed registry implementation composed from repositories.
/// </summary>
internal sealed class InMemoryRemediationRegistry : IRemediationRegistry
internal sealed class RepositoryBackedRemediationRegistry : IRemediationRegistry
{
private readonly IFixTemplateRepository _templates;
private readonly IPrSubmissionRepository _submissions;
public InMemoryRemediationRegistry(IFixTemplateRepository templates, IPrSubmissionRepository submissions)
public RepositoryBackedRemediationRegistry(IFixTemplateRepository templates, IPrSubmissionRepository submissions)
{
_templates = templates;
_submissions = submissions;
@@ -92,13 +196,13 @@ internal sealed class InMemoryRemediationRegistry : IRemediationRegistry
}
/// <summary>
/// In-memory matcher implementation that delegates to template repository.
/// Repository-backed matcher implementation that delegates to template repository.
/// </summary>
internal sealed class InMemoryRemediationMatcher : IRemediationMatcher
internal sealed class RepositoryBackedRemediationMatcher : IRemediationMatcher
{
private readonly IFixTemplateRepository _templates;
public InMemoryRemediationMatcher(IFixTemplateRepository templates)
public RepositoryBackedRemediationMatcher(IFixTemplateRepository templates)
{
_templates = templates;
}