Increase secrets unit coverage (#7545)
This commit is contained in:
parent
5245599131
commit
67ded31cba
32
test/unit/Elsa.Secrets.UnitTests/SecretModelMapperTests.cs
Normal file
32
test/unit/Elsa.Secrets.UnitTests/SecretModelMapperTests.cs
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
using Elsa.Secrets.Models;
|
||||
using Elsa.Secrets.Services;
|
||||
using Xunit;
|
||||
|
||||
namespace Elsa.Secrets.UnitTests;
|
||||
|
||||
public class SecretModelMapperTests
|
||||
{
|
||||
[Fact]
|
||||
public void ToModel_ReportsExpired_WhenActiveSecretHasOnlyExpiredVersions()
|
||||
{
|
||||
var secret = new Secret
|
||||
{
|
||||
Name = "smtp:password",
|
||||
DisplayName = "SMTP password",
|
||||
Versions =
|
||||
{
|
||||
new SecretVersion
|
||||
{
|
||||
Version = 1,
|
||||
ExpiresAt = DateTimeOffset.UtcNow.AddMinutes(-1)
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var model = secret.ToModel();
|
||||
|
||||
Assert.Equal(SecretStatus.Expired, model.Status);
|
||||
Assert.Null(model.CurrentVersion);
|
||||
Assert.Null(model.ExpiresAt);
|
||||
}
|
||||
}
|
||||
|
|
@ -40,6 +40,51 @@ public class SecretStoreTests
|
|||
Assert.Equal("configured-secret", value);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ConfigurationStore_FallsBackToRootConfigurationKey()
|
||||
{
|
||||
var configuration = new ConfigurationBuilder()
|
||||
.AddInMemoryCollection(new Dictionary<string, string?> { ["SmtpPassword"] = "root-configured-secret" })
|
||||
.Build();
|
||||
var fixture = new SecretTestFixture(configuration);
|
||||
|
||||
var secret = await fixture.Manager.CreateAsync(new CreateSecretRequest
|
||||
{
|
||||
Name = "smtp:password",
|
||||
StoreName = SecretStoreNames.Configuration,
|
||||
ConfigurationKey = " SmtpPassword "
|
||||
});
|
||||
var value = await fixture.Resolver.ResolveAsync("smtp:password");
|
||||
|
||||
Assert.Equal("root-configured-secret", value);
|
||||
Assert.Null(secret.Versions.Single().Payload.Value);
|
||||
Assert.Equal("SmtpPassword", secret.Versions.Single().Payload.Metadata["configurationKey"]);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ConfigurationStore_RotateAsync_UsesReplacementConfigurationKey()
|
||||
{
|
||||
var configuration = new ConfigurationBuilder()
|
||||
.AddInMemoryCollection(new Dictionary<string, string?>
|
||||
{
|
||||
["Elsa:Secrets:OldPassword"] = "old-configured-secret",
|
||||
["Elsa:Secrets:NewPassword"] = "new-configured-secret"
|
||||
})
|
||||
.Build();
|
||||
var fixture = new SecretTestFixture(configuration);
|
||||
|
||||
await fixture.Manager.CreateAsync(new CreateSecretRequest
|
||||
{
|
||||
Name = "smtp:password",
|
||||
StoreName = SecretStoreNames.Configuration,
|
||||
ConfigurationKey = "OldPassword"
|
||||
});
|
||||
await fixture.Manager.RotateAsync("smtp:password", new RotateSecretRequest { ConfigurationKey = "NewPassword" });
|
||||
var value = await fixture.Resolver.ResolveAsync("smtp:password");
|
||||
|
||||
Assert.Equal("new-configured-secret", value);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ConfigurationStore_TestAsync_ReturnsFalseWhenConfiguredValueIsMissing()
|
||||
{
|
||||
|
|
@ -57,6 +102,18 @@ public class SecretStoreTests
|
|||
Assert.Equal("Secret value is unavailable.", result.Error);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Registries_Throw_WhenTypeOrStoreIsMissing()
|
||||
{
|
||||
var fixture = new SecretTestFixture();
|
||||
|
||||
var missingType = Assert.Throws<InvalidOperationException>(() => fixture.TypeRegistry.Get("missing-type"));
|
||||
var missingStore = Assert.Throws<InvalidOperationException>(() => fixture.StoreRegistry.Get("missing-store"));
|
||||
|
||||
Assert.Contains("missing-type", missingType.Message);
|
||||
Assert.Contains("missing-store", missingStore.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task FileRepository_PersistsSecretAggregate()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -0,0 +1,52 @@
|
|||
using Elsa.Secrets.Options;
|
||||
using Elsa.Secrets.Services;
|
||||
using Xunit;
|
||||
|
||||
namespace Elsa.Secrets.UnitTests;
|
||||
|
||||
public class SecretValueProtectorTests
|
||||
{
|
||||
[Fact]
|
||||
public void Protect_AndUnprotect_RoundTripsValue()
|
||||
{
|
||||
var protector = CreateProtector("0123456789abcdef0123456789abcdef"u8.ToArray());
|
||||
|
||||
var protectedValue = protector.Protect("plain-text-secret");
|
||||
var value = protector.Unprotect(protectedValue);
|
||||
|
||||
Assert.NotEqual("plain-text-secret", protectedValue);
|
||||
Assert.Equal("plain-text-secret", value);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(null)]
|
||||
[InlineData(0)]
|
||||
[InlineData(15)]
|
||||
[InlineData(17)]
|
||||
public void Protect_RejectsMissingOrInvalidEncryptionKey(int? keyLength)
|
||||
{
|
||||
var protector = CreateProtector(keyLength == null ? null : new byte[keyLength.Value]);
|
||||
|
||||
var exception = Assert.Throws<InvalidOperationException>(() => protector.Protect("secret"));
|
||||
|
||||
Assert.Contains("encryption key", exception.Message, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("")]
|
||||
[InlineData("v2.payload")]
|
||||
[InlineData("v1.payload")]
|
||||
public void Unprotect_RejectsUnsupportedPayloadFormat(string protectedValue)
|
||||
{
|
||||
var protector = CreateProtector("0123456789abcdef0123456789abcdef"u8.ToArray());
|
||||
|
||||
var exception = Assert.Throws<InvalidOperationException>(() => protector.Unprotect(protectedValue));
|
||||
|
||||
Assert.Contains("not supported", exception.Message, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
private static DefaultSecretValueProtector CreateProtector(byte[]? key)
|
||||
{
|
||||
return new DefaultSecretValueProtector(Microsoft.Extensions.Options.Options.Create(new SecretsOptions { EncryptionKey = key }));
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue