Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
332 commits
Select commit Hold shift + click to select a range
f5d4ce6
compile errors
Excellencedev Jan 5, 2026
012c9e0
...
Excellencedev Jan 5, 2026
b37a967
logs
Excellencedev Jan 5, 2026
15c19f6
...
Excellencedev Jan 5, 2026
350bcab
fix bug
Excellencedev Jan 5, 2026
d262948
Merge branch 'main' into fix-24635
Excellencedev Jan 6, 2026
9610d7f
Implement all requested changes
Excellencedev Jan 6, 2026
b4a17df
lints
Excellencedev Jan 6, 2026
3fb03fb
lint
Excellencedev Jan 6, 2026
dcf43af
fix ui issues
Excellencedev Jan 6, 2026
ba3a3a7
Feedback
Excellencedev Jan 7, 2026
655733e
fix
Excellencedev Jan 7, 2026
28dff2a
update parser
Excellencedev Jan 7, 2026
43931dc
refactor the parser
Excellencedev Jan 7, 2026
a5debd9
add releases and projects units
Excellencedev Jan 7, 2026
f8a0b25
resolve todo
Excellencedev Jan 7, 2026
1dfc172
fixes
Excellencedev Jan 7, 2026
1840f0a
formatting issues
Excellencedev Jan 7, 2026
7364953
...
Excellencedev Jan 7, 2026
4e524d3
improve comments
Excellencedev Jan 8, 2026
79c38fe
Merge branch 'main' into fix-24635
Excellencedev Jan 11, 2026
f7fc879
Merge branch 'main' into fix-24635
Excellencedev Jan 16, 2026
feb791c
feedback fixes
Excellencedev Jan 16, 2026
7cccb84
fixes
Excellencedev Jan 16, 2026
6d14a69
ui fixes
Excellencedev Jan 16, 2026
87d9f86
Merge branch 'main' into fix-24635
Excellencedev Jan 16, 2026
01a328b
fixes
Excellencedev Jan 16, 2026
5067f1d
fixes
Excellencedev Jan 16, 2026
27a4055
fix
Excellencedev Jan 16, 2026
2317080
logs
Excellencedev Jan 16, 2026
130b94b
..
Excellencedev Jan 16, 2026
4ed81fe
fix
Excellencedev Jan 17, 2026
a8c2d13
refactor ui
Excellencedev Jan 17, 2026
068ef6d
lints
Excellencedev Jan 17, 2026
1934c55
Merge branch 'main' into fix-24635
Excellencedev Jan 17, 2026
9352cc2
update test
Excellencedev Jan 17, 2026
493d51d
fix test
Excellencedev Jan 17, 2026
b6bf0a1
Merge branch 'fix-24635' of https://github.com/Excellencedev/gitea in…
Excellencedev Jan 17, 2026
c770087
fix formatting
Excellencedev Jan 17, 2026
2480c30
CrossRepoMode
Excellencedev Jan 17, 2026
f5c5775
CrossRepoMode tests
Excellencedev Jan 17, 2026
77871ef
fixes
Excellencedev Jan 18, 2026
c9ea591
format
Excellencedev Jan 18, 2026
4410d73
use ToString
Excellencedev Jan 18, 2026
ef139fa
Merge branch 'main' into fix-24635
Excellencedev Jan 24, 2026
57d8b82
readd migration
Excellencedev Jan 24, 2026
0d63aa8
...
Excellencedev Jan 24, 2026
33ef56e
lints
Excellencedev Jan 24, 2026
f7a4406
copyright
Excellencedev Jan 24, 2026
a7c2c96
fix saving issue
Excellencedev Jan 24, 2026
574d317
Update models/migrations/migrations.go
ChristopherHX Jan 25, 2026
883d652
patch-1
Excellencedev Jan 25, 2026
493f133
patch-2
Excellencedev Jan 25, 2026
1de6d43
Merge branch 'fix-24635' of https://github.com/Excellencedev/gitea in…
Excellencedev Jan 25, 2026
440cfa1
fmt
Excellencedev Jan 25, 2026
e0c5381
Update models/migrations/v1_26/V326.go
Excellencedev Jan 31, 2026
cee21ad
Update tests/integration/actions_persistence_test.go
Excellencedev Jan 31, 2026
916806c
Update routers/web/org/setting/actions.go
Excellencedev Jan 31, 2026
2107fd6
Update routers/api/packages/api.go
Excellencedev Jan 31, 2026
f5c4c33
Update routers/api/v1/repo/file.go
Excellencedev Jan 31, 2026
005de17
Address Copilot review
Excellencedev Jan 31, 2026
7636c6c
remove actionsperm
Excellencedev Jan 31, 2026
2096877
fmt
Excellencedev Jan 31, 2026
f08356b
Merge branch 'main' into fix-24635
Excellencedev Feb 1, 2026
a2b88d6
ActionsTaskID
Excellencedev Feb 1, 2026
75023da
missing imports
Excellencedev Feb 1, 2026
ea981c2
fmt
Excellencedev Feb 1, 2026
6a7c528
Merge branch 'main' into fix-24635
Excellencedev Feb 6, 2026
a59b428
f8xes from feedback
Excellencedev Feb 6, 2026
d3fa0ec
update refernces
Excellencedev Feb 7, 2026
e2c14de
Merge branch 'main' into fix-24635
Excellencedev Feb 7, 2026
0912b12
fix lint
Excellencedev Feb 7, 2026
b95361c
extra blank lines
Excellencedev Feb 7, 2026
a2fc97a
Fix comment
ChristopherHX Feb 7, 2026
5c3493f
logic fixes
ChristopherHX Feb 7, 2026
9425be4
cross repo package access respect permission none and require package…
ChristopherHX Feb 7, 2026
0a3049a
revert, packages_model.Type(ctx.PathParam("type")) does not work
ChristopherHX Feb 7, 2026
fd0aed3
Refactor repo_permissions to repect none permission
ChristopherHX Feb 7, 2026
137efea
Store Readonly in database for PR from forks
ChristopherHX Feb 7, 2026
b04f759
refactor functions Effective => Default / no fork param
ChristopherHX Feb 7, 2026
c2045d2
Allow public read for public repos
ChristopherHX Feb 7, 2026
fc57605
clamp pr from fork
ChristopherHX Feb 7, 2026
d8ce6d9
Refactor Simplify broken container permission checks
ChristopherHX Feb 7, 2026
fc1620c
update tests
ChristopherHX Feb 7, 2026
455dfbb
Fix lint
ChristopherHX Feb 7, 2026
a6b5417
spelling
ChristopherHX Feb 7, 2026
e91e7ee
Merge branch 'main' into fix-24635
Excellencedev Feb 8, 2026
aba7f66
Actions package permissions
ChristopherHX Feb 9, 2026
42e9a6d
fix grantMode for private org
ChristopherHX Feb 9, 2026
50405cb
fix typo
ChristopherHX Feb 9, 2026
8736615
fix pkg type pub
ChristopherHX Feb 9, 2026
eed2ad9
fix code
ChristopherHX Feb 9, 2026
1806b29
fix lint
ChristopherHX Feb 9, 2026
9c01831
remove test stub
ChristopherHX Feb 9, 2026
56486b8
Revert "remove test stub"
ChristopherHX Feb 9, 2026
ae81b00
Revert Broken Package Access + single test
ChristopherHX Feb 9, 2026
9ce2472
add missing return
ChristopherHX Feb 9, 2026
6b4ed50
Merge branch 'main' into fix-24635
silverwind Feb 12, 2026
b4c61a4
Merge branch 'main' into fix-24635
Excellencedev Feb 13, 2026
08063e7
Apply suggestion from @silverwind
silverwind Feb 13, 2026
3e3e081
Update routers/private/hook_pre_receive.go
Excellencedev Feb 13, 2026
c9999c4
Address feedbac
Excellencedev Feb 14, 2026
ca6b32f
next
Excellencedev Feb 14, 2026
9e7db02
..
Excellencedev Feb 14, 2026
04299c9
fmt
Excellencedev Feb 14, 2026
7755c83
Refactor Cross-Repo Permission Logic
Excellencedev Feb 15, 2026
d7a8957
revert pacage.go
Excellencedev Feb 15, 2026
a8b9575
update the permission parser tests to include the projects scope
Excellencedev Feb 15, 2026
c636e81
bug
Excellencedev Feb 15, 2026
f9a64b6
simplify code
Zettat123 Feb 15, 2026
2d9794b
Merge pull request #2 from Zettat123/improve-token-perms-check
Excellencedev Feb 16, 2026
c684dd9
Merge branch 'main' into fix-24635
silverwind Feb 16, 2026
42fcef9
remove .CsrfTokenHtml
silverwind Feb 16, 2026
e17a531
address silverwind review
Excellencedev Feb 16, 2026
ddbc47a
Revert "remove .CsrfTokenHtml"
Excellencedev Feb 16, 2026
e6d5e82
Revert "address silverwind review"
Excellencedev Feb 16, 2026
18f8247
Reapply "remove .CsrfTokenHtml"
Excellencedev Feb 16, 2026
c31ebf6
...
Excellencedev Feb 16, 2026
89a6783
...
Excellencedev Feb 16, 2026
b7a92b8
...
Excellencedev Feb 17, 2026
d1126e9
fix tests
Excellencedev Feb 17, 2026
b1d1c64
Apply suggestion from @silverwind
silverwind Feb 17, 2026
214424c
Apply suggestion from @silverwind
silverwind Feb 17, 2026
ae62bad
Apply suggestion from @silverwind
silverwind Feb 17, 2026
3411280
Apply suggestion from @silverwind
silverwind Feb 17, 2026
ea4a284
Apply suggestion from @silverwind
silverwind Feb 17, 2026
8ea2cbd
Apply suggestion from @silverwind
silverwind Feb 17, 2026
381bc93
silverwind review
Excellencedev Feb 17, 2026
018339e
Merge branch 'fix-24635' of https://github.com/Excellencedev/gitea in…
Excellencedev Feb 17, 2026
ebed469
Fix build error: uncomment ActionsTokenPermissionModeCustom constant
silverwind Feb 17, 2026
618e21e
unt
Excellencedev Feb 17, 2026
b66c331
remove
Excellencedev Feb 17, 2026
8caf9e4
unused
Excellencedev Feb 17, 2026
6333714
Merge branch 'main' into fix-24635
Excellencedev Feb 17, 2026
8770d0b
newline
Excellencedev Feb 17, 2026
ed525fa
Merge branch 'main' into fix-24635
silverwind Feb 18, 2026
f0fc5a2
cleanup
Excellencedev Feb 19, 2026
ed80060
fmt
Excellencedev Feb 19, 2026
481b9ca
test
Excellencedev Feb 19, 2026
61c8bda
cleanup
Excellencedev Feb 19, 2026
b097095
cleanup
Excellencedev Feb 19, 2026
20ad9de
FEEDBACK
Excellencedev Feb 21, 2026
cb93b4b
lnt
Excellencedev Feb 21, 2026
f386234
Merge branch 'main' into fix-24635
silverwind Feb 22, 2026
2efe144
Fix form alignment in actions general settings shared template
silverwind Feb 22, 2026
0498df7
Fix review findings for actions token permissions
silverwind Feb 22, 2026
6110201
Extract shared permissions table template to reduce duplication
silverwind Feb 22, 2026
0bbafb6
Validate stored ActionsTokenPermissionMode against known values
silverwind Feb 22, 2026
2eb2044
Fix default cross-repo access mode to allow access by default
silverwind Feb 22, 2026
827c278
Merge branch 'main' into fix-24635
Excellencedev Feb 22, 2026
0dac17a
Merge branch 'main' into fix-24635
Excellencedev Feb 23, 2026
41c1d97
Latest feedback
Excellencedev Feb 23, 2026
c933f1c
com errors
Excellencedev Feb 23, 2026
9cc110f
fx
Excellencedev Feb 23, 2026
e9c5382
fx
Excellencedev Feb 23, 2026
b325f3e
Merge branch 'main' into fix-24635
Excellencedev Feb 23, 2026
0880942
add docs
Excellencedev Feb 23, 2026
5b7d7a5
doc changes
Excellencedev Feb 23, 2026
b1acdc2
last changes
Excellencedev Feb 23, 2026
9d2f890
feedback
Excellencedev Feb 28, 2026
195ee7d
err
Excellencedev Feb 28, 2026
9b95e0a
test
Excellencedev Feb 28, 2026
0427102
changes
Excellencedev Mar 1, 2026
81d4263
Merge branch 'main' into fix-24635
Excellencedev Mar 3, 2026
2084180
feedbac
Excellencedev Mar 3, 2026
b7f6bba
evrythng
Excellencedev Mar 5, 2026
17cc432
refactor
wxiaoguang Mar 5, 2026
ca2b627
clean up
wxiaoguang Mar 5, 2026
3eef9ed
clean up
Excellencedev Mar 5, 2026
85c4bef
remove fallback
Excellencedev Mar 5, 2026
400ab94
update document for packages permission
wxiaoguang Mar 5, 2026
393f9c4
refactor
wxiaoguang Mar 5, 2026
6a9dcb3
revert
wxiaoguang Mar 5, 2026
d2245c1
fix lint
wxiaoguang Mar 5, 2026
4cc1c1c
change
Excellencedev Mar 6, 2026
85d8431
change
Excellencedev Mar 6, 2026
952510a
Merge branch 'main' into fix-24635
Excellencedev Mar 6, 2026
d755ad4
fixes
Zettat123 Mar 6, 2026
1633d7b
fix test
Zettat123 Mar 6, 2026
1e439da
fix db query
Zettat123 Mar 6, 2026
7da98cc
check target repo config
Zettat123 Mar 7, 2026
290b2ce
new test
Excellencedev Mar 7, 2026
00b9f0f
fmt
Excellencedev Mar 7, 2026
bd7e748
fx test
Excellencedev Mar 7, 2026
1974c31
change
Excellencedev Mar 7, 2026
d7cf2b9
.
Excellencedev Mar 7, 2026
dd25d16
.
Excellencedev Mar 7, 2026
d22a375
Merge branch 'main' into fix-24635
silverwind Mar 10, 2026
0641565
Fix actions token permission bugs found during review
silverwind Mar 10, 2026
b9012fd
do not use GetXxx
wxiaoguang Mar 10, 2026
dd4f6f4
split actions unit config and rename vars
wxiaoguang Mar 11, 2026
f200c1d
merge git push env
wxiaoguang Mar 11, 2026
e32e37f
merge git push env
wxiaoguang Mar 11, 2026
5c6ae7e
remove ActionsCrossRepoMode=all (confusing and will be abused), clean up
wxiaoguang Mar 11, 2026
c6bb15c
dead translation
wxiaoguang Mar 11, 2026
109dc10
fix text
wxiaoguang Mar 11, 2026
c39b98f
Merge branch 'main' into fix-24635
Excellencedev Mar 11, 2026
01a6ce8
conflct
Excellencedev Mar 11, 2026
2f2bd8d
delete
Excellencedev Mar 11, 2026
1dce09b
conflct
Excellencedev Mar 11, 2026
d29f20c
fmt
Excellencedev Mar 11, 2026
2e4a779
26
Excellencedev Mar 11, 2026
ed82dff
address feedback
Excellencedev Mar 11, 2026
753d8c8
.
Excellencedev Mar 11, 2026
fda2362
changes
Excellencedev Mar 13, 2026
4bdecd2
fx tests
Excellencedev Mar 13, 2026
57e1288
Handle Nil Doer in Pushing Environment
Excellencedev Mar 13, 2026
fd8db9f
Fixing Test Failure
Excellencedev Mar 13, 2026
952fb03
fmt
Excellencedev Mar 13, 2026
824ed3c
Merge branch 'main' into fix-24635
wxiaoguang Mar 13, 2026
65ccecf
comment
Excellencedev Mar 13, 2026
0ea45c2
Merge branch 'fix-24635' of https://github.com/Excellencedev/gitea in…
Excellencedev Mar 13, 2026
8a54bcd
Update modules/repository/env.go
wxiaoguang Mar 13, 2026
b362a2a
fix git http push env
wxiaoguang Mar 13, 2026
dda0dff
remove duplicate EnvRepoID, it has already been set in DoerPushingEnv…
wxiaoguang Mar 13, 2026
5b38323
Update models/perm/access/repo_permission.go
Excellencedev Mar 13, 2026
3278b5e
Update models/perm/access/repo_permission.go
Excellencedev Mar 13, 2026
2a6f60d
fix test, that asserted now unexpected behavior
ChristopherHX Mar 13, 2026
0716eeb
WIP
Excellencedev Mar 14, 2026
183692c
Merge branch 'fix-24635' of https://github.com/Excellencedev/gitea in…
Excellencedev Mar 14, 2026
5a7bfdb
Merge branch 'main' into feature-actions-permission
wxiaoguang Mar 14, 2026
b7a91a7
refactor
wxiaoguang Mar 14, 2026
278bf61
fix layout bugs
wxiaoguang Mar 14, 2026
1e6fa1b
fix test
wxiaoguang Mar 14, 2026
1e1e1bf
fix test
wxiaoguang Mar 14, 2026
cb2a88a
fix test
wxiaoguang Mar 14, 2026
c989cd0
clean up
wxiaoguang Mar 14, 2026
172b18f
reformat doc
wxiaoguang Mar 14, 2026
8a268e9
fix migration
wxiaoguang Mar 14, 2026
aebde5e
fix unrelated repos bug
Excellencedev Mar 14, 2026
35a91b9
fine tune help text
wxiaoguang Mar 14, 2026
5b40171
fix layout
wxiaoguang Mar 14, 2026
598530b
fine tune help text
wxiaoguang Mar 14, 2026
4bb177f
fix tr key
wxiaoguang Mar 14, 2026
459d6de
show correct permission table inherited from owner
wxiaoguang Mar 14, 2026
0975485
do not render Actions Token Permissions if Actions is disabled
wxiaoguang Mar 14, 2026
b10db5d
change
Excellencedev Mar 14, 2026
46f9ad1
Merge branch 'fix-24635' of https://github.com/Excellencedev/gitea in…
Excellencedev Mar 14, 2026
eacdd04
remove useless attribute
Excellencedev Mar 14, 2026
bb64b07
Migration fix
Excellencedev Mar 15, 2026
e1d11ae
fix form
wxiaoguang Mar 16, 2026
ade5a6c
use explicit var name
wxiaoguang Mar 16, 2026
09454d7
Merge branch 'main' into feature-actions-permission
wxiaoguang Mar 17, 2026
f84981d
fix merge
wxiaoguang Mar 17, 2026
eb4ead7
fix tests
wxiaoguang Mar 17, 2026
9950752
fix tests
wxiaoguang Mar 17, 2026
c556da0
fix tests
wxiaoguang Mar 17, 2026
4ac9a9c
fix tests
wxiaoguang Mar 17, 2026
319fb31
Merge branch 'main' into fix-24635
lunny Mar 21, 2026
6aeda11
Merge branch 'main' into fix-24635
GiteaBot Mar 21, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions cmd/hook.go
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ Gitea or set your environment appropriately.`, "")
userID, _ := strconv.ParseInt(os.Getenv(repo_module.EnvPusherID), 10, 64)
prID, _ := strconv.ParseInt(os.Getenv(repo_module.EnvPRID), 10, 64)
deployKeyID, _ := strconv.ParseInt(os.Getenv(repo_module.EnvDeployKeyID), 10, 64)
actionPerm, _ := strconv.Atoi(os.Getenv(repo_module.EnvActionPerm))
actionsTaskID, _ := strconv.ParseInt(os.Getenv(repo_module.EnvActionsTaskID), 10, 64)
Comment thread
wxiaoguang marked this conversation as resolved.

hookOptions := private.HookOptions{
UserID: userID,
Expand All @@ -204,7 +204,7 @@ Gitea or set your environment appropriately.`, "")
GitPushOptions: pushOptions(),
PullRequestID: prID,
DeployKeyID: deployKeyID,
ActionPerm: actionPerm,
ActionsTaskID: actionsTaskID,
IsWiki: isWiki,
}

