mirror of
https://github.com/go-gitea/gitea.git
synced 2026-10-23 19:47:07 +09:00
backport #39579
This commit is contained in:
1 parent
e66e773a6f
commit
0a4078558e
8 files changed
+147
-3
No files matched your search
@@ -33,6 +33,7 @@ import (
|
|||||||
"gitea.dev/modelmigration/v1_8"
|
"gitea.dev/modelmigration/v1_8"
|
||||||
"gitea.dev/modelmigration/v1_9"
|
"gitea.dev/modelmigration/v1_9"
|
||||||
"gitea.dev/modelmigration/v28"
|
"gitea.dev/modelmigration/v28"
|
||||||
|
"gitea.dev/modelmigration/v29"
|
||||||
"gitea.dev/modules/git"
|
"gitea.dev/modules/git"
|
||||||
"gitea.dev/modules/log"
|
"gitea.dev/modules/log"
|
||||||
"gitea.dev/modules/setting"
|
"gitea.dev/modules/setting"
|
||||||
@@ -429,6 +430,10 @@ func prepareMigrationTasks() []*migration {
|
|||||||
newMigration(353, "Add audit event table", v28.AddAuditEventTable),
|
newMigration(353, "Add audit event table", v28.AddAuditEventTable),
|
||||||
newMigration(354, "Add Actions job queue indexes", v28.AddActionQueueIndexes),
|
newMigration(354, "Add Actions job queue indexes", v28.AddActionQueueIndexes),
|
||||||
newMigration(355, "Add AutoMerge merged_commit_id column", v28.AddAutoMergeMergedCommitID),
|
newMigration(355, "Add AutoMerge merged_commit_id column", v28.AddAutoMergeMergedCommitID),
|
||||||
|
// Gitea 28.0.0 ends at migration ID number 355 (database version 356)
|
||||||
|
// HERE: 2 migrations from 29 are added since they don't change database structure
|
||||||
|
newMigration(356, "Add index on action_run commit_sha", v29.AddActionRunCommitSHAIndex),
|
||||||
|
newMigration(357, "Normalize legacy team authorize values", v29.NormalizeLegacyTeamAuthorize),
|
||||||
}
|
}
|
||||||
return preparedMigrations
|
return preparedMigrations
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
// Copyright 2026 The Gitea Authors. All rights reserved.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
package v29
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"gitea.dev/modelmigration/migrationtest"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestMain(m *testing.M) {
|
||||||
|
migrationtest.MainTest(m)
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
// Copyright 2026 The Gitea Authors. All rights reserved.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
package v29
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"gitea.dev/modelmigration/base"
|
||||||
|
|
||||||
|
"xorm.io/xorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
// AddActionRunCommitSHAIndex indexes the runs lookup by commit, which the API `head_sha` filter uses.
|
||||||
|
func AddActionRunCommitSHAIndex(_ context.Context, x base.EngineMigration) error {
|
||||||
|
type ActionRun struct {
|
||||||
|
CommitSHA string `xorm:"index"`
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := x.SyncWithOptions(xorm.SyncOptions{
|
||||||
|
IgnoreDropIndices: true,
|
||||||
|
IgnoreConstrains: true,
|
||||||
|
}, new(ActionRun))
|
||||||
|
return err
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
// Copyright 2026 The Gitea Authors. All rights reserved.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
package v29
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"gitea.dev/modelmigration/base"
|
||||||
|
)
|
||||||
|
|
||||||
|
// NormalizeLegacyTeamAuthorize sets leftover read/write authorize values to none.
|
||||||
|
// https://github.com/go-gitea/gitea/pull/34128 made non-admin teams use team_unit (authorize=none).
|
||||||
|
// authorize>=write now means blanket access on every unit; migrating legacy read/write
|
||||||
|
// to none preserves their existing team_unit-scoped access.
|
||||||
|
func NormalizeLegacyTeamAuthorize(_ context.Context, x base.EngineMigration) error {
|
||||||
|
// AccessModeNone=0, AccessModeRead=1, AccessModeWrite=2, AccessModeAdmin=3
|
||||||
|
_, err := x.Exec(`
|
||||||
|
UPDATE team SET authorize = 0
|
||||||
|
WHERE authorize > 0 AND authorize < 3
|
||||||
|
AND EXISTS (
|
||||||
|
SELECT 1 FROM team_unit WHERE team_unit.team_id = team.id
|
||||||
|
);`)
|
||||||
|
return err
|
||||||
|
}
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
// Copyright 2026 The Gitea Authors. All rights reserved.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
package v29
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"gitea.dev/modelmigration/migrationtest"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestNormalizeLegacyTeamAuthorize(t *testing.T) {
|
||||||
|
type Team struct {
|
||||||
|
ID int64 `xorm:"pk"`
|
||||||
|
Authorize int
|
||||||
|
}
|
||||||
|
type TeamUnit struct {
|
||||||
|
ID int64 `xorm:"pk"`
|
||||||
|
TeamID int64 `xorm:"INDEX"`
|
||||||
|
}
|
||||||
|
|
||||||
|
x, deferrable := migrationtest.PrepareTestEnv(t, 0, new(Team), new(TeamUnit))
|
||||||
|
defer deferrable()
|
||||||
|
if x == nil || t.Failed() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := x.Insert(
|
||||||
|
&Team{ID: 1, Authorize: 4},
|
||||||
|
&Team{ID: 2, Authorize: 3},
|
||||||
|
&Team{ID: 3, Authorize: 2},
|
||||||
|
&Team{ID: 4, Authorize: 1},
|
||||||
|
&Team{ID: 5, Authorize: 0},
|
||||||
|
|
||||||
|
&TeamUnit{TeamID: 3},
|
||||||
|
)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NoError(t, NormalizeLegacyTeamAuthorize(t.Context(), x))
|
||||||
|
|
||||||
|
get := func(id int64) int {
|
||||||
|
tBean := &Team{ID: id}
|
||||||
|
has, err := x.Get(tBean)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.True(t, has)
|
||||||
|
return tBean.Authorize
|
||||||
|
}
|
||||||
|
assert.Equal(t, 4, get(1))
|
||||||
|
assert.Equal(t, 3, get(2))
|
||||||
|
assert.Equal(t, 0, get(3)) // has team unit, reset to none
|
||||||
|
assert.Equal(t, 1, get(4)) // no team unit, kept
|
||||||
|
assert.Equal(t, 0, get(5))
|
||||||
|
}
|
||||||
@@ -39,9 +39,9 @@ type ActionRun struct {
|
|||||||
TriggerUserID int64 `xorm:"index"`
|
TriggerUserID int64 `xorm:"index"`
|
||||||
TriggerUser *user_model.User `xorm:"-"`
|
TriggerUser *user_model.User `xorm:"-"`
|
||||||
ScheduleID int64
|
ScheduleID int64
|
||||||
Ref string `xorm:"index"` // the commit/tag/… that caused the run
|
Ref string `xorm:"index"` // the commit/tag/… that caused the run
|
||||||
IsRefDeleted bool `xorm:"-"`
|
IsRefDeleted bool `xorm:"-"`
|
||||||
CommitSHA string
|
CommitSHA string `xorm:"index"`
|
||||||
IsForkPullRequest bool // If this is triggered by a PR from a forked repository or an untrusted user, we need to check if it is approved and limit permissions when running the workflow.
|
IsForkPullRequest bool // If this is triggered by a PR from a forked repository or an untrusted user, we need to check if it is approved and limit permissions when running the workflow.
|
||||||
NeedApproval bool // may need approval if it's a fork pull request
|
NeedApproval bool // may need approval if it's a fork pull request
|
||||||
ApprovedBy int64 `xorm:"index"` // who approved
|
ApprovedBy int64 `xorm:"index"` // who approved
|
||||||
|
|||||||
@@ -167,6 +167,7 @@ func assignTeamPermissionUnits(team *organization.Team, permission string, units
|
|||||||
oldAccessMode := team.AccessMode
|
oldAccessMode := team.AccessMode
|
||||||
oldUnitPerms := team.GetUnitsMap()
|
oldUnitPerms := team.GetUnitsMap()
|
||||||
if len(unitsMap) > 0 {
|
if len(unitsMap) > 0 {
|
||||||
|
team.AccessMode = perm.AccessModeNone
|
||||||
team.Units = make([]*organization.TeamUnit, 0, len(unitsMap))
|
team.Units = make([]*organization.TeamUnit, 0, len(unitsMap))
|
||||||
for unitKey, p := range unitsMap {
|
for unitKey, p := range unitsMap {
|
||||||
unitType, unitPerm := unit_model.TypeFromKey(unitKey), perm.ParseAccessMode(p)
|
unitType, unitPerm := unit_model.TypeFromKey(unitKey), perm.ParseAccessMode(p)
|
||||||
|
|||||||
@@ -109,6 +109,16 @@ func TestAPITeam(t *testing.T) {
|
|||||||
checkTeamResponse(t, "EditTeam1_DescOnly", apiTeam, teamToEdit.Name, *teamToEditDesc.Description, *teamToEdit.IncludesAllRepositories, api.AccessLevelName(teamToEdit.Permission), nil)
|
checkTeamResponse(t, "EditTeam1_DescOnly", apiTeam, teamToEdit.Name, *teamToEditDesc.Description, *teamToEdit.IncludesAllRepositories, api.AccessLevelName(teamToEdit.Permission), nil)
|
||||||
checkTeamBean(t, apiTeam.ID, teamToEdit.Name, *teamToEditDesc.Description, *teamToEdit.IncludesAllRepositories, api.AccessLevelName(teamToEdit.Permission), nil)
|
checkTeamBean(t, apiTeam.ID, teamToEdit.Name, *teamToEditDesc.Description, *teamToEdit.IncludesAllRepositories, api.AccessLevelName(teamToEdit.Permission), nil)
|
||||||
|
|
||||||
|
// Edit team to granular permissions, team's permission should be reset to none
|
||||||
|
req = NewRequestWithJSON(t, "PATCH", fmt.Sprintf("/api/v1/teams/%d", teamID), api.EditTeamOption{
|
||||||
|
Permission: "read",
|
||||||
|
Units: []string{"repo.code", "repo.issues"},
|
||||||
|
}).AddTokenAuth(token)
|
||||||
|
resp = MakeRequest(t, req, http.StatusOK)
|
||||||
|
apiTeam = DecodeJSON(t, resp, &api.Team{})
|
||||||
|
checkTeamResponse(t, "EditTeam1_Granular", apiTeam, teamToEdit.Name, editDescription, editFalse, api.AccessLevelNameNone, expectedTeamUnitsMap)
|
||||||
|
checkTeamBean(t, teamID, teamToEdit.Name, editDescription, editFalse, api.AccessLevelNameNone, expectedTeamUnitsMap)
|
||||||
|
|
||||||
// Read team.
|
// Read team.
|
||||||
teamRead := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: teamID})
|
teamRead := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: teamID})
|
||||||
assert.NoError(t, teamRead.LoadUnits(t.Context()))
|
assert.NoError(t, teamRead.LoadUnits(t.Context()))
|
||||||
@@ -139,6 +149,15 @@ func TestAPITeam(t *testing.T) {
|
|||||||
checkTeamBean(t, apiTeam.ID, teamToCreate.Name, teamToCreate.Description, teamToCreate.IncludesAllRepositories, api.AccessLevelNameNone, teamToCreate.UnitsMap)
|
checkTeamBean(t, apiTeam.ID, teamToCreate.Name, teamToCreate.Description, teamToCreate.IncludesAllRepositories, api.AccessLevelNameNone, teamToCreate.UnitsMap)
|
||||||
teamID = apiTeam.ID
|
teamID = apiTeam.ID
|
||||||
|
|
||||||
|
// Create a team with permission=write, then edit it to granular permissions later, team's permission should be reset to none
|
||||||
|
req = NewRequestWithJSON(t, "PATCH", fmt.Sprintf("/api/v1/teams/%d", teamID), api.EditTeamOption{
|
||||||
|
Permission: "write",
|
||||||
|
}).AddTokenAuth(token)
|
||||||
|
resp = MakeRequest(t, req, http.StatusOK)
|
||||||
|
apiTeam = DecodeJSON(t, resp, &api.Team{})
|
||||||
|
checkTeamResponse(t, "EditTeam2_Write", apiTeam, teamToCreate.Name, teamToCreate.Description, teamToCreate.IncludesAllRepositories, api.AccessLevelNameWrite, nil)
|
||||||
|
checkTeamBean(t, teamID, teamToCreate.Name, teamToCreate.Description, teamToCreate.IncludesAllRepositories, api.AccessLevelNameWrite, nil)
|
||||||
|
|
||||||
// Edit team.
|
// Edit team.
|
||||||
editDescription = "team 1"
|
editDescription = "team 1"
|
||||||
editFalse = false
|
editFalse = false
|
||||||
|
|||||||
Reference in new issue
Block a user