OCPBUGS-87991: validate additionalNetworks name format in KubeVirt NodePools - #8710
Conversation
|
Pipeline controller notification For optional jobs, comment This repository is configured in: LGTM mode |
|
@chdeshpa-hue: This pull request references Jira Issue OCPBUGS-87991, which is invalid:
Comment The bug has been updated to refer to the pull request using the external bug tracker. DetailsIn response to this:
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. |
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughIn 🚥 Pre-merge checks | ✅ 11✅ Passed checks (11 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #8710 +/- ##
=======================================
Coverage 46.64% 46.64%
=======================================
Files 784 784
Lines 98880 98880
=======================================
Hits 46123 46123
Misses 49628 49628
Partials 3129 3129
Flags with carried forward coverage won't be shown. Click here to find out more. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
🧹 Nitpick comments (1)
hypershift-operator/controllers/nodepool/kubevirt/kubevirt.go (1)
142-162: ⚡ Quick winConsider validating namespace and name parts against Kubernetes DNS subdomain rules.
The current validation checks that parts are non-empty after trimming, but doesn't enforce Kubernetes DNS subdomain naming conventions (RFC 1123). This means names like
"my ns/nad"(with space) or"my_ns/nad"(with underscore) pass validation but will cause VM startup failures when KubeVirt attempts to reference a non-existent NetworkAttachmentDefinition.Kubernetes resource names must be lowercase alphanumeric with
-and., starting and ending with alphanumeric. Adding a regex check like^[a-z0-9]([-a-z0-9]*[a-z0-9])?$for each part would catch these at admission time with clearer error messages.♻️ Example validation with DNS subdomain rules
+import ( + "regexp" +) + +var dnsSubdomainRegex = regexp.MustCompile(`^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$`) + func ValidateAdditionalNetworks(networks []hyperv1.KubevirtNetwork) error { if len(networks) == 0 { return nil } seen := make(map[string]bool, len(networks)) for idx, network := range networks { parts := strings.Split(network.Name, "/") if len(parts) != 2 || strings.TrimSpace(parts[0]) == "" || strings.TrimSpace(parts[1]) == "" { return fmt.Errorf("additionalNetworks[%d].name %q must be in the format <namespace>/<name>", idx, network.Name) } + namespace := strings.TrimSpace(parts[0]) + name := strings.TrimSpace(parts[1]) + if !dnsSubdomainRegex.MatchString(namespace) { + return fmt.Errorf("additionalNetworks[%d].name %q has invalid namespace part %q (must be a valid DNS subdomain)", idx, network.Name, namespace) + } + if !dnsSubdomainRegex.MatchString(name) { + return fmt.Errorf("additionalNetworks[%d].name %q has invalid name part %q (must be a valid DNS subdomain)", idx, network.Name, name) + } if seen[network.Name] { return fmt.Errorf("additionalNetworks[%d].name %q is duplicated", idx, network.Name) }🤖 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 `@hypershift-operator/controllers/nodepool/kubevirt/kubevirt.go` around lines 142 - 162, The ValidateAdditionalNetworks function currently only checks for non-empty namespace/name parts; update it to enforce Kubernetes DNS subdomain/name rules by validating each part (the namespace and the name from strings.Split(network.Name, "/")) against the RFC1123 regex (e.g. ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$), and return clear formatted errors like "additionalNetworks[%d].name %q: namespace %q is invalid" or "…: name %q is invalid" when a part fails; keep the existing duplicate check and virtualMachineInterfaceName length check intact, and reference the same symbols (ValidateAdditionalNetworks, virtualMachineInterfaceName) so the change is localized to this function.
🤖 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.
Nitpick comments:
In `@hypershift-operator/controllers/nodepool/kubevirt/kubevirt.go`:
- Around line 142-162: The ValidateAdditionalNetworks function currently only
checks for non-empty namespace/name parts; update it to enforce Kubernetes DNS
subdomain/name rules by validating each part (the namespace and the name from
strings.Split(network.Name, "/")) against the RFC1123 regex (e.g.
^[a-z0-9]([-a-z0-9]*[a-z0-9])?$), and return clear formatted errors like
"additionalNetworks[%d].name %q: namespace %q is invalid" or "…: name %q is
invalid" when a part fails; keep the existing duplicate check and
virtualMachineInterfaceName length check intact, and reference the same symbols
(ValidateAdditionalNetworks, virtualMachineInterfaceName) so the change is
localized to this function.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository YAML (base), Central YAML (inherited)
Review profile: CHILL
Plan: Enterprise
Run ID: 098416f3-4a27-47b2-8089-b95cf2b80aec
📒 Files selected for processing (3)
hypershift-operator/controllers/hostedcluster/hostedcluster_webhook.gohypershift-operator/controllers/nodepool/kubevirt/kubevirt.gohypershift-operator/controllers/nodepool/kubevirt/kubevirt_test.go
bryan-cox
left a comment
There was a problem hiding this comment.
Thanks for tackling this — the validation gap is real and the user experience improvement is clear. The checks themselves are the right ones to add.
However, this validation should live in the API types (CEL markers) rather than the webhook. Our project rule (.claude/rules/webhook-validation.md) is explicit:
"HyperShift uses CRD CEL validation rules instead of webhooks. The webhook exists only for KubeVirt platform-specific needs (defaulting and JSON patch annotation validation). Do not add new validation or defaulting logic here."
All three checks are expressible declaratively:
1. Format check — CEL regex on KubevirtNetwork.Name:
// +kubebuilder:validation:XValidation:rule="self.matches('^[^/]+/[^/]+$')",message="name must be in the format <namespace>/<name> to reference a multus network attachment definition"There's direct precedent for this pattern in our Azure subnet ID validation (api/hypershift/v1beta1/azure.go).
2. Uniqueness — use Kubernetes list map semantics on AdditionalNetworks:
// +listType=map
// +listMapKey=nameNo CEL needed. Schema-level enforcement with proper server-side-apply merge semantics.
3. Interface name length — tighten MaxLength instead of computing it in Go. The generated name is iface{N}_{name} where the prefix is at most 8 chars (iface20_ at MaxItems=20). So:
// +kubebuilder:validation:MaxLength=55This replaces the entire Go length check. It's slightly conservative but avoids coupling the API to the controller's internal virtualMachineInterfaceName() implementation.
What I'd suggest:
- Move format + uniqueness to API type markers (blocking — per project convention)
- Tighten
MaxLengthfrom 255 to 55 onName - Remove the webhook additions
- Keep the
PlatformValidation()call as a defense-in-depth safety net - Add envtest YAML test coverage for the new CEL rules (see
test/envtest/README.md)
Happy to help if you have questions about the CEL/envtest patterns — there are good examples to follow in the existing codebase.
|
Thanks @bryan-cox — you're right, this belongs in the API types, not the webhook. Redesigning from scratch. Here's the approach I'm planning — wanted to align before writing code, especially since you mentioned there are good examples to follow. Planned changes1. Format check — CEL regex on
|
|
1. Examples to follow for CEL/envtest patterns: For the envtest YAML test suites, the existing NodePool test suites are the best reference:
Create your new suite as For CEL marker patterns on the API types, For the Run 2. MaxLength 255 → 55 ratcheting: This is acceptable. Names >55 already fail at runtime due to the 63-char interface name limit, so you're moving the failure left to admission time. CRD ratcheting handles the transition — unchanged values pass through on update. The math checks out: worst-case prefix is 3. A few things to flag on the approach: CEL regex: Defense-in-depth: I'd push back on keeping Webhook cleanup: Make sure the removal includes reverting any changes to |
53adcee to
9580fed
Compare
|
Thanks @bryan-cox — redesigned from scratch based on your feedback. Force-pushed a single commit. What changedRemoved
Added (API types only)
TestsNew What was NOT keptPer your guidance: no defense-in-depth /cc @bryan-cox |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 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 `@api/hypershift/v1beta1/kubevirt.go`:
- Around line 204-205: The XValidation rule introduced in
api/hypershift/v1beta1/kubevirt.go for validating the multus network attachment
definition reference format lacks corresponding envtest coverage. Following the
coding guidelines that require all API CEL validations to be covered with
envtests, add envtest cases to validate both valid and invalid inputs for the
format constraint that ensures the field matches the pattern for namespace/name
format. Refer to test/envtest/README.md for guidance on structuring these tests,
and ensure the tests verify that the validation rule correctly accepts properly
formatted namespace/name references and rejects improperly formatted ones.
🪄 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: Repository YAML (base), Central YAML (inherited)
Review profile: CHILL
Plan: Enterprise
Run ID: 09a3bf35-1698-497b-8b4b-9654ce14e281
⛔ Files ignored due to path filters (9)
api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/nodepools.hypershift.openshift.io/AAA_ungated.yamlis excluded by!**/zz_generated.featuregated-crd-manifests/**api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/nodepools.hypershift.openshift.io/GCPPlatform.yamlis excluded by!**/zz_generated.featuregated-crd-manifests/**api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/nodepools.hypershift.openshift.io/OSStreams.yamlis excluded by!**/zz_generated.featuregated-crd-manifests/**api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/nodepools.hypershift.openshift.io/OpenStack.yamlis excluded by!**/zz_generated.featuregated-crd-manifests/**cmd/install/assets/crds/hypershift-operator/tests/nodepools.hypershift.openshift.io/stable.nodepools.kubevirt.testsuite.yamlis excluded by!cmd/install/assets/**/*.yamlcmd/install/assets/crds/hypershift-operator/zz_generated.crd-manifests/nodepools-CustomNoUpgrade.crd.yamlis excluded by!**/zz_generated.crd-manifests/**,!cmd/install/assets/**/*.yamlcmd/install/assets/crds/hypershift-operator/zz_generated.crd-manifests/nodepools-Default.crd.yamlis excluded by!**/zz_generated.crd-manifests/**,!cmd/install/assets/**/*.yamlcmd/install/assets/crds/hypershift-operator/zz_generated.crd-manifests/nodepools-TechPreviewNoUpgrade.crd.yamlis excluded by!**/zz_generated.crd-manifests/**,!cmd/install/assets/**/*.yamlvendor/github.com/openshift/hypershift/api/hypershift/v1beta1/kubevirt.gois excluded by!vendor/**,!**/vendor/**
📒 Files selected for processing (1)
api/hypershift/v1beta1/kubevirt.go
| // multus network attachment definition | ||
| // +kubebuilder:validation:MaxLength=255 | ||
| // +kubebuilder:validation:MaxLength=55 | ||
| // +kubebuilder:validation:XValidation:rule="self.matches('^[^/\\\\s]+/[^/\\\\s]+$')",message="name must be in the format <namespace>/<name> to reference a multus network attachment definition" |
There was a problem hiding this comment.
Namespace and name being Kubernetes namespace and name? Namespaces are DNS1123 label validated and names, depends on the object, but the superset is DNS1123 subdomain.
These both have well defined regex that would be more complete than [^/\\\\s]
What's the minimum Kube supported version for HyperShift operator at this point?
There was a problem hiding this comment.
Good catch — the old regex was too permissive. Fixed in 3e0b085: replaced [^/\\s]+ with DNS1123-conformant patterns:
^[a-z0-9]([a-z0-9-]*[a-z0-9])?/[a-z0-9]([a-z0-9.-]*[a-z0-9])?$
- Namespace segment: DNS label (
[a-z0-9]([-a-z0-9]*[a-z0-9])?, max 63) - Name segment: DNS subdomain (
[a-z0-9]([-a-z0-9.]*[a-z0-9])?, max 253)
On minimum Kube version: HyperShift requires management cluster ≥ Kubernetes 1.30. CEL matches() has been GA since 1.25, so no concern there.
9580fed to
3e0b085
Compare
|
@JoelSpeed addressed both review points in 8dc71ec:
If you're happy with the direction, could you LGTM? |
3e0b085 to
252e740
Compare
|
@chdeshpa-hue: This pull request references Jira Issue OCPBUGS-87991, which is valid. The bug has been moved to the POST state. 3 validation(s) were run on this bug
DetailsIn response to this:
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. |
|
/test verify |
|
@chdeshpa-hue can you please rebase this PR and then as long as the new GHA tests pass, I'll tag the PR. |
Adds CEL validation to KubevirtNetwork.Name requiring the
<namespace>/<name> format with DNS label segments, and reduces
MaxLength from 255 to 55 to stay within the KubeVirt DNS label
limit for generated interface names (63 - len("iface20_") = 55).
Changes AdditionalNetworks list type to map with name as the key
to enforce uniqueness at the API level.
Includes envtest coverage for valid and invalid name formats, and
extends crdify-config.yaml to mirror openshift/api policy so
verify-crd-schema warns on intentional API tightenings.
Fixes: https://redhat.atlassian.net/browse/OCPBUGS-87991
Co-authored-by: Cursor <cursoragent@cursor.com>
6405bf9 to
2edc794
Compare
|
@bryan-cox Rebased onto current |
|
[APPROVALNOTIFIER] This PR is APPROVED This pull-request has been approved by: bryan-cox, chdeshpa-hue, JoelSpeed The full list of commands accepted by this bot can be found here. The pull request process is described here DetailsNeeds approval from an approver in each of these files:
Approvers can indicate their approval by writing |
|
@bryan-cox Pre-merge verification on HEAD What we ranCEL admission only (the change in this PR). Stock MCE 2.17.2 HyperShift operator was not replaced. We server-side-applied this PR’s Environment: Azure IPI, OCP 5.0.0-ec.5 (K8s 1.36.2), MCE 2.17.2. Before (stock MCE CRD: maxLength 255, no CEL, no
|
|
/lgtm from virt team |
|
/retest-required |
|
Scheduling tests matching the |
|
/test e2e-v2-azure-self-managed |
|
/test e2e-v2-azure-self-managed |
|
/verified by unit tests |
|
@qinqon: This PR has been marked as verified by DetailsIn response to this:
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. |
|
/retest-required |
921b8c6
into
openshift:main
|
@chdeshpa-hue: Jira Issue Verification Checks: Jira Issue OCPBUGS-87991 Jira Issue OCPBUGS-87991 has been moved to the MODIFIED state and will move to the VERIFIED state when the change is available in an accepted nightly payload. 🕓 DetailsIn response to this:
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. |
|
Fix included in release 5.1.0-0.nightly-2026-09-11-221906 |
Summary
KubeVirt NodePools accept invalid
additionalNetworks[].namevalues without admission-time rejection. The field must reference a Multus NAD as<namespace>/<name>, but previously nothing enforced format, uniqueness, or the KubeVirt interface-name length limit. Users who omit the namespace prefix can get a HostedCluster that looks healthy while VMs fail to start with errors buried in the hosted control plane namespace.This PR moves validation into the API types (CEL + schema markers) per HyperShift convention — no new webhook validation.
Changes
api/hypershift/v1beta1/kubevirt.goAdditionalNetworks:+listType=map/+listMapKey=name(schema-level uniqueness)KubevirtNetwork.Name:<namespace>/<name>with DNS-label segmentsMaxLengthtightened from 255 → 55 (KubeVirt interface name limit: 63 − len(iface20_))Generated artifacts
api.md,aggregated-docs.md)Tests
stable.nodepools.kubevirt.testsuite.yaml(valid/invalid formats, duplicates, maxLength)User experience after fix
Backward compatibility
additionalNetworksconfigured → unchangedns/nameentries → pass, zero behavior changeReviewer notes
Addresses @bryan-cox feedback (Jun 11 / Jul 14):
crdify-config.yamlpolicy hitchhike removed from this PRFixes: https://redhat.atlassian.net/browse/OCPBUGS-87991