fix(repo): centralize repository-scoped authorization (#39063)

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
This commit is contained in:
bircni
2026-08-26 14:12:53 +02:00
committed by GitHub
parent 90c43e8e78
commit e21c37703e
27 changed files with 383 additions and 476 deletions
+18 -40
View File
@@ -613,7 +613,7 @@ func GetTeamRepo(ctx *context.APIContext) {
// "404":
// "$ref": "#/responses/notFound"
repo := getRepositoryByParams(ctx)
repo, permission := getRepositoryByParams(ctx)
if ctx.Written() {
return
}
@@ -629,11 +629,6 @@ func GetTeamRepo(ctx *context.APIContext) {
return
}
permission, err := access_model.GetDoerRepoPermission(ctx, repo, ctx.Doer)
if err != nil {
ctx.APIErrorInternal(err)
return
}
// The team may be reachable by a non-team-member via its visibility tier;
// don't confirm the existence of a repo the doer cannot access.
if !permission.HasAnyUnitAccessOrPublicAccess() {
@@ -641,31 +636,28 @@ func GetTeamRepo(ctx *context.APIContext) {
return
}
ctx.JSON(http.StatusOK, convert.ToRepo(ctx, repo, permission))
ctx.JSON(http.StatusOK, convert.ToRepo(ctx, repo, *permission))
}
// getRepositoryByParams get repository by a team's organization ID and repo name
func getRepositoryByParams(ctx *context.APIContext) *repo_model.Repository {
func getRepositoryByParams(ctx *context.APIContext) (*repo_model.Repository, *access_model.Permission) {
repo, err := repo_model.GetRepositoryByName(ctx, ctx.Org.Team.OrgID, ctx.PathParam("reponame"))
if err != nil {
if repo_model.IsErrRepoNotExist(err) {
ctx.APIErrorNotFound()
} else {
ctx.APIErrorInternal(err)
}
return nil
ctx.APIErrorAuto(err)
return nil, nil
}
return repo
perm, err := access_model.GetDoerRepoPermission(ctx, repo, ctx.Doer)
if err != nil {
ctx.APIErrorAuto(err)
return nil, nil
}
return repo, &perm
}
func canChangeTeamRepository(ctx *context.APIContext) bool {
canChange, err := ctx.Org.Organization.CanChangeRepoTeamAccess(ctx, ctx.Doer)
if err != nil {
ctx.APIErrorInternal(err)
return false
}
func canManageRepoCollaboratorTeam(ctx *context.APIContext, repo *repo_model.Repository, perm *access_model.Permission) bool {
canChange := access_model.CanDoerManageOrgRepoCollaboratorTeam(ctx, repo, perm)
if !canChange {
ctx.APIError(http.StatusForbidden, "Must be an organization owner")
ctx.APIError(http.StatusForbidden, "Must have permission to manage team repository access")
return false
}
return true
@@ -703,18 +695,11 @@ func AddTeamRepository(ctx *context.APIContext) {
// "404":
// "$ref": "#/responses/notFound"
repo := getRepositoryByParams(ctx)
repo, perm := getRepositoryByParams(ctx)
if ctx.Written() {
return
}
if !canChangeTeamRepository(ctx) {
return
}
if access, err := access_model.AccessLevel(ctx, ctx.Doer, repo); err != nil {
ctx.APIErrorInternal(err)
return
} else if access < perm.AccessModeAdmin {
ctx.APIError(http.StatusForbidden, "Must have admin-level access to the repository")
if !canManageRepoCollaboratorTeam(ctx, repo, perm) {
return
}
if err := repo_service.TeamAddRepository(ctx, ctx.Org.Team, repo); err != nil {
@@ -758,18 +743,11 @@ func RemoveTeamRepository(ctx *context.APIContext) {
// "404":
// "$ref": "#/responses/notFound"
repo := getRepositoryByParams(ctx)
repo, perm := getRepositoryByParams(ctx)
if ctx.Written() {
return
}
if !canChangeTeamRepository(ctx) {
return
}
if access, err := access_model.AccessLevel(ctx, ctx.Doer, repo); err != nil {
ctx.APIErrorInternal(err)
return
} else if access < perm.AccessModeAdmin {
ctx.APIError(http.StatusForbidden, "Must have admin-level access to the repository")
if !canManageRepoCollaboratorTeam(ctx, repo, perm) {
return
}
if err := repo_service.RemoveRepositoryFromTeam(ctx, ctx.Org.Team, repo.ID); err != nil {