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 "context"
5 "crypto/ed25519"
6 "encoding/base64"
7 "encoding/json"
8 "errors"
9 "fmt"
10 "strings"
11 "testing"
12 "time"
13)
14
15func TestResignSignsTheDigestsTheOperatorSaw(t *testing.T) {
16 s := NewDirStore(t.TempDir())
17 ctx := context.Background()
18 priv, pub := testKeys(t)
19 shipRelease(t, s, "bab", "km", "v1", adoptPlatform, []byte("one"))
20 shipRelease(t, s, "bab", "km", "v2", adoptPlatform, []byte("two"))
21 for _, v := range []string{"v1", "v2"} {
22 if err := Promote(ctx, s, priv, "bab", "km", "stable", v); err != nil {
23 t.Fatal(err)
24 }
25 }
26 markerOn(t, s, priv, "bab") // every writer upgraded; the old pointer still has no digests
27 sg := RootSigner(priv)
28 plan, err := sg.PlanResign(ctx, s, "bab", "km", "stable")
29 if err != nil {
30 t.Fatal(err)
31 }
32 if plan.Digest != manifestDigestOf(t, s, "bab", "km", "v2") || plan.HistoryDigests[0] != manifestDigestOf(t, s, "bab", "km", "v1") ||
33 !plan.Computed[0] || !plan.Computed[1] {
34 t.Fatalf("plan = %+v", plan)
35 }
36 if p := readPtr(t, s, pub, "stable"); p.Digest != "" {
37 t.Fatal("PlanResign wrote something")
38 }
39 if err := sg.Resign(ctx, s, plan, "ops@example.com"); err != nil {
40 t.Fatal(err)
41 }
42 p := readPtr(t, s, pub, "stable")
43 if p.Version != "v2" || p.Digest != plan.Digest || p.HistoryDigests[0] != plan.HistoryDigests[0] {
44 t.Fatalf("resigned pointer = %+v", p)
45 }
46 // Once resigned, the rollback the spec refused is allowed.
47 if err := Rollback(ctx, s, priv, "bab", "km", "stable"); err != nil {
48 t.Fatalf("rollback after resign: %v", err)
49 }
50}
51
52func TestResignCopiesSignedDigestsAndLeavesGoneBuildsEmpty(t *testing.T) {
53 s := NewDirStore(t.TempDir())
54 ctx := context.Background()
55 priv, _ := testKeys(t)
56 shipRelease(t, s, "bab", "km", "v1", adoptPlatform, []byte("one"))
57 shipRelease(t, s, "bab", "km", "v2", adoptPlatform, []byte("two"))
58 shipRelease(t, s, "bab", "km", "v3", adoptPlatform, []byte("three"))
59 if err := Promote(ctx, s, priv, "bab", "km", "stable", "v1"); err != nil {
60 t.Fatal(err)
61 }
62 if err := Promote(ctx, s, priv, "bab", "km", "stable", "v2"); err != nil {
63 t.Fatal(err)
64 }
65 markerOn(t, s, priv, "bab")
66 if err := Promote(ctx, s, priv, "bab", "km", "stable", "v3"); err != nil {
67 t.Fatal(err)
68 }
69 if err := DeleteVersion(ctx, s, "bab", "km", "v1"); err != nil {
70 t.Fatal(err)
71 }
72 plan, err := RootSigner(priv).PlanResign(ctx, s, "bab", "km", "stable")
73 if err != nil {
74 t.Fatal(err)
75 }
76 // head v3 signed, v2 inherited "" (computed now), v1 gone.
77 if plan.Computed[0] || !plan.Computed[1] || plan.HistoryDigests[1] != "" || plan.Computed[2] {
78 t.Fatalf("plan = %+v", plan)
79 }
80}
81
82func TestResignRefusesAChannelThatMoved(t *testing.T) {
83 s := NewDirStore(t.TempDir())
84 ctx := context.Background()
85 priv, _ := testKeys(t)
86 shipRelease(t, s, "bab", "km", "v1", adoptPlatform, []byte("one"))
87 shipRelease(t, s, "bab", "km", "v2", adoptPlatform, []byte("two"))
88 if err := Promote(ctx, s, priv, "bab", "km", "stable", "v1"); err != nil {
89 t.Fatal(err)
90 }
91 markerOn(t, s, priv, "bab")
92 sg := RootSigner(priv)
93 plan, err := sg.PlanResign(ctx, s, "bab", "km", "stable")
94 if err != nil {
95 t.Fatal(err)
96 }
97 if err := Promote(ctx, s, priv, "bab", "km", "stable", "v2"); err != nil {
98 t.Fatal(err)
99 }
100 if err := sg.Resign(ctx, s, plan, "ops"); !errors.Is(err, ErrResignChanged) {
101 t.Fatalf("resign over a moved channel = %v, want ErrResignChanged", err)
102 }
103}
104
105func TestResignRefusesAHeadWithNoManifest(t *testing.T) {
106 s := NewDirStore(t.TempDir())
107 ctx := context.Background()
108 priv, _ := testKeys(t)
109 shipRelease(t, s, "bab", "km", "v1", adoptPlatform, []byte("one"))
110 if err := Promote(ctx, s, priv, "bab", "km", "stable", "v1"); err != nil {
111 t.Fatal(err)
112 }
113 if err := DeleteVersion(ctx, s, "bab", "km", "v1"); err != nil {
114 t.Fatal(err)
115 }
116 markerOn(t, s, priv, "bab")
117 if _, err := RootSigner(priv).PlanResign(ctx, s, "bab", "km", "stable"); err == nil || err.Error() != fmt.Sprintf(TextResignUnreadable, "v1") {
118 t.Fatalf("a head with no manifest was planned: %v", err)
119 }
120}
121
122// Astra I3 #4: resign arms every box's ratchet for the channel, so it needs
123// the verified marker (every writer upgraded), at plan time and at signing.
124func TestResignRequiresTheVerifiedMarker(t *testing.T) {
125 s := NewDirStore(t.TempDir())
126 ctx := context.Background()
127 priv, pub := testKeys(t)
128 shipRelease(t, s, "bab", "km", "v1", adoptPlatform, []byte("one"))
129 if err := Promote(ctx, s, priv, "bab", "km", "stable", "v1"); err != nil {
130 t.Fatal(err)
131 }
132 sg := RootSigner(priv)
133 if _, err := sg.PlanResign(ctx, s, "bab", "km", "stable"); err == nil || err.Error() != fmt.Sprintf(TextResignNoMarker, "bab", "bab") {
134 t.Fatalf("PlanResign with no marker = %v, want the no-marker refusal", err)
135 }
136 markerOn(t, s, priv, "bab")
137 plan, err := sg.PlanResign(ctx, s, "bab", "km", "stable")
138 if err != nil {
139 t.Fatal(err)
140 }
141 if err := RemoveDigestMarker(ctx, s, "bab"); err != nil { // turned off between plan and confirmation
142 t.Fatal(err)
143 }
144 if err := sg.Resign(ctx, s, plan, "ops"); err == nil || err.Error() != fmt.Sprintf(TextResignNoMarker, "bab", "bab") {
145 t.Fatalf("Resign with the marker gone = %v, want the no-marker refusal", err)
146 }
147 foreign, _ := testKeys(t)
148 markerOn(t, s, foreign, "bab") // present, but not root-signed
149 if err := sg.Resign(ctx, s, plan, "ops"); err == nil || !strings.Contains(err.Error(), "marker") {
150 t.Fatalf("Resign with an unverifiable marker = %v", err)
151 }
152 if p := readPtr(t, s, pub, "stable"); p.Digest != "" {
153 t.Fatal("a refused resign wrote digests")
154 }
155}
156
157// unbindPointer rewrites a channel's pointer as one signed before the account
158// binding existed: same fields, no account, root-signed.
159func unbindPointer(t *testing.T, s Store, priv ed25519.PrivateKey, acct, app, channel string) {
160 t.Helper()
161 ctx := context.Background()
162 key := ChannelKey(acct, app, channel)
163 body, etag, err := GetQualified(ctx, s, key)
164 if err != nil {
165 t.Fatal(err)
166 }
167 var w signedWrapper
168 if err := json.Unmarshal(body, &w); err != nil {
169 t.Fatal(err)
170 }
171 payload, err := base64.StdEncoding.DecodeString(w.Payload)
172 if err != nil {
173 t.Fatal(err)
174 }
175 var p ChannelPointer
176 if err := json.Unmarshal(payload, &p); err != nil {
177 t.Fatal(err)
178 }
179 p.Account = ""
180 payload, err = json.MarshalIndent(&p, "", " ")
181 if err != nil {
182 t.Fatal(err)
183 }
184 b64 := base64.StdEncoding.EncodeToString(payload)
185 wire, err := json.MarshalIndent(signedWrapper{Payload: b64, Sig: base64.StdEncoding.EncodeToString(ed25519.Sign(priv, []byte(b64)))}, "", " ")
186 if err != nil {
187 t.Fatal(err)
188 }
189 if _, err := s.Put(ctx, key, wire, etag); err != nil {
190 t.Fatal(err)
191 }
192}
193
194// A channel not promoted since the account binding has no account in its
195// pointer. Resign targets exactly those, and must bind the account.
196func TestResignBindsTheAccountOnAPreBindingPointer(t *testing.T) {
197 s := NewDirStore(t.TempDir())
198 ctx := context.Background()
199 priv, pub := testKeys(t)
200 shipRelease(t, s, "bab", "km", "v1", adoptPlatform, []byte("one"))
201 shipRelease(t, s, "bab", "km", "v2", adoptPlatform, []byte("two"))
202 for _, v := range []string{"v1", "v2"} {
203 if err := Promote(ctx, s, priv, "bab", "km", "stable", v); err != nil {
204 t.Fatal(err)
205 }
206 }
207 unbindPointer(t, s, priv, "bab", "km", "stable")
208 if p := readPtr(t, s, pub, "stable"); p.Account != "" {
209 t.Fatalf("test setup: pointer still bound to %q", p.Account)
210 }
211 markerOn(t, s, priv, "bab")
212 sg := RootSigner(priv)
213 plan, err := sg.PlanResign(ctx, s, "bab", "km", "stable")
214 if err != nil {
215 t.Fatal(err)
216 }
217 if err := sg.Resign(ctx, s, plan, "ops"); err != nil {
218 t.Fatalf("resign of a pre-binding pointer: %v", err)
219 }
220 p := readPtr(t, s, pub, "stable")
221 if p.Account != "bab" || p.Digest != plan.Digest || p.HistoryDigests[0] != plan.HistoryDigests[0] {
222 t.Fatalf("resigned pointer = %+v", p)
223 }
224}
225
226func TestResignRefusesAnInvalidPlan(t *testing.T) {
227 priv, _ := testKeys(t)
228 if err := RootSigner(priv).claimRawResign(context.Background(), NewDirStore(t.TempDir()), &ResignPlan{Account: "bab", App: "km", Channel: "../x"}, "ops", nil); err == nil {
229 t.Fatal("a plan with an invalid channel was signed")
230 }
231}
232
233func TestResignRefusesANilPlan(t *testing.T) {
234 priv, _ := testKeys(t)
235 if err := RootSigner(priv).Resign(context.Background(), NewDirStore(t.TempDir()), nil, "ops"); err == nil {
236 t.Fatal("a nil plan was signed")
237 }
238}
239
240func TestDigestStateOf(t *testing.T) {
241 at := time.Date(2026, 10, 7, 12, 0, 0, 0, time.UTC)
242 m := &DigestMarker{Schema: 1, Account: "bab", At: at}
243 legacyBefore := &ChannelPointer{Channel: "a", Version: "v1", PromotedAt: at.Add(-time.Hour), History: []string{"v0"}}
244 legacyAfter := &ChannelPointer{Channel: "b", Version: "v1", PromotedAt: at.Add(time.Hour)}
245 signed := &ChannelPointer{Channel: "c", Version: "v2", Digest: dA, PromotedAt: at.Add(time.Hour), History: []string{"v1"}, HistoryDigests: []string{""}}
246 if st := DigestStateOf(legacyBefore, m); st.HeadDigest || st.Straggler || st.HistoryMissing != 1 {
247 t.Fatalf("before the marker: %+v", st)
248 }
249 if st := DigestStateOf(legacyAfter, m); !st.Straggler {
250 t.Fatalf("written after the marker without digests: %+v", st)
251 }
252 if st := DigestStateOf(legacyAfter, nil); st.Straggler {
253 t.Fatal("no marker, no stragglers")
254 }
255 if st := DigestStateOf(signed, m); !st.HeadDigest || st.Straggler || st.HistoryMissing != 1 {
256 t.Fatalf("signed: %+v", st)
257 }
258}
259
260func TestDigestReportListsEveryChannel(t *testing.T) {
261 s := NewDirStore(t.TempDir())
262 ctx := context.Background()
263 priv, pub := testKeys(t)
264 shipRelease(t, s, "bab", "km", "v1", adoptPlatform, []byte("one"))
265 if err := Promote(ctx, s, priv, "bab", "km", "beta", "v1"); err != nil {
266 t.Fatal(err)
267 }
268 markerOn(t, s, priv, "bab")
269 if err := Promote(ctx, s, priv, "bab", "km", "canary/x", "v1"); err != nil {
270 t.Fatal(err)
271 }
272 rows, marker, err := DigestReport(ctx, s, pub, "bab", "km")
273 if err != nil || marker == nil || len(rows) != 2 {
274 t.Fatalf("report = %+v, %+v, %v", rows, marker, err)
275 }
276 got := map[string]bool{}
277 for _, r := range rows {
278 got[r.Channel] = r.HeadDigest
279 }
280 if got["beta"] || !got["canary/x"] {
281 t.Fatalf("report = %+v", rows)
282 }
283}
284
285// Astra r1 #2: ResignAuthorized asks the caller's authority of the pipeline
286// read inside the mutation, after the pointer; a refusal is an
287// AuthorizationError and the pointer is untouched. With no hook (Resign) the
288// same plan signs.
289func TestResignAuthorizedAsksTheHookAndWritesNothingOnRefusal(t *testing.T) {
290 s := NewDirStore(t.TempDir())
291 ctx := context.Background()
292 priv, pub := testKeys(t)
293 shipRelease(t, s, "bab", "km", "v1", adoptPlatform, []byte("one"))
294 if err := Promote(ctx, s, priv, "bab", "km", "stable", "v1"); err != nil {
295 t.Fatal(err)
296 }
297 if _, err := SetPipeline(ctx, s, priv, "bab", "km", []PipelineChannel{{Name: "stable", Rules: ChannelRules{Passkey: true}}}, "t"); err != nil {
298 t.Fatal(err)
299 }
300 markerOn(t, s, priv, "bab")
301 sg := RootSigner(priv)
302 plan, err := sg.PlanResign(ctx, s, "bab", "km", "stable")
303 if err != nil {
304 t.Fatal(err)
305 }
306 refusal := errors.New("needs a passkey")
307 var saw *Pipeline
308 err = sg.ResignAuthorized(ctx, s, plan, "ops@example.com", func(p *Pipeline) error {
309 saw = p
310 return refusal
311 })
312 var ae *AuthorizationError
313 if !errors.As(err, &ae) || !errors.Is(ae.Err, refusal) {
314 t.Fatalf("ResignAuthorized = %v, want the hook's refusal as an AuthorizationError", err)
315 }
316 if saw == nil || len(saw.Channels) != 1 || !saw.Channels[0].Rules.Passkey {
317 t.Fatalf("the hook saw pipeline %+v, want the app's", saw)
318 }
319 if p := readPtr(t, s, pub, "stable"); p.Digest != "" {
320 t.Fatalf("a refused resign wrote %+v", p)
321 }
322 if err := sg.ResignAuthorized(ctx, s, plan, "ops@example.com", func(*Pipeline) error { return nil }); err != nil {
323 t.Fatalf("an allowing hook: %v", err)
324 }
325 if p := readPtr(t, s, pub, "stable"); p.Digest != plan.Digest {
326 t.Fatalf("after an allowed resign = %+v", p)
327 }
328}
329