Skip to content

✨ feature: migrate structural validation to kubebuilder CEL markers (Phase 1) - #444

Open
Vaishnav88sk wants to merge 1 commit into
open-cluster-management-io:mainfrom
Vaishnav88sk:feature/cel-validation-migration
Open

✨ feature: migrate structural validation to kubebuilder CEL markers (Phase 1)#444
Vaishnav88sk wants to merge 1 commit into
open-cluster-management-io:mainfrom
Vaishnav88sk:feature/cel-validation-migration

Conversation

@Vaishnav88sk

@Vaishnav88sk Vaishnav88sk commented Jul 18, 2026

Copy link
Copy Markdown

Summary

This PR implements Phase 1 of the CEL Validation Migration as outlined and approved in Enhancement Proposal #181.

It replaces legacy Go-based structural webhook validation with native Kubernetes +kubebuilder:validation:XValidation CEL markers directly on the Custom Resource structs.

Validations Migrated:

  • ManagedCluster: Enforced HTTPS format for Spec.ManagedClusterClientConfigs URLs and regex format for metadata.name.
  • ManagedClusterSetBinding: Enforced cross-field parity (metadata.name == spec.clusterSet).
  • ManifestWork: Enforced manifests array is not empty.

Note: The corresponding ValidatingAdmissionPolicy additions and FeatureGate operator updates (Phase 2) will be submitted in a follow-up PR to the ocm repository once this API change is merged.

Related issue(s)

Fixes phase 1 of open-cluster-management-io/ocm#1566

Summary by CodeRabbit

Summary by CodeRabbit

  • New Features

    • Added the CELValidation feature gate to enable native CEL-based API validation.
  • Bug Fixes

    • Enforced non-empty manifests for add-on templates, manifest works, and manifest replica sets.
    • Strengthened ManagedCluster validation: DNS-compatible name (≤63 chars), managedClusterClientConfigs max 32, and clientConfigs[].url must be a valid https URL with non-empty host (≤2048 chars).
    • Ensured ManagedClusterSetBinding names match spec.clusterSet.
  • Tests

    • Added an integration test verifying rejection of invalid ManagedCluster client URLs.

@openshift-ci
openshift-ci Bot requested review from jnpacker and mikeshng July 18, 2026 11:14
@openshift-ci

openshift-ci Bot commented Jul 18, 2026

Copy link
Copy Markdown
Contributor

[APPROVALNOTIFIER] This PR is NOT APPROVED

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

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

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

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

@coderabbitai

coderabbitai Bot commented Jul 18, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: b614a2d9-58dd-4ab9-8745-e6b3afce3b73

📥 Commits

Reviewing files that changed from the base of the PR and between 2153948 and 5fc06ed.

📒 Files selected for processing (11)
  • addon/v1alpha1/0000_03_addon.open-cluster-management.io_addontemplates.crd.yaml
  • addon/v1beta1/0000_03_addon.open-cluster-management.io_addontemplates.crd.yaml
  • cluster/v1/0000_00_clusters.open-cluster-management.io_managedclusters.crd.yaml
  • cluster/v1/types.go
  • cluster/v1beta2/0000_01_clusters.open-cluster-management.io_managedclustersetbindings.crd.yaml
  • cluster/v1beta2/types_managedclustersetbinding.go
  • feature/feature.go
  • test/integration/api/managedcluster_test.go
  • work/v1/0000_00_work.open-cluster-management.io_manifestworks.crd.yaml
  • work/v1/types.go
  • work/v1alpha1/0000_00_work.open-cluster-management.io_manifestworkreplicasets.crd.yaml
🚧 Files skipped from review as they are similar to previous changes (10)
  • addon/v1alpha1/0000_03_addon.open-cluster-management.io_addontemplates.crd.yaml
  • work/v1alpha1/0000_00_work.open-cluster-management.io_manifestworkreplicasets.crd.yaml
  • work/v1/0000_00_work.open-cluster-management.io_manifestworks.crd.yaml
  • cluster/v1beta2/0000_01_clusters.open-cluster-management.io_managedclustersetbindings.crd.yaml
  • addon/v1beta1/0000_03_addon.open-cluster-management.io_addontemplates.crd.yaml
  • test/integration/api/managedcluster_test.go
  • cluster/v1/0000_00_clusters.open-cluster-management.io_managedclusters.crd.yaml
  • work/v1/types.go
  • cluster/v1beta2/types_managedclustersetbinding.go
  • cluster/v1/types.go

Walkthrough

The PR adds an Alpha CEL validation feature gate and CRD constraints for non-empty manifests, HTTPS client URLs, ManagedCluster names, client-config list size, and matching ManagedClusterSetBinding names. An integration test covers rejection of a hostless HTTPS URL.

Changes

CRD validation updates

Layer / File(s) Summary
CEL validation feature gate
feature/feature.go
Adds CELValidation as a disabled-by-default Alpha feature gate in registration and work hubs.
ManagedCluster name and URL validation
cluster/v1/types.go, cluster/v1/0000_00_clusters...yaml, test/integration/api/managedcluster_test.go
Constrains names, client-config list size, and client URLs, with integration coverage for URLs lacking a host.
Non-empty manifest validation
work/v1/types.go, work/v1/..., addon/v1alpha1/..., addon/v1beta1/...
Manifest collections in AddOnTemplate, ManifestWork, and ManifestWorkReplicaSet schemas must contain at least one entry.
ManagedClusterSetBinding name validation
cluster/v1beta2/types_managedclustersetbinding.go, cluster/v1beta2/0000_01_clusters...yaml
The resource name must equal spec.clusterSet.

Estimated code review effort: 2 (Simple) | ~15 minutes

Possibly related PRs

Suggested reviewers: jnpacker

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title is clear, specific, and accurately summarizes the main change as a Phase 1 migration to kubebuilder CEL markers.
Description check ✅ Passed The description matches the template with Summary and Related issue(s), and it clearly states the Phase 1 scope and follow-up work.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 Checkov (3.3.8)
addon/v1alpha1/0000_03_addon.open-cluster-management.io_addontemplates.crd.yaml

Traceback (most recent call last):
File "/usr/local/bin/checkov", line 2, in
from checkov.main import Checkov
ModuleNotFoundError: No module named 'checkov'

addon/v1beta1/0000_03_addon.open-cluster-management.io_addontemplates.crd.yaml

Traceback (most recent call last):
File "/usr/local/bin/checkov", line 2, in
from checkov.main import Checkov
ModuleNotFoundError: No module named 'checkov'

cluster/v1/0000_00_clusters.open-cluster-management.io_managedclusters.crd.yaml

Traceback (most recent call last):
File "/usr/local/bin/checkov", line 2, in
from checkov.main import Checkov
ModuleNotFoundError: No module named 'checkov'

  • 3 others

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

❤️ Share

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

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

Inline comments:
In `@cluster/v1/types.go`:
- Around line 86-87: Replace the URL validation marker on the URL field in
cluster/v1/types.go:86-87 with a CEL expression that performs real URL
validation and requires an HTTPS scheme, rejecting malformed values such as
https://. Regenerate
cluster/v1/0000_00_clusters.open-cluster-management.io_managedclusters.crd.yaml:111-113
so its validation rule and message match the updated source marker.

In `@work/v1/types.go`:
- Around line 69-71: Make Manifests required in work/v1/types.go by removing its
optional marker while retaining the non-empty validation. Regenerate the CRDs so
the required-field schema is reflected in
work/v1/0000_00_work.open-cluster-management.io_manifestworks.crd.yaml, both
listed addon/v1alpha1 and addon/v1beta1 AddonTemplates locations, the second
addon/v1beta1 location, and
work/v1alpha1/0000_00_work.open-cluster-management.io_manifestworkreplicasets.crd.yaml;
no other schema changes are needed.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

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

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: faef0d51-045c-4ee7-8c02-f0ba16262ca3

📥 Commits

Reviewing files that changed from the base of the PR and between 403378b and 22dfdbf.

📒 Files selected for processing (9)
  • addon/v1alpha1/0000_03_addon.open-cluster-management.io_addontemplates.crd.yaml
  • addon/v1beta1/0000_03_addon.open-cluster-management.io_addontemplates.crd.yaml
  • cluster/v1/0000_00_clusters.open-cluster-management.io_managedclusters.crd.yaml
  • cluster/v1/types.go
  • cluster/v1beta2/0000_01_clusters.open-cluster-management.io_managedclustersetbindings.crd.yaml
  • cluster/v1beta2/types_managedclustersetbinding.go
  • work/v1/0000_00_work.open-cluster-management.io_manifestworks.crd.yaml
  • work/v1/types.go
  • work/v1alpha1/0000_00_work.open-cluster-management.io_manifestworkreplicasets.crd.yaml

Comment thread cluster/v1/types.go Outdated
Comment thread work/v1/types.go
Comment thread work/v1/types.go Outdated
@qiujian16

Copy link
Copy Markdown
Member

please add integration tests to test all the validations.

@Vaishnav88sk
Vaishnav88sk force-pushed the feature/cel-validation-migration branch from f9ddf0f to 2153948 Compare July 20, 2026 09:08

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 3

♻️ Duplicate comments (1)
work/v1/types.go (1)

69-71: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Make manifests required.

The +optional marker and omitempty still allow the field to be omitted, so size(self) > 0 does not enforce the intended invariant for absent values. Remove the optional marker and regenerate the affected CRDs. (kubernetes.io)

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

In `@work/v1/types.go` around lines 69 - 71, Make Manifests required by removing
its +optional marker and omitempty JSON tag, while retaining the non-empty
validation rule. Regenerate the affected CRD manifests so the generated schemas
reflect the required field and size constraint.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@cluster/v1/types.go`:
- Around line 87-88: Update the XValidation rule on the URL field to require
url(self).getHostname() != '' instead of checking getHost(), preserving the
existing HTTPS and valid-URL requirements. Add a regression test covering
https://:6443 and verify it is rejected.

In `@feature/feature.go`:
- Around line 108-110: Use the existing featuregate.Feature symbol CELValidation
to gate the CRD-side CEL rollout: conditionally install CEL validation rules and
ValidatingAdmissionPolicy resources, or retain the legacy validating webhook
when the gate is disabled. Update the relevant CRD/policy installation and
webhook-removal paths so CELValidation=false preserves legacy behavior.

In `@test/integration/api/managedcluster_test.go`:
- Around line 151-168: The ManagedCluster integration coverage is missing
validation for the new name and client-config count constraints. Extend the
managed-cluster creation tests alongside the existing HTTPS host validation case
to cover an invalid metadata.name, acceptance of exactly 32
ManagedClusterClientConfigs, and rejection of 33 configs, asserting the expected
create success or validation error for each case.

---

Duplicate comments:
In `@work/v1/types.go`:
- Around line 69-71: Make Manifests required by removing its +optional marker
and omitempty JSON tag, while retaining the non-empty validation rule.
Regenerate the affected CRD manifests so the generated schemas reflect the
required field and size constraint.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

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

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 9b5635bd-7728-413a-81ba-b4e022dc2c14

📥 Commits

Reviewing files that changed from the base of the PR and between 42e47c7 and 2153948.

📒 Files selected for processing (9)
  • addon/v1alpha1/0000_03_addon.open-cluster-management.io_addontemplates.crd.yaml
  • addon/v1beta1/0000_03_addon.open-cluster-management.io_addontemplates.crd.yaml
  • cluster/v1/0000_00_clusters.open-cluster-management.io_managedclusters.crd.yaml
  • cluster/v1/types.go
  • feature/feature.go
  • test/integration/api/managedcluster_test.go
  • work/v1/0000_00_work.open-cluster-management.io_manifestworks.crd.yaml
  • work/v1/types.go
  • work/v1alpha1/0000_00_work.open-cluster-management.io_manifestworkreplicasets.crd.yaml
💤 Files with no reviewable changes (4)
  • work/v1/0000_00_work.open-cluster-management.io_manifestworks.crd.yaml
  • work/v1alpha1/0000_00_work.open-cluster-management.io_manifestworkreplicasets.crd.yaml
  • addon/v1alpha1/0000_03_addon.open-cluster-management.io_addontemplates.crd.yaml
  • addon/v1beta1/0000_03_addon.open-cluster-management.io_addontemplates.crd.yaml
🚧 Files skipped from review as they are similar to previous changes (1)
  • cluster/v1/0000_00_clusters.open-cluster-management.io_managedclusters.crd.yaml

Comment thread cluster/v1/types.go
Comment on lines +87 to +88
// +kubebuilder:validation:MaxLength=2048
// +kubebuilder:validation:XValidation:rule="isURL(self) && url(self).getScheme() == 'https' && url(self).getHost() != ''",message="url must be a valid https URL"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Validate the hostname, not only the host string.

url(self).getHost() != '' can accept https://:6443: the host string contains a port, but the hostname is empty. Use getHostname() != '' and add a regression test for this case. Kubernetes distinguishes getHost() from getHostname(). (kubernetes.io)

[details]

Proposed fix
- // +kubebuilder:validation:XValidation:rule="isURL(self) && url(self).getScheme() == 'https' && url(self).getHost() != ''",message="url must be a valid https URL"
+ // +kubebuilder:validation:XValidation:rule="isURL(self) && url(self).getScheme() == 'https' && url(self).getHostname() != ''",message="url must be a valid https URL"
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@cluster/v1/types.go` around lines 87 - 88, Update the XValidation rule on the
URL field to require url(self).getHostname() != '' instead of checking
getHost(), preserving the existing HTTPS and valid-URL requirements. Add a
regression test covering https://:6443 and verify it is rejected.

Comment thread feature/feature.go
Comment on lines +108 to +110
// CELValidation replaces the legacy Go Validating Webhooks with native Kubernetes
// CEL validation rules and ValidatingAdmissionPolicy bindings.
CELValidation featuregate.Feature = "CELValidation"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

git ls-files | rg '(^|/)feature/feature\.go$|CELValidation|ValidatingAdmissionPolicy|XValidation|CEL validation|legacy Go Validating Webhooks|webhook'

Repository: open-cluster-management-io/api

Length of output: 3097


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '--- feature/feature.go ---'
sed -n '1,220p' feature/feature.go

echo
echo '--- CELValidation references ---'
rg -n 'CELValidation' .

Repository: open-cluster-management-io/api

Length of output: 10322


🏁 Script executed:

#!/bin/bash
set -euo pipefail

rg -n -i 'CELValidation|ValidatingAdmissionPolicy|x-kubernetes-validations|xValidation|validating webhook|legacy webhook|admission policy' . --glob '!vendor/**'

Repository: open-cluster-management-io/api

Length of output: 3459


Gate the CRD-side CEL rollout on CELValidation
feature/feature.go:108-110 only registers the flag; the repo already ships x-kubernetes-validations in generated CRDs, so CELValidation=false does not preserve the legacy webhook path by itself. Tie CRD/policy installation or webhook removal to this gate if old behavior still needs to be supported.

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

In `@feature/feature.go` around lines 108 - 110, Use the existing
featuregate.Feature symbol CELValidation to gate the CRD-side CEL rollout:
conditionally install CEL validation rules and ValidatingAdmissionPolicy
resources, or retain the legacy validating webhook when the gate is disabled.
Update the relevant CRD/policy installation and webhook-removal paths so
CELValidation=false preserves legacy behavior.

Comment on lines +151 to +168
ginkgo.It("should reject HTTPS URL without host", func() {
managedCluster := &clusterv1.ManagedCluster{
ObjectMeta: metav1.ObjectMeta{
Name: clusterName,
},
Spec: clusterv1.ManagedClusterSpec{
HubAcceptsClient: true,
ManagedClusterClientConfigs: []clusterv1.ClientConfig{
{
URL: "https://",
},
},
},
}

_, err := hubClusterClient.ClusterV1().ManagedClusters().Create(context.TODO(), managedCluster, metav1.CreateOptions{})
gomega.Expect(err).To(gomega.HaveOccurred())
})

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Cover all new ManagedCluster constraints.

This test covers only the hostless HTTPS case. Add integration cases for invalid metadata.name, exactly 32 client configs, and rejection of 33 configs so the generated schema constraints are exercised end to end.

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

In `@test/integration/api/managedcluster_test.go` around lines 151 - 168, The
ManagedCluster integration coverage is missing validation for the new name and
client-config count constraints. Extend the managed-cluster creation tests
alongside the existing HTTPS host validation case to cover an invalid
metadata.name, acceptance of exactly 32 ManagedClusterClientConfigs, and
rejection of 33 configs, asserting the expected create success or validation
error for each case.

- migrate structural validation to kubebuilder CEL markers
- address CodeRabbit feedback on required fields and URL validation
- add CELValidation FeatureGate
- address PR feedback for CEL rules and Manifests

Signed-off-by: Vaishnav88sk <vaishnavsk8804@gmail.com>
@Vaishnav88sk
Vaishnav88sk force-pushed the feature/cel-validation-migration branch from 2153948 to 5fc06ed Compare July 21, 2026 10:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants