CPG-слой: Joern, межпроцедурные вызовы и честная деградация
Что добавляет Joern (php2cpg), 12 фактов CPG, backend torch.sparse, контракт degraded и почему отсутствие Joern — не авария, а режим.
Зачем нужен отдельный слой #
tree-sitter даёт внутрифайловый синтаксис: символы, вызовы в пределах файла, SQL-литералы. Но реальные вопросы агента — межпроцедурные: «что достижимо из этой точки», «обрывается ли маршрут согласования». Для PHP это особенно больно: динамика (call_user_func, магические методы, include-цепочки) делает статическую достижимость нетривиальной. RAGRAF не изобретает анализатор — он подключает Joern (Code Property Graph) как опциональный L1-экстрактор и заворачивает его в свой контракт.
Что именно добавляется #
Этап 5 конвейера (cpg) запускает Joern-сервер (localhost:9500, старт/стоп автоматически) и импортирует в graph.sqlite:
| Артефакт | Содержание |
|---|---|
Межпроцедурные CALL-рёбра | вызовы через границы файлов — то, чего tree-sitter не видит |
cfg_edge / dfg_edge | потоки управления и данных внутри функций (задел под taint-анализ — см. future) |
| 12 фактов CPG-покрытия | какие файлы/функции покрыты CPG, каким парсером (php2cpg), версия слоя |
joern_used в ревизии | 1/0 — флаг, который виден в status и панели; никогда не «подразумевается» |
На пилотном корпусе (123 PHP-файла) CPG-этап занял 64 с из 71 с полной индексации — Joern доминирует во времени, поэтому он опционален и отключаем (joern_enabled: false).
slice: единственная CPG-операция #
slice — межпроцедурный срез (вверх/вниз по потокам от символа, глубина настраивается). Это единственная операция, требующая capability=full. Контракт деградации:
$ ragraf -p cfg query slice --name markPaid
exit 3
{"op":"slice","capability":"degraded",
"reason":"CPG-слой недоступен: Joern не установлен",
"suggest":"install-joern.ps1 -Download или используйте callers/impact (граф tree-sitter)"}Отказ с причиной и предложением — вместо пустого результата, который агент принял бы за «зависимостей нет». Это анти-требование №4 в действии.
Алгоритмический backend: torch.sparse #
Обход CPG (достижимость, срезы) реализован в graph_algo.py с тремя бэкендами и честным каскадом:
| Backend | Условие | Характеристика |
|---|---|---|
torch-gpu | torch + CUDA доступны, граф ≥ порога | CSR-представление на GPU; батч-обходы |
torch-cpu | torch доступен | тот же код, CPU-тензоры |
none | torch нет | чистый Python/SQLite-обход — медленнее, но всегда работает |
Выбранный бэкенд пишется в метаданные ревизии (reason-поле), а не подразумевается. Важная честная деталь: CSR-представление ограничивает мутации графа на лету — пересборка CPG идёт полным прогоном (инкрементального CPG в Joern не существует). Порог переключения на тензорный путь — ~5 000 вершин (см. gpu-compute).
Установка и вес #
./scripts/install-joern.ps1 -Download # скачивает дистрибутив, проверяет SHA-256, восстанавливает окружение при сбоеТребуется JDK 21 + Joern (~5–6 ГБ). Установщик проверяет хеш архива (защита от битых/подменённых загрузок) и восстанавливает прежнее состояние при ошибке — дефекты пайп-дедлока и отсутствия таймаутов закрыты рефакторингом (INSTALLER-REFACTOR-NOTES).
Границы слоя #
- PHP-first: php2cpg проверен на PHP-корпусах; для других языков CPG экспериментальна (Joern поддерживает многие, но контракт RAGRAF проверен на PHP).
- Динамика остаётся динамикой:
call_user_func-цепочки Joern тоже не раскрывает магически — derived-рёбра с confidence 0.60 и отдельным блоком ответа (см. operations). - Taint-анализ не включён: CFG/DFG-факты лежат в графе как задел; продуктовых taint-операций в v0.1.0 нет — это осознанная граница релиза и первая крупная перспектива (future).
- Зависимости не объявлены в pyproject: torch/Joern — внешние опциональные компоненты; формализация extras (
pip install ragraf[gpu]) — пункт R-PKG-1 roadmap.
Смежное: GPU-вычисления → · архитектура → · перспективы →