
Открытая платформа SIEM, EDR и SOAR с искусственным интеллектом для самостоятельного развертывания, предназначенная для современных операций по обеспечению безопасности.
Самостоятельно размещаемый стек безопасности для небольших и средних команд, у которых нет выделенного
SOC. Установите агент на каждую конечную точку, укажите им сервер — и вы получите
журналы SIEM, контроль целостности файлов, уязвимости пакетов, обозреватель журналов на базе OpenSearch,
автономную ИИ-триаж и движок плейбуков SOAR — всё в одном
docker compose up.
Часть «ИИ» — это локально запускаемая модель Ollama (по умолчанию llama3.2:3b).
Журналы никогда не покидают машину; нет ключа OpenAI, нет ключа Anthropic, нет
связи с внешними серверами. Если хотите более умную модель и у вас достаточно ОЗУ — замените её в .env.

Собирает телеметрию с агентов Windows и Linux по одному TCP-каналу. События SIEM, оповещения, FIM, пакеты, сетевые подключения, открытые порты, активность Docker, кадры экрана.
Обнаруживает с помощью правил Sigma на конечной точке. 23 правила, покрывающих 23 техники MITRE
ATT&CK, поставляются в conf/sigma/builtin/; рядом можно размещать сообщества наборы правил.
Sigma сопоставляет именованные поля, а не текст, поэтому
Image|endswith: '\vssadmin.exe' нельзя обойти словом «vssadmin»,
встречающимся в несвязанном сообщении — а
CommandLine|utf16le|base64offset|contains читает внутри полезной нагрузки base64
-EncodedCommand, где в открытой командной строке виден только обёрточный код. По результатам оценки на корпусе: 9 из 10 атак ловятся одним лишь Sigma,
0 из 9 жёстких негативов ложно помечаются. Этот слой детерминирован и продолжает
работать, когда модель недоступна.
Коррелирует события между собой, чего не может сделать ни одно правило для отдельного события. Один
неудачный вход в систему — обычное дело; пять учётных записей, терпящих неудачу из одного источника за сорок секунд — это
password spray, и просмотр любого из этих пяти событий никогда не покажет
вам этого. Покрывает spray, brute force, успешный вход после повторных
неудач, а также всплески создания учётных записей или установки служб — на обеих
платформах, по идентификаторам событий Windows или по разобранным строкам auth.log.
Работает с двух точек обзора, потому что они видят разные атаки. На каждом хосте на агенте, где атака против одной машины видна полностью. И между хостами на пути приёма данных, где spray, прошедший по одной неудаче за раз по пятидесяти машинам, становится видимым — ни один агент не видит более одного события, и это более компетентная атака, поскольку широкий и неглубокий spray остаётся ниже как порогов блокировки на учётную запись, так и порогов на хост.
Общее покрытие с Sigma: 27 техник. Каждое окно срабатывает один раз, а не один раз на событие, и каждый счётчик ограничен — счётчик, привязанный к имени пользователя, предоставленному атакующим, — это примитив исчерпания памяти, а не обнаружение.
Сопоставляет обнаружения с MITRE ATT&CK на основе самих правил. Правила содержат
tags: attack.t1490, поэтому нет вручную поддерживаемой таблицы сопоставлений, которая могла бы устареть. Страница
покрытия разделяет три состояния, которые скрыл бы один «процент покрытия»:
покрыто и замечено, покрыто и тихо, и вообще не покрыто — последнее
— единственное, где тишина консоли ничего не значит.
Проводит триаж каждого события с помощью локальной LLM. Три воркера работают параллельно:
один следит за каждым входящим событием в реальном времени, один выполняет управляемые оператором
глубокие сканирования, а один решает, следует ли предпринять защитное действие
(BLOCK_IP, ISOLATE_HOST, KILL_PROCESS и т. д.).
Теневой режим для защитного воркера. Включите AI_SHADOW_MODE=1 — и
каждое автономное решение будет отправляться на утверждение человеку в SOAR Hub
вместо выполнения. Полезно для настройки модели на реальном
трафике, прежде чем позволить ей действовать самостоятельно.
Индексирует всё в OpenSearch, чтобы вы могли искать по своему флоту с помощью нечётких / точных / начинающихся-с запросов из одного места.
Запускает плейбуки SOAR, созданные в небольшом визуальном редакторе с многошаговым отслеживанием результатов по узлам; могут запускаться вручную или по решению ИИ.
Сканирует уязвимости установленных пакетов каждого агента по OSV (онлайн или через внутреннее зеркало).
Подтягивает каналы threat-intel с abuse.ch (Feodo, ThreatFox, URLhaus) в локальную таблицу индикаторов, с очисткой устаревших данных и переключателем для автономного режима.
Проверяет конфигурации агентов перед их отправкой. Разбор YAML, структурная форма и компиляция регулярных выражений — недопустимое регулярное выражение — это валидный YAML, который молча отключает содержащее его правило.
Встроенный удалённый рабочий стол через потоковую передачу JPEG по WebSocket, без отдельной установки VNC на конечной точке.
Боковая панель группирует всё в три раздела: телеметрия (панель управления, агенты, оповещения, активы, FIM, журналы, ИИ), автоматизация реагирования (защитные действия, плейбуки, правила автоматизации) и администрирование.
У каждого зарегистрированного агента есть своя страница с двенадцатью вкладками. Обзор показывает живые измерители ресурсов, самые последние журналы SIEM, метаданные агента и сводку угроз:

