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::plugins::builtin;
use crate::plugins::external::ExternalPlugin;
use crate::plugins::registry::PluginRegistry;
use crate::plugins::traits::{ScanPhase, SecurityPlugin};
use anyhow::Result;
use std::sync::Arc;

pub fn load_builtin_plugins(registry: &mut PluginRegistry) {
    registry.register(Arc::new(builtin::patterns::PatternScanner::new()));
    registry.register(Arc::new(builtin::secrets::SecretsScanner::new()));
    registry.register(Arc::new(builtin::entropy::EntropyScanner::new()));
    registry.register(Arc::new(builtin::binary::BinaryScanner::new()));
    registry.register(Arc::new(builtin::git_internals::GitInternalsScanner::new()));
    registry.register(Arc::new(builtin::cicd::CicdScanner::new()));
    registry.register(Arc::new(builtin::supply_chain::SupplyChainScanner::new()));
    registry.register(Arc::new(builtin::container::ContainerScanner::new()));
    registry.register(Arc::new(builtin::iac::IacScanner::new()));
    registry.register(Arc::new(
        builtin::deserialization::DeserializationScanner::new(),
    ));
    registry.register(Arc::new(
        builtin::dangerous_files::DangerousFilesScanner::new(),
    ));
    registry.register(Arc::new(builtin::encoding::EncodingScanner::new()));
}

pub async fn load_external_plugins(registry: &mut PluginRegistry) -> Result<usize> {
    let config_dir = dirs::config_dir()
        .ok_or_else(|| anyhow::anyhow!("Could not determine config directory"))?;

    let plugins_dir = config_dir.join("securegit").join("plugins");

    if !plugins_dir.exists() {
        std::fs::create_dir_all(&plugins_dir)?;
        return Ok(0);
    }

    let mut loaded_count = 0;

    for entry in std::fs::read_dir(&plugins_dir)? {
        let entry = entry?;
        let path = entry.path();

        if !path.is_file() {
            continue;
        }

        #[cfg(unix)]
        {
            use std::os::unix::fs::PermissionsExt;
            let metadata = std::fs::metadata(&path)?;
            if metadata.permissions().mode() & 0o111 == 0 {
                continue;
            }
        }

        if let Some(name) = path.file_name().and_then(|n| n.to_str()) {
            let mut plugin = ExternalPlugin::new(
                name.to_string(),
                path.clone(),
                format!("External plugin: {}", name),
                ScanPhase::PostExtract,
            );

            if plugin.initialize().await.is_ok() {
                registry.register(Arc::new(plugin));
                loaded_count += 1;
            }
        }
    }

    Ok(loaded_count)
}