namespace ZB.MOM.WW.OtOpcUa.Driver.Sql;
///
/// Resolves a Sql driver config's connectionStringRef — a NAME — into the connection string
/// it stands for (design §8.2). The deployed artifact carries only the name, so database credentials never
/// ride in a config blob, never land in the central config DB, and never appear in a deployment diff.
/// The environment is read directly, on purpose. A driver factory is invoked through
/// DriverFactoryRegistry's (driverInstanceId, driverConfigJson) closure — there is no
/// IConfiguration, no IServiceProvider and no ambient scope at that seam, and widening the
/// registry's signature for one driver would change every driver in the tree. The
/// Sql__ConnectionStrings__<ref> spelling is exactly the key .NET's environment-variable
/// configuration provider would bind to Sql:ConnectionStrings:<ref>, so an operator can set it
/// the same way they set every other secret and a later move onto IConfiguration needs no
/// re-provisioning.
/// Nothing here ever emits the resolved value. Messages name the environment
/// variable, which is not a secret and is the operator's next action; the value itself is returned
/// to exactly one caller and is otherwise unmentioned.
///
public static class SqlConnectionStringResolver
{
///
/// The environment-variable prefix a connectionStringRef is appended to. The double underscore
/// is .NET's configuration hierarchy separator, so this is the environment spelling of
/// Sql:ConnectionStrings:<ref>.
///
public const string EnvironmentVariablePrefix = "Sql__ConnectionStrings__";
/// The environment variable a given connectionStringRef is read from.
/// The authored reference name.
/// The full environment-variable name.
/// is null, empty or whitespace.
public static string EnvironmentVariableFor(string connectionStringRef)
{
ArgumentException.ThrowIfNullOrWhiteSpace(connectionStringRef);
return string.Concat(EnvironmentVariablePrefix, connectionStringRef);
}
///
/// Resolves to its connection string.
/// An absent or blank variable is a half-provisioned deployment and throws: handing an
/// empty string to the provider would surface as an unintelligible ADO.NET error at the first poll,
/// far from the missing secret that actually caused it.
///
/// The authored reference name.
/// The resolved connection string. Treat as a secret — never log it.
/// is null, empty or whitespace.
/// The environment variable is absent or blank.
public static string Resolve(string connectionStringRef)
{
var variable = EnvironmentVariableFor(connectionStringRef);
var value = Environment.GetEnvironmentVariable(variable);
if (string.IsNullOrWhiteSpace(value))
{
throw new InvalidOperationException(
$"Sql connection string '{connectionStringRef}' is not provisioned: set the environment " +
$"variable '{variable}' on every node that runs this driver. The connection string is " +
$"deliberately not carried in the deployed configuration.");
}
return value;
}
}