up
This commit is contained in:
@@ -4,22 +4,34 @@ using Microsoft.Extensions.Options;
|
||||
using StellaOps.Policy;
|
||||
using StellaOps.Policy.Engine.Compilation;
|
||||
using StellaOps.Policy.Engine.Options;
|
||||
|
||||
namespace StellaOps.Policy.Engine.Services;
|
||||
|
||||
/// <summary>
|
||||
/// Provides deterministic compilation for <c>stella-dsl@1</c> policy documents and exposes
|
||||
/// basic statistics consumed by API/CLI surfaces.
|
||||
/// </summary>
|
||||
using StellaOps.PolicyDsl;
|
||||
using DslCompiler = StellaOps.PolicyDsl.PolicyCompiler;
|
||||
using DslCompilationResult = StellaOps.PolicyDsl.PolicyCompilationResult;
|
||||
using IrDocument = StellaOps.PolicyDsl.PolicyIrDocument;
|
||||
using IrAction = StellaOps.PolicyDsl.PolicyIrAction;
|
||||
using IrAssignmentAction = StellaOps.PolicyDsl.PolicyIrAssignmentAction;
|
||||
using IrAnnotateAction = StellaOps.PolicyDsl.PolicyIrAnnotateAction;
|
||||
using IrIgnoreAction = StellaOps.PolicyDsl.PolicyIrIgnoreAction;
|
||||
using IrEscalateAction = StellaOps.PolicyDsl.PolicyIrEscalateAction;
|
||||
using IrRequireVexAction = StellaOps.PolicyDsl.PolicyIrRequireVexAction;
|
||||
using IrWarnAction = StellaOps.PolicyDsl.PolicyIrWarnAction;
|
||||
using IrDeferAction = StellaOps.PolicyDsl.PolicyIrDeferAction;
|
||||
|
||||
namespace StellaOps.Policy.Engine.Services;
|
||||
|
||||
/// <summary>
|
||||
/// Provides deterministic compilation for <c>stella-dsl@1</c> policy documents and exposes
|
||||
/// basic statistics consumed by API/CLI surfaces.
|
||||
/// </summary>
|
||||
internal sealed class PolicyCompilationService
|
||||
{
|
||||
private readonly PolicyCompiler compiler;
|
||||
private readonly DslCompiler compiler;
|
||||
private readonly PolicyComplexityAnalyzer complexityAnalyzer;
|
||||
private readonly IOptionsMonitor<PolicyEngineOptions> optionsMonitor;
|
||||
private readonly TimeProvider timeProvider;
|
||||
|
||||
public PolicyCompilationService(
|
||||
PolicyCompiler compiler,
|
||||
DslCompiler compiler,
|
||||
PolicyComplexityAnalyzer complexityAnalyzer,
|
||||
IOptionsMonitor<PolicyEngineOptions> optionsMonitor,
|
||||
TimeProvider timeProvider)
|
||||
@@ -29,30 +41,30 @@ internal sealed class PolicyCompilationService
|
||||
this.optionsMonitor = optionsMonitor ?? throw new ArgumentNullException(nameof(optionsMonitor));
|
||||
this.timeProvider = timeProvider ?? TimeProvider.System;
|
||||
}
|
||||
|
||||
public PolicyCompilationResultDto Compile(PolicyCompileRequest request)
|
||||
{
|
||||
if (request is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(request));
|
||||
}
|
||||
|
||||
if (request.Dsl is null || string.IsNullOrWhiteSpace(request.Dsl.Source))
|
||||
{
|
||||
throw new ArgumentException("Compilation requires DSL source.", nameof(request));
|
||||
}
|
||||
|
||||
if (!string.Equals(request.Dsl.Syntax, "stella-dsl@1", StringComparison.Ordinal))
|
||||
{
|
||||
|
||||
public PolicyCompilationResultDto Compile(PolicyCompileRequest request)
|
||||
{
|
||||
if (request is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(request));
|
||||
}
|
||||
|
||||
if (request.Dsl is null || string.IsNullOrWhiteSpace(request.Dsl.Source))
|
||||
{
|
||||
throw new ArgumentException("Compilation requires DSL source.", nameof(request));
|
||||
}
|
||||
|
||||
if (!string.Equals(request.Dsl.Syntax, "stella-dsl@1", StringComparison.Ordinal))
|
||||
{
|
||||
return PolicyCompilationResultDto.FromFailure(
|
||||
ImmutableArray.Create(PolicyIssue.Error(
|
||||
PolicyDslDiagnosticCodes.UnsupportedSyntaxVersion,
|
||||
DiagnosticCodes.UnsupportedSyntaxVersion,
|
||||
$"Unsupported syntax '{request.Dsl.Syntax ?? "null"}'. Expected 'stella-dsl@1'.",
|
||||
"dsl.syntax")),
|
||||
complexity: null,
|
||||
durationMilliseconds: 0);
|
||||
}
|
||||
|
||||
|
||||
var start = timeProvider.GetTimestamp();
|
||||
var result = compiler.Compile(request.Dsl.Source);
|
||||
var elapsed = timeProvider.GetElapsedTime(start, timeProvider.GetTimestamp());
|
||||
@@ -95,11 +107,11 @@ internal sealed class PolicyCompilationService
|
||||
? ImmutableArray.Create(diagnostic)
|
||||
: diagnostics.Add(diagnostic);
|
||||
}
|
||||
|
||||
internal sealed record PolicyCompileRequest(PolicyDslPayload Dsl);
|
||||
|
||||
internal sealed record PolicyDslPayload(string Syntax, string Source);
|
||||
|
||||
|
||||
internal sealed record PolicyCompileRequest(PolicyDslPayload Dsl);
|
||||
|
||||
public sealed record PolicyDslPayload(string Syntax, string Source);
|
||||
|
||||
internal sealed record PolicyCompilationResultDto(
|
||||
bool Success,
|
||||
string? Digest,
|
||||
@@ -116,7 +128,7 @@ internal sealed record PolicyCompilationResultDto(
|
||||
new(false, null, null, ImmutableArray<byte>.Empty, diagnostics, complexity, durationMilliseconds);
|
||||
|
||||
public static PolicyCompilationResultDto FromSuccess(
|
||||
PolicyCompilationResult compilationResult,
|
||||
DslCompilationResult compilationResult,
|
||||
PolicyComplexityReport complexity,
|
||||
long durationMilliseconds)
|
||||
{
|
||||
@@ -136,45 +148,45 @@ internal sealed record PolicyCompilationResultDto(
|
||||
durationMilliseconds);
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed record PolicyCompilationStatistics(
|
||||
int RuleCount,
|
||||
ImmutableDictionary<string, int> ActionCounts)
|
||||
{
|
||||
public static PolicyCompilationStatistics Create(PolicyIrDocument document)
|
||||
{
|
||||
var actions = ImmutableDictionary.CreateBuilder<string, int>(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
void Increment(string key)
|
||||
{
|
||||
actions[key] = actions.TryGetValue(key, out var existing) ? existing + 1 : 1;
|
||||
}
|
||||
|
||||
foreach (var rule in document.Rules)
|
||||
{
|
||||
foreach (var action in rule.ThenActions)
|
||||
{
|
||||
Increment(GetActionKey(action));
|
||||
}
|
||||
|
||||
foreach (var action in rule.ElseActions)
|
||||
{
|
||||
Increment($"else:{GetActionKey(action)}");
|
||||
}
|
||||
}
|
||||
|
||||
return new PolicyCompilationStatistics(document.Rules.Length, actions.ToImmutable());
|
||||
}
|
||||
|
||||
private static string GetActionKey(PolicyIrAction action) => action switch
|
||||
{
|
||||
PolicyIrAssignmentAction => "assign",
|
||||
PolicyIrAnnotateAction => "annotate",
|
||||
PolicyIrIgnoreAction => "ignore",
|
||||
PolicyIrEscalateAction => "escalate",
|
||||
PolicyIrRequireVexAction => "requireVex",
|
||||
PolicyIrWarnAction => "warn",
|
||||
PolicyIrDeferAction => "defer",
|
||||
_ => "unknown"
|
||||
};
|
||||
}
|
||||
|
||||
internal sealed record PolicyCompilationStatistics(
|
||||
int RuleCount,
|
||||
ImmutableDictionary<string, int> ActionCounts)
|
||||
{
|
||||
public static PolicyCompilationStatistics Create(IrDocument document)
|
||||
{
|
||||
var actions = ImmutableDictionary.CreateBuilder<string, int>(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
void Increment(string key)
|
||||
{
|
||||
actions[key] = actions.TryGetValue(key, out var existing) ? existing + 1 : 1;
|
||||
}
|
||||
|
||||
foreach (var rule in document.Rules)
|
||||
{
|
||||
foreach (var action in rule.ThenActions)
|
||||
{
|
||||
Increment(GetActionKey(action));
|
||||
}
|
||||
|
||||
foreach (var action in rule.ElseActions)
|
||||
{
|
||||
Increment($"else:{GetActionKey(action)}");
|
||||
}
|
||||
}
|
||||
|
||||
return new PolicyCompilationStatistics(document.Rules.Length, actions.ToImmutable());
|
||||
}
|
||||
|
||||
private static string GetActionKey(IrAction action) => action switch
|
||||
{
|
||||
IrAssignmentAction => "assign",
|
||||
IrAnnotateAction => "annotate",
|
||||
IrIgnoreAction => "ignore",
|
||||
IrEscalateAction => "escalate",
|
||||
IrRequireVexAction => "requireVex",
|
||||
IrWarnAction => "warn",
|
||||
IrDeferAction => "defer",
|
||||
_ => "unknown"
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
using System.Collections.Immutable;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Logging.Abstractions;
|
||||
using StellaOps.Policy.Engine.Compilation;
|
||||
using StellaOps.PolicyDsl;
|
||||
using StellaOps.Policy.Engine.Evaluation;
|
||||
|
||||
namespace StellaOps.Policy.Engine.Services;
|
||||
@@ -23,19 +23,19 @@ internal sealed partial class PolicyEvaluationService
|
||||
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
||||
}
|
||||
|
||||
internal PolicyEvaluationResult Evaluate(PolicyIrDocument document, PolicyEvaluationContext context)
|
||||
internal Evaluation.PolicyEvaluationResult Evaluate(PolicyIrDocument document, Evaluation.PolicyEvaluationContext context)
|
||||
{
|
||||
if (document is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(document));
|
||||
}
|
||||
|
||||
if (context is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(context));
|
||||
}
|
||||
throw new ArgumentNullException(nameof(document));
|
||||
}
|
||||
|
||||
var request = new PolicyEvaluationRequest(document, context);
|
||||
if (context is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(context));
|
||||
}
|
||||
|
||||
var request = new Evaluation.PolicyEvaluationRequest(document, context);
|
||||
return evaluator.Evaluate(request);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user