Перейти к основному содержимому
Accent

Accent / Пользователю

Руководство пользователя

Как читать вердикт, триаж одной находки и отчёта SARIF, работа через Monolit, встраивание в CI/CD.

Введение

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.

Описание операций

Как читать вердикт​

ПолеЧто означает
labelvulnerable — подтверждённая уязвимость (TP); safe — ложное срабатывание (FP); error — сервис не смог разобрать ответ модели
analysisОбоснование на русском
recommendationsЧто исправить или почему находку можно отклонить
ml_confidence1.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:

  1. Запустите сканирование как обычно.
  2. В списке уязвимостей смотрите столбец «Вердикт AI»: TP или FP.
  3. В карточке уязвимости откройте анализ и рекомендации Accent.

Находки без исходного кода рядом со срабатыванием (например, часть SCA) на триаж не отправляются. Если интеграция не выбрана в настройках приложения, столбец остаётся пустым.

Для большого числа находок платформа должна резать SARIF на страницы и опрашивать задачи Accent. Синхронный запрос на каждую уязвимость в поставке Accent отклоняется.

Встраивание в CI/CD​

  1. Сформируйте JSON одной находки или SARIF.
  2. Отправьте POST /analyze/async или POST /analyze/sarif/async с таймаутом 5–30 с.
  3. Опрашивайте GET /jobs/{id} до done / failed.
  4. По 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 запрос длится минуты и обрывается на балансировщике.

Аварийные ситуации​

  1. 503 при отправке. Очередь заполнена. Подождите Retry-After и повторите то же тело. Не запускайте пачку повторов сразу.
  2. 403 на /analyze. Это штатно. Перейдите на /analyze/async или /analyze/sarif/async.
  3. 404 на задаче. Истёк срок хранения или неверный идентификатор. Отправьте работу заново.
  4. label=error. Модель вернула неразборчивый ответ или сбой инференса. Повторите задачу; если повторяется — передайте администратору job_id и фрагмент кода.
  5. Долгий queued. На CPU одна находка занимает минуты, в очереди — дольше. Смотрите /health: поля jobs.queued, jobs.running, inference.in_use.

Часто задаваемые вопросы (FAQ)

Техническая поддержка

Если возникли вопросы по работе Accent, обратитесь к администратору системы или в службу поддержки: support@cybear.ru.

Поддержка Cybear

Не нашли ответ в документе?

Техподдержка: support@cybear.ru · +7 (495) 790-66-88, добавочный 3.

Написать в поддержку