Commit ed608b4d4a

ed608b4d4ace8d445780b0de41eedab4404b68f1

parent: 8c7a8b7eef

Verified · cmc ci/build: success ci/test: success ci/vuln: success

cmc <hello@cleberg.net> · 2026-09-02 01:58 UTC

gitbayd admin config show

check-config validated the file but could not say what the daemon would
actually run with, so a support question started from the file rather
than the effective values.

admin config show prints the loaded configuration as TOML with every
default filled in. smtp_pass, the one secret the file can hold, prints
as <redacted>. A file that fails validation still prints, followed by
the error, since the contradiction is what the reader came for. Host
-local, like backup and gc: the file has no session equivalent.

Closes #81

Layout: unified · split

cmd/gitbayd/configshow.go added +39
@@ -0,0 +1,39 @@
1package main
2
3import (
4 "fmt"
5 "os"
6
7 "github.com/BurntSushi/toml"
8 "github.com/spf13/cobra"
9
10 "gitbay.org/gitbay/internal/config"
11)
12
13// configShowCmd prints the configuration the daemon runs with: the file
14// with every default filled in, as TOML, so a support question starts
15// from what is in effect rather than what was written. The SMTP password
16// is the one secret the file can hold and is never printed.
17func configShowCmd() *cobra.Command {
18 return &cobra.Command{
19 Use: "show",
20 Short: "print the effective configuration, defaults filled in, secrets redacted",
21 RunE: func(cmd *cobra.Command, args []string) error {
22 cfg, err := config.Load(configPath)
23 if err != nil && cfg.Server.Root == "" {
24 // Nothing decoded: the file is missing or malformed.
25 return err
26 }
27 if cfg.Mail.SMTPPass != "" {
28 cfg.Mail.SMTPPass = "<redacted>"
29 }
30 fmt.Printf("# effective configuration from %s\n", configPath)
31 if encErr := toml.NewEncoder(os.Stdout).Encode(cfg); encErr != nil {
32 return encErr
33 }
34 // A validation failure still prints the config above; the
35 // contradiction it names is what the reader came to see.
36 return err
37 },
38 }
39}
cmd/gitbayd/main.go +3
@@ -327,10 +327,13 @@ func adminCmd() *cobra.Command {
327 hostCmd("visibility <owner/name> public|private", "set a repository's visibility", "admin", "repo", "visibility"), 327 hostCmd("visibility <owner/name> public|private", "set a repository's visibility", "admin", "repo", "visibility"),
328 hostCmd("delete <owner/name> --yes", "delete a repository", "admin", "repo", "delete"), 328 hostCmd("delete <owner/name> --yes", "delete a repository", "admin", "repo", "delete"),
329 ) 329 )
330 configCmd := &cobra.Command{Use: "config", Short: "the configuration in effect"}
331 configCmd.AddCommand(configShowCmd())
330 admin.AddCommand( 332 admin.AddCommand(
331 userCmd, 333 userCmd,
332 emailCmd, 334 emailCmd,
333 repoCmd, 335 repoCmd,
336 configCmd,
334 hostCmd("invite --email <address>", "issue a registration invite and email its code", "admin", "invite"), 337 hostCmd("invite --email <address>", "issue a registration invite and email its code", "admin", "invite"),
335 hostCmd("stats [--json]", "instance statistics: counts and per-repository disk usage", "admin", "stats"), 338 hostCmd("stats [--json]", "instance statistics: counts and per-repository disk usage", "admin", "stats"),
336 hostCmd("audit [--limit n] [--json]", "print the security audit log, newest first", "audit"), 339 hostCmd("audit [--limit n] [--json]", "print the security audit log, newest first", "audit"),
e2e/adminusers_test.go +13
@@ -555,3 +555,16 @@ func TestAdminQueuesDashboard(t *testing.T) {
555 t.Fatal("admin rail lacks /admin") 555 t.Fatal("admin rail lacks /admin")
556 } 556 }
557} 557}
558
559func TestAdminConfigShow(t *testing.T) {
560 inst := startInstanceWith(t, "[mail]\nsmtp_host = \"127.0.0.1:1\"\nfrom = \"forge@example.test\"\nsmtp_pass = \"hunter2\"\n")
561 out := inst.admin(t, "admin", "config", "show")
562 for _, want := range []string{"[server]", "site_url", "ssh_auth_rate = 10", "pull_interval_minutes = 15", "[mail]", `smtp_pass = "<redacted>"`} {
563 if !strings.Contains(out, want) {
564 t.Fatalf("config show lacks %q:\n%s", want, out)
565 }
566 }
567 if strings.Contains(out, "hunter2") {
568 t.Fatalf("config show printed the SMTP password:\n%s", out)
569 }
570}