declaration: an image may be named by the digest of its own configuration
A manifest digest is assigned by a registry on push, so insisting on one meant a registry had to exist before the thing that lets a mesh have a registry could start — a dependency the pinning rule created by accident, not a pin. The mesh's own control plane is built from source and lives in no public registry. A bare sha256:... names an image the machine already holds, by the digest of its own configuration: immutable and unforgeable in exactly the way the rule asks for. Absent, it says so plainly rather than failing at a pull nothing serves. Claude-Session: https://claude.ai/code/session_01LrgweAeERJYBg88c5cKDzF
This commit is contained in:
@@ -874,20 +874,41 @@ func checkMode(where, mode string) []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
// checkImage insists on a digest.
|
||||
// checkImage insists on content, not on a name.
|
||||
//
|
||||
// A tag moves and a digest does not. The bundle's whole claim is that what it names is exact
|
||||
// (novox/hq ADR 0006), and a bundle pinning `postgres:17` pins nothing — it names whatever
|
||||
// that tag points at on the day the host happens to run.
|
||||
//
|
||||
// **Two forms say something exact, and only one of them needs a registry.** `name@sha256:…` is a
|
||||
// manifest digest, which a registry assigns on push. A bare `sha256:…` is an image the machine
|
||||
// already holds, addressed by the digest of its own configuration — equally immutable, equally
|
||||
// unforgeable, and requiring nothing to have served it.
|
||||
//
|
||||
// That second form is what a first machine needs. The mesh's own control plane exists in no public
|
||||
// registry and never will: it is built from source, and until this mesh has a registry of its own
|
||||
// there is nowhere to push it to and therefore no manifest digest to name it by. Insisting on one
|
||||
// would mean a registry has to exist before the thing that lets a mesh have a registry can start —
|
||||
// which is not a pin, it is a dependency the rule accidentally created. A machine that built an
|
||||
// image, or was handed one, can name it by what it is.
|
||||
func checkImage(where, image string) []string {
|
||||
if image == "" {
|
||||
return []string{where + ": a container needs an image"}
|
||||
}
|
||||
// An image this machine holds, named by the digest of its own configuration.
|
||||
if strings.HasPrefix(image, "sha256:") {
|
||||
if len(image) != len("sha256:")+64 {
|
||||
return []string{fmt.Sprintf(
|
||||
"%s: image id %q is not a sha256 digest", where, image)}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
name, digest, found := strings.Cut(image, "@")
|
||||
if !found || name == "" {
|
||||
return []string{fmt.Sprintf(
|
||||
"%s: image %q is not pinned. Write it as name@sha256:... — a tag moves, and a "+
|
||||
"bundle that pinned a tag would not be pinned", where, image)}
|
||||
"%s: image %q is not pinned. Write it as name@sha256:… — or as sha256:… for an image "+
|
||||
"this machine already holds. A tag moves, and a bundle that pinned a tag would "+
|
||||
"not be pinned", where, image)}
|
||||
}
|
||||
if !strings.HasPrefix(digest, "sha256:") || len(digest) != len("sha256:")+64 {
|
||||
return []string{fmt.Sprintf(
|
||||
|
||||
Reference in New Issue
Block a user