catalogue: a contribution reaches the port its own machine published, from any machine

The co-located fix could not reach a grant assembled for a consumer on another
machine: ContributionsFrom never sees a port map, so the proxy was told the
workload's software port and dialled a number that machine never published. The
consumer's own assignments are fetched where the grant is built and applied
there. The same fault as 038, one node over.

Claude-Session: https://claude.ai/code/session_01LrgweAeERJYBg88c5cKDzF
This commit is contained in:
2026-09-10 21:08:09 +02:00
parent e78c849002
commit 9fab0b731a
3 changed files with 48 additions and 0 deletions
+9
View File
@@ -627,6 +627,15 @@ func grantsFor(ctx context.Context, open *stores, node string) ([]catalogue.Gran
if err != nil { if err != nil {
return nil, err return nil, err
} }
// A port in there is the consumer's software port until this. The consumer is on another
// machine, so the assignment that moved it is that machine's — fetched here rather than
// looked for in this one's, which is the whole reason the co-located fix could not reach
// this case (novox/hq 04-ISSUES/038, the cross-node half).
published, err := portsOn(ctx, inv, s.Consumer, s.ConsumerModule)
if err != nil {
return nil, err
}
values = catalogue.AtPublishedPort(values, s.ConsumerModule, published)
from := s.ConsumerModule from := s.ConsumerModule
if !asks { if !asks {
// That module no longer wants this. Left empty, which is what the declaration reads // That module no longer wants this. Left empty, which is what the declaration reads
+27
View File
@@ -259,6 +259,33 @@ func TestAContributionFromAnotherMachineKeepsItsOwnPort(t *testing.T) {
} }
} }
// The cross-node half of the same fault: a grant assembled on the providing machine carries the
// consumer's declared port until the CONSUMER's machine's assignments are applied to it. The
// declaration layer cannot do it — those assignments are not this machine's, which is the line the
// test above holds — so the grant layer is handed them and does it there.
func TestAContributionIsRedirectedToWhereItsOwnMachinePublishedIt(t *testing.T) {
published := map[int]int{3000: 20000}
got := AtPublishedPort(map[string]any{"name": "git.example.tld", "port": 3000}, "forge", published)
if port, _ := asPort(got["port"]); port != 20000 {
t.Errorf("the proxy would dial a port that machine never published: %v", got["port"])
}
if got["name"] != "git.example.tld" {
t.Errorf("redirecting the port disturbed the rest of the contribution: %v", got)
}
// Idempotent, and silent about a port nobody moved: a module that pinned its own mapping has no
// assignment, and must come back exactly as it was written.
again := AtPublishedPort(got, "forge", published)
if port, _ := asPort(again["port"]); port != 20000 {
t.Errorf("applying it twice moved the port again: %v", again["port"])
}
pinned := AtPublishedPort(map[string]any{"port": 9070}, "office", published)
if port, _ := asPort(pinned["port"]); port != 9070 {
t.Errorf("a port the mesh never assigned was rewritten: %v", pinned["port"])
}
}
func asStrings(v any) []string { func asStrings(v any) []string {
listed, ok := v.([]any) listed, ok := v.([]any)
if !ok { if !ok {
+12
View File
@@ -997,3 +997,15 @@ func atMachinePort(serves map[string]any, module string, ports map[string]map[in
copied["port"] = at copied["port"] = at
return copied return copied
} }
// AtPublishedPort redirects a contribution's port to where the CONSUMER's own machine published it.
//
// The same redirection as [atMachinePort], for the one caller that cannot reach it. A grant is
// assembled on the providing machine out of a consumer that lives on another one, so that
// consumer's assignments are fetched there and handed in, rather than looked for here where they
// are not. Without it a proxy told to reach a workload on another machine is told the port the
// workload's *software* uses, and dials a number that machine never published — the same fault as
// novox/hq 04-ISSUES/038, one node over.
func AtPublishedPort(values map[string]any, module string, published map[int]int) map[string]any {
return atMachinePort(values, module, map[string]map[int]int{module: published})
}