Skip to content

Commit

Permalink
Fix Permission in API returned repository struct (go-gitea#25388)
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
wolfogre authored and GiteaBot committed Jun 22, 2023
1 parent 0568297 commit 027d36b
Show file tree
Hide file tree
Showing 22 changed files with 174 additions and 153 deletions.
6 changes: 3 additions & 3 deletions modules/structs/repo.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ import (

// Permission represents a set of permissions
type Permission struct {
Admin bool `json:"admin"`
Push bool `json:"push"`
Pull bool `json:"pull"`
Admin bool `json:"admin"` // Admin indicates if the user is an administrator of the repository.
Push bool `json:"push"` // Push indicates if the user can push code to the repository.
Pull bool `json:"pull"` // Pull indicates if the user can pull code from the repository.
}

// InternalTracker represents settings for internal tracker
Expand Down
8 changes: 4 additions & 4 deletions routers/api/v1/org/team.go
Original file line number Diff line number Diff line change
Expand Up @@ -561,12 +561,12 @@ func GetTeamRepos(ctx *context.APIContext) {
}
repos := make([]*api.Repository, len(teamRepos))
for i, repo := range teamRepos {
access, err := access_model.AccessLevel(ctx, ctx.Doer, repo)
permission, err := access_model.GetUserRepoPermission(ctx, repo, ctx.Doer)
if err != nil {
ctx.Error(http.StatusInternalServerError, "GetTeamRepos", err)
return
}
repos[i] = convert.ToRepo(ctx, repo, access)
repos[i] = convert.ToRepo(ctx, repo, permission)
}
ctx.SetTotalCountHeader(int64(team.NumRepos))
ctx.JSON(http.StatusOK, repos)
Expand Down Expand Up @@ -612,13 +612,13 @@ func GetTeamRepo(ctx *context.APIContext) {
return
}

access, err := access_model.AccessLevel(ctx, ctx.Doer, repo)
permission, err := access_model.GetUserRepoPermission(ctx, repo, ctx.Doer)
if err != nil {
ctx.Error(http.StatusInternalServerError, "GetTeamRepos", err)
return
}

ctx.JSON(http.StatusOK, convert.ToRepo(ctx, repo, access))
ctx.JSON(http.StatusOK, convert.ToRepo(ctx, repo, permission))
}

// getRepositoryByParams get repository by a team's organization ID and repo name
Expand Down
8 changes: 4 additions & 4 deletions routers/api/v1/repo/fork.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,12 +60,12 @@ func ListForks(ctx *context.APIContext) {
}
apiForks := make([]*api.Repository, len(forks))
for i, fork := range forks {
access, err := access_model.AccessLevel(ctx, ctx.Doer, fork)
permission, err := access_model.GetUserRepoPermission(ctx, fork, ctx.Doer)
if err != nil {
ctx.Error(http.StatusInternalServerError, "AccessLevel", err)
ctx.Error(http.StatusInternalServerError, "GetUserRepoPermission", err)
return
}
apiForks[i] = convert.ToRepo(ctx, fork, access)
apiForks[i] = convert.ToRepo(ctx, fork, permission)
}

ctx.SetTotalCountHeader(int64(ctx.Repo.Repository.NumForks))
Expand Down Expand Up @@ -152,5 +152,5 @@ func CreateFork(ctx *context.APIContext) {
}

// TODO change back to 201
ctx.JSON(http.StatusAccepted, convert.ToRepo(ctx, fork, perm.AccessModeOwner))
ctx.JSON(http.StatusAccepted, convert.ToRepo(ctx, fork, access_model.Permission{AccessMode: perm.AccessModeOwner}))
}
3 changes: 2 additions & 1 deletion routers/api/v1/repo/hook.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"net/http"