Expand Down
74 changes: 74 additions & 0 deletions models/actions/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
// Copyright 2026 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT

package actions

import (
"context"

"code.gitea.io/gitea/models/perm"
repo_model "code.gitea.io/gitea/models/repo"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/json"
"code.gitea.io/gitea/modules/util"

"xorm.io/xorm/convert"
)

// OwnerActionsConfig defines the Actions configuration for a user or organization
type OwnerActionsConfig struct {
// TokenPermissionMode defines the default permission mode (permissive, restricted)
TokenPermissionMode repo_model.ActionsTokenPermissionMode `json:"token_permission_mode,omitempty"`

// MaxTokenPermissions defines the absolute maximum permissions any token can have in this context.
MaxTokenPermissions *repo_model.ActionsTokenPermissions `json:"max_token_permissions,omitempty"`

// AllowedCrossRepoIDs is a list of specific repo IDs that can be accessed cross-repo
AllowedCrossRepoIDs []int64 `json:"allowed_cross_repo_ids,omitempty"`
}

var _ convert.ConversionFrom = (*OwnerActionsConfig)(nil)

func (cfg *OwnerActionsConfig) FromDB(bytes []byte) error {
_ = json.Unmarshal(bytes, cfg)
cfg.TokenPermissionMode, _ = util.EnumValue(cfg.TokenPermissionMode)
return nil
}

