krz/gitbay
A CLI-first git forge.
clone: git clone https://gitbay.org/krz/gitbay.git
0d422fbdaf6144ce5f971d8210e4b8123f3bdad4
verified · cmc
author: Christian Cleberg <hello@cleberg.net> · 2026-08-24T02:31:43Z
cmd/gitbay/ssh.go | 43 ++++++++++++++++++++++--------------------- e2e/cli_test.go | 16 ++++++++++++++++ 2 files changed, 38 insertions(+), 21 deletions(-) @@ -20,39 +20,40 @@ type target struct { repo string // owner/name, "" when not inferable } -// resolveTarget picks the instance and repo. Inside a git repo whose origin -// remote points at a configured (or any ssh) forge host, that wins; -// otherwise the configured default instance. +// resolveTarget picks the instance and repo. An origin remote matching a +// CONFIGURED instance wins and carries repo inference; otherwise the +// default instance is used with no inference — a clone from some other +// host (github, a different forge) must never hijack the command. The +// raw origin serves as an ad-hoc instance only when nothing is configured +// at all. func resolveTarget() (target, error) { cfg, err := cliconfig.Load() if err != nil { return target{}, err } - if url := originURL(); url != "" { - if parsed, repo, ok := cliconfig.ParseRemoteURL(url); ok { - // Prefer a configured instance for the same host+port: it may - // carry ssh_options the bare URL cannot express. - norm := func(p int) int { - if p == 0 { - return 22 - } - return p + parsed, repo, originOK := cliconfig.ParseRemoteURL(originURL()) + if originOK { + norm := func(p int) int { + if p == 0 { + return 22 } - for _, inst := range cfg.Instances { - if inst.Host == parsed.Host && norm(inst.Port) == norm(parsed.Port) { - return target{inst: inst, repo: repo}, nil - } + return p + } + for _, inst := range cfg.Instances { + if inst.Host == parsed.Host && norm(inst.Port) == norm(parsed.Port) { + return target{inst: inst, repo: repo}, nil } - return target{inst: parsed, repo: repo}, nil } } - inst, _, err := cfg.DefaultInstance() - if err != nil { - return target{}, err + if inst, _, err := cfg.DefaultInstance(); err == nil { + return target{inst: inst}, nil + } + if originOK { + return target{inst: parsed, repo: repo}, nil } - return target{inst: inst}, nil + return target{}, fmt.Errorf("no gitbay instance configured; run: gitbay remote add <name> <host>") } func originURL() string { @@ -193,6 +193,22 @@ func TestCLI(t *testing.T) { t.Fatalf("init-created repo: %s", out) } + // A clone whose origin points at a FOREIGN host must not hijack the + // command: the configured default instance is used, and repo inference + // is dropped rather than guessed across hosts. + foreign := filepath.Join(t.TempDir(), "f") + os.MkdirAll(foreign, 0o755) + mustGit(t, foreign, cliGitEnv, "init", "-q") + mustGit(t, foreign, cliGitEnv, "remote", "add", "origin", "git@github.example:someone/thing.git") + out = c.must(t, foreign, "", "auth", "whoami") + if strings.TrimSpace(out) != "alice" { + t.Fatalf("foreign-origin whoami hit the wrong host: %q", out) + } + _, errOut2, code2 := c.run(t, foreign, "", "issue", "list") + if code2 != 2 || !strings.Contains(errOut2, "none inferable") { + t.Fatalf("foreign-origin repo inference: exit %d, %s", code2, errOut2) + } + // Man pages and completions generate. manDir := t.TempDir() c.must(t, "", "", "man", "--dir", manDir)