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.
92 lines
3.3 KiB
Go
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")
|
|
}
|
|
}
|