From 8bab9659887153147c2eebe243315b3143994f51 Mon Sep 17 00:00:00 2001 From: Andrey Epifancev Date: Sun, 4 Oct 2026 01:55:59 +0400 Subject: [PATCH] =?UTF-8?q?fix:=20dev-=D0=B7=D0=B0=D0=BF=D1=83=D1=81=D0=BA?= =?UTF-8?q?=20=D1=81=D0=BB=D1=83=D1=88=D0=B0=D0=B5=D1=82=20=D1=82=D0=BE?= =?UTF-8?q?=D0=BB=D1=8C=D0=BA=D0=BE=20127.0.0.1=20(M-11)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit В api/.env.example задан SERVER__HOST=127.0.0.1 (и SERVER__PORT=8000): при DEBUG и AUTH_DEV_ISSUER эндпоинт dev-токенов выдаёт токен любому, кто знает email. Значение приложения по умолчанию (0.0.0.0) не меняется. .env.test — те же ключи; новый тест сверяет набор ключей .env.example и .env.test. README: рекомендация в быстром старте и строка таблицы. Co-Authored-By: Claude Fable 5.1 --- README.md | 6 ++++-- api/.env.example | 5 +++++ api/.env.test | 4 ++++ api/tests/test_config.py | 20 +++++++++++++++++++- 4 files changed, 32 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index d37515e..2765b75 100644 --- a/README.md +++ b/README.md @@ -91,7 +91,9 @@ dev-пользователей. Seed идемпотентен: повторны cd api && .venv/bin/python run_server.py ``` -Сервер слушает `0.0.0.0:8000` (`SERVER__HOST`, `SERVER__PORT`). Дальнейшие команды — из другого терминала. +Сервер слушает `127.0.0.1:8000` (`SERVER__HOST`, `SERVER__PORT` из `api/.env`). Для dev-запуска оставляйте loopback: +при `DEBUG=true` и `AUTH_DEV_ISSUER=true` эндпоинт dev-токенов выдаёт токен любому, кто знает email пользователя, — +не открывайте его в сеть. Дальнейшие команды — из другого терминала. ### 6. Проверка @@ -197,7 +199,7 @@ docker compose -f ../docs/dev/docker-compose.yml down -v # полный сб |---|---|---| | `ENV_FILE` | `.env` | файл окружения (относительно `api/`) | | `DEBUG` | `false` | режим разработки. `true` необходим dev-эмитенту токенов; при `false` пакеты РАИСА подгружаются условно | -| `SERVER__HOST`, `SERVER__PORT` | `0.0.0.0`, `8000` | адрес и порт сервера (`run_server.py`) | +| `SERVER__HOST`, `SERVER__PORT` | `0.0.0.0`, `8000` | адрес и порт сервера (`run_server.py`); в `.env.example` — `127.0.0.1` (dev-запуск только на loopback) | | `ROOT_PATH` | `/` | корневой путь за прокси (должен совпадать с `REACT_APP_ROOT_PATH` фронта) | | `VERSION` | `1.0.0` | версия в `/healthcheck` и OpenAPI | | `OPENBAO__DATABASE__DATABASE_URL` | — (обязательно) | PostgreSQL, драйвер asyncpg: `postgresql+asyncpg://armka:armka@localhost:5432/armka` | diff --git a/api/.env.example b/api/.env.example index 2bd9534..97311dc 100644 --- a/api/.env.example +++ b/api/.env.example @@ -3,6 +3,11 @@ DEBUG=true +# Dev-запуск слушает только loopback: при DEBUG и AUTH_DEV_ISSUER эндпоинт dev-токенов выдаёт токен любому, кто знает +# email пользователя. По умолчанию приложения (без этой строки) — 0.0.0.0, как в контейнере платформы. +SERVER__HOST=127.0.0.1 +SERVER__PORT=8000 + # PostgreSQL (драйвер asyncpg) OPENBAO__DATABASE__DATABASE_URL=postgresql+asyncpg://armka:armka@localhost:5432/armka diff --git a/api/.env.test b/api/.env.test index 623e56d..8801f1d 100644 --- a/api/.env.test +++ b/api/.env.test @@ -4,6 +4,10 @@ DEBUG=true +# Как в .env.example (тесты сервер не запускают) +SERVER__HOST=127.0.0.1 +SERVER__PORT=8000 + OPENBAO__DATABASE__DATABASE_URL=postgresql+asyncpg://armka:armka@localhost:5432/armka OPENBAO__MINIO__MINIO_URL=localhost:9000 diff --git a/api/tests/test_config.py b/api/tests/test_config.py index f413f61..f06f7c6 100644 --- a/api/tests/test_config.py +++ b/api/tests/test_config.py @@ -15,7 +15,7 @@ API_DIR = Path(__file__).resolve().parent.parent def clean_env(monkeypatch: pytest.MonkeyPatch) -> pytest.MonkeyPatch: """Убирает из окружения процесса переменные, которые перебили бы значения из env-файла.""" for key in list(os.environ): - if key.startswith(("OPENBAO__", "AUTH_", "OUTBOX_", "ACK_")) or key in {"NATS_ENABLED", "DEBUG"}: + if key.startswith(("OPENBAO__", "AUTH_", "OUTBOX_", "ACK_", "SERVER__")) or key in {"NATS_ENABLED", "DEBUG"}: monkeypatch.delenv(key) return monkeypatch @@ -57,6 +57,7 @@ def test_defaults(clean_env: pytest.MonkeyPatch) -> None: assert s.OPENBAO.NATS.NATS_SEED == "" assert s.OPENBAO.NATS.NATS_JWT == "" assert s.OPENBAO.MINIO.MINIO_SECURE is True + assert (s.server.HOST, s.server.PORT) == ("0.0.0.0", 8000) # noqa: S104 - по умолчанию, как в контейнере smb = s.OPENBAO.SMB assert (smb.SMB_HOST, smb.SMB_PATH, smb.SMB_LOGIN, smb.SMB_PASSWORD) == ("", "", "", "") @@ -68,6 +69,7 @@ def test_empty_nats_seed_and_jwt_allowed(clean_env: pytest.MonkeyPatch) -> None: assert s.OPENBAO.NATS.NATS_JWT == "" assert s.NATS_ENABLED is True assert s.OPENBAO.SMB.SMB_HOST == "" + assert (s.server.HOST, s.server.PORT) == ("127.0.0.1", 8000) # dev-запуск — только loopback (M-11) REQUIRED_ENV = { @@ -105,3 +107,19 @@ def test_zero_republish_allowed(clean_env: pytest.MonkeyPatch) -> None: clean_env.setenv(name, required) clean_env.setenv("OUTBOX_MAX_REPUBLISH", "0") assert Settings(_env_file=None).OUTBOX_MAX_REPUBLISH == 0 # type: ignore[call-arg] + + +def _env_keys(name: str) -> set[str]: + lines = (API_DIR / name).read_text(encoding="utf-8").splitlines() + return {line.split("=", 1)[0] for line in lines if line.strip() and not line.lstrip().startswith("#")} + + +def test_env_example_and_env_test_have_same_keys() -> None: + """`.env.example` и `.env.test` перечисляют одни и те же переменные: новая настройка не забывается ни в одном.""" + assert _env_keys(".env.example") == _env_keys(".env.test") + + +def test_env_example_listens_on_loopback(clean_env: pytest.MonkeyPatch) -> None: + """Dev-запуск по `.env.example` слушает только 127.0.0.1 (финальное ревью M-11).""" + s = Settings(_env_file=API_DIR / ".env.example") # type: ignore[call-arg] + assert (s.server.HOST, s.server.PORT) == ("127.0.0.1", 8000)