SBOM Generator & Formatter — full Python pipeline (no shell)
Project description
Инструмент для безопасной генерации, анализа и форматирования Software Bill of Materials (SBOM).
Навигация
Документация (docs/):
- Руководство пользователя — быстрый старт
- Полное руководство (Manual) — все команды, флаги и примеры
- Демонстрация команд — гифки работы CLI
- Примеры результатов — образцы SBOM и отчётов
- Права доступа — требования к файловой системе
- Troubleshooting — частые проблемы и их решения
Разделы README:
Что делает:
- Генерирует SBOM двумя генераторами (cdxgen + syft) и объединяет результат — из локальной директории, Git-репозитория (GitHub / GitLab) или контейнерного образа
- Дедуплицирует компоненты по PURL и уязвимости по CVE+компонент
- Создаёт два подписанных SBOM: без уязвимостей и с ними
- Сканирует уязвимости параллельно через Trivy, OWASP Dependency-Check, Clair
- Встраивает найденные уязвимости в SBOM (CycloneDX 1.5)
- Опционально обогащает уязвимости идентификаторами БДУ ФСТЭК
- Экспортирует читаемые отчёты: Excel (.xlsx), Word (.docx), ODT (.odt)
- Готовит SBOM под требования ФСТЭК (
secsbom cert— поля GOST)
Main CLI
Установка
PyPI:
pip install sbom-pipeline
GitHub Packages:
pip install sbom-pipeline \
--index-url https://${GITHUB_TOKEN}@pypi.pkg.github.com/geminishkv/
Исходники:
git clone https://github.com/geminishkv/sbom_genform.git
cd sbom_genform
python3 -m venv venv && source venv/bin/activate
pip install -e ".[dev]"
Запуск утилиты
После установки доступна помощь:
secsbom --help
📖 Полное пошаговое руководство со всеми командами, сценариями и переменными окружения — в docs/USAGE.md.
Утилиту нужно запускать от обычного пользователя. Запуск с правами администратора/root завершается ошибкой, чтобы не выполнять сканеры и Docker-команды с лишними привилегиями.
Быстрый старт
Полный пайплайн генерирует SBOM, дедуплицирует компоненты, подписывает SBOM, сканирует уязвимости и экспортирует отчёты:
# локальный демо-проект
secsbom run
# указание локального проекта из примеров
secsbom run --path examples/project_inject
# удалёный репозиторий github с токеном
secsbom run --url https://github.com/org/repo --token ghp_...
# удалёный репозиторий gitlab с токеном
secsbom run --url https://gitlab.com/org/repo --token glpat-...
По умолчанию артефакты пишутся в secgensbom_out, отчёты — в
secgensbom_reports.
Основные режимы
Сгенерировать и подписать SBOM без этапа сканирования уязвимостей:
secsbom gen-sbom --path examples/project_inject
Просканировать уже готовый SBOM (и/или контейнерный образ) и сформировать отчёты только по уязвимостям:
# путь к папке проекта + готовый SBOM
secsbom scan secgensbom_out/app-bom-dedup-signed.json --path examples/project_inject
# только готовый SBOM
secsbom scan secgensbom_out/app-bom-dedup-signed.json
# только контейнерный образ
secsbom scan --clair --image nginx:latest
Отформатировать готовые SBOM JSON в Excel/Word/ODT:
secsbom format --sbom-dir secgensbom_out --report-dir secgensbom_reports
Проверить подпись SBOM:
secsbom verify secgensbom_out/merged-bom-signed.json
Примечание: SHA-256-подпись — это контрольная сумма целостности (защита от случайной порчи), а не криптографическая подпись: она не подтверждает аутентичность источника, поскольку хэш и
.sigпересчитываются после любого изменения файла. Для аутентичности и неотрекаемости используйте внешнюю подпись (cosign / sigstore).
Посмотреть краткую информацию по SBOM:
secsbom info secgensbom_out/merged-bom-signed.json
Проверить наличие внешних инструментов:
secsbom status
Сравнить два SBOM:
secsbom diff old-bom.json new-bom.json
Добавить поля GOST для отчёта по требованиям ФСТЭК:
secsbom cert sbom.json \
--component-name "My Product" \
--component-version "1.0.0" \
--manufacturer "My Company"
Полезные флаги и переменные
secsbom run --no-cdxgen # не использовать cdxgen
secsbom run --no-syft # не использовать syft
secsbom run --bdu # включить BDU-обогащение
secsbom run --clair --image nginx:latest
secsbom run -o secgensbom_out --reports-dir secgensbom_reports
Те же настройки можно передавать через переменные окружения:
export PROJECT_DIR=examples/project_inject
export OUTPUT_DIR=secgensbom_out
export REPORTS_DIR=secgensbom_reports
export BDU=true
export NVD_API_KEY=<token>
secsbom run
Для scan используются кэши внешних данных:
.dependency-check-data/DEP_CHECK_DATA— база NVD для OWASP Dependency-Check.bdu_cache/BDU_CACHE_DIR— соответствия CVE -> BDU ID
Сами этапы scan при повторном запуске выполняются заново, кэшируются именно
базы и справочные ответы внешних инструментов.
Выходные артефакты
SBOM JSON
| Файл | Описание |
|---|---|
secgensbom_out/app-bom-cdxgen.json |
SBOM от cdxgen |
secgensbom_out/app-bom-syft.json |
SBOM от syft |
secgensbom_out/app-bom-merged.json |
Объединённый SBOM (cdxgen + syft) |
secgensbom_out/app-bom-dedup.json |
После дедупликации компонентов |
secgensbom_out/app-bom-dedup-signed.json |
Подписанный SBOM без уязвимостей |
secgensbom_out/app-bom-dedup-signed.sig |
SHA-256 контрольная сумма (без уязв.) |
secgensbom_out/merged-bom-signed.json |
Подписанный SBOM с уязвимостями |
secgensbom_out/merged-bom-signed.sig |
SHA-256 контрольная сумма (с уязв.) |
secgensbom_out/vulns-normalized.json |
Нормализованные уязвимости |
<sbom>(cert).json |
SBOM с полями GOST/ФСТЭК (команда cert) |
Если включено BDU-обогащение, в merged-bom-signed.json идентификатор БДУ записывается в vulnerabilities[].properties[] как свойство с именем ru.fstec.bdu:id.
Отчёты сканеров
| Путь | Сканер |
|---|---|
secgensbom_out/trivy/trivy-fs.json |
Trivy — файловая система |
secgensbom_out/trivy/sbom-vulns.json |
Trivy — анализ SBOM |
secgensbom_out/dependency-check/ |
OWASP Dependency-Check |
secgensbom_out/clair/ |
Clair (если включён) |
Reports
| Путь | Формат | Содержимое |
|---|---|---|
secgensbom_reports/excel/*.xlsx |
Excel | Лист 1: компоненты, Лист 2: уязвимости |
secgensbom_reports/docx/*.docx |
Word | Таблица компонентов + таблица уязвимостей |
secgensbom_reports/odt/*.odt |
ODT | То же самое |
Лист «Компоненты»
| Колонка | Источник |
|---|---|
| № п/п | порядковый номер |
| Наименование компонента | components[].name из SBOM |
| Версия компонента | components[].version из SBOM |
| Тип пакета / тип компонента | тип экосистемы из PURL (pypi, maven, npm, apk, …) |
| PURL / технический идентификатор компонента | components[].purl из SBOM |
| Язык (языки) | определяется по PURL-типу (dependency.py) |
| Признак принадлежности к поверхности атаки | свойство компонента CycloneDX: attack-surface / attackSurface / isAttackSurface / GOST: attack_surface |
| Признак выполнения функций безопасности | свойство компонента CycloneDX: security-function / securityFunction / isSecurityFunction / GOST: security_function |
| Принадлежность к контейнерному образу | metadata.component.name (только если type = "container") |
| Роль компонента в составе контейнерного образа | свойство компонента: container-role / containerRole / cdx:docker:layer / layer |
| Адрес веб-ресурса | реестровый URL, вычисленный по PURL |
Лист «Уязвимости»
| Колонка | Источник |
|---|---|
| Компонент | имя пакета из сканера |
| Версия | версия при сканировании |
| CVE / ID | идентификатор уязвимости |
| CVSS | оценка CVSS v3 / v2 |
| Критичность | CRITICAL / HIGH / MEDIUM / LOW / UNKNOWN |
| Описание | первые 200 символов описания |
| Сканер | trivy / clair / dependency-check |
| Исправлено в версии | версия с исправлением (если известна) |
| Рекомендация / компенсирующая мера | Trivy: PrimaryURL → «Обновить до X»; Clair: Links[0]; Dependency-Check: notes → references[].url |
| Статус допустимости в рассматриваемой конфигурации | Trivy: поле Status (fixed, affected, will_not_fix, end_of_life, …) |
Если пайплайн запущен с --bdu или BDU=true, во всех форматах отчётов уязвимостей появляется отдельная колонка BDU / ID. Если BDU-обогащение выключено, эта колонка не выводится.
Примеры результатов
Подробные примеры итогового SBOM, vulns-normalized.json и экспортируемых таблиц вынесены в docs/RESULT_EXAMPLES.md.
Короткий пример структуры после полного запуска:
secgensbom_out/
├── app-bom-dedup-signed.json
├── merged-bom-signed.json
├── vulns-normalized.json
├── dependency-check/
├── trivy/
└── clair/
secgensbom_reports/
├── excel/merged-bom-signed.xlsx
├── docx/merged-bom-signed.docx
└── odt/merged-bom-signed.odt
BDU Enrichment
Обогащение идентификаторами БДУ ФСТЭК выключено по умолчанию.
Включение через CLI:
secsbom run --bdu
Включение через переменную окружения:
export BDU=true
secsbom run
При включённом BDU пайплайн:
- запрашивает соответствия
CVE -> BDU IDчерезbdu.fstec.ru - добавляет BDU ID в итоговый CycloneDX SBOM как свойство уязвимости
- выводит BDU ID в экспортируемые отчёты
Пример фрагмента SBOM:
{
"id": "CVE-2023-1234",
"properties": [
{
"name": "ru.fstec.bdu:id",
"value": "BDU:2023-01813"
}
]
}
Docker
Образ включает Python, Syft, Trivy, Docker CLI и Node.js/npx (cdxgen для non-Python проектов).
OWASP Dependency-Check запускается внутри утилиты через docker run (Docker-in-Docker), его Java-зависимость утяжелила бы основной образ на ~400 МБ.
Clair требует отдельного работающего HTTP-сервера — поэтому он вынесен в docker-compose.yml.
Безопасность образа: контейнер работает от непривилегированного пользователя sbom (uid 1001) — secsbom отказывается запускаться от root. В docker-compose.yml сервисам secgensbom / scan заданы security_opt: no-new-privileges и cap_drop: ALL. В образ встроен HEALTHCHECK, OCI-метки указывают лицензию Apache-2.0.
Docker Hub (только Trivy, без Clair/Dependency-Check)
docker pull geminishkv/sbom-pipeline:latest
docker run --rm \
-v "$(pwd)/examples/project_inject:/app/project_inject" \
-v "$(pwd)/secgensbom_out:/app/secgensbom_out" \
-v "$(pwd)/secgensbom_reports:/app/secgensbom_reports" \
-v /var/run/docker.sock:/var/run/docker.sock \
geminishkv/sbom-pipeline:latest
Docker Compose (Trivy + Dependency-Check + Clair)
Полный стек с OWASP Dependency-Check и Clair v4 запускается через docker-compose.yml.
Всё одной командой (компоненты + контейнеры + SBOM + отчёты)
Поднимает Clair, собирает SBOM по исходному коду, сканирует уязвимости (Trivy + Dependency-Check + Clair) и контейнерный образ, обогащает БДУ ФСТЭК и выгружает отчёты — NVD-ключ не нужен:
SKIP_CLAIR=false BDU=true IMAGE_NAME=nginx:latest docker compose up --build
- Код проекта берётся из
./examples/project_inject— замените содержимое этой папки на свой проект (или переопределите volumesecgensbomвdocker-compose.yml). IMAGE_NAME— контейнерный образ для сканирования через Clair (по умолчаниюpostgres:14).SKIP_CLAIR=falseвключает анализ контейнерного образа;BDU=trueдобавляет идентификаторы БДУ ФСТЭК.- Без
NVD_API_KEYбаза NVD для Dependency-Check скачается автоматически при первом запуске (~220 МБ, несколько минут; она кэшируется в./.dependency-check-dataи переиспользуется далее). Clair на первом запуске прогревает updater'ы до ~10 минут. - Результат:
./secgensbom_out/(SBOM-артефакты) +./secgensbom_reports/{excel,docx,odt}/(отчёты по компонентам и уязвимостям).
Минимальный запуск (только демо-проект, без сканирования образа):
docker compose up --build
Порядок запуска:
clair-db(Postgres) — база данных Clair, ожидает healthcheckclair— HTTP-сервер уязвимостей Clair v4, ожидает готовности БДsecgensbom— основной пайплайн, стартует после того, как Clair пройдёт healthcheck
Что происходит внутри secgensbom:
- Trivy запускается напрямую (встроен в образ)
- OWASP Dependency-Check запускается через
docker run owasp/dependency-check(Docker-in-Docker через/var/run/docker.sock) - Clair сканирует образ через
clairctl, подключаясь кhttp://clair:8080
Переменные окружения:
| Переменная | По умолчанию | Описание |
|---|---|---|
SOURCE |
local |
Источник проекта: local, github, gitlab |
PROJECT_DIR |
/app/project_inject |
Путь к проекту внутри контейнера |
SKIP_CLAIR |
false |
Отключить сканирование Clair (true/false) |
CLAIR_ENDPOINT |
http://clair:8080 |
Адрес Clair API |
IMAGE_NAME |
— | Docker-образ для сканирования Clair |
BDU |
false |
Включить обогащение идентификаторами БДУ ФСТЭК |
DEP_CHECK_DATA |
/app/.dependency-check-data |
Кэш NVD для Dependency-Check |
NVD_CACHE_DIR |
$DEP_CHECK_DATA/nvd-api-cache |
Кэш ответов NVD API для повторного CVSS lookup |
SBOM_COMPONENT_NETWORK |
false |
Разрешить сетевые уточнения языков/URL при экспорте компонентов |
Примечание: Если
IMAGE_NAMEне задан, шаг Clair пропускается автоматически.
NVD_CACHE_DIR хранит ответы NVD API по CVE и используется Clair fallback при заполнении пустого CVSS. Повторный запуск берёт оценку из уже сохранённого ответа и не делает новый HTTP-запрос.
По умолчанию экспорт компонентов не ходит в npm/NuGet/Debian/GitHub за уточнениями; для максимально быстрых и воспроизводимых отчётов язык и URL вычисляются из PURL.
Troubleshooting
Частые ошибки запуска, сетевых лимитов NVD, Docker/Clair и пустых отчётных колонок собраны в docs/TROUBLESHOOTING.md.
CI/CD
GitHub Actions
| Workflow | Триггер | Назначение |
|---|---|---|
ci.yml |
push / PR → main | lint + mypy + pytest (3.11–3.13) |
secgensbom.yml |
push → securitycheck, вручную |
запуск пайплайна, сохранение SBOM и отчётов |
publish.yml |
тег v*.*.* |
GitHub Packages + PyPI + Docker Hub + GitHub Release |
Публикация новой версии — один тег запускает всё:
git tag v2.2.0 -m "Release v2.2.0"
git push origin v2.2.0
Shared template
Файл secgensbom/secgensbom.yml — это переиспользуемый шаблон CI для GitLab. Любой другой проект в GitLab может подключить готовый SBOM-шаг одной строкой, не копируя конфигурацию:
Архитектура
Пайплайн secsbom run
flowchart TD
IN(["Источник\nlocal / github / gitlab / образ"]) --> STEP1
subgraph pipeline["secsbom run — этапы"]
subgraph STEP1["1 · Генерация SBOM"]
direction TB
CDXGEN["cdxgen\napp-bom-cdxgen.json"]
SYFT["syft\napp-bom-syft.json"]
GEN["generate.py — merge\napp-bom-merged.json"]
CLAIR_SCAN["clair.py — run_scan_report()\nclair-*.json\nполучение пакетов образа"]
CLAIR_ENRICH["clair.py — enrich_sbom_with_clair_packages()\nдобавление пакетов образа в SBOM\n(только добавление, без обновления)"]
CDXGEN --> GEN
SYFT --> GEN
GEN --> CLAIR_SCAN --> CLAIR_ENRICH
end
STEP1 --> DEDUP["2 · dedup.py\napp-bom-dedup.json\nдедуп компонентов по PURL\n(cdxgen + syft + Clair)"]
DEDUP --> SIGN1["3 · sign.py\napp-bom-dedup-signed.json + .sig\nSHA-256 — SBOM без уязвимостей"]
SIGN1 --> SCAN
subgraph SCAN["4 · scanner/ — параллельно (ThreadPoolExecutor)"]
direction LR
TRIVY_FS["trivy.py — scan_filesystem\ntrivy-fs.json (опц. --path)"]
TRIVY_SBOM["trivy.py — scan_sbom\nsbom-vulns.json"]
DEPCHECK["depcheck.py — docker run\ndependency-check-report.* (опц. --path)"]
CLAIR_VULNS["clair.py — parse_report_findings()\n+ NVD CVSS fallback (опц. --image)"]
end
TRIVY_FS & TRIVY_SBOM & DEPCHECK & CLAIR_VULNS --> CROSS["cross-populate CVSS\nмежду сканерами"]
CROSS --> DDUP2["5 · dedup.py\nдедуп уязвимостей\nпо CVE + компонент"]
DDUP2 --> MERGE["6 · vuln_merger.py\nvulnerabilities[] в SBOM\n+ БДУ ФСТЭК (опц. --bdu)\nvulns-normalized.json"]
MERGE --> SIGN2["7 · sign.py\nmerged-bom-signed.json + .sig\nSHA-256 — SBOM с уязвимостями"]
SIGN2 --> EXPORT["8 · exporter.py"]
end
CLAIR_SCAN -.->|"отчёт повторно используется\nна этапе 4"| CLAIR_VULNS
EXPORT --> XLSX["secgensbom_reports/\n*.xlsx"]
EXPORT --> DOCX["secgensbom_reports/\n*.docx"]
EXPORT --> ODT["secgensbom_reports/\n*.odt"]
Структура репозитория
sbom_genform/
├── src/sbom_pipeline/
│ ├── cli.py # secsbom / secsbom-pipeline (typer)
│ ├── pipeline.py # оркестратор
│ ├── generate.py # генерация SBOM
│ ├── dedup.py # дедупликация
│ ├── sign.py # SHA-256 подпись
│ ├── exporter.py # xlsx / docx / odt
│ ├── vuln_merger.py # встраивание уязвимостей
│ ├── config.py # конфигурация
│ ├── scanner/
│ │ ├── trivy.py
│ │ ├── depcheck.py
│ │ └── clair.py
│ └── enrichters/
│ ├── bdu.py # БДУ ФСТЭК (CVE → BDU ID)
│ └── nvd.py # NVD API (CVSS fallback)
├── docker/
│ └── Dockerfile.secgensbom
├── examples/project_inject/ # уязвимый PHP проект
├── secgensbom/secgensbom.yml # GitLab CI shared template
├── .github/workflows/
│ ├── ci.yml
│ ├── secgensbom.yml
│ └── publish.yml
├── tests/test_smoke.py
├── pyproject.toml
└── .env.example
Copyright (c) 2026 Elijah S Shmakov
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file sbom_pipeline-2.2.0.tar.gz.
File metadata
- Download URL: sbom_pipeline-2.2.0.tar.gz
- Upload date:
- Size: 7.1 MB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
26c85cab8f6fafa452cdec804c7c4efcf3a3a2092f98c8c21544deed608df4fe
|
|
| MD5 |
9539555486934b619a3762d369b348fc
|
|
| BLAKE2b-256 |
c9c2843c2781c30b3b47419b2b9dd8faf7f867292104ad076b6fff2a547c7e53
|
File details
Details for the file sbom_pipeline-2.2.0-py3-none-any.whl.
File metadata
- Download URL: sbom_pipeline-2.2.0-py3-none-any.whl
- Upload date:
- Size: 79.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
576e31e98a6536363444160c6b868848cd63a64735118c0c5c3a16423afbd563
|
|
| MD5 |
91bb70f7068ba2d9a135e780d234061c
|
|
| BLAKE2b-256 |
0df7967b16ffe273aab1a210ad5eeb72f3314b7dd951059ef793c301e5438833
|