This commit is contained in:
StellaOps Bot
2025-12-09 00:20:52 +02:00
parent 3d01bf9edc
commit bc0762e97d
261 changed files with 14033 additions and 4427 deletions

View File

@@ -26,6 +26,10 @@ using StellaOps.Findings.Ledger.WebService.Services;
using StellaOps.Telemetry.Core;
using StellaOps.Findings.Ledger.Services.Security;
using StellaOps.Findings.Ledger.Observability;
using StellaOps.Findings.Ledger.OpenApi;
using System.Security.Cryptography;
using System.Text;
using StellaOps.Findings.Ledger.Services.Incident;
const string LedgerWritePolicy = "ledger.events.write";
const string LedgerExportPolicy = "ledger.export.read";
@@ -62,6 +66,11 @@ builder.Services.AddOptions<LedgerServiceOptions>()
.PostConfigure(options => options.Validate())
.ValidateOnStart();
builder.Services.AddOptions<LedgerIncidentOptions>()
.Bind(builder.Configuration.GetSection(LedgerIncidentOptions.SectionName))
.PostConfigure(options => options.Validate())
.ValidateOnStart();
builder.Services.AddSingleton(TimeProvider.System);
builder.Services.AddProblemDetails();
builder.Services.AddEndpointsApiExplorer();
@@ -80,6 +89,8 @@ builder.Services.AddStellaOpsTelemetry(
tracerBuilder.AddHttpClientInstrumentation();
});
builder.Services.AddIncidentMode(builder.Configuration);
builder.Services.AddStellaOpsResourceServerAuthentication(
builder.Configuration,
configurationSection: null,
@@ -130,6 +141,10 @@ builder.Services.AddAuthorization(options =>
});
});
builder.Services.AddSingleton<ILedgerIncidentNotifier, LoggingLedgerIncidentNotifier>();
builder.Services.AddSingleton<LedgerIncidentCoordinator>();
builder.Services.AddSingleton<ILedgerIncidentDiagnostics>(sp => sp.GetRequiredService<LedgerIncidentCoordinator>());
builder.Services.AddSingleton<ILedgerIncidentState>(sp => sp.GetRequiredService<LedgerIncidentCoordinator>());
builder.Services.AddSingleton<LedgerAnchorQueue>();
builder.Services.AddSingleton<LedgerDataSource>();
builder.Services.AddSingleton<IMerkleAnchorRepository, PostgresMerkleAnchorRepository>();
@@ -232,6 +247,8 @@ app.MapGet("/ledger/export/findings", async Task<Results<FileStreamHttpResult, J
ExportQueryService exportQueryService,
CancellationToken cancellationToken) =>
{
DeprecationHeaders.Apply(httpContext.Response, "ledger.export.findings");
if (!httpContext.Request.Headers.TryGetValue("X-Stella-Tenant", out var tenantValues) || string.IsNullOrWhiteSpace(tenantValues))
{
return TypedResults.Problem(statusCode: StatusCodes.Status400BadRequest, title: "missing_tenant", detail: "X-Stella-Tenant header is required.");
@@ -841,20 +858,40 @@ app.MapPut("/v1/ledger/attestation-pointers/{pointerId}/verification", async Tas
.Produces(StatusCodes.Status404NotFound)
.ProducesProblem(StatusCodes.Status400BadRequest);
app.MapGet("/.well-known/openapi", () =>
app.MapGet("/.well-known/openapi", async (HttpContext context) =>
{
var contentRoot = AppContext.BaseDirectory;
var candidate = Path.GetFullPath(Path.Combine(contentRoot, "../../docs/modules/findings-ledger/openapi/findings-ledger.v1.yaml"));
if (!File.Exists(candidate))
var specPath = OpenApiMetadataFactory.GetSpecPath(contentRoot);
if (!File.Exists(specPath))
{
return Results.Problem(statusCode: StatusCodes.Status500InternalServerError, title: "openapi_missing", detail: "OpenAPI document not found on server.");
}
var yaml = File.ReadAllText(candidate);
return Results.Text(yaml, "application/yaml");
var specBytes = await File.ReadAllBytesAsync(specPath, context.RequestAborted).ConfigureAwait(false);
var etag = OpenApiMetadataFactory.ComputeEtag(specBytes);
if (context.Request.Headers.IfNoneMatch.Any(match => string.Equals(match, etag, StringComparison.Ordinal)))
{
return Results.StatusCode(StatusCodes.Status304NotModified);
}
context.Response.Headers.ETag = etag;
context.Response.Headers.CacheControl = "public, max-age=300, must-revalidate";
context.Response.Headers.Append("X-Api-Version", OpenApiMetadataFactory.ApiVersion);
context.Response.Headers.Append("X-Build-Version", OpenApiMetadataFactory.GetBuildVersion());
var lastModified = OpenApiMetadataFactory.GetLastModified(specPath);
if (lastModified.HasValue)
{
context.Response.Headers.LastModified = lastModified.Value.ToString("R");
}
return Results.Text(Encoding.UTF8.GetString(specBytes), "application/yaml");
})
.WithName("LedgerOpenApiDocument")
.Produces(StatusCodes.Status200OK)
.Produces(StatusCodes.Status304NotModified)
.ProducesProblem(StatusCodes.Status500InternalServerError);
// Snapshot Endpoints (LEDGER-PACKS-42-001-DEV)