diff --git a/code-reviews/Driver.FOCAS/findings.md b/code-reviews/Driver.FOCAS/findings.md index bede10f..8e3cf3d 100644 --- a/code-reviews/Driver.FOCAS/findings.md +++ b/code-reviews/Driver.FOCAS/findings.md @@ -7,7 +7,7 @@ | Review date | 2026-05-22 | | Commit reviewed | `76d35d1` | | Status | Reviewed | -| Open findings | 9 | +| Open findings | 8 | ## Checklist coverage @@ -119,7 +119,7 @@ unresolved device host so the operator fixes the typo at startup. | Severity | Medium | | Category | OtOpcUa conventions | | Location | `FocasDriver.cs:374-379`, `WireFocasClient.cs:48-50` | -| Status | Open | +| Status | Resolved | **Description:** `DiscoverAsync` emits user tags with `SecurityClass = tag.Writable ? SecurityClassification.Operate : SecurityClassification.ViewOnly`, @@ -137,7 +137,7 @@ be written. write. Given the wire backend is read-only and is the only production backend, treating all FOCAS tags as `ViewOnly` is the simplest correct behaviour. -**Resolution:** _(open)_ +**Resolution:** Resolved 2026-05-22 — `DiscoverAsync` now unconditionally emits `SecurityClassification.ViewOnly` for all user-authored tags; the `Writable` config field no longer influences the advertised security class since the wire backend never writes. ### Driver.FOCAS-005 diff --git a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.FOCAS.Tests/FocasCapabilityTests.cs b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.FOCAS.Tests/FocasCapabilityTests.cs index 2c002a6..befcad2 100644 --- a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.FOCAS.Tests/FocasCapabilityTests.cs +++ b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.FOCAS.Tests/FocasCapabilityTests.cs @@ -31,7 +31,9 @@ public sealed class FocasCapabilityTests builder.Folders.ShouldContain(f => f.BrowseName == "FOCAS"); builder.Folders.ShouldContain(f => f.BrowseName == "focas://10.0.0.5:8193" && f.DisplayName == "Lathe-1"); - builder.Variables.Single(v => v.BrowseName == "Run").Info.SecurityClass.ShouldBe(SecurityClassification.Operate); + // FOCAS is read-only by design — all user tags are ViewOnly regardless of the + // Writable field, because WireFocasClient.WriteAsync always returns BadNotWritable. + builder.Variables.Single(v => v.BrowseName == "Run").Info.SecurityClass.ShouldBe(SecurityClassification.ViewOnly); builder.Variables.Single(v => v.BrowseName == "Alarm").Info.SecurityClass.ShouldBe(SecurityClassification.ViewOnly); }