Fix various permission & login related bugs (#36002)

Permission & protection check:

- Fix Delete Release permission check
- Fix Update Pull Request with rebase branch protection check
- Fix Issue Dependency permission check
- Fix Delete Comment History ID check

Information leaking:

- Show unified message for non-existing user and invalid password
    - Fix #35984
- Don't expose release draft to non-writer users.
- Make API returns signature's email address instead of the user
profile's.

Auth & Login:

- Avoid GCM OAuth2 attempt when OAuth2 is disabled
    - Fix #35510

---------

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
This commit is contained in:
Lunny Xiao
2025-11-21 23:16:08 -08:00
committed by GitHub
parent a60a8c6966
commit 62d750eadb
18 changed files with 385 additions and 61 deletions

View File

@@ -11,7 +11,11 @@ import (
"time"
auth_model "code.gitea.io/gitea/models/auth"
git_model "code.gitea.io/gitea/models/git"
issues_model "code.gitea.io/gitea/models/issues"
"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"
"code.gitea.io/gitea/modules/gitrepo"
@@ -58,6 +62,14 @@ func TestAPIPullUpdate(t *testing.T) {
})
}
func enableRepoAllowUpdateWithRebase(t *testing.T, repoID int64, allow bool) {
t.Helper()
repoUnit := unittest.AssertExistsAndLoadBean(t, &repo_model.RepoUnit{RepoID: repoID, Type: unit.TypePullRequests})
repoUnit.PullRequestsConfig().AllowRebaseUpdate = allow
assert.NoError(t, repo_model.UpdateRepoUnit(t.Context(), repoUnit))
}
func TestAPIPullUpdateByRebase(t *testing.T) {
onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) {
// Create PR to test
@@ -73,10 +85,32 @@ func TestAPIPullUpdateByRebase(t *testing.T) {
assert.Equal(t, 1, diffCount.Ahead)
assert.NoError(t, pr.LoadIssue(t.Context()))
enableRepoAllowUpdateWithRebase(t, pr.BaseRepo.ID, false)
session := loginUser(t, "user2")
token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository)
req := NewRequestf(t, "POST", "/api/v1/repos/%s/%s/pulls/%d/update?style=rebase", pr.BaseRepo.OwnerName, pr.BaseRepo.Name, pr.Issue.Index).
AddTokenAuth(token)
session.MakeRequest(t, req, http.StatusForbidden)
enableRepoAllowUpdateWithRebase(t, pr.BaseRepo.ID, true)
assert.NoError(t, pr.LoadHeadRepo(t.Context()))
// use a user which have write access to the pr but not write permission to the head repository to do the rebase
user40 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 40})
err = repo_service.AddOrUpdateCollaborator(t.Context(), pr.BaseRepo, user40, perm.AccessModeWrite)
assert.NoError(t, err)
token40 := getUserToken(t, "user40", auth_model.AccessTokenScopeWriteRepository)
req = NewRequestf(t, "POST", "/api/v1/repos/%s/%s/pulls/%d/update?style=rebase", pr.BaseRepo.OwnerName, pr.BaseRepo.Name, pr.Issue.Index).
AddTokenAuth(token40)
session.MakeRequest(t, req, http.StatusForbidden)
err = repo_service.AddOrUpdateCollaborator(t.Context(), pr.HeadRepo, user40, perm.AccessModeWrite)
assert.NoError(t, err)
req = NewRequestf(t, "POST", "/api/v1/repos/%s/%s/pulls/%d/update?style=rebase", pr.BaseRepo.OwnerName, pr.BaseRepo.Name, pr.Issue.Index).
AddTokenAuth(token40)
session.MakeRequest(t, req, http.StatusOK)
// Test GetDiverging after update
@@ -87,6 +121,49 @@ func TestAPIPullUpdateByRebase(t *testing.T) {
})
}
func TestAPIPullUpdateByRebase2(t *testing.T) {
onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) {
// Create PR to test
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
org26 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 26})
pr := createOutdatedPR(t, user, org26)
assert.NoError(t, pr.LoadBaseRepo(t.Context()))
assert.NoError(t, pr.LoadIssue(t.Context()))
enableRepoAllowUpdateWithRebase(t, pr.BaseRepo.ID, false)
session := loginUser(t, "user2")
token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository)
req := NewRequestf(t, "POST", "/api/v1/repos/%s/%s/pulls/%d/update?style=rebase", pr.BaseRepo.OwnerName, pr.BaseRepo.Name, pr.Issue.Index).
AddTokenAuth(token)
session.MakeRequest(t, req, http.StatusForbidden)
enableRepoAllowUpdateWithRebase(t, pr.BaseRepo.ID, true)
assert.NoError(t, pr.LoadHeadRepo(t.Context()))
// add a protected branch rule to the head branch to block rebase
pb := git_model.ProtectedBranch{
RepoID: pr.HeadRepo.ID,
RuleName: pr.HeadBranch,
CanPush: false,
CanForcePush: false,
}
err := git_model.UpdateProtectBranch(t.Context(), pr.HeadRepo, &pb, git_model.WhitelistOptions{})
assert.NoError(t, err)
req = NewRequestf(t, "POST", "/api/v1/repos/%s/%s/pulls/%d/update?style=rebase", pr.BaseRepo.OwnerName, pr.BaseRepo.Name, pr.Issue.Index).
AddTokenAuth(token)
session.MakeRequest(t, req, http.StatusForbidden)
// remove the protected branch rule to allow rebase
err = git_model.DeleteProtectedBranch(t.Context(), pr.HeadRepo, pb.ID)
assert.NoError(t, err)
req = NewRequestf(t, "POST", "/api/v1/repos/%s/%s/pulls/%d/update?style=rebase", pr.BaseRepo.OwnerName, pr.BaseRepo.Name, pr.Issue.Index).
AddTokenAuth(token)
session.MakeRequest(t, req, http.StatusOK)
})
}
func createOutdatedPR(t *testing.T, actor, forkOrg *user_model.User) *issues_model.PullRequest {
baseRepo, err := repo_service.CreateRepository(t.Context(), actor, actor, repo_service.CreateRepoOptions{
Name: "repo-pr-update",