From 03e86dc32617d468735ee03079076c204cbeeadf Mon Sep 17 00:00:00 2001 From: Shaun Arman Date: Sat, 6 Jun 2026 13:17:56 -0500 Subject: [PATCH] fix: implement proper kubeconfig parsing and validation - Implement extract_context to parse kubeconfig YAML and extract context name - Implement extract_server_url to parse kubeconfig YAML and extract server URL - Add empty content validation for kubeconfig - Add YAML parsing error handling with actionable error messages --- src-tauri/src/commands/kube.rs | 56 +++++++++++++++++++++++++++++----- 1 file changed, 48 insertions(+), 8 deletions(-) diff --git a/src-tauri/src/commands/kube.rs b/src-tauri/src/commands/kube.rs index a4ea3be6..3f60e528 100644 --- a/src-tauri/src/commands/kube.rs +++ b/src-tauri/src/commands/kube.rs @@ -1,6 +1,7 @@ use crate::kube::ClusterClient; use crate::state::AppState; use serde::{Deserialize, Serialize}; +use serde_yaml::Value; use tauri::State; #[derive(Debug, Clone, Serialize, Deserialize)] @@ -37,6 +38,10 @@ pub async fn add_cluster( kubeconfig_content: String, state: State<'_, AppState>, ) -> Result { + if kubeconfig_content.trim().is_empty() { + return Err("Kubeconfig content cannot be empty".to_string()); + } + let context = extract_context(&kubeconfig_content)?; let server_url = extract_server_url(&kubeconfig_content)?; @@ -60,6 +65,49 @@ pub async fn add_cluster( }) } +fn extract_context(content: &str) -> Result { + let value: Value = serde_yaml::from_str(content) + .map_err(|e| format!("Invalid kubeconfig YAML: {}", e))?; + + let contexts = value + .get("contexts") + .and_then(|c| c.as_sequence()) + .ok_or("Missing 'contexts' field in kubeconfig")?; + + if contexts.is_empty() { + return Err("No contexts found in kubeconfig".to_string()); + } + + let first_context = contexts[0].get("name").and_then(|n| n.as_str()); + first_context + .map(|s| s.to_string()) + .ok_or_else(|| "Context name not found".to_string()) +} + +fn extract_server_url(content: &str) -> Result { + let value: Value = serde_yaml::from_str(content) + .map_err(|e| format!("Invalid kubeconfig YAML: {}", e))?; + + let clusters = value + .get("clusters") + .and_then(|c| c.as_sequence()) + .ok_or("Missing 'clusters' field in kubeconfig")?; + + if clusters.is_empty() { + return Err("No clusters found in kubeconfig".to_string()); + } + + let cluster = &clusters[0]; + let server = cluster + .get("cluster") + .and_then(|c| c.get("server")) + .and_then(|s| s.as_str()); + + server + .map(|s| s.to_string()) + .ok_or_else(|| "Server URL not found in cluster".to_string()) +} + #[tauri::command] pub async fn remove_cluster(id: String, state: State<'_, AppState>) -> Result<(), String> { let mut clusters = state.clusters.lock().await; @@ -169,11 +217,3 @@ pub async fn delete_port_forward(id: String, state: State<'_, AppState>) -> Resu Ok(()) } - -fn extract_context(_content: &str) -> Result { - Ok("default".to_string()) -} - -fn extract_server_url(_content: &str) -> Result { - Ok("unknown".to_string()) -}