Files
intervalsicu-mcp-ui/tests/test_db.py
T
Chris Farhood bb5e9d518c
build-image / test (push) Successful in 37s
build-image / build (push) Successful in 25s
feat: Intervals.icu MCP portal (FastAPI + Authentik OIDC)
- OIDC login via Authentik; first login creates a disabled user (admin approval).
- Users set/replace their Intervals.icu athlete ID + API key; the key is validated
  against Intervals.icu and stored AES-256-GCM encrypted (shared key with the MCP
  server). Same users table (schema owned by the MCP server's migrations).
- Admin page (gated on the intervalsicu-mcp-admins group claim): list, approve,
  disable, delete users.
- 29 tests @ 93% (OIDC routes integration-only); Dockerfile asserts templates are
  packaged; .gitea CI test-gates the image build.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-04 20:51:46 -04:00

61 lines
2.2 KiB
Python

"""Store operations against in-memory SQLite (mirrors the MCP server's schema)."""
import asyncio
from sqlalchemy.ext.asyncio import async_sessionmaker, create_async_engine
from sqlalchemy.pool import StaticPool
from intervalsicu_mcp_ui import crypto, db
KEY = crypto.generate_key_b64()
def _run_db(monkeypatch, body):
async def go():
monkeypatch.setenv("INTERVALS_ENC_KEY", KEY)
engine = create_async_engine(
"sqlite+aiosqlite:///:memory:",
poolclass=StaticPool,
connect_args={"check_same_thread": False},
)
async with engine.begin() as conn:
await conn.run_sync(db.Base.metadata.create_all)
maker = async_sessionmaker(engine, expire_on_commit=False)
try:
await body(maker)
finally:
await engine.dispose()
asyncio.run(go())
def test_first_login_disabled_then_credentials_encrypted(monkeypatch):
async def body(maker):
async with maker() as s:
user = await db.upsert_login(s, "sub1", "a@b.com", "Alice")
assert user.enabled is False and user.has_credentials is False
assert await db.set_credentials(s, "sub1", "i123", "SECRET") is True
again = await db.get_user(s, "sub1")
assert again.athlete_id == "i123"
assert b"SECRET" not in again.api_key_enc
assert crypto.decrypt(again.api_key_enc) == "SECRET"
assert again.has_credentials is True
_run_db(monkeypatch, body)
def test_enable_disable_delete_and_list(monkeypatch):
async def body(maker):
async with maker() as s:
await db.upsert_login(s, "sub1", "a@b.com", None)
await db.upsert_login(s, "sub2", "b@b.com", None)
assert len(await db.list_users(s)) == 2
assert await db.set_enabled(s, "sub1", True) is True
assert (await db.get_user(s, "sub1")).enabled is True
assert await db.clear_credentials(s, "sub1") is True
assert await db.delete_user(s, "sub2") is True
assert await db.get_user(s, "sub2") is None
assert await db.delete_user(s, "ghost") is False
_run_db(monkeypatch, body)