From dd6aad4a2ff53dc0036634422dd39849d5eef861 Mon Sep 17 00:00:00 2001 From: jochen Date: Tue, 22 Sep 2026 19:44:35 +0200 Subject: [PATCH] Give a machine port only to a port a module's container publishes, which is the only one the mesh can move (hq ADR 0038) --- internal/catalogue/adoption_test.go | 13 +++++++++++++ internal/catalogue/filtering.go | 22 +++++++++++----------- 2 files changed, 24 insertions(+), 11 deletions(-) diff --git a/internal/catalogue/adoption_test.go b/internal/catalogue/adoption_test.go index 949288a..ee6497b 100644 --- a/internal/catalogue/adoption_test.go +++ b/internal/catalogue/adoption_test.go @@ -397,3 +397,16 @@ func TestPublishedLeavesOutLoopbackInBothFamilies(t *testing.T) { t.Fatalf("published is %v, want %v", got, want) } } + +// novox/hq ADR 0038: only a published port is the mesh's to move. A module that binds the machine +// itself listens where its software was told to, so giving it a machine port is refused. +func TestAGivenPortIsRefusedForAPortNoContainerPublishes(t *testing.T) { + onTheMachine := Manifest{Module: "daemon", + Listens: []Listening{{Port: 9000, From: FromMesh}}, Guards: []int{9000}} + layers := []Layer{{From: "node anchor", + Values: map[string]any{PortsSetting: map[string]any{"9000": float64(9100)}}}} + _, err := GivenPorts(onTheMachine, layers) + if err == nil || !strings.Contains(err.Error(), "does not publish") { + t.Fatalf("a port no container publishes was given: %v", err) + } +} diff --git a/internal/catalogue/filtering.go b/internal/catalogue/filtering.go index 453f651..674ebe1 100644 --- a/internal/catalogue/filtering.go +++ b/internal/catalogue/filtering.go @@ -475,17 +475,16 @@ const MeshWideLayer = "the mesh" // GivenPorts reads a module's given machine ports from its settings: software port → machine port. // // Refused from a mesh-wide layer — a port is a fact about one machine, and one number for every -// machine is the collision this exists to avoid — and for a port the module neither listens on, -// publishes from a container, nor guards: a given port that reaches nothing is a setting somebody -// believes changed something. +// machine is the collision this exists to avoid — and for a port the module's containers do not +// publish. +// +// **Only a published port is the mesh's to move** (novox/hq ADR 0038). A container's mapping is +// what translates; a module binding the machine's network directly binds the number its software +// was configured with, and moving that number would put it in the filter, in the openings and in +// what consumers are told while the software still listens on the old one — a port that reads as +// moved and is not. func GivenPorts(m Manifest, layers []Layer) (map[int]int, error) { known := map[int]bool{} - for _, l := range m.Listens { - known[l.Port] = true - } - for _, p := range m.Guards { - known[p] = true - } for _, p := range containerPorts(m) { known[p] = true } @@ -510,8 +509,9 @@ func GivenPorts(m Manifest, layers []Layer) (map[int]int, error) { return nil, fmt.Errorf("%s gives %q a port, which is not a port", m.Module, portText) } if !known[port] { - return nil, fmt.Errorf("%s gives port %d a machine port, and it neither listens "+ - "on, publishes nor guards %d — the setting reaches nothing", m.Module, port, port) + return nil, fmt.Errorf("%s gives port %d a machine port, and no container of its "+ + "publishes %d — the mesh cannot move a port the module does not publish; the "+ + "software would go on listening where it was told to", m.Module, port, port) } at, ok := asPort(value) if !ok || at < 1 || at > 65535 {