up
This commit is contained in:
@@ -178,6 +178,7 @@ builder.Services.AddSingleton<StellaOps.Findings.Ledger.Infrastructure.Snapshot.
|
||||
builder.Services.AddSingleton<StellaOps.Findings.Ledger.Infrastructure.Snapshot.ITimeTravelRepository,
|
||||
StellaOps.Findings.Ledger.Infrastructure.Postgres.PostgresTimeTravelRepository>();
|
||||
builder.Services.AddSingleton<SnapshotService>();
|
||||
builder.Services.AddSingleton<VexConsensusService>();
|
||||
|
||||
var app = builder.Build();
|
||||
|
||||
@@ -1271,6 +1272,222 @@ app.MapGet("/v1/ledger/current-point", async Task<Results<JsonHttpResult<QueryPo
|
||||
.Produces(StatusCodes.Status200OK)
|
||||
.ProducesProblem(StatusCodes.Status400BadRequest);
|
||||
|
||||
// VexLens Consensus Endpoints (UI-PROOF-VEX-0215-010)
|
||||
app.MapPost("/v1/vex-consensus/compute", async Task<Results<JsonHttpResult<VexConsensusResponse>, ProblemHttpResult>> (
|
||||
HttpContext httpContext,
|
||||
ComputeVexConsensusRequest request,
|
||||
VexConsensusService consensusService,
|
||||
CancellationToken cancellationToken) =>
|
||||
{
|
||||
if (!TryGetTenant(httpContext, out var tenantProblem, out var tenantId))
|
||||
{
|
||||
return tenantProblem!;
|
||||
}
|
||||
|
||||
var result = await consensusService.ComputeConsensusAsync(tenantId, request, cancellationToken).ConfigureAwait(false);
|
||||
return TypedResults.Json(result);
|
||||
})
|
||||
.WithName("ComputeVexConsensus")
|
||||
.RequireAuthorization(LedgerExportPolicy)
|
||||
.Produces(StatusCodes.Status200OK)
|
||||
.ProducesProblem(StatusCodes.Status400BadRequest);
|
||||
|
||||
app.MapPost("/v1/vex-consensus/compute-batch", async Task<Results<JsonHttpResult<VexConsensusBatchResponse>, ProblemHttpResult>> (
|
||||
HttpContext httpContext,
|
||||
ComputeVexConsensusBatchRequest request,
|
||||
VexConsensusService consensusService,
|
||||
CancellationToken cancellationToken) =>
|
||||
{
|
||||
if (!TryGetTenant(httpContext, out var tenantProblem, out var tenantId))
|
||||
{
|
||||
return tenantProblem!;
|
||||
}
|
||||
|
||||
var result = await consensusService.ComputeConsensusBatchAsync(tenantId, request, cancellationToken).ConfigureAwait(false);
|
||||
return TypedResults.Json(result);
|
||||
})
|
||||
.WithName("ComputeVexConsensusBatch")
|
||||
.RequireAuthorization(LedgerExportPolicy)
|
||||
.Produces(StatusCodes.Status200OK)
|
||||
.ProducesProblem(StatusCodes.Status400BadRequest);
|
||||
|
||||
app.MapGet("/v1/vex-consensus/projections/{projectionId}", async Task<Results<JsonHttpResult<VexProjectionDetailResponse>, NotFound, ProblemHttpResult>> (
|
||||
string projectionId,
|
||||
VexConsensusService consensusService,
|
||||
CancellationToken cancellationToken) =>
|
||||
{
|
||||
var result = await consensusService.GetProjectionAsync(projectionId, cancellationToken).ConfigureAwait(false);
|
||||
if (result is null)
|
||||
{
|
||||
return TypedResults.NotFound();
|
||||
}
|
||||
return TypedResults.Json(result);
|
||||
})
|
||||
.WithName("GetVexProjection")
|
||||
.RequireAuthorization(LedgerExportPolicy)
|
||||
.Produces(StatusCodes.Status200OK)
|
||||
.Produces(StatusCodes.Status404NotFound)
|
||||
.ProducesProblem(StatusCodes.Status400BadRequest);
|
||||
|
||||
app.MapGet("/v1/vex-consensus/projections", async Task<Results<JsonHttpResult<QueryVexProjectionsResponse>, ProblemHttpResult>> (
|
||||
HttpContext httpContext,
|
||||
VexConsensusService consensusService,
|
||||
CancellationToken cancellationToken) =>
|
||||
{
|
||||
if (!TryGetTenant(httpContext, out var tenantProblem, out var tenantId))
|
||||
{
|
||||
return tenantProblem!;
|
||||
}
|
||||
|
||||
var request = new QueryVexProjectionsRequest(
|
||||
VulnerabilityId: httpContext.Request.Query["vulnerability_id"].ToString(),
|
||||
ProductKey: httpContext.Request.Query["product_key"].ToString(),
|
||||
Status: httpContext.Request.Query["status"].ToString(),
|
||||
Outcome: httpContext.Request.Query["outcome"].ToString(),
|
||||
MinimumConfidence: ParseDecimal(httpContext.Request.Query["min_confidence"].ToString()) is decimal d ? (double)d : null,
|
||||
ComputedAfter: ParseDate(httpContext.Request.Query["computed_after"].ToString()),
|
||||
ComputedBefore: ParseDate(httpContext.Request.Query["computed_before"].ToString()),
|
||||
StatusChanged: ParseBool(httpContext.Request.Query["status_changed"].ToString()),
|
||||
Limit: ParseInt(httpContext.Request.Query["limit"].ToString()),
|
||||
Offset: ParseInt(httpContext.Request.Query["offset"].ToString()),
|
||||
SortBy: httpContext.Request.Query["sort_by"].ToString(),
|
||||
SortDescending: ParseBool(httpContext.Request.Query["sort_desc"].ToString()));
|
||||
|
||||
var result = await consensusService.QueryProjectionsAsync(tenantId, request, cancellationToken).ConfigureAwait(false);
|
||||
return TypedResults.Json(result);
|
||||
})
|
||||
.WithName("QueryVexProjections")
|
||||
.RequireAuthorization(LedgerExportPolicy)
|
||||
.Produces(StatusCodes.Status200OK)
|
||||
.ProducesProblem(StatusCodes.Status400BadRequest);
|
||||
|
||||
app.MapGet("/v1/vex-consensus/projections/latest", async Task<Results<JsonHttpResult<VexProjectionDetailResponse>, NotFound, ProblemHttpResult>> (
|
||||
HttpContext httpContext,
|
||||
VexConsensusService consensusService,
|
||||
CancellationToken cancellationToken) =>
|
||||
{
|
||||
if (!TryGetTenant(httpContext, out var tenantProblem, out var tenantId))
|
||||
{
|
||||
return tenantProblem!;
|
||||
}
|
||||
|
||||
var vulnId = httpContext.Request.Query["vulnerability_id"].ToString();
|
||||
var productKey = httpContext.Request.Query["product_key"].ToString();
|
||||
|
||||
if (string.IsNullOrEmpty(vulnId) || string.IsNullOrEmpty(productKey))
|
||||
{
|
||||
return TypedResults.Problem(statusCode: StatusCodes.Status400BadRequest, title: "missing_params", detail: "vulnerability_id and product_key are required.");
|
||||
}
|
||||
|
||||
var result = await consensusService.GetLatestProjectionAsync(tenantId, vulnId, productKey, cancellationToken).ConfigureAwait(false);
|
||||
if (result is null)
|
||||
{
|
||||
return TypedResults.NotFound();
|
||||
}
|
||||
return TypedResults.Json(result);
|
||||
})
|
||||
.WithName("GetLatestVexProjection")
|
||||
.RequireAuthorization(LedgerExportPolicy)
|
||||
.Produces(StatusCodes.Status200OK)
|
||||
.Produces(StatusCodes.Status404NotFound)
|
||||
.ProducesProblem(StatusCodes.Status400BadRequest);
|
||||
|
||||
app.MapGet("/v1/vex-consensus/history", async Task<Results<JsonHttpResult<VexProjectionHistoryResponse>, ProblemHttpResult>> (
|
||||
HttpContext httpContext,
|
||||
VexConsensusService consensusService,
|
||||
CancellationToken cancellationToken) =>
|
||||
{
|
||||
if (!TryGetTenant(httpContext, out var tenantProblem, out var tenantId))
|
||||
{
|
||||
return tenantProblem!;
|
||||
}
|
||||
|
||||
var vulnId = httpContext.Request.Query["vulnerability_id"].ToString();
|
||||
var productKey = httpContext.Request.Query["product_key"].ToString();
|
||||
var limit = ParseInt(httpContext.Request.Query["limit"].ToString());
|
||||
|
||||
if (string.IsNullOrEmpty(vulnId) || string.IsNullOrEmpty(productKey))
|
||||
{
|
||||
return TypedResults.Problem(statusCode: StatusCodes.Status400BadRequest, title: "missing_params", detail: "vulnerability_id and product_key are required.");
|
||||
}
|
||||
|
||||
var result = await consensusService.GetProjectionHistoryAsync(tenantId, vulnId, productKey, limit, cancellationToken).ConfigureAwait(false);
|
||||
return TypedResults.Json(result);
|
||||
})
|
||||
.WithName("GetVexProjectionHistory")
|
||||
.RequireAuthorization(LedgerExportPolicy)
|
||||
.Produces(StatusCodes.Status200OK)
|
||||
.ProducesProblem(StatusCodes.Status400BadRequest);
|
||||
|
||||
app.MapGet("/v1/vex-consensus/statistics", async Task<Results<JsonHttpResult<VexConsensusStatisticsResponse>, ProblemHttpResult>> (
|
||||
HttpContext httpContext,
|
||||
VexConsensusService consensusService,
|
||||
CancellationToken cancellationToken) =>
|
||||
{
|
||||
if (!TryGetTenant(httpContext, out var tenantProblem, out var tenantId))
|
||||
{
|
||||
return tenantProblem!;
|
||||
}
|
||||
|
||||
var result = await consensusService.GetStatisticsAsync(tenantId, cancellationToken).ConfigureAwait(false);
|
||||
return TypedResults.Json(result);
|
||||
})
|
||||
.WithName("GetVexConsensusStatistics")
|
||||
.RequireAuthorization(LedgerExportPolicy)
|
||||
.Produces(StatusCodes.Status200OK)
|
||||
.ProducesProblem(StatusCodes.Status400BadRequest);
|
||||
|
||||
app.MapGet("/v1/vex-consensus/issuers", async Task<Results<JsonHttpResult<VexIssuerListResponse>, ProblemHttpResult>> (
|
||||
HttpContext httpContext,
|
||||
VexConsensusService consensusService,
|
||||
CancellationToken cancellationToken) =>
|
||||
{
|
||||
var result = await consensusService.ListIssuersAsync(
|
||||
httpContext.Request.Query["category"].ToString(),
|
||||
httpContext.Request.Query["min_trust_tier"].ToString(),
|
||||
httpContext.Request.Query["status"].ToString(),
|
||||
httpContext.Request.Query["search"].ToString(),
|
||||
ParseInt(httpContext.Request.Query["limit"].ToString()),
|
||||
ParseInt(httpContext.Request.Query["offset"].ToString()),
|
||||
cancellationToken).ConfigureAwait(false);
|
||||
return TypedResults.Json(result);
|
||||
})
|
||||
.WithName("ListVexIssuers")
|
||||
.RequireAuthorization(LedgerExportPolicy)
|
||||
.Produces(StatusCodes.Status200OK)
|
||||
.ProducesProblem(StatusCodes.Status400BadRequest);
|
||||
|
||||
app.MapGet("/v1/vex-consensus/issuers/{issuerId}", async Task<Results<JsonHttpResult<VexIssuerDetailResponse>, NotFound, ProblemHttpResult>> (
|
||||
string issuerId,
|
||||
VexConsensusService consensusService,
|
||||
CancellationToken cancellationToken) =>
|
||||
{
|
||||
var result = await consensusService.GetIssuerAsync(issuerId, cancellationToken).ConfigureAwait(false);
|
||||
if (result is null)
|
||||
{
|
||||
return TypedResults.NotFound();
|
||||
}
|
||||
return TypedResults.Json(result);
|
||||
})
|
||||
.WithName("GetVexIssuer")
|
||||
.RequireAuthorization(LedgerExportPolicy)
|
||||
.Produces(StatusCodes.Status200OK)
|
||||
.Produces(StatusCodes.Status404NotFound)
|
||||
.ProducesProblem(StatusCodes.Status400BadRequest);
|
||||
|
||||
app.MapPost("/v1/vex-consensus/issuers", async Task<Results<Created<VexIssuerDetailResponse>, ProblemHttpResult>> (
|
||||
RegisterVexIssuerRequest request,
|
||||
VexConsensusService consensusService,
|
||||
CancellationToken cancellationToken) =>
|
||||
{
|
||||
var result = await consensusService.RegisterIssuerAsync(request, cancellationToken).ConfigureAwait(false);
|
||||
return TypedResults.Created($"/v1/vex-consensus/issuers/{result.IssuerId}", result);
|
||||
})
|
||||
.WithName("RegisterVexIssuer")
|
||||
.RequireAuthorization(LedgerWritePolicy)
|
||||
.Produces(StatusCodes.Status201Created)
|
||||
.ProducesProblem(StatusCodes.Status400BadRequest);
|
||||
|
||||
app.Run();
|
||||
|
||||
static Created<LedgerEventResponse> CreateCreatedResponse(LedgerEventRecord record)
|
||||
|
||||
Reference in New Issue
Block a user