Skip to main content

zoi_resolver/
mini_resolve.rs

1use anyhow::{Result, anyhow};
2use colored::*;
3use serde::{Deserialize, Serialize};
4use std::collections::HashMap;
5pub use zoi_core::types::MiniVulnerability;
6
7fn default_revision() -> String {
8    "1".to_string()
9}
10
11#[derive(Debug, Serialize, Deserialize, Clone)]
12pub struct MiniPackageIndex {
13    pub repo: String,
14    pub repo_type: String,
15    pub version: String,
16    #[serde(default = "default_revision")]
17    pub revision: String,
18    pub description: String,
19    #[serde(default, deserialize_with = "deserialize_sub_packages")]
20    pub sub_packages: Option<Vec<String>>,
21    pub vuln: Option<Vec<MiniVulnerability>>,
22}
23
24fn deserialize_sub_packages<'de, D>(deserializer: D) -> Result<Option<Vec<String>>, D::Error>
25where
26    D: serde::Deserializer<'de>,
27{
28    let v: serde_json::Value = serde::Deserialize::deserialize(deserializer)?;
29    if v.is_array() {
30        Ok(serde_json::from_value(v).ok())
31    } else {
32        Ok(None)
33    }
34}
35
36#[derive(Debug, Serialize, Deserialize, Clone)]
37pub struct MiniRegistryIndex {
38    pub packages: HashMap<String, MiniPackageIndex>,
39}
40
41pub fn fetch_registry_index() -> Result<MiniRegistryIndex> {
42    let url = "https://gitlab.com/zillowe/zillwen/zusty/zoidberg/-/raw/main/packages.json";
43    let client = zoi_core::utils::get_http_client()?;
44    let response = client.get(url).send()?;
45    if !response.status().is_success() {
46        return Err(anyhow!(
47            "Failed to fetch packages.json from Zoidberg registry: {}",
48            response.status()
49        ));
50    }
51    let index: MiniRegistryIndex = response.json()?;
52    Ok(index)
53}
54
55pub fn fetch_registry_config() -> Result<zoi_core::types::RepoConfig> {
56    let url = "https://gitlab.com/zillowe/zillwen/zusty/zoidberg/-/raw/main/repo.yaml";
57    let client = zoi_core::utils::get_http_client()?;
58    let response = client.get(url).send()?;
59    if !response.status().is_success() {
60        return Err(anyhow!(
61            "Failed to fetch repo.yaml from Zoidberg registry: {}",
62            response.status()
63        ));
64    }
65    let content = response.text()?;
66    let config: zoi_core::types::RepoConfig = serde_yaml::from_str(&content)?;
67    Ok(config)
68}
69
70pub fn get_package_lua_url(repo: &str, name: &str) -> String {
71    format!(
72        "https://gitlab.com/zillowe/zillwen/zusty/zoidberg/-/raw/main/{}/{}/{}.pkg.lua",
73        repo, name, name
74    )
75}
76
77pub fn check_vulnerabilities(
78    pkg_name: &str,
79    pkg_index: &MiniPackageIndex,
80    version: &str,
81) -> Result<bool> {
82    let Some(vulns) = &pkg_index.vuln else {
83        return Ok(true);
84    };
85
86    let target_version = semver::Version::parse(version.trim_start_matches('v'))
87        .map_err(|e| anyhow!("Failed to parse version {}: {}", version, e))?;
88
89    let mut affected = Vec::new();
90
91    for vuln in vulns {
92        if let Ok(req) = semver::VersionReq::parse(&vuln.affected_range)
93            && req.matches(&target_version)
94        {
95            affected.push(vuln);
96        }
97    }
98
99    if affected.is_empty() {
100        return Ok(true);
101    }
102
103    println!("\n{}", "SECURITY WARNING".red().bold());
104    for vuln in affected {
105        println!(
106            "Package {} v{} is known to be vulnerable:",
107            pkg_name.cyan().bold(),
108            version.red()
109        );
110        println!(
111            "[{}] {} (Severity: {})",
112            vuln.id.dimmed(),
113            vuln.summary,
114            vuln.severity.to_uppercase()
115        );
116        if let Some(fixed) = &vuln.fixed_in {
117            println!("Fixed in version: {}", fixed.green());
118        }
119        println!();
120    }
121
122    Ok(zoi_core::utils::ask_for_confirmation(
123        "Do you want to continue with the installation anyway?",
124        false,
125    ))
126}