Frmwrk-GmbH/sbom-scanner
GitHub: Frmwrk-GmbH/sbom-scanner
跨生态系统的SBOM生成与依赖分析工具,支持CVE扫描并输出交互式HTML报告和CycloneDX标准格式
Stars: 0 | Forks: 0
# SBOM 扫描器
一款通用的软件项目 SBOM 和 HTML 报告生成器。生成包含所有依赖(包括传递依赖)的 [CycloneDX 1.6](https://cyclonedx.org/) SBOM,以及带有 CVE 扫描和版本分析的交互式 HTML 报告。
## 功能
- **多生态系统** — npm, PyPI, Dart/Flutter, Maven/Gradle, Rust/Cargo, yarn
- **多根目录 / Monorepo** — 每个生态系统支持多个 lockfile,包含标签和标记
- **Gradle 子项目** — 自动检测并扫描所有子模块
- **自动检测** — 从 lockfile 自动发现生态系统
- **自动配置器** — 递归扫描项目并以交互方式生成配置(精美 TUI 或简单文本模式)
- **CVE 扫描** — 可插拔扫描器架构,内置 [grype](https://github.com/anchore/grype) 和 [osv-scanner](https://github.com/google/osv-scanner)
- **最新版本检查** — 并行查询 npm, PyPI, crates.io, Maven Central, Google Maven
- **HTML 报告** — 选项卡、搜索、过滤器(依赖类型、模块、状态)、深色模式、打印样式
- **依赖树** — 可展开、动画效果、过时后代冒泡显示、按生态系统/模块分选项卡
- **PDF 导出** — 通过 weasyprint、Chrome headless 或 wkhtmltopdf
- **两种报告模式** — 交互式(选项卡/JS),带 `--simple` 回退(扁平、无 JS)
- **完全模块化** — 新生态系统或 CVE 扫描器 = 一个文件 + 注册条目,无需修改报告生成器
- **库 API** — 可直接导入 (`from sbom_scanner import generate_sbom, generate_report`)
- **i18n** — 默认英语,包含德语翻译 (`--lang de`)
- **可安装** — `pip install` 后提供三个 CLI 命令
## 快速开始
```
# 安装
pip install sbom-scanner[all]
# 1. 生成配置(交互式 — 扫描项目并询问)
sbom configure --project-dir /path/to/project
# 2. 生成 SBOM
sbom scan --project-dir /path/to/project
# 3. 生成 HTML 报告
sbom report --project-dir /path/to/project
# 打开报告
open /path/to/project/sbom-report.html
```
第 1 步是可选的 —— 如果没有配置文件,生态系统将使用默认路径自动检测。对于 Monorepo 或子目录布局,建议使用配置。
## 安装
```
# 从 PyPI(发布后)
pip install sbom-scanner[all]
# 从仓库
pip install .[all]
# 用于开发
pip install -e .[all]
```
**可选扩展:**
| 扩展 | 安装内容 | 何时需要 |
|---|---|---|
| `yaml` | PyYAML | YAML 配置和 Dart/Flutter |
| `python` | pipdeptree | 传递 Python 依赖和依赖图 |
| `pdf` | weasyprint | PDF 导出(替代方案:Chrome headless) |
| `tui` | rich, InquirerPy | 精美交互式配置器 |
| `all` | PyYAML + pipdeptree + rich + InquirerPy | 推荐 |
**外部工具(可选):**
| 工具 | 何时需要 |
|---|---|
| [grype](https://github.com/anchore/grype) | CVE 扫描 |
| [osv-scanner](https://github.com/google/osv-scanner) | CVE 扫描 |
| Google Chrome / Chromium | PDF 导出(weasyprint 的替代方案) |
| `dart` CLI | Dart/Flutter 过时检查 |
## 配置
在项目目录中创建 `sbom.config.yaml`(或让 `sbom configure` 生成):
### 最小配置
```
project:
name: my-app
version: "1.0.0"
```
### 完整配置
```
project:
name: my-app
version: "2.0.0"
description: "My application"
# 仅在路径与默认值不同时指定。
# 省略 = 使用默认路径自动检测。
sources:
npm:
package_json: package.json # default
lockfile: package-lock.json # default (also supports yarn.lock)
pypi:
requirements: requirements.txt # default (pip-compile or plain)
pub:
pubspec_yaml: pubspec.yaml # default
pubspec_lock: pubspec.lock # default
maven:
gradle_dir: . # default (root with build.gradle)
configuration: runtimeClasspath # default
cargo:
cargo_toml: Cargo.toml # default
lockfile: Cargo.lock # default
output:
sbom: sbom.cyclonedx.json
report: sbom-report.html
options:
skip_cve: false
pdf: false
simple: false
workers: 20
```
### 子目录路径
当 lockfile 不在项目根目录时:
```
project:
name: my-fullstack-app
version: "1.0.0"
sources:
pypi:
requirements: backend/requirements.txt
npm:
package_json: frontend/package.json
lockfile: frontend/package-lock.json
```
### 多根目录 / Monorepo
同一生态系统的多个实例以列表形式配置:
```
project:
name: my-monorepo
version: "3.0.0"
sources:
npm:
- label: frontend
package_json: apps/frontend/package.json
lockfile: apps/frontend/package-lock.json
tags: [web, react]
- label: admin
package_json: apps/admin/package.json
lockfile: apps/admin/package-lock.json
tags: [internal]
cargo:
cargo_toml: services/api/Cargo.toml
lockfile: services/api/Cargo.lock
```
- **`label`** — 报告中的显示名称。回退:当存在多个条目时从目录路径派生。
- **`tags`** — 作为 [CycloneDX tags](https://cyclonedx.org/docs/1.6/json/#components_items_tags) 应用于每个组件。在报告中显示为徽章,并在 SBOM JSON 中提供以供自动化使用。
### Gradle 子项目
带有子模块的 Gradle 项目会被自动检测。所有子项目(`:client`、`:server`、`:common` 等)都会被单独扫描。模块过滤器和依赖树子选项卡会出现在报告中。
```
sources:
maven:
gradle_dir: .
configuration: runtimeClasspath # optional, default: runtimeClasspath
```
## 自动配置器
无需手动编写配置:
```
sbom configure --project-dir /path/to/project
```
安装 `rich` + `InquirerPy` 后,您将获得带有光标导航、状态表和选项子菜单的精美 TUI。如果没有这些依赖,将使用简单的文本菜单作为回退(`--simple` 强制使用)。
功能:
- 递归扫描,跳过 `node_modules`、`target`、`.venv` 等
- 从目录名称建议标签
- 从清单文件读取项目名称/版本
- 加载现有配置以进行编辑
- 选项子菜单:CVE 扫描、PDF、简单报告、工作线程数
- `--non-interactive` 接受所有默认值
## CLI 参考
### sbom configure
```
sbom configure [--project-dir DIR] [--output FILE] [--non-interactive] [--simple] [--lang LANG]
```
| 标志 | 默认值 | 描述 |
|---|---|---|
| `--project-dir` | `.` | 要扫描的项目目录 |
| `--output` | `sbom.config.yaml` | 输出路径(相对于 project-dir) |
| `--non-interactive` | `false` | 接受所有默认值 |
| `--simple` | `false` | 强制使用简单文本菜单(无 TUI) |
| `--lang` | `en` | 语言 (`en`, `de`) |
### sbom scan
```
sbom scan [--project-dir DIR] [--config FILE] [--output FILE] [--lang LANG]
```
| 标志 | 默认值 | 描述 |
|---|---|---|
| `--project-dir` | `.` | 项目目录 |
| `--config` | `sbom.config.yaml` | 配置文件(在 project-dir 中) |
| `--output` | 来自配置或 `sbom.cyclonedx.json` | 输出路径 |
| `--lang` | `en` | 语言 (`en`, `de`) |
### sbom report
```
sbom report [--project-dir DIR] [--config FILE] [--sbom FILE] [--output FILE] [--skip-cve] [--pdf] [--simple] [--lang LANG]
```
| 标志 | 默认值 | 描述 |
|---|---|---|
| `--project-dir` | `.` | 项目目录 |
| `--config` | `sbom.config.yaml` | 配置文件 |
| `--sbom` | 来自配置或 `sbom.cyclonedx.json` | 输入 SBOM |
| `--output` | 来自配置或 `sbom-report.html` | 输出路径 |
| `--skip-cve` | `false` | 跳过 CVE 扫描 |
| `--pdf` | `false` | 额外生成 PDF(使用简单报告) |
| `--simple` | `false` | 无选项卡、搜索和过滤器的简单报告 |
| `--lang` | `en` | 语言 (`en`, `de`) |
## 库 API
可直接在 Python 中导入:
```
from pathlib import Path
from sbom_scanner import generate_sbom, generate_report, load_config
project = Path("../my-project")
config = load_config(project / "sbom.config.yaml")
sbom_path = project / "sbom.cyclonedx.json"
# 生成 SBOM
generate_sbom(project, config, sbom_path)
# 生成 HTML 报告
generate_report(sbom_path, project / "sbom-report.html", skip_cve=True)
```
## 支持的生态系统
| 生态系统 | Lockfile | Registry | 检测方式 |
|---|---|---|---|
| npm | `package-lock.json` (v1/v2/v3), `yarn.lock` (v1) | npmjs.org | `package.json` + lockfile |
| PyPI | `requirements.txt` (pip-compile 或普通) | pypi.org | `requirements.txt` |
| Dart/Flutter | `pubspec.lock` | pub.dev | `pubspec.yaml` + `pubspec.lock` |
| Maven/Gradle | `build.gradle` / `build.gradle.kts` | Maven Central + Google Maven | `build.gradle` + `gradlew` |
| Rust/Cargo | `Cargo.lock` | crates.io | `Cargo.toml` + `Cargo.lock` |
**PyPI 注意事项:**
- pip-compile 格式(带 `# via` 注释) — 自动检测直接依赖与传递依赖
- 普通 `requirements.txt` — 所有包视为直接依赖,传递依赖通过 `pipdeptree` 获取(如已安装)
**Maven/Gradle 注意事项:**
- 子项目会被自动检测并单独扫描
- 模块成员资格(`:client`、`:server` 等)在报告中显示为过滤器
- 也支持预计算的 `gradle-dependencies.json`(自定义 Gradle 任务)
## 添加新生态系统
只需一个文件 + 注册条目。**无需修改报告生成器。**
1. 创建一个新文件,例如 `src/sbom_scanner/ecosystems/composer.py`:
```
from .base import Ecosystem
class ComposerEcosystem(Ecosystem):
# Identification
name = "composer"
display_name = "PHP/Composer"
cdx_prefix = "cdx:composer"
purl_type = "composer"
# Report configuration
package_url_template = "https://packagist.org/packages/{name}"
dep_property = "cdx:composer:dependency"
latest_property = "cdx:composer:latestVersion"
dep_labels = {"direct main": "direct", "transitive": "transitive"}
has_group_column = False
# Auto-configurator pattern
def scan_pattern(self):
return {
"detect_files": ["composer.lock"],
"companion_files": ["composer.json"],
"config_keys": {"composer.lock": "lockfile", "composer.json": "composer_json"},
"icon": "🐘",
}
# Required methods
def detect(self, project_dir, config): ...
def parse(self, project_dir, config): ...
def fetch_latest_versions(self, packages, workers=20): ...
def build_component(self, pkg, latest): ...
def get_direct_purls(self, packages): ...
# Optional
def parse_dependency_graph(self, project_dir, config, packages):
return []
```
2. 在 `src/sbom_scanner/ecosystems/__init__.py` 中注册:
```
from .composer import ComposerEcosystem
REGISTRY: list = [
...
ComposerEcosystem(),
]
```
就是这样。报告生成器从类中读取所有属性 —— 选项卡、过滤器、徽章、树均可自动工作。自动配置器通过 `scan_pattern()` 发现它。
## 添加新 CVE 扫描器
相同的架构 —— 一个文件 + 注册条目。
1. 创建 `src/sbom_scanner/scanners/trivy.py`:
```
from .base import Scanner
class TrivyScanner(Scanner):
name = "trivy"
targets = ["*"] # or ["npm", "pypi"] for specific ecosystems
def is_available(self): ...
def scan(self, sbom_path, lockfiles, project_dir): ...
```
2. 在 `src/sbom_scanner/scanners/__init__.py` 中注册。
**内置扫描器:**
| 扫描器 | 类型 | 目标 | 描述 |
|---|---|---|---|
| grype | 基于 SBOM | `*` | 扫描 CycloneDX SBOM |
| osv | 基于 Lockfile | `*` | 对照 OSV 数据库扫描 lockfile |
## 项目结构
```
sbom-scanner/
├── pyproject.toml
├── README.md
├── LICENSE # MIT
├── CONTRIBUTING.md
├── sbom.config.yaml # Example config
└── src/
└── sbom_scanner/
├── __init__.py # Version + library API
├── i18n.py # Internationalization (gettext)
├── configure.py # sbom configure (TUI + simple fallback)
├── generate_sbom.py # sbom scan (ecosystem-agnostic)
├── generate_sbom_report.py # sbom report (ecosystem-agnostic)
├── ecosystems/
│ ├── __init__.py # Registry
│ ├── base.py # Base class (Ecosystem)
│ ├── npm.py # npm + yarn
│ ├── pypi.py # PyPI + pipdeptree
│ ├── pub.py # Dart/Flutter
│ ├── maven.py # Maven/Gradle + subprojects
│ └── cargo.py # Rust/Cargo
├── scanners/
│ ├── __init__.py # Registry
│ ├── base.py # Base class (Scanner)
│ ├── grype.py # grype (SBOM-based)
│ └── osv.py # osv-scanner (lockfile-based)
└── locales/
└── de/LC_MESSAGES/ # German translation (.po/.mo)
```
## CI/CD 集成
GitLab CI 示例:
```
sbom:
stage: test
script:
- pip install sbom-scanner[all]
- sbom scan --project-dir .
- sbom report --project-dir . --skip-cve
artifacts:
paths:
- sbom.cyclonedx.json
- sbom-report.html
```
带 CVE 扫描:
```
sbom:
stage: test
image: python:3.13
before_script:
- pip install sbom-scanner[all]
- curl -sSfL https://raw.githubusercontent.com/anchore/grype/main/install.sh | sh -s -- -b /usr/local/bin
script:
- sbom scan --project-dir .
- sbom report --project-dir .
artifacts:
paths:
- sbom.cyclonedx.json
- sbom-report.html
```
## 许可证
MIT — © 2026 Frmwrk GmbH
标签:Angular, Cargo, CycloneDX, Dart, DevSecOps, Flutter, Gradle, Grype, HTML报告, Maven, Monorepo支持, npm, OSV-Scanner, PDF导出, PyPI, Python安全工具, Rust, SBOM生成器, 上游代理, 云安全监控, 交互式报告, 依赖树分析, 多模态安全, 多生态系统支持, 文档安全, 漏洞测试, 漏洞验证, 版本审计, 组件漏洞, 网络流量审计, 逆向工具, 静态分析