package resource_test import ( "errors" "testing" "github.com/google/cel-go/cel" engine "github.com/kyverno/kyverno/pkg/cel" "github.com/kyverno/kyverno/pkg/cel/resource" "github.com/stretchr/testify/assert" "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/kube-openapi/pkg/validation/spec" ) func testSchema() *spec.Schema { // Manual construction of a schema with the following definition: // // schema: // type: object // metadata: // custom_type: "CustomObject" // required: // - name // - value // properties: // name: // type: string // nested: // type: object // properties: // subname: // type: string // flags: // type: object // additionalProperties: // type: boolean // dates: // type: array // items: // type: string // format: date-time // metadata: // type: object // additionalProperties: // type: object // properties: // key: // type: string // values: // type: array // items: string // value: // type: integer // format: int64 // default: 1 // enum: [1,2,3] return &spec.Schema{ SchemaProps: spec.SchemaProps{ Type: []string{"object"}, Properties: map[string]spec.Schema{ "name": *spec.StringProperty(), "value": {SchemaProps: spec.SchemaProps{ Type: []string{"integer"}, Default: int64(1), Format: "int64", Enum: []any{1, 2, 3}, }}, "nested": {SchemaProps: spec.SchemaProps{ Type: []string{"object"}, Properties: map[string]spec.Schema{ "subname": *spec.StringProperty(), "flags": {SchemaProps: spec.SchemaProps{ Type: []string{"object"}, AdditionalProperties: &spec.SchemaOrBool{ Schema: spec.BooleanProperty(), }, }}, "dates": {SchemaProps: spec.SchemaProps{ Type: []string{"array"}, Items: &spec.SchemaOrArray{Schema: &spec.Schema{ SchemaProps: spec.SchemaProps{ Type: []string{"string"}, Format: "date-time", }}}}}, }, }, }, "metadata": {SchemaProps: spec.SchemaProps{ Type: []string{"object"}, Properties: map[string]spec.Schema{ "name": *spec.StringProperty(), "value": { SchemaProps: spec.SchemaProps{ Type: []string{"array"}, Items: &spec.SchemaOrArray{Schema: &spec.Schema{ SchemaProps: spec.SchemaProps{ Type: []string{"string"}, }}}, }, }, }, }}, }}} } type TestClient struct{} func (_ TestClient) ResolveSchema(gvk schema.GroupVersionKind) (*spec.Schema, error) { return testSchema(), nil } func TestOpenAPITypeResolver(t *testing.T) { typeName := "self" s := schema.FromAPIVersionAndKind("v1", "CustomObject") resolver := resource.NewOpenAPITypeResolver(TestClient{}) provider, err := resolver.GetDeclProvier(s, typeName) if err != nil { t.Fatal(err.Error()) } env, err := engine.NewEnv() opts, err := provider.EnvOptions(env.CELTypeProvider()) rootType, ok := provider.FindDeclType(typeName) if !ok { t.Fatal("declaration type not found") } opts = append(opts, cel.Variable("object", rootType.CelType())) env, err = env.Extend(opts...) ast, issue := env.Compile(`object.name != ""`) if issue != nil { t.Fatal(issue.Err().Error()) } prog, err := env.Program(ast) if err != nil { t.Fatal(err.Error()) } _, _, err = prog.Eval(map[string]any{ "object": map[string]any{ "name": "test", }, }) if err != nil { t.Fatal(err.Error()) } } type TestClientError struct{} func (_ TestClientError) ResolveSchema(gvk schema.GroupVersionKind) (*spec.Schema, error) { return nil, errors.New("dummy") } func TestOpenAPITypeResolverError(t *testing.T) { typeName := "self" s := schema.FromAPIVersionAndKind("v1", "CustomObject") resolver := resource.NewOpenAPITypeResolver(TestClientError{}) _, err := resolver.GetDeclProvier(s, typeName) assert.Error(t, err) }