using System.Text.Json; using EntKube.Clusters.Features.AdoptCluster.Components.SecurityPolicies; using EntKube.Clusters.Features.ClusterSettings; using FluentAssertions; namespace EntKube.Clusters.Tests.Features; /// /// Tests the JSON parsing logic that extracts allowed registries from a Kyverno /// ClusterPolicy. This is the core logic that reads the restrict-image-registries /// policy and returns the list of approved registries. /// public class KyvernoClusterSettingsProviderTests { [Fact] public void ExtractRegistries_WithValidPolicy_ReturnsRegistryList() { // Arrange — a policy JSON with three allowed registries. string json = """ { "spec": { "validationFailureAction": "Audit", "rules": [{ "name": "validate-image-registry", "validate": { "foreach": [{ "list": "request.object.spec.[initContainers, containers][]", "deny": { "conditions": { "all": [ { "key": "{{ element.image }}", "operator": "NotEquals", "value": "docker.io/*" }, { "key": "{{ element.image }}", "operator": "NotEquals", "value": "ghcr.io/*" }, { "key": "{{ element.image }}", "operator": "NotEquals", "value": "registry.k8s.io/*" } ] } } }] } }] } } """; // Act List registries = KyvernoClusterSettingsProvider.ExtractRegistriesFromPolicyJson(json); // Assert registries.Should().BeEquivalentTo(new[] { "docker.io", "ghcr.io", "registry.k8s.io" }); } [Fact] public void ExtractRegistries_WithEmptyJson_ReturnsEmptyList() { // Act List registries = KyvernoClusterSettingsProvider.ExtractRegistriesFromPolicyJson("{}"); // Assert registries.Should().BeEmpty(); } [Fact] public void ExtractRegistries_WithMalformedJson_ReturnsEmptyList() { // Act List registries = KyvernoClusterSettingsProvider.ExtractRegistriesFromPolicyJson("not json"); // Assert registries.Should().BeEmpty(); } [Fact] public void ExtractRegistries_WithNoPolicyRules_ReturnsEmptyList() { // Arrange string json = """{ "spec": { "rules": [] } }"""; // Act List registries = KyvernoClusterSettingsProvider.ExtractRegistriesFromPolicyJson(json); // Assert registries.Should().BeEmpty(); } // ─── Round-trip tests ────────────────────────────────────────────────── [Fact] public void BuildRegistryPolicy_RoundTrip_PreservesRegistries() { // When the settings provider writes a policy and then reads it back, // the extracted registries should match what was written. This simulates // the full Kubernetes API round-trip: build → serialize → parse. // Arrange — a custom list of registries. List registries = new() { "docker.io", "ghcr.io", "myregistry.example.com" }; // Act — build the policy, serialize it to JSON (simulating K8s storage), // then extract registries back out. object policy = KyvernoClusterSettingsProvider.BuildRegistryPolicy(registries, "test message", "Audit"); string json = JsonSerializer.Serialize(policy); List extracted = KyvernoClusterSettingsProvider.ExtractRegistriesFromPolicyJson(json); // Assert — the registries should survive the round-trip intact. extracted.Should().BeEquivalentTo(registries); } [Fact] public void BuildRegistryPolicy_IncludesExcludeBlock() { // The policy must include the exclude block so system namespaces // (kube-system, cert-manager, etc.) are not subject to registry // restrictions. Without this, saving registries via the Settings tab // would create a policy that differs from the installer's policy and // could break system pods. // Arrange List registries = new() { "docker.io" }; // Act object policy = KyvernoClusterSettingsProvider.BuildRegistryPolicy(registries, "test", "Audit"); string json = JsonSerializer.Serialize(policy); using JsonDocument doc = JsonDocument.Parse(json); // Assert — the rule should have an "exclude" block with namespace exclusions. JsonElement rule = doc.RootElement .GetProperty("spec") .GetProperty("rules")[0]; rule.TryGetProperty("exclude", out JsonElement exclude).Should().BeTrue( "the policy rule must include an exclude block to protect system namespaces"); string excludeJson = exclude.GetRawText(); excludeJson.Should().Contain("kube-system"); } [Fact] public void BuildRegistryPolicy_IncludesManagedByLabels() { // The policy labels must match what the SecurityPoliciesInstaller creates // so the installer can find and replace the policy during reconfiguration. // Arrange List registries = new() { "docker.io" }; // Act object policy = KyvernoClusterSettingsProvider.BuildRegistryPolicy(registries, "test", "Enforce"); string json = JsonSerializer.Serialize(policy); using JsonDocument doc = JsonDocument.Parse(json); // Assert — should have both managed-by and part-of labels. JsonElement labels = doc.RootElement .GetProperty("metadata") .GetProperty("labels"); labels.GetProperty("app.kubernetes.io/managed-by").GetString().Should().Be("entkube"); labels.GetProperty("app.kubernetes.io/part-of").GetString().Should().Be("security-policies"); } }