Taketo-Yoda/uv-sbom

GitHub: Taketo-Yoda/uv-sbom

为 uv 管理的 Python 项目生成 SBOM 并检查漏洞与许可证合规性的命令行工具

Stars: 1 | Forks: 0

# uv-sbom [![GitHub release](https://img.shields.io/github/release/Taketo-Yoda/uv-sbom.svg)](https://github.com/Taketo-Yoda/uv-sbom/releases) [![PyPI - Version](https://img.shields.io/pypi/v/uv-sbom-bin?logo=python&logoColor=white&label=PyPI)](https://pypi.org/project/uv-sbom-bin/) [![Crates.io Version](https://img.shields.io/crates/v/uv-sbom?logo=rust&logoColor=white)](https://crates.io/crates/uv-sbom) [![shield_license]][license_file] [![CI](https://static.pigsec.cn/wp-content/uploads/repos/2026/03/6411ffecef103115.svg)](https://github.com/Taketo-Yoda/uv-sbom/actions/workflows/ci.yml) [![Dependabot Updates](https://static.pigsec.cn/wp-content/uploads/repos/2026/03/d78c5aa925103116.svg)](https://github.com/Taketo-Yoda/uv-sbom/actions/workflows/dependabot/dependabot-updates) [![CodeQL](https://static.pigsec.cn/wp-content/uploads/repos/2026/03/6d05808369103117.svg)](https://github.com/Taketo-Yoda/uv-sbom/actions/workflows/github-code-scanning/codeql) [English](README.md) | [日本語](README-JP.md) 为通过 [uv](https://github.com/astral-sh/uv) 管理的 Python 项目生成 SBOM (软件物料清单)。 ## 功能特性 - 📦 解析 `uv.lock` 文件以提取依赖信息 - 🔍 通过重试逻辑自动从 PyPI 获取许可证信息 - 🛡️ 使用 OSV API 检查已知漏洞(仅限 Markdown 格式) - 📋 许可证合规性策略检查,支持可配置的允许/拒绝列表和通配符 - 🔎 **漏洞解决指南** - 识别哪个直接依赖引入了每个有漏洞的传递依赖 - 📊 多种格式输出: - **CycloneDX 1.6** JSON 格式(标准 SBOM 格式) - **Markdown** 格式,清晰区分直接依赖和传递依赖 - 🚀 快速且独立 - 使用 Rust 编写 - 💾 输出到标准输出或文件 - 🛡️ 健壮的错误处理,提供有用的错误消息和建议 - 📈 许可证信息检索期间的进度跟踪 - 🏗️ 采用 **六边形架构** (端口与适配器) + **领域驱动设计**,确保可维护性和可测试性 - ✅ 全面的测试覆盖(单元测试、集成测试、E2E 测试) ## 范围与 CycloneDX 的主要区别 ### SBOM 范围 本工具基于 **uv.lock** 文件内容生成 SBOM,包括: - 直接运行时依赖 - 传递运行时依赖 - 开发依赖(如果锁定在 uv.lock 中) **不包含的内容:** - 构建系统依赖(例如 hatchling, setuptools) - 发布工具(例如 twine, build) - 仅存在于虚拟环境中但未锁定在 uv.lock 中的依赖 ### 与 CycloneDX 官方工具的对比 截至 v7.2.1,官方 cyclonedx-python 库尚未直接支持 uv。在为 Python 项目生成 SBOM 时: | 方面 | uv-sbom (本工具) | CycloneDX 官方工具 | |--------|---------------------|--------------------------| | **数据来源** | `uv.lock` 文件 | `.venv` 虚拟环境 | | **范围** | 仅生产运行时依赖 | 包括构建/开发工具在内的完整供应链 | | **包数量** | 通常较少(例如 16 个包) | 通常较多(例如 38+ 个包) | | **使用场景** | 生产环境安全扫描 | 全面供应链审计 | | **准确性** | 反映锁定的依赖 | 反映已安装的包 | ### 应该使用哪个工具? - **用于生产环境安全扫描**:使用 `uv-sbom` 专注于将要部署到生产环境的依赖 - **用于全面供应链审计**:使用 CycloneDX 官方工具以包含所有开发和构建时依赖 - **用于法规合规**:检查您的具体要求 - 某些法规可能要求采用全面的方法 `uv-sbom` 的聚焦方法通过排除不随最终应用程序发布的构建时依赖,减少了安全漏洞扫描中的噪音。 ## 安装 ### Cargo (推荐 Rust 用户使用) ![Crates.io Total Downloads](https://img.shields.io/crates/d/uv-sbom) 从 [crates.io](https://crates.io/crates/uv-sbom) 安装: ``` cargo install uv-sbom ``` ### uv tool (Python 用户) ![PyPI - Downloads](https://img.shields.io/pypi/dm/uv-sbom-bin?logo=PyPI&logoColor=white) 安装 Python 封装包: ``` uv tool install uv-sbom-bin ``` 或通过 pip 安装: ``` pip install uv-sbom-bin ``` 安装后,使用 `uv-sbom` 命令: ``` uv-sbom --version ``` **注意**:包名是 `uv-sbom-bin`,但安装的命令是 `uv-sbom`。 ### 预编译二进制文件 ![GitHub Downloads (all assets, all releases)](https://img.shields.io/github/downloads/Taketo-Yoda/uv-sbom/total?logo=GitHub) 从 [GitHub Releases](https://github.com/Taketo-Yoda/uv-sbom/releases) 下载预编译二进制文件: **macOS (Apple Silicon)**: ``` curl -LO https://github.com/Taketo-Yoda/uv-sbom/releases/latest/download/uv-sbom-aarch64-apple-darwin.tar.gz tar xzf uv-sbom-aarch64-apple-darwin.tar.gz sudo mv uv-sbom /usr/local/bin/ ``` **macOS (Intel)**: ``` curl -LO https://github.com/Taketo-Yoda/uv-sbom/releases/latest/download/uv-sbom-x86_64-apple-darwin.tar.gz tar xzf uv-sbom-x86_64-apple-darwin.tar.gz sudo mv uv-sbom /usr/local/bin/ ``` **Linux (x86_64)**: ``` curl -LO https://github.com/Taketo-Yoda/uv-sbom/releases/latest/download/uv-sbom-x86_64-unknown-linux-gnu.tar.gz tar xzf uv-sbom-x86_64-unknown-linux-gnu.tar.gz sudo mv uv-sbom /usr/local/bin/ ``` **Windows**: 从 [releases 页面](https://github.com/Taketo-Yoda/uv-sbom/releases) 下载 `uv-sbom-x86_64-pc-windows-msvc.zip` 并解压到您想要的位置。 ### 从源码构建 ``` # 克隆仓库 git clone https://github.com/Taketo-Yoda/uv-sbom.git cd uv-sbom # 构建并安装 cargo build --release cargo install --path . ``` ### 验证安装 ``` uv-sbom --version ``` ## 使用方法 ### 基本用法 为当前目录生成 CycloneDX JSON SBOM: ``` uv-sbom ``` ### 输出格式 生成包含直接和传递依赖的 Markdown 表格: ``` uv-sbom --format markdown ``` 生成 CycloneDX JSON(默认): ``` uv-sbom --format json ``` ### 指定项目路径 分析不同目录中的项目: ``` uv-sbom --path /path/to/project ``` ### 保存到文件 输出到文件而不是标准输出: ``` uv-sbom --format json --output sbom.json uv-sbom --format markdown --output SBOM.md ``` ### 组合选项 ``` uv-sbom --path /path/to/project --format markdown --output SBOM.md ``` ### 排除包 您可以使用 `--exclude` 或 `-e` 选项从 SBOM 中排除特定包: ``` # 排除单个包 uv-sbom -e "pytest" # 排除多个包 uv-sbom -e "pytest" -e "mypy" -e "black" # 使用通配符排除模式 uv-sbom -e "debug-*" # Exclude all packages starting with "debug-" uv-sbom -e "*-dev" # Exclude all packages ending with "-dev" uv-sbom -e "*-test-*" # Exclude all packages containing "-test-" # 与其他选项结合 uv-sbom --format json --output sbom.json -e "pytest" -e "*-dev" ``` **模式语法:** - 使用 `*` 作为通配符匹配零个或多个字符 - 模式区分大小写 - 每次调用最多 64 个模式 **防止信息泄露:** 使用 `--exclude` 选项跳过特定的内部或专有库。这可以防止它们的名称在元数据检索期间被发送到外部注册表(如 PyPI),从而确保您的内部项目结构保持私密。 ### 配置文件 您可以使用配置文件 (`uv-sbom.config.yml`) 来设置默认选项,而不必每次都在命令行上传递它们。 #### 生成配置模板 使用 `--init` 选项生成模板配置文件,其中包含所有可用字段作为注释示例: ``` # 在当前目录生成模板 uv-sbom --init # 在特定目录生成模板 uv-sbom --init --path ./my-project ``` 这将创建一个 `uv-sbom.config.yml` 文件,其中包含每个选项的内联文档。如果文件已存在,该命令将以错误退出,以防止意外覆盖。 **自动发现**:在您的项目目录(`uv.lock` 所在位置)中放置一个 `uv-sbom.config.yml` 文件。工具会自动检测并加载它。 **显式路径**:使用 `--config` / `-c` 在自定义位置指定配置文件。 ``` # 自动发现配置文件(放置在项目目录中) uv-sbom --check-cve # 显式配置文件路径 uv-sbom --config ./custom-config.yml --check-cve ``` **示例配置文件** (`uv-sbom.config.yml`): ``` # 输出格式:json 或 markdown format: markdown # 从 SBOM 排除的包(支持通配符) exclude_packages: - "pytest" - "mypy" - "*-dev" # 启用 CVE 漏洞检查 check_cve: true # 漏洞检查的严重性阈值 (low/medium/high/critical) severity_threshold: high # 漏洞检查的 CVSS 阈值 (0.0-10.0) # cvss_threshold: 7.0 # 忽略的 CVE(可附带原因) ignore_cves: - id: CVE-2024-1234 reason: "False positive for our use case" - id: CVE-2024-5678 reason: "Mitigated by network configuration" # 许可证合规策略 license_policy: allow: ["MIT", "Apache-2.0", "BSD-*", "ISC", "PSF-2.0"] deny: ["GPL-3.0-only", "GPL-3.0-or-later", "AGPL-*"] unknown: "warn" # "warn" | "deny" | "allow" ``` #### 配置文件结构参考 | 字段 | 类型 | 必填 | 描述 | |-------|------|----------|-------------| | `format` | string | No | 输出格式 (`json` / `markdown`) | | `exclude_packages` | string[] | No | 包排除模式(支持通配符) | | `check_cve` | bool | No | 启用 CVE 检查 | | `severity_threshold` | string | No | 严重性阈值 (`low` / `medium` / `high` / `critical`) | | `cvss_threshold` | number | No | CVSS 阈值 (0.0 - 10.0) | | `ignore_cves` | object[] | No | 要忽略的 CVE 列表 | | `ignore_cves[].id` | string | Yes | CVE ID (例如, `CVE-2024-1234`) | | `ignore_cves[].reason` | string | No | 忽略的原因 | | `license_policy` | object | No | 许可证合规策略配置 | | `license_policy.allow` | string[] | No | 允许的许可证模式(支持通配符) | | `license_policy.deny` | string[] | No | 拒绝的许可证模式(支持通配符) | | `license_policy.unknown` | string | No | 未知许可证处理方式 (`warn` / `deny` / `allow`) | #### 优先级与合并规则 - **CLI 参数覆盖配置文件值**(针对标量字段:`format`、`severity_threshold`、`cvss_threshold`) - **`check_cve`** 如果通过 CLI 标志或配置文件设置,则启用(逻辑或) - **`exclude_packages`** 从 CLI 和配置文件**合并**,然后去重 - **`ignore_cves`** 从 CLI (`--ignore-cve`) 和配置文件**合并**,按 ID 去重(CLI 条目在重复时优先) - **`check_license`** 如果通过 CLI 标志或配置文件设置,则启用(逻辑或,与 `check_cve` 相同) - **`--license-allow`** 和 **`--license-deny`** CLI 选项**覆盖**配置文件中的 `license_policy.allow` / `license_policy.deny`(不合并) ### 忽略特定 CVE 您可以使用 `--ignore-cve` / `-i` 从命令行忽略特定的 CVE: ``` # 从 CLI 忽略特定 CVE uv-sbom --check-cve --ignore-cve CVE-2024-1234 --ignore-cve CVE-2024-5678 # 简写形式 uv-sbom --check-cve -i CVE-2024-1234 -i CVE-2024-5678 # 结合配置文件和 CLI 忽略项(合并两个来源) uv-sbom --config ./config.yml --check-cve -i CVE-2024-9999 ``` ### 检查漏洞 使用 `--check-cve` 选项,通过 [OSV (开源漏洞) 数据库](https://osv.dev) 检查包的已知安全漏洞: ``` # 检查 Markdown 输出中的漏洞 uv-sbom --format markdown --check-cve # 保存漏洞报告到文件 uv-sbom --format markdown --check-cve --output SBOM.md # 与排除模式结合 uv-sbom --format markdown --check-cve -e "pytest" -e "*-dev" ``` ### 许可证合规性检查 使用 `--check-license` 选项根据可配置的许可证策略检查包: ``` # 启用许可证合规检查(使用配置文件策略) uv-sbom --check-license --format markdown # 使用内联策略(覆盖配置文件) uv-sbom --check-license --license-allow "MIT,Apache-2.0,BSD-*" --license-deny "GPL-3.0,AGPL-*" # 结合漏洞检查 uv-sbom --check-license --check-cve --severity-threshold high ``` **工作原理:** - **拒绝优先于允许**:如果许可证同时匹配两个列表,则被拒绝 - **通配符模式**:使用 `BSD-*`、`AGPL-*` 等进行模式匹配(不区分大小写) - **未知许可证处理**:配置如何处理不在任一列表中的许可证: - `warn`(默认):报告为警告但不失败 - `deny`:将未知许可证视为违规 - `allow`:静默允许未知许可证 - **退出代码**:检测到策略违规时返回退出代码 1 ### 漏洞阈值选项 您可以使用阈值选项控制哪些漏洞触发非零退出代码: ``` # 检查是否存在任何漏洞(如果发现则退出码为 1) uv-sbom --format markdown --check-cve # 仅检查高或严重严重性 uv-sbom --format markdown --check-cve --severity-threshold high # 仅检查严重严重性 uv-sbom --format markdown --check-cve --severity-threshold critical # 仅检查 CVSS >= 7.0 uv-sbom --format markdown --check-cve --cvss-threshold 7.0 # 仅检查 CVSS >= 9.0(严重) uv-sbom --format markdown --check-cve --cvss-threshold 9.0 ``` **阈值选项:** - `--severity-threshold `:按严重性级别过滤 - `--cvss-threshold `:按 CVSS 分数过滤 (0.0-10.0) **注意:** - 一次只能使用一个阈值选项 - 需要启用 `--check-cve` - 低于阈值的漏洞仍会显示在报告中,但不会触发退出代码 1 - 使用 `--cvss-threshold` 时,没有 CVSS 分数 (N/A) 的漏洞被排除在阈值评估之外 ### PyPI 链接验证 使用 `--verify-links` 选项在生成超链接之前验证包是否存在于 PyPI 上。不存在于 PyPI 的包将被渲染为纯文本: ``` # 生成带有已验证 PyPI 链接的 Markdown uv-sbom --format markdown --verify-links # 与其他选项结合 uv-sbom --format markdown --verify-links --check-cve --output SBOM.md ``` **行为:** - 不使用 `--verify-links`:所有包名都获得 PyPI 超链接(默认,快速) - 使用 `--verify-links`:仅经过验证的包获得超链接;未验证的包渲染为纯文本 - 网络错误会优雅地回退到纯文本(不会崩溃) - 请求并行执行(最多 10 个并发)以提高性能 ### CI 集成 使用漏洞阈值进行 CI/CD 流水线集成: ``` # GitHub Actions 示例 - name: Generate SBOM run: uv-sbom --format markdown --output sbom.md - name: Security Check (High and Critical only) run: uv-sbom --format markdown --check-cve --severity-threshold high - name: Security Check (CVSS >= 7.0) run: uv-sbom --format markdown --check-cve --cvss-threshold 7.0 ``` ``` # GitHub Actions - 许可证合规检查 - name: License Compliance Check run: uv-sbom --check-license --format markdown - name: Combined Security and License Check run: uv-sbom --check-license --check-cve --severity-threshold high ``` ``` # GitLab CI 示例 security_scan: script: - uv-sbom --format markdown --check-cve --severity-threshold high allow_failure: false ``` **重要说明:** - 漏洞检查**仅适用于 Markdown 格式** - 需要互联网连接以查询 OSV API - 在 `--dry-run` 模式下不可用(跳过网络操作) - 使用 `--exclude` 防止内部包被发送到 OSV API **示例输出:** 当发现漏洞时,Markdown 输出中会添加如下部分: ``` ## 漏洞报告 **⚠️ Security Issues Detected** The following packages have known security vulnerabilities: | Package | Current Version | Fixed Version | CVSS | Severity | CVE ID | |---------|----------------|---------------|------|----------|--------| | urllib3 | 2.0.0 | 2.0.7 | 9.8 | 🔴 CRITICAL | CVE-2023-45803 | | requests | 2.28.0 | 2.31.0 | 7.5 | 🟠 HIGH | CVE-2023-32681 | --- *Vulnerability data provided by [OSV](https://osv.dev) under CC-BY 4.0* ``` ### 漏洞解决指南 当 `--check-cve` 在传递依赖中检测到漏洞时,uv-sbom 会自动生成**漏洞解决指南**。此部分显示哪个直接依赖引入了每个有漏洞的传递包,以便您确切知道需要升级什么。 #### Markdown 输出示例 ``` ## 漏洞解决指南 The following transitive dependencies have known vulnerabilities. The table shows which direct dependency introduces each vulnerable package. | Vulnerable Package | Current | Fixed Version | Severity | Introduced By (Direct Dep) | Vulnerability ID | |--------------------|---------|---------------|----------|---------------------------|-----------------| | urllib3 | 1.26.15 | >= 2.0.7 | 🟠 HIGH | requests (2.31.0) | [CVE-2024-XXXXX](https://nvd.nist.gov/vuln/detail/CVE-2024-XXXXX) | | certifi | 2023.7.22 | >= 2024.2.2 | 🟠 HIGH | requests (2.31.0), httpx (0.25.0) | [CVE-2024-YYYYY](https://nvd.nist.gov/vuln/detail/CVE-2024-YYYYY) | ``` #### CycloneDX JSON 输出 在 CycloneDX 格式中,引入依赖作为 `properties` 条目包含: ``` { "vulnerabilities": [ { "id": "CVE-2024-XXXXX", "properties": [ { "name": "uv-sbom:introduced-by", "value": "requests@2.31.0" } ] } ] } ``` ### 升级顾问 (`--suggest-fix`) 结合使用 `--suggest-fix` 和 `--check-cve`,自动建议应将直接依赖升级到哪个版本解决每个传递依赖漏洞。 **需要**: - 启用 `--check-cve` 标志 - 安装了 `uv` CLI - 项目目录中有 `pyproject.toml` **示例**: ``` uv-sbom generate --check-cve --suggest-fix ``` **输出**:在漏洞解决指南中添加“建议操作”列,显示: - `⬆️ Upgrade requests → 2.32.3 (resolves urllib3 to 2.2.1)` — 当升级可以修复漏洞时 - `⚠️ Cannot resolve: latest httpx still pins idna < 3.7` — 当没有升级方案时 - `❓ Could not analyze: ` — 当模拟失败时 **使用附带的示例尝试**: ``` # 此示例包含传递性 CVE,旨在展示可升级和无法解决的结果 uv-sbom -p examples/suggest-fix-project --check-cve --suggest-fix -f markdown ``` 完整演练请参阅 [`examples/suggest-fix-project/README.md`](examples/suggest-fix-project/README.md)。 **许可证合规性检查输出示例:** ``` ## 许可证合规检查 Policy: 3 allowed patterns, 1 denied pattern | Unknown: warn ### 违规(发现 2 项) | Package | Version | License | Reason | |---------|---------|---------|--------| | some-gpl-lib | 1.0.0 | GPL-3.0 | Denied by policy | | mystery-pkg | 2.1.0 | Unknown | Not in allow list | ``` 当未发现漏洞时: ``` ## 漏洞报告 **✅ No Known Vulnerabilities** No security vulnerabilities were found in the scanned packages. --- *Vulnerability data provided by [OSV](https://osv.dev) under CC-BY 4.0* ``` ### 使用 dry-run 验证配置 使用 `--dry-run` 选项在工具与外部注册表通信之前验证您的配置: ``` # 验证排除模式工作正常 uv-sbom --dry-run -e "internal-*" -e "proprietary-pkg" # 测试包含所有选项的配置 uv-sbom --dry-run --path /path/to/project --format json -e "*-dev" ``` **为什么使用 --dry-run:** - **验证排除模式**:确保您的 `--exclude` 模式正确匹配您要跳过的包 - **防止信息泄露**:在工具与 PyPI 注册表通信之前确认敏感的内部包已被排除 - **快速验证**:所有输入验证都在没有网络开销的情况下进行 - **早期错误检测**:立即捕获配置问题(缺少 uv.lock、无效模式等) **在 dry-run 模式下会发生什么:** - ✅ 读取并解析 `uv.lock` 文件 - ✅ 验证所有命令行参数 - ✅ 检查排除模式并警告未匹配的模式 - ✅ 如果未发现问题则输出成功消息 - ❌ 跳过从 PyPI 获取许可证(无网络通信) - ❌ 跳过 SBOM 输出生成 ## 安全性 ### 排除模式输入验证 `-e`/`--exclude` 选项实施以下安全措施以防止恶意输入: #### 字符限制 模式中仅允许以下字符: - **字母数字字符**:a-z, A-Z, 0-9, Unicode 字母/数字 - **连字符** (`-`), **下划线** (`_`), **点** (`.`):包名中常见 - **方括号** (`[`, `]`):用于包扩展(例如 `requests[security]`) - **星号** (`*`):用于通配符匹配 控制字符、Shell 元字符和路径分隔符被阻止,以防止: - 终端转义序列注入 - 日志注入攻击 - 命令注入(纵深防御) #### 模式限制 - **最大模式数**:每次调用可指定 64 个模式 - **最大长度**:每个模式 255 个字符 - **最小内容**:模式必须包含至少一个非通配符字符 这些限制可防止以下拒绝服务攻击: - 过度内存消耗 - 复杂模式匹配导致的 CPU 耗尽 #### 示例 **有效模式**: ``` uv-sbom -e 'pytest' # Exact match uv-sbom -e 'test-*' # Prefix wildcard uv-sbom -e '*-dev' # Suffix wildcard uv-sbom -e 'package[extra]' # Package with extras ``` **无效模式**(被拒绝并报错): ``` uv-sbom -e '' # Empty pattern uv-sbom -e '***' # Only wildcards uv-sbom -e 'pkg;rm -rf /' # Contains shell metacharacter uv-sbom -e "$(cat /etc/passwd)" # Shell command substitution blocked ``` 有关更详细的安全信息,包括威胁模型和攻击向量,请参阅 [SECURITY.md](SECURITY.md)。 ## 命令行选项 ``` Options: -f, --format Output format: json or markdown [default: json] -p, --path Path to the project directory [default: current directory] -o, --output Output file path (if not specified, outputs to stdout) -e, --exclude Exclude packages matching patterns (supports wildcards: *) -c, --config Path to config file (auto-discovers uv-sbom.config.yml if not specified) -i, --ignore-cve CVE IDs to ignore (can be specified multiple times) --init Generate a uv-sbom.config.yml template file --dry-run Validate configuration without network communication or output generation --verify-links Verify PyPI links exist before generating hyperlinks (Markdown format only) --check-cve Check for known vulnerabilities using OSV API (Markdown format only) --severity-threshold Severity threshold for vulnerability check (low/medium/high/critical) Requires --check-cve to be enabled --cvss-threshold CVSS threshold for vulnerability check (0.0-10.0) Requires --check-cve to be enabled --suggest-fix Suggest direct dependency upgrade versions to resolve transitive vulnerabilities Requires --check-cve to be enabled, uv CLI installed, and pyproject.toml in project directory --check-license Check license compliance against policy --license-allow Comma-separated list of allowed license patterns (overrides config) --license-deny Comma-separated list of denied license patterns (overrides config) -h, --help Print help -V, --version Print version ``` ## 退出代码 uv-sbom 返回以下退出代码: | 退出代码 | 描述 | 示例 | |-----------|-------------|----------| | 0 | 成功 | SBOM 生成成功,未发现超过阈值的漏洞,显示 `--help` 或 `--version` | | 1 | 检测到漏洞或许可证违规 | 检测到超过阈值的漏洞,发现许可证策略违规 | | 2 | 无效的命令行参数 | 未知选项,无效的参数类型 | | 3 | 应用程序错误 | 缺少 uv.lock 文件,无效的项目路径,无效的排除模式,网络错误,文件写入错误 | ### 漏洞和许可证检查时的退出代码 使用 `--check-cve` 或 `--check-license` 时,退出代码行为根据阈值设置而变化: | 场景 | 退出代码 | |----------|-----------| | 未发现漏洞 | 0 | | 发现漏洞(未指定阈值) | 1 | | 发现漏洞,全部低于阈值 | 0 | | 发现漏洞,部分高于阈值 | 1 | | 检测到许可证策略违规 | 1 | | 组合:任一检查失败 | 1 | | 组合:两项检查都通过 | 0 | **示例:** ``` # 如果没有高/严重漏洞则返回 0,即使存在低/中危漏洞 uv-sbom --format markdown --check-cve --severity-threshold high # 如果没有 CVSS >= 7.0 的漏洞则返回 0 uv-sbom --format markdown --check-cve --cvss-threshold 7.0 ``` ### 常见错误场景 **退出代码 3 - 应用程序错误:** ``` # 缺失 uv.lock 文件 $ uv-sbom --path /path/without/uv-lock ❌ An error occurred: uv.lock file not found: /path/without/uv-lock/uv.lock # 退出码:3 # 无效的排除模式(为空) $ uv-sbom -e "" ❌ An error occurred: Exclusion pattern cannot be empty # 退出码:3 # 无效的排除模式(包含无效字符) $ uv-sbom -e "pkg;name" ❌ An error occurred: Exclusion pattern contains invalid character ';' in pattern 'pkg;name' # 退出码:3 # 不存在的项目路径 $ uv-sbom --path /nonexistent ❌ An error occurred: Invalid project path: /nonexistent # 退出码:3 ``` **退出代码 2 - CLI 参数错误:** ``` # 未知选项 $ uv-sbom --unknown-option error: unexpected argument '--unknown-option' found # 退出码:2 # 无效的格式值 $ uv-sbom --format invalid error: invalid value 'invalid' for '--format ' # 退出码:2 ``` ### 在脚本中使用 ``` #!/bin/bash uv-sbom --format json --output sbom.json case $? in 0) echo "SBOM generated successfully" ;; 1) echo "Vulnerabilities detected above threshold" exit 1 ;; 2) echo "Invalid command-line arguments" exit 2 ;; 3) echo "Application error occurred" exit 3 ;; esac ``` ## 输出示例 ### Markdown 格式 ``` # 软件物料清单 (SBOM) ## 组件清单 A comprehensive list of all software components and libraries included in this project. | Package | Version | License | Description | |---------|---------|---------|-------------| | janome | 0.5.0 | AL2 | Japanese morphological analysis engine. | | pydantic | 2.12.5 | MIT | Data validation using Python type hints | | ...additional packages... | ## 直接依赖 Primary packages explicitly defined in the project configuration(e.g., pyproject.toml). | Package | Version | License | Description | |---------|---------|---------|-------------| | janome | 0.5.0 | AL2 | Japanese morphological analysis engine. | | pydantic | 2.12.5 | MIT | Data validation using Python type hints | ## 传递依赖 Secondary dependencies introduced by the primary packages. ### pydantic 的依赖 | Package | Version | License | Description | |---------|---------|---------|-------------| | annotated-types | 0.7.0 | MIT License | Reusable constraint types to use with typing.Annotated | | pydantic-core | 2.41.5 | MIT | Core functionality for Pydantic validation and serialization | ``` ### CycloneDX JSON 格式 ``` { "bomFormat": "CycloneDX", "specVersion": "1.6", "version": 1, "serialNumber": "urn:uuid:...", "metadata": { "timestamp": "2024-01-01T00:00:00Z", "tools": [ { "name": "uv-sbom", "version": "0.1.0" } ] }, "components": [ { "type": "library", "name": "requests", "version": "2.31.0", "description": "HTTP library for Python", "licenses": [ { "license": { "name": "Apache 2.0" } } ], "purl": "pkg:pypi/requests@2.31.0" } ] } ``` ## 要求 - 由 `uv` 管理且包含 `uv.lock` 文件的 Python 项目 - 用于从 PyPI 获取许可证信息的互联网连接 ## 网络要求 ### 访问的外部域名 `uv-sbom` 在 SBOM 生成期间向以下外部服务发出 HTTP 请求: #### 所有操作都需要: 1. **PyPI (Python Package Index)** - 域名:`https://pypi.org` - 目的:获取 Python 包的许可证信息 - 时机:每次 SBOM 生成(除非使用 `--dry-run`) - 速率限制:无官方限制,但工具实现了重试逻辑 - 端点:`/pypi/{package_name}/json` #### 可选(仅在使用 `--check-cve` 或 `--verify-links` 时): 2. **PyPI 链接验证** - 域名:`https://pypi.org` - 目的:通过 HTTP HEAD 请求验证包在 PyPI 上是否存在 - 时机:仅在使用 `--verify-links` 标志时 - 速率限制:最多 10 个并发请求 - 端点:`/project/{package_name}/` 3. **OSV (开源漏洞数据库)** - 域名:`https://api.osv.dev` - 目的:获取安全扫描的漏洞信息 - 时机:仅在使用 `--check-cve` 标志时 - 速率限制:工具实现了 10 请求/秒的限制 - 端点: - `/v1/querybatch` - 漏洞 ID 批量查询 - `/v1/vulns/{vuln_id}` - 详细漏洞信息 ### 防火墙配置 如果您在公司防火墙或代理后面,请确保以下域名在白名单中: ``` # 必需 pypi.org # 可选(用于 --verify-links 和 --check-cve) pypi.org # Also used for --verify-links api.osv.dev # Only for --check-cve ``` ### 代理配置 该工具遵循标准的 HTTP/HTTPS 代理环境变量: ``` export HTTP_PROXY=http://proxy.company.com:8080 export HTTPS_PROXY=http://proxy.company.com:8080 export NO_PROXY=localhost,127.0.0.1 uv-sbom --format json ``` ### 离线模式 要在不发出网络请求的情况下验证配置,请使用 `--dry-run`: ``` uv-sbom --dry-run ``` 此模式: - 验证 `uv.lock` 文件 - 验证命令行参数 - 检查排除模式 - 跳过许可证获取(不访问 PyPI) - 跳过漏洞检查(不访问 OSV) - 跳过 SBOM 输出生成 ## 错误处理 uv-sbom 提供带有有用建议的详细错误消息: - **缺少 uv.lock 文件**:清晰的消息,包含修复建议 - **无效的项目路径**:在处理前验证目录是否存在 - **许可证获取失败**:重试失败的请求(最多 3 次尝试)并继续处理 - **文件写入错误**:检查目录是否存在及其权限 - **进度跟踪**:在许可证信息检索期间显示实时进度 示例错误消息: ``` ❌ An error occurred: uv.lock file not found: /path/to/project/uv.lock 💡 Hint: uv.lock file does not exist in project directory "/path/to/project". Please run in the root directory of a uv project, or specify the correct path with the --path option. ``` ## 故障排除 ### 找不到 uv.lock 文件 确保您在包含 `uv.lock` 文件的目录中运行命令,或使用 `--path` 选项指定正确的项目目录。 ### 许可证信息获取失败 某些包可能无法从 PyPI 检索许可证信息。工具将: 1. 自动重试最多 3 次 2. 继续处理其他包 3. 为失败的包显示警告 4. 如果获取失败,在输出中包含没有许可证信息的包 ### 网络问题 如果您在代理或防火墙后面,请确保您可以访问 `https://pypi.org`。工具对 API 请求使用 10 秒超时。 ## 文档 ### 用户文档 - [README.md](README.md) - 用户文档 - [LICENSE](LICENSE) - MIT 许可证 ### 开发者文档 - [DEVELOPMENT.md](DEVELOPMENT.md) - 开发指南 - [ARCHITECTURE.md](ARCHITECTURE.md) - **六边形架构 + DDD 实现**(层、端口、适配器、测试策略、ADR) - [CHANGELOG.md](CHANGELOG.md) - 变更历史 ### Claude Code 用户 - [.claude/project-context.md](.claude/project-context.md) - Claude Code 的完整项目上下文 - [.claude/instructions.md](.claude/instructions.md) - Claude Code 的编码指南和说明 这些文件为使用 Claude Code 进行 AI 辅助开发提供了全面的上下文。 ## 致谢 ### 漏洞数据 使用 `--check-cve` 选项时,本工具从 [OSV (开源漏洞)](https://osv.dev) 检索漏洞数据,该数据基于 [知识共享署名 4.0 国际许可协议](https://creativecommons.org/licenses/by/4.0/) 提供。 **必需的致谢:** - 漏洞数据由 OSV 提供 - 网址:https://osv.dev - 许可证:CC-BY 4.0 OSV 数据库是一项协作努力,旨在为开源软件提供全面、准确和可访问的漏洞信息。 ## 许可证 MIT 许可证 - 详见 [LICENSE](LICENSE) 文件。
标签:CycloneDX, DevSecOps, OSV, PyPI, Python, Rust, SBOM, uv, uv.lock, Vercel, 上游代理, 云安全监控, 依赖管理, 可视化界面, 数据集, 无后门, 硬件无关, 网络流量审计, 许可证合规, 跌倒检测, 软件开发工具包, 软件物料清单, 逆向工具, 通知系统, 静态分析