Skip to content

Commit 9789fae

Browse files
authored
Merge pull request #250 from somtochiama/add-user-login
Validate user ref when creating user repository
2 parents 8772525 + c8137f4 commit 9789fae

11 files changed

+153
-18
lines changed

gitea/client_repositories_user.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,19 @@ func (c *UserRepositoriesClient) listUserRepos(username string) ([]*gitea.Reposi
9595
return validateRepositoryObjects(apiObjs)
9696
}
9797

98+
// GetUserLogin returns the authenticated user
99+
func (c *UserRepositoriesClient) GetUserLogin(ctx context.Context) (gitprovider.IdentityRef, error) {
100+
// GET /user
101+
user, _, err := c.c.GetMyUserInfo()
102+
if err != nil {
103+
return nil, err
104+
}
105+
return gitprovider.UserRef{
106+
Domain: c.domain,
107+
UserLogin: user.UserName,
108+
}, nil
109+
}
110+
98111
// Create creates a repository for the given organization, with the data and options
99112
//
100113
// ErrAlreadyExists will be returned if the resource already exists.
@@ -108,6 +121,17 @@ func (c *UserRepositoriesClient) Create(ctx context.Context,
108121
return nil, err
109122
}
110123

124+
// extra validation to ensure we don't create a project when the wrong owner
125+
// is passed in
126+
idRef, err := c.GetUserLogin(ctx)
127+
if err != nil {
128+
return nil, fmt.Errorf("unable to get owner from API")
129+
}
130+
131+
if ref.GetIdentity() != idRef.GetIdentity() {
132+
return nil, gitprovider.NewErrIncorrectUser(ref.GetIdentity())
133+
}
134+
111135
apiObj, err := createRepository(ctx, c.c, ref, "", req, opts...)
112136
if err != nil {
113137
return nil, err

gitea/integration_repositories_user_test.go

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,13 @@ var _ = Describe("Gitea Provider", func() {
5858
Expect(*info.DefaultBranch).To(Equal(defaultBranch))
5959
}
6060

61+
It("should get the current user", func() {
62+
user, err := c.UserRepositories().GetUserLogin(ctx)
63+
Expect(err).ToNot(HaveOccurred())
64+
65+
Expect(user.GetIdentity()).To(Equal(giteaUser))
66+
})
67+
6168
It("should be possible to create a user repository", func() {
6269
// First, check what repositories are available
6370
repos, err := c.UserRepositories().List(ctx, newUserRef(giteaUser))
@@ -100,17 +107,15 @@ var _ = Describe("Gitea Provider", func() {
100107
Expect(getSpec.Equals(postSpec)).To(BeTrue())
101108
})
102109

103-
It("should return correct repo info when creating a repository with wrong UserLogin", func() {
110+
It("should fail when creating a repository with wrong UserLogin", func() {
104111
repoName := fmt.Sprintf("test-user-repo-creation-%03d", rand.Intn(1000))
105112
repoRef := newUserRepoRef(repoName)
106113
repoRef.UserLogin = "yadda-yadda-yada"
107114

108-
repo, err := c.UserRepositories().Create(ctx, repoRef, gitprovider.RepositoryInfo{})
115+
_, err := c.UserRepositories().Create(ctx, repoRef, gitprovider.RepositoryInfo{})
109116

110-
Expect(err).To(BeNil())
111-
Expect(
112-
repo.Repository().GetCloneURL(gitprovider.TransportTypeHTTPS)).
113-
To(Equal(fmt.Sprintf("%s/%s/%s.git", giteaBaseUrl, giteaUser, repoName)))
117+
expectedErr := gitprovider.NewErrIncorrectUser(repoRef.UserLogin)
118+
Expect(err).To(MatchError(expectedErr))
114119
})
115120

116121
It("should error at creation time if the repo already does exist", func() {

github/client_repositories_user.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,19 @@ type UserRepositoriesClient struct {
3232
*clientContext
3333
}
3434

35+
// GetUserLogin returns the current authenticated user.
36+
func (c *UserRepositoriesClient) GetUserLogin(ctx context.Context) (gitprovider.IdentityRef, error) {
37+
// GET /user
38+
user, err := c.c.GetUser(ctx)
39+
if err != nil {
40+
return nil, err
41+
}
42+
return gitprovider.UserRef{
43+
Domain: c.domain,
44+
UserLogin: user.GetLogin(),
45+
}, nil
46+
}
47+
3548
// Get returns the repository at the given path.
3649
//
3750
// ErrNotFound is returned if the resource does not exist.
@@ -88,6 +101,17 @@ func (c *UserRepositoriesClient) Create(ctx context.Context,
88101
return nil, err
89102
}
90103

104+
// extra validation to ensure we don't create a project when the wrong owner
105+
// is passed in
106+
idRef, err := c.GetUserLogin(ctx)
107+
if err != nil {
108+
return nil, fmt.Errorf("unable to get owner from API")
109+
}
110+
111+
if ref.GetIdentity() != idRef.GetIdentity() {
112+
return nil, gitprovider.NewErrIncorrectUser(ref.GetIdentity())
113+
}
114+
91115
apiObj, err := createRepository(ctx, c.c, ref, "", req, opts...)
92116
if err != nil {
93117
return nil, err

github/githubclient.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,9 @@ type githubClient interface {
6767
// DANGEROUS COMMAND: In order to use this, you must set destructiveActions to true.
6868
DeleteRepo(ctx context.Context, owner, repo string) error
6969

70+
// GetUser is a wrapper for "GET /user"
71+
GetUser(ctx context.Context) (*github.User, error)
72+
7073
// ListKeys is a wrapper for "GET /repos/{owner}/{repo}/keys".
7174
// This function handles pagination, HTTP error wrapping, and validates the server result.
7275
ListKeys(ctx context.Context, owner, repo string) ([]*github.Key, error)
@@ -297,6 +300,12 @@ func (c *githubClientImpl) ListKeys(ctx context.Context, owner, repo string) ([]
297300
return apiObjs, nil
298301
}
299302

303+
func (c *githubClientImpl) GetUser(ctx context.Context) (*github.User, error) {
304+
// GET /user
305+
user, _, err := c.c.Users.Get(ctx, "")
306+
return user, err
307+
}
308+
300309
func (c *githubClientImpl) ListCommitsPage(ctx context.Context, owner, repo, branch string, perPage int, page int) ([]*github.Commit, error) {
301310
apiObjs := make([]*github.Commit, 0)
302311
lcOpts := &github.CommitsListOptions{

github/integration_test.go

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,13 @@ var _ = Describe("GitHub Provider", func() {
202202
}
203203
}
204204

205+
It("should get the current user", func() {
206+
user, err := c.UserRepositories().GetUserLogin(ctx)
207+
Expect(err).ToNot(HaveOccurred())
208+
209+
Expect(user.GetIdentity()).To(Equal(testUser))
210+
})
211+
205212
It("should list the available organizations the user has access to", func() {
206213
// Get a list of all organizations the user is part of
207214
orgs, err := c.Organizations().List(ctx)
@@ -345,16 +352,14 @@ var _ = Describe("GitHub Provider", func() {
345352
Expect(getSpec.Equals(postSpec)).To(BeTrue())
346353
})
347354

348-
It("should return correct repo info when creating a repository with wrong UserLogin", func() {
355+
It("should fail when creating a repository with wrong UserLogin", func() {
349356
repoName := fmt.Sprintf("test-user-repo-creation-%03d", rand.Intn(1000))
350357
repoRef := newUserRepoRef("yadda-yadda-yada", repoName)
351358

352-
repo, err := c.UserRepositories().Create(ctx, repoRef, gitprovider.RepositoryInfo{})
359+
_, err := c.UserRepositories().Create(ctx, repoRef, gitprovider.RepositoryInfo{})
353360

354-
Expect(err).To(BeNil())
355-
Expect(
356-
repo.Repository().GetCloneURL(gitprovider.TransportTypeHTTPS)).
357-
To(Equal(fmt.Sprintf("https://%s/%s/%s.git", githubDomain, testUser, repoName)))
361+
expectedErr := gitprovider.NewErrIncorrectUser(repoRef.GetIdentity())
362+
Expect(err).To(MatchError(expectedErr))
358363
})
359364

360365
It("should error at creation time if the repo already does exist", func() {

gitlab/client_repositories_user.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,19 @@ type UserRepositoriesClient struct {
3232
*clientContext
3333
}
3434

35+
// GetUserLogin returns the current authenticated user.
36+
func (c *UserRepositoriesClient) GetUserLogin(ctx context.Context) (gitprovider.IdentityRef, error) {
37+
// GET /user
38+
user, err := c.c.GetUser(ctx)
39+
if err != nil {
40+
return nil, err
41+
}
42+
return &gitprovider.UserRef{
43+
Domain: c.domain,
44+
UserLogin: user.Username,
45+
}, nil
46+
}
47+
3548
// Get returns the repository at the given path.
3649
//
3750
// ErrNotFound is returned if the resource does not exist.
@@ -89,6 +102,17 @@ func (c *UserRepositoriesClient) Create(ctx context.Context,
89102
return nil, err
90103
}
91104

105+
// extra validation to ensure we don't create a project when the wrong owner
106+
// is passed in
107+
idRef, err := c.GetUserLogin(ctx)
108+
if err != nil {
109+
return nil, fmt.Errorf("unable to get owner from API")
110+
}
111+
112+
if ref.GetIdentity() != idRef.GetIdentity() {
113+
return nil, gitprovider.NewErrIncorrectUser(ref.GetIdentity())
114+
}
115+
92116
apiObj, err := createProject(ctx, c.c, ref, "", req, opts...)
93117
if err != nil {
94118
return nil, err

gitlab/gitlabclient.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,9 @@ type gitlabClient interface {
7676
// DANGEROUS COMMAND: In order to use this, you must set destructiveActions to true.
7777
DeleteProject(ctx context.Context, projectName string) error
7878

79+
// GetUser is a wrapper for "GET /user"
80+
GetUser(ctx context.Context) (*gitlab.User, error)
81+
7982
// Deploy key methods
8083

8184
// ListKeys is a wrapper for "GET /projects/{project}/deploy_keys".
@@ -341,6 +344,12 @@ func (c *gitlabClientImpl) DeleteProject(ctx context.Context, projectName string
341344
return err
342345
}
343346

347+
func (c *gitlabClientImpl) GetUser(ctx context.Context) (*gitlab.User, error) {
348+
// GET /user
349+
proj, _, err := c.c.Users.CurrentUser(gitlab.WithContext(ctx))
350+
return proj, err
351+
}
352+
344353
func (c *gitlabClientImpl) ListKeys(projectName string) ([]*gitlab.ProjectDeployKey, error) {
345354
apiObjs := []*gitlab.ProjectDeployKey{}
346355
opts := &gitlab.ListProjectDeployKeysOptions{}

gitlab/integration_test.go

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -318,6 +318,13 @@ var _ = Describe("GitLab Provider", func() {
318318
}
319319
}
320320

321+
It("should get the current user", func() {
322+
user, err := c.UserRepositories().GetUserLogin(ctx)
323+
Expect(err).ToNot(HaveOccurred())
324+
325+
Expect(user.GetIdentity()).To(Equal(testUserName))
326+
})
327+
321328
It("should list the available organizations the user has access to", func() {
322329
// Get a list of all organizations the user is part of
323330
orgs, err := c.Organizations().List(ctx)
@@ -796,16 +803,14 @@ var _ = Describe("GitLab Provider", func() {
796803
Expect(errors.Is(err, gitprovider.ErrAlreadyExists)).To(BeTrue())
797804
})
798805

799-
It("should return correct repo info when creating a repository with wrong UserLogin", func() {
806+
It("should fail info when creating a repository with wrong UserLogin", func() {
800807
repoName := fmt.Sprintf("test-user-repo-creation-%03d", rand.Intn(1000))
801808
repoRef := newUserRepoRef(testBaseUrl, "yadda-yadda-yada", repoName)
802809

803-
repo, err := c.UserRepositories().Create(ctx, repoRef, gitprovider.RepositoryInfo{})
810+
_, err := c.UserRepositories().Create(ctx, repoRef, gitprovider.RepositoryInfo{})
804811

805-
Expect(err).To(BeNil())
806-
Expect(
807-
repo.Repository().GetCloneURL(gitprovider.TransportTypeHTTPS)).
808-
To(Equal(fmt.Sprintf("%s/%s/%s.git", testBaseUrl, testUserName, repoName)))
812+
expectedErr := gitprovider.NewErrIncorrectUser(repoRef.GetIdentity())
813+
Expect(err).To(MatchError(expectedErr))
809814
})
810815

811816
It("should update if the user repo already exists when reconciling", func() {

gitprovider/client.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,9 @@ type UserRepositoriesClient interface {
123123
// ErrAlreadyExists will be returned if the resource already exists.
124124
Create(ctx context.Context, r UserRepositoryRef, req RepositoryInfo, opts ...RepositoryCreateOption) (UserRepository, error)
125125

126+
// GetUserLogin returns the current authenticated user.
127+
GetUserLogin(ctx context.Context) (IdentityRef, error)
128+
126129
// Reconcile makes sure the given desired state (req) becomes the actual state in the backing Git provider.
127130
//
128131
// If req doesn't exist under the hood, it is created (actionTaken == true).

gitprovider/errors.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ package gitprovider
1818

1919
import (
2020
"errors"
21+
"fmt"
2122
"net/http"
2223
"time"
2324
)
@@ -131,3 +132,20 @@ type InvalidCredentialsError struct {
131132
// InvalidCredentialsError extends HTTPError.
132133
HTTPError `json:",inline"`
133134
}
135+
136+
// ErrIncorrectUser describes that the user provided was incorrect
137+
//
138+
// It is returned by `UserRepositories().Create` when an incorrect UserLogin is passed in
139+
type ErrIncorrectUser struct {
140+
user string
141+
}
142+
143+
// Error implements the error interface.
144+
func NewErrIncorrectUser(user string) *ErrIncorrectUser {
145+
return &ErrIncorrectUser{user}
146+
}
147+
148+
// Error implements the error interface.
149+
func (e *ErrIncorrectUser) Error() string {
150+
return fmt.Sprintf("incorrect user '%s' provided", e.user)
151+
}

0 commit comments

Comments
 (0)