--- a/config/config.go Mon May 01 21:36:29 2017 -0500
+++ b/config/config.go Tue May 02 02:13:31 2017 -0500
@@ -23,8 +23,9 @@
- Tasks map[string]tasks.Task
- Plans map[string]plans.Plan
- MetaPlans map[string]plans.MetaPlan
+ Tasks map[string]tasks.Task + Plans map[string]plans.Plan + MetaPlans map[string]plans.MetaPlan --- a/config/convey.go Mon May 01 21:36:29 2017 -0500
+++ b/config/convey.go Tue May 02 02:13:31 2017 -0500
@@ -28,11 +28,12 @@
type conveyConfig struct {
- DefaultPlan string `yaml:"default-plan"`
- Tasks map[string]yaml.MapSlice `yaml:"tasks"`
- Plans map[string]plans.Plan `yaml:"plans"`
- MetaPlans map[string]plans.MetaPlan `yaml:"meta-plans"`
- Environment []string `yaml:"environment"`
+ DefaultPlan string `yaml:"default-plan"` + Tasks map[string]yaml.MapSlice `yaml:"tasks"` + Plans map[string]plans.Plan `yaml:"plans"` + MetaPlans map[string]plans.MetaPlan `yaml:"meta-plans"` + SSHIdentities []string `yaml:"ssh-identities"` + Environment []string `yaml:"environment"` type conveyOverride struct {
--- a/convey.yml Mon May 01 21:36:29 2017 -0500
+++ b/convey.yml Tue May 02 02:13:31 2017 -0500
@@ -1,6 +1,8 @@
- GO_PACKAGE=bitbucket.org/rw_grim/convey
+ - SHA256:Efrocgd+rvwjDAnHt2jZAcwDqeka0s8Vv7N3m08cVnA # tasks for the default plan
--- a/main.go Mon May 01 21:36:29 2017 -0500
+++ b/main.go Tue May 02 02:13:31 2017 -0500
@@ -54,7 +54,8 @@
listPlans = app.Flag("list-plans", "List the plans that are available").Short('P').Default("false").Bool()
memory = app.Flag("memory", "The ammount of memor to give the run task").Short('m').String()
showConfig = app.Flag("show-config", "Show a dump of the config file").Short('C').Hidden().Default("false").Bool()
- sshAgent = app.Flag("ssh-agent", "Enabled ssh-agent support for tasks").Default("false").Bool()
+ sshAgent = app.Flag("ssh-agent", "A shortcut for --ssh-identity=*").Default("false").Bool() + sshIdentities = app.Flag("ssh-identity", "Enable ssh-agent for the given identities").Strings() taskTimeout = app.Flag("timeout", "The maximum amount of time a task can run in seconds. 0 to disable").Default("15m").Duration()
verbose = app.Flag("verbose", "Be more verbose").Short('v').Default("False").Bool()
@@ -114,7 +115,11 @@
defEnv := environment.Initialize()
- haveKeys, err := ssh.KeysAvailable()
+ *sshIdentities = append(*sshIdentities, "*") + if len(*sshIdentities) > 0 { + haveKeys, err := ssh.KeysAvailable(*sshIdentities) fmt.Printf("error talking to ssh-agent: %s\n", err)
--- a/ssh/agent.go Mon May 01 21:36:29 2017 -0500
+++ b/ssh/agent.go Tue May 02 02:13:31 2017 -0500
@@ -18,25 +18,71 @@
+ "golang.org/x/crypto/ssh" "golang.org/x/crypto/ssh/agent"
// KeysAvailable returns True if there is at least one key that the ssh agent
// knows about, otherwise false. err will be set if there is an error along
-func KeysAvailable() (bool, error) {
+func KeysAvailable(identites []string) (bool, error) { sshAgent, err := net.Dial("unix", os.Getenv("SSH_AUTH_SOCK"))
- keys, err := agent.NewClient(sshAgent).List()
+ return keysAvailable(sshAgent, identites) +func keysAvailable(rw io.ReadWriter, identities []string) (bool, error) { + keys, err := agent.NewClient(rw).List() - return len(keys) != 0, nil
+ // this runs in O(m * n) but thankful the number of keys should be low. + for _, identity := range identities { + // if the user doesn't care which key and we have a key, return true + // if the user doesn't care which key but we have no keys, return an error + return false, fmt.Errorf("no ssh keys available") + uIdentity := strings.ToUpper(identity) + for _, pubKey := range keys { + fpSHA256 := strings.ToUpper(ssh.FingerprintSHA256(pubKey)) + fpMD5 := strings.ToUpper(ssh.FingerprintLegacyMD5(pubKey)) + if strings.HasPrefix(uIdentity, "SHA256:") { + if uIdentity == fpSHA256 { + } else if strings.HasPrefix(uIdentity, "MD5:") { + if uIdentity[4:] == fpMD5 { + // no known prefix check sha256 then md5, then give up + if uIdentity == fpSHA256[7:] || uIdentity == fpMD5 { + err = fmt.Errorf("no usable ssh identities found")