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 crate::cli::UI;
use anyhow::{bail, Result};
use std::path::Path;
use tracing::warn;

pub fn list(path: &Path, verbose: bool, ui: &UI) -> Result<()> {
    let repo = crate::ops::open_repo(path)?;
    let remotes = repo.remotes()?;

    for name in remotes.iter().flatten() {
        if verbose {
            if let Ok(remote) = repo.find_remote(name) {
                let url = remote.url().unwrap_or("");
                ui.list_item(format!("{}\t{} (fetch)", name, url));
                let push_url = remote.pushurl().unwrap_or(url);
                ui.list_item(format!("{}\t{} (push)", name, push_url));
            }
        } else {
            ui.list_item(name);
        }
    }

    Ok(())
}

pub fn add(path: &Path, name: &str, url: &str, ui: &UI) -> Result<()> {
    validate_remote_url(url)?;

    let repo = crate::ops::open_repo(path)?;
    repo.remote(name, url)?;
    ui.success(format!("Added remote '{}' -> {}", name, url));

    Ok(())
}

pub fn remove(path: &Path, name: &str, ui: &UI) -> Result<()> {
    let repo = crate::ops::open_repo(path)?;
    repo.remote_delete(name)?;
    ui.success(format!("Removed remote '{}'", name));
    Ok(())
}

pub fn set_url(path: &Path, name: &str, url: &str, ui: &UI) -> Result<()> {
    validate_remote_url(url)?;

    let repo = crate::ops::open_repo(path)?;
    repo.remote_set_url(name, url)?;
    ui.success(format!("Updated remote '{}' URL to {}", name, url));

    Ok(())
}

/// Validate remote URL for security.
fn validate_remote_url(url: &str) -> Result<()> {
    if url.starts_with("file://") {
        bail!("file:// protocol is blocked for security. Use a path or HTTPS URL instead.");
    }

    if url.starts_with("http://") {
        warn!("WARNING: HTTP remote URL detected. Consider using HTTPS for security.");
        eprintln!("WARNING: HTTP remote URL detected. Consider using HTTPS for security.");
    }

    Ok(())
}