carlos / platform Public

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

Plain git — no account needed to clone.

Download

Download this file

1package hostactors
2
3import (
4 "crypto/ed25519"
5 "reflect"
6 "slices"
7 "strings"
8 "testing"
9 "time"
10)
11
12func bindingRoster() Roster {
13 key := ed25519.NewKeyFromSeed(make([]byte, ed25519.SeedSize)).Public().(ed25519.PublicKey)
14 row := Box{EnrolledAt: time.Date(2026, 10, 1, 0, 0, 0, 0, time.UTC), CensusPublicKey: key, Enrollment: strings.Repeat("a", 32), Namespace: "platform", BoxID: "box", Label: "label", Region: "ie", Pool: "default", Cloud: Cloud{Provider: "aws", Account: "111122223333", Region: "eu-west-1", InstanceID: "i-0abc"}, EvidenceSHA256: strings.Repeat("c", 64), State: "active", QuarantineRevision: 2, LossIDs: []string{"loss_1"}, Group: "group", Role: ""}
15 sibling := row
16 sibling.BoxID, sibling.Enrollment, sibling.Cloud.InstanceID = "sibling", strings.Repeat("b", 32), "i-0def"
17 return Roster{
18 HomeRegion: "ie", RequestLimitNS: 30_000_000_000, Publication: "published", FloorSHA256: strings.Repeat("d", 64),
19 EnrollmentAttempts: map[string]EnrollmentAttempt{}, Regions: map[string]Region{"ie": {Namespaces: []string{"platform"}, Pools: []string{"default"}}},
20 V: 1, DeploymentBucket: "deployment", Revision: 7,
21 Boxes: map[string]Box{"box": row, "sibling": sibling},
22 Consoles: map[string]Console{}, Holds: map[string]Reservation{}, Activations: map[string]Reservation{},
23 }
24}
25
26// The v1 tuple is frozen: the golden digest pins its order and encoding, every
27// bound fact moves it, and every excluded fact leaves it alone. The field
28// lists below must name every Roster and Box field, so a field added later
29// fails here until someone decides which side it is on (and, if bound, writes
30// a v2 encoder).
31func TestBoxBindingTuple(t *testing.T) {
32 // The encoded tuple and its sha256 (checked by hand with sha256sum).
33 const tuple = `["carlos-box-binding-v1","deployment","ie",30000000000,"published","dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd","aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa","platform","box","ie","default",["aws","111122223333","eu-west-1","i-0abc"],"cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc","active",2,"3b6a27bcceb6a42d62a3a8d02a6f0d73653215771de243a63ac048a18b59da29"]`
34 const golden = "878c8d6e101fac0431418841b065a199c0796a2b83d30ee86e64400e44f94dca"
35 base := bindingRoster()
36 if raw := string(boxBindingV1(base, base.Boxes["box"])); raw != tuple {
37 t.Fatalf("v1 tuple encoding changed:\n got %s\nwant %s", raw, tuple)
38 }
39 got, ok := BoxBinding(base, "box")
40 if !ok || !ValidBinding(got) {
41 t.Fatalf("BoxBinding = %q, %v", got, ok)
42 }
43 if got != golden {
44 t.Fatalf("golden binding changed: got %s want %s (the v1 tuple is frozen)", got, golden)
45 }
46 if _, ok := BoxBinding(base, "unknown"); ok {
47 t.Fatal("unknown box returned a binding")
48 }
49 if _, ok := BoxBinding(Roster{}, "box"); ok {
50 t.Fatal("empty roster returned a binding")
51 }
52
53 bound := map[string]func(*Roster, *Box){
54 "Roster.DeploymentBucket": func(r *Roster, _ *Box) { r.DeploymentBucket = "other" },
55 "Roster.HomeRegion": func(r *Roster, _ *Box) { r.HomeRegion = "uk" },
56 "Roster.RequestLimitNS": func(r *Roster, _ *Box) { r.RequestLimitNS++ },
57 "Roster.Publication": func(r *Roster, _ *Box) { r.Publication = "preparing" },
58 "Roster.FloorSHA256": func(r *Roster, _ *Box) { r.FloorSHA256 = strings.Repeat("e", 64) },
59 "Box.Enrollment": func(_ *Roster, b *Box) { b.Enrollment = strings.Repeat("f", 32) },
60 "Box.Namespace": func(_ *Roster, b *Box) { b.Namespace = "other" },
61 "Box.BoxID": func(_ *Roster, b *Box) { b.BoxID = "other" },
62 "Box.Region": func(_ *Roster, b *Box) { b.Region = "uk" },
63 "Box.Pool": func(_ *Roster, b *Box) { b.Pool = "other" },
64 "Box.Cloud.Provider": func(_ *Roster, b *Box) { b.Cloud.Provider = "other" },
65 "Box.Cloud.Account": func(_ *Roster, b *Box) { b.Cloud.Account = "444455556666" },
66 "Box.Cloud.Region": func(_ *Roster, b *Box) { b.Cloud.Region = "eu-west-2" },
67 "Box.Cloud.InstanceID": func(_ *Roster, b *Box) { b.Cloud.InstanceID = "i-0fff" },
68 "Box.EvidenceSHA256": func(_ *Roster, b *Box) { b.EvidenceSHA256 = strings.Repeat("9", 64) },
69 "Box.State": func(_ *Roster, b *Box) { b.State = "quarantined" },
70 "Box.QuarantineRevision": func(_ *Roster, b *Box) { b.QuarantineRevision++ },
71 "Box.CensusPublicKey": func(_ *Roster, b *Box) {
72 b.CensusPublicKey = ed25519.NewKeyFromSeed(append(make([]byte, ed25519.SeedSize-1), 1)).Public().(ed25519.PublicKey)
73 },
74 }
75 excluded := map[string]func(*Roster, *Box){
76 "Roster.V": func(r *Roster, _ *Box) { r.V = 2 },
77 "Roster.Revision": func(r *Roster, _ *Box) { r.Revision++ },
78 "Roster.Holds": func(r *Roster, _ *Box) {
79 r.Holds["hold_1"] = Reservation{ID: "hold_1", Host: "h", OpID: "op", Actors: map[string]string{"box": "x"}}
80 },
81 "Roster.Activations": func(r *Roster, _ *Box) {
82 r.Activations["act_1"] = Reservation{ID: "act_1", Actors: map[string]string{"box": "x"}}
83 },
84 "Roster.EnrollmentAttempts": func(r *Roster, _ *Box) {
85 r.EnrollmentAttempts["attempt"] = EnrollmentAttempt{AttemptID: "attempt", InstanceID: "i-0new"}
86 },
87 "Roster.Consoles": func(r *Roster, _ *Box) {
88 r.Consoles["i-console"] = Console{Enrollment: strings.Repeat("e", 32), InstanceID: "i-console", Namespaces: []string{"platform"}, DeploymentBucket: "deployment"}
89 },
90 "Roster.Regions": func(r *Roster, _ *Box) { r.Regions["uk"] = Region{Namespaces: []string{"platform"}} },
91 "Roster.Boxes": func(r *Roster, _ *Box) {
92 s := r.Boxes["sibling"]
93 s.State, s.QuarantineRevision, s.LossIDs = "quarantined", 1, []string{"loss"}
94 r.Boxes["sibling"] = s
95 r.Boxes["third"] = Box{BoxID: "third"}
96 },
97 "Box.Role": func(_ *Roster, b *Box) { b.Role = "platform" },
98 "Box.Label": func(_ *Roster, b *Box) { b.Label = "renamed" },
99 "Box.Group": func(_ *Roster, b *Box) { b.Group = "other-group" },
100 "Box.LossIDs": func(_ *Roster, b *Box) { b.LossIDs = append(b.LossIDs, "loss_2") },
101 "Box.EnrolledAt": func(_ *Roster, b *Box) { b.EnrolledAt = b.EnrolledAt.Add(time.Hour) },
102 }
103
104 // Every field is classified, exactly once.
105 var fields []string
106 for _, ty := range []struct {
107 prefix string
108 t reflect.Type
109 }{{"Roster.", reflect.TypeOf(Roster{})}, {"Box.", reflect.TypeOf(Box{})}, {"Box.Cloud.", reflect.TypeOf(Cloud{})}} {
110 for i := 0; i < ty.t.NumField(); i++ {
111 name := ty.prefix + ty.t.Field(i).Name
112 if name == "Box.Cloud" {
113 continue
114 }
115 fields = append(fields, name)
116 }
117 }
118 for _, name := range fields {
119 _, in := bound[name]
120 _, out := excluded[name]
121 if in == out {
122 t.Errorf("%s: bound=%v excluded=%v; classify every field exactly once", name, in, out)
123 }
124 }
125 if len(bound)+len(excluded) != len(fields) {
126 t.Errorf("classified %d fields, struct has %d", len(bound)+len(excluded), len(fields))
127 }
128
129 mutate := func(edit func(*Roster, *Box)) string {
130 r := bindingRoster()
131 b := r.Boxes["box"]
132 edit(&r, &b)
133 ref := "box"
134 delete(r.Boxes, "box")
135 r.Boxes[ref] = b
136 out, ok := BoxBinding(r, ref)
137 if !ok {
138 t.Fatal("box vanished")
139 }
140 return out
141 }
142 names := func(m map[string]func(*Roster, *Box)) []string {
143 var out []string
144 for k := range m {
145 out = append(out, k)
146 }
147 slices.Sort(out)
148 return out
149 }
150 seen := map[string]string{got: "base"}
151 for _, name := range names(bound) {
152 d := mutate(bound[name])
153 if d == got {
154 t.Errorf("%s changed but the binding did not", name)
155 }
156 if prior, dup := seen[d]; dup {
157 t.Errorf("%s and %s gave the same binding", name, prior)
158 }
159 seen[d] = name
160 }
161 for _, name := range names(excluded) {
162 if d := mutate(excluded[name]); d != got {
163 t.Errorf("%s changed and the binding moved; it is excluded", name)
164 }
165 }
166}
167
168func TestValidBinding(t *testing.T) {
169 for s, want := range map[string]bool{
170 strings.Repeat("a", 64): true,
171 strings.Repeat("0", 64): true,
172 strings.Repeat("A", 64): false,
173 strings.Repeat("a", 63): false,
174 strings.Repeat("a", 65): false,
175 strings.Repeat("g", 64): false,
176 "": false,
177 "7": false,
178 strings.Repeat("a", 63) + " ": false,
179 } {
180 if got := ValidBinding(s); got != want {
181 t.Errorf("ValidBinding(%q) = %v, want %v", s, got, want)
182 }
183 }
184}
185