fix(configuration): resolve Medium code-review findings (Configuration-002, -003, -006, -009)
Configuration-002: sp_PublishGeneration is transaction-nesting aware (BEGIN TRANSACTION vs SAVE TRANSACTION on @@TRANCOUNT) so a caller's outer transaction survives a publish failure; sp_ValidateDraft wrapped in TRY/CATCH. Configuration-003: ValidatePathLength uses the cluster's actual Enterprise/Site lengths when available, falling back to the conservative approximation. Configuration-006: ResilientConfigReader treats a command-timeout TaskCanceledException as a fault (not caller cancellation) and falls back. Configuration-009: removed the checked-in plaintext sa connection string; CreateDbContext now requires OTOPCUA_CONFIG_CONNECTION. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -11,6 +11,18 @@ public sealed class DraftSnapshot
|
||||
public required long GenerationId { get; init; }
|
||||
public required string ClusterId { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Cluster's Enterprise segment (UNS level 1). When set, <see cref="DraftValidator"/> uses
|
||||
/// the actual length for path-length checks instead of a conservative 32-char upper bound.
|
||||
/// </summary>
|
||||
public string? Enterprise { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Cluster's Site segment (UNS level 2). When set, <see cref="DraftValidator"/> uses the
|
||||
/// actual length for path-length checks instead of a conservative 32-char upper bound.
|
||||
/// </summary>
|
||||
public string? Site { get; init; }
|
||||
|
||||
public IReadOnlyList<Namespace> Namespaces { get; init; } = [];
|
||||
public IReadOnlyList<DriverInstance> DriverInstances { get; init; } = [];
|
||||
public IReadOnlyList<Device> Devices { get; init; } = [];
|
||||
|
||||
@@ -59,8 +59,13 @@ public static class DraftValidator
|
||||
/// <summary>Cluster.Enterprise + Site + area + line + equipment + 4 slashes ≤ 200 chars.</summary>
|
||||
private static void ValidatePathLength(DraftSnapshot draft, List<ValidationError> errors)
|
||||
{
|
||||
// The cluster row isn't in the snapshot — we assume caller pre-validated Enterprise+Site
|
||||
// length and bound them as constants <= 64 chars each. Here we validate the dynamic portion.
|
||||
// Use actual Enterprise/Site lengths when the snapshot carries them (populated by
|
||||
// DraftValidationService from the ServerCluster row). Fall back to a conservative
|
||||
// 32-char upper bound per segment when not supplied — over-penalises short values
|
||||
// but never under-penalises long ones, which is acceptable for the fallback case.
|
||||
var enterpriseLen = draft.Enterprise?.Length ?? 32;
|
||||
var siteLen = draft.Site?.Length ?? 32;
|
||||
|
||||
var areaById = draft.UnsAreas.ToDictionary(a => a.UnsAreaId);
|
||||
var lineById = draft.UnsLines.ToDictionary(l => l.UnsLineId);
|
||||
|
||||
@@ -69,8 +74,7 @@ public static class DraftValidator
|
||||
if (!lineById.TryGetValue(eq.UnsLineId!, out var line)) continue;
|
||||
if (!areaById.TryGetValue(line.UnsAreaId, out var area)) continue;
|
||||
|
||||
// rough upper bound: Enterprise+Site at most 32+32; add dynamic segments + 4 slashes
|
||||
var len = 32 + 32 + area.Name.Length + line.Name.Length + eq.Name.Length + 4;
|
||||
var len = enterpriseLen + siteLen + area.Name.Length + line.Name.Length + eq.Name.Length + 4;
|
||||
if (len > MaxPathLength)
|
||||
errors.Add(new("PathTooLong",
|
||||
$"Equipment path exceeds {MaxPathLength} chars (approx {len})",
|
||||
|
||||
Reference in New Issue
Block a user