mesh/merge-gate head 47ef2644aca1 merged into trunk e22326240833 — pass: builds build-agent, gitea → ace, g14, novox, shanks; no bus step; every machine co…
mesh/repo-check head 47ef2644aca1 merged into trunk e22326240833 — pass: its merge-check.sh passed, each part in its toolchain: merge-check.sh (go), merge-…
mesh/delivery delivered
mesh/delivery-group group fix/704-release-branch-judge delivered: every member is delivered
Every merge check's judge is built where no pull request can reach (hq ADR 0358 §6, issue 704): the build agent needs a directory beside its workspace, mounted at the same path, that only judge builds mount. ADR 0358 §5 already holds in the forge's holder; this test keeps it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
172 lines
5.9 KiB
Go
172 lines
5.9 KiB
Go
// The build agent's manifest (novox/hq ADR 0336, issue 121). The build agent is assigned at genesis's
|
|
// step 13, before anything provides the package registry, so that requirement is optional
|
|
// (ADR 0330); until it binds, the agent on genesis's node reads the genesis document the installer
|
|
// seals to it at the packages step. The program is mesh-controller's cmd/mesh-builder; only the
|
|
// packaging lives here, and this is its test.
|
|
package buildagent
|
|
|
|
import (
|
|
"encoding/json"
|
|
"os"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
type manifest struct {
|
|
Requires []json.RawMessage `json:"requires"`
|
|
Binds map[string]string `json:"binds"`
|
|
Secrets map[string]string `json:"secrets"`
|
|
OwnSecrets map[string]json.RawMessage `json:"own-secrets"`
|
|
Resources []map[string]any `json:"resources"`
|
|
}
|
|
|
|
func read(t *testing.T) manifest {
|
|
t.Helper()
|
|
raw, err := os.ReadFile("module.json")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
var m manifest
|
|
if err := json.Unmarshal(raw, &m); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
return m
|
|
}
|
|
|
|
// requirement is one entry of `requires`: its name, and whether it is optional.
|
|
func requirements(t *testing.T, m manifest) map[string]bool {
|
|
t.Helper()
|
|
out := map[string]bool{}
|
|
for _, raw := range m.Requires {
|
|
var name string
|
|
if json.Unmarshal(raw, &name) == nil {
|
|
out[name] = false
|
|
continue
|
|
}
|
|
var long struct {
|
|
Name string `json:"name"`
|
|
Optional bool `json:"optional"`
|
|
}
|
|
if err := json.Unmarshal(raw, &long); err != nil {
|
|
t.Fatalf("requires: %s: %v", raw, err)
|
|
}
|
|
out[long.Name] = long.Optional
|
|
}
|
|
return out
|
|
}
|
|
|
|
func TestThePackageRegistryIsOptionalAndTheArtifactStoreStaysHard(t *testing.T) {
|
|
r := requirements(t, read(t))
|
|
optional, has := r["npm-package-registry"]
|
|
if !has || !optional {
|
|
t.Errorf("npm-package-registry is not an optional requirement (ADR 0336 §1): %v", r)
|
|
}
|
|
if optional, has := r["artifact-store"]; !has || optional {
|
|
t.Errorf("artifact-store is not a hard requirement: %v", r)
|
|
}
|
|
}
|
|
|
|
// The binding and the credential of the registry are delivered only while it is bound: ADR 0330 §6
|
|
// composes neither for an absent requirement, so no file of the module may name them through a
|
|
// placeholder unless it is itself only-when-bound.
|
|
func TestTheRegistrysBindsAndSecretsAreOnlyWhenBound(t *testing.T) {
|
|
m := read(t)
|
|
if m.Binds["npm-package-registry"] == "" || m.Secrets["npm-package-registry"] == "" {
|
|
t.Fatalf("the agent is not told where the registry is once it binds: binds %v, secrets %v", m.Binds, m.Secrets)
|
|
}
|
|
for _, r := range m.Resources {
|
|
content, _ := r["content"].(string)
|
|
if strings.Contains(content, "${bound:npm-package-registry:") || strings.Contains(content, "${secret:npm-package-registry}") {
|
|
if r["only-when-bound"] != "npm-package-registry" {
|
|
t.Errorf("%v names the registry's binding and is delivered while it is absent", r["id"])
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// The genesis document is an own-secret issued outside the mesh — by the installer at genesis's packages
|
|
// step (ADR 0336 §3) — so the mesh never makes one of its own on any other machine, and the agent is
|
|
// told where it lands.
|
|
func TestTheGenesisDocumentIsDeclaredAndIssuedOutside(t *testing.T) {
|
|
m := read(t)
|
|
raw, has := m.OwnSecrets["genesis-package-registry"]
|
|
if !has {
|
|
t.Fatalf("the build agent declares no genesis-package-registry own-secret: %v", m.OwnSecrets)
|
|
}
|
|
var own struct {
|
|
Path string `json:"path"`
|
|
IssuedBy string `json:"issued-by"`
|
|
}
|
|
if err := json.Unmarshal(raw, &own); err != nil || own.IssuedBy != "outside" {
|
|
t.Fatalf("the genesis document is not issued outside the mesh: %s (%v)", raw, err)
|
|
}
|
|
if !strings.HasPrefix(own.Path, "${dir:mesh-state}/") {
|
|
t.Fatalf("the genesis document is not where the container reads /run/mesh: %s", own.Path)
|
|
}
|
|
inside := "/run/mesh/" + strings.TrimPrefix(own.Path, "${dir:mesh-state}/")
|
|
for _, r := range m.Resources {
|
|
if r["id"] == "agent-env" {
|
|
content, _ := r["content"].(string)
|
|
if !strings.Contains(content, "MESH_GENESIS_PACKAGE_REGISTRY="+inside+"\n") {
|
|
t.Errorf("the agent is not told where the genesis document is (%s):\n%s", inside, content)
|
|
}
|
|
return
|
|
}
|
|
}
|
|
t.Fatal("the build agent has no environment file")
|
|
}
|
|
|
|
// **The judge cache is the agent's own, beside its workspace and never in it** (novox/hq ADR 0358 §6, issue 704): a
|
|
// directory resource of its own, kept as the agent's data, mounted into the agent at the same path as on the host —
|
|
// the container runtime resolves a judge build's mounts on the host — and handed to the agent as MESH_JUDGE_CACHE.
|
|
func TestTheJudgeCacheIsADirectoryOfItsOwnMountedAtTheSamePath(t *testing.T) {
|
|
raw, err := os.ReadFile("module.json")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
var m struct {
|
|
Data struct {
|
|
Own []struct {
|
|
ID string `json:"id"`
|
|
Path string `json:"path"`
|
|
Class string `json:"class"`
|
|
} `json:"own"`
|
|
} `json:"data"`
|
|
Resources []struct {
|
|
ID string `json:"id"`
|
|
Type string `json:"type"`
|
|
Content string `json:"content"`
|
|
Volumes []string `json:"volumes"`
|
|
} `json:"resources"`
|
|
}
|
|
if err := json.Unmarshal(raw, &m); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
dir, data, env, mounted := false, false, false, false
|
|
for _, d := range m.Data.Own {
|
|
if d.ID == "judge-cache" && d.Path == "${dir:judge-cache}" && d.Class == "cache" {
|
|
data = true
|
|
}
|
|
}
|
|
for _, r := range m.Resources {
|
|
switch {
|
|
case r.ID == "judge-cache" && r.Type == "directory":
|
|
dir = true
|
|
case r.ID == "agent-env":
|
|
env = strings.Contains(r.Content, "MESH_JUDGE_CACHE=${dir:judge-cache}\n")
|
|
case r.ID == "server":
|
|
for _, v := range r.Volumes {
|
|
if v == "${dir:judge-cache}:${dir:judge-cache}" {
|
|
mounted = true
|
|
}
|
|
if strings.HasPrefix(v, "${dir:workspace}") && strings.Contains(v, "judge-cache") {
|
|
t.Errorf("the judge cache is mounted inside the workspace: %s", v)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if !dir || !data || !env || !mounted {
|
|
t.Fatalf("the judge cache: directory %v, data %v, env %v, mounted at the same path %v", dir, data, env, mounted)
|
|
}
|
|
}
|