Fix issue label deletion with Actions tokens (#37013)

Use shared repo permission resolution for Actions task users in issue
label remove and clear paths, and add a regression test for deleting
issue labels with a Gitea Actions token.

This fixes issue label deletion when the request is authenticated with a
Gitea Actions token.
Fixes #37011 

The bug was that the delete path re-resolved repository permissions
using the normal user permission helper, which does not handle Actions
task users. As a result, `DELETE
/api/v1/repos/{owner}/{repo}/issues/{index}/labels/{id}` could return
`500` for Actions tokens even though label listing and label addition
worked.

---------

Co-authored-by: Codex <codex@openai.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: Giteabot <teabot@gitea.io>
This commit is contained in:
Nicolas
2026-03-29 11:21:14 +02:00
committed by GitHub
parent a1b0bffd0c
commit db7eb4d51b
61 changed files with 268 additions and 181 deletions
+36 -8
View File
@@ -6,6 +6,7 @@ package access
import (
"testing"
actions_model "code.gitea.io/gitea/models/actions"
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/organization"
perm_model "code.gitea.io/gitea/models/perm"
@@ -157,8 +158,13 @@ func TestUnitAccessMode(t *testing.T) {
assert.Equal(t, perm_model.AccessModeRead, perm.UnitAccessMode(unit.TypeWiki), "has unit, and map, use map")
}
func TestGetUserRepoPermission(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
func TestGetRepoPermission(t *testing.T) {
require.NoError(t, unittest.PrepareTestDatabase())
t.Run("GetIndividualUserRepoPermission", testGetIndividualUserRepoPermission)
t.Run("GetDoerRepoPermission", testGetDoerRepoPermission)
}
func testGetIndividualUserRepoPermission(t *testing.T) {
ctx := t.Context()
repo32 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 32}) // org public repo
require.NoError(t, repo32.LoadOwner(ctx))
@@ -172,7 +178,7 @@ func TestGetUserRepoPermission(t *testing.T) {
require.NoError(t, db.Insert(ctx, &organization.TeamUser{OrgID: org.ID, TeamID: team.ID, UID: user.ID}))
t.Run("DoerInTeamWithNoRepo", func(t *testing.T) {
perm, err := GetUserRepoPermission(ctx, repo32, user)
perm, err := GetIndividualUserRepoPermission(ctx, repo32, user)
require.NoError(t, err)
assert.Equal(t, perm_model.AccessModeRead, perm.AccessMode)
assert.Nil(t, perm.unitsMode) // doer in the team, but has no access to the repo
@@ -181,7 +187,7 @@ func TestGetUserRepoPermission(t *testing.T) {
require.NoError(t, db.Insert(ctx, &organization.TeamRepo{OrgID: org.ID, TeamID: team.ID, RepoID: repo32.ID}))
require.NoError(t, db.Insert(ctx, &organization.TeamUnit{OrgID: org.ID, TeamID: team.ID, Type: unit.TypeCode, AccessMode: perm_model.AccessModeNone}))
t.Run("DoerWithTeamUnitAccessNone", func(t *testing.T) {
perm, err := GetUserRepoPermission(ctx, repo32, user)
perm, err := GetIndividualUserRepoPermission(ctx, repo32, user)
require.NoError(t, err)
assert.Equal(t, perm_model.AccessModeRead, perm.AccessMode)
assert.Equal(t, perm_model.AccessModeRead, perm.unitsMode[unit.TypeCode])
@@ -191,7 +197,7 @@ func TestGetUserRepoPermission(t *testing.T) {
require.NoError(t, db.TruncateBeans(ctx, &organization.TeamUnit{}))
require.NoError(t, db.Insert(ctx, &organization.TeamUnit{OrgID: org.ID, TeamID: team.ID, Type: unit.TypeCode, AccessMode: perm_model.AccessModeWrite}))
t.Run("DoerWithTeamUnitAccessWrite", func(t *testing.T) {
perm, err := GetUserRepoPermission(ctx, repo32, user)
perm, err := GetIndividualUserRepoPermission(ctx, repo32, user)
require.NoError(t, err)
assert.Equal(t, perm_model.AccessModeRead, perm.AccessMode)
assert.Equal(t, perm_model.AccessModeWrite, perm.unitsMode[unit.TypeCode])
@@ -204,7 +210,7 @@ func TestGetUserRepoPermission(t *testing.T) {
require.NoError(t, db.TruncateBeans(ctx, &organization.TeamUnit{}, &Access{})) // The user has access set of that repo, remove it, it is useless for our test
require.NoError(t, db.Insert(ctx, &organization.TeamRepo{OrgID: org.ID, TeamID: team.ID, RepoID: repo3.ID}))
t.Run("DoerWithNoopTeamOnPrivateRepo", func(t *testing.T) {
perm, err := GetUserRepoPermission(ctx, repo3, user)
perm, err := GetIndividualUserRepoPermission(ctx, repo3, user)
require.NoError(t, err)
assert.Equal(t, perm_model.AccessModeNone, perm.AccessMode)
assert.Equal(t, perm_model.AccessModeNone, perm.unitsMode[unit.TypeCode])
@@ -214,7 +220,7 @@ func TestGetUserRepoPermission(t *testing.T) {
require.NoError(t, db.Insert(ctx, &organization.TeamUnit{OrgID: org.ID, TeamID: team.ID, Type: unit.TypeCode, AccessMode: perm_model.AccessModeNone}))
require.NoError(t, db.Insert(ctx, &organization.TeamUnit{OrgID: org.ID, TeamID: team.ID, Type: unit.TypeIssues, AccessMode: perm_model.AccessModeRead}))
t.Run("DoerWithReadIssueTeamOnPrivateRepo", func(t *testing.T) {
perm, err := GetUserRepoPermission(ctx, repo3, user)
perm, err := GetIndividualUserRepoPermission(ctx, repo3, user)
require.NoError(t, err)
assert.Equal(t, perm_model.AccessModeNone, perm.AccessMode)
assert.Equal(t, perm_model.AccessModeNone, perm.unitsMode[unit.TypeCode])
@@ -233,7 +239,7 @@ func TestGetUserRepoPermission(t *testing.T) {
require.NoError(t, db.Insert(ctx, repo_model.Collaboration{RepoID: repo3.ID, UserID: user.ID, Mode: perm_model.AccessModeWrite}))
require.NoError(t, db.Insert(ctx, Access{RepoID: repo3.ID, UserID: user.ID, Mode: perm_model.AccessModeWrite}))
t.Run("DoerWithReadIssueTeamAndWriteCollaboratorOnPrivateRepo", func(t *testing.T) {
perm, err := GetUserRepoPermission(ctx, repo3, user)
perm, err := GetIndividualUserRepoPermission(ctx, repo3, user)
require.NoError(t, err)
assert.Equal(t, perm_model.AccessModeWrite, perm.AccessMode)
assert.Equal(t, perm_model.AccessModeWrite, perm.unitsMode[unit.TypeCode])
@@ -245,3 +251,25 @@ func TestGetUserRepoPermission(t *testing.T) {
assert.Equal(t, user.ID, users[0].ID)
})
}
func testGetDoerRepoPermission(t *testing.T) {
ctx := t.Context()
repo4 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 4})
repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
task47 := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionTask{ID: 47})
actionsDoer := user_model.NewActionsUserWithTaskID(task47.ID)
regularUser := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
actionsPerm, err := GetDoerRepoPermission(ctx, repo4, actionsDoer)
require.NoError(t, err)
directPerm, err := GetActionsUserRepoPermission(ctx, repo4, actionsDoer, task47.ID)
require.NoError(t, err)
assert.Equal(t, directPerm, actionsPerm)
doerPerm, err := GetDoerRepoPermission(ctx, repo1, regularUser)
require.NoError(t, err)
individualPerm, err := GetIndividualUserRepoPermission(ctx, repo1, regularUser)
require.NoError(t, err)
assert.Equal(t, individualPerm, doerPerm)
}