[WotCon] Add the HTTP, Modbus, OPC UA and MQTT binding executors - #4144
[WotCon] Add the HTTP, Modbus, OPC UA and MQTT binding executors#4144marcschier wants to merge 22 commits into
Conversation
Adds the concrete transports for the WoT binding runtime introduced by the planner layer: HTTP, Modbus TCP, OPC UA and MQTT. The OPC UA executor supports Read, Write, native data change observation, Method invocation and Event subscription, including portable nsu= NodeIds. The Modbus client reconnects a faulted connection on its next transaction and honours the standard modv:pollingTime interval, with backoff left to the polling subscription so there is only one retry loop. MQTT enables TLS for mqtts, defaults to port 8883, and resolves credentials and trust through the injected providers. CoAP, BACnet, PROFINET and LoRaWAN remain planner and validation only; they report their non-executable capability explicitly rather than failing at run time. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 9e6a5abf-3299-4cd1-9855-010fedbf0ad8
The fluent builder generator emits calls to INodeManagerBuilder.VariableFromDataTypeId and to a NodeManagerBuilder constructor overload that carries the data-type lookup, but the runtime side of that API was missing, so every generated node manager failed to compile with CS1729 and CS1061. Adds the VariableFromDataTypeId resolution to the builder interface and implementation, along with NodeStateLookupExtensions.FindByDataType, which is the lookup the builder delegates to and has no other consumer. Resolution reports BadNodeIdInvalid for a null data type, BadNodeIdUnknown when nothing matches, BadBrowseNameDuplicated when the match is ambiguous, and BadTypeMismatch when the resolved node is not a variable. An optional browse name disambiguates a data type that is carried by more than one variable. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 9e6a5abf-3299-4cd1-9855-010fedbf0ad8
|
Fixed the net10.0 solution build failure on this PR. This branch carries the The fix lands in #4132 (where the generator change belongs) and is cherry-picked here so Verified locally: |
DiNodeManager constructed NodeManagerBuilder without the data-type resolver, so
VariableFromDataTypeId reported BadNodeIdUnknown ("no predefined variable has DataType")
for every DI node manager - a misleading error, since the lookup had simply never
been supplied rather than the variable being absent.
Delegates to NodeStateLookupExtensions.FindByDataType rather than hand-rolling the
scan a fourth time in this file.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 9e6a5abf-3299-4cd1-9855-010fedbf0ad8
…-executors # Conflicts: # src/Opc.Ua.Di.Server/DiNodeManager.cs
Thing Descriptions are remote-supplied, so the host in a form's href was an unvalidated outbound request target: the executors would connect to loopback, link-local and private-range addresses, including the cloud instance metadata service, and return the response body to the caller as a readable value. Adds WotEndpointPolicy and WotEndpointValidator and enforces them in WotProtocolBinderRegistry.OpenChannelAsync, the single point through which every executor opens a channel. Loopback and private ranges are denied by default and can be re-enabled per deployment. As with the asset endpoint validator, DNS is deliberately not resolved during validation, because resolving at validation time and again at connect time is itself a request-forgery vector. Also rejects control characters in a form's declared content type, which could otherwise be injected verbatim into outbound request headers, and MQTT topic wildcards, which would subscribe the server to an entire broker namespace under its own identity. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 9e6a5abf-3299-4cd1-9855-010fedbf0ad8
Validate HTTP content types with MediaTypeHeaderValue before assigning request content, and add parser-backed validation for configured default headers and credential headers so CRLF-injected values are rejected instead of written to the wire. Reject MQTT wildcard publish topics at the executor sink even when planning has explicitly opted into wildcard subscribe topics, and add the missing Modbus multiple-register write null and range guards. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 9e6a5abf-3299-4cd1-9855-010fedbf0ad8
|
Security fixes pushed in
Verification:
|
The endpoint policy was applied to a form's own target before the channel opened, but a redirect selects a new target after that check. A permitted origin could therefore bounce the request to a loopback or link-local address - including the cloud instance metadata service - that the initial validation would have refused. Redirect resolution now re-validates each hop against the same policy, so the scheme, downgrade, loop and endpoint gates all apply for the whole chain. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 9e6a5abf-3299-4cd1-9855-010fedbf0ad8
|
Follow-up: closed a bypass in the SSRF fix. The endpoint policy added in the previous commit is applied to a form's own target in
Verified by mutation testing rather than by the tests merely passing: with the new check
|
Opc.Ua.WotCon.Bindings.Mqtt was added without being listed in UA.slnx, so the solution build never compiled it. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 9e6a5abf-3299-4cd1-9855-010fedbf0ad8
There was a problem hiding this comment.
Pull request overview
This PR adds concrete WoT Connectivity binding executors (HTTP, Modbus TCP, OPC UA, MQTT) on top of the previously-landed planner/abstraction layer, and wires in end-to-end + unit test coverage including in-process protocol harnesses.
Changes:
- Add new executor implementations and DI builder extensions for HTTP, Modbus TCP, and OPC UA in
Opc.Ua.WotCon.Bindings. - Introduce a new
Opc.Ua.WotCon.Bindings.Mqttproject containing the MQTT executor implementation and packaging metadata. - Expand
Opc.Ua.WotCon.Bindings.Testswith protocol harnesses and end-to-end tests covering HTTP/Modbus/MQTT/OPC UA execution.
Reviewed changes
Copilot reviewed 47 out of 47 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| UA.slnx | Adds the new MQTT executor project to the solution. |
| tests/Opc.Ua.WotCon.Bindings.Tests/Support/TestModbusServer.cs | Adds an in-process Modbus TCP simulator used by Modbus executor tests. |
| tests/Opc.Ua.WotCon.Bindings.Tests/Support/TestHttpServer.cs | Adds an in-process HTTP/1.1 server used by HTTP executor tests. |
| tests/Opc.Ua.WotCon.Bindings.Tests/OpcUaWotExecutorTests.cs | Adds end-to-end OPC UA executor tests using an in-process ReferenceServer. |
| tests/Opc.Ua.WotCon.Bindings.Tests/OpcUaWotBindingBuilderExtensionsTests.cs | Extends DI builder extension tests to cover new transport executors. |
| tests/Opc.Ua.WotCon.Bindings.Tests/Opc.Ua.WotCon.Bindings.Tests.csproj | Updates test project dependencies and references to include new executors and harnesses. |
| tests/Opc.Ua.WotCon.Bindings.Tests/MqttWotExecutorTests.cs | Adds end-to-end MQTT executor tests against an in-process broker. |
| tests/Opc.Ua.WotCon.Bindings.Tests/MqttWotConnectionTests.cs | Adds unit tests for MQTT connection security policy (mqtt vs mqtts, credential handling). |
| tests/Opc.Ua.WotCon.Bindings.Tests/ModbusWotExecutorTests.cs | Adds end-to-end Modbus executor tests using the in-process Modbus simulator. |
| tests/Opc.Ua.WotCon.Bindings.Tests/ModbusDataConverterTests.cs | Adds unit tests for Modbus register/value conversions. |
| tests/Opc.Ua.WotCon.Bindings.Tests/ModbusDataConverterAdditionalTests.cs | Adds additional Modbus conversion tests covering aliases and byte/word order combinations. |
| tests/Opc.Ua.WotCon.Bindings.Tests/HttpWotExecutorTests.cs | Adds end-to-end HTTP executor tests using the in-process HTTP server. |
| tests/Opc.Ua.WotCon.Bindings.Tests/HttpWotBindingChannelTests.cs | Adds channel-level HTTP executor tests (status mapping, bounds, decoding, polling observe, etc.). |
| tests/Opc.Ua.WotCon.Bindings.Tests/HttpStatusMapperTests.cs | Adds unit tests for HTTP status-code to OPC UA StatusCode mapping. |
| tests/Opc.Ua.WotCon.Bindings.Tests/HttpCredentialResolutionTests.cs | Adds concurrency/race tests for HTTP credential resolution behavior. |
| tests/Opc.Ua.WotCon.Bindings.Tests/ExecutorUnitTests.cs | Adds unit tests for executor identity/dispatch and HTTP sink hardening scenarios. |
| src/Opc.Ua.WotCon.Bindings/OpcUa/OpcUaWotBindingOptions.cs | Adds OPC UA executor options including session factory + observe/event configuration. |
| src/Opc.Ua.WotCon.Bindings/OpcUa/OpcUaWotBindingExecutor.cs | Implements OPC UA executor activation via an injected session factory. |
| src/Opc.Ua.WotCon.Bindings/OpcUa/OpcUaTargetWotBindingBuilderExtensions.cs | Adds DI builder extension to register OPC UA executor + planners. |
| src/Opc.Ua.WotCon.Bindings/Modbus/OpcUaModbusWotBindingBuilderExtensions.cs | Adds DI builder extension to register Modbus executor + planners. |
| src/Opc.Ua.WotCon.Bindings/Modbus/ModbusWotBindingOptions.cs | Adds Modbus executor options and Modbus exception→StatusCode mapping helper. |
| src/Opc.Ua.WotCon.Bindings/Modbus/ModbusWotBindingExecutor.cs | Implements Modbus executor activation and connection lifecycle. |
| src/Opc.Ua.WotCon.Bindings/Modbus/ModbusWotBindingChannel.cs | Implements Modbus channel read/write/observe behavior and status mapping. |
| src/Opc.Ua.WotCon.Bindings/Modbus/ModbusException.cs | Adds Modbus protocol exception type carrying device exception codes. |
| src/Opc.Ua.WotCon.Bindings/Modbus/ModbusDataConverter.cs | Adds Modbus register↔Variant conversion logic with byte/word-order handling. |
| src/Opc.Ua.WotCon.Bindings/Modbus/ModbusAddressing.cs | Adds validated Modbus addressing parsing/validation from compiled forms. |
| src/Opc.Ua.WotCon.Bindings/Http/OpcUaHttpWotBindingBuilderExtensions.cs | Adds DI builder extension to register HTTP executor + planners. |
| src/Opc.Ua.WotCon.Bindings/Http/HttpWotBindingOptions.cs | Adds HTTP executor options (client factory, redirect policy flags, polling, etc.). |
| src/Opc.Ua.WotCon.Bindings/Http/HttpWotBindingExecutor.cs | Implements HTTP executor activation and caller-client safety fail-closed behavior. |
| src/Opc.Ua.WotCon.Bindings/Http/HttpStatusMapper.cs | Implements HTTP status-code to OPC UA StatusCode mapping. |
| src/Opc.Ua.WotCon.Bindings.Mqtt/Properties/AssemblyInfo.cs | Adds assembly metadata for the new MQTT executor project. |
| src/Opc.Ua.WotCon.Bindings.Mqtt/OpcUaMqttWotBindingBuilderExtensions.cs | Adds DI builder extension to register MQTT executor + planners. |
| src/Opc.Ua.WotCon.Bindings.Mqtt/Opc.Ua.WotCon.Bindings.Mqtt.csproj | Introduces the MQTT executor project (TFMs, packaging, references). |
| src/Opc.Ua.WotCon.Bindings.Mqtt/NugetREADME.md | Adds NuGet package README documenting MQTT executor behavior/security rules. |
| src/Opc.Ua.WotCon.Bindings.Mqtt/MqttWotConnection.cs | Implements MQTT connection planning with transport security + credential/trust resolution. |
| src/Opc.Ua.WotCon.Bindings.Mqtt/MqttWotBindingOptions.cs | Adds MQTT executor options (client factory, TLS validation, timeouts, etc.). |
| src/Opc.Ua.WotCon.Bindings.Mqtt/MqttWotBindingExecutor.cs | Implements MQTT executor activation and connection lifecycle. |
| src/Opc.Ua.WotCon.Bindings.Mqtt/MqttWotBindingChannel.cs | Implements MQTT channel read/write/invoke/observe and message dispatch. |
Validate hand-built MQTT subscribe topics, reject concurrent MQTT reads, preserve synthetic OPC UA endpoint ports, and remove blocking waits from test helper teardown. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 9e6a5abf-3299-4cd1-9855-010fedbf0ad8
… into marcschier/wot-12-executors
… into marcschier/wot-12-executors
The HTTP and Modbus channels are the only production callers that create a PollingWotSubscription, so without forwarding the runtime context the disposal diagnostic could never reach a real logger. Both channels already receive a WotExecutorContext, so hand its telemetry to the subscription; the Modbus channel now retains that context the same way the HTTP channel does. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 9e6a5abf-3299-4cd1-9855-010fedbf0ad8
… into marcschier/wot-12-executors
… into marcschier/wot-12-executors
Summary
Stack context
This is PR 12 of the stacked split of integration PR #4093. It is stacked on #4140, where the protocol-agnostic planner layer landed separately, so this PR is limited to the concrete transport implementations.
Validation
dotnet build tests\Opc.Ua.WotCon.Bindings.Tests\Opc.Ua.WotCon.Bindings.Tests.csproj -c Release -p:CustomTestTarget=net10.0 -v:mdotnet test tests\Opc.Ua.WotCon.Bindings.Tests\Opc.Ua.WotCon.Bindings.Tests.csproj -c Release -p:CustomTestTarget=net10.0 --no-build(512 passed)dotnet build src\Opc.Ua.WotCon.Bindings\Opc.Ua.WotCon.Bindings.csproj -c Release -v:mdotnet build src\Opc.Ua.WotCon.Bindings.Mqtt\Opc.Ua.WotCon.Bindings.Mqtt.csproj -c Release -v:m