Files
contracts/History/sonnet-audit-request.md
T

12 KiB
Raw Blame History

Аудит для Sonnet — пофайловый разбор

Ты должен прочитать КАЖДЫЙ файл из списка ниже и выдать по нему детальный отчёт.

Формат отчёта ПОФАЙЛОВО

Для каждого файла:

### convert_server.py
| Строка | Тип | Серьёзность | Что не так | Как исправить |
|--------|-----|-------------|------------|---------------|
| 242    | dead code | low | Дубликат _handle_cleanup | Удалить второй |

После пофайлового разбора — СВОДНАЯ ТАБЛИЦА всех проблем по серьёзности: critical → high → medium → low.


Файл 1: contractor/deploy/convert_server.py

Что это: HTTP роутер на http.server + ThreadingMixIn. Все endpoint'ы приложения.

Что смотреть:

  • ВСЕ do_GET, do_POST, do_DELETE — правильная диспетчеризация? Нет мёртвых путей?
  • _handle_process_v2 — валидация UUID? SSE корректно закрывается при ошибке? Утечка соединений?
  • _handle_upload — размер тела? Content-Type проверка? Таумаут?
  • _handle_cleanup — ДВА определения (строки ~242 и ~255). Второй перекрывает первый. Dead code. Порядок DELETE правильный?
  • _handle_api_sync — читает JSON body. Что если тело пустое/битое? Что если keep_ids содержит 10000 id? Нет лимита.
  • _handle_api_document — doc_id из URL без валидации UUID → psycopg2.InvalidTextRepresentation на "fake-id".
  • _handle_api_document_delete — cascade порядок: spec_current → spec_events → supplements → document. Правильный?
  • _handle_classify_batch — batch_id из JSON без валидации UUID.
  • _handle_apply_groups — валидация структуры groups?
  • _handle_api_prompts_* — role из query params без валидации.
  • _json() — экранирует ли спецсимволы в данных?
  • _sse() — f-string с json.dumps. Данные от LLM могут содержать спецсимволы.
  • Импорт execute на строке 12 — не конфликтует с другими импортами?
  • ALTER TABLE ADD COLUMN IF NOT EXISTS — права на DDL? Идемпотентно?
  • CORS — _send_cors() вызывается везде? OPTIONS?

Файл 2: contractor/deploy/app.js

Что это: Весь фронтенд (42KB). Загрузка, классификация, группы, сравнение, промпты.

Что смотреть:

  • fileQueue, contractId, batchId — глобальные. Где расходятся с сервером?
  • renderTable()innerHTML из fileQueue[].name, fileQueue[].status. XSS?
  • fileInput change — гонка удаления старых + upload новых?
  • syncDB() — fire-and-forget, без await, без проверки ответа.
  • runClassify() — утечка таймеров при ошибке?
  • loadGroups() — ЕДИНСТВЕННОЕ место где diffBody. Больше никто не должен.
  • runCompareForGroup() — compareCard. Все ссылки compareBody/compareStatus?
  • llmBtn — compareCard. То же.
  • SSE handler'ы — ДВА почти идентичных. Дублирование.
  • showText()escHtml(classify_raw) ок, но counterparty, own_number — НЕ экранированы! XSS.
  • escHtml() — экранирует <>&"'?
  • stepDone/Active/resetStepper — innerHTML через replace. Спецсимволы в id?
  • window._groupsData — устаревает после remove→re-classify. runCompareForGroup использует индекс.
  • showClassifyBtn() — идемпотентно?
  • lucide.createIcons() — не ломает onclick?

Файл 3: contractor/deploy/app_utils.js

Что это: Утилиты: форматирование, removeFile, escHtml, модалки.

Что смотреть:

  • removeFile() — syncDB+resetStepper+showClassifyBtn через typeof. Если нет — молча.
  • formatDate(), formatSize() — null/undefined safe?
  • escHtml() — все опасные символы: < > & " '?
  • moveUp/Down — не вызывают syncDB (правильно, состав не меняется).

Файл 4: contractor/deploy/services/classify.py

Что это: LLM-классификация. ThreadPoolExecutor, выжимка, вызов LLM.

Что смотреть:

  • classify_batch() — reset + list_pending. Гонка между ними?
  • _classify_one()_smart_extract может упасть до LLM. Обрабатывается?
  • _smart_extract() — неожиданная структура elements_json?
  • _call_llm_classify() — httpx verify=False. MITM уязвимость.
  • _safe_json_parse() — edge cases: Null/None, числа без кавычек, пустой ответ.
  • MAX_WORKERS=4 — 4 одновременных запроса создают каждый свой пул?
  • LLM_KEY из env — если не задан?
  • API key в коде? (берётся из env, ок)

Файл 5: contractor/deploy/services/grouping.py

Что это: Группировка документов по контрактам + виртуальные группы.

