A registry inside the scenario: the mechanism, verified

Issue 009's resolution, proven manually end to end before any of it was
written.

A sealed machine pulled an image BY DIGEST from a registry on its own segment
and ran it; then the host applied all four shapes -- package, service with
boot, container from that digest, and an action inside it -- idempotently. That
is the first time the container shape has worked anywhere but a workstation,
and it was the shape blocking the whole substrate bootstrap.

The registry's digests are its own, not Docker Hub's, and that is correct
rather than a compromise: ADR 0046 requires a reference that is exact and
cannot move, and a digest this registry assigned is both. It is also not a
lab workaround -- 0048 names an OCI registry as substrate and 0046 says a first
node fetches "upstream, wherever the image ordinarily lives". This IS that
upstream, scenery in the same sense the transit router is the internet.

The base image now trusts the RFC 5737 and RFC 3849 documentation ranges as
plain-HTTP registries. Scoped to those rather than an address because they
never route on the real internet, so it cannot make a real machine trust a real
registry whatever it is copied onto.

Three faults found while verifying, two of them mine:

My probe script picked an interface with `ls /sys/class/net | head -1`, which
returns docker0 once a runtime exists -- so it addressed the wrong interface and
then, because that address overlapped the segment, broke routing on the machine
entirely. The lab itself is immune: it matches by MAC, for a related reason it
already recorded (bus-position naming on multi-homed machines).

And a test that proved nothing: I asserted `sha256:tooshort` is rejected, but
its letters fall outside a-f, so it failed the character class rather than the
length check. Replaced with hex of the wrong length, after which removing the
length check bites.
This commit is contained in:
2026-08-28 02:18:35 +02:00
parent d6eef25590
commit 37c6a0ba21
3 changed files with 278 additions and 0 deletions
+66
View File
@@ -0,0 +1,66 @@
import { test } from "node:test";
import assert from "node:assert/strict";
import { digestFrom, pinnedReference, registryAddress, repositoryFor } from "../src/lifecycle/registry.ts";
/**
* The registry inside a scenario (novox/hq 04-ISSUES/009).
*
* These test the pure parts. The parts that need a registry are exercised by raising a
* scenario, because a fake registry would assert that the fake behaves as expected
* (novox/hq ADR 0034).
*/
test("a digest is read from what the registry actually said", () => {
// The real shape of `docker push` output. The digest here is the REGISTRY's, not Docker
// Hub's, and that is the point: a declaration pins what this registry serves.
const output =
"The push refers to repository [localhost:5000/alpine]\n" +
"63f227048c13: Pushed\n" +
"3.20: digest: sha256:6c2a9711b0a9f32b0239d9222eb1072309cf46c6431d319ae249186d811a987c size: 528\n";
assert.equal(
digestFrom(output),
"sha256:6c2a9711b0a9f32b0239d9222eb1072309cf46c6431d319ae249186d811a987c",
);
});
test("no digest is not an empty digest", () => {
// A push that reported no digest leaves nothing for a declaration to pin, and inventing one
// would be worse than failing — the host would refuse it later, further from the cause.
assert.equal(digestFrom("The push refers to repository [localhost:5000/alpine]\n"), null);
assert.equal(digestFrom(""), null);
// Hex, but the wrong LENGTH. An earlier version used "tooshort", whose letters fall outside
// a-f — so it failed the character class and proved nothing about the length check.
assert.equal(digestFrom("digest: sha256:abc123"), null);
assert.equal(digestFrom("digest: sha256:" + "a".repeat(63)), null, "63 is not 64");
});
test("the repository is the reference without its tag", () => {
assert.equal(repositoryFor("alpine:3.20"), "alpine");
assert.equal(repositoryFor("alpine"), "alpine");
assert.equal(repositoryFor("library/postgres:17"), "library/postgres");
// A port in a hostname is a colon that is NOT a tag, and treating it as one would serve the
// image from a truncated path.
assert.equal(repositoryFor("localhost:5000/alpine:3.20"), "localhost:5000/alpine");
assert.equal(repositoryFor("localhost:5000/alpine"), "localhost:5000/alpine");
});
test("the registry's address is derived from its segment", () => {
assert.equal(registryAddress("192.0.2.0/24"), "192.0.2.250");
assert.equal(registryAddress("198.51.100.0/24"), "198.51.100.250");
// An IPv6-only segment cannot host it, and saying so beats producing an address nothing
// can be pointed at.
assert.throws(() => registryAddress("2001:db8:a::/48"), /not an IPv4 network/);
});
test("what a declaration pins is the registry's own digest", () => {
// Not Docker Hub's. ADR 0046 requires a reference that is exact and cannot move, and a
// digest this registry assigned is both.
const pinned = pinnedReference("192.0.2.250", {
requested: "alpine:3.20",
repository: "alpine",
digest: "sha256:" + "6".repeat(64),
});
assert.equal(pinned, `192.0.2.250:5000/alpine@sha256:${"6".repeat(64)}`);
assert.ok(pinned.includes("@sha256:"), "the host refuses anything not pinned by digest");
assert.ok(!pinned.includes(":3.20"), "a tag would move; the digest is what is pinned");
});