mirror of
https://github.com/Sea-Haven-Industries/shoc-backend.git
synced 2026-09-30 15:23:12 +00:00
98 lines
3.6 KiB
C#
98 lines
3.6 KiB
C#
using Amazon.SecretsManager;
|
|
using Amazon.SecretsManager.Model;
|
|
using Api.SeaHavenIndustries.Infrastructure;
|
|
using Microsoft.Extensions.Logging.Abstractions;
|
|
using Microsoft.Extensions.Options;
|
|
using Moq;
|
|
using SeaHaven.Services.Configuration;
|
|
using SeaHaven.Services.Interfaces;
|
|
using Xunit;
|
|
|
|
namespace Api.SeaHavenIndustries.Tests;
|
|
|
|
public sealed class WorkOrderWebhookSecretProviderTests
|
|
{
|
|
[Fact]
|
|
public async Task Known_key_is_cached_and_callers_receive_independent_secret_copies()
|
|
{
|
|
var client = new Mock<IAmazonSecretsManager>(MockBehavior.Strict);
|
|
client.Setup(c => c.GetSecretValueAsync(
|
|
It.Is<GetSecretValueRequest>(r => r.SecretId == "arn:configured"),
|
|
It.IsAny<CancellationToken>()))
|
|
.ReturnsAsync(new GetSecretValueResponse { SecretString = "shared-secret" });
|
|
var provider = CreateProvider(client.Object);
|
|
|
|
var first = await provider.GetSecretAsync("current", CancellationToken.None);
|
|
first.Secret![0] = 0;
|
|
var second = await provider.GetSecretAsync("current", CancellationToken.None);
|
|
|
|
Assert.Equal(WorkOrderWebhookSecretStatus.Found, second.Status);
|
|
Assert.Equal("shared-secret", System.Text.Encoding.UTF8.GetString(second.Secret!));
|
|
client.VerifyAll();
|
|
client.Verify(
|
|
c => c.GetSecretValueAsync(
|
|
It.IsAny<GetSecretValueRequest>(),
|
|
It.IsAny<CancellationToken>()),
|
|
Times.Once);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task Unknown_key_never_influences_an_aws_request()
|
|
{
|
|
var client = new Mock<IAmazonSecretsManager>(MockBehavior.Strict);
|
|
var provider = CreateProvider(client.Object);
|
|
|
|
var result = await provider.GetSecretAsync(
|
|
"attacker-controlled-key",
|
|
CancellationToken.None);
|
|
|
|
Assert.Equal(WorkOrderWebhookSecretStatus.UnknownKey, result.Status);
|
|
client.VerifyNoOtherCalls();
|
|
}
|
|
|
|
[Fact]
|
|
public async Task Aws_failure_returns_unavailable_without_exposing_the_exception()
|
|
{
|
|
var client = new Mock<IAmazonSecretsManager>(MockBehavior.Strict);
|
|
client.Setup(c => c.GetSecretValueAsync(
|
|
It.IsAny<GetSecretValueRequest>(),
|
|
It.IsAny<CancellationToken>()))
|
|
.ThrowsAsync(new InvalidOperationException("sensitive provider detail"));
|
|
var provider = CreateProvider(client.Object);
|
|
|
|
var result = await provider.GetSecretAsync("current", CancellationToken.None);
|
|
|
|
Assert.Equal(WorkOrderWebhookSecretStatus.Unavailable, result.Status);
|
|
Assert.Null(result.Secret);
|
|
}
|
|
|
|
private static AwsWorkOrderWebhookSecretProvider CreateProvider(
|
|
IAmazonSecretsManager client) =>
|
|
new(
|
|
client,
|
|
new TestOptionsMonitor(new WorkOrderWebhookOptions
|
|
{
|
|
SecretCacheSeconds = 300,
|
|
KeySecrets = new Dictionary<string, string>
|
|
{
|
|
["current"] = "arn:configured"
|
|
}
|
|
}),
|
|
TimeProvider.System,
|
|
NullLogger<AwsWorkOrderWebhookSecretProvider>.Instance);
|
|
|
|
private sealed class TestOptionsMonitor : IOptionsMonitor<WorkOrderWebhookOptions>
|
|
{
|
|
public TestOptionsMonitor(WorkOrderWebhookOptions currentValue)
|
|
{
|
|
CurrentValue = currentValue;
|
|
}
|
|
|
|
public WorkOrderWebhookOptions CurrentValue { get; }
|
|
|
|
public WorkOrderWebhookOptions Get(string? name) => CurrentValue;
|
|
|
|
public IDisposable? OnChange(
|
|
Action<WorkOrderWebhookOptions, string?> listener) => null;
|
|
}
|
|
}
|