cmd/gitbay-runner/init.go

3bcdce33fb9a2309312854331359d376171c7368
gitbay/cmd/gitbay-runner/init.go history · blame · raw

89 lines · 3183 bytes

 1package main
 2
 3import (
 4	"flag"
 5	"fmt"
 6	"io"
 7	"os"
 8	"os/exec"
 9	"path/filepath"
10	"strings"
11
12	"gitbay.org/gitbay/internal/toolpath"
13)
14
15// initOut is where init prints; tests capture it.
16var initOut io.Writer = os.Stdout
17
18// runInit makes a fresh install ready to attach: a key of its own, a
19// config file the service reads, and the one command to run next. It never
20// overwrites a key or a config that exists, so running it twice is safe.
21func runInit(args []string) int {
22	fs := flag.NewFlagSet("init", flag.ContinueOnError)
23	fs.SetOutput(initOut)
24	remote := fs.String("remote", "git@gitbay.org", "ssh destination of the gitbay server")
25	workdir := fs.String("workdir", defaultWorkdir(), "build workspace root")
26	isolation := fs.String("isolation", isolationNone, "how steps run: none, or podman with -image")
27	image := fs.String("image", "", "container image for -isolation podman")
28	if err := fs.Parse(args); err != nil {
29		return 2
30	}
31	if *isolation == isolationPodman && *image == "" {
32		fmt.Fprintln(initOut, "-isolation podman needs -image <ref>: the runner refuses to start without one, and there is no image to guess")
33		return 2
34	}
35	if *isolation != isolationPodman && *isolation != isolationNone {
36		fmt.Fprintf(initOut, "unknown isolation %q\n", *isolation)
37		return 2
38	}
39
40	dir := configDir()
41	if err := os.MkdirAll(dir, 0o700); err != nil {
42		fmt.Fprintln(initOut, err)
43		return 1
44	}
45	os.Chmod(dir, 0o700)
46	key := filepath.Join(dir, "id_ed25519")
47	if !fileExists(key) {
48		cmd := exec.Command(toolpath.Look("ssh-keygen"), "-q", "-t", "ed25519", "-N", "", "-C", "gitbay-runner", "-f", key)
49		if out, err := cmd.CombinedOutput(); err != nil {
50			fmt.Fprintf(initOut, "ssh-keygen: %v\n%s", err, out)
51			return 1
52		}
53	}
54	os.Chmod(key, 0o600)
55
56	cfgPath := filepath.Join(dir, "config.toml")
57	if !fileExists(cfgPath) {
58		var b strings.Builder
59		fmt.Fprintf(&b, "remote = %q\n", *remote)
60		fmt.Fprintf(&b, "workdir = %q\n", *workdir)
61		fmt.Fprintf(&b, "isolation = %q\n", *isolation)
62		if *image != "" {
63			fmt.Fprintf(&b, "image = %q\n", *image)
64		}
65		fmt.Fprintf(&b, "untrusted = false\n")
66		fmt.Fprintf(&b, "identity = %q\n", key)
67		if err := os.WriteFile(cfgPath, []byte(b.String()), 0o600); err != nil {
68			fmt.Fprintln(initOut, err)
69			return 1
70		}
71	}
72
73	pub, err := os.ReadFile(key + ".pub")
74	if err != nil {
75		fmt.Fprintln(initOut, err)
76		return 1
77	}
78	host := *remote
79	if i := strings.LastIndex(host, "@"); i >= 0 {
80		host = host[i+1:]
81	}
82	fmt.Fprintf(initOut, "config: %s\nkey:    %s\n\n", cfgPath, key)
83	if *isolation == isolationNone {
84		fmt.Fprintln(initOut, "Steps run on this machine as your user, with no container. Untrusted builds\n(merge requests from forks) are excluded unless the runner is started with\n-untrusted, so that means your own commits.")
85	}
86	fmt.Fprintf(initOut, "This runner's public key:\n\n  %s\nAttach it to each repository it should build, as a repository admin:\n\n  gitbay repo runner add owner/name < %s.pub\n\nor paste it under Runners at https://%s/owner/name/settings\n\nThen start it:\n\n  brew services start krz/tap/gitbay-runner\n\nor run gitbay-runner with no arguments.\n",
87		strings.TrimSpace(string(pub)), key, host)
88	return 0
89}