diff options
Diffstat (limited to 'tests/integration/git_general_test.go')
-rw-r--r-- | tests/integration/git_general_test.go | 112 |
1 files changed, 85 insertions, 27 deletions
diff --git a/tests/integration/git_general_test.go b/tests/integration/git_general_test.go index a47cb75196..03bc8bdab8 100644 --- a/tests/integration/git_general_test.go +++ b/tests/integration/git_general_test.go @@ -11,8 +11,10 @@ import ( "net/http" "net/url" "os" + "os/exec" "path" "path/filepath" + "slices" "strconv" "testing" "time" @@ -31,7 +33,9 @@ import ( gitea_context "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/tests" + "github.com/kballard/go-shellquote" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) const ( @@ -80,6 +84,7 @@ func testGitGeneral(t *testing.T, u *url.URL) { mediaTest(t, &httpContext, pushedFilesStandard[0], pushedFilesStandard[1], pushedFilesLFS[0], pushedFilesLFS[1]) t.Run("CreateAgitFlowPull", doCreateAgitFlowPull(dstPath, &httpContext, "test/head")) + t.Run("CreateProtectedBranch", doCreateProtectedBranch(&httpContext, dstPath)) t.Run("BranchProtectMerge", doBranchProtectPRMerge(&httpContext, dstPath)) t.Run("AutoMerge", doAutoPRMerge(&httpContext, dstPath)) t.Run("CreatePRAndSetManuallyMerged", doCreatePRAndSetManuallyMerged(httpContext, httpContext, dstPath, "master", "test-manually-merge")) @@ -104,7 +109,12 @@ func testGitGeneral(t *testing.T, u *url.URL) { // Setup key the user ssh key withKeyFile(t, keyname, func(keyFile string) { - t.Run("CreateUserKey", doAPICreateUserKey(sshContext, "test-key", keyFile)) + var keyID int64 + t.Run("CreateUserKey", doAPICreateUserKey(sshContext, "test-key", keyFile, func(t *testing.T, key api.PublicKey) { + keyID = key.ID + })) + assert.NotZero(t, keyID) + t.Run("LFSAccessTest", doSSHLFSAccessTest(sshContext, keyID)) // Setup remote link // TODO: get url from api @@ -121,6 +131,7 @@ func testGitGeneral(t *testing.T, u *url.URL) { mediaTest(t, &sshContext, pushedFilesStandard[0], pushedFilesStandard[1], pushedFilesLFS[0], pushedFilesLFS[1]) t.Run("CreateAgitFlowPull", doCreateAgitFlowPull(dstPath, &sshContext, "test/head2")) + t.Run("CreateProtectedBranch", doCreateProtectedBranch(&sshContext, dstPath)) t.Run("BranchProtectMerge", doBranchProtectPRMerge(&sshContext, dstPath)) t.Run("MergeFork", func(t *testing.T) { defer tests.PrintCurrentTest(t)() @@ -134,6 +145,36 @@ func testGitGeneral(t *testing.T, u *url.URL) { }) } +func doSSHLFSAccessTest(_ APITestContext, keyID int64) func(*testing.T) { + return func(t *testing.T) { + sshCommand := os.Getenv("GIT_SSH_COMMAND") // it is set in withKeyFile + sshCmdParts, err := shellquote.Split(sshCommand) // and parse the ssh command to construct some mocked arguments + require.NoError(t, err) + + t.Run("User2AccessOwned", func(t *testing.T) { + sshCmdUser2Self := append(slices.Clone(sshCmdParts), + "-p", strconv.Itoa(setting.SSH.ListenPort), "git@"+setting.SSH.ListenHost, + "git-lfs-authenticate", "user2/repo1.git", "upload", // accessible to own repo + ) + cmd := exec.CommandContext(git.DefaultContext, sshCmdUser2Self[0], sshCmdUser2Self[1:]...) + _, err := cmd.Output() + assert.NoError(t, err) // accessible, no error + }) + + t.Run("User2AccessOther", func(t *testing.T) { + sshCmdUser2Other := append(slices.Clone(sshCmdParts), + "-p", strconv.Itoa(setting.SSH.ListenPort), "git@"+setting.SSH.ListenHost, + "git-lfs-authenticate", "user5/repo4.git", "upload", // inaccessible to other's (user5/repo4) + ) + cmd := exec.CommandContext(git.DefaultContext, sshCmdUser2Other[0], sshCmdUser2Other[1:]...) + _, err := cmd.Output() + var errExit *exec.ExitError + require.ErrorAs(t, err, &errExit) // inaccessible, error + assert.Contains(t, string(errExit.Stderr), fmt.Sprintf("User: 2:user2 with Key: %d:test-key is not authorized to write to user5/repo4.", keyID)) + }) + } +} + func ensureAnonymousClone(t *testing.T, u *url.URL) { dstLocalPath := t.TempDir() t.Run("CloneAnonymous", doGitClone(dstLocalPath, u)) @@ -325,6 +366,34 @@ func generateCommitWithNewData(size int, repoPath, email, fullName, prefix strin return filepath.Base(tmpFile.Name()), err } +func doCreateProtectedBranch(baseCtx *APITestContext, dstPath string) func(t *testing.T) { + return func(t *testing.T) { + defer tests.PrintCurrentTest(t)() + ctx := NewAPITestContext(t, baseCtx.Username, baseCtx.Reponame, auth_model.AccessTokenScopeWriteRepository) + + t.Run("ProtectBranchWithFilePatterns", doProtectBranch(ctx, "release-*", baseCtx.Username, "", "", "config*")) + + // push a new branch without any new commits + t.Run("CreateProtectedBranch-NoChanges", doGitCreateBranch(dstPath, "release-v1.0")) + t.Run("PushProtectedBranch-NoChanges", doGitPushTestRepository(dstPath, "origin", "release-v1.0")) + t.Run("CheckoutMaster-NoChanges", doGitCheckoutBranch(dstPath, "master")) + + // push a new branch with a new unprotected file + t.Run("CreateProtectedBranch-UnprotectedFile", doGitCreateBranch(dstPath, "release-v2.0")) + _, err := generateCommitWithNewData(testFileSizeSmall, dstPath, "user2@example.com", "User Two", "abc.txt") + assert.NoError(t, err) + t.Run("PushProtectedBranch-UnprotectedFile", doGitPushTestRepository(dstPath, "origin", "release-v2.0")) + t.Run("CheckoutMaster-UnprotectedFile", doGitCheckoutBranch(dstPath, "master")) + + // push a new branch with a new protected file + t.Run("CreateProtectedBranch-ProtectedFile", doGitCreateBranch(dstPath, "release-v3.0")) + _, err = generateCommitWithNewData(testFileSizeSmall, dstPath, "user2@example.com", "User Two", "config") + assert.NoError(t, err) + t.Run("PushProtectedBranch-ProtectedFile", doGitPushTestRepositoryFail(dstPath, "origin", "release-v3.0")) + t.Run("CheckoutMaster-ProtectedFile", doGitCheckoutBranch(dstPath, "master")) + } +} + func doBranchProtectPRMerge(baseCtx *APITestContext, dstPath string) func(t *testing.T) { return func(t *testing.T) { defer tests.PrintCurrentTest(t)() @@ -334,27 +403,23 @@ func doBranchProtectPRMerge(baseCtx *APITestContext, dstPath string) func(t *tes ctx := NewAPITestContext(t, baseCtx.Username, baseCtx.Reponame, auth_model.AccessTokenScopeWriteRepository) // Protect branch without any whitelisting - t.Run("ProtectBranchNoWhitelist", func(t *testing.T) { - doProtectBranch(ctx, "protected", "", "", "") - }) + t.Run("ProtectBranchNoWhitelist", doProtectBranch(ctx, "protected", "", "", "", "")) // Try to push without permissions, which should fail t.Run("TryPushWithoutPermissions", func(t *testing.T) { _, err := generateCommitWithNewData(testFileSizeSmall, dstPath, "user2@example.com", "User Two", "branch-data-file-") assert.NoError(t, err) - doGitPushTestRepositoryFail(dstPath, "origin", "protected") + doGitPushTestRepositoryFail(dstPath, "origin", "protected")(t) }) // Set up permissions for normal push but not force push - t.Run("SetupNormalPushPermissions", func(t *testing.T) { - doProtectBranch(ctx, "protected", baseCtx.Username, "", "") - }) + t.Run("SetupNormalPushPermissions", doProtectBranch(ctx, "protected", baseCtx.Username, "", "", "")) // Normal push should work t.Run("NormalPushWithPermissions", func(t *testing.T) { _, err := generateCommitWithNewData(testFileSizeSmall, dstPath, "user2@example.com", "User Two", "branch-data-file-") assert.NoError(t, err) - doGitPushTestRepository(dstPath, "origin", "protected") + doGitPushTestRepository(dstPath, "origin", "protected")(t) }) // Try to force push without force push permissions, which should fail @@ -364,30 +429,22 @@ func doBranchProtectPRMerge(baseCtx *APITestContext, dstPath string) func(t *tes _, err := generateCommitWithNewData(testFileSizeSmall, dstPath, "user2@example.com", "User Two", "branch-data-file-new") assert.NoError(t, err) }) - doGitPushTestRepositoryFail(dstPath, "-f", "origin", "protected") + doGitPushTestRepositoryFail(dstPath, "-f", "origin", "protected")(t) }) // Set up permissions for force push but not normal push - t.Run("SetupForcePushPermissions", func(t *testing.T) { - doProtectBranch(ctx, "protected", "", baseCtx.Username, "") - }) + t.Run("SetupForcePushPermissions", doProtectBranch(ctx, "protected", "", baseCtx.Username, "", "")) // Try to force push without normal push permissions, which should fail - t.Run("ForcePushWithoutNormalPermissions", func(t *testing.T) { - doGitPushTestRepositoryFail(dstPath, "-f", "origin", "protected") - }) + t.Run("ForcePushWithoutNormalPermissions", doGitPushTestRepositoryFail(dstPath, "-f", "origin", "protected")) // Set up permissions for normal and force push (both are required to force push) - t.Run("SetupNormalAndForcePushPermissions", func(t *testing.T) { - doProtectBranch(ctx, "protected", baseCtx.Username, baseCtx.Username, "") - }) + t.Run("SetupNormalAndForcePushPermissions", doProtectBranch(ctx, "protected", baseCtx.Username, baseCtx.Username, "", "")) // Force push should now work - t.Run("ForcePushWithPermissions", func(t *testing.T) { - doGitPushTestRepository(dstPath, "-f", "origin", "protected") - }) + t.Run("ForcePushWithPermissions", doGitPushTestRepository(dstPath, "-f", "origin", "protected")) - t.Run("ProtectProtectedBranchNoWhitelist", doProtectBranch(ctx, "protected", "", "", "")) + t.Run("ProtectProtectedBranchNoWhitelist", doProtectBranch(ctx, "protected", "", "", "", "")) t.Run("PushToUnprotectedBranch", doGitPushTestRepository(dstPath, "origin", "protected:unprotected")) var pr api.PullRequest var err error @@ -409,14 +466,14 @@ func doBranchProtectPRMerge(baseCtx *APITestContext, dstPath string) func(t *tes t.Run("MergePR", doAPIMergePullRequest(ctx, baseCtx.Username, baseCtx.Reponame, pr.Index)) t.Run("PullProtected", doGitPull(dstPath, "origin", "protected")) - t.Run("ProtectProtectedBranchUnprotectedFilePaths", doProtectBranch(ctx, "protected", "", "", "unprotected-file-*")) + t.Run("ProtectProtectedBranchUnprotectedFilePaths", doProtectBranch(ctx, "protected", "", "", "unprotected-file-*", "")) t.Run("GenerateCommit", func(t *testing.T) { _, err := generateCommitWithNewData(testFileSizeSmall, dstPath, "user2@example.com", "User Two", "unprotected-file-") assert.NoError(t, err) }) t.Run("PushUnprotectedFilesToProtectedBranch", doGitPushTestRepository(dstPath, "origin", "protected")) - t.Run("ProtectProtectedBranchWhitelist", doProtectBranch(ctx, "protected", baseCtx.Username, "", "")) + t.Run("ProtectProtectedBranchWhitelist", doProtectBranch(ctx, "protected", baseCtx.Username, "", "", "")) t.Run("CheckoutMaster", doGitCheckoutBranch(dstPath, "master")) t.Run("CreateBranchForced", doGitCreateBranch(dstPath, "toforce")) @@ -431,7 +488,7 @@ func doBranchProtectPRMerge(baseCtx *APITestContext, dstPath string) func(t *tes } } -func doProtectBranch(ctx APITestContext, branch, userToWhitelistPush, userToWhitelistForcePush, unprotectedFilePatterns string) func(t *testing.T) { +func doProtectBranch(ctx APITestContext, branch, userToWhitelistPush, userToWhitelistForcePush, unprotectedFilePatterns, protectedFilePatterns string) func(t *testing.T) { // We are going to just use the owner to set the protection. return func(t *testing.T) { csrf := GetUserCSRFToken(t, ctx.Session) @@ -440,6 +497,7 @@ func doProtectBranch(ctx APITestContext, branch, userToWhitelistPush, userToWhit "_csrf": csrf, "rule_name": branch, "unprotected_file_patterns": unprotectedFilePatterns, + "protected_file_patterns": protectedFilePatterns, } if userToWhitelistPush != "" { @@ -465,7 +523,7 @@ func doProtectBranch(ctx APITestContext, branch, userToWhitelistPush, userToWhit // Check if master branch has been locked successfully flashCookie := ctx.Session.GetCookie(gitea_context.CookieNameFlash) assert.NotNil(t, flashCookie) - assert.EqualValues(t, "success%3DBranch%2Bprotection%2Bfor%2Brule%2B%2522"+url.QueryEscape(branch)+"%2522%2Bhas%2Bbeen%2Bupdated.", flashCookie.Value) + assert.EqualValues(t, "success%3DBranch%2Bprotection%2Bfor%2Brule%2B%2522"+url.QueryEscape(url.QueryEscape(branch))+"%2522%2Bhas%2Bbeen%2Bupdated.", flashCookie.Value) } } |