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…
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:
@@ -1,3 +0,0 @@
|
||||
module git.novox.be/novox/mesh-catalog/checks/images
|
||||
|
||||
go 1.22
|
||||
@@ -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")
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
@@ -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.
|
||||
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user