//go:build integration && isolation 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) } }