mirror of
https://github.com/kyverno/kyverno.git
synced 2024-12-14 11:57:48 +00:00
feat: add auto-gen rules for CEL (#7859)
* feat: add auto-gen rules for CEL Signed-off-by: Mariam Fahmy <mariam.fahmy@nirmata.com> * clean up Signed-off-by: Mariam Fahmy <mariam.fahmy@nirmata.com> --------- Signed-off-by: Mariam Fahmy <mariam.fahmy@nirmata.com>
This commit is contained in:
parent
ea631bdf81
commit
35e368730b
3 changed files with 119 additions and 0 deletions
|
@ -204,6 +204,15 @@ func convertRule(rule kyvernoRule, kind string) (*kyvernov1.Rule, error) {
|
|||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// CEL variables are object, oldObject, request, params and authorizer.
|
||||
// Therefore CEL expressions can be either written as object.spec or request.object.spec
|
||||
if rule.Validation != nil && rule.Validation.CEL != nil {
|
||||
bytes = updateCELFields(bytes, kind)
|
||||
if err := json.Unmarshal(bytes, &rule); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
out := kyvernov1.Rule{
|
||||
|
|
|
@ -350,6 +350,47 @@ func TestUpdateGenRuleByte(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestUpdateCELFields(t *testing.T) {
|
||||
tests := []struct {
|
||||
pbyte []byte
|
||||
kind string
|
||||
want []byte
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
pbyte: []byte("object.spec"),
|
||||
kind: "Pod",
|
||||
want: []byte("object.spec.template.spec"),
|
||||
},
|
||||
{
|
||||
pbyte: []byte("oldObject.spec"),
|
||||
kind: "Pod",
|
||||
want: []byte("oldObject.spec.template.spec"),
|
||||
},
|
||||
{
|
||||
pbyte: []byte("object.spec"),
|
||||
kind: "Cronjob",
|
||||
want: []byte("object.spec.jobTemplate.spec.template.spec"),
|
||||
},
|
||||
{
|
||||
pbyte: []byte("oldObject.spec"),
|
||||
kind: "Cronjob",
|
||||
want: []byte("oldObject.spec.jobTemplate.spec.template.spec"),
|
||||
},
|
||||
{
|
||||
pbyte: []byte("object.metadata"),
|
||||
kind: "Pod",
|
||||
want: []byte("object.spec.template.metadata"),
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
got := updateCELFields(tt.pbyte, tt.kind)
|
||||
if !reflect.DeepEqual(got, tt.want) {
|
||||
t.Errorf("updateCELFields() = %v, want %v", string(got), string(tt.want))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func Test_ComputeRules(t *testing.T) {
|
||||
intPtr := func(i int) *int { return &i }
|
||||
testCases := []struct {
|
||||
|
@ -546,3 +587,51 @@ func Test_PodSecurityWithNoExceptions(t *testing.T) {
|
|||
rules := computeRules(policies[0])
|
||||
assert.Equal(t, 3, len(rules))
|
||||
}
|
||||
|
||||
func Test_ValidateWithCELExpressions(t *testing.T) {
|
||||
policy := []byte(`
|
||||
{
|
||||
"apiVersion": "kyverno.io/v1",
|
||||
"kind": "ClusterPolicy",
|
||||
"metadata": {
|
||||
"name": "disallow-host-path"
|
||||
},
|
||||
"spec": {
|
||||
"validationFailureAction": "Enforce",
|
||||
"background": false,
|
||||
"rules": [
|
||||
{
|
||||
"name": "host-path",
|
||||
"match": {
|
||||
"any": [
|
||||
{
|
||||
"resources": {
|
||||
"kinds": [
|
||||
"Pod"
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"validate": {
|
||||
"cel": {
|
||||
"expressions": [
|
||||
{
|
||||
"expression": "!has(object.spec.volumes) || object.spec.volumes.all(volume, !has(volume.hostPath))",
|
||||
"message": "HostPath volumes are forbidden. The field spec.template.spec.volumes[*].hostPath must be unset."
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
`)
|
||||
policies, _, err := yamlutils.GetPolicy([]byte(policy))
|
||||
assert.NilError(t, err)
|
||||
assert.Equal(t, 1, len(policies))
|
||||
|
||||
rules := computeRules(policies[0])
|
||||
assert.Equal(t, 3, len(rules))
|
||||
}
|
||||
|
|
|
@ -200,6 +200,11 @@ func generateRule(name string, rule *kyvernov1.Rule, tplKey, shift string, kinds
|
|||
rule.VerifyImages = newVerifyImages
|
||||
return rule
|
||||
}
|
||||
if rule.HasValidateCEL() {
|
||||
cel := rule.Validation.CEL.DeepCopy()
|
||||
rule.Validation.CEL = cel
|
||||
return rule
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -326,3 +331,19 @@ func updateRestrictedFields(pbyte []byte, kind string) (obj []byte) {
|
|||
obj = []byte(strings.ReplaceAll(string(obj), "metadata", "spec.template.metadata"))
|
||||
return obj
|
||||
}
|
||||
|
||||
func updateCELFields(pbyte []byte, kind string) (obj []byte) {
|
||||
if kind == "Pod" {
|
||||
obj = []byte(strings.ReplaceAll(string(pbyte), "object.spec", "object.spec.template.spec"))
|
||||
obj = []byte(strings.ReplaceAll(string(obj), "oldObject.spec", "oldObject.spec.template.spec"))
|
||||
obj = []byte(strings.ReplaceAll(string(obj), "object.metadata", "object.spec.template.metadata"))
|
||||
obj = []byte(strings.ReplaceAll(string(obj), "oldObject.metadata", "oldObject.spec.template.metadata"))
|
||||
}
|
||||
if kind == "Cronjob" {
|
||||
obj = []byte(strings.ReplaceAll(string(pbyte), "object.spec", "object.spec.jobTemplate.spec.template.spec"))
|
||||
obj = []byte(strings.ReplaceAll(string(obj), "oldObject.spec", "oldObject.spec.jobTemplate.spec.template.spec"))
|
||||
obj = []byte(strings.ReplaceAll(string(obj), "object.metadata", "object.spec.jobTemplate.spec.template.metadata"))
|
||||
obj = []byte(strings.ReplaceAll(string(obj), "oldObject.metadata", "oldObject.spec.jobTemplate.spec.template.metadata"))
|
||||
}
|
||||
return obj
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue