233 lines
7.3 KiB
C#
233 lines
7.3 KiB
C#
using EntKube.Secrets.Domain;
|
|
using FluentAssertions;
|
|
|
|
namespace EntKube.Secrets.Tests.Domain;
|
|
|
|
public class SecretScopeTests
|
|
{
|
|
// ─── Factory Method Tests ────────────────────────────────────────────
|
|
|
|
[Fact]
|
|
public void ForCluster_CreatesInfrastructureScope()
|
|
{
|
|
// Arrange — Infrastructure secrets are scoped to Tenant + Environment + Cluster.
|
|
// These are things like kubeconfig credentials, DNS tokens, cloud provider secrets.
|
|
|
|
Guid tenantId = Guid.NewGuid();
|
|
Guid environmentId = Guid.NewGuid();
|
|
Guid clusterId = Guid.NewGuid();
|
|
|
|
// Act
|
|
|
|
SecretScope scope = SecretScope.ForCluster(tenantId, environmentId, clusterId);
|
|
|
|
// Assert
|
|
|
|
scope.TenantId.Should().Be(tenantId);
|
|
scope.EnvironmentId.Should().Be(environmentId);
|
|
scope.ClusterId.Should().Be(clusterId);
|
|
scope.CustomerId.Should().BeNull();
|
|
scope.AppName.Should().BeNull();
|
|
}
|
|
|
|
[Fact]
|
|
public void ForApp_CreatesApplicationScope()
|
|
{
|
|
// Arrange — Application secrets are scoped to Tenant + Customer + App + Environment.
|
|
// These are things like database connection strings, API keys for third-party services.
|
|
|
|
Guid tenantId = Guid.NewGuid();
|
|
Guid customerId = Guid.NewGuid();
|
|
Guid environmentId = Guid.NewGuid();
|
|
|
|
// Act
|
|
|
|
SecretScope scope = SecretScope.ForApp(tenantId, customerId, "my-api", environmentId);
|
|
|
|
// Assert
|
|
|
|
scope.TenantId.Should().Be(tenantId);
|
|
scope.EnvironmentId.Should().Be(environmentId);
|
|
scope.ClusterId.Should().BeNull();
|
|
scope.CustomerId.Should().Be(customerId);
|
|
scope.AppName.Should().Be("my-api");
|
|
}
|
|
|
|
// ─── Record Construction Tests ───────────────────────────────────────
|
|
|
|
[Fact]
|
|
public void Create_WithAllFields_StoresAllValues()
|
|
{
|
|
// Arrange — A fully-scoped secret with all fields populated.
|
|
|
|
Guid tenantId = Guid.NewGuid();
|
|
Guid environmentId = Guid.NewGuid();
|
|
Guid clusterId = Guid.NewGuid();
|
|
Guid customerId = Guid.NewGuid();
|
|
|
|
// Act
|
|
|
|
SecretScope scope = new(tenantId, environmentId, clusterId, customerId, "my-api");
|
|
|
|
// Assert
|
|
|
|
scope.TenantId.Should().Be(tenantId);
|
|
scope.EnvironmentId.Should().Be(environmentId);
|
|
scope.ClusterId.Should().Be(clusterId);
|
|
scope.CustomerId.Should().Be(customerId);
|
|
scope.AppName.Should().Be("my-api");
|
|
}
|
|
|
|
[Fact]
|
|
public void Create_WithTenantOnly_AllowsNullOptionalFields()
|
|
{
|
|
// Arrange & Act — A tenant-wide secret (e.g. a shared API key)
|
|
// that isn't scoped to a specific environment, cluster, customer, or app.
|
|
|
|
Guid tenantId = Guid.NewGuid();
|
|
SecretScope scope = new(tenantId, null, null, null, null);
|
|
|
|
// Assert
|
|
|
|
scope.TenantId.Should().Be(tenantId);
|
|
scope.EnvironmentId.Should().BeNull();
|
|
scope.ClusterId.Should().BeNull();
|
|
scope.CustomerId.Should().BeNull();
|
|
scope.AppName.Should().BeNull();
|
|
}
|
|
|
|
[Fact]
|
|
public void Create_WithTenantAndEnvironment_ScopesToEnvironment()
|
|
{
|
|
// Arrange & Act — A secret scoped to a tenant + environment
|
|
// (e.g. a dev database password shared across all customers in dev).
|
|
|
|
Guid tenantId = Guid.NewGuid();
|
|
Guid environmentId = Guid.NewGuid();
|
|
SecretScope scope = new(tenantId, environmentId, null, null, null);
|
|
|
|
// Assert
|
|
|
|
scope.TenantId.Should().Be(tenantId);
|
|
scope.EnvironmentId.Should().Be(environmentId);
|
|
scope.ClusterId.Should().BeNull();
|
|
scope.CustomerId.Should().BeNull();
|
|
scope.AppName.Should().BeNull();
|
|
}
|
|
|
|
// ─── BuildPath Tests ─────────────────────────────────────────────────
|
|
|
|
[Fact]
|
|
public void BuildPath_TenantOnly_ReturnsPathWithTenantPrefix()
|
|
{
|
|
// Arrange — A tenant-scoped secret should have a path like
|
|
// "tenants/{tenantId}/secrets/my-key".
|
|
|
|
Guid tenantId = Guid.NewGuid();
|
|
SecretScope scope = new(tenantId, null, null, null, null);
|
|
|
|
// Act
|
|
|
|
string path = scope.BuildPath("my-key");
|
|
|
|
// Assert
|
|
|
|
path.Should().Be($"tenants/{tenantId}/secrets/my-key");
|
|
}
|
|
|
|
[Fact]
|
|
public void BuildPath_TenantAndEnvironment_ReturnsEnvironmentScopedPath()
|
|
{
|
|
// Arrange
|
|
|
|
Guid tenantId = Guid.NewGuid();
|
|
Guid environmentId = Guid.NewGuid();
|
|
SecretScope scope = new(tenantId, environmentId, null, null, null);
|
|
|
|
// Act
|
|
|
|
string path = scope.BuildPath("db-password");
|
|
|
|
// Assert
|
|
|
|
path.Should().Be($"tenants/{tenantId}/environments/{environmentId}/secrets/db-password");
|
|
}
|
|
|
|
[Fact]
|
|
public void BuildPath_ClusterScope_ReturnsClusterScopedPath()
|
|
{
|
|
// Arrange — Infrastructure secret scoped to a specific cluster.
|
|
|
|
Guid tenantId = Guid.NewGuid();
|
|
Guid environmentId = Guid.NewGuid();
|
|
Guid clusterId = Guid.NewGuid();
|
|
SecretScope scope = SecretScope.ForCluster(tenantId, environmentId, clusterId);
|
|
|
|
// Act
|
|
|
|
string path = scope.BuildPath("dns-credential");
|
|
|
|
// Assert — Path includes the cluster segment.
|
|
|
|
path.Should().Be(
|
|
$"tenants/{tenantId}/environments/{environmentId}/clusters/{clusterId}/secrets/dns-credential");
|
|
}
|
|
|
|
[Fact]
|
|
public void BuildPath_AppScope_ReturnsFullAppScopedPath()
|
|
{
|
|
// Arrange — Application secret: tenant → environment → customer → app.
|
|
|
|
Guid tenantId = Guid.NewGuid();
|
|
Guid customerId = Guid.NewGuid();
|
|
Guid environmentId = Guid.NewGuid();
|
|
SecretScope scope = SecretScope.ForApp(tenantId, customerId, "extract01", environmentId);
|
|
|
|
// Act
|
|
|
|
string path = scope.BuildPath("api-token");
|
|
|
|
// Assert
|
|
|
|
path.Should().Be(
|
|
$"tenants/{tenantId}/environments/{environmentId}/customers/{customerId}/apps/extract01/secrets/api-token");
|
|
}
|
|
|
|
[Fact]
|
|
public void BuildPath_CustomerWithoutApp_IncludesCustomerScope()
|
|
{
|
|
// Arrange — Customer-scoped without a specific app.
|
|
|
|
Guid tenantId = Guid.NewGuid();
|
|
Guid environmentId = Guid.NewGuid();
|
|
Guid customerId = Guid.NewGuid();
|
|
SecretScope scope = new(tenantId, environmentId, null, customerId, null);
|
|
|
|
// Act
|
|
|
|
string path = scope.BuildPath("shared-token");
|
|
|
|
// Assert
|
|
|
|
path.Should().Be(
|
|
$"tenants/{tenantId}/environments/{environmentId}/customers/{customerId}/secrets/shared-token");
|
|
}
|
|
|
|
// ─── Equality ────────────────────────────────────────────────────────
|
|
|
|
[Fact]
|
|
public void Equality_SameValues_AreEqual()
|
|
{
|
|
// Arrange — Records should have value-based equality.
|
|
|
|
Guid tenantId = Guid.NewGuid();
|
|
Guid envId = Guid.NewGuid();
|
|
SecretScope scope1 = new(tenantId, envId, null, null, null);
|
|
SecretScope scope2 = new(tenantId, envId, null, null, null);
|
|
|
|
// Assert
|
|
|
|
scope1.Should().Be(scope2);
|
|
}
|
|
}
|