Skip to content

Commit c1316bb

Browse files
committed
[public-api] Initial stub implemention for CreateToken
1 parent 47865a0 commit c1316bb

File tree

2 files changed

+105
-12
lines changed

2 files changed

+105
-12
lines changed

components/public-api-server/pkg/apiv1/tokens.go

Lines changed: 46 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"context"
99
"errors"
1010
"fmt"
11+
"strings"
1112

1213
"github.com/bufbuild/connect-go"
1314
"github.com/gitpod-io/gitpod/common-go/experiments"
@@ -17,6 +18,7 @@ import (
1718
protocol "github.com/gitpod-io/gitpod/gitpod-protocol"
1819
"github.com/gitpod-io/gitpod/public-api-server/pkg/auth"
1920
"github.com/gitpod-io/gitpod/public-api-server/pkg/proxy"
21+
"github.com/google/uuid"
2022
)
2123

2224
func NewTokensService(connPool proxy.ServerConnectionPool, expClient experiments.Client) *TokensService {
@@ -35,24 +37,50 @@ type TokensService struct {
3537
}
3638

3739
func (s *TokensService) CreatePersonalAccessToken(ctx context.Context, req *connect.Request[v1.CreatePersonalAccessTokenRequest]) (*connect.Response[v1.CreatePersonalAccessTokenResponse], error) {
40+
conn, err := getConnection(ctx, s.connectionPool)
41+
if err != nil {
42+
return nil, err
43+
}
44+
45+
_, err = s.getUser(ctx, conn)
46+
if err != nil {
47+
return nil, err
48+
}
49+
50+
return nil, connect.NewError(connect.CodeUnimplemented, errors.New("gitpod.experimental.v1.TokensService.CreatePersonalAccessToken is not implemented"))
51+
}
52+
53+
func (s *TokensService) GetPersonalAccessToken(ctx context.Context, req *connect.Request[v1.GetPersonalAccessTokenRequest]) (*connect.Response[v1.GetPersonalAccessTokenResponse], error) {
54+
tokenID, err := validateTokenID(req.Msg.GetId())
55+
if err != nil {
56+
return nil, err
57+
}
3858

3959
conn, err := getConnection(ctx, s.connectionPool)
4060
if err != nil {
4161
return nil, err
4262
}
4363

64+
_, err = s.getUser(ctx, conn)
65+
if err != nil {
66+
return nil, err
67+
}
68+
69+
log.Infof("Handling GetPersonalAccessToken request for Token ID '%s'", tokenID.String())
70+
return nil, connect.NewError(connect.CodeUnimplemented, errors.New("gitpod.experimental.v1.TokensService.GetPersonalAccessToken is not implemented"))
71+
}
72+
73+
func (s *TokensService) getUser(ctx context.Context, conn protocol.APIInterface) (*protocol.User, error) {
4474
user, err := conn.GetLoggedInUser(ctx)
4575
if err != nil {
4676
return nil, proxy.ConvertError(err)
4777
}
4878

49-
isEnabled := experiments.IsPersonalAccessTokensEnabled(ctx, s.expClient, experiments.Attributes{UserID: user.ID})
50-
51-
if !isEnabled {
79+
if !experiments.IsPersonalAccessTokensEnabled(ctx, s.expClient, experiments.Attributes{UserID: user.ID}) {
5280
return nil, connect.NewError(connect.CodePermissionDenied, errors.New("This feature is currently in beta. If you would like to be part of the beta, please contact us."))
5381
}
5482

55-
return nil, connect.NewError(connect.CodeUnimplemented, errors.New("gitpod.experimental.v1.TokensService.CreatePersonalAccessToken is not implemented"))
83+
return user, nil
5684
}
5785

5886
func getConnection(ctx context.Context, pool proxy.ServerConnectionPool) (protocol.APIInterface, error) {
@@ -69,3 +97,17 @@ func getConnection(ctx context.Context, pool proxy.ServerConnectionPool) (protoc
6997

7098
return conn, nil
7199
}
100+
101+
func validateTokenID(id string) (uuid.UUID, error) {
102+
trimmed := strings.TrimSpace(id)
103+
if trimmed == "" {
104+
return uuid.Nil, connect.NewError(connect.CodeInvalidArgument, fmt.Errorf("Token ID is a required argument."))
105+
}
106+
107+
tokenID, err := uuid.Parse(trimmed)
108+
if err != nil {
109+
return uuid.Nil, connect.NewError(connect.CodeInvalidArgument, fmt.Errorf("Token ID must be a valid UUID"))
110+
}
111+
112+
return tokenID, nil
113+
}

components/public-api-server/pkg/apiv1/tokens_test.go

Lines changed: 59 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,24 +18,28 @@ import (
1818
protocol "github.com/gitpod-io/gitpod/gitpod-protocol"
1919
"github.com/gitpod-io/gitpod/public-api-server/pkg/auth"
2020
"github.com/golang/mock/gomock"
21+
"github.com/google/uuid"
2122
"github.com/stretchr/testify/require"
2223
)
2324

24-
func TestTokensService_CreatePersonalAccessTokenWithoutFeatureFlag(t *testing.T) {
25-
experimentsClient := &experimentstest.Client{
25+
var (
26+
withTokenFeatureDisabled = &experimentstest.Client{
27+
BoolMatcher: func(ctx context.Context, experiment string, defaultValue bool, attributes experiments.Attributes) bool {
28+
return false
29+
},
30+
}
31+
withTokenFeatureEnabled = &experimentstest.Client{
2632
BoolMatcher: func(ctx context.Context, experiment string, defaultValue bool, attributes experiments.Attributes) bool {
2733
return experiment == experiments.PersonalAccessTokensEnabledFlag
2834
},
2935
}
36+
)
3037

38+
func TestTokensService_CreatePersonalAccessTokenWithoutFeatureFlag(t *testing.T) {
3139
user := newUser(&protocol.User{})
3240

3341
t.Run("permission denied when feature flag is not enabled", func(t *testing.T) {
34-
serverMock, client := setupTokensService(t, &experimentstest.Client{
35-
BoolMatcher: func(ctx context.Context, experiment string, defaultValue bool, attributes experiments.Attributes) bool {
36-
return false
37-
},
38-
})
42+
serverMock, client := setupTokensService(t, withTokenFeatureDisabled)
3943

4044
serverMock.EXPECT().GetLoggedInUser(gomock.Any()).Return(user, nil)
4145

@@ -46,7 +50,7 @@ func TestTokensService_CreatePersonalAccessTokenWithoutFeatureFlag(t *testing.T)
4650
})
4751

4852
t.Run("unimplemented when feature flag enabled", func(t *testing.T) {
49-
serverMock, client := setupTokensService(t, experimentsClient)
53+
serverMock, client := setupTokensService(t, withTokenFeatureEnabled)
5054

5155
serverMock.EXPECT().GetLoggedInUser(gomock.Any()).Return(user, nil)
5256

@@ -55,6 +59,53 @@ func TestTokensService_CreatePersonalAccessTokenWithoutFeatureFlag(t *testing.T)
5559
})
5660
}
5761

62+
func TestTokensService_GetPersonalAccessToken(t *testing.T) {
63+
user := newUser(&protocol.User{})
64+
65+
t.Run("permission denied when feature flag is disabled", func(t *testing.T) {
66+
serverMock, client := setupTokensService(t, withTokenFeatureDisabled)
67+
68+
serverMock.EXPECT().GetLoggedInUser(gomock.Any()).Return(user, nil)
69+
70+
_, err := client.GetPersonalAccessToken(context.Background(), connect.NewRequest(&v1.GetPersonalAccessTokenRequest{
71+
Id: uuid.New().String(),
72+
}))
73+
74+
require.Error(t, err, "This feature is currently in beta. If you would like to be part of the beta, please contact us.")
75+
require.Equal(t, connect.CodePermissionDenied, connect.CodeOf(err))
76+
})
77+
78+
t.Run("invalid argument when Token ID is empty", func(t *testing.T) {
79+
_, client := setupTokensService(t, withTokenFeatureEnabled)
80+
81+
_, err := client.GetPersonalAccessToken(context.Background(), connect.NewRequest(&v1.GetPersonalAccessTokenRequest{}))
82+
83+
require.Equal(t, connect.CodeInvalidArgument, connect.CodeOf(err))
84+
})
85+
86+
t.Run("invalid argument when Token ID is not a valid UUID", func(t *testing.T) {
87+
_, client := setupTokensService(t, withTokenFeatureEnabled)
88+
89+
_, err := client.GetPersonalAccessToken(context.Background(), connect.NewRequest(&v1.GetPersonalAccessTokenRequest{
90+
Id: "foo-bar",
91+
}))
92+
93+
require.Equal(t, connect.CodeInvalidArgument, connect.CodeOf(err))
94+
})
95+
96+
t.Run("unimplemented when feature flag enabled", func(t *testing.T) {
97+
serverMock, client := setupTokensService(t, withTokenFeatureEnabled)
98+
99+
serverMock.EXPECT().GetLoggedInUser(gomock.Any()).Return(user, nil)
100+
101+
_, err := client.GetPersonalAccessToken(context.Background(), connect.NewRequest(&v1.GetPersonalAccessTokenRequest{
102+
Id: uuid.New().String(),
103+
}))
104+
105+
require.Equal(t, connect.CodeUnimplemented, connect.CodeOf(err))
106+
})
107+
}
108+
58109
func setupTokensService(t *testing.T, expClient experiments.Client) (*protocol.MockAPIInterface, v1connect.TokensServiceClient) {
59110
t.Helper()
60111

0 commit comments

Comments
 (0)