Skip to content

OLS-3632: Add oc-ols CLI scaffolding and kubeconfig integration - #1936

Open
xiormeesh wants to merge 4 commits into
openshift:mainfrom
xiormeesh:OLS-3632-cli-scaffolding
Open

OLS-3632: Add oc-ols CLI scaffolding and kubeconfig integration#1936
xiormeesh wants to merge 4 commits into
openshift:mainfrom
xiormeesh:OLS-3632-cli-scaffolding

Conversation

@xiormeesh

@xiormeesh xiormeesh commented Aug 7, 2026

Copy link
Copy Markdown

Description

Adds the foundation for the oc-ols kubectl/oc plugin — a CLI for querying OpenShift Lightspeed from the terminal. This is the first PR in the OLS-1062 epic (9 stories total).

Structure follows the oc-agentic CLI pattern: thin entry point in cmd/oc-ols/, all command logic in cli/. Unlike oc-agentic (which is a K8s API client via controller-runtime), oc-ols is a REST client that extracts bearer tokens and TLS config from kubeconfig to make HTTP calls to the OLS service endpoint.

New direct dependencies: spf13/cobra (CLI framework) and k8s.io/cli-runtime (IOStreams). Both are standard kubectl ecosystem libraries.

oc-ols requires token-based authentication (bearer token from kubeconfig). Client-certificate-only contexts (e.g. kubeadmin) are rejected — users must oc login with username/password or SSO first. This is by design: OLS performs user-level authorization via the token, per .ai/spec/how/cli.md (Kubeconfig integration).

Build: go build -o /tmp/oc-ols ./cmd/oc-ols/

Type of change

  • Refactor
  • New feature
  • Bug fix
  • CVE fix
  • Optimization
  • Documentation Update
  • Configuration Update
  • Bump-up dependent library

Related Tickets & Documents

Checklist before requesting a review

  • I have performed a self-review of my code.
  • PR has passed all pre-merge test jobs.
  • If it is a core feature, I have added thorough tests.

Testing

  • 12 unit tests covering root command, version, and kubeconfig integration
  • make test — full operator suite passes (0 failures, our code adds none)
  • Manual verification:
    • go build -o /tmp/oc-ols ./cmd/oc-ols/ compiles successfully
    • /tmp/oc-ols version → "oc-ols dev"
    • /tmp/oc-ols "hello" → default mode dispatch stub on stderr
    • /tmp/oc-ols --help → shows global flags and version subcommand
    • Version injection: go build -ldflags "-X github.com/openshift/lightspeed-operator/cli.Version=v0.1.0" -o /tmp/oc-ols ./cmd/oc-ols/ && /tmp/oc-ols version → "oc-ols v0.1.0"

Summary by CodeRabbit

  • New Features

    • Added the oc-ols command-line plugin entry point.
    • Added command help, version reporting, and global Kubernetes connection options.
    • Added kubeconfig support for bearer tokens, token files, custom CA certificates, and insecure TLS mode.
    • Added clear errors for invalid configuration or missing authentication.
  • Tests

    • Added coverage for CLI behavior, version output, kubeconfig authentication, and TLS configuration.
  • Documentation

    • Updated CLI implementation details and key file location guidance.

Adds the foundation for the oc-ols kubectl/oc plugin: entry point,
root command with global flags and default-mode dispatching, version
command, and kubeconfig integration for bearer token extraction and
TLS configuration.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@openshift-ci-robot openshift-ci-robot added the jira/valid-reference Indicates that this PR references a valid Jira ticket of any type. label Aug 7, 2026
@openshift-ci-robot

openshift-ci-robot commented Aug 7, 2026

Copy link
Copy Markdown

@xiormeesh: This pull request references OLS-3632 which is a valid jira issue.

Details

In response to this:

Description

Adds the foundation for the oc-ols kubectl/oc plugin — a CLI for querying OpenShift Lightspeed from the terminal. This is the first PR in the OLS-1062 epic (9 stories total).

Structure follows the oc-agentic CLI pattern: thin entry point in cmd/oc-ols/, all command logic in cli/. Unlike oc-agentic (which is a K8s API client via controller-runtime), oc-ols is a REST client that extracts bearer tokens and TLS config from kubeconfig to make HTTP calls to the OLS service endpoint.

New direct dependencies: spf13/cobra (CLI framework) and k8s.io/cli-runtime (IOStreams). Both are standard kubectl ecosystem libraries.

oc-ols requires token-based authentication (bearer token from kubeconfig). Client-certificate-only contexts (e.g. kubeadmin) are rejected — users must oc login with username/password or SSO first. This is by design: OLS performs user-level authorization via the token, per .ai/spec/how/cli.md (Kubeconfig integration).

Build: go build -o /tmp/oc-ols ./cmd/oc-ols/

