diff --git a/Gopkg.lock b/Gopkg.lock index 7deddeb6b..c1c4f6a82 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -622,6 +622,14 @@ revision = "0599d764e054d4e983bb120e30759179fafe3942" version = "v1.2.0" +[[projects]] + branch = "master" + digest = "1:2e43242796ee48ff0256eaf784ffaca015614ea5cb284cbc7b6e0fb65c219887" + name = "github.com/whilp/git-urls" + packages = ["."] + pruneopts = "" + revision = "31bac0d230fa29f36ed1b3279c2343752e7196c0" + [[projects]] branch = "master" digest = "1:2ea6df0f542cc95a5e374e9cdd81eaa599ed0d55366eef92d2f6b9efa2795c07" @@ -1210,6 +1218,7 @@ "github.com/stretchr/testify/assert", "github.com/weaveworks/common/middleware", "github.com/weaveworks/go-checkpoint", + "github.com/whilp/git-urls", "golang.org/x/sys/unix", "golang.org/x/time/rate", "gopkg.in/yaml.v2", diff --git a/daemon/loop.go b/daemon/loop.go index 8d1923d3a..2ab75e2b9 100644 --- a/daemon/loop.go +++ b/daemon/loop.go @@ -2,6 +2,8 @@ package daemon import ( "context" + "crypto/sha256" + "encoding/base64" "fmt" "strings" "sync" @@ -23,7 +25,6 @@ import ( const ( // Timeout for git operations we're prepared to abandon gitOpTimeout = 15 * time.Second - syncSetName = "git" ) type LoopVars struct { @@ -162,6 +163,9 @@ func (d *Daemon) doSync(logger log.Logger, lastKnownSyncTagRev *string, warnedAb fluxmetrics.LabelSuccess, fmt.Sprint(retErr == nil), ).Observe(time.Since(started).Seconds()) }() + + syncSetName := makeSyncLabel(d.Repo.Origin(), d.GitConfig) + // We don't care how long this takes overall, only about not // getting bogged down in certain operations, so use an // undeadlined context in general. @@ -450,3 +454,16 @@ func isUnknownRevision(err error) bool { (strings.Contains(err.Error(), "unknown revision or path not in the working tree.") || strings.Contains(err.Error(), "bad revision")) } + +func makeSyncLabel(remote git.Remote, conf git.Config) string { + urlbit := remote.SafeURL() + pathshash := sha256.New() + pathshash.Write([]byte(urlbit)) + pathshash.Write([]byte(conf.Branch)) + for _, path := range conf.Paths { + pathshash.Write([]byte(path)) + } + // the prefix is in part to make sure it's a valid (Kubernetes) + // label value -- a modest abstraction leak + return "git-" + base64.RawURLEncoding.EncodeToString(pathshash.Sum(nil)) +} diff --git a/git/repo.go b/git/repo.go index f81fe47ba..5f104521d 100644 --- a/git/repo.go +++ b/git/repo.go @@ -44,11 +44,6 @@ const ( RepoReady GitRepoStatus = "ready" // has been written to, so ready to sync ) -// Remote points at a git repo somewhere. -type Remote struct { - URL string // clone from here -} - type Repo struct { // As supplied to constructor origin Remote diff --git a/git/url.go b/git/url.go new file mode 100644 index 000000000..d59cafd4f --- /dev/null +++ b/git/url.go @@ -0,0 +1,24 @@ +package git + +import ( + "fmt" + "net/url" + + "github.com/whilp/git-urls" +) + +// Remote points at a git repo somewhere. +type Remote struct { + URL string // clone from here +} + +func (r Remote) SafeURL() string { + u, err := giturls.Parse(r.URL) + if err != nil { + return fmt.Sprintf("", r.URL) + } + if u.User != nil { + u.User = url.User(u.User.Username()) + } + return u.String() +} diff --git a/git/url_test.go b/git/url_test.go new file mode 100644 index 000000000..b119010f3 --- /dev/null +++ b/git/url_test.go @@ -0,0 +1,20 @@ +package git + +import ( + "strings" + "testing" +) + +func TestSafeURL(t *testing.T) { + const password = "abc123" + for _, url := range []string{ + "git@github.com:weaveworks/flux", + "https://user@example.com:5050/repo.git", + "https://user:" + password + "@example.com:5050/repo.git", + } { + u := Remote{url} + if strings.Contains(u.SafeURL(), password) { + t.Errorf("Safe URL for %s contains password %q", url, password) + } + } +}