tenant fixes

This commit is contained in:
master
2026-02-23 23:44:50 +02:00
parent bdb1438654
commit 4f947a8b61
159 changed files with 1064 additions and 556 deletions

View File

@@ -10,6 +10,7 @@ using StellaOps.AdvisoryAI.Attestation;
using StellaOps.AdvisoryAI.Attestation.Models;
using StellaOps.AdvisoryAI.Attestation.Storage;
using StellaOps.AdvisoryAI.WebService.Security;
using StellaOps.Auth.ServerIntegration.Tenancy;
namespace StellaOps.AdvisoryAI.WebService.Endpoints;
@@ -34,7 +35,8 @@ public static class AttestationEndpoints
.Produces(StatusCodes.Status404NotFound)
.Produces(StatusCodes.Status401Unauthorized)
.RequireAuthorization(AdvisoryAIPolicies.ViewPolicy)
.RequireRateLimiting("advisory-ai");
.RequireRateLimiting("advisory-ai")
.RequireTenant();
// GET /v1/advisory-ai/runs/{runId}/claims
app.MapGet("/v1/advisory-ai/runs/{runId}/claims", HandleGetRunClaims)
@@ -46,7 +48,8 @@ public static class AttestationEndpoints
.Produces(StatusCodes.Status404NotFound)
.Produces(StatusCodes.Status401Unauthorized)
.RequireAuthorization(AdvisoryAIPolicies.ViewPolicy)
.RequireRateLimiting("advisory-ai");
.RequireRateLimiting("advisory-ai")
.RequireTenant();
// GET /v1/advisory-ai/attestations/recent
app.MapGet("/v1/advisory-ai/attestations/recent", HandleListRecentAttestations)
@@ -57,7 +60,8 @@ public static class AttestationEndpoints
.Produces<RecentAttestationsResponse>(StatusCodes.Status200OK)
.Produces(StatusCodes.Status401Unauthorized)
.RequireAuthorization(AdvisoryAIPolicies.ViewPolicy)
.RequireRateLimiting("advisory-ai");
.RequireRateLimiting("advisory-ai")
.RequireTenant();
// POST /v1/advisory-ai/attestations/verify
app.MapPost("/v1/advisory-ai/attestations/verify", HandleVerifyAttestation)
@@ -69,7 +73,8 @@ public static class AttestationEndpoints
.Produces<AttestationVerificationResponse>(StatusCodes.Status400BadRequest)
.Produces(StatusCodes.Status401Unauthorized)
.RequireAuthorization(AdvisoryAIPolicies.ViewPolicy)
.RequireRateLimiting("advisory-ai");
.RequireRateLimiting("advisory-ai")
.RequireTenant();
}
private static async Task<IResult> HandleGetRunAttestation(

View File

@@ -18,6 +18,7 @@ using StellaOps.AdvisoryAI.Chat.Services;
using StellaOps.AdvisoryAI.Chat.Settings;
using StellaOps.AdvisoryAI.WebService.Contracts;
using StellaOps.AdvisoryAI.WebService.Security;
using StellaOps.Auth.ServerIntegration.Tenancy;
using System.Collections.Immutable;
using System.Runtime.CompilerServices;
using System.Text.Json;
@@ -45,7 +46,8 @@ public static class ChatEndpoints
{
var group = builder.MapGroup("/api/v1/chat")
.WithTags("Advisory Chat")
.RequireAuthorization(AdvisoryAIPolicies.OperatePolicy);
.RequireAuthorization(AdvisoryAIPolicies.OperatePolicy)
.RequireTenant();
// Single query endpoint (non-streaming)
group.MapPost("/query", ProcessQueryAsync)

View File

@@ -7,6 +7,7 @@ using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Routing;
using StellaOps.AdvisoryAI.WebService.Security;
using StellaOps.Auth.ServerIntegration.Tenancy;
using StellaOps.Determinism;
using StellaOps.Evidence.Pack;
using StellaOps.Evidence.Pack.Models;
@@ -35,7 +36,8 @@ public static class EvidencePackEndpoints
.Produces(StatusCodes.Status400BadRequest)
.Produces(StatusCodes.Status401Unauthorized)
.RequireAuthorization(AdvisoryAIPolicies.OperatePolicy)
.RequireRateLimiting("advisory-ai");
.RequireRateLimiting("advisory-ai")
.RequireTenant();
// GET /v1/evidence-packs/{packId} - Get Evidence Pack
app.MapGet("/v1/evidence-packs/{packId}", HandleGetEvidencePack)
@@ -47,7 +49,8 @@ public static class EvidencePackEndpoints
.Produces(StatusCodes.Status404NotFound)
.Produces(StatusCodes.Status401Unauthorized)
.RequireAuthorization(AdvisoryAIPolicies.ViewPolicy)
.RequireRateLimiting("advisory-ai");
.RequireRateLimiting("advisory-ai")
.RequireTenant();
// POST /v1/evidence-packs/{packId}/sign - Sign Evidence Pack
app.MapPost("/v1/evidence-packs/{packId}/sign", HandleSignEvidencePack)
@@ -59,7 +62,8 @@ public static class EvidencePackEndpoints
.Produces(StatusCodes.Status404NotFound)
.Produces(StatusCodes.Status401Unauthorized)
.RequireAuthorization(AdvisoryAIPolicies.OperatePolicy)
.RequireRateLimiting("advisory-ai");
.RequireRateLimiting("advisory-ai")
.RequireTenant();
// POST /v1/evidence-packs/{packId}/verify - Verify Evidence Pack
app.MapPost("/v1/evidence-packs/{packId}/verify", HandleVerifyEvidencePack)
@@ -71,7 +75,8 @@ public static class EvidencePackEndpoints
.Produces(StatusCodes.Status404NotFound)
.Produces(StatusCodes.Status401Unauthorized)
.RequireAuthorization(AdvisoryAIPolicies.ViewPolicy)
.RequireRateLimiting("advisory-ai");
.RequireRateLimiting("advisory-ai")
.RequireTenant();
// GET /v1/evidence-packs/{packId}/export - Export Evidence Pack
app.MapGet("/v1/evidence-packs/{packId}/export", HandleExportEvidencePack)
@@ -83,7 +88,8 @@ public static class EvidencePackEndpoints
.Produces(StatusCodes.Status404NotFound)
.Produces(StatusCodes.Status401Unauthorized)
.RequireAuthorization(AdvisoryAIPolicies.ViewPolicy)
.RequireRateLimiting("advisory-ai");
.RequireRateLimiting("advisory-ai")
.RequireTenant();
// GET /v1/runs/{runId}/evidence-packs - List Evidence Packs for Run
app.MapGet("/v1/runs/{runId}/evidence-packs", HandleListRunEvidencePacks)
@@ -94,7 +100,8 @@ public static class EvidencePackEndpoints
.Produces<EvidencePackListResponse>(StatusCodes.Status200OK)
.Produces(StatusCodes.Status401Unauthorized)
.RequireAuthorization(AdvisoryAIPolicies.ViewPolicy)
.RequireRateLimiting("advisory-ai");
.RequireRateLimiting("advisory-ai")
.RequireTenant();
// GET /v1/evidence-packs - List Evidence Packs
app.MapGet("/v1/evidence-packs", HandleListEvidencePacks)
@@ -105,7 +112,8 @@ public static class EvidencePackEndpoints
.Produces<EvidencePackListResponse>(StatusCodes.Status200OK)
.Produces(StatusCodes.Status401Unauthorized)
.RequireAuthorization(AdvisoryAIPolicies.ViewPolicy)
.RequireRateLimiting("advisory-ai");
.RequireRateLimiting("advisory-ai")
.RequireTenant();
}
private static async Task<IResult> HandleCreateEvidencePack(

View File

@@ -3,6 +3,7 @@ using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Routing;
using StellaOps.AdvisoryAI.KnowledgeSearch;
using StellaOps.AdvisoryAI.WebService.Security;
using StellaOps.Auth.ServerIntegration.Tenancy;
namespace StellaOps.AdvisoryAI.WebService.Endpoints;
@@ -19,7 +20,8 @@ public static class KnowledgeSearchEndpoints
{
var group = builder.MapGroup("/v1/advisory-ai")
.WithTags("Advisory AI - Knowledge Search")
.RequireAuthorization(AdvisoryAIPolicies.ViewPolicy);
.RequireAuthorization(AdvisoryAIPolicies.ViewPolicy)
.RequireTenant();
group.MapPost("/search", SearchAsync)
.WithName("AdvisoryAiKnowledgeSearch")

View File

@@ -5,6 +5,7 @@ using Microsoft.AspNetCore.Routing;
using StellaOps.AdvisoryAI.Inference.LlmProviders;
using StellaOps.AdvisoryAI.Plugin.Unified;
using StellaOps.AdvisoryAI.WebService.Security;
using StellaOps.Auth.ServerIntegration.Tenancy;
using StellaOps.Plugin.Abstractions.Capabilities;
using System.Security.Cryptography;
using System.Text;
@@ -29,7 +30,8 @@ public static class LlmAdapterEndpoints
{
var group = builder.MapGroup("/v1/advisory-ai/adapters")
.WithTags("Advisory AI - LLM Adapters")
.RequireAuthorization(AdvisoryAIPolicies.ViewPolicy);
.RequireAuthorization(AdvisoryAIPolicies.ViewPolicy)
.RequireTenant();
group.MapGet("/llm/providers", ListProvidersAsync)
.WithName("ListLlmProviders")

View File

@@ -9,6 +9,7 @@ using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Routing;
using StellaOps.AdvisoryAI.Runs;
using StellaOps.AdvisoryAI.WebService.Security;
using StellaOps.Auth.ServerIntegration.Tenancy;
using StellaOps.Determinism;
using System.Collections.Immutable;
@@ -29,7 +30,8 @@ public static class RunEndpoints
{
var group = builder.MapGroup("/api/v1/runs")
.WithTags("Runs")
.RequireAuthorization(AdvisoryAIPolicies.ViewPolicy);
.RequireAuthorization(AdvisoryAIPolicies.ViewPolicy)
.RequireTenant();
group.MapPost("/", CreateRunAsync)
.WithName("CreateRun")

View File

@@ -29,6 +29,7 @@ using StellaOps.AdvisoryAI.WebService.Services;
using StellaOps.Auth.Abstractions;
using StellaOps.Evidence.Pack;
using StellaOps.Auth.ServerIntegration;
using StellaOps.Auth.ServerIntegration.Tenancy;
using StellaOps.Router.AspNet;
using System.Collections.Immutable;
using System.Diagnostics;
@@ -103,6 +104,7 @@ var routerEnabled = builder.Services.AddRouterMicroservice(
version: System.Reflection.CustomAttributeExtensions.GetCustomAttribute<System.Reflection.AssemblyInformationalVersionAttribute>(System.Reflection.Assembly.GetExecutingAssembly())?.InformationalVersion ?? "1.0.0",
routerOptionsSection: "Router");
builder.Services.AddStellaOpsTenantServices();
builder.Services.AddStellaOpsCors(builder.Environment, builder.Configuration);
builder.Services.AddRateLimiter(options =>
@@ -145,6 +147,7 @@ if (app.Environment.IsDevelopment())
app.UseStellaOpsCors();
app.UseAuthorization();
app.UseStellaOpsTenantMiddleware();
app.UseRateLimiter();
app.TryUseStellaRouter(routerEnabled);

View File

@@ -41,6 +41,7 @@ public sealed class CompanionExplainEndpointTests
using var client = factory.CreateClient();
client.DefaultRequestHeaders.Add("X-StellaOps-Client", "companion-tests");
client.DefaultRequestHeaders.Add("X-StellaOps-Scopes", "advisory:companion");
client.DefaultRequestHeaders.Add("X-StellaOps-Tenant", "test-tenant");
var request = new CompanionExplainRequest
{
@@ -84,6 +85,7 @@ public sealed class CompanionExplainEndpointTests
using var client = factory.CreateClient();
client.DefaultRequestHeaders.Add("X-StellaOps-Client", "companion-tests");
client.DefaultRequestHeaders.Add("X-StellaOps-Scopes", "advisory:companion");
client.DefaultRequestHeaders.Add("X-StellaOps-Tenant", "test-tenant");
var request = new CompanionExplainRequest
{

View File

@@ -49,6 +49,7 @@ public sealed class KnowledgeSearchEndpointsIntegrationTests : IDisposable
{
using var client = _factory.CreateClient();
client.DefaultRequestHeaders.Add("X-StellaOps-Scopes", "advisory:search");
client.DefaultRequestHeaders.Add("X-StellaOps-Tenant", "test-tenant");
var response = await client.PostAsJsonAsync("/v1/advisory-ai/search", new AdvisoryKnowledgeSearchRequest
{
@@ -75,6 +76,7 @@ public sealed class KnowledgeSearchEndpointsIntegrationTests : IDisposable
{
using var client = _factory.CreateClient();
client.DefaultRequestHeaders.Add("X-StellaOps-Scopes", "advisory:index:write");
client.DefaultRequestHeaders.Add("X-StellaOps-Tenant", "test-tenant");
var response = await client.PostAsync("/v1/advisory-ai/index/rebuild", content: null);
response.StatusCode.Should().Be(HttpStatusCode.OK);

View File

@@ -40,6 +40,7 @@ public sealed class LlmAdapterEndpointsIntegrationTests
{
using var client = _factory.CreateClient();
client.DefaultRequestHeaders.Add("X-StellaOps-Scopes", "advisory:adapter:read");
client.DefaultRequestHeaders.Add("X-StellaOps-Tenant", "test-tenant");
var response = await client.GetAsync("/v1/advisory-ai/adapters/llm/providers");
response.StatusCode.Should().Be(HttpStatusCode.OK);
@@ -57,6 +58,7 @@ public sealed class LlmAdapterEndpointsIntegrationTests
{
using var client = _factory.CreateClient();
client.DefaultRequestHeaders.Add("X-StellaOps-Scopes", "advisory:adapter:invoke");
client.DefaultRequestHeaders.Add("X-StellaOps-Tenant", "test-tenant");
var request = new OpenAiChatCompletionRequest
{