67 lines
2.8 KiB
Go
67 lines
2.8 KiB
Go
//go:build integration
|
|
|
|
package buildstep
|
|
|
|
import (
|
|
"context"
|
|
"net"
|
|
"os"
|
|
"os/exec"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
|
|
"git.novox.be/novox/mesh-sdk/go/forgekey"
|
|
)
|
|
|
|
// 1309/S19, the issue's proof: a run step, in bubblewrap as Isolated runs it, reads no key and no login, resolves no
|
|
// name, reaches no TCP or unix socket of the machine, finds no home of the account, and leaves the shared cache it
|
|
// wrote unchanged; the workspace it writes keeps what it wrote. It needs bubblewrap and unprivileged user namespaces
|
|
// (issue 1308) on the machine that runs it, and fails naming them when they are not there.
|
|
func TestARunStepReachesNothingAndLeavesTheCachesUnchanged(t *testing.T) {
|
|
if _, err := exec.LookPath(Bubblewrap); err != nil {
|
|
t.Fatalf("bubblewrap is not installed here, so the isolation of a run step cannot be proved (issue 1309): %v", err)
|
|
}
|
|
root := t.TempDir()
|
|
account := filepath.Join(root, "account")
|
|
key, login := filepath.Join(account, ".ssh", "id_ed25519"), filepath.Join(account, "bus-login.json")
|
|
writeFile(t, filepath.Dir(key), filepath.Base(key), "PRIVATE KEY")
|
|
writeFile(t, account, "bus-login.json", `{"password":"secret"}`)
|
|
cacheDir := filepath.Join(root, "cache")
|
|
writeFile(t, cacheDir, "warm", "warm\n")
|
|
workspace := filepath.Join(root, "work", "tree")
|
|
if err := os.MkdirAll(workspace, 0o755); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
probe := filepath.Join(workspace, "probe")
|
|
if out, err := exec.Command("go", "build", "-o", probe, "./testdata/isolated-probe").CombinedOutput(); err != nil {
|
|
t.Fatalf("building the probe: %v\n%s", err, out)
|
|
}
|
|
tcp, err := net.Listen("tcp", "127.0.0.1:0")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer tcp.Close()
|
|
socket := filepath.Join(account, "bus.sock")
|
|
unix, err := net.Listen("unix", socket)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer unix.Close()
|
|
|
|
run := Isolated(forgekey.ExecRunnerFor(0), Isolation{Workspace: workspace, Caches: []string{cacheDir}})
|
|
r := run(context.Background(), []string{"PATH=/usr/bin:/bin"}, probe, key, login, tcp.Addr().String(), socket, "localhost.localdomain.invalid", filepath.Join(cacheDir, "warm"))
|
|
if r.Status != 0 || r.Err != "" || strings.TrimSpace(r.Stdout) != "shut off" {
|
|
t.Fatalf("the run step was not shut off (status %d, %s):\n%s%s", r.Status, r.Err, r.Stdout, r.Stderr)
|
|
}
|
|
if b, _ := os.ReadFile(filepath.Join(cacheDir, "warm")); string(b) != "warm\n" {
|
|
t.Fatalf("the step changed the shared cache: %q", b)
|
|
}
|
|
|
|
// The workspace is the step's own: what it writes there stays.
|
|
r = run(context.Background(), nil, "/bin/sh", "-c", "echo built > out")
|
|
if b, err := os.ReadFile(filepath.Join(workspace, "out")); r.Status != 0 || err != nil || string(b) != "built\n" {
|
|
t.Fatalf("the step's write to its workspace did not stay (status %d, %s%s): %q %v", r.Status, r.Stderr, r.Err, b, err)
|
|
}
|
|
}
|