Files
app/backend/fluksio/core/bootstrap.py
T
stroblmeandClaude Opus 5 d01a8dad37 Rename Installation to Instance
Follows the portal: the noun is "instance" everywhere the app says it —
UI strings, CLI output, error details, docs and comments. The wire keys
(`instance_id`, `instance_token`) and the hub route this calls move with it.

An existing cloud.json is adopted rather than refused: without the key
alias the dataclass fails to parse, which the caller swallows and reads as
"never enrolled" instead of "reconnect".

`instance_key` on a node type becomes `target_key`. It means the outside
thing a node points at, which is a different sense of the word, and keeping
both would put two meanings of "instance" in one codebase.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015YrQnKV3bnQd4K342y8tKj
2026-08-31 10:12:01 +02:00

65 lines
2.3 KiB
Python

"""First run: an account to sign in with.
An instance started from the command line is given no environment, so the
superuser a deployment sets in `.env` has to come from somewhere. The session
key is the CLI's own business — it has to be set before this module can be
imported at all.
"""
from __future__ import annotations
import secrets
from sqlmodel import Session, select
from fluksio import crud
from fluksio.models import User, UserCreate
#: A generated admin's address. `example.com` is reserved for exactly this
#: (RFC 2606) — `@localhost` and `.local` are too, and `EmailStr` refuses those.
#: It is a name to sign in with, not somewhere mail is sent.
DEFAULT_ADMIN = "admin@example.com"
def ensure_superuser(
session: Session, *, email: str | None = None, password: str | None = None
) -> tuple[User, str | None]:
"""The account to sign in with, made on first run.
Returns the user and, when it was just created, the password in clear —
the caller prints it once. An instance that already has a superuser is
left alone: this is a first run, not a password reset.
"""
existing = session.exec(
select(User).where(User.is_superuser == True) # noqa: E712
).first()
if existing is not None:
return existing, None
generated = password or secrets.token_urlsafe(12)
user = crud.create_user(
session=session,
user_create=UserCreate(
email=email or DEFAULT_ADMIN, password=generated, is_superuser=True
),
)
return user, generated
def pick_superuser(session: Session, email: str | None = None) -> User:
"""The account an enrolment acts as; a portal session arrives as this one."""
if email:
user = session.exec(select(User).where(User.email == email)).first()
if user is None:
raise LookupError(f"No account here with the address {email}")
return user
users = session.exec(
select(User).where(User.is_superuser == True) # noqa: E712
).all()
if not users:
raise LookupError("This instance has no superuser to enrol as")
if len(users) > 1:
addresses = ", ".join(sorted(u.email for u in users))
raise LookupError(f"Several superusers here — name one with --as: {addresses}")
return users[0]