This commit is contained in:
master
2026-02-23 21:30:15 +02:00
parent e746577380
commit e05d803490
2561 changed files with 116 additions and 1279795 deletions

View File

@@ -908,9 +908,12 @@ if (authorityConfigured)
});
app.UseAuthorization();
app.UseStellaOpsTenantMiddleware();
}
// Tenant middleware runs unconditionally so that .RequireTenant() endpoint
// filters can resolve tenant context from headers even when authority is disabled.
app.UseStellaOpsTenantMiddleware();
// Stella Router integration
app.TryUseStellaRouter(routerEnabled);

View File

@@ -2,7 +2,7 @@
"openapi": "3.1.0",
"info": {
"title": "StellaOps Concelier API",
"version": "1.0.0\u002Baf4f261de8ad2b65cd94317cf24020351a42677f",
"version": "1.0.0-alpha1\u002Be74657738086bd216ffac712ed9331401adbbbc1",
"description": "Programmatic contract for Concelier advisory ingestion, observation replay, evidence exports, and job orchestration."
},
"servers": [
@@ -255,6 +255,76 @@
}
}
},
"/api/v1/advisory-sources": {
"get": {
"operationId": "get_api_v1_advisory_sources",
"summary": "GET /api/v1/advisory-sources/",
"tags": [
"Api"
],
"responses": {
"200": {
"description": "Request processed successfully."
},
"401": {
"description": "Authentication required."
},
"403": {
"description": "Authorization failed for the requested scope."
}
}
}
},
"/api/v1/advisory-sources/summary": {
"get": {
"operationId": "get_api_v1_advisory_sources_summary",
"summary": "GET /api/v1/advisory-sources/summary",
"tags": [
"Api"
],
"responses": {
"200": {
"description": "Request processed successfully."
},
"401": {
"description": "Authentication required."
},
"403": {
"description": "Authorization failed for the requested scope."
}
}
}
},
"/api/v1/advisory-sources/{id}/freshness": {
"get": {
"operationId": "get_api_v1_advisory_sources_id_freshness",
"summary": "GET /api/v1/advisory-sources/{id}/freshness",
"tags": [
"Api"
],
"parameters": [
{
"name": "id",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "Request processed successfully."
},
"401": {
"description": "Authentication required."
},
"403": {
"description": "Authorization failed for the requested scope."
}
}
}
},
"/api/v1/canonical": {
"get": {
"operationId": "get_api_v1_canonical",

View File

@@ -1416,6 +1416,7 @@ public sealed class WebServiceEndpointsTests : IAsyncLifetime
using var factory = new ConcelierApplicationFactory(_runner.ConnectionString, environmentOverrides: environment);
using var client = factory.CreateClient();
client.DefaultRequestHeaders.Add("X-Stella-Tenant", "test-tenant");
var indexResponse = await client.GetAsync("/concelier/exports/index.json");
Assert.Equal(HttpStatusCode.OK, indexResponse.StatusCode);
@@ -1485,6 +1486,7 @@ public sealed class WebServiceEndpointsTests : IAsyncLifetime
environment);
using var client = factory.CreateClient();
client.DefaultRequestHeaders.Add("X-Stella-Tenant", "test-tenant");
var response = await client.GetAsync("/concelier/exports/mirror/secure/manifest.json");
Assert.Equal(HttpStatusCode.Unauthorized, response.StatusCode);
var authHeader = Assert.Single(response.Headers.WwwAuthenticate);
@@ -1518,6 +1520,7 @@ public sealed class WebServiceEndpointsTests : IAsyncLifetime
using var factory = new ConcelierApplicationFactory(_runner.ConnectionString, environmentOverrides: environment);
using var client = factory.CreateClient();
client.DefaultRequestHeaders.Add("X-Stella-Tenant", "test-tenant");
var okResponse = await client.GetAsync("/concelier/exports/index.json");
Assert.Equal(HttpStatusCode.OK, okResponse.StatusCode);