Что смотреть:

  • group_documents() — виртуальные группы: что если parent_number и own_number оба null?
  • Коллизия normalize_number: разные номера → одинаковый нормализованный.
  • Сортировка по doc_date: None у всех → нестабильный порядок.
  • apply_groups() — нет проверки на существующий contract (дубликат при повторе).
  • supplements_list.remove(s) внутри цикла for — может пропускать элементы.

Файл 6: contractor/deploy/services/process.py

Что это: SSE пайплайн сравнения.

Что смотреть:

  • run_pipeline() — битая ссылка supplement→document? timeout? retry?
  • call_llm() — таймаут?
  • SSE события — все ли обрабатываются на фронте?

Файл 7: contractor/deploy/services/parse.py

Что это: Парсинг PDF/DOCX.

Что смотреть:

  • Расширение: .PDF uppercase? Без расширения?
  • PDF: битый/зашифрованный → исключение?
  • DOCX: .doc (OLE) → исключение?
  • Таблицы: пустые, объединённые ячейки?
  • file_data = None?

Файл 8: contractor/deploy/services/upload.py

Что это: Multipart загрузка через cgi.FieldStorage.

Что смотреть:

  • cgi.FieldStorage deprecated. Большие файлы?
  • content_length — отрицательное/огромное → rfile.read?
  • filename — path traversal (../../etc/passwd)?
  • 100MB файл → весь в памяти.
  • contract_id без валидации → SQL.
  • delete_by_document до создания нового → исключение = потеря старого без создания нового.
  • base64 → +33% размер.

Файл 9: contractor/deploy/db/connection.py

Что это: ThreadedConnectionPool.

Что смотреть:

  • DB_PASS из env, пустой → ошибка подключения.
  • minconn=1, maxconn=10 — достаточно?
  • getconn/putconn всегда в finally?
  • _connection глобальная — сервер не стартует без БД.

Файл 10: contractor/deploy/db/documents.py

Что это: CRUD documents + classify_raw.

Что смотреть:

  • insert() — все параметры через %s?
  • set_classification() — classify_raw=None → NULL.
  • set_classify_failed() — не чистит старые поля классификации.
  • delete() — без cascade!
  • get() — SELECT *, может вернуть base64 original_bytes.

Файл 11: contractor/deploy/db/supplements.py

Что это: CRUD supplements + cascade.

Что смотреть:

  • delete_by_document() — spec_current WHERE contract_id удаляет ВСЁ для контракта. Если несколько supplements → остальные теряют spec_current.
  • list_by_contract() — orphan supplements игнорируются.
  • insert() — нет FK проверки.

Файл 12: contractor/deploy/db/contracts.py

Что это: CRUD contracts.

Что смотреть:

  • insert() — нет уникальности, можно дубликат.
  • delete_orphaned() — вызывается? Где?

Файл 13: contractor/deploy/db/spec_events.py

Что это: Event Sourcing.

Что смотреть:

  • get_next_seq()MAX(seq)+1. Гонка! Два потока → одинаковый seq.
  • reset() — необратимо.
  • apply_ops() — валидация структуры?

Файл 14: contractor/deploy/db/spec_current.py

Что это: Текущая спецификация.

Что смотреть:

  • Кто обновляет spec_current после удаления spec_events?
  • get_elements_json() — где используется?

Файл 15: contractor/deploy/db/prompts.py

Что это: CRUD промптов с версионированием.

Что смотреть:

  • seed_defaults()if count>0: return — если есть extract но нет classify → classify не создастся.
  • _ensure_classify_prompt() — отдельный механизм, почему?
  • save_new_version() — UPDATE+INSERT не атомарно. Гонка.
  • activate() — гонка.
  • delete_prompt() — проверка is_active потом DELETE. Гонка.
  • _serialize() — мутирует словарь.

Файл 16: contractor/deploy/llm_prompt.py

Что это: Билдер промптов.

Что смотреть:

  • build_prompt() — f-string с данными парсинга. Безопасно?
  • _fetch_prompt() — HTTP к Lucee. Таймаут? Fallback при недоступности?
  • build_classify_prompt() — прямой доступ к БД, не через HTTP. Почему?
  • FALLBACK_* хардкод — дублирование с БД.

Файл 17: contractor/index.cfm

Что это: HTML-оболочка.

Что смотреть:

  • ?v=1.0.175 хардкод — менять при каждом обновлении JS.
  • pipelineStepper — ○✓ через replace. Надёжно?
  • XSS через prompt body в textarea/div?
  • Z-index конфликты модалок?
  • inline onclick — ломаются при перезагрузке JS?

СВОДНАЯ ТАБЛИЦА (выдать после пофайлового разбора)

# Файл:строка Серьёзность Тип Описание Как исправить

ТОП-5 (срочно)

5 проблем, которые надо чинить прямо сейчас.