code.gitea.io/gitea@v1.21.7/tests/integration/ssh_key_test.go (about)

     1  // Copyright 2019 The Gitea Authors. All rights reserved.
     2  // SPDX-License-Identifier: MIT
     3  
     4  package integration
     5  
     6  import (
     7  	"fmt"
     8  	"net/http"
     9  	"net/url"
    10  	"os"
    11  	"path/filepath"
    12  	"testing"
    13  	"time"
    14  
    15  	auth_model "code.gitea.io/gitea/models/auth"
    16  	"code.gitea.io/gitea/modules/git"
    17  	api "code.gitea.io/gitea/modules/structs"
    18  
    19  	"github.com/stretchr/testify/assert"
    20  )
    21  
    22  func doCheckRepositoryEmptyStatus(ctx APITestContext, isEmpty bool) func(*testing.T) {
    23  	return doAPIGetRepository(ctx, func(t *testing.T, repository api.Repository) {
    24  		assert.Equal(t, isEmpty, repository.Empty)
    25  	})
    26  }
    27  
    28  func doAddChangesToCheckout(dstPath, filename string) func(*testing.T) {
    29  	return func(t *testing.T) {
    30  		assert.NoError(t, os.WriteFile(filepath.Join(dstPath, filename), []byte(fmt.Sprintf("# Testing Repository\n\nOriginally created in: %s at time: %v", dstPath, time.Now())), 0o644))
    31  		assert.NoError(t, git.AddChanges(dstPath, true))
    32  		signature := git.Signature{
    33  			Email: "test@example.com",
    34  			Name:  "test",
    35  			When:  time.Now(),
    36  		}
    37  		assert.NoError(t, git.CommitChanges(dstPath, git.CommitChangesOptions{
    38  			Committer: &signature,
    39  			Author:    &signature,
    40  			Message:   "Initial Commit",
    41  		}))
    42  	}
    43  }
    44  
    45  func TestPushDeployKeyOnEmptyRepo(t *testing.T) {
    46  	onGiteaRun(t, testPushDeployKeyOnEmptyRepo)
    47  }
    48  
    49  func testPushDeployKeyOnEmptyRepo(t *testing.T, u *url.URL) {
    50  	// OK login
    51  	ctx := NewAPITestContext(t, "user2", "deploy-key-empty-repo-1", auth_model.AccessTokenScopeWriteRepository, auth_model.AccessTokenScopeWriteUser)
    52  	ctxWithDeleteRepo := NewAPITestContext(t, "user2", "deploy-key-empty-repo-1", auth_model.AccessTokenScopeWriteRepository, auth_model.AccessTokenScopeWriteUser)
    53  
    54  	keyname := fmt.Sprintf("%s-push", ctx.Reponame)
    55  	u.Path = ctx.GitPath()
    56  
    57  	t.Run("CreateEmptyRepository", doAPICreateRepository(ctx, true))
    58  
    59  	t.Run("CheckIsEmpty", doCheckRepositoryEmptyStatus(ctx, true))
    60  
    61  	withKeyFile(t, keyname, func(keyFile string) {
    62  		t.Run("CreatePushDeployKey", doAPICreateDeployKey(ctx, keyname, keyFile, false))
    63  
    64  		// Setup the testing repository
    65  		dstPath := t.TempDir()
    66  
    67  		t.Run("InitTestRepository", doGitInitTestRepository(dstPath))
    68  
    69  		// Setup remote link
    70  		sshURL := createSSHUrl(ctx.GitPath(), u)
    71  
    72  		t.Run("AddRemote", doGitAddRemote(dstPath, "origin", sshURL))
    73  
    74  		t.Run("SSHPushTestRepository", doGitPushTestRepository(dstPath, "origin", "master"))
    75  
    76  		t.Run("CheckIsNotEmpty", doCheckRepositoryEmptyStatus(ctx, false))
    77  
    78  		t.Run("DeleteRepository", doAPIDeleteRepository(ctxWithDeleteRepo))
    79  	})
    80  }
    81  
    82  func TestKeyOnlyOneType(t *testing.T) {
    83  	onGiteaRun(t, testKeyOnlyOneType)
    84  }
    85  
    86  func testKeyOnlyOneType(t *testing.T, u *url.URL) {
    87  	// Once a key is a user key we cannot use it as a deploy key
    88  	// If we delete it from the user we should be able to use it as a deploy key
    89  	reponame := "ssh-key-test-repo"
    90  	username := "user2"
    91  	u.Path = fmt.Sprintf("%s/%s.git", username, reponame)
    92  	keyname := fmt.Sprintf("%s-push", reponame)
    93  
    94  	// OK login
    95  	ctx := NewAPITestContext(t, username, reponame, auth_model.AccessTokenScopeWriteRepository, auth_model.AccessTokenScopeWriteUser)
    96  	ctxWithDeleteRepo := NewAPITestContext(t, username, reponame, auth_model.AccessTokenScopeWriteRepository, auth_model.AccessTokenScopeWriteUser)
    97  
    98  	otherCtx := ctx
    99  	otherCtx.Reponame = "ssh-key-test-repo-2"
   100  	otherCtxWithDeleteRepo := ctxWithDeleteRepo
   101  	otherCtxWithDeleteRepo.Reponame = otherCtx.Reponame
   102  
   103  	failCtx := ctx
   104  	failCtx.ExpectedCode = http.StatusUnprocessableEntity
   105  
   106  	t.Run("CreateRepository", doAPICreateRepository(ctx, false))
   107  	t.Run("CreateOtherRepository", doAPICreateRepository(otherCtx, false))
   108  
   109  	withKeyFile(t, keyname, func(keyFile string) {
   110  		var userKeyPublicKeyID int64
   111  		t.Run("KeyCanOnlyBeUser", func(t *testing.T) {
   112  			dstPath := t.TempDir()
   113  
   114  			sshURL := createSSHUrl(ctx.GitPath(), u)
   115  
   116  			t.Run("FailToClone", doGitCloneFail(sshURL))
   117  
   118  			t.Run("CreateUserKey", doAPICreateUserKey(ctx, keyname, keyFile, func(t *testing.T, publicKey api.PublicKey) {
   119  				userKeyPublicKeyID = publicKey.ID
   120  			}))
   121  
   122  			t.Run("FailToAddReadOnlyDeployKey", doAPICreateDeployKey(failCtx, keyname, keyFile, true))
   123  
   124  			t.Run("FailToAddDeployKey", doAPICreateDeployKey(failCtx, keyname, keyFile, false))
   125  
   126  			t.Run("Clone", doGitClone(dstPath, sshURL))
   127  
   128  			t.Run("AddChanges", doAddChangesToCheckout(dstPath, "CHANGES1.md"))
   129  
   130  			t.Run("Push", doGitPushTestRepository(dstPath, "origin", "master"))
   131  
   132  			t.Run("DeleteUserKey", doAPIDeleteUserKey(ctx, userKeyPublicKeyID))
   133  		})
   134  
   135  		t.Run("KeyCanBeAnyDeployButNotUserAswell", func(t *testing.T) {
   136  			dstPath := t.TempDir()
   137  
   138  			sshURL := createSSHUrl(ctx.GitPath(), u)
   139  
   140  			t.Run("FailToClone", doGitCloneFail(sshURL))
   141  
   142  			// Should now be able to add...
   143  			t.Run("AddReadOnlyDeployKey", doAPICreateDeployKey(ctx, keyname, keyFile, true))
   144  
   145  			t.Run("Clone", doGitClone(dstPath, sshURL))
   146  
   147  			t.Run("AddChanges", doAddChangesToCheckout(dstPath, "CHANGES2.md"))
   148  
   149  			t.Run("FailToPush", doGitPushTestRepositoryFail(dstPath, "origin", "master"))
   150  
   151  			otherSSHURL := createSSHUrl(otherCtx.GitPath(), u)
   152  			dstOtherPath := t.TempDir()
   153  
   154  			t.Run("AddWriterDeployKeyToOther", doAPICreateDeployKey(otherCtx, keyname, keyFile, false))
   155  
   156  			t.Run("CloneOther", doGitClone(dstOtherPath, otherSSHURL))
   157  
   158  			t.Run("AddChangesToOther", doAddChangesToCheckout(dstOtherPath, "CHANGES3.md"))
   159  
   160  			t.Run("PushToOther", doGitPushTestRepository(dstOtherPath, "origin", "master"))
   161  
   162  			t.Run("FailToCreateUserKey", doAPICreateUserKey(failCtx, keyname, keyFile))
   163  		})
   164  
   165  		t.Run("DeleteRepositoryShouldReleaseKey", func(t *testing.T) {
   166  			otherSSHURL := createSSHUrl(otherCtx.GitPath(), u)
   167  			dstOtherPath := t.TempDir()
   168  
   169  			t.Run("DeleteRepository", doAPIDeleteRepository(ctxWithDeleteRepo))
   170  
   171  			t.Run("FailToCreateUserKeyAsStillDeploy", doAPICreateUserKey(failCtx, keyname, keyFile))
   172  
   173  			t.Run("MakeSureCloneOtherStillWorks", doGitClone(dstOtherPath, otherSSHURL))
   174  
   175  			t.Run("AddChangesToOther", doAddChangesToCheckout(dstOtherPath, "CHANGES3.md"))
   176  
   177  			t.Run("PushToOther", doGitPushTestRepository(dstOtherPath, "origin", "master"))
   178  
   179  			t.Run("DeleteOtherRepository", doAPIDeleteRepository(otherCtxWithDeleteRepo))
   180  
   181  			t.Run("RecreateRepository", doAPICreateRepository(ctxWithDeleteRepo, false))
   182  
   183  			t.Run("CreateUserKey", doAPICreateUserKey(ctx, keyname, keyFile, func(t *testing.T, publicKey api.PublicKey) {
   184  				userKeyPublicKeyID = publicKey.ID
   185  			}))
   186  
   187  			dstPath := t.TempDir()
   188  
   189  			sshURL := createSSHUrl(ctx.GitPath(), u)
   190  
   191  			t.Run("Clone", doGitClone(dstPath, sshURL))
   192  
   193  			t.Run("AddChanges", doAddChangesToCheckout(dstPath, "CHANGES1.md"))
   194  
   195  			t.Run("Push", doGitPushTestRepository(dstPath, "origin", "master"))
   196  		})
   197  
   198  		t.Run("DeleteUserKeyShouldRemoveAbilityToClone", func(t *testing.T) {
   199  			sshURL := createSSHUrl(ctx.GitPath(), u)
   200  
   201  			t.Run("DeleteUserKey", doAPIDeleteUserKey(ctx, userKeyPublicKeyID))
   202  
   203  			t.Run("FailToClone", doGitCloneFail(sshURL))
   204  		})
   205  	})
   206  }