diff --git a/internal/catalogue/pin_names_module_test.go b/internal/catalogue/pin_names_module_test.go index ad7c893..8191e5a 100644 --- a/internal/catalogue/pin_names_module_test.go +++ b/internal/catalogue/pin_names_module_test.go @@ -103,3 +103,13 @@ func TestAPinSettlesTwoProvidersBesideTheConsumer(t *testing.T) { t.Fatalf("no need for acme-ca was created: %+v", got.Needs) } } + +func TestTheFirstPassDoesNotRefuseTwoProvidersBesideTheConsumer(t *testing.T) { + // The first pass answers only what a node offers. Refused there, the node vanishes from every + // other node's world — and the whole mesh loses its vault for an ambiguity one machine has to + // settle. The second pass is where it is refused, and the test above proves it is. + if _, err := Resolve(issuerShelf(), []string{"route-proxy", "public-acme", "step-ca"}, reachable(), + World{Unchecked: true}); err != nil { + t.Fatalf("the first pass refused what only the second may: %v", err) + } +} diff --git a/internal/catalogue/resolve.go b/internal/catalogue/resolve.go index 74be21e..a33f761 100644 --- a/internal/catalogue/resolve.go +++ b/internal/catalogue/resolve.go @@ -342,6 +342,15 @@ func Resolve(catalogue map[string]Manifest, assigned []string, node Node, world // Two modules on this machine answer it. Taking whichever a map walk met first // was the rule until novox/hq #258 — random, per plan — and the same stance as // across machines applies: ambiguity is refused, never resolved by picking. + // + // **Not in the first pass.** That pass exists only to answer *what does this node + // offer*, and refusing there makes the machine vanish rather than report a problem + // (the sibling case below says why): every other node then loses what this one + // provides — the vault, the identity provider — and refuses for a fault that is + // this node's to settle. The second pass refuses it properly, where it is asked. + if world.Unchecked { + continue + } c, pinned := world.Pinned[want] if !pinned || c.Node != node.Name || !oneOf(matter, c.Module) { reported[want] = true