Files
mesh-catalog/modules/mesh-build-node/cmd/mesh-build-node/isolation_integration_test.go
T
jschoubben 56f842c3af mesh-build-node: run the type-check, the test script, tsc and esbuild in bubblewrap, so a change's code reaches no key, login or network (issue 1309, S1 S7 S8 S9, ADR 0448)
Each run step goes through mesh-sdk's buildstep.Isolated: no network, none of the account,
the workspace read-write, the toolchain read-only, the npm cache beneath a throwaway layer
unless the build step is told publish (a trunk build). The module declares the bubblewrap
package and refuses a step, unhealthy, while bwrap is missing or older than 0.10. The proof
test runs a probe script through the real test step.
2026-10-22 18:08:12 +02:00

92 lines
3.3 KiB
Go

//go:build integration
package main
import (
"context"
"encoding/json"
"net"
"os"
"os/exec"
"path/filepath"
"strconv"
"testing"
)
// probeScript is a package's test script that tries what a change's code must not reach and writes what it saw.
const probeScript = `import fs from "node:fs";
import dns from "node:dns/promises";
import net from "node:net";
const [key, login, port, sock, cache] = process.argv.slice(2);
const seen = {};
const read = (p) => { try { fs.readFileSync(p); return true; } catch { return false; } };
seen.key = read(key);
seen.login = read(login);
try { await dns.lookup("git.novox.be"); seen.resolved = true; } catch { seen.resolved = false; }
const reach = (opts) => new Promise((ok) => { const c = net.connect(opts); c.on("connect", () => { c.destroy(); ok(true); }); c.on("error", () => ok(false)); });
seen.tcp = await reach({ host: "127.0.0.1", port: Number(port) });
seen.socket = await reach({ path: sock });
try { fs.writeFileSync(cache + "/written-by-a-candidate", "x"); seen.wroteCache = true; } catch { seen.wroteCache = false; }
fs.writeFileSync("seen.json", JSON.stringify(seen));
`
// 1309-S9 (ADR 0448's check): a package's test script, run by the test step, reads no key and no login of the account,
// resolves no name, reaches no socket of the machine (a TCP port on its loopback, a unix socket), and leaves the
// shared cache unchanged.
func TestARunStepReachesNoKeyLoginNameOrSocketAndLeavesTheCacheUnchanged(t *testing.T) {
if _, err := exec.LookPath("bwrap"); err != nil {
t.Skip("NOT RUN: no bubblewrap installed where this check runs; every build node has it (the module declares it)")
}
m, work := realMachine(t)
home := m.Toolchain.Paths.Home
key, login := filepath.Join(home, ".ssh", "mesh_ed25519"), filepath.Join(home, "broker")
write(t, key, "a key", 0o600)
write(t, login, "a login", 0o600)
tcp, err := net.Listen("tcp", "127.0.0.1:0")
if err != nil {
t.Fatal(err)
}
defer tcp.Close()
sockDir, err := os.MkdirTemp("", "sock")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(sockDir)
sock := filepath.Join(sockDir, "s")
unix, err := net.Listen("unix", sock)
if err != nil {
t.Fatal(err)
}
defer unix.Close()
if err := os.MkdirAll(m.npmCache(), 0o700); err != nil {
t.Fatal(err)
}
port := strconv.Itoa(tcp.Addr().(*net.TCPAddr).Port)
dir := filepath.Join(work, "w1", "tree", "modules", "m")
write(t, filepath.Join(dir, "probe.mjs"), probeScript, 0o644)
write(t, filepath.Join(dir, "package.json"), `{"name":"m","type":"module","scripts":{"test":"node probe.mjs `+key+` `+login+` `+port+` `+sock+` `+m.npmCache()+`"}}`, 0o644)
out, err := m.test(context.Background(), map[string]any{"workspace": "w1", "module": "modules/m", "level": "unit"})
if err != nil {
t.Fatal(err)
}
if r := out.(*TestResult); !r.Passed {
t.Fatalf("the probe did not run: %+v", r)
}
raw, err := os.ReadFile(filepath.Join(dir, "seen.json"))
if err != nil {
t.Fatalf("the probe wrote nothing: %v", err)
}
var seen map[string]bool
if err := json.Unmarshal(raw, &seen); err != nil {
t.Fatal(err)
}
for what, reached := range seen {
if reached && what != "wroteCache" {
t.Errorf("the run step reached %s: %s", what, raw)
}
}
if _, err := os.Stat(filepath.Join(m.npmCache(), "written-by-a-candidate")); err == nil {
t.Errorf("a candidate's step changed the shared cache")
}
}