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 return c 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.
401var 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.
407func 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// serverHelp prints the registry's usage for a prefix and reports whether 415// serverHelp prints the registry's usage for a prefix and reports whether
394// it did. cliPath is the group's own path in the CLI. At a terminal it 416// it did. cliPath is the group's own path in the CLI. At a terminal it
395// goes through the terminal-aware path, so it gets the same 417// goes through the terminal-aware path, so it gets the same
@@ -401,7 +423,7 @@ func serverHelp(prefix, cliPath string) bool {
401 if err != nil { 423 if err != nil {
402 return false 424 return false
403 } 425 }
404 argv := withCLIPath(cliPath, prefix, []string{"help", prefix}) 426 argv := helpArgv(prefix, cliPath)
405 if term.IsTerminal(int(os.Stdout.Fd())) { 427 if term.IsTerminal(int(os.Stdout.Fd())) {
406 return runSSH(t, argv, strings.NewReader("")) == 0 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 t.Errorf("mismatched CLI paths = %v\nwant %v", got, want) 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).
51func 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.
63func 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.
75func 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 if strings.Contains(errOut, "auth") { 52 if strings.Contains(errOut, "auth") {
53 t.Errorf("stock ssh saw the CLI's auth grouping: %q", errOut) 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// keys add and pgp add wire stdin directly to the server rather than going 85// keys add and pgp add wire stdin directly to the server rather than going