Accent / Пользователю
Руководство пользователя
Как читать вердикт, триаж одной находки и отчёта SARIF, работа через Monolit, встраивание в CI/CD.
Accent
Версия Next
Введение
Accent — сервис интеллектуального триажа уязвимостей. Он принимает находку сканера или страницу отчёта SARIF и возвращает вердикт: реальная проблема или ложное срабатывание, обоснование и рекомендацию на русском языке.
Собственного веб-интерфейса у Accent нет. Пользователь работает через HTTP API либо видит вердикты Accent внутри платформы Monolit, если администратор подключил сервис как AI-интеграцию.
Основные возможности
- Оценка одной находки. Передаёте фрагмент кода и метаданные правила — получаете вердикт
vulnerable/safe, анализ и рекомендацию. - Пакетный разбор SARIF. Отправляете страницу документа SARIF 2.1.0 (до 20 находок) и забираете вердикты одним заданием.
- Асинхронная работа. Сервис сразу принимает задачу и отдаёт результат по короткому опросу статуса. HTTP-соединение не держится минутами.
- Локальная модель. Инференс выполняется on-prem, исходный код не уходит во внешние облака.
- Интеграция с Monolit. Вердикты отображаются в списке и карточке уязвимости платформы.
Подготовка к работе
Адрес стенда сообщает администратор. По умолчанию API слушает порт 13001.
Проверьте, что сервис отвечает:
curl -sS "http://<хост>:13001/health"
В ответе должно быть "status": "ok". Поле allow_sync_analyze в поставке равно false: синхронные запросы анализа отклоняются.
Учётных записей и токенов в Accent нет. Доступ к API ограничивает сеть. Не публикуйте адрес сервиса в интернет.
Интерактивная схема API доступна по адресу http://<хост>:13001/docs.
Описание операций
Как читать вердикт
| Поле | Что означает |
|---|---|
label | vulnerable — подтверждённая уязвимость (TP); safe — ложное срабатывание (FP); error — сервис не смог разобрать ответ модели |
analysis | Обоснование на русском |
recommendations | Что исправить или почему находку можно отклонить |
ml_confidence | 1.0 для vulnerable, 0.0 для safe и error |
Сервис подтверждает находку, если в переданном коде не видно защиты. Ложным срабатыванием он считает параметризованный SQL, экранирование, белый список, зашитый внутренний путь, код в каталоге тестов.
Качество оценки зависит от контекста. Передавайте функцию целиком и пометьте строку срабатывания маркером >>>. На CPU не отправляйте огромные файлы — достаточно одной функции.
Триаж одной находки
Шаг 1. Отправить задачу
curl -sS -X POST "http://<хост>:13001/analyze/async" \
-H "Content-Type: application/json" \
-d @finding.json
Пример finding.json:
{
"vuln_id": 1001,
"source": "bandit",
"rule_name": "B608:hardcoded_sql_expressions",
"primary_cwe": "CWE-89",
"file_path": "app/views/users.py",
"start_line": 42,
"code_context": " 38 def search_user(request):\n 39 conn = sqlite3.connect(\"app.db\")\n 40 cur = conn.cursor()\n 41 name = request.GET.get(\"name\", \"\")\n 42 >>> cur.execute(f\"SELECT * FROM users WHERE name='{name}'\")\n 43 return JsonResponse({\"rows\": cur.fetchall()})",
"code_snippet": "cur.execute(f\"SELECT * FROM users WHERE name='{name}'\")",
"description": "SQL statement built from f-string with HTTP-controlled value",
"owasp": ["A03:2021"]
}
| Поле | Обязательное | В модель |
|---|---|---|
code_context | да (или code_snippet) | да |
code_snippet | нет | запасной вариант, если контекст пуст |
source, rule_name, primary_cwe, file_path, start_line, description, owasp | нет | да, как метаданные |
vuln_id | нет | нет, только для вашей корреляции |
severity, likelihood, impact | нет | нет |
Успешный ответ — 202:
{
"job_id": "a1b2c3d4e5f67890abcdef1234567890",
"status": "queued",
"kind": "analyze",
"position": 1,
"poll_url": "/jobs/a1b2c3d4e5f67890abcdef1234567890"
}
После 202 тот же запрос повторять не нужно — получите дубликат задачи. Если сервис вернул 503, подождите секунд, указанных в Retry-After, и отправьте то же тело ещё раз: задача не создавалась.
Шаг 2. Дождаться результата
curl -sS "http://<хост>:13001/jobs/<job_id>"
Опрашивайте каждые 2–5 секунд, при долгой очереди увеличьте интервал до 10 секунд. Таймаут одного HTTP-запроса — 5–30 секунд.
status | Действие |
|---|---|
queued | Ждать. position — оценка места в очереди |
running | Ждать |
done | Забрать result и остановиться |
failed | Смотреть error. Если retryable равно true — отправить задачу заново |
Пример успешного результата:
{
"job_id": "a1b2c3d4e5f67890abcdef1234567890",
"kind": "analyze",
"status": "done",
"result": {
"label": "vulnerable",
"analysis": "SQL собирается через f-string из HTTP-параметра name без параметризации — возможна инъекция.",
"recommendations": "Использовать параметризованный запрос: cur.execute(\"SELECT ... WHERE name=?\", (name,)).",
"ml_confidence": 1.0
}
}
Если задача не найдена или истёк срок хранения — 404. Отправьте работу заново.
Триаж отчёта SARIF
Подходит, когда находок много: выгрузка сканера или пакет из Monolit.
Формат входа
Можно отправить «голый» SARIF (version + runs) или обёртку:
{
"offset": 0,
"limit": 20,
"sarif": {
"version": "2.1.0",
"runs": [
{
"tool": {
"driver": {
"name": "semgrep",
"rules": [
{
"id": "python.sql.injection",
"shortDescription": { "text": "SQL injection via f-string (CWE-89)" },
"properties": { "tags": ["CWE-89"] },
"defaultConfiguration": { "level": "error" }
}
]
}
},
"results": [
{
"ruleId": "python.sql.injection",
"level": "error",
"message": { "text": "Possible SQL injection" },
"locations": [
{
"physicalLocation": {
"artifactLocation": { "uri": "app/views/users.py" },
"region": {
"startLine": 42,
"snippet": { "text": "cur.execute(f\"SELECT * FROM users WHERE name='{name}'\")" }
}
}
}
]
}
]
}
]
}
}
Без offset и limit сервис берёт первые находки (не больше 20). Без region.snippet в SARIF поле code_context будет пустым, и оценка ухудшится.
Отправка страницы
curl -sS -X POST "http://<хост>:13001/analyze/sarif/async" \
-H "Content-Type: application/json" \
--data-binary @findings.sarif.json
Ответ 202 дополнительно содержит kind=sarif, total, offset, limit. Битый документ — 400, задача не создаётся. Переполнение очереди — 503.
Пока страница считается, GET /jobs/{id} показывает progress.processed без частичных вердиктов. После done в result приходит список:
| Поле | Назначение |
|---|---|
index | Порядковый номер находки во всём документе |
rule_id, file_path, start_line | Идентификация находки |
response | Тот же вердикт, что у одиночного триажа |
Если result.truncated равно true, отправьте следующую страницу с offset, увеличенным на limit.
Ошибка одной находки даёт ей label=error, страница всё равно завершается как done. Соседние вердикты не теряются.
Работа через Monolit
Если Accent подключён к приложению в Monolit:
- Запустите сканирование как обычно.
- В списке уязвимостей смотрите столбец «Вердикт AI»: TP или FP.
- В карточке уязвимости откройте анализ и рекомендации Accent.
Находки без исходного кода рядом со срабатыванием (например, часть SCA) на триаж не отправляются. Если интеграция не выбрана в настройках приложения, столбец остаётся пустым.
Для большого числа находок платформа должна резать SARIF на страницы и опрашивать задачи Accent. Синхронный запрос на каждую уязвимость в поставке Accent отклоняется.
Встраивание в CI/CD
- Сформируйте JSON одной находки или SARIF.
- Отправьте
POST /analyze/asyncилиPOST /analyze/sarif/asyncс таймаутом 5–30 с. - Опрашивайте
GET /jobs/{id}доdone/failed. - По
label=vulnerableпринимайте решение в пайплайне отдельно: на первых прогонах доля ложных срабатываний может быть заметной, автоматически ломать сборку не стоит.
Пример цикла для одной находки:
JOB=$(curl -sS -X POST "$ACCENT/analyze/async" \
-H "Content-Type: application/json" \
-d @finding.json | python -c "import sys,json; print(json.load(sys.stdin)['job_id'])")
while true; do
RESP=$(curl -sS "$ACCENT/jobs/$JOB")
STATUS=$(printf '%s' "$RESP" | python -c "import sys,json; print(json.load(sys.stdin)['status'])")
case "$STATUS" in
done|failed) printf '%s\n' "$RESP"; break ;;
*) sleep 5 ;;
esac
done
Синхронные запросы (только отладка)
POST /analyze и POST /analyze/sarif в поставке отвечают 403. Если администратор временно включил ALLOW_SYNC_ANALYZE=1, тот же JSON можно отправить синхронно и получить вердикт в одном ответе. В конвейерах и в Monolit этот режим не используйте: на CPU запрос длится минуты и обрывается на балансировщике.
Аварийные ситуации
- 503 при отправке. Очередь заполнена. Подождите
Retry-Afterи повторите то же тело. Не запускайте пачку повторов сразу. - 403 на
/analyze. Это штатно. Перейдите на/analyze/asyncили/analyze/sarif/async. - 404 на задаче. Истёк срок хранения или неверный идентификатор. Отправьте работу заново.
label=error. Модель вернула неразборчивый ответ или сбой инференса. Повторите задачу; если повторяется — передайте администраторуjob_idи фрагмент кода.- Долгий
queued. На CPU одна находка занимает минуты, в очереди — дольше. Смотрите/health: поляjobs.queued,jobs.running,inference.in_use.
Часто задаваемые вопросы (FAQ)
Техническая поддержка
Если возникли вопросы по работе Accent, обратитесь к администратору системы или в службу поддержки: support@cybear.ru.
