Genesis is a pivot, public routing is name-agnostic, and five issues the fake registry was hiding #32
+40
-21
@@ -1,8 +1,8 @@
|
||||
---
|
||||
status: open
|
||||
status: resolved
|
||||
opened: 2026-09-09
|
||||
located-in: []
|
||||
fixed-by:
|
||||
located-in: [mesh-control]
|
||||
fixed-by: mesh-control — a same-node provider is announced at the port it is published on
|
||||
amended-design:
|
||||
---
|
||||
|
||||
@@ -49,24 +49,43 @@ consumers (the ordinary small-mesh case) is exactly where it bites.
|
||||
It also blocks anything that must *reach* a routed/served name from inside the mesh, not just
|
||||
application traffic — see the internal-CA validation dependency noted in the connectivity design.
|
||||
|
||||
## Narrowing
|
||||
## Diagnosis
|
||||
|
||||
The loopback bind appears tied to **mesh-assigned** host ports, not to publishing as such. A
|
||||
container that declares a bare port (`"5432"`) — which the mesh assigns a host port for — is bound
|
||||
to `127.0.0.1:<assigned>`. A container that declares an explicit host mapping (`"17672:15672"`) is
|
||||
bound to `0.0.0.0:17672` and is reachable at the node's private-network address. So the defect is
|
||||
in the path that assigns and binds a host port for a bare declaration, not in the general publish
|
||||
step — which is also why a route to an explicitly-mapped port works while a database on an assigned
|
||||
port does not.
|
||||
The symptom's first reading — "published on loopback" — was **partly a red herring**. Two things
|
||||
were tangled:
|
||||
|
||||
## Open questions
|
||||
1. **The real, current-code defect is a served-*port* mismatch, not a bind address.** A bare
|
||||
`ports: ["5432"]` is assigned a host port and published as `"15432:5432"` — no bind IP, so on
|
||||
**all interfaces**, reachable at the node's private-network address. But the port a consumer is
|
||||
*told* is only re-derived from the assignment on the **cross-node** path. The **same-node** paths
|
||||
(the resolver's `servedHere`, and the `here()` fallback) settle their served facts *while
|
||||
resolving* — before the host port is assigned — so they carry the **declared** port (5432), not
|
||||
the **assigned** one (15432). A co-located consumer is therefore announced
|
||||
`<node>.internal:5432` while the provider is published on `<node>.internal:15432`, and dials a
|
||||
port nothing listens on. Cross-node consumers were always fine, which is why it read as "the
|
||||
small-mesh case."
|
||||
|
||||
- Should a `from: mesh` provision publish on the node's private-network address specifically, on
|
||||
all interfaces, or on whatever address the resolver will hand consumers as `at` — i.e. should the
|
||||
publish bind be derived from the *same* decision that fills `at`, so the two cannot drift?
|
||||
- What is correct for a `from: machine` provision by contrast — is loopback right there, and is the
|
||||
bug simply that both are being treated the same?
|
||||
- How is this checked so it cannot regress: a test that resolves a co-located provider/consumer and
|
||||
asserts the announced `at:port` is actually connectable (not merely that a binding file exists, which
|
||||
is what 018 asserts)?
|
||||
- Does the same address/publish mismatch affect the substrate's own ports, or only module provisions?
|
||||
2. **The `127.0.0.1:15432` seen in the running lab was a stale build.** Current code's publish step
|
||||
binds all interfaces; the running instance was raised from a mesh-control predating the ADR 0038
|
||||
publish rewrite. The substrate's own store *is* deliberately `127.0.0.1:5432` (a private store
|
||||
must not be exposed) — correct, and not this bug.
|
||||
|
||||
## Fixed by
|
||||
|
||||
`mesh-control` branch `fix/same-node-provider-announced-port` (`c147a26`): after the host port is
|
||||
assigned, same-node needs (and the `here()` fallback) are redirected through the same
|
||||
provision→module→assigned-port lookup the cross-node path already uses, so a co-located consumer is
|
||||
announced the port that is actually published. Idempotent (keyed by the declared port). Regression
|
||||
test `TestASameNodeProviderIsAnnouncedAtThePortItIsPublishedOn` asserts the announced port equals
|
||||
the published host port for a co-located provider/consumer — the next assertion after 018's (which
|
||||
only checked a binding file exists); verified failing without the change.
|
||||
|
||||
*Not yet merged, and the running lab is additionally stale — proving it end-to-end there needs
|
||||
mesh-control rebuilt and the affected consumer containers recreated.*
|
||||
|
||||
## Noted, not taken
|
||||
|
||||
Binding the assigned port to the node's private-network address specifically (rather than all
|
||||
interfaces) would be defence-in-depth and would make the publish address match `at` by construction
|
||||
— but it is a larger behavioural change entangled with the unenforced firewall scope
|
||||
([003](../003-firewall-scope-is-read-by-no-code/00-report.md)), so it is left as an option.
|
||||
|
||||
Reference in New Issue
Block a user