Closes#15 · мержить после #45 и #46 (ветка от feat/18-agent)
Что сделано
Детекторыapp/alerts/detectors.py — чистые функции после каждого раунда снапшотов (15 с):
💥 краш — выход с кодом ≠ 0 (docker stop с кодом 0 — не инцидент);
🧠 OOM;
🔁 цикл рестартов — ≥ 3 за 10 мин;
🩺 unhealthy;
🔥 перегрузка — CPU > 80 % или RAM > 90 % на протяжении минуты, всплеск не считается;
💾 мало места — < 10 % на разделе тома бота, то есть на диске хоста;
🔌 Docker API недоступен дольше 5 мин.
Пороги — в config/alerts.yaml.
По состоянию, а не по событиям. Условие появилось — алерт открывается, пропало — закрывается с «✅ Восстановлено · … · длилось N» ответом на исходное сообщение (AL-4). Бесконечный рестарт остаётся одним алертом.
Антиспам (AL-5). Повтор kind + service в течение 10 мин после закрытия снова открывает тот же алерт: в исходных сообщениях растёт «повторов: N», новых сообщений нет.
Рассылка (AL-1, AL-3). Алерт уходит всем активным участникам: тип, сервис, время, последние 30 строк лога и кнопки «📜 Логи», «🩺 Статус», «📋 Список алертов». Темп около 25 сообщений в секунду, RetryAfter пережидается, заблокировавший бота участник пропускается.
Кнопки под алертом открывают экран новым сообщением — сам алерт не затирается.
«🚨 Алерты» (AL-6). Активные сверху, затем история за 7 дней, по 10 на страницу; карточка — начало, конец, повторы, хвост лога.
🛡 атака через агента (#46) идёт через тот же сервис, только администраторам; повторные атаки одного участника — счётчик.
Если Docker недоступен, оцениваются только 🔌 и 💾 — алерты контейнеров вслепую не закрываются.
Убраны последние заглушки «Раздел в разработке».
Не сделано
📦 CD упал и ⛔ отказ после деплоя — нужны #11 (SourceCraft) и #13 (runner). В сервисе для них уже есть разовые события event(), останется только вызвать.
AL-7 «🔕 Тишина на час» (P2).
Как проверено
293 теста (21 новый): детекторы на инъектируемых часах; шторм — один алерт; флап — счётчик; область оценки при недоступном Docker; заблокировавший бота участник; восстановление только там, куда алерт дошёл; пагинация; кнопки под алертом не редактируют его.
Closes #15 · **мержить после #45 и #46** (ветка от `feat/18-agent`)
## Что сделано
- **Детекторы** `app/alerts/detectors.py` — чистые функции после каждого раунда снапшотов (15 с):
- 💥 краш — выход с кодом ≠ 0 (`docker stop` с кодом 0 — не инцидент);
- 🧠 OOM;
- 🔁 цикл рестартов — ≥ 3 за 10 мин;
- 🩺 unhealthy;
- 🔥 перегрузка — CPU > 80 % или RAM > 90 % на протяжении минуты, всплеск не считается;
- 💾 мало места — < 10 % на разделе тома бота, то есть на диске хоста;
- 🔌 Docker API недоступен дольше 5 мин.
Пороги — в `config/alerts.yaml`.
- **По состоянию, а не по событиям.** Условие появилось — алерт открывается, пропало — закрывается с «✅ Восстановлено · … · длилось N» ответом на исходное сообщение (AL-4). Бесконечный рестарт остаётся одним алертом.
- **Антиспам (AL-5).** Повтор `kind + service` в течение 10 мин после закрытия снова открывает тот же алерт: в исходных сообщениях растёт «повторов: N», новых сообщений нет.
- **Рассылка (AL-1, AL-3).** Алерт уходит всем активным участникам: тип, сервис, время, последние 30 строк лога и кнопки «📜 Логи», «🩺 Статус», «📋 Список алертов». Темп около 25 сообщений в секунду, `RetryAfter` пережидается, заблокировавший бота участник пропускается.
- **Кнопки под алертом** открывают экран новым сообщением — сам алерт не затирается.
- **«🚨 Алерты» (AL-6).** Активные сверху, затем история за 7 дней, по 10 на страницу; карточка — начало, конец, повторы, хвост лога.
- **🛡 атака через агента** (#46) идёт через тот же сервис, только администраторам; повторные атаки одного участника — счётчик.
- Если Docker недоступен, оцениваются только 🔌 и 💾 — алерты контейнеров вслепую не закрываются.
- Убраны последние заглушки «Раздел в разработке».
## Не сделано
- 📦 CD упал и ⛔ отказ после деплоя — нужны #11 (SourceCraft) и #13 (runner). В сервисе для них уже есть разовые события `event()`, останется только вызвать.
- AL-7 «🔕 Тишина на час» (P2).
## Как проверено
- 293 теста (21 новый): детекторы на инъектируемых часах; шторм — один алерт; флап — счётчик; область оценки при недоступном Docker; заблокировавший бота участник; восстановление только там, куда алерт дошёл; пагинация; кнопки под алертом не редактируют его.
- Покрытие 92%, ruff, mypy strict.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
- app/logs/grep.py: подмножество grep (шаблон, -i -v -E -c -C N), разбор
shlex без исполнения, BRE → regex, таймаут на строку и бюджет на поиск,
лимиты 200 символов / 500 строк вывода
- app/logs/journal.py: каждый поиск в log_queries (L-6)
- бот: выбор контейнера, хвост 50/200 строк или 5 мин/1 ч/24 ч, свой grep
по 24 ч, длинный результат — файлом .log (L-5)
- логи Docker: не больше 50 000 строк и 5 МБ, сохраняются новейшие
- fix: кнопки меню и /menu, /help больше не проглатываются шагами ввода
(имя файла, содержимое, сообщение коммита, grep) — фильтр free_input
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- prefilter: правила из config/agent_rules.yaml (длина, команды, shell,
секреты и системные файлы, prompt injection) — без LLM
- guard: отдельный вызов, JSON {verdict, reason}; невалидный ответ = attack,
недоступный LLM — «попробуйте позже», а не атака
- planner: только AgentLogQuery (контейнер из белого списка, ≤ 7 д, шаблон
≤ 200 без вложенных квантификаторов, лимит ≤ 500); логи в LLM не идут
- бот: «🤖 Спросить агента» → показывает построенный grep и строки;
атака — вежливый отказ и 🛡 администраторам; квота 30 в сутки
- журнал agent_requests + log_queries (mode=agent)
- при LLM_PROVIDER=mock агент выключен
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- детекторы по состоянию после каждого раунда снапшотов: краш, OOM,
цикл рестартов, unhealthy, перегрузка ≥ 1 мин, мало места, Docker
недоступен; пороги в config/alerts.yaml
- AlertService: ключ kind+service, повтор в 10 мин — счётчик в исходном
сообщении, «✅ восстановлено» ответом; разовые события (🛡) со счётчиком
- рассылка всем активным (🛡 — только админам), темп ~25/с, RetryAfter,
заблокировавший бота пропускается; alert_deliveries для правок и ответов
- «🚨 Алерты»: активные + 7 дней по 10, карточка; кнопки «📜 Логи»,
«🩺 Статус» под алертом открывают новое сообщение, а не затирают алерт
- 🛡 атаки через агента идут через общий сервис алертов
- убраны заглушки «Раздел в разработке» — у всех разделов свои роутеры
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Найдено смоуком на живых контейнерах (examples/, #19):
- контейнер с restart: on-failure поднимается за секунду — между раундами
его не видно в exited; краш теперь распознаётся и по росту RestartCount
(сравнение со снапшотами до текущего раунда), повторы — счётчик
- алерт закрывается, только когда условия нет resolve_after (60 с): иначе
флапающий сервис получал бы «✅ восстановлено» после каждого раунда
- правки сообщений со счётчиком — не чаще раза в минуту на алерт
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Closes #15 · мержить после #45 и #46 (ветка от
feat/18-agent)Что сделано
Детекторы
app/alerts/detectors.py— чистые функции после каждого раунда снапшотов (15 с):docker stopс кодом 0 — не инцидент);Пороги — в
config/alerts.yaml.По состоянию, а не по событиям. Условие появилось — алерт открывается, пропало — закрывается с «✅ Восстановлено · … · длилось N» ответом на исходное сообщение (AL-4). Бесконечный рестарт остаётся одним алертом.
Антиспам (AL-5). Повтор
kind + serviceв течение 10 мин после закрытия снова открывает тот же алерт: в исходных сообщениях растёт «повторов: N», новых сообщений нет.Рассылка (AL-1, AL-3). Алерт уходит всем активным участникам: тип, сервис, время, последние 30 строк лога и кнопки «📜 Логи», «🩺 Статус», «📋 Список алертов». Темп около 25 сообщений в секунду,
RetryAfterпережидается, заблокировавший бота участник пропускается.Кнопки под алертом открывают экран новым сообщением — сам алерт не затирается.
«🚨 Алерты» (AL-6). Активные сверху, затем история за 7 дней, по 10 на страницу; карточка — начало, конец, повторы, хвост лога.
🛡 атака через агента (#46) идёт через тот же сервис, только администраторам; повторные атаки одного участника — счётчик.
Если Docker недоступен, оцениваются только 🔌 и 💾 — алерты контейнеров вслепую не закрываются.
Убраны последние заглушки «Раздел в разработке».
Не сделано
event(), останется только вызвать.Как проверено
🤖 Generated with Claude Code
- prefilter: правила из config/agent_rules.yaml (длина, команды, shell, секреты и системные файлы, prompt injection) — без LLM - guard: отдельный вызов, JSON {verdict, reason}; невалидный ответ = attack, недоступный LLM — «попробуйте позже», а не атака - planner: только AgentLogQuery (контейнер из белого списка, ≤ 7 д, шаблон ≤ 200 без вложенных квантификаторов, лимит ≤ 500); логи в LLM не идут - бот: «🤖 Спросить агента» → показывает построенный grep и строки; атака — вежливый отказ и 🛡 администраторам; квота 30 в сутки - журнал agent_requests + log_queries (mode=agent) - при LLM_PROVIDER=mock агент выключен Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>