diff --git a/components/public-api-server/pkg/apiv1/tokens.go b/components/public-api-server/pkg/apiv1/tokens.go index 6dd2d55c583ea0..e32fd2760737f8 100644 --- a/components/public-api-server/pkg/apiv1/tokens.go +++ b/components/public-api-server/pkg/apiv1/tokens.go @@ -70,6 +70,80 @@ func (s *TokensService) GetPersonalAccessToken(ctx context.Context, req *connect return nil, connect.NewError(connect.CodeUnimplemented, errors.New("gitpod.experimental.v1.TokensService.GetPersonalAccessToken is not implemented")) } +func (s *TokensService) ListPersonalAccessTokens(ctx context.Context, req *connect.Request[v1.ListPersonalAccessTokensRequest]) (*connect.Response[v1.ListPersonalAccessTokensResponse], error) { + conn, err := getConnection(ctx, s.connectionPool) + if err != nil { + return nil, err + } + + _, err = s.getUser(ctx, conn) + if err != nil { + return nil, err + } + + return nil, connect.NewError(connect.CodeUnimplemented, errors.New("gitpod.experimental.v1.TokensService.ListPersonalAccessTokens is not implemented")) +} + +func (s *TokensService) RegeneratePersonalAccessToken(ctx context.Context, req *connect.Request[v1.RegeneratePersonalAccessTokenRequest]) (*connect.Response[v1.RegeneratePersonalAccessTokenResponse], error) { + tokenID, err := validateTokenID(req.Msg.GetId()) + if err != nil { + return nil, err + } + + conn, err := getConnection(ctx, s.connectionPool) + if err != nil { + return nil, err + } + + _, err = s.getUser(ctx, conn) + if err != nil { + return nil, err + } + + log.Infof("Handling RegeneratePersonalAccessToken request for Token ID '%s'", tokenID.String()) + return nil, connect.NewError(connect.CodeUnimplemented, errors.New("gitpod.experimental.v1.TokensService.RegeneratePersonalAccessToken is not implemented")) +} + +func (s *TokensService) UpdatePersonalAccessToken(ctx context.Context, req *connect.Request[v1.UpdatePersonalAccessTokenRequest]) (*connect.Response[v1.UpdatePersonalAccessTokenResponse], error) { + tokenID, err := validateTokenID(req.Msg.GetToken().GetId()) + if err != nil { + return nil, err + } + + conn, err := getConnection(ctx, s.connectionPool) + if err != nil { + return nil, err + } + + _, err = s.getUser(ctx, conn) + if err != nil { + return nil, err + } + + log.Infof("Handling UpdatePersonalAccessToken request for Token ID '%s'", tokenID.String()) + return nil, connect.NewError(connect.CodeUnimplemented, errors.New("gitpod.experimental.v1.TokensService.UpdatePersonalAccessToken is not implemented")) +} + +func (s *TokensService) DeletePersonalAccessToken(ctx context.Context, req *connect.Request[v1.DeletePersonalAccessTokenRequest]) (*connect.Response[v1.DeletePersonalAccessTokenResponse], error) { + tokenID, err := validateTokenID(req.Msg.GetId()) + if err != nil { + return nil, err + } + + conn, err := getConnection(ctx, s.connectionPool) + if err != nil { + return nil, err + } + + _, err = s.getUser(ctx, conn) + if err != nil { + return nil, err + } + + log.Infof("Handling DeletePersonalAccessToken request for Token ID '%s'", tokenID.String()) + return nil, connect.NewError(connect.CodeUnimplemented, errors.New("gitpod.experimental.v1.TokensService.DeletePersonalAccessToken is not implemented")) +} + func (s *TokensService) getUser(ctx context.Context, conn protocol.APIInterface) (*protocol.User, error) { user, err := conn.GetLoggedInUser(ctx) if err != nil { diff --git a/components/public-api-server/pkg/apiv1/tokens_test.go b/components/public-api-server/pkg/apiv1/tokens_test.go index 8444c664dfd434..4351fd724279f4 100644 --- a/components/public-api-server/pkg/apiv1/tokens_test.go +++ b/components/public-api-server/pkg/apiv1/tokens_test.go @@ -106,6 +106,178 @@ func TestTokensService_GetPersonalAccessToken(t *testing.T) { }) } +func TestTokensService_ListPersonalAccessTokens(t *testing.T) { + user := newUser(&protocol.User{}) + + t.Run("permission denied when feature flag is disabled", func(t *testing.T) { + serverMock, client := setupTokensService(t, withTokenFeatureDisabled) + + serverMock.EXPECT().GetLoggedInUser(gomock.Any()).Return(user, nil) + + _, err := client.ListPersonalAccessTokens(context.Background(), connect.NewRequest(&v1.ListPersonalAccessTokensRequest{})) + + require.Error(t, err, "This feature is currently in beta. If you would like to be part of the beta, please contact us.") + require.Equal(t, connect.CodePermissionDenied, connect.CodeOf(err)) + }) + + t.Run("unimplemented when feature flag enabled", func(t *testing.T) { + serverMock, client := setupTokensService(t, withTokenFeatureEnabled) + + serverMock.EXPECT().GetLoggedInUser(gomock.Any()).Return(user, nil) + + _, err := client.ListPersonalAccessTokens(context.Background(), connect.NewRequest(&v1.ListPersonalAccessTokensRequest{})) + + require.Equal(t, connect.CodeUnimplemented, connect.CodeOf(err)) + }) +} + +func TestTokensService_RegeneratePersonalAccessToken(t *testing.T) { + user := newUser(&protocol.User{}) + + t.Run("permission denied when feature flag is disabled", func(t *testing.T) { + serverMock, client := setupTokensService(t, withTokenFeatureDisabled) + + serverMock.EXPECT().GetLoggedInUser(gomock.Any()).Return(user, nil) + + _, err := client.RegeneratePersonalAccessToken(context.Background(), connect.NewRequest(&v1.RegeneratePersonalAccessTokenRequest{ + Id: uuid.New().String(), + })) + + require.Error(t, err, "This feature is currently in beta. If you would like to be part of the beta, please contact us.") + require.Equal(t, connect.CodePermissionDenied, connect.CodeOf(err)) + }) + + t.Run("invalid argument when Token ID is empty", func(t *testing.T) { + _, client := setupTokensService(t, withTokenFeatureEnabled) + + _, err := client.RegeneratePersonalAccessToken(context.Background(), connect.NewRequest(&v1.RegeneratePersonalAccessTokenRequest{})) + + require.Equal(t, connect.CodeInvalidArgument, connect.CodeOf(err)) + }) + + t.Run("invalid argument when Token ID is not a valid UUID", func(t *testing.T) { + _, client := setupTokensService(t, withTokenFeatureEnabled) + + _, err := client.RegeneratePersonalAccessToken(context.Background(), connect.NewRequest(&v1.RegeneratePersonalAccessTokenRequest{ + Id: "foo-bar", + })) + + require.Equal(t, connect.CodeInvalidArgument, connect.CodeOf(err)) + }) + + t.Run("unimplemented when feature flag enabled", func(t *testing.T) { + serverMock, client := setupTokensService(t, withTokenFeatureEnabled) + + serverMock.EXPECT().GetLoggedInUser(gomock.Any()).Return(user, nil) + + _, err := client.RegeneratePersonalAccessToken(context.Background(), connect.NewRequest(&v1.RegeneratePersonalAccessTokenRequest{ + Id: uuid.New().String(), + })) + + require.Equal(t, connect.CodeUnimplemented, connect.CodeOf(err)) + }) +} + +func TestTokensService_UpdatePersonalAccessToken(t *testing.T) { + user := newUser(&protocol.User{}) + + t.Run("permission denied when feature flag is disabled", func(t *testing.T) { + serverMock, client := setupTokensService(t, withTokenFeatureDisabled) + + serverMock.EXPECT().GetLoggedInUser(gomock.Any()).Return(user, nil) + + _, err := client.UpdatePersonalAccessToken(context.Background(), connect.NewRequest(&v1.UpdatePersonalAccessTokenRequest{ + Token: &v1.PersonalAccessToken{ + Id: uuid.New().String(), + }, + })) + + require.Error(t, err, "This feature is currently in beta. If you would like to be part of the beta, please contact us.") + require.Equal(t, connect.CodePermissionDenied, connect.CodeOf(err)) + }) + + t.Run("invalid argument when Token ID is empty", func(t *testing.T) { + _, client := setupTokensService(t, withTokenFeatureEnabled) + + _, err := client.UpdatePersonalAccessToken(context.Background(), connect.NewRequest(&v1.UpdatePersonalAccessTokenRequest{})) + + require.Equal(t, connect.CodeInvalidArgument, connect.CodeOf(err)) + }) + + t.Run("invalid argument when Token ID is not a valid UUID", func(t *testing.T) { + _, client := setupTokensService(t, withTokenFeatureEnabled) + + _, err := client.UpdatePersonalAccessToken(context.Background(), connect.NewRequest(&v1.UpdatePersonalAccessTokenRequest{ + Token: &v1.PersonalAccessToken{ + Id: "foo-bar", + }, + })) + + require.Equal(t, connect.CodeInvalidArgument, connect.CodeOf(err)) + }) + + t.Run("unimplemented when feature flag enabled", func(t *testing.T) { + serverMock, client := setupTokensService(t, withTokenFeatureEnabled) + + serverMock.EXPECT().GetLoggedInUser(gomock.Any()).Return(user, nil) + + _, err := client.UpdatePersonalAccessToken(context.Background(), connect.NewRequest(&v1.UpdatePersonalAccessTokenRequest{ + Token: &v1.PersonalAccessToken{ + Id: uuid.New().String(), + }, + })) + + require.Equal(t, connect.CodeUnimplemented, connect.CodeOf(err)) + }) +} + +func TestTokensService_DeletePersonalAccessToken(t *testing.T) { + user := newUser(&protocol.User{}) + + t.Run("permission denied when feature flag is disabled", func(t *testing.T) { + serverMock, client := setupTokensService(t, withTokenFeatureDisabled) + + serverMock.EXPECT().GetLoggedInUser(gomock.Any()).Return(user, nil) + + _, err := client.DeletePersonalAccessToken(context.Background(), connect.NewRequest(&v1.DeletePersonalAccessTokenRequest{ + Id: uuid.New().String(), + })) + + require.Error(t, err, "This feature is currently in beta. If you would like to be part of the beta, please contact us.") + require.Equal(t, connect.CodePermissionDenied, connect.CodeOf(err)) + }) + + t.Run("invalid argument when Token ID is empty", func(t *testing.T) { + _, client := setupTokensService(t, withTokenFeatureEnabled) + + _, err := client.DeletePersonalAccessToken(context.Background(), connect.NewRequest(&v1.DeletePersonalAccessTokenRequest{})) + + require.Equal(t, connect.CodeInvalidArgument, connect.CodeOf(err)) + }) + + t.Run("invalid argument when Token ID is not a valid UUID", func(t *testing.T) { + _, client := setupTokensService(t, withTokenFeatureEnabled) + + _, err := client.DeletePersonalAccessToken(context.Background(), connect.NewRequest(&v1.DeletePersonalAccessTokenRequest{ + Id: "foo-bar", + })) + + require.Equal(t, connect.CodeInvalidArgument, connect.CodeOf(err)) + }) + + t.Run("unimplemented when feature flag enabled", func(t *testing.T) { + serverMock, client := setupTokensService(t, withTokenFeatureEnabled) + + serverMock.EXPECT().GetLoggedInUser(gomock.Any()).Return(user, nil) + + _, err := client.DeletePersonalAccessToken(context.Background(), connect.NewRequest(&v1.DeletePersonalAccessTokenRequest{ + Id: uuid.New().String(), + })) + + require.Equal(t, connect.CodeUnimplemented, connect.CodeOf(err)) + }) +} + func setupTokensService(t *testing.T, expClient experiments.Client) (*protocol.MockAPIInterface, v1connect.TokensServiceClient) { t.Helper()