envseal 0.3.12

Write-only secret vault with process-level access control — post-agent secret management
Documentation
//! Integration contracts and registry.
//!
//! This module defines stable extension points so new integrations
//! (OAuth providers, cloud secret backends, CI systems, etc.) can be
//! added without rewiring CLI/MCP/Desktop layers.

use std::collections::BTreeMap;

/// Built-in integrations shipped with envseal.
pub mod builtin;

/// Lifecycle phase of an integration.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum IntegrationStage {
    /// Experimental, disabled by default.
    Experimental,
    /// Available but not yet considered stable API.
    Beta,
    /// Stable and intended for broad use.
    Stable,
    /// Deprecated and pending removal.
    Deprecated,
}

/// Capability surface advertised by an integration.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
#[allow(clippy::struct_excessive_bools)]
pub struct IntegrationCapabilities {
    /// Supports OAuth-style user authorization flows.
    pub oauth: bool,
    /// Supports importing secrets from external source.
    pub import: bool,
    /// Supports exporting secrets to external source.
    pub export: bool,
    /// Supports runtime token refresh.
    pub refresh_tokens: bool,
}

/// Stable contract every integration must implement.
pub trait IntegrationProvider: Send + Sync + 'static {
    /// Stable machine name (e.g. `github`, `aws-secrets-manager`).
    fn id(&self) -> &'static str;
    /// Human-readable display name.
    fn display_name(&self) -> &'static str;
    /// Current lifecycle stage.
    fn stage(&self) -> IntegrationStage;
    /// Capability flags.
    fn capabilities(&self) -> IntegrationCapabilities;
}

/// Runtime registry of available integrations.
#[derive(Default)]
pub struct IntegrationRegistry {
    providers: BTreeMap<&'static str, Box<dyn IntegrationProvider>>,
}

impl IntegrationRegistry {
    /// Create an empty registry.
    pub fn new() -> Self {
        Self::default()
    }

    /// Register a provider by its stable id.
    pub fn register<P: IntegrationProvider>(&mut self, provider: P) {
        self.providers.insert(provider.id(), Box::new(provider));
    }

    /// Whether a provider id exists.
    pub fn has(&self, id: &str) -> bool {
        self.providers.contains_key(id)
    }

    /// Return all provider ids in deterministic order.
    pub fn ids(&self) -> Vec<&'static str> {
        self.providers.keys().copied().collect()
    }
}

/// Build the canonical integration registry for this build.
///
/// New integrations should be added by implementing `IntegrationProvider`
/// in their own module and registering in `builtin::register_all`.
pub fn default_registry() -> IntegrationRegistry {
    let mut registry = IntegrationRegistry::new();
    builtin::register_all(&mut registry);
    registry
}