work
This commit is contained in:
@@ -29,38 +29,45 @@ public static class ServiceCollectionExtensions
|
||||
var env = sp.GetRequiredService<ISurfaceEnvironment>();
|
||||
var options = sp.GetRequiredService<IOptions<SurfaceSecretsOptions>>().Value;
|
||||
var logger = sp.GetRequiredService<ILoggerFactory>().CreateLogger("SurfaceSecrets");
|
||||
return CreateProvider(env.Settings.Secrets, logger);
|
||||
return CreateProviderChain(env.Settings.Secrets, logger);
|
||||
});
|
||||
|
||||
return services;
|
||||
}
|
||||
|
||||
private static ISurfaceSecretProvider CreateProvider(SurfaceSecretsConfiguration configuration, ILogger logger)
|
||||
private static ISurfaceSecretProvider CreateProviderChain(SurfaceSecretsConfiguration configuration, ILogger logger)
|
||||
{
|
||||
var providers = new List<ISurfaceSecretProvider>();
|
||||
|
||||
switch (configuration.Provider.ToLowerInvariant())
|
||||
var providers = new List<ISurfaceSecretProvider>
|
||||
{
|
||||
case "kubernetes":
|
||||
providers.Add(new KubernetesSurfaceSecretProvider(configuration, logger));
|
||||
break;
|
||||
case "file":
|
||||
providers.Add(new FileSurfaceSecretProvider(configuration.Root ?? throw new ArgumentException("Secrets root is required for file provider.")));
|
||||
break;
|
||||
case "inline":
|
||||
providers.Add(new InlineSurfaceSecretProvider(configuration));
|
||||
break;
|
||||
default:
|
||||
logger.LogWarning("Unknown surface secret provider '{Provider}'. Falling back to inline provider.", configuration.Provider);
|
||||
providers.Add(new InlineSurfaceSecretProvider(configuration));
|
||||
break;
|
||||
}
|
||||
CreateProvider(configuration.Provider, configuration, logger)
|
||||
};
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(configuration.FallbackProvider))
|
||||
if (configuration.HasFallback)
|
||||
{
|
||||
providers.Add(new InlineSurfaceSecretProvider(configuration with { Provider = configuration.FallbackProvider }));
|
||||
providers.Add(CreateProvider(configuration.FallbackProvider!, configuration, logger));
|
||||
}
|
||||
|
||||
return providers.Count == 1 ? providers[0] : new CompositeSurfaceSecretProvider(providers);
|
||||
}
|
||||
|
||||
private static ISurfaceSecretProvider CreateProvider(string providerId, SurfaceSecretsConfiguration configuration, ILogger logger)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(providerId))
|
||||
{
|
||||
throw new ArgumentException("Provider id is required", nameof(providerId));
|
||||
}
|
||||
|
||||
switch (providerId.Trim().ToLowerInvariant())
|
||||
{
|
||||
case "kubernetes":
|
||||
return new KubernetesSurfaceSecretProvider(configuration, logger);
|
||||
case "file":
|
||||
return new FileSurfaceSecretProvider(configuration.Root ?? throw new ArgumentException("Secrets root is required for file provider."));
|
||||
case "inline":
|
||||
return new InlineSurfaceSecretProvider(configuration);
|
||||
default:
|
||||
logger.LogWarning("Unknown surface secret provider '{Provider}'. Falling back to inline provider if allowed; otherwise requests will fail.", providerId);
|
||||
return new InlineSurfaceSecretProvider(configuration);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ public static class SurfaceValidationIssueCodes
|
||||
public const string CacheQuotaInvalid = "SURFACE_ENV_CACHE_QUOTA_INVALID";
|
||||
public const string SecretsProviderUnknown = "SURFACE_SECRET_PROVIDER_UNKNOWN";
|
||||
public const string SecretsConfigurationMissing = "SURFACE_SECRET_CONFIGURATION_MISSING";
|
||||
public const string SecretsConfigurationInvalid = "SURFACE_SECRET_FORMAT_INVALID";
|
||||
public const string TenantMissing = "SURFACE_ENV_TENANT_MISSING";
|
||||
public const string BucketMissing = "SURFACE_FS_BUCKET_MISSING";
|
||||
public const string FeatureUnknown = "SURFACE_FEATURE_UNKNOWN";
|
||||
|
||||
@@ -35,6 +35,14 @@ internal sealed class SurfaceSecretsValidator : ISurfaceValidator
|
||||
"Set SCANNER_SURFACE_SECRETS_PROVIDER to 'kubernetes', 'file', or another supported provider."));
|
||||
}
|
||||
|
||||
if (secrets.HasFallback && !KnownProviders.Contains(secrets.FallbackProvider!))
|
||||
{
|
||||
issues.Add(SurfaceValidationIssue.Error(
|
||||
SurfaceValidationIssueCodes.SecretsProviderUnknown,
|
||||
$"Fallback secrets provider '{secrets.FallbackProvider}' is not recognised.",
|
||||
"Choose a supported fallback provider (kubernetes | file | inline) or clear SCANNER_SURFACE_SECRETS_FALLBACK_PROVIDER."));
|
||||
}
|
||||
|
||||
if (string.Equals(secrets.Provider, "kubernetes", StringComparison.OrdinalIgnoreCase) &&
|
||||
string.IsNullOrWhiteSpace(secrets.Namespace))
|
||||
{
|
||||
@@ -53,6 +61,24 @@ internal sealed class SurfaceSecretsValidator : ISurfaceValidator
|
||||
"Set SCANNER_SURFACE_SECRETS_ROOT to a directory path."));
|
||||
}
|
||||
|
||||
if (string.Equals(secrets.Provider, "file", StringComparison.OrdinalIgnoreCase) &&
|
||||
!string.IsNullOrWhiteSpace(secrets.Root) &&
|
||||
!Directory.Exists(secrets.Root))
|
||||
{
|
||||
issues.Add(SurfaceValidationIssue.Error(
|
||||
SurfaceValidationIssueCodes.SecretsConfigurationInvalid,
|
||||
$"File secrets root '{secrets.Root}' does not exist.",
|
||||
"Ensure SCANNER_SURFACE_SECRETS_ROOT points to an existing directory with 0600-style permissions."));
|
||||
}
|
||||
|
||||
if (string.Equals(secrets.Provider, "inline", StringComparison.OrdinalIgnoreCase) && !secrets.AllowInline)
|
||||
{
|
||||
issues.Add(SurfaceValidationIssue.Error(
|
||||
SurfaceValidationIssueCodes.SecretsConfigurationInvalid,
|
||||
"Inline secrets provider is selected but AllowInline=false.",
|
||||
"Either enable SCANNER_SURFACE_SECRETS_ALLOW_INLINE for dev/test or switch provider."));
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(secrets.Tenant))
|
||||
{
|
||||
issues.Add(SurfaceValidationIssue.Error(
|
||||
|
||||
Reference in New Issue
Block a user