Skip to content

Commit b33d4a7

Browse files
authored
Merge branch 'main' into misccss
2 parents da2aea9 + de69e7f commit b33d4a7

File tree

74 files changed

+612
-296
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

74 files changed

+612
-296
lines changed

.gitattributes

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,4 @@
88
/vendor/** -text -eol linguist-vendored
99
/web_src/js/vendor/** -text -eol linguist-vendored
1010
Dockerfile.* linguist-language=Dockerfile
11+
Makefile.* linguist-language=Makefile

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,3 +127,6 @@ prime/
127127

128128
# Ignore worktrees when working on multiple branches
129129
.worktrees/
130+
131+
# A Makefile for custom make targets
132+
Makefile.local

Makefile

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,10 @@ TEST_MSSQL_DBNAME ?= gitea
198198
TEST_MSSQL_USERNAME ?= sa
199199
TEST_MSSQL_PASSWORD ?= MwantsaSecurePassword1
200200

201+
# Include local Makefile
202+
# Makefile.local is listed in .gitignore
203+
sinclude Makefile.local
204+
201205
.PHONY: all
202206
all: build
203207

custom/conf/app.example.ini

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -567,6 +567,11 @@ ENABLED = true
567567
;; Alternative location to specify OAuth2 authentication secret. You cannot specify both this and JWT_SECRET, and must pick one
568568
;JWT_SECRET_URI = file:/etc/gitea/oauth2_jwt_secret
569569
;;
570+
;; The "issuer" claim identifies the principal that issued the JWT.
571+
;; Gitea 1.25 makes it default to "ROOT_URL without the last slash" to follow the standard.
572+
;; If you have old logins from before 1.25, you may want to set it to the old (non-standard) value "ROOT_URL with the last slash".
573+
;JWT_CLAIM_ISSUER =
574+
;;
570575
;; Lifetime of an OAuth2 access token in seconds
571576
;ACCESS_TOKEN_EXPIRATION_TIME = 3600
572577
;;

go.mod

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
module code.gitea.io/gitea
22

3-
go 1.25.4
3+
go 1.25.0
4+
5+
toolchain go1.25.4
46

57
// rfc5280 said: "The serial number is an integer assigned by the CA to each certificate."
68
// But some CAs use negative serial number, just relax the check. related:
@@ -115,9 +117,9 @@ require (
115117
github.com/yuin/goldmark-highlighting/v2 v2.0.0-20230729083705-37449abec8cc
116118
github.com/yuin/goldmark-meta v1.1.0
117119
gitlab.com/gitlab-org/api/client-go v0.142.4
118-
golang.org/x/crypto v0.42.0
120+
golang.org/x/crypto v0.43.0
119121
golang.org/x/image v0.30.0
120-
golang.org/x/net v0.44.0
122+
golang.org/x/net v0.45.0
121123
golang.org/x/oauth2 v0.30.0
122124
golang.org/x/sync v0.17.0
123125
golang.org/x/sys v0.37.0

go.sum

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -840,8 +840,8 @@ golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDf
840840
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
841841
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
842842
golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc=
843-
golang.org/x/crypto v0.42.0 h1:chiH31gIWm57EkTXpwnqf8qeuMUi0yekh6mT2AvFlqI=
844-
golang.org/x/crypto v0.42.0/go.mod h1:4+rDnOTJhQCx2q7/j6rAN5XDw8kPjeaXEUR2eL94ix8=
843+
golang.org/x/crypto v0.43.0 h1:dduJYIi3A3KOfdGOHX8AVZ/jGiyPa3IbBozJ5kNuE04=
844+
golang.org/x/crypto v0.43.0/go.mod h1:BFbav4mRNlXJL4wNeejLpWxB7wMbc79PdRGhWKncxR0=
845845
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
846846
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
847847
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@@ -908,8 +908,8 @@ golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
908908
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
909909
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
910910
golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
911-
golang.org/x/net v0.44.0 h1:evd8IRDyfNBMBTTY5XRF1vaZlD+EmWx6x8PkhR04H/I=
912-
golang.org/x/net v0.44.0/go.mod h1:ECOoLqd5U3Lhyeyo/QDCEVQ4sNgYsqvCZ722XogGieY=
911+
golang.org/x/net v0.45.0 h1:RLBg5JKixCy82FtLJpeNlVM0nrSqpCRYzVU1n8kj0tM=
912+
golang.org/x/net v0.45.0/go.mod h1:ECOoLqd5U3Lhyeyo/QDCEVQ4sNgYsqvCZ722XogGieY=
913913
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
914914
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
915915
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@@ -987,8 +987,8 @@ golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
987987
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
988988
golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM=
989989
golang.org/x/term v0.28.0/go.mod h1:Sw/lC2IAUZ92udQNf3WodGtn4k/XoLyZoh8v/8uiwek=
990-
golang.org/x/term v0.35.0 h1:bZBVKBudEyhRcajGcNc3jIfWPqV4y/Kt2XcoigOWtDQ=
991-
golang.org/x/term v0.35.0/go.mod h1:TPGtkTLesOwf2DE8CgVYiZinHAOuy5AYUYT1lENIZnA=
990+
golang.org/x/term v0.36.0 h1:zMPR+aF8gfksFprF/Nc/rd1wRS1EI6nDBGyWAvDzx2Q=
991+
golang.org/x/term v0.36.0/go.mod h1:Qu394IJq6V6dCBRgwqshf3mPF85AqzYEzofzRdZkWss=
992992
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
993993
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
994994
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=

models/git/protected_branch.go

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -466,11 +466,13 @@ func updateApprovalWhitelist(ctx context.Context, repo *repo_model.Repository, c
466466
return currentWhitelist, nil
467467
}
468468

469+
prUserIDs, err := access_model.GetUserIDsWithUnitAccess(ctx, repo, perm.AccessModeRead, unit.TypePullRequests)
470+
if err != nil {
471+
return nil, err
472+
}
469473
whitelist = make([]int64, 0, len(newWhitelist))
470474
for _, userID := range newWhitelist {
471-
if reader, err := access_model.IsRepoReader(ctx, repo, userID); err != nil {
472-
return nil, err
473-
} else if !reader {
475+
if !prUserIDs.Contains(userID) {
474476
continue
475477
}
476478
whitelist = append(whitelist, userID)

models/organization/team_repo.go

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -53,24 +53,45 @@ func RemoveTeamRepo(ctx context.Context, teamID, repoID int64) error {
5353
// GetTeamsWithAccessToAnyRepoUnit returns all teams in an organization that have given access level to the repository special unit.
5454
// This function is only used for finding some teams that can be used as branch protection allowlist or reviewers, it isn't really used for access control.
5555
// FIXME: TEAM-UNIT-PERMISSION this logic is not complete, search the fixme keyword to see more details
56-
func GetTeamsWithAccessToAnyRepoUnit(ctx context.Context, orgID, repoID int64, mode perm.AccessMode, unitType unit.Type, unitTypesMore ...unit.Type) ([]*Team, error) {
57-
teams := make([]*Team, 0, 5)
56+
func GetTeamsWithAccessToAnyRepoUnit(ctx context.Context, orgID, repoID int64, mode perm.AccessMode, unitType unit.Type, unitTypesMore ...unit.Type) (teams []*Team, err error) {
57+
teamIDs, err := getTeamIDsWithAccessToAnyRepoUnit(ctx, orgID, repoID, mode, unitType, unitTypesMore...)
58+
if err != nil {
59+
return nil, err
60+
}
61+
if len(teamIDs) == 0 {
62+
return teams, nil
63+
}
64+
err = db.GetEngine(ctx).Where(builder.In("id", teamIDs)).OrderBy("team.name").Find(&teams)
65+
return teams, err
66+
}
5867

68+
func getTeamIDsWithAccessToAnyRepoUnit(ctx context.Context, orgID, repoID int64, mode perm.AccessMode, unitType unit.Type, unitTypesMore ...unit.Type) (teamIDs []int64, err error) {
5969
sub := builder.Select("team_id").From("team_unit").
6070
Where(builder.Expr("team_unit.team_id = team.id")).
6171
And(builder.In("team_unit.type", append([]unit.Type{unitType}, unitTypesMore...))).
6272
And(builder.Expr("team_unit.access_mode >= ?", mode))
6373

64-
err := db.GetEngine(ctx).
74+
err = db.GetEngine(ctx).
75+
Select("team.id").
76+
Table("team").
6577
Join("INNER", "team_repo", "team_repo.team_id = team.id").
66-
And("team_repo.org_id = ?", orgID).
67-
And("team_repo.repo_id = ?", repoID).
78+
And("team_repo.org_id = ? AND team_repo.repo_id = ?", orgID, repoID).
6879
And(builder.Or(
6980
builder.Expr("team.authorize >= ?", mode),
7081
builder.In("team.id", sub),
7182
)).
72-
OrderBy("name").
73-
Find(&teams)
83+
Find(&teamIDs)
84+
return teamIDs, err
85+
}
7486

75-
return teams, err
87+
func GetTeamUserIDsWithAccessToAnyRepoUnit(ctx context.Context, orgID, repoID int64, mode perm.AccessMode, unitType unit.Type, unitTypesMore ...unit.Type) (userIDs []int64, err error) {
88+
teamIDs, err := getTeamIDsWithAccessToAnyRepoUnit(ctx, orgID, repoID, mode, unitType, unitTypesMore...)
89+
if err != nil {
90+
return nil, err
91+
}
92+
if len(teamIDs) == 0 {
93+
return userIDs, nil
94+
}
95+
err = db.GetEngine(ctx).Table("team_user").Select("uid").Where(builder.In("team_id", teamIDs)).Find(&userIDs)
96+
return userIDs, err
7697
}

models/perm/access/repo_permission.go

Lines changed: 28 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import (
1616
repo_model "code.gitea.io/gitea/models/repo"
1717
"code.gitea.io/gitea/models/unit"
1818
user_model "code.gitea.io/gitea/models/user"
19+
"code.gitea.io/gitea/modules/container"
1920
"code.gitea.io/gitea/modules/log"
2021
"code.gitea.io/gitea/modules/setting"
2122
"code.gitea.io/gitea/modules/util"
@@ -498,54 +499,44 @@ func HasAnyUnitAccess(ctx context.Context, userID int64, repo *repo_model.Reposi
498499
return perm.HasAnyUnitAccess(), nil
499500
}
500501

501-
// getUsersWithAccessMode returns users that have at least given access mode to the repository.
502-
func getUsersWithAccessMode(ctx context.Context, repo *repo_model.Repository, mode perm_model.AccessMode) (_ []*user_model.User, err error) {
503-
if err = repo.LoadOwner(ctx); err != nil {
502+
func GetUsersWithUnitAccess(ctx context.Context, repo *repo_model.Repository, mode perm_model.AccessMode, unitType unit.Type) (users []*user_model.User, err error) {
503+
userIDs, err := GetUserIDsWithUnitAccess(ctx, repo, mode, unitType)
504+
if err != nil {
504505
return nil, err
505506
}
507+
if len(userIDs) == 0 {
508+
return users, nil
509+
}
510+
if err = db.GetEngine(ctx).In("id", userIDs.Values()).OrderBy("`name`").Find(&users); err != nil {
511+
return nil, err
512+
}
513+
return users, nil
514+
}
506515

516+
func GetUserIDsWithUnitAccess(ctx context.Context, repo *repo_model.Repository, mode perm_model.AccessMode, unitType unit.Type) (container.Set[int64], error) {
517+
userIDs := container.Set[int64]{}
507518
e := db.GetEngine(ctx)
508519
accesses := make([]*Access, 0, 10)
509-
if err = e.Where("repo_id = ? AND mode >= ?", repo.ID, mode).Find(&accesses); err != nil {
520+
if err := e.Where("repo_id = ? AND mode >= ?", repo.ID, mode).Find(&accesses); err != nil {
510521
return nil, err
511522
}
523+
for _, a := range accesses {
524+
userIDs.Add(a.UserID)
525+
}
512526

513-
// Leave a seat for owner itself to append later, but if owner is an organization
514-
// and just waste 1 unit is cheaper than re-allocate memory once.
515-
users := make([]*user_model.User, 0, len(accesses)+1)
516-
if len(accesses) > 0 {
517-
userIDs := make([]int64, len(accesses))
518-
for i := 0; i < len(accesses); i++ {
519-
userIDs[i] = accesses[i].UserID
520-
}
521-
522-
if err = e.In("id", userIDs).Find(&users); err != nil {
523-
return nil, err
524-
}
527+
if err := repo.LoadOwner(ctx); err != nil {
528+
return nil, err
525529
}
526530
if !repo.Owner.IsOrganization() {
527-
users = append(users, repo.Owner)
528-
}
529-
530-
return users, nil
531-
}
532-
533-
// GetRepoReaders returns all users that have explicit read access or higher to the repository.
534-
func GetRepoReaders(ctx context.Context, repo *repo_model.Repository) (_ []*user_model.User, err error) {
535-
return getUsersWithAccessMode(ctx, repo, perm_model.AccessModeRead)
536-
}
537-
538-
// GetRepoWriters returns all users that have write access to the repository.
539-
func GetRepoWriters(ctx context.Context, repo *repo_model.Repository) (_ []*user_model.User, err error) {
540-
return getUsersWithAccessMode(ctx, repo, perm_model.AccessModeWrite)
541-
}
542-
543-
// IsRepoReader returns true if user has explicit read access or higher to the repository.
544-
func IsRepoReader(ctx context.Context, repo *repo_model.Repository, userID int64) (bool, error) {
545-
if repo.OwnerID == userID {
546-
return true, nil
531+
userIDs.Add(repo.Owner.ID)
532+
} else {
533+
teamUserIDs, err := organization.GetTeamUserIDsWithAccessToAnyRepoUnit(ctx, repo.OwnerID, repo.ID, mode, unitType)
534+
if err != nil {
535+
return nil, err
536+
}
537+
userIDs.AddMultiple(teamUserIDs...)
547538
}
548-
return db.GetEngine(ctx).Where("repo_id = ? AND user_id = ? AND mode >= ?", repo.ID, userID, perm_model.AccessModeRead).Get(&Access{})
539+
return userIDs, nil
549540
}
550541

551542
// CheckRepoUnitUser check whether user could visit the unit of this repository

models/perm/access/repo_permission_test.go

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -169,9 +169,9 @@ func TestGetUserRepoPermission(t *testing.T) {
169169
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4})
170170
team := &organization.Team{OrgID: org.ID, LowerName: "test_team"}
171171
require.NoError(t, db.Insert(ctx, team))
172+
require.NoError(t, db.Insert(ctx, &organization.TeamUser{OrgID: org.ID, TeamID: team.ID, UID: user.ID}))
172173

173174
t.Run("DoerInTeamWithNoRepo", func(t *testing.T) {
174-
require.NoError(t, db.Insert(ctx, &organization.TeamUser{OrgID: org.ID, TeamID: team.ID, UID: user.ID}))
175175
perm, err := GetUserRepoPermission(ctx, repo32, user)
176176
require.NoError(t, err)
177177
assert.Equal(t, perm_model.AccessModeRead, perm.AccessMode)
@@ -219,6 +219,15 @@ func TestGetUserRepoPermission(t *testing.T) {
219219
assert.Equal(t, perm_model.AccessModeNone, perm.AccessMode)
220220
assert.Equal(t, perm_model.AccessModeNone, perm.unitsMode[unit.TypeCode])
221221
assert.Equal(t, perm_model.AccessModeRead, perm.unitsMode[unit.TypeIssues])
222+
223+
users, err := GetUsersWithUnitAccess(ctx, repo3, perm_model.AccessModeRead, unit.TypeIssues)
224+
require.NoError(t, err)
225+
require.Len(t, users, 1)
226+
assert.Equal(t, user.ID, users[0].ID)
227+
228+
users, err = GetUsersWithUnitAccess(ctx, repo3, perm_model.AccessModeWrite, unit.TypeIssues)
229+
require.NoError(t, err)
230+
require.Empty(t, users)
222231
})
223232

224233
require.NoError(t, db.Insert(ctx, repo_model.Collaboration{RepoID: repo3.ID, UserID: user.ID, Mode: perm_model.AccessModeWrite}))
@@ -229,5 +238,10 @@ func TestGetUserRepoPermission(t *testing.T) {
229238
assert.Equal(t, perm_model.AccessModeWrite, perm.AccessMode)
230239
assert.Equal(t, perm_model.AccessModeWrite, perm.unitsMode[unit.TypeCode])
231240
assert.Equal(t, perm_model.AccessModeWrite, perm.unitsMode[unit.TypeIssues])
241+
242+
users, err := GetUsersWithUnitAccess(ctx, repo3, perm_model.AccessModeWrite, unit.TypeIssues)
243+
require.NoError(t, err)
244+
require.Len(t, users, 1)
245+
assert.Equal(t, user.ID, users[0].ID)
232246
})
233247
}

0 commit comments

Comments
 (0)