"code.gitea.io/gitea/models/perm"
access_model "code.gitea.io/gitea/models/perm/access"
"code.gitea.io/gitea/models/webhook"
"code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/git"
Expand Down Expand Up @@ -185,7 +186,7 @@ func TestHook(ctx *context.APIContext) {
Commits: []*api.PayloadCommit{commit},
TotalCommits: 1,
HeadCommit: commit,
Repo: convert.ToRepo(ctx, ctx.Repo.Repository, perm.AccessModeNone),
Repo: convert.ToRepo(ctx, ctx.Repo.Repository, access_model.Permission{AccessMode: perm.AccessModeNone}),
Pusher: convert.ToUserWithAccessMode(ctx, ctx.Doer, perm.AccessModeNone),
Sender: convert.ToUserWithAccessMode(ctx, ctx.Doer, perm.AccessModeNone),
}); err != nil {
Expand Down
5 changes: 3 additions & 2 deletions routers/api/v1/repo/key.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
asymkey_model "code.gitea.io/gitea/models/asymkey"
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/perm"
access_model "code.gitea.io/gitea/models/perm/access"
repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/setting"
Expand All @@ -27,13 +28,13 @@ import (
func appendPrivateInformation(ctx stdCtx.Context, apiKey *api.DeployKey, key *asymkey_model.DeployKey, repository *repo_model.Repository) (*api.DeployKey, error) {
apiKey.ReadOnly = key.Mode == perm.AccessModeRead
if repository.ID == key.RepoID {
apiKey.Repository = convert.ToRepo(ctx, repository, key.Mode)
apiKey.Repository = convert.ToRepo(ctx, repository, access_model.Permission{AccessMode: key.Mode})
} else {
repo, err := repo_model.GetRepositoryByID(ctx, key.RepoID)
if err != nil {
return apiKey, err
}
apiKey.Repository = convert.ToRepo(ctx, repo, key.Mode)
apiKey.Repository = convert.ToRepo(ctx, repo, access_model.Permission{AccessMode: key.Mode})
}
return apiKey, nil
}
Expand Down
3 changes: 2 additions & 1 deletion routers/api/v1/repo/migrate.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/organization"
"code.gitea.io/gitea/models/perm"
access_model "code.gitea.io/gitea/models/perm/access"
repo_model "code.gitea.io/gitea/models/repo"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/context"
Expand Down Expand Up @@ -211,7 +212,7 @@ func Migrate(ctx *context.APIContext) {
}

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

func handleMigrateError(ctx *context.APIContext, repoOwner *user_model.User, remoteAddr string, err error) {
Expand Down
20 changes: 10 additions & 10 deletions routers/api/v1/repo/repo.go
Original file line number Diff line number Diff line change
Expand Up @@ -211,14 +211,14 @@ func Search(ctx *context.APIContext) {
})
return
}
accessMode, err := access_model.AccessLevel(ctx, ctx.Doer, repo)
permission, err := access_model.GetUserRepoPermission(ctx, repo, ctx.Doer)
if err != nil {
ctx.JSON(http.StatusInternalServerError, api.SearchError{
OK: false,
Error: err.Error(),
})
}
results[i] = convert.ToRepo(ctx, repo, accessMode)
results[i] = convert.ToRepo(ctx, repo, permission)
}
ctx.SetLinkHeader(int(count), opts.PageSize)
ctx.SetTotalCountHeader(count)
Expand Down Expand Up @@ -272,7 +272,7 @@ func CreateUserRepo(ctx *context.APIContext, owner *user_model.User, opt api.Cre
ctx.Error(http.StatusInternalServerError, "GetRepositoryByID", err)
}

ctx.JSON(http.StatusCreated, convert.ToRepo(ctx, repo, perm.AccessModeOwner))
ctx.JSON(http.StatusCreated, convert.ToRepo(ctx, repo, access_model.Permission{AccessMode: perm.AccessModeOwner}))
}

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

ctx.JSON(http.StatusCreated, convert.ToRepo(ctx, repo, perm.AccessModeOwner))
ctx.JSON(http.StatusCreated, convert.ToRepo(ctx, repo, access_model.Permission{AccessMode: perm.AccessModeOwner}))
}

