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  }