From ee17ed9f6e13d955029b2f30c296d036aacc1434 Mon Sep 17 00:00:00 2001 From: goodboy Date: Fri, 14 Aug 2026 09:51:36 -0400 Subject: [PATCH] Update `wg` docs for the merged py-multiaddr#108 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit it lands" framing in plan-03 and the example README was stale in both directions: the branch pin is obsolete, yet you still can't just `pip install multiaddr`. Deats, - §3.2's grammar table is now re-verified against the upstream merge (`f86519da`) rather than only `baudco@wg_support` in a throwaway venv. Also notes the codec enforces a 32-byte key, so a truncated one is a `StringParseError` and not a silently mangled parse. - §1 says merged-but-unreleased; the still-open work is spec registration (py-multiaddr#107 + gh #483). - §3.4 swaps "pin the branch" for the `[tool.uv.sources]` `rev` pin, and fixes the `_have_wg_maddr_proto()` recipe it suggested — probing w/ `Multiaddr('/wg/uAAAA')` now ALWAYS raises bc the codec wants 32B, i.e. that feature-detect would report `False` even w/ the proto perfectly well known. - risk table row goes "#108 not merged" -> "merged but unreleased". - example README: `uv sync` alone now suffices bc of the pin; documents the 32B check and points at `_have_wg_maddr_proto()` as the gate. The one surviving `baudco` mention is deliberate, it records where the grammar was *first* verified. (this patch was generated in some part by `claude-code` using `claude-opus-5` (`anthropic`)) --- ai/tpt-backends/03_wg_tunnel_bindspace.md | 37 ++++++++++++++--------- examples/multihost/wg_lan/README.md | 23 ++++++++++---- 2 files changed, 39 insertions(+), 21 deletions(-) diff --git a/ai/tpt-backends/03_wg_tunnel_bindspace.md b/ai/tpt-backends/03_wg_tunnel_bindspace.md index 78d5f1ed..ffb0dfd3 100644 --- a/ai/tpt-backends/03_wg_tunnel_bindspace.md +++ b/ai/tpt-backends/03_wg_tunnel_bindspace.md @@ -26,10 +26,11 @@ onto `trio` as the library's sans-io layer allows. `/ip4|ip6//tcp/

` and `/unix/

`; a `.../wg/u` maddr raises `ValueError('Unsupported multiaddr protocol combo')`. -- there is no `wg` proto in the multiaddr spec; the first-draft - upstream PR is multiformats/py-multiaddr#108 with key form - `u` (commit `8be3a8b`), tracked by - multiformats/py-multiaddr#107 and gh #483. +- there is no `wg` proto in the multiaddr *spec* yet, but + multiformats/py-multiaddr#108 (key form `u`) is + **merged** as of 2026-07-28 (`f86519da`) — and unreleased, the + latest `0.2.0` predating it. Spec registration is still tracked + by multiformats/py-multiaddr#107 and gh #483. - so **today's deployable story is declarative**: run `wg-quick` out-of-band, parse the maddr, strip to the inner `(host, port)`, verify the pubkey against the live tunnel, @@ -112,9 +113,12 @@ class WGTunnelSpec( ### 3.2 `parse_maddr()`/`mk_maddr()` -Grammar — **verified** against py-multiaddr#108 -(`baudco/py-multiaddr@wg_support`, installed in a throwaway venv; -all three forms below parse *and* round-trip): +Grammar — **verified** against py-multiaddr#108, first on the +`baudco/py-multiaddr@wg_support` branch and re-verified after it +merged upstream (`multiformats/py-multiaddr@f86519da`); all three +forms below parse *and* round-trip. Note the codec also validates +that the key decodes to exactly 32 bytes, so a truncated key is a +`StringParseError`, not a silently-mangled parse: ``` /ip4/192.168.1.50/udp/51820/wg/u/ip4/10.0.11.1/tcp/1616 @@ -169,13 +173,16 @@ Observed protocol-name lists, for writing the `match`: (bearer_names, tunnel_specs, inner_names)`. This is also what makes a wg-inside-wg stack fall out for free. - `mk_maddr()` inverse for `TunnelledAddress`. -- **blocked on upstream**: `Multiaddr('/…/wg/u…')` only parses - once py-multiaddr#108 lands. Until then: pin the branch in the - `wg` extra / dev-group and gate the tests on - `_have_wg_maddr_proto()` (a cheap try/except around - `Multiaddr('/wg/uAAAA')`). Do **not** hand-roll a `wg` parser - in `tractor` — the whole point of #429 was dropping the NIH - parser. +- **pending an upstream release**: py-multiaddr#108 is merged, so + `Multiaddr('/…/wg/u…')` parses — but off a `[tool.uv.sources]` + `rev` pin, since no release carries the codec. Gate the tests + on `_have_wg_maddr_proto()`, implemented as + `protocols.protocol_with_name('wg')` under + `except ProtocolNotFoundError`. Do **not** probe by parsing a + dummy like `Multiaddr('/wg/uAAAA')` — the codec enforces a + 32-byte key, so that raises even when the proto *is* known. Do + **not** hand-roll a `wg` parser in `tractor` — the whole point + of #429 was dropping the NIH parser. ### 3.3 verification helper (pure, composable) @@ -437,7 +444,7 @@ consider doing it *first* for exactly that reason. | risk | mitigation | | --- | --- | | `to_thread` worker runs in the wrong netns | §5.3; pass `netns=` to pyroute2 or pin a worker; test-first | -| py-multiaddr#108 not merged | branch pin + `_have_wg_maddr_proto()` gate; layer A's inner-addr path works regardless | +| py-multiaddr#108 merged but unreleased | `[tool.uv.sources]` `rev` pin + `_have_wg_maddr_proto()` gate; layer A's inner-addr path works regardless | | `TunnelledAddress` leaks into `Endpoint` and breaks `inspect.getmodule()` | unwrap at parse/bindspace boundary; assert `not isinstance(ep.addr, TunnelledAddress)` in `Endpoint.__post_init__` | | privileged ops in a library | never `sudo`; explicit cap probe + actionable error; pre-provisioned is the default | | pyroute2 0.9 asyncio core drags a loop into the actor | option (1) is a *thread*, not a loop; forbid `trio-asyncio` here (§4.1) | diff --git a/examples/multihost/wg_lan/README.md b/examples/multihost/wg_lan/README.md index 64c1b36b..8bea3344 100644 --- a/examples/multihost/wg_lan/README.md +++ b/examples/multihost/wg_lan/README.md @@ -39,16 +39,27 @@ this composed form parses and round-trips ## requirements -The `wg` proto isn't in released `py-multiaddr` yet (`0.2.0` has -no `wg` codec), so until #108 lands: +py-multiaddr #108 is **merged** (2026-07-28) but ships in no +release yet — the latest `0.2.0` (2026-03-17) predates it and has +no `wg` codec. So `pyproject.toml` carries a temporary +`[tool.uv.sources]` `rev` pin at the merge commit, and a plain ```bash -uv pip install 'git+https://github.com/baudco/py-multiaddr.git@wg_support' multibase +uv sync ``` -`wg_maddr.py` degrades to a plain segment split when the codec is -absent, so the examples still run — but you lose per-segment -validation. It deliberately does **not** hand-roll a `wg` codec +gets you a `wg`-aware `multiaddr`. That pin goes away once a +release carries the codec. You also need `multibase`: + +```bash +uv pip install multibase +``` + +Without the codec `wg_maddr.py` degrades to a plain segment split +— the examples still run, but you lose per-segment validation +(incl. the 32-byte key-length check), so a malformed key reaches +the returned struct instead of raising. `_have_wg_maddr_proto()` +is the gate. It deliberately does **not** hand-roll a `wg` codec (gh #429 was about *dropping* our NIH parser). ## 0. tunnel setup (out-of-band, both hosts)