cmd/gitbay-runner/init.go
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}