sbom_tools/lib.rs
1//! **A powerful library for working with Software Bills of Materials (SBOMs).**
2//!
3//! `sbom-tools` provides a comprehensive suite of tools for parsing, analyzing, diffing,
4//! and enriching software bills of materials. It is designed to be a foundational library for
5//! supply chain security, compliance, and dependency management workflows.
6//!
7//! The library supports common SBOM formats like **CycloneDX** and **SPDX** and normalizes them
8//! into a unified, easy-to-use data model. It powers both a command-line interface (CLI)
9//! for direct use and a Rust library for programmatic integration into your own applications.
10//!
11//! ## Key Features
12//!
13//! - **Multi-Format Parsing**: Ingests CycloneDX (JSON) and SPDX (JSON, Tag-Value) files,
14//! with automatic format detection.
15//! - **Intelligent Diffing**: Performs semantic diffs between two SBOMs to identify changes
16//! in components, dependencies, licenses, and vulnerabilities.
17//! - **Data Enrichment**: Augments SBOMs with external data, including:
18//! - **Vulnerability Information**: Fetches vulnerability data from the OSV (Open Source Vulnerability) database.
19//! - **End-of-Life (EOL) Status**: Checks components against the `endoflife.date` API to identify unsupported software.
20//! - More enrichers for staleness, KEV, etc.
21//! - **Quality & Compliance Scoring**: Checks SBOMs for compliance against established standards
22//! like NTIA Minimum Elements and the EU Cyber Resilience Act (CRA).
23//! - **Flexible Reporting**: Generates analysis reports in multiple formats, including JSON,
24//! Markdown, SARIF, and a full-featured interactive Terminal UI (TUI).
25//!
26//! ## Core Concepts & Modules
27//!
28//! The library is organized into several key modules:
29//!
30//! - **[`model`]**: Defines the central data structure, [`NormalizedSbom`]. Regardless of the input
31//! format (CycloneDX or SPDX), the library parses it into this unified model. This allows you to work with
32//! a consistent and predictable API for all your SBOM analysis tasks.
33//! - **[`pipeline`]**: Contains the primary functions for processing SBOMs. You can use the functions
34//! in this module to construct a pipeline to parse, enrich, and generate reports in a single,
35//! streamlined operation.
36//! - **[`diff`]**: Home of the [`DiffEngine`], which performs a semantic comparison of two `NormalizedSbom` objects.
37//! - **[`enrichment`]**: Provides `Enricher` traits and implementations for augmenting SBOMs with external data.
38//! Requires the `enrichment` feature flag.
39//! - **[`quality`]**: Contains the [`ComplianceChecker`] for validating SBOMs against standards and the
40//! [`QualityScorer`] for grading overall quality.
41//! - **[`reports`]**: Includes generators for creating output reports in various formats.
42//!
43//! ## Getting Started: Parsing an SBOM
44//!
45//! The most common entry point is to parse an existing SBOM file using the [`pipeline`] module.
46//! The library will automatically detect the format and return a [`NormalizedSbom`].
47//!
48//! ```no_run
49//! use std::path::Path;
50//! use sbom_tools::parse_sbom;
51//!
52//! fn main() -> Result<(), Box<dyn std::error::Error>> {
53//! let sbom = parse_sbom(Path::new("path/to/your/sbom.json"))?;
54//!
55//! println!(
56//! "Successfully parsed SBOM for '{}' with {} components.",
57//! sbom.document.name.unwrap_or_else(|| "Unknown".to_string()),
58//! sbom.components.len()
59//! );
60//!
61//! Ok(())
62//! }
63//! ```
64//!
65//! ## Examples
66//!
67//! Below are examples for other common use cases.
68//!
69//! ### Diffing Two SBOMs
70//!
71//! The [`DiffEngine`] identifies what has been added, removed, or modified between an "old"
72//! and a "new" SBOM.
73//!
74//! ```no_run
75//! use std::path::Path;
76//! use sbom_tools::{parse_sbom, DiffEngine};
77//!
78//! fn main() -> Result<(), Box<dyn std::error::Error>> {
79//! let old_sbom = parse_sbom(Path::new("path/to/old-sbom.json"))?;
80//! let new_sbom = parse_sbom(Path::new("path/to/new-sbom.json"))?;
81//!
82//! let engine = DiffEngine::new();
83//! let diff = engine.diff(&old_sbom, &new_sbom)?;
84//!
85//! println!("Components Added: {}", diff.components.added.len());
86//! println!("Components Removed: {}", diff.components.removed.len());
87//!
88//! for added in &diff.components.added {
89//! println!(" + {} {}", added.name,
90//! added.new_version.as_deref().unwrap_or(""));
91//! }
92//!
93//! Ok(())
94//! }
95//! ```
96//!
97//! ### Enriching with Vulnerability and End-of-Life (EOL) Data
98//!
99//! You can configure the processing pipeline to run enrichment stages. The following example
100//! enables both OSV vulnerability scanning and EOL status checking.
101//!
102//! *Note: This requires the `enrichment` feature flag to be enabled.*
103//!
104//! ```ignore
105//! use sbom_tools::parse_sbom;
106//! use sbom_tools::model::EolStatus;
107//!
108//! fn main() -> Result<(), Box<dyn std::error::Error>> {
109//! let mut sbom = parse_sbom("path/to/your/sbom.json")?;
110//!
111//! // Enrich with OSV vulnerability data (requires `enrichment` feature)
112//! #[cfg(feature = "enrichment")]
113//! {
114//! use sbom_tools::{OsvEnricher, OsvEnricherConfig, VulnerabilityEnricher};
115//! let enricher = OsvEnricher::new(OsvEnricherConfig::default());
116//! enricher.enrich(&mut sbom)?;
117//! }
118//!
119//! println!("--- Vulnerability and EOL Report ---");
120//! for component in sbom.components.values() {
121//! if !component.vulnerabilities.is_empty() {
122//! println!("\n[!] Component '{}' has {} vulnerabilities:",
123//! component.name, component.vulnerabilities.len());
124//! for vuln in &component.vulnerabilities {
125//! println!(" - {}: {}", vuln.id,
126//! vuln.summary.as_deref().unwrap_or("No summary"));
127//! }
128//! }
129//!
130//! if let Some(eol_info) = &component.eol {
131//! if eol_info.status == EolStatus::EndOfLife {
132//! println!("\n[!] Component '{}' has reached End-of-Life!",
133//! component.name);
134//! println!(" - Product: {}", eol_info.product);
135//! if let Some(eol_date) = eol_info.eol_date {
136//! println!(" - EOL Date: {}", eol_date);
137//! }
138//! }
139//! }
140//! }
141//!
142//! Ok(())
143//! }
144//! ```
145//!
146//! ### Checking for Compliance
147//!
148//! The [`ComplianceChecker`] validates an SBOM against a specific standard, such as the
149//! EU Cyber Resilience Act (CRA).
150//!
151//! ```no_run
152//! use std::path::Path;
153//! use sbom_tools::parse_sbom;
154//! use sbom_tools::quality::{ComplianceChecker, ComplianceLevel};
155//!
156//! fn main() -> Result<(), Box<dyn std::error::Error>> {
157//! let sbom = parse_sbom(Path::new("path/to/your/sbom.json"))?;
158//!
159//! // Check against the EU CRA Phase 2 requirements
160//! let checker = ComplianceChecker::new(ComplianceLevel::CraPhase2);
161//! let result = checker.check(&sbom);
162//!
163//! if result.is_compliant {
164//! println!("SBOM is compliant with {}.", result.level.name());
165//! } else {
166//! println!("SBOM is NOT compliant with {}. Found {} errors and {} warnings.",
167//! result.level.name(),
168//! result.error_count,
169//! result.warning_count
170//! );
171//!
172//! for violation in result.violations {
173//! println!("[{:?}] {}: {}",
174//! violation.severity, violation.category.name(), violation.message);
175//! }
176//! }
177//!
178//! Ok(())
179//! }
180//! ```
181//!
182//! ## Feature Flags
183//!
184//! `sbom-tools` uses feature flags to manage optional functionality and dependencies.
185//! - `enrichment`: Enables all data enrichment modules, such as OSV and EOL lookups.
186//! This adds network dependencies like `reqwest`.
187//!
188//! ## Command-Line Interface (CLI)
189//!
190//! This documentation is for the `sbom-tools` library crate. If you are looking for the
191//! command-line tool, please refer to the project's README or install it via `cargo install sbom-tools`.
192
193// Lint to discourage unwrap() in production code - prefer explicit error handling
194#![warn(clippy::unwrap_used)]
195// Pedantic lints: allow categories that are design choices for this codebase
196#![allow(
197 // Cast safety: usize↔f64/f32/u16/i32 casts are pervasive in TUI layout math
198 // and statistical calculations — all values are bounded in practice
199 clippy::cast_precision_loss,
200 clippy::cast_possible_truncation,
201 clippy::cast_sign_loss,
202 clippy::cast_possible_wrap,
203 // Doc completeness: # Errors / # Panics sections are aspirational for 78+15 fns
204 clippy::missing_errors_doc,
205 clippy::missing_panics_doc,
206 // TUI render functions are inherently long — splitting hurts readability
207 clippy::too_many_lines,
208 // State structs legitimately use many bools for toggle flags
209 clippy::struct_excessive_bools,
210 clippy::fn_params_excessive_bools,
211 // self is kept for API consistency / future use across trait-like impls
212 clippy::unused_self,
213 // Variable names like `min`/`mid` or `old`/`new` are clear in context
214 clippy::similar_names
215)]
216
217pub mod cli;
218pub mod config;
219pub mod diff;
220#[cfg(feature = "enrichment")]
221pub mod enrichment;
222pub mod error;
223pub mod matching;
224pub mod model;
225pub mod parsers;
226pub mod pipeline;
227pub mod quality;
228pub mod reports;
229pub mod tui;
230pub mod utils;
231pub mod watch;
232
233// Re-export main types for convenience
234pub use config::{AppConfig, AppConfigBuilder, ConfigPreset, EnrichmentConfig, TuiConfig};
235pub use config::{
236 BehaviorConfig, FilterConfig, GraphAwareDiffConfig, MatchingConfig, MatchingRulesPathConfig,
237 OutputConfig,
238};
239pub use config::{ConfigError, Validatable};
240pub use config::{
241 DiffConfig, MatrixConfig, MultiDiffConfig, QueryConfig, TimelineConfig, ViewConfig,
242};
243pub use diff::{DiffEngine, DiffResult, GraphDiffConfig};
244#[cfg(feature = "enrichment")]
245pub use enrichment::{
246 EnricherConfig, EnrichmentStats, NoOpEnricher, OsvEnricher, OsvEnricherConfig,
247 VulnerabilityEnricher,
248};
249pub use error::{ErrorContext, OptionContext, Result, SbomDiffError};
250pub use matching::{
251 ComponentMatcher, FuzzyMatchConfig, FuzzyMatcher, MatchResult, MatchTier, MatchingRulesConfig,
252 RuleEngine,
253};
254pub use model::{
255 CanonicalId, Component, ComponentSortKey, NormalizedSbom, NormalizedSbomIndex, SbomIndexBuilder,
256};
257pub use parsers::{SbomParser, parse_sbom, parse_sbom_str};
258pub use quality::{QualityGrade, QualityReport, QualityScorer, ScoringProfile};
259#[allow(deprecated)]
260pub use reports::{ReportFormat, ReportGenerator, StreamingReporter, WriterReporter};
261
262// TUI shared ViewModel exports for building custom TUI components
263pub use tui::{
264 CycleFilter, FilterState, ListNavigation, ListState, OverlayState, SearchState,
265 SearchStateCore, StatusMessage, ViewModelOverlayKind,
266};