Skip to content

fix(k8s,ui): resolve RBAC and full-flow reliability issues - #4

Open
clamshell2000 wants to merge 2 commits into
p10node:mainfrom
clamshell2000:fix/confirmed-production-findings
Open

fix(k8s,ui): resolve RBAC and full-flow reliability issues#4
clamshell2000 wants to merge 2 commits into
p10node:mainfrom
clamshell2000:fix/confirmed-production-findings

Conversation

@clamshell2000

@clamshell2000 clamshell2000 commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Fix RBAC scoping, error visibility, and context handling in K10s

Summary

This PR resolves the confirmed reliability and safety issues found during full-flow testing of K10s.

The main changes improve namespace-scoped RBAC support, Kubernetes error reporting, context switching, Service port-forwarding, Custom Resource states, and mock data isolation. It also prevents resource actions from being triggered while the context chooser is active.

Changes

Context chooser safety

Resource shortcuts were still active behind the :ctx chooser. Pressing uppercase D could open a deletion dialog for a Pod hidden behind the context list.

Resource-specific actions are now blocked while the context chooser is active. Context selection and navigation continue to work normally.

Namespace-scoped RBAC

K10s previously used cluster-wide informers for namespaced views. A RoleBinding-only user could list Pods with:

kubectl -n <namespace> get pods

…but K10s remained on loading pods… because its cluster-wide LIST/WATCH request was forbidden.

K10s now creates namespace-scoped informer factories lazily and reserves cluster-wide informers for cluster-scoped resources or explicit all views. A failed all-namespace request is not reused after returning to an authorized namespace.

Visible LIST/WATCH errors

When a restricted user selected :ns all, Kubernetes returned Forbidden, but K10s displayed an indefinite loading spinner.

LIST/WATCH failures are now tracked per resource kind and namespace scope. The UI displays the original Kubernetes error with an RBAC and namespace hint.

Transient errors are cleared after a successful synchronization, and an error from all does not leak into an authorized namespace.

Named Service targetPort

Service forwarding did not correctly resolve named targets such as:

ports:
  - port: 8080
    targetPort: http

K10s now uses Kubernetes-compatible Service port resolution against the selected Pod's container ports. Unknown named ports and selectorless Services return explicit errors instead of creating broken forwarding listeners.

Custom Resource loading states

A Custom Resource view could return to loading… after deleting its final object.

The polling cache now distinguishes between:

  • loading;
  • successfully loaded with resources;
  • successfully loaded with zero resources;
  • failed discovery or list requests.

Successful empty results now display no resources found. CRD discovery and per-resource list failures are surfaced to the user.

DaemonSet actions

DaemonSets previously advertised Scale even though the backend rejected the operation.

DaemonSets now have a dedicated action list without Scale, while retaining Describe, YAML, Logs, Rollout Restart, Edit, and Delete.

Mock source isolation

Mock sources shared mutable package-level fixture data. Deleting or scaling resources in one instance could affect later instances and repeated tests.

Every mock source now owns a deep copy of its resources, nested rows, and node state. Reads and mutations are synchronized.

Quiet shell fallback

Opening a shell in an Alpine-based container printed:

/bin/sh: bash: not found

K10s now checks for Bash silently and directly executes the available shell:

command -v bash >/dev/null 2>&1 && exec bash || exec sh

Cold-cache namespace detection

The first command containing a namespace could interpret that namespace as row-filter text while the namespace informer was still cold.

K10s now performs a bounded namespace lookup during cold-cache validation. For restricted users who cannot list Namespace objects, the namespace configured in their kubeconfig context is still recognized.

Direct context switching from Demo

The :ctx chooser could leave Demo mode, but the equivalent direct command:

:ctx <real-context>

…reported that the context did not exist.

The chooser and direct command now share the same merged context list, including backend contexts, kubeconfig contexts, and the Demo context. A stale chooser filter no longer affects direct context validation.

Reproduction and verification

Restricted RBAC flow

  1. Create a service account with Pod access through a namespace Role and RoleBinding.

  2. Verify namespace access succeeds:

    kubectl --kubeconfig=<restricted-config> \
      -n <authorized-namespace> get pods
  3. Verify cluster-wide access is forbidden:

    kubectl --kubeconfig=<restricted-config> get pods --all-namespaces
  4. Start K10s with the restricted kubeconfig.

  5. Confirm the authorized namespace loads normally.

  6. Run :ns all.

  7. Confirm K10s displays the Kubernetes Forbidden error instead of spinning indefinitely.

  8. Return to the authorized namespace and confirm the Pod loads again.

Demo context flow

  1. Start K10s with a valid real kubeconfig context.
  2. Run /demo.
  3. Run :ctx <real-context> directly.
  4. Confirm K10s leaves Demo and connects to the real context without opening the chooser.

Context chooser safety flow

  1. Open a resource view containing a Pod.
  2. Run :ctx.
  3. Press uppercase D.
  4. Confirm no hidden Pod deletion dialog is opened and no resource action is executed.

Tests

The final changes passed:

go test -count=1 ./...
go test -count=10 ./...
go vet ./...
go test -race -count=1 ./...
git diff --check

Focused RBAC, load-error, Custom Resource, and Demo-context regression tests passed 20 consecutive runs.

Live testing used:

  • a three-node Kind cluster;
  • a secondary one-node Kind cluster;
  • a namespace-scoped service account;
  • an explicit forbidden all-namespace control;
  • direct context switching from Demo;
  • all 30 built-in resource entry points.

The restricted identity loaded its authorized Pod, displayed the expected Kubernetes error for :ns all, and recovered immediately after returning to its authorized namespace.

The context chooser preserves the resource selected in the underlying table so k10s can return there after reconnecting. Built-in action and plugin shortcuts remained active, so pressing D in :ctx could open a delete confirmation for an unseen pod and, if confirmed, send that delete to the currently connected cluster.

Reproduce before this fix in the safe offline renderer with: go run ./cmd/shot 120 36 ':,ctx,enter,D'. The resulting context frame incorrectly contains a Delete po confirmation for the hidden pod.

Block every built-in resource action while modeContexts is active, hide and block ordinary and override plugins, and replace the stale Actions pane with an actions-paused context hint. Add regression tests for all built-in action hotkeys, plugin variants, and the rendered pane.

After this fix the same renderer sequence remains in the context chooser without a modal, while go run ./cmd/shot 120 36 'D' still opens the normal pod deletion confirmation.

Verified with go test -count=1 ./..., go test -race -count=1 ./..., go vet ./..., gofmt -l ., and git diff --check.
Use namespace-scoped informers for least-privilege RBAC users and surface Kubernetes LIST/WATCH failures instead of leaving views in an indefinite loading state.

Also fix named Service targetPort resolution, Custom Resource empty states, DaemonSet actions, mock fixture isolation, quiet shell fallback, cold-cache namespace detection, and direct context switching from Demo. Add focused regression coverage for the confirmed findings.
@clamshell2000 clamshell2000 changed the title Fix/confirmed production findings fix(k8s,ui): resolve RBAC and full-flow reliability issues Sep 2, 2026
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.

1 participant