Skip to content

Commit 1742135

Browse files
authored
Fix Permission in API returned repository struct (#25388)
The old code generates `structs.Repository.Permissions` with only `access.Permission.AccessMode`, however, it should check the units too, or the value could be incorrect. For example, `structs.Repository.Permissions.Push` could be false even the doer has write access to code unit. Should fix renovatebot/renovate#14059 (comment) (Not reported by it, I just found it when I was looking into this bug) --- Review tips: The major changes are - `modules/structs/repo.go` https://github.com/go-gitea/gitea/pull/25388/files#diff-870406f6857117f8b03611c43fca0ab9ed6d6e76a2d0069a7c1f17e8fa9092f7 - `services/convert/repository.go` https://github.com/go-gitea/gitea/pull/25388/files#diff-7736f6d2ae894c9edb7729a80ab89aa183b888a26a811a0c1fdebd18726a7101 And other changes are passive.
1 parent 7fb5396 commit 1742135

22 files changed

+174
-153
lines changed

modules/structs/repo.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,9 @@ import (
1010

1111
// Permission represents a set of permissions
1212
type Permission struct {
13-
Admin bool `json:"admin"`
14-
Push bool `json:"push"`
15-
Pull bool `json:"pull"`
13+
Admin bool `json:"admin"` // Admin indicates if the user is an administrator of the repository.
14+
Push bool `json:"push"` // Push indicates if the user can push code to the repository.
15+
Pull bool `json:"pull"` // Pull indicates if the user can pull code from the repository.
1616
}
1717

1818
// InternalTracker represents settings for internal tracker

routers/api/v1/org/team.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -561,12 +561,12 @@ func GetTeamRepos(ctx *context.APIContext) {
561561
}
562562
repos := make([]*api.Repository, len(teamRepos))
563563
for i, repo := range teamRepos {
564-
access, err := access_model.AccessLevel(ctx, ctx.Doer, repo)
564+
permission, err := access_model.GetUserRepoPermission(ctx, repo, ctx.Doer)
565565
if err != nil {
566566
ctx.Error(http.StatusInternalServerError, "GetTeamRepos", err)
567567
return
568568
}
569-
repos[i] = convert.ToRepo(ctx, repo, access)
569+
repos[i] = convert.ToRepo(ctx, repo, permission)
570570
}
571571
ctx.SetTotalCountHeader(int64(team.NumRepos))
572572
ctx.JSON(http.StatusOK, repos)
@@ -612,13 +612,13 @@ func GetTeamRepo(ctx *context.APIContext) {
612612
return
613613
}
614614

615-
access, err := access_model.AccessLevel(ctx, ctx.Doer, repo)
615+
permission, err := access_model.GetUserRepoPermission(ctx, repo, ctx.Doer)
616616
if err != nil {
617617
ctx.Error(http.StatusInternalServerError, "GetTeamRepos", err)
618618
return
619619
}
620620

621-
ctx.JSON(http.StatusOK, convert.ToRepo(ctx, repo, access))
621+
ctx.JSON(http.StatusOK, convert.ToRepo(ctx, repo, permission))
622622
}
623623

624624
// getRepositoryByParams get repository by a team's organization ID and repo name

routers/api/v1/repo/fork.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -60,12 +60,12 @@ func ListForks(ctx *context.APIContext) {
6060
}
6161
apiForks := make([]*api.Repository, len(forks))
6262
for i, fork := range forks {
63-
access, err := access_model.AccessLevel(ctx, ctx.Doer, fork)
63+
permission, err := access_model.GetUserRepoPermission(ctx, fork, ctx.Doer)
6464
if err != nil {
65-
ctx.Error(http.StatusInternalServerError, "AccessLevel", err)
65+
ctx.Error(http.StatusInternalServerError, "GetUserRepoPermission", err)
6666
return
6767
}
68-
apiForks[i] = convert.ToRepo(ctx, fork, access)
68+
apiForks[i] = convert.ToRepo(ctx, fork, permission)
6969
}
7070

7171
ctx.SetTotalCountHeader(int64(ctx.Repo.Repository.NumForks))
@@ -152,5 +152,5 @@ func CreateFork(ctx *context.APIContext) {
152152
}
153153

154154
// TODO change back to 201
155-
ctx.JSON(http.StatusAccepted, convert.ToRepo(ctx, fork, perm.AccessModeOwner))
155+
ctx.JSON(http.StatusAccepted, convert.ToRepo(ctx, fork, access_model.Permission{AccessMode: perm.AccessModeOwner}))
156156
}

routers/api/v1/repo/hook.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"net/http"
99

1010
"code.gitea.io/gitea/models/perm"
11+
access_model "code.gitea.io/gitea/models/perm/access"
1112
"code.gitea.io/gitea/models/webhook"
1213
"code.gitea.io/gitea/modules/context"
1314
"code.gitea.io/gitea/modules/git"
@@ -185,7 +186,7 @@ func TestHook(ctx *context.APIContext) {
185186
Commits: []*api.PayloadCommit{commit},
186187
TotalCommits: 1,
187188
HeadCommit: commit,
188-
Repo: convert.ToRepo(ctx, ctx.Repo.Repository, perm.AccessModeNone),
189+
Repo: convert.ToRepo(ctx, ctx.Repo.Repository, access_model.Permission{AccessMode: perm.AccessModeNone}),
189190
Pusher: convert.ToUserWithAccessMode(ctx, ctx.Doer, perm.AccessModeNone),
190191
Sender: convert.ToUserWithAccessMode(ctx, ctx.Doer, perm.AccessModeNone),
191192
}); err != nil {

routers/api/v1/repo/key.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import (
1313
asymkey_model "code.gitea.io/gitea/models/asymkey"
1414
"code.gitea.io/gitea/models/db"
1515
"code.gitea.io/gitea/models/perm"
16+
access_model "code.gitea.io/gitea/models/perm/access"
1617
repo_model "code.gitea.io/gitea/models/repo"
1718
"code.gitea.io/gitea/modules/context"
1819
"code.gitea.io/gitea/modules/setting"
@@ -27,13 +28,13 @@ import (
2728
func appendPrivateInformation(ctx stdCtx.Context, apiKey *api.DeployKey, key *asymkey_model.DeployKey, repository *repo_model.Repository) (*api.DeployKey, error) {
2829
apiKey.ReadOnly = key.Mode == perm.AccessModeRead
2930
if repository.ID == key.RepoID {
30-
apiKey.Repository = convert.ToRepo(ctx, repository, key.Mode)
31+
apiKey.Repository = convert.ToRepo(ctx, repository, access_model.Permission{AccessMode: key.Mode})
3132
} else {
3233
repo, err := repo_model.GetRepositoryByID(ctx, key.RepoID)
3334
if err != nil {
3435
return apiKey, err
3536
}
36-
apiKey.Repository = convert.ToRepo(ctx, repo, key.Mode)
37+
apiKey.Repository = convert.ToRepo(ctx, repo, access_model.Permission{AccessMode: key.Mode})
3738
}
3839
return apiKey, nil
3940
}

routers/api/v1/repo/migrate.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import (
1414
"code.gitea.io/gitea/models/db"
1515
"code.gitea.io/gitea/models/organization"
1616
"code.gitea.io/gitea/models/perm"
17+
access_model "code.gitea.io/gitea/models/perm/access"
1718
repo_model "code.gitea.io/gitea/models/repo"
1819
user_model "code.gitea.io/gitea/models/user"
1920
"code.gitea.io/gitea/modules/context"
@@ -211,7 +212,7 @@ func Migrate(ctx *context.APIContext) {
211212
}
212213

213214
log.Trace("Repository migrated: %s/%s", repoOwner.Name, form.RepoName)
214-
ctx.JSON(http.StatusCreated, convert.ToRepo(ctx, repo, perm.AccessModeAdmin))
215+
ctx.JSON(http.StatusCreated, convert.ToRepo(ctx, repo, access_model.Permission{AccessMode: perm.AccessModeAdmin}))
215216
}
216217

217218
func handleMigrateError(ctx *context.APIContext, repoOwner *user_model.User, remoteAddr string, err error) {

routers/api/v1/repo/repo.go

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -211,14 +211,14 @@ func Search(ctx *context.APIContext) {
211211
})
212212
return
213213
}
214-
accessMode, err := access_model.AccessLevel(ctx, ctx.Doer, repo)
214+
permission, err := access_model.GetUserRepoPermission(ctx, repo, ctx.Doer)
215215
if err != nil {
216216
ctx.JSON(http.StatusInternalServerError, api.SearchError{
217217
OK: false,
218218
Error: err.Error(),
219219
})
220220
}
221-
results[i] = convert.ToRepo(ctx, repo, accessMode)
221+
results[i] = convert.ToRepo(ctx, repo, permission)
222222
}
223223
ctx.SetLinkHeader(int(count), opts.PageSize)
224224
ctx.SetTotalCountHeader(count)
@@ -272,7 +272,7 @@ func CreateUserRepo(ctx *context.APIContext, owner *user_model.User, opt api.Cre
272272
ctx.Error(http.StatusInternalServerError, "GetRepositoryByID", err)
273273
}
274274

275-
ctx.JSON(http.StatusCreated, convert.ToRepo(ctx, repo, perm.AccessModeOwner))
275+
ctx.JSON(http.StatusCreated, convert.ToRepo(ctx, repo, access_model.Permission{AccessMode: perm.AccessModeOwner}))
276276
}
277277

