mirror of
https://github.com/kyverno/kyverno.git
synced 2025-03-22 07:41:10 +00:00
feat(vp): implement gctx in context library (#12055)
* feat(vp): implement gctx in context library Signed-off-by: Khaled Emara <khaled.emara@nirmata.com> * test(cel): add chainsaw test for validating policies gctx Signed-off-by: Khaled Emara <khaled.emara@nirmata.com> --------- Signed-off-by: Khaled Emara <khaled.emara@nirmata.com> Signed-off-by: ShutingZhao <shuting@nirmata.com> Co-authored-by: Vishal Choudhary <vishal.choudhary@nirmata.com> Co-authored-by: shuting <shuting@nirmata.com> Co-authored-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com>
This commit is contained in:
parent
637f756994
commit
c61d0735e3
16 changed files with 314 additions and 27 deletions
|
@ -35,6 +35,7 @@ import (
|
||||||
"github.com/kyverno/kyverno/pkg/clients/dclient"
|
"github.com/kyverno/kyverno/pkg/clients/dclient"
|
||||||
"github.com/kyverno/kyverno/pkg/config"
|
"github.com/kyverno/kyverno/pkg/config"
|
||||||
engineapi "github.com/kyverno/kyverno/pkg/engine/api"
|
engineapi "github.com/kyverno/kyverno/pkg/engine/api"
|
||||||
|
gctxstore "github.com/kyverno/kyverno/pkg/globalcontext/store"
|
||||||
"github.com/kyverno/kyverno/pkg/imageverification/imagedataloader"
|
"github.com/kyverno/kyverno/pkg/imageverification/imagedataloader"
|
||||||
gitutils "github.com/kyverno/kyverno/pkg/utils/git"
|
gitutils "github.com/kyverno/kyverno/pkg/utils/git"
|
||||||
policyvalidation "github.com/kyverno/kyverno/pkg/validation/policy"
|
policyvalidation "github.com/kyverno/kyverno/pkg/validation/policy"
|
||||||
|
@ -348,11 +349,13 @@ func (c *ApplyCommandConfig) applyValidatingPolicies(
|
||||||
}
|
}
|
||||||
eng := engine.NewEngine(provider, namespaceProvider, matching.NewMatcher())
|
eng := engine.NewEngine(provider, namespaceProvider, matching.NewMatcher())
|
||||||
// TODO: mock when no cluster provided
|
// TODO: mock when no cluster provided
|
||||||
|
gctxStore := gctxstore.New()
|
||||||
var contextProvider celpolicy.Context
|
var contextProvider celpolicy.Context
|
||||||
if dclient != nil {
|
if dclient != nil {
|
||||||
contextProvider, err = celpolicy.NewContextProvider(
|
contextProvider, err = celpolicy.NewContextProvider(
|
||||||
dclient,
|
dclient,
|
||||||
[]imagedataloader.Option{imagedataloader.WithLocalCredentials(c.RegistryAccess)},
|
[]imagedataloader.Option{imagedataloader.WithLocalCredentials(c.RegistryAccess)},
|
||||||
|
gctxStore,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
|
@ -593,9 +593,11 @@ func main() {
|
||||||
backgroundServiceAccountName,
|
backgroundServiceAccountName,
|
||||||
reportsServiceAccountName,
|
reportsServiceAccountName,
|
||||||
)
|
)
|
||||||
|
|
||||||
contextProvider, err := celpolicy.NewContextProvider(
|
contextProvider, err := celpolicy.NewContextProvider(
|
||||||
setup.KyvernoDynamicClient,
|
setup.KyvernoDynamicClient,
|
||||||
nil,
|
nil,
|
||||||
|
gcstore,
|
||||||
// []imagedataloader.Option{imagedataloader.WithLocalCredentials(c.RegistryAccess)},
|
// []imagedataloader.Option{imagedataloader.WithLocalCredentials(c.RegistryAccess)},
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -27,13 +27,18 @@ func (c *impl) get_configmap_string_string(args ...ref.Val) ref.Val {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *impl) get_globalreference_string(ctx ref.Val, name ref.Val) ref.Val {
|
func (c *impl) get_globalreference_string(args ...ref.Val) ref.Val {
|
||||||
if self, err := utils.ConvertToNative[Context](ctx); err != nil {
|
if len(args) != 3 {
|
||||||
|
return types.NewErr("expected 3 arguments, got %d", len(args))
|
||||||
|
}
|
||||||
|
if self, err := utils.ConvertToNative[Context](args[0]); err != nil {
|
||||||
return types.WrapErr(err)
|
return types.WrapErr(err)
|
||||||
} else if name, err := utils.ConvertToNative[string](name); err != nil {
|
} else if name, err := utils.ConvertToNative[string](args[1]); err != nil {
|
||||||
|
return types.WrapErr(err)
|
||||||
|
} else if projection, err := utils.ConvertToNative[string](args[2]); err != nil {
|
||||||
return types.WrapErr(err)
|
return types.WrapErr(err)
|
||||||
} else {
|
} else {
|
||||||
globalRef, err := self.GetGlobalReference(name)
|
globalRef, err := self.GetGlobalReference(name, projection)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// Errors are not expected here since Parse is a more lenient parser than ParseRequestURI.
|
// Errors are not expected here since Parse is a more lenient parser than ParseRequestURI.
|
||||||
return types.NewErr("failed to get global reference: %v", err)
|
return types.NewErr("failed to get global reference: %v", err)
|
||||||
|
|
|
@ -2,10 +2,12 @@ package context
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/google/cel-go/cel"
|
"github.com/google/cel-go/cel"
|
||||||
|
"github.com/kyverno/kyverno/pkg/globalcontext/store"
|
||||||
"github.com/kyverno/kyverno/pkg/imageverification/imagedataloader"
|
"github.com/kyverno/kyverno/pkg/imageverification/imagedataloader"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||||
|
@ -13,7 +15,7 @@ import (
|
||||||
|
|
||||||
type ctx struct {
|
type ctx struct {
|
||||||
GetConfigMapFunc func(string, string) (unstructured.Unstructured, error)
|
GetConfigMapFunc func(string, string) (unstructured.Unstructured, error)
|
||||||
GetGlobalReferenceFunc func(string) (any, error)
|
GetGlobalReferenceFunc func(string, string) (any, error)
|
||||||
GetImageDataFunc func(string) (*imagedataloader.ImageData, error)
|
GetImageDataFunc func(string) (*imagedataloader.ImageData, error)
|
||||||
ListResourcesFunc func(string, string, string) (*unstructured.UnstructuredList, error)
|
ListResourcesFunc func(string, string, string) (*unstructured.UnstructuredList, error)
|
||||||
GetResourcesFunc func(string, string, string, string) (*unstructured.Unstructured, error)
|
GetResourcesFunc func(string, string, string, string) (*unstructured.Unstructured, error)
|
||||||
|
@ -23,8 +25,8 @@ func (mock *ctx) GetConfigMap(ns string, n string) (unstructured.Unstructured, e
|
||||||
return mock.GetConfigMapFunc(ns, n)
|
return mock.GetConfigMapFunc(ns, n)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (mock *ctx) GetGlobalReference(n string) (any, error) {
|
func (mock *ctx) GetGlobalReference(n, p string) (any, error) {
|
||||||
return mock.GetGlobalReferenceFunc(n)
|
return mock.GetGlobalReferenceFunc(n, p)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (mock *ctx) GetImageData(n string) (*imagedataloader.ImageData, error) {
|
func (mock *ctx) GetImageData(n string) (*imagedataloader.ImageData, error) {
|
||||||
|
@ -71,6 +73,33 @@ func Test_impl_get_configmap_string_string(t *testing.T) {
|
||||||
assert.True(t, called)
|
assert.True(t, called)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type mockGctxStore struct {
|
||||||
|
data map[string]store.Entry
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *mockGctxStore) Get(name string) (store.Entry, bool) {
|
||||||
|
entry, ok := m.data[name]
|
||||||
|
return entry, ok
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *mockGctxStore) Set(name string, data store.Entry) {
|
||||||
|
if m.data == nil {
|
||||||
|
m.data = make(map[string]store.Entry)
|
||||||
|
}
|
||||||
|
m.data[name] = data
|
||||||
|
}
|
||||||
|
|
||||||
|
type mockEntry struct {
|
||||||
|
data any
|
||||||
|
err error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *mockEntry) Get(_ string) (any, error) {
|
||||||
|
return m.data, m.err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *mockEntry) Stop() {}
|
||||||
|
|
||||||
func Test_impl_get_globalreference_string(t *testing.T) {
|
func Test_impl_get_globalreference_string(t *testing.T) {
|
||||||
opts := Lib()
|
opts := Lib()
|
||||||
base, err := cel.NewEnv(opts)
|
base, err := cel.NewEnv(opts)
|
||||||
|
@ -82,28 +111,83 @@ func Test_impl_get_globalreference_string(t *testing.T) {
|
||||||
env, err := base.Extend(options...)
|
env, err := base.Extend(options...)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.NotNil(t, env)
|
assert.NotNil(t, env)
|
||||||
ast, issues := env.Compile(`context.GetGlobalReference("foo")`)
|
ast, issues := env.Compile(`context.GetGlobalReference("foo", "bar")`)
|
||||||
assert.Nil(t, issues)
|
assert.Nil(t, issues)
|
||||||
assert.NotNil(t, ast)
|
assert.NotNil(t, ast)
|
||||||
prog, err := env.Program(ast)
|
prog, err := env.Program(ast)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.NotNil(t, prog)
|
assert.NotNil(t, prog)
|
||||||
called := false
|
|
||||||
data := map[string]any{
|
tests := []struct {
|
||||||
"context": Context{&ctx{
|
name string
|
||||||
GetGlobalReferenceFunc: func(string) (any, error) {
|
gctxStoreData map[string]store.Entry
|
||||||
type foo struct {
|
expectedValue any
|
||||||
s string
|
expectedError string
|
||||||
}
|
}{
|
||||||
called = true
|
{
|
||||||
return foo{"bar"}, nil
|
name: "global context entry not found",
|
||||||
|
gctxStoreData: map[string]store.Entry{},
|
||||||
|
expectedError: "global context entry not found",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "global context entry returns error",
|
||||||
|
gctxStoreData: map[string]store.Entry{
|
||||||
|
"foo": &mockEntry{err: errors.New("get entry error")},
|
||||||
},
|
},
|
||||||
}},
|
expectedError: "get entry error",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "global context entry returns string",
|
||||||
|
gctxStoreData: map[string]store.Entry{
|
||||||
|
"foo": &mockEntry{data: "stringValue"},
|
||||||
|
},
|
||||||
|
expectedValue: "stringValue",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "global context entry returns map",
|
||||||
|
gctxStoreData: map[string]store.Entry{
|
||||||
|
"foo": &mockEntry{data: map[string]interface{}{"key": "value"}},
|
||||||
|
},
|
||||||
|
expectedValue: map[string]interface{}{"key": "value"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
mockStore := &mockGctxStore{data: tt.gctxStoreData}
|
||||||
|
data := map[string]any{
|
||||||
|
"context": Context{&ctx{
|
||||||
|
GetGlobalReferenceFunc: func(name string, path string) (any, error) {
|
||||||
|
ent, ok := mockStore.Get(name)
|
||||||
|
if !ok {
|
||||||
|
return nil, errors.New("global context entry not found")
|
||||||
|
}
|
||||||
|
return ent.Get(path)
|
||||||
|
},
|
||||||
|
}},
|
||||||
|
}
|
||||||
|
out, _, err := prog.Eval(data)
|
||||||
|
|
||||||
|
if tt.expectedError != "" {
|
||||||
|
assert.Error(t, err)
|
||||||
|
assert.Contains(t, err.Error(), tt.expectedError)
|
||||||
|
} else {
|
||||||
|
assert.NoError(t, err)
|
||||||
|
if tt.expectedValue == nil {
|
||||||
|
assert.Nil(t, out.Value())
|
||||||
|
} else {
|
||||||
|
assert.NotNil(t, out)
|
||||||
|
if expectedUnstructured, ok := tt.expectedValue.(unstructured.Unstructured); ok {
|
||||||
|
actualUnstructured, ok := out.Value().(unstructured.Unstructured)
|
||||||
|
assert.True(t, ok, "Expected unstructured.Unstructured, got %T", out.Value())
|
||||||
|
assert.Equal(t, expectedUnstructured, actualUnstructured)
|
||||||
|
} else {
|
||||||
|
assert.Equal(t, tt.expectedValue, out.Value())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
out, _, err := prog.Eval(data)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
assert.NotNil(t, out)
|
|
||||||
assert.True(t, called)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func Test_impl_get_imagedata_string(t *testing.T) {
|
func Test_impl_get_imagedata_string(t *testing.T) {
|
||||||
|
|
|
@ -52,7 +52,7 @@ func (c *lib) extendEnv(env *cel.Env) (*cel.Env, error) {
|
||||||
},
|
},
|
||||||
"GetGlobalReference": {
|
"GetGlobalReference": {
|
||||||
// TODO: should not use DynType in return
|
// TODO: should not use DynType in return
|
||||||
cel.MemberOverload("get_globalreference_string", []*cel.Type{ContextType, types.StringType}, types.DynType, cel.BinaryBinding(impl.get_globalreference_string)),
|
cel.MemberOverload("get_globalreference_string", []*cel.Type{ContextType, types.StringType, types.StringType}, types.DynType, cel.FunctionBinding(impl.get_globalreference_string)),
|
||||||
},
|
},
|
||||||
"GetImageData": {
|
"GetImageData": {
|
||||||
// TODO: should not use DynType in return
|
// TODO: should not use DynType in return
|
||||||
|
|
|
@ -15,7 +15,7 @@ var (
|
||||||
|
|
||||||
type ContextInterface interface {
|
type ContextInterface interface {
|
||||||
GetConfigMap(string, string) (unstructured.Unstructured, error)
|
GetConfigMap(string, string) (unstructured.Unstructured, error)
|
||||||
GetGlobalReference(string) (any, error)
|
GetGlobalReference(string, string) (any, error)
|
||||||
GetImageData(string) (*imagedataloader.ImageData, error)
|
GetImageData(string) (*imagedataloader.ImageData, error)
|
||||||
ListResource(apiVersion, resource, namespace string) (*unstructured.UnstructuredList, error)
|
ListResource(apiVersion, resource, namespace string) (*unstructured.UnstructuredList, error)
|
||||||
GetResource(apiVersion, resource, namespace, name string) (*unstructured.Unstructured, error)
|
GetResource(apiVersion, resource, namespace, name string) (*unstructured.Unstructured, error)
|
||||||
|
|
|
@ -2,14 +2,18 @@ package policy
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
|
||||||
contextlib "github.com/kyverno/kyverno/pkg/cel/libs/context"
|
contextlib "github.com/kyverno/kyverno/pkg/cel/libs/context"
|
||||||
"github.com/kyverno/kyverno/pkg/clients/dclient"
|
"github.com/kyverno/kyverno/pkg/clients/dclient"
|
||||||
"github.com/kyverno/kyverno/pkg/config"
|
"github.com/kyverno/kyverno/pkg/config"
|
||||||
|
gctxstore "github.com/kyverno/kyverno/pkg/globalcontext/store"
|
||||||
"github.com/kyverno/kyverno/pkg/imageverification/imagedataloader"
|
"github.com/kyverno/kyverno/pkg/imageverification/imagedataloader"
|
||||||
kubeutils "github.com/kyverno/kyverno/pkg/utils/kube"
|
kubeutils "github.com/kyverno/kyverno/pkg/utils/kube"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||||
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||||
"k8s.io/client-go/dynamic"
|
"k8s.io/client-go/dynamic"
|
||||||
"k8s.io/client-go/kubernetes"
|
"k8s.io/client-go/kubernetes"
|
||||||
|
@ -21,9 +25,14 @@ type contextProvider struct {
|
||||||
client kubernetes.Interface
|
client kubernetes.Interface
|
||||||
dclient dynamic.Interface
|
dclient dynamic.Interface
|
||||||
imagedata imagedataloader.Fetcher
|
imagedata imagedataloader.Fetcher
|
||||||
|
gctxStore gctxstore.Store
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewContextProvider(client dclient.Interface, imageOpts []imagedataloader.Option) (Context, error) {
|
func NewContextProvider(
|
||||||
|
client dclient.Interface,
|
||||||
|
imageOpts []imagedataloader.Option,
|
||||||
|
gctxStore gctxstore.Store,
|
||||||
|
) (Context, error) {
|
||||||
idl, err := imagedataloader.New(client.GetKubeClient().CoreV1().Secrets(config.KyvernoNamespace()), imageOpts...)
|
idl, err := imagedataloader.New(client.GetKubeClient().CoreV1().Secrets(config.KyvernoNamespace()), imageOpts...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -32,6 +41,7 @@ func NewContextProvider(client dclient.Interface, imageOpts []imagedataloader.Op
|
||||||
client: client.GetKubeClient(),
|
client: client.GetKubeClient(),
|
||||||
dclient: client.GetDynamicInterface(),
|
dclient: client.GetDynamicInterface(),
|
||||||
imagedata: idl,
|
imagedata: idl,
|
||||||
|
gctxStore: gctxStore,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -47,8 +57,38 @@ func (cp *contextProvider) GetConfigMap(namespace string, name string) (unstruct
|
||||||
return *out, nil
|
return *out, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cp *contextProvider) GetGlobalReference(string) (any, error) {
|
func (cp *contextProvider) GetGlobalReference(name, projection string) (any, error) {
|
||||||
return nil, nil
|
ent, ok := cp.gctxStore.Get(name)
|
||||||
|
if !ok {
|
||||||
|
return nil, errors.New("global context entry not found")
|
||||||
|
}
|
||||||
|
data, err := ent.Get(projection)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if isLikelyKubernetesObject(data) {
|
||||||
|
out, err := kubeutils.ObjToUnstructured(data)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if out != nil {
|
||||||
|
return *out, nil
|
||||||
|
} else {
|
||||||
|
return nil, errors.New("failed to convert to Unstructured")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
raw, err := json.Marshal(data)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
apiData := map[string]interface{}{}
|
||||||
|
err = json.Unmarshal(raw, &apiData)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return data, nil
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cp *contextProvider) GetImageData(image string) (*imagedataloader.ImageData, error) {
|
func (cp *contextProvider) GetImageData(image string) (*imagedataloader.ImageData, error) {
|
||||||
|
@ -56,6 +96,24 @@ func (cp *contextProvider) GetImageData(image string) (*imagedataloader.ImageDat
|
||||||
return cp.imagedata.FetchImageData(context.TODO(), image)
|
return cp.imagedata.FetchImageData(context.TODO(), image)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func isLikelyKubernetesObject(data any) bool {
|
||||||
|
if data == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if m, ok := data.(map[string]interface{}); ok {
|
||||||
|
_, hasAPIVersion := m["apiVersion"]
|
||||||
|
_, hasKind := m["kind"]
|
||||||
|
return hasAPIVersion && hasKind
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, ok := data.(runtime.Object); ok {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
func (cp *contextProvider) ListResource(apiVersion, resource, namespace string) (*unstructured.UnstructuredList, error) {
|
func (cp *contextProvider) ListResource(apiVersion, resource, namespace string) (*unstructured.UnstructuredList, error) {
|
||||||
groupVersion, err := schema.ParseGroupVersion(apiVersion)
|
groupVersion, err := schema.ParseGroupVersion(apiVersion)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -16,6 +16,7 @@ import (
|
||||||
"github.com/kyverno/kyverno/pkg/engine"
|
"github.com/kyverno/kyverno/pkg/engine"
|
||||||
engineapi "github.com/kyverno/kyverno/pkg/engine/api"
|
engineapi "github.com/kyverno/kyverno/pkg/engine/api"
|
||||||
"github.com/kyverno/kyverno/pkg/engine/jmespath"
|
"github.com/kyverno/kyverno/pkg/engine/jmespath"
|
||||||
|
gctxstore "github.com/kyverno/kyverno/pkg/globalcontext/store"
|
||||||
reportutils "github.com/kyverno/kyverno/pkg/utils/report"
|
reportutils "github.com/kyverno/kyverno/pkg/utils/report"
|
||||||
"go.uber.org/multierr"
|
"go.uber.org/multierr"
|
||||||
admissionv1 "k8s.io/api/admission/v1"
|
admissionv1 "k8s.io/api/admission/v1"
|
||||||
|
@ -154,12 +155,14 @@ func (s *scanner) ScanResource(
|
||||||
func(name string) *corev1.Namespace { return ns },
|
func(name string) *corev1.Namespace { return ns },
|
||||||
matching.NewMatcher(),
|
matching.NewMatcher(),
|
||||||
)
|
)
|
||||||
|
gctxStore := gctxstore.New()
|
||||||
// create context provider
|
// create context provider
|
||||||
context, err := celpolicy.NewContextProvider(
|
context, err := celpolicy.NewContextProvider(
|
||||||
s.client,
|
s.client,
|
||||||
nil,
|
nil,
|
||||||
// TODO
|
// TODO
|
||||||
// []imagedataloader.Option{imagedataloader.WithLocalCredentials(c.RegistryAccess)},
|
// []imagedataloader.Option{imagedataloader.WithLocalCredentials(c.RegistryAccess)},
|
||||||
|
gctxStore,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error(err, "failed to create cel context provider")
|
logger.Error(err, "failed to create cel context provider")
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
## Description
|
||||||
|
|
||||||
|
This test verifies that Global Context Entries are evaluated correctly.
|
||||||
|
|
||||||
|
## Expected Behavior
|
||||||
|
|
||||||
|
`new-deployment` should be created.
|
||||||
|
|
||||||
|
## Reference Issues
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
apiVersion: chainsaw.kyverno.io/v1alpha1
|
||||||
|
kind: Test
|
||||||
|
metadata:
|
||||||
|
name: apicall-correct
|
||||||
|
spec:
|
||||||
|
steps:
|
||||||
|
- try:
|
||||||
|
- apply:
|
||||||
|
file: namespace.yaml
|
||||||
|
- apply:
|
||||||
|
file: main-deployment.yaml
|
||||||
|
- apply:
|
||||||
|
file: gctxentry.yaml
|
||||||
|
- sleep:
|
||||||
|
duration: 3s
|
||||||
|
- name: create policy
|
||||||
|
try:
|
||||||
|
- create:
|
||||||
|
file: policy.yaml
|
||||||
|
- sleep:
|
||||||
|
duration: 3s
|
||||||
|
- try:
|
||||||
|
- apply:
|
||||||
|
file: new-deployment.yaml
|
||||||
|
- assert:
|
||||||
|
file: new-deployment-exists.yaml
|
|
@ -0,0 +1,8 @@
|
||||||
|
apiVersion: kyverno.io/v2alpha1
|
||||||
|
kind: GlobalContextEntry
|
||||||
|
metadata:
|
||||||
|
name: gctxentry-apicall-correct
|
||||||
|
spec:
|
||||||
|
apiCall:
|
||||||
|
urlPath: "/apis/apps/v1/namespaces/test-globalcontext-apicall-correct/deployments"
|
||||||
|
refreshInterval: 1h
|
|
@ -0,0 +1,28 @@
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: main-deployment
|
||||||
|
namespace: test-globalcontext-apicall-correct
|
||||||
|
labels:
|
||||||
|
app: main-deployment
|
||||||
|
spec:
|
||||||
|
replicas: 1
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: main-deployment
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: main-deployment
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: pause
|
||||||
|
image: registry.k8s.io/pause:latest
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 10m
|
||||||
|
memory: 10Mi
|
||||||
|
limits:
|
||||||
|
cpu: 10m
|
||||||
|
memory: 10Mi
|
||||||
|
terminationGracePeriodSeconds: 0
|
|
@ -0,0 +1,4 @@
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Namespace
|
||||||
|
metadata:
|
||||||
|
name: test-globalcontext-apicall-correct
|
|
@ -0,0 +1,7 @@
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: new-deployment
|
||||||
|
namespace: test-globalcontext-apicall-correct
|
||||||
|
labels:
|
||||||
|
app: new-deployment
|
|
@ -0,0 +1,28 @@
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: new-deployment
|
||||||
|
namespace: test-globalcontext-apicall-correct
|
||||||
|
labels:
|
||||||
|
app: new-deployment
|
||||||
|
spec:
|
||||||
|
replicas: 1
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: new-deployment
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: new-deployment
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: pause
|
||||||
|
image: registry.k8s.io/pause:latest
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 10m
|
||||||
|
memory: 10Mi
|
||||||
|
limits:
|
||||||
|
cpu: 10m
|
||||||
|
memory: 10Mi
|
||||||
|
terminationGracePeriodSeconds: 0
|
|
@ -0,0 +1,20 @@
|
||||||
|
apiVersion: policies.kyverno.io/v1alpha1
|
||||||
|
kind: ValidatingPolicy
|
||||||
|
metadata:
|
||||||
|
name: cpol-apicall-correct
|
||||||
|
spec:
|
||||||
|
matchConstraints:
|
||||||
|
resourceRules:
|
||||||
|
- apiGroups: []
|
||||||
|
apiVersions: [v1]
|
||||||
|
operations: [CREATE, UPDATE]
|
||||||
|
resources: [pods]
|
||||||
|
variables:
|
||||||
|
- name: dcount
|
||||||
|
expression: >-
|
||||||
|
context.GetGlobalReference("gctxentry-apicall-correct", "")
|
||||||
|
validations:
|
||||||
|
- expression: >-
|
||||||
|
variables.dcount != 0
|
||||||
|
message: >-
|
||||||
|
main-deployment should exist
|
Loading…
Add table
Reference in a new issue