| @@ -0,0 +1,89 @@ |
| 1 | package main |
| 2 | |
| 3 | import ( |
| 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. |
| 16 | var 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. |
| 21 | func 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 | } |