Twenty-eight integration tests each carried their own copy of the same two helpers, which pointed a manifest and the substrate bundle at whatever the lab's registry had assigned. They now share two in the harness, and the difference is the point: ours is rewritten to the ID the machine holds it under, and everything else is left exactly as written so the machine pulls it. **The substrate bundle is where the fiction was most load-bearing.** mesh-host's `examples/substrate-first-node.lock` pins all three of its images at `192.0.2.250:5000/…`, which is the address the lab's registry served from — it was written for a target, and the target was the lab. Two of those are ordinary third-party images and become the digests mesh-catalog's own postgres and lavinmq modules pin, so the substrate's store and broker are literally the images the mesh runs. mesh-control exists in no registry at all and becomes the ID the machine was handed. **The bundle itself should be fixed in mesh-host and this substitution deleted with it.** Beds that wrote a manifest by hand named an image by repository and let the rewrite supply a digest. There is nothing to supply one now, so `onTheMachine` refuses an unpinned reference and hands back the digest the catalogue pins — a bed runs the image the mesh ships, and a bed that drifts from the catalogue is testing a different postgres. Three beds took a third-party image out of the raised list, which no longer contains one: certificates (pebble), objectstore (minio and its client) and provisioner (postgres) now name theirs and pull it. builds and mesh publish into the MESH's own artifact store — the `registry` module's image, on the node, on 5000 — rather than into scenery the lab raised. That is a different claim, and only one of them exists in production. New unit tests cover what a full raise would otherwise be the only way to check: the routes an egress machine gets (that its gateway is still the path to the rest of the scenario, that a range with no path is unreachable rather than leaked to the uplink, that each family gets its own next hop), which machine is handed which of our images, and the `images:` rule that refuses a third-party entry. The "shipped scenarios are valid" test now loads every scenario rather than two of them. Claude-Session: https://claude.ai/code/session_01LrgweAeERJYBg88c5cKDzF
137 lines
5.8 KiB
TypeScript
137 lines
5.8 KiB
TypeScript
import { test } from "node:test";
|
|
import assert from "node:assert/strict";
|
|
|
|
import {
|
|
isMeshBuilt, pinnedInto, referenceFor, repositoryOf, stillUnpinned, type HeldImage,
|
|
} from "../src/pinning.ts";
|
|
|
|
/**
|
|
* What a machine holds, and what it does not.
|
|
*
|
|
* The lab used to raise a registry inside the scenario and rewrite EVERY reference to it —
|
|
* third-party ones included. That registry exists in no production mesh, so what these tests
|
|
* describe now is the real division: our images are handed over and named by their own ID,
|
|
* everything else is pulled from the internet and left exactly as written.
|
|
*/
|
|
const HELD: HeldImage[] = [
|
|
{
|
|
requested: "mesh-control:development",
|
|
repository: "mesh-control",
|
|
reference: "sha256:" + "a".repeat(64),
|
|
},
|
|
{
|
|
requested: "mesh-runtime-postgres:development",
|
|
repository: "mesh-runtime-postgres",
|
|
reference: "sha256:" + "b".repeat(64),
|
|
},
|
|
{
|
|
requested: "mesh-route-proxy:development",
|
|
repository: "mesh-route-proxy",
|
|
reference: "sha256:" + "c".repeat(64),
|
|
},
|
|
];
|
|
|
|
test("the repository is the reference without its tag", () => {
|
|
assert.equal(repositoryOf("mesh-runtime-postgres:development"), "mesh-runtime-postgres");
|
|
assert.equal(repositoryOf("alpine"), "alpine");
|
|
assert.equal(repositoryOf("gitea/gitea:1.22"), "gitea/gitea");
|
|
assert.equal(repositoryOf("ghcr.io/mailu/admin@sha256:" + "d".repeat(64)), "ghcr.io/mailu/admin");
|
|
// A port in a hostname is a colon that is NOT a tag, and treating it as one would truncate the
|
|
// host rather than the tag.
|
|
assert.equal(
|
|
repositoryOf("registry.example:5000/novox/www:latest"), "registry.example:5000/novox/www");
|
|
});
|
|
|
|
/**
|
|
* The line the whole change turns on.
|
|
*
|
|
* An image with somewhere to be fetched from is fetched from there. An image with nowhere — no
|
|
* registry host, no upstream organisation, and a `mesh-` name — is one built here and handed over.
|
|
*/
|
|
test("only what is built here and published nowhere counts as ours", () => {
|
|
for (const ours of [
|
|
"mesh-control:development", "mesh-runtime-plex:development", "mesh-route-proxy:development",
|
|
"mesh-provision-postgres@sha256:" + "0".repeat(64),
|
|
]) {
|
|
assert.ok(isMeshBuilt(ours), `${ours} is one of ours and was not recognised`);
|
|
}
|
|
for (const theirs of [
|
|
"postgres:17-alpine", "gitea/gitea:1.22", "ghcr.io/mailu/admin:1.9",
|
|
"registry.example:5000/novox/www:latest",
|
|
// A registry host in front of one of our names does NOT make it ours: it says somebody
|
|
// published it, so the machine can fetch it from there like anything else.
|
|
"registry.example:5000/mesh-control:development",
|
|
]) {
|
|
assert.ok(!isMeshBuilt(theirs), `${theirs} is not ours and was claimed`);
|
|
}
|
|
});
|
|
|
|
// The case this exists for: an image the mesh builds has no digest until it is built, so a
|
|
// manifest ships sixty-four zeros and would stop on the machine (novox/hq 04-ISSUES/025).
|
|
test("a placeholder for one of our own images becomes the image the machine holds", () => {
|
|
const before = `"image": "mesh-runtime-postgres@sha256:${"0".repeat(64)}"`;
|
|
const after = pinnedInto(before, HELD);
|
|
assert.equal(after, `"image": "sha256:${"b".repeat(64)}"`);
|
|
assert.deepEqual(stillUnpinned(after), []);
|
|
});
|
|
|
|
/**
|
|
* **The heart of it.** A third-party reference is not touched.
|
|
*
|
|
* It used to be rewritten to whatever the lab's registry assigned, which meant the bed never once
|
|
* fetched an image the way a real machine does — and every bootstrap fault that depended on that
|
|
* went unfound.
|
|
*/
|
|
test("a third-party image is left exactly as the manifest wrote it", () => {
|
|
for (const reference of [
|
|
`postgres@sha256:${"7".repeat(64)}`,
|
|
`gitea/gitea@sha256:${"8".repeat(64)}`,
|
|
`ghcr.io/mailu/admin@sha256:${"9".repeat(64)}`,
|
|
`registry.example:5000/novox/www:latest`,
|
|
]) {
|
|
const before = `"image": "${reference}"`;
|
|
assert.equal(pinnedInto(before, HELD), before, `${reference} was rewritten`);
|
|
}
|
|
});
|
|
|
|
test("a reference of ours that already carries a registry is still redirected", () => {
|
|
// What the committed substrate bundle looks like: written for a target that had a registry.
|
|
const before = `"image": "192.0.2.250:5000/mesh-control@sha256:${"e".repeat(64)}"`;
|
|
assert.equal(pinnedInto(before, HELD), `"image": "sha256:${"a".repeat(64)}"`);
|
|
});
|
|
|
|
// A longer repository ending in a shorter one must not be half-replaced.
|
|
test("a repository that ends in another one is not partly rewritten", () => {
|
|
const before = `"image": "our-mesh-control@sha256:${"7".repeat(64)}"`;
|
|
assert.equal(pinnedInto(before, HELD), before,
|
|
"'our-mesh-control' was rewritten because it ends in 'mesh-control'");
|
|
});
|
|
|
|
test("every image in a whole manifest is settled at once", () => {
|
|
const manifest = JSON.stringify({
|
|
resources: [
|
|
{ id: "db", image: `postgres@sha256:${"1".repeat(64)}` },
|
|
{ id: "runtime", image: `mesh-runtime-postgres@sha256:${"0".repeat(64)}` },
|
|
{ id: "proxy", image: `mesh-route-proxy@sha256:${"0".repeat(64)}` },
|
|
{ id: "app", image: `gitea/gitea@sha256:${"2".repeat(64)}` },
|
|
],
|
|
});
|
|
const after = pinnedInto(manifest, HELD);
|
|
assert.deepEqual(stillUnpinned(after), []);
|
|
assert.ok(after.includes(`sha256:${"b".repeat(64)}`), after);
|
|
assert.ok(after.includes(`sha256:${"c".repeat(64)}`), after);
|
|
// And the two that are not ours are still whole, digest and all.
|
|
assert.ok(after.includes(`postgres@sha256:${"1".repeat(64)}`), after);
|
|
assert.ok(after.includes(`gitea/gitea@sha256:${"2".repeat(64)}`), after);
|
|
});
|
|
|
|
test("what a repository is held under can be asked for, and absence is not an empty string", () => {
|
|
assert.equal(referenceFor(HELD, "mesh-control"), `sha256:${"a".repeat(64)}`);
|
|
assert.equal(referenceFor(HELD, "mesh-runtime-plex"), undefined);
|
|
});
|
|
|
|
test("what is still a placeholder can be named", () => {
|
|
const text = `"image": "something-of-ours@sha256:${"0".repeat(64)}"`;
|
|
assert.deepEqual(stillUnpinned(text), ["something-of-ours"]);
|
|
});
|