// GetOwnerActionsConfig loads the OwnerActionsConfig for a user or organization from user settings
// It returns a default config if no setting is found
func GetOwnerActionsConfig(ctx context.Context, userID int64) (ret OwnerActionsConfig, err error) {
return user_model.GetUserSettingJSON(ctx, userID, user_model.SettingsKeyActionsConfig, ret)
}

// SetOwnerActionsConfig saves the OwnerActionsConfig for a user or organization to user settings
func SetOwnerActionsConfig(ctx context.Context, userID int64, cfg OwnerActionsConfig) error {
return user_model.SetUserSettingJSON(ctx, userID, user_model.SettingsKeyActionsConfig, cfg)
}

// GetDefaultTokenPermissions returns the default token permissions by its TokenPermissionMode.
func (cfg *OwnerActionsConfig) GetDefaultTokenPermissions() repo_model.ActionsTokenPermissions {
switch cfg.TokenPermissionMode {
case repo_model.ActionsTokenPermissionModeRestricted:
return repo_model.MakeRestrictedPermissions()
case repo_model.ActionsTokenPermissionModePermissive:
return repo_model.MakeActionsTokenPermissions(perm.AccessModeWrite)
default:
return repo_model.MakeActionsTokenPermissions(perm.AccessModeNone)
}
}

