Initial commit: backend scaffold, auth, frontend login
- 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>
This commit is contained in:
@@ -0,0 +1,57 @@
|
||||
"""Сборка 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"
|
||||
Reference in New Issue
Block a user