Skip to content

Commit 36300be

Browse files
Gustedearl-warren
authored andcommitted
fix: don't show private forks in forks list
- If a repository is forked to a private or limited user/organization, the fork should not be visible in the list of forks depending on the doer requesting the list of forks. - Added integration testing for web and API route. (cherry picked from commit 061abe6)
1 parent c8c8377 commit 36300be

File tree

5 files changed

+88
-11
lines changed

5 files changed

+88
-11
lines changed

models/repo/fork.go

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"context"
88

99
"code.gitea.io/gitea/models/db"
10+
"code.gitea.io/gitea/models/unit"
1011
user_model "code.gitea.io/gitea/models/user"
1112

1213
"xorm.io/builder"
@@ -54,9 +55,9 @@ func GetUserFork(ctx context.Context, repoID, userID int64) (*Repository, error)
5455
return &forkedRepo, nil
5556
}
5657

57-
// GetForks returns all the forks of the repository
58-
func GetForks(ctx context.Context, repo *Repository, listOptions db.ListOptions) ([]*Repository, error) {
59-
sess := db.GetEngine(ctx)
58+
// GetForks returns all the forks of the repository that are visible to the user.
59+
func GetForks(ctx context.Context, repo *Repository, user *user_model.User, listOptions db.ListOptions) ([]*Repository, int64, error) {
60+
sess := db.GetEngine(ctx).Where(AccessibleRepositoryCondition(user, unit.TypeInvalid))
6061

6162
var forks []*Repository
6263
if listOptions.Page == 0 {
@@ -66,7 +67,8 @@ func GetForks(ctx context.Context, repo *Repository, listOptions db.ListOptions)
6667
sess = db.SetSessionPagination(sess, &listOptions)
6768
}
6869

69-
return forks, sess.Find(&forks, &Repository{ForkID: repo.ID})
70+
count, err := sess.FindAndCount(&forks, &Repository{ForkID: repo.ID})
71+
return forks, count, err
7072
}
7173

7274
// IncrementRepoForkNum increment repository fork number

routers/api/v1/repo/fork.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ func ListForks(ctx *context.APIContext) {
5656
// "404":
5757
// "$ref": "#/responses/notFound"
5858

59-
forks, err := repo_model.GetForks(ctx, ctx.Repo.Repository, utils.GetListOptions(ctx))
59+
forks, total, err := repo_model.GetForks(ctx, ctx.Repo.Repository, ctx.Doer, utils.GetListOptions(ctx))
6060
if err != nil {
6161
ctx.Error(http.StatusInternalServerError, "GetForks", err)
6262
return
@@ -71,7 +71,7 @@ func ListForks(ctx *context.APIContext) {
7171
apiForks[i] = convert.ToRepo(ctx, fork, permission)
7272
}
7373

74-
ctx.SetTotalCountHeader(int64(ctx.Repo.Repository.NumForks))
74+
ctx.SetTotalCountHeader(total)
7575
ctx.JSON(http.StatusOK, apiForks)
7676
}
7777

routers/web/repo/view.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1233,18 +1233,18 @@ func Forks(ctx *context.Context) {
12331233
page = 1
12341234
}
12351235

1236-
pager := context.NewPagination(ctx.Repo.Repository.NumForks, setting.MaxForksPerPage, page, 5)
1237-
ctx.Data["Page"] = pager
1238-
1239-
forks, err := repo_model.GetForks(ctx, ctx.Repo.Repository, db.ListOptions{
1240-
Page: pager.Paginater.Current(),
1236+
forks, total, err := repo_model.GetForks(ctx, ctx.Repo.Repository, ctx.Doer, db.ListOptions{
1237+
Page: page,
12411238
PageSize: setting.MaxForksPerPage,
12421239
})
12431240
if err != nil {
12441241
ctx.ServerError("GetForks", err)
12451242
return
12461243
}
12471244

1245+
pager := context.NewPagination(int(total), setting.MaxForksPerPage, page, 5)
1246+
ctx.Data["Page"] = pager
1247+
12481248
for _, fork := range forks {
12491249
if err = fork.LoadOwner(ctx); err != nil {
12501250
ctx.ServerError("LoadOwner", err)

tests/integration/api_fork_test.go

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ import (
1818
"code.gitea.io/gitea/modules/test"
1919
"code.gitea.io/gitea/routers"
2020
"code.gitea.io/gitea/tests"
21+
22+
"github.com/stretchr/testify/assert"
2123
)
2224

2325
func TestAPIForkAsAdminIgnoringLimits(t *testing.T) {
@@ -108,3 +110,44 @@ func TestAPIDisabledForkRepo(t *testing.T) {
108110
})
109111
})
110112
}
113+
114+
func TestAPIForkListPrivateRepo(t *testing.T) {
115+
defer tests.PrepareTestEnv(t)()
116+
117+
session := loginUser(t, "user5")
118+
token := getTokenForLoggedInUser(t, session,
119+
auth_model.AccessTokenScopeWriteRepository,
120+
auth_model.AccessTokenScopeWriteOrganization)
121+
org23 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 23, Visibility: api.VisibleTypePrivate})
122+
123+
req := NewRequestWithJSON(t, "POST", "/api/v1/repos/user2/repo1/forks", &api.CreateForkOption{
124+
Organization: &org23.Name,
125+
}).AddTokenAuth(token)
126+
MakeRequest(t, req, http.StatusAccepted)
127+
128+
t.Run("Anomynous", func(t *testing.T) {
129+
defer tests.PrintCurrentTest(t)()
130+
131+
req := NewRequest(t, "GET", "/api/v1/repos/user2/repo1/forks")
132+
resp := MakeRequest(t, req, http.StatusOK)
133+
134+
var forks []*api.Repository
135+
DecodeJSON(t, resp, &forks)
136+
137+
assert.Empty(t, forks)
138+
assert.EqualValues(t, "0", resp.Header().Get("X-Total-Count"))
139+
})
140+
141+
t.Run("Logged in", func(t *testing.T) {
142+
defer tests.PrintCurrentTest(t)()
143+
144+
req := NewRequest(t, "GET", "/api/v1/repos/user2/repo1/forks").AddTokenAuth(token)
145+
resp := MakeRequest(t, req, http.StatusOK)
146+
147+
var forks []*api.Repository
148+
DecodeJSON(t, resp, &forks)
149+
150+
assert.Len(t, forks, 1)
151+
assert.EqualValues(t, "1", resp.Header().Get("X-Total-Count"))
152+
})
153+
}

tests/integration/repo_fork_test.go

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import (
1717
"code.gitea.io/gitea/models/unittest"
1818
user_model "code.gitea.io/gitea/models/user"
1919
"code.gitea.io/gitea/modules/setting"
20+
"code.gitea.io/gitea/modules/structs"
2021
"code.gitea.io/gitea/modules/test"
2122
"code.gitea.io/gitea/routers"
2223
repo_service "code.gitea.io/gitea/services/repository"
@@ -238,3 +239,34 @@ func TestRepoForkToOrg(t *testing.T) {
238239
})
239240
})
240241
}
242+
243+
func TestForkListPrivateRepo(t *testing.T) {
244+
forkItemSelector := ".tw-flex.tw-items-center.tw-py-2"
245+
246+
onGiteaRun(t, func(t *testing.T, u *url.URL) {
247+
session := loginUser(t, "user5")
248+
org23 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 23, Visibility: structs.VisibleTypePrivate})
249+
250+
testRepoFork(t, session, "user2", "repo1", org23.Name, "repo1")
251+
252+
t.Run("Anomynous", func(t *testing.T) {
253+
defer tests.PrintCurrentTest(t)()
254+
255+
req := NewRequest(t, "GET", "/user2/repo1/forks")
256+
resp := MakeRequest(t, req, http.StatusOK)
257+
htmlDoc := NewHTMLParser(t, resp.Body)
258+
259+
htmlDoc.AssertElement(t, forkItemSelector, false)
260+
})
261+
262+
t.Run("Logged in", func(t *testing.T) {
263+
defer tests.PrintCurrentTest(t)()
264+
265+
req := NewRequest(t, "GET", "/user2/repo1/forks")
266+
resp := session.MakeRequest(t, req, http.StatusOK)
267+
htmlDoc := NewHTMLParser(t, resp.Body)
268+
269+
htmlDoc.AssertElement(t, forkItemSelector, true)
270+
})
271+
})
272+
}

0 commit comments

Comments
 (0)