1
0
Fork 0
mirror of https://github.com/kyverno/kyverno.git synced 2024-12-14 11:57:48 +00:00

ignore non-policy files in CLI and improve validation messages (#1362)

* improve validation message

* improve error behaviors

* fix tests

* fix tests
This commit is contained in:
Jim Bugwadia 2020-12-07 11:26:04 -08:00 committed by GitHub
parent a64915128b
commit 6afd2e6f3a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
20 changed files with 249 additions and 205 deletions

1
go.mod
View file

@ -25,6 +25,7 @@ require (
github.com/minio/minio v0.0.0-20200114012931-30922148fbb5
github.com/onsi/ginkgo v1.11.0
github.com/onsi/gomega v1.8.1
github.com/ory/go-acc v0.2.6 // indirect
github.com/pkg/errors v0.9.1
github.com/sirupsen/logrus v1.6.0 // indirect
github.com/spf13/cobra v1.0.0

27
go.sum
View file

@ -109,8 +109,12 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dchest/siphash v1.1.0 h1:1Rs9eTUlZLPBEvV+2sTaM8O0NWn0ppbgqS7p11aWawI=
github.com/dchest/siphash v1.1.0/go.mod h1:q+IRvb2gOSrUnYoPqHiyHXS0FOBBOdl6tONBlVnOnt4=
github.com/dgraph-io/ristretto v0.0.1/go.mod h1:T40EBc7CJke8TkpiYfGGKAeFjSaxuFXhuXRyumBd6RE=
github.com/dgraph-io/ristretto v0.0.2 h1:a5WaUrDa0qm0YrAAS1tUykT5El3kt62KNZZeMxQn3po=
github.com/dgraph-io/ristretto v0.0.2/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E=
github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
github.com/djherbis/atime v1.0.0/go.mod h1:5W+KBIuTwVGcqjIfaTwt+KSYX1o6uep8dtevevQP/f8=
github.com/docker/docker v0.7.3-0.20190327010347-be7ac8be2ae0/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
@ -428,6 +432,8 @@ github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de h1:9TO3cAIGXtEhn
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE=
github.com/logrusorgru/aurora v0.0.0-20181002194514-a7b3b318ed4e/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4=
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4=
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.0.0-20180730094502-03f2033d19d5/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
@ -484,6 +490,8 @@ github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eI
github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo=
github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/mitchellh/mapstructure v1.3.2 h1:mRS76wmkOn3KkKAyXDu42V+6ebnXWIztFSYGN7GeoRg=
github.com/mitchellh/mapstructure v1.3.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
@ -530,12 +538,18 @@ github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1Cpa
github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/onsi/gomega v1.8.1 h1:C5Dqfs/LeauYDX0jJXIe2SWmwCbGzx9yF8C8xy3Lh34=
github.com/onsi/gomega v1.8.1/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA=
github.com/ory/go-acc v0.2.6 h1:YfI+L9dxI7QCtWn2RbawqO0vXhiThdXu/RgizJBbaq0=
github.com/ory/go-acc v0.2.6/go.mod h1:4Kb/UnPcT8qRAk3IAxta+hvVapdxTLWtrr7bFLlEgpw=
github.com/ory/viper v1.7.5 h1:+xVdq7SU3e1vNaCsk/ixsfxE4zylk1TJUiJrY647jUE=
github.com/ory/viper v1.7.5/go.mod h1:ypOuyJmEUb3oENywQZRgeAMwqgOyDqwboO1tj3DjTaM=
github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
github.com/paulmach/orb v0.1.3/go.mod h1:VFlX/8C+IQ1p6FTRRKzKoOPJnvEtA5G0Veuqwbu//Vk=
github.com/pborman/getopt v0.0.0-20180729010549-6fdd0a2c7117/go.mod h1:85jBQOZwpVEaDAr341tbn15RS4fCAsIst0qp7i8ex1o=
github.com/pborman/uuid v1.2.0 h1:J7Q5mO4ysT1dv8hyrUGHb9+ooztCXu1D8MY8DZYsu3g=
github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/pelletier/go-toml v1.8.0 h1:Keo9qb7iRJs2voHvunFtuuYFsbWeOBh8/P9v/kVMFtw=
github.com/pelletier/go-toml v1.8.0/go.mod h1:D6yutnOGMveHEPV7VQOuvI/gXY61bv+9bAOTRnLElKs=
github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI=
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
@ -608,6 +622,7 @@ github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1
github.com/smartystreets/assertions v0.0.0-20190401211740-f487f9de1cd3/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
github.com/smartystreets/go-aws-auth v0.0.0-20180515143844-0c1422d1fdb9/go.mod h1:SnhjPscd9TpLiy1LpzGSKh3bXCfxxXuqd9xmQJy3slM=
github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
github.com/soheilhy/cmux v0.1.3/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
github.com/sourcegraph/go-diff v0.5.1/go.mod h1:j2dHj3m8aZgQO8lMTcTnBcXkRRRqi34cd2MNlA9u1mE=
@ -616,11 +631,15 @@ github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B
github.com/spf13/afero v1.2.2 h1:5jhuqJyZCZf2JRofRvN/nIFgIWNzPa3/Vz8mYylgbWc=
github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng=
github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
github.com/spf13/cobra v1.0.0 h1:6m/oheQuQ13N9ks4hubMG6BnvwOeaJrqSPLahSnczz8=
github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE=
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk=
github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
@ -641,6 +660,8 @@ github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJy
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s=
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
github.com/tevino/abool v0.0.0-20170917061928-9b9efcf221b5 h1:hNna6Fi0eP1f2sMBe/rJicDmaHmoXGe1Ta84FPYHLuE=
github.com/tevino/abool v0.0.0-20170917061928-9b9efcf221b5/go.mod h1:f1SCnEOt6sc3fOJfPQDRDzHOtSXuTtnz0ImG9kPRDV0=
github.com/tidwall/gjson v1.3.5/go.mod h1:P256ACg0Mn+j1RXIDXoss50DeIABTYK1PULOJHhxOls=
@ -712,6 +733,7 @@ golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3
golang.org/x/crypto v0.0.0-20191117063200-497ca9f6d64f/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200220183623-bac4c82f6975 h1:/Tl7pH94bvbAAHBdZJT947M/+gp0+CqQXDtMRC0fseo=
golang.org/x/crypto v0.0.0-20200220183623-bac4c82f6975/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
@ -792,6 +814,8 @@ golang.org/x/sys v0.0.0-20191022100944-742c48ecaeb7/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42 h1:vEOn+mP2zCOVzKckCZy6YsCtDblrpj/w7B9nxGNELpg=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f h1:+Nyd8tzPX9R7BWHguqsrbFdRx3WQ/1ib8I44HXV5yTA=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@ -880,6 +904,9 @@ gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
gopkg.in/ini.v1 v1.42.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/ini.v1 v1.48.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/ini.v1 v1.57.0 h1:9unxIsFcTt4I55uWluz+UmL95q4kdJ0buvQ1ZIqVQww=
gopkg.in/ini.v1 v1.57.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/jcmturner/aescts.v1 v1.0.1/go.mod h1:nsR8qBOg+OucoIW+WMhB3GspUQXq9XorLnQb9XtvcOo=
gopkg.in/jcmturner/dnsutils.v1 v1.0.1/go.mod h1:m3v+5svpVOhtFAP/wSz+yzh4Mc0Fg7eRhxkJMWSIz9Q=
gopkg.in/jcmturner/goidentity.v3 v3.0.0/go.mod h1:oG2kH0IvSYNIu80dVAyu/yoefjq1mNfM5bm88whjWx4=

View file

@ -160,7 +160,7 @@ func Test_variableSubstitutionPathNotExist(t *testing.T) {
Context: ctx,
NewResource: *resourceUnstructured}
er := Mutate(policyContext)
expectedErrorStr := "variable request.object.metadata.name1 not found (path: /spec/name)"
expectedErrorStr := "variable request.object.metadata.name1 not resolved at path /spec/name"
t.Log(er.PolicyResponse.Rules[0].Message)
assert.Equal(t, er.PolicyResponse.Rules[0].Message, expectedErrorStr)
}

View file

@ -3,6 +3,7 @@ package engine
import (
"fmt"
"reflect"
"strings"
"time"
"github.com/go-logr/logr"
@ -246,8 +247,8 @@ func isSameRules(oldRules []response.RuleResponse, newRules []response.RuleRespo
// validatePatterns validate pattern and anyPattern
func validatePatterns(log logr.Logger, ctx context.EvalInterface, resource unstructured.Unstructured, rule kyverno.Rule) (resp response.RuleResponse) {
startTime := time.Now()
logger := log.WithValues("rule", rule.Name)
logger.V(4).Info("start processing rule", "startTime", startTime)
logger := log.WithValues("rule", rule.Name, "name", resource.GetName(), "kind", resource.GetKind())
logger.V(5).Info("start processing rule", "startTime", startTime)
resp.Name = rule.Name
resp.Type = utils.Validation.String()
defer func() {
@ -255,34 +256,26 @@ func validatePatterns(log logr.Logger, ctx context.EvalInterface, resource unstr
logger.V(4).Info("finished processing rule", "processingTime", resp.RuleStats.ProcessingTime.String())
}()
// work on a copy of validation rule
validationRule := rule.Validation.DeepCopy()
// either pattern or anyPattern can be specified in Validation rule
if validationRule.Pattern != nil {
// substitute variables in the pattern
pattern := validationRule.Pattern
var err error
if pattern, err = variables.SubstituteVars(logger, ctx, pattern); err != nil {
// variable substitution failed
resp.Success = false
resp.Message = fmt.Sprintf("Validation error: %s; Validation rule '%s' failed. '%s'",
rule.Validation.Message, rule.Name, err)
resp.Message = fmt.Sprintf("variable substitution failed for rule %s: %s", rule.Name, err.Error())
return resp
}
if path, err := validate.ValidateResourceWithPattern(logger, resource.Object, pattern); err != nil {
// validation failed
logger.V(5).Info(err.Error())
logger.V(3).Info("validation failed", "path", path, "error", err.Error())
resp.Success = false
resp.Message = fmt.Sprintf("Validation error: %s; Validation rule %s failed at path %s",
rule.Validation.Message, rule.Name, path)
resp.Message = buildErrorMessage(rule, path)
return resp
}
logger.V(4).Info("successfully processed rule")
resp.Success = true
resp.Message = fmt.Sprintf("Validation rule '%s' succeeded.", rule.Name)
resp.Message = fmt.Sprintf("validation rule '%s' passed.", rule.Name)
return resp
}
@ -294,31 +287,32 @@ func validatePatterns(log logr.Logger, ctx context.EvalInterface, resource unstr
anyPatterns, err := rule.Validation.DeserializeAnyPattern()
if err != nil {
resp.Success = false
resp.Message = fmt.Sprintf("Failed to deserialize anyPattern, expect type array: %v", err)
resp.Message = fmt.Sprintf("failed to deserialize anyPattern, expected type array: %v", err)
return resp
}
for idx, pattern := range anyPatterns {
if pattern, err = variables.SubstituteVars(logger, ctx, pattern); err != nil {
// variable substitution failed
failedSubstitutionsErrors = append(failedSubstitutionsErrors, err)
continue
}
_, err := validate.ValidateResourceWithPattern(logger, resource.Object, pattern)
path, err := validate.ValidateResourceWithPattern(logger, resource.Object, pattern)
if err == nil {
resp.Success = true
resp.Message = fmt.Sprintf("Validation rule '%s' anyPattern[%d] succeeded.", rule.Name, idx)
resp.Message = fmt.Sprintf("validation rule '%s' anyPattern[%d] passed.", rule.Name, idx)
return resp
}
logger.V(4).Info(fmt.Sprintf("validation rule failed for anyPattern[%d]", idx), "message", rule.Validation.Message)
patternErr := fmt.Errorf("anyPattern[%d] failed; %s", idx, err)
logger.V(4).Info("validation rule failed", "anyPattern[%d]", idx, "path", path)
patternErr := fmt.Errorf("Rule %s[%d] failed at path %s.", rule.Name, idx, path)
failedAnyPatternsErrors = append(failedAnyPatternsErrors, patternErr)
}
// Substitution failures
if len(failedSubstitutionsErrors) > 0 {
resp.Success = false
resp.Message = fmt.Sprintf("Substitutions failed: %v", failedSubstitutionsErrors)
resp.Message = fmt.Sprintf("failed to substitute variables: %v", failedSubstitutionsErrors)
return resp
}
@ -328,15 +322,38 @@ func validatePatterns(log logr.Logger, ctx context.EvalInterface, resource unstr
for _, err := range failedAnyPatternsErrors {
errorStr = append(errorStr, err.Error())
}
resp.Success = false
log.V(4).Info(fmt.Sprintf("Validation rule '%s' failed. %s", rule.Name, errorStr))
if rule.Validation.Message == "" {
resp.Message = fmt.Sprintf("Validation rule '%s' has failed", rule.Name)
} else {
resp.Message = rule.Validation.Message
}
resp.Success = false
resp.Message = buildAnyPatternErrorMessage(rule, errorStr)
return resp
}
}
return response.RuleResponse{}
}
func buildErrorMessage(rule kyverno.Rule, path string) string {
if rule.Validation.Message == "" {
return fmt.Sprintf("validation error: rule %s failed at path %s", rule.Name, path)
}
if strings.HasSuffix(rule.Validation.Message, ".") {
return fmt.Sprintf("validation error: %s Rule %s failed at path %s", rule.Validation.Message, rule.Name, path)
}
return fmt.Sprintf("validation error: %s. Rule %s failed at path %s", rule.Validation.Message, rule.Name, path)
}
func buildAnyPatternErrorMessage(rule kyverno.Rule, errors []string) string {
errStr := strings.Join(errors, " ")
if rule.Validation.Message == "" {
return fmt.Sprintf("validation error: %s", errStr)
}
if strings.HasSuffix(rule.Validation.Message, ".") {
return fmt.Sprintf("validation error: %s %s", rule.Validation.Message, errStr)
}
return fmt.Sprintf("validation error: %s. %s", rule.Validation.Message, errStr)
}

View file

@ -124,8 +124,8 @@ func TestValidate_image_tag_fail(t *testing.T) {
resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
assert.NilError(t, err)
msgs := []string{
"Validation rule 'validate-tag' succeeded.",
"Validation error: imagePullPolicy 'Always' required with tag 'latest'; Validation rule validate-latest failed at path /spec/containers/0/imagePullPolicy/",
"validation rule 'validate-tag' passed.",
"validation error: imagePullPolicy 'Always' required with tag 'latest'. Rule validate-latest failed at path /spec/containers/0/imagePullPolicy/",
}
er := Validate(PolicyContext{Policy: policy, NewResource: *resourceUnstructured})
for index, r := range er.PolicyResponse.Rules {
@ -223,8 +223,8 @@ func TestValidate_image_tag_pass(t *testing.T) {
resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
assert.NilError(t, err)
msgs := []string{
"Validation rule 'validate-tag' succeeded.",
"Validation rule 'validate-latest' succeeded.",
"validation rule 'validate-tag' passed.",
"validation rule 'validate-latest' passed.",
}
er := Validate(PolicyContext{Policy: policy, NewResource: *resourceUnstructured})
for index, r := range er.PolicyResponse.Rules {
@ -301,7 +301,7 @@ func TestValidate_Fail_anyPattern(t *testing.T) {
resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
assert.NilError(t, err)
er := Validate(PolicyContext{Policy: policy, NewResource: *resourceUnstructured})
msgs := []string{"A namespace is required"}
msgs := []string{"validation error: A namespace is required. Rule check-default-namespace[0] failed at path /metadata/namespace/. Rule check-default-namespace[1] failed at path /metadata/namespace/."}
for index, r := range er.PolicyResponse.Rules {
assert.Equal(t, r.Message, msgs[index])
}
@ -383,7 +383,7 @@ func TestValidate_host_network_port(t *testing.T) {
resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
assert.NilError(t, err)
er := Validate(PolicyContext{Policy: policy, NewResource: *resourceUnstructured})
msgs := []string{"Validation error: Host network and port are not allowed; Validation rule validate-host-network-port failed at path /spec/containers/0/ports/0/hostPort/"}
msgs := []string{"validation error: Host network and port are not allowed. Rule validate-host-network-port failed at path /spec/containers/0/ports/0/hostPort/"}
for index, r := range er.PolicyResponse.Rules {
assert.Equal(t, r.Message, msgs[index])
@ -473,7 +473,7 @@ func TestValidate_anchor_arraymap_pass(t *testing.T) {
resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
assert.NilError(t, err)
er := Validate(PolicyContext{Policy: policy, NewResource: *resourceUnstructured})
msgs := []string{"Validation rule 'validate-host-path' succeeded."}
msgs := []string{"validation rule 'validate-host-path' passed."}
for index, r := range er.PolicyResponse.Rules {
assert.Equal(t, r.Message, msgs[index])
@ -561,7 +561,7 @@ func TestValidate_anchor_arraymap_fail(t *testing.T) {
resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
assert.NilError(t, err)
er := Validate(PolicyContext{Policy: policy, NewResource: *resourceUnstructured})
msgs := []string{"Validation error: Host path '/var/lib/' is not allowed; Validation rule validate-host-path failed at path /spec/volumes/0/hostPath/path/"}
msgs := []string{"validation error: Host path '/var/lib/' is not allowed. Rule validate-host-path failed at path /spec/volumes/0/hostPath/path/"}
for index, r := range er.PolicyResponse.Rules {
assert.Equal(t, r.Message, msgs[index])
@ -631,7 +631,7 @@ func TestValidate_anchor_map_notfound(t *testing.T) {
resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
assert.NilError(t, err)
er := Validate(PolicyContext{Policy: policy, NewResource: *resourceUnstructured})
msgs := []string{"Validation rule 'pod rule 2' succeeded."}
msgs := []string{"validation rule 'pod rule 2' passed."}
for index, r := range er.PolicyResponse.Rules {
assert.Equal(t, r.Message, msgs[index])
@ -704,7 +704,7 @@ func TestValidate_anchor_map_found_valid(t *testing.T) {
resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
assert.NilError(t, err)
er := Validate(PolicyContext{Policy: policy, NewResource: *resourceUnstructured})
msgs := []string{"Validation rule 'pod rule 2' succeeded."}
msgs := []string{"validation rule 'pod rule 2' passed."}
for index, r := range er.PolicyResponse.Rules {
assert.Equal(t, r.Message, msgs[index])
@ -777,7 +777,7 @@ func TestValidate_anchor_map_found_invalid(t *testing.T) {
resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
assert.NilError(t, err)
er := Validate(PolicyContext{Policy: policy, NewResource: *resourceUnstructured})
msgs := []string{"Validation error: pod: validate run as non root user; Validation rule pod rule 2 failed at path /spec/securityContext/runAsNonRoot/"}
msgs := []string{"validation error: pod: validate run as non root user. Rule pod rule 2 failed at path /spec/securityContext/runAsNonRoot/"}
for index, r := range er.PolicyResponse.Rules {
assert.Equal(t, r.Message, msgs[index])
@ -852,7 +852,7 @@ func TestValidate_AnchorList_pass(t *testing.T) {
resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
assert.NilError(t, err)
er := Validate(PolicyContext{Policy: policy, NewResource: *resourceUnstructured})
msgs := []string{"Validation rule 'pod image rule' succeeded."}
msgs := []string{"validation rule 'pod image rule' passed."}
for index, r := range er.PolicyResponse.Rules {
t.Log(r.Message)
@ -927,11 +927,6 @@ func TestValidate_AnchorList_fail(t *testing.T) {
resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
assert.NilError(t, err)
er := Validate(PolicyContext{Policy: policy, NewResource: *resourceUnstructured})
// msgs := []string{"Validation rule 'pod image rule' failed at '/spec/containers/1/name/' for resource Pod//myapp-pod."}
// for index, r := range er.PolicyResponse.Rules {
// // t.Log(r.Message)
// assert.Equal(t, r.Message, msgs[index])
// }
assert.Assert(t, !er.IsSuccessful())
}
@ -1002,12 +997,6 @@ func TestValidate_existenceAnchor_fail(t *testing.T) {
resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
assert.NilError(t, err)
er := Validate(PolicyContext{Policy: policy, NewResource: *resourceUnstructured})
// msgs := []string{"Validation rule 'pod image rule' failed at '/spec/containers/' for resource Pod//myapp-pod."}
// for index, r := range er.PolicyResponse.Rules {
// t.Log(r.Message)
// assert.Equal(t, r.Message, msgs[index])
// }
assert.Assert(t, !er.IsSuccessful())
}
@ -1078,7 +1067,7 @@ func TestValidate_existenceAnchor_pass(t *testing.T) {
resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
assert.NilError(t, err)
er := Validate(PolicyContext{Policy: policy, NewResource: *resourceUnstructured})
msgs := []string{"Validation rule 'pod image rule' succeeded."}
msgs := []string{"validation rule 'pod image rule' passed."}
for index, r := range er.PolicyResponse.Rules {
assert.Equal(t, r.Message, msgs[index])
@ -1166,7 +1155,7 @@ func TestValidate_negationAnchor_deny(t *testing.T) {
resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
assert.NilError(t, err)
er := Validate(PolicyContext{Policy: policy, NewResource: *resourceUnstructured})
msgs := []string{"Validation error: Host path is not allowed; Validation rule validate-host-path failed at path /spec/volumes/0/hostPath/"}
msgs := []string{"validation error: Host path is not allowed. Rule validate-host-path failed at path /spec/volumes/0/hostPath/"}
for index, r := range er.PolicyResponse.Rules {
assert.Equal(t, r.Message, msgs[index])
@ -1253,7 +1242,7 @@ func TestValidate_negationAnchor_pass(t *testing.T) {
resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
assert.NilError(t, err)
er := Validate(PolicyContext{Policy: policy, NewResource: *resourceUnstructured})
msgs := []string{"Validation rule 'validate-host-path' succeeded."}
msgs := []string{"validation rule 'validate-host-path' passed."}
for index, r := range er.PolicyResponse.Rules {
assert.Equal(t, r.Message, msgs[index])
@ -1330,7 +1319,8 @@ func Test_VariableSubstitutionPathNotExistInPattern(t *testing.T) {
NewResource: *resourceUnstructured}
er := Validate(policyContext)
assert.Assert(t, !er.PolicyResponse.Rules[0].Success)
assert.Equal(t, er.PolicyResponse.Rules[0].Message, "Validation error: ; Validation rule 'test-path-not-exist' failed. 'variable request.object.metadata.name1 not found (path: /spec/containers/0/name)'")
assert.Equal(t, er.PolicyResponse.Rules[0].Message,
"variable substitution failed for rule test-path-not-exist: variable request.object.metadata.name1 not resolved at path /spec/containers/0/name")
}
func Test_VariableSubstitutionPathNotExistInAnyPattern_OnePatternStatisfies(t *testing.T) {
@ -1421,7 +1411,7 @@ func Test_VariableSubstitutionPathNotExistInAnyPattern_OnePatternStatisfies(t *t
NewResource: *resourceUnstructured}
er := Validate(policyContext)
assert.Assert(t, er.PolicyResponse.Rules[0].Success)
assert.Equal(t, er.PolicyResponse.Rules[0].Message, "Validation rule 'test-path-not-exist' anyPattern[1] succeeded.")
assert.Equal(t, er.PolicyResponse.Rules[0].Message, "validation rule 'test-path-not-exist' anyPattern[1] passed.")
}
func Test_VariableSubstitutionPathNotExistInAnyPattern_AllPathNotPresent(t *testing.T) {
@ -1512,7 +1502,7 @@ func Test_VariableSubstitutionPathNotExistInAnyPattern_AllPathNotPresent(t *test
NewResource: *resourceUnstructured}
er := Validate(policyContext)
assert.Assert(t, !er.PolicyResponse.Rules[0].Success)
assert.Equal(t, er.PolicyResponse.Rules[0].Message, "Substitutions failed: [variable request.object.metadata.name1 not found (path: /spec/template/spec/containers/0/name) variable request.object.metadata.name2 not found (path: /spec/template/spec/containers/0/name)]")
assert.Equal(t, er.PolicyResponse.Rules[0].Message, "failed to substitute variables: [variable request.object.metadata.name1 not resolved at path /spec/template/spec/containers/0/name variable request.object.metadata.name2 not resolved at path /spec/template/spec/containers/0/name]")
}
func Test_VariableSubstitutionPathNotExistInAnyPattern_AllPathPresent_NonePatternSatisfy(t *testing.T) {
@ -1603,9 +1593,9 @@ func Test_VariableSubstitutionPathNotExistInAnyPattern_AllPathPresent_NonePatter
NewResource: *resourceUnstructured}
er := Validate(policyContext)
// expectedMsg := "Validation error: ; Validation rule test-path-not-exist anyPattern[0] failed at path /spec/template/spec/containers/0/name/. Validation rule test-path-not-exist anyPattern[1] failed at path /spec/template/spec/containers/0/name/."
assert.Assert(t, !er.PolicyResponse.Rules[0].Success)
assert.Equal(t, er.PolicyResponse.Rules[0].Message, "Validation rule 'test-path-not-exist' has failed")
assert.Equal(t, er.PolicyResponse.Rules[0].Message,
"validation error: Rule test-path-not-exist[0] failed at path /spec/template/spec/containers/0/name/. Rule test-path-not-exist[1] failed at path /spec/template/spec/containers/0/name/.")
}
func Test_denyFeatureIssue744(t *testing.T) {

View file

@ -82,7 +82,7 @@ type NotFoundVariableErr struct {
}
func (n NotFoundVariableErr) Error() string {
return fmt.Sprintf("variable %v not found (path: %v)", n.variable, n.path)
return fmt.Sprintf("variable %s not resolved at path %s", n.variable, n.path)
}
// subValR resolves the variables if defined

View file

@ -18,7 +18,7 @@ import (
"github.com/kyverno/kyverno/pkg/engine/context"
"github.com/kyverno/kyverno/pkg/engine/response"
"github.com/kyverno/kyverno/pkg/kyverno/common"
sanitizedError "github.com/kyverno/kyverno/pkg/kyverno/sanitizedError"
"github.com/kyverno/kyverno/pkg/kyverno/sanitizedError"
"github.com/kyverno/kyverno/pkg/openapi"
policy2 "github.com/kyverno/kyverno/pkg/policy"
"github.com/kyverno/kyverno/pkg/utils"
@ -59,18 +59,7 @@ type SkippedPolicy struct {
Variable string `json:"variable"`
}
func Command() *cobra.Command {
var cmd *cobra.Command
var resourcePaths []string
var cluster, policyReport bool
var mutateLogPath, variablesString, valuesFile, namespace string
kubernetesConfig := genericclioptions.NewConfigFlags(true)
cmd = &cobra.Command{
Use: "apply",
Short: "applies policies on resources",
Example: fmt.Sprintf(`
var applyHelp = `
To apply on a resource:
kyverno apply /path/to/policy.yaml /path/to/folderOfPolicies --resource=/path/to/resource1 --resource=/path/to/resource2
@ -112,12 +101,25 @@ To apply policy with variables:
<variable1 in policy2>: <value>
<variable2 in policy2>: <value>
More info: https://kyverno.io/docs/kyverno-cli/
`),
More info: https://kyverno.io/docs/kyverno-cli/
`
func Command() *cobra.Command {
var cmd *cobra.Command
var resourcePaths []string
var cluster, policyReport bool
var mutateLogPath, variablesString, valuesFile, namespace string
kubernetesConfig := genericclioptions.NewConfigFlags(true)
cmd = &cobra.Command{
Use: "apply",
Short: "applies policies on resources",
Example: applyHelp,
RunE: func(cmd *cobra.Command, policyPaths []string) (err error) {
defer func() {
if err != nil {
if !sanitizedError.IsErrorSanitized(err) {
if !sanitizederror.IsErrorSanitized(err) {
log.Log.Error(err, "failed to sanitize")
err = fmt.Errorf("internal error")
}
@ -125,20 +127,20 @@ To apply policy with variables:
}()
if valuesFile != "" && variablesString != "" {
return sanitizedError.NewWithError("pass the values either using set flag or values_file flag", err)
return sanitizederror.NewWithError("pass the values either using set flag or values_file flag", err)
}
variables, valuesMap, err := getVariable(variablesString, valuesFile)
if err != nil {
if !sanitizedError.IsErrorSanitized(err) {
return sanitizedError.NewWithError("failed to decode yaml", err)
if !sanitizederror.IsErrorSanitized(err) {
return sanitizederror.NewWithError("failed to decode yaml", err)
}
return err
}
openAPIController, err := openapi.NewOpenAPIController()
if err != nil {
return sanitizedError.NewWithError("failed to initialize openAPIController", err)
return sanitizederror.NewWithError("failed to initialize openAPIController", err)
}
var dClient *client.Client
@ -154,33 +156,41 @@ To apply policy with variables:
}
if len(policyPaths) == 0 {
return sanitizedError.NewWithError(fmt.Sprintf("require policy"), err)
return sanitizederror.NewWithError(fmt.Sprintf("require policy"), err)
}
policies, err := common.ValidateAndGetPolicies(policyPaths)
if err != nil {
if !sanitizedError.IsErrorSanitized(err) {
return sanitizedError.NewWithError("failed to mutate policies.", err)
policies, errors := common.GetPolicies(policyPaths)
if len(policies) == 0 {
if len(errors) > 0 {
return sanitizederror.NewWithErrors("failed to read policies", errors)
}
return sanitizederror.New(fmt.Sprintf("no policies found in paths %v", policyPaths))
}
if len(errors) > 0 && log.Log.V(1).Enabled() {
fmt.Printf("ignoring errors: \n")
for _, e := range errors {
fmt.Printf(" %v \n", e.Error())
}
return err
}
if len(resourcePaths) == 0 && !cluster {
return sanitizedError.NewWithError(fmt.Sprintf("resource file(s) or cluster required"), err)
return sanitizederror.NewWithError(fmt.Sprintf("resource file(s) or cluster required"), err)
}
mutateLogPathIsDir, err := checkMutateLogPath(mutateLogPath)
if err != nil {
if !sanitizedError.IsErrorSanitized(err) {
return sanitizedError.NewWithError("failed to create file/folder", err)
if !sanitizederror.IsErrorSanitized(err) {
return sanitizederror.NewWithError("failed to create file/folder", err)
}
return err
}
mutatedPolicies, err := mutatePolices(policies)
if err != nil {
if !sanitizedError.IsErrorSanitized(err) {
return sanitizedError.NewWithError("failed to mutate policy", err)
if !sanitizederror.IsErrorSanitized(err) {
return sanitizederror.NewWithError("failed to mutate policy", err)
}
}
@ -244,12 +254,12 @@ To apply policy with variables:
}
if len(common.PolicyHasVariables(*policy)) > 0 && len(thisPolicyResourceValues) == 0 {
return sanitizedError.NewWithError(fmt.Sprintf("policy %s have variables. pass the values for the variables using set/values_file flag", policy.Name), err)
return sanitizederror.NewWithError(fmt.Sprintf("policy %s have variables. pass the values for the variables using set/values_file flag", policy.Name), err)
}
ers, validateErs, err := applyPolicyOnResource(policy, resource, mutateLogPath, mutateLogPathIsDir, thisPolicyResourceValues, rc, policyReport)
if err != nil {
return sanitizedError.NewWithError(fmt.Errorf("failed to apply policy %v on resource %v", policy.Name, resource.GetName()).Error(), err)
return sanitizederror.NewWithError(fmt.Errorf("failed to apply policy %v on resource %v", policy.Name, resource.GetName()).Error(), err)
}
engineResponses = append(engineResponses, ers...)
validateEngineResponses = append(validateEngineResponses, validateErs)
@ -285,17 +295,17 @@ func getVariable(variablesString, valuesFile string) (variables map[string]strin
if valuesFile != "" {
yamlFile, err := ioutil.ReadFile(valuesFile)
if err != nil {
return variables, valuesMap, sanitizedError.NewWithError("unable to read yaml", err)
return variables, valuesMap, sanitizederror.NewWithError("unable to read yaml", err)
}
valuesBytes, err := yaml.ToJSON(yamlFile)
if err != nil {
return variables, valuesMap, sanitizedError.NewWithError("failed to convert json", err)
return variables, valuesMap, sanitizederror.NewWithError("failed to convert json", err)
}
values := &Values{}
if err := json.Unmarshal(valuesBytes, values); err != nil {
return variables, valuesMap, sanitizedError.NewWithError("failed to decode yaml", err)
return variables, valuesMap, sanitizederror.NewWithError("failed to decode yaml", err)
}
for _, p := range values.Policies {
@ -323,8 +333,8 @@ func checkMutateLogPath(mutateLogPath string) (mutateLogPathIsDir bool, err erro
err := createFileOrFolder(mutateLogPath, mutateLogPathIsDir)
if err != nil {
if !sanitizedError.IsErrorSanitized(err) {
return mutateLogPathIsDir, sanitizedError.NewWithError("failed to create file/folder.", err)
if !sanitizederror.IsErrorSanitized(err) {
return mutateLogPathIsDir, sanitizederror.NewWithError("failed to create file/folder.", err)
}
return mutateLogPathIsDir, err
}
@ -345,7 +355,7 @@ func getResourceAccordingToResourcePath(resourcePaths []string, cluster bool, po
yamlBytes := []byte(resourceStr)
resources, err = common.GetResource(yamlBytes)
if err != nil {
return resources, sanitizedError.NewWithError("failed to extract the resources", err)
return resources, sanitizederror.NewWithError("failed to extract the resources", err)
}
}
} else if (len(resourcePaths) > 0 && resourcePaths[0] != "-") || len(resourcePaths) < 0 || cluster {
@ -434,7 +444,7 @@ func applyPolicyOnResource(policy *v1.ClusterPolicy, resource *unstructured.Unst
} else {
err := printMutatedOutput(mutateLogPath, mutateLogPathIsDir, string(yamlEncodedResource), resource.GetName()+"-mutated")
if err != nil {
return engineResponses, response.EngineResponse{}, sanitizedError.NewWithError("failed to print mutated result", err)
return engineResponses, response.EngineResponse{}, sanitizederror.NewWithError("failed to print mutated result", err)
}
fmt.Printf("\n\nMutation:\nMutation has been applied successfully. Check the files.")
}
@ -503,8 +513,8 @@ func mutatePolices(policies []*v1.ClusterPolicy) ([]*v1.ClusterPolicy, error) {
for _, policy := range policies {
p, err := common.MutatePolicy(policy, logger)
if err != nil {
if !sanitizedError.IsErrorSanitized(err) {
return nil, sanitizedError.NewWithError("failed to mutate policy.", err)
if !sanitizederror.IsErrorSanitized(err) {
return nil, sanitizederror.NewWithError("failed to mutate policy.", err)
}
return nil, err
}
@ -557,30 +567,30 @@ func createFileOrFolder(mutateLogPath string, mutateLogPathIsDir bool) error {
if os.IsNotExist(err) {
errDir := os.MkdirAll(folderPath, 0755)
if errDir != nil {
return sanitizedError.NewWithError(fmt.Sprintf("failed to create directory"), err)
return sanitizederror.NewWithError(fmt.Sprintf("failed to create directory"), err)
}
}
}
file, err := os.OpenFile(mutateLogPath, os.O_RDONLY|os.O_CREATE, 0644)
if err != nil {
return sanitizedError.NewWithError(fmt.Sprintf("failed to create file"), err)
return sanitizederror.NewWithError(fmt.Sprintf("failed to create file"), err)
}
err = file.Close()
if err != nil {
return sanitizedError.NewWithError(fmt.Sprintf("failed to close file"), err)
return sanitizederror.NewWithError(fmt.Sprintf("failed to close file"), err)
}
} else {
errDir := os.MkdirAll(mutateLogPath, 0755)
if errDir != nil {
return sanitizedError.NewWithError(fmt.Sprintf("failed to create directory"), err)
return sanitizederror.NewWithError(fmt.Sprintf("failed to create directory"), err)
}
}
} else {
return sanitizedError.NewWithError(fmt.Sprintf("failed to describe file"), err)
return sanitizederror.NewWithError(fmt.Sprintf("failed to describe file"), err)
}
}

View file

@ -9,6 +9,7 @@ import (
"io/ioutil"
"os"
"path/filepath"
"sigs.k8s.io/controller-runtime/pkg/log"
jsonpatch "github.com/evanphx/json-patch"
"github.com/go-logr/logr"
@ -22,62 +23,56 @@ import (
)
// GetPolicies - Extracting the policies from multiple YAML
func GetPolicies(paths []string) (policies []*v1.ClusterPolicy, error error) {
func GetPolicies(paths []string) (policies []*v1.ClusterPolicy, errors []error) {
for _, path := range paths {
log.Log.V(5).Info("reading policies", "path", path)
path = filepath.Clean(path)
fileDesc, err := os.Stat(path)
if err != nil {
return nil, err
errors = append(errors, err)
continue
}
if fileDesc.IsDir() {
files, err := ioutil.ReadDir(path)
if err != nil {
return nil, sanitizederror.NewWithError(fmt.Sprintf("failed to parse %v", path), err)
errors = append(errors, fmt.Errorf("failed to read %v: %v", path, err.Error()))
continue
}
listOfFiles := make([]string, 0)
for _, file := range files {
listOfFiles = append(listOfFiles, filepath.Join(path, file.Name()))
}
policiesFromDir, err := GetPolicies(listOfFiles)
if err != nil {
return nil, sanitizederror.NewWithError(fmt.Sprintf("failed to extract policies from %v", listOfFiles), err)
}
policies = append(policies, policiesFromDir...)
} else {
file, err := ioutil.ReadFile(path)
if err != nil {
return nil, sanitizederror.NewWithError(fmt.Sprintf("failed to load file %v", path), err)
}
getPolicies, getErrors := utils.GetPolicy(file)
var errString string
for _, err := range getErrors {
if err != nil {
errString += err.Error() + "\n"
ext := filepath.Ext(file.Name())
if ext == "" || ext == ".yaml" || ext == ".yml" {
listOfFiles = append(listOfFiles, filepath.Join(path, file.Name()))
}
}
if errString != "" {
fmt.Printf("failed to extract policies: %s\n", errString)
os.Exit(2)
policiesFromDir, errorsFromDir := GetPolicies(listOfFiles)
errors = append(errors, errorsFromDir...)
policies = append(policies, policiesFromDir...)
} else {
fileBytes, err := ioutil.ReadFile(path)
if err != nil {
errors = append(errors, fmt.Errorf("failed to read %v: %v", path, err.Error()))
continue
}
policies = append(policies, getPolicies...)
policiesFromFile, errFromFile := utils.GetPolicy(fileBytes)
if errFromFile != nil {
err := fmt.Errorf("failed to process %s: %v", path, errFromFile.Error())
errors = append(errors, err)
continue
}
policies = append(policies, policiesFromFile...)
}
}
return policies, nil
}
//ValidateAndGetPolicies - validating policies
func ValidateAndGetPolicies(policyPaths []string) ([]*v1.ClusterPolicy, error) {
policies, err := GetPolicies(policyPaths)
if err != nil {
if !sanitizederror.IsErrorSanitized(err) {
return nil, sanitizederror.NewWithError((fmt.Sprintf("failed to parse %v path/s.", policyPaths)), err)
}
return nil, err
}
return policies, nil
log.Log.V(3).Info("read policies", "policies", len(policies), "errors", len(errors))
return policies, errors
}
// PolicyHasVariables - check for variables in the policy

View file

@ -1,6 +1,9 @@
package sanitizederror
import "fmt"
import (
"fmt"
"strings"
)
type customError struct {
message string
@ -10,9 +13,18 @@ func (c customError) Error() string {
return c.message
}
// New creates a new sanitized error with given message
func New(message string) error {
return customError{message: message}
func New(msg string) error {
return customError{message: msg}
}
func NewWithErrors(message string, errors []error) error {
bldr := strings.Builder{}
bldr.WriteString(message + "\n")
for _, err := range errors {
bldr.WriteString(err.Error() + "\n")
}
return customError{message: bldr.String()}
}
// NewWithError creates a new sanitized error with given message and error

View file

@ -9,13 +9,13 @@ import (
v1 "github.com/kyverno/kyverno/pkg/api/kyverno/v1"
"github.com/kyverno/kyverno/pkg/kyverno/common"
sanitizederror "github.com/kyverno/kyverno/pkg/kyverno/sanitizedError"
"github.com/kyverno/kyverno/pkg/kyverno/sanitizedError"
"github.com/kyverno/kyverno/pkg/openapi"
policy2 "github.com/kyverno/kyverno/pkg/policy"
"github.com/kyverno/kyverno/pkg/utils"
"github.com/spf13/cobra"
log "sigs.k8s.io/controller-runtime/pkg/log"
yaml "sigs.k8s.io/yaml"
"sigs.k8s.io/controller-runtime/pkg/log"
"sigs.k8s.io/yaml"
)
// Command returns validate command
@ -27,12 +27,10 @@ func Command() *cobra.Command {
Short: "Validates kyverno policies",
Example: "kyverno validate /path/to/policy.yaml /path/to/folderOfPolicies",
RunE: func(cmd *cobra.Command, policyPaths []string) (err error) {
log := log.Log
defer func() {
if err != nil {
if !sanitizederror.IsErrorSanitized(err) {
log.Error(err, "failed to sanitize")
log.Log.Error(err, "failed to sanitize")
err = fmt.Errorf("internal error")
}
}
@ -58,26 +56,22 @@ func Command() *cobra.Command {
}
yamlBytes := []byte(policyStr)
var getErrors []error
policies, getErrors = utils.GetPolicy(yamlBytes)
var errString string
for _, err := range getErrors {
if err != nil {
errString += err.Error() + "\n"
}
}
if errString != "" {
return sanitizederror.NewWithError("failed to extract the resources", errors.New(errString))
policies, err = utils.GetPolicy(yamlBytes)
if err != nil {
return sanitizederror.NewWithError("failed to parse policy", err)
}
}
} else {
policies, err = common.ValidateAndGetPolicies(policyPaths)
if err != nil {
if !sanitizederror.IsErrorSanitized(err) {
return sanitizederror.NewWithError("failed to mutate policies.", err)
policies, errs := common.GetPolicies(policyPaths)
if len(errs) > 0 && len(policies) == 0 {
return sanitizederror.NewWithErrors("failed to read policies", errs)
}
if len(errs) > 0 && log.Log.V(1).Enabled() {
fmt.Printf("ignoring errors: \n")
for _, e := range errs {
fmt.Printf(" %v \n", e.Error())
}
return err
}
}
@ -109,7 +103,7 @@ func Command() *cobra.Command {
} else {
fmt.Printf("Policy %s is valid.\n\n", policy.Name)
if outputType != "" {
logger := log.WithName("validate")
logger := log.Log.WithName("validate")
p, err := common.MutatePolicy(policy, logger)
if err != nil {
if !sanitizederror.IsErrorSanitized(err) {

View file

@ -30,9 +30,9 @@ func Test_Exclude(t *testing.T) {
if err != nil {
t.Log(err)
}
policies, errs := utils.GetPolicy(file)
if len(errs) != 0 {
t.Log(errs)
policies, err := utils.GetPolicy(file)
if err != nil {
t.Log(err)
}
policy := policies[0]
@ -61,9 +61,9 @@ func Test_CronJobOnly(t *testing.T) {
if err != nil {
t.Log(err)
}
policies, errs := utils.GetPolicy(file)
if len(errs) != 0 {
t.Log(errs)
policies, err := utils.GetPolicy(file)
if err != nil {
t.Log(err)
}
policy := policies[0]
@ -94,9 +94,9 @@ func Test_CronJob_hasExclude(t *testing.T) {
if err != nil {
t.Log(err)
}
policies, errs := utils.GetPolicy(file)
if len(errs) != 0 {
t.Log(errs)
policies, err := utils.GetPolicy(file)
if err != nil {
t.Log(err)
}
policy := policies[0]
@ -130,9 +130,9 @@ func Test_CronJobAndDeployment(t *testing.T) {
if err != nil {
t.Log(err)
}
policies, errs := utils.GetPolicy(file)
if len(errs) != 0 {
t.Log(errs)
policies, err := utils.GetPolicy(file)
if err != nil {
t.Log(err)
}
policy := policies[0]

View file

@ -11,35 +11,33 @@ import (
"k8s.io/apimachinery/pkg/util/yaml"
)
// GetPolicy - Extracts policies from a YAML
func GetPolicy(file []byte) (clusterPolicies []*v1.ClusterPolicy, errors []error) {
policies, err := SplitYAMLDocuments(file)
// GetPolicy - extracts policies from YAML bytes
func GetPolicy(bytes []byte) (clusterPolicies []*v1.ClusterPolicy, err error) {
policies, err := SplitYAMLDocuments(bytes)
if err != nil {
errors = append(errors, err)
return clusterPolicies, errors
return nil, err
}
for _, thisPolicyBytes := range policies {
policyBytes, err := yaml.ToJSON(thisPolicyBytes)
if err != nil {
errors = append(errors, fmt.Errorf(fmt.Sprintf("failed to convert json. error: %v", err)))
continue
return nil, fmt.Errorf("failed to convert to JSON: %v", err)
}
policy := &v1.ClusterPolicy{}
if err := json.Unmarshal(policyBytes, policy); err != nil {
errors = append(errors, fmt.Errorf(fmt.Sprintf("failed to decode policy. error: %v", err)))
continue
return nil, fmt.Errorf("failed to decode policy: %v", err)
}
if !(policy.TypeMeta.Kind == "ClusterPolicy" || policy.TypeMeta.Kind == "Policy") {
errors = append(errors, fmt.Errorf(fmt.Sprintf("resource %v is not a policy/clusterPolicy", policy.Name)))
continue
msg := fmt.Sprintf("resource %s/%s is not a Policy or a ClusterPolicy", policy.Kind, policy.Name)
return nil, fmt.Errorf(msg)
}
clusterPolicies = append(clusterPolicies, policy)
}
return clusterPolicies, errors
return clusterPolicies, nil
}
// SplitYAMLDocuments reads the YAML bytes per-document, unmarshals the TypeMeta information from each document

View file

@ -28,5 +28,5 @@ expected:
rules:
- name: check-cpu-memory-limits
type: Validation
message: Validation rule 'check-cpu-memory-limits' succeeded.
message: validation rule 'check-cpu-memory-limits' passed.
success: true

View file

@ -15,5 +15,5 @@ expected:
rules:
- name: validate-default-proc-mount
type: Validation
message: "Validation rule 'validate-default-proc-mount' succeeded."
message: "validation rule 'validate-default-proc-mount' passed."
success: true

View file

@ -14,5 +14,5 @@ expected:
rules:
- name: prevent-mounting-default-serviceaccount
type: Validation
message: "Validation error: Prevent mounting of default service account; Validation rule prevent-mounting-default-serviceaccount failed at path /spec/serviceAccountName/"
message: "validation error: Prevent mounting of default service account. Rule prevent-mounting-default-serviceaccount failed at path /spec/serviceAccountName/"
success: false

View file

@ -14,9 +14,9 @@ expected:
rules:
- name: check-readinessProbe-exists
type: Validation
message: Validation rule 'check-readinessProbe-exists' succeeded.
message: validation rule 'check-readinessProbe-exists' passed.
success: true
- name: check-livenessProbe-exists
type: Validation
message: Validation rule 'check-livenessProbe-exists' succeeded.
message: validation rule 'check-livenessProbe-exists' passed.
success: true

View file

@ -15,5 +15,5 @@ expected:
rules:
- name: validate-selinux-options
type: Validation
message: "Validation error: SELinux level is required; Validation rule validate-selinux-options failed at path /spec/containers/0/securityContext/seLinuxOptions/"
message: "validation error: SELinux level is required. Rule validate-selinux-options failed at path /spec/containers/0/securityContext/seLinuxOptions/"
success: false

View file

@ -15,5 +15,5 @@ expected:
rules:
- name: validate-volumes-whitelist
type: Validation
message: "Validation rule 'validate-volumes-whitelist' anyPattern[2] succeeded."
message: "validation rule 'validate-volumes-whitelist' anyPattern[2] passed."
success: true

View file

@ -14,5 +14,5 @@ expected:
rules:
- name: validate-docker-sock-mount
type: Validation
message: "Validation error: Use of the Docker Unix socket is not allowed; Validation rule validate-docker-sock-mount failed at path /spec/volumes/0/hostPath/path/"
message: "validation error: Use of the Docker Unix socket is not allowed. Rule validate-docker-sock-mount failed at path /spec/volumes/0/hostPath/path/"
success: false

View file

@ -12,5 +12,5 @@ expected:
rules:
- name: validate-helm-tiller
type: Validation
message: "Validation error: Helm Tiller is not allowed; Validation rule validate-helm-tiller failed at path /spec/containers/0/image/"
message: "validation error: Helm Tiller is not allowed. Rule validate-helm-tiller failed at path /spec/containers/0/image/"
success: false