-
Notifications
You must be signed in to change notification settings - Fork 469
RFE-9789: oc whoami --show-token should return exec plugin tokens #2378
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -3,6 +3,8 @@ package whoami | |
| import ( | ||
| "context" | ||
| "fmt" | ||
| "net/http" | ||
| "strings" | ||
|
|
||
| "github.com/spf13/cobra" | ||
|
|
||
|
|
@@ -40,6 +42,9 @@ var whoamiLong = templates.LongDesc(` | |
| var whoamiExample = templates.Examples(` | ||
| # Display the currently authenticated user | ||
| oc whoami | ||
|
|
||
| # Display the token for this session | ||
| oc whoami --show-token | ||
| `) | ||
|
|
||
| type WhoAmIOptions struct { | ||
|
|
@@ -83,7 +88,7 @@ func NewCmdWhoAmI(f kcmdutil.Factory, streams genericiooptions.IOStreams) *cobra | |
| }, | ||
| } | ||
|
|
||
| cmd.Flags().BoolVarP(&o.ShowToken, "show-token", "t", o.ShowToken, "Print the token the current session is using. This will return an error if you are using a different form of authentication.") | ||
| cmd.Flags().BoolVarP(&o.ShowToken, "show-token", "t", o.ShowToken, "Print the token the current session is using, including tokens from exec credential plugins. This will return an error if you are using a different form of authentication.") | ||
| cmd.Flags().BoolVarP(&o.ShowContext, "show-context", "c", o.ShowContext, "Print the current user context name") | ||
| cmd.Flags().BoolVar(&o.ShowServer, "show-server", o.ShowServer, "If true, print the current server's REST API URL") | ||
| cmd.Flags().BoolVar(&o.ShowConsoleUrl, "show-console", o.ShowConsoleUrl, "If true, print the current server's web console URL") | ||
|
|
@@ -152,9 +157,6 @@ func (o *WhoAmIOptions) Validate() error { | |
| if o.PrintFlags.OutputFlagSpecified() && (o.ShowToken || o.ShowContext || o.ShowServer || o.ShowConsoleUrl) { | ||
| return fmt.Errorf("--output cannot be used with --show-token, --show-context, --show-server, or --show-console") | ||
| } | ||
| if o.ShowToken && len(o.ClientConfig.BearerToken) == 0 { | ||
| return fmt.Errorf("no token is currently in use for this session") | ||
| } | ||
| if o.ShowContext && len(o.RawConfig.CurrentContext) == 0 { | ||
| return fmt.Errorf("no context has been set") | ||
| } | ||
|
|
@@ -181,7 +183,14 @@ func (o *WhoAmIOptions) getWebConsoleUrl() (string, error) { | |
| func (o *WhoAmIOptions) Run() error { | ||
| switch { | ||
| case o.ShowToken: | ||
| fmt.Fprintf(o.Out, "%s\n", o.ClientConfig.BearerToken) | ||
| token, err := currentBearerToken(o.ClientConfig) | ||
| if err != nil { | ||
| return err | ||
| } | ||
| if len(token) == 0 { | ||
| return fmt.Errorf("no token is currently in use for this session") | ||
| } | ||
| fmt.Fprintf(o.Out, "%s\n", token) | ||
| return nil | ||
| case o.ShowContext: | ||
| fmt.Fprintf(o.Out, "%s\n", o.RawConfig.CurrentContext) | ||
|
|
@@ -212,3 +221,55 @@ func (o *WhoAmIOptions) Run() error { | |
| _, err = o.WhoAmI() | ||
| return err | ||
| } | ||
|
|
||
| // currentBearerToken returns the bearer token used by the current session. | ||
| // Static kubeconfig tokens and token files are returned directly. Exec | ||
| // credential plugins (ExecCredential) and auth providers are resolved through | ||
| // the same client-go transport stack used for API requests, including plugin | ||
| // caching and TTL. | ||
| func currentBearerToken(config *rest.Config) (string, error) { | ||
| if config == nil { | ||
| return "", nil | ||
| } | ||
| if len(config.BearerToken) > 0 { | ||
| return config.BearerToken, nil | ||
|
Comment on lines
+234
to
+235
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
rg -n 'k8s.io/client-go' go.mod
curl -fsSL https://raw.githubusercontent.com/kubernetes/client-go/v0.36.2/rest/config.go | sed -n '66,74p'
curl -fsSL https://raw.githubusercontent.com/kubernetes/client-go/v0.36.2/tools/clientcmd/client_config.go | sed -n '247,260p'Repository: openshift/oc Length of output: 1070 🏁 Script executed: #!/bin/bash
set -euo pipefail
printf '%s\n' '--- whoami implementation ---'
sed -n '160,290p' pkg/cli/whoami/whoami.go
printf '%s\n' '--- whoami tests ---'
sed -n '470,630p' pkg/cli/whoami/whoami_test.go
printf '%s\n' '--- client-go token handling references ---'
rg -n -C 4 'BearerToken(File)?|tokenFile' "$(go env GOPATH 2>/dev/null)/pkg/mod/k8s.io/client-go@v0.36.2/rest" 2>/dev/null || true
rg -n -C 4 'BearerToken(File)?|tokenFile' . -g '*.go'Repository: openshift/oc Length of output: 50369 🏁 Script executed: #!/bin/bash
set -euo pipefail
mod="$(go env GOPATH)/pkg/mod/k8s.io/client-go@v0.36.2"
printf '%s\n' '--- client-go transport construction ---'
rg -n -C 8 'BearerTokenFile|bearerAuthRoundTripper|NewBearerAuth' "$mod/rest" -g '*.go' \
| head -n 220
printf '%s\n' '--- client-go kubeconfig auth merge ---'
rg -n -C 10 'BearerTokenFile|BearerToken|TokenFile|Token' "$mod/tools/clientcmd" -g '*.go' \
| head -n 260
printf '%s\n' '--- repository test coverage for both fields ---'
rg -n -C 3 'BearerToken:\s*".*".*BearerTokenFile|BearerTokenFile:.*[\r\n ]+.*BearerToken:' pkg/cli/whoami -g '*.go' || trueRepository: openshift/oc Length of output: 45106 🏁 Script executed: #!/bin/bash
set -euo pipefail
mod="$(go env GOPATH)/pkg/mod/k8s.io/client-go@v0.36.2"
printf '%s\n' '--- transport authentication precedence ---'
rg -n -C 12 'BearerTokenFile|bearerToken|NewBearerAuth|bearerAuth' "$mod/transport" -g '*.go' \
| head -n 320
printf '%s\n' '--- token-file refresh implementation ---'
rg -n -C 16 'NewCachedFileTokenSource|NewFileTokenSource|last successfully|TokenFile' "$mod" -g '*.go' \
| head -n 320Repository: openshift/oc Length of output: 50368 Honor When 📍 Affects 2 files
🤖 Prompt for AI Agents |
||
| } | ||
|
|
||
| cfg := rest.CopyConfig(config) | ||
| capture := &bearerCapturingRoundTripper{} | ||
| rt, err := rest.HTTPWrappersForConfig(cfg, capture) | ||
| if err != nil { | ||
| return "", err | ||
| } | ||
|
|
||
| req, err := http.NewRequest(http.MethodGet, "https://kubernetes.default.svc", nil) | ||
| if err != nil { | ||
| return "", err | ||
| } | ||
| if _, err := rt.RoundTrip(req); err != nil { | ||
| return "", fmt.Errorf("unable to get token for this session: %w", err) | ||
| } | ||
| return capture.token, nil | ||
| } | ||
|
|
||
| type bearerCapturingRoundTripper struct { | ||
| token string | ||
| } | ||
|
|
||
| func (rt *bearerCapturingRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) { | ||
| rt.token = tokenFromAuthorizationHeader(req.Header.Get("Authorization")) | ||
| return &http.Response{ | ||
| StatusCode: http.StatusOK, | ||
| Body: http.NoBody, | ||
| Header: make(http.Header), | ||
| Request: req, | ||
| }, nil | ||
| } | ||
|
|
||
| func tokenFromAuthorizationHeader(header string) string { | ||
| const prefix = "Bearer " | ||
| if len(header) < len(prefix) || !strings.EqualFold(header[:len(prefix)], prefix) { | ||
| return "" | ||
| } | ||
| return header[len(prefix):] | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win
Handle output errors.
The command returns success when writing the token fails. The exec-plugin fixture exits successfully when JSON encoding fails.
pkg/cli/whoami/whoami.go#L193-L193: Check the write result and return a wrapped error.pkg/cli/whoami/whoami_test.go#L602-L608: CheckEncodeand exit non-zero when it fails.As per coding guidelines, “Wrap errors with meaningful context before returning or logging them.” As per path instructions, “Never ignore error returns.”
🧰 Tools
🪛 golangci-lint (2.12.2)
[error] 193-193: Error return value of
fmt.Fprintfis not checked(errcheck)
📍 Affects 2 files
pkg/cli/whoami/whoami.go#L193-L193(this comment)pkg/cli/whoami/whoami_test.go#L602-L608🤖 Prompt for AI Agents
Sources: Coding guidelines, Path instructions, Linters/SAST tools