fix(kube): bridge kubeconfig storage to in-memory cluster map and fix UI issues #79

Merged
sarman merged 2 commits from fix/kube-cluster-connection into master 2026-06-07 23:32:01 +00:00
Owner

Summary

  • Cluster not found (GUID error): All kube resource commands look up state.clusters (in-memory map) which was never populated from the kubeconfig_files DB table. Added connect_cluster_from_kubeconfig Tauri command that decrypts and loads the stored kubeconfig into state.clusters. Called on page load and on cluster change.
  • Dropdown selection has no effect: Same root cause — activating a kubeconfig only updated the DB is_active flag but never hydrated the in-memory client map.
  • GUID shown instead of cluster name: ClusterOverview displayed the raw UUID as the subtitle. Now accepts a clusterName prop (passed from kubeconfig.context) and renders it instead. ClusterDetails similarly changed to show kubeconfig.context in the header.
  • Bell icon not clickable: Hotbar bell button had no onClick handler. Added optional onNotifications / notificationCount props. Badge count is now dynamic rather than hardcoded. KubernetesPage wires up a notifications dialog showing active cluster context.

Test plan

  • Start app with an existing kubeconfig — Overview, Pods, Nodes etc. load without "Cluster not found" error
  • Select a different cluster from the dropdown — resources update to the new cluster
  • Cluster Overview/Details header shows context name (e.g. devops1-mgmt), not UUID
  • Click bell icon — notifications dialog opens and closes correctly
  • npm run test:run — 262 tests pass
  • cargo test — 331 tests pass
  • Zero TypeScript/lint/clippy errors
## Summary - **Cluster not found (GUID error)**: All kube resource commands look up `state.clusters` (in-memory map) which was never populated from the `kubeconfig_files` DB table. Added `connect_cluster_from_kubeconfig` Tauri command that decrypts and loads the stored kubeconfig into `state.clusters`. Called on page load and on cluster change. - **Dropdown selection has no effect**: Same root cause — activating a kubeconfig only updated the DB `is_active` flag but never hydrated the in-memory client map. - **GUID shown instead of cluster name**: `ClusterOverview` displayed the raw UUID as the subtitle. Now accepts a `clusterName` prop (passed from `kubeconfig.context`) and renders it instead. `ClusterDetails` similarly changed to show `kubeconfig.context` in the header. - **Bell icon not clickable**: `Hotbar` bell button had no `onClick` handler. Added optional `onNotifications` / `notificationCount` props. Badge count is now dynamic rather than hardcoded. `KubernetesPage` wires up a notifications dialog showing active cluster context. ## Test plan - Start app with an existing kubeconfig — Overview, Pods, Nodes etc. load without "Cluster not found" error - Select a different cluster from the dropdown — resources update to the new cluster - Cluster Overview/Details header shows context name (e.g. `devops1-mgmt`), not UUID - Click bell icon — notifications dialog opens and closes correctly - `npm run test:run` — 262 tests pass - `cargo test` — 331 tests pass - Zero TypeScript/lint/clippy errors
sarman added 1 commit 2026-06-07 22:58:05 +00:00
fix(kube): bridge kubeconfig storage to in-memory cluster map and fix UI issues
Some checks failed
PR Review Automation / review (pull_request) Has been cancelled
Test / frontend-tests (pull_request) Successful in 1m37s
Test / frontend-typecheck (pull_request) Successful in 1m46s
Test / rust-fmt-check (pull_request) Failing after 10m52s
Test / rust-clippy (pull_request) Successful in 12m34s
Test / rust-tests (pull_request) Successful in 14m8s
ef3709ffe9
Resolves four bugs in the Kubernetes management interface:

1. **Cluster not found error** - commands/kube.rs::list_nodes (and all other
   kube resource commands) look up clusters from state.clusters (in-memory map)
   which was never populated from the kubeconfig_files table. Add a new
   connect_cluster_from_kubeconfig Tauri command that reads the encrypted
   kubeconfig from the DB, decrypts it, and inserts a ClusterClient into
   state.clusters. Wire it into KubernetesPage on initial load and cluster
   change so the in-memory map is always populated before any kube command runs.

2. **Dropdown selection has no effect** - same root cause as #1; activating a
   kubeconfig only updated the DB flag but never loaded the client into memory.
   handleClusterChange now calls connectClusterFromKubeconfigCmd after activation.

3. **GUID shown instead of cluster name** - ClusterOverview displayed the raw
   internal UUID as the page subtitle. Now accepts a clusterName prop (populated
   from kubeconfig.context) and renders that instead. ClusterDetails similarly
   changed to show kubeconfig.context in the header, not the UUID.

4. **Bell icon not clickable** - Hotbar bell button had no onClick handler. Add
   optional onNotifications / notificationCount props; badge count is now dynamic
   rather than hardcoded. KubernetesPage wires up a notifications dialog showing
   active cluster context and a link to the Events section.

All changes follow TDD: failing tests written first, then implementation.
sarman added 1 commit 2026-06-07 23:15:50 +00:00
fix(classifier): fix 3 safety bugs, extract const arrays, make tier UI dynamic
All checks were successful
Test / frontend-typecheck (pull_request) Successful in 1m36s
Test / frontend-tests (pull_request) Successful in 1m40s
PR Review Automation / review (pull_request) Successful in 10m27s
Test / rust-fmt-check (pull_request) Successful in 11m4s
Test / rust-clippy (pull_request) Successful in 12m50s
Test / rust-tests (pull_request) Successful in 14m20s
7d8d5bdbba
Bug 1 — Dead multi-word tier3 entries / missing single-token commands
  parse_single_command() extracts only the first token as `command`, so
  multi-word entries like "kill -9", "init 0", "service stop" in the tier3
  array never matched. Adding the single-token forms "kill", "pkill",
  "killall", "init" to TIER3_COMMANDS ensures these commands are always
  denied. Removed all dead multi-word entries.

