Path: blob/main/test/tests/smoke-test/collaborator_test.go
2496 views
// Copyright (c) 2024 Gitpod GmbH. All rights reserved.1// Licensed under the GNU Affero General Public License (AGPL).2// See License.AGPL.txt in the project root for license information.34package smoketest56import (7"context"8"fmt"9"net/http"10"os"11"strings"12"testing"13"time"1415connect "github.com/bufbuild/connect-go"16"github.com/gitpod-io/gitpod/common-go/util"17experimentalv1 "github.com/gitpod-io/gitpod/components/public-api/go/experimental/v1"18experimentalv1connect "github.com/gitpod-io/gitpod/components/public-api/go/experimental/v1/v1connect"19v1 "github.com/gitpod-io/gitpod/components/public-api/go/v1"20v1connect "github.com/gitpod-io/gitpod/components/public-api/go/v1/v1connect"21serverapi "github.com/gitpod-io/gitpod/gitpod-protocol"22log "github.com/sirupsen/logrus"23"golang.org/x/xerrors"24"google.golang.org/grpc"25"google.golang.org/grpc/credentials/insecure"26)2728/**29*30# 1. Create an org31# 2. Invite your another account to be a collaborator of this org32# 3. Create a project in this org3334cd test35export TEST_COLLABORATOR=true36export GITPOD_HOST=hw-collaborator.preview.gitpod-dev.com37export ORG_ID=130d67cf-8b11-45e9-b8d2-33bf34ca4a4c38export PROJECT_ID=699c6566-1049-469e-9e61-c8fe0db9d3963940# test with cookie, cookie should format like `_hw_collaborator_preview_gitpod_dev_com_jwt2_=xxx“41export USE_COOKIE=true42export USER_TOKEN="<your_cookie>"43go test -run "^TestMembers|TestProjects|TestGetProject$" github.com/gitpod-io/gitpod/test/tests/smoke-test -v -count=14445# test with PAT46export USE_COOKIE=false47export USER_TOKEN=<your_pat>48go test -run "^TestMembers|TestProjects|TestGetProject$" github.com/gitpod-io/gitpod/test/tests/smoke-test -v -count=14950# debug: go test -run "^TestProjects$" github.com/gitpod-io/gitpod/test/tests/smoke-test -v -count=151*/5253// TestMembers tests collaborator can't access members with:54// 1. experimental.v1 + COOKIE -> permission_denied55// 2. experimental.v1 + PAT -> permission_denied56// 3. v1 + COOKIE -> permission_denied57// 4. v1 + PAT -> permission_denied58// 5. server + COOKIE -> code 40359func TestMembers(t *testing.T) {60if !shouldTestCollaborator() {61t.Skip("skipping collaborator test")62return63}64userToken, _ := os.LookupEnv("USER_TOKEN")65gitpodHost, _ := os.LookupEnv("GITPOD_HOST")66orgID, _ := os.LookupEnv("ORG_ID")6768serverConn, err0 := connectToServer(gitpodHost, userToken)69if err0 != nil {70t.Errorf("failed getting server conn: %v", err0)71}72v1Http, v1Opts, v1Host := getPAPIConnSettings(gitpodHost, userToken, getUseCookie(), false)73ev1Http, ev1Opts, ev1Host := getPAPIConnSettings(gitpodHost, userToken, getUseCookie(), true)74ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)75defer cancel()76client := experimentalv1connect.NewTeamsServiceClient(ev1Http, ev1Host, ev1Opts...)77v1Client := v1connect.NewOrganizationServiceClient(v1Http, v1Host, v1Opts...)78_, err := client.ListTeamMembers(ctx, connect.NewRequest(&experimentalv1.ListTeamMembersRequest{79TeamId: orgID,80}))81_, err2 := v1Client.ListOrganizationMembers(ctx, connect.NewRequest(&v1.ListOrganizationMembersRequest{82OrganizationId: orgID,83Pagination: &v1.PaginationRequest{},84}))85_, err3 := serverConn.GetTeamMembers(ctx, orgID)8687if !strings.Contains(err.Error(), "permission_denied:") {88t.Errorf("experimental should respond permission_denied, got: %s", err)89}90if !strings.Contains(err2.Error(), "permission_denied:") {91t.Errorf("v1 should respond permission_denied, got: %s", err2)92}93if getUseCookie() {94if !strings.Contains(err3.Error(), "code 403 ") {95t.Errorf("server should respond permission_denied, got: %s", err3)96}97}98}99100// TestProjects tests collaborator can't access projects with:101// 1. experimental.v1 + COOKIE -> empty array102// 2. experimental.v1 + PAT -> empty array103// 3. v1 + COOKIE -> empty array104// 4. v1 + PAT -> empty array105// 5. server + COOKIE -> empty array106func TestProjects(t *testing.T) {107if !shouldTestCollaborator() {108t.Skip("skipping collaborator test")109return110}111userToken, _ := os.LookupEnv("USER_TOKEN")112gitpodHost, _ := os.LookupEnv("GITPOD_HOST")113orgID, _ := os.LookupEnv("ORG_ID")114115serverConn, err0 := connectToServer(gitpodHost, userToken)116if err0 != nil {117t.Errorf("failed getting server conn: %v", err0)118}119v1Http, v1Opts, v1Host := getPAPIConnSettings(gitpodHost, userToken, getUseCookie(), false)120ev1Http, ev1Opts, ev1Host := getPAPIConnSettings(gitpodHost, userToken, getUseCookie(), false)121122ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)123defer cancel()124client := experimentalv1connect.NewProjectsServiceClient(ev1Http, ev1Host, ev1Opts...)125v1Client := v1connect.NewConfigurationServiceClient(v1Http, v1Host, v1Opts...)126resp, err := client.ListProjects(ctx, connect.NewRequest(&experimentalv1.ListProjectsRequest{127TeamId: orgID,128Pagination: &experimentalv1.Pagination{},129}))130resp2, err2 := v1Client.ListConfigurations(ctx, connect.NewRequest(&v1.ListConfigurationsRequest{131OrganizationId: orgID,132Pagination: &v1.PaginationRequest{},133}))134resp3, err3 := serverConn.GetTeamProjects(ctx, orgID)135136if getUseCookie() {137if err != nil || err2 != nil || err3 != nil {138t.Errorf("should respond empty array, got: %v, %v, %v", err, err2, err3)139}140if len(resp.Msg.GetProjects()) != 0 || len(resp2.Msg.GetConfigurations()) != 0 || len(resp3) != 0 {141t.Errorf("should respond empty array, got: %d, %d, %d", len(resp.Msg.GetProjects()), len(resp2.Msg.GetConfigurations()), len(resp3))142}143} else {144if err != nil || err2 != nil {145t.Errorf("should respond empty array, got: %v, %v, %v", err, err2, err3)146}147148if len(resp.Msg.GetProjects()) != 0 || len(resp2.Msg.GetConfigurations()) != 0 {149t.Errorf("should respond empty array, got: %d, %d", len(resp.Msg.GetProjects()), len(resp2.Msg.GetConfigurations()))150}151}152}153154// TestGetProject tests collaborator can't access project detail with:155// 1. v1 + COOKIE -> not_found156// 2. v1 + PAT -> not_found157func TestGetProject(t *testing.T) {158if !shouldTestCollaborator() {159t.Skip("skipping collaborator test")160return161}162userToken, _ := os.LookupEnv("USER_TOKEN")163gitpodHost, _ := os.LookupEnv("GITPOD_HOST")164projectID, _ := os.LookupEnv("PROJECT_ID")165166if _, err := connectToServer(gitpodHost, userToken); err != nil {167t.Errorf("failed getting server conn: %v", err)168}169v1Http, v1Opts, v1Host := getPAPIConnSettings(gitpodHost, userToken, getUseCookie(), false)170171ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)172defer cancel()173174v1Client := v1connect.NewConfigurationServiceClient(v1Http, v1Host, v1Opts...)175_, err2 := v1Client.GetConfiguration(ctx, connect.NewRequest(&v1.GetConfigurationRequest{176ConfigurationId: projectID,177}))178if !strings.Contains(err2.Error(), "not_found") {179t.Errorf("v1 should respond not_found, got: %s", err2)180}181}182183// Note: there's no usage endpoint in the server / public v1 experimental.v1 APIs184185func shouldTestCollaborator() bool {186should, _ := os.LookupEnv("TEST_COLLABORATOR")187return should == "true"188}189190func getUseCookie() bool {191useCookie, _ := os.LookupEnv("USE_COOKIE")192return useCookie == "true"193}194195func connectToServer(gitpodHost, token string) (*serverapi.APIoverJSONRPC, error) {196supervisorConn, err := grpc.Dial(util.GetSupervisorAddress(), grpc.WithTransportCredentials(insecure.NewCredentials()))197if err != nil {198return nil, xerrors.Errorf("failed connecting to supervisor: %w", err)199}200defer supervisorConn.Close()201if err != nil {202return nil, xerrors.Errorf("failed getting token from supervisor: %w", err)203}204205endpoint := "wss://" + gitpodHost + "/api/gitpod"206useCookie := getUseCookie()207opts := serverapi.ConnectToServerOpts{208Context: context.Background(),209Log: log.NewEntry(log.StandardLogger()),210ExtraHeaders: map[string]string{211"User-Agent": "gitpod/cli",212"X-Client-Version": "0.0.1",213},214}215if useCookie {216opts.ExtraHeaders["Cookie"] = token217} else {218opts.Token = token219}220client, err := serverapi.ConnectToServer(endpoint, opts)221if err != nil {222return nil, xerrors.Errorf("failed connecting to server: %w", err)223}224return client, nil225}226227func getPAPIConnSettings(gitpodHost, token string, useCookie, isExperimental bool) (*http.Client, []connect.ClientOption, string) {228client := &http.Client{229Transport: &AuthenticatedTransport{Token: token, T: http.DefaultTransport, UseCookie: useCookie},230}231opts := []connect.ClientOption{232connect.WithInterceptors(233connect.UnaryInterceptorFunc(func(next connect.UnaryFunc) connect.UnaryFunc {234return func(ctx context.Context, req connect.AnyRequest) (connect.AnyResponse, error) {235if req.Spec().IsClient {236if useCookie {237req.Header().Set("Cookie", token)238} else {239req.Header().Set("Authorization", fmt.Sprintf("Bearer %s", token))240}241}242return next(ctx, req)243}244}),245),246}247endpoint := fmt.Sprintf("https://%s/public-api", gitpodHost)248if isExperimental {249endpoint = fmt.Sprintf("https://api.%s", gitpodHost)250}251return client, opts, endpoint252}253254type AuthenticatedTransport struct {255T http.RoundTripper256UseCookie bool257Token string258}259260func (t *AuthenticatedTransport) RoundTrip(req *http.Request) (*http.Response, error) {261if t.UseCookie {262req.Header.Add("Cookie", t.Token)263} else {264req.Header.Add("Authorization", "Bearer "+t.Token)265}266return t.T.RoundTrip(req)267}268269270