Документация / CI/CD и API
API Core
Через API Core доступно всё, что делает интерфейс: продукты, ассеты, уязвимости, аудиты, запуск сканов, настройки. Источник истины по методам и полям - спецификация OpenAPI в самом Core. Эта страница - введение: адрес, аутентификация, общие правила и ключевые сценарии.
Базовый адрес и версия
- Базовый путь:
https://core.example.ru/api/v1/. Других версий API нет. - Формат - JSON. Исключение - приём отчётов
POST /api/v1/scan/import/:multipart/form-data. - Пути заканчиваются слешем:
/api/v1/findings/, а не/api/v1/findings. - Проверка живости без аутентификации:
GET /healthcheck/на порту 8000 процесса API - пустой ответ 200, см. Мониторинг и журналы.
Аутентификация
API принимает API-токен пользователя в заголовке:
Authorization: Token <токен>
- Токен один на пользователя и действует до ротации.
- Получить: "Профиль" → "Токен аутентификации API" или
GET /api/v1/profile/auth-token/. Нужна роль с правом "API токен" - "Просмотр". - Ротировать: кнопка "Ротировать" там же или
GET /api/v1/profile/auth-token/rotate/. Нужно "API токен" - "Изменение". Старый токен перестаёт действовать сразу. - Запросы выполняются с правами владельца токена: его ролями и областью продуктов, см. Роли и права.
- Заголовок
Authorization: Bearer ...Core не принимает - ответ 401. Интерфейс Core работает на JWT в cookie, для интеграций используйте толькоToken.
Отдельный пользователь для интеграций
Для CI и скриптов заведите сервисного пользователя с минимальной ролью под задачу. Пример роли для CI - Security checker.
Спецификация OpenAPI
| Что | Путь |
|---|---|
| Swagger UI | /api/v1/docs/ |
| ReDoc | /api/v1/redoc/ |
| Схема JSON | /api/v1/docs.json |
| Схема YAML | /api/v1/docs.yaml |
Спецификация - Swagger 2.0, заголовок "Core API". Ссылка "Swagger" есть в профиле пользователя. Откройте её в браузере, где вы вошли в Core.
Права и лицензия
- Чтение (
GET) требует права роли на уровне "Просмотр", запись - "Изменение". Право зависит от раздела: "Продукты", "Уязвимости", "Radar", "Глобальные настройки" и другие. - Без активированной лицензии - ответ 419
NO_LICENSE. - Платные функции без платной лицензии - 403
Paid feature only.. Методы Radar открыты лицензиям с доступом к Radar. Подробно - Лицензирование.
Пагинация и фильтры
Списки делятся на страницы по 24 элемента. Номер страницы - ?page=N. Размер страницы не настраивается.
{
"next": 2,
"previous": null,
"current": 1,
"count": 57,
"pages_count": 3,
"results": [ ... ]
}
nextиprevious- номера соседних страниц илиnull.- Часть списков (уязвимости, ассеты, продукты, аудиты) принимает
?slice_indexes=<начало>,<конец>- срез выборки, границы включительно. - Фильтры - query-параметры с суффиксами Django:
__exact,__in,__icontains. Напримерseverity__in=3,4,repository__exact=.... Полный список фильтров метода - в Swagger. - Поиск по тексту -
?search=....
Коды, которые встречаются в фильтрах:
| Справочник | Коды |
|---|---|
Критичность (severity) |
0 "Инфо", 1 "Низкая", 2 "Средняя", 3 "Высокая", 4 "Критичная" |
Статус (triage_status__in) |
0 "Решено", 1 "Не обработано", 2 "В работе", 3 "Назначено", 4 "Отклонено", 5 "Временно принят риск", 6 "Постоянно принят риск" |
Тип ассета (asset_type) |
0 "Репозиторий", 1 "Docker-образ", 2 "Домен", 3 "Хост", 4 "Облачный аккаунт" |
Ключевые методы
Префикс /api/v1/ опущен.
| Метод | Путь | Назначение |
|---|---|---|
| GET | profile/ |
текущий пользователь и его роли |
| GET | profile/auth-token/ |
свой API-токен |
| GET | profile/auth-token/rotate/ |
ротировать свой токен |
| GET, POST, PATCH, DELETE | products/ |
продукты |
| GET, POST, PATCH, DELETE | product-type/ |
типы продуктов, без пагинации |
| GET, POST, PATCH, DELETE | product-assets/ |
ассеты |
| GET | findings/ |
список уязвимостей с фильтрами |
| GET | findings/{id}/ |
уязвимость |
| POST | findings/{id}/set-status/{статус}/ |
сменить статус уязвимости |
| POST | findings/bulk/set-status/{статус}/ |
сменить статус выборки, заданной фильтрами |
| GET | findings/counters/triage-status/ |
число уязвимостей по статусам для выборки |
| GET, POST | findings/{id}/comments/ |
комментарии |
| POST | scan/import/ |
загрузить отчёт сканера, см. Загрузка отчётов из CI |
| GET | scanners/ |
сканеры и их импортёры |
| GET, DELETE | audit/, audit/{id}/ |
аудиты и их итоги по сканерам |
| POST | ci/pipelines/run/ |
запустить аудит продуктов в Radar |
| POST | products/bulk/run-audit/, product-assets/bulk/run-audit/ |
запустить аудит продуктов или ассетов, выбранных фильтрами |
| GET, POST, PATCH, DELETE | job-sequences/, jobs/ |
последовательности и джобы в них |
| GET, POST, PATCH, DELETE | ci/schedules/ |
расписания сканов |
| GET | ci/health-check/ |
связь Core с Radar: is_healthy, is_authenticated |
| GET, POST, PATCH, DELETE | quality-gate/ |
контроль качества |
| GET | license/ |
данные лицензии |
| GET | celery/tasks/active/ |
активные фоновые задачи |
Массовые методы - всегда с фильтром
Массовые методы .../bulk/... выбирают объекты по query-фильтрам. Всегда передавайте фильтр: например, products/bulk/run-audit/ без фильтров запустит аудит всех продуктов, доступных роли. Для конкретных продуктов используйте ci/pipelines/run/.
Статус в set-status - код или имя: resolved, unverified, verified, rejected, risk_accepted_temporarily, risk_accepted_permanently. Статус "Назначено" Core выставляет сам по данным Jira, когда у задачи уязвимости есть исполнитель.
Сценарии
Проверить токен
curl -s "https://core.example.ru/api/v1/profile/" \
-H "Authorization: Token <токен>"
Ответ 200 с данными пользователя (сокращено):
{
"id": 7,
"username": "ci",
"email": "ci@example.ru",
"roles": [ ... ]
}
401 - токен неверный. 419 - в Core не активирована лицензия.
Найти открытые критичные уязвимости репозитория
Статусы 1-3 - неразобранные, критичность 3-4 - "Высокая" и "Критичная".
curl -s -G "https://core.example.ru/api/v1/findings/" \
-H "Authorization: Token <токен>" \
--data-urlencode "repository__exact=git@gitlab.example.ru:team/payments.git" \
--data-urlencode "branch__exact=main" \
--data-urlencode "severity__in=3,4" \
--data-urlencode "triage_status__in=1,2,3" \
--data-urlencode "page=1"
Ответ 200 (сокращено):
{
"next": null,
"previous": null,
"current": 1,
"count": 1,
"pages_count": 1,
"results": [
{
"id": 4811,
"name": "Hard-coded password",
"severity": 3,
"current_sla_level": 1,
"product": 7,
"file_path": "app/settings.py",
"line": 42,
"repository": "git@gitlab.example.ru:team/payments.git",
"branch": "main",
"sla_violated": false
}
]
}
current_sla_level - код статуса уязвимости.
Посчитать уязвимости по статусам для проверки в CI
curl -s -G "https://core.example.ru/api/v1/findings/counters/triage-status/" \
-H "Authorization: Token <токен>" \
--data-urlencode "repository__exact=git@gitlab.example.ru:team/payments.git" \
--data-urlencode "branch__exact=main" \
--data-urlencode "severity__in=3,4"
{"0": 12, "1": 0, "2": 2, "3": 1, "4": 3, "5": 0, "6": 0}
Ключи - коды статусов. Сумма ключей 1, 2 и 3 - неразобранные уязвимости.
Отклонить уязвимость или временно принять риск
curl -s -X POST "https://core.example.ru/api/v1/findings/4811/set-status/rejected/" \
-H "Authorization: Token <токен>"
curl -s -X POST "https://core.example.ru/api/v1/findings/4811/set-status/risk_accepted_temporarily/" \
-H "Authorization: Token <токен>" \
-H "Content-Type: application/json" \
-d '{"accept_duration_days": 14}'
- Ответ 200 - уязвимость в новом статусе.
- Тот же статус повторно - 409
Finding already has status .... accept_duration_days- срок временного принятия риска в днях, не меньше 1.
Смена статуса запускает те же действия, что в интерфейсе: задачи Jira, уведомления. Подробно - Жизненный цикл уязвимости.
Запустить аудит продукта
curl -s -X POST "https://core.example.ru/api/v1/ci/pipelines/run/" \
-H "Authorization: Token <токен>" \
-H "Content-Type: application/json" \
-d '{"products": [7], "branch": "main", "job_sequence": 2}'
| Поле | Обязательное | Описание |
|---|---|---|
products |
да | id продуктов. Сканируются все их ассеты |
branch |
нет | ветка для ассетов-репозиториев, до 100 символов |
job_sequence |
нет | id последовательности. Не задан - последовательность ассета или по умолчанию |
exclude_asset_ids |
нет | id ассетов, которые не сканировать. Не передавайте пустой список |
Ответ 202 без тела. Аудиты создаются в фоне, по одному на ассет. Нужны право "Radar" - "Изменение" и лицензия с доступом к Radar.
Асинхронные операции
Ответ 202 значит "принято в работу", результат появляется позже:
| Операция | Как узнать результат |
|---|---|
POST scan/import/ |
GET audit/{audit_id}/: в scanners появится запись сканера |
POST ci/pipelines/run/, POST products/bulk/run-audit/ |
аудиты в GET audit/, пайплайны - в Radar |
POST findings/bulk/set-status/{статус}/ для выборки больше 24 уязвимостей |
ответ 202 с телом []; статусы меняются в фоне, проверьте повторным запросом списка |
Коды ответа
| Код | Когда | Что делать |
|---|---|---|
| 200 | успех | - |
| 201 | объект создан | - |
| 202 | операция принята в фоновую обработку | проверьте результат, см. выше |
| 204 | объект удалён | - |
| 400 | ошибка в данных: {"поле": ["текст"]} или {"detail": "текст"} |
исправьте запрос по тексту ошибки |
| 401 | нет заголовка Authorization: Token, токен неверный или ротирован |
проверьте токен и схему Token |
| 403 | у роли нет права; функция платная (Paid feature only.); подпись лицензии не прошла проверку или срок истёк |
проверьте роль и лицензию |
| 404 | объект не найден или вне области продуктов роли; номер страницы больше последней | проверьте id и область роли |
| 409 | конфликт: статус уже установлен, продукт с таким именем и типом существует | - |
| 419 | лицензия не активирована: {"detail": "NO_LICENSE"} |
активируйте лицензию, см. Активация лицензии в Core |
| 420 | POST license/activate/, а лицензия уже активирована |
замените лицензию через POST license/ |
| 500 | внутренняя ошибка | журнал бэкенда Core: поды из образа sf-core-back |
После 403 из-за неверной подписи или истёкшего срока Core удаляет лицензию, и следующие запросы получают 419.