From 7d6e79551eecb0ee94e394cf34e9722579da5343 Mon Sep 17 00:00:00 2001 From: goodboy Date: Fri, 14 Aug 2026 09:50:48 -0400 Subject: [PATCH] Fix silently-corrupt keys in `parse_wg_maddr()` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `_segments()` called `Multiaddr(maddr)` purely to validate, then swallowed every failure under `except Exception: pass`. That was harmless pre-#108 — w/o a `wg` codec there was nothing to validate — but now that the codec is pinned in, the swallow is load-bearing and disabled: a malformed key sails past validation into `wg8_pubkey()`, which happily emits a corrupt b64 str, and the returned struct then fails its own `.maddr` round-trip. No raise, just quietly wrong output. Deats, - add `_have_wg_maddr_proto()`, the gate plan-03 already referenced but which never actually existed. Impl'd as `protocols.protocol_with_name('wg')` under `except ProtocolNotFoundError` and cached in a mod global, same shape as the TIPC plan's `is_tipc_available()`. - only validate when that gate is `True`, and let `StringParseError` propagate — a maddr which doesn't parse must NOT reach `wg8_pubkey()`. - keep the degraded split for a pre-#108 install, now w/ an explicit `XXX` naming the validation you give up. So parsing stays pure but becomes total-or-raises. Our own `ValueError`s (missing `/wg/` seg, bare tunnel w/o an overlay ep) are unaffected, as is the `wg(8)` b64 round-trip. (this patch was generated in some part by `claude-code` using `claude-opus-5` (`anthropic`)) --- examples/multihost/wg_lan/wg_maddr.py | 67 ++++++++++++++++++++------- 1 file changed, 50 insertions(+), 17 deletions(-) diff --git a/examples/multihost/wg_lan/wg_maddr.py b/examples/multihost/wg_lan/wg_maddr.py index 44d22e0a..0a4c3385 100644 --- a/examples/multihost/wg_lan/wg_maddr.py +++ b/examples/multihost/wg_lan/wg_maddr.py @@ -2,9 +2,9 @@ r''' Parse `wg`-tunnelled multiaddrs into `tractor`-ready addrs. -The canonical form (per py-multiaddr PR #108, verified to parse + -round-trip on that branch) nests the *overlay* endpoint **after** -the `/wg/` segment: +The canonical form (per py-multiaddr #108, verified to parse + +round-trip against its upstream merge) nests the *overlay* +endpoint **after** the `/wg/` segment: /ip4/10.0.0.1/udp/51820/wg/u/ip4/10.0.11.1/tcp/1616 \_______ wg bearer ______/\_ key _/\____ tractor ep _____/ @@ -111,8 +111,10 @@ def parse_wg_maddr( Split a `wg`-tunnelled maddr into its bearer/key/overlay parts. Pure — no I/O. - Uses `py-multiaddr` when it knows the `wg` proto (PR #108), - else falls back to a minimal segment split. + Total-or-raises: with a `wg`-aware `py-multiaddr` (#108) an + unparseable maddr raises instead of yielding a struct built + from garbage segments. See `_segments()` for the degraded + pre-#108 path. ''' segs: list[str] = _segments(maddr) @@ -164,22 +166,53 @@ def parse_wg_maddr( ) -def _segments(maddr: str) -> list[str]: +_wg_proto_known: bool|None = None + + +def _have_wg_maddr_proto() -> bool: ''' - Deliver a maddr's `/`-split segments, preferring the real - parser when it supports `wg`. + True iff the installed `py-multiaddr` knows the `/wg/` proto, + i.e. carries py-multiaddr#108. + + Merged upstream 2026-07-28 but in no release as of `0.2.0`, + hence the `[tool.uv.sources]` `rev` pin. + + Pure predicate; result cached since it can't change without a + reinstall. ''' - from multiaddr import Multiaddr - try: - # the real thing: validates every proto + value + global _wg_proto_known + if _wg_proto_known is None: + from multiaddr.protocols import protocol_with_name + from multiaddr.exceptions import ProtocolNotFoundError + try: + protocol_with_name('wg') + _wg_proto_known = True + except ProtocolNotFoundError: + _wg_proto_known = False + + return _wg_proto_known + + +def _segments(maddr: str) -> list[str]: + ''' + Deliver a maddr's `/`-split segments, validating via the real + parser whenever it knows `wg`. + + ''' + if _have_wg_maddr_proto(): + from multiaddr import Multiaddr + # the real thing: validates every proto + value, incl. + # that the `wg` key decodes to exactly 32 bytes. Let it + # raise — a maddr that doesn't parse must NOT reach + # `wg8_pubkey()`, which would happily emit a corrupt key. Multiaddr(maddr) - except Exception: - # XXX STOPGAP, only until py-multiaddr#108 lands; then - # this branch is dead and `Multiaddr` is authoritative. - # We deliberately DON'T hand-roll a `wg` codec (the whole - # point of gh #429 was dropping the NIH parser). - pass + + # XXX, degraded path for a pre-#108 `py-multiaddr` ONLY: no + # per-segment validation, so a malformed key survives to the + # returned struct. We deliberately DON'T hand-roll a `wg` + # codec (the whole point of gh #429 was dropping the NIH + # parser) — install the pinned rev to get validation back. return [s for s in maddr.split('/') if s]