texts fixes, search bar fixes, global menu fixes.
This commit is contained in:
@@ -11,3 +11,4 @@ Source of truth: `docs-archived/implplan/2025-12-29-csproj-audit/SPRINT_20251229
|
||||
| REMED-06 | DONE | SOLID review notes captured for SPRINT_20260130_002. |
|
||||
| RGH-01 | DONE | 2026-02-22: Added SPA fallback handling for browser deep links on microservice route matches; API prefixes remain backend-dispatched. |
|
||||
| RGH-02 | DONE | 2026-03-04: Expanded approved auth passthrough prefixes (`/authority`, `/doctor`, `/api`) to unblock authenticated gateway routes used by Audit Log UI E2E. |
|
||||
| RGH-03 | DONE | 2026-03-05: Aligned `/api/v1/search*` and `/api/v1/advisory-ai*` route translations to AdvisoryAI `/v1/*`, added compose/runtime parity safeguards, and verified setup smoke coverage. |
|
||||
|
||||
@@ -102,7 +102,8 @@
|
||||
{ "Type": "ReverseProxy", "Path": "/api/v1/evidence", "TranslatesTo": "http://evidencelocker.stella-ops.local/api/v1/evidence" },
|
||||
{ "Type": "ReverseProxy", "Path": "/api/v1/proofs", "TranslatesTo": "http://evidencelocker.stella-ops.local/api/v1/proofs" },
|
||||
{ "Type": "ReverseProxy", "Path": "/api/v1/timeline", "TranslatesTo": "http://timelineindexer.stella-ops.local/api/v1/timeline" },
|
||||
{ "Type": "ReverseProxy", "Path": "/api/v1/advisory-ai", "TranslatesTo": "http://advisoryai.stella-ops.local/api/v1/advisory-ai" },
|
||||
{ "Type": "ReverseProxy", "Path": "/api/v1/search", "TranslatesTo": "http://advisoryai.stella-ops.local/v1/search" },
|
||||
{ "Type": "ReverseProxy", "Path": "/api/v1/advisory-ai", "TranslatesTo": "http://advisoryai.stella-ops.local/v1/advisory-ai" },
|
||||
{ "Type": "ReverseProxy", "Path": "/api/v1/advisory", "TranslatesTo": "http://advisoryai.stella-ops.local/api/v1/advisory" },
|
||||
{ "Type": "ReverseProxy", "Path": "/api/v1/concelier", "TranslatesTo": "http://concelier.stella-ops.local/api/v1/concelier" },
|
||||
{ "Type": "ReverseProxy", "Path": "/api/v1/vulnerabilities", "TranslatesTo": "http://scanner.stella-ops.local/api/v1/vulnerabilities" },
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
using System.Text.Json;
|
||||
|
||||
namespace StellaOps.Gateway.WebService.Tests.Configuration;
|
||||
|
||||
public sealed class GatewayRouteSearchMappingsTests
|
||||
{
|
||||
private static readonly (string Path, string Target, string RouteType)[] RequiredMappings =
|
||||
[
|
||||
("/api/v1/search", "http://advisoryai.stella-ops.local/v1/search", "ReverseProxy"),
|
||||
("/api/v1/advisory-ai", "http://advisoryai.stella-ops.local/v1/advisory-ai", "ReverseProxy")
|
||||
];
|
||||
|
||||
public static TheoryData<string> RouteConfigPaths => new()
|
||||
{
|
||||
"src/Router/StellaOps.Gateway.WebService/appsettings.json",
|
||||
"devops/compose/router-gateway-local.json",
|
||||
"devops/compose/router-gateway-local.reverseproxy.json"
|
||||
};
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(RouteConfigPaths))]
|
||||
public void RouteTable_ContainsUnifiedSearchMappingsAndKeepsThemAheadOfApiCatchAll(string configRelativePath)
|
||||
{
|
||||
var repoRoot = FindRepositoryRoot();
|
||||
var configPath = Path.Combine(repoRoot, configRelativePath.Replace('/', Path.DirectorySeparatorChar));
|
||||
Assert.True(File.Exists(configPath), $"Config file not found: {configPath}");
|
||||
|
||||
using var stream = File.OpenRead(configPath);
|
||||
using var document = JsonDocument.Parse(stream);
|
||||
|
||||
var routes = document.RootElement
|
||||
.GetProperty("Gateway")
|
||||
.GetProperty("Routes")
|
||||
.EnumerateArray()
|
||||
.Select((route, index) => new RouteEntry(
|
||||
index,
|
||||
route.GetProperty("Type").GetString() ?? string.Empty,
|
||||
route.GetProperty("Path").GetString() ?? string.Empty,
|
||||
route.TryGetProperty("TranslatesTo", out var translatesTo)
|
||||
? translatesTo.GetString() ?? string.Empty
|
||||
: string.Empty))
|
||||
.ToList();
|
||||
|
||||
var catchAllIndex = routes.FindIndex(route => string.Equals(route.Path, "/api", StringComparison.Ordinal));
|
||||
|
||||
foreach (var (requiredPath, requiredTarget, requiredType) in RequiredMappings)
|
||||
{
|
||||
var route = routes.FirstOrDefault(candidate => string.Equals(candidate.Path, requiredPath, StringComparison.Ordinal));
|
||||
Assert.True(route is not null, $"Missing route '{requiredPath}' in {configRelativePath}.");
|
||||
Assert.Equal(requiredType, route!.Type);
|
||||
Assert.Equal(requiredTarget, route!.TranslatesTo);
|
||||
|
||||
if (catchAllIndex >= 0)
|
||||
{
|
||||
Assert.True(route.Index < catchAllIndex, $"{requiredPath} must appear before /api catch-all in {configRelativePath}.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static string FindRepositoryRoot()
|
||||
{
|
||||
for (var current = new DirectoryInfo(AppContext.BaseDirectory); current is not null; current = current.Parent)
|
||||
{
|
||||
if (Directory.Exists(Path.Combine(current.FullName, ".git")))
|
||||
{
|
||||
return current.FullName;
|
||||
}
|
||||
}
|
||||
|
||||
throw new InvalidOperationException($"Unable to locate repository root from {AppContext.BaseDirectory}.");
|
||||
}
|
||||
|
||||
private sealed record RouteEntry(int Index, string Type, string Path, string TranslatesTo);
|
||||
}
|
||||
@@ -10,3 +10,4 @@ Source of truth: `docs-archived/implplan/2025-12-29-csproj-audit/SPRINT_20251229
|
||||
| AUDIT-0349-A | DONE | Waived (test project; revalidated 2026-01-07). |
|
||||
| REMED-06 | DONE | SOLID review notes captured for SPRINT_20260130_002. |
|
||||
| RGH-01-T | DONE | 2026-02-22: Added route-dispatch unit tests for microservice SPA fallback and API-prefix bypass behavior. |
|
||||
| RGH-03-T | DONE | 2026-03-05: Added deterministic route-table parity tests for unified search mappings across gateway runtime and compose configs; verified in gateway test run. |
|
||||
|
||||
Reference in New Issue
Block a user