Files
git.stella-ops.org/src/Policy/StellaOps.Policy.Engine/Endpoints/PathScopeSimulationEndpoint.cs

65 lines
2.5 KiB
C#

using Microsoft.AspNetCore.Http.HttpResults;
using Microsoft.AspNetCore.Mvc;
using StellaOps.Auth.Abstractions;
using StellaOps.Auth.ServerIntegration;
using StellaOps.Policy.Engine.Options;
using StellaOps.Policy.Engine.Overlay;
using StellaOps.Policy.Engine.Streaming;
using System.Text;
using System.Text.Json;
namespace StellaOps.Policy.Engine.Endpoints;
public static class PathScopeSimulationEndpoint
{
public static IEndpointRouteBuilder MapPathScopeSimulation(this IEndpointRouteBuilder routes)
{
routes.MapPost("/simulation/path-scope", HandleAsync)
.RequireRateLimiting(PolicyEngineRateLimitOptions.PolicyName)
.WithName("PolicyEngine.PathScopeSimulation")
.WithDescription("Stream a what-if path-scope simulation showing how a change in call-graph reachability would alter policy verdicts. Returns NDJSON lines for each simulated path segment with optional deterministic trace output.")
.RequireAuthorization(policy => policy.RequireStellaOpsScopes(StellaOpsScopes.PolicySimulate));
return routes;
}
private static async Task<IResult> HandleAsync(
[FromBody] PathScopeSimulationRequest request,
PathScopeSimulationService service,
PathScopeSimulationBridgeService bridge,
CancellationToken cancellationToken)
{
try
{
var stream = service.StreamAsync(request, cancellationToken);
var responseBuilder = new StringBuilder();
await foreach (var line in stream.ConfigureAwait(false))
{
responseBuilder.AppendLine(line);
}
// Emit change event stub when run in what-if mode.
if (request.Options.Deterministic && request.Options.IncludeTrace)
{
var bridgeRequest = new PathScopeSimulationBridgeRequest(
Tenant: request.Tenant,
Rules: Array.Empty<string>(),
Overlays: null,
Paths: new[] { request },
Mode: "preview",
Seed: null);
await bridge.SimulateAsync(bridgeRequest, cancellationToken).ConfigureAwait(false);
}
return Results.Text(responseBuilder.ToString(), "application/x-ndjson", Encoding.UTF8);
}
catch (PathScopeSimulationException ex)
{
var errorLine = JsonSerializer.Serialize(ex.Error);
return Results.Text(errorLine + "\n", "application/x-ndjson", Encoding.UTF8, StatusCodes.Status400BadRequest);
}
}
}