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 "bytes"
5 "context"
6 "crypto/ed25519"
7 "net/http"
8 "net/http/httptest"
9 "reflect"
10 "strings"
11 "testing"
12 "time"
13
14 "github.com/carlosframework/platform/internal/hostclaim"
15 "github.com/carlosframework/platform/internal/hostfloor"
16 "github.com/carlosframework/platform/internal/hostwrite"
17 "github.com/carlosframework/platform/internal/release"
18 "github.com/carlosframework/platform/internal/svcrole"
19)
20
21func resetRequest(t *testing.T, s *Server, url, token, body string) (int, string) {
22 t.Helper()
23 req := httptest.NewRequest(http.MethodPost, url, bytes.NewBufferString(body))
24 if token != "" {
25 req.Header.Set("Authorization", "Bearer "+token)
26 }
27 req.Header.Set("Content-Type", "application/json")
28 rec := httptest.NewRecorder()
29 s.mux.ServeHTTP(rec, req)
30 return rec.Code, rec.Body.String()
31}
32func TestHostWakeResetMountedOperatorGates(t *testing.T) {
33 st := openGatedStore(t)
34 now := time.Now()
35 user, device, err := st.NewCLIAuth("reset", "127.0.0.1", now)
36 if err != nil {
37 t.Fatal(err)
38 }
39 if err = st.ApproveCLIAuth(user, "paul@keymail.dev", now); err != nil {
40 t.Fatal(err)
41 }
42 _, token, _, err := st.PollCLIAuth(device, now)
43 if err != nil {
44 t.Fatal(err)
45 }
46 _, key, err := ed25519.GenerateKey(nil)
47 if err != nil {
48 t.Fatal(err)
49 }
50 store := release.NewDirStore(t.TempDir())
51 if err := hostfloor.Publish(t.Context(), store, release.RootSigner(key), "bucket", hostfloor.Floor{Min: 1, MinRelease: "v1.0.0"}); err != nil {
52 t.Fatal(err)
53 }
54 s, err := NewServer(Config{Origin: "https://console.example", Keymail: "https://keymail.example", HostClaim: true, Key: key, Bucket: "bucket", Releases: store}, st)
55 if err != nil {
56 t.Fatal(err)
57 }
58 url := "/api/cli/ops/hosts/shop.example.test/resolve"
59 calls := 0
60 s.cfg.WakeRetryReset = &WakeRetryResetDoor{Claims: release.NewDirStore(t.TempDir()), Authority: func(context.Context) error { calls++; return hostwrite.ErrUnavailable }, StopAttempt: func(context.Context, hostclaim.Observed, hostclaim.WakeRetryAttempt) error { return nil }, NewID: func() string { return "new" }}
61 if status, _ := resetRequest(t, s, url, "", "{}"); status != 401 {
62 t.Fatal(status)
63 }
64 ghostStatus, ghostBody := resetRequest(t, s, "/not-found", token, "{}")
65 status, body := resetRequest(t, s, url, token, "{}")
66 if status != ghostStatus || body != ghostBody || calls != 0 {
67 t.Fatalf("nonoperator %d %q calls=%d", status, body, calls)
68 }
69 if err := st.SetOperator("paul@keymail.dev", true); err != nil {
70 t.Fatal(err)
71 }
72 service := serviceToken(t, st, OpsAccountID, "reset-service", "", svcrole.Publish)
73 if status, _ := resetRequest(t, s, url, service, "{}"); status == 200 || calls != 0 {
74 t.Fatalf("service status=%d calls=%d", status, calls)
75 }
76 if status, _ := resetRequest(t, s, url, token, `{"action":"reset-wake-retry","incarnation":"i","episode":"e","request_id":"r"}`); status != 409 || calls != 1 {
77 t.Fatalf("operator status=%d calls=%d", status, calls)
78 }
79 for _, bad := range []string{
80 `{"action":"reset-wake-retry","unknown":true}`,
81 `{"action":"reset-wake-retry"} {}`,
82 `{"action":"reset-wake-retry","request_id":"` + strings.Repeat("x", 16<<10) + `"}`,
83 } {
84 if status, _ := resetRequest(t, s, url, token, bad); status != 400 || calls != 1 {
85 t.Fatalf("malformed reset status=%d calls=%d", status, calls)
86 }
87 }
88 // Other resolution actions still use main's dispatcher and authority.
89 for _, action := range []string{"declare-lost", "readmit"} {
90 if status, _ := resetRequest(t, s, url, token, `{"action":"`+action+`"}`); status != 409 || calls != 1 {
91 t.Fatalf("%s reached wake reset: status=%d calls=%d", action, status, calls)
92 }
93 }
94 savedStore := s.cfg.Releases
95 s.cfg.Releases = release.NewDirStore(t.TempDir())
96 if status, _ := resetRequest(t, s, url, token, `{"action":"reset-wake-retry"}`); status != 503 || calls != 1 {
97 t.Fatalf("missing floor reached reset: status=%d calls=%d", status, calls)
98 }
99 s.cfg.Releases = savedStore
100 s.cfg.HostClaim = false
101 if status, _ := resetRequest(t, s, url, token, "{}"); status != 404 || calls != 1 {
102 t.Fatalf("disabled status=%d calls=%d", status, calls)
103 }
104}
105func TestHostWakeResetExactAttemptAndAudit(t *testing.T) {
106 ctx := context.Background()
107 st := release.NewDirStore(t.TempDir())
108 now := time.Date(2026, 10, 6, 12, 0, 0, 0, time.UTC)
109 host := "shop.bab.oncarlos.com"
110 in := hostclaim.NewHolder{Family: "instance", Key: "apps/bab/jam/instances/" + host + ".json", Account: "bab", App: "jam", Host: host, Region: "ie", RecordRegion: "ie", CreatedAt: now}
111 absent, _ := hostclaim.Read(ctx, st, host)
112 o, err := hostclaim.Update(ctx, st, absent, hostclaim.BeginCreate(in, []byte(`{"schema":1,"host":"shop.bab.oncarlos.com","account":"bab","app":"jam","region":"ie","created_at":"2026-10-06T12:00:00Z"}`), "create", "console", now))
113 if err != nil {
114 t.Fatal(err)
115 }
116 o, err = hostclaim.Update(ctx, st, o, hostclaim.CompleteCreate("create", "box"))
117 if err != nil {
118 t.Fatal(err)
119 }
120 attempt := hostclaim.WakeRetryAttempt{ID: "a", Box: "box", Enrollment: "enroll", BootID: "boot", ControllerID: "controller", InvocationID: "inv", LaunchInputs: "inputs"}
121 o, err = hostclaim.Update(ctx, st, o, hostclaim.ReserveWakeRetryAttempt(hostclaim.WakeRetryReservation{HolderIncarnation: o.Claim.Holder.Incarnation, EpisodeID: "episode", Attempt: attempt, Now: now}))
122 if err != nil {
123 t.Fatal(err)
124 }
125 request := wakeResetRequest{Action: "reset-wake-retry", Incarnation: o.Claim.Holder.Incarnation, Episode: "episode", RequestID: "request"}
126 door := WakeRetryResetDoor{Claims: st, Authority: func(context.Context) error { return nil }, StopAttempt: func(context.Context, hostclaim.Observed, hostclaim.WakeRetryAttempt) error {
127 return hostwrite.ErrUnavailable
128 }, NewID: func() string { return "replacement" }}
129 if err = door.reset(ctx, host, "operator@example.test", request); err == nil {
130 t.Fatal("unsettled attempt reset")
131 }
132 fresh, _ := hostclaim.Read(ctx, st, host)
133 if fresh.ETag != o.ETag {
134 t.Fatal("failure changed retry")
135 }
136 door.StopAttempt = func(_ context.Context, _ hostclaim.Observed, a hostclaim.WakeRetryAttempt) error {
137 if a != attempt {
138 t.Fatal("wrong attempt stopped")
139 }
140 return nil
141 }
142 if err = door.reset(ctx, host, "operator@example.test", request); err != nil {
143 t.Fatal(err)
144 }
145 fresh, _ = hostclaim.Read(ctx, st, host)
146 retry := fresh.Claim.Holder.WakeRetry
147 if retry.EpisodeID != "replacement" || retry.AttemptsReserved != 0 || retry.ResetRequest != `{"Actor":"operator@example.test","RequestID":"request"}` {
148 t.Fatalf("reset=%+v", retry)
149 }
150 if fresh.Claim.Holder.Incarnation != o.Claim.Holder.Incarnation || fresh.Claim.Holder.Stamp != o.Claim.Holder.Stamp || fresh.Claim.Holder.Session != o.Claim.Holder.Session || !reflect.DeepEqual(fresh.Claim.Op, o.Claim.Op) {
151 t.Fatal("reset changed execution authority")
152 }
153 if err = door.reset(ctx, host, "operator@example.test", request); err == nil {
154 t.Fatal("stale episode reset successor")
155 }
156}
157