carlos / platform Public

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

Plain git — no account needed to clone.

Download

Download this file

1package release
2
3import (
4 "bytes"
5 "encoding/base64"
6 "encoding/json"
7 "errors"
8 "math"
9 "reflect"
10 "strings"
11 "testing"
12 "time"
13
14 "github.com/carlosframework/platform/internal/maintenanceguard"
15)
16
17func workerTestRef(b byte) maintenanceguard.Reference {
18 return maintenanceguard.Reference{ID: base64.RawURLEncoding.EncodeToString(bytes.Repeat([]byte{b}, 32)), Digest: strings.Repeat("ab", 32)}
19}
20func workerTestHead() WorkerHead {
21 return WorkerHead{Schema: 1, Kind: "maintenance-worker", Deployment: "https://console.example.com", Account: "bds", Box: "annie-welding", PhysicalIdentity: strings.Repeat("cd", 32), Generation: 1, Revision: 1, TokenHash: strings.Repeat("ef", 32), Status: "active", Placement: "eu", Candidate: workerTestRef(1), Open: []maintenanceguard.Reference{workerTestRef(2)}}
22}
23func workerTestAssignment() WorkerAssignmentState {
24 return WorkerAssignmentState{Schema: 1, Kind: "maintenance-assignment", Identity: WorkerAssignmentIdentity{Assignment: workerTestRef(2), Deployment: "https://console.example.com", Box: "annie-welding", Generation: 1, Account: "bds", App: "home", Host: "home.example.com", Operation: workerTestRef(3).ID, Request: workerTestRef(4).ID, Attempt: workerTestRef(5).ID}, Revision: 1, Expires: 2000000000}
25}
26func TestWorkerControlRoundTripAndTypeSeparation(t *testing.T) {
27 priv, pub := testKeys(t)
28 head := workerTestHead()
29 head.Generation = math.MaxInt64
30 head.Revision = math.MaxInt64
31 wire, err := SignWorkerHead(RootSigner(priv), head)
32 if err != nil {
33 t.Fatal(err)
34 }
35 got, err := VerifyWorkerHead(pub, wire)
36 if err != nil || !reflect.DeepEqual(got, head) {
37 t.Fatalf("head round trip: %v", err)
38 }
39 if _, err = VerifyWorkerAssignment(pub, wire); !errors.Is(err, ErrWorkerControl) {
40 t.Fatal("head accepted as assignment")
41 }
42 state := workerTestAssignment()
43 refs := []*maintenanceguard.Reference{&head.Candidate, &head.Open[0]}
44 state.Preflight = refs[0]
45 state.Execution = refs[1]
46 state.Disabled = true
47 wire, err = SignWorkerAssignment(RootSigner(priv), state)
48 if err != nil {
49 t.Fatal(err)
50 }
51 gotState, err := VerifyWorkerAssignment(pub, wire)
52 if err != nil || !reflect.DeepEqual(gotState, state) {
53 t.Fatalf("assignment round trip: %v", err)
54 }
55 if _, err = VerifyWorkerHead(pub, wire); !errors.Is(err, ErrWorkerControl) {
56 t.Fatal("assignment accepted as head")
57 }
58 _, otherPub := testKeys(t)
59 if _, err = VerifyWorkerAssignment(otherPub, wire); !errors.Is(err, ErrWorkerControl) {
60 t.Fatal("wrong root accepted")
61 }
62 if _, err = VerifyWorkerAssignment(nil, wire); !errors.Is(err, ErrWorkerControl) {
63 t.Fatal("missing root accepted")
64 }
65 wire[len(wire)/2] ^= 1
66 if _, err = VerifyWorkerAssignment(pub, wire); !errors.Is(err, ErrWorkerControl) {
67 t.Fatal("tampered wire accepted")
68 }
69}
70func TestWorkerControlRefusesNonRootSigner(t *testing.T) {
71 _, _, scoped := scopedFixture(t, []string{"canary"}, time.Hour)
72 for _, sg := range []Signer{{}, scoped} {
73 if _, err := SignWorkerHead(sg, workerTestHead()); !errors.Is(err, ErrWorkerControl) {
74 t.Fatal("head signed without root")
75 }
76 if _, err := SignWorkerAssignment(sg, workerTestAssignment()); !errors.Is(err, ErrWorkerControl) {
77 t.Fatal("assignment signed without root")
78 }
79 }
80}
81func TestWorkerControlRefusesSignedMalformedPayload(t *testing.T) {
82 priv, pub := testKeys(t)
83 headRaw, _ := json.Marshal(workerTestHead())
84 stateRaw, _ := json.Marshal(workerTestAssignment())
85 for name, mutate := range map[string]func(string) string{
86 "duplicate": func(s string) string { return strings.Replace(s, `"schema":1`, `"schema":1,"schema":1`, 1) },
87 "alias": func(s string) string { return strings.Replace(s, `"schema":1`, `"Schema":1`, 1) },
88 "unknown": func(s string) string { return strings.Replace(s, `"schema":1`, `"schema":1,"extension":true`, 1) },
89 "float": func(s string) string { return strings.Replace(s, `"schema":1`, `"schema":1.0`, 1) },
90 "overflow": func(s string) string { return strings.Replace(s, `"revision":1`, `"revision":9223372036854775808`, 1) },
91 "trailing": func(s string) string { return s + ` {}` },
92 "escaped-alias": func(s string) string { return strings.Replace(s, `"schema":1`, `"\u0073chema":1`, 1) },
93 "invalid-utf8": func(s string) string { return strings.Replace(s, "console", string([]byte{255}), 1) },
94 "surrogate": func(s string) string { return strings.Replace(s, "console", `\ud800`, 1) },
95 } {
96 t.Run(name, func(t *testing.T) {
97 for _, raw := range [][]byte{headRaw, stateRaw} {
98 wire, err := signRootPayload(RootSigner(priv), []byte(mutate(string(raw))))
99 if err != nil {
100 t.Fatal(err)
101 }
102 if _, err = VerifyWorkerHead(pub, wire); !errors.Is(err, ErrWorkerControl) {
103 t.Fatal("malformed head accepted")
104 }
105 if _, err = VerifyWorkerAssignment(pub, wire); !errors.Is(err, ErrWorkerControl) {
106 t.Fatal("malformed assignment accepted")
107 }
108 }
109 })
110 }
111 for _, raw := range []string{
112 strings.Replace(string(stateRaw), `"disabled":false,`, "", 1),
113 strings.TrimSuffix(string(stateRaw), "}") + `,"execution":null}`,
114 strings.Replace(string(headRaw), `"open":[`+mustWorkerJSON(t, workerTestRef(2))+`]`, `"open":null`, 1),
115 } {
116 wire, err := signRootPayload(RootSigner(priv), []byte(raw))
117 if err != nil {
118 t.Fatal(err)
119 }
120 if _, err = VerifyWorkerHead(pub, wire); !errors.Is(err, ErrWorkerControl) {
121 t.Fatal("missing/null field accepted as head")
122 }
123 if _, err = VerifyWorkerAssignment(pub, wire); !errors.Is(err, ErrWorkerControl) {
124 t.Fatal("missing/null field accepted as assignment")
125 }
126 }
127}
128func mustWorkerJSON(t *testing.T, v any) string {
129 t.Helper()
130 raw, err := json.Marshal(v)
131 if err != nil {
132 t.Fatal(err)
133 }
134 return string(raw)
135}
136func TestWorkerControlRefusesInvalidHeadScope(t *testing.T) {
137 priv, pub := testKeys(t)
138 for name, change := range map[string]func(*WorkerHead){
139 "http": func(h *WorkerHead) { h.Deployment = "http://console.example.com" },
140 "path": func(h *WorkerHead) { h.Deployment += "/" },
141 "user": func(h *WorkerHead) { h.Deployment = "https://owner@console.example.com" },
142 "box-path": func(h *WorkerHead) { h.Box = "../other" },
143 "zero-generation": func(h *WorkerHead) { h.Generation = 0 },
144 "zero-revision": func(h *WorkerHead) { h.Revision = 0 },
145 "token": func(h *WorkerHead) { h.TokenHash = "bad" },
146 "physical-identity": func(h *WorkerHead) { h.PhysicalIdentity = "bad" },
147 "unknown-state": func(h *WorkerHead) { h.Status = "enabled" },
148 "duplicate-assignment": func(h *WorkerHead) { h.Open = append(h.Open, h.Open[0]) },
149 "overflow-open": func(h *WorkerHead) {
150 for i := byte(3); i < 11; i++ {
151 h.Open = append(h.Open, workerTestRef(i))
152 }
153 },
154 "detached-open": func(h *WorkerHead) { h.Status = "detached" },
155 "null-open": func(h *WorkerHead) { h.Open = nil },
156 } {
157 t.Run(name, func(t *testing.T) {
158 h := workerTestHead()
159 change(&h)
160 if _, err := SignWorkerHead(RootSigner(priv), h); !errors.Is(err, ErrWorkerControl) {
161 t.Fatal("invalid head signed")
162 }
163 wire, err := signRootPayload(RootSigner(priv), []byte(mustWorkerJSON(t, h)))
164 if err != nil {
165 t.Fatal(err)
166 }
167 if _, err = VerifyWorkerHead(pub, wire); !errors.Is(err, ErrWorkerControl) {
168 t.Fatal("invalid signed head accepted")
169 }
170 })
171 }
172}
173func TestWorkerControlRejectsWrapperAmbiguityAndOversize(t *testing.T) {
174 priv, pub := testKeys(t)
175 wire, err := SignWorkerHead(RootSigner(priv), workerTestHead())
176 if err != nil {
177 t.Fatal(err)
178 }
179 var compact bytes.Buffer
180 if err = json.Compact(&compact, wire); err != nil {
181 t.Fatal(err)
182 }
183 s := compact.String()
184 for _, raw := range []string{
185 strings.Replace(s, `"payload":`, `"Payload":`, 1),
186 strings.TrimSuffix(s, "}") + `,"grant":null}`,
187 strings.TrimSuffix(s, "}") + `,"extra":0}`,
188 s + strings.Repeat(" ", MaxWorkerControlBytes),
189 `null`,
190 } {
191 if _, err := VerifyWorkerHead(pub, []byte(raw)); !errors.Is(err, ErrWorkerControl) {
192 t.Fatal("malformed wrapper accepted")
193 }
194 }
195 big, err := signRootPayload(RootSigner(priv), bytes.Repeat([]byte(" "), MaxWorkerControlBytes))
196 if err != nil {
197 t.Fatal(err)
198 }
199 if _, err = VerifyWorkerHead(pub, big); !errors.Is(err, ErrWorkerControl) {
200 t.Fatal("oversize payload accepted")
201 }
202}
203
204func TestWorkerControlRefusesInvalidAssignmentScope(t *testing.T) {
205 priv, pub := testKeys(t)
206 for name, change := range map[string]func(*WorkerAssignmentState){
207 "kind": func(s *WorkerAssignmentState) { s.Kind = "maintenance-worker" },
208 "schema": func(s *WorkerAssignmentState) { s.Schema = 2 },
209 "assignment-digest": func(s *WorkerAssignmentState) { s.Identity.Assignment.Digest = "bad" },
210 "deployment": func(s *WorkerAssignmentState) { s.Identity.Deployment = "https://console.example.com/#fragment" },
211 "box": func(s *WorkerAssignmentState) { s.Identity.Box = "../other" },
212 "generation": func(s *WorkerAssignmentState) { s.Identity.Generation = 0 },
213 "account": func(s *WorkerAssignmentState) { s.Identity.Account = "../bds" },
214 "app": func(s *WorkerAssignmentState) { s.Identity.App = "../home" },
215 "host": func(s *WorkerAssignmentState) { s.Identity.Host = "https://home.example.com" },
216 "operation": func(s *WorkerAssignmentState) { s.Identity.Operation = "bad" },
217 "request": func(s *WorkerAssignmentState) { s.Identity.Request = "bad" },
218 "attempt": func(s *WorkerAssignmentState) { s.Identity.Attempt = "bad" },
219 "revision": func(s *WorkerAssignmentState) { s.Revision = 0 },
220 "expiry": func(s *WorkerAssignmentState) { s.Expires = 0 },
221 "preflight": func(s *WorkerAssignmentState) { s.Preflight = &maintenanceguard.Reference{} },
222 "compatibility": func(s *WorkerAssignmentState) { s.Compatibility = &maintenanceguard.Reference{} },
223 "execution": func(s *WorkerAssignmentState) { s.Execution = &maintenanceguard.Reference{} },
224 "resume": func(s *WorkerAssignmentState) { s.Resume = &maintenanceguard.Reference{} },
225 } {
226 t.Run(name, func(t *testing.T) {
227 state := workerTestAssignment()
228 change(&state)
229 if _, err := SignWorkerAssignment(RootSigner(priv), state); !errors.Is(err, ErrWorkerControl) {
230 t.Fatal("invalid assignment signed")
231 }
232 wire, err := signRootPayload(RootSigner(priv), []byte(mustWorkerJSON(t, state)))
233 if err != nil {
234 t.Fatal(err)
235 }
236 if _, err = VerifyWorkerAssignment(pub, wire); !errors.Is(err, ErrWorkerControl) {
237 t.Fatal("invalid signed assignment accepted")
238 }
239 })
240 }
241}
242