use super::vulnerability::Severity;
#[allow(dead_code)]
#[derive(Debug, Clone)]
pub struct ResolutionEntry {
vulnerable_package: String,
current_version: String,
fixed_version: Option<String>,
severity: Severity,
vulnerability_id: String,
introduced_by: Vec<IntroducedBy>,
}
impl ResolutionEntry {
#[allow(dead_code)]
pub fn new(
vulnerable_package: String,
current_version: String,
fixed_version: Option<String>,
severity: Severity,
vulnerability_id: String,
introduced_by: Vec<IntroducedBy>,
) -> Self {
Self {
vulnerable_package,
current_version,
fixed_version,
severity,
vulnerability_id,
introduced_by,
}
}
#[allow(dead_code)]
pub fn vulnerable_package(&self) -> &str {
&self.vulnerable_package
}
#[allow(dead_code)]
pub fn current_version(&self) -> &str {
&self.current_version
}
#[allow(dead_code)]
pub fn fixed_version(&self) -> Option<&str> {
self.fixed_version.as_deref()
}
#[allow(dead_code)]
pub fn severity(&self) -> Severity {
self.severity
}
#[allow(dead_code)]
pub fn vulnerability_id(&self) -> &str {
&self.vulnerability_id
}
#[allow(dead_code)]
pub fn introduced_by(&self) -> &[IntroducedBy] {
&self.introduced_by
}
}
#[allow(dead_code)]
#[derive(Debug, Clone)]
pub struct IntroducedBy {
package_name: String,
version: String,
}
impl IntroducedBy {
#[allow(dead_code)]
pub fn new(package_name: String, version: String) -> Self {
Self {
package_name,
version,
}
}
#[allow(dead_code)]
pub fn package_name(&self) -> &str {
&self.package_name
}
#[allow(dead_code)]
pub fn version(&self) -> &str {
&self.version
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_introduced_by_new() {
let entry = IntroducedBy::new("requests".to_string(), "2.28.0".to_string());
assert_eq!(entry.package_name(), "requests");
assert_eq!(entry.version(), "2.28.0");
}
#[test]
fn test_resolution_entry_new() {
let introduced = vec![
IntroducedBy::new("requests".to_string(), "2.28.0".to_string()),
IntroducedBy::new("httpx".to_string(), "0.23.0".to_string()),
];
let entry = ResolutionEntry::new(
"urllib3".to_string(),
"1.26.5".to_string(),
Some("1.26.18".to_string()),
Severity::High,
"CVE-2023-43804".to_string(),
introduced,
);
assert_eq!(entry.vulnerable_package(), "urllib3");
assert_eq!(entry.current_version(), "1.26.5");
assert_eq!(entry.fixed_version(), Some("1.26.18"));
assert_eq!(entry.severity(), Severity::High);
assert_eq!(entry.vulnerability_id(), "CVE-2023-43804");
assert_eq!(entry.introduced_by().len(), 2);
assert_eq!(entry.introduced_by()[0].package_name(), "requests");
assert_eq!(entry.introduced_by()[1].package_name(), "httpx");
}
#[test]
fn test_resolution_entry_without_fixed_version() {
let entry = ResolutionEntry::new(
"vulnerable-pkg".to_string(),
"0.1.0".to_string(),
None,
Severity::Critical,
"CVE-2024-0001".to_string(),
vec![IntroducedBy::new(
"parent-pkg".to_string(),
"1.0.0".to_string(),
)],
);
assert_eq!(entry.fixed_version(), None);
assert_eq!(entry.severity(), Severity::Critical);
}
#[test]
fn test_resolution_entry_empty_introduced_by() {
let entry = ResolutionEntry::new(
"some-pkg".to_string(),
"1.0.0".to_string(),
Some("1.0.1".to_string()),
Severity::Medium,
"GHSA-xxxx-yyyy-zzzz".to_string(),
vec![],
);
assert!(entry.introduced_by().is_empty());
}
}