From 8efa73dcbfd15e163a195ebe831c20c2d2561ef1 Mon Sep 17 00:00:00 2001 From: kim-codefresh Date: Wed, 11 Jan 2023 10:39:31 +0200 Subject: [PATCH] CR-15777 (#409) * from repo CR-15777 Signed-off-by: kim-codefresh * bump Signed-off-by: kim-codefresh * resolve comments Signed-off-by: kim-codefresh * fix test Signed-off-by: kim-codefresh Signed-off-by: kim-codefresh --- pkg/git/repository.go | 17 ++++++ pkg/git/repository_test.go | 116 ++++++++++++++++++++++++++++++++++--- 2 files changed, 126 insertions(+), 7 deletions(-) diff --git a/pkg/git/repository.go b/pkg/git/repository.go index 82167966..0d4cecfe 100644 --- a/pkg/git/repository.go +++ b/pkg/git/repository.go @@ -242,6 +242,11 @@ func (o *CloneOptions) GetRepo(ctx context.Context) (Repository, fs.FS, error) { default: return nil, nil, err } + } else if o.CloneForWrite { + err = validateRepoWritePermission(ctx, r) + if err != nil { + return nil, nil, fmt.Errorf("failed to validate repository write permission: %w", err) + } } bootstrapFS, err := o.FS.Chroot(o.path) @@ -252,6 +257,18 @@ func (o *CloneOptions) GetRepo(ctx context.Context) (Repository, fs.FS, error) { return r, fs.Create(bootstrapFS), nil } +var validateRepoWritePermission = func(ctx context.Context, r *repo) error { + _, err := r.Persist(ctx, &PushOptions{ + CommitMsg: "Validating repository write permission", + }) + + if err != nil { + return fmt.Errorf("failed pushing commit to repository: %w", err) + } + + return nil +} + func (o *CloneOptions) URL() string { return o.url } diff --git a/pkg/git/repository_test.go b/pkg/git/repository_test.go index 22995ba3..76662618 100644 --- a/pkg/git/repository_test.go +++ b/pkg/git/repository_test.go @@ -596,12 +596,13 @@ func Test_clone(t *testing.T) { func TestGetRepo(t *testing.T) { tests := map[string]struct { - opts *CloneOptions - wantErr string - cloneFn func(context.Context, *CloneOptions) (*repo, error) - createRepoFn func(context.Context, *CloneOptions) (defaultBranch string, err error) - initRepoFn func(context.Context, *CloneOptions, string) (*repo, error) - assertFn func(*testing.T, Repository, fs.FS, error) + opts *CloneOptions + wantErr string + cloneFn func(context.Context, *CloneOptions) (*repo, error) + validateRepoWritePermissionFn func(ctx context.Context, r *repo) error + createRepoFn func(context.Context, *CloneOptions) (defaultBranch string, err error) + initRepoFn func(context.Context, *CloneOptions, string) (*repo, error) + assertFn func(*testing.T, Repository, fs.FS, error) }{ "Should get a repo": { opts: &CloneOptions{ @@ -611,6 +612,9 @@ func TestGetRepo(t *testing.T) { cloneFn: func(_ context.Context, opts *CloneOptions) (*repo, error) { return &repo{}, nil }, + validateRepoWritePermissionFn: func(ctx context.Context, r *repo) error { + return nil + }, assertFn: func(t *testing.T, r Repository, f fs.FS, e error) { assert.NotNil(t, r) assert.NotNil(t, f) @@ -708,20 +712,25 @@ func TestGetRepo(t *testing.T) { assert.NotNil(t, f) assert.Nil(t, e) }, + validateRepoWritePermissionFn: func(ctx context.Context, r *repo) error { + return nil + }, }, } - origClone, origCreateRepo, origInitRepo := clone, createRepo, initRepo + origClone, origCreateRepo, origInitRepo, origValidateRepoWritePermission := clone, createRepo, initRepo, validateRepoWritePermission defer func() { clone = origClone createRepo = origCreateRepo initRepo = origInitRepo + validateRepoWritePermission = origValidateRepoWritePermission }() for tname, tt := range tests { t.Run(tname, func(t *testing.T) { clone = tt.cloneFn createRepo = tt.createRepoFn initRepo = tt.initRepoFn + validateRepoWritePermission = tt.validateRepoWritePermissionFn if tt.opts != nil { tt.opts.Parse() } @@ -1550,3 +1559,96 @@ func Test_repo_commit(t *testing.T) { }) } } +func Test_validateRepoWritePermission(t *testing.T) { + tests := map[string]struct { + opts *PushOptions + wantErr bool + beforeFn func(r *mocks.MockRepository, w *mocks.MockWorktree) + }{ + "Should fail if push context failed": { + opts: nil, + wantErr: true, + beforeFn: func(r *mocks.MockRepository, w *mocks.MockWorktree) { + r.EXPECT().PushContext(gomock.Any(), &gg.PushOptions{ + Auth: nil, + Progress: os.Stderr, + }). + Times(1). + Return(fmt.Errorf("some error")) + w.EXPECT().AddGlob(gomock.Any()). + Times(1). + Return(nil) + w.EXPECT().Commit("Validating repository write permission", gomock.Any()). + Times(1). + Return(plumbing.Hash{}, nil) + }, + }, + "Should fail if commit failed": { + opts: nil, + wantErr: true, + beforeFn: func(r *mocks.MockRepository, w *mocks.MockWorktree) { + w.EXPECT().AddGlob(gomock.Any()). + Times(1). + Return(nil) + w.EXPECT().Commit("Validating repository write permission", gomock.Any()). + Times(1). + Return(plumbing.Hash{}, fmt.Errorf("some error")) + }, + }, + "Should succeed if push context succeed": { + opts: nil, + wantErr: false, + beforeFn: func(r *mocks.MockRepository, w *mocks.MockWorktree) { + r.EXPECT().PushContext(gomock.Any(), &gg.PushOptions{ + Auth: nil, + Progress: os.Stderr, + }). + Times(1). + Return(nil) + w.EXPECT().AddGlob(gomock.Any()). + Times(1). + Return(nil) + w.EXPECT().Commit("Validating repository write permission", gomock.Any()). + Times(1). + Return(plumbing.Hash{}, nil) + }, + }, + } + + gitConfig := &config.Config{ + User: struct { + Name string + Email string + }{ + Name: "name", + Email: "email", + }, + } + + for tname, tt := range tests { + t.Run(tname, func(t *testing.T) { + ctrl := gomock.NewController(t) + mockRepo := mocks.NewMockRepository(ctrl) + mockWt := mocks.NewMockWorktree(ctrl) + mockProvider := &mockProvider{} + + mockRepo.EXPECT().ConfigScoped(gomock.Any()).Return(gitConfig, nil).AnyTimes() + getProvider = func(providerType, repoURL string, auth *Auth) (Provider, error) { return mockProvider, nil } + worktree = func(r gogit.Repository) (gogit.Worktree, error) { return mockWt, nil } + + r := &repo{ + Repository: mockRepo, + progress: os.Stderr, + } + + tt.beforeFn(mockRepo, mockWt) + + err := validateRepoWritePermission(context.Background(), r) + if (err != nil) != tt.wantErr { + t.Errorf("error = %v, wantErr %v", err, tt.wantErr) + return + } + + }) + } +}