Commit 44191b1a52

44191b1a52f271815cbb40ed85a228ba313d65ae

parent: d905c69753

Verified · cmc

cmc <hello@cleberg.net> · 2026-09-28 07:15 UTC

auth keys add, pgp add: check --help before reading stdin

Ref #267

Layout: unified · split

cmd/gitbay/main.go +14 −2
@@ -435,6 +435,12 @@ func authCmd() *cobra.Command {
435435 keysAdd := pass("add", passOpts{server: []string{"keys", "add"}, alwaysStdin: true, stdinWhat: "an SSH public key"})
436436 // keys add always reads stdin on the server; wire it through directly.
437437 keysAdd.RunE = func(cmd *cobra.Command, args []string) error {
438 cliPath := cliPathOf(cmd)
439 for _, a := range args {
440 if a == "--help" || a == "-h" {
441 os.Exit(runServerHelp(passOpts{server: []string{"keys", "add"}}, cliPath))
442 }
443 }
438444 t, err := resolveTarget()
439445 if err != nil {
440446 return err
@@ -443,7 +449,7 @@ func authCmd() *cobra.Command {
443449 if err != nil {
444450 return err
445451 }
446 os.Exit(runSSH(t, append([]string{"keys", "add"}, args...), in))
452 os.Exit(runSSH(t, withCLIPath(cliPath, "keys add", append([]string{"keys", "add"}, args...)), in))
447453 return nil
448454 }
449455 pgpAdd := &cobra.Command{
@@ -455,6 +461,12 @@ func authCmd() *cobra.Command {
455461 },
456462 DisableFlagParsing: true,
457463 RunE: func(cmd *cobra.Command, args []string) error {
464 cliPath := cliPathOf(cmd)
465 for _, a := range args {
466 if a == "--help" || a == "-h" {
467 os.Exit(runServerHelp(passOpts{server: []string{"pgp", "add"}}, cliPath))
468 }
469 }
458470 t, err := resolveTarget()
459471 if err != nil {
460472 return err
@@ -463,7 +475,7 @@ func authCmd() *cobra.Command {
463475 if err != nil {
464476 return err
465477 }
466 os.Exit(runSSH(t, append([]string{"pgp", "add"}, args...), in))
478 os.Exit(runSSH(t, withCLIPath(cliPath, "pgp add", append([]string{"pgp", "add"}, args...)), in))
467479 return nil
468480 },
469481 }
e2e/cliusage_test.go +36
@@ -53,3 +53,39 @@ func TestCLIUsagePrintsTheInvokingPath(t *testing.T) {
5353 t.Errorf("stock ssh saw the CLI's auth grouping: %q", errOut)
5454 }
5555}
56
57// keys add and pgp add wire stdin directly to the server rather than going
58// through pass(), so they lost the --help check every other passthrough
59// command has: --help was treated as key material instead of showing help
60// (#267).
61func TestKeysAddAndPGPAddCheckHelpBeforeStdin(t *testing.T) {
62 t.Parallel()
63 inst := startInstance(t)
64 key := inst.newKey(t, "alice")
65 inst.admin(t, "admin", "user", "create", "alice", "--key", key+".pub",
66 "--email", "alice@example.test", "--verified")
67
68 c := &cli{bin: buildGitbayCLI(t), configDir: t.TempDir(), inst: inst, key: key}
69 c.must(t, "", "", "remote", "add", "test", "127.0.0.1",
70 "--port", fmt.Sprint(inst.port),
71 "--ssh-option", "-i", "--ssh-option", key,
72 "--ssh-option", "-oIdentitiesOnly=yes",
73 "--ssh-option", "-oStrictHostKeyChecking=no",
74 "--ssh-option", "-oUserKnownHostsFile="+filepath.Join(inst.sshDir, "kh"),
75 "--ssh-option", "-oBatchMode=yes",
76 "--default")
77
78 for _, args := range [][]string{
79 {"auth", "keys", "add", "--help"},
80 {"auth", "pgp", "add", "--help"},
81 } {
82 out, errOut, code := c.run(t, "", "", args...)
83 if code != 0 {
84 t.Errorf("%v: exit %d, stdout %q, stderr %q", args, code, out, errOut)
85 }
86 want := "gitbay " + strings.Join(args[:len(args)-1], " ")
87 if !strings.Contains(out, want) {
88 t.Errorf("%v: stdout %q does not contain %q", args, out, want)
89 }
90 }
91}