1
0
Fork 0
mirror of https://github.com/kyverno/kyverno.git synced 2025-03-28 18:38:40 +00:00

refactor: move ImageExtractorConfigs in api package (#3781)

This commit is contained in:
Charles-Edouard Brétéché 2022-05-03 10:45:08 +02:00 committed by GitHub
parent 52d1b642d6
commit f70ef051dc
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 189 additions and 66 deletions

View file

@ -6,13 +6,33 @@ import (
"reflect"
wildcard "github.com/kyverno/go-wildcard"
"github.com/kyverno/kyverno/pkg/utils/kube"
"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions"
apiextv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
"k8s.io/apimachinery/pkg/util/sets"
"k8s.io/apimachinery/pkg/util/validation/field"
)
type ImageExtractorConfigs map[string][]ImageExtractorConfig
type ImageExtractorConfig struct {
// Path is the path to the object containing the image field in a custom resource.
// It should be slash-separated. Each slash-separated key must be a valid YAML key or a wildcard '*'.
// Wildcard keys are expanded in case of arrays or objects.
Path string `json:"path" yaml:"path"`
// Value is an optional name of the field within 'path' that points to the image URI.
// This is useful when a custom 'key' is also defined.
// +optional
Value string `json:"value,omitempty" yaml:"value,omitempty"`
// Name is the entry the image will be available under 'images.<name>' in the context.
// If this field is not defined, image entries will appear under 'images.custom'.
// +optional
Name string `json:"name,omitempty" yaml:"name,omitempty"`
// Key is an optional name of the field within 'path' that will be used to uniquely identify an image.
// Note - this field MUST be unique.
// +optional
Key string `json:"key,omitempty" yaml:"key,omitempty"`
}
// Rule defines a validation, mutation, or generation control for matching resources.
// Each rules contains a match declaration to select resources, and an optional exclude
// declaration to specify which resources to exclude.
@ -40,7 +60,7 @@ type Rule struct {
// ImageExtractors defines a mapping from kinds to ImageExtractorConfigs.
// This config is only valid for verifyImages rules.
// +optional
ImageExtractors kube.ImageExtractorConfigs `json:"imageExtractors,omitempty" yaml:"imageExtractors,omitempty"`
ImageExtractors ImageExtractorConfigs `json:"imageExtractors,omitempty" yaml:"imageExtractors,omitempty"`
// Preconditions are used to determine if a policy rule should be applied by evaluating a
// set of conditions. The declaration can contain nested `any` or `all` statements. A direct list

View file

@ -20,7 +20,6 @@ limitations under the License.
package v1
import (
"github.com/kyverno/kyverno/pkg/utils/kube"
rbacv1 "k8s.io/api/rbac/v1"
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@ -595,6 +594,50 @@ func (in *Generation) DeepCopy() *Generation {
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ImageExtractorConfig) DeepCopyInto(out *ImageExtractorConfig) {
*out = *in
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ImageExtractorConfig.
func (in *ImageExtractorConfig) DeepCopy() *ImageExtractorConfig {
if in == nil {
return nil
}
out := new(ImageExtractorConfig)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in ImageExtractorConfigs) DeepCopyInto(out *ImageExtractorConfigs) {
{
in := &in
*out = make(ImageExtractorConfigs, len(*in))
for key, val := range *in {
var outVal []ImageExtractorConfig
if val == nil {
(*out)[key] = nil
} else {
in, out := &val, &outVal
*out = make([]ImageExtractorConfig, len(*in))
copy(*out, *in)
}
(*out)[key] = outVal
}
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ImageExtractorConfigs.
func (in ImageExtractorConfigs) DeepCopy() ImageExtractorConfigs {
if in == nil {
return nil
}
out := new(ImageExtractorConfigs)
in.DeepCopyInto(out)
return *out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ImageRegistry) DeepCopyInto(out *ImageRegistry) {
*out = *in
@ -977,14 +1020,14 @@ func (in *Rule) DeepCopyInto(out *Rule) {
in.ExcludeResources.DeepCopyInto(&out.ExcludeResources)
if in.ImageExtractors != nil {
in, out := &in.ImageExtractors, &out.ImageExtractors
*out = make(kube.ImageExtractorConfigs, len(*in))
*out = make(ImageExtractorConfigs, len(*in))
for key, val := range *in {
var outVal []kube.ImageExtractorConfig
var outVal []ImageExtractorConfig
if val == nil {
(*out)[key] = nil
} else {
in, out := &val, &outVal
*out = make([]kube.ImageExtractorConfig, len(*in))
*out = make([]ImageExtractorConfig, len(*in))
copy(*out, *in)
}
(*out)[key] = outVal

View file

@ -1648,6 +1648,81 @@ resource will be created with default data only.</p>
</tbody>
</table>
<hr />
<h3 id="kyverno.io/v1.ImageExtractorConfig">ImageExtractorConfig
</h3>
<p>
</p>
<table class="table table-striped">
<thead class="thead-dark">
<tr>
<th>Field</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<code>path</code></br>
<em>
string
</em>
</td>
<td>
<p>Path is the path to the object containing the image field in a custom resource.
It should be slash-separated. Each slash-separated key must be a valid YAML key or a wildcard &lsquo;*&rsquo;.
Wildcard keys are expanded in case of arrays or objects.</p>
</td>
</tr>
<tr>
<td>
<code>value</code></br>
<em>
string
</em>
</td>
<td>
<em>(Optional)</em>
<p>Value is an optional name of the field within &lsquo;path&rsquo; that points to the image URI.
This is useful when a custom &lsquo;key&rsquo; is also defined.</p>
</td>
</tr>
<tr>
<td>
<code>name</code></br>
<em>
string
</em>
</td>
<td>
<em>(Optional)</em>
<p>Name is the entry the image will be available under &lsquo;images.<name>&rsquo; in the context.
If this field is not defined, image entries will appear under &lsquo;images.custom&rsquo;.</p>
</td>
</tr>
<tr>
<td>
<code>key</code></br>
<em>
string
</em>
</td>
<td>
<em>(Optional)</em>
<p>Key is an optional name of the field within &lsquo;path&rsquo; that will be used to uniquely identify an image.
Note - this field MUST be unique.</p>
</td>
</tr>
</tbody>
</table>
<hr />
<h3 id="kyverno.io/v1.ImageExtractorConfigs">ImageExtractorConfigs
(<code>map[string][]./api/kyverno/v1.ImageExtractorConfig</code> alias)</p></h3>
<p>
(<em>Appears on:</em>
<a href="#kyverno.io/v1.Rule">Rule</a>)
</p>
<p>
</p>
<h3 id="kyverno.io/v1.ImageRegistry">ImageRegistry
</h3>
<p>
@ -2607,7 +2682,9 @@ and admission review request information like the name or role.</p>
<td>
<code>imageExtractors</code></br>
<em>
github.com/kyverno/kyverno/pkg/utils/kube.ImageExtractorConfigs
<a href="#kyverno.io/v1.ImageExtractorConfigs">
ImageExtractorConfigs
</a>
</em>
</td>
<td>

View file

@ -6,9 +6,10 @@ import (
"sync"
jsonpatch "github.com/evanphx/json-patch/v5"
urkyverno "github.com/kyverno/kyverno/api/kyverno/v1beta1"
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
kyvernov1beta1 "github.com/kyverno/kyverno/api/kyverno/v1beta1"
pkgcommon "github.com/kyverno/kyverno/pkg/common"
kubeutils "github.com/kyverno/kyverno/pkg/utils/kube"
apiutils "github.com/kyverno/kyverno/pkg/utils/api"
"github.com/pkg/errors"
admissionv1 "k8s.io/api/admission/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
@ -50,7 +51,7 @@ type Interface interface {
AddOldResource(data map[string]interface{}) error
// AddUserInfo merges userInfo json under kyverno.userInfo
AddUserInfo(userInfo urkyverno.RequestInfo) error
AddUserInfo(userInfo kyvernov1beta1.RequestInfo) error
// AddServiceAccount merges ServiceAccount types
AddServiceAccount(userName string) error
@ -62,17 +63,17 @@ type Interface interface {
AddElement(data interface{}, index int) error
// AddImageInfo adds image info to the context
AddImageInfo(info kubeutils.ImageInfo) error
AddImageInfo(info apiutils.ImageInfo) error
// AddImageInfos adds image infos to the context
AddImageInfos(resource *unstructured.Unstructured) error
// ImageInfo returns image infos present in the context
ImageInfo() map[string]map[string]kubeutils.ImageInfo
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 kubeutils.ImageExtractorConfigs) (map[string]map[string]kubeutils.ImageInfo, error)
GenerateCustomImageInfo(resource *unstructured.Unstructured, imageExtractorConfigs kyvernov1.ImageExtractorConfigs) (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()
@ -94,7 +95,7 @@ type context struct {
mutex sync.RWMutex
jsonRaw []byte
jsonRawCheckpoints [][]byte
images map[string]map[string]kubeutils.ImageInfo
images map[string]map[string]apiutils.ImageInfo
}
// NewContext returns a new context
@ -166,7 +167,7 @@ func (ctx *context) AddOldResource(data map[string]interface{}) error {
}
// AddUserInfo adds userInfo at path request.userInfo
func (ctx *context) AddUserInfo(userRequestInfo urkyverno.RequestInfo) error {
func (ctx *context) AddUserInfo(userRequestInfo kyvernov1beta1.RequestInfo) error {
return addToContext(ctx, userRequestInfo, "request")
}
@ -231,7 +232,7 @@ func (ctx *context) AddElement(data interface{}, index int) error {
return addToContext(ctx, data)
}
func (ctx *context) AddImageInfo(info kubeutils.ImageInfo) error {
func (ctx *context) AddImageInfo(info apiutils.ImageInfo) error {
data := map[string]interface{}{
"image": info.String(),
"registry": info.Registry,
@ -247,7 +248,7 @@ func (ctx *context) AddImageInfos(resource *unstructured.Unstructured) error {
log.Log.V(4).Info("extracting image info", "obj", resource.UnstructuredContent())
images, err := kubeutils.ExtractImagesFromResource(*resource, nil)
images, err := apiutils.ExtractImagesFromResource(*resource, nil)
if err != nil {
return err
}
@ -261,8 +262,8 @@ func (ctx *context) AddImageInfos(resource *unstructured.Unstructured) error {
return addToContext(ctx, images, "images")
}
func (ctx *context) GenerateCustomImageInfo(resource *unstructured.Unstructured, imageExtractorConfigs kubeutils.ImageExtractorConfigs) (map[string]map[string]kubeutils.ImageInfo, error) {
images, err := kubeutils.ExtractImagesFromResource(*resource, imageExtractorConfigs)
func (ctx *context) GenerateCustomImageInfo(resource *unstructured.Unstructured, imageExtractorConfigs kyvernov1.ImageExtractorConfigs) (map[string]map[string]apiutils.ImageInfo, error) {
images, err := apiutils.ExtractImagesFromResource(*resource, imageExtractorConfigs)
if err != nil {
return nil, errors.Wrapf(err, "failed to extract images")
}
@ -275,7 +276,7 @@ func (ctx *context) GenerateCustomImageInfo(resource *unstructured.Unstructured,
return images, addToContext(ctx, images, "images")
}
func (ctx *context) ImageInfo() map[string]map[string]kubeutils.ImageInfo {
func (ctx *context) ImageInfo() map[string]map[string]apiutils.ImageInfo {
return ctx.images
}

View file

@ -21,7 +21,7 @@ import (
engineUtils "github.com/kyverno/kyverno/pkg/engine/utils"
"github.com/kyverno/kyverno/pkg/engine/variables"
"github.com/kyverno/kyverno/pkg/registryclient"
kubeutils "github.com/kyverno/kyverno/pkg/utils/kube"
apiutils "github.com/kyverno/kyverno/pkg/utils/api"
"github.com/pkg/errors"
"sigs.k8s.io/controller-runtime/pkg/log"
)
@ -139,7 +139,7 @@ type imageVerifier struct {
resp *response.EngineResponse
}
func (iv *imageVerifier) verify(imageVerify v1.ImageVerification, images map[string]map[string]kubeutils.ImageInfo) {
func (iv *imageVerifier) verify(imageVerify v1.ImageVerification, images map[string]map[string]apiutils.ImageInfo) {
// for backward compatibility
imageVerify = *imageVerify.Convert()
@ -193,7 +193,7 @@ func (iv *imageVerifier) verify(imageVerify v1.ImageVerification, images map[str
}
}
func (iv *imageVerifier) handleMutateDigest(digest string, imageInfo kubeutils.ImageInfo) ([]byte, error) {
func (iv *imageVerifier) handleMutateDigest(digest string, imageInfo apiutils.ImageInfo) ([]byte, error) {
if digest == "" {
digest, err := fetchImageDigest(imageInfo.String())
if err != nil {
@ -211,7 +211,7 @@ func (iv *imageVerifier) handleMutateDigest(digest string, imageInfo kubeutils.I
return patch, nil
}
func (iv *imageVerifier) markImageVerified(imageVerify v1.ImageVerification, ruleResp *response.RuleResponse, digest string, imageInfo kubeutils.ImageInfo) *response.RuleResponse {
func (iv *imageVerifier) markImageVerified(imageVerify v1.ImageVerification, ruleResp *response.RuleResponse, digest string, imageInfo apiutils.ImageInfo) *response.RuleResponse {
if hasImageVerifiedAnnotationChanged(iv.policyContext, imageInfo.Name, digest) {
msg := "changes to `images.kyverno.io` annotation are not allowed"
return ruleResponse(*iv.rule, response.ImageVerify, msg, response.RuleStatusFail, nil)
@ -243,7 +243,7 @@ func hasImageVerifiedAnnotationChanged(ctx *PolicyContext, name, digest string)
return newValue != oldValue
}
func makeImageVerifiedPatches(imageInfo kubeutils.ImageInfo, digest string, verified, hasAnnotations bool) ([][]byte, error) {
func makeImageVerifiedPatches(imageInfo apiutils.ImageInfo, digest string, verified, hasAnnotations bool) ([][]byte, error) {
var patches [][]byte
if !hasAnnotations {
var addAnnotationsPatch = make(map[string]interface{})
@ -314,7 +314,7 @@ func imageMatches(image string, imagePatterns []string) bool {
return false
}
func (iv *imageVerifier) verifySignatures(imageVerify v1.ImageVerification, imageInfo kubeutils.ImageInfo) (*response.RuleResponse, string) {
func (iv *imageVerifier) verifySignatures(imageVerify v1.ImageVerification, imageInfo apiutils.ImageInfo) (*response.RuleResponse, string) {
image := imageInfo.String()
iv.logger.V(2).Info("verifying image signatures", "image", image, "attestors", len(imageVerify.Attestors), "attestations", len(imageVerify.Attestations))
@ -479,7 +479,7 @@ func (iv *imageVerifier) buildOptionsAndPath(attestor v1.Attestor, imageVerify v
return opts, path
}
func makeAddDigestPatch(imageInfo kubeutils.ImageInfo, digest string) ([]byte, error) {
func makeAddDigestPatch(imageInfo apiutils.ImageInfo, digest string) ([]byte, error) {
var patch = make(map[string]interface{})
patch["op"] = "replace"
patch["path"] = imageInfo.Pointer
@ -487,7 +487,7 @@ func makeAddDigestPatch(imageInfo kubeutils.ImageInfo, digest string) ([]byte, e
return json.Marshal(patch)
}
func (iv *imageVerifier) verifyAttestations(imageVerify v1.ImageVerification, imageInfo kubeutils.ImageInfo) *response.RuleResponse {
func (iv *imageVerifier) verifyAttestations(imageVerify v1.ImageVerification, imageInfo apiutils.ImageInfo) *response.RuleResponse {
image := imageInfo.String()
start := time.Now()
@ -539,7 +539,7 @@ func buildStatementMap(statements []map[string]interface{}) map[string][]map[str
return results
}
func (iv *imageVerifier) checkAttestations(a v1.Attestation, s map[string]interface{}, img kubeutils.ImageInfo) (bool, error) {
func (iv *imageVerifier) checkAttestations(a v1.Attestation, s map[string]interface{}, img apiutils.ImageInfo) (bool, error) {
if len(a.Conditions) == 0 {
return true, nil
}

View file

@ -13,7 +13,7 @@ import (
gojmespath "github.com/jmespath/go-jmespath"
kyverno "github.com/kyverno/kyverno/api/kyverno/v1"
"github.com/kyverno/kyverno/pkg/engine/response"
kubeutils "github.com/kyverno/kyverno/pkg/utils/kube"
apiutils "github.com/kyverno/kyverno/pkg/utils/api"
"github.com/pkg/errors"
)
@ -61,7 +61,7 @@ func processImageValidationRule(log logr.Logger, ctx *PolicyContext, rule *kyver
return ruleResponse(*rule, response.Validation, "image verified", response.RuleStatusPass, nil)
}
func validateImage(ctx *PolicyContext, imageVerify *kyverno.ImageVerification, imageInfo kubeutils.ImageInfo) error {
func validateImage(ctx *PolicyContext, imageVerify *kyverno.ImageVerification, imageInfo apiutils.ImageInfo) error {
image := imageInfo.String()
if imageVerify.VerifyDigest && imageInfo.Digest == "" {
log.Log.Info("missing digest", "request.object", ctx.NewResource.UnstructuredContent())
@ -87,7 +87,7 @@ type ImageVerificationMetadata struct {
Digest string `json:"digest,omitempty"`
}
func isImageVerified(ctx *PolicyContext, imageInfo kubeutils.ImageInfo) (bool, error) {
func isImageVerified(ctx *PolicyContext, imageInfo apiutils.ImageInfo) (bool, error) {
if reflect.DeepEqual(ctx.NewResource, unstructured.Unstructured{}) {
return false, errors.Errorf("resource does not exist")
}

View file

@ -6,7 +6,6 @@ import (
"strings"
"testing"
kubeutils "github.com/kyverno/kyverno/pkg/utils/kube"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"sigs.k8s.io/controller-runtime/pkg/log"
@ -15,6 +14,7 @@ import (
"github.com/kyverno/kyverno/pkg/engine/context"
"github.com/kyverno/kyverno/pkg/engine/response"
"github.com/kyverno/kyverno/pkg/engine/utils"
apiutils "github.com/kyverno/kyverno/pkg/utils/api"
"gotest.tools/assert"
)
@ -533,7 +533,7 @@ func Test_MarkImageVerified(t *testing.T) {
ruleResp := &response.RuleResponse{Status: response.RuleStatusPass}
digest := "sha256:859ab6768a6f26a79bc42b231664111317d095a4f04e4b6fe79ce37b3d199097"
imageInfo := kubeutils.ImageInfo{}
imageInfo := apiutils.ImageInfo{}
imageInfo.Name = "nginx"
iv.markImageVerified(imageVerifyRule, ruleResp, digest, imageInfo)

View file

@ -3,6 +3,7 @@ package engine
import (
"encoding/json"
"fmt"
"github.com/go-logr/logr"
"github.com/google/go-containerregistry/pkg/name"
"github.com/google/go-containerregistry/pkg/v1/remote"

View file

@ -1,10 +1,11 @@
package kube
package api
import (
"fmt"
"strconv"
"strings"
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
imageutils "github.com/kyverno/kyverno/pkg/utils/image"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
)
@ -15,27 +16,6 @@ type ImageInfo struct {
Pointer string `json:"-"`
}
type ImageExtractorConfigs map[string][]ImageExtractorConfig
type ImageExtractorConfig struct {
// Path is the path to the object containing the image field in a custom resource.
// It should be slash-separated. Each slash-separated key must be a valid YAML key or a wildcard '*'.
// Wildcard keys are expanded in case of arrays or objects.
Path string `json:"path" yaml:"path"`
// Value is an optional name of the field within 'path' that points to the image URI.
// This is useful when a custom 'key' is also defined.
// +optional
Value string `json:"value,omitempty" yaml:"value,omitempty"`
// Name is the entry the image will be available under 'images.<name>' in the context.
// If this field is not defined, image entries will appear under 'images.custom'.
// +optional
Name string `json:"name,omitempty" yaml:"name,omitempty"`
// Key is an optional name of the field within 'path' that will be used to uniquely identify an image.
// Note - this field MUST be unique.
// +optional
Key string `json:"key,omitempty" yaml:"key,omitempty"`
}
var (
podExtractors = BuildStandardExtractors("spec")
podControllerExtractors = BuildStandardExtractors("spec", "template", "spec")
@ -132,7 +112,7 @@ func BuildStandardExtractors(tags ...string) []imageExtractor {
return extractors
}
func lookupImageExtractor(kind string, configs ImageExtractorConfigs) []imageExtractor {
func lookupImageExtractor(kind string, configs kyvernov1.ImageExtractorConfigs) []imageExtractor {
if configs != nil {
if extractorConfigs, ok := configs[kind]; ok {
extractors := []imageExtractor{}
@ -169,7 +149,7 @@ func lookupImageExtractor(kind string, configs ImageExtractorConfigs) []imageExt
return registeredExtractors[kind]
}
func ExtractImagesFromResource(resource unstructured.Unstructured, configs ImageExtractorConfigs) (map[string]map[string]ImageInfo, error) {
func ExtractImagesFromResource(resource unstructured.Unstructured, configs kyvernov1.ImageExtractorConfigs) (map[string]map[string]ImageInfo, error) {
infos := map[string]map[string]ImageInfo{}
extractors := lookupImageExtractor(resource.GetKind(), configs)

View file

@ -1,8 +1,9 @@
package kube
package api
import (
"testing"
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
"github.com/kyverno/kyverno/pkg/engine/utils"
imageutils "github.com/kyverno/kyverno/pkg/utils/image"
"gotest.tools/assert"
@ -10,7 +11,7 @@ import (
func Test_extractImageInfo(t *testing.T) {
tests := []struct {
extractionConfig ImageExtractorConfigs
extractionConfig kyvernov1.ImageExtractorConfigs
raw []byte
images map[string]map[string]ImageInfo
}{
@ -125,8 +126,8 @@ func Test_extractImageInfo(t *testing.T) {
},
},
{
extractionConfig: ImageExtractorConfigs{
"Task": []ImageExtractorConfig{
extractionConfig: kyvernov1.ImageExtractorConfigs{
"Task": []kyvernov1.ImageExtractorConfig{
{Path: "/spec/steps/*/image"},
},
},
@ -164,8 +165,8 @@ func Test_extractImageInfo(t *testing.T) {
},
},
{
extractionConfig: ImageExtractorConfigs{
"Task": []ImageExtractorConfig{
extractionConfig: kyvernov1.ImageExtractorConfigs{
"Task": []kyvernov1.ImageExtractorConfig{
{Name: "steps", Path: "/spec/steps/*", Value: "image", Key: "name"},
},
}, raw: []byte(`{"apiVersion":"tekton.dev/v1beta1","kind":"Task","metadata":{"name":"example-task-name"},"spec":{"steps":[{"name":"ubuntu-example","image":"ubuntu","args":["ubuntu-build-example","SECRETS-example.md"]},{"name":"dockerfile-pushexample","image":"gcr.io/example-builders/push-example","args":["push","$(resources.outputs.builtImage.url)"]}]}}`),
@ -193,8 +194,8 @@ func Test_extractImageInfo(t *testing.T) {
},
},
{
extractionConfig: ImageExtractorConfigs{
"ClusterTask": []ImageExtractorConfig{
extractionConfig: kyvernov1.ImageExtractorConfigs{
"ClusterTask": []kyvernov1.ImageExtractorConfig{
{Name: "steps", Path: "/spec/steps/*", Value: "image", Key: "name"},
},
},