Skip to content

Fix OpenAPI validations by adding API list markers #3964

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

Merged
merged 1 commit into from
Aug 6, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .golangci-kal.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ linters:
- "nomaps" # Ensure maps are not used.
- "nophase" # Phase fields are discouraged by the Kube API conventions, use conditions instead.
- "optionalorrequired" # Every field should be marked as `+optional` or `+required`.
- "ssatags" # Ensure proper Server-Side Apply (SSA) tags on array fields.
- "statussubresource" # All root objects that have a `status` field should have a status subresource.
- "uniquemarkers" # Ensure that types and fields do not contain more than a single definition of a marker that should only be present once.
disable:
Expand Down
11 changes: 9 additions & 2 deletions apis/v1/gateway_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,7 @@ type GatewaySpec struct {
// Support: Extended
//
// +optional
// +listType=atomic
// <gateway:validateIPAddress>
// +kubebuilder:validation:MaxItems=16
// +kubebuilder:validation:XValidation:message="IPAddress values must be unique",rule="self.all(a1, a1.type == 'IPAddress' ? self.exists_one(a2, a2.type == a1.type && a2.value == a1.value) : true )"
Expand Down Expand Up @@ -569,6 +570,7 @@ type GatewayTLSConfig struct {
// Support: Implementation-specific (More than one reference or other resource types)
//
// +optional
// +listType=atomic
// +kubebuilder:validation:MaxItems=64
CertificateRefs []SecretObjectReference `json:"certificateRefs,omitempty"`

Expand Down Expand Up @@ -643,9 +645,10 @@ type FrontendTLSValidation struct {
// "ResolvedRefs" condition MUST be set to False for this listener with the
// "RefNotPermitted" reason.
//
// +required
// +listType=atomic
// +kubebuilder:validation:MaxItems=8
// +kubebuilder:validation:MinItems=1
// +required
CACertificateRefs []ObjectReference `json:"caCertificateRefs,omitempty"`
}

Expand All @@ -657,6 +660,7 @@ type AllowedRoutes struct {
// Support: Core
//
// +optional
// +listType=atomic
// +kubebuilder:default={from: Same}
Namespaces *RouteNamespaces `json:"namespaces,omitempty"`

Expand All @@ -673,6 +677,7 @@ type AllowedRoutes struct {
// Support: Core
//
// +optional
// +listType=atomic
// +kubebuilder:validation:MaxItems=8
Kinds []RouteGroupKind `json:"kinds,omitempty"`
}
Expand Down Expand Up @@ -791,6 +796,7 @@ type GatewayStatus struct {
// * a specified address was unusable (e.g. already in use)
//
// +optional
// +listType=atomic
// <gateway:validateIPAddress>
// +kubebuilder:validation:MaxItems=16
Addresses []GatewayStatusAddress `json:"addresses,omitempty"`
Expand Down Expand Up @@ -1123,8 +1129,9 @@ type ListenerStatus struct {
// and invalid Route kinds are specified, the implementation MUST
// reference the valid Route kinds that have been specified.
//
// +kubebuilder:validation:MaxItems=8
// +required
// +listType=atomic
// +kubebuilder:validation:MaxItems=8
SupportedKinds []RouteGroupKind `json:"supportedKinds"`

// AttachedRoutes represents the total number of Routes that have been
Expand Down
6 changes: 6 additions & 0 deletions apis/v1/grpcroute_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -139,12 +139,14 @@ type GRPCRouteSpec struct {
// Support: Core
//
// +optional
// +listType=atomic
// +kubebuilder:validation:MaxItems=16
Hostnames []Hostname `json:"hostnames,omitempty"`

// Rules are a list of GRPC matchers, filters and actions.
//
// +optional
// +listType=atomic
// +kubebuilder:validation:MaxItems=16
// +kubebuilder:validation:XValidation:message="While 16 rules and 64 matches per rule are allowed, the total number of matches across all rules in a route must be less than 128",rule="(self.size() > 0 ? (has(self[0].matches) ? self[0].matches.size() : 0) : 0) + (self.size() > 1 ? (has(self[1].matches) ? self[1].matches.size() : 0) : 0) + (self.size() > 2 ? (has(self[2].matches) ? self[2].matches.size() : 0) : 0) + (self.size() > 3 ? (has(self[3].matches) ? self[3].matches.size() : 0) : 0) + (self.size() > 4 ? (has(self[4].matches) ? self[4].matches.size() : 0) : 0) + (self.size() > 5 ? (has(self[5].matches) ? self[5].matches.size() : 0) : 0) + (self.size() > 6 ? (has(self[6].matches) ? self[6].matches.size() : 0) : 0) + (self.size() > 7 ? (has(self[7].matches) ? self[7].matches.size() : 0) : 0) + (self.size() > 8 ? (has(self[8].matches) ? self[8].matches.size() : 0) : 0) + (self.size() > 9 ? (has(self[9].matches) ? self[9].matches.size() : 0) : 0) + (self.size() > 10 ? (has(self[10].matches) ? self[10].matches.size() : 0) : 0) + (self.size() > 11 ? (has(self[11].matches) ? self[11].matches.size() : 0) : 0) + (self.size() > 12 ? (has(self[12].matches) ? self[12].matches.size() : 0) : 0) + (self.size() > 13 ? (has(self[13].matches) ? self[13].matches.size() : 0) : 0) + (self.size() > 14 ? (has(self[14].matches) ? self[14].matches.size() : 0) : 0) + (self.size() > 15 ? (has(self[15].matches) ? self[15].matches.size() : 0) : 0) <= 128"
// <gateway:experimental:validation:XValidation:message="Rule name must be unique within the route",rule="self.all(l1, !has(l1.name) || self.exists_one(l2, has(l2.name) && l1.name == l2.name))">
Expand Down Expand Up @@ -212,6 +214,7 @@ type GRPCRouteRule struct {
// the above criteria.
//
// +optional
// +listType=atomic
// +kubebuilder:validation:MaxItems=64
Matches []GRPCRouteMatch `json:"matches,omitempty"`

Expand Down Expand Up @@ -241,6 +244,7 @@ type GRPCRouteRule struct {
// Support: Core
//
// +optional
// +listType=atomic
// +kubebuilder:validation:MaxItems=16
// +kubebuilder:validation:XValidation:message="RequestHeaderModifier filter cannot be repeated",rule="self.filter(f, f.type == 'RequestHeaderModifier').size() <= 1"
// +kubebuilder:validation:XValidation:message="ResponseHeaderModifier filter cannot be repeated",rule="self.filter(f, f.type == 'ResponseHeaderModifier').size() <= 1"
Expand Down Expand Up @@ -276,6 +280,7 @@ type GRPCRouteRule struct {
// Support for weight: Core
//
// +optional
// +listType=atomic
// +kubebuilder:validation:MaxItems=16
BackendRefs []GRPCBackendRef `json:"backendRefs,omitempty"`

Expand Down Expand Up @@ -636,6 +641,7 @@ type GRPCBackendRef struct {
// Filters field in GRPCRouteRule.)
//
// +optional
// +listType=atomic
// +kubebuilder:validation:MaxItems=16
// +kubebuilder:validation:XValidation:message="RequestHeaderModifier filter cannot be repeated",rule="self.filter(f, f.type == 'RequestHeaderModifier').size() <= 1"
// +kubebuilder:validation:XValidation:message="ResponseHeaderModifier filter cannot be repeated",rule="self.filter(f, f.type == 'ResponseHeaderModifier').size() <= 1"
Expand Down
7 changes: 7 additions & 0 deletions apis/v1/httproute_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -114,12 +114,14 @@ type HTTPRouteSpec struct {
// Support: Core
//
// +optional
// +listType=atomic
// +kubebuilder:validation:MaxItems=16
Hostnames []Hostname `json:"hostnames,omitempty"`

// Rules are a list of HTTP matchers, filters and actions.
//
// +optional
// +listType=atomic
// <gateway:experimental:validation:XValidation:message="Rule name must be unique within the route",rule="self.all(l1, !has(l1.name) || self.exists_one(l2, has(l2.name) && l1.name == l2.name))">
// +kubebuilder:validation:MaxItems=16
// +kubebuilder:default={{matches: {{path: {type: "PathPrefix", value: "/"}}}}}
Expand Down Expand Up @@ -201,6 +203,7 @@ type HTTPRouteRule struct {
// parent a request is coming from, a HTTP 404 status code MUST be returned.
//
// +optional
// +listType=atomic
// +kubebuilder:validation:MaxItems=64
// +kubebuilder:default={{path:{ type: "PathPrefix", value: "/"}}}
Matches []HTTPRouteMatch `json:"matches,omitempty"`
Expand Down Expand Up @@ -243,6 +246,7 @@ type HTTPRouteRule struct {
// Support: Core
//
// +optional
// +listType=atomic
// +kubebuilder:validation:MaxItems=16
// +kubebuilder:validation:XValidation:message="May specify either httpRouteFilterRequestRedirect or httpRouteFilterRequestRewrite, but not both",rule="!(self.exists(f, f.type == 'RequestRedirect') && self.exists(f, f.type == 'URLRewrite'))"
// +kubebuilder:validation:XValidation:message="RequestHeaderModifier filter cannot be repeated",rule="self.filter(f, f.type == 'RequestHeaderModifier').size() <= 1"
Expand Down Expand Up @@ -288,6 +292,7 @@ type HTTPRouteRule struct {
// Support for weight: Core
//
// +optional
// +listType=atomic
// +kubebuilder:validation:MaxItems=16
BackendRefs []HTTPBackendRef `json:"backendRefs,omitempty"`

Expand Down Expand Up @@ -382,6 +387,7 @@ type HTTPRouteRetry struct {
// Support: Extended
//
// +optional
// +listType=atomic
Codes []HTTPRouteRetryStatusCode `json:"codes,omitempty"`

// Attempts specifies the maximum number of times an individual request
Expand Down Expand Up @@ -1603,6 +1609,7 @@ type HTTPBackendRef struct {
// Filters field in HTTPRouteRule.)
//
// +optional
// +listType=atomic
// +kubebuilder:validation:MaxItems=16
// +kubebuilder:validation:XValidation:message="May specify either httpRouteFilterRequestRedirect or httpRouteFilterRequestRewrite, but not both",rule="!(self.exists(f, f.type == 'RequestRedirect') && self.exists(f, f.type == 'URLRewrite'))"
// +kubebuilder:validation:XValidation:message="RequestHeaderModifier filter cannot be repeated",rule="self.filter(f, f.type == 'RequestHeaderModifier').size() <= 1"
Expand Down
4 changes: 3 additions & 1 deletion apis/v1/shared_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,7 @@ type CommonRouteSpec struct {
// </gateway:experimental:description>
//
// +optional
// +listType=atomic
// +kubebuilder:validation:MaxItems=32
// <gateway:standard:validation:XValidation:message="sectionName must be specified when parentRefs includes 2 or more references to the same parent",rule="self.all(p1, self.all(p2, p1.group == p2.group && p1.kind == p2.kind && p1.name == p2.name && (((!has(p1.__namespace__) || p1.__namespace__ == '') && (!has(p2.__namespace__) || p2.__namespace__ == '')) || (has(p1.__namespace__) && has(p2.__namespace__) && p1.__namespace__ == p2.__namespace__ )) ? ((!has(p1.sectionName) || p1.sectionName == '') == (!has(p2.sectionName) || p2.sectionName == '')) : true))">
// <gateway:standard:validation:XValidation:message="sectionName must be unique when parentRefs includes 2 or more references to the same parent",rule="self.all(p1, self.exists_one(p2, p1.group == p2.group && p1.kind == p2.kind && p1.name == p2.name && (((!has(p1.__namespace__) || p1.__namespace__ == '') && (!has(p2.__namespace__) || p2.__namespace__ == '')) || (has(p1.__namespace__) && has(p2.__namespace__) && p1.__namespace__ == p2.__namespace__ )) && (((!has(p1.sectionName) || p1.sectionName == '') && (!has(p2.sectionName) || p2.sectionName == '')) || (has(p1.sectionName) && has(p2.sectionName) && p1.sectionName == p2.sectionName))))">
Expand Down Expand Up @@ -502,8 +503,9 @@ type RouteStatus struct {
// A maximum of 32 Gateways will be represented in this list. An empty list
// means the route has not been attached to any Gateway.
//
// +kubebuilder:validation:MaxItems=32
// +required
// +listType=atomic
// +kubebuilder:validation:MaxItems=32
Parents []RouteParentStatus `json:"parents"`
}

Expand Down
3 changes: 2 additions & 1 deletion apis/v1alpha2/policy_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,8 @@ type PolicyStatus struct {
// additional Gateways would be able to reference the Service targeted by
// the BackendTLSPolicy.
//
// +kubebuilder:validation:MaxItems=16
// +required
// +listType=atomic
// +kubebuilder:validation:MaxItems=16
Ancestors []PolicyAncestorStatus `json:"ancestors"`
}
2 changes: 2 additions & 0 deletions apis/v1alpha2/tcproute_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ type TCPRouteSpec struct {
// Rules are a list of TCP matchers and actions.
//
// +required
// +listType=atomic
// +kubebuilder:validation:MinItems=1
// +kubebuilder:validation:MaxItems=16
// <gateway:experimental:validation:XValidation:message="Rule name must be unique within the route",rule="self.all(l1, !has(l1.name) || self.exists_one(l2, has(l2.name) && l1.name == l2.name))">
Expand Down Expand Up @@ -86,6 +87,7 @@ type TCPRouteRule struct {
// Support for weight: Extended
//
// +required
// +listType=atomic
// +kubebuilder:validation:MinItems=1
// +kubebuilder:validation:MaxItems=16
BackendRefs []BackendRef `json:"backendRefs,omitempty"`
Expand Down
3 changes: 3 additions & 0 deletions apis/v1alpha2/tlsroute_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,12 +85,14 @@ type TLSRouteSpec struct {
// Support: Core
//
// +optional
// +listType=atomic
// +kubebuilder:validation:MaxItems=16
Hostnames []Hostname `json:"hostnames,omitempty"`

// Rules are a list of TLS matchers and actions.
//
// +required
// +listType=atomic
// +kubebuilder:validation:MinItems=1
// +kubebuilder:validation:MaxItems=16
// <gateway:experimental:validation:XValidation:message="Rule name must be unique within the route",rule="self.all(l1, !has(l1.name) || self.exists_one(l2, has(l2.name) && l1.name == l2.name))">
Expand Down Expand Up @@ -129,6 +131,7 @@ type TLSRouteRule struct {
// Support for weight: Extended
//
// +required
// +listType=atomic
// +kubebuilder:validation:MinItems=1
// +kubebuilder:validation:MaxItems=16
BackendRefs []BackendRef `json:"backendRefs,omitempty"`
Expand Down
2 changes: 2 additions & 0 deletions apis/v1alpha2/udproute_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ type UDPRouteSpec struct {
// Rules are a list of UDP matchers and actions.
//
// +required
// +listType=atomic
// +kubebuilder:validation:MinItems=1
// +kubebuilder:validation:MaxItems=16
// <gateway:experimental:validation:XValidation:message="Rule name must be unique within the route",rule="self.all(l1, !has(l1.name) || self.exists_one(l2, has(l2.name) && l1.name == l2.name))">
Expand Down Expand Up @@ -86,6 +87,7 @@ type UDPRouteRule struct {
// Support for weight: Extended
//
// +required
// +listType=atomic
// +kubebuilder:validation:MinItems=1
// +kubebuilder:validation:MaxItems=16
BackendRefs []BackendRef `json:"backendRefs,omitempty"`
Expand Down
8 changes: 6 additions & 2 deletions apis/v1alpha3/backendtlspolicy_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,9 +80,10 @@ type BackendTLSPolicySpec struct {
//
// Support: Implementation-specific for any other resource
//
// +required
// +listType=atomic
// +kubebuilder:validation:MinItems=1
// +kubebuilder:validation:MaxItems=16
// +required
// +kubebuilder:validation:XValidation:message="sectionName must be specified when targetRefs includes 2 or more references to the same target",rule="self.all(p1, self.all(p2, p1.group == p2.group && p1.kind == p2.kind && p1.name == p2.name ? ((!has(p1.sectionName) || p1.sectionName == '') == (!has(p2.sectionName) || p2.sectionName == '')) : true))"
// +kubebuilder:validation:XValidation:message="sectionName must be unique when targetRefs includes 2 or more references to the same target",rule="self.all(p1, self.exists_one(p2, p1.group == p2.group && p1.kind == p2.kind && p1.name == p2.name && (((!has(p1.sectionName) || p1.sectionName == '') && (!has(p2.sectionName) || p2.sectionName == '')) || (has(p1.sectionName) && has(p2.sectionName) && p1.sectionName == p2.sectionName))))"
TargetRefs []v1alpha2.LocalPolicyTargetReferenceWithSectionName `json:"targetRefs"`
Expand Down Expand Up @@ -133,8 +134,9 @@ type BackendTLSPolicyValidation struct {
// Support: Implementation-specific (More than one reference, or other kinds
// of resources).
//
// +kubebuilder:validation:MaxItems=8
// +optional
// +listType=atomic
// +kubebuilder:validation:MaxItems=8
CACertificateRefs []v1.LocalObjectReference `json:"caCertificateRefs,omitempty"`

// WellKnownCACertificates specifies whether system CA certificates may be used in
Expand All @@ -150,6 +152,7 @@ type BackendTLSPolicyValidation struct {
// Support: Implementation-specific
//
// +optional
// +listType=atomic
WellKnownCACertificates *WellKnownCACertificatesType `json:"wellKnownCACertificates,omitempty"`

// Hostname is used for two purposes in the connection between Gateways and
Expand All @@ -170,6 +173,7 @@ type BackendTLSPolicyValidation struct {
// Support: Extended
//
// +optional
// +listType=atomic
// +kubebuilder:validation:MaxItems=5
SubjectAltNames []SubjectAltName `json:"subjectAltNames,omitempty"`
}
Expand Down
4 changes: 3 additions & 1 deletion apis/v1alpha3/tlsroute_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,14 +87,16 @@ type TLSRouteSpec struct {
//
// Support: Core
//
// +required
// +listType=atomic
// +kubebuilder:validation:MinItems=1
// +kubebuilder:validation:MaxItems=16
// +required
Hostnames []Hostname `json:"hostnames,omitempty"`

// Rules are a list of actions.
//
// +required
// +listType=atomic
// +kubebuilder:validation:MinItems=1
// +kubebuilder:validation:MaxItems=1
// <gateway:experimental:validation:XValidation:message="Rule name must be unique within the route",rule="self.all(l1, !has(l1.name) || self.exists_one(l2, has(l2.name) && l1.name == l2.name))">
Expand Down
6 changes: 4 additions & 2 deletions apis/v1beta1/referencegrant_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,9 +72,10 @@ type ReferenceGrantSpec struct {
//
// Support: Core
//
// +required
// +listType=atomic
// +kubebuilder:validation:MinItems=1
// +kubebuilder:validation:MaxItems=16
// +required
From []ReferenceGrantFrom `json:"from"`

// To describes the resources that may be referenced by the resources
Expand All @@ -84,9 +85,10 @@ type ReferenceGrantSpec struct {
//
// Support: Core
//
// +required
// +listType=atomic
// +kubebuilder:validation:MinItems=1
// +kubebuilder:validation:MaxItems=16
// +required
To []ReferenceGrantTo `json:"to"`
}

Expand Down
3 changes: 2 additions & 1 deletion apisx/v1alpha1/xlistenerset_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -255,8 +255,9 @@ type ListenerEntryStatus struct {
// and invalid Route kinds are specified, the implementation MUST
// reference the valid Route kinds that have been specified.
//
// +kubebuilder:validation:MaxItems=8
// +required
// +listType=atomic
// +kubebuilder:validation:MaxItems=8
SupportedKinds []RouteGroupKind `json:"supportedKinds"`

// AttachedRoutes represents the total number of Routes that have been
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading