Skip to content
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

validator: prevent multiple filters/predicates per yaml item #2691

Merged
merged 5 commits into from
Oct 25, 2023
Merged
Show file tree
Hide file tree
Changes from 4 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
10 changes: 10 additions & 0 deletions cmd/webhook/admission/admission_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,16 @@ func TestRouteGroupAdmitter(t *testing.T) {
inputFile: "rg-with-invalid-eskip-filters-and-predicates.json",
message: "parse failed after token status, last route id: , position 11: syntax error\\nparse failed after token Method, last route id: Method, position 6: syntax error",
},
{
name: "invalid routgroup multiple filters per json/yaml array item",
inputFile: "rg-with-multiple-filters.json",
message: `single filter expected at \"status(201) -> inlineContent(\"hi\")\"\nsingle filter expected at \" \"`,
},
{
name: "invalid routgroup multiple predicates per json/yaml array item",
inputFile: "rg-with-multiple-predicates.json",
message: `single predicate expected at \"Method(\"GET\") && Path(\"/\")\"\nsingle predicate expected at \" \"`,
},
} {
t.Run(tc.name, func(t *testing.T) {
expectedResponse := responseAllowedFmt
Expand Down
49 changes: 49 additions & 0 deletions cmd/webhook/admission/testdata/rg/rg-with-multiple-filters.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
{
"request": {
"uid": "req-uid",
"name": "req1",
"operation": "create",
"kind": {
"group": "zalando",
"version": "v1",
"kind": "RouteGroup"
},
"namespace": "n1",
"object": {
"metadata": {
"name": "rg1",
"namespace": "n1"
},
"spec": {
"backends": [
{
"name": "backend",
"type": "shunt"
}
],
"defaultBackends": [
{
"backendName": "backend"
}
],
"routes": [
{
"backends": [
{
"backendName": "backend"
}
],
"filters": [
"status(201) -> inlineContent(\"hi\")",
" "
],
"path": "/",
"predicates": [
"Method(\"GET\")"
]
}
]
}
}
}
}
49 changes: 49 additions & 0 deletions cmd/webhook/admission/testdata/rg/rg-with-multiple-predicates.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
{
"request": {
"uid": "req-uid",
"name": "req1",
"operation": "create",
"kind": {
"group": "zalando",
"version": "v1",
"kind": "RouteGroup"
},
"namespace": "n1",
"object": {
"metadata": {
"name": "rg1",
"namespace": "n1"
},
"spec": {
"backends": [
{
"name": "backend",
"type": "shunt"
}
],
"defaultBackends": [
{
"backendName": "backend"
}
],
"routes": [
{
"backends": [
{
"backendName": "backend"
}
],
"filters": [
"status(201)"
],
"path": "/",
"predicates": [
"Method(\"GET\") && Path(\"/\")",
" "
]
}
]
}
}
}
}
8 changes: 7 additions & 1 deletion dataclients/kubernetes/definitions/definitions_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package definitions_test

import (
"os"
"strings"
"testing"

"github.com/stretchr/testify/assert"
Expand All @@ -18,10 +19,15 @@ func TestValidateRouteGroups(t *testing.T) {
data, err := os.ReadFile("testdata/errorwrapdata/routegroups.json")
require.NoError(t, err)

logs, err := os.ReadFile("testdata/errorwrapdata/errors.log")
require.NoError(t, err)

logsString := strings.TrimSuffix(string(logs), "\n")

rgl, err := definitions.ParseRouteGroupsJSON(data)
require.NoError(t, err)

err = definitions.ValidateRouteGroups(&rgl)

assert.EqualError(t, err, "route group without name\nerror in route group default/rg1: route group without backend")
assert.EqualError(t, err, logsString)
}
2 changes: 0 additions & 2 deletions dataclients/kubernetes/definitions/routegroups.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,6 @@ var (
errRouteGroupWithoutName = errors.New("route group without name")
errRouteGroupWithoutSpec = errors.New("route group without spec")
errInvalidRouteSpec = errors.New("invalid route spec")
errInvalidPredicate = errors.New("invalid predicate")
errInvalidFilter = errors.New("invalid filter")
errInvalidMethod = errors.New("invalid method")
errBothPathAndPathSubtree = errors.New("path and path subtree in the same route")
errMissingBackendReference = errors.New("missing backend reference")
Expand Down
26 changes: 16 additions & 10 deletions dataclients/kubernetes/definitions/routegroupvalidator.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,19 @@
package definitions

import (
"errors"
"fmt"

"github.com/zalando/skipper/eskip"
)

type RouteGroupValidator struct{}

var (
errSingleFilterExpected = errors.New("single filter expected")
errSinglePredicateExpected = errors.New("single predicate expected")
)

var defaultRouteGroupValidator = &RouteGroupValidator{}

// ValidateRouteGroup validates a RouteGroupItem
Expand Down Expand Up @@ -56,7 +64,10 @@ func (rgv *RouteGroupValidator) filtersValidation(item *RouteGroupItem) error {
var errs []error
for _, r := range item.Spec.Routes {
for _, f := range r.Filters {
_, err := eskip.ParseFilters(f)
filters, err := eskip.ParseFilters(f)
if len(filters) != 1 && err == nil {
MustafaSaber marked this conversation as resolved.
Show resolved Hide resolved
errs = append(errs, fmt.Errorf("%w at \"%s\"", errSingleFilterExpected, f))
MustafaSaber marked this conversation as resolved.
Show resolved Hide resolved
}
errs = append(errs, err)
}
}
Expand All @@ -68,7 +79,10 @@ func (rgv *RouteGroupValidator) predicatesValidation(item *RouteGroupItem) error
var errs []error
for _, r := range item.Spec.Routes {
for _, p := range r.Predicates {
_, err := eskip.ParsePredicates(p)
predicates, err := eskip.ParsePredicates(p)
if len(predicates) != 1 && err == nil {
errs = append(errs, fmt.Errorf("%w at \"%s\"", errSinglePredicateExpected, p))
MustafaSaber marked this conversation as resolved.
Show resolved Hide resolved
}
errs = append(errs, err)
}
}
Expand Down Expand Up @@ -131,14 +145,6 @@ func (r *RouteSpec) validate(hasDefault bool, backends map[string]bool) error {
return errBothPathAndPathSubtree
}

if hasEmpty(r.Predicates) {
return errInvalidPredicate
}

if hasEmpty(r.Filters) {
return errInvalidFilter
}

if hasEmpty(r.Methods) {
return errInvalidMethod
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
route group without name
error in route group default/rg1: route group without backend
single predicate expected at "Path("/foo") && Method("GET")"
single predicate expected at ""
single filter expected at "inlineContent("/foo") -> status(200)"
single filter expected at " "
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,41 @@
"kind": "RouteGroup",
"spec": {
"backends": [
{
{
"name": "shunt",
"type": "shunt"
}
],
"hosts": [
"test.example.com"
],
"routes": [
{
"backends": [
{
"backendName": "shunt"
}
],
"filters": [
"inlineContent(\"/foo\")"
],
"path": "/foo"
}
]
}
},
{
"apiVersion": "zalando.org/v1",
"metadata": {
"name": "rg1"
},
"kind": "RouteGroup",
"spec": {
"backends": [
{
"name": "shunt",
"type": "shunt"
}
}
],
"hosts": [
"test.example.com"
Expand All @@ -60,13 +91,49 @@
"backendName": "shunt"
}
],
"predicates": [
"Path(\"/foo\") && Method(\"GET\")",
""
],
"filters": [
"inlineContent(\"/foo\")"
],
"path": "/foo"
}
]
}
},
{
"apiVersion": "zalando.org/v1",
"metadata": {
"name": "rg1"
},
"kind": "RouteGroup",
"spec": {
"backends": [
{
"name": "shunt",
"type": "shunt"
}
],
"hosts": [
"test.example.com"
],
"routes": [
{
"backends": [
{
"backendName": "shunt"
}
],
"filters": [
"inlineContent(\"/foo\") -> status(200)",
" "
],
"path": "/foo"
}
]
}
}
]
}
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
test-route-group
invalid filter
single filter expected
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
test-route-group
invalid predicate
single predicate expected
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
single filter expected
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
apiVersion: zalando.org/v1
kind: RouteGroup
metadata:
name: test-route-group
spec:
hosts:
- example.org
backends:
- name: app
type: service
serviceName: app-svc
servicePort: 80
defaultBackends:
- backendName: app
routes:
- path: /
methods:
- GET
- HEAD
predicates:
- Foo("X-Bar", "42")
filters:
- foo(42) -> bar(24)
backends:
- backendName: app
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
single predicate expected
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
apiVersion: zalando.org/v1
kind: RouteGroup
metadata:
name: test-route-group
spec:
hosts:
- example.org
backends:
- name: app
type: service
serviceName: app-svc
servicePort: 80
defaultBackends:
- backendName: app
routes:
- path: /
methods:
- GET
- HEAD
predicates:
- Foo("X-Bar", "42") && Bar("X-Foo", "24")
filters:
- foo(42)
- bar(24)
backends:
- backendName: app
Loading