using Shouldly; using Xunit; using ZB.MOM.WW.OtOpcUa.Configuration.Entities; using ZB.MOM.WW.OtOpcUa.Configuration.Validation; namespace ZB.MOM.WW.OtOpcUa.Configuration.Tests; /// lmxopcua#815: the credential-reference namespace deploy gate (Galaxy, OpcUaClient). [Trait("Category", "Unit")] public sealed class DraftValidatorCredentialReferenceTests { private static IReadOnlyList Validate(string type, string driverConfig, string deviceConfig = "{}") => DraftValidator.Validate(new DraftSnapshot { GenerationId = 1, ClusterId = "c", DriverInstances = [new DriverInstance { DriverInstanceId = "drv", ClusterId = "c", Name = "drv", DriverType = type, DriverConfig = driverConfig }], Devices = [new Device { DeviceId = "dev", DriverInstanceId = "drv", Name = "dev1", DeviceConfig = deviceConfig }], Tags = [], }).Where(e => e.Code == CredentialReferenceDeployChecks.Code).ToList(); [Theory] [InlineData("GalaxyMxGateway", """{"Gateway":{"Endpoint":"http://evil:5001","ApiKeySecretRef":"env:ConnectionStrings__ConfigDb"}}""")] [InlineData("GalaxyMxGateway", """{"Gateway":{"ApiKeySecretRef":"env:ServerHistorian__ApiKey"}}""")] [InlineData("GalaxyMxGateway", """{"Gateway":{"ApiKeySecretRef":"file:C:\\otopcua\\appsettings.json"}}""")] [InlineData("GalaxyMxGateway", """{"AlarmAck":{"FallbackPasswordSecretRef":"secret:otopcua/apikeys/ab/galaxy-ack-password"}}""")] [InlineData("OpcUaClient", """{"EndpointUrl":"opc.tcp://evil:4840","Password":"secret:otopcua/historian/api-key"}""")] [InlineData("OpcUaClient", """{"UserCertificatePassword":"env:ConnectionStrings__ConfigDb"}""")] public void An_out_of_namespace_reference_is_refused_naming_the_allowed_form(string type, string config) { var e = Validate(type, config).ShouldHaveSingleItem(); e.Context.ShouldBe("drv"); e.Message.ShouldContain("secret:"); e.Message.ShouldContain("lmxopcua#815"); e.Message.ShouldContain("Migrate it before deploying"); e.Message.ShouldNotContain("ConnectionStrings__ConfigDb"); } [Fact] public void A_reference_in_a_device_config_is_checked_too() => Validate("GalaxyMxGateway", "{}", """{"Gateway":{"ApiKeySecretRef":"env:ConnectionStrings__ConfigDb"}}""") .ShouldHaveSingleItem().Context.ShouldBe("dev"); [Theory] [InlineData("GalaxyMxGateway", """{"Gateway":{"ApiKeySecretRef":"secret:galaxy/main/apikey"},"AlarmAck":{"FallbackPasswordSecretRef":"secret:otopcua/galaxy/ack-fallback"}}""")] [InlineData("GalaxyMxGateway", """{"Gateway":{"ApiKeySecretRef":"env:GALAXY_MXGW_API_KEY"}}""")] [InlineData("GalaxyMxGateway", """{"Gateway":{"ApiKeySecretRef":"dev:k"}}""")] [InlineData("OpcUaClient", """{"Password":"literal","UserCertificatePassword":"env:OTOPCUA_OPCUACLIENT_CERT_PW"}""")] [InlineData("Modbus", """{"Password":"env:ConnectionStrings__ConfigDb"}""")] public void Namespaced_literal_and_unrelated_configs_pass(string type, string config) => Validate(type, config).ShouldBeEmpty(); [Fact] public void Heidenhain_is_reported_once_by_its_own_gate_not_twice() => DraftValidator.Validate(new DraftSnapshot { GenerationId = 1, ClusterId = "c", DriverInstances = [new DriverInstance { DriverInstanceId = "hh", ClusterId = "c", Name = "hh", DriverType = "Heidenhain", DriverConfig = """{"Access":{"InspectPassword":"env:ConnectionStrings__ConfigDb"}}""" }], Devices = [], Tags = [], }) .Count(e => e.Code is CredentialReferenceDeployChecks.Code or HeidenhainDeployChecks.CredentialCode).ShouldBe(1); }