diff --git a/internal/catalogue/adoption_test.go b/internal/catalogue/adoption_test.go index ee6497b..6de58f1 100644 --- a/internal/catalogue/adoption_test.go +++ b/internal/catalogue/adoption_test.go @@ -410,3 +410,22 @@ func TestAGivenPortIsRefusedForAPortNoContainerPublishes(t *testing.T) { t.Fatalf("a port no container publishes was given: %v", err) } } + +// novox/hq ADR 0103: a guarded port this node is told to open to everyone is opened, not guarded. +// An opening from everywhere beside a guard dropping it is one statement refusing the other. +func TestAGuardedPortOpenedToEveryoneIsNotGuarded(t *testing.T) { + with := anchorRendering(true) + with.Settings["postgres"] = []Layer{{From: "node anchor", + Values: map[string]any{ExposeSetting: map[string]any{"5432": FromEverywhere}}}} + composed, err := anAdoptedAnchor().Compose(with) + if err != nil { + t.Fatal(err) + } + got := byID(composed.Resources) + if o := got["adoption.opening-tcp-5432-forwarded"]; o == nil || o["from"] != OpeningFromEverywhere { + t.Fatalf("the store's port is not opened to everyone: %v", o) + } + if guard, _ := got[GuardID()]["content"].(string); guard != AsGuard([]int{5672, 15672}) { + t.Fatalf("a port opened to everyone is still guarded:\n%s", guard) + } +} diff --git a/internal/catalogue/declaration.go b/internal/catalogue/declaration.go index 0cc318f..b9cfdf7 100644 --- a/internal/catalogue/declaration.go +++ b/internal/catalogue/declaration.go @@ -610,13 +610,21 @@ func (r Resolution) compose(with Rendering, owner map[string]string) ([]map[stri func (r Resolution) guarded(out []map[string]any, owner map[string]string, rules []Rule, with Rendering) []int { meshOnly := map[int]bool{} + fromEverywhere := map[int]bool{} for _, rule := range rules { - if rule.Protocol == "tcp" && rule.From == FromMesh { + if rule.Protocol != "tcp" { + continue + } + switch rule.From { + case FromMesh: meshOnly[rule.Port] = true + case FromEverywhere: + fromEverywhere[rule.Port] = true } } for _, port := range with.Foundation { delete(meshOnly, port) + fromEverywhere[port] = true } seen := map[int]bool{} var ports []int @@ -655,7 +663,12 @@ func (r Resolution) guarded(out []map[string]any, owner map[string]string, rules } } } - guard(at) + // Not what this node is told to open to everyone: a per-node exposure setting that + // widens a guarded port is the operator saying so, and declaring an opening for it + // and a guard dropping it would be one statement refusing the other. + if !fromEverywhere[at] { + guard(at) + } } } sort.Ints(ports)