Comments naming records that no longer exist now point at the consolidated record holding their reasoning -- the four lab records are 0016, a test defends a decision is 0017.
67 lines
3.2 KiB
TypeScript
67 lines
3.2 KiB
TypeScript
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 0017).
|
|
*/
|
|
|
|
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 0006 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");
|
|
});
|