Repository navigation
users.endpoints.views.login_page dev_accounts resolution skips .env fallback — inconsistent with users.bootstrap #159
Description
Summary
users/endpoints/views.py:login_page resolves the bootstrap credentials it surfaces as dev_accounts (the "Dev quick-login" buttons on /users/login) from only two sources: UsersSettings and os.environ. The companion code in users/bootstrap.py:bootstrap_admin_from_env resolves the same fields from three sources, with a direct parse_dotenv() fallback. This asymmetry means an admin can be successfully bootstrapped on one boot path while the login page shows no quick-login button on another — even though the design intent is that both surface the same dev credentials.
Code
users/endpoints/views.py:50-69 (current):
if request.app.state.sm.settings.is_development:
admin_email = users_settings.bootstrap_email or os.environ.get(
"SM_USERS_BOOTSTRAP_EMAIL", ""
)
admin_password = users_settings.bootstrap_password or os.environ.get(
"SM_USERS_BOOTSTRAP_PASSWORD", ""
)
if admin_email and admin_password:
dev_accounts.append({"label": "Admin", "email": admin_email, "password": admin_password})
user_email = users_settings.bootstrap_user_email or os.environ.get(
"SM_USERS_BOOTSTRAP_USER_EMAIL", ""
)
user_password = users_settings.bootstrap_user_password or os.environ.get(
"SM_USERS_BOOTSTRAP_USER_PASSWORD", ""
)
if user_email and user_password:
dev_accounts.append({"label": "User", "email": user_email, "password": user_password})users/bootstrap.py:203-225 (the correct three-source pattern):
async def bootstrap_admin_from_env(app: FastAPI) -> None:
settings: UsersSettings = app.state.users.settings
dotenv_vars = _read_dotenv_bootstrap_vars()
resolved = {
attr: getattr(settings, attr) or os.environ.get(env_key) or dotenv_vars.get(env_key, "")
for attr, env_key in BOOTSTRAP_ENV_KEYS.items()
}bootstrap.py even has a comment explaining why the direct .env read is needed:
UsersSettingsdeliberately doesn't useenv_file— runtime fields come from the DB, and pulling the whole.envin would re-expose every SMTP/cookie/token secret as an env knob. So we re-read.envjust for the four documented seed keys.
That rationale applies equally to the view code path.
Repro
In any host where .env has SM_USERS_BOOTSTRAP_EMAIL/SM_USERS_BOOTSTRAP_PASSWORD set but os.environ does NOT (e.g. when uvicorn is started from a cwd where parse_dotenv()'s default lookup doesn't find the file — see sibling issue about host/main.py not loading .env into os.environ):
bootstrap_admin_from_envcorrectly creates the admin via itsdotenv_varsfallback.- The login page renders without a "Dev quick-login" section because
views.pydoesn't have that fallback. The admin exists but the convenience button doesn't show.
Suggested fix
Have views.py use the same BOOTSTRAP_ENV_KEYS map and _read_dotenv_bootstrap_vars() helper that bootstrap.py already exports (or move the resolution into a single shared helper). Concretely:
from users.bootstrap import BOOTSTRAP_ENV_KEYS, _read_dotenv_bootstrap_vars # or a public re-export
if request.app.state.sm.settings.is_development:
dotenv_vars = _read_dotenv_bootstrap_vars()
resolved = {
attr: getattr(users_settings, attr) or os.environ.get(env_key) or dotenv_vars.get(env_key, "")
for attr, env_key in BOOTSTRAP_ENV_KEYS.items()
}
if resolved["bootstrap_email"] and resolved["bootstrap_password"]:
dev_accounts.append({
"label": "Admin",
"email": resolved["bootstrap_email"],
"password": resolved["bootstrap_password"],
})
if resolved["bootstrap_user_email"] and resolved["bootstrap_user_password"]:
dev_accounts.append({
"label": "User",
"email": resolved["bootstrap_user_email"],
"password": resolved["bootstrap_user_password"],
})If _read_dotenv_bootstrap_vars should stay private, promote a small public helper users.bootstrap.resolve_bootstrap_credentials(settings) -> dict[str, str] and have both call sites use it.
Framework version
0.0.13.
Context
Cross-referenced with the sibling issue on host/main.py not loading .env into os.environ. Fixing this one independently would mask the host-scaffold issue but make the dev-quick-login UX work, so they're orthogonal — both worth landing.
Activity
fix(users,host): align .env loading + dev-quick-login resolution (#158,
antosubash commentedon May 21, 2026
Fixed by #160 (merged c74edff).