Drop the semver-major exclusion from the Dependabot auto-merge gate so
that major version PRs are also auto-approved and merged once CI passes,
matching the workflow already in place for minor and patch updates.
Interactive mode was launching fzf and handing it the parent TTY on fd
0, then relying on fzf to re-exec kubectx via FZF_DEFAULT_COMMAND to
obtain the candidate list. fzf never received the list on its stdin, so
on systems where fzf did not honor FZF_DEFAULT_COMMAND the picker showed
no items and kubectx exited with 'you did not choose any of the
options'.
Build the candidate list in-process and pipe it directly to fzf's
stdin. This removes the self-re-exec, the $SHELL -c dependency, and the
TTY-plumbing hack on fd 0.
Fixes#500
The isUpgrade() check used exact string match (== "Upgrade") for the
Connection header value. A client sending "Connection: upgrade"
(lowercase) would bypass this check. While not exploitable in practice
(the Upgrade header check catches real upgrades), this hardens the
proxy with defense-in-depth.
Also adds a comprehensive security test suite covering jailbreak
attempts: method override smuggling, path traversal, dryRun parameter
injection, upgrade header smuggling, review endpoint spoofing, unusual
HTTP methods, concurrent request filtering, and credential leakage.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The readonly proxy now permits:
- K8s "review" POST endpoints (SubjectAccessReview, TokenReview, etc.)
that query auth state without persisting resources
- Requests with ?dryRun=All for server-side validation
Review endpoints are matched with anchored regexps pinned to
authorization.k8s.io and authentication.k8s.io API groups, preventing
spoofing via custom resources with the same name.
Refactors the handler into small, independently tested filter functions
(isUpgrade, isReadOnly, isNonMutatingPost, isDryRun) composed by a
checkRequest commander.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Document -r/--readonly flag with usage example
- Reorganize Examples into Usage section with kubectx/kubens subsections
- Each command example in its own code block
- Remove outdated 'written in bash' badge
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add description strings from bash scripts to Go help output
- Add -r/--readonly usage lines to kubectx help
- Reorder help to show -s/-r flags more prominently
- Normalize flag separators to comma-space consistently
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Introduces ReadonlyShellOp and InteractiveReadonlyShellOp that spawn
an isolated sub-shell routing kubectl traffic through the readonly
reverse proxy. The proxy blocks write operations while allowing reads.
- Extracts minimal kubeconfig, starts proxy, rewrites kubeconfig to
point at proxy, spawns shell with KUBECTX_READONLY_SHELL=1
- Proxy and temp files cleaned up on shell exit
- Flag parsing mirrors -s/--shell pattern with optional context arg
- Interactive fzf mode supported when no context specified
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Introduces a new internal/proxy package that provides a localhost HTTP
reverse proxy enforcing read-only access to the Kubernetes API server.
- Allows GET, HEAD, OPTIONS requests (kubectl get/describe/logs/top/watch)
- Blocks POST, PUT, DELETE, PATCH with metav1.Status 405 responses
- Blocks Connection: Upgrade requests (kubectl exec/cp/port-forward)
- Uses client-go transport for TLS/auth to the real API server
- Rewrites kubeconfig: server URL to proxy, strips auth, sets insecure-skip-tls-verify
- Appends [RO] suffix to context name in rewritten kubeconfig
- DEBUG=1 enables request/response logging
- Comprehensive test coverage for all proxy behavior
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
When `kubectx -s` (or `--shell`) is invoked without a context name and
fzf is available in an interactive terminal, launch fzf to let the user
pick a context, then start an isolated shell scoped to that selection.
This mirrors the existing behavior where `kubectx` with no arguments
launches fzf for context switching, and `kubectx -d` with no arguments
launches fzf for context deletion.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace shallow checkout + `git fetch --tags` with `fetch-depth: 0` so
GoReleaser has the full commit history between tags to generate release
notes.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
When kubens needs to query the Kubernetes API (e.g. to check if a
namespace exists), it builds a REST client from the in-memory
kubeconfig bytes using clientcmd.RESTConfigFromKubeConfig(). This
function has no knowledge of the kubeconfig file's location on disk,
so it cannot resolve relative paths in exec credential plugin commands
(e.g. `command: ../scripts/get-token.sh`). This causes a "no such file
or directory" error for users whose kubeconfig uses relative paths in
exec-based authentication.
The fix threads the kubeconfig file path through a new PathHinter
optional interface on ReadWriteResetCloser. When a file path is
available, newKubernetesClientSet now uses
clientcmd.NewNonInteractiveDeferredLoadingClientConfig with
ExplicitPath, which resolves relative paths relative to the kubeconfig
file's directory — matching kubectl's own behavior. The old
bytes-based fallback is preserved for in-memory configs (e.g. tests).
Fixes#488
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Previously, kubectx would error with "multiple files in KUBECONFIG are
currently not supported" when KUBECONFIG contained colon-separated paths.
This is a common setup where users maintain separate kubeconfig files for
different clusters/environments.
This change evolves the internal Kubeconfig struct from holding a single
file to a slice of file entries, matching kubectl's merge semantics:
- Reading current-context: first file with a non-empty value wins
- Writing current-context: always written to the first file
- Listing contexts: merged from all files, first occurrence wins for
duplicate names
- Modifying a context (delete/rename/set-namespace): written to the
file that owns that context
- Missing files in the KUBECONFIG list are silently skipped (matching
kubectl behavior), but permission errors are propagated
The Loader interface already returned []ReadWriteResetCloser, so all
public method signatures remain unchanged — zero modifications needed
in cmd/kubectx/ or cmd/kubens/ callers.
Fixes#485Fixes#211
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Fixes#484: The ::set-output:: workflow command is deprecated. Updated
CI workflow to use the $GITHUB_OUTPUT environment file syntax instead.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>