ui progressing
This commit is contained in:
@@ -0,0 +1,557 @@
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Routing;
|
||||
using StellaOps.Platform.WebService.Constants;
|
||||
using StellaOps.Platform.WebService.Contracts;
|
||||
using StellaOps.Platform.WebService.Services;
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace StellaOps.Platform.WebService.Endpoints;
|
||||
|
||||
public static class LegacyAliasEndpoints
|
||||
{
|
||||
public static IEndpointRouteBuilder MapLegacyAliasEndpoints(this IEndpointRouteBuilder app)
|
||||
{
|
||||
var legacy = app.MapGroup("/api/v1")
|
||||
.WithTags("Pack22 Legacy Aliases");
|
||||
|
||||
legacy.MapGet("/context/regions", async Task<IResult>(
|
||||
HttpContext context,
|
||||
PlatformRequestContextResolver resolver,
|
||||
PlatformContextService service,
|
||||
CancellationToken cancellationToken) =>
|
||||
{
|
||||
if (!TryResolveContext(context, resolver, out _, out var failure))
|
||||
{
|
||||
return failure!;
|
||||
}
|
||||
|
||||
var regions = await service.GetRegionsAsync(cancellationToken).ConfigureAwait(false);
|
||||
return Results.Ok(regions);
|
||||
})
|
||||
.WithName("GetPlatformContextRegionsV1Alias")
|
||||
.WithSummary("Legacy alias for v2 context regions")
|
||||
.RequireAuthorization(PlatformPolicies.ContextRead);
|
||||
|
||||
legacy.MapGet("/releases", async Task<IResult>(
|
||||
HttpContext context,
|
||||
PlatformRequestContextResolver resolver,
|
||||
ReleaseReadModelService service,
|
||||
TimeProvider timeProvider,
|
||||
[AsParameters] LegacyReleaseListQuery query,
|
||||
CancellationToken cancellationToken) =>
|
||||
{
|
||||
if (!TryResolveContext(context, resolver, out var requestContext, out var failure))
|
||||
{
|
||||
return failure!;
|
||||
}
|
||||
|
||||
var page = await service.ListReleasesAsync(
|
||||
requestContext!,
|
||||
query.Region,
|
||||
query.Environment,
|
||||
query.Type,
|
||||
query.Status,
|
||||
query.Limit,
|
||||
query.Offset,
|
||||
cancellationToken).ConfigureAwait(false);
|
||||
|
||||
return Results.Ok(new PlatformListResponse<ReleaseProjection>(
|
||||
requestContext!.TenantId,
|
||||
requestContext.ActorId,
|
||||
timeProvider.GetUtcNow(),
|
||||
Cached: false,
|
||||
CacheTtlSeconds: 0,
|
||||
page.Items,
|
||||
page.Total,
|
||||
page.Limit,
|
||||
page.Offset));
|
||||
})
|
||||
.WithName("ListReleasesV1Alias")
|
||||
.WithSummary("Legacy alias for v2 releases projection")
|
||||
.RequireAuthorization(PlatformPolicies.ReleaseControlRead);
|
||||
|
||||
var runAliases = legacy.MapGroup("/releases/runs");
|
||||
|
||||
runAliases.MapGet(string.Empty, async Task<IResult>(
|
||||
HttpContext context,
|
||||
PlatformRequestContextResolver resolver,
|
||||
ReleaseReadModelService service,
|
||||
TimeProvider timeProvider,
|
||||
[AsParameters] LegacyRunListQuery query,
|
||||
CancellationToken cancellationToken) =>
|
||||
{
|
||||
if (!TryResolveContext(context, resolver, out var requestContext, out var failure))
|
||||
{
|
||||
return failure!;
|
||||
}
|
||||
|
||||
var page = await service.ListRunsAsync(
|
||||
requestContext!,
|
||||
query.Status,
|
||||
query.Lane,
|
||||
query.Environment,
|
||||
query.Region,
|
||||
query.Outcome,
|
||||
query.NeedsApproval,
|
||||
query.BlockedByDataIntegrity,
|
||||
query.Limit,
|
||||
query.Offset,
|
||||
cancellationToken).ConfigureAwait(false);
|
||||
|
||||
return Results.Ok(new PlatformListResponse<ReleaseRunProjection>(
|
||||
requestContext!.TenantId,
|
||||
requestContext.ActorId,
|
||||
timeProvider.GetUtcNow(),
|
||||
Cached: false,
|
||||
CacheTtlSeconds: 0,
|
||||
page.Items,
|
||||
page.Total,
|
||||
page.Limit,
|
||||
page.Offset));
|
||||
})
|
||||
.WithName("ListReleaseRunsV1Alias")
|
||||
.WithSummary("Legacy alias for v2 run list projection")
|
||||
.RequireAuthorization(PlatformPolicies.ReleaseControlRead);
|
||||
|
||||
runAliases.MapGet("/{runId:guid}", async Task<IResult>(
|
||||
HttpContext context,
|
||||
PlatformRequestContextResolver resolver,
|
||||
ReleaseReadModelService service,
|
||||
TimeProvider timeProvider,
|
||||
Guid runId,
|
||||
CancellationToken cancellationToken) =>
|
||||
{
|
||||
if (!TryResolveContext(context, resolver, out var requestContext, out var failure))
|
||||
{
|
||||
return failure!;
|
||||
}
|
||||
|
||||
var item = await service.GetRunDetailAsync(requestContext!, runId, cancellationToken).ConfigureAwait(false);
|
||||
return ToRunItemResponse(requestContext!, timeProvider, runId, item);
|
||||
})
|
||||
.WithName("GetReleaseRunDetailV1Alias")
|
||||
.WithSummary("Legacy alias for v2 run detail projection")
|
||||
.RequireAuthorization(PlatformPolicies.ReleaseControlRead);
|
||||
|
||||
runAliases.MapGet("/{runId:guid}/timeline", async Task<IResult>(
|
||||
HttpContext context,
|
||||
PlatformRequestContextResolver resolver,
|
||||
ReleaseReadModelService service,
|
||||
TimeProvider timeProvider,
|
||||
Guid runId,
|
||||
CancellationToken cancellationToken) =>
|
||||
{
|
||||
if (!TryResolveContext(context, resolver, out var requestContext, out var failure))
|
||||
{
|
||||
return failure!;
|
||||
}
|
||||
|
||||
var item = await service.GetRunTimelineAsync(requestContext!, runId, cancellationToken).ConfigureAwait(false);
|
||||
return ToRunItemResponse(requestContext!, timeProvider, runId, item);
|
||||
})
|
||||
.WithName("GetReleaseRunTimelineV1Alias")
|
||||
.WithSummary("Legacy alias for v2 run timeline projection")
|
||||
.RequireAuthorization(PlatformPolicies.ReleaseControlRead);
|
||||
|
||||
runAliases.MapGet("/{runId:guid}/gate-decision", async Task<IResult>(
|
||||
HttpContext context,
|
||||
PlatformRequestContextResolver resolver,
|
||||
ReleaseReadModelService service,
|
||||
TimeProvider timeProvider,
|
||||
Guid runId,
|
||||
CancellationToken cancellationToken) =>
|
||||
{
|
||||
if (!TryResolveContext(context, resolver, out var requestContext, out var failure))
|
||||
{
|
||||
return failure!;
|
||||
}
|
||||
|
||||
var item = await service.GetRunGateDecisionAsync(requestContext!, runId, cancellationToken).ConfigureAwait(false);
|
||||
return ToRunItemResponse(requestContext!, timeProvider, runId, item);
|
||||
})
|
||||
.WithName("GetReleaseRunGateDecisionV1Alias")
|
||||
.WithSummary("Legacy alias for v2 run gate decision projection")
|
||||
.RequireAuthorization(PlatformPolicies.ReleaseControlRead);
|
||||
|
||||
runAliases.MapGet("/{runId:guid}/approvals", async Task<IResult>(
|
||||
HttpContext context,
|
||||
PlatformRequestContextResolver resolver,
|
||||
ReleaseReadModelService service,
|
||||
TimeProvider timeProvider,
|
||||
Guid runId,
|
||||
CancellationToken cancellationToken) =>
|
||||
{
|
||||
if (!TryResolveContext(context, resolver, out var requestContext, out var failure))
|
||||
{
|
||||
return failure!;
|
||||
}
|
||||
|
||||
var item = await service.GetRunApprovalsAsync(requestContext!, runId, cancellationToken).ConfigureAwait(false);
|
||||
return ToRunItemResponse(requestContext!, timeProvider, runId, item);
|
||||
})
|
||||
.WithName("GetReleaseRunApprovalsV1Alias")
|
||||
.WithSummary("Legacy alias for v2 run approvals projection")
|
||||
.RequireAuthorization(PlatformPolicies.ReleaseControlRead);
|
||||
|
||||
runAliases.MapGet("/{runId:guid}/deployments", async Task<IResult>(
|
||||
HttpContext context,
|
||||
PlatformRequestContextResolver resolver,
|
||||
ReleaseReadModelService service,
|
||||
TimeProvider timeProvider,
|
||||
Guid runId,
|
||||
CancellationToken cancellationToken) =>
|
||||
{
|
||||
if (!TryResolveContext(context, resolver, out var requestContext, out var failure))
|
||||
{
|
||||
return failure!;
|
||||
}
|
||||
|
||||
var item = await service.GetRunDeploymentsAsync(requestContext!, runId, cancellationToken).ConfigureAwait(false);
|
||||
return ToRunItemResponse(requestContext!, timeProvider, runId, item);
|
||||
})
|
||||
.WithName("GetReleaseRunDeploymentsV1Alias")
|
||||
.WithSummary("Legacy alias for v2 run deployments projection")
|
||||
.RequireAuthorization(PlatformPolicies.ReleaseControlRead);
|
||||
|
||||
runAliases.MapGet("/{runId:guid}/security-inputs", async Task<IResult>(
|
||||
HttpContext context,
|
||||
PlatformRequestContextResolver resolver,
|
||||
ReleaseReadModelService service,
|
||||
TimeProvider timeProvider,
|
||||
Guid runId,
|
||||
CancellationToken cancellationToken) =>
|
||||
{
|
||||
if (!TryResolveContext(context, resolver, out var requestContext, out var failure))
|
||||
{
|
||||
return failure!;
|
||||
}
|
||||
|
||||
var item = await service.GetRunSecurityInputsAsync(requestContext!, runId, cancellationToken).ConfigureAwait(false);
|
||||
return ToRunItemResponse(requestContext!, timeProvider, runId, item);
|
||||
})
|
||||
.WithName("GetReleaseRunSecurityInputsV1Alias")
|
||||
.WithSummary("Legacy alias for v2 run security inputs projection")
|
||||
.RequireAuthorization(PlatformPolicies.ReleaseControlRead);
|
||||
|
||||
runAliases.MapGet("/{runId:guid}/evidence", async Task<IResult>(
|
||||
HttpContext context,
|
||||
PlatformRequestContextResolver resolver,
|
||||
ReleaseReadModelService service,
|
||||
TimeProvider timeProvider,
|
||||
Guid runId,
|
||||
CancellationToken cancellationToken) =>
|
||||
{
|
||||
if (!TryResolveContext(context, resolver, out var requestContext, out var failure))
|
||||
{
|
||||
return failure!;
|
||||
}
|
||||
|
||||
var item = await service.GetRunEvidenceAsync(requestContext!, runId, cancellationToken).ConfigureAwait(false);
|
||||
return ToRunItemResponse(requestContext!, timeProvider, runId, item);
|
||||
})
|
||||
.WithName("GetReleaseRunEvidenceV1Alias")
|
||||
.WithSummary("Legacy alias for v2 run evidence projection")
|
||||
.RequireAuthorization(PlatformPolicies.ReleaseControlRead);
|
||||
|
||||
runAliases.MapGet("/{runId:guid}/rollback", async Task<IResult>(
|
||||
HttpContext context,
|
||||
PlatformRequestContextResolver resolver,
|
||||
ReleaseReadModelService service,
|
||||
TimeProvider timeProvider,
|
||||
Guid runId,
|
||||
CancellationToken cancellationToken) =>
|
||||
{
|
||||
if (!TryResolveContext(context, resolver, out var requestContext, out var failure))
|
||||
{
|
||||
return failure!;
|
||||
}
|
||||
|
||||
var item = await service.GetRunRollbackAsync(requestContext!, runId, cancellationToken).ConfigureAwait(false);
|
||||
return ToRunItemResponse(requestContext!, timeProvider, runId, item);
|
||||
})
|
||||
.WithName("GetReleaseRunRollbackV1Alias")
|
||||
.WithSummary("Legacy alias for v2 run rollback projection")
|
||||
.RequireAuthorization(PlatformPolicies.ReleaseControlRead);
|
||||
|
||||
runAliases.MapGet("/{runId:guid}/replay", async Task<IResult>(
|
||||
HttpContext context,
|
||||
PlatformRequestContextResolver resolver,
|
||||
ReleaseReadModelService service,
|
||||
TimeProvider timeProvider,
|
||||
Guid runId,
|
||||
CancellationToken cancellationToken) =>
|
||||
{
|
||||
if (!TryResolveContext(context, resolver, out var requestContext, out var failure))
|
||||
{
|
||||
return failure!;
|
||||
}
|
||||
|
||||
var item = await service.GetRunReplayAsync(requestContext!, runId, cancellationToken).ConfigureAwait(false);
|
||||
return ToRunItemResponse(requestContext!, timeProvider, runId, item);
|
||||
})
|
||||
.WithName("GetReleaseRunReplayV1Alias")
|
||||
.WithSummary("Legacy alias for v2 run replay projection")
|
||||
.RequireAuthorization(PlatformPolicies.ReleaseControlRead);
|
||||
|
||||
runAliases.MapGet("/{runId:guid}/audit", async Task<IResult>(
|
||||
HttpContext context,
|
||||
PlatformRequestContextResolver resolver,
|
||||
ReleaseReadModelService service,
|
||||
TimeProvider timeProvider,
|
||||
Guid runId,
|
||||
CancellationToken cancellationToken) =>
|
||||
{
|
||||
if (!TryResolveContext(context, resolver, out var requestContext, out var failure))
|
||||
{
|
||||
return failure!;
|
||||
}
|
||||
|
||||
var item = await service.GetRunAuditAsync(requestContext!, runId, cancellationToken).ConfigureAwait(false);
|
||||
return ToRunItemResponse(requestContext!, timeProvider, runId, item);
|
||||
})
|
||||
.WithName("GetReleaseRunAuditV1Alias")
|
||||
.WithSummary("Legacy alias for v2 run audit projection")
|
||||
.RequireAuthorization(PlatformPolicies.ReleaseControlRead);
|
||||
|
||||
legacy.MapGet("/topology/regions", async Task<IResult>(
|
||||
HttpContext context,
|
||||
PlatformRequestContextResolver resolver,
|
||||
TopologyReadModelService service,
|
||||
TimeProvider timeProvider,
|
||||
[AsParameters] LegacyTopologyRegionQuery query,
|
||||
CancellationToken cancellationToken) =>
|
||||
{
|
||||
if (!TryResolveContext(context, resolver, out var requestContext, out var failure))
|
||||
{
|
||||
return failure!;
|
||||
}
|
||||
|
||||
var page = await service.ListRegionsAsync(
|
||||
requestContext!,
|
||||
query.Region,
|
||||
query.Environment,
|
||||
query.Limit,
|
||||
query.Offset,
|
||||
cancellationToken).ConfigureAwait(false);
|
||||
|
||||
return Results.Ok(new PlatformListResponse<TopologyRegionProjection>(
|
||||
requestContext!.TenantId,
|
||||
requestContext.ActorId,
|
||||
timeProvider.GetUtcNow(),
|
||||
Cached: false,
|
||||
CacheTtlSeconds: 0,
|
||||
page.Items,
|
||||
page.Total,
|
||||
page.Limit,
|
||||
page.Offset));
|
||||
})
|
||||
.WithName("ListTopologyRegionsV1Alias")
|
||||
.WithSummary("Legacy alias for v2 topology regions projection")
|
||||
.RequireAuthorization(PlatformPolicies.TopologyRead);
|
||||
|
||||
legacy.MapGet("/security/findings", async Task<IResult>(
|
||||
HttpContext context,
|
||||
PlatformRequestContextResolver resolver,
|
||||
SecurityReadModelService service,
|
||||
TimeProvider timeProvider,
|
||||
[AsParameters] LegacySecurityFindingsQuery query,
|
||||
CancellationToken cancellationToken) =>
|
||||
{
|
||||
if (!TryResolveContext(context, resolver, out var requestContext, out var failure))
|
||||
{
|
||||
return failure!;
|
||||
}
|
||||
|
||||
var page = await service.ListFindingsAsync(
|
||||
requestContext!,
|
||||
query.Pivot,
|
||||
query.Region,
|
||||
query.Environment,
|
||||
query.Severity,
|
||||
query.Disposition,
|
||||
query.Search,
|
||||
query.Limit,
|
||||
query.Offset,
|
||||
cancellationToken).ConfigureAwait(false);
|
||||
|
||||
return Results.Ok(new SecurityFindingsResponse(
|
||||
requestContext!.TenantId,
|
||||
requestContext.ActorId,
|
||||
timeProvider.GetUtcNow(),
|
||||
Cached: false,
|
||||
CacheTtlSeconds: 0,
|
||||
page.Items,
|
||||
page.Total,
|
||||
page.Limit,
|
||||
page.Offset,
|
||||
page.Pivot,
|
||||
page.PivotBuckets,
|
||||
page.Facets));
|
||||
})
|
||||
.WithName("ListSecurityFindingsV1Alias")
|
||||
.WithSummary("Legacy alias for v2 security findings projection")
|
||||
.RequireAuthorization(PlatformPolicies.SecurityRead);
|
||||
|
||||
legacy.MapGet("/integrations/feeds", async Task<IResult>(
|
||||
HttpContext context,
|
||||
PlatformRequestContextResolver resolver,
|
||||
IntegrationsReadModelService service,
|
||||
TimeProvider timeProvider,
|
||||
[AsParameters] LegacyIntegrationQuery query,
|
||||
CancellationToken cancellationToken) =>
|
||||
{
|
||||
if (!TryResolveContext(context, resolver, out var requestContext, out var failure))
|
||||
{
|
||||
return failure!;
|
||||
}
|
||||
|
||||
var page = await service.ListFeedsAsync(
|
||||
requestContext!,
|
||||
query.Region,
|
||||
query.Environment,
|
||||
query.Status,
|
||||
query.SourceType,
|
||||
query.Limit,
|
||||
query.Offset,
|
||||
cancellationToken).ConfigureAwait(false);
|
||||
|
||||
return Results.Ok(new PlatformListResponse<IntegrationFeedProjection>(
|
||||
requestContext!.TenantId,
|
||||
requestContext.ActorId,
|
||||
timeProvider.GetUtcNow(),
|
||||
Cached: false,
|
||||
CacheTtlSeconds: 0,
|
||||
page.Items,
|
||||
page.Total,
|
||||
page.Limit,
|
||||
page.Offset));
|
||||
})
|
||||
.WithName("ListIntegrationFeedsV1Alias")
|
||||
.WithSummary("Legacy alias for v2 integrations feed projection")
|
||||
.RequireAuthorization(PlatformPolicies.IntegrationsRead);
|
||||
|
||||
legacy.MapGet("/integrations/vex-sources", async Task<IResult>(
|
||||
HttpContext context,
|
||||
PlatformRequestContextResolver resolver,
|
||||
IntegrationsReadModelService service,
|
||||
TimeProvider timeProvider,
|
||||
[AsParameters] LegacyIntegrationQuery query,
|
||||
CancellationToken cancellationToken) =>
|
||||
{
|
||||
if (!TryResolveContext(context, resolver, out var requestContext, out var failure))
|
||||
{
|
||||
return failure!;
|
||||
}
|
||||
|
||||
var page = await service.ListVexSourcesAsync(
|
||||
requestContext!,
|
||||
query.Region,
|
||||
query.Environment,
|
||||
query.Status,
|
||||
query.SourceType,
|
||||
query.Limit,
|
||||
query.Offset,
|
||||
cancellationToken).ConfigureAwait(false);
|
||||
|
||||
return Results.Ok(new PlatformListResponse<IntegrationVexSourceProjection>(
|
||||
requestContext!.TenantId,
|
||||
requestContext.ActorId,
|
||||
timeProvider.GetUtcNow(),
|
||||
Cached: false,
|
||||
CacheTtlSeconds: 0,
|
||||
page.Items,
|
||||
page.Total,
|
||||
page.Limit,
|
||||
page.Offset));
|
||||
})
|
||||
.WithName("ListIntegrationVexSourcesV1Alias")
|
||||
.WithSummary("Legacy alias for v2 integrations VEX source projection")
|
||||
.RequireAuthorization(PlatformPolicies.IntegrationsVexRead);
|
||||
|
||||
return app;
|
||||
}
|
||||
|
||||
private static bool TryResolveContext(
|
||||
HttpContext context,
|
||||
PlatformRequestContextResolver resolver,
|
||||
out PlatformRequestContext? requestContext,
|
||||
out IResult? failure)
|
||||
{
|
||||
if (resolver.TryResolve(context, out requestContext, out var error))
|
||||
{
|
||||
failure = null;
|
||||
return true;
|
||||
}
|
||||
|
||||
failure = Results.BadRequest(new { error = error ?? "tenant_missing" });
|
||||
return false;
|
||||
}
|
||||
|
||||
private static IResult ToRunItemResponse<TProjection>(
|
||||
PlatformRequestContext requestContext,
|
||||
TimeProvider timeProvider,
|
||||
Guid runId,
|
||||
TProjection? projection)
|
||||
where TProjection : class
|
||||
{
|
||||
if (projection is null)
|
||||
{
|
||||
return Results.NotFound(new { error = "run_not_found", runId });
|
||||
}
|
||||
|
||||
return Results.Ok(new PlatformItemResponse<TProjection>(
|
||||
requestContext.TenantId,
|
||||
requestContext.ActorId,
|
||||
timeProvider.GetUtcNow(),
|
||||
Cached: false,
|
||||
CacheTtlSeconds: 0,
|
||||
projection));
|
||||
}
|
||||
|
||||
public sealed record LegacyReleaseListQuery(
|
||||
string? Region,
|
||||
string? Environment,
|
||||
string? Type,
|
||||
string? Status,
|
||||
int? Limit,
|
||||
int? Offset);
|
||||
|
||||
public sealed record LegacyRunListQuery(
|
||||
string? Status,
|
||||
string? Lane,
|
||||
string? Environment,
|
||||
string? Region,
|
||||
string? Outcome,
|
||||
bool? NeedsApproval,
|
||||
bool? BlockedByDataIntegrity,
|
||||
int? Limit,
|
||||
int? Offset);
|
||||
|
||||
public sealed record LegacyTopologyRegionQuery(
|
||||
string? Region,
|
||||
string? Environment,
|
||||
int? Limit,
|
||||
int? Offset);
|
||||
|
||||
public sealed record LegacySecurityFindingsQuery(
|
||||
string? Pivot,
|
||||
string? Region,
|
||||
string? Environment,
|
||||
string? Severity,
|
||||
string? Disposition,
|
||||
string? Search,
|
||||
int? Limit,
|
||||
int? Offset);
|
||||
|
||||
public sealed record LegacyIntegrationQuery(
|
||||
string? Region,
|
||||
string? Environment,
|
||||
string? Status,
|
||||
string? SourceType,
|
||||
int? Limit,
|
||||
int? Offset);
|
||||
}
|
||||
Reference in New Issue
Block a user