1
0
Fork 0
mirror of https://github.com/kyverno/kyverno.git synced 2025-03-31 03:45:17 +00:00

Add path_canonicalize custom JMESPath function (#2787)

* Add path_canonicalize custom JMESPath function

Signed-off-by: weiwei.danny <weiwei.danny@bytedance.com>

* Add CLI test for the custom path_canonicalize function

Signed-off-by: weiwei.danny <weiwei.danny@bytedance.com>

* remove the extra parameter

Signed-off-by: weiwei.danny <weiwei.danny@bytedance.com>

Co-authored-by: weiwei.danny <weiwei.danny@bytedance.com>
This commit is contained in:
Danny__Wei 2021-12-06 19:10:34 +08:00 committed by GitHub
parent b7767d79d3
commit beeec06c7f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 131 additions and 1 deletions

View file

@ -4,6 +4,7 @@ import (
"encoding/base64"
"errors"
"fmt"
"path/filepath"
"reflect"
"regexp"
"strconv"
@ -50,6 +51,7 @@ var (
base64Decode = "base64_decode"
base64Encode = "base64_encode"
timeSince = "time_since"
pathCanonicalize = "path_canonicalize"
)
const errorPrefix = "JMESPath function '%s': "
@ -231,6 +233,13 @@ func getFunctions() []*gojmespath.FunctionEntry {
},
Handler: jpTimeSince,
},
{
Name: pathCanonicalize,
Arguments: []ArgSpec{
{Types: []JpType{JpString}},
},
Handler: jpPathCanonicalize,
},
}
}
@ -628,6 +637,16 @@ func jpTimeSince(arguments []interface{}) (interface{}, error) {
return t2.Sub(t1).String(), nil
}
func jpPathCanonicalize(arguments []interface{}) (interface{}, error) {
var err error
str, err := validateArg(pathCanonicalize, arguments, 0, reflect.String)
if err != nil {
return nil, err
}
return filepath.Join(str.String()), nil
}
// InterfaceToString casts an interface to a string type
func ifaceToString(iface interface{}) (string, error) {
switch i := iface.(type) {

View file

@ -559,3 +559,57 @@ func Test_TimeSince(t *testing.T) {
})
}
}
func Test_PathCanonicalize(t *testing.T) {
testCases := []struct {
jmesPath string
expectedResult string
}{
{
jmesPath: "path_canonicalize('///')",
expectedResult: "/",
},
{
jmesPath: "path_canonicalize('///var/run/containerd/containerd.sock')",
expectedResult: "/var/run/containerd/containerd.sock",
},
{
jmesPath: "path_canonicalize('/var/run///containerd/containerd.sock')",
expectedResult: "/var/run/containerd/containerd.sock",
},
{
jmesPath: "path_canonicalize('/var/run///containerd////')",
expectedResult: "/var/run/containerd",
},
{
jmesPath: "path_canonicalize('/run///')",
expectedResult: "/run",
},
{
jmesPath: "path_canonicalize('/run/../etc')",
expectedResult: "/etc",
},
{
jmesPath: "path_canonicalize('///etc*')",
expectedResult: "/etc*",
},
{
jmesPath: "path_canonicalize('/../../')",
expectedResult: "/",
},
}
for _, tc := range testCases {
t.Run(tc.jmesPath, func(t *testing.T) {
jp, err := New(tc.jmesPath)
assert.NilError(t, err)
result, err := jp.Search("")
assert.NilError(t, err)
res, ok := result.(string)
assert.Assert(t, ok)
assert.Equal(t, res, tc.expectedResult)
})
}
}

View file

@ -4,10 +4,11 @@ import (
"context"
"encoding/json"
"fmt"
"github.com/pkg/errors"
"strings"
"time"
"github.com/pkg/errors"
"github.com/googleapis/gnostic/compiler"
openapiv2 "github.com/googleapis/gnostic/openapiv2"
client "github.com/kyverno/kyverno/pkg/dclient"

View file

@ -39,3 +39,34 @@ spec:
- key: "{{pattern_match('prefix-*', request.object.metadata.labels.value)}}"
operator: Equals
value: false
---
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: path-canonicalize
spec:
validationFailureAction: enforce
background: false
rules:
- name: disallow-mount-containerd-sock
match:
resources:
kinds:
- Pod
validate:
foreach:
- list: "request.object.spec.volumes[]"
preconditions:
all:
- key: "{{ element.hostPath.path }}"
operator: NotEquals
value: ""
deny:
conditions:
any:
- key: "{{ path_canonicalize(element.hostPath.path) }}"
operator: Equals
value: "/var/run/containerd/containerd.sock"
- key: "{{ path_canonicalize(element.hostPath.path) }}"
operator: Equals
value: "/run/containerd/containerd.sock"

View file

@ -31,3 +31,23 @@ metadata:
name: pattern-match-test-no-match
labels:
value: test
---
apiVersion: v1
kind: Pod
metadata:
name: mount-containerd-sock
spec:
volumes:
- name: test
emptyDir: {}
- name: sock
hostPath:
path: ///var/run/containerd///containerd.sock
containers:
- name: mount-containerd-sock
image: nginx
volumeMounts:
- name: sock
mountPath: /sock
- name: test
mountPath: /test

View file

@ -24,3 +24,8 @@ results:
resource: pattern-match-test-no-match
kind: Namespace
status: fail
- policy: path-canonicalize
rule: disallow-mount-containerd-sock
resource: mount-containerd-sock
kind: Pod
status: fail