// GetMaxTokenPermissions returns the maximum allowed permissions
func (cfg *OwnerActionsConfig) GetMaxTokenPermissions() repo_model.ActionsTokenPermissions {
if cfg.MaxTokenPermissions != nil {
return *cfg.MaxTokenPermissions
}
// Default max is write for everything
return repo_model.MakeActionsTokenPermissions(perm.AccessModeWrite)
}

// ClampPermissions ensures that the given permissions don't exceed the maximum
func (cfg *OwnerActionsConfig) ClampPermissions(perms repo_model.ActionsTokenPermissions) repo_model.ActionsTokenPermissions {
maxPerms := cfg.GetMaxTokenPermissions()
return repo_model.ClampActionsTokenPermissions(perms, maxPerms)
}
5 changes: 5 additions & 0 deletions models/actions/run_job.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,11 @@ type ActionRunJob struct {
ConcurrencyGroup string `xorm:"index(repo_concurrency) NOT NULL DEFAULT ''"` // evaluated concurrency.group
ConcurrencyCancel bool `xorm:"NOT NULL DEFAULT FALSE"` // evaluated concurrency.cancel-in-progress

// TokenPermissions stores the explicit permissions from workflow/job YAML (no org/repo clamps applied).
// Org/repo clamps are enforced when the token is used at runtime.
// It is JSON-encoded repo_model.ActionsTokenPermissions and may be empty if not specified.
TokenPermissions *repo_model.ActionsTokenPermissions `xorm:"JSON TEXT"`

Started timeutil.TimeStamp
Stopped timeutil.TimeStamp
Created timeutil.TimeStamp `xorm:"created"`
Expand Down
60 changes: 60 additions & 0 deletions models/actions/token_permissions.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// Copyright 2026 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT

package actions

import (
"context"

repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/models/unit"
)

// ComputeTaskTokenPermissions computes the effective permissions for a job token against the target repository.
// It uses the job's stored permissions (if any), then applies org/repo clamps and fork/cross-repo restrictions.
// Note: target repository access policy checks are enforced in GetActionsUserRepoPermission; this function only computes the job token's effective permission ceiling.
func ComputeTaskTokenPermissions(ctx context.Context, task *ActionTask, targetRepo *repo_model.Repository) (ret repo_model.ActionsTokenPermissions, err error) {
if err := task.LoadJob(ctx); err != nil {
return ret, err
}
if err := task.Job.LoadRepo(ctx); err != nil {
return ret, err
}
runRepo := task.Job.Repo

if err := runRepo.LoadOwner(ctx); err != nil {
return ret, err
}

repoActionsCfg := runRepo.MustGetUnit(ctx, unit.TypeActions).ActionsConfig()
ownerActionsCfg, err := GetOwnerActionsConfig(ctx, runRepo.OwnerID)
if err != nil {
return ret, err
}

var jobDeclaredPerms repo_model.ActionsTokenPermissions
if task.Job.TokenPermissions != nil {
jobDeclaredPerms = *task.Job.TokenPermissions
} else if repoActionsCfg.OverrideOwnerConfig {
jobDeclaredPerms = repoActionsCfg.GetDefaultTokenPermissions()
} else {
jobDeclaredPerms = ownerActionsCfg.GetDefaultTokenPermissions()
}

var effectivePerms repo_model.ActionsTokenPermissions
if repoActionsCfg.OverrideOwnerConfig {
effectivePerms = repoActionsCfg.ClampPermissions(jobDeclaredPerms)
} else {
effectivePerms = ownerActionsCfg.ClampPermissions(jobDeclaredPerms)
}

// Cross-repository access and fork pull requests are strictly read-only for security.
// This ensures a "task repo" cannot gain write access to other repositories via CrossRepoAccess settings.
isSameRepo := task.Job.RepoID == targetRepo.ID
restrictCrossRepoAccess := task.IsForkPullRequest || !isSameRepo
if restrictCrossRepoAccess {
effectivePerms = repo_model.ClampActionsTokenPermissions(effectivePerms, repo_model.MakeRestrictedPermissions())
}

return effectivePerms, nil
}
1 change: 1 addition & 0 deletions models/migrations/migrations.go
Original file line number Diff line number Diff line change
Expand Up @@ -402,6 +402,7 @@ func prepareMigrationTasks() []*migration {
newMigration(325, "Fix missed repo_id when migrate attachments", v1_26.FixMissedRepoIDWhenMigrateAttachments),
newMigration(326, "Migrate commit status target URL to use run ID and job ID", v1_26.FixCommitStatusTargetURLToUseRunAndJobID),
newMigration(327, "Add disabled state to action runners", v1_26.AddDisabledToActionRunner),
newMigration(328, "Add TokenPermissions column to ActionRunJob", v1_26.AddTokenPermissionsToActionRunJob),
}
return preparedMigrations
}
Expand Down
16 changes: 16 additions & 0 deletions models/migrations/v1_26/v328.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// Copyright 2026 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT

package v1_26

import (
"xorm.io/xorm"
)

func AddTokenPermissionsToActionRunJob(x *xorm.Engine) error {
type ActionRunJob struct {
TokenPermissions string `xorm:"JSON TEXT"`
}
_, err := x.SyncWithOptions(xorm.SyncOptions{IgnoreDropIndices: true}, new(ActionRunJob))
return err
}
155 changes: 155 additions & 0 deletions models/perm/access/actions_repo_permission_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
// Copyright 2026 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT

package access

import (
"testing"

actions_model "code.gitea.io/gitea/models/actions"
"code.gitea.io/gitea/models/db"
perm_model "code.gitea.io/gitea/models/perm"
repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/models/unit"
"code.gitea.io/gitea/models/unittest"
user_model "code.gitea.io/gitea/models/user"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

func TestGetActionsUserRepoPermission(t *testing.T) {
require.NoError(t, unittest.PrepareTestDatabase())
ctx := t.Context()

// Use fixtures for repos and users
repo4 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 4}) // Public, Owner 5, has Actions unit
repo2 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2}) // Private, Owner 2, no Actions unit in fixtures
repo15 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 15}) // Private, Owner 2, no Actions unit in fixtures
owner2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
actionsUser := user_model.NewActionsUser()

// Ensure repo2 and repo15 have Actions units for testing configuration
for _, r := range []*repo_model.Repository{repo2, repo15} {
require.NoError(t, db.Insert(ctx, &repo_model.RepoUnit{
RepoID: r.ID,
Type: unit.TypeActions,
Config: &repo_model.ActionsConfig{},
}))
}

