Files
site_aegisone/error.md
T

107 lines
9.9 KiB
Markdown
Raw 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.
Root Causes & Plan
Ошибка 1: column bot_users_1.patronymic does not exist
Причина: _add_column_if_not_exists() — синхронная функция (def), но conn — AsyncConnection. conn.execute() возвращает корутину, которая никогда не awaits:
max_bot/app/main.py:91: conn.execute(sa_text(...)) — нет await
Лог при запуске: RuntimeWarning: coroutine 'AsyncConnection.execute' was never awaited
Миграции молча не выполняются, колонки не создаются.
План исправления:
main.py:88 — сделать async def _add_column_if_not_exists
main.py:91 — добавить await conn.execute(...)
main.py:75-85 — добавить await перед каждым вызовом _add_column_if_not_exists
После деплоя колонки создадутся при следующем рестарте
Ошибка 2: Тёмная тема в тестовом прогоне
Причина: bot_test.html — это полноценный HTML-документ (не наследует base.html), цвета жёстко закодированы в <style>:
body { background:#1B2838; color:#E8EDF2; ... }
.test-chat { border:1px solid #253248; ... }
Если портал в светлой теме, iframe остаётся тёмным.
План исправления:
Добавить в <head> скрипт инициализации темы (как в base.html:7)
Заменить хардкод на CSS-переменные (var(--bg-card), var(--text-primary), var(--border), var(--accent)) с запасными цветами
Импортировать service-theme.css или определить :root { } блок с reference-переменными
Что затронет:
Файл Изменение
max_bot/app/main.py:88-102 def → async def, await conn.execute()
max_bot/app/main.py:75-85 Добавить await перед каждым вызовом _add_column_if_not_exists
py_service/app/templates/pages/bot_test.html Добавить тему + CSS variables
Аудит — все баги и проблемы
🔴 P1 — CRITICAL (крашит бота)
# Файл Строка Проблема
1 main.py 88-102 _add_column_if_not_exists — def вместо async def, нет await — миграции никогда не выполнялись. Все 11 новых колонок не созданы → column patronymic does not exist
2 main.py 75-85 11 вызовов _add_column_if_not_exists без await — корутина возвращается, SQL не отправляется
🟠 P2 — CSS (внешний вид, тема)
# Файл Проблема
3 bot_test.html Полностью standalone HTML — 0 CSS-переменных, все цвета хардкодом. Не наследует тему
4 bot_consent.html 3 хардкод цвета (#155724, #721c24, rgba(0,0,0,0.5)). var(--light-bg) не определён — <th> прозрачные
5 bot_tickets.html 6 хардкод цветов статусов баджей. Тот же var(--light-bg) не определён
6 bot_kb.html 6 хардкод цветов (активные/неактивные, модалка, кнопка удаления). Тот же var(--light-bg) не определён
7 bot_settings.html 1 хардкод rgba(0,150,200,0.1) для фокуса
🟡 P3 — Блокировка event loop
# Файл Строка Проблема
8 inquiry.py 96-103 email_sender.send_ticket_escalation() — синхронный subprocess.run() + файловый I/O внутри async-функции. Блокирует event loop
🟢 P4 — SQL injection (низкий риск, но паттерн опасен)
# Файл Строка Проблема
9 main.py 91 f-string в sa_text() — {table}, {column}, {col_type} интерполируются напрямую. Сейчас вызывается с константами, но если переиспользовать — дыра
План исправления
P1 (2 файла):
main.py:88 — def → async def _add_column_if_not_exists
main.py:91 — conn.execute( → await conn.execute(
main.py:75-85 — добавить await перед каждым _add_column_if_not_exists(
P2 (5 файлов): 4. bot_test.html — скрипт темы (как в base.html:7) + заменить хардкод на var(--*) + <link> на CSS 5. bot_consent.html — заменить хардкод на CSS-переменные + var(--light-bg) → var(--bg-card) 6. bot_tickets.html — статус-баджи на CSS-переменные + var(--light-bg) → var(--bg-card) 7. bot_kb.html — хардкод на CSS-переменные + var(--light-bg) → var(--bg-card) 8. bot_settings.html — rgba(0,150,200,0.1) → var(--accent) с opacity
P3 (1 файл): 9. email_sender.py — subprocess.run обернуть в asyncio.to_thread() или loop.run_in_executor() для неблокирующего вызова
P4 (1 файл, профилактика): 10. main.py:91 — убрать f-string, использовать sa_text() с аргументами через bindparams() или встроить валидацию
Повторный аудит — после исправления P1-P4
Все P1-P4 (миграция, CSS, email, SQL-injection) считаю исправленными. Вот что остаётся:
🔴 CRITICAL — краши/NameError
# Файл Строка Ошибка
C1 main.py 179, 197 BotConversation не импортирован в main.py. Импорт: from app.models import Base (строка 12), без BotConversation. При контакте или dialog_cleared → NameError: name 'BotConversation' is not defined → HTTP 500
C2 main.py 516 VCF N-field regex сломан: r"N(?:;[^:]*)?:([^;\r\n]+)" — останавливается на ;, захватывает только фамилию. Для N:Doe;John;Michael;; вернёт только "Doe", имя и отчество теряются
C3 contact.py 23 Email пишется в user.phone: elif EMAIL_PATTERN.match(text): user.phone = text — должно быть user.email = text
C4 inquiry.py 40 user is None → AttributeError: _finalize_ticket(..., user, ...) → user.first_name упадёт, если BotUser не найден
C5 inquiry.py 53-54 Преждевременный commit: ticket создаётся, BotTicketMessage и BotTicketStatus — нет. Если второй commit упадёт — висячий тикет без описания и статуса
C6 docker-compose.yml 11-15 Секреты в VCS: пароль БД, токен MAX, секрет вебхука — хардкодом. Должны быть ${BOT_DATABASE_URL} c .env
🟠 HIGH — логические, prompt injection
# Файл Строка Ошибка
H1 yandex_gpt.py 65-104 Prompt injection: текст пользователя вставляется напрямую в system_prompt без экранирования или instruction boundary
H2 contact.py 42-50 Дубликат BotMessage: handle_message() уже сохранил сообщение (greeting.py:94-101), а handle_manual_contact() сохраняет то же самое повторно
H3 main.py 476 _extract_phone_from_vcf захватывает только код страны: regex r"\+?\d+" → для +7 (861) 203-33-30 возвращает +7
H4 greeting.py 33-59 Race condition на BotUser: два одновременных bot_started для нового пользователя → оба проходят if not user → второй падает с IntegrityError
H5 email_sender.py 35 Silent error: except Exception: без as e и без logger.error(). Ошибки sendmail глотаются
H6 inquiry.py 88 Блокировка event loop: email_sender.send_ticket_escalation() — синхронный subprocess.run() внутри async-функции
🟡 MEDIUM — состояние, атомарность, TOCTOU
# Файл Строка Ошибка
M1 main.py 452-469 TOCTOU на статус тикета: old_status читается, затем пишется — между ними другой запрос может изменить статус. Audit-log врёт
M2 inquiry.py 14-31,71-77 Двухсессионный дизайн: если _finalize_ticket упадёт между commits, conversation зависнет в "escalated" без тикета
M3 greeting.py 81-105 Stale state: conv.state читается в одной сессии, а используется после закрытия. Callback мог изменить состояние между чтением и маршрутизацией
M4 settings_cache.py 19-22 Double-load race: два одновременных get() оба увидят _loaded == False и оба загрузят кэш
M5 main.py 538 ORG regex обрезает отдел: [^\r\n;]+ не захватывает ;, теряется Engineering Dept из ORG:Acme Corp;Engineering Dept
M6 consent.html, tickets.html, kb.html var(--light-bg) undefined — CSS-переменная не определена нигде, прозрачные
M7 bot_test.html весь Standalone, 0 CSS-переменных — всегда тёмная тема, не наследует портал
🟢 LOW — мусор
# Файл Строка Ошибка
L1 main.py 482-487 Функция _extract_name_from_vcf никогда не вызывается (dead code)
L2 Несколько файлов Неиспользуемые импорты: Optional, json
L3 .gitignore .opencode/ не в gitignore
📊 Покрытие тестами — 15% (21 тест)
Критические пробелы — 0 тестов на:
FastAPI endpoints (webhook, health, users, tickets, KB CRUD, broadcast, settings)
VCF парсинг и handle_contact_share
handle_greeting, handle_message, analyze_and_respond
Обработка ошибок (MAX API down, DB down, GPT unavailable)
Webhook secret validation (401)
Concurrent requests