// CreateOrgRepoDeprecated create one repository of the organization
Expand Down Expand Up @@ -537,7 +537,7 @@ func Get(ctx *context.APIContext) {
return
}

ctx.JSON(http.StatusOK, convert.ToRepo(ctx, ctx.Repo.Repository, ctx.Repo.AccessMode))
ctx.JSON(http.StatusOK, convert.ToRepo(ctx, ctx.Repo.Repository, ctx.Repo.Permission))
}

// GetByID returns a single Repository
Expand Down Expand Up @@ -568,15 +568,15 @@ func GetByID(ctx *context.APIContext) {
return
}

perm, err := access_model.GetUserRepoPermission(ctx, repo, ctx.Doer)
permission, err := access_model.GetUserRepoPermission(ctx, repo, ctx.Doer)
if err != nil {
ctx.Error(http.StatusInternalServerError, "AccessLevel", err)
ctx.Error(http.StatusInternalServerError, "GetUserRepoPermission", err)
return
} else if !perm.HasAccess() {
} else if !permission.HasAccess() {
ctx.NotFound()
return
}
ctx.JSON(http.StatusOK, convert.ToRepo(ctx, repo, perm.AccessMode))
ctx.JSON(http.StatusOK, convert.ToRepo(ctx, repo, permission))
}

// Edit edit repository properties
Expand Down Expand Up @@ -638,7 +638,7 @@ func Edit(ctx *context.APIContext) {
return
}

ctx.JSON(http.StatusOK, convert.ToRepo(ctx, repo, ctx.Repo.AccessMode))
ctx.JSON(http.StatusOK, convert.ToRepo(ctx, repo, ctx.Repo.Permission))
}

// updateBasicProperties updates the basic properties of a repo: Name, Description, Website and Visibility
Expand Down
2 changes: 1 addition & 1 deletion routers/api/v1/repo/status.go
Original file line number Diff line number Diff line change
Expand Up @@ -264,7 +264,7 @@ func GetCombinedCommitStatusByRef(ctx *context.APIContext) {
return
}

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

ctx.SetTotalCountHeader(count)
ctx.JSON(http.StatusOK, combiStatus)
Expand Down
9 changes: 5 additions & 4 deletions routers/api/v1/repo/transfer.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/models/organization"
"code.gitea.io/gitea/models/perm"
access_model "code.gitea.io/gitea/models/perm/access"
repo_model "code.gitea.io/gitea/models/repo"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/context"
Expand Down Expand Up @@ -122,12 +123,12 @@ func Transfer(ctx *context.APIContext) {

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

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

// AcceptTransfer accept a repo transfer
Expand Down Expand Up @@ -165,7 +166,7 @@ func AcceptTransfer(ctx *context.APIContext) {
return
}

ctx.JSON(http.StatusAccepted, convert.ToRepo(ctx, ctx.Repo.Repository, ctx.Repo.AccessMode))
ctx.JSON(http.StatusAccepted, convert.ToRepo(ctx, ctx.Repo.Repository, ctx.Repo.Permission))
}

// RejectTransfer reject a repo transfer
Expand Down Expand Up @@ -203,7 +204,7 @@ func RejectTransfer(ctx *context.APIContext) {
return
}

ctx.JSON(http.StatusOK, convert.ToRepo(ctx, ctx.Repo.Repository, ctx.Repo.AccessMode))
ctx.JSON(http.StatusOK, convert.ToRepo(ctx, ctx.Repo.Repository, ctx.Repo.Permission))
}

