feat(tunnel): VNC bridge tunnel mode (VA-19) #19

Merged
David merged 1 commit from feat/vnc-bridge-va-19 into main 2026-05-19 03:37:44 +02:00
Owner

Summary

Closes VA-19. Adds USAGE_VNC = 6 to the rendezvous tunnel dispatcher. On open, the agent picks a free ephemeral port on 127.0.0.1, spawns x11vnc (X11) or wayvnc (Wayland) bound to loopback, waits up to 5 s for the helper to accept, and then proxies bytes both ways between the relay WS and the helper's TCP socket. Helper selection is environment-driven; WAYLAND_DISPLAY wins over DISPLAY because Plasma-on-Wayland hosts often still export an Xwayland DISPLAY.

The agent never speaks RFB. Auth is the rendezvous tunnel's own auth plus the loopback bind; helpers run with -nopw / no built-in auth.

What's in the diff

  • crates/meshagent/src/host/vnc.rs (new): helper detection, ephemeral-port pick, helper spawn with kill_on_drop, readiness poll, and the bidirectional pump (run + the standalone pump for tests).
  • crates/meshagent/src/host/tunnel.rs: USAGE_VNC constant, dispatch arm, docstring entry, and pub(super) control_echo so the new module reuses the existing rtt-probe parser. Also adds #![allow(clippy::doc_overindented_list_items)] at the module level to unblock CI (clippy 1.94 flags the hand-aligned n -> ... list in the crate docstring; reformatting would obscure the layout).
  • crates/meshagent/src/host/mod.rs: register the new module.
  • README.md: new "Runtime dependencies" section listing x11vnc / wayvnc as optional per-tunnel-mode helpers.

Test plan

  • cargo test --workspace --lib (17 lib tests + 7 new vnc tests pass).
  • cargo clippy --workspace --all-targets -- --deny warnings (clean).
  • cargo fmt --all --check (clean).
  • just pre-commit (full docker check: fmt + clippy + build + tests, all green).
  • Manual: spawn an x11vnc server through the tunnel against a real SPA, connect a TigerVNC client end-to-end. Deferred to a follow-up once the server side knows how to issue a USAGE_VNC = 6 tunnel.
## Summary Closes VA-19. Adds `USAGE_VNC = 6` to the rendezvous tunnel dispatcher. On open, the agent picks a free ephemeral port on 127.0.0.1, spawns `x11vnc` (X11) or `wayvnc` (Wayland) bound to loopback, waits up to 5 s for the helper to accept, and then proxies bytes both ways between the relay WS and the helper's TCP socket. Helper selection is environment-driven; `WAYLAND_DISPLAY` wins over `DISPLAY` because Plasma-on-Wayland hosts often still export an Xwayland `DISPLAY`. The agent never speaks RFB. Auth is the rendezvous tunnel's own auth plus the loopback bind; helpers run with `-nopw` / no built-in auth. ## What's in the diff - `crates/meshagent/src/host/vnc.rs` (new): helper detection, ephemeral-port pick, helper spawn with `kill_on_drop`, readiness poll, and the bidirectional pump (`run` + the standalone `pump` for tests). - `crates/meshagent/src/host/tunnel.rs`: `USAGE_VNC` constant, dispatch arm, docstring entry, and `pub(super) control_echo` so the new module reuses the existing rtt-probe parser. Also adds `#![allow(clippy::doc_overindented_list_items)]` at the module level to unblock CI (clippy 1.94 flags the hand-aligned `n -> ...` list in the crate docstring; reformatting would obscure the layout). - `crates/meshagent/src/host/mod.rs`: register the new module. - `README.md`: new "Runtime dependencies" section listing `x11vnc` / `wayvnc` as optional per-tunnel-mode helpers. ## Test plan - [x] `cargo test --workspace --lib` (17 lib tests + 7 new vnc tests pass). - [x] `cargo clippy --workspace --all-targets -- --deny warnings` (clean). - [x] `cargo fmt --all --check` (clean). - [x] `just pre-commit` (full docker check: fmt + clippy + build + tests, all green). - [ ] Manual: spawn an x11vnc server through the tunnel against a real SPA, connect a TigerVNC client end-to-end. Deferred to a follow-up once the server side knows how to issue a `USAGE_VNC = 6` tunnel.
feat(tunnel): VNC bridge tunnel mode (VA-19)
Some checks failed
Check / clippy + fmt + tests (pull_request) Failing after 45s
acf14d14d5
Add USAGE_VNC=6 tunnel mode that proxies the rendezvous WebSocket to a locally-spawned RFB helper (`x11vnc` on X11, `wayvnc` on wlroots / KDE Wayland) bound to 127.0.0.1. The agent never speaks RFB; it is a raw byte-pipe inside the already-authenticated rendezvous tunnel, in the same spirit as `host::tcpforward` but framed as binary WS instead of base64-in-JSON.

Helper selection is environment-driven (`$WAYLAND_DISPLAY` takes precedence over `$DISPLAY`), the helper is spawned with `kill_on_drop` so it goes down with the tunnel, and the agent polls TCP `connect` on the chosen ephemeral port with a 5 s budget before giving up. WS text frames matching the SPA's `ctrlChannel` rtt probe are echoed back; all other text is dropped.

Lifts `tunnel::control_echo` from private to `pub(super)` so the new `vnc.rs` module can reuse the existing rtt-probe parser instead of duplicating the JSON shape. Adds a module-level `#![allow(clippy::doc_overindented_list_items)]` to `tunnel.rs` to unblock CI: the hand-aligned `n -> ...` list in the crate-level docstring is flagged by clippy 1.94 but reformatting would obscure the layout.

Documents the optional helper deps in README.md under a new "Runtime dependencies" section.

Tests: 7 new unit tests covering helper detection precedence (Wayland > X11 > none), argv construction (loopback bind for both helpers), bidirectional byte pump through an in-process echo server, `ctrlChannel` rtt-probe echo, clean exit on WS close, and the no-display error path from `run`.

#VA-19 State Done

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
David merged commit 678736d3c5 into main 2026-05-19 03:37:44 +02:00
David deleted branch feat/vnc-bridge-va-19 2026-05-19 03:37:44 +02:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
psa-systems/vervain-agent!19
No description provided.