From a9f6c86c7cc25d3384d94070cd280e500217ed9e Mon Sep 17 00:00:00 2001 From: sascha Date: Sat, 5 Sep 2026 13:04:05 +0200 Subject: [PATCH 1/2] fix: valid WireGuard interface candidate name (app.py) --- app.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app.py b/app.py index 613089b..1f63730 100644 --- a/app.py +++ b/app.py @@ -12,7 +12,7 @@ from contextlib import asynccontextmanager from contextvars import ContextVar log = logging.getLogger("butler") -VERSION = "2.3.8" +VERSION = "2.3.9" API_DIR = os.environ.get("API_KEY_DIR", "/data/api") VAULT_CACHE_DIR = os.environ.get("VAULT_CACHE_DIR", "/data/vault-cache") @@ -2409,7 +2409,7 @@ def _media_tunnel_install_command(role: Literal["vps", "emby"], peer_public_key: +lines.extend(["", "[Peer]", "PublicKey = {peer_public_key}", "AllowedIPs = {settings['peer']}"]) +if {settings['endpoint']!r}: lines.append("Endpoint = " + {settings['endpoint']!r}) +if {settings['keepalive']!r}: lines.append("PersistentKeepalive = " + str({settings['keepalive']!r})) -+candidate = root / "wg-media-candidate.conf" ++candidate = root / "wgmtest.conf" +candidate.write_text("\\n".join(lines) + "\\n") +os.chmod(candidate, 0o600) +check = subprocess.run(["wg-quick", "strip", str(candidate)], text=True, capture_output=True) From b0fd3c1e361e8866b6084becdae0935fcde3af5e Mon Sep 17 00:00:00 2001 From: sascha Date: Sat, 5 Sep 2026 13:04:06 +0200 Subject: [PATCH 2/2] fix: valid WireGuard interface candidate name (tests/test_app.py) --- tests/test_app.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/tests/test_app.py b/tests/test_app.py index c1bb9c8..4552a81 100644 --- a/tests/test_app.py +++ b/tests/test_app.py @@ -43,7 +43,7 @@ def test_health_exposes_current_version(): with TestClient(app.app) as client: response = client.get("/health") assert response.status_code == 200 - assert response.json()["version"] == app.VERSION == "2.3.8" + assert response.json()["version"] == app.VERSION == "2.3.9" def test_media_handoff_proxies_strict_category_contract(monkeypatch): @@ -1344,3 +1344,14 @@ def test_sascha_media_tunnel_apply_returns_redacted_result(monkeypatch): assert response.status_code == 200 assert response.json()["handshake"] is True assert "private" not in response.text.lower() + + +def test_sascha_media_tunnel_candidate_uses_valid_wireguard_interface_name(): + import base64 + import re + + command = app._media_tunnel_install_command("vps", "A" * 43 + "=") + encoded = re.search(r"b64decode\('([^']+)'\)", command).group(1) + script = base64.b64decode(encoded).decode() + assert 'root / "wgmtest.conf"' in script + assert len("wgmtest") <= 15