Skip to content

Introduce kubectl and kubeconfig overrides#365

Open
metalgrid wants to merge 20 commits into
TabularisDB:mainfrom
metalgrid:enh/k8s-advanced-kubectl-settings
Open

Introduce kubectl and kubeconfig overrides#365
metalgrid wants to merge 20 commits into
TabularisDB:mainfrom
metalgrid:enh/k8s-advanced-kubectl-settings

Conversation

@metalgrid

Copy link
Copy Markdown
Contributor

Overview

Adds the ability to override the kubectl binary path and KUBECONFIG file per
Kubernetes connection, plus on-blur validation of those paths in both the K8s
connections modal and the new-connection modal's inline K8s flow.

What's new

Backend (Rust)

  • New optional fields kubectl_path / kubeconfig_path on K8sConnection and
    K8sConnectionInput models, persisted to k8s_connections.json.
  • K8sCommandOptions plumbing through the tunnel, discovery commands (contexts,
    namespaces, resources, resource ports), connection test, and MCP connection
    expansion — so overrides take effect for port-forward tunnels and the cascading
    discovery dropdowns.
  • New Tauri command validate_k8s_path_cmd that validates:
    • kubectl: the path exists, is a file, and is executable (resolves bare names
      like kubectl via PATH, honors PATHEXT on Windows).
    • kubeconfig: the path exists and is a file.
  • kubectl_command now preflight-validates explicit overrides before spawning kubectl,
    giving clear errors instead of cryptic spawn failures.
  • Path helpers handle ~ expansion and PATH lookup.

Frontend (TS/React)

  • Advanced collapsible "kubectl settings" section in both K8sConnectionsModal and
    NewConnectionModal (inline K8s) with kubectl Path and Kubeconfig Path inputs.
  • On-blur validation with live status: validating spinner, green border + tick when
    valid, red border + error message when invalid.
  • Discovery dropdowns reset context/namespace/resource whenever the applied
    kubectl/kubeconfig paths change, and Save/Test are blocked until paths are valid
    (with a prompt to re-select context/namespace/resource when paths change).
  • validateK8sPath utility + K8sCommandOptions threaded through all K8s discovery/test
    calls.

i18n

  • New keys (kubectlPath, kubeconfigPath, placeholders, advancedSettings,
    validation/reset messages) across all 8 locales (en, it, de, es, fr, ja, ru, zh).

Tests

  • Rust unit tests for path validation (moved to k8s_tunnel/tests.rs per project Rust
    rules): empty paths valid, missing file, directory rejected,
    executable/non-executable file, Windows/Unix handling.
  • Frontend tests for validateK8sPath invoke contract; updated NewConnectionModal test
    for the added k8sCommandOptions arg.

Provides native tooling for resolving issues like #323.


