mirror of
https://github.com/OPCFoundation/UA-.NETStandard.git
synced 2026-10-19 07:02:16 +08:00
copilot/fix-code-review-comment
2391 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
8f0a9d4108 | Initial plan | ||
|
|
537b10c8b3 |
Fix History User Access Levels and add CTT coverage nodes (#4026)
# Description Improve Reference Server coverage for OPC UA Compliance Test Tool scenarios and document the latest CTT findings. ## Reference Server coverage - Historize the configured AccessRights nodes and seed them with the same deterministic mixed-quality history as the other test nodes while preserving their access controls. - Add a historian node that intentionally does not support ServerTimestamp. - Add a SelectionListType String instance whose Selections property is String[] as required by Part 5, with localized descriptions and RestrictToList enforcement. - Add an EUR CurrencyUnit property and verify its structured value and binary encoding. - Add a node with explicit read/write base access bits plus NonatomicRead and NonatomicWrite AccessLevelEx flags. - Ensure the first ByteString array elements meet the CTT minimum-length prerequisite. ## Latest CTT findings - Confirm run-23 A&C residuals are CTT re-entrant Read and branch-unaware Retain checks rather than server regressions. - Confirm NumberOfTransitions includes Uncertain values as required by Part 13. - Document the CTT CurrencyUnit decoder dropping a correctly encoded Exponent. ## Related Issues - Follow-up to #3960 and #4002. ## Checklist - [x] I have signed the [CLA](https://opcfoundation.org/license/cla/ContributorLicenseAgreementv1.0.pdf) and read the [CONTRIBUTING](https://github.com/OPCFoundation/UA-.NETStandard/blob/master/CONTRIBUTING.md) doc. - [x] I have added tests that prove my fix is effective or that my feature works and increased code coverage. - [x] I have added all necessary documentation. - [x] I have verified that my changes do not introduce (new) build or analyzer warnings. - [ ] I ran **all** tests locally using the **UA.slnx** solution against at least .net **framework** and .net **10**, and all passed. - [ ] I fixed **all** failing and flaky tests in the CI pipelines and **all** CodeQL warnings. - [x] I have addressed **all** PR feedback received. Focused affected tests pass on .NET 10 and .NET Framework 4.8. --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: Marc Schier <marcschier@hotmail.com> |
||
|
|
5206cc4e13 |
Self-fence Kubernetes Lease leadership using monotonic time (#4042)
## Failure Lease takeover trusted another replica's wall-clock `RenewTime`, so clock skew could steal a live Lease. A hung renewal could also leave local leadership asserted, and a stale completion or notification could resurrect leadership after fencing or disposal. ## Fix - Measure unchanged foreign `resourceVersion` age with local monotonic time. - Serialize and bound API attempts, and self-fence with a lease-duration watchdog. - Reject stale completions and suppress out-of-order leadership notifications. ## Standard This is a Kubernetes coordination extension to OPC 10000-4 §6.6 redundancy. Kubernetes Lease ownership is now evaluated from stable resource observations rather than untrusted peer wall clocks. ## Tests - `dotnet test tests\Opc.Ua.Redundancy.Kubernetes.Tests\Opc.Ua.Redundancy.Kubernetes.Tests.csproj -c Release --nologo -m:1` — 97 passed on net8.0 and 97 passed on net10.0 - Review follow-up: `KubernetesLeaseLeaderElectionTests` — 22 passed on net8.0. ## Split Split from #4021. --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> |
||
|
|
3c4661d2bf |
Protect certificate and identity secrets in MCP and durable samples (OPC 10000-4 security) (#4043)
## Failure MCP auto-accept mutated the shared application certificate manager and accepted every certificate error, so one permissive connection could affect concurrent or later strict sessions. The durable-subscription sample also serialized complete user identity tokens, including user-name passwords and issued bearer tokens. ## Fix - Isolate auto-accept certificate managers/configurations per connection and keep their lifetime with the managed session. - Auto-accept only `BadCertificateUntrusted`; retain strict validation for all other certificate errors and shared sessions. - Version the durable store and reject the previous unsafe format. - Remove user-name passwords before persistence and reject issued-token subscriptions rather than storing bearer credentials. - Add focused tools tests plus solution, project, and durable-subscription docs. ## Reference - OPC 10000-4 Session identity-token and application-certificate security. - Split from #4021. ## Tests - `Opc.Ua.Tools.Tests` Release: 7 passed on net10.0; 4 passed on net48. - `Quickstarts.Servers` Release builds passed on net10.0 and net48 with zero warnings/errors. - `Opc.Ua.Mcp` Release net10.0 build passed with zero warnings/errors. --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> |
||
|
|
1d2a7c8d00 |
Complete partial vectored UA-TCP sends (OPC 10000-6) (#4028)
# Description Stream socket semantics permit a successful vectored send to complete after fewer bytes than requested. The previous one-shot send treated that legal partial completion as a closed connection and left the remaining bytes unsent, risking truncation of an OPC 10000-6 UA-TCP message chunk. The transport now continues sending while advancing across copied buffer segments, without mutating the caller's `BufferCollection`, and rejects zero-byte or impossible over-reported sends. ## Validation - `TcpByteTransportTests`: net10.0 (10 passed), net48 (10 passed). - `git diff --check` passed. ## Related Issues - Split from #4021. ## Checklist _Only verified claims are checked._ - [ ] I have signed the [CLA](https://opcfoundation.org/license/cla/ContributorLicenseAgreementv1.0.pdf) and read the [CONTRIBUTING](https://github.com/OPCFoundation/UA-.NETStandard/blob/master/CONTRIBUTING.md) doc. - [ ] I have added tests that prove my fix is effective or that my feature works and increased code coverage. - [ ] I have added all necessary documentation. - [x] I have verified that my changes do not introduce (new) build or analyzer warnings. - [ ] I ran **all** tests locally using the **UA.slnx** solution against at least .net **framework** and .net **10**, and all passed. - [ ] I fixed **all** failing and flaky tests in the CI pipelines and **all** CodeQL warnings. - [ ] I have addressed **all** PR feedback received. --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> |
||
|
|
973cc81483 |
fix(di): accept FunctionalGroupType subtypes in BrowseFunctionalGroupsAsync (#4032)
### Summary This PR makes `DiDeviceClient.BrowseFunctionalGroupsAsync()` accept `FunctionalGroupType` subtypes instead of requiring an exact type-definition match and adds a regression test that verifies derived functional groups are included in the returned results. ### Problem In OPC UA DI, functional groups may be modeled as instances of `FunctionalGroupType` or of any subtype derived from it. A client helper that enumerates functional groups therefore needs to follow the OPC UA type hierarchy instead of requiring the object's `TypeDefinition` to be exactly `FunctionalGroupType`. Previously, `BrowseFunctionalGroupsAsync()` filtered browse results through a helper named `IsSubtypeOf()`, but that helper only compared `typeDefinition == expectedType`. As a result, any device that exposed functional groups through a legal subtype of `FunctionalGroupType` would have those groups silently filtered out even though they were valid DI functional-group objects. ### Changes - Replace the exact type-definition comparison in `BrowseFunctionalGroupsAsync()` with a real subtype check based on `Session.NodeCache.IsTypeOfAsync(...)`. - Preserve the existing filtering behaviour for non-functional-group objects. - Add a regression test that verifies a derived functional-group type is returned while an unrelated object is still excluded. |
||
|
|
8602d40cff |
fix(alias): compare PortableNodeId identifiers by NodeId semantics (#4037)
### Summary This PR fixes `AliasNamePubSubRefreshStrategy` category matching for string NodeIds whose identifier contains semicolons and adds a regression test covering that scenario. ### Problem `AliasNamePubSubRefreshStrategy` is supposed to match the publisher's `PortableNodeId.Identifier` against the local alias category `NodeId` while ignoring namespace index differences. However, the previous implementation did that by converting both NodeIds to text and stripping everything before the first `;`. That happened to work for simple identifiers such as `ns=1;s=MyCategory`, but it broke for valid string NodeIds whose identifier itself contains semicolons. For example, when the local category is `ns=1;s=A;B`, the previous logic transformed the local value into `s=A;B` but transformed the already namespace-free portable form `s=A;B` into just `B`. As a result, both sides represented the same identifier semantically, yet the refresh strategy could never match them and would silently ignore legitimate alias update messages for that category. ### Changes - Replace the string-prefix stripping comparison in `AliasNamePubSubRefreshStrategy` with namespace-insensitive `NodeId` equality, preserving the original identifier type and value. - Add a regression test that verifies a PubSub alias update for a category such as `s=A;B` still invalidates the local cache. |
||
|
|
8f4087605a |
Fix unordered server endpoint validation (#4029)
### Summary This PR makes `Session.ValidateServerEndpoints()` compare `ServerEndpoints` and `UserIdentityTokens` as unordered sets and adds regression tests that verify `OpenAsync()` no longer rejects legal servers that return the same endpoint data in a different order. ### Problem According to OPC UA Part 4, the client validates the endpoint set returned by `CreateSessionResponse.ServerEndpoints` against the endpoint set observed during discovery. The specification describes these values as a set of endpoint descriptions filtered by the relevant transport profile, not as an ordered array that must preserve the exact discovery-time enumeration order. Previously, `Session.ValidateServerEndpoints()` first checked the endpoint count and then compared `m_discoveryServerEndpoints[ii]` against `serverEndpoints[ii]` by index. It also compared `UserIdentityTokens[jj]` by index within each endpoint. As a result, a server that returned the same legal endpoints in a different order, or returned the same token policies in a different order within an endpoint, could be rejected with `BadSecurityChecksFailed` even though the endpoint data itself had not changed. ### Changes - Replace index-based `ServerEndpoints` validation with unordered matching based on the same endpoint fields already validated by the client. - Compare `UserIdentityTokens` as an unordered multiset instead of requiring the server to preserve the original token enumeration order. - Extend the client session test scaffolding so discovery endpoints can be supplied explicitly. - Add regression tests that verify `OpenAsync()` accepts reordered `ServerEndpoints` and reordered `UserIdentityTokens`. |
||
|
|
399747f6a0 |
fix: don't return continuation points on BadNoContinuationPoints (#4022)
### Summary This PR fixes `Browse` and `BrowseNext` so they do not return a usable continuation point when the server reports `BadNoContinuationPoints`, and adds regression tests that cover both code paths. ### Problem According to OPC UA Part 4, if the server cannot allocate another continuation point for a `Browse` or `BrowseNext` operation, the result should be `Bad_NoContinuationPoints`. In that case, the server must not also return a continuation point that the client can continue to use. Previously, `MasterNodeManager.FetchReferencesAsync()` could return `BadNoContinuationPoints` while still passing a live continuation point object back to its callers. `BrowseAsync()` then copied that continuation point into the result, producing a contradictory response with `StatusCode = BadNoContinuationPoints` and a non-empty `ContinuationPoint`. `BrowseNextAsync()` went further and overwrote the error with `Good` whenever a continuation point object was still present. That behavior hides continuation-point quota exhaustion and breaks the expected paging semantics. ### Changes - Dispose and clear the continuation point when `FetchReferencesAsync()` hits the no-continuation-points path. - Only copy a continuation point into `Browse` and `BrowseNext` results when the operation completed successfully. - Add deterministic regression tests that verify both `Browse` and `BrowseNext` return `BadNoContinuationPoints` without a continuation point when the continuation-point quota is exhausted. |
||
|
|
f6ae61c6bc |
fix(di): accept DeviceType subtypes during device discovery (#4033)
### Summary This PR makes `DiDiscoveryClient.EnumerateDevicesAsync()` accept `DeviceType` subtypes instead of requiring an exact type-definition match and adds regression tests that verify derived device types are discovered while non-device objects remain filtered out. ### Problem In OPC UA DI, device instances may be modeled directly as `DeviceType` or as instances of any subtype derived from `DeviceType`. A discovery helper that claims to enumerate `DeviceType` devices therefore needs to follow the OPC UA type hierarchy instead of requiring an exact `TypeDefinition` match. Previously, `DiDiscoveryClient.BrowseForDevicesAsync()` identified devices with a direct comparison against `DeviceType`. As a result, any server that exposed devices through a legal subtype of `DeviceType` would have those devices treated as non-device objects, causing them to be skipped or only used as recursion points instead of being returned as discovered devices. ### Changes - Replace the exact `DeviceType` comparison in `BrowseForDevicesAsync()` with a real subtype check based on `session.NodeCache.IsTypeOfAsync(...)`. - Preserve the existing recursive browse behaviour for non-device objects. - Add regression coverage that verifies exact `DeviceType` instances still work, derived device types are now discovered, and non-device objects are still excluded. |
||
|
|
565fc02535 |
fix(subscription): fail transfer synchronization when deleting stale monitored items (#4031)
### Summary This PR makes `MonitoredItemManager.TrySynchronizeHandlesAsync()` treat `DeleteMonitoredItems` failures as transfer-synchronization failures and adds a regression test that verifies the client no longer reports success when the server rejects deletion of stale monitored items. ### Problem OPC UA Part 4 requires clients to evaluate service results at two levels: `ResponseHeader.ServiceResult` reports the outcome of the service call as a whole. `Results[]` reports the outcome of each individual operation in that service. Even when the service-level result is `Good`, the service may still have only partially succeeded. The client therefore still needs to inspect the response payload, especially the per-operation `StatusCode` values, before concluding that the requested work actually completed. In `TrySynchronizeHandlesAsync()`, the transfer/recovery path deletes monitored items that still exist on the server but no longer exist locally. Previously, this delete path treated `DeleteMonitoredItemsAsync()` as successful as long as the call itself did not throw, and it did not validate `ResponseHeader.ServiceResult`, `Results[]`, or the associated diagnostic information. As a result, the client could report transfer synchronization success even when the server explicitly returned failures for one or more stale monitored items. ### Changes - Validate the `DeleteMonitoredItemsAsync()` response inside `TrySynchronizeHandlesAsync()` instead of treating any non-throwing call as success. - Return `false` when the delete operation reports a bad service-level result or any bad per-item result, so synchronization only succeeds after stale server-side items are actually removed. - Add a regression test that verifies `TryCompleteTransferAsync()` returns `false` when deletion of an extraneous server-side monitored item is rejected. |
||
|
|
b105eaae02 |
fix(subscription): do not acknowledge keep-alive future sequence numbers (#4030)
### Summary This PR stops the V2 subscription message processor from acknowledging keep-alive sequence numbers and adds a regression test that verifies acknowledgements are only queued for notification messages that actually contain data. ### Problem According to OPC UA Part 4 publish semantics, a keep-alive `NotificationMessage` does not acknowledge delivery of a real notification. Its `SequenceNumber` identifies the next notification message that will be sent, not a notification payload that the client has already received. Previously, `MessageProcessor.ProcessMessageAsync()` correctly treated `NotificationData.Count == 0` as a keep-alive and intentionally avoided advancing the data-message deduplication gate. However, `OnNotificationReceivedAsync()` still unconditionally queued a `SubscriptionAcknowledgement` for every message, including empty keep-alives. As a result, the V2 client could acknowledge a future sequence number before the corresponding data/event notification had actually been received. This could produce spurious acknowledgement noise against strict servers and made the V2 path inconsistent with the existing classic subscription engine, which only acknowledges messages that contain notification data. ### Changes - Stop queueing acknowledgements for keep-alive messages in `MessageProcessor.OnNotificationReceivedAsync()`. - Preserve the existing keep-alive dispatch path and continue acknowledging notification messages that carry real data. - Extend the message processor tests to verify that keep-alives do not enqueue acknowledgements and that the subsequent real notification still does. |
||
|
|
12f770b3b6 |
Fix managed session failover target selection (#4025)
### Summary This PR makes `ManagedSession` select failover targets relative to the currently active endpoint after a successful failover and adds a regression test that verifies subsequent failover decisions no longer use the original connection target as the current server. ### Problem According to OPC UA Part 4 redundancy semantics, once a client has failed over to a different redundant server, subsequent target selection must be based on the server that is currently hosting the active session. The current server is not permanently tied to the endpoint that was used for the initial connection. Previously, `ManagedSession` stored the constructor-supplied `ConfiguredEndpoint` in a read-only property and always passed that outer value into `IServerRedundancyHandler.SelectFailoverTarget()`. However, the inner `Session` updates its own `ConfiguredEndpoint` during `RecreateInPlaceAsync()` when failover succeeds. After the first failover, the outer `ManagedSession` and inner `Session` could therefore disagree about which redundant member was currently active, causing later failover decisions to be evaluated against the original endpoint instead of the active one. ### Changes - Make `ManagedSession.HandleFailoverAsync()` prefer the inner session's current `ConfiguredEndpoint` when selecting a failover target, while keeping the outer endpoint as a fallback before the session is available. - Preserve the existing failover flow and scope the fix to target selection only. - Add a regression test that verifies `HandleFailoverAsync()` passes the inner session's current endpoint to `IServerRedundancyHandler.SelectFailoverTarget()`. |
||
|
|
70c74e7cb8 |
fix: scope Cancel request matching to the current session (#4023)
### Summary This PR scopes `Cancel` request matching to the caller's session and adds regression tests that verify a request handle can no longer cancel work that belongs to another session. ### Problem According to OPC UA Part 4, `Cancel` applies to a request handle from the same session that issued the original request. The server should not use a client-supplied `requestHandle` to match outstanding requests across all sessions. Previously, `StandardServer.CancelAsync()` validated the caller's session but then forwarded only the raw `requestHandle` to `RequestManager.CancelRequests()`. `RequestManager` iterated the global outstanding-request table and canceled every request whose `ClientHandle` matched, without checking the owning session. Since request handles are only session-scoped and different sessions can legitimately reuse the same value, one session could cancel another session's in-flight request. ### Changes - Pass the validated caller session id from `StandardServer.CancelAsync()` into `RequestManager.CancelRequests()`. - Restrict `RequestManager.CancelRequests()` to requests whose `SessionId` and `ClientHandle` both match the `Cancel` request. - Update existing request-manager and publish-queue tests to pass the session id and add a regression test that proves matching request handles in different sessions no longer interfere with each other. |
||
|
|
2d55126cb8 |
fix: return BadInvalidState for unlatched alarm reset (#4020)
### Summary This PR fixes the reset status code returned for unlatched alarms and adds a regression test that verifies `Reset` and `Reset2` both report `BadInvalidState` when the alarm is not latched. ### Problem According to the alarm reset semantics described in OPC UA Part 9, `Reset` is only valid for a latched alarm that is no longer active and has already been acknowledged and confirmed when those states are present. For any other invalid state, the server should return `Bad_InvalidState`. Previously, `AlarmConditionState.HandleResetCore()` returned `BadConditionNotShelved` when `LatchedState.Id == false`. That status code belongs to the shelving state machine, not the latched alarm reset flow. As a result, clients calling `AlarmClient.ResetAsync()` could receive a shelving-related error for a reset precondition failure, which misrepresents the actual alarm state and breaks the expected Part 9 semantics. ### Changes - Change the unlatched branch in `AlarmConditionState.HandleResetCore()` to return `BadInvalidState` instead of `BadConditionNotShelved`. - Add a regression test in `AlarmConditionStateMethodTests` that covers both `Reset` and `Reset2` when `LatchedState` exists but the alarm is not latched. |
||
|
|
20d9d65a64 |
Fix generated configuration namespace resolution (#4019)
# Description Fix source-generated configuration types whose explicit namespace references constants emitted by the same generator pass. Roslyn cannot resolve those constants while `[DataType]` attributes are analyzed, so the generated XML codec silently fell back to `urn:memorybuffer` / `urn:testdata` while the shipped configuration uses the model namespace URIs. This change: - adds `MODELGEN021` to fail when an explicitly supplied `[DataType.Namespace]` expression cannot be resolved; - uses compile-time-available model namespace URIs for the MemoryBuffer and TestData configuration types; - restores production-shaped XML fixtures and exercises the `UpdateExtension<T>()` / `ParseExtension<T>()` path; - documents the source-generator namespace requirement and migration guidance. Targeted validation passed: - `TypeGeneratorTests`: 17 tests on `net10.0` and `net48`; - `ConfigurationRoundTripTests`: 4 tests on `net10.0` and `net48`. ## Related Issues - Fixes #4014 ## Checklist - [ ] I have signed the [CLA](https://opcfoundation.org/license/cla/ContributorLicenseAgreementv1.0.pdf) and read the [CONTRIBUTING](https://github.com/OPCFoundation/UA-.NETStandard/blob/master/CONTRIBUTING.md) doc. - [x] I have added tests that prove my fix is effective or that my feature works and increased code coverage. - [x] I have added all necessary documentation. - [x] I have verified that my changes do not introduce (new) build or analyzer warnings. - [ ] I ran **all** tests locally using the **UA.slnx** solution against at least .net **framework** and .net **10**, and all passed. - [ ] I fixed **all** failing and flaky tests in the CI pipelines and **all** CodeQL warnings. - [x] I have addressed **all** PR feedback received. |
||
|
|
84fa8e8906 |
CTT follow-up: monitored items, alarms, codecs, history, and model validation (#4002)
# Description Follow-up to #3978 based on the latest OPC UA CTT aggregate, matrix, Historical Access, Attribute, and Node Management runs. ## Aggregate run 16 - Ignore synthetic `BadBoundNotFound` raw-bound markers when feeding aggregate calculators. - Add direct and live historian regression coverage. ## Multi-dimensional Variant matrices - Fix `Variant.Copy()` so rank-2 Variant matrices preserve their payload and dimensions. - Enforce valid Variant matrix dimensions consistently across Binary, JSON, XML stream, and XML parser codecs. - Encoders return `BadEncodingError`; decoders return `BadDecodingError` for malformed matrix dimensions. - Add cross-codec valid/null/empty/malformed tests and a batched ReferenceServer Read regression. - Correct the previous CTT issue attribution: the invalid `Scalar_Static_Arrays2D_Variant` server encoding poisoned the batched CTT Read. ## Node Management AddNodes - Return `BadNodeIdRejected` for unsupported requested-NodeId namespaces. - Validate hierarchical ReferenceType source/target NodeClass constraints. - Document run-18 confirmation that all remaining 15 AddNodes errors are CTT project/script configuration issues. ## Historical Access and Attribute Services run 18 - Reject whitespace in `NumericRange` syntax with `BadIndexRangeInvalid`. - Add HistoryRead tests for operation-level invalid syntax and per-DataValue `BadIndexRangeNoData`. - Document CTT defects: - `012.js` expects `BadIndexRangeNoData` at the operation level instead of on returned DataValues; - `Err-012.js` uses a non-historizing node for an access-denied test; - generic Attribute array helpers omit NodeId[] and StatusCode[] conversion paths. ## Base Information model validation run 19 - Run the CTT main session as `sysadmin` over Basic256Sha256 SignAndEncrypt so SecurityAdmin RolePermissions and EncryptionRequired restrictions are both satisfied without weakening the server model. - Preserve predefined well-known NodeIds while making generated dynamic type and optional-child factories allocate compatible per-instance NodeIds, remap internal references, and update references from the owning subtree. - Materialize dynamic RoleType properties through generated helpers and keep role-child string NodeIds disjoint from numeric RoleManager root IDs. - Add net48/net10 regressions for generator output, NodeId allocation/reference remapping, DI mandatory children, dynamic roles, and low-privilege versus SecurityAdmin Browse visibility. - Document CTT defects for permission-unaware mandatory-child validation, the UA 1.04 reference model used against a UA 1.05 server, stale ServerDiagnostics cache, and the `ConformanceUnits` scalar/array mismatch. ## Related Issues - Follow-up to #3960 and #3978. ## Checklist - [x] I have signed the CLA and read the CONTRIBUTING document. - [x] Tests prove the fixes and improve coverage. - [x] Required CTT documentation is updated. - [x] Focused builds/tests introduce no warnings. - [x] Affected tests pass on .NET Framework and .NET 10. - [ ] CI and CodeQL are green. - [ ] All PR feedback is addressed. ## Latest CTT full run and A&C run 20 - Fix Monitor Value Change V2 `036.js`: an ambiguous `DataValue(StatusCode)` call encoded `BadIndexRangeNoData` as a Good value. - Prove all 19 configured matrix monitored items notify when the selected value actually changes; document the independent `042.js` script defects. - Rebase dynamic `CertificateExpired` / `TrustListOutOfDate` alarm roots and descendants, restore standard type declarations and ModellingRules, and expose the cross-node-manager references. - Deliver method-triggered events to every authorized Session, fixing the two-Session Confirm scenario. - Preserve locale-only `LocalizedText` values consistently across Binary, JSON, and XML and align Acknowledge/Confirm comment behavior and tests. - Document the remaining proven CTT defects for TransactionDiagnostics, SemanticChange, History `013`, PolicyId scope, A&C, durable subscriptions, and Subscription Minimum events. ## Base synchronization Merged `master` through `007cfaf90` (`#4010`, repository layout consolidation) and retained the matrix regression tests at their new `tests/` locations. ## Latest validation - Focused merged-tree tests pass on net10 and net48. - `Opc.Ua.Server` and `Quickstarts.Servers` Release builds complete with 0 warnings and 0 errors on net10 and net48. - The existing `DisableEnableViaTypeAndInstanceMethodNoEventsDuringDisabledAsync` timing test took its documented inconclusive timeout path after the layout merge; no test failure was reported. --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com> Co-authored-by: romanett <romanett98@gmail.com> |
||
|
|
b76022d13d |
Add MinimalClient - lightweight OPC UA console client with fluent API (#4006)
# Description
Adds `MinimalClient`, a compact console OPC UA application demonstrating
the unified dependency-injection surface, secure endpoint discovery,
managed sessions, fluent V2 subscriptions, and Alarms & Conditions
support.
## Changes
- Adds `ConfigureApplication(options => ...)` to build and validate one
shared `ApplicationConfiguration` for combined client/server hosts.
- Extends `OpcUaClientOptions` so the existing `AddClient(options =>
...)` callback accepts application identity, PKI, and
certificate-validation settings like `AddServer(...)`.
- Composes root `ConfigureApplication(...)` values with client defaults
in either registration order; shared values take precedence and client
values fill gaps.
- Keeps server samples on their established `AddServer(...)`
configuration pattern.
- Adds `MinimalClient` as a .NET 10 Native AOT console application using
top-level statements and `HostApplicationBuilder`.
- Discovers a `SignAndEncrypt` / `Basic256Sha256` endpoint by default;
`--insecure` and `--auto-accept` are explicit opt-ins with warnings.
- Demonstrates fluent `AddSubscription(...)`,
`TryAddMonitoredItem(...)`, and `AlarmClientFactory` usage.
- Adds targeted configuration, client, and combined client/server tests.
## Example
```csharp
builder.Services
.AddOpcUa()
.AddClient(options =>
{
options.ApplicationName = "MinimalClient";
options.ApplicationUri = "urn:localhost:OPCFoundation:MinimalClient";
options.ProductUri = "uri:opcfoundation.org:MinimalClient";
options.Session = new ManagedSessionOptions
{
SessionName = "MinimalClient",
SessionTimeout = TimeSpan.FromSeconds(60)
};
})
.AddDiscoveryAndConnect(options =>
{
options.DiscoveryUrl = discoveryUrl;
options.SecurityMode = MessageSecurityMode.SignAndEncrypt;
options.SecurityPolicyUri = SecurityPolicies.Basic256Sha256;
})
.AddSubscriptions()
.AddAlarms();
```
## Related Issues
_If there is no issue yet, open one and link it here._
## Checklist
- [ ] I have signed the
[CLA](https://opcfoundation.org/license/cla/ContributorLicenseAgreementv1.0.pdf)
and read the
[CONTRIBUTING](https://github.com/OPCFoundation/UA-.NETStandard/blob/master/CONTRIBUTING.md)
doc.
- [x] I have added tests that prove my fix is effective or that my
feature works and increased code coverage.
- [x] I have added all necessary documentation.
- [x] I have verified that my changes do not introduce new build or
analyzer warnings.
- [ ] I ran all tests locally using the `UA.slnx` solution against at
least .NET Framework and .NET 10.
- [ ] I fixed all failing and flaky tests in the CI pipelines and all
CodeQL warnings.
- [x] I have addressed all PR feedback received.
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: romanett <romanett98@gmail.com>
Co-authored-by: Marc Schier <marcschier@hotmail.com>
|
||
|
|
41a648c9db |
Fail fast on reverse connect listener startup (#4009)
# Description Fail reverse-connect listener startup immediately instead of logging bind failures and surfacing a later connection timeout. - Validate and stage configured and programmatic listener endpoints before replacing active configuration. - Open all listeners atomically and report endpoint-specific failures with `BadTcpEndpointUrlInvalid`, the transport-specific status, or `BadNoCommunication`. - Roll back listeners opened by a failed attempt without reacquiring the manager lock, including forced listener disposal when normal close fails. - Preserve meaningful `ServiceResultException` status codes through both `StartService` overloads. - Dispose replaced configuration watchers and reject callbacks from stale watcher generations. - Keep the intended shared-listener behavior: one long-lived `ReverseConnectManager` can accept connections from multiple Servers on the same Client URL. - Expand `Docs/ReverseConnect.md` with listener lifetime, shared-manager usage, diagnostics, and specification references. ## Validation - `ReverseConnectManagerTests`: net10.0 and net48. - `ReverseConnectHostTests`: net10.0 and net48. - Ordered reverse-connect listener reuse integration tests: net10.0. ## Related Issues - Relates to #3985. ## Checklist - [ ] I have signed the [CLA](https://opcfoundation.org/license/cla/ContributorLicenseAgreementv1.0.pdf) and read the [CONTRIBUTING](https://github.com/OPCFoundation/UA-.NETStandard/blob/master/CONTRIBUTING.md) doc. - [x] I have added tests that prove my fix is effective or that my feature works and increased code coverage. - [x] I have added all necessary documentation. - [x] I have verified that my changes do not introduce (new) build or analyzer warnings. - [ ] I ran **all** tests locally using the **UA.slnx** solution against at least .net **framework** and .net **10**, and all passed. - [ ] I fixed **all** failing and flaky tests in the CI pipelines and **all** CodeQL warnings. - [ ] I have addressed **all** PR feedback received. |
||
|
|
98984af7c3 |
CI: share managed pool and hosted agents across the pipeline (#3969)
Replace the all-or-nothing `managedPool` boolean with a `poolMode` enum (mixed | managed | hosted) and route stages across two pool profiles so the netstandard Managed DevOps Pool and the Microsoft-hosted agents share the workload of a single run. - mixed (default): each stage uses its assigned profile, so both pools run in parallel. The two always-concurrent PR stages are split across pools: build -> hosted (bigger temp disk for multi-TFM bin trees), testfastpr -> managed (fast, image-pinned gate). Full-run stages are balanced ~5/5. - managed / hosted: global overrides that collapse both profiles onto a single pool (all-managed or all-hosted) for emergencies. The pool switch lives only in the variables block (mgd*/host* profiles), so stages carry no per-stage conditionals. macOS is unchanged (always hosted; the managed pool has no macOS images). |
||
|
|
12ebfba603 |
Add ISA95 JobControl and ManagedSession regression coverage (#3998)
## Summary - Adds the official ISA95 JobControl 2.0.0 NodeSet2 as a complete source-generator regression fixture. - Extends the lightweight generated-stack test stub with `NamespaceMetadataState`, required by the complete model. - Adds a deterministic ManagedSession cancellation regression proving that a started connect attempt is stopped. The ManagedSession cleanup implementation and Quickstarts utility coverage now come from `master`; this PR retains the additional deterministic cleanup regression. ## ISA95 fixture provenance and integrity The fixture is byte-for-byte the official file: - Source: `OPCFoundation/UA-Nodeset@e0b5d80cfff698f0276393e28df138a7fbc4b541` - Path: `ISA95-JOBCONTROL/opc.ua.isa95-jobcontrol.nodeset2.xml` - Git blob: `82f008cd126ade54e5f2c737bcc116621a8c3087` - SHA-256: `52327e736beb604c7253a5a5393d1ad525b9ecf35b71fbacb4f429cacb334064` The fixture test retains the OPC Foundation MIT header and verifies the 2.0.0 model/date, 258 nodes (including 134 variables), representative late variables, and that every `ns=1` reference target resolves locally. ## Validation - ManagedSession tests: 17 passing on net10.0; 15 passing and 2 framework-gated skips on net48. - Quickstarts server utility tests: 3 passing on net10.0 and net48. - ISA95 generator and fixture integrity regression: 5 passing on net10.0. |
||
|
|
007cfaf902 |
DO NOT SQUASH: Consolidate repository layout under src, samples, tests, tools, docs, and fuzzing (#4010)
# Description Consolidates the repository into conventional lowercase source roots: - flattens `Stack/` and `Libraries/` into `src/`; - moves `Applications/` to `samples/`; - moves the MCP tool to `tools/Opc.Ua.Mcp`; - renames `Tests/`, `Tools/`, `Docs/`, and `Fuzzing/` to lowercase; - updates all project references, solutions, CI pipelines, scripts, Dockerfiles, package documentation, and repository links. The final tree contains the same projects, package identities, assemblies, and runtime behavior as before. > [!IMPORTANT] > Merge this PR with a merge commit; do not squash it. Git stores trees rather than rename metadata, and 115 files share duplicate blobs. The four commits temporarily disambiguate those files, preserve all 4,580 exact old-to-new path mappings, and then restore the final content. ## Related Issues - Fixes #3907 ## Validation - Windows `net10.0`: 45 test projects, 42,485 passed and 683 skipped. One timing-sensitive History project was rerun in isolation and passed. - Windows `net48`: 45 test projects, 40,651 passed and 706 skipped. - Linux case-sensitive `net10.0` build and path-sensitive integration tests passed. - NativeAOT publish and all 115 published AOT tests passed. - Full preview solution restore/pack completed across all target frameworks and produced 81 packages. - The packaged MCP tool installed and returned `--help` successfully. - All 10 Dockerfile paths and all 6 compose files validated. Full image builds were attempted but Docker Desktop's Linux daemon was unavailable locally. ## Checklist - [ ] I have signed the [CLA](https://opcfoundation.org/license/cla/ContributorLicenseAgreementv1.0.pdf) and read the [CONTRIBUTING](https://github.com/OPCFoundation/UA-.NETStandard/blob/master/CONTRIBUTING.md) doc. - [ ] I have added tests that prove my fix is effective or that my feature works and increased code coverage. - [x] I have added all necessary documentation. - [x] I have verified that my changes do not introduce (new) build or analyzer warnings. - [x] I ran **all** tests locally using the **UA.slnx** solution against at least .net **framework** and .net **10**, and all passed. - [ ] I fixed **all** failing and flaky tests in the CI pipelines and **all** CodeQL warnings. - [ ] I have addressed **all** PR feedback received. This is a repository-layout-only change, so no new behavioral tests were added. |
||
|
|
437a0dadc7 | Merge origin/master into marcschier/3907-repository-layout | ||
|
|
8538f531e7 | Update paths for the consolidated repository layout | ||
|
|
a21b690d08 | Move the remaining duplicate binary assets | ||
|
|
7cec2d614d | Move repository files to the consolidated layout | ||
|
|
9335c15bdd | Temporarily disambiguate duplicate files for the repository move | ||
|
|
80889b0971 |
PumpDeviceIntegrationServer - Register DeviceHealth node, use HasAddIn for SoftwareUpdate (#4008)
This pull request makes important improvements to how the `SoftwareUpdate` object is modeled and registered in the OPC UA Device Integration (DI) server, ensuring better compliance with the OPC 10000-100 specification and improved compatibility with companion-spec checkers. The main changes involve updating the reference type for `SoftwareUpdate` to use `HasAddIn`, explicitly registering the `DeviceHealth` node, and enhancing related tests. **Device Model Compliance and Registration:** * The `SoftwareUpdate` object is now attached to its host device using the `HasAddIn` reference type instead of `HasComponent`, aligning with the OPC 10000-100 specification and reducing validation noise from companion-spec checkers. * The `DeviceHealth` child node is now explicitly registered with the node manager after device registration to ensure its attributes resolve correctly and it can be mapped by companion-spec checkers. **Testing Improvements:** * Added a test assertion to verify that the `SoftwareUpdate` child is attached via the `HasAddIn` reference, ensuring the implementation matches the OPC UA specification.Explicitly register DeviceHealth child node after creation to ensure attributes resolve and DI checker compatibility. Reference SoftwareUpdate facet via HasAddIn per OPC 10000-100 spec, not HasComponent, to avoid validation issues. Update tests to assert correct reference type. # Description _Describe the changes here to communicate to the maintainers why they should accept this pull request. By default - this will become the Commit message after merging and thus define history._ ## Related Issues _Reference all GitHub issues this PR addresses. If there is no issue yet, open one and link it here._ _If this is a relatively large or complex change, a design must have been discussed in the related tracking issue and signed off (which becomes the Architectural Decision Record (ADR))._ - Fixes #github-issue-number, ... ## Checklist _Put an `x` in the boxes that apply. You can complete these step by step after opening the PR._ - [ ] I have signed the [CLA](https://opcfoundation.org/license/cla/ContributorLicenseAgreementv1.0.pdf) and read the [CONTRIBUTING](https://github.com/OPCFoundation/UA-.NETStandard/blob/master/CONTRIBUTING.md) doc. - [ ] I have added tests that prove my fix is effective or that my feature works and increased code coverage. - [ ] I have added all necessary documentation. - [ ] I have verified that my changes do not introduce (new) build or analyzer warnings. - [ ] I ran **all** tests locally using the **UA.slnx** solution against at least .net **framework** and .net **10**, and all passed. - [ ] I fixed **all** failing and flaky tests in the CI pipelines and **all** CodeQL warnings. - [ ] I have addressed **all** PR feedback received. --------- Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> |
||
|
|
7d0e5870cb |
Migrate to source-generated logging across Stack, Libraries and Applications (#3908) (#4003)
# Description Migrates the entire code base (Stack, Libraries and Applications) from direct `ILogger.LogInformation/LogError/LogWarning/LogDebug/LogTrace/LogCritical(...)` calls to **source-generated `[LoggerMessage]` logging**, as tracked in #3908. Source-generated logging avoids boxing of value-type arguments, caches the message formatter, and emits an efficient `IsEnabled` check so a disabled log level costs nothing. This is a behavior-preserving refactor: message text, levels and structured placeholders are unchanged; only the call shape changes. ## What changed - **36 projects migrated.** Every static log call now goes through a per-file `internal static partial class <Class>Log` holding `[LoggerMessage]` extension methods on `ILogger`, so call sites keep the natural `logger.SomeEvent(...)` shape. Closely-related files that emit the same messages share one log class (e.g. the encoders/decoders in `Opc.Ua.Types` share `EncodingLog`) to avoid duplication and CS0121 ambiguity. - **Per-assembly event-id classes.** Each project has one `internal static class <AssemblyToken>EventIds` (e.g. `CoreEventIds`, `ClientEventIds`, `PubSubEventIds`) with a reserved `public const int` offset block per log class. The assembly-token prefix avoids CS0436 collisions across `InternalsVisibleTo` boundaries. - **`CA1873` enabled solution-wide** in `.editorconfig` now that the whole code base (including test, sample and tooling projects) is migrated, so any regression back to a direct `ILogger.Log*` call with an expensive argument is flagged. Every occurrence has been guarded with an `IsEnabled` check (or the check merged into an existing condition where the log was the sole body of an `if`/`else`, preserving side effects); the only suppressions are two Moq `Verify` expression-tree sites, which are not executed log calls. - **Dynamic log levels stay hand-written.** A handful of calls whose level is only known at runtime keep the structured `logger.Log(logLevel, ...)` form under an `if (logger.IsEnabled(logLevel))` guard — `[LoggerMessage]` requires a compile-time level. - **netstandard duplicate-generator fix.** Projects that also pull in an R9 package (`Microsoft.Extensions.Http.Resilience`, `.Compliance`, `.Telemetry`) get the `Microsoft.Gen.Logging` generator in addition to the in-box one; on `netstandard` both implement every partial method (CS0757). A single `Directory.Build.targets` target removes the R9 analyzer on `netstandard` only (no-op elsewhere and where it is not referenced). - **Shared/linked source files** that are compiled into more than one project (e.g. sample files linked into test projects) use self-contained literal event ids instead of a per-assembly class the consumer does not compile. - **Docs.** The authoring recipe (event-id convention, log-class convention, parameter rules, the `IsEnabled` guard, shared/linked files, and the netstandard generator interaction) lives in the new [`Docs/DeveloperGuide.md`](Docs/DeveloperGuide.md#add-a-log-message-source-generated); `Docs/Diagnostics.md` keeps the runtime/observability side and links to it. - **Redaction preserved.** Log calls that previously wrapped sensitive values with `Redact.Create(...)` keep passing the `RedactionWrapper<T>` (instead of an eager `.ToString()`), so format-time redaction still applies — this also clears the CodeQL clear-text alerts introduced during the migration. ## Validation - Full `UA.slnx` build passes with **0 errors / 0 warnings**; the multi-target test projects force every referenced library to build on net472/net48/netstandard2.1/net8.0/net9.0/net10.0. - No unguarded static `ILogger.Log*` calls remain anywhere (only the guarded dynamic-level calls); `CA1873` is clean across the full solution on net10.0. ## Related Issues - Fixes #3908 ## Checklist _Put an `x` in the boxes that apply. You can complete these step by step after opening the PR._ - [ ] I have signed the [CLA](https://opcfoundation.org/license/cla/ContributorLicenseAgreementv1.0.pdf) and read the [CONTRIBUTING](https://github.com/OPCFoundation/UA-.NETStandard/blob/master/CONTRIBUTING.md) doc. - [ ] I have added tests that prove my fix is effective or that my feature works and increased code coverage. - [x] I have added all necessary documentation. - [x] I have verified that my changes do not introduce (new) build or analyzer warnings. - [ ] I ran **all** tests locally using the **UA.slnx** solution against at least .net **framework** and .net **10**, and all passed. - [ ] I fixed **all** failing and flaky tests in the CI pipelines and **all** CodeQL warnings. - [ ] I have addressed **all** PR feedback received. |
||
|
|
ce2ccc72b0 |
Fix transport buffer pooling, limiting, and in-process capture (#3994)
# Description Fixes transport-buffer pool amplification when `TransportQuotas.MaxBufferSize` is an exact power of two, adds injectable buffer-manager policies and a process-wide memory limiter, and fixes in-process pcap capture of maximum-size UASC chunks. `BufferManager` previously reserved an ownership cookie after the usable data in every build. A 65,536-byte limit therefore requested 65,537 bytes from `ArrayPool<byte>.Shared`, selecting the 131,072-byte bucket. The compatibility `BufferManager` is now a facade over `IBufferManager`; Release defaults to `FastBufferManager`, Debug defaults to `CookieBufferManager`, and explicit `TRACK_MEMORY` builds use `TracingBufferManager`. `IBufferManagerFactory` and `BufferManagerFactoryOptions` are registered through dependency injection and wired through raw TCP, HTTPS/WSS, and Kestrel channel/listener creation while preserving existing direct constructors. Applications can replace the factory or explicitly select fast, cookie, or tracing behavior. `LimitingBufferManager` wraps any implementation and uses a factory-shared `BufferManagerMemoryLimiter` to cap actual outstanding bytes across all managers created by that factory. It blocks synchronous rents without holding manager locks, supports cancellation on transport I/O paths, accounts for actual pool bucket sizes, rejects impossible or synchronous re-entrant rents safely, and protects accounting from failed, foreign, and duplicate returns. The client and accepted-server TCP transports also retained raw quota values. The fix carries bucket-safe limits into transport creation and reconnects, while preserving the active connection’s negotiated receive limit. Configurable transports receive updated limits during server reconnect, and every channel independently rejects and faults/reconnects on chunks above the negotiated limit. Maximum-size UASC chunks exceeded the synthetic IPv4 total-length field once TCP/IP headers were added. The capture path now segments those chunks into sequence-aware synthetic TCP packets sized for both IPv4 and the pcap snap length. Every capturing transport receives a stable process-unique synthetic flow identity that is preserved in the full TCP tuple and independent sequence state. Capture queuing remains non-blocking and queues or drops complete UASC chunks atomically; sequence space is reserved before bounded frame admission so dropped chunks remain visible as TCP gaps, while packetization stays in the single writer. Key-material snapshots use a separate prioritized unbounded queue and are drained and disposed reliably during shutdown. This change includes: - `IBufferManager`, `IBufferManagerFactory`, factory options, and compatibility facade; - fast, cookie, allocation-tracing, and memory-limiting implementations; - shared DI factory wiring for raw TCP, HTTPS/WSS, and Kestrel transports; - Debug/Release/TRACK_MEMORY implementation selection; - cancellation-aware transport rents and no-loss in-process receive behavior; - deterministic ownership, limiter, bucket-size, reconnect, oversized-chunk, cancellation, and DI tests; - explicit subscription diagnostics using `ArrayPoolEventSource`; - pcap framing, sequence-space, atomic-queue, and reassembly regression tests; - updated benchmark and dependency-injection documentation. Measured with 255 and 257 Publish queues plus a slow-consumer scenario, configured values of both 65,535 and 65,536 used only 65,536-byte arrays. Every observed rent had a matching return, outstanding buffers returned to zero, and no Gen 2 collections occurred. The 500-session baseline also passed for `opc.tcp`, `https`, and `opc.https`, with all sessions receiving notifications. ## Related Issues - Fixes #3988 ## Checklist - [x] I have signed the [CLA](https://opcfoundation.org/license/cla/ContributorLicenseAgreementv1.0.pdf) and read the [CONTRIBUTING](https://github.com/OPCFoundation/UA-.NETStandard/blob/master/CONTRIBUTING.md) doc. - [x] I have added tests that prove my fix is effective or that my feature works and increased code coverage. - [x] I have added all necessary documentation. - [x] I have verified that my changes do not introduce (new) build or analyzer warnings. - [ ] I ran **all** tests locally using the **UA.slnx** solution against at least .net **framework** and .net **10**, and all passed. - [ ] I fixed **all** failing and flaky tests in the CI pipelines and **all** CodeQL warnings. - [x] I have addressed **all** PR feedback received. |
||
|
|
c250db682b |
Complete Part 12 ServerConfiguration and transactional PushManagement (#3989)
# Description Completes the OPC UA Part 12 ServerConfiguration and transactional PushManagement implementation, including opt-in distributed/HA coordination, while retaining the original review-feedback fixes from #3952. ## Transactional certificate and TrustList management - Adds a Session-owned transaction coordinator shared by certificate groups and TrustLists. - Stages certificate and TrustList changes until `ApplyChanges`, with ordered prepare/commit, rollback, intra-operation compensation, cancellation, Session cleanup, and diagnostics. - Implements `CreateSelfSignedCertificate`, `DeleteCertificate`, `GetCertificates`, `CancelChanges`, `SupportsTransactions`, and `TransactionDiagnostics`. - Enforces method-specific SecureChannel requirements and standard Part 12 status codes. - Persists regenerated signing-request keys and incorporates caller nonce entropy where supported. - Protects certificates currently presented by live endpoint security policies. ## Distributed and high-availability PushManagement - Adds opt-in `UseDistributedPushConfiguration` for redundant server deployments. - Uses the existing `ISharedKeyValueStore` CAS primitives for a renewable cluster-wide transaction lease. - Reuses the configured `ILeaderElection`; Kubernetes deployments use the existing native Kubernetes Lease implementation, while Raft/shared-store deployments use their existing providers. - Persists pending regenerated keys in the shared store with `IRecordProtector` authenticated encryption and atomic cross-replica consumption. - Fails closed when an external shared store lacks record protection. - Keeps non-distributed server behavior unchanged. ## ApplyChanges effects - Forces affected classic and Kestrel opc.tcp peer channels to renegotiate after TrustList changes. - Routes trust effects by listener trust-list scope. - Revalidates X.509 user identities and closes invalid Sessions and Subscriptions. - Preserves response-before-channel-close sequencing and drains deferred effects during shutdown. ## Diagnostics, alarms, and optional configuration - Implements Part 12 TransactionDiagnostics DataValue status semantics with client-safe error messages. - Activates CertificateExpiration and TrustListOutOfDate alarms. - Exposes identity properties and provider-backed optional ServerConfiguration functionality. - Adds secure, versioned configuration-file updates with rollback and confirm/revert lifecycle. - Aligns advertised and enforced MaxTrustListSize. ## Security and reliability feedback - Clears certificate-store password buffers after use. - Prevents internal exception details and paths from leaking through TransactionDiagnostics. - Hardens shared-fixture transaction cleanup. - Preserves `IRecordProtector` compatibility through an additive owned-buffer extension. ## Related Issues - Follow-up to #3952 ## Testing - Full server and GDS suites pass on net10.0. - Focused server and distributed PushManagement suites pass on net10.0 and net48. - Distributed HA tests cover cross-replica contention, lease expiry/renewal, leadership gating, protected pending-key transfer, tamper rejection, and fail-closed configuration. - Analyzer-enabled affected-project builds pass without new warnings or errors. - CTT/UACTT was not run because the licensed GUI tooling is unavailable in this environment. ## Checklist - [ ] I have signed the [CLA](https://opcfoundation.org/license/cla/ContributorLicenseAgreementv1.0.pdf) and read the [CONTRIBUTING](https://github.com/OPCFoundation/UA-.NETStandard/blob/master/CONTRIBUTING.md) doc. - [x] I have added tests that prove my fix is effective or that my feature works and increased code coverage. - [x] I have added all necessary documentation. - [x] I have verified that my changes do not introduce (new) build or analyzer warnings. - [ ] I ran **all** tests locally using the **UA.slnx** solution against at least .net **framework** and .net **10**, and all passed. - [ ] I fixed **all** failing and flaky tests in the CI pipelines and **all** CodeQL warnings. - [x] I have addressed **all** PR feedback received. --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> |
||
|
|
b8765ee9b4 |
Dispose canceled managed session creation and expand server utility coverage (#3995)
# Description Dispose a `ManagedSession` when its initial connection wait fails or is canceled so the background state machine and owned resources do not outlive a failed `CreateAsync` call. Log cleanup failures while preserving the original connection failure or cancellation. Add regression coverage for canceled managed-session creation and cleanup logging, plus coverage for Quickstarts default node manager registration and the reusable Reference Server helper flags. ## Related Issues None. ## Checklist - [ ] I have signed the [CLA](https://opcfoundation.org/license/cla/ContributorLicenseAgreementv1.0.pdf) and read the [CONTRIBUTING](https://github.com/OPCFoundation/UA-.NETStandard/blob/master/CONTRIBUTING.md) doc. - [x] I have added tests that prove my fix is effective or that my feature works and increased code coverage. - [x] I have added all necessary documentation. - [x] I have verified that my changes do not introduce (new) build or analyzer warnings. - [ ] I ran **all** tests locally using the **UA.slnx** solution against at least .net **framework** and .net **10**, and all passed. - [ ] I fixed **all** failing and flaky tests in the CI pipelines and **all** CodeQL warnings. - [x] I have addressed **all** PR feedback received. --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> |
||
|
|
2e24fd0b74 |
Fix companion spec compliance bugs in pump sample application (#3999)
This pull request introduces several important improvements to the Device Integration (DI) server implementation and its documentation, focusing on compliance with the DI companion specification, robust node instantiation, and clearer documentation for users. The key changes ensure that device instances are created with all mandatory children and correct namespace assignments, resolve NodeId collisions for multiple instances, and clarify the behavior of helper methods in the documentation. **Device instantiation and compliance improvements:** * Device instances are now materialized through the source-generated `CreateInstanceOfDeviceType` factory, ensuring that all mandatory DI children (such as the eight nameplate variables) and `HasInterface` references are present with the correct DI-namespace BrowseNames. This change brings the implementation in line with the DI companion-spec requirements and prevents compliance failures. (`Libraries/Opc.Ua.Di.Server/DiNodeManager.cs`, `Docs/DeviceIntegration.md`) [[1]](diffhunk://#diff-8786a28f8727cc3c9b7d14ca549dd08dfbe257842d287b4ea6bd614ab0ad2787L340-R355) [[2]](diffhunk://#diff-f8292a4fd8ad9f3cdb4955707f4e63d6b0ca7472045cce21e46e835e69bc7bf5L168-R179) [[3]](diffhunk://#diff-f8292a4fd8ad9f3cdb4955707f4e63d6b0ca7472045cce21e46e835e69bc7bf5L210-R242) * When registering devices and software update subtrees, per-instance NodeIds are recursively assigned to all children, preventing NodeId collisions across multiple instances of the same type. (`Libraries/Opc.Ua.Di.Server/DiNodeManager.cs`, `Libraries/Opc.Ua.Di.Server/Builders/SoftwareUpdateFacetWiring.cs`) [[1]](diffhunk://#diff-8786a28f8727cc3c9b7d14ca549dd08dfbe257842d287b4ea6bd614ab0ad2787R438-R490) [[2]](diffhunk://#diff-642220ec038696416cb3a615a37ee47e2e7e38c81bea6ff8cf652a2fac5a178bR126-R134) [[3]](diffhunk://#diff-642220ec038696416cb3a615a37ee47e2e7e38c81bea6ff8cf652a2fac5a178bR144-R161) **Property and namespace handling:** * The `WithProperty` helper now creates properties when missing, with correct DI-namespace qualification, and documentation has been updated to reflect this behavior. This ensures that both mandatory and optional properties are handled correctly and that custom functional groups can add properties dynamically. (`Docs/SourceGeneratedNodeManagers.md`, `Applications/PumpDeviceIntegrationServer/Program.cs`, `Libraries/Opc.Ua.Di.Server/Builders/DeviceBuilder.cs`) [[1]](diffhunk://#diff-24f0ac53195633e085935831e9bd8de7d918de1ccf59699730b8f7770d9c7899L621-R626) [[2]](diffhunk://#diff-24f0ac53195633e085935831e9bd8de7d918de1ccf59699730b8f7770d9c7899L639-R668) [[3]](diffhunk://#diff-82e3eaf8442a044f3bfad256e188e4eb6fdb62a2146796aebae0323c7f2b7dc8R458-R465) [[4]](diffhunk://#diff-0b763658716a4959f371881988e7ddb399ec62eb92345dab229ca8441ac452b6L105-R108) **Software update facet and method declaration fixes:** * The software update facet builder now correctly assigns `MethodDeclarationId`s for methods such as `Resume`, `InstallSoftwarePackage`, `InstallFiles`, and `Uninstall`, ensuring that these methods resolve to their in-type declarations and pass compliance checks. (`Libraries/Opc.Ua.Di.Server/Builders/SoftwareUpdateFacetWiring.cs`) [[1]](diffhunk://#diff-642220ec038696416cb3a615a37ee47e2e7e38c81bea6ff8cf652a2fac5a178bR258-R264) [[2]](diffhunk://#diff-642220ec038696416cb3a615a37ee47e2e7e38c81bea6ff8cf652a2fac5a178bR309-R314) [[3]](diffhunk://#diff-642220ec038696416cb3a615a37ee47e2e7e38c81bea6ff8cf652a2fac5a178bR326-R327) [[4]](diffhunk://#diff-642220ec038696416cb3a615a37ee47e2e7e38c81bea6ff8cf652a2fac5a178bR336-R339) **Documentation updates:** * The documentation has been updated to clarify the device instantiation process, DI companion-spec compliance, and the behavior of helper methods for property creation and bulk initialization. (`Docs/DeviceIntegration.md`, `Docs/SourceGeneratedNodeManagers.md`) [[1]](diffhunk://#diff-f8292a4fd8ad9f3cdb4955707f4e63d6b0ca7472045cce21e46e835e69bc7bf5L168-R179) [[2]](diffhunk://#diff-f8292a4fd8ad9f3cdb4955707f4e63d6b0ca7472045cce21e46e835e69bc7bf5L210-R242) [[3]](diffhunk://#diff-24f0ac53195633e085935831e9bd8de7d918de1ccf59699730b8f7770d9c7899L621-R626) [[4]](diffhunk://#diff-24f0ac53195633e085935831e9bd8de7d918de1ccf59699730b8f7770d9c7899L639-R668) These changes collectively improve DI spec compliance, prevent subtle bugs with NodeId collisions, and make the codebase and documentation more robust and user-friendly.# Description _Describe the changes here to communicate to the maintainers why they should accept this pull request. By default - this will become the Commit message after merging and thus define history._ ## Related Issues _Reference all GitHub issues this PR addresses. If there is no issue yet, open one and link it here._ _If this is a relatively large or complex change, a design must have been discussed in the related tracking issue and signed off (which becomes the Architectural Decision Record (ADR))._ - Fixes #github-issue-number, ... ## Checklist _Put an `x` in the boxes that apply. You can complete these step by step after opening the PR._ - [x] I have signed the [CLA](https://opcfoundation.org/license/cla/ContributorLicenseAgreementv1.0.pdf) and read the [CONTRIBUTING](https://github.com/OPCFoundation/UA-.NETStandard/blob/master/CONTRIBUTING.md) doc. - [x] I have added tests that prove my fix is effective or that my feature works and increased code coverage. - [x] I have added all necessary documentation. - [ ] I have verified that my changes do not introduce (new) build or analyzer warnings. - [ ] I ran **all** tests locally using the **UA.slnx** solution against at least .net **framework** and .net **10**, and all passed. - [ ] I fixed **all** failing and flaky tests in the CI pipelines and **all** CodeQL warnings. - [ ] I have addressed **all** PR feedback received. --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> |
||
|
|
0da85b9d89 |
CTT conformance: access rights, X509, aggregates, and matrix diagnostics (#3978)
# Description Investigates successive OPC UA CTT runs and fixes the proven server conformance defects while documenting proven CTT script/codec defects in `plans/ctt-issues.md`. ## Server fixes - Grant `WriteAttribute` on `Scalar_Static_Int32` so attributes advertised by `WriteMask` are writable. - Disable the client-certificate-keyed authentication lockout in the dedicated CTT configuration so negative token tests do not mask later results with `BadUserAccessDenied`. - Map an X509 user-token signature algorithm mismatch to token-level `BadIdentityTokenInvalid`. - Persist rejected X509 user certificates to `pki/rejectedUser` to simplify trusted-user provisioning. - Populate `HistoricalDataConfiguration.AggregateConfiguration` with the server's actual defaults. - Return per-node `BadInvalidArgument` for processed reads with equal StartTime/EndTime. - Feed reverse processed reads in request order and preserve exact non-Bad interpolation boundaries. - Correct PercentGood/PercentBad uncertain classification. - Correct WorstQuality/WorstQuality2 eligible bounds, StatusCode preservation, and `MultipleValues`. - Correct reverse Min/Max Raw-vs-Calculated semantics. - Fix `HistoryClient.GetConfigurationAsync` traversal and aggregate-configuration reads. ## Tests and CTT evidence - Added direct calculator and live historian Part 11/13 oracle tests covering forward/reverse intervals, equal-time validation, bounds, status aggregates, DurationInState, and Min/Max. - Added exact Part 6 Table 26 binary golden-vector coverage for a 2×3 Int32 Matrix Variant. - Added in-process whole-matrix read/write and multidimensional `NumericRange` coverage. - Updated `plans/ctt-issues.md` with exact evidence and recommended fixes for CTT aggregate, X509, multidimensional-array, A&C, and AliasName script defects. No CTT failure is suppressed or accepted without a spec-based classification. ## Related Issues - Relates to #3960. ## Checklist - [x] Tests proving the server fixes are included. - [x] CTT-side defects are documented with script locations and specification references. - [x] Targeted aggregate/routing/matrix suites pass on net48 and net10. - [x] History aggregate/client suites pass on net48 and net10. - [x] Modified lines are analyzer-clean. - [ ] CI and CodeQL complete. - [ ] Maintainer review complete. --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: Roman Ettlinger <romanett98@gmail.com> |
||
|
|
2a1db65aec |
Fix legacy password verification and JSON QualifiedName decoding (#3991)
# Description Fix two compatibility and decoding regressions: - Verify persisted PBKDF2 password hashes using the iteration count stored with each hash. This preserves authentication for user databases created with the previous 10,000-iteration policy when running on .NET 10. - Normalize malformed string-form JSON `QualifiedName` values through the decoder's existing strict/lenient contract. Lenient parsing now returns `QualifiedName.Null`, while strict parsing reports `BadDecodingError` instead of leaking `BadNodeIdInvalid`. The change adds deterministic legacy/current password-hash vectors and scalar, array, and Variant JSON decoder coverage. ## Related Issues - No related issue. ## Checklist - [ ] I have signed the [CLA](https://opcfoundation.org/license/cla/ContributorLicenseAgreementv1.0.pdf) and read the [CONTRIBUTING](https://github.com/OPCFoundation/UA-.NETStandard/blob/master/CONTRIBUTING.md) doc. - [x] I have added tests that prove my fix is effective or that my feature works and increased code coverage. - [x] I have added all necessary documentation. - [x] I have verified that my changes do not introduce (new) build or analyzer warnings. - [ ] I ran **all** tests locally using the **UA.slnx** solution against at least .net **framework** and .net **10**, and all passed. - [ ] I fixed **all** failing and flaky tests in the CI pipelines and **all** CodeQL warnings. - [ ] I have addressed **all** PR feedback received. ## Validation - `LinqUserDatabaseTests`: 10/10 passed on `net10.0` and `net48`. - `JsonDecoderTests`: 262/262 passed on `net10.0` and `net48`. - Deterministic JSON fuzz regression tests: 1368/1368 passed on `net10.0` and `net48`. - Affected test projects build with zero warnings and errors on `net10.0` and `net48`. |
||
|
|
aadba8b618 |
Add runtime NodeSet-backed node managers (#3990)
# Description Add a dedicated startup-time runtime NodeSet2 loading path for servers that need to expose information models without source generation. This introduces: - `AddRuntimeNodeSet` DI extensions for single files, grouped sources, and lazy stream providers. - A dedicated `RuntimeNodeSetNodeManagerFactory` and `FluentNodeManagerBase` implementation that remain separate from source-generated NodeManagers and typed fluent builders. - Model ownership validation, `RequiredModel` dependency ordering, parent-child linking, external reference handling, and fail-fast diagnostics. - Untyped `INodeManagerBuilder` code-behind wiring for imported variables, methods, events, alarms, and simulations. - Reuse of the existing default server-side complex-type loading path after the runtime address space is created. - Runtime NodeSet documentation plus NUnit and NativeAOT coverage. The feature intentionally loads NodeSets only during server startup. Live add, reload, or removal after clients connect remains out of scope because it requires separate MasterNodeManager routing, NamespaceArray, model-change, subscription, and complex-type lifecycle design. ## Related Issues - Fixes #3974 ## Validation - Runtime NodeSet tests: 38 passed on `net10.0`. - Runtime NodeSet tests: 38 passed on `net48`. - NativeAOT publish succeeded and the full 107-test executable passed. - Changed C# files pass whitespace verification and the server library builds without new warnings. ## Checklist - [ ] I have signed the [CLA](https://opcfoundation.org/license/cla/ContributorLicenseAgreementv1.0.pdf) and read the [CONTRIBUTING](https://github.com/OPCFoundation/UA-.NETStandard/blob/master/CONTRIBUTING.md) doc. - [x] I have added tests that prove my fix is effective or that my feature works and increased code coverage. - [x] I have added all necessary documentation. - [x] I have verified that my changes do not introduce (new) build or analyzer warnings. - [ ] I ran **all** tests locally using the **UA.slnx** solution against at least .net **framework** and .net **10**, and all passed. - [ ] I fixed **all** failing and flaky tests in the CI pipelines and **all** CodeQL warnings. - [ ] I have addressed **all** PR feedback received. --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> |
||
|
|
c8bafd2bdf |
Add test coverage for JSON user database and state machine availability (#3992)
# Description Adds focused tests for production paths introduced in #3980 that remained below the repository's 80% Codecov patch-coverage threshold. The existing fixtures now cover: - Current and legacy `ExpandedNodeId` JSON representations used by `JsonUserDatabase`, including numeric, string, GUID, opaque, null, absolute, and malformed role identifiers. - Optional or null `AvailableStates` and `AvailableTransitions` values in `FiniteStateMachineTypeClientExtensions`. The tests assert the exact loaded users, roles, identifiers, fallback behavior, and state-machine results rather than only executing converter branches. Local changed-line measurement reports: - `JsonUserDatabase.cs`: 100% line coverage. - Changed executable lines in `FiniteStateMachineTypeClientExtensions.cs`: 100% coverage. Focused validation passes on .NET 10 and .NET Framework 4.8: 58 tests passed. ## Related Issues Follow-up to #3980. ## Checklist - [x] I have signed the [CLA](https://opcfoundation.org/license/cla/ContributorLicenseAgreementv1.0.pdf) and read the [CONTRIBUTING](https://github.com/OPCFoundation/UA-.NETStandard/blob/master/CONTRIBUTING.md) doc. - [x] I have added tests that prove my fix is effective or that my feature works and increased code coverage. - [x] I have added all necessary documentation. - [x] I have verified that my changes do not introduce (new) build or analyzer warnings. - [ ] I ran **all** tests locally using the **UA.slnx** solution against at least .net **framework** and .net **10**, and all passed. - [ ] I fixed **all** failing and flaky tests in the CI pipelines and **all** CodeQL warnings. - [x] I have addressed **all** PR feedback received. |
||
|
|
c8bc1bbee6 |
Fix nightly Stress Tests (Chaos TCP): transparent reconnect + robust chaos assertions (#3986)
# Description Fixes the nightly **Stress Tests / Chaos TCP** job (e.g. run [29068846476](https://github.com/OPCFoundation/UA-.NETStandard/actions/runs/29068846476)), which had failed on **every run since it was introduced** — the workflow runs on a schedule and never gated PRs, so the failures went unnoticed. ## Root cause The Chaos TCP tests point a `ConfiguredEndpoint` at a local `TcpChaosProxy` and set `UpdateBeforeConnect = false` so the session connects *through* the proxy. Two problems prevented this from working: 1. `ManagedSession.HandleConnectAsync` **ignored** `ConfiguredEndpoint.UpdateBeforeConnect` and hard-coded a pre-connect re-discovery for all non-OpenAPI endpoints. Re-discovery adopted the server's advertised `EndpointUrl`, so the session connected **directly to the server, bypassing the proxy** — no chaos ever reached the connection. Two tests "passed" vacuously. 2. Once the proxy was genuinely engaged, the transparent-reconnect feature had a gap: a request that hit the just-dropped channel (before the manager detected the drop) failed with `BadConnectionClosed` instead of transparently recovering. ## Changes **Product** - **`ManagedSession`** now honours `ConfiguredEndpoint.UpdateBeforeConnect` (default `true`). Setting it `false` opens the channel against exactly the supplied URL (proxy / gateway / NAT / pinned endpoint) without re-discovering. - **`ManagedTransportChannelLease.SendRequestAsync`** transparently resends **idempotent** requests (`Read` / `Browse` / `TranslateBrowsePaths` / `GetEndpoints` / `FindServers`) across a channel-manager reconnect. On a transient transport-drop error it forces a *coalesced* reconnect and resends once the shared channel recovers. - A new **`ChannelEntry.ReconnectGeneration`** counter guards this so a reconnect is only forced for a genuinely undetected drop (same generation, still `Ready`), never for a stale in-flight failure that arrives after recovery — which previously spawned spurious extra reconnect cycles that tore down healthy channels. - **Non-idempotent** requests (`Create*`, `Write`, `Call`, `Publish`, …) surface the error so higher-level recovery (e.g. the subscription engine's own re-create loop) stays in control; requests are never double-applied. **Tests / harness** - **`TcpChaosProxy`** no longer rethrows the expected `OperationAborted` raised by an in-flight upstream `ConnectAsync` during `DropAllConnections` (it was faulting the awaited connection task and failing the test). - Chaos reconnect assertions (L3-A1/A2/A5) are made robust to the inherent non-determinism of reconnect **counts** under concurrent chaos (coalescing merges drops landing in one recovery window; a stale keep-alive `Bad` can add one cycle). Survival is asserted via `FailureRate`, `ReconnectFailed == 0`, and the coalescing fan-out relationship rather than exact `ReconnectStarted/Completed == dropCount`. - Subscription post-drop recovery window widened (`2s → 8s`) to allow re-creating all sessions' subscriptions and monitored items on a loaded CI agent. - **New unit tests** in `ClientChannelManagerManagedTests` cover the new product paths (fast-PR / codecov, since the nightly ChaosTCP job does not run in the fast pipeline): idempotent transient-drop retry, non-idempotent no-retry, non-transient no-retry, and `ChannelEntry.ReconnectGeneration` increment. ## Validation (local, net10.0) - **Chaos TCP**: 6/6 pass across many random seeds (incl. post-merge re-runs of `338475986` and `1999999999`). - `Opc.Ua.Client.Tests` ChannelManager/ManagedSession: **256/256** (incl. the 4 new tests). - `Opc.Ua.Sessions.Tests` ChannelManager/Reconnect: **139/139**. - Core / Client / Stress build with **0 warnings**. ## Notes - This branch has been merged up to date with `master` (redundancy PR #3918). - The two failing `Opc.Ua.PubSub.Tests` in CI — `UdpLoopbackActionResponderAnswersRequesterAsync` and `UdpLoopbackDiscoveryPublisherAnswersSubscriberRequests` — are **unrelated** to this PR (UDP-loopback request/response tests in the PubSub library, associated with #3918) and are timing/environment-flaky. They are out of scope for this change. ## Related Issues - Fixes the recurring nightly Chaos TCP failure (workflow: `.github/workflows/stress-test.yml`). ## Checklist - [ ] I have signed the [CLA](https://opcfoundation.org/license/cla/ContributorLicenseAgreementv1.0.pdf) and read the [CONTRIBUTING](https://github.com/OPCFoundation/UA-.NETStandard/blob/master/CONTRIBUTING.md) doc. - [x] I have added tests that prove my fix is effective or that my feature works and increased code coverage. - [ ] I have added all necessary documentation. - [x] I have verified that my changes do not introduce (new) build or analyzer warnings. - [ ] I ran **all** tests locally using the **UA.slnx** solution against at least .net **framework** and .net **10**, and all passed. - [ ] I fixed **all** failing and flaky tests in the CI pipelines and **all** CodeQL warnings. - [ ] I have addressed **all** PR feedback received. |
||
|
|
28a1779dc9 |
Stabilize Core.Security X509 user tests on macOS by preferring RSA endpoints (#3983)
# Description
The `test-macOS-latest-Core.Security` job was failing in X509 user-token
tests due to endpoint/certificate algorithm mismatch.
`SecurityX509UserTests` generated RSA user certs but could bind to
ECC-first endpoints on macOS, leading to signing failures (`Missing
private key needed for create a signature`).
- **Root cause**
- Endpoint selection matched only `MessageSecurityMode` and could choose
ECC policies first depending on endpoint ordering.
- X509 user-token signing then entered the ECDSA path with an RSA user
cert.
- **Change**
- Updated `SecurityX509UserTests.FindEndpoint(...)` to prefer
RSA-compatible endpoints first, then fall back to any endpoint in the
same mode.
- Added focused helper methods in the test fixture for policy filtering:
- `FindMatchingEndpoint(...)`
- `IsEccPolicy(...)`
- **Why this is minimal**
- Test-only change, localized to one fixture.
- No production runtime behavior changed.
```csharp
private EndpointDescription FindEndpoint(ArrayOf<EndpointDescription> endpoints, MessageSecurityMode mode)
{
EndpointDescription rsaEndpoint = FindMatchingEndpoint(endpoints, mode, requireRsa: true);
if (rsaEndpoint != null)
{
return rsaEndpoint;
}
return FindMatchingEndpoint(endpoints, mode, requireRsa: false);
}
```
## Related Issues
Issue linkage is handled automatically by the system.
## Checklist
- [ ] I have signed the
[CLA](https://opcfoundation.org/license/cla/ContributorLicenseAgreementv1.0.pdf)
and read the
[CONTRIBUTING](https://github.com/OPCFoundation/UA-.NETStandard/blob/master/CONTRIBUTING.md)
doc.
- [ ] I have added tests that prove my fix is effective or that my
feature works and increased code coverage.
- [ ] I have added all necessary documentation.
- [x] I have verified that my changes do not introduce (new) build or
analyzer warnings.
- [ ] I ran **all** tests locally using the **UA.slnx** solution against
at least .net **framework** and .net **10**, and all passed.
- [ ] I fixed **all** failing and flaky tests in the CI pipelines and
**all** CodeQL warnings.
- [ ] I have addressed **all** PR feedback received.
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: romanett <romanett98@gmail.com>
Co-authored-by: Marc Schier <marcschier@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
|
||
|
|
26771349af |
Add Docker support for Pump Device Integration Server (#3987)
- Introduced a GitHub Actions workflow for building and pushing the Docker image. - Created a Dockerfile for multi-stage build of the PumpDeviceIntegrationServer. - Updated Program.cs to allow configurable host and port for the OPC UA endpoint. - Enhanced README with Docker usage instructions. - Added fluent builder extensions for property access levels. - Implemented unit tests for new fluent builder functionalities. # Description _Describe the changes here to communicate to the maintainers why they should accept this pull request. By default - this will become the Commit message after merging and thus define history._ ## Related Issues _Reference all GitHub issues this PR addresses. If there is no issue yet, open one and link it here._ _If this is a relatively large or complex change, a design must have been discussed in the related tracking issue and signed off (which becomes the Architectural Decision Record (ADR))._ - Fixes #github-issue-number, ... ## Checklist _Put an `x` in the boxes that apply. You can complete these step by step after opening the PR._ - [x] I have signed the [CLA](https://opcfoundation.org/license/cla/ContributorLicenseAgreementv1.0.pdf) and read the [CONTRIBUTING](https://github.com/OPCFoundation/UA-.NETStandard/blob/master/CONTRIBUTING.md) doc. - [ ] I have added tests that prove my fix is effective or that my feature works and increased code coverage. - [ ] I have added all necessary documentation. - [ ] I have verified that my changes do not introduce (new) build or analyzer warnings. - [ ] I ran **all** tests locally using the **UA.slnx** solution against at least .net **framework** and .net **10**, and all passed. - [ ] I fixed **all** failing and flaky tests in the CI pipelines and **all** CodeQL warnings. - [ ] I have addressed **all** PR feedback received. --------- Co-authored-by: Marc Schier <marcschier@hotmail.com> |
||
|
|
70f2e0557a |
Increase Core, Client and Server coverage to 80-85% and fix test-discovered defects (#3980)
# Description Raises **line coverage to the 80–85% target** for the core stack libraries by extending existing NUnit fixtures wherever possible and preferring unit tests over integration tests. Each library was measured for a per-file coverage baseline, gaps were ranked by absolute uncovered lines, and tests were added around concrete behavior rather than type-only or non-null assertions. | Library | Before | After | |---------|-------:|------:| | Opc.Ua.Server | 78.3% | **80.0%** | | Opc.Ua.Core | 69.5% | **81.1%** (combined with integration suites) | | Opc.Ua.Types | 79.0% | **80.3%** | | Opc.Ua.Core.Types | 0% | **82.9%** | | Opc.Ua.Client | 57.9% | **81.4%** | | Opc.Ua.Core.Diagnostics | 68.9% | **80.3%** | | Opc.Ua.Core.Schema | 43.7% | **80.2%** | Reviewing the added tests exposed several production defects, which are fixed in this PR: - Correct registered and unknown view handling in `ViewTable`. - Set `FolderTypeState` to derive from `BaseObjectType` rather than itself. - Preserve `JsonUserDatabase` users, credentials, and roles across current and legacy JSON round trips. - Produce semantic, allocation-free diagnostics summaries for generated request collections and Browse views. - Discover finite-state-machine availability through the standard `AvailableStates` and `AvailableTransitions` properties. The tests were strengthened to validate exact request IDs, index ranges, signature inputs, typed ECDH payloads, subscription lifecycle behavior, delegation calls, cached-secret disposal, and deterministic fake-time reconnect behavior. ### Notes - Tests use NUnit `Assert.That` and Moq and follow `.editorconfig`. - The affected projects pass on .NET Framework 4.8 and .NET 10. `Opc.Ua.Core.Diagnostics.Tests` remains modern-.NET-only by design. - The three pre-existing `OfflineSecureChannelSmokeTests` token-expiry failures are unrelated and reproduce without these changes. ## Related Issues No tracking issue. ## Checklist - [x] I have signed the [CLA](https://opcfoundation.org/license/cla/ContributorLicenseAgreementv1.0.pdf) and read the [CONTRIBUTING](https://github.com/OPCFoundation/UA-.NETStandard/blob/master/CONTRIBUTING.md) doc. - [x] I have added tests that prove my fix is effective or that my feature works and increased code coverage. - [x] I have added all necessary documentation. - [x] I have verified that my changes do not introduce (new) build or analyzer warnings. - [x] I ran **all** tests locally using the **UA.slnx** solution against at least .net **framework** and .net **10**, and all passed. - [ ] I fixed **all** failing and flaky tests in the CI pipelines and **all** CodeQL warnings. - [x] I have addressed **all** PR feedback received. --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> |
||
|
|
7f409657ad |
OPC UA Part 4 6.6 Redundancy (server + client) with opt-in distributed high-availability (#3918)
## Summary This branch implements **OPC 10000-4 §6.6 Redundancy** end to end — server and client, **transparent and non-transparent**, across all failover modes (`None`, `Cold`, `Warm`, `Hot`, `HotAndMirrored`, `Transparent`) — and layers an **opt-in distributed high-availability (HA)** capability on top so replicas can share address-space, session, and subscription state and expose redundancy to clients through the documented OPC UA mechanisms (for example, running a server replica set across nodes in Kubernetes). The single-instance, in-memory path stays **zero-overhead**: every distributed feature is opt-in through dependency injection, with a direct-construction fallback, and replaced APIs are kept and marked `[Obsolete]`. ## New packages | Package | Purpose | | --- | --- | | `OPCFoundation.NetStandard.Opc.Ua.Server.Redundancy` | §6.6 redundancy nodes plus opt-in distributed state: shared address space, secure session sharing, subscription/continuation-point mirroring, and leader election. | | `OPCFoundation.NetStandard.Opc.Ua.Server.Redundancy.Crdt` | Active/active, leaderless multi-writer replication via CRDTs (an extension beyond §6.6). | | `OPCFoundation.NetStandard.Opc.Ua.Server.Redundancy.K8s` | Kubernetes integration: Lease leader election, EndpointSlice peer discovery, and ServiceLevel-driven readiness. | Also adds the worked samples `Applications/RedundantServer` and `Applications/RedundantClient`, and the guides `Docs/HighAvailability.md` and `Docs/HighAvailabilityKubernetes.md`. ## Server side (§6.6) - `AddServerRedundancy(...)` populates the live `Server.ServerRedundancy` nodes (`RedundancySupport` plus `RedundantServerArray` / `ServerUriArray` / `CurrentServerId`) and drives `Server.ServiceLevel` from an `IServiceLevelProvider` (leader high, standby low). `Server.ServerRedundancy` is typed to the NonTransparent or Transparent subtype according to the configured mode. - `AddRequestServerStateChange(...)` implements the §6.6.5 manual-failover method, with `EstimatedReturnTime` and the Maintenance / NoData `ServiceLevel` sub-ranges. - Non-transparent peers resolve through `FindServers` (`ConfiguredRedundantServerSetProvider`) and advertise the `NTRS` discovery capability for GDS/NTRS registration. - Deterministic, replica-stable `EventId` synchronization for Transparent and HotAndMirrored sets (§6.6.2.2), excluding per-replica fields so de-duplicating clients do not double-process events. ## Client side (§6.6) - `DefaultServerRedundancyHandler` reads `Server.ServerRedundancy` and `Server.ServiceLevel` and fails over to the highest-ServiceLevel peer. It honors Maintenance (Part 4 Table 105 — disconnect to an available peer), keeps Warm backups disabled until failover (Table 107), and treats peers known only through `ServerUriArray` as failover candidates. - `RedundantManagedClient` implements the Cold, Warm, Hot (a), Hot (b), and HotAndMirrored client patterns: one active session, optional lightweight ServiceLevel status-check sessions to backups, and — for Hot (b) — merging of concurrent reporting streams with exact value-identity de-duplication. HotAndMirrored failover re-activates the mirrored session with the existing `AuthenticationToken` instead of recreating it. - Network redundancy: alternate communication paths via endpoint selection. ## Distributed state (opt-in; an extension beyond §6.6) - `ISharedKeyValueStore` (in-memory default) and `INodeStateStore`, with an `AddressSpaceSynchronizer` that bridges a `CustomNodeManager2`'s predefined nodes to the shared store, so node and reference additions/removals and value changes propagate to other replicas. `IDistributedValueCache` lets read/write callbacks cache the last value with a freshness bound; monitored items use the normal read pipeline and therefore participate only when the read path does. - **Secure session sharing (active/passive fast reconnect), server and client.** `DistributedSessionManager` (wired through a new additive `ISessionManagerFactory` seam on `StandardServer`) mirrors **encrypted** session state across replicas. On a failover reconnect the standby restores the session and performs the **full `ActivateSession` client-certificate signature validation** against a **single-use** `serverNonce` consumed via compare-and-swap across the replica set, enforcing the same SecurityPolicy and SecurityMode. The `AuthenticationToken` is a **lookup key only**, never an authenticator: entries are keyed by the SHA-256 digest of the token, and a cross-replica restore emits a distinct audit event. - Subscription, retransmission-queue, and continuation-point mirroring for subscription transfer and failover. - Leader election: a static single-leader provider and a shared-store **lease via compare-and-swap**, supporting active/passive and active/active (shared-read / master-write). - Fail-closed security defaults: shared records are protected at rest through `IRecordProtector`; secret-bearing mirrors require a registered protector or an explicit opt-out. ## Active/active (CRDT) `Opc.Ua.Server.Redundancy.Crdt` adds leaderless multi-writer address-space replication with CRDTs and gossip (`UseReplicatedAddressSpace`) plus CRDT-backed session metadata (`UseReplicatedSessions`). Networked gossip is **fail-closed without authenticated transport** (mutual TLS for TCP; an explicit opt-out for isolated dev/test). CRDT state is eventually consistent, so exactly-once decisions (such as the single-use nonce registry) stay on a strongly consistent store. The package is available on all stack target frameworks. ## Kubernetes `Opc.Ua.Server.Redundancy.K8s` provides Kubernetes Lease leader election, EndpointSlice-based peer discovery, and ServiceLevel-driven readiness for running an OPC UA server replica set. `Docs/HighAvailabilityKubernetes.md` covers StatefulSet/Deployment and Service manifests, RBAC, probes, time synchronization, secrets, gossip-port NetworkPolicy, and GDS/NTRS registration. ## Compatibility and validation - **Zero-overhead** single-instance default; additive, backward-compatible seams (for example `ISessionManagerFactory` and `IServerStartupTask`); replaced APIs marked `[Obsolete]` for migration. - Builds across the full stack TFM set (`net472`, `net48`, `netstandard2.0`, `netstandard2.1`, `net8.0`, `net9.0`, `net10.0`); NativeAOT-compatible where the runtime supports it. - Unit and integration tests for server, client, subscriptions, session mirroring, CRDT, and Kubernetes; the conformance suite stays green. See `Docs/HighAvailability.md` for the full OPC 10000-4 §6.6 mapping, the `Add*` (standard nodes) versus `Use*` (extension) builder convention, and the security/rotation guidance. --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> |
||
|
|
cff6e47596 |
Fix Fluent NodeManager Configure wiring: typed OnCall for imported methods + runtime value updates (#3973) (#3977)
# Description Fixes two gaps in the fluent, source-generated NodeManager `Configure` surface reported in #3973. ## 1. Typed `OnCall` overloads for imported / void-returning methods The documented form `builder.X.SetOutputVal.OnCall((float v) => …)` failed to compile with **CS1593 "Delegate 'Action' does not take 1 arguments"**. The Fluent and ObjectType-proxy generators read `MethodDesign.InputArguments` / `OutputArguments` directly, with no fallback. For **NodeSet2-imported instance methods**, the arguments live only on the referenced method declaration (`MethodDeclarationNode` / `MethodType`), so the generator saw zero inputs and emitted only `OnCall(System.Action)`. - Added `Tools/Opc.Ua.SourceGeneration.Core/Generators/MethodDesignArgumentResolver.cs` — resolves the effective input/output `Parameter[]` with a fallback to `MethodDeclarationNode` → `MethodType`. - Wired it into `FluentBuilderGenerator` and `ObjectTypeProxyGenerator`. - A method with inputs but no output now binds to `OnCall(Action<TIn…>)` (and the async `Func<…, CancellationToken, ValueTask>`), with `Variant.TryGetValue` unpacking. ## 2. Runtime value changes now reach subscribed MonitoredItems An `OnRead`-backed variable (or a backing field mutated inside an `OnCall` handler) updated on the Attribute (Read) service but **not** for subscriptions: the getter isn't sampled, and the old `Node.ClearChangeMasks(...)` recipe is unreachable because the fluent builder is sealed after `Configure`. Added a supported, AOT-safe, DI-friendly runtime surface in `Libraries/Opc.Ua.Server/Fluent/`: - **`IValueUpdater<TValue>`** (+ `ValueUpdater<TValue>`) — a runtime handle captured during `Configure` that survives sealing. `SetValue` sets Value + StatusCode + Timestamp and flushes `ClearChangeMasks` in one serialized call; overloads for status/timestamp plus `NotifyChange()` for in-place mutations. - **`RuntimeValueBuilderExtensions`** — - `Bind(out IValueUpdater<TValue>)` for explicit pushes (e.g. from an `OnCall` handler); - `PollEvery(interval, getter)` opt-in auto-sampling that pushes only on change, reusing the manager-owned `SimulationRegistry` loop infrastructure. - `FluentVariant` centralizes the single Variant boxing / AOT-suppression site (shared with `VariableBuilder`). Usage: ```csharp private IValueUpdater<float> m_ao01 = null!; partial void Configure(IMyNodeManagerBuilder builder) { builder.MyEquipment03.AO01.Builder.AsVariable<float>().Bind(out m_ao01); builder.MyEquipment03.SetOutputVal.OnCall((float value) => m_ao01.SetValue(value)); } ``` ## Documentation - `Docs/SourceGeneratedNodeManagers.md`: corrected the typed-`OnCall` overload description (input-only / imported methods) and added a **"Pushing runtime value changes to subscribers"** section with `Bind` / `PollEvery` examples. ## Related Issues - Fixes #3973 ## Checklist - [ ] I have signed the [CLA](https://opcfoundation.org/license/cla/ContributorLicenseAgreementv1.0.pdf) and read the [CONTRIBUTING](https://github.com/OPCFoundation/UA-.NETStandard/blob/master/CONTRIBUTING.md) doc. - [x] I have added tests that prove my fix is effective or that my feature works and increased code coverage. - [x] I have added all necessary documentation. - [x] I have verified that my changes do not introduce (new) build or analyzer warnings. - [x] I ran **all** tests locally using the **UA.slnx** solution against at least .net **framework** and .net **10**, and all passed. - [ ] I fixed **all** failing and flaky tests in the CI pipelines and **all** CodeQL warnings. - [ ] I have addressed **all** PR feedback received. --- ### Validation - `Opc.Ua.Server.Tests` Fluent suite: **232/232** pass on **net10.0** and **net48** (new `RuntimeValueBuilderExtensionsTests`, 8 cases). - `Opc.Ua.SourceGeneration.Core.Tests`: **3712** pass on **net10.0** (3 new generator tests + declaration-backed NodeSet2 fixture; new tests also verified on net48). - Builds are warning-clean under `TreatWarningsAsErrors`. |
||
|
|
13c16a0376 |
Fix unreachable owner-identity fallback in SamplingGroup.MeetsGroupCriteria (#3971)
# Description
`SamplingGroup.MeetsGroupCriteria` gated its owner-identity fallback on
`context?.SessionId == null`. Because `NodeId` is now a readonly struct,
`OperationContext.SessionId` returns `default(NodeId)` (not `null`) for
a sessionless context, so that condition was always `false`. As a result
the owner-identity comparison was dead code, sessionless groups fell
into the session branch and compared `default(NodeId)` against `null`
(always mismatching), and a null `context` would throw on the final
`context!.DiagnosticsMask` dereference.
Changes:
- **Gate on group state, not context** — the fallback now branches on
`m_session == null` (the group's own sessionless state) and compares
`m_effectiveIdentity` against `savedOwnerIdentity`; otherwise it
compares `context?.SessionId` to `m_session.Id`.
- **Null-context hardening** — the final diagnostics-mask check now
returns `false` for a null `context` instead of throwing.
- **Tests** — added offline unit tests for the sessionless
accept-by-owner-identity path and the mismatched-owner-identity reject
path.
```csharp
if (m_session == null)
{
// fallback to compare user Identity if session is not set.
if (!m_effectiveIdentity!.Equals(savedOwnerIdentity))
{
return false;
}
}
// compare session
else if (context?.SessionId != m_session.Id)
{
return false;
}
// check the diagnostics marks.
return context != null &&
m_diagnosticsMask == (context.DiagnosticsMask & DiagnosticsMasks.OperationAll);
```
Session-based matching is unaffected.
## Related Issues
## Checklist
_Put an `x` in the boxes that apply. You can complete these step by step
after opening the PR._
- [ ] I have signed the
[CLA](https://opcfoundation.org/license/cla/ContributorLicenseAgreementv1.0.pdf)
and read the
[CONTRIBUTING](https://github.com/OPCFoundation/UA-.NETStandard/blob/master/CONTRIBUTING.md)
doc.
- [x] I have added tests that prove my fix is effective or that my
feature works and increased code coverage.
- [ ] I have added all necessary documentation.
- [x] I have verified that my changes do not introduce (new) build or
analyzer warnings.
- [ ] I ran **all** tests locally using the **UA.slnx** solution against
at least .net **framework** and .net **10**, and all passed.
- [ ] I fixed **all** failing and flaky tests in the CI pipelines and
**all** CodeQL warnings.
- [ ] I have addressed **all** PR feedback received.
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Marc Schier <marcschier@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Marc Schier <marcschier@hotmail.com>
|
||
|
|
61ba003116 |
Add integration test for server side complex types (#3961) (#3970)
# Description Adds a client↔server **integration test** for the server side complex type system (`ServerComplexTypeSystem.LoadComplexTypesAsync` / the `AddComplexTypeSystem` builder extension). Until now this feature was only covered by mock-based unit tests (`ServerComplexTypeSystemTests`); there was no end-to-end test proving a real server that hosts runtime-loaded custom DataTypes (no compiled .NET backing) can encode/decode them over the wire. The new test (`Tests/Opc.Ua.Server.Tests/ComplexTypes/`): - A `ReferenceServer` subclass hosts a small hand-authored **NodeSet2** (embedded resource) loaded at runtime by a test node manager. It declares custom types with no compiled backing: - `TestPoint` — a `Structure` (`X:Int32`, `Y:Int32`, `Name:String`) with a Default Binary encoding node. - `TestColor` — an `Enumeration` (Red/Green/Blue). - The server builds dynamic stand-in encodeables via the default `OnNodeManagerStartedAsync` path and then populates the sample variables (the runtime struct value is built through `server.Factory.TryGetEncodeableType(...).CreateInstance()`). - A real client connects, loads its complex type system, and exercises the round-trip. **Assertions:** 1. The server `IEncodeableFactory` registers the runtime `TestPoint` stand-in (+ its binary encoding id) and the `TestColor` enumeration. 2. Server→client read: the client decodes the runtime structure (`X`/`Y`/`Name`). 3. Enum read round-trips. 4. Client→server write: the server decodes the runtime structure via its stand-in and returns the updated value. This is a **test-only** change — no production code is modified. ## Related Issues - Fixes #3961 ## Checklist - [ ] I have signed the [CLA](https://opcfoundation.org/license/cla/ContributorLicenseAgreementv1.0.pdf) and read the [CONTRIBUTING](https://github.com/OPCFoundation/UA-.NETStandard/blob/master/CONTRIBUTING.md) doc. - [x] I have added tests that prove my fix is effective or that my feature works and increased code coverage. - [x] I have added all necessary documentation. - [x] I have verified that my changes do not introduce (new) build or analyzer warnings. - [x] I ran the affected tests locally against .net **framework (net48)** and .net **10**, and all passed (4/4 on each TFM). - [ ] I fixed **all** failing and flaky tests in the CI pipelines and **all** CodeQL warnings. - [ ] I have addressed **all** PR feedback received. --------- Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> |
||
|
|
d7cb170b86 |
CTT compliance (#3960) + HA/Aggregate facets (#3875) + server-side pcap capture (#3962)
## Summary This PR bundles two independent bodies of work on the branch: 1. **CTT compliance & Historical Access** — improves OPC UA Compliance Test Tool (CTT) conformance of the Console Reference Server (issue #3960) and advertises the correct Historical Raw Data + Aggregate server facets (issue #3875). 2. **Server-side in-process packet capture (pcap)** — lets a hosted server capture its inbound client→server traffic in-process, with a documented non-DI wiring path. The CTT work was driven by an actual CTT run (`NewCTT2`, script v1.05.513) whose 4757 error results were parsed and clustered by conformance unit. Fixes are verified live via MCP against the running `--ctt` server and covered by unit/integration tests that are green on **net48 + net10**. ## Server-side in-process packet capture (pcap) Adds the ability to capture a hosted server's **inbound** (client→server) `opc.tcp` traffic in-process, symmetric to the existing client-channel capture in `Opc.Ua.Core.Diagnostics`. Previously `PcapBindings.Install(server.Server.TransportBindings)` only installed a client *channel* decorator — a server accepts connections through *listeners*, which never consult channel factories — so nothing was captured, and `InProcessServerCaptureSource` was a placeholder. Installing a binding also records nothing on its own until a `CaptureSessionManager` session is started (which is now documented). - **Core seam** (`Opc.Ua.Core`, opt-in, zero cost when unused): `TransportListenerSettings.AcceptedTransportDecorator` + `OnAcceptedChannel`, applied in `TcpListenerChannel.Attach(socket)` and the reverse-connect path; `TcpTransportListener` wires them per accepted channel. Default `null` → no behavior change for non-capturing servers. - **`PcapTransportListenerBinding`** — an `ITransportListenerFactory` **listener decorator** (the server-side mirror of the client `PcapTransportChannelBinding`) that injects the capture seam via `OpenAsync`, wraps each accepted channel's byte transport in `CapturingByteTransport`, and forwards channel-token key material to the active observer. - **`PcapBindings`** — `Install` now wires **both** client and server; new `InstallClient` / `InstallServer` helpers. `AddPcap` covers both sides too. `InProcessServerCaptureSource` is now functional. - **Non-DI usability** — new public `ClientChannelManager.DefaultChannelBindings` accessor so non-DI clients can install the binding into the registry the client actually uses, plus a new "Enable pcap capture without dependency injection" guide in `Docs/Diagnostics.md` (server / client / both recipes, install-before-start timing, the two-registries nuance) and `NugetREADME` updates. - **Tests** — Core settings-seam unit tests (net48 + net10), `PcapTransportListenerBinding` / `PcapBindings` unit tests, and a real server↔client integration test asserting a non-empty pcap of server-accepted frames. ## Fixes (CTT compliance / Historical Access) ### Historical Access — Read Raw (~1996 CTT errors) The new historian returned `Good_MoreData` when handing back a `ContinuationPoint`. Per OPC UA Part 11 §6.5.3.2 (and the CTT HA Read Raw tests 008/009, which assert `Good` **and** a `ContinuationPoint` together) the operation status must be **`Good`** — the non-empty ContinuationPoint alone signals more data. Fixed all four continuation sites (raw / modified / annotation / processed-event) in `HistorianDispatcher`, and additionally report **`Good_NoData`** for a raw/modified read of an interval that contains no data and requests no bounds (CTT HA Read Raw 007). Adds regression tests. ### Historical Access — HA Configuration (~282 CTT errors) Historizing reference-server nodes had no `HasHistoricalConfiguration` reference, so History Access aggregate clients (and the CTT) could not discover the archive/aggregate configuration. The reference server now attaches a populated `HistoricalDataConfigurationType` companion object ("HA Configuration") to every historizing node. This also fixes a latent bug in `HistoricalDataConfigurationInstaller`: a freshly created configuration instance (and its mandatory `Stepped` / `AggregateConfiguration` children) retained the type's shared NodeIds, so the reference targeted the type node and multiple nodes collided — the installer now assigns instance NodeIds to the whole subtree via the node manager's `INodeIdFactory`. Adds a regression test. ### Historical Access — Read Raw status codes Additional CTT HA Read Raw conformance fixes: - Insufficient details (<2 of startTime/endTime/numValuesPerNode) → `Bad_HistoryOperationInvalid` (Err-027). - IndexRange on scalar history → `Bad_IndexRangeNoData` at the operation level (Err-009). - Unknown/foreign ContinuationPoint (e.g. a Browse CP) → `Bad_ContinuationPointInvalid` (Err-014/Err-024). - No spurious ContinuationPoint on the final page of a one-value-at-a-time read (008/009). - `TimestampsToReturn.Neither` → `Bad_TimestampsToReturnInvalid` (Err-002). All validated against the actual CTT run (`NewCTT2` Run2, an HA-only re-run built with the base fixes) which confirms the 1999 "Good_MoreData vs Good" failures are gone. Covered by tests. ### Earlier commits in this PR Variant/BaseDataType array write `BadTypeMismatch`, DiagnosticInfos gating on `DiagnosticsMask`, multi-dimensional array values; strengthened Attribute Write conformance tests; Condition comment retention on null Acknowledge/Confirm; historized the full scalar type set + paired aggregate nodes; populated `ServerCapabilities.ConformanceUnits`; advertised `HistoricalRawData2022` + `AggregateHistorical2022` facets (#3875) with `Docs/Profiles.md` updates. ## Diagnosed (not server bugs — CTT connection configuration) ### Auditing Connections (~1684 CTT errors) All 1684 failures are identical ("Unable to Find Entry for ClientAuditEntryId"). Audit events are, per spec, delivered only to sessions holding the `SecurityAdmin` role: the server validates `PermissionType.ReceiveEvents` per event-monitored-item, and the integration test `AuditingOperationTests` connects as `sysadmin`/`demo` for exactly this reason. The CTT run collected zero audit events because it connected **anonymously**. Documented in `Docs/Diagnostics.md`: configure the CTT to authenticate as `sysadmin`/`demo` (mapped to `[SecurityAdmin, AuthenticatedUser]` in `ReferenceServer.cs`). ### Address Space WriteMask (~126 CTT errors) `revertToOriginalNodeAttributes` writes back all node attributes and gets `BadUserAccessDenied` (a permission error) rather than Good/BadNotWritable/BadAttributeIdInvalid — the same anonymous-connection cause; expected to clear when the CTT connects as `sysadmin`/`demo`. ## Still open Alarms & Conditions Retain/ConditionDisabled/InputNode (logic is spec-aligned on inspection; needs a CTT-faithful reproduction to separate a genuine bug from alarm-simulation timing), Aggregate function values (now unblocked by the HA Configuration fix), GDS self-registration, residual Attribute IndexRange/type-mismatch. CTT-script errors (`ArrayItems` / `ItemsHistoryCountExceeds` undefined) are not server-fixable. ## Testing `Opc.Ua.Server.Tests` (Historian) and `Opc.Ua.History.Tests` green on net48 + net10; historian and HA-configuration behaviour verified live against the running `--ctt` server. Server-side pcap capture: Core builds clean on net48 + net10, and the new unit + server↔client integration tests pass (the only failing `Opc.Ua.Core.Diagnostics.Tests` are 3 pre-existing, unrelated `OfflineSecureChannelSmokeTests`). The single most decisive remaining CTT step is a re-run authenticated as `sysadmin`/`demo`, which clears the permission-based clusters and isolates the true remaining server bugs. |
||
|
|
b26be47a48 |
Increase Opc.Ua.Server library unit-test coverage (#3967)
## Summary Adds focused, deterministic, offline unit tests that raise coverage across the **Opc.Ua.Server** library. All changes are test-only — no production code is modified. The PR diff touches only files under `Tests/`. ## Areas covered **NodeManager** - `ContinuationPoint`, `EventManager` - `CustomNodeManager2` / `AsyncCustomNodeManager` (incl. `CallAsync`) - `SamplingGroup`, `SamplingGroupManager`, `SamplingGroupMonitoredItemManager` - Shared `DeterministicServerMock` helper for constructing node managers offline **Configuration / server** - `TrustList` - `ResourceManager`, `ModellingRulesManager`, `DataTypeSchemaRegistrationExtensions`, `OpcUaServerEventSource` - `ReverseConnectServer`, `StandardServer` **Sessions / identity** - `Session` and `SessionManager` (targeted at the previously-uncovered lines, ~90%) - `UserManagementBinding`, `ServerIdentityRegistryExtensions` **FileSystem** (all files now ≥80% line coverage) - `PhysicalFileSystemProvider`, `FileSystemNodeId`, `FileHandle`, `FileSystemNodeManager` / `FileSystemNodeManagerFactory` - `FileObjectState` (92.6%) and `DirectoryObjectState` (85.7%) — drive the FileType / FileDirectoryType method handlers, metadata property read hooks, browser population and exception branches by invoking the state `OnCall` / `OnCallAsync` delegates against a physical provider rooted at a temp directory **Historian** (all files ≥80%) - Installer, ProviderBase, EventFilterTarget, Dispatcher, Registry, InMemoryProvider, CaptureSink ## Notes - Tests use NUnit constraint-model asserts (`Assert.That`), minimal Moq, no reflection. - Built and run against `net8.0`; `dotnet format --verify-no-changes` is clean on the new files. - A separate issue was filed for the SamplingGroup behaviour discovered while writing these tests. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: Marc Schier <marcschier@users.noreply.github.com> Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> |
||
|
|
8899af69b5 |
GH Actions pipelines update, nightly + mac gating, diagnostic dumps (#3881)
# Description CI-only PR (no shipped-code change). Modernises the AzDO + GitHub Actions pipelines, adds a preview-package workflow that publishes to GitHub Packages, adds a nightly full-scope run, tightens macOS gating, and improves testhost diagnostics. ## Summary ### Azure Pipelines 1. **`managedPool` parameter** — Optional routing of Windows/Linux jobs to the `netstandard` Managed DevOps Pool (`ImageOverride` demands). Default `false`; operators can flip per queue. 2. **Per-TFM build matrix** — `sln.yml` fans out into one job per (TFM × configuration) for the full-scope build so each matrix leaf fits on small-disk pool agents. 3. **Cancel-aware `condition:` forwarding in `test.yml`** — parameters wrapped in `and(succeeded(), <forwarded>)` so user-cancel propagates to jobs. 4. **Decoupled test / result-publish steps** — `DotNetCoreCLI@2 command: test` runs with `publishTestResults: false` + explicit `--logger trx`; a separate `PublishTestResults@2` runs `succeededOrFailed() + continueOnError: true`. Prevents transient DNS blips against `opcfoundation.visualstudio.com` from flipping green runs to failed. 5. **Blame + dump collection** — `dotnet test` uses `--blame-hang-timeout 10m --blame-hang-dump-type mini` so silent hangs become named test failures with a mini-dump attachment. Fuzz-artifact download/extract/upload steps gated to `Fuzz.Tests` jobs only. 6. **Diagnostic dumps published as build artifacts** — new `Stage/Publish diagnostic dumps` steps collect `*.dmp`, `*.mdmp`, `*.dump`, Linux `core`/`core.*` from `$(Agent.TempDirectory)` on every finished job (`succeededOrFailed()`), keyed by `System.JobId` so parallel matrix entries never collide. Root-caused from a run where the previous `failed()` gate silently skipped because the test task itself was reported succeeded despite testhost issues. 7. **Weekly full-scope run** — new `schedules:` block firing Sundays 02:00 UTC (`always: true`, master). All stages already gated on `ScheduledBuild` (`Debug`, `.NET 9/8/472/netstandard`, `Coverage`, `AOT`, macOS matrix) participate automatically. 8. **macOS gating** — mac net10 job added back to `testfastpr` gated on `ne(ScheduledBuild, 'False')` so mac runs nightly/manual only (not on PR/master push). Stripped 4 stale `IsDraft` per-job conditions in already-`ScheduledBuild`-gated stages (`testdebug`, `testnet90`, `testnet80`, `testnetstandard21`). 9. **Preview solution generation** — deleted the hand-maintained `UA Core Library.slnx` (and dead `MonoReferenceServer.csproj`); added `.azurepipelines/generate-slnx.ps1` that derives `preview-pack.slnx` from `UA.slnx` by stripping `/Tests/`, `/Fuzzing/`, `/Solution Items/`. `preview.yml` uses the generated solution. ### GitHub Actions 10. **New `.github/workflows/preview-publish.yml`** — mirrors `.azurepipelines/preview.yml` end-to-end (versioning via existing `set-version.ps1`, strong-name + Authenticode + nupkg signing, modern + legacy nuspec packaging) and publishes to **GitHub Packages** (`https://nuget.pkg.github.com/OPCFoundation/index.json`) with `--skip-duplicate`. Triggers: `workflow_dispatch`, push to `master` (Preview version), push to `v*` tags (Public version). Every signing step gracefully skips when the corresponding secret is missing (fork-friendly). Requires `permissions: packages: write`. 11. **Reshuffled `buildandtest.yml` matrix** — GH Actions covers Linux + macOS (net10 only); Windows is fully covered by AzDO. AoT job expanded to `ubuntu-latest` (`linux-x64`), `macos-13` (`osx-x64`), `macos-latest` (`osx-arm64`) with a single RID-aware run step. Added `schedule` (Sun 02:00 UTC) + `workflow_dispatch(include_macos)` triggers. The `discover` job computes `test_os` + `aot_matrix` dynamically based on event type: macOS is **off** by default on `pull_request` and **on** by default for push/schedule/workflow_dispatch (respecting the input). ### Tests 12. **`ReferenceNodeManager.DoSimulation`** — added `catch (ObjectDisposedException) when (m_simulationTimer is null)` to swallow the expected teardown race between the simulation timer callback and `Dispose`. 13. **`AlarmsAndConditions*` test fixture** — added `DefaultEventWaitTimeout = TimeSpan.FromSeconds(30)` and migrated 22 call sites off the previous 5 s poll; `AcknowledgeBranchAsync` + `ConfirmBranchAsync` marked `[Retry(2)]` to absorb a rare macOS `BadSecureChannelClosed` race. ## Related issues Follow-up to #3872. |
||
|
|
00377a34ab |
Expand DI / Fluent API: injectability + one-shot ergonomics (client, server, PubSub, discovery/bindings) (#3957)
# Description Completes a dependency-injection / fluent-API surface review follow-up so that **every feature is reachable and configurable from the `services.AddOpcUa()` chain**, while keeping all existing granular registrations and direct-construct (`new`) fallbacks. The change is backward compatible — the single rename (`WithAuthorizationService` → `AddAuthorizationService`) keeps an `[Obsolete]` alias. **Client** — chainable `IOpcUaClientBuilder` overloads of `AddComplexTypes` / `AddAlarms` / `AddWebApiTransportChannel`; `ManagedSessionOptions.LoadComplexTypes` + `AddManagedClient()` one-shot; injectable multi-endpoint `IManagedSessionFactory`; DI factories `AddHistorian` / `AddRoleManagement` / `AddFileTransfer` / `AddAliasNames`; fail-fast options validation + `AddDiscovery()`. **Server** — `IOpcUaServerFactory` / `AddServer<TServer>()` seam (the hosted service no longer hardcodes `new StandardServer`) unlocking injectable durable subscriptions and session/subscription managers; plus `AddHistorian`, `AddFileSystem` (Part 20), `AddSecretStore` / `AddCertificateManager` / `AddAliasNameStore`; secure-by-default anonymous authenticator (marker-guarded, no double-registration). **PubSub** — `AddUdpPubSub()` / `AddMqttPubSub()` one-shots; `IPubSubBuilder` anchor unification (`AddSecurityKeyServiceClient/Server/PushTarget`, `AddSchema`, `AddPcapCapture`); `ConfigureConfiguration()` config-authoring bridge; `IMqttTransportBuilder` parity with UDP/Eth; order-independent pcap decoration. **Discovery / Bindings** — LDS/GDS non-TCP endpoints fail loudly instead of silently; GDS `AddInMemoryStores()` + fast-fail when stores are missing; order-independent one-shot `AddHttpsTransport()` (Kestrel + HTTPS/WSS + optional WebApi/auth); `AddAuthorizationService` (`[Obsolete]` alias for `WithAuthorizationService`); root-level `IOpcUaBuilder.AddPcap()`; WotCon-server-without-`AddServer` startup guard. Docs updated: `Docs/DependencyInjection.md`, `Docs/PubSub.md`, `Docs/Transports.md`, `Docs/WebApi.md`. Validation performed locally: the 12 changed libraries and 9 affected test projects build clean (0 warnings / 0 errors) on **net10.0 and net48**; the full net10.0 sweep of the affected suites passes (~7,700 tests — Server 1920, GDS 904, LDS 149, Client 1577, ComplexTypes 2733, PubSub 1141 + Diagnostics 53, WotCon 344, HTTPS.WebApi 319); the net48 new-feature suites pass (Client 123, Server 43, PubSub 49, GDS 21, LDS 10, WotCon 8, ComplexTypes 7). ## Related Issues Follow-up to an internal DI / Fluent-API surface review (no single tracking issue). Happy to open a tracking issue / ADR if maintainers prefer before merge. - Fixes # _(n/a — review follow-up)_ ## Checklist _Put an `x` in the boxes that apply. You can complete these step by step after opening the PR._ - [ ] I have signed the [CLA](https://opcfoundation.org/license/cla/ContributorLicenseAgreementv1.0.pdf) and read the [CONTRIBUTING](https://github.com/OPCFoundation/UA-.NETStandard/blob/master/CONTRIBUTING.md) doc. - [x] I have added tests that prove my fix is effective or that my feature works and increased code coverage. - [x] I have added all necessary documentation. - [x] I have verified that my changes do not introduce (new) build or analyzer warnings. - [ ] I ran **all** tests locally using the **UA.slnx** solution against at least .net **framework** and .net **10**, and all passed. _(Ran the affected areas comprehensively on net10.0 + net48; a full UA.slnx run across both TFMs is still pending.)_ - [ ] I fixed **all** failing and flaky tests in the CI pipelines and **all** CodeQL warnings. - [ ] I have addressed **all** PR feedback received. |
||
|
|
b15d6e7dbc |
Fix false-positive MODELGEN010 for mixed NodeSet2 + ModelDesign [NodeManager] binding (#3968)
Fixes the false-positive MODELGEN010 ("did not match any model") that blocked builds
when a project combined a NodeSet2 types file (with a [NodeManager] bound to its URI)
and a ModelDesign instances file.
[NodeManager] binding resolution now aggregates a shared "used" set and a global model
count across the NodeSet2 and ModelDesign generation passes, reporting unmatched or
ambiguous bindings once (via Generators.ReportUnmatchedNodeManagerBindings) instead of
per pass. Also corrects the single-model fallback / ambiguity detection to use the
global model count.
Includes end-to-end and core regression tests plus docs fixes (the MODELGEN010
diagnostics entry, and mixed-project [NodeManager] / Prefix-Name clarifications).
Addresses #3937.
|