diff --git a/lib/bolt/cli/src/commands/config.rs b/lib/bolt/cli/src/commands/config.rs index c862ce6234..b2a99354ef 100644 --- a/lib/bolt/cli/src/commands/config.rs +++ b/lib/bolt/cli/src/commands/config.rs @@ -143,9 +143,8 @@ impl SubCommand { // Load namespace config let ns_config = if fs::metadata(&namespace_path).await.is_ok() { - // TODO (RVT-3747): Parse as plain toml let ns_config = - ProjectContextData::read_ns(project_root.as_path(), &ns_id).await; + ProjectContextData::read_partial_ns(project_root.as_path(), &ns_id).await; // Try to read op paths from ns config if let Some(_1password) = &ns_config.secrets._1password { @@ -187,14 +186,17 @@ impl SubCommand { }; // Determine local secrets path - let secrets_path = - ProjectContextData::get_secrets_path(ns_config.as_ref(), &project_root, &ns_id); + let secrets_path = ProjectContextData::get_secrets_path( + ns_config.as_ref().map(|ns| &ns.secrets), + &project_root, + &ns_id, + ); // Load secrets let secrets = if fs::metadata(&secrets_path).await.is_ok() { Some( ProjectContextData::read_secrets( - ns_config.as_ref(), + ns_config.as_ref().map(|ns| &ns.secrets), project_root.as_path(), &ns_id, ) @@ -429,7 +431,8 @@ impl SubCommand { .context("failed to read namespace config")?; let local_secrets_str = fs::read_to_string(&secrets_path).await?; let secrets = - ProjectContextData::read_secrets(Some(ctx.ns()), ctx.path(), ns_id).await; + ProjectContextData::read_secrets(Some(&ctx.ns().secrets), ctx.path(), ns_id) + .await; let ns_patches = json_patch::diff(&op_namespace, &namespace); if !ns_patches.is_empty() { diff --git a/lib/bolt/config/src/ns.rs b/lib/bolt/config/src/ns.rs index 541ffbe23a..7fb54d2e29 100644 --- a/lib/bolt/config/src/ns.rs +++ b/lib/bolt/config/src/ns.rs @@ -766,3 +766,10 @@ fn default_tunnel_port() -> u16 { fn default_job_server_provision_margin() -> u32 { 2 } + +// Used for parsing from 1password +#[derive(Deserialize, Debug)] +pub struct PartialNamespace { + #[serde(default)] + pub secrets: Secrets, +} diff --git a/lib/bolt/core/src/context/project.rs b/lib/bolt/core/src/context/project.rs index ddd6dfbd76..80d8ea8791 100644 --- a/lib/bolt/core/src/context/project.rs +++ b/lib/bolt/core/src/context/project.rs @@ -103,9 +103,12 @@ impl ProjectContextData { let ns_config = ProjectContextData::read_ns(project_root.as_path(), &ns_id).await; // Load secrets - let secrets = - ProjectContextData::read_secrets(Some(&ns_config), project_root.as_path(), &ns_id) - .await; + let secrets = ProjectContextData::read_secrets( + Some(&ns_config.secrets), + project_root.as_path(), + &ns_id, + ) + .await; let mut svc_ctxs_map = HashMap::new(); @@ -358,14 +361,15 @@ impl ProjectContextData { } pub fn get_secrets_path( - ns: Option<&config::ns::Namespace>, + ns_secrets: Option<&config::ns::Secrets>, project_path: &Path, ns_id: &str, ) -> PathBuf { - ns.and_then(|ns| ns.secrets.path.as_ref()).map_or_else( - || project_path.join("secrets").join(format!("{}.toml", ns_id)), - |v| v.clone(), - ) + if let Some(path) = ns_secrets.and_then(|s| s.path.as_ref()) { + path.clone() + } else { + project_path.join("secrets").join(format!("{}.toml", ns_id)) + } } } @@ -481,7 +485,7 @@ impl ProjectContextData { } } - pub async fn read_ns(project_path: &Path, ns_id: &str) -> config::ns::Namespace { + async fn read_ns(project_path: &Path, ns_id: &str) -> config::ns::Namespace { let path = project_path .join("namespaces") .join(format!("{ns_id}.toml")); @@ -496,7 +500,7 @@ impl ProjectContextData { "failed to parse namespace config ({:?}): {}\n\n{}\n", &span, err.message(), - &config_str[span.clone()] + &config_str[span.clone()], ); } else { panic!("failed to parse namespace config: {}", err.message()); @@ -515,12 +519,40 @@ impl ProjectContextData { config } + pub async fn read_partial_ns(project_path: &Path, ns_id: &str) -> config::ns::PartialNamespace { + let path = project_path + .join("namespaces") + .join(format!("{ns_id}.toml")); + let config_str = fs::read_to_string(&path) + .await + .unwrap_or_else(|_| panic!("failed to read namespace config: {}", path.display())); + + match toml::from_str::(&config_str) { + Result::Ok(x) => x, + Result::Err(err) => { + if let Some(span) = err.span().filter(|span| span.start != span.end) { + panic!( + "failed to partially parse namespace config ({:?}): {}\n\n{}\n", + &span, + err.message(), + &config_str[span.clone()], + ); + } else { + panic!( + "failed to partially parse namespace config: {}", + err.message() + ); + } + } + } + } + pub async fn read_secrets( - ns: Option<&config::ns::Namespace>, + ns_secrets: Option<&config::ns::Secrets>, project_path: &Path, ns_id: &str, ) -> serde_json::Value { - let secrets_path = ProjectContextData::get_secrets_path(ns, project_path, ns_id); + let secrets_path = ProjectContextData::get_secrets_path(ns_secrets, project_path, ns_id); // Read the config let config_str = fs::read_to_string(&secrets_path) .await @@ -692,7 +724,7 @@ impl ProjectContextData { } pub fn secrets_path(&self) -> PathBuf { - ProjectContextData::get_secrets_path(Some(self.ns()), self.path(), self.ns_id()) + ProjectContextData::get_secrets_path(Some(&self.ns().secrets), self.path(), self.ns_id()) } pub fn gen_path(&self) -> PathBuf { diff --git a/lib/bolt/core/src/tasks/check.rs b/lib/bolt/core/src/tasks/check.rs index 1517d5688d..436e0b346f 100644 --- a/lib/bolt/core/src/tasks/check.rs +++ b/lib/bolt/core/src/tasks/check.rs @@ -236,7 +236,8 @@ pub async fn check_config_sync(ctx: &ProjectContext) { let local_namespace_str = fs::read_to_string(&namespace_path).await.unwrap(); let namespace = toml::from_str::(&local_namespace_str) .expect("failed to read namespace config"); - let secrets = ProjectContextData::read_secrets(Some(ctx.ns()), ctx.path(), &ns_id).await; + let secrets = + ProjectContextData::read_secrets(Some(&ctx.ns().secrets), ctx.path(), &ns_id).await; let ns_patches = json_patch::diff(&op_namespace, &namespace); if !ns_patches.is_empty() {