Инструмент для безопасной генерации, анализа и форматирования Software Bill of Materials (SBOM).

Что делает:
- Генерирует SBOM из локальной директории или Git-репозитория (GitHub / GitLab)
- Дедуплицирует компоненты по PURL и уязвимости по CVE+компонент
- Создаёт два подписанных SBOM: без уязвимостей и с ними
- Сканирует уязвимости через Trivy, OWASP Dependency-Check, Clair
- Встраивает найденные уязвимости в SBOM (CycloneDX 1.5)
- Опционально обогащает уязвимости идентификаторами БДУ ФСТЭК
- Экспортирует читаемые отчёты: Excel (.xlsx), Word (.docx), ODT (.odt)
PyPI:
pip install sbom-pipelineGitHub 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 run # локальный демо-проект │
secsbom run --path ./myproject │
secsbom run --url https://github.com/org/repo --token ghp_... │
secsbom run --url https://gitlab.com/org/repo --token glpat-...| Файл | Описание |
|---|---|
secgensbom_out/app-bom-cdxgen.json |
Исходный SBOM |
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/report_name(cert) |
Отчет с добавлением полей GOST |
secgensbom_out/merged-bom-signed.sig |
SHA-256 контрольная сумма (с уязв.) |
secgensbom_out/vulns-normalized.json |
Нормализованные уязвимости |
Если включено 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 (если включён) |
| Путь | Формат | Содержимое |
|---|---|---|
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 |
| Признак выполнения функций безопасности | свойство компонента CycloneDX: security-function / securityFunction / isSecurityFunction |
| Принадлежность к контейнерному образу | 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-обогащение выключено, эта колонка не выводится.
Обогащение идентификаторами БДУ ФСТЭК выключено по умолчанию.
Включение через 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"
}
]
}Образ включает Python, Trivy, Docker CLI и Node.js/npx (cdxgen для non-Python проектов).
OWASP Dependency-Check запускается внутри утилиты через docker run (Docker-in-Docker), его Java-зависимость утяжелила бы основной образ на ~400 МБ.
Clair требует отдельного работающего HTTP-сервера — поэтому он вынесен в docker-compose.yml.
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Полный стек с OWASP Dependency-Check и Clair v4 запускается через docker-compose.yml:
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 |
Примечание: Если
IMAGE_NAMEне задан, шаг Clair пропускается автоматически.
| Workflow | Триггер | Назначение |
|---|---|---|
ci.yml |
push / PR → main | lint + mypy + pytest (3.11–3.13) |
secgensbom.yml |
push → main, вручную | запуск пайплайна, сохранение SBOM и отчётов |
publish.yml |
тег v*.*.* |
GitHub Packages + PyPI + Docker Hub + GitHub Release |
Публикация новой версии — один тег запускает всё:
git tag v2.1.0
git push --tagsФайл secgensbom/secgensbom.yml — это переиспользуемый шаблон CI для GitLab. Любой другой проект в GitLab может подключить готовый SBOM-шаг одной строкой, не копируя конфигурацию:
flowchart TD
IN(["Источник\nlocal / github / gitlab"]) --> GEN
subgraph pipeline["secsbom run — этапы"]
subgraph STEP1["1 · Генерация SBOM"]
direction TB
GEN["generate.py\napp-bom-cdxgen.json"]
CLAIR_SCAN["clair.py — run_scan_report()\nclair-*.json\nполучение пакетов образа"]
CLAIR_ENRICH["clair.py — enrich_sbom_with_clair_packages()\nдобавление пакетов образа в SBOM\n(только добавление, без обновления)"]
GEN --> CLAIR_SCAN --> CLAIR_ENRICH
end
STEP1 --> DEDUP["2 · dedup.py\napp-bom-dedup.json\nдедупликация компонентов по PURL\n(объединение данных из cdxgen и Clair)"]
DEDUP --> SIGN1["3 · sign.py\napp-bom-dedup-signed.json + .sig\nSHA-256 — SBOM без уязвимостей"]
SIGN1 --> SCAN
subgraph SCAN["4 · scanner/"]
direction LR
TRIVY["trivy.py\ntrivy-fs.json\nsbom-vulns.json"]
DEPCHECK["depcheck.py\ndependency-check-report.*"]
CLAIR_VULNS["clair.py — parse_report_findings()\nизвлечение уязвимостей\nиз уже готового отчёта"]
end
TRIVY & DEPCHECK & CLAIR_VULNS --> DDUP2["5 · dedup.py\nдедупликация уязвимостей\nпо CVE + компонент"]
DDUP2 --> MERGE["6 · vuln_merger.py\nvulnerabilities[] в SBOM"]
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
├── 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

