feat: created initial parity gman generalization for vault provider
This commit is contained in:
+1
-1
@@ -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
@@ -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
@@ -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()
|
||||||
|
|||||||
Reference in New Issue
Block a user