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

fix: reduce dependency from engine to cli (#6134)

* fix: remove dependency from engine to cli

Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com>

* refactor

Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com>

---------

Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com>
This commit is contained in:
Charles-Edouard Brétéché 2023-01-30 16:30:47 +01:00 committed by GitHub
parent 892b8f921d
commit 2f487ffda0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 148 additions and 175 deletions

View file

@ -341,7 +341,7 @@ func (c *ApplyCommandConfig) applyCommandHelper() (rc *common.ResultCounts, reso
fmt.Printf("Error: failed to load request info\nCause: %s\n", err)
osExit(1)
}
store.SetSubjects(subjectInfo)
store.SetSubject(subjectInfo.Subject)
}
if c.VariablesString != "" {

View file

@ -778,7 +778,7 @@ func applyPoliciesFromPath(fs billy.Filesystem, policyBytes []byte, isGit bool,
fmt.Printf("Error: failed to load request info\nCause: %s\n", err)
os.Exit(1)
}
store.SetSubjects(subjectInfo)
store.SetSubject(subjectInfo.Subject)
}
policyFullPath := getFullPath(values.Policies, policyResourcePath, isGit)

View file

@ -362,9 +362,7 @@ func GetVariable(variablesString, valuesFile string, fs billy.Filesystem, isGit
})
}
store.SetContext(store.Context{
Policies: storePolicies,
})
store.SetPolicies(storePolicies...)
return variables, globalValMap, valuesMapResource, namespaceSelectorMap, subresources, nil
}
@ -855,9 +853,7 @@ func SetInStoreContext(mutatedPolicies []kyvernov1.PolicyInterface, variables ma
})
}
store.SetContext(store.Context{
Policies: storePolicies,
})
store.SetPolicies(storePolicies...)
return variables
}
@ -965,7 +961,7 @@ func CheckVariableForPolicy(valuesMap map[string]map[string]Resource, globalValM
// skipping the variable check for non matching kind
if _, ok := kindOnwhichPolicyIsApplied[resourceKind]; ok {
if len(variable) > 0 && len(thisPolicyResourceValues) == 0 && len(store.GetContext().Policies) == 0 {
if len(variable) > 0 && len(thisPolicyResourceValues) == 0 && store.HasPolicies() {
return thisPolicyResourceValues, sanitizederror.NewWithError(fmt.Sprintf("policy `%s` have variables. pass the values for the variables for resource `%s` using set/values_file flag", policyName, resourceName), nil)
}
}

View file

@ -5,75 +5,6 @@ import (
rbacv1 "k8s.io/api/rbac/v1"
)
var (
Mock bool
registryClient registryclient.Client
AllowApiCalls bool
ContextVar Context
ForeachElement int
Subjects Subject
)
func SetMock(mock bool) {
Mock = mock
}
func GetMock() bool {
return Mock
}
func SetForEachElement(foreachElement int) {
ForeachElement = foreachElement
}
func GetForeachElement() int {
return ForeachElement
}
func SetRegistryAccess(access bool) {
if access {
registryClient = registryclient.NewOrDie(registryclient.WithLocalKeychain())
}
}
func GetRegistryAccess() bool {
return registryClient != nil
}
func GetRegistryClient() registryclient.Client {
return registryClient
}
func SetContext(context Context) {
ContextVar = context
}
func GetContext() Context {
return ContextVar
}
func GetPolicyFromContext(policyName string) *Policy {
for _, policy := range ContextVar.Policies {
if policy.Name == policyName {
return &policy
}
}
return nil
}
func GetPolicyRuleFromContext(policyName string, ruleName string) *Rule {
for _, policy := range ContextVar.Policies {
if policy.Name == policyName {
for _, rule := range policy.Rules {
if rule.Name == ruleName {
return &rule
}
}
}
}
return nil
}
type Context struct {
Policies []Policy `json:"policies"`
}
@ -89,22 +20,92 @@ type Rule struct {
ForEachValues map[string][]interface{} `json:"foreachValues"`
}
func SetSubjects(subjects Subject) {
Subjects = subjects
}
func GetSubjects() Subject {
return Subjects
}
type Subject struct {
Subject rbacv1.Subject `json:"subject,omitempty" yaml:"subject,omitempty"`
}
func AllowApiCall(allow bool) {
AllowApiCalls = allow
var (
mock bool
registryClient registryclient.Client
allowApiCalls bool
policies []Policy
// contextVar Context
foreachElement int
subject rbacv1.Subject
)
func SetMock(m bool) {
mock = m
}
func IsAllowApiCall() bool {
return AllowApiCalls
func IsMock() bool {
return mock
}
func SetForEachElement(element int) {
foreachElement = element
}
func GetForeachElement() int {
return foreachElement
}
func SetRegistryAccess(access bool) {
if access {
registryClient = registryclient.NewOrDie(registryclient.WithLocalKeychain())
}
}
func GetRegistryAccess() bool {
return registryClient != nil
}
func GetRegistryClient() registryclient.Client {
return registryClient
}
func SetPolicies(p ...Policy) {
policies = p
}
func HasPolicies() bool {
return len(policies) != 0
}
func GetPolicy(policyName string) *Policy {
for _, policy := range policies {
if policy.Name == policyName {
return &policy
}
}
return nil
}
func GetPolicyRule(policyName string, ruleName string) *Rule {
for _, policy := range policies {
if policy.Name == policyName {
for _, rule := range policy.Rules {
if rule.Name == ruleName {
return &rule
}
}
}
}
return nil
}
func SetSubject(s rbacv1.Subject) {
subject = s
}
func GetSubject() rbacv1.Subject {
return subject
}
func AllowApiCall(allow bool) {
allowApiCalls = allow
}
func IsApiCallAllowed() bool {
return allowApiCalls
}

View file

@ -22,8 +22,8 @@ func LoadContext(ctx context.Context, logger logr.Logger, rclient registryclient
}
policyName := enginectx.policy.GetName()
if store.GetMock() {
rule := store.GetPolicyRuleFromContext(policyName, ruleName)
if store.IsMock() {
rule := store.GetPolicyRule(policyName, ruleName)
if rule != nil && len(rule.Values) > 0 {
variables := rule.Values
for key, value := range variables {
@ -46,7 +46,7 @@ func LoadContext(ctx context.Context, logger logr.Logger, rclient registryclient
if err := loadVariable(logger, entry, enginectx); err != nil {
return err
}
} else if entry.APICall != nil && store.IsAllowApiCall() {
} else if entry.APICall != nil && store.IsApiCallAllowed() {
if err := loadAPIData(ctx, logger, entry, enginectx); err != nil {
return err
}
@ -55,7 +55,7 @@ func LoadContext(ctx context.Context, logger logr.Logger, rclient registryclient
if rule != nil && len(rule.ForEachValues) > 0 {
for key, value := range rule.ForEachValues {
if err := enginectx.jsonContext.AddVariable(key, value[store.ForeachElement]); err != nil {
if err := enginectx.jsonContext.AddVariable(key, value[store.GetForeachElement()]); err != nil {
return err
}
}

View file

@ -9,7 +9,6 @@ import (
"github.com/go-logr/logr"
gojmespath "github.com/jmespath/go-jmespath"
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
"github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/utils/store"
"github.com/kyverno/kyverno/pkg/autogen"
engineapi "github.com/kyverno/kyverno/pkg/engine/api"
"github.com/kyverno/kyverno/pkg/engine/mutate"
@ -264,33 +263,30 @@ func (f *forEachMutator) mutateElements(ctx context.Context, foreach kyvernov1.F
invertedElement(elements)
}
for i, e := range elements {
if e == nil {
for index, element := range elements {
if element == nil {
continue
}
f.policyContext.JSONContext().Reset()
policyContext := f.policyContext.Copy()
// TODO - this needs to be refactored. The engine should not have a dependency to the CLI code
store.SetForEachElement(i)
falseVar := false
if err := addElementToContext(policyContext, e, i, f.nesting, &falseVar); err != nil {
return mutate.NewErrorResponse(fmt.Sprintf("failed to add element to mutate.foreach[%d].context", i), err)
if err := addElementToContext(policyContext, element, index, f.nesting, &falseVar); err != nil {
return mutate.NewErrorResponse(fmt.Sprintf("failed to add element to mutate.foreach[%d].context", index), err)
}
if err := LoadContext(ctx, f.log, f.rclient, foreach.Context, policyContext, f.rule.Name); err != nil {
return mutate.NewErrorResponse(fmt.Sprintf("failed to load to mutate.foreach[%d].context", i), err)
return mutate.NewErrorResponse(fmt.Sprintf("failed to load to mutate.foreach[%d].context", index), err)
}
preconditionsPassed, err := checkPreconditions(f.log, policyContext, foreach.AnyAllConditions)
if err != nil {
return mutate.NewErrorResponse(fmt.Sprintf("failed to evaluate mutate.foreach[%d].preconditions", i), err)
return mutate.NewErrorResponse(fmt.Sprintf("failed to evaluate mutate.foreach[%d].preconditions", index), err)
}
if !preconditionsPassed {
f.log.Info("mutate.foreach.preconditions not met", "elementIndex", i)
f.log.Info("mutate.foreach.preconditions not met", "elementIndex", index)
continue
}

View file

@ -230,25 +230,21 @@ func Test_variableSubstitutionCLI(t *testing.T) {
}
}`)
configMapVariableContext := store.Context{
Policies: []store.Policy{
{
Name: "cm-variable-example",
Rules: []store.Rule{
{
Name: "example-configmap-lookup",
Values: map[string]interface{}{
"dictionary.data.env": "dev1",
},
expectedPatch := []byte(`{"op":"add","path":"/metadata/labels","value":{"my-environment-name":"dev1"}}`)
store.SetPolicies(
store.Policy{
Name: "cm-variable-example",
Rules: []store.Rule{
{
Name: "example-configmap-lookup",
Values: map[string]interface{}{
"dictionary.data.env": "dev1",
},
},
},
},
}
expectedPatch := []byte(`{"op":"add","path":"/metadata/labels","value":{"my-environment-name":"dev1"}}`)
store.SetContext(configMapVariableContext)
)
store.SetMock(true)
var policy kyverno.ClusterPolicy
err := json.Unmarshal(policyRaw, &policy)

View file

@ -161,8 +161,8 @@ func doesResourceMatchConditionBlock(subresourceGVKToAPIResource map[string]*met
// matchSubjects return true if one of ruleSubjects exist in userInfo
func matchSubjects(ruleSubjects []rbacv1.Subject, userInfo authenticationv1.UserInfo, dynamicConfig []string) bool {
if store.GetMock() {
mockSubject := store.GetSubjects().Subject
if store.IsMock() {
mockSubject := store.GetSubject()
for _, subject := range ruleSubjects {
switch subject.Kind {
case "ServiceAccount":

View file

@ -12,7 +12,6 @@ import (
gojmespath "github.com/jmespath/go-jmespath"
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
kyvernov2alpha1 "github.com/kyverno/kyverno/api/kyverno/v2alpha1"
"github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/utils/store"
"github.com/kyverno/kyverno/pkg/autogen"
"github.com/kyverno/kyverno/pkg/config"
engineapi "github.com/kyverno/kyverno/pkg/engine/api"
@ -323,17 +322,14 @@ func (v *validator) validateElements(ctx context.Context, rclient registryclient
defer v.policyContext.jsonContext.Restore()
applyCount := 0
for i, e := range elements {
if e == nil {
for index, element := range elements {
if element == nil {
continue
}
// TODO - this needs to be refactored. The engine should not have a dependency to the CLI code
store.SetForEachElement(i)
v.policyContext.JSONContext().Reset()
policyContext := v.policyContext.Copy()
if err := addElementToContext(policyContext, e, i, v.nesting, elementScope); err != nil {
if err := addElementToContext(policyContext, element, index, v.nesting, elementScope); err != nil {
v.log.Error(err, "failed to add element to context")
return ruleError(v.rule, engineapi.Validation, "failed to process foreach", err), applyCount
}
@ -353,7 +349,7 @@ func (v *validator) validateElements(ctx context.Context, rclient registryclient
continue
} else if r.Status != engineapi.RuleStatusPass {
if r.Status == engineapi.RuleStatusError {
if i < len(elements)-1 {
if index < len(elements)-1 {
continue
}
msg := fmt.Sprintf("validation failure: %v", r.Message)
@ -369,13 +365,13 @@ func (v *validator) validateElements(ctx context.Context, rclient registryclient
return ruleResponse(*v.rule, engineapi.Validation, "", engineapi.RuleStatusPass), applyCount
}
func addElementToContext(ctx *PolicyContext, e interface{}, elementIndex, nesting int, elementScope *bool) error {
data, err := variables.DocumentToUntyped(e)
func addElementToContext(ctx *PolicyContext, element interface{}, index, nesting int, elementScope *bool) error {
data, err := variables.DocumentToUntyped(element)
if err != nil {
return err
}
if err := ctx.JSONContext().AddElement(data, elementIndex, nesting); err != nil {
return errors.Wrapf(err, "failed to add element (%v) to JSON context", e)
if err := ctx.JSONContext().AddElement(data, index, nesting); err != nil {
return errors.Wrapf(err, "failed to add element (%v) to JSON context", element)
}
dataMap, ok := data.(map[string]interface{})
// We set scoped to true by default if the data is a map

View file

@ -2198,23 +2198,19 @@ func TestValidate_context_variable_substitution_CLI(t *testing.T) {
}
`)
configMapVariableContext := store.Context{
Policies: []store.Policy{
{
Name: "restrict-pod-count",
Rules: []store.Rule{
{
Name: "restrict-pod-count",
Values: map[string]interface{}{
"podcounts": "12",
},
store.SetPolicies(
store.Policy{
Name: "restrict-pod-count",
Rules: []store.Rule{
{
Name: "restrict-pod-count",
Values: map[string]interface{}{
"podcounts": "12",
},
},
},
},
}
store.SetContext(configMapVariableContext)
)
store.SetMock(true)
var policy kyverno.ClusterPolicy
@ -2712,24 +2708,20 @@ func Test_foreach_context_preconditions(t *testing.T) {
}
}`)
configMapVariableContext := store.Context{
Policies: []store.Policy{
{
Name: "test",
Rules: []store.Rule{
{
Name: "test",
Values: map[string]interface{}{
"img.data.podvalid": "nginx/nginx:v1",
"img.data.podinvalid": "nginx/nginx:v2",
},
store.SetPolicies(
store.Policy{
Name: "test",
Rules: []store.Rule{
{
Name: "test",
Values: map[string]interface{}{
"img.data.podvalid": "nginx/nginx:v1",
"img.data.podinvalid": "nginx/nginx:v2",
},
},
},
},
}
store.SetContext(configMapVariableContext)
)
store.SetMock(true)
testForEach(t, policyraw, resourceRaw, "", engineapi.RuleStatusPass)
@ -2806,24 +2798,20 @@ func Test_foreach_context_preconditions_fail(t *testing.T) {
}
}`)
configMapVariableContext := store.Context{
Policies: []store.Policy{
{
Name: "test",
Rules: []store.Rule{
{
Name: "test",
Values: map[string]interface{}{
"img.data.podvalid": "nginx/nginx:v1",
"img.data.podinvalid": "nginx/nginx:v1",
},
store.SetPolicies(
store.Policy{
Name: "test",
Rules: []store.Rule{
{
Name: "test",
Values: map[string]interface{}{
"img.data.podvalid": "nginx/nginx:v1",
"img.data.podinvalid": "nginx/nginx:v1",
},
},
},
},
}
store.SetContext(configMapVariableContext)
)
store.SetMock(true)
testForEach(t, policyraw, resourceRaw, "", engineapi.RuleStatusFail)