From f51050e8c07353be5e0196b83d227bda145616f9 Mon Sep 17 00:00:00 2001 From: Paulo Gomes Date: Tue, 26 Jul 2022 11:17:12 +0100 Subject: [PATCH] Enrich 'early EOF' error message Signed-off-by: Paulo Gomes --- controllers/git_test.go | 57 +++++++++++++++++-- .../imageupdateautomation_controller.go | 3 + controllers/update_test.go | 31 ++++++---- go.mod | 12 ++-- go.sum | 20 +++---- 5 files changed, 92 insertions(+), 31 deletions(-) diff --git a/controllers/git_test.go b/controllers/git_test.go index 85472e80..1040b58c 100644 --- a/controllers/git_test.go +++ b/controllers/git_test.go @@ -14,6 +14,7 @@ import ( "k8s.io/apimachinery/pkg/types" "github.com/fluxcd/pkg/gittestserver" + "github.com/fluxcd/source-controller/pkg/git" ) func populateRepoFromFixture(repo *libgit2.Repository, fixture string) error { @@ -141,13 +142,13 @@ func TestPushRejected(t *testing.T) { repoURL := gitServer.HTTPAddressWithCredentials() + "/appconfig.git" cloneCtx, cancel := context.WithTimeout(ctx, time.Second*10) defer cancel() - repo, err := clone(cloneCtx, repoURL, "test") + repo, err := clone(cloneCtx, repoURL, "test", nil) if err != nil { t.Fatal(err) } defer repo.Free() - cleanup, err := configureTransportOptsForRepo(repo) + cleanup, err := configureTransportOptsForRepo(repo, nil) if err != nil { t.Fatal(err) } @@ -172,6 +173,54 @@ func TestPushRejected(t *testing.T) { } } +func TestEarlyEOF(t *testing.T) { + g := NewWithT(t) + + gitServer, err := gittestserver.NewTempGitServer() + g.Expect(err).ToNot(HaveOccurred()) + defer os.RemoveAll(gitServer.Root()) + + username := "norris" + password := "chuck" + + gitServer. + AutoCreate(). + KeyDir(filepath.Join(t.TempDir(), "keys")). + Auth(username, password). + ReadOnly(true) + + err = gitServer.StartHTTP() + g.Expect(err).ToNot(HaveOccurred()) + + err = initGitRepo(gitServer, "testdata/appconfig", "test", "/appconfig.git") + g.Expect(err).ToNot(HaveOccurred()) + + repoURL := gitServer.HTTPAddressWithCredentials() + "/appconfig.git" + cloneCtx, cancel := context.WithTimeout(ctx, time.Second*10) + defer cancel() + + access := repoAccess{ + auth: &git.AuthOptions{ + Username: username, + Password: password, + }, + } + + repo, err := clone(cloneCtx, repoURL, "test", access.auth) + g.Expect(err).ToNot(HaveOccurred()) + + defer repo.Free() + + cleanup, err := configureTransportOptsForRepo(repo, access.auth) + g.Expect(err).ToNot(HaveOccurred()) + + defer cleanup() + + err = push(context.TODO(), repo.Workdir(), "test", access) + g.Expect(err).To(HaveOccurred()) + g.Expect(err.Error()).To(ContainSubstring("early EOF (the SSH key may not have write access to the repository)")) +} + func Test_switchToBranch(t *testing.T) { g := NewWithT(t) gitServer, err := gittestserver.NewTempGitServer() @@ -190,7 +239,7 @@ func Test_switchToBranch(t *testing.T) { repoURL := gitServer.HTTPAddressWithCredentials() + "/appconfig.git" cloneCtx, cancel := context.WithTimeout(ctx, time.Second*10) defer cancel() - repo, err := clone(cloneCtx, repoURL, branch) + repo, err := clone(cloneCtx, repoURL, branch, nil) g.Expect(err).ToNot(HaveOccurred()) defer repo.Free() @@ -200,7 +249,7 @@ func Test_switchToBranch(t *testing.T) { target := head.Target() // register transport options and update remote to transport url - cleanup, err := configureTransportOptsForRepo(repo) + cleanup, err := configureTransportOptsForRepo(repo, nil) if err != nil { t.Fatal(err) } diff --git a/controllers/imageupdateautomation_controller.go b/controllers/imageupdateautomation_controller.go index 8c7c03b3..0e2c1f7c 100644 --- a/controllers/imageupdateautomation_controller.go +++ b/controllers/imageupdateautomation_controller.go @@ -887,6 +887,9 @@ func push(ctx context.Context, path, branch string, access repoAccess) error { ProxyOptions: libgit2.ProxyOptions{Type: libgit2.ProxyTypeAuto}, }) if err != nil { + if strings.Contains(err.Error(), "early EOF") { + return fmt.Errorf("%w (the SSH key may not have write access to the repository)", err) + } return libgit2PushError(err) } return callbackErr diff --git a/controllers/update_test.go b/controllers/update_test.go index 2334cbd8..aa773423 100644 --- a/controllers/update_test.go +++ b/controllers/update_test.go @@ -54,6 +54,7 @@ import ( "github.com/fluxcd/pkg/gittestserver" "github.com/fluxcd/pkg/ssh" sourcev1 "github.com/fluxcd/source-controller/api/v1beta2" + "github.com/fluxcd/source-controller/pkg/git" "github.com/fluxcd/source-controller/pkg/git/libgit2/managed" imagev1 "github.com/fluxcd/image-automation-controller/api/v1beta1" @@ -484,7 +485,7 @@ func TestImageAutomationReconciler_e2e(t *testing.T) { // Clone the repo locally. cloneCtx, cancel := context.WithTimeout(ctx, timeout) defer cancel() - localRepo, err := clone(cloneCtx, cloneLocalRepoURL, branch) + localRepo, err := clone(cloneCtx, cloneLocalRepoURL, branch, nil) g.Expect(err).ToNot(HaveOccurred(), "failed to clone git repo") defer localRepo.Free() @@ -628,7 +629,7 @@ func TestImageAutomationReconciler_e2e(t *testing.T) { // separate localRepo. cloneCtx, cancel := context.WithTimeout(ctx, timeout) defer cancel() - localRepo, err := clone(cloneCtx, cloneLocalRepoURL, branch) + localRepo, err := clone(cloneCtx, cloneLocalRepoURL, branch, nil) g.Expect(err).ToNot(HaveOccurred(), "failed to clone git repo") defer localRepo.Free() @@ -880,7 +881,7 @@ func compareRepoWithExpected(g *WithT, repoURL, branch, fixture string, changeFi changeFixture(expected) cloneCtx, cancel := context.WithTimeout(ctx, timeout) defer cancel() - repo, err := clone(cloneCtx, repoURL, branch) + repo, err := clone(cloneCtx, repoURL, branch, nil) g.Expect(err).ToNot(HaveOccurred()) defer repo.Free() // NOTE: The workdir contains a trailing /. Clean it to not confuse the @@ -897,7 +898,7 @@ func compareRepoWithExpected(g *WithT, repoURL, branch, fixture string, changeFi // it tries to figure it out by looking at the remote url of origin. It returns a function // which removes the transport options for this repo and sets the remote url of the origin // back to the actual url. Callers are expected to call this function in a deferred manner. -func configureTransportOptsForRepo(repo *libgit2.Repository) (func(), error) { +func configureTransportOptsForRepo(repo *libgit2.Repository, authOpts *git.AuthOptions) (func(), error) { origin, err := repo.Remotes.Lookup(originRemote) if err != nil { return nil, err @@ -911,6 +912,7 @@ func configureTransportOptsForRepo(repo *libgit2.Repository) (func(), error) { transportOptsURL := u.Scheme + "://" + randStringRunes(5) managed.AddTransportOptions(transportOptsURL, managed.TransportOptions{ TargetURL: repoURL, + AuthOpts: authOpts, }) err = repo.Remotes.SetUrl(originRemote, transportOptsURL) @@ -926,7 +928,7 @@ func configureTransportOptsForRepo(repo *libgit2.Repository) (func(), error) { func commitInRepo(g *WithT, repoURL, branch, msg string, changeFiles func(path string)) *libgit2.Oid { cloneCtx, cancel := context.WithTimeout(ctx, timeout) defer cancel() - repo, err := clone(cloneCtx, repoURL, branch) + repo, err := clone(cloneCtx, repoURL, branch, nil) g.Expect(err).ToNot(HaveOccurred()) defer repo.Free() @@ -940,7 +942,7 @@ func commitInRepo(g *WithT, repoURL, branch, msg string, changeFiles func(path s id, err := commitWorkDir(repo, branch, msg, sig) g.Expect(err).ToNot(HaveOccurred()) - cleanup, err := configureTransportOptsForRepo(repo) + cleanup, err := configureTransportOptsForRepo(repo, nil) g.Expect(err).ToNot(HaveOccurred()) defer cleanup() origin, err := repo.Remotes.Lookup(originRemote) @@ -1177,15 +1179,22 @@ func mockSignature(time time.Time) *git2go.Signature { } } -func clone(ctx context.Context, repoURL, branchName string) (*git2go.Repository, error) { +func clone(ctx context.Context, repoURL, branchName string, authOpts *git.AuthOptions) (*git2go.Repository, error) { dir, err := os.MkdirTemp("", "iac-clone-*") if err != nil { return nil, err } - transportOptsURL := "http://" + randStringRunes(5) + + u, err := url.Parse(repoURL) + if err != nil { + return nil, err + } + + transportOptsURL := u.Scheme + "://" + randStringRunes(5) managed.AddTransportOptions(transportOptsURL, managed.TransportOptions{ TargetURL: repoURL, Context: ctx, + AuthOpts: authOpts, }) defer managed.RemoveTransportOptions(transportOptsURL) @@ -1214,7 +1223,7 @@ func clone(ctx context.Context, repoURL, branchName string) (*git2go.Repository, func waitForNewHead(g *WithT, repo *git2go.Repository, branch, preChangeHash string) { var commitToResetTo *git2go.Commit - cleanup, err := configureTransportOptsForRepo(repo) + cleanup, err := configureTransportOptsForRepo(repo, nil) g.Expect(err).ToNot(HaveOccurred()) defer cleanup() @@ -1272,7 +1281,7 @@ func commitIdFromBranch(repo *git2go.Repository, branchName string) string { } func getRemoteHead(repo *git2go.Repository, branchName string) (*git2go.Oid, error) { - cleanup, err := configureTransportOptsForRepo(repo) + cleanup, err := configureTransportOptsForRepo(repo, nil) if err != nil { return nil, err } @@ -1460,7 +1469,7 @@ func testWithCustomRepoAndImagePolicy( repoURL := gitServer.HTTPAddressWithCredentials() + repositoryPath cloneCtx, cancel := context.WithTimeout(ctx, timeout) defer cancel() - localRepo, err := clone(cloneCtx, repoURL, args.branch) + localRepo, err := clone(cloneCtx, repoURL, args.branch, nil) g.Expect(err).ToNot(HaveOccurred(), "failed to clone git repo") defer localRepo.Free() diff --git a/go.mod b/go.mod index b9c5e7d7..5c3d71bb 100644 --- a/go.mod +++ b/go.mod @@ -12,7 +12,7 @@ require ( github.com/fluxcd/image-reflector-controller/api v0.19.3 github.com/fluxcd/pkg/apis/acl v0.0.3 github.com/fluxcd/pkg/apis/meta v0.14.2 - github.com/fluxcd/pkg/gittestserver v0.5.4 + github.com/fluxcd/pkg/gittestserver v0.6.0 github.com/fluxcd/pkg/runtime v0.16.2 github.com/fluxcd/pkg/ssh v0.5.0 github.com/fluxcd/source-controller v0.25.10 @@ -23,6 +23,7 @@ require ( github.com/onsi/gomega v1.19.0 github.com/otiai10/copy v1.7.0 github.com/spf13/pflag v1.0.5 + golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d k8s.io/api v0.24.2 k8s.io/apimachinery v0.24.2 k8s.io/client-go v0.24.2 @@ -55,7 +56,7 @@ require ( github.com/emicklei/go-restful/v3 v3.8.0 // indirect github.com/emirpasic/gods v1.18.1 // indirect github.com/evanphx/json-patch v5.6.0+incompatible // indirect - github.com/fluxcd/gitkit v0.5.1 // indirect + github.com/fluxcd/gitkit v0.6.0 // indirect github.com/fluxcd/pkg/gitutil v0.1.0 // indirect github.com/fluxcd/pkg/version v0.1.0 // indirect github.com/fsnotify/fsnotify v1.5.1 // indirect @@ -110,10 +111,9 @@ require ( go.uber.org/atomic v1.7.0 // indirect go.uber.org/multierr v1.6.0 // indirect go.uber.org/zap v1.21.0 // indirect - golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d - golang.org/x/net v0.0.0-20220706163947-c90051bbdb60 // indirect - golang.org/x/oauth2 v0.0.0-20220622183110-fd043fe589d2 // indirect - golang.org/x/sys v0.0.0-20220624220833-87e55d714810 // indirect + golang.org/x/net v0.0.0-20220708220712-1185a9018129 // indirect + golang.org/x/oauth2 v0.0.0-20220718184931-c8730f7fcb92 // indirect + golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 // indirect golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect golang.org/x/text v0.3.7 // indirect golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 // indirect diff --git a/go.sum b/go.sum index ff9efa4d..2402d9ba 100644 --- a/go.sum +++ b/go.sum @@ -186,16 +186,16 @@ github.com/evanphx/json-patch v5.6.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLi github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= -github.com/fluxcd/gitkit v0.5.1 h1:kmpXs0g+eNuoq9CUzGppGadVF+c7j4n2kPYE/bvkMD0= -github.com/fluxcd/gitkit v0.5.1/go.mod h1:svOHuKi0fO9HoawdK4HfHAJJseZDHHjk7I3ihnCIqNo= +github.com/fluxcd/gitkit v0.6.0 h1:iNg5LTx6ePo+Pl0ZwqHTAkhbUHxGVSY3YCxCdw7VIFg= +github.com/fluxcd/gitkit v0.6.0/go.mod h1:svOHuKi0fO9HoawdK4HfHAJJseZDHHjk7I3ihnCIqNo= github.com/fluxcd/image-reflector-controller/api v0.19.3 h1:mgKNHZL8AAvqzBdiuVNQtOVlEijgFyGvTr4A6vuNVgc= github.com/fluxcd/image-reflector-controller/api v0.19.3/go.mod h1:QFRYeJTfUQY9l3r+PqGGAlr7KzJRCKN7Lsvg9nXaWHk= github.com/fluxcd/pkg/apis/acl v0.0.3 h1:Lw0ZHdpnO4G7Zy9KjrzwwBmDZQuy4qEjaU/RvA6k1lc= github.com/fluxcd/pkg/apis/acl v0.0.3/go.mod h1:XPts6lRJ9C9fIF9xVWofmQwftvhY25n1ps7W9xw0XLU= github.com/fluxcd/pkg/apis/meta v0.14.2 h1:/Hf7I/Vz01vv3m7Qx7DtQvrzAL1oVt0MJcLb/I1Y1HE= github.com/fluxcd/pkg/apis/meta v0.14.2/go.mod h1:ijZ61VG/8T3U17gj0aFL3fdtZL+mulD6V8VrLLUCAgM= -github.com/fluxcd/pkg/gittestserver v0.5.4 h1:qRPtyjtJ98lDL5w5gnOjTjjBLWWq7+gknrVqC77mwuU= -github.com/fluxcd/pkg/gittestserver v0.5.4/go.mod h1:h84tnNBKIlOaZWS2HeQNkCH5WKHD6sUsjwIRhZunX0Q= +github.com/fluxcd/pkg/gittestserver v0.6.0 h1:HYuvs+MUzNwgdVnrBn5ge48wfoKpkOH0Ug5f3S9pk1k= +github.com/fluxcd/pkg/gittestserver v0.6.0/go.mod h1:nHVrVybYg9j13Evy99aTGCF9Wj1llmaJD+UQBEvgkc8= github.com/fluxcd/pkg/gitutil v0.1.0 h1:VO3kJY/CKOCO4ysDNqfdpTg04icAKBOSb3lbR5uE/IE= github.com/fluxcd/pkg/gitutil v0.1.0/go.mod h1:Ybz50Ck5gkcnvF0TagaMwtlRy3X3wXuiri1HVsK5id4= github.com/fluxcd/pkg/runtime v0.16.2 h1:CexfMmJK+r12sHTvKWyAax0pcPomjd6VnaHXcxjUrRY= @@ -798,8 +798,8 @@ golang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su golang.org/x/net v0.0.0-20220412020605-290c469a71a5/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.0.0-20220706163947-c90051bbdb60 h1:8NSylCMxLW4JvserAndSgFL7aPli6A68yf0bYFTcWCM= -golang.org/x/net v0.0.0-20220706163947-c90051bbdb60/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.0.0-20220708220712-1185a9018129 h1:vucSRfWwTsoXro7P+3Cjlr6flUMtzCwzlvkxEQtHHB0= +golang.org/x/net v0.0.0-20220708220712-1185a9018129/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -821,8 +821,8 @@ golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= golang.org/x/oauth2 v0.0.0-20220608161450-d0670ef3b1eb/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE= -golang.org/x/oauth2 v0.0.0-20220622183110-fd043fe589d2 h1:+jnHzr9VPj32ykQVai5DNahi9+NSp7yYuCsl5eAQtL0= -golang.org/x/oauth2 v0.0.0-20220622183110-fd043fe589d2/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE= +golang.org/x/oauth2 v0.0.0-20220718184931-c8730f7fcb92 h1:oVlhw3Oe+1reYsE2Nqu19PDJfLzwdU3QUUrG86rLK68= +golang.org/x/oauth2 v0.0.0-20220718184931-c8730f7fcb92/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -922,8 +922,8 @@ golang.org/x/sys v0.0.0-20220502124256-b6088ccd6cba/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220610221304-9f5ed59c137d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220624220833-87e55d714810 h1:rHZQSjJdAI4Xf5Qzeh2bBc5YJIkPFVM6oDtMFYmgws0= -golang.org/x/sys v0.0.0-20220624220833-87e55d714810/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 h1:0A+M6Uqn+Eje4kHMK80dtF3JCXC4ykBgQG4Fe06QRhQ= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY=