carlos / platform Public

edges file: merge the wildcard class on an in-file collision, cert halves from EIP-less files, role wildcard only on catch-all keys, deduped cap (#305 round 2)

A route's own catch-all row kept the key with Wildcard false, so the
parent's PEM would load nowhere else — the same class drop the fold
already merges, now merged at the publisher too. A file with no EIP
still contributes cert halves (its dial halves become cert-only). Role
wildcard on an exact key is refused (it would be a KnownHost admission
with no dial). The delegated union dedupes (lower-cased) before the cap
so a duplicate never costs a slot, and its two standing-condition lines
are said once.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Paul Campbell pushed by paul@keymail.dev f8218553709edbe28fd2d48a127cb9401fdcf562 parent 16a2e49
5 files changed, +91 −10
  • internal/edge/homemap.go +23 −2
  • internal/edge/wildcard.go +31 −5
  • internal/edge/wildcard_parents_test.go +25 −0
  • internal/host/edgesfile.go +8 −1
  • internal/host/edgesfile_test.go +4 −2
diff --git a/internal/edge/homemap.go b/internal/edge/homemap.go
index a8ed1c4ca..aa675bfd8 100644
--- a/internal/edge/homemap.go
+++ b/internal/edge/homemap.go
@@ -503,11 +503,32 @@ func foldHomes(files map[string]edgesFileView, self string) map[string]homeEntry
hosts := make(map[string]homeEntry)
for _, k := range keys {
f := files[k]
- if f.Box == "" || f.Box == self || f.EIP == "" {
+ if f.Box == "" || f.Box == self {
continue
}
for host, h := range f.Hosts {
- if host == "" || (h.Role != edgeRoleHome && h.Role != edgeRoleWildcard) {
+ if host == "" {
+ continue
+ }
+ switch h.Role {
+ case edgeRoleHome:
+ // A dial target needs an address. A file with no EIP (a box
+ // with no discoverable public IP) still carries its cert
+ // halves below; its dial halves are simply not dialable.
+ if f.EIP == "" {
+ if !h.Wildcard || !strings.HasPrefix(host, "*.") {
+ continue
+ }
+ h.Role = edgeRoleWildcard
+ }
+ case edgeRoleWildcard:
+ // The cert-only role is defined for marked catch-all keys
+ // alone; on an exact key it would be a KnownHost admission
+ // with no dial behind it — refused.
+ if !h.Wildcard || !strings.HasPrefix(host, "*.") {
+ continue
+ }
+ default:
continue
}
in := homeEntry{eip: f.EIP, box: f.Box, platform: h.Platform && !h.Alias && !h.Wildcard, alias: h.Alias, wildcard: h.Wildcard, dial: h.Role == edgeRoleHome}
diff --git a/internal/edge/wildcard.go b/internal/edge/wildcard.go
index 8e0743bf7..eb78a74e9 100644
--- a/internal/edge/wildcard.go
+++ b/internal/edge/wildcard.go
@@ -44,6 +44,7 @@ import (
"sort"
"strings"
"sync"
+ "sync/atomic"
"time"
"golang.org/x/crypto/acme"
@@ -144,19 +145,44 @@ const maxDelegatedParents = 32
// rollout mistake worth a line — this box could win the issuer lease and
// would then fail every order for it against the customer's own zone.
func unionDelegated(local, remote []string, zone string) []string {
+ seen := make(map[string]bool, len(local)+len(remote))
out := make([]string, 0, len(local)+len(remote))
- out = append(out, local...)
- if len(remote) > 0 && zone == "" {
- log.Printf("edge: %d delegated wildcard parent(s) published by other boxes but CARLOS_ACME_DELEGATION_ZONE is unset here — set it fleet-wide, or this box cannot issue for them if it becomes the issuer", len(remote))
+ add := func(d string) {
+ d = strings.ToLower(strings.TrimSpace(d))
+ if d == "" || seen[d] {
+ return
+ }
+ seen[d] = true
+ out = append(out, d)
+ }
+ for _, d := range local {
+ add(d)
+ }
+ nLocal := len(out)
+ for _, d := range remote {
+ add(d)
+ }
+ if len(out) > nLocal && zone == "" {
+ delegationZoneUnsetOnce.Do(func() {
+ log.Printf("edge: %d delegated wildcard parent(s) published by other boxes but CARLOS_ACME_DELEGATION_ZONE is unset here — set it fleet-wide, or this box cannot issue for them if it becomes the issuer", len(out)-nLocal)
+ })
}
- out = append(out, remote...)
if len(out) > maxDelegatedParents {
- log.Printf("edge: delegated wildcard parents capped at %d (%d present: %d local, %d remote) — the overflow gets no wildcard", maxDelegatedParents, len(out), len(local), len(remote))
+ if n := int32(len(out)); delegatedCapLogged.Swap(n) != n {
+ log.Printf("edge: delegated wildcard parents capped at %d (%d distinct: %d local, %d remote) — the overflow gets no wildcard", maxDelegatedParents, len(out), nLocal, len(out)-nLocal)
+ }
out = out[:maxDelegatedParents]
}
return out
}
+// Standing conditions are said once: an unset zone stays unset, and the cap
+// line repeats only when the count it reports changes.
+var (
+ delegationZoneUnsetOnce sync.Once
+ delegatedCapLogged atomic.Int32
+)
+
// parentsFor computes the wildcard parent set: staticAndDelegated (the
// static CARLOS_WILDCARD_DOMAINS plus any delegated parents refresh() has
// already vetted — both arrive pre-merged through this one parameter) union
diff --git a/internal/edge/wildcard_parents_test.go b/internal/edge/wildcard_parents_test.go
index c5cecd5da..ddc3f3c54 100644
--- a/internal/edge/wildcard_parents_test.go
+++ b/internal/edge/wildcard_parents_test.go
@@ -398,6 +398,21 @@ func TestHomeMapWildcardCollisionMergesClasses(t *testing.T) {
t.Fatalf("order %v: a cert-only wildcard entry was a dial target", order)
}
}
+ // Role wildcard on an EXACT key is refused (no KnownHost admission
+ // without a dial); a file with no EIP still contributes cert halves.
+ s2 := meshTestStore(t)
+ putJSON(t, s2, "control/edges/carol.json", `{"v":1,"box":"carol","eip":"","hosts":{"*.noeip.example":{"role":"home","wildcard":true},"victim.example":{"role":"wildcard"},"served.example":{"role":"home","platform":true}}}`)
+ m2 := newHomeMap(s2, "self")
+ refreshHomeMap(t, m2)
+ if got := m2.WildcardParents(); !reflect.DeepEqual(got, []string{"noeip.example"}) {
+ t.Fatalf("EIP-less file: WildcardParents = %v", got)
+ }
+ if m2.KnownHost("victim.example") || m2.KnownHost("served.example") {
+ t.Fatal("an exact key from an EIP-less file or with role wildcard was admitted")
+ }
+ if _, _, ok := m2.Home("x.noeip.example"); ok {
+ t.Fatal("an EIP-less file offered a dial target")
+ }
// A remote parent of bad shape is not a parent.
s := meshTestStore(t)
putJSON(t, s, "control/edges/betty.json", `{"v":1,"box":"betty","eip":"2.2.2.2","hosts":{"*.nodot":{"role":"wildcard","wildcard":true},"*.*.double.example":{"role":"wildcard","wildcard":true},"*.ok.example":{"role":"wildcard","wildcard":true}}}`)
@@ -411,6 +426,8 @@ func TestHomeMapWildcardCollisionMergesClasses(t *testing.T) {
// The fleet's delegated set is capped where the per-box table is: local
// rows first, the overflow logged and dropped.
func TestUnionDelegatedCapsAndWarns(t *testing.T) {
+ delegatedCapLogged.Store(0) // once-per-process throttles: isolate from -count>1
+ delegationZoneUnsetOnce = sync.Once{}
var buf strings.Builder
log.SetOutput(&buf)
t.Cleanup(func() { log.SetOutput(os.Stderr) })
@@ -419,10 +436,14 @@ func TestUnionDelegatedCapsAndWarns(t *testing.T) {
for i := 0; i < 40; i++ {
remote = append(remote, fmt.Sprintf("r%02d.example", i))
}
+ remote = append(remote, "L1.example", "r00.example") // duplicates never cost a slot
got := unionDelegated(local, remote, "acme.apps.test")
if len(got) != maxDelegatedParents || got[0] != "l1.example" || got[1] != "l2.example" || got[2] != "r00.example" {
t.Fatalf("union = %d entries, head %v", len(got), got[:3])
}
+ if got := unionDelegated([]string{"a.example"}, []string{"A.example", "a.example", "b.example"}, "z"); !reflect.DeepEqual(got, []string{"a.example", "b.example"}) {
+ t.Fatalf("dedupe = %v", got)
+ }
if !strings.Contains(buf.String(), "capped at 32") {
t.Fatalf("overflow not logged:\n%s", buf.String())
}
@@ -431,6 +452,10 @@ func TestUnionDelegatedCapsAndWarns(t *testing.T) {
t.Fatalf("no-zone case: %v / %s", got, buf.String())
}
buf.Reset()
+ unionDelegated(local, []string{"r.example"}, "") // a standing condition is said once
+ if buf.Len() != 0 {
+ t.Fatalf("zone-unset line repeated:\n%s", buf.String())
+ }
if got := unionDelegated(local, nil, ""); len(got) != 2 || buf.Len() != 0 {
t.Fatalf("local-only case logged or changed: %v / %s", got, buf.String())
}
diff --git a/internal/host/edgesfile.go b/internal/host/edgesfile.go
index 850847120..b44827d49 100644
--- a/internal/host/edgesfile.go
+++ b/internal/host/edgesfile.go
@@ -224,7 +224,14 @@ func edgesFilePass(ctx context.Context, s release.Store, reg *registry.Registry,
continue
}
key := "*." + wd.Host
- if _, taken := hosts[key]; taken {
+ if prev, taken := hosts[key]; taken {
+ // A real route owns the key (its catch-all row, published above):
+ // the route keeps its role and class, and the parent's class is
+ // ADDED — the reader's fold merges classes the same way, and a
+ // parent whose PEM must load everywhere is a fact about the name,
+ // not about which row got there first.
+ prev.Wildcard = true
+ hosts[key] = prev
continue
}
role := "wildcard"
diff --git a/internal/host/edgesfile_test.go b/internal/host/edgesfile_test.go
index e477e740e..c19c1e219 100644
--- a/internal/host/edgesfile_test.go
+++ b/internal/host/edgesfile_test.go
@@ -762,7 +762,9 @@ func TestEdgesFilePublishesDelegatedWildcardParents(t *testing.T) {
if _, ok := f.Hosts["*.*.odd.example"]; ok {
t.Error("a malformed wildcard_domains row was published")
}
- if h := f.Hosts["*.taken.example"]; !h.Platform || h.Wildcard {
- t.Errorf("a wildcard entry displaced a real route's key: %+v", h)
+ // A real route owns the key: it keeps role and class, and the parent's
+ // class is added — the reader must still load the PEM everywhere.
+ if h := f.Hosts["*.taken.example"]; !h.Platform || !h.Wildcard || h.Role != "home" {
+ t.Errorf("route-owned key = %+v; want platform AND wildcard, role home", h)
}
}