mesh/merge-gate pass: builds build-agent, mesh-controller, route-proxy → ace, g14, novox, shanks; no bus step; every machine composes with the change as it…
mesh/repo-check pass: its merge-check.sh passed
mesh/delivery-group group fix/383-a-proposal-reads-whole-on-the-phone ready: every member ready, and composed together they pass
mesh/delivery superseded: a newer head of the same pull request
The review of 2026-10-10: a mixed-case path with a digit ("/mnt/Photos_2024/Jochen") read as a
random string and was withheld from the whole words, the symptom again (outward.Secret now judges
a run with a slash piece by piece, as the messenger's CheckSecret does); and the Details line on
masking read, on the phone, as if something there were masked.
126 lines
5.8 KiB
Go
126 lines
5.8 KiB
Go
package outward
|
|
|
|
import (
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
// machines are the names a mesh in these tests has.
|
|
var machines = []string{"anchor", "laptop", "g14", "home-server"}
|
|
|
|
// **The content rule's table** (novox/hq ADR 0234, "machine names pass the content rule; domains,
|
|
// addresses, paths and secrets do not"): the shapes the messenger refuses are refused here, and the
|
|
// words a condition is made of pass — the mesh's machine names among them.
|
|
func TestMachineNamesPassAndAddressesDomainsPathsAndSecretsDoNot(t *testing.T) {
|
|
pass := []string{
|
|
"the mesh's resolver on anchor has not answered for two runs of the self-check",
|
|
"laptop has not been heard from since 2026-10-06 15:02 UTC (bound 3m0s)",
|
|
"g14's node-engine would refuse its declaration whole",
|
|
"home-server runs the node-engine 3f2a9c1b7d0e, the mesh holds 5e6f7a8b9c0d",
|
|
"seat.mesh-dns-resolver.anchor.wrong",
|
|
"anchor/postgres.query answers",
|
|
"3/4 of the consumers are behind; 1200 message(s) behind its stream's head",
|
|
"the plan for novox/app c0ffee00 has been at tier 1 of 2",
|
|
"mesh-controller.conditions key=machine.anchor.silent",
|
|
"backed-up 2 days ago: tank/data shrank to 1.2 GiB",
|
|
}
|
|
for _, text := range pass {
|
|
if r, ok := Check(text, machines...); !ok {
|
|
t.Errorf("refused as %s: %q", r, text)
|
|
}
|
|
}
|
|
refuse := map[string]string{
|
|
"AAAA for anchor: no answer from 10.77.0.1: read udp 10.77.0.3:41234->10.77.0.1:53: i/o timeout": "address",
|
|
"the resolver at [fd00::1]:53 did not answer": "address",
|
|
"fe80::1ff:fe23:4567:890a is banned": "address",
|
|
"anchor.internal answered NXDOMAIN": "address",
|
|
"the store at https://artifacts.example.org/v2 is away": "address",
|
|
"write to jochen@example.org": "address",
|
|
"aa:bb:cc:dd:ee:ff": "address",
|
|
"data at /srv/postgres/data is gone": "path",
|
|
"kept at ~/backups": "path",
|
|
`kept at C:\backups`: "path",
|
|
"password=hunter2": "secret",
|
|
"the token glpat-abcdefghijklmnop12 leaked": "secret",
|
|
"0123456789abcdef0123456789abcdef01": "secret",
|
|
}
|
|
for text, class := range refuse {
|
|
r, ok := Check(text, machines...)
|
|
if ok || r.Class != class {
|
|
t.Errorf("%q: want refused as %s, got %v %v", text, class, r, ok)
|
|
}
|
|
}
|
|
// A machine name joined to a domain is a domain, the machine's name notwithstanding.
|
|
if _, ok := Check("anchor.lan answered", machines...); ok {
|
|
t.Error("a machine's name with a domain passed")
|
|
}
|
|
// And a machine whose name has a shape the rule would otherwise refuse still passes as a name.
|
|
if _, ok := Check("node.internal is silent", "node.internal"); !ok {
|
|
t.Error("a machine name was refused")
|
|
}
|
|
}
|
|
|
|
// **Scrub says what Check refuses in words, and what it gives back always passes** — or is the
|
|
// fallback, never the text as it was.
|
|
func TestScrubAlwaysGivesWhatMayLeave(t *testing.T) {
|
|
for _, text := range []string{
|
|
"AAAA for anchor.internal: no answer from 10.77.0.1: read udp 10.77.0.3:41234->10.77.0.1:53: i/o timeout",
|
|
"dial tcp [fd00::1]:4222: connect: connection refused",
|
|
"open /var/lib/mesh/data/x.db: no such file or directory",
|
|
"GET https://artifacts.example.org/v2/blobs/sha256:0123456789abcdef0123456789abcdef0123456789abcdef: 404",
|
|
"password=hunter2 and a key -----BEGIN PRIVATE KEY-----\nAAAA\n-----END PRIVATE KEY-----",
|
|
"laptop's ban list holds 192.0.2.7 (anchor's endpoint)",
|
|
} {
|
|
got := Scrub(text, "FALLBACK", machines...)
|
|
if r, ok := Check(got, machines...); !ok {
|
|
t.Errorf("Scrub(%q) = %q still refused as %s", text, got, r)
|
|
}
|
|
if got == "FALLBACK" {
|
|
t.Errorf("Scrub(%q) fell back where words could be kept", text)
|
|
}
|
|
}
|
|
if got := Scrub("laptop's ban list holds 192.0.2.7", "", machines...); !strings.HasPrefix(got, "laptop's ban list holds an address") {
|
|
t.Errorf("the machine's name was not kept: %q", got)
|
|
}
|
|
if got := Scrub("nothing wrong with anchor", "", machines...); got != "nothing wrong with anchor" {
|
|
t.Errorf("a text that passes was changed: %q", got)
|
|
}
|
|
}
|
|
|
|
// Secret is the one class that leaves the mesh nowhere (novox/hq issue 383): it refuses every secret's shape
|
|
// Check refuses, and nothing Check refuses as an address or a path — those an ask's whole words may carry.
|
|
func TestSecretRefusesOnlyASecretsShape(t *testing.T) {
|
|
for _, text := range []string{
|
|
"-----BEGIN RSA PRIVATE KEY-----",
|
|
"eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxIn0.abc",
|
|
"123456789:ABCdefGHIjklMNOpqrSTUvwxYZ0123456789ab",
|
|
"ghp_abcdefghijklmnopqrstuvwxyz0123456789",
|
|
"password=hunter2",
|
|
"0123456789abcdef0123456789abcdef",
|
|
"a key xK9mQ2vL8pR4tW7yB3nF6hJ1dG5sA0zC",
|
|
} {
|
|
r, ok := Secret(text)
|
|
if ok || r.Class != "secret" {
|
|
t.Errorf("not refused as a secret: %q (%s)", text, r)
|
|
}
|
|
}
|
|
for _, text := range []string{
|
|
"recalbox=smb://nas.lan/recalbox@/mnt/recalbox:ro",
|
|
"library=/mnt/library",
|
|
"photos=/mnt/Photos_2024/Jochen",
|
|
"games=smb://nas.lan/Recalbox_Games2024",
|
|
"/srv/media/Series_Archive/Season01",
|
|
"10.77.0.9:53",
|
|
"jochen@example.com",
|
|
"C:\\Users\\jo",
|
|
"anchor and the laptop",
|
|
} {
|
|
if r, ok := Secret(text, "anchor"); !ok {
|
|
t.Errorf("refused as %s: %q", r, text)
|
|
}
|
|
if _, ok := Check(text, "anchor"); ok && text != "anchor and the laptop" {
|
|
t.Errorf("Check lets %q leave, so Secret is not the narrower rule", text)
|
|
}
|
|
}
|
|
}
|