fix: implement proper kubeconfig parsing and validation
Some checks failed
Test / frontend-tests (pull_request) Successful in 1m23s
Test / frontend-typecheck (pull_request) Successful in 1m29s
PR Review Automation / review (pull_request) Successful in 3m37s
Test / rust-fmt-check (pull_request) Failing after 11m1s
Test / rust-clippy (pull_request) Successful in 11m49s
Test / rust-tests (pull_request) Has been cancelled

- 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
This commit is contained in:
Shaun Arman 2026-06-06 13:17:56 -05:00
parent a7a0f01674
commit 03e86dc326

View File

@ -1,6 +1,7 @@
use crate::kube::ClusterClient; use crate::kube::ClusterClient;
use crate::state::AppState; use crate::state::AppState;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use serde_yaml::Value;
use tauri::State; use tauri::State;
#[derive(Debug, Clone, Serialize, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize)]
@ -37,6 +38,10 @@ pub async fn add_cluster(
kubeconfig_content: String, kubeconfig_content: String,
state: State<'_, AppState>, state: State<'_, AppState>,
) -> Result<ClusterInfo, String> { ) -> Result<ClusterInfo, String> {
if kubeconfig_content.trim().is_empty() {
return Err("Kubeconfig content cannot be empty".to_string());
}
let context = extract_context(&kubeconfig_content)?; let context = extract_context(&kubeconfig_content)?;
let server_url = extract_server_url(&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<String, String> {
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<String, String> {
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] #[tauri::command]
pub async fn remove_cluster(id: String, state: State<'_, AppState>) -> Result<(), String> { pub async fn remove_cluster(id: String, state: State<'_, AppState>) -> Result<(), String> {
let mut clusters = state.clusters.lock().await; let mut clusters = state.clusters.lock().await;
@ -169,11 +217,3 @@ pub async fn delete_port_forward(id: String, state: State<'_, AppState>) -> Resu
Ok(()) Ok(())
} }
fn extract_context(_content: &str) -> Result<String, String> {
Ok("default".to_string())
}
fn extract_server_url(_content: &str) -> Result<String, String> {
Ok("unknown".to_string())
}