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

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

unresolved libraries

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

Unresolved libraries — это компоненты, которые сборка точно использует, но генератор фактов не смог привязать к устойчивому идентификатору: есть .so, который ldd показал, но dpkg -S не нашёл; есть .a, который слинкован, но непонятно, какой это пакет и версия; есть libfoo, упомянутая в -l, но не сопоставленная ни с одним системным пакетом. Ключевая идея темы — такой компонент нельзя ни молча выкинуть, ни молча выдать за разрешённый. Молчаливый пропуск превращает неполный SBOM в формально «зелёный», и именно в этом провале живут невидимые уязвимости.

Честная обработка unresolved — это маркер зрелости процесса. SBOM, который явно говорит «вот эти N компонентов я не смог опознать», полезнее SBOM, который делает вид, что их нет: первый даёт worklist и измеримое покрытие, второй создаёт ложную уверенность.

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

Unresolved появляется на стыке шагов: библиотека видна в одном инструменте, но проваливается на сопоставлении в другом.

# .so есть в зависимостях бинаря...
readelf -d ./app | grep NEEDED
#   0x0000000000000001 (NEEDED) Shared library: [libfoo.so.2]

# ...но система не знает, какому пакету он принадлежит
dpkg -S "$(ldconfig -p | awk '/libfoo\.so\.2/{print $NF; exit}')"
#   dpkg-query: no path found matching pattern *libfoo.so.2*   ← unresolved

# Статическая библиотека слинкована, но идентичность не установлена
ar t third_party/lib/libbar.a | head     # объектники есть, версии/пакета нет

В CycloneDX это компонент с непустым name, но purl == null (или pkg:generic/... без версии). Подсчёт таких записей и есть метрика покрытия:

jq -r '.components[] | select(.purl == null) | .name' bom.json | sort -u   # → worklist
jq '[.components[] | select(.purl==null)] | length' bom.json               # → число unresolved

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

Слепая зона возникает не от самого наличия unresolved, а от их тихого исчезновения. Если генератор просто не добавляет то, что не смог опознать, разрыв между «слинковано» и «учтено в SBOM» не виден никому. Приём — превратить unresolved в явный, считаемый и адресуемый артефакт: отдельный список unresolved.json, число в метриках покрытия, пониженный confidence на записи.

Приём: unresolved как первоклассный артефакт поставки Делайте unresolved.json обязательной частью поставки наравне с bom.json и build-логами. Тогда приёмка проверяет не только «есть ли SBOM», но и «насколько он полон». Компонент без идентификатора — это не «нет компонента», а «компонент есть, идентичность не доказана» (см. honest SBOM).

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

  1. Сопоставьте список линковки (readelf -d, -l из логов, входные .a) с тем, что реально опознано в SBOM; разница и есть unresolved.
  2. Выгрузите unresolved в отдельный unresolved.json с полями: имя, путь occurrences, хеш, источник (динамика/статика/каталог).
  3. По каждому пункту проведите доразметку: dpkg -S/rpm -qf, поиск по хешу, сверка с upstream-релизом (см. hash-based identification).
  4. Считайте покрытие как (всего − unresolved) / всего и выводите его в gate качества SBOM (см. П34. SBOM quality gate).
  5. На записи, оставшиеся без идентификатора, ставьте пониженный confidence — не выдавайте их за чистые.
  6. Передавайте worklist ответственному (для своей сборки — команде, для чужой — соисполнителю).

Связь