use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum Ecosystem {
Npm,
Cargo,
PyPI,
Go,
}
impl Ecosystem {
pub fn deps_dev_system(self) -> &'static str {
match self {
Ecosystem::Npm => "npm",
Ecosystem::Cargo => "cargo",
Ecosystem::PyPI => "pypi",
Ecosystem::Go => "go",
}
}
pub fn label(self) -> &'static str {
match self {
Ecosystem::Npm => "npm",
Ecosystem::Cargo => "crates.io",
Ecosystem::PyPI => "PyPI",
Ecosystem::Go => "Go",
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct Dependency {
pub name: String,
pub requested: Option<String>,
pub ecosystem: Ecosystem,
pub direct: bool,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct Vuln {
pub id: String,
pub cvss: Option<f64>,
pub title: Option<String>,
}
impl Vuln {
pub fn severity(&self) -> Severity {
match self.cvss {
Some(s) if s >= 9.0 => Severity::Critical,
Some(s) if s >= 7.0 => Severity::High,
Some(s) if s >= 4.0 => Severity::Medium,
Some(_) => Severity::Low,
None => Severity::Medium,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub enum Severity {
Low,
Medium,
High,
Critical,
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct Facts {
pub analyzed_version: Option<String>,
pub latest_published: Option<DateTime<Utc>>,
pub releases_last_year: Option<u32>,
pub total_versions: Option<u32>,
pub deprecated: bool,
pub deprecated_reason: Option<String>,
pub archived: bool,
pub licenses: Vec<String>,
pub vulns: Vec<Vuln>,
pub repo: Option<String>,
pub stars: Option<u64>,
pub open_issues: Option<u64>,
pub scorecard_maintained: Option<f64>,
pub scorecard_overall: Option<f64>,
pub top_contributor_share: Option<f64>,
#[serde(default)]
pub maintainers: Vec<String>,
#[serde(default)]
pub has_install_script: bool,
}
impl Facts {
pub fn is_unresolved(&self) -> bool {
self.total_versions.is_none() && self.latest_published.is_none()
}
}