Skip to content

Commit 2aff6b2

Browse files
authored
Merge branch 'main' into fix-access-expensive
2 parents 3ae9466 + cddd19e commit 2aff6b2

Some content is hidden

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

57 files changed

+2212
-1264
lines changed

models/actions/run_job.go

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
"time"
1111

1212
"code.gitea.io/gitea/models/db"
13+
repo_model "code.gitea.io/gitea/models/repo"
1314
"code.gitea.io/gitea/modules/timeutil"
1415
"code.gitea.io/gitea/modules/util"
1516

@@ -19,11 +20,12 @@ import (
1920
// ActionRunJob represents a job of a run
2021
type ActionRunJob struct {
2122
ID int64
22-
RunID int64 `xorm:"index"`
23-
Run *ActionRun `xorm:"-"`
24-
RepoID int64 `xorm:"index"`
25-
OwnerID int64 `xorm:"index"`
26-
CommitSHA string `xorm:"index"`
23+
RunID int64 `xorm:"index"`
24+
Run *ActionRun `xorm:"-"`
25+
RepoID int64 `xorm:"index"`
26+
Repo *repo_model.Repository `xorm:"-"`
27+
OwnerID int64 `xorm:"index"`
28+
CommitSHA string `xorm:"index"`
2729
IsForkPullRequest bool
2830
Name string `xorm:"VARCHAR(255)"`
2931
Attempt int64
@@ -58,6 +60,17 @@ func (job *ActionRunJob) LoadRun(ctx context.Context) error {
5860
return nil
5961
}
6062

63+
func (job *ActionRunJob) LoadRepo(ctx context.Context) error {
64+
if job.Repo == nil {
65+
repo, err := repo_model.GetRepositoryByID(ctx, job.RepoID)
66+
if err != nil {
67+
return err
68+
}
69+
job.Repo = repo
70+
}
71+
return nil
72+
}
73+
6174
// LoadAttributes load Run if not loaded
6275
func (job *ActionRunJob) LoadAttributes(ctx context.Context) error {
6376
if job == nil {
@@ -83,7 +96,7 @@ func GetRunJobByID(ctx context.Context, id int64) (*ActionRunJob, error) {
8396
return &job, nil
8497
}
8598

86-
func GetRunJobsByRunID(ctx context.Context, runID int64) ([]*ActionRunJob, error) {
99+
func GetRunJobsByRunID(ctx context.Context, runID int64) (ActionJobList, error) {
87100
var jobs []*ActionRunJob
88101
if err := db.GetEngine(ctx).Where("run_id=?", runID).OrderBy("id").Find(&jobs); err != nil {
89102
return nil, err

models/actions/run_job_list.go

Lines changed: 28 additions & 7 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+
repo_model "code.gitea.io/gitea/models/repo"
1011
"code.gitea.io/gitea/modules/container"
1112
"code.gitea.io/gitea/modules/timeutil"
1213

@@ -21,7 +22,33 @@ func (jobs ActionJobList) GetRunIDs() []int64 {
2122
})
2223
}
2324

25+
func (jobs ActionJobList) LoadRepos(ctx context.Context) error {
26+
repoIDs := container.FilterSlice(jobs, func(j *ActionRunJob) (int64, bool) {
27+
return j.RepoID, j.RepoID != 0 && j.Repo == nil
28+
})
29+
if len(repoIDs) == 0 {
30+
return nil
31+
}
32+
33+
repos := make(map[int64]*repo_model.Repository, len(repoIDs))
34+
if err := db.GetEngine(ctx).In("id", repoIDs).Find(&repos); err != nil {
35+
return err
36+
}
37+
for _, j := range jobs {
38+
if j.RepoID > 0 && j.Repo == nil {
39+
j.Repo = repos[j.RepoID]
40+
}
41+
}
42+
return nil
43+
}
44+
2445
func (jobs ActionJobList) LoadRuns(ctx context.Context, withRepo bool) error {
46+
if withRepo {
47+
if err := jobs.LoadRepos(ctx); err != nil {
48+
return err
49+
}
50+
}
51+
2552
runIDs := jobs.GetRunIDs()
2653
runs := make(map[int64]*ActionRun, len(runIDs))
2754
if err := db.GetEngine(ctx).In("id", runIDs).Find(&runs); err != nil {
@@ -30,15 +57,9 @@ func (jobs ActionJobList) LoadRuns(ctx context.Context, withRepo bool) error {
3057
for _, j := range jobs {
3158
if j.RunID > 0 && j.Run == nil {
3259
j.Run = runs[j.RunID]
60+
j.Run.Repo = j.Repo
3361
}
3462
}
35-
if withRepo {
36-
var runsList RunList = make([]*ActionRun, 0, len(runs))
37-
for _, r := range runs {
38-
runsList = append(runsList, r)
39-
}
40-
return runsList.LoadRepos(ctx)
41-
}
4263
return nil
4364
}
4465

models/migrations/migrations.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -378,6 +378,7 @@ func prepareMigrationTasks() []*migration {
378378
newMigration(315, "Add Ephemeral to ActionRunner", v1_24.AddEphemeralToActionRunner),
379379
newMigration(316, "Add description for secrets and variables", v1_24.AddDescriptionForSecretsAndVariables),
380380
newMigration(317, "Add new index for action for heatmap", v1_24.AddNewIndexForUserDashboard),
381+
newMigration(318, "Add anonymous_access_mode for repo_unit", v1_24.AddRepoUnitAnonymousAccessMode),
381382
}
382383
return preparedMigrations
383384
}

models/migrations/v1_24/v318.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// Copyright 2025 The Gitea Authors. All rights reserved.
2+
// SPDX-License-Identifier: MIT
3+
4+
package v1_24 //nolint
5+
6+
import (
7+
"code.gitea.io/gitea/models/perm"
8+
9+
"xorm.io/xorm"
10+
)
11+
12+
func AddRepoUnitAnonymousAccessMode(x *xorm.Engine) error {
13+
type RepoUnit struct { //revive:disable-line:exported
14+
AnonymousAccessMode perm.AccessMode `xorm:"NOT NULL DEFAULT 0"`
15+
}
16+
return x.Sync(&RepoUnit{})
17+
}

models/perm/access/repo_permission.go

Lines changed: 45 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import (
1515
"code.gitea.io/gitea/models/unit"
1616
user_model "code.gitea.io/gitea/models/user"
1717
"code.gitea.io/gitea/modules/log"
18+
"code.gitea.io/gitea/modules/setting"
1819
"code.gitea.io/gitea/modules/util"
1920
)
2021

@@ -25,7 +26,8 @@ type Permission struct {
2526
units []*repo_model.RepoUnit
2627
unitsMode map[unit.Type]perm_model.AccessMode
2728

28-
everyoneAccessMode map[unit.Type]perm_model.AccessMode
29+
everyoneAccessMode map[unit.Type]perm_model.AccessMode // the unit's minimal access mode for every signed-in user
30+
anonymousAccessMode map[unit.Type]perm_model.AccessMode // the unit's minimal access mode for anonymous (non-signed-in) user
2931
}
3032

3133
// IsOwner returns true if current user is the owner of repository.
@@ -39,7 +41,7 @@ func (p *Permission) IsAdmin() bool {
3941
}
4042

4143
// HasAnyUnitAccess returns true if the user might have at least one access mode to any unit of this repository.
42-
// It doesn't count the "everyone access mode".
44+
// It doesn't count the "public(anonymous/everyone) access mode".
4345
func (p *Permission) HasAnyUnitAccess() bool {
4446
for _, v := range p.unitsMode {
4547
if v >= perm_model.AccessModeRead {
@@ -49,13 +51,22 @@ func (p *Permission) HasAnyUnitAccess() bool {
4951
return p.AccessMode >= perm_model.AccessModeRead
5052
}
5153

52-
func (p *Permission) HasAnyUnitAccessOrEveryoneAccess() bool {
54+
func (p *Permission) HasAnyUnitPublicAccess() bool {
55+
for _, v := range p.anonymousAccessMode {
56+
if v >= perm_model.AccessModeRead {
57+
return true
58+
}
59+
}
5360
for _, v := range p.everyoneAccessMode {
5461
if v >= perm_model.AccessModeRead {
5562
return true
5663
}
5764
}
58-
return p.HasAnyUnitAccess()
65+
return false
66+
}
67+
68+
func (p *Permission) HasAnyUnitAccessOrPublicAccess() bool {
69+
return p.HasAnyUnitPublicAccess() || p.HasAnyUnitAccess()
5970
}
6071

6172
// HasUnits returns true if the permission contains attached units
@@ -73,14 +84,16 @@ func (p *Permission) GetFirstUnitRepoID() int64 {
7384
}
7485

7586
// UnitAccessMode returns current user access mode to the specify unit of the repository
76-
// It also considers "everyone access mode"
87+
// It also considers "public (anonymous/everyone) access mode"
7788
func (p *Permission) UnitAccessMode(unitType unit.Type) perm_model.AccessMode {
7889
// if the units map contains the access mode, use it, but admin/owner mode could override it
7990
if m, ok := p.unitsMode[unitType]; ok {
8091
return util.Iif(p.AccessMode >= perm_model.AccessModeAdmin, p.AccessMode, m)
8192
}
8293
// if the units map does not contain the access mode, return the default access mode if the unit exists
83-
unitDefaultAccessMode := max(p.AccessMode, p.everyoneAccessMode[unitType])
94+
unitDefaultAccessMode := p.AccessMode
95+
unitDefaultAccessMode = max(unitDefaultAccessMode, p.anonymousAccessMode[unitType])
96+
unitDefaultAccessMode = max(unitDefaultAccessMode, p.everyoneAccessMode[unitType])
8497
hasUnit := slices.ContainsFunc(p.units, func(u *repo_model.RepoUnit) bool { return u.Type == unitType })
8598
return util.Iif(hasUnit, unitDefaultAccessMode, perm_model.AccessModeNone)
8699
}
@@ -171,27 +184,41 @@ func (p *Permission) LogString() string {
171184
format += "\n\tunitsMode[%-v]: %-v"
172185
args = append(args, key.LogString(), value.LogString())
173186
}
187+
format += "\n\tanonymousAccessMode: %-v"
188+
args = append(args, p.anonymousAccessMode)
174189
format += "\n\teveryoneAccessMode: %-v"
175190
args = append(args, p.everyoneAccessMode)
176191
format += "\n\t]>"
177192
return fmt.Sprintf(format, args...)
178193
}
179194

195+
func applyPublicAccessPermission(unitType unit.Type, accessMode perm_model.AccessMode, modeMap *map[unit.Type]perm_model.AccessMode) {
196+
if setting.Repository.ForcePrivate {
197+
return
198+
}
199+
if accessMode >= perm_model.AccessModeRead && accessMode > (*modeMap)[unitType] {
200+
if *modeMap == nil {
201+
*modeMap = make(map[unit.Type]perm_model.AccessMode)
202+
}
203+
(*modeMap)[unitType] = accessMode
204+
}
205+
}
206+
180207
func finalProcessRepoUnitPermission(user *user_model.User, perm *Permission) {
208+
// apply public (anonymous) access permissions
209+
for _, u := range perm.units {
210+
applyPublicAccessPermission(u.Type, u.AnonymousAccessMode, &perm.anonymousAccessMode)
211+
}
212+
181213
if user == nil || user.ID <= 0 {
182214
// for anonymous access, it could be:
183215
// AccessMode is None or Read, units has repo units, unitModes is nil
184216
return
185217
}
186218

187-
// apply everyone access permissions
219+
// apply public (everyone) access permissions
188220
for _, u := range perm.units {
189-
if u.EveryoneAccessMode >= perm_model.AccessModeRead && u.EveryoneAccessMode > perm.everyoneAccessMode[u.Type] {
190-
if perm.everyoneAccessMode == nil {
191-
perm.everyoneAccessMode = make(map[unit.Type]perm_model.AccessMode)
192-
}
193-
perm.everyoneAccessMode[u.Type] = u.EveryoneAccessMode
194-
}
221+
applyPublicAccessPermission(u.Type, u.EveryoneAccessMode, &perm.everyoneAccessMode)
195222
}
196223

197224
if perm.unitsMode == nil {
@@ -209,6 +236,11 @@ func finalProcessRepoUnitPermission(user *user_model.User, perm *Permission) {
209236
break
210237
}
211238
}
239+
for t := range perm.anonymousAccessMode {
240+
if shouldKeep = shouldKeep || u.Type == t; shouldKeep {
241+
break
242+
}
243+
}
212244
for t := range perm.everyoneAccessMode {
213245
if shouldKeep = shouldKeep || u.Type == t; shouldKeep {
214246
break

models/perm/access/repo_permission_test.go

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,21 @@ func TestHasAnyUnitAccess(t *testing.T) {
2222
units: []*repo_model.RepoUnit{{Type: unit.TypeWiki}},
2323
}
2424
assert.False(t, perm.HasAnyUnitAccess())
25-
assert.False(t, perm.HasAnyUnitAccessOrEveryoneAccess())
25+
assert.False(t, perm.HasAnyUnitAccessOrPublicAccess())
2626

2727
perm = Permission{
2828
units: []*repo_model.RepoUnit{{Type: unit.TypeWiki}},
2929
everyoneAccessMode: map[unit.Type]perm_model.AccessMode{unit.TypeIssues: perm_model.AccessModeRead},
3030
}
3131
assert.False(t, perm.HasAnyUnitAccess())
32-
assert.True(t, perm.HasAnyUnitAccessOrEveryoneAccess())
32+
assert.True(t, perm.HasAnyUnitAccessOrPublicAccess())
33+
34+
perm = Permission{
35+
units: []*repo_model.RepoUnit{{Type: unit.TypeWiki}},
36+
anonymousAccessMode: map[unit.Type]perm_model.AccessMode{unit.TypeIssues: perm_model.AccessModeRead},
37+
}
38+
assert.False(t, perm.HasAnyUnitAccess())
39+
assert.True(t, perm.HasAnyUnitAccessOrPublicAccess())
3340

3441
perm = Permission{
3542
AccessMode: perm_model.AccessModeRead,
@@ -43,7 +50,7 @@ func TestHasAnyUnitAccess(t *testing.T) {
4350
assert.True(t, perm.HasAnyUnitAccess())
4451
}
4552

46-
func TestApplyEveryoneRepoPermission(t *testing.T) {
53+
func TestApplyPublicAccessRepoPermission(t *testing.T) {
4754
perm := Permission{
4855
AccessMode: perm_model.AccessModeNone,
4956
units: []*repo_model.RepoUnit{
@@ -53,6 +60,15 @@ func TestApplyEveryoneRepoPermission(t *testing.T) {
5360
finalProcessRepoUnitPermission(nil, &perm)
5461
assert.False(t, perm.CanRead(unit.TypeWiki))
5562

63+
perm = Permission{
64+
AccessMode: perm_model.AccessModeNone,
65+
units: []*repo_model.RepoUnit{
66+
{Type: unit.TypeWiki, AnonymousAccessMode: perm_model.AccessModeRead},
67+
},
68+
}
69+
finalProcessRepoUnitPermission(nil, &perm)
70+
assert.True(t, perm.CanRead(unit.TypeWiki))
71+
5672
perm = Permission{
5773
AccessMode: perm_model.AccessModeNone,
5874
units: []*repo_model.RepoUnit{

models/repo/repo_unit.go

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -42,12 +42,13 @@ func (err ErrUnitTypeNotExist) Unwrap() error {
4242

4343
// RepoUnit describes all units of a repository
4444
type RepoUnit struct { //revive:disable-line:exported
45-
ID int64
46-
RepoID int64 `xorm:"INDEX(s)"`
47-
Type unit.Type `xorm:"INDEX(s)"`
48-
Config convert.Conversion `xorm:"TEXT"`
49-
CreatedUnix timeutil.TimeStamp `xorm:"INDEX CREATED"`
50-
EveryoneAccessMode perm.AccessMode `xorm:"NOT NULL DEFAULT 0"`
45+
ID int64
46+
RepoID int64 `xorm:"INDEX(s)"`
47+
Type unit.Type `xorm:"INDEX(s)"`
48+
Config convert.Conversion `xorm:"TEXT"`
49+
CreatedUnix timeutil.TimeStamp `xorm:"INDEX CREATED"`
50+
AnonymousAccessMode perm.AccessMode `xorm:"NOT NULL DEFAULT 0"`
51+
EveryoneAccessMode perm.AccessMode `xorm:"NOT NULL DEFAULT 0"`
5152
}
5253

5354
func init() {
@@ -341,3 +342,9 @@ func UpdateRepoUnit(ctx context.Context, unit *RepoUnit) error {
341342
_, err := db.GetEngine(ctx).ID(unit.ID).Update(unit)
342343
return err
343344
}
345+
346+
func UpdateRepoUnitPublicAccess(ctx context.Context, unit *RepoUnit) error {
347+
_, err := db.GetEngine(ctx).Where("repo_id=? AND `type`=?", unit.RepoID, unit.Type).
348+
Cols("anonymous_access_mode", "everyone_access_mode").Update(unit)
349+
return err
350+
}

0 commit comments

Comments
 (0)