Fix PocketID config lookup when multiple admins exist
Build and push images / validate (push) Successful in 19s
Build and push images / build-backend (push) Successful in 32s
Build and push images / build-worker (push) Successful in 30s
Build and push images / build-frontend (push) Successful in 30s

_get_pocketid_config / _get_allowed_group selected an admin row with an
unordered LIMIT 1. With more than one admin (e.g. the seeded password admin
plus a passkey-linked admin), this non-deterministically returned an admin
without PocketID config — making the passkey button disappear (available=false)
and group gating inconsistent. Add _config_admin() which prefers the admin that
actually has an issuer set, then falls back to the lowest-id admin.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-08 13:37:19 +01:00
parent 0e18ef2291
commit e0ddc4cbf4
2 changed files with 50 additions and 8 deletions
+25 -4
View File
@@ -14,10 +14,32 @@ from app.models.user import User
router = APIRouter()
async def _config_admin(db: AsyncSession):
"""The admin row that holds instance-wide PocketID settings.
Settings live on an admin user row, but there can be more than one admin.
Prefer the admin that actually has an issuer configured; otherwise fall back
to the lowest-id admin. Without this, an unordered LIMIT 1 could return an
admin with no config and make PocketID look disabled / gating inconsistent.
"""
result = await db.execute(
select(User)
.where(User.is_admin == True, User.pocketid_issuer.isnot(None))
.order_by(User.id)
.limit(1)
)
admin = result.scalar_one_or_none()
if admin is None:
result = await db.execute(
select(User).where(User.is_admin == True).order_by(User.id).limit(1)
)
admin = result.scalar_one_or_none()
return admin
async def _get_pocketid_config(db: AsyncSession):
"""Get PocketID config from DB (admin user) falling back to env vars."""
result = await db.execute(select(User).where(User.is_admin == True).limit(1))
admin = result.scalar_one_or_none()
admin = await _config_admin(db)
issuer = (admin and admin.pocketid_issuer) or settings.pocketid_issuer
client_id = (admin and admin.pocketid_client_id) or settings.pocketid_client_id
client_secret = (admin and admin.pocketid_client_secret) or settings.pocketid_client_secret
@@ -26,8 +48,7 @@ async def _get_pocketid_config(db: AsyncSession):
async def _get_allowed_group(db: AsyncSession):
"""Group a PocketID user must belong to in order to sign in (None = allow all)."""
result = await db.execute(select(User).where(User.is_admin == True).limit(1))
admin = result.scalar_one_or_none()
admin = await _config_admin(db)
group = (admin and admin.pocketid_allowed_group) or settings.pocketid_allowed_group
return (group or "").strip() or None