part #2
This commit is contained in:
@@ -9,8 +9,10 @@ using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Routing;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
using StellaOps.Platform.WebService.Constants;
|
||||
using StellaOps.Platform.WebService.Contracts;
|
||||
using StellaOps.Platform.WebService.Options;
|
||||
using StellaOps.Platform.WebService.Services;
|
||||
using System;
|
||||
using System.Threading;
|
||||
@@ -20,6 +22,9 @@ namespace StellaOps.Platform.WebService.Endpoints;
|
||||
|
||||
/// <summary>
|
||||
/// Setup wizard API endpoints aligned to docs/setup/setup-wizard-ux.md.
|
||||
/// All endpoints are AllowAnonymous because during initial setup the Authority
|
||||
/// service is not running. When setup is already complete, the handlers
|
||||
/// enforce auth via TryResolveContext before proceeding.
|
||||
/// </summary>
|
||||
public static class SetupEndpoints
|
||||
{
|
||||
@@ -35,6 +40,41 @@ public static class SetupEndpoints
|
||||
return app;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resolves the request context, falling back to a bootstrap context during initial setup.
|
||||
/// When setup is complete, requires authenticated context (returns error on failure).
|
||||
/// </summary>
|
||||
private static async Task<(PlatformRequestContext Context, IResult? Failure)> ResolveSetupContextAsync(
|
||||
HttpContext httpContext,
|
||||
PlatformRequestContextResolver resolver,
|
||||
SetupStateDetector setupDetector,
|
||||
IOptions<PlatformServiceOptions> options,
|
||||
IEnvironmentSettingsStore envSettingsStore,
|
||||
CancellationToken ct)
|
||||
{
|
||||
var dbSettings = await envSettingsStore.GetAllAsync(ct);
|
||||
var setupState = setupDetector.Detect(options.Value.Storage, dbSettings);
|
||||
|
||||
if (setupState == "complete")
|
||||
{
|
||||
// Setup already done — require auth for re-configuration
|
||||
if (!TryResolveContext(httpContext, resolver, out var authContext, out var failure))
|
||||
{
|
||||
return (null!, failure);
|
||||
}
|
||||
return (authContext!, null);
|
||||
}
|
||||
|
||||
// During initial setup, resolve context best-effort
|
||||
if (!resolver.TryResolve(httpContext, out var requestContext, out _))
|
||||
{
|
||||
// No tenant/auth available — use bootstrap context
|
||||
requestContext = new PlatformRequestContext("setup", "setup-wizard", null);
|
||||
}
|
||||
|
||||
return (requestContext!, null);
|
||||
}
|
||||
|
||||
private static void MapSessionEndpoints(IEndpointRouteBuilder setup)
|
||||
{
|
||||
var sessions = setup.MapGroup("/sessions").WithTags("Setup Sessions");
|
||||
@@ -44,16 +84,18 @@ public static class SetupEndpoints
|
||||
HttpContext context,
|
||||
PlatformRequestContextResolver resolver,
|
||||
PlatformSetupService service,
|
||||
SetupStateDetector setupDetector,
|
||||
IOptions<PlatformServiceOptions> options,
|
||||
IEnvironmentSettingsStore envSettingsStore,
|
||||
CancellationToken ct) =>
|
||||
{
|
||||
if (!TryResolveContext(context, resolver, out var requestContext, out var failure))
|
||||
{
|
||||
return failure!;
|
||||
}
|
||||
var (requestContext, failure) = await ResolveSetupContextAsync(
|
||||
context, resolver, setupDetector, options, envSettingsStore, ct);
|
||||
if (failure is not null) return failure;
|
||||
|
||||
try
|
||||
{
|
||||
var result = await service.GetSessionAsync(requestContext!, ct).ConfigureAwait(false);
|
||||
var result = await service.GetSessionAsync(requestContext, ct).ConfigureAwait(false);
|
||||
if (result is null)
|
||||
{
|
||||
return Results.NotFound(CreateProblem(
|
||||
@@ -67,7 +109,7 @@ public static class SetupEndpoints
|
||||
{
|
||||
return Results.BadRequest(CreateProblem("Invalid Operation", ex.Message, StatusCodes.Status400BadRequest));
|
||||
}
|
||||
}).RequireAuthorization(PlatformPolicies.SetupRead)
|
||||
}).AllowAnonymous()
|
||||
.WithName("GetSetupSession")
|
||||
.Produces<SetupSessionResponse>(StatusCodes.Status200OK)
|
||||
.Produces<ProblemDetails>(StatusCodes.Status404NotFound);
|
||||
@@ -77,18 +119,20 @@ public static class SetupEndpoints
|
||||
HttpContext context,
|
||||
PlatformRequestContextResolver resolver,
|
||||
PlatformSetupService service,
|
||||
SetupStateDetector setupDetector,
|
||||
IOptions<PlatformServiceOptions> options,
|
||||
IEnvironmentSettingsStore envSettingsStore,
|
||||
[FromBody] CreateSetupSessionRequest? request,
|
||||
CancellationToken ct) =>
|
||||
{
|
||||
if (!TryResolveContext(context, resolver, out var requestContext, out var failure))
|
||||
{
|
||||
return failure!;
|
||||
}
|
||||
var (requestContext, failure) = await ResolveSetupContextAsync(
|
||||
context, resolver, setupDetector, options, envSettingsStore, ct);
|
||||
if (failure is not null) return failure;
|
||||
|
||||
try
|
||||
{
|
||||
var result = await service.CreateSessionAsync(
|
||||
requestContext!,
|
||||
requestContext,
|
||||
request ?? new CreateSetupSessionRequest(),
|
||||
ct).ConfigureAwait(false);
|
||||
return Results.Created($"/api/v1/setup/sessions", result);
|
||||
@@ -97,7 +141,7 @@ public static class SetupEndpoints
|
||||
{
|
||||
return Results.BadRequest(CreateProblem("Invalid Operation", ex.Message, StatusCodes.Status400BadRequest));
|
||||
}
|
||||
}).RequireAuthorization(PlatformPolicies.SetupWrite)
|
||||
}).AllowAnonymous()
|
||||
.WithName("CreateSetupSession")
|
||||
.Produces<SetupSessionResponse>(StatusCodes.Status201Created)
|
||||
.Produces<ProblemDetails>(StatusCodes.Status400BadRequest);
|
||||
@@ -107,23 +151,25 @@ public static class SetupEndpoints
|
||||
HttpContext context,
|
||||
PlatformRequestContextResolver resolver,
|
||||
PlatformSetupService service,
|
||||
SetupStateDetector setupDetector,
|
||||
IOptions<PlatformServiceOptions> options,
|
||||
IEnvironmentSettingsStore envSettingsStore,
|
||||
CancellationToken ct) =>
|
||||
{
|
||||
if (!TryResolveContext(context, resolver, out var requestContext, out var failure))
|
||||
{
|
||||
return failure!;
|
||||
}
|
||||
var (requestContext, failure) = await ResolveSetupContextAsync(
|
||||
context, resolver, setupDetector, options, envSettingsStore, ct);
|
||||
if (failure is not null) return failure;
|
||||
|
||||
try
|
||||
{
|
||||
var result = await service.ResumeOrCreateSessionAsync(requestContext!, ct).ConfigureAwait(false);
|
||||
var result = await service.ResumeOrCreateSessionAsync(requestContext, ct).ConfigureAwait(false);
|
||||
return Results.Ok(result);
|
||||
}
|
||||
catch (InvalidOperationException ex)
|
||||
{
|
||||
return Results.BadRequest(CreateProblem("Invalid Operation", ex.Message, StatusCodes.Status400BadRequest));
|
||||
}
|
||||
}).RequireAuthorization(PlatformPolicies.SetupWrite)
|
||||
}).AllowAnonymous()
|
||||
.WithName("ResumeSetupSession")
|
||||
.Produces<SetupSessionResponse>(StatusCodes.Status200OK)
|
||||
.Produces<ProblemDetails>(StatusCodes.Status400BadRequest);
|
||||
@@ -133,18 +179,20 @@ public static class SetupEndpoints
|
||||
HttpContext context,
|
||||
PlatformRequestContextResolver resolver,
|
||||
PlatformSetupService service,
|
||||
SetupStateDetector setupDetector,
|
||||
IOptions<PlatformServiceOptions> options,
|
||||
IEnvironmentSettingsStore envSettingsStore,
|
||||
[FromBody] FinalizeSetupSessionRequest? request,
|
||||
CancellationToken ct) =>
|
||||
{
|
||||
if (!TryResolveContext(context, resolver, out var requestContext, out var failure))
|
||||
{
|
||||
return failure!;
|
||||
}
|
||||
var (requestContext, failure) = await ResolveSetupContextAsync(
|
||||
context, resolver, setupDetector, options, envSettingsStore, ct);
|
||||
if (failure is not null) return failure;
|
||||
|
||||
try
|
||||
{
|
||||
var result = await service.FinalizeSessionAsync(
|
||||
requestContext!,
|
||||
requestContext,
|
||||
request ?? new FinalizeSetupSessionRequest(),
|
||||
ct).ConfigureAwait(false);
|
||||
return Results.Ok(result);
|
||||
@@ -153,7 +201,7 @@ public static class SetupEndpoints
|
||||
{
|
||||
return Results.BadRequest(CreateProblem("Invalid Operation", ex.Message, StatusCodes.Status400BadRequest));
|
||||
}
|
||||
}).RequireAuthorization(PlatformPolicies.SetupWrite)
|
||||
}).AllowAnonymous()
|
||||
.WithName("FinalizeSetupSession")
|
||||
.Produces<FinalizeSetupSessionResponse>(StatusCodes.Status200OK)
|
||||
.Produces<ProblemDetails>(StatusCodes.Status400BadRequest);
|
||||
@@ -168,13 +216,15 @@ public static class SetupEndpoints
|
||||
HttpContext context,
|
||||
PlatformRequestContextResolver resolver,
|
||||
PlatformSetupService service,
|
||||
SetupStateDetector setupDetector,
|
||||
IOptions<PlatformServiceOptions> options,
|
||||
IEnvironmentSettingsStore envSettingsStore,
|
||||
[FromBody] ExecuteSetupStepRequest request,
|
||||
CancellationToken ct) =>
|
||||
{
|
||||
if (!TryResolveContext(context, resolver, out var requestContext, out var failure))
|
||||
{
|
||||
return failure!;
|
||||
}
|
||||
var (requestContext, failure) = await ResolveSetupContextAsync(
|
||||
context, resolver, setupDetector, options, envSettingsStore, ct);
|
||||
if (failure is not null) return failure;
|
||||
|
||||
if (request is null)
|
||||
{
|
||||
@@ -186,14 +236,14 @@ public static class SetupEndpoints
|
||||
|
||||
try
|
||||
{
|
||||
var result = await service.ExecuteStepAsync(requestContext!, request, ct).ConfigureAwait(false);
|
||||
var result = await service.ExecuteStepAsync(requestContext, request, ct).ConfigureAwait(false);
|
||||
return Results.Ok(result);
|
||||
}
|
||||
catch (InvalidOperationException ex)
|
||||
{
|
||||
return Results.BadRequest(CreateProblem("Invalid Operation", ex.Message, StatusCodes.Status400BadRequest));
|
||||
}
|
||||
}).RequireAuthorization(PlatformPolicies.SetupWrite)
|
||||
}).AllowAnonymous()
|
||||
.WithName("ExecuteSetupStep")
|
||||
.Produces<ExecuteSetupStepResponse>(StatusCodes.Status200OK)
|
||||
.Produces<ProblemDetails>(StatusCodes.Status400BadRequest);
|
||||
@@ -203,13 +253,15 @@ public static class SetupEndpoints
|
||||
HttpContext context,
|
||||
PlatformRequestContextResolver resolver,
|
||||
PlatformSetupService service,
|
||||
SetupStateDetector setupDetector,
|
||||
IOptions<PlatformServiceOptions> options,
|
||||
IEnvironmentSettingsStore envSettingsStore,
|
||||
[FromBody] SkipSetupStepRequest request,
|
||||
CancellationToken ct) =>
|
||||
{
|
||||
if (!TryResolveContext(context, resolver, out var requestContext, out var failure))
|
||||
{
|
||||
return failure!;
|
||||
}
|
||||
var (requestContext, failure) = await ResolveSetupContextAsync(
|
||||
context, resolver, setupDetector, options, envSettingsStore, ct);
|
||||
if (failure is not null) return failure;
|
||||
|
||||
if (request is null)
|
||||
{
|
||||
@@ -221,14 +273,14 @@ public static class SetupEndpoints
|
||||
|
||||
try
|
||||
{
|
||||
var result = await service.SkipStepAsync(requestContext!, request, ct).ConfigureAwait(false);
|
||||
var result = await service.SkipStepAsync(requestContext, request, ct).ConfigureAwait(false);
|
||||
return Results.Ok(result);
|
||||
}
|
||||
catch (InvalidOperationException ex)
|
||||
{
|
||||
return Results.BadRequest(CreateProblem("Invalid Operation", ex.Message, StatusCodes.Status400BadRequest));
|
||||
}
|
||||
}).RequireAuthorization(PlatformPolicies.SetupWrite)
|
||||
}).AllowAnonymous()
|
||||
.WithName("SkipSetupStep")
|
||||
.Produces<SetupSessionResponse>(StatusCodes.Status200OK)
|
||||
.Produces<ProblemDetails>(StatusCodes.Status400BadRequest);
|
||||
@@ -240,19 +292,12 @@ public static class SetupEndpoints
|
||||
|
||||
// GET /api/v1/setup/definitions/steps - Get all step definitions
|
||||
definitions.MapGet("/steps", async Task<IResult> (
|
||||
HttpContext context,
|
||||
PlatformRequestContextResolver resolver,
|
||||
PlatformSetupService service,
|
||||
CancellationToken ct) =>
|
||||
{
|
||||
if (!TryResolveContext(context, resolver, out var requestContext, out var failure))
|
||||
{
|
||||
return failure!;
|
||||
}
|
||||
|
||||
var result = await service.GetStepDefinitionsAsync(ct).ConfigureAwait(false);
|
||||
return Results.Ok(result);
|
||||
}).RequireAuthorization(PlatformPolicies.SetupRead)
|
||||
}).AllowAnonymous()
|
||||
.WithName("GetSetupStepDefinitions")
|
||||
.Produces<SetupStepDefinitionsResponse>(StatusCodes.Status200OK);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user