mirror of
https://github.com/kyverno/kyverno.git
synced 2025-03-28 10:28:36 +00:00
refactor: introduce engine handler (#6680)
* refactor: introduce engine handler Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com> * clean Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com> --------- Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com> Co-authored-by: shuting <shuting@nirmata.com>
This commit is contained in:
parent
028bf61e06
commit
873ea5c564
13 changed files with 493 additions and 455 deletions
|
@ -9,6 +9,8 @@ import (
|
|||
"github.com/kyverno/kyverno/pkg/config"
|
||||
engineapi "github.com/kyverno/kyverno/pkg/engine/api"
|
||||
enginecontext "github.com/kyverno/kyverno/pkg/engine/context"
|
||||
"github.com/kyverno/kyverno/pkg/engine/handlers"
|
||||
"github.com/kyverno/kyverno/pkg/engine/handlers/manifest"
|
||||
"github.com/kyverno/kyverno/pkg/engine/internal"
|
||||
"github.com/kyverno/kyverno/pkg/logging"
|
||||
"github.com/kyverno/kyverno/pkg/registryclient"
|
||||
|
@ -20,6 +22,7 @@ type engine struct {
|
|||
rclient registryclient.Client
|
||||
contextLoader engineapi.ContextLoaderFactory
|
||||
exceptionSelector engineapi.PolicyExceptionSelector
|
||||
manifestHandler handlers.Handler
|
||||
}
|
||||
|
||||
func NewEngine(
|
||||
|
@ -35,6 +38,7 @@ func NewEngine(
|
|||
rclient: rclient,
|
||||
contextLoader: contextLoader,
|
||||
exceptionSelector: exceptionSelector,
|
||||
manifestHandler: manifest.NewHandler(client),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
18
pkg/engine/handlers/handler.go
Normal file
18
pkg/engine/handlers/handler.go
Normal file
|
@ -0,0 +1,18 @@
|
|||
package handlers
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/go-logr/logr"
|
||||
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
|
||||
engineapi "github.com/kyverno/kyverno/pkg/engine/api"
|
||||
)
|
||||
|
||||
type Handler interface {
|
||||
Process(
|
||||
context.Context,
|
||||
logr.Logger,
|
||||
engineapi.PolicyContext,
|
||||
kyvernov1.Rule,
|
||||
) *engineapi.RuleResponse
|
||||
}
|
|
@ -1,10 +1,9 @@
|
|||
package engine
|
||||
package manifest
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/rand"
|
||||
"crypto/x509"
|
||||
_ "embed"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"math"
|
||||
|
@ -20,7 +19,10 @@ import (
|
|||
"github.com/kyverno/kyverno/pkg/clients/dclient"
|
||||
"github.com/kyverno/kyverno/pkg/config"
|
||||
engineapi "github.com/kyverno/kyverno/pkg/engine/api"
|
||||
"github.com/kyverno/kyverno/pkg/engine/handlers"
|
||||
"github.com/kyverno/kyverno/pkg/engine/internal"
|
||||
engineresources "github.com/kyverno/kyverno/pkg/engine/resources"
|
||||
engineutils "github.com/kyverno/kyverno/pkg/engine/utils"
|
||||
"github.com/sigstore/k8s-manifest-sigstore/pkg/k8smanifest"
|
||||
"go.uber.org/multierr"
|
||||
admissionv1 "k8s.io/api/admission/v1"
|
||||
|
@ -32,45 +34,42 @@ const (
|
|||
CosignEnvVariable = "COSIGN_EXPERIMENTAL"
|
||||
)
|
||||
|
||||
//go:embed resources/default-config.yaml
|
||||
var defaultConfigBytes []byte
|
||||
|
||||
func processYAMLValidationRule(
|
||||
client dclient.Interface,
|
||||
log logr.Logger,
|
||||
ctx engineapi.PolicyContext,
|
||||
rule *kyvernov1.Rule,
|
||||
) *engineapi.RuleResponse {
|
||||
if isDeleteRequest(ctx) {
|
||||
return nil
|
||||
}
|
||||
ruleResp := handleVerifyManifest(client, ctx, rule, log)
|
||||
return ruleResp
|
||||
type handler struct {
|
||||
client dclient.Interface
|
||||
}
|
||||
|
||||
func handleVerifyManifest(
|
||||
client dclient.Interface,
|
||||
ctx engineapi.PolicyContext,
|
||||
rule *kyvernov1.Rule,
|
||||
func NewHandler(client dclient.Interface) handlers.Handler {
|
||||
return handler{
|
||||
client: client,
|
||||
}
|
||||
}
|
||||
|
||||
func (h handler) Process(
|
||||
ctx context.Context,
|
||||
logger logr.Logger,
|
||||
policyContext engineapi.PolicyContext,
|
||||
rule kyvernov1.Rule,
|
||||
) *engineapi.RuleResponse {
|
||||
verified, reason, err := verifyManifest(client, ctx, *rule.Validation.Manifests, logger)
|
||||
if engineutils.IsDeleteRequest(policyContext) {
|
||||
return nil
|
||||
}
|
||||
verified, reason, err := h.verifyManifest(ctx, logger, policyContext, *rule.Validation.Manifests)
|
||||
if err != nil {
|
||||
logger.V(3).Info("verifyManifest return err", "error", err.Error())
|
||||
return internal.RuleError(rule, engineapi.Validation, "error occurred during manifest verification", err)
|
||||
return internal.RuleError(&rule, engineapi.Validation, "error occurred during manifest verification", err)
|
||||
}
|
||||
logger.V(3).Info("verifyManifest result", "verified", strconv.FormatBool(verified), "reason", reason)
|
||||
if !verified {
|
||||
return internal.RuleResponse(*rule, engineapi.Validation, reason, engineapi.RuleStatusFail)
|
||||
return internal.RuleResponse(rule, engineapi.Validation, reason, engineapi.RuleStatusFail)
|
||||
}
|
||||
return internal.RulePass(rule, engineapi.Validation, reason)
|
||||
return internal.RulePass(&rule, engineapi.Validation, reason)
|
||||
}
|
||||
|
||||
func verifyManifest(
|
||||
client dclient.Interface,
|
||||
func (h handler) verifyManifest(
|
||||
ctx context.Context,
|
||||
logger logr.Logger,
|
||||
policyContext engineapi.PolicyContext,
|
||||
verifyRule kyvernov1.Manifests,
|
||||
logger logr.Logger,
|
||||
) (bool, string, error) {
|
||||
// load AdmissionRequest
|
||||
request, err := policyContext.JSONContext().Query("request")
|
||||
|
@ -121,7 +120,7 @@ func verifyManifest(
|
|||
}
|
||||
if !vo.DisableDryRun {
|
||||
// check if kyverno can 'create' dryrun resource
|
||||
ok, err := checkDryRunPermission(client, adreq.Kind.Kind, vo.DryRunNamespace)
|
||||
ok, err := h.checkDryRunPermission(ctx, adreq.Kind.Kind, vo.DryRunNamespace)
|
||||
if err != nil {
|
||||
logger.V(1).Info("failed to check permissions to 'create' resource. disabled DryRun option.", "dryrun namespace", vo.DryRunNamespace, "kind", adreq.Kind.Kind, "error", err.Error())
|
||||
vo.DisableDryRun = true
|
||||
|
@ -167,6 +166,15 @@ func verifyManifest(
|
|||
return true, msg, nil
|
||||
}
|
||||
|
||||
func (h handler) checkDryRunPermission(ctx context.Context, kind, namespace string) (bool, error) {
|
||||
canI := auth.NewCanI(h.client.Discovery(), h.client.GetKubeClient().AuthorizationV1().SelfSubjectAccessReviews(), kind, namespace, "create", "")
|
||||
ok, err := canI.RunAccessCheck(ctx)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return ok, nil
|
||||
}
|
||||
|
||||
func verifyManifestAttestorSet(resource unstructured.Unstructured, attestorSet kyvernov1.AttestorSet, vo *k8smanifest.VerifyResourceOption, path string, uid string, logger logr.Logger) (bool, string, error) {
|
||||
verifiedCount := 0
|
||||
attestorSet = internal.ExpandStaticKeys(attestorSet)
|
||||
|
@ -382,7 +390,7 @@ func addConfig(vo, defaultConfig *k8smanifest.VerifyResourceOption) *k8smanifest
|
|||
|
||||
func loadDefaultConfig() *k8smanifest.VerifyResourceOption {
|
||||
var defaultConfig *k8smanifest.VerifyResourceOption
|
||||
err := yaml.Unmarshal(defaultConfigBytes, &defaultConfig)
|
||||
err := yaml.Unmarshal(engineresources.DefaultConfigBytes, &defaultConfig)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
@ -413,20 +421,7 @@ func checkManifestAnnotations(mnfstAnnotations map[string]string, annotations ma
|
|||
return nil
|
||||
}
|
||||
|
||||
func checkDryRunPermission(dclient dclient.Interface, kind, namespace string) (bool, error) {
|
||||
canI := auth.NewCanI(dclient.Discovery(), dclient.GetKubeClient().AuthorizationV1().SelfSubjectAccessReviews(), kind, namespace, "create", "")
|
||||
ok, err := canI.RunAccessCheck(context.TODO())
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return ok, nil
|
||||
}
|
||||
|
||||
func checkDryRunNamespace(namespace string) bool {
|
||||
// should not use kyverno namespace for dryrun
|
||||
if namespace != config.KyvernoNamespace() {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
return namespace != config.KyvernoNamespace()
|
||||
}
|
|
@ -1,11 +1,17 @@
|
|||
package engine
|
||||
package manifest
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"testing"
|
||||
|
||||
"github.com/go-logr/logr"
|
||||
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
|
||||
"github.com/kyverno/kyverno/pkg/config"
|
||||
engineapi "github.com/kyverno/kyverno/pkg/engine/api"
|
||||
enginecontext "github.com/kyverno/kyverno/pkg/engine/context"
|
||||
"github.com/kyverno/kyverno/pkg/engine/policycontext"
|
||||
kubeutils "github.com/kyverno/kyverno/pkg/utils/kube"
|
||||
"gotest.tools/assert"
|
||||
v1 "k8s.io/api/admission/v1"
|
||||
apiextv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
|
||||
|
@ -611,12 +617,17 @@ FdGxexVrR4YqO1pRViKxmD9oMu4I7K/4sM51nbH65ycB2uRiDfIdRoV/+A==
|
|||
-----END PUBLIC KEY-----
|
||||
`
|
||||
|
||||
var (
|
||||
h = handler{}
|
||||
cfg = config.NewDefaultConfiguration()
|
||||
)
|
||||
|
||||
func Test_VerifyManifest_SignedYAML(t *testing.T) {
|
||||
policyContext := buildContext(t, test_policy, signed_resource, "")
|
||||
var request *v1.AdmissionRequest
|
||||
_ = json.Unmarshal([]byte(signed_adreq), &request)
|
||||
policyContext.jsonContext.AddRequest(request)
|
||||
policyContext.policy.SetName("test-policy")
|
||||
policyContext.JSONContext().AddRequest(request)
|
||||
policyContext.Policy().SetName("test-policy")
|
||||
verifyRule := kyvernov1.Manifests{}
|
||||
verifyRule.Attestors = append(verifyRule.Attestors, kyvernov1.AttestorSet{
|
||||
Entries: []kyvernov1.Attestor{
|
||||
|
@ -628,7 +639,7 @@ func Test_VerifyManifest_SignedYAML(t *testing.T) {
|
|||
},
|
||||
})
|
||||
logger := logr.Discard()
|
||||
verified, _, err := verifyManifest(nil, policyContext, verifyRule, logger)
|
||||
verified, _, err := h.verifyManifest(context.TODO(), logger, policyContext, verifyRule)
|
||||
assert.NilError(t, err)
|
||||
assert.Equal(t, verified, true)
|
||||
}
|
||||
|
@ -637,8 +648,8 @@ func Test_VerifyManifest_UnsignedYAML(t *testing.T) {
|
|||
policyContext := buildContext(t, test_policy, unsigned_resource, "")
|
||||
var request *v1.AdmissionRequest
|
||||
_ = json.Unmarshal([]byte(unsigned_adreq), &request)
|
||||
policyContext.jsonContext.AddRequest(request)
|
||||
policyContext.policy.SetName("test-policy")
|
||||
policyContext.JSONContext().AddRequest(request)
|
||||
policyContext.Policy().SetName("test-policy")
|
||||
verifyRule := kyvernov1.Manifests{}
|
||||
verifyRule.Attestors = append(verifyRule.Attestors, kyvernov1.AttestorSet{
|
||||
Entries: []kyvernov1.Attestor{
|
||||
|
@ -650,7 +661,7 @@ func Test_VerifyManifest_UnsignedYAML(t *testing.T) {
|
|||
},
|
||||
})
|
||||
logger := logr.Discard()
|
||||
verified, _, err := verifyManifest(nil, policyContext, verifyRule, logger)
|
||||
verified, _, err := h.verifyManifest(context.TODO(), logger, policyContext, verifyRule)
|
||||
assert.NilError(t, err)
|
||||
assert.Equal(t, verified, false)
|
||||
}
|
||||
|
@ -659,8 +670,8 @@ func Test_VerifyManifest_InvalidYAML(t *testing.T) {
|
|||
policyContext := buildContext(t, test_policy, invalid_resource, "")
|
||||
var request *v1.AdmissionRequest
|
||||
_ = json.Unmarshal([]byte(invalid_adreq), &request)
|
||||
policyContext.jsonContext.AddRequest(request)
|
||||
policyContext.policy.SetName("test-policy")
|
||||
policyContext.JSONContext().AddRequest(request)
|
||||
policyContext.Policy().SetName("test-policy")
|
||||
verifyRule := kyvernov1.Manifests{}
|
||||
verifyRule.Attestors = append(verifyRule.Attestors, kyvernov1.AttestorSet{
|
||||
Entries: []kyvernov1.Attestor{
|
||||
|
@ -672,7 +683,7 @@ func Test_VerifyManifest_InvalidYAML(t *testing.T) {
|
|||
},
|
||||
})
|
||||
logger := logr.Discard()
|
||||
verified, _, err := verifyManifest(nil, policyContext, verifyRule, logger)
|
||||
verified, _, err := h.verifyManifest(context.TODO(), logger, policyContext, verifyRule)
|
||||
assert.NilError(t, err)
|
||||
assert.Equal(t, verified, false)
|
||||
}
|
||||
|
@ -681,8 +692,8 @@ func Test_VerifyManifest_MustAll_InvalidYAML(t *testing.T) {
|
|||
policyContext := buildContext(t, test_policy, multi_sig_resource, "")
|
||||
var request *v1.AdmissionRequest
|
||||
_ = json.Unmarshal([]byte(multi_sig_adreq), &request)
|
||||
policyContext.jsonContext.AddRequest(request)
|
||||
policyContext.policy.SetName("test-policy")
|
||||
policyContext.JSONContext().AddRequest(request)
|
||||
policyContext.Policy().SetName("test-policy")
|
||||
verifyRule := kyvernov1.Manifests{}
|
||||
verifyRule.Attestors = append(verifyRule.Attestors, kyvernov1.AttestorSet{
|
||||
Entries: []kyvernov1.Attestor{
|
||||
|
@ -699,7 +710,7 @@ func Test_VerifyManifest_MustAll_InvalidYAML(t *testing.T) {
|
|||
},
|
||||
})
|
||||
logger := logr.Discard()
|
||||
verified, _, err := verifyManifest(nil, policyContext, verifyRule, logger)
|
||||
verified, _, err := h.verifyManifest(context.TODO(), logger, policyContext, verifyRule)
|
||||
errMsg := `.attestors[0].entries[1].keys: failed to verify signature: verification failed for 1 signature. all trials: ["[publickey 1/1] [signature 1/1] error: cosign.VerifyBlobCmd() returned an error: invalid signature when validating ASN.1 encoded signature"]`
|
||||
assert.Error(t, err, errMsg)
|
||||
assert.Equal(t, verified, false)
|
||||
|
@ -709,8 +720,8 @@ func Test_VerifyManifest_MustAll_ValidYAML(t *testing.T) {
|
|||
policyContext := buildContext(t, test_policy, multi_sig2_resource, "")
|
||||
var request *v1.AdmissionRequest
|
||||
_ = json.Unmarshal([]byte(multi_sig2_adreq), &request)
|
||||
policyContext.jsonContext.AddRequest(request)
|
||||
policyContext.policy.SetName("test-policy")
|
||||
policyContext.JSONContext().AddRequest(request)
|
||||
policyContext.Policy().SetName("test-policy")
|
||||
verifyRule := kyvernov1.Manifests{}
|
||||
count := 3
|
||||
verifyRule.Attestors = append(verifyRule.Attestors, kyvernov1.AttestorSet{
|
||||
|
@ -732,7 +743,7 @@ func Test_VerifyManifest_MustAll_ValidYAML(t *testing.T) {
|
|||
},
|
||||
})
|
||||
logger := logr.Discard()
|
||||
verified, _, err := verifyManifest(nil, policyContext, verifyRule, logger)
|
||||
verified, _, err := h.verifyManifest(context.TODO(), logger, policyContext, verifyRule)
|
||||
assert.NilError(t, err)
|
||||
assert.Equal(t, verified, true)
|
||||
}
|
||||
|
@ -741,8 +752,8 @@ func Test_VerifyManifest_AtLeastOne(t *testing.T) {
|
|||
policyContext := buildContext(t, test_policy, multi_sig_resource, "")
|
||||
var request *v1.AdmissionRequest
|
||||
_ = json.Unmarshal([]byte(multi_sig_adreq), &request)
|
||||
policyContext.jsonContext.AddRequest(request)
|
||||
policyContext.policy.SetName("test-policy")
|
||||
policyContext.JSONContext().AddRequest(request)
|
||||
policyContext.Policy().SetName("test-policy")
|
||||
verifyRule := kyvernov1.Manifests{}
|
||||
count := 1
|
||||
verifyRule.Attestors = append(verifyRule.Attestors, kyvernov1.AttestorSet{
|
||||
|
@ -761,7 +772,41 @@ func Test_VerifyManifest_AtLeastOne(t *testing.T) {
|
|||
},
|
||||
})
|
||||
logger := logr.Discard()
|
||||
verified, _, err := verifyManifest(nil, policyContext, verifyRule, logger)
|
||||
verified, _, err := h.verifyManifest(context.TODO(), logger, policyContext, verifyRule)
|
||||
assert.NilError(t, err)
|
||||
assert.Equal(t, verified, true)
|
||||
}
|
||||
|
||||
func buildContext(t *testing.T, policy, resource string, oldResource string) engineapi.PolicyContext {
|
||||
var cpol kyvernov1.ClusterPolicy
|
||||
err := json.Unmarshal([]byte(policy), &cpol)
|
||||
assert.NilError(t, err)
|
||||
|
||||
resourceUnstructured, err := kubeutils.BytesToUnstructured([]byte(resource))
|
||||
assert.NilError(t, err)
|
||||
|
||||
ctx := enginecontext.NewContext()
|
||||
err = enginecontext.AddResource(ctx, []byte(resource))
|
||||
assert.NilError(t, err)
|
||||
|
||||
policyContext := policycontext.NewPolicyContextWithJsonContext(ctx).
|
||||
WithPolicy(&cpol).
|
||||
WithNewResource(*resourceUnstructured)
|
||||
|
||||
if oldResource != "" {
|
||||
oldResourceUnstructured, err := kubeutils.BytesToUnstructured([]byte(oldResource))
|
||||
assert.NilError(t, err)
|
||||
|
||||
err = enginecontext.AddOldResource(ctx, []byte(oldResource))
|
||||
assert.NilError(t, err)
|
||||
|
||||
policyContext = policyContext.WithOldResource(*oldResourceUnstructured)
|
||||
}
|
||||
|
||||
if err := ctx.AddImageInfos(resourceUnstructured, cfg); err != nil {
|
||||
t.Errorf("unable to add image info to variables context: %v", err)
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
return policyContext
|
||||
}
|
|
@ -9,6 +9,7 @@ import (
|
|||
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
|
||||
engineapi "github.com/kyverno/kyverno/pkg/engine/api"
|
||||
"github.com/kyverno/kyverno/pkg/engine/internal"
|
||||
engineutils "github.com/kyverno/kyverno/pkg/engine/utils"
|
||||
apiutils "github.com/kyverno/kyverno/pkg/utils/api"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
)
|
||||
|
@ -19,7 +20,7 @@ func (e *engine) processImageValidationRule(
|
|||
enginectx engineapi.PolicyContext,
|
||||
rule *kyvernov1.Rule,
|
||||
) *engineapi.RuleResponse {
|
||||
if isDeleteRequest(enginectx) {
|
||||
if engineutils.IsDeleteRequest(enginectx) {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
@ -15,6 +15,7 @@ import (
|
|||
enginecontext "github.com/kyverno/kyverno/pkg/engine/context"
|
||||
"github.com/kyverno/kyverno/pkg/engine/context/resolvers"
|
||||
"github.com/kyverno/kyverno/pkg/engine/internal"
|
||||
"github.com/kyverno/kyverno/pkg/engine/policycontext"
|
||||
"github.com/kyverno/kyverno/pkg/engine/utils"
|
||||
"github.com/kyverno/kyverno/pkg/registryclient"
|
||||
kubeutils "github.com/kyverno/kyverno/pkg/utils/kube"
|
||||
|
@ -217,11 +218,9 @@ func buildContext(t *testing.T, policy, resource string, oldResource string) *Po
|
|||
err = enginecontext.AddResource(ctx, []byte(resource))
|
||||
assert.NilError(t, err)
|
||||
|
||||
policyContext := &PolicyContext{
|
||||
policy: &cpol,
|
||||
jsonContext: ctx,
|
||||
newResource: *resourceUnstructured,
|
||||
}
|
||||
policyContext := policycontext.NewPolicyContextWithJsonContext(ctx).
|
||||
WithPolicy(&cpol).
|
||||
WithNewResource(*resourceUnstructured)
|
||||
|
||||
if oldResource != "" {
|
||||
oldResourceUnstructured, err := kubeutils.BytesToUnstructured([]byte(oldResource))
|
||||
|
@ -230,7 +229,7 @@ func buildContext(t *testing.T, policy, resource string, oldResource string) *Po
|
|||
err = enginecontext.AddOldResource(ctx, []byte(oldResource))
|
||||
assert.NilError(t, err)
|
||||
|
||||
policyContext.oldResource = *oldResourceUnstructured
|
||||
policyContext = policyContext.WithOldResource(*oldResourceUnstructured)
|
||||
}
|
||||
|
||||
if err := ctx.AddImageInfos(resourceUnstructured, cfg); err != nil {
|
||||
|
@ -467,7 +466,7 @@ func Test_ConfigMapMissingFailure(t *testing.T) {
|
|||
|
||||
func Test_SignatureGoodSigned(t *testing.T) {
|
||||
policyContext := buildContext(t, testSampleSingleKeyPolicy, testSampleResource, "")
|
||||
policyContext.policy.GetSpec().Rules[0].VerifyImages[0].MutateDigest = true
|
||||
policyContext.Policy().GetSpec().Rules[0].VerifyImages[0].MutateDigest = true
|
||||
cosign.ClearMock()
|
||||
engineResp, _ := testVerifyAndPatchImages(context.TODO(), registryclient.NewOrDie(), nil, policyContext, cfg)
|
||||
assert.Equal(t, len(engineResp.PolicyResponse.Rules), 1)
|
||||
|
@ -543,7 +542,7 @@ func Test_RuleSelectorImageVerify(t *testing.T) {
|
|||
|
||||
policyContext := buildContext(t, testSampleSingleKeyPolicy, testSampleResource, "")
|
||||
rule := newStaticKeyRule("match-all", "*", testOtherKey)
|
||||
spec := policyContext.policy.GetSpec()
|
||||
spec := policyContext.Policy().GetSpec()
|
||||
spec.Rules = append(spec.Rules, *rule)
|
||||
|
||||
applyAll := kyverno.ApplyAll
|
||||
|
|
|
@ -113,11 +113,11 @@ func Test_VariableSubstitutionPatchStrategicMerge(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
policyContext := &PolicyContext{
|
||||
policy: &policy,
|
||||
jsonContext: ctx,
|
||||
newResource: *resourceUnstructured,
|
||||
}
|
||||
|
||||
policyContext := NewPolicyContextWithJsonContext(ctx).
|
||||
WithPolicy(&policy).
|
||||
WithNewResource(*resourceUnstructured)
|
||||
|
||||
er := testMutate(context.TODO(), nil, registryclient.NewOrDie(), policyContext, nil)
|
||||
t.Log(string(expectedPatch))
|
||||
|
||||
|
@ -187,11 +187,10 @@ func Test_variableSubstitutionPathNotExist(t *testing.T) {
|
|||
err = enginecontext.AddResource(ctx, resourceRaw)
|
||||
assert.NilError(t, err)
|
||||
|
||||
policyContext := &PolicyContext{
|
||||
policy: &policy,
|
||||
jsonContext: ctx,
|
||||
newResource: *resourceUnstructured,
|
||||
}
|
||||
policyContext := NewPolicyContextWithJsonContext(ctx).
|
||||
WithPolicy(&policy).
|
||||
WithNewResource(*resourceUnstructured)
|
||||
|
||||
er := testMutate(context.TODO(), nil, registryclient.NewOrDie(), policyContext, nil)
|
||||
assert.Equal(t, len(er.PolicyResponse.Rules), 1)
|
||||
assert.Assert(t, strings.Contains(er.PolicyResponse.Rules[0].Message, "Unknown key \"name1\" in path"))
|
||||
|
@ -265,11 +264,9 @@ func Test_variableSubstitutionCLI(t *testing.T) {
|
|||
err = enginecontext.AddResource(ctx, resourceRaw)
|
||||
assert.NilError(t, err)
|
||||
|
||||
policyContext := &PolicyContext{
|
||||
policy: &policy,
|
||||
jsonContext: ctx,
|
||||
newResource: *resourceUnstructured,
|
||||
}
|
||||
policyContext := NewPolicyContextWithJsonContext(ctx).
|
||||
WithPolicy(&policy).
|
||||
WithNewResource(*resourceUnstructured)
|
||||
|
||||
er := testMutate(
|
||||
context.TODO(),
|
||||
|
@ -387,11 +384,9 @@ func Test_chained_rules(t *testing.T) {
|
|||
err = ctx.AddResource(resource.Object)
|
||||
assert.NilError(t, err)
|
||||
|
||||
policyContext := &PolicyContext{
|
||||
policy: &policy,
|
||||
jsonContext: ctx,
|
||||
newResource: *resource,
|
||||
}
|
||||
policyContext := NewPolicyContextWithJsonContext(ctx).
|
||||
WithPolicy(&policy).
|
||||
WithNewResource(*resource)
|
||||
|
||||
err = ctx.AddImageInfos(resource, cfg)
|
||||
assert.NilError(t, err)
|
||||
|
@ -477,11 +472,9 @@ func Test_precondition(t *testing.T) {
|
|||
err = enginecontext.AddResource(ctx, resourceRaw)
|
||||
assert.NilError(t, err)
|
||||
|
||||
policyContext := &PolicyContext{
|
||||
policy: &policy,
|
||||
jsonContext: ctx,
|
||||
newResource: *resourceUnstructured,
|
||||
}
|
||||
policyContext := NewPolicyContextWithJsonContext(ctx).
|
||||
WithPolicy(&policy).
|
||||
WithNewResource(*resourceUnstructured)
|
||||
|
||||
er := testMutate(context.TODO(), nil, registryclient.NewOrDie(), policyContext, enginetest.ContextLoaderFactory(nil, nil))
|
||||
t.Log(string(expectedPatch))
|
||||
|
@ -573,11 +566,9 @@ func Test_nonZeroIndexNumberPatchesJson6902(t *testing.T) {
|
|||
err = enginecontext.AddResource(ctx, resourceRaw)
|
||||
assert.NilError(t, err)
|
||||
|
||||
policyContext := &PolicyContext{
|
||||
policy: &policy,
|
||||
jsonContext: ctx,
|
||||
newResource: *resourceUnstructured,
|
||||
}
|
||||
policyContext := NewPolicyContextWithJsonContext(ctx).
|
||||
WithPolicy(&policy).
|
||||
WithNewResource(*resourceUnstructured)
|
||||
|
||||
er := testMutate(context.TODO(), nil, registryclient.NewOrDie(), policyContext, enginetest.ContextLoaderFactory(nil, nil))
|
||||
t.Log(string(expectedPatch))
|
||||
|
@ -661,11 +652,9 @@ func Test_foreach(t *testing.T) {
|
|||
err = ctx.AddResource(resource.Object)
|
||||
assert.NilError(t, err)
|
||||
|
||||
policyContext := &PolicyContext{
|
||||
policy: &policy,
|
||||
jsonContext: ctx,
|
||||
newResource: *resource,
|
||||
}
|
||||
policyContext := NewPolicyContextWithJsonContext(ctx).
|
||||
WithPolicy(&policy).
|
||||
WithNewResource(*resource)
|
||||
|
||||
err = ctx.AddImageInfos(resource, cfg)
|
||||
assert.NilError(t, err)
|
||||
|
@ -765,11 +754,9 @@ func Test_foreach_element_mutation(t *testing.T) {
|
|||
err = ctx.AddResource(resource.Object)
|
||||
assert.NilError(t, err)
|
||||
|
||||
policyContext := &PolicyContext{
|
||||
policy: &policy,
|
||||
jsonContext: ctx,
|
||||
newResource: *resource,
|
||||
}
|
||||
policyContext := NewPolicyContextWithJsonContext(ctx).
|
||||
WithPolicy(&policy).
|
||||
WithNewResource(*resource)
|
||||
|
||||
err = ctx.AddImageInfos(resource, cfg)
|
||||
assert.NilError(t, err)
|
||||
|
@ -888,11 +875,9 @@ func Test_Container_InitContainer_foreach(t *testing.T) {
|
|||
err = ctx.AddResource(resource.Object)
|
||||
assert.NilError(t, err)
|
||||
|
||||
policyContext := &PolicyContext{
|
||||
policy: &policy,
|
||||
jsonContext: ctx,
|
||||
newResource: *resource,
|
||||
}
|
||||
policyContext := NewPolicyContextWithJsonContext(ctx).
|
||||
WithPolicy(&policy).
|
||||
WithNewResource(*resource)
|
||||
|
||||
err = ctx.AddImageInfos(resource, cfg)
|
||||
assert.NilError(t, err)
|
||||
|
@ -1035,11 +1020,9 @@ func testApplyPolicyToResource(t *testing.T, policyRaw, resourceRaw []byte) engi
|
|||
err = ctx.AddResource(resource.Object)
|
||||
assert.NilError(t, err)
|
||||
|
||||
policyContext := &PolicyContext{
|
||||
policy: &policy,
|
||||
jsonContext: ctx,
|
||||
newResource: *resource,
|
||||
}
|
||||
policyContext := NewPolicyContextWithJsonContext(ctx).
|
||||
WithPolicy(&policy).
|
||||
WithNewResource(*resource)
|
||||
|
||||
err = ctx.AddImageInfos(resource, cfg)
|
||||
assert.NilError(t, err)
|
||||
|
@ -1588,11 +1571,9 @@ func Test_mutate_existing_resources(t *testing.T) {
|
|||
_, err = dclient.GetResource(context.TODO(), target.GetAPIVersion(), target.GetKind(), target.GetNamespace(), target.GetName())
|
||||
assert.NilError(t, err)
|
||||
|
||||
policyContext = &PolicyContext{
|
||||
policy: &policy,
|
||||
jsonContext: ctx,
|
||||
newResource: *trigger,
|
||||
}
|
||||
policyContext = NewPolicyContextWithJsonContext(ctx).
|
||||
WithPolicy(&policy).
|
||||
WithNewResource(*trigger)
|
||||
|
||||
er := testMutate(context.TODO(), dclient, registryclient.NewOrDie(), policyContext, nil)
|
||||
|
||||
|
@ -1697,11 +1678,9 @@ func Test_RuleSelectorMutate(t *testing.T) {
|
|||
_, err = ctx.Query("request.object.metadata.name")
|
||||
assert.NilError(t, err)
|
||||
|
||||
policyContext := &PolicyContext{
|
||||
policy: &policy,
|
||||
jsonContext: ctx,
|
||||
newResource: *resourceUnstructured,
|
||||
}
|
||||
policyContext := NewPolicyContextWithJsonContext(ctx).
|
||||
WithPolicy(&policy).
|
||||
WithNewResource(*resourceUnstructured)
|
||||
|
||||
er := testMutate(context.TODO(), nil, registryclient.NewOrDie(), policyContext, nil)
|
||||
assert.Equal(t, len(er.PolicyResponse.Rules), 2)
|
||||
|
@ -1716,7 +1695,7 @@ func Test_RuleSelectorMutate(t *testing.T) {
|
|||
}
|
||||
|
||||
applyOne := kyverno.ApplyOne
|
||||
policyContext.policy.GetSpec().ApplyRules = &applyOne
|
||||
policyContext.Policy().GetSpec().ApplyRules = &applyOne
|
||||
|
||||
er = testMutate(context.TODO(), nil, registryclient.NewOrDie(), policyContext, nil)
|
||||
assert.Equal(t, len(er.PolicyResponse.Rules), 1)
|
||||
|
@ -2078,11 +2057,9 @@ func Test_SpecialCharacters(t *testing.T) {
|
|||
}
|
||||
|
||||
// Create policy context.
|
||||
policyContext := &PolicyContext{
|
||||
policy: &policy,
|
||||
jsonContext: ctx,
|
||||
newResource: *resource,
|
||||
}
|
||||
policyContext := NewPolicyContextWithJsonContext(ctx).
|
||||
WithPolicy(&policy).
|
||||
WithNewResource(*resource)
|
||||
|
||||
// Mutate and make sure that we got the expected amount of rules.
|
||||
patches := testMutate(context.TODO(), nil, registryclient.NewOrDie(), policyContext, nil).GetPatches()
|
||||
|
|
|
@ -1,227 +1,14 @@
|
|||
package engine
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
|
||||
kyvernov1beta1 "github.com/kyverno/kyverno/api/kyverno/v1beta1"
|
||||
"github.com/kyverno/kyverno/pkg/clients/dclient"
|
||||
"github.com/kyverno/kyverno/pkg/config"
|
||||
engineapi "github.com/kyverno/kyverno/pkg/engine/api"
|
||||
enginectx "github.com/kyverno/kyverno/pkg/engine/context"
|
||||
admissionutils "github.com/kyverno/kyverno/pkg/utils/admission"
|
||||
admissionv1 "k8s.io/api/admission/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"github.com/kyverno/kyverno/pkg/engine/policycontext"
|
||||
)
|
||||
|
||||
// PolicyContext contains the contexts for engine to process
|
||||
type PolicyContext struct {
|
||||
// policy is the policy to be processed
|
||||
policy kyvernov1.PolicyInterface
|
||||
type PolicyContext = policycontext.PolicyContext
|
||||
|
||||
// newResource is the resource to be processed
|
||||
newResource unstructured.Unstructured
|
||||
|
||||
// oldResource is the prior resource for an update, or nil
|
||||
oldResource unstructured.Unstructured
|
||||
|
||||
// element is set when the context is used for processing a foreach loop
|
||||
element unstructured.Unstructured
|
||||
|
||||
// admissionInfo contains the admission request information
|
||||
admissionInfo kyvernov1beta1.RequestInfo
|
||||
|
||||
// requestResource is GVR of the admission request
|
||||
requestResource metav1.GroupVersionResource
|
||||
|
||||
// gvk is GVK of the top level resource
|
||||
gvk schema.GroupVersionKind
|
||||
|
||||
// subresource is the subresource being requested, if any (for example, "status" or "scale")
|
||||
subresource string
|
||||
|
||||
// jsonContext is the variable context
|
||||
jsonContext enginectx.Interface
|
||||
|
||||
// namespaceLabels stores the label of namespace to be processed by namespace selector
|
||||
namespaceLabels map[string]string
|
||||
|
||||
// admissionOperation represents if the caller is from the webhook server
|
||||
admissionOperation bool
|
||||
}
|
||||
|
||||
// engineapi.PolicyContext interface
|
||||
|
||||
func (c *PolicyContext) Policy() kyvernov1.PolicyInterface {
|
||||
return c.policy
|
||||
}
|
||||
|
||||
func (c *PolicyContext) NewResource() unstructured.Unstructured {
|
||||
return c.newResource
|
||||
}
|
||||
|
||||
func (c *PolicyContext) OldResource() unstructured.Unstructured {
|
||||
return c.oldResource
|
||||
}
|
||||
|
||||
func (c *PolicyContext) RequestResource() metav1.GroupVersionResource {
|
||||
return c.requestResource
|
||||
}
|
||||
|
||||
func (c *PolicyContext) ResourceKind() (schema.GroupVersionKind, string) {
|
||||
// if the top level GVK is empty, fallback to the GVK of the resource
|
||||
if c.gvk.Empty() {
|
||||
if c.newResource.Object != nil {
|
||||
return c.newResource.GroupVersionKind(), ""
|
||||
} else {
|
||||
return c.oldResource.GroupVersionKind(), ""
|
||||
}
|
||||
}
|
||||
return c.gvk, c.subresource
|
||||
}
|
||||
|
||||
func (c *PolicyContext) AdmissionInfo() kyvernov1beta1.RequestInfo {
|
||||
return c.admissionInfo
|
||||
}
|
||||
|
||||
func (c *PolicyContext) NamespaceLabels() map[string]string {
|
||||
return c.namespaceLabels
|
||||
}
|
||||
|
||||
func (c *PolicyContext) AdmissionOperation() bool {
|
||||
return c.admissionOperation
|
||||
}
|
||||
|
||||
func (c *PolicyContext) Element() unstructured.Unstructured {
|
||||
return c.element
|
||||
}
|
||||
|
||||
func (c *PolicyContext) SetElement(element unstructured.Unstructured) {
|
||||
c.element = element
|
||||
}
|
||||
|
||||
func (c *PolicyContext) JSONContext() enginectx.Interface {
|
||||
return c.jsonContext
|
||||
}
|
||||
|
||||
func (c PolicyContext) Copy() engineapi.PolicyContext {
|
||||
return c.copy()
|
||||
}
|
||||
|
||||
// Mutators
|
||||
|
||||
func (c *PolicyContext) WithPolicy(policy kyvernov1.PolicyInterface) *PolicyContext {
|
||||
copy := c.copy()
|
||||
copy.policy = policy
|
||||
return copy
|
||||
}
|
||||
|
||||
func (c *PolicyContext) WithNamespaceLabels(namespaceLabels map[string]string) *PolicyContext {
|
||||
copy := c.copy()
|
||||
copy.namespaceLabels = namespaceLabels
|
||||
return copy
|
||||
}
|
||||
|
||||
func (c *PolicyContext) WithAdmissionInfo(admissionInfo kyvernov1beta1.RequestInfo) *PolicyContext {
|
||||
copy := c.copy()
|
||||
copy.admissionInfo = admissionInfo
|
||||
return copy
|
||||
}
|
||||
|
||||
func (c *PolicyContext) WithNewResource(resource unstructured.Unstructured) *PolicyContext {
|
||||
copy := c.copy()
|
||||
copy.newResource = resource
|
||||
return copy
|
||||
}
|
||||
|
||||
func (c *PolicyContext) WithOldResource(resource unstructured.Unstructured) *PolicyContext {
|
||||
copy := c.copy()
|
||||
copy.oldResource = resource
|
||||
return copy
|
||||
}
|
||||
|
||||
func (c *PolicyContext) WithResourceKind(gvk schema.GroupVersionKind, subresource string) *PolicyContext {
|
||||
copy := c.copy()
|
||||
copy.gvk = gvk
|
||||
copy.subresource = subresource
|
||||
return copy
|
||||
}
|
||||
|
||||
func (c *PolicyContext) WithRequestResource(gvr metav1.GroupVersionResource) *PolicyContext {
|
||||
copy := c.copy()
|
||||
copy.requestResource = gvr
|
||||
return copy
|
||||
}
|
||||
|
||||
func (c *PolicyContext) WithResources(newResource unstructured.Unstructured, oldResource unstructured.Unstructured) *PolicyContext {
|
||||
return c.WithNewResource(newResource).WithOldResource(oldResource)
|
||||
}
|
||||
|
||||
func (c *PolicyContext) withAdmissionOperation(admissionOperation bool) *PolicyContext {
|
||||
copy := c.copy()
|
||||
copy.admissionOperation = admissionOperation
|
||||
return copy
|
||||
}
|
||||
|
||||
func (c PolicyContext) copy() *PolicyContext {
|
||||
return &c
|
||||
}
|
||||
|
||||
// Constructors
|
||||
|
||||
func NewPolicyContextWithJsonContext(jsonContext enginectx.Interface) *PolicyContext {
|
||||
return &PolicyContext{
|
||||
jsonContext: jsonContext,
|
||||
}
|
||||
}
|
||||
|
||||
func NewPolicyContext() *PolicyContext {
|
||||
return NewPolicyContextWithJsonContext(enginectx.NewContext())
|
||||
}
|
||||
|
||||
func NewPolicyContextFromAdmissionRequest(
|
||||
client dclient.IDiscovery,
|
||||
request *admissionv1.AdmissionRequest,
|
||||
admissionInfo kyvernov1beta1.RequestInfo,
|
||||
configuration config.Configuration,
|
||||
) (*PolicyContext, error) {
|
||||
ctx, err := newVariablesContext(request, &admissionInfo)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create policy rule context: %w", err)
|
||||
}
|
||||
newResource, oldResource, err := admissionutils.ExtractResources(nil, request)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to parse resource: %w", err)
|
||||
}
|
||||
if err := ctx.AddImageInfos(&newResource, configuration); err != nil {
|
||||
return nil, fmt.Errorf("failed to add image information to the policy rule context: %w", err)
|
||||
}
|
||||
gvk, err := client.GetGVKFromGVR(schema.GroupVersionResource(request.Resource))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
policyContext := NewPolicyContextWithJsonContext(ctx).
|
||||
WithNewResource(newResource).
|
||||
WithOldResource(oldResource).
|
||||
WithAdmissionInfo(admissionInfo).
|
||||
withAdmissionOperation(true).
|
||||
WithResourceKind(gvk, request.SubResource).
|
||||
WithRequestResource(request.Resource)
|
||||
return policyContext, nil
|
||||
}
|
||||
|
||||
func newVariablesContext(request *admissionv1.AdmissionRequest, userRequestInfo *kyvernov1beta1.RequestInfo) (enginectx.Interface, error) {
|
||||
ctx := enginectx.NewContext()
|
||||
if err := ctx.AddRequest(request); err != nil {
|
||||
return nil, fmt.Errorf("failed to load incoming request in context: %w", err)
|
||||
}
|
||||
if err := ctx.AddUserInfo(*userRequestInfo); err != nil {
|
||||
return nil, fmt.Errorf("failed to load userInfo in context: %w", err)
|
||||
}
|
||||
if err := ctx.AddServiceAccount(userRequestInfo.AdmissionUserInfo.Username); err != nil {
|
||||
return nil, fmt.Errorf("failed to load service account in context: %w", err)
|
||||
}
|
||||
return ctx, nil
|
||||
}
|
||||
var (
|
||||
NewPolicyContextWithJsonContext = policycontext.NewPolicyContextWithJsonContext
|
||||
NewPolicyContext = policycontext.NewPolicyContext
|
||||
NewPolicyContextFromAdmissionRequest = policycontext.NewPolicyContextFromAdmissionRequest
|
||||
)
|
||||
|
|
227
pkg/engine/policycontext/policyContext.go
Normal file
227
pkg/engine/policycontext/policyContext.go
Normal file
|
@ -0,0 +1,227 @@
|
|||
package policycontext
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
|
||||
kyvernov1beta1 "github.com/kyverno/kyverno/api/kyverno/v1beta1"
|
||||
"github.com/kyverno/kyverno/pkg/clients/dclient"
|
||||
"github.com/kyverno/kyverno/pkg/config"
|
||||
engineapi "github.com/kyverno/kyverno/pkg/engine/api"
|
||||
enginectx "github.com/kyverno/kyverno/pkg/engine/context"
|
||||
admissionutils "github.com/kyverno/kyverno/pkg/utils/admission"
|
||||
admissionv1 "k8s.io/api/admission/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
)
|
||||
|
||||
// PolicyContext contains the contexts for engine to process
|
||||
type PolicyContext struct {
|
||||
// policy is the policy to be processed
|
||||
policy kyvernov1.PolicyInterface
|
||||
|
||||
// newResource is the resource to be processed
|
||||
newResource unstructured.Unstructured
|
||||
|
||||
// oldResource is the prior resource for an update, or nil
|
||||
oldResource unstructured.Unstructured
|
||||
|
||||
// element is set when the context is used for processing a foreach loop
|
||||
element unstructured.Unstructured
|
||||
|
||||
// admissionInfo contains the admission request information
|
||||
admissionInfo kyvernov1beta1.RequestInfo
|
||||
|
||||
// requestResource is GVR of the admission request
|
||||
requestResource metav1.GroupVersionResource
|
||||
|
||||
// gvk is GVK of the top level resource
|
||||
gvk schema.GroupVersionKind
|
||||
|
||||
// subresource is the subresource being requested, if any (for example, "status" or "scale")
|
||||
subresource string
|
||||
|
||||
// jsonContext is the variable context
|
||||
jsonContext enginectx.Interface
|
||||
|
||||
// namespaceLabels stores the label of namespace to be processed by namespace selector
|
||||
namespaceLabels map[string]string
|
||||
|
||||
// admissionOperation represents if the caller is from the webhook server
|
||||
admissionOperation bool
|
||||
}
|
||||
|
||||
// engineapi.PolicyContext interface
|
||||
|
||||
func (c *PolicyContext) Policy() kyvernov1.PolicyInterface {
|
||||
return c.policy
|
||||
}
|
||||
|
||||
func (c *PolicyContext) NewResource() unstructured.Unstructured {
|
||||
return c.newResource
|
||||
}
|
||||
|
||||
func (c *PolicyContext) OldResource() unstructured.Unstructured {
|
||||
return c.oldResource
|
||||
}
|
||||
|
||||
func (c *PolicyContext) RequestResource() metav1.GroupVersionResource {
|
||||
return c.requestResource
|
||||
}
|
||||
|
||||
func (c *PolicyContext) ResourceKind() (schema.GroupVersionKind, string) {
|
||||
// if the top level GVK is empty, fallback to the GVK of the resource
|
||||
if c.gvk.Empty() {
|
||||
if c.newResource.Object != nil {
|
||||
return c.newResource.GroupVersionKind(), ""
|
||||
} else {
|
||||
return c.oldResource.GroupVersionKind(), ""
|
||||
}
|
||||
}
|
||||
return c.gvk, c.subresource
|
||||
}
|
||||
|
||||
func (c *PolicyContext) AdmissionInfo() kyvernov1beta1.RequestInfo {
|
||||
return c.admissionInfo
|
||||
}
|
||||
|
||||
func (c *PolicyContext) NamespaceLabels() map[string]string {
|
||||
return c.namespaceLabels
|
||||
}
|
||||
|
||||
func (c *PolicyContext) AdmissionOperation() bool {
|
||||
return c.admissionOperation
|
||||
}
|
||||
|
||||
func (c *PolicyContext) Element() unstructured.Unstructured {
|
||||
return c.element
|
||||
}
|
||||
|
||||
func (c *PolicyContext) SetElement(element unstructured.Unstructured) {
|
||||
c.element = element
|
||||
}
|
||||
|
||||
func (c *PolicyContext) JSONContext() enginectx.Interface {
|
||||
return c.jsonContext
|
||||
}
|
||||
|
||||
func (c PolicyContext) Copy() engineapi.PolicyContext {
|
||||
return c.copy()
|
||||
}
|
||||
|
||||
// Mutators
|
||||
|
||||
func (c *PolicyContext) WithPolicy(policy kyvernov1.PolicyInterface) *PolicyContext {
|
||||
copy := c.copy()
|
||||
copy.policy = policy
|
||||
return copy
|
||||
}
|
||||
|
||||
func (c *PolicyContext) WithNamespaceLabels(namespaceLabels map[string]string) *PolicyContext {
|
||||
copy := c.copy()
|
||||
copy.namespaceLabels = namespaceLabels
|
||||
return copy
|
||||
}
|
||||
|
||||
func (c *PolicyContext) WithAdmissionInfo(admissionInfo kyvernov1beta1.RequestInfo) *PolicyContext {
|
||||
copy := c.copy()
|
||||
copy.admissionInfo = admissionInfo
|
||||
return copy
|
||||
}
|
||||
|
||||
func (c *PolicyContext) WithNewResource(resource unstructured.Unstructured) *PolicyContext {
|
||||
copy := c.copy()
|
||||
copy.newResource = resource
|
||||
return copy
|
||||
}
|
||||
|
||||
func (c *PolicyContext) WithOldResource(resource unstructured.Unstructured) *PolicyContext {
|
||||
copy := c.copy()
|
||||
copy.oldResource = resource
|
||||
return copy
|
||||
}
|
||||
|
||||
func (c *PolicyContext) WithResourceKind(gvk schema.GroupVersionKind, subresource string) *PolicyContext {
|
||||
copy := c.copy()
|
||||
copy.gvk = gvk
|
||||
copy.subresource = subresource
|
||||
return copy
|
||||
}
|
||||
|
||||
func (c *PolicyContext) WithRequestResource(gvr metav1.GroupVersionResource) *PolicyContext {
|
||||
copy := c.copy()
|
||||
copy.requestResource = gvr
|
||||
return copy
|
||||
}
|
||||
|
||||
func (c *PolicyContext) WithResources(newResource unstructured.Unstructured, oldResource unstructured.Unstructured) *PolicyContext {
|
||||
return c.WithNewResource(newResource).WithOldResource(oldResource)
|
||||
}
|
||||
|
||||
func (c *PolicyContext) withAdmissionOperation(admissionOperation bool) *PolicyContext {
|
||||
copy := c.copy()
|
||||
copy.admissionOperation = admissionOperation
|
||||
return copy
|
||||
}
|
||||
|
||||
func (c PolicyContext) copy() *PolicyContext {
|
||||
return &c
|
||||
}
|
||||
|
||||
// Constructors
|
||||
|
||||
func NewPolicyContextWithJsonContext(jsonContext enginectx.Interface) *PolicyContext {
|
||||
return &PolicyContext{
|
||||
jsonContext: jsonContext,
|
||||
}
|
||||
}
|
||||
|
||||
func NewPolicyContext() *PolicyContext {
|
||||
return NewPolicyContextWithJsonContext(enginectx.NewContext())
|
||||
}
|
||||
|
||||
func NewPolicyContextFromAdmissionRequest(
|
||||
client dclient.IDiscovery,
|
||||
request *admissionv1.AdmissionRequest,
|
||||
admissionInfo kyvernov1beta1.RequestInfo,
|
||||
configuration config.Configuration,
|
||||
) (*PolicyContext, error) {
|
||||
ctx, err := newVariablesContext(request, &admissionInfo)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create policy rule context: %w", err)
|
||||
}
|
||||
newResource, oldResource, err := admissionutils.ExtractResources(nil, request)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to parse resource: %w", err)
|
||||
}
|
||||
if err := ctx.AddImageInfos(&newResource, configuration); err != nil {
|
||||
return nil, fmt.Errorf("failed to add image information to the policy rule context: %w", err)
|
||||
}
|
||||
gvk, err := client.GetGVKFromGVR(schema.GroupVersionResource(request.Resource))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
policyContext := NewPolicyContextWithJsonContext(ctx).
|
||||
WithNewResource(newResource).
|
||||
WithOldResource(oldResource).
|
||||
WithAdmissionInfo(admissionInfo).
|
||||
withAdmissionOperation(true).
|
||||
WithResourceKind(gvk, request.SubResource).
|
||||
WithRequestResource(request.Resource)
|
||||
return policyContext, nil
|
||||
}
|
||||
|
||||
func newVariablesContext(request *admissionv1.AdmissionRequest, userRequestInfo *kyvernov1beta1.RequestInfo) (enginectx.Interface, error) {
|
||||
ctx := enginectx.NewContext()
|
||||
if err := ctx.AddRequest(request); err != nil {
|
||||
return nil, fmt.Errorf("failed to load incoming request in context: %w", err)
|
||||
}
|
||||
if err := ctx.AddUserInfo(*userRequestInfo); err != nil {
|
||||
return nil, fmt.Errorf("failed to load userInfo in context: %w", err)
|
||||
}
|
||||
if err := ctx.AddServiceAccount(userRequestInfo.AdmissionUserInfo.Username); err != nil {
|
||||
return nil, fmt.Errorf("failed to load service account in context: %w", err)
|
||||
}
|
||||
return ctx, nil
|
||||
}
|
8
pkg/engine/resources/resources.go
Normal file
8
pkg/engine/resources/resources.go
Normal file
|
@ -0,0 +1,8 @@
|
|||
package resources
|
||||
|
||||
import (
|
||||
_ "embed"
|
||||
)
|
||||
|
||||
//go:embed default-config.yaml
|
||||
var DefaultConfigBytes []byte
|
|
@ -5,12 +5,30 @@ import (
|
|||
|
||||
jsonpatch "github.com/evanphx/json-patch/v5"
|
||||
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
|
||||
engineapi "github.com/kyverno/kyverno/pkg/engine/api"
|
||||
"github.com/kyverno/kyverno/pkg/logging"
|
||||
apiutils "github.com/kyverno/kyverno/pkg/utils/api"
|
||||
jsonutils "github.com/kyverno/kyverno/pkg/utils/json"
|
||||
"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
)
|
||||
|
||||
func IsDeleteRequest(ctx engineapi.PolicyContext) bool {
|
||||
newResource := ctx.NewResource()
|
||||
// if the OldResource is not empty, and the NewResource is empty, the request is a DELETE
|
||||
return IsEmptyUnstructured(&newResource)
|
||||
}
|
||||
|
||||
func IsEmptyUnstructured(u *unstructured.Unstructured) bool {
|
||||
if u == nil {
|
||||
return true
|
||||
}
|
||||
if u.Object == nil {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// ApplyPatches patches given resource with given patches and returns patched document
|
||||
// return original resource if any error occurs
|
||||
func ApplyPatches(resource []byte, patches [][]byte) ([]byte, error) {
|
||||
|
|
|
@ -14,6 +14,7 @@ import (
|
|||
"github.com/kyverno/kyverno/pkg/config"
|
||||
engineapi "github.com/kyverno/kyverno/pkg/engine/api"
|
||||
"github.com/kyverno/kyverno/pkg/engine/internal"
|
||||
engineutils "github.com/kyverno/kyverno/pkg/engine/utils"
|
||||
"github.com/kyverno/kyverno/pkg/engine/validate"
|
||||
"github.com/kyverno/kyverno/pkg/engine/variables"
|
||||
"github.com/kyverno/kyverno/pkg/pss"
|
||||
|
@ -88,7 +89,7 @@ func (e *engine) validateResource(
|
|||
} else if hasValidateImage {
|
||||
return e.processImageValidationRule(ctx, logger, policyContext, rule)
|
||||
} else if hasYAMLSignatureVerify {
|
||||
return processYAMLValidationRule(e.client, logger, policyContext, rule)
|
||||
return e.manifestHandler.Process(ctx, logger, policyContext, *rule)
|
||||
}
|
||||
return nil
|
||||
},
|
||||
|
@ -209,7 +210,7 @@ func (v *validator) validate(ctx context.Context) *engineapi.RuleResponse {
|
|||
}
|
||||
|
||||
if v.podSecurity != nil {
|
||||
if !isDeleteRequest(v.policyContext) {
|
||||
if !engineutils.IsDeleteRequest(v.policyContext) {
|
||||
ruleResponse := v.validatePodSecurity()
|
||||
return ruleResponse
|
||||
}
|
||||
|
@ -461,10 +462,10 @@ func (v *validator) validatePodSecurity() *engineapi.RuleResponse {
|
|||
|
||||
func (v *validator) validateResourceWithRule() *engineapi.RuleResponse {
|
||||
element := v.policyContext.Element()
|
||||
if !isEmptyUnstructured(&element) {
|
||||
if !engineutils.IsEmptyUnstructured(&element) {
|
||||
return v.validatePatterns(element)
|
||||
}
|
||||
if isDeleteRequest(v.policyContext) {
|
||||
if engineutils.IsDeleteRequest(v.policyContext) {
|
||||
v.log.V(3).Info("skipping validation on deleted resource")
|
||||
return nil
|
||||
}
|
||||
|
@ -472,22 +473,6 @@ func (v *validator) validateResourceWithRule() *engineapi.RuleResponse {
|
|||
return resp
|
||||
}
|
||||
|
||||
func isDeleteRequest(ctx engineapi.PolicyContext) bool {
|
||||
newResource := ctx.NewResource()
|
||||
// if the OldResource is not empty, and the NewResource is empty, the request is a DELETE
|
||||
return isEmptyUnstructured(&newResource)
|
||||
}
|
||||
|
||||
func isEmptyUnstructured(u *unstructured.Unstructured) bool {
|
||||
if u == nil {
|
||||
return true
|
||||
}
|
||||
if u.Object == nil {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// matches checks if either the new or old resource satisfies the filter conditions defined in the rule
|
||||
func matches(
|
||||
logger logr.Logger,
|
||||
|
|
|
@ -135,7 +135,7 @@ func TestValidate_image_tag_fail(t *testing.T) {
|
|||
"validation error: imagePullPolicy 'Always' required with tag 'latest'. rule validate-latest failed at path /spec/containers/0/imagePullPolicy/",
|
||||
}
|
||||
|
||||
er := testValidate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()}, cfg, nil)
|
||||
er := testValidate(context.TODO(), registryclient.NewOrDie(), NewPolicyContextWithJsonContext(enginecontext.NewContext()).WithPolicy(&policy).WithNewResource(*resourceUnstructured), cfg, nil)
|
||||
for index, r := range er.PolicyResponse.Rules {
|
||||
assert.Equal(t, r.Message, msgs[index])
|
||||
}
|
||||
|
@ -235,7 +235,7 @@ func TestValidate_image_tag_pass(t *testing.T) {
|
|||
"validation rule 'validate-tag' passed.",
|
||||
"validation rule 'validate-latest' passed.",
|
||||
}
|
||||
er := testValidate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()}, cfg, nil)
|
||||
er := testValidate(context.TODO(), registryclient.NewOrDie(), NewPolicyContextWithJsonContext(enginecontext.NewContext()).WithPolicy(&policy).WithNewResource(*resourceUnstructured), cfg, nil)
|
||||
for index, r := range er.PolicyResponse.Rules {
|
||||
assert.Equal(t, r.Message, msgs[index])
|
||||
}
|
||||
|
@ -309,7 +309,7 @@ func TestValidate_Fail_anyPattern(t *testing.T) {
|
|||
|
||||
resourceUnstructured, err := kubeutils.BytesToUnstructured(rawResource)
|
||||
assert.NilError(t, err)
|
||||
er := testValidate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()}, cfg, nil)
|
||||
er := testValidate(context.TODO(), registryclient.NewOrDie(), NewPolicyContextWithJsonContext(enginecontext.NewContext()).WithPolicy(&policy).WithNewResource(*resourceUnstructured), cfg, nil)
|
||||
assert.Assert(t, !er.IsSuccessful())
|
||||
|
||||
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/"}
|
||||
|
@ -392,7 +392,7 @@ func TestValidate_host_network_port(t *testing.T) {
|
|||
|
||||
resourceUnstructured, err := kubeutils.BytesToUnstructured(rawResource)
|
||||
assert.NilError(t, err)
|
||||
er := testValidate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()}, cfg, nil)
|
||||
er := testValidate(context.TODO(), registryclient.NewOrDie(), NewPolicyContextWithJsonContext(enginecontext.NewContext()).WithPolicy(&policy).WithNewResource(*resourceUnstructured), cfg, nil)
|
||||
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 {
|
||||
|
@ -482,7 +482,7 @@ func TestValidate_anchor_arraymap_pass(t *testing.T) {
|
|||
|
||||
resourceUnstructured, err := kubeutils.BytesToUnstructured(rawResource)
|
||||
assert.NilError(t, err)
|
||||
er := testValidate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()}, cfg, nil)
|
||||
er := testValidate(context.TODO(), registryclient.NewOrDie(), NewPolicyContextWithJsonContext(enginecontext.NewContext()).WithPolicy(&policy).WithNewResource(*resourceUnstructured), cfg, nil)
|
||||
msgs := []string{"validation rule 'validate-host-path' passed."}
|
||||
|
||||
for index, r := range er.PolicyResponse.Rules {
|
||||
|
@ -570,7 +570,7 @@ func TestValidate_anchor_arraymap_fail(t *testing.T) {
|
|||
assert.NilError(t, err)
|
||||
resourceUnstructured, err := kubeutils.BytesToUnstructured(rawResource)
|
||||
assert.NilError(t, err)
|
||||
er := testValidate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()}, cfg, nil)
|
||||
er := testValidate(context.TODO(), registryclient.NewOrDie(), NewPolicyContextWithJsonContext(enginecontext.NewContext()).WithPolicy(&policy).WithNewResource(*resourceUnstructured), cfg, nil)
|
||||
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 {
|
||||
|
@ -640,7 +640,7 @@ func TestValidate_anchor_map_notfound(t *testing.T) {
|
|||
|
||||
resourceUnstructured, err := kubeutils.BytesToUnstructured(rawResource)
|
||||
assert.NilError(t, err)
|
||||
er := testValidate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()}, cfg, nil)
|
||||
er := testValidate(context.TODO(), registryclient.NewOrDie(), NewPolicyContextWithJsonContext(enginecontext.NewContext()).WithPolicy(&policy).WithNewResource(*resourceUnstructured), cfg, nil)
|
||||
msgs := []string{"validation rule 'pod rule 2' passed."}
|
||||
|
||||
for index, r := range er.PolicyResponse.Rules {
|
||||
|
@ -713,7 +713,7 @@ func TestValidate_anchor_map_found_valid(t *testing.T) {
|
|||
|
||||
resourceUnstructured, err := kubeutils.BytesToUnstructured(rawResource)
|
||||
assert.NilError(t, err)
|
||||
er := testValidate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()}, cfg, nil)
|
||||
er := testValidate(context.TODO(), registryclient.NewOrDie(), NewPolicyContextWithJsonContext(enginecontext.NewContext()).WithPolicy(&policy).WithNewResource(*resourceUnstructured), cfg, nil)
|
||||
msgs := []string{"validation rule 'pod rule 2' passed."}
|
||||
|
||||
for index, r := range er.PolicyResponse.Rules {
|
||||
|
@ -787,7 +787,7 @@ func TestValidate_inequality_List_Processing(t *testing.T) {
|
|||
|
||||
resourceUnstructured, err := kubeutils.BytesToUnstructured(rawResource)
|
||||
assert.NilError(t, err)
|
||||
er := testValidate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()}, cfg, nil)
|
||||
er := testValidate(context.TODO(), registryclient.NewOrDie(), NewPolicyContextWithJsonContext(enginecontext.NewContext()).WithPolicy(&policy).WithNewResource(*resourceUnstructured), cfg, nil)
|
||||
msgs := []string{"validation rule 'pod rule 2' passed."}
|
||||
|
||||
for index, r := range er.PolicyResponse.Rules {
|
||||
|
@ -867,7 +867,7 @@ func TestValidate_inequality_List_ProcessingBrackets(t *testing.T) {
|
|||
|
||||
resourceUnstructured, err := kubeutils.BytesToUnstructured(rawResource)
|
||||
assert.NilError(t, err)
|
||||
er := testValidate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()}, cfg, nil)
|
||||
er := testValidate(context.TODO(), registryclient.NewOrDie(), NewPolicyContextWithJsonContext(enginecontext.NewContext()).WithPolicy(&policy).WithNewResource(*resourceUnstructured), cfg, nil)
|
||||
msgs := []string{"validation rule 'pod rule 2' passed."}
|
||||
|
||||
for index, r := range er.PolicyResponse.Rules {
|
||||
|
@ -941,7 +941,7 @@ func TestValidate_anchor_map_found_invalid(t *testing.T) {
|
|||
|
||||
resourceUnstructured, err := kubeutils.BytesToUnstructured(rawResource)
|
||||
assert.NilError(t, err)
|
||||
er := testValidate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()}, cfg, nil)
|
||||
er := testValidate(context.TODO(), registryclient.NewOrDie(), NewPolicyContextWithJsonContext(enginecontext.NewContext()).WithPolicy(&policy).WithNewResource(*resourceUnstructured), cfg, nil)
|
||||
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 {
|
||||
|
@ -1016,7 +1016,7 @@ func TestValidate_AnchorList_pass(t *testing.T) {
|
|||
|
||||
resourceUnstructured, err := kubeutils.BytesToUnstructured(rawResource)
|
||||
assert.NilError(t, err)
|
||||
er := testValidate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()}, cfg, nil)
|
||||
er := testValidate(context.TODO(), registryclient.NewOrDie(), NewPolicyContextWithJsonContext(enginecontext.NewContext()).WithPolicy(&policy).WithNewResource(*resourceUnstructured), cfg, nil)
|
||||
msgs := []string{"validation rule 'pod image rule' passed."}
|
||||
|
||||
for index, r := range er.PolicyResponse.Rules {
|
||||
|
@ -1091,7 +1091,7 @@ func TestValidate_AnchorList_fail(t *testing.T) {
|
|||
|
||||
resourceUnstructured, err := kubeutils.BytesToUnstructured(rawResource)
|
||||
assert.NilError(t, err)
|
||||
er := testValidate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()}, cfg, nil)
|
||||
er := testValidate(context.TODO(), registryclient.NewOrDie(), NewPolicyContextWithJsonContext(enginecontext.NewContext()).WithPolicy(&policy).WithNewResource(*resourceUnstructured), cfg, nil)
|
||||
assert.Assert(t, !er.IsSuccessful())
|
||||
}
|
||||
|
||||
|
@ -1161,7 +1161,7 @@ func TestValidate_existenceAnchor_fail(t *testing.T) {
|
|||
|
||||
resourceUnstructured, err := kubeutils.BytesToUnstructured(rawResource)
|
||||
assert.NilError(t, err)
|
||||
er := testValidate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()}, cfg, nil)
|
||||
er := testValidate(context.TODO(), registryclient.NewOrDie(), NewPolicyContextWithJsonContext(enginecontext.NewContext()).WithPolicy(&policy).WithNewResource(*resourceUnstructured), cfg, nil)
|
||||
assert.Assert(t, !er.IsSuccessful())
|
||||
}
|
||||
|
||||
|
@ -1231,7 +1231,7 @@ func TestValidate_existenceAnchor_pass(t *testing.T) {
|
|||
|
||||
resourceUnstructured, err := kubeutils.BytesToUnstructured(rawResource)
|
||||
assert.NilError(t, err)
|
||||
er := testValidate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()}, cfg, nil)
|
||||
er := testValidate(context.TODO(), registryclient.NewOrDie(), NewPolicyContextWithJsonContext(enginecontext.NewContext()).WithPolicy(&policy).WithNewResource(*resourceUnstructured), cfg, nil)
|
||||
msgs := []string{"validation rule 'pod image rule' passed."}
|
||||
|
||||
for index, r := range er.PolicyResponse.Rules {
|
||||
|
@ -1319,7 +1319,7 @@ func TestValidate_negationAnchor_deny(t *testing.T) {
|
|||
|
||||
resourceUnstructured, err := kubeutils.BytesToUnstructured(rawResource)
|
||||
assert.NilError(t, err)
|
||||
er := testValidate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()}, cfg, nil)
|
||||
er := testValidate(context.TODO(), registryclient.NewOrDie(), NewPolicyContextWithJsonContext(enginecontext.NewContext()).WithPolicy(&policy).WithNewResource(*resourceUnstructured), cfg, nil)
|
||||
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 {
|
||||
|
@ -1406,7 +1406,7 @@ func TestValidate_negationAnchor_pass(t *testing.T) {
|
|||
|
||||
resourceUnstructured, err := kubeutils.BytesToUnstructured(rawResource)
|
||||
assert.NilError(t, err)
|
||||
er := testValidate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()}, cfg, nil)
|
||||
er := testValidate(context.TODO(), registryclient.NewOrDie(), NewPolicyContextWithJsonContext(enginecontext.NewContext()).WithPolicy(&policy).WithNewResource(*resourceUnstructured), cfg, nil)
|
||||
msgs := []string{"validation rule 'validate-host-path' passed."}
|
||||
|
||||
for index, r := range er.PolicyResponse.Rules {
|
||||
|
@ -1478,11 +1478,7 @@ func Test_VariableSubstitutionPathNotExistInPattern(t *testing.T) {
|
|||
err = enginecontext.AddResource(ctx, resourceRaw)
|
||||
assert.NilError(t, err)
|
||||
|
||||
policyContext := &PolicyContext{
|
||||
policy: &policy,
|
||||
jsonContext: ctx,
|
||||
newResource: *resourceUnstructured,
|
||||
}
|
||||
policyContext := NewPolicyContextWithJsonContext(ctx).WithPolicy(&policy).WithNewResource(*resourceUnstructured)
|
||||
er := testValidate(context.TODO(), registryclient.NewOrDie(), policyContext, cfg, nil)
|
||||
|
||||
assert.Equal(t, len(er.PolicyResponse.Rules), 1)
|
||||
|
@ -1572,11 +1568,7 @@ func Test_VariableSubstitutionPathNotExistInAnyPattern_OnePatternStatisfiesButSu
|
|||
err = enginecontext.AddResource(ctx, resourceRaw)
|
||||
assert.NilError(t, err)
|
||||
|
||||
policyContext := &PolicyContext{
|
||||
policy: &policy,
|
||||
jsonContext: ctx,
|
||||
newResource: *resourceUnstructured,
|
||||
}
|
||||
policyContext := NewPolicyContextWithJsonContext(ctx).WithPolicy(&policy).WithNewResource(*resourceUnstructured)
|
||||
er := testValidate(context.TODO(), registryclient.NewOrDie(), policyContext, cfg, nil)
|
||||
|
||||
assert.Equal(t, len(er.PolicyResponse.Rules), 1)
|
||||
|
@ -1634,11 +1626,7 @@ func Test_VariableSubstitution_NotOperatorWithStringVariable(t *testing.T) {
|
|||
err = enginecontext.AddResource(ctx, resourceRaw)
|
||||
assert.NilError(t, err)
|
||||
|
||||
policyContext := &PolicyContext{
|
||||
policy: &policy,
|
||||
jsonContext: ctx,
|
||||
newResource: *resourceUnstructured,
|
||||
}
|
||||
policyContext := NewPolicyContextWithJsonContext(ctx).WithPolicy(&policy).WithNewResource(*resourceUnstructured)
|
||||
er := testValidate(context.TODO(), registryclient.NewOrDie(), policyContext, cfg, nil)
|
||||
assert.Equal(t, er.PolicyResponse.Rules[0].Status, engineapi.RuleStatusFail)
|
||||
assert.Equal(t, er.PolicyResponse.Rules[0].Message, "validation error: rule not-operator-with-variable-should-alway-fail-validation failed at path /spec/content/")
|
||||
|
@ -1726,11 +1714,7 @@ func Test_VariableSubstitutionPathNotExistInAnyPattern_AllPathNotPresent(t *test
|
|||
err = enginecontext.AddResource(ctx, resourceRaw)
|
||||
assert.NilError(t, err)
|
||||
|
||||
policyContext := &PolicyContext{
|
||||
policy: &policy,
|
||||
jsonContext: ctx,
|
||||
newResource: *resourceUnstructured,
|
||||
}
|
||||
policyContext := NewPolicyContextWithJsonContext(ctx).WithPolicy(&policy).WithNewResource(*resourceUnstructured)
|
||||
er := testValidate(context.TODO(), registryclient.NewOrDie(), policyContext, cfg, nil)
|
||||
|
||||
assert.Equal(t, len(er.PolicyResponse.Rules), 1)
|
||||
|
@ -1820,11 +1804,7 @@ func Test_VariableSubstitutionPathNotExistInAnyPattern_AllPathPresent_NonePatter
|
|||
err = enginecontext.AddResource(ctx, resourceRaw)
|
||||
assert.NilError(t, err)
|
||||
|
||||
policyContext := &PolicyContext{
|
||||
policy: &policy,
|
||||
jsonContext: ctx,
|
||||
newResource: *resourceUnstructured,
|
||||
}
|
||||
policyContext := NewPolicyContextWithJsonContext(ctx).WithPolicy(&policy).WithNewResource(*resourceUnstructured)
|
||||
er := testValidate(context.TODO(), registryclient.NewOrDie(), policyContext, cfg, nil)
|
||||
|
||||
assert.Equal(t, er.PolicyResponse.Rules[0].Status, engineapi.RuleStatusFail)
|
||||
|
@ -1926,11 +1906,7 @@ func Test_VariableSubstitutionValidate_VariablesInMessageAreResolved(t *testing.
|
|||
err = enginecontext.AddResource(ctx, resourceRaw)
|
||||
assert.NilError(t, err)
|
||||
|
||||
policyContext := &PolicyContext{
|
||||
policy: &policy,
|
||||
jsonContext: ctx,
|
||||
newResource: *resourceUnstructured,
|
||||
}
|
||||
policyContext := NewPolicyContextWithJsonContext(ctx).WithPolicy(&policy).WithNewResource(*resourceUnstructured)
|
||||
er := testValidate(context.TODO(), registryclient.NewOrDie(), policyContext, cfg, nil)
|
||||
assert.Equal(t, er.PolicyResponse.Rules[0].Status, engineapi.RuleStatusFail)
|
||||
assert.Equal(t, er.PolicyResponse.Rules[0].Message, "The animal cow is not in the allowed list of animals.")
|
||||
|
@ -1980,11 +1956,7 @@ func Test_Flux_Kustomization_PathNotPresent(t *testing.T) {
|
|||
err = enginecontext.AddResource(ctx, test.resourceRaw)
|
||||
assert.NilError(t, err)
|
||||
|
||||
policyContext := &PolicyContext{
|
||||
policy: &policy,
|
||||
jsonContext: ctx,
|
||||
newResource: *resourceUnstructured,
|
||||
}
|
||||
policyContext := NewPolicyContextWithJsonContext(ctx).WithPolicy(&policy).WithNewResource(*resourceUnstructured)
|
||||
er := testValidate(context.TODO(), registryclient.NewOrDie(), policyContext, cfg, nil)
|
||||
|
||||
for i, rule := range er.PolicyResponse.Rules {
|
||||
|
@ -2143,13 +2115,11 @@ func executeTest(t *testing.T, test testCase) {
|
|||
t.Fatal(err)
|
||||
}
|
||||
|
||||
pc := &PolicyContext{
|
||||
policy: &policy,
|
||||
newResource: newR,
|
||||
oldResource: oldR,
|
||||
admissionInfo: userInfo,
|
||||
jsonContext: ctx,
|
||||
}
|
||||
pc := NewPolicyContextWithJsonContext(ctx).
|
||||
WithPolicy(&policy).
|
||||
WithNewResource(newR).
|
||||
WithOldResource(oldR).
|
||||
WithAdmissionInfo(userInfo)
|
||||
|
||||
resp := testValidate(context.TODO(), registryclient.NewOrDie(), pc, cfg, nil)
|
||||
if resp.IsSuccessful() && test.requestDenied {
|
||||
|
@ -2234,7 +2204,7 @@ func TestValidate_context_variable_substitution_CLI(t *testing.T) {
|
|||
er := testValidate(
|
||||
context.TODO(),
|
||||
registryclient.NewOrDie(),
|
||||
&PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()},
|
||||
NewPolicyContextWithJsonContext(enginecontext.NewContext()).WithPolicy(&policy).WithNewResource(*resourceUnstructured),
|
||||
cfg,
|
||||
enginetest.ContextLoaderFactory(
|
||||
nil,
|
||||
|
@ -2339,7 +2309,11 @@ func Test_EmptyStringInDenyCondition(t *testing.T) {
|
|||
resourceUnstructured, err := kubeutils.BytesToUnstructured(resourceRaw)
|
||||
assert.NilError(t, err)
|
||||
|
||||
er := testValidate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: ctx}, cfg, nil)
|
||||
er := testValidate(context.TODO(), registryclient.NewOrDie(),
|
||||
NewPolicyContextWithJsonContext(ctx).
|
||||
WithPolicy(&policy).
|
||||
WithNewResource(*resourceUnstructured),
|
||||
cfg, nil)
|
||||
assert.Assert(t, !er.IsSuccessful())
|
||||
}
|
||||
|
||||
|
@ -2428,7 +2402,11 @@ func Test_StringInDenyCondition(t *testing.T) {
|
|||
resourceUnstructured, err := kubeutils.BytesToUnstructured(resourceRaw)
|
||||
assert.NilError(t, err)
|
||||
|
||||
er := testValidate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: ctx}, cfg, nil)
|
||||
er := testValidate(context.TODO(), registryclient.NewOrDie(),
|
||||
NewPolicyContextWithJsonContext(ctx).
|
||||
WithPolicy(&policy).
|
||||
WithNewResource(*resourceUnstructured),
|
||||
cfg, nil)
|
||||
assert.Assert(t, er.IsSuccessful())
|
||||
}
|
||||
|
||||
|
@ -3104,11 +3082,9 @@ func testForEach(t *testing.T, policyraw []byte, resourceRaw []byte, msg string,
|
|||
err = enginecontext.AddResource(ctx, resourceRaw)
|
||||
assert.NilError(t, err)
|
||||
|
||||
policyContext := &PolicyContext{
|
||||
policy: &policy,
|
||||
jsonContext: ctx,
|
||||
newResource: *resourceUnstructured,
|
||||
}
|
||||
policyContext := NewPolicyContextWithJsonContext(ctx).
|
||||
WithPolicy(&policy).
|
||||
WithNewResource(*resourceUnstructured)
|
||||
er := testValidate(context.TODO(), registryclient.NewOrDie(), policyContext, cfg, contextLoader)
|
||||
|
||||
assert.Equal(t, er.PolicyResponse.Rules[0].Status, status)
|
||||
|
@ -3168,20 +3144,18 @@ func Test_delete_ignore_pattern(t *testing.T) {
|
|||
err = enginecontext.AddResource(ctx, resourceRaw)
|
||||
assert.NilError(t, err)
|
||||
|
||||
policyContextCreate := &PolicyContext{
|
||||
policy: &policy,
|
||||
jsonContext: ctx,
|
||||
newResource: *resourceUnstructured,
|
||||
}
|
||||
policyContextCreate := NewPolicyContextWithJsonContext(ctx).
|
||||
WithPolicy(&policy).
|
||||
WithNewResource(*resourceUnstructured)
|
||||
|
||||
engineResponseCreate := testValidate(context.TODO(), registryclient.NewOrDie(), policyContextCreate, cfg, nil)
|
||||
assert.Equal(t, len(engineResponseCreate.PolicyResponse.Rules), 1)
|
||||
assert.Equal(t, engineResponseCreate.PolicyResponse.Rules[0].Status, engineapi.RuleStatusFail)
|
||||
|
||||
policyContextDelete := &PolicyContext{
|
||||
policy: &policy,
|
||||
jsonContext: ctx,
|
||||
oldResource: *resourceUnstructured,
|
||||
}
|
||||
policyContextDelete := NewPolicyContextWithJsonContext(ctx).
|
||||
WithPolicy(&policy).
|
||||
WithOldResource(*resourceUnstructured)
|
||||
|
||||
engineResponseDelete := testValidate(context.TODO(), registryclient.NewOrDie(), policyContextDelete, cfg, nil)
|
||||
assert.Equal(t, len(engineResponseDelete.PolicyResponse.Rules), 0)
|
||||
}
|
||||
|
@ -3241,7 +3215,7 @@ func Test_ValidatePattern_anyPattern(t *testing.T) {
|
|||
resourceUnstructured, err := kubeutils.BytesToUnstructured(tc.rawResource)
|
||||
assert.NilError(t, err)
|
||||
|
||||
er := testValidate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()}, cfg, nil)
|
||||
er := testValidate(context.TODO(), registryclient.NewOrDie(), NewPolicyContextWithJsonContext(enginecontext.NewContext()).WithPolicy(&policy).WithNewResource(*resourceUnstructured), cfg, nil)
|
||||
if tc.expectedFailed {
|
||||
assert.Assert(t, er.IsFailed())
|
||||
} else if tc.expectedSkipped {
|
||||
|
|
Loading…
Add table
Reference in a new issue