setPathValidation({ status: "validating", value: trimmedPath, message: null });
try {
await validateK8sPath(trimmedPath, kind);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WARNING: Stale async validation can overwrite current path validation state

validateAdvancedPath does not cancel or ignore in-flight validateK8sPath calls. If the user edits a path while a previous validation is still pending, the older promise can resolve last and overwrite the validation state with an out-of-date value/status.


Reply with @kilocode-bot fix it to have Kilo Code address this issue.

try {
await validateK8sPath(trimmedPath, kind);
setPathValidation({ status: "valid", value: trimmedPath, message: null });
setValidationError(null);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WARNING: Successful path validation clears unrelated form errors

Calling setValidationError(null) here clears any higher-level validation error (e.g., missing name) while the user is still editing the form.


Reply with @kilocode-bot fix it to have Kilo Code address this issue.

try {
setNamespaces(await getK8sNamespaces(context));
} catch {
setNamespaces(await getK8sNamespaces(context, getCommandOptions()));

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WARNING: Discovery effect has no cancellation guard

The namespace-loading effect starts an async request without a cancellation/ignore flag. When applyAdvancedPaths resets the dropdowns after a path change, an in-flight request can still resolve and repopulate namespaces with stale data.


Reply with @kilocode-bot fix it to have Kilo Code address this issue.

setDiscoveryError(null);
};

const applyAdvancedPaths = useCallback(() => {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WARNING: applyAdvancedPaths leaves the old port selected

When kubectl/kubeconfig paths change, this function resets context, namespace, and resourceName but leaves port and isPortOverridden untouched. After re-selecting a new resource, the previously chosen port can be saved for the wrong resource.


Reply with @kilocode-bot fix it to have Kilo Code address this issue.


setPathValidation({ status: "validating", value: trimmedPath, message: null });
try {
await validateK8sPath(trimmedPath, kind);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WARNING: Stale async validation can overwrite current path validation state

validateK8sAdvancedPath does not cancel or sequence in-flight validateK8sPath calls. A slower, stale validation result can finish last and display the wrong validity icon/message for the current input.


Reply with @kilocode-bot fix it to have Kilo Code address this issue.

);

// ── K8s cascading dropdown loading ──
useEffect(() => {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WARNING: Duplicate K8s context fetch on modal open

This effect and the init effect at line 889 both call getK8sContexts when the modal opens. Because the init effect sets saved kubectl/kubeconfig paths asynchronously, the first fetch uses stale k8sCommandOptions and a second fetch with the correct options follows, causing duplicate requests and a potential spurious discovery error.


Reply with @kilocode-bot fix it to have Kilo Code address this issue.


useEffect(() => {
if (formData.k8s_context) {
loadK8sNamespacesList(formData.k8s_context);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WARNING: Discovery effect has no cancellation guard

The namespace-loading effect starts an async request without a cancellation/ignore flag. Rapid context switches can leave a stale namespace list on screen if an earlier request resolves after a later one.


Reply with @kilocode-bot fix it to have Kilo Code address this issue.

);
} else {
setK8sResources([]);
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WARNING: Discovery effect has no cancellation guard

The resource-loading effect starts an async request without a cancellation/ignore flag. Rapid context/namespace/type changes can leave a stale resource list on screen if an earlier request resolves after a later one.


Reply with @kilocode-bot fix it to have Kilo Code address this issue.

@kilo-code-bot

kilo-code-bot Bot commented Jun 23, 2026

Copy link
Copy Markdown
Contributor

Code Review Summary

Status: No Issues Found | Recommendation: Merge

Files Reviewed (2 files)
  • src/components/modals/K8sConnectionsModal.tsx
  • src/components/modals/NewConnectionModal.tsx
Previous Review Summaries (2 snapshots, latest commit 0d7e4c3)

Current summary above is authoritative. Previous snapshots are kept for context only.

Previous review (commit 0d7e4c3)

Status: 2 Issues Found | Recommendation: Address before merge

Overview

Severity Count
CRITICAL 2
WARNING 0
SUGGESTION 0
Issue Details (click to expand)

CRITICAL

File Line Issue
src/components/modals/K8sConnectionsModal.tsx 448 isLatest guard is bypassed because it is not invoked
src/components/modals/NewConnectionModal.tsx 667 isLatest guard is bypassed because it is not invoked
Files Reviewed (6 files)
  • src/components/modals/K8sConnectionsModal.tsx - 1 issue
  • src/components/modals/NewConnectionModal.tsx - 1 issue
  • src/hooks/useLatestAsync.ts - 0 issues
  • tests/components/modals/K8sConnectionsModal.test.tsx - 0 issues
  • tests/components/modals/NewConnectionModal.test.tsx - 0 issues
  • tests/hooks/useLatestAsync.test.ts - 0 issues

Fix these issues in Kilo Cloud

Previous review (commit f48590c)

Status: 8 Issues Found | Recommendation: Address before merge

Overview

Severity Count
CRITICAL 0
WARNING 8
SUGGESTION 0
Issue Details (click to expand)

WARNING

File Line Issue
src/components/modals/K8sConnectionsModal.tsx 434 Stale async validation can overwrite current path validation state
src/components/modals/K8sConnectionsModal.tsx 436 Successful path validation clears unrelated form errors
src/components/modals/K8sConnectionsModal.tsx 142 Discovery effect has no cancellation guard
src/components/modals/K8sConnectionsModal.tsx 347 applyAdvancedPaths leaves the old port selected
src/components/modals/NewConnectionModal.tsx 662 Stale async validation can overwrite current path validation state
src/components/modals/NewConnectionModal.tsx 467 Duplicate K8s context fetch on modal open
src/components/modals/NewConnectionModal.tsx 484 Discovery effect has no cancellation guard
src/components/modals/NewConnectionModal.tsx 499 Discovery effect has no cancellation guard
Files Reviewed (20 files)
  • src-tauri/src/commands.rs
  • src-tauri/src/k8s_tunnel.rs
  • src-tauri/src/k8s_tunnel/tests.rs
  • src-tauri/src/lib.rs
  • src-tauri/src/mcp/mod.rs
  • src-tauri/src/models.rs
  • src-tauri/src/plugins/driver.rs
  • src/components/modals/K8sConnectionsModal.tsx
  • src/components/modals/NewConnectionModal.tsx
  • src/i18n/locales/de.json
  • src/i18n/locales/en.json
  • src/i18n/locales/es.json
  • src/i18n/locales/fr.json
  • src/i18n/locales/it.json
  • src/i18n/locales/ja.json
  • src/i18n/locales/ru.json
  • src/i18n/locales/zh.json
  • src/utils/k8s.ts
  • tests/components/modals/NewConnectionModal.test.tsx
  • tests/utils/k8s.test.ts

Fix these issues in Kilo Cloud


Reviewed by kimi-k2.7-code · Input: 48.6K · Output: 7.7K · Cached: 440.8K

return run(kind, async (isLatest) => {
try {
await validateK8sPath(trimmedPath, kind);
if (isLatest) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CRITICAL: isLatest guard is bypassed because it is not invoked

useLatestAsync passes isLatest as a function () => boolean. Checking it as a truthy value (if (isLatest)) is always true, so stale validateK8sPath results can still overwrite the current path validation state and call applyAdvancedPaths. The same bug occurs on lines 451 and 456.

Suggested change
if (isLatest) {
if (isLatest()) {

Reply with @kilocode-bot fix it to have Kilo Code address this issue.

return run(kind, async (isLatest) => {
try {
await validateK8sPath(trimmedPath, kind);
if (isLatest) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CRITICAL: isLatest guard is bypassed because it is not invoked

useLatestAsync passes isLatest as a function () => boolean. Checking it as a truthy value (if (isLatest)) is always true, so stale validateK8sPath results can still overwrite the current path validation state and call applyK8sAdvancedFields. The same bug occurs on lines 670 and 675.

Suggested change
if (isLatest) {
if (isLatest()) {

Reply with @kilocode-bot fix it to have Kilo Code address this issue.

debba and others added 8 commits June 24, 2026 09:57
* feat: add rowsToCSVWithHeaders function to include headers in CSV output

* feat: enhance copy functionality to include headers in CSV output

* feat: enhance copy functionality to handle errors and include headers in clipboard output

* feat: add option to toggle CSV headers when copying

Add a csvIncludeHeaders setting (persisted in config.json) and a toolbar
toggle in the copy controls to choose whether copied CSV output includes
the column header row. Defaults to true. Threaded through MultiResultPanel,
StackedResultItem and ResultEntryContent down to DataGrid, with i18n keys
added across all 8 locales.

---------

Co-authored-by: Andrea Debernardi <andrea@debbaweb.it>
@metalgrid metalgrid force-pushed the enh/k8s-advanced-kubectl-settings branch from 0d7e4c3 to 4331d0a Compare June 24, 2026 06:58
@metalgrid

Copy link
Copy Markdown
Contributor Author

@kilocode-bot please review the new changes.

@kilo-code-bot

kilo-code-bot Bot commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

To use Kilo from GitHub you first need to link your GitHub account to Kilo. Link your Kilo account to continue. After linking, mention me again in this issue or pull request.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants