Files
mesh-lab/test/pinning.test.ts
T
jschoubben 6c09ddb528 An image the machine has no account for is handed over, not fetched
Deleting the lab's registry left the operator's own images to be pulled like
anything else, and they cannot be: their registry wants an account and a
scenario machine has none. The pull fails with 'no basic auth credentials',
which is not something more patience fixes.

So the test is no longer 'did the mesh build it' but 'can the machine get it at
all'. Two ways to fail that — published nowhere, or published somewhere the
machine cannot authenticate to — and one consequence: the workstation, which
does hold the credential, exports it and loads it.

Worth saying what this stands in for. In a finished mesh these are built by the
builder and published to the mesh's own store, and every machine pulls them from
there with a credential the mesh granted. Until that store exists there is
nowhere for them to come from, and handing them over is the closest honest thing
— not a registry the lab invents, which is what was just removed.

Claude-Session: https://claude.ai/code/session_01LrgweAeERJYBg88c5cKDzF
2026-09-11 01:11:18 +02:00

165 lines
7.0 KiB
TypeScript

import { test } from "node:test";
import assert from "node:assert/strict";
import {
isMeshBuilt, mustBeHandedOver, 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"]);
});
/**
* An image a machine cannot fetch by itself has to be handed to it, and there are two ways to be in
* that position: built here and published nowhere, or sitting in a registry the machine has no
* account for. The second was found by deleting the lab's registry — the operator's own images
* failed with `no basic auth credentials`, which no amount of retrying improves.
*/
test("an image the machine cannot fetch by itself is handed over", () => {
for (const handed of [
"mesh-control:development",
"mesh-runtime-plex:development",
`registry.example/novox/www@sha256:${"a".repeat(64)}`,
"registry.example:5000/novox/photos-server:latest",
]) {
assert.ok(mustBeHandedOver(handed), `${handed} cannot be fetched and was not handed over`);
}
for (const fetched of [
"postgres:17-alpine",
"gitea/gitea:1.22",
"ghcr.io/mailu/admin:1.9",
"quay.io/keycloak/keycloak:26",
"lscr.io/linuxserver/sonarr:latest",
"mcr.microsoft.com/mssql/server:2022-latest",
]) {
assert.ok(!mustBeHandedOver(fetched), `${fetched} can be fetched and was handed over anyway`);
}
});