using Shouldly; using Xunit; using ZB.MOM.WW.OtOpcUa.Driver.OpcUaClient; using ZB.MOM.WW.Secrets.Abstractions; namespace ZB.MOM.WW.OtOpcUa.Driver.OpcUaClient.Tests; /// /// G-2b — pins , the Layer-B /// arm that resolves secret:-prefixed /// and through the shared /// just before the async session-open consumes them. The /// secret: arm is fail-closed — an absent secret throws rather than leaving the /// secret: literal in place (which would be sent verbatim as the password). /// Non-secret literals and null/empty pass through unchanged. /// public sealed class OpcUaClientSecretResolutionTests { private const string KnownPwName = "opcua/inst/password"; private const string KnownPwValue = "resolved-password-plaintext"; private const string KnownCertPwName = "opcua/inst/cert-pw"; private const string KnownCertPwValue = "resolved-cert-pw-plaintext"; /// A fake resolver: returns known values for two known names, null otherwise. private static ISecretResolver FakeResolver() => new StubSecretResolver(); /// (a) A secret: Password resolves to the store's plaintext. [Fact] public async Task Secret_password_resolves_to_store_plaintext() { var options = new OpcUaClientDriverOptions { Password = $"secret:{KnownPwName}" }; var resolved = await OpcUaClientSecretResolution.ResolveSecretRefsAsync( options, FakeResolver(), CancellationToken.None); resolved.Password.ShouldBe(KnownPwValue); } /// (b) A secret: UserCertificatePassword resolves to the store's plaintext. [Fact] public async Task Secret_cert_password_resolves_to_store_plaintext() { var options = new OpcUaClientDriverOptions { UserCertificatePassword = $"secret:{KnownCertPwName}" }; var resolved = await OpcUaClientSecretResolution.ResolveSecretRefsAsync( options, FakeResolver(), CancellationToken.None); resolved.UserCertificatePassword.ShouldBe(KnownCertPwValue); } /// (c) A non-secret literal Password and a null field pass through unchanged. [Fact] public async Task Literal_and_null_pass_through_unchanged() { var options = new OpcUaClientDriverOptions { Password = "plainpw", UserCertificatePassword = null, }; var resolved = await OpcUaClientSecretResolution.ResolveSecretRefsAsync( options, FakeResolver(), CancellationToken.None); resolved.Password.ShouldBe("plainpw"); resolved.UserCertificatePassword.ShouldBeNull(); } /// (d) An unknown secret: ref (resolver returns null) is fail-closed — it throws /// and never leaves the secret: literal in place. [Fact] public async Task Unknown_secret_ref_is_fail_closed() { var options = new OpcUaClientDriverOptions { Password = "secret:opcua/inst/absent" }; var ex = await Should.ThrowAsync(() => OpcUaClientSecretResolution.ResolveSecretRefsAsync( options, FakeResolver(), CancellationToken.None)); ex.Message.ShouldContain("Password"); ex.Message.ShouldContain("opcua/inst/absent"); } /// A fake resolver: returns known values for two known names, null otherwise. private sealed class StubSecretResolver : ISecretResolver { /// public Task GetAsync(SecretName name, CancellationToken ct) => Task.FromResult(name.Value switch { KnownPwName => KnownPwValue, KnownCertPwName => KnownCertPwValue, _ => null, }); } }