diff --git a/cmd/mesh-controller/proposals.go b/cmd/mesh-controller/proposals.go index 6481ae71..b4b37023 100644 --- a/cmd/mesh-controller/proposals.go +++ b/cmd/mesh-controller/proposals.go @@ -178,7 +178,7 @@ func (p settingsProposal) ask(id string, machines []string) (asks.Ask, map[strin var d strings.Builder fmt.Fprintf(&d, "Fingerprint %s.\n", fingerprint(p.Digest)) if !shownWhole { - d.WriteString("Parts shown as ‹address›, ‹path› or ‹withheld› may not leave the mesh where the sender is not proven.\n") + d.WriteString("On a channel that does not prove who answers, these values are shown as ‹address›, ‹path› or ‹withheld›.\n") } fmt.Fprintf(&d, "Read it whole, with this fingerprint: settings proposals %s at the controller's terminal, or "+ "mesh-controller.settings with proposal %s through the mesh MCP server.\n", id, id) diff --git a/cmd/mesh-controller/proposals_test.go b/cmd/mesh-controller/proposals_test.go index 2eaba0e2..1f9711fa 100644 --- a/cmd/mesh-controller/proposals_test.go +++ b/cmd/mesh-controller/proposals_test.go @@ -133,7 +133,7 @@ func TestAProposalAsksAtTheLevelApproveWithTheExactChange(t *testing.T) { } for _, line := range []string{ "Fingerprint " + fingerprint(layerDigest(mountsSources)) + ".", - "Parts shown as ‹address›, ‹path› or ‹withheld› may not leave the mesh where the sender is not proven.", + "On a channel that does not prove who answers, these values are shown as ‹address›, ‹path› or ‹withheld›.", "Read it whole, with this fingerprint: settings proposals " + kept(r).ID + " at the controller's terminal", "Approved, the layer is set at once and the machine takes it at its next push.", } { @@ -141,7 +141,7 @@ func TestAProposalAsksAtTheLevelApproveWithTheExactChange(t *testing.T) { t.Errorf("Details lack %q:\n%s", line, q.Details) } } - for _, howTo := range []string{"ingerprint", "settings proposals", "mesh-controller.settings", "may not leave", "Approved,"} { + for _, howTo := range []string{"ingerprint", "settings proposals", "mesh-controller.settings", "does not prove", "Approved,"} { if strings.Contains(q.Explanation, howTo) || strings.Contains(q.Whole, howTo) { t.Errorf("the message carries the how-to %q", howTo) } @@ -261,7 +261,7 @@ func TestAProposalShowsItsValuesWholeOnlyWhereTheSenderIsProvenAndNeverASecret(t t.Fatal(err) } if q2 := r2.askSent(t); q2.Whole != "" || !strings.HasPrefix(q2.Explanation, "+ font-size: 13\n+ width: 500\nProposed by ") || - strings.Contains(q2.Details, "may not leave") { + strings.Contains(q2.Details, "does not prove who answers") { t.Errorf("%+v", q2) } } diff --git a/internal/outward/outward.go b/internal/outward/outward.go index a2466329..6167b440 100644 --- a/internal/outward/outward.go +++ b/internal/outward/outward.go @@ -105,13 +105,27 @@ func Check(text string, machines ...string) (Refusal, bool) { // Secret says whether a text carries a secret's shape, the one class that leaves the mesh nowhere — the // messenger's CheckSecret, one for one. It is what an ask's whole words (asks.Ask.Whole, novox/hq issue 383) // are held to: on a channel that proves who answers, a path or an address is what the operator approves and -// is shown; a secret never is. +// is shown; a secret never is. A path is read as one: a run with a slash in it is judged piece by piece +// between the slashes, so "/mnt/Photos_2024/Jochen" is a path and not a random string (the review of +// 2026-10-10); the named shapes hold whatever the run holds. func Secret(text string, machines ...string) (Refusal, bool) { text = withoutMachines(text, machines) if refusal, ok := secretShape(text); !ok { return refusal, false } - return randomRun(text) + return randomRunOutsidePaths(text) +} + +// randomRunOutsidePaths is randomRun with each run that holds a slash judged by its pieces between the slashes. +func randomRunOutsidePaths(text string) (Refusal, bool) { + for _, run := range reRun.FindAllString(text, -1) { + for _, piece := range strings.Split(run, "/") { + if len(piece) >= 20 && looksRandom(piece) { + return Refusal{"secret", "a long random-looking string"}, false + } + } + } + return Refusal{}, true } // secretShape is the secret shapes a pattern names. diff --git a/internal/outward/outward_test.go b/internal/outward/outward_test.go index 45fb2bf3..0901cd70 100644 --- a/internal/outward/outward_test.go +++ b/internal/outward/outward_test.go @@ -107,6 +107,9 @@ func TestSecretRefusesOnlyASecretsShape(t *testing.T) { 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",