securegit 0.8.5

Zero-trust git replacement with 12 built-in security scanners, LLM redteam bridge, universal undo, durable backups, and a 50-tool MCP server
Documentation
use serde::{Deserialize, Deserializer, Serialize};

/// Model metadata from the HuggingFace Hub API.
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct HfModelInfo {
    pub id: String,
    pub model_id: Option<String>,
    #[serde(default)]
    pub sha: Option<String>,
    #[serde(default)]
    pub pipeline_tag: Option<String>,
    #[serde(default)]
    pub library_name: Option<String>,
    #[serde(default)]
    pub tags: Vec<String>,
    #[serde(default)]
    pub downloads: u64,
    #[serde(default)]
    pub likes: u64,
    #[serde(default)]
    pub private: bool,
    #[serde(default, deserialize_with = "deserialize_gated")]
    pub gated: Option<String>,
    #[serde(default)]
    pub last_modified: Option<String>,
    #[serde(default)]
    pub card_data: Option<serde_json::Value>,
    #[serde(default)]
    pub siblings: Option<Vec<HfRepoFile>>,
}

/// A single file entry in a HuggingFace repository.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct HfRepoFile {
    #[serde(rename = "rfilename")]
    pub filename: String,
    #[serde(default)]
    pub size: Option<u64>,
    #[serde(default)]
    pub lfs: Option<HfLfsInfo>,
}

/// LFS pointer metadata for a file in a HuggingFace repository.
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct HfLfsInfo {
    pub size: u64,
    pub oid: String,
    #[serde(default)]
    pub pointer_size: Option<u64>,
}

/// File entry returned by the HuggingFace tree endpoint.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct HfTreeEntry {
    #[serde(rename = "type")]
    pub entry_type: String,
    pub oid: String,
    pub size: u64,
    pub path: String,
    #[serde(default)]
    pub lfs: Option<HfLfsInfo>,
}

/// Result of an armyknife-redteam model security scan.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ModelScanResult {
    pub model_id: String,
    pub total_probes: u64,
    pub findings_count: u64,
    pub max_severity: String,
    pub findings: Vec<ModelFinding>,
}

/// Individual finding from a model security scan.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ModelFinding {
    pub id: String,
    pub severity: String,
    pub category: String,
    pub title: String,
    pub description: String,
}

/// GitLab CI/CD pipeline status.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PipelineStatus {
    pub id: u64,
    pub status: String,
    pub r#ref: String,
    pub web_url: String,
    #[serde(default)]
    pub created_at: Option<String>,
    #[serde(default)]
    pub updated_at: Option<String>,
    #[serde(default)]
    pub finished_at: Option<String>,
}

/// HF API returns `gated` as `false` (bool) or `"auto"`/`"manual"` (string).
fn deserialize_gated<'de, D>(deserializer: D) -> Result<Option<String>, D::Error>
where
    D: Deserializer<'de>,
{
    let value: serde_json::Value = Deserialize::deserialize(deserializer)?;
    match value {
        serde_json::Value::String(s) => Ok(Some(s)),
        serde_json::Value::Bool(false) | serde_json::Value::Null => Ok(None),
        serde_json::Value::Bool(true) => Ok(Some("true".to_string())),
        _ => Ok(None),
    }
}