using System; using System.Collections.Generic; using System.IO; using System.Threading.Tasks; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using StellaOps.Scanner.Surface.Env; using StellaOps.Scanner.Surface.Secrets; namespace StellaOps.Scanner.Surface.Secrets.Tests { public sealed class SurfaceSecretsServiceCollectionExtensionsTests { [Fact] public void AddSurfaceSecrets_RegistersProvider() { var services = new ServiceCollection(); services.AddSingleton(_ => new TestSurfaceEnvironment()); services.AddLogging(builder => builder.ClearProviders()); services.AddSurfaceSecrets(); using var provider = services.BuildServiceProvider(); var secretProvider = provider.GetRequiredService(); Assert.NotNull(secretProvider); } [Fact] public async Task AddSurfaceSecrets_UsesFallbackProvider_WhenPrimaryCannotResolve() { const string key = "SURFACE_SECRET_TENANT_COMPONENT_REGISTRY_DEFAULT"; Environment.SetEnvironmentVariable(key, Convert.ToBase64String(new byte[] { 9, 9, 9 })); var services = new ServiceCollection(); services.AddSingleton(_ => new TestSurfaceEnvironmentWithFallback()); services.AddLogging(builder => builder.ClearProviders()); services.AddSurfaceSecrets(); await using var provider = services.BuildServiceProvider(); var secretProvider = provider.GetRequiredService(); var handle = await secretProvider.GetAsync(new SurfaceSecretRequest("tenant", "component", "registry")); try { Assert.Equal(new byte[] { 9, 9, 9 }, handle.AsBytes().ToArray()); } finally { handle.Dispose(); Environment.SetEnvironmentVariable(key, null); } } private sealed class TestSurfaceEnvironment : ISurfaceEnvironment { public SurfaceEnvironmentSettings Settings { get; } public IReadOnlyDictionary RawVariables { get; } public TestSurfaceEnvironment() { Settings = new SurfaceEnvironmentSettings( new Uri("https://surface.example"), "surface", null, new DirectoryInfo(Path.GetTempPath()), 1024, false, Array.Empty(), new SurfaceSecretsConfiguration("file", "tenant", Root: Path.GetTempPath(), Namespace: null, FallbackProvider: null, AllowInline: true), "tenant", new SurfaceTlsConfiguration(null, null, null)) { CreatedAtUtc = DateTimeOffset.UtcNow }; RawVariables = new Dictionary(); } } private sealed class TestSurfaceEnvironmentWithFallback : ISurfaceEnvironment { public SurfaceEnvironmentSettings Settings { get; } public IReadOnlyDictionary RawVariables { get; } public TestSurfaceEnvironmentWithFallback() { var root = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()); Settings = new SurfaceEnvironmentSettings( new Uri("https://surface.example"), "surface", null, new DirectoryInfo(Path.GetTempPath()), 1024, false, Array.Empty(), new SurfaceSecretsConfiguration("kubernetes", "tenant", Root: root, Namespace: "ns", FallbackProvider: "inline", AllowInline: true), "tenant", new SurfaceTlsConfiguration(null, null, null)) { CreatedAtUtc = DateTimeOffset.UtcNow }; RawVariables = new Dictionary(); } } } }