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:
@@ -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.
|
||||
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}`);
|
||||
|
||||
// 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,7 +24,7 @@ import { raise } from "../../src/lifecycle/raise.ts";
|
||||
import type { HeldImage } from "../../src/pinning.ts";
|
||||
import { destroy, exec } from "../../src/lifecycle/operate.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 { machineName } from "../../src/lifecycle/names.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"
|
||||
: !bundle || !existsSync(bundle)
|
||||
? "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";
|
||||
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
|
||||
* loopback — the one that builds until a builder module can (see the retired test's note). */
|
||||
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", `pgrep -x mesh-builder >/dev/null || ` +
|
||||
`(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
|
||||
// assumed: nothing else in this scenario would start one.
|
||||
if (builder) {
|
||||
await incus([
|
||||
"file", "push", builder, `${machineName(instanceId, "anchor")}/usr/local/bin/mesh-builder`,
|
||||
"--mode", "0755",
|
||||
], 180_000);
|
||||
await startBuilder();
|
||||
}
|
||||
if (builder) await startBuilder();
|
||||
if (warming) {
|
||||
// Snapshotted only now, with everything up: a state worth returning to is the one after the
|
||||
// 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
|
||||
// fails at once and says which name it was.
|
||||
//
|
||||
// Both, and that is not tidiness: `mesh-resolver` requires name resolution, which requires the
|
||||
// network, so unassigning the domain module alone leaves the machine on the network — pulled
|
||||
// back by its own requirement. The mesh was right and this test was wrong the first time.
|
||||
// Both: the resolver's data follows the private network, so the machine leaves the network as
|
||||
// well as the resolver, and what is asserted is that the machine that stayed is answered for and
|
||||
// the one that left is not.
|
||||
await mesh("unassign laptop dnsmasq");
|
||||
await mesh("unassign laptop networking");
|
||||
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
|
||||
// larger job. This is the half that can be known now, and it is the half where a design fault
|
||||
// would live.
|
||||
// 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
|
||||
// and proves the composed declaration), "the forge runs, on a database the mesh gave it" (the same
|
||||
// bed, gitea on the mesh's postgres) and "a consumer's cache grant means exactly its own keys"
|
||||
// (mesh-grant-end-to-end, against the catalogue's redis). Retired 2026-09-22 rather than rewritten
|
||||
// into copies of those beds (novox/hq issue 074).
|
||||
// Three tests lived here that read the mesh's example modules, which moved to the catalogue.
|
||||
// Retired 2026-09-22 rather than rewritten into copies of the beds that stand where they stood
|
||||
// (novox/hq issue 074): "the real modules resolve together" — whole-mesh-novox installs the
|
||||
// catalogue's modules together and its gate is the composed declaration accepted and every core
|
||||
// container running; "the forge runs, on a database the mesh gave it" — the same bed, which gates
|
||||
// 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.
|
||||
|
||||
Reference in New Issue
Block a user