- Added `SchedulerWorkerOptions` class to encapsulate configuration for the scheduler worker. - Introduced `PlannerBackgroundService` to manage the planner loop, fetching and processing planning runs. - Created `PlannerExecutionService` to handle the execution logic for planning runs, including impact targeting and run persistence. - Developed `PlannerExecutionResult` and `PlannerExecutionStatus` to standardize execution outcomes. - Implemented validation logic within `SchedulerWorkerOptions` to ensure proper configuration. - Added documentation for the planner loop and impact targeting features. - Established health check endpoints and authentication mechanisms for the Signals service. - Created unit tests for the Signals API to ensure proper functionality and response handling. - Configured options for authority integration and fallback authentication methods.
137 lines
5.2 KiB
C#
137 lines
5.2 KiB
C#
using System.Collections.Immutable;
|
|
using Xunit;
|
|
|
|
namespace StellaOps.Policy.Tests;
|
|
|
|
public sealed class PolicyEvaluationTests
|
|
{
|
|
[Fact]
|
|
public void EvaluateFinding_AppliesTrustAndReachabilityWeights()
|
|
{
|
|
var action = new PolicyAction(PolicyActionType.Block, null, null, null, false);
|
|
var rule = PolicyRule.Create(
|
|
"BlockMedium",
|
|
action,
|
|
ImmutableArray.Create(PolicySeverity.Medium),
|
|
ImmutableArray<string>.Empty,
|
|
ImmutableArray<string>.Empty,
|
|
ImmutableArray<string>.Empty,
|
|
ImmutableArray<string>.Empty,
|
|
ImmutableArray<string>.Empty,
|
|
PolicyRuleMatchCriteria.Empty,
|
|
expires: null,
|
|
justification: null);
|
|
var document = new PolicyDocument(
|
|
PolicySchema.CurrentVersion,
|
|
ImmutableArray.Create(rule),
|
|
ImmutableDictionary<string, string>.Empty,
|
|
PolicyExceptionConfiguration.Empty);
|
|
|
|
var config = PolicyScoringConfig.Default;
|
|
var finding = PolicyFinding.Create(
|
|
"finding-medium",
|
|
PolicySeverity.Medium,
|
|
source: "community",
|
|
tags: ImmutableArray.Create("reachability:indirect"));
|
|
|
|
var verdict = PolicyEvaluation.EvaluateFinding(document, config, finding);
|
|
|
|
Assert.Equal(PolicyVerdictStatus.Blocked, verdict.Status);
|
|
Assert.Equal(19.5, verdict.Score, 3);
|
|
|
|
var inputs = verdict.GetInputs();
|
|
Assert.Equal(50, inputs["severityWeight"]);
|
|
Assert.Equal(0.65, inputs["trustWeight"], 3);
|
|
Assert.Equal(0.6, inputs["reachabilityWeight"], 3);
|
|
Assert.Equal(19.5, inputs["baseScore"], 3);
|
|
}
|
|
|
|
[Fact]
|
|
public void EvaluateFinding_QuietWithRequireVexAppliesQuietPenalty()
|
|
{
|
|
var ignoreOptions = new PolicyIgnoreOptions(null, null);
|
|
var requireVexOptions = new PolicyRequireVexOptions(
|
|
ImmutableArray<string>.Empty,
|
|
ImmutableArray<string>.Empty);
|
|
var action = new PolicyAction(PolicyActionType.Ignore, ignoreOptions, null, requireVexOptions, true);
|
|
var rule = PolicyRule.Create(
|
|
"QuietIgnore",
|
|
action,
|
|
ImmutableArray.Create(PolicySeverity.Critical),
|
|
ImmutableArray<string>.Empty,
|
|
ImmutableArray<string>.Empty,
|
|
ImmutableArray<string>.Empty,
|
|
ImmutableArray<string>.Empty,
|
|
ImmutableArray<string>.Empty,
|
|
PolicyRuleMatchCriteria.Empty,
|
|
expires: null,
|
|
justification: null);
|
|
|
|
var document = new PolicyDocument(
|
|
PolicySchema.CurrentVersion,
|
|
ImmutableArray.Create(rule),
|
|
ImmutableDictionary<string, string>.Empty,
|
|
PolicyExceptionConfiguration.Empty);
|
|
|
|
var config = PolicyScoringConfig.Default;
|
|
var finding = PolicyFinding.Create(
|
|
"finding-critical",
|
|
PolicySeverity.Critical,
|
|
tags: ImmutableArray.Create("reachability:entrypoint"));
|
|
|
|
var verdict = PolicyEvaluation.EvaluateFinding(document, config, finding);
|
|
|
|
Assert.Equal(PolicyVerdictStatus.Ignored, verdict.Status);
|
|
Assert.True(verdict.Quiet);
|
|
Assert.Equal("QuietIgnore", verdict.QuietedBy);
|
|
Assert.Equal(10, verdict.Score, 3);
|
|
|
|
var inputs = verdict.GetInputs();
|
|
Assert.Equal(90, inputs["baseScore"], 3);
|
|
Assert.Equal(config.IgnorePenalty, inputs["ignorePenalty"]);
|
|
Assert.Equal(config.QuietPenalty, inputs["quietPenalty"]);
|
|
}
|
|
|
|
[Fact]
|
|
public void EvaluateFinding_UnknownSeverityComputesConfidence()
|
|
{
|
|
var action = new PolicyAction(PolicyActionType.Block, null, null, null, false);
|
|
var rule = PolicyRule.Create(
|
|
"BlockUnknown",
|
|
action,
|
|
ImmutableArray.Create(PolicySeverity.Unknown),
|
|
ImmutableArray<string>.Empty,
|
|
ImmutableArray<string>.Empty,
|
|
ImmutableArray<string>.Empty,
|
|
ImmutableArray<string>.Empty,
|
|
ImmutableArray<string>.Empty,
|
|
PolicyRuleMatchCriteria.Empty,
|
|
expires: null,
|
|
justification: null);
|
|
|
|
var document = new PolicyDocument(
|
|
PolicySchema.CurrentVersion,
|
|
ImmutableArray.Create(rule),
|
|
ImmutableDictionary<string, string>.Empty,
|
|
PolicyExceptionConfiguration.Empty);
|
|
|
|
var config = PolicyScoringConfig.Default;
|
|
var finding = PolicyFinding.Create(
|
|
"finding-unknown",
|
|
PolicySeverity.Unknown,
|
|
tags: ImmutableArray.Create("reachability:unknown", "unknown-age-days:5"));
|
|
|
|
var verdict = PolicyEvaluation.EvaluateFinding(document, config, finding);
|
|
|
|
Assert.Equal(PolicyVerdictStatus.Blocked, verdict.Status);
|
|
Assert.Equal(30, verdict.Score, 3); // 60 * 1 * 0.5
|
|
Assert.Equal(0.55, verdict.UnknownConfidence ?? 0, 3);
|
|
Assert.Equal("medium", verdict.ConfidenceBand);
|
|
Assert.Equal(5, verdict.UnknownAgeDays ?? 0, 3);
|
|
|
|
var inputs = verdict.GetInputs();
|
|
Assert.Equal(0.55, inputs["unknownConfidence"], 3);
|
|
Assert.Equal(5, inputs["unknownAgeDays"], 3);
|
|
}
|
|
}
|