Пиков / КАПО
Как читать авторский курс и нормативные материалы

Это учебные материалы, а не заключение о соответствии конкретного продукта. Организационные модели курса отделяйте от терминов стандарта: ППК в опубликованном проекте — машиночитаемый перечень, а живой реестр его версий является практикой сопровождения. Термин OSA в разных материалах имеет разный охват. Статус и обязательность нормативного документа проверяются отдельно; проект КАПО опубликован как проект первой редакции.

Conan recipe package id graph

Почему это важно для SCA/OSA

Conan — один из немногих случаев, когда C/C++ проект отдаёт настоящий граф зависимостей с устойчивой идентичностью пакета. В отличие от голого CMake, здесь есть recipe (conanfile.py/conanfile.txt), lock-файл (conan.lock) и команда conan graph info, которая печатает полный транзитивный граф с версиями, ревизиями и опциями. Для SCA это золото: из графа восстанавливается состав, который иначе пришлось бы вытаскивать бинарным анализом.

Но именно из-за package_id идентичность в Conan не сводится к паре «имя+версия». package_id — это хеш от настроек (settings), опций (options) и требований (requires). Поэтому openssl/3.2.1 с shared=True и openssl/3.2.1 с shared=False — это два разных бинарных пакета с разными package_id, и в SBOM их нельзя схлопывать в одну запись: у них может отличаться поверхность уязвимостей и набор слинкованного кода.

Как это проявляется

Граф с идентичностью снимается одной командой и отдаёт ровно те поля, которых не хватает в CMake-проекте:

conan graph info как источник состава

conan graph info . --format=json > graph.json

В каждом узле графа: ref (например zlib/1.3.1#<recipe_revision>), package_id, развёрнутые options, settings и список requires. Recipe revision (#... после версии) фиксирует, какая именно версия рецепта собрала бинарь, — это часть provenance, которую теряет любой поздний скан готового артефакта.

Принципиальный момент для полноты SBOM — разделение контекстов сборки и запуска:

Тип требования Попадает в артефакт Должно быть в SBOM продукта
requires (host) да, линкуется/вкомпилируется да
build_requires / tool_requires (cmake, ninja, протоген) нет, только инструмент сборки нет (или отдельной секцией)
test_requires нет нет

Слепая зона или приём

Слепая зона — это build_requires/tool_requires. Они видны в conan graph info, но не входят в поставляемый бинарь, и если механически выгрузить весь граф в SBOM, продукт получит фантомные «зависимости» от компилятора и кодогенераторов. Обратная ошибка не менее опасна: схлопывание разных package_id одной версии скрывает, что собранный с другими опциями пакет — это другой код.

Фиксируйте lock и различайте контексты Снимайте conan.lock (conan lock create) — он замораживает точные ревизии и package_id всего графа. В SBOM переносите только узлы host-контекста (context: host), а build/test-контекст выносите отдельно или помечайте scope как excluded/optional.

Что делать на проекте

  1. Выгрузите граф: conan graph info . --format=json > graph.json и сохраните как артефакт сборки.
  2. Зафиксируйте conan.lock; сравнивайте сборки по нему, а не по диапазонам версий из рецепта.
  3. В SBOM переносите только узлы с context: host; tool_requires/test_requires исключайте или помечайте отдельным scope.
  4. Для каждого компонента возьмите ref с recipe revision и package_id — это устойчивый ключ; не схлопывайте разные package_id одной версии.
  5. Сверьте options критичных пакетов (shared, fPIC, with_*): они меняют, какой код реально слинкован.
  6. PURL формируйте по типу conan и нормализуйте приватные qualifiers (см. смежную заметку) перед матчингом на публичные источники уязвимостей.

Связь