Summary
users.settings.UsersSettings no longer reads SM_USERS_* env vars at boot — but the validator that requires RESET_PASSWORD_TOKEN_SECRET and VERIFICATION_TOKEN_SECRET to be non-default in production fires anyway. So the documented escape hatch (set SM_USERS_RESET_PASSWORD_TOKEN_SECRET=...) silently has no effect, and the user can't get past the validator without DB-backed settings setup.
What the docstring says
"""Users module settings — DB-backed via ``register_module_settings``.
Construction no longer reads ``SM_USERS_*`` environment variables. Values
come from pydantic defaults at boot, then get hydrated from the DB by the
hosting lifespan before module ``on_startup`` runs. Runtime changes go
through ``settings.reload.apply_changes_and_reload``.
The one remaining env read is ``SM_ENVIRONMENT``, consulted by the
``@model_validator`` to refuse placeholder token secrets in production —
that's a host-level setting, not a users-module field.
"""
What actually happens
SM_ENVIRONMENT=production \
SM_USERS_RESET_PASSWORD_TOKEN_SECRET="$(python -c 'import secrets; print(secrets.token_urlsafe(48))')" \
SM_USERS_VERIFICATION_TOKEN_SECRET="$(python -c 'import secrets; print(secrets.token_urlsafe(48))')" \
uv run uvicorn main:app
Boot fails:
pydantic_core._pydantic_core.ValidationError: 1 validation error for UsersSettings
Value error, users.RESET_PASSWORD_TOKEN_SECRET, VERIFICATION_TOKEN_SECRET must
be set to non-default value(s) when SM_ENVIRONMENT='production'.
The env vars are ignored. The model is constructed with extra="ignore" so they're dropped, then defaults ("dev-reset-token-secret-change-me") are used, then the validator rejects.
What you have to do
The new model says secrets come from DB-backed settings. So before booting the app in production, you have to:
- Boot the app once in
development mode.
- Use the runtime settings UI / API to override
users.reset_password_token_secret and users.verification_token_secret to non-placeholder values, persisted in the DB.
- Restart in production mode.
This is an awful onboarding story. There's a chicken-and-egg problem the moment you provision a fresh production DB: you can't boot to set the values, but you can't set the values without booting.
Suggested fixes
-
Restore env var override for the secrets. Module-level settings hydrated from DB are a fine UX for runtime tweaks, but startup bootstrapping needs the env-var path. Add the two fields back to the env-readable list.
-
Or document the bootstrap procedure clearly. A migration / management command that seeds the secrets from env vars on a fresh DB would also work:
SM_USERS_RESET_PASSWORD_TOKEN_SECRET=... \
SM_USERS_VERIFICATION_TOKEN_SECRET=... \
uv run sm-users seed-settings-from-env
-
Or relax the validator when the values are non-placeholder strings, regardless of where they came from. The validator currently checks secret == _PLACEHOLDER_RESET_SECRET. If the user set a real string in the DB-backed settings, the validator won't fire — but the env-var path doesn't reach the model in the first place.
The current state combines the worst of both worlds: validator rejects placeholders, env vars don't override, no obvious bootstrap path.
Impact
I tried SM_ENVIRONMENT=production to use the built assets during the smoke test and was completely blocked. Falling back to SM_ENVIRONMENT=development worked but kept Vite in the path, exposing the preamble bug (#66). Without DB-backed settings tooling, fresh production deployments need an out-of-band write to the settings table.
Environment
simple_module_users==0.0.3
- Discovered Phase 5 smoke test, laco_wiki_python rewrite.
Summary
users.settings.UsersSettingsno longer readsSM_USERS_*env vars at boot — but the validator that requiresRESET_PASSWORD_TOKEN_SECRETandVERIFICATION_TOKEN_SECRETto be non-default in production fires anyway. So the documented escape hatch (setSM_USERS_RESET_PASSWORD_TOKEN_SECRET=...) silently has no effect, and the user can't get past the validator without DB-backed settings setup.What the docstring says
What actually happens
Boot fails:
The env vars are ignored. The model is constructed with
extra="ignore"so they're dropped, then defaults ("dev-reset-token-secret-change-me") are used, then the validator rejects.What you have to do
The new model says secrets come from DB-backed settings. So before booting the app in production, you have to:
developmentmode.users.reset_password_token_secretandusers.verification_token_secretto non-placeholder values, persisted in the DB.This is an awful onboarding story. There's a chicken-and-egg problem the moment you provision a fresh production DB: you can't boot to set the values, but you can't set the values without booting.
Suggested fixes
Restore env var override for the secrets. Module-level settings hydrated from DB are a fine UX for runtime tweaks, but startup bootstrapping needs the env-var path. Add the two fields back to the env-readable list.
Or document the bootstrap procedure clearly. A migration / management command that seeds the secrets from env vars on a fresh DB would also work:
Or relax the validator when the values are non-placeholder strings, regardless of where they came from. The validator currently checks
secret == _PLACEHOLDER_RESET_SECRET. If the user set a real string in the DB-backed settings, the validator won't fire — but the env-var path doesn't reach the model in the first place.The current state combines the worst of both worlds: validator rejects placeholders, env vars don't override, no obvious bootstrap path.
Impact
I tried
SM_ENVIRONMENT=productionto use the built assets during the smoke test and was completely blocked. Falling back toSM_ENVIRONMENT=developmentworked but kept Vite in the path, exposing the preamble bug (#66). Without DB-backed settings tooling, fresh production deployments need an out-of-band write to the settings table.Environment
simple_module_users==0.0.3