Help:13-alpha MCP

From Svacer Wiki

Архитектура

MCP — открытый стандарт, через который LLM-клиенты (Claude Desktop, Cursor, VS Code, OpenWebUI и др.) вызывают внешние инструменты. Svacer MCP соединяет одно с другим: 8 инструментов поверх публичного REST API Svacer, которые LLM выбирает и вызывает в ответ на обычный текстовый запрос. Вместо ручной последовательности «открыть UI, найти проект, выбрать снимок, применить фильтр» достаточно сформулировать вопрос в чате, например, «сколько критических предупреждений в последнем снимке bash?», и получить ответ. Необходимые вызовы инструментов модель выполняет самостоятельно.

architectureMCP
Архитектура MCP-сервер

Поток запроса: LLM-клиент отправляет MCP-вызов через STDIO или Streamable HTTP → server.py передаёт его в выбранный инструмент из tools/ → инструмент проверяет параметры и обращается к api_client.py → клиент получает JWT от auth.py (модуль автоматически обновляет токен по истечении срока действия или при ответе 401) → запрос отправляется в Svacer REST API.

Установка

Установка Svacer MCP, подключение клиентов и конфигурация.

Требования

  • Python 3.10+
  • Доступ к Svacer-серверу: URL + логин/пароль

Режим STDIO

Подходит для настольных клиентов: Claude Desktop, Claude Code, Cursor, VS Code.

git clone https://gitlab.ispras.ru/svacerai/mcp.git && cd mcp

python3 -m venv .venv
.venv/bin/pip install -e .

cp .env.example .env
# Отредактировать .env — указать URL и учётные данные Svacer

# Проверить запуск (сервер ожидает данные на stdin; для выхода — Ctrl+C)
.venv/bin/svacer-mcp

После pip install -e . в окружении становится доступна команда svacer-mcp — её указывают в конфигурации клиентов ниже.

Режим HTTP (Docker)

Подходит для веб-клиентов (OpenWebUI) и удалённого доступа.

Требования: Docker, Docker Compose.

cp .env.example .env

# В .env обязательно задать SVACER_MCP_TOKEN — без него сервер не запускается
echo "SVACER_MCP_TOKEN=$(openssl rand -hex 32)" >> .env

docker compose up -d

# MCP endpoint: http://localhost:8002/mcp
# Клиенты передают заголовок: Authorization: Bearer <SVACER_MCP_TOKEN>

Внешний порт хоста задаётся переменной MCP_PORT (по умолчанию 8002), внутри контейнера сервер всегда слушает порт 8000.

Подключение клиентов

Claude Desktop

Файл конфигурации: ~/.config/Claude/claude_desktop_config.json (Linux) или %APPDATA%\Claude\claude_desktop_config.json (Windows).

Укажите абсолютный путь к svacer-mcp из вашего venv (which svacer-mcp в активированном venv или /path/to/mcp/.venv/bin/svacer-mcp).

{
  "mcpServers": {
    "svacer": {
      "command": "/path/to/mcp/.venv/bin/svacer-mcp",
      "env": {
        "SVACER_URL": "https://your-svacer.example.com",
        "SVACER_LOGIN": "your-login",
        "SVACER_PASSWORD": "your-password"
      }
    }
  }
}

Claude Code

claude mcp add svacer \
  -e SVACER_URL=https://your-svacer.example.com \
  -e SVACER_LOGIN=your-login \
  -e SVACER_PASSWORD=your-password \
  -- /path/to/mcp/.venv/bin/svacer-mcp

VS Code

Файл .vscode/mcp.json в корне рабочей директории:

{
  "servers": {
    "svacer": {
      "type": "stdio",
      "command": "/path/to/mcp/.venv/bin/svacer-mcp",
      "env": {
        "SVACER_URL": "https://your-svacer.example.com",
        "SVACER_LOGIN": "your-login",
        "SVACER_PASSWORD": "your-password"
      }
    }
  }
}

Cursor

Файл .cursor/mcp.json в корне проекта или глобально:

{
  "mcpServers": {
    "svacer": {
      "command": "/path/to/mcp/.venv/bin/svacer-mcp",
      "env": {
        "SVACER_URL": "https://your-svacer.example.com",
        "SVACER_LOGIN": "your-login",
        "SVACER_PASSWORD": "your-password"
      }
    }
  }
}

