diff --git a/modules/betterbird/README.md b/modules/betterbird/README.md index bbc081d1..d1253dc7 100644 --- a/modules/betterbird/README.md +++ b/modules/betterbird/README.md @@ -1,6 +1,6 @@ # betterbird -Betterbird, the mail and calendar client of g14 and shanks (a Thunderbird fork, with the operator's +Betterbird, the mail and calendar client of node-b and node-d (a Thunderbird fork, with the operator's Exchange calendar through the Owl add-on), as a module (novox/hq issue 345, issue 586, ADR 0208, ADR 0316, ADR 0317, ADR 0329, to-be 56). It requires `x11-display`, so it is assigned only where a display server is held on the same machine. It installs Betterbird from a pinned upstream release, ships Owl with it through @@ -58,7 +58,7 @@ reading the new range there (ADR 0316 §8). **The policy** turns Betterbird's own updater off (`DisableAppUpdate`, which Betterbird's update check honours) and installs Owl into every profile from `file:///opt/betterbird/owl/owl.xpi` as `force_installed`, with `updates_disabled`. A profile that already runs another Owl keeps it: the policy -installs the pinned one where Owl is missing. A newer Owl in the profile (g14 runs 1.5.7) is said as a +installs the pinned one where Owl is missing. A newer Owl in the profile (node-b runs 1.5.7) is said as a fact by `betterbird_status`; Owl installed by policy cannot be removed in Betterbird, so the remedy is moving the pin. An older one is a finding of `betterbird_check`, with the same remedy. @@ -323,10 +323,10 @@ question. ## What changes when it is pushed -The module is assigned to shanks today (look-only, from issue 345's first part); g14 runs Betterbird +The module is assigned to node-d today (look-only, from issue 345's first part); node-b runs Betterbird outside the mesh. With this version, a push to a node (each waits for the operator: `upgrade: record`): -| | on a node with the community package (g14, shanks) | +| | on a node with the community package (node-b, node-d) | |---|---| | the package | `betterbird-bin` removed (quit Betterbird first) | | `/opt/betterbird` | the mesh's 153.4.0esr-bb10, in the same place, so the same profile opens | diff --git a/modules/betterbird/cmd/betterbird-tools/config_test.go b/modules/betterbird/cmd/betterbird-tools/config_test.go index c92a7288..c8efe5c1 100644 --- a/modules/betterbird/cmd/betterbird-tools/config_test.go +++ b/modules/betterbird/cmd/betterbird-tools/config_test.go @@ -412,13 +412,13 @@ func TestKeepProposesANodeLayerThroughTheController(t *testing.T) { f.write(profileDir+"/prefs.js", `user_pref("mail.uifontsize", 16);`+"\n"+`user_pref("mail.spam.manualMark", true);`+"\n") oldNode, oldAsk := nodeName, asker t.Cleanup(func() { nodeName, asker = oldNode, oldAsk }) - nodeName = func() string { return "shanks" } + nodeName = func() string { return "node-d" } var asked []map[string]any asker = func(v string, a any) (json.RawMessage, error) { args := a.(map[string]any) asked = append(asked, args) if args["propose"] == nil { - return json.RawMessage(`{"ok": true, "output": "{\"prefs\": {\"calendar.alarms.playsound\": false}, \"identities\": {\"mail\": {\"account\": \"mail\"}}}\n set at the terminal\nbetterbird on shanks, every value"}`), nil + return json.RawMessage(`{"ok": true, "output": "{\"prefs\": {\"calendar.alarms.playsound\": false}, \"identities\": {\"mail\": {\"account\": \"mail\"}}}\n set at the terminal\nbetterbird on node-d, every value"}`), nil } return json.RawMessage(`{"ok": true, "output": "proposed: p-1"}`), nil } @@ -427,7 +427,7 @@ func TestKeepProposesANodeLayerThroughTheController(t *testing.T) { if err != nil { t.Fatal(err) } - if len(asked) != 2 || asked[0]["node"] != "shanks" || asked[1]["node"] != "shanks" || asked[1]["propose"] != "true" || + if len(asked) != 2 || asked[0]["node"] != "node-d" || asked[1]["node"] != "node-d" || asked[1]["propose"] != "true" || asked[1]["module"] != "betterbird" { t.Fatalf("the node's layer read, then proposed: %v", asked) } diff --git a/modules/betterbird/cmd/betterbird-tools/derive_test.go b/modules/betterbird/cmd/betterbird-tools/derive_test.go index 549e98d9..ea1651f5 100644 --- a/modules/betterbird/cmd/betterbird-tools/derive_test.go +++ b/modules/betterbird/cmd/betterbird-tools/derive_test.go @@ -12,11 +12,11 @@ import ( // ADR 0329 §10, §12: derived from every desktop node's profile, laid out per layer, and proposed one layer at a // time, carrying the layer as it stands. -// derivingMesh is two desktop nodes, g14 (this one, f) and shanks (f2), and a server that holds no Betterbird, as the +// derivingMesh is two desktop nodes, node-b (this one, f) and node-d (f2), and a server that holds no Betterbird, as the // controller answers them; layers are the controller's layers, open the proposals that wait. type derivingMesh struct { t *testing.T - shanks *fake + nodeD *fake layers map[string]map[string]any open bool proposed []map[string]any @@ -35,17 +35,17 @@ func (d *derivingMesh) ask(key string, body any) (json.RawMessage, error) { } switch { case key == "seat:mesh-controller.nodes": - return answer(true, `[{"name": "g14"}, {"name": "novox"}, {"name": "shanks"}]`) + return answer(true, `[{"name": "node-b"}, {"name": "node-c"}, {"name": "node-d"}]`) case key == "seat:mesh-controller.node": - if args["node"] == "novox" { - return answer(true, "novox\n assigned: postgres, nats\n") + if args["node"] == "node-c" { + return answer(true, "node-c\n assigned: postgres, nats\n") } return answer(true, fmt.Sprintf("%s\n last heard from here\n assigned: adwaita, betterbird, dunst\n", args["node"])) - case key == "betterbird.betterbird_derive@shanks": + case key == "betterbird.betterbird_derive@node-d": if d.asleep { return nil, errors.New("nats: no responders available for request") } - here, err := d.shanks.deriveHere(stringsOf(args["kinds"])) + here, err := d.nodeD.deriveHere(stringsOf(args["kinds"])) if err != nil { d.t.Fatal(err) } @@ -53,10 +53,10 @@ func (d *derivingMesh) ask(key string, body any) (json.RawMessage, error) { return json.Marshal(map[string]any{"content": []any{map[string]any{"type": "text", "text": string(text)}}}) case key == "seat:mesh-controller.settings" && args["proposals"] == "true": if d.open { - return answer(true, "sab12 set betterbird on the whole mesh (accounts, identities)\n by g14.node-tools at 2026-10-13 01:00; fingerprint ab12\n waiting for the operator until 2026-10-14 01:00\n"+ - "scd34 set mounts on shanks (sources)\n by g14.node-tools at 2026-10-11 00:05; fingerprint dd0b\n chosen: done\n") + return answer(true, "sab12 set betterbird on the whole mesh (accounts, identities)\n by node-b.node-tools at 2026-10-13 01:00; fingerprint ab12\n waiting for the operator until 2026-10-14 01:00\n"+ + "scd34 set mounts on node-d (sources)\n by node-b.node-tools at 2026-10-11 00:05; fingerprint dd0b\n chosen: done\n") } - return answer(true, "scd34 set mounts on shanks (sources)\n by g14.node-tools; fingerprint dd0b\n chosen: done\n") + return answer(true, "scd34 set mounts on node-d (sources)\n by node-b.node-tools; fingerprint dd0b\n chosen: done\n") case key == "seat:mesh-controller.settings" && args["propose"] == "true": d.proposed = append(d.proposed, args) return answer(true, "proposal sab12: Set the settings of betterbird?\n fingerprint ab12") @@ -107,23 +107,23 @@ func TestDeriveLaysEachEntryOutPerLayerAndProposesOneLayerAtATime(t *testing.T) f2 := newFake(t) f2.profileWithAccounts() f2.profileWithConfiguration() - // shanks holds the same accounts and calendars, another signature, another tag colour and a calendar of its own. + // node-d holds the same accounts and calendars, another signature, another tag colour and a calendar of its own. f2.write(profileDir+"/prefs.js", strings.NewReplacer(`"Regards"`, `"Cheers"`, `"#FF0000"`, `"#CC0000"`).Replace(f2.read(profileDir+"/prefs.js"))+ `user_pref("calendar.registry.s1.type", "caldav");`+"\n"+ `user_pref("calendar.registry.s1.uri", "https://dav.example.org/cal/standup/");`+"\n"+ `user_pref("calendar.registry.s1.name", "Standup");`+"\n") f2.declareAccounts(adoptable) - mesh := &derivingMesh{t: t, shanks: f2, layers: map[string]map[string]any{"": {"accounts": map[string]any{"mail": "as approved"}}}} + mesh := &derivingMesh{t: t, nodeD: f2, layers: map[string]map[string]any{"": {"accounts": map[string]any{"mail": "as approved"}}}} oldNode, oldAsk := nodeName, asker t.Cleanup(func() { nodeName, asker = oldNode, oldAsk }) - nodeName = func() string { return "g14" } + nodeName = func() string { return "node-b" } asker = mesh.ask a, err := f.Derive(nil, false, false, nil, "") if err != nil { t.Fatal(err) } - if !reflect.DeepEqual(a.From, []string{"g14", "shanks"}) || len(a.NotHeard) != 0 { + if !reflect.DeepEqual(a.From, []string{"node-b", "node-d"}) || len(a.NotHeard) != 0 { t.Fatalf("derived from the nodes holding Betterbird: %v %v", a.From, a.NotHeard) } whole := mustJSON(a) @@ -134,9 +134,9 @@ func TestDeriveLaysEachEntryOutPerLayerAndProposesOneLayerAtATime(t *testing.T) } cals, _ := mw[kindCalendars].(map[string]any) if cals["home"] == nil || cals["standup"] != nil { - t.Errorf("a calendar both hold is mesh-wide, one only shanks holds is not: %v", cals) + t.Errorf("a calendar both hold is mesh-wide, one only node-d holds is not: %v", cals) } - if sh := mustJSON(a.Layers["shanks"]); !strings.Contains(sh, "https://dav.example.org/cal/standup/") { + if sh := mustJSON(a.Layers["node-d"]); !strings.Contains(sh, "https://dav.example.org/cal/standup/") { t.Errorf("an entry on one node only goes into that node's layer: %s", sh) } tags, _ := mw[kindTags].(map[string]any) @@ -147,8 +147,8 @@ func TestDeriveLaysEachEntryOutPerLayerAndProposesOneLayerAtATime(t *testing.T) for _, d := range a.Differences { diffs[d.Kind+"/"+d.Entry+"/"+d.Field] = d } - if d := diffs["identities/mail/signature"]; d.Node != "shanks" || mustJSON(d.There) != `["Cheers"]` { - t.Errorf("the answer lists the field shanks holds differently: %+v", a.Differences) + if d := diffs["identities/mail/signature"]; d.Node != "node-d" || mustJSON(d.There) != `["Cheers"]` { + t.Errorf("the answer lists the field node-d holds differently: %+v", a.Differences) } if d := diffs["tags/$label1/color"]; d.There != "#CC0000" || d.MeshWide != "#FF0000" { t.Errorf("%+v", a.Differences) @@ -195,22 +195,22 @@ func TestDeriveLaysEachEntryOutPerLayerAndProposesOneLayerAtATime(t *testing.T) if _, err := f.Derive(nil, false, true, nil, ""); err == nil || !strings.Contains(err.Error(), "sab12 (the whole mesh)") || len(mesh.proposed) != 1 { t.Fatalf("one open proposal of the module's at a time: %v", err) } - // Approved: the mesh-wide layer holds it, so the next layer is shanks's own. + // Approved: the mesh-wide layer holds it, so the next layer is node-d's own. mesh.open = false mesh.layers[""] = values a, err = f.Derive(nil, false, true, prefs, "") if err != nil { t.Fatal(err) } - if len(mesh.proposed) != 2 || mesh.proposed[1]["node"] != "shanks" || a.Next != "shanks" || + if len(mesh.proposed) != 2 || mesh.proposed[1]["node"] != "node-d" || a.Next != "node-d" || !strings.Contains(mesh.proposed[1]["values"].(string), "standup") { t.Fatalf("then the node's own layer: %v", mesh.proposed) } - var shanks map[string]any - if err := json.Unmarshal([]byte(mesh.proposed[1]["values"].(string)), &shanks); err != nil { + var nodeD map[string]any + if err := json.Unmarshal([]byte(mesh.proposed[1]["values"].(string)), &nodeD); err != nil { t.Fatal(err) } - mesh.layers["shanks"] = shanks + mesh.layers["node-d"] = nodeD if a, err = f.Derive(nil, false, true, prefs, ""); err != nil || len(mesh.proposed) != 2 || !strings.HasPrefix(a.Next, "none") { t.Fatalf("nothing left to propose: %v %s", err, a.Next) } @@ -240,10 +240,10 @@ func TestALayerThatCannotBeReadRefusesTheProposal(t *testing.T) { f2 := newFake(t) f2.profileWithAccounts() f2.declareAccounts(adoptable) - mesh := &derivingMesh{t: t, shanks: f2, garbled: true} + mesh := &derivingMesh{t: t, nodeD: f2, garbled: true} oldNode, oldAsk := nodeName, asker t.Cleanup(func() { nodeName, asker = oldNode, oldAsk }) - nodeName = func() string { return "g14" } + nodeName = func() string { return "node-b" } asker = mesh.ask if _, err := f.Derive(nil, false, true, nil, ""); err == nil || !strings.Contains(err.Error(), "cannot be read as the layer") || len(mesh.proposed) != 0 { @@ -257,7 +257,7 @@ func TestALayerThatCannotBeReadRefusesTheProposal(t *testing.T) { t.Fatal("an unreadable layer is an error, never an empty layer") } mesh.garbled = false - if got, err := readLayer("shanks"); err != nil || len(got) != 0 { + if got, err := readLayer("node-d"); err != nil || len(got) != 0 { t.Fatalf("no layer, in the controller's words, is an empty layer: %v %v", got, err) } } diff --git a/modules/brother/cmd/brother/device_integration_test.go b/modules/brother/cmd/brother/device_integration_test.go index e54cd5fa..b4118853 100644 --- a/modules/brother/cmd/brother/device_integration_test.go +++ b/modules/brother/cmd/brother/device_integration_test.go @@ -64,7 +64,7 @@ func TestTheAdminProcessAnswersAnAskOverARealBus(t *testing.T) { Retention: jetstream.WorkQueuePolicy, Discard: jetstream.DiscardNew, MaxAge: 24 * time.Hour, MaxBytes: 8 << 20}); err != nil { t.Fatal(err) } - account := process.Account{URL: url, Node: "g14", Module: "brother", User: "g14.brother." + DeviceProcessID, Password: "pw"} + account := process.Account{URL: url, Node: "node-b", Module: "brother", User: "node-b.brother." + DeviceProcessID, Password: "pw"} if _, err := js.CreateConsumer(ctx, AsksStream, jetstream.ConsumerConfig{Durable: account.QueueConsumerName(), AckPolicy: jetstream.AckExplicitPolicy, AckWait: 30 * time.Second, MaxDeliver: 3}); err != nil { t.Fatal(err) diff --git a/modules/brother/cmd/brother/fetch_test.go b/modules/brother/cmd/brother/fetch_test.go index 434b5041..5d4ce13b 100644 --- a/modules/brother/cmd/brother/fetch_test.go +++ b/modules/brother/cmd/brother/fetch_test.go @@ -234,7 +234,7 @@ func TestAFetchedPDFIsStoredUnderItsHashAndPrinted(t *testing.T) { // A refusal inside the mesh is answered, and nothing is stored nor printed. fake.body = nil before := len(r.objects.keys()) - if _, err := r.call(t, "printer.print", map[string]any{"url": "http://127.0.0.1:9000/mesh-shanks-brother/x"}); err == nil || !strings.Contains(err.Error(), "loopback") { + if _, err := r.call(t, "printer.print", map[string]any{"url": "http://127.0.0.1:9000/mesh-node-d-brother/x"}); err == nil || !strings.Contains(err.Error(), "loopback") { t.Errorf("a loopback address: error = %v", err) } if len(r.objects.keys()) != before || fake.body != nil { diff --git a/modules/brother/cmd/brother/printlink_test.go b/modules/brother/cmd/brother/printlink_test.go index 56670d1f..a1a4fa6a 100644 --- a/modules/brother/cmd/brother/printlink_test.go +++ b/modules/brother/cmd/brother/printlink_test.go @@ -56,15 +56,15 @@ func TestPrintTakesExactlyOneSource(t *testing.T) { for name, args := range map[string]map[string]any{ "none": {}, "only options": {"copies": float64(2)}, - "object and path": {"object": key, "path": "/home/ops/a.pdf", "node": "g14"}, + "object and path": {"object": key, "path": "/home/ops/a.pdf", "node": "node-b"}, "object and url": {"object": key, "url": "https://example.com/a.pdf"}, - "path+node and url": {"path": "/home/ops/a.pdf", "node": "g14", "url": "https://example.com/a.pdf"}, - "all three": {"object": key, "path": "/home/ops/a.pdf", "node": "g14", "url": "https://example.com/a.pdf"}, + "path+node and url": {"path": "/home/ops/a.pdf", "node": "node-b", "url": "https://example.com/a.pdf"}, + "all three": {"object": key, "path": "/home/ops/a.pdf", "node": "node-b", "url": "https://example.com/a.pdf"}, "path without node": {"path": "/home/ops/a.pdf"}, - "node without path": {"node": "g14", "object": key}, + "node without path": {"node": "node-b", "object": key}, "the retired upload": {"upload": "u1"}, "object and upload": {"object": key, "upload": "u1"}, - "path and its object": {"path": "/home/ops/a.pdf", "node": "g14", "object": key}, + "path and its object": {"path": "/home/ops/a.pdf", "node": "node-b", "object": key}, } { _, err := r.call(t, "printer.print", args) if err == nil { @@ -82,7 +82,7 @@ func TestPrintTakesExactlyOneSource(t *testing.T) { } } -// 1598/AC2: with path and node g14, printer.print asks g14's node-files to upload the path into brother's bucket, and +// 1598/AC2: with path and node node-b, printer.print asks node-b's node-files to upload the path into brother's bucket, and // queues a print ask that carries the returned key and the options: under 4 KiB, and no path, node or bytes. func TestPrintOfAFileOfAnotherMachineUploadsThenPrintsTheKey(t *testing.T) { fake := newIPPFake(t, 31, 5) @@ -90,12 +90,12 @@ func TestPrintOfAFileOfAnotherMachineUploadsThenPrintsTheKey(t *testing.T) { key := sha256Hex(doc) up := withUpload(t, key, nil) r := newRig(t, `{"printer":"192.0.2.10"}`, "pw") - r.objects.Put(t.Context(), key, "application/pdf", doc) // what g14's upload stored - got, err := r.call(t, "printer.print", map[string]any{"path": "/home/ops/letter.pdf", "node": "g14", "copies": float64(2)}) + r.objects.Put(t.Context(), key, "application/pdf", doc) // what node-b's upload stored + got, err := r.call(t, "printer.print", map[string]any{"path": "/home/ops/letter.pdf", "node": "node-b", "copies": float64(2)}) if err != nil { t.Fatal(err) } - if len(up.seen()) != 1 || up.seen()[0] != "g14|/home/ops/letter.pdf|brother-test" { + if len(up.seen()) != 1 || up.seen()[0] != "node-b|/home/ops/letter.pdf|brother-test" { t.Fatalf("uploads asked: %v", up.seen()) } if len(r.bus.published) != 1 { @@ -114,7 +114,7 @@ func TestPrintOfAFileOfAnotherMachineUploadsThenPrintsTheKey(t *testing.T) { } } m := got.(map[string]any) - if m["job-id"] != float64(31) || m["node"] != "g14" || m["path"] != "/home/ops/letter.pdf" { + if m["job-id"] != float64(31) || m["node"] != "node-b" || m["path"] != "/home/ops/letter.pdf" { t.Errorf("answer = %v", m) } if _, sent := fake.request(t); string(sent) != string(doc) { @@ -127,7 +127,7 @@ func TestARefusedUploadIsAnsweredWithItsReasonAndNothingIsPrinted(t *testing.T) fake := newIPPFake(t, 1, 3) up := withUpload(t, "", errors.New("/home/ops/.ssh/id_ed25519 is refused by name: it is in .ssh, which holds an account's credentials")) r := newRig(t, `{"printer":"192.0.2.10"}`, "pw") - _, err := r.call(t, "printer.print", map[string]any{"path": "/home/ops/.ssh/id_ed25519", "node": "g14"}) + _, err := r.call(t, "printer.print", map[string]any{"path": "/home/ops/.ssh/id_ed25519", "node": "node-b"}) if err == nil || !strings.Contains(err.Error(), "is refused by name: it is in .ssh") { t.Fatalf("error = %v", err) } @@ -277,7 +277,7 @@ func TestASlowUploadAndPrintAnswersStartedNeverATimeout(t *testing.T) { t.Cleanup(func() { uploadVia = old }) r := newRig(t, `{"printer":"192.0.2.10"}`, "pw") r.objects.Put(t.Context(), key, "application/pdf", doc) - got, err := r.call(t, "printer.print", map[string]any{"path": "/home/ops/letter.pdf", "node": "g14"}) + got, err := r.call(t, "printer.print", map[string]any{"path": "/home/ops/letter.pdf", "node": "node-b"}) if err != nil { t.Fatalf("a slow upload failed the call: %v", err) } @@ -292,7 +292,7 @@ func TestASlowUploadAndPrintAnswersStartedNeverATimeout(t *testing.T) { t.Fatal(err) } if rm := read.(map[string]any); rm["state"] == nil { - if rm["job-id"] != float64(72) || rm["path"] != "/home/ops/letter.pdf" || rm["node"] != "g14" { + if rm["job-id"] != float64(72) || rm["path"] != "/home/ops/letter.pdf" || rm["node"] != "node-b" { t.Errorf("the outcome = %v", rm) } break @@ -309,7 +309,7 @@ func TestASlowUploadAndPrintAnswersStartedNeverATimeout(t *testing.T) { time.Sleep(150 * time.Millisecond) return "", errors.New("/home/ops/.ssh/id_ed25519 is refused by name") } - got, _ = r.call(t, "printer.print", map[string]any{"path": "/home/ops/.ssh/id_ed25519", "node": "g14"}) + got, _ = r.call(t, "printer.print", map[string]any{"path": "/home/ops/.ssh/id_ed25519", "node": "node-b"}) id2, _ := got.(map[string]any)["ask"].(string) time.Sleep(300 * time.Millisecond) if _, err := r.call(t, "printer.print", map[string]any{"ask": id2}); err == nil || !strings.Contains(err.Error(), "refused by name") { diff --git a/modules/brother/cmd/brother/rig_test.go b/modules/brother/cmd/brother/rig_test.go index 22ae831f..52b38a1d 100644 --- a/modules/brother/cmd/brother/rig_test.go +++ b/modules/brother/cmd/brother/rig_test.go @@ -139,7 +139,7 @@ func newRig(t *testing.T, settings, password string) *printerRig { return nil }, Answers: answers, - Node: "shanks", + Node: "node-d", Now: func() time.Time { return fixedNow }, } bus := &fakeAskBus{worker: w, answers: answers} diff --git a/modules/brother/cmd/brother/scanlink_test.go b/modules/brother/cmd/brother/scanlink_test.go index 7f480eec..6dbcc751 100644 --- a/modules/brother/cmd/brother/scanlink_test.go +++ b/modules/brother/cmd/brother/scanlink_test.go @@ -76,7 +76,7 @@ func TestTheDeviceAnswerCarriesALinkAndNoBytes(t *testing.T) { } // The real store: the binding's key signs, for the binding's host and port, in the module's bucket. - s3 := NewS3(StoreFacts{Scheme: "http", At: "novox.internal", Port: "20001", Bucket: "mesh-shanks-brother", Region: "eu-west", + s3 := NewS3(StoreFacts{Scheme: "http", At: "node-c.internal", Port: "20001", Bucket: "mesh-node-d-brother", Region: "eu-west", Key: "binding-key", Secret: "binding-secret"}) s3.Now = func() time.Time { return fixedNow } got, err := s3.Link("GET", "abc.pdf", 10*time.Minute) @@ -84,7 +84,7 @@ func TestTheDeviceAnswerCarriesALinkAndNoBytes(t *testing.T) { t.Fatal(err) } gu, _ := url.Parse(got) - if gu.Host != "novox.internal:20001" || gu.Path != "/mesh-shanks-brother/abc.pdf" || + if gu.Host != "node-c.internal:20001" || gu.Path != "/mesh-node-d-brother/abc.pdf" || !strings.HasPrefix(gu.Query().Get("X-Amz-Credential"), "binding-key/") || gu.Query().Get("X-Amz-Expires") != "600" { t.Errorf("link %s", got) } diff --git a/modules/brother/cmd/brother/service_test.go b/modules/brother/cmd/brother/service_test.go index 99f83dc8..6a409426 100644 --- a/modules/brother/cmd/brother/service_test.go +++ b/modules/brother/cmd/brother/service_test.go @@ -111,7 +111,7 @@ func TestScanNowEmitsOneEventAfterTheScanIsKeptUnderTheSha256(t *testing.T) { if kept, err := r.objects.Get(t.Context(), want+".pdf"); err != nil || !bytes.Equal(kept, pdf) { t.Errorf("the bucket does not hold the filed PDF under its sha256 (%v)", err) } - if ev.body["bytes"] != len(pdf) || ev.body["node"] != "shanks" || ev.body["cropped"] != true || ev.body["color-mode"] != "color" { + if ev.body["bytes"] != len(pdf) || ev.body["node"] != "node-d" || ev.body["cropped"] != true || ev.body["color-mode"] != "color" { t.Errorf("event = %v", ev.body) } if want := fixedNow.UTC().Format(time.RFC3339); ev.body["scanned-at"] != want { diff --git a/modules/dnsmasq/cmd/dnsmasq-tools/dnsmasq_test.go b/modules/dnsmasq/cmd/dnsmasq-tools/dnsmasq_test.go index c9ae3b9a..13cabca2 100644 --- a/modules/dnsmasq/cmd/dnsmasq-tools/dnsmasq_test.go +++ b/modules/dnsmasq/cmd/dnsmasq-tools/dnsmasq_test.go @@ -134,8 +134,8 @@ func aResolverMachine(t *testing.T, port string, now func() time.Time) *Machine } } write(ConfigFile, "bind-interfaces\nlisten-address=127.0.0.2\nlisten-address=127.0.0.1\nno-resolv\n") - write(NodesFile, "local=/internal/\naddress=/novox.internal/127.0.0.2\nhost-record=novox.internal,127.0.0.2\n"+ - "address=/ace.internal/10.77.0.2\nhost-record=ace.internal,10.77.0.2\n") + write(NodesFile, "local=/internal/\naddress=/node-c.internal/127.0.0.2\nhost-record=node-c.internal,127.0.0.2\n"+ + "address=/node-a.internal/10.77.0.2\nhost-record=node-a.internal,10.77.0.2\n") if err := os.MkdirAll(filepath.Join(root, filepath.Dir(StateFile)), 0o755); err != nil { t.Fatal(err) } @@ -147,13 +147,13 @@ func TestTheConfigurationAndTheRosterSayWhereAndWhatToAsk(t *testing.T) { if strings.Join(listen, " ") != "10.77.0.1 127.0.0.1" { t.Fatalf("listen addresses %v", listen) } - names := AnsweredNames("local=/internal/\naddress=/ace.internal/10.77.0.2\nhost-record=ace.internal,10.77.0.2\n" + - "host-record=novox.internal,10.77.0.1\n") + names := AnsweredNames("local=/internal/\naddress=/node-a.internal/10.77.0.2\nhost-record=node-a.internal,10.77.0.2\n" + + "host-record=node-c.internal,10.77.0.1\n") q, ok := Question(listen, names) - if !ok || q.Name != "novox.internal" || q.Address != "10.77.0.1" { + if !ok || q.Name != "node-c.internal" || q.Address != "10.77.0.1" { t.Fatalf("asks %+v", q) } - if q, _ := Question([]string{"127.0.0.1"}, names); q.Name != "ace.internal" { + if q, _ := Question([]string{"127.0.0.1"}, names); q.Name != "node-a.internal" { t.Fatalf("with no own name in the roster, asks %+v", q) } } @@ -165,7 +165,7 @@ func TestALookFindsAResolverThatStoppedAnsweringOnOneAddress(t *testing.T) { m := aResolverMachine(t, port, time.Now) private := startStandIn(t, "127.0.0.2", port, "127.0.0.2") startStandIn(t, "127.0.0.1", port, "127.0.0.2") - if l := m.Look(t.Context()); !l.Healthy || len(l.Answers) != 4 || l.Asked.Name != "novox.internal" { + if l := m.Look(t.Context()); !l.Healthy || len(l.Answers) != 4 || l.Asked.Name != "node-c.internal" { t.Fatalf("a resolver answering everywhere: %+v", l) } private.stop() @@ -173,14 +173,14 @@ func TestALookFindsAResolverThatStoppedAnsweringOnOneAddress(t *testing.T) { if l.Healthy || len(l.Wrong) != 2 { t.Fatalf("a resolver that stopped answering on its private address: %+v", l) } - if why := l.Why(); !strings.Contains(why, "127.0.0.2:"+port+" over udp did not answer novox.internal: refused") || + if why := l.Why(); !strings.Contains(why, "127.0.0.2:"+port+" over udp did not answer node-c.internal: refused") || !strings.Contains(why, "over tcp") || strings.Contains(why, "127.0.0.1:") { t.Fatalf("said as %q", why) } } func TestAWrongAnswerIsNotAnAnswer(t *testing.T) { - q := Named{Name: "novox.internal", Address: "10.77.0.1"} + q := Named{Name: "node-c.internal", Address: "10.77.0.1"} for _, c := range []struct { a Answer want string @@ -198,7 +198,7 @@ func TestAWrongAnswerIsNotAnAnswer(t *testing.T) { func failing(at time.Time) Look { return Look{At: at, Answers: []Answer{{Server: "10.77.0.1:53", Over: "udp", Failed: "refused: nothing listens there"}}, - Wrong: []string{"10.77.0.1:53 over udp did not answer novox.internal: refused: nothing listens there"}} + Wrong: []string{"10.77.0.1:53 over udp did not answer node-c.internal: refused: nothing listens there"}} } func healthy(at time.Time) Look { return Look{At: at, Healthy: true} } @@ -323,7 +323,7 @@ func TestTheWatchRestartsAResolverThatStoppedAnsweringAndHealthSaysWhetherItHelp look() } h := m.Health(t.Context()) - if h.Healthy || !strings.Contains(h.Why, "did not answer novox.internal: refused") || + if h.Healthy || !strings.Contains(h.Why, "did not answer node-c.internal: refused") || !strings.Contains(h.Why, "which did not help") { t.Fatalf("a restart that did not help: %q", h.Why) } @@ -482,10 +482,10 @@ func TestResolveAsksOnlyAListenAddress(t *testing.T) { m := aResolverMachine(t, port, time.Now) startStandIn(t, "127.0.0.2", port, "127.0.0.2") startStandIn(t, "127.0.0.1", port, "127.0.0.2") - if _, err := m.Resolve(t.Context(), "novox.internal", "8.8.8.8", ""); err == nil || !strings.Contains(err.Error(), "not one the resolver listens on") { + if _, err := m.Resolve(t.Context(), "node-c.internal", "8.8.8.8", ""); err == nil || !strings.Contains(err.Error(), "not one the resolver listens on") { t.Fatalf("another address was asked: %v", err) } - got, err := m.Resolve(t.Context(), "novox.internal", "127.0.0.2", "tcp") + got, err := m.Resolve(t.Context(), "node-c.internal", "127.0.0.2", "tcp") if err != nil { t.Fatal(err) } @@ -493,10 +493,10 @@ func TestResolveAsksOnlyAListenAddress(t *testing.T) { if len(answers) != 1 || answers[0].Over != "tcp" || answers[0].Code != "NOERROR" || answers[0].Addresses[0] != "127.0.0.2" { t.Fatalf("%+v", answers) } - if got, _ := m.Resolve(t.Context(), "novox.internal", "", ""); len(got.(map[string]any)["answers"].([]Answer)) != 4 { + if got, _ := m.Resolve(t.Context(), "node-c.internal", "", ""); len(got.(map[string]any)["answers"].([]Answer)) != 4 { t.Fatalf("every listen address over both: %+v", got) } - if _, err := m.Resolve(t.Context(), "novox.internal", "", "quic"); err == nil { + if _, err := m.Resolve(t.Context(), "node-c.internal", "", "quic"); err == nil { t.Fatal("over quic was accepted") } if _, err := m.Resolve(t.Context(), "", "", ""); err == nil { @@ -540,12 +540,12 @@ func TestTheAnnouncerSaysWhatChangedAndRemembersOnlyWhatWasSaid(t *testing.T) { } // The roster changes: one machine added, one gone. An unreadable roster says nothing. nodes := filepath.Join(m.Root, NodesFile) - if err := os.WriteFile(nodes, []byte("host-record=novox.internal,127.0.0.2\nhost-record=shanks.internal,10.77.0.4\n"), 0o644); err != nil { + if err := os.WriteFile(nodes, []byte("host-record=node-c.internal,127.0.0.2\nhost-record=node-d.internal,10.77.0.4\n"), 0o644); err != nil { t.Fatal(err) } Tell(m, &a, emit) - if got := strings.Join(said, "|"); !strings.Contains(got, "name.added shanks.internal") || - !strings.Contains(got, "name.removed ace.internal") || len(said) != 2 { + if got := strings.Join(said, "|"); !strings.Contains(got, "name.added node-d.internal") || + !strings.Contains(got, "name.removed node-a.internal") || len(said) != 2 { t.Fatalf("the roster's change: %v", said) } said = nil diff --git a/modules/influxdb/test/grants.test.ts b/modules/influxdb/test/grants.test.ts index 7b7b78cd..c0a8bb91 100644 --- a/modules/influxdb/test/grants.test.ts +++ b/modules/influxdb/test/grants.test.ts @@ -108,13 +108,13 @@ const grants = new ApiGrants(new InfluxDBClient(`http://127.0.0.1:${port}`, ADMI const PW = "mesh-minted-password-of-forty-characters"; -/** Grafana on ace, as the mesh hands it to the provisioner. */ +/** Grafana on node-a, as the mesh hands it to the provisioner. */ function grafana(password = PW, values: Record = { access: "read" }) { - return { as: "mesh_ace_grafana", password, consumer: "ace", values }; + return { as: "mesh_node-a_grafana", password, consumer: "node-a", values }; } -/** Node-RED on ace: writes one bucket. */ +/** Node-RED on node-a: writes one bucket. */ function nodered(password = PW, values: Record = { access: "write", buckets: ["zurag"] }) { - return { as: "mesh_ace_nodered", password, consumer: "ace", values }; + return { as: "mesh_node-a_nodered", password, consumer: "node-a", values }; } function only(token: string): Rec { @@ -144,7 +144,7 @@ test("what a contribution may ask for, and what is refused", () => { test("a reader is given one authorization, reading every bucket of the org, under the mesh's password", async () => { assert.equal(await grants.ensure(grafana()), "created"); - const a = only("mesh_ace_grafana"); + const a = only("mesh_node-a_grafana"); assert.equal(a.orgID, "org1"); assert.equal(a.status, "active"); assert.ok(a.description.startsWith(MARK)); @@ -158,8 +158,8 @@ test("a writer is allowed its own buckets only, and a missing one is made — ne const made = buckets.find((b) => b.name === "printer"); assert.ok(made, "the missing bucket was created"); assert.deepEqual(made!.retentionRules, [], "kept for ever: retention is the operator's choice"); - assert.deepEqual(perms(only("mesh_ace_nodered")), [`write:buckets:${made!.id}`, "write:buckets:zb"]); - assert.equal(await grants.remove("mesh_ace_nodered"), "removed"); + assert.deepEqual(perms(only("mesh_node-a_nodered")), [`write:buckets:${made!.id}`, "write:buckets:zb"]); + assert.equal(await grants.remove("mesh_node-a_nodered"), "removed"); assert.equal(buckets.length, 2, "withdrawing the consumer leaves every bucket and its data"); }); @@ -168,30 +168,30 @@ test("applying the same grant again writes nothing", async () => { calls = []; assert.equal(await grants.ensure(grafana()), "unchanged"); assert.ok(calls.every((c) => c.startsWith("GET")), `only reads: ${calls.join(", ")}`); - only("mesh_ace_grafana"); + only("mesh_node-a_grafana"); }); test("a rotated password is set in place; a changed access remakes only the mesh's own", async () => { await grants.ensure(nodered()); - const id = only("mesh_ace_nodered").id; + const id = only("mesh_node-a_nodered").id; assert.equal(await grants.holds(nodered("rotated-password-0123456789")), false); assert.equal(await grants.ensure(nodered("rotated-password-0123456789")), "updated"); - assert.equal(only("mesh_ace_nodered").id, id, "updated, not replaced"); + assert.equal(only("mesh_node-a_nodered").id, id, "updated, not replaced"); assert.equal(await grants.holds(nodered("rotated-password-0123456789")), true); await grants.ensure(nodered(PW, { access: "read-write", buckets: ["zurag"] })); - assert.deepEqual(perms(only("mesh_ace_nodered")), ["read:buckets:zb", "write:buckets:zb"]); + assert.deepEqual(perms(only("mesh_node-a_nodered")), ["read:buckets:zb", "write:buckets:zb"]); assert.equal(await grants.holds(nodered(PW, { access: "read-write", buckets: ["zurag"] })), true); }); test("an authorization disabled, re-passworded or deleted behind the mesh's back is not held, and is made whole", async () => { await grants.ensure(grafana()); - only("mesh_ace_grafana").status = "inactive"; + only("mesh_node-a_grafana").status = "inactive"; assert.equal(await grants.holds(grafana()), false); assert.equal(await grants.ensure(grafana()), "updated"); assert.equal(await grants.holds(grafana()), true); - only("mesh_ace_grafana").password = "somebody-else-set-this"; + only("mesh_node-a_grafana").password = "somebody-else-set-this"; assert.equal(await grants.holds(grafana()), false); await grants.ensure(grafana()); assert.equal(await grants.holds(grafana()), true); @@ -211,14 +211,14 @@ test("holds only reads, and a bucket gone missing is not held rather than made", }); test("an authorization of the same name the mesh did not make is refused, and left exactly as it was", async () => { - auths = [{ id: "theirs", token: "mesh_ace_grafana", orgID: "org1", status: "active", description: "hand-made", + auths = [{ id: "theirs", token: "mesh_node-a_grafana", orgID: "org1", status: "active", description: "hand-made", permissions: [{ action: "write", resource: { type: "buckets", orgID: "org1" } }], password: "their-password" }]; const before = JSON.stringify(auths); await assert.rejects(grants.ensure(grafana()), /did not make/); assert.equal(JSON.stringify(auths), before); assert.ok(calls.every((c) => c.startsWith("GET")), `only reads: ${calls.join(", ")}`); assert.equal(await grants.holds(grafana()), false); - assert.equal(await grants.remove("mesh_ace_grafana"), "not ours"); + assert.equal(await grants.remove("mesh_node-a_grafana"), "not ours"); assert.equal(auths.length, 1, "never deleted"); }); @@ -240,7 +240,7 @@ test("an org the instance does not have, or a non-mesh name, makes nothing", asy test("a withdrawn consumer's authorization is removed, and an absent one is not an error", async () => { await grants.ensure(grafana()); - assert.equal(await grants.remove("mesh_ace_grafana"), "removed"); + assert.equal(await grants.remove("mesh_node-a_grafana"), "removed"); assert.equal(auths.length, 0); - assert.equal(await grants.remove("mesh_ace_grafana"), "absent"); + assert.equal(await grants.remove("mesh_node-a_grafana"), "absent"); }); diff --git a/modules/keycloak/cmd/keycloak-provider/admin_test.go b/modules/keycloak/cmd/keycloak-provider/admin_test.go index 09ae9886..ebe8c866 100644 --- a/modules/keycloak/cmd/keycloak-provider/admin_test.go +++ b/modules/keycloak/cmd/keycloak-provider/admin_test.go @@ -52,7 +52,7 @@ type guardWorld struct { func newGuardWorld(t *testing.T) *guardWorld { w := &guardWorld{now: time.Date(2026, 10, 5, 23, 55, 0, 0, time.UTC)} - w.f = newFakeKeycloak(t, "Novox", "old-password-from-2022") + w.f = newFakeKeycloak(t, "NodeC", "old-password-from-2022") w.x = &fakeExec{f: w.f} w.g = &Guard{KC: w.f.client("the-mesh-minted-this"), Exec: w.x, Now: func() time.Time { return w.now }, @@ -195,7 +195,7 @@ func TestWhileTheAdminIsRefusedTheProvisionerDoesNotAskKeycloak(t *testing.T) { w := newGuardWorld(t) w.x.fails = true w.g.Ensure(ctx, true, false) - a := provisioner{clients: OidcClients{KC: w.g.KC, Realm: "Novox"}, guard: w.g, + a := provisioner{clients: OidcClients{KC: w.g.KC, Realm: "NodeC"}, guard: w.g, announce: func(string, map[string]any) {}, log: func(string, ...any) {}} logins := w.f.logins err := a.Create(ctx, grafana("s", nil)) diff --git a/modules/keycloak/cmd/keycloak-provider/grant_moved_test.go b/modules/keycloak/cmd/keycloak-provider/grant_moved_test.go index 20843dcd..3511168e 100644 --- a/modules/keycloak/cmd/keycloak-provider/grant_moved_test.go +++ b/modules/keycloak/cmd/keycloak-provider/grant_moved_test.go @@ -91,13 +91,13 @@ func movedWorld(t *testing.T, h *harness.Harness) (f *fakeKeycloak, start func() } } -// 1332/AC1: a consumer only the grant file gives (oidc-client for novox.mesh-mail-web, not moved) is wanted and +// 1332/AC1: a consumer only the grant file gives (oidc-client for node-c.mesh-mail-web, not moved) is wanted and // Adapter.Create is asked for its client, though keycloak runs on the moved path. func TestAGrantFileConsumerNotMovedIsMadeOnTheMovedPath(t *testing.T) { - mailWeb := "mesh_novox_mail_web" - receives := grantGives(t, map[string]any{"as": mailWeb, "node": "novox", "values": map[string]any{ + mailWeb := "mesh_node_c_mail_web" + receives := grantGives(t, map[string]any{"as": mailWeb, "node": "node-c", "values": map[string]any{ "label": "mail-web", "endpoint": "web", "callback": "/login/generic_oauth", "name": "mail.example.org"}}) - h := &harness.Harness{Resource: ProvisionName, Receives: receives, Node: "novox"} + h := &harness.Harness{Resource: ProvisionName, Receives: receives, Node: "node-c"} f, start := movedWorld(t, h) start() waitUntil(t, time.Second, func() bool { @@ -113,13 +113,13 @@ func TestAGrantFileConsumerNotMovedIsMadeOnTheMovedPath(t *testing.T) { }) } -// 1332/AC2: a grant-file consumer whose client already exists in the backend (mesh_ace_grafana) counts as asked and +// 1332/AC2: a grant-file consumer whose client already exists in the backend (mesh_node_a_grafana) counts as asked and // is not held for retirement on the moved path. func TestAGrantFileConsumerAlreadyInKeycloakIsNotRetiredOnTheMovedPath(t *testing.T) { - grafana := "mesh_ace_grafana" - receives := grantGives(t, map[string]any{"as": grafana, "node": "ace", "values": map[string]any{ + grafana := "mesh_node_a_grafana" + receives := grantGives(t, map[string]any{"as": grafana, "node": "node-a", "values": map[string]any{ "label": "grafana", "endpoint": "web", "callback": "/login/generic_oauth", "name": "grafana.example.org"}}) - h := &harness.Harness{Resource: ProvisionName, Receives: receives, Node: "ace", + h := &harness.Harness{Resource: ProvisionName, Receives: receives, Node: "node-a", StablePasses: 1, StableFor: time.Millisecond} f, start := movedWorld(t, h) // Seed the backend with the client the mesh made earlier, exactly as grafana's already is — before anything diff --git a/modules/keycloak/cmd/keycloak-provider/main_test.go b/modules/keycloak/cmd/keycloak-provider/main_test.go index 617873d6..6f7681f4 100644 --- a/modules/keycloak/cmd/keycloak-provider/main_test.go +++ b/modules/keycloak/cmd/keycloak-provider/main_test.go @@ -8,7 +8,7 @@ import "testing" // 1332/AC3: the moved-path harness, built from the environment, reads MESH_RECEIVES the way the grant path does // (main.go's other branch, line 67), as postgres's moved harness does (postgres-provider/main.go:43). func TestTheMovedPathHarnessReadsMESH_RECEIVESAsTheGrantPathDoes(t *testing.T) { - env := map[string]string{"MESH_RECEIVES": "/grants/mesh.json", "MESH_NODE": "novox"} + env := map[string]string{"MESH_RECEIVES": "/grants/mesh.json", "MESH_NODE": "node-c"} getenv := func(k string) string { return env[k] } h := movedHarness(getenv, provisioner{}) if h.Receives != env["MESH_RECEIVES"] { diff --git a/modules/keycloak/cmd/keycloak-provider/moved_test.go b/modules/keycloak/cmd/keycloak-provider/moved_test.go index f69aa363..03d1af3f 100644 --- a/modules/keycloak/cmd/keycloak-provider/moved_test.go +++ b/modules/keycloak/cmd/keycloak-provider/moved_test.go @@ -14,7 +14,7 @@ import ( "git.novox.be/novox/mesh-sdk/go/provider/harness" ) -const testIssuer = "https://id.example.org/realms/Novox" +const testIssuer = "https://id.example.org/realms/NodeC" // keycloak's own part of the moved path (issue 849): the shared driving of it is proven in the SDK's harness package. @@ -143,12 +143,12 @@ func TestBothPathsLeaveTheSameClientInKeycloak(t *testing.T) { }) viaFile := made(func(p provisioner) { list, _ := json.Marshal([]provider.ConsumerCredential{{Consumer: "home", Module: "grafana", - Credential: provider.PairName("novox", ProvisionName, "home", "grafana", ""), Value: "pw-" + grafana}}) + Credential: provider.PairName("node-c", ProvisionName, "home", "grafana", ""), Value: "pw-" + grafana}}) file := filepath.Join(t.TempDir(), "consumers.json") if err := os.WriteFile(file, list, 0o600); err != nil { t.Fatal(err) } - h := &harness.Harness{Resource: ProvisionName, Adapter: p, Node: "novox", + h := &harness.Harness{Resource: ProvisionName, Adapter: p, Node: "node-c", Now: func() time.Time { return now }, Log: func(string, ...any) {}} run, _, _, err := moved(file, h, testIssuer) if err != nil { @@ -156,10 +156,10 @@ func TestBothPathsLeaveTheSameClientInKeycloak(t *testing.T) { } bus := &bucketBus{buckets: map[string]map[string][]byte{}} plan, _ := json.Marshal(map[string]any{"node": "home", "module": "grafana", "provisioning": map[string]any{ - "provisions": []any{map[string]any{"provision": ProvisionName, "provider": "novox", + "provisions": []any{map[string]any{"provision": ProvisionName, "provider": "node-c", "provider-module": "keycloak", "contributes": grafanaContributes, "names": grafanaNames}}}}) _ = bus.Put(ctx, provider.AssignmentsBucket, "home.grafana", plan) - pr := provider.New(provider.Options{Node: "novox", Module: "keycloak", Bus: bus, + pr := provider.New(provider.Options{Node: "node-c", Module: "keycloak", Bus: bus, Vault: provider.ConsumersFile{Paths: []string{file}}, Offers: map[string]provider.Offer{ProvisionName: {Credential: provider.PerConsumer, Serves: servedValues(testIssuer)}}, diff --git a/modules/keycloak/cmd/keycloak-provider/oidc.go b/modules/keycloak/cmd/keycloak-provider/oidc.go index c7815462..f23804f5 100644 --- a/modules/keycloak/cmd/keycloak-provider/oidc.go +++ b/modules/keycloak/cmd/keycloak-provider/oidc.go @@ -64,7 +64,7 @@ func RolesMapper() Rep { var realmPath = regexp.MustCompile(`/realms/([^/]+)/?$`) -// RealmOf is the realm named by an issuer URL — `https://id.example/realms/Novox` is realm `Novox`. +// RealmOf is the realm named by an issuer URL — `https://id.example/realms/NodeC` is realm `NodeC`. // The issuer is the one value an assignment sets, so the realm is read out of it rather than set a // second time where the two could disagree. func RealmOf(issuer string) (string, error) { diff --git a/modules/keycloak/cmd/keycloak-provider/oidc_test.go b/modules/keycloak/cmd/keycloak-provider/oidc_test.go index 45c95ae3..4045fc91 100644 --- a/modules/keycloak/cmd/keycloak-provider/oidc_test.go +++ b/modules/keycloak/cmd/keycloak-provider/oidc_test.go @@ -15,8 +15,8 @@ import ( ) func oidcWorld(t *testing.T) (*fakeKeycloak, OidcClients) { - f := newFakeKeycloak(t, "Novox", "pw") - return f, OidcClients{KC: f.client("pw"), Realm: "Novox"} + f := newFakeKeycloak(t, "NodeC", "pw") + return f, OidcClients{KC: f.client("pw"), Realm: "NodeC"} } // grafana is a dashboard on the home server, as the mesh hands it to the provisioner. @@ -53,8 +53,8 @@ func mustHold(t *testing.T, o OidcClients, p harness.Provision, want bool) { func TestTheRealmIsReadOutOfTheIssuer(t *testing.T) { for issuer, want := range map[string]string{ - "https://id.example.org/realms/Novox": "Novox", - "https://id.example.org/realms/Novox/": "Novox", + "https://id.example.org/realms/NodeC": "NodeC", + "https://id.example.org/realms/NodeC/": "NodeC", "http://127.0.0.1:18500/realms/master": "master", } { if got, err := RealmOf(issuer); err != nil || got != want { diff --git a/modules/mesh-mail-reader/cmd/mesh-mail-reader/batch_test.go b/modules/mesh-mail-reader/cmd/mesh-mail-reader/batch_test.go index c882125b..830072d0 100644 --- a/modules/mesh-mail-reader/cmd/mesh-mail-reader/batch_test.go +++ b/modules/mesh-mail-reader/cmd/mesh-mail-reader/batch_test.go @@ -151,22 +151,22 @@ func TestNewJudgeCollectsAPendingAnswer(t *testing.T) { var sawTicket string collected := 0 ask := func(key string, body map[string]any) (json.RawMessage, error) { - if key == "claude-code.claude_code_judge@novox" { + if key == "claude-code.claude_code_judge@node-c" { sawWithin = body["within"].(int) - return json.Marshal(map[string]any{"pending": true, "ticket": "tk-1", "node": "novox"}) + return json.Marshal(map[string]any{"pending": true, "ticket": "tk-1", "node": "node-c"}) } - if key == "claude-code.claude_code_judged@novox" { + if key == "claude-code.claude_code_judged@node-c" { sawTicket = body["ticket"].(string) collected++ if collected < 2 { - return json.Marshal(map[string]any{"pending": true, "ticket": "tk-1", "node": "novox"}) + return json.Marshal(map[string]any{"pending": true, "ticket": "tk-1", "node": "node-c"}) } return json.Marshal(map[string]any{"answer": json.RawMessage(`{"mails":[{"id":1,"mark":"neither"}]}`)}) } return nil, fmt.Errorf("unexpected ask %s", key) } now := time.Now() - judge := NewJudge(ask, "novox", func() time.Time { return now }) + judge := NewJudge(ask, "node-c", func() time.Time { return now }) raw, outcome, why := judge("the question", AnswerSchema()) if outcome != OutcomeOK { t.Fatalf("outcome = %q, why = %q, want OutcomeOK", outcome, why) @@ -198,9 +198,9 @@ func TestNewJudgeTimesOut(t *testing.T) { } else { now = now.Add(JudgeWithin + 2*time.Minute) // collecting again takes "too long" } - return json.Marshal(map[string]any{"pending": true, "ticket": "tk-1", "node": "novox"}) + return json.Marshal(map[string]any{"pending": true, "ticket": "tk-1", "node": "node-c"}) } - judge := NewJudge(ask, "novox", func() time.Time { return now }) + judge := NewJudge(ask, "node-c", func() time.Time { return now }) _, outcome, why := judge("the question", AnswerSchema()) if outcome != OutcomeTimedOut { t.Fatalf("outcome = %q, why = %q, want OutcomeTimedOut", outcome, why) @@ -212,7 +212,7 @@ func TestNewJudgeRefused(t *testing.T) { ask := func(string, map[string]any) (json.RawMessage, error) { return nil, fmt.Errorf("holds no licence") } - judge := NewJudge(ask, "novox", time.Now) + judge := NewJudge(ask, "node-c", time.Now) _, outcome, why := judge("the question", AnswerSchema()) if outcome != OutcomeRefused || !strings.Contains(why, "licence") { t.Fatalf("outcome = %q, why = %q, want OutcomeRefused naming the licence", outcome, why) @@ -228,14 +228,14 @@ func TestNewJudgeSortsItsCauseByTheRealJudgesWords(t *testing.T) { err string want HealthOutcome }{ - {"timed out", "the agent on novox did not answer within 40s; the judgement was ended", OutcomeTimedOut}, - {"out of shape", `the agent on novox answered, and not in the shape asked: "mails" is not an array`, OutcomeOutOfShape}, - {"refused", "the agent on novox could not judge: holds no licence", OutcomeRefused}, + {"timed out", "the agent on node-c did not answer within 40s; the judgement was ended", OutcomeTimedOut}, + {"out of shape", `the agent on node-c answered, and not in the shape asked: "mails" is not an array`, OutcomeOutOfShape}, + {"refused", "the agent on node-c could not judge: holds no licence", OutcomeRefused}, } for _, c := range cases { t.Run(c.name, func(t *testing.T) { ask := func(string, map[string]any) (json.RawMessage, error) { return nil, fmt.Errorf("%s", c.err) } - judge := NewJudge(ask, "novox", time.Now) + judge := NewJudge(ask, "node-c", time.Now) _, outcome, why := judge("the question", AnswerSchema()) if outcome != c.want { t.Fatalf("outcome = %q, want %q", outcome, c.want) @@ -355,7 +355,7 @@ func TestRunOneBatchNeverAsksToSendMoveFlagOrDelete(t *testing.T) { return json.Marshal(map[string]any{"text": "hi"}) } readText := NewReadText(recordingAsk) - judge := NewJudge(recordingAsk, "novox", time.Now) + judge := NewJudge(recordingAsk, "node-c", time.Now) if err := RunOneBatch(ctx, store, readText, judge, waiting, time.Now, noopLogf); err != nil { t.Fatal(err) } diff --git a/modules/mesh-mail-reader/cmd/mesh-mail-reader/callers.go b/modules/mesh-mail-reader/cmd/mesh-mail-reader/callers.go index 6d666e91..1bd82b11 100644 --- a/modules/mesh-mail-reader/cmd/mesh-mail-reader/callers.go +++ b/modules/mesh-mail-reader/cmd/mesh-mail-reader/callers.go @@ -1,6 +1,6 @@ package main -// Callers is the trusted setting `callers` (lead-m2@g14's decision at this milestone's prepare step, said to +// Callers is the trusted setting `callers` (lead-m2@node-b's decision at this milestone's prepare step, said to // the operator; novox/hq ADR 0459 §2: "each answers only a caller the operator grants it"): who may call one // of mail-reading's six verbs. An entry is a bare module name (granted wherever it runs, on any machine), // exactly ., or exactly person. — the same shapes mesh-mail's own trusted setting diff --git a/modules/mesh-mail-reader/cmd/mesh-mail-reader/callers_test.go b/modules/mesh-mail-reader/cmd/mesh-mail-reader/callers_test.go index 19349c7f..54cb6763 100644 --- a/modules/mesh-mail-reader/cmd/mesh-mail-reader/callers_test.go +++ b/modules/mesh-mail-reader/cmd/mesh-mail-reader/callers_test.go @@ -5,15 +5,15 @@ package main import "testing" func TestCallersAllowsEachShape(t *testing.T) { - c := Callers{"mesh-mail-web", "novox.mesh-knowledge", "person.jochen"} + c := Callers{"mesh-mail-web", "node-c.mesh-knowledge", "person.jochen"} cases := []struct { caller string want bool }{ {"mesh-mail-web", true}, // a bare module name - {"shanks.mesh-mail-web", true}, // ... on any machine - {"novox.mesh-knowledge", true}, // exactly . - {"shanks.mesh-knowledge", false}, // ... but not on another machine + {"node-d.mesh-mail-web", true}, // ... on any machine + {"node-c.mesh-knowledge", true}, // exactly . + {"node-d.mesh-knowledge", false}, // ... but not on another machine {"person.jochen", true}, // exactly person. {"person.someoneelse", false}, // ... but not another person {"mesh-mail-notifier", false}, // not named at all