mesh/delivery-group group fix/121-genesis-package-registry delivering: 2 of 4 delivered
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
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.
103 lines
3.7 KiB
Go
103 lines
3.7 KiB
Go
package main
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/novox/mesh-controller/internal/builder"
|
|
)
|
|
|
|
// The build agent's package registry (novox/hq ADR 0336, issue 121): its npm-package-registry
|
|
// requirement is optional, so the binding may be absent, and on genesis's node the installer seals
|
|
// the forge it raised as one genesis document instead.
|
|
|
|
// registryFiles names the three paths the build agent's environment always names, writing only those
|
|
// given.
|
|
func registryFiles(t *testing.T, binding, token, genesis string) {
|
|
t.Helper()
|
|
dir := t.TempDir()
|
|
for env, content := range map[string]string{
|
|
"MESH_PACKAGE_BINDING": binding,
|
|
"MESH_NPM_TOKEN_FILE": token,
|
|
"MESH_GENESIS_PACKAGE_REGISTRY": genesis,
|
|
} {
|
|
path := filepath.Join(dir, env)
|
|
t.Setenv(env, path)
|
|
if content != "" {
|
|
if err := os.WriteFile(path, []byte(content), 0o600); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
}
|
|
for _, env := range []string{"MESH_NPM_REGISTRY", "MESH_NPM_TOKEN", "MESH_NPM_USER", "MESH_NPM_SCOPE"} {
|
|
t.Setenv(env, "")
|
|
}
|
|
}
|
|
|
|
const (
|
|
aBinding = `{"from":"gitea","at":"anchor.mesh","as":"anchor-agent",
|
|
"serves":{"scheme":"http","port":3000,"npm-path":"/api/packages/novox/npm/"}}`
|
|
aGenesisDocument = `{"scheme":"http","at":"127.0.0.1","port":3100,"npm-path":"/api/packages/novox/npm/",
|
|
"as":"mesh-builder","password":"genesis-secret"}`
|
|
)
|
|
|
|
func TestUntilTheRequirementBindsTheGenesisDocumentIsRead(t *testing.T) {
|
|
registryFiles(t, "", "", aGenesisDocument)
|
|
n, err := packagesFrom("anchor")
|
|
if err != nil {
|
|
t.Fatalf("an absent binding beside a genesis document was refused: %v", err)
|
|
}
|
|
if n.From != builder.FromGenesis || n.Registry != "http://127.0.0.1:3100/api/packages/novox/npm/" ||
|
|
n.Username != "mesh-builder" || n.Password != "genesis-secret" || n.Scope != "@novox" {
|
|
t.Fatalf("the genesis document was not what the registry came from: %+v", n)
|
|
}
|
|
file, err := n.File()
|
|
if err != nil || !strings.Contains(file, "//127.0.0.1:3100/api/packages/novox/npm/:username=mesh-builder") {
|
|
t.Fatalf("the .npmrc is not written from the genesis document: %v\n%s", err, file)
|
|
}
|
|
if got := saysRegistry(n); !strings.Contains(got, "genesis document") {
|
|
t.Errorf("the log does not say the genesis document: %s", got)
|
|
}
|
|
}
|
|
|
|
func TestARealBindingWinsOverTheGenesisDocument(t *testing.T) {
|
|
registryFiles(t, aBinding, "bound-secret\n", aGenesisDocument)
|
|
n, err := packagesFrom("anchor")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if n.From != builder.FromBinding || n.Registry != "http://anchor.mesh:3000/api/packages/novox/npm/" ||
|
|
n.Username != "anchor-agent" || n.Password != "bound-secret" {
|
|
t.Fatalf("the binding did not win over the genesis document: %+v", n)
|
|
}
|
|
if got := saysRegistry(n); !strings.Contains(got, "binding") {
|
|
t.Errorf("the log does not say the binding: %s", got)
|
|
}
|
|
}
|
|
|
|
func TestWithNeitherTheAgentHasNoRegistryAndSaysWhere(t *testing.T) {
|
|
registryFiles(t, "", "", "")
|
|
n, err := packagesFrom("workstation")
|
|
if err != nil {
|
|
t.Fatalf("an unbound optional requirement was a fault: %v", err)
|
|
}
|
|
if n.Enabled() || n.Machine != "workstation" {
|
|
t.Fatalf("a registry came from nowhere: %+v", n)
|
|
}
|
|
got := saysRegistry(n)
|
|
for _, want := range []string{"npm-package-registry", "unbound", "workstation"} {
|
|
if !strings.Contains(got, want) {
|
|
t.Errorf("the log does not say %q: %s", want, got)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestAGenesisDocumentMissingAFieldIsRefusedByName(t *testing.T) {
|
|
registryFiles(t, "", "", `{"at":"127.0.0.1","port":3000,"npm-path":"/api/packages/novox/npm/","as":"mesh-builder"}`)
|
|
if _, err := packagesFrom("anchor"); err == nil || !strings.Contains(err.Error(), "password") {
|
|
t.Fatalf("a genesis document with no password was taken: %v", err)
|
|
}
|
|
}
|