OpenWebUI

  1. Развернуть через Docker (см. «Режим HTTP» выше).
  2. Открыть Settings → Tools (или Admin Panel → Settings → Tools).
  3. Добавить сервер:
    • http://localhost:8002/mcp — если OpenWebUI работает на хосте, снаружи Docker.
    • http://svacer-mcp:8000/mcp — если OpenWebUI развёрнут в той же compose-сети, что и svacer-mcp (имя берётся из docker-compose.yml → service name, порт 8000 — внутренний порт контейнера).
  4. Тип подключения: MCP (Streamable HTTP).
  5. В настройках инструмента указать заголовок Authorization: Bearer <SVACER_MCP_TOKEN> (значение — то же, что в .env сервера).
  6. Сохранить — инструменты появятся в чате.

Конфигурация

Переменная По умолчанию Описание
SVACER_URL https://svacer-demo.ispras.ru URL Svacer-сервера
SVACER_LOGIN admin Логин
SVACER_PASSWORD admin Пароль
SVACER_TIMEOUT 30 Тайм-аут HTTP-запросов к Svacer, секунды
SVACER_TRANSPORT stdio Режим транспорта: stdio или http
SVACER_HTTP_PORT 8000 TCP-порт сервера в режиме HTTP (внутри контейнера)
SVACER_MCP_TOKEN (не задано) Bearer-токен для клиентов /mcp. Обязателен при SVACER_TRANSPORT=http, в режиме STDIO игнорируется. Генерация: openssl rand -hex 32
SVACER_MCP_RESOURCE_URL http://localhost:<HTTP_PORT> Публичный URL MCP-сервера для заголовка WWW-Authenticate (RFC 9728). Задаётся при работе за обратным прокси
SVACER_TOOLS (не задано) Список инструментов через запятую. Если не задано, регистрируются все 8
MCP_PORT 8002 Внешний порт хоста при запуске через docker compose (отображается на внутренний SVACER_HTTP_PORT)

Переменные читаются из .env или из окружения. Для STDIO-клиентов их можно указать в секции env конфигурации клиента.

Ограничение набора инструментов

Чтобы запустить сервер с подмножеством инструментов (например, для уменьшения объёма контекста у модели или разграничения доступа), задайте SVACER_TOOLS:

SVACER_TOOLS=get_projects,get_snapshots,get_markers

Допустимые имена: get_projects, get_snapshots, get_warnings, get_markers, get_project_stats, get_project_groups, get_advanced_file_preview, get_diff. Неизвестное имя в списке приводит к ошибке при запуске. Если переменная пустая или не задана, регистрируются все 8 инструментов.

Несколько экземпляров сервера

Параллельный запуск нескольких MCP-серверов поддерживается без ограничений.

  • В режиме STDIO каждая запись в конфигурации клиента описывает отдельный процесс — несколько подключений к разным экземплярам Svacer задаются простым перечислением.
  • В режиме HTTP запускаются независимые контейнеры на разных хост-портах: например, MCP_PORT=8002 для одного экземпляра и MCP_PORT=8003 для другого. Для каждого контейнера задаётся собственный SVACER_MCP_TOKEN.

Безопасность

  • STDIO: сервер не открывает сетевых портов и обменивается данными через стандартные потоки ввода/вывода процесса.
  • Streamable HTTP: эндпоинт /mcp требует заголовок Authorization: Bearer <SVACER_MCP_TOKEN>. Запросы без токена или с неверным значением получают ответ 401 и заголовок WWW-Authenticate: Bearer .... Токен является разделяемым секретом и не заменяет TLS, а дополняет его: при работе за обратным прокси необходимо использовать HTTPS, а сам токен передавать только по защищённому каналу.
  • Без SVACER_MCP_TOKEN HTTP-сервер не запускается.
  • Учётные данные admin/admin предназначены только для тестового стенда. В рабочем окружении необходимо задать собственные логин и пароль через переменные окружения.
  • Файл .env не должен добавляться в систему контроля версий.

Передача токена клиентом

Большинство HTTP-клиентов MCP (OpenWebUI и др.) позволяют задать произвольный заголовок Authorization в настройках инструмента — указывается значение Bearer <токен>. Для ручной проверки:

curl -H "Authorization: Bearer $SVACER_MCP_TOKEN" \
     -H 'Content-Type: application/json' \
     -H 'Accept: application/json, text/event-stream' \
     -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-11-25","capabilities":{},"clientInfo":{"name":"curl","version":"0"}}}' \
     http://localhost:8002/mcp