278278
// Create one repository of mine
@@ -419,7 +419,7 @@ func Generate(ctx *context.APIContext) {
419419
}
420420
log.Trace("Repository generated [%d]: %s/%s", repo.ID, ctxUser.Name, repo.Name)
421421

422-
ctx.JSON(http.StatusCreated, convert.ToRepo(ctx, repo, perm.AccessModeOwner))
422+
ctx.JSON(http.StatusCreated, convert.ToRepo(ctx, repo, access_model.Permission{AccessMode: perm.AccessModeOwner}))
423423
}
424424

425425
// CreateOrgRepoDeprecated create one repository of the organization
@@ -537,7 +537,7 @@ func Get(ctx *context.APIContext) {
537537
return
538538
}
539539

540-
ctx.JSON(http.StatusOK, convert.ToRepo(ctx, ctx.Repo.Repository, ctx.Repo.AccessMode))
540+
ctx.JSON(http.StatusOK, convert.ToRepo(ctx, ctx.Repo.Repository, ctx.Repo.Permission))
541541
}
542542

543543
// GetByID returns a single Repository
@@ -568,15 +568,15 @@ func GetByID(ctx *context.APIContext) {
568568
return
569569
}
570570

571-
perm, err := access_model.GetUserRepoPermission(ctx, repo, ctx.Doer)
571+
permission, err := access_model.GetUserRepoPermission(ctx, repo, ctx.Doer)
572572
if err != nil {
573-
ctx.Error(http.StatusInternalServerError, "AccessLevel", err)
573+
ctx.Error(http.StatusInternalServerError, "GetUserRepoPermission", err)
574574
return
575-
} else if !perm.HasAccess() {
575+
} else if !permission.HasAccess() {
576576
ctx.NotFound()
577577
return
578578
}
579-
ctx.JSON(http.StatusOK, convert.ToRepo(ctx, repo, perm.AccessMode))
579+
ctx.JSON(http.StatusOK, convert.ToRepo(ctx, repo, permission))
580580
}
581581

582582
// Edit edit repository properties
@@ -638,7 +638,7 @@ func Edit(ctx *context.APIContext) {
638638
return
639639
}
640640

641-
ctx.JSON(http.StatusOK, convert.ToRepo(ctx, repo, ctx.Repo.AccessMode))
641+
ctx.JSON(http.StatusOK, convert.ToRepo(ctx, repo, ctx.Repo.Permission))
642642
}
643643

644644
// updateBasicProperties updates the basic properties of a repo: Name, Description, Website and Visibility

