change: protocol seam and WireGuard conf codec #189
Loading…
Reference in a new issue
No description provided.
Delete branch "protocol-seam"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Problem
Tunnel-type knowledge was spread as string matches and ad-hoc state: the service tracked WireGuard teardown with
wg_connect/wg_providerflags, the GUI hardcoded threetunnel == "WireGuard"guards, and conf-format knowledge sat in four files — including tunnel.py'sinsert(8/9)Mullvad completion that only worked because inserting past a list's end appends. #152's design discussion settled the target shape; #187 covers the conf side.Fix
Two commits, independently revertible:
Protocol seam —
wireguard.WireGuardcarries the contract's first half:up(role)/down()/dev/alive(), with the device firewall accepts inside up/down and secondary roles refused before any side effect. The service holds the object and tears down symmetrically (flags deleted); the thread receives it by composition. Role is a parameter, never per-role methods — main/hop/bypass routing stays shared policy. The GUI's three guards collapse intoconfig.TUNNEL_SECONDARY(same import-cycle rationale asPROVIDER_TYPES, pinned to the class by test), so #176 lifts a flag instead of editing string matches.alive()is handshake age with the idle-tunnel caveat documented for #123. OpenVPN's half is deliberately deferred to #123, its first real consumer — its process lifecycle is entangled with the thread and works; extracting it without a consumer is churn.Conf codec (#187) —
parse_conf/generate_confas inverses over a data form (extras + native(key, value)entries per section, spelling kept, unknown keys likePresharedKey/PersistentKeepalivepreserved).wg setconfinput is always generated, never passthrough; Mullvad's per-server fields append to the parsed[Peer]section; custom.py splits endpoints through the codec helper — which also fixes bracketed v6 endpoints and no-spaceEndpoint=host:portconfs the oldsplit(" = ")choked on.Verification
pytest: 461 passed (pre-existing test_mgmt socket cases excluded in my sandbox, pass on a normal shell). New coverage: class contract (role refusal before side effects, accept rollback on failed bring-up, symmetric down), handshake-age liveness, codec round-trip incl. unknown-key preservation, section-anchored Mullvad completion, capability-flag pinning.build-branch-and-install.sh. Mullvad WG and custom-import paths are covered by the new tests; a Mullvad live connect additionally exercises the generated conf end-to-end if you want the belt and braces.🤖 Generated with Claude Code
Live verification: ProtonVPN WG connect/disconnect through the new dispatch path works on the real system (user-tested post-install).
Scope note: the Mullvad WG path (template completion via the codec, Mullvad-specific import) is covered by tests only — no Mullvad account to verify against, so Mullvad-over-WireGuard stays effectively unsupported until one exists to test with (a temp subscription is within the project's established testing scope if it ever becomes worth it; Mullvad dropping OpenVPN in Jan 2026 makes that likelier eventually). The codepath is exercised end-to-end by TestMullvadWgConf up to the point of handing the generated conf to link_up, which the Proton test covers from there.