github.com/redhat-appstudio/e2e-tests@v0.0.0-20230619105049-9a422b2094d7/tests/spi/access-control.go (about)

     1  package spi
     2  
     3  import (
     4  	"bytes"
     5  	"context"
     6  	"fmt"
     7  	"strings"
     8  	"time"
     9  
    10  	"github.com/redhat-appstudio/e2e-tests/pkg/constants"
    11  	"github.com/redhat-appstudio/e2e-tests/pkg/utils"
    12  	"github.com/redhat-appstudio/service-provider-integration-operator/api/v1beta1"
    13  
    14  	. "github.com/onsi/ginkgo/v2"
    15  	. "github.com/onsi/gomega"
    16  	client "github.com/redhat-appstudio/e2e-tests/pkg/apis/kubernetes"
    17  	"github.com/redhat-appstudio/e2e-tests/pkg/framework"
    18  	corev1 "k8s.io/api/core/v1"
    19  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    20  	"k8s.io/apimachinery/pkg/types"
    21  	"k8s.io/client-go/tools/clientcmd"
    22  	"k8s.io/client-go/tools/remotecommand"
    23  	"k8s.io/kubectl/pkg/scheme"
    24  	crclient "sigs.k8s.io/controller-runtime/pkg/client"
    25  )
    26  
    27  type User struct {
    28  	Framework                    *framework.Framework
    29  	LinkedAccessTokenName        string
    30  	SPIGithubWorkSpaceSecretName string
    31  	WorkspaceURL                 string
    32  	APIProxyClientA              *crclient.Client
    33  	APIProxyClientB              *crclient.Client
    34  	APIProxyClientC              *crclient.Client
    35  }
    36  
    37  /*
    38   * Component: spi
    39   * Description: SVPI-495 - Test automation to ensure that a user can't access and use secrets from another workspace
    40  
    41   * User A is the owner of workspace A and has access to workspace C as the maintainer
    42   * User B is the owner of workspace B
    43   * User C is the owner of workspace C
    44  
    45   * Test cases:
    46  	* check if user can access the SPIAccessToken from another workspace
    47  	* check if user can read the GitHub repo from another workspace
    48  	* check if user can read the secret from another workspace
    49  	* check if user's pod deployed in the user's workspace can read the GitHub repo from another workspace
    50  */
    51  
    52  var _ = framework.SPISuiteDescribe(Label("spi-suite", "access-control"), func() {
    53  
    54  	defer GinkgoRecover()
    55  
    56  	var userA, userB, userC User
    57  
    58  	Describe("SVPI-495 - Test automation to ensure that a user can't access and use secrets from another workspace", Ordered, func() {
    59  
    60  		delete := func(user User) {
    61  			Expect(user.Framework.AsKubeAdmin.SPIController.DeleteAllBindingTokensInASpecificNamespace(user.Framework.UserNamespace)).To(Succeed())
    62  			Expect(user.Framework.AsKubeAdmin.SPIController.DeleteAllAccessTokensInASpecificNamespace(user.Framework.UserNamespace)).To(Succeed())
    63  			Expect(user.Framework.AsKubeAdmin.SPIController.DeleteAllAccessTokenDataInASpecificNamespace(user.Framework.UserNamespace)).To(Succeed())
    64  			Expect(user.Framework.SandboxController.DeleteUserSignup(user.Framework.UserName)).NotTo(BeFalse())
    65  		}
    66  
    67  		createAPIProxyClient := func(userToken, proxyURL string) *crclient.Client {
    68  			APIProxyClient, err := client.CreateAPIProxyClient(userToken, proxyURL)
    69  			Expect(err).NotTo(HaveOccurred())
    70  			client := APIProxyClient.KubeRest()
    71  			return &client
    72  		}
    73  
    74  		createSPITokenBinding := func(user User) {
    75  			namespace := user.Framework.UserNamespace
    76  			secretName := user.SPIGithubWorkSpaceSecretName
    77  
    78  			// creates SPITokenBinding
    79  			SPITokenBinding, err := user.Framework.AsKubeDeveloper.SPIController.CreateSPIAccessTokenBinding(SPITokenBindingName, namespace, GithubPrivateRepoURL, secretName, "kubernetes.io/basic-auth")
    80  			Expect(err).NotTo(HaveOccurred())
    81  
    82  			// start of upload token
    83  			// SPITokenBinding to be in AwaitingTokenData phase
    84  			// wait SPITokenBinding to be in AwaitingTokenData phase before trying to upload a token
    85  			Eventually(func() bool {
    86  				SPITokenBinding, err = user.Framework.AsKubeDeveloper.SPIController.GetSPIAccessTokenBinding(SPITokenBinding.Name, namespace)
    87  				if err != nil {
    88  					return false
    89  				}
    90  
    91  				return (SPITokenBinding.Status.Phase == v1beta1.SPIAccessTokenBindingPhaseAwaitingTokenData)
    92  			}, 1*time.Minute, 5*time.Second).Should(BeTrue(), "SPIAccessTokenBinding is not in AwaitingTokenData phase")
    93  
    94  			// uploads username and token using rest endpoint
    95  			// the UploadUrl in SPITokenBinding should be available before uploading the token
    96  			Eventually(func() bool {
    97  				SPITokenBinding, err = user.Framework.AsKubeDeveloper.SPIController.GetSPIAccessTokenBinding(SPITokenBinding.Name, namespace)
    98  				if err != nil {
    99  					return false
   100  				}
   101  
   102  				return SPITokenBinding.Status.UploadUrl != ""
   103  			}, 1*time.Minute, 10*time.Second).Should(BeTrue(), "uploadUrl not set")
   104  			Expect(err).NotTo(HaveOccurred())
   105  
   106  			// LinkedAccessToken should exist
   107  			linkedAccessTokenName := SPITokenBinding.Status.LinkedAccessTokenName
   108  			Expect(linkedAccessTokenName).NotTo(BeEmpty())
   109  
   110  			// keep LinkedAccessToken name
   111  			username := user.Framework.UserName
   112  			if strings.HasPrefix(username, "spi-user-a") {
   113  				userA.LinkedAccessTokenName = linkedAccessTokenName
   114  			} else if strings.HasPrefix(username, "spi-user-b") {
   115  				userB.LinkedAccessTokenName = linkedAccessTokenName
   116  			} else {
   117  				userC.LinkedAccessTokenName = linkedAccessTokenName
   118  			}
   119  
   120  			// get the url to manually upload the token
   121  			uploadURL := SPITokenBinding.Status.UploadUrl
   122  			Expect(uploadURL).NotTo(BeEmpty())
   123  
   124  			// Get the token for the current openshift user
   125  			bearerToken, err := utils.GetOpenshiftToken()
   126  			Expect(err).NotTo(HaveOccurred())
   127  
   128  			// build and upload the payload using the uploadURL. it should return 204
   129  			oauthCredentials := `{"access_token":"` + utils.GetEnv(constants.GITHUB_TOKEN_ENV, "") + `"}`
   130  			statusCode, err := user.Framework.AsKubeDeveloper.SPIController.UploadWithRestEndpoint(uploadURL, oauthCredentials, bearerToken)
   131  			Expect(err).NotTo(HaveOccurred())
   132  			Expect(statusCode).Should(Equal(204))
   133  
   134  			// SPITokenBinding to be in Injected phase
   135  			Eventually(func() bool {
   136  				SPITokenBinding, err = user.Framework.AsKubeDeveloper.SPIController.GetSPIAccessTokenBinding(SPITokenBinding.Name, namespace)
   137  				Expect(err).NotTo(HaveOccurred())
   138  				return SPITokenBinding.Status.Phase == v1beta1.SPIAccessTokenBindingPhaseInjected
   139  			}, 1*time.Minute, 5*time.Second).Should(BeTrue(), "SPIAccessTokenBinding is not in Injected phase")
   140  
   141  			// SPIAccessToken exists and is in Read phase
   142  			Eventually(func() bool {
   143  				SPIAccessToken, err := user.Framework.AsKubeDeveloper.SPIController.GetSPIAccessToken(SPITokenBinding.Status.LinkedAccessTokenName, namespace)
   144  
   145  				if err != nil {
   146  					return false
   147  				}
   148  
   149  				return (SPIAccessToken.Status.Phase == v1beta1.SPIAccessTokenPhaseReady)
   150  			}, 1*time.Minute, 5*time.Second).Should(BeTrue(), "SPIAccessToken should be in ready phase")
   151  			// end of upload token
   152  		}
   153  
   154  		// check if guestUser can access a primary's secret in the primary's workspace
   155  		checkSecretAccess := func(client crclient.Client, primaryUser User, shouldAccess bool) {
   156  			// checks that guest user can access a primary's secret in primary's workspace
   157  			spiAccessToken := &v1beta1.SPIAccessToken{}
   158  			err := client.Get(context.TODO(), types.NamespacedName{Name: primaryUser.LinkedAccessTokenName, Namespace: primaryUser.Framework.UserNamespace}, spiAccessToken)
   159  
   160  			if shouldAccess {
   161  				Expect(err).NotTo(HaveOccurred())
   162  			} else {
   163  				Expect(err).To(HaveOccurred())
   164  			}
   165  		}
   166  
   167  		// check if guest user can read a primary's GitHub repo in the primary's workspace
   168  		checkRepositoryReading := func(client crclient.Client, primaryUser User, shouldRead bool) {
   169  			// create SPIFileContentRequest in primary's workspace URL
   170  			spiFcr := v1beta1.SPIFileContentRequest{
   171  				ObjectMeta: metav1.ObjectMeta{
   172  					GenerateName: "spi-file-content-request-",
   173  					Namespace:    primaryUser.Framework.UserNamespace,
   174  				},
   175  				Spec: v1beta1.SPIFileContentRequestSpec{RepoUrl: GithubPrivateRepoURL, FilePath: GithubPrivateRepoFilePath},
   176  			}
   177  			err := client.Create(context.TODO(), &spiFcr)
   178  
   179  			if shouldRead {
   180  				Expect(err).NotTo(HaveOccurred())
   181  
   182  				// check that guest user can read a primary's GitHub repo in the primary's workspace
   183  				Eventually(func() bool {
   184  					err = client.Get(context.TODO(), types.NamespacedName{Name: spiFcr.Name, Namespace: spiFcr.Namespace}, &spiFcr)
   185  					Expect(err).NotTo(HaveOccurred())
   186  
   187  					return spiFcr.Status.Phase == v1beta1.SPIFileContentRequestPhaseDelivered && spiFcr.Status.Content != ""
   188  				}, 2*time.Minute, 10*time.Second).Should(BeTrue(), "content not provided by SPIFileContentRequest")
   189  			} else {
   190  				Expect(err).To(HaveOccurred())
   191  			}
   192  		}
   193  
   194  		// check if guest user can read a primary's secret in the primary's workspace
   195  		checkSecretReading := func(client crclient.Client, primaryUser User, shouldRead bool) {
   196  			resultSecret := &corev1.Secret{}
   197  			err := client.Get(context.TODO(), types.NamespacedName{Name: primaryUser.SPIGithubWorkSpaceSecretName, Namespace: primaryUser.Framework.UserNamespace}, resultSecret)
   198  
   199  			if shouldRead {
   200  				Expect(err).ToNot(HaveOccurred())
   201  				token := resultSecret.Data["password"]
   202  				Expect(token).ToNot(BeEmpty())
   203  			} else {
   204  				Expect(err).To(HaveOccurred())
   205  			}
   206  		}
   207  
   208  		// check that guest user can make a request to create a SPIFileContentRequest in the primary's workspace
   209  		makeGhReadRequestFromPod := func(guestUser, primaryUser User, podName, podNamespace, spiFcrName string) {
   210  			spiFcrData := fmt.Sprintf(`---
   211  apiVersion: appstudio.redhat.com/v1beta1
   212  kind: SPIFileContentRequest
   213  metadata:
   214    name: %s
   215    namespace: %s
   216  spec:
   217    filePath: README.md
   218    repoUrl: %s
   219  `, spiFcrName, primaryUser.Framework.UserNamespace, GithubPrivateRepoURL)
   220  			readRequest := fmt.Sprintf(
   221  				"curl '%s' \\"+
   222  					"-k \\"+
   223  					"-H 'Authorization: Bearer %s' \\"+
   224  					"-X POST \\"+
   225  					"-H 'Content-Type: application/yaml' \\"+
   226  					"-d '%s'",
   227  				fmt.Sprintf("%s/apis/appstudio.redhat.com/v1beta1/namespaces/%s/spifilecontentrequests", primaryUser.WorkspaceURL, primaryUser.Framework.UserNamespace),
   228  				guestUser.Framework.UserToken,
   229  				spiFcrData,
   230  			)
   231  			request := guestUser.Framework.AsKubeAdmin.CommonController.KubeInterface().CoreV1().RESTClient().
   232  				Post().Namespace(podNamespace).
   233  				Resource("pods").
   234  				Name(podName).
   235  				SubResource("exec").
   236  				VersionedParams(&corev1.PodExecOptions{
   237  					Command: []string{
   238  						"/bin/sh",
   239  						"-c",
   240  						readRequest,
   241  					},
   242  					Stdin:  false,
   243  					Stdout: true,
   244  					Stderr: true,
   245  					TTY:    true,
   246  				}, scheme.ParameterCodec)
   247  
   248  			config := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(
   249  				clientcmd.NewDefaultClientConfigLoadingRules(),
   250  				&clientcmd.ConfigOverrides{},
   251  			)
   252  			restConfig, err := config.ClientConfig()
   253  			Expect(err).NotTo(HaveOccurred())
   254  
   255  			exec, err := remotecommand.NewSPDYExecutor(restConfig, "POST", request.URL())
   256  			Expect(err).NotTo(HaveOccurred())
   257  
   258  			buffer := &bytes.Buffer{}
   259  			errBuffer := &bytes.Buffer{}
   260  			err = exec.Stream(remotecommand.StreamOptions{
   261  				Stdout: buffer,
   262  				Stderr: errBuffer,
   263  			})
   264  			Expect(err).ToNot(HaveOccurred(), fmt.Sprintf("reason: %v", err))
   265  			Expect(buffer.String()).NotTo(BeEmpty())
   266  			Expect(errBuffer.String()).To(BeEmpty())
   267  		}
   268  
   269  		// check if guest user's pod deployed in guest user's workspace should be able to construct an API request that reads code in the Github repo for primary's user workspace
   270  		checkRepoReadingFromPod := func(client crclient.Client, guestUser, primaryUser User, shouldRead bool) {
   271  			namespace := guestUser.Framework.UserNamespace
   272  			p := &corev1.Pod{
   273  				ObjectMeta: metav1.ObjectMeta{
   274  					Namespace:    namespace,
   275  					GenerateName: "pod-",
   276  				},
   277  				Spec: corev1.PodSpec{
   278  					RestartPolicy: corev1.RestartPolicyNever,
   279  					Containers: []corev1.Container{
   280  						{
   281  							Name:  "read",
   282  							Image: "quay.io/redhat-appstudio/buildah:v1.28",
   283  							// workaround to force the pod to be running
   284  							Command: []string{
   285  								"sleep",
   286  								"600",
   287  							},
   288  						},
   289  					},
   290  				},
   291  			}
   292  
   293  			// create pod
   294  			pod, err := guestUser.Framework.AsKubeAdmin.CommonController.KubeInterface().CoreV1().Pods(namespace).Create(context.Background(), p, metav1.CreateOptions{})
   295  			Expect(err).NotTo(HaveOccurred())
   296  
   297  			// check that pod started
   298  			Eventually(func() bool {
   299  				pod, err := guestUser.Framework.AsKubeAdmin.CommonController.GetPod(namespace, pod.Name)
   300  				Expect(err).NotTo(HaveOccurred())
   301  
   302  				return pod.Status.Phase == corev1.PodRunning
   303  			}, 1*time.Minute, 5*time.Second).Should(BeTrue(), "Pod not created successfully")
   304  			Expect(err).NotTo(HaveOccurred())
   305  
   306  			// make read request
   307  			spiFcrName := utils.GetGeneratedNamespace("pod-spi-file-content-request")
   308  			makeGhReadRequestFromPod(guestUser, primaryUser, pod.Name, pod.Namespace, spiFcrName)
   309  
   310  			spiFcr := v1beta1.SPIFileContentRequest{}
   311  			if shouldRead {
   312  				// check that guest user's pod can read a primary's GitHub repo in the primary's workspace
   313  				Eventually(func() bool {
   314  					err = client.Get(context.TODO(), types.NamespacedName{Name: spiFcrName, Namespace: primaryUser.Framework.UserNamespace}, &spiFcr)
   315  					Expect(err).NotTo(HaveOccurred())
   316  
   317  					return spiFcr.Status.Phase == v1beta1.SPIFileContentRequestPhaseDelivered && spiFcr.Status.Content != ""
   318  				}, 2*time.Minute, 10*time.Second).Should(BeTrue(), "content not provided by SPIFileContentRequest")
   319  			} else {
   320  				// check that guest user's pod can not read a primary's GitHub repo in the primary's workspace
   321  				err = client.Get(context.TODO(), types.NamespacedName{Name: spiFcrName, Namespace: primaryUser.Framework.UserNamespace}, &spiFcr)
   322  				Expect(err).To(HaveOccurred())
   323  			}
   324  		}
   325  
   326  		BeforeAll(func() {
   327  			// Initialize the tests controllers for user A
   328  			// test user A is the owner and have access to the workspace A
   329  			fwUserA, err := framework.NewFramework(utils.GetGeneratedNamespace("spi-user-a"))
   330  			Expect(err).NotTo(HaveOccurred())
   331  			namespaceUserA := fwUserA.UserNamespace
   332  			Expect(namespaceUserA).NotTo(BeEmpty())
   333  			userA = User{
   334  				Framework:                    fwUserA,
   335  				SPIGithubWorkSpaceSecretName: "e2e-github-secret-workspace-a",
   336  				WorkspaceURL:                 fmt.Sprintf("%s/workspaces/%s", fwUserA.ProxyUrl, fwUserA.UserName),
   337  			}
   338  
   339  			// Initialize the tests controllers for user B
   340  			// test user B is the owner and have access to the workspace B
   341  			fwUserB, err := framework.NewFramework(utils.GetGeneratedNamespace("spi-user-b"))
   342  			Expect(err).NotTo(HaveOccurred())
   343  			namespaceUserB := fwUserB.UserNamespace
   344  			Expect(namespaceUserB).NotTo(BeEmpty())
   345  			userB = User{
   346  				Framework:                    fwUserB,
   347  				SPIGithubWorkSpaceSecretName: "e2e-github-secret-workspace-b",
   348  				WorkspaceURL:                 fmt.Sprintf("%s/workspaces/%s", fwUserB.ProxyUrl, fwUserB.UserName),
   349  			}
   350  
   351  			// Initialize the tests controllers for user C
   352  			// test user C is the owner and have access to the workspace C
   353  			fwUserC, err := framework.NewFramework(utils.GetGeneratedNamespace("spi-user-c"))
   354  			Expect(err).NotTo(HaveOccurred())
   355  			namespaceUserC := fwUserC.UserNamespace
   356  			Expect(namespaceUserC).NotTo(BeEmpty())
   357  			userC = User{
   358  				Framework:                    fwUserC,
   359  				SPIGithubWorkSpaceSecretName: "e2e-github-secret-workspace-c",
   360  				WorkspaceURL:                 fmt.Sprintf("%s/workspaces/%s", fwUserC.ProxyUrl, fwUserC.UserName),
   361  			}
   362  
   363  			// create api proxy client with user A token and user's A workspace URL
   364  			userA.APIProxyClientA = createAPIProxyClient(userA.Framework.UserToken, userA.WorkspaceURL)
   365  			// create api proxy client with user A token and user's B workspace URL
   366  			userA.APIProxyClientB = createAPIProxyClient(userA.Framework.UserToken, userB.WorkspaceURL)
   367  			// create api proxy client with user A token and user's C workspace URL
   368  			userA.APIProxyClientC = createAPIProxyClient(userA.Framework.UserToken, userC.WorkspaceURL)
   369  
   370  			// create api proxy client with user B token and user's A workspace URL
   371  			userB.APIProxyClientA = createAPIProxyClient(userB.Framework.UserToken, userA.WorkspaceURL)
   372  			// create api proxy client with user B token and user's B workspace URL
   373  			userB.APIProxyClientB = createAPIProxyClient(userB.Framework.UserToken, userB.WorkspaceURL)
   374  			// create api proxy client with user B token and user's C workspace URL
   375  			userB.APIProxyClientC = createAPIProxyClient(userB.Framework.UserToken, userC.WorkspaceURL)
   376  
   377  			// create api proxy client with user C token and user's A workspace URL
   378  			userC.APIProxyClientA = createAPIProxyClient(userC.Framework.UserToken, userA.WorkspaceURL)
   379  			// create api proxy client with user C token and user's B workspace URL
   380  			userC.APIProxyClientB = createAPIProxyClient(userC.Framework.UserToken, userB.WorkspaceURL)
   381  			// create api proxy client with user C token and user's C workspace URL
   382  			userC.APIProxyClientC = createAPIProxyClient(userC.Framework.UserToken, userC.WorkspaceURL)
   383  
   384  			// share workspace C with user A with maintainer roles
   385  			_, err = fwUserC.AsKubeAdmin.CommonController.CreateSpaceBinding(fwUserA.UserName, fwUserC.UserName, "maintainer")
   386  			Expect(err).NotTo(HaveOccurred())
   387  
   388  			// check if workspace C was shared with user A
   389  			Eventually(func() bool {
   390  				err = fwUserC.AsKubeAdmin.CommonController.CheckWorkspaceShare(fwUserA.UserName, fwUserC.UserNamespace)
   391  				return err == nil
   392  			}, 1*time.Minute, 5*time.Second).Should(BeTrue(), "error checking if the workspace C was shared with user A")
   393  
   394  			// check if user C is provisioned after workspace share
   395  			Eventually(func() bool {
   396  				_, err := fwUserC.SandboxController.GetUserProvisionedNamespace(fwUserC.UserName)
   397  				return err == nil
   398  			}, 1*time.Minute, 5*time.Second).Should(BeTrue(), "error getting provisioned usernamespace")
   399  
   400  			// create SPITokenBinding for user A
   401  			createSPITokenBinding(userA)
   402  
   403  			// create SPITokenBinding for user B
   404  			createSPITokenBinding(userB)
   405  
   406  			// create SPITokenBinding for user C
   407  			createSPITokenBinding(userC)
   408  		})
   409  
   410  		AfterAll(func() {
   411  			if !CurrentSpecReport().Failed() {
   412  				delete(userA)
   413  				delete(userB)
   414  				delete(userC)
   415  			}
   416  		})
   417  
   418  		It("checks that user A can access the SPIAccessToken A in workspace A", func() {
   419  			checkSecretAccess(*userA.APIProxyClientA, userA, true)
   420  		})
   421  
   422  		It("checks that user A can not access the SPIAccessToken B in workspace B", func() {
   423  			checkSecretAccess(*userA.APIProxyClientB, userB, false)
   424  		})
   425  
   426  		It("checks that user A can access the SPIAccessToken C in workspace C", func() {
   427  			// workspace C was shared with user A
   428  			checkSecretAccess(*userA.APIProxyClientC, userC, true)
   429  		})
   430  
   431  		It("checks that user B can not access the SPIAccessToken A in workspace A", func() {
   432  			checkSecretAccess(*userB.APIProxyClientA, userA, false)
   433  		})
   434  
   435  		It("checks that user B can access the SPIAccessToken B in workspace B", func() {
   436  			checkSecretAccess(*userB.APIProxyClientB, userB, true)
   437  		})
   438  
   439  		It("checks that user B can not access the SPIAccessToken C in workspace C", func() {
   440  			checkSecretAccess(*userB.APIProxyClientC, userC, false)
   441  		})
   442  
   443  		It("checks that user C can not access the SPIAccessToken A in workspace A", func() {
   444  			checkSecretAccess(*userC.APIProxyClientA, userA, false)
   445  		})
   446  
   447  		It("checks that user C can not access the SPIAccessToken B in workspace B", func() {
   448  			checkSecretAccess(*userC.APIProxyClientB, userB, false)
   449  		})
   450  
   451  		It("checks that user C can access the SPIAccessToken C in workspace C", func() {
   452  			checkSecretAccess(*userC.APIProxyClientC, userC, true)
   453  		})
   454  
   455  		It("checks that user A can read the GitHub repo in workspace A", func() {
   456  			checkRepositoryReading(*userA.APIProxyClientA, userA, true)
   457  		})
   458  
   459  		It("checks that user A can not read the GitHub repo in workspace B", func() {
   460  			checkRepositoryReading(*userA.APIProxyClientB, userB, false)
   461  		})
   462  
   463  		It("checks that user A can read the GitHub repo in workspace C", func() {
   464  			// workspace C was shared with user A
   465  			checkRepositoryReading(*userA.APIProxyClientC, userC, true)
   466  		})
   467  
   468  		It("checks that user B can not read the GitHub repo in workspace A", func() {
   469  			checkRepositoryReading(*userB.APIProxyClientA, userA, false)
   470  		})
   471  
   472  		It("checks that user B can read the GitHub repo in workspace B", func() {
   473  			checkRepositoryReading(*userB.APIProxyClientB, userB, true)
   474  		})
   475  
   476  		It("checks that user B can not read the GitHub repo in workspace C", func() {
   477  			checkRepositoryReading(*userB.APIProxyClientC, userC, false)
   478  		})
   479  
   480  		It("checks that user C can not read the GitHub repo in workspace A", func() {
   481  			checkRepositoryReading(*userC.APIProxyClientA, userA, false)
   482  		})
   483  
   484  		It("checks that user C can not read the GitHub repo in workspace B", func() {
   485  			checkRepositoryReading(*userC.APIProxyClientB, userB, false)
   486  		})
   487  
   488  		It("checks that user C can read the GitHub repo in workspace C", func() {
   489  			checkRepositoryReading(*userC.APIProxyClientC, userC, true)
   490  		})
   491  
   492  		It("checks that user A can read the secret in workspace A", func() {
   493  			checkSecretReading(*userA.APIProxyClientA, userA, true)
   494  		})
   495  
   496  		It("checks that user A can not read the secret in workspace B", func() {
   497  			checkSecretReading(*userA.APIProxyClientB, userB, false)
   498  		})
   499  
   500  		It("checks that user A can not read the secret in workspace C", func() {
   501  			// although workspace C is shared with user A, the role given is maintainer,
   502  			// which does not have any permissions for secrets object
   503  			checkSecretReading(*userA.APIProxyClientC, userC, false)
   504  		})
   505  
   506  		It("checks that user B can not read the secret in workspace A", func() {
   507  			checkSecretReading(*userB.APIProxyClientA, userA, false)
   508  		})
   509  
   510  		It("checks that user B can read the secret in workspace B", func() {
   511  			checkSecretReading(*userB.APIProxyClientB, userB, true)
   512  		})
   513  
   514  		It("checks that user B can not read the secret in workspace C", func() {
   515  			checkSecretReading(*userB.APIProxyClientC, userC, false)
   516  		})
   517  
   518  		It("checks that user C can not read the secret in workspace A", func() {
   519  			checkSecretReading(*userC.APIProxyClientA, userA, false)
   520  		})
   521  
   522  		It("checks that user C can not read the secret in workspace B", func() {
   523  			checkSecretReading(*userC.APIProxyClientB, userB, false)
   524  		})
   525  
   526  		It("checks that user C can read the secret in workspace C", func() {
   527  			checkSecretReading(*userC.APIProxyClientC, userC, true)
   528  		})
   529  
   530  		It("checks that a user's A pod deployed in workspace A should be able to construct an API request that reads code in the Github repo for workspace A", func() {
   531  			checkRepoReadingFromPod(*userA.APIProxyClientA, userA, userA, true)
   532  		})
   533  
   534  		It("checks that a user's A pod deployed in workspace A should not be able to construct an API request that reads code in the Github repo for workspace B", func() {
   535  			checkRepoReadingFromPod(*userA.APIProxyClientB, userA, userB, false)
   536  		})
   537  
   538  		It("checks that a user's A pod deployed in workspace A should be able to construct an API request that reads code in the Github repo for workspace C", func() {
   539  			// workspace C was shared with user A
   540  			checkRepoReadingFromPod(*userA.APIProxyClientC, userA, userC, true)
   541  		})
   542  
   543  		It("checks that a user's B pod deployed in workspace B should not be able to construct an API request that reads code in the Github repo for workspace A", func() {
   544  			checkRepoReadingFromPod(*userB.APIProxyClientA, userB, userA, false)
   545  		})
   546  
   547  		It("checks that a user's B pod deployed in workspace B should be able to construct an API request that reads code in the Github repo for workspace B", func() {
   548  			checkRepoReadingFromPod(*userB.APIProxyClientB, userB, userB, true)
   549  		})
   550  
   551  		It("checks that a user's B pod deployed in workspace B should not be able to construct an API request that reads code in the Github repo for workspace C", func() {
   552  			checkRepoReadingFromPod(*userB.APIProxyClientC, userB, userC, false)
   553  		})
   554  
   555  		It("checks that a user's C pod deployed in workspace C should not be able to construct an API request that reads code in the Github repo for workspace A", func() {
   556  			checkRepoReadingFromPod(*userC.APIProxyClientA, userC, userA, false)
   557  		})
   558  
   559  		It("checks that a user's C pod deployed in workspace C should not be able to construct an API request that reads code in the Github repo for workspace B", func() {
   560  			checkRepoReadingFromPod(*userC.APIProxyClientB, userC, userB, false)
   561  		})
   562  
   563  		It("checks that a user's C pod deployed in workspace C should be able to construct an API request that reads code in the Github repo for workspace C", func() {
   564  			checkRepoReadingFromPod(*userC.APIProxyClientC, userC, userC, true)
   565  		})
   566  	})
   567  })