import os import pytest import tempfile import secrets from helpers.wg_runner import WGInterface, build_wg_config, cleanup_stale_e2e_interfaces @pytest.fixture(scope='session', autouse=True) def cleanup_stale_wg_interfaces(): cleanup_stale_e2e_interfaces() yield cleanup_stale_e2e_interfaces() @pytest.fixture(scope='session') def wg_server_info(admin_client, pic_host): """Get server public key and listen port from the running API.""" # Public key lives at /api/wireguard/keys keys_r = admin_client.get('/api/wireguard/keys') keys = keys_r.json() server_pubkey = keys.get('public_key', '') # Port comes from the WireGuard config or status port = 51820 try: status = admin_client.get('/api/wireguard/status').json() port = ( status.get('listen_port') or status.get('port') or status.get('ListenPort') or 51820 ) except Exception: pass return { 'public_key': server_pubkey, 'endpoint': pic_host, 'port': int(port), } @pytest.fixture def connected_peer(make_peer, wg_server_info, tmp_path): """ Creates a peer, builds its WireGuard config, brings the tunnel up, yields, then tears everything down. Requires: sudo wg-quick available on the test runner. """ peer = make_peer('e2etest-wg-basic', service_access=['calendar', 'files', 'mail', 'webdav']) iface_name = f"pic-e2e-{secrets.token_hex(3)}" conf_path = str(tmp_path / f"{iface_name}.conf") config_text = build_wg_config( private_key=peer['private_key'], peer_ip=peer['ip'], server_pubkey=wg_server_info['public_key'], server_endpoint=wg_server_info['endpoint'], server_port=wg_server_info['port'], allowed_ips='10.0.0.0/24', ) # Write config with restricted permissions with open(conf_path, 'w') as f: f.write(config_text) os.chmod(conf_path, 0o600) iface = WGInterface(conf_path, iface_name) try: iface.bring_up() peer['iface'] = iface peer['conf_path'] = conf_path yield peer finally: iface.bring_down() try: os.unlink(conf_path) except Exception: pass @pytest.fixture def full_tunnel_peer(make_peer, wg_server_info, tmp_path): """Like connected_peer but with AllowedIPs=0.0.0.0/0 (full tunnel).""" peer = make_peer('e2etest-wg-fulltunnel') iface_name = f"pic-e2e-{secrets.token_hex(3)}" conf_path = str(tmp_path / f"{iface_name}.conf") config_text = build_wg_config( private_key=peer['private_key'], peer_ip=peer['ip'], server_pubkey=wg_server_info['public_key'], server_endpoint=wg_server_info['endpoint'], server_port=wg_server_info['port'], allowed_ips='0.0.0.0/0', ) with open(conf_path, 'w') as f: f.write(config_text) os.chmod(conf_path, 0o600) iface = WGInterface(conf_path, iface_name) try: iface.bring_up() peer['iface'] = iface peer['conf_path'] = conf_path yield peer finally: iface.bring_down() try: os.unlink(conf_path) except Exception: pass