ADR 0016: Northbound gRPC Stack Exception (gNMI)
Status
Accepted
Date
2026-06-13
Context
ADR 0014 §3 states: "No gRPC stack (tonic/prost) in SDK crates. … A future
exception requires an ADR, not a Cargo.toml edit." That rule keeps the core
SDK dependency graph lean and auditable: internal transports use hand-specified
framing over tokio/rustls, and external 3GPP interfaces are HTTP/2 (hyper) or
raw protocol codecs.
The management-plane work introduces opc-gnmi-server (see
docs/design/opc-gnmi-server-spec.md).
gNMI (OpenConfig) is a gRPC service:
its contract is a protobuf service over HTTP/2. There is no rustls/hyper-only
or hand-framed path to a conformant gNMI server — a client (gnmic, gNMIc,
OpenConfig collectors) speaks gRPC and nothing else. So opc-gnmi-server cannot
exist without a gRPC stack, and per ADR 0014 §3 that requires this ADR.
gNMI is a distinct dependency category from the cases ADR 0014 §3 was written for. It is a northbound management interface embedded by a CNF that chooses to expose gNMI — not an internal SDK transport and not a 3GPP data-plane codec.
Decision
Permit tonic, prost, and prost-types only for the northbound gNMI server
crate, opc-gnmi-server. prost-types is included because the vendored
OpenConfig gNMI proto uses standard Google protobuf types such as
google.protobuf.Any. tonic-build is permitted only as that crate's
build-time proto-generation dependency if the Phase-0 spike chooses build-time
generation. Any future gRPC-based management crate requires an explicit ADR
amendment and an update to the mechanical allow-list; this exception is not a
blanket "management crates may use gRPC" policy. Specifically:
- Scope boundary.
tonic/prost/prost-typesMUST NOT appear in any core SDK crate (opc-config-bus,opc-config-model,opc-persist,opc-runtime,opc-identity,opc-tls,opc-nacm,opc-yanggen, theopc-proto-*codecs,opc-sbi, theopc-mgmt-*foundation crates, etc.). They live only inopc-gnmi-serverunless this ADR is amended. ADR 0014 §3 remains in force everywhere else. Inside this SDK workspace, no other crate may depend on or re-exportopc-gnmi-server; downstream CNFs outside the workspace opt in to gNMI by depending on the server crate directly. - Boundary is enforced mechanically.
scripts/check-management-plane-policy.py --checkasserts that no crate outside the explicit allowed set directly or transitively depends ontonic/prost/prost-types/tonic-build, or onopc-gnmi-serveritself. The CI job runs this gate. The initial allowed set is exactlyopc-gnmi-server. - One TLS stack only (ADR 0014 §1 preserved).
opc-gnmi-serverserves tonic over therustls::ServerConfigproduced byopc-mgmt-transport(ringprovider), not tonic's own/native TLS. Noopenssl/native-tlsenters the graph (verifytonic/hyperfeatures withdefault-features = false, rustls only). - Dependency hygiene (ADR 0014 §6/§7).
tonic/prost/prost-typesare MIT/Apache — compatible with the license gate. The PR adding them justifies them per §7 and passescargo deny. The pinnedtonicversion MUST compile on the workspace MSRV (currently 1.88, ADR 0014 §5); the Phase-0 spike validates this before the version is pinned, and any MSRV bump follows the §5 process. - Proto pin and generation mode. The gNMI proto is vendored at an exact tag
under
crates/opc-gnmi-server/proto/; the vendored files carry the upstream tag/commit in their header, and the advertised gNMI version string derives from this pin. The Phase-0 spike must choose and document exactly one generation mode:- build-time generation with
tonic-build, which adds an explicitprotocbuild prerequisite and a CI check that generated output is reproducible; or - checked-in generated Rust, which avoids
protocin downstream builds but requires a regeneration script and a CI drift check. In either mode, generated service code is treated as part of theopc-gnmi-serverboundary and does not become a shared SDK dependency.
- build-time generation with
- This exception does not generalize. It authorizes a gRPC server for a northbound management protocol that is gRPC by definition. It is not license to adopt gRPC for internal transports or to relax ADR 0014 §3 for core crates.
Consequences
- A downstream CNF outside this workspace that embeds
opc-gnmi-serverinheritstonic/prost/prost-types. That is an explicit opt-in to gNMI; CNFs that do not expose gNMI never pull the stack. - The core SDK graph stays gRPC-free and auditable, exactly as ADR 0014 §3 intends; only the optional northbound server adds gRPC.
- The mechanical gate from point 2 exists and runs in CI, so this exception's scope cannot silently erode — the same "implicit policy does not survive maintenance" lesson that motivated ADR 0014.
- NETCONF (
opc-netconf-server) is unaffected: it is XML over SSH/TLS and needs no gRPC stack.