REST API¶
Полный и всегда актуальный справочник по API доступен в самом развёрнутом экземпляре Hub:
Там описаны все эндпоинты, включая административные. Эта страница описывает только те, что нужны для внешних интеграций, и общие правила работы с API.
С 0.33 в поставке есть портируемая спецификация OpenAPI 3
(docs/openapi/openapi.json) — по ней генерируются клиенты на любом языке.
Ту же спецификацию использует консольный клиент sshub.
Общие правила¶
Базовый путь — /api/v1. Все примеры ниже приводятся относительно него.
Формат — JSON. Имена полей в теле запросов и ответов записываются
строчными буквами через подчёркивание (product_id, created_at).
Успешный ответ оборачивается в поле data:
Ошибка возвращается в поле error. Текст сообщения локализован: язык
выбирается по заголовку Accept-Language, поддерживаются русский и
английский.
Время — во всех полях в UTC, в формате RFC 3339 с признаком Z.
Аутентификация¶
Есть два способа, и путать их нельзя.
| Кто обращается | Заголовок | Примечание |
|---|---|---|
| Пользователь или внешнее приложение с токеном | Authorization: Bearer <токен> |
Значение проверяется как JWT |
| Сервисная учётная запись | X-API-Key: <ключ> |
Также принимается Authorization: ApiKey <ключ> |
Ключ сервисной учётной записи и Bearer несовместимы
Ключ вида sa_…, переданный как Authorization: Bearer sa_…, будет
разобран как JWT, не пройдёт проверку и вернёт 401. Для ключей
используйте X-API-Key.
Ключ имеет вид sa_<8 шестнадцатеричных символов>_<секрет>. В базе хранится
только хеш ключа и его начало — по началу можно понять, какой именно ключ
использовался, но восстановить сам ключ нельзя. Полное значение показывается
один раз при создании.
Ограничение частоты¶
Лимит считается двумя слоями: общий пол по адресу клиента и отдельный лимит по личности — пользователю или ключу сервисного аккаунта.
| Что | Значение по умолчанию | Переменная |
|---|---|---|
| Обычные эндпоинты, по адресу | 600 запросов в минуту | RATE_LIMIT_API |
| По пользователю | 300 запросов в минуту | RATE_LIMIT_API_USER |
| По ключу сервисного аккаунта | 1200 запросов в минуту | RATE_LIMIT_API_SERVICE_ACCOUNT |
| Эндпоинты входа | 10 запросов в минуту | RATE_LIMIT_AUTH |
Лимит по личности выше общего пола по адресу не выполняется: с одного адреса интегратор всё равно упрётся в пол. Если значения заданы так, Hub сообщает об этом при старте, называя оба числа.
Если Hub стоит за обратным прокси, задайте TRUSTED_PROXIES — иначе все
запросы будут выглядеть пришедшими с адреса прокси, а заголовком
X-Forwarded-For лимит обходится подделкой.
Коды ответов¶
| Код | Когда |
|---|---|
200 |
Успех |
201 |
Объект создан |
202 |
Принято в обработку; результат появится позже |
400 |
Некорректный запрос: неверное поле, недопустимое расширение файла |
401 |
Нет аутентификации, ключ неверен, истёк или отозван |
403 |
Аутентификация есть, прав на этот объект нет |
404 |
Объект не найден либо возможность выключена |
409 |
Конфликт: объект уже существует |
413 |
Тело запроса больше допустимого |
422 |
Запрос корректен, но выполнить его нельзя в текущем состоянии |
429 |
Превышена частота запросов |
503 |
Очередь задач недоступна |
Загрузка отчёта сканера¶
Основной эндпоинт интеграции с системой сборки.
Поля формы:
| Поле | Тип | Обязательное | Назначение |
|---|---|---|---|
file |
файл | да | Отчёт. Расширение только .sarif или .json; архивы не принимаются |
format |
строка | нет | sarif либо sonarqube. Если не указан — определяется по содержимому |
engine |
строка | нет | Имя сканера, если в отчёте его нет |
engine_version |
строка | нет | Версия сканера |
commit_id |
строка | нет | Идентификатор ревизии |
verify_fixes |
булево | нет | Пометить отчёт как пригодный для автоматического закрытия исправленных находок |
Заголовок X-Commit-Id — альтернатива полю commit_id.
Ответ — 202 Accepted:
Обработка асинхронная
Код 202 означает «отчёт принят и поставлен в очередь», а не «отчёт
разобран». Счётчиков найденного в ответе нет. Ошибки разбора возникают
позже: узнать итог можно, запросив состояние отчёта по
GET /api/v1/reports/<report_id> — оно перейдёт из pending в
completed либо в failed.
Пример:
curl -X POST "https://hub.example.com/api/v1/products/$PRODUCT_ID/reports" \
-H "X-API-Key: $HUB_API_KEY" \
-H "X-Commit-Id: $(git rev-parse HEAD)" \
-F "file=@scan.sarif"
Подробности и примеры для систем сборки: Загрузка SARIF.
Поиск продукта по репозиторию¶
Позволяет заданию сборки не хранить идентификатор продукта, а находить его по адресу репозитория.
Требует права list_products.
Чтение находок¶
Поддерживает разбиение на страницы, сортировку и фильтры — по состоянию, критичности, сканеру и другим полям. Точный перечень параметров смотрите в Swagger UI: он меняется чаще, чем эта страница.
Требует права read_findings.
Периметр сканирования¶
Эти эндпоинты нужны, если внешний сканер должен брать список целей из Hub, а не хранить его у себя.
| Метод и путь | Назначение | Требуемое право |
|---|---|---|
GET /projects/<id>/scope/export |
Выгрузка периметра для сканера | любое право на проект |
GET /projects/<id>/scope |
Просмотр записей периметра | любое право на проект |
POST /projects/<id>/scope/filter |
Отбор целей, попадающих в периметр | любое право на проект |
POST /projects/<id>/scope/proposals |
Предложение добавить обнаруженный объект | upload_report |
POST /projects/<id>/scope/assets |
Инвентарь: обнаруженные пары домен ↔ IP | upload_report |
POST /projects/<id>/scope/resolution-report |
Домены, переставшие или снова начавшие резолвиться | upload_report |
GET /projects/<id>/scope/proposals |
Список предложений, ожидающих решения | любое право на проект |
POST /projects/<id>/scope/entries |
Добавление записи | manage_scope |
POST /projects/<id>/scope/import/netbox |
Импорт из NetBox | manage_scope |
Права разделены намеренно. Первые шесть строк — это то, что вызывает сканер:
ему достаточно upload_report, который у него и так есть для загрузки отчётов.
Изменение периметра и решения по предложениям — действия администратора и
требуют отдельного права manage_scope; выдавать его сканеру не нужно.
Предложение не расширяет периметр само по себе — его подтверждает администратор.
Сквозной сценарий с DomainScope: Связка DomainScope и Hub.
Ручная перепроверка¶
Доступны только при включённом признаке ручной перепроверки; иначе — 404.
Подробнее: Ручная перепроверка.
Приём обратных вызовов¶
| Метод и путь | Кто вызывает |
|---|---|
POST /api/v1/scanner-callbacks/verify-finding |
Сканер — с результатом перепроверки находки |
POST /api/v1/webhooks/ticketing/<project_id>/<секрет> |
Трекер задач — при изменении задачи; тело разбирает плагин-провайдера |
Обратный вызов сканера проверяется ключом и подписью тела; поддерживается
окно смены ключа, когда действительны сразу два. Адрес приёма уведомлений от
трекера содержит секрет в пути, и его можно перевыпустить через
POST /api/v1/projects/<id>/ticket-webhook/rotate — новый секрет
возвращается в ответе один раз.
Состояние фоновых задач¶
| Метод и путь | Назначение |
|---|---|
GET /api/v1/jobs |
Список фоновых задач |
GET /api/v1/jobs/stats |
Сводка по состояниям |
GET /api/v1/jobs/<id> |
Одна задача |
POST /api/v1/jobs/<id>/retry |
Повторить |
POST /api/v1/jobs/<id>/cancel |
Отменить |
Отмена работает и для уже выполняющейся задачи: обработчик проверяет отмену перед тем, как начать записывать результат.
Нарушения сроков¶
| Метод и путь | Назначение |
|---|---|
GET /api/v1/sla/violations |
Открытые нарушения сроков |
POST /api/v1/sla/violations/<id>/resolve |
Закрыть нарушение |
GET /api/v1/dashboard/sla-compliance |
Сводка соблюдения сроков |
GET /api/v1/dashboard/sla-trend |
Динамика |
Ручной ввод находки¶
Заводит находку без SARIF — для результатов ручного тестирования и систем, не
умеющих отдавать отчёт. Требует права upload_report. Поля: заголовок,
критичность, описание, узел или путь, идентификатор правила, название
«сканера». Повторный ввод той же находки дубля не создаёт.
Задачи во внешнем трекере¶
| Метод и путь | Назначение |
|---|---|
GET /api/v1/ticket-providers |
Установленные провайдеры задач |
GET /api/v1/projects/<id>/ticket-targets |
Цели заведения, доступные проекту |
POST /api/v1/findings/<id>/ticket |
Завести задачу |
POST /api/v1/findings/<id>/ticket/link |
Привязать существующую задачу |
POST /api/v1/findings/ticket/bulk |
Одна задача на группу находок |
POST /api/v1/findings/ticket-url |
Ссылка на форму создания (полуручной режим) |
POST /api/v1/projects/<id>/tickets/backfill |
Догнать историю проекта |
GET/PUT /api/v1/projects/<id>/ticket-provider/config |
Настройки провайдера для проекта |
POST /api/v1/projects/<id>/ticket-webhook/rotate |
Ротация секрета вебхука |
POST /api/v1/webhooks/ticketing/<project_id>/<secret> |
Приём вебхука от трекера |
Подробности — Учёт задач.
Теги, подавление и своды¶
| Метод и путь | Назначение |
|---|---|
POST/DELETE /api/v1/findings/<id>/tags |
Ручные теги находки |
POST /api/v1/findings/bulk-tags |
Теги на выборку находок |
POST /api/v1/findings/<id>/enrich-tags/<plugin_id> |
Ручное обогащение плагином |
GET/POST /api/v1/projects/<id>/suppression-rules |
Правила подавления |
POST /api/v1/projects/<id>/suppression-rules/<rule_id>/run |
Применить правило к накопленным находкам |
GET /api/v1/findings/inventory-rollup |
Свод инвентарных находок по пакету, узлу или CVE |
POST /api/v1/findings/inventory-rollup/bulk-status |
Массовое действие по строке свода |
GET /api/v1/findings/<id>/group-axes |
Оси группировки находки |
POST /api/v1/findings/merge, POST /api/v1/findings/<id>/unmerge |
Объединение находок вручную и его отмена |
Плагины¶
| Метод и путь | Назначение |
|---|---|
GET /api/v1/plugins/capabilities/finding-enrichers |
Плагины обогащения |
GET /api/v1/plugins/capabilities/inventory-sources |
Источники инвентаря |
GET /api/v1/projects/<id>/plugin-channels |
Каналы уведомлений проекта |
GET/PUT /api/v1/projects/<id>/plugin-channels/<plugin_id>/config |
Настройки канала |
POST /api/v1/admin/installed-plugins/<id>/sync-now |
Внеочередной опрос источника |
POST /api/v1/admin/installed-plugins/<id>/acknowledge-capability-change |
Подтверждение расширения возможностей при обновлении |
GET /api/v1/admin/plugin-marketplaces/<id>/catalog |
Каталог источника |
POST /api/v1/admin/maintenance/channel-config-backfill |
Перенос настроек канала из ядра в плагин |
Метрики для систем мониторинга¶
| Метод и путь | Назначение |
|---|---|
GET /api/v1/grafana/projects/stats |
Показатели по проектам |
GET /api/v1/grafana/products/stats |
Показатели по продуктам |
GET /api/v1/grafana/sla/metrics |
Показатели по срокам |
Требуют права read_metrics, которое выдаётся только на общем уровне.
Вход и токены¶
| Метод и путь | Назначение |
|---|---|
GET /api/v1/auth/config |
Режим входа и список провайдеров с адресами кнопок |
GET /api/v1/auth/sso/<provider>/login |
Начало входа через провайдера |
GET /api/v1/auth/sso/<provider>/callback |
Возврат от провайдера |
POST /api/v1/auth/local/login |
Вход по логину и паролю |
POST /api/v1/auth/token/refresh |
Обновление токена доступа |
POST /api/v1/auth/logout |
Выход с отзывом всех токенов обновления |
GET /api/v1/auth/me |
Текущий пользователь и его права |
Обновление токена выполняется без тела запроса: токен обновления читается
из защищённой cookie и там же обновляется. Сохранены прежние адреса
/auth/keycloak/login и /auth/keycloak/callback — они работают как
синонимы для провайдера keycloak.
Права сервисных учётных записей¶
Право выдаётся на проект, продукт или на всю установку — набор допустимых уровней у каждого права свой.
| Право | Что разрешает | Уровни |
|---|---|---|
upload_report |
Загружать отчёты | проект, продукт, общий |
read_findings |
Читать находки | проект, продукт, общий |
read_reports |
Читать загруженные отчёты | проект, продукт |
list_products |
Искать продукты по адресу репозитория | проект, общий |
create_project |
Создавать проекты | общий |
create_product |
Создавать продукты | проект, общий |
update_product |
Изменять свойства продукта | проект, продукт, общий |
delete_product |
Удалять продукт | проект, продукт, общий |
read_metrics |
Читать показатели | общий |
manage_scope |
Управлять периметром | проект |
manage_notifications |
Управлять настройками каналов уведомлений | проект |
write_findings |
Менять состояние существующей находки: статус, назначение, поля триажа | проект, продукт, общий |
Выдача права с несовместимым уровнем отклоняется с кодом 400. Права
delete_product и manage_notifications дают доступ к разрушительным
действиям и к секретам каналов — выдавайте их осознанно.
write_findings отделено от upload_report намеренно
upload_report позволяет принести данные. Перевод находки в
«принятый риск» или «не будет исправлено» — решение о риске, и эквивалента
ему среди импорта нет. Ключ загрузки отчётов — самый распространённый и
самый часто утекающий из CI, поэтому закрывать находки он не должен.
По умолчанию право не выдаётся никому. Выдача на всю установку дополнительно требует срока действия: ключ, способный закрыть находки во всех проектах разом, не должен быть вечным.
Удаление находки ключу недоступно в любом случае — оно остаётся действием пользователя.
Что доступно по ключу¶
| Метод и путь | Право |
|---|---|
POST /api/v1/products/<id>/reports |
upload_report |
POST /api/v1/products/<id>/findings |
upload_report — ручной ввод находки без SARIF |
GET /api/v1/findings, GET /api/v1/findings/<id> |
read_findings |
PATCH /api/v1/findings/<id> |
write_findings |
GET /api/v1/sla/violations |
read_findings |
GET /api/v1/dashboard/* |
read_metrics |
GET /api/v1/products/lookup, GET /api/v1/products/scan-enabled |
list_products |
POST /api/v1/projects, POST /api/v1/projects/<id>/products |
create_project, create_product |
PUT/DELETE /api/v1/products/<id> |
update_product, delete_product |
Остальные маршруты — включая экспорт, массовые операции и заведение задач — доступны только по пользовательскому токену. Тем же разделением живёт консольный клиент.
Версия¶
Возвращают версию компонента. Используются интерфейсом для сверки версий и удобны как признак работоспособности после обновления.