repro-run/runner/runner.go

133 lines
3.1 KiB
Go
Raw Normal View History

2023-01-22 13:14:48 +00:00
package runner
2023-01-22 03:21:11 +00:00
import (
"embed"
2023-01-22 13:06:23 +00:00
"fmt"
2023-01-22 03:21:11 +00:00
"io"
"log"
"os"
"os/exec"
"path"
"strings"
)
//go:embed alpine/keys
var alpineKeys embed.FS
2023-01-23 00:58:44 +00:00
func Run(config Config, rootfs string, cache string, src string, w io.Writer) (err error) {
if err = os.RemoveAll(rootfs); err != nil {
2023-01-22 13:06:23 +00:00
return
}
2023-01-22 03:43:17 +00:00
2023-01-23 00:58:44 +00:00
if err = os.MkdirAll(path.Join(rootfs, "etc/apk/keys"), 0700); err != nil {
2023-01-22 13:06:23 +00:00
return
}
2023-01-23 00:58:44 +00:00
if err = os.WriteFile(path.Join(rootfs, "etc/apk/repositories"), []byte(
2023-01-22 03:21:11 +00:00
`https://dl-cdn.alpinelinux.org/alpine/v3.17/main
2023-01-22 13:06:23 +00:00
https://dl-cdn.alpinelinux.org/alpine/v3.17/community`), 0600); err != nil {
return
}
2023-01-23 00:58:44 +00:00
if err = os.WriteFile(path.Join(rootfs, "etc/resolv.conf"), []byte(`nameserver 8.8.8.8`), 0644); err != nil {
2023-01-22 13:06:23 +00:00
return
}
2023-01-22 03:21:11 +00:00
keys, err := alpineKeys.ReadDir("alpine/keys")
2023-01-22 13:06:23 +00:00
if err != nil {
return
}
2023-01-22 03:21:11 +00:00
for _, entry := range keys {
2023-01-23 00:58:44 +00:00
o, err := os.Create(path.Join(rootfs, "etc/apk/keys/", entry.Name()))
2023-01-22 13:06:23 +00:00
if err != nil {
return err
}
2023-01-22 03:21:11 +00:00
s, err := alpineKeys.Open(path.Join("alpine/keys", entry.Name()))
2023-01-22 13:06:23 +00:00
if err != nil {
return err
}
if _, err = io.Copy(o, s); err != nil {
return err
}
2023-01-22 03:21:11 +00:00
}
2023-01-23 00:58:44 +00:00
if err = os.MkdirAll(path.Join(cache, "_var_cache_apk"), 0700); err != nil {
2023-01-22 13:06:23 +00:00
return
}
2023-01-23 00:58:44 +00:00
if err = os.Symlink("/var/cache/apk", path.Join(rootfs, "etc/apk/cache")); err != nil {
2023-01-22 13:06:23 +00:00
return
}
2023-01-22 03:21:11 +00:00
cmd := exec.Command("apk", "add",
2023-01-23 00:58:44 +00:00
"--root", rootfs,
2023-01-22 03:21:11 +00:00
"--initdb",
2023-01-23 00:58:44 +00:00
"--cache-dir", path.Join(cache, "_var_cache_apk"),
2023-01-22 03:21:11 +00:00
"apk-tools")
2023-01-22 13:06:23 +00:00
if err = cmd.Run(); err != nil {
return fmt.Errorf("apk add apk-tools: %w", err)
}
2023-01-22 03:21:11 +00:00
cached := append(config.Cache, "/var/cache/apk")
var cachedParams []string
for _, c := range cached {
2023-01-23 00:58:44 +00:00
cacheDir := path.Join(cache, strings.ReplaceAll(c, "/", "_"))
2023-01-22 13:06:23 +00:00
if err = os.MkdirAll(cacheDir, 0700); err != nil {
return
}
2023-01-22 03:21:11 +00:00
cachedParams = append(cachedParams, "--bind", cacheDir, c)
}
tmp, err := os.MkdirTemp("", "repro-run-")
2023-01-22 13:06:23 +00:00
if err != nil {
return
}
2023-01-22 03:29:56 +00:00
defer os.RemoveAll(tmp)
2023-01-22 03:28:00 +00:00
log.Println("/work = " + tmp)
2023-01-22 03:21:11 +00:00
params := append(
2023-01-23 00:58:44 +00:00
[]string{"--bind", rootfs, "/",
"--ro-bind", src, "/src",
2023-01-22 03:28:10 +00:00
"--dev-bind", "/dev", "/dev",
2023-01-22 03:21:11 +00:00
"--bind", tmp, "/work",
2023-01-22 03:43:36 +00:00
"--unshare-user", "--uid", "1000", "--gid", "1000",
"--setenv", "HOME", "/home/repro",
2023-01-22 03:21:11 +00:00
"--chdir", "/work",
},
cachedParams...)
log.Println(strings.Join(params, " "))
cmd = exec.Command("bwrap", append(params,
2023-01-23 14:40:47 +00:00
"apk", "add", "--quiet", "busybox", "busybox-suid", "libc-utils", "alpine-baselayout", "alpine-conf", "alpine-release")...)
cmd.Stdout = os.Stderr
cmd.Stderr = os.Stderr
2023-01-22 13:06:23 +00:00
if err = cmd.Run(); err != nil {
return fmt.Errorf("bwrap apk add: %w", err)
}
2023-01-22 03:43:36 +00:00
cmd = exec.Command("bwrap", append(params,
"--uid", "0",
"adduser", "-u", "1000", "-D", "repro")...)
2023-01-23 14:40:47 +00:00
cmd.Stdout = os.Stderr
cmd.Stderr = os.Stderr
2023-01-22 13:06:23 +00:00
if err = cmd.Run(); err != nil {
return fmt.Errorf("bwrap adduser repro: %w", err)
}
2023-01-22 03:21:11 +00:00
cmd = exec.Command("bwrap", append(params, strings.Split(config.Command, " ")...)...)
2023-01-23 00:58:44 +00:00
// cmd.Stdin = os.Stdin
if w == nil {
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
} else {
cmd.Stdout = w
cmd.Stderr = w
}
2023-01-22 13:06:23 +00:00
if err = cmd.Run(); err != nil {
return fmt.Errorf("running Command: %w", err)
}
2023-01-22 03:21:11 +00:00
2023-01-22 13:06:23 +00:00
return
2023-01-22 03:21:11 +00:00
}
2023-01-23 00:58:44 +00:00
type Config struct {
Command string
Cache []string
}