* fix: run bcrypt off the event loop in auth routes The auth routes are async, but each bcrypt call ran synchronously on the event loop. bcrypt (checkpw/hashpw) is intentionally CPU-expensive (~100-300 ms), so every login / signup / setup / change-password froze the single event loop for that window, stalling all other in-flight requests (chat streams, polling, ...). /api/auth/login is the worst case: it is reachable unauthenticated, runs bcrypt twice (verify_password, then create_session re-verifies), and is rate-limited only per-IP. A burst of login attempts serializes the whole server — cheap DoS amplification. Offload the bcrypt-bearing AuthManager calls (setup, signup/create_user, login's verify_password + create_session, change_password) via asyncio.to_thread, matching how the codebase already offloads blocking work (e.g. src/builtin_actions._run_subprocess, email summarize). The event loop stays responsive while bcrypt runs on a worker thread. Add tests/test_auth_event_loop.py: asserts login runs verify_password and create_session on a worker thread, not the loop thread. Fails if those calls are awaited inline again. * test: isolate auth event-loop test from heavy core/* import chain The regression test imported routes.auth_routes, which pulls in core.auth and so triggers core/__init__.py — transitively importing src.llm_core (hangs at import under the project venv) and the SQLAlchemy declarative models (metaclass error on a bare core.database import / under the conftest sqlalchemy stubs). Reported by the maintainer: collection failed on system Python and hung under the venv. Stub core.auth/core.database before the import, mirroring the existing _ensure_stub pattern in test_auth_regressions.py and test_null_owner_gates.py. AuthManager is only a type hint here and the handler is exercised with a MagicMock, so no real core machinery is needed. Test now imports cleanly and passes in <0.3s without bcrypt/sqlalchemy installed.
4.5 KiB
4.5 KiB