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) } } }