Pin the example modules to images that exist
novox/hq 04-ISSUES/025. Every image reference in every example module was sixty-four zeros — eighteen of them across five modules. Each parsed, resolved, and composed into a declaration a host accepts, and none could ever have started: the machine reaches `docker pull` and stops. That is why those modules were written and not running, and no check saw it because every check passed. The host validates the shape of a reference and nothing more, which is correct: verifying a digest exists means reaching a registry, and that is the one thing a host must never have to do. So the last place that could catch this is the wrong place to try. The guard therefore sits where a declaration is composed, not where a manifest is parsed. A file in a repository is allowed to await a pin — the design already says the manifest in a repository names artifacts while the manifest the mesh holds names digests, and the bundle works exactly that way. What must never happen is a placeholder reaching a machine, and composing is the last moment before one does. Twelve third-party images resolved to real digests without pulling anything, which is also the mechanism the open issue needs. Two discoveries came free: mailu publishes to ghcr rather than Docker Hub, so seven references named repositories that do not exist at all; and it renamed roundcube to webmail, so that one would have failed even with the right registry. What stays a placeholder is the mesh's own provisioner images, which genuinely have no digest until built and pushed — the bundle's problem, legitimately unresolved here. The stand-in consumer now stands in with a real image rather than an invented one.
This commit is contained in:
@@ -342,6 +342,9 @@ func (r Resolution) Declaration(with Rendering) ([]map[string]any, error) {
|
||||
if err := boundInto(copied, known, m.Module); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := pinned(copied, m.Module); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
copied["id"] = m.Module + "." + fmt.Sprint(resource["id"])
|
||||
// A service saying what it reflects names resources within its own module, so those
|
||||
// are prefixed too or they would point at nothing.
|
||||
@@ -638,3 +641,29 @@ func withMeshNames(resources []map[string]any, names map[string]string) []map[st
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// pinned refuses an image that is not really pinned, on its way to a machine.
|
||||
//
|
||||
// **Here and not at parse** (novox/hq 04-ISSUES/025). A manifest in a repository names artifacts
|
||||
// and the manifest the mesh holds names digests — they are deliberately not the same document, so
|
||||
// a file awaiting a pin is legitimate exactly as the bundle's is. What must never happen is a
|
||||
// placeholder reaching a machine, and this is the last moment before one does.
|
||||
//
|
||||
// The host checks only the *shape* of a reference, and cannot do more: verifying a digest exists
|
||||
// means reaching a registry, which is the one thing a host must never have to do. So sixty-four
|
||||
// zeros satisfies every gate in the system and stops on the machine at `docker pull` — which is
|
||||
// how eighteen of them shipped across five modules that parse, resolve and compose cleanly.
|
||||
func pinned(resource map[string]any, module string) error {
|
||||
image, ok := resource["image"].(string)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
_, digest, found := strings.Cut(image, "@")
|
||||
if !found || strings.Trim(strings.TrimPrefix(digest, "sha256:"), "0") != "" {
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf(
|
||||
"%s would send %v to a machine pinned to a placeholder digest, which is never a real "+
|
||||
"image — it would be fetched and fail there. Resolve the tag to a digest first",
|
||||
module, resource["id"])
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user