carlos / platform Public

edges file: aliases marked on the wire, routes win collisions, publish only pointing aliases (#287 review)

Review: on a non-home edge an alias entry was indistinguishable from a
route entry, so a tenant attaching a hostname that is an operator's
route on ANOTHER box could capture it fleet-wide on a box-name coin
flip; the raw alias set is tenant-chosen and unbounded (attach needs no
DNS proof), which handed a tenant an unbounded set of names the shared
issuer would order for; and a published catch-all alias was a dial
target no remote edge could terminate.

Now: entries carry alias:true (additive) and the fold lets a route beat
an alias whatever the sort order, an alias can never carry the platform
mark; only an alias whose DNS the sweep stamped 'pointing' publishes;
catch-all aliases stay unpublished (served on their home box only, as
before). Also: the plain alias branch shape-checks like the wildcard
branch, the tunnel host joins the console's deny list, and the spec
amendment states the two residuals (#286 order start, no cert purge on
detach) instead of overclaiming.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Paul Campbell pushed by paul@keymail.dev b6468b0adb7f2ca105a0373d05ed87159f5b8782 parent 5621c58
7 files changed, +139 −55
  • docs/superpowers/specs/2026-08-20-multi-region-ingress-design.md +17 −10
  • internal/console/apidomains.go +9 −0
  • internal/domains/aliases.go +5 −0
  • internal/edge/homemap.go +14 −3
  • internal/edge/wildcard_parents_test.go +22 −1
  • internal/host/edgesfile.go +23 −8
  • internal/host/edgesfile_test.go +49 −33
diff --git a/docs/superpowers/specs/2026-08-20-multi-region-ingress-design.md b/docs/superpowers/specs/2026-08-20-multi-region-ingress-design.md
index 89d2f2366..e4d111856 100644
--- a/docs/superpowers/specs/2026-08-20-multi-region-ingress-design.md
+++ b/docs/superpowers/specs/2026-08-20-multi-region-ingress-design.md
@@ -256,16 +256,23 @@ follow-up issue, with one constraint stated in advance: an alias whose
host is a `*.<parent>` catch-all must stay wildcard-cert-only if it is
ever published — the same #180 bound this amendment refuses to widen.
-*Amendment 2026-08-26 (#287): done.* The publisher writes each alias
-whose primary is a served row under the alias's own name (`role:
-"home"`, never `platform`), so `Home` backhauls it and `KnownHost`
-admits it on every edge — the issuer orders its per-host cert whichever
-edge the validation lands on. A `*.<parent>` catch-all alias goes
-verbatim, exactly as the routes' catch-all rows do: `Home`'s one-label
-rule dials it, `KnownHost` still refuses it. Custom domains on a
-multi-edge deployment therefore work through any edge — `CNAME` to
-`edge.<apps-domain>` inherits steering and failover; an apex needs the
-current edge-IP set (#299).
+*Amendment 2026-08-26 (#287).* The publisher writes each exact alias
+whose primary is a served row AND whose DNS the sweep has stamped
+`pointing` under the alias's own name (`role: "home"`, `alias: true`,
+never `platform`), so `Home` backhauls it and `KnownHost` admits it on
+every edge — any edge answers its validations. Bounds: the `pointing`
+gate keeps the issuer's orderable set to names that actually resolve
+here (attach needs no DNS proof, so the raw alias set is tenant-chosen
+and unbounded); the fold lets a route beat an alias on a cross-box name
+collision, whatever the boxes' sort order; a `*.<parent>` catch-all
+alias is NOT published — its delegated wildcard parent is box-local, so
+a remote edge could dial it but never terminate it. Two residuals stay
+as they were: an ORDER still only starts from a hello reaching the
+issuer (#286), so a steered custom domain whose hellos never land there
+stays certless; and nothing purges `control/certs/` on detach. Net for
+#299: a customer subdomain `CNAME → edge.<apps-domain>` works through
+any edge with steering and failover; an apex needs the current edge-IP
+set.
**Order amplification, accepted.** The set of names a stranger can induce
a fresh ACME order for at the issuer grows from one box's routes to every
diff --git a/internal/console/apidomains.go b/internal/console/apidomains.go
index 0b1ee0fe4..04a6d099a 100644
--- a/internal/console/apidomains.go
+++ b/internal/console/apidomains.go
@@ -40,6 +40,7 @@ import (
"log"
"net/http"
"net/url"
+ "os"
"sort"
"strconv"
"strings"
@@ -97,6 +98,14 @@ func (s *Server) deniedDomains() []string {
deny = append(deny, h)
}
}
+ // The fleet hub's reserved hostname (CARLOS_TUNNEL_HOST, the edge's env —
+ // host.env is shared with the console on the same box) is Allowed by the
+ // edge but is no registry route, so nothing else here names it; a tenant
+ // must not attach it (#151 said "MUST be in CONSOLE_DENY_DOMAINS" —
+ // this makes it so without relying on the operator remembering).
+ if h := normalizeHost(os.Getenv("CARLOS_TUNNEL_HOST")); h != "" {
+ deny = append(deny, h)
+ }
return deny
}
diff --git a/internal/domains/aliases.go b/internal/domains/aliases.go
index 27e0e7c61..79b52473f 100644
--- a/internal/domains/aliases.go
+++ b/internal/domains/aliases.go
@@ -65,6 +65,11 @@ func ReconcileAliases(ctx context.Context, s release.Store, reg *registry.Regist
c.Host, c.Route, release.RouteAccount(rt), rt.App, c.Account, c.App)
} else if _, taken := byHost[c.Host]; taken {
log.Printf("domains: alias %s skipped: a real route owns that host", c.Host)
+ } else if !validHostShape(c.Host) {
+ // Same check the wildcard branch below applies: both doors
+ // normalise, but this row now becomes a key in a file every
+ // edge folds (#287), so a hand-written claim must not reach it.
+ log.Printf("domains: alias %s refused: invalid host shape", c.Host)
} else {
desired[c.Host] = true
if err := reg.UpsertAlias(registry.RouteAlias{
diff --git a/internal/edge/homemap.go b/internal/edge/homemap.go
index d8931fcf2..3ef5cf39a 100644
--- a/internal/edge/homemap.go
+++ b/internal/edge/homemap.go
@@ -138,6 +138,9 @@ type edgesHostView struct {
// existed, which reads as "not platform" — fail closed for the one
// consumer that cares (Hosts, the wildcard parent set).
Platform bool `json:"platform,omitempty"`
+ // Alias marks an attached custom domain (#287). On a name collision
+ // across boxes a route entry beats an alias entry (foldHomes).
+ Alias bool `json:"alias,omitempty"`
}
// homeEntry is one folded answer: where to dial, and which box that is.
@@ -146,6 +149,8 @@ type homeEntry struct {
box string
// platform carries the publisher's class mark through the fold.
platform bool
+ // alias marks an attached custom domain's entry (never platform).
+ alias bool
}
// homeSnapshot is one poll's result, swapped in whole and immutable once
@@ -459,10 +464,16 @@ func foldHomes(files map[string]edgesFileView, self string) map[string]homeEntry
if host == "" || h.Role != edgeRoleHome {
continue
}
- if _, dup := hosts[host]; dup {
- continue // first box in sorted order wins, everywhere
+ if prev, dup := hosts[host]; dup {
+ // First box in sorted order wins, everywhere — except that a
+ // ROUTE beats an ALIAS whatever the order: a tenant attaching
+ // an operator's hostname on one box must not capture it on
+ // every other (#287).
+ if !(prev.alias && !h.Alias) {
+ continue
+ }
}
- hosts[host] = homeEntry{eip: f.EIP, box: f.Box, platform: h.Platform}
+ hosts[host] = homeEntry{eip: f.EIP, box: f.Box, platform: h.Platform && !h.Alias, alias: h.Alias}
}
}
return hosts
diff --git a/internal/edge/wildcard_parents_test.go b/internal/edge/wildcard_parents_test.go
index 6b234ee3c..3a233d6bb 100644
--- a/internal/edge/wildcard_parents_test.go
+++ b/internal/edge/wildcard_parents_test.go
@@ -257,7 +257,7 @@ func TestWildcardRefreshIsSerialized(t *testing.T) {
// is never an exact admission (#180).
func TestAliasEntriesBackhaulAndAdmitButDeriveNoParent(t *testing.T) {
e, _, base := remoteHomedEdge(t, nil)
- putJSON(t, base, "control/edges/betty.json", `{"v":1,"box":"betty","eip":"2.2.2.2","hosts":{"www.customer.com":{"role":"home","platform":false},"*.customer.com":{"role":"home","platform":false},"app.acct.apps.test":{"role":"home","platform":true}}}`)
+ putJSON(t, base, "control/edges/betty.json", `{"v":1,"box":"betty","eip":"2.2.2.2","hosts":{"www.customer.com":{"role":"home","platform":false,"alias":true},"*.customer.com":{"role":"home","platform":false,"alias":true},"app.acct.apps.test":{"role":"home","platform":true}}}`)
hm := e.homes.Load()
refreshHomeMap(t, hm)
if _, box, ok := hm.Home("www.customer.com"); !ok || box != "betty" {
@@ -276,3 +276,24 @@ func TestAliasEntriesBackhaulAndAdmitButDeriveNoParent(t *testing.T) {
t.Fatalf("customer names leaked into the parent input: %v", got)
}
}
+
+// A route beats an alias on a cross-box name collision whatever the
+// boxes' sort order (#287): a tenant attaching an operator's hostname
+// captures nothing beyond its own box. And an alias can never smuggle the
+// platform mark.
+func TestHomeMapRouteBeatsAliasOnCollision(t *testing.T) {
+ for _, order := range [][2]string{{"aaa", "zzz"}, {"zzz", "aaa"}} {
+ routeBox, aliasBox := order[0], order[1]
+ s := meshTestStore(t)
+ putJSON(t, s, "control/edges/"+routeBox+".json", `{"v":1,"box":"`+routeBox+`","eip":"1.1.1.1","hosts":{"status.platform.test":{"role":"home","platform":false}}}`)
+ putJSON(t, s, "control/edges/"+aliasBox+".json", `{"v":1,"box":"`+aliasBox+`","eip":"2.2.2.2","hosts":{"status.platform.test":{"role":"home","platform":true,"alias":true}}}`)
+ m := newHomeMap(s, "self")
+ refreshHomeMap(t, m)
+ if _, box, ok := m.Home("status.platform.test"); !ok || box != routeBox {
+ t.Fatalf("order %v: home = %s; want the route's box %s", order, box, routeBox)
+ }
+ if got := m.Hosts(); len(got) != 0 {
+ t.Fatalf("order %v: an alias entry reached the parent input: %v", order, got)
+ }
+ }
+}
diff --git a/internal/host/edgesfile.go b/internal/host/edgesfile.go
index 27834115c..bfa9e6d18 100644
--- a/internal/host/edgesfile.go
+++ b/internal/host/edgesfile.go
@@ -43,6 +43,11 @@ type edgeHost struct {
// homing nothing platform-class. A reader seeing no flag treats the host
// as unclassed and derives no parent from it (#300).
Platform bool `json:"platform"`
+ // Alias marks an attached custom domain (route_aliases, #287) as opposed
+ // to a registry route. Additive (omitempty). The reader's fold lets a
+ // route beat an alias on a name collision across boxes: a tenant
+ // attaching an operator's hostname must never capture it fleet-wide.
+ Alias bool `json:"alias,omitempty"`
}
// edgesFile is the wire shape at edgesFileKey(box), schema v1 (spec Part 3):
@@ -132,18 +137,28 @@ func edgesFilePass(ctx context.Context, s release.Store, reg *registry.Registry,
// a served row above, under the alias's own name — the reader wants
// exact names, and every reader already does the right thing with one:
// Home dials the home box with the alias as SNI, and the home box's own
- // upstream map serves it. Never platform-class: a customer's name
- // derives no wildcard parent. A "*.parent" catch-all alias goes verbatim,
- // as the routes' catch-all rows do — Home's one-label rule dials it,
- // KnownHost refuses it (PR #180's bound: a wildcard label is never an
- // exact cert admission). An alias shadowed by a real route is the
- // route's, as edge.Reload rules.
+ // upstream map serves it. Bounds, each doing work:
+ //
+ // - only an alias whose DNS the sweep has stamped "pointing" (at one of
+ // PLATFORM_EDGE_IPS). Attach needs no DNS proof, so the alias set is
+ // tenant-chosen and unbounded; publishing every one would hand a
+ // tenant an unbounded set of names the shared issuer will order for
+ // (#277's amplification envelope covers routes, which the platform
+ // provisions). A name that actually resolves to this deployment is
+ // the name whose validations must be answerable everywhere;
+ // - never platform-class: a customer's name derives no wildcard parent;
+ // - marked alias: the reader lets a real route on another box beat it;
+ // - no "*.parent" catch-all alias: a remote edge could dial it but has
+ // no cert for it (delegated wildcard parents are box-local), so it
+ // stays exactly as before — served on its home box only;
+ // - an alias shadowed by a real route here is the route's, as
+ // edge.Reload rules.
aliases, err := reg.ListAliases()
if err != nil {
return fmt.Errorf("edges: list aliases: %w", err)
}
for _, a := range aliases {
- if a.Alias == "" {
+ if a.Alias == "" || strings.HasPrefix(a.Alias, "*.") || a.DNSStatus != "pointing" {
continue
}
if _, served := hosts[a.Host]; !served {
@@ -152,7 +167,7 @@ func edgesFilePass(ctx context.Context, s release.Store, reg *registry.Registry,
if _, taken := hosts[a.Alias]; taken {
continue
}
- hosts[a.Alias] = edgeHost{Role: "home"}
+ hosts[a.Alias] = edgeHost{Role: "home", Alias: true}
}
if eip == "" && *last != nil {
diff --git a/internal/host/edgesfile_test.go b/internal/host/edgesfile_test.go
index d167216d3..b29c01bbe 100644
--- a/internal/host/edgesfile_test.go
+++ b/internal/host/edgesfile_test.go
@@ -614,11 +614,14 @@ func TestEdgesFileMarksPlatformRows(t *testing.T) {
}
// #287: attached custom domains are published under their own names —
-// only when their primary is served, never platform-class, catch-alls
-// verbatim, and never over a real route.
-func TestEdgesFilePublishesAliasesOfServedPrimaries(t *testing.T) {
+// only when their primary is served AND their DNS points here, marked as
+// aliases, never platform-class, catch-alls never, and never over a real
+// route. Detaching one republishes without it.
+func TestEdgesFilePublishesPointingAliasesOfServedPrimaries(t *testing.T) {
s, reg := release.NewDirStore(t.TempDir()), edgesTestRegistry(t)
- seedRoute(t, reg, "app.acct.apps.test")
+ if err := reg.Upsert(registry.Route{Host: "app.acct.apps.test", Kind: "service", Addr: "10.0.0.1:3000", Status: "ready", Platform: true}); err != nil {
+ t.Fatal(err)
+ }
if err := reg.Upsert(registry.Route{Host: "pending.acct.apps.test", Kind: "service", Addr: "10.0.0.1:3001", Status: "pending"}); err != nil {
t.Fatal(err)
}
@@ -626,45 +629,58 @@ func TestEdgesFilePublishesAliasesOfServedPrimaries(t *testing.T) {
t.Fatal(err)
}
for _, a := range []registry.RouteAlias{
- {Alias: "www.customer.com", Host: "app.acct.apps.test", Account: "acct", App: "app"},
- {Alias: "*.customer.com", Host: "app.acct.apps.test", Account: "acct", App: "app"},
- {Alias: "orphan.example.org", Host: "pending.acct.apps.test", Account: "acct", App: "pending"},
- {Alias: "real.example.net", Host: "app.acct.apps.test", Account: "acct", App: "app"}, // shadowed
+ {Alias: "www.customer.com", Host: "app.acct.apps.test", Account: "acct", App: "app", DNSStatus: "pointing"},
+ {Alias: "unpointed.customer.com", Host: "app.acct.apps.test", Account: "acct", App: "app", DNSStatus: "elsewhere"},
+ {Alias: "fresh.customer.com", Host: "app.acct.apps.test", Account: "acct", App: "app"},
+ {Alias: "*.customer.com", Host: "app.acct.apps.test", Account: "acct", App: "app", DNSStatus: "pointing"},
+ {Alias: "orphan.example.org", Host: "pending.acct.apps.test", Account: "acct", App: "pending", DNSStatus: "pointing"},
+ {Alias: "real.example.net", Host: "app.acct.apps.test", Account: "acct", App: "app", DNSStatus: "pointing"}, // shadowed
} {
if err := reg.UpsertAlias(a); err != nil {
t.Fatal(err)
}
}
- var lastBody []byte
- if err := edgesFilePass(context.Background(), s, reg, "annie", "1.2.3.4", "", &lastBody); err != nil {
- t.Fatal(err)
+ type hostView struct {
+ Role string `json:"role"`
+ Platform bool `json:"platform"`
+ Alias bool `json:"alias"`
}
- body, _, err := s.Get(context.Background(), "control/edges/annie.json")
- if err != nil {
- t.Fatal(err)
- }
- var f struct {
- Hosts map[string]struct {
- Role string `json:"role"`
- Platform bool `json:"platform"`
- } `json:"hosts"`
+ publish := func() map[string]hostView {
+ t.Helper()
+ var lastBody []byte
+ if err := edgesFilePass(context.Background(), s, reg, "annie", "1.2.3.4", "", &lastBody); err != nil {
+ t.Fatal(err)
+ }
+ body, _, err := s.Get(context.Background(), "control/edges/annie.json")
+ if err != nil {
+ t.Fatal(err)
+ }
+ var f struct {
+ Hosts map[string]hostView `json:"hosts"`
+ }
+ if err := json.Unmarshal(body, &f); err != nil {
+ t.Fatal(err)
+ }
+ return f.Hosts
}
- if err := json.Unmarshal(body, &f); err != nil {
- t.Fatal(err)
+ hosts := publish()
+ h, ok := hosts["www.customer.com"]
+ if !ok || h.Role != "home" || !h.Alias || h.Platform {
+ t.Errorf("www.customer.com = %+v, %v; want home, alias, not platform", h, ok)
}
- for _, alias := range []string{"www.customer.com", "*.customer.com"} {
- h, ok := f.Hosts[alias]
- if !ok || h.Role != "home" {
- t.Errorf("%s: not published as home (%+v, %v)", alias, h, ok)
- }
- if h.Platform {
- t.Errorf("%s: a customer alias must never be platform-class", alias)
+ for _, absent := range []string{"unpointed.customer.com", "fresh.customer.com", "*.customer.com", "orphan.example.org"} {
+ if _, ok := hosts[absent]; ok {
+ t.Errorf("%s must not be published", absent)
}
}
- if _, ok := f.Hosts["orphan.example.org"]; ok {
- t.Error("an alias of an unserved primary was published")
+ if h := hosts["real.example.net"]; !h.Platform || h.Alias {
+ t.Errorf("an alias colliding with a real route displaced the route's entry: %+v", h)
+ }
+ // Detach: gone on the next pass.
+ if err := reg.DeleteAlias("www.customer.com"); err != nil {
+ t.Fatal(err)
}
- if h := f.Hosts["real.example.net"]; !h.Platform {
- t.Error("an alias colliding with a real route displaced the route's entry")
+ if _, ok := publish()["www.customer.com"]; ok {
+ t.Error("a detached alias was still published")
}
}