# Description
Fixes the issue where alarms could not be properly initialized via the
CTT (`--ctt`) flag. The fix addresses both the server-side
initialization and the CTT configuration node references.
The fix involves two complementary changes:
1. **Async Node Manager Registration**: The root cause was that the
`AlarmNodeManager` and other async node managers were never being
registered when the Reference Server started. Without the
`AlarmNodeManager` being initialized, the Alarms namespace was not
registered, making it unavailable when `ApplyCTTModeAsync` attempted to
use it.
2. **Correct CTT Configuration References**: The CTT configuration file
now includes explicit namespace references for alarm types that
correctly reference their actual location in the address space. After
the A&C implementation changes, alarms are now children of
`AnalogSource` and `BooleanSource` nodes (not direct children of the
Alarms folder), and the CTT configuration has been updated to reflect
this structure.
## Changes Made
**ConsoleReferenceServer startup
(`Applications/ConsoleReferenceServer/Program.cs`)**
- Added explicit registration of async node managers before server
startup
- Ensures that the `AlarmNodeManager` and all other async factories are
properly initialized
- Follows the same pattern already used for GDS node manager
registration
- Added registration loop to process all async node manager factories
**CTT Configuration (`Applications/UAReferenceServer.ctt.xml`)**
- Updated explicit namespace references for 8 alarm type Input Nodes to
point to the correct source nodes:
- **Analog-based alarms** → `ns=7;s=Alarms.AnalogSource`:
- DiscrepancyAlarmType
- LimitAlarmType
- ExclusiveLimitAlarmType
- ExclusiveDeviationAlarmType
- NonExclusiveDeviationAlarmType
- AlarmConditionType
- **Boolean-based alarms** → `ns=7;s=Alarms.BooleanSource`:
- OffNormalAlarmType
- SystemOffNormalAlarmType
- Minimal surgical changes: only the namespace mappings were updated to
reference the correct source nodes
The async node managers are now registered between the sync node manager
registration (`server.Create()`) and the server startup
(`server.StartAsync()`), ensuring all namespaces are available when CTT
initialization occurs.
## Testing
- ✅ Server with `--ctt` flag now properly initializes the Alarms
namespace
- ✅ CTT alarms can be enabled without "namespace does not exist" error
- ✅ Explicit namespace mappings correctly reference alarm types under
their respective source nodes
- ✅ Follows existing code patterns for consistency
- ✅ No build or analyzer warnings introduced
- ✅ Build succeeds with 0 warnings, 0 errors
## Related Issues
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Roman Ettlinger <romanett98@gmail.com>
Migrate all NodeManagers to IAsyncNodeManager
Add more Tests
## Related Issues
Issue linking is handled automatically by the system.
## Types of changes
What types of changes does your code introduce?
_Put an `x` in the boxes that apply. You can also fill these out after
creating the PR._
- [x] Bugfix (non-breaking change which fixes an issue)
- [ ] Enhancement (non-breaking change which adds functionality)
- [ ] Test enhancement (non-breaking change to increase test coverage)
- [ ] Breaking change (fix or feature that would cause existing
functionality to not work as expected, requires version increase of
Nuget packages)
- [ ] Documentation Update (if none of the other choices apply)
## Checklist
_Put an `x` in the boxes that apply. You can also fill these out after
creating the PR. If you're unsure about any of them, don't hesitate to
ask. We're here to help! This is simply a reminder of what we are going
to look for before merging your code._
- [ ] I have read the
[CONTRIBUTING](https://github.com/OPCFoundation/UA-.NETStandard/blob/master/CONTRIBUTING.md)
doc.
- [ ] I have signed the
[CLA](https://opcfoundation.org/license/cla/ContributorLicenseAgreementv1.0.pdf).
- [x] I ran tests locally with my changes, all passed.
- [x] I fixed all failing tests in the CI pipelines.
- [x] I fixed all introduced issues with CodeQL and LGTM.
- [ ] I have added tests that prove my fix is effective or that my
feature works and increased code coverage.
- [ ] I have added necessary documentation (if appropriate).
- [ ] Any dependent changes have been merged and published in downstream
modules.
## Further comments
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: romanett <romanett98@gmail.com>
Co-authored-by: Marc Schier <marcschier@users.noreply.github.com>
* GDS: Authorization & SecureChannel hardening (Part 12 §6.5, §7.2, §7.6)
* Fix OnGetCertificates self-admin authorization: pass applicationId to
HasAuthorization so ApplicationSelfAdmin can read its own certificates per
OPC 10000-12 §7.6.10 (was rejecting self-admin pull-management callers).
* Fix OnUnregisterApplicationAsync self-admin authorization: also pass
applicationId (was silently failing the self-admin branch).
* OnUpdateApplication: accept ApplicationSelfAdmin and ApplicationAdmin in
addition to DiscoveryAdmin per §6.5.7. Add self-admin role-permission shim.
* OnGetCertificateStatus: accept CertificateAuthorityAdmin / SelfAdmin /
ApplicationAdmin per §7.6.12 (was using AuthenticatedUserOrSelfAdmin which
is more permissive than spec).
* Introduce ApplicationAdmin privilege (Part 12 §7.2):
- Add GdsRole.ApplicationAdmin static privilege.
- Extend GdsRoleBasedIdentity with AdministeredApplicationIds and a new
constructor accepting the list. WithAdditionalRoles preserves it.
- AuthorizationHelper.HasAuthorization recognises the privilege: alone
when no applicationId is supplied (e.g. RegisterApplication) and
membership-tested against AdministeredApplicationIds otherwise.
- HasTrustListAccess honours the ApplicationAdmin privilege for the
administered applications' trust lists.
- New role lists: DiscoveryAdminOrAppAdmin (RegisterApplication),
DiscoveryAdminOrSelfAdminOrAppAdmin (Update/UnregisterApplication),
CertificateAuthorityAdminOrSelfAdminOrAppAdmin (cert management).
* SecureChannel result-code alignment (Part 12 method tables):
- HasAuthenticatedSecureChannel throws BadSecurityModeInsufficient (was
BadUserAccessDenied).
- Adds requireEncryption flag so callers can demand SignAndEncrypt
(used by future StartNewKeyPairRequest/FinishRequest tightening).
- Sign and SignAndEncrypt are now both accepted as 'authenticated'.
* Tests:
- Register the GDS namespace in AuthorizationHelperTests SetUp so
GDS-namespace role NodeIds do not collide on NodeId.Null with
privilege roles.
- Update HasAuthenticatedSecureChannelThrowsForNonSecureChannel to
expect BadSecurityModeInsufficient.
- Add HasAuthenticatedSecureChannelDoesNotThrowForSign and
HasAuthenticatedSecureChannelWithRequireEncryptionThrowsForSign.
- Add ApplicationAdmin coverage: SucceedsForAdministeredApp,
ThrowsForUnmanagedApp, SucceedsForRegisterApplication,
ThrowsWithEmptyAdministeredList.
- Add NewRoleListsAreCorrectlyPopulated regression test.
The framework already enforces SigningRequired/EncryptionRequired via
DefaultAccessRestrictions in OpcUaGdsModel.xml, returning
BadSecurityModeInsufficient at request dispatch time
(MasterNodeManager.ValidateAccessRestrictions). The model declares the
correct restriction on every admin method, so explicit handler-level
checks would be redundant. Verified manually against §6.5.6, §6.5.7,
§6.5.8, §7.6.4-7.6.10 and §7.6.12.
23 Authorization unit tests pass. 181 unit + 420 integration GDS tests
pass on net10.0; build clean on net48 and net10.0.
* GDS: Audit event correctness (Part 12 7.6, 7.9)
* Fix audit-event ordering: emit CertificateRequestedAuditEvent AFTER the
method outcome is known. Previously the event was raised before
authorization with Status=true, so any failed call appeared in audit as
a successful certificate request and any authorization-denied call
generated a misleading 'success' audit trail.
- OnStartNewKeyPairRequest: refactor to try/catch/finally, emit audit
once with auditException reflecting either the captured throw, the
bad ServiceResult, or null on success.
- OnStartSigningRequestAsync: add the audit emission (previously
missing entirely - 7.9.3 requires it) using the same pattern.
* Redact privateKeyPassword from audit InputArguments. The previous
ApplicationsNodeManager.cs:1206-1223 included the raw password string
as a Variant in the audit event payload, leaking the secret into any
downstream audit sink. The password is now replaced with
AuditEvents.RedactedPrivateKeyPassword (placeholder string).
* OnFinishRequestAsync: build the audit InputArguments from only the
actual method inputs (applicationId, requestId) per 7.6.6 method
signature. Previously the implementation appended the returned
Certificate / PrivateKey / IssuerCertificates to InputArguments, which
leaked the returned PrivateKey into audit payloads.
* Raise CertificateRevokedAuditEventType in OnRevokeCertificate on
success and failure per 7.6.9. The event type was defined in the
model (OpcUaGdsModel.xml:543) but never emitted. Refactored
OnRevokeCertificate with try/catch/finally; sync-over-async (.Result)
is preserved here and addressed separately in Track C (c-revoke-async).
* AuditEvents helper:
- New ReportCertificateRevokedAuditEvent extension method, mirroring
the existing CertificateRequested/Delivered helpers, with an
Exception parameter that drives Status (true on success, false on
failure).
- New RedactedPrivateKeyPassword and RedactedPrivateKey constants
documented as the canonical placeholders. Class-level remarks
instruct callers to redact sensitive arguments before invoking the
helpers.
* Tests:
- AuditEventsTests: lock the placeholder values
(RedactedPrivateKeyPassword and RedactedPrivateKey) so they remain
stable for downstream audit-sink filters.
- Existing 181 unit + 420 integration GDS tests pass on net10.0; build
clean on net48 and net10.0.
b-keycred-audit and b-token-audit remain pending pending Track E and F
respectively (KeyCredentialService and AuthorizationService handlers).
* GDS: Directory / Pull Management correctness gaps (Part 12 6.5, 7.6)
* OnRevokeCertificate converted to async OnRevokeCertificateAsync; uses
await instead of sync-over-async .Result, accepts the method-call
cancellation token, and is now wired through OnCallAsync to integrate
with the async dispatch path. RevokeCertificateAsync helper takes an
optional CancellationToken so callers (OnUnregisterApplicationAsync,
OnRevokeCertificateAsync) can forward it.
* OnCheckRevocationStatusAsync now computes the ValidityTime per
OPC 10000-12 7.6.11. The previous implementation always returned
DateTime.MinValue. The new implementation enumerates the CRLs in the
trusted-issuer store and uses the earliest NextUpdate as ValidityTime
when the chain validates. On Bad results (chain validation failed)
ValidityTime remains DateTime.MinValue so callers re-check
immediately.
* OnFinishRequestAsync returns the issuer chain via a new
BuildIssuerCertificateChain helper. The previous implementation
returned only the immediate signing CA, which is incomplete for
multi-tier CAs per OPC 10000-12 7.6.6. The helper uses
ICertificateGroup.Certificates (in-memory) as the X509Chain
ExtraStore and falls back to the immediate issuing CA if chain
building does not yield a chain. The helper is intentionally
synchronous to avoid contending with concurrent SigningRequestAsync /
NewKeyPairRequestAsync writes against the CertificateGroup's
AuthoritiesStore (which caused parameterised PushTest cases to fail
in parallel runs).
* ValidateApplication (ApplicationsDatabaseBase) now enforces the
reverse-connect rules in OPC 10000-12 6.5.5:
- Server / DiscoveryServer DiscoveryUrls must NOT start with the
"rcp+" prefix.
- Client DiscoveryUrls (when non-empty) must all start with "rcp+"
AND ServerCapabilities must include "RCP".
- ClientAndServer must register at least one non-rcp+ Server
DiscoveryUrl; reverse-connect URLs are still permitted alongside
and require the RCP ServerCapability.
Removed the previous blanket rejection of any DiscoveryUrls on
ApplicationType.Client (which contradicted the spec's reverse-connect
registration pattern).
* Tests:
- RegisterApplicationClientWithRcpDiscoveryUrlsAndRcpCapabilityDoesNotThrow
- RegisterApplicationClientWithRcpDiscoveryUrlsAndMissingCapabilityThrows
- RegisterApplicationServerWithRcpDiscoveryUrlThrows
- RegisterApplicationClientAndServerWithMixedUrlsDoesNotThrow
- RegisterApplicationClientAndServerWithOnlyRcpDiscoveryUrlsThrows
All 188 unit + 420 integration GDS tests pass on net10.0; build clean
on net48 and net10.0.
c-redundancy intentionally requires no enforcement: both transparent
(single application with multiple DiscoveryUrls) and non-transparent
(separate applications with NTRS capability) patterns per OPC 10000-12
6.5.6 are admitted by the validator; transparent redundancy is a
registrant convention rather than a server-enforceable invariant.
* Annex D capabilities: Self-advertise the LDS-ME capability identifier
whenever the MulticastExtension is configured. Previously LdsServer
hard-coded ["LDS"] regardless of whether multicast was running, so
FindServersOnNetwork peers could not distinguish LDS from LDS-ME
instances. Refactored the capability computation into a public static
ComputeServerCapabilities(existing, hasMulticast) helper:
- empty input + no multicast -> ["LDS"]
- empty input + multicast -> ["LDS", "LDS-ME"]
- custom seed list with no "LDS" -> "LDS" is appended
- existing "LDS-ME" is not duplicated
OnServerStarting now wires up the multicast layer first so the
capability set reflects the configured topology.
* Annex C / rcp+ reverse-connect preservation: MulticastDiscovery now
carries the OPC 10000-12 6.5.5 rcp+ DiscoveryUrl prefix end-to-end
through mDNS announce / discover.
- TryBuildProfile strips the rcp+ prefix before parsing the
underlying transport URL (Uri parsing on "rcp+opc.tcp://..." is
brittle across runtimes) and emits a dedicated TXT-record key
ReverseConnectTxtKey ("rc") so receivers can reconstruct it
verbatim.
- OnServiceInstanceDiscovered honours the "rc" key when present
and rebuilds the DiscoveryUrl with the rcp+ scheme.
Exposes MulticastDiscovery.OpcUaServiceType,
MulticastDiscovery.ReverseConnectScheme and
MulticastDiscovery.ReverseConnectTxtKey as public constants so
client code and tests can reference the same values used during
registration and discovery.
* RegisterServer2 fallback (4.2.2): verified that LdsServer overrides
both RegisterServerAsync and RegisterServer2Async, so the LDS
accepts both legacy RegisterServer registrations and the modern
RegisterServer2 + MdnsDiscoveryConfiguration path; no code change
required.
* Tests: new LdsServerStaticTests fixture exercising the capability
computation (six matrix cases) and locking in the Annex C / rcp+
constants (one regression test). 195 unit + 420 integration GDS
tests pass on net10.0; build clean on net48 and net10.0.
* Added Opc.Ua.Lds.Server as a ProjectReference of Opc.Ua.Gds.Tests so
the new tests can use the public static surface of LdsServer and
MulticastDiscovery.
* GDS: Push management hardening (Part 12 7.10)
* d-push-client-multitype: Make ServerPushConfigurationClient.ApplicationCertificateType
settable instead of hard-coded to RsaSha256ApplicationCertificateType.
Callers managing ECC, Brainpool or HTTPS certificates can now override
the default before invoking certificate-management methods (or pass an
explicit certificate type to the methods themselves). Removed the
TODO comment that flagged this limitation.
* d-trustlist-ext: Set Writable / UserWritable to true for the
DefaultApplicationGroup / DefaultHttpsGroup / DefaultUserTokenGroup
TrustList instances in the GDS. Per OPC 10000-12 7.8.2.1 a TrustList
that supports CloseAndUpdate / AddCertificate / RemoveCertificate is
writeable; role-based access controls on the individual methods still
enforce who may actually mutate the trust list. The previous values
(false) were misleading to clients browsing the trust-list nodes.
* d-server-cred-audit: Redact the private key from
CertificateUpdateRequestedAuditEventType InputArguments per OPC 10000-12
7.10.3. ConfigurationNodeManager.UpdateCertificateAsync was passing
the raw private-key ByteString into the audit payload, leaking the
secret to any downstream audit sink. The audit payload now uses
Opc.Ua.Server.AuditEvents.RedactedPrivateKey (an empty ByteString)
as the placeholder; the certificate, issuer chain and key format
remain in the payload so administrators can correlate the request.
Also extended Server.ReportCertificateUpdateRequestedAuditEvent with
an optional Exception parameter so callers can raise the event with
Status=false on failure (parity with the GDS-side helpers).
* Build clean on net48 and net10.0. 195 unit + 420 integration GDS
tests pass on net10.0.
Remaining Track D items (d-create-selfsigned, d-confirm-update,
d-managed-apps, d-alarms, d-push-tests) are larger features that
depend on Track H model additions and are not in scope for this
commit; their todos remain pending.
* GDS: Lock in ServerPushConfigurationClient.ApplicationCertificateType behaviour
Adds ServerPushConfigurationClientStaticTests covering the
Track D quick-win (d-push-client-multitype): the property defaults
to RsaSha256ApplicationCertificateType for backwards compatibility
and is now caller-overridable (e.g. for ECC management).
* GDS: Implement CreateSelfSignedCertificate (Part 12 7.10.6)
* Server-side: ConfigurationNodeManager wires the generated
CreateSelfSignedCertificateMethodState.OnCallAsync handler when the
optional method node exists on the ServerConfiguration instance.
The handler:
- Requires SecurityAdmin access (HasApplicationSecureAdminAccess)
- Validates CertificateGroupId / CertificateTypeId via the existing
VerifyGroupAndTypeId helper
- Creates a self-signed certificate using the CertificateFactory
pipeline (RSA with caller-specified key size, or ECC from the
curve mapped by the certificateTypeId)
- Merges DnsNames and IpAddresses into the SAN extension
- Stores the resulting raw data on the existing
CertificateIdentifier so the resolver can materialise it
- Returns the DER-encoded public certificate to the caller
The method is Optional per the spec; servers that load a nodeset
without it simply skip the wire-up (null guard).
* Client-side: IServerPushConfigurationClient extended with
CreateSelfSignedCertificateAsync; ServerPushConfigurationClient
delegates to the generated ServerConfigurationTypeClient proxy
with the standard elevate/revert permission pattern.
* net48 compat: uses new ValueTask<T>(result) instead of
ValueTask.FromResult which is unavailable on .NET Framework 4.8.
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
* 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
* fix missing mandatory children
* Source generator: fix encoding nodes, EventNotifier, and type RBAC
- Emit DataType encoding nodes (Default Binary/XML/JSON) into the
generated address space. CollectEncodingNodes() discovers
DataTypeEncodingType instances and builds synthetic hierarchies
with their HasEncoding/HasDescription references.
- Auto-set EventNotifier=SubscribeToEvents on Object nodes that have
forward HasEventSource or HasNotifier references. The fix works at
two levels: ModelDesignValidator infers SupportsEvents on types with
event references in design XML, and NodeStateGenerator checks the
resolved reference set for merged instances that inherit references
from their type definitions.
- Wrap AccessRestrictions/RolePermissions in if(forInstance) guards
for ObjectType, VariableType, DataType, and ReferenceType templates
so type definition nodes remain accessible to all users.
- Allow ModellingRule=None Object children on type definitions to be
emitted (e.g. state machine states/transitions).
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Update missing nodes analysis after source generator fixes
Retest with admin credentials against ConsoleReferenceServer v1.05.07.
Categorize 794 truly missing nodes (after filtering optional/placeholder):
- 384 encoding nodes (NodeSet2.xml-only, not in design XML)
- 172 role instance children
- 84 other nodes
- Remaining: trust list, PubSub, diagnostics, etc.
RBAC and EventNotifier fixes confirmed working.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* update
* plans: detailed analysis of 292 remaining missing nodes
Replaced the two previous analysis files with a single consolidated
validation report. Each of the 292 nodes is classified with a reason:
- 212 type-level children (ObjectType definitions not instantiated)
- 48 instance-level children (diagnostics, HA, FileSystem, PubSub)
- 32 orphan property templates (design-time canonical definitions)
Only 1 fix recommended: Server.Auditing (i=2994) should be exposed
as false per Part 5 section 6.3.3.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* feat: add GDS node manager to ConsoleReferenceServer
Add Global Discovery Server functionality to the reference server:
- Add Opc.Ua.Gds.Server.Common project reference
- Add GdsNodeManagerFactory that creates ApplicationsNodeManager
with JsonApplicationsDatabase and CertificateGroup (auto-approve)
- Add GlobalDiscoveryServerConfiguration extension to config XML
- Add GDS to ServerCapabilities
- Registration is opt-in: only when config extension is present
Also fix pre-existing source generator test failures:
- Add missing CreateOrReplaceTransitionNumber stub method to
StateMachineTransitionState in CompilerUtils.cs (8 tests fixed)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* plans: update missing nodes report with GDS retest results
Retested after adding GDS node manager to ConsoleReferenceServer.
Total missing reduced from 1325 to 1243 (82 fewer).
335 remaining 'other' nodes fully classified with per-node reasons.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* plans: Server.Auditing is present (access-restricted, not missing)
Live validation confirmed i=2994 exists with value=true, visible to
admin users. Returns BadUserAccessDenied for anonymous. No fixes needed.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Fix CttTestRunner build errors for v1.6 API and Jint 4.8.0
- Update System.CommandLine 2.0.7 API: SetHandler->SetAction, InvokeAsync->Parse().InvokeAsync()
- Remove ObjectInstance inheritance from CttAssert, CttServiceRegister, CttIdentifierConstants, CttMonitoredItemHelper; use ToJsObject() factory methods instead
- Replace Jint.Native.JsValueType with .IsObject()/.IsNumber()/.IsString() etc.
- Add missing using directives (Jint.Runtime, Microsoft.Extensions.Logging, etc.)
- Fix NodeId.Identifier obsolete -> TryGetIdentifier<uint>
- Fix DataValue.Value obsolete -> WrappedValue.AsBoxedObject()
- Fix ApplicationInstance() obsolete -> ApplicationInstance(ITelemetryContext)
- Fix LoadApplicationConfiguration -> LoadApplicationConfigurationAsync
- Fix CheckApplicationInstanceCertificate -> CheckApplicationInstanceCertificatesAsync
- Fix CoreClientUtils.SelectEndpointAsync signature (requires telemetry param)
- Fix DefaultSessionFactory() obsolete -> DefaultSessionFactory(ITelemetryContext)
- Fix DiscoveryClient.Create -> DiscoveryClient.CreateAsync
- Fix FindServers/GetEndpoints -> FindServersAsync/GetEndpointsAsync
- Fix StatusCode to uint conversions
- Fix ArrayOf<T> iteration (use foreach instead of LINQ on IConvertableToArray)
- Fix XmlNodeList null coalescing in CttProjectSettings
- Fix JsValue.False -> JsValue.FromObject(engine, false)
- Add --json option to Program.cs for machine-readable output
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* fix: emit type-level children with ModellingRule=None for all node classes
The source generator's GetChildren method only included
ModellingRule=None children when they were ObjectDesign instances
(state machine states/transitions). This excluded Variables and
Methods that are explicitly defined on types without a modelling
rule, such as:
- ConditionType.ConditionRefresh (Method)
- ConditionType.ConditionRefresh2 (Method)
- ConditionType.SupportsFilteredRetain (Variable)
- ProgramStateMachineType.Creatable (Variable)
- Various TrueState/FalseState display-hint properties
Remove the ObjectDesign restriction so all explicitly defined
type-level children with ModellingRule=None are included in the
generated address space. This adds ~52 previously missing nodes.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* plans: update report after ModellingRule=None generator fix
Type-level children dropped from 261 to 203 (-58) after fixing the
source generator to emit Variables and Methods with ModellingRule=None.
Total 'other' reduced from 335 to 283. No fixes needed for any
remaining nodes.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* plans: all 203 type-level children confirmed present via Read
Verified all 203 'type-level children' exist in the server (none
return BadNodeIdUnknown). They return Good, BadUserAccessDenied,
or BadSecurityModeInsufficient -- all confirming the node exists
but is access-restricted for anonymous users.
All 1,316 export-missing nodes are now accounted for. Zero nodes
are actually missing from the server address space.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Fix CttTestRunner session service methods for CTT JS script compatibility
- Implement ServiceCreateSession with real Session.CreateAsync connection
- Implement ServiceActivateSession with proper response fields
- Implement ServiceCloseSession with session cleanup
- Fix UaSession constructor to provide service methods via CreateServiceObject
- Convert all type constructors from ClrFunction to JS functions for 'new' support
(Jint 4.x ClrFunction does not support [[Construct]])
- Add UaChannel.connect/disconnect stubs for OpenSecureChannel flow
- Add UaDiscovery with getEndpoints/findServers from discovery session
- Add missing types: UaSubscriptionDiagnosticsDataType, UaHistoryUpdateResult, etc.
- Add missing enums: IdentifierType, Constants (DateTime/numeric limits)
- Add UaPkiCertificate.fromDER, UaByteString.fromStringData, PkiType, UaPkiUtility
- Add UaDateTime.Now constructor, equals/msecsTo methods
- Add UaStatusCode with isGood/isBad/isUncertain as JS constructor
- Fix response headers with Timestamp (UaDateTime), ServiceDiagnostics, StringTable
- Fix endpoint descriptions with Server, UserIdentityTokens, ServerCertificate
- Add CreateResponseHeader helper for consistent response header construction
- Override warnOnce.js loggers to avoid Function.caller incompatibility
- Add stopTest, checkResourceError (lowercase) global functions
- Add UaOpcServer constructor with all method stubs
- Handle JS parse errors in include() for malformed CTT files
- Test.Connect() now calls InstanciateHelpers with DiscoverySession
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Add CttTestRunner: .NET replacement for CTT JavaScript host environment
Implements a Jint-based JavaScript engine that can execute the OPC Foundation's
Compliance Test Tool .js test scripts using the OPC UA .NET Standard stack.
Features:
- Parses CTT .ctt.xml project files (Qt AbstractItemModelData format)
- Loads and resolves CTT include() dependency chains (~100 library files)
- Registers ~250 Ua* type constructors for JavaScript
- Implements session.read/write/browse/getEndpoints/findServers
- Provides all OPC UA enumerations, NodeId constants, Assert methods
- CLI with --list, --file, --conformance-unit, --result, --json flags
- Headless operation for agent/CI integration
Current status: Framework connects to OPC UA server and loads CTT test
infrastructure. Session establishment flow needs additional property
compatibility for CreateSession/ActivateSession request objects.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* fix: do not apply DefaultAccessRestrictions/DefaultRolePermissions to type definitions
ObjectType and VariableType nodes should never have access
restrictions or role permissions from DefaultAccessRestrictions/
DefaultRolePermissions. These defaults are meant to apply to
instances of the type, not to the type definition node itself.
Previously, CertificateGroupType, TrustListType, SecurityGroupType
and other types were incorrectly emitted with AccessRestrictions
inherited from their DefaultAccessRestrictions, making them
unreadable without encryption even though the spec defines no
restrictions on these type definitions.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* CttTestRunner: fix session establishment flow
- Fix constructor patterns (new/no-new dual call support)
- Fix ResponseHeader with ServiceDiagnostics/StringTable
- Populate ServerNonce, ServerCertificate, ServerEndpoints in CreateSession response
- Add UaVariant setter methods (setNodeId/setString/setBoolean/etc.)
- Add UaCreateSessionRequest/ActivateSessionRequest with proper nested structures
- Fix UaPkiUtility/UaPkiCertificate with Thumbprint/toDERFile/loadCertificateFromFile
- Add missing enums: PerformUpdateType, SecurityPolicy, StructureType, etc.
- Add HostInfo, Bit helper, KeyPairCollection, ExpectedAndAcceptedResults
- Add _error.store(), MessageSecurityMode.toString()
Status: Session creates successfully, CreateSession validation runs,
hits validateCertificate in PKI chain (next to implement).
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* plans: update report after DefaultAccessRestrictions type definition fix
ObjectTypes no longer have incorrect access restrictions. Type
children reduced from 203 to 164 (39 now visible). Total export-
missing reduced from 1316 to 1146. Remaining 164 type children are
individual methods/variables with spec-correct access restrictions.
Two source generator fixes applied:
- ModellingRule=None children for Variables/Methods
- DefaultAccessRestrictions not applied to ObjectType/VariableType
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* CttTestRunner: fix PKI, cert validation, warnOnce, session response
- Intercept warnOnce.js with Jint-compatible replacement (no Function.caller)
- Add _log.store() global helper
- Add HOSTNAMES/HostnameFromUrl helpers for cert hostname validation
- Add UaPkiCertificate properties: PublicKey, Issuer, Subject, KeyUsage, Hostnames
- Add UaPkiUtility.validateCertificate stub
- Add UaByteString static helpers: FromByteArray, ToByteArray, fromHexString
- Use JS UaNodeId constructor for proper equals() support
- Fill AuthenticationToken and 32-byte ServerNonce in CreateSession response
- Add clone/append to ByteString objects
Session flow: CreateSession validates, ActivateSession reached, hits
Channel.ServerCertificate.clone() (IsSecure check — next to fix).
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* CttTestRunner: complete session establishment, crypto stubs, ByteString helpers
- Add _makeByteString() helper for consistent ByteString objects with clone/append/isEmpty
- Add UaCryptoProvider with asymmetricSign/Verify stubs
- Add UaExtensionObject setter methods (setAnonymousIdentityToken, etc.)
- Fix UaChannel with full properties (RequestedSecurityPolicyUri, IsSecure, etc.)
- Fix duplicate type registrations overriding custom constructors
- Fix ActivateSession response header with ServiceDiagnostics
- Remove UaCreateSessionResponse/ActivateSessionRequest/CloseSessionRequest duplicates
Status: Full session lifecycle works (GetEndpoints → OpenSecureChannel →
CreateSession → ActivateSession). Test scripts execute and hit server
capabilities initialization (MonitoredItem NodeId settings configuration).
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* update
* plans: add spec references for access restriction reasoning
Added links to Part 3 sections 5.2.9, 5.2.11, and 6.3.3 explaining
why DefaultRolePermissions are applied to instance children but not
to type definitions. The NodeSet2.xml has no explicit RolePermissions
on these 164 nodes -- restrictions come from model design defaults.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* fix: add GDS project references to ConsoleReferenceServer Dockerfile
Add Opc.Ua.Gds.Common and Opc.Ua.Gds.Server.Common csproj COPY
lines to the Docker restore layer, required since the GDS node
manager was added to the ConsoleReferenceServer.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* update
* feat: add IsPartOfTypeHierarchy flag to bypass access restrictions on types
Type hierarchy nodes (ObjectType/VariableType definitions and their
children) should be universally accessible regardless of
AccessRestrictions and RolePermissions.
Changes:
- Add IsPartOfTypeHierarchy property to NodeState
- Set flag on ObjectType/VariableType in generated code (!forInstance)
- Propagate flag from parent to children in AddPredefinedNode
- Add flag to NodeMetadata, propagate in GetPermissionMetadata
- Bypass ValidateRolePermissions and ValidateAccessRestrictions
when IsPartOfTypeHierarchy is true
- Revert isTypeDefinition guard: AccessRestrictions and
RolePermissions are now emitted on all nodes as metadata,
but enforcement is skipped for type hierarchy nodes
- Fix forInstance propagation in type factories: use
forInstance: forInstance for type children so deep children
(TrueState/FalseState etc.) are included when !forInstance
Type-level missing nodes reduced from 201 to 99. Remaining 99 are
in the server but not reachable by the export tool's browse path.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* plans: update report with final IsPartOfTypeHierarchy results
Missing from export reduced to 998 (from 1325 original).
Type children: 201 -> 99 (forInstance propagation fix).
All nodes verified present via OPC UA Read.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* fix: propagate IsPartOfTypeHierarchy in GetNodeMetadataAsync
The Browse service's per-reference ValidateRolePermissionsAsync
calls GetNodeMetadataAsync (not GetPermissionMetadataAsync). The
IsPartOfTypeHierarchy flag was only set in GetPermissionMetadataAsync,
causing type hierarchy nodes to be filtered out of Browse results.
This fixes 99 ObjectType children that were previously invisible
in Browse from their parent types. Type-level missing: 99 -> 0.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* plans: final report -- 0 type-level children missing (694 total)
Type-level missing: 99 -> 0 after fixing IsPartOfTypeHierarchy
propagation in GetNodeMetadataAsync. Total export-missing: 694
(384 encoding + 236 access-restricted + 74 instance/orphan).
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* update
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Concrete sub-types of the abstract OptionSet DataType (i=12755, e.g. AccessRights, CarExtras, OptionSetBase) were silently skipped by ComplexTypeSystem.LoadBaseStructureDataTypesAsync when only an EnumDefinition or OptionSetValues property was available. This change registers them with a new runtime class Opc.Ua.Encoders.OptionSet that reuses the generated Opc.Ua.OptionSet wire format (Value/ValidBits ByteStrings) and self-registers via IEncodeableType.
Key changes:
- New Stack/Opc.Ua/Types/OptionSet.cs with EnumDefinition-driven bit accessors (by name and index), GetSetFieldNames helper, and a fixed ByteLength derived from the highest declared bit per OPC UA Part 3 paragraph 8.40 / 3.2.8. SetBit throws ArgumentOutOfRangeException outside that range and always materializes Value/ValidBits to the fixed length.
- New AddOptionSetType entry point on IComplexTypeBuilder (source-breaking addition for custom implementations); DefaultComplexTypeBuilder implements it. The Reflection.Emit ComplexTypeBuilder throws NotSupportedException.
- ComplexTypeSystem detects OptionSet descendants via a HasSubtype walk and resolves the EnumDefinition from DataTypeDefinition or the OptionSetValues property fallback before the old skip path.
- Removed stale V1.04 OptionSet limitation remark from ComplexTypeSystem.
- 10 unit tests in Tests/Opc.Ua.Client.Tests/ComplexTypes/DefaultOptionSetTests.cs covering factory registration, bit accessors, binary round-trip via ExtensionObject, hand-crafted Part 6 wire format, Clone/CreateInstance semantics, and the ByteLength invariant.
- Live-verified against opc.tcp://DESKTOP-BGFJS91:48010 (UA C++ SDK demo): AccessRights/CarExtras/OptionSetBase now appear in the registered custom-type list; no skip-log entries; LoadAsync(throwOnError:true) returns true.
- Docs/ComplexTypes.md Known Limitations reworded; Docs/MigrationGuide.md gains an OptionSet DataType support subsection.
UInteger-backed OptionSet DataTypes remain intentionally opaque (carried as their unsigned integer in a Variant).
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* merged security changes
* Tailor SecurityPolicyUri for format expected in s_securityPolicyUriToInfo
* Enhance security policy handling and key computation logic
* Merge SecurityEnhancements.
* Add support for SessionTransferToken. Removed obsolete SoftwareCertificate code.
* Fix NonceLength for None.
* Add support for RSA_DH, more fixes from IOP testings.
* Finish implementation of SecureChannelEnhancements.
* Rename EccUtils.cs to CryptoUtils.cs
* Address feedback from reviewers.
* Fix CoPilot flagged spelling errors.
* Rename EccUtils to CryptoUtils
* Update version from 1.5.378-preview to 1.5.378
* Fix unit tests.
* Allow SignatureData.Algorithm to be NULL or Empty.
* Fix issue with BrainPool_p256r1_ChaChaPoly
* Fix RSA_DH_AesGcm
* Fix OSC/padding by deriving HMAC keys, tightening symmetric size math, and correcting ECC_brainpoolP384r1/Basic128Rsa15 IV, signature, padding, and nonce parameters.
* Policies without asymmetric encryption (ECC) return the plaintext when encrypting user tokens; this prevents null payloads from causing BadIdentityTokenInvalid.
* Reserve outer CBC padding for avoiding SymetricEncryptAndSign->AddPadding to overwrite next fields (signature)
* Nonce stored as byte array in SessionConfiguration; Sesion snapshot restores ServerNonce and reconstructs ECC ephemeral key Nonce from bytes and policy
* Added _AesGcm and _ChaChaPoly variants to BuildSupportedSecurityPolicies() for all six ECC certificate types (nistP256, nistP384, brainpoolP256r1, brainpoolP384r1, curve25519, curve448) to SecurityConfiguration. Added Sign and SignAndEncrypt endpoints for the four ECC AesGcm/ChaChaPoly policy pairs (nistP256, nistP384, brainpoolP256r1, brainpoolP384r1) to ServerFixture.
* make ephemeralKeyPolicyUri nullable
* GenerateSecret also for NET7 and NET8
* Adjust Basic128Rsa15 policy properties for backword compatibility
* Exclude unsuported AEAD policies from .NET Framework client tests
* Addapt to new changes (still build fail)
* Addapt code to make it compile
* Fixed failing build on net48 (by ignoring potential null ref which is not reported on other newer targets)
* Preserve the certificate reference in Clone() so copied handlers can still sign
* Remove extra code and addapt to existing master configuration settings
* Filter *_AesGcm and *_ChaChaPoly security policies based on actual runtime support, so unsupported AEAD policies are not advertised or selected on older frameworks
* Expand ECC/RSA policy test coverage and keep Basic128Rsa15 nonce length backward-compatible
* Fix ReconnectSessionOnAlternateChannel _AES and _ChaCha policies
* Fixed IgnoreIfPolicyNotAdvertised so it now fetches endpoints on-demand (instead of relying on Endpoints being preloaded by earlier tests), which avoids false ignores when running tests directlyy
* Merge with commit 5e627f2ca1 from secure-channel-enhancements-2025-11 branch
* minor log mesatge formating
* Fix ClientLockoutTests
* Add ServerFixture policies upfront only if framework and runtime capability supports them
* A few cosmetic/config changes as review sugested
* Moved the session/security handling from StandardServer into a dedicated helper
* use X509IdentityTokenHandler from secure-channel-enhancements-2025-11
* Removed unused Opc.Ua.Types.UnitTests.csproj
* test(client): fix Basic128Rsa15 reconnect token-policy coverage
Advertise an explicit Basic128Rsa15 user token policy in the test fixture and tighten the reconnect test preconditions for non-advertised policies.
* test(client): fix session nonce persistence test helpers
Replace the generic reflection helpers in SessionTests with explicit client/server nonce accessors that match the actual field types.
Add a short Session comment to explain why client and server nonces currently use different representations.
* Merge branch 'master' into secure-channel-enhancements-2025-11-merge5
Merge with latest master and fix conflicts.
* Removed unused Opc.Ua.Types.UnitTests.csproj
* test(client): fix Basic128Rsa15 reconnect token-policy coverage
Advertise an explicit Basic128Rsa15 user token policy in the test fixture and tighten the reconnect test preconditions for non-advertised policies.
* test(client): fix session nonce persistence test helpers
Replace the generic reflection helpers in SessionTests with explicit client/server nonce accessors that match the actual field types.
Add a short Session comment to explain why client and server nonces currently use different representations.
* Build fixes
* Fix build
* update
* Minor updates
* Fix tests
* Add code to check all Endpoints.
* Update Design files to 1.05.7
* Run code fixers, add missing docs
* Fix build
* Revert removal of using
* Increase build timeout
---------
Co-authored-by: mrsuciu <Mircea-Adrian.Suciu@Softing.com>
Co-authored-by: Randy Armstrong <randy@sparhawksoftware.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
* Improve logging and fix UserNameIdentityToken to return BadIdentityTokenInvalid for failed verification
Refactor DataChangeQueueHandler to return overflow status from QueueValue and Enqueue, updating MonitoredItem to log overflows accurately. Update IDataChangeQueueHandler interface accordingly. Enhance ConsoleTelemetry logger configuration management and ensure proper disposal of old logger factories.
Change UserNameIdentityToken password/nonce failure to return BadIdentityTokenInvalid for more precise error reporting. To prevent the leakage of information useful to attackers, Servers shall ensure that the process of validating UserIdentityTokens completes in a fixed interval independent of whether an error occurs or not. The process of validation includes decrypting, check for padding and checking for a valid nonce. If any errors occur the return code is Bad_IdentityTokenInvalid.
* fix GDS ApplicationNames to include the Locale
* fix ctt testcase by allowing faster sampling for XmlNodeNode
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
* Refactor string usage for secrets (#394)
Strings are immutable and the lifetime of secrets can not be controlled.
Use byte[] or char[] instead of strings for secrets, which can be erased
after use.
* Clear pw
---------
Co-authored-by: Martin Regen <7962757+mregen@users.noreply.github.com>
* extend MonitoredItem manager
* Update MonitoredItem List with event montiored items
* Update comments
* Add SetMonitoringMode function call to SubscriptionTest
* Enable use of Sampling Groups in Reference Node Manager
* set minimum sampling interval for Sampling Groups
* Dispose SamplingGroups on shutdown and cleanup
* Use Central Package Management
* Add Directory.Packages.props to solution files
* remove sourcelink version from common.props
* remove old entry from signlist
* remove .net 6 target
remove conditional packages
remove debug flag from pubsub
* Remove net 6 from azp
* Update Nuget Packages
* Update missed pipeline
* Add net 8 App Target framework
* fix asn1 package reference
* remove more net 6 references from AZP
* move main pipeline to net 8
* install net 8 in runners
* install net 8 in CC yml pipeline