Files
2026-06-30 11:25:29 +04:00

65 lines
5.0 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Аудит кода contracts-flask — 2026-06-30
## Контекст
После переименования `services/``compare/` и восстановления сервиса проведён аудит кодовой базы.
Фокус: **что реально упадёт, сломается или работает нестабильно**. Без вылизывания.
Сервис непубличный, дев-окружение. Auth пока не нужен.
---
## ⚠️ Исправлено в этом цикле
### #1. POST-хендлеры без try вокруг Content-Length и json.loads
**Файл:** `deploy/convert_server.py`
**Проблема:** `_handle_api_sync`, `_handle_api_groups`, `_handle_apply_groups`, промпт-хендлеры — все делают `json.loads(self.rfile.read(length))` без try. Битый Content-Length → ValueError, пустой body → JSONDecodeError. Оба не ловятся → оборванное соединение.
**Фикс:** обёрнуто в try/except с возвратом `{"ok": false, "error": "..."}`.
### #11. ZIP-бомба в DrHider
**Файл:** `deploy/drhider/drhider.py`
**Проблема:** проверяется только заявленный `info.file_size` (можно подделать), нет лимита фактически распакованных байт, нет проверки ratio сжатия.
**Фикс:** скопирована защита из `compare/unzip.py` — накопительный счётчик распакованных байт + ratio-проверка (100×).
### #6. classify сбрасывает status у уже классифицированных документов
**Файл:** `deploy/compare/classify.py`
**Проблема:** `reset_classify_status(batch_id)` в начале `classify_batch()` сбрасывает на 'pending' ВСЕ документы батча, включая уже классифицированные. При повторном запуске — жжёт токены LLM на переклассификацию.
**Фикс:** `reset_classify_status` теперь сбрасывает только `'processing'` (crash recovery), оставляя `'classified'` и `'garbage'` нетронутыми.
---
## 🟡 Известные проблемы (не исправлены — низкий приоритет)
### SSE: двойная запись в мёртвый сокет
`convert_server.py` — при отвале клиента `run_pipeline` бросает `BrokenPipeError`, except ловит и **снова** зовёт `_sse` → второе исключение. Грязные трейсы, но не крашит сервер.
### classify: «успешный» JSON от LLM, который не dict
`classify.py``json.loads` может вернуть список/строку вместо dict → `AttributeError` → документ молча помечается failed. Случается редко.
### .doc через /upload не работает
`parse.py` зовёт `_parse_docx` (python-docx) для `.doc`, а тот читает только OOXML/.docx. Формат разрешён в `upload.py`, но не парсится. Надо либо убрать `.doc` из whitelist, либо звать `/convert-doc`.
### Гонка счётчиков в ThreadPoolExecutor
`classify.py` мутирует `garbage`, `json_total`, `type_counts` из 4 потоков через `nonlocal` без локов. Счётчики могут привирать на 1-2 единицы.
### _safe_json_parse — 4 уровня эвристик
Реаниматор битого JSON. Лечит симптом «LLM обрезал ответ». Дописывание кавычек/скобок вслепую может дать валидный но мусорный JSON → тихая неверная классификация.
### Весь файл в base64 в БД
`upload.py` хранит `original_bytes` как base64 (+33%) в Postgres. `SELECT *` таскает мегабайты. База пухнет.
### LLM URL/key захардкожены в 3 местах
`classify.py`, `drhider_server.py`, `llm_client.py`. Рассинхрон — тот же класс проблемы, что с `DB_NAME`.
### DrHider: PDF→txt + потеря форматирования DOCX
PDF на выходе становится `.txt`. Замена в DOCX сваливает текст в первый run → форматирование плывёт.
---
## ✅ Что НЕ является проблемой (проверено)
- SQL-инъекций нет — весь `db/` на параметризованных запросах
- Path traversal в static-раздаче прикрыт `realpath`+`startswith`
- Path traversal в ZIP-распаковке прикрыт (`unzip.py`, `drhider.py`)
- Nginx защищает от больших тел (client_max_body_size)
- DrHider двойной encode fix сделан