An example may not name an image nothing builds

Found by reading the manifests rather than by running them. Two of the
provisioner images the examples name had no way to be produced: the
object store's had a Dockerfile and no target, and Keycloak's did not
exist at all — no image, no Dockerfile, no program.

A module naming an image nothing produces resolves, plans, pushes and
stops on the machine at `docker pull`, which is the fault arriving as
far from its cause as it can get.

The object store's target is added. Keycloak's provisioner is removed
from its manifest, because writing a manifest for a program that does
not exist is the same mistake as the .env files: it parses, it resolves,
and it could never work.

That makes keycloak's manifest true about today — a server the mesh
runs, with its database and its admin credential — and it makes the gap
loud. Keycloak no longer claims to provide oidc-client, so a consumer
asking for one is refused at plan time by name, rather than resolving
cleanly and never having a client created.

The check covers only images beginning `mesh-`. Postgres and the rest
come from a registry and are somebody else's to build; what this bounds
is the set this repository is responsible for and might forget.
This commit is contained in:
2026-09-01 03:12:49 +02:00
parent e5243cd753
commit a4090014f3
3 changed files with 55 additions and 26 deletions
+11
View File
@@ -53,6 +53,17 @@ provisioner-image:
@echo
@docker image inspect $(PROVISIONER_IMAGE) --format 'built {{.RepoTags}} {{.Size}} bytes'
# The object store's provisioner, for the same reason: a bucket and a policy are not files, and
# the mesh cannot make them -- it discarded the credential it would have to use.
OBJECTSTORE_IMAGE ?= mesh-provision-objectstore:$(VERSION)
OBJECTSTORE_DEV_TAG ?= mesh-provision-objectstore:development
objectstore-image:
docker build -f examples/objectstore-provisioner/Dockerfile \
-t $(OBJECTSTORE_IMAGE) -t $(OBJECTSTORE_DEV_TAG) .
@echo
@docker image inspect $(OBJECTSTORE_IMAGE) --format 'built {{.RepoTags}} {{.Size}} bytes'
# The proxy that turns a route grant into traffic reaching a workload.
PROXY_IMAGE ?= mesh-route-proxy:$(VERSION)
PROXY_DEV_TAG ?= mesh-route-proxy:development
+1 -26
View File
@@ -9,7 +9,6 @@
"binds": {"postgres-database": "/var/lib/keycloak/database.json"},
"secrets": {"postgres-database": "/var/lib/keycloak/database.secret"},
"provides": [{"name": "oidc-client", "scope": "mesh"}],
"capabilities": ["container-runtime"],
"listens": [
@@ -17,18 +16,10 @@
"why": "anything the mesh runs that authenticates a person"}
],
"serves": {
"oidc-client": {"port": 8080, "realm": "mesh", "scheme": "http"}
},
"receives": {"oidc-client": "/var/lib/keycloak/grants/mesh.json"},
"grants": {"oidc-client": "/var/lib/keycloak/grants"},
"own-secrets": {"admin": "/var/lib/keycloak/admin.secret"},
"resources": [
{"id": "state", "type": "directory", "path": "/var/lib/keycloak", "mode": "0700"},
{"id": "grants", "type": "directory", "path": "/var/lib/keycloak/grants", "mode": "0700"},
{"id": "admin-env", "type": "file", "path": "/var/lib/keycloak/admin.env", "mode": "0600",
"content": "KEYCLOAK_ADMIN=admin\nKEYCLOAK_ADMIN_PASSWORD=${secret:admin}\n"},
@@ -45,22 +36,6 @@
"env": {"KC_DB": "postgres", "KC_HTTP_ENABLED": "true", "KC_HEALTH_ENABLED": "true"},
"env-file": ["/var/lib/keycloak/admin.env", "/var/lib/keycloak/database.env"],
"ports": ["8080:8080"],
"restart-on": ["admin-env", "database-env"]},
{"id": "provisioner", "type": "container", "name": "mesh-provision-keycloak",
"image": "mesh-provision-keycloak@sha256:0000000000000000000000000000000000000000000000000000000000000000",
"network": "keycloak",
"env": {
"GRANTS": "/var/lib/keycloak/grants",
"MESH_KEYCLOAK_URL": "http://keycloak:8080",
"MESH_KEYCLOAK_REALM": "mesh",
"MESH_KEYCLOAK_ADMIN": "admin",
"MESH_KEYCLOAK_ADMIN_PASSWORD_FILE": "/run/secrets/admin"
},
"volumes": [
"/var/lib/keycloak/grants:/var/lib/keycloak/grants:ro",
"/var/lib/keycloak/admin.secret:/run/secrets/admin:ro"
],
"restart-on": ["grants", "admin-env"]}
"restart-on": ["admin-env", "database-env"]}
]
}
+43
View File
@@ -462,3 +462,46 @@ func declareOnItsOwn(t *testing.T, shelf map[string]catalogue.Manifest,
}
return out
}
// Every image an example names is one this repository builds.
//
// A manifest naming an image nothing produces is a module that resolves, plans, pushes, and stops
// on the machine at `docker pull` — the fault arriving as far from its cause as it can get. Two of
// these were found by reading the manifests rather than by running them: the object store's
// provisioner had a Dockerfile and no target, and Keycloak's did not exist at all.
//
// Only the mesh's own images are checked. `postgres`, `redis` and the rest come from a registry
// and are somebody else's to build; what this bounds is the set this repository is responsible
// for and might forget.
func TestEveryImageTheExamplesNameIsOneThisRepositoryBuilds(t *testing.T) {
makefile, err := os.ReadFile(filepath.Join("..", "..", "Makefile"))
if err != nil {
t.Fatal(err)
}
found, _ := filepath.Glob("*.json")
var checked int
for _, name := range found {
for _, r := range read(t, name).Resources {
image, ok := r["image"].(string)
if !ok {
continue
}
repository, _, _ := strings.Cut(image, "@")
if !strings.HasPrefix(repository, "mesh-") {
continue
}
checked++
if !strings.Contains(string(makefile), repository+":") {
t.Errorf(
"%s names the image %q and nothing in this repository builds one. A module "+
"naming an image that does not exist resolves, plans, pushes, and stops "+
"on the machine at `docker pull`",
name, repository)
}
}
}
if checked == 0 {
t.Fatal("no example names an image this repository builds, so this proves nothing")
}
}