From afe59a551880924bb22de12adf0bb42d7a2030dd Mon Sep 17 00:00:00 2001 From: Joseph Doherty Date: Wed, 2 Sep 2026 22:46:11 -0400 Subject: [PATCH] chore(host): pin ZB.MOM.WW.Auth 0.3.0 + ApiKeys.SqlServer; InboundApiKeyStoreOptions (Provider Sqlite|SqlServer, ReadProvider fails the boot on an unknown value) Claude-Session: https://claude.ai/code/session_013L3XdmVii9i5sY4FChU8pB --- Directory.Packages.props | 9 +-- .../InboundApiKeyStoreOptions.cs | 36 ++++++++++ .../ZB.MOM.WW.ScadaBridge.Host.csproj | 1 + .../InboundApiKeyStoreOptionsTests.cs | 70 +++++++++++++++++++ 4 files changed, 112 insertions(+), 4 deletions(-) create mode 100644 src/ZB.MOM.WW.ScadaBridge.Host/InboundApiKeyStoreOptions.cs create mode 100644 tests/ZB.MOM.WW.ScadaBridge.Host.Tests/InboundApiKeyStoreOptionsTests.cs diff --git a/Directory.Packages.props b/Directory.Packages.props index 93d01d98..07f57ce7 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -98,10 +98,11 @@ - - - - + + + + + diff --git a/src/ZB.MOM.WW.ScadaBridge.Host/InboundApiKeyStoreOptions.cs b/src/ZB.MOM.WW.ScadaBridge.Host/InboundApiKeyStoreOptions.cs new file mode 100644 index 00000000..69798ed7 --- /dev/null +++ b/src/ZB.MOM.WW.ScadaBridge.Host/InboundApiKeyStoreOptions.cs @@ -0,0 +1,36 @@ +using Microsoft.Extensions.Configuration; + +namespace ZB.MOM.WW.ScadaBridge.Host; + +/// Which backend holds inbound API keys. Bound from ScadaBridge:InboundApi:ApiKeyStore alongside the library's own ApiKeyOptions. +public enum InboundApiKeyStoreProvider { Sqlite, SqlServer } + +/// Host-side selector for the inbound API key store. Sqlite is per-node (single-node installs); SqlServer shares one row set across a central pair (design 2026-09-02). +public sealed class InboundApiKeyStoreOptions +{ + public const string SectionPath = "ScadaBridge:InboundApi:ApiKeyStore"; + + public InboundApiKeyStoreProvider Provider { get; set; } = InboundApiKeyStoreProvider.Sqlite; + + /// SQLite file to import once when is SqlServer; defaults to the library's SqlitePath. Renamed *.imported afterwards. + public string? ImportFromSqlitePath { get; set; } + + /// Reads Provider from configuration (case-insensitive). Throws naming the legal values on an unknown one, so a typo fails the boot with a readable message instead of silently falling back to SQLite. + public static InboundApiKeyStoreProvider ReadProvider(IConfiguration configuration) + { + var value = configuration[$"{SectionPath}:Provider"]; + if (string.IsNullOrWhiteSpace(value)) + { + return InboundApiKeyStoreProvider.Sqlite; + } + + if (Enum.TryParse(value, ignoreCase: true, out var parsed) + && Enum.IsDefined(parsed)) + { + return parsed; + } + + throw new InvalidOperationException( + $"{SectionPath}:Provider '{value}' is not recognised; use 'Sqlite' or 'SqlServer'."); + } +} diff --git a/src/ZB.MOM.WW.ScadaBridge.Host/ZB.MOM.WW.ScadaBridge.Host.csproj b/src/ZB.MOM.WW.ScadaBridge.Host/ZB.MOM.WW.ScadaBridge.Host.csproj index 57a1ae27..24f4bc73 100644 --- a/src/ZB.MOM.WW.ScadaBridge.Host/ZB.MOM.WW.ScadaBridge.Host.csproj +++ b/src/ZB.MOM.WW.ScadaBridge.Host/ZB.MOM.WW.ScadaBridge.Host.csproj @@ -32,6 +32,7 @@ +