API VEGA

sentinelx-cloud-core

Управляйте вашими Linux-серверами из Claude.ai или ChatGPT безопасно. SentinelX предоставляет вашему LLM разрешённый к аудиту шелл: он может выполнять только те команды, которые вы явно разрешили; доступ к файловой системе ограничен per-path allowlist, и каждое действие фиксируется. Нет входящих портов — только один исходящий WebSocket. Модель безопасности — это суть. Предоставление LLM неограниченного шелла на сервере, которым вы руководите, — именно то, чего SentinelX избегает: allowlist является реальной границей доверия, поэтому агент не может запустить — или изобрести — ничего, чего вы не разрешили. Это агент, который устанавливаете на хосте; структурированные редактирования файлов и управление сервисами идут вместе с ним.

Установка (многие начинают с этого):

curl -fsSL https://get.sentinelx.app | sudo bash

SentinelX также указан в каталоге приложений ChatGPT — пользователи ChatGPT могут подключить его в один клик, без необходимости настраивать собственный MCP URL. Этот репозиторий также является исходником агента — читайте дальше, если хотите провести аудит или внести вклад.

Архитектура

Internet
                                            │
   ┌────────────────┐                       │                  ┌─────────────────┐
   │  Claude.ai or  │   MCP over HTTPS      │   WebSocket      │  Your Linux box │
   │   ChatGPT      │ ◄───────────────────► │ ◄──────────────► │                 │
   │                │   (OAuth via Google)  │                  │  ┌───────────┐  │
   └────────────────┘                       │                  │  │  agent    │  │
                                ┌───────────────────────┐      │  │ (this)    │  │
                                │   mcp.sentinelx.app   │      │  └─────┬─────┘  │
                                │  (SentinelX hub —     │      │        │        │
                                │   closed source)      │      │   shell, edit,  │
                                └───────────────────────┘      │   service mgmt  │
                                                               └─────────────────┘

Агент — это коробка справа. Во время установки агент открывает один исходящий WebSocket к хабу и поддерживает соединение постоянно. Входящие порты отсутствуют, проброс портов отсутствует, обратного туннеля нет.

Что запускается где

КомпонентГдеЧто делает
sentinelx-cloud-core (этот репозиторий)/opt/sentinelx-cloud-core на вашем хостеПринимает MCP-вызовы инструментов от хаба, выполняет их локально и возвращает вывод
Хабmcp.sentinelx.app (управляется Pensa)Аутентификация, маршрутизация по нескольким хостам, транспорт MCP
Конфигурация/etc/sentinelx/config.yamlAllowlist: какие команды, сервисы и пути агент примет
Идентификация/etc/sentinelx/identity.jsonJWT регистрации агента, используется для аутентификации рукопожатия WebSocket

Поддерживаемые платформы: любая современная Linux-дистрибуция с systemd (проверено на Ubuntu 22.04/24.04 и Debian 12). Агент также без изменений запустим внутри WSL2 на Windows — полезно для разработчиков, которые хотят, чтобы SentinelX управлял их окружением WSL совместно с любыми другими Linux-хостами.

Инструменты, доступные агенту

Агент представляет операции своей хост-системы как инструменты MCP вашему LLM через хаб:

ИнструментЧто делает
sentinel_execВыполнить разрешённую команду оболочки
sentinel_script_runЗапуск однократного bash- или python3-скрипта
sentinel_editСтруктурированное редактирование файлов (замена, по регулярному выражению, замена-блок, запись, добавление, префикс)
sentinel_edit_upload_*Трёхступенчатая загрузка для крупных редактирований файлов
sentinel_moveПереместить/переименовать файл или директорию
sentinel_copyСкопировать файл или директорию
sentinel_deleteУдалить файл или директорию
sentinel_chmodИзменить разрешения файла
sentinel_chownИзменить владельца/группу файла
sentinel_serviceуправление единицами через systemctl: start/stop/restart/reload/status
sentinel_restartКороткий путь к sentinel_service restart
sentinel_upload_fileОдноразовая загрузка файла на хост
sentinel_upload_*Трёхступенчатая порционная загрузка больших файлов
sentinel_readПрочитать содержимое файла с опциональным диапазоном строк
sentinel_listСтруктурированное перечисление содержимого каталога (имя, тип, размер, mtime)
sentinel_searchРекурсивный поиск по содержимому с использованием regex и фильтрами по glob
sentinel_capabilitiesВозвращает allowlist хоста и определения сервисов
sentinel_helpКраткое резюме агента плюс количество разрешённых команд, сервисов и плейбуков
sentinel_stateВнутреннее состояние агента, для отладки
sentinel_pingБыстрая проверка соединения

