Skip to content

Commit

Permalink
Add initial set of CEL validations for HTTPRoute
Browse files Browse the repository at this point in the history
  • Loading branch information
gauravkghildiyal committed Aug 3, 2023
1 parent 3ae9fa7 commit adb94d2
Show file tree
Hide file tree
Showing 9 changed files with 2,656 additions and 0 deletions.
47 changes: 47 additions & 0 deletions apis/v1beta1/httproute_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,12 @@ type HTTPRouteSpec struct {
// HTTPRouteRule defines semantics for matching an HTTP request based on
// conditions (matches), processing it (filters), and forwarding the request to
// an API object (backendRefs).
//
// +kubebuilder:validation:XValidation:message="RequestRedirect filter must not be used together with backendRefs",rule="(has(self.backendRefs) && size(self.backendRefs) > 0) ? (!has(self.filters) || self.filters.all(f, !has(f.requestRedirect))): true"
// +kubebuilder:validation:XValidation:message="When using RequestRedirect filter with Path.ReplacePrefixMatch, exactly one PathPrefix match must be specified",rule="(has(self.filters) && self.filters.exists_one(f, has(f.requestRedirect) && has(f.requestRedirect.path) && f.requestRedirect.path.type == 'ReplacePrefixMatch' && has(f.requestRedirect.path.replacePrefixMatch))) ? ((size(self.matches) != 1 || !has(self.matches[0].path) || self.matches[0].path.type != 'PathPrefix') ? false : true) : true"
// +kubebuilder:validation:XValidation:message="When using URLRewrite filter with Path.ReplacePrefixMatch, exactly one PathPrefix match must be specified",rule="(has(self.filters) && self.filters.exists_one(f, has(f.urlRewrite) && has(f.urlRewrite.path) && f.urlRewrite.path.type == 'ReplacePrefixMatch' && has(f.urlRewrite.path.replacePrefixMatch))) ? ((size(self.matches) != 1 || !has(self.matches[0].path) || self.matches[0].path.type != 'PathPrefix') ? false : true) : true"
// +kubebuilder:validation:XValidation:message="Within BackendRefs, when using RequestRedirect filter with Path.ReplacePrefixMatch, exactly one PathPrefix match must be specified",rule="(has(self.backendRefs) && self.backendRefs.exists_one(b, (has(b.filters) && b.filters.exists_one(f, has(f.requestRedirect) && has(f.requestRedirect.path) && f.requestRedirect.path.type == 'ReplacePrefixMatch' && has(f.requestRedirect.path.replacePrefixMatch))) )) ? ((size(self.matches) != 1 || !has(self.matches[0].path) || self.matches[0].path.type != 'PathPrefix') ? false : true) : true"
// +kubebuilder:validation:XValidation:message="Within BackendRefs, When using URLRewrite filter with Path.ReplacePrefixMatch, exactly one PathPrefix match must be specified",rule="(has(self.backendRefs) && self.backendRefs.exists_one(b, (has(b.filters) && b.filters.exists_one(f, has(f.urlRewrite) && has(f.urlRewrite.path) && f.urlRewrite.path.type == 'ReplacePrefixMatch' && has(f.urlRewrite.path.replacePrefixMatch))) )) ? ((size(self.matches) != 1 || !has(self.matches[0].path) || self.matches[0].path.type != 'PathPrefix') ? false : true) : true"
type HTTPRouteRule struct {
// Matches define conditions used for matching the rule against incoming
// HTTP requests. Each match is independent, i.e. this rule will be matched
Expand Down Expand Up @@ -216,6 +222,11 @@ type HTTPRouteRule struct {
//
// +optional
// +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.exists(f, f.type == 'RequestHeaderModifier') ? self.exists_one(f, f.type == 'RequestHeaderModifier') : true"
// +kubebuilder:validation:XValidation:message="ResponseHeaderModifier filter cannot be repeated",rule="self.exists(f, f.type == 'ResponseHeaderModifier') ? self.exists_one(f, f.type == 'ResponseHeaderModifier') : true"
// +kubebuilder:validation:XValidation:message="RequestRedirect filter cannot be repeated",rule="self.exists(f, f.type == 'RequestRedirect') ? self.exists_one(f, f.type == 'RequestRedirect') : true"
// +kubebuilder:validation:XValidation:message="URLRewrite filter cannot be repeated",rule="self.exists(f, f.type == 'URLRewrite') ? self.exists_one(f, f.type == 'URLRewrite') : true"
Filters []HTTPRouteFilter `json:"filters,omitempty"`

// BackendRefs defines the backend(s) where matching requests should be
Expand Down Expand Up @@ -306,6 +317,18 @@ const (
)

// HTTPPathMatch describes how to select a HTTP route by matching the HTTP request path.
//
// +kubebuilder:validation:XValidation:message="value must be an absolute path and start with '/' when type one of ['Exact', 'PathPrefix']",rule="(self.type == 'Exact' || self.type == 'PathPrefix') ? self.value.startsWith('/') : true"
// +kubebuilder:validation:XValidation:message="must not contain '//' when type one of ['Exact', 'PathPrefix']",rule="(self.type == 'Exact' || self.type == 'PathPrefix') ? !self.value.contains('//') : true"
// +kubebuilder:validation:XValidation:message="must not contain '/./' when type one of ['Exact', 'PathPrefix']",rule="(self.type == 'Exact' || self.type == 'PathPrefix') ? !self.value.contains('/./') : true"
// +kubebuilder:validation:XValidation:message="must not contain '/../' when type one of ['Exact', 'PathPrefix']",rule="(self.type == 'Exact' || self.type == 'PathPrefix') ? !self.value.contains('/../') : true"
// +kubebuilder:validation:XValidation:message="must not contain '%2f' when type one of ['Exact', 'PathPrefix']",rule="(self.type == 'Exact' || self.type == 'PathPrefix') ? !self.value.contains('%2f') : true"
// +kubebuilder:validation:XValidation:message="must not contain '%2F' when type one of ['Exact', 'PathPrefix']",rule="(self.type == 'Exact' || self.type == 'PathPrefix') ? !self.value.contains('%2F') : true"
// +kubebuilder:validation:XValidation:message="must not contain '#' when type one of ['Exact', 'PathPrefix']",rule="(self.type == 'Exact' || self.type == 'PathPrefix') ? !self.value.contains('#') : true"
// +kubebuilder:validation:XValidation:message="must not end with '/..' when type one of ['Exact', 'PathPrefix']",rule="(self.type == 'Exact' || self.type == 'PathPrefix') ? !self.value.endsWith('/..') : true"
// +kubebuilder:validation:XValidation:message="must not end with '/.' when type one of ['Exact', 'PathPrefix']",rule="(self.type == 'Exact' || self.type == 'PathPrefix') ? !self.value.endsWith('/.') : true"
// +kubebuilder:validation:XValidation:message="type must be one of ['Exact', 'PathPrefix', 'RegularExpression']",rule="self.type == 'Exact' || self.type == 'PathPrefix' || self.type == 'RegularExpression'"
// +kubebuilder:validation:XValidation:message="must only contain valid characters (matching ^(?:[-A-Za-z0-9/._~!$&'()*+,;=:@]|[%][0-9a-fA-F]{2})+$) for types ['Exact', 'PathPrefix']",rule="(self.type == 'Exact' || self.type == 'PathPrefix') ? self.value.matches(r\"\"\"^(?:[-A-Za-z0-9/._~!$&'()*+,;=:@]|[%][0-9a-fA-F]{2})+$\"\"\") : true"
type HTTPPathMatch struct {
// Type specifies how to match against the path Value.
//
Expand Down Expand Up @@ -560,6 +583,19 @@ type HTTPRouteMatch struct {
// examples include request or response modification, implementing
// authentication strategies, rate-limiting, and traffic shaping. API
// guarantee/conformance is defined based on the type of the filter.
//
// +kubebuilder:validation:XValidation:message="filter.RequestHeaderModifier must be nil if the HTTPRouteFilter.Type is not RequestHeaderModifier",rule="!(has(self.requestHeaderModifier) && self.type != 'RequestHeaderModifier')"
// +kubebuilder:validation:XValidation:message="filter.RequestHeaderModifier must be specified for RequestHeaderModifier HTTPRouteFilter.Type",rule="!(!has(self.requestHeaderModifier) && self.type == 'RequestHeaderModifier')"
// +kubebuilder:validation:XValidation:message="filter.ResponseHeaderModifier must be nil if the HTTPRouteFilter.Type is not ResponseHeaderModifier",rule="!(has(self.responseHeaderModifier) && self.type != 'ResponseHeaderModifier')"
// +kubebuilder:validation:XValidation:message="filter.ResponseHeaderModifier must be specified for ResponseHeaderModifier HTTPRouteFilter.Type",rule="!(!has(self.responseHeaderModifier) && self.type == 'ResponseHeaderModifier')"
// +kubebuilder:validation:XValidation:message="filter.RequestMirror must be nil if the HTTPRouteFilter.Type is not RequestMirror",rule="!(has(self.requestMirror) && self.type != 'RequestMirror')"
// +kubebuilder:validation:XValidation:message="filter.RequestMirror must be specified for RequestMirror HTTPRouteFilter.Type",rule="!(!has(self.requestMirror) && self.type == 'RequestMirror')"
// +kubebuilder:validation:XValidation:message="filter.RequestRedirect must be nil if the HTTPRouteFilter.Type is not RequestRedirect",rule="!(has(self.requestRedirect) && self.type != 'RequestRedirect')"
// +kubebuilder:validation:XValidation:message="filter.RequestRedirect must be specified for RequestRedirect HTTPRouteFilter.Type",rule="!(!has(self.requestRedirect) && self.type == 'RequestRedirect')"
// +kubebuilder:validation:XValidation:message="filter.URLRewrite must be nil if the HTTPRouteFilter.Type is not URLRewrite",rule="!(has(self.urlRewrite) && self.type != 'URLRewrite')"
// +kubebuilder:validation:XValidation:message="filter.URLRewrite must be specified for URLRewrite HTTPRouteFilter.Type",rule="!(!has(self.urlRewrite) && self.type == 'URLRewrite')"
// +kubebuilder:validation:XValidation:message="filter.ExtensionRef must be nil if the HTTPRouteFilter.Type is not ExtensionRef",rule="!(has(self.extensionRef) && self.type != 'ExtensionRef')"
// +kubebuilder:validation:XValidation:message="filter.ExtensionRef must be specified for ExtensionRef HTTPRouteFilter.Type",rule="!(!has(self.extensionRef) && self.type == 'ExtensionRef')"
type HTTPRouteFilter struct {
// Type identifies the type of filter to apply. As with other API fields,
// types are classified into three conformance levels:
Expand Down Expand Up @@ -829,6 +865,11 @@ const (
)

// HTTPPathModifier defines configuration for path modifiers.
//
// +kubebuilder:validation:XValidation:message="replaceFullPath must be set when type is set to 'ReplaceFullPath'",rule="self.type == 'ReplaceFullPath' ? has(self.replaceFullPath) : true"
// +kubebuilder:validation:XValidation:message="type must be 'ReplaceFullPath' when replaceFullPath is set",rule="has(self.replaceFullPath) ? self.type == 'ReplaceFullPath' : true"
// +kubebuilder:validation:XValidation:message="replacePrefixMatch must be set when type is set to 'ReplacePrefixMatch'",rule="self.type == 'ReplacePrefixMatch' ? has(self.replacePrefixMatch) : true"
// +kubebuilder:validation:XValidation:message="type must be 'ReplacePrefixMatch' when replacePrefixMatch is set",rule="has(self.replacePrefixMatch) ? self.type == 'ReplacePrefixMatch' : true"
type HTTPPathModifier struct {
// Type defines the type of path modifier. Additional types may be
// added in a future release of the API.
Expand Down Expand Up @@ -1054,6 +1095,12 @@ type HTTPBackendRef struct {
//
// +optional
// +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="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.exists(f, f.type == 'RequestHeaderModifier') ? self.exists_one(f, f.type == 'RequestHeaderModifier') : true"
// +kubebuilder:validation:XValidation:message="ResponseHeaderModifier filter cannot be repeated",rule="self.exists(f, f.type == 'ResponseHeaderModifier') ? self.exists_one(f, f.type == 'ResponseHeaderModifier') : true"
// +kubebuilder:validation:XValidation:message="RequestRedirect filter cannot be repeated",rule="self.exists(f, f.type == 'RequestRedirect') ? self.exists_one(f, f.type == 'RequestRedirect') : true"
// +kubebuilder:validation:XValidation:message="URLRewrite filter cannot be repeated",rule="self.exists(f, f.type == 'URLRewrite') ? self.exists_one(f, f.type == 'URLRewrite') : true"
Filters []HTTPRouteFilter `json:"filters,omitempty"`
}

Expand Down
2 changes: 2 additions & 0 deletions apis/v1beta1/object_reference_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,8 @@ type SecretObjectReference struct {
// References to objects with invalid Group and Kind are not valid, and must
// be rejected by the implementation, with appropriate Conditions set
// on the containing object.
//
// +kubebuilder:validation:XValidation:message="Must have port for Service reference",rule="((!has(self.group) || size(self.group) == 0) && (!has(self.kind) || self.kind == 'Service')) ? has(self.port) : true"
type BackendObjectReference struct {
// Group is the group of the referent. For example, "gateway.networking.k8s.io".
// When unspecified or empty string, core API group is inferred.
Expand Down
14 changes: 14 additions & 0 deletions config/crd/experimental/gateway.networking.k8s.io_grpcroutes.yaml

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

Loading

0 comments on commit adb94d2

Please sign in to comment.