github.com/redhat-appstudio/e2e-tests@v0.0.0-20230619105049-9a422b2094d7/tests/release/e2e-test-push-image-to-pyxis.go (about)

     1  package release
     2  
     3  import (
     4  	"encoding/base64"
     5  	"encoding/json"
     6  	"fmt"
     7  	"os"
     8  	"regexp"
     9  	"strings"
    10  
    11  	"github.com/devfile/library/pkg/util"
    12  	. "github.com/onsi/ginkgo/v2"
    13  	. "github.com/onsi/gomega"
    14  	"gopkg.in/yaml.v2"
    15  
    16  	appservice "github.com/redhat-appstudio/application-api/api/v1alpha1"
    17  	"github.com/redhat-appstudio/e2e-tests/pkg/constants"
    18  	"github.com/redhat-appstudio/e2e-tests/pkg/framework"
    19  	"github.com/redhat-appstudio/e2e-tests/pkg/utils"
    20  	"github.com/redhat-appstudio/e2e-tests/pkg/utils/release"
    21  	"github.com/redhat-appstudio/e2e-tests/pkg/utils/tekton"
    22  	releaseApi "github.com/redhat-appstudio/release-service/api/v1alpha1"
    23  	"knative.dev/pkg/apis"
    24  
    25  	ecp "github.com/enterprise-contract/enterprise-contract-controller/api/v1alpha1"
    26  	corev1 "k8s.io/api/core/v1"
    27  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    28  )
    29  
    30  var _ = framework.ReleaseSuiteDescribe("[HACBS-1571]test-release-e2e-push-image-to-pyxis", Label("release", "pushPyxis", "HACBS"), func() {
    31  	defer GinkgoRecover()
    32  	// Initialize the tests controllers
    33  	var fw *framework.Framework
    34  	var err error
    35  	var kubeController tekton.KubeController
    36  	var devNamespace, managedNamespace, compName, additionalCompName string
    37  	var imageIDs []string
    38  	var pyxisKeyDecoded, pyxisCertDecoded []byte
    39  	var releasePrName, additionalReleasePrName string
    40  	scGitRevision := fmt.Sprintf("test-pyxis-%s", util.GenerateRandomString(4))
    41  
    42  	var component1, component2 *appservice.Component
    43  
    44  	var componentDetected, additionalComponentDetected appservice.ComponentDetectionDescription
    45  
    46  	BeforeAll(func() {
    47  		fw, err = framework.NewFramework(utils.GetGeneratedNamespace("e2e-pyxis"))
    48  		Expect(err).NotTo(HaveOccurred())
    49  
    50  		kubeController = tekton.KubeController{
    51  			Commonctrl: *fw.AsKubeAdmin.CommonController,
    52  			Tektonctrl: *fw.AsKubeAdmin.TektonController,
    53  		}
    54  
    55  		devNamespace = fw.UserNamespace
    56  		managedNamespace = utils.GetGeneratedNamespace("pyxis-managed")
    57  
    58  		_, err = fw.AsKubeAdmin.CommonController.CreateTestNamespace(managedNamespace)
    59  		Expect(err).NotTo(HaveOccurred(), "Error when creating managedNamespace: ", err)
    60  
    61  		destinationAuthJson := utils.GetEnv("QUAY_OAUTH_TOKEN_RELEASE_DESTINATION", "")
    62  		Expect(destinationAuthJson).ToNot(BeEmpty())
    63  
    64  		keyPyxisStage := os.Getenv(constants.PYXIS_STAGE_KEY_ENV)
    65  		Expect(keyPyxisStage).ToNot(BeEmpty())
    66  
    67  		certPyxisStage := os.Getenv(constants.PYXIS_STAGE_CERT_ENV)
    68  		Expect(certPyxisStage).ToNot(BeEmpty())
    69  
    70  		// Create secret for the release registry repo "hacbs-release-tests".
    71  		_, err = fw.AsKubeAdmin.CommonController.CreateRegistryAuthSecret(redhatAppstudioUserSecret, managedNamespace, destinationAuthJson)
    72  		Expect(err).ToNot(HaveOccurred())
    73  
    74  		// Linking the build secret to the pipeline service account in dev namespace.
    75  		err = fw.AsKubeAdmin.CommonController.LinkSecretToServiceAccount(devNamespace, hacbsReleaseTestsTokenSecret, serviceAccount, true)
    76  		Expect(err).ToNot(HaveOccurred())
    77  
    78  		publicKey, err := kubeController.GetTektonChainsPublicKey()
    79  		Expect(err).ToNot(HaveOccurred())
    80  
    81  		// Creating k8s secret to access Pyxis stage based on base64 decoded of key and cert
    82  		pyxisKeyDecoded, err = base64.StdEncoding.DecodeString(string(keyPyxisStage))
    83  		Expect(err).ToNot(HaveOccurred())
    84  		pyxisCertDecoded, err = base64.StdEncoding.DecodeString(string(certPyxisStage))
    85  		Expect(err).ToNot(HaveOccurred())
    86  
    87  		secret := &corev1.Secret{
    88  			ObjectMeta: metav1.ObjectMeta{
    89  				Name:      "pyxis",
    90  				Namespace: managedNamespace,
    91  			},
    92  			Type: corev1.SecretTypeOpaque,
    93  			Data: map[string][]byte{
    94  				"cert": pyxisCertDecoded,
    95  				"key":  pyxisKeyDecoded,
    96  			},
    97  		}
    98  
    99  		_, err = fw.AsKubeAdmin.CommonController.CreateSecret(managedNamespace, secret)
   100  		Expect(err).ToNot(HaveOccurred())
   101  
   102  		Expect(kubeController.CreateOrUpdateSigningSecret(
   103  			publicKey, publicSecretNameAuth, managedNamespace)).To(Succeed())
   104  
   105  		defaultEcPolicy, err := kubeController.GetEnterpriseContractPolicy("default", "enterprise-contract-service")
   106  		Expect(err).NotTo(HaveOccurred())
   107  
   108  		defaultEcPolicySpec := ecp.EnterpriseContractPolicySpec{
   109  			Description: "Red Hat's enterprise requirements",
   110  			PublicKey:   string(publicKey),
   111  			Sources:     defaultEcPolicy.Spec.Sources,
   112  			Configuration: &ecp.EnterpriseContractPolicyConfiguration{
   113  				Collections: []string{"minimal", "slsa2"},
   114  				Exclude:     []string{"cve"},
   115  			},
   116  		}
   117  
   118  		_, err = fw.AsKubeAdmin.CommonController.CreateServiceAccount(releaseStrategyServiceAccountDefault, managedNamespace, managednamespaceSecret)
   119  		Expect(err).NotTo(HaveOccurred())
   120  
   121  		err = fw.AsKubeAdmin.CommonController.LinkSecretToServiceAccount(managedNamespace, redhatAppstudioUserSecret, releaseStrategyServiceAccountDefault, true)
   122  		Expect(err).ToNot(HaveOccurred())
   123  
   124  		// using cdq since git ref is not known
   125  		compName = componentName
   126  		cdq, err := fw.AsKubeAdmin.HasController.CreateComponentDetectionQuery(compName, devNamespace, gitSourceComponentUrl, "", "", "", false)
   127  		Expect(err).NotTo(HaveOccurred())
   128  		Expect(len(cdq.Status.ComponentDetected)).To(Equal(1), "Expected length of the detected Components was not 1")
   129  
   130  		for _, compDetected := range cdq.Status.ComponentDetected {
   131  			compName = compDetected.ComponentStub.ComponentName
   132  			componentDetected = compDetected
   133  		}
   134  
   135  		// using cdq since git ref is not known
   136  		additionalCompName = additionalComponentName
   137  		cdq, err = fw.AsKubeAdmin.HasController.CreateComponentDetectionQuery(additionalCompName, devNamespace, additionalGitSourceComponentUrl, "", "", "", false)
   138  		Expect(err).NotTo(HaveOccurred())
   139  		Expect(len(cdq.Status.ComponentDetected)).To(Equal(1), "Expected length of the detected Components was not 1")
   140  
   141  		for _, compDetected := range cdq.Status.ComponentDetected {
   142  			additionalCompName = compDetected.ComponentStub.ComponentName
   143  			additionalComponentDetected = compDetected
   144  		}
   145  
   146  		_, err = fw.AsKubeAdmin.ReleaseController.CreateReleasePlan(sourceReleasePlanName, devNamespace, applicationNameDefault, managedNamespace, "")
   147  		Expect(err).NotTo(HaveOccurred())
   148  
   149  		components := []release.Component{{Name: compName, Repository: releasedImagePushRepo}, {Name: additionalCompName, Repository: additionalReleasedImagePushRepo}}
   150  		sc := fw.AsKubeAdmin.ReleaseController.GenerateReleaseStrategyConfig(components)
   151  		scYaml, err := yaml.Marshal(sc)
   152  		Expect(err).ShouldNot(HaveOccurred())
   153  
   154  		scPath := "release-push-to-pyxis.yaml"
   155  		Expect(fw.AsKubeAdmin.CommonController.Github.CreateRef("strategy-configs", "main", scGitRevision)).To(Succeed())
   156  		_, err = fw.AsKubeAdmin.CommonController.Github.CreateFile("strategy-configs", scPath, string(scYaml), scGitRevision)
   157  		Expect(err).ShouldNot(HaveOccurred())
   158  
   159  		_, err = fw.AsKubeAdmin.ReleaseController.CreateReleaseStrategy("mvp-push-to-external-registry-strategy", managedNamespace, "push-to-external-registry", "quay.io/hacbs-release/pipeline-push-to-external-registry:0.11", releaseStrategyPolicyDefault, releaseStrategyServiceAccountDefault, []releaseApi.Params{
   160  			{Name: "extraConfigGitUrl", Value: fmt.Sprintf("https://github.com/%s/strategy-configs.git", utils.GetEnv(constants.GITHUB_E2E_ORGANIZATION_ENV, "redhat-appstudio-qe"))},
   161  			{Name: "extraConfigPath", Value: scPath},
   162  			{Name: "extraConfigGitRevision", Value: scGitRevision},
   163  			{Name: "pyxisServerType", Value: "stage"},
   164  			{Name: "pyxisSecret", Value: "pyxis"},
   165  			{Name: "tag", Value: "latest"},
   166  		})
   167  		Expect(err).NotTo(HaveOccurred())
   168  
   169  		_, err = fw.AsKubeAdmin.ReleaseController.CreateReleasePlanAdmission(targetReleasePlanAdmissionName, devNamespace, applicationNameDefault, managedNamespace, "", "", "mvp-push-to-external-registry-strategy")
   170  		Expect(err).NotTo(HaveOccurred())
   171  
   172  		_, err = fw.AsKubeAdmin.TektonController.CreateEnterpriseContractPolicy(releaseStrategyPolicyDefault, managedNamespace, defaultEcPolicySpec)
   173  		Expect(err).NotTo(HaveOccurred())
   174  
   175  		_, err = fw.AsKubeAdmin.TektonController.CreatePVCInAccessMode(releasePvcName, managedNamespace, corev1.ReadWriteOnce)
   176  		Expect(err).NotTo(HaveOccurred())
   177  
   178  		_, err = fw.AsKubeAdmin.CommonController.CreateRole("role-release-service-account", managedNamespace, map[string][]string{
   179  			"apiGroupsList": {""},
   180  			"roleResources": {"secrets"},
   181  			"roleVerbs":     {"get", "list", "watch"},
   182  		})
   183  		Expect(err).NotTo(HaveOccurred())
   184  
   185  		_, err = fw.AsKubeAdmin.CommonController.CreateRoleBinding("role-release-service-account-binding", managedNamespace, "ServiceAccount", releaseStrategyServiceAccountDefault, "Role", "role-release-service-account", "rbac.authorization.k8s.io")
   186  		Expect(err).NotTo(HaveOccurred())
   187  
   188  		_, err = fw.AsKubeAdmin.HasController.CreateHasApplication(applicationNameDefault, devNamespace)
   189  		Expect(err).NotTo(HaveOccurred())
   190  	})
   191  
   192  	AfterAll(func() {
   193  		err = fw.AsKubeAdmin.CommonController.Github.DeleteRef("strategy-configs", scGitRevision)
   194  		if err != nil {
   195  			Expect(err.Error()).To(ContainSubstring("Reference does not exist"))
   196  		}
   197  		if !CurrentSpecReport().Failed() {
   198  			Expect(fw.AsKubeAdmin.CommonController.DeleteNamespace(managedNamespace)).NotTo(HaveOccurred())
   199  			Expect(fw.SandboxController.DeleteUserSignup(fw.UserName)).NotTo(BeFalse())
   200  		}
   201  	})
   202  
   203  	var _ = Describe("Post-release verification", func() {
   204  
   205  		It("verifies that Component 1 can be created and build PipelineRun is created for it in dev namespace and succeeds", func() {
   206  			component1, err = fw.AsKubeAdmin.HasController.CreateComponentFromStub(componentDetected, devNamespace, "", "", applicationNameDefault)
   207  			Expect(err).NotTo(HaveOccurred())
   208  			Expect(fw.AsKubeAdmin.HasController.WaitForComponentPipelineToBeFinished(component1, "", 2)).To(Succeed())
   209  		})
   210  
   211  		It("verifies that Component 2 can be created and build PipelineRun is created for it in dev namespace and succeeds", func() {
   212  			component2, err = fw.AsKubeAdmin.HasController.CreateComponentFromStub(additionalComponentDetected, devNamespace, "", "", applicationNameDefault)
   213  			Expect(err).NotTo(HaveOccurred())
   214  			Expect(fw.AsKubeAdmin.HasController.WaitForComponentPipelineToBeFinished(component2, "", 2)).To(Succeed())
   215  		})
   216  
   217  		It("verifies that a release PipelineRun for each Component is created in managed namespace.", func() {
   218  			Eventually(func() bool {
   219  				prList, err := fw.AsKubeAdmin.TektonController.ListAllPipelineRuns(managedNamespace)
   220  				if err != nil || prList == nil || len(prList.Items) < 1 {
   221  					GinkgoWriter.Printf("Error getting Release PipelineRun:\n %s", err)
   222  					return false
   223  				}
   224  				foudFirstReleasePr := false
   225  				for _, pr := range prList.Items {
   226  					if strings.Contains(pr.Name, "release-pipelinerun") {
   227  						if !foudFirstReleasePr {
   228  							releasePrName = pr.Name
   229  							foudFirstReleasePr = true
   230  						} else {
   231  							additionalReleasePrName = pr.Name
   232  						}
   233  					}
   234  				}
   235  
   236  				return strings.Contains(releasePrName, "release-pipelinerun") &&
   237  					strings.Contains(additionalReleasePrName, "release-pipelinerun")
   238  			}, releasePipelineRunCreationTimeout, defaultInterval).Should(BeTrue())
   239  		})
   240  
   241  		It("verifies a release PipelineRun for each component started in managed namespace and succeeded.", func() {
   242  			Eventually(func() bool {
   243  
   244  				releasePr, err := fw.AsKubeAdmin.TektonController.GetPipelineRun(releasePrName, managedNamespace)
   245  				if err != nil {
   246  					GinkgoWriter.Printf("\nError getting Release PipelineRun %s:\n %s", releasePr, err)
   247  					return false
   248  				}
   249  				additionalReleasePr, err := fw.AsKubeAdmin.TektonController.GetPipelineRun(additionalReleasePrName, managedNamespace)
   250  				if err != nil {
   251  					GinkgoWriter.Printf("\nError getting PipelineRun %s:\n %s", additionalReleasePr, err)
   252  					return false
   253  				}
   254  
   255  				return releasePr.HasStarted() && releasePr.IsDone() && releasePr.Status.GetCondition(apis.ConditionSucceeded).IsTrue() &&
   256  					additionalReleasePr.HasStarted() && additionalReleasePr.IsDone() && additionalReleasePr.Status.GetCondition(apis.ConditionSucceeded).IsTrue()
   257  			}, releasePipelineRunCompletionTimeout, defaultInterval).Should(BeTrue())
   258  		})
   259  
   260  		It("validate the result of task create-pyxis-image contains image ids.", func() {
   261  			Eventually(func() bool {
   262  
   263  				releasePr, err := fw.AsKubeAdmin.TektonController.GetPipelineRun(releasePrName, managedNamespace)
   264  				if err != nil {
   265  					GinkgoWriter.Printf("\nError getting Release PipelineRun %s:\n %s", releasePr, err)
   266  					return false
   267  				}
   268  				additionalReleasePr, err := fw.AsKubeAdmin.TektonController.GetPipelineRun(additionalReleasePrName, managedNamespace)
   269  				if err != nil {
   270  					GinkgoWriter.Printf("\nError getting PipelineRun %s:\n %s", additionalReleasePr, err)
   271  					return false
   272  				}
   273  				re := regexp.MustCompile("[a-fA-F0-9]{24}")
   274  
   275  				trReleasePr, err := kubeController.GetTaskRunStatus(fw.AsKubeAdmin.CommonController.KubeRest(), releasePr, "create-pyxis-image")
   276  				if err != nil {
   277  					Expect(err).NotTo(HaveOccurred())
   278  				}
   279  
   280  				trAdditionalReleasePr, err := kubeController.GetTaskRunStatus(fw.AsKubeAdmin.CommonController.KubeRest(), additionalReleasePr, "create-pyxis-image")
   281  				if err != nil {
   282  					Expect(err).NotTo(HaveOccurred())
   283  				}
   284  
   285  				trReleaseImageIDs := re.FindAllString(trReleasePr.Status.TaskRunResults[0].Value.StringVal, -1)
   286  				trAdditionalReleaseIDs := re.FindAllString(trAdditionalReleasePr.Status.TaskRunResults[0].Value.StringVal, -1)
   287  
   288  				if len(trReleaseImageIDs) < 1 && len(trAdditionalReleaseIDs) < 1 {
   289  					GinkgoWriter.Printf("\n Invalid ImageID in results of task create-pyxis-image..")
   290  					return false
   291  				}
   292  
   293  				if len(trReleaseImageIDs) > len(trAdditionalReleaseIDs) {
   294  					imageIDs = trReleaseImageIDs
   295  				} else {
   296  					imageIDs = trAdditionalReleaseIDs
   297  				}
   298  
   299  				return len(imageIDs) == 2
   300  			}, avgControllerQueryTimeout, defaultInterval).Should(BeTrue())
   301  		})
   302  
   303  		It("tests a Release should have been created in the dev namespace and succeeded.", func() {
   304  			Eventually(func() bool {
   305  				releaseCreated, err := fw.AsKubeAdmin.ReleaseController.GetFirstReleaseInNamespace(devNamespace)
   306  				if releaseCreated == nil || err != nil {
   307  					return false
   308  				}
   309  
   310  				return releaseCreated.IsReleased()
   311  			}, releaseCreationTimeout, defaultInterval).Should(BeTrue())
   312  		})
   313  
   314  		It("validates that imageIds from task create-pyxis-image exist in Pyxis.", func() {
   315  
   316  			for _, imageID := range imageIDs {
   317  				Eventually(func() bool {
   318  
   319  					body, err := fw.AsKubeAdmin.ReleaseController.GetSbomPyxisByImageID(pyxisStageURL, imageID,
   320  						[]byte(pyxisCertDecoded), []byte(pyxisKeyDecoded))
   321  					if err != nil {
   322  						GinkgoWriter.Printf("Error getting response body:", err)
   323  						Expect(err).NotTo(HaveOccurred())
   324  					}
   325  
   326  					sbomImage := &release.Image{}
   327  					err = json.Unmarshal(body, sbomImage)
   328  					if err != nil {
   329  						GinkgoWriter.Printf("Error json unmarshal body content.", err)
   330  						Expect(err).NotTo(HaveOccurred())
   331  					}
   332  
   333  					if sbomImage.ContentManifestComponents == nil {
   334  						GinkgoWriter.Printf("Content Mainfest Components is empty.")
   335  						return false
   336  					}
   337  
   338  					return len(sbomImage.ContentManifestComponents) > 1
   339  				}, releaseCreationTimeout, defaultInterval).Should(BeTrue())
   340  			}
   341  
   342  		})
   343  	})
   344  })