< Summary - Envilder .NET SDK

Information
Class: Envilder.Infrastructure.SecretProviderFactory
Assembly: Envilder
File(s): /home/runner/work/envilder/envilder/src/sdks/dotnet/Infrastructure/SecretProviderFactory.cs
Tag: 151_24479375065
Line coverage
85%
Covered lines: 29
Uncovered lines: 5
Coverable lines: 34
Total lines: 108
Line coverage: 85.2%
Branch coverage
80%
Covered branches: 24
Total branches: 30
Branch coverage: 80%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.cctor()100%11100%
Create(...)100%88100%
CreateAzureSecretProvider(...)100%66100%
CreateAwsSecretProvider(...)75%8883.33%
ResolveProfileRegion(...)0%2040%
ResolveRegion()100%44100%

File(s)

/home/runner/work/envilder/envilder/src/sdks/dotnet/Infrastructure/SecretProviderFactory.cs

#LineLine coverage
 1namespace Envilder.Infrastructure;
 2
 3using Amazon;
 4using Amazon.Runtime.CredentialManagement;
 5using Amazon.SimpleSystemsManagement;
 6using Envilder.Domain;
 7using Envilder.Domain.Ports;
 8using Envilder.Infrastructure.Aws;
 9using Envilder.Infrastructure.Azure;
 10using global::Azure.Identity;
 11using global::Azure.Security.KeyVault.Secrets;
 12using System;
 13
 14/// <summary>
 15/// Creates the appropriate <see cref="ISecretProvider"/> implementation
 16/// based on the map file configuration and optional runtime overrides.
 17/// </summary>
 18public static class SecretProviderFactory
 19{
 120    private static readonly RegionEndpoint FallbackRegion = RegionEndpoint.USEast1;
 21
 22    /// <summary>
 23    /// Creates an <see cref="ISecretProvider"/> for the provider specified in
 24    /// <paramref name="config"/>. When <paramref name="options"/> is provided,
 25    /// its values take precedence over <paramref name="config"/>.
 26    /// </summary>
 27    /// <param name="config">Configuration from the <c>$config</c> section of a map file.</param>
 28    /// <param name="options">Optional runtime overrides (e.g. CLI flags).</param>
 29    /// <returns>A ready-to-use secret provider.</returns>
 30    /// <exception cref="InvalidOperationException">
 31    /// Thrown when Azure is selected but no Vault URL is provided.
 32    /// </exception>
 33    public static ISecretProvider Create(MapFileConfig config, EnvilderOptions? options = null)
 34    {
 135        if (config is null)
 36        {
 137            throw new ArgumentNullException(nameof(config));
 38        }
 39
 140        var provider = options?.Provider ?? config.Provider;
 41
 142        return provider switch
 143        {
 144            SecretProviderType.Azure => CreateAzureSecretProvider(config, options),
 145            _ => CreateAwsSecretProvider(config, options),
 146        };
 47    }
 48
 49    private static AzureKeyVaultSecretProvider CreateAzureSecretProvider(MapFileConfig config, EnvilderOptions? options)
 50    {
 151        var vaultUrl = options?.VaultUrl ?? config.VaultUrl;
 52
 153        if (string.IsNullOrWhiteSpace(vaultUrl))
 54        {
 155            throw new InvalidOperationException("Vault URL must be provided for Azure Key Vault provider.");
 56        }
 57
 158        var secretClient = new SecretClient(new Uri(vaultUrl), new DefaultAzureCredential());
 159        return new(secretClient);
 60    }
 61
 62    private static AwsSsmSecretProvider CreateAwsSecretProvider(MapFileConfig config, EnvilderOptions? options)
 63    {
 164        var profile = options?.Profile ?? config.Profile;
 65
 166        if (!string.IsNullOrWhiteSpace(profile))
 67        {
 168            var chain = new CredentialProfileStoreChain();
 169            if (chain.TryGetAWSCredentials(profile, out var credentials))
 70            {
 071                var region = ResolveProfileRegion(chain, profile!);
 072                return new(new AmazonSimpleSystemsManagementClient(credentials, region));
 73            }
 74
 175            throw new InvalidOperationException(
 176                $"AWS profile '{profile}' was not found in the credential store.");
 77        }
 78
 179        return new(new AmazonSimpleSystemsManagementClient(new AmazonSimpleSystemsManagementConfig
 180        {
 181            RegionEndpoint = ResolveRegion(),
 182        }));
 83    }
 84
 85    private static RegionEndpoint ResolveProfileRegion(CredentialProfileStoreChain chain, string profile)
 86    {
 087        if (chain.TryGetProfile(profile, out var credentialProfile) && credentialProfile.Region != null)
 88        {
 089            return credentialProfile.Region;
 90        }
 91
 092        return ResolveRegion();
 93    }
 94
 95    /// <summary>
 96    /// Resolves the AWS region from environment variables (<c>AWS_REGION</c> or
 97    /// <c>AWS_DEFAULT_REGION</c>), falling back to <c>us-east-1</c> when neither is set.
 98    /// </summary>
 99    private static RegionEndpoint ResolveRegion()
 100    {
 1101        var regionName = Environment.GetEnvironmentVariable("AWS_REGION")
 1102            ?? Environment.GetEnvironmentVariable("AWS_DEFAULT_REGION");
 103
 1104        return string.IsNullOrWhiteSpace(regionName)
 1105            ? FallbackRegion
 1106            : RegionEndpoint.GetBySystemName(regionName);
 107    }
 108}