From 2c21dfeb3ea4dadf28e272679901b0cb5bf96b04 Mon Sep 17 00:00:00 2001 From: Brian Krabach Date: Mon, 6 Apr 2026 04:57:23 -0700 Subject: [PATCH] fix: federation client accepts self-signed TLS certificates MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit httpx.AsyncClient used default SSL verification, rejecting self-signed certs from muxplex setup-tls. Remote HTTPS instances (e.g., setup-tls with self-signed fallback) were unreachable — all federation requests failed with CERTIFICATE_VERIFY_FAILED. Fix: verify=False on the federation client. Bearer token auth still protects authorization. --- muxplex/main.py | 9 ++++++++- muxplex/tests/test_api.py | 26 ++++++++++++++++++++++++++ 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/muxplex/main.py b/muxplex/main.py index 30f0e52..7e02580 100644 --- a/muxplex/main.py +++ b/muxplex/main.py @@ -176,7 +176,14 @@ async def lifespan(app: FastAPI): except Exception: pass # tmux not running at startup is OK; hook will be set on first poll - app.state.federation_client = httpx.AsyncClient(timeout=5.0, follow_redirects=False) + app.state.federation_client = httpx.AsyncClient( + timeout=5.0, + follow_redirects=False, + verify=False, # nosec B501 — muxplex is a dev tool for LAN/Tailscale use; + # self-signed certs from `muxplex setup-tls` must be accepted for federation. + # Bearer token auth handles authorization. Users who need cert verification + # should use mkcert (CA-trusted) or Tailscale (LE-trusted) certs. + ) yield diff --git a/muxplex/tests/test_api.py b/muxplex/tests/test_api.py index 7b197c3..24c0b98 100644 --- a/muxplex/tests/test_api.py +++ b/muxplex/tests/test_api.py @@ -1583,6 +1583,32 @@ def test_federation_client_exists_on_app_state(monkeypatch): ) +def test_federation_client_disables_ssl_verification(monkeypatch): + """Federation httpx client must disable SSL verification for self-signed certs. + + muxplex setup-tls can generate self-signed certificates. When a remote instance + uses such a cert, httpx's default SSL verification rejects it with + CERTIFICATE_VERIFY_FAILED, making the remote unreachable in federation. + The client must use verify=False so self-signed certs on LAN/Tailscale remotes + are accepted. Bearer token auth still protects authorization. + """ + import ssl + + monkeypatch.setenv("MUXPLEX_PASSWORD", "test-password") + + with TestClient(app): + client = app.state.federation_client + # httpx.AsyncClient(verify=False) creates a transport whose SSL context + # has verify_mode=ssl.CERT_NONE (0). If verify=True (default), it would + # use CERT_REQUIRED (2). + ssl_context = client._transport._pool._ssl_context + assert ssl_context is not None, "federation_client SSL context must be present" + assert ssl_context.verify_mode == ssl.CERT_NONE, ( + "federation_client must use verify=False (CERT_NONE) " + "to support self-signed certificates on remote instances" + ) + + # --------------------------------------------------------------------------- # GET /api/federation/sessions (task-5) # ---------------------------------------------------------------------------