carlos / platform Public

Clone
git clone https://amadan.net/carlos/platform

Plain git — no account needed to clone.

Download

Download this file

1package console
2
3import (
4 "context"
5 "net/http"
6 "strings"
7 "testing"
8 "time"
9
10 "github.com/carlosframework/platform/internal/domains"
11 "github.com/carlosframework/platform/internal/edgesfile"
12 "github.com/carlosframework/platform/internal/registry"
13 "github.com/carlosframework/platform/internal/status"
14)
15
16func TestDirectAppsDomainHost(t *testing.T) {
17 cases := []struct {
18 name string
19 appsDomain string
20 host string
21 want bool
22 }{
23 {"no apps domain configured", "", "widget.apps.test", false},
24 {"the apex itself is not a one-label alias", "apps.test", "apps.test", false},
25 {"one label under the apps domain", "apps.test", "widget.apps.test", true},
26 {"a nested name is refused", "apps.test", "a.b.apps.test", false},
27 {"a host unrelated to the apps domain", "apps.test", "widget.other.test", false},
28 {"a suffix match without the separating dot", "apps.test", "notapps.test", false},
29 }
30 for _, c := range cases {
31 t.Run(c.name, func(t *testing.T) {
32 s := &Server{cfg: Config{AppsDomain: c.appsDomain, ReservePlatformDomains: true}}
33 if got := s.directAppsDomainHost(c.host); got != c.want {
34 t.Errorf("directAppsDomainHost(%q) with AppsDomain=%q = %v, want %v", c.host, c.appsDomain, got, c.want)
35 }
36 })
37 }
38}
39
40func TestDomainHostDeniedPolicyMatrix(t *testing.T) {
41 const appsDomain = "apps.test"
42 const alias = "widget." + appsDomain
43 base := func() Config {
44 return Config{
45 AppsDomain: appsDomain,
46 ReservePlatformDomains: true,
47 Origin: "https://origin." + appsDomain,
48 DenyDomains: []string{"blocked." + appsDomain},
49 RedirectHosts: []string{"retired." + appsDomain},
50 }
51 }
52 cases := []struct {
53 name string
54 mutate func(*Config)
55 host string
56 want bool
57 }{
58 {"flag off denies a one-label alias, unchanged from before the flag existed",
59 func(c *Config) {}, alias, true},
60 {"flag on allows an ordinary one-label alias",
61 func(c *Config) { c.AppsDomainAliasAccounts = []string{"bab"} }, alias, false},
62 {"flag on still denies the apex",
63 func(c *Config) { c.AppsDomainAliasAccounts = []string{"bab"} }, appsDomain, true},
64 {"flag on still denies a nested name",
65 func(c *Config) { c.AppsDomainAliasAccounts = []string{"bab"} }, "a.b." + appsDomain, true},
66 {"flag on still denies an explicit DenyDomains entry",
67 func(c *Config) { c.AppsDomainAliasAccounts = []string{"bab"} }, "blocked." + appsDomain, true},
68 {"flag on still denies the console's own origin host",
69 func(c *Config) { c.AppsDomainAliasAccounts = []string{"bab"} }, "origin." + appsDomain, true},
70 {"flag on still denies a retired redirect host",
71 func(c *Config) { c.AppsDomainAliasAccounts = []string{"bab"} }, "retired." + appsDomain, true},
72 {"flag on with no apps domain configured denies nothing new",
73 func(c *Config) { c.AppsDomainAliasAccounts = []string{"bab"}; c.AppsDomain = "" }, "widget.example.com", false},
74 }
75 for _, c := range cases {
76 t.Run(c.name, func(t *testing.T) {
77 cfg := base()
78 c.mutate(&cfg)
79 s := &Server{cfg: cfg}
80 if got := s.domainHostDenied(c.host, "bab"); got != c.want {
81 t.Errorf("domainHostDenied(%q) = %v, want %v (cfg=%+v)", c.host, got, c.want, cfg)
82 }
83 })
84 }
85}
86
87func TestAPIDomainAttachDeniesAppsDomainAliasByDefault(t *testing.T) {
88 fx, member := instanceFixture(t, "code-dom-alias-default")
89 fx.srv.cfg.AppsDomain = "oncarlos.test"
90 fx.srv.cfg.ReservePlatformDomains = true
91 code, _, out := rawReq(t, http.MethodPost, domainsURL(fx, "bab", "titogo"), member,
92 attachBody("widget.oncarlos.test", "go.tito.io"))
93 if code != http.StatusBadRequest {
94 t.Fatalf("attach of an apps-domain alias with the flag unset = %d %s, want 400", code, out)
95 }
96 claimAbsent(t, fx, "widget.oncarlos.test")
97}
98
99func TestAPIDomainAttachAllowsAppsDomainAlias(t *testing.T) {
100 fx, member := instanceFixture(t, "code-dom-alias-allow")
101 fx.srv.cfg.AppsDomain = "oncarlos.test"
102 fx.srv.cfg.ReservePlatformDomains = true
103 fx.srv.cfg.AppsDomainAliasAccounts = []string{fx.sqid}
104
105 if got := attachDomain(t, fx, member, "widget.oncarlos.test", "go.tito.io"); !got.Created {
106 t.Fatalf("attach of a one-label apps-domain alias = %+v, want created true", got)
107 }
108
109 for _, host := range []string{
110 "a.widget.oncarlos.test", // nested
111 "oncarlos.test", // the apex itself
112 } {
113 code, _, out := rawReq(t, http.MethodPost, domainsURL(fx, "bab", "titogo"), member,
114 attachBody(host, "go.tito.io"))
115 if code != http.StatusBadRequest {
116 t.Errorf("attach %q with aliases allowed = %d %s, want 400", host, code, out)
117 }
118 claimAbsent(t, fx, host)
119 }
120}
121
122func TestAPIDomainAttachAppsDomainAliasRejectsWildcardAndCatchall(t *testing.T) {
123 fx, member := instanceFixture(t, "code-dom-alias-wild")
124 fx.srv.cfg.AppsDomain = "oncarlos.test"
125 fx.srv.cfg.ReservePlatformDomains = true
126 fx.srv.cfg.AppsDomainAliasAccounts = []string{fx.sqid}
127 const host = "widget.oncarlos.test"
128
129 for name, body := range map[string]string{
130 "wildcard": `{"host":"` + host + `","route":"go.tito.io","wildcard":true}`,
131 "catchall": `{"host":"` + host + `","route":"go.tito.io","catchall":true}`,
132 } {
133 code, _, out := rawReq(t, http.MethodPost, domainsURL(fx, "bab", "titogo"), member, body)
134 if code != http.StatusBadRequest {
135 t.Errorf("%s flag on an apps-domain alias = %d %s, want 400", name, code, out)
136 }
137 claimAbsent(t, fx, host)
138 }
139 if got := attachDomain(t, fx, member, host, "go.tito.io"); !got.Created {
140 t.Fatalf("plain attach of the same host with neither flag set = %+v, want created true", got)
141 }
142}
143
144func TestAPIDomainAttachAppsDomainAliasStillRefusesForeignClaim(t *testing.T) {
145 fx, member := instanceFixture(t, "code-dom-alias-conflict")
146 fx.srv.cfg.AppsDomain = "oncarlos.test"
147 fx.srv.cfg.ReservePlatformDomains = true
148 fx.srv.cfg.AppsDomainAliasAccounts = []string{fx.sqid}
149 const host = "widget.oncarlos.test"
150 if _, _, err := domains.AttachClaim(context.Background(), fx.rel, domains.Claim{
151 Host: host, Account: "cdef", App: "widgets",
152 Route: "widgets.example.net", CreatedAt: time.Now().UTC().Format(time.RFC3339),
153 }); err != nil {
154 t.Fatal(err)
155 }
156 code, _, out := rawReq(t, http.MethodPost, domainsURL(fx, "bab", "titogo"), member,
157 attachBody(host, "go.tito.io"))
158 if code != http.StatusConflict {
159 t.Fatalf("attach of an apps-domain alias another account holds = %d %s, want 409", code, out)
160 }
161 if got := strings.TrimSpace(out); got != `{"error":"hostname unavailable"}` {
162 t.Fatalf("409 body = %s, want the neutral refusal", got)
163 }
164}
165
166func TestAPIDomainAttachAppsDomainAliasStillRefusesDeploymentRoute(t *testing.T) {
167 ctx := context.Background()
168 fx, member := instanceFixture(t, "code-dom-alias-route")
169 fx.srv.cfg.AppsDomain = "oncarlos.test"
170 fx.srv.cfg.ReservePlatformDomains = true
171 fx.srv.cfg.AppsDomainAliasAccounts = []string{fx.sqid}
172 const host = "widget.oncarlos.test"
173 if _, err := fx.rel.Put(ctx, edgesfile.Key("annie"),
174 []byte(`{"v":1,"box":"annie","eip":"198.51.100.9","hosts":{"`+host+`":{"role":"home"}}}`), ""); err != nil {
175 t.Fatal(err)
176 }
177 if err := status.WriteBox(ctx, fx.rel, status.Box{Label: "annie", GeneratedAt: time.Now()}); err != nil {
178 t.Fatal(err)
179 }
180 code, _, out := rawReq(t, http.MethodPost, domainsURL(fx, "bab", "titogo"), member,
181 attachBody(host, "two.go.tito.io"))
182 if code != http.StatusConflict {
183 t.Fatalf("attach of an apps-domain alias a live box already serves = %d %s, want 409", code, out)
184 }
185 claimAbsent(t, fx, host)
186}
187
188func TestAttachDomainCoreAppsDomainAlias(t *testing.T) {
189 fx, acct := attachFixture(t)
190 fx.srv.cfg.ReservePlatformDomains = true
191 fx.srv.cfg.Registry = attachRegistry(t,
192 registry.Route{Host: "story." + fx.sqid + ".oncarlos.com", Kind: "static", App: "story",
193 Account: fx.sqid, Channel: "canary/live", Status: "ready"},
194 )
195 const alias = "widget.oncarlos.com"
196
197 if _, ref := fx.srv.attachDomain(context.Background(), acct, "story", alias, "", "", "paul@keymail.dev"); ref == nil || ref.Status != http.StatusUnprocessableEntity {
198 t.Fatalf("attach of an apps-domain alias with the flag unset = %+v, want 422", ref)
199 }
200 claimAbsent(t, fx, alias)
201
202 fx.srv.cfg.AppsDomainAliasAccounts = []string{fx.sqid}
203 res, ref := fx.srv.attachDomain(context.Background(), acct, "story", alias, "", "", "paul@keymail.dev")
204 if ref != nil {
205 t.Fatalf("attach of an apps-domain alias with the flag set = refused %+v", ref)
206 }
207 want := "story." + fx.sqid + ".oncarlos.com"
208 if res.Claim.Route != want {
209 t.Fatalf("claim route = %q, want the ready route %q it aliases", res.Claim.Route, want)
210 }
211
212 if _, ref := fx.srv.attachDomain(context.Background(), acct, "story", "a.b.oncarlos.com", "", "", "paul@keymail.dev"); ref == nil || ref.Status != http.StatusUnprocessableEntity {
213 t.Fatalf("attach of a nested apps-domain name with the flag set = %+v, want still 422", ref)
214 }
215 claimAbsent(t, fx, "a.b.oncarlos.com")
216}
217
218func TestAttachDomainCoreAppsDomainAliasStillRefusesHeldHost(t *testing.T) {
219 fx, acct := attachFixture(t)
220 fx.srv.cfg.ReservePlatformDomains = true
221 fx.srv.cfg.AppsDomainAliasAccounts = []string{fx.sqid}
222 fx.srv.cfg.Registry = attachRegistry(t,
223 registry.Route{Host: "story." + fx.sqid + ".oncarlos.com", Kind: "static", App: "story",
224 Account: fx.sqid, Channel: "canary/live", Status: "ready"},
225 )
226 const alias = "widget.oncarlos.com"
227 seedClaim(t, fx, domains.Claim{Schema: 1, Host: alias, Account: "zzz", App: "rival"})
228
229 _, ref := fx.srv.attachDomain(context.Background(), acct, "story", alias, "", "", "paul@keymail.dev")
230 if ref == nil || ref.Status != http.StatusConflict || ref.Msg != "hostname unavailable" {
231 t.Fatalf("refusal = %+v, want exactly 409 hostname unavailable even though aliases are allowed", ref)
232 }
233}
234
235func TestAppsDomainAliasAccountAuthority(t *testing.T) {
236 s := &Server{cfg: Config{
237 AppsDomain: "platform.example.test", AppsDomainAliasAccounts: []string{"bap"},
238 ReservePlatformDomains: true,
239 Origin: "https://console.platform.example.test",
240 DenyDomains: []string{"example.test", "platform.example.test", "blocked.platform.example.test"},
241 }}
242 for _, tc := range []struct {
243 host, account string
244 denied bool
245 }{
246 {"pullup.platform.example.test", "bap", false},
247 {"pullup.platform.example.test", "bab", true},
248 {"pullup.platform.example.test", "", true},
249 {"bap.platform.example.test", "bap", true},
250 {"bab.platform.example.test", "bap", true},
251 {"edge.platform.example.test", "bap", true},
252 {"console.platform.example.test", "bap", true},
253 {"blocked.platform.example.test", "bap", true},
254 {"x.bap.platform.example.test", "bap", true},
255 {"platform.example.test", "bap", true},
256 {"outside.example.test", "bap", true},
257 } {
258 if got := s.domainHostDenied(tc.host, tc.account); got != tc.denied {
259 t.Errorf("%s/%s: denied=%v, want %v", tc.account, tc.host, got, tc.denied)
260 }
261 }
262 s.cfg.SteeringHost = "steering.platform.example.test."
263 if !s.domainHostDenied("steering.platform.example.test", "bap") {
264 t.Fatal("steering host allowed")
265 }
266}
267
268func TestAppsDomainAliasCannotMintFirstRoute(t *testing.T) {
269 fx, acct := attachFixture(t)
270 fx.srv.cfg.ReservePlatformDomains = true
271 fx.srv.cfg.AppsDomainAliasAccounts = []string{fx.sqid}
272 fx.srv.cfg.Registry = attachRegistry(t)
273 for _, kind := range []string{"", "static"} {
274 _, ref := fx.srv.attachDomain(context.Background(), acct, "story", "pullup.oncarlos.com", kind, "", "actor")
275 if ref == nil || ref.Status != http.StatusUnprocessableEntity {
276 t.Fatalf("kind %q: refusal=%v", kind, ref)
277 }
278 claimAbsent(t, fx, "pullup.oncarlos.com")
279 }
280}
281