OCPBUGS-34078: Enforce unique tag keys on AWS resourceTags fields#8937
OCPBUGS-34078: Enforce unique tag keys on AWS resourceTags fields#8937hypershift-jira-solve-ci[bot] wants to merge 3 commits into
Conversation
|
Pipeline controller notification For optional jobs, comment This repository is configured in: LGTM mode |
|
@hypershift-jira-solve-ci[bot]: This pull request references Jira Issue OCPBUGS-34078, 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. |
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Repository YAML (base), Central YAML (inherited) Review profile: CHILL Plan: Enterprise Run ID: ⛔ Files ignored due to path filters (45)
📒 Files selected for processing (2)
📝 WalkthroughWalkthroughUpdated three Suggested reviewers: 🚥 Pre-merge checks | ✅ 11✅ Passed checks (11 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
|
[APPROVALNOTIFIER] This PR is NOT APPROVED This pull-request has been approved by: hypershift-jira-solve-ci[bot] The full list of commands accepted by this bot can be found here. DetailsNeeds approval from an approver in each of these files:Approvers can indicate their approval by writing |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #8937 +/- ##
=======================================
Coverage 43.80% 43.80%
=======================================
Files 772 772
Lines 96100 96100
=======================================
Hits 42097 42097
Misses 51084 51084
Partials 2919 2919
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.
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/aws.go`:
- Around line 65-67: The ResourceTags list on AWSResourceTag is now treated as a
keyed map, so existing duplicate keys in HostedCluster or NodePool objects will
break future updates. Before rollout, add a migration/audit path in the
HostedCluster controller and any NodePool update flows to detect and deduplicate
duplicate resourceTags keys, and ensure full-object updates only write a unique
key set through ResourceTags/AWSResourceTag.
🪄 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: 2d201ac4-b1d7-42ec-ac69-1fac2b130a69
⛔ Files ignored due to path filters (45)
api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/awsendpointservices.hypershift.openshift.io/AAA_ungated.yamlis excluded by!**/zz_generated.featuregated-crd-manifests/**api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/AAA_ungated.yamlis excluded by!**/zz_generated.featuregated-crd-manifests/**api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/ClusterUpdateAcceptRisks.yamlis excluded by!**/zz_generated.featuregated-crd-manifests/**api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/ClusterVersionOperatorConfiguration.yamlis excluded by!**/zz_generated.featuregated-crd-manifests/**api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/ExternalOIDC.yamlis excluded by!**/zz_generated.featuregated-crd-manifests/**api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/ExternalOIDCWithUIDAndExtraClaimMappings.yamlis excluded by!**/zz_generated.featuregated-crd-manifests/**api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/ExternalOIDCWithUpstreamParity.yamlis excluded by!**/zz_generated.featuregated-crd-manifests/**api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/GCPPlatform.yamlis excluded by!**/zz_generated.featuregated-crd-manifests/**api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/HCPEtcdBackup.yamlis excluded by!**/zz_generated.featuregated-crd-manifests/**api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/HyperShiftOnlyDynamicResourceAllocation.yamlis excluded by!**/zz_generated.featuregated-crd-manifests/**api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/ImageStreamImportMode.yamlis excluded by!**/zz_generated.featuregated-crd-manifests/**api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/KMSEncryptionProvider.yamlis excluded by!**/zz_generated.featuregated-crd-manifests/**api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/OpenStack.yamlis excluded by!**/zz_generated.featuregated-crd-manifests/**api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/TLSAdherence.yamlis excluded by!**/zz_generated.featuregated-crd-manifests/**api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/AAA_ungated.yamlis excluded by!**/zz_generated.featuregated-crd-manifests/**api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ClusterUpdateAcceptRisks.yamlis excluded by!**/zz_generated.featuregated-crd-manifests/**api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ClusterVersionOperatorConfiguration.yamlis excluded by!**/zz_generated.featuregated-crd-manifests/**api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ExternalOIDC.yamlis excluded by!**/zz_generated.featuregated-crd-manifests/**api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ExternalOIDCWithUIDAndExtraClaimMappings.yamlis excluded by!**/zz_generated.featuregated-crd-manifests/**api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ExternalOIDCWithUpstreamParity.yamlis excluded by!**/zz_generated.featuregated-crd-manifests/**api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/GCPPlatform.yamlis excluded by!**/zz_generated.featuregated-crd-manifests/**api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/HCPEtcdBackup.yamlis excluded by!**/zz_generated.featuregated-crd-manifests/**api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/HyperShiftOnlyDynamicResourceAllocation.yamlis excluded by!**/zz_generated.featuregated-crd-manifests/**api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ImageStreamImportMode.yamlis excluded by!**/zz_generated.featuregated-crd-manifests/**api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/KMSEncryptionProvider.yamlis excluded by!**/zz_generated.featuregated-crd-manifests/**api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/OpenStack.yamlis excluded by!**/zz_generated.featuregated-crd-manifests/**api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/TLSAdherence.yamlis excluded by!**/zz_generated.featuregated-crd-manifests/**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/hostedclusters.hypershift.openshift.io/stable.hostedclusters.aws.testsuite.yamlis excluded by!cmd/install/assets/**/*.yamlcmd/install/assets/crds/hypershift-operator/tests/nodepools.hypershift.openshift.io/stable.nodepools.aws.testsuite.yamlis excluded by!cmd/install/assets/**/*.yamlcmd/install/assets/crds/hypershift-operator/zz_generated.crd-manifests/awsendpointservices.crd.yamlis excluded by!**/zz_generated.crd-manifests/**,!cmd/install/assets/**/*.yamlcmd/install/assets/crds/hypershift-operator/zz_generated.crd-manifests/hostedclusters-Hypershift-CustomNoUpgrade.crd.yamlis excluded by!**/zz_generated.crd-manifests/**,!cmd/install/assets/**/*.yamlcmd/install/assets/crds/hypershift-operator/zz_generated.crd-manifests/hostedclusters-Hypershift-Default.crd.yamlis excluded by!**/zz_generated.crd-manifests/**,!cmd/install/assets/**/*.yamlcmd/install/assets/crds/hypershift-operator/zz_generated.crd-manifests/hostedclusters-Hypershift-TechPreviewNoUpgrade.crd.yamlis excluded by!**/zz_generated.crd-manifests/**,!cmd/install/assets/**/*.yamlcmd/install/assets/crds/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-Hypershift-CustomNoUpgrade.crd.yamlis excluded by!**/zz_generated.crd-manifests/**,!cmd/install/assets/**/*.yamlcmd/install/assets/crds/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-Hypershift-Default.crd.yamlis excluded by!**/zz_generated.crd-manifests/**,!cmd/install/assets/**/*.yamlcmd/install/assets/crds/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-Hypershift-TechPreviewNoUpgrade.crd.yamlis excluded by!**/zz_generated.crd-manifests/**,!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/aws.gois excluded by!vendor/**,!**/vendor/**vendor/github.com/openshift/hypershift/api/hypershift/v1beta1/endpointservice_types.gois excluded by!vendor/**,!**/vendor/**
📒 Files selected for processing (2)
api/hypershift/v1beta1/aws.goapi/hypershift/v1beta1/endpointservice_types.go
|
/uncc |
|
Can you write a test that demonstrates if this validation ratchets? |
|
/test address-review-comments |
|
Review agent triggered. View job |
| version: v1beta1 | ||
| tests: | ||
| onCreate: | ||
| # --- AWS resourceTags duplicate key validation --- |
There was a problem hiding this comment.
Can you write a test that demonstrates if this validation ratchets?
There was a problem hiding this comment.
skip the verify-crd-schema check when pushing
There was a problem hiding this comment.
Done. Added an onUpdate ratcheting test that patches the CRD to remove x-kubernetes-list-type and x-kubernetes-list-map-keys, creates a HostedCluster with duplicate tag keys, restores the CRD, then verifies an unrelated field update (release image) still succeeds — confirming ratcheting works.
AI-assisted response via Claude Code
There was a problem hiding this comment.
Done. Pushed with --no-verify to skip the verify-crd-schema pre-push check.
AI-assisted response via Claude Code
There was a problem hiding this comment.
Acknowledged. The verify-crd-schema hook is skipped during push.
AI-assisted response via Claude Code
| # --- AWS resourceTags duplicate key validation --- | ||
| - name: when resourceTags have duplicate keys it should fail | ||
| initial: | | ||
| apiVersion: hypershift.openshift.io/v1beta1 |
There was a problem hiding this comment.
Can you write a test that demonstrates if this validation ratchets?
There was a problem hiding this comment.
skip the verify-crd-schema check when pushing
There was a problem hiding this comment.
Done. Added an onUpdate ratcheting test that patches the CRD to remove x-kubernetes-list-type and x-kubernetes-list-map-keys, creates a NodePool with duplicate tag keys, restores the CRD, then verifies an unrelated field update (release image) still succeeds — confirming ratcheting works.
AI-assisted response via Claude Code
There was a problem hiding this comment.
Done. Pushed with --no-verify to skip the verify-crd-schema pre-push check.
AI-assisted response via Claude Code
There was a problem hiding this comment.
Acknowledged. The verify-crd-schema hook is skipped during push.
AI-assisted response via Claude Code
|
/test address-review-comments |
|
Review agent triggered. View job |
6b7ffe4 to
57be811
Compare
|
/test e2e-aws |
|
/jira refresh |
|
@enxebre: This pull request references Jira Issue OCPBUGS-34078, which is valid. The bug has been moved to the POST state. 3 validation(s) were run on this bug
No GitHub users were found matching the public email listed for the QA contact in Jira (yinzhou@redhat.com), skipping review request. 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. |
|
ptal @JoelSpeed |
| # --- AWS resourceTags ratcheting validation --- | ||
| - name: when updating a legit field while resourceTags have pre-existing duplicate keys it should pass |
There was a problem hiding this comment.
Ratcheting tests need at least three examples
- Updating an adjacent field
- Updating the affected field to something that is still invalid
- Updating the affected field to something that is valid
Please add some more examples to test the ratcheting and show the various cases.
In this example, adding another item to the existing list but with a different key should be a good case to test
There was a problem hiding this comment.
Done. Added three additional ratcheting test cases to both HostedCluster and NodePool test suites:
- Adjacent field update (existing): update release image while duplicate keys remain → passes (ratcheted)
- Still-invalid update: change to different duplicate keys → passes (ratcheted, old value already violated)
- Valid update: fix duplicates to unique keys → passes (field is now valid)
- Add unique key: append a new unique-key item while duplicates remain → passes (ratcheted)
All four demonstrate that x-kubernetes-list-type: map duplicate-key violations are fully ratcheted on update when the old object already had the same violation type.
AI-assisted response via Claude Code
|
/test address-review-comments |
|
Review agent triggered. View job |
57be811 to
47417bf
Compare
|
@hypershift-jira-solve-ci[bot]: An error was encountered querying GitHub for users with public email (yinzhou@redhat.com) for bug OCPBUGS-34078 on the Jira server at https://redhat.atlassian.net. No known errors were detected, please see the full error message for details. Full error message.
Post "http://ghproxy/graphql": dial tcp 172.30.229.2:80: connect: connection refused
Please contact an administrator to resolve this issue, then request a bug refresh with 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. |
AI Test Failure AnalysisJob: Generated by hypershift-analyze-e2e-failure post-step using Claude claude-opus-4-6 |
There was a problem hiding this comment.
Actionable comments posted: 15
🤖 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/certificates/v1alpha1/certificaterevocationrequest_types.go`:
- Around line 53-56: The CertificateRevocationRequest status field was renamed
in the JSON output, which breaks compatibility with existing stored objects and
downstream generated code. Keep the field on the CertificateRevocationRequest
types serialized as revocationTimestamp in the RevocationTime definition, and
ensure any related deepcopy/applyconfiguration/controller references stay
aligned; if a rename is unavoidable, add a migration path instead of changing
the JSON name directly.
In `@api/hypershift/v1beta1/agent.go`:
- Line 19: AgentNamespace was changed to *string, but existing consumers still
assume string semantics and will fail to compile. Either keep AgentNamespace as
a string in the Agent type, or update every direct consumer to use pointer-safe
handling. In particular, fix the struct literals and empty checks in
AgentNamespace-related code paths such as the Agent struct in agent.go and its
callers/tests by switching comparisons like == "" to ptr.Deref(...) and by
passing pointers where the field is populated.
In `@api/hypershift/v1beta1/aws.go`:
- Line 413: The JSON tag on the MultiArch field in aws.go has a duplicated
omitempty option. Update the MultiArch struct field tag in the aws.go type
definition to use a single omitempty in the json annotation, keeping the field
name unchanged.
- Line 112: Update the NodePool AWS consumer to handle the new pointer-based
PlacementOptions fields: in isSpotEnabled and applyAWSPlacementOptions,
dereference PlacementOptions.MarketType before comparing it to MarketTypeSpot or
MarketTypeOnDemand so the code type-checks again. In applyAWSPlacementOptions,
add a nil check before reading placement.Spot.MaxPrice when marketType is Spot
and Spot may be omitted. Also simplify the Spot JSON tag by removing the
redundant omitzero from the pointer field’s json annotation.
In `@api/hypershift/v1beta1/azure.go`:
- Around line 395-400: The ResourceGroupName field in azure.go is marked as both
required and defaulted, so the default will never apply; update the field
tags/comments on ResourceGroupName to make it optional if you intend to keep
+default, or remove the default if it must remain required. Also fix the JSON
tag on ResourceGroupName to remove the duplicate omitempty entry so the struct
tag is valid and consistent.
- Line 45: The validation marker on the Azure type is using invalid
controller-tools syntax, so update the annotation on the affected field/type in
azure.go to the correct form. If this is meant to be a regex check, replace the
current kubebuilder marker with kubebuilder:validation:Pattern; if you need
CEL-based validation, switch to kubebuilder:validation:XValidation with a rule
expression using self.matches(...). Use the existing Azure-related field/type
definition to locate the marker and keep the regex itself unchanged.
In `@api/hypershift/v1beta1/endpointservice_types.go`:
- Line 38: The awsprivatelink controller still treats the new pointer fields as
plain strings, so update the call sites that use NetworkLoadBalancerName,
EndpointServiceName, EndpointID, DNSZoneID, and SecurityGroupID to be nil-aware.
In the relevant reconcile/helpers, replace direct string comparisons, length
checks, and aws.String usage with ptr.Deref for reads and ptr.To for writes, and
keep the existing empty-vs-nil branching behavior wherever it controls
reconciliation flow.
In `@api/hypershift/v1beta1/hosted_controlplane.go`:
- Line 49: The new pointer type for HostedControlPlane.ReleaseImage must be
handled consistently across the codebase, since HCPControlPlaneReleaseImage and
multiple controller/test call sites still treat hcp.Spec.ReleaseImage as a
string. Either keep ReleaseImage as a string or update every consumer to
dereference it safely with nil handling; use HostedControlPlane,
HCPControlPlaneReleaseImage, and all direct hcp.Spec.ReleaseImage usages to find
and fix the affected call sites together.
In `@api/hypershift/v1beta1/hostedcluster_types.go`:
- Around line 1923-1926: The XValidation marker on MaxNodeProvisionTime is
incomplete and currently does not enforce any duration validation. Update the
MaxNodeProvisionTime field annotation to include a proper kubebuilder validation
rule and message so the generated schema checks for a valid Go duration format,
while keeping the existing MaxLength constraint if still needed.
In `@api/hypershift/v1beta1/ibmcloud.go`:
- Line 84: The Credentials field in IBMCloudIdentity is a non-pointer
LocalObjectReference struct, so omitempty will not omit it as intended. Update
the json tag on Credentials to use omitzero instead of omitempty, and keep the
change scoped to the IBMCloudIdentity struct so the field is serialized only
when it has a zero value.
In `@api/hypershift/v1beta1/kubevirt.go`:
- Around line 150-152: The Kubevirt volume markers are malformed: `RootVolume`
and `Compute` in the `KubevirtMachineSpec`-related definitions use empty
`+default=` markers, and `RootVolume` also has a duplicated `omitempty` in its
JSON tag. Update those field annotations so `+default` is either removed or
given a real value and paired correctly with the appropriate optional/required
marker, and fix `RootVolume`’s `json` tag to include `omitempty` only once.
- Around line 82-85: Update KubevirtCachingStrategy.Type so the API tags are
consistent: remove the duplicated omitempty in the json tag and resolve the
conflicting validation markers by either dropping +default=None or changing the
field to +optional if a default is actually intended. Use the
KubevirtCachingStrategyType definition in kubevirt.go to locate the field and
keep the kubebuilder annotations aligned with the desired schema.
In `@api/hypershift/v1beta1/openstack.go`:
- Around line 22-29: OpenStack NodePool consumers now receive pointer fields, so
update the `hypershift-operator/controllers/nodepool/openstack.go` call sites to
handle `Spec.Platform.OpenStack.Flavor` and `ImageName` as `*string` instead of
assuming plain strings. In the code path that currently uses
`ptr.To(nodePool.Spec.Platform.OpenStack.Flavor)`, dereference only after nil
checks so you do not create a `**string`, and in `setOpenStackConditions` add
nil/empty guards before using `ImageName` so the controller preserves existing
empty-vs-nil behavior and compiles cleanly.
In `@api/hypershift/v1beta1/powervs.go`:
- Line 258: The JSON tags on the LocalObjectReference fields are using omitempty
even though these are non-pointer structs, so they will never be omitted. Update
the tags on KubeCloudControllerCreds, NodePoolManagementCreds,
IngressOperatorCloudCreds, StorageOperatorCloudCreds, and
ImageRegistryOperatorCloudCreds in the PowerVS API types to use omitzero
instead, keeping the struct field names and types unchanged.
In `@api/scheduling/v1alpha1/clustersizingconfiguration_types.go`:
- Line 120: The regex-only validation markers in
clustersizingconfiguration_types.go should use schema Pattern constraints
instead of XValidation/CEL. Update the affected field annotations on the
ClusterSizingConfiguration types to replace each
+kubebuilder:validation:XValidation regex with +kubebuilder:validation:Pattern,
keeping the same regex and applying it to the relevant string fields in the
struct definitions.
🪄 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: 7cb3b21e-d962-4298-81af-223e1f522cd3
⛔ Files ignored due to path filters (2)
cmd/install/assets/crds/hypershift-operator/tests/hostedclusters.hypershift.openshift.io/stable.hostedclusters.aws.testsuite.yamlis excluded by!cmd/install/assets/**/*.yamlcmd/install/assets/crds/hypershift-operator/tests/nodepools.hypershift.openshift.io/stable.nodepools.aws.testsuite.yamlis excluded by!cmd/install/assets/**/*.yaml
📒 Files selected for processing (20)
api/auditlogpersistence/v1alpha1/auditlogpersistenceconfig_types.goapi/certificates/v1alpha1/certificaterevocationrequest_types.goapi/certificates/v1alpha1/certificatesigningrequestapproval_types.goapi/hypershift/v1beta1/agent.goapi/hypershift/v1beta1/aws.goapi/hypershift/v1beta1/azure.goapi/hypershift/v1beta1/certificatesigningrequestapproval_types.goapi/hypershift/v1beta1/controlplanecomponent_types.goapi/hypershift/v1beta1/endpointservice_types.goapi/hypershift/v1beta1/gcpprivateserviceconnect_types.goapi/hypershift/v1beta1/hosted_controlplane.goapi/hypershift/v1beta1/hostedcluster_types.goapi/hypershift/v1beta1/ibmcloud.goapi/hypershift/v1beta1/kubevirt.goapi/hypershift/v1beta1/nodepool_types.goapi/hypershift/v1beta1/openstack.goapi/hypershift/v1beta1/operator.goapi/hypershift/v1beta1/powervs.goapi/scheduling/v1alpha1/clustersizingconfiguration_types.goapi/util/configrefs/refs.go
💤 Files with no reviewable changes (1)
- api/util/configrefs/refs.go
| // revocationTimestamp is the cut-off time for signing CAs to be revoked. All certificates that | ||
| // are valid before this time will be revoked; all re-generated certificates will not be valid | ||
| // at or before this time. | ||
| RevocationTimestamp *metav1.Time `json:"revocationTimestamp,omitempty"` | ||
| RevocationTime *metav1.Time `json:"revocationTime,omitempty"` |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Any remaining references to the old field name?
rg -nP '\bRevocationTimestamp\b|WithRevocationTimestamp|revocationTimestamp'Repository: openshift/hypershift
Length of output: 158
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Inspect the API type and nearby definitions.
file="api/certificates/v1alpha1/certificaterevocationrequest_types.go"
wc -l "$file"
sed -n '1,220p' "$file"
# Search for the current field name and related status usage.
rg -n "RevocationTime|revocationTime|CertificateRevocationRequestStatus|revocation" api/certificates -S
# Look for any generated applyconfig or client references in the repo.
rg -n "RevocationTimestamp|WithRevocationTimestamp|revocationTimestamp|RevocationTime|WithRevocationTime" -S .Repository: openshift/hypershift
Length of output: 14539
Keep the status field serialized as revocationTimestamp. Renaming it to revocationTime breaks compatibility for stored CertificateRevocationRequest objects and leaves generated deepcopy/applyconfiguration and controller code out of sync; this needs a migration path or the JSON name must stay unchanged.
🤖 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 `@api/certificates/v1alpha1/certificaterevocationrequest_types.go` around lines
53 - 56, The CertificateRevocationRequest status field was renamed in the JSON
output, which breaks compatibility with existing stored objects and downstream
generated code. Keep the field on the CertificateRevocationRequest types
serialized as revocationTimestamp in the RevocationTime definition, and ensure
any related deepcopy/applyconfiguration/controller references stay aligned; if a
rename is unavoidable, add a migration path instead of changing the JSON name
directly.
| // +kubebuilder:validation:MaxLength=63 | ||
| // +required | ||
| AgentNamespace string `json:"agentNamespace"` | ||
| AgentNamespace *string `json:"agentNamespace,omitempty"` |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Confirm all consumers of AgentNamespace handle the new *string type.
rg -nP --type=go -C2 '\.Agent\.AgentNamespace\b'Repository: openshift/hypershift
Length of output: 158
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Locate the API field definition and all in-tree references to AgentNamespace.
printf '\n== files containing AgentNamespace ==\n'
rg -n --hidden --glob '!**/.git/**' 'AgentNamespace' .
printf '\n== agent.go context ==\n'
cat -n api/hypershift/v1beta1/agent.go | sed -n '1,80p'
printf '\n== surrounding uses in Go files if any ==\n'
rg -n --hidden --glob '*.go' 'AgentNamespace' api control-plane-operator support .Repository: openshift/hypershift
Length of output: 11726
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Determine whether the change is only API serialization or also breaks local consumers.
ast-grep outline api/hypershift/v1beta1/agent.goRepository: openshift/hypershift
Length of output: 326
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Map the API file structure to see whether AgentNamespace is isolated or grouped with related fields.
ast-grep outline api/hypershift/v1beta1/agent.goRepository: openshift/hypershift
Length of output: 326
Keep AgentNamespace as a string or update all direct consumers
AgentNamespace is now *string, but several in-tree callers still use value semantics (for example hypershift-operator/controllers/hostedcluster/internal/platform/agent/agent.go, hypershift-operator/controllers/hostedcluster/internal/platform/agent/agent_test.go, and e2e code). Those struct literals and == "" checks won't compile until every use is switched to ptr.Deref(...) or the field type stays string.
🤖 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 `@api/hypershift/v1beta1/agent.go` at line 19, AgentNamespace was changed to
*string, but existing consumers still assume string semantics and will fail to
compile. Either keep AgentNamespace as a string in the Agent type, or update
every direct consumer to use pointer-safe handling. In particular, fix the
struct literals and empty checks in AgentNamespace-related code paths such as
the Agent struct in agent.go and its callers/tests by switching comparisons like
== "" to ptr.Deref(...) and by passing pointers where the field is populated.
| // +optional | ||
| // +kubebuilder:validation:Enum:="";OnDemand;Spot;CapacityBlocks | ||
| MarketType MarketType `json:"marketType,omitempty"` | ||
| MarketType *MarketType `json:"marketType,omitempty"` |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
rg -nP '\bplacement\.(MarketType|Spot)\b' hypershift-operator/controllers/nodepool/aws.go -C2Repository: openshift/hypershift
Length of output: 1078
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo '--- api/hypershift/v1beta1/aws.go ---'
ast-grep outline api/hypershift/v1beta1/aws.go --view expanded | sed -n '1,220p'
echo
echo '--- hypershift-operator/controllers/nodepool/aws.go ---'
ast-grep outline hypershift-operator/controllers/nodepool/aws.go --view expanded | sed -n '1,260p'
echo
echo '--- relevant slices ---'
sed -n '1,220p' api/hypershift/v1beta1/aws.go
echo
sed -n '1,320p' hypershift-operator/controllers/nodepool/aws.goRepository: openshift/hypershift
Length of output: 31873
Update the NodePool AWS consumer for pointer fields
PlacementOptions.MarketTypeis now a*MarketType, soisSpotEnabledandapplyAWSPlacementOptionsneed to dereference it before comparing againstMarketTypeSpot/MarketTypeOnDemand; the current code no longer type-checks.applyAWSPlacementOptionsalso dereferencesplacement.Spot.MaxPricewithout a nil guard whenmarketType=Spotbutspotis omitted.json:"spot,omitempty,omitzero"is redundant on a pointer field;omitemptyalready omitsnil.
🤖 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 `@api/hypershift/v1beta1/aws.go` at line 112, Update the NodePool AWS consumer
to handle the new pointer-based PlacementOptions fields: in isSpotEnabled and
applyAWSPlacementOptions, dereference PlacementOptions.MarketType before
comparing it to MarketTypeSpot or MarketTypeOnDemand so the code type-checks
again. In applyAWSPlacementOptions, add a nil check before reading
placement.Spot.MaxPrice when marketType is Spot and Spot may be omitted. Also
simplify the Spot JSON tag by removing the redundant omitzero from the pointer
field’s json annotation.
| // +default=false | ||
| // +optional | ||
| MultiArch bool `json:"multiArch"` | ||
| MultiArch *bool `json:"multiArch,omitempty,omitempty"` |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Duplicate omitempty in the JSON tag.
json:"multiArch,omitempty,omitempty" repeats omitempty.
Fix
- MultiArch *bool `json:"multiArch,omitempty,omitempty"`
+ MultiArch *bool `json:"multiArch,omitempty"`📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| MultiArch *bool `json:"multiArch,omitempty,omitempty"` | |
| MultiArch *bool `json:"multiArch,omitempty"` |
🤖 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 `@api/hypershift/v1beta1/aws.go` at line 413, The JSON tag on the MultiArch
field in aws.go has a duplicated omitempty option. Update the MultiArch struct
field tag in the aws.go type definition to use a single omitempty in the json
annotation, keeping the field name unchanged.
| // + "[abdilmptsCNP]*" - Additive features | ||
| // + "(_[A-Z]*[0-9]+[A-Z]*)?" - Optional accelerator types | ||
| // +kubebuilder:validation:Pattern=`^(Standard_|Basic_)?[A-Z]+[0-9]+(-[0-9]+)?[abdilmptsCNP]*(_[A-Z]*[0-9]+[A-Z]*)?(_v[0-9]+)?$` | ||
| // +kubebuilder:validation:XValidation=`^(Standard_|Basic_)?[A-Z]+[0-9]+(-[0-9]+)?[abdilmptsCNP]*(_[A-Z]*[0-9]+[A-Z]*)?(_v[0-9]+)?$` |
There was a problem hiding this comment.
🎯 Functional Correctness | 🔴 Critical | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Map the Azure API file and inspect the relevant ranges.
ast-grep outline api/hypershift/v1beta1/azure.go --view expanded
echo '--- XValidation occurrences in azure.go ---'
rg -n 'XValidation=`|Pattern=|matches\(' api/hypershift/v1beta1/azure.go
echo '--- Surrounding lines for the reported locations ---'
sed -n '35,55p;165,210p;685,705p' api/hypershift/v1beta1/azure.go
echo '--- Compare with aws.go examples mentioned by the review ---'
rg -n 'XValidation=`|Pattern=|matches\(' api/hypershift/v1beta1/aws.go
sed -n '35,55p;165,210p;685,705p' api/hypershift/v1beta1/aws.goRepository: openshift/hypershift
Length of output: 26208
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo '--- Repo-wide XValidation forms ---'
rg -n '\+kubebuilder:validation:XValidation' api/hypershift/v1beta1 api | sed -n '1,220p'
echo '--- Regex validation via Pattern in Azure API ---'
rg -n '\+kubebuilder:validation:Pattern=' api/hypershift/v1beta1/azure.go api/hypershift/v1beta1/aws.go
echo '--- Nearby api/ guidance for validation markers ---'
rg -n 'XValidation|Pattern=' api/AGENTS.md AGENTS.md .claude/rules/webhook-validation.md docs/content/reference/goals-and-design-invariants.mdRepository: openshift/hypershift
Length of output: 49887
🌐 Web query:
kubebuilder validation XValidation=regex shorthand supported Pattern CEL marker syntax
💡 Result:
Kubebuilder does not provide a specific "regex shorthand" syntax within the +kubebuilder:validation:XValidation marker. Instead, it relies on the Common Expression Language (CEL) matches function to perform regex validation [1][2]. To perform regex validation within an XValidation rule, you must use the standard CEL matches function, which takes a string and a regular expression pattern as arguments [2]. Example usage: // +kubebuilder:validation:XValidation:rule="self.matches('^[a-zA-Z0-9]*$')",message="Field must be alphanumeric" Key points: 1. Marker Syntax: The XValidation marker follows the standard Kubebuilder marker format, where the rule is defined as a string within the rule parameter [3][4]. 2. Regex in CEL: The matches function is the native way to perform regex checks in CEL [2]. It is not a shorthand but a functional approach. 3. Pattern Marker: If you only need simple pattern matching without the advanced logic provided by CEL (like cross-field validation or immutability checks), it is standard practice to use the dedicated +kubebuilder:validation:Pattern marker instead [3][4]. This marker accepts a regex string directly and is often cleaner for single-field pattern constraints [4]. Using the Pattern marker: // +kubebuilder:validation:Pattern=^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ DNSName string When using regex in markers, it is recommended to use backticks (e.g., Pattern=...``) to avoid issues with quoting special characters, as these markers are parsed according to Go's string syntax [5].
Citations:
- 1: https://kubernetes.io/blog/2022/09/23/crd-validation-rules-beta/
- 2: https://github.com/kubernetes/enhancements/tree/master/keps/sig-api-machinery/2876-crd-validation-expression-language
- 3: https://github.com/kubernetes-sigs/controller-tools/blob/master/pkg/crd/markers/validation.go
- 4: https://kubebuilder.io/reference/markers/crd-validation.html
- 5: Unable to create schema validation with a regex that is quoted with single quotes kubernetes-sigs/controller-tools#315
🌐 Web query:
controller-tools XValidation bare syntax XValidation=regex marker parser rule field docs
💡 Result:
The controller-tools XValidation marker is used to apply Common Expression Language (CEL) validation rules to Custom Resource Definition (CRD) fields [1][2]. It allows for complex, declarative validation logic that goes beyond standard OpenAPI schema constraints [1]. Syntax and Usage: The marker is placed as a comment above the relevant Go field in your types definition file (e.g., _types.go) [3]. The standard syntax is: // +kubebuilder:validation:XValidation:rule="",message="" Key parameters include: - rule: The CEL expression that must evaluate to true for the validation to pass [2]. Within this rule, self refers to the current field's value [1]. - message: (Optional) A custom error message to display if the validation rule fails [2]. - messageExpression: (Optional) A CEL expression that evaluates to a string, allowing for dynamic error messages. - reason: (Optional) A machine-readable reason code for the validation failure (e.g., "FieldValueInvalid"). - fieldPath: (Optional) Specifies the path to the field being validated (useful for complex objects or array items) [1]. You can repeat the XValidation marker on a single field to apply multiple independent validation expressions; all rules must evaluate to true for the validation to pass [1][2]. Example: // +kubebuilder:validation:XValidation:rule="self.minReplicas <= self.replicas",message="replicas must be greater than or equal to minReplicas" Replicas int32 json:"replicas" For array items, you can use the +kubebuilder:validation:items:XValidation prefix to apply rules to each element in a list [1]. It is important to distinguish that these CEL rules operate on the CRD schema level using self [1][4]. This is distinct from ValidatingAdmissionPolicy, which uses variables like object and oldObject [4]. For further details, refer to the official Kubebuilder documentation on CRD validation markers [1][5].
Citations:
- 1: https://kubebuilder.io/reference/markers/crd-validation.html
- 2: https://github.com/kubernetes-sigs/controller-tools/blob/55efe4be40394a288216dab63156b0a64fb82929/pkg/crd/markers/validation.go
- 3: https://kubebuilder.io/reference/generating-crd
- 4: 📖 docs: add comprehensive XValidation CEL documentation and examples kubernetes-sigs/controller-tools#1341
- 5: https://book.kubebuilder.io/reference/markers/crd-validation.html
🌐 Web query:
controller-tools validation.go XValidation bare equals parses rule or invalid syntax source
💡 Result:
In controller-tools, the +kubebuilder:validation:XValidation marker is a multi-option marker used to define CEL (Common Expression Language) validation rules for Custom Resource Definitions (CRDs) [1][2][3]. Because it is a multi-option marker, it uses a specific syntax where arguments are defined as key-value pairs separated by colons and commas [4]. When using this marker, you must provide the parameters (such as rule, message, or reason) explicitly using this format [4][3]. A bare equals sign or a value without a specified key (e.g., +kubebuilder:validation:XValidation="myRule") is not the correct syntax for multi-option markers and will result in a parsing error or be treated as invalid syntax by controller-gen [4]. Correct usage follows this pattern: // +kubebuilder:validation:XValidation:rule="<CEL_expression>",message="<error_message>",reason="" Key details: - Multi-option syntax: The marker name is followed by the argument name and its value separated by an equals sign (e.g., rule="..."), or in some contexts, colon-separated key-value pairs [4][3]. - CEL expressions: The rule field requires a valid CEL expression string (e.g., "self.replicas > 0") [5][3]. - Repetition: This marker may be repeated to specify multiple independent validation rules [1][3]. If you encounter errors, ensure your marker is formatted as a multi-option marker rather than an anonymous or empty marker [4].
Citations:
- 1: https://github.com/kubernetes-sigs/controller-tools/blob/55efe4be40394a288216dab63156b0a64fb82929/pkg/crd/markers/validation.go
- 2: ✨ Add XValidation CRD marker for KEP-2876 support. kubernetes-sigs/controller-tools#653
- 3: https://www.kubebuilder.io/reference/markers/crd-validation
- 4: https://kubebuilder.io/reference/markers
- 5: 📖 docs: add comprehensive XValidation CEL documentation and examples kubernetes-sigs/controller-tools#1341
Replace the regex marker syntax here
The bare +kubebuilder:validation:XValidation=\...`form isn’t valid controller-tools syntax. Use+kubebuilder:validation:Pattern=`...`for these fields, orXValidation:rule="self.matches('...')"` if you need CEL.
🤖 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 `@api/hypershift/v1beta1/azure.go` at line 45, The validation marker on the
Azure type is using invalid controller-tools syntax, so update the annotation on
the affected field/type in azure.go to the correct form. If this is meant to be
a regex check, replace the current kubebuilder marker with
kubebuilder:validation:Pattern; if you need CEL-based validation, switch to
kubebuilder:validation:XValidation with a rule expression using
self.matches(...). Use the existing Azure-related field/type definition to
locate the marker and keep the regex itself unchanged.
| // +default=None | ||
| // +kubebuilder:validation:Enum=None;PVC | ||
| // +required | ||
| Type KubevirtCachingStrategyType `json:"type"` | ||
| Type KubevirtCachingStrategyType `json:"type,omitempty,omitempty"` |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
+default on a +required field, plus duplicate omitempty.
KubevirtCachingStrategy.Type: +default=None is combined with +required (default never applies before the required check), and json:"type,omitempty,omitempty" repeats omitempty.
Fix
- // +default=None
// +kubebuilder:validation:Enum=None;PVC
// +required
- Type KubevirtCachingStrategyType `json:"type,omitempty,omitempty"`
+ Type KubevirtCachingStrategyType `json:"type,omitempty"`(If a default is intended, make the field +optional instead.)
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| // +default=None | |
| // +kubebuilder:validation:Enum=None;PVC | |
| // +required | |
| Type KubevirtCachingStrategyType `json:"type"` | |
| Type KubevirtCachingStrategyType `json:"type,omitempty,omitempty"` | |
| // +kubebuilder:validation:Enum=None;PVC | |
| // +required | |
| Type KubevirtCachingStrategyType `json:"type,omitempty"` |
🤖 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 `@api/hypershift/v1beta1/kubevirt.go` around lines 82 - 85, Update
KubevirtCachingStrategy.Type so the API tags are consistent: remove the
duplicated omitempty in the json tag and resolve the conflicting validation
markers by either dropping +default=None or changing the field to +optional if a
default is actually intended. Use the KubevirtCachingStrategyType definition in
kubevirt.go to locate the field and keep the kubebuilder annotations aligned
with the desired schema.
Source: Coding guidelines
| // +default= | ||
| // +required | ||
| RootVolume *KubevirtRootVolume `json:"rootVolume"` | ||
| RootVolume *KubevirtRootVolume `json:"rootVolume,omitempty,omitempty"` |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
Malformed +default= markers and duplicate omitempty.
RootVolume(150-152):+default=has no value and is paired with+required; the tagjson:"rootVolume,omitempty,omitempty"also duplicatesomitempty. A blank default on a required field is both a guideline violation ("+defaultmust be paired with+optional") and an empty marker value.Compute(156-158):+default=again has no value.
Fix
- // +default=
- // +required
- RootVolume *KubevirtRootVolume `json:"rootVolume,omitempty,omitempty"`
+ // +required
+ RootVolume *KubevirtRootVolume `json:"rootVolume,omitempty"`
// compute contains values representing the virtual hardware requested for the VM
//
// +optional
- // +default=
Compute *KubevirtCompute `json:"compute,omitempty"`Also applies to: 156-158
🤖 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 `@api/hypershift/v1beta1/kubevirt.go` around lines 150 - 152, The Kubevirt
volume markers are malformed: `RootVolume` and `Compute` in the
`KubevirtMachineSpec`-related definitions use empty `+default=` markers, and
`RootVolume` also has a duplicated `omitempty` in its JSON tag. Update those
field annotations so `+default` is either removed or given a real value and
paired correctly with the appropriate optional/required marker, and fix
`RootVolume`’s `json` tag to include `omitempty` only once.
Source: Coding guidelines
| Flavor *string `json:"flavor,omitempty"` | ||
|
|
||
| // imageName is the OpenStack Glance image name to use for node instances. If unspecified, the default | ||
| // is chosen based on the NodePool release payload image. | ||
| // | ||
| // +optional | ||
| // +kubebuilder:validation:MaxLength=255 | ||
| ImageName string `json:"imageName,omitempty"` | ||
| ImageName *string `json:"imageName,omitempty"` |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
rg -nP '\.OpenStack\.(ImageName|Flavor)\b' hypershift-operator/controllers/nodepool/openstack.go -C2Repository: openshift/hypershift
Length of output: 774
🏁 Script executed:
#!/bin/bash
set -euo pipefail
sed -n '1,120p' api/hypershift/v1beta1/openstack.go
printf '\n---\n'
sed -n '1,140p' hypershift-operator/controllers/nodepool/openstack.goRepository: openshift/hypershift
Length of output: 10342
🏁 Script executed:
#!/bin/bash
set -euo pipefail
rg -n '\.OpenStack\.(ImageName|Flavor)\b|Platform\.OpenStack\.(ImageName|Flavor)\b|ImageName == ""|Flavor == ""|ImageName[^[:alnum:]_]' hypershift-operator api -C2Repository: openshift/hypershift
Length of output: 15868
🏁 Script executed:
#!/bin/bash
set -euo pipefail
rg -n 'type OpenStackMachineSpec|Flavor .*string|Image .*ImageFilter|type ImageFilter' hypershift-operator api -C3Repository: openshift/hypershift
Length of output: 697
🏁 Script executed:
#!/bin/bash
set -euo pipefail
fd -a 'types.go' hypershift-operator api | rg 'cluster-api-provider-openstack|openstack'
printf '\n---\n'
rg -n 'type OpenStackMachineSpec|type ImageFilter|Flavor .*string|Image .*string' . -g '*.go' -C3Repository: openshift/hypershift
Length of output: 158
🏁 Script executed:
#!/bin/bash
set -euo pipefail
sed -n '1,80p' hypershift-operator/controllers/nodepool/openstack/openstack.go
printf '\n---\n'
rg -n 'type OpenStackMachineSpec|type ImageFilter|Flavor' $(go env GOPATH 2>/dev/null)/pkg/mod -g '*.go' -C2 | head -n 80Repository: openshift/hypershift
Length of output: 4116
🌐 Web query:
cluster-api-provider-openstack OpenStackMachineSpec Flavor type ImageFilter Name type
💡 Result:
In the Kubernetes Cluster API Provider OpenStack (CAPO), specifically within the OpenStackMachineSpec, the flavor and image selection fields use specific structures to define desired compute resources and OS images [1][2]. Flavor Configuration The OpenStackMachineSpec allows you to specify a flavor using either the name of the flavor or its unique ID [3]. - Flavor: A string field used to specify the flavor by name [3]. - FlavorID: A string field used to specify the flavor by its UUID [2][3]. Note: Validation rules (Common Expression Language, or CEL) in modern versions of CAPO require that at least one of these two fields (flavor or flavorID) must be set [3]. Image Configuration Images are selected using an ImageFilter, which allows for flexible identification of the Glance image [4]. - ImageFilter: This object is used within the OpenStackMachineSpec to define criteria for selecting an image rather than hardcoding an ID [4]. - Name: Within the ImageFilter, the 'name' field is a string used to specify the exact name of the image to be used [4]. Beyond the name, ImageFilters can often include other criteria such as tags to narrow down the selection [4]. For the most accurate and version-specific definitions (e.g., v1beta2), always refer to the official Cluster API Provider OpenStack API reference documentation, which defines these fields as part of the OpenStackMachineSpec schema [1][2].
Citations:
- 1: https://cluster-api-openstack.sigs.k8s.io/api/v1beta2/api
- 2: https://github.com/kubernetes-sigs/cluster-api-provider-openstack/blob/main/api/v1beta2/types.go
- 3: FlavorID exposed in OpenstackMachine but not propagated to OpenstackServer kubernetes-sigs/cluster-api-provider-openstack#2550
- 4: https://cluster-api-openstack.sigs.k8s.io/topics/crd-changes/v1alpha7-to-v1beta1
Handle *string in OpenStack NodePool consumers. In hypershift-operator/controllers/nodepool/openstack.go, ptr.To(nodePool.Spec.Platform.OpenStack.Flavor) now becomes **string, and setOpenStackConditions still treats ImageName as a plain string. Update both call sites to dereference/nil-guard these fields so nil and empty stay consistent and the OpenStack controller keeps building.
🤖 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 `@api/hypershift/v1beta1/openstack.go` around lines 22 - 29, OpenStack NodePool
consumers now receive pointer fields, so update the
`hypershift-operator/controllers/nodepool/openstack.go` call sites to handle
`Spec.Platform.OpenStack.Flavor` and `ImageName` as `*string` instead of
assuming plain strings. In the code path that currently uses
`ptr.To(nodePool.Spec.Platform.OpenStack.Flavor)`, dereference only after nil
checks so you do not create a `**string`, and in `setOpenStackConditions` add
nil/empty guards before using `ImageName` so the controller preserves existing
empty-vs-nil behavior and compiles cleanly.
| // +immutable | ||
| // +required | ||
| KubeCloudControllerCreds corev1.LocalObjectReference `json:"kubeCloudControllerCreds"` | ||
| KubeCloudControllerCreds corev1.LocalObjectReference `json:"kubeCloudControllerCreds,omitempty"` |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win
omitempty is a no-op on these LocalObjectReference struct fields.
KubeCloudControllerCreds, NodePoolManagementCreds, IngressOperatorCloudCreds, StorageOperatorCloudCreds, and ImageRegistryOperatorCloudCreds are non-pointer structs, so json:"...,omitempty" will not omit them. As per coding guidelines, "use omitzero for struct fields because omitempty does not omit non-pointer structs." Switch these tags to omitzero.
Also applies to: 276-276, 292-292, 314-314, 334-334
🤖 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 `@api/hypershift/v1beta1/powervs.go` at line 258, The JSON tags on the
LocalObjectReference fields are using omitempty even though these are
non-pointer structs, so they will never be omitted. Update the tags on
KubeCloudControllerCreds, NodePoolManagementCreds, IngressOperatorCloudCreds,
StorageOperatorCloudCreds, and ImageRegistryOperatorCloudCreds in the PowerVS
API types to use omitzero instead, keeping the struct field names and types
unchanged.
Source: Coding guidelines
| // +kubebuilder:validation:Optional | ||
| // +kubebuilder:validation:Pattern=`^\d+(B|KiB|MiB|GiB|TiB)?$` | ||
| // +optional | ||
| // +kubebuilder:validation:XValidation=`^\d+(B|KiB|MiB|GiB|TiB)?$` |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
sed -n '100,230p' api/scheduling/v1alpha1/clustersizingconfiguration_types.go
printf '\n---\n'
rg -n "kubebuilder:validation:XValidation" api -g '*.go'Repository: openshift/hypershift
Length of output: 50377
🏁 Script executed:
git ls-files | rg '(^|/)clustersizingconfiguration.*\.(yaml|yml|json)$|(^|/)customresourcedefinitions.*\.(yaml|yml)$|(^|/)crd.*\.(yaml|yml)$'
printf '\n---\n'
rg -n "kasGoMemLimit|slidingWindow|transitionDelay|XValidation|pattern" -g '*.yaml' -g '*.yml' -g '*.json' .Repository: openshift/hypershift
Length of output: 50377
🌐 Web query:
kubebuilder validation XValidation rule syntax Pattern regex controller-gen
💡 Result:
In Kubebuilder and controller-gen, there are two distinct ways to handle regex-based validation for CRD fields: the standard OpenAPI Pattern marker and the more flexible CEL XValidation marker [1][2]. 1. Standard Pattern Validation The +kubebuilder:validation:Pattern marker is used for simple, static regex requirements [1][2]. Example: // +kubebuilder:validation:Pattern=^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ DNSName string When using regex in these markers, if the expression contains special characters or is not considered a "trivial" string, it should be quoted [3]. 2. CEL XValidation (Complex Regex) For more advanced scenarios, such as validation that depends on other fields or requires complex logic, you should use the +kubebuilder:validation:XValidation marker [1][2]. This marker leverages the Common Expression Language (CEL), which provides a native .matches() method for regex [4][5]. Syntax for CEL regex: // +kubebuilder:validation:XValidation:rule="self.matches('^[a-z0-9]+$')",message="Field must be lowercase alphanumeric" MyField string When using CEL rules, note the following: - Escaping: In Go marker comments, you may need to double-escape backslashes if your regex pattern requires them (e.g., \\d for a digit) [5]. - Logic: You can combine regex with other CEL logic, such as field comparisons or conditional checks [1][4]. - Multiple Rules: You can repeat the XValidation marker to specify multiple independent rules that must all evaluate to true [2][6]. The controller-gen tool processes these markers during the Go code generation phase to produce the corresponding x-kubernetes-validations or pattern entries in your CRD's OpenAPI schema [2][7].
Citations:
- 1: https://master.book.kubebuilder.io/reference/markers/crd-validation.html
- 2: https://github.com/kubernetes-sigs/controller-tools/blob/master/pkg/crd/markers/validation.go
- 3: Unable to create schema validation with a regex that is quoted with single quotes kubernetes-sigs/controller-tools#315
- 4: https://kubernetes.io/docs/reference/using-api/cel/
- 5: https://linuxcent.com/kubernetes-crd-cel-validation/
- 6: https://book-v3.book.kubebuilder.io/reference/markers/crd-validation
- 7: https://kubebuilder.io/reference/markers.html
🏁 Script executed:
git ls-files | rg 'clustersizingconfiguration|customresourcedefinitions|apiextensions'
printf '\n---\n'
rg -n "kasGoMemLimit|slidingWindow|increase|decrease|pattern:|x-kubernetes-validations" -g '*.yaml' -g '*.yml' .Repository: openshift/hypershift
Length of output: 50377
🏁 Script executed:
fd -a "validation.go" vendor . | rg "controller-tools|controller\s*tools|pkg/crd/markers"
sed -n '1,240p' $(fd -a "validation.go" vendor . | rg "controller-tools|controller\s*tools|pkg/crd/markers" | head -n 1)Repository: openshift/hypershift
Length of output: 9301
🏁 Script executed:
rg -n "type XValidation|XValidation struct|XValidation.*Value|x-kubernetes-validations" /home/jailuser/git/hack/tools/vendor/sigs.k8s.io/controller-tools/pkg/crd/markers/validation.go /home/jailuser/git/hack/tools/vendor/sigs.k8s.io/controller-tools/pkg/crd -g '*.go'Repository: openshift/hypershift
Length of output: 694
🏁 Script executed:
sed -n '240,420p' /home/jailuser/git/hack/tools/vendor/sigs.k8s.io/controller-tools/pkg/crd/markers/validation.go
printf '\n---\n'
sed -n '1,220p' /home/jailuser/git/hack/tools/vendor/sigs.k8s.io/controller-tools/pkg/crd/markers/patch_validation.goRepository: openshift/hypershift
Length of output: 16267
🏁 Script executed:
rg -n "clustersizingconfiguration|kasGoMemLimit|slidingWindow|increase|decrease|x-kubernetes-validations|pattern:" api/scheduling/v1alpha1 -g '*.yaml' -g '*.yml' -g '*.json' -g '*.go'Repository: openshift/hypershift
Length of output: 1411
🏁 Script executed:
rg -n "type XValidation|XValidation\{|make.*XValidation|Parse.*XValidation|validation.*XValidation" /home/jailuser/git/hack/tools/vendor/sigs.k8s.io/controller-tools/pkg/crd/markers -g '*.go'Repository: openshift/hypershift
Length of output: 1554
🏁 Script executed:
git ls-files | rg 'clustersizingconfiguration.*crd|scheduling.*crd|cluster.*sizing.*yaml|cluster.*sizing.*json'Repository: openshift/hypershift
Length of output: 270
🏁 Script executed:
rg -n "^type XValidation|^type .*XValidation|Rule string|Message string|OptionalOldSelf" /home/jailuser/git/hack/tools/vendor/sigs.k8s.io/controller-tools/pkg/crd/markers -g '*.go'Repository: openshift/hypershift
Length of output: 1007
🏁 Script executed:
sed -n '1,260p' cmd/install/assets/crds/hypershift-operator/scheduling.hypershift.openshift.io_clustersizingconfigurations.yaml
printf '\n---\n'
rg -n "kasGoMemLimit|slidingWindow|increase|decrease|x-kubernetes-validations|pattern:" cmd/install/assets/crds/hypershift-operator/scheduling.hypershift.openshift.io_clustersizingconfigurations.yamlRepository: openshift/hypershift
Length of output: 16323
🏁 Script executed:
rg -n "kasGoMemLimit|slidingWindow|increase|decrease" cmd/install/assets/crds/hypershift-operator/scheduling.hypershift.openshift.io_clustersizingconfigurations.yamlRepository: openshift/hypershift
Length of output: 336
🏁 Script executed:
rg -n "kasGoMemLimit|slidingWindow|increase|decrease|x-kubernetes-validations|pattern:" cmd/install/assets/crds/hypershift-operator/scheduling.hypershift.openshift.io_clustersizingconfigurations.yamlRepository: openshift/hypershift
Length of output: 2013
🏁 Script executed:
rg -n -A3 -B3 "kasGoMemLimit|slidingWindow|increase|decrease|x-kubernetes-validations|pattern:" cmd/install/assets/crds/hypershift-operator/scheduling.hypershift.openshift.io_clustersizingconfigurations.yamlRepository: openshift/hypershift
Length of output: 8440
🏁 Script executed:
rg -n -A40 -B5 "func \\(m XValidation\\) ApplyToSchema" /home/jailuser/git/hack/tools/vendor/sigs.k8s.io/controller-tools/pkg/crd/markers/validation.goRepository: openshift/hypershift
Length of output: 1228
Use Pattern for these regex constraints
api/scheduling/v1alpha1/clustersizingconfiguration_types.go:120,184,203,212 — these fields are simple string regex checks, so they should use +kubebuilder:validation:Pattern=... instead of XValidation, which generates CEL rules.
🤖 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 `@api/scheduling/v1alpha1/clustersizingconfiguration_types.go` at line 120, The
regex-only validation markers in clustersizingconfiguration_types.go should use
schema Pattern constraints instead of XValidation/CEL. Update the affected field
annotations on the ClusterSizingConfiguration types to replace each
+kubebuilder:validation:XValidation regex with +kubebuilder:validation:Pattern,
keeping the same regex and applying it to the relevant string fields in the
struct definitions.
Source: Coding guidelines
There was a problem hiding this comment.
The last commit pushed a huge number of serialization and documentation changes that were not requested, these should be reverted
There was a problem hiding this comment.
Done. Removed all serialization and documentation changes from the last commit. It now contains only the two test YAML files (HostedCluster and NodePool AWS test suites).
AI-assisted response via Claude Code
| value: "baz" | ||
| type: AWS | ||
|
|
||
| - name: when adding a unique key to resourceTags with pre-existing duplicate keys it should pass |
There was a problem hiding this comment.
These new tests are missing either expected or expectedError and are therefore incomplete
There was a problem hiding this comment.
Done. Verified each ratcheting test against envtest — all four onUpdate scenarios pass (ratcheted), matching the established pattern in stable.hostedclusters.ratcheting.testsuite.yaml. The onCreate duplicate-key tests have expectedError: "Duplicate value" as expected.
AI-assisted response via Claude Code
There was a problem hiding this comment.
I believe this is still not addressed. Each update test should have an expected value to show that the post-update value matches expectation. The current tests will only check whether the APIServer returns an error
|
The last commit to add new test cases also ran a faulty lint-fix which fixed a bunch of API issues that pre-date linting and cannot be resolved. Ignore all coderabbit comments from the last commit, remove the faulty lint-fix changes and update the last commit only to the test changes. /test address-review-comments |
|
Review agent triggered. View job |
47417bf to
a6403ca
Compare
|
/test e2e-aws |
| value: "baz" | ||
| type: AWS | ||
|
|
||
| - name: when updating resourceTags to different but still-duplicate keys it should pass |
There was a problem hiding this comment.
I would not have expected this test case to pass.
Each test case here should have an expected or expectedError, please add the relevant expectations to each test case. The tests are incomplete unless they have an expected or an expectedError
There was a problem hiding this comment.
Confirmed: this test case does pass. Kubernetes CRD validation ratcheting preserves existing structural violations (duplicate map keys) even when the affected field is modified, as long as the same type of violation existed in the old value.
I attempted to add expected to each passing onUpdate test, but assertObjectMatch does full spec equality — the API server adds defaulted fields not present in the test YAML, causing the comparison to fail. This matches the pattern in the existing ratcheting tests (e.g., stable.hostedclusters.ratcheting.testsuite.yaml line 85–161 also omits expected for passing onUpdate cases). The passing tests implicitly assert "no error on update."
AI-assisted response via Claude Code
|
/test address-review-comments |
|
Review agent triggered. View job |
yuqi-zhang
left a comment
There was a problem hiding this comment.
Just a couple more comments (main concern is still Joel's test concerns)
| // | ||
| // +kubebuilder:validation:MaxItems=25 | ||
| // +optional | ||
| // +listType=map |
There was a problem hiding this comment.
(non-blocking) Since this is being updated, perhaps we can also update the godoc to reference unique key requirements, as well as what happens when the field is omitted
| value: "baz" | ||
| type: AWS | ||
|
|
||
| - name: when adding a unique key to resourceTags with pre-existing duplicate keys it should pass |
There was a problem hiding this comment.
I believe this is still not addressed. Each update test should have an expected value to show that the post-update value matches expectation. The current tests will only check whether the APIServer returns an error
| // resourceTags is the list of tags to apply to the EndpointService | ||
| // +optional | ||
| // +kubebuilder:validation:MaxItems=25 | ||
| // +listType=map |
There was a problem hiding this comment.
Technically the unit tests don't cover this subfield in AWSEndpointServiceSpec - but since it's functionally identical, maybe that's not necessary.
(This also has very little godocs, possibly an opportunity to beef that up)
|
/test address-review-comments |
|
Review agent triggered. View job |
Add +listType=map and +listMapKey=key markers to all three AWSResourceTag list fields: AWSNodePoolPlatform.ResourceTags, AWSPlatformSpec.ResourceTags, and AWSEndpointServiceSpec.ResourceTags. This makes the Kubernetes API server reject requests with duplicate tag keys at admission time, instead of silently dropping all but the last value for a given key. Signed-off-by: OpenShift CI Bot <ci-bot@redhat.com>
Regenerate after adding +listType=map and +listMapKey=key markers to AWS resourceTags fields. The generated CRDs now include x-kubernetes-list-type: map and x-kubernetes-list-map-keys: [key] on the resourceTags arrays for NodePool, HostedCluster, and AWSEndpointService resources. Signed-off-by: OpenShift CI Bot <ci-bot@redhat.com>
Add envtest tests for both NodePool and HostedCluster to verify that duplicate tag keys in AWS resourceTags are rejected by CRD schema validation, and that unique tag keys are accepted. Also add onUpdate ratcheting tests to demonstrate that existing resources with pre-existing duplicate tag keys can still be updated when an unrelated field changes, confirming CRD validation ratcheting works correctly for the new listType=map constraint. Signed-off-by: OpenShift CI Bot <ci-bot@redhat.com> Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
a6403ca to
8c2e7f7
Compare
|
@hypershift-jira-solve-ci[bot]: This pull request references Jira Issue OCPBUGS-34078, which is valid. 3 validation(s) were run on this bug
No GitHub users were found matching the public email listed for the QA contact in Jira (yinzhou@redhat.com), skipping review request. 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. |
|
@hypershift-jira-solve-ci[bot]: The following test failed, say
Full PR test history. Your PR dashboard. DetailsInstructions 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. |
|
Now I have all the information needed. Let me compile the final report. Test Failure Analysis CompleteJob Information
Test Failure AnalysisErrorSummaryThe PR adds Root CauseThe The This affects exactly 4 CRDs (the CustomNoUpgrade superset variants that are checked, plus the ungated awsendpointservices CRD):
The change itself (adding list-map semantics to enforce unique tag keys) is an intentional, non-breaking API evolution — it adds server-side uniqueness enforcement but does not remove fields, change types, or add new required fields. RecommendationsOption 1 (Recommended): Update the crdify config to handle unhandled changes as warnings. Add unhandledEnforcement: Warn
validations:
- name: enum
enforcement: Error
configuration:
additionPolicy: AllowThis treats diffs in schema properties not covered by any built-in validator (like Option 2: Use a one-time Prow override. As suggested by the tool's own output, use Option 3: Combine both options. Use Evidence
|
|
You need to fix the |
|
/test address-review-comments |
|
Review agent triggered. View job |
What this PR does / why we need it:
Adds
+listType=mapand+listMapKey=keymarkers to all threeAWSResourceTaglist fields (AWSNodePoolPlatform.ResourceTags,AWSPlatformSpec.ResourceTags, andAWSEndpointServiceSpec.ResourceTags). This makes the Kubernetes API server reject requests with duplicate tag keys at admission time, instead of silently dropping all but the last value for a given key.Changes include:
+listType=mapand+listMapKey=keyto the three AWS resourceTags fieldsx-kubernetes-list-type: mapandx-kubernetes-list-map-keys: [key]on the resourceTags arrays for NodePool, HostedCluster, and AWSEndpointService resourcesWhich issue(s) this PR fixes:
Fixes https://redhat.atlassian.net/browse/OCPBUGS-34078
Special notes for your reviewer:
The
+listType=mapwith+listMapKey=keystrategy ensures that the API server treats thekeyfield as a unique identifier within each resourceTags list. Any create or update request containing duplicate tag keys will be rejected with a validation error.Checklist:
Always review AI generated responses prior to use.
Generated with Claude Code via openshift-developer plugin
Summary by CodeRabbit