carlos / platform Public

domains: sidecar names are reserved to everyone (#209 review)

Astra round 1, P1: a deny entry naming the sidecar suffix made its names
platform names, and the API alias branch never checked the suffix, so
--platform could claim one. domainHostPolicy now reserves the suffix outright,
which also closes the alias branch for members. The service-token test mints
as the ops owner, since a service principal carries its minter's address.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Human

Prompt

Can we address carlos/platform #209 ?

From this commit's own message. The prompt ledger has no entries for it — which is what a squashed, rebased or amended commit looks like, and what every commit looks like in a repo without a ledger.

Summary

Reserve .sidecar.internal names in domainHostPolicy; tighten the service-token test.
claude agent, operated by paul@keymail.dev dfeeb38900be3c70906373d7543e4a5af42bd584 parent 9fb9cbf
2 files changed, +29 −2
  • internal/console/domainplatform_test.go +20 −2
  • internal/console/domainpolicy.go +9 −0

CI passed — run details

diff --git a/internal/console/domainplatform_test.go b/internal/console/domainplatform_test.go
index a56f7cb73..9a31576cc 100644
--- a/internal/console/domainplatform_test.go
+++ b/internal/console/domainplatform_test.go
@@ -59,6 +59,7 @@ func TestDomainHostPolicyMatrix(t *testing.T) {
{"edge.apps.test", hostReserved}, // the steering host
{"apps.test", hostReserved},
{"site.bab.apps.test", hostReserved}, // a tenant's address
+ {"web.sidecar.internal", hostReserved},
}
for _, c := range cases {
if got := s.domainHostPolicy(c.host, "bab"); got != c.want {
@@ -108,10 +109,11 @@ func TestPlatformAttachRefusesMembers(t *testing.T) {
}
// TestPlatformAttachRefusesServices: an app token is never an operator, flag
-// or no flag.
+// or no flag, even one the ops owner minted (a service principal carries its
+// minter's address).
func TestPlatformAttachRefusesServices(t *testing.T) {
fx, _, _ := platformFixture(t, "code-plat-svc")
- tok, err := fx.st.NewAppToken(OpsAccountID, "titogo", "alice@keymail.dev", "signup", time.Now())
+ tok, err := fx.st.NewAppToken(OpsAccountID, "titogo", "paul@keymail.dev", "signup", time.Now())
if err != nil {
t.Fatal(err)
}
@@ -192,12 +194,16 @@ func TestPlatformAttachBySystemOperator(t *testing.T) {
func TestPlatformAttachReservedStaysRefused(t *testing.T) {
fx, _, paul := platformFixture(t, "code-plat-reserved")
fx.srv.cfg.Origin = "https://console.carloku.test"
+ // A deny entry naming the sidecar suffix must not make it a platform
+ // name the door lifts.
+ fx.srv.cfg.DenyDomains = append(fx.srv.cfg.DenyDomains, "sidecar.internal")
for _, host := range []string{
"console.carloku.test",
"hub.carloku.test",
"edge.oncarlos.test",
"oncarlos.test",
"titogo.bab.oncarlos.test",
+ "web.sidecar.internal",
} {
code, _, out := rawReq(t, http.MethodPost, domainsURL(fx, "bab", "titogo"), paul,
platformAttachBody(host, "go.tito.io"))
@@ -293,3 +299,15 @@ func TestPlatformBrowserDoors(t *testing.T) {
}
claimAbsent(t, fx, "carloku.test")
}
+
+// TestAPIAttachRefusesSidecarNames: the API door's alias branch refuses a
+// sidecar name to a member too, with or without a deny entry covering it.
+func TestAPIAttachRefusesSidecarNames(t *testing.T) {
+ fx, alice, _ := platformFixture(t, "code-plat-sidecar")
+ code, _, out := rawReq(t, http.MethodPost, domainsURL(fx, "bab", "titogo"), alice,
+ attachBody("web.sidecar.internal", "go.tito.io"))
+ if code != http.StatusBadRequest {
+ t.Errorf("member alias attach of a sidecar name = %d %s, want 400", code, out)
+ }
+ claimAbsent(t, fx, "web.sidecar.internal")
+}
diff --git a/internal/console/domainpolicy.go b/internal/console/domainpolicy.go
index a5f7e2aa7..052a5c9c0 100644
--- a/internal/console/domainpolicy.go
+++ b/internal/console/domainpolicy.go
@@ -6,6 +6,7 @@ import (
"strings"
"github.com/carlosframework/platform/internal/domains"
+ "github.com/carlosframework/platform/internal/provision"
)
// directAppsDomainHost reports whether host is one label under the apps
@@ -65,6 +66,14 @@ func (s *Server) domainHostPolicy(host, account string) hostPolicy {
if slices.Contains(s.consoleHosts(), host) {
return hostReserved
}
+ // provision.SidecarSuffix names a sidecar process, never a hostname
+ // anyone serves. attachDomain refuses it with its own message; this
+ // covers the API door's alias branch, which does not reach that check,
+ // and keeps a deny entry naming the suffix from turning it into a
+ // platform name the operator's door would lift (Astra review, #209).
+ if strings.HasSuffix(host, provision.SidecarSuffix) {
+ return hostReserved
+ }
allowed := domains.ValidSqid(account) && slices.Contains(s.cfg.AppsDomainAliasAccounts, account) && s.directAppsDomainHost(host)
if allowed {
domain := strings.ToLower(strings.TrimSpace(s.cfg.AppsDomain))