Check an image's Dockerfile place instead of refusing the image kind (ADR 0487 clause 13)
mesh/delivery-group group feat/r4d checking: composed check out of date: novox/mesh-catalog@c948f3a61c74 was judged against trunk 848249cf54b6, the trunk is no…
mesh/merge-gate waits for its group's composed check
mesh/repo-check head cff5ed46b794 merged into trunk 529c156f6407 beside mesh-controller#433@707bfba4 — pass: THE CHANGE ALTERS ITS OWN CHECK (merge-check.s…
mesh/delivery superseded: a newer head of the same pull request
mesh/check failed: unit: modules/gitea.test: [gitea] where the poll of merges last looked from could not be read, so none is kept — no runtime | cff5e…

This commit is contained in:
2026-10-22 11:44:45 +02:00
parent 7451e7edf4
commit cff5ed46b7
5 changed files with 4 additions and 139 deletions
-3
View File
@@ -1,3 +0,0 @@
module git.novox.be/novox/mesh-catalog/checks/images
go 1.22
-80
View File
@@ -1,80 +0,0 @@
// Command images refuses any manifest but build-agent's declaring an artifact of kind `image`, an image built from a
// Dockerfile (novox/hq ADR 0452 clause 1, ADR 0480 clause 11 as ADR 0487 clause 13 changed it). From R4d a module
// runs a pinned upstream image with its programs mounted in; build-agent is the one builder that still builds an
// image until R4g, when the catalogue refuses the kind outright (issue 1619) and this check goes with it.
//
// go run . <catalogue root>
//
// Exits 1 on a finding.
package main
import (
"encoding/json"
"fmt"
"os"
"path/filepath"
"sort"
)
// Exempt is the one module still allowed to declare the kind, until R4g.
var Exempt = map[string]bool{"build-agent": true}
// Finding is one refusal: Module's artifact Artifact is an image built from a Dockerfile.
type Finding struct{ Module, Artifact string }
// Check reads every manifest under root/modules and answers what it refuses.
func Check(root string) ([]Finding, error) {
manifests, err := filepath.Glob(filepath.Join(root, "modules", "*", "module.json"))
if err != nil {
return nil, err
}
sort.Strings(manifests)
var out []Finding
for _, path := range manifests {
raw, err := os.ReadFile(path)
if err != nil {
return nil, err
}
var m struct {
Module string `json:"module"`
Build struct {
Artifacts []struct {
Name string `json:"name"`
Kind string `json:"kind"`
} `json:"artifacts"`
} `json:"build"`
}
if err := json.Unmarshal(raw, &m); err != nil {
return nil, fmt.Errorf("%s: %w", path, err)
}
if Exempt[m.Module] {
continue
}
for _, a := range m.Build.Artifacts {
if a.Kind == "image" {
out = append(out, Finding{Module: m.Module, Artifact: a.Name})
}
}
}
return out, nil
}
func main() {
root := "."
if len(os.Args) > 1 {
root = os.Args[1]
}
found, err := Check(root)
if err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
for _, f := range found {
fmt.Printf("%s declares the artifact %s as an image built from a Dockerfile: run a pinned upstream image with the "+
"module's programs mounted in (novox/hq ADR 0452 clause 1, ADR 0480 clause 11)\n", f.Module, f.Artifact)
}
if len(found) > 0 {
os.Exit(1)
}
fmt.Println("images: no module but build-agent builds an image from a Dockerfile")
}
-51
View File
@@ -1,51 +0,0 @@
package main
import (
"os"
"path/filepath"
"reflect"
"testing"
)
func catalogue(t *testing.T, manifests map[string]string) string {
t.Helper()
root := t.TempDir()
for name, body := range manifests {
dir := filepath.Join(root, "modules", name)
if err := os.MkdirAll(dir, 0o755); err != nil {
t.Fatal(err)
}
if err := os.WriteFile(filepath.Join(dir, "module.json"), []byte(body), 0o644); err != nil {
t.Fatal(err)
}
}
return root
}
// A fixture manifest with an image artifact is refused, the builder's is not, and an upstream image is no image.
func TestOnlyBuildAgentMayDeclareAnImageBuiltFromADockerfile(t *testing.T) {
root := catalogue(t, map[string]string{
"old": `{"module":"old","build":{"artifacts":[{"name":"server","kind":"image","from":"Dockerfile"}]}}`,
"build-agent": `{"module":"build-agent","build":{"artifacts":[{"name":"agent","kind":"image","from":"Dockerfile"}]}}`,
"new": `{"module":"new","build":{"artifacts":[{"name":"server","kind":"upstream","from":"alpine@sha256:00"},{"name":"p","kind":"bundle"}]}}`,
"none": `{"module":"none"}`,
})
got, err := Check(root)
if err != nil {
t.Fatal(err)
}
if want := []Finding{{Module: "old", Artifact: "server"}}; !reflect.DeepEqual(got, want) {
t.Errorf("found %v, want %v", got, want)
}
}
// The catalogue this check lives in passes it.
func TestTheCatalogueDeclaresNoImage(t *testing.T) {
got, err := Check("../..")
if err != nil {
t.Fatal(err)
}
if len(got) > 0 {
t.Errorf("the catalogue declares %v", got)
}
}
-2
View File
@@ -57,8 +57,6 @@ set -eu
(cd checks/words && go test -count=1 . && go run . ../..)
# The toolchains (novox/hq ADR 0477 clause 4): the package go only in modules/go, nodejs and npm only in modules/nodejs.
(cd checks/toolchains && go test -count=1 . && go run . ../..)
# The image (novox/hq ADR 0480 clause 11): no manifest but build-agent's declares an image built from a Dockerfile.
(cd checks/images && go test -count=1 . && go run . ../..)
# The image builder (novox/hq ADR 0487 §3): only modules/buildah provides rootless-image-build, docker never.
(cd checks/imagebuild && go test -count=1 . && go run . ../..)
# The image's place (novox/hq ADR 0487 §1): every image builds from a Dockerfile in its own module's directory.
+4 -3
View File
@@ -107,8 +107,9 @@ func TestAutomxIsAGoBundleForAlpineMountedAtOptMeshAndRestartedWithIt(t *testing
}
}
// Clause 3: an upstream artifact pinned by digest, the one route-proxy's trust artifact runs; never an image
// built from a Dockerfile (clause 11), and no Dockerfile or base to build one on.
// Clause 3: an upstream artifact pinned by digest, the one route-proxy's trust artifact runs. automx's own design
// builds no image from a Dockerfile and has no Dockerfile or base to build one on; the catalogue as such does not
// refuse the image kind (novox/hq ADR 0487 clause 13).
func TestAutomxRunsTheMirroredAlpineImageAndBuildsNoImage(t *testing.T) {
m := readManifest(t)
c := m.resource("automx")
@@ -121,7 +122,7 @@ func TestAutomxRunsTheMirroredAlpineImageAndBuildsNoImage(t *testing.T) {
}
for _, a := range m.Build["artifacts"].([]any) {
if a.(map[string]any)["kind"] == "image" {
t.Errorf("artifact %v is an image built from a Dockerfile (ADR 0452)", a)
t.Errorf("artifact %v is an image built from a Dockerfile, which automx's design (ADR 0480) does not use", a)
}
}
if _, has := m.Build["on"]; has {