2023-01-22 03:21:11 +00:00
|
|
|
package main
|
|
|
|
|
|
|
|
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
|
|
|
|
|
|
|
|
func main() {
|
|
|
|
config, err := readConfig()
|
|
|
|
must(err)
|
2023-01-22 13:06:23 +00:00
|
|
|
must(run(config, "rootfs/", "cache/"))
|
2023-01-22 03:21:11 +00:00
|
|
|
|
2023-01-22 13:06:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func run(config Config, rootfs string, cache string) (err error) {
|
|
|
|
if err = os.RemoveAll("rootfs/"); err != nil {
|
|
|
|
return
|
|
|
|
}
|
2023-01-22 03:43:17 +00:00
|
|
|
|
2023-01-22 13:06:23 +00:00
|
|
|
if err = os.MkdirAll("rootfs/etc/apk/keys", 0700); err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if err = os.WriteFile("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
|
|
|
|
}
|
|
|
|
|
|
|
|
if err = os.WriteFile("rootfs/etc/resolv.conf", []byte(`nameserver 8.8.8.8`), 0644); err != nil {
|
|
|
|
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 {
|
|
|
|
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-22 13:06:23 +00:00
|
|
|
if err = os.MkdirAll("cache/_var_cache_apk", 0700); err != nil {
|
|
|
|
return
|
|
|
|
}
|
2023-01-22 03:21:11 +00:00
|
|
|
os.Remove("rootfs/etc/apk/cache")
|
2023-01-22 13:06:23 +00:00
|
|
|
if err = os.Symlink("/var/cache/apk", "rootfs/etc/apk/cache"); err != nil {
|
|
|
|
return
|
|
|
|
}
|
2023-01-22 03:21:11 +00:00
|
|
|
cmd := exec.Command("apk", "add",
|
|
|
|
"--root", "rootfs",
|
|
|
|
"--initdb",
|
|
|
|
"--cache-dir", "../cache/_var_cache_apk",
|
|
|
|
"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 {
|
|
|
|
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(
|
|
|
|
[]string{"--bind", "./rootfs", "/",
|
|
|
|
"--ro-bind", ".", "/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,
|
|
|
|
"apk", "add", "busybox", "busybox-suid", "libc-utils", "alpine-baselayout", "alpine-conf", "alpine-release")...)
|
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-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, " ")...)...)
|
|
|
|
cmd.Stdout = os.Stdout
|
|
|
|
cmd.Stdin = os.Stdin
|
|
|
|
cmd.Stderr = os.Stderr
|
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
|
|
|
}
|
|
|
|
|
|
|
|
func must(err error, where ...string) {
|
|
|
|
if err != nil {
|
|
|
|
log.Fatal(err, where)
|
|
|
|
}
|
|
|
|
}
|