diff --git a/go.mod b/go.mod index 8588e38b25..fa376b15ea 100644 --- a/go.mod +++ b/go.mod @@ -54,6 +54,7 @@ require ( ) require ( + github.com/aquilax/truncate v1.0.0 // indirect github.com/opencontainers/image-spec v1.0.2 // indirect gopkg.in/inf.v0 v0.9.1 ) diff --git a/go.sum b/go.sum index b56d1e1bfa..70c42b1d47 100644 --- a/go.sum +++ b/go.sum @@ -222,6 +222,8 @@ github.com/apex/logs v0.0.4/go.mod h1:XzxuLZ5myVHDy9SAmYpamKKRNApGj54PfYLcFrXqDw github.com/aphistic/golf v0.0.0-20180712155816-02c07f170c5a/go.mod h1:3NqKYiepwy8kCu4PNA+aP7WUV72eXWJeP9/r3/K9aLE= github.com/aphistic/sweet v0.2.0/go.mod h1:fWDlIh/isSE9n6EPsRmC0det+whmX6dJid3stzu0Xys= github.com/appscode/jsonpatch v0.0.0-20190108182946-7c0e3b262f30/go.mod h1:4AJxUpXUhv4N+ziTvIcWWXgeorXpxPZOfk9HdEVr96M= +github.com/aquilax/truncate v1.0.0 h1:UgIGS8U/aZ4JyOJ2h3xcF5cSQ06+gGBnjxH2RUHJe0U= +github.com/aquilax/truncate v1.0.0/go.mod h1:BeMESIDMlvlS3bmg4BVvBbbZUNwWtS8uzYPAKXwwhLw= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= diff --git a/pkg/engine/jmespath/functions.go b/pkg/engine/jmespath/functions.go index 7c8c699de9..fe992f5d3b 100644 --- a/pkg/engine/jmespath/functions.go +++ b/pkg/engine/jmespath/functions.go @@ -11,6 +11,7 @@ import ( "strings" "time" + trunc "github.com/aquilax/truncate" gojmespath "github.com/jmespath/go-jmespath" "github.com/minio/pkg/wildcard" ) @@ -53,6 +54,7 @@ var ( base64Encode = "base64_encode" timeSince = "time_since" pathCanonicalize = "path_canonicalize" + truncate = "truncate" ) const errorPrefix = "JMESPath function '%s': " @@ -242,6 +244,14 @@ func getFunctions() []*gojmespath.FunctionEntry { }, Handler: jpPathCanonicalize, }, + { + Name: truncate, + Arguments: []ArgSpec{ + {Types: []JpType{JpString}}, + {Types: []JpType{JpNumber}}, + }, + Handler: jpTruncate, + }, } } @@ -600,6 +610,20 @@ func jpPathCanonicalize(arguments []interface{}) (interface{}, error) { return filepath.Join(str.String()), nil } +func jpTruncate(arguments []interface{}) (interface{}, error) { + var err error + str, err := validateArg(truncate, arguments, 0, reflect.String) + if err != nil { + return nil, err + } + length, err := validateArg(truncate, arguments, 1, reflect.Float64) + if err != nil { + return nil, err + } + + return trunc.Truncator(str.String(), int(length.Float()), trunc.CutStrategy{}), nil +} + // InterfaceToString casts an interface to a string type func ifaceToString(iface interface{}) (string, error) { switch i := iface.(type) { diff --git a/pkg/engine/jmespath/functions_test.go b/pkg/engine/jmespath/functions_test.go index 11fc7b9b3d..d74ea16534 100644 --- a/pkg/engine/jmespath/functions_test.go +++ b/pkg/engine/jmespath/functions_test.go @@ -972,3 +972,42 @@ func Test_PathCanonicalize(t *testing.T) { }) } } + +func Test_Truncate(t *testing.T) { + // Can't use integer literals due to + // https://github.com/jmespath/go-jmespath/issues/27 + // + // TODO: fix this in https://github.com/kyverno/go-jmespath + + testCases := []struct { + jmesPath string + expectedResult string + }{ + { + jmesPath: "truncate('Lorem ipsum dolor sit amet', `5`)", + expectedResult: "Lorem", + }, + { + jmesPath: "truncate('Lorem ipsum ipsum ipsum dolor sit amet', `11`)", + expectedResult: "Lorem ipsum", + }, + { + jmesPath: "truncate('Lorem ipsum ipsum ipsum dolor sit amet', `40`)", + expectedResult: "Lorem ipsum ipsum ipsum dolor sit amet", + }, + } + + 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) + }) + } +}