Инструменты

Справочник по 8 инструментам Svacer MCP. Типичный порядок вызовов: get_projectsget_snapshots → любой из аналитических инструментов.

Инструмент Назначение
get_projects Список проектов с ветками — точка входа
get_snapshots Снимки конкретной ветки, от нового к старому
get_project_stats Агрегированные метрики снимка: severity / review / checker
get_markers Компактный список маркеров с серверной фильтрацией
get_warnings Полные предупреждения с трассами и историей ревью
get_diff Сравнение двух снимков: new / missing / modified / matched
get_advanced_file_preview Фрагмент исходного кода вокруг строки
get_project_groups Группа проектов по имени или UUID

get_projects

Список всех проектов с ветками. Точка входа: с этого вызова начинается практически любой сценарий — он возвращает project_id и branch_id, необходимые для последующих запросов.

Параметров нет.

Вызов:

get_projects()

Ответ:

[
  {
    "project_id": "91630e84-db2f-4d8c-8716-68b7fdf17a66",
    "project_name": "bash",
    "created": "2021-12-13T13:22:42.122456Z",
    "created_by": "admin",
    "branches": [
      {
        "branch_id": "77f66b9e-0453-4ae9-a187-88950b4c4bc4",
        "branch_name": "master",
        "created": "2021-12-13T13:22:42.394812Z"
      }
    ]
  }
]

get_snapshots

Список снимков для конкретной ветки проекта, от нового к старому.

Параметры.

Имя Тип Обязательный Описание
project_id string (UUID) да Из get_projects
branch_id string (UUID) да Из get_projects
name_filter string нет Подстрока или regex для фильтра по имени снимка

Вызов:

get_snapshots(
  project_id="91630e84-db2f-4d8c-8716-68b7fdf17a66",
  branch_id="77f66b9e-0453-4ae9-a187-88950b4c4bc4"
)

Ответ:

[
  {
    "snapshot_id": "b42cb563-86f4-4f96-900a-7782163327c9",
    "name": "Snapshot 2020-03-25 09:09:41 +0300",
    "import_time": "2020-03-25T09:09:41.837296Z",
    "commit_hash": null,
    "markers_count": 297,
    "link": "https://svacer-demo.ispras.ru/..."
  }
]

get_project_stats

Агрегированные метрики по снимку: общее количество предупреждений, распределение по критичности, по статусу ревью, по детекторам. Наиболее быстрый способ получить общую картину по проекту.

Параметры.

Имя Тип Обязательный Описание
project_id string (UUID) да
branch_id string (UUID) да
snapshot_id string (UUID) да

Вызов:

get_project_stats(
  project_id="91630e84-db2f-4d8c-8716-68b7fdf17a66",
  branch_id="77f66b9e-0453-4ae9-a187-88950b4c4bc4",
  snapshot_id="b42cb563-86f4-4f96-900a-7782163327c9"
)

Ответ:

{
  "total_warnings": 771,
  "by_severity": {
    "Critical": 1,
    "Major": 1,
    "Unspecified": 769
  },
  "by_review_status": {
    "Confirmed": 1,
    "False Positive": 1,
    "Undecided": 767,
    "Unclear": 1,
    "Won't fix": 1
  },
  "by_checker": {
    "PROC_USE.VULNERABLE": 337,
    "UNUSED_FUNC_RES.REWRITE.MINOR": 44,
    "UNREACHABLE_CODE": 28,
    "DEREF_AFTER_NULL.EX": 27,
    "NULL_AFTER_DEREF": 27
  }
}

get_markers

Компактный список маркеров с серверной фильтрацией. Основной инструмент для перечисления и обзора: его следует предпочитать get_warnings, когда не требуются развёрнутые поля — трассы и история ревью.

По умолчанию ответ ограничен 30 маркерами и содержит компактный набор полей. Подробнее об ограничении объёма см. раздел Про объём ответа в сценариях.

Параметры.

Имя Тип Обязательный Описание
project_id string (UUID) да
branch_id string (UUID) да
snapshot_id string (UUID) да
severity string[] нет Critical, Major, Minor, Unspecified. Фильтр по review.severity, применяется на стороне коннектора
review string[] нет Confirmed, Won't fix, False Positive, Unclear
warnClass string[] нет Идентификатор детектора (DEREF_AFTER_NULL, …)
file string[] нет Подстрока пути к файлу
traces bool нет Включить трассы маркеров
checker_info bool нет Включить метаданные детектора (CWE, описание)
review_history bool нет Включить историю изменений ревью
comment_history bool нет Включить комментарии к маркеру
custom_filter string нет Имя или идентификатор сохранённого фильтра из веб-интерфейса Svacer
limit int нет Максимальное количество маркеров в ответе (по умолчанию 30). Значение 0 снимает ограничение
fields string[] нет Список разрешённых полей маркера верхнего уровня. По умолчанию — компактный набор id, warnClass, file, line, msg, function, review. Значение ["*"] возвращает все поля коннектора (id, warnClass, file, line, msg, tool, function, mtid, review, а также traces/checkerInfo/review_history/comments, если они запрошены). Допустим и произвольный список — например, ["id","warnClass"]

Вызов:

get_markers(
  project_id="91630e84-db2f-4d8c-8716-68b7fdf17a66",
  branch_id="77f66b9e-0453-4ae9-a187-88950b4c4bc4",
  snapshot_id="b42cb563-86f4-4f96-900a-7782163327c9",
  warnClass=["PROC_USE.VULNERABLE"]
)

Ответ:

{
  "total_count": 341,
  "returned_count": 30,
  "truncated": true,
  "filters_applied": {"warnClass": ["PROC_USE.VULNERABLE"]},
  "markers": [
    {
      "id": "e05bb35b-a95e-4eb2-85ae-3101b788f07d",
      "warnClass": "PROC_USE.VULNERABLE.TEMP",
      "file": "/.build/lib/sh/tmpfile.c",
      "line": 160,
      "msg": "Use of vulnerable function 'mktemp' at tmpfile.c:160. ...",
      "function": "sh_mktmpname",
      "review": null
    }
  ]
}

total_count отражает количество маркеров, удовлетворяющих фильтру до применения ограничения; returned_count — количество маркеров, фактически содержащихся в markers. При truncated: true следует либо сузить фильтры (severity, warnClass, file), либо передать limit=0 для получения полного списка. Поля tool и mtid возвращаются только при fields=["*"].


get_warnings

Полные предупреждения с детальной разметкой. Ответ значительно объёмнее, чем у get_markers, поэтому инструмент следует использовать только тогда, когда нужны поля, отсутствующие в компактной форме: traces, review_history, checker_info, comment_history.

Лимит по умолчанию — 30; при включённых traces, review_history или comment_history он автоматически снижается до 8, поскольку такие предупреждения существенно объёмнее.

Параметры.

Имя Тип Обязательный Описание
project_id string (UUID) да
branch_id string (UUID) да
snapshot_id string (UUID) да
severity string[] нет Critical, Major, Minor, Unspecified. Фильтр по review.severity, применяется на стороне коннектора
review string[] нет Confirmed, Won't fix, False Positive, Unclear
warnClass string[] нет Идентификатор детектора
file string[] нет Подстрока пути к файлу
traces bool нет Включить трассы. Активирует режим расширенных полей (лимит по умолчанию — 8)
checker_info bool нет Включить метаданные детектора (CWE, описание)
review_history bool нет Включить историю ревью. Режим расширенных полей
comment_history bool нет Включить комментарии. Режим расширенных полей
custom_filter string нет Имя или идентификатор сохранённого фильтра
limit int нет Максимальное количество предупреждений в ответе. По умолчанию — 30, в режиме расширенных полей — 8. Значение 0 снимает ограничение. Явно заданное limit отменяет автоматическое снижение
fields string[] нет См. описание у get_markers

Вызов:

get_warnings(
  project_id="91630e84-db2f-4d8c-8716-68b7fdf17a66",
  branch_id="77f66b9e-0453-4ae9-a187-88950b4c4bc4",
  snapshot_id="b42cb563-86f4-4f96-900a-7782163327c9",
  severity=["Critical"],
  review_history=True,
  traces=True
)

Ответ:

{
  "total_count": 1,
  "returned_count": 1,
  "truncated": false,
  "filters_applied": {"severity": ["Critical"], "traces": true, "review_history": true},
  "warnings": [
    {
      "id": "a3f21c90-1d4e-4b82-9f63-7c8e5d2a1b09",
      "warnClass": "DEREF_AFTER_NULL.LOOP",
      "file": "/.build/execute_cmd.c",
      "line": 3327,
      "msg": "Possible null pointer dereference of 'l' after loop exit.",
      "function": "select_query",
      "review": {"status": "Confirmed", "severity": "Critical"},
      "review_history": [{"status": "Confirmed", "changed_by": "admin", "changed_at": "2021-12-13T14:00:00Z"}],
      "traces": [{"file": "/.build/execute_cmd.c", "line": 3320, "msg": "Loop starts here; 'l' may exhaust the list."}]
    }
  ]
}

