Prove a route reaches the workload, and does not outlive it

The request goes to the name, across the private network, and returns the
workload's own answer. Then the module is unassigned and the same request must
stop working — a stale public name pointing at nothing fails more visibly than
a stale grant.

The workload declares its port as well as its route, because they are different
questions and the earlier test leaves this machine filtering: a module that
asked for a route and not for the port would be unreachable by the proxy it
just asked for.
This commit is contained in:
2026-08-31 02:43:19 +02:00
parent 21a1e85d32
commit 47d990b33a
2 changed files with 88 additions and 0 deletions
+2
View File
@@ -34,6 +34,8 @@ images:
# And the provisioner, which is what makes a sealed credential true on a machine — the mesh
# discarded the plaintext and cannot tell a database to start accepting it.
- mesh-provision-postgres:development
# And the proxy, which is what turns a route grant into traffic actually arriving.
- mesh-route-proxy:development
place:
all: [host, runtime]
+86
View File
@@ -851,3 +851,89 @@ test("rotating a credential moves both ends, and the old one stops working", {
assert.ok(!(await login(first)).ok,
"the password that was rotated away still authenticates, so nothing was rotated");
});
test("a route is a grant: a workload is reached by the name it asked for", {
skip, timeout: 900_000,
}, async () => {
// novox/hq 08-connectivity §3. The mirror of a database grant: there the consumer supplies a
// name and receives credentials; here it supplies a target and receives a name. Nothing new in
// the vocabulary — a route is a provision like any other.
//
// The workload is the registry image, because it is an HTTP server this scenario already has.
// What is being tested is the mesh's arrangement, not the workload.
await must("anchor", `printf %s '{"module":"frontdoor","version":"1",` +
`"provides":[{"name":"route","scope":"mesh"}],` +
`"capabilities":["container-runtime"],` +
`"receives":{"route":"/etc/frontdoor/routes.json"},` +
`"serves":{"route":{"domain":"mesh.test"}},` +
`"listens":[{"port":8081,"from":"mesh","why":"the front door"}],` +
`"resources":[{"id":"dir","type":"directory","path":"/etc/frontdoor","mode":"0755"},` +
`{"id":"proxy","type":"container","name":"front-door",` +
`"image":"${pinned("mesh-route-proxy")}","network":"host",` +
`"volumes":["/etc/frontdoor:/etc/frontdoor:ro"],` +
`"env":{"ROUTES":"/etc/frontdoor/routes.json","LISTEN":":8081"}}]}' ` +
`> /tmp/frontdoor.json`);
// The workload declares the port it listens on as well as the route it wants. Both, because
// they are different questions: one says who may reach it, the other says by what name — and
// the earlier test left this machine filtering, so a module that asked for a route and not for
// the port would be unreachable by the proxy it just asked for.
await must("anchor", `printf %s '{"module":"storefront","version":"1",` +
`"requires":["route"],"capabilities":["container-runtime"],` +
`"contributes":{"route":{"name":"shop.mesh.test","port":8088}},` +
`"binds":{"route":"/etc/storefront/route.json"},` +
`"listens":[{"port":8088,"from":"mesh","why":"the proxy reaches it here"}],` +
`"resources":[{"id":"dir","type":"directory","path":"/etc/storefront","mode":"0755"},` +
`{"id":"app","type":"container","name":"storefront",` +
`"image":"${pinned("registry")}","ports":["8088:5000"]}]}' > /tmp/storefront.json`);
for (const f of ["frontdoor", "storefront"]) {
await must("anchor", `docker cp /tmp/${f}.json mesh-control:/${f}.json`);
await mesh(`module add /${f}.json`);
}
await mesh("assign anchor frontdoor");
await mesh("assign laptop storefront");
await mesh("push");
await new Promise((r) => setTimeout(r, 25_000));
// The provider was told who asked, and where that machine is — which it needs in order to
// reach back, and which it must not have to derive from a naming convention.
const routes = await must("anchor", `cat /etc/frontdoor/routes.json`);
assert.match(routes, /shop\.mesh\.test/, `the proxy was not told about the route:\n${routes}`);
assert.match(routes, /"at": *"laptop\.internal"/,
`the proxy was not told where the consumer is, so it cannot reach it:\n${routes}`);
// And the consumer was told what the provider serves, which is how it knows its own name.
const bound = await must("laptop", `cat /etc/storefront/route.json`);
assert.match(bound, /mesh\.test/, `the consumer was not told the public name:\n${bound}`);
// The whole point: a request for the name reaches the workload, across the private network.
let reached = false;
let said = "";
for (let i = 0; i < 20 && !reached; i++) {
const answer = await on("anchor",
`curl -sf -H 'Host: shop.mesh.test' http://127.0.0.1:8081/v2/ -o /dev/null -w '%{http_code}'`);
said = answer.out;
reached = answer.ok && said.trim() === "200";
if (!reached) await new Promise((r) => setTimeout(r, 4000));
}
assert.ok(reached, `a request for the name did not reach the workload (${said}):\n` +
`${(await on("anchor", `docker logs front-door 2>&1 | tail -20`)).out}`);
// Withdrawal, which 08-connectivity lists as open: a stale public name pointing at nothing
// fails more visibly than a stale grant, so it must not survive the module leaving.
await mesh("unassign laptop storefront");
await mesh("push");
await new Promise((r) => setTimeout(r, 20_000));
const after = await must("anchor", `cat /etc/frontdoor/routes.json`);
assert.doesNotMatch(after, /shop\.mesh\.test/,
`the route outlived the module that asked for it:\n${after}`);
let gone = false;
for (let i = 0; i < 15 && !gone; i++) {
const answer = await on("anchor",
`curl -s -H 'Host: shop.mesh.test' http://127.0.0.1:8081/v2/ -o /dev/null -w '%{http_code}'`);
gone = answer.out.trim() === "404";
if (!gone) await new Promise((r) => setTimeout(r, 3000));
}
assert.ok(gone, "the proxy still serves a name whose module was unassigned");
});