diff --git a/test/integration/mesh.test.ts b/test/integration/mesh.test.ts index 9819fe7..feca269 100644 --- a/test/integration/mesh.test.ts +++ b/test/integration/mesh.test.ts @@ -553,17 +553,25 @@ test("a machine filters exactly what its modules declared, and nothing else", { `LISTENER`); await must("laptop", `nohup python3 /root/listen.py > /var/log/listen.log 2>&1 & sleep 2`); - const reach = async (port: number) => { + // Two paths to the same machine, which is what makes "from the mesh" testable at all: over the + // private network, and over the segment both machines happen to share. A rule that opens a port + // to the mesh must accept the first and refuse the second — and a test that only ever used one + // path could not tell "open to the mesh" from "open". + const reach = async (where: string, port: number) => { const said = await on("anchor", - `timeout 5 python3 -c "import socket;s=socket.create_connection(('192.0.2.20',${port}),4);` + + `timeout 5 python3 -c "import socket;s=socket.create_connection(('${where}',${port}),4);` + `print(s.recv(32).decode());s.close()"`); return said.ok; }; + const overlay = (port: number) => reach("laptop.internal", port); + const segment = (port: number) => reach("192.0.2.20", port); - // Reachable before any rule set exists, so what changes afterwards is the rule set and not the - // listener. Without this the test would pass against a service that never started. - assert.ok(await reach(9101), "the declared port never opened, so nothing below tests anything"); - assert.ok(await reach(9102), "the undeclared port never opened"); + // Reachable both ways before any rule set exists, so what changes afterwards is the rule set and + // not the listener. Without this the test would pass against a service that never started. + assert.ok(await overlay(9101), "the declared port never opened, so nothing below tests anything"); + assert.ok(await overlay(9102), "the undeclared port never opened"); + assert.ok(await segment(9101), "the declared port is not reachable off the private network yet, " + + "so closing it later would prove nothing"); await must("anchor", `printf %s '{"module":"talker","version":"1",` + `"listens":[{"port":9101,"from":"mesh","why":"the thing this test is about"}],` + @@ -589,18 +597,25 @@ test("a machine filters exactly what its modules declared, and nothing else", { // A rule names its source. Not decoration: it is the only thing that answers "why is this open". assert.match(written, /# talker . the thing this test is about/, `the rule does not name what caused it:\n${written}`); - assert.match(written, /192\.0\.2\.\d+/, `"from the mesh" resolved to nothing:\n${written}`); + // The mesh's addresses are the ones on the private network, which is what "from the mesh" + // means — not the segment the machines happen to share. + assert.match(written, /ip saddr \{ [0-9., ]+ \} tcp dport 9101 accept/, + `"from the mesh" resolved to nothing:\n${written}`); assert.doesNotMatch(written, /dport 9102/, `a port no module declared was opened:\n${written}`); // Loaded, not merely written. The service was restarted because a file it reflects changed. const table = await must("laptop", `nft list table inet mesh`); assert.match(table, /dport 9101 accept/, `the rule set was never loaded:\n${table}`); - // And it filters. The declared port answers from another machine; the undeclared one does not. - assert.ok(await reach(9101), - "the declared port is closed, so the machine is filtering more than it was told to"); - assert.ok(!(await reach(9102)), + // And it filters. Three assertions, and the third is the one that makes "from the mesh" mean + // something rather than being a synonym for "open". + assert.ok(await overlay(9101), + "the declared port is closed on the private network, so the machine is filtering more than " + + "it was told to"); + assert.ok(!(await overlay(9102)), "a port no module declared is still reachable, so the rule set restricts nothing"); + assert.ok(!(await segment(9101)), + "the declared port answers off the private network, so `from: mesh` restricted nothing"); // The machine did not lock itself out of the mesh: it is still taking declarations. assert.doesNotMatch(await mesh("status"), /laptop\s+(failed|refused)/, @@ -612,7 +627,7 @@ test("a machine filters exactly what its modules declared, and nothing else", { await mesh("unassign laptop talker"); await mesh("push laptop"); await new Promise((r) => setTimeout(r, 20_000)); - assert.ok(!(await reach(9101)), + assert.ok(!(await overlay(9101)), "the port stayed open after the module that wanted it was removed"); }); @@ -693,7 +708,7 @@ test("the builder is a module the mesh assigns, with a credential the mesh deliv // And what to check the broker against. A mesh's broker presents a certificate of the mesh's // own, so a URL alone reaches only a broker some public authority vouches for — which is no // mesh broker at all, and fails at TLS with an error about an unknown authority. - assert.match(credential, /"fingerprint":"[0-9a-f]{64}"/, + assert.match(credential, /"fingerprint":"(sha256:)?[0-9a-f]{64}"/, `the builder was given nothing to verify the broker with:\n${credential}`); // And it works: the mesh asks this builder to build something, and it does. Answering is the