Частично я эту проблему поднимал в своём докладе на NeoQUEST в прошлом году
https://t.me/tech_b0lt_Genona/5727
На Хабре вышла статья от ребят из CodeScoring в конце сентября, но почитать только сейчас добрался вдумчиво.
Пост большой, я оставлю у себя только важные, на мой взгляд, моменты.
Код, пот и слезы: композиционный анализ проектов на С/С++
https://habr.com/ru/companies/codescoring/articles/1086376/
Установить название и версию библиотеки проще, если её добавили через пакетный менеджер, который сохранил эти сведения. При этом менеджеры зависимостей проекта и системных пакетов хранят данные о разных частях окружения. Conan и vcpkg управляют зависимостями конкретного C/C++ проекта, а системные менеджеры вроде apt или dnf устанавливают программы и библиотеки в операционную систему. Например, в Debian и Ubuntu сведения об установленных файлах хранятся в базе dpkg, а системы семейства RPM используют базу RPM. По такой базе файл можно связать с пакетом и его версией.
Базы dpkg и RPM помогают, если библиотеку установили через системный пакетный менеджер. Для ранее собранной библиотеки связь с исходным проектом, версией и набором патчей приходится сохранять вместе с артефактом. Сам формат статического архива или динамической библиотеки не предъявляет требования к наличии этих сведений.
При включении сторонних исходников и header‑only библиотек отдельного артефакта может вообще не быть. Происхождение такого кода приходится устанавливать по исходникам и данным сборки.
Поскольку g++ может выполнять и компиляцию, и линковку, то при разборе сборки приходится смотреть на аргументы вызова. Сборочная система передаёт инструментам пути, параметры и порядок действий.
...
Для SBOM конкретного релиза нужно не только установить происхождение библиотек, но и выяснить, какие из них вошли в поставку. Наличие библиотеки в сборочном окружении ещё не означает, что она используется в выпускаемом приложении.
При сборке через Make или CMake без менеджера зависимостей библиотеки могут приходить из системных пакетов, каталогов с исходниками и других пайплайнов. Какие из них понадобятся для конкретного выпуска — зависит от операционной системы, параметров компиляции и выбранных целей сборки.
...
Что же делать?
...
При статической линковке линковщик извлекает из архива объектные файлы, необходимые для разрешения символов, и включает их в компоновку. Сам архив после сборки для запуска не нужен. Динамическую библиотеку выбирает динамический загрузчик с учётом путей поиска и настроек среды исполнения. Поэтому при запуске приложение может получить иную совместимую версию библиотеки, нежели та которая была доступна в системе сборки.
Отсюда возникают два вида инвентаря и соответственно два SBOM. Build‑time фиксирует сведения, собранные во время компиляции и линковки конкретного выпуска, включая использованные статические библиотеки, выбранные цели и наблюдавшиеся команды. Runtime исследует уже запущенное приложение и показывает динамические библиотеки, доступные ему в конкретной среде.
Два разных SBOM отвечают на разные вопросы. Первый объясняет, из чего собрали артефакт, а второй показывает, с чем он фактически запускается. Свести два списка бывает сложнее, чем получить их по отдельности, но попытка заменить один другим почти гарантированно оставит слепую зону. В итоге приходится отдельно инвентаризировать сборку и среду исполнения, а затем сопоставлять результаты.
...
Куда движется практика
Сведения о происхождении библиотек надёжнее сохранять при сборке, пока известны исходники, версии и внесённые изменения. Если след сборки уже потерян, инструменты вынуждены расширять анализ готового результата. После этого остаётся связать полученный SBOM с конкретным выпуском. Открытые проекты развивают эти направления независимо, поэтому их результаты пока приходится сводить.
Например, чтобы сохранить происхождение до его потери, проект BOMsh наблюдает команды сборки и для каждого выходного файла записывает входные файлы, команду и хеши. OmniBOR соединяет такие записи в дерево происхождения, или provenance, по которому можно пройти от готовой программы к участвовавшим в её создании артефактам.
Однако provenance ещё не равен SBOM. Разработчики BOMsh предупреждают, что конфигурационные проверки, тесты и подготовка инструментов порождают дополнительные записи, которые трудно отличить от сборки поставляемого продукта. Историю приходится сокращать, а файлам всё равно назначать имена и версии компонентов.
Если полноценный след сборки уже потерян, то инструменты расширяют поверхность поиска. cdxgen объединяет данные из манифестов, исходников, контейнерных образов и бинарных файлов, а CVE Binary Tool ищет узнаваемые признаки библиотек в готовых файлах.
После сборки SBOM можно связать с конкретным артефактом аттестацией. Например, Syft выпускает CycloneDX и SPDX и умеет создавать подписанные аттестации in‑toto. Такая запись связывает хеш артефакта с SBOM и указывает, кто сформировал документ. Подпись подтверждает автора и целостность утверждения, но не исправляет ошибочную атрибуцию внутри SBOM. Ценность аттестации скорее в том, что перечень компонентов перестаёт быть отдельным файлом неизвестного происхождения и входит в проверяемую историю релиза продукта.
Доклад с FOSDEM в эту же тему
LibreOffice and Collabora Online - how we managed to automate SBOM generation for a large legacy project
https://archive.fosdem.org/2026/schedule/event/TMFSBD-sboms-for-collabora-online/