Add signal contracts for reachability, exploitability, trust, and unknown symbols
- Introduced `ReachabilityState`, `RuntimeHit`, `ExploitabilitySignal`, `ReachabilitySignal`, `SignalEnvelope`, `SignalType`, `TrustSignal`, and `UnknownSymbolSignal` records to define various signal types and their properties. - Implemented JSON serialization attributes for proper data interchange. - Created project files for the new signal contracts library and corresponding test projects. - Added deterministic test fixtures for micro-interaction testing. - Included cryptographic keys for secure operations with cosign.
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using StellaOps.Policy.Engine.ConsoleSurface;
|
||||
using StellaOps.Policy.Engine.Options;
|
||||
|
||||
namespace StellaOps.Policy.Engine.Endpoints;
|
||||
|
||||
@@ -8,6 +9,7 @@ internal static class ConsoleSimulationEndpoint
|
||||
public static IEndpointRouteBuilder MapConsoleSimulationDiff(this IEndpointRouteBuilder routes)
|
||||
{
|
||||
routes.MapPost("/policy/console/simulations/diff", HandleAsync)
|
||||
.RequireRateLimiting(PolicyEngineRateLimitOptions.PolicyName)
|
||||
.WithName("PolicyEngine.ConsoleSimulationDiff")
|
||||
.Produces<ConsoleSimulationDiffResponse>(StatusCodes.Status200OK)
|
||||
.ProducesValidationProblem();
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using StellaOps.Policy.Engine.Options;
|
||||
using StellaOps.Policy.Engine.Overlay;
|
||||
|
||||
namespace StellaOps.Policy.Engine.Endpoints;
|
||||
@@ -8,6 +9,7 @@ public static class OverlaySimulationEndpoint
|
||||
public static IEndpointRouteBuilder MapOverlaySimulation(this IEndpointRouteBuilder routes)
|
||||
{
|
||||
routes.MapPost("/simulation/overlay", HandleAsync)
|
||||
.RequireRateLimiting(PolicyEngineRateLimitOptions.PolicyName)
|
||||
.WithName("PolicyEngine.OverlaySimulation");
|
||||
|
||||
return routes;
|
||||
|
||||
@@ -2,6 +2,7 @@ using System.Text;
|
||||
using System.Text.Json;
|
||||
using Microsoft.AspNetCore.Http.HttpResults;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using StellaOps.Policy.Engine.Options;
|
||||
using StellaOps.Policy.Engine.Streaming;
|
||||
using StellaOps.Policy.Engine.Overlay;
|
||||
|
||||
@@ -12,6 +13,7 @@ public static class PathScopeSimulationEndpoint
|
||||
public static IEndpointRouteBuilder MapPathScopeSimulation(this IEndpointRouteBuilder routes)
|
||||
{
|
||||
routes.MapPost("/simulation/path-scope", HandleAsync)
|
||||
.RequireRateLimiting(PolicyEngineRateLimitOptions.PolicyName)
|
||||
.WithName("PolicyEngine.PathScopeSimulation");
|
||||
|
||||
return routes;
|
||||
|
||||
@@ -82,6 +82,12 @@ internal static class RiskProfileEndpoints
|
||||
.Produces<RiskProfileHashResponse>(StatusCodes.Status200OK)
|
||||
.Produces<ProblemHttpResult>(StatusCodes.Status404NotFound);
|
||||
|
||||
group.MapGet("/{profileId}/metadata", GetProfileMetadata)
|
||||
.WithName("GetRiskProfileMetadata")
|
||||
.WithSummary("Export risk profile metadata for notification enrichment (POLICY-RISK-40-002).")
|
||||
.Produces<RiskProfileMetadataExportResponse>(StatusCodes.Status200OK)
|
||||
.Produces<ProblemHttpResult>(StatusCodes.Status404NotFound);
|
||||
|
||||
return endpoints;
|
||||
}
|
||||
|
||||
@@ -461,6 +467,53 @@ internal static class RiskProfileEndpoints
|
||||
return Results.Ok(new RiskProfileHashResponse(profile.Id, profile.Version, hash, contentOnly));
|
||||
}
|
||||
|
||||
private static IResult GetProfileMetadata(
|
||||
HttpContext context,
|
||||
[FromRoute] string profileId,
|
||||
RiskProfileConfigurationService profileService,
|
||||
RiskProfileLifecycleService lifecycleService)
|
||||
{
|
||||
var scopeResult = ScopeAuthorization.RequireScope(context, StellaOpsScopes.PolicyRead);
|
||||
if (scopeResult is not null)
|
||||
{
|
||||
return scopeResult;
|
||||
}
|
||||
|
||||
var profile = profileService.GetProfile(profileId);
|
||||
if (profile == null)
|
||||
{
|
||||
return Results.NotFound(new ProblemDetails
|
||||
{
|
||||
Title = "Profile not found",
|
||||
Detail = $"Risk profile '{profileId}' was not found.",
|
||||
Status = StatusCodes.Status404NotFound
|
||||
});
|
||||
}
|
||||
|
||||
var versions = lifecycleService.GetAllVersions(profileId);
|
||||
var activeVersion = versions.FirstOrDefault(v => v.Status == RiskProfileLifecycleStatus.Active);
|
||||
var hash = profileService.ComputeHash(profile);
|
||||
|
||||
// Extract signal names and severity thresholds for notification context
|
||||
var signalNames = profile.Signals.Select(s => s.Name).ToList();
|
||||
var severityThresholds = profile.Overrides.Severity
|
||||
.Select(s => new SeverityThresholdInfo(s.Set.ToString(), s.When))
|
||||
.ToList();
|
||||
|
||||
return Results.Ok(new RiskProfileMetadataExportResponse(
|
||||
ProfileId: profile.Id,
|
||||
Version: profile.Version,
|
||||
Description: profile.Description,
|
||||
Hash: hash,
|
||||
Status: activeVersion?.Status.ToString() ?? "unknown",
|
||||
SignalNames: signalNames,
|
||||
SeverityThresholds: severityThresholds,
|
||||
CustomMetadata: profile.Metadata,
|
||||
ExtendsProfile: profile.Extends,
|
||||
ExportedAt: DateTime.UtcNow
|
||||
));
|
||||
}
|
||||
|
||||
private static string? ResolveActorId(HttpContext context)
|
||||
{
|
||||
var user = context.User;
|
||||
@@ -521,4 +574,26 @@ internal sealed record CompareRiskProfilesRequest(
|
||||
string ToProfileId,
|
||||
string ToVersion);
|
||||
|
||||
/// <summary>
|
||||
/// Metadata export response for notification enrichment (POLICY-RISK-40-002).
|
||||
/// </summary>
|
||||
internal sealed record RiskProfileMetadataExportResponse(
|
||||
string ProfileId,
|
||||
string Version,
|
||||
string? Description,
|
||||
string Hash,
|
||||
string Status,
|
||||
IReadOnlyList<string> SignalNames,
|
||||
IReadOnlyList<SeverityThresholdInfo> SeverityThresholds,
|
||||
Dictionary<string, object?>? CustomMetadata,
|
||||
string? ExtendsProfile,
|
||||
DateTime ExportedAt);
|
||||
|
||||
/// <summary>
|
||||
/// Severity threshold information for notification context.
|
||||
/// </summary>
|
||||
internal sealed record SeverityThresholdInfo(
|
||||
string TargetSeverity,
|
||||
Dictionary<string, object> WhenConditions);
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using Microsoft.AspNetCore.Http.HttpResults;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using StellaOps.Auth.Abstractions;
|
||||
using StellaOps.Policy.Engine.Options;
|
||||
using StellaOps.Policy.Engine.Services;
|
||||
using StellaOps.Policy.Engine.Simulation;
|
||||
|
||||
@@ -12,6 +13,7 @@ internal static class RiskSimulationEndpoints
|
||||
{
|
||||
var group = endpoints.MapGroup("/api/risk/simulation")
|
||||
.RequireAuthorization()
|
||||
.RequireRateLimiting(PolicyEngineRateLimitOptions.PolicyName)
|
||||
.WithTags("Risk Simulation");
|
||||
|
||||
group.MapPost("/", RunSimulation)
|
||||
|
||||
Reference in New Issue
Block a user