too much for one commit
This commit is contained in:
@@ -0,0 +1,609 @@
|
||||
using EntKube.Clusters.Domain;
|
||||
using EntKube.Clusters.Features.AdoptCluster;
|
||||
using EntKube.Clusters.Features.AdoptCluster.ConfigureComponent;
|
||||
using EntKube.Clusters.Features.AdoptCluster.DeployComponent;
|
||||
using EntKube.Clusters.Infrastructure;
|
||||
using EntKube.SharedKernel.Domain;
|
||||
using FluentAssertions;
|
||||
using Moq;
|
||||
|
||||
namespace EntKube.Clusters.Tests.Features;
|
||||
|
||||
/// <summary>
|
||||
/// Tests for the trust bundle and internal CA components. These two are co-dependent:
|
||||
///
|
||||
/// 1. **cert-manager** — prerequisite, already tested elsewhere
|
||||
/// 2. **trust-manager** — distributes CA bundles to namespaces via Bundle CRDs
|
||||
/// 3. **internal-ca** — provisions a self-signed CA ClusterIssuer via cert-manager,
|
||||
/// then adds its root certificate to the trust bundle
|
||||
///
|
||||
/// The dependency chain: cert-manager → internal-ca → trust-manager (bundle update)
|
||||
/// Both internal-ca and trust-manager require cert-manager to be installed first.
|
||||
/// </summary>
|
||||
public class TrustBundleAndInternalCATests
|
||||
{
|
||||
private readonly InMemoryClusterRepository repository;
|
||||
private readonly Mock<IComponentInstaller> trustManagerInstaller;
|
||||
private readonly Mock<IComponentInstaller> internalCaInstaller;
|
||||
|
||||
public TrustBundleAndInternalCATests()
|
||||
{
|
||||
repository = new InMemoryClusterRepository();
|
||||
|
||||
trustManagerInstaller = new Mock<IComponentInstaller>();
|
||||
trustManagerInstaller.Setup(i => i.ComponentName).Returns("trust-manager");
|
||||
|
||||
internalCaInstaller = new Mock<IComponentInstaller>();
|
||||
internalCaInstaller.Setup(i => i.ComponentName).Returns("internal-ca");
|
||||
}
|
||||
|
||||
// ─── Trust Manager Installer ──────────────────────────────────────────────
|
||||
|
||||
[Fact]
|
||||
public async Task TrustManager_Install_DeploysHelmAndCreatesBundle()
|
||||
{
|
||||
// Arrange — cert-manager is already installed. Now we deploy trust-manager
|
||||
// to distribute CA bundles cluster-wide.
|
||||
|
||||
KubernetesCluster cluster = CreateConnectedCluster();
|
||||
await repository.AddAsync(cluster);
|
||||
|
||||
trustManagerInstaller
|
||||
.Setup(i => i.InstallAsync(cluster, It.IsAny<ComponentInstallOptions>(), It.IsAny<CancellationToken>()))
|
||||
.ReturnsAsync(new InstallResult(
|
||||
Success: true,
|
||||
ComponentName: "trust-manager",
|
||||
Message: "trust-manager 0.14.0 installed with platform-trust-bundle Bundle",
|
||||
Actions: new List<string>
|
||||
{
|
||||
"Ensured namespace 'cert-manager'",
|
||||
"Helm install trust-manager v0.14.0",
|
||||
"Created Bundle 'platform-trust-bundle'"
|
||||
}));
|
||||
|
||||
DeployComponentHandler handler = new(repository, new List<IComponentInstaller>
|
||||
{
|
||||
trustManagerInstaller.Object, internalCaInstaller.Object
|
||||
}, Microsoft.Extensions.Logging.Abstractions.NullLogger<DeployComponentHandler>.Instance);
|
||||
|
||||
DeployComponentRequest request = new("trust-manager", Version: "0.14.0",
|
||||
Parameters: new Dictionary<string, string>
|
||||
{
|
||||
["bundleName"] = "platform-trust-bundle",
|
||||
["targetNamespaces"] = "*"
|
||||
});
|
||||
|
||||
// Act
|
||||
|
||||
Result<InstallResult> result = await handler.HandleAsync(cluster.Id, request);
|
||||
|
||||
// Assert — trust-manager installed and Bundle CR created.
|
||||
|
||||
result.IsSuccess.Should().BeTrue();
|
||||
result.Value!.ComponentName.Should().Be("trust-manager");
|
||||
result.Value.Actions.Should().Contain(a => a.Contains("Bundle"));
|
||||
|
||||
trustManagerInstaller.Verify(i => i.InstallAsync(
|
||||
cluster,
|
||||
It.Is<ComponentInstallOptions>(o =>
|
||||
o.Version == "0.14.0" &&
|
||||
o.Parameters!["bundleName"] == "platform-trust-bundle"),
|
||||
It.IsAny<CancellationToken>()), Times.Once);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task TrustManager_Configure_AddsCertificatesToBundle()
|
||||
{
|
||||
// Arrange — trust-manager is installed. We want to add extra CA certificates
|
||||
// to the platform trust bundle (e.g., corporate PKI, external services).
|
||||
|
||||
KubernetesCluster cluster = CreateConnectedCluster();
|
||||
await repository.AddAsync(cluster);
|
||||
|
||||
trustManagerInstaller
|
||||
.Setup(i => i.ConfigureAsync(cluster, It.IsAny<ComponentConfiguration>(), It.IsAny<CancellationToken>()))
|
||||
.ReturnsAsync(new InstallResult(
|
||||
Success: true,
|
||||
ComponentName: "trust-manager",
|
||||
Message: "Trust bundle updated with 2 additional certificates",
|
||||
Actions: new List<string>
|
||||
{
|
||||
"Added certificate 'corporate-root-ca' to bundle",
|
||||
"Added certificate 'partner-api-ca' to bundle"
|
||||
}));
|
||||
|
||||
List<IComponentInstaller> installers = new() { trustManagerInstaller.Object, internalCaInstaller.Object };
|
||||
ConfigureComponentHandler configHandler = new(repository, installers);
|
||||
|
||||
// Act — The user adds managed certificates to the trust bundle.
|
||||
|
||||
ConfigureComponentRequest configRequest = new(
|
||||
ComponentName: "trust-manager",
|
||||
Values: new Dictionary<string, string>
|
||||
{
|
||||
["additionalCertificates"] = "corporate-root-ca:LS0tLS1CRUdJTi...;partner-api-ca:LS0tLS1CRUdJTi...",
|
||||
["bundleName"] = "platform-trust-bundle"
|
||||
});
|
||||
|
||||
Result<InstallResult> result = await configHandler.HandleAsync(cluster.Id, configRequest);
|
||||
|
||||
// Assert
|
||||
|
||||
result.IsSuccess.Should().BeTrue();
|
||||
result.Value!.Actions.Should().Contain(a => a.Contains("corporate-root-ca"));
|
||||
}
|
||||
|
||||
// ─── Internal CA ──────────────────────────────────────────────────────────
|
||||
|
||||
[Fact]
|
||||
public async Task InternalCA_Install_CreatesSelfSignedCAAndAddsToBundle()
|
||||
{
|
||||
// Arrange — cert-manager and trust-manager are installed. Now we create
|
||||
// an internal CA that signs service certificates and whose root is
|
||||
// distributed via the trust bundle.
|
||||
|
||||
KubernetesCluster cluster = CreateConnectedCluster();
|
||||
await repository.AddAsync(cluster);
|
||||
|
||||
internalCaInstaller
|
||||
.Setup(i => i.InstallAsync(cluster, It.IsAny<ComponentInstallOptions>(), It.IsAny<CancellationToken>()))
|
||||
.ReturnsAsync(new InstallResult(
|
||||
Success: true,
|
||||
ComponentName: "internal-ca",
|
||||
Message: "Internal CA provisioned and added to trust bundle",
|
||||
Actions: new List<string>
|
||||
{
|
||||
"Created self-signed ClusterIssuer 'selfsigned-bootstrap'",
|
||||
"Created root CA Certificate 'platform-internal-ca'",
|
||||
"Created CA ClusterIssuer 'internal-ca'",
|
||||
"Added root CA to Bundle 'platform-trust-bundle'"
|
||||
}));
|
||||
|
||||
DeployComponentHandler handler = new(repository, new List<IComponentInstaller>
|
||||
{
|
||||
trustManagerInstaller.Object, internalCaInstaller.Object
|
||||
}, Microsoft.Extensions.Logging.Abstractions.NullLogger<DeployComponentHandler>.Instance);
|
||||
|
||||
DeployComponentRequest request = new("internal-ca",
|
||||
Parameters: new Dictionary<string, string>
|
||||
{
|
||||
["caName"] = "platform-internal-ca",
|
||||
["bundleName"] = "platform-trust-bundle",
|
||||
["caOrganization"] = "EntKube Platform",
|
||||
["caDurationDays"] = "3650"
|
||||
});
|
||||
|
||||
// Act
|
||||
|
||||
Result<InstallResult> result = await handler.HandleAsync(cluster.Id, request);
|
||||
|
||||
// Assert — CA created and injected into trust bundle.
|
||||
|
||||
result.IsSuccess.Should().BeTrue();
|
||||
result.Value!.Actions.Should().Contain(a => a.Contains("ClusterIssuer 'internal-ca'"));
|
||||
result.Value.Actions.Should().Contain(a => a.Contains("Bundle"));
|
||||
|
||||
internalCaInstaller.Verify(i => i.InstallAsync(
|
||||
cluster,
|
||||
It.Is<ComponentInstallOptions>(o =>
|
||||
o.Parameters!["caName"] == "platform-internal-ca" &&
|
||||
o.Parameters["bundleName"] == "platform-trust-bundle"),
|
||||
It.IsAny<CancellationToken>()), Times.Once);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task InternalCA_Adopt_DiscoversExistingCAAndRegistersInBundle()
|
||||
{
|
||||
// Arrange — A cluster already has a CA ClusterIssuer. The adoption check
|
||||
// should discover it and register its root cert in the trust bundle.
|
||||
|
||||
KubernetesCluster cluster = CreateConnectedCluster();
|
||||
await repository.AddAsync(cluster);
|
||||
|
||||
internalCaInstaller
|
||||
.Setup(i => i.InstallAsync(cluster, It.IsAny<ComponentInstallOptions>(), It.IsAny<CancellationToken>()))
|
||||
.ReturnsAsync(new InstallResult(
|
||||
Success: true,
|
||||
ComponentName: "internal-ca",
|
||||
Message: "Existing internal CA adopted and added to trust bundle",
|
||||
Actions: new List<string>
|
||||
{
|
||||
"Discovered existing CA ClusterIssuer 'existing-ca'",
|
||||
"Read root CA certificate from Secret 'existing-ca-secret'",
|
||||
"Added root CA to Bundle 'platform-trust-bundle'"
|
||||
}));
|
||||
|
||||
DeployComponentHandler handler = new(repository, new List<IComponentInstaller>
|
||||
{
|
||||
trustManagerInstaller.Object, internalCaInstaller.Object
|
||||
}, Microsoft.Extensions.Logging.Abstractions.NullLogger<DeployComponentHandler>.Instance);
|
||||
|
||||
DeployComponentRequest request = new("internal-ca",
|
||||
Parameters: new Dictionary<string, string>
|
||||
{
|
||||
["adoptExisting"] = "true",
|
||||
["existingIssuerName"] = "existing-ca",
|
||||
["bundleName"] = "platform-trust-bundle"
|
||||
});
|
||||
|
||||
// Act
|
||||
|
||||
Result<InstallResult> result = await handler.HandleAsync(cluster.Id, request);
|
||||
|
||||
// Assert — Existing CA adopted and cert added to bundle.
|
||||
|
||||
result.IsSuccess.Should().BeTrue();
|
||||
result.Value!.Actions.Should().Contain(a => a.Contains("Discovered existing CA"));
|
||||
result.Value.Actions.Should().Contain(a => a.Contains("Bundle"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task InternalCA_Configure_RotatesCACertificate()
|
||||
{
|
||||
// Arrange — The internal CA already exists. We want to configure it
|
||||
// (e.g., update the duration or rotate the CA cert).
|
||||
|
||||
KubernetesCluster cluster = CreateConnectedCluster();
|
||||
await repository.AddAsync(cluster);
|
||||
|
||||
internalCaInstaller
|
||||
.Setup(i => i.ConfigureAsync(cluster, It.IsAny<ComponentConfiguration>(), It.IsAny<CancellationToken>()))
|
||||
.ReturnsAsync(new InstallResult(
|
||||
Success: true,
|
||||
ComponentName: "internal-ca",
|
||||
Message: "Internal CA reconfigured",
|
||||
Actions: new List<string>
|
||||
{
|
||||
"Updated CA Certificate duration to 7300 days",
|
||||
"Refreshed root CA in Bundle 'platform-trust-bundle'"
|
||||
}));
|
||||
|
||||
DeployComponentHandler handler = new(repository, new List<IComponentInstaller>
|
||||
{
|
||||
trustManagerInstaller.Object, internalCaInstaller.Object
|
||||
}, Microsoft.Extensions.Logging.Abstractions.NullLogger<DeployComponentHandler>.Instance);
|
||||
|
||||
// Act
|
||||
|
||||
ComponentConfiguration config = new("cert-manager", new Dictionary<string, string>
|
||||
{
|
||||
["caDurationDays"] = "7300",
|
||||
["bundleName"] = "platform-trust-bundle"
|
||||
});
|
||||
|
||||
// Use the configure path through the deploy handler
|
||||
// (the handler routes based on whether the component is already installed)
|
||||
|
||||
internalCaInstaller
|
||||
.Setup(i => i.InstallAsync(cluster, It.IsAny<ComponentInstallOptions>(), It.IsAny<CancellationToken>()))
|
||||
.ReturnsAsync(new InstallResult(
|
||||
Success: true,
|
||||
ComponentName: "internal-ca",
|
||||
Message: "Internal CA reconfigured",
|
||||
Actions: new List<string>
|
||||
{
|
||||
"Updated CA Certificate duration to 7300 days",
|
||||
"Refreshed root CA in Bundle 'platform-trust-bundle'"
|
||||
}));
|
||||
|
||||
DeployComponentRequest request = new("internal-ca",
|
||||
Parameters: config.Values);
|
||||
|
||||
Result<InstallResult> result = await handler.HandleAsync(cluster.Id, request);
|
||||
|
||||
// Assert
|
||||
|
||||
result.IsSuccess.Should().BeTrue();
|
||||
}
|
||||
|
||||
// ─── Dependency Chain ─────────────────────────────────────────────────────
|
||||
|
||||
[Fact]
|
||||
public async Task InternalCA_WithoutCertManager_ReportsFailure()
|
||||
{
|
||||
// Arrange — cert-manager is NOT installed. internal-ca cannot function.
|
||||
|
||||
KubernetesCluster cluster = CreateConnectedCluster();
|
||||
await repository.AddAsync(cluster);
|
||||
|
||||
internalCaInstaller
|
||||
.Setup(i => i.InstallAsync(cluster, It.IsAny<ComponentInstallOptions>(), It.IsAny<CancellationToken>()))
|
||||
.ReturnsAsync(new InstallResult(
|
||||
Success: false,
|
||||
ComponentName: "internal-ca",
|
||||
Message: "cert-manager is required but not installed",
|
||||
Actions: new List<string> { "Prerequisite check failed: cert-manager not found" }));
|
||||
|
||||
DeployComponentHandler handler = new(repository, new List<IComponentInstaller>
|
||||
{
|
||||
trustManagerInstaller.Object, internalCaInstaller.Object
|
||||
}, Microsoft.Extensions.Logging.Abstractions.NullLogger<DeployComponentHandler>.Instance);
|
||||
|
||||
DeployComponentRequest request = new("internal-ca",
|
||||
Parameters: new Dictionary<string, string>
|
||||
{
|
||||
["caName"] = "platform-internal-ca",
|
||||
["bundleName"] = "platform-trust-bundle"
|
||||
});
|
||||
|
||||
// Act
|
||||
|
||||
Result<InstallResult> result = await handler.HandleAsync(cluster.Id, request);
|
||||
|
||||
// Assert — DeployComponentHandler wraps a failed InstallResult in Result.Failure.
|
||||
|
||||
result.IsFailure.Should().BeTrue();
|
||||
result.Error.Should().Contain("cert-manager");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task TrustManager_AddManagedCertificate_UpdatesBundleWithNewCert()
|
||||
{
|
||||
// Arrange — trust-manager is installed. We add a new managed certificate
|
||||
// (e.g., a partner's CA cert that our services need to trust).
|
||||
|
||||
KubernetesCluster cluster = CreateConnectedCluster();
|
||||
await repository.AddAsync(cluster);
|
||||
|
||||
trustManagerInstaller
|
||||
.Setup(i => i.ConfigureAsync(cluster, It.IsAny<ComponentConfiguration>(), It.IsAny<CancellationToken>()))
|
||||
.ReturnsAsync(new InstallResult(
|
||||
Success: true,
|
||||
ComponentName: "trust-manager",
|
||||
Message: "Certificate added to trust bundle",
|
||||
Actions: new List<string>
|
||||
{
|
||||
"Created ConfigMap 'managed-cert-partner-api' with certificate data",
|
||||
"Updated Bundle 'platform-trust-bundle' to include new source"
|
||||
}));
|
||||
|
||||
// Use the configure handler path (component already installed)
|
||||
|
||||
List<IComponentInstaller> installers = new() { trustManagerInstaller.Object, internalCaInstaller.Object };
|
||||
ConfigureComponentHandler configHandler = new(repository, installers);
|
||||
|
||||
ConfigureComponentRequest configRequest = new(
|
||||
ComponentName: "trust-manager",
|
||||
Values: new Dictionary<string, string>
|
||||
{
|
||||
["addCertificate"] = "true",
|
||||
["certificateName"] = "partner-api",
|
||||
["certificateData"] = "LS0tLS1CRUdJTi...",
|
||||
["bundleName"] = "platform-trust-bundle"
|
||||
});
|
||||
|
||||
// Act
|
||||
|
||||
Result<InstallResult> result = await configHandler.HandleAsync(cluster.Id, configRequest);
|
||||
|
||||
// Assert — Certificate stored and bundle updated to reference it.
|
||||
|
||||
result.IsSuccess.Should().BeTrue();
|
||||
result.Value!.Actions.Should().Contain(a => a.Contains("ConfigMap"));
|
||||
result.Value.Actions.Should().Contain(a => a.Contains("Bundle"));
|
||||
}
|
||||
|
||||
// ─── Domain-Scoped CA ───────────────────────────────────────────────────
|
||||
|
||||
[Fact]
|
||||
public async Task DomainCA_Install_CreatesSeparateCAForInternalDomains()
|
||||
{
|
||||
// Arrange — The platform already has an internal-ca for service mesh certs.
|
||||
// Now the team wants a SEPARATE CA specifically for *.internal.corp.com
|
||||
// so they can issue certs for internal services on that domain.
|
||||
|
||||
KubernetesCluster cluster = CreateConnectedCluster();
|
||||
await repository.AddAsync(cluster);
|
||||
|
||||
Mock<IComponentInstaller> domainCaInstaller = new();
|
||||
domainCaInstaller.Setup(i => i.ComponentName).Returns("domain-ca");
|
||||
|
||||
domainCaInstaller
|
||||
.Setup(i => i.InstallAsync(cluster, It.IsAny<ComponentInstallOptions>(), It.IsAny<CancellationToken>()))
|
||||
.ReturnsAsync(new InstallResult(
|
||||
Success: true,
|
||||
ComponentName: "domain-ca",
|
||||
Message: "Domain CA 'corp-internal-ca' provisioned for *.internal.corp.com",
|
||||
Actions: new List<string>
|
||||
{
|
||||
"Created root CA Certificate 'corp-internal-ca'",
|
||||
"Created CA ClusterIssuer 'corp-internal-ca'",
|
||||
"Created Certificate policy: only signs for [*.internal.corp.com, *.svc.corp.local]",
|
||||
"Added root CA to Bundle 'platform-trust-bundle'"
|
||||
}));
|
||||
|
||||
DeployComponentHandler handler = new(repository, new List<IComponentInstaller>
|
||||
{
|
||||
trustManagerInstaller.Object, internalCaInstaller.Object, domainCaInstaller.Object
|
||||
}, Microsoft.Extensions.Logging.Abstractions.NullLogger<DeployComponentHandler>.Instance);
|
||||
|
||||
DeployComponentRequest request = new("domain-ca",
|
||||
Parameters: new Dictionary<string, string>
|
||||
{
|
||||
["caName"] = "corp-internal-ca",
|
||||
["domains"] = "*.internal.corp.com,*.svc.corp.local",
|
||||
["caOrganization"] = "Corp Internal",
|
||||
["caDurationDays"] = "1825",
|
||||
["bundleName"] = "platform-trust-bundle"
|
||||
});
|
||||
|
||||
// Act
|
||||
|
||||
Result<InstallResult> result = await handler.HandleAsync(cluster.Id, request);
|
||||
|
||||
// Assert — Separate domain CA created with scope restrictions.
|
||||
|
||||
result.IsSuccess.Should().BeTrue();
|
||||
result.Value!.Actions.Should().Contain(a => a.Contains("ClusterIssuer 'corp-internal-ca'"));
|
||||
result.Value.Actions.Should().Contain(a => a.Contains("policy"));
|
||||
result.Value.Actions.Should().Contain(a => a.Contains("Bundle"));
|
||||
|
||||
domainCaInstaller.Verify(i => i.InstallAsync(
|
||||
cluster,
|
||||
It.Is<ComponentInstallOptions>(o =>
|
||||
o.Parameters!["caName"] == "corp-internal-ca" &&
|
||||
o.Parameters["domains"] == "*.internal.corp.com,*.svc.corp.local"),
|
||||
It.IsAny<CancellationToken>()), Times.Once);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task DomainCA_ImportExternalCA_CreatesIssuerFromProvidedCertAndKey()
|
||||
{
|
||||
// Arrange — The team has a public SSL cert from DigiCert for *.example.com
|
||||
// and wants to use it as a CA/issuer for subdomains, or simply wants
|
||||
// cert-manager to serve this cert for ingress. We import it.
|
||||
|
||||
KubernetesCluster cluster = CreateConnectedCluster();
|
||||
await repository.AddAsync(cluster);
|
||||
|
||||
Mock<IComponentInstaller> domainCaInstaller = new();
|
||||
domainCaInstaller.Setup(i => i.ComponentName).Returns("domain-ca");
|
||||
|
||||
domainCaInstaller
|
||||
.Setup(i => i.InstallAsync(cluster, It.IsAny<ComponentInstallOptions>(), It.IsAny<CancellationToken>()))
|
||||
.ReturnsAsync(new InstallResult(
|
||||
Success: true,
|
||||
ComponentName: "domain-ca",
|
||||
Message: "External CA 'digicert-example-com' imported for *.example.com",
|
||||
Actions: new List<string>
|
||||
{
|
||||
"Created TLS Secret 'digicert-example-com-tls' with imported cert+key",
|
||||
"Created CA ClusterIssuer 'digicert-example-com'",
|
||||
"Added CA certificate to Bundle 'platform-trust-bundle'"
|
||||
}));
|
||||
|
||||
DeployComponentHandler handler = new(repository, new List<IComponentInstaller>
|
||||
{
|
||||
trustManagerInstaller.Object, internalCaInstaller.Object, domainCaInstaller.Object
|
||||
}, Microsoft.Extensions.Logging.Abstractions.NullLogger<DeployComponentHandler>.Instance);
|
||||
|
||||
DeployComponentRequest request = new("domain-ca",
|
||||
Parameters: new Dictionary<string, string>
|
||||
{
|
||||
["caName"] = "digicert-example-com",
|
||||
["importExternal"] = "true",
|
||||
["tlsCert"] = "LS0tLS1CRUdJTi...", // base64 PEM cert
|
||||
["tlsKey"] = "LS0tLS1CRUdJTi...", // base64 PEM key
|
||||
["domains"] = "*.example.com",
|
||||
["bundleName"] = "platform-trust-bundle"
|
||||
});
|
||||
|
||||
// Act
|
||||
|
||||
Result<InstallResult> result = await handler.HandleAsync(cluster.Id, request);
|
||||
|
||||
// Assert — External cert imported, ClusterIssuer created, trust bundle updated.
|
||||
|
||||
result.IsSuccess.Should().BeTrue();
|
||||
result.Value!.Actions.Should().Contain(a => a.Contains("TLS Secret"));
|
||||
result.Value.Actions.Should().Contain(a => a.Contains("ClusterIssuer"));
|
||||
result.Value.Actions.Should().Contain(a => a.Contains("Bundle"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task DomainCA_ImportExternalCertOnly_AddsToBundleWithoutIssuer()
|
||||
{
|
||||
// Arrange — The team has an external CA root cert (no private key) that
|
||||
// services need to trust (e.g., partner API CA). We just need it in the
|
||||
// trust bundle — no ClusterIssuer needed since we can't sign certs with it.
|
||||
|
||||
KubernetesCluster cluster = CreateConnectedCluster();
|
||||
await repository.AddAsync(cluster);
|
||||
|
||||
Mock<IComponentInstaller> domainCaInstaller = new();
|
||||
domainCaInstaller.Setup(i => i.ComponentName).Returns("domain-ca");
|
||||
|
||||
domainCaInstaller
|
||||
.Setup(i => i.InstallAsync(cluster, It.IsAny<ComponentInstallOptions>(), It.IsAny<CancellationToken>()))
|
||||
.ReturnsAsync(new InstallResult(
|
||||
Success: true,
|
||||
ComponentName: "domain-ca",
|
||||
Message: "External CA certificate 'partner-root-ca' added to trust bundle",
|
||||
Actions: new List<string>
|
||||
{
|
||||
"Created ConfigMap 'managed-cert-partner-root-ca' with CA certificate",
|
||||
"Added certificate to Bundle 'platform-trust-bundle'",
|
||||
"No ClusterIssuer created (no private key provided — trust-only)"
|
||||
}));
|
||||
|
||||
DeployComponentHandler handler = new(repository, new List<IComponentInstaller>
|
||||
{
|
||||
trustManagerInstaller.Object, internalCaInstaller.Object, domainCaInstaller.Object
|
||||
}, Microsoft.Extensions.Logging.Abstractions.NullLogger<DeployComponentHandler>.Instance);
|
||||
|
||||
DeployComponentRequest request = new("domain-ca",
|
||||
Parameters: new Dictionary<string, string>
|
||||
{
|
||||
["caName"] = "partner-root-ca",
|
||||
["importExternal"] = "true",
|
||||
["tlsCert"] = "LS0tLS1CRUdJTi...", // cert only, no key
|
||||
["bundleName"] = "platform-trust-bundle"
|
||||
});
|
||||
|
||||
// Act
|
||||
|
||||
Result<InstallResult> result = await handler.HandleAsync(cluster.Id, request);
|
||||
|
||||
// Assert — Cert added to trust bundle but no issuer (can't sign without key).
|
||||
|
||||
result.IsSuccess.Should().BeTrue();
|
||||
result.Value!.Actions.Should().Contain(a => a.Contains("trust-only"));
|
||||
result.Value.Actions.Should().NotContain(a => a.Contains("ClusterIssuer 'partner-root-ca'") && !a.Contains("No ClusterIssuer"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task DomainCA_Configure_UpdatesDomainRestrictions()
|
||||
{
|
||||
// Arrange — An existing domain CA needs its allowed domains updated.
|
||||
|
||||
KubernetesCluster cluster = CreateConnectedCluster();
|
||||
await repository.AddAsync(cluster);
|
||||
|
||||
Mock<IComponentInstaller> domainCaInstaller = new();
|
||||
domainCaInstaller.Setup(i => i.ComponentName).Returns("domain-ca");
|
||||
|
||||
domainCaInstaller
|
||||
.Setup(i => i.ConfigureAsync(cluster, It.IsAny<ComponentConfiguration>(), It.IsAny<CancellationToken>()))
|
||||
.ReturnsAsync(new InstallResult(
|
||||
Success: true,
|
||||
ComponentName: "domain-ca",
|
||||
Message: "Domain CA 'corp-internal-ca' reconfigured",
|
||||
Actions: new List<string>
|
||||
{
|
||||
"Updated Certificate policy: [*.internal.corp.com, *.new-domain.corp.com]"
|
||||
}));
|
||||
|
||||
List<IComponentInstaller> installers = new()
|
||||
{
|
||||
trustManagerInstaller.Object, internalCaInstaller.Object, domainCaInstaller.Object
|
||||
};
|
||||
ConfigureComponentHandler configHandler = new(repository, installers);
|
||||
|
||||
ConfigureComponentRequest configRequest = new(
|
||||
ComponentName: "domain-ca",
|
||||
Values: new Dictionary<string, string>
|
||||
{
|
||||
["caName"] = "corp-internal-ca",
|
||||
["domains"] = "*.internal.corp.com,*.new-domain.corp.com"
|
||||
});
|
||||
|
||||
// Act
|
||||
|
||||
Result<InstallResult> result = await configHandler.HandleAsync(cluster.Id, configRequest);
|
||||
|
||||
// Assert
|
||||
|
||||
result.IsSuccess.Should().BeTrue();
|
||||
result.Value!.Actions.Should().Contain(a => a.Contains("new-domain"));
|
||||
}
|
||||
|
||||
private static KubernetesCluster CreateConnectedCluster()
|
||||
{
|
||||
KubernetesCluster cluster = KubernetesCluster.Register(
|
||||
"prod-cluster", "https://k8s.example.com:6443",
|
||||
"apiVersion: v1\nkind: Config\nclusters: []\nusers: []\ncontexts: []",
|
||||
Guid.NewGuid(), "prod-ctx", Guid.NewGuid());
|
||||
cluster.MarkConnected();
|
||||
return cluster;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user