feat: created initial parity gman generalization for vault provider

This commit is contained in:
2026-06-02 13:59:32 -06:00
parent 695a684b8d
commit 156de15a33
3 changed files with 51 additions and 19 deletions
+1 -1
View File
@@ -640,7 +640,7 @@ pub async fn create_config_file(config_path: &Path) -> Result<()> {
let mut config = json!({}); let mut config = json!({});
let (model, clients_config) = create_client_config(client, &vault).await?; let (model, clients_config) = create_client_config(client, &vault).await?;
config["model"] = model.into(); config["model"] = model.into();
config["vault_password_file"] = vault.password_file()?.display().to_string().into(); config["vault_password_file"] = vault.local_password_file()?.display().to_string().into();
config["stream"] = json!(true); config["stream"] = json!(true);
config["save"] = json!(true); config["save"] = json!(true);
config["keybindings"] = json!("vi"); config["keybindings"] = json!("vi");
+40 -15
View File
@@ -7,9 +7,10 @@ pub use utils::interpolate_secrets;
use crate::cli::Cli; use crate::cli::Cli;
use crate::config::AppConfig; use crate::config::AppConfig;
use crate::vault::utils::ensure_password_file_initialized; use crate::vault::utils::ensure_password_file_initialized;
use anyhow::{Context, Result}; use anyhow::{Context, Result, anyhow};
use fancy_regex::Regex; use fancy_regex::Regex;
use gman::providers::SecretProvider; use gman::providers::SecretProvider;
use gman::providers::SupportedProvider;
use gman::providers::local::LocalProvider; use gman::providers::local::LocalProvider;
use inquire::{Password, PasswordDisplayMode, required}; use inquire::{Password, PasswordDisplayMode, required};
use std::sync::{Arc, LazyLock}; use std::sync::{Arc, LazyLock};
@@ -19,7 +20,7 @@ pub static SECRET_RE: LazyLock<Regex> = LazyLock::new(|| Regex::new(r"\{\{(.+)}}
#[derive(Debug, Default, Clone)] #[derive(Debug, Default, Clone)]
pub struct Vault { pub struct Vault {
local_provider: LocalProvider, pub(crate) provider: SupportedProvider,
} }
pub type GlobalVault = Arc<Vault>; pub type GlobalVault = Arc<Vault>;
@@ -33,7 +34,11 @@ impl Vault {
..LocalProvider::default() ..LocalProvider::default()
}; };
Self { local_provider } Self {
provider: SupportedProvider::Local {
provider_def: local_provider,
},
}
} }
pub fn init(config: &AppConfig) -> Self { pub fn init(config: &AppConfig) -> Self {
@@ -47,14 +52,34 @@ impl Vault {
ensure_password_file_initialized(&mut local_provider) ensure_password_file_initialized(&mut local_provider)
.expect("Failed to initialize password file"); .expect("Failed to initialize password file");
Self { local_provider } Self {
provider: SupportedProvider::Local {
provider_def: local_provider,
},
}
} }
pub fn password_file(&self) -> Result<PathBuf> { pub fn local_password_file(&self) -> Result<PathBuf> {
self.local_provider match &self.provider {
.password_file SupportedProvider::Local { provider_def } => provider_def
.clone() .password_file
.with_context(|| "A password file is required for the local provider") .clone()
.with_context(|| "A password file is required for the local provider"),
_ => Err(anyhow!(
"password_file is only available for the local provider"
)),
}
}
fn provider_ref(&self) -> &dyn SecretProvider {
match &self.provider {
SupportedProvider::Local { provider_def } => provider_def,
SupportedProvider::AwsSecretsManager { provider_def } => provider_def,
SupportedProvider::GcpSecretManager { provider_def } => provider_def,
SupportedProvider::AzureKeyVault { provider_def } => provider_def,
SupportedProvider::Gopass { provider_def } => provider_def,
SupportedProvider::OnePassword { provider_def } => provider_def,
}
} }
pub fn add_secret(&self, secret_name: &str) -> Result<()> { pub fn add_secret(&self, secret_name: &str) -> Result<()> {
@@ -66,7 +91,7 @@ impl Vault {
let h = Handle::current(); let h = Handle::current();
tokio::task::block_in_place(|| { tokio::task::block_in_place(|| {
h.block_on(self.local_provider.set_secret(secret_name, &secret_value)) h.block_on(self.provider_ref().set_secret(secret_name, &secret_value))
})?; })?;
println!("✓ Secret '{secret_name}' added to the vault."); println!("✓ Secret '{secret_name}' added to the vault.");
@@ -76,7 +101,7 @@ impl Vault {
pub fn get_secret(&self, secret_name: &str, display_output: bool) -> Result<String> { pub fn get_secret(&self, secret_name: &str, display_output: bool) -> Result<String> {
let h = Handle::current(); let h = Handle::current();
let secret = tokio::task::block_in_place(|| { let secret = tokio::task::block_in_place(|| {
h.block_on(self.local_provider.get_secret(secret_name)) h.block_on(self.provider_ref().get_secret(secret_name))
})?; })?;
if display_output { if display_output {
@@ -95,7 +120,7 @@ impl Vault {
let h = Handle::current(); let h = Handle::current();
tokio::task::block_in_place(|| { tokio::task::block_in_place(|| {
h.block_on( h.block_on(
self.local_provider self.provider_ref()
.update_secret(secret_name, &secret_value), .update_secret(secret_name, &secret_value),
) )
})?; })?;
@@ -106,7 +131,7 @@ impl Vault {
pub fn delete_secret(&self, secret_name: &str) -> Result<()> { pub fn delete_secret(&self, secret_name: &str) -> Result<()> {
let h = Handle::current(); let h = Handle::current();
tokio::task::block_in_place(|| h.block_on(self.local_provider.delete_secret(secret_name)))?; tokio::task::block_in_place(|| h.block_on(self.provider_ref().delete_secret(secret_name)))?;
println!("✓ Secret '{secret_name}' deleted from the vault."); println!("✓ Secret '{secret_name}' deleted from the vault.");
Ok(()) Ok(())
@@ -115,7 +140,7 @@ impl Vault {
pub fn list_secrets(&self, display_output: bool) -> Result<Vec<String>> { pub fn list_secrets(&self, display_output: bool) -> Result<Vec<String>> {
let h = Handle::current(); let h = Handle::current();
let secrets = let secrets =
tokio::task::block_in_place(|| h.block_on(self.local_provider.list_secrets()))?; tokio::task::block_in_place(|| h.block_on(self.provider_ref().list_secrets()))?;
if display_output { if display_output {
if secrets.is_empty() { if secrets.is_empty() {
@@ -193,6 +218,6 @@ mod tests {
#[test] #[test]
fn vault_default_creates_instance() { fn vault_default_creates_instance() {
let vault = Vault::default(); let vault = Vault::default();
assert!(vault.password_file().is_err()); assert!(vault.local_password_file().is_err());
} }
} }
+10 -3
View File
@@ -2,6 +2,7 @@ use crate::config::ensure_parent_exists;
use crate::vault::{SECRET_RE, Vault}; use crate::vault::{SECRET_RE, Vault};
use anyhow::Result; use anyhow::Result;
use anyhow::anyhow; use anyhow::anyhow;
use gman::providers::SupportedProvider;
use gman::providers::local::LocalProvider; use gman::providers::local::LocalProvider;
use indoc::formatdoc; use indoc::formatdoc;
use inquire::validator::Validation; use inquire::validator::Validation;
@@ -34,8 +35,14 @@ pub fn ensure_password_file_initialized(local_provider: &mut LocalProvider) -> R
} }
pub fn create_vault_password_file(vault: &mut Vault) -> Result<()> { pub fn create_vault_password_file(vault: &mut Vault) -> Result<()> {
let vault_password_file = vault let SupportedProvider::Local {
.local_provider provider_def: local_provider,
} = &mut vault.provider
else {
return Ok(());
};
let vault_password_file = local_provider
.password_file .password_file
.clone() .clone()
.ok_or_else(|| anyhow!("Password file is not configured"))?; .ok_or_else(|| anyhow!("Password file is not configured"))?;
@@ -148,7 +155,7 @@ pub fn create_vault_password_file(vault: &mut Vault) -> Result<()> {
match password { match password {
Ok(pw) => { Ok(pw) => {
std::fs::write(&password_file, pw.as_bytes())?; std::fs::write(&password_file, pw.as_bytes())?;
vault.local_provider.password_file = Some(password_file); local_provider.password_file = Some(password_file);
println!( println!(
"✓ Password file '{}' created.", "✓ Password file '{}' created.",
vault_password_file.display() vault_password_file.display()