Skip to content

GCP-231: feat(api): add GCP Workload Identity Federation types and validation - #7285

Merged
openshift-merge-bot[bot] merged 2 commits into
openshift:mainfrom
apahim:gcp_wif_api
Dec 3, 2025
Merged

openshift-merge-bot[bot] merged 2 commits into
openshift:mainfrom
apahim:gcp_wif_api

Conversation

@apahim

@apahim apahim commented Nov 25, 2025 •

Copy link
Copy Markdown
Contributor

What this PR does / why we need it:

This PR introduces Workload Identity Federation (WIF) API types for the GCP platform in HyperShift. These changes lay the foundation for secure, keyless
authentication between hosted control planes and GCP services.

The PR adds:

  1. GCP Workload Identity Federation API Types (feat(api)):

    • GCPWorkloadIdentityConfig: Core structure for WIF configuration including service account references and project metadata
    • GCPResourceLabel: RFC1035-compliant labels for Compute Engine resources
    • Comprehensive validation rules following GCP specifications:
      • Project ID and region validation
      • Resource labels (RFC1035 format, no underscores)
      • Service account email validation with hardened regex patterns
      • Project number validation
      • Network and subnet name validation
      • Reserved prefix validation (blocks 'goog' prefix per GCP standards)
    • New condition type ValidWorkloadIdentityConfiguration for platform validation
    • Complete unit test coverage for validation rules
  2. Client Apply Configurations (feat(client)):

    • Generated apply configurations for declarative client operations with server-side apply
    • Support for GCPPlatformSpec, GCPResourceLabel, GCPServiceAccountsRef, and GCPWorkloadIdentityConfig

All changes include:

  • Updated CRD manifests (feature-gated and standard)
  • Generated deepcopy functions
  • API documentation updates
  • Vendored API updates

Which issue(s) this PR fixes:

Fixes GCP-231

Special notes for your reviewer:

  • This PR only adds the API layer for WIF - no controller implementation yet
  • All validation rules follow official GCP naming conventions and constraints
  • Resource labels specifically follow RFC1035 (used by Compute Engine) which differs from standard Kubernetes labels (RFC1123)
  • The GCPWorkloadIdentityConfig structure is designed to support both user-provided and HyperShift-managed service accounts
  • Validation tests cover edge cases including reserved prefixes, special characters, and length constraints

Checklist:

  • Subject and description added to both, commit and PR.
  • Relevant issues have been referenced.
  • This change includes docs. (API docs auto-generated)
  • This change includes unit tests.

@coderabbitai

coderabbitai Bot commented Nov 25, 2025 •

Copy link
Copy Markdown
Contributor

Walkthrough

Adds GCP Workload Identity Federation and resource label types; extends GCPPlatformSpec with WorkloadIdentity and ResourceLabels; tightens GCP naming regexes; adds immutability and cross-field CRD validations; introduces two GCP condition types; updates deepcopy, client apply configs, CLI flags/tests, CRD manifests, docs, fixtures, and pins k8s.io/utils.

Changes

Cohort / File(s) Summary
API Types
api/hypershift/v1beta1/gcp.go
Added GCPResourceLabel, GCPWorkloadIdentityConfig, GCPServiceAccountsEmails; changed GCPResourceReference name pattern; added ResourceLabels and WorkloadIdentity fields and XValidation immutability/validation rules.
Conditions & Constants
api/hypershift/v1beta1/hostedcluster_conditions.go, api/hypershift/v1beta1/hostedcluster_types.go
Added ValidGCPCredentials and ValidGCPWorkloadIdentity ConditionTypes and ClusterAPIGCPProviderImage constant.
DeepCopy Generated
api/hypershift/v1beta1/zz_generated.deepcopy.go
Generated DeepCopy methods for new GCP types; updated GCPPlatformSpec and PlatformSpec DeepCopy logic to deep-copy ResourceLabels and WorkloadIdentity.
Feature-gated CRD Manifests
api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/.../GCPPlatform.yaml
Added resourceLabels and workloadIdentity schemas, patterns, lengths, immutability rules, list/map semantics, and cross-field validations; tightened project, region, and resource name regexes and docs.
Installed CRD Manifests
cmd/install/assets/.../zz_generated.crd-manifests/.../hostedclusters-*.crd.yaml, .../hostedcontrolplanes-*.crd.yaml
Mirrored schema additions and validations: resourceLabels, workloadIdentity, stricter regexes, x-kubernetes-validations enforcing immutability and project-consistency; updated descriptions and required fields.
Client Apply Configs
client/applyconfiguration/hypershift/v1beta1/gcpplatformspec.go, .../gcpresourcelabel.go, .../gcpworkloadidentityconfig.go, .../gcpserviceaccountsemails.go
Added apply-configuration types and builders for GCPResourceLabel, GCPWorkloadIdentityConfig, GCPServiceAccountsEmails; added WithResourceLabels and WithWorkloadIdentity.
Client Utils / Mapping
client/applyconfiguration/utils.go
Registered new kinds in ForKind mapping for apply-configuration types.
CLI: cluster create
cmd/cluster/gcp/create.go
Added raw create options/flags (Network, PrivateServiceConnectSubnet, WorkloadIdentityProjectNumber, WorkloadIdentityPoolID, WorkloadIdentityProviderID, NodePoolServiceAccount, ControlPlaneServiceAccount); validation and mapping into GCP platform spec.
CLI Tests & Fixture
cmd/cluster/gcp/create_test.go, cmd/cluster/gcp/testdata/zz_fixture_TestCreateCluster_minimal_flags_necessary_to_render.yaml
Updated tests/fixture to include new CLI fields and workloadIdentity; extended validation cases and assertions.
E2E Tests
test/e2e/v2/tests/api_ux_validation_test.go
Added GCP Workload Identity Federation validation contexts (accept/reject cases) and helper functions for HostedCluster/NodePool creation (duplicate context block present).
Docs
docs/content/reference/api.md
Documented new GCP types and fields (GCPResourceLabel, GCPServiceAccountsEmails, GCPWorkloadIdentityConfig) and added resourceLabels and workloadIdentity to GCPPlatformSpec docs.
Dependency Pin
api/go.mod, go.mod
Added replace directive pinning k8s.io/utils to v0.0.0-20241104100929-3ea5e8cea738.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

  • Areas needing extra attention:
    • CRD x-kubernetes-validations (immutability and cross-field project/email checks).
    • Regex/pattern changes for project, region, and resource name constraints (verify semantics and examples).
    • DeepCopy correctness for slices/pointers (ResourceLabels, WorkloadIdentity, ServiceAccountsEmails).
    • CLI flag parsing/validation and mapping to platform spec plus unit tests.
    • E2E test additions (remove duplicated context) and new helper functions.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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

@openshift-ci
openshift-ci Bot requested review from jparrill and muraee November 25, 2025 13:47
@openshift-ci openshift-ci Bot added area/api Indicates the PR includes changes for the API area/cli Indicates the PR includes changes for CLI area/documentation Indicates the PR includes changes for documentation and removed do-not-merge/needs-area labels Nov 25, 2025

@coderabbitai coderabbitai Bot 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.

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 (2)
api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/GCPPlatform.yaml (1)

4676-4689: Revise reserved-word guard to forbid only "google"—not "goog".

GCP project IDs forbid "google" but not "goog". The latter is a Cloud Storage bucket restriction. Update the CEL rule accordingly.

   project:
     ...
     pattern: ^[a-z]([a-z0-9-]{4,28}[a-z0-9])$
     type: string
     x-kubernetes-validations:
+    - message: Project ID must not contain reserved substring "google"
+      rule: !self.contains('google')
     - message: Project is immutable
       rule: self == oldSelf
api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/GCPPlatform.yaml (1)

4784-4798: Refine the regex pattern to block only "google", not "goog".

GCP project ID restrictions disallow the substring "google" but do not restrict "goog" at the project ID level (it's only restricted for specific resources like GCS buckets). Update the pattern to block only the reserved word:

   project:
@@
-  pattern: ^(?!.*google)(?!.*goog)[a-z]([a-z0-9-]{4,28}[a-z0-9])$
+  pattern: ^(?!.*google)[a-z]([a-z0-9-]{4,28}[a-z0-9])$
🧹 Nitpick comments (16)
api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/GCPPlatform.yaml (4)

4634-4649: Scope immutability to the field, not the whole object (future-proofing).

Object-level immutability on network may block adding future optional fields. Prefer making only name immutable.

   properties:
     name:
       ...
       type: string
+      x-kubernetes-validations:
+      - message: Network name is immutable
+        rule: self == oldSelf
   required:
   - name
   type: object
-  x-kubernetes-validations:
-  - message: Network is immutable
-    rule: self == oldSelf

4655-4670: Same here: make only subnet name immutable.

Avoid freezing the entire privateServiceConnectSubnet object.

   properties:
     name:
       ...
       type: string
+      x-kubernetes-validations:
+      - message: Private Service Connect subnet name is immutable
+        rule: self == oldSelf
   required:
   - name
   type: object
-  x-kubernetes-validations:
-  - message: Private Service Connect subnet is immutable
-    rule: self == oldSelf

4708-4757: Consider lowering maxItems to leave headroom for system labels.

You note HyperShift reserves ~4 labels; with maxItems 64 users can hit per-resource limits. Consider maxItems 60 to avoid runtime failures.

-                        maxItems: 64
+                        maxItems: 60

4759-4854: Deduplicate per-field immutability; add cross-field validation for project consistency.

Verification confirms all three points:

  1. "gcp-" prefix reservation: Verified correct. Google reserves this prefix for Workload Identity Pool and Provider IDs.

  2. Per-field immutability redundancy: The code contains individual immutability rules for poolID, providerID, projectNumber, and nodePoolEmail (shown in snippet). These are redundant with the object-level rule: self == oldSelf at the workloadIdentity level. Remove the per-field duplicates.

  3. Feature gating is proper: workloadIdentity appears only in featuregated CRDs (*TechPreviewNoUpgrade.crd.yaml, *CustomNoUpgrade.crd.yaml) and is required there. It is completely absent from base *Default.crd.yaml CRDs, which correctly prevents breaking upgrades on non-featuregated installations.

  4. Cross-field validation feasibility: CEL supports the .split("@") syntax for email domain extraction. Add the proposed validation rule at spec.platform.gcp level to ensure nodePoolEmail project matches spec.platform.gcp.project.

api/hypershift/v1beta1/gcp_validation_test.go (2)

7-59: Consider adding negative test cases to validate rejection of invalid inputs.

The test only verifies that valid structs can be constructed, but doesn't test that invalid inputs would be rejected. According to the PR objectives, GCPResourceLabel has strict RFC1035-compliant validation rules including:

  • Keys starting with 'goog' prefix should be rejected
  • Keys/values with underscores should be rejected (RFC1035)
  • Keys/values ending with hyphens should be rejected
  • Keys/values exceeding 63 characters should be rejected
  • Keys starting with uppercase letters should be rejected

While CEL validation in the CRD will ultimately enforce these rules, consider adding table entries that document expected failures to serve as regression tests when the validation logic changes.

Example negative cases to add:

+	{
+		name:  "When label key starts with reserved 'goog' prefix, it should fail validation",
+		label: GCPResourceLabel{Key: "goog-test", Value: "value"},
+		expectError: true,
+	},
+	{
+		name:  "When label key contains underscore, it should fail validation",
+		label: GCPResourceLabel{Key: "test_key", Value: "value"},
+		expectError: true,
+	},

61-101: Consider adding negative test cases for invalid region formats.

Similar to the TestGCPResourceLabel function, this test only verifies that valid region strings can be assigned but doesn't validate that invalid formats would be rejected. Consider adding negative test cases such as:

  • Regions with uppercase letters
  • Regions with invalid characters
  • Empty regions
  • Regions with trailing/leading hyphens

This would document expected validation behavior and serve as regression tests.

docs/content/reference/api.md (3)

5954-5959: Make region format machine‑checkable.

Consider adding an explicit regex (e.g., ^[a-z]+(-[a-z0-9]+)*[0-9]$) and a note that zones (e.g., “-a”) must not be appended to regions. This reduces ambiguity for users and validators.


6001-6030: WIF prerequisites: add concrete attribute mapping example.

Include a brief mapping snippet (google.subject -> assertion.sub; attribute.aud -> assertion.aud) to make setup reproducible and reduce misconfiguration.


6001-6007: List reserved/auto‑applied labels.

You mention “reserves approximately 4 labels.” Naming them (keys) helps users avoid conflicts.

cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-CustomNoUpgrade.crd.yaml (1)

5894-5989: WIF block looks solid; minor nits only.

  • poolID/providerID/projectNumber validations and immutability are sensible.
  • Service account email regex is precise for GSA format.

Optional: object-level immutability plus per-field immutability is redundant; you can keep only the object-level rule to reduce noise.

api/hypershift/v1beta1/gcp.go (1)

131-139: Consider lowering ResourceLabels MaxItems to account for reserved system labels

You note that GCP allows up to 64 labels per resource and that HyperShift reserves ~4 labels for system use, but ResourceLabels currently allows up to 64 user-specified entries. This can lead to hard-to-debug failures at reconciliation time when combined with system labels.

Consider setting MaxItems to something like 60 (or another explicit budget) so user configs cannot exceed the provider’s effective limit once system labels are included.

cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-TechPreviewNoUpgrade.crd.yaml (2)

5554-5604: Prevent duplicate label keys and leave headroom for system labels

  • Today duplicates are possible since this is a plain array. Make it a map keyed by "key" to enforce uniqueness.
  • maxItems is 64, but controllers add ~4 system labels. Users could hit the per-resource 64 limit at runtime. Either reduce to 60 here or validate in controllers.

Proposed diff (unique keys + headroom to 60):

-                        maxItems: 64
-                        type: array
+                        maxItems: 60
+                        type: array
+                        x-kubernetes-list-map-keys:
+                        - key
+                        x-kubernetes-list-type: map

5605-5700: Relax object-level immutability on workloadIdentity

You already mark each field immutable. Keeping x-kubernetes-validations: self == oldSelf at the object level blocks any safe, additive day-2 changes (e.g., future optional fields) and forces cluster recreation for rotations. Recommend removing the object-level rule and relying on per-field immutability.

Proposed diff (remove object-level immutability):

-                        x-kubernetes-validations:
-                        - message: WorkloadIdentity is immutable
-                          rule: self == oldSelf

Please confirm you don’t need to rotate service account emails or extend this struct day‑2; if rotation is required, the current object-level immutability will prevent it.

api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/GCPPlatform.yaml (1)

4816-4865: Enforce unique label keys and prefer map semantics.

Duplicate keys can slip through and cause confusion when applied. Model this list as a map keyed by key.

Apply:

 resourceLabels:
@@
-  items:
+  x-kubernetes-list-type: map
+  x-kubernetes-list-map-keys:
+  - key
+  items:
     properties:
       key:
         pattern: ^[a-z]([0-9a-z-]{0,61}[0-9a-z])?$
       value:
         pattern: ^$|^[0-9a-z]([0-9a-z-]{0,61}[0-9a-z])?$
cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-TechPreviewNoUpgrade.crd.yaml (2)

5432-5441: Tighten region regex to avoid digits in non-terminal segments.

Current pattern allows cases like “us-2west1” which aren’t valid. Recommend constraining digits to the trailing segment only.

Apply this diff:

- pattern: ^[a-z]+(-[a-z0-9]+)+[0-9]+$
+ pattern: ^[a-z]+(?:-[a-z]+)+[0-9]+$

Examples still valid: us-central1, europe-west12, northamerica-northeast1. Invalid as intended: us1, us-central, us-central1-a.


5597-5598: Requiring workloadIdentity at platform.gcp may be a breaking change.

Making spec.platform.gcp.workloadIdentity required forces WIF on all new GCP clusters and blocks updates where it is unset.

  • Confirm this is feature-gated for TechPreview only and won’t affect existing non-WIF flows.
  • Consider making it optional (omit from required) and fail validation only when endpointAccess/networkConfig imply WIF.
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to Reviews -> Disable Knowledge Base setting

📥 Commits

Reviewing files that changed from the base of the PR and between 34cc9c7 and df43618.

⛔ Files ignored due to path filters (4)
  • vendor/github.com/openshift/hypershift/api/hypershift/v1beta1/gcp.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/openshift/hypershift/api/hypershift/v1beta1/hostedcluster_conditions.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/openshift/hypershift/api/hypershift/v1beta1/hostedcluster_types.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/openshift/hypershift/api/hypershift/v1beta1/zz_generated.deepcopy.go is excluded by !vendor/**, !**/vendor/**
📒 Files selected for processing (17)
  • api/hypershift/v1beta1/gcp.go (4 hunks)
  • api/hypershift/v1beta1/gcp_validation_test.go (1 hunks)
  • api/hypershift/v1beta1/hostedcluster_conditions.go (1 hunks)
  • api/hypershift/v1beta1/hostedcluster_types.go (1 hunks)
  • api/hypershift/v1beta1/zz_generated.deepcopy.go (4 hunks)
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/GCPPlatform.yaml (3 hunks)
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/GCPPlatform.yaml (3 hunks)
  • client/applyconfiguration/hypershift/v1beta1/gcpplatformspec.go (2 hunks)
  • client/applyconfiguration/hypershift/v1beta1/gcpresourcelabel.go (1 hunks)
  • client/applyconfiguration/hypershift/v1beta1/gcpserviceaccountsref.go (1 hunks)
  • client/applyconfiguration/hypershift/v1beta1/gcpworkloadidentityconfig.go (1 hunks)
  • client/applyconfiguration/utils.go (1 hunks)
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-CustomNoUpgrade.crd.yaml (3 hunks)
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-TechPreviewNoUpgrade.crd.yaml (3 hunks)
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-CustomNoUpgrade.crd.yaml (3 hunks)
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-TechPreviewNoUpgrade.crd.yaml (3 hunks)
  • docs/content/reference/api.md (5 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**

⚙️ CodeRabbit configuration file

-Focus on major issues impacting performance, readability, maintainability and security. Avoid nitpicks and avoid verbosity.

Files:

  • api/hypershift/v1beta1/gcp_validation_test.go
  • client/applyconfiguration/hypershift/v1beta1/gcpserviceaccountsref.go
  • client/applyconfiguration/utils.go
  • client/applyconfiguration/hypershift/v1beta1/gcpresourcelabel.go
  • client/applyconfiguration/hypershift/v1beta1/gcpworkloadidentityconfig.go
  • api/hypershift/v1beta1/hostedcluster_conditions.go
  • api/hypershift/v1beta1/hostedcluster_types.go
  • client/applyconfiguration/hypershift/v1beta1/gcpplatformspec.go
  • docs/content/reference/api.md
  • api/hypershift/v1beta1/zz_generated.deepcopy.go
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-CustomNoUpgrade.crd.yaml
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-TechPreviewNoUpgrade.crd.yaml
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-TechPreviewNoUpgrade.crd.yaml
  • api/hypershift/v1beta1/gcp.go
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/GCPPlatform.yaml
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-CustomNoUpgrade.crd.yaml
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/GCPPlatform.yaml
🧬 Code graph analysis (6)
api/hypershift/v1beta1/gcp_validation_test.go (2)
api/hypershift/v1beta1/gcp.go (1)
  • GCPResourceLabel (23-54)
test/e2e/util/external_oidc.go (1)
  • Key (289-292)
client/applyconfiguration/utils.go (4)
client/applyconfiguration/hypershift/v1beta1/gcpresourcelabel.go (1)
  • GCPResourceLabelApplyConfiguration (22-25)
client/applyconfiguration/hypershift/v1beta1/gcpresourcereference.go (1)
  • GCPResourceReferenceApplyConfiguration (22-24)
client/applyconfiguration/hypershift/v1beta1/gcpserviceaccountsref.go (1)
  • GCPServiceAccountsRefApplyConfiguration (22-24)
client/applyconfiguration/hypershift/v1beta1/gcpworkloadidentityconfig.go (1)
  • GCPWorkloadIdentityConfigApplyConfiguration (22-27)
client/applyconfiguration/hypershift/v1beta1/gcpworkloadidentityconfig.go (1)
client/applyconfiguration/hypershift/v1beta1/gcpserviceaccountsref.go (1)
  • GCPServiceAccountsRefApplyConfiguration (22-24)
api/hypershift/v1beta1/hostedcluster_conditions.go (1)
api/hypershift/v1beta1/hosted_controlplane.go (1)
  • ConditionType (294-294)
api/hypershift/v1beta1/zz_generated.deepcopy.go (1)
api/hypershift/v1beta1/gcp.go (3)
  • GCPResourceLabel (23-54)
  • GCPServiceAccountsRef (223-236)
  • GCPWorkloadIdentityConfig (162-219)
api/hypershift/v1beta1/gcp.go (1)
client/applyconfiguration/hypershift/v1beta1/gcpresourcereference.go (1)
  • GCPResourceReference (28-30)
🔇 Additional comments (42)
api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/GCPPlatform.yaml (1)

4694-4706: Region regex and guidance look good.

api/hypershift/v1beta1/hostedcluster_types.go (1)

129-131: LGTM!

The constant follows the established pattern for CAPI provider image overrides and is properly documented.

api/hypershift/v1beta1/hostedcluster_conditions.go (1)

154-163: LGTM!

The new condition types follow the established pattern for platform-specific validation conditions and are properly documented.

client/applyconfiguration/utils.go (1)

160-167: LGTM!

The new case statements follow the established pattern and are correctly ordered. As generated code, this is expected to be correct.

client/applyconfiguration/hypershift/v1beta1/gcpserviceaccountsref.go (1)

1-38: LGTM!

This is properly generated apply configuration code following the standard pattern.

client/applyconfiguration/hypershift/v1beta1/gcpresourcelabel.go (1)

1-47: LGTM!

This is properly generated apply configuration code following the standard pattern.

docs/content/reference/api.md (1)

5038-5048: Condition type naming: confirm alignment across API, CRDs, and docs.

Docs add “ValidGCPCredentials” and “ValidGCPWorkloadIdentity”, while the PR summary mentions “ValidWorkloadIdentityConfiguration”. Please confirm the canonical names and keep them consistent everywhere (constants, CRDs, status conditions, and docs).

client/applyconfiguration/hypershift/v1beta1/gcpplatformspec.go (1)

26-92: LGTM!

The auto-generated apply configuration correctly adds the new ResourceLabels and WorkloadIdentity fields with proper builder methods following standard patterns.

client/applyconfiguration/hypershift/v1beta1/gcpworkloadidentityconfig.go (1)

22-65: LGTM!

The auto-generated apply configuration for GCPWorkloadIdentityConfig correctly implements all builder methods with proper chaining support.

api/hypershift/v1beta1/zz_generated.deepcopy.go (3)

1485-1494: LGTM!

The auto-generated DeepCopyInto for GCPPlatformSpec correctly handles the new ResourceLabels slice with proper allocation and copy, and assigns WorkloadIdentity directly since it contains only value types.


1612-1671: LGTM!

The auto-generated deepcopy functions for GCPResourceLabel, GCPServiceAccountsRef, and GCPWorkloadIdentityConfig are correct. These types contain only value-type fields (strings and nested value types), so the simple *out = *in copy semantics are appropriate.


3431-3435: LGTM!

The PlatformSpec.DeepCopyInto now correctly calls DeepCopyInto on the GCPPlatformSpec pointer to ensure the ResourceLabels slice is properly deep-copied rather than shallow-copied.

cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-CustomNoUpgrade.crd.yaml (5)

5769-5785: GCP network name validation looks correct.

Pattern and immutability rule align with GCP naming (lowercase, hyphen, <=63). No issues.


5790-5805: GCP subnet name validation looks correct.

Pattern and immutability rule align with GCP subnet naming. No issues.


5814-5824: Project ID regex is appropriately strict.

Matches GCP rules (6–30, starts letter, lowercase/digits/hyphen, no trailing hyphen). Good guard.


5829-5841: Region regex correctly excludes zones and enforces trailing digits.

Examples provided match; pattern allows multi-segment regions (e.g., northamerica-northeast1). Looks good.


5966-5977: Service account email pattern: consider future-proofing.

If you anticipate longer IDs in the future, keep current limits but add a brief comment noting they mirror current GCP 6–30 constraints. No change required now.

api/hypershift/v1beta1/gcp.go (3)

7-18: Label and resource name validation look consistent with GCP rules

The updated GCPResourceReference name regex and the new GCPResourceLabel key/value patterns (including the goog reserved-prefix CEL check) line up with the documented RFC1035-style constraints and GCP docs you reference, and should give users clear, predictable validation behavior.

Also applies to: 20-54


70-83: Immutability enforcement for network fields is appropriate

Marking Network and PrivateServiceConnectSubnet as immutable both via +immutable and self == oldSelf XValidations matches how these fields are typically treated in cloud platform specs and avoids drift or disruptive mutations after cluster creation.


85-117: Project and region validation are tightened correctly

The Project pattern and length constraints capture the documented GCP project ID rules, and the new Region regex (plus immutability) correctly enforces “at least one hyphen” and “must end in digits” while rejecting zone-style values like us-central1-a.

cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-TechPreviewNoUpgrade.crd.yaml (7)

5480-5489: GCP network name pattern looks good

Matches RFC1035-style GCP resource naming and length constraints. No issues.


5493-5496: Immutability on network object

self == oldSelf is appropriate here since the object only carries name; safe.


5501-5510: GCP PSC subnet name pattern looks good

Consistent with GCP resource naming; no issues.


5514-5516: Immutability on PSC subnet

Reasonable to prevent renames post-create.


5531-5531: Project ID regex aligns with GCP rules

Start-letter, 6–30 chars, lowercase/digits/hyphen, no trailing hyphen. OK.


5540-5549: Region pattern is strict and correct

Forces at least one hyphen and trailing digits (regions, not zones). Examples provided match. OK.


5702-5706: Requiring workloadIdentity in TechPreview CRD: verify upgrade/create paths

Making workloadIdentity required is a breaking schema change. In TechPreviewNoUpgrade this might be fine, but please confirm:

  • No existing HostedClusters on GCP rely on the TechPreview CRD without this field.
  • All applyconfigs/builders default or enforce population.
  • E2E/create flows provide values; otherwise object creation will fail.

If needed, consider making it optional initially and gating enforcement in admission/controllers.

api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/GCPPlatform.yaml (3)

4742-4751: GCP network name validation looks good.

Pattern, bounds, and immutability align with Compute Engine naming rules.

Also applies to: 4755-4758


4763-4771: PSC subnet name validation looks good.

Matches GCP resource name constraints; immutability applied correctly.

Also applies to: 4776-4778


4802-4811: Region regex is reasonable and future-friendly.

Catches common formats and excludes zones; immutability is fine.

cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-CustomNoUpgrade.crd.yaml (4)

5661-5670: GCP network name regex/immutability — LGTM

Pattern and immutability look correct and match Compute naming rules.

Also applies to: 5674-5676


5682-5691: GCP subnet name regex/immutability — LGTM

Consistent with Compute naming rules and day-2 immutability.

Also applies to: 5695-5697


5703-5716: Project ID validation — LGTM

Regex + length bounds align with GCP constraints (6–30 chars; start letter; no trailing hyphen).


5718-5733: Region validation — LGTM

Regex excludes zone suffixes and enforces trailing digits; matches region formats (e.g., us-central1).

cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-TechPreviewNoUpgrade.crd.yaml (8)

5372-5381: GCP network name pattern looks good.

Lowercase, hyphen, end with alnum, ≤63 — matches Compute Engine naming. No changes requested.


5385-5387: Immutability guard for network is correct.

Object-level self == oldSelf is fine here.

Ensure server-side defaulting doesn’t mutate this object on updates (would trip immutability).


5393-5402: PSC subnet name pattern is correct.

Aligns with GCP RFC1035-style constraints. No changes requested.


5406-5408: Immutability for PSC subnet is correct.

Same caveat as network: avoid defaulting-on-update.


5423-5423: Project ID regex matches GCP rules.

6–30 chars, starts with letter, no trailing hyphen. Looks right.


5511-5529: Pool/Provider ID validation looks sound.

Length, charset, reserved ‘gcp-’ prefix, and immutability are appropriate.

Confirm Google’s API does not allow trailing hyphens for these IDs (your regex forbids them).

Also applies to: 5544-5561


5591-5592: Immutability for workloadIdentity object is good.

Object-level immutability matches the security intent.


5569-5577: I need to verify the claims about Google Service Account email formats and CAPG requirements.

I need more context about HyperShift/CAPG requirements for NodePool service accounts.

Let me search for explicit CAPG documentation on service account requirements for GCP NodePool.

The review comment is based on incorrect assumptions about CAPG requirements.

Cluster API Provider GCP documentation explicitly states to "create a new service account with Editor permissions," not use default service accounts. User-managed service accounts follow the format: service-account-name@project-id.iam.gserviceaccount.com—which the current regex correctly validates.

While the default Compute Engine service account does use the format PROJECT_NUMBER-compute@developer.gserviceaccount.com and the App Engine default uses PROJECT_ID@appspot.gserviceaccount.com, CAPG does not support these. The regex restriction to .iam.gserviceaccount.com is intentional—it enforces security best practices by requiring explicitly created, minimally-privileged service accounts rather than broad default accounts.

The review incorrectly assumes CAPG "can run" with default SAs. No evidence supports this claim, and documentation contradicts it. The current regex pattern is correct for its intended scope.

Likely an incorrect or invalid review comment.

Comment thread api/hypershift/v1beta1/gcp.go Outdated
Comment thread docs/content/reference/api.md
Comment thread docs/content/reference/api.md

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 3

♻️ Duplicate comments (5)
cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-CustomNoUpgrade.crd.yaml (2)

5842-5893: Enforce unique label keys via list-map semantics

Add list-map to prevent duplicate keys and get SSA-merge correctness on updates.

Apply at the array level:

 resourceLabels:
   ...
   maxItems: 60
   type: array
+  x-kubernetes-list-type: map
+  x-kubernetes-list-map-keys:
+  - key

Optionally, add a brief doc note clarifying that keys starting with “goog” are intentionally disallowed (broader than GCP’s “goog-”), to avoid confusion.


5996-6000: Confirm “workloadIdentity” required only in gated CRDs

You noted this is intentional under the feature gate. Please verify the non-gated CRDs don’t require it.

#!/bin/bash
# Show where workloadIdentity is required across generated CRDs
set -euo pipefail
rg -nC3 '^\s*-\s+workloadIdentity\s*$' cmd/install/assets/hypershift-operator/zz_generated.crd-manifests \
  | sed -n '1,200p'
echo
echo "If only CustomNoUpgrade (or other gated) manifests show it under a 'required:' block, we're good."
cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-CustomNoUpgrade.crd.yaml (1)

5734-5785: Enforce unique label keys; keep 60-item headroom

Duplicate label keys are still possible. Add a CEL rule at the array level to guarantee uniqueness without changing list semantics.

Apply:

   resourceLabels:
     description: |
       ...
     items:
       ...
     maxItems: 60
     type: array
+    x-kubernetes-validations:
+    - message: resourceLabels keys must be unique
+      rule: self == null || self.all(l1, self.exists_one(l2, l1.key == l2.key))

If desired later, mirror this with a kubebuilder XValidation comment on the Go field so it persists into generated CRDs.

api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/GCPPlatform.yaml (1)

4972-4972: Requiring workloadIdentity under feature gate is acceptable.

Per prior thread, this CRD is feature‑gated; keeping it required here is fine. No change requested.

cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-TechPreviewNoUpgrade.crd.yaml (1)

5446-5496: Enforce unique resourceLabels keys (without list-map semantics).

You kept array semantics (order preserved) and capped to 60. However, duplicate keys are still possible and can lead to last-wins/ambiguous behavior. Add a CEL array-level validation to guarantee uniqueness by key.

Apply this diff under spec.platform.gcp.resourceLabels (same level as items/maxItems):

 resourceLabels:
   description: |-
     resourceLabels are applied to all GCP resources created for the cluster.
+  x-kubernetes-validations:
+  - message: resourceLabels keys must be unique
+    rule: 'self.all(l, self.exists_one(x, x.key == l.key))'
   items:
     description: |-
       GCPResourceLabel is a label to apply to GCP resources created for the cluster.
   ...
   maxItems: 60
   type: array
🧹 Nitpick comments (8)
api/hypershift/v1beta1/gcp_validation_test.go (1)

50-58: Tests provide limited validation coverage.

These tests only verify non-empty struct creation. The actual pattern validation occurs via CEL in the CRD, so these tests serve mainly as documentation of expected valid inputs.

Consider adding regex-based validation in tests to catch pattern regressions without requiring a full CRD/admission test:

import "regexp"

var gcpLabelKeyPattern = regexp.MustCompile(`^[a-z]([0-9a-z-]{0,61}[0-9a-z])?$`)

func TestGCPResourceLabel(t *testing.T) {
    // ... existing valid cases ...
    
    // Add validation
    for _, tt := range tests {
        t.Run(tt.name, func(t *testing.T) {
            if !gcpLabelKeyPattern.MatchString(tt.label.Key) {
                t.Errorf("Key %q does not match pattern", tt.label.Key)
            }
        })
    }
    
    // Add invalid cases
    invalidCases := []struct {
        name string
        key  string
    }{
        {"key starts with digit", "1invalid"},
        {"key ends with hyphen", "invalid-"},
        {"key contains uppercase", "Invalid"},
    }
    // ...
}

Also applies to: 92-100

cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-CustomNoUpgrade.crd.yaml (1)

5894-5994: WIF fields/readability: solid constraints; minor nits optional

  • Strong immutability + tight regexes for poolID/providerID/projectNumber/nodePoolEmail look good.
  • Minor optional: top-level WorkloadIdentity immutability plus per-field immutability is redundant; keeping only the top-level rule reduces noise without changing behavior.
cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-TechPreviewNoUpgrade.crd.yaml (1)

5540-5545: Tighten region regex (optional) to avoid false accepts

Current regex allows digits in middle segments (e.g., "us-1central1"). Consider a stricter, future-tolerant pattern that matches known region formats where digits only trail the final segment:

- pattern: ^[a-z]+(-[a-z0-9]+)+[0-9]+$
+ pattern: ^[a-z]+(?:-[a-z]+)+[1-9][0-9]*$

Keeps examples like "us-central1", "europe-west12", "northamerica-northeast1" valid, while rejecting unlikely names.

Also applies to: 5548-5548

cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-CustomNoUpgrade.crd.yaml (2)

5661-5677: Make immutability target the specific field, not the whole object

Using self == oldSelf at the object level for network and privateServiceConnectSubnet freezes the entire object, which can impede safe future extensions. Prefer field-level immutability on .name instead.

Apply:

   properties:
     network:
       properties:
         name:
           description: ...
           maxLength: 63
           minLength: 1
           pattern: ^[a-z]([-a-z0-9]*[a-z0-9])?$
           type: string
+          x-kubernetes-validations:
+          - message: Network name is immutable
+            rule: self == oldSelf
       required:
       - name
       type: object
-      x-kubernetes-validations:
-      - message: Network is immutable
-        rule: self == oldSelf

     privateServiceConnectSubnet:
       properties:
         name:
           description: ...
           maxLength: 63
           minLength: 1
           pattern: ^[a-z]([-a-z0-9]*[a-z0-9])?$
           type: string
+          x-kubernetes-validations:
+          - message: Private Service Connect subnet name is immutable
+            rule: self == oldSelf
       required:
       - name
       type: object
-      x-kubernetes-validations:
-      - message: Private Service Connect subnet is immutable
-        rule: self == oldSelf

Also applies to: 5682-5697


5816-5821: Avoid redundant immutability — keep only the top-level guard

workloadIdentity has a top-level self == oldSelf and per-field immutability on poolID/providerID/projectNumber/serviceAccountsRef.nodePoolEmail. The nested rules are redundant and bloat the schema. Keep the top-level guard and drop the duplicates.

Apply:

   poolID:
     ...
-    x-kubernetes-validations:
-    - message: Pool ID is immutable
-      rule: self == oldSelf

   projectNumber:
     ...
-    x-kubernetes-validations:
-    - message: Project number is immutable
-      rule: self == oldSelf

   providerID:
     ...
-    x-kubernetes-validations:
-    - message: Provider ID is immutable
-      rule: self == oldSelf

   serviceAccountsRef:
     properties:
       nodePoolEmail:
         ...
-        x-kubernetes-validations:
-        - message: NodePool email is immutable
-          rule: self == oldSelf

   ...
   x-kubernetes-validations:
   - message: WorkloadIdentity is immutable
     rule: self == oldSelf

Also applies to: 5847-5852, 5885-5886

api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/GCPPlatform.yaml (2)

4816-4865: Make resourceLabels a map by key to prevent duplicates.

Currently an array; duplicate keys can slip in and last-write-wins is unclear. Use list‑map semantics so keys are unique and merges are predictable.

   resourceLabels:
@@
     maxItems: 60
     type: array
+    x-kubernetes-list-map-keys:
+    - key
+    x-kubernetes-list-type: map

4968-4973: Add CEL to ensure nodePoolEmail domain matches .project.

Early validation avoids subtle misconfigs (project typo vs GSA domain).

   gcp:
     description: gcp specifies configuration for clusters running
       on Google Cloud Platform.
     properties:
@@
-    required:
+    required:
       - networkConfig
       - project
       - region
       - workloadIdentity
     type: object
+    x-kubernetes-validations:
+    - message: serviceAccountsRef.nodePoolEmail must belong to the specified GCP project
+      rule: >-
+        !has(self.workloadIdentity) ||
+        !has(self.workloadIdentity.serviceAccountsRef) ||
+        self.workloadIdentity.serviceAccountsRef.nodePoolEmail.split("@")[1]
+        == (self.project + ".iam.gserviceaccount.com")
api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/GCPPlatform.yaml (1)

4708-4757: Enforce unique label keys with list‑map; current array allows duplicates

GCP labels are key/value; allowing duplicate keys in the array can lead to last‑write‑wins and confusion. Make the list a map keyed by “key” to enforce uniqueness.

Apply this diff on the resourceLabels array:

-                        type: array
+                        x-kubernetes-list-type: map
+                        x-kubernetes-list-map-keys:
+                        - key
+                        type: array
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to Reviews -> Disable Knowledge Base setting

📥 Commits

Reviewing files that changed from the base of the PR and between 207dfb1 and e9ef61e.

⛔ Files ignored due to path filters (4)
  • vendor/github.com/openshift/hypershift/api/hypershift/v1beta1/gcp.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/openshift/hypershift/api/hypershift/v1beta1/hostedcluster_conditions.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/openshift/hypershift/api/hypershift/v1beta1/hostedcluster_types.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/openshift/hypershift/api/hypershift/v1beta1/zz_generated.deepcopy.go is excluded by !vendor/**, !**/vendor/**
📒 Files selected for processing (18)
  • api/hypershift/v1beta1/gcp.go (4 hunks)
  • api/hypershift/v1beta1/gcp_validation_test.go (1 hunks)
  • api/hypershift/v1beta1/hostedcluster_conditions.go (1 hunks)
  • api/hypershift/v1beta1/hostedcluster_types.go (1 hunks)
  • api/hypershift/v1beta1/zz_generated.deepcopy.go (4 hunks)
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/GCPPlatform.yaml (3 hunks)
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/GCPPlatform.yaml (3 hunks)
  • client/applyconfiguration/hypershift/v1beta1/gcpplatformspec.go (2 hunks)
  • client/applyconfiguration/hypershift/v1beta1/gcpresourcelabel.go (1 hunks)
  • client/applyconfiguration/hypershift/v1beta1/gcpserviceaccountsref.go (1 hunks)
  • client/applyconfiguration/hypershift/v1beta1/gcpworkloadidentityconfig.go (1 hunks)
  • client/applyconfiguration/utils.go (1 hunks)
  • cmd/cluster/gcp/testdata/zz_fixture_TestCreateCluster_minimal_flags_necessary_to_render.yaml (1 hunks)
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-CustomNoUpgrade.crd.yaml (3 hunks)
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-TechPreviewNoUpgrade.crd.yaml (3 hunks)
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-CustomNoUpgrade.crd.yaml (3 hunks)
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-TechPreviewNoUpgrade.crd.yaml (3 hunks)
  • docs/content/reference/api.md (5 hunks)
✅ Files skipped from review due to trivial changes (1)
  • docs/content/reference/api.md
🚧 Files skipped from review as they are similar to previous changes (4)
  • client/applyconfiguration/utils.go
  • client/applyconfiguration/hypershift/v1beta1/gcpserviceaccountsref.go
  • api/hypershift/v1beta1/hostedcluster_types.go
  • client/applyconfiguration/hypershift/v1beta1/gcpresourcelabel.go
🧰 Additional context used
📓 Path-based instructions (1)
**

⚙️ CodeRabbit configuration file

-Focus on major issues impacting performance, readability, maintainability and security. Avoid nitpicks and avoid verbosity.

Files:

  • api/hypershift/v1beta1/hostedcluster_conditions.go
  • client/applyconfiguration/hypershift/v1beta1/gcpplatformspec.go
  • cmd/cluster/gcp/testdata/zz_fixture_TestCreateCluster_minimal_flags_necessary_to_render.yaml
  • client/applyconfiguration/hypershift/v1beta1/gcpworkloadidentityconfig.go
  • api/hypershift/v1beta1/gcp.go
  • api/hypershift/v1beta1/zz_generated.deepcopy.go
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/GCPPlatform.yaml
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-CustomNoUpgrade.crd.yaml
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-TechPreviewNoUpgrade.crd.yaml
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/GCPPlatform.yaml
  • api/hypershift/v1beta1/gcp_validation_test.go
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-CustomNoUpgrade.crd.yaml
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-TechPreviewNoUpgrade.crd.yaml
🧬 Code graph analysis (3)
api/hypershift/v1beta1/hostedcluster_conditions.go (1)
api/hypershift/v1beta1/hosted_controlplane.go (1)
  • ConditionType (294-294)
client/applyconfiguration/hypershift/v1beta1/gcpworkloadidentityconfig.go (1)
client/applyconfiguration/hypershift/v1beta1/gcpserviceaccountsref.go (1)
  • GCPServiceAccountsRefApplyConfiguration (22-24)
api/hypershift/v1beta1/zz_generated.deepcopy.go (2)
api/hypershift/v1beta1/gcp.go (3)
  • GCPResourceLabel (23-54)
  • GCPServiceAccountsRef (225-241)
  • GCPWorkloadIdentityConfig (162-221)
client/applyconfiguration/hypershift/v1beta1/workloadidentity.go (1)
  • WorkloadIdentity (32-34)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: Red Hat Konflux / hypershift-operator-main-on-pull-request
  • GitHub Check: Red Hat Konflux / hypershift-cli-mce-211-on-pull-request
  • GitHub Check: Red Hat Konflux / hypershift-release-mce-211-on-pull-request
🔇 Additional comments (32)
api/hypershift/v1beta1/zz_generated.deepcopy.go (1)

1485-1494: LGTM - Auto-generated deep copy functions are correct.

The generated DeepCopyInto implementations properly handle the new GCP types:

  • GCPResourceLabel and GCPServiceAccountsRef use value copy (appropriate for structs with only string fields)
  • GCPWorkloadIdentityConfig correctly copies the nested ServiceAccountsRef
  • GCPPlatformSpec properly allocates and copies the ResourceLabels slice
  • PlatformSpec now delegates to DeepCopyInto for proper deep copy of GCP fields

Also applies to: 1612-1671, 3431-3435

api/hypershift/v1beta1/gcp.go (4)

7-54: Well-structured GCP resource naming types with comprehensive validation.

The GCPResourceReference and GCPResourceLabel types have solid RFC1035-compliant validation:

  • Key pattern correctly enforces lowercase start, alphanumeric end, and no consecutive hyphens
  • Value pattern allows empty strings as GCP permits
  • The goog reserved prefix check via XValidation is appropriate

70-83: Network configuration immutability properly enforced.

The +immutable markers with corresponding XValidation rules on Network and PrivateServiceConnectSubnet fields ensure these critical networking configurations cannot be changed after cluster creation.


86-139: GCPPlatformSpec validation patterns are correct.

The project and region patterns correctly enforce GCP naming rules:

  • Project: 6-30 chars, lowercase start, alphanumeric end
  • Region: properly handles multi-segment regions like northamerica-northeast1 and multi-digit suffixes like europe-west12
  • ResourceLabels with MaxItems=60 reserves headroom for HyperShift's ~4 system labels within GCP's 64-label limit

159-241: GCPWorkloadIdentityConfig and GCPServiceAccountsRef validation is thorough.

The WIF configuration types have proper constraints:

  • ProjectNumber: numeric-only pattern with reasonable max length
  • PoolID/ProviderID: 4-32 char pattern matching GCP's requirements with gcp- prefix reservation
  • NodePoolEmail: pattern correctly validates service account email format with project ID constraints matching line 98

All fields are appropriately marked immutable to prevent breaking the authentication chain post-creation.

cmd/cluster/gcp/testdata/zz_fixture_TestCreateCluster_minimal_flags_necessary_to_render.yaml (1)

47-52: Test fixture correctly reflects the new workloadIdentity structure.

The fixture properly includes the new required workloadIdentity block with its nested fields, maintaining alignment with the API schema changes.

api/hypershift/v1beta1/hostedcluster_conditions.go (1)

154-163: New GCP condition types follow established patterns.

The ValidGCPCredentials and ValidGCPWorkloadIdentity conditions are well-documented and consistent with other platform-specific validation conditions (e.g., ValidAWSIdentityProvider, ValidAzureKMSConfig).

Consider adding corresponding reason constants (e.g., InvalidGCPCredentialsReason, InvalidGCPWorkloadIdentityReason) in the Reasons const block for consistency with patterns like InvalidAzureCredentialsReason. This can be done when the controller implementation is added.

client/applyconfiguration/hypershift/v1beta1/gcpplatformspec.go (3)

27-33: LGTM! Generated apply configuration fields follow standard patterns.

The new fields for ResourceLabels and WorkloadIdentity are correctly structured for declarative configuration with server-side apply.


73-84: LGTM! Append-style builder correctly handles nil values.

The WithResourceLabels method follows the standard pattern for slice builders in Kubernetes apply configurations, including the appropriate panic for nil values to prevent runtime errors.

Minor note: Line 74 has a typo ("build" should be "built"), but since this is generated code, the fix should be applied to the generator template rather than this file.


86-92: LGTM! Standard setter-style builder for optional field.

The WithWorkloadIdentity method correctly implements the builder pattern for an optional pointer field.

client/applyconfiguration/hypershift/v1beta1/gcpworkloadidentityconfig.go (2)

1-27: LGTM! Generated apply configuration structure is correct.

The GCPWorkloadIdentityConfigApplyConfiguration type is properly structured with appropriate optional fields for declarative configuration.


31-65: LGTM! All builder methods follow standard patterns.

The constructor and four With* methods correctly implement the fluent builder pattern for Kubernetes apply configurations, enabling method chaining for declarative configuration construction.

cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-CustomNoUpgrade.crd.yaml (4)

5769-5785: GCP VPC network name pattern + immutability LGTM

Regex and immutability rule look correct for GCP resource naming.


5790-5805: GCP PSC subnet name pattern + immutability LGTM

Constraints align with GCP standards; immutability rule is appropriate.


5812-5824: Project ID validation looks correct

Anchored regex enforces 6–30 chars, starts with letter, no trailing hyphen. Good.


5829-5841: Region regex blocks zones and enforces trailing digits — LGTM

Pattern matches regions like us-central1, europe-west12; excludes zone suffixes (e.g., us-central1-a).

cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-TechPreviewNoUpgrade.crd.yaml (2)

5480-5489: GCP resource name rules: LGTM + immutability

Patterns and immutability for network and PSC subnet names match GCP Compute constraints and look solid.

Also applies to: 5502-5510, 5493-5496, 5514-5516


5531-5531: Project ID regex: LGTM

The pattern and length bounds align with GCP project ID rules.

cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-CustomNoUpgrade.crd.yaml (2)

5712-5716: Good tightenings on project and region validation

Project ID and region patterns/lengths match GCP rules and improve error clarity. Immutability on both is appropriate.

Also applies to: 5721-5733


5800-5852: poolID/providerID regex now require a leading letter — correct

Leading-letter constraint aligns with GCP rules for WIF pool/provider IDs. Thanks for fixing.

api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/GCPPlatform.yaml (1)

4881-4934: WIF IDs and reserved prefix checks look correct.

Regex + ‘gcp-’ reservation aligned with IAM rules; immutability is right. No changes requested.

cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-TechPreviewNoUpgrade.crd.yaml (5)

5372-5387: Network name validation + immutability look good.

Pattern matches GCP resource naming, and object immutability rule is correct.


5393-5408: Subnet name validation + immutability look good.

Consistent with GCP naming rules and prevents day‑2 drift.


5415-5427: Project ID regex is appropriate and immutable.

6–30 chars, lowercase/digits/hyphens, no trailing hyphen; matches GCP guidance.


5432-5444: Region format and immutability are correct.

Regex blocks zone suffixes and enforces trailing digits (e.g., us-central1).


5497-5597: All validation patterns confirmed correct; no changes needed.

The verification confirms both specifications:

  • The 'gcp-' prefix is reserved and may not be used in Workload Identity pool or provider IDs, so the validation rule !self.startsWith('gcp-') is correct.
  • Service account IDs must be 6–30 characters with lowercase letters, digits, and hyphens (starting with a letter, ending with a letter or digit), and project IDs must also be 6–30 characters following the same character rules. The nodePoolEmail regex correctly enforces these constraints on both the local and project ID parts.

The poolID and providerID patterns also align properly with Workload Identity specifications.

api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/GCPPlatform.yaml (6)

4634-4649: LGTM: network name validation + immutability

The GCP VPC network name regex and the immutability rule look correct and aligned with Compute Engine naming.


4655-4670: LGTM: PSC subnet name validation + immutability

Same as network name; constraints and immutability are appropriate.


4861-4865: Double-check: making workloadIdentity required is intentional

Marking workloadIdentity as required under gcp is a behavioral change. If intentional behind the feature gate, document it in the PR and release notes. Otherwise, consider making it optional and validating presence only when WIF is enabled.


4759-4860: Workload Identity: solid immutability/format checks; verify requiredness vs feature gate

Validation for poolID/providerID/projectNumber and GSA email looks consistent and intentionally strict. Since this is the feature‑gated CRD, please confirm that the standard CRD (non‑featuregated) does NOT mark gcp.workloadIdentity as required, to avoid breaking existing clusters when the gate is off.


4691-4706: Region regex admits invalid forms like “us-central-1”; tighten to two segments

The pattern ^[a-z]+(-[a-z0-9]+)+[0-9]+$ accepts “us-central-1” (three segments). GCP regions are exactly two segments with digits at the end (e.g., “us-central1”, “europe-west12”, “northamerica-northeast1”). Recommend tightening the regex and adding a CEL guard for exactly one hyphen.

Apply this diff:

-                        pattern: ^[a-z]+(-[a-z0-9]+)+[0-9]+$
+                        pattern: ^[a-z]+-[a-z0-9]+[0-9]$

And append a validation alongside immutability:

                         x-kubernetes-validations:
+                        - message: Region must have exactly two segments separated by a single hyphen (e.g., us-central1)
+                          rule: self.split('-').size() == 2
                         - message: Region is immutable
                           rule: self == oldSelf

Likely an incorrect or invalid review comment.


4676-4689: Regex is correct; no CEL guard needed for reserved prefixes in project IDs

GCP project IDs are not documented as prohibiting "google" or "goog". Project ID rules restrict length and characters (lowercase letters, numbers, hyphens, start with a letter, etc.) only. Restrictions on "google"/"goog" apply to other resource types like Cloud Storage buckets and Integration Connectors, not project IDs. The regex in the YAML correctly enforces official GCP project ID requirements and requires no additional CEL validation for reserved prefixes.

Likely an incorrect or invalid review comment.

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 3

♻️ Duplicate comments (7)
docs/content/reference/api.md (1)

6263-6267: Fix invalid regex; remove HTML anchor and provide copy/paste‑able pattern.

The Pattern line renders an anchor, not a regex. Replace with a literal regex and ensure it’s generated from the Go doc comment.

Apply in source (api/hypershift/v1beta1/gcp.go) then regenerate docs:

- Pattern: “^<a href="[-a-z0-9]*[a-z0-9]">a-z</a>?$” (max 63 chars), per GCP naming requirements.
+ Pattern: `^[a-z]([-a-z0-9]{0,61}[a-z0-9])?$` (max 63 chars), per GCP naming requirements.

Wrap the regex in backticks in the Go comment to avoid Markdown/link expansion in the generated docs, then run make api-docs.

api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/GCPPlatform.yaml (1)

4979-4980: workloadIdentity marked required under GCP platform

Acknowledged as feature‑gated per prior discussion; keeping it required here is fine. No action.

cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-CustomNoUpgrade.crd.yaml (1)

5734-5785: Enforce unique label keys; keep headroom at 60.

Array allows duplicate keys; add a CEL uniqueness check to avoid last-write-wins ambiguity. MaxItems=60 headroom is good; keep it.

Apply under spec.platform.gcp.resourceLabels:

 resourceLabels:
   ...
   maxItems: 60
   type: array
+  x-kubernetes-validations:
+  - message: resourceLabels keys must be unique
+    rule: self == null || self.all(l1, self.exists_one(l2, l1.key == l2.key))
   items:
     properties:
       key:
         ...
cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-CustomNoUpgrade.crd.yaml (2)

6003-6007: Double‑check gating: workloadIdentity required only in gated CRDs.

Since this file is CustomNoUpgrade (gated), requiring workloadIdentity is fine. Please verify non‑gated CRDs don’t require it to avoid accidental breakage outside the feature gate.

#!/bin/bash
# Verify only gated CRDs require platform.gcp.workloadIdentity
rg -n -C2 'platform:\s*\n\s*gcp:.*\n.*required:([\s\S]*?)workloadIdentity' cmd/install/assets \
  | rg -n -C1 'featuregated|CustomNoUpgrade|DevPreviewNoUpgrade|TechPreviewNoUpgrade|standard|HostedCluster'

5856-5873: Clarify reserved‑prefix wording for label keys (policy is broader than GCP).

The rule intentionally blocks any key starting with “goog…”, but the message says “reserved 'goog' prefix” which can be read as the single token “goog-”. Consider clarifying to “reserved ‘goog*’ prefixes” (or narrow the rule/message to “goog-” if you decide to match GCP docs exactly). This is a follow‑up to earlier feedback.

-      - message: Label keys starting with the reserved 'goog' prefix are not allowed
+      - message: Label keys starting with reserved 'goog*' prefixes are not allowed
         rule: '!self.startsWith(''goog'')'
cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-TechPreviewNoUpgrade.crd.yaml (1)

5554-5604: Enforce unique label keys for resourceLabels

Prevent duplicate label keys and get idempotent merges by making the list a keyed map. Add list-map hints (and an optional CEL fallback) to the array:

 resourceLabels:
   items:
     properties:
       key:
         # …existing key schema…
       value:
         # …existing value schema…
     required:
     - key
     - value
     type: object
   maxItems: 60
   type: array
+  x-kubernetes-list-map-keys:
+  - key
+  x-kubernetes-list-type: map
+  x-kubernetes-validations:
+  - rule: self.map(l, l.key).allUnique()
+    message: Duplicate label keys are not allowed
cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-TechPreviewNoUpgrade.crd.yaml (1)

5446-5495: Enforce unique label keys at array level.

Without de-dup, duplicate keys can yield ambiguous reconciliation and last-write-wins surprises. Add a CEL array-level validation to ensure keys are unique. Max 60 headroom is good.

Apply this diff under resourceLabels:

 resourceLabels:
   description: |-
     resourceLabels are applied to all GCP resources created for the cluster.
+  x-kubernetes-validations:
+  - message: resourceLabels keys must be unique
+    rule: self.all(l, self.exists_one(x, x.key == l.key))
   items:
     description: |-
       GCPResourceLabel is a label to apply to GCP resources created for the cluster.
🧹 Nitpick comments (9)
api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/GCPPlatform.yaml (2)

4708-4757: Enforce label key uniqueness at the schema level.

As written, duplicate keys can be submitted; last-wins is ambiguous for users and propagation. Use a list-map keyed by “key” to force uniqueness.

Apply near items list:

 resourceLabels:
   ...
   items:
     ...
   maxItems: 60
-  type: array
+  type: array
+  x-kubernetes-list-map-keys:
+  - key
+  x-kubernetes-list-type: map

4836-4854: Add a cross-field check to align nodePoolEmail’s project with spec.gcp.project.

Prevents subtle misconfig (email domain’s project != .gcp.project). Suggested CEL at the gcp object level:

For example under spec.platform.gcp.x-kubernetes-validations:

- message: nodePoolEmail project must match spec.platform.gcp.project
  rule: "!has(self.workloadIdentity) || !has(self.workloadIdentity.serviceAccountsRef) || (
           self.workloadIdentity.serviceAccountsRef.nodePoolEmail.matches('^[a-z][a-z0-9-]{4,28}[a-z0-9]@[a-z][a-z0-9-]{4,28}[a-z0-9]\\.iam\\.gserviceaccount\\.com$')
           &&
           self.workloadIdentity.serviceAccountsRef.nodePoolEmail.split('@')[1].split('.')[0] == self.project
         )"
docs/content/reference/api.md (3)

6297-6307: Add Service Account User role to the required IAM set.

To attach a VM service account when creating instances, the controller needs roles/iam.serviceAccountUser on that service account (or project). Add it explicitly to avoid permission errors.

- This GSA requires the following IAM roles:
- - roles/compute.instanceAdmin.v1 (Compute Instance Admin v1)
- - roles/compute.networkAdmin (Compute Network Admin)
+ This GSA requires the following IAM roles:
+ - roles/compute.instanceAdmin.v1 (Compute Instance Admin v1)
+ - roles/compute.networkAdmin (Compute Network Admin)
+ - roles/iam.serviceAccountUser (on the VM service account used by created instances)

Please verify this against CAPG docs for your supported version or align with cmd/infra/gcp/iam-bindings.json.


6021-6029: Clarify WIF provider mappings with a concrete example.

Add a brief example for attribute/subject mapping and the principal used in the iam.workloadIdentityUser binding to reduce setup ambiguity.

Example snippet to append:

Example:
- Provider attribute mapping includes:
  google.subject -> assertion.sub
- Subject pattern used by controllers:
  system:serviceaccount:kube-system:capi-gcp-controller-manager
- IAM binding:
  role: roles/iam.workloadIdentityUser
  member: principalSet://iam.googleapis.com/projects/${PROJECT_NUMBER}/locations/global/workloadIdentityPools/${POOL_ID}/attribute.subject/system:serviceaccount:kube-system:capi-gcp-controller-manager

6003-6007: Quantify or qualify reserved label count.

“Reserves approximately 4 labels” is vague. Either state the exact number or say “at least 4 labels may be reserved” to set clearer expectations.

api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/GCPPlatform.yaml (2)

4816-4865: Ensure label key uniqueness with list-as-map

To prevent duplicate label keys, make resourceLabels a map keyed by “key”. This also improves apply semantics.

   resourceLabels:
     description: |-
       resourceLabels are applied to all GCP resources created for the cluster.
@@
     items:
@@
       required:
       - key
       - value
       type: object
     maxItems: 60
     type: array
+    x-kubernetes-list-type: map
+    x-kubernetes-list-map-keys:
+    - key

4784-4798: Add CEL to ensure nodePoolEmail domain matches configured project

Prevents subtle typos where the GSA belongs to a different project than .platform.gcp.project.

   gcp:
     type: object
+    x-kubernetes-validations:
+    - message: serviceAccountsRef.nodePoolEmail must belong to the specified GCP project
+      rule: >-
+        !has(self.workloadIdentity) ||
+        !has(self.workloadIdentity.serviceAccountsRef) ||
+        self.workloadIdentity.serviceAccountsRef.nodePoolEmail.split("@")[1]
+        == (self.project + ".iam.gserviceaccount.com")

Also applies to: 4938-4963

cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-CustomNoUpgrade.crd.yaml (1)

5862-5884: GSA email pattern is precise; confirm cross‑project intent.

Regex accepts only PROJECT_ID.iam.gserviceaccount.com and a conservative local-part; immutability OK. If cross‑project GSAs are not intended, consider a CEL to ensure the domain’s project matches spec.platform.gcp.project; otherwise ignore.

Option (only if same‑project is required):

x-kubernetes-validations:
- message: nodePoolEmail project must match spec.platform.gcp.project
  rule: self.split("@")[1].split(".iam.gserviceaccount.com")[0] == oldSelf.split("@")[1].split(".iam.gserviceaccount.com")[0] || self.split("@")[1].split(".iam.gserviceaccount.com")[0] == root.spec.platform.gcp.project
cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-CustomNoUpgrade.crd.yaml (1)

5842-5893: Enforce unique label keys via list‑map semantics.

Without list‑map, duplicate keys can slip in and merge poorly. Treat resourceLabels as a map keyed by “key” for validation and server‑side apply behavior.

Apply:

 resourceLabels:
   description: |-
@@
   items:
@@
     type: object
-  maxItems: 60
-  type: array
+  maxItems: 60
+  type: array
+  x-kubernetes-list-map-keys:
+  - key
+  x-kubernetes-list-type: map
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to Reviews -> Disable Knowledge Base setting

📥 Commits

Reviewing files that changed from the base of the PR and between e9ef61e and 569ba13.

⛔ Files ignored due to path filters (4)
  • vendor/github.com/openshift/hypershift/api/hypershift/v1beta1/gcp.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/openshift/hypershift/api/hypershift/v1beta1/hostedcluster_conditions.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/openshift/hypershift/api/hypershift/v1beta1/hostedcluster_types.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/openshift/hypershift/api/hypershift/v1beta1/zz_generated.deepcopy.go is excluded by !vendor/**, !**/vendor/**
📒 Files selected for processing (18)
  • api/hypershift/v1beta1/gcp.go (4 hunks)
  • api/hypershift/v1beta1/gcp_validation_test.go (1 hunks)
  • api/hypershift/v1beta1/hostedcluster_conditions.go (1 hunks)
  • api/hypershift/v1beta1/hostedcluster_types.go (1 hunks)
  • api/hypershift/v1beta1/zz_generated.deepcopy.go (4 hunks)
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/GCPPlatform.yaml (3 hunks)
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/GCPPlatform.yaml (3 hunks)
  • client/applyconfiguration/hypershift/v1beta1/gcpplatformspec.go (2 hunks)
  • client/applyconfiguration/hypershift/v1beta1/gcpresourcelabel.go (1 hunks)
  • client/applyconfiguration/hypershift/v1beta1/gcpserviceaccountsref.go (1 hunks)
  • client/applyconfiguration/hypershift/v1beta1/gcpworkloadidentityconfig.go (1 hunks)
  • client/applyconfiguration/utils.go (1 hunks)
  • cmd/cluster/gcp/testdata/zz_fixture_TestCreateCluster_minimal_flags_necessary_to_render.yaml (1 hunks)
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-CustomNoUpgrade.crd.yaml (3 hunks)
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-TechPreviewNoUpgrade.crd.yaml (3 hunks)
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-CustomNoUpgrade.crd.yaml (3 hunks)
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-TechPreviewNoUpgrade.crd.yaml (3 hunks)
  • docs/content/reference/api.md (5 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • api/hypershift/v1beta1/hostedcluster_types.go
  • client/applyconfiguration/utils.go
  • api/hypershift/v1beta1/gcp_validation_test.go
🧰 Additional context used
📓 Path-based instructions (1)
**

⚙️ CodeRabbit configuration file

-Focus on major issues impacting performance, readability, maintainability and security. Avoid nitpicks and avoid verbosity.

Files:

  • client/applyconfiguration/hypershift/v1beta1/gcpworkloadidentityconfig.go
  • api/hypershift/v1beta1/hostedcluster_conditions.go
  • client/applyconfiguration/hypershift/v1beta1/gcpresourcelabel.go
  • client/applyconfiguration/hypershift/v1beta1/gcpserviceaccountsref.go
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-CustomNoUpgrade.crd.yaml
  • cmd/cluster/gcp/testdata/zz_fixture_TestCreateCluster_minimal_flags_necessary_to_render.yaml
  • client/applyconfiguration/hypershift/v1beta1/gcpplatformspec.go
  • api/hypershift/v1beta1/zz_generated.deepcopy.go
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-CustomNoUpgrade.crd.yaml
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/GCPPlatform.yaml
  • docs/content/reference/api.md
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-TechPreviewNoUpgrade.crd.yaml
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-TechPreviewNoUpgrade.crd.yaml
  • api/hypershift/v1beta1/gcp.go
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/GCPPlatform.yaml
🧬 Code graph analysis (4)
client/applyconfiguration/hypershift/v1beta1/gcpworkloadidentityconfig.go (1)
client/applyconfiguration/hypershift/v1beta1/gcpserviceaccountsref.go (1)
  • GCPServiceAccountsRefApplyConfiguration (22-24)
client/applyconfiguration/hypershift/v1beta1/gcpplatformspec.go (4)
client/applyconfiguration/hypershift/v1beta1/gcpnetworkconfig.go (1)
  • GCPNetworkConfigApplyConfiguration (22-25)
api/hypershift/v1beta1/gcp.go (1)
  • GCPEndpointAccessType (58-58)
client/applyconfiguration/hypershift/v1beta1/gcpresourcelabel.go (1)
  • GCPResourceLabelApplyConfiguration (22-25)
client/applyconfiguration/hypershift/v1beta1/gcpworkloadidentityconfig.go (1)
  • GCPWorkloadIdentityConfigApplyConfiguration (22-27)
api/hypershift/v1beta1/zz_generated.deepcopy.go (2)
api/hypershift/v1beta1/gcp.go (3)
  • GCPResourceLabel (23-54)
  • GCPServiceAccountsRef (228-248)
  • GCPWorkloadIdentityConfig (162-224)
client/applyconfiguration/hypershift/v1beta1/workloadidentity.go (1)
  • WorkloadIdentity (32-34)
api/hypershift/v1beta1/gcp.go (1)
client/applyconfiguration/hypershift/v1beta1/gcpresourcereference.go (1)
  • GCPResourceReference (28-30)
🔇 Additional comments (44)
api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/GCPPlatform.yaml (8)

4634-4643: GCP network name regex looks correct; keep.

Matches GCP naming and 63-char max. Good addition.


4647-4649: Immutability for network object is appropriate.

Prevents day-2 drift; aligns with infra invariants.


4655-4664: PSC subnet name regex looks correct; keep.

Conforms to GCP resource naming.


4668-4670: Immutability for PSC subnet is appropriate.

Prevents reconciliation churn.


4685-4685: Project ID regex is tight and matches GCP rules.

6–30 chars, starts with letter, no trailing hyphen. Good.


4759-4866: WIF block (patterns + immutability) looks solid.

poolID/providerID/projectNumber constraints and reserved-prefix checks are clear; object immutability is appropriate.


4871-4871: Confirm gating for new required field.

workloadIdentity is marked required. Please confirm this only ships in the feature‑gated CRD and cannot impact existing GCP HCPs that aren’t using WIF yet (upgrade safety).


4694-4703: Region regex pattern is correct and verified.

The verification confirms the regex pattern ^[a-z]+(-[a-z0-9]+)+[0-9]+$ correctly validates GCP region names:

  • All 10 known valid regions match
  • All invalid cases (non-hyphenated, non-digit-ending, zones, malformed) are properly rejected
  • Requirements are satisfied: at least one hyphen, lowercase letters/digits only, must end with digits
cmd/cluster/gcp/testdata/zz_fixture_TestCreateCluster_minimal_flags_necessary_to_render.yaml (1)

47-52: LGTM! Fixture correctly demonstrates the new workloadIdentity API structure.

The test fixture appropriately shows the new GCP Workload Identity Federation fields with empty values, which is suitable for a "minimal flags necessary to render" test case. This helps document the API surface for developers.

api/hypershift/v1beta1/hostedcluster_conditions.go (1)

154-163: LGTM! Well-documented condition types for GCP validation.

The new ValidGCPCredentials and ValidGCPWorkloadIdentity condition types are clearly documented and follow the established patterns in the codebase. The comments appropriately explain their purpose and expected failure scenarios.

client/applyconfiguration/hypershift/v1beta1/gcpserviceaccountsref.go (1)

1-38: Generated code - skipping detailed review.

This is auto-generated code (as indicated by the comment on line 16). The structure follows standard Kubernetes apply configuration patterns. No critical issues identified.

api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/GCPPlatform.yaml (4)

4742-4758: GCP network and subnet name validation/immutability — LGTM

Patterns and immutability guards match Compute Engine naming rules and prevent day‑2 drift. No changes requested.

Also applies to: 4763-4778


4784-4798: Project ID regex — LGTM

The 6–30 chars, start-with-letter, hyphen/digit constraints are correct for GCP project IDs, and immutability is appropriate.


4802-4814: Region regex tightened — looks right; please sanity‑check a few newer regions

Pattern enforces at least one hyphen and trailing digits (e.g., us-central1, europe-west12, northamerica-northeast2). Suggest adding/confirming unit cases for those examples.

Also applies to: 4811-4811


4867-4974: WIF config validations — solid coverage

Reserved “gcp-” prefix blocks, length/patterns, and immutability on pool/provider/projectNumber and SA email look good. No changes requested beyond the cross‑field check suggested separately.

client/applyconfiguration/hypershift/v1beta1/gcpresourcelabel.go (1)

22-47: LGTM - Generated apply configuration follows standard patterns.

The generated apply configuration for GCPResourceLabel correctly implements the builder pattern with appropriate field types and chaining methods. The structure aligns with Kubernetes apply configuration conventions.

client/applyconfiguration/hypershift/v1beta1/gcpplatformspec.go (3)

27-32: LGTM - New fields properly integrated.

The ResourceLabels and WorkloadIdentity fields are correctly added to support GCP Workload Identity Federation configuration with appropriate types.


73-84: LGTM - Defensive nil check prevents misuse.

The WithResourceLabels method correctly implements the variadic append pattern with a nil panic to catch programming errors early. This is appropriate defensive programming for generated builder code.


86-92: LGTM - Standard setter pattern.

The WithWorkloadIdentity method follows the correct builder pattern for setting pointer fields.

client/applyconfiguration/hypershift/v1beta1/gcpworkloadidentityconfig.go (1)

22-65: LGTM - Generated apply configuration correctly implements WIF structure.

The GCPWorkloadIdentityConfigApplyConfiguration properly defines all required fields (ProjectNumber, PoolID, ProviderID, ServiceAccountsRef) with appropriate builder methods following Kubernetes apply configuration conventions. The nested ServiceAccountsRef reference is correctly typed.

cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-CustomNoUpgrade.crd.yaml (8)

5661-5670: GCP network name regex + doc look solid.

Pattern and description match GCP Compute naming; no issues.


5674-5677: Network immutability rule is appropriate.

Object-level immutability via self == oldSelf aligns with rest of CRD.


5682-5691: PSC subnet name validation is correct.

Regex and limits conform to GCP resource naming.


5695-5697: PSC subnet immutability is correct.


5712-5713: Project ID regex matches stated rules.

Starts with letter; 6–30 chars; hyphen rules OK.


5721-5730: Region pattern blocks zones and enforces trailing digits.

Good balance vs. enumerating regions.


5792-5855: WIF poolID/providerID regex tightened to start with letter + reserved-prefix guard.

This fixes the earlier leading-digit issue and blocks gcp- prefix; immutability is correct.


5821-5834: projectNumber numeric validation and immutability look good.

api/hypershift/v1beta1/zz_generated.deepcopy.go (3)

1485-1494: GCPPlatformSpec deepcopy for ResourceLabels/WorkloadIdentity looks correct

Cloning the ResourceLabels slice with make + copy avoids aliasing between copies, and value-copying WorkloadIdentity is sufficient given it only contains value fields. This matches controller-gen’s typical patterns and should behave correctly when PlatformSpec is deep-copied.


1612-1625: DeepCopy implementations for GCP WIF support types are sufficient

GCPResourceLabel, GCPServiceAccountsRef, and GCPWorkloadIdentityConfig contain only value fields (strings and a value-typed embedded struct), so the autogenerated shallow copies (*out = *in plus direct assignment of ServiceAccountsRef) are correct and won’t introduce shared mutable state.

Also applies to: 1642-1671


3431-3435: Using DeepCopyInto for PlatformSpec.GCP is the right fix

Switching the GCP branch to allocate a new GCPPlatformSpec and invoke DeepCopyInto ensures the new ResourceLabels slice (and other future composite fields) are properly deep-copied instead of aliasing the original.

cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-CustomNoUpgrade.crd.yaml (2)

5769-5778: LGTM on GCP name/project/region validations and immutability.

Patterns for network/subnet names, project ID, and region plus immutability rules look correct and defensively scoped.

Also applies to: 5782-5784, 5791-5798, 5803-5805, 5812-5821, 5836-5838


5907-5963: Verification confirms the "gcp-" prefix restriction is correct and documented.

The Google Cloud IAM docs confirm that the prefix "gcp-" is reserved and cannot be used in workload identity pool or provider IDs. The code's validation checks and descriptions accurately reflect this requirement. No changes are needed.

api/hypershift/v1beta1/gcp.go (5)

3-18: LGTM! Improved GCP resource naming validation.

The updated pattern ^[a-z]([-a-z0-9]*[a-z0-9])?$ correctly enforces GCP's RFC1035-style naming requirements and is more readable than the previous regex. The expanded documentation clearly explains the validation rules.


20-54: LGTM! Solid RFC1035-compliant label validation.

The validation patterns correctly enforce Compute Engine label requirements: no underscores, proper start/end character constraints, and reserved prefix blocking. The distinction between Key (must be non-empty) and Value (can be empty) aligns with GCP behavior.


70-83: LGTM! Appropriate immutability constraints.

Network and subnet immutability is correct for GCP clusters, as these resources cannot be changed after cluster creation without breaking connectivity.


159-224: LGTM! Comprehensive WIF configuration with proper safeguards.

The validation patterns correctly enforce GCP's WIF naming requirements, including the 4-32 character length constraint and reserved prefix blocking. The immutability constraints appropriately prevent breaking the authentication chain, and the detailed comments provide valuable context for users setting up WIF.


85-157: LGTM! Well-structured GCP platform configuration.

The validation patterns for Project and Region are correct, and the 60-item limit on ResourceLabels appropriately reserves capacity for system labels. The required, immutable WorkloadIdentity field is appropriate for preventing authentication chain breakage (and backward compatibility is addressed via feature-gating per past review discussion).

Verification confirms: All 42 current GCP region IDs follow the pattern with letter groups separated by hyphens and ending with numeric suffixes, so the region regex pattern ^[a-z]+(-[a-z0-9]+)+[0-9]+$ is correct and comprehensive.

cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-TechPreviewNoUpgrade.crd.yaml (6)

5372-5388: GCP network name regex + immutability LGTM.

Pattern matches GCP VPC naming and self == oldSelf is appropriate.


5393-5408: PSC subnet name regex + immutability LGTM.

Matches GCP subnet naming and prevents day-2 drift.


5414-5427: Project ID validation is correct.

Pattern enforces 6–30, lowercase/digits/hyphen, starts with letter, no trailing hyphen; aligns with GCP rules.


5432-5444: Region validation looks good.

Structural check excludes zones (must end with digits) and allows multi-segment regions.


5497-5604: Workload Identity Federation schema + immutability LGTM.

Field regexes, reserved-prefix bans, and object immutability look solid.


5573-5593: GSA email regex LGTM; immutable fits intent.

Covers typical 6–30 char SA IDs and project IDs with required domain suffix.

Comment thread api/hypershift/v1beta1/gcp.go Outdated

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 1

♻️ Duplicate comments (7)
cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-CustomNoUpgrade.crd.yaml (1)

5842-5892: Enforce unique label keys and clarify reserved prefix wording.

  • Add list‑map semantics so duplicate keys are rejected at admission and merge works predictably.
  • Wording: since you intentionally reserve any key starting with “goog” (broader than GCP’s “goog-”), say “reserved by HyperShift” to avoid implying this is a GCP rule.

Apply on resourceLabels (array):

   resourceLabels:
@@
-  maxItems: 60
-  type: array
+  maxItems: 60
+  type: array
+  x-kubernetes-list-type: map
+  x-kubernetes-list-map-keys:
+  - key

And on the key description:

-                                GCP reserves the 'goog' prefix for system labels.
+                                HyperShift intentionally reserves any key starting with 'goog' to avoid collisions with Google-reserved labels.
api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/GCPPlatform.yaml (2)

4867-4974: Add a cross-field guard tying nodePoolEmail domain to the configured project.

Prevents mismatched project IDs in GSA emails (common typo). Add at platform.gcp scope:

   gcp:
     description: gcp specifies configuration for clusters running
       on Google Cloud Platform.
     properties:
@@
     type: object
+    x-kubernetes-validations:
+    - message: serviceAccountsRef.nodePoolEmail must belong to the specified GCP project
+      rule: >-
+        !has(self.workloadIdentity) ||
+        !has(self.workloadIdentity.serviceAccountsRef) ||
+        self.workloadIdentity.serviceAccountsRef.nodePoolEmail.split("@")[1]
+        == (self.project + ".iam.gserviceaccount.com")

4979-4980: Keeping workloadIdentity required is fine under the GCPPlatform feature gate.

Given this CRD is feature-gated, requiring it won’t break existing non-GCP users. No change requested.

docs/content/reference/api.md (1)

6263-6268: Fix broken regex in “Pattern” (HTML anchor rendered inside regex).

Replace the invalid anchor with a copy/paste‑able regex and wrap it in code to prevent linkification. Also ensure the source Go comment is updated and docs regenerated via make api-docs.

Apply this doc change:

-Pattern: “^<a href="[-a-z0-9]*[a-z0-9]">a-z</a>?$” (max 63 chars), per GCP naming requirements.
+Pattern: `^[a-z]([-a-z0-9]{0,61}[a-z0-9])?$` (max 63 chars), per GCP naming requirements.

And keep the surrounding text: “Must start with a lowercase letter and end with a letter or digit.”

cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-TechPreviewNoUpgrade.crd.yaml (1)

5554-5603: Enforce unique resource label keys at the schema level

Array allows duplicate keys today; this creates last‑write‑wins ambiguity and SSA merge drift. Make the list a map keyed by “key” to enforce uniqueness and improve apply semantics.

Apply this minimal change:

 resourceLabels:
   items:
@@
   maxItems: 60
-  type: array
+  type: array
+  x-kubernetes-list-map-keys:
+  - key
+  x-kubernetes-list-type: map
cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-CustomNoUpgrade.crd.yaml (1)

5734-5785: Enforce unique GCP label keys (CEL) to avoid ambiguous duplicates

Duplicate keys are currently allowed in spec.platform.gcp.resourceLabels. This can lead to last-write-wins ambiguity across controllers. Add a list-level CEL to guarantee uniqueness by key without changing list semantics.

Apply:

                       maxItems: 60
                       type: array
+                      x-kubernetes-validations:
+                      - message: resourceLabels keys must be unique
+                        rule: self == null || self.all(l1, self.exists_one(l2, l1.key == l2.key))
                       items:
cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-TechPreviewNoUpgrade.crd.yaml (1)

5445-5495: Enforce unique label keys; keep 60-item cap.

You cap at 60 (good headroom), but duplicate keys are still allowed and can be ambiguous downstream. Add an array-level CEL rule to ensure keys are unique while keeping list semantics/order.

Apply this diff near resourceLabels:

 resourceLabels:
   description: |-
     resourceLabels are applied to all GCP resources created for the cluster.
     ...
+  x-kubernetes-validations:
+  - message: resourceLabels keys must be unique
+    rule: 'self.all(l, self.exists_one(x, x.key == l.key))'
   items:
     description: |-
       GCPResourceLabel is a label to apply to GCP resources created for the cluster.
   ...
   maxItems: 60
   type: array
🧹 Nitpick comments (8)
api/hypershift/v1beta1/gcp.go (1)

103-117: Region validation pattern is correct, but MinLength could be more precise.

The region pattern ^[a-z]+(-[a-z0-9]+)+[0-9]+$ correctly enforces GCP region format (e.g., "us-central1", "europe-west2") and will reject invalid formats. However, MinLength=1 is inconsistent with the pattern's actual minimum of approximately 4-6 characters. While the pattern provides the real enforcement (making this a cosmetic issue), consider updating MinLength to better reflect the actual constraint.

Consider updating to better align schema metadata with the pattern:

 // +kubebuilder:validation:MinLength=1
+// +kubebuilder:validation:MinLength=6
api/hypershift/v1beta1/gcp_validation_test.go (1)

7-101: Tests are effectively no-ops and don’t exercise the actual validation behavior.

Both TestGCPResourceLabel and TestGCPRegionPattern only assert that Key/region are non-empty, and every table entry is already non-empty. As written, these tests can’t fail in any realistic scenario and don’t validate the RFC1035 patterns, reserved goog prefix rules, or region regexes you’ve added at the API/CRD level. They mainly add maintenance cost and a misleading impression of coverage.

Consider either:

  • Adding assertions that actually exercise the validation logic (e.g., via helper functions mirroring the regexes, or by inspecting the generated CRD/OpenAPI schema and including negative cases), or
  • Removing these tests entirely if meaningful validation can only be done at a higher level (e.g., envtest-based CRD validation).
api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/GCPPlatform.yaml (1)

4816-4865: Ensure label keys are unique and get proper merge semantics.

Today duplicates can slip through; prefer Kubernetes list-as-map to enforce uniqueness and avoid last-wins merges.

Apply under resourceLabels:

   resourceLabels:
     description: |-
@@
     items:
@@
       type: object
     maxItems: 60
     type: array
+    x-kubernetes-list-type: map
+    x-kubernetes-list-map-keys:
+    - key
cmd/cluster/gcp/create_test.go (1)

74-93: Consider refactoring test cases to reduce verbosity.

The test cases manually construct RawCreateOptions with all fields, making them verbose and harder to maintain. Consider starting from validOpts and selectively clearing the field being tested.

Example refactor:

 	tests := map[string]struct {
-		opts         RawCreateOptions
+		setupOpts    func() RawCreateOptions
 		expectErr    bool
 		expectSubstr string
 	}{
 		"missing project": {
-			opts:         RawCreateOptions{Region: validOpts.Region, Network: validOpts.Network, PrivateServiceConnectSubnet: validOpts.PrivateServiceConnectSubnet, WorkloadIdentityProjectNumber: validOpts.WorkloadIdentityProjectNumber, WorkloadIdentityPoolID: validOpts.WorkloadIdentityPoolID, WorkloadIdentityProviderID: validOpts.WorkloadIdentityProviderID, NodePoolServiceAccountEmail: validOpts.NodePoolServiceAccountEmail},
+			setupOpts: func() RawCreateOptions {
+				opts := validOpts
+				opts.Project = ""
+				return opts
+			},
 			expectErr:    true,
 			expectSubstr: "required flag(s) \"project\" not set",
 		},
 		"missing region": {
-			opts:         RawCreateOptions{Project: validOpts.Project, Network: validOpts.Network, PrivateServiceConnectSubnet: validOpts.PrivateServiceConnectSubnet, WorkloadIdentityProjectNumber: validOpts.WorkloadIdentityProjectNumber, WorkloadIdentityPoolID: validOpts.WorkloadIdentityPoolID, WorkloadIdentityProviderID: validOpts.WorkloadIdentityProviderID, NodePoolServiceAccountEmail: validOpts.NodePoolServiceAccountEmail},
+			setupOpts: func() RawCreateOptions {
+				opts := validOpts
+				opts.Region = ""
+				return opts
+			},
 			expectErr:    true
 			expectSubstr: "required flag(s) \"region\" not set",
 		},
 		"missing network": {
-			opts:         RawCreateOptions{Project: validOpts.Project, Region: validOpts.Region, PrivateServiceConnectSubnet: validOpts.PrivateServiceConnectSubnet, WorkloadIdentityProjectNumber: validOpts.WorkloadIdentityProjectNumber, WorkloadIdentityPoolID: validOpts.WorkloadIdentityPoolID, WorkloadIdentityProviderID: validOpts.WorkloadIdentityProviderID, NodePoolServiceAccountEmail: validOpts.NodePoolServiceAccountEmail},
+			setupOpts: func() RawCreateOptions {
+				opts := validOpts
+				opts.Network = ""
+				return opts
+			},
 			expectErr:    true,
 			expectSubstr: "required flag(s) \"network\" not set",
 		},
 		"all required fields provided": {
-			opts:      validOpts,
+			setupOpts: func() RawCreateOptions { return validOpts },
 			expectErr: false,
 		},
 	}

 	for name, tc := range tests {
 		t.Run(name, func(t *testing.T) {
-			_, err := tc.opts.Validate(context.Background(), &core.CreateOptions{})
+			_, err := tc.setupOpts().Validate(context.Background(), &core.CreateOptions{})
 			if tc.expectErr {
docs/content/reference/api.md (1)

5991-6030: New GCP fields read well; one suggestion on WIF prerequisites.

WIF prerequisites are helpful. Consider explicitly stating immutability for workloadIdentity subfields (poolID/providerID/projectNumber) in the prose to align with the “immutable after cluster creation” note and avoid day‑2 drift attempts.

cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-TechPreviewNoUpgrade.crd.yaml (1)

5497-5604: Add cross-field check: nodePoolEmail’s project must match spec.gcp.project.

Regexes/immutability look solid. To prevent misconfig (wrong project in the GSA email), add a CEL validation at the gcp level that ties nodePoolEmail’s domain to spec.gcp.project.

Example diff under spec.platform.gcp (same level as properties: …, required: …):

   gcp:
     description: gcp specifies configuration for clusters running on Google Cloud Platform.
     properties:
       endpointAccess:
         ...
+    x-kubernetes-validations:
+    - message: workloadIdentity.serviceAccountsRef.nodePoolEmail must belong to the same project as spec.platform.gcp.project
+      rule: 'has(self.project) && has(self.workloadIdentity) && has(self.workloadIdentity.serviceAccountsRef) ?
+              self.workloadIdentity.serviceAccountsRef.nodePoolEmail.endsWith(sprintf("@%s.iam.gserviceaccount.com", self.project)) : true'
api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/GCPPlatform.yaml (2)

4708-4757: Enforce uniqueness of label keys to prevent duplicate entries.

As modeled, resourceLabels is an array and can accept duplicate keys. Make it a map-list keyed by "key" so duplicates are rejected and merges behave predictably.

   resourceLabels:
@@
-  items:
+  x-kubernetes-list-type: map
+  x-kubernetes-list-map-keys:
+  - key
+  items:
     description: |-
       GCPResourceLabel is a label to apply to GCP resources created for the cluster.

4799-4807: Tighten projectNumber lower bound (verify exact spec).

Today’s regex allows any 1+ digits; consider a safer floor (e.g., 6) to catch obvious mistakes while still future‑proof. Please verify the officially documented length range before changing.

-                            minLength: 1
+                            minLength: 6

If docs indicate a different minimum/maximum, adjust accordingly.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to Reviews -> Disable Knowledge Base setting

📥 Commits

Reviewing files that changed from the base of the PR and between 569ba13 and e413e19.

⛔ Files ignored due to path filters (4)
  • vendor/github.com/openshift/hypershift/api/hypershift/v1beta1/gcp.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/openshift/hypershift/api/hypershift/v1beta1/hostedcluster_conditions.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/openshift/hypershift/api/hypershift/v1beta1/hostedcluster_types.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/openshift/hypershift/api/hypershift/v1beta1/zz_generated.deepcopy.go is excluded by !vendor/**, !**/vendor/**
📒 Files selected for processing (20)
  • api/hypershift/v1beta1/gcp.go (4 hunks)
  • api/hypershift/v1beta1/gcp_validation_test.go (1 hunks)
  • api/hypershift/v1beta1/hostedcluster_conditions.go (1 hunks)
  • api/hypershift/v1beta1/hostedcluster_types.go (1 hunks)
  • api/hypershift/v1beta1/zz_generated.deepcopy.go (4 hunks)
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/GCPPlatform.yaml (3 hunks)
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/GCPPlatform.yaml (3 hunks)
  • client/applyconfiguration/hypershift/v1beta1/gcpplatformspec.go (2 hunks)
  • client/applyconfiguration/hypershift/v1beta1/gcpresourcelabel.go (1 hunks)
  • client/applyconfiguration/hypershift/v1beta1/gcpserviceaccountsref.go (1 hunks)
  • client/applyconfiguration/hypershift/v1beta1/gcpworkloadidentityconfig.go (1 hunks)
  • client/applyconfiguration/utils.go (1 hunks)
  • cmd/cluster/gcp/create.go (4 hunks)
  • cmd/cluster/gcp/create_test.go (3 hunks)
  • cmd/cluster/gcp/testdata/zz_fixture_TestCreateCluster_minimal_flags_necessary_to_render.yaml (1 hunks)
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-CustomNoUpgrade.crd.yaml (3 hunks)
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-TechPreviewNoUpgrade.crd.yaml (3 hunks)
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-CustomNoUpgrade.crd.yaml (3 hunks)
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-TechPreviewNoUpgrade.crd.yaml (3 hunks)
  • docs/content/reference/api.md (5 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
  • client/applyconfiguration/hypershift/v1beta1/gcpresourcelabel.go
  • client/applyconfiguration/utils.go
  • client/applyconfiguration/hypershift/v1beta1/gcpworkloadidentityconfig.go
  • cmd/cluster/gcp/testdata/zz_fixture_TestCreateCluster_minimal_flags_necessary_to_render.yaml
🧰 Additional context used
📓 Path-based instructions (1)
**

⚙️ CodeRabbit configuration file

-Focus on major issues impacting performance, readability, maintainability and security. Avoid nitpicks and avoid verbosity.

Files:

  • api/hypershift/v1beta1/hostedcluster_conditions.go
  • api/hypershift/v1beta1/hostedcluster_types.go
  • api/hypershift/v1beta1/gcp_validation_test.go
  • client/applyconfiguration/hypershift/v1beta1/gcpplatformspec.go
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/GCPPlatform.yaml
  • cmd/cluster/gcp/create.go
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-TechPreviewNoUpgrade.crd.yaml
  • api/hypershift/v1beta1/zz_generated.deepcopy.go
  • api/hypershift/v1beta1/gcp.go
  • docs/content/reference/api.md
  • cmd/cluster/gcp/create_test.go
  • client/applyconfiguration/hypershift/v1beta1/gcpserviceaccountsref.go
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-CustomNoUpgrade.crd.yaml
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-CustomNoUpgrade.crd.yaml
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/GCPPlatform.yaml
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-TechPreviewNoUpgrade.crd.yaml
🧬 Code graph analysis (7)
api/hypershift/v1beta1/hostedcluster_conditions.go (1)
api/hypershift/v1beta1/hosted_controlplane.go (1)
  • ConditionType (294-294)
api/hypershift/v1beta1/gcp_validation_test.go (1)
api/hypershift/v1beta1/gcp.go (1)
  • GCPResourceLabel (23-54)
client/applyconfiguration/hypershift/v1beta1/gcpplatformspec.go (4)
client/applyconfiguration/hypershift/v1beta1/gcpnetworkconfig.go (1)
  • GCPNetworkConfigApplyConfiguration (22-25)
api/hypershift/v1beta1/gcp.go (1)
  • GCPEndpointAccessType (58-58)
client/applyconfiguration/hypershift/v1beta1/gcpresourcelabel.go (1)
  • GCPResourceLabelApplyConfiguration (22-25)
client/applyconfiguration/hypershift/v1beta1/gcpworkloadidentityconfig.go (1)
  • GCPWorkloadIdentityConfigApplyConfiguration (22-27)
cmd/cluster/gcp/create.go (2)
cmd/util/util.go (1)
  • ValidateRequiredOption (11-16)
support/globalconfig/network.go (1)
  • NetworkConfig (23-29)
api/hypershift/v1beta1/zz_generated.deepcopy.go (1)
api/hypershift/v1beta1/gcp.go (3)
  • GCPResourceLabel (23-54)
  • GCPServiceAccountsRef (228-248)
  • GCPWorkloadIdentityConfig (162-224)
api/hypershift/v1beta1/gcp.go (2)
test/e2e/util/external_oidc.go (1)
  • Key (289-292)
client/applyconfiguration/hypershift/v1beta1/gcpresourcereference.go (1)
  • GCPResourceReference (28-30)
cmd/cluster/gcp/create_test.go (2)
support/globalconfig/network.go (1)
  • NetworkConfig (23-29)
cmd/cluster/gcp/create.go (2)
  • RawCreateOptions (30-54)
  • CreateOptions (119-122)
🔇 Additional comments (42)
api/hypershift/v1beta1/hostedcluster_types.go (1)

129-131: LGTM! Consistent addition for GCP CAPI provider image override.

The new constant follows the established pattern for CAPI provider image overrides and is properly placed alongside other provider-specific constants.

api/hypershift/v1beta1/hostedcluster_conditions.go (1)

154-163: LGTM! Well-documented GCP validation conditions.

The new condition types follow the established pattern for platform-specific validation conditions and are appropriately placed alongside other cloud provider validation conditions.

api/hypershift/v1beta1/gcp.go (1)

226-248: LGTM! GSA email validation is correct and addresses previous review feedback.

The pattern correctly enforces Google Service Account email format, and the MinLength=37 accurately reflects the minimum possible length (6-char service account name + '@' + 6-char project + 24-char domain suffix). This properly addresses the feedback from the previous review.

cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-CustomNoUpgrade.crd.yaml (6)

5769-5778: LGTM: GCP network name validation and immutability are correct.

Also applies to: 5782-5785


5791-5798: LGTM: Subnet name validation and immutability look good.

Also applies to: 5803-5805


5811-5821: LGTM: Project ID pattern matches GCP constraints and prevents trailing hyphen.


5826-5838: LGTM: Region validation is precise (regions only) and immutable.

Also applies to: 5840-5841


5894-6001: ****

Google reserves the "gcp-" prefix for both workload identity pool IDs and provider IDs, as documented in the official Google Cloud IAM guidance. The validation rules in this CRD correctly enforce this documented requirement. The code comments accurately reflect this constraint, and the regex pattern and immutability validations are appropriate.

Likely an incorrect or invalid review comment.


6003-6007: Gating verified: workloadIdentity is correctly required only in gated CRDs.

Verification confirms proper implementation:

  • Default variant: workloadIdentity NOT present (standard, non-gated)
  • CustomNoUpgrade variant: workloadIdentity required at line 6006 (gated)
  • TechPreviewNoUpgrade variant: workloadIdentity required at line 5717 (gated)

The code correctly restricts the workloadIdentity requirement to feature-gated CRD variants, with the standard Default variant remaining unaffected.

client/applyconfiguration/hypershift/v1beta1/gcpserviceaccountsref.go (1)

20-37: Generated applyconfig for GCPServiceAccountsRef looks correct and consistent.

Struct shape, JSON tag, constructor, and WithNodePoolEmail setter all match existing applyconfiguration patterns; no issues found.

client/applyconfiguration/hypershift/v1beta1/gcpplatformspec.go (1)

27-32: New ResourceLabels and WorkloadIdentity apply fields/methods look consistent with existing patterns.

Field additions and WithResourceLabels/WithWorkloadIdentity match the established applyconfiguration style (including nil-guard + panic on variadic inputs); no functional or maintainability issues spotted.

Also applies to: 73-92

api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/GCPPlatform.yaml (4)

4742-4757: GCP network name validation and immutability look good.

Pattern and immutability rule align with GCP resource naming (start letter, [-a-z0-9], <=63). No issues.


4763-4778: PSC subnet name validation and immutability look good.

Same constraints as network name; consistent with GCP requirements.


4793-4797: Project ID regex is correct.

Enforces 6–30 chars, starts with letter, no trailing hyphen. Immutable guard is appropriate.


4802-4811: Region format validation is reasonable.

Requires at least one hyphen and trailing digits; blocks zone suffixes. Immutable guard is appropriate.

cmd/cluster/gcp/create_test.go (1)

22-58: LGTM! Comprehensive test coverage.

The test properly verifies that all new GCP WIF-related fields are correctly mapped from CLI options to the HostedCluster spec, ensuring the integration works end-to-end.

cmd/cluster/gcp/create.go (3)

18-66: LGTM! Clear field declarations and helpful flag descriptions.

The flag bindings properly reference hypershift infra create gcp output, which guides users to obtain the required WIF configuration values.


88-105: Verify that making all WIF fields required is intentional.

All Workload Identity Federation fields (--workload-identity-project-number, --workload-identity-pool-id, --workload-identity-provider-id, --node-pool-service-account-email) are now mandatory. This means WIF is required for all GCP clusters.

If WIF is the only supported authentication method for HyperShift on GCP, this is correct. However, if there are scenarios where users might not want WIF (e.g., using alternative authentication), making these fields unconditionally required could be overly restrictive.

Based on learnings, ensure this aligns with the GCP platform requirements. If WIF is optional, consider adding conditional validation or making these fields optional with appropriate defaults.


168-193: LGTM! Clean mapping of CLI options to API types.

The implementation correctly populates the GCP-specific configuration with network and WIF settings, maintaining a clear structure that aligns with the API design.

api/hypershift/v1beta1/zz_generated.deepcopy.go (3)

1612-1671: LGTM! Properly generated DeepCopy methods.

The auto-generated DeepCopy methods for GCPResourceLabel, GCPServiceAccountsRef, and GCPWorkloadIdentityConfig follow the standard pattern with appropriate nil checks.


1485-1494: LGTM! Correct deep copy logic for GCP fields.

The DeepCopyInto method properly handles:

  • ResourceLabels: Allocates a new slice and copies elements
  • WorkloadIdentity: Direct assignment is correct since the type contains only value types

3431-3435: LGTM! Important fix for proper deep copying.

Line 3434 now correctly calls DeepCopyInto instead of shallow assignment. This ensures nested fields like ResourceLabels are properly deep copied, preventing shared references between copies.

docs/content/reference/api.md (4)

5954-5959: Region validation text looks correct.

Examples and invalid cases are precise; guidance to avoid zone suffixes is clear.


6181-6236: Label constraints are accurately captured.

RFC1035-style rules and ‘goog’ reserved prefix guidance match GCE requirements. LGTM.


6289-6310: Verify IAM roles for nodePoolEmail GSA (least‑privilege).

Current list includes roles/compute.instanceAdmin.v1 and roles/compute.networkAdmin. Many CAPG setups also need roles/iam.serviceAccountUser to attach a VM service account; please confirm against your “cmd/infra/gcp/iam-bindings.json” and CAPG version, and update the list or add a note to rely on that file as the source of truth.


5038-5049: Condition names added — ensure cross‑repo consistency.

Validate that “ValidGCPCredentials” and “ValidGCPWorkloadIdentity” exactly match the condition constants used in CRDs/controllers and any status reporting, to avoid doc/code drift.

cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-TechPreviewNoUpgrade.crd.yaml (5)

5480-5496: LGTM: Network name validation + immutability

Regex and object‑level immutability look correct for GCP VPC network names.


5501-5516: LGTM: Private Service Connect subnet name + immutability

Consistent RFC1035‑style pattern and immutability.


5531-5535: LGTM: GCP project ID regex

Pattern matches documented constraints (start with letter, hyphens allowed, 6–30, no trailing hyphen) and is immutable.


5541-5552: LGTM: Region format regex

Forbids zones and enforces trailing digits; immutable.


5605-5712: LGTM: Workload Identity Federation schema

Required + immutable, reserved prefix checks, and hardened patterns look solid.

cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-CustomNoUpgrade.crd.yaml (2)

5799-5855: WIF IDs: leading-letter + reserved-prefix guard — looks good

poolID/providerID now require a leading letter and block the reserved 'gcp-' prefix. This aligns with GCP rules and prevents invalid configs from passing CRD validation.


5863-5881: Service account email regex (modern domain only) — acknowledged

Strictly allowing PROJECT_ID.iam.gserviceaccount.com and excluding legacy developer.gserviceaccount.com is intentional here. Pattern bounds and immutability look correct.

cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-TechPreviewNoUpgrade.crd.yaml (4)

5372-5387: LGTM on GCP network/subnet name rules and immutability.

Patterns match GCP resource-name requirements and immutability is applied at the object level.

Also applies to: 5393-5408


5423-5427: LGTM on GCP project ID regex and immutability.

The tightened pattern enforces 6–30, lowercase, hyphen, no trailing hyphen, and is immutable.


5432-5444: Region regex looks right.

Pattern excludes zones (e.g., “-a”), requires at least one hyphen and trailing digits; immutability included.


5609-5610: LGTM on making workloadIdentity required for GCP.

Consistent with introducing WIF as the supported auth path for this TechPreview CRD.

Please confirm this won’t block existing non-WIF clusters from applying TechPreview HCPs accidentally.

api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/GCPPlatform.yaml (5)

4634-4649: GCP network name validation + immutability look correct.

Regex and immutability match Compute Engine naming rules; no issues spotted.


4655-4670: PSC subnet name validation + immutability look correct.

Consistent with network name rules; good guardrails.


4685-4689: Project ID regex is appropriately strict.

Length, charset, start/end constraints align with GCP guidance; immutability is appropriate.


4694-4706: Region pattern excludes zones and enforces trailing digits — LGTM.

Examples given match the pattern; immutability is appropriate.


4759-4866: WIF fields and immutability are well‑designed. One question on required-ness.

Schema and reserved‑prefix checks look solid. Confirm that making workloadIdentity required under gcp is intentional for all gated clusters; otherwise consider making it optional initially with validation/conditions guiding users.

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 0

♻️ Duplicate comments (6)
docs/content/reference/api.md (1)

6263-6267: Fix invalid regex (HTML anchor leaked into “Pattern”) and regenerate docs.

The rendered “Pattern” is not a regex; it includes an HTML anchor. Replace with a literal, copy/paste‑able regex and keep the 63‑char note. Update the source Go comment (for hypershift/v1beta1.GCPResourceReference.name), wrap the regex in backticks, then re-run make api-docs.

Apply in docs after regeneration:

-Pattern: “^<a href="[-a-z0-9]*[a-z0-9]">a-z</a>?$” (max 63 chars), per GCP naming requirements.
+Pattern: `^[a-z]([-a-z0-9]{0,61}[a-z0-9])?$` (max 63 chars), per GCP naming requirements.

Also keep the prose “Must start with a lowercase letter and end with a letter or digit.”

api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/GCPPlatform.yaml (1)

4867-4974: WIF: add a cross-field guard for project consistency and tighten projectNumber length.

  • Add a CEL rule ensuring serviceAccountsRef.nodePoolEmail domain matches .project (early typo catch).
  • projectNumber allows any length; suggest 6–20 to avoid obvious input errors while staying flexible.

Proposed diffs:

  1. Cross-field validation under the gcp object:
                   gcp:
                     type: object
+                    x-kubernetes-validations:
+                    - message: serviceAccountsRef.nodePoolEmail must belong to the specified GCP project
+                      rule: >-
+                        !has(self.workloadIdentity) ||
+                        !has(self.workloadIdentity.serviceAccountsRef) ||
+                        self.workloadIdentity.serviceAccountsRef.nodePoolEmail.split("@")[1]
+                        == (self.project + ".iam.gserviceaccount.com")
  1. projectNumber length tweak:
                           projectNumber:
                             ...
-                            maxLength: 25
-                            minLength: 1
+                            maxLength: 20
+                            minLength: 6
api/hypershift/v1beta1/gcp.go (1)

241-247: MinLength is off by one character.

Based on the pattern, the minimum valid email length is 37 characters:

  • Service account name: 6 chars (min from [a-z][a-z0-9-]{4,28}[a-z0-9])
  • @: 1 char
  • Project ID: 6 chars (same pattern)
  • .iam.gserviceaccount.com: 24 chars
  • Total: 37 chars

MinLength=38 would incorrectly reject the shortest valid emails.

 // +kubebuilder:validation:Pattern=`^[a-z][a-z0-9-]{4,28}[a-z0-9]@[a-z][a-z0-9-]{4,28}[a-z0-9]\.iam\.gserviceaccount\.com$`
-// +kubebuilder:validation:MinLength=38
+// +kubebuilder:validation:MinLength=37
 // +kubebuilder:validation:MaxLength=100
cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-CustomNoUpgrade.crd.yaml (1)

5734-5785: Enforce unique label keys at the array level (no list‑map semantics).

Duplicate label keys are currently allowed; last-write-wins is ambiguous. Add a CEL x-kubernetes-validations rule on the array to guarantee uniqueness by key.

Apply under spec.platform.gcp.resourceLabels:

 resourceLabels:
   ...
-  maxItems: 60
-  type: array
+  maxItems: 60
+  type: array
+  x-kubernetes-validations:
+  - message: resourceLabels keys must be unique
+    rule: self == null || self.all(l1, self.exists_one(l2, l1.key == l2.key))
   items:
     properties:
       key:
         ...
cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-TechPreviewNoUpgrade.crd.yaml (1)

5554-5604: Enforce unique label keys for resourceLabels

Allowing duplicates introduces last-write-wins ambiguity and complicates SSA merges. Make the list a keyed map by "key" to enforce uniqueness at the API level.

Apply this minimal change to the list metadata:

 resourceLabels:
   items:
     properties:
       key:
         # …existing key schema…
       value:
         # …existing value schema…
     required:
     - key
     - value
     type: object
   maxItems: 60
-  type: array
+  type: array
+  x-kubernetes-list-map-keys:
+  - key
+  x-kubernetes-list-type: map
cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-TechPreviewNoUpgrade.crd.yaml (1)

5446-5495: Enforce unique label keys for resourceLabels (array-level CEL).

Duplicate keys can cause ambiguous downstream behavior. Keep list semantics and add a CEL uniqueness rule at the array level.

Apply this diff near resourceLabels (array scope):

 resourceLabels:
   description: |-
     resourceLabels are applied to all GCP resources created for the cluster.
     ...
+  x-kubernetes-validations:
+  - message: resourceLabels keys must be unique
+    rule: 'self.all(l, self.exists_one(x, x.key == l.key))'
   items:
     description: |-
       GCPResourceLabel is a label to apply to GCP resources created for the cluster.
     ...
   maxItems: 60
   type: array

Note: This preserves order and avoids list-map semantics while preventing duplicates.

🧹 Nitpick comments (8)
api/hypershift/v1beta1/gcp_validation_test.go (1)

7-101: Tests are lightweight smoke checks; consider strengthening if you want real validation coverage

Right now both tests only assert non‑empty fields (label key, region), so they’ll pass even if the underlying CEL regexes or reserved‑prefix rules are accidentally weakened, as long as these sample values remain non‑empty. That’s fine as a compile‑time/smoke check, but if you want these tests to guard the new GCP constraints more strongly, consider (in a follow‑up):

  • Adding explicit negative cases (e.g. keys starting with goog, bad region formats) and
  • Either reusing a shared validation helper or at least mirroring the regexes in Go so failures surface here and not only via CRD/apiserver tests.

Not critical, but would increase the tests’ signal if you decide it’s worth the extra maintenance.

api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/GCPPlatform.yaml (2)

4802-4811: Tighten region regex to avoid accepting invalid multi-hyphen regions.

Current pattern allows extra “-segment”s (e.g., “us-central1-1”). Recommend exactly one hyphen and trailing digits.

Apply this diff:

-                        pattern: ^[a-z]+(-[a-z0-9]+)+[0-9]+$
+                        pattern: ^[a-z]+-[a-z]+[a-z0-9]*[0-9]$

4815-4865: Enforce unique label keys and keep constraints — switch list to map semantics.

Constraints on key/value and ‘goog’ prefix are solid. To prevent duplicate keys, use map-style list with key as the map key.

Apply this diff:

                       resourceLabels:
                         ...
-                        items:
+                        x-kubernetes-list-map-keys:
+                        - key
+                        x-kubernetes-list-type: map
+                        items:
                           properties:
                             key:
                               ...
                             value:
                               ...
-                        maxItems: 60
+                        maxItems: 60
                         type: array
cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-TechPreviewNoUpgrade.crd.yaml (1)

5605-5712: Consider consolidating immutability to object-level for WorkloadIdentity

You already have x-kubernetes-validations: self == oldSelf on workloadIdentity. Keeping per-field immutability rules duplicates checks and increases churn on future schema changes. Prefer object-level immutability only; retain per-field constraints (length/pattern) for shape validation.

cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-CustomNoUpgrade.crd.yaml (2)

5842-5892: Prevent duplicate GCP label keys (uniqueness).

As written, duplicate keys can be submitted in resourceLabels. Recommend list-map semantics for SSA + validation, or add a CEL guard.

Option A (preferred): treat list as a map keyed by “key”.

   resourceLabels:
     maxItems: 60
     type: array
+    x-kubernetes-list-type: map
+    x-kubernetes-list-map-keys:
+    - key
     items:
       type: object

Option B (CEL guard) if you prefer to keep list-type: atomic.

   resourceLabels:
     maxItems: 60
     type: array
+    x-kubernetes-validations:
+    - message: resourceLabels keys must be unique
+      rule: self.all(x, self.exists_one(y, x.key == y.key))

5894-6001: Guard against mismatched project in service account email.

Add a cross-field validation ensuring workloadIdentity.serviceAccountsRef.nodePoolEmail belongs to the same project as platform.gcp.project to avoid silent misconfig.

   gcp:
     properties:
       ...
     required:
       - networkConfig
       - project
       - region
       - workloadIdentity
     type: object
+    x-kubernetes-validations:
+    - message: serviceAccountsRef.nodePoolEmail project must match platform.gcp.project
+      rule: >
+        !has(self.workloadIdentity) ||
+        self.workloadIdentity.serviceAccountsRef.nodePoolEmail.split("@", 2)[1].endsWith(".iam.gserviceaccount.com") &&
+        self.workloadIdentity.serviceAccountsRef.nodePoolEmail
+          .split("@", 2)[1]
+          .split(".iam.gserviceaccount.com", 2)[0] == self.project

Also applies to: 6003-6008

api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/GCPPlatform.yaml (2)

4708-4757: Enforce label key uniqueness via list=map for resourceLabels.

Today duplicates can slip in; GCP treats labels as a map. Make the list a map keyed by "key" to guarantee uniqueness and better patch semantics.

Apply this minimal diff in the resourceLabels array block:

 resourceLabels:
   items:
     properties:
       key:
         ...
     required:
     - key
     - value
     type: object
   maxItems: 60
-  type: array
+  x-kubernetes-list-map-keys:
+  - key
+  x-kubernetes-list-type: map
+  type: array

4759-4866: WIF types/immutability look good; add cross-field check for GSA email project.

Great coverage on pool/provider IDs, reserved prefixes, and hardened SA email regex. Add a CEL guard to ensure nodePoolEmail’s project matches spec.platform.gcp.project to avoid subtle misconfigurations.

Apply at the gcp object level (same scope as project/region):

   gcp:
     properties:
       project:
         ...
       workloadIdentity:
         ...
+    x-kubernetes-validations:
+    - message: serviceAccountsRef.nodePoolEmail must belong to the same project as spec.platform.gcp.project
+      rule: '!has(self.workloadIdentity) || self.workloadIdentity.serviceAccountsRef.nodePoolEmail.split("@").size() == 2 && self.workloadIdentity.serviceAccountsRef.nodePoolEmail.split("@")[1] == (self.project + ".iam.gserviceaccount.com")'

Note: placing this at the gcp object allows referencing both fields in one rule.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to Reviews -> Disable Knowledge Base setting

📥 Commits

Reviewing files that changed from the base of the PR and between e413e19 and 5016044.

⛔ Files ignored due to path filters (4)
  • vendor/github.com/openshift/hypershift/api/hypershift/v1beta1/gcp.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/openshift/hypershift/api/hypershift/v1beta1/hostedcluster_conditions.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/openshift/hypershift/api/hypershift/v1beta1/hostedcluster_types.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/openshift/hypershift/api/hypershift/v1beta1/zz_generated.deepcopy.go is excluded by !vendor/**, !**/vendor/**
📒 Files selected for processing (20)
  • api/hypershift/v1beta1/gcp.go (4 hunks)
  • api/hypershift/v1beta1/gcp_validation_test.go (1 hunks)
  • api/hypershift/v1beta1/hostedcluster_conditions.go (1 hunks)
  • api/hypershift/v1beta1/hostedcluster_types.go (1 hunks)
  • api/hypershift/v1beta1/zz_generated.deepcopy.go (4 hunks)
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/GCPPlatform.yaml (3 hunks)
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/GCPPlatform.yaml (3 hunks)
  • client/applyconfiguration/hypershift/v1beta1/gcpplatformspec.go (2 hunks)
  • client/applyconfiguration/hypershift/v1beta1/gcpresourcelabel.go (1 hunks)
  • client/applyconfiguration/hypershift/v1beta1/gcpserviceaccountsref.go (1 hunks)
  • client/applyconfiguration/hypershift/v1beta1/gcpworkloadidentityconfig.go (1 hunks)
  • client/applyconfiguration/utils.go (1 hunks)
  • cmd/cluster/gcp/create.go (4 hunks)
  • cmd/cluster/gcp/create_test.go (3 hunks)
  • cmd/cluster/gcp/testdata/zz_fixture_TestCreateCluster_minimal_flags_necessary_to_render.yaml (1 hunks)
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-CustomNoUpgrade.crd.yaml (3 hunks)
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-TechPreviewNoUpgrade.crd.yaml (3 hunks)
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-CustomNoUpgrade.crd.yaml (3 hunks)
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-TechPreviewNoUpgrade.crd.yaml (3 hunks)
  • docs/content/reference/api.md (5 hunks)
🚧 Files skipped from review as they are similar to previous changes (5)
  • cmd/cluster/gcp/create.go
  • client/applyconfiguration/utils.go
  • client/applyconfiguration/hypershift/v1beta1/gcpserviceaccountsref.go
  • client/applyconfiguration/hypershift/v1beta1/gcpworkloadidentityconfig.go
  • client/applyconfiguration/hypershift/v1beta1/gcpplatformspec.go
🧰 Additional context used
📓 Path-based instructions (1)
**

⚙️ CodeRabbit configuration file

-Focus on major issues impacting performance, readability, maintainability and security. Avoid nitpicks and avoid verbosity.

Files:

  • api/hypershift/v1beta1/hostedcluster_conditions.go
  • api/hypershift/v1beta1/hostedcluster_types.go
  • client/applyconfiguration/hypershift/v1beta1/gcpresourcelabel.go
  • cmd/cluster/gcp/create_test.go
  • cmd/cluster/gcp/testdata/zz_fixture_TestCreateCluster_minimal_flags_necessary_to_render.yaml
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-TechPreviewNoUpgrade.crd.yaml
  • docs/content/reference/api.md
  • api/hypershift/v1beta1/gcp.go
  • api/hypershift/v1beta1/zz_generated.deepcopy.go
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-CustomNoUpgrade.crd.yaml
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-CustomNoUpgrade.crd.yaml
  • api/hypershift/v1beta1/gcp_validation_test.go
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/GCPPlatform.yaml
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-TechPreviewNoUpgrade.crd.yaml
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/GCPPlatform.yaml
🧬 Code graph analysis (5)
api/hypershift/v1beta1/hostedcluster_conditions.go (1)
api/hypershift/v1beta1/hosted_controlplane.go (1)
  • ConditionType (294-294)
cmd/cluster/gcp/create_test.go (1)
cmd/cluster/gcp/create.go (2)
  • RawCreateOptions (30-54)
  • CreateOptions (119-122)
api/hypershift/v1beta1/gcp.go (1)
client/applyconfiguration/hypershift/v1beta1/gcpresourcereference.go (1)
  • GCPResourceReference (28-30)
api/hypershift/v1beta1/zz_generated.deepcopy.go (1)
api/hypershift/v1beta1/gcp.go (3)
  • GCPResourceLabel (23-54)
  • GCPServiceAccountsRef (228-248)
  • GCPWorkloadIdentityConfig (162-224)
api/hypershift/v1beta1/gcp_validation_test.go (1)
api/hypershift/v1beta1/gcp.go (1)
  • GCPResourceLabel (23-54)
🔇 Additional comments (35)
api/hypershift/v1beta1/hostedcluster_types.go (1)

129-131: GCP CAPI provider image annotation matches existing pattern

The new ClusterAPIGCPProviderImage constant is consistent with other CAPI provider image override annotations and introduces no behavioral risk. LGTM.

api/hypershift/v1beta1/hostedcluster_conditions.go (1)

154-163: New GCP conditions are consistent with existing condition taxonomy

ValidGCPCredentials and ValidGCPWorkloadIdentity follow the established condition naming and documentation style (AWS/Azure counterparts) and give controllers clear hooks to surface GCP failures. No issues from an API/compatibility standpoint.

api/hypershift/v1beta1/zz_generated.deepcopy.go (1)

1485-1494: GCP deep‑copy semantics look correct and avoid aliasing

  • GCPPlatformSpec.DeepCopyInto now:
    • Deep‑copies ResourceLabels by allocating a new slice and copying value elements.
    • Copies WorkloadIdentity by value, which is appropriate given it and GCPServiceAccountsRef are value‑only structs.
  • New DeepCopy helpers for GCPResourceLabel, GCPServiceAccountsRef, and GCPWorkloadIdentityConfig are straightforward and correct for their field shapes.
  • PlatformSpec.DeepCopyInto now deep‑copies the GCP pointer via DeepCopyInto, preventing shared mutable state across copies.

Overall this generated code matches the new GCP API types and should behave correctly.

Also applies to: 1612-1625, 1642-1655, 1657-1671, 3394-3435

cmd/cluster/gcp/testdata/zz_fixture_TestCreateCluster_minimal_flags_necessary_to_render.yaml (1)

42-52: Fixture updates align with new GCP validation requirements

The updated fixture now includes non‑empty network/subnet names and a workloadIdentity block whose values match the documented GCP regex constraints (project number, pool/provider IDs, and service account email). This should keep the “minimal flags” test meaningful as the API tightens validation.

docs/content/reference/api.md (2)

5038-5049: Align condition type naming for GCP WIF validation.

Docs list “ValidGCPWorkloadIdentity”, while the PR summary mentions “ValidWorkloadIdentityConfiguration”. Use a single, canonical ConditionType across code, CRDs, and docs to avoid confusion, then regenerate docs.


6297-6307: Current documentation is accurate per authoritative iam-bindings.json source.

The documentation at lines 6297-6307 correctly reflects the roles defined in cmd/infra/gcp/iam-bindings.json for the nodepool-mgmt service account:

  • roles/compute.instanceAdmin.v1
  • roles/compute.networkAdmin

The suggested roles/iam.serviceAccountUser role is not present in the authoritative IAM bindings file referenced in the documentation itself. No changes needed.

Likely an incorrect or invalid review comment.

api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/GCPPlatform.yaml (4)

4742-4757: GCP network name regex and immutability look correct.

Pattern matches GCP naming rules and immutability guard is appropriate.


4763-4778: Subnet name validation and immutability look good.

Matches GCP constraints; object-level immutability is fine here.


4785-4797: Project ID validation looks right.

Regex enforces 6–30 chars, start with letter, no trailing hyphen — aligns with GCP rules. Immutability guard is correct.


4976-4980: Requiring workloadIdentity is OK under the GCPPlatform feature gate.

Given this CRD is feature-gated, making workloadIdentity required here won’t impact existing non-GCP clusters.

client/applyconfiguration/hypershift/v1beta1/gcpresourcelabel.go (1)

1-47: LGTM - Generated apply configuration code.

This is auto-generated code following standard controller-runtime patterns for server-side apply. The fluent builder pattern is correctly implemented.

cmd/cluster/gcp/create_test.go (3)

63-97: Good use of baseline validOpts for test maintainability.

The pattern of defining a valid baseline and selectively omitting fields for negative test cases is clean. The test coverage for the new required fields (network, WIF configuration) is appropriate.


52-57: Assertions correctly verify the new API structure.

The test properly validates that CLI options are correctly mapped to the nested GCPPlatformSpec fields including NetworkConfig, WorkloadIdentity, and ServiceAccountsRef.


131-146: Integration test updated with all required flags.

The minimal flags test case is appropriately updated to include the new required GCP flags, ensuring the CLI rendering works end-to-end.

api/hypershift/v1beta1/gcp.go (4)

6-18: Improved resource name pattern.

The updated pattern ^[a-z]([-a-z0-9]*[a-z0-9])?$ correctly allows single-character names (just "a") while still enforcing GCP naming rules. The optional group properly handles the case where hyphens and digits can appear in the middle but names must end with a letter or digit.


20-54: Well-documented RFC1035 label validation.

The patterns correctly enforce Compute Engine label requirements. Good documentation noting that other GCP services may have different rules. The CEL validation for the reserved 'goog' prefix is appropriate.


102-117: Region pattern correctly enforces GCP region format.

The pattern ^[a-z]+(-[a-z0-9]+)+[0-9]+$ correctly validates regions (e.g., us-central1, europe-west12) while rejecting zones (e.g., us-central1-a) and invalid formats (e.g., us1, us-central). The comments clearly document valid and invalid examples.


159-224: Workload Identity configuration is well-structured.

The validation constraints are internally consistent - PoolID/ProviderID patterns enforce 4-32 characters which matches the documented and annotated length constraints. The reserved gcp- prefix is correctly blocked via CEL validation, and immutability is properly enforced.

cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-CustomNoUpgrade.crd.yaml (1)

5799-5856: WIF IDs: good fix to require a leading letter; please verify across generated CRDs.

poolID/providerID now start with a letter and are immutable. Looks correct. Please confirm all CRDs (HostedClusters/HostedControlPlanes, Custom/TechPreview) and the Go types carry the same pattern.

cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-TechPreviewNoUpgrade.crd.yaml (5)

5480-5496: GCP network name validation looks correct

Pattern matches GCP RFC1035-style names and immutability is enforced. LGTM.


5501-5516: GCP PSC subnet name validation looks correct

Pattern and immutability align with GCP rules. LGTM.


5531-5535: Project ID regex + immutability: good coverage

Regex enforces GCP rules (6–30 chars, starts letter, no trailing dash). Immutability is appropriate. LGTM.


5537-5549: Region format validation is sensible

Rejects zone suffixes and requires trailing digits; permissive enough for future regions. LGTM.


5717-5718: Verify consumer paths for required workloadIdentity field in GCP platform spec

The workloadIdentity field is marked as required in both TechPreviewNoUpgrade and CustomNoUpgrade CRD variants. Infrastructure code exists to create Workload Identity Pool, OIDC Provider, and service accounts via a separate create_iam CLI command, and API documentation includes prerequisites and configuration requirements for workloadIdentity.

However, verification found no practical examples in examples/ directory and no e2e tests demonstrating complete GCP cluster creation with workloadIdentity populated. The create_iam CLI operates independently, requiring users to manually wire its output into the cluster spec. Confirm that:

  • CLI/operator flow documents this two-step process clearly
  • Test coverage validates end-to-end GCP cluster creation with workloadIdentity
  • User-facing examples show how to combine create_iam output with cluster manifest
cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-TechPreviewNoUpgrade.crd.yaml (5)

5372-5387: GCP network name regex + immutability: LGTM

Pattern matches GCP VPC naming and is immutable as intended.


5393-5408: PSC subnet name regex + immutability: LGTM

Consistent with GCP resource naming and locked post‑create.


5423-5427: Project ID validation: LGTM

Regex, length bounds, and immutability align with GCP rules.


5432-5444: Region format validation: LGTM

Pattern excludes zones (e.g., “-a”) and enforces digit suffix; immutability added.


5497-5604: Confirm intent: workloadIdentity is required and fully immutable.

Making workloadIdentity required (Line 5606) and immutable is a strong contract. Given this PR adds only the API layer (no controller), confirm this won’t block existing GCP users or day‑2 adjustments during TechPreview rollout.

cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-CustomNoUpgrade.crd.yaml (1)

5769-5785: GCP name/project/region validations look solid.

Regexes and immutability rules align with GCP docs and RFC1035-style constraints. No issues from me here.

Also applies to: 5791-5805, 5820-5824, 5830-5838

api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/GCPPlatform.yaml (5)

4634-4650: GCP network name regex + immutability look correct.

Meets Compute Engine rules; object-level immutability is fine.


4655-4670: Private Service Connect subnet name validation is solid.

Pattern and immutability align with GCP naming.


4676-4686: Project ID pattern tightened appropriately.

Length and boundary rules match GCP constraints; no issues spotted.


4868-4872: Making workloadIdentity required: confirm gating and CLI UX.

Since workloadIdentity is now required for GCP, confirm:

  • The feature gate and CLI validations surface clear errors when omitted.
  • Docs and examples are updated accordingly.

4694-4703: Region pattern validation confirmed.

The regex pattern correctly validates GCP region format. Test results confirm all valid regions pass and common mistakes (missing hyphens, missing trailing digits, zone suffixes, uppercase letters, double hyphens) are properly rejected.

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 2

♻️ Duplicate comments (8)
api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/GCPPlatform.yaml (1)

4938-4986: CEL guard: ensure GSAs belong to the configured GCP project.

Add a cross-field validation so controlPlaneEmail/nodePoolEmail domains match .project to avoid hard-to-debug mismatches.

   gcp:
     description: gcp specifies configuration for clusters running
       on Google Cloud Platform.
     properties:
@@
     type: object
+    x-kubernetes-validations:
+    - message: serviceAccountsRef.controlPlaneEmail must belong to the specified GCP project
+      rule: >-
+        !has(self.workloadIdentity) || !has(self.workloadIdentity.serviceAccountsRef) ||
+        self.workloadIdentity.serviceAccountsRef.controlPlaneEmail.split("@")[1] ==
+        (self.project + ".iam.gserviceaccount.com")
+    - message: serviceAccountsRef.nodePoolEmail must belong to the specified GCP project
+      rule: >-
+        !has(self.workloadIdentity) || !has(self.workloadIdentity.serviceAccountsRef) ||
+        self.workloadIdentity.serviceAccountsRef.nodePoolEmail.split("@")[1] ==
+        (self.project + ".iam.gserviceaccount.com")

Based on learnings, the requirement was previously discussed as optional given the feature gate; still a low-cost safety net.

docs/content/reference/api.md (1)

6263-6267: Fix invalid regex rendering (HTML anchor leaked into “Pattern”).

The regex for GCPResourceReference.name is broken in the generated docs (contains an HTML anchor). Replace with a copy/paste‑able pattern and keep the 63‑char note. Update the source Go comment to wrap the regex in backticks and regenerate docs.

Apply this doc change:

-Pattern: “^<a href="[-a-z0-9]*[a-z0-9]">a-z</a>?$” (max 63 chars), per GCP naming requirements.
+Pattern: `^[a-z]([-a-z0-9]{0,61}[a-z0-9])?$` (max 63 chars), per GCP naming requirements.

Tip: In api/hypershift/v1beta1/gcp.go, wrap the regex in backticks in the field doc and run make api-docs so it renders as code, not a link.

cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-CustomNoUpgrade.crd.yaml (1)

5734-5785: Enforce unique GCP label keys (keep maxItems=60 headroom).

The resourceLabels array permits duplicate keys, causing ambiguous last-write-wins behavior at reconciliation time. Add a CEL uniqueness check at the array level to guarantee keys are unique without switching list semantics.

Apply under spec.platform.gcp.resourceLabels:

                       resourceLabels:
                         description: |-
                           resourceLabels are applied to all GCP resources created for the cluster.
@@
                         maxItems: 60
                         type: array
+                        x-kubernetes-validations:
+                        - message: resourceLabels keys must be unique
+                          rule: self == null || self.all(l1, self.exists_one(l2, l1.key == l2.key))
api/hypershift/v1beta1/gcp.go (1)

226-267: Service account email MinLength is off by one vs the regex and blocks valid addresses

The regex for NodePoolEmail/ControlPlaneEmail:

^[a-z][a-z0-9-]{4,28}[a-z0-9]@[a-z][a-z0-9-]{4,28}[a-z0-9]\.iam\.gserviceaccount\.com$

implies a minimum length of:

  • local part: 1 + 4 + 1 = 6
  • @: 1
  • project ID: 1 + 4 + 1 = 6
  • suffix .iam.gserviceaccount.com: 24

Total minimum: 6 + 1 + 6 + 24 = 37 characters.

With +kubebuilder:validation:MinLength=38, a perfectly valid minimal address like aaaaab@aaaaab.iam.gserviceaccount.com (37 chars) would match the pattern but still be rejected by the schema. That’s a user‑visible correctness issue.

Consider aligning MinLength with the regex for both fields:

-	// +kubebuilder:validation:MinLength=38
+	// +kubebuilder:validation:MinLength=37
@@
-	// +kubebuilder:validation:MinLength=38
+	// +kubebuilder:validation:MinLength=37

This keeps the schema constraints self‑consistent and avoids unnecessarily rejecting valid GSAs.

cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-TechPreviewNoUpgrade.crd.yaml (1)

5554-5604: Enforce unique label keys for resourceLabels

resourceLabels as a plain array allows duplicate keys and last-write-wins ambiguity. Make it a list-map keyed by “key” to ensure uniqueness and clean merge/apply semantics.

Apply this minimal change at the array level:

 resourceLabels:
   items:
     properties:
       key:
         ...
       value:
         ...
     required:
     - key
     - value
     type: object
   maxItems: 60
   type: array
+  x-kubernetes-list-map-keys:
+  - key
+  x-kubernetes-list-type: map
cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-TechPreviewNoUpgrade.crd.yaml (1)

5445-5495: Enforce unique label keys to avoid ambiguous updates

Duplicates in resourceLabels can cause last-write-wins ambiguity across resources/operators. Add a CEL array-level rule to ensure keys are unique. Also, you set maxItems: 60 (headroom) — confirm this is intentional and mirrored in other CRDs.

Apply this diff near resourceLabels (array level):

 resourceLabels:
   description: |-
     resourceLabels are applied to all GCP resources created for the cluster.
     ...
+  x-kubernetes-validations:
+  - message: resourceLabels keys must be unique
+    rule: 'self.all(l, self.exists_one(x, x.key == l.key))'
   items:
     description: |-
       GCPResourceLabel is a label to apply to GCP resources created for the cluster.
   ...
-  maxItems: 60
+  maxItems: 60
   type: array
cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-CustomNoUpgrade.crd.yaml (2)

5842-5892: Enforce unique label keys via list‑map semantics (optional).

To prevent duplicate label keys and get stable SSA merge behavior, mark resourceLabels as a map keyed by “key”. Non‑breaking and improves UX.

 resourceLabels:
@@
-  maxItems: 60
-  type: array
+  maxItems: 60
+  type: array
+  x-kubernetes-list-map-keys:
+  - key
+  x-kubernetes-list-type: map

5869-5873: Reserved prefix message: keep as-is if intentionally stricter than GCP.

You’re blocking any “goog*”. If this broader reservation is intentional (to avoid collisions), consider a short doc note in the field description to make it explicit to users.

🧹 Nitpick comments (8)
api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/GCPPlatform.yaml (1)

4815-4865: Enforce unique label keys and SSA-friendly merges for resourceLabels.

Make resourceLabels a map keyed by "key" to prevent duplicates and improve server-side apply behavior.

 resourceLabels:
   description: |-
@@
   items:
@@
     type: object
   maxItems: 60
   type: array
+  x-kubernetes-list-map-keys:
+  - key
+  x-kubernetes-list-type: map
api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/GCPPlatform.yaml (2)

4885-4887: Overly strict immutability blocks safe GSA rotation.

Making workloadIdentity entirely immutable prevents rotating GSAs (serviceAccountsRef) during incident response or routine rotation. Keep poolID/projectNumber/providerID immutable, but allow serviceAccountsRef updates (still format-validated).

Adjust validations:

-                        x-kubernetes-validations:
-                        - message: WorkloadIdentity is immutable
-                          rule: self == oldSelf
+                        x-kubernetes-validations:
+                        - message: WorkloadIdentity identifiers (poolID, projectNumber, providerID) are immutable; serviceAccountsRef may be rotated.
+                          rule: self.poolID == oldSelf.poolID && self.projectNumber == oldSelf.projectNumber && self.providerID == oldSelf.providerID

And drop per-field immutability on emails:

-                                x-kubernetes-validations:
-                                - message: ControlPlane email is immutable
-                                  rule: self == oldSelf
-                                x-kubernetes-validations:
-                                - message: NodePool email is immutable
-                                  rule: self == oldSelf

Also applies to: 4853-4855, 4873-4875


4735-4738: Narrow reserved-prefix check to 'goog-' to avoid false positives.

Current rule blocks any key starting with "goog" (e.g., "goody-..."). GCP reserves the "goog-" prefix; narrow the match accordingly.

-                              - message: Label keys starting with the reserved 'goog'
-                                  prefix are not allowed
-                                rule: '!self.startsWith(''goog'')'
+                              - message: Label keys starting with the reserved 'goog-' prefix are not allowed
+                                rule: '!self.startsWith(''goog-'')'
cmd/cluster/gcp/create.go (2)

18-27: New GCP flags and validation: confirm intentional requirement of full WIF configuration

The new flags and RawCreateOptions fields are wired cleanly and Validate enforces that all of them (network, PSC subnet, WIF project number, pool/provider IDs, and both service account emails) are non-empty before proceeding. This makes hypershift cluster create gcp require a full Workload Identity configuration plus network details for every new cluster.

If the intent is that WIF is always mandatory for GCP-created clusters, this is fine, but it is a behavioral change for the CLI and may break existing scripts that relied on fewer required flags. If WIF is meant to be optional, you’ll likely want to relax some of these ValidateRequiredOption checks and/or gate them behind a feature flag.

Also applies to: 30-58, 60-71, 84-113


175-198: ApplyPlatformSpecifics wiring for NetworkConfig and WorkloadIdentity looks correct

The mapping from validated options into GCPPlatformSpec (NetworkConfig with Network and PrivateServiceConnectSubnet, and WorkloadIdentity including ServiceAccountsRef) is straightforward and matches the API types described in api/hypershift/v1beta1/gcp.go. This should round-trip cleanly into the rendered HostedCluster and the YAML fixture.

If Workload Identity may evolve (e.g., additional optional fields or different service account roles), consider keeping all WIF-related wiring localized here so future changes don’t leak into other parts of the CLI.

cmd/cluster/gcp/create_test.go (1)

65-75: Extend validation tests to cover all newly required GCP flags

TestValidateGCPOptions now covers missing project, region, and network, plus the all-fields-valid case, but Validate also requires PrivateServiceConnectSubnet, WorkloadIdentityProjectNumber, WorkloadIdentityPoolID, WorkloadIdentityProviderID, and both service account emails.

Consider adding individual table entries for each of these missing fields so future changes to validation behavior are caught by tests.

Also applies to: 77-101, 105-115

api/hypershift/v1beta1/gcp.go (1)

159-224: Redundant immutability markers could be simplified later

Within GCPWorkloadIdentityConfig, each field has both +immutable and an explicit XValidation:rule="self == oldSelf" (and ServiceAccountsRef is also immutable at the parent level). Functionally this is fine, but it results in redundant immutability constraints in the generated CRD and slightly more verbose schema.

In a follow‑up, you could rely on either the +immutable marker or the explicit XValidation (but not both) on these fields to reduce schema noise while preserving behavior.

cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-TechPreviewNoUpgrade.crd.yaml (1)

5497-5625: Add cross-field check: SA emails’ project must match spec.gcp.project

Prevent misconfig by ensuring controlPlaneEmail/nodePoolEmail belong to the same project as spec.platform.gcp.project.

Apply this diff under the spec.platform.gcp object (sibling to “type: object”):

                     required:
                     - networkConfig
                     - project
                     - region
                     - workloadIdentity
                     type: object
+                    x-kubernetes-validations:
+                    - message: service account emails must use the same project as spec.platform.gcp.project
+                      rule: |
+                        !has(self.workloadIdentity) || !has(self.project) ||
+                        (
+                          self.workloadIdentity.serviceAccountsRef.controlPlaneEmail.split("@")[1].split(".")[0] == self.project &&
+                          self.workloadIdentity.serviceAccountsRef.nodePoolEmail.split("@")[1].split(".")[0] == self.project
+                        )

If you prefer scoping the rule, we can place an equivalent validation at a higher ancestor for broader context. I can mirror this to the non-TechPreview CRD in a follow-up.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to Reviews -> Disable Knowledge Base setting

📥 Commits

Reviewing files that changed from the base of the PR and between 5016044 and f85702a.

⛔ Files ignored due to path filters (1)
  • vendor/github.com/openshift/hypershift/api/hypershift/v1beta1/gcp.go is excluded by !vendor/**, !**/vendor/**
📒 Files selected for processing (11)
  • api/hypershift/v1beta1/gcp.go (4 hunks)
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/GCPPlatform.yaml (3 hunks)
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/GCPPlatform.yaml (3 hunks)
  • cmd/cluster/gcp/create.go (4 hunks)
  • cmd/cluster/gcp/create_test.go (3 hunks)
  • cmd/cluster/gcp/testdata/zz_fixture_TestCreateCluster_minimal_flags_necessary_to_render.yaml (1 hunks)
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-CustomNoUpgrade.crd.yaml (3 hunks)
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-TechPreviewNoUpgrade.crd.yaml (3 hunks)
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-CustomNoUpgrade.crd.yaml (3 hunks)
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-TechPreviewNoUpgrade.crd.yaml (3 hunks)
  • docs/content/reference/api.md (5 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**

⚙️ CodeRabbit configuration file

-Focus on major issues impacting performance, readability, maintainability and security. Avoid nitpicks and avoid verbosity.

Files:

  • cmd/cluster/gcp/create_test.go
  • docs/content/reference/api.md
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-TechPreviewNoUpgrade.crd.yaml
  • cmd/cluster/gcp/create.go
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-CustomNoUpgrade.crd.yaml
  • cmd/cluster/gcp/testdata/zz_fixture_TestCreateCluster_minimal_flags_necessary_to_render.yaml
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/GCPPlatform.yaml
  • api/hypershift/v1beta1/gcp.go
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-TechPreviewNoUpgrade.crd.yaml
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/GCPPlatform.yaml
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-CustomNoUpgrade.crd.yaml
🧬 Code graph analysis (3)
cmd/cluster/gcp/create_test.go (2)
support/globalconfig/network.go (1)
  • NetworkConfig (23-29)
cmd/cluster/gcp/create.go (2)
  • RawCreateOptions (31-58)
  • CreateOptions (127-130)
cmd/cluster/gcp/create.go (3)
cmd/util/util.go (1)
  • ValidateRequiredOption (11-16)
support/globalconfig/network.go (1)
  • NetworkConfig (23-29)
api/hypershift/v1beta1/gcp.go (4)
  • GCPNetworkConfig (71-83)
  • GCPResourceReference (6-18)
  • GCPWorkloadIdentityConfig (162-224)
  • GCPServiceAccountsRef (228-268)
api/hypershift/v1beta1/gcp.go (2)
test/e2e/util/external_oidc.go (1)
  • Key (289-292)
client/applyconfiguration/hypershift/v1beta1/gcpresourcereference.go (1)
  • GCPResourceReference (28-30)
🔇 Additional comments (26)
api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/GCPPlatform.yaml (1)

4902-4915: Reconsider minLength constraint—Google does not enforce fixed project number length.

Google's public docs do not specify a fixed digit length for project numbers, treating them as opaque numeric IDs. While 12-digit numbers are typical in practice, setting minLength: 6 could reject valid project numbers. Keep the original minLength: 1 to avoid unnecessarily rejecting valid identifiers, and use maxLength: 20-25 as headroom. The pattern ^[0-9]+$ is appropriate.

api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/GCPPlatform.yaml (1)

4889-4893: Verify backward compatibility impact of required workloadIdentity field in GCP platform specs.

The review concern is partially confirmed: workloadIdentity is marked as required in the featuregated CRD manifest (lines 4889–4893), and the CLI enforces its presence when creating clusters via cmd/cluster/gcp/create.go (lines 99–106). However, the verification was inconclusive on backward compatibility:

  • Standard (non-featuregated) CRD manifests do not appear to reference workloadIdentity in available search results, suggesting this is a new requirement.
  • The featuregated deployment mechanism could not be located in the codebase, making it unclear whether:
    • These manifests are deployed conditionally (only on supported clusters) or universally
    • Existing clusters without workloadIdentity config would be rejected or migrated
    • Controllers gracefully handle the absence of this field

Manually verify:

  1. How zz_generated.featuregated-crd-manifests/ CRDs are selected and deployed
  2. Whether old HCP/HC instances without workloadIdentity would fail validation or create operations
  3. Whether default values or optional handling exists in controllers as a fallback
docs/content/reference/api.md (1)

5038-5049: Condition naming consistency: “ValidGCPWorkloadIdentity” vs PR objective.

Docs introduce ValidGCPWorkloadIdentity, while the PR summary mentions ValidWorkloadIdentityConfiguration. Please confirm the intended condition type name and align code, CRD, and docs.

cmd/cluster/gcp/testdata/zz_fixture_TestCreateCluster_minimal_flags_necessary_to_render.yaml (1)

42-53: Fixture values correctly aligned with new GCP flags and spec wiring

The updated fixture (network, privateServiceConnectSubnet, and workloadIdentity block including service account emails) matches the new CLI flags and the ApplyPlatformSpecifics mapping, so comparison-based tests should remain stable.

cmd/cluster/gcp/create_test.go (2)

25-39: ApplyPlatformSpecifics test thoroughly covers new GCP fields

The test now asserts all key fields (NetworkConfig names, WorkloadIdentity project number/pool/provider IDs, and both service account emails). This gives good confidence that the GCPPlatformSpec wiring stays correct when the API evolves.

Also applies to: 47-59


135-145: CreateCluster CLI test and fixture stay consistent with new required flags

The minimal CLI args include all new flags, and the rendered manifests are compared against the updated fixture. This is a good end-to-end guard that the flag wiring, ApplyPlatformSpecifics, and YAML structure remain in sync as the API evolves.

Also applies to: 171-176

api/hypershift/v1beta1/gcp.go (5)

7-17: GCPResourceReference name validation and docs look consistent with GCP naming rules

The updated comments and pattern (^[a-z]([-a-z0-9]*[a-z0-9])?$ with MaxLength=63) correctly enforce “starts with a letter, ends with letter/digit, lowercase/digits/hyphens only” for resource names and align with Compute Engine naming expectations. No issues here.


20-54: GCPResourceLabel key/value validation is appropriately strict and reserves goog safely

The RFC1035-style key/value regexes and the explicit !self.startsWith('goog') XValidation match the stated constraints and avoid underscores while staying compatible with Compute Engine label rules. Allowing empty values via MinLength=0 + ^$|... is also in line with GCP behavior. This struct looks well‑designed.


70-83: Immutability on network and Private Service Connect subnet is a good safety guard

Marking both Network and PrivateServiceConnectSubnet as immutable (with explicit self == oldSelf XValidation) is a sensible choice for network topology—changing these after cluster creation would be highly disruptive. The config here is clear and robust.


85-117: Project and region validation tighten inputs without blocking valid GCP values

The project ID regex now enforces 6–30 chars, starting with a letter and not ending in -, which matches GCP requirements. The region pattern (^[a-z]+(-[a-z0-9]+)+[0-9]+$) correctly allows multi‑segment regions like europe-west12 while rejecting zones (us-central1-a). Overall, this is a solid tightening of validation.


131-156: ResourceLabels cap and WorkloadIdentity immutability fit the API design

Capping resourceLabels at 60 items to leave headroom under GCP’s 64‑label limit is a pragmatic choice. Making workloadIdentity required and immutable (plus self == oldSelf XValidation) matches the intent to treat WIF configuration as a “set once at creation” concern and avoids mid‑lifecycle auth breakage, which aligns with the feature’s semantics.

cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-TechPreviewNoUpgrade.crd.yaml (4)

5480-5496: GCP VPC/subnet naming and immutability: LGTM

Regex matches GCP rules and immutability is correctly enforced at the object level.

Also applies to: 5501-5516


5522-5552: Project ID and region validations: LGTM

  • Project ID regex enforces 6–30, lowercase/digits/hyphens, start letter, no trailing hyphen.
  • Region regex prevents zone suffixes and requires trailing digits (e.g., us-central1).

5711-5720: nodePoolEmail minLength tightened to 38: LGTM

Matches the shortest valid service account email length.


5605-5733: No action needed — "gcp-" prefix ban is official and correct.

The "gcp-" prefix is reserved by Google for both Workload Identity Pools and Workload Identity Pool Providers, as documented in the official GCP IAM REST API. The validation rules in the YAML correctly prevent users from specifying IDs with this prefix, aligning with actual GCP constraints.

cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-TechPreviewNoUpgrade.crd.yaml (4)

5372-5388: GCP network/subnet name rules + immutability: LGTM

Patterns match GCP naming and immutability is enforced correctly.

Also applies to: 5393-5408


5423-5423: Project/region validation: LGTM

Project ID regex and region pattern (disallowing zone suffix) look correct and constrained appropriately; immutability is set.

Also applies to: 5432-5445


5497-5566: WIF poolID/providerID constraints + immutability: LGTM

Length, charset, reserved prefix, and immutability rules are appropriate.


5568-5612: Service account email regex: LGTM

Pattern matches GSA email rules and bounds look reasonable.

cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-CustomNoUpgrade.crd.yaml (7)

5769-5778: GCP VPC name regex + immutability look correct.

Pattern and object-level immutability align with GCE naming (lowercase, hyphen, <=63). LGTM.

Also applies to: 5782-5784


5790-5798: PSC subnet name validation is consistent and safe.

Same constraints and immutability applied; looks good.

Also applies to: 5803-5805


5818-5821: Project ID regex matches GCP rules.

Length 6–30, starts with letter, no trailing hyphen. Good.


5830-5838: Region pattern covers multi‑segment regions ending with digits.

Blocks zones (e.g., “-a”) as intended. LGTM.


5971-6013: GSA email regexes look solid.

Anchors to RFC‑style SA ID and project ID segments, domain fixed to .iam.gserviceaccount.com, min/max lengths sensible. LGTM.


5908-5927: Code correctly enforces actual Google Cloud constraint.

Google reserves the prefix "gcp-" for use by Google and customer-defined pool/provider IDs must not start with "gcp-". The schema validation is correctly implemented and aligns with the documented WIF/IAM requirement.


6024-6028: Feature-gating correctly implemented—no action required.

Verification confirms the gating is working as intended: workloadIdentity is completely absent from the non-gated hostedclusters-Default.crd.yaml variant and is marked as required only in the gated variants (hostedclusters-TechPreviewNoUpgrade.crd.yaml and hostedclusters-CustomNoUpgrade.crd.yaml). The lines flagged (6024-6028) in CustomNoUpgrade.crd.yaml correctly include workloadIdentity in the required array for that gated variant. No accidental enforcement occurs outside the feature flag.

Comment thread docs/content/reference/api.md Outdated
@apahim

apahim commented Nov 25, 2025

Copy link
Copy Markdown
Contributor Author

/retest

1 similar comment
@apahim

apahim commented Nov 25, 2025

Copy link
Copy Markdown
Contributor Author

/retest

@csrwng csrwng 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.

Same comments as in the original PR
#7251

Comment thread api/hypershift/v1beta1/gcp.go Outdated
Comment thread api/hypershift/v1beta1/gcp_validation_test.go Outdated
Comment thread api/hypershift/v1beta1/gcp.go Outdated
@openshift-ci openshift-ci Bot added the area/testing Indicates the PR includes changes for e2e testing label Nov 26, 2025
Comment thread api/hypershift/v1beta1/gcp.go Outdated

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 4

♻️ Duplicate comments (10)
api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/GCPPlatform.yaml (2)

4867-4996: Add CEL guard ensuring GSAs belong to the configured GCP project.

Validate that serviceAccountsRef.controlPlane and serviceAccountsRef.nodePool domains match .project + ".iam.gserviceaccount.com". Catches fat‑fingered project IDs early.

Apply under .platform.gcp (or inside .platform.gcp.workloadIdentity) as:

+                    x-kubernetes-validations:
+                    - message: serviceAccountsRef emails must belong to the specified GCP project
+                      rule: >-
+                        !has(self.workloadIdentity) ||
+                        !has(self.workloadIdentity.serviceAccountsRef) ||
+                        (
+                          let dom = (self.project + ".iam.gserviceaccount.com");
+                          self.workloadIdentity.serviceAccountsRef.controlPlane.split("@")[1] == dom &&
+                          self.workloadIdentity.serviceAccountsRef.nodePool.split("@")[1] == dom
+                        )

5000-5000: Required workloadIdentity under the GCPPlatform feature gate is OK.

Acknowledging prior thread: since this CRD slice is feature‑gated, requiring it won’t block existing clusters.

docs/content/reference/api.md (2)

6289-6330: Clarify IAM: WorkloadIdentityUser vs ServiceAccountUser.
Add a one‑liner to avoid confusion:

  • If the CAPG controller impersonates the VM GSA via roles/iam.workloadIdentityUser, roles/iam.serviceAccountUser is not required.
  • When using a distinct VM service account, grant roles/iam.serviceAccountUser on that VM SA to the controller GSA to attach it to instances.

Keep roles scoped narrowly and reference your authoritative iam-bindings.json.


6263-6268: Fix broken regex (update source comment, then regenerate).
The “Pattern” shows an HTML anchor, not a regex. Please change the source Go comment (api/hypershift/v1beta1/gcp.go for GCPResourceReference.Name) to wrap the regex in backticks and use the correct expression, then run “make api-docs”.

Suggested source comment line:

// Pattern: `^[a-z]([-a-z0-9]{0,61}[a-z0-9])?$` (max 63 chars), per GCP naming requirements.
cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-CustomNoUpgrade.crd.yaml (2)

5842-5893: Enforce unique label keys and clarify reserved prefix wording

  • Recommend list-map semantics to prevent duplicate label keys and ensure stable SSA merges.
  • The message says GCP reserves 'goog' prefix; if the stricter-than-GCP ban on any 'goog*' is intentional, adjust the text to explicitly say it’s an intentional HyperShift restriction to avoid collisions.

Suggested schema additions:

 resourceLabels:
   maxItems: 60
   type: array
+  x-kubernetes-list-type: map
+  x-kubernetes-list-map-keys:
+  - key

Optionally, update the key doc string to: “We intentionally reserve any key starting with ‘goog’ to avoid collisions with Google-reserved labels.”


6027-6027: workloadIdentity required in gated CRD: acknowledged

Required here is fine if this manifest is only served under the CustomNoUpgrade feature gate and non-gated CRDs don’t require it. No action if that remains true.

cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-TechPreviewNoUpgrade.crd.yaml (1)

5554-5604: Enforce unique label keys for resourceLabels

Duplicate keys create last-write-wins ambiguity and drift when syncing to GCP. Make the list a keyed map by "key":

 resourceLabels:
   items:
     properties:
       key:
         ...
       value:
         ...
     required:
     - key
     - value
     type: object
   maxItems: 60
-  type: array
+  type: array
+  x-kubernetes-list-map-keys:
+  - key
+  x-kubernetes-list-type: map
cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-TechPreviewNoUpgrade.crd.yaml (1)

5445-5495: Enforce unique label keys; narrow reserved prefix to 'goog-'.

  • Keys aren’t enforced unique; duplicates can lead to last-write-wins ambiguity. Add a CEL array-level rule.
  • Reserved-prefix check currently blocks any key starting with "goog", which is broader than the documented "goog-" reservation. Narrowing avoids false rejections.

Apply this diff:

 resourceLabels:
   description: |-
@@
-  items:
+  x-kubernetes-validations:
+  - message: resourceLabels keys must be unique
+    rule: 'self.all(l, self.exists_one(x, x.key == l.key))'
+  items:
@@
       key:
@@
-        x-kubernetes-validations:
-        - message: Label keys starting with the reserved 'goog'
-            prefix are not allowed
-          rule: '!self.startsWith(''goog'')'
+        x-kubernetes-validations:
+        - message: Label keys starting with the reserved 'goog-' prefix are not allowed
+          rule: '!self.startsWith(''goog-'')'
api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/GCPPlatform.yaml (1)

4707-4757: Resource labels schema looks good.

  • RFC1035-style keys/values for Compute Engine.
  • Reserved 'goog' prefix blocked.
  • Capacity capped at 60 to leave headroom.

No further action from my side given prior decision to keep a plain list.

cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-CustomNoUpgrade.crd.yaml (1)

5734-5785: Prevent duplicate resource label keys (array-level uniqueness)

Duplicate keys are still possible; add a CEL validation at the array level to enforce uniqueness without changing list semantics.

Apply:

 resourceLabels:
   description: |-
@@
   items:
     ...
   maxItems: 60
   type: array
+  x-kubernetes-validations:
+  - message: resourceLabels keys must be unique
+    rule: self == null || self.all(l1, self.exists_one(l2, l1.key == l2.key))
🧹 Nitpick comments (4)
api/hypershift/v1beta1/gcp_validation_test.go (1)

9-107: Tests don’t exercise the actual validation logic

Both TestGCPResourceLabel and TestGCPRegionPattern only assert that Key/region are non-empty, so they will succeed even if the underlying regex/CEL rules on GCPResourceLabel and GCP region fields are misconfigured. This gives very weak signal compared to the e2e/API UX tests that already hit the real CRD validations.

Consider either:

  • Reworking these tests to actually drive objects through the same validation path the API server uses (or at least validate against the generated schema), or
  • Removing this file and relying on the stronger coverage in test/e2e/v2/tests/api_ux_validation_test.go.
cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-TechPreviewNoUpgrade.crd.yaml (1)

5540-5549: Optional: tighten region regex to allow digits only in the last segment

Current pattern permits digits in earlier segments. If you want to model GCP regions more closely, prefer a pattern where only the final segment ends with digits, e.g.:

  • ^[a-z]+(?:-[a-z]+)+[0-9]+$

Purely optional; the existing rule is acceptable.

cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-TechPreviewNoUpgrade.crd.yaml (1)

5497-5626: Guard against reusing the same GSA for controlPlane and nodePool.

Recommend a CEL check to prevent misconfiguration:

           serviceAccountsRef:
             description: |-
@@
             type: object
+            x-kubernetes-validations:
+            - message: controlPlane and nodePool service accounts must be different
+              rule: self.controlPlane != self.nodePool
cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-CustomNoUpgrade.crd.yaml (1)

5916-5921: Cross-field guard: SA email domain should match project ID

Add a CEL to ensure controlPlane/nodePool GSAs belong to the same project as spec.platform.gcp.project; avoids subtle misconfig.

Apply near the gcp object (after required/type):

   required:
   - networkConfig
   - project
   - region
   - workloadIdentity
   type: object
+  x-kubernetes-validations:
+  - message: serviceAccountsRef emails must match the GCP project ID
+    rule: has(self.workloadIdentity) && has(self.workloadIdentity.serviceAccountsRef) ?
+          (self.workloadIdentity.serviceAccountsRef.controlPlane.split('@', 2)[1] ==
+             (self.project + ".iam.gserviceaccount.com") &&
+           self.workloadIdentity.serviceAccountsRef.nodePool.split('@', 2)[1] ==
+             (self.project + ".iam.gserviceaccount.com")) : true
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to Reviews -> Disable Knowledge Base setting

📥 Commits

Reviewing files that changed from the base of the PR and between f85702a and c89bedf.

⛔ Files ignored due to path filters (4)
  • vendor/github.com/openshift/hypershift/api/hypershift/v1beta1/gcp.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/openshift/hypershift/api/hypershift/v1beta1/hostedcluster_conditions.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/openshift/hypershift/api/hypershift/v1beta1/hostedcluster_types.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/openshift/hypershift/api/hypershift/v1beta1/zz_generated.deepcopy.go is excluded by !vendor/**, !**/vendor/**
📒 Files selected for processing (22)
  • api/go.mod (1 hunks)
  • api/hypershift/v1beta1/gcp.go (4 hunks)
  • api/hypershift/v1beta1/gcp_validation_test.go (1 hunks)
  • api/hypershift/v1beta1/hostedcluster_conditions.go (1 hunks)
  • api/hypershift/v1beta1/hostedcluster_types.go (1 hunks)
  • api/hypershift/v1beta1/zz_generated.deepcopy.go (4 hunks)
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/GCPPlatform.yaml (3 hunks)
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/GCPPlatform.yaml (3 hunks)
  • client/applyconfiguration/hypershift/v1beta1/gcpplatformspec.go (2 hunks)
  • client/applyconfiguration/hypershift/v1beta1/gcpresourcelabel.go (1 hunks)
  • client/applyconfiguration/hypershift/v1beta1/gcpserviceaccountsref.go (1 hunks)
  • client/applyconfiguration/hypershift/v1beta1/gcpworkloadidentityconfig.go (1 hunks)
  • client/applyconfiguration/utils.go (1 hunks)
  • cmd/cluster/gcp/create.go (4 hunks)
  • cmd/cluster/gcp/create_test.go (3 hunks)
  • cmd/cluster/gcp/testdata/zz_fixture_TestCreateCluster_minimal_flags_necessary_to_render.yaml (1 hunks)
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-CustomNoUpgrade.crd.yaml (3 hunks)
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-TechPreviewNoUpgrade.crd.yaml (3 hunks)
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-CustomNoUpgrade.crd.yaml (3 hunks)
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-TechPreviewNoUpgrade.crd.yaml (3 hunks)
  • docs/content/reference/api.md (5 hunks)
  • test/e2e/v2/tests/api_ux_validation_test.go (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • api/hypershift/v1beta1/hostedcluster_types.go
  • client/applyconfiguration/utils.go
  • api/hypershift/v1beta1/hostedcluster_conditions.go
🧰 Additional context used
📓 Path-based instructions (1)
**

⚙️ CodeRabbit configuration file

-Focus on major issues impacting performance, readability, maintainability and security. Avoid nitpicks and avoid verbosity.

Files:

  • client/applyconfiguration/hypershift/v1beta1/gcpresourcelabel.go
  • client/applyconfiguration/hypershift/v1beta1/gcpplatformspec.go
  • client/applyconfiguration/hypershift/v1beta1/gcpserviceaccountsref.go
  • test/e2e/v2/tests/api_ux_validation_test.go
  • api/hypershift/v1beta1/gcp_validation_test.go
  • api/go.mod
  • client/applyconfiguration/hypershift/v1beta1/gcpworkloadidentityconfig.go
  • cmd/cluster/gcp/create.go
  • api/hypershift/v1beta1/zz_generated.deepcopy.go
  • cmd/cluster/gcp/create_test.go
  • cmd/cluster/gcp/testdata/zz_fixture_TestCreateCluster_minimal_flags_necessary_to_render.yaml
  • api/hypershift/v1beta1/gcp.go
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-TechPreviewNoUpgrade.crd.yaml
  • docs/content/reference/api.md
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/GCPPlatform.yaml
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-TechPreviewNoUpgrade.crd.yaml
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-CustomNoUpgrade.crd.yaml
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-CustomNoUpgrade.crd.yaml
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/GCPPlatform.yaml
🧬 Code graph analysis (8)
client/applyconfiguration/hypershift/v1beta1/gcpplatformspec.go (4)
client/applyconfiguration/hypershift/v1beta1/gcpnetworkconfig.go (1)
  • GCPNetworkConfigApplyConfiguration (22-25)
api/hypershift/v1beta1/gcp.go (1)
  • GCPEndpointAccessType (58-58)
client/applyconfiguration/hypershift/v1beta1/gcpresourcelabel.go (1)
  • GCPResourceLabelApplyConfiguration (22-25)
client/applyconfiguration/hypershift/v1beta1/gcpworkloadidentityconfig.go (1)
  • GCPWorkloadIdentityConfigApplyConfiguration (22-27)
test/e2e/v2/tests/api_ux_validation_test.go (2)
test/e2e/util/crd.go (1)
  • HasFieldInCRDSchema (15-38)
hypershift-operator/controllers/hostedcluster/internal/platform/gcp/gcp.go (1)
  • GCP (34-34)
api/hypershift/v1beta1/gcp_validation_test.go (1)
api/hypershift/v1beta1/gcp.go (1)
  • GCPResourceLabel (23-54)
client/applyconfiguration/hypershift/v1beta1/gcpworkloadidentityconfig.go (1)
client/applyconfiguration/hypershift/v1beta1/gcpserviceaccountsref.go (1)
  • GCPServiceAccountsRefApplyConfiguration (22-25)
cmd/cluster/gcp/create.go (2)
cmd/util/util.go (1)
  • ValidateRequiredOption (11-16)
support/globalconfig/network.go (1)
  • NetworkConfig (23-29)
api/hypershift/v1beta1/zz_generated.deepcopy.go (1)
api/hypershift/v1beta1/gcp.go (3)
  • GCPResourceLabel (23-54)
  • GCPServiceAccountsRef (228-268)
  • GCPWorkloadIdentityConfig (162-224)
cmd/cluster/gcp/create_test.go (1)
cmd/cluster/gcp/create.go (2)
  • RawCreateOptions (31-58)
  • CreateOptions (127-130)
api/hypershift/v1beta1/gcp.go (2)
test/e2e/util/external_oidc.go (1)
  • Key (289-292)
client/applyconfiguration/hypershift/v1beta1/gcpresourcereference.go (1)
  • GCPResourceReference (28-30)
🔇 Additional comments (47)
api/go.mod (1)

10-10: LGTM: Dependency promotion aligns with new validation code.

Promoting k8s.io/utils to a direct dependency is appropriate given the PR introduces comprehensive validation rules that likely leverage utilities from this package.

client/applyconfiguration/hypershift/v1beta1/gcpresourcelabel.go (1)

1-47: LGTM: Standard auto-generated apply configuration.

The generated apply configuration follows Kubernetes patterns correctly with appropriate fluent builders for the GCPResourceLabel type.

client/applyconfiguration/hypershift/v1beta1/gcpserviceaccountsref.go (1)

1-47: LGTM: Standard auto-generated apply configuration.

The generated apply configuration follows Kubernetes patterns correctly with appropriate fluent builders for the GCPServiceAccountsRef type.

api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/GCPPlatform.yaml (4)

4742-4757: Network name regex + immutability look correct.

Pattern matches GCP constraints and the field is immutable. LGTM.


4763-4778: PSC subnet name regex + immutability look correct.

Matches GCP naming and locks day‑2 changes. LGTM.


4793-4793: Project ID pattern is appropriate.

6–30 chars, starts with letter, hyphens allowed (not trailing). LGTM.


4803-4811: Region pattern is reasonable and excludes zones.

Requires hyphenated segments and trailing digits (e.g., us-central1). LGTM.

cmd/cluster/gcp/testdata/zz_fixture_TestCreateCluster_minimal_flags_necessary_to_render.yaml (1)

42-53: GCP fixture values align with new WIF and network validations

The network/PSC subnet names, projectNumber, pool/provider IDs, and service account emails all look consistent with the new GCP validation rules and are reasonable choices for the minimal render fixture.

test/e2e/v2/tests/api_ux_validation_test.go (1)

343-672: Comprehensive WIF + GCP label e2e coverage looks good

The new GCP WIF context cleanly follows existing API UX patterns and exercises the important success and failure paths (projectNumber, reserved pool/provider prefixes, SA email formats, label semantics, and max-count). The struct setup is a bit repetitive but consistent with the rest of the file and acceptable for these scenario tests.

docs/content/reference/api.md (4)

5038-5048: LGTM: new GCP condition types read clearly and match intent.


5954-5959: LGTM: region format guidance is accurate and blocks zones.
Examples and constraints align with GCP regions.


5991-6030: WIF prerequisites are good; keep the “immutable after creation” note.
No changes requested.


6181-6236: LGTM: label rules reflect Compute Engine (RFC1035) constraints and ‘goog’ reserve.
Clear and actionable.

cmd/cluster/gcp/create.go (4)

18-28: LGTM - Flag constants follow conventions.

The new flag constants are well-named and consistent with the existing codebase patterns.


37-58: LGTM - New fields are well-documented.

The new RawCreateOptions fields have clear documentation and appropriate types.


93-113: LGTM - Required validation is appropriate for WIF setup.

All new fields are validated as required, which is appropriate since Workload Identity Federation needs complete configuration. Since GCP support is feature-gated, this won't impact existing clusters.


181-198: LGTM - Platform specifics correctly populated.

The CLI options are properly mapped to the GCPPlatformSpec fields, including NetworkConfig and WorkloadIdentity configuration.

client/applyconfiguration/hypershift/v1beta1/gcpplatformspec.go (1)

27-32: LGTM - Generated apply configuration code is correct.

The builder methods for ResourceLabels and WorkloadIdentity follow the standard apply configuration pattern with appropriate nil handling and method chaining.

Also applies to: 73-92

cmd/cluster/gcp/create_test.go (1)

29-59: LGTM - Comprehensive test coverage for new fields.

The tests thoroughly validate the new WIF and networking fields, including positive cases, validation of missing required fields, and end-to-end CLI flag rendering.

Also applies to: 65-96, 136-146

client/applyconfiguration/hypershift/v1beta1/gcpworkloadidentityconfig.go (1)

1-65: LGTM - Generated apply configuration follows standard patterns.

The GCPWorkloadIdentityConfig apply configuration correctly implements the builder pattern for all fields with proper method chaining.

api/hypershift/v1beta1/zz_generated.deepcopy.go (1)

1488-1495: LGTM - Generated deepcopy code correctly handles new types.

The deepcopy implementations properly handle the ResourceLabels slice with per-element copying, and correctly manage the pointer field in GCPResourceLabel.Value.

Also applies to: 1614-1678

api/hypershift/v1beta1/gcp.go (5)

7-17: LGTM - Updated resource name pattern is more precise.

The updated pattern ^[a-z]([-a-z0-9]*[a-z0-9])?$ correctly enforces GCP resource naming requirements: must start with lowercase letter and end with lowercase letter or digit.


74-82: LGTM - Immutability correctly enforced on network configuration.

The Network and PrivateServiceConnectSubnet fields are properly marked as immutable with XValidation rules, preventing changes after cluster creation.


86-157: LGTM - GCPPlatformSpec additions are well-designed.

The updated validation patterns for Project and Region are more precise and match GCP requirements. The new ResourceLabels field with MaxItems=60 appropriately reserves space for system labels. The WorkloadIdentity field is correctly marked as required and immutable, which is appropriate for feature-gated WIF support.


159-224: LGTM - GCPWorkloadIdentityConfig validation is comprehensive.

The validation rules are thorough:

  • ProjectNumber enforces numeric format (up to 25 digits)
  • PoolID and ProviderID correctly block the reserved gcp- prefix
  • All fields properly marked as immutable
  • Patterns enforce GCP naming requirements

226-268: LGTM - Service account email validation is appropriate.

The regex pattern correctly validates Google Service Account email format. The MinLength=38 is conservatively set (pattern minimum is 37) which is safe. Immutability markers are appropriate since changing service accounts would break WIF authentication.

cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-CustomNoUpgrade.crd.yaml (4)

5769-5785: GCP network name regex/immutability: LGTM

Pattern and immutability match GCP naming rules; no issues.


5791-5805: GCP subnet name regex/immutability: LGTM

Consistent with Compute Engine naming and safe to make immutable.


5820-5821: Project ID regex: LGTM

Matches documented constraints (start letter, a–z/0–9/-, 6–30 chars, no trailing hyphen).


5830-5837: Region format regex: LGTM

Enforces hyphenated segments and numeric suffix (e.g., us-central1); excludes zones as intended.

cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-TechPreviewNoUpgrade.crd.yaml (5)

5480-5496: LGTM: strict RFC1035-style VPC network name + immutability

The regex and immutability guard look correct and align with GCP naming.


5501-5516: LGTM: strict PSC subnet name + immutability

Consistent with GCP constraints; good to lock the object atomically.


5531-5535: LGTM: project ID regex and immutability

Pattern matches GCP rules (6–30, lowercase, hyphens, no trailing hyphen) and locking is appropriate.


5618-5674: Remove the request for verification—the "gcp-" prefix validation is correct per Google Cloud's official documentation.

According to Google Cloud's official IAM documentation and gcloud CLI references, the "gcp-" prefix is explicitly reserved for Workload Identity Pool IDs and Provider IDs. This restriction is documented in the gcloud IAM workload-identity-pools API reference and applies to both pool and provider identifiers. The validation rules in the CRD correctly enforce this constraint and should remain.


5726-5734: workloadIdentity immutability enforced — verify CLI/e2e populate all required fields

GCP Workload Identity constraints confirm the concern: pool ID, provider ID, and numeric project number are immutable post-creation and must be supplied at cluster creation. The CRD correctly enforces this with the immutability rule self == oldSelf.

However, direct verification of whether CLI, e2e tests, and examples actually populate all required fields (poolID, projectNumber, providerID, and both service account emails) at creation could not be completed due to repository access constraints. Manual code review is recommended to confirm that all HostedCluster creation paths for GCP properly initialize the complete workloadIdentity object to avoid schema validation failures.

cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-TechPreviewNoUpgrade.crd.yaml (5)

5372-5387: Network name regex + immutability look good.

Pattern matches GCP constraints and object immutability is appropriate.


5393-5408: PSC subnet name regex + immutability look good.

Consistent with Compute Engine naming and day-2 immutability.


5423-5423: Project ID validation looks correct.

Regex and length bounds align with GCP rules.


5432-5444: Region validation is sensible.

Pattern allows hyphenated regions ending in digits and rejects zone suffices; immutability OK.


5630-5631: Required WIF field looks correct.

Requiring workloadIdentity under GCP is consistent with the new API surface.

api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/GCPPlatform.yaml (6)

4634-4649: GCP network name regex + immutability look correct.

RFC1035-style pattern and object-level immutability are appropriate for VPC names.


4655-4670: PSC subnet name regex + immutability look correct.

Consistent with GCP naming constraints and day-2 stability.


4685-4685: Project ID pattern tightened appropriately.

6–30 chars, start letter, end alnum, hyphens allowed — matches GCP rules.


4694-4706: Region validation is solid.

Pattern excludes zones and enforces trailing digits (e.g., us-central1, europe-west12). Immutability OK.


4759-4887: WIF block generally looks tight.

Pool/provider ID rules, reserved-prefix guards, and object immutability are appropriate.


4892-4893: Confirm intent: workloadIdentity is required for all GCP clusters.

Making workloadIdentity mandatory is a schema hard-requirement that blocks objects lacking it (and may affect upgrades of existing objects once touched). If that’s intentional for the GCP feature-gated path, all good; otherwise consider making it optional with CEL to validate internals when present.

cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-CustomNoUpgrade.crd.yaml (1)

5808-5855: Good fix on pool/provider IDs and immutability

Leading-letter regex and 'gcp-' prefix block align with IAM WIF rules; field/object immutability is appropriate.

Comment thread api/hypershift/v1beta1/gcp.go

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 3

♻️ Duplicate comments (9)
docs/content/reference/api.md (1)

6263-6268: Fix invalid regex (HTML anchor rendered as “Pattern”). Regenerate docs from Go comment.

Pattern line shows an HTML link instead of a usable regex. Replace with the correct RFC1035‑style regex and wrap it in backticks in the Go source for GCPResourceReference.Name, then run make api-docs.

Apply in Go comment (not directly in this generated file):

-// Pattern: "^<a href="[-a-z0-9]*[a-z0-9]">a-z</a>?$" (max 63 chars), per GCP naming requirements.
+// Pattern: `^[a-z]([-a-z0-9]{0,61}[a-z0-9])?$` (max 63 chars), per GCP naming requirements.

This ensures the rendered docs show a copy/paste‑able regex and keep “Must start with a lowercase letter, end with a letter or digit.” intact.

api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/GCPPlatform.yaml (1)

4867-4996: Tie GSA domain to the configured project to catch typos.

Add a cross-field CEL guard ensuring serviceAccountsRef.{controlPlane,nodePool} belong to .project.

   gcp:
     type: object
     properties:
       ...
     required:
       - networkConfig
       - project
       - region
       - workloadIdentity
+    x-kubernetes-validations:
+    - message: controlPlane and nodePool GSAs must belong to the specified GCP project
+      rule: >-
+        !has(self.workloadIdentity) || !has(self.workloadIdentity.serviceAccountsRef) ||
+        (
+          self.workloadIdentity.serviceAccountsRef.controlPlane.split("@")[1] ==
+          (self.project + ".iam.gserviceaccount.com")
+          &&
+          self.workloadIdentity.serviceAccountsRef.nodePool.split("@")[1] ==
+          (self.project + ".iam.gserviceaccount.com")
+        )
cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-CustomNoUpgrade.crd.yaml (2)

5842-5892: Enforce unique label keys with list-map semantics (non-breaking, improves SSA merges).

Recommend treating resourceLabels as a map keyed by "key" to reject duplicates and get stable apply behavior.

 resourceLabels:
   maxItems: 60
   type: array
+  x-kubernetes-list-type: map
+  x-kubernetes-list-map-keys:
+  - key
   items:
     type: object

5870-5873: If broader 'goog' reservation is intentional, clarify in description.

Keep the stricter check, but add a note that any key starting with "goog" is intentionally reserved to avoid collisions with Google labels. This avoids user confusion when GCP docs mention "goog-".

cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-TechPreviewNoUpgrade.crd.yaml (2)

5738-5739: Required workloadIdentity — ensure all create paths populate it

This is required and immutable. Please confirm CLI/e2e/examples set spec.platform.gcp.workloadIdentity fields at creation to avoid schema failures.

You can quick-check with:

#!/bin/bash
# Find GCP create paths that set workloadIdentity in HostedCluster specs
rg -nP --type go --type yaml -g '!**/vendor/**' \
  'spec\.platform\.gcp\.workloadIdentity|poolID|providerID|projectNumber|serviceAccountsRef' \
  cmd/cluster docs examples test || true

5554-5604: Enforce unique label keys and stable merge semantics for resourceLabels

Allowing duplicates enables last-write-wins ambiguity. Make this a list‑map keyed by “key” to enforce uniqueness and better SSA/merge behavior.

Apply:

 resourceLabels:
   items:
     properties:
       key:
         ...
       value:
         ...
     required:
     - key
     - value
     type: object
   maxItems: 60
-  type: array
+  type: array
+  x-kubernetes-list-map-keys:
+  - key
+  x-kubernetes-list-type: map

Optional (belt-and-suspenders) CEL uniqueness check if list-map isn’t feasible now:

+  x-kubernetes-validations:
+  - message: resourceLabels.keys must be unique
+    rule: self.map(l, l.key).isUnique()
cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-TechPreviewNoUpgrade.crd.yaml (1)

5445-5495: Enforce unique label keys; narrow reserved prefix; keep headroom.

  • Keys aren’t unique today; duplicates can lead to last-write-wins ambiguity across reconcilers. Add a CEL array-level rule to ensure uniqueness by key while preserving list semantics. Google’s guidance also expects keys to be unique per resource. (docs.cloud.google.com)
  • Consider narrowing the reserved rule from any key starting with “goog” to the documented “goog-” system-prefixed family (e.g., goog-dataproc-…), to avoid blocking benign keys like “google-…”. (cloud.google.com)

Apply this focused diff under spec.platform.gcp.resourceLabels:

 resourceLabels:
   description: |-
     resourceLabels are applied to all GCP resources created for the cluster.
     ...
+  x-kubernetes-validations:
+  - message: resourceLabels keys must be unique
+    rule: "self.all(l, self.exists_one(x, x.key == l.key))"
   items:
     description: |-
       GCPResourceLabel is a label to apply to GCP resources created for the cluster.
     ...
     properties:
       key:
         ...
-        x-kubernetes-validations:
-        - message: Label keys starting with the reserved 'goog' prefix are not allowed
-          rule: '!self.startsWith(''goog'')'
+        x-kubernetes-validations:
+        - message: Label keys starting with the reserved 'goog-' prefix are not allowed
+          rule: "!self.startsWith('goog-')"
     ...
   maxItems: 60
   type: array

Would you like me to mirror the same uniqueness rule in the non-TechPreview CRDs for parity?

cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-CustomNoUpgrade.crd.yaml (1)

5734-5784: Enforce unique resourceLabels keys (avoid dup key last-write-wins).

Duplicate label keys can slip through; enforce uniqueness at the array level with CEL to prevent ambiguous updates.

Apply:

                       resourceLabels:
                         description: |-
@@
                         maxItems: 60
                         type: array
+                        x-kubernetes-validations:
+                        - message: resourceLabels keys must be unique
+                          rule: self == null || self.all(l1, self.exists_one(l2, l1.key == l2.key))
api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/GCPPlatform.yaml (1)

4708-4757: Clarify duplicate label-key behavior (doc-only).

Because resourceLabels remains an array, duplicate keys can be supplied. Consider adding a brief note in the field description stating how duplicates are handled (e.g., “last-wins” on apply) to avoid user surprises.

🧹 Nitpick comments (8)
cmd/cluster/gcp/create_test.go (1)

77-101: Consider adding negative test cases for other required fields.

Currently only missing project, missing region, and missing network are tested. For completeness, consider adding test cases for the other required fields (e.g., WorkloadIdentityProjectNumber, NodePoolServiceAccount). This is optional since the validation logic is uniform.

docs/content/reference/api.md (3)

5991-6008: Tighten label quota wording; cross‑reference constraints.

Replace “reserves approximately 4 labels” with “reserves up to 4 labels” and add a pointer that keys/values must follow GCPResourceLabel rules to avoid surprises.

- HyperShift reserves approximately 4 labels for system use.
+ HyperShift reserves up to 4 labels for system use.
+ See GCPResourceLabel for key/value character and length constraints.

6010-6031: WIF prerequisites: add member principal variants (subject vs principalSet) for clarity.

Consider noting both Google IAM member forms commonly used with WIF:

  • principal://…/subject/
  • principalSet://…/attribute./

This helps users match their provider attribute mapping. No behavior change.


6187-6214: Optional: include copy/paste‑able regex snippets for label key/value.

Adding explicit regex (in backticks) alongside the prose improves usability and aligns with other sections that show patterns.

Also applies to: 6225-6232

api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/GCPPlatform.yaml (1)

4816-4865: Enforce unique label keys to prevent duplicate labels.

Add a CEL rule so duplicate keys in spec.platform.gcp.resourceLabels are rejected early.

   resourceLabels:
     ...
-    maxItems: 60
-    type: array
+    maxItems: 60
+    type: array
+    x-kubernetes-validations:
+    - message: duplicate label keys are not allowed
+      rule: self.all(x, self.filter(y, y.key == x.key).size() <= 1)
cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-CustomNoUpgrade.crd.yaml (1)

5970-6013: Add cross-field CEL: ensure GSA emails match spec.gcp.project.

Prevent misconfig by asserting both serviceAccountsRef emails are in the same project declared in spec.gcp.project.

   gcp:
     properties:
       project:
         ...
+    x-kubernetes-validations:
+    - message: controlPlane GSA must belong to the same project as spec.platform.gcp.project
+      rule: '!has(self.workloadIdentity) || !has(self.workloadIdentity.serviceAccountsRef) || self.workloadIdentity.serviceAccountsRef.controlPlane.split("@", 2)[1] == self.project + ".iam.gserviceaccount.com"'
+    - message: nodePool GSA must belong to the same project as spec.platform.gcp.project
+      rule: '!has(self.workloadIdentity) || !has(self.workloadIdentity.serviceAccountsRef) || self.workloadIdentity.serviceAccountsRef.nodePool.split("@", 2)[1] == self.project + ".iam.gserviceaccount.com"'
cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-TechPreviewNoUpgrade.crd.yaml (2)

5619-5639: Verify “gcp-” reserved prefix for poolID

The validation blocks poolID starting with “gcp-”. If this isn’t a documented reservation, this may reject valid pools. Please confirm and, if not reserved, drop the check.

Would you like me to remove the rule or gate it behind a feature flag if unverified?


5655-5674: Verify “gcp-” reserved prefix for providerID

Same concern as poolID. Confirm reservation or remove to avoid false negatives.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to Reviews -> Disable Knowledge Base setting

📥 Commits

Reviewing files that changed from the base of the PR and between f85702a and c89bedf.

⛔ Files ignored due to path filters (4)
  • vendor/github.com/openshift/hypershift/api/hypershift/v1beta1/gcp.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/openshift/hypershift/api/hypershift/v1beta1/hostedcluster_conditions.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/openshift/hypershift/api/hypershift/v1beta1/hostedcluster_types.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/openshift/hypershift/api/hypershift/v1beta1/zz_generated.deepcopy.go is excluded by !vendor/**, !**/vendor/**
📒 Files selected for processing (22)
  • api/go.mod (1 hunks)
  • api/hypershift/v1beta1/gcp.go (4 hunks)
  • api/hypershift/v1beta1/gcp_validation_test.go (1 hunks)
  • api/hypershift/v1beta1/hostedcluster_conditions.go (1 hunks)
  • api/hypershift/v1beta1/hostedcluster_types.go (1 hunks)
  • api/hypershift/v1beta1/zz_generated.deepcopy.go (4 hunks)
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/GCPPlatform.yaml (3 hunks)
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/GCPPlatform.yaml (3 hunks)
  • client/applyconfiguration/hypershift/v1beta1/gcpplatformspec.go (2 hunks)
  • client/applyconfiguration/hypershift/v1beta1/gcpresourcelabel.go (1 hunks)
  • client/applyconfiguration/hypershift/v1beta1/gcpserviceaccountsref.go (1 hunks)
  • client/applyconfiguration/hypershift/v1beta1/gcpworkloadidentityconfig.go (1 hunks)
  • client/applyconfiguration/utils.go (1 hunks)
  • cmd/cluster/gcp/create.go (4 hunks)
  • cmd/cluster/gcp/create_test.go (3 hunks)
  • cmd/cluster/gcp/testdata/zz_fixture_TestCreateCluster_minimal_flags_necessary_to_render.yaml (1 hunks)
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-CustomNoUpgrade.crd.yaml (3 hunks)
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-TechPreviewNoUpgrade.crd.yaml (3 hunks)
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-CustomNoUpgrade.crd.yaml (3 hunks)
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-TechPreviewNoUpgrade.crd.yaml (3 hunks)
  • docs/content/reference/api.md (5 hunks)
  • test/e2e/v2/tests/api_ux_validation_test.go (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (6)
  • api/hypershift/v1beta1/hostedcluster_conditions.go
  • client/applyconfiguration/hypershift/v1beta1/gcpplatformspec.go
  • api/hypershift/v1beta1/gcp_validation_test.go
  • api/hypershift/v1beta1/hostedcluster_types.go
  • cmd/cluster/gcp/testdata/zz_fixture_TestCreateCluster_minimal_flags_necessary_to_render.yaml
  • client/applyconfiguration/utils.go
🧰 Additional context used
📓 Path-based instructions (1)
**

⚙️ CodeRabbit configuration file

-Focus on major issues impacting performance, readability, maintainability and security. Avoid nitpicks and avoid verbosity.

Files:

  • client/applyconfiguration/hypershift/v1beta1/gcpworkloadidentityconfig.go
  • client/applyconfiguration/hypershift/v1beta1/gcpresourcelabel.go
  • cmd/cluster/gcp/create.go
  • client/applyconfiguration/hypershift/v1beta1/gcpserviceaccountsref.go
  • api/hypershift/v1beta1/zz_generated.deepcopy.go
  • test/e2e/v2/tests/api_ux_validation_test.go
  • api/hypershift/v1beta1/gcp.go
  • api/go.mod
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/GCPPlatform.yaml
  • cmd/cluster/gcp/create_test.go
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-TechPreviewNoUpgrade.crd.yaml
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-TechPreviewNoUpgrade.crd.yaml
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-CustomNoUpgrade.crd.yaml
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-CustomNoUpgrade.crd.yaml
  • docs/content/reference/api.md
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/GCPPlatform.yaml
🧬 Code graph analysis (5)
client/applyconfiguration/hypershift/v1beta1/gcpworkloadidentityconfig.go (1)
client/applyconfiguration/hypershift/v1beta1/gcpserviceaccountsref.go (1)
  • GCPServiceAccountsRefApplyConfiguration (22-25)
api/hypershift/v1beta1/zz_generated.deepcopy.go (1)
api/hypershift/v1beta1/gcp.go (3)
  • GCPResourceLabel (23-54)
  • GCPServiceAccountsRef (228-268)
  • GCPWorkloadIdentityConfig (162-224)
test/e2e/v2/tests/api_ux_validation_test.go (2)
test/e2e/util/crd.go (1)
  • HasFieldInCRDSchema (15-38)
hypershift-operator/controllers/hostedcluster/internal/platform/gcp/gcp.go (1)
  • GCP (34-34)
api/hypershift/v1beta1/gcp.go (1)
client/applyconfiguration/hypershift/v1beta1/gcpresourcereference.go (1)
  • GCPResourceReference (28-30)
cmd/cluster/gcp/create_test.go (2)
support/globalconfig/network.go (1)
  • NetworkConfig (23-29)
cmd/cluster/gcp/create.go (2)
  • RawCreateOptions (31-58)
  • CreateOptions (127-130)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: Red Hat Konflux / hypershift-release-mce-211-on-pull-request
  • GitHub Check: Red Hat Konflux / hypershift-operator-main-on-pull-request
  • GitHub Check: Red Hat Konflux / hypershift-cli-mce-211-on-pull-request
🔇 Additional comments (47)
client/applyconfiguration/hypershift/v1beta1/gcpserviceaccountsref.go (1)

1-47: LGTM!

Auto-generated apply configuration follows the standard pattern with proper fluent builder methods.

cmd/cluster/gcp/create.go (3)

18-28: LGTM!

New flag constants are well-named and follow the existing naming convention.


93-113: Verify that all new flags should be required.

All seven new flags are marked as required, which is a breaking change for existing GCP cluster creation workflows. Please confirm this is intentional — users will now need to provide --network, --private-service-connect-subnet, and all workload identity flags to create GCP clusters.


175-202: LGTM!

The ApplyPlatformSpecifics function correctly maps CLI options to the GCPPlatformSpec structure, including the nested NetworkConfig and WorkloadIdentity fields.

client/applyconfiguration/hypershift/v1beta1/gcpworkloadidentityconfig.go (1)

1-65: LGTM!

Auto-generated apply configuration correctly composes with GCPServiceAccountsRefApplyConfiguration and follows the standard fluent builder pattern.

cmd/cluster/gcp/create_test.go (2)

22-60: LGTM!

Test coverage for ApplyPlatformSpecifics comprehensively validates all new fields are correctly mapped to the HostedCluster spec.


130-150: LGTM!

Integration test correctly includes all new required CLI flags and validates the complete rendering flow.

test/e2e/v2/tests/api_ux_validation_test.go (2)

343-672: LGTM!

Comprehensive E2E validation coverage for GCP Workload Identity Federation, including edge cases for reserved prefixes, format validation, and constraint boundaries.


1952-1964: LGTM!

Helper function encapsulates common test pattern cleanly. The dual cleanup (defer + explicit delete) is documented and ensures resource cleanup in all scenarios.

client/applyconfiguration/hypershift/v1beta1/gcpresourcelabel.go (1)

20-47: Generated apply configuration for GCPResourceLabel looks correct

The struct shape and fluent builder methods follow the standard applyconfiguration-gen pattern and correctly model the key/value fields; no issues from a correctness or maintainability standpoint.

docs/content/reference/api.md (4)

5954-5959: I'll help verify that the region validation documentation matches the actual implementation. Let me search for the GCPPlatformSpec region validation logic.
<function_calls>

#!/bin/bash

Find GCPPlatformSpec and region validation rules

Search in Go files first

rg -nP -C3 'GCPPlatformSpec' --type go | head -50

Then search for region validation patterns

rg -nP 'region.pattern|x-kubernetes-validations' -g '**/.yaml' | head -50


</function_calls>

<function_calls>

#!/bin/bash

Find CRD and API definition files

fd -e yaml -e yml | grep -i 'crd|openapi' | head -20


</function_calls>

<function_calls>

#!/bin/bash

Broader search for GCPPlatformSpec

rg 'GCPPlatformSpec' -l | head -10


</function_calls>


6316-6324: Based on my web search, I can confirm that the review comment's concern appears valid. Here's why:

Key Finding: roles/iam.serviceAccountUser is specifically for attaching/using a pre-existing service account on resources. It does not grant permissions to:

  • Create or manage service accounts
  • Mint short-lived credentials
  • Impersonate via API or CLI (requires roles/iam.serviceAccountTokenCreator instead)

For a control plane operator that "manages control plane infrastructure and resources," the appropriate roles would typically be:

  • roles/iam.serviceAccountAdmin (if it must create/manage service accounts)
  • roles/iam.serviceAccountTokenCreator (if it must mint tokens for workloads)
  • roles/storage.admin ✓ (correctly listed; for bucket management)

However, I cannot access the repository to verify the actual cmd/infra/gcp/iam-bindings.json file due to clone errors. The documentation should be cross-checked against that authoritative source to confirm whether roles/iam.serviceAccountUser is indeed listed or if a different role is actually required.

**Validate controlPlane GSA roles in cmd/infra/gcp/iam-bindings.json — confirm whether roles/iam.serviceAccountUser or a different service account management role (e.g., roles/iam.serviceAccountAdmin or roles/iam.serviceAccountTokenCreator) is actually defined for the controlPlane operator. If the binding uses a different role, update the documentation to match.


6289-6307: Based on my research, I can now verify the review comment concerns. The web search results confirm that:

  1. roles/iam.serviceAccountUser is indeed missing from the documented IAM roles for the nodePool GSA
  2. This role is critical for scenarios where the controller GSA needs to attach/bind a different service account to VM resources
  3. The distinction between when this role is needed (different SAs) vs. not needed (same SA via WIF) is valid and important for least-privilege security

However, I cannot fully verify the exact contents of cmd/infra/gcp/iam-bindings.json due to repository access limitations. The review comment's concerns are substantive and the documentation appears incomplete.


Document missing roles/iam.serviceAccountUser for nodePool GSA and clarify least-privilege requirements.

The nodePool GSA documentation omits roles/iam.serviceAccountUser, which is required when the controller GSA needs to attach a different service account to VM resources. Add:

  • roles/iam.serviceAccountUser is required only if the VM-attached SA differs from the controller's GSA (WIF impersonation scenario); not needed when using the same GSA via WIF.

Verify that the documented role list (roles/compute.instanceAdmin.v1, roles/compute.networkAdmin) matches the complete set in cmd/infra/gcp/iam-bindings.json and includes any additional roles such as storage, logging, or monitoring roles required for CAPG.


5038-5049: Yes, please search the HyperShift GitHub repo and API docs for the exact HostedCluster/HostedControlPlane status condition type names, specifically looking for:

  • ValidGCPCredentials
  • ValidGCPWorkloadIdentity
  • ValidConfiguration

I need to verify these exact names match the Go constant definitions.

api/hypershift/v1beta1/zz_generated.deepcopy.go (5)

1488-1495: LGTM! Proper deep copy implementation for GCPPlatformSpec.

The generated code correctly handles:

  • ResourceLabels slice: nil-checked, properly allocated, and per-element deep copied
  • WorkloadIdentity: shallow copy is appropriate since GCPWorkloadIdentityConfig contains only value types (strings)

1614-1622: LGTM! Correct deep copy for pointer field.

The Value field (a pointer to string) is properly deep copied with nil check, allocation, and value copy. This follows the standard deep copy pattern.


1649-1652: LGTM! Shallow copy is correct for value-type struct.

GCPServiceAccountsRef contains only string fields (NodePool, ControlPlane), so the shallow copy via *out = *in is correct and efficient.


1664-1668: LGTM! Shallow copy is correct for value-type struct.

GCPWorkloadIdentityConfig and its nested ServiceAccountsRef contain only string fields, so shallow copy is correct and efficient.


3441-3441: LGTM! Ensures proper deep copy of nested GCP structures.

Calling (*in).DeepCopyInto(*out) ensures that GCPPlatformSpec and all its nested structures (including the ResourceLabels slice and WorkloadIdentity) are properly deep copied. This is consistent with how other platform specs are handled.

api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/GCPPlatform.yaml (4)

4742-4757: LGTM: GCP VPC/subnet name rules and immutability are correct.

Regex matches RFC1035-style names; immutability guards look right.

Also applies to: 4763-4778


4793-4797: LGTM: Project ID pattern/immutability.

6–30 chars, starts with letter, no trailing hyphen — good.


4802-4814: LGTM: Region format validation.

Pattern enforces hyphenated segments and numeric suffix (e.g., us-central1).


4897-4900: LGTM: Reserved 'gcp-' prefix blocked for WIF pool/provider IDs.

Matches Google’s reservation; immutability is appropriate.

Also applies to: 4932-4936

api/hypershift/v1beta1/gcp.go (6)

7-17: LGTM! Clean pattern update with excellent documentation.

The updated regex pattern ^[a-z]([-a-z0-9]*[a-z0-9])?$ is more concise than the previous version while maintaining the same GCP naming enforcement (start with letter, end with letter/digit, hyphens allowed in middle). The comprehensive documentation with GCP references is helpful.


20-54: LGTM! Thorough RFC1035 validation with reserved prefix protection.

The GCPResourceLabel implementation is solid:

  • Key validation correctly enforces RFC1035 rules and blocks the reserved 'goog' prefix via CEL validation
  • Value pattern ^$|^[0-9a-z]([0-9a-z-]{0,61}[0-9a-z])?$ explicitly allows empty strings as per GCP requirements
  • Documentation clearly distinguishes Compute Engine constraints from other GCP services
  • Pointer type for Value appropriately handles the nil vs empty string distinction

74-82: LGTM! Proper immutability constraints for network config.

The CEL validations correctly enforce immutability on network infrastructure fields, preventing accidental changes that could break cluster connectivity.


98-98: LGTM! Strengthened validation patterns and well-designed API surface.

The updates to GCPPlatformSpec are excellent:

  • Project pattern now strictly enforces the 6-30 character constraint inline with the regex
  • Region pattern correctly validates region format and rejects zone suffixes (e.g., "us-central1-a")
  • ResourceLabels with MaxItems=60 appropriately reserves headroom within GCP's 64-label limit
  • WorkloadIdentity field design is sound with comprehensive prerequisites documentation

Also applies to: 115-116, 131-139, 141-157


159-224: LGTM! Comprehensive WIF configuration with proper validation.

The GCPWorkloadIdentityConfig implementation is excellent:

  • ProjectNumber validation correctly handles GCP numeric project identifiers
  • PoolID and ProviderID patterns enforce GCP naming rules (4-32 chars, start with letter, no trailing hyphens)
  • CEL validations appropriately block the reserved 'gcp-' prefix on both identifiers
  • Immutability constraints prevent breaking the authentication chain post-creation
  • Documentation provides clear guidance on prerequisites and where to obtain values

226-268: LGTM! Robust service account validation with excellent IAM documentation.

The GCPServiceAccountsRef implementation is solid:

  • Pattern correctly validates the full GSA email format including domain
  • MinLength=38 is appropriately conservative (actual pattern minimum is 37, but being 1 char off is safe)
  • Immutability prevents breaking WIF bindings
  • Documentation of required IAM roles with reference to authoritative source (iam-bindings.json) is excellent
cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-CustomNoUpgrade.crd.yaml (3)

5769-5785: GCP name regexes and immutability look solid.

Patterns match GCE naming rules and immutability guards are correct. No action needed.

Also applies to: 5791-5805


5907-5928: The "gcp-" prefix constraint is correctly enforced per official Google Cloud documentation.

GCP officially reserves the "gcp-" prefix for Workload Identity Federation pool and provider IDs and prohibits its use. This is documented in the gcloud IAM workload-identity-pools CLI documentation and Workload Identity Federation configuration pages. The validation constraint !self.startsWith('gcp-') accurately enforces this GCP requirement and should remain in place.


6011-6022: Based on my investigation, I've reached the limits of what can be verified without direct repository access. Here's what I've learned:

Verified Context:

  • GCP Workload Identity Federation is supported in Red Hat's OpenShift/HyperShift implementation (not upstream)
  • It uses external account credentials and OIDC token exchange
  • The immutability constraint makes sense for security (prevents unintended credential changes)

Unverifiable (repo access required):

  • Whether workloadIdentity is required only in the CustomNoUpgrade CRD variant
  • Whether standard (non-CustomNoUpgrade) hostedclusters CRD files also include this requirement

The review comment's core request—to verify that workloadIdentity gating is scoped to CustomNoUpgrade and not present in standard CRDs—cannot be confirmed due to infrastructure constraints preventing repository access.


cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-TechPreviewNoUpgrade.crd.yaml (6)

5480-5496: LGTM: GCP network name regex + immutability

Naming rules and immutability guard look correct and aligned with GCP.


5501-5516: LGTM: PSC subnet name regex + immutability

Consistent with network name rules; immutability guard is appropriate.


5522-5535: LGTM: GCP project ID validation

Pattern/length and immutability look good.


5540-5552: LGTM: GCP region validation

Pattern enforces region (not zone) and immutability; looks correct.


5694-5701: LGTM: service account email regex/min length

Regex and minLength=38 match the shortest valid GSA email; immutability guard is fine.


5714-5721: LGTM: nodePool service account email validation

Consistent with controlPlane; looks good.

cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-TechPreviewNoUpgrade.crd.yaml (5)

5372-5381: GCP network and subnet name validations look correct and immutable.

Regex and immutability for VPC network name align with GCP limits. Same pattern is reused elsewhere; good consistency.

Also applies to: 5385-5387


5393-5402: PSC subnet name validation/immutability LGTM.

Matches Compute Engine naming rules; immutability guard is appropriate.

Also applies to: 5406-5408


5414-5427: Project ID regex matches GCP rules.

6–30 chars, starts with a letter, hyphens allowed, no trailing hyphen. Immutability is appropriate.


5432-5444: Region pattern excludes zones and enforces digit suffix — good.

Pattern requires at least one hyphen and trailing digits (e.g., us-central1), which blocks zone forms like us-central1-a. Immutability is correct.


5497-5625: WIF IDs: ‘gcp-’ prefix block and immutability are correct.

  • Google reserves the gcp- prefix for pool/provider IDs; your validations enforce that and immutability prevents drift. (pulumi.com)
  • GSA email regex is appropriately constrained to valid account/project IDs and domain.

Two confirmations:

  • Making spec.platform.gcp.workloadIdentity required (line 5630 context) is intentional for all new GCP clusters? Any upgrade/defaulting concerns?
  • Label character policy here is stricter than generic GCP label rules (which allow underscores). If that’s a deliberate “Compute Engine/RFC1035-only” stance, please confirm tests cover services that might attach labels outside Compute (to avoid unexpected rejections). (docs.cloud.google.com)
api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/GCPPlatform.yaml (4)

4634-4650: LGTM: GCP network name rules and immutability.

Pattern and immutability read well and match GCP constraints.


4655-4670: LGTM: PSC subnet name rules and immutability.

Consistent with GCP naming and day‑2 safety.


4685-4685: LGTM: Project ID regex tightened.

Enforces 6–30 chars, start alpha, end alnum, hyphens allowed; matches GCP rules.


4694-4703: LGTM: Region format regex.

Hyphenated segments ending with digits; blocks zone suffixes; good.

Comment thread api/go.mod Outdated

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 3

♻️ Duplicate comments (10)
api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/GCPPlatform.yaml (2)

4708-4756: Labels schema is good; consider clarifying duplicate-key behavior (or block duplicates).

Current array allows duplicate keys; controllers typically end up last-wins. If list-map is out (per earlier thread), add either:

  • Option A (docs-only): Append to description that duplicate keys are rejected/undefined and last-wins may occur.
  • Option B (CEL): Enforce uniqueness without changing list type.

Example patch for Option B (under resourceLabels):

 resourceLabels:
   ...
   maxItems: 60
   type: array
+  x-kubernetes-validations:
+  - message: resourceLabels keys must be unique
+    rule: self.map(x, x.key).all(k, self.map(y, y.key).exists_one(kk, kk == k))

4758-4886: WIF schema/validation LGTM; thanks for fixing GSA minLength and locking fields.

  • Strong per-field patterns and immutability.
  • GSA email minLength set to 37 resolves the earlier off‑by‑one.
docs/content/reference/api.md (1)

6264-6268: Replace broken regex (HTML anchor rendered into pattern).

The “Pattern” line isn’t a valid regex and renders an HTML anchor. Use a copy/paste‑able regex and keep the 63‑char note.

-Pattern: “^<a href="[-a-z0-9]*[a-z0-9]">a-z</a>?$” (max 63 chars), per GCP naming requirements.
+Pattern: `^[a-z]([-a-z0-9]{0,61}[a-z0-9])?$` (max 63 chars), per GCP naming requirements.

Also keep the surrounding prose: “Must start with a lowercase letter and end with a letter or digit.”

cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-CustomNoUpgrade.crd.yaml (2)

5842-5891: Enforce unique label keys via list‑map semantics.

Prevents accidental duplicate keys and improves SSA merge behavior. Non‑breaking at API surface.

 resourceLabels:
   maxItems: 60
   type: array
+  x-kubernetes-list-map-keys:
+  - key
+  x-kubernetes-list-type: map
   items:
     type: object

5928-5941: Tighten projectNumber length to 19 digits (int64 upper bound).

25 allows invalid lengths; 19 matches numeric GCP project numbers.

-                            maxLength: 25
+                            maxLength: 19
cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-TechPreviewNoUpgrade.crd.yaml (3)

5604-5733: Required+immutable workloadIdentity — verify create paths are wired

These fields are required and immutable. Ensure CLI/e2e/examples populate poolID, projectNumber, providerID, and both service account emails at creation; otherwise CRD validation will block cluster creation.

If gaps remain, wire infra output into HostedCluster spec population or add flags to accept user values. Based on earlier repo sweep, ...


5554-5603: Enforce unique label keys for resourceLabels

Prevent duplicate keys by declaring list‑map semantics keyed by "key".

Apply:

 resourceLabels:
   items:
     properties:
       key:
         ...
       value:
         ...
     required:
     - key
-    type: object
+    type: object
   maxItems: 60
-  type: array
+  type: array
+  x-kubernetes-list-map-keys:
+  - key
+  x-kubernetes-list-type: map

This avoids last‑write‑wins ambiguity and improves merge/apply behavior. Based on previous feedback, ...


5694-5696: Minimum length for GSA emails should be 38, not 37

Shortest valid is 6 (name) + 1 (@) + 6 (project) + 25 (suffix) = 38. Bump for both fields.

-                                minLength: 37
+                                minLength: 38

Do this in serviceAccountsEmails.controlPlane and serviceAccountsEmails.nodePool.

Also applies to: 5714-5716

cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-TechPreviewNoUpgrade.crd.yaml (1)

5446-5494: Enforce unique label keys at array level (keep list semantics).

Keys can repeat across items today. Add a CEL array-level rule to ensure uniqueness by key while preserving order and avoiding list-map semantics.

Apply this diff under gcp.resourceLabels:

 resourceLabels:
   description: |-
     resourceLabels are applied to all GCP resources created for the cluster.
+  x-kubernetes-validations:
+  - message: resourceLabels keys must be unique
+    rule: 'self.all(l, self.exists_one(x, x.key == l.key))'
   items:
     description: |-
       GCPResourceLabel is a label to apply to GCP resources created for the cluster.
   ...
   maxItems: 60
   type: array
cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-CustomNoUpgrade.crd.yaml (1)

5734-5783: Enforce unique label keys in resourceLabels (avoid duplicate keys).

Duplicate keys are currently allowed, causing ambiguous last-write-wins behavior and potential API update failures. Add an array-level CEL to enforce key uniqueness. You can keep maxItems at 60 (headroom) or switch to 64 per team preference—either way, ensure uniqueness.

Apply under spec.platform.gcp.resourceLabels:

 resourceLabels:
   description: |-
@@
   maxItems: 60
   type: array
+  x-kubernetes-validations:
+  - message: resourceLabels keys must be unique
+    rule: self == null || self.all(l1, self.exists_one(l2, l1.key == l2.key))
   items:
     description: |-
       GCPResourceLabel is a label to apply to GCP resources created for the cluster.

Optional: mirror this with a kubebuilder XValidation tag on the Go field to keep generators in sync. Based on prior discussion, avoiding list-map semantics while using CEL meets the goal.

🧹 Nitpick comments (4)
api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/GCPPlatform.yaml (1)

4956-4957: Correct minLength for GSA email fields (off by one).

Minimum valid length is 38 chars (6 local + 1 @ + 6 project + 25 suffix). Current minLength: 37 is inconsistent.

-                                minLength: 37
+                                minLength: 38
...
-                                minLength: 37
+                                minLength: 38

Also applies to: 4976-4977

docs/content/reference/api.md (1)

6298-6324: Add conditional note for Service Account User role when VM SA differs.

When the VM’s attached GSA differs from the controller’s GSA, the controller needs iam.serviceAccounts.actAs (typically via roles/iam.serviceAccountUser) on that VM GSA to attach it to instances. Add a one‑liner to prevent misconfig.

 This GSA requires the following IAM roles:
 - roles/compute.instanceAdmin.v1 (Compute Instance Admin v1)
 - roles/compute.networkAdmin (Compute Network Admin)
+Note: If the VM’s service account is distinct from this controller GSA, also grant
+`roles/iam.serviceAccountUser` on that VM service account to this controller GSA so it
+can attach the SA to instances.

Ensure this matches your authoritative bindings (cmd/infra/gcp/iam-bindings.json).

cmd/cluster/gcp/create.go (1)

93-113: Consider adding client-side validation for complex field patterns.

The current validation only checks for non-empty values, which is consistent with the existing pattern for Project and Region. However, the new fields have complex API-level validation rules (regex patterns, length constraints, and reserved prefix checks), and all fields are immutable once the cluster is created.

Without client-side validation, users will discover validation errors only after attempting cluster creation, and fixing them requires deleting and recreating the entire cluster. Consider adding pattern validation here to provide immediate feedback, especially for:

  • WorkloadIdentityPoolID and WorkloadIdentityProviderID (cannot start with 'gcp-', must match ^[a-z]([a-z0-9-]{2,30}[a-z0-9])$)
  • Service account emails (must match email format pattern)
  • WorkloadIdentityProjectNumber (must be numeric)
cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-TechPreviewNoUpgrade.crd.yaml (1)

5730-5732: Reduce immutability duplication (optional)

Top‑level “WorkloadIdentity is immutable” plus per‑field immutability is redundant and can double error noise. Keep either the top‑level or the per‑field rules.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to Reviews -> Disable Knowledge Base setting

📥 Commits

Reviewing files that changed from the base of the PR and between c89bedf and c5e1417.

⛔ Files ignored due to path filters (12)
  • api/go.sum is excluded by !**/*.sum
  • api/vendor/k8s.io/utils/buffer/ring_growing.go is excluded by !**/vendor/**
  • api/vendor/k8s.io/utils/clock/testing/fake_clock.go is excluded by !**/vendor/**
  • api/vendor/k8s.io/utils/lru/lru.go is excluded by !**/vendor/**
  • api/vendor/modules.txt is excluded by !**/vendor/**
  • go.sum is excluded by !**/*.sum
  • vendor/github.com/openshift/hypershift/api/hypershift/v1beta1/gcp.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/openshift/hypershift/api/hypershift/v1beta1/zz_generated.deepcopy.go is excluded by !vendor/**, !**/vendor/**
  • vendor/k8s.io/utils/buffer/ring_growing.go is excluded by !vendor/**, !**/vendor/**
  • vendor/k8s.io/utils/clock/testing/fake_clock.go is excluded by !vendor/**, !**/vendor/**
  • vendor/k8s.io/utils/lru/lru.go is excluded by !vendor/**, !**/vendor/**
  • vendor/modules.txt is excluded by !vendor/**, !**/vendor/**
📒 Files selected for processing (16)
  • api/go.mod (2 hunks)
  • api/hypershift/v1beta1/gcp.go (3 hunks)
  • api/hypershift/v1beta1/zz_generated.deepcopy.go (4 hunks)
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/GCPPlatform.yaml (3 hunks)
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/GCPPlatform.yaml (3 hunks)
  • client/applyconfiguration/hypershift/v1beta1/gcpserviceaccountsemails.go (1 hunks)
  • client/applyconfiguration/hypershift/v1beta1/gcpworkloadidentityconfig.go (1 hunks)
  • client/applyconfiguration/utils.go (1 hunks)
  • cmd/cluster/gcp/create.go (4 hunks)
  • cmd/cluster/gcp/create_test.go (3 hunks)
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-CustomNoUpgrade.crd.yaml (3 hunks)
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-TechPreviewNoUpgrade.crd.yaml (3 hunks)
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-CustomNoUpgrade.crd.yaml (3 hunks)
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-TechPreviewNoUpgrade.crd.yaml (3 hunks)
  • docs/content/reference/api.md (5 hunks)
  • go.mod (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • client/applyconfiguration/hypershift/v1beta1/gcpworkloadidentityconfig.go
🧰 Additional context used
📓 Path-based instructions (1)
**

⚙️ CodeRabbit configuration file

-Focus on major issues impacting performance, readability, maintainability and security. Avoid nitpicks and avoid verbosity.

Files:

  • cmd/cluster/gcp/create.go
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-CustomNoUpgrade.crd.yaml
  • cmd/cluster/gcp/create_test.go
  • api/go.mod
  • go.mod
  • client/applyconfiguration/utils.go
  • client/applyconfiguration/hypershift/v1beta1/gcpserviceaccountsemails.go
  • api/hypershift/v1beta1/zz_generated.deepcopy.go
  • docs/content/reference/api.md
  • api/hypershift/v1beta1/gcp.go
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-TechPreviewNoUpgrade.crd.yaml
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-TechPreviewNoUpgrade.crd.yaml
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/GCPPlatform.yaml
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-CustomNoUpgrade.crd.yaml
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/GCPPlatform.yaml
🧬 Code graph analysis (5)
cmd/cluster/gcp/create.go (1)
api/hypershift/v1beta1/gcp.go (4)
  • GCPNetworkConfig (71-83)
  • GCPResourceReference (6-18)
  • GCPWorkloadIdentityConfig (164-226)
  • GCPServiceAccountsEmails (230-270)
cmd/cluster/gcp/create_test.go (3)
hypershift-operator/controllers/hostedcluster/internal/platform/gcp/gcp.go (1)
  • GCP (34-34)
support/globalconfig/network.go (1)
  • NetworkConfig (23-29)
cmd/cluster/gcp/create.go (2)
  • RawCreateOptions (31-58)
  • CreateOptions (127-130)
client/applyconfiguration/utils.go (3)
client/applyconfiguration/hypershift/v1beta1/gcpresourcelabel.go (1)
  • GCPResourceLabelApplyConfiguration (22-25)
client/applyconfiguration/hypershift/v1beta1/gcpserviceaccountsemails.go (1)
  • GCPServiceAccountsEmailsApplyConfiguration (22-25)
client/applyconfiguration/hypershift/v1beta1/gcpworkloadidentityconfig.go (1)
  • GCPWorkloadIdentityConfigApplyConfiguration (22-27)
client/applyconfiguration/hypershift/v1beta1/gcpserviceaccountsemails.go (1)
api/hypershift/v1beta1/gcp.go (1)
  • GCPServiceAccountsEmails (230-270)
api/hypershift/v1beta1/zz_generated.deepcopy.go (1)
api/hypershift/v1beta1/gcp.go (3)
  • GCPResourceLabel (23-54)
  • GCPServiceAccountsEmails (230-270)
  • GCPWorkloadIdentityConfig (164-226)
🔇 Additional comments (43)
go.mod (1)

295-297: Replace pin for k8s.io/utils looks appropriate; just confirm no newer-API usage

Aligning k8s.io/utils to the Kubernetes v1.32.3 pseudo‑version via replace is a reasonable compatibility move and the inline comment is clear. Please just ensure there are no call sites relying on symbols added in the later v0.0.0-20250321185631-1f6e0b77f77e version so this pin doesn’t introduce subtle compile/runtime regressions if other deps were updated earlier.

client/applyconfiguration/hypershift/v1beta1/gcpserviceaccountsemails.go (1)

20-47: GCPServiceAccountsEmails applyconfiguration is consistent and correct

The generated applyconfiguration type and its builder methods follow the usual pattern (pointer fields, chainable setters) and correctly mirror the underlying GCPServiceAccountsEmails shape. No issues from a correctness or maintainability standpoint.

api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/GCPPlatform.yaml (5)

4634-4650: Network name validation + immutability look solid.

Pattern matches GCP VPC naming and the field is immutable. LGTM.


4655-4670: PSC subnet name validation + immutability are correct.

Matches GCP resource naming; immutability guard is appropriate.


4685-4689: Project ID regex matches GCP rules.

6–30 chars, starts with letter, no trailing hyphen; immutability enforced. LGTM.


4694-4706: Region format tightened appropriately.

Requires at least one hyphen and digit-suffixed region; zones like “us-central1-a” are excluded; immutability enforced. LGTM.


4894-4900: Good cross-field project consistency checks.

CEL ensures both GSAs belong to spec.platform.gcp.project. This prevents runtime misconfig. LGTM.

api/go.mod (1)

10-10: LGTM! Dependency pinning correctly implemented.

The direct requirement for k8s.io/utils combined with the replace directive properly pins the module to the version required by Kubernetes v1.32.3 (v0.0.0-20241104100929-3ea5e8cea738). This approach ensures compatibility with your k8s.io/api v0.32.3 and k8s.io/apimachinery v0.32.3 dependencies while following the agreed-upon solution from the previous review discussion.

Also applies to: 91-92

client/applyconfiguration/utils.go (1)

160-167: LGTM! New GCP WIF types properly integrated.

The three new apply configuration cases for GCP Workload Identity Federation types (GCPResourceLabel, GCPServiceAccountsEmails, GCPWorkloadIdentityConfig) are correctly integrated into the factory function. They follow the established pattern, maintain alphabetical ordering within the GCP section, and match the type definitions shown in the relevant code snippets.

cmd/cluster/gcp/create.go (4)

18-28: LGTM!

Flag constants are well-named and follow the existing kebab-case convention for CLI flags.


38-57: LGTM!

The new fields are well-documented and appropriately typed for capturing CLI input.


64-70: LGTM!

Flag bindings are correct, and the help text provides useful context about obtaining values from the hypershift infra create gcp command output.


176-202: LGTM!

All new GCP configuration fields are correctly mapped from CLI options to the API types. The structure matches the expected GCPNetworkConfig and GCPWorkloadIdentityConfig types with all required fields populated.

cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-CustomNoUpgrade.crd.yaml (6)

5769-5785: LGTM: network name rules and immutability are correct for GCP.


5791-5805: LGTM: PSC subnet name rules and immutability look good.


5820-5821: LGTM: project ID pattern matches documented constraints (6–30, starts with letter, hyphen allowed, no trailing hyphen).


5830-5838: LGTM: region pattern excludes zones and requires trailing digits; sensible validation.


6019-6021: LGTM: WorkloadIdentity immutability is explicit and appropriate while gated.


6029-6036: LGTM: cross-field check ensures GSAs belong to specified project.

api/hypershift/v1beta1/zz_generated.deepcopy.go (1)

1485-1496: LGTM! Auto-generated deepcopy methods are correct.

The generated deepcopy code correctly handles:

  • Slice deep-copy for ResourceLabels with per-element DeepCopyInto calls
  • Pointer field handling for GCPResourceLabel.Value *string
  • Value copying for structs without pointer fields

Also applies to: 1614-1678

cmd/cluster/gcp/create_test.go (1)

22-178: LGTM! Test coverage properly validates new GCP fields.

The tests correctly:

  • Verify ApplyPlatformSpecifics wiring for new network, WIF, and service account fields
  • Add validation test cases for missing required fields (including new network field)
  • Include new CLI flags in the rendering test
api/hypershift/v1beta1/gcp.go (5)

6-18: Improved pattern for GCPResourceReference.

The updated pattern ^[a-z]([-a-z0-9]*[a-z0-9])?$ is more concise than the previous version and explicitly prevents names ending with hyphens, which aligns better with GCP naming requirements.


20-54: GCPResourceLabel implementation is consistent and well-documented.

The field markers are now consistent:

  • Key: required string with RFC1035 pattern and reserved prefix validation
  • Value: optional *string with omitempty, allowing empty strings per GCP API

The MaxItems=60 for ResourceLabels correctly reserves ~4 labels for system use out of GCP's 64-label limit.

Also applies to: 133-141


100-100: Validation patterns for Project and Region are correct.

Both patterns align with GCP requirements:

  • Project pattern (^[a-z]([a-z0-9-]{4,28}[a-z0-9])$): Correctly enforces 6-30 character length (1 start + 4-28 middle + 1 end)
  • Region pattern (^[a-z]+(-[a-z0-9]+)+[0-9]+$): Uses regex backtracking to ensure trailing digits aren't consumed by the middle section, correctly matching regions like us-central1 while rejecting zone suffixes like us-central1-a

Also applies to: 117-117


245-248: Service account email validation correctly aligned with pattern.

The MinLength=37 on lines 246 and 266 correctly matches the minimum length enforced by the pattern:

  • Service account name: 6 chars minimum
  • @ separator: 1 char
  • Project ID: 6 chars minimum
  • .iam.gserviceaccount.com: 24 chars
  • Total: 37 chars minimum ✓

This addresses the previous review concern.

Also applies to: 265-268


143-226: Comprehensive WIF configuration with proper immutability.

The GCPWorkloadIdentityConfig type includes:

  • Clear documentation of WIF prerequisites and setup requirements
  • Proper validation patterns (numeric ProjectNumber, RFC1035-style PoolID/ProviderID)
  • Reserved prefix validation (!self.startsWith('gcp-'))
  • Immutability enforcement at the field level

The design is well-structured for keyless authentication.

cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-TechPreviewNoUpgrade.crd.yaml (5)

5480-5489: GCP network name validation + immutability look solid

Pattern and immutability rule match GCP naming guidance. No changes needed.

Also applies to: 5493-5496


5501-5511: PSC subnet name validation + immutability look solid

Pattern and immutability rule are correct and consistent.

Also applies to: 5514-5516


5523-5535: Project ID rules are consistent

Length, charset, and pattern align; end‑char constraint prevents trailing hyphen. Good as‑is.


5540-5552: Region pattern is correct

Forces at least one hyphen and trailing digits; excludes zone suffixes. Looks good.


5634-5637: Constraint is correctly documented and should be retained

The "gcp-" prefix restriction for pool and provider IDs is a documented GCP requirement. Per Google Cloud IAM documentation, the prefix "gcp-" is reserved and cannot be used for Workload Identity Federation pool or provider IDs. This validation rule correctly enforces GCP's API constraints and should not be removed.

cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-TechPreviewNoUpgrade.crd.yaml (6)

5372-5387: GCP network name + immutability: LGTM

Pattern and immutability rule align with GCP RFC1035-style naming and day-2 stability.


5393-5408: GCP PSC subnet name + immutability: LGTM

Consistent with Compute Engine naming and immutable infra wiring.


5414-5427: Project ID pattern + immutability: LGTM

Constraints match GCP project-id rules (6–30, lowercase/digits/hyphen, leading letter, no trailing hyphen).


5432-5445: Region validation: LGTM

Regex enforces hyphenated region names ending with digits and excludes zones (e.g., “-a”). Immutability is appropriate.


5567-5615: Service Account email regex + same-project rules: LGTM

Email patterns are tight and cross-field checks ensure both GSAs belong to the declared project. Good hardening.

Also applies to: 5632-5638


5518-5530: The 'gcp-' prefix restriction is officially reserved by Google Cloud and the validation rule is correct—retain it.

According to Google Cloud's official Workload Identity documentation, the "gcp-" prefix is explicitly reserved for pool IDs and may not be used. This validation rule correctly implements Google's official constraint. The other constraints (4–32 characters, pattern [a-z0-9-], start/end with alphanumeric, immutability) are also accurate per GCP specifications. The rule should remain unchanged.

cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-CustomNoUpgrade.crd.yaml (6)

5661-5670: LGTM — GCP network name pattern and immutability are correct.

Pattern matches GCP rules; object immutability via self == oldSelf is consistent.

Also applies to: 5674-5676


5682-5691: LGTM — PSC subnet name pattern and immutability are correct.

Matches GCP subnet naming and freezes day‑2 changes as intended.

Also applies to: 5695-5697


5703-5716: LGTM — Project ID regex.

Length, charset, start/end constraints align with GCP requirements.


5718-5733: LGTM — Region format tightening.

Pattern excludes zones and enforces trailing digits; immutability is appropriate.


5785-5914: LGTM — WIF pool/provider IDs, reserved prefixes, and immutability.

  • Start-with-letter enforced.
  • Reserved “gcp-” blocked.
  • Field immutability guarded.

5921-5927: LGTM — Bind SA emails to the configured project.

CEL rules correctly guard cross-field consistency for controlPlane/nodePool GSAs.

Comment thread api/hypershift/v1beta1/gcp.go Outdated
Comment thread docs/content/reference/api.md

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 4

♻️ Duplicate comments (7)
cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-CustomNoUpgrade.crd.yaml (1)

5918-5936: projectNumber max length too permissive; cap at 19 digits.

GCP project numbers are int64; 19 digits max suffices. Tighten to reduce accidental invalid inputs.

-                            maxLength: 25
+                            maxLength: 19
cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-CustomNoUpgrade.crd.yaml (1)

5734-5781: Enforce unique label keys at array level to prevent duplicates

Currently duplicates are possible; add a CEL x-kubernetes-validations on the array so keys are unique. Keep maxItems: 60 headroom.

                       resourceLabels:
                         description: |-
@@
                         maxItems: 60
                         type: array
+                        x-kubernetes-validations:
+                        - message: resourceLabels keys must be unique
+                          rule: self == null || self.all(l1, self.exists_one(l2, l1.key == l2.key))
docs/content/reference/api.md (1)

6262-6268: Fix broken regex/pattern for GCP resource names (doc bug).

The “Pattern” contains an HTML anchor, not a regex. Replace with a valid, copy/paste‑able pattern and keep the 63‑char constraint. Also ensure the prose states “Must start with a lowercase letter, end with a letter or digit.”

Apply this doc change:

-Pattern: “^<a href="[-a-z0-9]*[a-z0-9]">a-z</a>?$” (max 63 chars), per GCP naming requirements.
+Pattern: `^[a-z]([-a-z0-9]{0,61}[a-z0-9])?$` (max 63 chars), per GCP naming requirements.

Tip: wrap the regex in backticks in the Go comment for GCPResourceReference.Name and re‑generate the docs (make api-docs) to avoid Markdown auto-linking.

cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-TechPreviewNoUpgrade.crd.yaml (3)

5554-5601: Enforce uniqueness of resourceLabels by key (use list‑map).

The array permits duplicate label keys; this causes last‑write‑wins ambiguity and poor merge semantics. Make it a list‑map keyed by "key".

Apply at the resourceLabels level:

 resourceLabels:
   items:
     properties:
       key:
         ...
       value:
         ...
     required:
     - key
     type: object
   maxItems: 60
-  type: array
+  type: array
+  x-kubernetes-list-map-keys:
+  - key
+  x-kubernetes-list-type: map

5708-5714: GSA email minLength off by 1 (nodePool).

Same as above; increase to 38 for accuracy.

-                                minLength: 37
+                                minLength: 38

5688-5694: GSA email minLength off by 1 (controlPlane).

Shortest valid address is 6 + 1 + 6 + 25 = 38 chars. Bump minLength to 38.

-                                minLength: 37
+                                minLength: 38
cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-TechPreviewNoUpgrade.crd.yaml (1)

5446-5493: Enforce unique resourceLabels keys via CEL (no list-map semantics).

Duplicate keys can cause ambiguous merges. Add an array-level CEL rule to guarantee uniqueness while preserving list semantics.

Apply:

                       resourceLabels:
                         description: |-
                           resourceLabels are applied to all GCP resources created for the cluster.
                           ...
+                        x-kubernetes-validations:
+                        - message: resourceLabels keys must be unique
+                          rule: 'self.all(l, self.exists_one(x, x.key == l.key))'
                         items:
                           description: |-
                             GCPResourceLabel is a label to apply to GCP resources created for the cluster.

(Based on prior discussion; keeps list semantics while preventing duplicates.)

🧹 Nitpick comments (11)
api/go.mod (1)

10-10: Align the direct require version with the replace directive for clarity.

The direct require on Line 10 specifies k8s.io/utils v0.0.0-20250321185631-1f6e0b77f77e (March 2025), but the replace directive on Line 92 pins it to v0.0.0-20241104100929-3ea5e8cea738 (November 2024, matching Kubernetes 1.32.3). While the replace directive ensures the correct version is used, having a different version in the require block can confuse developers about which version is actually in effect.

Consider updating Line 10 to use the same pseudo-version as the replace directive:

-	k8s.io/utils v0.0.0-20250321185631-1f6e0b77f77e
+	k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738
api/hypershift/v1beta1/gcp_validation_test.go (2)

9-65: Consider adding validation assertions to strengthen test coverage.

While the test documents valid GCPResourceLabel examples, it only checks that Key is non-empty (Line 60-62). The test doesn't verify the actual validation rules enforced by the CRD markers:

  • Key pattern: ^[a-z][a-z0-9_-]{0,62}$
  • Reserved prefix check: keys starting with goog should be rejected
  • Value pattern: ^$|^[a-z0-9_][a-z0-9_-]{0,62}$

Consider adding negative test cases and assertions that actually validate the patterns, or add integration tests that verify the CRD validation rules reject invalid inputs.


67-107: Consider adding pattern validation to region tests.

Similar to TestGCPResourceLabel, this test only verifies that region strings are non-empty (Line 102-104) without actually validating the expected region format pattern. Consider adding assertions that verify the region format matches GCP's region naming conventions or add negative test cases for invalid region formats.

cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-CustomNoUpgrade.crd.yaml (1)

5842-5890: Enforce unique label keys; clarify underscore policy.

  • Recommend map semantics to prevent duplicate label keys and improve SSA merges.
  • The descriptions allow underscores; if the intent is RFC1035 (no underscores) for Compute Engine, tighten the patterns or update text to avoid confusion.

Apply uniqueness with list-map:

 resourceLabels:
@@
   maxItems: 60
   type: array
+  x-kubernetes-list-map-keys:
+  - key
+  x-kubernetes-list-type: map

If RFC1035-only keys/values are intended, consider:

- pattern: ^[a-z][a-z0-9_-]{0,62}$
+ pattern: ^[a-z]([a-z0-9-]{0,62})$  # no underscores

Otherwise, keep current patterns and adjust docs to state underscores are allowed on GCE.

cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-CustomNoUpgrade.crd.yaml (2)

5674-5677: Prefer field‑level immutability over object‑level for network

Use immutability on properties (e.g., name) instead of self == oldSelf on the whole object to avoid freezing future optional fields.

-                            x-kubernetes-validations:
-                            - message: Network is immutable
-                              rule: self == oldSelf
+                            # Keep the object extensible; enforce immutability on fields under properties.name
+                            # (name already has pattern/max/min; add:)
+                            properties:
+                              name:
+                                x-kubernetes-validations:
+                                - message: network name is immutable
+                                  rule: self == oldSelf

5695-5697: Same for privateServiceConnectSubnet: scope immutability to fields

Avoid self == oldSelf at object level; pin immutability to properties.name so new optional fields can be added later without breaking updates.

-                            x-kubernetes-validations:
-                            - message: Private Service Connect subnet is immutable
-                              rule: self == oldSelf
+                            properties:
+                              name:
+                                x-kubernetes-validations:
+                                - message: Private Service Connect subnet name is immutable
+                                  rule: self == oldSelf
test/e2e/v2/tests/api_ux_validation_test.go (2)

1952-1964: Double deletion is redundant but harmless.

The explicit client.Delete call on line 1962 after creation is redundant with the deferred cleanup on lines 1954-1956. While this doesn't cause functional issues (delete is idempotent), it adds unnecessary API calls.

Consider removing the explicit delete since defer already handles cleanup:

 func testHostedClusterCreation(ctx context.Context, client crclient.Client, file string, mutate func(*hyperv1.HostedCluster)) error {
 	hostedCluster := assets.ShouldHostedCluster(content.ReadFile, fmt.Sprintf("assets/%s", file))
 	defer func() {
 		_ = client.Delete(ctx, hostedCluster)
 	}()
 	mutate(hostedCluster)
 
-	err := client.Create(ctx, hostedCluster)
-	// Explicitly delete the resource after creation attempt, in addition to defer
-	// This matches the original test behavior and ensures cleanup even if creation fails
-	_ = client.Delete(ctx, hostedCluster)
-	return err
+	return client.Create(ctx, hostedCluster)
 }

1969-1980: Same redundant deletion pattern in testNodePoolCreation.

Same observation as the HostedCluster helper - the explicit delete is redundant with defer.

docs/content/reference/api.md (1)

5954-5959: Region format text is accurate; consider adding a regex for copy/paste.

Optional: add a pattern like ^[a-z]+(?:-[a-z0-9]+)*[0-9]$ to help users validate inputs locally. Keep the examples as-is.

cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-TechPreviewNoUpgrade.crd.yaml (1)

5547-5549: Region: drop minLength (pattern already enforces structure).

minLength: 1 is redundant and misleading given the strict regex; remove it to avoid confusion.

-                        minLength: 1
                         pattern: ^[a-z]+(-[a-z0-9]+)+[0-9]+$
cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-TechPreviewNoUpgrade.crd.yaml (1)

5458-5487: Clarify underscore policy for label keys/values or adjust regex to match RFC1035.

Descriptions and regex allow underscores (_), but PR objectives mention RFC1035-compliant labels (no underscores). Please confirm intended policy:

  • If RFC1035 (no _) is desired, tighten patterns:
    • key: ^[a-z]([-a-z0-9]{0,62})$
    • value: ^$|^[a-z0-9]([-a-z0-9]{0,62})$
  • Otherwise, update docs to explicitly allow underscores to match current regex.
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to Reviews -> Disable Knowledge Base setting

📥 Commits

Reviewing files that changed from the base of the PR and between c5e1417 and 8994d6b.

⛔ Files ignored due to path filters (14)
  • api/go.sum is excluded by !**/*.sum
  • api/vendor/k8s.io/utils/buffer/ring_growing.go is excluded by !**/vendor/**
  • api/vendor/k8s.io/utils/clock/testing/fake_clock.go is excluded by !**/vendor/**
  • api/vendor/k8s.io/utils/lru/lru.go is excluded by !**/vendor/**
  • api/vendor/modules.txt is excluded by !**/vendor/**
  • go.sum is excluded by !**/*.sum
  • vendor/github.com/openshift/hypershift/api/hypershift/v1beta1/gcp.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/openshift/hypershift/api/hypershift/v1beta1/hostedcluster_conditions.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/openshift/hypershift/api/hypershift/v1beta1/hostedcluster_types.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/openshift/hypershift/api/hypershift/v1beta1/zz_generated.deepcopy.go is excluded by !vendor/**, !**/vendor/**
  • vendor/k8s.io/utils/buffer/ring_growing.go is excluded by !vendor/**, !**/vendor/**
  • vendor/k8s.io/utils/clock/testing/fake_clock.go is excluded by !vendor/**, !**/vendor/**
  • vendor/k8s.io/utils/lru/lru.go is excluded by !vendor/**, !**/vendor/**
  • vendor/modules.txt is excluded by !vendor/**, !**/vendor/**
📒 Files selected for processing (23)
  • api/go.mod (2 hunks)
  • api/hypershift/v1beta1/gcp.go (3 hunks)
  • api/hypershift/v1beta1/gcp_validation_test.go (1 hunks)
  • api/hypershift/v1beta1/hostedcluster_conditions.go (1 hunks)
  • api/hypershift/v1beta1/hostedcluster_types.go (1 hunks)
  • api/hypershift/v1beta1/zz_generated.deepcopy.go (4 hunks)
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/GCPPlatform.yaml (3 hunks)
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/GCPPlatform.yaml (3 hunks)
  • client/applyconfiguration/hypershift/v1beta1/gcpplatformspec.go (2 hunks)
  • client/applyconfiguration/hypershift/v1beta1/gcpresourcelabel.go (1 hunks)
  • client/applyconfiguration/hypershift/v1beta1/gcpserviceaccountsemails.go (1 hunks)
  • client/applyconfiguration/hypershift/v1beta1/gcpworkloadidentityconfig.go (1 hunks)
  • client/applyconfiguration/utils.go (1 hunks)
  • cmd/cluster/gcp/create.go (4 hunks)
  • cmd/cluster/gcp/create_test.go (3 hunks)
  • cmd/cluster/gcp/testdata/zz_fixture_TestCreateCluster_minimal_flags_necessary_to_render.yaml (1 hunks)
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-CustomNoUpgrade.crd.yaml (3 hunks)
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-TechPreviewNoUpgrade.crd.yaml (3 hunks)
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-CustomNoUpgrade.crd.yaml (3 hunks)
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-TechPreviewNoUpgrade.crd.yaml (3 hunks)
  • docs/content/reference/api.md (5 hunks)
  • go.mod (1 hunks)
  • test/e2e/v2/tests/api_ux_validation_test.go (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (9)
  • go.mod
  • client/applyconfiguration/utils.go
  • api/hypershift/v1beta1/hostedcluster_conditions.go
  • client/applyconfiguration/hypershift/v1beta1/gcpplatformspec.go
  • client/applyconfiguration/hypershift/v1beta1/gcpworkloadidentityconfig.go
  • api/hypershift/v1beta1/hostedcluster_types.go
  • client/applyconfiguration/hypershift/v1beta1/gcpserviceaccountsemails.go
  • cmd/cluster/gcp/create.go
  • client/applyconfiguration/hypershift/v1beta1/gcpresourcelabel.go
🧰 Additional context used
📓 Path-based instructions (1)
**

⚙️ CodeRabbit configuration file

-Focus on major issues impacting performance, readability, maintainability and security. Avoid nitpicks and avoid verbosity.

Files:

  • cmd/cluster/gcp/create_test.go
  • api/go.mod
  • test/e2e/v2/tests/api_ux_validation_test.go
  • api/hypershift/v1beta1/gcp_validation_test.go
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/GCPPlatform.yaml
  • cmd/cluster/gcp/testdata/zz_fixture_TestCreateCluster_minimal_flags_necessary_to_render.yaml
  • api/hypershift/v1beta1/zz_generated.deepcopy.go
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-TechPreviewNoUpgrade.crd.yaml
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-CustomNoUpgrade.crd.yaml
  • docs/content/reference/api.md
  • api/hypershift/v1beta1/gcp.go
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-CustomNoUpgrade.crd.yaml
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-TechPreviewNoUpgrade.crd.yaml
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/GCPPlatform.yaml
🧬 Code graph analysis (4)
cmd/cluster/gcp/create_test.go (3)
hypershift-operator/controllers/hostedcluster/internal/platform/gcp/gcp.go (1)
  • GCP (34-34)
support/globalconfig/network.go (1)
  • NetworkConfig (23-29)
cmd/cluster/gcp/create.go (2)
  • RawCreateOptions (31-58)
  • CreateOptions (127-130)
test/e2e/v2/tests/api_ux_validation_test.go (2)
test/e2e/util/crd.go (1)
  • HasFieldInCRDSchema (15-38)
hypershift-operator/controllers/hostedcluster/internal/platform/gcp/gcp.go (1)
  • GCP (34-34)
api/hypershift/v1beta1/gcp_validation_test.go (1)
api/hypershift/v1beta1/gcp.go (1)
  • GCPResourceLabel (23-52)
api/hypershift/v1beta1/zz_generated.deepcopy.go (1)
api/hypershift/v1beta1/gcp.go (3)
  • GCPResourceLabel (23-52)
  • GCPServiceAccountsEmails (228-268)
  • GCPWorkloadIdentityConfig (162-224)
🔇 Additional comments (36)
cmd/cluster/gcp/testdata/zz_fixture_TestCreateCluster_minimal_flags_necessary_to_render.yaml (1)

42-53: LGTM!

The test fixture correctly reflects the new GCP Workload Identity Federation API structure, including network configuration and service account email references. The values are consistent with the test inputs in create_test.go.

cmd/cluster/gcp/create_test.go (3)

30-59: LGTM!

The test comprehensively validates the new GCP Workload Identity Federation fields:

  • Verifies all new fields (Network, PrivateServiceConnectSubnet, WorkloadIdentity*, service accounts) are properly populated in the options
  • Confirms fields propagate correctly to HostedCluster.Spec.Platform.GCP.WorkloadIdentity and NetworkConfig
  • Includes proper assertions for the nested ServiceAccountsEmails structure

65-116: LGTM!

Excellent validation test coverage:

  • Defines a complete validOpts baseline with all required WIF fields
  • Tests missing required fields individually (project, region, network)
  • Verifies appropriate error messages are returned
  • Confirms valid options pass without errors

139-145: LGTM!

The integration test correctly includes all new required CLI flags for GCP Workload Identity Federation, ensuring the end-to-end cluster creation flow can render manifests with the new WIF configuration.

cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-CustomNoUpgrade.crd.yaml (3)

5769-5785: GCE resource naming + immutability look solid.

Name regexes and self==oldSelf immutability checks for network and PSC subnet align with GCE rules. LGTM.

Also applies to: 5791-5805


5820-5821: Project ID and region validations are appropriate.

  • Project ID pattern enforces 6–30, start letter, no trailing hyphen.
  • Region pattern excludes zones and requires trailing digits (e.g., us-central1). LGTM.

Also applies to: 5836-5837


6027-6035: Cross-field GSA/project consistency checks are good.

Ends-with validation ties GSAs to the configured project domain correctly. LGTM.

api/hypershift/v1beta1/gcp.go (5)

7-52: LGTM: GCP resource naming and labeling validation is comprehensive.

The updated patterns for resource names and labels correctly enforce GCP requirements. The resolution of the GCPResourceLabel.Value field (now properly marked +optional with pointer type) addresses the previous review concern.


84-85: LGTM: CEL validation correctly implemented.

The service account email validation now uses contains('@') and endsWith() instead of the invalid split('@', 2)[1] syntax from earlier iterations. This correctly verifies that service accounts belong to the specified project.


141-224: LGTM: Workload Identity Federation configuration is well-validated.

The WIF types include comprehensive validation:

  • Numeric project number pattern and length constraints
  • PoolID and ProviderID patterns correctly enforce 4-32 character length
  • Reserved prefix validation blocks "gcp-" prefix conflicts
  • Immutability markers prevent breaking changes to authentication chain

The decision to make WorkloadIdentity required is appropriate given the feature-gated status of GCP support.


226-268: LGTM: Service account email validation is correctly implemented.

The GSA email pattern and length constraints are now consistent (MinLength=37 correctly matches the pattern's minimum). The previous discrepancy flagged in past reviews has been resolved in commit c5e1417.

Both NodePool and ControlPlane fields share the same comprehensive validation, which ensures consistency across service account references.


115-115: Based on my verification, I can now provide an assessment:

Verification Results:

  1. Pattern correctness: The regex ^[a-z]+(-[a-z0-9]+)+[0-9]+$ is correct and comprehensive. It successfully matches all GCP region naming patterns:

    • ✓ us-central1, us-east1, us-east4, us-east5
    • ✓ europe-west1 through europe-west12
    • ✓ northamerica-northeast1, northamerica-northeast2
    • ✓ asia-northeast1, asia-south1, australia-southeast1
    • ✓ southamerica-east1, southamerica-west1
  2. Backtracking concern: The regex engine's backtracking is normal and not problematic. The (-[a-z0-9]+)+ segment correctly forces the engine to backtrack when necessary to ensure the final [0-9]+ requirement is satisfied.

  3. Testing verification: I cannot access the repository to confirm whether gcp_validation_test.go exists or contains test cases for this pattern.


Verify region pattern against GCP's official naming conventions.

The pattern ^[a-z]+(-[a-z0-9]+)+[0-9]+$ correctly validates all GCP region formats (us-central1, europe-west1-12, northamerica-northeast1, etc.). Regex backtracking here is expected behavior and not a concern. Ensure test coverage exists in gcp_validation_test.go with representative examples like us-central1, europe-west12, and northamerica-northeast1 to maintain pattern validation confidence across GCP regions.

cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-CustomNoUpgrade.crd.yaml (6)

5712-5716: Project ID regex looks correct

Pattern enforces 6‑30, starts with letter, allowed hyphen, ends alnum. LGTM.


5721-5733: Region pattern is aligned with GCP regions (ends with digits, not zones)

Blocks zone suffices like -a and requires at least one hyphen. LGTM.


5809-5816: poolID: start‑with‑letter and reserved prefix guard — good

Regex and !self.startsWith('gcp-') match GCP rules. LGTM.


5845-5852: providerID: mirrors poolID constraints correctly

Start‑with‑letter + reserved prefix + immutability. LGTM.


5873-5881: Service account email regex and immutability look right

Modern domain only and project/local‑part bounds enforced; immutability set. LGTM.

Also applies to: 5893-5899


5919-5927: Cross‑field validation tying SA emails to project — good

endsWith('@'+project+'.iam.gserviceaccount.com') ensures alignment with configured project. LGTM.

test/e2e/v2/tests/api_ux_validation_test.go (6)

343-350: LGTM - BeforeEach follows established pattern.

The BeforeEach correctly checks for GCP field availability in the CRD schema before running tests, matching the pattern used in the existing "GCP platform validation" context (lines 299-306).


352-378: Good comprehensive test for valid WIF configuration.

The test covers all required WIF fields including ProjectNumber, PoolID, ProviderID, and ServiceAccountsRef with properly formatted values.


380-453: Thorough validation coverage for WIF field constraints.

Tests cover key validation scenarios: non-numeric project number, reserved gcp- prefix on poolID, minimum length constraints. The expected error messages align with the validation rules defined in the API types.


455-528: Good coverage for providerID and service account email validation.

Tests verify reserved prefix rejection for providerID and invalid email format detection for both NodePool and ControlPlane service accounts.


530-610: Resource label validation tests cover important edge cases.

Tests include valid labels, empty values, nil values, and these correctly expect success - matching GCP's label requirements where empty values are allowed.


612-671: Good coverage for reserved prefix and max items constraints.

Tests for the goog reserved prefix and the 60-item limit on resource labels are correctly implemented.

api/hypershift/v1beta1/zz_generated.deepcopy.go (4)

1488-1496: Generated deepcopy correctly handles new GCP fields.

The auto-generated code properly:

  1. Nil-checks and deep copies the ResourceLabels slice with element-wise DeepCopyInto
  2. Copies WorkloadIdentity by value (correct since GCPWorkloadIdentityConfig contains no pointer fields)

1614-1632: GCPResourceLabel deepcopy correctly handles optional Value pointer.

The generated code properly allocates a new string pointer when Value is non-nil, preventing shared pointer references between copies.


1649-1678: GCPServiceAccountsEmails and GCPWorkloadIdentityConfig deepcopy implementations are correct.

Both types contain only value types (strings and embedded structs with strings), so the simple value assignment is the correct approach.


3438-3442: PlatformSpec.DeepCopyInto correctly updated for GCP.

The change from **out = **in to (*in).DeepCopyInto(*out) is necessary because GCPPlatformSpec now contains a slice (ResourceLabels) requiring proper deep copy semantics.

docs/content/reference/api.md (5)

6181-6235: GCPResourceLabel rules align with Compute Engine label spec.

Underscores allowed, key starts with lowercase letter, and reserved “goog” noted. LGTM.


5038-5049: I'm unable to complete the verification due to repository access issues. However, I can assess the review comment itself:

The original review comment is structured as a verification request rather than a finalized review. It asks for confirmation that condition type names match across the codebase, but this task requires examining:

  1. Go API constants/types in api/hypershift/v1beta1
  2. CRD YAML status descriptors
  3. Documentation in docs/content/reference/api.md

Since:

  • The repository clone failed, I cannot execute the verification script
  • The review comment itself contains an unexecuted `` block
  • The names "ValidGCPCredentials" and "ValidGCPWorkloadIdentity" appear in the documentation snippet but remain unvalidated against the source code

The review comment cannot be finalized without direct codebase access to cross-reference the condition type definitions.

Please retry this verification task, or if you have direct access to the repository, you can manually run the provided rg command to search for these condition type names in api/**/*.go and config/**/*.yaml files to confirm consistency.


6331-6416: Documentation constraint inaccuracy: start character rule differs from Google's specification.

The review verified correctly that poolID/providerID constraints (length 4–32, hyphens allowed, cannot start/end with hyphen, "gcp-" prefix reserved) match Google's current WIF requirements.

However, the documentation states IDs "must start with a lowercase letter," but Google's actual constraint is that IDs must start and end with an alphanumeric character (letters or digits). This means the documentation is overly restrictive—digits are valid starting characters per Google's specification.

Correct the constraint documentation to: "Must be 4–32 characters, start and end with an alphanumeric character (a–z or 0–9), and contain only lowercase letters, digits, and hyphens."

Cannot verify CRD CEL/regex validations without repository access.


6289-6327: Based on the web search results, I now have sufficient evidence to rewrite the review comment. The search results clearly distinguish between the roles and provide strong evidence that the review comment's concern is valid.


Verify IAM role alignment with WIF architecture: serviceAccountUser vs workloadIdentityUser for controlPlane GSA.

The documentation currently lists roles/iam.serviceAccountUser for the controlPlane GSA. However, standard GCP Workload Identity Federation best practices indicate:

  • roles/iam.workloadIdentityUser is the correct role for external/federated principals to impersonate a GSA via WIF
  • roles/iam.serviceAccountUser is for attaching a SA to GCP resources and does not enable impersonation token minting

If Hypershift's GCP infrastructure uses WIF for external identity federation (common pattern), the documented role should be roles/iam.workloadIdentityUser instead. Please reconcile the documented roles against cmd/infra/gcp/iam-bindings.json and confirm the WIF setup to ensure consistency.


5992-6030: Based on my verification attempts, I was unable to access the HyperShift repository's CRD definitions through available tools (repository cloning failed, and web searches for the specific CRD files were inconclusive). Without direct access to the CRD schema files, I cannot definitively verify the claims about:

  1. Immutability enforcement for workloadIdentity fields (whether x-kubernetes-validations rules exist)
  2. In-place propagation support for resourceLabels
  3. System label headroom (~4 labels reserved by HyperShift) matching implementation

The only verified fact is that GCP enforces a 64-label maximum per resource, which the documentation correctly states.

Manual verification needed: Check the CRD schema in api/v1beta1/gcpplatform_types.go or corresponding YAML to confirm immutability rules and resource label validation.

api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/GCPPlatform.yaml (1)

4985-5008: LGTM: WIF immutability and CEL domain guards look correct.

  • ‘gcp-’ reserved-prefix checks and field immutability are enforced.
  • Email domain checks use contains/endsWith and align with required project domain.
cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-TechPreviewNoUpgrade.crd.yaml (1)

5630-5638: Nice cross-field validation for GSA domain vs project.

The endsWith('@' + self.project + '.iam.gserviceaccount.com') checks are concise and effective.

api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/GCPPlatform.yaml (1)

4882-4900: Nice: immutable WIF block and project-matching for GSAs.

The immutability guard on workloadIdentity and the endsWith checks that GSA emails belong to spec.platform.gcp.project look good. The minLength=37 fix also matches the shortest valid address.

@apahim
apahim force-pushed the gcp_wif_api branch 2 times, most recently from 0c60104 to 9b470e5 Compare December 3, 2025 11:29

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 2

♻️ Duplicate comments (11)
api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/GCPPlatform.yaml (1)

4846-4847: Regression: GSA email minLength off by one (rejects valid 6-char IDs).

Minimal valid address is 37 chars: 6(sa)+1(@)+6(project)+24(".iam.gserviceaccount.com"). Current minLength 38 is too strict for both controlPlane and nodePool.

Please apply:

-                                minLength: 38
+                                minLength: 37

at both occurrences.

Also applies to: 4866-4867

docs/content/reference/api.md (2)

6299-6304: Fix broken regex/pattern for GCP resource names (doc bug).

The “Pattern” includes an HTML anchor and isn’t a valid, copy/paste‑able regex. Replace it with the correct regex wrapped in code formatting and keep the 63‑char note.

Apply this doc change:

-Pattern: “^<a href="[-a-z0-9]*[a-z0-9]">a-z</a>?$” (max 63 chars), per GCP naming requirements.
+Pattern: `^[a-z]([-a-z0-9]{0,61}[a-z0-9])?$` (max 63 chars), per GCP naming requirements.

Also ensure the surrounding prose still states “Must start with a lowercase letter and end with a letter or digit.”


6246-6270: Allow underscores in GCP label keys/values; update charset rules.

Compute Engine labels permit underscores in keys and values. The current text limits to letters/digits/hyphens only. Please update both key and value descriptions to allow “lowercase letters, digits, underscores (_), and hyphens (-)”, keep start/end rules and 63‑char limits, and retain the reserved “goog” note.

Suggested edits:

-Contain only lowercase letters, digits, or hyphens
+Contain only lowercase letters, digits, underscores (_), or hyphens (-)

Make the same adjustment for value, while keeping “empty allowed”.

api/hypershift/v1beta1/gcp.go (1)

242-244: MinLength should be 37 to match the pattern's enforced minimum.

The regex pattern enforces a minimum of 37 characters:

  • Service account name: 6 chars min ([a-z][a-z0-9-]{4,28}[a-z0-9])
  • @: 1 char
  • Project ID: 6 chars min (same pattern)
  • Domain suffix: 24 chars (.iam.gserviceaccount.com)
  • Total: 37 chars

Setting MinLength=38 incorrectly rejects valid 37-character emails.

Apply this diff to both fields:

-// +kubebuilder:validation:MinLength=38
+// +kubebuilder:validation:MinLength=37

Also applies to: 262-264

cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-CustomNoUpgrade.crd.yaml (2)

5926-5939: projectNumber maxLength too large for int64.

Project numbers are int64; cap at 19 digits or drop maxLength and rely on the numeric regex.

-                            maxLength: 25
+                            maxLength: 19
Do Google Cloud project numbers fit within signed 64-bit integers (i.e., at most 19 digits)?

5981-5986: Service account email minLength: prefer relying on regex.

minLength=38 can drift from the regex and observed minima; drop minLength to avoid false rejects.

-                                minLength: 38
-                                minLength: 38
#!/bin/bash
# Compute minimal email length implied by the regex (6-char local + '@' + 6-char proj + '.iam.gserviceaccount.com')
python - <<'PY'
local_min = 6
proj_min = 6
suffix = len("@.iam.gserviceaccount.com")  # 25
print("Computed minimum:", local_min + 1 + proj_min + (suffix-1))  # Show working if needed
PY

Also applies to: 6001-6006

cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-TechPreviewNoUpgrade.crd.yaml (1)

5431-5443: Fix region regex and description (rejects valid regions like northamerica-northeast1).

  • Current pattern ^[a-z]+-[a-z]+[0-9]+$ only allows one hyphen and fails for multi‑segment regions (e.g., northamerica-northeast1).
  • Description also incorrectly says “exactly one hyphen.”

Use a pattern that allows one or more hyphen‑separated segments and ends with digits, and update the prose accordingly.

Apply:

-                          Must be in the form of <geographic-area>-<location><number> (e.g., us-central1, europe-west12).
-                          Must contain exactly one hyphen separating the geographic area from the location.
+                          Must be in the form of <area>-<location><number> (e.g., us-central1, europe-west12, northamerica-northeast1).
+                          Must contain at least one hyphen; the final segment must end with one or more digits.
@@
-                        pattern: ^[a-z]+-[a-z]+[0-9]+$
+                        # allow multi-segment areas/locations; last segment must end with digit(s)
+                        pattern: ^[a-z]+(?:-[a-z]+)*-[a-z]+[0-9]+$
cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-TechPreviewNoUpgrade.crd.yaml (1)

5552-5601: Label value pattern is too restrictive compared to GCP requirements; update to support underscores and leading digits

GCP Compute Engine label values allow lowercase letters, digits, underscores, and hyphens, with no requirement for a leading letter. The current pattern ^$|^[a-z]([-a-z0-9]{0,61}[a-z0-9])?$ rejects valid GCP labels like "2025", "_prod", and "team_alpha". The pattern must permit underscores anywhere and leading digits/underscores to match GCP's actual constraints.

Suggested update:

-                                Empty values are allowed by GCP. If non-empty, it must start with a lowercase letter,
-                                contain only lowercase letters, digits, or hyphens, and end with a lowercase letter or digit.
+                                Empty values are allowed by GCP. If non-empty, it must contain only lowercase letters, digits, underscores, or hyphens.
@@
-                              pattern: ^$|^[a-z]([-a-z0-9]{0,61}[a-z0-9])?$
+                              pattern: ^$|^[a-z0-9_][-a-z0-9_]{0,61}[a-z0-9_]$|^[a-z0-9_]$
api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/GCPPlatform.yaml (2)

4742-4757: WIF schema, naming patterns, and CEL guards look solid.

  • Network/subnet name patterns and immutability: OK.
  • Project ID pattern and region format: OK.
  • WIF pool/provider ID formats with reserved 'gcp-' prefix: OK.
  • CEL endsWith guard tying GSAs to project: OK.
  • workloadIdentity required under the feature gate: acknowledged.

Also applies to: 4763-4778, 4793-4794, 4801-4813, 4877-4898, 4914-4934, 4994-4998, 5000-5008


4846-4854: Label value regex and description must permit underscores per GCP documentation.

GCP Compute Engine label values allow lowercase letters, digits, underscores, and hyphens. The current regex pattern and description incorrectly exclude underscores. Update both to match the actual GCP requirements:

-                                Empty values are allowed by GCP. If non-empty, it must start with a lowercase letter,
-                                contain only lowercase letters, digits, or hyphens, and end with a lowercase letter or digit.
+                                Empty values are allowed by GCP. If non-empty, it must start with a lowercase letter,
+                                and may contain only lowercase letters, digits, underscores (_), or hyphens (-), and end with a lowercase letter or digit.
@@
-                              pattern: ^$|^[a-z]([-a-z0-9]{0,61}[a-z0-9])?$
+                              pattern: ^$|^[a-z]([-a-z0-9_]{0,61}[a-z0-9])?$
cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-CustomNoUpgrade.crd.yaml (1)

5734-5782: Label regex rejects valid GCP labels (missing underscores) — update patterns

GCP Compute Engine labels allow underscores in both keys and values. Current patterns disallow "_", causing valid labels to be rejected at admission. Update both key and value patterns to include underscores.

Apply:

-                              pattern: ^[a-z]([-a-z0-9]{0,61}[a-z0-9])?$
+                              pattern: ^[a-z]([a-z0-9_-]{0,61}[a-z0-9])?$
-                              pattern: ^$|^[a-z]([-a-z0-9]{0,61}[a-z0-9])?$
+                              pattern: ^$|^[a-z]([a-z0-9_-]{0,61}[a-z0-9])?$

Also update the descriptions to mention underscores and dashes (they currently say "hyphens only").

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to Reviews -> Disable Knowledge Base setting

📥 Commits

Reviewing files that changed from the base of the PR and between 1bc2036 and 9b470e5.

⛔ Files ignored due to path filters (6)
  • api/go.sum is excluded by !**/*.sum
  • api/vendor/k8s.io/utils/buffer/ring_growing.go is excluded by !**/vendor/**
  • api/vendor/k8s.io/utils/clock/testing/fake_clock.go is excluded by !**/vendor/**
  • api/vendor/k8s.io/utils/lru/lru.go is excluded by !**/vendor/**
  • api/vendor/modules.txt is excluded by !**/vendor/**
  • go.sum is excluded by !**/*.sum
📒 Files selected for processing (21)
  • api/go.mod (1 hunks)
  • api/hypershift/v1beta1/gcp.go (3 hunks)
  • api/hypershift/v1beta1/hostedcluster_conditions.go (1 hunks)
  • api/hypershift/v1beta1/hostedcluster_types.go (1 hunks)
  • api/hypershift/v1beta1/zz_generated.deepcopy.go (4 hunks)
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/GCPPlatform.yaml (2 hunks)
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/GCPPlatform.yaml (2 hunks)
  • client/applyconfiguration/hypershift/v1beta1/gcpplatformspec.go (2 hunks)
  • client/applyconfiguration/hypershift/v1beta1/gcpresourcelabel.go (1 hunks)
  • client/applyconfiguration/hypershift/v1beta1/gcpserviceaccountsemails.go (1 hunks)
  • client/applyconfiguration/hypershift/v1beta1/gcpworkloadidentityconfig.go (1 hunks)
  • client/applyconfiguration/utils.go (1 hunks)
  • cmd/cluster/gcp/create.go (4 hunks)
  • cmd/cluster/gcp/create_test.go (3 hunks)
  • cmd/cluster/gcp/testdata/zz_fixture_TestCreateCluster_minimal_flags_necessary_to_render.yaml (1 hunks)
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-CustomNoUpgrade.crd.yaml (2 hunks)
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-TechPreviewNoUpgrade.crd.yaml (2 hunks)
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-CustomNoUpgrade.crd.yaml (2 hunks)
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-TechPreviewNoUpgrade.crd.yaml (2 hunks)
  • docs/content/reference/api.md (5 hunks)
  • go.mod (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • go.mod
🚧 Files skipped from review as they are similar to previous changes (6)
  • client/applyconfiguration/utils.go
  • client/applyconfiguration/hypershift/v1beta1/gcpworkloadidentityconfig.go
  • cmd/cluster/gcp/create_test.go
  • client/applyconfiguration/hypershift/v1beta1/gcpplatformspec.go
  • api/go.mod
  • cmd/cluster/gcp/testdata/zz_fixture_TestCreateCluster_minimal_flags_necessary_to_render.yaml
🧰 Additional context used
📓 Path-based instructions (1)
**

⚙️ CodeRabbit configuration file

-Focus on major issues impacting performance, readability, maintainability and security. Avoid nitpicks and avoid verbosity.

Files:

  • client/applyconfiguration/hypershift/v1beta1/gcpresourcelabel.go
  • client/applyconfiguration/hypershift/v1beta1/gcpserviceaccountsemails.go
  • api/hypershift/v1beta1/hostedcluster_conditions.go
  • api/hypershift/v1beta1/hostedcluster_types.go
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/GCPPlatform.yaml
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-CustomNoUpgrade.crd.yaml
  • cmd/cluster/gcp/create.go
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-TechPreviewNoUpgrade.crd.yaml
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-TechPreviewNoUpgrade.crd.yaml
  • docs/content/reference/api.md
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-CustomNoUpgrade.crd.yaml
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/GCPPlatform.yaml
  • api/hypershift/v1beta1/zz_generated.deepcopy.go
  • api/hypershift/v1beta1/gcp.go
🧬 Code graph analysis (4)
api/hypershift/v1beta1/hostedcluster_conditions.go (1)
api/hypershift/v1beta1/hosted_controlplane.go (1)
  • ConditionType (294-294)
cmd/cluster/gcp/create.go (1)
cmd/util/util.go (1)
  • ValidateRequiredOption (11-16)
api/hypershift/v1beta1/zz_generated.deepcopy.go (1)
api/hypershift/v1beta1/gcp.go (3)
  • GCPResourceLabel (23-50)
  • GCPServiceAccountsEmails (227-267)
  • GCPWorkloadIdentityConfig (161-223)
api/hypershift/v1beta1/gcp.go (2)
test/e2e/util/external_oidc.go (1)
  • Key (289-292)
client/applyconfiguration/hypershift/v1beta1/gcpresourcereference.go (1)
  • GCPResourceReference (28-30)
🪛 golangci-lint (2.5.0)
api/hypershift/v1beta1/gcp.go

[error] 228-228: : # github.com/openshift/hypershift/sync-global-pullsecret [github.com/openshift/hypershift/sync-global-pullsecret.test]
sync-global-pullsecret/sync-global-pullsecret_test.go:228:23: undefined: MockdbusConn
sync-global-pullsecret/sync-global-pullsecret_test.go:234:26: undefined: MockdbusConn
sync-global-pullsecret/sync-global-pullsecret_test.go:247:26: undefined: MockdbusConn
sync-global-pullsecret/sync-global-pullsecret_test.go:257:26: undefined: MockdbusConn
sync-global-pullsecret/sync-global-pullsecret_test.go:270:26: undefined: MockdbusConn
sync-global-pullsecret/sync-global-pullsecret_test.go:283:26: undefined: MockdbusConn
sync-global-pullsecret/sync-global-pullsecret_test.go:296:26: undefined: MockdbusConn
sync-global-pullsecret/sync-global-pullsecret_test.go:309:26: undefined: MockdbusConn
sync-global-pullsecret/sync-global-pullsecret_test.go:327:12: undefined: NewMockdbusConn

(typecheck)

🔇 Additional comments (41)
api/hypershift/v1beta1/zz_generated.deepcopy.go (3)

1488-1493: LGTM! Correct deepcopy implementation for new GCP fields.

The deepcopy logic is correctly implemented:

  • ResourceLabels slice is properly allocated and copied using the standard pattern for slices of value-type structs.
  • WorkloadIdentity struct assignment is appropriate since GCPWorkloadIdentityConfig and its nested types contain only string fields (no pointers, slices, or maps).

1612-1671: LGTM! New GCP type deepcopy methods are correct.

The deepcopy implementations for the three new GCP types are appropriate:

  • All types contain only string fields or nested structs with string fields.
  • Shallow struct copying via *out = *in is correct and efficient for value types.
  • The pattern is consistent with similar types throughout the file.

3434-3434: LGTM! Correct deepcopy pattern for GCP platform.

The change from shallow copy to calling DeepCopyInto is necessary and correct because GCPPlatformSpec now contains the ResourceLabels slice field that requires proper deep copying. This pattern is consistent with other platform types in the file.

api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/GCPPlatform.yaml (1)

4634-4650: LGTM: GCP naming/immutability, labels, and WIF validations look solid.

  • Network/subnet names and immutability are aligned with GCE constraints.
  • Project/region regexes and docs are clear and restrictive in the right ways.
  • Label key/value patterns block reserved 'goog' prefix and enforce RFC1035-like rules; list-map enforces unique keys.
  • WIF: pool/provider IDs, projectNumber, and overall immutability checks are well-scoped; project match checks for GSAs are in place.

No further action from me here.

Also applies to: 4655-4670, 4685-4689, 4693-4705, 4706-4755, 4756-4826, 4892-4900

api/hypershift/v1beta1/hostedcluster_types.go (1)

133-135: LGTM!

The constant follows the established pattern for ClusterAPI provider image overrides and is properly documented.

api/hypershift/v1beta1/hostedcluster_conditions.go (1)

154-163: LGTM!

The new GCP validation conditions are well-structured and follow the established pattern for platform-specific validation. The separation between credential validation and Workload Identity configuration is appropriate and the documentation clearly indicates the external intervention that may be required.

client/applyconfiguration/hypershift/v1beta1/gcpserviceaccountsemails.go (1)

1-47: LGTM!

This is generated code that follows the standard apply configuration pattern. The implementation provides proper constructor and fluent builder methods for GCPServiceAccountsEmails configuration.

client/applyconfiguration/hypershift/v1beta1/gcpresourcelabel.go (1)

1-47: LGTM!

This is generated code that follows the standard apply configuration pattern. The implementation provides proper constructor and fluent builder methods for GCPResourceLabel configuration.

docs/content/reference/api.md (1)

5062-5072: New GCP condition types look good.

The additions for ValidGCPCredentials and ValidGCPWorkloadIdentity are clear and consistent with the rest of the condition set.

cmd/cluster/gcp/create.go (3)

18-28: LGTM! Well-structured flag definitions and options.

The new GCP WIF-related fields are properly defined with clear naming and documentation. The help text appropriately references hypershift infra create gcp output for obtaining the required values.

Also applies to: 37-57


93-113: Validation logic correctly enforces all required WIF fields.

The validation follows the established pattern and properly ensures all WorkloadIdentity configuration is provided. This aligns with the confirmed design decision for WIF-only GCP support at this stage.


175-198: Correct mapping of CLI options to GCPPlatformSpec.

The ApplyPlatformSpecifics method properly populates the nested GCPNetworkConfig and GCPWorkloadIdentityConfig structures with all required fields from the validated options.

api/hypershift/v1beta1/gcp.go (5)

6-18: LGTM! GCPResourceReference pattern and documentation improved.

The updated regex pattern ^[a-z]([-a-z0-9]*[a-z0-9])?$ correctly allows both single-character names (a) and multi-character names ending with alphanumeric, conforming to GCP naming standards.


20-50: GCPResourceLabel type correctly implements GCP Compute Engine label constraints.

The key validation properly blocks the reserved goog prefix via XValidation. The value field correctly allows empty strings as permitted by GCP. The pattern enforces RFC1035-compliant naming (no underscores, lowercase only).


66-79: LGTM! Immutability constraints properly applied to network configuration.

The XValidation rules correctly use self == oldSelf CEL syntax to enforce immutability of VPC network and Private Service Connect subnet after cluster creation.


82-83: Cross-field validation correctly ensures service accounts belong to the project.

The XValidation rules use contains('@') and endsWith() CEL functions to verify that both service account emails match the project specified in self.project. This approach avoids the previously flagged split() syntax issue.


158-223: GCPWorkloadIdentityConfig properly validates WIF resource identifiers.

The configuration correctly enforces:

  • Numeric project number format
  • Pool/Provider ID constraints (4-32 chars, no gcp- prefix)
  • Immutability via XValidation rules

The documentation helpfully references hypershift infra create gcp as the source for these values.

cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-CustomNoUpgrade.crd.yaml (6)

5769-5784: GCP network/subnet naming + immutability: LGTM.

Patterns match GCP rules; immutability on the object is correct.


5820-5821: Project ID regex: LGTM.

Matches GCP format and aligns with min/max length.


5841-5890: Resource labels schema: LGTM.

  • Map semantics prevent duplicate keys.
  • RFC1035‑style key/value patterns consistent with stated intent.
  • Reserved 'goog' prefix ban is documented and enforced.

If you want stronger clarity, add “This is stricter than some GCP services; intentionally RFC1035 for Compute Engine resources.”


5904-5960: WIF pool/provider IDs: LGTM.

Length/patterns, ‘gcp-’ reservation, and immutability look correct.


6026-6035: Cross‑field SA domain check: LGTM.

endsWith validation ties SA emails to the same project ID as intended.


5826-5837: Regex pattern is correct for all current GCP regions.

The pattern ^[a-z]+-[a-z]+[0-9]+$ successfully matches all current Google Cloud regions including: us-central1, europe-west12, northamerica-northeast1, australia-southeast2, asia-south1, southamerica-east1, me-central1, me-west1, africa-south1, and all other variations. No modifications needed.

cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-TechPreviewNoUpgrade.crd.yaml (6)

5372-5381: LGTM: GCP network name rules and immutability.

Pattern and immutability align with GCP constraints.

Also applies to: 5385-5387


5393-5402: LGTM: PSC subnet name rules and immutability.

Consistent with GCP subnet naming.

Also applies to: 5406-5408


5423-5423: LGTM: GCP project ID pattern.

Length and character rules are correct; hyphen not allowed at end is enforced.


5445-5493: resourceLabels: confirm list semantics and parity across CRDs.

You’ve chosen x-kubernetes-list-type: map keyed by “key” (good for uniqueness). Please confirm this intent is applied consistently to the non‑TechPreview CRDs to avoid drift. If parity isn’t desired, call it out in docs.


5494-5622: LGTM: Workload Identity Federation schema.

Field shapes, immutability, and email patterns look solid.

If you want an extra guard, we can add a CEL rule ensuring controlPlane/nodePool emails are not identical (optional).


5630-5638: LGTM: SA email ↔ project cross-field validation.

Simple and effective domain check against spec.gcp.project.

cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-TechPreviewNoUpgrade.crd.yaml (6)

5480-5496: GCP VPC network name: regex + immutability look good

Pattern matches GCP naming and locks the field. LGTM.


5501-5516: PSC subnet name: regex + immutability look good

Consistent with GCP naming and prevents day‑2 drift. LGTM.


5531-5531: Project ID validation looks correct

Length, charset, start/end constraints align with GCP guidance. LGTM.


5539-5548: Region format check is reasonable

The pattern enforces “area-locationN” and excludes zone suffixes. LGTM.

If you want extra safety, verify it still admits all current regions (e.g., northamerica-northeast1, australia-southeast2) as GCP adds regions over time.


5738-5746: Same‑project SA checks: nice cross‑field guard

EndsWith checks for controlPlane/nodePool against spec.platform.gcp.project are clear and cheap. LGTM.


5602-5730: Keep "gcp-" prefix validation — it's officially required

The "gcp-" prefix restriction is documented in Google Cloud's official Workload Identity documentation and REST API reference. The validation rules correctly implement this official constraint and should not be removed.

cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-CustomNoUpgrade.crd.yaml (6)

5661-5670: GCP network name validation looks good

Pattern and immutability match GCP resource naming rules.

Also applies to: 5674-5677


5682-5691: PSC subnet name validation looks good

Pattern and immutability align with GCP subnet naming.

Also applies to: 5695-5697


5712-5712: Project ID regex is correct

Enforces 6–30 chars, starts with letter, no trailing hyphen.


5720-5729: Region pattern acceptable

Covers current region formats and excludes zone suffixes.


5783-5852: poolID/providerID regex tightened correctly

Now requires leading letter and blocks reserved “gcp-” prefix; immutability is appropriate.


5854-5899: Service account email validation is solid

Domain constrained to PROJECT_ID.iam.gserviceaccount.com, hardened local/project patterns, and minLength consistent.

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to Reviews -> Disable Knowledge Base setting

📥 Commits

Reviewing files that changed from the base of the PR and between 9b470e5 and 9c15321.

📒 Files selected for processing (1)
  • api/hypershift/v1beta1/gcp.go (3 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**

⚙️ CodeRabbit configuration file

-Focus on major issues impacting performance, readability, maintainability and security. Avoid nitpicks and avoid verbosity.

Files:

  • api/hypershift/v1beta1/gcp.go
🧬 Code graph analysis (1)
api/hypershift/v1beta1/gcp.go (1)
client/applyconfiguration/hypershift/v1beta1/gcpresourcereference.go (1)
  • GCPResourceReference (28-30)
🪛 golangci-lint (2.5.0)
api/hypershift/v1beta1/gcp.go

[error] 228-228: : # github.com/openshift/hypershift/sync-global-pullsecret [github.com/openshift/hypershift/sync-global-pullsecret.test]
sync-global-pullsecret/sync-global-pullsecret_test.go:228:23: undefined: MockdbusConn
sync-global-pullsecret/sync-global-pullsecret_test.go:234:26: undefined: MockdbusConn
sync-global-pullsecret/sync-global-pullsecret_test.go:247:26: undefined: MockdbusConn
sync-global-pullsecret/sync-global-pullsecret_test.go:257:26: undefined: MockdbusConn
sync-global-pullsecret/sync-global-pullsecret_test.go:270:26: undefined: MockdbusConn
sync-global-pullsecret/sync-global-pullsecret_test.go:283:26: undefined: MockdbusConn
sync-global-pullsecret/sync-global-pullsecret_test.go:296:26: undefined: MockdbusConn
sync-global-pullsecret/sync-global-pullsecret_test.go:309:26: undefined: MockdbusConn
sync-global-pullsecret/sync-global-pullsecret_test.go:327:12: undefined: NewMockdbusConn

(typecheck)

🔇 Additional comments (8)
api/hypershift/v1beta1/gcp.go (8)

7-16: LGTM - Pattern simplification improves clarity.

The updated regex pattern ^[a-z]([-a-z0-9]*[a-z0-9])?$ is cleaner and aligns well with GCP resource naming requirements. The change from the previous pattern maintains the same constraints (start with lowercase letter, end with lowercase letter or number, hyphens allowed in the middle) with improved readability.


20-50: LGTM - GCPResourceLabel implementation is sound.

The label validation correctly implements GCP Compute Engine label requirements:

  • Key validation enforces RFC1035-like naming with the reserved "goog" prefix check
  • Value is properly optional with support for empty strings per GCP API
  • All constraints align with GCP documentation

70-78: LGTM - Immutability rules are appropriate.

Making Network and PrivateServiceConnectSubnet immutable after cluster creation is correct, as changing VPC configuration post-creation would break cluster connectivity.


82-83: LGTM - CEL validation correctly enforces project membership.

The XValidation rules properly verify that service account emails belong to the same project using contains('@') and endsWith(). This approach avoids the invalid split('@', 2) syntax from earlier drafts.


96-114: LGTM - Project and Region patterns are correctly tightened.

Both patterns now properly enforce GCP naming requirements:

  • Project: enforces 6-30 character length with proper start/end constraints
  • Region: requires exactly one hyphen and trailing digits, correctly excluding zone suffixes

128-138: LGTM - ResourceLabels configuration is appropriate.

The listType=map with listMapKey=key ensures unique keys, and MaxItems=60 appropriately reserves headroom for system labels within GCP's 64-label limit.


140-156: LGTM - WorkloadIdentity configuration is well-documented.

The field is correctly marked as required and immutable, with comprehensive documentation covering prerequisites and the authentication chain. The omitzero tag is appropriate for the struct field.


158-223: LGTM - WIF configuration validation is comprehensive.

All fields have appropriate validation:

  • ProjectNumber correctly validates numeric GCP project identifiers
  • PoolID and ProviderID patterns enforce 4-32 character length with proper constraints
  • Reserved "gcp-" prefix checks prevent conflicts with Google system resources
  • Immutability protects the authentication chain

Comment thread api/hypershift/v1beta1/gcp.go
@apahim
apahim force-pushed the gcp_wif_api branch 2 times, most recently from 746f28a to 3231ee8 Compare December 3, 2025 12:41
Update vendor files and dependencies to support upcoming GCP WIF types:
- k8s.io/utils updates for compatibility
- Go module dependency updates

These dependency updates are required for the GCP Workload Identity
Federation implementation and ensure compatibility across the codebase.

Signed-off-by: Amador Pahim <apahim@redhat.com>
Commit-Message-Assisted-by: Claude (via Claude Code)

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 3

♻️ Duplicate comments (10)
api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/GCPPlatform.yaml (1)

4846-4848: Fix off‑by‑one: GSA email minLength 38 rejects valid addresses.

Minimal valid length is 37 (6 + 1 + 6 + 24). Pattern already permits 37; schema must too.

Apply:

-                                minLength: 38
+                                minLength: 37

And for nodePool:

-                                minLength: 38
+                                minLength: 37

Verification (also checks other CRD variants):

#!/bin/bash
rg -nC2 -e 'gserviceaccount\.com' -e 'minLength:\s*3[7-8]' api cmd | sed -n '1,200p'

Also applies to: 4866-4868

docs/content/reference/api.md (1)

6299-6304: Fix broken regex/pattern for GCP resource names (doc bug).

Pattern currently includes an HTML anchor and is not a valid regex. Replace with a copy/paste‑able pattern and keep the 63‑char note.

Use:

- Pattern: “^<a href="[-a-z0-9]*[a-z0-9]">a-z</a>?$” (max 63 chars), per GCP naming requirements.
+ Pattern: `^[a-z]([-a-z0-9]{0,61}[a-z0-9])?$` (max 63 chars), per GCP naming requirements.

Note: Put the regex in backticks in the source Go comment (e.g., api/hypershift/v1beta1/gcp.go), then regenerate docs (make api-docs).

api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/GCPPlatform.yaml (1)

4846-4854: Allow underscores in label values per GCE docs.

Compute Engine label values may include underscores; current regex/description reject them. Update both to avoid blocking valid inputs.

Suggested change:

-                              description: |-
-                                value is the value part of the label. A label value can have a maximum of 63 characters.
-                                Empty values are allowed by GCP. If non-empty, it must start with a lowercase letter,
-                                contain only lowercase letters, digits, or hyphens, and end with a lowercase letter or digit.
+                              description: |-
+                                value is the value part of the label. A label value can have a maximum of 63 characters.
+                                Empty values are allowed by GCP. If non-empty, it must start with a lowercase letter,
+                                and may contain only lowercase letters, digits, underscores (_), or hyphens (-).
@@
-                              pattern: ^$|^[a-z]([-a-z0-9]{0,61}[a-z0-9])?$
+                              pattern: ^$|^[a-z][a-z0-9_-]{0,62}$

To verify there are no lingering non-underscore patterns across generated CRDs and sources, run:

#!/bin/bash
# Find label value patterns that still exclude underscores
rg -n -C2 -S "pattern:\s*\^\$\|\^\[a-z]\(\[-a-z0-9\]\{0,61\}\[a-z0-9\]\)\?\$" api/ cmd/ || true

# Show occurrences that already include underscores (expected)
rg -n -C2 -S "pattern:\s*\^\$\|\^\[a-z]\[a-z0-9_-\]\{0,62\}\$" api/ cmd/ || true
api/hypershift/v1beta1/gcp.go (1)

242-244: Adjust MinLength from 38 to 37 to match the pattern's actual minimum.

The regex pattern enforces a minimum of 37 characters:

  • Service account name: 6 chars min ([a-z] + [a-z0-9-]{4,28} (min 4) + [a-z0-9])
  • @: 1 char
  • Project ID: 6 chars min
  • Domain: 24 chars (.iam.gserviceaccount.com)
  • Total: 37 chars

Setting MinLength=38 creates an off-by-one error where valid 37-character emails like aaaaaa@bbbbbb.iam.gserviceaccount.com would be rejected.

Apply this diff to both fields:

-// +kubebuilder:validation:MinLength=38
+// +kubebuilder:validation:MinLength=37

Also applies to: 262-264

cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-TechPreviewNoUpgrade.crd.yaml (2)

5431-5440: Region regex fix looks correct.

Accepts valid regions (e.g., us-central1, europe-west12, northamerica-northeast1) and rejects zones; description aligns.


5445-5493: Labels: uniqueness + headroom implemented correctly.

Using list-map semantics keyed by ‘key’ with maxItems: 60 prevents duplicates and preserves system label headroom.

cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-TechPreviewNoUpgrade.crd.yaml (1)

5565-5593: GCP label value pattern is too restrictive; must allow underscores and leading digits.

According to official GCP documentation, Compute Engine label values allow lowercase letters, digits, underscores, and hyphens. The current pattern ^$|^[a-z]([-a-z0-9]{0,61}[a-z0-9])?$ incorrectly forbids underscores and requires leading letters instead of allowing leading digits.

Apply:

-                              pattern: ^$|^[a-z]([-a-z0-9]{0,61}[a-z0-9])?$
+                              pattern: ^$|^[a-z0-9][a-z0-9_-]{0,62}$

Update the description to mention "letter or digit" instead of just "lowercase letter" and add "underscores (_) allowed."

cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-CustomNoUpgrade.crd.yaml (2)

5919-5927: Fix project match: endsWith() is spoofable; compare domain exactly after '@'.

Suffix collisions like sa@other-myproj.iam.gserviceaccount.com will pass for project "myproj". Split on '@' and compare the domain exactly.

-                      rule: self.workloadIdentity.serviceAccountsEmails.controlPlane.contains('@')
-                        && self.workloadIdentity.serviceAccountsEmails.controlPlane.endsWith('@'
-                        + self.project + '.iam.gserviceaccount.com')
+                      rule: self.workloadIdentity.serviceAccountsEmails.controlPlane.split("@", 2)[1] == self.project + ".iam.gserviceaccount.com"
...
-                      rule: self.workloadIdentity.serviceAccountsEmails.nodePool.contains('@')
-                        && self.workloadIdentity.serviceAccountsEmails.nodePool.endsWith('@'
-                        + self.project + '.iam.gserviceaccount.com')
+                      rule: self.workloadIdentity.serviceAccountsEmails.nodePool.split("@", 2)[1] == self.project + ".iam.gserviceaccount.com"

5734-5781: Label regex too strict; allow underscores and relaxed ending per GCP label rules.

Keys/values currently reject valid labels (no “_”, no trailing “-”). GCP labels allow underscores; values may be empty and need not start with a letter. Update patterns to match GCP behavior.

-                              pattern: ^[a-z]([-a-z0-9]{0,61}[a-z0-9])?$
+                              pattern: ^[a-z][a-z0-9_-]{0,62}$

-                              pattern: ^$|^[a-z]([-a-z0-9]{0,61}[a-z0-9])?$
+                              pattern: ^$|^[a-z0-9_-]{1,63}$

Optional (list semantics): prefer array + CEL uniqueness over listType=map to avoid SSA merge surprises.

-                        x-kubernetes-list-map-keys:
-                        - key
-                        x-kubernetes-list-type: map
+                        x-kubernetes-validations:
+                        - message: resourceLabels keys must be unique
+                          rule: self == null || self.all(l1, self.exists_one(l2, l1.key == l2.key))
cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-CustomNoUpgrade.crd.yaml (1)

5926-5939: Tighten projectNumber maxLength to match GCP int64 limits

GCP project numbers are int64 values with a maximum of 19 decimal digits (9,223,372,036,854,775,807). Reduce maxLength from 25 to 19 to enforce stricter validation and prevent accepting invalid inputs.

-                            maxLength: 25
+                            maxLength: 19
🧹 Nitpick comments (5)
docs/content/reference/api.md (2)

6220-6272: Align label charset with GCP Compute labels (underscores).

Doc says keys/values allow only letters, digits, hyphens. Compute Engine labels allow underscores (_) too; keys 1–63 chars, start with a lowercase letter; values up to 63, empty allowed.

Please update the copy to include underscores (and keep the reserved "goog" prefix note), or explicitly state you’re intentionally stricter than GCP.

Would you verify against the latest “Organize resources using labels” docs and adjust this section accordingly?


6325-6366: Document least‑privilege for nodePool GSA; add SA User nuance.

Add that when the VM SA differs from the controller’s GSA, grant roles/iam.serviceAccountUser on that VM SA; if using roles/iam.workloadIdentityUser to impersonate the same SA, SA User isn’t needed.

Suggested tweak:

  This GSA requires the following IAM roles:
  - roles/compute.instanceAdmin.v1 (Compute Instance Admin v1)
  - roles/compute.networkAdmin (Compute Network Admin)
+ - If a distinct VM service account is attached to instances, also grant
+   roles/iam.serviceAccountUser on that VM SA to the controller GSA.

Ensure this aligns with cmd/infra/gcp/iam-bindings.json.

cmd/cluster/gcp/create_test.go (1)

62-75: Validation tests correctly cover new required flags; consider adding a couple more cases

Using a fully-populated validOpts and then deriving “missing X” cases is a solid pattern and the new tests for missing project, region, and network align with the CLI validation messages. Since the implementation now also requires private-service-connect-subnet, WIF IDs, and both service accounts, you might optionally add a couple of representative “missing workload identity field” cases to catch regressions in those error paths as well, but this is not strictly required.

Also applies to: 77-101, 103-115

cmd/cluster/gcp/create.go (1)

85-113: Requiring all WIF/network fields at validation time matches the WIF-only design; optional: add shallow format checks

The validation now enforces presence of network, PSC subnet, WIF project number, pool/provider IDs, and both service account emails, which is appropriate given the current “Workload Identity only” support. This ensures incomplete CLI invocations fail fast before attempting cluster creation.

If you want to improve UX further, you could optionally add lightweight format checks here (e.g., numeric check for project number, or a basic GSA email shape) to surface obvious mistakes earlier instead of relying solely on API/CRD validation, but that’s not strictly necessary.

cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-CustomNoUpgrade.crd.yaml (1)

5841-5890: Labels: uniqueness is enforced; consider clarifying reserved-prefix wording

  • Good: list-map semantics prevent duplicate keys; RFC1035-style constraints are consistent for Compute Engine.
  • Wording nit: the description states “GCP reserves the 'goog' prefix...”, while the validation intentionally blocks any 'goog*'. Clarify it’s a product choice to avoid confusion with Google-reserved 'goog-'.

Apply wording tweak:

-                                GCP reserves the 'goog' prefix for system labels.
+                                We reserve any key starting with 'goog' to avoid collisions with Google‑reserved 'goog-' system labels.
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to Reviews -> Disable Knowledge Base setting

📥 Commits

Reviewing files that changed from the base of the PR and between 9c15321 and 966a9e0.

⛔ Files ignored due to path filters (14)
  • api/go.sum is excluded by !**/*.sum
  • api/vendor/k8s.io/utils/buffer/ring_growing.go is excluded by !**/vendor/**
  • api/vendor/k8s.io/utils/clock/testing/fake_clock.go is excluded by !**/vendor/**
  • api/vendor/k8s.io/utils/lru/lru.go is excluded by !**/vendor/**
  • api/vendor/modules.txt is excluded by !**/vendor/**
  • go.sum is excluded by !**/*.sum
  • vendor/github.com/openshift/hypershift/api/hypershift/v1beta1/gcp.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/openshift/hypershift/api/hypershift/v1beta1/hostedcluster_conditions.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/openshift/hypershift/api/hypershift/v1beta1/hostedcluster_types.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/openshift/hypershift/api/hypershift/v1beta1/zz_generated.deepcopy.go is excluded by !vendor/**, !**/vendor/**
  • vendor/k8s.io/utils/buffer/ring_growing.go is excluded by !vendor/**, !**/vendor/**
  • vendor/k8s.io/utils/clock/testing/fake_clock.go is excluded by !vendor/**, !**/vendor/**
  • vendor/k8s.io/utils/lru/lru.go is excluded by !vendor/**, !**/vendor/**
  • vendor/modules.txt is excluded by !vendor/**, !**/vendor/**
📒 Files selected for processing (22)
  • api/go.mod (1 hunks)
  • api/hypershift/v1beta1/gcp.go (3 hunks)
  • api/hypershift/v1beta1/hostedcluster_conditions.go (1 hunks)
  • api/hypershift/v1beta1/hostedcluster_types.go (1 hunks)
  • api/hypershift/v1beta1/zz_generated.deepcopy.go (4 hunks)
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/GCPPlatform.yaml (2 hunks)
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/GCPPlatform.yaml (2 hunks)
  • client/applyconfiguration/hypershift/v1beta1/gcpplatformspec.go (2 hunks)
  • client/applyconfiguration/hypershift/v1beta1/gcpresourcelabel.go (1 hunks)
  • client/applyconfiguration/hypershift/v1beta1/gcpserviceaccountsemails.go (1 hunks)
  • client/applyconfiguration/hypershift/v1beta1/gcpworkloadidentityconfig.go (1 hunks)
  • client/applyconfiguration/utils.go (1 hunks)
  • cmd/cluster/gcp/create.go (4 hunks)
  • cmd/cluster/gcp/create_test.go (3 hunks)
  • cmd/cluster/gcp/testdata/zz_fixture_TestCreateCluster_minimal_flags_necessary_to_render.yaml (1 hunks)
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-CustomNoUpgrade.crd.yaml (2 hunks)
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-TechPreviewNoUpgrade.crd.yaml (2 hunks)
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-CustomNoUpgrade.crd.yaml (2 hunks)
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-TechPreviewNoUpgrade.crd.yaml (2 hunks)
  • docs/content/reference/api.md (5 hunks)
  • go.mod (1 hunks)
  • test/e2e/v2/tests/api_ux_validation_test.go (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (7)
  • api/hypershift/v1beta1/hostedcluster_conditions.go
  • api/hypershift/v1beta1/hostedcluster_types.go
  • client/applyconfiguration/hypershift/v1beta1/gcpserviceaccountsemails.go
  • client/applyconfiguration/hypershift/v1beta1/gcpworkloadidentityconfig.go
  • cmd/cluster/gcp/testdata/zz_fixture_TestCreateCluster_minimal_flags_necessary_to_render.yaml
  • client/applyconfiguration/hypershift/v1beta1/gcpplatformspec.go
  • client/applyconfiguration/hypershift/v1beta1/gcpresourcelabel.go
🧰 Additional context used
📓 Path-based instructions (1)
**

⚙️ CodeRabbit configuration file

-Focus on major issues impacting performance, readability, maintainability and security. Avoid nitpicks and avoid verbosity.

Files:

  • go.mod
  • client/applyconfiguration/utils.go
  • api/go.mod
  • cmd/cluster/gcp/create.go
  • test/e2e/v2/tests/api_ux_validation_test.go
  • cmd/cluster/gcp/create_test.go
  • api/hypershift/v1beta1/zz_generated.deepcopy.go
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/GCPPlatform.yaml
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/GCPPlatform.yaml
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-TechPreviewNoUpgrade.crd.yaml
  • api/hypershift/v1beta1/gcp.go
  • docs/content/reference/api.md
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-CustomNoUpgrade.crd.yaml
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-CustomNoUpgrade.crd.yaml
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-TechPreviewNoUpgrade.crd.yaml
🧬 Code graph analysis (5)
client/applyconfiguration/utils.go (4)
client/applyconfiguration/hypershift/v1beta1/gcpresourcelabel.go (1)
  • GCPResourceLabelApplyConfiguration (22-25)
client/applyconfiguration/hypershift/v1beta1/gcpresourcereference.go (1)
  • GCPResourceReferenceApplyConfiguration (22-24)
client/applyconfiguration/hypershift/v1beta1/gcpserviceaccountsemails.go (1)
  • GCPServiceAccountsEmailsApplyConfiguration (22-25)
client/applyconfiguration/hypershift/v1beta1/gcpworkloadidentityconfig.go (1)
  • GCPWorkloadIdentityConfigApplyConfiguration (22-27)
cmd/cluster/gcp/create.go (4)
cmd/util/util.go (1)
  • ValidateRequiredOption (11-16)
api/hypershift/v1beta1/gcp.go (4)
  • GCPNetworkConfig (67-79)
  • GCPResourceReference (6-18)
  • GCPWorkloadIdentityConfig (161-223)
  • GCPServiceAccountsEmails (227-267)
client/applyconfiguration/hypershift/v1beta1/gcpworkloadidentityconfig.go (1)
  • GCPWorkloadIdentityConfig (31-33)
client/applyconfiguration/hypershift/v1beta1/gcpserviceaccountsemails.go (1)
  • GCPServiceAccountsEmails (29-31)
test/e2e/v2/tests/api_ux_validation_test.go (3)
test/e2e/util/crd.go (1)
  • HasFieldInCRDSchema (15-38)
api/hypershift/v1beta1/hostedcluster_types.go (2)
  • HostedCluster (2013-2026)
  • GCPPlatform (1205-1205)
api/hypershift/v1beta1/gcp.go (6)
  • GCPPlatformSpec (84-156)
  • GCPNetworkConfig (67-79)
  • GCPResourceReference (6-18)
  • GCPWorkloadIdentityConfig (161-223)
  • GCPServiceAccountsEmails (227-267)
  • GCPResourceLabel (23-50)
cmd/cluster/gcp/create_test.go (1)
cmd/cluster/gcp/create.go (2)
  • RawCreateOptions (31-58)
  • CreateOptions (127-130)
api/hypershift/v1beta1/gcp.go (4)
client/applyconfiguration/hypershift/v1beta1/gcpresourcereference.go (1)
  • GCPResourceReference (28-30)
client/applyconfiguration/hypershift/v1beta1/gcpresourcelabel.go (1)
  • GCPResourceLabel (29-31)
client/applyconfiguration/hypershift/v1beta1/gcpworkloadidentityconfig.go (1)
  • GCPWorkloadIdentityConfig (31-33)
client/applyconfiguration/hypershift/v1beta1/gcpserviceaccountsemails.go (1)
  • GCPServiceAccountsEmails (29-31)
🪛 golangci-lint (2.5.0)
api/hypershift/v1beta1/gcp.go

[error] 228-228: : # github.com/openshift/hypershift/sync-global-pullsecret [github.com/openshift/hypershift/sync-global-pullsecret.test]
sync-global-pullsecret/sync-global-pullsecret_test.go:228:23: undefined: MockdbusConn
sync-global-pullsecret/sync-global-pullsecret_test.go:234:26: undefined: MockdbusConn
sync-global-pullsecret/sync-global-pullsecret_test.go:247:26: undefined: MockdbusConn
sync-global-pullsecret/sync-global-pullsecret_test.go:257:26: undefined: MockdbusConn
sync-global-pullsecret/sync-global-pullsecret_test.go:270:26: undefined: MockdbusConn
sync-global-pullsecret/sync-global-pullsecret_test.go:283:26: undefined: MockdbusConn
sync-global-pullsecret/sync-global-pullsecret_test.go:296:26: undefined: MockdbusConn
sync-global-pullsecret/sync-global-pullsecret_test.go:309:26: undefined: MockdbusConn
sync-global-pullsecret/sync-global-pullsecret_test.go:327:12: undefined: NewMockdbusConn

(typecheck)

🔇 Additional comments (40)
go.mod (1)

293-295: Dependency pin for k8s.io/utils looks intentional and consistent

The replace/pin with an explanatory comment matches other targeted overrides in this module and is a reasonable way to align with the Kubernetes 1.32.3 stack. No issues from a correctness or maintainability perspective.

client/applyconfiguration/utils.go (1)

176-183: New GCP WIF ForKind mappings are correct and idiomatic

The added cases for GCPResourceLabel, GCPServiceAccountsEmails, and GCPWorkloadIdentityConfig follow the existing pattern and return the expected apply configuration types; this should seamlessly enable client-side apply for the new GCP WIF APIs.

api/hypershift/v1beta1/zz_generated.deepcopy.go (5)

1488-1495: Deep copy for GCPPlatformSpec correctly handles new fields

The updated GCPPlatformSpec.DeepCopyInto now deep-copies the ResourceLabels slice element‑by‑element and copies WorkloadIdentity by value. Given the new GCP types are value-only (or have their own DeepCopy), this prevents shared mutable state while keeping the implementation minimal.


1614-1632: GCPResourceLabel DeepCopy correctly handles pointer field

The DeepCopy implementation allocates a new Value string when non‑nil and otherwise relies on value copy for the rest, which matches the struct’s shape and avoids pointer aliasing.


1649-1662: GCPServiceAccountsEmails DeepCopy is sufficient for its value-only fields

Using *out = *in is appropriate here since the type has no pointer, map, or slice fields; no risk of shared mutable state.


1664-1678: GCPWorkloadIdentityConfig DeepCopy matches the new type’s structure

The implementation copies the struct by value, including ServiceAccountsEmails, which itself is value-only. This is correct and keeps the DeepCopy minimal while preserving isolation.


3438-3442: DeepCopy for PlatformSpec.GCP is now correctly delegated

Switching the GCP branch in PlatformSpec.DeepCopyInto to allocate a new GCPPlatformSpec and call DeepCopyInto ensures the new nested slice (ResourceLabels) and WIF config are fully deep‑copied instead of shallowly assigned. This brings GCP in line with other complex platform specs.

api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/GCPPlatform.yaml (7)

4634-4650: GCP network name + immutability look good.

Pattern and immutability rule match GCP constraints.


4655-4671: PSC subnet name + immutability look good.

Matches GCP naming and locks the field post‑create.


4685-4685: Project ID regex is correct.

Length and charset align with GCP rules; anchors prevent edge cases.


4693-4702: Region validation looks right.

Single hyphen, trailing digits, lowercase; covers known regions.


4706-4755: Labels: solid constraints and map semantics.

  • Correct key/value patterns (lowercase, hyphens), reserved “goog” blocked.
  • List‑map keyed by “key” prevents dupes; SSA‑friendly.

4756-4884: WIF fields and immutability are well‑scoped.

poolID/providerID patterns, reserved prefix blocks, projectNumber numeric, and per‑field immutability look correct.


4891-4900: Project consistency check is good.

CEL endsWith() guards ensure SA project matches spec.platform.gcp.project.

api/go.mod (1)

90-92: LGTM! Correct k8s.io/utils version pinned.

The replace directive correctly pins k8s.io/utils to v0.0.0-20241104100929-3ea5e8cea738, which aligns with the k8s.io/client-go v0.32.3 dependency as discussed in the previous review. The comment clearly documents the rationale.

test/e2e/v2/tests/api_ux_validation_test.go (2)

343-672: Comprehensive GCP WIF validation test coverage.

The new test context thoroughly exercises GCP Workload Identity Federation validation rules with well-structured acceptance and rejection scenarios. Tests cover:

  • Valid and invalid ProjectNumber, PoolID, ProviderID formats
  • Reserved prefix validation ('gcp-' and 'goog')
  • Service account email format validation
  • Resource label constraints (key/value format, max 60 items)

The BeforeEach guard properly skips tests when GCP CRD fields are unavailable, and all tests follow consistent patterns with the rest of the file.


1949-1981: Well-designed helper functions for validation testing.

The testHostedClusterCreation and testNodePoolCreation helpers effectively reduce code duplication across validation tests. The double-deletion pattern (defer + explicit delete) is appropriate for validation test scenarios:

  • The defer ensures cleanup in all code paths (panic, early return, normal completion)
  • The explicit delete after Create ensures immediate cleanup when creation succeeds
  • Both deletions safely ignore errors, handling cases where the resource doesn't exist

This defensive approach is good practice for test isolation and resource cleanup.

docs/content/reference/api.md (2)

5062-5072: New GCP conditions look good.

ValidGCPCredentials and ValidGCPWorkloadIdentity add useful observability. No issues found.


5977-5982: Region validation text LGTM.

Examples and constraints read well and are accurate.

cmd/cluster/gcp/create_test.go (2)

25-43: ApplyPlatformSpecifics wiring is exercised end-to-end and looks correct

The test now builds a RawCreateOptions with all new network and Workload Identity fields and asserts each one is present in HostedCluster.Spec.Platform.GCP (including nested NetworkConfig and WorkloadIdentity.ServiceAccountsEmails). This gives good coverage of the new ApplyPlatformSpecifics wiring; no issues spotted.

Also applies to: 53-59


130-150: CLI flag plumbing for new GCP options is covered via render test

Extending the “minimal flags necessary to render” scenario with the new network, PSC subnet, Workload Identity, and service account flags ensures they are accepted and flow through the generic core.CreateCluster path without breaking rendering. This is a good high-level integration check; no problems identified.

cmd/cluster/gcp/create.go (2)

18-28: Flag constants, raw options, and bindings are consistent and aligned with API types

The new flag names (--network, --private-service-connect-subnet, WIF IDs, and service accounts) match the tests and are clearly documented, including references to hypershift infra create gcp for sourcing values. The corresponding RawCreateOptions fields and BindOptions wiring are straightforward and map 1:1 to the future API fields. No functional or maintainability issues here.

Also applies to: 30-58, 60-71


175-198: ApplyPlatformSpecifics correctly populates new GCP network and Workload Identity fields

The new NetworkConfig and WorkloadIdentity blocks are populated directly from the validated options and align with the corresponding API types (GCPNetworkConfig, GCPResourceReference, GCPWorkloadIdentityConfig, GCPServiceAccountsEmails). This should satisfy the API’s +required and immutability constraints from the outset. Wiring looks correct and cohesive.

api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/GCPPlatform.yaml (1)

4742-4757: LGTM on GCP naming, region, and CEL cross-field checks.

  • Network/subnet name patterns and immutability: good.
  • Project ID pattern: matches GCP constraints.
  • Region doc and regex: matches current GCP region format.
  • CEL endsWith/contains for GSA domain binding: safe and correct.

Also applies to: 4764-4778, 4793-4793, 4801-4810, 5000-5008

api/hypershift/v1beta1/gcp.go (5)

7-18: LGTM! GCPResourceReference pattern updated correctly.

The updated pattern ^[a-z]([-a-z0-9]*[a-z0-9])?$ correctly implements GCP resource naming standards, allowing hyphens anywhere in the middle while enforcing lowercase letters/digits at boundaries.


20-50: LGTM! GCPResourceLabel validation is well-designed.

The implementation correctly handles GCP Compute Engine label requirements:

  • Key validation blocks the reserved 'goog' prefix via XValidation
  • Value is properly optional (*string with omitempty) to allow empty values per GCP API
  • Patterns enforce RFC1035-style constraints (no underscores, lowercase only)
  • MaxItems=60 on the parent list (line 137) leaves headroom for HyperShift system labels

66-79: LGTM! Immutability constraints prevent breaking changes.

The XValidation rules self == oldSelf on Network and PrivateServiceConnectSubnet correctly prevent modifications after cluster creation, which is essential since these underpin the Private Service Connect networking model.


81-156: LGTM! Cross-field validation ensures consistency.

The XValidation rules on lines 82-83 correctly enforce that service account emails belong to the cluster's project by validating they end with @{project}.iam.gserviceaccount.com. The WorkloadIdentity field's immutability and required status are appropriate given the feature-gated nature of GCP support.


158-223: LGTM! WIF configuration fields have strong validation.

The GCPWorkloadIdentityConfig type correctly validates:

  • ProjectNumber as numeric-only string
  • PoolID and ProviderID with reserved prefix checks ('gcp-' blocked)
  • All WIF fields immutable to prevent breaking the authentication chain

The extensive documentation references (hypershift infra create gcp, IAM role requirements) help users understand the prerequisites.

cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-TechPreviewNoUpgrade.crd.yaml (4)

5372-5388: LGTM: GCP network and PSC subnet name validation + immutability.

Patterns match GCP rules and object immutability is correctly enforced.

Also applies to: 5393-5408


5414-5427: LGTM: Project ID pattern.

Bounds and charset align with GCP project-id constraints; immutable as expected.


5630-5638: LGTM: SA email belongs-to-project check.

CEL endsWith guard is clear and resilient; contains('@') avoids false positives.


5507-5528: The "gcp-" prefix reservation is correct.

Verified against Google Cloud IAM Workload Identity Federation documentation: the "gcp-" prefix is indeed reserved by Google for both Workload Identity Pool IDs and Provider IDs and cannot be used. The validation rule, character restrictions, and length constraints (4–32 characters, lowercase letters/digits/hyphens only, no leading/trailing hyphens) all align with official Google Cloud specifications.

cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-TechPreviewNoUpgrade.crd.yaml (2)

5537-5548: Region regex rejects valid multi-hyphen regions (e.g., northamerica-northeast1).

Your pattern only allows a single hyphen: ^[a-z]+-[a-z]+[0-9]+$. Permit additional hyphenated location segments.

Apply:

-                        pattern: ^[a-z]+-[a-z]+[0-9]+$
+                        pattern: ^[a-z]+-[a-z]+(?:-[a-z]+)*[0-9]+$

Likely an incorrect or invalid review comment.


5569-5583: GCP label key pattern must allow underscores to match GCP requirements.

The current pattern forbids underscores, but Google Cloud Compute Engine allows label keys to contain lowercase letters, digits, underscores, and dashes. Keys must start with a lowercase letter and end with a letter or digit (1-63 characters total).

Apply:

-                              pattern: ^[a-z]([-a-z0-9]{0,61}[a-z0-9])?$
+                              pattern: ^[a-z][a-z0-9_-]{0,61}[a-z0-9]$

Keep the reserved prefix rule for "goog" as-is.

Likely an incorrect or invalid review comment.

cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-CustomNoUpgrade.crd.yaml (5)

5769-5785: Network and PSC subnet naming + immutability: LGTM

Patterns match GCP rules and immutability guards are correct.

Also applies to: 5791-5805


5811-5824: Project ID validation: LGTM

Regex and bounds align with GCP’s 6–30, lowercase/digits/hyphens, start letter, no trailing hyphen.


5826-5837: Region validation text and pattern: LGTM

Pattern allows known regions (e.g., us-central1, europe-west12, northamerica-northeast1). Docs clearly exclude zones.


5967-6007: Service account email regex and minLength: LGTM

Pattern is strict and minLength 38 matches the shortest possible address (6+1+6+1+24).


6026-6035: Cross-field SA→project ownership checks: LGTM

Ends-with guard ties both GSAs to the specified project; simple and effective.

Comment thread docs/content/reference/api.md

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 5

♻️ Duplicate comments (8)
api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/GCPPlatform.yaml (1)

4846-4847: GSA email minLength off by one (rejects valid 6‑char IDs).

Minimal valid address length is 37 chars (6 + 1 + 6 + 24). Current minLength: 38 will reject valid addresses.

Apply this diff to both controlPlane and nodePool:

-                                minLength: 38
+                                minLength: 37

Also applies to: 4866-4867

api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/GCPPlatform.yaml (2)

4954-4976: Off-by-one: minLength for GSA emails should be 37 (not 38).

Shortest valid: 6(local) + 1(@) + 6(project) + 24(".iam.gserviceaccount.com") = 37. Current 38 rejects valid addresses. Fix both controlPlane and nodePool.

Apply this diff:

-                                minLength: 38
+                                minLength: 37
@@
-                                minLength: 38
+                                minLength: 37

4814-4863: Update label value pattern to allow underscores as per GCP documentation.

GCP Compute Engine label values allow lowercase letters, digits, underscores (_), and dashes (-). The current pattern ^$|^[a-z]([-a-z0-9]{0,61}[a-z0-9])?$ excludes underscores and unnecessarily restricts the ending character. Update the description and regex to ^$|^[a-z][a-z0-9_-]{0,62}$:

-                              description: |-
-                                value is the value part of the label. A label value can have a maximum of 63 characters.
-                                Empty values are allowed by GCP. If non-empty, it must start with a lowercase letter,
-                                contain only lowercase letters, digits, or hyphens, and end with a lowercase letter or digit.
+                              description: |-
+                                value is the value part of the label. A label value can have a maximum of 63 characters.
+                                Empty values are allowed by GCP. If non-empty, it must start with a lowercase letter,
+                                and may contain only lowercase letters, digits, underscores (_), or hyphens (-).
                                See https://cloud.google.com/compute/docs/labeling-resources for Compute Engine label requirements.
@@
-                              pattern: ^$|^[a-z]([-a-z0-9]{0,61}[a-z0-9])?$
+                              pattern: ^$|^[a-z][a-z0-9_-]{0,62}$
docs/content/reference/api.md (1)

6299-6304: Replace broken name regex; remove HTML anchor.

The “Pattern” includes an HTML link and is not a valid regex. Use a copy/paste‑able pattern and wrap it in backticks in the source Go comment, then regenerate docs.

- Pattern: “^<a href="[-a-z0-9]*[a-z0-9]">a-z</a>?$” (max 63 chars) ...
+ Pattern: `^[a-z]([-a-z0-9]{0,61}[a-z0-9])?$` (max 63 chars), per GCP naming requirements.

Tip: apply in api/hypershift/v1beta1/gcp.go comments and run make api-docs.

api/hypershift/v1beta1/gcp.go (1)

240-246: MinLength=38 creates an off-by-one inconsistency with the pattern.

The regex pattern's minimum valid email is 37 characters:

  • Service account name: 6 chars (1 + 4 + 1)
  • @: 1 char
  • Project ID: 6 chars (1 + 4 + 1)
  • Domain .iam.gserviceaccount.com: 24 chars
  • Total: 37 chars

A valid 37-character email like aaaaaa@bbbbbb.iam.gserviceaccount.com would be rejected by MinLength=38 despite matching the pattern.

-// +kubebuilder:validation:MinLength=38
+// +kubebuilder:validation:MinLength=37

The same fix applies to controlPlane at line 263.

cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-TechPreviewNoUpgrade.crd.yaml (1)

5553-5600: Label value regex too strict — allow leading digits and underscores per GCP.

Current value pattern forbids leading digits and underscores, rejecting valid labels like "2025" or "ci_build". Update description and pattern to match GCP Compute label rules; keep keys as-is.

Apply this diff:

@@
-                            value:
-                              description: |-
-                                value is the value part of the label. A label value can have a maximum of 63 characters.
-                                Empty values are allowed by GCP. If non-empty, it must start with a lowercase letter,
-                                contain only lowercase letters, digits, or hyphens, and end with a lowercase letter or digit.
+                            value:
+                              description: |-
+                                value is the value part of the label. A label value can have a maximum of 63 characters.
+                                Empty values are allowed by GCP. If non-empty, it must start with a lowercase letter or digit,
+                                may contain only lowercase letters, digits, underscores, or hyphens, and must end with a lowercase letter or digit.
@@
-                              pattern: ^$|^[a-z]([-a-z0-9]{0,61}[a-z0-9])?$
+                              pattern: ^$|^[a-z0-9][a-z0-9_-]{0,62}$
cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-CustomNoUpgrade.crd.yaml (2)

5734-5782: GCP label key/value regex too strict — underscores must be allowed.

GCP Compute Engine labels permit underscores in keys and values; current patterns reject them, blocking valid configs.

Apply:

-                              pattern: ^[a-z]([-a-z0-9]{0,61}[a-z0-9])?$
+                              pattern: ^[a-z]([a-z0-9_-]{0,61}[a-z0-9])?$
-                              pattern: ^$|^[a-z]([-a-z0-9]{0,61}[a-z0-9])?$
+                              pattern: ^$|^[a-z]([a-z0-9_-]{0,61}[a-z0-9])?$

Also consider avoiding list-map semantics here and enforce key uniqueness with a CEL rule at the array level to prevent SSA merge surprises. This was suggested earlier.


5919-5927: endsWith-based project check is vulnerable to suffix collisions — compare domain exactly.

Use split('@',2)[1] equality for both controlPlane and nodePool to prevent false positives like sa@other-myproj.iam....

Apply:

-                    - message: controlPlane service account must belong to the same project
-                      rule: self.workloadIdentity.serviceAccountsEmails.controlPlane.contains('@')
-                        && self.workloadIdentity.serviceAccountsEmails.controlPlane.endsWith('@'
-                        + self.project + '.iam.gserviceaccount.com')
-                    - message: nodePool service account must belong to the same project
-                      rule: self.workloadIdentity.serviceAccountsEmails.nodePool.contains('@')
-                        && self.workloadIdentity.serviceAccountsEmails.nodePool.endsWith('@'
-                        + self.project + '.iam.gserviceaccount.com')
+                    - message: controlPlane service account must belong to the same project
+                      rule: self.workloadIdentity.serviceAccountsEmails.controlPlane.split("@", 2)[1] == self.project + ".iam.gserviceaccount.com"
+                    - message: nodePool service account must belong to the same project
+                      rule: self.workloadIdentity.serviceAccountsEmails.nodePool.split("@", 2)[1] == self.project + ".iam.gserviceaccount.com"
🧹 Nitpick comments (7)
api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/GCPPlatform.yaml (1)

4892-4900: Simplify CEL checks for SA project match.

The contains('@') guard is redundant; endsWith alone suffices and reduces noise.

-  rule: self.workloadIdentity.serviceAccountsEmails.controlPlane.contains('@')
-    && self.workloadIdentity.serviceAccountsEmails.controlPlane.endsWith('@' + self.project + '.iam.gserviceaccount.com')
+  rule: self.workloadIdentity.serviceAccountsEmails.controlPlane.endsWith('@' + self.project + '.iam.gserviceaccount.com')

Do the same for nodePool.

docs/content/reference/api.md (1)

6333-6341: Clarify when Service Account User is needed for NodePool GSA.

If the VM’s service account differs from the controller’s GSA, note that the controller principal needs roles/iam.serviceAccountUser on the VM SA to attach it to instances. If identical and assumed via WIF, this can be omitted.

cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-CustomNoUpgrade.crd.yaml (1)

5926-5936: Tighten projectNumber maxLength to 19 digits

GCP project numbers are int64; a numeric string over 19 digits isn’t valid. Recommend maxLength: 19 (pattern remains ^[0-9]+$).

Apply:

-                            maxLength: 25
+                            maxLength: 19
api/hypershift/v1beta1/gcp.go (2)

33-38: Inconsistent +required marker with omitempty json tag on Key field.

The Key field is marked +required but has json:"key,omitempty". For required fields, using omitempty can lead to the field being silently omitted during serialization if it's an empty string, which contradicts the required semantics.

Consider removing omitempty from the json tag:

-	Key string `json:"key,omitempty"`
+	Key string `json:"key"`

169-176: Inconsistent +required with omitempty on required string fields.

Similar to the Key field, projectNumber, poolID, and providerID are all marked +required but use omitempty json tags. This creates an inconsistency where required fields could be silently omitted during serialization.

Consider using omitzero (Go 1.24+) or removing omitempty for consistency with required semantics:

-	ProjectNumber string `json:"projectNumber,omitempty"`
+	ProjectNumber string `json:"projectNumber"`

The same applies to poolID (line 195) and providerID (line 214).

cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-TechPreviewNoUpgrade.crd.yaml (2)

5385-5387: Soften immutability to field-level to preserve forward-compat.

Freezing the entire object (self == oldSelf) blocks adding future non-identity fields. Prefer freezing only .name.

Apply:

- x-kubernetes-validations:
- - message: Network is immutable
-   rule: self == oldSelf
+ x-kubernetes-validations:
+ - message: Network name is immutable
+   rule: self.name == oldSelf.name

5406-5408: Limit subnet immutability to .name.

Same rationale as network: keep .name immutable but allow future extra fields without forcing object equality.

- x-kubernetes-validations:
- - message: Private Service Connect subnet is immutable
-   rule: self == oldSelf
+ x-kubernetes-validations:
+ - message: Private Service Connect subnet name is immutable
+   rule: self.name == oldSelf.name
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to Reviews -> Disable Knowledge Base setting

📥 Commits

Reviewing files that changed from the base of the PR and between 9c15321 and 966a9e0.

⛔ Files ignored due to path filters (14)
  • api/go.sum is excluded by !**/*.sum
  • api/vendor/k8s.io/utils/buffer/ring_growing.go is excluded by !**/vendor/**
  • api/vendor/k8s.io/utils/clock/testing/fake_clock.go is excluded by !**/vendor/**
  • api/vendor/k8s.io/utils/lru/lru.go is excluded by !**/vendor/**
  • api/vendor/modules.txt is excluded by !**/vendor/**
  • go.sum is excluded by !**/*.sum
  • vendor/github.com/openshift/hypershift/api/hypershift/v1beta1/gcp.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/openshift/hypershift/api/hypershift/v1beta1/hostedcluster_conditions.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/openshift/hypershift/api/hypershift/v1beta1/hostedcluster_types.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/openshift/hypershift/api/hypershift/v1beta1/zz_generated.deepcopy.go is excluded by !vendor/**, !**/vendor/**
  • vendor/k8s.io/utils/buffer/ring_growing.go is excluded by !vendor/**, !**/vendor/**
  • vendor/k8s.io/utils/clock/testing/fake_clock.go is excluded by !vendor/**, !**/vendor/**
  • vendor/k8s.io/utils/lru/lru.go is excluded by !vendor/**, !**/vendor/**
  • vendor/modules.txt is excluded by !vendor/**, !**/vendor/**
📒 Files selected for processing (22)
  • api/go.mod (1 hunks)
  • api/hypershift/v1beta1/gcp.go (3 hunks)
  • api/hypershift/v1beta1/hostedcluster_conditions.go (1 hunks)
  • api/hypershift/v1beta1/hostedcluster_types.go (1 hunks)
  • api/hypershift/v1beta1/zz_generated.deepcopy.go (4 hunks)
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/GCPPlatform.yaml (2 hunks)
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/GCPPlatform.yaml (2 hunks)
  • client/applyconfiguration/hypershift/v1beta1/gcpplatformspec.go (2 hunks)
  • client/applyconfiguration/hypershift/v1beta1/gcpresourcelabel.go (1 hunks)
  • client/applyconfiguration/hypershift/v1beta1/gcpserviceaccountsemails.go (1 hunks)
  • client/applyconfiguration/hypershift/v1beta1/gcpworkloadidentityconfig.go (1 hunks)
  • client/applyconfiguration/utils.go (1 hunks)
  • cmd/cluster/gcp/create.go (4 hunks)
  • cmd/cluster/gcp/create_test.go (3 hunks)
  • cmd/cluster/gcp/testdata/zz_fixture_TestCreateCluster_minimal_flags_necessary_to_render.yaml (1 hunks)
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-CustomNoUpgrade.crd.yaml (2 hunks)
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-TechPreviewNoUpgrade.crd.yaml (2 hunks)
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-CustomNoUpgrade.crd.yaml (2 hunks)
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-TechPreviewNoUpgrade.crd.yaml (2 hunks)
  • docs/content/reference/api.md (5 hunks)
  • go.mod (1 hunks)
  • test/e2e/v2/tests/api_ux_validation_test.go (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (5)
  • api/go.mod
  • api/hypershift/v1beta1/hostedcluster_types.go
  • client/applyconfiguration/hypershift/v1beta1/gcpplatformspec.go
  • go.mod
  • client/applyconfiguration/hypershift/v1beta1/gcpserviceaccountsemails.go
🧰 Additional context used
📓 Path-based instructions (1)
**

⚙️ CodeRabbit configuration file

-Focus on major issues impacting performance, readability, maintainability and security. Avoid nitpicks and avoid verbosity.

Files:

  • cmd/cluster/gcp/create.go
  • client/applyconfiguration/hypershift/v1beta1/gcpworkloadidentityconfig.go
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/GCPPlatform.yaml
  • cmd/cluster/gcp/testdata/zz_fixture_TestCreateCluster_minimal_flags_necessary_to_render.yaml
  • api/hypershift/v1beta1/hostedcluster_conditions.go
  • test/e2e/v2/tests/api_ux_validation_test.go
  • cmd/cluster/gcp/create_test.go
  • api/hypershift/v1beta1/zz_generated.deepcopy.go
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/GCPPlatform.yaml
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-CustomNoUpgrade.crd.yaml
  • client/applyconfiguration/hypershift/v1beta1/gcpresourcelabel.go
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-TechPreviewNoUpgrade.crd.yaml
  • api/hypershift/v1beta1/gcp.go
  • docs/content/reference/api.md
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-CustomNoUpgrade.crd.yaml
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-TechPreviewNoUpgrade.crd.yaml
  • client/applyconfiguration/utils.go
🧬 Code graph analysis (6)
client/applyconfiguration/hypershift/v1beta1/gcpworkloadidentityconfig.go (2)
client/applyconfiguration/hypershift/v1beta1/gcpserviceaccountsemails.go (1)
  • GCPServiceAccountsEmailsApplyConfiguration (22-25)
api/hypershift/v1beta1/gcp.go (1)
  • GCPWorkloadIdentityConfig (161-223)
api/hypershift/v1beta1/hostedcluster_conditions.go (1)
api/hypershift/v1beta1/hosted_controlplane.go (1)
  • ConditionType (294-294)
test/e2e/v2/tests/api_ux_validation_test.go (2)
test/e2e/util/crd.go (1)
  • HasFieldInCRDSchema (15-38)
api/hypershift/v1beta1/gcp.go (6)
  • GCPPlatformSpec (84-156)
  • GCPNetworkConfig (67-79)
  • GCPResourceReference (6-18)
  • GCPWorkloadIdentityConfig (161-223)
  • GCPServiceAccountsEmails (227-267)
  • GCPResourceLabel (23-50)
cmd/cluster/gcp/create_test.go (1)
cmd/cluster/gcp/create.go (2)
  • RawCreateOptions (31-58)
  • CreateOptions (127-130)
client/applyconfiguration/hypershift/v1beta1/gcpresourcelabel.go (1)
api/hypershift/v1beta1/gcp.go (1)
  • GCPResourceLabel (23-50)
api/hypershift/v1beta1/gcp.go (5)
test/e2e/util/external_oidc.go (1)
  • Key (289-292)
client/applyconfiguration/hypershift/v1beta1/gcpresourcereference.go (1)
  • GCPResourceReference (28-30)
client/applyconfiguration/hypershift/v1beta1/gcpresourcelabel.go (1)
  • GCPResourceLabel (29-31)
client/applyconfiguration/hypershift/v1beta1/gcpworkloadidentityconfig.go (1)
  • GCPWorkloadIdentityConfig (31-33)
client/applyconfiguration/hypershift/v1beta1/gcpserviceaccountsemails.go (1)
  • GCPServiceAccountsEmails (29-31)
🪛 golangci-lint (2.5.0)
api/hypershift/v1beta1/gcp.go

[error] 228-228: : # github.com/openshift/hypershift/sync-global-pullsecret [github.com/openshift/hypershift/sync-global-pullsecret.test]
sync-global-pullsecret/sync-global-pullsecret_test.go:228:23: undefined: MockdbusConn
sync-global-pullsecret/sync-global-pullsecret_test.go:234:26: undefined: MockdbusConn
sync-global-pullsecret/sync-global-pullsecret_test.go:247:26: undefined: MockdbusConn
sync-global-pullsecret/sync-global-pullsecret_test.go:257:26: undefined: MockdbusConn
sync-global-pullsecret/sync-global-pullsecret_test.go:270:26: undefined: MockdbusConn
sync-global-pullsecret/sync-global-pullsecret_test.go:283:26: undefined: MockdbusConn
sync-global-pullsecret/sync-global-pullsecret_test.go:296:26: undefined: MockdbusConn
sync-global-pullsecret/sync-global-pullsecret_test.go:309:26: undefined: MockdbusConn
sync-global-pullsecret/sync-global-pullsecret_test.go:327:12: undefined: NewMockdbusConn

(typecheck)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Red Hat Konflux / hypershift-cli-mce-211-on-pull-request
🔇 Additional comments (43)
api/hypershift/v1beta1/hostedcluster_conditions.go (1)

154-163: LGTM! Well-structured condition definitions.

Both new GCP condition types follow established naming conventions and documentation patterns. The placement among other platform-specific validation conditions is logical, and the comments clearly explain when these conditions would fail and the expected remediation approach.

cmd/cluster/gcp/create_test.go (3)

30-59: LGTM! Comprehensive test coverage for new GCP fields.

The test properly initializes all new GCP-related fields and verifies their propagation through nested structures (NetworkConfig, WorkloadIdentity, ServiceAccountsEmails). Test data follows valid GCP naming conventions.


65-116: LGTM! Good refactoring and valuable new test case.

The refactoring to use a validOpts base improves readability and maintainability by eliminating duplication across test cases. The new "missing network" test case (lines 92-96) properly validates that network is now a required field.


139-145: LGTM! CLI flags properly integrated.

The new flags for GCP fields are correctly added to the minimal rendering test, ensuring the CLI can parse and use these fields. Flag values are consistent with test data used elsewhere.

api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/GCPPlatform.yaml (6)

4634-4649: Network name regex and immutability look solid.

Pattern matches GCP resource naming and immutability is correctly enforced.


4655-4670: PSC subnet name validation is correct.

Regex and immutability align with GCP requirements.


4676-4689: GCP project ID validation: LGTM.

Length/pattern and immutability match GCP guidelines.


4691-4705: Region format check: good coverage.

Regex blocks zones and enforces one hyphen + trailing digits; immutability set.


4706-4755: Labels: regexes and reserved prefix block are correct; list‑map avoids dup keys.

This is SSA‑friendly and matches GCE label constraints.


4786-4790: WIF IDs and immutability: good constraints.

Reserved prefix checks for pool/provider and top‑level immutability read well.

Also applies to: 4821-4825, 4882-4884

api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/GCPPlatform.yaml (8)

4742-4758: LGTM: network name validation + immutability guard are correct.

Pattern matches GCP resource naming and immutability is enforced.


4764-4778: LGTM: PSC subnet name validation + immutability guard are correct.

Consistent with GCP naming rules; immutable as expected.


4793-4793: LGTM: project ID regex matches GCP constraints.

Start letter, [a-z0-9-], 6–30 chars, no trailing hyphen.


4801-4809: LGTM: region validation.

Regex and docs text accept current region formats like us-central1, europe-west12, northamerica-northeast1.


4877-4897: LGTM: poolID rules + reserved “gcp-” check and immutability.

Regex bounds are sound; CEL guard blocks reserved prefix and mutations.


4926-4933: LGTM: providerID rules + reserved “gcp-” check and immutability.

Symmetric to poolID; looks good.


4997-4997: LGTM: workloadIdentity required under GCP (feature-gated CRD).

Acceptable since this CRD is gated; no upgrade risk for GA paths.


5000-5008: LGTM: CEL domain check for GSA emails.

Using contains() + endsWith() avoids split()/indexing pitfalls and handles malformed input safely.

cmd/cluster/gcp/testdata/zz_fixture_TestCreateCluster_minimal_flags_necessary_to_render.yaml (1)

42-53: LGTM! Test fixture correctly demonstrates the new WIF API.

The workload identity configuration is properly structured with valid test data. Service account emails correctly reference the project ID, and all field formats align with GCP conventions.

client/applyconfiguration/utils.go (1)

176-183: LGTM! Generated code properly extends ForKind for new GCP WIF types.

The three new cases for GCPResourceLabel, GCPServiceAccountsEmails, and GCPWorkloadIdentityConfig follow the existing pattern and are correctly placed within the hypershift v1beta1 group.

client/applyconfiguration/hypershift/v1beta1/gcpresourcelabel.go (1)

20-47: Generated apply-configuration for GCPResourceLabel looks correct

Struct fields and fluent setters are consistent with the corresponding API type and applyconfiguration patterns; nothing to fix here.

cmd/cluster/gcp/create.go (1)

18-58: GCP create options and WIF wiring into HostedCluster look consistent

The new raw options, flag bindings, required-field validation, and ApplyPlatformSpecifics mapping to GCPPlatformSpec.NetworkConfig and GCPWorkloadIdentityConfig (including ServiceAccountsEmails) align with the API definitions and the WIF‑only design for GCP. No issues from a correctness or maintainability standpoint.

Also applies to: 60-71, 84-113, 175-201

client/applyconfiguration/hypershift/v1beta1/gcpworkloadidentityconfig.go (1)

20-65: Apply-configuration for GCPWorkloadIdentityConfig matches API shape

Field set and fluent With* builders correctly mirror GCPWorkloadIdentityConfig and its nested GCPServiceAccountsEmails applyconfig, enabling predictable declarative usage.

api/hypershift/v1beta1/zz_generated.deepcopy.go (1)

1485-1496: New GCP deepcopy implementations correctly handle ResourceLabels and WorkloadIdentity

  • GCPResourceLabel.DeepCopyInto safely duplicates the optional Value *string.
  • GCPPlatformSpec.DeepCopyInto now deep-copies the ResourceLabels slice and includes WorkloadIdentity.
  • PlatformSpec.DeepCopyInto delegates to GCPPlatformSpec.DeepCopyInto for the GCP branch.

Given the current field shapes (all value types except the label value pointer), this avoids aliasing issues and matches how other platform structs are deep-copied.

Also applies to: 1614-1678, 3401-3442

cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-CustomNoUpgrade.crd.yaml (3)

5841-5890: Labels map semantics look solid

Using x-kubernetes-list-type: map with x-kubernetes-list-map-keys: ["key"] prevents duplicate keys; regex/lengths align with your RFC1035 intent. No issues.


5968-6006: Service account email minLength is correct

minLength: 38 matches the minimum possible: 6 (sa) + 1 ('@') + 6 (project) + 25 (".iam.gserviceaccount.com") = 38. Regex also enforces structure. LGTM.


6024-6024: Confirm gating of required workloadIdentity across CRDs

Since workloadIdentity is required here by design, verify it's only required in the gated manifests and not in GA CRDs by checking all hostedclusters CRD variants (CustomNoUpgrade, CustomUpgrade, GA versions).

api/hypershift/v1beta1/gcp.go (4)

6-18: LGTM!

The GCPResourceReference type has well-documented naming constraints that align with GCP resource naming standards. The pattern and length validations are consistent.


66-79: LGTM!

The immutability validations on Network and PrivateServiceConnectSubnet are correctly implemented using CEL rules.


81-84: Good fix for the CEL validation rules.

The XValidation rules now use contains('@') and endsWith() instead of the previously flagged invalid split('@', 2) syntax. This approach is simpler and correctly validates that service account emails belong to the configured project.


127-156: Well-structured WIF configuration with comprehensive validation.

The resourceLabels and workloadIdentity additions follow good practices:

  • resourceLabels uses +listType=map with +listMapKey=key for proper map semantics
  • MaxItems=60 leaves headroom for system labels (64 total GCP limit)
  • omitzero on struct types (workloadIdentity, serviceAccountsEmails) is the correct serialization choice
  • Immutability enforcement is consistent across all WIF-related fields
cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-TechPreviewNoUpgrade.crd.yaml (6)

5372-5381: GCP network name regex is correct.

Matches GCE naming rules (lowercase, digits, hyphens; start with letter; end with letter/digit; ≤63 chars). LGTM.


5393-5402: GCP PSC subnet name regex is correct.

Consistent with GCE naming requirements. LGTM.


5414-5427: Project ID validation looks good.

Length (6–30), charset, start/end rules, and immutability are correct. LGTM.


5431-5440: Region validation is sane and matches current GCP regions.

Pattern enforces two segments and digit suffix (e.g., us-central1, europe-west12, northamerica-northeast1). LGTM.


5445-5493: resourceLabels: solid schema, headroom preserved.

  • list-map semantics keyed by key ensure uniqueness.
  • maxItems: 60 leaves space for system labels.
  • Key/value patterns + reserved 'goog' prefix block are correct.

LGTM.


5494-5622: Top-level immutability may serve a purpose beyond field-level validation; verification needed.

The review suggests removing object-level self == oldSelf as redundant, but this overlooks a key distinction: field-level immutability protects only currently-defined fields. Removing the object-level rule would allow future optional fields to be added to an already-deployed configuration, potentially bypassing immutability for new fields. For a security-critical feature like Workload Identity Federation, the conservative dual-layer approach (both field-level and object-level immutability) may be intentional. Verify whether this design aligns with project conventions and whether parity exists across all CRD variants before removing the top-level constraint.

cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-TechPreviewNoUpgrade.crd.yaml (3)

5480-5496: LGTM on GCP naming and immutability rules.

Network/subnet name patterns, project ID regex, and region validation look correct and align with GCP constraints.

Also applies to: 5501-5516, 5531-5535, 5539-5548


5738-5746: Cross-field project ownership check for SA emails — good.

The endsWith('@{project}.iam.gserviceaccount.com') validations are a clear, low-cost guardrail.


5632-5635: The "gcp-" prefix restriction is correct and mandated by Google.

The validation rule blocking pool IDs starting with "gcp-" aligns with official GCP requirements. Per Google's IAM API reference and gcloud documentation, the "gcp-" prefix is reserved by Google for both Workload Identity Federation pool IDs and provider IDs. This restriction is not a false negative; it prevents users from creating pools/providers that would fail in GCP due to official naming constraints.

cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-CustomNoUpgrade.crd.yaml (3)

5661-5670: LGTM on GCP network/subnet naming, immutability, and project ID pattern.

Patterns align with GCP naming (start letter, lowercase/digits/hyphen, no trailing hyphen) and immutability is appropriate.

Also applies to: 5674-5676, 5682-5691, 5695-5697, 5712-5716


5805-5816: LGTM on poolID/providerID patterns (must start with a letter).

Good fix to enforce leading letter and immutability.

Also applies to: 5841-5852


5721-5729: Region regex rejects valid GCP regions (e.g., northamerica-northeast1).

Current pattern doesn’t allow hyphens inside the location segment. Allow hyphenated locations and still require trailing digits.

Apply:

-                        pattern: ^[a-z]+-[a-z]+[0-9]+$
+                        pattern: ^[a-z]+-[a-z]+(?:-[a-z]+)*[0-9]+$

Optionally clarify the description that the location segment may include hyphens (e.g., “northamerica-northeast1”).

Likely an incorrect or invalid review comment.

Comment thread docs/content/reference/api.md
Comment thread docs/content/reference/api.md
Comment thread docs/content/reference/api.md
Comment thread test/e2e/v2/tests/api_ux_validation_test.go
Add comprehensive GCP Workload Identity Federation (WIF) support for
secure, short-lived token-based authentication without storing
long-term service account keys.

API Changes:
- GCPWorkloadIdentityConfig: Core WIF configuration with immutable fields
- GCPServiceAccountsEmails: Service account mappings for different controllers
- GCPResourceReference: GCP resource naming patterns with validation
- GCPResourceLabel: GCP resource labeling with reserved prefix protection
- Enhanced GCPPlatformSpec with workloadIdentity and resourceLabels fields

Client Changes:
- Apply configuration builders for all new WIF types
- Fluent builder methods for programmatic resource creation
- Server-side apply support for GCP platform resources

CLI Changes:
- WIF flags: --wif-pool-id, --wif-provider-id, --wif-project-number
- Service account email flags for control plane and node pool
- Integration with existing GCP cluster creation workflow
- Updated test fixtures and validation coverage

Features:
- Immutable WIF configuration to prevent breaking auth chains
- Comprehensive validation patterns for GCP naming conventions
- Cross-validation ensuring service accounts belong to the same project
- Support for resource labeling with GCP-specific constraints

This enables secure cluster provisioning on GCP using modern
identity federation instead of long-lived service account keys.

Signed-off-by: Amador Pahim <apahim@redhat.com>
Commit-Message-Assisted-by: Claude (via Claude Code)
Signed-off-by: Amador Pahim <apahim@redhat.com>

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 4

♻️ Duplicate comments (14)
api/hypershift/v1beta1/gcp.go (2)

242-244: MinLength should be 37 to match the pattern's minimum.

The regex pattern ^[a-z][a-z0-9-]{4,28}[a-z0-9]@[a-z][a-z0-9-]{4,28}[a-z0-9]\.iam\.gserviceaccount\.com$ enforces a minimum length of:

  • Service account name: 6 chars (1 + 4 + 1)
  • @: 1 char
  • Project ID: 6 chars (1 + 4 + 1)
  • Domain suffix: 24 chars
  • Total: 37 chars

Setting MinLength=38 creates an off-by-one gap where valid 37-character emails matching the pattern (e.g., aaaaaa@bbbbbb.iam.gserviceaccount.com) would be rejected by the length constraint.

Apply this diff to align the validation:

-// +kubebuilder:validation:MinLength=38
+// +kubebuilder:validation:MinLength=37

262-264: MinLength should be 37 to match the pattern's minimum.

Same issue as the NodePool field: the pattern enforces a 37-character minimum, but MinLength=38 creates an off-by-one inconsistency.

Apply this diff:

-// +kubebuilder:validation:MinLength=38
+// +kubebuilder:validation:MinLength=37
api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/GCPPlatform.yaml (1)

4846-4854: Label value regex excludes underscores; GCP allows them.

GCP label values may contain lowercase letters, digits, underscores, and dashes (max 63 characters, empty allowed). The current pattern ^$|^[a-z]([-a-z0-9]{0,61}[a-z0-9])?$ and description omit underscores and enforce incorrect start/end constraints.

Update the pattern to include underscores and correct the description to match GCP requirements.

Proposed diff:

-                                Empty values are allowed by GCP. If non-empty, it must start with a lowercase letter,
-                                contain only lowercase letters, digits, or hyphens, and end with a lowercase letter or digit.
+                                Empty values are allowed by GCP. If non-empty, it must start with a lowercase letter,
+                                and may contain only lowercase letters, digits, underscores (_), or hyphens (-).
@@
-                              pattern: ^$|^[a-z]([-a-z0-9]{0,61}[a-z0-9])?$
+                              pattern: ^$|^[a-z][a-z0-9_-]{0,62}$
cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-TechPreviewNoUpgrade.crd.yaml (1)

5552-5600: Allow label values that start with a digit (GCP permits it).

GCP label values may be empty or start with a letter or digit. Current pattern forces a leading letter, rejecting valid values like “2025”. Relax the value regex and description accordingly.

Apply this diff:

-                              description: |-
-                                value is the value part of the label. A label value can have a maximum of 63 characters.
-                                Empty values are allowed by GCP. If non-empty, it must start with a lowercase letter,
-                                contain only lowercase letters, digits, or hyphens, and end with a lowercase letter or digit.
+                              description: |-
+                                value is the value part of the label. A label value can have a maximum of 63 characters.
+                                Empty values are allowed by GCP. If non-empty, it must start with a lowercase letter or digit,
+                                contain only lowercase letters, digits, or hyphens, and end with a lowercase letter or digit.
@@
-                              pattern: ^$|^[a-z]([-a-z0-9]{0,61}[a-z0-9])?$
+                              pattern: ^$|^[a-z0-9]([-a-z0-9]{0,61}[a-z0-9])?$
docs/content/reference/api.md (5)

6335-6343: Document least‑privilege note for nodePool/controlPlane GSAs (Service Account User vs WIF).

If the controller attaches a distinct VM SA, it needs roles/iam.serviceAccountUser on that VM SA; if using WIF impersonation with the same SA, call that out to avoid confusion.

  This GSA requires the following IAM roles:
   - roles/compute.instanceAdmin.v1 (Compute Instance Admin v1)
   - roles/compute.networkAdmin (Compute Network Admin)
+  - If a distinct VM service account is attached to instances, also grant
+    roles/iam.serviceAccountUser on that VM service account to the controller GSA.
+    When the controller GSA directly impersonates the same VM SA via
+    roles/iam.workloadIdentityUser, Service Account User is not additionally required.

Also applies to: 6355-6363


6299-6304: Broken regex/pattern for GCP resource names (HTML anchor inlined).

Replace the invalid anchor with a copy/paste‑able regex and clarify start/end constraints.

- Pattern: “^<a href="[-a-z0-9]*[a-z0-9]">a-z</a>?$” (max 63 chars), per GCP naming requirements.
+ Pattern: `^[a-z]([-a-z0-9]{0,61}[a-z0-9])?$` (max 63 chars), per GCP naming requirements.

Tip: wrap the regex in backticks in the Go doc comment and regenerate to prevent linkification. As per coding guidelines, ...


6439-6447: “serviceAccountsEmails,omitzero” leak indicates wrong struct tag; fix Go tags and regenerate.

Same tag issue as above; the field name includes “,omitzero”.

- <code>serviceAccountsEmails,omitzero</code>
+ <code>serviceAccountsEmails</code>

Action: fix the struct tag in the Go type and run make api-docs. As per coding guidelines, ...


6033-6046: “workloadIdentity,omitzero” leak indicates wrong struct tag; fix Go tags and regenerate.

The field name renders with “,omitzero”, implying a bad json tag option in the API type (should be “omitempty”). Fix the Go source tags and re-run docs gen.

- <code>workloadIdentity,omitzero</code>
+ <code>workloadIdentity</code>

Action: in api/hypershift/v1beta1 (GCP types), replace json:"...,omitzero,omitempty" with json:"...,omitempty" and make api-docs. As per coding guidelines, ...


5976-5982: Fix GCP region rule (“exactly one hyphen” is wrong).

Regions can contain multiple hyphens (e.g., northamerica-northeast1). Update the sentence accordingly.

- Must be in the form of <geographic-area>-<location><number> (e.g., us-central1, europe-west12).
- Must contain exactly one hyphen separating the geographic area from the location.
- Must end with one or more digits.
+ Must be one or more lowercase segments separated by hyphens and end with one or more digits
+ (e.g., us-central1, europe-west12, northamerica-northeast1).
+ Must not include a zone suffix (e.g., “-a”, “-b”).
test/e2e/v2/tests/api_ux_validation_test.go (1)

343-672: Past issue resolved; test coverage is comprehensive.

The GCPResourceLabel.Value initializations flagged in the previous review have all been corrected to use ptr.To() (lines 550-551, 578, 632, 645). The nil-value test case (line 605) correctly omits the Value field.

Test coverage for GCP WIF validation is thorough, including:

  • Valid WIF configuration with all required fields
  • Format validation (project number, pool/provider IDs, service account emails)
  • Reserved prefix checks (gcp-, goog)
  • Length constraints (poolID minimum 4 chars)
  • Resource label limits (max 60 items)
cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-CustomNoUpgrade.crd.yaml (1)

5926-5939: Tighten projectNumber maxLength to 19 digits.

maxLength: 25 is overly permissive. GCP project numbers are stored as int64 (automatically generated, read-only values), which limits them to a maximum value of 9,223,372,036,854,775,807—exactly 19 decimal digits. Reduce maxLength from 25 to 19 to align with the actual constraint.

-                            maxLength: 25
+                            maxLength: 19
cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-TechPreviewNoUpgrade.crd.yaml (1)

5584-5584: Fix off-by-one: service account email minLength should be 37 (not 38).

Shortest valid GSA email (6+1+6+24) is 37 chars; 38 rejects valid inputs. Update both controlPlane and nodePool.

-                                minLength: 38
+                                minLength: 37
...
-                                minLength: 38
+                                minLength: 37

Also applies to: 5604-5604

api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/GCPPlatform.yaml (1)

4846-4847: GSA email minLength off by one (rejects valid 6‑char IDs).

Minimal valid is 37 chars: 6 + 1 + 6 + 24. Current minLength 38 will reject edge‑valid emails.

Apply this diff in both places (controlPlane and nodePool):

-                                minLength: 38
+                                minLength: 37

Also applies to: 4866-4867

cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-CustomNoUpgrade.crd.yaml (1)

5919-5927: Make project-domain check exact; endsWith() is spoofable.

endsWith('@' + project + '.iam.gserviceaccount.com') can pass for wrong projects via suffix collisions. Compare the domain part exactly after '@'.

Apply:

-                      rule: self.workloadIdentity.serviceAccountsEmails.controlPlane.contains('@')
-                        && self.workloadIdentity.serviceAccountsEmails.controlPlane.endsWith('@'
-                        + self.project + '.iam.gserviceaccount.com')
+                      rule: self.workloadIdentity.serviceAccountsEmails.controlPlane.split("@", 2)[1]
+                        == self.project + ".iam.gserviceaccount.com"
-                      rule: self.workloadIdentity.serviceAccountsEmails.nodePool.contains('@')
-                        && self.workloadIdentity.serviceAccountsEmails.nodePool.endsWith('@'
-                        + self.project + '.iam.gserviceaccount.com')
+                      rule: self.workloadIdentity.serviceAccountsEmails.nodePool.split("@", 2)[1]
+                        == self.project + ".iam.gserviceaccount.com"
🧹 Nitpick comments (3)
cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-CustomNoUpgrade.crd.yaml (1)

5841-5890: Reserved label prefix: keep stricter rule, add doc note for clarity.

You intentionally ban any key starting with “goog” (stricter than GCP’s documented “goog-”). Keep it if desired, but add a short note to the Key field docs that this is intentionally stricter than GCP to avoid collisions. List‑map semantics for uniqueness look good.

cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-CustomNoUpgrade.crd.yaml (2)

5733-5782: Confirm intentional restriction of GCP label syntax (no underscores, last char must be alnum).

Current patterns disallow “_” and trailing “-”, which is stricter than typical GCP label rules. If this is product intent, fine; if not, consider allowing underscores and dropping the final-char requirement.


5779-5781: Prefer array + CEL uniqueness over list-type=map (to avoid SSA merge semantics).

If list-map semantics are discouraged, replace list-type=map with an array and add a CEL rule to enforce unique keys.

Example:

-                        x-kubernetes-list-map-keys:
-                        - key
-                        x-kubernetes-list-type: map
+                        x-kubernetes-validations:
+                        - message: resourceLabels keys must be unique
+                          rule: self == null || self.all(l1, self.exists_one(l2, l1.key == l2.key))
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to Reviews -> Disable Knowledge Base setting

📥 Commits

Reviewing files that changed from the base of the PR and between 966a9e0 and 7a93ad5.

📒 Files selected for processing (20)
  • api/hypershift/v1beta1/gcp.go (3 hunks)
  • api/hypershift/v1beta1/hostedcluster_conditions.go (1 hunks)
  • api/hypershift/v1beta1/hostedcluster_types.go (1 hunks)
  • api/hypershift/v1beta1/zz_generated.deepcopy.go (4 hunks)
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/GCPPlatform.yaml (2 hunks)
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/GCPPlatform.yaml (2 hunks)
  • client/applyconfiguration/hypershift/v1beta1/gcpplatformspec.go (2 hunks)
  • client/applyconfiguration/hypershift/v1beta1/gcpresourcelabel.go (1 hunks)
  • client/applyconfiguration/hypershift/v1beta1/gcpserviceaccountsemails.go (1 hunks)
  • client/applyconfiguration/hypershift/v1beta1/gcpworkloadidentityconfig.go (1 hunks)
  • client/applyconfiguration/utils.go (1 hunks)
  • cmd/cluster/gcp/create.go (4 hunks)
  • cmd/cluster/gcp/create_test.go (3 hunks)
  • cmd/cluster/gcp/testdata/zz_fixture_TestCreateCluster_minimal_flags_necessary_to_render.yaml (1 hunks)
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-CustomNoUpgrade.crd.yaml (2 hunks)
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-TechPreviewNoUpgrade.crd.yaml (2 hunks)
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-CustomNoUpgrade.crd.yaml (2 hunks)
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-TechPreviewNoUpgrade.crd.yaml (2 hunks)
  • docs/content/reference/api.md (5 hunks)
  • test/e2e/v2/tests/api_ux_validation_test.go (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (7)
  • client/applyconfiguration/hypershift/v1beta1/gcpserviceaccountsemails.go
  • cmd/cluster/gcp/create_test.go
  • client/applyconfiguration/hypershift/v1beta1/gcpplatformspec.go
  • client/applyconfiguration/utils.go
  • api/hypershift/v1beta1/hostedcluster_conditions.go
  • api/hypershift/v1beta1/zz_generated.deepcopy.go
  • cmd/cluster/gcp/testdata/zz_fixture_TestCreateCluster_minimal_flags_necessary_to_render.yaml
🧰 Additional context used
📓 Path-based instructions (1)
**

⚙️ CodeRabbit configuration file

-Focus on major issues impacting performance, readability, maintainability and security. Avoid nitpicks and avoid verbosity.

Files:

  • api/hypershift/v1beta1/hostedcluster_types.go
  • client/applyconfiguration/hypershift/v1beta1/gcpresourcelabel.go
  • client/applyconfiguration/hypershift/v1beta1/gcpworkloadidentityconfig.go
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-CustomNoUpgrade.crd.yaml
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/GCPPlatform.yaml
  • cmd/cluster/gcp/create.go
  • api/hypershift/v1beta1/gcp.go
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-TechPreviewNoUpgrade.crd.yaml
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-TechPreviewNoUpgrade.crd.yaml
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/GCPPlatform.yaml
  • docs/content/reference/api.md
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-CustomNoUpgrade.crd.yaml
  • test/e2e/v2/tests/api_ux_validation_test.go
🧬 Code graph analysis (3)
client/applyconfiguration/hypershift/v1beta1/gcpresourcelabel.go (1)
api/hypershift/v1beta1/gcp.go (1)
  • GCPResourceLabel (23-50)
client/applyconfiguration/hypershift/v1beta1/gcpworkloadidentityconfig.go (2)
client/applyconfiguration/hypershift/v1beta1/gcpserviceaccountsemails.go (1)
  • GCPServiceAccountsEmailsApplyConfiguration (22-25)
api/hypershift/v1beta1/gcp.go (1)
  • GCPWorkloadIdentityConfig (161-223)
api/hypershift/v1beta1/gcp.go (5)
test/e2e/util/external_oidc.go (1)
  • Key (289-292)
client/applyconfiguration/hypershift/v1beta1/gcpresourcereference.go (1)
  • GCPResourceReference (28-30)
client/applyconfiguration/hypershift/v1beta1/gcpresourcelabel.go (1)
  • GCPResourceLabel (29-31)
client/applyconfiguration/hypershift/v1beta1/gcpworkloadidentityconfig.go (1)
  • GCPWorkloadIdentityConfig (31-33)
client/applyconfiguration/hypershift/v1beta1/gcpserviceaccountsemails.go (1)
  • GCPServiceAccountsEmails (29-31)
🪛 golangci-lint (2.5.0)
api/hypershift/v1beta1/gcp.go

[error] 228-228: : # github.com/openshift/hypershift/sync-global-pullsecret [github.com/openshift/hypershift/sync-global-pullsecret.test]
sync-global-pullsecret/sync-global-pullsecret_test.go:228:23: undefined: MockdbusConn
sync-global-pullsecret/sync-global-pullsecret_test.go:234:26: undefined: MockdbusConn
sync-global-pullsecret/sync-global-pullsecret_test.go:247:26: undefined: MockdbusConn
sync-global-pullsecret/sync-global-pullsecret_test.go:257:26: undefined: MockdbusConn
sync-global-pullsecret/sync-global-pullsecret_test.go:270:26: undefined: MockdbusConn
sync-global-pullsecret/sync-global-pullsecret_test.go:283:26: undefined: MockdbusConn
sync-global-pullsecret/sync-global-pullsecret_test.go:296:26: undefined: MockdbusConn
sync-global-pullsecret/sync-global-pullsecret_test.go:309:26: undefined: MockdbusConn
sync-global-pullsecret/sync-global-pullsecret_test.go:327:12: undefined: NewMockdbusConn

(typecheck)

🔇 Additional comments (44)
client/applyconfiguration/hypershift/v1beta1/gcpresourcelabel.go (1)

1-47: LGTM! Generated apply-configuration code is correct.

The generated apply-configuration type correctly mirrors the GCPResourceLabel API type with appropriate builder methods for declarative configuration.

client/applyconfiguration/hypershift/v1beta1/gcpworkloadidentityconfig.go (1)

1-65: LGTM! Generated apply-configuration code is correct.

The generated apply-configuration type correctly mirrors the GCPWorkloadIdentityConfig API type with appropriate builder methods and nested ServiceAccountsEmails configuration.

cmd/cluster/gcp/create.go (4)

18-28: LGTM! Flag constants are well-defined.

The new flag constants follow the existing naming convention and cover all required GCP WIF and network configuration fields.


38-70: LGTM! Options and flag bindings are well-structured.

The new fields are well-documented, and the help text appropriately references the hypershift infra create gcp command as the source for WIF configuration values.


93-113: LGTM! Validation correctly enforces WIF requirements.

All WorkloadIdentity and network fields are validated as required, which aligns with the design decision to support WIF-only authentication for the initial GCP implementation.


181-197: LGTM! Platform-specific configuration is correctly applied.

The new GCP fields are properly populated into the HostedCluster spec, with correct mapping from CLI options to NetworkConfig and WorkloadIdentity API structures.

api/hypershift/v1beta1/gcp.go (5)

7-17: LGTM! GCP resource naming pattern is correct.

The updated pattern correctly enforces GCP resource naming requirements: start with lowercase letter, end with lowercase letter or digit, max 63 characters.


20-50: LGTM! GCPResourceLabel validation is comprehensive.

The type correctly implements GCP Compute Engine label requirements with proper RFC1035 validation, reserved prefix blocking, and support for optional empty values.


66-79: LGTM! Network immutability is properly enforced.

The XValidation rules correctly prevent modification of network configuration after cluster creation, which is appropriate for these infrastructure fields.


81-156: LGTM! GCPPlatformSpec extensions are well-designed.

The new ResourceLabels and WorkloadIdentity fields are properly validated with:

  • Cross-field CEL validation ensuring service accounts belong to the correct project
  • Appropriate list constraints and immutability rules
  • Comprehensive documentation referencing GCP standards

158-223: LGTM! WorkloadIdentity configuration is comprehensive.

The WIF configuration type includes:

  • Proper validation of GCP-specific identifiers (project number, pool ID, provider ID)
  • Reserved prefix blocking for 'gcp-' prefixes
  • Immutability enforcement to prevent breaking auth chains
  • Extensive documentation with prerequisites and references to infra commands
api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/GCPPlatform.yaml (2)

4801-4810: Region regex looks good.

Pattern and description align with current GCP region naming (one hyphen; ends with digits), e.g., us-central1, europe-west12, northamerica-northeast1.


5000-5008: CEL split fix + domain check LGTM.

Using contains('@') and endsWith(...) avoids split/TDZ pitfalls and guards malformed emails.

cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-TechPreviewNoUpgrade.crd.yaml (7)

5480-5489: GCP network name validation looks correct and immutable.

Pattern matches GCE standards and immutability rule is appropriate.

Also applies to: 5493-5495


5501-5510: PSC subnet name validation and immutability look good.

Matches GCE naming; immutability avoids day‑2 drift.

Also applies to: 5514-5516


5523-5535: Project ID validation: solid.

Length, charset, and edge constraints align with GCP guidance; immutability is right.


5539-5548: Region format validation LGTM.

The pattern accepts current GCP regions and blocks zones; immutability is appropriate.

Also applies to: 5550-5551


5680-5717: WIF SA email regex + immutability + project match checks look right.

Patterns, min lengths, and cross‑field validations enforce correct tenancy and prevent day‑2 drift.

Also applies to: 5723-5730


5738-5746: Cross‑field validation for SA domain matches project is correct.

EndsWith check enforces project consistency for both controlPlane and nodePool GSAs.


5629-5635: The validation rule correctly prevents IDs from using the 'gcp-' prefix. Google Cloud's official documentation explicitly reserves this prefix for Workload Identity Federation pool and provider IDs, making the check necessary and appropriate.

api/hypershift/v1beta1/hostedcluster_types.go (1)

133-135: GCP CAPI provider image annotation is consistent with existing patterns

The new ClusterAPIGCPProviderImage constant follows the established naming, documentation, and annotation-key patterns used for other CAPI provider image overrides (AWS, Azure, KubeVirt, Agent, PowerVS, OpenStack). No issues from a maintainability or API-shape perspective.

docs/content/reference/api.md (1)

5062-5072: LGTM on new GCP condition types.

The additions for ValidGCPCredentials and ValidGCPWorkloadIdentity read clearly and match the feature intent.

test/e2e/v2/tests/api_ux_validation_test.go (1)

1949-1981: LGTM: Clean test helper pattern.

The double-delete pattern (explicit + deferred) is appropriate for validation tests that only check API acceptance/rejection. The comment at line 1961 clearly explains the rationale.

cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-CustomNoUpgrade.crd.yaml (7)

5769-5785: LGTM: GCP network and PSC subnet naming + immutability are correct.

Patterns match GCP constraints and day‑2 immutability is appropriate.

Also applies to: 5791-5805


5812-5824: LGTM: GCP project ID validation.

Pattern prevents trailing hyphen and enforces 6–30 chars as intended; immutability OK.


5826-5840: LGTM: Region format validation.

Pattern covers examples like us-central1, europe-west12, northamerica-northeast1; immutability OK.


5904-5960: LGTM: Pool/Provider IDs validation and reserved “gcp-” prefix.

Patterns/lengths align with IAM WIF rules; reserved-prefix block is correct; immutability OK.


5967-6007: LGTM: Service account email regex and minLength.

Regex is hardened; minLength: 38 matches the true minimum (6 + 1 + 6 + len(".iam.gserviceaccount.com")=25).


6027-6035: LGTM: Cross-field checks for SA emails vs project.

CEL ensures both GSAs belong to the same project as spec.gcp.project.


6024-6024: Verify workloadIdentity gating in non-gated CRDs.

The concern is valid: workloadIdentity should only be required in gated CRDs (CustomNoUpgrade/TechPreviewNoUpgrade). Confirm that non-gated hostedclusters CRDs do not enforce workloadIdentity in their required fields, as HyperShift's feature-gate mechanism should prevent new gated fields from appearing in base CRD schemas.

cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-TechPreviewNoUpgrade.crd.yaml (6)

5372-5388: LGTM: GCP network and PSC subnet name validation + immutability.

Regex matches GCP Compute naming rules; immutability guard is appropriate.

Also applies to: 5393-5409


5414-5427: LGTM: GCP project ID constraints.

Length, charset, and start/end constraints align with GCP rules.


5429-5443: LGTM: Region validation.

Pattern accepts current regions (e.g., us-central1, europe-west12, northamerica-northeast1) and rejects zones. Immutability is correct.


5445-5493: LGTM: Resource labels schema.

RFC1035-style key/value, reserved 'goog' prefix block, map semantics for uniqueness, and 60-item cap for headroom look good.


5494-5622: LGTM: Workload Identity Federation block.

Reserved-prefix checks, per-field patterns, and immutability on pool/provider/projectNumber and emails are sound.


5630-5638: LGTM: Cross-field SA domain verification.

CEL ensures GSAs belong to the configured project.

api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/GCPPlatform.yaml (8)

4634-4643: GCP network name validation: LGTM.

Pattern/length + immutability match GCE rules.

Also applies to: 4647-4649


4655-4663: GCP subnet name validation: LGTM.

Consistent with GCE naming and made immutable.

Also applies to: 4668-4670


4676-4689: Project ID regex: LGTM.

6–30 chars, starts with letter, no trailing hyphen; immutability set.


4693-4705: Region format validation: LGTM.

Regex/description appropriately constrain regions (no zones), immutable.


4706-4755: Resource labels schema/regex: LGTM.

  • Keys/values align with GCE label rules.
  • Reserved 'goog' prefix blocked.
  • list‑map by key avoids duplicates.

4756-4885: WIF field validations: LGTM (pool/provider/projectNumber immutability, reserved prefixes, SA patterns).

Solid constraints and immutability. Fix the GSA minLength noted separately.

Please confirm there aren’t other CRD variants (non‑featuregated) where minLength still reads 38 to keep schemas consistent.


4886-4889: Making workloadIdentity required — verify backcompat.

This can block spec updates for existing GCP clusters without WIF populated. If intentional, OK; otherwise consider making it optional with controller defaults/migration notes.


4891-4900: CEL cross‑field checks for SA project match: LGTM.

Simple, effective guard against misconfigurations.

Comment thread docs/content/reference/api.md
@patjlm

patjlm commented Dec 3, 2025

Copy link
Copy Markdown
Contributor

/lgtm

@openshift-ci openshift-ci Bot added the lgtm Indicates that a PR is ready to be merged. label Dec 3, 2025
@patjlm

patjlm commented Dec 3, 2025

Copy link
Copy Markdown
Contributor

/verified later @apahim

@openshift-ci-robot openshift-ci-robot added verified-later verified Signifies that the PR passed pre-merge verification criteria labels Dec 3, 2025
@openshift-ci-robot

Copy link
Copy Markdown

@patjlm: This PR has been marked to be verified later by @apahim.

Details

In response to this:

/verified later @apahim

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.

@patjlm

patjlm commented Dec 3, 2025

Copy link
Copy Markdown
Contributor

/hold cancel

@openshift-ci openshift-ci Bot removed the do-not-merge/hold Indicates that a PR should not merge because someone has issued a /hold command. label Dec 3, 2025
@patjlm

patjlm commented Dec 3, 2025

Copy link
Copy Markdown
Contributor

/retest-required

@apahim

apahim commented Dec 3, 2025

Copy link
Copy Markdown
Contributor Author

/retest

@csrwng

csrwng commented Dec 3, 2025

Copy link
Copy Markdown
Contributor

/label acknowledge-critical-fixes-only

@openshift-ci openshift-ci Bot added the acknowledge-critical-fixes-only Indicates if the issuer of the label is OK with the policy. label Dec 3, 2025
@apahim

apahim commented Dec 3, 2025

Copy link
Copy Markdown
Contributor Author

/retest

@openshift-ci

openshift-ci Bot commented Dec 3, 2025

Copy link
Copy Markdown
Contributor

@apahim: all tests passed!

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.

@openshift-merge-bot
openshift-merge-bot Bot merged commit db10877 into openshift:main Dec 3, 2025
20 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

acknowledge-critical-fixes-only Indicates if the issuer of the label is OK with the policy. approved Indicates a PR has been approved by an approver from all required OWNERS files. area/api Indicates the PR includes changes for the API area/cli Indicates the PR includes changes for CLI area/documentation Indicates the PR includes changes for documentation area/platform/gcp PR/issue for GCP (GCPPlatform) platform area/testing Indicates the PR includes changes for e2e testing jira/valid-reference Indicates that this PR references a valid Jira ticket of any type. lgtm Indicates that a PR is ready to be merged. priority/critical-urgent Highest priority. Must be actively worked on as someone's top priority right now. verified Signifies that the PR passed pre-merge verification criteria verified-later

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants