From 1f42df541cb8ca9d1ebe1d5e2eb77a3e6c465271 Mon Sep 17 00:00:00 2001 From: wilstdu Date: Mon, 20 May 2024 14:51:26 +0300 Subject: [PATCH] Bundle resolver can use ServiceAccount for auth --- config/resolvers/200-clusterrole.yaml | 2 +- config/resolvers/bundleresolver-config.yaml | 2 + .../resolver/bundle/resolver_test.go | 71 +++++++- pkg/resolution/resolver/bundle/bundle.go | 1 + pkg/resolution/resolver/bundle/config.go | 3 + pkg/resolution/resolver/bundle/params.go | 19 +- pkg/resolution/resolver/bundle/resolver.go | 8 +- .../resolver/bundle/resolver_test.go | 172 ++++++++++++++---- 8 files changed, 232 insertions(+), 46 deletions(-) diff --git a/config/resolvers/200-clusterrole.yaml b/config/resolvers/200-clusterrole.yaml index 3215d74b145..544983c9ea1 100644 --- a/config/resolvers/200-clusterrole.yaml +++ b/config/resolvers/200-clusterrole.yaml @@ -30,5 +30,5 @@ rules: verbs: ["get", "list"] # Read-only access to these. - apiGroups: [""] - resources: ["secrets"] + resources: ["secrets", "serviceaccounts"] verbs: ["get", "list", "watch"] diff --git a/config/resolvers/bundleresolver-config.yaml b/config/resolvers/bundleresolver-config.yaml index 62e53fec96a..d48372ddd11 100644 --- a/config/resolvers/bundleresolver-config.yaml +++ b/config/resolvers/bundleresolver-config.yaml @@ -22,5 +22,7 @@ metadata: app.kubernetes.io/instance: default app.kubernetes.io/part-of: tekton-pipelines data: + # the default service account name to use for bundle requests. + default-service-account: "default" # The default layer kind in the bundle image. default-kind: "task" diff --git a/pkg/remoteresolution/resolver/bundle/resolver_test.go b/pkg/remoteresolution/resolver/bundle/resolver_test.go index 9ce0b25f1d7..738c523991b 100644 --- a/pkg/remoteresolution/resolver/bundle/resolver_test.go +++ b/pkg/remoteresolution/resolver/bundle/resolver_test.go @@ -38,6 +38,7 @@ import ( frtesting "github.com/tektoncd/pipeline/pkg/remoteresolution/resolver/framework/testing" resolutioncommon "github.com/tektoncd/pipeline/pkg/resolution/common" bundleresolution "github.com/tektoncd/pipeline/pkg/resolution/resolver/bundle" + "github.com/tektoncd/pipeline/pkg/resolution/resolver/framework" frameworktesting "github.com/tektoncd/pipeline/pkg/resolution/resolver/framework/testing" "github.com/tektoncd/pipeline/test" "github.com/tektoncd/pipeline/test/diff" @@ -65,8 +66,12 @@ func TestGetSelector(t *testing.T) { } } -func TestValidate(t *testing.T) { +func TestValidateParamsSecret(t *testing.T) { resolver := bundle.Resolver{} + config := map[string]string{ + bundleresolution.ConfigServiceAccount: "default", + } + ctx := framework.InjectResolverConfigToContext(context.Background(), config) paramsWithTask := []pipelinev1.Param{{ Name: bundleresolution.ParamKind, @@ -82,7 +87,7 @@ func TestValidate(t *testing.T) { Value: *pipelinev1.NewStructuredValues("baz"), }} req := v1beta1.ResolutionRequestSpec{Params: paramsWithTask} - if err := resolver.Validate(context.Background(), &req); err != nil { + if err := resolver.Validate(ctx, &req); err != nil { t.Fatalf("unexpected error validating params: %v", err) } @@ -100,6 +105,50 @@ func TestValidate(t *testing.T) { Value: *pipelinev1.NewStructuredValues("baz"), }} req = v1beta1.ResolutionRequestSpec{Params: paramsWithPipeline} + if err := resolver.Validate(ctx, &req); err != nil { + t.Fatalf("unexpected error validating params: %v", err) + } +} + +func TestValidateParamsServiceAccount(t *testing.T) { + resolver := bundle.Resolver{} + config := map[string]string{ + bundleresolution.ConfigServiceAccount: "default", + } + ctx := framework.InjectResolverConfigToContext(context.Background(), config) + + paramsWithTask := []pipelinev1.Param{{ + Name: bundleresolution.ParamKind, + Value: *pipelinev1.NewStructuredValues("task"), + }, { + Name: bundleresolution.ParamName, + Value: *pipelinev1.NewStructuredValues("foo"), + }, { + Name: bundleresolution.ParamBundle, + Value: *pipelinev1.NewStructuredValues("bar"), + }, { + Name: bundleresolution.ParamServiceAccount, + Value: *pipelinev1.NewStructuredValues("baz"), + }} + req := v1beta1.ResolutionRequestSpec{Params: paramsWithTask} + if err := resolver.Validate(ctx, &req); err != nil { + t.Fatalf("unexpected error validating params: %v", err) + } + + paramsWithPipeline := []pipelinev1.Param{{ + Name: bundleresolution.ParamKind, + Value: *pipelinev1.NewStructuredValues("pipeline"), + }, { + Name: bundleresolution.ParamName, + Value: *pipelinev1.NewStructuredValues("foo"), + }, { + Name: bundleresolution.ParamBundle, + Value: *pipelinev1.NewStructuredValues("bar"), + }, { + Name: bundleresolution.ParamServiceAccount, + Value: *pipelinev1.NewStructuredValues("baz"), + }} + req = v1beta1.ResolutionRequestSpec{Params: paramsWithPipeline} if err := resolver.Validate(context.Background(), &req); err != nil { t.Fatalf("unexpected error validating params: %v", err) } @@ -221,7 +270,8 @@ func TestResolve_KeyChainError(t *testing.T) { Namespace: resolverconfig.ResolversNamespace(system.Namespace()), }, Data: map[string]string{ - bundleresolution.ConfigKind: "task", + bundleresolution.ConfigKind: "task", + bundleresolution.ConfigServiceAccount: "default", }, }}, } @@ -246,10 +296,11 @@ func TestResolve_KeyChainError(t *testing.T) { } type params struct { - secret string - bundle string - name string - kind string + serviceAccount string + secret string + bundle string + name string + kind string } func TestResolve(t *testing.T) { @@ -450,7 +501,8 @@ func TestResolve(t *testing.T) { resolver := &bundle.Resolver{} confMap := map[string]string{ - bundleresolution.ConfigKind: "task", + bundleresolution.ConfigKind: "task", + bundleresolution.ConfigServiceAccount: "default", } for _, tc := range testcases { @@ -544,6 +596,9 @@ func createRequest(p *params) *v1beta1.ResolutionRequest { }, { Name: bundleresolution.ParamImagePullSecret, Value: *pipelinev1.NewStructuredValues(p.secret), + }, { + Name: bundleresolution.ParamServiceAccount, + Value: *pipelinev1.NewStructuredValues(p.serviceAccount), }}, }, } diff --git a/pkg/resolution/resolver/bundle/bundle.go b/pkg/resolution/resolver/bundle/bundle.go index 0b150031b25..f5f9997f63b 100644 --- a/pkg/resolution/resolver/bundle/bundle.go +++ b/pkg/resolution/resolver/bundle/bundle.go @@ -37,6 +37,7 @@ const ( // RequestOptions are the options used to request a resource from // a remote bundle. type RequestOptions struct { + ServiceAccount string ImagePullSecret string Bundle string EntryName string diff --git a/pkg/resolution/resolver/bundle/config.go b/pkg/resolution/resolver/bundle/config.go index 45a12846259..e46a3151334 100644 --- a/pkg/resolution/resolver/bundle/config.go +++ b/pkg/resolution/resolver/bundle/config.go @@ -16,6 +16,9 @@ package bundle const ( // ConfigMapName is the bundle resolver's config map ConfigMapName = "bundleresolver-config" + // ConfigServiceAccount is the configuration field name for controlling + // the Service Account name to use for bundle requests. + ConfigServiceAccount = "default-service-account" // ConfigKind is the configuration field name for controlling // what the layer name in the bundle image is. ConfigKind = "default-kind" diff --git a/pkg/resolution/resolver/bundle/params.go b/pkg/resolution/resolver/bundle/params.go index fddef31e498..2712cbe4c09 100644 --- a/pkg/resolution/resolver/bundle/params.go +++ b/pkg/resolution/resolver/bundle/params.go @@ -24,6 +24,10 @@ import ( "github.com/tektoncd/pipeline/pkg/resolution/resource" ) +// ParamServiceAccount is the parameter defining what service +// account name to use for bundle requests. +const ParamServiceAccount = "serviceAccount" + // ParamImagePullSecret is the parameter defining what secret // name to use for bundle requests. const ParamImagePullSecret = "secret" @@ -50,6 +54,18 @@ func OptionsFromParams(ctx context.Context, params []pipelinev1.Param) (RequestO paramsMap[p.Name] = p.Value } + saVal, ok := paramsMap[ParamServiceAccount] + sa := "" + if !ok || saVal.StringVal == "" { + if saString, ok := conf[ConfigServiceAccount]; ok { + sa = saString + } else { + return opts, errors.New("default Service Account was not set during installation of the bundle resolver") + } + } else { + sa = saVal.StringVal + } + bundleVal, ok := paramsMap[ParamBundle] if !ok || bundleVal.StringVal == "" { return opts, fmt.Errorf("parameter %q required", ParamBundle) @@ -69,12 +85,13 @@ func OptionsFromParams(ctx context.Context, params []pipelinev1.Param) (RequestO if kindString, ok := conf[ConfigKind]; ok { kind = kindString } else { - return opts, errors.New("default resource Kind was not set during installation of the bundle resolver") + return opts, errors.New("default resource Kind was not set during installation of the bundle resolver") } } else { kind = kindVal.StringVal } + opts.ServiceAccount = sa opts.ImagePullSecret = paramsMap[ParamImagePullSecret].StringVal opts.Bundle = bundleVal.StringVal opts.EntryName = nameVal.StringVal diff --git a/pkg/resolution/resolver/bundle/resolver.go b/pkg/resolution/resolver/bundle/resolver.go index 9f88ff2caec..95c18f21963 100644 --- a/pkg/resolution/resolver/bundle/resolver.go +++ b/pkg/resolution/resolver/bundle/resolver.go @@ -22,9 +22,7 @@ import ( "time" "github.com/google/go-containerregistry/pkg/authn/k8schain" - kauth "github.com/google/go-containerregistry/pkg/authn/kubernetes" resolverconfig "github.com/tektoncd/pipeline/pkg/apis/config/resolver" - pipelinev1 "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1" v1 "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1" "github.com/tektoncd/pipeline/pkg/apis/resolution/v1beta1" common "github.com/tektoncd/pipeline/pkg/resolution/common" @@ -79,7 +77,7 @@ func (r *Resolver) GetSelector(context.Context) map[string]string { } // ValidateParams ensures parameters from a request are as expected. -func (r *Resolver) ValidateParams(ctx context.Context, params []pipelinev1.Param) error { +func (r *Resolver) ValidateParams(ctx context.Context, params []v1.Param) error { return ValidateParams(ctx, params) } @@ -104,8 +102,8 @@ func ResolveRequest(ctx context.Context, kubeClientSet kubernetes.Interface, req namespace := common.RequestNamespace(ctx) kc, err := k8schain.New(ctx, kubeClientSet, k8schain.Options{ Namespace: namespace, + ServiceAccountName: opts.ServiceAccount, ImagePullSecrets: imagePullSecrets, - ServiceAccountName: kauth.NoServiceAccount, }) if err != nil { return nil, err @@ -115,7 +113,7 @@ func ResolveRequest(ctx context.Context, kubeClientSet kubernetes.Interface, req return GetEntry(ctx, kc, opts) } -func ValidateParams(ctx context.Context, params []pipelinev1.Param) error { +func ValidateParams(ctx context.Context, params []v1.Param) error { if isDisabled(ctx) { return errors.New(disabledError) } diff --git a/pkg/resolution/resolver/bundle/resolver_test.go b/pkg/resolution/resolver/bundle/resolver_test.go index 2cdc8571631..d5e1ce4f84d 100644 --- a/pkg/resolution/resolver/bundle/resolver_test.go +++ b/pkg/resolution/resolver/bundle/resolver_test.go @@ -30,12 +30,12 @@ import ( "github.com/google/go-containerregistry/pkg/registry" resolverconfig "github.com/tektoncd/pipeline/pkg/apis/config/resolver" pipelinev1 "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1" - pipelinev1beta1 "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1beta1" "github.com/tektoncd/pipeline/pkg/apis/resolution/v1beta1" "github.com/tektoncd/pipeline/pkg/internal/resolution" ttesting "github.com/tektoncd/pipeline/pkg/reconciler/testing" common "github.com/tektoncd/pipeline/pkg/resolution/common" - bundle "github.com/tektoncd/pipeline/pkg/resolution/resolver/bundle" + "github.com/tektoncd/pipeline/pkg/resolution/resolver/bundle" + "github.com/tektoncd/pipeline/pkg/resolution/resolver/framework" frtesting "github.com/tektoncd/pipeline/pkg/resolution/resolver/framework/testing" "github.com/tektoncd/pipeline/test" "github.com/tektoncd/pipeline/test/diff" @@ -63,8 +63,12 @@ func TestGetSelector(t *testing.T) { } } -func TestValidateParams(t *testing.T) { +func TestValidateParamsSecret(t *testing.T) { resolver := bundle.Resolver{} + config := map[string]string{ + bundle.ConfigServiceAccount: "default", + } + ctx := framework.InjectResolverConfigToContext(context.Background(), config) paramsWithTask := []pipelinev1.Param{{ Name: bundle.ParamKind, @@ -80,7 +84,7 @@ func TestValidateParams(t *testing.T) { Value: *pipelinev1.NewStructuredValues("baz"), }} - if err := resolver.ValidateParams(context.Background(), paramsWithTask); err != nil { + if err := resolver.ValidateParams(ctx, paramsWithTask); err != nil { t.Fatalf("unexpected error validating params: %v", err) } @@ -97,7 +101,47 @@ func TestValidateParams(t *testing.T) { Name: bundle.ParamImagePullSecret, Value: *pipelinev1.NewStructuredValues("baz"), }} - if err := resolver.ValidateParams(context.Background(), paramsWithPipeline); err != nil { + if err := resolver.ValidateParams(ctx, paramsWithPipeline); err != nil { + t.Fatalf("unexpected error validating params: %v", err) + } +} + +func TestValidateParamsServiceAccount(t *testing.T) { + resolver := bundle.Resolver{} + config := map[string]string{ + bundle.ConfigServiceAccount: "default", + } + ctx := framework.InjectResolverConfigToContext(context.Background(), config) + + paramsWithTask := []pipelinev1.Param{{ + Name: bundle.ParamKind, + Value: *pipelinev1.NewStructuredValues("task"), + }, { + Name: bundle.ParamName, + Value: *pipelinev1.NewStructuredValues("foo"), + }, { + Name: bundle.ParamBundle, + Value: *pipelinev1.NewStructuredValues("bar"), + }, { + Name: bundle.ParamServiceAccount, + Value: *pipelinev1.NewStructuredValues("baz"), + }} + + if err := resolver.ValidateParams(context.Background(), paramsWithTask); err != nil { + t.Fatalf("unexpected error validating params: %v", err) + } + + paramsWithPipeline := []pipelinev1.Param{{ + Name: bundle.ParamKind, + Value: *pipelinev1.NewStructuredValues("pipeline"), + }, { + Name: bundle.ParamName, + Value: *pipelinev1.NewStructuredValues("foo"), + }, { + Name: bundle.ParamBundle, + Value: *pipelinev1.NewStructuredValues("bar"), + }} + if err := resolver.ValidateParams(ctx, paramsWithPipeline); err != nil { t.Fatalf("unexpected error validating params: %v", err) } } @@ -107,7 +151,7 @@ func TestValidateParamsDisabled(t *testing.T) { var err error - params := []pipelinev1.Param{{ + paramsSecret := []pipelinev1.Param{{ Name: bundle.ParamKind, Value: *pipelinev1.NewStructuredValues("task"), }, { @@ -120,7 +164,29 @@ func TestValidateParamsDisabled(t *testing.T) { Name: bundle.ParamImagePullSecret, Value: *pipelinev1.NewStructuredValues("baz"), }} - err = resolver.ValidateParams(resolverDisabledContext(), params) + err = resolver.ValidateParams(resolverDisabledContext(), paramsSecret) + if err == nil { + t.Fatalf("expected disabled err") + } + + if d := cmp.Diff(disabledError, err.Error()); d != "" { + t.Errorf("unexpected error: %s", diff.PrintWantGot(d)) + } + + paramsServiceAccount := []pipelinev1.Param{{ + Name: bundle.ParamKind, + Value: *pipelinev1.NewStructuredValues("task"), + }, { + Name: bundle.ParamName, + Value: *pipelinev1.NewStructuredValues("foo"), + }, { + Name: bundle.ParamBundle, + Value: *pipelinev1.NewStructuredValues("bar"), + }, { + Name: bundle.ParamServiceAccount, + Value: *pipelinev1.NewStructuredValues("baz"), + }} + err = resolver.ValidateParams(resolverDisabledContext(), paramsServiceAccount) if err == nil { t.Fatalf("expected disabled err") } @@ -214,7 +280,8 @@ func TestResolve_KeyChainError(t *testing.T) { Namespace: resolverconfig.ResolversNamespace(system.Namespace()), }, Data: map[string]string{ - bundle.ConfigKind: "task", + bundle.ConfigKind: "task", + bundle.ConfigServiceAccount: "default", }, }}, } @@ -239,26 +306,27 @@ func TestResolve_KeyChainError(t *testing.T) { } type params struct { - secret string - bundle string - name string - kind string + serviceAccount string + secret string + bundle string + name string + kind string } func TestResolve(t *testing.T) { // example task resource - exampleTask := &pipelinev1beta1.Task{ + exampleTask := &pipelinev1.Task{ ObjectMeta: metav1.ObjectMeta{ Name: "example-task", Namespace: "task-ns", ResourceVersion: "00002", }, TypeMeta: metav1.TypeMeta{ - Kind: string(pipelinev1beta1.NamespacedTaskKind), - APIVersion: "tekton.dev/v1beta1", + Kind: string(pipelinev1.NamespacedTaskKind), + APIVersion: "tekton.dev/v1", }, - Spec: pipelinev1beta1.TaskSpec{ - Steps: []pipelinev1beta1.Step{{ + Spec: pipelinev1.TaskSpec{ + Steps: []pipelinev1.Step{{ Name: "some-step", Image: "some-image", Command: []string{"something"}, @@ -271,7 +339,7 @@ func TestResolve(t *testing.T) { } // example pipeline resource - examplePipeline := &pipelinev1beta1.Pipeline{ + examplePipeline := &pipelinev1.Pipeline{ ObjectMeta: metav1.ObjectMeta{ Name: "example-pipeline", Namespace: "pipeline-ns", @@ -279,14 +347,14 @@ func TestResolve(t *testing.T) { }, TypeMeta: metav1.TypeMeta{ Kind: "Pipeline", - APIVersion: "tekton.dev/v1beta1", + APIVersion: "tekton.dev/v1", }, - Spec: pipelinev1beta1.PipelineSpec{ - Tasks: []pipelinev1beta1.PipelineTask{{ + Spec: pipelinev1.PipelineSpec{ + Tasks: []pipelinev1.PipelineTask{{ Name: "some-pipeline-task", - TaskRef: &pipelinev1beta1.TaskRef{ + TaskRef: &pipelinev1.TaskRef{ Name: "some-task", - Kind: pipelinev1beta1.NamespacedTaskKind, + Kind: pipelinev1.NamespacedTaskKind, }, }}, }, @@ -300,12 +368,12 @@ func TestResolve(t *testing.T) { var tooManyObjs []runtime.Object for i := 0; i <= bundle.MaximumBundleObjects; i++ { name := fmt.Sprintf("%d-task", i) - obj := pipelinev1beta1.Task{ + obj := pipelinev1.Task{ ObjectMeta: metav1.ObjectMeta{ Name: name, }, TypeMeta: metav1.TypeMeta{ - APIVersion: "tekton.dev/v1beta1", + APIVersion: "tekton.dev/v1", Kind: "Task", }, } @@ -325,10 +393,10 @@ func TestResolve(t *testing.T) { "single-pipeline": pushToRegistry(t, r, "single-pipeline", []runtime.Object{examplePipeline}, test.DefaultObjectAnnotationMapper), "multiple-resources": pushToRegistry(t, r, "multiple-resources", []runtime.Object{exampleTask, examplePipeline}, test.DefaultObjectAnnotationMapper), "too-many-objs": pushToRegistry(t, r, "too-many-objs", tooManyObjs, asIsMapper), - "single-task-no-version": pushToRegistry(t, r, "single-task-no-version", []runtime.Object{&pipelinev1beta1.Task{TypeMeta: metav1.TypeMeta{Kind: "task"}, ObjectMeta: metav1.ObjectMeta{Name: "foo"}}}, asIsMapper), - "single-task-no-kind": pushToRegistry(t, r, "single-task-no-kind", []runtime.Object{&pipelinev1beta1.Task{TypeMeta: metav1.TypeMeta{APIVersion: "tekton.dev/v1beta1"}, ObjectMeta: metav1.ObjectMeta{Name: "foo"}}}, asIsMapper), - "single-task-no-name": pushToRegistry(t, r, "single-task-no-name", []runtime.Object{&pipelinev1beta1.Task{TypeMeta: metav1.TypeMeta{APIVersion: "tekton.dev/v1beta1", Kind: "task"}}}, asIsMapper), - "single-task-kind-incorrect-form": pushToRegistry(t, r, "single-task-kind-incorrect-form", []runtime.Object{&pipelinev1beta1.Task{TypeMeta: metav1.TypeMeta{APIVersion: "tekton.dev/v1beta1", Kind: "Task"}, ObjectMeta: metav1.ObjectMeta{Name: "foo"}}}, asIsMapper), + "single-task-no-version": pushToRegistry(t, r, "single-task-no-version", []runtime.Object{&pipelinev1.Task{TypeMeta: metav1.TypeMeta{Kind: "task"}, ObjectMeta: metav1.ObjectMeta{Name: "foo"}}}, asIsMapper), + "single-task-no-kind": pushToRegistry(t, r, "single-task-no-kind", []runtime.Object{&pipelinev1.Task{TypeMeta: metav1.TypeMeta{APIVersion: "tekton.dev/v1"}, ObjectMeta: metav1.ObjectMeta{Name: "foo"}}}, asIsMapper), + "single-task-no-name": pushToRegistry(t, r, "single-task-no-name", []runtime.Object{&pipelinev1.Task{TypeMeta: metav1.TypeMeta{APIVersion: "tekton.dev/v1", Kind: "task"}}}, asIsMapper), + "single-task-kind-incorrect-form": pushToRegistry(t, r, "single-task-kind-incorrect-form", []runtime.Object{&pipelinev1.Task{TypeMeta: metav1.TypeMeta{APIVersion: "tekton.dev/v1", Kind: "Task"}, ObjectMeta: metav1.ObjectMeta{Name: "foo"}}}, asIsMapper), } testcases := []struct { @@ -375,6 +443,24 @@ func TestResolve(t *testing.T) { }, imageName: "single-task", expectedStatus: resolution.CreateResolutionRequestStatusWithData(taskAsYAML), + }, { + name: "single task: using secret from params", + args: ¶ms{ + bundle: testImages["single-task"].uri + ":latest", + name: "example-task", + secret: "example-secret", + }, + imageName: "single-task", + expectedStatus: resolution.CreateResolutionRequestStatusWithData(taskAsYAML), + }, { + name: "single task: using SA from params", + args: ¶ms{ + bundle: testImages["single-task"].uri + ":latest", + name: "example-task", + serviceAccount: "example-sa", + }, + imageName: "single-task", + expectedStatus: resolution.CreateResolutionRequestStatusWithData(taskAsYAML), }, { name: "single pipeline", args: ¶ms{ @@ -384,6 +470,26 @@ func TestResolve(t *testing.T) { }, imageName: "single-pipeline", expectedStatus: resolution.CreateResolutionRequestStatusWithData(pipelineAsYAML), + }, { + name: "single pipeline: with service account", + args: ¶ms{ + bundle: testImages["single-pipeline"].uri + ":latest", + name: "example-pipeline", + kind: "pipeline", + serviceAccount: "example-sa", + }, + imageName: "single-pipeline", + expectedStatus: resolution.CreateResolutionRequestStatusWithData(pipelineAsYAML), + }, { + name: "single pipeline: with secret", + args: ¶ms{ + bundle: testImages["single-pipeline"].uri + ":latest", + name: "example-pipeline", + kind: "pipeline", + secret: "example-secret", + }, + imageName: "single-pipeline", + expectedStatus: resolution.CreateResolutionRequestStatusWithData(pipelineAsYAML), }, { name: "multiple resources: an image has both task and pipeline resource", args: ¶ms{ @@ -443,7 +549,8 @@ func TestResolve(t *testing.T) { resolver := &bundle.Resolver{} confMap := map[string]string{ - bundle.ConfigKind: "task", + bundle.ConfigKind: "task", + bundle.ConfigServiceAccount: "default", } for _, tc := range testcases { @@ -489,7 +596,7 @@ func TestResolve(t *testing.T) { } expectedStatus.Annotations[bundle.ResolverAnnotationName] = tc.args.name - expectedStatus.Annotations[bundle.ResolverAnnotationAPIVersion] = "v1beta1" + expectedStatus.Annotations[bundle.ResolverAnnotationAPIVersion] = "v1" expectedStatus.RefSource = &pipelinev1.RefSource{ URI: testImages[tc.imageName].uri, @@ -537,6 +644,9 @@ func createRequest(p *params) *v1beta1.ResolutionRequest { }, { Name: bundle.ParamImagePullSecret, Value: *pipelinev1.NewStructuredValues(p.secret), + }, { + Name: bundle.ParamServiceAccount, + Value: *pipelinev1.NewStructuredValues(p.serviceAccount), }}, }, }