Commit 84c34a5d09
84c34a5d09dbd23ca1c79c1670570b84e64459b2
parent: bf7ced2be6
Verified · cmc ci/build: success ci/test: success
cmc <hello@cleberg.net> · 2026-09-10 03:36 UTC
runner: -identity ignores the user's ssh config
IdentitiesOnly keeps identities named in ~/.ssh/config, so on a machine
whose config names a full-scope key for the instance the runner
authenticated as that key. With -F /dev/null only the runner's key is
offered; a first-seen host key is accepted, since a service cannot
answer a prompt.
Ref #184
cmd/gitbay-runner/config.go
+7 −3
| @@ -84,11 +84,15 @@ func applyConfig(fs *flag.FlagSet, values map[string]string) error { |
| 84 | 84 | } |
| 85 | 85 | |
| 86 | 86 | // identityOpts is what makes ssh and git use the runner's own key and no |
| 87 | | // other: on a laptop the ambient key is the user's full-scope one, which |
| 88 | | // the runner protocol refuses. |
| 87 | // other. On a laptop the user's ~/.ssh/config names their full-scope key |
| 88 | // for the instance, and IdentitiesOnly keeps identities from the config, |
| 89 | // so the runner would authenticate as that key and, on an admin's |
| 90 | // machine, claim every repository's builds. -F /dev/null drops the |
| 91 | // config; known_hosts is unaffected, and a host seen for the first time |
| 92 | // is accepted, since a service cannot answer a prompt. |
| 89 | 93 | func identityOpts(path string) []string { |
| 90 | 94 | if path == "" { |
| 91 | 95 | return nil |
| 92 | 96 | } |
| 93 | | return []string{"-i", path, "-o", "IdentitiesOnly=yes"} |
| 97 | return []string{"-F", "/dev/null", "-i", path, "-o", "IdentitiesOnly=yes", "-o", "StrictHostKeyChecking=accept-new"} |
| 94 | 98 | } |
cmd/gitbay-runner/config_test.go
+5 −3
| @@ -4,6 +4,7 @@ import ( |
| 4 | 4 | "flag" |
| 5 | 5 | "os" |
| 6 | 6 | "path/filepath" |
| 7 | "strings" |
| 7 | 8 | "testing" |
| 8 | 9 | ) |
| 9 | 10 | |
| @@ -77,8 +78,9 @@ func TestIdentityOpts(t *testing.T) { |
| 77 | 78 | if got := identityOpts(""); got != nil { |
| 78 | 79 | t.Fatalf("empty identity produced %v", got) |
| 79 | 80 | } |
| 80 | | got := identityOpts("/k") |
| 81 | | if len(got) != 4 || got[0] != "-i" || got[1] != "/k" || got[3] != "IdentitiesOnly=yes" { |
| 82 | | t.Fatalf("got %v", got) |
| 81 | got := strings.Join(identityOpts("/k"), " ") |
| 82 | want := "-F /dev/null -i /k -o IdentitiesOnly=yes -o StrictHostKeyChecking=accept-new" |
| 83 | if got != want { |
| 84 | t.Fatalf("got %q, want %q", got, want) |
| 83 | 85 | } |
| 84 | 86 | } |