using ScadaLink.Commons.Entities.InboundApi; using ScadaLink.Commons.Types.InboundApi; namespace ScadaLink.Commons.Tests.Entities; /// /// ConfigurationDatabase-012: the entity must never carry the /// plaintext bearer credential as a persisted field — only its deterministic hash. /// public class ApiKeyTests { [Fact] public void ApiKey_HasNoPlaintextKeyValueProperty() { // The plaintext key is shown to the operator once at creation and is never // persisted. The entity must therefore expose KeyHash, not KeyValue. var properties = typeof(ApiKey).GetProperties().Select(p => p.Name).ToArray(); Assert.DoesNotContain("KeyValue", properties); Assert.Contains("KeyHash", properties); } [Fact] public void Constructor_FromPlaintext_StoresHashNotPlaintext() { var key = new ApiKey("MES-Production", "the-secret-key-value"); Assert.NotEqual("the-secret-key-value", key.KeyHash); Assert.Equal(ApiKeyHasher.Default.Hash("the-secret-key-value"), key.KeyHash); } [Fact] public void FromHash_StoresHashVerbatim() { var key = ApiKey.FromHash("RecipeManager-Dev", "precomputed-hash-value"); Assert.Equal("RecipeManager-Dev", key.Name); Assert.Equal("precomputed-hash-value", key.KeyHash); } [Fact] public void Constructor_NullArguments_Throw() { Assert.Throws(() => new ApiKey(null!, "value")); Assert.Throws(() => new ApiKey("name", (string)null!)); Assert.Throws(() => ApiKey.FromHash(null!, "hash")); Assert.Throws(() => ApiKey.FromHash("name", null!)); } }