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

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

П28. Поставка от нескольких исполнителей

Корпоративное изделие Организации собирается из подсистем 5–10 соисполнителей. Источник факта о составе подсистемы — не ваш пайплайн, а ZIP-поставка внешней команды. Эта практика — про приёмку такой поставки: проверить, что ZIP содержит всё нужное, и измерить пригодность данных, а не предположить её.

Цель

По одной ZIP-поставке соисполнителя получить проверяемый вердикт приёмки: ZIP структурно полон (есть bom.json, build-логи, список unresolved) и SBOM достаточен по качеству координат. Конкретно — посчитать три числа покрытия (всего компонентов, без PURL, с распознанной лицензией) и принять одно из трёх решений: «принято» / «принято с замечаниями» / «вернуть worklist».

Команда или действие

Поставку забирают из артефакт-репозитория по иммутабельным координатам (имя:версия), а не из почты. Дальше — два шага: проверка структуры ZIP и измерение покрытия по обогащённому bom.json.

# 1. Структура поставки: что реально лежит в ZIP
unzip -l contractor-A.zip
#   ожидаем как минимум: bom.json, build/*.log, unresolved.json

# 2. Распаковать и обогатить сырой SBOM через генератор фактов (enrichment-утилита)
unzip contractor-A.zip -d contractor-A/
enrich-sbom contractor-A/bom.json enriched/A-bom.json --component-path subsystem-A

# 3. Измерить покрытие обогащённого SBOM (jq поверх CycloneDX)
BOM=enriched/A-bom.json
echo "всего компонентов : $(jq '.components | length' "$BOM")"
echo "без PURL          : $(jq '[.components[] | select(.purl == null)] | length' "$BOM")"
echo "с лицензией       : $(jq '[.components[] | select(.licenses != null and (.licenses | length > 0))] | length' "$BOM")"

# 4. Список нераспознанного — это worklist соисполнителю
jq -r '.components[] | select(.purl == null) | .name' "$BOM" | sort -u

Почему ZIP, а не один bom.json Для C/C++ legacy состав не выводится из манифеста — нужен build evidence (что реально слинковалось) и явный перечень того, что инструмент не распознал. Один bom.json без логов и unresolved.json не доказывает полноту состава, поэтому приёмке подлежит вся поставка, а не файл SBOM.

Что вы должны увидеть

Шаг 1 — поставка структурно полна (присутствуют три обязательных артефакта):

Archive:  contractor-A.zip
  Length      Date    Time    Name
---------  ---------- -----   ----
   184320  2026-06-15 11:02   bom.json
    51200  2026-06-15 11:02   build/link.log
      980  2026-06-15 11:02   unresolved.json

Шаг 3 — три числа покрытия. Ориентир «хорошей» поставки (подсистема A из карты модуля М10): ~142 компонента, без PURL — единицы, лицензии распознаны:

всего компонентов : 142
без PURL          : 3
с лицензией       : 139

Сводка по партии соисполнителей — основа вердикта. PURL coverage = (всего − без PURL) / всего:

Соисполнитель Компонентов PURL coverage unresolved Вердикт
A 142 96% 3 принято
B 88 61% 27 вернуть worklist
N 210 89% 11 принято с замечаниями

Строка B — «технически валидный SBOM»: файл есть, но 27 компонентов без идентификаторов, поэтому состав подсистемы не считается известным до доразметки.

Если не получилось

Типичные ошибки приёмки - unzip: cannot find or open contractor-A.zip — поставку тянут из почты/мессенджера вместо артефакт-репозитория; нет иммутабельных координат и provenance. Забирайте из репозитория по имя:версия. - jq: error: Cannot iterate over null (null) — в файле нет ключа .components (это не CycloneDX, а, например, голый SPDX или сырой лог). Проверьте jq '.bomFormat,.specVersion' "$BOM" — должно быть "CycloneDX". - PURL coverage ~100%, но число findings у сканера почти ноль — компоненты есть, а версии/идентификаторы пустые: сканер не на что мэтчить CVE. Это ложное ощущение чистоты, а не успех — смотрите долю компонентов с непустым version. - Версия ZIP ≠ версия bom.json внутри — ZIP пересобрали, а SBOM старый; provenance ломается молча. Сверяйте commit/tag в metadata.component с координатами поставки.

Критерий зачёта

Показать преподавателю: вывод unzip -l (три обязательных артефакта на месте), три числа покрытия по jq, заполненную строку сводки по соисполнителю и обоснованный вердикт приёмки. Для поставки-«двойки» (низкий coverage) — сформированный worklist (список компонентов без PURL), а не молчаливое «принято».

Нормативная связка