feat(delmia-notifier): optional ScadaBridge:ApiKey in appsettings.json as a fallback to SCADABRIDGE_API_KEY (env still wins); README/env inventory/design row updated

The 2026-06-26 design kept the key env-only. The file is now an explicit fallback: SCADABRIDGE_API_KEY (non-blank) -> ScadaBridge:ApiKey (non-blank, trimmed) -> not configured. Env-only stays the recommended production posture; the failure message names both sources.

Claude-Session: https://claude.ai/code/session_013L3XdmVii9i5sY4FChU8pB
This commit is contained in:
Joseph Doherty
2026-09-02 12:43:21 -04:00
parent 7dc30085be
commit 8adb09a083
8 changed files with 65 additions and 22 deletions
@@ -38,13 +38,42 @@ public class ConfigLoaderTests
[Fact]
public void ResolveApiKey_returns_null_when_unset_or_whitespace()
{
Assert.Null(ConfigLoader.ResolveApiKey(_ => null));
Assert.Null(ConfigLoader.ResolveApiKey(_ => " "));
Assert.Null(ConfigLoader.ResolveApiKey(_ => null, new NotifierConfig()));
Assert.Null(ConfigLoader.ResolveApiKey(_ => " ", new NotifierConfig()));
}
[Fact]
public void ResolveApiKey_returns_value_when_present()
{
Assert.Equal("sbk_x", ConfigLoader.ResolveApiKey(n => n == "SCADABRIDGE_API_KEY" ? "sbk_x" : null));
Assert.Equal("sbk_x", ConfigLoader.ResolveApiKey(n => n == "SCADABRIDGE_API_KEY" ? "sbk_x" : null, new NotifierConfig()));
}
[Fact]
public void Load_reads_ApiKey_from_ScadaBridge_section()
{
var cfg = ConfigLoader.Load("{\"ScadaBridge\":{\"BaseUrls\":\"http://x\",\"ApiKey\":\"sbk_file\"}}");
Assert.Equal("sbk_file", cfg.ScadaBridge.ApiKey);
}
[Fact]
public void ResolveApiKey_prefers_env_over_config()
{
var cfg = ConfigLoader.Load("{\"ScadaBridge\":{\"ApiKey\":\"sbk_file\"}}");
Assert.Equal("sbk_env", ConfigLoader.ResolveApiKey(n => n == "SCADABRIDGE_API_KEY" ? "sbk_env" : null, cfg));
}
[Fact]
public void ResolveApiKey_falls_back_to_config_when_env_unset_or_blank()
{
var cfg = ConfigLoader.Load("{\"ScadaBridge\":{\"ApiKey\":\" sbk_file \"}}");
Assert.Equal("sbk_file", ConfigLoader.ResolveApiKey(_ => null, cfg));
Assert.Equal("sbk_file", ConfigLoader.ResolveApiKey(_ => " ", cfg));
}
[Fact]
public void ResolveApiKey_returns_null_when_neither_source_set()
{
var cfg = ConfigLoader.Load("{\"ScadaBridge\":{\"ApiKey\":\" \"}}");
Assert.Null(ConfigLoader.ResolveApiKey(_ => null, cfg));
}
}