mirror of
https://codeberg.org/forgejo/forgejo.git
synced 2024-12-12 07:42:08 +01:00
f7638f5414
user, topic, project, label, milestone, repository, pull_request, release, asset, comment, reaction, review providers Signed-off-by: Earl Warren <contact@earl-warren.org> Preserve file size when creating attachments Introduced inc6f5029708
repoList.LoadAttributes has a ctx argument now Rename `repo.GetOwner` to `repo.LoadOwner`bd66fa586a
upgrade to the latest gof3 (cherry picked from commitc770713656
) [F3] ID remapping logic is in place, remove workaround (cherry picked from commitd0fee30167
) [F3] it is experimental, do not enable by default (cherry picked from commitde325b21d0
) (cherry picked from commit547e7b3c40
) (cherry picked from commit820df3a56b
) (cherry picked from commiteaba87689b
) (cherry picked from commit1b86896b3b
) (cherry picked from commit0046aac1c6
) (cherry picked from commitf14220df8f
) (cherry picked from commit559b731001
) (cherry picked from commit801f7d600d
) (cherry picked from commit6aa76e9bcf
) (cherry picked from commita8757dcb07
) [F3] promote F3 users to matching OAuth2 users on first sign-in (cherry picked from commitbd7fef7496
) (cherry picked from commit07412698e8
) (cherry picked from commitd143e5b2a3
) [F3] upgrade to gof3 50a6e740ac04 Add new methods GetIDString() & SetIDString() & ToFormatInterface() Change the prototype of the fixture function (cherry picked from commitd7b263ff8b
) (cherry picked from commitb3eaf2249d
) (cherry picked from commitd492ddd9bb
) [F3] add GetLocalMatchingRemote with a default implementation (cherry picked from commit0a22015039
) (cherry picked from commitf1310c38fb
) (cherry picked from commitdeb68552f2
) [F3] GetLocalMatchingRemote for user (cherry picked from commite73cb837f5
) (cherry picked from commita24bc0b85e
) (cherry picked from commit846a522ecc
) [F3] GetAdminUser now has a ctx argument (cherry picked from commit37357a92af
) (cherry picked from commit660bc1673c
) (cherry picked from commit72d692a767
) [F3] introduce UserTypeF3 To avoid conflicts should UserTypeRemoteUser be used differently by Gitea (cherry picked from commit6de2701bb3
) [F3] user.Put: idempotency (cherry picked from commit821e38573c
)
330 lines
12 KiB
Go
330 lines
12 KiB
Go
// SPDX-License-Identifier: MIT
|
|
|
|
package integration
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"net/http"
|
|
"net/url"
|
|
"testing"
|
|
|
|
auth_model "code.gitea.io/gitea/models/auth"
|
|
"code.gitea.io/gitea/models/unittest"
|
|
user_model "code.gitea.io/gitea/models/user"
|
|
"code.gitea.io/gitea/modules/log"
|
|
"code.gitea.io/gitea/modules/setting"
|
|
"code.gitea.io/gitea/modules/test"
|
|
"code.gitea.io/gitea/services/f3/util"
|
|
"code.gitea.io/gitea/tests"
|
|
|
|
"github.com/markbates/goth"
|
|
"github.com/stretchr/testify/assert"
|
|
"lab.forgefriends.org/friendlyforgeformat/gof3"
|
|
f3_forges "lab.forgefriends.org/friendlyforgeformat/gof3/forges"
|
|
f3_common "lab.forgefriends.org/friendlyforgeformat/gof3/forges/common"
|
|
f3_f3 "lab.forgefriends.org/friendlyforgeformat/gof3/forges/f3"
|
|
f3_forgejo "lab.forgefriends.org/friendlyforgeformat/gof3/forges/forgejo"
|
|
f3_tests "lab.forgefriends.org/friendlyforgeformat/gof3/forges/tests"
|
|
"lab.forgefriends.org/friendlyforgeformat/gof3/format"
|
|
f3_util "lab.forgefriends.org/friendlyforgeformat/gof3/util"
|
|
)
|
|
|
|
func TestF3Mirror(t *testing.T) {
|
|
onGiteaRun(t, func(t *testing.T, u *url.URL) {
|
|
AllowLocalNetworks := setting.Migrations.AllowLocalNetworks
|
|
setting.F3.Enabled = true
|
|
setting.Migrations.AllowLocalNetworks = true
|
|
AppVer := setting.AppVer
|
|
// Gitea SDK (go-sdk) need to parse the AppVer from server response, so we must set it to a valid version string.
|
|
setting.AppVer = "1.16.0"
|
|
defer func() {
|
|
setting.Migrations.AllowLocalNetworks = AllowLocalNetworks
|
|
setting.AppVer = AppVer
|
|
}()
|
|
|
|
//
|
|
// Step 1: create a fixture
|
|
//
|
|
fixtureNewF3Forge := func(t f3_tests.TestingT, user *format.User, tmpDir string) *f3_forges.ForgeRoot {
|
|
root := f3_forges.NewForgeRoot(&f3_f3.Options{
|
|
Options: gof3.Options{
|
|
Configuration: gof3.Configuration{
|
|
Directory: tmpDir,
|
|
},
|
|
Features: gof3.AllFeatures,
|
|
Logger: util.ToF3Logger(nil),
|
|
},
|
|
Remap: true,
|
|
})
|
|
return root
|
|
}
|
|
fixture := f3_forges.NewFixture(t, f3_forges.FixtureForgeFactory{Fun: fixtureNewF3Forge, AdminRequired: false})
|
|
fixture.NewUser(5432)
|
|
fixture.NewMilestone()
|
|
fixture.NewLabel()
|
|
fixture.NewIssue()
|
|
fixture.NewTopic()
|
|
fixture.NewRepository()
|
|
fixture.NewPullRequest()
|
|
fixture.NewRelease()
|
|
fixture.NewAsset()
|
|
fixture.NewIssueComment(nil)
|
|
fixture.NewPullRequestComment()
|
|
// fixture.NewReview()
|
|
fixture.NewIssueReaction()
|
|
fixture.NewCommentReaction()
|
|
|
|
//
|
|
// Step 2: mirror F3 into Forgejo
|
|
//
|
|
doer, err := user_model.GetAdminUser(context.Background())
|
|
assert.NoError(t, err)
|
|
forgejoLocal := util.ForgejoForgeRoot(gof3.AllFeatures, doer, 0)
|
|
options := f3_common.NewMirrorOptionsRecurse()
|
|
forgejoLocal.Forge.Mirror(context.Background(), fixture.Forge, options)
|
|
|
|
//
|
|
// Step 3: mirror Forgejo into F3
|
|
//
|
|
adminUsername := "user1"
|
|
forgejoAPI := f3_forges.NewForgeRootFromDriver(&f3_forgejo.Forgejo{}, &f3_forgejo.Options{
|
|
Options: gof3.Options{
|
|
Configuration: gof3.Configuration{
|
|
URL: setting.AppURL,
|
|
Directory: t.TempDir(),
|
|
},
|
|
Features: gof3.AllFeatures,
|
|
},
|
|
AuthToken: getUserToken(t, adminUsername, auth_model.AccessTokenScopeWriteAdmin, auth_model.AccessTokenScopeAll),
|
|
})
|
|
|
|
f3 := f3_forges.FixtureNewF3Forge(t, nil, t.TempDir())
|
|
apiForge := forgejoAPI.Forge
|
|
apiUser := apiForge.Users.GetFromFormat(context.Background(), &format.User{UserName: fixture.UserFormat.UserName})
|
|
apiProject := apiUser.Projects.GetFromFormat(context.Background(), &format.Project{Name: fixture.ProjectFormat.Name})
|
|
options = f3_common.NewMirrorOptionsRecurse(apiUser, apiProject)
|
|
f3.Forge.Mirror(context.Background(), apiForge, options)
|
|
|
|
//
|
|
// Step 4: verify the fixture and F3 are equivalent
|
|
//
|
|
files := f3_util.Command(context.Background(), "find", f3.GetDirectory())
|
|
assert.Contains(t, files, "/repository/git/hooks")
|
|
assert.Contains(t, files, "/label/")
|
|
assert.Contains(t, files, "/issue/")
|
|
assert.Contains(t, files, "/milestone/")
|
|
assert.Contains(t, files, "/topic/")
|
|
assert.Contains(t, files, "/pull_request/")
|
|
assert.Contains(t, files, "/release/")
|
|
assert.Contains(t, files, "/asset/")
|
|
assert.Contains(t, files, "/comment/")
|
|
// assert.Contains(t, files, "/review/")
|
|
assert.Contains(t, files, "/reaction/")
|
|
// f3_util.Command(context.Background(), "cp", "-a", f3.GetDirectory(), "abc")
|
|
})
|
|
}
|
|
|
|
func TestMaybePromoteF3User(t *testing.T) {
|
|
defer tests.PrepareTestEnv(t)()
|
|
|
|
//
|
|
// OAuth2 authentication source GitLab
|
|
//
|
|
gitlabName := "gitlab"
|
|
_ = addAuthSource(t, authSourcePayloadGitLabCustom(gitlabName))
|
|
//
|
|
// F3 authentication source matching the GitLab authentication source
|
|
//
|
|
f3Name := "f3"
|
|
f3 := createF3AuthSource(t, f3Name, "http://mygitlab.eu", gitlabName)
|
|
|
|
//
|
|
// Create a user as if it had been previously been created by the F3
|
|
// authentication source.
|
|
//
|
|
gitlabUserID := "5678"
|
|
gitlabEmail := "gitlabuser@example.com"
|
|
userBeforeSignIn := &user_model.User{
|
|
Name: "gitlabuser",
|
|
Type: user_model.UserTypeF3,
|
|
LoginType: auth_model.F3,
|
|
LoginSource: f3.ID,
|
|
LoginName: gitlabUserID,
|
|
}
|
|
defer createUser(context.Background(), t, userBeforeSignIn)()
|
|
|
|
//
|
|
// A request for user information sent to Goth will return a
|
|
// goth.User exactly matching the user created above.
|
|
//
|
|
defer mockCompleteUserAuth(func(res http.ResponseWriter, req *http.Request) (goth.User, error) {
|
|
return goth.User{
|
|
Provider: gitlabName,
|
|
UserID: gitlabUserID,
|
|
Email: gitlabEmail,
|
|
}, nil
|
|
})()
|
|
req := NewRequest(t, "GET", fmt.Sprintf("/user/oauth2/%s/callback?code=XYZ&state=XYZ", gitlabName))
|
|
resp := MakeRequest(t, req, http.StatusSeeOther)
|
|
assert.Equal(t, "/", test.RedirectURL(resp))
|
|
userAfterSignIn := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: userBeforeSignIn.ID})
|
|
|
|
// both are about the same user
|
|
assert.Equal(t, userAfterSignIn.ID, userBeforeSignIn.ID)
|
|
// the login time was updated, proof the login succeeded
|
|
assert.Greater(t, userAfterSignIn.LastLoginUnix, userBeforeSignIn.LastLoginUnix)
|
|
// the login type was promoted from F3 to OAuth2
|
|
assert.Equal(t, userBeforeSignIn.LoginType, auth_model.F3)
|
|
assert.Equal(t, userAfterSignIn.LoginType, auth_model.OAuth2)
|
|
// the OAuth2 email was used to set the missing user email
|
|
assert.Equal(t, userBeforeSignIn.Email, "")
|
|
assert.Equal(t, userAfterSignIn.Email, gitlabEmail)
|
|
}
|
|
|
|
func TestF3UserMappingExisting(t *testing.T) {
|
|
onGiteaRun(t, func(t *testing.T, u *url.URL) {
|
|
AllowLocalNetworks := setting.Migrations.AllowLocalNetworks
|
|
setting.F3.Enabled = true
|
|
setting.Migrations.AllowLocalNetworks = true
|
|
AppVer := setting.AppVer
|
|
// Gitea SDK (go-sdk) need to parse the AppVer from server response, so we must set it to a valid version string.
|
|
setting.AppVer = "1.16.0"
|
|
defer func() {
|
|
setting.Migrations.AllowLocalNetworks = AllowLocalNetworks
|
|
setting.AppVer = AppVer
|
|
}()
|
|
|
|
log.Debug("Step 1: create a fixture in F3")
|
|
fixtureNewF3Forge := func(t f3_tests.TestingT, user *format.User, tmpDir string) *f3_forges.ForgeRoot {
|
|
root := f3_forges.NewForgeRoot(&f3_f3.Options{
|
|
Options: gof3.Options{
|
|
Configuration: gof3.Configuration{
|
|
Directory: tmpDir,
|
|
},
|
|
Features: gof3.AllFeatures,
|
|
Logger: util.ToF3Logger(nil),
|
|
},
|
|
Remap: true,
|
|
})
|
|
return root
|
|
}
|
|
fixture := f3_forges.NewFixture(t, f3_forges.FixtureForgeFactory{Fun: fixtureNewF3Forge, AdminRequired: false})
|
|
userID := int64(5432)
|
|
fixture.NewUser(userID)
|
|
// fixture.NewProject()
|
|
|
|
log.Debug("Step 2: mirror F3 into Forgejo")
|
|
//
|
|
// OAuth2 authentication source GitLab
|
|
//
|
|
gitlabName := "gitlab"
|
|
gitlab := addAuthSource(t, authSourcePayloadGitLabCustom(gitlabName))
|
|
//
|
|
// Create a user as if it had been previously been created by the F3
|
|
// authentication source.
|
|
//
|
|
gitlabUserID := fmt.Sprintf("%d", userID)
|
|
gitlabUser := &user_model.User{
|
|
Name: "gitlabuser",
|
|
Email: "gitlabuser@example.com",
|
|
LoginType: auth_model.OAuth2,
|
|
LoginSource: gitlab.ID,
|
|
LoginName: gitlabUserID,
|
|
}
|
|
defer createUser(context.Background(), t, gitlabUser)()
|
|
|
|
doer, err := user_model.GetAdminUser(context.Background())
|
|
assert.NoError(t, err)
|
|
forgejoLocal := util.ForgejoForgeRoot(gof3.AllFeatures, doer, gitlab.ID)
|
|
options := f3_common.NewMirrorOptionsRecurse()
|
|
forgejoLocal.Forge.Mirror(context.Background(), fixture.Forge, options)
|
|
|
|
log.Debug("Step 3: mirror Forgejo into F3")
|
|
adminUsername := "user1"
|
|
forgejoAPI := f3_forges.NewForgeRootFromDriver(&f3_forgejo.Forgejo{}, &f3_forgejo.Options{
|
|
Options: gof3.Options{
|
|
Configuration: gof3.Configuration{
|
|
URL: setting.AppURL,
|
|
Directory: t.TempDir(),
|
|
},
|
|
Features: gof3.AllFeatures,
|
|
Logger: util.ToF3Logger(nil),
|
|
},
|
|
AuthToken: getUserToken(t, adminUsername, auth_model.AccessTokenScopeWriteAdmin, auth_model.AccessTokenScopeAll),
|
|
})
|
|
|
|
f3 := f3_forges.FixtureNewF3Forge(t, nil, t.TempDir())
|
|
apiForge := forgejoAPI.Forge
|
|
apiUser := apiForge.Users.GetFromFormat(context.Background(), &format.User{UserName: gitlabUser.Name})
|
|
// apiProject := apiUser.Projects.GetFromFormat(context.Background(), &format.Project{Name: fixture.ProjectFormat.Name})
|
|
// options = f3_common.NewMirrorOptionsRecurse(apiUser, apiProject)
|
|
options = f3_common.NewMirrorOptionsRecurse(apiUser)
|
|
f3.Forge.Mirror(context.Background(), apiForge, options)
|
|
|
|
//
|
|
// Step 4: verify the fixture and F3 are equivalent
|
|
//
|
|
files := f3_util.Command(context.Background(), "find", f3.GetDirectory())
|
|
assert.Contains(t, files, fmt.Sprintf("/user/%d", gitlabUser.ID))
|
|
})
|
|
}
|
|
|
|
func TestF3UserMappingNew(t *testing.T) {
|
|
onGiteaRun(t, func(t *testing.T, u *url.URL) {
|
|
AllowLocalNetworks := setting.Migrations.AllowLocalNetworks
|
|
setting.F3.Enabled = true
|
|
setting.Migrations.AllowLocalNetworks = true
|
|
AppVer := setting.AppVer
|
|
// Gitea SDK (go-sdk) need to parse the AppVer from server response, so we must set it to a valid version string.
|
|
setting.AppVer = "1.16.0"
|
|
defer func() {
|
|
setting.Migrations.AllowLocalNetworks = AllowLocalNetworks
|
|
setting.AppVer = AppVer
|
|
}()
|
|
|
|
log.Debug("Step 1: create a fixture in F3")
|
|
fixtureNewF3Forge := func(t f3_tests.TestingT, user *format.User, tmpDir string) *f3_forges.ForgeRoot {
|
|
root := f3_forges.NewForgeRoot(&f3_f3.Options{
|
|
Options: gof3.Options{
|
|
Configuration: gof3.Configuration{
|
|
Directory: tmpDir,
|
|
},
|
|
Features: gof3.AllFeatures,
|
|
Logger: util.ToF3Logger(nil),
|
|
},
|
|
Remap: true,
|
|
})
|
|
return root
|
|
}
|
|
fixture := f3_forges.NewFixture(t, f3_forges.FixtureForgeFactory{Fun: fixtureNewF3Forge, AdminRequired: false})
|
|
userID := int64(5432)
|
|
fixture.NewUser(userID)
|
|
|
|
log.Debug("Step 2: mirror F3 into Forgejo")
|
|
doer, err := user_model.GetAdminUser(context.Background())
|
|
assert.NoError(t, err)
|
|
forgejoLocalDestination := util.ForgejoForgeRoot(gof3.AllFeatures, doer, 0)
|
|
options := f3_common.NewMirrorOptionsRecurse()
|
|
forgejoLocalDestination.Forge.Mirror(context.Background(), fixture.Forge, options)
|
|
|
|
log.Debug("Step 3: change the Name of the user in F3 and mirror to Forgejo")
|
|
otherusername := "otheruser"
|
|
fixture.UserFormat.UserName = otherusername
|
|
fixture.Forge.Users.Upsert(context.Background(), fixture.UserFormat)
|
|
forgejoLocalDestination.Forge.Mirror(context.Background(), fixture.Forge, options)
|
|
|
|
log.Debug("Step 4: mirror Forgejo into F3 using the changed name")
|
|
f3 := util.F3ForgeRoot(gof3.AllFeatures, t.TempDir())
|
|
forgejoLocalOrigin := util.ForgejoForgeRoot(gof3.AllFeatures, doer, 0)
|
|
forgejoLocalOriginUser := forgejoLocalOrigin.Forge.Users.GetFromFormat(context.Background(), &format.User{UserName: otherusername})
|
|
options = f3_common.NewMirrorOptionsRecurse(forgejoLocalOriginUser)
|
|
f3.Forge.Mirror(context.Background(), forgejoLocalOrigin.Forge, options)
|
|
|
|
//
|
|
// verify the fixture and F3 are equivalent
|
|
//
|
|
files := f3_util.Command(context.Background(), "find", f3.GetDirectory())
|
|
assert.Contains(t, files, fmt.Sprintf("/user/%d", forgejoLocalOriginUser.GetID()))
|
|
})
|
|
}
|