refactor: Refactor configuration structs directly into the provider definition to simplify validation, structs, and future extensions

This commit is contained in:
2025-09-12 15:37:17 -06:00
parent cb1a97471f
commit 9d8fa17dde
13 changed files with 1535 additions and 347 deletions
+26 -32
View File
@@ -2,46 +2,36 @@
//!
//! 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::ProviderConfig;
use crate::providers::local::LocalProvider;
use anyhow::{Result, anyhow};
use serde::Deserialize;
use serde::{Deserialize, Serialize};
use std::fmt::{Display, Formatter};
use std::str::FromStr;
use thiserror::Error;
use validator::{Validate, ValidationErrors};
/// 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: &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<()> {
fn get_secret(&self, key: &str) -> Result<String>;
fn set_secret(&self, key: &str, value: &str) -> Result<()>;
fn update_secret(&self, _key: &str, _value: &str) -> Result<()> {
Err(anyhow!(
"update secret not supported for provider {}",
self.name()
))
}
fn delete_secret(&self, config: &ProviderConfig, key: &str) -> Result<()>;
fn list_secrets(&self, _config: &ProviderConfig) -> Result<Vec<String>> {
fn delete_secret(&self, key: &str) -> Result<()>;
fn list_secrets(&self) -> Result<Vec<String>> {
Err(anyhow!(
"list secrets is not supported for the provider {}",
self.name()
))
}
fn sync(&self, config: &mut ProviderConfig) -> Result<()>;
fn sync(&mut self) -> Result<()>;
}
/// Errors when parsing a provider identifier.
@@ -52,24 +42,28 @@ pub enum ParseProviderError {
}
/// Registry of built-in providers.
#[derive(Debug, Clone, Copy, Deserialize, Eq, PartialEq)]
#[derive(Debug, Clone, Deserialize, Serialize, Eq, PartialEq)]
#[serde(deny_unknown_fields, tag = "type", rename_all = "snake_case")]
//TODO test that this works with the AWS config
pub enum SupportedProvider {
Local(LocalProvider),
Local {
#[serde(flatten)]
provider_def: LocalProvider,
},
}
impl Validate for SupportedProvider {
fn validate(&self) -> Result<(), ValidationErrors> {
match self {
SupportedProvider::Local { provider_def } => provider_def.validate(),
}
}
}
impl Default for SupportedProvider {
fn default() -> Self {
SupportedProvider::Local(LocalProvider)
}
}
impl FromStr for SupportedProvider {
type Err = ParseProviderError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s.trim().to_lowercase().as_str() {
"local" => Ok(SupportedProvider::Local(LocalProvider)),
_ => Err(ParseProviderError::Unsupported(s.to_string())),
SupportedProvider::Local {
provider_def: LocalProvider::default(),
}
}
}
@@ -77,7 +71,7 @@ impl FromStr for SupportedProvider {
impl Display for SupportedProvider {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
SupportedProvider::Local(_) => write!(f, "local"),
SupportedProvider::Local { .. } => write!(f, "local"),
}
}
}