get_diff

Сравнение двух снимков. Категории располагаются под ключом markers: new_markers (появилось в новом снимке), missing_markers (исчезло из нового), modified_markers (тот же идентификатор, изменился контекст), matched_markers (совпало в обоих). Параметры project_id и branch_id не требуются — достаточно UUID снимков.

Параметры.

Имя Тип Обязательный Описание
base_snapshot_id string (UUID) да Старый снимок
head_snapshot_id string (UUID) нет Новый снимок; если не указан, сравнение выполняется с предыдущим по времени
level int нет 0 — только статистика; 1 — статистика и идентификаторы маркеров; 2 — полные маркеры по категориям
checker_info bool нет Метаданные детекторов для маркеров (только при level >= 2)
limit int нет Максимальное количество маркеров на каждую категорию при level >= 2. По умолчанию — 20, значение 0 снимает ограничение. Параметр игнорируется при level < 2
fields string[] нет См. описание у get_markers/get_warnings. Применяется к маркерам внутри категорий при level >= 2

Вызов (level=0):

get_diff(
  base_snapshot_id="72b3df7b-c15a-4e3d-8f92-a041dc6e5b87",
  head_snapshot_id="b42cb563-86f4-4f96-900a-7782163327c9",
  level=0
)

Ответ (level=0):

{
  "stats": {
    "context1": {"projectName": "paho.mqtt.c", "snapshotName": "Snapshot 2020-03-20 ..."},
    "context2": {"projectName": "paho.mqtt.c", "snapshotName": "Snapshot 2020-03-25 ..."},
    "scope": ["NEW", "MISSING", "MATCHED", "MODIFIED"],
    "new": 9,
    "missing": 12,
    "modified": 98,
    "matched": 187
  }
}

Ответ (level=2) — каждая категория внутри markers оформляется и ограничивается независимо:

{
  "stats": {"new": 50, "missing": 5, "modified": 0, "matched": 187},
  "markers": {
    "new_markers": {
      "total_count": 50,
      "returned_count": 20,
      "truncated": true,
      "markers": [
        {"id": "a3f21c90-...", "warnClass": "DEREF_AFTER_NULL.LOOP", "file": "...", "line": 3327, "msg": "...", "function": "select_query", "review": null}
      ]
    },
    "missing_markers": {"total_count": 5, "returned_count": 5, "truncated": false, "markers": [...]},
    "modified_markers": {"total_count": 0, "returned_count": 0, "truncated": false, "markers": []},
    "matched_markers": {"total_count": 187, "returned_count": 20, "truncated": true, "markers": [...]}
  }
}

Если требуется полное содержимое категории, следует увеличить limit либо запросить нужные идентификаторы отдельным вызовом get_markers. Маркеры внутри категорий проходят ту же компактную обработку, что и в get_warnings: значение fields=["*"] возвращает фиксированный набор полей коннектора, а не произвольные «сырые» поля API.


get_advanced_file_preview

Фрагмент исходного кода из снимка вокруг указанной строки. Параметры project_id и branch_id не требуются — достаточно идентификатора снимка и пути к файлу.

Параметры.

Имя Тип Обязательный Описание
snapshot_id string (UUID) да
file_path string да Путь к файлу в том виде, в котором его возвращают get_markers и get_warnings
line int нет Центральная строка, нумерация с 1 (по умолчанию 1)
before int нет Количество строк до центральной (по умолчанию 0)
after int нет Количество строк после центральной (по умолчанию 99999 — до конца файла)

Вызов:

get_advanced_file_preview(
  snapshot_id="b42cb563-86f4-4f96-900a-7782163327c9",
  file_path="/.build/execute_cmd.c",
  line=3327,
  before=10,
  after=10
)

Ответ:

{
  "line": 3327,
  "content": "      for (l = list; l && --reply; l = l->next)\n\t;\n      return (l->word->word);\n",
  "total_lines": 6082
}

get_project_groups

