Gaps fill up, fixes, ui restructuring
This commit is contained in:
@@ -82,6 +82,9 @@ builder.Services.AddOptions<SignalsOptions>()
|
||||
builder.Services.AddSingleton(sp => sp.GetRequiredService<IOptions<SignalsOptions>>().Value);
|
||||
builder.Services.AddSingleton<SignalsStartupState>();
|
||||
builder.Services.AddDeterminismDefaults();
|
||||
|
||||
// Triage auto-suppress join service (Sprint: SPRINT_20260219_012, MWS-02)
|
||||
builder.Services.AddTriageSuppressServices();
|
||||
builder.Services.AddSingleton<SignalsSealedModeMonitor>();
|
||||
builder.Services.AddProblemDetails();
|
||||
builder.Services.AddHealthChecks();
|
||||
@@ -213,6 +216,16 @@ builder.Services.AddSingleton<IReachabilityUnionIngestionService, ReachabilityUn
|
||||
builder.Services.AddSingleton<IUnknownsIngestionService, UnknownsIngestionService>();
|
||||
builder.Services.AddSingleton<SyntheticRuntimeProbeBuilder>();
|
||||
|
||||
// Execution evidence pipeline (Sprint: SPRINT_20260219_013)
|
||||
builder.Services.AddOptions<ExecutionEvidenceOptions>()
|
||||
.Bind(builder.Configuration.GetSection(ExecutionEvidenceOptions.SectionName));
|
||||
builder.Services.AddSingleton<IExecutionEvidenceBuilder, ExecutionEvidenceBuilder>();
|
||||
|
||||
// Beacon attestation pipeline (Sprint: SPRINT_20260219_014)
|
||||
builder.Services.AddOptions<BeaconOptions>()
|
||||
.Bind(builder.Configuration.GetSection(BeaconOptions.SectionName));
|
||||
builder.Services.AddSingleton<IBeaconAttestationBuilder, BeaconAttestationBuilder>();
|
||||
|
||||
// SCM/CI webhook services (Sprint: SPRINT_20251229_013)
|
||||
builder.Services.AddSingleton<IWebhookSignatureValidator, GitHubWebhookValidator>();
|
||||
builder.Services.AddSingleton<IWebhookSignatureValidator, GitLabWebhookValidator>();
|
||||
@@ -855,6 +868,105 @@ signalsGroup.MapGet("/unknowns/{id}/explain", async Task<IResult> (
|
||||
});
|
||||
}).WithName("SignalsUnknownsExplain");
|
||||
|
||||
// Execution evidence endpoint (Sprint: SPRINT_20260219_013, SEE-02)
|
||||
signalsGroup.MapPost("/execution-evidence", async Task<IResult> (
|
||||
HttpContext context,
|
||||
SignalsOptions options,
|
||||
ExecutionEvidenceRequest request,
|
||||
IExecutionEvidenceBuilder evidenceBuilder,
|
||||
SignalsSealedModeMonitor sealedModeMonitor,
|
||||
CancellationToken cancellationToken) =>
|
||||
{
|
||||
if (!Program.TryAuthorize(context, SignalsPolicies.Write, options.Authority.AllowAnonymousFallback, out var authFailure))
|
||||
{
|
||||
return authFailure ?? Results.Unauthorized();
|
||||
}
|
||||
|
||||
if (!Program.TryEnsureSealedMode(sealedModeMonitor, out var sealedFailure))
|
||||
{
|
||||
return sealedFailure ?? Results.StatusCode(StatusCodes.Status503ServiceUnavailable);
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(request.ArtifactId) || string.IsNullOrWhiteSpace(request.EnvironmentId))
|
||||
{
|
||||
return Results.BadRequest(new { error = "artifact_id and environment_id are required." });
|
||||
}
|
||||
|
||||
var result = await evidenceBuilder.BuildAsync(request, cancellationToken).ConfigureAwait(false);
|
||||
if (result is null)
|
||||
{
|
||||
return Results.UnprocessableEntity(new { error = "Insufficient trace events or pipeline disabled." });
|
||||
}
|
||||
|
||||
if (result.RateLimited)
|
||||
{
|
||||
return Results.Ok(new { status = "rate_limited", artifact_id = request.ArtifactId, environment_id = request.EnvironmentId });
|
||||
}
|
||||
|
||||
return Results.Accepted($"/signals/execution-evidence/{request.ArtifactId}/{request.EnvironmentId}", result);
|
||||
}).WithName("SignalsExecutionEvidenceBuild");
|
||||
|
||||
// Beacon ingest endpoint (Sprint: SPRINT_20260219_014, BEA-02)
|
||||
signalsGroup.MapPost("/beacons", async Task<IResult> (
|
||||
HttpContext context,
|
||||
SignalsOptions options,
|
||||
BeaconIngestRequest request,
|
||||
IBeaconAttestationBuilder beaconBuilder,
|
||||
SignalsSealedModeMonitor sealedModeMonitor,
|
||||
CancellationToken cancellationToken) =>
|
||||
{
|
||||
if (!Program.TryAuthorize(context, SignalsPolicies.Write, options.Authority.AllowAnonymousFallback, out var authFailure))
|
||||
{
|
||||
return authFailure ?? Results.Unauthorized();
|
||||
}
|
||||
|
||||
if (!Program.TryEnsureSealedMode(sealedModeMonitor, out var sealedFailure))
|
||||
{
|
||||
return sealedFailure ?? Results.StatusCode(StatusCodes.Status503ServiceUnavailable);
|
||||
}
|
||||
|
||||
if (request.Events is null || request.Events.Count == 0)
|
||||
{
|
||||
return Results.BadRequest(new { error = "At least one beacon event is required." });
|
||||
}
|
||||
|
||||
var response = await beaconBuilder.IngestAsync(request, cancellationToken).ConfigureAwait(false);
|
||||
return Results.Accepted("/signals/beacons", response);
|
||||
}).WithName("SignalsBeaconIngest");
|
||||
|
||||
// Beacon verification rate query (Sprint: SPRINT_20260219_014, BEA-03)
|
||||
signalsGroup.MapGet("/beacons/rate/{artifactId}/{environmentId}", (
|
||||
HttpContext context,
|
||||
SignalsOptions options,
|
||||
string artifactId,
|
||||
string environmentId,
|
||||
IBeaconAttestationBuilder beaconBuilder,
|
||||
SignalsSealedModeMonitor sealedModeMonitor) =>
|
||||
{
|
||||
if (!Program.TryAuthorize(context, SignalsPolicies.Read, options.Authority.AllowAnonymousFallback, out var authFailure))
|
||||
{
|
||||
return authFailure ?? Results.Unauthorized();
|
||||
}
|
||||
|
||||
if (!Program.TryEnsureSealedMode(sealedModeMonitor, out var sealedFailure))
|
||||
{
|
||||
return sealedFailure ?? Results.StatusCode(StatusCodes.Status503ServiceUnavailable);
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(artifactId) || string.IsNullOrWhiteSpace(environmentId))
|
||||
{
|
||||
return Results.BadRequest(new { error = "artifactId and environmentId are required." });
|
||||
}
|
||||
|
||||
var rate = beaconBuilder.GetVerificationRate(artifactId.Trim(), environmentId.Trim());
|
||||
if (rate is null)
|
||||
{
|
||||
return Results.NotFound(new { error = "No beacon data for this artifact/environment pair." });
|
||||
}
|
||||
|
||||
return Results.Ok(rate);
|
||||
}).WithName("SignalsBeaconRateQuery");
|
||||
|
||||
signalsGroup.MapPost("/reachability/recompute", async Task<IResult> (
|
||||
HttpContext context,
|
||||
SignalsOptions options,
|
||||
|
||||
Reference in New Issue
Block a user