Files
git.stella-ops.org/src/Policy/__Tests/StellaOps.Policy.Pack.Tests/StarterPolicyPackTests.cs

182 lines
6.9 KiB
C#

// SPDX-License-Identifier: BUSL-1.1
// Sprint: SPRINT_5200_0001_0001 - Starter Policy Template
// Task: T6 - Starter Policy Tests
using System.Text.Json;
using System.Text.Json.Nodes;
using FluentAssertions;
using Json.Schema;
using YamlDotNet.Serialization;
using StellaOps.TestKit;
namespace StellaOps.Policy.Pack.Tests;
public class StarterPolicyPackTests
{
private readonly string _testDataPath;
private readonly IDeserializer _yamlDeserializer;
public StarterPolicyPackTests()
{
_testDataPath = Path.Combine(AppContext.BaseDirectory, "TestData");
_yamlDeserializer = new DeserializerBuilder()
.WithNamingConvention(YamlDotNet.Serialization.NamingConventions.CamelCaseNamingConvention.Instance)
.Build();
}
[Trait("Category", TestCategories.Unit)]
[Fact]
public void StarterDay1Policy_Exists()
{
var policyPath = Path.Combine(_testDataPath, "starter-day1.yaml");
File.Exists(policyPath).Should().BeTrue("starter-day1.yaml should exist");
}
[Trait("Category", TestCategories.Unit)]
[Fact]
public void StarterDay1Policy_HasValidYamlStructure()
{
var policyPath = Path.Combine(_testDataPath, "starter-day1.yaml");
var content = File.ReadAllText(policyPath);
var act = () => _yamlDeserializer.Deserialize<Dictionary<string, object>>(content);
act.Should().NotThrow("YAML should be valid and parseable");
}
[Trait("Category", TestCategories.Unit)]
[Fact]
public void StarterDay1Policy_HasRequiredFields()
{
var policyPath = Path.Combine(_testDataPath, "starter-day1.yaml");
var content = File.ReadAllText(policyPath);
var policy = _yamlDeserializer.Deserialize<Dictionary<string, object>>(content);
policy.Should().ContainKey("apiVersion", "Policy should have apiVersion field");
policy.Should().ContainKey("kind", "Policy should have kind field");
policy.Should().ContainKey("metadata", "Policy should have metadata field");
policy.Should().ContainKey("spec", "Policy should have spec field");
}
[Trait("Category", TestCategories.Unit)]
[Fact]
public void StarterDay1Policy_HasCorrectApiVersion()
{
var policyPath = Path.Combine(_testDataPath, "starter-day1.yaml");
var content = File.ReadAllText(policyPath);
var policy = _yamlDeserializer.Deserialize<Dictionary<string, object>>(content);
policy["apiVersion"].Should().Be("policy.stellaops.io/v1");
}
[Trait("Category", TestCategories.Unit)]
[Fact]
public void StarterDay1Policy_HasCorrectKind()
{
var policyPath = Path.Combine(_testDataPath, "starter-day1.yaml");
var content = File.ReadAllText(policyPath);
var policy = _yamlDeserializer.Deserialize<Dictionary<string, object>>(content);
policy["kind"].Should().Be("PolicyPack");
}
[Trait("Category", TestCategories.Unit)]
[Fact]
public void StarterDay1Policy_HasValidMetadata()
{
var policyPath = Path.Combine(_testDataPath, "starter-day1.yaml");
var content = File.ReadAllText(policyPath);
var policy = _yamlDeserializer.Deserialize<Dictionary<string, object>>(content);
var metadata = policy["metadata"] as Dictionary<object, object>;
metadata.Should().NotBeNull();
metadata!.Should().ContainKey("name");
metadata.Should().ContainKey("version");
metadata.Should().ContainKey("description");
metadata["name"].Should().Be("starter-day1");
metadata["version"].ToString().Should().MatchRegex(@"^\d+\.\d+\.\d+(-[a-zA-Z0-9]+)?$", "version should be semver");
}
[Trait("Category", TestCategories.Unit)]
[Fact]
public void StarterDay1Policy_HasRulesSection()
{
var policyPath = Path.Combine(_testDataPath, "starter-day1.yaml");
var content = File.ReadAllText(policyPath);
var policy = _yamlDeserializer.Deserialize<Dictionary<string, object>>(content);
var spec = policy["spec"] as Dictionary<object, object>;
spec.Should().NotBeNull();
spec!.Should().ContainKey("rules");
var rules = spec["rules"] as List<object>;
rules.Should().NotBeNull();
rules!.Should().HaveCountGreaterThan(0, "Policy should have at least one rule");
}
[Trait("Category", TestCategories.Unit)]
[Fact]
public void StarterDay1Policy_HasSettingsSection()
{
var policyPath = Path.Combine(_testDataPath, "starter-day1.yaml");
var content = File.ReadAllText(policyPath);
var policy = _yamlDeserializer.Deserialize<Dictionary<string, object>>(content);
var spec = policy["spec"] as Dictionary<object, object>;
spec.Should().NotBeNull();
spec!.Should().ContainKey("settings");
var settings = spec["settings"] as Dictionary<object, object>;
settings.Should().NotBeNull();
settings!.Should().ContainKey("defaultAction");
}
[Trait("Category", TestCategories.Unit)]
[Theory]
[InlineData("block-reachable-high-critical")]
[InlineData("warn-reachable-medium")]
[InlineData("allow-unreachable")]
[InlineData("fail-on-unknowns")]
[InlineData("block-kev")]
[InlineData("default-allow")]
public void StarterDay1Policy_ContainsExpectedRule(string ruleName)
{
var policyPath = Path.Combine(_testDataPath, "starter-day1.yaml");
var content = File.ReadAllText(policyPath);
var policy = _yamlDeserializer.Deserialize<Dictionary<string, object>>(content);
var spec = policy["spec"] as Dictionary<object, object>;
var rules = spec!["rules"] as List<object>;
var ruleNames = rules!.Cast<Dictionary<object, object>>()
.Select(r => r["name"]?.ToString())
.Where(n => n != null)
.ToList();
ruleNames.Should().Contain(ruleName, $"Policy should contain rule '{ruleName}'");
}
[Trait("Category", TestCategories.Unit)]
[Fact]
public void StarterDay1Policy_HasDefaultAllowRuleWithLowestPriority()
{
var policyPath = Path.Combine(_testDataPath, "starter-day1.yaml");
var content = File.ReadAllText(policyPath);
var policy = _yamlDeserializer.Deserialize<Dictionary<string, object>>(content);
var spec = policy["spec"] as Dictionary<object, object>;
var rules = spec!["rules"] as List<object>;
var defaultAllowRule = rules!.Cast<Dictionary<object, object>>()
.FirstOrDefault(r => r["name"]?.ToString() == "default-allow");
defaultAllowRule.Should().NotBeNull("Policy should have a default-allow rule");
var priority = Convert.ToInt32(defaultAllowRule!["priority"]);
priority.Should().Be(0, "default-allow rule should have the lowest priority (0)");
var action = defaultAllowRule["action"]?.ToString();
action.Should().Be("allow", "default-allow rule should have action 'allow'");
}
}