- FastAPI + SQLAlchemy async + Alembic + Postgres backend - Auth: JWT access + rotating refresh tokens, argon2, roles, audit log - React 19 + Vite frontend: login page, protected route, auth context - Docker Compose: postgres, redis, migrate, api, worker (placeholder), frontend/nginx Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
58 lines
2.2 KiB
Python
58 lines
2.2 KiB
Python
"""Сборка DSN из настроек.
|
|
|
|
Регрессия: `PostgresDsn.build` не экранирует username/password сам —
|
|
спецсимвол в пароле (запятая, `@`, `:`, `/`) ломает разбор URL. Баг
|
|
воспроизводится только с «настоящим» паролем и незаметен на тестовых
|
|
значениях вроде `test` или `postgres`.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import pytest
|
|
|
|
from app.core.config import Settings
|
|
|
|
|
|
def _settings(**overrides: str) -> Settings:
|
|
defaults = {
|
|
"secret_key": "test-secret-key",
|
|
"encryption_key": "dGVzdC1lbmNyeXB0aW9uLWtleS0zMi1ieXRlcyEh",
|
|
"postgres_host": "postgres",
|
|
"postgres_port": 5432,
|
|
"postgres_db": "lux_fiscal",
|
|
"postgres_user": "lux_fiscal",
|
|
"postgres_password": "postgres",
|
|
}
|
|
return Settings(**{**defaults, **overrides}) # type: ignore[arg-type]
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"password",
|
|
[
|
|
"Jvth,fqkjn2020", # запятая — реальный пароль из этого проекта
|
|
"p@ss:word/with#special?chars",
|
|
"простой-пароль-с-кириллицей",
|
|
],
|
|
)
|
|
def test_database_url_survives_special_characters_in_password(password: str) -> None:
|
|
settings = _settings(postgres_password=password)
|
|
|
|
url = settings.database_url
|
|
|
|
assert url.startswith("postgresql+asyncpg://")
|
|
# Порт обязан остаться числом 5432 — при поломанном парсинге он
|
|
# «съезжает» вместе с частью пароля или пропадает совсем.
|
|
assert "@postgres:5432/lux_fiscal" in url
|
|
|
|
|
|
def test_database_url_roundtrips_via_sqlalchemy_make_url() -> None:
|
|
"""URL должен оставаться валидным для драйвера, а не только для pydantic."""
|
|
from sqlalchemy.engine import make_url
|
|
|
|
settings = _settings(postgres_password="Jvth,fqkjn2020")
|
|
parsed = make_url(settings.database_url)
|
|
|
|
assert parsed.password == "Jvth,fqkjn2020"
|
|
assert parsed.port == 5432
|
|
assert parsed.database == "lux_fiscal"
|