Type of change

  • Refactor
  • New feature
  • Bug fix
  • CVE fix
  • Optimization
  • Documentation Update
  • Configuration Update
  • Bump-up dependent library

Related Tickets & Documents

Checklist before requesting a review

  • I have performed a self-review of my code.
  • PR has passed all pre-merge test jobs.
  • If it is a core feature, I have added thorough tests.

Testing

  • 12 unit tests covering root command, version, and kubeconfig integration
  • make test — full operator suite passes (0 failures, our code adds none)
  • Manual verification:
  • go build -o /tmp/oc-ols ./cmd/oc-ols/ compiles successfully
  • /tmp/oc-ols version → "oc-ols dev"
  • /tmp/oc-ols "hello" → default mode dispatch stub on stderr
  • /tmp/oc-ols --help → shows global flags and version subcommand
  • Version injection: go build -ldflags "-X github.com/openshift/lightspeed-operator/cli.Version=v0.1.0" -o /tmp/oc-ols ./cmd/oc-ols/ && /tmp/oc-ols version → "oc-ols v0.1.0"

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository.

@openshift-ci
openshift-ci Bot requested review from raptorsun and xrajesh August 7, 2026 12:57
@openshift-ci

openshift-ci Bot commented Aug 7, 2026

Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by:
Once this PR has been reviewed and has the lgtm label, please assign raptorsun for approval. For more information see the Code Review Process.

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@coderabbitai

coderabbitai Bot commented Aug 7, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@xiormeesh, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 11 minutes

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: a11404e9-f568-4376-a708-d8a374a143a0

📥 Commits

Reviewing files that changed from the base of the PR and between e180600 and b546e81.

📒 Files selected for processing (7)
  • cli/kubeconfig.go
  • cli/kubeconfig_test.go
  • cli/root.go
  • cli/root_test.go
  • cli/suite_test.go
  • cli/version.go
  • cli/version_test.go
📝 Walkthrough

Walkthrough

The pull request adds the oc-ols CLI entry point, Cobra root and version commands, kubeconfig credential and TLS resolution, tests, dependencies, and related documentation.

Changes

CLI plugin

Layer / File(s) Summary
Kubeconfig and TLS resolution
cli/kubeconfig.go, cli/kubeconfig_test.go
The CLI loads a kubeconfig context, resolves bearer tokens from inline or file-based credentials, applies TLS options, and validates CA sources. Tests cover token, TLS, path, and certificate cases.
CLI commands and entry point
cli/root.go, cli/version.go, cli/*_test.go, cmd/oc-ols/main.go, go.mod, .ai/spec/how/cli.md, AGENTS.md
The CLI registers global kubeconfig and TLS flags, provides help and version commands, wires IO streams through the binary entry point, adds Cobra and Kubernetes CLI runtime dependencies, and documents the implementation.

Estimated code review effort: 3 (Moderate) | ~20 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 11.11% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely summarizes the primary changes: oc-ols CLI scaffolding and kubeconfig integration.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 7

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@cli/kubeconfig_test.go`:
- Around line 17-176: Convert the tests in cli/kubeconfig_test.go, including
writeTestKubeconfig and all TestLoadKubeConfig_* cases, from testing.T
assertions to the repository’s established Ginkgo/Gomega BDD structure and
matchers. Preserve each test’s existing coverage and expectations, then run make
test to validate the conversion.

In `@cli/kubeconfig.go`:
- Line 34: Update the error-wrapping paths in the kubeconfig loading flow to
define or reuse appropriate error constants and use each constant as the
fmt.Errorf prefix in the “%s: %w” format. Replace the literal prefixes at the
error sites corresponding to lines 34, 44, 51, and 100 while preserving the
existing wrapped errors and behavior.
- Around line 49-53: Trim whitespace from the contents read in the
BearerTokenFile branch before assigning the result to token, matching client-go
behavior. Add or update the token-file test to write the token followed by a
newline and verify the configured token excludes that newline.
- Around line 64-66: Update the tlsConfig initialization in the kubeconfig TLS
setup to assign ServerName from restConfig.TLSClientConfig.ServerName,
preserving kubeconfig tls-server-name overrides for SNI and certificate
validation. Add a regression test covering propagation of this override.

In `@cli/root.go`:
- Around line 13-26: Update NewRootCmd when constructing the root Cobra command
to bind its input, output, and error streams via SetIn, SetOut, and SetErr using
the injected IOStreams, ensuring help and error output use those streams instead
of process-level defaults.

In `@cli/version_test.go`:
- Around line 8-34: Convert the tests in cli/version_test.go (lines 8-34) and
cli/root_test.go (lines 9-60) from testing.T to the required Ginkgo Describe/It
structure with Gomega assertions, reusing an existing CLI suite or adding one
suite entrypoint as needed. Preserve the current version and root-command
behavior checks, including injected Version validation, and verify the changes
with make test.

In `@cli/version.go`:
- Around line 19-20: Wrap both command output write failures with dedicated
error constants: update cli/version.go lines 19-20 around the version-output
write to return fmt.Errorf with its new constant and the original error, and
update cli/root.go lines 21-22 around the default-mode error-output write
similarly with a separate constant; preserve successful output behavior.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: bb0ae2a4-94e2-45d2-83a1-187a08028ddb

📥 Commits

Reviewing files that changed from the base of the PR and between e08f38f and e180600.

⛔ Files ignored due to path filters (1)
  • go.sum is excluded by !**/*.sum, !go.sum
