Merge pull request 'The first pass does not refuse two providers beside the consumer (hotfix for #195)' (#196) from fix/first-pass-does-not-refuse-two-providers-beside into main

This commit was merged in pull request #196.
This commit is contained in:
2026-10-01 15:34:23 +00:00
2 changed files with 19 additions and 0 deletions
@@ -103,3 +103,13 @@ func TestAPinSettlesTwoProvidersBesideTheConsumer(t *testing.T) {
t.Fatalf("no need for acme-ca was created: %+v", got.Needs) 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)
}
}
+9
View File
@@ -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 // 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 // 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. // 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] c, pinned := world.Pinned[want]
if !pinned || c.Node != node.Name || !oneOf(matter, c.Module) { if !pinned || c.Node != node.Name || !oneOf(matter, c.Module) {
reported[want] = true reported[want] = true