Перейти к содержанию

REST API

Полный и всегда актуальный справочник по API доступен в самом развёрнутом экземпляре Hub:

https://<адрес-вашего-hub>/swagger/index.html

Там описаны все эндпоинты, включая административные. Эта страница описывает только те, что нужны для внешних интеграций, и общие правила работы с API.

С 0.33 в поставке есть портируемая спецификация OpenAPI 3 (docs/openapi/openapi.json) — по ней генерируются клиенты на любом языке. Ту же спецификацию использует консольный клиент sshub.

Общие правила

Базовый путь — /api/v1. Все примеры ниже приводятся относительно него.

Формат — JSON. Имена полей в теле запросов и ответов записываются строчными буквами через подчёркивание (product_id, created_at).

Успешный ответ оборачивается в поле data:

{ "data": { "id": "…", "name": "…" } }

Ошибка возвращается в поле 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 Очередь задач недоступна

Загрузка отчёта сканера

Основной эндпоинт интеграции с системой сборки.

POST /api/v1/products/<product_id>/reports
X-API-Key: <ключ>
Content-Type: multipart/form-data

Поля формы:

Поле Тип Обязательное Назначение
file файл да Отчёт. Расширение только .sarif или .json; архивы не принимаются
format строка нет sarif либо sonarqube. Если не указан — определяется по содержимому
engine строка нет Имя сканера, если в отчёте его нет
engine_version строка нет Версия сканера
commit_id строка нет Идентификатор ревизии
verify_fixes булево нет Пометить отчёт как пригодный для автоматического закрытия исправленных находок

Заголовок X-Commit-Id — альтернатива полю commit_id.

Ответ — 202 Accepted:

{
  "data": {
    "message": "Report queued for processing",
    "report_id": "…",
    "job_id": 12345
  }
}

Обработка асинхронная

Код 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.

Поиск продукта по репозиторию

Позволяет заданию сборки не хранить идентификатор продукта, а находить его по адресу репозитория.

GET /api/v1/products/lookup?repository_url=<адрес>
X-API-Key: <ключ>

Требует права list_products.

Чтение находок

GET /api/v1/products/<product_id>/findings

Поддерживает разбиение на страницы, сортировку и фильтры — по состоянию, критичности, сканеру и другим полям. Точный перечень параметров смотрите в 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.

Ручная перепроверка

POST /api/v1/projects/<id>/rescan
POST /api/v1/findings/<id>/rescan?via=scanner|llm

Доступны только при включённом признаке ручной перепроверки; иначе — 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 Динамика

Ручной ввод находки

POST /api/v1/products/<id>/findings

Заводит находку без 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

Остальные маршруты — включая экспорт, массовые операции и заведение задач — доступны только по пользовательскому токену. Тем же разделением живёт консольный клиент.

Версия

GET /version
GET /api/v1/version

Возвращают версию компонента. Используются интерфейсом для сверки версий и удобны как признак работоспособности после обновления.