Added support for multiple providers and wrote additional regression tests. Also fixed a bug with local synchronization with remote Git repositories when the CLI was just installed but the remote repo already exists with stuff in it.

This commit is contained in:
2025-09-11 15:07:16 -06:00
parent 0f5c28a040
commit a8d959dac3
19 changed files with 1155 additions and 239 deletions
+29 -6
View File
@@ -1,19 +1,34 @@
//! Secret provider trait and registry.
//!
//! Implementations provide storage/backends for secrets and a common
//! interface used by the CLI.
//!
//! Selecting a provider from a string:
//! ```
//! use std::str::FromStr;
//! use gman::providers::SupportedProvider;
//!
//! let p = SupportedProvider::from_str("local").unwrap();
//! assert_eq!(p.to_string(), "local");
//! ```
mod git_sync;
pub mod local;
use crate::config::Config;
use crate::config::ProviderConfig;
use crate::providers::local::LocalProvider;
use anyhow::{Result, anyhow};
use anyhow::{anyhow, Result};
use serde::Deserialize;
use std::fmt::{Display, Formatter};
use std::str::FromStr;
use thiserror::Error;
/// A secret storage backend capable of CRUD and sync, with optional
/// update and listing
pub trait SecretProvider {
fn name(&self) -> &'static str;
fn get_secret(&self, config: &Config, key: &str) -> Result<String>;
fn set_secret(&self, config: &Config, key: &str, value: &str) -> Result<()>;
fn update_secret(&self, _config: &Config, _key: &str, _value: &str) -> Result<()> {
fn get_secret(&self, config: &ProviderConfig, key: &str) -> Result<String>;
fn set_secret(&self, config: &ProviderConfig, key: &str, value: &str) -> Result<()>;
fn update_secret(&self, _config: &ProviderConfig, _key: &str, _value: &str) -> Result<()> {
Err(anyhow!(
"update secret not supported for provider {}",
self.name()
@@ -26,20 +41,28 @@ pub trait SecretProvider {
self.name()
))
}
fn sync(&self, config: &mut Config) -> Result<()>;
fn sync(&self, config: &mut ProviderConfig) -> Result<()>;
}
/// Errors when parsing a provider identifier.
#[derive(Debug, Error)]
pub enum ParseProviderError {
#[error("unsupported provider '{0}'")]
Unsupported(String),
}
/// Registry of built-in providers.
#[derive(Debug, Clone, Copy, Deserialize, Eq, PartialEq)]
pub enum SupportedProvider {
Local(LocalProvider),
}
impl Default for SupportedProvider {
fn default() -> Self {
SupportedProvider::Local(LocalProvider)
}
}
impl FromStr for SupportedProvider {
type Err = ParseProviderError;