diff --git a/Makefile b/Makefile index 1808d63d0b..dd8385012a 100644 --- a/Makefile +++ b/Makefile @@ -58,10 +58,7 @@ clean-gitops-repositories: DRY_RUN=false ./mage -v local:cleanupGithubOrg clean-github-webhooks: - ./mage -v cleanGitHubWebHooks - -clean-gitlab-webhooks: - ./mage -v cleanGitLabWebHooks + ./mage -v cleanWebHooks clean-quay-repos-and-robots: ./mage -v local:cleanupQuayReposAndRobots @@ -75,6 +72,9 @@ clean-private-repos: clean-registered-servers: ./mage -v CleanupRegisteredPacServers +setup-multi-arch-tests: + ./mage -v SetupMultiArchTests + setup-multi-platform-tests: ./mage -v SetupMultiPlatformTests diff --git a/magefiles/magefile.go b/magefiles/magefile.go index 4b2841de51..5022a8c163 100644 --- a/magefiles/magefile.go +++ b/magefiles/magefile.go @@ -26,7 +26,6 @@ import ( "github.com/konflux-ci/e2e-tests/magefiles/installation" "github.com/konflux-ci/e2e-tests/magefiles/upgrade" "github.com/konflux-ci/e2e-tests/pkg/clients/github" - "github.com/konflux-ci/e2e-tests/pkg/clients/gitlab" "github.com/konflux-ci/e2e-tests/pkg/clients/slack" "github.com/konflux-ci/e2e-tests/pkg/clients/sprayproxy" "github.com/konflux-ci/e2e-tests/pkg/constants" @@ -36,7 +35,7 @@ import ( "github.com/konflux-ci/image-controller/pkg/quay" "github.com/magefile/mage/sh" tektonapi "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1" - gl "github.com/xanzy/go-gitlab" + "k8s.io/apimachinery/pkg/selection" ) const ( @@ -59,6 +58,7 @@ var ( requiresSprayProxyRegistering bool requiresMultiPlatformTests bool + requiresMultiArchTests bool platforms = []string{"linux/arm64", "linux/s390x", "linux/ppc64le"} sprayProxyConfig *sprayproxy.SprayProxyConfig @@ -274,6 +274,12 @@ func (ci CI) TestE2E() error { } } + if requiresMultiArchTests { + if err := SetupMultiArchTests(); err != nil { + return err + } + } + if requiresMultiPlatformTests { if err := SetupMultiPlatformTests(); err != nil { return err @@ -502,6 +508,7 @@ func setRequiredEnvVars() error { */ os.Setenv("E2E_TEST_SUITE_LABEL", "e2e-demo,rhtap-demo,spi-suite,remote-secret,integration-service,ec,build-templates,multi-platform") } else if strings.Contains(jobName, "release-service-catalog") { // release-service-catalog jobs (pull, rehearsal) + requiresMultiArchTests = true envVarPrefix := "RELEASE_SERVICE" os.Setenv("E2E_TEST_SUITE_LABEL", "release-pipelines") // "rehearse" jobs metadata are not relevant for testing @@ -542,6 +549,192 @@ func setRequiredEnvVars() error { return nil } +func SetupMultiArchTests() error { + klog.Infof("going to create new Tekton bundle remote-build for the purpose of testing multi-arch PR") + var err error + var defaultBundleRef string + var tektonObj runtime.Object + //currently, we can only create one image and the image index + platformType := "linux/amd64" + + tag := fmt.Sprintf("%d-%s", time.Now().Unix(), util.GenerateRandomString(4)) + quayOrg := utils.GetEnv(constants.DEFAULT_QUAY_ORG_ENV, constants.DefaultQuayOrg) + newMultiPlatformBuilderPipelineImg := strings.ReplaceAll(constants.DefaultImagePushRepo, constants.DefaultQuayOrg, quayOrg) + var newRemotePipeline, _ = name.ParseReference(fmt.Sprintf("%s:pipeline-bundle-%s", newMultiPlatformBuilderPipelineImg, tag)) + var newPipelineYaml []byte + + if err = utils.CreateDockerConfigFile(os.Getenv("QUAY_TOKEN")); err != nil { + return fmt.Errorf("failed to create docker config file: %+v", err) + } + if defaultBundleRef, err = tekton.GetDefaultPipelineBundleRef(constants.BuildPipelineConfigConfigMapYamlURL, "docker-build"); err != nil { + return fmt.Errorf("failed to get the pipeline bundle ref: %+v", err) + } + if tektonObj, err = tekton.ExtractTektonObjectFromBundle(defaultBundleRef, "pipeline", "docker-build"); err != nil { + return fmt.Errorf("failed to extract the Tekton Pipeline from bundle: %+v", err) + } + dockerPipelineObject := tektonObj.(*tektonapi.Pipeline) + + var currentBuildahTaskRef string + for i := range dockerPipelineObject.PipelineSpec().Tasks { + t := &dockerPipelineObject.PipelineSpec().Tasks[i] + if t.Name == "build-source-image" { + t.RunAfter = []string{"build-container"} + for i, p := range t.Params { + tmpParam := &t.Params[i] + if p.Name == "BASE_IMAGES" { + tmpParam.Value = *tektonapi.NewStructuredValues("$(tasks.build-container-amd64.results.BASE_IMAGES_DIGESTS)") + } + } + } + if t.Name == "ecosystem-cert-preflight-checks" { + t.RunAfter = []string{"build-container"} + for i, p := range t.Params { + tmpParam := &t.Params[i] + if p.Name == "image-url" { + tmpParam.Value = *tektonapi.NewStructuredValues("$(tasks.build-container-amd64.results.IMAGE_URL)") + } + } + } + if t.Name == "clair-scan" || t.Name == "clamav-scan" { + t.RunAfter = []string{"build-container"} + for i, p := range t.Params { + tmpParam := &t.Params[i] + if p.Name == "image-digest" { + tmpParam.Value = *tektonapi.NewStructuredValues("$(tasks.build-container-amd64.results.IMAGE_DIGEST)") + } + if p.Name == "image-url" { + tmpParam.Value = *tektonapi.NewStructuredValues("$(tasks.build-container-amd64.results.IMAGE_URL)") + } + } + } + if t.Name == "deprecated-base-image-check" || t.Name == "sbom-json-check" { + t.RunAfter = []string{"build-container"} + for i, p := range t.Params { + tmpParam := &t.Params[i] + if p.Name == "IMAGE_URL" { + tmpParam.Value = *tektonapi.NewStructuredValues("$(tasks.build-container-amd64.results.IMAGE_URL)") + } + if p.Name == "IMAGES_DIGESTS" { + tmpParam.Value = *tektonapi.NewStructuredValues("$(tasks.build-container-amd64.results.IMAGES_DIGESTS)") + } + if t.Name == "deprecated-base-image-check" && p.Name == "BASE_IMAGES_DIGESTS" { + tmpParam.Value = *tektonapi.NewStructuredValues("$(tasks.build-container-amd64.results.BASE_IMAGES_DIGESTS)") + } + } + } + } + for i := range dockerPipelineObject.PipelineSpec().Finally { + t := &dockerPipelineObject.PipelineSpec().Finally[i] + if t.Name == "show-sbom" { + for i, p := range t.Params { + tmpParam := &t.Params[i] + if p.Name == "IMAGE_URL" { + tmpParam.Value = *tektonapi.NewStructuredValues("$(tasks.build-container-amd64.results.IMAGE_URL)") + } + } + } + } + for i := range dockerPipelineObject.PipelineSpec().Tasks { + t := &dockerPipelineObject.PipelineSpec().Tasks[i] + params := t.TaskRef.Params + var lastBundle *tektonapi.Param + var lastName *tektonapi.Param + buildahTask := false + for i, param := range params { + if param.Name == "bundle" { + lastBundle = &t.TaskRef.Params[i] + } else if param.Name == "name" && param.Value.StringVal == "buildah" { + lastName = &t.TaskRef.Params[i] + buildahTask = true + } + } + if buildahTask { + t.Name = "build-container-amd64" + currentBuildahTaskRef = lastBundle.Value.StringVal + klog.Infof("Found current task ref %s", currentBuildahTaskRef) + //TODO: current use pinned sha? + lastBundle.Value = *tektonapi.NewStructuredValues("quay.io/redhat-appstudio-tekton-catalog/task-buildah-remote:0.1-ac185e95bbd7a25c1c4acf86995cbaf30eebedc4") + lastName.Value = *tektonapi.NewStructuredValues("buildah-remote") + t.Params = append(t.Params, tektonapi.Param{Name: "PLATFORM", Value: *tektonapi.NewStructuredValues("$(params.PLATFORM)")}) + dockerPipelineObject.Spec.Params = append(dockerPipelineObject.PipelineSpec().Params, tektonapi.ParamSpec{Name: "PLATFORM", Default: tektonapi.NewStructuredValues(platformType)}) + for i, result := range dockerPipelineObject.Spec.Results { + if result.Name == "JAVA_COMMUNITY_DEPENDENCIES" { + javaResult := &dockerPipelineObject.Spec.Results[i] + javaResult.Value = *tektonapi.NewStructuredValues("$(tasks.build-container-amd64.results.JAVA_COMMUNITY_DEPENDENCIES)") + } + } + dockerPipelineObject.Name = "multi-arch-pipeline" + break + } + } + newTaskRef := &tektonapi.TaskRef{ + ResolverRef: tektonapi.ResolverRef{ + Params: []tektonapi.Param{ + { + Name: "name", + Value: *tektonapi.NewStructuredValues("build-image-manifest"), + }, + { + Name: "bundle", + //?use the fixed sha + Value: *tektonapi.NewStructuredValues("quay.io/redhat-appstudio-tekton-catalog/task-build-image-manifest:0.1@sha256:e064b63b2311d23d6bf6538347cb4eb18c980d61883f48149bc9c728f76b276c"), + }, + { + Name: "kind", + Value: *tektonapi.NewStructuredValues("task"), + }, + }, + Resolver: "bundles", + }, + } + + newTask := &tektonapi.PipelineTask{ + Name: "build-container", + RunAfter: []string{"build-container-amd64"}, + TaskRef: newTaskRef, + Params: []tektonapi.Param{ + { + Name: "IMAGE", + Value: *tektonapi.NewStructuredValues("$(params.output-image)"), + }, + { + Name: "COMMIT_SHA", + Value: *tektonapi.NewStructuredValues("$(tasks.clone-repository.results.commit)"), + }, + { + Name: "IMAGES", + Value: tektonapi.ParamValue{ + Type: tektonapi.ParamTypeArray, + ArrayVal: []string{ + "$(tasks.build-container-amd64.results.IMAGE_URL)@$(tasks.build-container-amd64.results.IMAGE_DIGEST)", + }, + }, + }, + }, + When: tektonapi.WhenExpressions{{ + Input: "$(tasks.init.results.build)", + Operator: selection.In, + Values: []string{"true"}, + }}, + } + + dockerPipelineObject.Spec.Tasks = append(dockerPipelineObject.PipelineSpec().Tasks, *newTask) + if newPipelineYaml, err = yaml.Marshal(dockerPipelineObject); err != nil { + return fmt.Errorf("error when marshalling a new pipeline to YAML: %v", err) + } + + keychain := authn.NewMultiKeychain(authn.DefaultKeychain) + authOption := remoteimg.WithAuthFromKeychain(keychain) + + if err = tekton.BuildAndPushTektonBundle(newPipelineYaml, newRemotePipeline, authOption); err != nil { + return fmt.Errorf("error when building/pushing a tekton pipeline bundle: %v", err) + } + klog.Infof("SETTING ENV VAR %s to value %s\n", constants.CUSTOM_MULTI_ARCH_PIPELINE_BUILD_BUNDLE_ENV, newRemotePipeline.String()) + os.Setenv(constants.CUSTOM_MULTI_ARCH_PIPELINE_BUILD_BUNDLE_ENV, newRemotePipeline.String()) + + return nil +} + func SetupMultiPlatformTests() error { klog.Infof("going to create new Tekton bundle remote-build for the purpose of testing multi-platform-controller PR") var err error @@ -825,9 +1018,8 @@ func GenerateTestSuiteFile(packageName string) error { return nil } -// Remove all webhooks older than 1 day from GitHub repo. -// By default will delete webhooks from redhat-appstudio-qe -func CleanGitHubWebHooks() error { +// Remove all webhooks which with 1 day lifetime. By default will delete webooks from redhat-appstudio-qe +func CleanWebHooks() error { token := utils.GetEnv(constants.GITHUB_TOKEN_ENV, "") if token == "" { return fmt.Errorf("empty GITHUB_TOKEN env. Please provide a valid github token") @@ -856,38 +1048,6 @@ func CleanGitHubWebHooks() error { return nil } -// Remove all webhooks older than 1 day from GitLab repo. -func CleanGitLabWebHooks() error { - gcToken := utils.GetEnv(constants.GITLAB_TOKEN_ENV, "") - if gcToken == "" { - return fmt.Errorf("empty PAC_GITLAB_TOKEN env") - } - projectID := utils.GetEnv(constants.GITLAB_PROJECT_ID, "") - if projectID == "" { - return fmt.Errorf("empty PAC_PROJECT_ID env. Please provide a valid GitLab Project ID") - } - gitlabURL := utils.GetEnv(constants.GITLAB_URL_ENV, "https://gitlab.com/api/v4") - gc, err := gitlab.NewGitlabClient(gcToken, gitlabURL) - if err != nil { - return err - } - webhooks, _, err := gc.GetClient().Projects.ListProjectHooks(projectID, &gl.ListProjectHooksOptions{PerPage: 100}) - if err != nil { - return fmt.Errorf("failed to list project hooks: %v", err) - } - // Delete webhooks that are older than 1 day - for _, webhook := range webhooks { - dayDuration, _ := time.ParseDuration("24h") - if time.Since(*webhook.CreatedAt) > dayDuration { - klog.Infof("removing webhookURL: %s", webhook.URL) - if _, err := gc.GetClient().Projects.DeleteProjectHook(projectID, webhook.ID); err != nil { - return fmt.Errorf("failed to delete webhook (URL: %s): %v", webhook.URL, err) - } - } - } - return nil -} - // Generate a Text Outline file from a Ginkgo Spec func GenerateTextOutlineFromGinkgoSpec(source string, destination string) error { diff --git a/pkg/constants/constants.go b/pkg/constants/constants.go index 9c8cc48685..8c5f62a4a5 100644 --- a/pkg/constants/constants.go +++ b/pkg/constants/constants.go @@ -85,6 +85,9 @@ const ( // Managed workspace for release pipelines tests RELEASE_MANAGED_WORKSPACE_ENV = "RELEASE_MANAGED_WORKSPACE" + // Bundle ref for overriding the default Java build bundle specified in BuildPipelineConfigConfigMapYamlURL + CUSTOM_MULTI_ARCH_PIPELINE_BUILD_BUNDLE_ENV string = "CUSTOM_MULTI_ARCH_PIPELINE_BUILD_BUNDLE" + // Bundle ref for overriding the default Java build bundle specified in BuildPipelineConfigConfigMapYamlURL CUSTOM_JAVA_PIPELINE_BUILD_BUNDLE_ENV string = "CUSTOM_JAVA_PIPELINE_BUILD_BUNDLE" diff --git a/tests/release/const.go b/tests/release/const.go index ef49274cf7..71936558c3 100644 --- a/tests/release/const.go +++ b/tests/release/const.go @@ -36,6 +36,7 @@ const ( ComponentName string = "dc-metro-map" GitSourceComponentUrl string = "https://github.com/scoheb/dc-metro-map" AdditionalComponentName string = "simple-python" + MultiArchComponentUrl string = "https://github.com/jinqi7/multi-platform-test-prod" AdditionalGitSourceComponentUrl string = "https://github.com/devfile-samples/devfile-sample-python-basic" ReleasedImagePushRepo string = "quay.io/redhat-appstudio-qe/dcmetromap" AdditionalReleasedImagePushRepo string = "quay.io/redhat-appstudio-qe/simplepython" diff --git a/tests/release/pipelines/multi_arch_advisories.go b/tests/release/pipelines/multi_arch_advisories.go new file mode 100644 index 0000000000..55027f1d05 --- /dev/null +++ b/tests/release/pipelines/multi_arch_advisories.go @@ -0,0 +1,289 @@ +package pipelines + +import ( + "encoding/base64" + "encoding/json" + "fmt" + "os" + "regexp" + "time" + + "github.com/devfile/library/v2/pkg/util" + ecp "github.com/enterprise-contract/enterprise-contract-controller/api/v1alpha1" + appservice "github.com/konflux-ci/application-api/api/v1alpha1" + "github.com/konflux-ci/e2e-tests/pkg/constants" + "github.com/konflux-ci/e2e-tests/pkg/framework" + "github.com/konflux-ci/e2e-tests/pkg/utils" + "github.com/konflux-ci/e2e-tests/pkg/utils/tekton" + releasecommon "github.com/konflux-ci/e2e-tests/tests/release" + releaseapi "github.com/konflux-ci/release-service/api/v1alpha1" + tektonutils "github.com/konflux-ci/release-service/tekton/utils" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + tektonv1 "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "knative.dev/pkg/apis" +) + +const ( + multiServiceAccountName = "release-service-account" + multiCatalogPathInRepo = "pipelines/rh-advisories/rh-advisories.yaml" +) + +var mcomponent *appservice.Component + +var _ = framework.ReleasePipelinesSuiteDescribe("e2e tests for rh-advisories pipeline", Label("release-pipelines", "multiarch-advisories"), func() { + defer GinkgoRecover() + var pyxisKeyDecoded, pyxisCertDecoded []byte + + var devWorkspace = utils.GetEnv(constants.RELEASE_DEV_WORKSPACE_ENV, constants.DevReleaseTeam) + var managedWorkspace = utils.GetEnv(constants.RELEASE_MANAGED_WORKSPACE_ENV, constants.ManagedReleaseTeam) + + var devNamespace = devWorkspace + "-tenant" + var managedNamespace = managedWorkspace + "-tenant" + + var err error + var devFw *framework.Framework + var managedFw *framework.Framework + var multiApplicationName = "multi-app-" + util.GenerateRandomString(4) + var multiComponentName = "multi-comp-" + util.GenerateRandomString(4) + var multiReleasePlanName = "multi-rp-" + util.GenerateRandomString(4) + var multiReleasePlanAdmissionName = "multi-rpa-" + util.GenerateRandomString(4) + var multiEnterpriseContractPolicyName = "multi-policy-" + util.GenerateRandomString(4) + + var snapshot *appservice.Snapshot + var releaseCR *releaseapi.Release + var releasePR, buildPR *tektonv1.PipelineRun + + AfterEach(framework.ReportFailure(&devFw)) + + Describe("Multiarch-advisories happy path", Label("multiArchAdvisories"), func() { + BeforeAll(func() { + devFw = releasecommon.NewFramework(devWorkspace) + managedFw = releasecommon.NewFramework(managedWorkspace) + managedNamespace = managedFw.UserNamespace + + keyPyxisStage := os.Getenv(constants.PYXIS_STAGE_KEY_ENV) + Expect(keyPyxisStage).ToNot(BeEmpty()) + + certPyxisStage := os.Getenv(constants.PYXIS_STAGE_CERT_ENV) + Expect(certPyxisStage).ToNot(BeEmpty()) + + // Creating k8s secret to access Pyxis stage based on base64 decoded of key and cert + pyxisKeyDecoded, err = base64.StdEncoding.DecodeString(string(keyPyxisStage)) + Expect(err).ToNot(HaveOccurred()) + + pyxisCertDecoded, err = base64.StdEncoding.DecodeString(string(certPyxisStage)) + Expect(err).ToNot(HaveOccurred()) + + secret := &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: "pyxis", + Namespace: managedNamespace, + }, + Type: corev1.SecretTypeOpaque, + Data: map[string][]byte{ + "cert": pyxisCertDecoded, + "key": pyxisKeyDecoded, + }, + } + + // Delete the secret if it exists in case it is not correct + _ = managedFw.AsKubeAdmin.CommonController.DeleteSecret(managedNamespace, "pyxis") + _, err = managedFw.AsKubeAdmin.CommonController.CreateSecret(managedNamespace, secret) + Expect(err).ToNot(HaveOccurred()) + + err = managedFw.AsKubeAdmin.CommonController.LinkSecretToServiceAccount(managedNamespace, releasecommon.RedhatAppstudioUserSecret, constants.DefaultPipelineServiceAccount, true) + Expect(err).ToNot(HaveOccurred()) + + _, err = devFw.AsKubeDeveloper.HasController.CreateApplication(multiApplicationName, devNamespace) + Expect(err).NotTo(HaveOccurred()) + + createMULTIReleasePlan(multiReleasePlanName, *devFw, devNamespace, multiApplicationName, managedNamespace, "true") + + customBuildahRemotePipeline := utils.GetEnv("CUSTOM_MULTI_ARCH_PIPELINE_BUILD_BUNDLE", "quay.io/redhat-appstudio-qe/test-images@sha256:f527c1a4e77559cc94ee32c9751fac36cf32883e6c2e28c0df0f4773d2c25f54") + + buildPipelineAnnotation := map[string]string{ + "build.appstudio.openshift.io/pipeline": fmt.Sprintf(`{"name":"multi-arch-pipeline", "bundle": "%s"}`, customBuildahRemotePipeline), + } + + mcomponent = releasecommon.CreateComponent(*devFw, devNamespace, multiApplicationName, multiComponentName, releasecommon.MultiArchComponentUrl, "", ".", constants.DockerFilePath, buildPipelineAnnotation) + + createMULTIReleasePlanAdmission(multiReleasePlanAdmissionName, *managedFw, devNamespace, managedNamespace, multiApplicationName, multiEnterpriseContractPolicyName, multiCatalogPathInRepo) + + createMULTIEnterpriseContractPolicy(multiEnterpriseContractPolicyName, *managedFw, devNamespace, managedNamespace) + }) + + AfterAll(func() { + devFw = releasecommon.NewFramework(devWorkspace) + managedFw = releasecommon.NewFramework(managedWorkspace) + Expect(devFw.AsKubeDeveloper.HasController.DeleteApplication(multiApplicationName, devNamespace, false)).NotTo(HaveOccurred()) + Expect(managedFw.AsKubeDeveloper.TektonController.DeleteEnterpriseContractPolicy(multiEnterpriseContractPolicyName, managedNamespace, false)).NotTo(HaveOccurred()) + Expect(managedFw.AsKubeDeveloper.ReleaseController.DeleteReleasePlanAdmission(multiReleasePlanAdmissionName, managedNamespace, false)).NotTo(HaveOccurred()) + }) + + var _ = Describe("Post-release verification", func() { + It("verifies that a build PipelineRun is created in dev namespace and succeeds", func() { + devFw = releasecommon.NewFramework(devWorkspace) + managedFw = releasecommon.NewFramework(managedWorkspace) + // Create a ticker that ticks every 3 minutes + ticker := time.NewTicker(3 * time.Minute) + // Schedule the stop of the ticker after 15 minutes + time.AfterFunc(15*time.Minute, func() { + ticker.Stop() + fmt.Println("Stopped executing every 3 minutes.") + }) + // Run a goroutine to handle the ticker ticks + go func() { + for range ticker.C { + devFw = releasecommon.NewFramework(devWorkspace) + managedFw = releasecommon.NewFramework(managedWorkspace) + } + }() + Eventually(func() error { + buildPR, err = devFw.AsKubeDeveloper.HasController.GetComponentPipelineRun(mcomponent.Name, multiApplicationName, devNamespace, "") + if err != nil { + GinkgoWriter.Printf("Build PipelineRun has not been created yet for the component %s/%s\n", devNamespace, mcomponent.Name) + return err + } + GinkgoWriter.Printf("PipelineRun %s reason: %s\n", buildPR.Name, buildPR.GetStatusCondition().GetCondition(apis.ConditionSucceeded).GetReason()) + if !buildPR.IsDone() { + return fmt.Errorf("build pipelinerun %s in namespace %s did not finish yet", buildPR.Name, buildPR.Namespace) + } + if buildPR.GetStatusCondition().GetCondition(apis.ConditionSucceeded).IsTrue() { + snapshot, err = devFw.AsKubeDeveloper.IntegrationController.GetSnapshot("", buildPR.Name, "", devNamespace) + if err != nil { + return err + } + return nil + } else { + return fmt.Errorf(tekton.GetFailedPipelineRunLogs(devFw.AsKubeDeveloper.HasController.KubeRest(), devFw.AsKubeDeveloper.HasController.KubeInterface(), buildPR)) + } + }, releasecommon.BuildPipelineRunCompletionTimeout, releasecommon.DefaultInterval).Should(Succeed(), fmt.Sprintf("timed out when waiting for the build PipelineRun to be finished for the component %s/%s", devNamespace, mcomponent.Name)) + }) + It("verifies the multi release pipelinerun is running and succeeds", func() { + devFw = releasecommon.NewFramework(devWorkspace) + managedFw = releasecommon.NewFramework(managedWorkspace) + + releaseCR, err = devFw.AsKubeDeveloper.ReleaseController.GetRelease("", snapshot.Name, devNamespace) + Expect(err).ShouldNot(HaveOccurred()) + + Expect(managedFw.AsKubeAdmin.ReleaseController.WaitForReleasePipelineToBeFinished(releaseCR, managedNamespace)).To(Succeed(), fmt.Sprintf("Error when waiting for a release pipelinerun for release %s/%s to finish", releaseCR.GetNamespace(), releaseCR.GetName())) + }) + + It("verifies release CR completed and set succeeded.", func() { + devFw = releasecommon.NewFramework(devWorkspace) + Eventually(func() error { + releaseCr, err := devFw.AsKubeDeveloper.ReleaseController.GetRelease("", snapshot.Name, devNamespace) + if err != nil { + return err + } + GinkgoWriter.Println("Release CR: ", releaseCr.Name) + if !releaseCr.IsReleased() { + return fmt.Errorf("release %s/%s is not marked as finished yet", releaseCR.GetNamespace(), releaseCR.GetName()) + } + return nil + }, 10*time.Minute, releasecommon.DefaultInterval).Should(Succeed()) + }) + + It("verifies if the repository URL is valid", func() { + managedFw = releasecommon.NewFramework(managedWorkspace) + releasePR, err = managedFw.AsKubeAdmin.ReleaseController.GetPipelineRunInNamespace(managedFw.UserNamespace, releaseCR.GetName(), releaseCR.GetNamespace()) + Expect(err).NotTo(HaveOccurred()) + advisoryURL := releasePR.Status.PipelineRunStatusFields.Results[0].Value.StringVal + pattern := `https?://[^/\s]+/[^/\s]+/[^/\s]+/+\-\/blob\/main\/data\/advisories\/[^\/]+\/[^\/]+\/[^\/]+\/advisory\.yaml` + re, err := regexp.Compile(pattern) + Expect(err).NotTo(HaveOccurred()) + Expect(re.MatchString(advisoryURL)).To(BeTrue(), fmt.Sprintf("Advisory_url %s is not valid", advisoryURL)) + }) + }) + }) +}) + +func createMULTIEnterpriseContractPolicy(multiECPName string, managedFw framework.Framework, devNamespace, managedNamespace string) { + defaultEcPolicySpec := ecp.EnterpriseContractPolicySpec{ + Description: "Red Hat's enterprise requirements", + PublicKey: "k8s://openshift-pipelines/public-key", + Sources: []ecp.Source{{ + Name: "Default", + Policy: []string{releasecommon.EcPolicyLibPath, releasecommon.EcPolicyReleasePath}, + Data: []string{releasecommon.EcPolicyDataBundle, releasecommon.EcPolicyDataPath}, + }}, + Configuration: &ecp.EnterpriseContractPolicyConfiguration{ + Exclude: []string{"step_image_registries", "tasks.required_tasks_found:prefetch-dependencies"}, + Include: []string{"@slsa3"}, + }, + } + + _, err := managedFw.AsKubeDeveloper.TektonController.CreateEnterpriseContractPolicy(multiECPName, managedNamespace, defaultEcPolicySpec) + Expect(err).NotTo(HaveOccurred()) + +} + +func createMULTIReleasePlan(multiReleasePlanName string, devFw framework.Framework, devNamespace, multiAppName, managedNamespace string, autoRelease string) { + var err error + + data, err := json.Marshal(map[string]interface{}{ + "releaseNotes": map[string]interface{}{ + "description": "releaseNotes description", + "references": []string{"https://server.com/ref1", "http://server2.com/ref2"}, + "solution": "some solution", + "synopsis": "test synopsis", + "topic": "test topic", + }, + }) + Expect(err).NotTo(HaveOccurred()) + + _, err = devFw.AsKubeDeveloper.ReleaseController.CreateReleasePlan(multiReleasePlanName, devNamespace, multiAppName, + managedNamespace, autoRelease, &runtime.RawExtension{ + Raw: data, + }) + Expect(err).NotTo(HaveOccurred()) +} + +func createMULTIReleasePlanAdmission(multiRPAName string, managedFw framework.Framework, devNamespace, managedNamespace, multiAppName, multiECPName, pathInRepoValue string) { + var err error + + data, err := json.Marshal(map[string]interface{}{ + "mapping": map[string]interface{}{ + "components": []map[string]interface{}{ + { + "name": mcomponent.GetName(), + "repository": "quay.io/redhat-pending/rhtap----konflux-release-e2e", + "tags": []string{"latest", "latest-{{ timestamp }}", "testtag", + "testtag-{{ timestamp }}", "testtag2", "testtag2-{{ timestamp }}"}, + }, + }, + }, + "pyxis": map[string]interface{}{ + "server": "stage", + "secret": "pyxis", + }, + "releaseNotes": map[string]interface{}{ + "cpe": "cpe:/a:example.com", + "product_id": "555", + "product_name": "test product", + "product_stream": "rhtas-tp1", + "product_version": "v1.0", + "type": "RHSA", + }, + "sign": map[string]interface{}{ + "configMapName": "hacbs-signing-pipeline-config-redhatbeta2", + }, + }) + Expect(err).NotTo(HaveOccurred()) + + _, err = managedFw.AsKubeAdmin.ReleaseController.CreateReleasePlanAdmission(multiRPAName, managedNamespace, "", devNamespace, multiECPName, multiServiceAccountName, []string{multiAppName}, true, &tektonutils.PipelineRef{ + Resolver: "git", + Params: []tektonutils.Param{ + {Name: "url", Value: releasecommon.RelSvcCatalogURL}, + {Name: "revision", Value: releasecommon.RelSvcCatalogRevision}, + {Name: "pathInRepo", Value: pathInRepoValue}, + }, + }, &runtime.RawExtension{ + Raw: data, + }) + Expect(err).NotTo(HaveOccurred()) +}