Получить группу проектов по имени или UUID. Группы объединяют проекты в логические блоки — например, по команде или продукту.

Параметры.

Имя Тип Обязательный Описание
name_or_id string да Имя группы или её UUID

Вызов:

get_project_groups(name_or_id="Linux Tools")

Ответ:

{
  "project_group_id": "c4f8a2d1-3b7e-4f90-82ac-1d5e8f2b6c04",
  "project_group_name": "Linux Tools",
  "projects": [
    {"id": "91630e84-db2f-4d8c-8716-68b7fdf17a66", "name": "bash"},
    {"id": "d3a17f52-...", "name": "coreutils"}
  ]
}

projects[].id — это project_id, который далее передаётся в get_snapshots. Группы и проекты — разные сущности; идентификатор группы и идентификатор проекта не взаимозаменяемы.

Примеры сценариев

Приведённые ниже запросы выполнены на демонстрационном стенде svacer-demo.ispras.ru с использованием OpenWebUI и модели qwen3-coder:30b. В любом другом MCP-клиенте с моделью достаточной мощности порядок вызовов будет аналогичным.

Про объём ответа

get_markers, get_warnings и get_diff(level=2) по умолчанию ограничивают объём ответа, чтобы не перегружать контекст модели:

  • get_markers и get_warnings — 30 маркеров по умолчанию. Если у get_warnings включены traces, review_history или comment_history, лимит снижается до 8, поскольку такие маркеры значительно объёмнее.
  • get_diff(level=2) — 20 маркеров на каждую категорию внутри markers (new_markers/missing_markers/modified_markers/matched_markers).

В ответе присутствуют поля total_count, returned_count, truncated. При truncated: true есть два варианта действий: сузить фильтр (severity, warnClass, file) либо явно увеличить limit (значение limit=0 полностью снимает ограничение).

Поле fields определяет, какие ключи маркера возвращаются. По умолчанию применяется компактный набор id, warnClass, file, line, msg, function, review (а также traces/checkerInfo/review_history/comments, если они запрошены логическими флагами и пришли с сервера). Для полного маркера со всеми служебными ключами — fields=["*"]. Для произвольной выборки — список полей верхнего уровня, например fields=["id","warnClass"]. Поле review — объект {status, severity, action}; вложенные ключи в fields не поддерживаются, поэтому объект review запрашивается целиком.

Перечислить

тка master.

Посмотреть снимки проекта

Какие снимки есть у paho.mqtt.c? Самый свежий когда?

Цепочка вызовов:

  1. get_projects() — найти project_id и branch_id
  2. get_snapshots(project_id=..., branch_id=...)

Ответ модели:

У paho.mqtt.c 3 снимка. Самый свежий — «Snapshot 2020-03-25 09:09:41 +0300» (297 маркеров). Предыдущий — 20 марта (306 маркеров).

Поле commit_hash может принимать значение null, если проект не сохраняет хэш коммита в custom_properties. Имена снимков произвольны: одни проекты записывают в имя дату, другие — коммит, третьи — свободный текст.

Сводка по проекту

Что в bash в последнем снимке? Сколько всего предупреждений, есть ли критические, какие топ-детекторы?

Цепочка вызовов:

  1. get_projects()
  2. get_snapshots(project_id, branch_id) — взять последний снимок
  3. get_project_stats(project_id, branch_id, snapshot_id)

Ответ модели:

