Files
git.stella-ops.org/src/Policy/__Tests/StellaOps.Policy.Engine.Tests/PolicyCompilerTests.cs
StellaOps Bot 8abbf9574d up
2025-11-27 21:10:06 +02:00

105 lines
3.8 KiB
C#

using System.Collections.Immutable;
using System.Linq;
using StellaOps.Policy;
using StellaOps.PolicyDsl;
using Xunit;
using Xunit.Sdk;
namespace StellaOps.Policy.Engine.Tests;
public sealed class PolicyCompilerTests
{
[Fact]
public void Compile_BaselinePolicy_Succeeds()
{
const string source = """
policy "Baseline Production Policy" syntax "stella-dsl@1" {
metadata {
description = "Block critical, escalate high, enforce VEX justifications."
tags = ["baseline","production"]
}
profile severity {
map vendor_weight {
source "GHSA" => +0.5
source "OSV" => +0.0
}
env exposure_adjustments {
if env.exposure == "internet" then +0.5
}
}
rule block_critical priority 5 {
when severity.normalized >= "Critical"
then status := "blocked"
because "Critical severity must be remediated before deploy."
}
rule escalate_high_internet {
when severity.normalized == "High"
and env.exposure == "internet"
then escalate to severity_band("Critical")
because "High severity on internet-exposed asset escalates to critical."
}
rule require_vex_justification {
when vex.any(status in ["not_affected","fixed"])
and vex.justification in ["component_not_present","vulnerable_code_not_present"]
then status := vex.status
annotate winning_statement := vex.latest().statementId
because "Respect strong vendor VEX claims."
}
rule alert_warn_eol_runtime priority 1 {
when severity.normalized <= "Medium"
and sbom.has_tag("runtime:eol")
then warn message "Runtime marked as EOL; upgrade recommended."
because "Deprecated runtime should be upgraded."
}
}
""";
var compiler = new PolicyCompiler();
var result = compiler.Compile(source);
if (!result.Success)
{
throw new Xunit.Sdk.XunitException($"Compilation failed: {Describe(result.Diagnostics)}");
}
Assert.False(string.IsNullOrWhiteSpace(result.Checksum));
Assert.NotEmpty(result.CanonicalRepresentation);
Assert.All(result.Diagnostics, issue => Assert.NotEqual(PolicyIssueSeverity.Error, issue.Severity));
var document = Assert.IsType<PolicyIrDocument>(result.Document);
Assert.Equal("Baseline Production Policy", document.Name);
Assert.Equal("stella-dsl@1", document.Syntax);
Assert.Equal(4, document.Rules.Length);
Assert.Single(document.Profiles);
var firstAction = Assert.IsType<PolicyIrAssignmentAction>(document.Rules[0].ThenActions[0]);
Assert.Equal("status", firstAction.Target[0]);
}
[Fact]
public void Compile_MissingBecause_ReportsDiagnostic()
{
const string source = """
policy "Incomplete" syntax "stella-dsl@1" {
rule missing_because {
when true
then status := "suppressed"
}
}
""";
var compiler = new PolicyCompiler();
var result = compiler.Compile(source);
Assert.False(result.Success);
PolicyIssue diagnostic = result.Diagnostics.First(issue => issue.Code == "POLICY-DSL-PARSE-006");
Assert.Equal(PolicyIssueSeverity.Error, diagnostic.Severity);
}
private static string Describe(ImmutableArray<PolicyIssue> issues) =>
string.Join(" | ", issues.Select(issue => $"{issue.Severity}:{issue.Code}:{issue.Message}"));
}