Review: the cache grant's tenancy assertions move into the grant bed; retirement notes say what the beds prove; the builder binary is pushed on a warm return; the large bed needs the catalogue

This commit is contained in:
2026-09-22 01:27:52 +02:00
parent 353cf88a4b
commit 10cfbd094a
2 changed files with 36 additions and 18 deletions
@@ -227,4 +227,16 @@ test("the mesh grants a consumer redis's cache, and the credential it delivers a
// writing the contributions rather than the bed. // writing the contributions rather than the bed.
const runtimeEnv = await must(`docker inspect mesh-redis --format '{{json .Config.Env}}'`); const runtimeEnv = await must(`docker inspect mesh-redis --format '{{json .Config.Env}}'`);
assert.doesNotMatch(runtimeEnv, /MESH_SEAL_KEY/, `a seal key was set after all — ADR 0048 is not what ran:\n${runtimeEnv}`); assert.doesNotMatch(runtimeEnv, /MESH_SEAL_KEY/, `a seal key was set after all — ADR 0048 is not what ran:\n${runtimeEnv}`);
// A grant means exactly the consumer's own keys: under its name it reads and writes, outside it
// and on the server as a whole it is refused. Carried over from the large mesh bed's retired
// cache-grant test — without this a provisioner that granted everything would keep every bed green.
const asConsumer = (command: string) =>
on(`docker exec redis redis-cli --user ${quote(as)} --pass ${quote(password)} --no-auth-warning ${command} 2>&1`);
assert.match((await asConsumer("SET cacheuser:proof yes")).out, /OK/, "the consumer cannot write under its own name");
assert.match((await asConsumer("GET cacheuser:proof")).out, /yes/, "the consumer cannot read back what it wrote");
assert.match((await asConsumer("SET other:proof no")).out, /NOPERM|no permissions/i,
"the consumer wrote outside its own keys, so the grant means more than it says");
assert.match((await asConsumer("FLUSHALL")).out, /NOPERM|no permissions/i,
"the consumer flushed the whole server, so the grant means more than it says");
}); });
+24 -18
View File
@@ -24,7 +24,7 @@ import { raise } from "../../src/lifecycle/raise.ts";
import type { HeldImage } from "../../src/pinning.ts"; import type { HeldImage } from "../../src/pinning.ts";
import { destroy, exec } from "../../src/lifecycle/operate.ts"; import { destroy, exec } from "../../src/lifecycle/operate.ts";
import { hostBinaryPath, HOST_PATH } from "../../src/lifecycle/place.ts"; import { hostBinaryPath, HOST_PATH } from "../../src/lifecycle/place.ts";
import { labIsUsable, destroyAll, foundationBundle, onTheMachine, catalogueModule, deriveTheFilterOn } from "./harness.ts"; import { labIsUsable, destroyAll, foundationBundle, onTheMachine, catalogueModule, deriveTheFilterOn, catalogueIsPresent } from "./harness.ts";
import { incus } from "../../src/incus/client.ts"; import { incus } from "../../src/incus/client.ts";
import { machineName } from "../../src/lifecycle/names.ts"; import { machineName } from "../../src/lifecycle/names.ts";
import { ready, returnTo, keep, rememberStock, warmStock } from "../../src/warm.ts"; import { ready, returnTo, keep, rememberStock, warmStock } from "../../src/warm.ts";
@@ -44,7 +44,8 @@ const skip = !capability.usable
? "MESH_LAB_HOST_BINARY is not set to a built mesh-host" ? "MESH_LAB_HOST_BINARY is not set to a built mesh-host"
: !bundle || !existsSync(bundle) : !bundle || !existsSync(bundle)
? "MESH_LAB_BUNDLE is not set to a foundation bundle (mesh-host examples/)" ? "MESH_LAB_BUNDLE is not set to a foundation bundle (mesh-host examples/)"
: false; // The anchor's filter and the resolvers are the catalogue's (ADR 0088, issue 074).
: catalogueIsPresent() || false;
const SCENARIO = "two-nodes"; const SCENARIO = "two-nodes";
let instanceId = ""; let instanceId = "";
@@ -202,6 +203,14 @@ function tokenFrom(said: string): string {
/** The builder started by hand on the anchor, against the foundation broker's plain port on /** The builder started by hand on the anchor, against the foundation broker's plain port on
* loopback — the one that builds until a builder module can (see the retired test's note). */ * loopback — the one that builds until a builder module can (see the retired test's note). */
async function startBuilder(): Promise<void> { async function startBuilder(): Promise<void> {
// The binary is disk and survives a snapshot; a snapshot taken without it does not gain it on a
// return, so it is pushed whenever the machine has none.
if (!(await on("anchor", `test -x /usr/local/bin/mesh-builder`)).ok) {
await incus([
"file", "push", builder, `${machineName(instanceId, "anchor")}/usr/local/bin/mesh-builder`,
"--mode", "0755",
], 180_000);
}
await must("anchor", `mkdir -p /var/lib/mesh-builder`); await must("anchor", `mkdir -p /var/lib/mesh-builder`);
await must("anchor", `pgrep -x mesh-builder >/dev/null || ` + await must("anchor", `pgrep -x mesh-builder >/dev/null || ` +
`(MESH_BROKER_AMQP='amqp://guest:guest@127.0.0.1:5672/' MESH_REGISTRY=${registry} ` + `(MESH_BROKER_AMQP='amqp://guest:guest@127.0.0.1:5672/' MESH_REGISTRY=${registry} ` +
@@ -269,13 +278,7 @@ before(async () => {
// A build machine, so anything here can ask the mesh to build something. Placed rather than // A build machine, so anything here can ask the mesh to build something. Placed rather than
// assumed: nothing else in this scenario would start one. // assumed: nothing else in this scenario would start one.
if (builder) { if (builder) await startBuilder();
await incus([
"file", "push", builder, `${machineName(instanceId, "anchor")}/usr/local/bin/mesh-builder`,
"--mode", "0755",
], 180_000);
await startBuilder();
}
if (warming) { if (warming) {
// Snapshotted only now, with everything up: a state worth returning to is the one after the // Snapshotted only now, with everything up: a state worth returning to is the one after the
// part nobody wants to repeat. // part nobody wants to repeat.
@@ -1386,9 +1389,9 @@ test("every name under a machine resolves to that machine", {
// because a wildcard pointing at nothing resolves and then hangs — where an unresolvable name // because a wildcard pointing at nothing resolves and then hangs — where an unresolvable name
// fails at once and says which name it was. // fails at once and says which name it was.
// //
// Both, and that is not tidiness: `mesh-resolver` requires name resolution, which requires the // Both: the resolver's data follows the private network, so the machine leaves the network as
// network, so unassigning the domain module alone leaves the machine on the network — pulled // well as the resolver, and what is asserted is that the machine that stayed is answered for and
// back by its own requirement. The mesh was right and this test was wrong the first time. // the one that left is not.
await mesh("unassign laptop dnsmasq"); await mesh("unassign laptop dnsmasq");
await mesh("unassign laptop networking"); await mesh("unassign laptop networking");
await mesh("push anchor"); await mesh("push anchor");
@@ -1646,9 +1649,12 @@ test("a third-party workload is adopted, with the credential it already had", {
// Running them needs their images stocked and two provisioners built, which is a separate and // Running them needs their images stocked and two provisioners built, which is a separate and
// larger job. This is the half that can be known now, and it is the half where a design fault // larger job. This is the half that can be known now, and it is the half where a design fault
// would live. // would live.
// Three tests lived here that read the mesh's example modules, which moved to the catalogue: // Three tests lived here that read the mesh's example modules, which moved to the catalogue.
// "the real modules resolve together" (whole-mesh-novox installs the catalogue's modules together // Retired 2026-09-22 rather than rewritten into copies of the beds that stand where they stood
// and proves the composed declaration), "the forge runs, on a database the mesh gave it" (the same // (novox/hq issue 074): "the real modules resolve together" — whole-mesh-novox installs the
// bed, gitea on the mesh's postgres) and "a consumer's cache grant means exactly its own keys" // catalogue's modules together and its gate is the composed declaration accepted and every core
// (mesh-grant-end-to-end, against the catalogue's redis). Retired 2026-09-22 rather than rewritten // container running; "the forge runs, on a database the mesh gave it" — the same bed, which gates
// into copies of those beds (novox/hq issue 074). // on gitea running but does not yet ask it to answer on its port with the credential it was given,
// a gap that bed should close; "a consumer's cache grant means exactly its own keys" — its tenancy
// assertions (a write outside the consumer's keys and a FLUSHALL are refused) moved into
// mesh-grant-end-to-end, against the catalogue's redis.