ADR 0097: a vendor image is a declared build input; issue 064's image half decided; design 18 amended

This commit is contained in:
2026-09-21 20:45:36 +02:00
parent 8d981e21b1
commit 71072e240d
4 changed files with 74 additions and 2 deletions
@@ -0,0 +1,59 @@
---
topic: building it
status: accepted
date: 2026-09-21
deciders: jochen
reconstructed: false
extends: 02-DECISIONS/0096-an-upstream-image-is-copied-between-registries.md
---
# 97. A vendor image is a declared build input, and a recipe fetches nothing undeclared
## Context
Three modules could not be built by the mesh's builder because their recipes reached for what
no manifest named: a public package, or a binary copied out of a public image
([issue 064](../04-ISSUES/064-a-mesh-build-cannot-fetch-a-modules-external-dependencies/00-report.md)).
A module already names the bases it stands on — another module's artifact, by name — and the
builder answers with what the mesh holds; a vendor's image had no such declaration, so a recipe
named it directly and the build worked when the public registry answered, which is sometimes.
## Considered Options
1. **Let the build environment reach public registries.** Rejected: a build that fetches from
somebody else's registry on its own is one the mesh cannot rebuild the same way twice.
2. **A vendor image is a base like any other**, declared under `build.on` with the argument the
recipe reads it from, pinned by digest, copied into the mesh's registry before the build
([ADR 0096](0096-an-upstream-image-is-copied-between-registries.md)). Adopted.
## Decision
A build's `on` entry is either a module's artifact or an image published elsewhere, pinned by
digest, read from one build argument. Before the build the image is copied into the mesh's
registry under the module's repository and the recipe is handed the copy; genesis, with no
registry, pulls it into the first machine's store. A recipe whose `FROM` or `COPY --from` names a
registry image the manifest did not declare is refused before the build, naming the image and
the remedy; its own stages, declared arguments and `scratch` are not fetches. An unpinned vendor
image is refused: a tag is what somebody else can move.
The package half of the issue is not decided here: the mesh's package registry already proxies
the public one, and the failure the report saw has to be run again to be placed.
## Consequences
A module's build inputs are all in its manifest, and every one of them is something the mesh
holds a copy of. What got harder: a recipe that used to name a base image on its first line now
names an argument, and the manifest names the image.
## How it is checked
A builder test declares a pinned vendor image, asserts it is copied under the module's
repository and handed to the recipe as the argument, and asserts an unpinned one is refused. A
recipe test asserts an undeclared `FROM`, an undeclared `COPY --from` and an undeclared argument
are named, and that stages, declared arguments and `scratch` are not.
## References
- [issue 064](../04-ISSUES/064-a-mesh-build-cannot-fetch-a-modules-external-dependencies/00-report.md)
- [ADR 0096](0096-an-upstream-image-is-copied-between-registries.md)
- [`03-DESIGN/01-to-be/18-building-a-module.md`](../03-DESIGN/01-to-be/18-building-a-module.md)
+1
View File
@@ -162,6 +162,7 @@ python3 00-META/checks/index.py fail if stale
- **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)
- **0097** — [A vendor image is a declared build input, and a recipe fetches nothing undeclared](0097-a-vendor-image-is-a-declared-build-input.md)
### How it is checked