From 0f92e9e238805fbdf0799af24abc388ac1d2437d Mon Sep 17 00:00:00 2001 From: Joseph Doherty Date: Tue, 16 Jun 2026 22:31:42 -0400 Subject: [PATCH] fix(adminui): reject AbLegacy array length >256 at author-time (review I-3) --- .../Uns/TagEditors/AbLegacyTagConfigModel.cs | 16 +++++++++- .../Uns/AbLegacyTagConfigModelTests.cs | 30 +++++++++++++++++++ 2 files changed, 45 insertions(+), 1 deletion(-) diff --git a/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Uns/TagEditors/AbLegacyTagConfigModel.cs b/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Uns/TagEditors/AbLegacyTagConfigModel.cs index d35fb320..e5d81829 100644 --- a/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Uns/TagEditors/AbLegacyTagConfigModel.cs +++ b/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Uns/TagEditors/AbLegacyTagConfigModel.cs @@ -44,5 +44,19 @@ public sealed class AbLegacyTagConfigModel /// Validation hook; returns an error message or null when the model is valid. public string? Validate() - => string.IsNullOrWhiteSpace(Address) ? "Address is required." : null; + { + if (string.IsNullOrWhiteSpace(Address)) + return "Address is required."; + + // Array-length cap: PCCC data-file elements are limited to AbLegacyArray.MaxElements (256). + // The driver-agnostic materialiser uses the raw arrayLength to set OPC UA ArrayDimensions, but the + // driver clamps to 256 at runtime — so an authored length > 256 produces a Part 6 §5.3.2 mismatch. + // Reject it here at author-time so the error surfaces in the TagModal before the config is saved. + var isArray = TagConfigJson.GetBool(_bag, "isArray"); + var arrayLength = TagConfigJson.GetInt(_bag, "arrayLength"); + if (isArray && arrayLength > AbLegacyArray.MaxElements) + return $"AbLegacy array length cannot exceed {AbLegacyArray.MaxElements} (PCCC data-file element limit)."; + + return null; + } } diff --git a/tests/Server/ZB.MOM.WW.OtOpcUa.AdminUI.Tests/Uns/AbLegacyTagConfigModelTests.cs b/tests/Server/ZB.MOM.WW.OtOpcUa.AdminUI.Tests/Uns/AbLegacyTagConfigModelTests.cs index 6552bcb5..e9e8f2f4 100644 --- a/tests/Server/ZB.MOM.WW.OtOpcUa.AdminUI.Tests/Uns/AbLegacyTagConfigModelTests.cs +++ b/tests/Server/ZB.MOM.WW.OtOpcUa.AdminUI.Tests/Uns/AbLegacyTagConfigModelTests.cs @@ -99,4 +99,34 @@ public sealed class AbLegacyTagConfigModelTests json.ShouldContain("\"deviceHostAddress\":\"ab://host\""); } + + // Array-length cap (review I-3): authored arrayLength > 256 on an AbLegacy array tag must be + // rejected at author-time to prevent a Part 6 §5.3.2 ArrayDimensions mismatch at runtime. + + [Fact] + public void Validate_returns_error_when_array_length_exceeds_256() + { + var m = AbLegacyTagConfigModel.FromJson("""{"address":"N7:0","isArray":true,"arrayLength":300}"""); + + var error = m.Validate(); + + error.ShouldNotBeNull(); + error.ShouldContain("256"); + } + + [Fact] + public void Validate_returns_null_when_array_length_exactly_256() + { + var m = AbLegacyTagConfigModel.FromJson("""{"address":"N7:0","isArray":true,"arrayLength":256}"""); + + m.Validate().ShouldBeNull(); + } + + [Fact] + public void Validate_returns_null_for_scalar_tag_regardless_of_no_array_length() + { + var m = AbLegacyTagConfigModel.FromJson("""{"address":"N7:0"}"""); + + m.Validate().ShouldBeNull(); + } }