feat(kube): add Kubernetes management GUI components #71
No reviewers
Labels
No Label
Compat/Breaking
Kind/Bug
Kind/Documentation
Kind/Enhancement
Kind/Feature
Kind/Security
Kind/Testing
Priority
Critical
Priority
High
Priority
Low
Priority
Medium
Reviewed
Confirmed
Reviewed
Duplicate
Reviewed
Invalid
Reviewed
Won't Fix
Status
Abandoned
Status
Blocked
Status
Need More Info
No Milestone
No project
No Assignees
1 Participants
Notifications
Due Date
No due date set.
Dependencies
No dependencies set.
Reference: sarman/tftsr-devops_investigation#71
Loading…
Reference in New Issue
Block a user
No description provided.
Delete Branch "feature/kubernetes-management"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Automated PR Review (qwen3-coder-next via liteLLM):\n\nSummary
The PR adds Kubernetes management GUI components with associated Tauri command wrappers and unit tests. However, two critical logic flaws were identified: the
PortForwardListcomponent allows stopping a port forward using both the "Stop" and "Delete" buttons, leading to redundant API calls and potential UI state inconsistency, and thePortForwardFormlacks validation for the namespace field, allowing empty or invalid values to be submitted.Findings
[BLOCKER] src/components/Kubernetes/PortForwardList.tsx:80-92 - Two separate UI buttons ("Stop" and "Delete") both call the same
handleStopfunction to stop a port forward, but "Stop" and "Delete" imply different actions (stopping vs removing from DB); this double-action creates ambiguous behavior and risk of unintended state.Evidence:
Fix: Introduce a distinct "Delete" handler that calls a
deletePortForwardCmd(or equivalent backend delete) instead of usinghandleStop, and ensure only one action per button.[WARNING] src/components/Kubernetes/PortForwardForm.tsx:79-92 - Namespace field allows empty input; no validation for required field or allowed patterns, potentially leading to API failures or defaulting to unexpected behavior.
Evidence:
Fix: Add
namespaceto required field checks or ensure default value ("default") is always used and validated.Verdict: REQUEST CHANGES
6c54479ecdtoaefe935de5Automated PR Review (qwen3-coder-next via liteLLM):\n\nSummary
The PR introduces Kubernetes management GUI components with UI forms and list displays for clusters and port forwards, along with the corresponding Tauri command wrappers and tests. A critical inconsistency exists in the port forward deletion logic:
stopPortForwardCmdis incorrectly reused asdeletePortForwardCmd, leading to data inconsistency since stopped port forwards are not permanently deleted but only removed from state, and no actual backend delete operation is invoked. Additionally, UI components for port forwarding do not implement separate “stop” and “delete” behaviors correctly.Findings
[BLOCKER] src/pages/Kubernetes/KubernetesPage.tsx:85-92 -
deletePortForwardCmdincorrectly only stops the port forward instead of performing a delete, and does not call any backend delete command. This causes deleted port forwards to remain active on the backend and creates data inconsistency.Evidence:
Fix: Add a separate
deletePortForwardCmdthat invokes aremove_port_forwardordelete_port_forwardcommand (if supported by the backend), or renamehandleDeletePortForwardto reflect stopping only. However, per current Tauri commands, onlystop_port_forwardexists; consider adding aremovePortForwardCmdwrapper or clarifying intent.[WARNING] src/components/Kubernetes/PortForwardList.tsx:38-43 - Error handling in status badge does not handle unknown or empty status gracefully; falls back to muted color which may be unclear.
Evidence:
Fix: Add explicit handling for
"","unknown", or add a fallback label and color.[WARNING] src/components/Kubernetes/PortForwardForm.tsx:67-68 - Input validation for port does not distinguish between empty and invalid port. If user clears field, it passes validation due to
containerPortdefaulting to"80".Evidence:
Fix: Add explicit check for empty string before parsing.
[SUGGESTION] src/lib/tauriCommands.ts:733-735 -
addClusterCmdpasseskubeconfig_contentto backend but field name in interface iskubeconfigContent(case mismatch). While this is handled correctly in invocation, it may cause confusion or future mismatches if not aligned.Evidence:
Fix: Document or rename parameter to match expected backend field name (
kubeconfig_content) explicitly to reduce confusion.Verdict: REQUEST CHANGES
Automated PR Review (qwen3-coder-next via liteLLM):\n\nSummary
A critical logic error exists in
tauriCommands.tswheredeletePortForwardCmdincorrectly invokes"stop_port_forward"instead of a dedicated"delete_port_forward"command. Additionally, thePortForwardList.tsxcomponent attempts to callonDelete, but no correspondingdeletePortForwardCmdinvoke wrapper maps to a Rust command that deletes port forwards (the Rust side only hasstop_port_forwardand nodelete_port_forwardfunction is registered or implemented). This results in a broken UI flow and silent failures on delete attempts.Findings
deletePortForwardCmdinvokes"stop_port_forward"instead of a proper delete command; no"delete_port_forward"command exists in the Rust command listEvidence:
export const deletePortForwardCmd = (id: string) => invoke<void>("stop_port_forward", { id });Fix: Either implement and register a
delete_port_forwardcommand in Rust (addcommands::kube::delete_port_forwardtogenerate_handler![], implementpub async fn delete_port_forward(id: String, ...), etc.), or updatedeletePortForwardCmdto use the correct Tauri command name if deletion is intended to be handled bystop_port_forward. However, based onPortForwardList.tsx,onDeleteshould truly delete, not just stop — so implementation of the missing Rust command is required.Verdict: REQUEST CHANGES
Automated PR Review (qwen3-coder-next via liteLLM):\n\nSummary
The PR introduces Kubernetes management GUI components and Tauri commands for cluster and port-forward management. However, several issues exist: the
extract_contextandextract_server_urlfunctions inkube.rshardcode return values instead of parsing the kubeconfig, making cluster info inaccurate and insecure; port-forward local port is always 0 and never assigned dynamically; the frontend and backend implementations assume direct kubeconfig content handling without validation or schema enforcement, risking malformed config ingestion; and missing error handling around port conflicts and port-forward lifecycle management.Findings
extract_contextandextract_server_urldo not parse kubeconfig and instead return hardcoded values.Evidence:
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()) }Fix: Implement kubeconfig parsing using
kubeconfigcrate or similar to extract actual context and server URL from YAML content.start_port_forwardhardcodeslocal_portto 0 instead of dynamically assigning an available local port.Evidence:
session: crate::kube::PortForwardSession::new(... vec![request.container_port], vec![0],)Fix: Use an available port allocator (e.g.,
TcpListener::bind((Ipv4Addr::LOCALHOST, 0))) and persist the assigned local port inPortForwardSessionand response.add_clustervalidates inputs only for presence but not correctness or format, allowing malformed kubeconfig to be stored and later fail silently.Evidence:
let context = extract_context(&kubeconfig_content)?;// returns hardcoded defaultNo actual kubeconfig parsing or structural validation.
Fix: Parse kubeconfig YAML, validate presence of required fields (
apiVersion,kind,clusters,contexts,users), and reject invalid inputs with actionable error messages.Evidence:
if (isNaN(port) || port < 1 || port > 65535) { setError("Container port must be a valid port number (1-65535)"); ... }Fix: Add backend enforcement of local port uniqueness or document that the frontend must avoid collisions (currently impossible since
local_portis always 0).kubectl port-forward;PortForwardSessionand its status tracking are not used to control real subprocess.Evidence:
session.stop()is called instop_port_forward, but nokubectlinvocation is present in the command handlers.Fix: Implement actual
kubectl port-forwardsubprocess spawning and integration withPortForwardSession(e.g., track PID, handle stdout/stderr, detect early exit).list_port_forwardsmapss.ports.first().copied().unwrap_or(0)forcontainer_port, but does not reflect real container port if multiple ports are supported.Evidence:
container_port: s.ports.first().copied().unwrap_or(0)Fix: Support multiple ports per port-forward or document single-port limitation clearly.
ClusterInfoandPortForwardResponsestructs embed raw strings (status,cluster_url) without sanitization, vulnerable to XSS if rendered unsafely in UI.Evidence:
pub struct ClusterInfo { pub cluster_url: String, ... }Fix: Sanitize or encode strings on rendering (e.g., treat as plain text, use
textContentin frontend), and avoid embedding untrusted data directly in DOM attributes.Verdict: REQUEST CHANGES
Automated PR Review (qwen3-coder-next via liteLLM):\n\nSummary
The PR adds Kubernetes management GUI components including UI for cluster and port-forward management and associated Tauri commands. A critical logic flaw exists in
kube.rswhere port-forward local ports are hardcoded to0, and no actual port-forwarding logic (e.g., binding or forwarding ports) is implemented. Additionally, thePortForwardSessionstruct is referenced but not defined in the visible scope, and thekube.rsfile referencescrate::kubetypes without definition, making the code non-functional.Findings
[BLOCKER] src-tauri/src/commands/kube.rs:94-108 -
start_port_forwardcreates a port-forward session but setslocal_ports: vec![0], and there is no actual port-forwarding logic (e.g., spawning akubectl port-forwardprocess or binding to a local port). Thelocal_portinPortForwardResponseis always0, misleading the UI.Evidence:
let session = crate::kube::PortForwardSession::new(session_id.clone(), request.cluster_id.clone(), request.namespace.clone(), request.pod.clone(), None, vec![request.container_port], vec![0],);Fix: Implement real port-forwarding using
kubectl port-forwardor similar (e.g., spawn the command and bind to an available local port), and store the actual local port in the session and response.[BLOCKER] src-tauri/src/commands/kube.rs:1 -
crate::kube::PortForwardSessionandcrate::kube::PortForwardStatusare used but never defined in the provided codebase. Thekubemodule is declared inlib.rsbut nokube.rsimplementation file is shown besides the command definitions.Evidence:
use crate::kube::ClusterClient;andcrate::kube::PortForwardSession::new(...)andcrate::kube::PortForwardStatus::Active— all fromkube.rslines 1, 97, and 142–146.Fix: Provide a complete
kube.rsmodule (insrc-tauri/src/kube.rs) with definitions forClusterClient,PortForwardSession, andPortForwardStatus, plus implementations of actual Kubernetes port-forwarding.[BLOCKER] src-tauri/src/commands/kube.rs:142–146 - The
list_port_forwardsfunction assumess.ports.first().copied().unwrap_or(0)ands.local_ports.first().copied().unwrap_or(0), butlocal_portsis initialized to[0]and never updated. This misleads the UI and user about actual port bindings.Evidence:
container_port: s.ports.first().copied().unwrap_or(0), local_port: s.local_ports.first().copied().unwrap_or(0),Fix: Ensure
local_portsis updated upon successful binding (e.g., after spawning a subprocess), and use the real bound port.[BLOCKER] src-tauri/src/commands/kube.rs:23 -
extract_server_urlonly extracts the server URL from the first cluster in the kubeconfig, ignoring possible multiple clusters. If the kubeconfig references a different cluster, this will be incorrect or misleading.Evidence:
let cluster = &clusters[0];Fix: Document that only the first cluster is used, or support multiple clusters by allowing the user to select context/cluster in the UI.
[WARNING] src-tauri/src/commands/kube.rs:151 -
stop_port_forwardcallssession.stop()butsession.stop()is not defined or implemented in the providedkube.rsfile or any supporting module. There is no actual termination logic.Evidence:
session.stop();Fix: Implement a
stop()method onPortForwardSessionthat terminates the underlying process or connection (e.g., send SIGTERM to a spawnedkubectlprocess).[WARNING] src-tauri/src/commands/kube.rs:179-181 -
add_clusterdoes not validate the kubeconfig format beyond checking top-level keys; malformed or invalid cluster config will not be caught until later runtime (e.g., during port-forward attempts).Evidence:
serde_yaml::from_str(content)is used without validation of cluster/server credentials or TLS settings.Fix: Add validation for required kubeconfig fields (e.g.,
server,certificate-authority-data,token, etc.), and warn or error if essential authentication fields are missing.[WARNING] src/components/Kubernetes/PortForwardForm.tsx:39-42 - The
loadClusterseffect runs every timeisOpenistrue, butclustersstate is not reset on close; stale clusters can persist if multiple sessions are opened.Evidence:
React.useEffect(() => { if (isOpen) { loadClusters(); } }, [isOpen]);Fix: Add cleanup to reset
clustersstate on close, or guardloadClusterswith a ref to avoid duplicate calls.Verdict: REQUEST CHANGES
Automated PR Review (qwen3-coder-next via liteLLM):\n\nSummary
The PR introduces Kubernetes management GUI components and corresponding Rust/Tauri backend logic. A critical data race and logic flaw exists in port forward session handling due to missing actual
kubectl port-forwardprocess spawning and incorrect session state initialization, which will cause runtime failures and incorrect UI behavior.Findings
[BLOCKER] src-tauri/src/commands/kube.rs:163-183 -
start_port_forwardcreates aPortForwardSessionwithkubectl_child: Noneandstatus: Active, but never actually spawns akubectl port-forwardprocess or updates the session with the real child process or assigned local port. This leads tostop_port_forwardanddelete_port_forwardoperating on invalid state andPortForwardResponsealways reportslocal_port: 0.Evidence:
[BLOCKER] src-tauri/src/kube/portforward.rs:29-40 -
PortForwardSession::stop()andDropimplementation rely onkubectl_childbeing Some, butkubectl_childisNonein all currentstart_port_forwardusages, makingstop()andDropeffectively no-ops despite reporting status as "Stopped" or "Active". This breaks lifecycle management and cleanup.Evidence:
[WARNING] src-tauri/src/kube/portforward.rs:70-79 -
Dropimplementation does not handlekubectl_childbeingNone, and also lacks any logic to clean up port mappings or update server-side tracking if actual port-forwarding were implemented. While not yet critical due to missingkubectl_childassignment, it indicates incomplete resource management design.Evidence:
[WARNING] src-tauri/src/commands/kube.rs:76-97 -
extract_server_urlextracts only the first cluster's server URL, ignoring that kubeconfigs can have multiple clusters and the context may point to a specific cluster. This will incorrectly use the wrong cluster URL if multiple clusters are present.Evidence:
Verdict: REQUEST CHANGES
Automated PR Review (qwen3-coder-next via liteLLM):\n\nSummary
The Kubernetes management GUI components introduce new Tauri commands and React components for cluster and port-forward management. A critical logic flaw exists in port-forward session handling where
local_portis always reported as 0 instead of being dynamically assigned, andkubectlprocess lifecycle management is missing actual execution logic, rendering port forwarding non-functional.Findings
[BLOCKER] src-tauri/src/commands/kube.rs:209 -
start_port_forwardcommand returnslocal_port: 0hardcoded without actually starting a port-forward session or resolving a real local port.Evidence:
Fix: Implement dynamic port assignment (e.g., by binding to port 0 and querying
local_port), or defer reporting until actual port binding occurs.[BLOCKER] src-tauri/src/kube/portforward.rs:40-75 -
PortForwardSession::new()initializes session metadata but never spawns akubectl port-forwardsubprocess;kubectl_childremainsNone, making actual port forwarding impossible.Evidence:
Fix: Implement
kubectl port-forwardprocess spawning inPortForwardSession::new(), store child process inkubectl_child, and update status accordingly.[WARNING] src-tauri/src/kube/portforward.rs:58-66 & 68-76 -
Dropandstop()handlers assumekubectl_childcontains a valid process, but due to missing initialization innew(), they do nothing in practice, risking orphanedkubectlprocesses if this were implemented later.Evidence:
Fix: Ensure
kubectl_childis properly assigned andStoplogic executes only on valid child handles.[WARNING] src-tauri/src/commands/kube.rs:62-66 - Cluster server URL is extracted only from the first cluster in kubeconfig; multi-cluster kubeconfigs are silently truncated.
Evidence:
Fix: Extract and surface all clusters, or clearly document and warn if only the first is supported.
[WARNING] src-tauri/src/commands/kube.rs:305 -
list_port_forwardsassumes every session has at least one port (unwrap_or(0)), but this is a weak contract if future changes allow zero ports.Evidence:
Fix: Validate invariants or surface port lists explicitly.
Verdict: REQUEST CHANGES
Blocker-level issues prevent port-forwarding from functioning at all. These must be resolved before merging. Additionally, multi-cluster kubeconfig handling should be clarified.
Automated PR Review (qwen3-coder-next via liteLLM):\n\nSummary
The PR introduces Kubernetes management GUI components with Tauri backend support. A critical issue is identified: port forwarding does not actually start
kubectl port-forwardprocesses, only recording metadata without spawning the underlying command, meaning port forwards will appear active but never function. Additionally, there is a potential panic risk inPortForwardSession::drop()due to unsafeMutex::lock().unwrap()usage.Findings
[BLOCKER] src-tauri/src/kube/portforward.rs:37-54 -
PortForwardSession::newcreates a session but never spawns akubectl port-forwardprocess or stores akubectl_child;kubectl_childremainsNone, sostop()andDropcannot terminate the actual process.Evidence:
Fix: Implement actual kubectl invocation in a new
start()method and assignkubectl_childto the spawned child process.[BLOCKER] src-tauri/src/kube/portforward.rs:60-71,73-81 -
Dropimplementation andstop()useunwrap()onMutex::lock(), causing potential panic if the mutex is poisoned.Evidence:
Fix: Replace
.unwrap()with safe.map_err(|_| ...)orunwrap_or_else()to gracefully handle poisoned locks.[WARNING] src-tauri/src/commands/kube.rs:140-148,161-166 -
start_port_forwardandstop_port_forward/delete_port_forwardcommands do not interact with theAppState::refresh_registry(declared in lib.rs) or track dynamic local ports, yet the frontend shows"local_port: 0"andpendingstatus—suggesting port assignment is incomplete.Evidence:
Evidence:
Fix: Assign an actual free port using
std::net::TcpListener::bind("127.0.0.1:0")and store it inlocal_ports.[WARNING] src-tauri/src/commands/kube.rs:76-95,100-121 -
extract_contextandextract_server_urlassume kubeconfig has exactly one context and one cluster, ignoring multi-cluster kubeconfigs or non-first context selection.Evidence:
Fix: Allow user to select context/cluster from list, or at least warn if kubeconfig has multiple.
[WARNING] src-tauri/src/commands/kube.rs:41 -
add_clusterreturnsClusterInfobut never validates that theidis unique before insertion; duplicate IDs will silently overwrite existing clients.Evidence:
Fix: Check for duplicate ID before insertion and return an error if present.
[WARNING] tests/unit/kubernetesCommands.test.ts:126-135 - Unit tests mock Tauri
invokebut do not test failure cases (e.g., invalid kubeconfig, cluster not found, port in use), risking untested real-world failure paths.Evidence:
Fix: Add tests for error cases with
mockRejectedValueand verify error handling in frontend.Verdict: REQUEST CHANGES
Automated PR Review (qwen3-coder-next via liteLLM):\n\nSummary
The PR introduces Kubernetes management functionality via a GUI with frontend components and backend commands. Several critical issues were identified: the
kubeconfig_contentis stored in memory without encryption or secure handling,kubectlsubprocess management is unsafe (no proper cleanup on errors or crashes), and the port-forward session does not uselocal_portcorrectly, causing misleading UI behavior.Findings
[BLOCKER] src-tauri/src/commands/kube.rs:89 -
kubeconfig_contentis stored inArc<String>and kept in memory acrossClusterClientinstances, exposing sensitive credentials in process memory without secure handling.Evidence:
let kubeconfig_arc = Arc::new(kubeconfig_content.clone());(line 89) andpub kubeconfig_content: Arc<String>inClusterClient(src-tauri/src/kube/client.rs:13)Fix: Do not store full kubeconfig in memory; instead, only store minimal metadata and use secure credential vault or encrypted storage with runtime-only in-memory access via temporary files, with explicit cleanup.
[WARNING] src-tauri/src/kube/portforward.rs:47 -
kubectl_childis never populated (the actualkubectl port-forwardsubprocess is not started), yetDropandstop()assume it exists and attempt to kill it.Evidence:
kubectl_child: None(line 47), andif let Some(child_mutex) = &self.kubectl_child { ... let _ = child.kill(); }in bothstop()(lines 57–61) andDrop(lines 72–78)Fix: Implement actual
kubectl port-forwardprocess spawning inPortForwardSession::new()and populatekubectl_child, or refactor session lifecycle to remove kill logic until process is created.[WARNING] src-tauri/src/commands/kube.rs:168–175 &
src-tauri/src/kube/portforward.rs:48–local_portis hardcoded to 0 inPortForwardResponse, misleading frontend UI.Evidence:
local_port: 0,instart_port_forward(line 168) andlocal_port: s.local_ports.first().copied().unwrap_or(0)(lines 196–197), whilelocal_portsinPortForwardSessionis initialized tovec![0]inPortForwardSession::new(src-tauri/src/kube/portforward.rs:48)Fix: Either properly determine and assign the local port used by the subprocess, or refactor API to mark port pending or unavailable until resolved.
[WARNING] tests/unit/kubernetesCommands.test.ts:17 – Test mocks do not cover
invokefailures, hiding potential error handling gaps in production code.Evidence: All tests use
mockResolvedValueonly, with no test cases formockRejectedValue(e.g., network errors, kubeconfig parse failures)Fix: Add test cases for error flows in all commands, especially
addClusterCmd,startPortForwardCmd.[BLOCKER] src-tauri/src/lib.rs:91–94 – Port-forwards and clusters are stored in
Arc<Mutex<HashMap>>, but no garbage collection or cleanup logic on error/exit leads to potential resource leaks or stale sessions.Evidence:
clusters: Arc::new(tokio::sync::Mutex::new(std::collections::HashMap::new())),(line 91) andport_forwards: Arc::new(tokio::sync::Mutex::new(std::collections::HashMap::new())),(line 92) with no cleanup hooks or TTL logicFix: Implement automatic cleanup of stopped/error sessions (e.g., via polling or event-based handler), or store sessions durably (e.g., in DB) with health checks.
Verdict: REQUEST CHANGES