Skip to content

[deckhouse-cli] add --scope flag to d8 k for cross-namespace listing#399

Merged
ldmonster merged 1 commit into
mainfrom
feat-scope-flag
Jul 13, 2026
Merged

[deckhouse-cli] add --scope flag to d8 k for cross-namespace listing#399
ldmonster merged 1 commit into
mainfrom
feat-scope-flag

Conversation

@AlwxSin

@AlwxSin AlwxSin commented Jul 10, 2026

Copy link
Copy Markdown

Adds --scope=accessible|projects|system|project: to d8 k get, wired via ConfigFlags.WithWrapConfigFn: parses and validates the flag in PersistentPreRunE (so a bad value fails fast, before any request), then injects the corresponding X-Deckhouse-Scope / X-Deckhouse-Project headers into every outgoing request via a rest.Config.WrapTransport RoundTripper. Composes with any pre-existing WrapTransport (e.g. an exec-credential auth plugin) rather than replacing it -- covered by a dedicated test, since this is a new pattern for this codebase.

--scope is a flag on get only, deliberately NOT persistent on the k root: the server only ACL-filters list/get/watch of top-level resources, which in kubectl terms is get (and get -w). On other subcommands the header is either ignored (top hits metrics.k8s.io; delete/patch are not bypassed; logs/exec are subresources) or actively misleading (describe's internal LIST would be silently filtered), so the flag is not offered there and also becomes discoverable in d8 k get --help.

--scope requires -A/--all-namespaces and is refused alongside an explicit -n/--namespace: it filters a cross-namespace listing, which needs the cluster-scoped request URL that -A produces. Without -A the request is locked to a single namespace and --scope could only ever narrow that one namespace, silently turning a clean 403 into a misleading empty result; the guard reports the -n conflict in preference to the missing -A.

When a get -A WITHOUT --scope dies with kubectl's cluster-scope Forbidden error, a hint is appended pointing at --scope, with copy-pasteable examples for each scope value built from the resource the user actually asked for (placeholder when unknown -- never a guess). This hooks cmdutil.BehaviorOnFatal, which as a bonus routes fatal messages through the same "d8 " -> "d8 k " rewrite the rest of stderr gets -- kubectl's fatal path previously bypassed the rewriter entirely.

Registers shell completion for --scope: the static enum values plus project: for each real project. Project names are listed via the discovery RESTMapper (group deckhouse.io, Kind Project) rather than a hardcoded GVR, so completion keeps working across served-version bumps. Completing a non-project value never triggers a cluster round-trip.

Requires server-side support from the generalized namespace ACL-filtering kube-apiserver patch (deckhouse/deckhouse); with no --scope passed and no cluster-scope Forbidden on a scope-eligible get -A, behavior is unchanged.

Copilot AI left a comment

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.

Pull request overview

This PR extends the d8 k get (kubectl wrapper) command with a --scope flag that enables Deckhouse server-side ACL-filtering for cross-namespace listings by injecting X-Deckhouse-Scope / X-Deckhouse-Project headers into every Kubernetes API request (via rest.Config.WrapTransport). It also adds UX improvements: a targeted hint when get -A fails with a cluster-scope Forbidden, and shell completion that can enumerate Deckhouse Project names.

Changes:

  • Add --scope=accessible|projects|system|project:<name> to d8 k get, validate it early, and inject corresponding headers via a composed WrapTransport.
  • Append an actionable --scope hint to kubectl’s cluster-scope Forbidden fatal path (and ensure d8 <subcmd> messages are rewritten to d8 k <subcmd> there too).
  • Add tests covering scope parsing, usage validation, hint generation, and WrapTransport composition behavior.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.

File Description
cmd/commands/kubectl.go Implements parsing/validation, header injection transport wrapper, hinting on Forbidden, and shell completion for --scope.
cmd/commands/kubectl_scope_test.go Adds unit tests for parsing, usage guard, Forbidden hint behavior, and WrapTransport composition/injection.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread cmd/commands/kubectl.go Outdated
Comment thread cmd/commands/kubectl.go
Comment thread cmd/commands/kubectl_scope_test.go

Copilot AI left a comment

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.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.

Comment thread cmd/commands/kubectl.go
Comment thread cmd/commands/kubectl.go
Comment thread cmd/commands/kubectl.go
Comment thread cmd/commands/kubectl.go Outdated
Comment thread cmd/commands/kubectl.go
Comment thread cmd/commands/kubectl.go Outdated
Comment thread cmd/commands/kubectl.go Outdated
Comment thread cmd/commands/kubectl.go Outdated
Comment thread cmd/commands/kubectl.go
Adds --scope=accessible|projects|system|project:<name> to `d8 k get`, wired
via ConfigFlags.WithWrapConfigFn: parses and validates the flag in
PersistentPreRunE (so a bad value fails fast, before any request), then
injects the corresponding X-Deckhouse-Scope / X-Deckhouse-Project headers
into every outgoing request via a rest.Config.WrapTransport RoundTripper.
Composes with any pre-existing WrapTransport (e.g. an exec-credential auth
plugin) rather than replacing it -- covered by a dedicated test, since this
is a new pattern for this codebase.

--scope is a flag on `get` only, deliberately NOT persistent on the `k`
root: the server only ACL-filters list/get/watch of top-level resources,
which in kubectl terms is `get` (and `get -w`). On other subcommands the
header is either ignored (top hits metrics.k8s.io; delete/patch are not
bypassed; logs/exec are subresources) or actively misleading (describe's
internal LIST would be silently filtered), so the flag is not offered there
and also becomes discoverable in `d8 k get --help`.

--scope requires -A/--all-namespaces and is refused alongside an explicit
-n/--namespace: it filters a cross-namespace listing, which needs the
cluster-scoped request URL that -A produces. Without -A the request is
locked to a single namespace and --scope could only ever narrow that one
namespace, silently turning a clean 403 into a misleading empty result;
the guard reports the -n conflict in preference to the missing -A.

When a `get -A` WITHOUT --scope dies with kubectl's cluster-scope Forbidden
error, a hint is appended pointing at --scope, with copy-pasteable examples
for each scope value built from the resource the user actually asked for
(placeholder when unknown -- never a guess). This hooks
cmdutil.BehaviorOnFatal, which as a bonus routes fatal messages through the
same "d8 <subcmd>" -> "d8 k <subcmd>" rewrite the rest of stderr gets --
kubectl's fatal path previously bypassed the rewriter entirely.

Registers shell completion for --scope: the static enum values plus
project:<name> for each real project. Project names are listed via the
discovery RESTMapper (group deckhouse.io, Kind Project) rather than a
hardcoded GVR, so completion keeps working across served-version bumps.
Completing a non-project value never triggers a cluster round-trip.

Requires server-side support from the generalized namespace ACL-filtering
kube-apiserver patch (deckhouse/deckhouse); with no --scope passed and no
cluster-scope Forbidden on a scope-eligible `get -A`, behavior is unchanged.

Signed-off-by: Aleksandr Sinichkin <aleksandr.sinichkin@flant.com>
@ldmonster ldmonster merged commit 34fec52 into main Jul 13, 2026
5 checks passed
@ldmonster ldmonster deleted the feat-scope-flag branch July 13, 2026 14:10
@ldmonster ldmonster added the enhancement New feature or request label Jul 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants