Skip to content
This repository was archived by the owner on May 30, 2024. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions internal/server/api/v1/repos/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ type (

ListReposOfUser(ctx context.Context, u *ent.User, q, namespace, name string, sorted bool, page, perPage int) ([]*ent.Repo, error)
FindRepoOfUserByID(ctx context.Context, u *ent.User, id string) (*ent.Repo, error)
FindRepoOfUserByNamespaceName(ctx context.Context, u *ent.User, namespace, name string) (*ent.Repo, error)
UpdateRepo(ctx context.Context, r *ent.Repo) (*ent.Repo, error)
ActivateRepo(ctx context.Context, u *ent.User, r *ent.Repo, c *vo.WebhookConfig) (*ent.Repo, error)
DeactivateRepo(ctx context.Context, u *ent.User, r *ent.Repo) (*ent.Repo, error)
Expand Down
43 changes: 23 additions & 20 deletions internal/server/api/v1/repos/middleware.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,30 +33,31 @@ func (rm *RepoMiddleware) RepoReadPerm() gin.HandlerFunc {
ctx := c.Request.Context()

var (
id = c.Param("id")
namespace = c.Param("namespace")
name = c.Param("name")
)

v, _ := c.Get(gb.KeyUser)
u := v.(*ent.User)

r, err := rm.i.FindRepoOfUserByID(ctx, u, id)
r, err := rm.i.FindRepoOfUserByNamespaceName(ctx, u, namespace, name)
if ent.IsNotFound(err) {
rm.log.Warn("The repository is not found.", zap.String("repo_id", id), zap.Error(err))
rm.log.Warn("The repository is not found.", zap.String("repo", namespace+"/"+name), zap.Error(err))
gb.AbortWithErrorResponse(c, http.StatusNotFound, "The repository is not found.")
return
} else if err != nil {
rm.log.Error("It has failed to get the repository.", zap.String("repo_id", id), zap.Error(err))
rm.log.Error("It has failed to get the repository.", zap.String("repo", namespace+"/"+name), zap.Error(err))
gb.AbortWithErrorResponse(c, http.StatusInternalServerError, "It has failed to get the repository.")
return
}

_, err = rm.i.FindPermOfRepo(ctx, r, u)
if ent.IsNotFound(err) {
rm.log.Warn("It is denied to access the repository.", zap.String("repo_id", id), zap.Error(err))
rm.log.Warn("It is denied to access the repository.", zap.String("repo", namespace+"/"+name), zap.Error(err))
gb.AbortWithErrorResponse(c, http.StatusForbidden, "It is denied to access the repository.")
return
} else if err != nil {
rm.log.Error("It has failed to get the permission.", zap.String("repoID", id), zap.Error(err))
rm.log.Error("It has failed to get the permission.", zap.String("repo", namespace+"/"+name), zap.Error(err))
gb.AbortWithErrorResponse(c, http.StatusInternalServerError, "It has failed to get the permission.")
return
}
Expand All @@ -70,36 +71,37 @@ func (rm *RepoMiddleware) RepoWritePerm() gin.HandlerFunc {
ctx := c.Request.Context()

var (
id = c.Param("id")
namespace = c.Param("namespace")
name = c.Param("name")
)

v, _ := c.Get(gb.KeyUser)
u := v.(*ent.User)

r, err := rm.i.FindRepoOfUserByID(ctx, u, id)
r, err := rm.i.FindRepoOfUserByNamespaceName(ctx, u, namespace, name)
if ent.IsNotFound(err) {
rm.log.Warn("The repository is not found.", zap.String("repo_id", id), zap.Error(err))
rm.log.Warn("The repository is not found.", zap.String("repo", namespace+"/"+name), zap.Error(err))
gb.AbortWithErrorResponse(c, http.StatusNotFound, "The repository is not found.")
return
} else if err != nil {
rm.log.Error("It has failed to get the repository.", zap.String("repo_id", id), zap.Error(err))
rm.log.Error("It has failed to get the repository.", zap.String("repo", namespace+"/"+name), zap.Error(err))
gb.AbortWithErrorResponse(c, http.StatusInternalServerError, "It has failed to get the repository.")
return
}

p, err := rm.i.FindPermOfRepo(ctx, r, u)
if ent.IsNotFound(err) {
rm.log.Warn("It is denied to access the repository.", zap.String("repo_id", id), zap.Error(err))
rm.log.Warn("It is denied to access the repository.", zap.String("repo", namespace+"/"+name), zap.Error(err))
gb.AbortWithErrorResponse(c, http.StatusForbidden, "It is denied to access the repository.")
return
} else if err != nil {
rm.log.Error("It has failed to get the repository.", zap.String("repo_id", id), zap.Error(err))
rm.log.Error("It has failed to get the repository.", zap.String("repo", namespace+"/"+name), zap.Error(err))
gb.AbortWithErrorResponse(c, http.StatusInternalServerError, "It has failed to get the permission.")
return
}

if !(p.RepoPerm == perm.RepoPermWrite || p.RepoPerm == perm.RepoPermAdmin) {
rm.log.Warn("The access is forbidden. Only write permission can access.", zap.String("repo_id", id))
rm.log.Warn("The access is forbidden. Only write permission can access.", zap.String("repo", namespace+"/"+name))
gb.AbortWithErrorResponse(c, http.StatusForbidden, "Only write permission can access.")
return
}
Expand All @@ -113,36 +115,37 @@ func (rm *RepoMiddleware) RepoAdminPerm() gin.HandlerFunc {
ctx := c.Request.Context()

var (
id = c.Param("id")
namespace = c.Param("namespace")
name = c.Param("name")
)

v, _ := c.Get(gb.KeyUser)
u := v.(*ent.User)

r, err := rm.i.FindRepoOfUserByID(ctx, u, id)
r, err := rm.i.FindRepoOfUserByNamespaceName(ctx, u, namespace, name)
if ent.IsNotFound(err) {
rm.log.Warn("The repository is not found.", zap.String("repo_id", id), zap.Error(err))
rm.log.Warn("The repository is not found.", zap.String("repo", namespace+"/"+name), zap.Error(err))
gb.AbortWithErrorResponse(c, http.StatusNotFound, "The repository is not found.")
return
} else if err != nil {
rm.log.Error("It has failed to get the repository.", zap.String("repo_id", id), zap.Error(err))
rm.log.Error("It has failed to get the repository.", zap.String("repo", namespace+"/"+name), zap.Error(err))
gb.AbortWithErrorResponse(c, http.StatusInternalServerError, "It has failed to get the repository.")
return
}

p, err := rm.i.FindPermOfRepo(ctx, r, u)
if ent.IsNotFound(err) {
rm.log.Warn("It is denied to access the repo.", zap.String("repo_id", id), zap.Error(err))
rm.log.Warn("It is denied to access the repo.", zap.String("repo", namespace+"/"+name), zap.Error(err))
gb.AbortWithErrorResponse(c, http.StatusForbidden, "It is denied to access the repo.")
return
} else if err != nil {
rm.log.Error("It has failed to get the permission.", zap.String("repo_id", id), zap.Error(err))
rm.log.Error("It has failed to get the permission.", zap.String("repo", namespace+"/"+name), zap.Error(err))
gb.AbortWithErrorResponse(c, http.StatusInternalServerError, "It has failed to get the permission.")
return
}

if p.RepoPerm != perm.RepoPermAdmin {
rm.log.Warn("The access is forbidden. Only admin permission can access.", zap.String("repo_id", id))
rm.log.Warn("The access is forbidden. Only admin permission can access.", zap.String("repo", namespace+"/"+name))
gb.AbortWithErrorResponse(c, http.StatusForbidden, "Only admin permission can access.")
return
}
Expand Down
57 changes: 30 additions & 27 deletions internal/server/api/v1/repos/middleware_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,11 @@ func TestRepoMiddleware_RepoWritePerm(t *testing.T) {

t.Run("Return 403 error when the permission is read.", func(t *testing.T) {
input := struct {
RepoID string
namespace string
name string
}{
RepoID: "1",
namespace: "octocat",
name: "hello-world",
}

ctrl := gomock.NewController(t)
Expand All @@ -30,17 +32,16 @@ func TestRepoMiddleware_RepoWritePerm(t *testing.T) {
t.Logf("It finds the repository.")
m.
EXPECT().
FindRepoOfUserByID(ctx, gomock.AssignableToTypeOf(&ent.User{}), gomock.Eq(input.RepoID)).
FindRepoOfUserByNamespaceName(ctx, gomock.AssignableToTypeOf(&ent.User{}), input.namespace, input.name).
Return(&ent.Repo{
ID: input.RepoID,
Namespace: input.namespace,
Name: input.name,
}, nil)

t.Logf("It returns the read permission.")
m.
EXPECT().
FindPermOfRepo(ctx, gomock.Eq(&ent.Repo{
ID: input.RepoID,
}), gomock.AssignableToTypeOf(&ent.User{})).
FindPermOfRepo(ctx, gomock.AssignableToTypeOf(&ent.Repo{}), gomock.AssignableToTypeOf(&ent.User{})).
Return(&ent.Perm{
RepoPerm: perm.RepoPermRead,
}, nil)
Expand All @@ -49,14 +50,14 @@ func TestRepoMiddleware_RepoWritePerm(t *testing.T) {
router := gin.New()

rm := NewRepoMiddleware(m)
router.PATCH("/repos/:id", func(c *gin.Context) {
router.PATCH("/repos/:namespace/:name", func(c *gin.Context) {
// Mocking middlewares to return a user and a repository.
c.Set(global.KeyUser, &ent.User{})
}, rm.RepoWritePerm(), func(c *gin.Context) {
c.Status(http.StatusOK)
})

req, _ := http.NewRequest("PATCH", fmt.Sprintf("/repos/%s", input.RepoID), nil)
req, _ := http.NewRequest("PATCH", fmt.Sprintf("/repos/%s/%s", input.namespace, input.name), nil)

w := httptest.NewRecorder()
router.ServeHTTP(w, req)
Expand All @@ -68,9 +69,11 @@ func TestRepoMiddleware_RepoWritePerm(t *testing.T) {

t.Run("Return 200 when the permission is write.", func(t *testing.T) {
input := struct {
RepoID string
namespace string
name string
}{
RepoID: "1",
namespace: "octocat",
name: "hello-world",
}

ctrl := gomock.NewController(t)
Expand All @@ -79,17 +82,16 @@ func TestRepoMiddleware_RepoWritePerm(t *testing.T) {
t.Logf("It finds the repository.")
m.
EXPECT().
FindRepoOfUserByID(ctx, gomock.AssignableToTypeOf(&ent.User{}), gomock.Eq(input.RepoID)).
FindRepoOfUserByNamespaceName(ctx, gomock.AssignableToTypeOf(&ent.User{}), input.namespace, input.name).
Return(&ent.Repo{
ID: input.RepoID,
Namespace: input.namespace,
Name: input.name,
}, nil)

t.Logf("It returns the read permission.")
m.
EXPECT().
FindPermOfRepo(ctx, gomock.Eq(&ent.Repo{
ID: input.RepoID,
}), gomock.AssignableToTypeOf(&ent.User{})).
FindPermOfRepo(ctx, gomock.AssignableToTypeOf(&ent.Repo{}), gomock.AssignableToTypeOf(&ent.User{})).
Return(&ent.Perm{
RepoPerm: perm.RepoPermWrite,
}, nil)
Expand All @@ -98,14 +100,14 @@ func TestRepoMiddleware_RepoWritePerm(t *testing.T) {
router := gin.New()

rm := NewRepoMiddleware(m)
router.PATCH("/repos/:id", func(c *gin.Context) {
router.PATCH("/repos/:namespace/:name", func(c *gin.Context) {
// Mocking middlewares to return a user and a repository.
c.Set(global.KeyUser, &ent.User{})
}, rm.RepoWritePerm(), func(c *gin.Context) {
c.Status(http.StatusOK)
})

req, _ := http.NewRequest("PATCH", fmt.Sprintf("/repos/%s", input.RepoID), nil)
req, _ := http.NewRequest("PATCH", fmt.Sprintf("/repos/%s/%s", input.namespace, input.name), nil)

w := httptest.NewRecorder()
router.ServeHTTP(w, req)
Expand All @@ -121,9 +123,11 @@ func TestRepoMiddleware_RepoAdminPerm(t *testing.T) {

t.Run("Return 200 when the permission is admin.", func(t *testing.T) {
input := struct {
RepoID string
namespace string
name string
}{
RepoID: "1",
namespace: "octocat",
name: "hello-world",
}

ctrl := gomock.NewController(t)
Expand All @@ -132,17 +136,16 @@ func TestRepoMiddleware_RepoAdminPerm(t *testing.T) {
t.Logf("It finds the repository.")
m.
EXPECT().
FindRepoOfUserByID(ctx, gomock.AssignableToTypeOf(&ent.User{}), gomock.Eq(input.RepoID)).
FindRepoOfUserByNamespaceName(ctx, gomock.AssignableToTypeOf(&ent.User{}), input.namespace, input.name).
Return(&ent.Repo{
ID: input.RepoID,
Namespace: input.namespace,
Name: input.name,
}, nil)

t.Logf("It returns the read permission.")
m.
EXPECT().
FindPermOfRepo(ctx, gomock.Eq(&ent.Repo{
ID: input.RepoID,
}), gomock.AssignableToTypeOf(&ent.User{})).
FindPermOfRepo(ctx, gomock.AssignableToTypeOf(&ent.Repo{}), gomock.AssignableToTypeOf(&ent.User{})).
Return(&ent.Perm{
RepoPerm: perm.RepoPermAdmin,
}, nil)
Expand All @@ -151,14 +154,14 @@ func TestRepoMiddleware_RepoAdminPerm(t *testing.T) {
router := gin.New()

rm := NewRepoMiddleware(m)
router.PATCH("/repos/:id", func(c *gin.Context) {
router.PATCH("/repos/:namespace/:name", func(c *gin.Context) {
// Mocking middlewares to return a user and a repository.
c.Set(global.KeyUser, &ent.User{})
}, rm.RepoWritePerm(), func(c *gin.Context) {
c.Status(http.StatusOK)
})

req, _ := http.NewRequest("PATCH", fmt.Sprintf("/repos/%s", input.RepoID), nil)
req, _ := http.NewRequest("PATCH", fmt.Sprintf("/repos/%s/%s", input.namespace, input.name), nil)

w := httptest.NewRecorder()
router.ServeHTTP(w, req)
Expand Down
30 changes: 15 additions & 15 deletions internal/server/api/v1/repos/mock/interactor.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

52 changes: 26 additions & 26 deletions internal/server/router.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,32 +123,32 @@ func NewRouter(c *RouterConfig) *gin.Engine {
c.Interactor,
)
repov1.GET("", r.ListRepos)
repov1.GET("/:id", rm.RepoReadPerm(), r.GetRepo)
repov1.PATCH("/:id", rm.RepoAdminPerm(), r.UpdateRepo)
repov1.GET("/:id/commits", rm.RepoReadPerm(), r.ListCommits)
repov1.GET("/:id/commits/:sha", rm.RepoReadPerm(), r.GetCommit)
repov1.GET("/:id/commits/:sha/statuses", rm.RepoReadPerm(), r.ListStatuses)
repov1.GET("/:id/branches", rm.RepoReadPerm(), r.ListBranches)
repov1.GET("/:id/branches/:branch", rm.RepoReadPerm(), r.GetBranch)
repov1.GET("/:id/tags", rm.RepoReadPerm(), r.ListTags)
repov1.GET("/:id/tags/:tag", rm.RepoReadPerm(), r.GetTag)
repov1.GET("/:id/deployments", rm.RepoReadPerm(), r.ListDeployments)
repov1.POST("/:id/deployments", rm.RepoWritePerm(), r.CreateDeployment)
repov1.GET("/:id/deployments/:number", rm.RepoReadPerm(), r.GetDeploymentByNumber)
repov1.PATCH("/:id/deployments/:number", rm.RepoWritePerm(), r.UpdateDeployment)
repov1.GET("/:id/deployments/:number/changes", rm.RepoReadPerm(), r.ListDeploymentChanges)
repov1.POST("/:id/deployments/:number/rollback", rm.RepoWritePerm(), r.RollbackDeployment)
repov1.GET("/:id/deployments/:number/approvals", rm.RepoReadPerm(), r.ListApprovals)
repov1.POST("/:id/deployments/:number/approvals", rm.RepoReadPerm(), r.CreateApproval)
repov1.GET("/:id/deployments/:number/approval", rm.RepoReadPerm(), r.GetMyApproval)
repov1.PATCH("/:id/deployments/:number/approval", rm.RepoReadPerm(), r.UpdateApproval)
repov1.GET("/:id/approvals/:aid", rm.RepoReadPerm(), r.GetApproval)
repov1.DELETE("/:id/approvals/:aid", rm.RepoReadPerm(), r.DeleteApproval)
repov1.GET("/:id/locks", rm.RepoReadPerm(), r.ListLocks)
repov1.POST("/:id/locks", rm.RepoWritePerm(), r.CreateLock)
repov1.DELETE("/:id/locks/:lockID", rm.RepoWritePerm(), r.DeleteLock)
repov1.GET("/:id/perms", rm.RepoReadPerm(), r.ListPerms)
repov1.GET("/:id/config", rm.RepoReadPerm(), r.GetConfig)
repov1.GET("/:namespace/:name", rm.RepoReadPerm(), r.GetRepo)
repov1.PATCH("/:namespace/:name", rm.RepoAdminPerm(), r.UpdateRepo)
repov1.GET("/:namespace/:name/commits", rm.RepoReadPerm(), r.ListCommits)
repov1.GET("/:namespace/:name/commits/:sha", rm.RepoReadPerm(), r.GetCommit)
repov1.GET("/:namespace/:name/commits/:sha/statuses", rm.RepoReadPerm(), r.ListStatuses)
repov1.GET("/:namespace/:name/branches", rm.RepoReadPerm(), r.ListBranches)
repov1.GET("/:namespace/:name/branches/:branch", rm.RepoReadPerm(), r.GetBranch)
repov1.GET("/:namespace/:name/tags", rm.RepoReadPerm(), r.ListTags)
repov1.GET("/:namespace/:name/tags/:tag", rm.RepoReadPerm(), r.GetTag)
repov1.GET("/:namespace/:name/deployments", rm.RepoReadPerm(), r.ListDeployments)
repov1.POST("/:namespace/:name/deployments", rm.RepoWritePerm(), r.CreateDeployment)
repov1.GET("/:namespace/:name/deployments/:number", rm.RepoReadPerm(), r.GetDeploymentByNumber)
repov1.PATCH("/:namespace/:name/deployments/:number", rm.RepoWritePerm(), r.UpdateDeployment)
repov1.GET("/:namespace/:name/deployments/:number/changes", rm.RepoReadPerm(), r.ListDeploymentChanges)
repov1.POST("/:namespace/:name/deployments/:number/rollback", rm.RepoWritePerm(), r.RollbackDeployment)
repov1.GET("/:namespace/:name/deployments/:number/approvals", rm.RepoReadPerm(), r.ListApprovals)
repov1.POST("/:namespace/:name/deployments/:number/approvals", rm.RepoReadPerm(), r.CreateApproval)
repov1.GET("/:namespace/:name/deployments/:number/approval", rm.RepoReadPerm(), r.GetMyApproval)
repov1.PATCH("/:namespace/:name/deployments/:number/approval", rm.RepoReadPerm(), r.UpdateApproval)
repov1.GET("/:namespace/:name/approvals/:aid", rm.RepoReadPerm(), r.GetApproval)
repov1.DELETE("/:namespace/:name/approvals/:aid", rm.RepoReadPerm(), r.DeleteApproval)
repov1.GET("/:namespace/:name/locks", rm.RepoReadPerm(), r.ListLocks)
repov1.POST("/:namespace/:name/locks", rm.RepoWritePerm(), r.CreateLock)
repov1.DELETE("/:namespace/:name/locks/:lockID", rm.RepoWritePerm(), r.DeleteLock)
repov1.GET("/:namespace/:name/perms", rm.RepoReadPerm(), r.ListPerms)
repov1.GET("/:namespace/:name/config", rm.RepoReadPerm(), r.GetConfig)
}

usersv1 := v1.Group("/users")
Expand Down
Loading