stela ops usage fixes roles propagation and timoeut, one account to support multi tenants, migrations consolidation, search to support documentation, doctor and open api vector db search

This commit is contained in:
master
2026-02-22 19:27:54 +02:00
parent a29f438f53
commit bd8fee6ed8
373 changed files with 832097 additions and 3369 deletions

View File

@@ -7,6 +7,7 @@ using Microsoft.AspNetCore.Mvc.Testing;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Npgsql;
using StellaOps.Platform.WebService.Options;
using StellaOps.Platform.WebService.Contracts;
using StellaOps.Platform.WebService.Services;
using StellaOps.TestKit;
@@ -89,7 +90,7 @@ public sealed class AnalyticsEndpointsSuccessTests : IClassFixture<PlatformWebAp
Assert.Equal("stage", response.Items[0].Environment);
}
private WebApplicationFactory<Program> CreateFactory(IPlatformAnalyticsQueryExecutor executor)
private WebApplicationFactory<PlatformServiceOptions> CreateFactory(IPlatformAnalyticsQueryExecutor executor)
{
return factory.WithWebHostBuilder(builder =>
{

View File

@@ -0,0 +1,142 @@
using System;
using System.Linq;
using System.Net;
using System.Net.Http.Json;
using System.Text.Json;
using Microsoft.AspNetCore.Mvc;
using StellaOps.TestKit;
using Xunit;
namespace StellaOps.Platform.WebService.Tests;
public sealed class MigrationAdminEndpointsTests : IClassFixture<PlatformWebApplicationFactory>
{
private static readonly string[] ExpectedModules =
[
"AirGap",
"Authority",
"Concelier",
"Excititor",
"Notify",
"Platform",
"Policy",
"Scanner",
"Scheduler",
"TimelineIndexer"
];
private readonly PlatformWebApplicationFactory _factory;
public MigrationAdminEndpointsTests(PlatformWebApplicationFactory factory)
{
_factory = factory;
}
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task Modules_Returns_Deterministic_PlatformRegistrySet()
{
using var client = _factory.CreateClient();
client.DefaultRequestHeaders.Add("X-StellaOps-Tenant", $"tenant-migration-modules-{Guid.NewGuid():N}");
client.DefaultRequestHeaders.Add("X-StellaOps-Actor", "migration-admin-tester");
var response = await client.GetAsync(
"/api/v1/admin/migrations/modules",
TestContext.Current.CancellationToken);
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
using var document = JsonDocument.Parse(
await response.Content.ReadAsStringAsync(TestContext.Current.CancellationToken));
var modules = document.RootElement
.GetProperty("modules")
.EnumerateArray()
.Select(static element => element.GetString())
.Where(static element => element is not null)
.Cast<string>()
.ToArray();
Assert.Equal(ExpectedModules, modules);
}
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task Status_WhenModuleUnknown_ReturnsBadRequestProblem()
{
using var client = _factory.CreateClient();
client.DefaultRequestHeaders.Add("X-StellaOps-Tenant", $"tenant-migration-status-unknown-{Guid.NewGuid():N}");
client.DefaultRequestHeaders.Add("X-StellaOps-Actor", "migration-admin-tester");
var response = await client.GetAsync(
"/api/v1/admin/migrations/status?module=unknown-module",
TestContext.Current.CancellationToken);
Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode);
var problem = await response.Content.ReadFromJsonAsync<ProblemDetails>(
TestContext.Current.CancellationToken);
Assert.NotNull(problem);
Assert.Equal("Invalid module filter", problem!.Title);
}
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task Status_WhenConnectionMissing_ReturnsServiceUnavailableProblem()
{
using var client = _factory.CreateClient();
client.DefaultRequestHeaders.Add("X-StellaOps-Tenant", $"tenant-migration-status-missing-{Guid.NewGuid():N}");
client.DefaultRequestHeaders.Add("X-StellaOps-Actor", "migration-admin-tester");
var response = await client.GetAsync(
"/api/v1/admin/migrations/status?module=all",
TestContext.Current.CancellationToken);
Assert.Equal(HttpStatusCode.ServiceUnavailable, response.StatusCode);
var problem = await response.Content.ReadFromJsonAsync<ProblemDetails>(
TestContext.Current.CancellationToken);
Assert.NotNull(problem);
Assert.Equal("Database connection unavailable", problem!.Title);
}
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task Verify_WhenConnectionMissing_ReturnsServiceUnavailableProblem()
{
using var client = _factory.CreateClient();
client.DefaultRequestHeaders.Add("X-StellaOps-Tenant", $"tenant-migration-verify-missing-{Guid.NewGuid():N}");
client.DefaultRequestHeaders.Add("X-StellaOps-Actor", "migration-admin-tester");
var response = await client.GetAsync(
"/api/v1/admin/migrations/verify?module=all",
TestContext.Current.CancellationToken);
Assert.Equal(HttpStatusCode.ServiceUnavailable, response.StatusCode);
var problem = await response.Content.ReadFromJsonAsync<ProblemDetails>(
TestContext.Current.CancellationToken);
Assert.NotNull(problem);
Assert.Equal("Database connection unavailable", problem!.Title);
}
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task Run_ReleaseWithoutForceAndDryRun_ReturnsBadRequestProblem()
{
using var client = _factory.CreateClient();
client.DefaultRequestHeaders.Add("X-StellaOps-Tenant", $"tenant-migration-run-release-{Guid.NewGuid():N}");
client.DefaultRequestHeaders.Add("X-StellaOps-Actor", "migration-admin-tester");
var response = await client.PostAsJsonAsync(
"/api/v1/admin/migrations/run",
new { module = "all", category = "release", dryRun = false, force = false },
TestContext.Current.CancellationToken);
Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode);
var problem = await response.Content.ReadFromJsonAsync<ProblemDetails>(
TestContext.Current.CancellationToken);
Assert.NotNull(problem);
Assert.Equal("Release migration approval required", problem!.Title);
}
}

View File

@@ -10,10 +10,11 @@ using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using StellaOps.Platform.WebService.Options;
namespace StellaOps.Platform.WebService.Tests;
public sealed class PlatformWebApplicationFactory : WebApplicationFactory<Program>
public sealed class PlatformWebApplicationFactory : WebApplicationFactory<PlatformServiceOptions>
{
protected override void ConfigureWebHost(IWebHostBuilder builder)
{

View File

@@ -14,6 +14,7 @@ using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using StellaOps.Platform.WebService.Options;
using StellaOps.TestKit;
using Xunit;
@@ -54,7 +55,7 @@ public sealed class SeedEndpointsTests : IClassFixture<PlatformWebApplicationFac
[Fact]
public async Task SeedDemo_WhenModuleFilterMixesAllAndSpecific_ReturnsBadRequestProblem()
{
using WebApplicationFactory<Program> enabledFactory = _factory.WithWebHostBuilder(builder =>
using WebApplicationFactory<PlatformServiceOptions> enabledFactory = _factory.WithWebHostBuilder(builder =>
{
builder.ConfigureAppConfiguration((_, config) =>
{
@@ -91,7 +92,7 @@ public sealed class SeedEndpointsTests : IClassFixture<PlatformWebApplicationFac
[Fact]
public async Task SeedDemo_WhenConnectionMissing_ReturnsServiceUnavailableProblem()
{
using WebApplicationFactory<Program> enabledFactory = _factory.WithWebHostBuilder(builder =>
using WebApplicationFactory<PlatformServiceOptions> enabledFactory = _factory.WithWebHostBuilder(builder =>
{
builder.ConfigureAppConfiguration((_, config) =>
{
@@ -124,7 +125,7 @@ public sealed class SeedEndpointsTests : IClassFixture<PlatformWebApplicationFac
[Fact]
public async Task SeedDemo_WhenUnauthenticated_ReturnsUnauthorized()
{
using WebApplicationFactory<Program> unauthenticatedFactory = _factory.WithWebHostBuilder(builder =>
using WebApplicationFactory<PlatformServiceOptions> unauthenticatedFactory = _factory.WithWebHostBuilder(builder =>
{
builder.ConfigureTestServices(services =>
{
@@ -157,7 +158,7 @@ public sealed class SeedEndpointsTests : IClassFixture<PlatformWebApplicationFac
[Fact]
public async Task SeedDemo_WhenAuthorizationFails_ReturnsForbidden()
{
using WebApplicationFactory<Program> forbiddenFactory = _factory.WithWebHostBuilder(builder =>
using WebApplicationFactory<PlatformServiceOptions> forbiddenFactory = _factory.WithWebHostBuilder(builder =>
{
builder.ConfigureTestServices(services =>
{

View File

@@ -5,6 +5,7 @@ Source of truth: `docs-archived/implplan/2025-12-29-csproj-audit/SPRINT_20251229
| Task ID | Status | Notes |
| --- | --- | --- |
| SPRINT_20260222_051-MGC-12-T | DONE | Added `MigrationAdminEndpointsTests` covering module registry listing, module-filter validation, release-force guard, and no-connection service-unavailable responses for `/api/v1/admin/migrations/*`. |
| PACK-ADM-01-T | DONE | Added/verified `PackAdapterEndpointsTests` coverage for `/api/v1/administration/{summary,identity-access,tenant-branding,notifications,usage-limits,policy-governance,trust-signing,system}` and deterministic alias ordering assertions. |
| PACK-ADM-02-T | DONE | Added `AdministrationTrustSigningMutationEndpointsTests` covering trust-owner key/issuer/certificate/transparency lifecycle plus route metadata policy bindings for `platform.trust.read`, `platform.trust.write`, and `platform.trust.admin`. |
| B22-01-T | DONE | Sprint `docs/implplan/SPRINT_20260220_018_Platform_pack22_backend_contracts_and_migrations.md`: added `ContextEndpointsTests` + `ContextMigrationScriptTests` for `/api/v2/context/*` deterministic ordering, preference round-trip behavior, and migration `047` coverage. |