Forward --context/--cluster/--user in kubectl generators - #331
Conversation
kubectl_script() previously forwarded only --kubeconfig and --namespace to generated kubectl invocations, so every cluster-hitting generator (namespace, resource, pods, deployments, etc.) ignored an explicitly typed --context or --cluster and always queried the shell's current context. Forward --context, --cluster, and --user (both space- and equals-delimited forms) the same way --namespace already is. Also add a "user" generator (kubectl config get-users) and wire it onto the persistent --user option in kubectl.json, which previously had no generatorName and fell back to file-path suggestions. Fixes symptom 2 of GH#5186 / APP-46. Symptom 1 (file paths instead of context/cluster names) already landed in #247. Co-Authored-By: Warp Agent <agent@warp.dev>
|
This PR was generated with Warp. |
Three fixes from review of 398ddb1: 1. critical: values forwarded into the generated kubectl command (--context, --cluster, --user, and the pre-existing --kubeconfig, --namespace) are now shell-quoted before interpolation. Previously they were spliced into the unquoted command string as-is, so a context/cluster/user name containing whitespace, `$`, a quote, or a `;` (all of which can arrive unmodified from a kubeconfig handed out by a cloud provider or colleague) could break argument splitting, trigger shell expansion, or inject a second command. No shell-aware quoting utility exists in this repo or in warp-completion-metadata (the only close match, warp_util::path:: ShellFamily::escape, lives in the downstream warpdotdev/warp monorepo, covers only Posix/PowerShell and not this crate's Shell::CmdExe, and pulling it in would mean adding a new dependency from this standalone repo onto a private warp crate -- inverting today's dependency direction). kubectl_script's own $KUBECONFIG fallback already assumes POSIX parameter-expansion syntax unconditionally, and GeneratorProcess::CommandFromTokens never receives the runtime Shell in the first place, so this function has always implicitly required a POSIX-compatible shell. Given that, this applies the same POSIX single-quote escaping already used for this exact hazard in files_for_staging_command (git.rs), rather than inventing new cross-shell infrastructure. 2. important: space_or_equals_delimited_option_value used `.position()`, taking the *first* matching flag occurrence. kubectl flags are Cobra/pflag string flags whose `Set` overwrites, so kubectl itself acts on the *last* occurrence. The same scan also didn't stop at a `--` terminator, where pflag has already stopped parsing flags. Now scans for the last match before any `--`. 3. suggestion: added a unit test exercising USER_GENERATOR's on_complete parser directly (via the public Generator::on_complete), covering the NAME-header filter and the connected/general-error short circuits. Verified against a synthetic kubeconfig with two contexts pointing at distinct unreachable hosts: `kubectl config get-contexts/get-clusters/ get-users` all run and parse correctly offline (confirming get-clusters and get-users really do emit a NAME header), and running the generated namespace command with an explicit --context named the *other* context's server in its connection error, proving the typed context is honored. Also confirmed empirically that a context value of `prod; touch /tmp/PWNED` is received by kubectl as a single literal value (a "context not found" error naming the whole string) rather than executing the injected command. Co-Authored-By: Warp Agent <agent@warp.dev>
There was a problem hiding this comment.
Overview
Forwards an explicitly typed --context/--cluster/--user into every kubectl completion generator and adds the missing user generator, closing the residual half of #5186. Review findings were addressed in 1d1e41a; one scope question is left for your judgment.
Concerns
- The new
shell_quoteescaping is POSIX-only, while this crate'sShellenum includesCmdExe. That is a deliberate choice, not an oversight:kubectl_scriptalready hard-codes POSIX${VAR:+...}for its$KUBECONFIGfallback, andGeneratorProcess::CommandFromTokensnever receives the runtimeShell, so per-shell quoting is not wireable here today. Your call whether kubectl completions on a non-POSIX shell warrant a follow-up, or whether this generator's existing POSIX assumption is fine to keep. - Escaping was extended to the pre-existing
--kubeconfig/--namespaceinterpolation too, since this change widened the same hazard; flag it if you would rather see that split out.
Verdict
Checks: build pass, tests pass (166), CI green (CodeQL/rust still running), visual proof n/a — no rendered UI available for an unmerged rev; offline-kubeconfig evidence is in the description instead.
Found: 0 critical, 0 important, 0 suggestions, 0 nits, 1 question
Responding as wilson: Open session · View factory task
|
@warp-agent-staging[bot] I'm starting a first review of this pull request. You can view the conversation on Warp. I completed the review and no human review was requested for this pull request. Comment Powered by Oz |
There was a problem hiding this comment.
Overview
This PR forwards kubectl context, cluster, user, namespace, and kubeconfig values into dynamic generators and adds a user generator for --user. The general approach fixes the intended POSIX-shell injection hazard, but the new quoting path is applied to all shell targets.
Concerns
shell_quotealways emits POSIX single-quote syntax even when the generated command is later built for PowerShell or CmdExe. That can break completions for ordinary forwarded values on Windows/CmdExe and for embedded quotes on PowerShell.- No approved spec context was provided for this PR, so there was no spec drift to assess.
Verdict
Found: 0 critical, 1 important, 0 suggestions
Request changes
Comment /oz-review on this pull request to retrigger a review (up to 3 times on the same pull request).
Powered by Oz
The previous revision ran every forwarded value through POSIX single-quoting, but the generated string is also built for Shell::Powershell and Shell::CmdExe, where POSIX single quotes are not stripped -- so ordinary kubectl completions would have broken on Windows. Values made only of characters that POSIX shells, PowerShell and cmd.exe all treat literally are now interpolated bare, byte for byte as before any quoting existed here. That covers every ordinary kubeconfig name: minikube, gke_proj_us-central1-a_prod, EKS ARNs, admin@prod.local, POSIX config paths. Only a value outside that set gets quoted, and that is exactly the injection case, so the hazard stays closed -- a context named `prod; rm -rf /` still cannot start a second command. The quoted fallback stays POSIX-shaped. That is unavoidable here: kubectl_script's own $KUBECONFIG fallback already requires POSIX parameter expansion, and GeneratorProcess::CommandFromTokens never receives the runtime Shell, so quoting cannot be selected per shell without changing that signature. Keeping the common case unquoted confines the limitation to values that would otherwise be an injection vector instead of applying it to every completion on Windows. Renamed shell_quote to escape_forwarded_value since it no longer always quotes, and added tests pinning the unquoted path. Co-Authored-By: Warp Agent <agent@warp.dev>
Both specs declare persistent --context, --cluster and --user options with no generatorName, so `kubecolor get --context <TAB>` fell back to file path completions -- the un-migrated version of what #247 fixed for kubectl. Both already register kubectl's generators, so this is spec wiring plus registering the new `user` generator for them. Co-Authored-By: Warp Agent <agent@warp.dev>
The existing tests check individual forwarded flags with `contains`. Asserting the entire command string for `kubectl --context staging-cluster --namespace <TAB>` -- the exact case in warpdotdev/warp#5186 and warpdotdev/warp#3929 -- also pins the spacing and the unquoted form of an ordinary value. Co-Authored-By: Warp Agent <agent@warp.dev>
Picks up warpdotdev/command-signatures#331, which forwards a --context, --cluster or --user written on the command line into the commands the kubectl completion generators run. Without it, completions after a --context enumerated from the shell's active context instead of the one on the line (#5186, #3929). Also adds --user value completions and wires --context/--cluster/--user up for kubecolor and oc. Co-Authored-By: Warp Agent <agent@warp.dev>
is_safe_unquoted and escape_forwarded_value are four lines each and their names say what they do, so the doc comments were noise. Also restores space_or_equals_delimited_option_value's doc comment to the original one-liner, dropping the paragraph about last-occurrence-wins and the bare -- terminator that had been added on top of it. Comments only; no behavior change. Co-Authored-By: Warp Agent <agent@warp.dev>
Picks up warpdotdev/command-signatures#331, which forwards a --context, --cluster or --user written on the command line into the commands the kubectl completion generators run. Without it, completions after a --context enumerated from the shell's active context instead of the one on the line (#5186, #3929). Also adds --user value completions and wires --context/--cluster/--user up for kubecolor and oc. Co-Authored-By: Warp Agent <agent@warp.dev>
|
/oz-review |
|
I'm re-reviewing this pull request in response to a review request. You can view the conversation on Warp. I completed the review and no human review was requested for this pull request. Comment Powered by Oz |
There was a problem hiding this comment.
Overview
This PR wires kubectl/kubecolor/oc kubeconfig-related generators, forwards --context, --cluster, and --user through kubectl-backed generators, and adds escaping plus unit coverage for those paths.
Concerns
- The new escaping path is POSIX-only while the generated command still supports non-POSIX shells. On
cmd.exe, single quotes do not protect metacharacters, so a forwarded kubeconfig context/cluster/user/kubeconfig value can still inject a second command when completions run.
Security
- Shell metacharacters in forwarded values are not safely escaped for
Shell::CmdExe; this keeps the command-injection class open for the new forwarded flags on Windows.
Verdict
Found: 1 critical, 0 important, 0 suggestions
Request changes
Comment /oz-review on this pull request to retrigger a review (up to 3 times on the same pull request).
Powered by Oz
Quoting was still POSIX-shaped, and kubectl_script's output is also built
for Shell::CmdExe, which has no single-quote concept -- so a value like
`prod&whoami` would still have run a second command there.
Rather than making the quoting shell-aware, don't forward a value that
would need quoting at all. --context, --cluster, --user, --namespace and
an explicit --kubeconfig are now emitted only when the value passes
is_safe_unquoted; otherwise the flag is omitted. No shell, POSIX or not,
ever receives a metacharacter that came off the command line, and there
is no shell-specific quoting left to get wrong.
The pre-existing ${KUBECONFIG:+--kubeconfig="$KUBECONFIG"} fallback is
untouched: it is not attacker-controlled through the command line, and
dropping an unsafe explicit --kubeconfig simply leaves that default in
place.
Tradeoff: a legitimate but exotic value -- a path with a space, a name
with a quote -- is no longer forwarded, so those completions fall back to
the shell's active context or default kubeconfig. That is what already
happened for such values before this PR, since interpolating them raw
broke the generated command outright.
The injection tests now assert the flag is absent rather than quoted,
including one that checks all three Shell variants.
Co-Authored-By: Warp Agent <agent@warp.dev>
|
/oz-review |
Picks up warpdotdev/command-signatures#331, which forwards a --context, --cluster or --user written on the command line into the commands the kubectl completion generators run. Without it, completions after a --context enumerated from the shell's active context instead of the one on the line (#5186, #3929). Also adds --user value completions and wires --context/--cluster/--user up for kubecolor and oc. Co-Authored-By: Warp Agent <agent@warp.dev>
|
/oz-review |
|
I'm re-reviewing this pull request in response to a review request. You can view the conversation on Warp. I completed the review and no human review was requested for this pull request. Comment Powered by Oz |
There was a problem hiding this comment.
Overview
This PR forwards explicitly provided kubectl --context, --cluster, --user, --namespace, and --kubeconfig values into kubectl-backed completion generators when the values are safe to interpolate, adds a user generator, wires the generator into kubectl/kubecolor/oc specs, and adds focused tests for forwarding, unsafe-value dropping, repeated flags, -- termination, and user parsing.
Concerns
- No blocking concerns found.
- No approved or repository spec context was available, so there was no spec drift to flag.
Verdict
Found: 0 critical, 0 important, 0 suggestions
Approve
Comment /oz-review on this pull request to retrigger a review (up to 3 times on the same pull request).
Powered by Oz
Merged PRs: - Fix nx run completions: use nx graph --file=stdout (warpdotdev/command-signatures#335) - Add completion specs for yay and paru (AUR helpers) (warpdotdev/command-signatures#334) - Fix yay/paru completion specs: -Pc field separators and -B/--build option placement (warpdotdev/command-signatures#336) - Forward --context/--cluster/--user in kubectl generators (warpdotdev/command-signatures#331) The kubectl change forwards a --context, --cluster or --user written on the command line into the commands the completion generators run. Without it, completions after a --context enumerated from the shell's active context instead of the one on the line (#5186, #3929). It also adds --user value completions and wires --context/--cluster/--user up for kubecolor and oc. Co-Authored-By: Warp Agent <agent@warp.dev>
…--cluster/--user forwarding) (#15109) ## Description Updates `warp-command-signatures` to `15debaeb`, the squash commit on `command-signatures:main` for warpdotdev/command-signatures#331. That PR fixes the last remaining symptom of #5186: a `--context` (or `--cluster`, or `--user`) written on the command line was never forwarded into the commands the kubectl completion generators run, so later completions enumerated from the shell's active context instead of the one on the line. With `kubectl --context staging-cluster --namespace <TAB>`, the generator ran `kubectl … get namespace -o custom-columns=:.metadata.name` with no `--context`. It now forwards `--context`, `--cluster` and `--user`, mirroring the existing `--kubeconfig` and `--namespace` handling. It also adds value completion for `kubectl --user`, and wires `--context`/`--cluster`/`--user` up for `kubecolor` and `oc`, which declared those options with no generator. ### Merged PRs - Fix nx run completions: use nx graph --file=stdout (warpdotdev/command-signatures#335) - Add completion specs for yay and paru (AUR helpers) (warpdotdev/command-signatures#334) - Fix yay/paru completion specs: -Pc field separators and -B/--build option placement (warpdotdev/command-signatures#336) - Forward --context/--cluster/--user in kubectl generators (warpdotdev/command-signatures#331) ## Linked Issue Addresses #5186 (labeled `ready-to-implement`). Also addresses #3929, which asks for this same context-forwarding behavior. Deliberately no closing keyword — #5186 covers several symptoms and should be closed manually with a note that the earlier parts landed in the June 2026 stable builds. - [x] The linked issue is labeled `ready-to-spec` or `ready-to-implement`. - [ ] Where appropriate, screenshots or a short video of the implementation are included below (especially for user-visible or UI changes). ## Testing The kubectl behavior is covered by unit tests in warpdotdev/command-signatures#331, which assert the generated command string rather than merely that completion happens — including an `assert_eq` on the entire command for the reported case, and a tightened `test_context_and_namespace_flags_before_subcommand` (it previously passed a `--context` but only checked namespace forwarding, which is why the earlier #247 fix missed this). That repo's `./script/presubmit` and CI were green on merge: 174 tests, 33 of them kubectl-specific. For this dependency bump: - `cargo fmt --all --check` passes. - `cargo clippy -p warp_completer --all-targets --tests -- -D warnings` passes against the new rev. - `cargo metadata --locked` accepts the lockfile, so `Cargo.lock` is in sync; the lockfile diff is limited to the two `command-signatures` source lines. - `cargo tree -p warp_completer -i warp-command-signatures` confirms `15debaeb` is what resolves. - `cargo test -p warp_completer` reports 138 passed / 25 failed, identical to `origin/master` with this change stashed. Those 25 failures are pre-existing in this environment and unrelated to the bump. There are no kubectl-specific tests in `warp_completer`. - [ ] I have manually tested my changes locally with `./script/run` ### Screenshots / Videos No capture taken. Exercising this path in a running client requires a full client build against the bumped rev, which is expensive relative to the value: warpdotdev/command-signatures#247 already carries screenshots of the `--context`/`--cluster` value completion working, #331 carries end-to-end evidence from real `kubectl` runs against a synthetic offline kubeconfig, and the generated command is asserted precisely by unit tests. ## Agent Mode - [x] Warp Agent Mode - This PR was created via Warp's AI Agent Mode <!-- ## Changelog Entries for Stable --> CHANGELOG-IMPROVEMENT: Added completions for `yay` and `paru`, and `kubectl --user` value completions. CHANGELOG-BUG-FIX: Fixed `kubectl` completions ignoring a `--context`, `--cluster` or `--user` written on the command line, so namespaces, pods and other resources are now suggested from that cluster instead of the shell's active context. `kubecolor` and `oc` now complete those flags too, and `nx run` completions were fixed. <!-- warp:pr-description-artifacts start --> <!-- warp:pr-description-artifacts end --> Co-authored-by: Warp Agent <agent@warp.dev>


Summary
Fixes the residual bug behind GH#5186 / APP-46: explicitly typing
--context,--cluster, or--useron akubectlcommand line had no effect on the completions offered for later flags/arguments (e.g.--namespace, resource names) — they were always generated against the shell's current context.The issue reported two symptoms:
--context/--clustercompletions themselves showed file paths instead of context/cluster names. This already landed in Fix kubectl --context and --cluster persistent flag completions #247 and is not touched here (kept passing by the tightenedtest_context_and_namespace_flags_before_subcommandtest).--context/--clusterwas not forwarded to the generators used for other completions, so e.g.kubectl get --context staging get pods --namespace <tab>would still list namespaces from the shell's current context, notstaging. This PR fixes that.Also,
--userwas persistent inkubectl.jsonbut had no generator wired up, so it fell back to offering file paths — the same class of bug as symptom 1, just never fixed for--user. This PR adds ausergenerator and wires it up.Changes
kubectl_script()now extracts--context,--cluster, and--userfrom the command-line tokens (both--flag valueand--flag=valueforms, reusing the existingspace_or_equals_delimited_option_valuehelper) and forwards them to the generatedkubectlinvocation, the same way--namespace/--kubeconfigalready were. Every generator built throughkubectl_script(namespace, resource, pods, deployments, roles, etc.) now respects an explicitly specified context/cluster/user.USER_GENERATOR(kubectl config get-users) and wiredgeneratorName: "user"onto the persistent--useroption inkubectl.json, so it stops falling back to file-path suggestions.--context,--cluster,--user,--namespace, and an explicit--kubeconfig); otherwise the flag is omitted. Previously these were interpolated raw, so a context/cluster/user/namespace name containing whitespace,$, a quote, a;or an&— plausible values from a kubeconfig handed out by a cloud provider or colleague — could break argument splitting, trigger shell expansion, or inject a second command. See "A note on the escaping approach" below for why unsafe values are dropped rather than quoted.space_or_equals_delimited_option_valuenow resolves a repeated flag to its last occurrence (matching kubectl's own Cobra/pflagSet-overwrites semantics) and stops scanning at a bare--terminator (pflag stops parsing flags there, so anything after it — including something that looks like a flag — is a literal positional argument).test_context_and_namespace_flags_before_subcommandto assert--contextforwarding (it previously only asserted--namespace, which is why the original Fix kubectl --context and --cluster persistent flag completions #247 fix missed this).--context/--cluster/--userforwarding (space and=forms); which values are considered safe to forward (realistic kubeconfig names accepted; whitespace, embedded quote,$,;,&, backticks/double-quotes, backslash and empty rejected) and that an unsafe value is absent from the generated command — including one case asserted across all threeShellvariants; last-occurrence-wins for a repeated flag (space and=forms); a flag-lookalike after--being ignored; andUSER_GENERATOR'son_completeparser (NAME-header filtering, connected-to-cluster/general-error short circuits).kubecolorandoc: both specs declared persistent--context/--cluster/--userwith nogeneratorName, sokubecolor get --context <TAB>still showed file paths — the un-migrated version of what Fix kubectl --context and --cluster persistent flag completions #247 fixed for kubectl. Both already register kubectl's generators, so this is spec wiring plus registeringuserfor them.assert_eqon the entire generated command for the exact reported case (kubectl --context staging-cluster --namespace <TAB>), which pins the spacing and the unquoted form alongside thecontains-style per-flag assertions.A note on the escaping approach
There is no quoting here at all, and that is deliberate. Two earlier revisions tried quoting and
oz-for-oss[bot]was right to reject both: POSIX single-quoting every value broke ordinary completions onShell::Powershell/Shell::CmdExe, where those quotes are not stripped, and quoting only unsafe values still leftcmd.exeopen, sincecmd.exehas no single-quote concept and a value likeprod&whoamiwould split there regardless.So instead of quoting an unsafe value, this does not forward it. A value made only of characters that POSIX shells, PowerShell and cmd.exe all treat literally — ASCII alphanumerics plus
. _ - : / @ +— is interpolated bare; anything else means the flag is omitted from the generated command. That covers every ordinary kubeconfig name (minikube,gke_my-project_us-central1-a_prod,arn:aws:eks:us-east-1:1234:cluster/prod,admin@prod.local,/home/me/.kube/config), so the fix in this PR works for real users, while no shell — POSIX or not — ever receives a metacharacter that came off the command line.This is stronger than the shell-aware quoting the reviewer suggested, not weaker, and it needs no cross-cutting change:
GeneratorProcess::CommandFromTokensis never handed the runtimeShell, so per-shell quoting would have meant changing that signature, and there is no shell-aware quoting utility to borrow (warp_util::path::ShellFamily::escapelives in the downstreamwarpdotdev/warpmonorepo, covers only Posix/PowerShell, and depending on it here would invert this repo's dependency direction). With nothing quoted, there is no per-shell quoting left to get wrong.The pre-existing
${KUBECONFIG:+--kubeconfig="$KUBECONFIG"}env fallback is untouched — it is not attacker-controlled through the command line — and dropping an unsafe explicit--kubeconfigsimply leaves that default in place.The tradeoff: a legitimate but exotic value — a kubeconfig path containing a space, a context name containing a quote — is no longer forwarded, so those completions fall back to the shell's active context or default kubeconfig. That is already what happened for such values before this PR, because interpolating them raw broke the generated command outright.
Consolidation
This PR now also carries the work from #332, which was opened in parallel against the same request and has been closed in favor of this one: the
kubecolor/ocspec wiring and the full-generated-command assertion. Everything else in #332 duplicated this PR.Verification
Ran the repo's own checks from the repo root:
npm run format:check— passedcargo fmt -p warp-command-signatures -p warp-completion-metadata --check— passedcargo clippy -p warp-command-signatures -p warp-completion-metadata --all-targets --all-features -- -D warnings— passed, no warningscargo test --verbose— all 174 tests passed (up from 148 at the initial revision), including the pre-existingall_referenced_generators_existinvariant test, which is what checks that the newusergenerator name resolves forkubectl,kubecolorandoccargo test -p warp-command-signatures kubectl— all 33 kubectl tests passedEnd-to-end evidence against a synthetic, fully offline kubeconfig (two contexts,
context-a/context-b, each with its own cluster pointing at a distinct unreachable host and its own user):kubectl config get-contexts -o name,get-clusters, andget-usersall ran and parsed correctly against it — confirmingget-clusters/get-usersreally do emit aNAMEheader line (as our filtering assumes) on real output, not just a hand-written test fixture.--contextfailed trying to reachcluster-a.invalid(the current context); the same command with--context='context-b'failed trying to reachcluster-b.invalidinstead — proof the explicitly typed context is honored rather than the shell's current context.--contextset toprod; touch /tmp/PWNEDdid not create/tmp/PWNED. That evidence was gathered when the value was being quoted; under the current approach such a value is not forwarded at all, so the flag never reaches the shell — a strictly narrower attack surface than what was tested there. The unit tests assert the absence directly, for all threeShellvariants.What I did not attempt, and it would be disproportionate to for this change: a rendered Warp completions popup. That needs a Warp client built against this unmerged
command-signaturesrevision. The evidence above (real kubectl runs against a real, synthetic kubeconfig, asserting on the actual connection-error output) is the achievable ceiling in this sandbox.Out of scope (already fixed elsewhere, confirmed still passing): the #247
--context/--clustergenerator wiring,$KUBECONFIGhandling (APP-3478), and the namespace-before-subcommand resource issue (APP-3476 / CORE-2054).Refs: GH#5186 (warpdotdev/warp#5186), APP-46 (https://linear.app/warpdotdev/issue/APP-46/gh05186-kubectl-context-completions-are-not-working-in-warpdev-shell)