From 04a85108e57fae39f92d567f70c59cd48f3177c9 Mon Sep 17 00:00:00 2001 From: jochen Date: Thu, 22 Oct 2026 21:38:44 +0200 Subject: [PATCH] Name no node in mesh-mail's fixtures (issue 1838) --- .../mesh-mail/acceptance_integration_test.go | 14 ++-- modules/mesh-mail/cmd/mesh-mail/ask_test.go | 18 ++--- modules/mesh-mail/cmd/mesh-mail/claim_test.go | 2 +- .../mesh-mail/cmd/mesh-mail/config_test.go | 20 +++--- .../mesh-mail/cmd/mesh-mail/content_rule.go | 4 +- .../mesh-mail/cmd/mesh-mail/manifest_test.go | 4 +- .../mesh-mail/cmd/mesh-mail/mirror_test.go | 4 +- .../mesh-mail/cmd/mesh-mail/objects_test.go | 10 +-- .../mesh-mail/cmd/mesh-mail/search_test.go | 40 +++++------ .../cmd/mesh-mail/secret_boundary_test.go | 8 +-- modules/mesh-mail/cmd/mesh-mail/send_test.go | 70 +++++++++---------- .../cmd/mesh-mail/sender_integration_test.go | 2 +- .../mesh-mail/cmd/mesh-mail/sender_test.go | 6 +- .../cmd/mesh-mail/smtp_classify_test.go | 8 +-- modules/mesh-mail/cmd/mesh-mail/tools_test.go | 40 +++++------ 15 files changed, 125 insertions(+), 125 deletions(-) diff --git a/modules/mesh-mail/cmd/mesh-mail/acceptance_integration_test.go b/modules/mesh-mail/cmd/mesh-mail/acceptance_integration_test.go index 33ae896c..8ccbd545 100644 --- a/modules/mesh-mail/cmd/mesh-mail/acceptance_integration_test.go +++ b/modules/mesh-mail/cmd/mesh-mail/acceptance_integration_test.go @@ -161,15 +161,15 @@ func TestMailSenderAcceptanceAnApprovedSendIsSentOnceAndSaidOnce(t *testing.T) { dir := t.TempDir() accountsPath := filepath.Join(dir, "accounts.json") - writeFile(t, accountsPath, `{"accounts": {"mesh": {"kind": "imap", "address": "jschoubben@novox.be", - "incoming": {"host": "mail.novox.be", "port": 993, "security": "tls"}, + writeFile(t, accountsPath, `{"accounts": {"mesh": {"kind": "imap", "address": "jschoubben@node-c.be", + "incoming": {"host": "mail.node-c.be", "port": 993, "security": "tls"}, "outgoing": {"host": "127.0.0.1", "port": 1, "security": "tls"}}}}`) writeFile(t, filepath.Join(dir, "mail-credential-mesh.secret"), "the-password\n") approvedAt := judgedAt req, id := queueAnApprovedSend(t, bus, "mesh", approvedAt) - account := process.Account{URL: url, Node: "g14", Module: Module, User: "g14." + Module + "." + SendProcessID, Password: "pw"} + account := process.Account{URL: url, Node: "node-b", Module: Module, User: "node-b." + Module + "." + SendProcessID, Password: "pw"} if _, err := bus.js.CreateConsumer(context.Background(), MailSendsStream, jetstream.ConsumerConfig{ Durable: account.QueueConsumerName(), AckPolicy: jetstream.AckExplicitPolicy, AckWait: 5 * time.Second, MaxDeliver: MostAttempts}); err != nil { t.Fatal(err) @@ -209,7 +209,7 @@ func TestMailSenderAcceptanceAnApprovedSendIsSentOnceAndSaidOnce(t *testing.T) { if got.to[0] != "ops@example.org" { t.Fatalf("received: %+v", got) } - if !strings.Contains(got.data, "Message-Id: <"+req.ID+"@novox.be>") { + if !strings.Contains(got.data, "Message-Id: <"+req.ID+"@node-c.be>") { t.Fatalf("the mail's Message-ID does not name the send: %s", got.data) } @@ -238,15 +238,15 @@ func TestMailSenderAcceptanceARefusedSignInFailsAfterItsAttemptsAndNothingIsRece dir := t.TempDir() accountsPath := filepath.Join(dir, "accounts.json") - writeFile(t, accountsPath, `{"accounts": {"mesh": {"kind": "imap", "address": "jschoubben@novox.be", - "incoming": {"host": "mail.novox.be", "port": 993, "security": "tls"}, + writeFile(t, accountsPath, `{"accounts": {"mesh": {"kind": "imap", "address": "jschoubben@node-c.be", + "incoming": {"host": "mail.node-c.be", "port": 993, "security": "tls"}, "outgoing": {"host": "127.0.0.1", "port": 1, "security": "tls"}}}}`) writeFile(t, filepath.Join(dir, "mail-credential-mesh.secret"), "the-wrong-password\n") approvedAt := judgedAt _, id := queueAnApprovedSend(t, bus, "mesh", approvedAt) - account := process.Account{URL: url, Node: "g14", Module: Module, User: "g14." + Module + "." + SendProcessID, Password: "pw"} + account := process.Account{URL: url, Node: "node-b", Module: Module, User: "node-b." + Module + "." + SendProcessID, Password: "pw"} if _, err := bus.js.CreateConsumer(context.Background(), MailSendsStream, jetstream.ConsumerConfig{ Durable: account.QueueConsumerName(), AckPolicy: jetstream.AckExplicitPolicy, AckWait: 2 * time.Second, MaxDeliver: MostAttempts}); err != nil { t.Fatal(err) diff --git a/modules/mesh-mail/cmd/mesh-mail/ask_test.go b/modules/mesh-mail/cmd/mesh-mail/ask_test.go index 41f20759..9f8574e3 100644 --- a/modules/mesh-mail/cmd/mesh-mail/ask_test.go +++ b/modules/mesh-mail/cmd/mesh-mail/ask_test.go @@ -44,16 +44,16 @@ func mustNotBeRefused(t *testing.T, a asks.Ask) { } // (1) A recipient that is one of the operator's own mesh-mail accounts (sendTestBundle's "mesh", address -// jschoubben@novox.be) is named by the account's name alone: the ask carries no mail address at all, and +// jschoubben@node-c.be) is named by the account's name alone: the ask carries no mail address at all, and // passes the real content rule. This is the first test issue 868's decision asked for; it fails today // because AskMailSend puts the raw address into the ask. func TestMailSendAskForOwnAccountRecipientCarriesNoAddress(t *testing.T) { b, router, _ := sendTestBundle(t, Server{Host: "127.0.0.1", Port: 25, Security: "tls"}) rt := startBundle(t, b.Tools()) - args := map[string]any{"account": "mesh", "to": []any{"jschoubben@novox.be"}, + args := map[string]any{"account": "mesh", "to": []any{"jschoubben@node-c.be"}, "subject": "Testing issue 868", "body": "Does the ask reach the operator now?"} - text, isErr := rt.call(SendTool, "novox.triage", args) + text, isErr := rt.call(SendTool, "node-c.triage", args) if isErr { t.Fatalf("%s", text) } @@ -81,7 +81,7 @@ func TestMailSendAskForOutsideRecipientCarriesNoAddress(t *testing.T) { b, router, _ := sendTestBundle(t, Server{Host: "127.0.0.1", Port: 25, Security: "tls"}) rt := startBundle(t, b.Tools()) - text, isErr := rt.call(SendTool, "novox.triage", sendArgs) // to: ops@example.org, lead@example.org + text, isErr := rt.call(SendTool, "node-c.triage", sendArgs) // to: ops@example.org, lead@example.org if isErr { t.Fatalf("%s", text) } @@ -108,7 +108,7 @@ func TestMailSendAskForManyRecipientsCountsTheRest(t *testing.T) { args := map[string]any{"account": "mesh", "to": []any{"a@example.org", "b@example.org", "c@example.org", "d@example.org", "e@example.org"}, "subject": "Many recipients", "body": "body"} - text, isErr := rt.call(SendTool, "novox.triage", args) + text, isErr := rt.call(SendTool, "node-c.triage", args) if isErr { t.Fatalf("%s", text) } @@ -133,7 +133,7 @@ func TestMailSendAskMasksAnAddressAndALinkInTheSubject(t *testing.T) { args := map[string]any{"account": "mesh", "to": []any{"ops@example.org"}, "subject": "Contact ops@example.org or see https://example.com/issue/42", "body": "See https://example.com/issue/42 and write to ops@example.org for details."} - text, isErr := rt.call(SendTool, "novox.triage", args) + text, isErr := rt.call(SendTool, "node-c.triage", args) if isErr { t.Fatalf("%s", text) } @@ -164,7 +164,7 @@ func TestMailSendAskFallsBackToDetailsWhenTheSubjectStillRefuses(t *testing.T) { b, router, _ := sendTestBundle(t, Server{Host: "127.0.0.1", Port: 25, Security: "tls"}) rt := startBundle(t, b.Tools()) args := map[string]any{"account": "mesh", "to": []any{"ops@example.org"}, "subject": subject, "body": "body"} - text, isErr := rt.call(SendTool, "novox.triage", args) + text, isErr := rt.call(SendTool, "node-c.triage", args) if isErr { t.Fatalf("%s", text) } @@ -198,9 +198,9 @@ func TestMailSendAskMatchesADisplayNameRecipientByItsAddress(t *testing.T) { b, router, _ := sendTestBundle(t, Server{Host: "127.0.0.1", Port: 25, Security: "tls"}) rt := startBundle(t, b.Tools()) - args := map[string]any{"account": "mesh", "to": []any{"Jochen Schoubben "}, + args := map[string]any{"account": "mesh", "to": []any{"Jochen Schoubben "}, "subject": "Testing a display name", "body": "body"} - text, isErr := rt.call(SendTool, "novox.triage", args) + text, isErr := rt.call(SendTool, "node-c.triage", args) if isErr { t.Fatalf("%s", text) } diff --git a/modules/mesh-mail/cmd/mesh-mail/claim_test.go b/modules/mesh-mail/cmd/mesh-mail/claim_test.go index 8b2e9535..76771903 100644 --- a/modules/mesh-mail/cmd/mesh-mail/claim_test.go +++ b/modules/mesh-mail/cmd/mesh-mail/claim_test.go @@ -25,7 +25,7 @@ func claimTestSend(t *testing.T) (id string, router *sendRouter, sends *memSends b.Queue = queue.publish rt := startBundle(t, b.Tools()) - text, isErr := rt.call(SendTool, "novox.triage", sendArgs) + text, isErr := rt.call(SendTool, "node-c.triage", sendArgs) if isErr { t.Fatalf("%s", text) } diff --git a/modules/mesh-mail/cmd/mesh-mail/config_test.go b/modules/mesh-mail/cmd/mesh-mail/config_test.go index 3f3560a5..b2a7b15a 100644 --- a/modules/mesh-mail/cmd/mesh-mail/config_test.go +++ b/modules/mesh-mail/cmd/mesh-mail/config_test.go @@ -12,16 +12,16 @@ import ( // The first stage's account, as the operator sets the setting `accounts` (ADR 0359 §5): its address and its server, // never a credential; its password is the own secret mail-credential-mesh. -const stageOne = `{"accounts": {"mesh": {"kind": "imap", "address": "jschoubben@novox.be", - "incoming": {"host": "mail.novox.be", "port": 993, "security": "tls"}}}}` +const stageOne = `{"accounts": {"mesh": {"kind": "imap", "address": "jschoubben@node-c.be", + "incoming": {"host": "mail.node-c.be", "port": 993, "security": "tls"}}}}` func TestTheFirstStagesAccountIsReadAndItsSecretNamed(t *testing.T) { got, err := ParseAccounts([]byte(stageOne)) if err != nil { t.Fatal(err) } - if len(got) != 1 || got[0].Name != "mesh" || got[0].Kind != KindIMAP || got[0].SignInAs() != "jschoubben@novox.be" || - got[0].Incoming.Address() != "mail.novox.be:993" || got[0].Secret() != "mail-credential-mesh" || got[0].Outgoing != nil { + if len(got) != 1 || got[0].Name != "mesh" || got[0].Kind != KindIMAP || got[0].SignInAs() != "jschoubben@node-c.be" || + got[0].Incoming.Address() != "mail.node-c.be:993" || got[0].Secret() != "mail-credential-mesh" || got[0].Outgoing != nil { t.Fatalf("%+v", got) } if p := secret.Path("/state", got[0].Secret()); p != "/state/mail-credential-mesh.secret" { @@ -34,7 +34,7 @@ func TestTheFirstStagesAccountIsReadAndItsSecretNamed(t *testing.T) { // uses to send through it (novox/hq ADR 0361 §1). func TestASecondIMAPAccountIsConfigurationOnly(t *testing.T) { got, err := ParseAccounts([]byte(`{"accounts": { - "mesh": {"kind": "imap", "address": "jschoubben@novox.be", "incoming": {"host": "mail.novox.be", "port": 993, "security": "tls"}}, + "mesh": {"kind": "imap", "address": "jschoubben@node-c.be", "incoming": {"host": "mail.node-c.be", "port": 993, "security": "tls"}}, "gmail": {"kind": "imap", "address": "someone@gmail.com", "incoming": {"host": "imap.gmail.com", "port": 993, "security": "tls"}, "outgoing": {"host": "smtp.gmail.com", "port": 465, "security": "tls"}, "folders": ["[Gmail]/Sent Mail"]}}}`)) if err != nil { @@ -68,23 +68,23 @@ func TestAnAccountThatCannotBeWatchedRefusesTheSetting(t *testing.T) { // Grants (ADR 0359 §4): nobody by default; a module's name grants it wherever it runs; a module on one machine, or a // person, by its full name; never the unproven, never by a wildcard, never one account for another. func TestGrantsAreByAccountAndByProvenCaller(t *testing.T) { - g := Grants{"mesh": {"triage", "novox.desk", "person.jochen", "*"}} + g := Grants{"mesh": {"triage", "node-c.desk", "person.jochen", "*"}} for caller, want := range map[string]bool{ - "novox.triage": true, "shanks.triage": true, "novox.desk": true, "g14.desk": false, "person.jochen": true, - "person.triage": false, "novox.other": false, Unproven: false, "": false, "novox.*": false, + "node-c.triage": true, "node-d.triage": true, "node-c.desk": true, "node-b.desk": false, "person.jochen": true, + "person.triage": false, "node-c.other": false, Unproven: false, "": false, "node-c.*": false, } { if got := g.Allows(caller, "mesh"); got != want { t.Errorf("%s: %v", caller, got) } } - if g.Allows("novox.triage", "gmail") || (Grants{}).Allows("novox.triage", "mesh") { + if g.Allows("node-c.triage", "gmail") || (Grants{}).Allows("node-c.triage", "mesh") { t.Fatal("a grant reached an account it does not name") } dir := t.TempDir() path := filepath.Join(dir, "grants.json") _ = os.WriteFile(path, []byte(`{"grants": {"mesh": ["triage"]}}`), 0o600) read, err := ReadGrants(path) - if err != nil || !read.Allows("novox.triage", "mesh") { + if err != nil || !read.Allows("node-c.triage", "mesh") { t.Fatalf("%v %v", read, err) } _ = os.WriteFile(path, []byte(`{"grants": {"mesh": "triage"}}`), 0o600) diff --git a/modules/mesh-mail/cmd/mesh-mail/content_rule.go b/modules/mesh-mail/cmd/mesh-mail/content_rule.go index 2c0b5552..beede419 100644 --- a/modules/mesh-mail/cmd/mesh-mail/content_rule.go +++ b/modules/mesh-mail/cmd/mesh-mail/content_rule.go @@ -145,7 +145,7 @@ func randomRun(text string) (Refusal, bool) { } // isPath: absolute, home-relative or dot-relative, or two separators deep. A mesh address names one -// machine and one tool (`ace/postgres.query`) and has one; a ratio ("3/4") has digits only. +// machine and one tool (`node-a/postgres.query`) and has one; a ratio ("3/4") has digits only. func isPath(w string) bool { if w == "" { return false @@ -162,7 +162,7 @@ func isPath(w string) bool { } // isHostName: two names or more, the last a top-level one. A condition key's last name is its kind -// (`machine.ace.silent`), which none of these is. +// (`machine.node-a.silent`), which none of these is. func isHostName(w string) bool { w = strings.ToLower(w) if w == "localhost" { diff --git a/modules/mesh-mail/cmd/mesh-mail/manifest_test.go b/modules/mesh-mail/cmd/mesh-mail/manifest_test.go index 9e8b53cd..c1e3d341 100644 --- a/modules/mesh-mail/cmd/mesh-mail/manifest_test.go +++ b/modules/mesh-mail/cmd/mesh-mail/manifest_test.go @@ -81,7 +81,7 @@ func TestTheManifestSaysWhatTheCodeDoes(t *testing.T) { t.Fatalf("module %s, requires %v, contributes %v", m.Module, m.Requires, m.Contributes) } // mesh__ fits the S3 access key's 20 characters on every node. - if len("mesh_shanks_"+m.Slug) > 20 { + if len("mesh_node-d_"+m.Slug) > 20 { t.Fatalf("the slug %q overflows an S3 access key", m.Slug) } fam := m.OwnSecrets[SecretFamily+"*"] @@ -304,7 +304,7 @@ func TestItsManifestDeclaresTheSenderProcess(t *testing.T) { t.Fatalf("send's bus: %+v", bus) } - // On novox the operator account's state directory is 0700, so mesh-mail-send cannot reach its own 0600 + // On node-c the operator account's state directory is 0700, so mesh-mail-send cannot reach its own 0600 // files inside it: the state directory becomes 0711 (passable, not listable) and accounts.json (server // names and addresses, no password) becomes 0644, so the sender can read the outgoing server. No password // file's mode widens (the lead's decision, issue 1172). diff --git a/modules/mesh-mail/cmd/mesh-mail/mirror_test.go b/modules/mesh-mail/cmd/mesh-mail/mirror_test.go index a6ad8837..571dedd5 100644 --- a/modules/mesh-mail/cmd/mesh-mail/mirror_test.go +++ b/modules/mesh-mail/cmd/mesh-mail/mirror_test.go @@ -52,7 +52,7 @@ func (m *memMirrorState) Keys() ([]string, error) { // accountsAndStore is one account "mesh", granted no caller (the Mirror reads no grant), with the index given. func accountsAndStore(t *testing.T) ([]Account, *memStore) { t.Helper() - return []Account{{Name: "mesh", Kind: KindIMAP, Address: "jschoubben@novox.be"}}, newMemStore() + return []Account{{Name: "mesh", Kind: KindIMAP, Address: "jschoubben@node-c.be"}}, newMemStore() } func mirrorOf(accounts []Account, st *memStore, bucket MirrorState) *Mirror { @@ -147,7 +147,7 @@ func TestMirrorRoundWritesNothingWhenUnchanged(t *testing.T) { func TestMirrorRoundWritesOnlyTheChangedAccountsKey(t *testing.T) { ctx := context.Background() accounts, st := accountsAndStore(t) - accounts = append(accounts, Account{Name: "other", Kind: KindIMAP, Address: "other@novox.be"}) + accounts = append(accounts, Account{Name: "other", Kind: KindIMAP, Address: "other@node-c.be"}) _ = st.SetState(ctx, AccountState{Account: "mesh", State: AccountCurrent}) _ = st.SetState(ctx, AccountState{Account: "other", State: AccountCurrent}) addMail(t, st, "mesh", "INBOX", 1, []string{}) diff --git a/modules/mesh-mail/cmd/mesh-mail/objects_test.go b/modules/mesh-mail/cmd/mesh-mail/objects_test.go index 1c24de34..f57074f5 100644 --- a/modules/mesh-mail/cmd/mesh-mail/objects_test.go +++ b/modules/mesh-mail/cmd/mesh-mail/objects_test.go @@ -31,7 +31,7 @@ func TestAnAttachmentIsKeptOnceByItsHash(t *testing.T) { kept := map[string][]byte{} puts := 0 srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - if !strings.HasPrefix(r.Header.Get("Authorization"), "AWS4-HMAC-SHA256 Credential=mesh_novox_mail/") { + if !strings.HasPrefix(r.Header.Get("Authorization"), "AWS4-HMAC-SHA256 Credential=mesh_node-c_mail/") { w.WriteHeader(http.StatusForbidden) return } @@ -59,8 +59,8 @@ func TestAnAttachmentIsKeptOnceByItsHash(t *testing.T) { dir := t.TempDir() path := filepath.Join(dir, "store.json") host, port, _ := strings.Cut(strings.TrimPrefix(srv.URL, "http://"), ":") - writeFile(t, path, `{"scheme": "http", "at": "`+host+`", "port": "`+port+`", "bucket": "mesh-novox-mail", "region": "eu-west", - "key": "mesh_novox_mail", "secret": "s3cr3t"}`) + writeFile(t, path, `{"scheme": "http", "at": "`+host+`", "port": "`+port+`", "bucket": "mesh-node-c-mail", "region": "eu-west", + "key": "mesh_node-c_mail", "secret": "s3cr3t"}`) facts, err := ReadStoreFacts(path) if err != nil { t.Fatal(err) @@ -75,10 +75,10 @@ func TestAnAttachmentIsKeptOnceByItsHash(t *testing.T) { if err != nil { t.Fatal(err) } - if a.Key != b.Key || a.Bucket != "mesh-novox-mail" || puts != 1 || len(a.Key) != 64 { + if a.Key != b.Key || a.Bucket != "mesh-node-c-mail" || puts != 1 || len(a.Key) != 64 { t.Fatalf("%+v %+v, %d put(s)", a, b, puts) } - if _, ok := kept["/mesh-novox-mail/"+a.Key]; !ok { + if _, ok := kept["/mesh-node-c-mail/"+a.Key]; !ok { t.Fatalf("kept %v", kept) } got, err := s3.Get(ctx, a.Key) diff --git a/modules/mesh-mail/cmd/mesh-mail/search_test.go b/modules/mesh-mail/cmd/mesh-mail/search_test.go index 62f8fce5..6a84256f 100644 --- a/modules/mesh-mail/cmd/mesh-mail/search_test.go +++ b/modules/mesh-mail/cmd/mesh-mail/search_test.go @@ -29,66 +29,66 @@ func searchFixtures() []Message { return []Message{ // mesh/INBOX ------------------------------------------------------------------------------------------------ {Account: "mesh", Folder: "INBOX", UID: 1, MessageID: "", Subject: "October invoice", - Date: at(9, 0), From: []Person{{Name: "Bob", Address: "bob@example.org"}}, To: []Person{{Address: "jschoubben@novox.be"}}, + Date: at(9, 0), From: []Person{{Name: "Bob", Address: "bob@example.org"}}, To: []Person{{Address: "jschoubben@node-c.be"}}, Flags: []string{}, Attachments: []AttachmentRef{{Bucket: "mail", Key: "a1", Size: 1200, Type: "application/pdf", Name: "invoice.pdf"}}, Body: "please settle the invoice, due at month end", Size: 1500}, {Account: "mesh", Folder: "INBOX", UID: 2, MessageID: "", Subject: "renovatie plannen", Date: time.Date(2026, 9, 1, 8, 0, 0, 0, time.UTC), From: []Person{{Name: "Alice", Address: "alice@example.org"}}, - To: []Person{{Address: "bob@example.org"}}, Cc: []Person{{Address: "jschoubben@novox.be"}}, + To: []Person{{Address: "bob@example.org"}}, Cc: []Person{{Address: "jschoubben@node-c.be"}}, Flags: []string{"\\Seen"}, Attachments: []AttachmentRef{}, Body: "over de renovatie van de keuken", Size: 900}, {Account: "mesh", Folder: "INBOX", UID: 3, MessageID: "", Subject: "renovatie herinnering", Date: time.Date(2026, 9, 2, 8, 0, 0, 0, time.UTC), From: []Person{{Name: "Alice", Address: "alice@example.org"}}, - To: []Person{{Address: "jschoubben@novox.be"}}, Flags: []string{"\\Seen"}, Attachments: []AttachmentRef{}, + To: []Person{{Address: "jschoubben@node-c.be"}}, Flags: []string{"\\Seen"}, Attachments: []AttachmentRef{}, Body: "nog een vraag over de renovatie", Size: 800}, {Account: "mesh", Folder: "INBOX", UID: 4, MessageID: "", Subject: "security alert", Date: time.Date(2026, 10, 15, 7, 0, 0, 0, time.UTC), From: []Person{{Name: "Carol", Address: "carol@google.com"}}, - To: []Person{{Address: "jschoubben@novox.be"}}, Flags: []string{"\\Seen"}, Attachments: []AttachmentRef{}, + To: []Person{{Address: "jschoubben@node-c.be"}}, Flags: []string{"\\Seen"}, Attachments: []AttachmentRef{}, Body: "someone logged into your account from a new device", Size: 600}, {Account: "mesh", Folder: "INBOX", UID: 5, MessageID: "", Subject: "team meeting invite", - Date: at(8, 0), From: []Person{{Name: "Dave", Address: "dave@example.org"}}, To: []Person{{Address: "jschoubben@novox.be"}}, + Date: at(8, 0), From: []Person{{Name: "Dave", Address: "dave@example.org"}}, To: []Person{{Address: "jschoubben@node-c.be"}}, Flags: []string{"\\Seen"}, Attachments: []AttachmentRef{{Bucket: "mail", Key: "a2", Size: 300, Type: "text/calendar", Name: "meeting.ics"}}, Body: "please join the planning meeting", Size: 700}, {Account: "mesh", Folder: "INBOX", UID: 6, MessageID: "", InReplyTo: "", Subject: "Re: quick note", - Date: at(12, 30), From: []Person{{Name: "Bob", Address: "bob@example.org"}}, To: []Person{{Address: "jschoubben@novox.be"}}, + Date: at(12, 30), From: []Person{{Name: "Bob", Address: "bob@example.org"}}, To: []Person{{Address: "jschoubben@node-c.be"}}, Flags: []string{}, Attachments: []AttachmentRef{}, Body: "sounds good, thanks for the note", Size: 400}, // 1229/AC5: from a domain (google.com), has-attachment, name *.pdf and the word "factuur" — in the // subject only (review round 1 finding 3), so Words's "subject or body" is genuinely exercised, not // merely a body match that would pass even with a subject-only bug. {Account: "mesh", Folder: "INBOX", UID: 7, MessageID: "", Subject: "the factuur for Q3", - Date: at(13, 0), From: []Person{{Name: "Erik", Address: "erik@google.com"}}, To: []Person{{Address: "jschoubben@novox.be"}}, + Date: at(13, 0), From: []Person{{Name: "Erik", Address: "erik@google.com"}}, To: []Person{{Address: "jschoubben@node-c.be"}}, Flags: []string{}, Attachments: []AttachmentRef{{Bucket: "mail", Key: "a4", Size: 200, Type: "application/pdf", Name: "factuur.pdf"}}, Body: "see the attached file, due on receipt", Size: 850}, // 1229/AC12: a word with digits and a dash ("4711-882"), matched whole, in the subject only (review // round 1 finding 3). {Account: "mesh", Folder: "INBOX", UID: 8, MessageID: "", Subject: "order 4711-882 confirmed", - Date: at(14, 0), From: []Person{{Address: "ops@example.org"}}, To: []Person{{Address: "jschoubben@novox.be"}}, + Date: at(14, 0), From: []Person{{Address: "ops@example.org"}}, To: []Person{{Address: "jschoubben@node-c.be"}}, Flags: []string{}, Attachments: []AttachmentRef{}, Body: "your order has shipped", Size: 300}, // Control for 1229/AC12: "4711" and "882" appear as separate tokens, never hyphenated together. {Account: "mesh", Folder: "INBOX", UID: 9, MessageID: "", Subject: "order 4711 shipped, item 882 noted", - Date: at(14, 5), From: []Person{{Address: "ops@example.org"}}, To: []Person{{Address: "jschoubben@novox.be"}}, + Date: at(14, 5), From: []Person{{Address: "ops@example.org"}}, To: []Person{{Address: "jschoubben@node-c.be"}}, Flags: []string{}, Attachments: []AttachmentRef{}, Body: "item 4711 and item 882 are unrelated", Size: 300}, // 1229/AC15 (the "any" word list): only "verzekering" is present, not "schade" — in the subject only // (review round 1 finding 3) — with an attachment. {Account: "mesh", Folder: "INBOX", UID: 10, MessageID: "", Subject: "verzekering aanvraag", - Date: at(14, 10), From: []Person{{Address: "broker@example.org"}}, To: []Person{{Address: "jschoubben@novox.be"}}, + Date: at(14, 10), From: []Person{{Address: "broker@example.org"}}, To: []Person{{Address: "jschoubben@node-c.be"}}, Flags: []string{}, Attachments: []AttachmentRef{{Bucket: "mail", Key: "a5", Size: 150, Type: "application/pdf", Name: "polis.pdf"}}, Body: "nieuwe polis aanvraag", Size: 450}, // mesh/Sent --------------------------------------------------------------------------------------------------- {Account: "mesh", Folder: "Sent", UID: 1, MessageID: "", InReplyTo: "", Subject: "Re: October invoice", - Date: at(10, 0), From: []Person{{Address: "jschoubben@novox.be"}}, To: []Person{{Address: "bob@example.org"}}, + Date: at(10, 0), From: []Person{{Address: "jschoubben@node-c.be"}}, To: []Person{{Address: "bob@example.org"}}, Flags: []string{"\\Seen"}, Attachments: []AttachmentRef{}, Body: "paid, thank you", Size: 300}, {Account: "mesh", Folder: "Sent", UID: 2, MessageID: "", Subject: "quick note", - Date: time.Date(2026, 10, 18, 9, 0, 0, 0, time.UTC), From: []Person{{Address: "jschoubben@novox.be"}}, + Date: time.Date(2026, 10, 18, 9, 0, 0, 0, time.UTC), From: []Person{{Address: "jschoubben@node-c.be"}}, To: []Person{{Address: "bob@example.org"}}, Flags: []string{"\\Seen"}, Attachments: []AttachmentRef{}, Body: "just checking in", Size: 250}, // mesh/Junk --------------------------------------------------------------------------------------------------- {Account: "mesh", Folder: "Junk", UID: 1, MessageID: "", Subject: "special offer just for you", Date: time.Date(2026, 10, 10, 6, 0, 0, 0, time.UTC), From: []Person{{Address: "bob@example.org"}}, - To: []Person{{Address: "jschoubben@novox.be"}}, Flags: []string{}, Attachments: []AttachmentRef{}, Body: "buy now and save big", Size: 500}, + To: []Person{{Address: "jschoubben@node-c.be"}}, Flags: []string{}, Attachments: []AttachmentRef{}, Body: "buy now and save big", Size: 500}, {Account: "mesh", Folder: "Junk", UID: 2, MessageID: "", Subject: "you won the lottery", Date: time.Date(2026, 10, 10, 6, 5, 0, 0, time.UTC), From: []Person{{Address: "spam@unknown.com"}}, - To: []Person{{Address: "jschoubben@novox.be"}}, Flags: []string{}, Attachments: []AttachmentRef{}, Body: "claim your prize now", Size: 500}, + To: []Person{{Address: "jschoubben@node-c.be"}}, Flags: []string{}, Attachments: []AttachmentRef{}, Body: "claim your prize now", Size: 500}, // gmail/INBOX ------------------------------------------------------------------------------------------------- {Account: "gmail", Folder: "INBOX", UID: 1, MessageID: "", Subject: "security alert for your account", @@ -134,7 +134,7 @@ func searchFixtures() []Message { // mesh/Junk (review round 1 finding 2): someone@example.org, written to only by gmail's Sent, not mesh's. {Account: "mesh", Folder: "Junk", UID: 3, MessageID: "", Subject: "a gmail contact's junk mail", Date: time.Date(2026, 10, 11, 6, 0, 0, 0, time.UTC), From: []Person{{Address: "someone@example.org"}}, - To: []Person{{Address: "jschoubben@novox.be"}}, Flags: []string{}, Attachments: []AttachmentRef{}, Body: "unrelated offer", Size: 500}, + To: []Person{{Address: "jschoubben@node-c.be"}}, Flags: []string{}, Attachments: []AttachmentRef{}, Body: "unrelated offer", Size: 500}, // gmail/Junk (review round 1 finding 1): the same someone@example.org, but here it is gmail's own // account, whose "[Gmail]/Sent Mail" did write to this address — so this one must match. @@ -242,7 +242,7 @@ func TestSearchFiltersByCcNotTo(t *testing.T) { eachStore(t, func(t *testing.T, st Store) { ctx := context.Background() addFixtures(t, ctx, st) - got, err := st.Search(ctx, Query{Accounts: []string{"mesh"}, Cc: "jschoubben@novox.be", Limit: 10}) + got, err := st.Search(ctx, Query{Accounts: []string{"mesh"}, Cc: "jschoubben@node-c.be", Limit: 10}) if err != nil { t.Fatal(err) } @@ -280,7 +280,7 @@ func TestSearchFiltersByCcAndSubjectOrBodyWord(t *testing.T) { eachStore(t, func(t *testing.T, st Store) { ctx := context.Background() addFixtures(t, ctx, st) - got, err := st.Search(ctx, Query{Accounts: []string{"mesh"}, Cc: "jschoubben@novox.be", Words: []string{"renovatie"}, Limit: 10}) + got, err := st.Search(ctx, Query{Accounts: []string{"mesh"}, Cc: "jschoubben@node-c.be", Words: []string{"renovatie"}, Limit: 10}) if err != nil { t.Fatal(err) } @@ -502,7 +502,7 @@ func TestSearchOrdersBySenderAndSubject(t *testing.T) { if err != nil { t.Fatal(err) } - // Both Sent messages share the same sender (jschoubben@novox.be): the tie-break (account, folder, uid) + // Both Sent messages share the same sender (jschoubben@node-c.be): the tie-break (account, folder, uid) // orders them by uid ascending. sameOrder(t, bySender, "", "") @@ -755,10 +755,10 @@ func TestSearchWithNoFolderAnswersTheSameMessageIDOncePerAccount(t *testing.T) { ctx := context.Background() for _, m := range []Message{ {Account: "mesh", Folder: "Sent", UID: 50, MessageID: "", Subject: "cross-account", - Date: at1248(9, 0), From: []Person{{Address: "jschoubben@novox.be"}}, To: []Person{{Address: "me@gmail.example"}}, + Date: at1248(9, 0), From: []Person{{Address: "jschoubben@node-c.be"}}, To: []Person{{Address: "me@gmail.example"}}, Flags: []string{}, Attachments: []AttachmentRef{}}, {Account: "gmail", Folder: "INBOX", UID: 50, MessageID: "", Subject: "cross-account", - Date: at1248(9, 1), From: []Person{{Address: "jschoubben@novox.be"}}, To: []Person{{Address: "me@gmail.example"}}, + Date: at1248(9, 1), From: []Person{{Address: "jschoubben@node-c.be"}}, To: []Person{{Address: "me@gmail.example"}}, Flags: []string{}, Attachments: []AttachmentRef{}}, } { if err := st.Add(ctx, m, nil); err != nil { diff --git a/modules/mesh-mail/cmd/mesh-mail/secret_boundary_test.go b/modules/mesh-mail/cmd/mesh-mail/secret_boundary_test.go index 6dd6d1b5..dadc6331 100644 --- a/modules/mesh-mail/cmd/mesh-mail/secret_boundary_test.go +++ b/modules/mesh-mail/cmd/mesh-mail/secret_boundary_test.go @@ -85,15 +85,15 @@ func TestTheToolPathSucceedsWithTheSecretsDirectoryAbsent(t *testing.T) { dir := t.TempDir() missing := filepath.Join(dir, "never-created") env := Env{Accounts: filepath.Join(dir, "accounts.json"), Grants: filepath.Join(dir, "grants.json"), Secrets: missing} - writeFile(t, env.Accounts, `{"accounts": {"mesh": {"kind": "imap", "address": "jschoubben@novox.be", - "incoming": {"host": "mail.novox.be", "port": 993, "security": "tls"}, + writeFile(t, env.Accounts, `{"accounts": {"mesh": {"kind": "imap", "address": "jschoubben@node-c.be", + "incoming": {"host": "mail.node-c.be", "port": 993, "security": "tls"}, "outgoing": {"host": "h", "port": 465, "security": "tls"}}}}`) writeFile(t, env.Grants, `{"grants": {"mesh": ["triage"]}}`) router, sends, queue := newSendRouter(), newMemSends(), newMemQueue() b := &Bundle{Env: env, Now: func() time.Time { return judgedAt }, Asks: router, Sends: sends, Queue: queue.publish} rt := startBundle(t, b.Tools()) - text, isErr := rt.call(SendTool, "novox.triage", sendArgs) + text, isErr := rt.call(SendTool, "node-c.triage", sendArgs) if isErr { t.Fatalf("mail_send: %s", text) } @@ -114,7 +114,7 @@ func TestTheToolPathSucceedsWithTheSecretsDirectoryAbsent(t *testing.T) { t.Fatalf("the decision names a secret file: %q", d.Outcome) } - text, isErr = rt.call(SendStatusTool, "novox.triage", map[string]any{"id": id}) + text, isErr = rt.call(SendStatusTool, "node-c.triage", map[string]any{"id": id}) if isErr { t.Fatalf("mail_send_status: %s", text) } diff --git a/modules/mesh-mail/cmd/mesh-mail/send_test.go b/modules/mesh-mail/cmd/mesh-mail/send_test.go index ea27bbc4..b6602490 100644 --- a/modules/mesh-mail/cmd/mesh-mail/send_test.go +++ b/modules/mesh-mail/cmd/mesh-mail/send_test.go @@ -349,8 +349,8 @@ func sendTestBundle(t *testing.T, outgoing Server) (*Bundle, *sendRouter, *memSe t.Helper() dir := t.TempDir() env := Env{Accounts: filepath.Join(dir, "accounts.json"), Grants: filepath.Join(dir, "grants.json"), Secrets: dir} - writeFile(t, env.Accounts, fmt.Sprintf(`{"accounts": {"mesh": {"kind": "imap", "address": "jschoubben@novox.be", - "incoming": {"host": "mail.novox.be", "port": 993, "security": "tls"}, + writeFile(t, env.Accounts, fmt.Sprintf(`{"accounts": {"mesh": {"kind": "imap", "address": "jschoubben@node-c.be", + "incoming": {"host": "mail.node-c.be", "port": 993, "security": "tls"}, "outgoing": {"host": %q, "port": %d, "security": %q}}}}`, outgoing.Host, outgoing.Port, outgoing.Security)) writeFile(t, env.Grants, `{"grants": {"mesh": ["triage"]}}`) giveSecret(t, dir, Account{Name: "mesh"}, "the-password") @@ -366,7 +366,7 @@ var sendArgs = map[string]any{"account": "mesh", "to": []any{"ops@example.org", func TestMailSendRefusesAnUngrantedCallerAndRaisesNoAsk(t *testing.T) { b, router, _ := sendTestBundle(t, Server{Host: "127.0.0.1", Port: 25, Security: "tls"}) rt := startBundle(t, b.Tools()) - text, isErr := rt.call(SendTool, "novox.other", sendArgs) + text, isErr := rt.call(SendTool, "node-c.other", sendArgs) if !isErr || !strings.Contains(text, "refused") || !strings.Contains(text, "mesh") { t.Fatalf("%v %s", isErr, text) } @@ -381,7 +381,7 @@ func TestMailSendRefusesAnUngrantedCallerAndRaisesNoAsk(t *testing.T) { func TestMailSendAsksWithTheAccountRecipientsSubjectAndFirstLines(t *testing.T) { b, router, _ := sendTestBundle(t, Server{Host: "127.0.0.1", Port: 25, Security: "tls"}) rt := startBundle(t, b.Tools()) - text, isErr := rt.call(SendTool, "novox.triage", sendArgs) + text, isErr := rt.call(SendTool, "node-c.triage", sendArgs) if isErr { t.Fatalf("%s", text) } @@ -425,7 +425,7 @@ func TestOnApproveTheSendIsQueuedExactlyOnceEvenDeliveredTwice(t *testing.T) { b.Queue = queue.publish rt := startBundle(t, b.Tools()) - text, isErr := rt.call(SendTool, "novox.triage", sendArgs) + text, isErr := rt.call(SendTool, "node-c.triage", sendArgs) if isErr { t.Fatalf("%s", text) } @@ -457,7 +457,7 @@ func TestOnApproveTheSendIsQueuedExactlyOnceEvenDeliveredTwice(t *testing.T) { // mail_send_status reports it waiting on the sender, and reports the same thing again without queueing a // third time. - text, isErr = rt.call(SendStatusTool, "novox.triage", map[string]any{"id": id}) + text, isErr = rt.call(SendStatusTool, "node-c.triage", map[string]any{"id": id}) if isErr || !strings.Contains(text, `"status":"waiting"`) { t.Fatalf("%v %s", isErr, text) } @@ -473,7 +473,7 @@ func TestOnDeclineNothingIsQueuedAndTheStatusSaysDeclined(t *testing.T) { b.Queue = queue.publish rt := startBundle(t, b.Tools()) - text, isErr := rt.call(SendTool, "novox.triage", sendArgs) + text, isErr := rt.call(SendTool, "node-c.triage", sendArgs) if isErr { t.Fatalf("%s", text) } @@ -490,7 +490,7 @@ func TestOnDeclineNothingIsQueuedAndTheStatusSaysDeclined(t *testing.T) { t.Fatalf("the queue received %d message(s) on Decline", n) } - text, isErr = rt.call(SendStatusTool, "novox.triage", map[string]any{"id": id}) + text, isErr = rt.call(SendStatusTool, "node-c.triage", map[string]any{"id": id}) if isErr || !strings.Contains(text, `"status":"declined"`) { t.Fatalf("%v %s", isErr, text) } @@ -505,7 +505,7 @@ func TestMailSendRefusesAnAccountWithNoOutgoingServer(t *testing.T) { router := newSendRouter() b := &Bundle{Env: env, Now: func() time.Time { return judgedAt }, Asks: router, Sends: newMemSends()} rt := startBundle(t, b.Tools()) - text, isErr := rt.call(SendTool, "novox.triage", sendArgs) + text, isErr := rt.call(SendTool, "node-c.triage", sendArgs) if !isErr || !strings.Contains(text, "no outgoing server") { t.Fatalf("%v %s", isErr, text) } @@ -522,7 +522,7 @@ func TestAnApprovedSendIsQueuedOnceWithNoStatusCall(t *testing.T) { b.Queue = queue.publish rt := startBundle(t, b.Tools()) - text, isErr := rt.call(SendTool, "novox.triage", sendArgs) + text, isErr := rt.call(SendTool, "node-c.triage", sendArgs) if isErr { t.Fatalf("%s", text) } @@ -551,7 +551,7 @@ func TestSweepActsOnAnApprovedSendItWasNotToldAboutDirectly(t *testing.T) { b.Queue = queue.publish rt := startBundle(t, b.Tools()) - text, isErr := rt.call(SendTool, "novox.triage", sendArgs) + text, isErr := rt.call(SendTool, "node-c.triage", sendArgs) if isErr { t.Fatalf("%s", text) } @@ -585,7 +585,7 @@ func TestSweepPublishesAgainAQueuedRecordPastItsGrace(t *testing.T) { b.Queue = queue.publish rt := startBundle(t, b.Tools()) - text, isErr := rt.call(SendTool, "novox.triage", sendArgs) + text, isErr := rt.call(SendTool, "node-c.triage", sendArgs) if isErr { t.Fatalf("%s", text) } @@ -632,7 +632,7 @@ func TestAStaleSendingClaimIsNotProvenNotWaiting(t *testing.T) { b, _, sends := sendTestBundle(t, Server{Host: "127.0.0.1", Port: 25, Security: "tls"}) rt := startBundle(t, b.Tools()) - text, isErr := rt.call(SendTool, "novox.triage", sendArgs) + text, isErr := rt.call(SendTool, "node-c.triage", sendArgs) if isErr { t.Fatalf("%s", text) } @@ -650,7 +650,7 @@ func TestAStaleSendingClaimIsNotProvenNotWaiting(t *testing.T) { t.Fatalf("%v", err) } - text, isErr = rt.call(SendStatusTool, "novox.triage", map[string]any{"id": id}) + text, isErr = rt.call(SendStatusTool, "node-c.triage", map[string]any{"id": id}) if isErr { t.Fatalf("%s", text) } @@ -670,14 +670,14 @@ func TestMailSendRefusesAControlCharacterInTheSubjectOrAnAddress(t *testing.T) { bySubject := map[string]any{"account": "mesh", "to": []any{"ops@example.org"}, "subject": "Report\r\nBcc: attacker@example.org", "body": "body"} - text, isErr := rt.call(SendTool, "novox.triage", bySubject) + text, isErr := rt.call(SendTool, "node-c.triage", bySubject) if !isErr || !strings.Contains(text, "control character") { t.Fatalf("a subject with a control character was not refused: %v %s", isErr, text) } byAddress := map[string]any{"account": "mesh", "to": []any{"ops@example.org\r\nBcc: attacker@example.org"}, "subject": "Report", "body": "body"} - text, isErr = rt.call(SendTool, "novox.triage", byAddress) + text, isErr = rt.call(SendTool, "node-c.triage", byAddress) if !isErr || !strings.Contains(text, "control character") { t.Fatalf("an address with a control character was not refused: %v %s", isErr, text) } @@ -689,7 +689,7 @@ func TestMailSendRefusesAControlCharacterInTheSubjectOrAnAddress(t *testing.T) { // is where SendMail is actually called from. func TestSendUsesTheParsedAddressForRcptAndTheFormattedAddressForTheToHeader(t *testing.T) { fake := newFakeSMTPServer(t) - acc := Account{Name: "mesh", Address: "jschoubben@novox.be", Outgoing: &Server{Host: "127.0.0.1", Port: 25, Security: "tls"}} + acc := Account{Name: "mesh", Address: "jschoubben@node-c.be", Outgoing: &Server{Host: "127.0.0.1", Port: 25, Security: "tls"}} if err := SendMail(fake.dialer(), acc, "the-password", []string{"Ops Team "}, "Status", "body", judgedAt, "send-abc123"); err != nil { t.Fatalf("SendMail: %v", err) } @@ -710,7 +710,7 @@ func TestASendWhoseAskNeverPublishedEndsAfterTheAskWouldHaveLasted(t *testing.T) router.publishErr = errors.New("the bus is down") rt := startBundle(t, b.Tools()) - _, isErr := rt.call(SendTool, "novox.triage", sendArgs) + _, isErr := rt.call(SendTool, "node-c.triage", sendArgs) if !isErr { t.Fatalf("mail_send did not report the publish failure") } @@ -731,7 +731,7 @@ func TestASendWhoseAskNeverPublishedEndsAfterTheAskWouldHaveLasted(t *testing.T) } // Before the ask would have lasted, it still reads waiting: the router may yet come up and record it. - text, isErr := rt.call(SendStatusTool, "novox.triage", map[string]any{"id": id}) + text, isErr := rt.call(SendStatusTool, "node-c.triage", map[string]any{"id": id}) if isErr || !strings.Contains(text, `"status":"waiting"`) { t.Fatalf("before expiry: %v %s", isErr, text) } @@ -739,7 +739,7 @@ func TestASendWhoseAskNeverPublishedEndsAfterTheAskWouldHaveLasted(t *testing.T) // Once a sweep runs after the ask would have lasted, it settles as ended, and nothing was sent. b.Sweep(judgedAt.Add(SendAskLasts + time.Minute)) - text, isErr = rt.call(SendStatusTool, "novox.triage", map[string]any{"id": id}) + text, isErr = rt.call(SendStatusTool, "node-c.triage", map[string]any{"id": id}) if isErr { t.Fatalf("%s", text) } @@ -758,7 +758,7 @@ func TestSweepReadsOnlyUndecidedSends(t *testing.T) { rt := startBundle(t, b.Tools()) // One send, declined right away: decided, so it leaves the undecided index. - text, isErr := rt.call(SendTool, "novox.triage", sendArgs) + text, isErr := rt.call(SendTool, "node-c.triage", sendArgs) if isErr { t.Fatalf("%s", text) } @@ -772,7 +772,7 @@ func TestSweepReadsOnlyUndecidedSends(t *testing.T) { } // A second send, left undecided: still waiting on the operator. - text, isErr = rt.call(SendTool, "novox.triage", sendArgs) + text, isErr = rt.call(SendTool, "node-c.triage", sendArgs) if isErr { t.Fatalf("%s", text) } @@ -798,7 +798,7 @@ func TestMailSendRefusesWhenTheUndecidedIndexCannotBeWritten(t *testing.T) { sends.failKey, sends.failErr = undecidedIndexKey, errors.New("the store is down") rt := startBundle(t, b.Tools()) - text, isErr := rt.call(SendTool, "novox.triage", sendArgs) + text, isErr := rt.call(SendTool, "node-c.triage", sendArgs) if !isErr { t.Fatalf("mail_send did not report the undecided index failing to write: %s", text) } @@ -838,7 +838,7 @@ func TestADigestMismatchIsRefusedAndNothingIsQueued(t *testing.T) { b.Queue = queue.publish rt := startBundle(t, b.Tools()) - text, isErr := rt.call(SendTool, "novox.triage", sendArgs) + text, isErr := rt.call(SendTool, "node-c.triage", sendArgs) if isErr { t.Fatalf("%s", text) } @@ -870,7 +870,7 @@ func TestSendStatusAnswersTheCallersOwnSendInFull(t *testing.T) { b, _, _ := sendTestBundle(t, Server{Host: "127.0.0.1", Port: 25, Security: "tls"}) rt := startBundle(t, b.Tools()) - text, isErr := rt.call(SendTool, "novox.triage", sendArgs) + text, isErr := rt.call(SendTool, "node-c.triage", sendArgs) if isErr { t.Fatalf("%s", text) } @@ -878,7 +878,7 @@ func TestSendStatusAnswersTheCallersOwnSendInFull(t *testing.T) { _ = json.Unmarshal([]byte(text), &out) id := out["ask"].(string) - text, isErr = rt.call(SendStatusTool, "novox.triage", map[string]any{"id": id}) + text, isErr = rt.call(SendStatusTool, "node-c.triage", map[string]any{"id": id}) if isErr { t.Fatalf("%s", text) } @@ -901,7 +901,7 @@ func TestSendStatusAnswersUnknownAndNothingElseToAnotherCaller(t *testing.T) { b, _, _ := sendTestBundle(t, Server{Host: "127.0.0.1", Port: 25, Security: "tls"}) rt := startBundle(t, b.Tools()) - text, isErr := rt.call(SendTool, "novox.triage", sendArgs) + text, isErr := rt.call(SendTool, "node-c.triage", sendArgs) if isErr { t.Fatalf("%s", text) } @@ -909,7 +909,7 @@ func TestSendStatusAnswersUnknownAndNothingElseToAnotherCaller(t *testing.T) { _ = json.Unmarshal([]byte(text), &out) id := out["ask"].(string) - text, isErr = rt.call(SendStatusTool, "novox.someone-else", map[string]any{"id": id}) + text, isErr = rt.call(SendStatusTool, "node-c.someone-else", map[string]any{"id": id}) if isErr { t.Fatalf("another caller's read of the send was an error: %s", text) } @@ -927,7 +927,7 @@ func TestSendStatusAnswersUnknownForAnUnknownIDWithoutAnError(t *testing.T) { b, _, _ := sendTestBundle(t, Server{Host: "127.0.0.1", Port: 25, Security: "tls"}) rt := startBundle(t, b.Tools()) - text, isErr := rt.call(SendStatusTool, "novox.triage", map[string]any{"id": "send-0000000000000000"}) + text, isErr := rt.call(SendStatusTool, "node-c.triage", map[string]any{"id": "send-0000000000000000"}) if isErr { t.Fatalf("an unknown id was an error: %s", text) } @@ -944,7 +944,7 @@ func TestSendStatusAnswersUnknownForAnUnknownIDWithoutAnError(t *testing.T) { // not proven, declined, expired), answered to the send's own caller. func TestSendStatusWordsAreTheFixedVocabularyForTheCallersOwnSend(t *testing.T) { sends := newMemSends() - const caller = "novox.triage" + const caller = "node-c.triage" cases := []struct { name, outcome, want string }{ @@ -981,7 +981,7 @@ func TestSeatSendStatusAnswersExactlyAsMailSendStatus(t *testing.T) { b, _, _ := sendTestBundle(t, Server{Host: "127.0.0.1", Port: 25, Security: "tls"}) rt := startBundle(t, b.Tools()) - text, isErr := rt.call(SendTool, "novox.triage", sendArgs) + text, isErr := rt.call(SendTool, "node-c.triage", sendArgs) if isErr { t.Fatalf("%s", text) } @@ -989,8 +989,8 @@ func TestSeatSendStatusAnswersExactlyAsMailSendStatus(t *testing.T) { _ = json.Unmarshal([]byte(text), &out) id := out["ask"].(string) - toolText, toolErr := rt.call(SendStatusTool, "novox.triage", map[string]any{"id": id}) - seatText, seatErr := rt.call(SeatSendStatusTool, "novox.triage", map[string]any{"id": id}) + toolText, toolErr := rt.call(SendStatusTool, "node-c.triage", map[string]any{"id": id}) + seatText, seatErr := rt.call(SeatSendStatusTool, "node-c.triage", map[string]any{"id": id}) if toolErr != seatErr || toolText != seatText { t.Fatalf("mail_send_status: %v %s; mail-store.send-status: %v %s", toolErr, toolText, seatErr, seatText) } @@ -1004,7 +1004,7 @@ func TestSweepSettlesASendRegardlessOfCaller(t *testing.T) { b.Queue = queue.publish rt := startBundle(t, b.Tools()) - text, isErr := rt.call(SendTool, "novox.triage", sendArgs) + text, isErr := rt.call(SendTool, "node-c.triage", sendArgs) if isErr { t.Fatalf("%s", text) } @@ -1015,7 +1015,7 @@ func TestSweepSettlesASendRegardlessOfCaller(t *testing.T) { w := router.chose(id, OptionSend, judgedAt.Add(time.Minute)) router.close(w) // only the router's record holds the answer - // The sweep itself names no caller at all; it must still settle "novox.triage"'s send. + // The sweep itself names no caller at all; it must still settle "node-c.triage"'s send. b.Sweep(judgedAt.Add(2 * time.Minute)) if n := queue.count(); n != 1 { t.Fatalf("the sweep did not settle the send regardless of caller: %d message(s)", n) diff --git a/modules/mesh-mail/cmd/mesh-mail/sender_integration_test.go b/modules/mesh-mail/cmd/mesh-mail/sender_integration_test.go index e4f9a3ea..ac0260f2 100644 --- a/modules/mesh-mail/cmd/mesh-mail/sender_integration_test.go +++ b/modules/mesh-mail/cmd/mesh-mail/sender_integration_test.go @@ -90,7 +90,7 @@ func TestSendConsumesMailSendsAndStopsCleanlyOnSignal(t *testing.T) { t.Fatal(err) } - account := process.Account{URL: url, Node: "g14", Module: Module, User: "g14." + Module + "." + SendProcessID, Password: "pw"} + account := process.Account{URL: url, Node: "node-b", Module: Module, User: "node-b." + Module + "." + SendProcessID, Password: "pw"} if _, err := js.CreateConsumer(ctx, MailSendsStream, mailSendsConsumerConfig(account.QueueConsumerName())); err != nil { t.Fatal(err) } diff --git a/modules/mesh-mail/cmd/mesh-mail/sender_test.go b/modules/mesh-mail/cmd/mesh-mail/sender_test.go index 5df2f9cb..1c8c4c1d 100644 --- a/modules/mesh-mail/cmd/mesh-mail/sender_test.go +++ b/modules/mesh-mail/cmd/mesh-mail/sender_test.go @@ -12,8 +12,8 @@ import ( // form, when it starts, then it reads the account and the accounts file, and refuses to start naming what // is missing when either is absent. func TestSendRefusesToStartNamingWhatIsMissing(t *testing.T) { - validAccount := `{"url": "nats://127.0.0.1:4222", "node": "g14", "module": "mesh-mail", ` + - `"user": "g14.mesh-mail.send", "password": "pw"}` + validAccount := `{"url": "nats://127.0.0.1:4222", "node": "node-b", "module": "mesh-mail", ` + + `"user": "node-b.mesh-mail.send", "password": "pw"}` t.Run("no secrets directory", func(t *testing.T) { dir := t.TempDir() @@ -57,7 +57,7 @@ func TestSendRefusesToStartNamingWhatIsMissing(t *testing.T) { dir := t.TempDir() env := Env{Accounts: filepath.Join(dir, "accounts.json"), Secrets: dir} writeFile(t, env.Accounts, stageOne) - writeFile(t, filepath.Join(dir, "broker-send.secret"), `{"url": "nats://127.0.0.1:4222", "node": "g14", "module": "mesh-mail"}`) + writeFile(t, filepath.Join(dir, "broker-send.secret"), `{"url": "nats://127.0.0.1:4222", "node": "node-b", "module": "mesh-mail"}`) code := send(env) if code == 0 { t.Fatal("send started with an own account missing its user and password") diff --git a/modules/mesh-mail/cmd/mesh-mail/smtp_classify_test.go b/modules/mesh-mail/cmd/mesh-mail/smtp_classify_test.go index 97bc90f5..af04bb9b 100644 --- a/modules/mesh-mail/cmd/mesh-mail/smtp_classify_test.go +++ b/modules/mesh-mail/cmd/mesh-mail/smtp_classify_test.go @@ -139,7 +139,7 @@ func classifyTestAccount(addr string) Account { host, portStr, _ := net.SplitHostPort(addr) var port int _, _ = fmt.Sscanf(portStr, "%d", &port) - return Account{Name: "mesh", Address: "jschoubben@novox.be", Outgoing: &Server{Host: host, Port: port, Security: "tls"}} + return Account{Name: "mesh", Address: "jschoubben@node-c.be", Outgoing: &Server{Host: host, Port: port, Security: "tls"}} } func outcomeOf(t *testing.T, err error) SendOutcome { @@ -234,8 +234,8 @@ func TestSendMailSaysNotProvenWhenTheConnectionIsLostAfterTheDataWasWritten(t *t // (@). Proved both in isolation (composeMessage) and over the wire // (SendMail, with the existing fakeSMTPServer, which keeps the body it received). func TestComposeMessageCarriesTheSendIDInItsMessageID(t *testing.T) { - raw := composeMessage("jschoubben@novox.be", []string{"a@b.c"}, "s", "body", judgedAt, "send-abc123") - if !strings.Contains(string(raw), "Message-Id: ") { + raw := composeMessage("jschoubben@node-c.be", []string{"a@b.c"}, "s", "body", judgedAt, "send-abc123") + if !strings.Contains(string(raw), "Message-Id: ") { t.Fatalf("the message does not carry the send id's Message-ID:\n%s", raw) } } @@ -256,7 +256,7 @@ func TestSendMailCarriesTheMessageIDOverTheWire(t *testing.T) { t.Fatalf("SendMail: %v", err) } got := fake.last() - if !strings.Contains(got.data, "Message-Id: ") { + if !strings.Contains(got.data, "Message-Id: ") { t.Fatalf("the message sent does not carry the send id's Message-ID:\n%s", got.data) } } diff --git a/modules/mesh-mail/cmd/mesh-mail/tools_test.go b/modules/mesh-mail/cmd/mesh-mail/tools_test.go index 747b1d30..dbbf3574 100644 --- a/modules/mesh-mail/cmd/mesh-mail/tools_test.go +++ b/modules/mesh-mail/cmd/mesh-mail/tools_test.go @@ -133,7 +133,7 @@ func aBundle(t *testing.T) (*Bundle, *memStore, *memObjects) { t.Fatal(err) } m := Message{Account: "mesh", Folder: "INBOX", UID: 7, UIDValidity: 1, MessageID: "att@example.org", Subject: "the invoice", - Date: judgedAt, From: []Person{{Name: "Bob", Address: "bob@example.org"}}, To: []Person{{Address: "jschoubben@novox.be"}}, + Date: judgedAt, From: []Person{{Name: "Bob", Address: "bob@example.org"}}, To: []Person{{Address: "jschoubben@node-c.be"}}, Flags: []string{}, Attachments: []AttachmentRef{ref}, Body: "Please find the invoice attached."} if err := st.Add(ctx, m, addedEvent(m)); err != nil { t.Fatal(err) @@ -151,11 +151,11 @@ func TestTheBodyToolsAnswerAGrantedCallerAndRefuseAnyOther(t *testing.T) { rt := startBundle(t, b.Tools()) read := map[string]any{"account": "mesh", "folder": "INBOX", "uid": 7} - text, isErr := rt.call(ReadTool, "novox.triage", read) + text, isErr := rt.call(ReadTool, "node-c.triage", read) if isErr || !strings.Contains(text, "Please find the invoice attached.") || !strings.Contains(text, `"subject":"the invoice"`) { t.Fatalf("granted: %v %s", isErr, text) } - for _, caller := range []string{"novox.other", "person.someone", Unproven} { + for _, caller := range []string{"node-c.other", "person.someone", Unproven} { text, isErr := rt.call(ReadTool, caller, read) if !isErr || !strings.Contains(text, "refused") || strings.Contains(text, "Please find") { t.Fatalf("%s: %v %s", caller, isErr, text) @@ -166,11 +166,11 @@ func TestTheBodyToolsAnswerAGrantedCallerAndRefuseAnyOther(t *testing.T) { } } // An argument cannot name the caller. - if text, isErr := rt.call(ReadTool, "novox.other", map[string]any{"account": "mesh", "folder": "INBOX", "uid": 7, "caller": "novox.triage"}); !isErr || strings.Contains(text, "Please find") { + if text, isErr := rt.call(ReadTool, "node-c.other", map[string]any{"account": "mesh", "folder": "INBOX", "uid": 7, "caller": "node-c.triage"}); !isErr || strings.Contains(text, "Please find") { t.Fatalf("an argument named the caller: %s", text) } - text, isErr = rt.call(SearchTool, "shanks.triage", map[string]any{"query": "invoice"}) + text, isErr = rt.call(SearchTool, "node-d.triage", map[string]any{"query": "invoice"}) if isErr || !strings.Contains(text, `"message-id":"att@example.org"`) || strings.Contains(text, "Please find") { t.Fatalf("search: %v %s", isErr, text) } @@ -180,7 +180,7 @@ func TestTheBodyToolsAnswerAGrantedCallerAndRefuseAnyOther(t *testing.T) { got, _, _ := m.Get(context.Background(), "mesh", "INBOX", 7) sum = got.Attachments[0].Key } - text, isErr = rt.call(ReadTool, "novox.triage", map[string]any{"account": "mesh", "folder": "INBOX", "uid": 7, "attachment": sum}) + text, isErr = rt.call(ReadTool, "node-c.triage", map[string]any{"account": "mesh", "folder": "INBOX", "uid": 7, "attachment": sum}) var att struct { Base64 string `json:"base64"` } @@ -200,7 +200,7 @@ func TestTheAccountsToolListsOnlyTheAccountsTheCallerIsGranted(t *testing.T) { st, _ := b.Index(context.Background()) _ = st.SetFolder(context.Background(), Folder{Account: "mesh", Name: "Secret-Project", Messages: 41, Synced: judgedAt}) _ = st.SetState(context.Background(), AccountState{Account: "mesh", State: AccountFailing, Why: "the server said NO [AUTHENTICATIONFAILED]", Said: judgedAt}) - text, isErr := rt.call(AccountsTool, "novox.other", map[string]any{}) + text, isErr := rt.call(AccountsTool, "node-c.other", map[string]any{}) if isErr || !strings.Contains(text, `"accounts":[]`) { t.Fatalf("ungranted: %s", text) } @@ -209,8 +209,8 @@ func TestTheAccountsToolListsOnlyTheAccountsTheCallerIsGranted(t *testing.T) { t.Fatalf("an ungranted caller learns %q: %s", leak, text) } } - text, _ = rt.call(AccountsTool, "novox.triage", map[string]any{}) - if !strings.Contains(text, `"address":"jschoubben@novox.be"`) || !strings.Contains(text, "Secret-Project") || !strings.Contains(text, "AUTHENTICATIONFAILED") { + text, _ = rt.call(AccountsTool, "node-c.triage", map[string]any{}) + if !strings.Contains(text, `"address":"jschoubben@node-c.be"`) || !strings.Contains(text, "Secret-Project") || !strings.Contains(text, "AUTHENTICATIONFAILED") { t.Fatalf("granted: %s", text) } } @@ -260,15 +260,15 @@ func TestARefusalSaysWhyTheGrantsCouldNotBeRead(t *testing.T) { b, _, _ := aBundle(t) writeFile(t, b.Env.Grants, `{"grants": {"mesh": "triage"}}`) rt := startBundle(t, b.Tools()) - text, isErr := rt.call(ReadTool, "novox.triage", map[string]any{"account": "mesh", "folder": "INBOX", "uid": 7}) + text, isErr := rt.call(ReadTool, "node-c.triage", map[string]any{"account": "mesh", "folder": "INBOX", "uid": 7}) if !isErr || !strings.Contains(text, "the setting grants cannot be read") || !strings.Contains(text, "not the module's") || strings.Contains(text, "Please find") { t.Fatalf("read: %v %s", isErr, text) } - text, isErr = rt.call(SearchTool, "novox.triage", map[string]any{"query": "invoice"}) + text, isErr = rt.call(SearchTool, "node-c.triage", map[string]any{"query": "invoice"}) if !isErr || !strings.Contains(text, "the setting grants cannot be read") { t.Fatalf("search: %v %s", isErr, text) } - text, _ = rt.call(AccountsTool, "novox.triage", map[string]any{}) + text, _ = rt.call(AccountsTool, "node-c.triage", map[string]any{}) if !strings.Contains(text, "the setting grants cannot be read") || !strings.Contains(text, `"accounts":[]`) { t.Fatalf("accounts: %s", text) } @@ -284,7 +284,7 @@ func TestMailSearchWithNoFilterAnswersTheNewestGrantedMail(t *testing.T) { env := Env{Accounts: filepath.Join(dir, "accounts.json"), Grants: filepath.Join(dir, "grants.json"), Secrets: dir, Status: filepath.Join(dir, "health.json")} writeFile(t, env.Accounts, `{"accounts": { - "mesh": {"kind": "imap", "address": "jschoubben@novox.be", "incoming": {"host": "mail.novox.be", "port": 993, "security": "tls"}}, + "mesh": {"kind": "imap", "address": "jschoubben@node-c.be", "incoming": {"host": "mail.node-c.be", "port": 993, "security": "tls"}}, "gmail": {"kind": "imap", "address": "me@gmail.example", "incoming": {"host": "imap.gmail.com", "port": 993, "security": "tls"}}, "secret": {"kind": "imap", "address": "other@example.org", "incoming": {"host": "mail.example.org", "port": 993, "security": "tls"}}}}`) writeFile(t, env.Grants, `{"grants": {"mesh": ["triage"], "gmail": ["triage"], "secret": ["other"]}}`) @@ -314,7 +314,7 @@ func TestMailSearchWithNoFilterAnswersTheNewestGrantedMail(t *testing.T) { } b := &Bundle{Env: env, Index: func(context.Context) (Store, error) { return st, nil }, Now: func() time.Time { return judgedAt }} rt := startBundle(t, b.Tools()) - text, isErr := rt.call(SearchTool, "novox.triage", map[string]any{"limit": 3}) + text, isErr := rt.call(SearchTool, "node-c.triage", map[string]any{"limit": 3}) if isErr { t.Fatalf("%v %s", isErr, text) } @@ -350,7 +350,7 @@ func TestMailSearchValidatesBeforeAskingTheIndex(t *testing.T) { {"account", map[string]any{"account": "no-such-account"}, "no-such-account"}, } for _, c := range cases { - text, isErr := rt.call(SearchTool, "novox.triage", c.args) + text, isErr := rt.call(SearchTool, "node-c.triage", c.args) if !isErr || !strings.Contains(text, c.want) { t.Fatalf("%s: %v %s", c.name, isErr, text) } @@ -412,12 +412,12 @@ func TestMailSearchEndToEndFiltersAndGroupBySender(t *testing.T) { ctx := context.Background() older := judgedAt.Add(-time.Hour) if err := st.Add(ctx, Message{Account: "mesh", Folder: "INBOX", UID: 1, MessageID: "", Subject: "from alice", - Date: older, From: []Person{{Address: "alice@example.org"}}, To: []Person{{Address: "jschoubben@novox.be"}}, + Date: older, From: []Person{{Address: "alice@example.org"}}, To: []Person{{Address: "jschoubben@node-c.be"}}, Flags: []string{}, Attachments: []AttachmentRef{}, Body: "hi"}, nil); err != nil { t.Fatal(err) } if err := st.Add(ctx, Message{Account: "mesh", Folder: "INBOX", UID: 2, MessageID: "", Subject: "from alice again", - Date: judgedAt, From: []Person{{Address: "alice@example.org"}}, To: []Person{{Address: "jschoubben@novox.be"}}, + Date: judgedAt, From: []Person{{Address: "alice@example.org"}}, To: []Person{{Address: "jschoubben@node-c.be"}}, Flags: []string{"\\Seen"}, Attachments: []AttachmentRef{}, Body: "hi again"}, nil); err != nil { t.Fatal(err) } @@ -425,13 +425,13 @@ func TestMailSearchEndToEndFiltersAndGroupBySender(t *testing.T) { rt := startBundle(t, b.Tools()) unread := true - text, isErr := rt.call(SearchTool, "novox.triage", map[string]any{"from": []any{"example.org"}, "unread": unread, + text, isErr := rt.call(SearchTool, "node-c.triage", map[string]any{"from": []any{"example.org"}, "unread": unread, "order-by": "date", "order": "asc"}) if isErr || !strings.Contains(text, "a@mesh") || strings.Contains(text, "b@mesh") { t.Fatalf("%v %s", isErr, text) } - text, isErr = rt.call(SearchTool, "novox.triage", map[string]any{"group-by-sender": true}) + text, isErr = rt.call(SearchTool, "node-c.triage", map[string]any{"group-by-sender": true}) var grouped struct { Senders []SenderGroup `json:"senders"` } @@ -443,7 +443,7 @@ func TestMailSearchEndToEndFiltersAndGroupBySender(t *testing.T) { // 1232/AC17 (review round 1 finding 5): order-by given, order left out, defaults to desc, as the schema's // own description promises — not asc. "from alice" is a prefix of "from alice again", so ascending would put // first; descending puts first. - text, isErr = rt.call(SearchTool, "novox.triage", map[string]any{"order-by": "subject"}) + text, isErr = rt.call(SearchTool, "node-c.triage", map[string]any{"order-by": "subject"}) if isErr { t.Fatalf("%v %s", isErr, text) }