A CLI-first git forge.

cli forge git self-hosted

https://gitbay.org

Commit 71b6697774

71b669777420d90dd45caa8d4a8ccb2a948de751

parent: 8246c58f81

Verified · cmc ci/build: success

cmc <hello@cleberg.net> · 2026-08-25T18:44:55Z

CLI: pipe stdin through for repo secret set

stdinOK only wires stdin when --file - or --token-stdin appears in the
args; secret set has no flag — stdin is the payload. Use alwaysStdin,
like release asset add.
cmd/gitbay/main.go +1 −1
@@ -260,7 +260,7 @@ func repoCmd() *cobra.Command {
260260 pass("sync", "schedule an immediate sync", passOpts{server: []string{"repo", "mirror", "sync"}, needsRepo: true}),
261261 ),
262262 group("secret", "build secrets (values on stdin, injected into build env)",
263 pass("set", "set a secret: <NAME> (value on stdin)", passOpts{server: []string{"repo", "secret", "set"}, needsRepo: true, stdinOK: true}),
263 pass("set", "set a secret: <NAME> (value on stdin)", passOpts{server: []string{"repo", "secret", "set"}, needsRepo: true, alwaysStdin: true}),
264264 pass("list", "list secret names", passOpts{server: []string{"repo", "secret", "list"}, needsRepo: true}),
265265 pass("remove", "remove a secret: <NAME>", passOpts{server: []string{"repo", "secret", "remove"}, needsRepo: true}),
266266 ),
e2e/cli_test.go +7
@@ -106,6 +106,13 @@ func TestCLI(t *testing.T) {
106106
107107 // Repo create + clone through the CLI.
108108 c.must(t, "", "", "repo", "create", "alice/proj")
109
110 // Secret values travel on stdin through the CLI (piped, no flag).
111 c.must(t, "", "hunter2\n", "repo", "secret", "set", "alice/proj", "TOKEN")
112 if out := c.must(t, "", "", "repo", "secret", "list", "alice/proj"); !strings.Contains(out, "TOKEN") || strings.Contains(out, "hunter2") {
113 t.Fatalf("secret list via CLI: %s", out)
114 }
115
109116 work := t.TempDir()
110117 c.must(t, work, "", "repo", "clone", "alice/proj")
111118 dir := filepath.Join(work, "proj")