mirror of
https://github.com/kyverno/kyverno.git
synced 2025-03-28 02:18:15 +00:00
Adding support for overriding the default registry (#4715)
Signed-off-by: Njegos Railic <railic.njegos@gmail.com> Signed-off-by: Njegos Railic <railic.njegos@gmail.com>
This commit is contained in:
parent
eabd7a238b
commit
c429f845dd
34 changed files with 421 additions and 159 deletions
|
@ -177,6 +177,8 @@ The command removes all the Kubernetes components associated with the chart and
|
|||
| generatecontrollerExtraResources | list | `[]` | Additional resources to be added to controller RBAC permissions. |
|
||||
| excludeKyvernoNamespace | bool | `true` | Exclude Kyverno namespace Determines if default Kyverno namespace exclusion is enabled for webhooks and resourceFilters |
|
||||
| resourceFiltersExcludeNamespaces | list | `[]` | resourceFilter namespace exclude Namespaces to exclude from the default resourceFilters |
|
||||
| config.defaultRegistry | string | `"docker.io"` | The registry hostname used for the image mutation. |
|
||||
| config.enableDefaultRegistryMutation | bool | `true` | Enable registry mutation for container images. Enabled by default. |
|
||||
| config.resourceFilters | list | See [values.yaml](values.yaml) | Resource types to be skipped by the Kyverno policy engine. Make sure to surround each entry in quotes so that it doesn't get parsed as a nested YAML list. These are joined together without spaces, run through `tpl`, and the result is set in the config map. |
|
||||
| config.existingConfig | string | `""` | Name of an existing config map (ignores default/provided resourceFilters) |
|
||||
| config.annotations | object | `{}` | Additional annotations to add to the configmap |
|
||||
|
|
|
@ -11,6 +11,12 @@ metadata:
|
|||
name: {{ template "kyverno.configMapName" . }}
|
||||
namespace: {{ template "kyverno.namespace" . }}
|
||||
data:
|
||||
{{- if .Values.config.defaultRegistry }}
|
||||
defaultRegistry: {{ .Values.config.defaultRegistry | quote }}
|
||||
{{- end }}
|
||||
{{- if .Values.config.enableDefaultRegistryMutation }}
|
||||
enableDefaultRegistryMutation: {{ .Values.config.enableDefaultRegistryMutation | quote }}
|
||||
{{- end }}
|
||||
# resource types to be skipped by kyverno policy engine
|
||||
{{- if .Values.config.resourceFilters }}
|
||||
resourceFilters: {{ include "kyverno.resourceFilters" . | quote }}
|
||||
|
|
|
@ -304,6 +304,12 @@ excludeKyvernoNamespace: true
|
|||
resourceFiltersExcludeNamespaces: []
|
||||
|
||||
config:
|
||||
# -- The registry hostname used for the image mutation.
|
||||
defaultRegistry: docker.io
|
||||
|
||||
# -- Enable registry mutation for container images. Enabled by default.
|
||||
enableDefaultRegistryMutation: true
|
||||
|
||||
# -- Resource types to be skipped by the Kyverno policy engine.
|
||||
# Make sure to surround each entry in quotes so that it doesn't get parsed as a nested YAML list.
|
||||
# These are joined together without spaces, run through `tpl`, and the result is set in the config map.
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
kyvernov2alpha1 "github.com/kyverno/kyverno/api/kyverno/v2alpha1"
|
||||
kyvernov2alpha1listers "github.com/kyverno/kyverno/pkg/client/listers/kyverno/v2alpha1"
|
||||
"github.com/kyverno/kyverno/pkg/clients/dclient"
|
||||
"github.com/kyverno/kyverno/pkg/config"
|
||||
enginecontext "github.com/kyverno/kyverno/pkg/engine/context"
|
||||
controllerutils "github.com/kyverno/kyverno/pkg/utils/controller"
|
||||
match "github.com/kyverno/kyverno/pkg/utils/match"
|
||||
|
@ -38,7 +39,7 @@ func New(
|
|||
}
|
||||
}
|
||||
|
||||
func (h *handlers) Cleanup(ctx context.Context, logger logr.Logger, name string, _ time.Time) error {
|
||||
func (h *handlers) Cleanup(ctx context.Context, logger logr.Logger, name string, _ time.Time, cfg config.Configuration) error {
|
||||
logger.Info("cleaning up...")
|
||||
defer logger.Info("done")
|
||||
namespace, name, err := cache.SplitMetaNamespaceKey(name)
|
||||
|
@ -49,7 +50,7 @@ func (h *handlers) Cleanup(ctx context.Context, logger logr.Logger, name string,
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return h.executePolicy(ctx, logger, policy)
|
||||
return h.executePolicy(ctx, logger, policy, cfg)
|
||||
}
|
||||
|
||||
func (h *handlers) lookupPolicy(namespace, name string) (kyvernov2alpha1.CleanupPolicyInterface, error) {
|
||||
|
@ -60,7 +61,7 @@ func (h *handlers) lookupPolicy(namespace, name string) (kyvernov2alpha1.Cleanup
|
|||
}
|
||||
}
|
||||
|
||||
func (h *handlers) executePolicy(ctx context.Context, logger logr.Logger, policy kyvernov2alpha1.CleanupPolicyInterface) error {
|
||||
func (h *handlers) executePolicy(ctx context.Context, logger logr.Logger, policy kyvernov2alpha1.CleanupPolicyInterface, cfg config.Configuration) error {
|
||||
spec := policy.GetSpec()
|
||||
kinds := sets.New(spec.MatchResources.GetKinds()...)
|
||||
debug := logger.V(5)
|
||||
|
@ -120,7 +121,7 @@ func (h *handlers) executePolicy(ctx context.Context, logger logr.Logger, policy
|
|||
errs = append(errs, err)
|
||||
continue
|
||||
}
|
||||
if err := enginectx.AddImageInfos(&resource); err != nil {
|
||||
if err := enginectx.AddImageInfos(&resource, cfg); err != nil {
|
||||
debug.Error(err, "failed to add image infos in context")
|
||||
errs = append(errs, err)
|
||||
continue
|
||||
|
|
|
@ -207,6 +207,7 @@ func main() {
|
|||
DumpPayload: dumpPayload,
|
||||
},
|
||||
probes{},
|
||||
config.NewDefaultConfiguration(),
|
||||
)
|
||||
// start server
|
||||
server.Run(ctx.Done())
|
||||
|
|
|
@ -32,7 +32,7 @@ type server struct {
|
|||
type (
|
||||
TlsProvider = func() ([]byte, []byte, error)
|
||||
ValidationHandler = func(context.Context, logr.Logger, *admissionv1.AdmissionRequest, time.Time) *admissionv1.AdmissionResponse
|
||||
CleanupHandler = func(context.Context, logr.Logger, string, time.Time) error
|
||||
CleanupHandler = func(context.Context, logr.Logger, string, time.Time, config.Configuration) error
|
||||
)
|
||||
|
||||
type Probes interface {
|
||||
|
@ -48,13 +48,14 @@ func NewServer(
|
|||
metricsConfig metrics.MetricsConfigManager,
|
||||
debugModeOpts webhooks.DebugModeOptions,
|
||||
probes Probes,
|
||||
cfg config.Configuration,
|
||||
) Server {
|
||||
policyLogger := logging.WithName("cleanup-policy")
|
||||
cleanupLogger := logging.WithName("cleanup")
|
||||
cleanupHandlerFunc := func(w http.ResponseWriter, r *http.Request) {
|
||||
policy := r.URL.Query().Get("policy")
|
||||
logger := cleanupLogger.WithValues("policy", policy)
|
||||
err := cleanupHandler(r.Context(), logger, policy, time.Now())
|
||||
err := cleanupHandler(r.Context(), logger, policy, time.Now(), cfg)
|
||||
if err == nil {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
} else {
|
||||
|
|
|
@ -21,6 +21,7 @@ import (
|
|||
"github.com/kyverno/kyverno/pkg/autogen"
|
||||
"github.com/kyverno/kyverno/pkg/background/generate"
|
||||
"github.com/kyverno/kyverno/pkg/clients/dclient"
|
||||
"github.com/kyverno/kyverno/pkg/config"
|
||||
"github.com/kyverno/kyverno/pkg/engine"
|
||||
engineContext "github.com/kyverno/kyverno/pkg/engine/context"
|
||||
"github.com/kyverno/kyverno/pkg/engine/response"
|
||||
|
@ -452,7 +453,8 @@ OuterLoop:
|
|||
}
|
||||
}
|
||||
|
||||
if err := ctx.AddImageInfos(c.Resource); err != nil {
|
||||
cfg := config.NewDefaultConfiguration()
|
||||
if err := ctx.AddImageInfos(c.Resource, cfg); err != nil {
|
||||
if err != nil {
|
||||
log.Log.Error(err, "failed to add image variables to context")
|
||||
}
|
||||
|
@ -511,7 +513,7 @@ OuterLoop:
|
|||
var info Info
|
||||
var validateResponse *response.EngineResponse
|
||||
if policyHasValidate {
|
||||
validateResponse = engine.Validate(context.Background(), registryclient.NewOrDie(), policyContext)
|
||||
validateResponse = engine.Validate(context.Background(), registryclient.NewOrDie(), policyContext, cfg)
|
||||
info = ProcessValidateEngineResponse(c.Policy, validateResponse, resPath, c.Rc, c.PolicyReport, c.AuditWarn)
|
||||
}
|
||||
|
||||
|
@ -519,7 +521,7 @@ OuterLoop:
|
|||
engineResponses = append(engineResponses, validateResponse)
|
||||
}
|
||||
|
||||
verifyImageResponse, _ := engine.VerifyAndPatchImages(context.Background(), registryclient.NewOrDie(), policyContext)
|
||||
verifyImageResponse, _ := engine.VerifyAndPatchImages(context.Background(), registryclient.NewOrDie(), policyContext, cfg)
|
||||
if verifyImageResponse != nil && !verifyImageResponse.IsEmpty() {
|
||||
engineResponses = append(engineResponses, verifyImageResponse)
|
||||
info = ProcessValidateEngineResponse(c.Policy, verifyImageResponse, resPath, c.Rc, c.PolicyReport, c.AuditWarn)
|
||||
|
|
|
@ -170,6 +170,7 @@ func createReportControllers(
|
|||
kyvernoInformer kyvernoinformer.SharedInformerFactory,
|
||||
configMapResolver resolvers.ConfigmapResolver,
|
||||
backgroundScanInterval time.Duration,
|
||||
configuration config.Configuration,
|
||||
) ([]internal.Controller, func(context.Context) error) {
|
||||
var ctrls []internal.Controller
|
||||
var warmups []func(context.Context) error
|
||||
|
@ -225,6 +226,7 @@ func createReportControllers(
|
|||
resourceReportController,
|
||||
configMapResolver,
|
||||
backgroundScanInterval,
|
||||
configuration,
|
||||
),
|
||||
backgroundScanWorkers,
|
||||
))
|
||||
|
@ -340,6 +342,7 @@ func createrLeaderControllers(
|
|||
kyvernoInformer,
|
||||
configMapResolver,
|
||||
backgroundScanInterval,
|
||||
configuration,
|
||||
)
|
||||
return append(
|
||||
[]internal.Controller{
|
||||
|
|
|
@ -46,6 +46,8 @@ metadata:
|
|||
name: kyverno
|
||||
namespace: kyverno
|
||||
data:
|
||||
defaultRegistry: "docker.io"
|
||||
enableDefaultRegistryMutation: "true"
|
||||
# resource types to be skipped by kyverno policy engine
|
||||
resourceFilters: "[*,kyverno,*][Event,*,*][*,kube-system,*][*,kube-public,*][*,kube-node-lease,*][Node,*,*][APIService,*,*][TokenReview,*,*][SubjectAccessReview,*,*][SelfSubjectAccessReview,*,*][Binding,*,*][ReplicaSet,*,*][AdmissionReport,*,*][ClusterAdmissionReport,*,*][BackgroundScanReport,*,*][ClusterBackgroundScanReport,*,*][ClusterRole,*,kyverno:*][ClusterRoleBinding,*,kyverno:*][ServiceAccount,kyverno,kyverno][ConfigMap,kyverno,kyverno][ConfigMap,kyverno,kyverno-metrics][Deployment,kyverno,kyverno][Job,kyverno,kyverno-hook-pre-delete][NetworkPolicy,kyverno,kyverno][PodDisruptionBudget,kyverno,kyverno][Role,kyverno,kyverno:*][RoleBinding,kyverno,kyverno:*][Secret,kyverno,kyverno-svc.kyverno.svc.*][Service,kyverno,kyverno-svc][Service,kyverno,kyverno-svc-metrics][ServiceMonitor,kyverno,kyverno-svc-service-monitor][Pod,kyverno,kyverno-test]"
|
||||
webhooks: '[{"namespaceSelector": {"matchExpressions": [{"key":"kubernetes.io/metadata.name","operator":"NotIn","values":["kyverno"]}]}}]'
|
||||
|
|
|
@ -75,7 +75,7 @@ func NewBackgroundContext(dclient dclient.Interface, ur *kyvernov1beta1.UpdateRe
|
|||
return nil, false, errors.Wrapf(err, "failed to load UserInfo in context")
|
||||
}
|
||||
|
||||
if err := ctx.AddImageInfos(trigger); err != nil {
|
||||
if err := ctx.AddImageInfos(trigger, cfg); err != nil {
|
||||
logger.Error(err, "unable to add image info to variables context")
|
||||
}
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
"strconv"
|
||||
"sync"
|
||||
|
||||
valid "github.com/asaskevich/govalidator"
|
||||
osutils "github.com/kyverno/kyverno/pkg/utils/os"
|
||||
wildcard "github.com/kyverno/kyverno/pkg/utils/wildcard"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
|
@ -130,6 +131,10 @@ func KyvernoConfigMapName() string {
|
|||
|
||||
// Configuration to be used by consumer to check filters
|
||||
type Configuration interface {
|
||||
// GetDefaultRegistry return default image registry
|
||||
GetDefaultRegistry() string
|
||||
// GetEnableDefaultRegistryMutation return if should mutate image registry
|
||||
GetEnableDefaultRegistryMutation() bool
|
||||
// ToFilter checks if the given resource is set to be filtered in the configuration
|
||||
ToFilter(kind, namespace, name string) bool
|
||||
// GetExcludeGroupRole return exclude roles
|
||||
|
@ -148,18 +153,22 @@ type Configuration interface {
|
|||
|
||||
// configuration stores the configuration
|
||||
type configuration struct {
|
||||
mux sync.RWMutex
|
||||
filters []filter
|
||||
excludeGroupRole []string
|
||||
excludeUsername []string
|
||||
webhooks []WebhookConfig
|
||||
generateSuccessEvents bool
|
||||
defaultRegistry string
|
||||
enableDefaultRegistryMutation bool
|
||||
excludeGroupRole []string
|
||||
excludeUsername []string
|
||||
filters []filter
|
||||
generateSuccessEvents bool
|
||||
mux sync.RWMutex
|
||||
webhooks []WebhookConfig
|
||||
}
|
||||
|
||||
// NewDefaultConfiguration ...
|
||||
func NewDefaultConfiguration() *configuration {
|
||||
return &configuration{
|
||||
excludeGroupRole: defaultExcludeGroupRole,
|
||||
defaultRegistry: "docker.io",
|
||||
enableDefaultRegistryMutation: true,
|
||||
excludeGroupRole: defaultExcludeGroupRole,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -199,6 +208,18 @@ func (cd *configuration) GetExcludeGroupRole() []string {
|
|||
return cd.excludeGroupRole
|
||||
}
|
||||
|
||||
func (cd *configuration) GetDefaultRegistry() string {
|
||||
cd.mux.RLock()
|
||||
defer cd.mux.RUnlock()
|
||||
return cd.defaultRegistry
|
||||
}
|
||||
|
||||
func (cd *configuration) GetEnableDefaultRegistryMutation() bool {
|
||||
cd.mux.RLock()
|
||||
defer cd.mux.RUnlock()
|
||||
return cd.enableDefaultRegistryMutation
|
||||
}
|
||||
|
||||
func (cd *configuration) GetExcludeUsername() []string {
|
||||
cd.mux.RLock()
|
||||
defer cd.mux.RUnlock()
|
||||
|
@ -250,6 +271,28 @@ func (cd *configuration) load(cm *corev1.ConfigMap) {
|
|||
cd.webhooks = nil
|
||||
// load filters
|
||||
cd.filters = parseKinds(cm.Data["resourceFilters"])
|
||||
newDefaultRegistry, ok := cm.Data["defaultRegistry"]
|
||||
if !ok {
|
||||
logger.V(4).Info("configuration: No defaultRegistry defined in ConfigMap")
|
||||
} else {
|
||||
if valid.IsDNSName(newDefaultRegistry) {
|
||||
logger.V(4).Info("Updated defaultRegistry config parameter.", "oldDefaultRegistry", cd.defaultRegistry, "newDefaultRegistry", newDefaultRegistry)
|
||||
cd.defaultRegistry = newDefaultRegistry
|
||||
} else {
|
||||
logger.V(4).Info("defaultRegistry didn't change because the provided config value isn't a valid DNS hostname")
|
||||
}
|
||||
}
|
||||
enableDefaultRegistryMutation, ok := cm.Data["enableDefaultRegistryMutation"]
|
||||
if !ok {
|
||||
logger.V(4).Info("configuration: No enableDefaultRegistryMutation defined in ConfigMap")
|
||||
} else {
|
||||
newEnableDefaultRegistryMutation, err := strconv.ParseBool(enableDefaultRegistryMutation)
|
||||
if err != nil {
|
||||
logger.V(4).Info("configuration: Invalid value for enableDefaultRegistryMutation defined in ConfigMap. enableDefaultRegistryMutation didn't change")
|
||||
}
|
||||
logger.V(4).Info("Updated enableDefaultRegistryMutation config parameter", "oldEnableDefaultRegistryMutation", cd.enableDefaultRegistryMutation, "newEnableDefaultRegistryMutation", newEnableDefaultRegistryMutation)
|
||||
cd.enableDefaultRegistryMutation = newEnableDefaultRegistryMutation
|
||||
}
|
||||
// load excludeGroupRole
|
||||
cd.excludeGroupRole = append(cd.excludeGroupRole, parseRbac(cm.Data["excludeGroupRole"])...)
|
||||
cd.excludeGroupRole = append(cd.excludeGroupRole, defaultExcludeGroupRole...)
|
||||
|
@ -281,6 +324,8 @@ func (cd *configuration) unload() {
|
|||
cd.mux.Lock()
|
||||
defer cd.mux.Unlock()
|
||||
cd.filters = []filter{}
|
||||
cd.defaultRegistry = "docker.io"
|
||||
cd.enableDefaultRegistryMutation = true
|
||||
cd.excludeGroupRole = []string{}
|
||||
cd.excludeUsername = []string{}
|
||||
cd.generateSuccessEvents = false
|
||||
|
|
|
@ -12,6 +12,7 @@ import (
|
|||
kyvernov1informers "github.com/kyverno/kyverno/pkg/client/informers/externalversions/kyverno/v1"
|
||||
kyvernov1listers "github.com/kyverno/kyverno/pkg/client/listers/kyverno/v1"
|
||||
"github.com/kyverno/kyverno/pkg/clients/dclient"
|
||||
"github.com/kyverno/kyverno/pkg/config"
|
||||
"github.com/kyverno/kyverno/pkg/controllers"
|
||||
"github.com/kyverno/kyverno/pkg/controllers/report/resource"
|
||||
"github.com/kyverno/kyverno/pkg/controllers/report/utils"
|
||||
|
@ -62,6 +63,8 @@ type controller struct {
|
|||
metadataCache resource.MetadataCache
|
||||
informerCacheResolvers resolvers.ConfigmapResolver
|
||||
forceDelay time.Duration
|
||||
|
||||
cfg config.Configuration
|
||||
}
|
||||
|
||||
func NewController(
|
||||
|
@ -75,6 +78,7 @@ func NewController(
|
|||
metadataCache resource.MetadataCache,
|
||||
informerCacheResolvers resolvers.ConfigmapResolver,
|
||||
forceDelay time.Duration,
|
||||
cfg config.Configuration,
|
||||
) controllers.Controller {
|
||||
bgscanr := metadataFactory.ForResource(kyvernov1alpha2.SchemeGroupVersion.WithResource("backgroundscanreports"))
|
||||
cbgscanr := metadataFactory.ForResource(kyvernov1alpha2.SchemeGroupVersion.WithResource("clusterbackgroundscanreports"))
|
||||
|
@ -94,6 +98,7 @@ func NewController(
|
|||
metadataCache: metadataCache,
|
||||
informerCacheResolvers: informerCacheResolvers,
|
||||
forceDelay: forceDelay,
|
||||
cfg: cfg,
|
||||
}
|
||||
controllerutils.AddEventHandlersT(polInformer.Informer(), c.addPolicy, c.updatePolicy, c.deletePolicy)
|
||||
controllerutils.AddEventHandlersT(cpolInformer.Informer(), c.addPolicy, c.updatePolicy, c.deletePolicy)
|
||||
|
@ -239,7 +244,7 @@ func (c *controller) updateReport(ctx context.Context, meta metav1.Object, gvk s
|
|||
}
|
||||
// if the resource changed, we need to rebuild the report
|
||||
if force || !reportutils.CompareHash(meta, resource.Hash) {
|
||||
scanner := utils.NewScanner(logger, c.client, c.rclient, c.informerCacheResolvers)
|
||||
scanner := utils.NewScanner(logger, c.client, c.rclient, c.informerCacheResolvers, c.cfg)
|
||||
before, err := c.getReport(ctx, meta.GetNamespace(), meta.GetName())
|
||||
if err != nil {
|
||||
return nil
|
||||
|
@ -329,7 +334,7 @@ func (c *controller) updateReport(ctx context.Context, meta metav1.Object, gvk s
|
|||
}
|
||||
// creations
|
||||
if len(toCreate) > 0 {
|
||||
scanner := utils.NewScanner(logger, c.client, c.rclient, c.informerCacheResolvers)
|
||||
scanner := utils.NewScanner(logger, c.client, c.rclient, c.informerCacheResolvers, c.cfg)
|
||||
resource, err := c.client.GetResource(ctx, gvk.GroupVersion().String(), gvk.Kind, resource.Namespace, resource.Name)
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
"github.com/go-logr/logr"
|
||||
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
|
||||
"github.com/kyverno/kyverno/pkg/clients/dclient"
|
||||
"github.com/kyverno/kyverno/pkg/config"
|
||||
"github.com/kyverno/kyverno/pkg/engine"
|
||||
enginecontext "github.com/kyverno/kyverno/pkg/engine/context"
|
||||
"github.com/kyverno/kyverno/pkg/engine/context/resolvers"
|
||||
|
@ -20,6 +21,7 @@ type scanner struct {
|
|||
client dclient.Interface
|
||||
rclient registryclient.Client
|
||||
informerCacheResolvers resolvers.ConfigmapResolver
|
||||
cfg config.Configuration
|
||||
excludeGroupRole []string
|
||||
}
|
||||
|
||||
|
@ -32,12 +34,13 @@ type Scanner interface {
|
|||
ScanResource(context.Context, unstructured.Unstructured, map[string]string, ...kyvernov1.PolicyInterface) map[kyvernov1.PolicyInterface]ScanResult
|
||||
}
|
||||
|
||||
func NewScanner(logger logr.Logger, client dclient.Interface, rclient registryclient.Client, informerCacheResolvers resolvers.ConfigmapResolver, excludeGroupRole ...string) Scanner {
|
||||
func NewScanner(logger logr.Logger, client dclient.Interface, rclient registryclient.Client, informerCacheResolvers resolvers.ConfigmapResolver, cfg config.Configuration, excludeGroupRole ...string) Scanner {
|
||||
return &scanner{
|
||||
logger: logger,
|
||||
client: client,
|
||||
rclient: rclient,
|
||||
informerCacheResolvers: informerCacheResolvers,
|
||||
cfg: cfg,
|
||||
excludeGroupRole: excludeGroupRole,
|
||||
}
|
||||
}
|
||||
|
@ -77,7 +80,7 @@ func (s *scanner) validateResource(ctx context.Context, resource unstructured.Un
|
|||
if err := enginectx.AddNamespace(resource.GetNamespace()); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := enginectx.AddImageInfos(&resource); err != nil {
|
||||
if err := enginectx.AddImageInfos(&resource, s.cfg); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := enginectx.AddOperation("CREATE"); err != nil {
|
||||
|
@ -90,7 +93,7 @@ func (s *scanner) validateResource(ctx context.Context, resource unstructured.Un
|
|||
WithNamespaceLabels(nsLabels).
|
||||
WithExcludeGroupRole(s.excludeGroupRole...).
|
||||
WithInformerCacheResolver(s.informerCacheResolvers)
|
||||
return engine.Validate(ctx, s.rclient, policyCtx), nil
|
||||
return engine.Validate(ctx, s.rclient, policyCtx, s.cfg), nil
|
||||
}
|
||||
|
||||
func (s *scanner) validateImages(ctx context.Context, resource unstructured.Unstructured, nsLabels map[string]string, policy kyvernov1.PolicyInterface) (*response.EngineResponse, error) {
|
||||
|
@ -101,7 +104,7 @@ func (s *scanner) validateImages(ctx context.Context, resource unstructured.Unst
|
|||
if err := enginectx.AddNamespace(resource.GetNamespace()); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := enginectx.AddImageInfos(&resource); err != nil {
|
||||
if err := enginectx.AddImageInfos(&resource, s.cfg); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := enginectx.AddOperation("CREATE"); err != nil {
|
||||
|
@ -114,7 +117,7 @@ func (s *scanner) validateImages(ctx context.Context, resource unstructured.Unst
|
|||
WithNamespaceLabels(nsLabels).
|
||||
WithExcludeGroupRole(s.excludeGroupRole...).
|
||||
WithInformerCacheResolver(s.informerCacheResolvers)
|
||||
response, _ := engine.VerifyAndPatchImages(ctx, s.rclient, policyCtx)
|
||||
response, _ := engine.VerifyAndPatchImages(ctx, s.rclient, policyCtx, s.cfg)
|
||||
if len(response.PolicyResponse.Rules) > 0 {
|
||||
s.logger.Info("validateImages", "policy", policy, "response", response)
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ import (
|
|||
jsonpatch "github.com/evanphx/json-patch/v5"
|
||||
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
|
||||
kyvernov1beta1 "github.com/kyverno/kyverno/api/kyverno/v1beta1"
|
||||
"github.com/kyverno/kyverno/pkg/config"
|
||||
"github.com/kyverno/kyverno/pkg/logging"
|
||||
apiutils "github.com/kyverno/kyverno/pkg/utils/api"
|
||||
"github.com/pkg/errors"
|
||||
|
@ -69,17 +70,17 @@ type Interface interface {
|
|||
AddElement(data interface{}, index, nesting int) error
|
||||
|
||||
// AddImageInfo adds image info to the context
|
||||
AddImageInfo(info apiutils.ImageInfo) error
|
||||
AddImageInfo(info apiutils.ImageInfo, cfg config.Configuration) error
|
||||
|
||||
// AddImageInfos adds image infos to the context
|
||||
AddImageInfos(resource *unstructured.Unstructured) error
|
||||
AddImageInfos(resource *unstructured.Unstructured, cfg config.Configuration) error
|
||||
|
||||
// ImageInfo returns image infos present in the context
|
||||
ImageInfo() map[string]map[string]apiutils.ImageInfo
|
||||
|
||||
// GenerateCustomImageInfo returns image infos as defined by a custom image extraction config
|
||||
// and updates the context
|
||||
GenerateCustomImageInfo(resource *unstructured.Unstructured, imageExtractorConfigs kyvernov1.ImageExtractorConfigs) (map[string]map[string]apiutils.ImageInfo, error)
|
||||
GenerateCustomImageInfo(resource *unstructured.Unstructured, imageExtractorConfigs kyvernov1.ImageExtractorConfigs, cfg config.Configuration) (map[string]map[string]apiutils.ImageInfo, error)
|
||||
|
||||
// Checkpoint creates a copy of the current internal state and pushes it into a stack of stored states.
|
||||
Checkpoint()
|
||||
|
@ -252,7 +253,7 @@ func (ctx *context) AddElement(data interface{}, index, nesting int) error {
|
|||
return addToContext(ctx, data)
|
||||
}
|
||||
|
||||
func (ctx *context) AddImageInfo(info apiutils.ImageInfo) error {
|
||||
func (ctx *context) AddImageInfo(info apiutils.ImageInfo, cfg config.Configuration) error {
|
||||
data := map[string]interface{}{
|
||||
"reference": info.String(),
|
||||
"referenceWithTag": info.ReferenceWithTag(),
|
||||
|
@ -265,8 +266,8 @@ func (ctx *context) AddImageInfo(info apiutils.ImageInfo) error {
|
|||
return addToContext(ctx, data, "image")
|
||||
}
|
||||
|
||||
func (ctx *context) AddImageInfos(resource *unstructured.Unstructured) error {
|
||||
images, err := apiutils.ExtractImagesFromResource(*resource, nil)
|
||||
func (ctx *context) AddImageInfos(resource *unstructured.Unstructured, cfg config.Configuration) error {
|
||||
images, err := apiutils.ExtractImagesFromResource(*resource, nil, cfg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -279,8 +280,8 @@ func (ctx *context) AddImageInfos(resource *unstructured.Unstructured) error {
|
|||
return addToContext(ctx, images, "images")
|
||||
}
|
||||
|
||||
func (ctx *context) GenerateCustomImageInfo(resource *unstructured.Unstructured, imageExtractorConfigs kyvernov1.ImageExtractorConfigs) (map[string]map[string]apiutils.ImageInfo, error) {
|
||||
images, err := apiutils.ExtractImagesFromResource(*resource, imageExtractorConfigs)
|
||||
func (ctx *context) GenerateCustomImageInfo(resource *unstructured.Unstructured, imageExtractorConfigs kyvernov1.ImageExtractorConfigs, cfg config.Configuration) (map[string]map[string]apiutils.ImageInfo, error) {
|
||||
images, err := apiutils.ExtractImagesFromResource(*resource, imageExtractorConfigs, cfg)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to extract images")
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@ import (
|
|||
"github.com/go-logr/logr"
|
||||
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
|
||||
"github.com/kyverno/kyverno/pkg/autogen"
|
||||
"github.com/kyverno/kyverno/pkg/config"
|
||||
"github.com/kyverno/kyverno/pkg/cosign"
|
||||
enginecontext "github.com/kyverno/kyverno/pkg/engine/context"
|
||||
"github.com/kyverno/kyverno/pkg/engine/response"
|
||||
|
@ -46,7 +47,7 @@ func getMatchingImages(images map[string]map[string]apiutils.ImageInfo, rule *ky
|
|||
return imageInfos, strings.Join(imageRefs, ",")
|
||||
}
|
||||
|
||||
func extractMatchingImages(policyContext *PolicyContext, rule *kyvernov1.Rule) ([]apiutils.ImageInfo, string, error) {
|
||||
func extractMatchingImages(policyContext *PolicyContext, rule *kyvernov1.Rule, cfg config.Configuration) ([]apiutils.ImageInfo, string, error) {
|
||||
var (
|
||||
images map[string]map[string]apiutils.ImageInfo
|
||||
err error
|
||||
|
@ -54,7 +55,7 @@ func extractMatchingImages(policyContext *PolicyContext, rule *kyvernov1.Rule) (
|
|||
images = policyContext.jsonContext.ImageInfo()
|
||||
if rule.ImageExtractors != nil {
|
||||
images, err = policyContext.jsonContext.GenerateCustomImageInfo(
|
||||
&policyContext.newResource, rule.ImageExtractors)
|
||||
&policyContext.newResource, rule.ImageExtractors, cfg)
|
||||
if err != nil {
|
||||
// if we get an error while generating custom images from image extractors,
|
||||
// don't check for matching images in imageExtractors
|
||||
|
@ -69,6 +70,7 @@ func VerifyAndPatchImages(
|
|||
ctx context.Context,
|
||||
rclient registryclient.Client,
|
||||
policyContext *PolicyContext,
|
||||
cfg config.Configuration,
|
||||
) (*response.EngineResponse, *ImageVerificationMetadata) {
|
||||
resp := &response.EngineResponse{}
|
||||
|
||||
|
@ -117,7 +119,7 @@ func VerifyAndPatchImages(
|
|||
|
||||
logger.V(3).Info("processing image verification rule", "ruleSelector", applyRules)
|
||||
|
||||
ruleImages, imageRefs, err := extractMatchingImages(policyContext, rule)
|
||||
ruleImages, imageRefs, err := extractMatchingImages(policyContext, rule, cfg)
|
||||
if err != nil {
|
||||
appendResponse(resp, rule, fmt.Sprintf("failed to extract images: %s", err.Error()), response.RuleStatusError)
|
||||
return
|
||||
|
@ -154,7 +156,7 @@ func VerifyAndPatchImages(
|
|||
}
|
||||
|
||||
for _, imageVerify := range ruleCopy.VerifyImages {
|
||||
iv.verify(ctx, imageVerify, ruleImages)
|
||||
iv.verify(ctx, imageVerify, ruleImages, cfg)
|
||||
}
|
||||
},
|
||||
)
|
||||
|
@ -205,7 +207,7 @@ type imageVerifier struct {
|
|||
|
||||
// verify applies policy rules to each matching image. The policy rule results and annotation patches are
|
||||
// added to tme imageVerifier `resp` and `ivm` fields.
|
||||
func (iv *imageVerifier) verify(ctx context.Context, imageVerify kyvernov1.ImageVerification, matchedImageInfos []apiutils.ImageInfo) {
|
||||
func (iv *imageVerifier) verify(ctx context.Context, imageVerify kyvernov1.ImageVerification, matchedImageInfos []apiutils.ImageInfo, cfg config.Configuration) {
|
||||
// for backward compatibility
|
||||
imageVerify = *imageVerify.Convert()
|
||||
|
||||
|
@ -234,7 +236,7 @@ func (iv *imageVerifier) verify(ctx context.Context, imageVerify kyvernov1.Image
|
|||
continue
|
||||
}
|
||||
|
||||
ruleResp, digest := iv.verifyImage(ctx, imageVerify, imageInfo)
|
||||
ruleResp, digest := iv.verifyImage(ctx, imageVerify, imageInfo, cfg)
|
||||
|
||||
if imageVerify.MutateDigest {
|
||||
patch, retrievedDigest, err := iv.handleMutateDigest(ctx, digest, imageInfo)
|
||||
|
@ -317,6 +319,7 @@ func (iv *imageVerifier) verifyImage(
|
|||
ctx context.Context,
|
||||
imageVerify kyvernov1.ImageVerification,
|
||||
imageInfo apiutils.ImageInfo,
|
||||
cfg config.Configuration,
|
||||
) (*response.RuleResponse, string) {
|
||||
if len(imageVerify.Attestors) <= 0 && len(imageVerify.Attestations) <= 0 {
|
||||
return nil, ""
|
||||
|
@ -326,7 +329,7 @@ func (iv *imageVerifier) verifyImage(
|
|||
iv.logger.V(2).Info("verifying image signatures", "image", image,
|
||||
"attestors", len(imageVerify.Attestors), "attestations", len(imageVerify.Attestations))
|
||||
|
||||
if err := iv.policyContext.jsonContext.AddImageInfo(imageInfo); err != nil {
|
||||
if err := iv.policyContext.jsonContext.AddImageInfo(imageInfo, cfg); err != nil {
|
||||
iv.logger.Error(err, "failed to add image to context")
|
||||
msg := fmt.Sprintf("failed to add image to context %s: %s", image, err.Error())
|
||||
return ruleResponse(*iv.rule, response.ImageVerify, msg, response.RuleStatusError), ""
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
"github.com/go-logr/logr"
|
||||
gojmespath "github.com/jmespath/go-jmespath"
|
||||
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
|
||||
"github.com/kyverno/kyverno/pkg/config"
|
||||
"github.com/kyverno/kyverno/pkg/engine/response"
|
||||
"github.com/kyverno/kyverno/pkg/registryclient"
|
||||
apiutils "github.com/kyverno/kyverno/pkg/utils/api"
|
||||
|
@ -15,13 +16,13 @@ import (
|
|||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
)
|
||||
|
||||
func processImageValidationRule(ctx context.Context, log logr.Logger, rclient registryclient.Client, enginectx *PolicyContext, rule *kyvernov1.Rule) *response.RuleResponse {
|
||||
func processImageValidationRule(ctx context.Context, log logr.Logger, rclient registryclient.Client, enginectx *PolicyContext, rule *kyvernov1.Rule, cfg config.Configuration) *response.RuleResponse {
|
||||
if isDeleteRequest(enginectx) {
|
||||
return nil
|
||||
}
|
||||
|
||||
log = log.WithValues("rule", rule.Name)
|
||||
matchingImages, _, err := extractMatchingImages(enginectx, rule)
|
||||
matchingImages, _, err := extractMatchingImages(enginectx, rule, cfg)
|
||||
if err != nil {
|
||||
return ruleResponse(*rule, response.Validation, err.Error(), response.RuleStatusError)
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ import (
|
|||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/kyverno/kyverno/pkg/config"
|
||||
"github.com/kyverno/kyverno/pkg/logging"
|
||||
"github.com/kyverno/kyverno/pkg/registryclient"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
|
@ -63,7 +64,7 @@ var testPolicyGood = `{
|
|||
"key": "{{ repo.uri }}",
|
||||
"operator": "Equals",
|
||||
"value": "https://github.com/example/my-project"
|
||||
},
|
||||
},
|
||||
{
|
||||
"key": "{{ repo.branch }}",
|
||||
"operator": "Equals",
|
||||
|
@ -112,7 +113,7 @@ var testPolicyBad = `{
|
|||
"key": "{{ repo.uri }}",
|
||||
"operator": "Equals",
|
||||
"value": "https://github.com/example/my-project"
|
||||
},
|
||||
},
|
||||
{
|
||||
"key": "{{ repo.branch }}",
|
||||
"operator": "Equals",
|
||||
|
@ -157,12 +158,14 @@ var signaturePayloads = [][]byte{
|
|||
[]byte(`{"critical":{"identity":{"docker-reference":"ghcr.io/kyverno/test-verify-image"},"image":{"docker-manifest-digest":"sha256:b31bfb4d0213f254d361e0079deaaebefa4f82ba7aa76ef82e90b4935ad5b105"},"type":"cosign container image signature"},"optional":null}`),
|
||||
}
|
||||
|
||||
var cfg = config.NewDefaultConfiguration()
|
||||
|
||||
func Test_CosignMockAttest(t *testing.T) {
|
||||
policyContext := buildContext(t, testPolicyGood, testResource, "")
|
||||
err := cosign.SetMock("ghcr.io/jimbugwadia/pause2:latest", attestationPayloads)
|
||||
assert.NilError(t, err)
|
||||
|
||||
er, ivm := VerifyAndPatchImages(context.TODO(), registryclient.NewOrDie(), policyContext)
|
||||
er, ivm := VerifyAndPatchImages(context.TODO(), registryclient.NewOrDie(), policyContext, cfg)
|
||||
assert.Equal(t, len(er.PolicyResponse.Rules), 1)
|
||||
assert.Equal(t, er.PolicyResponse.Rules[0].Status, response.RuleStatusPass,
|
||||
fmt.Sprintf("expected: %v, got: %v, failure: %v",
|
||||
|
@ -176,7 +179,7 @@ func Test_CosignMockAttest_fail(t *testing.T) {
|
|||
err := cosign.SetMock("ghcr.io/jimbugwadia/pause2:latest", attestationPayloads)
|
||||
assert.NilError(t, err)
|
||||
|
||||
er, _ := VerifyAndPatchImages(context.TODO(), registryclient.NewOrDie(), policyContext)
|
||||
er, _ := VerifyAndPatchImages(context.TODO(), registryclient.NewOrDie(), policyContext, cfg)
|
||||
assert.Equal(t, len(er.PolicyResponse.Rules), 1)
|
||||
assert.Equal(t, er.PolicyResponse.Rules[0].Status, response.RuleStatusFail)
|
||||
}
|
||||
|
@ -209,7 +212,7 @@ func buildContext(t *testing.T, policy, resource string, oldResource string) *Po
|
|||
policyContext.oldResource = *oldResourceUnstructured
|
||||
}
|
||||
|
||||
if err := ctx.AddImageInfos(resourceUnstructured); err != nil {
|
||||
if err := ctx.AddImageInfos(resourceUnstructured, cfg); err != nil {
|
||||
t.Errorf("unable to add image info to variables context: %v", err)
|
||||
t.Fail()
|
||||
}
|
||||
|
@ -425,7 +428,7 @@ var (
|
|||
func Test_ConfigMapMissingSuccess(t *testing.T) {
|
||||
policyContext := buildContext(t, testConfigMapMissing, testConfigMapMissingResource, "")
|
||||
cosign.ClearMock()
|
||||
err, _ := VerifyAndPatchImages(context.TODO(), registryclient.NewOrDie(), policyContext)
|
||||
err, _ := VerifyAndPatchImages(context.TODO(), registryclient.NewOrDie(), policyContext, cfg)
|
||||
assert.Equal(t, len(err.PolicyResponse.Rules), 1)
|
||||
assert.Equal(t, err.PolicyResponse.Rules[0].Status, response.RuleStatusSkip, err.PolicyResponse.Rules[0].Message)
|
||||
}
|
||||
|
@ -437,7 +440,7 @@ func Test_ConfigMapMissingFailure(t *testing.T) {
|
|||
assert.NilError(t, err)
|
||||
policyContext.informerCacheResolvers = resolver
|
||||
cosign.ClearMock()
|
||||
resp, _ := VerifyAndPatchImages(context.TODO(), registryclient.NewOrDie(), policyContext)
|
||||
resp, _ := VerifyAndPatchImages(context.TODO(), registryclient.NewOrDie(), policyContext, cfg)
|
||||
assert.Equal(t, len(resp.PolicyResponse.Rules), 1)
|
||||
assert.Equal(t, resp.PolicyResponse.Rules[0].Status, response.RuleStatusError, resp.PolicyResponse.Rules[0].Message)
|
||||
}
|
||||
|
@ -446,7 +449,7 @@ func Test_SignatureGoodSigned(t *testing.T) {
|
|||
policyContext := buildContext(t, testSampleSingleKeyPolicy, testSampleResource, "")
|
||||
policyContext.policy.GetSpec().Rules[0].VerifyImages[0].MutateDigest = true
|
||||
cosign.ClearMock()
|
||||
engineResp, _ := VerifyAndPatchImages(context.TODO(), registryclient.NewOrDie(), policyContext)
|
||||
engineResp, _ := VerifyAndPatchImages(context.TODO(), registryclient.NewOrDie(), policyContext, cfg)
|
||||
assert.Equal(t, len(engineResp.PolicyResponse.Rules), 1)
|
||||
assert.Equal(t, engineResp.PolicyResponse.Rules[0].Status, response.RuleStatusPass, engineResp.PolicyResponse.Rules[0].Message)
|
||||
assert.Equal(t, len(engineResp.PolicyResponse.Rules[0].Patches), 1)
|
||||
|
@ -458,7 +461,7 @@ func Test_SignatureUnsigned(t *testing.T) {
|
|||
cosign.ClearMock()
|
||||
unsigned := strings.Replace(testSampleResource, ":signed", ":unsigned", -1)
|
||||
policyContext := buildContext(t, testSampleSingleKeyPolicy, unsigned, "")
|
||||
engineResp, _ := VerifyAndPatchImages(context.TODO(), registryclient.NewOrDie(), policyContext)
|
||||
engineResp, _ := VerifyAndPatchImages(context.TODO(), registryclient.NewOrDie(), policyContext, cfg)
|
||||
assert.Equal(t, len(engineResp.PolicyResponse.Rules), 1)
|
||||
assert.Equal(t, engineResp.PolicyResponse.Rules[0].Status, response.RuleStatusFail, engineResp.PolicyResponse.Rules[0].Message)
|
||||
}
|
||||
|
@ -467,7 +470,7 @@ func Test_SignatureWrongKey(t *testing.T) {
|
|||
cosign.ClearMock()
|
||||
otherKey := strings.Replace(testSampleResource, ":signed", ":signed-by-someone-else", -1)
|
||||
policyContext := buildContext(t, testSampleSingleKeyPolicy, otherKey, "")
|
||||
engineResp, _ := VerifyAndPatchImages(context.TODO(), registryclient.NewOrDie(), policyContext)
|
||||
engineResp, _ := VerifyAndPatchImages(context.TODO(), registryclient.NewOrDie(), policyContext, cfg)
|
||||
assert.Equal(t, len(engineResp.PolicyResponse.Rules), 1)
|
||||
assert.Equal(t, engineResp.PolicyResponse.Rules[0].Status, response.RuleStatusFail, engineResp.PolicyResponse.Rules[0].Message)
|
||||
}
|
||||
|
@ -478,7 +481,7 @@ func Test_SignaturesMultiKey(t *testing.T) {
|
|||
policy = strings.Replace(policy, "KEY2", testVerifyImageKey, -1)
|
||||
policy = strings.Replace(policy, "COUNT", "0", -1)
|
||||
policyContext := buildContext(t, policy, testSampleResource, "")
|
||||
engineResp, _ := VerifyAndPatchImages(context.TODO(), registryclient.NewOrDie(), policyContext)
|
||||
engineResp, _ := VerifyAndPatchImages(context.TODO(), registryclient.NewOrDie(), policyContext, cfg)
|
||||
assert.Equal(t, len(engineResp.PolicyResponse.Rules), 1)
|
||||
assert.Equal(t, engineResp.PolicyResponse.Rules[0].Status, response.RuleStatusPass, engineResp.PolicyResponse.Rules[0].Message)
|
||||
}
|
||||
|
@ -488,7 +491,7 @@ func Test_SignaturesMultiKeyFail(t *testing.T) {
|
|||
policy := strings.Replace(testSampleMultipleKeyPolicy, "KEY1", testVerifyImageKey, -1)
|
||||
policy = strings.Replace(policy, "COUNT", "0", -1)
|
||||
policyContext := buildContext(t, policy, testSampleResource, "")
|
||||
engineResp, _ := VerifyAndPatchImages(context.TODO(), registryclient.NewOrDie(), policyContext)
|
||||
engineResp, _ := VerifyAndPatchImages(context.TODO(), registryclient.NewOrDie(), policyContext, cfg)
|
||||
assert.Equal(t, len(engineResp.PolicyResponse.Rules), 1)
|
||||
assert.Equal(t, engineResp.PolicyResponse.Rules[0].Status, response.RuleStatusFail, engineResp.PolicyResponse.Rules[0].Message)
|
||||
}
|
||||
|
@ -499,7 +502,7 @@ func Test_SignaturesMultiKeyOneGoodKey(t *testing.T) {
|
|||
policy = strings.Replace(policy, "KEY2", testOtherKey, -1)
|
||||
policy = strings.Replace(policy, "COUNT", "1", -1)
|
||||
policyContext := buildContext(t, policy, testSampleResource, "")
|
||||
engineResp, _ := VerifyAndPatchImages(context.TODO(), registryclient.NewOrDie(), policyContext)
|
||||
engineResp, _ := VerifyAndPatchImages(context.TODO(), registryclient.NewOrDie(), policyContext, cfg)
|
||||
assert.Equal(t, len(engineResp.PolicyResponse.Rules), 1)
|
||||
assert.Equal(t, engineResp.PolicyResponse.Rules[0].Status, response.RuleStatusPass, engineResp.PolicyResponse.Rules[0].Message)
|
||||
}
|
||||
|
@ -510,7 +513,7 @@ func Test_SignaturesMultiKeyZeroGoodKey(t *testing.T) {
|
|||
policy = strings.Replace(policy, "KEY2", testOtherKey, -1)
|
||||
policy = strings.Replace(policy, "COUNT", "1", -1)
|
||||
policyContext := buildContext(t, policy, testSampleResource, "")
|
||||
resp, _ := VerifyAndPatchImages(context.TODO(), registryclient.NewOrDie(), policyContext)
|
||||
resp, _ := VerifyAndPatchImages(context.TODO(), registryclient.NewOrDie(), policyContext, cfg)
|
||||
assert.Equal(t, len(resp.PolicyResponse.Rules), 1)
|
||||
assert.Equal(t, resp.PolicyResponse.Rules[0].Status, response.RuleStatusFail, resp.PolicyResponse.Rules[0].Message)
|
||||
}
|
||||
|
@ -526,14 +529,14 @@ func Test_RuleSelectorImageVerify(t *testing.T) {
|
|||
applyAll := kyverno.ApplyAll
|
||||
spec.ApplyRules = &applyAll
|
||||
|
||||
resp, _ := VerifyAndPatchImages(context.TODO(), registryclient.NewOrDie(), policyContext)
|
||||
resp, _ := VerifyAndPatchImages(context.TODO(), registryclient.NewOrDie(), policyContext, cfg)
|
||||
assert.Equal(t, len(resp.PolicyResponse.Rules), 2)
|
||||
assert.Equal(t, resp.PolicyResponse.Rules[0].Status, response.RuleStatusPass, resp.PolicyResponse.Rules[0].Message)
|
||||
assert.Equal(t, resp.PolicyResponse.Rules[1].Status, response.RuleStatusFail, resp.PolicyResponse.Rules[1].Message)
|
||||
|
||||
applyOne := kyverno.ApplyOne
|
||||
spec.ApplyRules = &applyOne
|
||||
resp, _ = VerifyAndPatchImages(context.TODO(), registryclient.NewOrDie(), policyContext)
|
||||
resp, _ = VerifyAndPatchImages(context.TODO(), registryclient.NewOrDie(), policyContext, cfg)
|
||||
assert.Equal(t, len(resp.PolicyResponse.Rules), 1)
|
||||
assert.Equal(t, resp.PolicyResponse.Rules[0].Status, response.RuleStatusPass, resp.PolicyResponse.Rules[0].Message)
|
||||
}
|
||||
|
@ -637,7 +640,7 @@ func Test_NestedAttestors(t *testing.T) {
|
|||
policy = strings.Replace(policy, "KEY2", testVerifyImageKey, -1)
|
||||
policy = strings.Replace(policy, "COUNT", "0", -1)
|
||||
policyContext := buildContext(t, policy, testSampleResource, "")
|
||||
err, _ := VerifyAndPatchImages(context.TODO(), registryclient.NewOrDie(), policyContext)
|
||||
err, _ := VerifyAndPatchImages(context.TODO(), registryclient.NewOrDie(), policyContext, cfg)
|
||||
assert.Equal(t, len(err.PolicyResponse.Rules), 1)
|
||||
assert.Equal(t, err.PolicyResponse.Rules[0].Status, response.RuleStatusPass)
|
||||
|
||||
|
@ -645,7 +648,7 @@ func Test_NestedAttestors(t *testing.T) {
|
|||
policy = strings.Replace(policy, "KEY2", testOtherKey, -1)
|
||||
policy = strings.Replace(policy, "COUNT", "0", -1)
|
||||
policyContext = buildContext(t, policy, testSampleResource, "")
|
||||
err, _ = VerifyAndPatchImages(context.TODO(), registryclient.NewOrDie(), policyContext)
|
||||
err, _ = VerifyAndPatchImages(context.TODO(), registryclient.NewOrDie(), policyContext, cfg)
|
||||
assert.Equal(t, len(err.PolicyResponse.Rules), 1)
|
||||
assert.Equal(t, err.PolicyResponse.Rules[0].Status, response.RuleStatusFail)
|
||||
|
||||
|
@ -653,7 +656,7 @@ func Test_NestedAttestors(t *testing.T) {
|
|||
policy = strings.Replace(policy, "KEY2", testOtherKey, -1)
|
||||
policy = strings.Replace(policy, "COUNT", "1", -1)
|
||||
policyContext = buildContext(t, policy, testSampleResource, "")
|
||||
err, _ = VerifyAndPatchImages(context.TODO(), registryclient.NewOrDie(), policyContext)
|
||||
err, _ = VerifyAndPatchImages(context.TODO(), registryclient.NewOrDie(), policyContext, cfg)
|
||||
assert.Equal(t, len(err.PolicyResponse.Rules), 1)
|
||||
assert.Equal(t, err.PolicyResponse.Rules[0].Status, response.RuleStatusPass)
|
||||
}
|
||||
|
@ -746,7 +749,7 @@ func Test_MarkImageVerified(t *testing.T) {
|
|||
err := cosign.SetMock(image, attestationPayloads)
|
||||
assert.NilError(t, err)
|
||||
|
||||
engineResponse, verifiedImages := VerifyAndPatchImages(context.TODO(), registryclient.NewOrDie(), policyContext)
|
||||
engineResponse, verifiedImages := VerifyAndPatchImages(context.TODO(), registryclient.NewOrDie(), policyContext, cfg)
|
||||
assert.Assert(t, engineResponse != nil)
|
||||
assert.Equal(t, len(engineResponse.PolicyResponse.Rules), 1)
|
||||
assert.Equal(t, engineResponse.PolicyResponse.Rules[0].Status, response.RuleStatusPass)
|
||||
|
@ -839,7 +842,7 @@ func Test_ParsePEMDelimited(t *testing.T) {
|
|||
err := cosign.SetMock(image, signaturePayloads)
|
||||
assert.NilError(t, err)
|
||||
|
||||
engineResponse, verifiedImages := VerifyAndPatchImages(context.TODO(), registryclient.NewOrDie(), policyContext)
|
||||
engineResponse, verifiedImages := VerifyAndPatchImages(context.TODO(), registryclient.NewOrDie(), policyContext, cfg)
|
||||
assert.Assert(t, engineResponse != nil)
|
||||
assert.Equal(t, len(engineResponse.PolicyResponse.Rules), 1)
|
||||
assert.Equal(t, engineResponse.PolicyResponse.Rules[0].Status, response.RuleStatusPass)
|
||||
|
|
|
@ -369,7 +369,7 @@ func Test_chained_rules(t *testing.T) {
|
|||
newResource: *resource,
|
||||
}
|
||||
|
||||
err = ctx.AddImageInfos(resource)
|
||||
err = ctx.AddImageInfos(resource, cfg)
|
||||
assert.NilError(t, err)
|
||||
|
||||
err = enginecontext.MutateResourceWithImageInfo(resourceRaw, ctx)
|
||||
|
@ -648,7 +648,7 @@ func Test_foreach(t *testing.T) {
|
|||
newResource: *resource,
|
||||
}
|
||||
|
||||
err = ctx.AddImageInfos(resource)
|
||||
err = ctx.AddImageInfos(resource, cfg)
|
||||
assert.NilError(t, err)
|
||||
|
||||
err = enginecontext.MutateResourceWithImageInfo(resourceRaw, ctx)
|
||||
|
@ -755,7 +755,7 @@ func Test_foreach_element_mutation(t *testing.T) {
|
|||
newResource: *resource,
|
||||
}
|
||||
|
||||
err = ctx.AddImageInfos(resource)
|
||||
err = ctx.AddImageInfos(resource, cfg)
|
||||
assert.NilError(t, err)
|
||||
|
||||
err = enginecontext.MutateResourceWithImageInfo(resourceRaw, ctx)
|
||||
|
@ -881,7 +881,7 @@ func Test_Container_InitContainer_foreach(t *testing.T) {
|
|||
newResource: *resource,
|
||||
}
|
||||
|
||||
err = ctx.AddImageInfos(resource)
|
||||
err = ctx.AddImageInfos(resource, cfg)
|
||||
assert.NilError(t, err)
|
||||
|
||||
err = enginecontext.MutateResourceWithImageInfo(resourceRaw, ctx)
|
||||
|
@ -1031,7 +1031,7 @@ func testApplyPolicyToResource(t *testing.T, policyRaw, resourceRaw []byte) *res
|
|||
newResource: *resource,
|
||||
}
|
||||
|
||||
err = ctx.AddImageInfos(resource)
|
||||
err = ctx.AddImageInfos(resource, cfg)
|
||||
assert.NilError(t, err)
|
||||
|
||||
err = enginecontext.MutateResourceWithImageInfo(resourceRaw, ctx)
|
||||
|
@ -1646,7 +1646,7 @@ func Test_RuleSelectorMutate(t *testing.T) {
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}`)
|
||||
|
|
|
@ -259,7 +259,7 @@ func NewPolicyContextFromAdmissionRequest(
|
|||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to parse resource")
|
||||
}
|
||||
if err := ctx.AddImageInfos(&newResource); err != nil {
|
||||
if err := ctx.AddImageInfos(&newResource, configuration); err != nil {
|
||||
return nil, errors.Wrap(err, "failed to add image information to the policy rule context")
|
||||
}
|
||||
requestResource := request.RequestResource.DeepCopy()
|
||||
|
|
|
@ -14,6 +14,7 @@ import (
|
|||
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"
|
||||
"github.com/kyverno/kyverno/pkg/engine/common"
|
||||
"github.com/kyverno/kyverno/pkg/engine/response"
|
||||
"github.com/kyverno/kyverno/pkg/engine/validate"
|
||||
|
@ -37,7 +38,7 @@ import (
|
|||
)
|
||||
|
||||
// Validate applies validation rules from policy on the resource
|
||||
func Validate(ctx context.Context, rclient registryclient.Client, policyContext *PolicyContext) (resp *response.EngineResponse) {
|
||||
func Validate(ctx context.Context, rclient registryclient.Client, policyContext *PolicyContext, cfg config.Configuration) (resp *response.EngineResponse) {
|
||||
resp = &response.EngineResponse{}
|
||||
startTime := time.Now()
|
||||
|
||||
|
@ -48,7 +49,7 @@ func Validate(ctx context.Context, rclient registryclient.Client, policyContext
|
|||
logger.V(4).Info("finished policy processing", "processingTime", resp.PolicyResponse.ProcessingTime.String(), "validationRulesApplied", resp.PolicyResponse.RulesAppliedCount)
|
||||
}()
|
||||
|
||||
resp = validateResource(ctx, logger, rclient, policyContext)
|
||||
resp = validateResource(ctx, logger, rclient, policyContext, cfg)
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -95,7 +96,7 @@ func buildResponse(ctx *PolicyContext, resp *response.EngineResponse, startTime
|
|||
resp.PolicyResponse.PolicyExecutionTimestamp = startTime.Unix()
|
||||
}
|
||||
|
||||
func validateResource(ctx context.Context, log logr.Logger, rclient registryclient.Client, enginectx *PolicyContext) *response.EngineResponse {
|
||||
func validateResource(ctx context.Context, log logr.Logger, rclient registryclient.Client, enginectx *PolicyContext, cfg config.Configuration) *response.EngineResponse {
|
||||
resp := &response.EngineResponse{}
|
||||
|
||||
enginectx.jsonContext.Checkpoint()
|
||||
|
@ -145,7 +146,7 @@ func validateResource(ctx context.Context, log logr.Logger, rclient registryclie
|
|||
if hasValidate && !hasYAMLSignatureVerify {
|
||||
return processValidationRule(ctx, log, rclient, enginectx, rule)
|
||||
} else if hasValidateImage {
|
||||
return processImageValidationRule(ctx, log, rclient, enginectx, rule)
|
||||
return processImageValidationRule(ctx, log, rclient, enginectx, rule, cfg)
|
||||
} else if hasYAMLSignatureVerify {
|
||||
return processYAMLValidationRule(log, enginectx, rule)
|
||||
}
|
||||
|
|
|
@ -133,7 +133,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 := Validate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()})
|
||||
er := Validate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()}, cfg)
|
||||
for index, r := range er.PolicyResponse.Rules {
|
||||
assert.Equal(t, r.Message, msgs[index])
|
||||
}
|
||||
|
@ -233,7 +233,7 @@ func TestValidate_image_tag_pass(t *testing.T) {
|
|||
"validation rule 'validate-tag' passed.",
|
||||
"validation rule 'validate-latest' passed.",
|
||||
}
|
||||
er := Validate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()})
|
||||
er := Validate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()}, cfg)
|
||||
for index, r := range er.PolicyResponse.Rules {
|
||||
assert.Equal(t, r.Message, msgs[index])
|
||||
}
|
||||
|
@ -307,7 +307,7 @@ func TestValidate_Fail_anyPattern(t *testing.T) {
|
|||
|
||||
resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
|
||||
assert.NilError(t, err)
|
||||
er := Validate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()})
|
||||
er := Validate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()}, cfg)
|
||||
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/"}
|
||||
|
@ -390,7 +390,7 @@ func TestValidate_host_network_port(t *testing.T) {
|
|||
|
||||
resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
|
||||
assert.NilError(t, err)
|
||||
er := Validate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()})
|
||||
er := Validate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()}, cfg)
|
||||
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 {
|
||||
|
@ -480,7 +480,7 @@ func TestValidate_anchor_arraymap_pass(t *testing.T) {
|
|||
|
||||
resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
|
||||
assert.NilError(t, err)
|
||||
er := Validate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()})
|
||||
er := Validate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()}, cfg)
|
||||
msgs := []string{"validation rule 'validate-host-path' passed."}
|
||||
|
||||
for index, r := range er.PolicyResponse.Rules {
|
||||
|
@ -568,7 +568,7 @@ func TestValidate_anchor_arraymap_fail(t *testing.T) {
|
|||
assert.NilError(t, err)
|
||||
resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
|
||||
assert.NilError(t, err)
|
||||
er := Validate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()})
|
||||
er := Validate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()}, cfg)
|
||||
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 {
|
||||
|
@ -638,7 +638,7 @@ func TestValidate_anchor_map_notfound(t *testing.T) {
|
|||
|
||||
resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
|
||||
assert.NilError(t, err)
|
||||
er := Validate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()})
|
||||
er := Validate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()}, cfg)
|
||||
msgs := []string{"validation rule 'pod rule 2' passed."}
|
||||
|
||||
for index, r := range er.PolicyResponse.Rules {
|
||||
|
@ -711,7 +711,7 @@ func TestValidate_anchor_map_found_valid(t *testing.T) {
|
|||
|
||||
resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
|
||||
assert.NilError(t, err)
|
||||
er := Validate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()})
|
||||
er := Validate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()}, cfg)
|
||||
msgs := []string{"validation rule 'pod rule 2' passed."}
|
||||
|
||||
for index, r := range er.PolicyResponse.Rules {
|
||||
|
@ -785,7 +785,7 @@ func TestValidate_inequality_List_Processing(t *testing.T) {
|
|||
|
||||
resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
|
||||
assert.NilError(t, err)
|
||||
er := Validate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()})
|
||||
er := Validate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()}, cfg)
|
||||
msgs := []string{"validation rule 'pod rule 2' passed."}
|
||||
|
||||
for index, r := range er.PolicyResponse.Rules {
|
||||
|
@ -865,7 +865,7 @@ func TestValidate_inequality_List_ProcessingBrackets(t *testing.T) {
|
|||
|
||||
resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
|
||||
assert.NilError(t, err)
|
||||
er := Validate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()})
|
||||
er := Validate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()}, cfg)
|
||||
msgs := []string{"validation rule 'pod rule 2' passed."}
|
||||
|
||||
for index, r := range er.PolicyResponse.Rules {
|
||||
|
@ -939,7 +939,7 @@ func TestValidate_anchor_map_found_invalid(t *testing.T) {
|
|||
|
||||
resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
|
||||
assert.NilError(t, err)
|
||||
er := Validate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()})
|
||||
er := Validate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()}, cfg)
|
||||
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 {
|
||||
|
@ -1014,7 +1014,7 @@ func TestValidate_AnchorList_pass(t *testing.T) {
|
|||
|
||||
resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
|
||||
assert.NilError(t, err)
|
||||
er := Validate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()})
|
||||
er := Validate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()}, cfg)
|
||||
msgs := []string{"validation rule 'pod image rule' passed."}
|
||||
|
||||
for index, r := range er.PolicyResponse.Rules {
|
||||
|
@ -1089,7 +1089,7 @@ func TestValidate_AnchorList_fail(t *testing.T) {
|
|||
|
||||
resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
|
||||
assert.NilError(t, err)
|
||||
er := Validate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()})
|
||||
er := Validate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()}, cfg)
|
||||
assert.Assert(t, !er.IsSuccessful())
|
||||
}
|
||||
|
||||
|
@ -1159,7 +1159,7 @@ func TestValidate_existenceAnchor_fail(t *testing.T) {
|
|||
|
||||
resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
|
||||
assert.NilError(t, err)
|
||||
er := Validate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()})
|
||||
er := Validate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()}, cfg)
|
||||
assert.Assert(t, !er.IsSuccessful())
|
||||
}
|
||||
|
||||
|
@ -1229,7 +1229,7 @@ func TestValidate_existenceAnchor_pass(t *testing.T) {
|
|||
|
||||
resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
|
||||
assert.NilError(t, err)
|
||||
er := Validate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()})
|
||||
er := Validate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()}, cfg)
|
||||
msgs := []string{"validation rule 'pod image rule' passed."}
|
||||
|
||||
for index, r := range er.PolicyResponse.Rules {
|
||||
|
@ -1317,7 +1317,7 @@ func TestValidate_negationAnchor_deny(t *testing.T) {
|
|||
|
||||
resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
|
||||
assert.NilError(t, err)
|
||||
er := Validate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()})
|
||||
er := Validate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()}, cfg)
|
||||
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 {
|
||||
|
@ -1404,7 +1404,7 @@ func TestValidate_negationAnchor_pass(t *testing.T) {
|
|||
|
||||
resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
|
||||
assert.NilError(t, err)
|
||||
er := Validate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()})
|
||||
er := Validate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()}, cfg)
|
||||
msgs := []string{"validation rule 'validate-host-path' passed."}
|
||||
|
||||
for index, r := range er.PolicyResponse.Rules {
|
||||
|
@ -1481,7 +1481,7 @@ func Test_VariableSubstitutionPathNotExistInPattern(t *testing.T) {
|
|||
jsonContext: ctx,
|
||||
newResource: *resourceUnstructured,
|
||||
}
|
||||
er := Validate(context.TODO(), registryclient.NewOrDie(), policyContext)
|
||||
er := Validate(context.TODO(), registryclient.NewOrDie(), policyContext, cfg)
|
||||
|
||||
assert.Equal(t, len(er.PolicyResponse.Rules), 1)
|
||||
assert.Equal(t, er.PolicyResponse.Rules[0].Status, response.RuleStatusError)
|
||||
|
@ -1575,7 +1575,7 @@ func Test_VariableSubstitutionPathNotExistInAnyPattern_OnePatternStatisfiesButSu
|
|||
jsonContext: ctx,
|
||||
newResource: *resourceUnstructured,
|
||||
}
|
||||
er := Validate(context.TODO(), registryclient.NewOrDie(), policyContext)
|
||||
er := Validate(context.TODO(), registryclient.NewOrDie(), policyContext, cfg)
|
||||
|
||||
assert.Equal(t, len(er.PolicyResponse.Rules), 1)
|
||||
assert.Equal(t, er.PolicyResponse.Rules[0].Status, response.RuleStatusError)
|
||||
|
@ -1637,7 +1637,7 @@ func Test_VariableSubstitution_NotOperatorWithStringVariable(t *testing.T) {
|
|||
jsonContext: ctx,
|
||||
newResource: *resourceUnstructured,
|
||||
}
|
||||
er := Validate(context.TODO(), registryclient.NewOrDie(), policyContext)
|
||||
er := Validate(context.TODO(), registryclient.NewOrDie(), policyContext, cfg)
|
||||
assert.Equal(t, er.PolicyResponse.Rules[0].Status, response.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/")
|
||||
}
|
||||
|
@ -1729,7 +1729,7 @@ func Test_VariableSubstitutionPathNotExistInAnyPattern_AllPathNotPresent(t *test
|
|||
jsonContext: ctx,
|
||||
newResource: *resourceUnstructured,
|
||||
}
|
||||
er := Validate(context.TODO(), registryclient.NewOrDie(), policyContext)
|
||||
er := Validate(context.TODO(), registryclient.NewOrDie(), policyContext, cfg)
|
||||
|
||||
assert.Equal(t, len(er.PolicyResponse.Rules), 1)
|
||||
assert.Equal(t, er.PolicyResponse.Rules[0].Status, response.RuleStatusError)
|
||||
|
@ -1823,7 +1823,7 @@ func Test_VariableSubstitutionPathNotExistInAnyPattern_AllPathPresent_NonePatter
|
|||
jsonContext: ctx,
|
||||
newResource: *resourceUnstructured,
|
||||
}
|
||||
er := Validate(context.TODO(), registryclient.NewOrDie(), policyContext)
|
||||
er := Validate(context.TODO(), registryclient.NewOrDie(), policyContext, cfg)
|
||||
|
||||
assert.Equal(t, er.PolicyResponse.Rules[0].Status, response.RuleStatusFail)
|
||||
assert.Equal(t, er.PolicyResponse.Rules[0].Message,
|
||||
|
@ -1929,7 +1929,7 @@ func Test_VariableSubstitutionValidate_VariablesInMessageAreResolved(t *testing.
|
|||
jsonContext: ctx,
|
||||
newResource: *resourceUnstructured,
|
||||
}
|
||||
er := Validate(context.TODO(), registryclient.NewOrDie(), policyContext)
|
||||
er := Validate(context.TODO(), registryclient.NewOrDie(), policyContext, cfg)
|
||||
assert.Equal(t, er.PolicyResponse.Rules[0].Status, response.RuleStatusFail)
|
||||
assert.Equal(t, er.PolicyResponse.Rules[0].Message, "The animal cow is not in the allowed list of animals.")
|
||||
}
|
||||
|
@ -1983,7 +1983,7 @@ func Test_Flux_Kustomization_PathNotPresent(t *testing.T) {
|
|||
jsonContext: ctx,
|
||||
newResource: *resourceUnstructured,
|
||||
}
|
||||
er := Validate(context.TODO(), registryclient.NewOrDie(), policyContext)
|
||||
er := Validate(context.TODO(), registryclient.NewOrDie(), policyContext, cfg)
|
||||
|
||||
for i, rule := range er.PolicyResponse.Rules {
|
||||
assert.Equal(t, er.PolicyResponse.Rules[i].Status, test.expectedResults[i], "\ntest %s failed\nexpected: %s\nactual: %s", test.name, test.expectedResults[i].String(), er.PolicyResponse.Rules[i].Status.String())
|
||||
|
@ -2149,7 +2149,7 @@ func executeTest(t *testing.T, test testCase) {
|
|||
jsonContext: ctx,
|
||||
}
|
||||
|
||||
resp := Validate(context.TODO(), registryclient.NewOrDie(), pc)
|
||||
resp := Validate(context.TODO(), registryclient.NewOrDie(), pc, cfg)
|
||||
if resp.IsSuccessful() && test.requestDenied {
|
||||
t.Errorf("Testcase has failed, policy: %v", policy.Name)
|
||||
}
|
||||
|
@ -2248,7 +2248,7 @@ func TestValidate_context_variable_substitution_CLI(t *testing.T) {
|
|||
msgs := []string{
|
||||
"restrict pod counts to be no more than 10 on node minikube",
|
||||
}
|
||||
er := Validate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()})
|
||||
er := Validate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()}, cfg)
|
||||
for index, r := range er.PolicyResponse.Rules {
|
||||
assert.Equal(t, r.Message, msgs[index])
|
||||
}
|
||||
|
@ -2337,7 +2337,7 @@ func Test_EmptyStringInDenyCondition(t *testing.T) {
|
|||
resourceUnstructured, err := utils.ConvertToUnstructured(resourceRaw)
|
||||
assert.NilError(t, err)
|
||||
|
||||
er := Validate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: ctx})
|
||||
er := Validate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: ctx}, cfg)
|
||||
assert.Assert(t, !er.IsSuccessful())
|
||||
}
|
||||
|
||||
|
@ -2426,7 +2426,7 @@ func Test_StringInDenyCondition(t *testing.T) {
|
|||
resourceUnstructured, err := utils.ConvertToUnstructured(resourceRaw)
|
||||
assert.NilError(t, err)
|
||||
|
||||
er := Validate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: ctx})
|
||||
er := Validate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: ctx}, cfg)
|
||||
assert.Assert(t, er.IsSuccessful())
|
||||
}
|
||||
|
||||
|
@ -3105,7 +3105,7 @@ func testForEach(t *testing.T, policyraw []byte, resourceRaw []byte, msg string,
|
|||
jsonContext: ctx,
|
||||
newResource: *resourceUnstructured,
|
||||
}
|
||||
er := Validate(context.TODO(), registryclient.NewOrDie(), policyContext)
|
||||
er := Validate(context.TODO(), registryclient.NewOrDie(), policyContext, cfg)
|
||||
|
||||
assert.Equal(t, er.PolicyResponse.Rules[0].Status, status)
|
||||
if msg != "" {
|
||||
|
@ -3169,7 +3169,7 @@ func Test_delete_ignore_pattern(t *testing.T) {
|
|||
jsonContext: ctx,
|
||||
newResource: *resourceUnstructured,
|
||||
}
|
||||
engineResponseCreate := Validate(context.TODO(), registryclient.NewOrDie(), policyContextCreate)
|
||||
engineResponseCreate := Validate(context.TODO(), registryclient.NewOrDie(), policyContextCreate, cfg)
|
||||
assert.Equal(t, len(engineResponseCreate.PolicyResponse.Rules), 1)
|
||||
assert.Equal(t, engineResponseCreate.PolicyResponse.Rules[0].Status, response.RuleStatusFail)
|
||||
|
||||
|
@ -3178,7 +3178,7 @@ func Test_delete_ignore_pattern(t *testing.T) {
|
|||
jsonContext: ctx,
|
||||
oldResource: *resourceUnstructured,
|
||||
}
|
||||
engineResponseDelete := Validate(context.TODO(), registryclient.NewOrDie(), policyContextDelete)
|
||||
engineResponseDelete := Validate(context.TODO(), registryclient.NewOrDie(), policyContextDelete, cfg)
|
||||
assert.Equal(t, len(engineResponseDelete.PolicyResponse.Rules), 0)
|
||||
}
|
||||
|
||||
|
@ -3237,7 +3237,7 @@ func Test_ValidatePattern_anyPattern(t *testing.T) {
|
|||
resourceUnstructured, err := utils.ConvertToUnstructured(tc.rawResource)
|
||||
assert.NilError(t, err)
|
||||
|
||||
er := Validate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()})
|
||||
er := Validate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()}, cfg)
|
||||
if tc.expectedFailed {
|
||||
assert.Assert(t, er.IsFailed())
|
||||
} else if tc.expectedSkipped {
|
||||
|
|
|
@ -11,6 +11,7 @@ import (
|
|||
"github.com/go-logr/logr"
|
||||
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
|
||||
"github.com/kyverno/kyverno/pkg/clients/dclient"
|
||||
"github.com/kyverno/kyverno/pkg/config"
|
||||
"github.com/kyverno/kyverno/pkg/engine"
|
||||
enginecontext "github.com/kyverno/kyverno/pkg/engine/context"
|
||||
"github.com/kyverno/kyverno/pkg/engine/context/resolvers"
|
||||
|
@ -31,6 +32,7 @@ func applyPolicy(
|
|||
rclient registryclient.Client,
|
||||
informerCacheResolvers resolvers.ConfigmapResolver,
|
||||
namespaceLabels map[string]string,
|
||||
cfg config.Configuration,
|
||||
) (responses []*response.EngineResponse) {
|
||||
startTime := time.Now()
|
||||
defer func() {
|
||||
|
@ -61,7 +63,7 @@ func applyPolicy(
|
|||
logger.Error(err, "failed to add namespace to ctx")
|
||||
}
|
||||
|
||||
if err := ctx.AddImageInfos(&resource); err != nil {
|
||||
if err := ctx.AddImageInfos(&resource, cfg); err != nil {
|
||||
logger.Error(err, "unable to add image info to variables context")
|
||||
}
|
||||
|
||||
|
@ -82,7 +84,7 @@ func applyPolicy(
|
|||
WithExcludeGroupRole(excludeGroupRole...).
|
||||
WithInformerCacheResolver(informerCacheResolvers)
|
||||
|
||||
engineResponseValidation = engine.Validate(context.TODO(), rclient, policyCtx)
|
||||
engineResponseValidation = engine.Validate(context.TODO(), rclient, policyCtx, cfg)
|
||||
engineResponses = append(engineResponses, mergeRuleRespose(engineResponseMutation, engineResponseValidation))
|
||||
|
||||
return engineResponses
|
||||
|
|
|
@ -460,7 +460,7 @@ func (pc *PolicyController) applyPolicy(policy kyvernov1.PolicyInterface, resour
|
|||
}
|
||||
|
||||
namespaceLabels := engineutils.GetNamespaceSelectorsFromNamespaceLister(resource.GetKind(), resource.GetNamespace(), pc.nsLister, logger)
|
||||
engineResponse := applyPolicy(policy, resource, logger, pc.configHandler.GetExcludeGroupRole(), pc.client, pc.rclient, pc.informerCacheResolvers, namespaceLabels)
|
||||
engineResponse := applyPolicy(policy, resource, logger, pc.configHandler.GetExcludeGroupRole(), pc.client, pc.rclient, pc.informerCacheResolvers, namespaceLabels, pc.configHandler)
|
||||
engineResponses = append(engineResponses, engineResponse...)
|
||||
|
||||
// post-processing, register the resource as processed
|
||||
|
|
|
@ -97,7 +97,7 @@ func validateJSONPatch(patch string, ruleIdx int) error {
|
|||
for _, operation := range decodedPatch {
|
||||
op := operation.Kind()
|
||||
if op != "add" && op != "remove" && op != "replace" {
|
||||
return fmt.Errorf("Unexpected kind: spec.rules[%d]: %s", ruleIdx, op)
|
||||
return fmt.Errorf("unexpected kind: spec.rules[%d]: %s", ruleIdx, op)
|
||||
}
|
||||
v, _ := operation.ValueInterface()
|
||||
if v != nil {
|
||||
|
|
|
@ -1732,7 +1732,7 @@ func Test_ValidateJSON6902(t *testing.T) {
|
|||
op: addition
|
||||
value: "nginx"`
|
||||
err := validateJSONPatch(patch, 0)
|
||||
assert.Error(t, err, "Unexpected kind: spec.rules[0]: addition")
|
||||
assert.Error(t, err, "unexpected kind: spec.rules[0]: addition")
|
||||
|
||||
patch = `- path: "/metadata/labels/img"
|
||||
op: add
|
||||
|
|
|
@ -13,6 +13,7 @@ import (
|
|||
|
||||
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
|
||||
"github.com/kyverno/kyverno/pkg/clients/dclient"
|
||||
"github.com/kyverno/kyverno/pkg/config"
|
||||
"github.com/kyverno/kyverno/pkg/engine"
|
||||
"github.com/kyverno/kyverno/pkg/engine/response"
|
||||
"github.com/kyverno/kyverno/pkg/registryclient"
|
||||
|
@ -158,7 +159,8 @@ func runTestCase(t *testing.T, tc TestCase) bool {
|
|||
|
||||
policyContext = policyContext.WithNewResource(*resource)
|
||||
|
||||
er = engine.Validate(context.TODO(), registryclient.NewOrDie(), policyContext)
|
||||
cfg := config.NewDefaultConfiguration()
|
||||
er = engine.Validate(context.TODO(), registryclient.NewOrDie(), policyContext, cfg)
|
||||
t.Log("---Validation---")
|
||||
validateResponse(t, er.PolicyResponse, tc.Expected.Validation.PolicyResponse)
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
"strings"
|
||||
|
||||
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
|
||||
"github.com/kyverno/kyverno/pkg/config"
|
||||
imageutils "github.com/kyverno/kyverno/pkg/utils/image"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
)
|
||||
|
@ -39,15 +40,15 @@ type imageExtractor struct {
|
|||
Name string
|
||||
}
|
||||
|
||||
func (i *imageExtractor) ExtractFromResource(resource interface{}) (map[string]ImageInfo, error) {
|
||||
func (i *imageExtractor) ExtractFromResource(resource interface{}, cfg config.Configuration) (map[string]ImageInfo, error) {
|
||||
imageInfo := map[string]ImageInfo{}
|
||||
if err := extract(resource, []string{}, i.Key, i.Value, i.Fields, &imageInfo); err != nil {
|
||||
if err := extract(resource, []string{}, i.Key, i.Value, i.Fields, &imageInfo, cfg); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return imageInfo, nil
|
||||
}
|
||||
|
||||
func extract(obj interface{}, path []string, keyPath, valuePath string, fields []string, imageInfos *map[string]ImageInfo) error {
|
||||
func extract(obj interface{}, path []string, keyPath, valuePath string, fields []string, imageInfos *map[string]ImageInfo, cfg config.Configuration) error {
|
||||
if obj == nil {
|
||||
return nil
|
||||
}
|
||||
|
@ -55,13 +56,13 @@ func extract(obj interface{}, path []string, keyPath, valuePath string, fields [
|
|||
switch typedObj := obj.(type) {
|
||||
case []interface{}:
|
||||
for i, v := range typedObj {
|
||||
if err := extract(v, append(path, strconv.Itoa(i)), keyPath, valuePath, fields[1:], imageInfos); err != nil {
|
||||
if err := extract(v, append(path, strconv.Itoa(i)), keyPath, valuePath, fields[1:], imageInfos, cfg); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
case map[string]interface{}:
|
||||
for i, v := range typedObj {
|
||||
if err := extract(v, append(path, i), keyPath, valuePath, fields[1:], imageInfos); err != nil {
|
||||
if err := extract(v, append(path, i), keyPath, valuePath, fields[1:], imageInfos, cfg); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
@ -89,7 +90,7 @@ func extract(obj interface{}, path []string, keyPath, valuePath string, fields [
|
|||
if !ok {
|
||||
return fmt.Errorf("invalid value")
|
||||
}
|
||||
if imageInfo, err := imageutils.GetImageInfo(value); err != nil {
|
||||
if imageInfo, err := imageutils.GetImageInfo(value, cfg); err != nil {
|
||||
return fmt.Errorf("invalid image %s", value)
|
||||
} else {
|
||||
(*imageInfos)[key] = ImageInfo{*imageInfo, pointer}
|
||||
|
@ -98,7 +99,7 @@ func extract(obj interface{}, path []string, keyPath, valuePath string, fields [
|
|||
}
|
||||
|
||||
currentPath := fields[0]
|
||||
return extract(output[currentPath], append(path, currentPath), keyPath, valuePath, fields[1:], imageInfos)
|
||||
return extract(output[currentPath], append(path, currentPath), keyPath, valuePath, fields[1:], imageInfos, cfg)
|
||||
}
|
||||
|
||||
func BuildStandardExtractors(tags ...string) []imageExtractor {
|
||||
|
@ -150,7 +151,7 @@ func lookupImageExtractor(kind string, configs kyvernov1.ImageExtractorConfigs)
|
|||
return registeredExtractors[kind]
|
||||
}
|
||||
|
||||
func ExtractImagesFromResource(resource unstructured.Unstructured, configs kyvernov1.ImageExtractorConfigs) (map[string]map[string]ImageInfo, error) {
|
||||
func ExtractImagesFromResource(resource unstructured.Unstructured, configs kyvernov1.ImageExtractorConfigs, cfg config.Configuration) (map[string]map[string]ImageInfo, error) {
|
||||
infos := map[string]map[string]ImageInfo{}
|
||||
|
||||
extractors := lookupImageExtractor(resource.GetKind(), configs)
|
||||
|
@ -159,7 +160,7 @@ func ExtractImagesFromResource(resource unstructured.Unstructured, configs kyver
|
|||
}
|
||||
|
||||
for _, extractor := range extractors {
|
||||
if infoMap, err := extractor.ExtractFromResource(resource.Object); err != nil {
|
||||
if infoMap, err := extractor.ExtractFromResource(resource.Object, cfg); err != nil {
|
||||
return nil, err
|
||||
} else if len(infoMap) > 0 {
|
||||
infos[extractor.Name] = infoMap
|
||||
|
|
|
@ -4,11 +4,14 @@ import (
|
|||
"testing"
|
||||
|
||||
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
|
||||
"github.com/kyverno/kyverno/pkg/config"
|
||||
"github.com/kyverno/kyverno/pkg/engine/utils"
|
||||
imageutils "github.com/kyverno/kyverno/pkg/utils/image"
|
||||
"gotest.tools/assert"
|
||||
)
|
||||
|
||||
var cfg = config.NewDefaultConfiguration()
|
||||
|
||||
func Test_extractImageInfo(t *testing.T) {
|
||||
tests := []struct {
|
||||
extractionConfig kyvernov1.ImageExtractorConfigs
|
||||
|
@ -219,7 +222,7 @@ func Test_extractImageInfo(t *testing.T) {
|
|||
for _, test := range tests {
|
||||
resource, err := utils.ConvertToUnstructured(test.raw)
|
||||
assert.NilError(t, err)
|
||||
images, err := ExtractImagesFromResource(*resource, test.extractionConfig)
|
||||
images, err := ExtractImagesFromResource(*resource, test.extractionConfig, cfg)
|
||||
assert.NilError(t, err)
|
||||
assert.DeepEqual(t, test.images, images)
|
||||
}
|
||||
|
|
|
@ -1,12 +1,17 @@
|
|||
package image
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/distribution/distribution/reference"
|
||||
"github.com/kyverno/kyverno/pkg/config"
|
||||
"github.com/pkg/errors"
|
||||
"sigs.k8s.io/controller-runtime/pkg/log"
|
||||
)
|
||||
|
||||
var logger = log.Log.WithName("image")
|
||||
|
||||
type ImageInfo struct {
|
||||
// Registry is the URL address of the image registry e.g. `docker.io`
|
||||
Registry string `json:"registry,omitempty"`
|
||||
|
@ -25,40 +30,73 @@ type ImageInfo struct {
|
|||
}
|
||||
|
||||
func (i *ImageInfo) String() string {
|
||||
image := i.Registry + "/" + i.Path
|
||||
if i.Digest != "" {
|
||||
return image + "@" + i.Digest
|
||||
var image string
|
||||
if i.Registry != "" {
|
||||
image = fmt.Sprintf("%s/%s", i.Registry, i.Path)
|
||||
} else {
|
||||
return image + ":" + i.Tag
|
||||
image = i.Path
|
||||
}
|
||||
if i.Digest != "" {
|
||||
return fmt.Sprintf("%s@%s", image, i.Digest)
|
||||
} else {
|
||||
return fmt.Sprintf("%s:%s", image, i.Tag)
|
||||
}
|
||||
}
|
||||
|
||||
func (i *ImageInfo) ReferenceWithTag() string {
|
||||
return i.Registry + "/" + i.Path + ":" + i.Tag
|
||||
if i.Registry != "" {
|
||||
return fmt.Sprintf("%s/%s:%s", i.Registry, i.Path, i.Tag)
|
||||
} else {
|
||||
return fmt.Sprintf("%s:%s", i.Path, i.Tag)
|
||||
}
|
||||
}
|
||||
|
||||
func GetImageInfo(image string) (*ImageInfo, error) {
|
||||
image = addDefaultDomain(image)
|
||||
ref, err := reference.Parse(image)
|
||||
func GetImageInfo(image string, cfg config.Configuration) (*ImageInfo, error) {
|
||||
logger.V(2).Info(
|
||||
"Getting the image info",
|
||||
image, "image",
|
||||
"defaultRegistry", config.Configuration.GetDefaultRegistry(cfg),
|
||||
"enableDefaultRegistryMutation", config.Configuration.GetEnableDefaultRegistryMutation(cfg),
|
||||
)
|
||||
// adding the default domain in order to properly parse image info
|
||||
fullImageName := addDefaultRegistry(image, cfg)
|
||||
ref, err := reference.Parse(fullImageName)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "bad image: %s", image)
|
||||
return nil, errors.Wrapf(err, "bad image: %s", fullImageName)
|
||||
}
|
||||
|
||||
var registry, path, name, tag, digest string
|
||||
if named, ok := ref.(reference.Named); ok {
|
||||
registry = reference.Domain(named)
|
||||
path = reference.Path(named)
|
||||
name = path[strings.LastIndex(path, "/")+1:]
|
||||
}
|
||||
|
||||
if tagged, ok := ref.(reference.Tagged); ok {
|
||||
tag = tagged.Tag()
|
||||
}
|
||||
if digested, ok := ref.(reference.Digested); ok {
|
||||
digest = digested.Digest().String()
|
||||
}
|
||||
// set default tag - the domain is set via addDefaultDomain before parsing
|
||||
// set default tag - the domain is set via addDefaultRegistry before parsing
|
||||
if digest == "" && tag == "" {
|
||||
tag = "latest"
|
||||
}
|
||||
// if registry mutation isn't enabled don't add the default registry
|
||||
if fullImageName != image && !config.Configuration.GetEnableDefaultRegistryMutation(cfg) {
|
||||
registry = ""
|
||||
}
|
||||
|
||||
logger.V(2).Info(
|
||||
"Getting the image info",
|
||||
"image", image,
|
||||
"registry", registry,
|
||||
"name", name,
|
||||
"path", path,
|
||||
"tag", tag,
|
||||
"digest", digest,
|
||||
)
|
||||
|
||||
return &ImageInfo{
|
||||
Registry: registry,
|
||||
Name: name,
|
||||
|
@ -68,10 +106,11 @@ func GetImageInfo(image string) (*ImageInfo, error) {
|
|||
}, nil
|
||||
}
|
||||
|
||||
func addDefaultDomain(name string) string {
|
||||
// addDefaultRegistry always adds default registry
|
||||
func addDefaultRegistry(name string, cfg config.Configuration) string {
|
||||
i := strings.IndexRune(name, '/')
|
||||
if i == -1 || (!strings.ContainsAny(name[:i], ".:") && name[:i] != "localhost" && strings.ToLower(name[:i]) == name[:i]) {
|
||||
return "docker.io/" + name
|
||||
name = fmt.Sprintf("%s/%s", config.Configuration.GetDefaultRegistry(cfg), name)
|
||||
}
|
||||
return name
|
||||
}
|
||||
|
|
|
@ -1,11 +1,33 @@
|
|||
package image
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"testing"
|
||||
|
||||
"github.com/kyverno/kyverno/pkg/config"
|
||||
"github.com/stretchr/testify/assert"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/client-go/kubernetes/fake"
|
||||
)
|
||||
|
||||
// initializeMockConfig initializes a basic configuration with a fake dynamic client
|
||||
func initializeMockConfig(defaultRegistry string, enableDefaultRegistryMutation bool) (config.Configuration, error) {
|
||||
configMapData := make(map[string]string, 0)
|
||||
configMapData["defaultRegistry"] = defaultRegistry
|
||||
configMapData["enableDefaultRegistryMutation"] = strconv.FormatBool(enableDefaultRegistryMutation)
|
||||
cm := v1.ConfigMap{
|
||||
ObjectMeta: metav1.ObjectMeta{Namespace: "kyverno", Name: "kyverno"},
|
||||
Data: configMapData,
|
||||
}
|
||||
cs := fake.NewSimpleClientset(&cm)
|
||||
dynamicConfig, err := config.NewConfiguration(cs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return dynamicConfig, nil
|
||||
}
|
||||
|
||||
func Test_GetImageInfo(t *testing.T) {
|
||||
validateImageInfo(t,
|
||||
"nginx",
|
||||
|
@ -14,7 +36,9 @@ func Test_GetImageInfo(t *testing.T) {
|
|||
"docker.io",
|
||||
"latest",
|
||||
"",
|
||||
"docker.io/nginx:latest")
|
||||
"docker.io/nginx:latest",
|
||||
"docker.io",
|
||||
true)
|
||||
|
||||
validateImageInfo(t,
|
||||
"nginx:v10.3",
|
||||
|
@ -23,7 +47,9 @@ func Test_GetImageInfo(t *testing.T) {
|
|||
"docker.io",
|
||||
"v10.3",
|
||||
"",
|
||||
"docker.io/nginx:v10.3")
|
||||
"docker.io/nginx:v10.3",
|
||||
"docker.io",
|
||||
true)
|
||||
|
||||
validateImageInfo(t,
|
||||
"docker.io/test/nginx:v10.3",
|
||||
|
@ -32,7 +58,9 @@ func Test_GetImageInfo(t *testing.T) {
|
|||
"docker.io",
|
||||
"v10.3",
|
||||
"",
|
||||
"docker.io/test/nginx:v10.3")
|
||||
"docker.io/test/nginx:v10.3",
|
||||
"docker.io",
|
||||
true)
|
||||
|
||||
validateImageInfo(t,
|
||||
"test/nginx",
|
||||
|
@ -41,7 +69,9 @@ func Test_GetImageInfo(t *testing.T) {
|
|||
"docker.io",
|
||||
"latest",
|
||||
"",
|
||||
"docker.io/test/nginx:latest")
|
||||
"docker.io/test/nginx:latest",
|
||||
"docker.io",
|
||||
true)
|
||||
|
||||
validateImageInfo(t,
|
||||
"localhost:4443/test/nginx",
|
||||
|
@ -50,7 +80,10 @@ func Test_GetImageInfo(t *testing.T) {
|
|||
"localhost:4443",
|
||||
"latest",
|
||||
"",
|
||||
"localhost:4443/test/nginx:latest")
|
||||
"localhost:4443/test/nginx:latest",
|
||||
"docker.io",
|
||||
true)
|
||||
|
||||
validateImageInfo(t,
|
||||
"docker.io/test/centos@sha256:dead07b4d8ed7e29e98de0f4504d87e8880d4347859d839686a31da35a3b532f",
|
||||
"centos",
|
||||
|
@ -58,7 +91,31 @@ func Test_GetImageInfo(t *testing.T) {
|
|||
"docker.io",
|
||||
"",
|
||||
"sha256:dead07b4d8ed7e29e98de0f4504d87e8880d4347859d839686a31da35a3b532f",
|
||||
"docker.io/test/centos@sha256:dead07b4d8ed7e29e98de0f4504d87e8880d4347859d839686a31da35a3b532f")
|
||||
"docker.io/test/centos@sha256:dead07b4d8ed7e29e98de0f4504d87e8880d4347859d839686a31da35a3b532f",
|
||||
"docker.io",
|
||||
true)
|
||||
|
||||
validateImageInfo(t,
|
||||
"test/nginx",
|
||||
"nginx",
|
||||
"test/nginx",
|
||||
"gcr.io",
|
||||
"latest",
|
||||
"",
|
||||
"gcr.io/test/nginx:latest",
|
||||
"gcr.io",
|
||||
true)
|
||||
|
||||
validateImageInfo(t,
|
||||
"test/nginx",
|
||||
"nginx",
|
||||
"test/nginx",
|
||||
"",
|
||||
"latest",
|
||||
"",
|
||||
"test/nginx:latest",
|
||||
"gcr.io",
|
||||
false)
|
||||
}
|
||||
|
||||
func Test_ReferenceWithTag(t *testing.T) {
|
||||
|
@ -84,8 +141,10 @@ func Test_ReferenceWithTag(t *testing.T) {
|
|||
input: "docker.io/test/centos@sha256:dead07b4d8ed7e29e98de0f4504d87e8880d4347859d839686a31da35a3b532f",
|
||||
expected: "docker.io/test/centos:",
|
||||
}}
|
||||
cfg, err := initializeMockConfig("docker.io", true)
|
||||
assert.NoError(t, err)
|
||||
for _, test := range testCases {
|
||||
imageInfo, err := GetImageInfo(test.input)
|
||||
imageInfo, err := GetImageInfo(test.input, cfg)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, test.expected, imageInfo.ReferenceWithTag())
|
||||
}
|
||||
|
@ -95,15 +154,20 @@ func Test_ParseError(t *testing.T) {
|
|||
testCases := []string{
|
||||
"++",
|
||||
}
|
||||
cfg, err := initializeMockConfig("docker.io", true)
|
||||
assert.NoError(t, err)
|
||||
for _, test := range testCases {
|
||||
imageInfo, err := GetImageInfo(test)
|
||||
|
||||
imageInfo, err := GetImageInfo(test, cfg)
|
||||
assert.Error(t, err)
|
||||
assert.Nil(t, imageInfo)
|
||||
}
|
||||
}
|
||||
|
||||
func validateImageInfo(t *testing.T, raw, name, path, registry, tag, digest, str string) {
|
||||
i1, err := GetImageInfo(raw)
|
||||
func validateImageInfo(t *testing.T, raw, name, path, registry, tag, digest, str string, defautRegistry string, enableDefaultRegistryMutation bool) {
|
||||
cfg, err := initializeMockConfig(defautRegistry, enableDefaultRegistryMutation)
|
||||
assert.NoError(t, err)
|
||||
i1, err := GetImageInfo(raw, cfg)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, name, i1.Name)
|
||||
assert.Equal(t, path, i1.Path)
|
||||
|
@ -112,3 +176,56 @@ func validateImageInfo(t *testing.T, raw, name, path, registry, tag, digest, str
|
|||
assert.Equal(t, digest, i1.Digest)
|
||||
assert.Equal(t, str, i1.String())
|
||||
}
|
||||
|
||||
func Test_addDefaultRegistry(t *testing.T) {
|
||||
tests := []struct {
|
||||
input string
|
||||
defaultRegistry string
|
||||
enableDefaultRegistryMutation bool
|
||||
want string
|
||||
}{
|
||||
{
|
||||
defaultRegistry: "test.io",
|
||||
enableDefaultRegistryMutation: true,
|
||||
input: "docker.io/test/nginx:v10.4",
|
||||
want: "docker.io/test/nginx:v10.4",
|
||||
},
|
||||
{
|
||||
defaultRegistry: "docker.io",
|
||||
enableDefaultRegistryMutation: true,
|
||||
input: "test/nginx:v10.3",
|
||||
want: "docker.io/test/nginx:v10.3",
|
||||
},
|
||||
{
|
||||
defaultRegistry: "myregistry.io",
|
||||
enableDefaultRegistryMutation: false,
|
||||
input: "test/nginx:v10.6",
|
||||
want: "myregistry.io/test/nginx:v10.6",
|
||||
},
|
||||
{
|
||||
input: "localhost/netd:v0.4.4-gke.0",
|
||||
defaultRegistry: "docker.io",
|
||||
enableDefaultRegistryMutation: true,
|
||||
want: "localhost/netd:v0.4.4-gke.0",
|
||||
},
|
||||
{
|
||||
input: "myregistry.org/test/nginx:v10.3",
|
||||
defaultRegistry: "docker.io",
|
||||
enableDefaultRegistryMutation: false,
|
||||
want: "myregistry.org/test/nginx:v10.3",
|
||||
},
|
||||
{
|
||||
input: "test/centos@sha256:dead07b4d8ed7e29e98de0f4504d87e8880d4347859d839686a31da35a3b532f",
|
||||
defaultRegistry: "docker.io",
|
||||
enableDefaultRegistryMutation: true,
|
||||
want: "docker.io/test/centos@sha256:dead07b4d8ed7e29e98de0f4504d87e8880d4347859d839686a31da35a3b532f",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
cfg, err := initializeMockConfig(tt.defaultRegistry, true)
|
||||
assert.NoError(t, err)
|
||||
got := addDefaultRegistry(tt.input, cfg)
|
||||
assert.Equal(t, tt.want, got)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -137,7 +137,7 @@ func (h *handlers) Validate(ctx context.Context, logger logr.Logger, request *ad
|
|||
namespaceLabels = engineutils.GetNamespaceSelectorsFromNamespaceLister(request.Kind.Kind, request.Namespace, h.nsLister, logger)
|
||||
}
|
||||
|
||||
vh := validation.NewValidationHandler(logger, h.kyvernoClient, h.rclient, h.pCache, h.pcBuilder, h.eventGen, h.admissionReports, h.metricsConfig)
|
||||
vh := validation.NewValidationHandler(logger, h.kyvernoClient, h.rclient, h.pCache, h.pcBuilder, h.eventGen, h.admissionReports, h.metricsConfig, h.configuration)
|
||||
|
||||
ok, msg, warnings := vh.HandleValidation(ctx, request, policies, policyContext, namespaceLabels, startTime)
|
||||
if !ok {
|
||||
|
@ -184,7 +184,7 @@ func (h *handlers) Mutate(ctx context.Context, logger logr.Logger, request *admi
|
|||
logger.Error(err, "failed to build policy context")
|
||||
return admissionutils.Response(request.UID, err)
|
||||
}
|
||||
ivh := imageverification.NewImageVerificationHandler(logger, h.kyvernoClient, h.rclient, h.eventGen, h.admissionReports)
|
||||
ivh := imageverification.NewImageVerificationHandler(logger, h.kyvernoClient, h.rclient, h.eventGen, h.admissionReports, h.configuration)
|
||||
imagePatches, imageVerifyWarnings, err := ivh.Handle(ctx, newRequest, verifyImagesPolicies, policyContext)
|
||||
if err != nil {
|
||||
logger.Error(err, "image verification failed")
|
||||
|
|
|
@ -9,6 +9,7 @@ import (
|
|||
"github.com/go-logr/logr"
|
||||
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
|
||||
"github.com/kyverno/kyverno/pkg/client/clientset/versioned"
|
||||
"github.com/kyverno/kyverno/pkg/config"
|
||||
"github.com/kyverno/kyverno/pkg/engine"
|
||||
"github.com/kyverno/kyverno/pkg/engine/response"
|
||||
"github.com/kyverno/kyverno/pkg/event"
|
||||
|
@ -35,6 +36,7 @@ type imageVerificationHandler struct {
|
|||
log logr.Logger
|
||||
eventGen event.Interface
|
||||
admissionReports bool
|
||||
cfg config.Configuration
|
||||
}
|
||||
|
||||
func NewImageVerificationHandler(
|
||||
|
@ -43,6 +45,7 @@ func NewImageVerificationHandler(
|
|||
rclient registryclient.Client,
|
||||
eventGen event.Interface,
|
||||
admissionReports bool,
|
||||
cfg config.Configuration,
|
||||
) ImageVerificationHandler {
|
||||
return &imageVerificationHandler{
|
||||
kyvernoClient: kyvernoClient,
|
||||
|
@ -50,6 +53,7 @@ func NewImageVerificationHandler(
|
|||
log: log,
|
||||
eventGen: eventGen,
|
||||
admissionReports: admissionReports,
|
||||
cfg: cfg,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -87,7 +91,7 @@ func (h *imageVerificationHandler) handleVerifyImages(
|
|||
fmt.Sprintf("POLICY %s/%s", policy.GetNamespace(), policy.GetName()),
|
||||
func(ctx context.Context, span trace.Span) {
|
||||
policyContext := policyContext.WithPolicy(policy)
|
||||
resp, ivm := engine.VerifyAndPatchImages(ctx, h.rclient, policyContext)
|
||||
resp, ivm := engine.VerifyAndPatchImages(ctx, h.rclient, policyContext, h.cfg)
|
||||
|
||||
engineResponses = append(engineResponses, resp)
|
||||
patches = append(patches, resp.GetPatches()...)
|
||||
|
|
|
@ -9,6 +9,7 @@ import (
|
|||
"github.com/go-logr/logr"
|
||||
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
|
||||
"github.com/kyverno/kyverno/pkg/client/clientset/versioned"
|
||||
"github.com/kyverno/kyverno/pkg/config"
|
||||
"github.com/kyverno/kyverno/pkg/engine"
|
||||
"github.com/kyverno/kyverno/pkg/engine/response"
|
||||
"github.com/kyverno/kyverno/pkg/event"
|
||||
|
@ -43,6 +44,7 @@ func NewValidationHandler(
|
|||
eventGen event.Interface,
|
||||
admissionReports bool,
|
||||
metrics metrics.MetricsConfigManager,
|
||||
cfg config.Configuration,
|
||||
) ValidationHandler {
|
||||
return &validationHandler{
|
||||
log: log,
|
||||
|
@ -53,6 +55,7 @@ func NewValidationHandler(
|
|||
eventGen: eventGen,
|
||||
admissionReports: admissionReports,
|
||||
metrics: metrics,
|
||||
cfg: cfg,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -65,6 +68,7 @@ type validationHandler struct {
|
|||
eventGen event.Interface
|
||||
admissionReports bool
|
||||
metrics metrics.MetricsConfigManager
|
||||
cfg config.Configuration
|
||||
}
|
||||
|
||||
func (v *validationHandler) HandleValidation(
|
||||
|
@ -110,7 +114,7 @@ func (v *validationHandler) HandleValidation(
|
|||
failurePolicy = kyvernov1.Fail
|
||||
}
|
||||
|
||||
engineResponse := engine.Validate(ctx, v.rclient, policyContext)
|
||||
engineResponse := engine.Validate(ctx, v.rclient, policyContext, v.cfg)
|
||||
if engineResponse.IsNil() {
|
||||
// we get an empty response if old and new resources created the same response
|
||||
// allow updates if resource update doesnt change the policy evaluation
|
||||
|
@ -169,7 +173,7 @@ func (v *validationHandler) buildAuditResponses(
|
|||
fmt.Sprintf("POLICY %s/%s", policy.GetNamespace(), policy.GetName()),
|
||||
func(ctx context.Context, span trace.Span) {
|
||||
policyContext := policyContext.WithPolicy(policy).WithNamespaceLabels(namespaceLabels)
|
||||
responses = append(responses, engine.Validate(ctx, v.rclient, policyContext))
|
||||
responses = append(responses, engine.Validate(ctx, v.rclient, policyContext, v.cfg))
|
||||
},
|
||||
)
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/kyverno/kyverno/pkg/config"
|
||||
log "github.com/kyverno/kyverno/pkg/logging"
|
||||
"github.com/kyverno/kyverno/pkg/registryclient"
|
||||
|
||||
|
@ -34,7 +35,7 @@ func TestValidate_failure_action_overrides(t *testing.T) {
|
|||
},
|
||||
"spec": {
|
||||
"validationFailureAction": "audit",
|
||||
"validationFailureActionOverrides":
|
||||
"validationFailureActionOverrides":
|
||||
[
|
||||
{
|
||||
"action": "enforce",
|
||||
|
@ -104,7 +105,7 @@ func TestValidate_failure_action_overrides(t *testing.T) {
|
|||
},
|
||||
"spec": {
|
||||
"validationFailureAction": "audit",
|
||||
"validationFailureActionOverrides":
|
||||
"validationFailureActionOverrides":
|
||||
[
|
||||
{
|
||||
"action": "enforce",
|
||||
|
@ -176,7 +177,7 @@ func TestValidate_failure_action_overrides(t *testing.T) {
|
|||
},
|
||||
"spec": {
|
||||
"validationFailureAction": "audit",
|
||||
"validationFailureActionOverrides":
|
||||
"validationFailureActionOverrides":
|
||||
[
|
||||
{
|
||||
"action": "enforce",
|
||||
|
@ -246,7 +247,7 @@ func TestValidate_failure_action_overrides(t *testing.T) {
|
|||
},
|
||||
"spec": {
|
||||
"validationFailureAction": "enforce",
|
||||
"validationFailureActionOverrides":
|
||||
"validationFailureActionOverrides":
|
||||
[
|
||||
{
|
||||
"action": "enforce",
|
||||
|
@ -316,7 +317,7 @@ func TestValidate_failure_action_overrides(t *testing.T) {
|
|||
},
|
||||
"spec": {
|
||||
"validationFailureAction": "enforce",
|
||||
"validationFailureActionOverrides":
|
||||
"validationFailureActionOverrides":
|
||||
[
|
||||
{
|
||||
"action": "enforce",
|
||||
|
@ -388,7 +389,7 @@ func TestValidate_failure_action_overrides(t *testing.T) {
|
|||
},
|
||||
"spec": {
|
||||
"validationFailureAction": "enforce",
|
||||
"validationFailureActionOverrides":
|
||||
"validationFailureActionOverrides":
|
||||
[
|
||||
{
|
||||
"action": "enforce",
|
||||
|
@ -458,7 +459,7 @@ func TestValidate_failure_action_overrides(t *testing.T) {
|
|||
},
|
||||
"spec": {
|
||||
"validationFailureAction": "enforce",
|
||||
"validationFailureActionOverrides":
|
||||
"validationFailureActionOverrides":
|
||||
[
|
||||
{
|
||||
"action": "enforce",
|
||||
|
@ -523,6 +524,7 @@ func TestValidate_failure_action_overrides(t *testing.T) {
|
|||
},
|
||||
}
|
||||
|
||||
cfg := config.NewDefaultConfiguration()
|
||||
for i, tc := range testcases {
|
||||
t.Run(fmt.Sprintf("case %d", i), func(t *testing.T) {
|
||||
var policy kyvernov1.ClusterPolicy
|
||||
|
@ -535,6 +537,7 @@ func TestValidate_failure_action_overrides(t *testing.T) {
|
|||
context.TODO(),
|
||||
registryclient.NewOrDie(),
|
||||
engine.NewPolicyContext().WithPolicy(&policy).WithNewResource(*resourceUnstructured),
|
||||
cfg,
|
||||
)
|
||||
if tc.blocked && tc.messages != nil {
|
||||
for _, r := range er.PolicyResponse.Rules {
|
||||
|
@ -563,7 +566,7 @@ func Test_RuleSelector(t *testing.T) {
|
|||
"match": {"name": "test-*", "resources": {"kinds": ["Pod"]}},
|
||||
"validate": {
|
||||
"message": "The label 'app' is required.",
|
||||
"pattern": { "metadata": { "labels": { "app": "?*" } } }
|
||||
"pattern": { "metadata": { "labels": { "app": "?*" } } }
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -571,7 +574,7 @@ func Test_RuleSelector(t *testing.T) {
|
|||
"match": {"name": "*", "resources": {"kinds": ["Pod"]}},
|
||||
"validate": {
|
||||
"message": "The label 'app' is required.",
|
||||
"pattern": { "metadata": { "labels": { "app": "?*", "test" : "?*" } } }
|
||||
"pattern": { "metadata": { "labels": { "app": "?*", "test" : "?*" } } }
|
||||
}
|
||||
}
|
||||
]
|
||||
|
@ -595,7 +598,8 @@ func Test_RuleSelector(t *testing.T) {
|
|||
|
||||
ctx := engine.NewPolicyContext().WithPolicy(&policy).WithNewResource(*resourceUnstructured)
|
||||
|
||||
resp := engine.Validate(context.TODO(), registryclient.NewOrDie(), ctx)
|
||||
cfg := config.NewDefaultConfiguration()
|
||||
resp := engine.Validate(context.TODO(), registryclient.NewOrDie(), ctx, cfg)
|
||||
assert.Assert(t, resp.PolicyResponse.RulesAppliedCount == 2)
|
||||
assert.Assert(t, resp.PolicyResponse.RulesErrorCount == 0)
|
||||
|
||||
|
@ -606,7 +610,7 @@ func Test_RuleSelector(t *testing.T) {
|
|||
applyOne := kyvernov1.ApplyOne
|
||||
policy.Spec.ApplyRules = &applyOne
|
||||
|
||||
resp = engine.Validate(context.TODO(), registryclient.NewOrDie(), ctx)
|
||||
resp = engine.Validate(context.TODO(), registryclient.NewOrDie(), ctx, cfg)
|
||||
assert.Assert(t, resp.PolicyResponse.RulesAppliedCount == 1)
|
||||
assert.Assert(t, resp.PolicyResponse.RulesErrorCount == 0)
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue