lmrc-cli 0.3.16

CLI tool for scaffolding LMRC Stack infrastructure projects
Documentation
//! Vault service layer - business logic for secrets management

use super::models::*;
use crate::error::AppError;
use lmrc_vault::{VaultClient, VaultConfig};
use std::collections::HashMap;

pub struct VaultService {
    client: VaultClient,
}

impl VaultService {
    pub fn new(vault_addr: String, vault_token: String) -> Result<Self, AppError> {
        let config = VaultConfig {
            address: vault_addr,
            token: vault_token,
        };

        let client = VaultClient::new(config)
            .map_err(|e| AppError::External(format!("Vault client error: {}", e)))?;

        Ok(Self { client })
    }

    /// Read a secret from Vault
    pub async fn read_secret(&self, path: &str) -> Result<SecretResponse, AppError> {
        let secret = self.client
            .read_secret(path)
            .await
            .map_err(|e| AppError::External(format!("Vault read error: {}", e)))?;

        Ok(SecretResponse {
            path: path.to_string(),
            data: secret.data,
            version: secret.metadata.as_ref().and_then(|m| m.version),
            created_at: secret.metadata.as_ref().and_then(|m| m.created_time),
        })
    }

    /// Write a secret to Vault
    pub async fn write_secret(&self, path: &str, data: HashMap<String, String>) -> Result<SecretResponse, AppError> {
        self.client
            .write_secret(path, data.clone())
            .await
            .map_err(|e| AppError::External(format!("Vault write error: {}", e)))?;

        // Return the written secret
        Ok(SecretResponse {
            path: path.to_string(),
            data,
            version: Some(1),
            created_at: Some(chrono::Utc::now()),
        })
    }

    /// Delete a secret from Vault
    pub async fn delete_secret(&self, path: &str) -> Result<(), AppError> {
        self.client
            .delete_secret(path)
            .await
            .map_err(|e| AppError::External(format!("Vault delete error: {}", e)))?;

        Ok(())
    }

    /// Create a new Vault token for service authentication
    pub async fn create_token(&self, policies: Vec<String>, ttl: Option<String>) -> Result<TokenResponse, AppError> {
        let token_request = lmrc_vault::CreateTokenRequest {
            policies: policies.clone(),
            ttl,
            renewable: Some(true),
            display_name: Some("infra-api-service-token".to_string()),
        };

        let token_response = self.client
            .create_token(token_request)
            .await
            .map_err(|e| AppError::External(format!("Vault token creation error: {}", e)))?;

        Ok(TokenResponse {
            token: token_response.client_token,
            accessor: token_response.accessor,
            policies,
            ttl: token_response.lease_duration,
            renewable: token_response.renewable,
        })
    }
}