You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
feat: negotiate NETCONF capabilities and type rpc-errors
Teach sessions to negotiate the shared NETCONF base capability and gate operations against what the server actually advertises.
Add structured RpcErrorException and ValidateException flows, harden rpc-error parsing for namespaced replies, and update commit/load/validate behavior to preserve server detail.
Back the change with unit and integration coverage, Javadocs for the new public API, and a sanitized integration runner/docs path story.
Copy file name to clipboardExpand all lines: README.md
+36-1Lines changed: 36 additions & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -34,6 +34,16 @@ mvn clean package
34
34
```
35
35
(The wrapper script downloads the correct Gradle version automatically.)
36
36
37
+
To run the live NETCONF integration suite with Gradle:
38
+
39
+
```bash
40
+
NETCONF_HOST=192.168.1.1 \
41
+
NETCONF_USERNAME=admin \
42
+
NETCONF_PASSWORD=secret \
43
+
NETCONF_PORT=830 \
44
+
./gradlew integrationTest
45
+
```
46
+
37
47
Releases
38
48
========
39
49
Releases contain source code only. Due to changing JDK licensing, jar files are not released.
@@ -47,7 +57,7 @@ User may download the source code and compile it with desired JDK version.
47
57
* Instructions to build using `mvn`
48
58
* Download Source Code for the required release
49
59
* Compile the code and build the jar using `mvn package`
50
-
* Use the jar file from (source to netconf-java)/netconf-java/target
60
+
* Use the jar file from `./target/`
51
61
* Use `mvn versions:display-dependency-updates` to identify possible target versions for dependencies
52
62
53
63
=======
@@ -56,11 +66,17 @@ v2.2.1
56
66
------
57
67
* Hardened NETCONF XML parsing against XXE and DTD-based attacks
58
68
* Fixed NETCONF RPC framing and `message-id` reply correlation for sequential session reuse
69
+
* Enforced shared NETCONF base capability negotiation and derive session framing from the negotiated base version
70
+
* Capability-gated candidate, validate, and confirmed-commit operations before sending RPCs
71
+
* Added negotiated capability inspection via `Device.getNegotiatedCapabilities()` and `NetconfSession.getNegotiatedCapabilities()`
72
+
* Typed NETCONF `<rpc-error>` replies as structured exceptions so callers can inspect server-reported error details
73
+
* Added `ValidateException` and clarified `validate()` semantics: server `rpc-error` replies throw, while warning-only or other non-`<ok/>` non-error replies still return `false`
59
74
* Improved SSH/NETCONF session cleanup on failed connection or session initialization
60
75
* Fixed shell exec helpers so commands are set, channels are connected, and timeout/cleanup behavior is more predictable
61
76
* Fixed nested XML path construction in the XML helper
62
77
* Documented `NetconfSession` as a sequential request/response channel rather than a concurrent in-flight RPC transport
63
78
* Added [`docs/compatibility.md`](docs/compatibility.md) with current RFC, capability, NMDA, and extension support details
79
+
* Added a dedicated Gradle `integrationTest` task that forwards NETCONF connection settings for live-server testing
64
80
* Upgraded `assertj-core` to `3.27.7` to address `CVE-2026-24400`
* Build one `Device` per target connection and use `try-with-resources` so SSH resources are released predictably.
148
181
* Call `connect()` before issuing RPCs. If `connect()` throws, no usable NETCONF session was established.
182
+
* Inspect `getNegotiatedCapabilities()` after `connect()` if your application needs to branch on server support for candidate, validate, or confirmed-commit behavior.
149
183
* Set `connectionTimeout` and `commandTimeout` explicitly for production use rather than relying on defaults.
150
184
* Prefer NETCONF RPC helpers (`executeRPC`, `getConfig`, `loadXMLConfiguration`, `commit`, and friends) for device operations; use shell helpers only for device-specific workflows that are not available over NETCONF.
185
+
* Treat `ValidateException` as the server-side `rpc-error` path for `validate()`. A `false` return now means the reply was non-error but not a clean `<ok/>`, typically warnings.
151
186
* Shell helper reads are bounded by `commandTimeout`. If you use `runShellCommandRunning(...)`, always close the returned reader so the underlying exec channel is released.
Copy file name to clipboardExpand all lines: docs/compatibility.md
+8-8Lines changed: 8 additions & 8 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -2,7 +2,7 @@
2
2
3
3
This document describes what `netconf-java` currently implements. It is an implementation matrix, not a blanket compliance claim. Interoperability still depends on the server's advertised capabilities and on whether the application stays within the library's supported session model.
4
4
5
-
Mental model: today the library is a synchronous, JSch-backed NETCONF-over-SSH client. Its strongest path is one sequential RPC conversation per `NetconfSession`, with explicit timeouts and explicit cleanup. Core NETCONF 1.0 and 1.1 framing is supported, several Junos workflows are wrapped ergonomically, and the main standards gap is that optional features are not yet enforced uniformly through capability negotiation.
5
+
Mental model: today the library is a synchronous, JSch-backed NETCONF-over-SSH client. Its strongest path is one sequential RPC conversation per `NetconfSession`, with explicit timeouts and explicit cleanup. Core NETCONF 1.0 and 1.1 framing is supported, several Junos workflows are wrapped ergonomically, and optional features are beginning to be enforced through capability negotiation, though coverage is not yet uniform across all extensions.
6
6
7
7
## Status legend
8
8
@@ -18,9 +18,9 @@ Mental model: today the library is a synchronous, JSch-backed NETCONF-over-SSH c
18
18
| Standard / feature | Status | Notes |
19
19
| --- | --- | --- |
20
20
| RFC 6242 SSH subsystem transport |`Supported`|`Device` opens an SSH subsystem channel with `subsystem=netconf` over JSch. |
21
-
| RFC 6241 `<hello>` parsing and generation |`Supported with caveats`|`Hello` parsing/building works, and `Hello.builder()` auto-adds `urn:ietf:params:netconf:base:1.1`. The library does not currently fail the session if the peers do not share a common base capability. |
21
+
| RFC 6241 `<hello>` parsing and generation |`Supported with caveats`|`Hello` parsing/building works, `Hello.builder()` auto-adds `urn:ietf:params:netconf:base:1.1`, and session establishment now fails if the peers do not share a common NETCONF base capability. The remaining caveat is that the client still cannot intentionally advertise only `base:1.0`. |
22
22
| NETCONF 1.0 end-of-message framing (`]]>]]>`) |`Supported`| Legacy framing is still supported for both outbound and inbound messages. |
23
-
| NETCONF 1.1 chunked framing |`Supported`| Chunked framing is enabled when the server `<hello>` advertises`urn:ietf:params:netconf:base:1.1`. |
23
+
| NETCONF 1.1 chunked framing |`Supported`| Chunked framing is selected when both peers share`urn:ietf:params:netconf:base:1.1`. |
24
24
| NETCONF 1.0 server interoperability |`Supported with caveats`| A 1.0-only server can interoperate because the client still advertises `base:1.0` and can read/write legacy framing. |
25
25
| NETCONF 1.0-only client advertisement |`Not implemented`| The client cannot intentionally advertise only `base:1.0`; `Hello.builder()` always injects `base:1.1`. |
26
26
| RPC `message-id` generation and reply correlation |`Supported with caveats`| Missing `message-id` attributes are injected, replies are validated, and sequential same-session alignment is covered by tests. One `NetconfSession` is still a sequential conversation, not a safe multiplexed channel for concurrent in-flight RPCs. |
@@ -35,11 +35,11 @@ Mental model: today the library is a synchronous, JSch-backed NETCONF-over-SSH c
|`<get-config>`|`Supported`| Candidate and running helpers exist. |
38
-
|`<edit-config>` to candidate |`Supported with caveats`|`loadXMLConfiguration(...)` and `loadTextConfiguration(...)` target `candidate`. The API does not expose `test-option`, `error-option`, or capability-gated behavior checks before use. |
39
-
|`:candidate:1.0`|`Supported with caveats`| Candidate-oriented helpers are a primary workflow, but the default client capability still uses the legacy `urn:ietf:params:netconf:base:1.0#candidate` form rather than the RFC 6241 `urn:ietf:params:netconf:capability:candidate:1.0` URN. |
38
+
|`<edit-config>` to candidate |`Supported with caveats`|`loadXMLConfiguration(...)` and `loadTextConfiguration(...)` target `candidate`, and candidate-dependent operations now fail locally when the server did not advertise candidate support. The API still does not expose `test-option` or `error-option`. |
39
+
|`:candidate:1.0`|`Supported with caveats`| Candidate-oriented helpers are a primary workflow and are now runtime-gated against the server `<hello>`, but the default client capability still uses the legacy `urn:ietf:params:netconf:base:1.0#candidate` form rather than the RFC 6241 `urn:ietf:params:netconf:capability:candidate:1.0` URN. |
40
40
|`<commit>`|`Supported`| Standard commit is implemented. |
41
-
|`:confirmed-commit:1.1`|`Supported with caveats`|`commitConfirm(seconds, persistToken)` and `cancelCommit(persistId)`exist, but the default client capability still uses the legacy `base:1.0#confirmed-commit` form instead of the RFC 6241 capability URN. |
42
-
|`:validate:1.0`|`Supported with caveats`|`validate()` is implemented against candidate, but default advertisement still uses the legacy `base:1.0#validate` URI and the call is not capability-gated at runtime. |
41
+
|`:confirmed-commit:1.1`|`Supported with caveats`|`commitConfirm(seconds, persistToken)` and `cancelCommit(persistId)`are runtime-gated. Persist-based flows require modern `confirmed-commit:1.1`, while legacy confirmed-commit remains usable for same-session confirmation flows without `persist`. The default client capability advertisement still uses the legacy `base:1.0#confirmed-commit` form. |
42
+
|`:validate:1.0`|`Supported with caveats`|`validate()` is implemented against candidate and now fails locally when validate support is absent, but default advertisement still uses the legacy `base:1.0#validate` URI. |
43
43
|`<lock>` / `<unlock>`|`Partial`| Candidate lock/unlock helpers exist. There is no first-class running datastore lock helper. |
44
44
|`:writable-running:1.0`|`Partial`| Running config retrieval exists, but there is no `edit-config` helper that targets `running` and the capability is not advertised by default. |
45
45
|`:startup:1.0`|`Not implemented`| No first-class startup datastore copy/delete flows are present. |
@@ -79,7 +79,7 @@ Mental model: today the library is a synchronous, JSch-backed NETCONF-over-SSH c
79
79
## Interoperability caveats worth knowing
80
80
81
81
- Default optional capability advertisement still uses legacy `urn:ietf:params:netconf:base:1.0#...` forms in `Device.DEFAULT_CLIENT_CAPABILITIES`. Many servers accept these, but strict RFC 6241 capability matching may not.
82
-
-Capability negotiation is parsed but not enforced consistently before invoking optional operations. The caller can request candidate, validate, confirmed-commit, or NMDA operations even if the server never advertised them.
82
+
-Candidate, validate, and confirmed-commit flows are now capability-gated before the RPC is sent. Other optional operations are still not enforced uniformly, especially outside the classic RFC 6241 capability set.
83
83
-`NetconfSession` should be treated as a single sequential request/response channel. Use separate sessions for concurrent workflows.
84
84
- The SSH transport is still tightly coupled to JSch. That preserves the current JSch-based deployment model, including existing FIPS-oriented environments, but transport abstraction is future work rather than current behavior.
0 commit comments