Commit 7664da8384
7664da8384df3367b3a29d26296e91ebd6c4ff05
parent: 4eb0f95ce5
Verified · cmc
cmc <hello@cleberg.net> · 2026-09-28 07:29 UTC
auth --help: force --path= for a bare CLI-only alias group
gitbay auth --help resolved cliPath and the registered prefix to the
same string ("auth"), so withCLIPath's equality shortcut sent no
--path= and the server, seeing no CLIPath, printed the registered rows
a caller cannot type. The registry has no "auth" command at all, so
the shortcut's premise (matching paths mean no override needed) does
not hold for it.
helpArgv forces --path= for the CLI-only alias groups (auth) regardless
of the equality check; every other group, whose name is a real
registered prefix, is unaffected.
Ref #267
Layout: unified · split
cmd/gitbay/main.go
+23 −1
| @@ -390,6 +390,28 @@ func group(use, short string, subs ...*cobra.Command) *cobra.Command { |
| 390 | 390 | return c |
| 391 | 391 | } |
| 392 | 392 | |
| 393 | // aliasGroupNames are CLI-only noun names with no matching registry |
| 394 | // prefix (internal/control's nounAliases keys — kept in sync by hand, |
| 395 | // since the CLI has no registry to consult): auth's own cliPath is |
| 396 | // "auth", equal to the prefix it asks help for, so withCLIPath's |
| 397 | // equality shortcut reads that as "no override needed" even though no |
| 398 | // registered command is named "auth" at all, and help would silently |
| 399 | // fall back to the registered forms (#267 review finding). Force |
| 400 | // --path= for these regardless of the equality check. |
| 401 | var aliasGroupNames = map[string]bool{"auth": true} |
| 402 | |
| 403 | // helpArgv builds the server argv for a group's --help: --path=cliPath |
| 404 | // when the CLI's path differs from the registered prefix it names, or |
| 405 | // unconditionally when prefix is a CLI-only alias grouping the registry |
| 406 | // never answers to under that name. |
| 407 | func helpArgv(prefix, cliPath string) []string { |
| 408 | argv := []string{"help", prefix} |
| 409 | if aliasGroupNames[prefix] { |
| 410 | return append([]string{"--path=" + cliPath}, argv...) |
| 411 | } |
| 412 | return withCLIPath(cliPath, prefix, argv) |
| 413 | } |
| 414 | |
| 393 | 415 | // serverHelp prints the registry's usage for a prefix and reports whether |
| 394 | 416 | // it did. cliPath is the group's own path in the CLI. At a terminal it |
| 395 | 417 | // goes through the terminal-aware path, so it gets the same |
| @@ -401,7 +423,7 @@ func serverHelp(prefix, cliPath string) bool { |
| 401 | 423 | if err != nil { |
| 402 | 424 | return false |
| 403 | 425 | } |
| 404 | | argv := withCLIPath(cliPath, prefix, []string{"help", prefix}) |
| 426 | argv := helpArgv(prefix, cliPath) |
| 405 | 427 | if term.IsTerminal(int(os.Stdout.Fd())) { |
| 406 | 428 | return runSSH(t, argv, strings.NewReader("")) == 0 |
| 407 | 429 | } |
cmd/gitbay/serverpath_test.go
+36
| @@ -43,3 +43,39 @@ func TestServerPathMismatches(t *testing.T) { |
| 43 | 43 | t.Errorf("mismatched CLI paths = %v\nwant %v", got, want) |
| 44 | 44 | } |
| 45 | 45 | } |
| 46 | |
| 47 | // TestHelpArgvSendsThePathForAnAliasGroup pins the review-round fix: a |
| 48 | // bare `gitbay auth --help` (cliPath == prefix == "auth") must still send |
| 49 | // --path=auth, since the registry has no "auth" command for withCLIPath's |
| 50 | // equality shortcut to correctly skip (#267 follow-up). |
| 51 | func TestHelpArgvSendsThePathForAnAliasGroup(t *testing.T) { |
| 52 | got := helpArgv("auth", "auth") |
| 53 | want := []string{"--path=auth", "help", "auth"} |
| 54 | if !slices.Equal(got, want) { |
| 55 | t.Errorf("helpArgv(auth, auth) = %v, want %v", got, want) |
| 56 | } |
| 57 | } |
| 58 | |
| 59 | // TestHelpArgvSendsNoPathWhenCLIMatchesTheRegistry pins the unaffected |
| 60 | // case: an ordinary noun's cliPath and registered prefix are the same |
| 61 | // string, and it is not a CLI-only alias grouping, so no --path= is sent |
| 62 | // and the server resolves it on its own. |
| 63 | func TestHelpArgvSendsNoPathWhenCLIMatchesTheRegistry(t *testing.T) { |
| 64 | got := helpArgv("issue", "issue") |
| 65 | want := []string{"help", "issue"} |
| 66 | if !slices.Equal(got, want) { |
| 67 | t.Errorf("helpArgv(issue, issue) = %v, want %v", got, want) |
| 68 | } |
| 69 | } |
| 70 | |
| 71 | // TestHelpArgvSendsThePathForAMismatchedGroup pins the ordinary |
| 72 | // Task 2.1 case, unchanged by the alias-group fix: a nested group whose |
| 73 | // cliPath differs from its registered prefix (auth keys, for keys) |
| 74 | // already sends --path= through withCLIPath. |
| 75 | func TestHelpArgvSendsThePathForAMismatchedGroup(t *testing.T) { |
| 76 | got := helpArgv("keys", "auth keys") |
| 77 | want := []string{"--path=auth keys", "help", "keys"} |
| 78 | if !slices.Equal(got, want) { |
| 79 | t.Errorf("helpArgv(keys, auth keys) = %v, want %v", got, want) |
| 80 | } |
| 81 | } |
e2e/cliusage_test.go
+28
| @@ -52,6 +52,34 @@ func TestCLIUsagePrintsTheInvokingPath(t *testing.T) { |
| 52 | 52 | if strings.Contains(errOut, "auth") { |
| 53 | 53 | t.Errorf("stock ssh saw the CLI's auth grouping: %q", errOut) |
| 54 | 54 | } |
| 55 | |
| 56 | // A bare `gitbay auth --help` (cliPath == "auth", the registered |
| 57 | // prefix it asks for) must still send --path=auth: the registry has |
| 58 | // no "auth" command, so withCLIPath's equality shortcut would |
| 59 | // otherwise read that as "no override needed" and print the |
| 60 | // registered rows the CLI cannot actually type (#267 review finding). |
| 61 | out, errOut, code = c.run(t, "", "", "auth", "--help") |
| 62 | if code != 0 { |
| 63 | t.Errorf("gitbay auth --help: exit %d, stdout %q, stderr %q", code, out, errOut) |
| 64 | } |
| 65 | for _, want := range []string{"auth keys add", "auth export"} { |
| 66 | if !strings.Contains(out, want) { |
| 67 | t.Errorf("gitbay auth --help: missing %q in %q", want, out) |
| 68 | } |
| 69 | } |
| 70 | |
| 71 | out, errOut, code = inst.ssh(t, key, "", "help", "auth") |
| 72 | if code != 0 { |
| 73 | t.Errorf("ssh help auth: exit %d, stdout %q, stderr %q", code, out, errOut) |
| 74 | } |
| 75 | for _, want := range []string{"keys add", "account export"} { |
| 76 | if !strings.Contains(out, want) { |
| 77 | t.Errorf("ssh help auth: missing %q in %q", want, out) |
| 78 | } |
| 79 | } |
| 80 | if strings.Contains(out, "auth keys add") { |
| 81 | t.Errorf("stock ssh saw the CLI's auth grouping: %q", out) |
| 82 | } |
| 55 | 83 | } |
| 56 | 84 | |
| 57 | 85 | // keys add and pgp add wire stdin directly to the server rather than going |