Остаток п. 9 ревью: синхронная БД вне event loop, повторное ревью
Повторное ревью кодовой базы: docs/reviews/2026-09-28-1243-codebase-review.md (статус 12 замечаний, новые замечания 13–16). Остаток п. 9 (docs/changes/022): - 14 async-функций API, UI и сервисов больше не обращаются к SQLite напрямую — через asyncio.to_thread; jobs.start_jobs стал async (БД в потоке, create_task в event loop); ops._conn для подключения к устройству; - тест-линтер по AST: в async def нет прямых вызовов функций с session_scope — защита от регресса. Тесты: 29 из 29. Стенд: задачи и актор событий в порядке, параллельные запросы не ждут медленного устройства, боевые данные не изменены. Ручная проверка UI пользователем на момент коммита не подтверждена. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
c4079724c5
commit
0bda0038d0
10 files changed
+320
-39
No files matched your search
@@ -0,0 +1,79 @@
|
||||
# Ревью кодовой базы ros_control — 2026-09-28 12:43 MSK
|
||||
|
||||
Повторное ревью. Состояние на коммит `c407972`. Тесты: 28/28 проходят.
|
||||
Предыдущее ревью: [`2026-09-27-codebase-review.md`](2026-09-27-codebase-review.md) (коммит `26dd1f8`).
|
||||
|
||||
## Итог
|
||||
|
||||
Из 12 замечаний предыдущего ревью закрыто 10 (одно — частично), открыто 2. Закрыты разделы «Безопасность»,
|
||||
«Корректность и согласованность», «Производительность и масштабирование»; раздел «Эксплуатация» не менялся.
|
||||
|
||||
| Изменение | Коммит | Пункты |
|
||||
|---|---|---|
|
||||
| `018-correctness-consistency` | `123b5ab` | 5, 6, 7 |
|
||||
| `019-performance-scaling` | `ba8ac7b` | 8, 9 (частично), 10 |
|
||||
| `020-custom-select-menus` | `6b5c521` | — (доработка UI по запросу) |
|
||||
| `021-security-hardening` | `c407972` | 1, 2, 3, 4 |
|
||||
|
||||
## Статус замечаний предыдущего ревью
|
||||
|
||||
### Безопасность
|
||||
|
||||
| № | Замечание | Приоритет | Статус | Подтверждение в коде |
|
||||
|---|---|---|---|---|
|
||||
| 1 | Небезопасные значения секретов по умолчанию | Высокий | ✅ 021 | `app/config.py::insecure_settings`; проверка первым шагом в `app/main.py::lifespan` — при пустых, `change-me` или коротких секретах (`API_TOKEN`, `SESSION_SECRET` ≥ 32, `ADMIN_PASSWORD` ≥ 12) и невалидном `SECRET_KEY` приложение не стартует |
|
||||
| 2 | Вход в UI без защиты от перебора | Высокий | ✅ 021 | `app/ui/routes.py::login`: 5 неверных за 10 минут → IP заблокирован на 10 минут (429, пароль не проверяется); `auth.locked` пишется один раз |
|
||||
| 3 | Сессионная cookie без флага Secure | Средний | ✅ 021 | `SESSION_COOKIE_SECURE` → `SessionMiddleware(https_only=…)`; по умолчанию выключен, за TLS — включить |
|
||||
| 4 | Открытый редирект в `/ui/move` | Низкий | ✅ 021 | `app/ui/routes.py::_safe_next` — только локальный путь; применён в `/ui/move` и групповом удалении бэкапов |
|
||||
|
||||
### Корректность и согласованность
|
||||
|
||||
| № | Замечание | Приоритет | Статус | Подтверждение в коде |
|
||||
|---|---|---|---|---|
|
||||
| 5 | Одиночное удаление бэкапа в обход сервиса | Средний | ✅ 018 | `app/ui/routes.py::backup_delete` → `backups.delete_many([key])` |
|
||||
| 6 | Две системы миграций | Низкий | ✅ 018 | `db._migrate` удалён; колонки старой схемы — `migrations._add_legacy_columns` при `user_version < 1` |
|
||||
| 7 | Синхронная групповая смена канала | Средний | ✅ 018 | Задачи `set_channel`; `PUT /api/v1/batch/channel` → 202 `{"job_ids"}` |
|
||||
|
||||
### Производительность и масштабирование
|
||||
|
||||
| № | Замечание | Приоритет | Статус | Подтверждение в коде |
|
||||
|---|---|---|---|---|
|
||||
| 8 | Каждое открытие «Бэкапов» перечитывает весь бакет | Средний | ✅ 019 | `app/services/backups.py::bucket_objects` — кэш на `BACKUPS_CACHE_TTL`, счётчик поколений, `invalidate()` после бэкапа и удаления, `refresh=1` |
|
||||
| 9 | Синхронная БД в async-обработчиках | Низкий | 🟡 019, частично | 44 обработчика стали `def`; фоновые записи — `asyncio.to_thread`; SQLite WAL + `busy_timeout`. Остаток — см. «Открытые замечания», п. 9 |
|
||||
| 10 | Состояние в памяти процесса | Низкий | ✅ 019 | `app/process_lock.py` — `flock` на `<файл БД>.lock` в `lifespan`; README «Ограничения» |
|
||||
|
||||
### Эксплуатация
|
||||
|
||||
| № | Замечание | Приоритет | Статус | Подтверждение в коде |
|
||||
|---|---|---|---|---|
|
||||
| 11 | Нет healthcheck, логирование не настроено | Низкий | ❌ Открыт | Нет `HEALTHCHECK` в `Dockerfile` и `docker-compose.yml`; логирование нигде не настраивается |
|
||||
| 12 | Тесты в одном файле | Низкий | ❌ Открыт, растёт | `tests/test_app.py`: 570 → 753 строки, 20 → 28 тестов |
|
||||
|
||||
## Открытые замечания
|
||||
|
||||
| № | Замечание | Где | Приоритет |
|
||||
|---|---|---|---|
|
||||
| 9 | Остаток синхронной работы с БД в async-коде: `groups.list_groups()` и `devices.list_devices()` в async-обработчике страницы «Бэкапы»; `devices.get_conn()` (чтение и расшифровка пароля) | `app/services/backups.py::search`, `app/services/ops.py::run_backup` | Низкий |
|
||||
| 11 | Нет healthcheck; логирование не настроено | `Dockerfile`, `docker-compose.yml`, `app/main.py` | Низкий |
|
||||
| 12 | Тесты в одном файле, файл растёт | `tests/test_app.py` | Низкий |
|
||||
|
||||
## Новые замечания
|
||||
|
||||
| № | Замечание | Где | Приоритет |
|
||||
|---|---|---|---|
|
||||
| 13 | Копирование БД в режиме WAL не описано: копия файла БД без `-wal` может быть неполной; нужен `sqlite3 .backup` или копирование вместе с `-wal` | `README.md` | Средний |
|
||||
| 14 | За reverse-proxy блокировка входа видит один IP прокси (нет настройки доверенных прокси и разбора `X-Forwarded-For`); ограничение описано в README | `app/ui/routes.py::login` | Низкий (прокси сейчас нет) |
|
||||
| 15 | `refresh=1` остаётся в адресе страницы «Бэкапы» после «Обновить список» — повторные перезагрузки идут мимо кэша | `app/ui/routes.py::backups_page` | Низкий |
|
||||
| 16 | Стенд запускается на порту 8001 через override-файл вне репозитория: порт 8000 на хосте занят посторонним процессом (`telemetry_web`); штатный `docker-compose.yml` без override не стартует. Порт не параметризован | `docker-compose.yml`, окружение хоста | Низкий (окружение) |
|
||||
|
||||
## Проверка UI
|
||||
|
||||
Ручная проверка интерфейса пользователем по изменениям 019–021 не подтверждена (отмечено в `summary.md` и сообщениях коммитов).
|
||||
Особенно важно для 020 (выпадающие списки): автотестов JS в проекте нет.
|
||||
|
||||
## Рекомендуемый порядок
|
||||
|
||||
1. **Изменение 022:** п. 11 (`HEALTHCHECK`, базовая настройка логов), остаток п. 9, п. 13 (копирование БД в README), п. 15.
|
||||
2. П. 16 — параметризовать порт в `docker-compose.yml` (`${HTTP_PORT:-8000}`) или освободить порт 8000 на хосте.
|
||||
3. П. 12 — разбить тесты по модулям отдельным изменением (только структура тестов).
|
||||
4. П. 14 — при появлении reverse-proxy: доверенные прокси и реальный IP клиента.
|
||||
Reference in new issue
Block a user