using ZB.MOM.WW.OtOpcUa.Commons.Types; using ZB.MOM.WW.OtOpcUa.Core.Abstractions; namespace ZB.MOM.WW.OtOpcUa.Configuration.Validation; /// /// Deploy gate for credential references (lmxopcua#815): every DriverConfig and DeviceConfig of a driver type /// listed in must carry its credential fields as blank, an acceptable /// literal, or a reference inside that driver's namespace (e.g. Galaxy secret:galaxy/… / /// env:OTOPCUA_GALAXY_…). The same table the AdminUI save path, Test Connect, live browse and every /// driver's resolve-time check read — so the gate and the runtime cannot disagree. /// /// /// Heidenhain is excluded here only because already reports the same rule /// (as ) through the shared parser; reporting it twice would /// duplicate every error. The message names the field and the allowed forms, never the value. /// public static class CredentialReferenceDeployChecks { /// A credential field holding a reference outside the driver's namespace (or a refused literal). public const string Code = "CredentialReferenceOutOfScope"; /// Runs the gate. /// The draft. /// The errors. public static IReadOnlyList Errors(DraftSnapshot draft) { var errors = new List(); foreach (var driver in draft.DriverInstances) { if (string.Equals(driver.DriverType, DriverTypeNames.Heidenhain, StringComparison.OrdinalIgnoreCase)) continue; if (!DriverCredentialPolicy.TryGet(driver.DriverType, out _)) continue; foreach (var problem in DriverCredentialPolicy.DescribeProblems(driver.DriverType, driver.DriverConfig)) errors.Add(new(Code, $"{driver.DriverType} driver '{driver.Name}': {problem}", driver.DriverInstanceId)); foreach (var device in draft.Devices.Where(d => string.Equals(d.DriverInstanceId, driver.DriverInstanceId, StringComparison.Ordinal))) { foreach (var problem in DriverCredentialPolicy.DescribeProblems(driver.DriverType, device.DeviceConfig)) errors.Add(new(Code, $"{driver.DriverType} device '{device.Name}': {problem}", device.DeviceId)); } } return errors; } }