github.com/redhat-appstudio/e2e-tests@v0.0.0-20230619105049-9a422b2094d7/tests/mvp-demo/mvp-demo.go (about)

     1  package mvp
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	build2 "github.com/redhat-appstudio/e2e-tests/tests/build"
     7  	"os"
     8  	"strings"
     9  	"time"
    10  
    11  	"github.com/devfile/library/pkg/util"
    12  	ecp "github.com/enterprise-contract/enterprise-contract-controller/api/v1alpha1"
    13  	"github.com/google/go-containerregistry/pkg/authn"
    14  	"github.com/google/go-containerregistry/pkg/name"
    15  	remoteimg "github.com/google/go-containerregistry/pkg/v1/remote"
    16  	"github.com/google/go-github/v44/github"
    17  	. "github.com/onsi/ginkgo/v2"
    18  	. "github.com/onsi/gomega"
    19  	routev1 "github.com/openshift/api/route/v1"
    20  	"knative.dev/pkg/apis"
    21  
    22  	appstudioApi "github.com/redhat-appstudio/application-api/api/v1alpha1"
    23  	buildservice "github.com/redhat-appstudio/build-service/api/v1alpha1"
    24  	"github.com/redhat-appstudio/e2e-tests/pkg/constants"
    25  	"github.com/redhat-appstudio/e2e-tests/pkg/framework"
    26  	"github.com/redhat-appstudio/e2e-tests/pkg/utils"
    27  	"github.com/redhat-appstudio/e2e-tests/pkg/utils/build"
    28  	r "github.com/redhat-appstudio/e2e-tests/pkg/utils/release"
    29  	"github.com/redhat-appstudio/e2e-tests/pkg/utils/tekton"
    30  	integrationv1beta1 "github.com/redhat-appstudio/integration-service/api/v1beta1"
    31  	"github.com/redhat-appstudio/jvm-build-service/pkg/apis/jvmbuildservice/v1alpha1"
    32  	releaseApi "github.com/redhat-appstudio/release-service/api/v1alpha1"
    33  	tektonapi "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1beta1"
    34  	k8sErrors "k8s.io/apimachinery/pkg/api/errors"
    35  
    36  	corev1 "k8s.io/api/core/v1"
    37  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    38  	"k8s.io/apimachinery/pkg/runtime"
    39  	"k8s.io/utils/pointer"
    40  
    41  	"sigs.k8s.io/yaml"
    42  )
    43  
    44  const (
    45  	// This app might be replaced with service-registry in a future
    46  	sampleRepoName             = "hacbs-test-project"
    47  	componentDefaultBranchName = "main"
    48  
    49  	// Kubernetes resource names
    50  	testNamespacePrefix = "mvp-dev"
    51  	managedNamespace    = "mvp-managed"
    52  
    53  	appName                = "mvp-test-app"
    54  	testScenarioGitURL     = "https://github.com/redhat-appstudio/integration-examples.git"
    55          testScenarioRevision   = "main"
    56          testScenarioPathInRepo = "pipelines/integration_resolver_pipeline_pass.yaml"
    57  
    58  
    59  	// Timeouts
    60  	appDeployTimeout            = time.Minute * 20
    61  	appRouteAvailableTimeout    = time.Minute * 5
    62  	customResourceUpdateTimeout = time.Minute * 2
    63  	jvmRebuildTimeout           = time.Minute * 20
    64  	mergePRTimeout              = time.Minute * 1
    65  	pipelineRunStartedTimeout   = time.Minute * 5
    66  	pullRequestCreationTimeout  = time.Minute * 5
    67  	releasePipelineTimeout      = time.Minute * 15
    68  	snapshotTimeout             = time.Minute * 4
    69  	releaseTimeout              = time.Minute * 4
    70  	testPipelineTimeout         = time.Minute * 15
    71  
    72  	// Intervals
    73  	defaultPollingInterval     = time.Second * 2
    74  	jvmRebuildPollingInterval  = time.Second * 10
    75  	pipelineRunPollingInterval = time.Second * 10
    76  	snapshotPollingInterval    = time.Second * 1
    77  	releasePollingInterval     = time.Second * 1
    78  )
    79  
    80  var sampleRepoURL = fmt.Sprintf("https://github.com/%s/%s", utils.GetEnv(constants.GITHUB_E2E_ORGANIZATION_ENV, "redhat-appstudio-qe"), sampleRepoName)
    81  
    82  var _ = framework.MvpDemoSuiteDescribe("MVP Demo tests", Label("mvp-demo"), func() {
    83  
    84  	defer GinkgoRecover()
    85  	var err error
    86  	var f *framework.Framework
    87  	var sharedSecret *corev1.Secret
    88  	var pacControllerRoute *routev1.Route
    89  	var componentName string
    90  
    91  	var untrustedPipelineBundle, componentNewBaseBranch, userNamespace string
    92  
    93  	var kc tekton.KubeController
    94  
    95  	// set vs. simply declare these pointers so we can use them in debug, where an empty name is indicative of Get's failing
    96  	component := &appstudioApi.Component{}
    97  	pipelineRun := &tektonapi.PipelineRun{}
    98  	release := &releaseApi.Release{}
    99  	snapshot := &appstudioApi.Snapshot{}
   100  	testPipelinerun := &tektonapi.PipelineRun{}
   101  	integrationTestScenario := &integrationv1beta1.IntegrationTestScenario{}
   102  
   103  	BeforeAll(func() {
   104  		// This pipeline contains an image that comes from "not allowed" container image registry repo
   105  		// https://github.com/hacbs-contract/ec-policies/blob/de8afa912e7a80d02abb82358ce7b23cf9a286c8/data/rule_data.yml#L9-L12
   106  		// It is required in order to test that the release of the image failed based on a failed check in EC
   107  		untrustedPipelineBundle, err = createUntrustedPipelineBundle()
   108  		Expect(err).NotTo(HaveOccurred())
   109  		GinkgoWriter.Printf("generated untrusted pipeline bundle: %s", untrustedPipelineBundle)
   110  
   111  		f, err = framework.NewFramework(utils.GetGeneratedNamespace(testNamespacePrefix))
   112  		Expect(err).NotTo(HaveOccurred())
   113  		userNamespace = f.UserNamespace
   114  		Expect(userNamespace).NotTo(BeEmpty())
   115  
   116  		componentName = fmt.Sprintf("test-mvp-component-%s", util.GenerateRandomString(4))
   117  		componentNewBaseBranch = fmt.Sprintf("base-%s", util.GenerateRandomString(4))
   118  
   119  		sharedSecret, err = f.AsKubeAdmin.CommonController.GetSecret(constants.QuayRepositorySecretNamespace, constants.QuayRepositorySecretName)
   120  		Expect(err).ShouldNot(HaveOccurred(), fmt.Sprintf("error when getting shared secret - make sure the secret %s in %s userNamespace is created", constants.QuayRepositorySecretName, constants.QuayRepositorySecretNamespace))
   121  
   122  		// Release configuration
   123  		kc = tekton.KubeController{
   124  			Commonctrl: *f.AsKubeAdmin.CommonController,
   125  			Tektonctrl: *f.AsKubeAdmin.TektonController,
   126  		}
   127  
   128  		secret := &corev1.Secret{ObjectMeta: metav1.ObjectMeta{Name: "release-pull-secret", Namespace: managedNamespace},
   129  			Data: map[string][]byte{".dockerconfigjson": sharedSecret.Data[".dockerconfigjson"]},
   130  			Type: corev1.SecretTypeDockerConfigJson,
   131  		}
   132  
   133  		// release stuff
   134  		_, err = f.AsKubeAdmin.CommonController.CreateTestNamespace(managedNamespace)
   135  		Expect(err).ShouldNot(HaveOccurred())
   136  
   137  		secret.Namespace = managedNamespace
   138  		secret.Name = "release-pull-secret"
   139  		secret.Type = corev1.SecretTypeDockerConfigJson
   140  		_, err = f.AsKubeAdmin.CommonController.CreateSecret(managedNamespace, secret)
   141  		Expect(err).ShouldNot(HaveOccurred())
   142  		_, err = f.AsKubeAdmin.CommonController.CreateServiceAccount("release-service-account", managedNamespace, []corev1.ObjectReference{{Name: secret.Name}})
   143  		Expect(err).NotTo(HaveOccurred())
   144  
   145  		publicKey, err := kc.GetTektonChainsPublicKey()
   146  		Expect(err).ToNot(HaveOccurred())
   147  
   148  		Expect(kc.CreateOrUpdateSigningSecret(publicKey, "cosign-public-key", managedNamespace)).To(Succeed())
   149  
   150  		_, err = f.AsKubeAdmin.ReleaseController.CreateReleasePlan("source-releaseplan", userNamespace, appName, managedNamespace, "")
   151  		Expect(err).NotTo(HaveOccurred())
   152  
   153  		components := []r.Component{{Name: componentName, Repository: constants.DefaultReleasedImagePushRepo}}
   154  		sc := f.AsKubeAdmin.ReleaseController.GenerateReleaseStrategyConfig(components)
   155  		scYaml, err := yaml.Marshal(sc)
   156  		Expect(err).ShouldNot(HaveOccurred())
   157  
   158  		scPath := "mvp-demo.yaml"
   159  		Expect(f.AsKubeAdmin.CommonController.Github.CreateRef("strategy-configs", "main", componentName)).To(Succeed())
   160  		_, err = f.AsKubeAdmin.CommonController.Github.CreateFile("strategy-configs", scPath, string(scYaml), componentName)
   161  		Expect(err).ShouldNot(HaveOccurred())
   162  
   163  		_, err = f.AsKubeAdmin.ReleaseController.CreateReleaseStrategy("mvp-strategy", managedNamespace, "release", constants.ReleasePipelineImageRef, "mvp-policy", "release-service-account", []releaseApi.Params{
   164  			{Name: "extraConfigGitUrl", Value: fmt.Sprintf("https://github.com/%s/strategy-configs.git", utils.GetEnv(constants.GITHUB_E2E_ORGANIZATION_ENV, "redhat-appstudio-qe"))},
   165  			{Name: "extraConfigPath", Value: scPath},
   166  			{Name: "extraConfigGitRevision", Value: componentName},
   167  		})
   168  		Expect(err).NotTo(HaveOccurred())
   169  
   170  		_, err = f.AsKubeAdmin.ReleaseController.CreateReleasePlanAdmission("demo", userNamespace, appName, managedNamespace, "", "", "mvp-strategy")
   171  		Expect(err).NotTo(HaveOccurred())
   172  
   173  		defaultEcPolicy, err := kc.GetEnterpriseContractPolicy("default", "enterprise-contract-service")
   174  		Expect(err).NotTo(HaveOccurred())
   175  
   176  		defaultEcPolicySpec := ecp.EnterpriseContractPolicySpec{
   177  			Description: "Red Hat's enterprise requirements",
   178  			PublicKey:   string(publicKey),
   179  			Sources:     defaultEcPolicy.Spec.Sources,
   180  			Configuration: &ecp.EnterpriseContractPolicyConfiguration{
   181  				Collections: []string{"minimal"},
   182  				Exclude:     []string{"cve"},
   183  			},
   184  		}
   185  		_, err = f.AsKubeAdmin.TektonController.CreateEnterpriseContractPolicy("mvp-policy", managedNamespace, defaultEcPolicySpec)
   186  		Expect(err).NotTo(HaveOccurred())
   187  
   188  		_, err = f.AsKubeAdmin.TektonController.CreatePVCInAccessMode("release-pvc", managedNamespace, corev1.ReadWriteOnce)
   189  		Expect(err).NotTo(HaveOccurred())
   190  
   191  		_, err = f.AsKubeAdmin.CommonController.CreateRole("role-release-service-account", managedNamespace, map[string][]string{
   192  			"apiGroupsList": {""},
   193  			"roleResources": {"secrets"},
   194  			"roleVerbs":     {"get", "list", "watch"},
   195  		})
   196  		Expect(err).NotTo(HaveOccurred())
   197  
   198  		_, err = f.AsKubeAdmin.CommonController.CreateRoleBinding("role-release-service-account-binding", managedNamespace, "ServiceAccount", "release-service-account", "Role", "role-release-service-account", "rbac.authorization.k8s.io")
   199  		Expect(err).NotTo(HaveOccurred())
   200  	})
   201  	AfterAll(func() {
   202  		err = f.AsKubeAdmin.CommonController.Github.DeleteRef(sampleRepoName, componentNewBaseBranch)
   203  		if err != nil {
   204  			Expect(err.Error()).To(ContainSubstring("Reference does not exist"))
   205  		}
   206  		if !CurrentSpecReport().Failed() {
   207  			Expect(f.SandboxController.DeleteUserSignup(f.UserName)).NotTo(BeFalse())
   208  			Expect(f.AsKubeAdmin.CommonController.DeleteNamespace(managedNamespace)).To(Succeed())
   209  			Expect(f.AsKubeAdmin.CommonController.Github.DeleteRef("strategy-configs", componentName)).To(Succeed())
   210  		}
   211  	})
   212  
   213  	Describe("MVP Demo Chapter 1 - basic build & deploy, failed release", Label("mvp-demo-chapter-1"), Ordered, func() {
   214  
   215  		BeforeAll(func() {
   216  			Expect(f.AsKubeAdmin.CommonController.Github.CreateRef(sampleRepoName, componentDefaultBranchName, componentNewBaseBranch)).To(Succeed())
   217  			_, err = f.AsKubeAdmin.HasController.CreateHasApplication(appName, userNamespace)
   218  			Expect(err).ShouldNot(HaveOccurred())
   219  			_, err = f.AsKubeAdmin.IntegrationController.CreateEnvironment(userNamespace, "mvp-test")
   220  			Expect(err).ShouldNot(HaveOccurred())
   221  			ps := &buildservice.BuildPipelineSelector{
   222  				ObjectMeta: metav1.ObjectMeta{
   223  					Name:      "build-pipeline-selector",
   224  					Namespace: userNamespace,
   225  				},
   226  				Spec: buildservice.BuildPipelineSelectorSpec{Selectors: []buildservice.PipelineSelector{
   227  					{
   228  						Name: "custom-selector",
   229  						PipelineRef: tektonapi.PipelineRef{
   230  							Name:   "docker-build",
   231  							Bundle: untrustedPipelineBundle,
   232  						},
   233  						WhenConditions: buildservice.WhenCondition{
   234  							DockerfileRequired: pointer.Bool(true),
   235  							ComponentName:      componentName,
   236  							Annotations:        map[string]string{"skip-initial-checks": "true"},
   237  							Labels:             constants.ComponentDefaultLabel,
   238  						},
   239  					},
   240  				}},
   241  			}
   242  
   243  			Expect(f.AsKubeAdmin.CommonController.KubeRest().Create(context.TODO(), ps)).To(Succeed())
   244  			integrationTestScenario, err = f.AsKubeAdmin.IntegrationController.CreateIntegrationTestScenario_beta1(appName, userNamespace, testScenarioGitURL, testScenarioRevision, testScenarioPathInRepo)
   245  			Expect(err).ShouldNot(HaveOccurred())
   246  		})
   247  
   248  		It("sample app can be built successfully", func() {
   249  			component, err = f.AsKubeAdmin.HasController.CreateComponent(appName, componentName, userNamespace, sampleRepoURL, componentNewBaseBranch, "", "", "", true)
   250  			Expect(err).ShouldNot(HaveOccurred())
   251  			Expect(f.AsKubeAdmin.HasController.WaitForComponentPipelineToBeFinished(component, "", 2)).To(Succeed())
   252  		})
   253  
   254  		It("sample app is successfully deployed to dev environment", func() {
   255  			Expect(utils.WaitUntil(f.AsKubeAdmin.CommonController.DeploymentIsCompleted(componentName, userNamespace, 1), appDeployTimeout)).To(Succeed())
   256  		})
   257  
   258  		It("sample app's route can be accessed", func() {
   259  			Expect(utils.WaitUntil(f.AsKubeAdmin.CommonController.RouteHostnameIsAccessible(componentName, userNamespace), appRouteAvailableTimeout)).To(Succeed())
   260  		})
   261  
   262  		It("Snapshot is created", func() {
   263  			Eventually(func() (bool, error) {
   264  				snapshot, err = f.AsKubeAdmin.IntegrationController.GetSnapshot("", "", componentName, userNamespace)
   265  				if err != nil {
   266  					GinkgoWriter.Printf("cannot get the Snapshot: %v\n", err)
   267  					return false, err
   268  				}
   269  				return true, nil
   270  			}, snapshotTimeout, snapshotPollingInterval).Should(BeTrue())
   271  		})
   272  
   273  		It("Integration Test PipelineRun is created", func() {
   274  			Eventually(func() (bool, error) {
   275  				testPipelinerun, err = f.AsKubeAdmin.IntegrationController.GetIntegrationPipelineRun(integrationTestScenario.Name, snapshot.Name, userNamespace)
   276  				if err != nil {
   277  					GinkgoWriter.Printf("failed to get Integration test PipelineRun for a snapshot '%s' in '%s' namespace: %+v\n", snapshot.Name, userNamespace, err)
   278  					return false, err
   279  				}
   280  				return testPipelinerun.HasStarted(), nil
   281  			}, pipelineRunStartedTimeout, defaultPollingInterval).Should(BeTrue())
   282  			Expect(testPipelinerun.Labels["appstudio.openshift.io/snapshot"]).To(ContainSubstring(snapshot.Name))
   283  			Expect(testPipelinerun.Labels["test.appstudio.openshift.io/scenario"]).To(ContainSubstring(integrationTestScenario.Name))
   284  		})
   285  
   286  		It("Integration Test PipelineRun should eventually succeed", func() {
   287  			Expect(f.AsKubeAdmin.IntegrationController.WaitForIntegrationPipelineToBeFinished(integrationTestScenario, snapshot, appName, userNamespace)).To(Succeed(), "Error when waiting for a integration pipeline to finish")
   288  		})
   289  
   290  		It("Snapshot is marked as passed", func() {
   291  			Expect(f.AsKubeAdmin.IntegrationController.HaveTestsSucceeded(snapshot)).To(BeTrue())
   292  		})
   293  
   294  		It("Release is created", func() {
   295  			release, err = f.AsKubeAdmin.ReleaseController.GetRelease("", snapshot.Name, userNamespace)
   296  			Expect(err).ToNot(HaveOccurred())
   297  			Expect(release.Name).ToNot(BeEmpty())
   298  		})
   299  
   300  		It("Release PipelineRun is triggered", func() {
   301  			Eventually(func() (bool, error) {
   302  				pipelineRun, err = f.AsKubeAdmin.ReleaseController.GetPipelineRunInNamespace(managedNamespace, release.Name, release.Namespace)
   303  				if err != nil {
   304  					GinkgoWriter.Printf("pipelineRun for component '%s' in namespace '%s' not created yet: %+v\n", componentName, managedNamespace, err)
   305  					return false, err
   306  				}
   307  				return pipelineRun.HasStarted(), nil
   308  			}, pipelineRunStartedTimeout, defaultPollingInterval).Should(BeTrue(), fmt.Sprintf("component %q did not start a pipelinerun named %q in namespace %q from release %q in namespace %q in time", componentName, pipelineRun.Name, managedNamespace, release.Name, release.Namespace))
   309  		})
   310  
   311  		It("Release PipelineRun should eventually fail", func() {
   312  			Eventually(func() (bool, error) {
   313  				pipelineRun, err = f.AsKubeAdmin.ReleaseController.GetPipelineRunInNamespace(managedNamespace, release.Name, release.Namespace)
   314  				if err != nil {
   315  					GinkgoWriter.Printf("failed to get PipelineRun for a release '%s' in '%s' namespace: %+v\n", release.Name, managedNamespace, err)
   316  					return false, err
   317  				}
   318  				return pipelineRun.IsDone(), nil
   319  			}, releasePipelineTimeout, pipelineRunPollingInterval).Should(BeTrue(), fmt.Sprintf("the pipelinerun %q in namespace %q for release %q in namespace %q did not fail in time", pipelineRun.Name, managedNamespace, release.Name, release.Namespace))
   320  		})
   321  
   322  		It("associated Release should be marked as failed", func() {
   323  			Eventually(func() (bool, error) {
   324  				release, err = f.AsKubeAdmin.ReleaseController.GetRelease(release.Name, "", userNamespace)
   325  				if err != nil {
   326  					GinkgoWriter.Printf("failed to get Release CR in '%s' namespace: %+v\n", managedNamespace, err)
   327  					return false, err
   328  				}
   329  				return release.HasReleaseFinished() && !release.IsReleased(), nil
   330  			}, customResourceUpdateTimeout, defaultPollingInterval).Should(BeTrue(), fmt.Sprintf("the release %q in namespace %q was not marked as released but failed", release.Name, release.Namespace))
   331  		})
   332  
   333  	})
   334  
   335  	Describe("MVP Demo Chapter 2 - advanced pipeline, JVM rebuild, successful release, switch to simple build", Label("mvp-demo-chapter-2"), Ordered, func() {
   336  
   337  		var pacControllerHost, pacBranchName, pacPurgeBranchName string
   338  		var prNumber int
   339  		var mergeResult *github.PullRequestMergeResult
   340  		var mergeResultSha string
   341  
   342  		BeforeAll(func() {
   343  			// Used for identifying related webhook on GitHub - in order to delete it
   344  			// TODO: Remove when https://github.com/redhat-appstudio/infra-deployments/pull/1725 it is merged
   345  			pacControllerRoute, err = f.AsKubeAdmin.CommonController.GetOpenshiftRoute("pipelines-as-code-controller", "pipelines-as-code")
   346  			if err != nil {
   347  				if k8sErrors.IsNotFound(err) {
   348  					pacControllerRoute, err = f.AsKubeAdmin.CommonController.GetOpenshiftRoute("pipelines-as-code-controller", "openshift-pipelines")
   349  				}
   350  			}
   351  
   352  			Expect(err).ShouldNot(HaveOccurred())
   353  			pacControllerHost = pacControllerRoute.Spec.Host
   354  
   355  			pacBranchName = fmt.Sprintf("appstudio-%s", componentName)
   356  			pacPurgeBranchName = fmt.Sprintf("appstudio-purge-%s", componentName)
   357  
   358  			_, err = f.AsKubeAdmin.JvmbuildserviceController.CreateJBSConfig(constants.JBSConfigName, userNamespace)
   359  			Expect(err).ShouldNot(HaveOccurred())
   360  			build2.WaitForCache(f.AsKubeAdmin, userNamespace)
   361  
   362  		})
   363  		AfterAll(func() {
   364  
   365  			// Delete new branch created by PaC and a testing branch used as a component's base branch
   366  			err = f.AsKubeAdmin.CommonController.Github.DeleteRef(sampleRepoName, pacBranchName)
   367  			if err != nil {
   368  				Expect(err.Error()).To(ContainSubstring("Reference does not exist"))
   369  			}
   370  
   371  			// Delete created webhook from GitHub
   372  			hooks, err := f.AsKubeAdmin.CommonController.Github.ListRepoWebhooks(sampleRepoName)
   373  			Expect(err).NotTo(HaveOccurred())
   374  
   375  			for _, h := range hooks {
   376  				hookUrl := h.Config["url"].(string)
   377  				if strings.Contains(hookUrl, pacControllerHost) {
   378  					Expect(f.AsKubeAdmin.CommonController.Github.DeleteWebhook(sampleRepoName, h.GetID())).To(Succeed())
   379  					break
   380  				}
   381  			}
   382  		})
   383  
   384  		It("upgrading to SLSA level 3 customizable pipeline triggers creation of a PR in the sample repo", func() {
   385  			comp, err := f.AsKubeAdmin.HasController.GetHasComponent(componentName, userNamespace)
   386  			Expect(err).ShouldNot(HaveOccurred())
   387  			comp.Annotations["skip-initial-checks"] = "false"
   388  			for k, v := range constants.ComponentPaCRequestAnnotation {
   389  				comp.Annotations[k] = v
   390  			}
   391  			Expect(f.AsKubeAdmin.CommonController.KubeRest().Update(context.TODO(), comp)).To(Succeed())
   392  
   393  			pacBranchName := fmt.Sprintf("appstudio-%s", componentName)
   394  
   395  			var prSHA string
   396  			Eventually(func() (bool, error) {
   397  				prs, err := f.AsKubeAdmin.CommonController.Github.ListPullRequests(sampleRepoName)
   398  				if err != nil {
   399  					return false, err
   400  				}
   401  				for _, pr := range prs {
   402  					if pr.Head.GetRef() == pacBranchName {
   403  						prNumber = pr.GetNumber()
   404  						prSHA = pr.GetHead().GetSHA()
   405  						return true, nil
   406  					}
   407  				}
   408  				return false, fmt.Errorf("could not get the expected PaC branch name %s", pacBranchName)
   409  			}, pullRequestCreationTimeout, defaultPollingInterval).Should(BeTrue(), fmt.Sprintf("timed out when waiting for init PaC PR to be created against the %q repo", sampleRepoName))
   410  
   411  			// We actually don't need the "on-pull-request" PipelineRun to complete, so we can delete it
   412  			Eventually(func() (bool, error) {
   413  				pipelineRun, err = f.AsKubeAdmin.HasController.GetComponentPipelineRun(componentName, appName, userNamespace, prSHA)
   414  				if err == nil {
   415  					Expect(kc.Tektonctrl.DeletePipelineRun(pipelineRun.Name, pipelineRun.Namespace)).To(Succeed())
   416  					return true, nil
   417  				}
   418  				return false, err
   419  			}, pipelineRunStartedTimeout, pipelineRunPollingInterval).Should(BeTrue(), fmt.Sprintf("timed out when waiting for init PaC PipelineRun to be present in the user namespace %q for component %q with a label pointing to %q", userNamespace, componentName, appName))
   420  
   421  		})
   422  
   423  		It("merging the PaC init branch eventually leads to triggering another PipelineRun", func() {
   424  			Eventually(func() error {
   425  				mergeResult, err = f.AsKubeAdmin.CommonController.Github.MergePullRequest(sampleRepoName, prNumber)
   426  				return err
   427  			}, mergePRTimeout).Should(BeNil(), fmt.Sprintf("error when merging PaC pull request: %+v\n", err))
   428  
   429  			mergeResultSha = mergeResult.GetSHA()
   430  
   431  			Eventually(func() (bool, error) {
   432  				pipelineRun, err = f.AsKubeAdmin.HasController.GetComponentPipelineRun(componentName, appName, userNamespace, mergeResultSha)
   433  				if err != nil {
   434  					GinkgoWriter.Println("PipelineRun has not been created yet")
   435  					return false, err
   436  				}
   437  				return pipelineRun.HasStarted(), nil
   438  			}, pipelineRunStartedTimeout, pipelineRunPollingInterval).Should(BeTrue(), fmt.Sprintf("timed out when waiting for a PipelineRun in namespace %q with label component label %q and application label %q and sha label %q to start", userNamespace, componentName, appName, mergeResultSha))
   439  		})
   440  
   441  		It("SLSA level 3 customizable pipeline completes successfully", func() {
   442  			Expect(f.AsKubeAdmin.HasController.WaitForComponentPipelineToBeFinished(component, mergeResultSha, 2)).To(Succeed())
   443  		})
   444  
   445  		It("resulting SBOM file can be downloaded", func() {
   446  			var outputImage string
   447  			for _, p := range pipelineRun.Spec.Params {
   448  				if p.Name == "output-image" {
   449  					outputImage = p.Value.StringVal
   450  				}
   451  			}
   452  			Expect(outputImage).ToNot(BeEmpty(), "output image of a component could not be found")
   453  
   454  			_, _, err = build.GetParsedSbomFilesContentFromImage(outputImage)
   455  			Expect(err).NotTo(HaveOccurred())
   456  		})
   457  
   458  		It("validation of Tekton TaskRun test results completes successfully", func() {
   459  			pipelineRun, err := f.AsKubeAdmin.HasController.GetComponentPipelineRun(componentName, appName, userNamespace, mergeResultSha)
   460  			Expect(err).ShouldNot(HaveOccurred())
   461  			Expect(build.ValidateBuildPipelineTestResults(pipelineRun, f.AsKubeAdmin.CommonController.KubeRest())).To(Succeed())
   462  		})
   463  
   464  		It("Snapshot is created", func() {
   465  			Eventually(func() (bool, error) {
   466  				snapshot, err = f.AsKubeAdmin.IntegrationController.GetSnapshot("", pipelineRun.Name, "", userNamespace)
   467  				if err != nil {
   468  					GinkgoWriter.Printf("cannot get the Snapshot: %v\n", err)
   469  					return false, err
   470  				}
   471  				return true, nil
   472  			}, snapshotTimeout, snapshotPollingInterval).Should(BeTrue(), "timed out when trying to check if the Snapshot exists")
   473  		})
   474  
   475  		It("Release is created and Release PipelineRun is triggered and Release status is updated", func() {
   476  			Eventually(func() (bool, error) {
   477  				release, err = f.AsKubeAdmin.ReleaseController.GetRelease("", snapshot.Name, userNamespace)
   478  				if err != nil {
   479  					GinkgoWriter.Printf("cannot get the release: %v\n", err)
   480  					return false, err
   481  				}
   482  				return true, nil
   483  			}, releaseTimeout, releasePollingInterval).Should(BeTrue(), "timed out when trying to check if the release exists")
   484  
   485  			Eventually(func() (bool, error) {
   486  				pipelineRun, err = f.AsKubeAdmin.ReleaseController.GetPipelineRunInNamespace(managedNamespace, release.Name, release.Namespace)
   487  				if err != nil {
   488  					GinkgoWriter.Printf("pipelineRun for component '%s' in namespace '%s' not created yet: %+v\n", componentName, managedNamespace, err)
   489  					return false, err
   490  				}
   491  				return pipelineRun.HasStarted(), nil
   492  			}, pipelineRunStartedTimeout, defaultPollingInterval).Should(BeTrue(), fmt.Sprintf("failed to get pipelinerun named %q in namespace %q with label to release %q in namespace %q to start", pipelineRun.Name, managedNamespace, release.Name, release.Namespace))
   493  
   494  			Eventually(func() (bool, error) {
   495  				release, err = f.AsKubeAdmin.ReleaseController.GetRelease(release.Name, "", userNamespace)
   496  				if err != nil {
   497  					GinkgoWriter.Printf("failed to get Release CR in '%s' namespace: %+v\n", managedNamespace, err)
   498  					return false, err
   499  				}
   500  				return release.IsReleasing(), nil
   501  			}, customResourceUpdateTimeout, defaultPollingInterval).Should(BeTrue(), fmt.Sprintf("failed to get release %q in namespace %q to releasing state", release.Name, userNamespace))
   502  		})
   503  
   504  		It("Release PipelineRun should eventually succeed and associated Release should be marked as succeeded", func() {
   505  			Skip("Skip until bug is fixed: https://issues.redhat.com/browse/RHTAPBUGS-356")
   506  			Eventually(func() (bool, error) {
   507  				pipelineRun, err = f.AsKubeAdmin.ReleaseController.GetPipelineRunInNamespace(managedNamespace, release.Name, release.Namespace)
   508  				if err != nil {
   509  					GinkgoWriter.Printf("failed to get PipelineRun for a release '%s' in '%s' namespace: %+v\n", release.Name, managedNamespace, err)
   510  					return false, err
   511  				}
   512  				Expect(utils.PipelineRunFailed(pipelineRun)).NotTo(BeTrue(), fmt.Sprintf("did not expect PipelineRun %s:%s to fail", pipelineRun.GetNamespace(), pipelineRun.GetName()))
   513  				return pipelineRun.IsDone() && pipelineRun.GetStatusCondition().GetCondition(apis.ConditionSucceeded).IsTrue(), nil
   514  			}, releasePipelineTimeout, pipelineRunPollingInterval).Should(BeTrue(), fmt.Sprintf("failed to see pipelinerun %q in namespace %q with a label pointing to release %q in namespace %q to complete successfully", pipelineRun.Name, managedNamespace, release.Name, release.Namespace))
   515  
   516  			Eventually(func() (bool, error) {
   517  				release, err = f.AsKubeAdmin.ReleaseController.GetRelease(release.Name, "", userNamespace)
   518  				if err != nil {
   519  					GinkgoWriter.Printf("failed to get Release CR in '%s' namespace: %+v\n", managedNamespace, err)
   520  					return false, err
   521  				}
   522  				return release.IsReleased(), nil
   523  			}, customResourceUpdateTimeout, defaultPollingInterval).Should(BeTrue(), fmt.Sprintf("failed to see release %q in namespace %q get marked as released", release.Name, userNamespace))
   524  		})
   525  
   526  		It("JVM Build Service is used for rebuilding dependencies and completes rebuild of all artifacts and dependencies", func() {
   527  			Eventually(func() (bool, error) {
   528  				abList, err := f.AsKubeAdmin.JvmbuildserviceController.ListArtifactBuilds(userNamespace)
   529  				if err != nil {
   530  					GinkgoWriter.Printf("error listing artifactbuilds: %s\n", err.Error())
   531  					return false, err
   532  				}
   533  				for _, ab := range abList.Items {
   534  					if ab.Status.State != v1alpha1.ArtifactBuildStateComplete {
   535  						GinkgoWriter.Printf("artifactbuild %s not complete\n", ab.Spec.GAV)
   536  						return false, err
   537  					}
   538  				}
   539  				dbList, err := f.AsKubeAdmin.JvmbuildserviceController.ListDependencyBuilds(userNamespace)
   540  				if err != nil {
   541  					GinkgoWriter.Printf("error listing dependencybuilds: %s\n", err.Error())
   542  					return false, err
   543  				}
   544  				for _, db := range dbList.Items {
   545  					if db.Status.State != v1alpha1.DependencyBuildStateComplete {
   546  						GinkgoWriter.Printf("dependencybuild %s not complete\n", db.Spec.ScmInfo.SCMURL)
   547  						return false, err
   548  					}
   549  				}
   550  				return true, nil
   551  			}, jvmRebuildTimeout, jvmRebuildPollingInterval).Should(BeTrue(), fmt.Sprintf("timed out when waiting for all artifactbuilds and dependencybuilds to complete in namespace %q", userNamespace))
   552  		})
   553  
   554  		When("User switchs to simple build", func() {
   555  			BeforeAll(func() {
   556  				comp, err := f.AsKubeAdmin.HasController.GetHasComponent(componentName, userNamespace)
   557  				Expect(err).ShouldNot(HaveOccurred())
   558  				comp.Annotations["appstudio.openshift.io/pac-provision"] = "delete"
   559  				Expect(f.AsKubeAdmin.CommonController.KubeRest().Update(context.TODO(), comp)).To(Succeed())
   560  			})
   561  			AfterAll(func() {
   562  				// Delete the new branch created by sending purge PR while moving to simple build
   563  				err = f.AsKubeAdmin.CommonController.Github.DeleteRef(sampleRepoName, pacPurgeBranchName)
   564  				if err != nil {
   565  					Expect(err.Error()).To(ContainSubstring("Reference does not exist"))
   566  				}
   567  			})
   568  			It("PR removing PAC configuration is created", func() {
   569  				Eventually(func() (bool, error) {
   570  					prs, err := f.AsKubeAdmin.CommonController.Github.ListPullRequests(sampleRepoName)
   571  					if err != nil {
   572  						return false, err
   573  					}
   574  					for _, pr := range prs {
   575  						if pr.Head.GetRef() == pacPurgeBranchName {
   576  							return true, nil
   577  						}
   578  					}
   579  					return false, fmt.Errorf("could not get the expected PaC purge PR branch %s", pacPurgeBranchName)
   580  				}, time.Minute*1, defaultPollingInterval).Should(BeTrue(), fmt.Sprintf("timed out when waiting for PaC purge PR to be created against the %q repo", sampleRepoName))
   581  			})
   582  		})
   583  
   584  	})
   585  
   586  })
   587  
   588  func createUntrustedPipelineBundle() (string, error) {
   589  	var err error
   590  	var defaultBundleRef string
   591  	var tektonObj runtime.Object
   592  
   593  	tag := fmt.Sprintf("%d-%s", time.Now().Unix(), util.GenerateRandomString(4))
   594  	quayOrg := utils.GetEnv(constants.DEFAULT_QUAY_ORG_ENV, constants.DefaultQuayOrg)
   595  	newBuildahTaskRefImg := strings.ReplaceAll(constants.DefaultImagePushRepo, constants.DefaultQuayOrg, quayOrg)
   596  	var newBuildahTaskRef, _ = name.ParseReference(fmt.Sprintf("%s:task-bundle-%s", newBuildahTaskRefImg, tag))
   597  	newDockerBuildPipelineRefImg := strings.ReplaceAll(constants.DefaultImagePushRepo, constants.DefaultQuayOrg, quayOrg)
   598  	var newDockerBuildPipelineRef, _ = name.ParseReference(fmt.Sprintf("%s:pipeline-bundle-%s", newDockerBuildPipelineRefImg, tag))
   599  	var newBuildImage = "quay.io/containers/buildah:latest"
   600  	var newTaskYaml, newPipelineYaml []byte
   601  
   602  	if err = utils.CreateDockerConfigFile(os.Getenv("QUAY_TOKEN")); err != nil {
   603  		return "", fmt.Errorf("failed to create docker config file: %+v", err)
   604  	}
   605  	if defaultBundleRef, err = utils.GetDefaultPipelineBundleRef(constants.BuildPipelineSelectorYamlURL, "Docker build"); err != nil {
   606  		return "", fmt.Errorf("failed to get the pipeline bundle ref: %+v", err)
   607  	}
   608  	if tektonObj, err = utils.ExtractTektonObjectFromBundle(defaultBundleRef, "pipeline", "docker-build"); err != nil {
   609  		return "", fmt.Errorf("failed to extract the Tekton Pipeline from bundle: %+v", err)
   610  	}
   611  	dockerPipelineObj := tektonObj.(tektonapi.PipelineObject)
   612  
   613  	var currentBuildahTaskRef string
   614  	for _, t := range dockerPipelineObj.PipelineSpec().Tasks {
   615  		if t.TaskRef.Name == "buildah" {
   616  			currentBuildahTaskRef = t.TaskRef.Bundle
   617  			t.TaskRef.Bundle = newBuildahTaskRef.String()
   618  		}
   619  	}
   620  	if tektonObj, err = utils.ExtractTektonObjectFromBundle(currentBuildahTaskRef, "task", "buildah"); err != nil {
   621  		return "", fmt.Errorf("failed to extract the Tekton Task from bundle: %+v", err)
   622  	}
   623  	taskObj := tektonObj.(tektonapi.TaskObject)
   624  
   625  	for i, s := range taskObj.TaskSpec().Steps {
   626  		if s.Name == "build" {
   627  			taskObj.TaskSpec().Steps[i].Image = newBuildImage
   628  		}
   629  	}
   630  
   631  	if newTaskYaml, err = yaml.Marshal(taskObj); err != nil {
   632  		return "", fmt.Errorf("error when marshalling a new task to YAML: %v", err)
   633  	}
   634  	if newPipelineYaml, err = yaml.Marshal(dockerPipelineObj); err != nil {
   635  		return "", fmt.Errorf("error when marshalling a new pipeline to YAML: %v", err)
   636  	}
   637  
   638  	keychain := authn.NewMultiKeychain(authn.DefaultKeychain)
   639  	authOption := remoteimg.WithAuthFromKeychain(keychain)
   640  
   641  	if err = utils.BuildAndPushTektonBundle(newTaskYaml, newBuildahTaskRef, authOption); err != nil {
   642  		return "", fmt.Errorf("error when building/pushing a tekton task bundle: %v", err)
   643  	}
   644  	if err = utils.BuildAndPushTektonBundle(newPipelineYaml, newDockerBuildPipelineRef, authOption); err != nil {
   645  		return "", fmt.Errorf("error when building/pushing a tekton pipeline bundle: %v", err)
   646  	}
   647  
   648  	return newDockerBuildPipelineRef.Name(), nil
   649  }