The five beds that read the catalogue read it through the harness

adopted-store-cross-node, two-node-db and the three whole-mesh beds each carried a
private loader; they drifted. The ace loader never resolved a runtime artifact, so a
module the mesh builds travelled unresolved; whole-mesh-full still asked for
'registry' and 'firewall', which the catalogue names distribution and nftables, and
swallowed the miss as NOT ASSIGNED. One loader now (novox/hq 04-ISSUES/073).
This commit is contained in:
2026-09-21 14:33:02 +02:00
parent 2456b2f533
commit e596758db9
6 changed files with 53 additions and 167 deletions
@@ -21,29 +21,25 @@
*/
import { test, before, after } from "node:test";
import assert from "node:assert/strict";
import { existsSync, readFileSync } from "node:fs";
import { dirname, resolve } from "node:path";
import { existsSync } from "node:fs";
import { loadScenario } from "../../src/declaration/parse.ts";
import { raise } from "../../src/lifecycle/raise.ts";
import { destroy, exec } from "../../src/lifecycle/operate.ts";
import { hostBinaryPath, HOST_PATH } from "../../src/lifecycle/place.ts";
import { labIsUsable, destroyAll, foundationBundle, onTheMachine } from "./harness.ts";
import { labIsUsable, destroyAll, foundationBundle, catalogueIsPresent, catalogueModule, needsBrokerAccount } from "./harness.ts";
import type { HeldImage } from "../../src/pinning.ts";
const capability = await labIsUsable();
const binary = hostBinaryPath();
const bundle = process.env["MESH_LAB_BUNDLE"] ?? "";
const modulesEnv = process.env["MESH_LAB_MODULES"] ?? "";
const skip = !capability.usable ? `lab not usable: ${capability.why}`
: !binary || !existsSync(binary) ? "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"
: false;
: catalogueIsPresent();
const SCENARIO = "adopted-store-cross-node";
const NODE = "node2";
const catalogDir = process.env["MESH_LAB_CATALOG"]
?? (modulesEnv ? resolve(dirname(dirname(dirname(modulesEnv))), "mesh-catalog", "modules") : "")
?? resolve(process.cwd(), "..", "mesh-catalog", "modules");
let instanceId = "";
let held: HeldImage[] = [];
@@ -65,29 +61,12 @@ async function must(machine: string, command: string, timeoutMs?: number): Promi
async function mesh(command: string, timeoutMs?: number): Promise<string> {
return must("anchor", `docker exec mesh-controller /mesh-controller ${command}`, timeoutMs);
}
function pinned(reference: string): string { return onTheMachine(reference, held); }
function bundleFor(images: HeldImage[]): string { return foundationBundle(bundle, images); }
/** Load a committed module.json with its container images rewritten to the scenario's pinned digests. */
/** The catalogue's manifest as the lab runs it (harness), and whether it needs a broker account. */
function loadManifest(name: string): { manifest: string; broker: boolean } {
const path = resolve(catalogDir, name, "module.json");
const m = JSON.parse(readFileSync(path, "utf8")) as {
resources?: { type: string; image?: string; artifact?: string }[];
};
for (const r of m.resources ?? []) {
if (r.type !== "container") continue;
if (typeof r.image === "string") {
// A placeholder image (mesh-runtime-<m>@0…0) resolves to the stocked digest, as redis does.
r.image = pinned(r.image);
} else if (typeof r.artifact === "string") {
// The bundle-model bed does not build, so resolve a module's runtime ARTIFACT to its stocked
// image directly — postgres/lavinmq name their provisioner by artifact, not a placeholder.
r.image = pinned(`mesh-runtime-${name}@sha256:${"0".repeat(64)}`);
delete r.artifact;
}
}
const manifest = JSON.stringify(m);
return { manifest, broker: manifest.includes("MESH_BROKER_FILE") };
const manifest = catalogueModule(name, held);
return { manifest, broker: needsBrokerAccount(manifest) };
}
function tokenFrom(said: string): string {
const found = said.split("\n").map((l) => l.trim()).find((l) => l.length > 100 && !l.includes(" "));
@@ -105,7 +84,6 @@ async function install(name: string, node: string): Promise<void> {
before(async () => {
if (skip) return;
assert.ok(existsSync(catalogDir), `mesh-catalog modules not found at ${catalogDir}`);
const raised = await raise(loadScenario(`scenarios/${SCENARIO}.yml`), { onProgress: (m) => console.log(`raise: ${m}`) });
instanceId = raised.instanceId;
held = raised.images;