From 4d13a1ddb2c639b27bc9645e2d3f46a1092be5da Mon Sep 17 00:00:00 2001 From: Andrey Epifancev Date: Sat, 3 Oct 2026 23:47:39 +0400 Subject: [PATCH] =?UTF-8?q?fix:=20=D0=BD=D0=B0=D1=81=D1=82=D1=80=D0=BE?= =?UTF-8?q?=D0=B9=D0=BA=D0=B0=20OPENBAO=5F=5FMINIO=5F=5FMINIO=5FSECURE=20?= =?UTF-8?q?=E2=80=94=20http-MinIO=20=D0=B8=D0=B7=20compose=20=D0=B1=D0=B5?= =?UTF-8?q?=D0=B7=20SSL-=D0=BE=D1=88=D0=B8=D0=B1=D0=BA=D0=B8=20=D0=BF?= =?UTF-8?q?=D1=80=D0=B8=20=D1=81=D1=82=D0=B0=D1=80=D1=82=D0=B5=20(R-20)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit MinioSettings.MINIO_SECURE (по умолчанию true — https, как в шаблоне и на платформе) передаётся в Minio(secure=...); .env.example и .env.test — false (MinIO из docker compose слушает http). README: трейсбэк S3 из раздела «что в логе» убран, переменная добавлена в таблицу конфигурации. Co-Authored-By: Claude Fable 5.1 --- README.md | 10 ++++++---- api/.env.example | 2 ++ api/.env.test | 2 ++ api/src/app.py | 3 ++- api/src/core/config.py | 1 + api/tests/test_app.py | 22 +++++++++++++++++++++- api/tests/test_config.py | 2 ++ 7 files changed, 36 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 593359b..99037f8 100644 --- a/README.md +++ b/README.md @@ -155,15 +155,16 @@ Dev-пользователи (`api/seed/dev/users.yaml`, создаются `mak ### Что вы увидите в логе при запуске -Старт занимает около секунды; в логе два трейсбэка — это ожидаемо в dev, приложение при этом работает: +Старт занимает около секунды; в логе один трейсбэк — это ожидаемо в dev, приложение при этом работает: - Трейсбэк SMB: `Ошибка при регистрации сессии SMB ... Failed to connect to 'localhost:445': Connection refused`. Настройки `OPENBAO__SMB__*` — заглушки, SMB в Срезе 0 не используется; игнорируйте. Пока на `localhost:445` ничего не слушает, отказ приходит сразу (старт не задерживается); если порт отвечает, но молчит, ожидание ограничено тайм-аутом `smbclient` (60 с). -- Трейсбэк S3: `ClientConnectorSSLError ... localhost:9000`. Клиент S3 из шаблона ходит по `https`, а MinIO из compose - слушает `http`. S3 в Срезе 0 не используется (`app.state.storage` остаётся пустым). Это до исправления в задаче 22 - (отдельная настройка схемы подключения к MinIO). + +Строки `Бакет проверен`, `Подключение к NATS установлено` и `Подписка NATS активна. subject=recognition.result, +queue=arm-core` означают, что S3 и NATS из compose подключены (MinIO из compose слушает `http`, поэтому в `.env` +задано `OPENBAO__MINIO__MINIO_SECURE=false`). Недоступность SMB, S3 или NATS при старте приложение не роняет и не задерживает: ошибка логируется, состояние NATS видно в `/healthcheck`. К NATS ядро подключается в фоне и повторяет попытки само (`nats=down`, пока связи нет; warning @@ -202,6 +203,7 @@ docker compose -f ../docs/dev/docker-compose.yml down -v # полный сб | `OPENBAO__MINIO__MINIO_ADMIN_LOGIN` | — (обязательно) | логин MinIO | | `OPENBAO__MINIO__MINIO_ADMIN_PASSWORD` | — (обязательно) | пароль MinIO | | `OPENBAO__MINIO__MINIO_BUCKET` | — (обязательно) | бакет MinIO (`arm-ka`) | +| `OPENBAO__MINIO__MINIO_SECURE` | `true` | `true` — MinIO по `https` (платформа), `false` — по `http` (MinIO из compose; так в `.env.example`) | | `OPENBAO__NATS__NATS_URL` | — (обязательно) | адрес NATS (`nats://localhost:4222`) | | `OPENBAO__NATS__NATS_SEED` | пусто | nkey seed; пусто — подключение без учётных данных (compose, тесты). Задаётся вместе с `NATS_JWT` или не задаётся вовсе | | `OPENBAO__NATS__NATS_JWT` | пусто | JWT NATS; см. `NATS_SEED` | diff --git a/api/.env.example b/api/.env.example index 11c2988..952c90f 100644 --- a/api/.env.example +++ b/api/.env.example @@ -11,6 +11,8 @@ OPENBAO__MINIO__MINIO_URL=localhost:9000 OPENBAO__MINIO__MINIO_ADMIN_LOGIN=minioadmin OPENBAO__MINIO__MINIO_ADMIN_PASSWORD=minioadmin OPENBAO__MINIO__MINIO_BUCKET=arm-ka +# false — MinIO по http (docker compose); по умолчанию true (https, как на платформе) +OPENBAO__MINIO__MINIO_SECURE=false # NATS без JetStream; пустые NATS_SEED/NATS_JWT — подключение без nkeys OPENBAO__NATS__NATS_URL=nats://localhost:4222 diff --git a/api/.env.test b/api/.env.test index e348f24..fe6f5cb 100644 --- a/api/.env.test +++ b/api/.env.test @@ -9,6 +9,8 @@ OPENBAO__MINIO__MINIO_URL=localhost:59000 OPENBAO__MINIO__MINIO_ADMIN_LOGIN=minioadmin OPENBAO__MINIO__MINIO_ADMIN_PASSWORD=minioadmin OPENBAO__MINIO__MINIO_BUCKET=arm-ka +# false — MinIO по http (docker compose); по умолчанию true (https, как на платформе) +OPENBAO__MINIO__MINIO_SECURE=false OPENBAO__NATS__NATS_URL=nats://localhost:54222 OPENBAO__NATS__NATS_SEED= diff --git a/api/src/app.py b/api/src/app.py index 2a39269..ba70527 100644 --- a/api/src/app.py +++ b/api/src/app.py @@ -1,6 +1,6 @@ """Точка входа FastAPI. Каркас из шаблона команды: инфраструктура без доменного кода. -Что здесь есть: настройки, подключение S3 (MinIO), NATS (`src/core/nats.py`: core +Что здесь есть: настройки, подключение S3 (MinIO; `MINIO_SECURE` — https или http), NATS (`src/core/nats.py`: core NATS без JetStream, подключение в фоне при NATS_ENABLED=true независимо от DEBUG, подписка `recognition.result` в queue group `arm-core`), SMB (горячие папки ИС Сканирование), middleware (gzip, proxy headers, CORS, РАИСА при DEBUG=False), healthcheck (uptime, version, nats: ok|down|off), раздача собранного SPA. @@ -72,6 +72,7 @@ async def _connect_s3() -> S3Storage | None: settings.OPENBAO.MINIO.MINIO_URL, access_key=settings.OPENBAO.MINIO.MINIO_ADMIN_LOGIN, secret_key=settings.OPENBAO.MINIO.MINIO_ADMIN_PASSWORD, + secure=settings.OPENBAO.MINIO.MINIO_SECURE, cert_check=False, ) try: diff --git a/api/src/core/config.py b/api/src/core/config.py index 7648784..52604b7 100644 --- a/api/src/core/config.py +++ b/api/src/core/config.py @@ -12,6 +12,7 @@ class MinioSettings(BaseSettings): MINIO_ADMIN_LOGIN: str MINIO_ADMIN_PASSWORD: str MINIO_BUCKET: str + MINIO_SECURE: bool = True # https (шаблон, платформа); false — http (MinIO из docker compose) class NATSSettings(BaseSettings): diff --git a/api/tests/test_app.py b/api/tests/test_app.py index b0d0fda..5e5ff58 100644 --- a/api/tests/test_app.py +++ b/api/tests/test_app.py @@ -1,4 +1,4 @@ -"""Быстрые тесты каркаса приложения: lifespan, /healthcheck, префикс API (без БД и NATS). +"""Быстрые тесты каркаса приложения: lifespan, /healthcheck, префикс API, клиент S3 (без БД и NATS). Аутентификация и supervisor NATS — tests/test_nats_core.py (подключение переехало в src/core/nats.py, рулинг R-3). """ @@ -178,3 +178,23 @@ def test_create_nats_enabled_returns_connection_for_results(monkeypatch: pytest. assert isinstance(nats, NatsConnection) assert (nats.result_subject, nats.queue) == ("recognition.result", "arm-core") assert not nats.is_connected # создание не подключает: подключение — в start() + + +@pytest.mark.parametrize("secure", [True, False]) +async def test_connect_s3_passes_secure_flag(monkeypatch: pytest.MonkeyPatch, secure: bool): + created: dict[str, Any] = {} + + class _FakeMinio: + def __init__(self, endpoint: str, **kwargs: Any) -> None: + created.update(kwargs, endpoint=endpoint) + + async def bucket_exists(self, bucket: str) -> bool: + return True + + monkeypatch.setattr(app_module, "Minio", _FakeMinio) + monkeypatch.setattr(app_module.settings.OPENBAO.MINIO, "MINIO_SECURE", secure) + + storage = await app_module._connect_s3() + + assert storage is not None + assert created["secure"] is secure diff --git a/api/tests/test_config.py b/api/tests/test_config.py index e014a37..c4be000 100644 --- a/api/tests/test_config.py +++ b/api/tests/test_config.py @@ -26,6 +26,7 @@ def test_env_test_is_read(clean_env: pytest.MonkeyPatch) -> None: assert s.OPENBAO.NATS.NATS_URL == "nats://localhost:54222" assert s.AUTH_DEV_ISSUER is True assert s.NATS_ENABLED is False + assert s.OPENBAO.MINIO.MINIO_SECURE is False def test_defaults(clean_env: pytest.MonkeyPatch) -> None: @@ -57,6 +58,7 @@ def test_defaults(clean_env: pytest.MonkeyPatch) -> None: assert (s.OUTBOX_POLL_SECONDS, s.ACK_TIMEOUT_SECONDS, s.OUTBOX_MAX_REPUBLISH) == (5, 30, 3) assert s.OPENBAO.NATS.NATS_SEED == "" assert s.OPENBAO.NATS.NATS_JWT == "" + assert s.OPENBAO.MINIO.MINIO_SECURE is True def test_empty_nats_seed_and_jwt_allowed(clean_env: pytest.MonkeyPatch) -> None: