Check an image's Dockerfile place instead of refusing the image kind (ADR 0487 clause 13)
mesh/check failed: unit: i3/cmd/i3-tools.TestTheMainFileAndEveryModulesContributionLoadTogether: manifest_test.go:247: expected the launcher, clipboar…
mesh/delivery-group group feat/r4d rejected: a member's own check failed
mesh/merge-gate waits for its group's composed check
mesh/repo-check head 707bfba4ea36 merged into trunk 4463991e0609 beside mesh-catalog#434@68183ee4 — fail: its merge-check.sh failed: --- FAIL: TestTheBusTh…
mesh/delivery superseded: a newer head of the same pull request
mesh/check failed: unit: i3/cmd/i3-tools.TestTheMainFileAndEveryModulesContributionLoadTogether: manifest_test.go:247: expected the launcher, clipboar…
mesh/delivery-group group feat/r4d rejected: a member's own check failed
mesh/merge-gate waits for its group's composed check
mesh/repo-check head 707bfba4ea36 merged into trunk 4463991e0609 beside mesh-catalog#434@68183ee4 — fail: its merge-check.sh failed: --- FAIL: TestTheBusTh…
mesh/delivery superseded: a newer head of the same pull request
This commit is contained in:
@@ -0,0 +1,92 @@
|
||||
package ownmanifest
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// imagesOutOfPlace lists the image artifacts among manifests (module name to its manifest's text) whose Dockerfile
|
||||
// is not a file inside that module's own directory, root/<module> (novox/hq ADR 0487 clause 13, which replaced the
|
||||
// refusal of the image kind of ADR 0480 clause 11). The image builder builds a module from its directory alone.
|
||||
// It reads the manifest as plain JSON, since the catalogue parser refuses some of these itself. It mirrors mesh-catalog's checks/imageplace: an empty from, an absolute one, one leaving the directory with ..,
|
||||
// or a name that is no file there, is refused.
|
||||
func imagesOutOfPlace(t *testing.T, root string, manifests map[string][]byte) []string {
|
||||
t.Helper()
|
||||
var out []string
|
||||
for module, raw := range manifests {
|
||||
var m struct {
|
||||
Build struct {
|
||||
Artifacts []struct{ Name, Kind, From string } `json:"artifacts"`
|
||||
} `json:"build"`
|
||||
}
|
||||
if err := json.Unmarshal(raw, &m); err != nil {
|
||||
t.Fatalf("%s does not parse: %v", module, err)
|
||||
}
|
||||
for _, a := range m.Build.Artifacts {
|
||||
if a.Kind != "image" {
|
||||
continue
|
||||
}
|
||||
clean := filepath.Clean(a.From)
|
||||
bad := a.From == "" || filepath.IsAbs(clean) || clean == ".." || strings.HasPrefix(clean, ".."+string(filepath.Separator))
|
||||
if !bad {
|
||||
info, err := os.Stat(filepath.Join(root, module, clean))
|
||||
bad = err != nil || info.IsDir()
|
||||
}
|
||||
if bad {
|
||||
out = append(out, module+" ("+a.Name+" from "+a.From+")")
|
||||
}
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// Every image a module of this repository declares is built from a Dockerfile in the module's own directory
|
||||
// (novox/hq ADR 0487 clause 13). The catalogue's own modules are held to the same by checks/imageplace in mesh-catalog.
|
||||
func TestEveryImageArtifactBuildsFromADockerfileInItsOwnModuleDirectory(t *testing.T) {
|
||||
root := filepath.Join("..", "..", "modules")
|
||||
paths, err := filepath.Glob(filepath.Join(root, "*", "module.json"))
|
||||
if err != nil || len(paths) == 0 {
|
||||
t.Fatalf("no module manifests found in this repository's modules: %v", err)
|
||||
}
|
||||
manifests := map[string][]byte{}
|
||||
for _, p := range paths {
|
||||
raw, err := os.ReadFile(p)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
manifests[filepath.Base(filepath.Dir(p))] = raw
|
||||
}
|
||||
if got := imagesOutOfPlace(t, root, manifests); len(got) != 0 {
|
||||
t.Errorf("these image artifacts do not build from a Dockerfile in their own module's directory "+
|
||||
"(ADR 0487 clause 13): %v", got)
|
||||
}
|
||||
}
|
||||
|
||||
// The check fails on each bad case and passes on a good one, so it holds something.
|
||||
func TestAnImageWhoseDockerfileIsOutOfPlaceIsFoundAndOneInPlaceIsNot(t *testing.T) {
|
||||
root := t.TempDir()
|
||||
if err := os.MkdirAll(filepath.Join(root, "x", "sub"), 0o755); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for _, f := range []string{"x/Dockerfile", "x/sub/Dockerfile", "outside"} {
|
||||
if err := os.WriteFile(filepath.Join(root, f), nil, 0o644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
manifest := func(from string) map[string][]byte {
|
||||
return map[string][]byte{"x": []byte(`{"module":"x","version":"1","build":{"artifacts":[{"name":"server","kind":"image","from":"` + from + `"}]}}`)}
|
||||
}
|
||||
for _, from := range []string{"Dockerfile", "sub/Dockerfile", "./Dockerfile"} {
|
||||
if got := imagesOutOfPlace(t, root, manifest(from)); len(got) != 0 {
|
||||
t.Errorf("from %q: found %v, want none", from, got)
|
||||
}
|
||||
}
|
||||
for _, from := range []string{"", "/etc/Dockerfile", "../outside", "..", "sub/../../outside", "Missing", "sub"} {
|
||||
if got := imagesOutOfPlace(t, root, manifest(from)); len(got) != 1 {
|
||||
t.Errorf("from %q: found %v, want it refused", from, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,69 +0,0 @@
|
||||
package ownmanifest
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"git.novox.be/novox/mesh-sdk/go/catalogue"
|
||||
)
|
||||
|
||||
// builderThatStillBuildsAnImage is the one builder allowed an image built from a Dockerfile until R4g removes it
|
||||
// (novox/hq ADR 0480 clause 11, ADR 0453 §10, ADR 0452 §1).
|
||||
const builderThatStillBuildsAnImage = "build-agent"
|
||||
|
||||
// imageArtifactModules lists the modules among manifests (module name to its manifest's text) that declare an
|
||||
// artifact of kind image, apart from the one builder allowed it.
|
||||
func imageArtifactModules(t *testing.T, manifests map[string][]byte) []string {
|
||||
t.Helper()
|
||||
var out []string
|
||||
for module, raw := range manifests {
|
||||
if module == builderThatStillBuildsAnImage {
|
||||
continue
|
||||
}
|
||||
m, err := catalogue.ParseManifest(raw)
|
||||
if err != nil {
|
||||
t.Fatalf("%s does not parse: %v", module, err)
|
||||
}
|
||||
if m.Build == nil {
|
||||
continue
|
||||
}
|
||||
for _, a := range m.Build.Artifacts {
|
||||
if a.Kind == "image" {
|
||||
out = append(out, module+" ("+a.Name+")")
|
||||
}
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// Every module of this repository but build-agent runs an upstream image with its program mounted in, so none
|
||||
// declares an image built from a Dockerfile (novox/hq ADR 0480 clause 11). The catalogue's own modules are held to
|
||||
// the same by a test in mesh-catalog.
|
||||
func TestNoModuleManifestButBuildAgentsDeclaresAnImage(t *testing.T) {
|
||||
paths, err := filepath.Glob(filepath.Join("..", "..", "modules", "*", "module.json"))
|
||||
if err != nil || len(paths) == 0 {
|
||||
t.Fatalf("no module manifests found in this repository's modules: %v", err)
|
||||
}
|
||||
manifests := map[string][]byte{}
|
||||
for _, p := range paths {
|
||||
raw, err := os.ReadFile(p)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
manifests[filepath.Base(filepath.Dir(p))] = raw
|
||||
}
|
||||
if got := imageArtifactModules(t, manifests); len(got) != 0 {
|
||||
t.Errorf("these modules declare an artifact of kind image, which only %s may until R4g (ADR 0480 clause 11, "+
|
||||
"ADR 0452 §1): %v. Ship the program as a Go bundle or an archive on an upstream image",
|
||||
builderThatStillBuildsAnImage, got)
|
||||
}
|
||||
}
|
||||
|
||||
// The test fails on a manifest with an image artifact, so it holds something.
|
||||
func TestAnImageArtifactIsFoundInAnyModuleButBuildAgents(t *testing.T) {
|
||||
image := []byte(`{"module":"x","version":"1","build":{"artifacts":[{"name":"server","kind":"image","from":"Dockerfile"}]}}`)
|
||||
if got := imageArtifactModules(t, map[string][]byte{"x": image, builderThatStillBuildsAnImage: image}); len(got) != 1 || got[0] != "x (server)" {
|
||||
t.Fatalf("found %v, want only x (server)", got)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user