func acceptOrRejectRepoTransfer(ctx *context.APIContext, accept bool) error {
Expand Down
15 changes: 8 additions & 7 deletions routers/api/v1/user/repo.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"code.gitea.io/gitea/models/perm"
access_model "code.gitea.io/gitea/models/perm/access"
repo_model "code.gitea.io/gitea/models/repo"
unit_model "code.gitea.io/gitea/models/unit"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/context"
api "code.gitea.io/gitea/modules/structs"
Expand Down Expand Up @@ -38,13 +39,13 @@ func listUserRepos(ctx *context.APIContext, u *user_model.User, private bool) {

apiRepos := make([]*api.Repository, 0, len(repos))
for i := range repos {
access, err := access_model.AccessLevel(ctx, ctx.Doer, repos[i])
permission, err := access_model.GetUserRepoPermission(ctx, repos[i], ctx.Doer)
if err != nil {
ctx.Error(http.StatusInternalServerError, "AccessLevel", err)
ctx.Error(http.StatusInternalServerError, "GetUserRepoPermission", err)
return
}
if ctx.IsSigned && ctx.Doer.IsAdmin || access >= perm.AccessModeRead {
apiRepos = append(apiRepos, convert.ToRepo(ctx, repos[i], access))
if ctx.IsSigned && ctx.Doer.IsAdmin || permission.UnitAccessMode(unit_model.TypeCode) >= perm.AccessModeRead {
apiRepos = append(apiRepos, convert.ToRepo(ctx, repos[i], permission))
}
}

Expand Down Expand Up @@ -123,11 +124,11 @@ func ListMyRepos(ctx *context.APIContext) {
ctx.Error(http.StatusInternalServerError, "LoadOwner", err)
return
}
accessMode, err := access_model.AccessLevel(ctx, ctx.Doer, repo)
permission, err := access_model.GetUserRepoPermission(ctx, repo, ctx.Doer)
if err != nil {
ctx.Error(http.StatusInternalServerError, "AccessLevel", err)
ctx.Error(http.StatusInternalServerError, "GetUserRepoPermission", err)
}
results[i] = convert.ToRepo(ctx, repo, accessMode)
results[i] = convert.ToRepo(ctx, repo, permission)
}

ctx.SetLinkHeader(int(count), opts.ListOptions.PageSize)
Expand Down
4 changes: 2 additions & 2 deletions routers/api/v1/user/star.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,11 @@ func getStarredRepos(ctx std_context.Context, user *user_model.User, private boo

repos := make([]*api.Repository, len(starredRepos))
for i, starred := range starredRepos {
access, err := access_model.AccessLevel(ctx, user, starred)
permission, err := access_model.GetUserRepoPermission(ctx, starred, user)
if err != nil {
return nil, err
}
repos[i] = convert.ToRepo(ctx, starred, access)
repos[i] = convert.ToRepo(ctx, starred, permission)
}
return repos, nil
}
Expand Down
4 changes: 2 additions & 2 deletions routers/api/v1/user/watch.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,11 @@ func getWatchedRepos(ctx std_context.Context, user *user_model.User, private boo

repos := make([]*api.Repository, len(watchedRepos))
for i, watched := range watchedRepos {
access, err := access_model.AccessLevel(ctx, user, watched)
permission, err := access_model.GetUserRepoPermission(ctx, watched, user)
if err != nil {
return nil, 0, err
}
repos[i] = convert.ToRepo(ctx, watched, access)
repos[i] = convert.ToRepo(ctx, watched, permission)
}
return repos, total, nil
}
Expand Down
3 changes: 2 additions & 1 deletion routers/web/repo/webhook.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
"strings"

"code.gitea.io/gitea/models/perm"
access_model "code.gitea.io/gitea/models/perm/access"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/models/webhook"
"code.gitea.io/gitea/modules/base"
Expand Down Expand Up @@ -685,7 +686,7 @@ func TestWebhook(ctx *context.Context) {
Commits: []*api.PayloadCommit{apiCommit},
TotalCommits: 1,
HeadCommit: apiCommit,
Repo: convert.ToRepo(ctx, ctx.Repo.Repository, perm.AccessModeNone),
Repo: convert.ToRepo(ctx, ctx.Repo.Repository, access_model.Permission{AccessMode: perm.AccessModeNone}),
Pusher: apiUser,
Sender: apiUser,
}
Expand Down
Loading

0 comments on commit 027d36b

Please sign in to comment.