ADR 0096: an upstream image is copied between registries; issue 046 resolved; design 18 amended

This commit is contained in:
2026-09-21 20:43:07 +02:00
parent 39a01b7f7e
commit 8d981e21b1
5 changed files with 85 additions and 6 deletions
@@ -0,0 +1,63 @@
---
topic: building it
status: accepted
date: 2026-09-21
deciders: jochen
reconstructed: false
extends: 02-DECISIONS/0006-the-substrate-and-the-control-plane.md
---
# 96. An upstream image is copied between registries, never through a machine's image store
## Context
A module may declare that an artifact is an image published elsewhere, to be copied into the
mesh's own registry so machines fetch it by a digest this mesh assigned rather than by a name
somebody else controls. The builder pulled it into the build machine's image store and pushed it
under the mesh's name, and the push was refused: a published image is an index over several
architectures, the runtime's store keeps the index, and pushing one platform out of it fails
however the platform is asked for
([issue 046](../04-ISSUES/046-an-upstream-image-cannot-be-mirrored-into-the-mesh/00-report.md)).
Every variant of pull-then-push was tried and failed the same way.
## Considered Options
1. **Resolve the index to one platform and push that.** Tried, reverted: it did not make the
push work, and a workaround for a store's behaviour is a thing nobody removes later.
2. **Tooling that copies between registries**, installed on the build machine. Rejected: one
more thing the builder's image carries, for a protocol the builder already speaks for blobs.
3. **Copy over the registry API**, in the builder. Adopted.
## Decision
The builder copies an upstream image between registries and never through a machine's image
store: it reads the index and every manifest it names, moves each blob by digest into the mesh's
registry — skipping what is already there, since blobs are content-named — puts the manifests
and then the index under the module's repository, and pins the index's digest. Public images are
read with the anonymous bearer token the registry hands out on challenge, which is how the
public hub and the others the catalogue names serve them. The mesh mirrors the whole index, so
what a machine fetches is the image for its own architecture; that every machine on one mesh is
the same architecture is an assumption this mesh makes and had not written down until now.
Genesis has no registry to copy into and keeps the pull: the image stays in the first machine's
store, named by its own id, as every artifact does before there is anywhere to publish.
## Consequences
An upstream artifact builds. What got harder: the builder now holds a registry client of its
own, some two hundred lines, where a runtime command used to do; and a private upstream that
demands a credential is refused, since the copy is anonymous by design.
## How it is checked
A test raises a fake upstream registry serving an index over two platforms behind a bearer
challenge, and a fake mesh registry that records what arrives: every blob of both platforms
arrives once, two manifests and the index are put under their digests, the reference returned
pins the index under the module's repository, and a second copy uploads nothing. A reference
test reads names the way a runtime does.
## References
- [issue 046](../04-ISSUES/046-an-upstream-image-cannot-be-mirrored-into-the-mesh/00-report.md)
- [ADR 0006](0006-the-substrate-and-the-control-plane.md)
- [`03-DESIGN/01-to-be/18-building-a-module.md`](../03-DESIGN/01-to-be/18-building-a-module.md)
+1
View File
@@ -161,6 +161,7 @@ python3 00-META/checks/index.py fail if stale
- **0076** — [The SDK is a published package, and the toolchain resolves it by version](0076-the-sdk-is-a-published-package.md)
- **0082** — [The registry is reached by name, and the overlay is its security](0082-the-registry-is-reached-by-name-and-trusted-by-the-overlay.md)
- **0086** — [A secret reaches a process as a file, and an exception is declared](0086-a-secret-reaches-a-process-as-a-file.md)
- **0096** — [An upstream image is copied between registries, never through a machine's image store](0096-an-upstream-image-is-copied-between-registries.md)
### How it is checked
@@ -7,6 +7,7 @@ code:
- mesh-catalog modules/builder
updated: 2026-09-21
decisions:
- 02-DECISIONS/0096-an-upstream-image-is-copied-between-registries.md
- 02-DECISIONS/0091-a-mount-is-declared-three-ways.md
- 02-DECISIONS/0087-a-seeded-file-is-created-once.md
- 02-DECISIONS/0040-what-a-module-is.md
@@ -202,6 +203,18 @@ remedies, and a test parses every manifest in the catalogue beside the checkout.
| `image` | built from a Dockerfile — for software that needs a particular base |
| `upstream` | somebody else's image, mirrored and pinned by a digest this mesh assigned |
**An upstream image is copied between registries, never through a machine's image store**
([ADR 0096](../../02-DECISIONS/0096-an-upstream-image-is-copied-between-registries.md)). A
published image is an index over several architectures, and a runtime's store refuses to push
one platform out of an index it pulled. The builder reads the index and every manifest it names
over the registry API, moves each blob by digest into the mesh's registry, puts the manifests and
then the index under the module's repository, and pins the index — the whole image, so what a
machine fetches is the one for its own architecture. Public images are read with the anonymous
token a registry hands out on challenge; a private upstream is refused. *How it is checked:* a
test copies an index over two platforms from a fake registry behind a bearer challenge into a fake
mesh registry and asserts every blob arrived once, the manifests and index under their digests,
and nothing uploaded on a second copy.
### What it puts on a machine
| resource | is | a module may |
@@ -1,9 +1,9 @@
---
status: located
status: resolved
opened: 2026-09-14
located-in: [mesh-controller internal/builder (upstream artifacts)]
fixed-by:
amended-design:
fixed-by: ADR 0096; mesh-controller multiple-fixes (the builder copies the index and its manifests between registries over the registry API); proven by a test against a fake upstream serving an index over two platforms
amended-design: 03-DESIGN/01-to-be/18-building-a-module.md
---
# 046 — An upstream image cannot be mirrored into the mesh's own registry
@@ -12,6 +12,8 @@
than a limitation; today every machine on one mesh is the same architecture, and that
assumption is now written down here rather than nowhere.
**Located in:** the builder's upstream-artifact step. Not fixed here: a registry-to-registry copy
is a few hundred lines against the registry API and is proven only against a real registry
serving a real index, which is a lab run of its own.
**Located in:** the builder's upstream-artifact step. Fixed as
[ADR 0096](../../02-DECISIONS/0096-an-upstream-image-is-copied-between-registries.md): a copy over
the registry API, proven against a fake upstream serving an index over two platforms behind a
bearer challenge. A run against the public hub from a mesh's builder is the remaining proof, and
the first build of a module with an upstream artifact will be it.