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 })