📒 Files selected for processing (11)
  • .ai/spec/how/cli.md
  • AGENTS.md
  • cli/kubeconfig.go
  • cli/kubeconfig_test.go
  • cli/root.go
  • cli/root_test.go
  • cli/testutil_test.go
  • cli/version.go
  • cli/version_test.go
  • cmd/oc-ols/main.go
  • go.mod

Comment thread cli/kubeconfig_test.go Outdated
Comment thread cli/kubeconfig.go Outdated
Comment thread cli/kubeconfig.go Outdated
Comment thread cli/kubeconfig.go
Comment on lines +64 to +66
tlsConfig := &tls.Config{
InsecureSkipVerify: insecureSkipTLS, //#nosec G402 -- user-controlled via --insecure-skip-tls-verify flag
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
curl -fsSL https://raw.githubusercontent.com/kubernetes/client-go/v0.36.3/rest/config.go |
  sed -n '213,240p'

Repository: openshift/lightspeed-operator

Length of output: 1295


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== file list =="
git ls-files | rg '(^|/)cli/kubeconfig\.go$|go\.mod$|go\.sum$' | sed -n '1,120p'

echo "== kubeconfig.go =="
if [ -f cli/kubeconfig.go ]; then
  nl -ba cli/kubeconfig.go | sed -n '1,180p'
fi

echo "== relevant config references =="
rg -n "TLSClientConfig|TLSClient|ServerName|InsecureSkipVerify|NewClientSet|config.*Context|restConfig" cli -S || true

echo "== kubernetes client-go version =="
rg -n "k8s.io/client-go" go.mod go.sum || true

echo "== lock file / installed cache probe (read-only) =="
find "$GOPATH" -path '*/pkg/mod/k8s.io/client-go@v0.36.3/rest/config.go' 2>/dev/null | head -n 1 | xargs -r -I{} sh -c 'echo "--- {}"; sed -n "200,260p" "{}"'

Repository: openshift/lightspeed-operator

Length of output: 275


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== locate kubeconfig.go =="
fd -a kubeconfig\.go . || find . -name kubeconfig.go -print

echo "== cli/kubeconfig.go (sed) =="
sed -n '1,220p' cli/kubeconfig.go

echo "== relevant config references =="
rg -n "TLSClientConfig|TLSClient|ServerName|InsecureSkipVerify|NewClientSet|restConfig|tls-server-name" cli -S || true

echo "== kubernetes client-go version =="
rg -n "k8s.io/client-go" go.mod go.sum || true

echo "== go command availability =="
command -v go || true

Repository: openshift/lightspeed-operator

Length of output: 4455


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== client-go `@v0.36.3` RESTConfig/ClientSet TLS flow =="
tmp=/tmp/client-go-v0.36.3
mkdir -p "$tmp"
curl -fsSL https://raw.githubusercontent.com/kubernetes/client-go/v0.36.3/rest/config.go -o "$tmp/config.go"
curl -fsSL https://raw.githubusercontent.com/kubernetes/client-go/v0.36.3/kubernetes/client.go -o "$tmp/client.go"

printf '\n--- config.go TLS assignment ---\n'
rg -n "TLSClientConfig|ServerName|Insecure|CertFile|KeyFile|CAFile|CAData" "$tmp/config.go" -C 2

printf '\n--- config.go BuildConfigFromFlags/RESTConfig relevant block ---\n'
sed -n '270,380p' "$tmp/config.go"

printf '\n--- client.go TLS dialer construction ---\n'
rg -n "TLSClient|TLSConfig|ServerName|DialTLS|DialContext" "$tmp/client.go" -C 3

printf '\n--- kubeconfig_test tls tests ---\n'
sed -n '1,140p' cli/kubeconfig_test.go

Repository: openshift/lightspeed-operator

Length of output: 273


🏁 Script executed:

#!/bin/bash
set -euo pipe Fail

echo "== Go cache availability =="
go env GOPATH GOMODCACHE GOROOT

echo "== Locate installed client-go v0.36.3 files =="
modpath="$GOPATH/pkg/mod/k8s.io/client-go@v0.36.3"
if [ -d "$modpath" ]; then
  ls -l "$modpath"
  for f in "$modpath/rest/config.go" "$modpath/kubernetes/client.go"; do
    if [ -f "$f" ]; then
      echo "--- $f ---"
      rg -n "TLSClientConfig|ServerName|Insecure|CertFile|KeyFile|CAFile|CAData|TLSConfig|TLSClient|DialTLS|DialContext" "$f" -C 2 || true
    fi
  done
else
  echo "client-go v0.36.3 not in GOMODCACHE=$GOMODCACHE"
fi

echo "== Kubeconfig test context around TLS assertions =="
if [ -f cli/kubeconfig_test.go ]; then
  sed -n '1,180p' cli/kubeconfig_test.go
fi

Repository: openshift/lightspeed-operator

Length of output: 212


🏁 Script executed:

#!/bin/bash
set -f
set -- 1

echo "== Go cache availability =="
go env GOPATH GOMODCACHE GOROOT

echo "== Locate installed client-go v0.36.3 files =="
modpath="$GOPATH/pkg/mod/k8s.io/client-go@v0.36.3"
if [ -d "$modpath" ]; then
  ls -l "$modpath"
  for f in "$modpath/rest/config.go" "$modpath/kubernetes/client.go"; do
    if [ -f "$f" ]; then
      echo "--- $f ---"
      rg -n "TLSClientConfig|ServerName|Insecure|CertFile|KeyFile|CAFile|CAData|TLSConfig|TLSClient|DialTLS|DialContext" "$f" -C 2 || true
    fi
  done
else
  echo "client-go v0.36.3 not in GOMODCACHE=$GOMODCACHE"
fi

echo "== Kubeconfig test context around TLS assertions =="
if [ -f cli/kubeconfig_test.go ]; then
  sed -n '1,180p' cli/kubeconfig_test.go
fi

Repository: openshift/lightspeed-operator

Length of output: 4667


🌐 Web query:

kubernetes client-go v0.36.3 TLSClientConfig.ServerName SNI certificate verification

💡 Result:

In Kubernetes client-go v0.36.3, the ServerName field within TLSClientConfig serves two critical functions regarding TLS connections [1][2][3]: 1. SNI (Server Name Indication): It is passed to the server as the hostname for the SNI extension during the TLS handshake [1][2][3]. 2. Certificate Verification: It is used by the client to verify the server's certificate [1][2][3]. Specifically, the client checks that the provided ServerName matches the hostnames present in the server's certificate [1][2][3]. If ServerName is left empty, the client-go library automatically defaults to using the hostname from the server's connection URL for both SNI and certificate verification purposes [1][4][2][3]. This implementation ensures that both SNI routing and proper certificate identity validation are maintained consistently [5][6].

Citations:


Preserve the kubeconfig TLS server name.

Set tlsConfig.ServerName from restConfig.TLSClientConfig.ServerName. A kubeconfig tls-server-name override is needed so the Kubernetes API client uses that value for SNI and certificate matching. Also add a regression test for this override.

Proposed fix
 tlsConfig := &tls.Config{
 	InsecureSkipVerify: insecureSkipTLS, //#nosec G402 -- user-controlled via --insecure-skip-tls-verify flag
+	ServerName:         restConfig.TLSClientConfig.ServerName,
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@cli/kubeconfig.go` around lines 64 - 66, Update the tlsConfig initialization
in the kubeconfig TLS setup to assign ServerName from
restConfig.TLSClientConfig.ServerName, preserving kubeconfig tls-server-name
overrides for SNI and certificate validation. Add a regression test covering
propagation of this override.

Comment thread cli/root.go
Comment thread cli/version_test.go Outdated
Comment thread cli/version.go Outdated
xiormeesh and others added 3 commits August 7, 2026 15:25
- Define error constants for all error wrapping paths
- Trim whitespace from bearer tokens (matches client-go behavior)
- Preserve kubeconfig tls-server-name (ServerName) in TLS config
- Bind Cobra streams to IOStreams via SetIn/SetOut/SetErr
- Wrap fmt.Fprintf errors with ErrWriteOutput constant
- Add ServerName propagation test

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Follow the repo's BDD test convention per CONTRIBUTING.md.
Add suite_test.go entrypoint, convert all test files to
Describe/It blocks with Gomega matchers.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@openshift-ci

openshift-ci Bot commented Aug 7, 2026

Copy link
Copy Markdown

@xiormeesh: The following test failed, say /retest to rerun all failed tests or /retest-required to rerun all mandatory failed tests:

Test name Commit Details Required Rerun command
ci/prow/bundle-e2e-4-21 b546e81 link true /test bundle-e2e-4-21

Full PR test history. Your PR dashboard.

Details

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository. I understand the commands that are listed here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

jira/valid-reference Indicates that this PR references a valid Jira ticket of any type.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants