Skip to content

feat(vsphere): Add VSphereCredentialsMode and ComponentCredentials to VSpherePlatformSpec#2

Open
splatypus-bot wants to merge 1 commit into
masterfrom
story-36-vsphere-credentials-mode
Open

feat(vsphere): Add VSphereCredentialsMode and ComponentCredentials to VSpherePlatformSpec#2
splatypus-bot wants to merge 1 commit into
masterfrom
story-36-vsphere-credentials-mode

Conversation

@splatypus-bot
Copy link
Copy Markdown

@splatypus-bot splatypus-bot commented May 8, 2026

Summary

  • Adds VSphereCredentialsMode type (Passthrough/PerComponent) to config/v1
  • Adds CredentialsMode and ComponentCredentials fields to VSpherePlatformSpec
  • Adds VSphereComponentCredentials and VSphereComponentSecretRef types
  • Adds DeepCopy methods for new types to zz_generated.deepcopy.go
  • Adds 14 unit tests covering all 3 ACs and adversarial cases

VSphereCredentialsModePassthrough uses "" (empty string) as its value so the Go zero value equals Passthrough, preserving backward compatibility for existing clusters that do not set credentialsMode.

go test output

=== RUN   TestVSphereCredentialsMode_ZeroValue
--- PASS: TestVSphereCredentialsMode_ZeroValue (0.00s)
=== RUN   TestVSpherePlatformSpec_CredentialsModeUnset_DefaultsPassthrough
--- PASS: TestVSpherePlatformSpec_CredentialsModeUnset_DefaultsPassthrough (0.00s)
=== RUN   TestVSpherePlatformSpec_CredentialsModePassthrough
--- PASS: TestVSpherePlatformSpec_CredentialsModePassthrough (0.00s)
=== RUN   TestVSpherePlatformSpec_CredentialsModePerComponent
--- PASS: TestVSpherePlatformSpec_CredentialsModePerComponent (0.00s)
=== RUN   TestVSpherePlatformSpec_JSONRoundTrip_NoCredentialsMode
--- PASS: TestVSpherePlatformSpec_JSONRoundTrip_NoCredentialsMode (0.00s)
=== RUN   TestVSpherePlatformSpec_JSONRoundTrip_ExplicitPassthrough
--- PASS: TestVSpherePlatformSpec_JSONRoundTrip_ExplicitPassthrough (0.00s)
=== RUN   TestVSpherePlatformSpec_PerComponent_AllComponents
--- PASS: TestVSpherePlatformSpec_PerComponent_AllComponents (0.00s)
=== RUN   TestVSpherePlatformSpec_PerComponent_PartialComponents
--- PASS: TestVSpherePlatformSpec_PerComponent_PartialComponents (0.00s)
=== RUN   TestVSpherePlatformSpec_PerComponent_JSONRoundTrip
--- PASS: TestVSpherePlatformSpec_PerComponent_JSONRoundTrip (0.00s)
=== RUN   TestVSpherePlatformSpec_EmptyStringCredentialsMode
--- PASS: TestVSpherePlatformSpec_EmptyStringCredentialsMode (0.00s)
=== RUN   TestVSpherePlatformSpec_ComponentCredentials_NilPointerSafety
--- PASS: TestVSpherePlatformSpec_ComponentCredentials_NilPointerSafety (0.00s)
=== RUN   TestVSphereComponentSecretRef_EmptyNamespace
--- PASS: TestVSphereComponentSecretRef_EmptyNamespace (0.00s)
=== RUN   TestVSphereComponentSecretRef_EmptyName
--- PASS: TestVSphereComponentSecretRef_EmptyName (0.00s)
=== RUN   TestVSpherePlatformSpec_DeepCopy_PointerIsolation
--- PASS: TestVSpherePlatformSpec_DeepCopy_PointerIsolation (0.00s)
PASS
ok      github.com/openshift/api/config/v1      0.011s

Implementation Notes

  • VSphereCredentialsModePassthrough = "" so the Go zero value is Passthrough; omitempty omits it from JSON for existing clusters — no custom marshaler needed
  • VSphereCredentialsModePerComponent = "PerComponent"
  • 4th component field named VSphereProblemDetector (matching updated design doc, not Diagnostics)
  • DeepCopy written by hand (no code-gen run); follows the pattern of existing generated deepcopy functions

Closes openshift-splat-team/splat-team#36

Summary by CodeRabbit

  • New Features

    • Added per-component credential configuration for vSphere infrastructure. Clusters can now choose between shared credentials (default) or individual credentials for machine API, CSI driver, cloud controller manager, and vSphere problem detector components.
  • Tests

    • Added comprehensive test coverage for vSphere credentials configuration.

…ls to VSpherePlatformSpec

Adds VSphereCredentialsMode (Passthrough/PerComponent) and
VSphereComponentCredentials/VSphereComponentSecretRef types to
VSpherePlatformSpec in the Infrastructure CR API, enabling per-component
vCenter credential isolation for story openshift#36.

- VSphereCredentialsModePassthrough (zero value = "") preserves backward
  compatibility: existing clusters that do not set credentialsMode
  automatically get Passthrough behavior
- VSphereCredentialsModePerComponent enables per-component secret refs
  for machineAPI, csiDriver, cloudController, and vsphereProblemDetector
- DeepCopy methods added to zz_generated.deepcopy.go for the new types
- 14 unit tests covering all 3 acceptance criteria and adversarial cases

Resolves: openshift-splat-team/splat-team#36
Parent: openshift-splat-team/splat-team#33
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 8, 2026

Review Change Stack

📝 Walkthrough

Walkthrough

This PR extends the vSphere infrastructure API with credential mode selection and per-component secret references. It introduces VSphereCredentialsMode (with Passthrough as the zero-value default) and ComponentCredentials containing optional secret refs for machine API, CSI driver, cloud controller manager, and vSphere problem detector. The changes include autogenerated deep-copy support and comprehensive test coverage for defaults, JSON round-tripping, and edge cases.

Changes

VSphere Credentials API Extension

Layer / File(s) Summary
API Type Definitions
config/v1/types_infrastructure.go
Extends VSpherePlatformSpec with CredentialsMode and ComponentCredentials fields. Adds VSphereCredentialsMode enum (Passthrough/"" and PerComponent), VSphereComponentCredentials struct with optional secret refs for four components, and VSphereComponentSecretRef with required Name and Namespace fields.
Deep Copy Support
config/v1/zz_generated.deepcopy.go
Auto-generated DeepCopyInto and DeepCopy methods for VSphereComponentCredentials and VSphereComponentSecretRef. Updated VSpherePlatformSpec.DeepCopyInto to recursively copy nested ComponentCredentials field.
Test Coverage
config/v1/vsphere_credentials_test.go
Validates zero-value defaults (Passthrough), explicit mode values, JSON round-tripping for legacy input without credentialsMode and with empty credentialsMode, per-component credential presence and absence, adversarial edge cases (empty Name/Namespace), and deep-copy pointer isolation for nested secret refs.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Possibly related issues

Poem

🐰 New types spring forth with credentials in hand,
Passthrough and PerComponent, working as planned,
Deep copies ensure no pointer confusion,
Tests check each edge case with precise precision,
vSphere components can now choose their way! 🎉

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 28.57% 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 accurately summarizes the main additions to VSpherePlatformSpec: VSphereCredentialsMode and ComponentCredentials types.
Linked Issues check ✅ Passed All acceptance criteria from issue #36 are met: VSphereCredentialsMode with Passthrough/PerComponent values [#36], zero-value default to Passthrough [#36], per-component credentials for machineAPI, csiDriver, cloudController, and diagnostics (VSphereProblemDetector) [#36].
Out of Scope Changes check ✅ Passed All changes are in-scope: infrastructure API types, credentials mode enums, component credentials structures, deep-copy implementations, and comprehensive test coverage for the new vSphere credentials functionality.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch story-36-vsphere-credentials-mode

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 and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (2)
config/v1/vsphere_credentials_test.go (2)

60-72: 💤 Low value

TestVSpherePlatformSpec_EmptyStringCredentialsMode is a duplicate of TestVSpherePlatformSpec_JSONRoundTrip_ExplicitPassthrough.

Both tests unmarshal the identical JSON string ({"credentialsMode": ""}) and assert the same condition (spec.CredentialsMode == VSphereCredentialsModePassthrough). The only difference is the error message wording. One of them should be removed — this inflates the stated test count of 14 by one redundant case and could mislead reviewers into thinking the adversarial section covers a distinct scenario.

♻️ Proposed fix: remove the redundant adversarial test
-func TestVSpherePlatformSpec_EmptyStringCredentialsMode(t *testing.T) {
-	raw := `{"credentialsMode": ""}`
-	var spec VSpherePlatformSpec
-	if err := json.Unmarshal([]byte(raw), &spec); err != nil {
-		t.Fatalf("unmarshal error: %v", err)
-	}
-	if spec.CredentialsMode != VSphereCredentialsModePassthrough {
-		t.Errorf("empty credentialsMode = %q; want Passthrough", spec.CredentialsMode)
-	}
-}

Also applies to: 176-185

🤖 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 `@config/v1/vsphere_credentials_test.go` around lines 60 - 72, Remove the
redundant test that duplicates behavior of
TestVSpherePlatformSpec_JSONRoundTrip_ExplicitPassthrough: locate the duplicate
test function TestVSpherePlatformSpec_EmptyStringCredentialsMode (also present
around the other occurrence noted) and delete it so only one test asserts that
unmarshalling `{"credentialsMode": ""}` yields
VSphereCredentialsModePassthrough; ensure there are no remaining duplicate
assertions or error-message-only differences after removal.

187-200: ⚡ Quick win

TestVSpherePlatformSpec_ComponentCredentials_NilPointerSafety has no meaningful assertion and is effectively a no-op.

Two issues:

  1. Trivially-true assertion (lines 192–194): ComponentCredentials was just assigned nil on line 190, so spec.ComponentCredentials != nil is always false and t.Fatalf is unreachable. This check never catches anything.

  2. Dead-code safe-access pattern (lines 195–199): The if spec.ComponentCredentials != nil branch is always false, so machineAPICreds is always nil. _ = machineAPICreds discards the result with no assertion — the nil-safety claim in the test name is never exercised.

A more meaningful version would at least assert machineAPICreds == nil after the guarded access to confirm the pattern yields the expected result:

♻️ Proposed fix: add a meaningful assertion
 func TestVSpherePlatformSpec_ComponentCredentials_NilPointerSafety(t *testing.T) {
 	spec := VSpherePlatformSpec{
 		CredentialsMode:      VSphereCredentialsModePassthrough,
 		ComponentCredentials: nil,
 	}
-	if spec.ComponentCredentials != nil {
-		t.Fatalf("expected nil ComponentCredentials")
-	}
 	var machineAPICreds *VSphereComponentSecretRef
 	if spec.ComponentCredentials != nil {
 		machineAPICreds = spec.ComponentCredentials.MachineAPI
 	}
-	_ = machineAPICreds
+	if machineAPICreds != nil {
+		t.Errorf("expected nil machineAPICreds when ComponentCredentials is nil; got %+v", machineAPICreds)
+	}
 }
🤖 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 `@config/v1/vsphere_credentials_test.go` around lines 187 - 200, The test
TestVSpherePlatformSpec_ComponentCredentials_NilPointerSafety currently contains
unreachable checks and no real assertion; update it so after initializing spec
:= VSpherePlatformSpec{ComponentCredentials: nil} you perform the guarded access
(if spec.ComponentCredentials != nil { machineAPICreds =
spec.ComponentCredentials.MachineAPI }) and then assert that machineAPICreds ==
nil (e.g. t.Fatalf or t.Errorf on non-nil) to validate the nil-safe access
pattern; remove the trivially-true/unreachable t.Fatalf and reference
VSpherePlatformSpec, ComponentCredentials, MachineAPI and
VSphereComponentSecretRef when locating the code to change.
🤖 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 `@config/v1/types_infrastructure.go`:
- Around line 1674-1680: The Name and Namespace fields in the secret reference
struct are marked Required but lack a minimum-length constraint, so add
kubebuilder validation to enforce non-empty values: add the annotation `//
+kubebuilder:validation:MinLength=1` above both the `Name string
\`json:"name"\`` and `Namespace string \`json:"namespace"\`` declarations in
types_infrastructure.go (the struct fields named Name and Namespace) so the CRD
rejects empty strings.

---

Nitpick comments:
In `@config/v1/vsphere_credentials_test.go`:
- Around line 60-72: Remove the redundant test that duplicates behavior of
TestVSpherePlatformSpec_JSONRoundTrip_ExplicitPassthrough: locate the duplicate
test function TestVSpherePlatformSpec_EmptyStringCredentialsMode (also present
around the other occurrence noted) and delete it so only one test asserts that
unmarshalling `{"credentialsMode": ""}` yields
VSphereCredentialsModePassthrough; ensure there are no remaining duplicate
assertions or error-message-only differences after removal.
- Around line 187-200: The test
TestVSpherePlatformSpec_ComponentCredentials_NilPointerSafety currently contains
unreachable checks and no real assertion; update it so after initializing spec
:= VSpherePlatformSpec{ComponentCredentials: nil} you perform the guarded access
(if spec.ComponentCredentials != nil { machineAPICreds =
spec.ComponentCredentials.MachineAPI }) and then assert that machineAPICreds ==
nil (e.g. t.Fatalf or t.Errorf on non-nil) to validate the nil-safe access
pattern; remove the trivially-true/unreachable t.Fatalf and reference
VSpherePlatformSpec, ComponentCredentials, MachineAPI and
VSphereComponentSecretRef when locating the code to change.
🪄 Autofix (Beta)

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

Review profile: CHILL

Plan: Pro Plus

Run ID: fdc5f779-83b0-4001-8177-da9ef11628e9

📥 Commits

Reviewing files that changed from the base of the PR and between 6bababe and 41cad17.

📒 Files selected for processing (3)
  • config/v1/types_infrastructure.go
  • config/v1/vsphere_credentials_test.go
  • config/v1/zz_generated.deepcopy.go

Comment on lines +1674 to +1680
// name is the name of the secret.
// +kubebuilder:validation:Required
Name string `json:"name"`

// namespace is the namespace of the secret.
// +kubebuilder:validation:Required
Namespace string `json:"namespace"`
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Enforce non-empty secret reference fields

Name and Namespace are marked required, but empty strings are still valid without length constraints. That allows invalid secret refs to pass schema validation and fail later at runtime. Please add MinLength=1 on both fields (Line 1676, Line 1680).

Suggested diff
 type VSphereComponentSecretRef struct {
 	// name is the name of the secret.
 	// +kubebuilder:validation:Required
+	// +kubebuilder:validation:MinLength=1
 	Name string `json:"name"`

 	// namespace is the namespace of the secret.
 	// +kubebuilder:validation:Required
+	// +kubebuilder:validation:MinLength=1
 	Namespace string `json:"namespace"`
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// name is the name of the secret.
// +kubebuilder:validation:Required
Name string `json:"name"`
// namespace is the namespace of the secret.
// +kubebuilder:validation:Required
Namespace string `json:"namespace"`
// name is the name of the secret.
// +kubebuilder:validation:Required
// +kubebuilder:validation:MinLength=1
Name string `json:"name"`
// namespace is the namespace of the secret.
// +kubebuilder:validation:Required
// +kubebuilder:validation:MinLength=1
Namespace string `json:"namespace"`
🤖 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 `@config/v1/types_infrastructure.go` around lines 1674 - 1680, The Name and
Namespace fields in the secret reference struct are marked Required but lack a
minimum-length constraint, so add kubebuilder validation to enforce non-empty
values: add the annotation `// +kubebuilder:validation:MinLength=1` above both
the `Name string \`json:"name"\`` and `Namespace string \`json:"namespace"\``
declarations in types_infrastructure.go (the struct fields named Name and
Namespace) so the CRD rejects empty strings.

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.

Infrastructure CR API Extension for VSphereCredentialsMode

1 participant