Skip to content

feat(check): add control-plane validator, stale namespace detection, and registry credential checks - #782

Open
rohithb-hub wants to merge 6 commits into
mainfrom
feat/nvcf-cli-cluster-validator
Open

feat(check): add control-plane validator, stale namespace detection, and registry credential checks#782
rohithb-hub wants to merge 6 commits into
mainfrom
feat/nvcf-cli-cluster-validator

Conversation

@rohithb-hub

@rohithb-hub rohithb-hub commented Aug 11, 2026

Copy link
Copy Markdown
Contributor

TL;DR

Adds three new capabilities to nvcf self-hosted check: a control-plane cluster validator (wired to the companion nvca PR), stale namespace detection before install, and pre-install registry credential validation using the generic OCI Bearer token flow.

Additional Details

This PR contains three logical changes, each in a separate commit.

Commit 1 -- re-gate cluster-validator and widen RBAC (Req 1, Req 3)

The validator was only triggered by --pre or --all, and --compute-plane was a
complete no-op. Two predicate functions now gate the validator:

  • computePlaneIsTargeted: --compute-plane, --all, or --pre in ModeSingle
  • controlPlaneIsTargeted: mirrors the above for the control-plane role

--pre in ModeSplit no longer triggers the validator because --pre does not
constitute explicit compute-plane targeting when two separate clusters are named.
mode is hoisted to runSelfHostedCheck so image resolution, timeout sizing,
and skip-note messaging all share the same answer.

The preflight-validator ClusterRole is widened to support the new checks:

  • namespaces, pods, services: added create and delete
  • pods/log: added get (for probe log reading without exec)
  • networkpolicies: added create, update, delete (for enforcement check)
  • gateway.networking.k8s.io: added get and list on gatewayclasses, gateways, httproutes, grpcroutes

The ClusterRole uses update-or-create so existing installs pick up the new
rules on the next check run without manual intervention.

Commit 2 -- stale namespace detection and control-plane validator wiring (Req 6, Req 2+4)

probeStaleNamespaces checks each known NVCF stack namespace and reports two
failure conditions:

  • Stuck Terminating: DeletionTimestamp set or phase Terminating, usually a finalizer deadlock
  • No Helm release: namespace exists but has no secret with label owner=helm, an empty shell from a partial helm uninstall

Severity is error so anyFailed trips the non-zero exit code. The check never
auto-cleans. The error message names every stale namespace and provides a
kubectl delete command operators can copy and run.

The control-plane validator is wired into controlPlaneCheckCategory. Before
submitting the Job, nvcf-cli creates a ConfigMap cluster-validator-network-checks
in the default namespace with nvcr.io reachability and enforcement config.
VALIDATOR_ROLE=control-plane is set in the Job env. The --cluster-validator-registries
flag (or cluster_validator_registries config key) appends operator-supplied
registry endpoints to the ConfigMap alongside nvcr.io.

Commit 3 -- registry credential validation (Req 5)

exchangeBearerToken now implements the OCI Distribution Spec Bearer token flow:
parses realm, service, and scope from the WWW-Authenticate header returned in
the registry 401 response, then fetches a token from that realm. The old NGC
/proxy_auth path is kept as a named fallback for when the header is absent or
NGC-specific behavior is needed.

credentialsForRegistry separates NGC_API_KEY from generic docker config lookup.
NGC_API_KEY applies only to NGC registries (nvcr.io, nvidia.com domains).
Sending it to quay.io or GHCR would cause confusing "credentials rejected"
errors when the real situation is "no credentials configured."

EnumerateRegistries builds the check list from:

  • Registry parsed from cluster_validator_image (always nvcr.io or similar, critical)
  • global.image.registry from environments/local.yaml when run from the repo root (critical if NGC)
  • quay.io as a hardcoded cert-manager exception (non-critical)
  • Operator-supplied extras via --cluster-validator-registries (non-critical)

The RepoHint carries the actual repo path from the image ref so the token
exchange uses the correct org scope. NGC checks org-level access, so using a
synthetic repo name like probe/credential-check returns 403 even with valid
credentials.

