github.com/redhat-appstudio/e2e-tests@v0.0.0-20240520140907-9709f6f59323/tests/release/pipelines/rh_advisories.go (about) 1 package pipelines 2 3 import ( 4 "encoding/base64" 5 "encoding/json" 6 "fmt" 7 "os" 8 "regexp" 9 "time" 10 11 "github.com/devfile/library/v2/pkg/util" 12 ecp "github.com/enterprise-contract/enterprise-contract-controller/api/v1alpha1" 13 . "github.com/onsi/ginkgo/v2" 14 . "github.com/onsi/gomega" 15 appservice "github.com/redhat-appstudio/application-api/api/v1alpha1" 16 "github.com/redhat-appstudio/e2e-tests/pkg/clients/has" 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/tekton" 21 releasecommon "github.com/redhat-appstudio/e2e-tests/tests/release" 22 releaseapi "github.com/redhat-appstudio/release-service/api/v1alpha1" 23 tektonutils "github.com/redhat-appstudio/release-service/tekton/utils" 24 tektonv1 "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1" 25 corev1 "k8s.io/api/core/v1" 26 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 27 "k8s.io/apimachinery/pkg/runtime" 28 ) 29 30 const ( 31 advsServiceAccountName = "release-service-account" 32 advsCatalogPathInRepo = "pipelines/rh-advisories/rh-advisories.yaml" 33 ) 34 35 var component *appservice.Component 36 37 var _ = framework.ReleasePipelinesSuiteDescribe("e2e tests for rh-advisories pipeline", Label("release-pipelines", "rh-advisories"), func() { 38 defer GinkgoRecover() 39 var pyxisKeyDecoded, pyxisCertDecoded []byte 40 41 var devWorkspace = utils.GetEnv(constants.RELEASE_DEV_WORKSPACE_ENV, constants.DevReleaseTeam) 42 var managedWorkspace = utils.GetEnv(constants.RELEASE_MANAGED_WORKSPACE_ENV, constants.ManagedReleaseTeam) 43 44 var devNamespace = devWorkspace + "-tenant" 45 var managedNamespace = managedWorkspace + "-tenant" 46 47 var err error 48 var devFw *framework.Framework 49 var managedFw *framework.Framework 50 var advsApplicationName = "advs-app-" + util.GenerateRandomString(4) 51 var advsComponentName = "advs-comp-" + util.GenerateRandomString(4) 52 var advsReleasePlanName = "advs-rp-" + util.GenerateRandomString(4) 53 var advsReleasePlanAdmissionName = "advs-rpa-" + util.GenerateRandomString(4) 54 var advsEnterpriseContractPolicyName = "advs-policy-" + util.GenerateRandomString(4) 55 56 var snapshot *appservice.Snapshot 57 var releaseCR *releaseapi.Release 58 var releasePR, buildPR *tektonv1.PipelineRun 59 60 AfterEach(framework.ReportFailure(&devFw)) 61 62 Describe("Rh-advisories happy path", Label("rhAdvisories"), func() { 63 BeforeAll(func() { 64 devFw = releasecommon.NewFramework(devWorkspace) 65 managedFw = releasecommon.NewFramework(managedWorkspace) 66 managedNamespace = managedFw.UserNamespace 67 68 keyPyxisStage := os.Getenv(constants.PYXIS_STAGE_KEY_ENV) 69 Expect(keyPyxisStage).ToNot(BeEmpty()) 70 71 certPyxisStage := os.Getenv(constants.PYXIS_STAGE_CERT_ENV) 72 Expect(certPyxisStage).ToNot(BeEmpty()) 73 74 // Creating k8s secret to access Pyxis stage based on base64 decoded of key and cert 75 pyxisKeyDecoded, err = base64.StdEncoding.DecodeString(string(keyPyxisStage)) 76 Expect(err).ToNot(HaveOccurred()) 77 78 pyxisCertDecoded, err = base64.StdEncoding.DecodeString(string(certPyxisStage)) 79 Expect(err).ToNot(HaveOccurred()) 80 81 secret := &corev1.Secret{ 82 ObjectMeta: metav1.ObjectMeta{ 83 Name: "pyxis", 84 Namespace: managedNamespace, 85 }, 86 Type: corev1.SecretTypeOpaque, 87 Data: map[string][]byte{ 88 "cert": pyxisCertDecoded, 89 "key": pyxisKeyDecoded, 90 }, 91 } 92 93 // Delete the secret if it exists in case it is not correct 94 _ = managedFw.AsKubeAdmin.CommonController.DeleteSecret(managedNamespace, "pyxis") 95 _, err = managedFw.AsKubeAdmin.CommonController.CreateSecret(managedNamespace, secret) 96 Expect(err).ToNot(HaveOccurred()) 97 98 err = managedFw.AsKubeAdmin.CommonController.LinkSecretToServiceAccount(managedNamespace, releasecommon.RedhatAppstudioUserSecret, constants.DefaultPipelineServiceAccount, true) 99 Expect(err).ToNot(HaveOccurred()) 100 101 _, err = devFw.AsKubeDeveloper.HasController.CreateApplication(advsApplicationName, devNamespace) 102 Expect(err).NotTo(HaveOccurred()) 103 104 createADVSReleasePlan(advsReleasePlanName, *devFw, devNamespace, advsApplicationName, managedNamespace, "true") 105 component = releasecommon.CreateComponentByCDQ(*devFw, devNamespace, managedNamespace, advsApplicationName, advsComponentName, releasecommon.AdditionalGitSourceComponentUrl) 106 createADVSReleasePlanAdmission(advsReleasePlanAdmissionName, *managedFw, devNamespace, managedNamespace, advsApplicationName, advsEnterpriseContractPolicyName, advsCatalogPathInRepo) 107 108 createADVSEnterpriseContractPolicy(advsEnterpriseContractPolicyName, *managedFw, devNamespace, managedNamespace) 109 }) 110 111 AfterAll(func() { 112 devFw = releasecommon.NewFramework(devWorkspace) 113 managedFw = releasecommon.NewFramework(managedWorkspace) 114 Expect(devFw.AsKubeDeveloper.HasController.DeleteApplication(advsApplicationName, devNamespace, false)).NotTo(HaveOccurred()) 115 Expect(managedFw.AsKubeDeveloper.TektonController.DeleteEnterpriseContractPolicy(advsEnterpriseContractPolicyName, managedNamespace, false)).NotTo(HaveOccurred()) 116 Expect(managedFw.AsKubeDeveloper.ReleaseController.DeleteReleasePlanAdmission(advsReleasePlanAdmissionName, managedNamespace, false)).NotTo(HaveOccurred()) 117 }) 118 119 var _ = Describe("Post-release verification", func() { 120 It("verifies that a build PipelineRun is created in dev namespace and succeeds", func() { 121 devFw = releasecommon.NewFramework(devWorkspace) 122 // Create a ticker that ticks every 3 minutes 123 ticker := time.NewTicker(3 * time.Minute) 124 // Schedule the stop of the ticker after 10 minutes 125 time.AfterFunc(10*time.Minute, func() { 126 ticker.Stop() 127 fmt.Println("Stopped executing every 3 minutes.") 128 }) 129 // Run a goroutine to handle the ticker ticks 130 go func() { 131 for range ticker.C { 132 devFw = releasecommon.NewFramework(devWorkspace) 133 } 134 }() 135 Eventually(func() error { 136 buildPR, err = devFw.AsKubeDeveloper.HasController.GetComponentPipelineRun(component.Name, advsApplicationName, devNamespace, "") 137 if err != nil { 138 return err 139 } 140 if !buildPR.IsDone() { 141 return fmt.Errorf("build pipelinerun %s in namespace %s did not finish yet", buildPR.Name, buildPR.Namespace) 142 } 143 Expect(tekton.HasPipelineRunSucceeded(buildPR)).To(BeTrue(), fmt.Sprintf("build pipelinerun %s/%s did not succeed", buildPR.GetNamespace(), buildPR.GetName())) 144 snapshot, err = devFw.AsKubeDeveloper.IntegrationController.GetSnapshot("", buildPR.Name, "", devNamespace) 145 if err != nil { 146 return err 147 } 148 return nil 149 }, releasecommon.BuildPipelineRunCompletionTimeout, releasecommon.DefaultInterval).Should(Succeed(), "timed out when waiting for build pipelinerun to be created") 150 Expect(devFw.AsKubeDeveloper.HasController.WaitForComponentPipelineToBeFinished(component, "", devFw.AsKubeDeveloper.TektonController, &has.RetryOptions{Retries: 3, Always: true}, nil)).To(Succeed()) 151 }) 152 It("verifies the advs release pipelinerun is running and succeeds", func() { 153 devFw = releasecommon.NewFramework(devWorkspace) 154 managedFw = releasecommon.NewFramework(managedWorkspace) 155 156 releaseCR, err = devFw.AsKubeDeveloper.ReleaseController.GetRelease("", snapshot.Name, devNamespace) 157 Expect(err).ShouldNot(HaveOccurred()) 158 Eventually(func() error { 159 releasePR, err = managedFw.AsKubeAdmin.ReleaseController.GetPipelineRunInNamespace(managedFw.UserNamespace, releaseCR.GetName(), releaseCR.GetNamespace()) 160 if err != nil { 161 return err 162 } 163 GinkgoWriter.Println("Release PR: ", releasePR.Name) 164 if !releasePR.IsDone() { 165 return fmt.Errorf("release pipelinerun %s in namespace %s did not finished yet", releasePR.Name, releasePR.Namespace) 166 } 167 return nil 168 }, releasecommon.ReleasePipelineRunCompletionTimeout, releasecommon.DefaultInterval).Should(Succeed(), "timed out when waiting for release pipelinerun to succeed") 169 Expect(tekton.HasPipelineRunSucceeded(releasePR)).To(BeTrue(), fmt.Sprintf("release pipelinerun %s/%s did not succeed", releasePR.GetNamespace(), releasePR.GetName())) 170 }) 171 172 It("verifies release CR completed and set succeeded.", func() { 173 devFw = releasecommon.NewFramework(devWorkspace) 174 Eventually(func() error { 175 releaseCr, err := devFw.AsKubeDeveloper.ReleaseController.GetRelease("", snapshot.Name, devNamespace) 176 if err != nil { 177 return err 178 } 179 GinkgoWriter.Println("Release CR: ", releaseCr.Name) 180 if !releaseCr.IsReleased() { 181 return fmt.Errorf("release %s/%s is not marked as finished yet", releaseCR.GetNamespace(), releaseCR.GetName()) 182 } 183 return nil 184 }, 10*time.Minute, releasecommon.DefaultInterval).Should(Succeed()) 185 }) 186 187 It("verifies if the repository URL is valid", func() { 188 managedFw = releasecommon.NewFramework(managedWorkspace) 189 releasePR, err = managedFw.AsKubeAdmin.ReleaseController.GetPipelineRunInNamespace(managedFw.UserNamespace, releaseCR.GetName(), releaseCR.GetNamespace()) 190 Expect(err).NotTo(HaveOccurred()) 191 advisoryURL := releasePR.Status.PipelineRunStatusFields.Results[0].Value.StringVal 192 pattern := `https?://[^/\s]+/[^/\s]+/[^/\s]+/+\-\/blob\/main\/data\/advisories\/[^\/]+\/[^\/]+\/[^\/]+\/advisory\.yaml` 193 re, err := regexp.Compile(pattern) 194 Expect(err).NotTo(HaveOccurred()) 195 Expect(re.MatchString(advisoryURL)).To(BeTrue(), fmt.Sprintf("Advisory_url %s is not valid", advisoryURL)) 196 }) 197 }) 198 }) 199 }) 200 201 func createADVSEnterpriseContractPolicy(advsECPName string, managedFw framework.Framework, devNamespace, managedNamespace string) { 202 defaultEcPolicySpec := ecp.EnterpriseContractPolicySpec{ 203 Description: "Red Hat's enterprise requirements", 204 PublicKey: "k8s://openshift-pipelines/public-key", 205 Sources: []ecp.Source{{ 206 Name: "Default", 207 Policy: []string{releasecommon.EcPolicyLibPath, releasecommon.EcPolicyReleasePath}, 208 Data: []string{releasecommon.EcPolicyDataBundle, releasecommon.EcPolicyDataPath}, 209 }}, 210 Configuration: &ecp.EnterpriseContractPolicyConfiguration{ 211 Exclude: []string{"cve", "step_image_registries", "tasks.required_tasks_found:prefetch-dependencies"}, 212 Include: []string{"minimal"}, 213 }, 214 } 215 216 _, err := managedFw.AsKubeDeveloper.TektonController.CreateEnterpriseContractPolicy(advsECPName, managedNamespace, defaultEcPolicySpec) 217 Expect(err).NotTo(HaveOccurred()) 218 219 } 220 221 func createADVSReleasePlan(advsReleasePlanName string, devFw framework.Framework, devNamespace, advsAppName, managedNamespace string, autoRelease string) { 222 var err error 223 224 data, err := json.Marshal(map[string]interface{}{ 225 "releaseNotes": map[string]interface{}{ 226 "description": "releaseNotes description", 227 "references": []string{"https://server.com/ref1", "http://server2.com/ref2"}, 228 "solution": "some solution", 229 "synopsis": "test synopsis", 230 "topic": "test topic", 231 }, 232 }) 233 Expect(err).NotTo(HaveOccurred()) 234 235 _, err = devFw.AsKubeDeveloper.ReleaseController.CreateReleasePlan(advsReleasePlanName, devNamespace, advsAppName, 236 managedNamespace, autoRelease, &runtime.RawExtension{ 237 Raw: data, 238 }) 239 Expect(err).NotTo(HaveOccurred()) 240 } 241 242 func createADVSReleasePlanAdmission(advsRPAName string, managedFw framework.Framework, devNamespace, managedNamespace, advsAppName, advsECPName, pathInRepoValue string) { 243 var err error 244 245 data, err := json.Marshal(map[string]interface{}{ 246 "mapping": map[string]interface{}{ 247 "components": []map[string]interface{}{ 248 { 249 "name": component.GetName(), 250 "repository": "quay.io/redhat-pending/rhtap----konflux-release-e2e", 251 }, 252 }, 253 }, 254 "pyxis": map[string]interface{}{ 255 "server": "stage", 256 "secret": "pyxis", 257 }, 258 "releaseNotes": map[string]interface{}{ 259 "cpe": "cpe:/a:example.com", 260 "product_id": "555", 261 "product_name": "test product", 262 "product_stream": "rhtas-tp1", 263 "product_version": "v1.0", 264 "type": "RHSA", 265 }, 266 "images": map[string]interface{}{ 267 "defaultTag": "latest", 268 "addGitShaTag": false, 269 "addTimestampTag": false, 270 "addSourceShaTag": false, 271 "floatingTags": []string{"testtag", "testtag2"}, 272 }, 273 "sign": map[string]interface{}{ 274 "configMapName": "hacbs-signing-pipeline-config-redhatbeta2", 275 }, 276 }) 277 Expect(err).NotTo(HaveOccurred()) 278 279 _, err = managedFw.AsKubeAdmin.ReleaseController.CreateReleasePlanAdmission(advsRPAName, managedNamespace, "", devNamespace, advsECPName, advsServiceAccountName, []string{advsAppName}, true, &tektonutils.PipelineRef{ 280 Resolver: "git", 281 Params: []tektonutils.Param{ 282 {Name: "url", Value: releasecommon.RelSvcCatalogURL}, 283 {Name: "revision", Value: releasecommon.RelSvcCatalogRevision}, 284 {Name: "pathInRepo", Value: pathInRepoValue}, 285 }, 286 }, &runtime.RawExtension{ 287 Raw: data, 288 }) 289 Expect(err).NotTo(HaveOccurred()) 290 }