fix: pure Python keypair generation, no wg CLI dependency
Some checks failed
CI / test (push) Successful in 2m5s
CI / release (push) Successful in 34s
CI / docker (push) Has been cancelled

Replace subprocess calls to wg genkey/pubkey with cryptography
library's X25519PrivateKey. This eliminates the wg CLI dependency
for key generation, fixes device creation on machines without
wireguard-tools, and removes the event loop blocking that caused
WebSocket disconnects during device creation.

Also fix E2E test teardown to use a fresh engine for cleanup,
avoiding cross-event-loop issues with asyncpg connection pools.
This commit is contained in:
Stefano Bertelli 2026-03-30 23:11:58 -05:00
parent 92554d4089
commit 41a62832f7
8 changed files with 62 additions and 71 deletions

View file

@ -1,9 +1,12 @@
"""E2E test configuration — loads NiceGUI testing plugin and app."""
import pytest
from sqlalchemy import text
from sqlalchemy.ext.asyncio import create_async_engine
from sqlmodel import select
from wiregui.auth.passwords import hash_password
from wiregui.config import get_settings
from wiregui.db import async_session
from wiregui.models.configuration import Configuration
from wiregui.models.user import User
@ -14,24 +17,32 @@ FAKE_SERVER_KEY = "SFake0ServerPubKey0000000000000000000000000w="
TEST_EMAIL = "e2e-test@example.com"
TEST_PASSWORD = "testpass123"
async def _delete_user_cascade(session, user_id):
"""Delete a user and all related objects via raw SQL to avoid stale ORM cache issues."""
from sqlalchemy import text
for table in ("devices", "rules", "mfa_methods", "api_tokens", "oidc_connections"):
await session.execute(text(f"DELETE FROM {table} WHERE user_id = :uid"), {"uid": user_id}) # noqa: S608
await session.execute(text("DELETE FROM users WHERE id = :uid"), {"uid": user_id})
_CHILD_TABLES = ("devices", "rules", "mfa_methods", "api_tokens", "oidc_connections")
async def _cleanup_test_user():
"""Delete the test user and all related objects using a fresh engine."""
engine = create_async_engine(get_settings().database_url)
async with engine.begin() as conn:
# Find user id by email
row = (await conn.execute(
text("SELECT id FROM users WHERE email = :email"), {"email": TEST_EMAIL}
)).first()
if row:
uid = row[0]
for table in _CHILD_TABLES:
await conn.execute(text(f"DELETE FROM {table} WHERE user_id = :uid"), {"uid": uid}) # noqa: S608
await conn.execute(text("DELETE FROM users WHERE id = :uid"), {"uid": uid})
await engine.dispose()
@pytest.fixture
async def test_user():
"""Create a test user and ensure server config has a public key."""
async with async_session() as session:
# Clean up any leftover from a previous failed run
existing = (await session.execute(select(User).where(User.email == TEST_EMAIL))).scalar_one_or_none()
if existing:
await _delete_user_cascade(session, existing.id)
await session.commit()
# Clean up any leftover from a previous failed run
await _cleanup_test_user()
async with async_session() as session:
# Ensure a Configuration with a server key exists
config = (await session.execute(select(Configuration).limit(1))).scalar_one_or_none()
if config:
@ -53,7 +64,4 @@ async def test_user():
yield user
# Teardown
async with async_session() as session:
await _delete_user_cascade(session, user.id)
await session.commit()
await _cleanup_test_user()