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; } }