Skip to content

Commit

Permalink
allow admin to read private repos
Browse files Browse the repository at this point in the history
  • Loading branch information
Lei Da authored and Rader committed Dec 10, 2024
1 parent 27431f7 commit f84307f
Show file tree
Hide file tree
Showing 2 changed files with 222 additions and 1 deletion.
10 changes: 9 additions & 1 deletion component/repo.go
Original file line number Diff line number Diff line change
Expand Up @@ -1493,7 +1493,15 @@ func (c *repoComponentImpl) GetUserRepoPermission(ctx context.Context, userName
func (c *repoComponentImpl) CheckCurrentUserPermission(ctx context.Context, userName string, namespace string, role membership.Role) (bool, error) {
ns, err := c.namespaceStore.FindByPath(ctx, namespace)
if err != nil {
return false, err
return false, fmt.Errorf("fail to find namespace '%s', err:%w", namespace, err)
}

u, err := c.userStore.FindByUsername(ctx, userName)
if err != nil {
return false, fmt.Errorf("fail to find user '%s', err:%w", userName, err)
}
if u.CanAdmin() {
return true, nil
}

if ns.NamespaceType == "user" {
Expand Down
213 changes: 213 additions & 0 deletions component/repo_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@ import (
"testing"

"github.com/alibabacloud-go/tea/tea"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"
"opencsg.com/csghub-server/builder/git/gitserver"
"opencsg.com/csghub-server/builder/git/membership"
"opencsg.com/csghub-server/builder/store/database"
"opencsg.com/csghub-server/common/types"
)
Expand Down Expand Up @@ -254,3 +256,214 @@ func TestRepoComponent_DeleteRepo(t *testing.T) {

// })
// }

// func TestRepoComponent_Tree(t *testing.T) {
// {
// t.Run("can read self-owned", func(t *testing.T) {
// ctx := context.TODO()
// repoComp := initializeTestRepoComponent(ctx, t)

// user := database.User{}
// user.Username = "user_name"
// repoComp.mocks.stores.UserMock().EXPECT().FindByUsername(mock.Anything, user.Username).Return(user, nil)

// ns := database.Namespace{}
// ns.NamespaceType = "user"
// ns.Path = "user_name"
// repoComp.mocks.stores.NamespaceMock().EXPECT().FindByPath(mock.Anything, ns.Path).Return(ns, nil)

// repo := &database.Repository{
// Private: true,
// User: user,
// Path: fmt.Sprintf("%s/%s", ns.Path, "repo_name"),
// Source: types.LocalSource,
// }
// repoComp.mocks.stores.RepoMock().EXPECT().FindByPath(mock.Anything, types.ModelRepo, ns.Path, repo.Name).Return(repo, nil)

// tree := []*types.File{}
// repoComp.mocks.gitServer.EXPECT().GetRepoFileTree(mock.Anything, mock.Anything).Return(tree, nil)

// actualTree, err := repoComp.Tree(context.Background(), &types.GetFileReq{
// Namespace: ns.Path,
// Name: repo.Name,
// Path: "",
// RepoType: types.ModelRepo,
// CurrentUser: user.Username,
// })
// require.Nil(t, err)
// require.Equal(t, tree, actualTree)

// })

// t.Run("forbidden anoymous user to read private repo", func(t *testing.T) {
// ctx := context.TODO()
// repoComp := initializeTestRepoComponent(ctx, t)

// repoComp.mocks.stores.RepoMock().EXPECT().FindByPath(mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&database.Repository{
// // private repo don't allow read from other user
// Private: true,
// }, nil)

// actualTree, err := repoComp.Tree(context.Background(), &types.GetFileReq{})
// require.Nil(t, actualTree)
// require.Equal(t, err, ErrForbidden)

// })
// }

// }
func TestRepoComponent_checkCurrentUserPermission(t *testing.T) {

t.Run("can read self-owned", func(t *testing.T) {
repoComp := initializeTestRepoComponent(context.TODO(), t)
ns := database.Namespace{}
ns.NamespaceType = "user"
ns.Path = "user_name"
repoComp.mocks.stores.NamespaceMock().EXPECT().FindByPath(mock.Anything, ns.Path).Return(ns, nil)

user := database.User{}
user.Username = "user_name"
repoComp.mocks.stores.UserMock().EXPECT().FindByUsername(mock.Anything, user.Username).Return(user, nil)

yes, err := repoComp.CheckCurrentUserPermission(context.Background(), user.Username, ns.Path, membership.RoleRead)
require.True(t, yes)
require.NoError(t, err)

yes, err = repoComp.CheckCurrentUserPermission(context.Background(), user.Username, ns.Path, membership.RoleWrite)
require.True(t, yes)
require.NoError(t, err)

yes, err = repoComp.CheckCurrentUserPermission(context.Background(), user.Username, ns.Path, membership.RoleAdmin)
require.True(t, yes)
require.NoError(t, err)
})

t.Run("can not read other's", func(t *testing.T) {
repoComp := initializeTestRepoComponent(context.TODO(), t)
ns := database.Namespace{}
ns.NamespaceType = "user"
ns.Path = "user_name_other"
repoComp.mocks.stores.NamespaceMock().EXPECT().FindByPath(mock.Anything, ns.Path).Return(ns, nil)

user := database.User{}
user.Username = "user_name"
repoComp.mocks.stores.UserMock().EXPECT().FindByUsername(mock.Anything, user.Username).Return(user, nil)

yes, err := repoComp.CheckCurrentUserPermission(context.Background(), user.Username, ns.Path, membership.RoleRead)
require.False(t, yes)
require.NoError(t, err)

yes, err = repoComp.CheckCurrentUserPermission(context.Background(), user.Username, ns.Path, membership.RoleWrite)
require.False(t, yes)
require.NoError(t, err)

yes, err = repoComp.CheckCurrentUserPermission(context.Background(), user.Username, ns.Path, membership.RoleAdmin)
require.False(t, yes)
require.NoError(t, err)
})

t.Run("can not read org's if not org member", func(t *testing.T) {
repoComp := initializeTestRepoComponent(context.TODO(), t)
ns := database.Namespace{}
ns.NamespaceType = "organization"
ns.Path = "org_name"
repoComp.mocks.stores.NamespaceMock().EXPECT().FindByPath(mock.Anything, ns.Path).Return(ns, nil)

user := database.User{}
user.Username = "user_name"
repoComp.mocks.stores.UserMock().EXPECT().FindByUsername(mock.Anything, user.Username).Return(user, nil)

//user not belongs to org
repoComp.mocks.userSvcClient.EXPECT().GetMemberRole(mock.Anything, ns.Path, user.Username).Return(membership.RoleUnknown, nil)

yes, err := repoComp.CheckCurrentUserPermission(context.Background(), user.Username, ns.Path, membership.RoleRead)
require.False(t, yes)
require.NoError(t, err)

yes, err = repoComp.CheckCurrentUserPermission(context.Background(), user.Username, ns.Path, membership.RoleWrite)
require.False(t, yes)
require.NoError(t, err)

yes, err = repoComp.CheckCurrentUserPermission(context.Background(), user.Username, ns.Path, membership.RoleAdmin)
require.False(t, yes)
require.NoError(t, err)
})

t.Run("can read org's as org member", func(t *testing.T) {
repoComp := initializeTestRepoComponent(context.TODO(), t)
ns := database.Namespace{}
ns.NamespaceType = "organization"
ns.Path = "org_name"
repoComp.mocks.stores.NamespaceMock().EXPECT().FindByPath(mock.Anything, ns.Path).Return(ns, nil)

user := database.User{}
user.Username = "user_name"
repoComp.mocks.stores.UserMock().EXPECT().FindByUsername(mock.Anything, user.Username).Return(user, nil)

//user is read-only member of the org
repoComp.mocks.userSvcClient.EXPECT().GetMemberRole(mock.Anything, ns.Path, user.Username).Return(membership.RoleRead, nil)

//can read
yes, err := repoComp.CheckCurrentUserPermission(context.Background(), user.Username, ns.Path, membership.RoleRead)
require.True(t, yes)
require.NoError(t, err)
//can't write
yes, err = repoComp.CheckCurrentUserPermission(context.Background(), user.Username, ns.Path, membership.RoleWrite)
require.False(t, yes)
require.NoError(t, err)
//can't admin
yes, err = repoComp.CheckCurrentUserPermission(context.Background(), user.Username, ns.Path, membership.RoleAdmin)
require.False(t, yes)
require.NoError(t, err)
})

t.Run("admin read org's", func(t *testing.T) {
repoComp := initializeTestRepoComponent(context.TODO(), t)
ns := database.Namespace{}
ns.NamespaceType = "organization"
ns.Path = "org_name"
repoComp.mocks.stores.NamespaceMock().EXPECT().FindByPath(mock.Anything, ns.Path).Return(ns, nil)

user := database.User{}
user.Username = "user_name_admin"
user.RoleMask = "admin"
repoComp.mocks.stores.UserMock().EXPECT().FindByUsername(mock.Anything, user.Username).Return(user, nil)

yes, err := repoComp.CheckCurrentUserPermission(context.Background(), user.Username, ns.Path, membership.RoleRead)
require.True(t, yes)
require.NoError(t, err)

yes, err = repoComp.CheckCurrentUserPermission(context.Background(), user.Username, ns.Path, membership.RoleWrite)
require.True(t, yes)
require.NoError(t, err)

yes, err = repoComp.CheckCurrentUserPermission(context.Background(), user.Username, ns.Path, membership.RoleAdmin)
require.True(t, yes)
require.NoError(t, err)
})

t.Run("admin read other's", func(t *testing.T) {
repoComp := initializeTestRepoComponent(context.TODO(), t)
ns := database.Namespace{}
ns.NamespaceType = "user"
ns.Path = "user_name"
repoComp.mocks.stores.NamespaceMock().EXPECT().FindByPath(mock.Anything, ns.Path).Return(ns, nil)

user := database.User{}
user.Username = "user_name_admin"
user.RoleMask = "admin"
repoComp.mocks.stores.UserMock().EXPECT().FindByUsername(mock.Anything, user.Username).Return(user, nil)

yes, err := repoComp.CheckCurrentUserPermission(context.Background(), user.Username, ns.Path, membership.RoleRead)
require.True(t, yes)
require.NoError(t, err)

yes, err = repoComp.CheckCurrentUserPermission(context.Background(), user.Username, ns.Path, membership.RoleWrite)
require.True(t, yes)
require.NoError(t, err)

yes, err = repoComp.CheckCurrentUserPermission(context.Background(), user.Username, ns.Path, membership.RoleAdmin)
require.True(t, yes)
require.NoError(t, err)
})
}

0 comments on commit f84307f

Please sign in to comment.