nabla_cli/
config.rs

1use anyhow::Result;
2use serde::Deserialize;
3
4#[cfg(feature = "private")]
5use doppler_rs::{apis::client::Client, apis::Error as DopplerError};
6
7#[derive(Debug, Clone, Deserialize, PartialEq)]
8pub enum DeploymentType {
9    OSS,
10    Private,
11}
12
13impl std::str::FromStr for DeploymentType {
14    type Err = anyhow::Error;
15
16    fn from_str(s: &str) -> Result<Self> {
17        match s.to_lowercase().as_str() {
18            "oss" => Ok(DeploymentType::OSS),
19            "private" => Ok(DeploymentType::Private),
20            _ => Err(anyhow::anyhow!("Invalid deployment type: {}", s)),
21        }
22    }
23}
24
25#[derive(Debug, Clone, Deserialize)]
26pub struct Config {
27    pub port: u16,
28    pub base_url: String,
29    pub fips_mode: bool,
30    pub fips_validation: bool,
31    pub deployment_type: DeploymentType,
32    pub license_signing_key: String,
33}
34
35impl Default for Config {
36    fn default() -> Self {
37        Self {
38            port: 8080,
39            base_url: "http://localhost:8080".to_string(),
40            fips_mode: false,
41            fips_validation: false,
42            deployment_type: DeploymentType::OSS,
43            license_signing_key: "t6eLp6y0Ly8BZJIVv_wK71WyBtJ1zY2Pxz2M_0z5t8Q".to_string(),
44        }
45    }
46}
47
48impl Config {
49    pub fn from_env() -> Result<Self> {
50        dotenvy::dotenv().ok();
51
52        let deployment_type = std::env::var("NABLA_DEPLOYMENT")
53            .unwrap_or_else(|_| "oss".to_string())
54            .parse()?;
55
56        let license_signing_key = Self::get_license_signing_key(&deployment_type)?;
57        
58        let config = Config {
59            port: std::env::var("PORT")
60                .unwrap_or_else(|_| "8080".to_string())
61                .parse()?,
62            base_url: std::env::var("BASE_URL")
63                .unwrap_or_else(|_| "http://localhost:8080".to_string()),
64            fips_mode: std::env::var("FIPS_MODE")
65                .unwrap_or_else(|_| "false".to_string())
66                .parse()
67                .unwrap_or(false),
68            fips_validation: std::env::var("FIPS_VALIDATION")
69                .unwrap_or_else(|_| "false".to_string())
70                .parse()
71                .unwrap_or(false),
72            deployment_type,
73            license_signing_key,
74        };
75
76        Ok(config)
77    }
78
79    fn get_license_signing_key(deployment_type: &DeploymentType) -> Result<String> {
80        match deployment_type {
81            DeploymentType::OSS => {
82                // Public key for OSS deployments
83                Ok("t6eLp6y0Ly8BZJIVv_wK71WyBtJ1zY2Pxz2M_0z5t8Q".to_string())
84            }
85            DeploymentType::Private => {
86                #[cfg(feature = "private")]
87                {
88                    // Try Doppler first for private deployments
89                    if let (Ok(project), Ok(config_name)) = (
90                        std::env::var("DOPPLER_PROJECT"),
91                        std::env::var("DOPPLER_CONFIG")
92                    ) {
93                        if let Ok(doppler_token) = std::env::var("DOPPLER_TOKEN") {
94                            let client = Client::new(&doppler_token);
95                            if let Ok(secret) = client.get_secret(&project, &config_name, "LICENSE_SIGNING_KEY") {
96                                return Ok(secret.value);
97                            }
98                        }
99                    }
100                }
101                
102                // Fallback to environment variable
103                std::env::var("LICENSE_SIGNING_KEY")
104                    .map_err(|_| anyhow::anyhow!("LICENSE_SIGNING_KEY env missing for private deployment"))
105            }
106        }
107    }
108}