aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--go.mod1
-rw-r--r--go.sum17
-rw-r--r--repository/config.go6
-rw-r--r--repository/git.go16
-rw-r--r--repository/gogit.go18
-rw-r--r--repository/keyring.go73
-rw-r--r--repository/mock_repo.go9
-rw-r--r--repository/repo.go11
8 files changed, 144 insertions, 7 deletions
diff --git a/go.mod b/go.mod
index 9f8b259b..77b3657f 100644
--- a/go.mod
+++ b/go.mod
@@ -4,6 +4,7 @@ go 1.12
require (
github.com/99designs/gqlgen v0.10.3-0.20200209012558-b7a58a1c0e4b
+ github.com/99designs/keyring v1.1.5
github.com/MichaelMure/go-term-text v0.2.9
github.com/araddon/dateparse v0.0.0-20190622164848-0fb0a474d195
github.com/awesome-gocui/gocui v0.6.1-0.20191115151952-a34ffb055986
diff --git a/go.sum b/go.sum
index 9b84ea6d..f0531a1c 100644
--- a/go.sum
+++ b/go.sum
@@ -1,6 +1,8 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
github.com/99designs/gqlgen v0.10.3-0.20200209012558-b7a58a1c0e4b h1:510xa84qGbDemwTHNio4cLWkdKFxxJgVtsIOH+Ku8bo=
github.com/99designs/gqlgen v0.10.3-0.20200209012558-b7a58a1c0e4b/go.mod h1:dfBhwZKMcSYiYRMTs8qWF+Oha6782e1xPfgRmVal9I8=
+github.com/99designs/keyring v1.1.5 h1:wLv7QyzYpFIyMSwOADq1CLTF9KbjbBfcnfmOGJ64aO4=
+github.com/99designs/keyring v1.1.5/go.mod h1:7hsVvt2qXgtadGevGJ4ujg+u8m6SpJ5TpHqTozIPqf0=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/Masterminds/glide v0.13.2/go.mod h1:STyF5vcenH/rUqTEv+/hBXlSTo7KYwg2oc2f4tzPWic=
github.com/Masterminds/semver v1.4.2/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y=
@@ -53,6 +55,8 @@ github.com/corpix/uarand v0.1.1/go.mod h1:SFKZvkcRoLqVRFZ4u25xPmp6m9ktANfbpXZ7SJ
github.com/cpuguy83/go-md2man/v2 v2.0.0 h1:EoUDS0afbrsXAZ9YQ9jdu/mZ2sXgT1/2yyNng4PGlyM=
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
+github.com/danieljoos/wincred v1.0.2 h1:zf4bhty2iLuwgjgpraD2E9UbvO+fe54XXGJbOwe23fU=
+github.com/danieljoos/wincred v1.0.2/go.mod h1:SnuYRW9lp1oJrZX/dXJqr0cPK5gYXqx3EJbmjhLdK9U=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@@ -62,6 +66,8 @@ github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/emirpasic/gods v1.12.0 h1:QAUIPSaCu4G+POclxeqb3F+WPpdKqFGlw36+yOzGlrg=
github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o=
+github.com/dvsekhvalnov/jose2go v0.0.0-20180829124132-7f401d37b68a h1:mq+R6XEM6lJX5VlLyZIrUSP8tSuJp82xTK89hvBwJbU=
+github.com/dvsekhvalnov/jose2go v0.0.0-20180829124132-7f401d37b68a/go.mod h1:7BvyPhdbLxMXIYTFPLsyJRFMsKmOZnQmzh6Gb+uquuM=
github.com/fatih/color v1.9.0 h1:8xPHl4/q1VyqGIPif1F+1V3Y3lSmrq01EabUW3CoW5s=
github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568 h1:BHsljHzVlRcyQhjrss6TZTdY2VfCqZPbv5k3iBFa2ZQ=
@@ -85,6 +91,8 @@ github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
+github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 h1:ZpnhV/YsD2/4cESfV5+Hoeu/iUR3ruzNvZ+yQfO03a0=
+github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4=
github.com/gogo/protobuf v1.0.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
@@ -112,6 +120,8 @@ github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoA
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
+github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c h1:6rhixN/i8ZofjG1Y75iExal34USq5p+wiN1tpie8IrU=
+github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c/go.mod h1:NMPJylDgVpX0MLRlPy15sqSwOFv/U1GZ2m21JhFfek0=
github.com/hashicorp/go-cleanhttp v0.5.1 h1:dH3aiDG9Jvb5r5+bYHsikaOUIpcM0xvgMXVoDkXMzJM=
github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
github.com/hashicorp/go-hclog v0.9.2 h1:CG6TE5H9/JXsFWJCfoIVpKFIkFe6ysEuHirp4DxCsHI=
@@ -136,6 +146,8 @@ github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd h1:Coekwdh0v2wtGp9Gmz1Ze3eVRAWJMLokvN3QjdzCHLY=
github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
+github.com/keybase/go-keychain v0.0.0-20190712205309-48d3d31d256d h1:Z+RDyXzjKE0i2sTjZ/b1uxiGtPhFy34Ou/Tk0qwN0kM=
+github.com/keybase/go-keychain v0.0.0-20190712205309-48d3d31d256d/go.mod h1:JJNrCn9otv/2QP4D7SMJBgaleKpOf66PnW6F5WGNRIc=
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
@@ -167,6 +179,8 @@ github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrk
github.com/mitchellh/mapstructure v0.0.0-20180203102830-a4e142e9c047/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
+github.com/mtibben/percent v0.2.1 h1:5gssi8Nqo8QU/r2pynCm+hBQHpkB/uNK7BJCFogWdzs=
+github.com/mtibben/percent v0.2.1/go.mod h1:KG9uO+SZkUp+VkRHsCdYQV3XSZrrSpR3O9ibNBTZrns=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/ngdinhtoan/glide-cleanup v0.2.0/go.mod h1:UQzsmiDOb8YV3nOsCxK/c9zPpCZVNoHScRE3EO9pVMM=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
@@ -232,6 +246,7 @@ github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
github.com/stretchr/testify v1.2.1/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
@@ -263,6 +278,7 @@ golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnf
golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550 h1:ObdrDkeb4kJdCP557AjRjq69pTHfNouLtWZG7j9rPN8=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073 h1:xMPOj6Pz6UipU1wXLkrtqpHbR0AVFnyPEQq/wRWz9lM=
@@ -302,6 +318,7 @@ golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223 h1:DH4skfRX4EBpamg7iV4ZlCpbl
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d h1:+R4KGOnez64A81RvjARKc4UT5/tI9ujCIVX+P5KiHuI=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190712062909-fae7ac547cb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42 h1:vEOn+mP2zCOVzKckCZy6YsCtDblrpj/w7B9nxGNELpg=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
diff --git a/repository/config.go b/repository/config.go
index 4fa5c69b..2133b169 100644
--- a/repository/config.go
+++ b/repository/config.go
@@ -1,10 +1,16 @@
package repository
import (
+ "errors"
"strconv"
"time"
)
+var (
+ ErrNoConfigEntry = errors.New("no config entry for the given key")
+ ErrMultipleConfigEntry = errors.New("multiple config entry for the given key")
+)
+
// Config represent the common function interacting with the repository config storage
type Config interface {
// Store writes a single key/value pair in the config
diff --git a/repository/git.go b/repository/git.go
index 3d756324..85107ba5 100644
--- a/repository/git.go
+++ b/repository/git.go
@@ -26,6 +26,8 @@ type GitRepo struct {
clocksMutex sync.Mutex
clocks map[string]lamport.Clock
+
+ keyring Keyring
}
// LocalConfig give access to the repository scoped configuration
@@ -38,6 +40,10 @@ func (repo *GitRepo) GlobalConfig() Config {
return newGitConfig(repo, true)
}
+func (repo *GitRepo) Keyring() Keyring {
+ return repo.keyring
+}
+
// Run the given git command with the given I/O reader/writers, returning an error if it fails.
func (repo *GitRepo) runGitCommandWithIO(stdin io.Reader, stdout, stderr io.Writer, args ...string) error {
// make sure that the working directory for the command
@@ -83,9 +89,15 @@ func (repo *GitRepo) runGitCommand(args ...string) (string, error) {
// NewGitRepo determines if the given working directory is inside of a git repository,
// and returns the corresponding GitRepo instance if it is.
func NewGitRepo(path string, clockLoaders []ClockLoader) (*GitRepo, error) {
+ k, err := defaultKeyring()
+ if err != nil {
+ return nil, err
+ }
+
repo := &GitRepo{
- path: path,
- clocks: make(map[string]lamport.Clock),
+ path: path,
+ clocks: make(map[string]lamport.Clock),
+ keyring: k,
}
// Check the repo and retrieve the root path
diff --git a/repository/gogit.go b/repository/gogit.go
index 71a7e6d0..f115fab5 100644
--- a/repository/gogit.go
+++ b/repository/gogit.go
@@ -24,6 +24,8 @@ type GoGitRepo struct {
clocksMutex sync.Mutex
clocks map[string]lamport.Clock
+
+ keyring Keyring
}
func NewGoGitRepo(path string, clockLoaders []ClockLoader) (*GoGitRepo, error) {
@@ -37,10 +39,16 @@ func NewGoGitRepo(path string, clockLoaders []ClockLoader) (*GoGitRepo, error) {
return nil, err
}
+ k, err := defaultKeyring()
+ if err != nil {
+ return nil, err
+ }
+
repo := &GoGitRepo{
- r: r,
- path: path,
- clocks: make(map[string]lamport.Clock),
+ r: r,
+ path: path,
+ clocks: make(map[string]lamport.Clock),
+ keyring: k,
}
for _, loader := range clockLoaders {
@@ -154,6 +162,10 @@ func (repo *GoGitRepo) GlobalConfig() Config {
panic("go-git doesn't support writing global config")
}
+func (repo *GoGitRepo) Keyring() Keyring {
+ return repo.keyring
+}
+
// GetPath returns the path to the repo.
func (repo *GoGitRepo) GetPath() string {
return repo.path
diff --git a/repository/keyring.go b/repository/keyring.go
new file mode 100644
index 00000000..9f8171db
--- /dev/null
+++ b/repository/keyring.go
@@ -0,0 +1,73 @@
+package repository
+
+import (
+ "os"
+ "path"
+
+ "github.com/99designs/keyring"
+)
+
+type Item = keyring.Item
+
+var ErrKeyringKeyNotFound = keyring.ErrKeyNotFound
+
+// Keyring provides the uniform interface over the underlying backends
+type Keyring interface {
+ // Returns an Item matching the key or ErrKeyringKeyNotFound
+ Get(key string) (Item, error)
+ // Stores an Item on the keyring
+ Set(item Item) error
+ // Removes the item with matching key
+ Remove(key string) error
+ // Provides a slice of all keys stored on the keyring
+ Keys() ([]string, error)
+}
+
+func defaultKeyring() (Keyring, error) {
+ ucd, err := os.UserConfigDir()
+ if err != nil {
+ return nil, err
+ }
+
+ backends := []keyring.BackendType{
+ keyring.WinCredBackend,
+ keyring.KeychainBackend,
+ keyring.PassBackend,
+ keyring.FileBackend,
+ }
+
+ return keyring.Open(keyring.Config{
+ // TODO: ideally this would not be there, it disable the freedesktop backend on linux
+ // due to https://github.com/99designs/keyring/issues/44
+ AllowedBackends: backends,
+
+ ServiceName: "git-bug",
+
+ // MacOS keychain
+ KeychainName: "git-bug",
+ KeychainTrustApplication: true,
+
+ // KDE Wallet
+ KWalletAppID: "git-bug",
+ KWalletFolder: "git-bug",
+
+ // Windows
+ WinCredPrefix: "git-bug",
+
+ // freedesktop.org's Secret Service
+ LibSecretCollectionName: "git-bug",
+
+ // Pass (https://www.passwordstore.org/)
+ PassPrefix: "git-bug",
+
+ // Fallback encrypted file
+ FileDir: path.Join(ucd, "git-bug", "keyring"),
+ // As we write the file in the user's config directory, this file should already be protected by the OS against
+ // other user's access. We actually don't terribly need to protect it further and a password prompt across all
+ // UI's would be a pain. Therefore we use here a constant password so the file will be unreadable by generic file
+ // scanners if the user's machine get compromised.
+ FilePasswordFunc: func(string) (string, error) {
+ return "git-bug", nil
+ },
+ })
+}
diff --git a/repository/mock_repo.go b/repository/mock_repo.go
index 576e984e..b3b4cb41 100644
--- a/repository/mock_repo.go
+++ b/repository/mock_repo.go
@@ -5,6 +5,8 @@ import (
"fmt"
"strings"
+ "github.com/99designs/keyring"
+
"github.com/MichaelMure/git-bug/util/lamport"
)
@@ -15,6 +17,7 @@ var _ TestedRepo = &mockRepoForTest{}
type mockRepoForTest struct {
config *MemConfig
globalConfig *MemConfig
+ keyring *keyring.ArrayKeyring
blobs map[Hash][]byte
trees map[Hash]string
commits map[Hash]commit
@@ -31,6 +34,7 @@ func NewMockRepoForTest() *mockRepoForTest {
return &mockRepoForTest{
config: NewMemConfig(),
globalConfig: NewMemConfig(),
+ keyring: keyring.NewArrayKeyring(nil),
blobs: make(map[Hash][]byte),
trees: make(map[Hash]string),
commits: make(map[Hash]commit),
@@ -49,6 +53,11 @@ func (r *mockRepoForTest) GlobalConfig() Config {
return r.globalConfig
}
+// Keyring give access to a user-wide storage for secrets
+func (r *mockRepoForTest) Keyring() Keyring {
+ return r.keyring
+}
+
// GetPath returns the path to the repo.
func (r *mockRepoForTest) GetPath() string {
return "~/mockRepo/"
diff --git a/repository/repo.go b/repository/repo.go
index 30d95806..696b032e 100644
--- a/repository/repo.go
+++ b/repository/repo.go
@@ -10,8 +10,6 @@ import (
)
var (
- ErrNoConfigEntry = errors.New("no config entry for the given key")
- ErrMultipleConfigEntry = errors.New("multiple config entry for the given key")
// ErrNotARepo is the error returned when the git repo root wan't be found
ErrNotARepo = errors.New("not a git repository")
// ErrClockNotExist is the error returned when a clock can't be found
@@ -24,9 +22,17 @@ type RepoConfig interface {
LocalConfig() Config
// GlobalConfig give access to the git global configuration
+ // Deprecated: to remove in favor of Keyring()
+ // TODO: remove
GlobalConfig() Config
}
+// RepoKeyring give access to a user-wide storage for secrets
+type RepoKeyring interface {
+ // Keyring give access to a user-wide storage for secrets
+ Keyring() Keyring
+}
+
// RepoCommon represent the common function the we want all the repo to implement
type RepoCommon interface {
// GetPath returns the path to the repo.
@@ -48,6 +54,7 @@ type RepoCommon interface {
// Repo represents a source code repository.
type Repo interface {
RepoConfig
+ RepoKeyring
RepoCommon
// FetchRefs fetch git refs from a remote