github.com/redhat-appstudio/e2e-tests@v0.0.0-20240520140907-9709f6f59323/tests/spi/oauth.go (about) 1 package spi 2 3 import ( 4 "context" 5 "fmt" 6 "net/url" 7 "os" 8 "time" 9 10 . "github.com/onsi/ginkgo/v2" 11 . "github.com/onsi/gomega" 12 "github.com/redhat-appstudio/e2e-tests/pkg/framework" 13 "github.com/redhat-appstudio/e2e-tests/pkg/utils" 14 "github.com/redhat-appstudio/service-provider-integration-operator/api/v1beta1" 15 corev1 "k8s.io/api/core/v1" 16 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 17 "k8s.io/klog/v2" 18 ) 19 20 /* 21 * Component: spi 22 * Description: SVPI-395 - Github OAuth flow to upload token 23 */ 24 25 var _ = framework.SPISuiteDescribe(Label("spi-suite", "gh-oauth-flow"), func() { 26 27 defer GinkgoRecover() 28 29 var fw *framework.Framework 30 var err error 31 var namespace string 32 var CYPRESS_GH_USER string 33 var CYPRESS_GH_PASSWORD string 34 var CYPRESS_GH_2FA_CODE string 35 var CYPRESS_SPI_LOGIN_URL string 36 var CYPRESS_K8S_TOKEN string 37 var cypressPodName string = "cypress-script" 38 AfterEach(framework.ReportFailure(&fw)) 39 40 // TODO: skip until https://issues.redhat.com/browse/KFLUXBUGS-1108 is fixed 41 Describe("SVPI-395 - Github OAuth flow to upload token", Pending, Ordered, func() { 42 BeforeAll(func() { 43 44 if os.Getenv("CI") != "true" { 45 Skip(fmt.Sprintln("test skipped on local execution")) 46 } 47 // Initialize the tests controllers 48 fw, err = framework.NewFramework(utils.GetGeneratedNamespace("spi-demos-oauth")) 49 Expect(err).NotTo(HaveOccurred()) 50 namespace = fw.UserNamespace 51 Expect(namespace).NotTo(BeEmpty()) 52 53 CYPRESS_GH_USER = utils.GetEnv("CYPRESS_GH_USER", "") 54 Expect(CYPRESS_GH_USER).NotTo(BeEmpty(), "Please provide CYPRESS_GH_USER") 55 56 CYPRESS_GH_PASSWORD = utils.GetEnv("CYPRESS_GH_PASSWORD", "") 57 Expect(CYPRESS_GH_PASSWORD).NotTo(BeEmpty(), "Please provide CYPRESS_GH_PASSWORD") 58 59 CYPRESS_GH_2FA_CODE = utils.GetEnv("CYPRESS_GH_2FA_CODE", "") 60 Expect(CYPRESS_GH_2FA_CODE).NotTo(BeEmpty(), "Please provide CYPRESS_GH_2FA_CODE env") 61 62 }) 63 64 // Clean up after running these tests and before the next tests block: can't have multiple AccessTokens in Injected phase 65 AfterAll(func() { 66 67 artifactDir := utils.GetEnv("ARTIFACT_DIR", "") 68 if artifactDir != "" { 69 // collect cypress recording from the pod and save it in the artifacts folder 70 err := utils.ExecuteCommandInASpecificDirectory("kubectl", []string{"cp", cypressPodName + ":/cypress-browser-oauth-flow/cypress/videos", artifactDir + "/cypress/spi-oauth/", "-n", namespace}, "") 71 if err != nil { 72 klog.Infof("cannot save screen recording in the artifacts folder: %s", err) 73 } 74 } 75 76 if !CurrentSpecReport().Failed() { 77 Expect(fw.AsKubeAdmin.SPIController.DeleteAllBindingTokensInASpecificNamespace(namespace)).To(Succeed()) 78 Expect(fw.AsKubeAdmin.SPIController.DeleteAllAccessTokensInASpecificNamespace(namespace)).To(Succeed()) 79 } 80 }) 81 82 var SPITokenBinding *v1beta1.SPIAccessTokenBinding 83 var CYPRESS_SPI_OAUTH_URL string 84 tokenBindingName := "spi-token-binding-oauth-" 85 OAUTH_REDIRECT_PROXY_URL := utils.GetEnv("OAUTH_REDIRECT_PROXY_URL", "") 86 87 if utils.GetEnv("CI", "") == "true" { 88 /* 89 If we are running this test in CI, we need to handle the dynamic url the cluster is assigned with. 90 To do that, we use a redirect proxy that allows us to have a static oauth url in the providers configuration and, at the same time, 91 will redirect the callback call to the spi component in our cluster. OAUTH_REDIRECT_PROXY_URL env should contains the url of such proxy. 92 If not running in CI, SPI expects that the callback url in the provider configuration is set to the default one: homepage URL + /oauth/callback 93 */ 94 It("ensure OauthRedirectProxyUrl is set", func() { 95 96 Expect(OAUTH_REDIRECT_PROXY_URL).NotTo(BeEmpty(), "OAUTH_REDIRECT_PROXY_URL env is not set") 97 98 spiNamespace := "spi-system" 99 config, err := fw.AsKubeAdmin.CommonController.GetConfigMap("spi-oauth-service-environment-config", spiNamespace) 100 Expect(err).NotTo(HaveOccurred()) 101 Expect(config.Data["OAUTH_REDIRECT_PROXY_URL"]).NotTo(BeEmpty()) 102 103 }) 104 } 105 106 It("creates SPITokenBinding", func() { 107 SPITokenBinding, err = fw.AsKubeDeveloper.SPIController.CreateSPIAccessTokenBinding(tokenBindingName, namespace, RepoURL, "", "kubernetes.io/basic-auth") 108 Expect(err).NotTo(HaveOccurred()) 109 110 Eventually(func() bool { 111 SPITokenBinding, err = fw.AsKubeDeveloper.SPIController.GetSPIAccessTokenBinding(SPITokenBinding.Name, namespace) 112 Expect(err).NotTo(HaveOccurred()) 113 114 return (SPITokenBinding.Status.OAuthUrl != "") 115 }, 1*time.Minute, 10*time.Second).Should(BeTrue(), "OAuthUrl should not be empty") 116 117 CYPRESS_SPI_OAUTH_URL = SPITokenBinding.Status.OAuthUrl 118 Expect(CYPRESS_SPI_OAUTH_URL).NotTo(BeEmpty()) 119 120 k8s_token, err := utils.GetOpenshiftToken() 121 Expect(err).NotTo(HaveOccurred()) 122 Expect(k8s_token).NotTo(BeEmpty()) 123 124 // Build the urls to login to spi 125 // An HTML form is server by the redirect-proxy to submit the k8s_token via spi POST /login endpoint 126 spi_oauth_url, err := url.Parse(CYPRESS_SPI_OAUTH_URL) 127 Expect(err).NotTo(HaveOccurred()) 128 oauth_redirect_proxy_url, err := url.Parse(OAUTH_REDIRECT_PROXY_URL) 129 Expect(err).NotTo(HaveOccurred()) 130 131 login_redirect_proxy_url := oauth_redirect_proxy_url.Scheme + "://" + oauth_redirect_proxy_url.Host + "/login" 132 spi_login_url := spi_oauth_url.Scheme + "://" + spi_oauth_url.Host + "/login" 133 134 CYPRESS_SPI_LOGIN_URL = login_redirect_proxy_url + "?url=" + spi_login_url 135 CYPRESS_K8S_TOKEN = k8s_token 136 }) 137 138 It("run browser oauth login flow in cypress pod", func() { 139 140 // Now we create a short-living pod that will use cypress to perform the browser login flow 141 cypressPod := &corev1.Pod{ 142 TypeMeta: metav1.TypeMeta{ 143 Kind: "Pod", 144 APIVersion: "v1", 145 }, 146 ObjectMeta: metav1.ObjectMeta{ 147 Name: cypressPodName, 148 Namespace: namespace, 149 }, 150 Spec: corev1.PodSpec{ 151 Containers: []corev1.Container{ 152 { 153 Name: cypressPodName, 154 Image: "quay.io/redhat-appstudio-qe/cypress/included:latest", 155 Command: []string{"/bin/sh", "-c"}, 156 Args: []string{"git clone https://github.com/redhat-appstudio-qe/cypress-browser-oauth-flow; cd cypress-browser-oauth-flow; npm install; cypress run --spec cypress/e2e/spec.cy.js; tail -f /dev/null;"}, 157 Env: []corev1.EnvVar{ 158 { 159 Name: "CYPRESS_GH_USER", 160 Value: CYPRESS_GH_USER, 161 }, 162 { 163 Name: "CYPRESS_GH_PASSWORD", 164 Value: CYPRESS_GH_PASSWORD, 165 }, 166 { 167 Name: "CYPRESS_GH_2FA_CODE", 168 Value: CYPRESS_GH_2FA_CODE, 169 }, 170 { 171 Name: "CYPRESS_SPI_OAUTH_URL", 172 Value: CYPRESS_SPI_OAUTH_URL, 173 }, 174 { 175 Name: "CYPRESS_SPI_LOGIN_URL", 176 Value: CYPRESS_SPI_LOGIN_URL, 177 }, 178 { 179 Name: "CYPRESS_K8S_TOKEN", 180 Value: CYPRESS_K8S_TOKEN, 181 }, 182 }, 183 ImagePullPolicy: corev1.PullIfNotPresent, 184 }, 185 }, 186 RestartPolicy: corev1.RestartPolicyNever, 187 }, 188 } 189 190 _, err := fw.AsKubeAdmin.CommonController.KubeInterface().CoreV1().Pods(namespace).Create(context.Background(), cypressPod, metav1.CreateOptions{}) 191 Expect(err).NotTo(HaveOccurred()) 192 193 // check pod is running 194 // if spi oauth flow is completed, the SPITokenBinding will be injected 195 // keeping the pod running and only checking the SPITokenBinding (instead of the pod status itself) allows us 196 // to get the logs and browser session recording from the cypress pod. 197 Eventually(func() bool { 198 pod, err := fw.AsKubeAdmin.CommonController.GetPod(namespace, cypressPod.Name) 199 Expect(err).NotTo(HaveOccurred()) 200 201 return (pod.Status.Phase == corev1.PodRunning) 202 }, 15*time.Minute, 5*time.Second).Should(BeTrue(), "Cypress pod did not start") 203 204 }) 205 206 It("SPITokenBinding should be in Injected phase", func() { 207 Eventually(func() bool { 208 SPITokenBinding, err = fw.AsKubeDeveloper.SPIController.GetSPIAccessTokenBinding(SPITokenBinding.Name, namespace) 209 Expect(err).NotTo(HaveOccurred()) 210 211 return SPITokenBinding.Status.Phase == v1beta1.SPIAccessTokenBindingPhaseInjected 212 }, 15*time.Minute, 10*time.Second).Should(BeTrue(), "SPIAccessTokenBinding is not in Injected phase after Oauth flow") 213 }) 214 215 }) 216 })