"""API-key lookups and issuance (ADR-0008, ADR-0009). Plain functions over an `AsyncSession` the caller owns. No function here commits, rolls back, or closes the session (ADR-0012). Secret comparison happens in `src/application/auth`, not here — this module only fetches rows by their non-secret `key_prefix`. """ import uuid from sqlalchemy import select from sqlalchemy.ext.asyncio import AsyncSession from src.infrastructure.postgres.models.api_key import ApiKey async def get_by_prefix(session: AsyncSession, key_prefix: str) -> ApiKey | None: result = await session.execute(select(ApiKey).where(ApiKey.key_prefix == key_prefix)) return result.scalar_one_or_none() def create( session: AsyncSession, *, tenant_id: uuid.UUID, name: str, key_prefix: str, key_hash: str, scopes: list[str], actor_type: str = "backend", created_by: str | None = None, ) -> ApiKey: """Persist an issued key. The caller hashes the secret; this never sees it.""" api_key = ApiKey( id=uuid.uuid4(), tenant_id=tenant_id, name=name, key_prefix=key_prefix, key_hash=key_hash, scopes=scopes, actor_type=actor_type, created_by=created_by, ) session.add(api_key) return api_key