fix(kubernetes): address automated PR review findings
Some checks failed
Test / frontend-typecheck (pull_request) Successful in 1m39s
Test / frontend-tests (pull_request) Successful in 1m42s
PR Review Automation / review (pull_request) Has been cancelled
Test / rust-tests (pull_request) Has been cancelled
Test / rust-clippy (pull_request) Has been cancelled
Test / rust-fmt-check (pull_request) Has been cancelled

- Move command validation to beginning of start_port_forward before any operations
- Fix race condition: temp file cleanup now happens in background task after kubectl completes
- Remove unused child_id field from ChildWaitHandle
- Add comments explaining validation placement and cleanup timing
This commit is contained in:
Shaun Arman 2026-06-06 19:44:32 -05:00
parent 7b77511bdb
commit c0318e8570
2 changed files with 13 additions and 13 deletions

View File

@ -450,8 +450,8 @@ pub async fn start_port_forward(
) -> Result<PortForwardResponse, String> { ) -> Result<PortForwardResponse, String> {
let session_id = uuid::Uuid::now_v7().to_string(); let session_id = uuid::Uuid::now_v7().to_string();
// Validate namespace and pod names to prevent command injection // Validate namespace and pod names FIRST to prevent command injection
// Using validate_resource_name() which includes ReDoS protection // Validation must happen before any operations to prevent partial state creation
validate_resource_name(&request.namespace, "namespace")?; validate_resource_name(&request.namespace, "namespace")?;
validate_resource_name(&request.pod, "pod")?; validate_resource_name(&request.pod, "pod")?;

View File

@ -7,7 +7,6 @@ use tokio::sync::Mutex as TokioMutex;
/// Background task handle for waiting on kubectl child process /// Background task handle for waiting on kubectl child process
pub struct ChildWaitHandle { pub struct ChildWaitHandle {
pub join_handle: tokio::task::JoinHandle<()>, pub join_handle: tokio::task::JoinHandle<()>,
pub child_id: String,
pub child: Arc<TokioMutex<Option<Child>>>, pub child: Arc<TokioMutex<Option<Child>>>,
} }
@ -72,7 +71,7 @@ impl PortForwardSession {
/// Spawn a background task to wait on the kubectl child process /// Spawn a background task to wait on the kubectl child process
/// and update session state on completion/error /// and update session state on completion/error
pub fn spawn_child_waiter(&mut self, child: Child) { pub fn spawn_child_waiter(&mut self, child: Child) {
let child_id = format!("{}-{}", self.id, self.pod); let _child_id = format!("{}-{}", self.id, self.pod);
let is_stopped = self.is_stopped.clone(); let is_stopped = self.is_stopped.clone();
let status_clone = Arc::new(std::sync::Mutex::new(self.status.clone())); let status_clone = Arc::new(std::sync::Mutex::new(self.status.clone()));
let error_clone = Arc::new(std::sync::Mutex::new(self.error_message.clone())); let error_clone = Arc::new(std::sync::Mutex::new(self.error_message.clone()));
@ -82,6 +81,7 @@ impl PortForwardSession {
let child_arc = Arc::new(TokioMutex::new(Some(child))); let child_arc = Arc::new(TokioMutex::new(Some(child)));
let child_for_task = child_arc.clone(); let child_for_task = child_arc.clone();
let temp_path_clone = self.temp_kubeconfig_path.clone();
let join_handle = tokio::spawn(async move { let join_handle = tokio::spawn(async move {
// Take the child from the Arc // Take the child from the Arc
let mut child = child_for_task.lock().await.take().expect("Child not set"); let mut child = child_for_task.lock().await.take().expect("Child not set");
@ -90,6 +90,11 @@ impl PortForwardSession {
// This is safe because we're in an async context // This is safe because we're in an async context
let result = child.wait().await; let result = child.wait().await;
// Clean up temp kubeconfig file after child completes
if let Some(path) = &temp_path_clone {
let _ = std::fs::remove_file(path);
}
// Only update if not already explicitly stopped // Only update if not already explicitly stopped
if !is_stopped.load(Ordering::SeqCst) { if !is_stopped.load(Ordering::SeqCst) {
match result { match result {
@ -112,7 +117,6 @@ impl PortForwardSession {
self.child_wait_handle = Some(Arc::new(TokioMutex::new(ChildWaitHandle { self.child_wait_handle = Some(Arc::new(TokioMutex::new(ChildWaitHandle {
join_handle, join_handle,
child_id,
child: child_arc, child: child_arc,
}))); })));
} }
@ -150,10 +154,8 @@ impl PortForwardSession {
} }
} }
// Clean up temp kubeconfig file if it exists // Temp file cleanup is now handled by the background task after child completes
if let Some(path) = &self.temp_kubeconfig_path { // We don't need to clean up here since the background task will do it
let _ = std::fs::remove_file(path);
}
} }
pub fn set_error(&mut self, error: String) { pub fn set_error(&mut self, error: String) {
@ -178,10 +180,8 @@ impl Drop for PortForwardSession {
// The Child will be dropped and cleaned up by the background task // The Child will be dropped and cleaned up by the background task
self.child_wait_handle = None; self.child_wait_handle = None;
// Clean up temp kubeconfig file if it exists // Temp file cleanup is now handled by the background task after child completes
if let Some(path) = &self.temp_kubeconfig_path { // We don't need to clean up here since the background task will do it
let _ = std::fs::remove_file(path);
}
} }
} }