3.8 KiB
Parity — rustdesk-server
The recipe-maintainer corpus has no recipe-info/rustdesk-server/ directory — rustdesk-server
was never in the recipe-maintainer parity suite (this is a fresh 2026-10-30 enrollment, requested
as a one-off upgrade of a single-client production deploy). So this PARITY.md documents the
cc-ci-authored suite as the baseline.
The recipe's shape (why the suite looks like this)
rustdesk-server is not HTTP-native: hbbs (rendezvous/registry) + hbbr (relay) speak a
hand-rolled protobuf protocol on host-published ports 21115-21119 (21116 also UDP; 21118/21119
websocket). There is no web UI, no HTTP API, and the stock compose's traefik labels point at a
port nothing serves. The cc-ci ENVIRONMENTAL overlay (compose.ccci.yml) adds a status
sidecar serving exactly hbbs's generated identity PUBLIC key at /id_ed25519.pub — the HTTP
health gate then asserts real app state (the key only exists because hbbs minted it), never a
canned page. The private key + sqlite peer DB in the same volume are asserted UNREACHABLE.
Host ports need no overlay: the stock compose publishes them mode:host, so protocol tests run
on-host at 127.0.0.1 (the mumble pattern).
Recipe-specific tests (≥2 beyond the generic floor)
| cc-ci file | what's verified | why non-vacuous |
|---|---|---|
custom/test_rendezvous_ports.py |
All 5 stock host-published ports (21115-21119) accept TCP; 21116 holds 3 consecutive connects. | The recipe's entire function is serving those ports; a missing/failed bind (e.g. a compose port change upstream) is named per-port. |
custom/test_websocket_handshake.py |
Real 101 Switching Protocols upgrades on hbbs :21118 and hbbr :21119. |
These are the app's own client-facing protocol listeners; a bare GET gets NO response, so 101 can only come from a genuinely serving hbbs/hbbr (verified live on 1.1.12 and 1.1.16). |
custom/test_identity_key.py |
hbbs's ed25519 identity key read back through THREE independent surfaces — HTTPS status route (via Traefik), hbbs's own Key: startup log, the volume file — asserted EQUAL and a valid 32-byte key; plus the private key / DB paths asserted 404. |
The §4.3-style round-trip of the recipe's defining generated state; a crash-looping hbbs (no key) fails, a routing gap fails, a surface mismatch (reading another deployment) fails, and an exposure fails. |
custom/test_punch_hole_no_amplification.py |
An unauthenticated UDP punch-hole request gets NO response on ≥1.1.16, while a register_peer sanity probe on the same socket IS answered. | The security regression test for the 1.1.16 amplification fix (GH #670, actively exploited pre-fix even with -k _). The in-test register_peer response proves silence means "fixed", not "broken"; a regression turns this RED naming the layer. Empirical baseline recorded in the file (1.1.12 answered 3/3, 1.1.16 silent 3/3). Version-gated per STYLE §2. |
Backup data-integrity
The stock recipe declares no backupbot.backup labels — backup/restore tiers auto-skip
(intentional non-run, auto-detected). Nothing here weakens that; if the recipe grows backup
support upstream, the generic tiers pick it up automatically.
Deferred
- A full register_pk/punch-hole EXCHANGE between two registered peers (proving the happy-path connection flow, not just the refusal) — needs the client-side crypto handshake (signed pk registration); the register_peer + ws + punch-hole surfaces already cover the server's externally observable behavior. Revisit if upstream changes the rendezvous flow.
- Host-port contention: 21115-21119 are unique to this recipe, but two CONCURRENT rustdesk deploys (e.g. a cold run racing a canonical reattach) would collide on them — same exposure mailu (25/465/587) and lasuite-meet (7882) already carry as host-port recipes. Cadence makes a collision rare; a failed deploy is loud and re-runnable.