Bug 2 — systemctl Tier 1 special case was dead code
  systemctl was not in tier1_general, so the block that was supposed to
  auto-execute `systemctl status` never ran. Moved systemctl handling into
  its own block (TIER1_SYSTEMCTL_SUBCOMMANDS / TIER2_SYSTEMCTL_SUBCOMMANDS)
  evaluated before the general tier checks. status, is-active, is-enabled,
  list-units, list-unit-files → Tier 1; all others → Tier 2.

Bug 3 — ldapmodify / ldapdelete / ldapadd misclassified as Tier 1
  Both appeared in the old tier1_general and tier2_general arrays; the tier1
  check ran first, so LDAP write operations auto-executed. Removed them from
  tier1. ldapsearch (read-only) remains Tier 1.

Dynamic Safety Architecture UI
  Extracted all tier classification arrays to module-level pub const slices
  (TIER3_COMMANDS, TIER1_KUBECTL_SUBCOMMANDS, etc.) so both the classifier
  logic and a new get_classifier_rules() Tauri command share a single source
  of truth. ShellExecution.tsx now calls getClassifierRulesCmd() on mount and
  renders the actual command lists in collapsible per-tier cards — any change
  to the const arrays is automatically reflected in the UI with no manual
  documentation update needed.

Also fixes the cargo fmt CI failure introduced in the previous commit
(ClusterClient::new call reformatted to a single line).
sarman reviewed 2026-06-07 23:26:16 +00:00
sarman left a comment
Author
Owner

Automated PR Review (qwen36-35b-a3b-nvfp4 via liteLLM):\n\nSummary
The PR introduces a connect_cluster_from_kubeconfig command to bridge encrypted kubeconfig storage with an in-memory cluster map. A critical logic error in KubernetesPage.tsx causes the application to attempt to connect every stored kubeconfig on startup, potentially causing unnecessary API calls, errors, or state pollution for all users. Additionally, the classifier.rs refactor removes comments explaining the safety rationale for Tier 3 commands, increasing the risk of future regression.

Findings

  • [WARNING] src/pages/Kubernetes/KubernetesPage.tsx:262 - Startup logic iterates over ALL kubeconfigs to connect them, rather than just the active one. This is likely unintended behavior causing "failed to load" noise for inactive clusters and potential race conditions.
    Evidence: const activeConfig = kubeconfigsData.find((c) => c.is_active); is retrieved but ignored. The subsequent loop for (const config of kubeconfigsData) { await connectClusterFromKubeconfigCmd(config.id).catch(() => {}); } connects everything.
    Fix: Replace the loop with a check for activeConfig and only connect that specific ID.

  • [SUGGESTION] src-tauri/src/shell/classifier.rs - Removal of inline comments explaining why specific commands (e.g., kill, init) are Tier 3 reduces code maintainability and makes it easier for future developers to accidentally revert the "Bug fix" safety hardening.
    Evidence: The diff removes lines like // Linux — process / system control (all destructive without subcommand context) and replaces them with minimal data structures.
    Fix: Add brief comments to the constant arrays explaining the classification rationale (e.g., "Destructive: kills processes, no recovery").

Verdict: APPROVE WITH COMMENTS

Automated PR Review (qwen36-35b-a3b-nvfp4 via liteLLM):\n\n**Summary** The PR introduces a `connect_cluster_from_kubeconfig` command to bridge encrypted kubeconfig storage with an in-memory cluster map. A critical logic error in `KubernetesPage.tsx` causes the application to attempt to connect *every* stored kubeconfig on startup, potentially causing unnecessary API calls, errors, or state pollution for all users. Additionally, the `classifier.rs` refactor removes comments explaining the safety rationale for Tier 3 commands, increasing the risk of future regression. **Findings** - [WARNING] src/pages/Kubernetes/KubernetesPage.tsx:262 - Startup logic iterates over ALL kubeconfigs to connect them, rather than just the active one. This is likely unintended behavior causing "failed to load" noise for inactive clusters and potential race conditions. Evidence: `const activeConfig = kubeconfigsData.find((c) => c.is_active);` is retrieved but ignored. The subsequent loop `for (const config of kubeconfigsData) { await connectClusterFromKubeconfigCmd(config.id).catch(() => {}); }` connects everything. Fix: Replace the loop with a check for `activeConfig` and only connect that specific ID. - [SUGGESTION] src-tauri/src/shell/classifier.rs - Removal of inline comments explaining why specific commands (e.g., `kill`, `init`) are Tier 3 reduces code maintainability and makes it easier for future developers to accidentally revert the "Bug fix" safety hardening. Evidence: The diff removes lines like `// Linux — process / system control (all destructive without subcommand context)` and replaces them with minimal data structures. Fix: Add brief comments to the constant arrays explaining the classification rationale (e.g., "Destructive: kills processes, no recovery"). **Verdict**: APPROVE WITH COMMENTS
sarman merged commit a626f053ed into master 2026-06-07 23:32:01 +00:00
sarman deleted branch fix/kube-cluster-connection 2026-06-07 23:32:02 +00:00
Sign in to join this conversation.
No reviewers
No Milestone
No project
No Assignees
1 Participants
Notifications
Due Date
The due date is invalid or out of range. Please use the format 'yyyy-mm-dd'.

No due date set.

Dependencies

No dependencies set.

Reference: sarman/tftsr-devops_investigation#79
No description provided.