t.Run("SameRepo_Public", func(t *testing.T) {
task47 := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionTask{ID: 47})
require.Equal(t, repo4.ID, task47.RepoID)

perm, err := GetActionsUserRepoPermission(ctx, repo4, actionsUser, task47.ID)
require.NoError(t, err)

// Public repo, bot should have Read access even if not collaborator
assert.Equal(t, perm_model.AccessModeNone, perm.AccessMode)
assert.True(t, perm.CanRead(unit.TypeCode))
})

t.Run("SameRepo_Private", func(t *testing.T) {
// Use Task 53 which is already in Repo 2 (Private)
task53 := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionTask{ID: 53})
require.Equal(t, repo2.ID, task53.RepoID)

perm, err := GetActionsUserRepoPermission(ctx, repo2, actionsUser, task53.ID)
require.NoError(t, err)

// Private repo, bot has no base access, but gets Write from effective tokens perms (Permissive by default)
assert.Equal(t, perm_model.AccessModeNone, perm.AccessMode)
assert.True(t, perm.CanWrite(unit.TypeCode))
})

t.Run("CrossRepo_Denied_None", func(t *testing.T) {
task53 := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionTask{ID: 53})

// Set owner policy to nil allowed repos (None)
cfg := actions_model.OwnerActionsConfig{}
require.NoError(t, actions_model.SetOwnerActionsConfig(ctx, owner2.ID, cfg))

perm, err := GetActionsUserRepoPermission(ctx, repo15, actionsUser, task53.ID)
require.NoError(t, err)

// Should NOT have access to the private repo.
assert.False(t, perm.CanRead(unit.TypeCode))
})

