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 "crypto/ed25519"
6 "encoding/json"
7 "errors"
8 "net/http"
9 "net/http/httptest"
10 "os"
11 "testing"
12 "time"
13
14 "github.com/carlosframework/platform/internal/hostops"
15 "github.com/carlosframework/platform/internal/release"
16)
17
18type aliasWriteSpy struct {
19 release.Store
20 writes int
21}
22
23func (s *aliasWriteSpy) Put(context.Context, string, []byte, string) (string, error) {
24 s.writes++
25 return "changed", nil
26}
27func (s *aliasWriteSpy) Delete(context.Context, string) error { s.writes++; return nil }
28func TestAliasOwnershipCannotRebaseOrBareDelete(t *testing.T) {
29 base := &aliasWriteSpy{}
30 guarded := claimAliasStore{data: base, key: "domains/alias.example.com.json", etag: "original"}
31 for _, etag := range []string{"", "successor"} {
32 if _, err := guarded.Put(context.Background(), guarded.key, []byte(`{}`), etag); !errors.Is(err, hostops.ErrPending) {
33 t.Fatalf("rebase %q: %v", etag, err)
34 }
35 }
36 if _, err := guarded.Put(context.Background(), "domains/other.example.com.json", []byte(`{}`), "original"); !errors.Is(err, hostops.ErrPending) {
37 t.Fatal(err)
38 }
39 if err := guarded.Delete(context.Background(), guarded.key); !errors.Is(err, hostops.ErrContract) {
40 t.Fatal(err)
41 }
42 if base.writes != 0 {
43 t.Fatalf("unauthorized writes: %d", base.writes)
44 }
45}
46
47func (s *aliasWriteSpy) Get(context.Context, string) ([]byte, string, error) {
48 return nil, "", os.ErrNotExist
49}
50func TestAliasMarkerPutCannotStartAfterPurgeDrain(t *testing.T) {
51 ctx := context.Background()
52 base := &aliasWriteSpy{}
53 raw := release.NewDirStore(t.TempDir())
54 pub, _, err := ed25519.GenerateKey(nil)
55 if err != nil {
56 t.Fatal(err)
57 }
58 now := time.Now()
59 w, err := hostops.NewControlWriter(raw, pub, func() time.Time { return now })
60 if err != nil {
61 t.Fatal(err)
62 }
63 open := hostops.AppAdmission{V: 1, AppID: "app-id", Revision: 1, Epoch: 1, State: "open", Registrations: map[string]hostops.Registration{}, Effects: map[string]hostops.Effect{}}
64 putAdmission := func(a hostops.AppAdmission) {
65 body, _ := json.Marshal(a)
66 _, tag, _ := raw.Get(ctx, "apps/bab/site/admission.json")
67 if _, err := raw.Put(ctx, "apps/bab/site/admission.json", body, tag); err != nil {
68 t.Fatal(err)
69 }
70 }
71 putAdmission(open)
72 owner := hostops.RegistrationOwner{Console: "console", Enrollment: "enrolled", Controller: "controller"}
73 h, err := w.RegisterStart(ctx, "bab", "site", "app-id", "old-registration", hostops.Registration{Kind: "create", Host: "alias.bab.example.com", Claim: hostops.SavedClaim{Absent: true}, Owner: owner, AppID: "app-id", Epoch: 1, CreatedAt: now}, now)
74 if err != nil {
75 t.Fatal(err)
76 }
77 // The purge drained the registration and closed the gate.
78 drained := open
79 drained.State, drained.Revision = "closed", 2
80 drained.Op = &hostops.AppOperation{ID: "purge", Kind: hostops.OpPurging, AppID: "app-id"}
81 putAdmission(drained)
82 guarded := claimAliasStore{data: base, key: "domains/alias.example.com.json", etag: "original", account: "bab", app: "site", acquisition: "acq", incarnation: "inc", effects: claimStoreEffects{OperationID: "old-registration", Runner: h.Runner(time.Now)}}
83 _, err = guarded.Put(ctx, guarded.key, []byte(`{"account":"bab","app":"site"}`), "original")
84 if !errors.Is(err, hostops.ErrPending) {
85 t.Fatalf("drained registration issued effect: %v", err)
86 }
87 if base.writes != 0 {
88 t.Fatalf("writes after drain: %d", base.writes)
89 }
90}
91
92func TestFlaggedDomainCapabilitiesRefuseBeforeBucketRead(t *testing.T) {
93 s := &Server{cfg: Config{HostClaim: true}}
94 w := httptest.NewRecorder()
95 yes := true
96 if s.setDomainCapabilities(w, httptest.NewRequest("POST", "/", nil), context.Background(), nil, "site", Principal{}, "alias.example.com", &yes, nil) {
97 t.Fatal("capability mutation admitted")
98 }
99 if w.Code != http.StatusConflict {
100 t.Fatalf("status=%d", w.Code)
101 }
102}
103