carlos / platform Public

host: mark a served catch-all as an alias, so it stops refusing itself (#382)

A box that serves a delegated wildcard's catch-all published the
"*.<parent>" row with role home and no alias mark. edgesfile.
DeploymentRoutes reads exactly `Role == RoleHome && !Alias` as "some live
box serves this hostname as a real route", so the box's own edges file
became evidence against its own claim: the next domains.ReconcileAliases
pass refused the catch-all ("another box serves that hostname as a
route") and deleted the alias row, which turned the dial half off, which
dropped the row, which let the pass after that recreate it.

The result is a name that flaps rather than one that breaks, so nothing
alerts. *.woodstar.app has been cycling every 5-6 minutes for at least a
day, taking the PDS endpoint and AT Proto handle resolution under it down
about half of every hour while the apex — which has its own route — stayed
green throughout.

The catch-all key never reaches the alias loop above (it skips "*." rows
deliberately, #302/#305), so the wildcard_domains loop is the only place
its class can be set. A catch-all we actually serve IS a materialized
claim, which is what the mark means. The merge branch just above already
preserved Alias when a real route owned the key; only the fresh write was
wrong, and a real route still publishes unmarked and keeps its authority.

The end-to-end test is the one that matters: neither half is wrong on its
own, so it publishes with the real publisher and folds with the real
reader. Reverted against this commit it reproduces the production set,
`map[*.customer.example:true app.acct.apps.test:true]`.


Claude-Session: https://claude.ai/code/session_01LX3AD7SrzYYBbeiFswMoqm
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Paul Campbell pushed by paul@keymail.dev ceecb3a9c27dcf5149cecadf2e076c6a0f950450 parent f975b47
2 files changed, +75 −10
  • internal/host/edgesfile.go +17 −3
  • internal/host/edgesfile_test.go +58 −7

CI passed — run details

diff --git a/internal/host/edgesfile.go b/internal/host/edgesfile.go
index faad8b53f..e6b89b944 100644
--- a/internal/host/edgesfile.go
+++ b/internal/host/edgesfile.go
@@ -258,11 +258,25 @@ func edgesFilePass(ctx context.Context, s release.Store, reg *registry.Registry,
hosts[key] = prev
continue
}
- role := "wildcard"
+ // Marked alias whenever the DIAL half is on, and the mark is
+ // load-bearing rather than cosmetic. The catch-all key never reaches
+ // the alias loop above (it skips "*." rows on purpose), so this is
+ // the only place its class can be set — and edgesfile.DeploymentRoutes
+ // reads exactly `Role == RoleHome && !Alias` as "some live box serves
+ // this hostname as a real route". Published unmarked, a served
+ // catch-all is therefore evidence against itself: the next
+ // domains.ReconcileAliases pass reads our own file back, refuses the
+ // claim that produced the row, and drops the alias — which turns the
+ // dial half off, unmarks nothing, and lets the pass after that
+ // recreate it. That loop is not theoretical; it ran on *.woodstar.app
+ // every 5-6 minutes, taking the name down about half of every hour.
+ // A catch-all we serve IS a materialized claim, which is what the
+ // mark means, so say so.
+ role, alias := "wildcard", false
if catchallServed[wd.Host] {
- role = "home"
+ role, alias = "home", true
}
- hosts[key] = edgeHost{Role: role, Wildcard: true}
+ hosts[key] = edgeHost{Role: role, Wildcard: true, Alias: alias}
}
if eip == "" && *last != nil {
diff --git a/internal/host/edgesfile_test.go b/internal/host/edgesfile_test.go
index 96fd900ff..d43ea1c99 100644
--- a/internal/host/edgesfile_test.go
+++ b/internal/host/edgesfile_test.go
@@ -746,28 +746,79 @@ func TestEdgesFilePublishesDelegatedWildcardParents(t *testing.T) {
Role string `json:"role"`
Platform bool `json:"platform"`
Wildcard bool `json:"wildcard"`
+ Alias bool `json:"alias"`
} `json:"hosts"`
}
if err := json.Unmarshal(body, &f); err != nil {
t.Fatal(err)
}
+ // Marked alias BECAUSE the dial half is on: a catch-all we serve is a
+ // materialized claim, and DeploymentRoutes keys the whole "is this
+ // somebody's real route" question on that mark. See the end-to-end
+ // tripwire below for what an unmarked row does to the claim.
h, ok := f.Hosts["*.customer.example"]
- if !ok || h.Role != "home" || !h.Wildcard || h.Platform {
- t.Fatalf("*.customer.example = %+v, %v; want home, wildcard, not platform", h, ok)
+ if !ok || h.Role != "home" || !h.Wildcard || h.Platform || !h.Alias {
+ t.Fatalf("*.customer.example = %+v, %v; want home, wildcard, alias, not platform", h, ok)
}
for _, name := range []string{"*.certonly.example", "*.pending.example"} {
h, ok := f.Hosts[name]
- if !ok || h.Role != "wildcard" || !h.Wildcard || h.Platform {
- t.Errorf("%s = %+v, %v; want the cert half only (role wildcard)", name, h, ok)
+ if !ok || h.Role != "wildcard" || !h.Wildcard || h.Platform || h.Alias {
+ t.Errorf("%s = %+v, %v; want the cert half only (role wildcard, unmarked)", name, h, ok)
}
}
if _, ok := f.Hosts["*.*.odd.example"]; ok {
t.Error("a malformed wildcard_domains row was published")
}
// 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)
+ // class is added — the reader must still load the PEM everywhere. It
+ // stays UNMARKED, which is the other half of the mark's meaning: this
+ // hostname really is served as a route, so it must go on outranking any
+ // claim another box makes on the same name.
+ if h := f.Hosts["*.taken.example"]; !h.Platform || !h.Wildcard || h.Role != "home" || h.Alias {
+ t.Errorf("route-owned key = %+v; want platform AND wildcard, role home, unmarked", h)
+ }
+}
+
+// The tripwire on a loop that ran in production: a served catch-all published
+// without the alias mark is read back by DeploymentRoutes as evidence that
+// some live box serves that hostname as a REAL route, so the next
+// domains.ReconcileAliases pass refuses the very claim that produced the row
+// and deletes the alias. Deleting it turns the dial half off, which drops the
+// row, which lets the pass after that recreate it — and the name flaps
+// on/off forever (*.woodstar.app, every 5-6 minutes, down about half the
+// time). Neither half is wrong alone, so only an end-to-end check catches it:
+// publish with the real publisher, then fold with the real reader.
+func TestEdgesFileServedCatchAllIsNotItsOwnDeploymentRoute(t *testing.T) {
+ s, reg := release.NewDirStore(t.TempDir()), edgesTestRegistry(t)
+ seedRoute(t, reg, "app.acct.apps.test")
+ if err := reg.UpsertAlias(registry.RouteAlias{
+ Alias: "*.customer.example", Host: "app.acct.apps.test", Account: "acct", App: "app",
+ }); err != nil {
+ t.Fatal(err)
+ }
+ if err := reg.UpsertWildcardDomain(registry.WildcardDomain{
+ Host: "customer.example", Account: "acct", App: "app",
+ }); err != nil {
+ t.Fatal(err)
+ }
+ var lastBody []byte
+ if err := edgesFilePass(context.Background(), s, reg, edgesFile{Box: "annie"}, "1.2.3.4", &lastBody); err != nil {
+ t.Fatal(err)
+ }
+ now := time.Now()
+ if err := status.WriteBox(context.Background(), s, status.Box{Label: "annie", GeneratedAt: now}); err != nil {
+ t.Fatal(err)
+ }
+
+ routes := edgesfile.DeploymentRoutes(context.Background(), s, now)
+ if routes["*.customer.example"] {
+ t.Errorf("routes = %v, want the served catch-all NOT counted as a real route — counting it makes the claim refuse itself every pass", routes)
+ }
+ // The join really happened: without this, an empty set would pass the
+ // assertion above for the wrong reason (a snapshot/label mismatch reads
+ // as "nothing known", which is permissive by contract).
+ if !routes["app.acct.apps.test"] {
+ t.Fatalf("routes = %v, want the box's real route counted — the fold did not join", routes)
}
}