В последнем снимке bash содержится 771 предупреждение:

  • Критических: 1 (Confirmed)
  • Major: 1 (Won't fix)
  • Остальные: 769 (Unspecified — не ревьюились)

Топ-детекторы по количеству:

  1. PROC_USE.VULNERABLE — 337
  2. UNUSED_FUNC_RES.REWRITE.MINOR — 44
  3. UNREACHABLE_CODE — 28
  4. DEREF_AFTER_NULL.EX — 27
  5. NULL_AFTER_DEREF — 27

Unspecified в by_severity — маркеры без ручного ревью, а не «низкий приоритет». Поле by_checker не сортируется, на большом снимке оно может содержать более 100 ключей — чтобы получить именно топ-N, следует явно сформулировать запрос: «топ-5 детекторов».

Тренд по нескольким снимкам

Как у openssl менялось число предупреждений за последние пять снимков? Покажи таблицей.

Цепочка вызовов:

  1. get_projects()
  2. get_snapshots() — взять список
  3. get_project_stats() × 5 — по каждому из последних пяти снимков

Ответ модели:


На демонстрационном стенде указанные пять снимков openssl импортированы с интервалом в 20 минут одного дня и полностью идентичны — поэтому динамика отсутствует. На реальном проекте с историей релизов значения будут изменяться.

Найти срабатывания конкретного детектора

Цепочка вызовов:

  1. get_projects()
  2. get_snapshots()
  3. get_markers(warnClass=["PROC_USE.VULNERABLE"])

Ответ модели:

  1. /.build/lib/sh/tmpfile.c:160mktemp(), race condition. Рекомендуется mkstemp().
  2. /.build/lib/readline/shell.c:151getenv(), значение может быть подменено.
  3. /.build/shell.c:415getenv() в main().
  4. /.build/lib/readline/complete.c:1516getenv().
  5. /.build/lib/sh/eaccess.c:115strcat(), рекомендуется strncat(). …

Фильтр warnClass=["PROC_USE.VULNERABLE"] охватывает все подклассы: PROC_USE.VULNERABLE.TEMP, .GETENV, .STRCAT и т. д. — всего 341 маркер. Несколько значений в одном параметре трактуются как логическое «ИЛИ»: severity=["Critical","Major"] возвращает маркеры обеих категорий.

В ответе будет total_count: 341, returned_count: 30, truncated: true — это ожидаемое поведение. Модель видит общий объём по total_count и при необходимости сужает запрос или вызывает get_markers(..., limit=0), чтобы получить полный список.

Сравнить два снимка

Возьми два последних снимка paho.mqtt.c — что между ними изменилось? Сколько новых предупреждений, сколько починили?

Цепочка вызовов:

  1. get_projects()
  2. get_snapshots() — два последних
  3. get_diff(base_snapshot_id="72b3df7b-...", head_snapshot_id="b42cb563-...", level=0)

Ответ модели:

Между двумя последними снимками paho.mqtt.c:

  • Новых: 12
  • Удалённых: 13
  • Изменённых: 99
  • Совпадающих: 185

Удалено несколько больше, чем добавлено — общая картина практически не изменилась.

Категория modified — маркер, присутствующий в обоих снимках, у которого изменилось окружение (номер строки, контекст функции). Это не новая ошибка. На больших проектах рекомендуется начинать с level=0 для получения статистики, при необходимости использовать level=1 (только идентификаторы маркеров) и затем точечно вызывать get_markers с нужными фильтрами.

level=2 возвращает полные маркеры по категориям, причём каждая категория по умолчанию ограничена 20 маркерами. Категории располагаются внутри markers: new_markers, missing_markers, modified_markers, matched_markers. Структура ответа в JSON: {"markers": {"new_markers": {"total_count": N, "returned_count": ..., "truncated": ..., "markers": [...]}, ...}}. Если требуется полное содержимое категории, следует увеличить limit или выполнить отдельный вызов get_markers по нужным идентификаторам.

Разобрать конкретное предупреждение

В bash есть один подтверждённый крит — что-то про разыменование указателя. Покажи код вокруг этого места и объясни в чём проблема.

Цепочка вызовов:

  1. get_projects()get_snapshots() — найти снимок bash
  2. get_markers(severity=["Critical"], review=["Confirmed"])
  3. get_advanced_file_preview(file_path="/.build/execute_cmd.c", line=3327, before=10, after=10)

Ответ модели:

Маркер DEREF_AFTER_NULL.LOOP в функции select_query(), строка 3327:

for (l = list; l && --reply; l = l->next)
    ;
return (l->word->word);  /* l может быть NULL после выхода из цикла */

Если список заканчивается раньше, чем reply обнуляется, l станет NULL на последнем l->next, и следующий l->word->word — разыменование нулевого указателя.

file_path должен точно совпадать со значением, возвращённым маркером, включая ведущий префикс /.build/.... Это путь внутри сборочной директории Svacer, а не путь в исходном репозитории; соответствие в репозитории определяется по имени файла.

Для одиночной разметки удобно сразу запрашивать полный маркер с трассами: get_markers(..., severity=["Critical"], review=["Confirmed"], traces=True, checker_info=True). Флаги traces и checker_info указывают серверу включить соответствующие поля в ответ; в выдаче они сохраняются и при значении fields по умолчанию. Значение fields=["*"] требуется лишь в том случае, когда дополнительно нужны tool и mtid — служебные ключи, исключённые из компактного набора.