sentinel_read, sentinel_list и sentinel_search — это файловые примитивы только для чтения. sentinel_edit и мутирующие примитивы (sentinel_move, sentinel_copy, sentinel_delete, sentinel_chmod, sentinel_chown) — это операции записи. Все они дают LLM структурированный доступ к файловой системе без запуска внешних инструментов через exec (например, вызов cat/ls/mv/rm), и все они защищены тем же самым path allowlist (file_ops в конфигурации, см. ниже), а не списком разрешённых команд. Каждый путь в allowlist имеет уровень доступа: r (только чтение) или rw (чтение плюс запись). Записывающие операции, которые перезаписывают или удаляют существующий файл/каталог, сначала создают резервную копию с отметкой времени.

Дополнительно хаб предоставляет ряд интеграций на своей стороне (Cloudflare DNS, Resend email, Telegram) как MCP-инструменты, которыми ваш LLM может пользоваться вместе с инструментами агента — эти интеграции живут на хабе, а не в этом репозитории. См. таблицу интеграций на sentinelx.app.

Конфигурация (/etc/sentinelx/config.yaml)

Стартовый конфиг генерируется во время установки. Редактируемый. Перезагружается при перезапуске сервиса. Схема:

# Команды, которые агент может выполнять через операцию `exec`. Префиксное соответствие этому списку; пустой/отсутствующий означает запрет по умолчанию.
allowed_commands:
  - uptime
  - df -h
  - free
  - systemctl
  - sudo systemctl
  - journalctl
  # См. config.example.yaml для полного стартового списка (проверка файлов,
  # сети, контейнеры, git и пр.) плюс опциональные категории
  # (Cloudflare tunnels, WireGuard, Android tooling, firewalling, SSH).

# Юниты служб, которыми агент может управлять через `service` / `restart`.
# Каждый юнит явно перечисляет разрешённые действия.
services:
  nginx:
    actions: [status, start, stop, restart, reload]
  docker:
    actions: [status, restart]
  # Агент сам по себе, чтобы LLM могла перезагрузить политику после редактирования конфигурации.
  # Перезапуск повторно читает /etc/sentinelx/config.yaml. Только консервативные
  # действия — нет start/stop, поскольку агент не может удалённо запустить себя после остановки.
  sentinelx-cloud-core:
    actions: [status, restart, is-active, is-enabled]
  # postgresql:
  #   actions: [status, start, stop, restart, reload]

# Необязательное: именованные плейбуки, которые LLM может читать или исполнять.
# Поддерживаются две формы и могут сосуществовать в одном мапе:
#
# 1) Диагностический плейбук — фиксированная последовательность разрешённых команд,
#    агент может выполнить их по порядку. Удобно для_prompt-ов типа "дай quick health snapshot".
#
# 2) Процедурный плейбук — структурированный рецепт для LLM, который следует,
#    выраженный через поля `description` / `when` / `steps` / `requires` / `notes`.
#    Агент сам по себе не выполняет шаги — LLM читает их через `capabilities` и затем вызывает обычные
#    инструменты (`sentinel_exec`, `sentinel_edit`, `sentinel_service`) самостоятельно.
#
# См. `config.example.yaml` для полной справки.
playbooks:
  # Диагностический плейбук (форма 1)
  health:
    description: "Show system health summary"
    commands:
      - "uptime"
      - "df -h /"
      - "free -m"

  # Процедурный плейбук (форма 2) — проводит LLM через процесс расширения
  # allowlist'а самого агента. Удобно, если пользователь хочет "позволить run htop здесь",
  # и LLM знает точный порядок действий (изменение конфигурации, перезапуск сервиса,
  # проверка capabilities).
  add_allowed_command:
    description: "How to add a new command to this host's allowlist"
    when: "User asks to allow a new command on this host"
    steps:
      - "Read /etc/sentinelx/config.yaml with sentinel_exec"
      - "Insert under allowed_commands with sentinel_edit (sudo, validator_preset=yaml)"
      - "Restart the agent: sentinel_service restart sentinelx-cloud-core"
      - "Verify with sentinel_capabilities"

