Skip to content
This repository has been archived by the owner on Nov 1, 2022. It is now read-only.

Commit

Permalink
Merge pull request #865 from weaveworks/issue/858-check-git-write
Browse files Browse the repository at this point in the history
Check git repo is writable before proceeding
  • Loading branch information
squaremo authored Dec 11, 2017
2 parents 06da547 + c02e072 commit 64c455a
Show file tree
Hide file tree
Showing 4 changed files with 77 additions and 2 deletions.
5 changes: 5 additions & 0 deletions cmd/fluxd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -370,6 +370,11 @@ func main() {
ctx, cancel := context.WithTimeout(context.Background(), git.DefaultCloneTimeout)
working, err := repo.Clone(ctx, gitConfig)
cancel()
if err == nil {
ctx, cancel = context.WithTimeout(context.Background(), git.DefaultCloneTimeout)
err = working.CheckOriginWritable(ctx)
cancel()
}
if err != nil {
if checker == nil {
checker = checkForUpdates(clusterVersion, "false", updateCheckLogger)
Expand Down
47 changes: 45 additions & 2 deletions git/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package git

import (
"errors"
"strings"

fluxerr "github.com/weaveworks/flux/errors"
)
Expand All @@ -24,7 +25,7 @@ func CloningError(url string, actual error) error {
return &fluxerr.Error{
Type: fluxerr.User,
Err: actual,
Help: `Problem cloning your git repository
Help: `Could not clone the upstream git repository
There was a problem cloning your git repository,
Expand All @@ -44,6 +45,47 @@ cross-check with the fingerprint given by
}
}

func ErrUpstreamNotWritable(url string, actual error) error {
help := `Could not write to upstream repository
To keep track of synchronisation, the flux daemon must be able to
write to the upstream git repository.
`
if strings.HasPrefix(url, "http://") ||
strings.HasPrefix(url, "https://") {
help = help + `
Usually, git URLs starting with "http://" or "https://" will not work
well with flux, because they require the user to supply credentials
interactively. If possible, use an SSH URL (starting with "ssh://", or
of the form "user@host:path/to/repo").
`
} else {
help = help + `
This failure may be due to the SSH (deploy) key used by the daemon not
having write permission. You can see the key used, with
fluxctl identity
In GitHub, please check via the repository settings that the deploy
key is "Read/write". You can cross-check the fingerprint with that
given by
fluxctl identity --fingerprint
If the key is present but read-only, you will need to delete it and
create a new deploy key. To create a new one, use
fluxctl identity --regenerate
`
}

return &fluxerr.Error{
Type: fluxerr.User,
Err: actual,
Help: help,
}
}

func PushError(url string, actual error) error {
return &fluxerr.Error{
Type: fluxerr.User,
Expand All @@ -57,7 +99,8 @@ If this has worked before, it most likely means a fast-forward push
was not possible. It is safe to try again.
If it has not worked before, this probably means that the repository
exists but the deploy key provided doesn't have write permission.
exists but the SSH (deploy) key provided doesn't have write
permission.
In GitHub, please check via the repository settings that the deploy
key is "Read/write". You can cross-check the fingerprint with that
Expand Down
14 changes: 14 additions & 0 deletions git/operations.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,20 @@ func clone(ctx context.Context, workingDir string, keyRing ssh.KeyRing, repoURL,
return repoPath, nil
}

// checkPush sanity-checks that we can write to the upstream repo with
// the given keyring (being able to `clone` is an adequate check that
// we can read the upstream).
func checkPush(ctx context.Context, keyRing ssh.KeyRing, workingDir, upstream string) error {
// --force just in case we fetched the tag from upstream when cloning
if err := execGitCmd(ctx, workingDir, nil, nil, "tag", "--force", CheckPushTag); err != nil {
return errors.Wrap(err, "tag for write check")
}
if err := execGitCmd(ctx, workingDir, keyRing, nil, "push", "--force", upstream, "tag", CheckPushTag); err != nil {
return errors.Wrap(err, "attempt to push tag")
}
return execGitCmd(ctx, workingDir, keyRing, nil, "push", "-d", upstream, "tag", CheckPushTag)
}

func commit(ctx context.Context, workingDir string, commitAction *CommitAction) error {
commitAuthor := commitAction.Author
if commitAuthor != "" {
Expand Down
13 changes: 13 additions & 0 deletions git/repo.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (

const (
DefaultCloneTimeout = 2 * time.Minute
CheckPushTag = "flux-write-check"
)

var (
Expand Down Expand Up @@ -141,6 +142,18 @@ func (c *Checkout) ManifestDir() string {
return filepath.Join(c.Dir, c.repo.Path)
}

// CheckOriginWritable tests that we can write to the origin
// repository; we need to be able to do this to push the sync tag, for
// example.
func (c *Checkout) CheckOriginWritable(ctx context.Context) error {
c.Lock()
defer c.Unlock()
if err := checkPush(ctx, c.repo.KeyRing, c.Dir, c.repo.URL); err != nil {
return ErrUpstreamNotWritable(c.repo.URL, err)
}
return nil
}

// CommitAndPush commits changes made in this checkout, along with any
// extra data as a note, and pushes the commit and note to the remote repo.
func (c *Checkout) CommitAndPush(ctx context.Context, commitAction *CommitAction, note *Note) error {
Expand Down

0 comments on commit 64c455a

Please sign in to comment.