Files
mesh-host/internal/bootstrap/builder_test.go
T
jochen 6f13813a59
mesh/merge-gate head 6f13813a59dc merged into trunk 0d11b4fc930d — fail: head 6f13813a59dc does not merge cleanly into trunk 0d11b4fc930d: in conflict inte…
mesh/repo-check head 6f13813a59dc merged into trunk 0d11b4fc930d — fail: head 6f13813a59dc does not merge cleanly into trunk 0d11b4fc930d: in conflict inte…
mesh/delivery-group group fix/121-genesis-package-registry rejected: its order contradicts itself: novox/mesh-catalog@e0bc919d4945 and novox/mesh-controller@a6…
mesh/delivery superseded: a newer head of the same pull request
Seal the build agent the forge genesis raised, in place of the builder's npm-password (hq issue 121, ADR 0336)
The build agent declares neither the retired builder's npm-password own-secret
nor a serves setting, so the packages step handed its credential to nothing
and genesis's sdk step had no way to publish. The packages step now seals the
genesis-package-registry own-secret to build-agent: the forge on this node's
loopback, the port given for the package registry, its npm path, and the
mesh-builder account with its password. setFoundationSettings no longer gives
the builder a serves.port.
2026-10-13 02:55:11 +02:00

149 lines
5.8 KiB
Go

package bootstrap
import (
"context"
"os"
"path/filepath"
"strings"
"testing"
"time"
)
// Defends novox/hq 04-ISSUES/085: the port given for the package registry at genesis is a setting
// of a module and not text in a manifest, so registering that manifest again does not put the
// catalogue's number back.
// theBuildersBinding is the resource the builder carries in place of a binding nothing can resolve
// yet, exactly as the catalogue's manifest has it — settable, with the port as its only default.
const theBuildersBinding = `{
"module": "builder",
"resources": [
{
"id": "package-binding",
"type": "file",
"path": "/var/lib/mesh/builder/package-registry.json",
"mode": "0600",
"merge": "json",
"protected": ["provision", "from", "at", "as"],
"content": "{\"provision\": \"package-registry\", \"from\": \"gitea\", \"at\": \"127.0.0.1\", \"as\": \"mesh-builder\", \"serves\": {\"scheme\": \"http\", \"port\": 3000, \"npm-path\": \"/api/packages/novox/npm/\"}}\n"
}
]
}`
func recording(t *testing.T) (*controlRecorder, controlPlane) {
t.Helper()
t.Setenv("TMPDIR", t.TempDir())
c := &controlRecorder{settings: map[string]string{}}
return c, controlPlane{container: "temp-mesh-controller", run: c.run, timeout: time.Second}
}
func TestTheBuilderOnTheDefaultPackagesPortIsToldNothing(t *testing.T) {
c, control := recording(t)
o := Options{Node: "anchor", Wait: time.Second}
if _, err := installModule(context.Background(), o, control, BuilderModule,
[]byte(theBuildersBinding), quietly); err != nil {
t.Fatal(err)
}
if c.index("settings") >= 0 {
t.Errorf("a genesis on the catalogue's packages port set a setting: %v", c.told)
}
}
// aCatalogueWith writes a checkout holding one module's manifest, which is all the installer reads
// a catalogue for.
func aCatalogueWith(t *testing.T, module, manifest string) string {
t.Helper()
dir := t.TempDir()
at := filepath.Join(dir, catalogueDir, module)
if err := os.MkdirAll(at, 0o700); err != nil {
t.Fatal(err)
}
if err := os.WriteFile(filepath.Join(at, "module.json"), []byte(manifest), 0o600); err != nil {
t.Fatal(err)
}
return dir
}
const theForgesManifest = `{"module": "gitea", "version": "1"}`
func TestThePackagesPortIsTheForgeModulesSettingOnThisNode(t *testing.T) {
c, control := recording(t)
o := Options{Node: "anchor", Catalogue: aCatalogueWith(t, ForgeModule, theForgesManifest),
Ports: FoundationPorts{Packages: 3100}, Wait: time.Second}
if err := recordTheForgesPort(context.Background(), o, control, quietly); err != nil {
t.Fatal(err)
}
if got := c.settings["gitea-settings.json"]; got != `{"ports":{"3000":3100}}` {
t.Errorf("the forge module was told %q about its port", got)
}
// Registered so there is something to hold the setting against, and never assigned: the forge
// module cannot run until the base it stands on has been built.
add, set := c.index("module add"), c.index("settings set gitea")
if add < 0 || set < 0 || add > set {
t.Fatalf("the forge's setting was recorded against a module the mesh does not know: %v", c.told)
}
if c.index("assign") >= 0 {
t.Errorf("genesis assigned the forge module: %v", c.told)
}
if !strings.Contains(c.told[set], "--node anchor") {
t.Errorf("the forge's port was set for the whole mesh, not this machine: %s", c.told[set])
}
}
// knowingControl is a control plane that already has the forge in its catalogue, as a mesh that
// has been running has.
type knowingControl struct{ controlRecorder }
func (k *knowingControl) run(ctx context.Context, name string, args ...string) (string, error) {
out, err := k.controlRecorder.run(ctx, name, args...)
if name == "docker" && args[0] == "exec" && len(args) > 4 &&
args[3] == "module" && args[4] == "list" {
return ForgeModule + " 1 assigned to anchor\n", nil
}
return out, err
}
func TestARerunDoesNotReplaceAForgeTheMeshAlreadyHas(t *testing.T) {
t.Setenv("TMPDIR", t.TempDir())
k := &knowingControl{controlRecorder{settings: map[string]string{}}}
control := controlPlane{container: "mesh-controller", run: k.run, timeout: time.Second}
// An older checkout than the mesh is running, which is what makes an overwrite here damage.
o := Options{Node: "anchor", Catalogue: aCatalogueWith(t, ForgeModule, `{"module": "gitea"}`),
Ports: FoundationPorts{Packages: 3100}, Wait: time.Second}
if err := recordTheForgesPort(context.Background(), o, control, quietly); err != nil {
t.Fatal(err)
}
// Registering is an overwrite, and the manifest of a forge that is built and assigned is not
// this installer's to replace with whatever checkout it was pointed at.
if k.index("module add") >= 0 {
t.Errorf("a re-run replaced the registered forge's manifest: %v", k.told)
}
// The port is still recorded: a settings row needs the module row, and it is already there.
if got := k.settings["gitea-settings.json"]; got != `{"ports":{"3000":3100}}` {
t.Errorf("the forge's port was not recorded on a mesh that knows it: %q", got)
}
}
func TestAGenesisOnTheCataloguesPackagesPortRegistersNoForge(t *testing.T) {
c, control := recording(t)
o := Options{Node: "anchor", Catalogue: aCatalogueWith(t, ForgeModule, theForgesManifest),
Wait: time.Second}
if err := recordTheForgesPort(context.Background(), o, control, quietly); err != nil {
t.Fatal(err)
}
if len(c.told) != 0 {
t.Errorf("a genesis on the defaults told the mesh something new: %v", c.told)
}
}
func TestAForgeManifestTheCatalogueDoesNotHaveIsNamed(t *testing.T) {
_, control := recording(t)
o := Options{Node: "anchor", Catalogue: t.TempDir(),
Ports: FoundationPorts{Packages: 3100}, Wait: time.Second}
err := recordTheForgesPort(context.Background(), o, control, quietly)
if err == nil || !strings.Contains(err.Error(), ForgeModule) ||
!strings.Contains(err.Error(), "package registry") {
t.Errorf("a missing forge manifest was not explained: %v", err)
}
}