# Логирование
log:
  path: /var/log/sentinelx/core.log
  level: INFO

# SSRF-защита для file_url. Имя хоста должно быть в этом allowlist и резолвиться
# в публично доступный IP (нет loopback, RFC1918, link-local и т.д.). Значение по умолчанию пустое — file_url выключен.
# Только добавляйте хосты, которыми вы управляете — сторонние хосты (github.com, pypi,
# любые CDN) подвергнут агент риску компрометации цепочки поставок.
security:
  trusted_fetch_hosts:
    - drop.pensa.ar
    - get.sentinelx.app
  file_url_timeout_seconds: 15

# Файловые примитивы (sentinel_read/list/search + edit, move, copy,
# delete, chmod, chown). Ограничены тем же path-allowlist, отдельно от
# allowlist команд выше. Пустой/отсутствующий — все файловые примитивы
# фактически отключены (они возвращают path_not_allowed для любого ввода).
#
# Каждый элемент объявляет уровень доступа:
#   r  = операции только для чтения (read, list, search) могут трогать этот поддерево
#   rw = операции только для чтения И операции записи (edit, move, copy, delete,
#        chmod, chown) могут трогать этот поддерево
#
# Путь разрешён только если, после канонизации (разрешены симлинки,
# убран '..'), он попадает под один из этих элементов. Канонизированная
# резолюция затем проверка префикса — это защищает от path traversal и escapes через
# симлинки. Пустой allowlist = примитивы файловой системы отключены.
#
# Историческая совместимость: старый `allowed_read_paths:` также принимается и
# трактуется как набор записей `r` (с предупреждением об устаревании).
file_ops:
  paths:
    - path: /etc/nginx
      access: r
    - path: /var/log
      access: r
    - path: /home/youruser/projects
      access: rw
  max_read_bytes: 65536       # на чтение; большие файлы возвращаются усечёнными
  max_list_entries: 1000      # на список
  max_search_results: 200     # на поиск

Агент совершенно запускает команды только с префиксом в allowed_commands. Так, разрешение git позволяет LLM выполнять git status, git log и т. п.; разрешение ls достаточно для охвата ls -lah /var/log. По умолчанию конфигурация ограничительная — смотрите config.example.yaml для полного стартового списка с разумными категориями.

Существует две независимые allowlist’ы, и они защищают разные операции:

  • allowed_commands ограничивает выполнение команд через exec (и команды внутри script_run).
  • file_ops.paths ограничивает каждую файловую примитиву — чтение/перечисление (sentinel_read, sentinel_list, sentinel_search) на любом записи r или rw, а запись (sentinel_edit, sentinel_move, sentinel_copy, sentinel_delete, sentinel_chmod, sentinel_chown) — только на rw.

Так что каталог, указанный как r, позволяет LLM просматривать его, но не изменять; каталог, помеченный как rw, позволяет и то, и другое. Каталог, не перечисленный ни в одном из списков, недоступен для всех файловых примитивов (LLM придётся использовать exec, который регулируется allowed_commands).

Единственное явное исключение: sentinel_edit с sudo=true НЕ ограничено path-allowlist. Точка доверия для редактирования через sudo — это политика sudo-оператора, а не path allowlist — именно это позволяет плейбуку add_allowed_command редактировать конфигурацию ROOT-владельца. Канонизация путей всё равно выполняется (без обхода traversal и обходов через симлинки); только членство в rw обходится для пути with sudo. Это исключение и его остаточный риск задокументированы в THREAT_MODEL.md (§4.2.1).