routers/api/v1/repo/status.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -264,7 +264,7 @@ func GetCombinedCommitStatusByRef(ctx *context.APIContext) {
264264
return
265265
}
266266

267-
combiStatus := convert.ToCombinedStatus(ctx, statuses, convert.ToRepo(ctx, repo, ctx.Repo.AccessMode))
267+
combiStatus := convert.ToCombinedStatus(ctx, statuses, convert.ToRepo(ctx, repo, ctx.Repo.Permission))
268268

269269
ctx.SetTotalCountHeader(count)
270270
ctx.JSON(http.StatusOK, combiStatus)

routers/api/v1/repo/transfer.go

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
"code.gitea.io/gitea/models"
1111
"code.gitea.io/gitea/models/organization"
1212
"code.gitea.io/gitea/models/perm"
13+
access_model "code.gitea.io/gitea/models/perm/access"
1314
repo_model "code.gitea.io/gitea/models/repo"
1415
user_model "code.gitea.io/gitea/models/user"
1516
"code.gitea.io/gitea/modules/context"
@@ -122,12 +123,12 @@ func Transfer(ctx *context.APIContext) {
122123

123124
if ctx.Repo.Repository.Status == repo_model.RepositoryPendingTransfer {
124125
log.Trace("Repository transfer initiated: %s -> %s", oldFullname, ctx.Repo.Repository.FullName())
125-
ctx.JSON(http.StatusCreated, convert.ToRepo(ctx, ctx.Repo.Repository, perm.AccessModeAdmin))
126+
ctx.JSON(http.StatusCreated, convert.ToRepo(ctx, ctx.Repo.Repository, access_model.Permission{AccessMode: perm.AccessModeAdmin}))
126127
return
127128
}
128129

129130
log.Trace("Repository transferred: %s -> %s", oldFullname, ctx.Repo.Repository.FullName())
130-
ctx.JSON(http.StatusAccepted, convert.ToRepo(ctx, ctx.Repo.Repository, perm.AccessModeAdmin))
131+
ctx.JSON(http.StatusAccepted, convert.ToRepo(ctx, ctx.Repo.Repository, access_model.Permission{AccessMode: perm.AccessModeAdmin}))
131132
}
132133

133134
// AcceptTransfer accept a repo transfer
@@ -165,7 +166,7 @@ func AcceptTransfer(ctx *context.APIContext) {
165166
return
166167
}
167168

168-
ctx.JSON(http.StatusAccepted, convert.ToRepo(ctx, ctx.Repo.Repository, ctx.Repo.AccessMode))
169+
ctx.JSON(http.StatusAccepted, convert.ToRepo(ctx, ctx.Repo.Repository, ctx.Repo.Permission))
169170
}
170171

171172
// RejectTransfer reject a repo transfer
@@ -203,7 +204,7 @@ func RejectTransfer(ctx *context.APIContext) {
203204
return
204205
}
205206

206-
ctx.JSON(http.StatusOK, convert.ToRepo(ctx, ctx.Repo.Repository, ctx.Repo.AccessMode))
207+
ctx.JSON(http.StatusOK, convert.ToRepo(ctx, ctx.Repo.Repository, ctx.Repo.Permission))
207208
}
208209

