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 "net/http"
5 "reflect"
6 "sort"
7 "testing"
8 "time"
9
10 "github.com/carlosframework/platform/internal/svcrole"
11)
12
13// deployDoors is spec §6, verbatim. A door added later is refused to a
14// deploy credential unless someone adds it here on purpose.
15var deployDoors = []string{
16 "GET /api/cli/apps",
17 "GET /api/cli/apps/{account}/{app}/channels",
18 "POST /api/cli/apps/{account}/{app}/releases",
19 "GET /api/cli/apps/{account}/{app}/releases",
20 "POST /api/cli/apps/{account}/{app}/promote",
21 "POST /api/cli/apps/{account}/{app}/rollback",
22 "GET /api/cli/apps/{account}/{app}/tags",
23 "GET /api/cli/apps/{account}/{app}/tags/{version}",
24 "GET /api/cli/apps/{account}/{app}/version-target",
25 "GET /api/cli/apps/{account}/{app}/pipeline",
26 "GET /api/cli/apps/{account}/{app}/pending",
27 "GET /api/cli/apps/{account}/{app}/instances", // R6: carlos deploy
28 "GET /api/cli/apps/{account}/{app}/regions", // R6: carlos deploy --region
29}
30
31func TestDeployReachesExactlyItsDoors(t *testing.T) {
32 s := newConsoleFixture(t).srv
33 var got []string
34 for pattern, set := range s.cliRoles {
35 if set.Permits(svcrole.Deploy) {
36 got = append(got, pattern)
37 }
38 }
39 sort.Strings(got)
40 want := append([]string(nil), deployDoors...)
41 sort.Strings(want)
42 if !reflect.DeepEqual(got, want) {
43 t.Fatalf("deploy reaches:\n got %q\nwant %q", got, want)
44 }
45}
46
47// Review Focus 2: the app binding holds for deploy like any service.
48func TestDeployIsBoundToItsApp(t *testing.T) {
49 fx := newConsoleFixture(t)
50 for _, app := range []string{"hello", "other"} {
51 if _, err := fx.st.CreateAppIn(OpsAccountID, app, "paul@keymail.dev", time.Now()); err != nil {
52 t.Fatal(err)
53 }
54 }
55 tok, err := fx.st.NewServicePrincipalScoped(OpsAccountID, "ci", "hello", svcrole.Deploy, []string{"edge"}, nil, "paul@keymail.dev", time.Now())
56 if err != nil {
57 t.Fatal(err)
58 }
59 // Sibling app: deploy reaches "other" (exists) but its token is bound to "hello"
60 statusA, bodyA := postRaw(t, fx.ts.URL+"/api/cli/apps/bab/other/promote",
61 map[string]string{"version": "v1", "channel": "edge"}, tok)
62 if statusA != http.StatusNotFound {
63 t.Fatalf("deploy on a sibling app = %d, want 404", statusA)
64 }
65 // Nonexistent app: deploy reaches "nosuchapp" (does not exist) on the same account
66 statusB, bodyB := postRaw(t, fx.ts.URL+"/api/cli/apps/bab/nosuchapp/promote",
67 map[string]string{"version": "v1", "channel": "edge"}, tok)
68 if statusB != http.StatusNotFound {
69 t.Fatalf("deploy on a nonexistent app = %d, want 404", statusB)
70 }
71 // Both refusals must be byte-identical to avoid leaking whether "other" exists
72 if bodyA != bodyB {
73 t.Fatalf("app-binding 404 is not identical to nonexistent-app 404:\n(sibling) %q\n(nonexistent) %q", bodyA, bodyB)
74 }
75 // And a door outside §6 is the role gate's 403, not a 404.
76 status, out := postJSON(t, fx.ts.URL+"/api/cli/apps/bab/hello/delete", map[string]string{}, tok)
77 if status != http.StatusForbidden {
78 t.Fatalf("deploy on trash = %d %v, want 403", status, out)
79 }
80}
81