Модель безопасности

  • Нет входящих портов. Только исходящий WebSocket к хабу.
  • Идентификация по JWT. identity.json подписан хабом при enrollment. Компрометация одного хоста не предоставляет доступ к другим.
  • Allowlist-защита. Всё, что не в config.yaml, возвращает command_not_allowed. Агент не будет синтезировать новые команды. Это реальная граница безопасности — не unix-пользователь и не политика sudo. Когда команда отклонена, агент возвращает классифицированную ошибку, которая направляет LLM к нужному инструменту, а не к угадыванию.
  • Файловая система. Любые структурированные файловые операции затрагивают только пути в file_ops.paths. Чтение/перечисление (sentinel_read, sentinel_list, sentinel_search) работают на r и rw; запись (sentinel_edit, sentinel_move, sentinel_copy, sentinel_delete, sentinel_chmod, sentinel_chown) — только на rw. Пути канонизируются — симлинки разрешены, .. сопоставляются — до проверки префикса, поэтому обход путей или выход за пределы allowlist невозможны. Пустой allowlist = примитивы отключены. Записывающие операции, которые перезаписывают или удаляют целевой файл/папку, делают резервную копию с отметкой времени. Исключение с sentinel_edit и sudo=true — документировано в THREAT_MODEL.md §4.2.1.
  • Неавторизованный пользователь с passwordless sudo. Агент работает от имени sentinelx, не от имени root. По умолчанию установщик предоставляет sentinelx passwordless sudo для управления сервисами и редактирования системных файлов — но всё равно можно делать только то, что разрешено в вашем allowlist. Чтобы запускать без sudo, установите SENTINELX_SKIP_SUDO=1 во время установки.
  • SSRF-защищённый file_url. При вызове upload_file по URL агент валидирует имя хоста против security.trusted_fetch_hosts, резолвит его в IP и отклоняет адреса типа loopback / RFC1918 / link-local. Перенаправления отключены, HTTPS по умолчанию, таймаут 15 сек. Allowlist по умолчанию пуст — file_url фактически отключён до тех пор, пока оператор не включит конкретные хосты.
  • Защита от path-traversal загрузок. Все аргументы target_path резолвятся в upload_base через safe_path_under(); .. и абсолютные пути, выходящие за пределы, отклоняются заранее.
  • Без телеметрии. Агент не сообщает ничего о вашем хосте или активности никому, кроме хаба, к которому вы явно подключены.

Для более глубокого обзора смотрите THREAT_MODEL.md (активы, противники, границы доверия, меры по каждому виду угроз) и SECURITY.md (отчёт о уязвимостях + политика раскрытия).

Локальная разработка

git clone https://github.com/pensados/sentinelx-cloud-core
cd sentinelx-cloud-core
python3 -m venv .venv
source .venv/bin/activate
pip install -e '.[dev]'
pytest                              # юнит-тесты

Чтобы запустить агент против хаба, отличного от продакшна:

SENTINELX_HUB_URL=wss://localhost:8000/agent/connect \
  python3 -m sentinelx_core --identity-file /tmp/dev-identity.json

Vendored: pensa-safe-edit

Фактическое редактирование файлов для sentinel_edit выполняется небольшим модулем stdlib-only, встроенным в src/sentinelx_core/vendored/pensa_safe_edit.py. Он вызывается внутри процесса через Python API (без вызова shell=True), поэтому в пути редактирования не используется внешний шелл. Он работает через временные файлы и атомарное переименование, делает резервную копию перед изменением, сохраняет метаданные файла и может запускать необязательный валидатор перед коммитом (json/yaml/toml/python/sh/nginx/systemd presets) — если валидация не прошла, исходный файл остаётся без изменений. Он по-прежнему зарегистрирован как точка входа в pip как консоль-скрипт для автономного/ручного использования.

Связано

Лицензия

Apache License 2.0 — смотрите LICENSE.