mesh/merge-gate head a641ed7d15c7 merged into trunk b12c4b82e820 — pass: builds build-agent, mesh-controller → ace, g14, novox, shanks; no bus step; every …
mesh/repo-check head a641ed7d15c7 merged into trunk b12c4b82e820 — pass: its merge-check.sh passed
mesh/delivery delivered
mesh/delivery-group group fix/121-genesis-package-registry delivered: every member is delivered
With npm-package-registry optional, the binding file the agent's environment names may be absent, and mesh-builder failed every build on reading it. It now reads the genesis document the installer seals at genesis's packages step when no binding is present, prefers the binding when both are, and each build's log says which it resolved from (§4). A build that needs the registry - a package, an image naming .npmrc, TypeScript with an @novox/ dependency - on an agent with neither is refused before anything is built or published, naming the machine, the unbound requirement and gitea (§6); it never falls back to the public registry. The captured catalogue moves to the mesh-catalog change it is judged with.
86 lines
4.0 KiB
Go
86 lines
4.0 KiB
Go
package catalogue
|
|
|
|
import (
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
// Genesis assigns the build agent before the package registry exists (novox/hq ADR 0336, issue 121),
|
|
// judged over the real catalogue. Genesis's step 13 was refused with "nothing provides
|
|
// \"npm-package-registry\", wanted by build-agent": the forge genesis raises at its packages step is a
|
|
// container, not the gitea module, and provides nothing.
|
|
|
|
// agentBuilt is the build agent as the mesh holds it once built: its image pinned.
|
|
func agentBuilt(t *testing.T) Manifest {
|
|
t.Helper()
|
|
agent := catalogueManifest(t, "build-agent")
|
|
built, err := agent.Resolve([]Built{{Name: "server", Kind: ArtifactImage,
|
|
Reference: "mesh-builder@sha256:" + strings.Repeat("a", 64)}})
|
|
if err != nil {
|
|
t.Fatalf("the build agent does not resolve against its own build: %v", err)
|
|
}
|
|
return built
|
|
}
|
|
|
|
func TestGenesisAssignsTheBuildAgentWithNothingProvidingTheRegistry(t *testing.T) {
|
|
agent := agentBuilt(t)
|
|
if !agent.IsOptional("npm-package-registry") {
|
|
t.Fatalf("the build agent's npm-package-registry is hard (ADR 0336 §1): %v", agent.Requires)
|
|
}
|
|
if agent.IsOptional("artifact-store") {
|
|
t.Fatal("the build agent's artifact-store is optional; it stays hard")
|
|
}
|
|
store := map[string][]Provider{"artifact-store": {
|
|
{Node: "anchor", At: "anchor.internal", Module: "distribution", Serves: map[string]any{"port": float64(5000)}}}}
|
|
books := shelf(agent, catalogueManifest(t, "gitea"), catalogueManifest(t, "distribution"))
|
|
|
|
// Genesis's node at step 13: the store answers, nothing provides the registry.
|
|
got, err := Resolve(books, []string{"build-agent"}, reachable(), World{Offered: store})
|
|
if err != nil {
|
|
t.Fatalf("assigning the build agent with no registry was refused: %v", err)
|
|
}
|
|
if have := strings.Join(names(got), " "); have != "build-agent" {
|
|
t.Fatalf("assigning the build agent put %s on the machine; nothing is installed for the registry", have)
|
|
}
|
|
if len(got.Absent) != 1 || got.Absent[0] != (Absent{Consumer: "build-agent", Requirement: "npm-package-registry"}) {
|
|
t.Fatalf("the registry is not listed unbound for the build agent: %+v", got.Absent)
|
|
}
|
|
out, err := got.Declaration(Rendering{ArtifactStore: "anchor.internal:5000",
|
|
Needed: map[string]map[string]string{"build-agent": {"broker": "sealed-broker"}}})
|
|
if err != nil {
|
|
t.Fatalf("the build agent does not compose with the registry unbound: %v", err)
|
|
}
|
|
for _, id := range []string{"build-agent." + BoundID("npm-package-registry"), "build-agent." + SecretID("npm-package-registry"),
|
|
"build-agent." + NeedID("genesis-package-registry")} {
|
|
if fileNamed(out, id) != nil {
|
|
t.Errorf("%s was delivered with the registry unbound and no genesis document given", id)
|
|
}
|
|
}
|
|
|
|
// The genesis document, once the installer seals it at the packages step (ADR 0336 §3).
|
|
out, err = got.Declaration(Rendering{ArtifactStore: "anchor.internal:5000",
|
|
Needed: map[string]map[string]string{"build-agent": {"broker": "sealed-broker", "genesis-package-registry": "sealed-genesis"}}})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
doc := fileNamed(out, "build-agent."+NeedID("genesis-package-registry"))
|
|
if doc == nil || doc["sealed"] != "sealed-genesis" || !strings.HasSuffix(doc["path"].(string), "/genesis-package-registry.json") {
|
|
t.Fatalf("the genesis document is not delivered where the agent reads it: %v", doc)
|
|
}
|
|
|
|
// The gitea module assigned: the requirement binds, with no act on the build agent (ADR 0336 §2).
|
|
registry := map[string][]Provider{"artifact-store": store["artifact-store"], "npm-package-registry": {
|
|
{Node: "anchor", At: "anchor.internal", Module: "gitea",
|
|
Serves: map[string]any{"port": float64(3000), "scheme": "http", "npm-path": "/api/packages/novox/npm/"}}}}
|
|
bound, err := Resolve(books, []string{"build-agent"}, reachable(), World{Offered: registry})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if n := boundFrom(t, bound, "build-agent", "npm-package-registry"); n.Module != "gitea" {
|
|
t.Fatalf("bound to %s", n.Module)
|
|
}
|
|
if len(bound.Absent) != 0 {
|
|
t.Fatalf("the registry is still listed unbound once gitea is assigned: %+v", bound.Absent)
|
|
}
|
|
}
|