aboutsummaryrefslogtreecommitdiffstats
path: root/packages/meshbay-hub/src/meshbay_hub/app.py
diff options
context:
space:
mode:
Diffstat (limited to 'packages/meshbay-hub/src/meshbay_hub/app.py')
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/app.py51
1 files changed, 40 insertions, 11 deletions
diff --git a/packages/meshbay-hub/src/meshbay_hub/app.py b/packages/meshbay-hub/src/meshbay_hub/app.py
index 16a9d4a..ca05fd8 100644
--- a/packages/meshbay-hub/src/meshbay_hub/app.py
+++ b/packages/meshbay-hub/src/meshbay_hub/app.py
@@ -42,22 +42,52 @@ from meshbay_hub.config import HubConfig
from meshbay_hub.db.engine import close_db, init_db
-async def _sync_admin_roles(admin_usernames: list[str]) -> None:
- """Ensure config-listed admin usernames have role='admin' in the DB."""
+async def _pin_config_admins(admin_usernames: list[str]) -> None:
+ """Pin each allow-listed admin name to the account holding it, once.
+
+ A name already pinned keeps its account whoever holds the name now, which is
+ what stops a released name from being registered into the admin role. Pins
+ of names no longer listed are dropped: removing a name, restarting, then
+ listing it again is how an operator hands it to a new account.
+ """
+ import logging
+
from sqlalchemy import select
+ from meshbay_hub.api.deps import set_admin_pins
from meshbay_hub.db.engine import get_session_factory
- from meshbay_hub.db.models import User
+ from meshbay_hub.db.models import AdminPin, User
+ log = logging.getLogger(__name__)
+ listed = set(admin_usernames)
factory = get_session_factory()
async with factory() as session:
- result = await session.execute(
- select(User).where(User.username.in_(admin_usernames))
- )
- for user in result.scalars().all():
- if user.role != "admin":
- user.role = "admin"
+ pins: dict[str, str] = {}
+ for pin in (await session.execute(select(AdminPin))).scalars().all():
+ if pin.username in listed:
+ pins[pin.username] = pin.user_id
+ else:
+ log.info("Admin allow-list: %s is no longer listed, its pin is dropped",
+ pin.username)
+ await session.delete(pin)
+
+ unpinned = listed - pins.keys()
+ if unpinned:
+ holders = (await session.execute(select(User).where(
+ User.username.in_(unpinned), User.status == "active"))).scalars().all()
+ for user in holders:
+ session.add(AdminPin(username=user.username, user_id=user.id))
+ pins[user.username] = user.id
+ log.info("Admin allow-list: %s pinned to account %s",
+ user.username, user.id[:8])
+
+ if pins:
+ for user in (await session.execute(select(User).where(
+ User.id.in_(pins.values()), User.status == "active"))).scalars().all():
+ if user.role != "admin":
+ user.role = "admin"
await session.commit()
+ set_admin_pins(pins)
async def _backfill_email_hashes() -> None:
@@ -123,8 +153,7 @@ def create_app(cfg: HubConfig | None = None) -> FastAPI:
# back to.
_hub_settings.set_mail_defaults(cfg.mail)
- if cfg.identity.admin_usernames:
- await _sync_admin_roles(cfg.identity.admin_usernames)
+ await _pin_config_admins(cfg.identity.admin_usernames)
from meshbay_hub.db.engine import get_session_factory
from meshbay_hub.tasks.cleanup import cleanup_loop