mirror of
https://github.com/kyverno/kyverno.git
synced 2025-03-29 02:45:06 +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:
parent
b7767d79d3
commit
beeec06c7f
6 changed files with 131 additions and 1 deletions
|
@ -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) {
|
||||
|
|
|
@ -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)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Add table
Reference in a new issue