63331b0416
#835: inside one driver namespace, a secret:<ns>/<X>/... reference whose first segment names ANOTHER existing same-type driver instance (id or name, case-insensitive; another-instance match beats an own-name match, so renaming one's driver after a victim's unlocks nothing) is refused at save (DriverConfigSaveGate.ValidateAsync), deploy (CredentialReferenceOtherInstance, Heidenhain included), Test Connect (TestDriverConnect.DriverInstanceId, ConfigDb read off the mailbox) and live browse (BrowserSessionService, fail-closed without a ConfigDb). One rule: DriverCredentialPolicy.DescribeOtherInstanceProblems + DriverInstanceIdentities. Shared names and the driver's own id stay valid; env: is not instance-scoped. Running drivers are unchanged (warn-only window: the deploy gate and the upgrade preflight / /raw banner list them). #836: OpcUaClient UserCertificatePath is a relative path inside Drivers:OpcUaClient:UserCertificateDirectory (default <LocalAppData>/OtOpcUa/pki/user-certificates). Syntactic rule (CredentialFilePaths, a DriverCredentialPolicy path field) at every #815 seam; at load time ResolveSecretRefsAsync joins, canonicalises and requires lexical AND link-resolved containment before the PFX password is resolved, and LoadCertificate refuses an unresolved path. A running driver's pre-#836 absolute path keeps loading with a rate-limited warning (LegacyCredentialReferenceTracker.ReportPath). Co-Authored-By: Claude <noreply@anthropic.com>
49 lines
2.6 KiB
C#
49 lines
2.6 KiB
C#
using Microsoft.EntityFrameworkCore;
|
|
using ZB.MOM.WW.OtOpcUa.Core.Abstractions;
|
|
|
|
namespace ZB.MOM.WW.OtOpcUa.Configuration.Validation;
|
|
|
|
/// <summary>
|
|
/// Loads the driver-instance identities the cross-instance credential rule (lmxopcua#835,
|
|
/// <see cref="DriverCredentialPolicy.DescribeOtherInstanceProblems"/>) matches against — the ONE query the AdminUI save
|
|
/// path, live browse and Test Connect share (the deploy gate reads the same rows from its draft snapshot).
|
|
/// </summary>
|
|
public static class DriverInstanceIdentities
|
|
{
|
|
/// <summary>Every stored driver instance of <paramref name="driverType"/>, fleet-wide.</summary>
|
|
/// <param name="db">The config DB.</param>
|
|
/// <param name="driverType">The driver type (compared case-insensitively, client-side).</param>
|
|
/// <param name="ct">Cancellation.</param>
|
|
/// <returns>The identities.</returns>
|
|
public static async Task<IReadOnlyList<DriverInstanceIdentity>> LoadAsync(
|
|
OtOpcUaConfigDbContext db, string driverType, CancellationToken ct)
|
|
{
|
|
ArgumentNullException.ThrowIfNull(db);
|
|
var rows = await db.DriverInstances.AsNoTracking()
|
|
.Select(d => new { d.DriverInstanceId, d.Name, d.DriverType })
|
|
.ToListAsync(ct).ConfigureAwait(false);
|
|
return rows
|
|
.Where(r => string.Equals(r.DriverType, driverType, StringComparison.OrdinalIgnoreCase))
|
|
.Select(r => new DriverInstanceIdentity(r.DriverInstanceId, r.Name, r.DriverType))
|
|
.ToList();
|
|
}
|
|
|
|
/// <summary>
|
|
/// The cross-instance problems of <paramref name="configJson"/> — reading the ConfigDb only when the config carries
|
|
/// an in-scope <c>secret:</c> reference at all.
|
|
/// </summary>
|
|
/// <param name="db">The config DB.</param>
|
|
/// <param name="driverType">The owning driver's type.</param>
|
|
/// <param name="configJson">The config about to be stored / probed / browsed.</param>
|
|
/// <param name="ownDriverInstanceId">The owning driver; null when it is being created.</param>
|
|
/// <param name="ct">Cancellation.</param>
|
|
/// <returns>The problems.</returns>
|
|
public static async Task<IReadOnlyList<string>> DescribeOtherInstanceProblemsAsync(
|
|
OtOpcUaConfigDbContext db, string? driverType, string? configJson, string? ownDriverInstanceId, CancellationToken ct)
|
|
{
|
|
if (driverType is null || !DriverCredentialPolicy.HasInstanceSegments(driverType, configJson)) return [];
|
|
var instances = await LoadAsync(db, driverType, ct).ConfigureAwait(false);
|
|
return DriverCredentialPolicy.DescribeOtherInstanceProblems(driverType, configJson, ownDriverInstanceId, instances);
|
|
}
|
|
}
|