For the Reviewer

  • cmd/self_hosted_check.go: computePlaneIsTargeted, controlPlaneIsTargeted, mode hoisting, anyValidatorIsTargeted, resolveStackValuesFile, registry credential wiring
  • internal/selfhosted/clustervalidator.go: RBAC rule set, VALIDATOR_ROLE in Job env, ConfigMap creation, ClusterValidatorParams.Role and .Registries
  • internal/selfhosted/preflight.go: staleNamespaceCheck, buildRegistryCredentialCategory, clusterValidatorCheck role+registries params, PreflightConfig new fields
  • internal/selfhosted/stale_namespace.go: new file with prober type, check logic, and namespace lists
  • internal/selfhosted/registry_cred.go: new file with probeRegistryCredential, EnumerateRegistries, readGlobalImageRegistry
  • internal/selfhosted/validatortag.go: parseWWWAuthenticate, exchangeBearerToken (generic OCI), credentialsForRegistry

For QA

Tested on k3d-ncp-local (NVCF stack deployed) and kind-kind (bare cluster).

nvcr.io credential check:

  • With valid NGC_API_KEY and actual org scope from cluster_validator_image: passed
  • With invalid NGC_API_KEY: "credentials rejected" at error severity

quay.io and ghcr.io:

  • No credentials configured: "no credentials configured" at warning severity
  • NGC_API_KEY correctly not sent to non-NGC registries

ECR hostname: "ECR registry detected, use aws ecr get-login-password" at warning severity

Stale namespace detection:

  • nvcf-backend (no Helm release): detected and reported on actual cluster
  • Terminating namespace (test): detected as stuck Terminating

Control-plane validator:

  • VALIDATOR_ROLE=control-plane confirmed in Job env via kubectl inspect
  • All gateway/storage checks passed on cluster with NVCF stack deployed
  • Network Policy Enforcement: fully verified after networkpolicies write RBAC fix

Issues

NO-REF

Checklist

  • I am familiar with the Contributing Guidelines.
  • I have signed off my commits for Developer Certificate of Origin (DCO) compliance.
  • New or existing tests cover these changes.
  • The documentation is up to date with these changes.

Summary by CodeRabbit

  • New Features

    • Added registry credential checks with authentication diagnostics and severity reporting.
    • Added detection and reporting of stale Kubernetes namespaces.
    • Added support for additional registries and automatic discovery from deployment configuration.
    • Expanded registry authentication across OCI-compatible registries.
    • Improved separate control-plane and compute-plane validation modes.
  • Bug Fixes

    • Improved validator targeting, image resolution, timeout handling, and skip notices.
    • Refined validation permissions and handling of existing cluster access rules.
    • Improved diagnostics for registry access and stale deployment resources.

@rohithb-hub
rohithb-hub requested a review from a team as a code owner August 11, 2026 21:02
@rohithb-hub
rohithb-hub requested a review from nvjaxzin August 11, 2026 21:02
@coderabbitai

coderabbitai Bot commented Aug 11, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: a05ea12b-d2b3-463f-b432-9374bb9b0c6d

📥 Commits

Reviewing files that changed from the base of the PR and between 4d7c477 and 6fa7733.

📒 Files selected for processing (3)
  • src/clis/nvcf-cli/cmd/self_hosted_check.go
  • src/clis/nvcf-cli/internal/selfhosted/clustervalidator.go
  • src/clis/nvcf-cli/internal/selfhosted/clustervalidator_test.go
🚧 Files skipped from review as they are similar to previous changes (3)
  • src/clis/nvcf-cli/cmd/self_hosted_check.go
  • src/clis/nvcf-cli/internal/selfhosted/clustervalidator.go
  • src/clis/nvcf-cli/internal/selfhosted/clustervalidator_test.go

📝 Walkthrough

Walkthrough

The self-hosted check command adds registry credential validation, stale-namespace detection, and role-aware cluster validation. It resolves control-plane and compute-plane targets across Kubernetes modes and passes role-specific configuration to preflight checks and validator Jobs.

Changes

Self-hosted validation