209210
func acceptOrRejectRepoTransfer(ctx *context.APIContext, accept bool) error {

routers/api/v1/user/repo.go

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"code.gitea.io/gitea/models/perm"
1010
access_model "code.gitea.io/gitea/models/perm/access"
1111
repo_model "code.gitea.io/gitea/models/repo"
12+
unit_model "code.gitea.io/gitea/models/unit"
1213
user_model "code.gitea.io/gitea/models/user"
1314
"code.gitea.io/gitea/modules/context"
1415
api "code.gitea.io/gitea/modules/structs"
@@ -38,13 +39,13 @@ func listUserRepos(ctx *context.APIContext, u *user_model.User, private bool) {
3839

3940
apiRepos := make([]*api.Repository, 0, len(repos))
4041
for i := range repos {
41-
access, err := access_model.AccessLevel(ctx, ctx.Doer, repos[i])
42+
permission, err := access_model.GetUserRepoPermission(ctx, repos[i], ctx.Doer)
4243
if err != nil {
43-
ctx.Error(http.StatusInternalServerError, "AccessLevel", err)
44+
ctx.Error(http.StatusInternalServerError, "GetUserRepoPermission", err)
4445
return
4546
}
46-
if ctx.IsSigned && ctx.Doer.IsAdmin || access >= perm.AccessModeRead {
47-
apiRepos = append(apiRepos, convert.ToRepo(ctx, repos[i], access))
47+
if ctx.IsSigned && ctx.Doer.IsAdmin || permission.UnitAccessMode(unit_model.TypeCode) >= perm.AccessModeRead {
48+
apiRepos = append(apiRepos, convert.ToRepo(ctx, repos[i], permission))
4849
}
4950
}
5051

@@ -123,11 +124,11 @@ func ListMyRepos(ctx *context.APIContext) {
123124
ctx.Error(http.StatusInternalServerError, "LoadOwner", err)
124125
return
125126
}
126-
accessMode, err := access_model.AccessLevel(ctx, ctx.Doer, repo)
127+
permission, err := access_model.GetUserRepoPermission(ctx, repo, ctx.Doer)
127128
if err != nil {
128-
ctx.Error(http.StatusInternalServerError, "AccessLevel", err)
129+
ctx.Error(http.StatusInternalServerError, "GetUserRepoPermission", err)
129130
}
130-
results[i] = convert.ToRepo(ctx, repo, accessMode)
131+
results[i] = convert.ToRepo(ctx, repo, permission)
131132
}
132133

133134
ctx.SetLinkHeader(int(count), opts.ListOptions.PageSize)

routers/api/v1/user/star.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,11 @@ func getStarredRepos(ctx std_context.Context, user *user_model.User, private boo
2828

2929
repos := make([]*api.Repository, len(starredRepos))
3030
for i, starred := range starredRepos {
31-
access, err := access_model.AccessLevel(ctx, user, starred)
31+
permission, err := access_model.GetUserRepoPermission(ctx, starred, user)
3232
if err != nil {
3333
return nil, err
3434
}
35-
repos[i] = convert.ToRepo(ctx, starred, access)
35+
repos[i] = convert.ToRepo(ctx, starred, permission)
3636
}
3737
return repos, nil
3838
}

routers/api/v1/user/watch.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,11 @@ func getWatchedRepos(ctx std_context.Context, user *user_model.User, private boo
2626

2727
repos := make([]*api.Repository, len(watchedRepos))
2828
for i, watched := range watchedRepos {
29-
access, err := access_model.AccessLevel(ctx, user, watched)
29+
permission, err := access_model.GetUserRepoPermission(ctx, watched, user)
3030
if err != nil {
3131
return nil, 0, err
3232
}
33-
repos[i] = convert.ToRepo(ctx, watched, access)
33+
repos[i] = convert.ToRepo(ctx, watched, permission)
3434
}
3535
return repos, total, nil
3636
}

routers/web/repo/webhook.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import (
1313
"strings"
1414

1515
"code.gitea.io/gitea/models/perm"
16+
access_model "code.gitea.io/gitea/models/perm/access"
1617
user_model "code.gitea.io/gitea/models/user"
1718
"code.gitea.io/gitea/models/webhook"
1819
"code.gitea.io/gitea/modules/base"
@@ -685,7 +686,7 @@ func TestWebhook(ctx *context.Context) {
685686
Commits: []*api.PayloadCommit{apiCommit},
686687
TotalCommits: 1,
687688
HeadCommit: apiCommit,
688-
Repo: convert.ToRepo(ctx, ctx.Repo.Repository, perm.AccessModeNone),
689+
Repo: convert.ToRepo(ctx, ctx.Repo.Repository, access_model.Permission{AccessMode: perm.AccessModeNone}),
689690
Pusher: apiUser,
690691
Sender: apiUser,
691692
}

0 commit comments

Comments
 (0)