Files
mesh-controller/internal/outward/outward_test.go
T
jochen 68557b412f
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
Review: a path is read as a path in the whole words, and Details say what the desk shows (issue 383)
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.
2026-10-10 15:46:55 +02:00

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