Layer / File(s) Summary
Registry discovery and authentication
src/clis/nvcf-cli/internal/selfhosted/registry_cred.go, src/clis/nvcf-cli/internal/selfhosted/validatortag.go, src/clis/nvcf-cli/internal/selfhosted/*_test.go
Registry endpoints are discovered from images, stack values, cert-manager, and extra configuration. OCI Bearer authentication, Docker credentials, NGC credentials, ECR diagnostics, and criticality handling are supported.
Stale namespaces and preflight checks
src/clis/nvcf-cli/internal/selfhosted/stale_namespace.go, src/clis/nvcf-cli/internal/selfhosted/preflight.go, src/clis/nvcf-cli/internal/selfhosted/*_test.go
Preflight checks detect stale namespaces, run registry credential checks, and invoke role-specific validators. Probe failures produce warnings, while stale namespaces and critical registry failures produce errors.
Role-aware cluster validator
src/clis/nvcf-cli/internal/selfhosted/clustervalidator.go, src/clis/nvcf-cli/internal/selfhosted/clustervalidator_test.go
The validator accepts a role and registry list. Control-plane runs create or update registry probe configuration, refresh RBAC rules, and set VALIDATOR_ROLE on generated Jobs.
CLI targeting and role wiring
src/clis/nvcf-cli/cmd/self_hosted_check.go, src/clis/nvcf-cli/cmd/self_hosted_check_test.go, src/clis/nvcf-cli/*/BUILD.bazel
The command resolves Kubernetes mode, targets control-plane and compute-plane checks, discovers stack values, injects validation seams, and runs standalone role checks with the correct skip notices.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant CLI as self-hosted check command
  participant Dispatch as runPreflightByRole
  participant Preflight as preflight
  participant Registry as RegistryCredentialChecker
  participant Namespace as StaleNamespaceProber
  participant Validator as cluster-validator Job
  CLI->>Dispatch: resolve mode and targeted roles
  Dispatch->>Preflight: pass role configuration
  Preflight->>Registry: check configured registries
  Preflight->>Namespace: inspect role namespaces
  Preflight->>Validator: run role-specific validation
  Validator-->>Preflight: return cluster validation result
  Preflight-->>CLI: emit category and check results
Loading
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 41.51% 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 follows Conventional Commits and accurately describes the primary feature changes in the pull request.
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 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/nvcf-cli-cluster-validator

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: 11

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/clis/nvcf-cli/cmd/self_hosted_check.go (1)

145-162: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

ModeSingle now runs the validator twice, but the outer budget still assumes one run.

cpRC and gpuRC both set ClusterValidator in the ModeSingle branch, and the two RunPreflightForRole calls at Line 482 and Line 483 are sequential. Each runClusterValidator invocation owns a 5-minute clusterValidatorTimeout, so the worst case is 10 minutes plus RBAC bootstrap and log fetch. outerTimeout is 6 minutes. The compute-plane validator then derives vctx from the remaining ceiling and its wait is truncated, which is the exact failure the comment at Line 155 sets out to prevent.

Two related effects in the same path: the second run calls sweepPriorClusterValidatorJobs, which deletes the control-plane Job, so --no-cleanup cannot preserve it for debugging.

Size the budget for the number of validator runs.

🐛 Proposed fix
 	outerTimeout := 2 * time.Minute
