// Copyright 2017 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT package setting import ( "net/http" "testing" asymkey_model "gitea.dev/models/asymkey" "gitea.dev/models/organization" "gitea.dev/models/perm" repo_model "gitea.dev/models/repo" "gitea.dev/models/unittest" user_model "gitea.dev/models/user" "gitea.dev/modules/gitrepo" "gitea.dev/modules/setting" "gitea.dev/modules/test" "gitea.dev/modules/web" "gitea.dev/services/context" "gitea.dev/services/contexttest" "gitea.dev/services/forms" mirror_service "gitea.dev/services/mirror" repo_service "gitea.dev/services/repository" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func TestAddReadOnlyDeployKey(t *testing.T) { defer test.MockVariableValue(&setting.SSH.RootPath, t.TempDir())() unittest.PrepareTestEnv(t) ctx, _ := contexttest.MockContext(t, "user2/repo1/settings/keys") contexttest.LoadUser(t, ctx, 2) contexttest.LoadRepo(t, ctx, 2) addKeyForm := forms.AddKeyForm{ Title: "read-only", Content: "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC4cn+iXnA4KvcQYSV88vGn0Yi91vG47t1P7okprVmhNTkipNRIHWr6WdCO4VDr/cvsRkuVJAsLO2enwjGWWueOO6BodiBgyAOZ/5t5nJNMCNuLGT5UIo/RI1b0WRQwxEZTRjt6mFNw6lH14wRd8ulsr9toSWBPMOGWoYs1PDeDL0JuTjL+tr1SZi/EyxCngpYszKdXllJEHyI79KQgeD0Vt3pTrkbNVTOEcCNqZePSVmUH8X8Vhugz3bnE0/iE9Pb5fkWO9c4AnM1FgI/8Bvp27Fw2ShryIXuR6kKvUqhVMTuOSDHwu6A8jLE5Owt3GAYugDpDYuwTVNGrHLXKpPzrGGPE/jPmaLCMZcsdkec95dYeU3zKODEm8UQZFhmJmDeWVJ36nGrGZHL4J5aTTaeFUJmmXDaJYiJ+K2/ioKgXqnXvltu0A9R8/LGy4nrTJRr4JMLuJFoUXvGm1gXQ70w2LSpk6yl71RNC0hCtsBe8BP8IhYCM0EP5jh7eCMQZNvM= nocomment\n", } web.SetForm(ctx, &addKeyForm) DeployKeysPost(ctx) assert.Equal(t, http.StatusSeeOther, ctx.Resp.WrittenStatus()) unittest.AssertExistsAndLoadBean(t, &asymkey_model.DeployKey{ Name: addKeyForm.Title, Content: addKeyForm.Content, Mode: perm.AccessModeRead, }) } func TestAddReadWriteOnlyDeployKey(t *testing.T) { defer test.MockVariableValue(&setting.SSH.RootPath, t.TempDir())() unittest.PrepareTestEnv(t) ctx, _ := contexttest.MockContext(t, "user2/repo1/settings/keys") contexttest.LoadUser(t, ctx, 2) contexttest.LoadRepo(t, ctx, 2) addKeyForm := forms.AddKeyForm{ Title: "read-write", Content: "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC4cn+iXnA4KvcQYSV88vGn0Yi91vG47t1P7okprVmhNTkipNRIHWr6WdCO4VDr/cvsRkuVJAsLO2enwjGWWueOO6BodiBgyAOZ/5t5nJNMCNuLGT5UIo/RI1b0WRQwxEZTRjt6mFNw6lH14wRd8ulsr9toSWBPMOGWoYs1PDeDL0JuTjL+tr1SZi/EyxCngpYszKdXllJEHyI79KQgeD0Vt3pTrkbNVTOEcCNqZePSVmUH8X8Vhugz3bnE0/iE9Pb5fkWO9c4AnM1FgI/8Bvp27Fw2ShryIXuR6kKvUqhVMTuOSDHwu6A8jLE5Owt3GAYugDpDYuwTVNGrHLXKpPzrGGPE/jPmaLCMZcsdkec95dYeU3zKODEm8UQZFhmJmDeWVJ36nGrGZHL4J5aTTaeFUJmmXDaJYiJ+K2/ioKgXqnXvltu0A9R8/LGy4nrTJRr4JMLuJFoUXvGm1gXQ70w2LSpk6yl71RNC0hCtsBe8BP8IhYCM0EP5jh7eCMQZNvM= nocomment\n", IsWritable: true, } web.SetForm(ctx, &addKeyForm) DeployKeysPost(ctx) assert.Equal(t, http.StatusSeeOther, ctx.Resp.WrittenStatus()) unittest.AssertExistsAndLoadBean(t, &asymkey_model.DeployKey{ Name: addKeyForm.Title, Content: addKeyForm.Content, Mode: perm.AccessModeWrite, }) } func TestCollaborationPost(t *testing.T) { unittest.PrepareTestEnv(t) ctx, _ := contexttest.MockContext(t, "user2/repo1/issues/labels") contexttest.LoadUser(t, ctx, 2) contexttest.LoadUser(t, ctx, 4) contexttest.LoadRepo(t, ctx, 1) ctx.Req.Form.Set("collaborator", "user4") u := &user_model.User{ LowerName: "user2", Type: user_model.UserTypeIndividual, } re := &repo_model.Repository{ ID: 2, Owner: u, } repo := &context.Repository{ Owner: u, Repository: re, } ctx.Repo = repo CollaborationPost(ctx) assert.Equal(t, http.StatusSeeOther, ctx.Resp.WrittenStatus()) exists, err := repo_model.IsCollaborator(ctx, re.ID, 4) assert.NoError(t, err) assert.True(t, exists) } func TestCollaborationPost_InactiveUser(t *testing.T) { unittest.PrepareTestEnv(t) ctx, _ := contexttest.MockContext(t, "user2/repo1/issues/labels") contexttest.LoadUser(t, ctx, 2) contexttest.LoadUser(t, ctx, 9) contexttest.LoadRepo(t, ctx, 1) ctx.Req.Form.Set("collaborator", "user9") repo := &context.Repository{ Owner: &user_model.User{ LowerName: "user2", }, } ctx.Repo = repo CollaborationPost(ctx) assert.Equal(t, http.StatusSeeOther, ctx.Resp.WrittenStatus()) assert.NotEmpty(t, ctx.Flash.ErrorMsg) } func TestCollaborationPost_AddCollaboratorTwice(t *testing.T) { unittest.PrepareTestEnv(t) ctx, _ := contexttest.MockContext(t, "user2/repo1/issues/labels") contexttest.LoadUser(t, ctx, 2) contexttest.LoadUser(t, ctx, 4) contexttest.LoadRepo(t, ctx, 1) ctx.Req.Form.Set("collaborator", "user4") u := &user_model.User{ LowerName: "user2", Type: user_model.UserTypeIndividual, } re := &repo_model.Repository{ ID: 2, Owner: u, } repo := &context.Repository{ Owner: u, Repository: re, } ctx.Repo = repo CollaborationPost(ctx) assert.Equal(t, http.StatusSeeOther, ctx.Resp.WrittenStatus()) exists, err := repo_model.IsCollaborator(ctx, re.ID, 4) assert.NoError(t, err) assert.True(t, exists) // Try adding the same collaborator again CollaborationPost(ctx) assert.Equal(t, http.StatusSeeOther, ctx.Resp.WrittenStatus()) assert.NotEmpty(t, ctx.Flash.ErrorMsg) } func TestCollaborationPost_NonExistentUser(t *testing.T) { unittest.PrepareTestEnv(t) ctx, _ := contexttest.MockContext(t, "user2/repo1/issues/labels") contexttest.LoadUser(t, ctx, 2) contexttest.LoadRepo(t, ctx, 1) ctx.Req.Form.Set("collaborator", "user34") repo := &context.Repository{ Owner: &user_model.User{ LowerName: "user2", }, } ctx.Repo = repo CollaborationPost(ctx) assert.Equal(t, http.StatusSeeOther, ctx.Resp.WrittenStatus()) assert.NotEmpty(t, ctx.Flash.ErrorMsg) } func TestAddTeamPost(t *testing.T) { unittest.PrepareTestEnv(t) ctx, _ := contexttest.MockContext(t, "org26/repo43") ctx.Req.Form.Set("team", "team11") org := &user_model.User{ LowerName: "org26", Type: user_model.UserTypeOrganization, } team := &organization.Team{ ID: 11, OrgID: 26, } re := &repo_model.Repository{ ID: 43, Owner: org, OwnerID: 26, } repo := &context.Repository{ Owner: &user_model.User{ ID: 26, LowerName: "org26", RepoAdminChangeTeamAccess: true, }, Repository: re, } ctx.Repo = repo AddTeamPost(ctx) assert.True(t, repo_service.HasRepository(t.Context(), team, re.ID)) assert.Equal(t, http.StatusSeeOther, ctx.Resp.WrittenStatus()) assert.Empty(t, ctx.Flash.ErrorMsg) } func TestAddTeamPost_NotAllowed(t *testing.T) { unittest.PrepareTestEnv(t) ctx, _ := contexttest.MockContext(t, "org26/repo43") ctx.Req.Form.Set("team", "team11") org := &user_model.User{ LowerName: "org26", Type: user_model.UserTypeOrganization, } team := &organization.Team{ ID: 11, OrgID: 26, } re := &repo_model.Repository{ ID: 43, Owner: org, OwnerID: 26, } repo := &context.Repository{ Owner: &user_model.User{ ID: 26, LowerName: "org26", RepoAdminChangeTeamAccess: false, }, Repository: re, } ctx.Repo = repo AddTeamPost(ctx) assert.False(t, repo_service.HasRepository(t.Context(), team, re.ID)) assert.Equal(t, http.StatusSeeOther, ctx.Resp.WrittenStatus()) assert.NotEmpty(t, ctx.Flash.ErrorMsg) } func TestAddTeamPost_AddTeamTwice(t *testing.T) { unittest.PrepareTestEnv(t) ctx, _ := contexttest.MockContext(t, "org26/repo43") ctx.Req.Form.Set("team", "team11") org := &user_model.User{ LowerName: "org26", Type: user_model.UserTypeOrganization, } team := &organization.Team{ ID: 11, OrgID: 26, } re := &repo_model.Repository{ ID: 43, Owner: org, OwnerID: 26, } repo := &context.Repository{ Owner: &user_model.User{ ID: 26, LowerName: "org26", RepoAdminChangeTeamAccess: true, }, Repository: re, } ctx.Repo = repo AddTeamPost(ctx) AddTeamPost(ctx) assert.True(t, repo_service.HasRepository(t.Context(), team, re.ID)) assert.Equal(t, http.StatusSeeOther, ctx.Resp.WrittenStatus()) assert.NotEmpty(t, ctx.Flash.ErrorMsg) } func TestAddTeamPost_NonExistentTeam(t *testing.T) { unittest.PrepareTestEnv(t) ctx, _ := contexttest.MockContext(t, "org26/repo43") ctx.Req.Form.Set("team", "team-non-existent") org := &user_model.User{ LowerName: "org26", Type: user_model.UserTypeOrganization, } re := &repo_model.Repository{ ID: 43, Owner: org, OwnerID: 26, } repo := &context.Repository{ Owner: &user_model.User{ ID: 26, LowerName: "org26", RepoAdminChangeTeamAccess: true, }, Repository: re, } ctx.Repo = repo AddTeamPost(ctx) assert.Equal(t, http.StatusSeeOther, ctx.Resp.WrittenStatus()) assert.NotEmpty(t, ctx.Flash.ErrorMsg) } func TestDeleteTeam(t *testing.T) { unittest.PrepareTestEnv(t) ctx, _ := contexttest.MockContext(t, "org3/team1/repo3") ctx.Req.Form.Set("id", "2") org := &user_model.User{ LowerName: "org3", Type: user_model.UserTypeOrganization, } team := &organization.Team{ ID: 2, OrgID: 3, } re := &repo_model.Repository{ ID: 3, Owner: org, OwnerID: 3, } repo := &context.Repository{ Owner: &user_model.User{ ID: 3, LowerName: "org3", RepoAdminChangeTeamAccess: true, }, Repository: re, } ctx.Repo = repo DeleteTeam(ctx) assert.False(t, repo_service.HasRepository(t.Context(), team, re.ID)) } func TestHandleSettingsPostMirrorPreservesExistingUsername(t *testing.T) { defer test.MockVariableValue(&setting.Mirror.Enabled, true)() unittest.PrepareTestEnv(t) // Use the existing fixture mirror repo (org3/repo5) which has a git repo on disk. mirrorRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 5}) mirror := unittest.AssertExistsAndLoadBean(t, &repo_model.Mirror{RepoID: 5}) require.NoError(t, mirror_service.UpdateAddress(t.Context(), mirror, "https://existing-user:existing-password@example.com/user2/repo1.git")) user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) ctx, _ := contexttest.MockContext(t, mirrorRepo.Link()+"/settings") contexttest.LoadUser(t, ctx, user.ID) contexttest.LoadRepo(t, ctx, mirrorRepo.ID) web.SetForm(ctx, &forms.RepoSettingForm{ Interval: "8h", MirrorAddress: "https://example.com/user2/repo1.git", MirrorPassword: "updated-password", }) handleSettingsPostMirror(ctx) assert.Equal(t, http.StatusSeeOther, ctx.Resp.WrittenStatus()) updatedMirror := unittest.AssertExistsAndLoadBean(t, &repo_model.Mirror{RepoID: mirrorRepo.ID}) assert.Equal(t, "https://example.com/user2/repo1.git", updatedMirror.RemoteAddress) updatedRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: mirrorRepo.ID}) assert.Equal(t, "https://example.com/user2/repo1.git", updatedRepo.OriginalURL) remoteURL, err := gitrepo.GitRemoteGetURL(t.Context(), updatedRepo, updatedMirror.GetRemoteName()) require.NoError(t, err) require.NotNil(t, remoteURL.User) assert.Equal(t, "existing-user", remoteURL.User.Username()) password, ok := remoteURL.User.Password() require.True(t, ok) assert.Equal(t, "updated-password", password) }