Оповещения — это всё, что уже пометили собственные правила корреляции агента. Окрашены по серьёзности, фильтруются, ищутся:

Вкладка AI Analysis — это сторона локальной LLM, обращённая к оператору. Ручные и автоматические сканирования попадают сюда. Каждое аналитическое заключение несёт чип вердикта, уверенность, индикаторы MITRE (когда модель их возвращает), IOC, следующие шаги и кнопку View Source, открывающую точную строку журнала, на которую смотрел ИИ:

Аппаратное обеспечение, программное обеспечение и сетевые сокеты на агента. Вкладка Hardware перечисляет каждое устройство PnP, Software — установленные пакеты, Network — каждый сокет TCP/UDP с его владеющим процессом:


Поиск по всем агентам на базе OpenSearch. Выберите агента, выберите набор данных (события SIEM, оповещения безопасности, события процессов, сеть, FIM, журналы аудита) и ищите. Также есть кнопка для открытия OpenSearch Dashboards (форк Kibana) для опытных пользователей:

Каждая попытка входа в саму платформу, как локальная, так и LDAP, с результатом, исходным IP-адресом и временной меткой. Полезно, когда кто-то в настроении «кто-когда-входил»:

Вам понадобится Docker 24+ с Compose v2 и Python 3.10+ на хосте (только для одноразового шага сборки агента). Полный стек требует ~16 ГБ ОЗУ, см. Системные требования ниже.```bash git clone https://github.com/d3vhex/Sentora.git cd Sentora
cp .env.example .env
python scripts/init_secrets.py
cd Sentora ./build_agent.sh # on Linux/macOS/WSL
cd ..
docker compose up --build -d
Откройте <http://localhost:8000>. Логин по умолчанию — `admin` / `admin123`.
Сразу же смените его в разделе **Users & Roles**.
Ollama автоматически загружает `llama3.2:3b` при первом запуске. Проверьте с помощью:```bash
docker exec sentora-ollama ollama list
Развёртывание агента: на странице Deploy Agent скопируйте однострочную команду для нужной ОС. На целевой машине (в оболочке администратора) вставьте её. Установщик скачивает бинарник, сохраняет конфиг, регистрирует агента на сервере и добавляет себя в качестве запланированного задания / systemd-юнита.
| Сервис | Порт | Доступен с | Назначение |
|---|---|---|---|
app | :8000 | откуда угодно | REST API + React UI |
ingest | :5001 | откуда угодно | TCP-коллектор логов (агент отправляет сюда) |
db | :3307 | localhost | MySQL 8.0 (3306 внутри сети) |
rabbitmq | :5672 / :15672 | localhost | Очередь задач + UI управления |
ollama | :11434 | localhost | Локальная среда LLM |
opensearch | :9200 | localhost | Полнотекстовый поиск по логам |
opensearch-dashboards | :5601 | localhost | Опциональный обозреватель в стиле Kibana |
ai-worker-{automation,manual,defensive} | — | Рабочие процессы LLM-анализа |
Только app и ingest слушают все интерфейсы. Остальные привязаны к
BIND_ADDR (по умолчанию 127.0.0.1), потому что ни один из них не требует аутентификации
в конфигурации по умолчанию — OpenSearch работает с отключённым плагином безопасности, а
Dashboards — это неаутентифицированный просмотр всех собранных логов. Откройте доступ к какому-либо
из них, разместив его за тем же обратным прокси и аутентификацией, что и app, а не расширяя
BIND_ADDR.
Кнопка «Open Dashboards» в Log Explorer ведёт на порт 5601 по имени хоста сервера, поэтому она работает с самого хоста; удалённым операторам нужен этот обратный прокси.
| Профиль | CPU | RAM | Диск | Примечания |
|---|---|---|---|---|
| Лаборатория (≤ 5 агентов) | 4 ядра | 12 ГБ | 40 ГБ SSD | llama3.2:3b, куча OpenSearch 1 ГБ |
| Небольшая команда (10–50 агентов) | 8 ядер | 16 ГБ | 100 ГБ SSD | Настройки compose по умолчанию подходят |
| Продакшн (50+ агентов) | 16+ ядер | 32 ГБ+ | 250 ГБ+ NVMe | Вынесите OpenSearch и Ollama на отдельные хосты |
Фоновое потребление ресурсов:
llama3.2:3b): ~3 ГБ, больше при инференсеЕсли RAM в обрез, переключитесь на qwen2.5:1.5b или другую небольшую модель Ollama
и уменьшите кучу OpenSearch. GPU не обязателен, но Ollama
использует его автоматически, если он есть.
Когда вердикт защитного воркера — ACT с уверенностью ≥
AI_AUTO_ACT_CONF (по умолчанию 0.75) и рекомендуемое действие входит в
безопасный список ниже, воркер ставит действие в очередь прямо в таблицу
automations агента:```
BLOCK_IP KILL_PROCESS RESTART_SERVICE ISOLATE_HOST
DISABLE_USER QUARANTINE_FILE SUSPEND_PROCESS LOGOFF_USER
CONTAINER_ISOLATE CONTAINER_STOP CONTAINER_KILL
Все, что вне этого списка (произвольные `RUN_CMD`, `DELETE_FILE` и т. д.), понижается до рекомендательного инсайта. Оператору приходится отправлять это вручную из SOAR Hub. Автоматически отправленные действия показывают красный чип AUTO в интерфейсе.
Чтобы полностью отключить автономность, задайте `AI_AUTO_ACT_CONF=1.0` в `.env`. Чтобы отключить периодическую защитную проверку, задайте `AI_DEFENSIVE_SWEEP_ENABLED=0`.
### Теневой режим
Задайте `AI_SHADOW_MODE=1` в `.env`, и защитный воркер перестанет запускать реальные действия. Вердикты, которые могли бы вызвать автономный ответ, вместо этого сохраняются как **предложения** с `source_file = AI_DEFENSIVE_SHADOW` и `shadow_status = pending`. Оператор просматривает каждое из них в **SOAR Hub > Shadow Queue** и либо:
- **Approve** > срабатывает реальное действие SOAR (`call_agent_soar`), и предложение помечается как `approved` (с временной меткой и именем оператора).
- **Reject** > предложение помечается как `rejected` с необязательной заметкой. Никаких действий не выполняется.
Предложения никогда не истекают; за вас никто не решает. Полезно для того, чтобы дать модели поработать на продакшн-телеметрии, пока вы набираетесь уверенности в её вердиктах, прежде чем задействовать реальные `BLOCK_IP` / `ISOLATE_HOST` и т. д.
---
## Заметки по безопасности
### Аутентификация
Интерфейс аутентифицируется через серверную сессию: при входе выдаётся непрозрачный токен в cookie `HttpOnly`, а `userdb.sessions` является источником истины. Хранится только SHA-256 хэш токена, поэтому дамп базы данных не даёт ничего пригодного к использованию.
Применяются два таймера, оба настраиваются в `.env`:
| Настройка | По умолчанию | Значение |
| :--- | :--- | :--- |
| `SESSION_IDLE_MINUTES` | `60` | Сессия завершается через это время после последнего запроса |
| `SESSION_ABSOLUTE_HOURS` | `12` | Жёсткий предел независимо от активности |
| `SESSION_COOKIE_SECURE` | `0` | Установите `1`, когда TLS завершается перед приложением |
| `SESSION_COOKIE_SAMESITE` | `Lax` | `Lax` блокирует межсайтовые POST/XHR, необходимые для CSRF |
Сессии немедленно отзываются при смене пароля, сбросе пароля администратором, изменении роли и удалении учётной записи — удаление доступа администратором больше не оставляет открытую вкладку пользователя рабочей.
Каждый маршрут защищён по принципу **deny-by-default**: без действительной сессии запрос отклоняется до запуска обработчика. Исключения — это конечная точка входа, оболочка SPA, статические ресурсы и конечные точки для агентов, которые аутентифицируются с помощью `X-Agent-Key` или токена регистрации.
`X-User-ID` по-прежнему отправляется фронтендом, но больше не является идентификацией — сервер проверяет его по сессии и отклоняет при несоответствии. Поскольку браузеры не могут прикреплять пользовательские заголовки к межсайтовым запросам без CORS preflight, требование его для запросов, изменяющих состояние, подкрепляет `SameSite` как второй контроль CSRF.
Защита маршрутов объявляется с помощью `@require_permission(...)` и применяется промежуточным ПО через реестр, поэтому она действует независимо от того, с какой стороны `@app.route` находится декоратор. Журнал загрузки выводит итог:```
[Auth] Routes: <n> permission-gated, <n> session-only, <n> public.
Если эта строка сообщает 0 permission-gated, RBAC не применяется — относитесь
к этому как к инциденту.
Каждый маршрут должен быть одним из трёх вариантов: ограниченным разрешениями, указанным в
_PUBLIC_HANDLERS, или названным в SESSION_ONLY_HANDLERS в
tests/test_auth_wiring.py с комментарием, объясняющим, почему одной сессии
достаточно. Тест проверяет это, поэтому новый маршрут не может незаметно появиться без контроля —
именно так run_playbook, delete_soar_action и test_ldap_connection
оказались доступны любой учётной записи, способной войти в систему.
Пять неудачных попыток для одной учётной записи или двадцать с одного адреса в течение
пятнадцати минут — и дальнейшие попытки отклоняются с кодом 429, пока окно
не пройдёт. Подсчёт ведётся из login_logs, который уже записывал каждый сбой
и который никто не читал — bcrypt был единственным тормозом для онлайн-подбора.
| Параметр | По умолчанию | Значение |
|---|---|---|
LOGIN_MAX_FAILURES_USER | 5 | Допустимое количество сбоев на учётную запись в окне |
LOGIN_MAX_FAILURES_IP | 20 | Сбоев на адрес; больше, потому что офис использует один NAT-адрес |
LOGIN_LOCKOUT_WINDOW_MIN | 15 | Насколько далеко назад учитываются сбои |
Проверка выполняется до сравнения пароля, поэтому она также устраняет разницу во времени
между известным и неизвестным именем пользователя. Она завершается открыто, если
login_logs недоступен: страница входа, которую невозможно открыть, потому что
аудиторская таблица не работает, — это сам по себе инцидент.
X-Forwarded-For учитывается только от узла, указанного в TRUSTED_PROXIES
(адреса или CIDR через запятую, по умолчанию пусто). Если перед
приложением ничего нет, заголовок предоставляется атакующим, поэтому безусловное доверие к нему —
именно это и было заменено — позволяло вызывающему коду записать любой адрес в аудиторский
журнал и сбросить собственный лимит скорости в том же запросе.```
TRUSTED_PROXIES=10.0.0.0/8,192.168.1.5
Оставьте пустым, когда приложение доступно напрямую.
### Собственный API агента
Агент прослушивает `0.0.0.0:9099` и работает как SYSTEM или root. Каждый маршрут
требует `X-Agent-Key`; `/self_destruct` требует именно ключ регистрации этого
агента, поэтому утёкший общий секрет флота не может удалить все
конечные точки одновременно. `/health` отвечает на проверку живости без ключа и
не раскрывает ничего больше без него.
Отсутствует разрешающий запасной вариант. Более ранняя сборка принимала любой непустой ключ
всякий раз, когда `AGENT_MASTER_SECRET` не был задан на хосте — а его никто
никогда не задавал, поэтому он был значением по умолчанию везде. EDR, который
открывается при сбое, хуже, чем отсутствие EDR, потому что консоль сообщает
о конечной точке как о защищённой.
`AGENT_BIND` перемещает слушатель. По умолчанию он всё ещё `0.0.0.0`, потому что
сервер обращается к агентам по HTTP на этом порту; привязка к loopback требует
замены транспорта, а не изменения конфигурации.
### CORS
`CORS_ORIGINS` по умолчанию пуст. В обычном развёртывании это приложение само
обслуживает SPA, поэтому запросы являются same-origin, и запись не нужна.
Подстановочный знак отклоняется сразу: браузеры отказывают в
`Access-Control-Allow-Origin: *` на любом запросе с cookie. Развёртывания с
раздельными источниками должны перечислять явные источники и задавать
`SESSION_COOKIE_SAMESITE=None` вместе с `SESSION_COOKIE_SECURE=1`.
### Секреты по умолчанию
`.env.example` поставляется с заполнителями. Настоящий `.env` игнорируется git.
Ротируйте их перед тем, как открывать платформу для чего-либо, кроме `localhost`:
- `DB_PASSWORD`
- `AGENT_SHARED_SECRET` (запасной вариант аутентификации агента). Автоматически
генерируется при первом запуске, если не задан.
Логин `admin / admin123` больше не нужно запоминать: учётная запись,
созданная при инициализации, создаётся с `must_change_password`, и пока этот
флаг установлен, сессия не может получить доступ ни к чему, кроме
`/change-password`. Это обеспечивается в middleware, а не в UI, потому что
флаг, который фронтенд обязан соблюдать, — это лишь рекомендация, а API
также отвечает на запросы curl.
### TLS-сертификаты
Ничего не поставляется с закрытым ключом. Рабочие `certs/server.key` и
`certs/rootCA.key` ранее были закоммичены, что давало каждому развёртыванию
одинаковую TLS-идентичность и публиковало её: любой, кто когда-либо клонировал
репозиторий, владел ключом, поэтому сертификат ничего не доказывал о том,
кто находится на другом конце.
При `TLS_ENABLED=1` и отсутствии сертификата приложение генерирует его при
первом запуске. Каждая установка получает собственный ключ, и ключ никогда не
покидает машину, которая его создала. `certs/*.key` и `certs/*.crt`
игнорируются git.
CA является самоподписанным, поэтому браузеры предупреждают, если вы не
доверяете ему явно. Это предупреждение честно — предпочтите его общему секрету,
который не вызывает никаких предупреждений. Для всего публичного укажите
`TLS_CERT` / `TLS_KEY` на настоящий сертификат; когда они заданы, но
отсутствуют, приложение сообщает об этом, а не подставляет самоподписанный.
Чтобы перегенерировать вручную:```bash
python certs/generate_certs.py --force
Старые ключи всё ещё находятся в истории git. Считайте пару, выпущенную до этого изменения, скомпрометированной; новые установки её больше не используют.
Сервер использует два ключа Fernet, оба автоматически генерируются при первом запуске:
| Ключ | Расположение | Защищает |
|---|---|---|
| Ключ агента | data/fernet.key (или FERNET_KEY_PATH) | Телеметрию агента; выдаётся через /api/agents/bootstrap |
| Ключ сервера | .env FERNET_KEY | Внутренние поля сервера в состоянии покоя (например, столбец пароля) |
Установите chmod 600 для обоих. Сделайте их резервные копии. Потеря любого из них сделает соответствующие
зашифрованные данные нечитаемыми. Ротации на месте пока нет.
Два независимых механизма, оба необязательные:
Обогащение по вердиктам (ai/intel.py). AI-воркер перекрёстно проверяет
индикаторы, найденные в логе, по AlienVault OTX и VirusTotal. Требуются
OTX_API_KEY / VT_API_KEY; если не заданы — внешние вызовы не выполняются вовсе.
Каналы индикаторов (core/threat_feeds.py). Ежечасно заполняет таблицу threat_intel
из abuse.ch — Feodo Tracker (адреса C2 ботнетов), ThreatFox
(смешанные IoC с оценкой доверия) и URLhaus (URL-адреса, распространяющие вредоносное ПО).
Индикаторы содержат last_seen и удаляются после THREAT_INTEL_STALE_DAYS
(по умолчанию 30): адрес, размещавший C2 в прошлом квартале, обычно теперь принадлежит
кому-то другому, и его сохранение приводит к бесконечным ложным срабатываниям. Каждый
канал ограничен THREAT_INTEL_MAX_PER_FEED строками, поскольку таблица читается
на пути срабатывания оповещений.
abuse.ch переводит загрузки за бесплатный ключ аккаунта. Если канал
возвращает 401/403, об этом сообщается в логе сервера; задайте THREAT_INTEL_AUTH_KEY.
Проверьте, что фактически поступило:```bash docker logs sentora-server | grep ThreatIntel
### Режим air-gap```ini
OSV_MODE=mirror
OSV_MIRROR_URL=http://osv.internal
THREAT_INTEL_MODE=off
# or serve the feeds internally:
# THREAT_INTEL_FEODO_URL=http://mirror.internal/feodo.json
С этими настройками, плюс OTX_API_KEY / VT_API_KEY не заданы, ничего не покидает
сеть. Шрифты встроены, Ollama локальный, CDN не используется.
/api/exposure/report подсчитывает незакрытые пакеты и события целостности файлов
по всему флоту, по каждому агенту, начиная с худших. Он сообщает о собственном покрытии:
complete: false, когда агента не удалось прочитать, потому что итог по половине
флота — это не итог по всему флоту.
Намеренно нет никакой оценки. Ранее конечная точка возвращала
100 - vulns*2 - fim*5 как «оценку соответствия» — она не соответствует ни одному фреймворку,
не масштабируется с размером флота и обнуляется на любом реальном флоте. Градация
серьёзности отсутствует по той же причине: в vulnerabilities_report нет
колонки серьёзности, а её поля зашифрованы в состоянии покоя, поэтому любую оценку
пришлось бы выдумывать.
POST /<agent>/config/<type> выполняет проверку до того, как что-либо достигнет сенсора:
разбор YAML, структурная форма и — самый важный слой — компиляция регулярных выражений.
Некорректное регулярное выражение — это вполне валидный YAML, который молча отключает
категорию, содержащую его, поэтому проверка только синтаксиса отправила бы его прямо
на конечную точку. Редактор проверяет через ту же конечную точку по мере ввода и
сообщает о проблемах с кликабельными номерами строк.
Agent (Win / Linux) │ TCP frames + REST polling ▼ ingest (:5001) ──► RabbitMQ ──► AI worker fleet (3 modes) │ │ ▼ ▼ MySQL (per-agent _db) ai_analysis_results │ ▼ app (Sanic :8000) ──► React UI + REST + WebSocket screen proxy
Более глубокая версия (раскладка по модулям, схема, AI-конвейер, автономность SOAR, поверхности air-gap) находится в
[docs/Sentora_Architecture.md](https://github.com/d3vhex/sentora/blob/HEAD/docs/Sentora_Architecture.md).
Эксплуатационная документация:
| Документ | Охватывает |
| :--- | :--- |
| [Архитектура](https://github.com/d3vhex/sentora/blob/HEAD/docs/Sentora_Architecture.md) | Раскладка модулей, поток данных, модель аутентификации, AI-конвейер |
| [Продакшн-развёртывание](https://github.com/d3vhex/sentora/blob/HEAD/docs/production-deployment.md) | Масштабирование, сетевая топология, TLS, резервное копирование, мониторинг, air-gap |
| [Runbook обновлений](https://github.com/d3vhex/sentora/blob/HEAD/docs/update-runbook.md) | Апгрейды, развёртывание агентов, миграции БД, откат |
| [Отчёт о прогрессе](https://github.com/d3vhex/sentora/blob/HEAD/docs/PROGRESS_REPORT.md) | Что изменилось и почему |
---
## Настройка разработки```bash
# 1. Database. Only init_userdb.sql — it creates and selects `userdb`.
#
# db/init.sql is NOT a server-init script. It is the per-agent schema
# template, applied by server.create_tables_if_not_exist() after
# connecting to that agent's own database, which is why it contains no
# CREATE DATABASE or USE. Running it standalone fails at line 5 with
# "No database selected" — the same way it broke every first-time
# `docker compose up` while it was mounted into the MySQL init directory.
mysql -u root -p < db/init_userdb.sql
# 2. Backend. requirements.lock pins every version the image is built
# from; requirements.txt is the loose list it was resolved from.
pip install -r requirements.lock
python app.py
# 3. Ingest (separate terminal)
python server.py
# 4. Frontend dev server
cd frontend
npm install
npm run dev
Тот же скрипт, три роли:```bash WORKER_TYPE=automation python ai_worker.py WORKER_TYPE=manual python ai_worker.py WORKER_TYPE=defensive python ai_worker.py
Production: пусть `docker-compose.yaml` сделает это.
---
## Вклад в проект
PR приветствуются. Перед открытием:
1. Форк → ветка → PR в `main`.
2. Запустите проверки:```bash
pytest -ra # no MySQL or RabbitMQ needed
python -m compileall -q app.py core security
cd frontend && npx tsc --noEmit && npm run build && cd ..
# With the stack up — enumerates every route and calls it twice
python scripts/api_smoke_test.py
@require_permission(...). Журнал загрузки
выводит итоговое количество; если он сообщает 0 permission-gated, что-то не так
с подключением, а не с вашим маршрутом.Для чего-то большего, чем исправление, сначала откройте issue, чтобы мы могли согласовать подход.
. ├── app.py # Sanic API + React SPA host ├── server.py # TCP ingest ├── ai_worker.py # AI worker fleet (3 modes) ├── ai/ │ ├── utils.py # LLM helpers, AI cache, SOAR queueing │ └── intel.py # OTX / VT per-verdict enrichment (opt-in) ├── core/ │ ├── mq.py # RabbitMQ publisher │ ├── opensearch.py # OpenSearch index/search │ ├── config_validation.py # Agent YAML validation (parse, shape, regex) │ └── threat_feeds.py # abuse.ch indicator feeds ├── security/ │ ├── session.py # Server-side session store │ └── ssrf.py # Proxy destination rules ├── scanners/ │ └── vuln.py # Server-side OSV scanner ├── scripts/ │ ├── init_secrets.py # Generate the secrets .env needs │ ├── rotate_db_password.py # Rotate the MySQL root password safely │ └── api_smoke_test.py # Exercise every route against a live server ├── tests/ # pytest; no MySQL or RabbitMQ required ├── frontend/ # React 18 + TS SPA │ └── src/lib/ # Shared logic (playbook action catalogue) ├── Sentora/ # Cross-platform agent ├── certs/ # Self-signed dev certs ├── docs/ # Architecture + screenshots └── docker-compose.yaml
---
## Лицензия
AGPL-3.0. См. [LICENSE](https://github.com/d3vhex/sentora/blob/HEAD/LICENSE).
Используйте, изменяйте, распространяйте. То, что AGPL добавляет поверх обычной GPL:
если вы запускаете модифицированную версию на сетевом сервере, где с ней
взаимодействуют другие пользователи, вы обязаны опубликовать изменения под AGPL тоже.
- Самостоятельный хостинг для внутреннего использования → нет обязательства раскрывать исходный код.
- Публичный SaaS на основе модифицированного Sentora → вы обязаны опубликовать
изменения.
- Хотите выпустить закрытый производный продукт или обойти условие сетевого копилефта?
Доступно коммерческое освобождение от лицензии. Свяжитесь с автором.
Название и логотип "Sentora" являются товарными знаками авторов проекта и
не покрываются AGPL. Форкайте свободно, но переименуйте, если распространяете
как собственный продукт.
---
## Чего нет в Community Edition
В Community Edition нет искусственных ограничений: ни лимита агентов, ни
лимита хранения, ни блокировки функций в ядре. Запускайте настолько широко, насколько
позволяет ваше оборудование.
Платное распространение Pro / Enterprise добавляет корпоративные функции-связки
(SAML/SCIM SSO, мультитенантность, отчёты о соответствии, HA, WORM-аудит,
подписанные пакеты обновлений для air-gap, утверждения SOAR с четырьмя глазами, премиальные
форвардеры тикетов/SIEM). Базовая возможность обнаружения никогда не
оказывается за этим барьером.
Если что-то из этого важно для вашего развёртывания,
[свяжитесь](mailto:[email protected]).