t.Run("ForkPR_NoCrossRepo", func(t *testing.T) {
task53 := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionTask{ID: 53})
task53.IsForkPullRequest = true
require.NoError(t, actions_model.UpdateTask(ctx, task53, "is_fork_pull_request"))

// Policy contains repo15
cfg := actions_model.OwnerActionsConfig{
AllowedCrossRepoIDs: []int64{repo15.ID},
}
require.NoError(t, actions_model.SetOwnerActionsConfig(ctx, owner2.ID, cfg))

perm, err := GetActionsUserRepoPermission(ctx, repo15, actionsUser, task53.ID)
require.NoError(t, err)

// Fork PR never gets cross-repo access to other private repos
assert.False(t, perm.CanRead(unit.TypeCode))
})

t.Run("Inheritance_And_Clamping", func(t *testing.T) {
task53 := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionTask{ID: 53})
task53.IsForkPullRequest = false
require.NoError(t, actions_model.UpdateTask(ctx, task53, "is_fork_pull_request"))

// Owner policy: Restricted mode (Read-only Code)
ownerCfg := actions_model.OwnerActionsConfig{
TokenPermissionMode: repo_model.ActionsTokenPermissionModeRestricted,
MaxTokenPermissions: &repo_model.ActionsTokenPermissions{
UnitAccessModes: map[unit.Type]perm_model.AccessMode{
unit.TypeCode: perm_model.AccessModeRead,
},
},
}
require.NoError(t, actions_model.SetOwnerActionsConfig(ctx, owner2.ID, ownerCfg))

// Repo policy: OverrideOwnerConfig = false (should inherit owner's restricted mode)
repo2ActionsUnit := repo2.MustGetUnit(ctx, unit.TypeActions)
repo2ActionsCfg := repo2ActionsUnit.ActionsConfig()
repo2ActionsCfg.OverrideOwnerConfig = false
require.NoError(t, repo_model.UpdateRepoUnitConfig(ctx, repo2ActionsUnit))

perm, err := GetActionsUserRepoPermission(ctx, repo2, actionsUser, task53.ID)
require.NoError(t, err)

// Should be clamped to Read-only
assert.Equal(t, perm_model.AccessModeRead, perm.UnitAccessMode(unit.TypeCode))
assert.False(t, perm.CanWrite(unit.TypeCode))
})

t.Run("RepoOverride_Clamping", func(t *testing.T) {
task53 := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionTask{ID: 53})

// Owner policy: Permissive (Write access)
ownerCfg := actions_model.OwnerActionsConfig{
TokenPermissionMode: repo_model.ActionsTokenPermissionModePermissive,
}
require.NoError(t, actions_model.SetOwnerActionsConfig(ctx, owner2.ID, ownerCfg))

// Repo policy: OverrideOwnerConfig = true, MaxTokenPermissions = Read
repo2ActionsUnit := repo2.MustGetUnit(ctx, unit.TypeActions)
repo2ActionsCfg := repo2ActionsUnit.ActionsConfig()
repo2ActionsCfg.OverrideOwnerConfig = true
repo2ActionsCfg.TokenPermissionMode = repo_model.ActionsTokenPermissionModeRestricted
repo2ActionsCfg.MaxTokenPermissions = &repo_model.ActionsTokenPermissions{
UnitAccessModes: map[unit.Type]perm_model.AccessMode{
unit.TypeCode: perm_model.AccessModeRead,
},
}
require.NoError(t, repo_model.UpdateRepoUnitConfig(ctx, repo2ActionsUnit))

perm, err := GetActionsUserRepoPermission(ctx, repo2, actionsUser, task53.ID)
require.NoError(t, err)

// Should be clamped to Read-only
assert.Equal(t, perm_model.AccessModeRead, perm.UnitAccessMode(unit.TypeCode))
})
}
Loading
Loading