uv-sbom
Generate SBOMs (Software Bill of Materials) for Python projects managed by uv.
Features
- 📦 Parses
uv.lockfiles to extract dependency information - 🔍 Automatically fetches license information from PyPI with retry logic
- 🛡️ Checks for known vulnerabilities using OSV API (Markdown format only)
- 📊 Outputs in multiple formats:
- CycloneDX 1.6 JSON format (standard SBOM format)
- Markdown format with direct and transitive dependencies clearly separated
- 🚀 Fast and standalone - written in Rust
- 💾 Output to stdout or file
- 🛡️ Robust error handling with helpful error messages and suggestions
- 📈 Progress tracking during license information retrieval
- 🏗️ Built with Hexagonal Architecture (Ports and Adapters) + Domain-Driven Design for maintainability and testability
- ✅ Comprehensive test coverage (Unit, Integration, E2E)
Scope and Key Differences from CycloneDX
SBOM Scope
This tool generates SBOMs based on uv.lock file contents, which includes:
- Direct runtime dependencies
- Transitive runtime dependencies
- Development dependencies (if locked in uv.lock)
What's NOT included:
- Build system dependencies (e.g., hatchling, setuptools)
- Publishing tools (e.g., twine, build)
- Dependencies only present in the virtual environment but not locked in uv.lock
Comparison with CycloneDX Official Tools
As of v7.2.1, the official cyclonedx-python library does not yet provide direct support for uv. When generating SBOMs for Python projects:
| Aspect | uv-sbom (this tool) | CycloneDX Official Tools |
|---|---|---|
| Data Source | uv.lock file |
.venv virtual environment |
| Scope | Production runtime dependencies only | Entire supply chain including build/dev tools |
| Package Count | Typically fewer (e.g., 16 packages) | Typically more (e.g., 38+ packages) |
| Use Case | Production security scanning | Comprehensive supply chain audit |
| Accuracy | Reflects locked dependencies | Reflects installed packages |
Which Tool Should You Use?
- For production security scanning: Use
uv-sbomto focus on dependencies that will be deployed to production - For comprehensive supply chain audit: Use CycloneDX official tools to include all development and build-time dependencies
- For regulatory compliance: Check your specific requirements - some regulations may require the comprehensive approach
The focused approach of uv-sbom reduces noise in security vulnerability scanning by excluding build-time dependencies that don't ship with the final application.
Installation
Cargo (Recommended for Rust users)
Install from crates.io:
uv tool (Python users)
Install the Python wrapper package:
Or via pip:
After installation, use the uv-sbom command:
Note: The package name is uv-sbom-bin, but the installed command is uv-sbom.
Pre-built Binaries
Download pre-built binaries from GitHub Releases:
macOS (Apple Silicon):
macOS (Intel):
Linux (x86_64):
Windows:
Download uv-sbom-x86_64-pc-windows-msvc.zip from the releases page and extract to your desired location.
From Source
# Clone the repository
# Build and install
Verify Installation
Usage
Basic usage
Generate a CycloneDX JSON SBOM for the current directory:
Output formats
Generate a Markdown table with direct and transitive dependencies:
Generate a CycloneDX JSON (default):
Specify project path
Analyze a project in a different directory:
Save to file
Output to a file instead of stdout:
Combined options
Excluding packages
You can exclude specific packages from the SBOM using the --exclude or -e option:
# Exclude a single package
# Exclude multiple packages
# Use wildcards to exclude patterns
# Combine with other options
Pattern Syntax:
- Use
*as a wildcard to match zero or more characters - Patterns are case-sensitive
- Maximum 64 patterns per invocation
Preventing Information Leakage:
Use the --exclude option to skip specific internal or proprietary libraries. This prevents their names from being sent to external registries (like PyPI) during metadata retrieval, ensuring your internal project structure remains private.
Checking for vulnerabilities
Use the --check-cve option to check packages for known security vulnerabilities using the OSV (Open Source Vulnerability) database:
# Check for vulnerabilities in Markdown output
# Save vulnerability report to file
# Combine with exclude patterns
Vulnerability Threshold Options
You can control which vulnerabilities trigger a non-zero exit code using threshold options:
# Check for any vulnerabilities (exits with 1 if found)
# Check for High or Critical severity only
# Check for Critical severity only
# Check for CVSS >= 7.0 only
# Check for CVSS >= 9.0 (Critical) only
Threshold Options:
--severity-threshold <LEVEL>: Filter by severity level (low, medium, high, critical)--cvss-threshold <SCORE>: Filter by CVSS score (0.0-10.0)
Notes:
- Only one threshold option can be used at a time
- Requires
--check-cveto be enabled - Vulnerabilities below the threshold are still shown in the report but don't trigger exit code 1
- When using
--cvss-threshold, vulnerabilities without CVSS scores (N/A) are excluded from threshold evaluation
CI Integration
Use vulnerability thresholds for CI/CD pipeline integration:
# GitHub Actions example
- 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
# GitLab CI example
security_scan:
script:
- uv-sbom --format markdown --check-cve --severity-threshold high
allow_failure: false
Important Notes:
- Vulnerability checking is only available for Markdown format
- Requires internet connection to query OSV API
- Not available in
--dry-runmode (skips network operations) - Use
--excludeto prevent internal packages from being sent to OSV API
Example Output:
When vulnerabilities are found, a section like this is added to the Markdown output:
**⚠️ Security Issues Detected**
The following packages have known security vulnerabilities:
*Vulnerability data provided by [OSV](https://osv.dev) under CC-BY 4.0*
When no vulnerabilities are found:
**✅ 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*
Validating configuration with dry-run
Use the --dry-run option to validate your configuration before the tool communicates with external registries:
# Verify exclude patterns work correctly
# Test configuration with all options
Why use --dry-run:
- Verify exclude patterns: Ensure your
--excludepatterns correctly match the packages you want to skip - Prevent information leakage: Confirm that sensitive internal packages are excluded BEFORE the tool communicates with PyPI registry
- Fast validation: All input validation happens without network overhead
- Early error detection: Catch configuration issues (missing uv.lock, invalid patterns, etc.) immediately
What happens in dry-run mode:
- ✅ Reads and parses
uv.lockfile - ✅ Validates all command-line arguments
- ✅ Checks exclude patterns and warns about unmatched patterns
- ✅ Outputs success message if no issues found
- ❌ Skips license fetching from PyPI (no network communication)
- ❌ Skips SBOM output generation
Security
Exclude Pattern Input Validation
The -e/--exclude option implements the following security measures to protect against malicious input:
Character Restrictions
Only the following characters are allowed in patterns:
- Alphanumeric characters: a-z, A-Z, 0-9, Unicode letters/numbers
- Hyphens (
-), underscores (_), dots (.): Common in package names - Square brackets (
[,]): For package extras (e.g.,requests[security]) - Asterisks (
*): For wildcard matching
Control characters, shell metacharacters, and path separators are blocked to prevent:
- Terminal escape sequence injection
- Log injection attacks
- Command injection (defense in depth)
Pattern Limits
- Maximum patterns: 64 patterns can be specified per invocation
- Maximum length: 255 characters per pattern
- Minimum content: Patterns must contain at least one non-wildcard character
These limits prevent denial-of-service attacks via:
- Excessive memory consumption
- CPU exhaustion from complex pattern matching
Examples
Valid patterns:
Invalid patterns (rejected with error):
For more detailed security information, including threat model and attack vectors, see SECURITY.md.
Command-line options
Options:
-f, --format <FORMAT> Output format: json or markdown [default: json]
-p, --path <PATH> Path to the project directory [default: current directory]
-o, --output <OUTPUT> Output file path (if not specified, outputs to stdout)
-e, --exclude <PATTERN> Exclude packages matching patterns (supports wildcards: *)
--dry-run Validate configuration without network communication or output generation
--check-cve Check for known vulnerabilities using OSV API (Markdown format only)
--severity-threshold <LEVEL> Severity threshold for vulnerability check (low/medium/high/critical)
Requires --check-cve to be enabled
--cvss-threshold <SCORE> CVSS threshold for vulnerability check (0.0-10.0)
Requires --check-cve to be enabled
-h, --help Print help
-V, --version Print version
Exit Codes
uv-sbom returns the following exit codes:
| Exit Code | Description | Examples |
|---|---|---|
| 0 | Success | SBOM generated successfully, no vulnerabilities above threshold, --help or --version displayed |
| 1 | Vulnerabilities detected (with --check-cve) |
Vulnerabilities above threshold detected |
| 2 | Invalid command-line arguments | Unknown option, invalid argument type |
| 3 | Application error | Missing uv.lock file, invalid project path, invalid exclude pattern, network error, file write error |
Exit Codes with Vulnerability Checking
When using --check-cve, the exit code behavior changes based on threshold settings:
| Scenario | Exit Code |
|---|---|
| No vulnerabilities found | 0 |
| Vulnerabilities found (no threshold specified) | 1 |
| Vulnerabilities found, all below threshold | 0 |
| Vulnerabilities found, some above threshold | 1 |
Examples:
# Returns 0 if no High/Critical vulnerabilities, even if Low/Medium exist
# Returns 0 if no vulnerabilities have CVSS >= 7.0
Common Error Scenarios
Exit code 1 - Application errors:
# Missing uv.lock file
# Exit code: 1
# Invalid exclude pattern (empty)
# Exit code: 1
# Invalid exclude pattern (invalid characters)
# Exit code: 1
# Nonexistent project path
# Exit code: 1
Exit code 2 - CLI argument errors:
# Unknown option
# Exit code: 2
# Invalid format value
# Exit code: 2
Usage in Scripts
#!/bin/bash
Output Examples
Markdown format
Note: The Markdown format sample is based on the SBOM format from ja-complete v0.1.0.
A comprehensive list of all software components and libraries included in this project.
Primary packages explicitly defined in the project configuration(e.g., pyproject.toml).
Secondary dependencies introduced by the primary packages.
CycloneDX JSON format
Requirements
- A Python project managed by
uvwith auv.lockfile - Internet connection for fetching license information from PyPI
Network Requirements
External Domains Accessed
uv-sbom makes HTTP requests to the following external services during SBOM generation:
Required for all operations:
- PyPI (Python Package Index)
- Domain:
https://pypi.org - Purpose: Fetch license information for Python packages
- When: Every SBOM generation (unless using
--dry-run) - Rate limit: No official limit, but tool implements retry logic
- Endpoint:
/pypi/{package_name}/json
- Domain:
Optional (only when using --check-cve):
- OSV (Open Source Vulnerability Database)
- Domain:
https://api.osv.dev - Purpose: Fetch vulnerability information for security scanning
- When: Only when
--check-cveflag is used - Rate limit: Tool implements 10 requests/second limit
- Endpoints:
/v1/querybatch- Batch query for vulnerability IDs/v1/vulns/{vuln_id}- Detailed vulnerability information
- Domain:
Firewall Configuration
If you are behind a corporate firewall or proxy, ensure the following domains are on the allowlist:
# Required
pypi.org
# Optional (only for --check-cve)
api.osv.dev
Proxy Configuration
The tool respects standard HTTP/HTTPS proxy environment variables:
Offline Mode
To validate configuration without making network requests, use --dry-run:
This mode:
- Validates
uv.lockfile - Validates command-line arguments
- Checks exclude patterns
- Skips license fetching (no PyPI access)
- Skips vulnerability checking (no OSV access)
- Skips SBOM output generation
Error Handling
uv-sbom provides detailed error messages with helpful suggestions:
- Missing uv.lock file: Clear message with suggestions on how to fix
- Invalid project path: Validates directory existence before processing
- License fetch failures: Retries failed requests (up to 3 attempts) and continues processing
- File write errors: Checks directory existence and permissions
- Progress tracking: Shows real-time progress during license information retrieval
Example error message:
❌ 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.
Troubleshooting
uv.lock file not found
Ensure you're running the command in a directory containing a uv.lock file, or use the --path option to specify the correct project directory.
License information fetch failures
Some packages may fail to retrieve license information from PyPI. The tool will:
- Automatically retry up to 3 times
- Continue processing other packages
- Display warnings for failed packages
- Include packages in the output without license information if fetching fails
Network issues
If you're behind a proxy or firewall, ensure that you can access https://pypi.org. The tool uses a 10-second timeout for API requests.
Documentation
For Users
For Developers
- DEVELOPMENT.md - Development guide
- ARCHITECTURE.md - Hexagonal Architecture + DDD implementation (layers, ports, adapters, test strategy, ADRs)
- CHANGELOG.md - Change history
For Claude Code Users
- .claude/project-context.md - Complete project context for Claude Code
- .claude/instructions.md - Coding guidelines and instructions for Claude Code
These files provide comprehensive context for AI-assisted development with Claude Code.
Attribution
Vulnerability Data
When using the --check-cve option, this tool retrieves vulnerability data from OSV (Open Source Vulnerability), which is provided under the Creative Commons Attribution 4.0 International License (CC-BY 4.0).
Required Attribution:
- Vulnerability data provided by OSV
- Available at: https://osv.dev
- License: CC-BY 4.0
The OSV database is a collaborative effort to provide comprehensive, accurate, and accessible vulnerability information for open source software.
License
MIT License - see LICENSE file for details.