sprints enhancements

This commit is contained in:
StellaOps Bot
2025-12-25 19:52:30 +02:00
parent ef6ac36323
commit b8b2d83f4a
138 changed files with 25133 additions and 594 deletions

View File

@@ -65,14 +65,14 @@ public sealed class PolicyDslRoundtripPropertyTests
PolicyDslArbs.ValidPolicyName(),
name =>
{
var source = $"""
policy "{name}" syntax "stella-dsl@1" {{
rule test priority 1 {{
var source = $$"""
policy "{{name}}" syntax "stella-dsl@1" {
rule test priority 1 {
when true
then severity := "low"
because "test"
}}
}}
}
}
""";
var result1 = _compiler.Compile(source);
@@ -179,6 +179,102 @@ public sealed class PolicyDslRoundtripPropertyTests
});
}
/// <summary>
/// Sprint 8200.0012.0003: Score-based conditions roundtrip correctly.
/// </summary>
[Property(MaxTest = 50)]
public Property ScoreConditions_RoundtripCorrectly()
{
return Prop.ForAll(
PolicyDslArbs.ValidPolicyWithScoreConditions(),
source =>
{
var result1 = _compiler.Compile(source);
if (!result1.Success || result1.Document is null)
{
return true.Label("Skip: Score policy doesn't parse");
}
var printed = PolicyIrPrinter.Print(result1.Document);
var result2 = _compiler.Compile(printed);
if (!result2.Success || result2.Document is null)
{
return false.Label($"Score policy roundtrip failed: {string.Join("; ", result2.Diagnostics.Select(d => d.Message))}");
}
return AreDocumentsEquivalent(result1.Document, result2.Document)
.Label("Score policy documents should be equivalent after roundtrip");
});
}
/// <summary>
/// Sprint 8200.0012.0003: Each score condition type parses successfully.
/// </summary>
[Property(MaxTest = 50)]
public Property IndividualScoreConditions_ParseSuccessfully()
{
return Prop.ForAll(
PolicyDslArbs.ScoreCondition(),
condition =>
{
var source = $$"""
policy "ScoreTest" syntax "stella-dsl@1" {
rule test priority 1 {
when {{condition}}
then severity := "high"
because "Score condition test"
}
}
""";
var result = _compiler.Compile(source);
return (result.Success && result.Document is not null)
.Label($"Score condition '{condition}' should parse successfully");
});
}
/// <summary>
/// Sprint 8200.0012.0003: Score expression structure preserved through roundtrip.
/// </summary>
[Property(MaxTest = 50)]
public Property ScoreExpressionStructure_PreservedThroughRoundtrip()
{
return Prop.ForAll(
PolicyDslArbs.ScoreCondition(),
condition =>
{
var source = $$"""
policy "ScoreTest" syntax "stella-dsl@1" {
rule test priority 1 {
when {{condition}}
then severity := "high"
because "Score test"
}
}
""";
var result1 = _compiler.Compile(source);
if (!result1.Success || result1.Document is null)
{
return true.Label($"Skip: Condition '{condition}' doesn't parse");
}
var printed = PolicyIrPrinter.Print(result1.Document);
var result2 = _compiler.Compile(printed);
if (!result2.Success || result2.Document is null)
{
return false.Label($"Roundtrip failed for '{condition}'");
}
// Verify rule count matches
return (result1.Document.Rules.Length == result2.Document.Rules.Length)
.Label($"Rule count preserved for condition '{condition}'");
});
}
/// <summary>
/// Property: Different policies produce different checksums.
/// </summary>
@@ -256,6 +352,29 @@ internal static class PolicyDslArbs
"status == \"blocked\""
];
// Sprint 8200.0012.0003: Score-based conditions for EWS integration
private static readonly string[] ScoreConditions =
[
"score >= 70",
"score > 80",
"score <= 50",
"score < 40",
"score == 75",
"score.is_act_now",
"score.is_schedule_next",
"score.is_investigate",
"score.is_watchlist",
"score.bucket == \"ActNow\"",
"score.rch > 0.8",
"score.xpl > 0.7",
"score.has_flag(\"kev\")",
"score.has_flag(\"live-signal\")",
"score.between(60, 80)",
"score >= 70 and score.is_schedule_next",
"score > 80 or score.has_flag(\"kev\")",
"score.rch > 0.8 and score.xpl > 0.7"
];
private static readonly string[] ValidActions =
[
"severity := \"info\"",
@@ -296,6 +415,22 @@ internal static class PolicyDslArbs
from rules in Gen.ArrayOf(1, GenRule())
select BuildPolicyWithMetadata(name, hasVersion, hasAuthor, rules));
/// <summary>
/// Sprint 8200.0012.0003: Generates policies with score-based conditions.
/// </summary>
public static Arbitrary<string> ValidPolicyWithScoreConditions() =>
Arb.From(
from name in Gen.Elements(ValidIdentifiers)
from ruleCount in Gen.Choose(1, 3)
from rules in Gen.ArrayOf(ruleCount, GenScoreRule())
select BuildPolicy(name, rules));
/// <summary>
/// Sprint 8200.0012.0003: Generates a specific score condition for targeted testing.
/// </summary>
public static Arbitrary<string> ScoreCondition() =>
Arb.From(Gen.Elements(ScoreConditions));
private static Gen<string> GenRule()
{
return from nameIndex in Gen.Choose(0, ValidIdentifiers.Length - 1)
@@ -306,22 +441,44 @@ internal static class PolicyDslArbs
let priority = ValidPriorities[priorityIndex]
let condition = ValidConditions[conditionIndex]
let action = ValidActions[actionIndex]
select $"""
rule {name} priority {priority} {{
when {condition}
then {action}
select $$"""
rule {{name}} priority {{priority}} {
when {{condition}}
then {{action}}
because "Generated test rule"
}}
}
""";
}
/// <summary>
/// Sprint 8200.0012.0003: Generates rules with score-based conditions.
/// </summary>
private static Gen<string> GenScoreRule()
{
return from nameIndex in Gen.Choose(0, ValidIdentifiers.Length - 1)
from priorityIndex in Gen.Choose(0, ValidPriorities.Length - 1)
from conditionIndex in Gen.Choose(0, ScoreConditions.Length - 1)
from actionIndex in Gen.Choose(0, ValidActions.Length - 1)
let name = ValidIdentifiers[nameIndex]
let priority = ValidPriorities[priorityIndex]
let condition = ScoreConditions[conditionIndex]
let action = ValidActions[actionIndex]
select $$"""
rule {{name}} priority {{priority}} {
when {{condition}}
then {{action}}
because "Score-based rule"
}
""";
}
private static string BuildPolicy(string name, string[] rules)
{
var rulesText = string.Join("\n", rules);
return $"""
policy "{name}" syntax "stella-dsl@1" {{
{rulesText}
}}
return $$"""
policy "{{name}}" syntax "stella-dsl@1" {
{{rulesText}}
}
""";
}
@@ -332,20 +489,20 @@ internal static class PolicyDslArbs
if (hasAuthor) metadataLines.Add(" author = \"test\"");
var metadata = metadataLines.Count > 0
? $"""
metadata {{
{string.Join("\n", metadataLines)}
}}
? $$"""
metadata {
{{string.Join("\n", metadataLines)}}
}
"""
: "";
var rulesText = string.Join("\n", rules);
return $"""
policy "{name}" syntax "stella-dsl@1" {{
{metadata}
{rulesText}
}}
return $$"""
policy "{{name}}" syntax "stella-dsl@1" {
{{metadata}}
{{rulesText}}
}
""";
}
}