fix(kube): unique temp kubeconfig paths — eliminate concurrent-call race condition

Each kubectl command now uses a globally unique temp kubeconfig path via
an AtomicU64 counter, preventing TempFileCleanup from deleting a file that
a concurrent call is still using.
This commit is contained in:
Shaun Arman 2026-06-08 21:47:06 -05:00
parent 5738aa1f31
commit ef1b3c3f23

View File

@ -20,6 +20,13 @@ lazy_static! {
static ref NAME_PATTERN_REGEX: Regex = Regex::new(r"^[a-z0-9]([a-z0-9.-]*[a-z0-9])?$").unwrap();
}
static KUBECONFIG_COUNTER: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
fn unique_kubeconfig_path(cluster_id: impl AsRef<str>) -> std::path::PathBuf {
let n = KUBECONFIG_COUNTER.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
std::env::temp_dir().join(format!("kubeconfig-{}-{}.yaml", cluster_id.as_ref(), n))
}
struct TempFileCleanup(std::path::PathBuf);
impl Drop for TempFileCleanup {
fn drop(&mut self) {
@ -319,8 +326,7 @@ pub async fn test_kubectl_connection(
(cluster.kubeconfig_content.clone(), cluster.context.clone())
};
let temp_dir = std::env::temp_dir();
let temp_path = temp_dir.join(format!("kubeconfig-{}-diag.yaml", cluster_id));
let temp_path = unique_kubeconfig_path(cluster_id);
let _cleanup = TempFileCleanup(temp_path.clone());
write_secure_temp_file(&temp_path, kubeconfig_content.as_ref())
@ -467,8 +473,7 @@ pub async fn test_cluster_connection(
let context = &cluster.context;
// Write kubeconfig to temp file and ensure cleanup even on panic
let temp_dir = std::env::temp_dir();
let temp_path = temp_dir.join(format!("kubeconfig-{}.yaml", cluster_id));
let temp_path = unique_kubeconfig_path(&cluster_id);
let _cleanup = TempFileCleanup(temp_path.clone());
write_secure_temp_file(&temp_path, kubeconfig_content)
@ -517,8 +522,7 @@ pub async fn discover_pods(
let context = &cluster.context;
// Write kubeconfig to temp file and ensure cleanup even on panic
let temp_dir = std::env::temp_dir();
let temp_path = temp_dir.join(format!("kubeconfig-{}-pods.yaml", cluster_id));
let temp_path = unique_kubeconfig_path(cluster_id);
let _cleanup = TempFileCleanup(temp_path.clone());
write_secure_temp_file(&temp_path, kubeconfig_content)
@ -647,8 +651,7 @@ pub async fn start_port_forward(
);
// Write kubeconfig to temp file
let temp_dir = std::env::temp_dir();
let temp_path = temp_dir.join(format!("kubeconfig-{}.yaml", request.cluster_id));
let temp_path = unique_kubeconfig_path(&request.cluster_id);
write_secure_temp_file(&temp_path, kubeconfig_content.as_ref())
.map_err(|e| format!("Failed to write kubeconfig temp file: {e}"))?;
@ -969,8 +972,7 @@ pub async fn list_namespaces(
let kubeconfig_content = cluster.kubeconfig_content.as_ref();
let context = &cluster.context;
let temp_dir = std::env::temp_dir();
let temp_path = temp_dir.join(format!("kubeconfig-{}-namespaces.yaml", cluster_id));
let temp_path = unique_kubeconfig_path(cluster_id);
let _cleanup = TempFileCleanup(temp_path.clone());
write_secure_temp_file(&temp_path, kubeconfig_content)
@ -1052,8 +1054,7 @@ pub async fn list_pods(
let kubeconfig_content = cluster.kubeconfig_content.as_ref();
let context = &cluster.context;
let temp_dir = std::env::temp_dir();
let temp_path = temp_dir.join(format!("kubeconfig-{}-pods.yaml", cluster_id));
let temp_path = unique_kubeconfig_path(cluster_id);
let _cleanup = TempFileCleanup(temp_path.clone());
write_secure_temp_file(&temp_path, kubeconfig_content)
@ -1176,8 +1177,7 @@ pub async fn list_services(
let kubeconfig_content = cluster.kubeconfig_content.as_ref();
let context = &cluster.context;
let temp_dir = std::env::temp_dir();
let temp_path = temp_dir.join(format!("kubeconfig-{}-services.yaml", cluster_id));
let temp_path = unique_kubeconfig_path(cluster_id);
let _cleanup = TempFileCleanup(temp_path.clone());
write_secure_temp_file(&temp_path, kubeconfig_content)
@ -1335,8 +1335,7 @@ pub async fn list_deployments(
let kubeconfig_content = cluster.kubeconfig_content.as_ref();
let context = &cluster.context;
let temp_dir = std::env::temp_dir();
let temp_path = temp_dir.join(format!("kubeconfig-{}-deployments.yaml", cluster_id));
let temp_path = unique_kubeconfig_path(cluster_id);
let _cleanup = TempFileCleanup(temp_path.clone());
write_secure_temp_file(&temp_path, kubeconfig_content)
@ -1470,8 +1469,7 @@ pub async fn list_statefulsets(
let kubeconfig_content = cluster.kubeconfig_content.as_ref();
let context = &cluster.context;
let temp_dir = std::env::temp_dir();
let temp_path = temp_dir.join(format!("kubeconfig-{}-statefulsets.yaml", cluster_id));
let temp_path = unique_kubeconfig_path(cluster_id);
let _cleanup = TempFileCleanup(temp_path.clone());
write_secure_temp_file(&temp_path, kubeconfig_content)
@ -1589,8 +1587,7 @@ pub async fn list_daemonsets(
let kubeconfig_content = cluster.kubeconfig_content.as_ref();
let context = &cluster.context;
let temp_dir = std::env::temp_dir();
let temp_path = temp_dir.join(format!("kubeconfig-{}-daemonsets.yaml", cluster_id));
let temp_path = unique_kubeconfig_path(cluster_id);
let _cleanup = TempFileCleanup(temp_path.clone());
write_secure_temp_file(&temp_path, kubeconfig_content)
@ -1758,8 +1755,7 @@ pub async fn get_pod_logs(
let kubeconfig_content = cluster.kubeconfig_content.as_ref();
let context = &cluster.context;
let temp_dir = std::env::temp_dir();
let temp_path = temp_dir.join(format!("kubeconfig-{}-logs.yaml", cluster_id));
let temp_path = unique_kubeconfig_path(cluster_id);
let _cleanup = TempFileCleanup(temp_path.clone());
write_secure_temp_file(&temp_path, kubeconfig_content)
@ -1808,8 +1804,7 @@ pub async fn scale_deployment(
let kubeconfig_content = cluster.kubeconfig_content.as_ref();
let context = &cluster.context;
let temp_dir = std::env::temp_dir();
let temp_path = temp_dir.join(format!("kubeconfig-{}-scale.yaml", cluster_id));
let temp_path = unique_kubeconfig_path(cluster_id);
let _cleanup = TempFileCleanup(temp_path.clone());
write_secure_temp_file(&temp_path, kubeconfig_content)
@ -1856,8 +1851,7 @@ pub async fn restart_deployment(
let kubeconfig_content = cluster.kubeconfig_content.as_ref();
let context = &cluster.context;
let temp_dir = std::env::temp_dir();
let temp_path = temp_dir.join(format!("kubeconfig-{}-restart.yaml", cluster_id));
let temp_path = unique_kubeconfig_path(cluster_id);
let _cleanup = TempFileCleanup(temp_path.clone());
write_secure_temp_file(&temp_path, kubeconfig_content)
@ -1904,8 +1898,7 @@ pub async fn delete_resource(
let kubeconfig_content = cluster.kubeconfig_content.as_ref();
let context = &cluster.context;
let temp_dir = std::env::temp_dir();
let temp_path = temp_dir.join(format!("kubeconfig-{}-delete.yaml", cluster_id));
let temp_path = unique_kubeconfig_path(cluster_id);
let _cleanup = TempFileCleanup(temp_path.clone());
write_secure_temp_file(&temp_path, kubeconfig_content)
@ -1953,8 +1946,7 @@ pub async fn exec_pod(
let kubeconfig_content = cluster.kubeconfig_content.as_ref();
let context = &cluster.context;
let temp_dir = std::env::temp_dir();
let temp_path = temp_dir.join(format!("kubeconfig-{}-exec.yaml", cluster_id));
let temp_path = unique_kubeconfig_path(cluster_id);
let _cleanup = TempFileCleanup(temp_path.clone());
write_secure_temp_file(&temp_path, kubeconfig_content)
@ -2232,8 +2224,7 @@ pub async fn list_replicasets(
let kubeconfig_content = cluster.kubeconfig_content.as_ref();
let context = &cluster.context;
let temp_dir = std::env::temp_dir();
let temp_path = temp_dir.join(format!("kubeconfig-{}-replicasets.yaml", cluster_id));
let temp_path = unique_kubeconfig_path(cluster_id);
let _cleanup = TempFileCleanup(temp_path.clone());
write_secure_temp_file(&temp_path, kubeconfig_content)
@ -2351,8 +2342,7 @@ pub async fn list_jobs(
let kubeconfig_content = cluster.kubeconfig_content.as_ref();
let context = &cluster.context;
let temp_dir = std::env::temp_dir();
let temp_path = temp_dir.join(format!("kubeconfig-{}-jobs.yaml", cluster_id));
let temp_path = unique_kubeconfig_path(cluster_id);
let _cleanup = TempFileCleanup(temp_path.clone());
write_secure_temp_file(&temp_path, kubeconfig_content)
@ -2508,8 +2498,7 @@ pub async fn list_cronjobs(
let kubeconfig_content = cluster.kubeconfig_content.as_ref();
let context = &cluster.context;
let temp_dir = std::env::temp_dir();
let temp_path = temp_dir.join(format!("kubeconfig-{}-cronjobs.yaml", cluster_id));
let temp_path = unique_kubeconfig_path(cluster_id);
let _cleanup = TempFileCleanup(temp_path.clone());
write_secure_temp_file(&temp_path, kubeconfig_content)
@ -2636,8 +2625,7 @@ pub async fn list_configmaps(
let kubeconfig_content = cluster.kubeconfig_content.as_ref();
let context = &cluster.context;
let temp_dir = std::env::temp_dir();
let temp_path = temp_dir.join(format!("kubeconfig-{}-configmaps.yaml", cluster_id));
let temp_path = unique_kubeconfig_path(cluster_id);
let _cleanup = TempFileCleanup(temp_path.clone());
write_secure_temp_file(&temp_path, kubeconfig_content)
@ -2735,8 +2723,7 @@ pub async fn list_secrets(
let kubeconfig_content = cluster.kubeconfig_content.as_ref();
let context = &cluster.context;
let temp_dir = std::env::temp_dir();
let temp_path = temp_dir.join(format!("kubeconfig-{}-secrets.yaml", cluster_id));
let temp_path = unique_kubeconfig_path(cluster_id);
let _cleanup = TempFileCleanup(temp_path.clone());
write_secure_temp_file(&temp_path, kubeconfig_content)
@ -2840,8 +2827,7 @@ pub async fn list_nodes(
let kubeconfig_content = cluster.kubeconfig_content.as_ref();
let context = &cluster.context;
let temp_dir = std::env::temp_dir();
let temp_path = temp_dir.join(format!("kubeconfig-{}-nodes.yaml", cluster_id));
let temp_path = unique_kubeconfig_path(cluster_id);
let _cleanup = TempFileCleanup(temp_path.clone());
write_secure_temp_file(&temp_path, kubeconfig_content)
@ -3029,8 +3015,7 @@ pub async fn list_events(
let kubeconfig_content = cluster.kubeconfig_content.as_ref();
let context = &cluster.context;
let temp_dir = std::env::temp_dir();
let temp_path = temp_dir.join(format!("kubeconfig-{}-events.yaml", cluster_id));
let temp_path = unique_kubeconfig_path(cluster_id);
let _cleanup = TempFileCleanup(temp_path.clone());
write_secure_temp_file(&temp_path, kubeconfig_content)
@ -3159,8 +3144,7 @@ pub async fn list_ingresses(
let kubeconfig_content = cluster.kubeconfig_content.as_ref();
let context = &cluster.context;
let temp_dir = std::env::temp_dir();
let temp_path = temp_dir.join(format!("kubeconfig-{}-ingresses.yaml", cluster_id));
let temp_path = unique_kubeconfig_path(cluster_id);
let _cleanup = TempFileCleanup(temp_path.clone());
write_secure_temp_file(&temp_path, kubeconfig_content)
@ -3286,8 +3270,7 @@ pub async fn list_persistentvolumeclaims(
let kubeconfig_content = cluster.kubeconfig_content.as_ref();
let context = &cluster.context;
let temp_dir = std::env::temp_dir();
let temp_path = temp_dir.join(format!("kubeconfig-{}-pvcs.yaml", cluster_id));
let temp_path = unique_kubeconfig_path(cluster_id);
let _cleanup = TempFileCleanup(temp_path.clone());
write_secure_temp_file(&temp_path, kubeconfig_content)
@ -3417,8 +3400,7 @@ pub async fn list_persistentvolumes(
let kubeconfig_content = cluster.kubeconfig_content.as_ref();
let context = &cluster.context;
let temp_dir = std::env::temp_dir();
let temp_path = temp_dir.join(format!("kubeconfig-{}-pvs.yaml", cluster_id));
let temp_path = unique_kubeconfig_path(cluster_id);
let _cleanup = TempFileCleanup(temp_path.clone());
write_secure_temp_file(&temp_path, kubeconfig_content)
@ -3544,8 +3526,7 @@ pub async fn list_serviceaccounts(
let kubeconfig_content = cluster.kubeconfig_content.as_ref();
let context = &cluster.context;
let temp_dir = std::env::temp_dir();
let temp_path = temp_dir.join(format!("kubeconfig-{}-sas.yaml", cluster_id));
let temp_path = unique_kubeconfig_path(cluster_id);
let _cleanup = TempFileCleanup(temp_path.clone());
write_secure_temp_file(&temp_path, kubeconfig_content)
@ -3643,8 +3624,7 @@ pub async fn list_roles(
let kubeconfig_content = cluster.kubeconfig_content.as_ref();
let context = &cluster.context;
let temp_dir = std::env::temp_dir();
let temp_path = temp_dir.join(format!("kubeconfig-{}-roles.yaml", cluster_id));
let temp_path = unique_kubeconfig_path(cluster_id);
let _cleanup = TempFileCleanup(temp_path.clone());
write_secure_temp_file(&temp_path, kubeconfig_content)
@ -3734,8 +3714,7 @@ pub async fn list_clusterroles(
let kubeconfig_content = cluster.kubeconfig_content.as_ref();
let context = &cluster.context;
let temp_dir = std::env::temp_dir();
let temp_path = temp_dir.join(format!("kubeconfig-{}-clusterroles.yaml", cluster_id));
let temp_path = unique_kubeconfig_path(cluster_id);
let _cleanup = TempFileCleanup(temp_path.clone());
write_secure_temp_file(&temp_path, kubeconfig_content)
@ -3810,8 +3789,7 @@ pub async fn list_rolebindings(
let kubeconfig_content = cluster.kubeconfig_content.as_ref();
let context = &cluster.context;
let temp_dir = std::env::temp_dir();
let temp_path = temp_dir.join(format!("kubeconfig-{}-rolebindings.yaml", cluster_id));
let temp_path = unique_kubeconfig_path(cluster_id);
let _cleanup = TempFileCleanup(temp_path.clone());
write_secure_temp_file(&temp_path, kubeconfig_content)
@ -3909,11 +3887,7 @@ pub async fn list_clusterrolebindings(
let kubeconfig_content = cluster.kubeconfig_content.as_ref();
let context = &cluster.context;
let temp_dir = std::env::temp_dir();
let temp_path = temp_dir.join(format!(
"kubeconfig-{}-clusterrolebindings.yaml",
cluster_id
));
let temp_path = unique_kubeconfig_path(cluster_id);
let _cleanup = TempFileCleanup(temp_path.clone());
write_secure_temp_file(&temp_path, kubeconfig_content)
@ -3999,8 +3973,7 @@ pub async fn list_horizontalpodautoscalers(
let kubeconfig_content = cluster.kubeconfig_content.as_ref();
let context = &cluster.context;
let temp_dir = std::env::temp_dir();
let temp_path = temp_dir.join(format!("kubeconfig-{}-hpas.yaml", cluster_id));
let temp_path = unique_kubeconfig_path(cluster_id);
let _cleanup = TempFileCleanup(temp_path.clone());
write_secure_temp_file(&temp_path, kubeconfig_content)
@ -4118,8 +4091,7 @@ pub async fn list_storageclasses(
let kubeconfig_content = cluster.kubeconfig_content.as_ref();
let context = &cluster.context;
let temp_dir = std::env::temp_dir();
let temp_path = temp_dir.join(format!("kubeconfig-{}-storageclasses.yaml", cluster_id));
let temp_path = unique_kubeconfig_path(cluster_id);
let _cleanup = TempFileCleanup(temp_path.clone());
write_secure_temp_file(&temp_path, kubeconfig_content)
@ -4224,8 +4196,7 @@ pub async fn list_networkpolicies(
let kubeconfig_content = cluster.kubeconfig_content.as_ref();
let context = &cluster.context;
let temp_dir = std::env::temp_dir();
let temp_path = temp_dir.join(format!("kubeconfig-{}-networkpolicies.yaml", cluster_id));
let temp_path = unique_kubeconfig_path(cluster_id);
let _cleanup = TempFileCleanup(temp_path.clone());
write_secure_temp_file(&temp_path, kubeconfig_content)
@ -4336,8 +4307,7 @@ pub async fn list_resourcequotas(
let kubeconfig_content = cluster.kubeconfig_content.as_ref();
let context = &cluster.context;
let temp_dir = std::env::temp_dir();
let temp_path = temp_dir.join(format!("kubeconfig-{}-resourcequotas.yaml", cluster_id));
let temp_path = unique_kubeconfig_path(cluster_id);
let _cleanup = TempFileCleanup(temp_path.clone());
write_secure_temp_file(&temp_path, kubeconfig_content)
@ -4458,8 +4428,7 @@ pub async fn list_limitranges(
let kubeconfig_content = cluster.kubeconfig_content.as_ref();
let context = &cluster.context;
let temp_dir = std::env::temp_dir();
let temp_path = temp_dir.join(format!("kubeconfig-{}-limitranges.yaml", cluster_id));
let temp_path = unique_kubeconfig_path(cluster_id);
let _cleanup = TempFileCleanup(temp_path.clone());
write_secure_temp_file(&temp_path, kubeconfig_content)
@ -4558,8 +4527,7 @@ pub async fn cordon_node(
let kubeconfig_content = cluster.kubeconfig_content.as_ref();
let context = &cluster.context;
let temp_dir = std::env::temp_dir();
let temp_path = temp_dir.join(format!("kubeconfig-{}-cordon.yaml", cluster_id));
let temp_path = unique_kubeconfig_path(cluster_id);
let _cleanup = TempFileCleanup(temp_path.clone());
write_secure_temp_file(&temp_path, kubeconfig_content)
@ -4600,8 +4568,7 @@ pub async fn uncordon_node(
let kubeconfig_content = cluster.kubeconfig_content.as_ref();
let context = &cluster.context;
let temp_dir = std::env::temp_dir();
let temp_path = temp_dir.join(format!("kubeconfig-{}-uncordon.yaml", cluster_id));
let temp_path = unique_kubeconfig_path(cluster_id);
let _cleanup = TempFileCleanup(temp_path.clone());
write_secure_temp_file(&temp_path, kubeconfig_content)
@ -4642,8 +4609,7 @@ pub async fn drain_node(
let kubeconfig_content = cluster.kubeconfig_content.as_ref();
let context = &cluster.context;
let temp_dir = std::env::temp_dir();
let temp_path = temp_dir.join(format!("kubeconfig-{}-drain.yaml", cluster_id));
let temp_path = unique_kubeconfig_path(cluster_id);
let _cleanup = TempFileCleanup(temp_path.clone());
write_secure_temp_file(&temp_path, kubeconfig_content)
@ -4688,8 +4654,7 @@ pub async fn rollback_deployment(
let kubeconfig_content = cluster.kubeconfig_content.as_ref();
let context = &cluster.context;
let temp_dir = std::env::temp_dir();
let temp_path = temp_dir.join(format!("kubeconfig-{}-rollback.yaml", cluster_id));
let temp_path = unique_kubeconfig_path(cluster_id);
let _cleanup = TempFileCleanup(temp_path.clone());
write_secure_temp_file(&temp_path, kubeconfig_content)
@ -4736,8 +4701,7 @@ pub async fn create_resource(
let kubeconfig_content = cluster.kubeconfig_content.as_ref();
let context = &cluster.context;
let temp_dir = std::env::temp_dir();
let temp_path = temp_dir.join(format!("kubeconfig-{}-create.yaml", cluster_id));
let temp_path = unique_kubeconfig_path(cluster_id);
let _cleanup = TempFileCleanup(temp_path.clone());
write_secure_temp_file(&temp_path, kubeconfig_content)
@ -4800,8 +4764,7 @@ pub async fn edit_resource(
let kubeconfig_content = cluster.kubeconfig_content.as_ref();
let context = &cluster.context;
let temp_dir = std::env::temp_dir();
let temp_path = temp_dir.join(format!("kubeconfig-{}-edit.yaml", cluster_id));
let temp_path = unique_kubeconfig_path(cluster_id);
let _cleanup = TempFileCleanup(temp_path.clone());
write_secure_temp_file(&temp_path, kubeconfig_content)
@ -5050,8 +5013,7 @@ pub async fn list_replicationcontrollers(
let kubeconfig_content = cluster.kubeconfig_content.as_ref();
let context = &cluster.context;
let temp_dir = std::env::temp_dir();
let temp_path = temp_dir.join(format!("kubeconfig-{}-rcs.yaml", cluster_id));
let temp_path = unique_kubeconfig_path(cluster_id);
let _cleanup = TempFileCleanup(temp_path.clone());
write_secure_temp_file(&temp_path, kubeconfig_content)
@ -5175,8 +5137,7 @@ pub async fn list_poddisruptionbudgets(
let kubeconfig_content = cluster.kubeconfig_content.as_ref();
let context = &cluster.context;
let temp_dir = std::env::temp_dir();
let temp_path = temp_dir.join(format!("kubeconfig-{}-pdbs.yaml", cluster_id));
let temp_path = unique_kubeconfig_path(cluster_id);
let _cleanup = TempFileCleanup(temp_path.clone());
write_secure_temp_file(&temp_path, kubeconfig_content)
@ -5291,8 +5252,7 @@ pub async fn list_priorityclasses(
let kubeconfig_content = cluster.kubeconfig_content.as_ref();
let context = &cluster.context;
let temp_dir = std::env::temp_dir();
let temp_path = temp_dir.join(format!("kubeconfig-{}-priorityclasses.yaml", cluster_id));
let temp_path = unique_kubeconfig_path(cluster_id);
let _cleanup = TempFileCleanup(temp_path.clone());
write_secure_temp_file(&temp_path, kubeconfig_content)
@ -5389,8 +5349,7 @@ pub async fn list_runtimeclasses(
let kubeconfig_content = cluster.kubeconfig_content.as_ref();
let context = &cluster.context;
let temp_dir = std::env::temp_dir();
let temp_path = temp_dir.join(format!("kubeconfig-{}-runtimeclasses.yaml", cluster_id));
let temp_path = unique_kubeconfig_path(cluster_id);
let _cleanup = TempFileCleanup(temp_path.clone());
write_secure_temp_file(&temp_path, kubeconfig_content)
@ -5475,8 +5434,7 @@ pub async fn list_leases(
let kubeconfig_content = cluster.kubeconfig_content.as_ref();
let context = &cluster.context;
let temp_dir = std::env::temp_dir();
let temp_path = temp_dir.join(format!("kubeconfig-{}-leases.yaml", cluster_id));
let temp_path = unique_kubeconfig_path(cluster_id);
let _cleanup = TempFileCleanup(temp_path.clone());
write_secure_temp_file(&temp_path, kubeconfig_content)
@ -5578,8 +5536,7 @@ pub async fn list_mutatingwebhookconfigurations(
let kubeconfig_content = cluster.kubeconfig_content.as_ref();
let context = &cluster.context;
let temp_dir = std::env::temp_dir();
let temp_path = temp_dir.join(format!("kubeconfig-{}-mwhc.yaml", cluster_id));
let temp_path = unique_kubeconfig_path(cluster_id);
let _cleanup = TempFileCleanup(temp_path.clone());
write_secure_temp_file(&temp_path, kubeconfig_content)
@ -5669,8 +5626,7 @@ pub async fn list_validatingwebhookconfigurations(
let kubeconfig_content = cluster.kubeconfig_content.as_ref();
let context = &cluster.context;
let temp_dir = std::env::temp_dir();
let temp_path = temp_dir.join(format!("kubeconfig-{}-vwhc.yaml", cluster_id));
let temp_path = unique_kubeconfig_path(cluster_id);
let _cleanup = TempFileCleanup(temp_path.clone());
write_secure_temp_file(&temp_path, kubeconfig_content)
@ -5761,8 +5717,7 @@ pub async fn list_endpoints(
let kubeconfig_content = cluster.kubeconfig_content.as_ref();
let context = &cluster.context;
let temp_dir = std::env::temp_dir();
let temp_path = temp_dir.join(format!("kubeconfig-{}-endpoints.yaml", cluster_id));
let temp_path = unique_kubeconfig_path(cluster_id);
let _cleanup = TempFileCleanup(temp_path.clone());
write_secure_temp_file(&temp_path, kubeconfig_content)
@ -5877,8 +5832,7 @@ pub async fn list_endpointslices(
let kubeconfig_content = cluster.kubeconfig_content.as_ref();
let context = &cluster.context;
let temp_dir = std::env::temp_dir();
let temp_path = temp_dir.join(format!("kubeconfig-{}-endpointslices.yaml", cluster_id));
let temp_path = unique_kubeconfig_path(cluster_id);
let _cleanup = TempFileCleanup(temp_path.clone());
write_secure_temp_file(&temp_path, kubeconfig_content)
@ -6000,8 +5954,7 @@ pub async fn list_ingressclasses(
let kubeconfig_content = cluster.kubeconfig_content.as_ref();
let context = &cluster.context;
let temp_dir = std::env::temp_dir();
let temp_path = temp_dir.join(format!("kubeconfig-{}-ingressclasses.yaml", cluster_id));
let temp_path = unique_kubeconfig_path(cluster_id);
let _cleanup = TempFileCleanup(temp_path.clone());
write_secure_temp_file(&temp_path, kubeconfig_content)
@ -6101,8 +6054,7 @@ pub async fn list_namespaces_resource(
let kubeconfig_content = cluster.kubeconfig_content.as_ref();
let context = &cluster.context;
let temp_dir = std::env::temp_dir();
let temp_path = temp_dir.join(format!("kubeconfig-{}-nsres.yaml", cluster_id));
let temp_path = unique_kubeconfig_path(cluster_id);
let _cleanup = TempFileCleanup(temp_path.clone());
write_secure_temp_file(&temp_path, kubeconfig_content)
@ -6187,8 +6139,7 @@ pub async fn list_crds(
let kubeconfig_content = cluster.kubeconfig_content.as_ref();
let context = &cluster.context;
let temp_dir = std::env::temp_dir();
let temp_path = temp_dir.join(format!("kubeconfig-{}-crds.yaml", cluster_id));
let temp_path = unique_kubeconfig_path(cluster_id);
let _cleanup = TempFileCleanup(temp_path.clone());
write_secure_temp_file(&temp_path, kubeconfig_content)
@ -6312,8 +6263,7 @@ pub async fn list_custom_resources(
let kubeconfig_content = cluster.kubeconfig_content.as_ref();
let context = &cluster.context;
let temp_dir = std::env::temp_dir();
let temp_path = temp_dir.join(format!("kubeconfig-{}-cr.yaml", cluster_id));
let temp_path = unique_kubeconfig_path(&cluster_id);
let _cleanup = TempFileCleanup(temp_path.clone());
write_secure_temp_file(&temp_path, kubeconfig_content)
@ -6439,8 +6389,7 @@ pub async fn force_delete_resource(
let kubeconfig_content = cluster.kubeconfig_content.as_ref();
let context = &cluster.context;
let temp_dir = std::env::temp_dir();
let temp_path = temp_dir.join(format!("kubeconfig-{}-force-delete.yaml", cluster_id));
let temp_path = unique_kubeconfig_path(&cluster_id);
let _cleanup = TempFileCleanup(temp_path.clone());
write_secure_temp_file(&temp_path, kubeconfig_content)
@ -6498,8 +6447,7 @@ pub async fn describe_resource(
let kubeconfig_content = cluster.kubeconfig_content.as_ref();
let context = &cluster.context;
let temp_dir = std::env::temp_dir();
let temp_path = temp_dir.join(format!("kubeconfig-{}-describe.yaml", cluster_id));
let temp_path = unique_kubeconfig_path(cluster_id);
let _cleanup = TempFileCleanup(temp_path.clone());
write_secure_temp_file(&temp_path, kubeconfig_content)
@ -6553,8 +6501,7 @@ pub async fn get_resource_yaml(
let kubeconfig_content = cluster.kubeconfig_content.as_ref();
let context = &cluster.context;
let temp_dir = std::env::temp_dir();
let temp_path = temp_dir.join(format!("kubeconfig-{}-getyaml.yaml", cluster_id));
let temp_path = unique_kubeconfig_path(cluster_id);
let _cleanup = TempFileCleanup(temp_path.clone());
write_secure_temp_file(&temp_path, kubeconfig_content)
@ -6608,8 +6555,7 @@ pub async fn attach_pod(
let session_id = uuid::Uuid::now_v7().to_string();
let temp_dir = std::env::temp_dir();
let temp_path = temp_dir.join(format!("kubeconfig-{}-attach.yaml", cluster_id));
let temp_path = unique_kubeconfig_path(&cluster_id);
let _cleanup = TempFileCleanup(temp_path.clone());
write_secure_temp_file(&temp_path, kubeconfig_content)
@ -6676,8 +6622,7 @@ pub async fn restart_statefulset(
let kubeconfig_content = cluster.kubeconfig_content.as_ref();
let context = &cluster.context;
let temp_dir = std::env::temp_dir();
let temp_path = temp_dir.join(format!("kubeconfig-{}-restart-sts.yaml", cluster_id));
let temp_path = unique_kubeconfig_path(cluster_id);
let _cleanup = TempFileCleanup(temp_path.clone());
write_secure_temp_file(&temp_path, kubeconfig_content)
@ -6724,8 +6669,7 @@ pub async fn restart_daemonset(
let kubeconfig_content = cluster.kubeconfig_content.as_ref();
let context = &cluster.context;
let temp_dir = std::env::temp_dir();
let temp_path = temp_dir.join(format!("kubeconfig-{}-restart-ds.yaml", cluster_id));
let temp_path = unique_kubeconfig_path(cluster_id);
let _cleanup = TempFileCleanup(temp_path.clone());
write_secure_temp_file(&temp_path, kubeconfig_content)
@ -6773,8 +6717,7 @@ pub async fn scale_statefulset(
let kubeconfig_content = cluster.kubeconfig_content.as_ref();
let context = &cluster.context;
let temp_dir = std::env::temp_dir();
let temp_path = temp_dir.join(format!("kubeconfig-{}-scale-sts.yaml", cluster_id));
let temp_path = unique_kubeconfig_path(cluster_id);
let _cleanup = TempFileCleanup(temp_path.clone());
write_secure_temp_file(&temp_path, kubeconfig_content)
@ -6822,8 +6765,7 @@ pub async fn scale_replicaset(
let kubeconfig_content = cluster.kubeconfig_content.as_ref();
let context = &cluster.context;
let temp_dir = std::env::temp_dir();
let temp_path = temp_dir.join(format!("kubeconfig-{}-scale-rs.yaml", cluster_id));
let temp_path = unique_kubeconfig_path(cluster_id);
let _cleanup = TempFileCleanup(temp_path.clone());
write_secure_temp_file(&temp_path, kubeconfig_content)
@ -6871,8 +6813,7 @@ pub async fn scale_replicationcontroller(
let kubeconfig_content = cluster.kubeconfig_content.as_ref();
let context = &cluster.context;
let temp_dir = std::env::temp_dir();
let temp_path = temp_dir.join(format!("kubeconfig-{}-scale-rc.yaml", cluster_id));
let temp_path = unique_kubeconfig_path(cluster_id);
let _cleanup = TempFileCleanup(temp_path.clone());
write_secure_temp_file(&temp_path, kubeconfig_content)
@ -6919,8 +6860,7 @@ pub async fn suspend_cronjob(
let kubeconfig_content = cluster.kubeconfig_content.as_ref();
let context = &cluster.context;
let temp_dir = std::env::temp_dir();
let temp_path = temp_dir.join(format!("kubeconfig-{}-suspend-cj.yaml", cluster_id));
let temp_path = unique_kubeconfig_path(cluster_id);
let _cleanup = TempFileCleanup(temp_path.clone());
write_secure_temp_file(&temp_path, kubeconfig_content)
@ -6968,8 +6908,7 @@ pub async fn resume_cronjob(
let kubeconfig_content = cluster.kubeconfig_content.as_ref();
let context = &cluster.context;
let temp_dir = std::env::temp_dir();
let temp_path = temp_dir.join(format!("kubeconfig-{}-resume-cj.yaml", cluster_id));
let temp_path = unique_kubeconfig_path(cluster_id);
let _cleanup = TempFileCleanup(temp_path.clone());
write_secure_temp_file(&temp_path, kubeconfig_content)
@ -7017,8 +6956,7 @@ pub async fn trigger_cronjob(
let kubeconfig_content = cluster.kubeconfig_content.as_ref();
let context = &cluster.context;
let temp_dir = std::env::temp_dir();
let temp_path = temp_dir.join(format!("kubeconfig-{}-trigger-cj.yaml", cluster_id));
let temp_path = unique_kubeconfig_path(cluster_id);
let _cleanup = TempFileCleanup(temp_path.clone());
write_secure_temp_file(&temp_path, kubeconfig_content)
@ -7069,8 +7007,7 @@ pub async fn create_namespace(
let kubeconfig_content = cluster.kubeconfig_content.as_ref();
let context = &cluster.context;
let temp_dir = std::env::temp_dir();
let temp_path = temp_dir.join(format!("kubeconfig-{}-create-ns.yaml", cluster_id));
let temp_path = unique_kubeconfig_path(&cluster_id);
let _cleanup = TempFileCleanup(temp_path.clone());
write_secure_temp_file(&temp_path, kubeconfig_content)
@ -7116,8 +7053,7 @@ pub async fn delete_namespace(
let kubeconfig_content = cluster.kubeconfig_content.as_ref();
let context = &cluster.context;
let temp_dir = std::env::temp_dir();
let temp_path = temp_dir.join(format!("kubeconfig-{}-delete-ns.yaml", cluster_id));
let temp_path = unique_kubeconfig_path(&cluster_id);
let _cleanup = TempFileCleanup(temp_path.clone());
write_secure_temp_file(&temp_path, kubeconfig_content)
@ -7189,8 +7125,7 @@ pub async fn stream_pod_logs(
let (kubeconfig_arc, context) = kubeconfig_content;
let temp_dir = std::env::temp_dir();
let temp_path = temp_dir.join(format!("kubeconfig-{}-stream.yaml", config.cluster_id));
let temp_path = unique_kubeconfig_path(config.cluster_id);
write_secure_temp_file(&temp_path, kubeconfig_arc.as_ref())
.map_err(|e| format!("Failed to write kubeconfig temp file: {e}"))?;
@ -7514,8 +7449,7 @@ pub async fn helm_list_releases(
let (kubeconfig_arc, context) = kubeconfig_content;
let temp_dir = std::env::temp_dir();
let temp_path = temp_dir.join(format!("kubeconfig-{}-helm-list.yaml", cluster_id));
let temp_path = unique_kubeconfig_path(cluster_id);
let _cleanup = TempFileCleanup(temp_path.clone());
write_secure_temp_file(&temp_path, kubeconfig_arc.as_ref())
@ -7638,8 +7572,7 @@ pub async fn helm_uninstall(
let (kubeconfig_arc, context) = kubeconfig_content;
let temp_dir = std::env::temp_dir();
let temp_path = temp_dir.join(format!("kubeconfig-{}-helm-uninstall.yaml", cluster_id));
let temp_path = unique_kubeconfig_path(&cluster_id);
let _cleanup = TempFileCleanup(temp_path.clone());
write_secure_temp_file(&temp_path, kubeconfig_arc.as_ref())
@ -7690,8 +7623,7 @@ pub async fn helm_rollback(
let (kubeconfig_arc, context) = kubeconfig_content;
let temp_dir = std::env::temp_dir();
let temp_path = temp_dir.join(format!("kubeconfig-{}-helm-rollback.yaml", cluster_id));
let temp_path = unique_kubeconfig_path(&cluster_id);
let _cleanup = TempFileCleanup(temp_path.clone());
write_secure_temp_file(&temp_path, kubeconfig_arc.as_ref())
@ -7909,4 +7841,14 @@ mod new_command_tests {
let result = parse_crds_json(json).unwrap();
assert!(result.is_empty());
}
#[test]
fn test_unique_kubeconfig_path_produces_distinct_paths() {
let path1 = unique_kubeconfig_path("test-cluster");
let path2 = unique_kubeconfig_path("test-cluster");
assert_ne!(
path1, path2,
"successive calls must return distinct paths to prevent concurrent-call race conditions"
);
}
}