-	if clusterValidatorWillRun {
-		outerTimeout = 6 * time.Minute
+	if clusterValidatorWillRun {
+		// ModeSingle runs the control-plane and compute-plane validators
+		// sequentially against the same cluster; budget both.
+		runs := 1
+		if mode == kubectx.ModeSingle &&
+			controlPlaneIsTargeted(mode) && computePlaneIsTargeted(mode) {
+			runs = 2
+		}
+		outerTimeout = time.Duration(runs) * 6 * time.Minute
 	}
🤖 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 `@src/clis/nvcf-cli/cmd/self_hosted_check.go` around lines 145 - 162, Update
the outerTimeout calculation near clusterValidatorWillRun to account for both
sequential validator executions in ModeSingle, using a 10-minute validator
budget plus existing headroom while retaining the shorter timeout for a single
run. Ensure the resulting context preserves the full wait for both
RunPreflightForRole calls and does not alter unrelated cleanup behavior.
🧹 Nitpick comments (7)
src/clis/nvcf-cli/cmd/self_hosted_check.go (1)

287-310: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

resolveStackValuesFile depends on the operator's working directory and a fixed environment name.

The function walks up from os.Getwd() for deploy/stacks/self-managed/environments/local.yaml. Two limits follow:

  • An installed CLI run outside the source tree never finds the file, so global.image.registry never contributes a registry entry.
  • The path pins the local environment. An operator running a staging or production environment file gets no registry from this source.

Add a flag or Viper key for the values file, and use this walk only as the fallback.

🤖 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 `@src/clis/nvcf-cli/cmd/self_hosted_check.go` around lines 287 - 310, Update
resolveStackValuesFile to first use a configurable values-file flag or Viper key
when provided, allowing any environment path and installed CLI usage; retain the
existing working-directory walk for
deploy/stacks/self-managed/environments/local.yaml only as the fallback when no
override is configured.
src/clis/nvcf-cli/internal/selfhosted/clustervalidator_test.go (2)

494-495: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add an assertion that VALIDATOR_ROLE reaches the container env.

Every buildClusterValidatorJob test passes "" for the new role argument. The Job env var is the only carrier of the role from preflight.go to the validator binary, and a dropped or misplaced role argument would still pass this suite. Add a case that builds with clusterValidatorControlPlaneRole and asserts env["VALIDATOR_ROLE"].

As per coding guidelines: "Code changes must include tests, or the Pull Request must explain why tests are not applicable".

💚 Proposed test
+func TestBuildClusterValidatorJobShape_RolePropagated(t *testing.T) {
+	job := buildClusterValidatorJob("test-job", "img:1", "", clusterValidatorControlPlaneRole, false)
+	env := map[string]string{}
+	for _, e := range job.Spec.Template.Spec.Containers[0].Env {
+		env[e.Name] = e.Value
+	}
+	assert.Equal(t, clusterValidatorControlPlaneRole, env["VALIDATOR_ROLE"],
+		"VALIDATOR_ROLE selects the validator check set and must reach the container env")
+}

Also applies to: 532-544

🤖 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 `@src/clis/nvcf-cli/internal/selfhosted/clustervalidator_test.go` around lines
494 - 495, Add a test case in TestBuildClusterValidatorJobShape that calls
buildClusterValidatorJob with clusterValidatorControlPlaneRole and asserts the
generated container environment contains that value under VALIDATOR_ROLE. Keep
the existing shape assertions and ensure the test covers role propagation
through the Job env.

Source: Coding guidelines


345-352: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Use slices.Contains instead of a local helper.

strSliceContains reimplements slices.Contains from the standard library.

🤖 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 `@src/clis/nvcf-cli/internal/selfhosted/clustervalidator_test.go` around lines
345 - 352, Remove the local strSliceContains helper and replace its call sites
with the standard-library slices.Contains function, adding the required slices
import while preserving the existing membership-check behavior.
src/clis/nvcf-cli/internal/selfhosted/registry_cred_test.go (1)

42-46: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Prefer an injected transport over mutating http.DefaultTransport.

Three tests swap the process-wide http.DefaultTransport. The restore is correct today because no test in this package calls t.Parallel. If any test in package selfhosted later becomes parallel, these swaps race with every other HTTP-using test. Consider giving probeRegistryCredential an injectable *http.Client (or transport) seam instead.

🤖 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 `@src/clis/nvcf-cli/internal/selfhosted/registry_cred_test.go` around lines 42
- 46, Update probeRegistryCredential to accept an injected *http.Client or
transport, and use that dependency for requests instead of the process-wide
http.DefaultTransport. Revise the affected tests to pass srv.Client() (or its
transport) directly and remove the DefaultTransport replacement and cleanup.
src/clis/nvcf-cli/cmd/self_hosted_check_test.go (1)

347-385: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add the matching table for controlPlaneIsTargeted.

controlPlaneIsTargeted is new and gates cpClusterValidator in runPreflightByRole. Only computePlaneIsTargeted has a table test. The two predicates differ in which flag they read, so a copy-paste error between them would not be caught.

As per coding guidelines: "Code changes must include tests, or the Pull Request must explain why tests are not applicable".

🤖 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 `@src/clis/nvcf-cli/cmd/self_hosted_check_test.go` around lines 347 - 385, Add
a table-driven TestControlPlaneIsTargeted alongside TestComputePlaneIsTargeted,
covering control-plane targeting across ModeSingle and ModeSplit, including
--pre, --compute-plane, --all, and no relevant flags. Assert each case against
controlPlaneIsTargeted and reset the shared checkPre, checkComputePlane, and
checkAll state after the test.

Source: Coding guidelines

src/clis/nvcf-cli/internal/selfhosted/clustervalidator.go (2)

360-384: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Build the ConfigMap YAML from a struct instead of string surgery.

buildControlPlaneValidatorConfig interpolates registry hostnames into a raw YAML string and then relies on strings.Replace finding the literal "enforcement:" token. Two consequences:

  • A hostname containing YAML-significant characters produces a malformed document that the validator cannot parse.
  • Any future edit to the template that changes or reorders enforcement: silently breaks the insertion point.

sigs.k8s.io/yaml is already a dependency in this package. Define the config as Go structs and marshal it.

🤖 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 `@src/clis/nvcf-cli/internal/selfhosted/clustervalidator.go` around lines 360 -
384, Replace string-based YAML interpolation in buildControlPlaneValidatorConfig
with typed config structs and sigs.k8s.io/yaml marshaling, including the
baseline endpoints and enforcement settings currently represented by
controlPlaneValidatorConfigTemplate. Parse and append valid extra registries as
non-critical tcp+tls endpoints, allowing YAML escaping to handle hostnames
safely, and remove the strings.Replace insertion logic.

386-408: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Replace the hand-rolled host:port parser with net.SplitHostPort.

The current parser has two defects:

  • IPv6 literals break. [::1]:5000 splits at the last colon and returns host [::1] only by accident; ::1 returns host : and port 1.
  • "nvcr.io:" returns host "nvcr.io:" with the trailing colon, which then becomes a malformed host: value in the ConfigMap.

net.SplitHostPort plus strconv.Atoi covers both cases and is the idiomatic choice.

♻️ Proposed refactor
 func parseRegistryHostPort(s string) (host string, port int) {
 	s = strings.TrimSpace(s)
 	if s == "" {
 		return "", 0
 	}
-	if idx := strings.LastIndex(s, ":"); idx > 0 {
-		h := s[:idx]
-		p := s[idx+1:]
-		n := 0
-		for _, c := range p {
-			if c < '0' || c > '9' {
-				return s, 443
-			}
-			n = n*10 + int(c-'0')
-		}
-		if n > 0 && n <= 65535 {
-			return h, n
-		}
-	}
-	return s, 443
+	h, p, err := net.SplitHostPort(s)
+	if err != nil {
+		return s, 443
+	}
+	n, err := strconv.Atoi(p)
+	if err != nil || n <= 0 || n > 65535 {
+		return h, 443
+	}
+	return h, n
 }
🤖 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 `@src/clis/nvcf-cli/internal/selfhosted/clustervalidator.go` around lines 386 -
408, Replace the hand-rolled parsing in parseRegistryHostPort with
net.SplitHostPort and strconv.Atoi. Support bracketed and unbracketed IPv6
correctly, remove trailing colons from empty-port inputs such as "nvcr.io:", and
preserve the existing fallback host/port behavior for missing or invalid ports.
🤖 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 `@src/clis/nvcf-cli/cmd/self_hosted_check_test.go`:
- Around line 390-448: Update TestCheck_ComputePlaneFlagRunsChecks and
TestCheck_ControlPlaneFlagRunsChecks to run with --skip-cluster-validation, and
set NVCF_CLI_SELFHOSTED_SKIP_INOTIFY via t.Setenv in each test. Preserve the
existing JSONL parsing and category assertions.

In `@src/clis/nvcf-cli/cmd/self_hosted_check.go`:
- Around line 200-207: Update the registry credential setup block to run
whenever !localOnly, removing the clusterValidatorImage non-empty condition.
Continue obtaining extraRegistries and stackValuesFile, and pass the possibly
empty clusterValidatorImage to selfhosted.EnumerateRegistries so
global.image.registry and configured extras are checked independently of the
validator image.

In `@src/clis/nvcf-cli/internal/selfhosted/clustervalidator.go`:
- Around line 210-225: Confirm the validator’s namespace-wide write requirements
by tracing the operations used by the validator binary, especially namespace,
pod, service, and network-policy checks. If writes only target the probe
namespace, replace the cluster-wide permissions with namespace-scoped
Role/RoleBinding access while retaining required cluster-wide read permissions;
otherwise, add cleanup in the --cleanup flow to delete the validator ClusterRole
and ClusterRoleBinding after the run.
- Around line 145-150: Preserve the error from ensureClusterValidatorConfig in
the control-plane path instead of assigning it to _. Store a non-fatal config
note and append it to cleaned before every ClusterValidatorResult return, or
otherwise expose it through the result transcript, while retaining the wrapped
error context and continuing validation.

In `@src/clis/nvcf-cli/internal/selfhosted/preflight.go`:
- Around line 348-353: Ensure the registry-credentials category is constructed
and executed only once per command invocation, rather than once for each role
passed to RunPreflightForRole. Update buildCategories or the cmd-layer
orchestration around RunPreflightForRole to gate registry handling to a single
role/invocation while preserving all other role-specific categories and result
emission.
- Around line 687-690: Update the stale-namespace message construction around
r.Message to emit remediation hints per stale reason rather than one blanket
kubectl delete command. For “stuck Terminating,” direct operators to remove
namespace finalizers; for “no Helm release,” provide a cautious
inspection/removal hint that does not imply force-deleting the namespace.
Preserve the stale namespace names and counts in the output.

In `@src/clis/nvcf-cli/internal/selfhosted/registry_cred.go`:
- Around line 172-178: The registry endpoint parsing must preserve non-default
ports and correctly handle IPv6 and trailing-colon inputs. In
src/clis/nvcf-cli/internal/selfhosted/registry_cred.go lines 172-178, update the
extras handling around parseRegistryHostPort so RegistryEntry.Registry retains
the parsed port when it is not 443, allowing probeRegistryCredential to use the
correct URL. In src/clis/nvcf-cli/internal/selfhosted/clustervalidator.go lines
386-408, replace the manual parsing in parseRegistryHostPort with
net.SplitHostPort and strconv.Atoi, and add table cases covering [::1]:5000 and
nvcr.io:.
- Around line 95-108: The probeRegistryCredential flow must require configured
credentials for critical registry entries before accepting a successful
exchangeBearerToken result. Check credentialsForRegistry and the entry’s
critical status before returning success, while preserving the existing
rejected-credentials error for configured credentials and the anonymous-token
behavior for non-critical entries.

In `@src/clis/nvcf-cli/internal/selfhosted/stale_namespace.go`:
- Around line 103-111: Update the Secret List call in the stale namespace check
to set ListOptions.Limit to 1, since only existence is required. Add a concise
comment documenting that this check assumes Helm’s default secret storage driver
and may report namespaces using configmap or SQL storage as having no Helm
release.

In `@src/clis/nvcf-cli/internal/selfhosted/validatortag.go`:
- Around line 334-343: Trim whitespace from unquoted parameter values in the
parsing branch of the validator, before assigning or using val. Preserve the
existing comma splitting and empty-params behavior, while ensuring values such
as service after a comma are passed without leading spaces.
- Around line 218-229: Validate the realm URL before applying credentials in the
request flow around credentialsForRegistry: parse the realm and reject it unless
it uses HTTPS and has an acceptable host for the registry authentication
endpoint. Ensure this validation occurs before req.SetBasicAuth, so credentials
are never sent to HTTP or unrelated hosts.

---

Outside diff comments:
In `@src/clis/nvcf-cli/cmd/self_hosted_check.go`:
- Around line 145-162: Update the outerTimeout calculation near
clusterValidatorWillRun to account for both sequential validator executions in
ModeSingle, using a 10-minute validator budget plus existing headroom while
retaining the shorter timeout for a single run. Ensure the resulting context
preserves the full wait for both RunPreflightForRole calls and does not alter
unrelated cleanup behavior.

---

Nitpick comments:
In `@src/clis/nvcf-cli/cmd/self_hosted_check_test.go`:
- Around line 347-385: Add a table-driven TestControlPlaneIsTargeted alongside
TestComputePlaneIsTargeted, covering control-plane targeting across ModeSingle
and ModeSplit, including --pre, --compute-plane, --all, and no relevant flags.
Assert each case against controlPlaneIsTargeted and reset the shared checkPre,
checkComputePlane, and checkAll state after the test.

In `@src/clis/nvcf-cli/cmd/self_hosted_check.go`:
- Around line 287-310: Update resolveStackValuesFile to first use a configurable
values-file flag or Viper key when provided, allowing any environment path and
installed CLI usage; retain the existing working-directory walk for
deploy/stacks/self-managed/environments/local.yaml only as the fallback when no
override is configured.

In `@src/clis/nvcf-cli/internal/selfhosted/clustervalidator_test.go`:
- Around line 494-495: Add a test case in TestBuildClusterValidatorJobShape that
calls buildClusterValidatorJob with clusterValidatorControlPlaneRole and asserts
the generated container environment contains that value under VALIDATOR_ROLE.
Keep the existing shape assertions and ensure the test covers role propagation
through the Job env.
- Around line 345-352: Remove the local strSliceContains helper and replace its
call sites with the standard-library slices.Contains function, adding the
required slices import while preserving the existing membership-check behavior.

In `@src/clis/nvcf-cli/internal/selfhosted/clustervalidator.go`:
- Around line 360-384: Replace string-based YAML interpolation in
buildControlPlaneValidatorConfig with typed config structs and sigs.k8s.io/yaml
marshaling, including the baseline endpoints and enforcement settings currently
represented by controlPlaneValidatorConfigTemplate. Parse and append valid extra
registries as non-critical tcp+tls endpoints, allowing YAML escaping to handle
hostnames safely, and remove the strings.Replace insertion logic.
- Around line 386-408: Replace the hand-rolled parsing in parseRegistryHostPort
with net.SplitHostPort and strconv.Atoi. Support bracketed and unbracketed IPv6
correctly, remove trailing colons from empty-port inputs such as "nvcr.io:", and
preserve the existing fallback host/port behavior for missing or invalid ports.

In `@src/clis/nvcf-cli/internal/selfhosted/registry_cred_test.go`:
- Around line 42-46: Update probeRegistryCredential to accept an injected
*http.Client or transport, and use that dependency for requests instead of the
process-wide http.DefaultTransport. Revise the affected tests to pass
srv.Client() (or its transport) directly and remove the DefaultTransport
replacement and cleanup.
🪄 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: Enterprise

Run ID: 5787046b-7875-46b3-b291-3db6a64094de

📥 Commits

Reviewing files that changed from the base of the PR and between 60bdfd1 and dfd490e.

📒 Files selected for processing (12)
  • src/clis/nvcf-cli/cmd/self_hosted_check.go
  • src/clis/nvcf-cli/cmd/self_hosted_check_test.go
  • src/clis/nvcf-cli/internal/selfhosted/clustervalidator.go
  • src/clis/nvcf-cli/internal/selfhosted/clustervalidator_test.go
  • src/clis/nvcf-cli/internal/selfhosted/preflight.go
  • src/clis/nvcf-cli/internal/selfhosted/preflight_test.go
  • src/clis/nvcf-cli/internal/selfhosted/registry_cred.go
  • src/clis/nvcf-cli/internal/selfhosted/registry_cred_test.go
  • src/clis/nvcf-cli/internal/selfhosted/stale_namespace.go
  • src/clis/nvcf-cli/internal/selfhosted/stale_namespace_test.go
  • src/clis/nvcf-cli/internal/selfhosted/validatortag.go
  • src/clis/nvcf-cli/internal/selfhosted/validatortag_test.go

Comment thread src/clis/nvcf-cli/cmd/self_hosted_check_test.go
Comment thread src/clis/nvcf-cli/cmd/self_hosted_check.go Outdated
Comment thread src/clis/nvcf-cli/internal/selfhosted/clustervalidator.go
Comment on lines +210 to 225
// Read-only: cluster inventory and configuration.
{APIGroups: []string{""}, Resources: []string{"nodes", "configmaps"}, Verbs: []string{"get", "list", "watch"}},
// Read + write: enforcement checks create and delete probe namespaces
// and pods; the active-LB check creates and deletes a probe service.
{APIGroups: []string{""}, Resources: []string{"namespaces", "pods", "services"}, Verbs: []string{"get", "list", "watch", "create", "delete"}},
// Pod log subresource: read probe output without exec.
{APIGroups: []string{""}, Resources: []string{"pods/log"}, Verbs: []string{"get"}},
{APIGroups: []string{"storage.k8s.io"}, Resources: []string{"csidrivers", "storageclasses"}, Verbs: []string{"get", "list"}},
{APIGroups: []string{"networking.k8s.io"}, Resources: []string{"networkpolicies"}, Verbs: []string{"get", "list"}},
// NetworkPolicies: read for CNI detection; write for enforcement
// check which creates/updates/deletes policies in the temp namespace.
{APIGroups: []string{"networking.k8s.io"}, Resources: []string{"networkpolicies"}, Verbs: []string{"get", "list", "create", "update", "delete"}},
{APIGroups: []string{"admissionregistration.k8s.io"}, Resources: []string{"mutatingwebhookconfigurations", "validatingwebhookconfigurations"}, Verbs: []string{"get", "list"}},
{APIGroups: []string{"apps"}, Resources: []string{"deployments", "daemonsets", "statefulsets"}, Verbs: []string{"get", "list"}},
// Gateway API: control-plane gateway and route health checks.
{APIGroups: []string{"gateway.networking.k8s.io"}, Resources: []string{"gatewayclasses", "gateways", "httproutes", "grpcroutes"}, Verbs: []string{"get", "list"}},
{NonResourceURLs: []string{"/readyz", "/version", "/healthz"}, Verbs: []string{"get"}},

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟠 Major | 🏗️ Heavy lift

Confirm that cluster-wide write verbs are required.

The ClusterRole grants create and delete on namespaces, pods, and services across every namespace, bound cluster-wide through the ClusterRoleBinding. A ServiceAccount that can create pods in any namespace can mount any ServiceAccount token in that namespace, which is a standard privilege-escalation path. The validator is short-lived, but the ClusterRole and binding persist after the Job because only Jobs are swept.

Confirm the validator binary needs namespace-wide write access rather than write access inside its own probe namespace. If it does, consider deleting the ClusterRole and binding at the end of a run that used --cleanup.

#!/bin/bash
# Locate the validator's own RBAC expectations and any existing cleanup of cluster-scoped RBAC.
rg -nP -C3 'clusterValidatorName|ClusterRoleBindings\(\)|ClusterRoles\(\)' --type=go
rg -nP -C3 'namespaces|networkpolicies' --type=yaml -g '**/cluster-validator/**'
🤖 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 `@src/clis/nvcf-cli/internal/selfhosted/clustervalidator.go` around lines 210 -
225, Confirm the validator’s namespace-wide write requirements by tracing the
operations used by the validator binary, especially namespace, pod, service, and
network-policy checks. If writes only target the probe namespace, replace the
cluster-wide permissions with namespace-scoped Role/RoleBinding access while
retaining required cluster-wide read permissions; otherwise, add cleanup in the
--cleanup flow to delete the validator ClusterRole and ClusterRoleBinding after
the run.

Comment thread src/clis/nvcf-cli/internal/selfhosted/preflight.go
Comment thread src/clis/nvcf-cli/internal/selfhosted/registry_cred.go
Comment thread src/clis/nvcf-cli/internal/selfhosted/registry_cred.go
Comment thread src/clis/nvcf-cli/internal/selfhosted/stale_namespace.go
Comment thread src/clis/nvcf-cli/internal/selfhosted/validatortag.go
Comment thread src/clis/nvcf-cli/internal/selfhosted/validatortag.go
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant