-
Notifications
You must be signed in to change notification settings - Fork 566
OCPBUGS-77827 fix(api): add missing has() check for servingCerts in validation #7901
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -6352,7 +6352,8 @@ spec: | |||||||||||
| - message: APIServer loadBalancer hostname cannot be in ClusterConfiguration.apiserver.servingCerts.namedCertificates[] | ||||||||||||
| rule: '!self.services.exists(s, s.service == ''APIServer'' && has(s.servicePublishingStrategy.loadBalancer) | ||||||||||||
| && s.servicePublishingStrategy.loadBalancer.hostname != "" && has(self.configuration) | ||||||||||||
| && has(self.configuration.apiServer) && self.configuration.apiServer.servingCerts.namedCertificates.exists(cert, | ||||||||||||
| && has(self.configuration.apiServer) && has(self.configuration.apiServer.servingCerts) | ||||||||||||
| && self.configuration.apiServer.servingCerts.namedCertificates.exists(cert, | ||||||||||||
|
Comment on lines
+6355
to
+6356
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🌐 Web query:
💡 Result: When to guard optional object/list fields with
|
||||||||||||
| && has(self.configuration.apiServer) && has(self.configuration.apiServer.servingCerts) | |
| && self.configuration.apiServer.servingCerts.namedCertificates.exists(cert, | |
| && has(self.configuration.apiServer) && has(self.configuration.apiServer.servingCerts) | |
| && has(self.configuration.apiServer.servingCerts.namedCertificates) | |
| && self.configuration.apiServer.servingCerts.namedCertificates.exists(cert, |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In
`@api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/ExternalOIDC.yaml`
around lines 6355 - 6356, The CEL expression calls .exists() on
self.configuration.apiServer.servingCerts.namedCertificates without first
checking the field exists; update the boolean guard by adding
has(self.configuration.apiServer.servingCerts.namedCertificates) before calling
.exists() so the expression becomes ... && has(self.configuration.apiServer) &&
has(self.configuration.apiServer.servingCerts) &&
has(self.configuration.apiServer.servingCerts.namedCertificates) &&
self.configuration.apiServer.servingCerts.namedCertificates.exists(...),
ensuring namedCertificates is present before dereferencing in the validation
rule.
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -6364,7 +6364,8 @@ spec: | |||||||||||||||||||||||||||
| - message: APIServer loadBalancer hostname cannot be in ClusterConfiguration.apiserver.servingCerts.namedCertificates[] | ||||||||||||||||||||||||||||
| rule: '!self.services.exists(s, s.service == ''APIServer'' && has(s.servicePublishingStrategy.loadBalancer) | ||||||||||||||||||||||||||||
| && s.servicePublishingStrategy.loadBalancer.hostname != "" && has(self.configuration) | ||||||||||||||||||||||||||||
| && has(self.configuration.apiServer) && self.configuration.apiServer.servingCerts.namedCertificates.exists(cert, | ||||||||||||||||||||||||||||
| && has(self.configuration.apiServer) && has(self.configuration.apiServer.servingCerts) | ||||||||||||||||||||||||||||
| && self.configuration.apiServer.servingCerts.namedCertificates.exists(cert, | ||||||||||||||||||||||||||||
| cert.names.exists(n, n == s.servicePublishingStrategy.loadBalancer.hostname)))' | ||||||||||||||||||||||||||||
|
Comment on lines
6365
to
6369
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Guard the other optional fields in this CEL rule too. This only fixes the Suggested fix- rule: '!self.services.exists(s, s.service == ''APIServer'' && has(s.servicePublishingStrategy.loadBalancer)
- && s.servicePublishingStrategy.loadBalancer.hostname != "" && has(self.configuration)
- && has(self.configuration.apiServer) && has(self.configuration.apiServer.servingCerts)
- && self.configuration.apiServer.servingCerts.namedCertificates.exists(cert,
- cert.names.exists(n, n == s.servicePublishingStrategy.loadBalancer.hostname)))'
+ rule: '!self.services.exists(s, s.service == ''APIServer'' && has(s.servicePublishingStrategy.loadBalancer)
+ && has(s.servicePublishingStrategy.loadBalancer.hostname)
+ && s.servicePublishingStrategy.loadBalancer.hostname != "" && has(self.configuration)
+ && has(self.configuration.apiServer) && has(self.configuration.apiServer.servingCerts)
+ && has(self.configuration.apiServer.servingCerts.namedCertificates)
+ && self.configuration.apiServer.servingCerts.namedCertificates.exists(cert,
+ has(cert.names) && cert.names.exists(n, n == s.servicePublishingStrategy.loadBalancer.hostname)))'📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||
| - message: disableMultiNetwork can only be set to true when networkType | ||||||||||||||||||||||||||||
| is 'Other' | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -6006,7 +6006,8 @@ spec: | |||||||||||||
| - message: APIServer loadBalancer hostname cannot be in ClusterConfiguration.apiserver.servingCerts.namedCertificates[] | ||||||||||||||
| rule: '!self.services.exists(s, s.service == ''APIServer'' && has(s.servicePublishingStrategy.loadBalancer) | ||||||||||||||
| && s.servicePublishingStrategy.loadBalancer.hostname != "" && has(self.configuration) | ||||||||||||||
| && has(self.configuration.apiServer) && self.configuration.apiServer.servingCerts.namedCertificates.exists(cert, | ||||||||||||||
| && has(self.configuration.apiServer) && has(self.configuration.apiServer.servingCerts) | ||||||||||||||
| && self.configuration.apiServer.servingCerts.namedCertificates.exists(cert, | ||||||||||||||
|
Comment on lines
+6009
to
+6010
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: # First, let's check the file exists and read the context around lines 6009-6010
file_path="api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/HyperShiftOnlyDynamicResourceAllocation.yaml"
# Check file size first
wc -l "$file_path"Repository: openshift/hypershift Length of output: 215 🏁 Script executed: # Read the context around lines 6009-6010 (lines 6000-6020 for context)
file_path="api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/HyperShiftOnlyDynamicResourceAllocation.yaml"
sed -n '6000,6020p' "$file_path"Repository: openshift/hypershift Length of output: 1977 🏁 Script executed: # Let's also look at the broader context to find this validation rule
file_path="api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/HyperShiftOnlyDynamicResourceAllocation.yaml"
# Look at more context - the rule definition should be visible
sed -n '5995,6025p' "$file_path"Repository: openshift/hypershift Length of output: 2471 🏁 Script executed: # Search for the schema definition of namedCertificates to confirm if it's optional
# First, let's find where the CRD schema is defined
rg -A 5 -B 5 "namedCertificates" api/hypershift/v1beta1/ --type yaml | head -100Repository: openshift/hypershift Length of output: 19415 🏁 Script executed: # Let's also look for the servingCerts definition to understand the structure
rg -A 10 "servingCerts:" api/hypershift/v1beta1/ --type yaml | head -80Repository: openshift/hypershift Length of output: 15269 🌐 Web query:
💡 Result:
Citations:
🌐 Web query:
💡 Result: In Kubernetes CRD CEL rules ( Pattern (recommended): or Kubernetes’ CEL docs explicitly show this style (for example: If you’re on Kubernetes v1.29+, Kubernetes also supports CEL optional types, but Sources Guard
Suggested fix- && has(self.configuration.apiServer) && has(self.configuration.apiServer.servingCerts)
- && self.configuration.apiServer.servingCerts.namedCertificates.exists(cert,
+ && has(self.configuration.apiServer)
+ && has(self.configuration.apiServer.servingCerts)
+ && has(self.configuration.apiServer.servingCerts.namedCertificates)
+ && self.configuration.apiServer.servingCerts.namedCertificates.exists(cert,📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||
| cert.names.exists(n, n == s.servicePublishingStrategy.loadBalancer.hostname)))' | ||||||||||||||
| - message: disableMultiNetwork can only be set to true when networkType | ||||||||||||||
| is 'Other' | ||||||||||||||
|
|
||||||||||||||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -6535,7 +6535,8 @@ spec: | |||||||||||||||||
| - message: APIServer loadBalancer hostname cannot be in ClusterConfiguration.apiserver.servingCerts.namedCertificates[] | ||||||||||||||||||
| rule: '!self.services.exists(s, s.service == ''APIServer'' && has(s.servicePublishingStrategy.loadBalancer) | ||||||||||||||||||
| && s.servicePublishingStrategy.loadBalancer.hostname != "" && has(self.configuration) | ||||||||||||||||||
| && has(self.configuration.apiServer) && self.configuration.apiServer.servingCerts.namedCertificates.exists(cert, | ||||||||||||||||||
| && has(self.configuration.apiServer) && has(self.configuration.apiServer.servingCerts) | ||||||||||||||||||
| && self.configuration.apiServer.servingCerts.namedCertificates.exists(cert, | ||||||||||||||||||
| cert.names.exists(n, n == s.servicePublishingStrategy.loadBalancer.hostname)))' | ||||||||||||||||||
|
Comment on lines
+6538
to
6540
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: # Check if the file exists and get basic info
file_path="api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/OpenStack.yaml"
if [ -f "$file_path" ]; then
echo "File found."
wc -l "$file_path"
else
echo "File not found. Searching for similar paths..."
find . -name "OpenStack.yaml" -type f 2>/dev/null | head -20
fiRepository: openshift/hypershift Length of output: 197 🏁 Script executed: # Read the specific lines mentioned in the review
file_path="api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/OpenStack.yaml"
if [ -f "$file_path" ]; then
echo "=== Lines 6530-6550 context ==="
sed -n '6530,6550p' "$file_path"
fiRepository: openshift/hypershift Length of output: 1939 🏁 Script executed: # Search for the CEL rule pattern to understand the validation rule
rg -A 10 -B 5 "servicePublishingStrategy.loadBalancer.hostname" . --type yaml 2>/dev/null | head -50Repository: openshift/hypershift Length of output: 10165 🏁 Script executed: # Look for schema definitions related to servingCerts and namedCertificates
rg -A 5 "servingCerts" . --type yaml 2>/dev/null | grep -A 5 "namedCertificates" | head -40Repository: openshift/hypershift Length of output: 6385 🏁 Script executed: # Search for the source schema or struct definition for servingCerts
find . -name "*.go" -type f -exec grep -l "namedCertificates" {} \; 2>/dev/null | head -20Repository: openshift/hypershift Length of output: 150 🏁 Script executed: # Look for CRD source or schema files that define servingCerts structure
find . -name "*.go" -type f -exec grep -l "servingCerts" {} \; 2>/dev/null | head -20Repository: openshift/hypershift Length of output: 150 🏁 Script executed: # Search for apiserver servingcerts structure definition
rg "type.*ServingCert" . --type go 2>/dev/null | head -20Repository: openshift/hypershift Length of output: 1660 🏁 Script executed: # Read the APIServerServingCerts struct definition
cat -n ./api/vendor/github.com/openshift/api/config/v1/types_apiserver.go | grep -A 30 "type APIServerServingCerts struct"Repository: openshift/hypershift Length of output: 2216 🏁 Script executed: # Also check the APIServerNamedServingCert struct
cat -n ./api/vendor/github.com/openshift/api/config/v1/types_apiserver.go | grep -A 15 "type APIServerNamedServingCert struct"Repository: openshift/hypershift Length of output: 1137 🌐 Web query:
💡 Result: To safely write Kubernetes CEL validation rules that touch optional (possibly absent) fields, use presence checks and/or CEL Optional types so the API server never evaluates a field access that isn’t valid. 1) Guard optional field access with
|
||||||||||||||||||
| && has(self.configuration.apiServer) && has(self.configuration.apiServer.servingCerts) | |
| && self.configuration.apiServer.servingCerts.namedCertificates.exists(cert, | |
| cert.names.exists(n, n == s.servicePublishingStrategy.loadBalancer.hostname)))' | |
| && has(self.configuration.apiServer) | |
| && has(self.configuration.apiServer.servingCerts) | |
| && has(self.configuration.apiServer.servingCerts.namedCertificates) | |
| && self.configuration.apiServer.servingCerts.namedCertificates.exists(cert, | |
| has(cert.names) && cert.names.exists(n, n == s.servicePublishingStrategy.loadBalancer.hostname)))' |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In
`@api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/OpenStack.yaml`
around lines 6538 - 6540, The CEL rule dereferences two optional fields without
presence checks: self.configuration.apiServer.servingCerts.namedCertificates and
cert.names; update the expression used in the rule to guard those accesses with
has() checks (e.g., add
has(self.configuration.apiServer.servingCerts.namedCertificates) before
iterating namedCertificates and add has(cert.names) before calling
cert.names.exists) so the overall condition only evaluates those sub-expressions
when those optional fields are present.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -6695,7 +6695,8 @@ spec: | |
| - message: APIServer loadBalancer hostname cannot be in ClusterConfiguration.apiserver.servingCerts.namedCertificates[] | ||
| rule: '!self.services.exists(s, s.service == ''APIServer'' && has(s.servicePublishingStrategy.loadBalancer) | ||
| && s.servicePublishingStrategy.loadBalancer.hostname != "" && has(self.configuration) | ||
| && has(self.configuration.apiServer) && self.configuration.apiServer.servingCerts.namedCertificates.exists(cert, | ||
| && has(self.configuration.apiServer) && has(self.configuration.apiServer.servingCerts) | ||
| && self.configuration.apiServer.servingCerts.namedCertificates.exists(cert, | ||
| cert.names.exists(n, n == s.servicePublishingStrategy.loadBalancer.hostname)))' | ||
|
Comment on lines
+6698
to
6700
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
echo "== Schema/source definitions for servingCerts and namedCertificates =="
rg -n -C3 'servingCerts:|namedCertificates:|json:".*namedCertificates,omitempty"|json:".*servingCerts,omitempty"' \
api/hypershift/v1beta1 \
cmd/install/assets/hypershift-operator/zz_generated.crd-manifests
echo
echo "== All copies of the APIServer loadBalancer hostname validation =="
rg -n -C2 "APIServer loadBalancer hostname cannot be in ClusterConfiguration\\.apiserver\\.servingCerts\\.namedCertificates\\[\\]|namedCertificates\\.exists\\(cert" \
api \
cmd/installRepository: openshift/hypershift Length of output: 50377 🏁 Script executed: #!/bin/bash
set -euo pipefail
echo "== Check if namedCertificates is optional in the schema (check required fields) =="
# Find servingCerts definitions and check if namedCertificates is in required list
rg -A 10 "servingCerts:" cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-Hypershift-Default.crd.yaml | head -30
echo ""
echo "== Find the exact CEL validation rule for loadBalancer.hostname =="
rg -n "namedCertificates\.exists\(cert" cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-Hypershift-Default.crd.yaml
echo ""
echo "== Count total occurrences of this pattern in all generated manifests =="
rg "namedCertificates\.exists\(cert" cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/ | wc -l
echo ""
echo "== List files with this pattern =="
rg -l "namedCertificates\.exists\(cert" cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/Repository: openshift/hypershift Length of output: 1572 🏁 Script executed: #!/bin/bash
set -euo pipefail
echo "== Full context around the CEL rule (lines 6695-6705) =="
sed -n '6695,6705p' cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-Hypershift-Default.crd.yaml
echo ""
echo "== Check for 'required' list in servingCerts section =="
# Look for the required fields list near servingCerts definition
rg -B 5 -A 30 "servingCerts:" cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-Hypershift-Default.crd.yaml | grep -A 20 "servingCerts:" | grep -E "(required:|namedCertificates)" | head -20Repository: openshift/hypershift Length of output: 1424 🏁 Script executed: #!/bin/bash
set -euo pipefannat
echo "== Check all 3 files for the same pattern == "
for file in \
cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-Hypershift-CustomNoUpgrade.crd.yaml \
cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-Hypershift-Default.crd.yaml \
cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-Hypershift-TechPreviewNoUpgrade.crd.yaml; do
echo "=== File: $(basename $file) ==="
rg -B 3 "namedCertificates\.exists\(cert" "$file"
echo ""
done
echo "== Verify namedCertificates is NOT in required list =="
# Search the actual schema for required fields under servingCerts
rg -A 50 '"servingCerts"' cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-Hypershift-Default.crd.yaml | grep -A 40 'properties:' | head -50Repository: openshift/hypershift Length of output: 119 🏁 Script executed: #!/bin/bash
set -euo pipefail
echo "== Check all 3 files for the same pattern == "
for file in \
cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-Hypershift-CustomNoUpgrade.crd.yaml \
cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-Hypershift-Default.crd.yaml \
cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-Hypershift-TechPreviewNoUpgrade.crd.yaml; do
echo "=== File: $(basename $file) ==="
rg -B 3 "namedCertificates\.exists\(cert" "$file"
echo ""
done
echo "== Verify namedCertificates is NOT in required list =="
# Search the actual schema for required fields under servingCerts
rg -A 50 '"servingCerts"' cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-Hypershift-Default.crd.yaml | grep -A 40 'properties:' | head -50Repository: openshift/hypershift Length of output: 1617 🏁 Script executed: #!/bin/bash
set -euo pipefail
# Find the section defining servingCerts and check for required fields
echo "== Context: servingCerts schema definition with required list check =="
rg -n "servingCerts:" cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-Hypershift-Default.crd.yaml | head -1
# Get line number and read 100 lines from that point
LINE=$(rg -n "servingCerts:" cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-Hypershift-Default.crd.yaml | head -1 | cut -d: -f1)
START=$((LINE - 2))
END=$((LINE + 50))
echo "Lines $START to $END:"
sed -n "${START},${END}p" cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-Hypershift-Default.crd.yaml
echo ""
echo "== Check if namedCertificates field has minItems or is in required list =="
sed -n "${START},${END}p" cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-Hypershift-Default.crd.yaml | grep -E "required:|minItems:|namedCertificates"Repository: openshift/hypershift Length of output: 4048 Guard Line 6699 still dereferences an optional field. Proposed fix- && has(self.configuration.apiServer) && has(self.configuration.apiServer.servingCerts)
- && self.configuration.apiServer.servingCerts.namedCertificates.exists(cert,
+ && has(self.configuration.apiServer) && has(self.configuration.apiServer.servingCerts)
+ && has(self.configuration.apiServer.servingCerts.namedCertificates)
+ && self.configuration.apiServer.servingCerts.namedCertificates.exists(cert,This same pattern appears in 3 manifest files and must be fixed in all of them:
🤖 Prompt for AI Agents |
||
| - message: disableMultiNetwork can only be set to true when networkType | ||
| is 'Other' | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -7672,7 +7672,8 @@ spec: | |||||||||||||||
| - message: APIServer loadBalancer hostname cannot be in ClusterConfiguration.apiserver.servingCerts.namedCertificates[] | ||||||||||||||||
| rule: '!self.services.exists(s, s.service == ''APIServer'' && has(s.servicePublishingStrategy.loadBalancer) | ||||||||||||||||
| && s.servicePublishingStrategy.loadBalancer.hostname != "" && has(self.configuration) | ||||||||||||||||
| && has(self.configuration.apiServer) && self.configuration.apiServer.servingCerts.namedCertificates.exists(cert, | ||||||||||||||||
| && has(self.configuration.apiServer) && has(self.configuration.apiServer.servingCerts) | ||||||||||||||||
| && self.configuration.apiServer.servingCerts.namedCertificates.exists(cert, | ||||||||||||||||
| cert.names.exists(n, n == s.servicePublishingStrategy.loadBalancer.hostname)))' | ||||||||||||||||
|
Comment on lines
+7675
to
7677
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: # First, check if the file exists and get the exact content at lines 7675-7677
wc -l cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-Hypershift-TechPreviewNoUpgrade.crd.yamlRepository: openshift/hypershift Length of output: 190 🏁 Script executed: # Read the target lines with context
sed -n '7670,7680p' cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-Hypershift-TechPreviewNoUpgrade.crd.yamlRepository: openshift/hypershift Length of output: 1094 🏁 Script executed: # Find the schema definitions for servingCerts, namedCertificates, and names fields
# Search for where these are defined in the CRD
rg -n "servingCerts|namedCertificates" cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-Hypershift-TechPreviewNoUpgrade.crd.yaml | head -30Repository: openshift/hypershift Length of output: 644 🏁 Script executed: # Find the apiServer schema definition to check if servingCerts is optional
rg -n "apiServer:" cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-Hypershift-TechPreviewNoUpgrade.crd.yaml | head -20Repository: openshift/hypershift Length of output: 130 🏁 Script executed: # Get context around servingCerts definition to check required/optional status
sed -n '555,590p' cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-Hypershift-TechPreviewNoUpgrade.crd.yamlRepository: openshift/hypershift Length of output: 2574 🏁 Script executed: # Search for namedCertificates item schema and names field definition
sed -n '560,620p' cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-Hypershift-TechPreviewNoUpgrade.crd.yamlRepository: openshift/hypershift Length of output: 4091 🏁 Script executed: # Check the required fields at each level to confirm optionality
# Looking at servingCerts definition
sed -n '555,610p' cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-Hypershift-TechPreviewNoUpgrade.crd.yaml | grep -A 5 "required:"Repository: openshift/hypershift Length of output: 319 🏁 Script executed: # Check if there's a required array for servingCerts or namedCertificates
sed -n '555,625p' cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-Hypershift-TechPreviewNoUpgrade.crd.yaml | cat -nRepository: openshift/hypershift Length of output: 5045 🌐 Web query:
💡 Result: In CRD Common patterns:
Citations:
🌐 Web query:
💡 Result: In Kubernetes CEL, guard an optional list/array field with For nested optional parents, guard each level: This works because Kubernetes CEL supports Sources: Guard optional list fields before calling The rule at lines 7675-7677 guards Suggested patch- && has(self.configuration.apiServer) && has(self.configuration.apiServer.servingCerts)
- && self.configuration.apiServer.servingCerts.namedCertificates.exists(cert,
- cert.names.exists(n, n == s.servicePublishingStrategy.loadBalancer.hostname)))'
+ && has(self.configuration.apiServer) && has(self.configuration.apiServer.servingCerts)
+ && has(self.configuration.apiServer.servingCerts.namedCertificates)
+ && self.configuration.apiServer.servingCerts.namedCertificates.exists(cert,
+ has(cert.names) && cert.names.exists(n, n == s.servicePublishingStrategy.loadBalancer.hostname)))'📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||
| - message: disableMultiNetwork can only be set to true when networkType | ||||||||||||||||
| is 'Other' | ||||||||||||||||
|
|
||||||||||||||||
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
Repository: openshift/hypershift
Length of output: 5603
🏁 Script executed:
Repository: openshift/hypershift
Length of output: 2471
🏁 Script executed:
Repository: openshift/hypershift
Length of output: 3530
🌐 Web query:
Kubernetes CEL optional fields has() guard namedCertificates exists() semantics💡 Result:
has()(presence guard) in Kubernetes CELhas(e.f)is a CEL macro used to test presence / availability of a field before you rely on it. Kubernetes explicitly calls outhas()as the way to check whether a field of a dynamically typed value is accessible (to avoid errors when the field might not exist in the schema for the object you’re evaluating). (kubernetes.io)e(github.com):has(e.f)is true iff key"f"exists (even if the value isnull; null ≠ absence in CEL). (github.com)fis repeated (list) or map field:has(e.f)is true iff it is non-empty. (github.com)has(e.f)can effectively mean “value is not the default” (because proto3 historically can’t always distinguish “unset” from “set-to-default”). (github.com)Implication for
namedCertificates(a list field):has(self.namedCertificates)is true only when the list is non-empty; it’s false for both “missing” and “present but empty”. (github.com)exists()semantics (including error/short-circuit behavior)list.exists(x, p)returns true if any element satisfies predicatep; for an empty list it returns false. (github.com)exists()“behaves like logical OR (||)” regarding short-circuiting and error absorption: if some element makes the result true, errors from other elements/predicates can be ignored (consistent with CEL’s OR behavior). (github.com)So for
namedCertificates:self.namedCertificates.exists(c, /*match*/)is false when the list is empty (and typically also when it’s absent but treated as empty by the underlying object model). (github.com)!has(self.namedCertificates) || self.namedCertificates.exists(c, /*match*/)(skip rule unless non-empty), becausehas()on a list means non-empty. (github.com)Citations:
Guard
namedCertificatesandcert.namesbefore dereferencing.Lines 6005–6006 access two optional fields without
has()guards:servingCerts.namedCertificatesandcert.names. Both are optional in the schema—namedCertificatesstates "If no named certificates are provided..." andnamesis marked "optional list". Per Kubernetes CEL best practices, optional fields must be guarded withhas()before dereferencing to prevent errors when fields are absent or empty.Suggested fix
📝 Committable suggestion
🤖 Prompt for AI Agents