route-proxy: placement is read through the module assigner's client, and a bus address is said without its credential by the proxy's own helper (N-1, ADR 0634 §4; issue 1966)

Claude-Session: https://claude.ai/code/session_01NcbgfFSnn24M3GcqttoU7i
This commit is contained in:
2026-11-05 15:33:20 +01:00
parent 5885ab600a
commit e313ac9d3b
4 changed files with 48 additions and 12 deletions
@@ -0,0 +1,18 @@
package main
import "testing"
// A message that says where the proxy could not connect never carries the account's password.
func TestABusAddressIsSaidWithoutItsCredential(t *testing.T) {
for in, want := range map[string]string{
"nats://route-proxy:secret@127.0.0.1:4222": "nats://127.0.0.1:4222",
"route-proxy:secret@127.0.0.1:4222": "127.0.0.1:4222",
"nats://u:a@b@127.0.0.1:4222": "nats://127.0.0.1:4222", // the password holds an at-sign
"nats://127.0.0.1:4222": "nats://127.0.0.1:4222",
"127.0.0.1:4222": "127.0.0.1:4222",
} {
if got := bareAddress(in); got != want {
t.Errorf("bareAddress(%q) = %q, want %q", in, got, want)
}
}
}
+25 -10
View File
@@ -10,11 +10,10 @@ import (
"github.com/nats-io/nats.go"
"git.novox.be/novox/mesh-contracts/placement/go/clients/meshmoduleassignerclient"
"git.novox.be/novox/mesh-contracts/provisioning/go/clients/meshprovisionerclient"
stdio "git.novox.be/novox/mesh-sdk/go"
"git.novox.be/novox/mesh-sdk/go/announce"
"git.novox.be/novox/mesh-sdk/go/delivery"
"git.novox.be/novox/mesh-sdk/go/membership"
"git.novox.be/novox/mesh-sdk/go/process"
"route-proxy/contract"
@@ -35,8 +34,8 @@ func keptStates() []announce.State {
// **The routes are the seat mesh-provisioner's plans, alone** (issue 774, research 072 row 34): every plan's entry
// naming this proxy as a route's provider, followed, so a route added or withdrawn reaches a running proxy without a
// restart, and said on the bus as it changes (contract.EventServed, EventWithdrawn, EventRefused). **Who is inside**
// is every node's address on the private network as the seat mesh-placement decides it (mesh-sdk
// delivery.InsideAddresses), which is who may be served an internal name; until it is read, an internal name is
// is every node's address on the private network as the seat mesh-placement decides it (the module assigner's
// client, InsideAddresses), which is who may be served an internal name; until it is read, an internal name is
// served to this machine alone.
// follow connects with the credential in path, follows the plans and the placement, and retries the connection for
@@ -59,7 +58,7 @@ func followOnce(path string, held *table) error {
}
conn, err := process.Connect(account, nats.Name(account.Node+"."+account.Module))
if err != nil {
return fmt.Errorf("connecting to the bus at %s: %w", membership.BareAddress(account.URL), err)
return fmt.Errorf("connecting to the bus at %s: %w", bareAddress(account.URL), err)
}
// What this proxy keeps, said on the bus (novox/hq ADR 0495; issue 774): the names it serves and the names it
// refused, readable by any module granted a read of them; the provider helper's entries, read by the machines'
@@ -75,8 +74,8 @@ func followOnce(path string, held *table) error {
}
}
// Who is inside first, so the first table is served to the machines it is meant for.
if err := followInside(conn.Read(delivery.PlacementRead), held); err != nil {
log.Printf("cannot follow %s, so an internal name is served to this machine alone: %v", delivery.PlacementRead, err)
if err := followInside(conn.Read(meshmoduleassignerclient.PlacementRead), held); err != nil {
log.Printf("cannot follow %s, so an internal name is served to this machine alone: %v", meshmoduleassignerclient.PlacementRead, err)
}
if err := followPlans(conn.Read(meshprovisionerclient.PlansRead), newPlanned(account.Node, say), held, say); err != nil {
conn.Close()
@@ -160,14 +159,14 @@ func sortedNames(m map[string]contract.Event) []string {
}
// followInside follows the seat mesh-placement's state and serves an internal name to every node's address on the
// private network it decides, each time it changes (mesh-sdk delivery.InsideAddresses; research 072 rows 33 and 34:
// private network it decides, each time it changes (the module assigner client's InsideAddresses; research 072 rows 33 and 34:
// the membership that carried them went with the assignments stream). A key that does not read keeps who is inside
// as it was.
func followInside(placement planWatch, held *table) error {
keys := delivery.NewPlacementKeys()
keys := meshmoduleassignerclient.NewKeys()
var read atomic.Bool
apply := func() {
inside, err := sourcesOf(delivery.InsideAddresses(keys.All()))
inside, err := sourcesOf(meshmoduleassignerclient.InsideAddresses(keys.All()))
if err != nil {
log.Printf("the placement says an address that is not one, so who is inside stays as it was: %v", err)
return
@@ -192,3 +191,19 @@ func followInside(placement planWatch, held *table) error {
apply()
return nil
}
// bareAddress is a bus address without the credential it may carry, `[scheme://]user:password@host:port`, for a message
// that says where the proxy could not connect: the password is never written in a log. It splits on the last at-sign,
// so a password holding one stays out whole. (Its only reader is this proxy: it was the SDK's membership package's,
// which keeps the runtime's read of its own membership and nothing else.)
func bareAddress(address string) string {
at := strings.LastIndex(address, "@")
if at < 0 {
return address
}
scheme := ""
if i := strings.Index(address[:at], "://"); i >= 0 {
scheme = address[:i+3]
}
return scheme + address[at+1:]
}
@@ -15,8 +15,9 @@ import (
"strings"
"testing"
"git.novox.be/novox/mesh-contracts/placement/go/clients/meshmoduleassignerclient"
seat "git.novox.be/novox/mesh-contracts/placement/go/seats/meshmoduleassigner"
stdio "git.novox.be/novox/mesh-sdk/go"
"git.novox.be/novox/mesh-sdk/go/delivery"
"route-proxy/contract"
)
@@ -305,7 +306,7 @@ func TestThePlansAreServedAndThePlacementSaysWhoIsInside(t *testing.T) {
if code, _ := askFrom(held, "admin.anchor.internal", "10.10.0.7:1"); code != http.StatusNotFound {
t.Errorf("before the placement is read, a machine of the mesh was served an internal-only name: %d", code)
}
laptop, err := delivery.PlacementValues(delivery.Placement{Node: "laptop", Decided: delivery.NodeDecided{Address: "10.10.0.7"}})
laptop, err := meshmoduleassignerclient.PlacementValues(seat.Placement{V: meshmoduleassignerclient.Version, Node: "laptop", Decided: seat.NodeDecided{Address: "10.10.0.7"}})
if err != nil {
t.Fatal(err)
}