package domains import ( "context" "encoding/json" "fmt" "path/filepath" "strings" "testing" "time" "github.com/carlosframework/platform/internal/registry" "github.com/carlosframework/platform/internal/release" ) // aliasRegWith opens a fresh registry and seeds it with routes, the same // pattern reconcile_test.go's regWith uses (that helper lives in the // domains_test package, unreachable from here). func aliasRegWith(t *testing.T, routes ...registry.Route) *registry.Registry { t.Helper() reg, err := registry.Open(filepath.Join(t.TempDir(), "registry.db")) if err != nil { t.Fatal(err) } for _, rt := range routes { if err := reg.Upsert(rt); err != nil { t.Fatal(err) } } return reg } // putClaim writes c's JSON straight to its ClaimKey, bypassing AttachClaim's // CAS dance — the reconcile pass reads whatever is in the bucket, not just // what AttachClaim would have produced. func putClaim(t *testing.T, s release.Store, c Claim) { t.Helper() c.Schema = 1 body, err := json.Marshal(c) if err != nil { t.Fatal(err) } if _, err := s.Put(context.Background(), ClaimKey(c.Host), body, ""); err != nil { t.Fatal(err) } } // deleteClaim removes host's claim from the bucket, so a re-run of // ReconcileAliases sees it gone (pass-owned removal tests). func deleteClaim(t *testing.T, s release.Store, host string) { t.Helper() if err := s.Delete(context.Background(), ClaimKey(host)); err != nil { t.Fatal(err) } } // addRoute upserts one route into reg, same shape the other tests in this // file inline into aliasRegWith's constructor call. func addRoute(t *testing.T, reg *registry.Registry, host, account, app string) { t.Helper() if err := reg.Upsert(registry.Route{ Host: host, App: app, Account: account, Kind: "instance", Status: "ready", }); err != nil { t.Fatal(err) } } func aliasNow() func() time.Time { return func() time.Time { return time.Unix(1755000000, 0) } } func TestReconcileAliasesMaterializes(t *testing.T) { s := release.NewDirStore(t.TempDir()) reg := aliasRegWith(t, registry.Route{ Host: "canary/live", App: "kass", Account: "bab", Kind: "instance", Status: "ready", }) putClaim(t, s, Claim{ Host: "tickets.example.com", Account: "bab", App: "kass", Route: "canary/live", }) if err := ReconcileAliases(context.Background(), s, reg, aliasNow(), nil, nil); err != nil { t.Fatal(err) } aliases, err := reg.ListAliases() if err != nil { t.Fatal(err) } if len(aliases) != 1 { t.Fatalf("got %d aliases, want 1: %+v", len(aliases), aliases) } a := aliases[0] if a.Alias != "tickets.example.com" || a.Host != "canary/live" || a.Account != "bab" || a.App != "kass" || a.CreatedAt != 1755000000 { t.Fatalf("alias row mismatch: %+v", a) } } func TestReconcileAliasesOwnershipGate(t *testing.T) { s := release.NewDirStore(t.TempDir()) reg := aliasRegWith(t, registry.Route{ Host: "canary/live", App: "kass", Account: "bab", Kind: "instance", Status: "ready", }) // Claim names the right route but the wrong app. putClaim(t, s, Claim{ Host: "tickets.example.com", Account: "bab", App: "somethingelse", Route: "canary/live", }) if err := ReconcileAliases(context.Background(), s, reg, aliasNow(), nil, nil); err != nil { t.Fatal(err) } aliases, err := reg.ListAliases() if err != nil { t.Fatal(err) } if len(aliases) != 0 { t.Fatalf("got %d aliases, want 0: %+v", len(aliases), aliases) } } func TestReconcileAliasesOwnershipGateAccountMismatch(t *testing.T) { s := release.NewDirStore(t.TempDir()) // Route's account is a VALID sqid ("bad") so release.RouteAccount // returns it verbatim rather than falling back to OpsAccount — the // mismatch must come from the comparison itself, not an invalid-account // fallback masking it. reg := aliasRegWith(t, registry.Route{ Host: "canary/live", App: "kass", Account: "bad", Kind: "instance", Status: "ready", }) // Claim names the right route and the right app, but a different // (also valid) account. putClaim(t, s, Claim{ Host: "tickets.example.com", Account: "bab", App: "kass", Route: "canary/live", }) if err := ReconcileAliases(context.Background(), s, reg, aliasNow(), nil, nil); err != nil { t.Fatal(err) } aliases, err := reg.ListAliases() if err != nil { t.Fatal(err) } if len(aliases) != 0 { t.Fatalf("got %d aliases, want 0 (account mismatch must refuse): %+v", len(aliases), aliases) } } func TestReconcileAliasesRoutesWin(t *testing.T) { s := release.NewDirStore(t.TempDir()) reg := aliasRegWith(t, registry.Route{Host: "canary/live", App: "kass", Account: "bab", Kind: "instance", Status: "ready"}, registry.Route{Host: "tickets.example.com", App: "other", Account: "bab", Kind: "instance", Status: "ready"}, ) putClaim(t, s, Claim{ Host: "tickets.example.com", Account: "bab", App: "kass", Route: "canary/live", }) if err := ReconcileAliases(context.Background(), s, reg, aliasNow(), nil, nil); err != nil { t.Fatal(err) } aliases, err := reg.ListAliases() if err != nil { t.Fatal(err) } if len(aliases) != 0 { t.Fatalf("got %d aliases, want 0 (a real route owns that host): %+v", len(aliases), aliases) } } func TestReconcileAliasesMissingRouteSkips(t *testing.T) { s := release.NewDirStore(t.TempDir()) reg := aliasRegWith(t) // no routes at all — this box doesn't have the route putClaim(t, s, Claim{ Host: "tickets.example.com", Account: "bab", App: "kass", Route: "canary/live", }) if err := ReconcileAliases(context.Background(), s, reg, aliasNow(), nil, nil); err != nil { t.Fatal(err) } aliases, err := reg.ListAliases() if err != nil { t.Fatal(err) } if len(aliases) != 0 { t.Fatalf("got %d aliases, want 0: %+v", len(aliases), aliases) } } func TestReconcileAliasesRemovesOrphans(t *testing.T) { s := release.NewDirStore(t.TempDir()) reg := aliasRegWith(t, registry.Route{ Host: "canary/live", App: "kass", Account: "bab", Kind: "instance", Status: "ready", }) if err := reg.UpsertAlias(registry.RouteAlias{ Alias: "orphan.example.com", Host: "canary/live", Account: "bab", App: "kass", CreatedAt: 1000, }); err != nil { t.Fatal(err) } // No claim backs orphan.example.com. if err := ReconcileAliases(context.Background(), s, reg, aliasNow(), nil, nil); err != nil { t.Fatal(err) } aliases, err := reg.ListAliases() if err != nil { t.Fatal(err) } if len(aliases) != 0 { t.Fatalf("got %d aliases, want 0 (orphan should have been removed): %+v", len(aliases), aliases) } } func TestReconcileAliasesRouteless(t *testing.T) { s := release.NewDirStore(t.TempDir()) reg := aliasRegWith(t, registry.Route{ Host: "canary/live", App: "kass", Account: "bab", Kind: "instance", Status: "ready", }) // A first-route claim (#82's case): no Route set yet. putClaim(t, s, Claim{ Host: "tickets.example.com", Account: "bab", App: "kass", }) if err := ReconcileAliases(context.Background(), s, reg, aliasNow(), nil, nil); err != nil { t.Fatal(err) } aliases, err := reg.ListAliases() if err != nil { t.Fatal(err) } if len(aliases) != 0 { t.Fatalf("got %d aliases, want 0 (routeless claim must be ignored): %+v", len(aliases), aliases) } } func TestReconcileAliasesIdempotent(t *testing.T) { s := release.NewDirStore(t.TempDir()) reg := aliasRegWith(t, registry.Route{ Host: "canary/live", App: "kass", Account: "bab", Kind: "instance", Status: "ready", }) putClaim(t, s, Claim{ Host: "tickets.example.com", Account: "bab", App: "kass", Route: "canary/live", }) if err := ReconcileAliases(context.Background(), s, reg, aliasNow(), nil, nil); err != nil { t.Fatal(err) } first, err := reg.ListAliases() if err != nil { t.Fatal(err) } if len(first) != 1 { t.Fatalf("got %d aliases after first pass, want 1: %+v", len(first), first) } firstCreatedAt := first[0].CreatedAt // Second pass, later clock: CreatedAt must be preserved, not bumped. later := func() time.Time { return time.Unix(1755000000+3600, 0) } if err := ReconcileAliases(context.Background(), s, reg, later, nil, nil); err != nil { t.Fatal(err) } second, err := reg.ListAliases() if err != nil { t.Fatal(err) } if len(second) != 1 { t.Fatalf("got %d aliases after second pass, want 1: %+v", len(second), second) } if second[0].CreatedAt != firstCreatedAt { t.Fatalf("CreatedAt changed on re-run: first=%d second=%d", firstCreatedAt, second[0].CreatedAt) } if second[0].Alias != first[0].Alias || second[0].Host != first[0].Host || second[0].Account != first[0].Account || second[0].App != first[0].App { t.Fatalf("alias row changed on re-run: first=%+v second=%+v", first[0], second[0]) } } // TestReconcileWildcardCreatedAtStable is the final-review pin: unlike // route_aliases (UpsertAlias's ON CONFLICT deliberately leaves created_at out // of its SET list, so the DB itself preserves it), UpsertWildcardDomain DOES // overwrite created_at on conflict — wildcard_domains.created_at is only kept // stable by the reconcile pass's own skip-upsert-when-unchanged guard (an // unchanged host/account/app row is never re-upserted). That guard matters // because Fingerprint hashes wildcard_domains.created_at (unlike // route_aliases, which excludes it): a created_at that bumped on every pass // would move the fingerprint on every 2s poll and force a needless edge // reload forever, even with a completely unchanged claim set. func TestReconcileWildcardCreatedAtStable(t *testing.T) { s := release.NewDirStore(t.TempDir()) reg := aliasRegWith(t) addRoute(t, reg, "woodstar-relay.bab.oncarlos.com", "bab", "woodstar-relay") putClaim(t, s, Claim{Host: "woodstar.app", Account: "bab", App: "woodstar-relay", Route: "woodstar-relay.bab.oncarlos.com", CreatedAt: "2026-08-13T00:00:00Z", Wildcard: true, Catchall: true}) if err := ReconcileAliases(context.Background(), s, reg, func() time.Time { return time.Unix(1000, 0) }, nil, nil); err != nil { t.Fatal(err) } first, err := reg.ListWildcardDomains() if err != nil { t.Fatal(err) } if len(first) != 1 || first[0].Host != "woodstar.app" { t.Fatalf("wildcard_domains after first pass = %+v, want one row for woodstar.app", first) } firstCreatedAt := first[0].CreatedAt // Second pass, later clock, same claim set: CreatedAt must be preserved, // not bumped — a bump here would move Fingerprint's wildcard_domains // section every poll and force a reload→refresh loop with nothing // actually changed. if err := ReconcileAliases(context.Background(), s, reg, func() time.Time { return time.Unix(1000+3600, 0) }, nil, nil); err != nil { t.Fatal(err) } second, err := reg.ListWildcardDomains() if err != nil { t.Fatal(err) } if len(second) != 1 || second[0].Host != "woodstar.app" { t.Fatalf("wildcard_domains after second pass = %+v, want one row for woodstar.app", second) } if second[0].CreatedAt != firstCreatedAt { t.Fatalf("wildcard_domains CreatedAt changed on re-run: first=%d second=%d", firstCreatedAt, second[0].CreatedAt) } } func TestReconcileDerivesWildcardState(t *testing.T) { ctx := context.Background() s := release.NewDirStore(t.TempDir()) reg := aliasRegWith(t) // Local primary route, tenancy bab/woodstar-relay. addRoute(t, reg, "woodstar-relay.bab.oncarlos.com", "bab", "woodstar-relay") putClaim(t, s, Claim{Host: "woodstar.app", Account: "bab", App: "woodstar-relay", Route: "woodstar-relay.bab.oncarlos.com", CreatedAt: "2026-08-13T00:00:00Z", Wildcard: true, Catchall: true}) // Wildcard-only (no catchall): row yes, *. alias no. putClaim(t, s, Claim{Host: "certonly.example", Account: "bab", App: "woodstar-relay", Route: "woodstar-relay.bab.oncarlos.com", CreatedAt: "2026-08-13T00:00:00Z", Wildcard: true}) // Wildcard claim whose primary is NOT on this box: no row. putClaim(t, s, Claim{Host: "elsewhere.example", Account: "bab", App: "woodstar-relay", Route: "not-here.bab.oncarlos.com", CreatedAt: "2026-08-13T00:00:00Z", Wildcard: true}) // Invalid host shape: no row, no alias. putClaim(t, s, Claim{Host: "bad host.example", Account: "bab", App: "woodstar-relay", Route: "woodstar-relay.bab.oncarlos.com", CreatedAt: "2026-08-13T00:00:00Z", Wildcard: true, Catchall: true}) if err := ReconcileAliases(ctx, s, reg, func() time.Time { return time.Unix(1000, 0) }, nil, nil); err != nil { t.Fatal(err) } wds, err := reg.ListWildcardDomains() if err != nil { t.Fatal(err) } if len(wds) != 2 || wds[0].Host != "certonly.example" || wds[1].Host != "woodstar.app" { t.Fatalf("wildcard_domains = %+v", wds) } aliases, _ := reg.ListAliases() var stars []string for _, a := range aliases { if strings.HasPrefix(a.Alias, "*.") { stars = append(stars, a.Alias+"->"+a.Host) } } if len(stars) != 1 || stars[0] != "*.woodstar.app->woodstar-relay.bab.oncarlos.com" { t.Fatalf("catch-all aliases = %v", stars) } // Claim removed => derived state removed (pass-owned). deleteClaim(t, s, "woodstar.app") if err := ReconcileAliases(ctx, s, reg, func() time.Time { return time.Unix(2000, 0) }, nil, nil); err != nil { t.Fatal(err) } wds, _ = reg.ListWildcardDomains() if len(wds) != 1 || wds[0].Host != "certonly.example" { t.Fatalf("after claim delete: %+v", wds) } aliases, _ = reg.ListAliases() for _, a := range aliases { if strings.HasPrefix(a.Alias, "*.") { t.Fatalf("catch-all alias must be removed with its claim: %+v", a) } } } func TestReconcileWildcardHostCollisionMismatchedTenant(t *testing.T) { // A named-Route wildcard claim whose own Host is itself a REAL local // route owned by a DIFFERENT tenant: the wildcard row (and any // catch-all) must be refused, same spirit as the plain-alias half // already refusing to shadow a real route. The claim's Route names a // primary that DOES belong to the claim's own tenant, so the // primary-tenancy check alone would pass — the collision on c.Host // itself is the only gate that can catch this case. ctx := context.Background() s := release.NewDirStore(t.TempDir()) reg := aliasRegWith(t) addRoute(t, reg, "primary.bab.oncarlos.com", "bab", "appA") addRoute(t, reg, "hostx.example", "bad", "appB") // real route, different tenant putClaim(t, s, Claim{Host: "hostx.example", Account: "bab", App: "appA", Route: "primary.bab.oncarlos.com", CreatedAt: "2026-08-13T00:00:00Z", Wildcard: true, Catchall: true}) if err := ReconcileAliases(ctx, s, reg, func() time.Time { return time.Unix(1000, 0) }, nil, nil); err != nil { t.Fatal(err) } wds, err := reg.ListWildcardDomains() if err != nil { t.Fatal(err) } if len(wds) != 0 { t.Fatalf("wildcard_domains = %+v, want none (real route under a different tenant owns the host)", wds) } aliases, err := reg.ListAliases() if err != nil { t.Fatal(err) } for _, a := range aliases { if strings.HasPrefix(a.Alias, "*.") { t.Fatalf("no catch-all should derive from a refused wildcard claim: %+v", a) } } } func TestReconcileWildcardCap(t *testing.T) { ctx := context.Background() s := release.NewDirStore(t.TempDir()) reg := aliasRegWith(t) addRoute(t, reg, "primary.bab.oncarlos.com", "bab", "appA") // 33 valid wildcard claims sharing one local primary, with deterministic // zero-padded hosts so bucket-list (lexicographic) order matches numeric // order: w00.example .. w32.example. for i := 0; i < 33; i++ { putClaim(t, s, Claim{Host: fmt.Sprintf("w%02d.example", i), Account: "bab", App: "appA", Route: "primary.bab.oncarlos.com", CreatedAt: "2026-08-13T00:00:00Z", Wildcard: true}) } if err := ReconcileAliases(ctx, s, reg, func() time.Time { return time.Unix(1000, 0) }, nil, nil); err != nil { t.Fatal(err) } wds, err := reg.ListWildcardDomains() if err != nil { t.Fatal(err) } if len(wds) != 32 { t.Fatalf("got %d wildcard_domains, want 32 (per-box cap): %+v", len(wds), wds) } for _, w := range wds { if w.Host == "w32.example" { t.Fatalf("w32.example (33rd claim, lexicographically last) should have been dropped over the cap: %+v", wds) } } } func TestReconcileWildcardEmptyRouteClaim(t *testing.T) { // First-route claim (#82's shape): empty Route, the claim's own host IS // the primary once materialized. Catchall aliases that primary. ctx := context.Background() s := release.NewDirStore(t.TempDir()) reg := aliasRegWith(t) addRoute(t, reg, "story.example", "bab", "story") putClaim(t, s, Claim{Host: "story.example", Account: "bab", App: "story", CreatedAt: "2026-08-13T00:00:00Z", Wildcard: true, Catchall: true}) if err := ReconcileAliases(ctx, s, reg, func() time.Time { return time.Unix(1000, 0) }, nil, nil); err != nil { t.Fatal(err) } wds, _ := reg.ListWildcardDomains() if len(wds) != 1 || wds[0].Host != "story.example" { t.Fatalf("wildcard_domains = %+v", wds) } aliases, _ := reg.ListAliases() found := false for _, a := range aliases { if a.Alias == "*.story.example" && a.Host == "story.example" { found = true } } if !found { t.Fatalf("want *.story.example -> story.example, got %+v", aliases) } } // --- Task 4: the reserved sidecar suffix, enforced at the alias door ----- // // Task 3 already refuses to SERVE a Kind=="sidecar" row (edge.go's Reload). // ReconcileAliases must never mint a route_aliases row that names a // reserved-suffix host on EITHER end: as the primary (Host), which would // keep an unroutable sidecar name "alive" as somebody's alias target, and — // the direction the Task 3 review caught, and the one most likely to be // missed — as the alias's OWN name (Alias), which would insert a sidecar // hostname into the edge's routing map serving an ORDINARY route's upstream, // making Allowed() return true for it (an ACME order on a sidecar hostname). // TestReconcileAliasesRefusesReservedSuffixPrimary: the claim's Route names // a host under the reserved suffix. Even though such a route can exist in // the registry (a real provisioned sidecar's own row, Kind=="sidecar"), // ReconcileAliases must never let anything alias it. func TestReconcileAliasesRefusesReservedSuffixPrimary(t *testing.T) { s := release.NewDirStore(t.TempDir()) reg := aliasRegWith(t, registry.Route{ Host: "bot.eleven.bdm.sidecar.internal", App: "eleven", Account: "bdm", Kind: "sidecar", Status: "ready", }) putClaim(t, s, Claim{ Host: "tickets.example.com", Account: "bdm", App: "eleven", Route: "bot.eleven.bdm.sidecar.internal", }) if err := ReconcileAliases(context.Background(), s, reg, aliasNow(), nil, nil); err != nil { t.Fatal(err) } aliases, err := reg.ListAliases() if err != nil { t.Fatal(err) } if len(aliases) != 0 { t.Fatalf("got %d aliases, want 0 (a reserved-suffix primary must never be aliased): %+v", len(aliases), aliases) } } // TestReconcileAliasesRefusesReservedSuffixAliasName is the end the brief's // wording alone would miss: the PRIMARY is an ordinary route, but the // ALIAS's own name is under the reserved suffix. Nothing about tenancy or // route existence would refuse this — only a check on the alias name // itself does, and this is the exact row the Task 3 review named: inserted // into edge's routing map, it would serve the primary's upstream under a // sidecar hostname and make Allowed() true for it. func TestReconcileAliasesRefusesReservedSuffixAliasName(t *testing.T) { s := release.NewDirStore(t.TempDir()) reg := aliasRegWith(t, registry.Route{ Host: "canary/live", App: "kass", Account: "bab", Kind: "instance", Status: "ready", }) putClaim(t, s, Claim{ Host: "bot.eleven.bdm.sidecar.internal", Account: "bab", App: "kass", Route: "canary/live", }) if err := ReconcileAliases(context.Background(), s, reg, aliasNow(), nil, nil); err != nil { t.Fatal(err) } aliases, err := reg.ListAliases() if err != nil { t.Fatal(err) } if len(aliases) != 0 { t.Fatalf("got %d aliases, want 0 (an alias name under the reserved suffix must never be minted): %+v", len(aliases), aliases) } } // TestReconcileAliasesRefusesReservedSuffixCatchall: the same alias-name-end // danger, through the OTHER route_aliases writer (the catch-all "*." // derivation off a Wildcard+Catchall claim) — a second call site, so it // needs its own guard, not just the plain-alias one above. func TestReconcileAliasesRefusesReservedSuffixCatchall(t *testing.T) { ctx := context.Background() s := release.NewDirStore(t.TempDir()) reg := aliasRegWith(t) addRoute(t, reg, "app.bab.oncarlos.com", "bab", "app") putClaim(t, s, Claim{ Host: "sub.eleven.bdm.sidecar.internal", Account: "bab", App: "app", Route: "app.bab.oncarlos.com", CreatedAt: "2026-08-13T00:00:00Z", Wildcard: true, Catchall: true, }) if err := ReconcileAliases(ctx, s, reg, aliasNow(), nil, nil); err != nil { t.Fatal(err) } aliases, err := reg.ListAliases() if err != nil { t.Fatal(err) } for _, a := range aliases { if strings.HasPrefix(a.Alias, "*.") { t.Fatalf("a catch-all alias under the reserved suffix must never be minted: %+v", a) } } } // A claim naming a hostname that ANOTHER box serves as a real route must not // materialize. The byHost check above it is per-box (byHost is THIS box's // routes), and the attach door cannot verify a route exists at all — // operator-minted rows have no instance record. So without this, an account // can claim someone else's operator route and, now that aliases publish // fleet-wide, capture its traffic on every remote edge. func TestReconcileAliasesRefusesAHostAnotherBoxServesAsARoute(t *testing.T) { s := release.NewDirStore(t.TempDir()) reg := aliasRegWith(t, registry.Route{ Host: "canary/live", App: "kass", Account: "bab", Kind: "instance", Status: "ready", }) putClaim(t, s, Claim{ Host: "go.tito.io", Account: "bab", App: "kass", Route: "canary/live", }) // go.tito.io is a real, non-alias route on some OTHER box in the fleet. deploymentRoutes := map[string]bool{"go.tito.io": true} if err := ReconcileAliases(context.Background(), s, reg, aliasNow(), deploymentRoutes, nil); err != nil { t.Fatal(err) } aliases, err := reg.ListAliases() if err != nil { t.Fatal(err) } for _, a := range aliases { if a.Alias == "go.tito.io" { t.Fatalf("an alias must not materialize for a hostname another box serves as a real route: %+v", aliases) } } } // Retro-clean: a claim that materialized before this rule existed is removed // on the next pass, which is the half neither the fold rule nor a door check // can deliver — both of those only ever act on NEW traffic and NEW attaches. func TestReconcileAliasesRemovesAnAliasThatNowCollidesWithADeploymentRoute(t *testing.T) { s := release.NewDirStore(t.TempDir()) reg := aliasRegWith(t, registry.Route{ Host: "canary/live", App: "kass", Account: "bab", Kind: "instance", Status: "ready", }) if err := reg.UpsertAlias(registry.RouteAlias{ Alias: "go.tito.io", Host: "canary/live", Account: "bab", App: "kass", CreatedAt: 1000, }); err != nil { t.Fatal(err) } putClaim(t, s, Claim{ Host: "go.tito.io", Account: "bab", App: "kass", Route: "canary/live", }) deploymentRoutes := map[string]bool{"go.tito.io": true} if err := ReconcileAliases(context.Background(), s, reg, aliasNow(), deploymentRoutes, nil); err != nil { t.Fatal(err) } aliases, err := reg.ListAliases() if err != nil { t.Fatal(err) } for _, a := range aliases { if a.Alias == "go.tito.io" { t.Fatalf("a pre-existing colliding alias must be removed on the next pass: %+v", aliases) } } } // An empty/unknown deployment-route set must not break ordinary attach: the // fold degrades to "nothing known", and an unrelated custom domain still // materializes. Fail-OPEN here is the deliberate choice — the fold is // best-effort evidence read out of a bucket, and a bucket that cannot be // listed must not take every tenant's custom domain down with it. The local // byHost check and the remote fold's route preference both still stand. func TestReconcileAliasesStillMaterializesWhenTheRouteSetIsUnknown(t *testing.T) { s := release.NewDirStore(t.TempDir()) reg := aliasRegWith(t, registry.Route{ Host: "canary/live", App: "kass", Account: "bab", Kind: "instance", Status: "ready", }) putClaim(t, s, Claim{ Host: "shop.customer.com", Account: "bab", App: "kass", Route: "canary/live", }) if err := ReconcileAliases(context.Background(), s, reg, aliasNow(), nil, nil); err != nil { t.Fatal(err) } aliases, err := reg.ListAliases() if err != nil { t.Fatal(err) } if len(aliases) != 1 || aliases[0].Alias != "shop.customer.com" { t.Fatalf("aliases = %+v, want the ordinary custom domain materialized", aliases) } } // The pin for the one mistake this task is most likely to make: the // catch-all guard must ask about "*."+host, NEVER host. // // A first-route wildcard claim's own host IS a real, non-alias route on the // claimant's OWN box — that is precisely what "first route" means — so it // appears in the deployment route set by construction. A guard keyed on // c.Host would therefore refuse the catch-all for every wildcard first-route // claim in the fleet, on the very deployment that owns it. That is the // woodstar.app class, live in production today. // // This test fails with deploymentRoutes[c.Host] and passes with // deploymentRoutes[star]. Nothing else in this file distinguishes them. func TestReconcileAliasesStillDerivesTheCatchAllForAFirstRouteClaim(t *testing.T) { s := release.NewDirStore(t.TempDir()) // The route carries the claim's OWN account and app on purpose: the // ownership gate above the new guard would short-circuit on a mismatched // row and the test would pass for the wrong reason. reg := aliasRegWith(t, registry.Route{ Host: "woodstar.app", App: "site", Account: "bab", Kind: "static", Status: "ready", }) putClaim(t, s, Claim{ Host: "woodstar.app", Account: "bab", App: "site", Route: "", Wildcard: true, Catchall: true, // first-route: its own primary }) // The claimant's own box publishes woodstar.app as a REAL route. deploymentRoutes := map[string]bool{"woodstar.app": true} if err := ReconcileAliases(context.Background(), s, reg, aliasNow(), deploymentRoutes, nil); err != nil { t.Fatal(err) } aliases, err := reg.ListAliases() if err != nil { t.Fatal(err) } found := false for _, a := range aliases { if a.Alias == "*.woodstar.app" && a.Host == "woodstar.app" { found = true } } if !found { t.Fatalf("catch-all missing: %+v — the guard keyed on the claim host "+ "instead of \"*.\"+host, refusing every first-route wildcard claim", aliases) } }