use jiff::Timestamp;
use uv_normalize::PackageName;
use uv_pep440::Version;
use uv_redacted::DisplaySafeUrl;
use uv_small_str::SmallString;
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Dependency {
name: PackageName,
version: Version,
}
impl Dependency {
pub fn new(name: PackageName, version: Version) -> Self {
Self { name, version }
}
pub fn name(&self) -> &PackageName {
&self.name
}
pub fn version(&self) -> &Version {
&self.version
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct VulnerabilityID(SmallString);
impl VulnerabilityID {
pub fn new(id: impl Into<SmallString>) -> Self {
Self(id.into())
}
pub fn as_str(&self) -> &str {
self.0.as_ref()
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum AdverseStatus {
Archived,
Quarantined,
Deprecated,
}
#[derive(Debug)]
pub struct Vulnerability {
pub dependency: Dependency,
pub id: VulnerabilityID,
pub summary: Option<String>,
pub description: Option<String>,
pub link: Option<DisplaySafeUrl>,
pub fix_versions: Vec<Version>,
pub aliases: Vec<VulnerabilityID>,
pub published: Option<Timestamp>,
pub modified: Option<Timestamp>,
}
impl Vulnerability {
pub fn new(
dependency: Dependency,
id: VulnerabilityID,
summary: Option<String>,
description: Option<String>,
link: Option<DisplaySafeUrl>,
fix_versions: Vec<Version>,
aliases: Vec<VulnerabilityID>,
published: Option<Timestamp>,
modified: Option<Timestamp>,
) -> Self {
let summary = summary.map(|summary| summary.trim().replace('\n', ""));
Self {
dependency,
id,
summary,
description,
link,
fix_versions,
aliases,
published,
modified,
}
}
fn ids(&self) -> impl Iterator<Item = &VulnerabilityID> {
std::iter::once(&self.id).chain(self.aliases.iter())
}
pub fn matches(&self, id: &VulnerabilityID) -> bool {
self.ids().any(|own_id| own_id == id)
}
pub fn best_id(&self) -> &VulnerabilityID {
self.ids()
.find(|id| {
id.as_str().starts_with("PYSEC-")
|| id.as_str().starts_with("GHSA-")
|| id.as_str().starts_with("CVE-")
})
.unwrap_or(&self.id)
}
}
#[derive(Debug)]
pub struct ProjectStatus {
pub dependency: Dependency,
pub status: AdverseStatus,
pub reason: Option<String>,
}
#[derive(Debug)]
pub enum Finding {
Vulnerability(Box<Vulnerability>),
ProjectStatus(ProjectStatus),
}