mirror of
https://github.com/OPCFoundation/UA-.NETStandard.git
synced 2026-10-22 01:26:20 +08:00
copilot/fix-code-review-comment
93 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
8538f531e7 | Update paths for the consolidated repository layout | ||
|
|
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. |
||
|
|
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> |
||
|
|
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. |
||
|
|
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> |
||
|
|
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> |
||
|
|
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. |
||
|
|
f9a8343dea |
Full 1.05.06 compliant OPC UA Part 14 (PubSub) (#3892)
# Full OPC UA Part 14 (PubSub) — v1.05.06 This PR replaces the legacy PubSub stack with a modern, **OPC UA Part 14 v1.05.06**-compliant reimplementation built on current .NET: fully `async`, dependency-injection-first with a fluent builder (`services.AddOpcUa().AddPubSub(...)`), NativeAOT/trim-safe, and designed for high-throughput, highly-available, distributed deployments. The libraries — `Opc.Ua.PubSub`, `Opc.Ua.PubSub.Udp`, `Opc.Ua.PubSub.Mqtt`, `Opc.Ua.PubSub.Server`, and `Opc.Ua.PubSub.Adapter` — keep source compatibility with 1.5.378 where practical (obsolete shims) and ship a complete migration path. See the **[PubSub guide](https://github.com/OPCFoundation/UA-.NETStandard/blob/part14pubsub/Docs/PubSub.md)** and the **[2.0.x migration guide](https://github.com/OPCFoundation/UA-.NETStandard/blob/part14pubsub/Docs/migrate/2.0.x/pubsub.md)**. **Encodings & transports.** Both wire encodings are implemented in full — **UADP** (key/delta/event/keepalive, RawData, chunked, signed+encrypted) and **JSON** (verbose/compact, single-message, metadata; migrated from `Newtonsoft.Json` to `System.Text.Json`) — across **UDP** (uni/multi/broadcast + discovery), **MQTT** (3.1.1/5.0, retained metadata, TLS), and a from-scratch **DTLS 1.3** secured datagram transport (`opc.dtls://`) implemented on the .NET BCL crypto primitives (ECDHE, HelloRetryRequest cookies, certificate auth, AEAD record protection, HKDF key schedule), wired through `AddUdpTransport().WithDtls(...)`. Details in [Transports](https://github.com/OPCFoundation/UA-.NETStandard/blob/part14pubsub/Docs/PubSub.md#transports) and [Encodings](https://github.com/OPCFoundation/UA-.NETStandard/blob/part14pubsub/Docs/PubSub.md#encodings). A raw **Ethernet (Layer 2)** transport (`opc.eth://`, EtherType `0xB62C`, optional 802.1Q VLAN) carries UADP NetworkMessages directly in Ethernet II frames with no IP/UDP, via `AddEthTransport()` (`.WithPcap()` for cross-platform capture). See [Ethernet transport](https://github.com/OPCFoundation/UA-.NETStandard/blob/part14pubsub/Docs/PubSub.md#ethernet--uadp-opceth). **Runtime schema generation.** A new schema subsystem (`Opc.Ua.Core.Schema`, `Opc.Ua.PubSub.Schema`) generates **XSD**, **OPC Binary (BSD)**, and **JSON Schema** for OPC UA data types at runtime — including PubSub NetworkMessage/DataSet message schemas — driven from the type system and source-generated metadata (no reflection; NativeAOT/trim-safe). It is consumable from the client, server, and PubSub stacks. See the **[Schema generation guide](https://github.com/OPCFoundation/UA-.NETStandard/blob/part14pubsub/Docs/SchemaGeneration.md)**. **Security, fail-closed.** Message-level security is wired end-to-end through `IPubSubSecurityWrapperResolver`: publishers are fail-closed (a secured group with no key source throws rather than emitting plaintext) and subscribers enforce per-reader inbound security. It includes AES-CTR (128/256) policies with HMAC-SHA-256, a deterministic 96-bit nonce with a messages-per-key cap, a monotonic sliding replay window, and a Security Key Service (SKS) pull client + in-memory server with SecurityGroups and key rotation. Two independent security assessments (IEC 62443-4-2 × OPC UA Part 2/4/14, plus a Microsoft SDL/SFI delta pass) drove remediation of all actionable findings — including orphaned message security, chunked-frame security bypass, unauthenticated Action invocation, pre-auth reassembly DoS, and DTLS hardening. See [Security](https://github.com/OPCFoundation/UA-.NETStandard/blob/part14pubsub/Docs/PubSub.md#security) and [SKS](https://github.com/OPCFoundation/UA-.NETStandard/blob/part14pubsub/Docs/PubSub.md#security-key-service-sks). **Server-side & high availability.** The runtime can optionally surface through a standard in-process OPC UA address space (`Opc.Ua.PubSub.Server`) with configuration methods, per-component diagnostics, the full PubSubState model, KeepAlive and MessageReceiveTimeout. Pluggable configuration/runtime-state stores, an id allocator, and HA runtime-state providers with failover support running publishers/subscribers in a distributed system. See [Server-side address space](https://github.com/OPCFoundation/UA-.NETStandard/blob/part14pubsub/Docs/PubSub.md#server-side-address-space) and [High availability](https://github.com/OPCFoundation/UA-.NETStandard/blob/part14pubsub/Docs/PubSub.md#high-availability-state-providers). **External-server adapter (bridge) with hot-reload.** A new `Opc.Ua.PubSub.Adapter` binds PubSub publishers, subscribers, and Action responders to an **external** OPC UA server over `ManagedSession` — cyclic Read or subscription-backed sources, browse-path node mapping, and metadata that resolves/retries and re-emits on model-change events. Adapter and PubSub configuration **hot-reload incrementally** (only changed writers/readers/responders are rewired; unchanged sessions are reused), driven by `IPubSubConfigurationStore.Changed` and `IOptionsMonitor`, with a pluggable change-feed source (e.g. etcd). See [Binding PubSub to an external server](https://github.com/OPCFoundation/UA-.NETStandard/blob/part14pubsub/Docs/PubSub.md#binding-pubsub-to-an-external-opc-ua-server-client-session-adapters). **Samples, packaging & quality.** One combined sample, `ConsoleReferencePubSubClient`, demonstrates publisher, subscriber, and external-server modes on `Host.CreateApplicationBuilder` with full fluent/DI wiring; all libraries publish **NativeAOT with zero IL2026/IL3050 warnings** ([Native AOT](https://github.com/OPCFoundation/UA-.NETStandard/blob/part14pubsub/Docs/PubSub.md#native-aot), [DI](https://github.com/OPCFoundation/UA-.NETStandard/blob/part14pubsub/Docs/DependencyInjection.md)). The change ships comprehensive NUnit/integration suites and a libFuzzer harness, maintains ≥80% coverage on the new libraries, and is documented end-to-end ([What's new in 2.0](https://github.com/OPCFoundation/UA-.NETStandard/blob/part14pubsub/Docs/WhatsNewIn2.0.md)). |
||
|
|
bab073952c |
Adding HTTPS/WSS transports + Web API binding (Part 6 §G.3 OpenAPI Mapping), shared Kestrel host, Kestrel-TCP (#3880)
# HTTPS / WSS transports + OPC UA Web API binding (Part 6 §G.3) + shared Kestrel host Combined follow-up that completes the HTTPS / WSS / Web API transport story started in #3876 and #3877. Three coordinated bodies of work land together: a **shared Kestrel host** with full WSS reverse-connect and an opt-in Kestrel-hosted `opc.tcp://` path (no separate NuGet), the **OPC UA Web API binding** (Part 6 §G.3 "OpenAPI Mapping") with a spec-compliant ASP.NET Core Minimal-API server and symmetric C# client, and a targeted **edge-security hardening** pass across every new HTTPS / WSS / JSON / Web API surface. UASC crypto / signing / sequence / nonce logic is unchanged. ## Shared Kestrel host, WSS reverse-connect, Kestrel-TCP Multiple `HttpsTransportListener` instances now share one `IHost`, so `opc.https://` and `opc.wss://` can be colocated on a single port. WSS gains full reverse-connect on **both** server and client sides via `HttpsTransportListener.CreateReverseConnection` / `TransferListenerChannelAsync`, plumbed through the same `TcpServerChannel.BeginReverseConnect(IUaSCByteTransport)` path as TCP. An opt-in `KestrelTcpTransportListener` (`AddKestrelOpcTcpTransport()`) hosts `opc.tcp://` on Kestrel via `ConnectionHandler` so consumers can run every OPC UA transport under one host; it ships **inside** `OPCFoundation.NetStandard.Opc.Ua.Bindings.Https` gated `#if NET8_0_OR_GREATER` with no new dependencies, while the raw-socket `TcpTransportListener` stays in `Opc.Ua.Core` for trimmed/AOT deployments. The key technical fix was overriding `StartReceiveLoop` in `TcpReverseConnectChannel` to do a one-shot `ReverseHello` read — `WebSocket.ReceiveAsync(CancellationToken)` aborts the socket on cancellation, which previously broke the WSS handoff. See [Docs/Transports.md](https://github.com/OPCFoundation/UA-.NETStandard/blob/httpwssbindingfollowups/Docs/Transports.md) and [Docs/ReverseConnect.md](https://github.com/OPCFoundation/UA-.NETStandard/blob/httpwssbindingfollowups/Docs/ReverseConnect.md). ## OPC UA Web API binding (Part 6 §G.3) All **28 services** from `opc.ua.openapi.allservices.json` are mapped at the spec routes (`/findservers`, `/getendpoints`, `/createsession`, `/read`, `/write`, `/browse`, `/call`, `/publish`, …) on ASP.NET Core Minimal-API endpoints. Both `application/json; encoding=compact` (mandatory per Part 6 §5.4.9) and `encoding=verbose` are supported via media-type negotiation. The implementation is **NativeAOT-compatible** — each route binds to a static `RequestDelegate` thunk that calls a generic instantiation of `WebApiEndpointDispatcher.HandleAsync<TRequest, TResponse>` with zero MVC reflection and no `[UnconditionalSuppressMessage]` (`<IsAotCompatible>true</IsAotCompatible>` is clean of `IL2xxx` / `IL3xxx` warnings on net10). NodeManagement (§5.8) and Query (§5.10) are deliberately omitted per the spec doc. New profile URIs `Profiles.HttpsOpenApiTransport` (profile/2338) and `Profiles.WssOpenApiTransport` (profile/2339) are emitted as discovery twins on every SM=None HTTPS / WSS endpoint. Naming follows the [OPC Foundation UA-WebApi-StarterKit](https://github.com/OPCFoundation/UA-WebApi-StarterKit). Full developer guide in [Docs/WebApi.md](https://github.com/OPCFoundation/UA-.NETStandard/blob/httpwssbindingfollowups/Docs/WebApi.md). ## Authentication, WSS sub-protocol, symmetric client Four pluggable auth modes wire through `OpcUaWebApiAuthenticationBuilderExtensions`: **Anonymous**, **Bearer (OIDC/JWT)** with a built-in `JwtClaimSessionlessIdentityProvider` that projects `sub` / `scope` / `roles` onto `IUserIdentity`, **Basic**, and **Mutual TLS**. A policy scheme (`WebApiAuthSchemes.Default`) becomes the default authenticate/challenge/forbid scheme so `UseAuthentication()` populates `HttpContext.User` even with multiple handlers registered; every route carries `RequireAuthorization()` except `/findservers` and `/getendpoints` which keep `AllowAnonymous` per the spec. The **WSS `opcua+openapi` sub-protocol** (profile/2339) is accepted in two forms — bare and `opcua+openapi+<accesstoken>` (bearer rides in the sub-protocol name because browser WebSocket APIs forbid custom headers, per Part 6 §7.5.2) — and the token is validated against the registered JwtBearer scheme **before** the upgrade completes; cleartext `ws://` bearer upgrades are rejected on both server and client. A symmetric **C# client** (`Libraries/Opc.Ua.Client/WebApi`) provides `IWebApiClient` / `WebApiTransportChannel` / `WebApiWssTransportChannelFactory` so `Session`, `ManagedSession`, and the V2 `SubscriptionManager` all dispatch unchanged; fluent shortcuts `ManagedSessionBuilder.UseWebApiEndpoint(url, encoding)` and `UseWssOpenApiEndpoint(url, encoding)` are wired in. ## Edge security hardening A targeted audit against OPC UA Part 2/4/6 + Microsoft SDL drove **fail-closed** defenses across every new surface. TLS server-cert validation in both `WebApiTransportChannel` and `WebApiWssTransportChannel` delegates to the OPC UA `CertificateValidator` (with the default .NET TLS chain check as fall-back), mirroring `HttpsTransportChannel`. WSS bearer tokens are validated before upgrade; empty-password identity-token fallbacks were removed from `DefaultSessionlessIdentityProvider` and `JwtClaimSessionlessIdentityProvider`, with the upstream principal now flowing via the new `SecureChannelContext.UpstreamIdentity`. `WebApiBodyCodec.DecodeBodyAsync` enforces `MaxMessageSize` during the read (BadRequestTooLarge before allocation), and both server and client WSS receive loops reject zero-byte continuation frames. On the base-branch side, `JsonRequestMapper.ReadAllBoundedAsync` bounds JSON/binary reads, HTTPS / WSS handlers fail-closed on missing SM=None JSON endpoints (BadSecurityPolicyRejected, restrict-to-discovery), and `WebSocketByteTransport` carries the same zero-progress guard for `opcua+uacp`. ## Testing, docs, scope Approximately **300 new passing net10 tests**: 107 in `Opc.Ua.Core.Tests` (codec, media type, route table, profile constants), 153 in `Opc.Ua.Bindings.WebApi.Tests` (endpoint dispatcher, auth handlers, TLS regression, mTLS source-pin, body-size, zero-progress, identity plumbing, bearer validation), 29 reference-server integration tests in `Opc.Ua.Sessions.Tests` (HTTPS WebApi, WSS OpenAPI, WSS reverse-connect, Kestrel-TCP, shared host), and 7 `Opc.Ua.Aot.Tests` round-trips on the natively-compiled binary. Full multi-TFM `dotnet build UA.slnx` is clean. Docs updated: [Transports](https://github.com/OPCFoundation/UA-.NETStandard/blob/httpwssbindingfollowups/Docs/Transports.md), [WebApi](https://github.com/OPCFoundation/UA-.NETStandard/blob/httpwssbindingfollowups/Docs/WebApi.md), [ReverseConnect](https://github.com/OPCFoundation/UA-.NETStandard/blob/httpwssbindingfollowups/Docs/ReverseConnect.md), [Profiles](https://github.com/OPCFoundation/UA-.NETStandard/blob/httpwssbindingfollowups/Docs/Profiles.md), [MigrationGuide](https://github.com/OPCFoundation/UA-.NETStandard/blob/httpwssbindingfollowups/Docs/MigrationGuide.md), [NativeAoT](https://github.com/OPCFoundation/UA-.NETStandard/blob/httpwssbindingfollowups/Docs/NativeAoT.md). Out of scope (tracked as follow-ups): own-listener hosting mode for Web API, source generation of extended complex types not exercised by the 28 services, load-testing harness, `MatchEndpoints` honouring user `TransportProfileUri` on `UpdateFromServer`, rate limiting on the long-poll `/publish` path, and a richer first-class `UpstreamPrincipal` model. ## Related issues - Closes the follow-up scope of #3876 (WSS transport) - Closes the follow-up scope of #3877 (HTTPS-JSON transport) - Supersedes #3882 (folded in via fast-forward push of `openapi` → `httpwssbindingfollowups`) |
||
|
|
208c601b09 |
Fix weekly all-TFM UA.slnx build (net8/net9 + netstandard) and add Windows/Linux all-TFM CI build jobs (#3913)
The OPC UA stack builds for seven target frameworks (net472, net48, netstandard2.0, netstandard2.1, net8.0, net9.0, net10.0), but our regular pull-request builds only compile two of them (net10.0 and net48). The complete per-framework build runs only in a weekly scheduled Azure job, so when a change breaks one of the other frameworks nobody notices for days. That is exactly what happened in build 14931, which was red on net8.0, net9.0, netstandard2.0 and netstandard2.1. This PR fixes all of those broken frameworks. The fixes are small and framework-specific: a net10.0-only test project reference is made conditional so net8.0/net9.0 can build, a set of "legacy-stripped" project shells that failed to compile as empty netstandard assemblies now build as net10.0, and a few polyfill and NuGet-package collisions in the netstandard2.1 build are resolved by building its test/app projects as net8.0 and pinning the matching MQTTnet version. After these changes, `dotnet build UA.slnx` succeeds cleanly for every framework. To stop this from regressing, the PR adds two CI jobs that run on every pull request, in parallel with the existing unit tests: one on Windows that builds the .NET Framework targets (net472, net48, netstandard2.0) and one on Linux that builds the modern .NET and netstandard2.1 targets (net8.0, net9.0, net10.0, netstandard2.1). Together they cover all seven frameworks and fail the PR if any single one won't build. The workflow's trigger list was also widened so these jobs run when only build or configuration files change (for example `*.props` or `*.targets`), not just C# source. This PR supersedes #3912 and folds in its fixes. |
||
|
|
44355a4c38 |
Fix client user-cert selection: curve-aware match + client-enabled-policy filter (#3891)
# Description X509ClientIdentityProvider previously accepted any `UserTokenPolicy` whose `TokenType` was `Certificate`, then narrowed by `HasSameEncryptionAlgorithm` which only checked `IsEccPolicy` parity. An ECC user cert could therefore satisfy a policy of any ECC curve (e.g. a NistP256 cert silently authenticating against a NistP384 policy), and policies the client had disabled in `SecurityConfiguration.SupportedSecurityPolicies` were silently used as long as the cert "looked compatible". This PR makes user-cert selection curve-aware and filters offered policies against the client's enabled set, with rich diagnostics on failure. ## What changed **API (v2.0-only, not yet shipped — no `[Obsolete]` shim):** - `IClientIdentityProvider.CanSatisfy(...)` → `CanSatisfyAsync(...)` returning a new `CanSatisfyResult` (bool + rejection reason). Sync-over-async would have been required for the X.509 provider to load the cert during selection — repo rules forbid this, so the contract is async end-to-end. - `IdentitySelectionContext` gained `EnabledSecurityPolicyUris` (init-only). The 3-arg ctor and the 2-arg `AcquireIdentityAsync` extension default this to `Array.Empty<string>()` (no filter) so existing callers keep their pre-PR behaviour. The 4-arg ctor is the explicit opt-in. - `SelectUserTokenPolicy` → `SelectUserTokenPolicyAsync`. **Curve-aware X.509 selection (`X509ClientIdentityProvider`):** - Loads the user cert once via `ICertificateProvider.GetPrivateKeyCertificateAsync` (cached lock-free via `Interlocked.CompareExchange`; load failures are NOT cached so transient errors / cert provisioning / rotation are retried). - Maps the public key to `CertificateKeyAlgorithm` (RSA / NistP256 / NistP384 / BrainpoolP256r1 / BrainpoolP384r1) by inspecting `Certificate.GetKeyAlgorithm()` and `PublicKey.EncodedParameters`. - Accepts a policy only when `SecurityPolicies.GetInfo(uri).CertificateKeyAlgorithm` matches the cert. Empty `SecurityPolicyUri` inherits the channel policy. `SecurityPolicies.None` imposes no constraint. Unknown / platform-unsupported policy URIs are rejected with `UnknownOrUnsupportedSecurityPolicy`. **Client-enabled-policy filter (`SelectUserTokenPolicyAsync`):** - Before delegating to `CanSatisfyAsync`, drop any offered `UserTokenPolicy` whose non-empty `SecurityPolicyUri` is not in `EnabledSecurityPolicyUris` (`NotEnabledByClient`). Applies to RSA / UserName / IssuedToken too, so deprecated policies (e.g. `Basic128Rsa15`) cannot be picked accidentally. **Aggregated diagnostics:** - When no policy is selectable, the `BadIdentityTokenRejected` exception lists every offered policy (PolicyId / TokenType / SecurityPolicyUri / IssuedTokenType) with its rejection reason — `NotEnabledByClient`, `TokenTypeNotSupported`, `IssuedTokenProfileNotSupported`, `CertificateAlgorithmMismatch` (with cert and policy algorithm names), `CertificateLoadFailed` (with cert subject/thumbprint), `UnknownOrUnsupportedSecurityPolicy`, `ProviderRejected` — plus the client's enabled-policy set. `CompositeClientIdentityProvider` aggregates child reasons. **Plumbing:** - `Session.cs` passes `Configuration.SecurityConfiguration.SupportedSecurityPolicies` into the context (falling back to `[channel]` only when the configuration is unset). - `AnonymousIdentityProvider`, `UserNamePasswordIdentityProvider`, `IssuedTokenIdentityProvider`, `CompositeClientIdentityProvider` updated to the async API; trivial providers wrap the existing logic in `ValueTask.FromResult` plus a reason string when rejecting. ## Tests - 4 existing test files updated for the async API. - New `X509ClientIdentityProviderSelectionTests.cs` (7 tests): - RSA cert prefers RSA policy over offered ECC policy. - NistP256 cert prefers `ECC_nistP256` policy over `ECC_nistP384`. - NistP384 cert with only `ECC_nistP256` offered → `BadIdentityTokenRejected` with `CertificateAlgorithmMismatch` (mentions both algorithms). - Disabled policy in offered set → `NotEnabledByClient` in diagnostic message. - With multiple offered policies, the enabled filter prefers the enabled one. - Cert load failure → `CertificateLoadFailed` with cert subject in the diagnostic. - Unsupported token type → `TokenTypeNotSupported` in diagnostic. `dotnet test` against `net10.0` for the Identity + ClientBuilder categories: 43/43 pass. `Opc.Ua.Core`, `Opc.Ua.Client`, `Opc.Ua.Server`, `Applications/ConsoleReferenceClient` all build clean. ## Related Issues _No tracking issue; this addresses a class of OPC UA client misbehaviour (curve confusion / silent acceptance of disabled policies) discovered during user-cert authentication review._ ## 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. |
||
|
|
1c312e5559 |
Fix #3546: re-enable FuzzCrashAssets and harden BinaryDecoder (#3884)
# Description Two coordinated fixes that close issue #3546 and remove the CI gap that allowed the regression to slip past `dotnet test`: 1. **`BinaryDecoder` hardens matrix-dimension handling** `Stack/Opc.Ua.Types/Encoders/BinaryDecoder.cs` — wraps the matrix-construction switch in `ReadVariantValue` (all 24 BuiltInType cases) and both `ReadEncodeableMatrix<T>` overloads in a try/catch that converts the deliberate `ArgumentException` thrown by `MatrixOf<T>(values, dimensions)` validation (overflow / negative / length-mismatch) into a `ServiceResultException(BadDecodingError)`. Attacker-controlled wire dimensions now flow through the standard decoder rejection channel instead of escaping as an unhandled exception. The `MatrixOf<T>` ctor validation itself (security hardening at `MatrixOf.cs:178-217`) is unchanged. 2. **`FuzzCrashAssets` is now assertive** `Fuzzing/Common/Fuzz.Tests/FuzzTargetTestsBase.cs` — replaces silent log-and-count with `Assert.That(failures, Is.Empty, …listing failed assets)`. CI now breaks loud the moment a residual `Assets/crash-*` reproduces on any target. `.github/agents/fuzz-tester.agent.md` doc note rewritten to match. The originally reported "DataTypeNode / VariableNode `IsEqual` non-determinism" symptom turned out to already be implicitly resolved by the modern `Equals` overhaul (`ArrayOf<T>` value-equality, `ExtensionObject.Equals` deep-compare, `IEquatable<T>` on `ReferenceNode` / `RolePermissionType`). The 8 new synthetic round-trip tests + 6 permanent corpus seeds confirm this end-to-end. ## Regression coverage * `Tests/Opc.Ua.Types.Tests/Encoders/BinaryDecoderTests.cs` — 3 new tests lock in the `BadDecodingError` contract for malformed matrix dimensions (overflow, negative, length-mismatch). * `Fuzzing/Opc.Ua.Encoders.Fuzz.Tests/Issue3546RoundTripTests.cs` — 8 synthetic round-trip tests for populated `DataTypeNode` and `VariableNode`, exercising the implicated fields (non-empty References, RolePermissions, `DataTypeDefinition` ExtensionObject body, `Value` Variant carrying ExtensionObject, `ArrayDimensions` empty / null / non-empty). * `Fuzzing/Opc.Ua.Encoders.Fuzz.Tools/Encoders.Testcases.cs` + `Fuzzing/Opc.Ua.Encoders.Fuzz.Corpus/Testcases.{Binary,Json,Xml}/` — `DataTypeNodeMessage` / `VariableNodeMessage` seed generators plus 6 generated corpus files. These feed `FuzzGoodTestcases` automatically on every test run. ## Verification | Suite | TFM | Result | |---|---|---| | `Opc.Ua.Encoders.Fuzz.Tests` | net10.0 | **4625** / 0 | | `Opc.Ua.Encoders.Fuzz.Tests` | net48 | **4625** / 0 | | `Opc.Ua.Types.Tests` (BinaryDecoder / Matrix / Variant / EncodeableMatrixRoundTrip subset) | net10.0 | **985** / 0 | The single pre-existing `Assets/crash-0483107a22caf892cff4f795c96ab14c581a8f55` no longer escapes any fuzz target — the matrix-dimensions fix turns it into a clean parser-rejected input. ## Related Issues - Fixes #3546 ## 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 the affected tests locally (`Opc.Ua.Encoders.Fuzz.Tests` on net10.0 + net48, targeted `Opc.Ua.Types.Tests` subset on net10.0); full UA.slnx still pending CI. - [ ] I fixed **all** failing and flaky tests in the CI pipelines and **all** CodeQL warnings. - [ ] I have addressed **all** PR feedback received. |
||
|
|
f358078b1c |
[Client] Central channel manager: ref-counted shared channels, coalesced reconnect, IRetryBudget (#3288) (#3852)
# Description Introduces a central `IClientChannelManager` that owns client-side transport channels with reference counting, sharing, coalesced reconnect, and asynchronous participant notification. Sessions, discovery clients, and registration clients targeting the same `ConfiguredEndpoint` (with the same reverse-connect identity) now share a single underlying `ITransportChannel`; reconnect is transparent to callers; and the previous `AttachChannel`/`DetachChannel` + `SessionReconnectHandler` patterns are obsoleted. ## What lands ### Core types (`Stack/Opc.Ua.Core/Stack/Client/`) - `ManagedChannelKey`, `ChannelState`, `ChannelStateChange`, `ParticipantReconnectResult` - `IReconnectParticipant`, `IManagedTransportChannel`, `IClientChannelManager` - `IChannelReconnectPolicy` + `ExponentialBackoffChannelReconnectPolicy` (default mirrors historical `SessionReconnectHandler`: 500 ms → 30 s exponential) - `IRetryBudget` + `RetryBudget` — shared retry deadline so the two-level retry no longer compounds multiplicatively - `ClientChannelManager` — single non-partial sealed class with SOLID-extracted internal types under `Stack/Opc.Ua.Core/Stack/Client/Channels/Internal/`: `ChannelEntry` (behind `IChannelEntryHost`), `ManagedTransportChannelLease`, `ClientChannel`, `ClientChannelManagerMetrics` (IMeter), `ClientChannelManagerCertRotation` (auto `ReconnectAllAsync` on `CertificateManager` rotation), `ClientChannelManagerDiagnostics` (ActivitySource + EventSource). Refcount, coalesced reconnect, and transparent faulted-entry recovery via `SwapFaultedEntryAsync` (swaps a lease's underlying entry on subsequent `ReconnectAsync` when the prior cycle Faulted/Closed, preserves participant, back-off via policy `GetDelay(SwapCount)`) ### Three-state lifecycle gate `Disconnected` → `TransportConnecting` / `TransportReconnecting` → `TransportConnectedSessionReactivating` → `Ready` (or `Faulted` / `Closed`). Only `Ready` releases the service-call gate; the manager bypasses the gate internally for participant `ActivateSession` traffic during reactivation via an `AsyncLocal` scope. ### Session integration (`Libraries/Opc.Ua.Client/Session/`) - New `Session.CreateAsync(IClientChannelManager, …)` overload - `Session` implements `IReconnectParticipant`; reactivation handler distinguishes `Reactivated` / `RequiresSessionRecreate` / `TransientFailure` / `FatalForParticipant` / `FatalForChannel` - `Session.ReconnectAsync(ct)` automatically delegates to the channel manager when wired - `Session.RecreateInPlaceAsync` swaps managed-channel leases for failover-to-different-endpoint via a new atomic `IClientChannelManager.GetAsync(endpoint, participantFactory, …)` overload; same-key recreates delegate to manager reconnect; explicit-channel/connection callers retain legacy behavior - KA failure routes through `IClientChannelManager.ReconnectAsync(channel)` ### ManagedSession integration - `WithChannelManager(...)` builder + ctor param; DI-resolved automatically - Two-level retry: channel-mgr handles transparent reconnect; outer `ConnectionStateMachine` + `IReconnectPolicy` only triggers on terminal channel `Faulted`. Outer-state churn suppressed during channel-mgr cycles via `_channelReconnectInProgress` flag wired through `IManagedTransportChannel.StateChanged` - New `ManagedSession.ChannelStateChanged` event surfaces transparent reconnects - `ConnectionStateChangedEventArgs.UnderlyingChannelState` populated when outer reconnect was triggered by a channel fault - Shared `IRetryBudget` propagated so the layers enforce a single max-total-time ### Discovery / Registration / GDS Channel-manager-aware `CreateAsync` overloads on `DiscoveryClient`, `RegistrationClient`, `ServerPushConfigurationClient`, `LocalDiscoveryServerClient`, `GlobalDiscoveryServerClient`. Each registers a minimal `IReconnectParticipant`; co-located sessions and discovery probes targeting the same endpoint share a channel. ### HTTPS transport (`Stack/Opc.Ua.Bindings.Https/`) - New `IOpcUaHttpClientFactory` abstraction - HTTPS / OPC-HTTPS channels migrated to `IHttpClientFactory` + `Microsoft.Extensions.Http.Resilience` (10.6.0; AOT-compatible on net10 via source generators; legacy direct-HTTP path retained for older TFMs / no-DI consumers) ### DI `AddOpcUa().AddClient(...)` registers `IClientChannelManager` and the named HTTPS `HttpClient` + standard resilience handler automatically. `ManagedSessionBuilder` resolves the manager from DI when present. ### Obsoletions (functional, `[Obsolete]` with guidance) - `IClientBase.AttachChannel` / `DetachChannel` - `SessionReconnectHandler` - `SessionExtensions.ReconnectAsync(connection, ct)` and `(channel, ct)` legacy overloads ### Tests - Core: `ClientChannelManagerManagedTests`, `ClientChannelManagerCertRotationTests`, `RetryBudgetTests`, `OpcUaHttpClientFactoryTests` — **56 / 56 pass** - Client: `ManagedSession*Tests` updated; legacy `SessionReconnectHandlerTests` + `SessionExtensionsTests` preserved with `#pragma warning disable CS0618` — **129 / 129 pass** - Sessions integration: `ChannelManagerSharing` / `TransparentReconnect` / `SessionLifecycle` / `CertRotation` — **7 pass, 1 skipped** (`ChannelManagerExhaustionEscalatesAndRecoversWhenServerReturns` un-`[Ignore]`d and implemented in this PR via `SwapFaultedEntryAsync`; remaining skip is end-to-end `RequiresSessionRecreate` plumbing — carry-forward) - Stress (consolidated `Tests/Opc.Ua.Stress.Tests/Subscriptions/` + `Channels/`): chaos / contract / soak / lifecycle / leak-accuracy / gap / participant-result-aggregation tests merged from the previously-separate `Opc.Ua.Channels.Stress.Tests` project; nightly run via `.github/workflows/stress-test.yml` Builds clean (0 warnings / 0 errors) across all six TFMs: `net472`, `net48`, `netstandard2.1`, `net8.0`, `net9.0`, `net10.0`. ### Docs - `Docs/Sessions.md` new § 4 documents the channel manager, three-state gating, two-level retry with shared `IRetryBudget`, HTTPS resilience layering - `Docs/MigrationGuide.md` migration recipes for the four obsoleted API groups - `Docs/DependencyInjection.md` channel-manager and HTTPS factory registration ## Carry-forward (separate PRs) - End-to-end `ParticipantReconnectResult.RequiresSessionRecreate` → `Session.RecreateAsync` lifecycle wiring (currently incomplete — flagged in the 1 remaining skipped integration test) ## Related Issues - Fixes #3288 - Builds on #3282 (PR that introduced the initial `ITransportChannelManager` skeleton) ## 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. *(Channel-manager-specific tests + ManagedSession/client tests verified across all 6 TFMs; full UA.slnx run is pending CI.)* - [ ] I fixed **all** failing and flaky tests in the CI pipelines and **all** CodeQL warnings. - [ ] I have addressed **all** PR feedback received. |
||
|
|
7728b65e8d | CI: Fix pipeline cannot be cancelled regression and flaky tests (#3872) | ||
|
|
4e6c3303dd |
Add V2 subscription triggering (SetTriggering) with N:M support and recreate replay (#3854)
# Description Adds **triggered-item (SetTriggering) support to the V2 (modern) subscription engine** with a hybrid API, batched apply pipeline, and automatic replay on recreate/reconnect — closing the gap from #3834 and adding store/load round-trip for triggering relationships. ## Public API | Concern | Surface | |---|---| | Declarative | `MonitoredItemOptions.TriggeredByNames` (`IReadOnlyList<string>`) — set at item-add time | | Imperative | `ISubscription.SetTriggeringAsync(IMonitoredItem triggeringItem, IReadOnlyCollection<IMonitoredItem>? linksToAdd, IReadOnlyCollection<IMonitoredItem>? linksToRemove, CancellationToken ct)` returning `SetTriggeringResult` with per-link statuses | | Fluent helpers | name-based overloads `SetTriggeringAsync(this ISubscription, string triggeringItemName, params string[] triggeredItemNames)` (and `add`/`remove`/`ct` variant) | | N:M navigation | `IMonitoredItem.TriggeringItems` (items that trigger this) and `IMonitoredItem.TriggeredItems` (items I trigger), both on-demand projections | | Result type | `public sealed record SetTriggeringResult(IMonitoredItem TriggeringItem, IReadOnlyList<(IMonitoredItem Item, StatusCode Status)> AddResults, IReadOnlyList<(IMonitoredItem Item, StatusCode Status)> RemoveResults, StatusCode ServiceResult)` | No client handles surface on the public API. Validation in the imperative path is by **reference identity** under the manager lock — items from a different subscription with a matching name cannot sneak through, and a removed-then-re-added item with the same name does not silently re-target. ## Engine — batched apply A new manager-level operations queue + a batched apply step in `MonitoredItemManager.ApplyMonitoredItemChangesAsync`: 1. After Create / Modify / SetMonitoringMode, drain the operations queue. 2. Group by triggering item (reference identity). 3. Re-queue ops whose triggering item is not yet `Created` (bounded by `MaxTriggeringRetryCount`; permanently failed items propagate the create-failure status to the operation TCS). 4. Fold per-edge across operations targeting the same triggering item — last-intent wins; same-edge add+remove resolves to one net operation. 5. Pre-resolve: triggered items with `Created=false` resolve to `Bad_MonitoredItemIdInvalid` (adds) or `Good` no-op (removes, per Part 4 §5.13.1.6 server auto-cleanup). 6. Issue **one `SetTriggering` RPC per triggering item** carrying both `linksToAdd` and `linksToRemove` (the server processes remove before add per §5.13.5.2 — atomic swap semantics). 7. Map per-link results back to contributing operations; complete each TCS with its own `SetTriggeringResult` subset. Imperative writes mutate the per-item runtime `DesiredTriggeredByNames` synchronously so navigation (`TriggeringItems`/`TriggeredItems`) and `Snapshot()` reflect intent before the RPC fires. Per-link failures roll back the optimistic mutation so the client view matches server reality. ## State ownership `MonitoredItemOptions.TriggeredByNames` is the **initial declarative input**. The canonical runtime source of truth is a per-item `DesiredTriggeredByNames` field, initialized from options and mutated by both the imperative API and subsequent options changes. The field is preserved across `Reset` (recreate path), which is what enables automatic SetTriggering replay after recreate. ## Save / load (closes #3834) - `MonitoredItemStateSnapshot.TriggeredByNames` (`ArrayOf<string>`) replaces the old `TriggeringItemClientHandle` field (V2-only — not yet shipped, so a clean break; classic snapshot format unchanged). - `Snapshot()` reads from runtime `DesiredTriggeredByNames`; `ApplyLoadState` writes loaded names into both options and runtime state without leaking through the OnChange tracker. - **TransferSubscriptions** success path: only the local view is restored — trusting the spec (`§5.13.5`) that servers preserve triggering links across subscription transfer. No SetTriggering RPC is issued. - **Recreate-fallback** (transfer rejected), **in-session `RecreateAsync`**, and **Reconnect** paths: `Reset` preserves `DesiredTriggeredByNames` and enqueues an add-delta per preserved triggering name; the batched apply pass replays SetTriggering after items finish (re)creating. ## Error handling Per OPC UA Part 4 §5.13.5.3/§5.13.5.4 (Tables 73/74): | Condition | Engine response | |---|---| | Per-link `Bad_MonitoredItemIdInvalid` | Surfaced in `SetTriggeringResult.AddResults`/`RemoveResults`; optimistic `DesiredTriggeredByNames` mutation rolled back | | Service-level `Bad_SubscriptionIdInvalid` | Operations re-queued, not terminal — replays after the subscription state machine recreates | | Service-level `Bad_TooManyOperations` | Surfaced as `ServiceResultException` to all contributing TCSs (no auto-chunking in this version) | | Triggering item never reaches `Created` | After `MaxTriggeringRetryCount` re-queues, op completes with the triggering item's propagated error (no infinite loop) | | Communication errors | Routed through the existing retry policy with bounded retry count | ## Spec consultation Cross-checked against **OPC UA Part 4 v1.05.07 §5.13.5** (verified Table 73 / Table 74 directly via the OPC Foundation spec site) and §5.13.1.6 (deletion side-effects, monitoring-mode interactions). The only per-link spec-specific status code is `Bad_MonitoredItemIdInvalid`; `linksToRemove` is processed server-side before `linksToAdd` (driving the single-RPC-per-trigger batch shape). ## Tests - **9 new unit tests** in `MonitoredItemManagerTriggeringTests.cs` (single op, multi-op merge into one RPC, per-trig grouping, requeue-when-not-Created, per-link rollback, `Bad_SubscriptionIdInvalid` recovery, deletion races, last-intent same-edge conflict resolution). - **Updated** integration tests `SetTriggeringTrackingV2Async` and `SnapshotCapturesTriggeringForReplayAsync` to use the new API. - **2 new integration tests** in `SubscriptionTests.cs`: `DeclarativeTriggeredByNamesV2Async` (options-driven path end-to-end) and `NToMTriggeringV2Async` (one triggered item linked to two trigger items, per-link removal). - **AOT smoke test** in `SubscriptionAotTests.cs` for the `MonitoredItemStateSnapshot.TriggeredByNames` binary encoder/decoder round-trip. - All **344 V2 subscription/monitored-item unit tests** and **71 V2 subscription integration tests** pass locally (net10). ## Documentation - New: `Docs/Subscriptions.md` — *Subscriptions and Monitored Items Service Set*. Merges the previous `StreamingSubscription.md` and `SubscriptionTriggering.md` into a single guide; leads with a Classic-vs-V2 engine overview (recommending V2 for new code) and links to `Sessions.md` §4 for the full engine comparison. Covers the V2 callback API, declarative + imperative SetTriggering with N:M, save/load/restore behavior, error handling, and the `IStreamingSubscription` async-enumerable surface. - Updated: `Docs/README.md`, `Docs/AlarmsAndConditions.md`, `Docs/StateMachines.md`, `Docs/Profiles.md` — all point to the new merged doc. - Updated: `plans/26-v2-subscription-parity.md` — rows 49 (`SetTriggeringAsync`) and 111 (`TriggeringItems` plural / `TriggeredItems`). ## Related Issues - Fixes #3834 — `TransferSubscription does not automatically restore/retain links between trigger and monitored items`. The fix is two-pronged: (a) transfer preserves links server-side per spec and the client snapshot captures `TriggeredByNames` so the local view restores automatically; (b) when transfer fails and the engine falls back to recreate (or when `RecreateAsync` is invoked explicitly), `Reset` enqueues per-triggering-name add-deltas from the preserved runtime state and the batched apply pass replays `SetTriggering` after re-creation. ## 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. - [ ] I have addressed **all** PR feedback received. |
||
|
|
a81d981755 |
dotnet format sweep (whitespace, IDE, RCS) + code-style enforcer agent fix (#3865)
# Description
Pure code-style sweep across the repo — no behavioral changes. Drives
`dotnet format` info-level diagnostics down on a large slice of the
codebase (Stack, Libraries, Tests, Tools).
Six commits, applied bottom-up in safety order so each batch leaves the
build green:
1. **`style: fix whitespace and final-newline formatting (WHITESPACE,
FINALNEWLINE)`**
197 hits across ~30 files; pure mechanical cleanup.
2. **`style: apply dotnet format style fixes (IDE rules)`**
IDE-rule batch via `dotnet format style --severity info` —
`var`/explicit type, simplify names, collection expressions, expression
bodies, unused usings, etc.
3. **`style: apply dotnet format analyzers fixes (RCS blank-line
formatting)`**
Roslynator formatting (RCS0xxx) blank-line and punctuation rules.
4. **`style: convert comments to doc comments and inline local vars
(RCS1181, RCS1124)`**
24 files. RCS1181 promotes `// summary`-style comments above
public/internal members to `/// <summary>` doc comments; RCS1124 inlines
locals used exactly once. Generated `Tools/` files were reverted to keep
the source-generator outputs deterministic.
5. **`docs(agent): correct --diagnostics flag form and verify Roslynator
4.x code fixers`**
Updates `.github/agents/opc-ua-codestyle-enforcer.agent.md` with two
corrections discovered while running this sweep:
- `dotnet format --diagnostics "RULE1 RULE2"` (single quoted,
space-separated) silently fixes nothing on `dotnet format` 10.x — it
parses as one unknown ID and exits 0. The correct form is `--diagnostics
RULE1 --diagnostics RULE2 …`, repeated per rule.
- Roslynator 4.15.0 **does** ship code fixers for
RCS1078/1118/1124/1140/1142/1181/1221/1260 (the previous "no auto-fixer"
list was outdated). RCS1140/1142 default to `Hidden` so need `--severity
info` to surface and fire; RCS1078 requires
`roslynator_empty_string_style = field` (already set in
`.editorconfig`). Only NUnit4002/2046/2010 genuinely lack auto-fixers in
this stack.
6. **`style: format new code from master merge (dotnet format sweep)`**
After merging master into the branch (commit `e3ebc8742`), re-ran the
same three-phase format sweep on the 151 .cs files brought in by the
merge, scoped per project via repeated `--include`. 81 files changed;
same rule families as commits 1–4.
- Hand-fixed `Tests/Opc.Ua.MigrationAnalyzer.Tests/AnalyzerHarness.cs`
for `RCS1174` (redundant `async`/`await` removal) because the auto-fixer
didn't apply for that specific case.
- Reverted files that the formatter would break:
- `Libraries/Opc.Ua.Server/Server/ServerInternalData.cs` — multi-TFM
analysis disagreement injected `<<<<<<<` / `=======` / `>>>>>>>`
markers.
-
`Tools/Opc.Ua.MigrationAnalyzer.Core/{Core/Stack/Client/ChannelBase.cs,
Core/Stack/Types/IUserIdentityTokenHandler.cs,
Client/Session/Session.cs}` — IDE0005 removed `using
Opc.Ua.Security.Certificates` that IS used (the files are 1.5.378
reference fixtures for the analyzer).
- `Tests/Opc.Ua.Gds.Tests/PushTest.cs` — IDE0002 over-simplified
`OpcUa.ObjectTypeIds` to `ObjectTypeIds`, which then resolves to a
conflicting type.
### What this PR does **not** touch
- No behavioral or semantic logic changes.
- No `.editorconfig` rule promotions (rules stay at their current
severities; this is a backlog-burndown pass, not a rule tightening).
- Generated source under `Tools/` is intentionally excluded.
- Higher-risk rule families (`RCS1090`/`CA2007` `ConfigureAwait`,
`RCS1249` null-forgiving cleanup, `IDE0270`/`IDE0059`) are left for
follow-up sweeps because they need per-TFM build verification or
semantic review.
## Related Issues
_No tracking issue — this is a non-functional style sweep and the
agent-doc correction is a follow-up to the same work. Happy to open one
if the maintainers prefer._
## 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. _(N/A — style-only, no
behavioral change)_
- [x] I have added all necessary documentation. _(agent doc updated with
the two corrections)_
- [x] I have verified that my changes do not introduce (new) build or
analyzer warnings. _(verified clean on `net10.0` and `net48`; only
pre-existing `NETSDK1005`/`NETSDK1207` failures on Tools/AOT projects)_
- [ ] I ran **all** tests locally using the **UA.slnx** solution against
at least .net **framework** and .net **10**, and all passed. _(build
verified on net10 and net48 per batch; full test suite not yet run
locally — relying on CI)_
- [ ] 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: agent <agent@local>
|
||
|
|
2966f693b2 |
2.0 Migration Analyzer and codefixer with Agent update (#3820)
Introduces `OPCFoundation.NetStandard.Opc.Ua.MigrationAnalyzer` — a single NuGet package that ships **three Roslyn components + a runtime shim** to make the 1.5.378 → 2.0 upgrade as close to "install package, run `dotnet format`, remove package" as possible: | DLL | Where | Purpose | |-----|-------|---------| | `Opc.Ua.MigrationAnalyzer.dll` | `analyzers/dotnet/cs/` | 19 Roslyn analyzers (`UA0001`–`UA0022`) covering every breaking-change pattern in [`Docs/MigrationGuide.md`](https://github.com/OPCFoundation/UA-.NETStandard/blob/master/Docs/MigrationGuide.md). Built against the stable Roslyn 4.14 analyzer API — loads cleanly in csc.exe (no `Microsoft.CodeAnalysis.Workspaces` reference). | | `Opc.Ua.MigrationAnalyzer.CodeFixer.dll` | `analyzers/dotnet/cs/` | 14 companion `CodeFixProvider`s; loaded only by Workspaces-aware hosts (Visual Studio, `dotnet format analyzers`). | | `Opc.Ua.MigrationAnalyzer.Generator.dll` | `analyzers/dotnet/cs/` | Roslyn `IIncrementalGenerator` that emits per-consumer `internal sealed [Obsolete] class <Name>Collection : List<TElement>` shims for every `<Type>Collection` wrapper the consumer references — including **arbitrary model-compiled `<UserType>Collection` patterns**, not just the 30 well-known built-in ones. | | `Opc.Ua.MigrationAnalyzer.Core.dll` | `lib/<tfm>/` for `net472, net48, netstandard2.1, net8.0, net9.0, net10.0` | 1.5.378 → 2.0 runtime compatibility shim. Re-exposes the obsolete extension surface so 1.5.378-style call sites keep compiling against 2.0 with warnings instead of errors. | ### Migration workflow the package enables 1. **Bump every `OPCFoundation.NetStandard.Opc.Ua.*` PackageReference to `2.0.*-*`.** 2. **Add the migration package** as a build-only dependency: ```xml <PackageReference Include="OPCFoundation.NetStandard.Opc.Ua.MigrationAnalyzer" Version="2.0.*-*" PrivateAssets="all" /> ``` 3. **Run `dotnet build`.** The Core shim DLL re-supplies obsolete extension members; the source generator covers `<Type>Collection` references; what remains are `[Obsolete]` warnings + `UA00xx` analyzer diagnostics + (occasionally) `MIG01` for unresolvable model-compiled element types. 4. **Apply auto-fixes** in the IDE or from the command line: ```bash dotnet format analyzers <solution>.sln \ --diagnostics UA0002 UA0003 UA0004 UA0005 UA0006 UA0007 UA0008 \ UA0009 UA0010 UA0012 UA0014 UA0019 UA0020 UA0022 \ --severity warn ``` 5. **Walk the residual** `UA0001` / `UA0011` / `UA0015` / `UA0018` / `UA0021` diagnostics manually — they cover patterns that require human judgement. 6. **Remove the migration package.** You are now on clean 2.0 with no shim dependency. ### Source generator (`Opc.Ua.MigrationAnalyzer.Generator.dll`) Per-consumer Roslyn `IIncrementalGenerator` that emits `.g.cs` files for every `<Name>Collection` reference in the consumer's compilation that fails to bind: - **Catalog override (30 entries)** — pins element types that renamed across the 1.5.378 → 2.0 boundary: `DateTime`→`DateTimeUtc`, `Guid`→`Uuid`, `byte[]`→`ByteString`, `XmlElement`→`Opc.Ua.XmlElement`, plus the primitives and built-in opc types whose element name didn't rename. - **Semantic lookup** — for model-compiled `<UserType>Collection` patterns the model compiler historically emitted for any user-defined complex type. Strips the `Collection` suffix, runs `Compilation.GetSymbolsWithName` against the unique element short name, emits the shim with the fully-qualified type reference. - **`MIG01` diagnostic** — fires when the element type can't be uniquely resolved (zero or multiple candidates). User adds the missing `using` or migrates the site manually. Each generated file emits a class shaped exactly like the 1.5.378 wrapper: ```csharp [global::System.Obsolete("'Int32Collection' was removed in 2.0. Use 'List<int>' or 'ArrayOf<int>' instead. (UA0002)")] internal sealed class Int32Collection : global::System.Collections.Generic.List<int> { public Int32Collection() { } public Int32Collection(int capacity) : base(capacity) { } public Int32Collection(global::System.Collections.Generic.IEnumerable<int> collection) : base(collection) { } public static implicit operator global::Opc.Ua.ArrayOf<int>(Int32Collection? value) => value is null ? default : value.ToArrayOf(); } ``` **Design choice — `internal` (not `public`):** the generated shim never leaks through the consumer's public API surface. Consumers with *public* methods or properties returning a `<Type>Collection` will hit `CS0050: Inconsistent accessibility` — the intended signal that the public surface must migrate to `List<T>` / `ArrayOf<T>` first; internal call sites keep compiling under the shim so iteration is incremental. ### 19-rule analyzer reference | Rule | Replaces | Default | Auto-fix | |------|----------|---------|----------| | `UA0001` | `Utils.Trace` / `Utils.LogX` | Info | No (telemetry plumbing requires manual review) | | `UA0002` | Removed `<Type>Collection` wrappers | Warning | Yes (→ `List<T>` / `ArrayOf<T>`); the source generator keeps the call site compiling in the meantime | | `UA0003` | `x == null` on now-struct built-ins | Warning | Yes (→ `x.IsNull`) | | `UA0004` | `?.` on now-struct built-ins | Warning | Yes (drop the `?`) | | `UA0005` | `byte[]` where `ByteString` is expected | Warning | Yes (append `.ToByteString()`) | | `UA0006` | `new Variant(object\|DateTime\|Guid\|byte[])` | Warning | Yes (→ `Variant.From(...)`) | | `UA0007` | `new NodeId(string)` / `new ExpandedNodeId(string)` | Warning | Yes (→ `Parse`) | | `UA0008` | `Session.Call(..., params object[])` | Warning | Yes (wrap with `Variant.From`) | | `UA0009` | `[DataContract]` / `[DataMember]` on config extensions | Warning | Yes (→ `[DataType]` / `[DataTypeField]`) | | `UA0010` | `using` / `Dispose` on `CertificateIdentifier` / `UserIdentity` / `IUserIdentityTokenHandler` | Warning | Yes (drop the disposable) | | `UA0011` | Sync `IUserIdentityTokenHandler.{Encrypt,Decrypt,Sign,Verify}` | Info | No (async promotion required) | | `UA0012` | `CertificateFactory.*` static helpers | Warning | Yes (→ instance methods) | | `UA0014` | `DataValue.IsGood(dv)` static helper | Warning | Yes (→ `dv.IsGood`) | | `UA0015` | Sync / APM members on GDS / LDS clients | Info | No (async promotion required) | | `UA0018` | `CertificateIdentifier.Certificate` getter | Info | No (→ `LoadCertificate2Async`) | | `UA0019` | `new DataValue(StatusCode[, ts])` | Warning | Yes (→ object-initializer form) | | `UA0020` | `EncodeableFactory.GlobalFactory` / `Create()` | Warning | Yes (→ `ServiceMessageContext.Factory` / `Fork()`) | | `UA0021` | `CertificateValidator` / `CertificateValidationEventArgs` (structural rename) | Info | No (see migration guide §Certificate validation) | | `UA0022` | `ApplicationConfiguration.CertificateValidator` / `ServerBase.CertificateValidator` property rename | Warning | Yes (→ `.CertificateManager`) | Plus one generator-only diagnostic: | Rule | Source | Default | Triggers | |------|--------|---------|----------| | `MIG01` | Generator | Warning | Generator can't uniquely resolve the element type for a `<Foo>Collection` reference (zero or multiple candidates). The user adds a `using` for the namespace defining `Foo`, or migrates the call site manually. | ### Runtime shim coverage (`Opc.Ua.MigrationAnalyzer.Core.dll`) C# 14 `extension` members so 1.5.378 call sites continue to compile: - **Moved obsolete extensions** the 2.0 libraries no longer carry inline: `NodeId` / `Variant` / `DataValue` null-check helpers, `Session` sync helpers, `Subscription` sync helpers, `ApplicationInstance` helpers, `ServerBase.Start` / `Stop`, `TransportChannel` APM, `ChannelBase` static factory methods, etc. - **New shims for genuinely-removed members**: `EncodeableFactory.GlobalFactory`, `CertificateIdentifier.Certificate` (throws), sync wrappers for `IUserIdentityTokenHandler.{Encrypt,Decrypt,Sign,Verify}`, sync + APM wrappers for the GDS / LDS client APIs, `GlobalDiscoverySampleServer` 1.5.378-shape ctor (in-tree `Libraries/Opc.Ua.Gds.Server.Common/`). > ⚠ The sync shims wrap their `*Async` counterparts via `Task.Run(…).GetAwaiter().GetResult()`. Intended as a **migration aid only** — port to `await` before shipping. ### Repo layout ``` Tools/Opc.Ua.MigrationAnalyzer/ # analyzer DLL Analyzers/UA00xxAnalyzer.cs # 19 DiagnosticAnalyzer impls Diagnostics/{DiagnosticIds,Descriptors,WellKnownProperties}.cs Helpers/{SymbolExtensions,UaSymbols}.cs Opc.Ua.MigrationAnalyzer.nuspec # ships all 3 analyzer DLLs + 6-TFM Core OPCFoundation.NetStandard.Opc.Ua.MigrationAnalyzer.props Tools/Opc.Ua.MigrationAnalyzer.CodeFixer/ # code-fix DLL CodeFixes/UA00xxCodeFix.cs # 14 CodeFixProvider impls Tools/Opc.Ua.MigrationAnalyzer.Generator/ # source generator DLL (NEW) MigrationGenerator.cs # IIncrementalGenerator CollectionShimCatalog.cs # 30-entry element-type overrides Diagnostics/GeneratorDiagnostics.cs # MIG01 Tools/Opc.Ua.MigrationAnalyzer.Core/ # runtime shim (multi-TFM) Client/, Configuration/, Core/, Gds.Client.Common/, Types/, Marker/ Tools/Roslyn.slnx # source-gen + migration projects Tests/Opc.Ua.MigrationAnalyzer.Tests/ # 142 tests Analyzers/UA00xxTests.cs # 107 analyzer + code-fix tests Generators/MigrationGeneratorTests.cs # 35 generator tests (NEW) Tests/Opc.Ua.MigrationAnalyzer.Core.Tests/ # 13 runtime-shim tests ``` ### Documentation - [`Docs/MigrationGuide.md`](https://github.com/OPCFoundation/UA-.NETStandard/blob/master/Docs/MigrationGuide.md) — §3 Collection Type Migration gains a tip pointing at the generator so CS0246 is replaced with `[Obsolete]` warnings + UA0002. - [`.github/agents/opcua-v20-migration.agent.md`](https://github.com/OPCFoundation/UA-.NETStandard/blob/master/.github/agents/opcua-v20-migration.agent.md) — Strategy section mentions the three Roslyn components + runtime shim explicitly, plus the MIG01 diagnostic and the "internal-by-design" CS0050 hint. ### Central package pinning `Directory.Packages.props` pins `Microsoft.CodeAnalysis.*` (Common, CSharp, CSharp.Workspaces, Workspaces.Common) to **4.14.0** — the stable analyzer API surface. The earlier 5.3 pin was the *csc-internal* version, which is not safe for analyzer hosts. ### Dogfood story The full 42-sample dogfood against `OPCFoundation/UA-.NETStandard-Samples` surfaced a **critical analyzer-loader bug** in an earlier iteration: the analyzer DLL initially co-shipped its code-fix providers in one assembly, which transitively referenced `Microsoft.CodeAnalysis.Workspaces.dll`. csc.exe's analyzer host ships only `Microsoft.CodeAnalysis.dll` + `CSharp.dll` in its bincore and **silently swallows** load failures — net result: zero diagnostics across all samples. Fix landed in commit `861fa6ee1`: 1. **Split** the assembly: analyzer in `Opc.Ua.MigrationAnalyzer.dll` (Workspaces-free, csc-safe), code-fixes in `Opc.Ua.MigrationAnalyzer.CodeFixer.dll` (Workspaces-aware, IDE-only). 2. **Downgrade** to Roslyn 4.14 — the stable analyzer API. 3. `/p:ReportAnalyzer=true` confirms all 19 analyzers initialise and execute on real consumer code. This PR's new generator was smoke-tested against a minimal consumer that exercises all 30 catalog entries + a model-compiled element type + the unresolvable case: - 30 catalog patterns + model-compiled `MyThingCollection` → all emit shims, fire CS0618 with `(UA0002)` marker - Element-type renames verified: `DateTimeCollection` → `DateTimeUtc`, `ByteStringCollection` → `ByteString`, `GuidCollection` → `Uuid`, etc. - `NeverHeardOfItCollection` → `MIG01` fires with help link to the migration guide Known compatibility gaps (documented in the migration agent): - Legacy WinForms `.Net4` sample projects use pre-SDK MSBuild XML and **ignore** `Directory.Build.targets` `<PackageReference>` injection — consumers in this format must add the migration package to their csproj inline. ### Packaging design notes - Hand-authored nuspec ships 3 DLLs in `analyzers/dotnet/cs/` + 6 TFMs of Core (shim) DLLs under `lib/`. All 6 OPC UA runtime package dependencies are declared per-TFM-group. - `build/OPCFoundation.NetStandard.Opc.Ua.MigrationAnalyzer.props` is auto-imported by NuGet (file name must match package id exactly) and injects all three analyzer DLLs as `<Analyzer>` items. - `DiagnosticIds.cs` / `DiagnosticDescriptors.cs` / `WellKnownProperties.cs` / `Helpers/*.cs` are **shared via `<Compile Link=…>`** between the analyzer and code-fixer projects to break what would otherwise be a NuGet restore cycle. The generator has no compile dependency on the analyzer; the 30-entry override table is duplicated in `CollectionShimCatalog.cs` (the analyzer table also drives diagnostic messages, so the duplication is small and intentional). - `Opc.Ua.MigrationAnalyzer.Core` is multi-TFM (`net472, net48, netstandard2.1, net8.0, net9.0, net10.0`) and **non-packable on its own**; the parent migration package's nuspec consumes each TFM's DLL by path. |
||
|
|
49305d9085 |
V2 subscription engine close gap for test and feature parity with classic engine (#3824)
# Description V2 subscription engine feature parity round to make the classic engine eligible for deprecation. Splits the test surface so the classic and V2 engines can evolve independently, ports the gaps the classic-engine integration tests had been exercising, and lands the public V2 API additions needed to close them. - Splits `Tests/Opc.Ua.Subscriptions.Tests` into a classic (`Opc.Ua.Subscriptions.Classic.Tests`) and a V2 (`Opc.Ua.Subscriptions.Tests`) project to shrink CI time and let the two engines diverge cleanly. - Adds the V2 public-surface gaps required by the test ports (`Subscription.ServerId` on the class, `SetSubscriptionDurableAsync`, `SendInitialValuesOnTransfer`, unified `OnSubscriptionStateChangedAsync` handler callback, per-item `ConditionRefreshAsync`, fluent `LoadSubscriptionsAsync(Stream, …)` and `Subscription.Snapshot()` / `RestoreAsync()` for save/load + transfer). - Lands handler-centric design (no `PublishingStopped` property handlers maintain derived state); always-sequential per-subscription delivery documented + tested. - **Adds short and long haul stability tests for the V2 `ManagedSession` + subscription engine. Closes #3744** (see "Issue #3744 Haul tests" below). - **Migrates SubscriptionStateSnapshot / MonitoredItemStateSnapshot to `[DataType]` source-generator codecs**. - `SubscriptionDurableV2Tests.cs` 5 V2 ports of the classic durable test patterns. - `V2FollowUpCoverageTests.cs` handler state-change callback, fluent stream-based `LoadSubscriptionsAsync`, `SendInitialValuesOnTransfer`, snapshot edge cases (empty / `DataChangeFilter` round-trip / concurrent mutation). - `SubscriptionFailoverV2Tests.cs` forced channel-break with and without `WithTransferSubscriptionsOnRecreate`. - `MonitoredItemConditionRefreshLiveV2Tests.cs` — live `ConditionRefresh` against the reference server's event source; asserts `RefreshStart` / `RefreshEnd` events flow through the handler. ## Fixes - #3744 Haul tests (V2 ManagedSession + subscription engine) `Tests/Opc.Ua.Sessions.Tests/ManagedSessionStabilityTest.cs` adds the short/long haul coverage requested by [#3744](https://github.com/OPCFoundation/UA-.NETStandard/issues/3744) plus the bonus fault-injection variant: | Test | Duration | Category | Purpose | |---|---|---|---| | `ShortHaulManagedSessionV2Async` | 2 minutes | `ManagedSessionHaul` (`[Explicit]`) | Quick local sanity check of the V2 monotonicity contract. | | `LongHaulManagedSessionV2Async` | 90 minutes (configurable via `TEST_DURATION_MINUTES`) | `ManagedSessionHaul` (`[Explicit]`) | Long-running V2 stability + monotonicity. | | `LongHaulManagedSessionWithFaultInjectionV2Async` | 90 minutes (configurable) + fault every `FAULT_INJECTION_INTERVAL_SECONDS` (default 60s) | `ManagedSessionHaul` (`[Explicit]`) | **Bonus** — force-closes the subscriber transport channel periodically; verifies V2 manager transfers/recreates the subscription and continues monotonic delivery across reconnects. | **Pattern.** A writer `ManagedSession` increments a `uint32` counter and writes it into `Scalar_Static_Mass_UInt32_UInt32_00` every 250ms. A subscriber `ManagedSession` runs a V2 subscription with a single monitored item on the same node. `MonotonicCounterHandler` asserts each received sample is *strictly greater than* the previous one. V2 `ISubscriptionNotificationHandler` per-subscription ordering guarantee. Skipped values (sampling rate < write rate) are tolerated; duplicates and reorderings are violations. |
||
|
|
01d7162313 |
Part 9 Alarms & Conditions: complete server + client implementation (#3805)
Complete implementation of **OPC UA Part 9 ΓÇö Alarms & Conditions** for
both server and client, **OPC UA Part 16 ΓÇö State Machines** (generic
extensible client + server API), and the supporting infrastructure
(source-generated event records, source-generated ObjectType proxies,
`IAsyncEnumerable` streaming subscriptions, address-space model change
tracking, per-node `INodeCache` invalidation, unified DI integration).
### Server-side (Part 9 complete)
- **`AlarmConditionState`** ΓÇö every Part 9 method wired automatically
in `OnAfterCreate`: `Silence`, `Suppress`/`Suppress2`,
`Unsuppress`/`Unsuppress2`, `RemoveFromService`/`RemoveFromService2`,
`PlaceInService`/`PlaceInService2`, `Reset`/`Reset2`,
`GetGroupMemberships`. Each method generates the spec-mandated audit
event and supports an optional veto-delegate hook.
- **Latched alarms** ΓÇö `ActiveState` reflects real process state;
`LatchedState` persists until explicit `Reset` (with full precondition
validation).
- **Re-alarming** ΓÇö
`ProcessReAlarm`/`ResetReAlarmRepeatCount`/`IsReAlarmEnabled` helpers
(opt-in, no hidden timer).
- **Audible alarms** ΓÇö `UpdateAudibleState` for
`AudibleEnabled`/`AudibleSound`/`SilenceState` lifecycle.
- **Suppression + groups** ΓÇö `AlarmGroup`, `AlarmSuppressionEngine`
(with first-in-group), `AlarmRateTracker` (for `AlarmMetricsType`).
- **Spec-compliance fixes** ΓÇö `SuppressedOrShelved` now includes
`OutOfServiceState`; `GetRetainState` includes `LatchedState`;
`EffectiveDisplayName` composition includes `OutOfServiceState` +
`LatchedState`.
### Client-side Part 9 API
- **`AlarmClient`** ΓÇö typed Part 9 operations. Each method delegates
to the matching source-generated `*TypeClient` proxy
(`ConditionTypeClient`, `AcknowledgeableConditionTypeClient`,
`AlarmConditionTypeClient`, `DialogConditionTypeClient`,
`ShelvedStateMachineTypeClient`) ΓÇö one source of truth for every
method NodeId.
- **Interface hierarchy** — `IConditionOperations` →
`IAcknowledgeableConditionOperations` → `IAlarmOperations` +
`IDialogConditionOperations`.
- **Source-generated event records** ΓÇö new `EventRecordGenerator`
(alongside `ObjectTypeProxyGenerator`) emits `{Type}TypeRecord` per OPC
UA event type: `ConditionTypeRecord` →
`AcknowledgeableConditionTypeRecord` → `AlarmConditionTypeRecord` →
`LimitAlarmTypeRecord`/`ExclusiveLimitAlarmTypeRecord`/… all the way
to vendor subtypes. **Vendor alarm types get records automatically.**
- **`AlarmEventDecoder`** ΓÇö decodes `EventNotification.Fields` into
the most-specific generated record.
- **`AlarmEventFilterBuilder`** ΓÇö fluent builder for Part 9
`EventFilter`s.
- **`ISession.GetAlarmClient(telemetry)`** convenience extension.
### Part 16 state machines (generic, extensible)
- **Client**: extension methods on the source-generated
`StateMachineTypeClient` / `FiniteStateMachineTypeClient` ΓÇö
`GetCurrentStateAsync`, `ObserveFiniteTransitionsAsync`
(`IAsyncEnumerable<FiniteStateSnapshot>`), `WaitForStateAsync`,
`GetAvailableStatesAsync` / `GetAvailableTransitionsAsync`. **Vendor
proxies inherit the API automatically** through the generated
inheritance chain.
- **Server**: `StateMachineBuilder` (fluent: `AddState` /
`AddTransition` / `OnCause` / validation) +
`FluentFiniteStateMachineState` ΓÇö declare a Part 16 state machine
without subclassing the abstract base.
- **Alarms alignment**: `AlarmClient.GetShelvingStateAsync` /
`ObserveShelvingTransitionsAsync` surface the API for every alarm's
`ShelvingState` child.
### IAsyncEnumerable streaming subscription
- **`IStreamingSubscription`** with
`SubscribeDataChangesAsync`/`SubscribeEventsAsync` returning
`IAsyncEnumerable<T>` (Channel-backed).
- **`ManagedSession.DefaultStreaming`** ΓÇö lazy shared subscription;
disposed with the session.
- **Helpers** ΓÇö `TakeUntilAsync`, `WithTimeoutAsync`, `TakeAsync`,
`BufferedAsync` for state-machine waits and bounded observation windows.
- **`AlarmStreamExtensions`** ΓÇö
`SubscribeAlarmsAsync`/`SubscribeConditionsAsync`/`SubscribeDialogsAsync`
returning the source-generated record types.
### Address-space model change tracking
- **Server**: `RaiseGeneralModelChangeEvent` on both `CustomNodeManager`
and `AsyncCustomNodeManager`; `ModelChangeAggregator` (in
`Opc.Ua.Server.NodeManager`, used by every node manager) batches changes
per service call; **auto-emit** from `CreateNode`/`DeleteNode` (opt-out
via `ModelChangeEmissionEnabled = false`).
- **Client**: `IModelChangeTracker` subscribes to
`BaseModelChangeEventType` via the streaming subscription, decodes
`ModelChangeStructureDataType` payloads, invalidates the `INodeCache`
per-node.
- **`INodeCache.InvalidateNode(NodeId)`** ΓÇö new interface member (true
per-node eviction in `NodeCache`).
- **`ManagedSession.EnableModelChangeTrackingAsync()`** +
`ManagedSessionOptions.ModelChangeTracking` +
`ManagedSessionBuilder.WithModelChangeTracking()` fluent method.
### Dependency Injection integration
- **`services.AddOpcUa().AddClient(...).AddAlarms()`** ΓÇö registers
`AlarmClientFactory` so DI-hosted apps can resolve a Part 9 client per
session without `new`-ing one manually.
- Cross-link added to the unified DI surface (`AddServer` / `AddClient`
/ `AddComplexTypes` / `AddGdsServer` / `AddLdsServer` /
`AddWotConServer`).
### Quickstart server modernization
- `Quickstarts.Servers/Alarms/AlarmNodeManager.cs` ported to
`AsyncCustomNodeManager` and demonstrates the new `AlarmGroup` +
`AlarmSuppressionEngine` end-to-end via a writable `MaintenanceMode`
boolean that suppresses every member alarm.
### Documentation
- New: `Docs/AlarmsAndConditions.md`, `Docs/StreamingSubscription.md`,
`Docs/ModelChangeTracking.md`, `Docs/StateMachines.md` ΓÇö full
developer guides.
- Updated: `Docs/DependencyInjection.md` (`AddAlarms()` row + section),
`Docs/README.md` index, `Docs/MigrationGuide.md` (Part 9 / Part 16 /
model change tracking sections covering behavior changes + breaking API
surface).
- Sample: `Applications/ConsoleReferenceClient/AlarmClientSample.cs`.
|
||
|
|
8d2402c995 |
Bump version to 2.0 and land 1.5.378 to 2.0 migration guide (#3819)
Prepares the repository for a 2.0 release: bumps every version reference from 1.6 to 2.0, and lands the migration guide describing the 1.5.378 → 2.0 upgrade path. The 1.6 line never shipped, so this is a straight rename with no historical 1.6 migration content to preserve. The PR is split into two commits: 1. **`Bump version to 2.0 (next release is a major version change)`** — version metadata, NuGet metadata, the side documentation, and the migration agent file. 2. **`[Docs] Close 19 audit gaps in 1.5.378 to 2.0 migration guide`** — adds and reorganizes `Docs/MigrationGuide.md` to close every gap from a rigorous code-review audit of the 1.5.378 → 2.0 breaking-change surface. ### Version bump (commit 1) - `version.json`: `1.6-preview` → `2.0-preview` - `common.props`: `<VersionPrefix>1.6</VersionPrefix>` → `<VersionPrefix>2.0</VersionPrefix>` - `nuget/Opc.Ua.nuspec` and `nuget/Opc.Ua.Symbols.nuspec`: `1.6.0` → `2.0.0` - `README.md`: "New in 1.6" → "New in 2.0" - `Docs/ComplexTypes.md`, `Docs/Observability.md`, `Docs/Sessions.md`: 1.6 → 2.0 mentions - Renames `.github/agents/opcua-v16-migration.agent.md` → `.github/agents/opcua-v20-migration.agent.md` and updates the agent metadata (name, description, trigger phrases, version table) - `UA.slnx`: solution-items reference updated to the new agent filename - `Tools/Opc.Ua.SourceGeneration.Core/Generators/ObjectTypeProxyGenerator.cs`: two v16 → v20 comment fixes ### Migration guide (commit 2) Closes 19 gaps from an audit comparing `master378` (1.5.378) with `master` (2.0). Adds a new top-level **Package, Target Framework and Dependency Changes** section covering the new `Opc.Ua.Core.Types` and `Opc.Ua.Security.Certificates` packages, the `LibTypesTargetFrameworks` netstandard2.0 drop, the NuGet dependency additions/removals, and the residual Newtonsoft.Json dependency in `Opc.Ua.PubSub`. In-place additions: - new H4 for `INodeManager3` under Node States - `Session.Call` `Variant.From` worked example - new H3 `Subscriptions and Transports` with H4 verdicts for Durable subscriptions (source-breaking), PubSub (no source break) and Reverse connect (no source break) - new H3 `Telemetry and Logging` covering `ITelemetryContext` constructor-injection patterns - `in DataValue` async copy-to-local pattern - UNSAFE / SAFE pair for `WithPoolNotifications` pooling - using-alias example for classic vs V2 `SubscriptionOptions` - "Silent regression" callout for `OnAfterCreate` - numbered lifecycle ordering for `ApplicationConfiguration.CertificateManager` Corrections: - clarifies that the `SessionReconnectHandler` `[Obsolete]` is still present in 2.0 (not withdrawn); - clarifies that the source-generated `ServerCapability` constants vs the `ServerCapabilityInfo` registry type are distinct; - disambiguates `ReconnectPolicyOptions` (DTO) from `ReconnectPolicy` (runtime). Adds an "Automate the migration" pointer to the forthcoming `Opc.Ua.CodeFixers` analyzer package, which mechanizes 17 of the patterns covered in this guide. The analyzer is published in a follow-up PR. |
||
|
|
eb40a59566 |
More format and diagnostic fixes (#3780)
Drive the solution to zero warnings / zero errors with analyzers on, promote the consistently-fixed rules to error, and lock in coverage on the only line of new logic. |
||
|
|
14e995c1d0 |
Restructure test projects for faster CI (#3767)
Rebalance the heavy test projects of the OPC UA .NET Standard stack so CI test execution can run cleanly in parallel.
### New test projects (Tests/Opc.Ua.<X>.Tests/)
| Project | Files | Sources |
|---|---:|---|
| Opc.Ua.Sessions.Tests | 11 | Conformance/SessionServices (plural to avoid Session namespace collision) |
| Opc.Ua.Subscriptions.Tests | 25 | SubscriptionServices + MonitoredItemServices |
| Opc.Ua.History.Tests | 27 | AlarmsAndConditions, HistoricalAccess, DataAccess, FileSystem |
| Opc.Ua.Lds.Tests | 15 | Discovery, DiscoveryServices, Miscellaneous |
| Opc.Ua.Core.Security.Tests | 39 | Security, Auditing |
| Opc.Ua.InformationModel.Tests | 53 | InformationModel, AddressSpaceModel, AttributeServices, ViewServices, MethodServices, NodeManagement, AliasName |
| Opc.Ua.Core.Encoders.Tests | 11 | Encoder tests extracted from Core.Tests |
| Opc.Ua.Gds.Tests (existing) | +5 | new GDS tests |
### New helper class libraries (Tests/Opc.Ua.<X>.TestFramework/ + Tests/Opc.Ua.Test.Common/)
* Opc.Ua.Client.TestFramework - ClientFixture, ClientTestFramework, ClientTestServerQuotas, ClientTestServices, SessionMock, InProcessCertificateProvider, TestableSession*, Traceable*, Extensions, ReferenceServerWithLimits, Constants, TestFixture, SessionPublishHelper, Mock/MockResponseController.
* Opc.Ua.Server.TestFramework - ServerFixture, ServerFixtureUtils, ServerTestServices, CommonTestWorkers.
* Opc.Ua.Core.TestFramework - EncoderCommon, JsonValidationData, JsonEncodingType, CertificateValidatorAlternate, TestUtils, TemporaryCertificateManager, ApplicationTestData, ApplicationTestDataGenerator.
* Opc.Ua.Test.Common - Logging.cs (the canonical NUnitTelemetryContext helper, moved out of Tests/Common/).
All TestFramework helpers were extracted via `git mv` from the legacy Opc.Ua.Client.Tests / Opc.Ua.Server.Tests / Opc.Ua.Core.Tests projects (no copy-paste).
### Server-side production-code fixes
1. `MasterNodeManager.ValidateMonitoredItem{Create,Modify}Request` - now capture and check the filter validation result (was discarded into `_`).
2. `MasterNodeManager.ReadAsync` - assign `value = values[ii] = value.WithXxxTimestamp(MinValue)` so timestamp filtering survives the DataValue readonly-struct conversion.
3. `ApplicationsDatabaseBase.{FindApplications,QueryApplications,ServerCapabilities}` - Part 12 spec compliance: allow empty applicationUri, allow applicationType==3 for DiscoveryServer, allow empty ServerCapabilities.
4. `LinqApplicationsDatabase.{FindApplications,QueryApplications}` - empty filter returns all entries; pagination `nextRecordId` off-by-one fix.
### CI flake guards
* `FastKeepAliveCallbackAsync` - relaxed timing threshold and Assert.Ignore on slow CI runners.
* `SecurityCertValidationTests` - Assert.Ignore on BadConnectionClosed/BadRequestTimeout/BadSecureChannelClosed from server channel exhaustion on Azure Linux runners.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
||
|
|
30bfa7895f |
Add OPC UA WoT Connectivity (OPC 10100-1) libraries and tests (#3786)
* Add WoT Connectivity (OPC 10100-1) libraries and tests Implements the OPC UA WoT Connectivity companion specification (OPC 10100-1, `WoT Connectivity for OPC UA`) through four new projects under the unified Opc.Ua.WotCon prefix: * Opc.Ua.WotCon - source-generated model from the official WotConnection.xml + WotConnection.csv design files (NodeStates, NodeIds, ObjectType client proxies including WoTAssetFileTypeClient : FileTypeClient). * Opc.Ua.WotCon.Server - WotConnectivityNodeManager (AsyncCustomNodeManager subclass), factory, DI options. Provider model split into IWotAssetProvider (per-asset Read/Write/Observe/InvokeAction) and IWotAssetDiscoveryProvider (server-level Discover/Test/CreateForEndpoint per spec sec. 6.3.4-6). System.Text.Json TD parser with AOT-safe JsonSerializerContext. Property mapper per spec table 14, action mapper per sec. 6.3.9. WotAssetFileManager enforces only OpenFileMode Read (1) and Write|EraseExisting (6) per spec sec. 6.3.10 and drives CloseAndUpdate materialisation + persistence. * Opc.Ua.WotCon.Client - WotConnectivityClient and WotAssetClient compose the generated proxies (no inheritance). Extension methods on FileTypeClient / WoTAssetFileTypeClient add chunked upload/download and the Open(Write|EraseExisting) -> Write* -> CloseAndUpdate flow, extending the existing FileSystem API without subclassing. * Opc.Ua.WotCon.Tests - NUnit suite (28 passing tests) covering TD parsing, property and action mappers, and the SimulatedWotAssetProvider/SimulatedWotDiscoveryProvider which serve as canonical examples of the provider contract. |
||
|
|
f3d3fd87d3 |
Reorganize Stack/ folder layout (#3775)
Two refactors that together reshape how the stack tier is laid out:
1. Rename `Opc.Ua` project to `Opc.Ua.Core.Types`
* Stack/Opc.Ua/ -> Stack/Opc.Ua.Core.Types/ (git mv preserves history)
* Opc.Ua.csproj -> Opc.Ua.Core.Types.csproj
* AssemblyName : `Opc.Ua` -> `Opc.Ua.Core.Types`
* PackageId : `OPCFoundation.NetStandard.Opc.Ua` ->
`OPCFoundation.NetStandard.Opc.Ua.Core.Types`
* RootNamespace : kept as `Opc.Ua`
* StackGeneration.cs assembly-name switch updated; the renamed
assembly still produces `StackGenerationType.Models`.
* The `OPCFoundation.NetStandard.Opc.Ua` name now belongs solely to
the roll-up meta-package (nuget/Opc.Ua.nuspec); the meta-package's
former self-dependency is replaced with the new
`.Core.Types` package, and `.Symbols.nuspec` gains the
matching `.Core.Types.Debug` debug-symbol dependency.
2. Move `Opc.Ua.Security.Certificates` from Libraries/ to Stack/
It is a stack-tier dependency consumed by Opc.Ua.Core, not a
higher-level library extension, so it now sits alongside the other
stack projects.
Both refactors update the same set of cross-cutting infrastructure:
- UA.slnx, UA Core Library.slnx, Applications/ConsoleReferenceServer/Dockerfile
- .azurepipelines/signlist{Debug,Release}.txt
- ProjectReferences across Stack/, Libraries/, Tests/, Fuzzing/
- Tests/Opc.Ua.SourceGeneration.Stack.Tests/StackGenerationAssemblyTests.cs
- Docs/PlatformBuild.md and .github/copilot-instructions.md (new
Core.Types package listed)
Verification
* dotnet build UA.slnx -c Debug -- succeeded, 0 errors
* StackGenerationAssemblyTests : 5 passed
* Opc.Ua.SourceGeneration.Tests : 40 passed
* Opc.Ua.SourceGeneration.Core.Tests : 3514 passed, 8 skipped
* Opc.Ua.Core.Tests (Stack filter) : 1982 passed, 80 skipped
* Opc.Ua.Security.Certificates.Tests : 239 passed
|
||
|
|
3836cbfdfe |
Add FileSystemClient: System.IO-style async client over OPC UA file APIs (#3760)
Add FileSystemClient: System.IO-style async client over OPC UA file APIs |
||
|
|
70b4498db8 |
Certificate manager and ref counted certificate type (#3688)
* New certificate and secrete abstraction with certificate infrastructure and certificate/secret stores. * leak testing for certificate resources to validate new ref counting in every test assembly * Migration guide updated and documentation added for all * Remove IDisposable from Nodestate and UserIdentity. * UserCertificateTokenHandler now just points into certificate registry/stores, no dispose required * Fix CA2000 warnings and cleanup of other diagnostics, increase warning levels in .editorconfig |
||
|
|
94653f1aee |
Add a MCP server that enables LLM/Copilot to be a OPC UA client (#3701)
* Opc ua client Mcp Server * fix for #3699 |
||
|
|
09e44453a4 |
Generate type safe (method) proxies for ObjectTypes inside models (#3685)
Add interop test agent The new stack-pass ObjectMethodProxyGenerator emits proxies that derive from Opc.Ua.ObjectTypeClient and reference Session.MessageContext.NamespaceUris. Neither type exists in the in-memory test compilation, which only references Opc.Ua.Types.dll. Moving ObjectTypeClient to Opc.Ua.Types would cascade ISessionClient, IClientBase, ITransportChannel and the generated service interfaces with it, so the type stays in Opc.Ua.Core and we add a minimal stub to OpcUaCoreStubs instead. Wire Microsoft.Extensions.Options 10.0.5 + DependencyInjection.Abstractions 10.0.5 into Directory.Packages.props and the Gds.Client.Common project to enable upcoming options-driven configuration work. Modernize Opc.Ua.Gds.Client.Common (DI, options, interfaces, async dispose) |
||
|
|
c71f2e7733 |
Fix source generator generated structures with optional fields (#3674)
Split validator load/validate; split DesignFileCollection Targets/Dependencies ModelDesignValidator.LoadNodes now skips ValidateDictionary when a model is loaded purely as a dependency. The flag is plumbed through LoadModelDesign and LoadDesignFile; the dep loop in ValidateModel passes false, the primary target passes true. This lets callers supply unrelated or reverse dependencies (deps that import the target) without triggering premature validation failures. DesignFileCollection exposes Targets + Dependencies; generators and tests updated. MergeNamespace preserves FilePath across PublicationDate-based replacement so later loads can still find the source file. Tester simplified to treat every other xml/csv pair as a dependency of each target. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> |
||
|
|
6c8c1a6d29 | Enable dispose analyzers CA2000 and CA2213 and fix all issues (#3670) | ||
|
|
fd41681f4b |
Add support to publish OPC UA applications as Native AOT (#3633)
* make most ptojects aot compatible * Remove newtonsoft * Migrate all projects from Mono.Options to System.CommandLine 2.0.5 * Fix array clone * Replace serializers for storage using new attribute driven type geberator * Add new AOT integration tests covering all functional areas * Documentation updates |
||
|
|
189a6c7c83 |
Bump codecov/codecov-action from 5 to 6 (#3645)
Bumps [codecov/codecov-action](https://github.com/codecov/codecov-action) from 5 to 6. - [Release notes](https://github.com/codecov/codecov-action/releases) - [Changelog](https://github.com/codecov/codecov-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/codecov/codecov-action/compare/v5...v6) --- updated-dependencies: - dependency-name: codecov/codecov-action dependency-version: '6' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> |
||
|
|
66f44396ff |
[Server] Improve Request Queue, fix Event handling, add Tests (#3611)
- implement RequestQueue using Channels - add event load test - add event integration test verifying event from server object is received - fix Client Reconnect Test - fix DiagnosticsNodeManager not creating RootNotifier for Server object - add Benchmarks for MonitoredItem.QueueEvent - add serveral UnitTest for DiagnosticsNodeManager Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: romanett <7413710+romanett@users.noreply.github.com> Co-authored-by: Marc Schier <marcschier@users.noreply.github.com> |
||
|
|
03777ecb09 |
New Json decoder/encoders, array/matrix abstractions, ByteString, and more. (#3619)
- **Collections overhaul** — new/rewritten collection types (`ArrayOf`, `Collections` commits)
- **`Variant` builder/accessor** — new APIs for constructing and accessing Variants
- **`NodeId` operators made explicit** — breaking change for implicit conversions
- **Version bumped to 1.6** with preview build support
- **NumericRange** uses Variant
- **object** type accessors and general usage removed.
### 🏗️ Infrastructure
- Build config updated; `.NET 10` targeting
- InternalsVisibleTo moved to `.csproj`
- Pipeline/CI adjustments
|
||
|
|
cff3743c33 | Update build configuration to latest (#3607) | ||
|
|
f66ceffd75 |
Immutable built in types and code generation (#3534)
Generate stack and application code using source generators Change built in types to readonly structs Update localized text implementation to use JSON text serializer Status code with symbolic names Immutable node ids No boxing for all built in types <= 8 bytes in Variant. Split user identity token and token handling via token handler Add migration guide for breaking changes |
||
|
|
0497953af2 | Change license reference in copilot agents file (#3479) | ||
|
|
78a9ba2ffa |
Set correct target framework for long running test (#3474)
* Set correct target framework * Split long and short haul tests but maintain most of the current code |
||
|
|
1806172500 | only run test on net 10, only print per node status in debug runs (#3439) | ||
|
|
703069ed97 |
Add long-running connection stability test with dynamic token renewal (#3424)
* Initial plan * Add connection stability test with 5-minute token renewal Co-authored-by: marcschier <11168470+marcschier@users.noreply.github.com> * Fix code style issues in ConnectionStabilityTest Co-authored-by: marcschier <11168470+marcschier@users.noreply.github.com> * Remove unused dictionaries to reduce memory overhead Co-authored-by: marcschier <11168470+marcschier@users.noreply.github.com> * Extract magic numbers to named constants for better maintainability Co-authored-by: marcschier <11168470+marcschier@users.noreply.github.com> * Add explicit permissions to workflow for security Co-authored-by: marcschier <11168470+marcschier@users.noreply.github.com> * Change non-CI test duration to 30 minutes for 6 token renewals Co-authored-by: marcschier <11168470+marcschier@users.noreply.github.com> * Set local test to 1 min with 10-second token renewal for 6 renewals Co-authored-by: marcschier <11168470+marcschier@users.noreply.github.com> * Fix SecurityTokenLifeTime to be applied for Server & Client before Startup --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: marcschier <11168470+marcschier@users.noreply.github.com> Co-authored-by: Roman Ettlinger <romanett98@gmail.com> |
||
|
|
113dbde541 |
Bump actions/upload-artifact from 5 to 6 (#3416)
Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 5 to 6. - [Release notes](https://github.com/actions/upload-artifact/releases) - [Commits](https://github.com/actions/upload-artifact/compare/v5...v6) --- updated-dependencies: - dependency-name: actions/upload-artifact dependency-version: '6' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> |
||
|
|
df212479fa | Disable mac os actions (#3404) | ||
|
|
b16c8020dd |
Bump actions/checkout from 5 to 6 (#3355)
Bumps [actions/checkout](https://github.com/actions/checkout) from 5 to 6. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v5...v6) --- updated-dependencies: - dependency-name: actions/checkout dependency-version: '6' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> |
||
|
|
35db52a7a6 | Move from .net 9 to .net 10 SDK and build new target framework .net 10 (#3333) | ||
|
|
712e770fbe |
Restructure core and built in types into base assembly and nuget (#3326)
This change adds a **new Opc.Ua.Types** nuget that contains core types that do not rely on generated code. Why the name? Because almost all code that was in the Types subfolder is part of it, and because we do not want to change the name of the Opc.Ua.Core nuget/assembly because code relies on it. Any other name like base or bootstrap felt out of place due to the current structure already defining the name "types". Key design is to depend on only a small set of libraries with limited transitive dependencies, that includes hashcode, logging.abstraction, and for non standard20 builds System.Text.Json (needed for localizedText mul parsing). Also, key is to support .netstd 2.0 to support source generators and to allow removal of EEC_SUPPORT defines by removing std2.0 from core and all libraries. The changes are mostly restructuring, and thus small but contain some key changes: - **Status code** struct now comes with a Symbol field, which is used to carry symbols in case the code is not generated. Currently (until generated) the status code struct must be manually created with a symbol or the ToSymbolicId extension must be called in the core project. Future will generate Status code constants just like NodeId that contain the symbol which also removes the reflection-based lookup. Several tests needed to be adjusted as they checked the status code symbol strings instead of the code. - **Core identifiers** are copied as they were needed for code to compile, that includes attributes, a subset of status codes and node identifiers. These will never change so no need to generate them. - The types folder now contains **encoders**, except for json which is still in core. Once the json encoder is ported to system.text.json it will also be included and Newtonsoft.Json dropped as dependency (-> #3329). - Since types relies on **IOperationContext** and **ISystemContext**, and these export IUserIdentity which relies on crypto, these were split and extended in core with ISessionOperationContext and ISessionSystemContext, which mean changes to ServerSystemContext and introduction of SessionOperationContext and SessionSystemContext classes that extend OperationContext and SystemContext. Some runtime checks in the server are therefore needed to get at the session and auth info, however, those are anyway optional fields and are not on the critical paths, and thus a type check is in order (and was done in the past already, but against OperationContext class). - **Manifest resources** are now split between Core (nodeset zip, some generated resoures) and Types (built in bsd/xsds). This needs to be revisited later if the bsd/xsd need to be regenerated during type generation. Note that the embedded resource names changed as a result. Since these are only used internally and do not constitute public API this feels reasonable vs duplication of resources in 2 assemblies. - Reflection however now needs to load not just the built in **encodeables** from Opc.Ua.Types assembly, but also the generated encodeables from Opc.Ua.Core assembly. For this a new helper Utils method was added to get the Core assembly when linked against Opc.Ua.Core otherwise null. - Whatever utils methods needed to be split out into the new Opc.Ua.Types assembly, they are now in **CoreUtils** static class in Opc.Ua.Types, and Utils.xxxx forwards to them to ensure minimal changes. Later we would want to obsolete them in favor of CoreUtils, although it might make sense to split them again into domain specific utilities, such as networking, files, etc |
||
|
|
9b1fec6d05 |
Add GitHub Copilot instructions for repository context (#3305)
* Initial plan * Add GitHub Copilot instructions file Co-authored-by: marcschier <11168470+marcschier@users.noreply.github.com> * Fix NuGet package references and preview feed URL Co-authored-by: marcschier <11168470+marcschier@users.noreply.github.com> * Apply suggestion from @romanett --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: marcschier <11168470+marcschier@users.noreply.github.com> Co-authored-by: romanett <romanett98@gmail.com> |
||
|
|
3d17807a87 |
Bump actions/upload-artifact from 4 to 5 (#3292)
Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 4 to 5. - [Release notes](https://github.com/actions/upload-artifact/releases) - [Commits](https://github.com/actions/upload-artifact/compare/v4...v5) --- updated-dependencies: - dependency-name: actions/upload-artifact dependency-version: '5' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> |
||
|
|
f8042e445c | Check bounds for switched on values and roslyn cleanup (#3264) | ||
|
|
234f5bac55 |
Bump github/codeql-action from 3 to 4 (#3260)
Bumps [github/codeql-action](https://github.com/github/codeql-action) from 3 to 4. - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/codeql-action/compare/v3...v4) --- updated-dependencies: - dependency-name: github/codeql-action dependency-version: '4' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> |
||
|
|
bdd1036127 |
Bump actions/setup-dotnet from 4 to 5 (#3191)
Bumps [actions/setup-dotnet](https://github.com/actions/setup-dotnet) from 4 to 5. - [Release notes](https://github.com/actions/setup-dotnet/releases) - [Commits](https://github.com/actions/setup-dotnet/compare/v4...v5) --- updated-dependencies: - dependency-name: actions/setup-dotnet dependency-version: '5' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> |