Table `app_user`, son dépôt, et la commande `create-admin`. Le nom évite `user`, mot réservé de PostgreSQL, et rappelle qu'il s'agit d'un compte applicatif, par opposition au rôle PostgreSQL qui portera le cantonnement des accès ETL et ML. `credentials_changed_at` couvre à elle seule le changement de mot de passe, le changement de rôle et la désactivation : tout jeton émis avant cet instant sera refusé, sans attendre son expiration. La configuration refuse désormais de démarrer sur cinq erreurs silencieuses : secret trop court ou laissé à sa valeur d'exemple, `debug` en production, joker CORS, origines vides hors local, et cookie `SameSite=None` sans `Secure`. Les fixtures de test et les deux `.env.example` suivent, sans quoi rien ne démarrerait. Le mot de passe de l'admin ne transite jamais par `argv`, visible de tout `ps` : il est saisi par `getpass` ou tiré au sort. Une révision Alembic qui insérerait ce compte graverait son empreinte dans Git pour toujours.
59 lines
1.9 KiB
Python
59 lines
1.9 KiB
Python
from app.core.cookies import RefreshCookie, cookie_name
|
|
from tests.factories import make_settings
|
|
|
|
|
|
def test_build_marks_the_cookie_http_only_and_scopes_it_to_the_auth_routes() -> None:
|
|
settings = make_settings(env="local")
|
|
|
|
cookie = RefreshCookie.build(settings, "un-secret-opaque")
|
|
|
|
assert cookie.httponly is True
|
|
assert cookie.samesite == "strict"
|
|
assert cookie.path == "/api/v1/auth"
|
|
assert cookie.max_age == settings.refresh_token_ttl_seconds
|
|
|
|
|
|
def test_build_prefixes_and_secures_the_cookie_outside_local() -> None:
|
|
settings = make_settings(env="prod", cors_origins="https://enervision.fr")
|
|
|
|
cookie = RefreshCookie.build(settings, "un-secret-opaque")
|
|
|
|
assert cookie.secure is True
|
|
assert cookie.key.startswith("__Secure-")
|
|
|
|
|
|
def test_build_leaves_the_cookie_unprefixed_in_local() -> None:
|
|
settings = make_settings(env="local")
|
|
|
|
cookie = RefreshCookie.build(settings, "un-secret-opaque")
|
|
|
|
assert cookie.key == "ev_refresh"
|
|
|
|
|
|
def test_expired_reuses_the_exact_name_and_path_of_the_posted_cookie() -> None:
|
|
settings = make_settings(env="prod", cors_origins="https://enervision.fr")
|
|
|
|
pose = RefreshCookie.build(settings, "un-secret-opaque")
|
|
suppression = RefreshCookie.expired(settings)
|
|
|
|
assert suppression.key == pose.key
|
|
assert suppression.path == pose.path
|
|
assert suppression.secure == pose.secure
|
|
assert suppression.samesite == pose.samesite
|
|
assert suppression.max_age == 0
|
|
assert suppression.value == ""
|
|
|
|
|
|
def test_as_kwargs_matches_the_starlette_set_cookie_signature() -> None:
|
|
settings = make_settings(env="local")
|
|
|
|
arguments = RefreshCookie.build(settings, "un-secret-opaque").as_kwargs()
|
|
|
|
assert set(arguments) == {"key", "value", "max_age", "path", "secure", "httponly", "samesite"}
|
|
|
|
|
|
def test_cookie_name_follows_the_configured_name() -> None:
|
|
settings = make_settings(env="local", refresh_cookie_name="autre_nom")
|
|
|
|
assert cookie_name(settings) == "autre_nom"
|